blob: 41ca0422bf1d99bac07db8d8d7d29ca4ba9f29a5 [file] [log] [blame]
Raef Coles8ff6df52021-07-21 12:42:15 +01001/*
2 * The LM-OTS one-time public-key signature scheme
3 *
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20/*
21 * The following sources were referenced in the design of this implementation
22 * of the LM-OTS algorithm:
23 *
24 * [1] IETF RFC8554
25 * D. McGrew, M. Curcio, S.Fluhrer
26 * https://datatracker.ietf.org/doc/html/rfc8554
27 *
28 * [2] NIST Special Publication 800-208
29 * David A. Cooper et. al.
30 * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-208.pdf
31 */
32
33#include "common.h"
34
Raef Coles7dce69a2022-08-24 14:07:06 +010035#ifdef MBEDTLS_LMS_C
Raef Coles8ff6df52021-07-21 12:42:15 +010036
37#include <string.h>
38
Raef Coles7dce69a2022-08-24 14:07:06 +010039#include "lmots.h"
40
Raef Colesc8f96042022-08-25 13:49:54 +010041#include "mbedtls/lms.h"
Raef Coles8ff6df52021-07-21 12:42:15 +010042#include "mbedtls/platform_util.h"
43#include "mbedtls/error.h"
44
Raef Colesc8f96042022-08-25 13:49:54 +010045#include "psa/crypto.h"
46
Raef Coles01c71a12022-08-31 15:55:00 +010047#define MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET (MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN)
Raef Colese9479a02022-09-01 16:06:35 +010048#define MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(type) (MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET + MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(type))
Raef Coles01c71a12022-08-31 15:55:00 +010049
50#define MBEDTLS_LMOTS_PUBLIC_KEY_TYPE_OFFSET (0)
51#define MBEDTLS_LMOTS_PUBLIC_KEY_I_KEY_ID_OFFSET (MBEDTLS_LMOTS_PUBLIC_KEY_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN)
52#define MBEDTLS_LMOTS_PUBLIC_KEY_Q_LEAF_ID_OFFSET (MBEDTLS_LMOTS_PUBLIC_KEY_I_KEY_ID_OFFSET + MBEDTLS_LMOTS_I_KEY_ID_LEN)
53#define MBEDTLS_LMOTS_PUBLIC_KEY_KEY_HASH_OFFSET (MBEDTLS_LMOTS_PUBLIC_KEY_Q_LEAF_ID_OFFSET + MBEDTLS_LMOTS_Q_LEAF_ID_LEN)
54
55/* We only support parameter sets that use 8-bit digits, as it does not require
56 * translation logic between digits and bytes */
57#define W_WINTERNITZ_PARAMETER (8u)
58#define CHECKSUM_LEN (2)
59#define I_DIGIT_IDX_LEN (2)
60#define J_HASH_IDX_LEN (1)
61#define D_CONST_LEN (2)
62
Raef Colese9479a02022-09-01 16:06:35 +010063/* Currently only defined for SHA256, 32 is the max hash output size */
64#define MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN_MAX (MBEDTLS_LMOTS_N_HASH_LEN_MAX)
65
Raef Coles01c71a12022-08-31 15:55:00 +010066#define DIGIT_MAX_VALUE ((1u << W_WINTERNITZ_PARAMETER) - 1u)
67
Raef Coles8ff6df52021-07-21 12:42:15 +010068#define D_CONST_LEN (2)
Raef Coles01c71a12022-08-31 15:55:00 +010069static const unsigned char D_PUBLIC_CONSTANT_BYTES[D_CONST_LEN] = {0x80, 0x80};
70static const unsigned char D_MESSAGE_CONSTANT_BYTES[D_CONST_LEN] = {0x81, 0x81};
Raef Coles8ff6df52021-07-21 12:42:15 +010071
Raef Coles01c71a12022-08-31 15:55:00 +010072void unsigned_int_to_network_bytes(unsigned int val, size_t len, unsigned char *bytes)
Raef Coles8ff6df52021-07-21 12:42:15 +010073{
74 size_t idx;
75
76 for (idx = 0; idx < len; idx++) {
77 bytes[idx] = (val >> ((len - 1 - idx) * 8)) & 0xFF;
78 }
79}
80
Raef Coles01c71a12022-08-31 15:55:00 +010081unsigned int network_bytes_to_unsigned_int(size_t len, const unsigned char *bytes)
Raef Coles8ff6df52021-07-21 12:42:15 +010082{
83 size_t idx;
84 unsigned int val = 0;
85
86 for (idx = 0; idx < len; idx++) {
87 val |= ((unsigned int)bytes[idx]) << (8 * (len - 1 - idx));
88 }
89
90 return val;
91}
92
Raef Colese9479a02022-09-01 16:06:35 +010093static unsigned short lmots_checksum_calculate( const mbedtls_lmots_parameters_t *params,
94 const unsigned char* digest )
Raef Coles8ff6df52021-07-21 12:42:15 +010095{
96 size_t idx;
Raef Coles01c71a12022-08-31 15:55:00 +010097 unsigned sum = 0;
Raef Coles8ff6df52021-07-21 12:42:15 +010098
Raef Colese9479a02022-09-01 16:06:35 +010099 for ( idx = 0; idx < MBEDTLS_LMOTS_N_HASH_LEN(params->type); idx++ )
Raef Coles8ff6df52021-07-21 12:42:15 +0100100 {
Raef Coles01c71a12022-08-31 15:55:00 +0100101 sum += DIGIT_MAX_VALUE - digest[idx];
Raef Coles8ff6df52021-07-21 12:42:15 +0100102 }
103
104 return sum;
105}
106
Raef Coles01c71a12022-08-31 15:55:00 +0100107static int create_digit_array_with_checksum( const mbedtls_lmots_parameters_t *params,
108 const unsigned char *msg,
109 size_t msg_len,
Raef Colese9479a02022-09-01 16:06:35 +0100110 const unsigned char *C_random_value,
111 unsigned char *out )
Raef Coles8ff6df52021-07-21 12:42:15 +0100112{
Raef Colesc8f96042022-08-25 13:49:54 +0100113 psa_hash_operation_t op;
114 psa_status_t status;
115 size_t output_hash_len;
Raef Coles8ff6df52021-07-21 12:42:15 +0100116 unsigned short checksum;
117 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
118
Raef Colesc8f96042022-08-25 13:49:54 +0100119 op = psa_hash_operation_init();
120 status = psa_hash_setup( &op, PSA_ALG_SHA_256 );
121 ret = mbedtls_lms_error_from_psa( status );
122 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100123 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100124
Raef Colesf5632d32022-09-01 09:56:52 +0100125 status = psa_hash_update( &op, params->I_key_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100126 MBEDTLS_LMOTS_I_KEY_ID_LEN );
Raef Colesc8f96042022-08-25 13:49:54 +0100127 ret = mbedtls_lms_error_from_psa( status );
128 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100129 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100130
Raef Colesf5632d32022-09-01 09:56:52 +0100131 status = psa_hash_update( &op, params->q_leaf_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100132 MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
Raef Colesc8f96042022-08-25 13:49:54 +0100133 ret = mbedtls_lms_error_from_psa( status );
134 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100135 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100136
Raef Coles01c71a12022-08-31 15:55:00 +0100137 status = psa_hash_update( &op, D_MESSAGE_CONSTANT_BYTES, D_CONST_LEN );
Raef Colesc8f96042022-08-25 13:49:54 +0100138 ret = mbedtls_lms_error_from_psa( status );
139 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100140 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100141
Raef Colese9479a02022-09-01 16:06:35 +0100142 status = psa_hash_update( &op, C_random_value,
143 MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(params->type) );
Raef Colesc8f96042022-08-25 13:49:54 +0100144 ret = mbedtls_lms_error_from_psa( status );
145 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100146 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100147
Raef Colesc8f96042022-08-25 13:49:54 +0100148 status = psa_hash_update( &op, msg, msg_len );
149 ret = mbedtls_lms_error_from_psa( status );
150 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100151 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100152
Raef Colese9479a02022-09-01 16:06:35 +0100153 status = psa_hash_finish( &op, out,
154 MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(params->type),
Raef Colesc8f96042022-08-25 13:49:54 +0100155 &output_hash_len );
156 ret = mbedtls_lms_error_from_psa( status );
157 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100158 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100159
Raef Colese9479a02022-09-01 16:06:35 +0100160 checksum = lmots_checksum_calculate( params, out );
161 unsigned_int_to_network_bytes( checksum, CHECKSUM_LEN,
162 out + MBEDTLS_LMOTS_N_HASH_LEN(params->type) );
Raef Coles8ff6df52021-07-21 12:42:15 +0100163
Raef Coles01c71a12022-08-31 15:55:00 +0100164exit:
Raef Colesc8f96042022-08-25 13:49:54 +0100165 psa_hash_abort( &op );
Raef Coles8ff6df52021-07-21 12:42:15 +0100166
167 return( ret );
168}
169
Raef Coles01c71a12022-08-31 15:55:00 +0100170static int hash_digit_array( const mbedtls_lmots_parameters_t *params,
Raef Colese9479a02022-09-01 16:06:35 +0100171 const unsigned char *x_digit_array,
Raef Coles01c71a12022-08-31 15:55:00 +0100172 const unsigned char *hash_idx_min_values,
173 const unsigned char *hash_idx_max_values,
Raef Colese9479a02022-09-01 16:06:35 +0100174 unsigned char *output )
Raef Coles8ff6df52021-07-21 12:42:15 +0100175{
Raef Coles01c71a12022-08-31 15:55:00 +0100176 unsigned char i_digit_idx;
Raef Coles8ff6df52021-07-21 12:42:15 +0100177 unsigned char j_hash_idx;
Raef Coles01c71a12022-08-31 15:55:00 +0100178 unsigned char i_digit_idx_bytes[I_DIGIT_IDX_LEN];
Raef Coles8ff6df52021-07-21 12:42:15 +0100179 unsigned char j_hash_idx_bytes[1];
Raef Coles01c71a12022-08-31 15:55:00 +0100180 /* These can't be unsigned chars, because they are sometimes set to
181 * #DIGIT_MAX_VALUE, which has a value of 256
182 */
183 unsigned int j_hash_idx_min;
184 unsigned int j_hash_idx_max;
Raef Colesc8f96042022-08-25 13:49:54 +0100185 psa_hash_operation_t op;
186 psa_status_t status;
187 size_t output_hash_len;
Raef Colese9479a02022-09-01 16:06:35 +0100188 unsigned char tmp_hash[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
Raef Coles8ff6df52021-07-21 12:42:15 +0100189 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
190
Raef Coles01c71a12022-08-31 15:55:00 +0100191 op = psa_hash_operation_init();
192
Raef Colese9479a02022-09-01 16:06:35 +0100193 for ( i_digit_idx = 0;
194 i_digit_idx < MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(params->type);
195 i_digit_idx++ )
Raef Coles8ff6df52021-07-21 12:42:15 +0100196 {
197
Raef Colese9479a02022-09-01 16:06:35 +0100198 memcpy( tmp_hash, &x_digit_array[i_digit_idx * MBEDTLS_LMOTS_N_HASH_LEN(params->type)],
199 MBEDTLS_LMOTS_N_HASH_LEN(params->type) );
Raef Coles8ff6df52021-07-21 12:42:15 +0100200
Raef Coles01c71a12022-08-31 15:55:00 +0100201 j_hash_idx_min = hash_idx_min_values != NULL ? hash_idx_min_values[i_digit_idx] : 0;
202 j_hash_idx_max = hash_idx_max_values != NULL ? hash_idx_max_values[i_digit_idx] : DIGIT_MAX_VALUE;
Raef Coles8ff6df52021-07-21 12:42:15 +0100203
204 for ( j_hash_idx = (unsigned char)j_hash_idx_min; j_hash_idx < j_hash_idx_max; j_hash_idx++ )
205 {
Raef Colesc8f96042022-08-25 13:49:54 +0100206 status = psa_hash_setup( &op, PSA_ALG_SHA_256 );
207 ret = mbedtls_lms_error_from_psa( status );
208 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100209 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100210
Raef Coles01c71a12022-08-31 15:55:00 +0100211 status = psa_hash_update( &op,
Raef Colesf5632d32022-09-01 09:56:52 +0100212 params->I_key_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100213 MBEDTLS_LMOTS_I_KEY_ID_LEN );
Raef Colesc8f96042022-08-25 13:49:54 +0100214 ret = mbedtls_lms_error_from_psa( status );
215 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100216 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100217
Raef Coles01c71a12022-08-31 15:55:00 +0100218 status = psa_hash_update( &op,
Raef Colesf5632d32022-09-01 09:56:52 +0100219 params->q_leaf_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100220 MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
Raef Colesc8f96042022-08-25 13:49:54 +0100221 ret = mbedtls_lms_error_from_psa( status );
222 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100223 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100224
Raef Coles01c71a12022-08-31 15:55:00 +0100225 unsigned_int_to_network_bytes( i_digit_idx, I_DIGIT_IDX_LEN, i_digit_idx_bytes );
226 status = psa_hash_update( &op, i_digit_idx_bytes, I_DIGIT_IDX_LEN );
Raef Colesc8f96042022-08-25 13:49:54 +0100227 ret = mbedtls_lms_error_from_psa( status );
228 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100229 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100230
Raef Coles01c71a12022-08-31 15:55:00 +0100231 unsigned_int_to_network_bytes( j_hash_idx, J_HASH_IDX_LEN, j_hash_idx_bytes );
Raef Colesc8f96042022-08-25 13:49:54 +0100232 status = psa_hash_update( &op, j_hash_idx_bytes, J_HASH_IDX_LEN );
233 ret = mbedtls_lms_error_from_psa( status );
234 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100235 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100236
Raef Colese9479a02022-09-01 16:06:35 +0100237 status = psa_hash_update( &op, tmp_hash,
238 MBEDTLS_LMOTS_N_HASH_LEN(params->type) );
Raef Colesc8f96042022-08-25 13:49:54 +0100239 ret = mbedtls_lms_error_from_psa( status );
240 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100241 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100242
Raef Colesc8f96042022-08-25 13:49:54 +0100243 status = psa_hash_finish( &op, tmp_hash, sizeof( tmp_hash ), &output_hash_len );
244 ret = mbedtls_lms_error_from_psa( status );
245 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100246 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100247
Raef Colesc8f96042022-08-25 13:49:54 +0100248 psa_hash_abort( &op );
Raef Coles8ff6df52021-07-21 12:42:15 +0100249 }
250
Raef Colese9479a02022-09-01 16:06:35 +0100251 memcpy( &output[i_digit_idx * MBEDTLS_LMOTS_N_HASH_LEN(params->type)], tmp_hash,
252 MBEDTLS_LMOTS_N_HASH_LEN(params->type) );
Raef Coles8ff6df52021-07-21 12:42:15 +0100253 }
254
Raef Coles01c71a12022-08-31 15:55:00 +0100255exit:
Raef Coles8ff6df52021-07-21 12:42:15 +0100256 if( ret )
257 {
Raef Colesc8f96042022-08-25 13:49:54 +0100258 psa_hash_abort( &op );
Raef Coles8ff6df52021-07-21 12:42:15 +0100259 return( ret );
260 }
261
Raef Coles01c71a12022-08-31 15:55:00 +0100262 mbedtls_platform_zeroize( tmp_hash, sizeof( tmp_hash ) );
263
Raef Coles8ff6df52021-07-21 12:42:15 +0100264 return ret;
265}
266
Raef Coles01c71a12022-08-31 15:55:00 +0100267static int public_key_from_hashed_digit_array( const mbedtls_lmots_parameters_t *params,
Raef Colese9479a02022-09-01 16:06:35 +0100268 const unsigned char *y_hashed_digits,
Raef Coles01c71a12022-08-31 15:55:00 +0100269 unsigned char *pub_key )
Raef Coles8ff6df52021-07-21 12:42:15 +0100270{
Raef Colesc8f96042022-08-25 13:49:54 +0100271 psa_hash_operation_t op;
272 psa_status_t status;
273 size_t output_hash_len;
Raef Coles8ff6df52021-07-21 12:42:15 +0100274 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
275
Raef Colesc8f96042022-08-25 13:49:54 +0100276 op = psa_hash_operation_init( );
277 status = psa_hash_setup( &op, PSA_ALG_SHA_256 );
278 ret = mbedtls_lms_error_from_psa( status );
279 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100280 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100281
Raef Coles01c71a12022-08-31 15:55:00 +0100282 status = psa_hash_update( &op,
Raef Colesf5632d32022-09-01 09:56:52 +0100283 params->I_key_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100284 MBEDTLS_LMOTS_I_KEY_ID_LEN );
Raef Colesc8f96042022-08-25 13:49:54 +0100285 ret = mbedtls_lms_error_from_psa( status );
286 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100287 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100288
Raef Colesf5632d32022-09-01 09:56:52 +0100289 status = psa_hash_update( &op, params->q_leaf_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100290 MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
Raef Colesc8f96042022-08-25 13:49:54 +0100291 ret = mbedtls_lms_error_from_psa( status );
292 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100293 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100294
Raef Coles01c71a12022-08-31 15:55:00 +0100295 status = psa_hash_update( &op, D_PUBLIC_CONSTANT_BYTES, D_CONST_LEN );
Raef Colesc8f96042022-08-25 13:49:54 +0100296 ret = mbedtls_lms_error_from_psa( status );
297 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100298 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100299
Raef Colese9479a02022-09-01 16:06:35 +0100300 status = psa_hash_update( &op, y_hashed_digits,
301 MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(params->type) *
302 MBEDTLS_LMOTS_N_HASH_LEN(params->type) );
Raef Colesc8f96042022-08-25 13:49:54 +0100303 ret = mbedtls_lms_error_from_psa( status );
304 if ( ret != 0 )
Raef Coles01c71a12022-08-31 15:55:00 +0100305 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100306
Raef Colese9479a02022-09-01 16:06:35 +0100307 status = psa_hash_finish( &op, pub_key, MBEDTLS_LMOTS_N_HASH_LEN(params->type),
308 &output_hash_len );
Raef Colesc8f96042022-08-25 13:49:54 +0100309 ret = mbedtls_lms_error_from_psa( status );
Raef Coles8ff6df52021-07-21 12:42:15 +0100310
Raef Coles01c71a12022-08-31 15:55:00 +0100311exit:
Raef Colesc8f96042022-08-25 13:49:54 +0100312 psa_hash_abort( &op );
Raef Coles8ff6df52021-07-21 12:42:15 +0100313 return( ret );
314}
315
Raef Colesc8f96042022-08-25 13:49:54 +0100316int mbedtls_lms_error_from_psa(psa_status_t status)
317{
318 switch( status ) {
319 case PSA_SUCCESS:
320 return( 0 );
321 case PSA_ERROR_HARDWARE_FAILURE:
322 return( MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED );
323 case PSA_ERROR_NOT_SUPPORTED:
324 return( MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED );
325 case PSA_ERROR_BUFFER_TOO_SMALL:
326 return( MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL );
327 case PSA_ERROR_INVALID_ARGUMENT:
328 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
329 default:
330 return( MBEDTLS_ERR_ERROR_GENERIC_ERROR );
331 }
332}
333
Raef Coles01c71a12022-08-31 15:55:00 +0100334void mbedtls_lmots_init_public( mbedtls_lmots_public_t *ctx )
Raef Coles8ff6df52021-07-21 12:42:15 +0100335{
Raef Coles01c71a12022-08-31 15:55:00 +0100336 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lmots_public_t ) ) ;
Raef Coles8ff6df52021-07-21 12:42:15 +0100337}
338
Raef Coles01c71a12022-08-31 15:55:00 +0100339void mbedtls_lmots_free_public( mbedtls_lmots_public_t *ctx )
Raef Coles8ff6df52021-07-21 12:42:15 +0100340{
Raef Coles01c71a12022-08-31 15:55:00 +0100341 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lmots_public_t ) ) ;
Raef Coles8ff6df52021-07-21 12:42:15 +0100342}
343
Raef Coles01c71a12022-08-31 15:55:00 +0100344int mbedtls_lmots_import_public_key( mbedtls_lmots_public_t *ctx,
345 const unsigned char *key, size_t key_len )
Raef Coles8ff6df52021-07-21 12:42:15 +0100346{
Raef Colesf5632d32022-09-01 09:56:52 +0100347 ctx->params.type =
Raef Coles01c71a12022-08-31 15:55:00 +0100348 network_bytes_to_unsigned_int( MBEDTLS_LMOTS_TYPE_LEN,
349 key + MBEDTLS_LMOTS_SIG_TYPE_OFFSET );
350
Raef Colese9479a02022-09-01 16:06:35 +0100351 if ( key_len < MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type) )
352 {
353 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
354 }
355
Raef Colesf5632d32022-09-01 09:56:52 +0100356 memcpy( ctx->params.I_key_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100357 key + MBEDTLS_LMOTS_PUBLIC_KEY_I_KEY_ID_OFFSET, MBEDTLS_LMOTS_I_KEY_ID_LEN );
358
Raef Colesf5632d32022-09-01 09:56:52 +0100359 memcpy( ctx->params.q_leaf_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100360 key + MBEDTLS_LMOTS_PUBLIC_KEY_Q_LEAF_ID_OFFSET, MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
361
Raef Colesf5632d32022-09-01 09:56:52 +0100362 memcpy( ctx->public_key,
Raef Coles01c71a12022-08-31 15:55:00 +0100363 key + MBEDTLS_LMOTS_PUBLIC_KEY_KEY_HASH_OFFSET,
Raef Colese9479a02022-09-01 16:06:35 +0100364 MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type) );
Raef Coles01c71a12022-08-31 15:55:00 +0100365
Raef Colesf5632d32022-09-01 09:56:52 +0100366 ctx->have_public_key = 1;
Raef Coles8ff6df52021-07-21 12:42:15 +0100367
368 return( 0 );
369}
370
Raef Coles01c71a12022-08-31 15:55:00 +0100371int mbedtls_lmots_calculate_public_key_candidate( const mbedtls_lmots_parameters_t *params,
372 const unsigned char *msg,
373 size_t msg_size,
374 const unsigned char *sig,
375 size_t sig_size,
376 unsigned char *out,
377 size_t out_size,
378 size_t *out_len)
Raef Coles8ff6df52021-07-21 12:42:15 +0100379{
Raef Colese9479a02022-09-01 16:06:35 +0100380 unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX];
381 unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
Raef Coles8ff6df52021-07-21 12:42:15 +0100382 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
383
Raef Coles01c71a12022-08-31 15:55:00 +0100384 if ( msg == NULL && msg_size != 0 )
385 {
386 return ( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
387 }
388
Raef Colese9479a02022-09-01 16:06:35 +0100389 if ( sig_size != MBEDTLS_LMOTS_SIG_LEN(params->type) ||
390 out_size < MBEDTLS_LMOTS_N_HASH_LEN(params->type) )
Raef Coles8ff6df52021-07-21 12:42:15 +0100391 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100392 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100393 }
394
Raef Coles01c71a12022-08-31 15:55:00 +0100395 ret = create_digit_array_with_checksum( params, msg, msg_size,
396 sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET,
397 tmp_digit_array );
Raef Coles8ff6df52021-07-21 12:42:15 +0100398 if ( ret )
399 {
400 return ( ret );
401 }
402
Raef Coles01c71a12022-08-31 15:55:00 +0100403 ret = hash_digit_array( params,
Raef Colese9479a02022-09-01 16:06:35 +0100404 sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(params->type),
405 tmp_digit_array, NULL, (unsigned char *)y_hashed_digits );
Raef Coles8ff6df52021-07-21 12:42:15 +0100406 if ( ret )
407 {
408 return ( ret );
409 }
410
Raef Colese9479a02022-09-01 16:06:35 +0100411 ret = public_key_from_hashed_digit_array( params,
412 (unsigned char *)y_hashed_digits,
413 out );
Raef Coles8ff6df52021-07-21 12:42:15 +0100414 if ( ret )
415 {
416 return ( ret );
417 }
418
Raef Coles01c71a12022-08-31 15:55:00 +0100419 if ( out_len != NULL )
420 {
Raef Colese9479a02022-09-01 16:06:35 +0100421 *out_len = MBEDTLS_LMOTS_N_HASH_LEN(params->type);
Raef Coles01c71a12022-08-31 15:55:00 +0100422 }
423
Raef Coles8ff6df52021-07-21 12:42:15 +0100424 return( 0 );
425}
426
Raef Coles01c71a12022-08-31 15:55:00 +0100427int mbedtls_lmots_verify( mbedtls_lmots_public_t *ctx, const unsigned char *msg,
428 size_t msg_size, const unsigned char *sig,
429 size_t sig_size )
Raef Coles8ff6df52021-07-21 12:42:15 +0100430{
Raef Colese9479a02022-09-01 16:06:35 +0100431 unsigned char Kc_public_key_candidate[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
Raef Coles8ff6df52021-07-21 12:42:15 +0100432 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
433
Raef Coles01c71a12022-08-31 15:55:00 +0100434 if ( msg == NULL && msg_size != 0 )
435 {
436 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
437 }
438
Raef Colesf5632d32022-09-01 09:56:52 +0100439 if ( !ctx->have_public_key )
Raef Coles01c71a12022-08-31 15:55:00 +0100440 {
441 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
442 }
443
Raef Colesf5632d32022-09-01 09:56:52 +0100444 if( ctx->params.MBEDTLS_PRIVATE( type )
Raef Coles01c71a12022-08-31 15:55:00 +0100445 != MBEDTLS_LMOTS_SHA256_N32_W8 )
446 {
447 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
448 }
449
450 if ( network_bytes_to_unsigned_int( MBEDTLS_LMOTS_TYPE_LEN,
451 sig + MBEDTLS_LMOTS_SIG_TYPE_OFFSET ) != MBEDTLS_LMOTS_SHA256_N32_W8 )
452 {
453 return( MBEDTLS_ERR_LMS_VERIFY_FAILED );
454 }
455
Raef Colesf5632d32022-09-01 09:56:52 +0100456 ret = mbedtls_lmots_calculate_public_key_candidate( &ctx->params,
Raef Coles01c71a12022-08-31 15:55:00 +0100457 msg, msg_size, sig, sig_size,
458 Kc_public_key_candidate,
Raef Colese9479a02022-09-01 16:06:35 +0100459 MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type),
Raef Coles01c71a12022-08-31 15:55:00 +0100460 NULL);
461 if ( ret )
462 {
463 return( ret );
464 }
465
Raef Colesf5632d32022-09-01 09:56:52 +0100466 if ( memcmp( &Kc_public_key_candidate, ctx->public_key,
467 sizeof( ctx->public_key ) ) )
Raef Coles01c71a12022-08-31 15:55:00 +0100468 {
469 return( MBEDTLS_ERR_LMS_VERIFY_FAILED );
470 }
471
472 return( 0 );
473}
474
Raef Colesab4f8742022-09-01 12:24:31 +0100475#ifdef MBEDTLS_LMS_PRIVATE
476
Raef Coles01c71a12022-08-31 15:55:00 +0100477void mbedtls_lmots_init_private( mbedtls_lmots_private_t *ctx )
478{
479 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lmots_private_t ) ) ;
480}
481
482void mbedtls_lmots_free_private( mbedtls_lmots_private_t *ctx )
483{
484 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_lmots_private_t ) ) ;
485}
486
487int mbedtls_lmots_generate_private_key( mbedtls_lmots_private_t *ctx,
488 mbedtls_lmots_algorithm_type_t type,
489 const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
490 uint32_t q_leaf_identifier,
491 const unsigned char *seed,
492 size_t seed_size )
493{
494 psa_hash_operation_t op;
495 psa_status_t status;
496 size_t output_hash_len;
497 unsigned int i_digit_idx;
498 unsigned char i_digit_idx_bytes[2];
499 unsigned char const_bytes[1];
500 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
501
Raef Colesf5632d32022-09-01 09:56:52 +0100502 if ( ctx->have_private_key )
Raef Coles01c71a12022-08-31 15:55:00 +0100503 {
504 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
505 }
506
507 if ( type != MBEDTLS_LMOTS_SHA256_N32_W8 ) {
508 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
509 }
510
Raef Colesebd35b52022-09-01 11:52:17 +0100511 op = psa_hash_operation_init( );
512
Raef Colesf5632d32022-09-01 09:56:52 +0100513 ctx->params.type = type;
Raef Coles01c71a12022-08-31 15:55:00 +0100514
Raef Colesf5632d32022-09-01 09:56:52 +0100515 memcpy( ctx->params.I_key_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100516 I_key_identifier,
Raef Colesf5632d32022-09-01 09:56:52 +0100517 sizeof( ctx->params.I_key_identifier ) );
Raef Coles01c71a12022-08-31 15:55:00 +0100518
519 unsigned_int_to_network_bytes(q_leaf_identifier,
520 MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
Raef Colesf5632d32022-09-01 09:56:52 +0100521 ctx->params.q_leaf_identifier );
Raef Coles01c71a12022-08-31 15:55:00 +0100522
523 unsigned_int_to_network_bytes( 0xFF, sizeof( const_bytes ), const_bytes );
524
Raef Colese9479a02022-09-01 16:06:35 +0100525 for ( i_digit_idx = 0;
526 i_digit_idx < MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type);
527 i_digit_idx++ )
Raef Coles01c71a12022-08-31 15:55:00 +0100528 {
Raef Coles01c71a12022-08-31 15:55:00 +0100529 status = psa_hash_setup( &op, PSA_ALG_SHA_256 );
530 ret = mbedtls_lms_error_from_psa( status );
531 if ( ret != 0 )
532 goto exit;
533
534 ret = psa_hash_update( &op,
Raef Colesf5632d32022-09-01 09:56:52 +0100535 ctx->params.I_key_identifier,
536 sizeof( ctx->params.I_key_identifier ) );
Raef Coles01c71a12022-08-31 15:55:00 +0100537 ret = mbedtls_lms_error_from_psa( status );
538 if ( ret )
539 goto exit;
540
541 status = psa_hash_update( &op,
Raef Colesf5632d32022-09-01 09:56:52 +0100542 ctx->params.q_leaf_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100543 MBEDTLS_LMOTS_Q_LEAF_ID_LEN );
544 ret = mbedtls_lms_error_from_psa( status );
545 if ( ret )
546 goto exit;
547
548 unsigned_int_to_network_bytes( i_digit_idx, I_DIGIT_IDX_LEN, i_digit_idx_bytes );
549 status = psa_hash_update( &op, i_digit_idx_bytes, I_DIGIT_IDX_LEN );
550 ret = mbedtls_lms_error_from_psa( status );
551 if ( ret )
552 goto exit;
553
554 status = psa_hash_update( &op, const_bytes, sizeof( const_bytes) );
555 ret = mbedtls_lms_error_from_psa( status );
556 if ( ret )
557 goto exit;
558
559 status = psa_hash_update( &op, seed, seed_size );
560 ret = mbedtls_lms_error_from_psa( status );
561 if ( ret )
562 goto exit;
563
564 status = psa_hash_finish( &op,
Raef Colesf5632d32022-09-01 09:56:52 +0100565 ctx->private_key[i_digit_idx],
Raef Colese9479a02022-09-01 16:06:35 +0100566 MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type),
567 &output_hash_len );
Raef Coles01c71a12022-08-31 15:55:00 +0100568 ret = mbedtls_lms_error_from_psa( status );
569 if ( ret )
570 goto exit;
571
572 psa_hash_abort( &op );
573 }
574
Raef Colesf5632d32022-09-01 09:56:52 +0100575 ctx->have_private_key = 1;
Raef Coles01c71a12022-08-31 15:55:00 +0100576
577exit:
578 if( ret )
579 {
580 psa_hash_abort( &op );
581 return( ret );
582 }
583
584 return ret;
585}
586
587int mbedtls_lmots_calculate_public_key( mbedtls_lmots_public_t *ctx,
588 mbedtls_lmots_private_t *priv_ctx)
589{
Raef Colese9479a02022-09-01 16:06:35 +0100590 unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
Raef Coles01c71a12022-08-31 15:55:00 +0100591 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
592
Raef Coles8ff6df52021-07-21 12:42:15 +0100593 /* Check that a private key is loaded */
Raef Colesf5632d32022-09-01 09:56:52 +0100594 if ( !priv_ctx->have_private_key )
Raef Coles01c71a12022-08-31 15:55:00 +0100595 {
596 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
597 }
598
Raef Colese9479a02022-09-01 16:06:35 +0100599 ret = hash_digit_array( &priv_ctx->params,
600 (unsigned char *)priv_ctx->private_key, NULL,
601 NULL, (unsigned char *)y_hashed_digits );
Raef Coles01c71a12022-08-31 15:55:00 +0100602 if ( ret )
603 {
604 return( ret );
605 }
606
Raef Colesf5632d32022-09-01 09:56:52 +0100607 ret = public_key_from_hashed_digit_array( &priv_ctx->params,
Raef Colese9479a02022-09-01 16:06:35 +0100608 (unsigned char *)y_hashed_digits,
Raef Coles0c88d4e2022-09-01 10:48:32 +0100609 ctx->public_key );
Raef Coles01c71a12022-08-31 15:55:00 +0100610 if ( ret )
611 {
612 return( ret );
613 }
614
Raef Colesf5632d32022-09-01 09:56:52 +0100615 memcpy( &ctx->params, &priv_ctx->params,
616 sizeof( ctx->params ) );
Raef Coles01c71a12022-08-31 15:55:00 +0100617
618 ctx->MBEDTLS_PRIVATE(have_public_key = 1);
619
620 return( ret );
621}
622
623
624int mbedtls_lmots_export_public_key( mbedtls_lmots_public_t *ctx,
625 unsigned char *key, size_t key_size,
626 size_t *key_len )
627{
Raef Colese9479a02022-09-01 16:06:35 +0100628 if( key_size < MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type) )
Raef Coles01c71a12022-08-31 15:55:00 +0100629 {
630 return( MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL );
631 }
632
Raef Colesf5632d32022-09-01 09:56:52 +0100633 if( ! ctx->have_public_key )
Raef Coles01c71a12022-08-31 15:55:00 +0100634 {
635 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
636 }
637
Raef Colesf5632d32022-09-01 09:56:52 +0100638 unsigned_int_to_network_bytes( ctx->params.type,
Raef Coles01c71a12022-08-31 15:55:00 +0100639 MBEDTLS_LMOTS_TYPE_LEN,
640 key + MBEDTLS_LMOTS_SIG_TYPE_OFFSET );
641
642 memcpy( key + MBEDTLS_LMOTS_PUBLIC_KEY_I_KEY_ID_OFFSET,
Raef Colesf5632d32022-09-01 09:56:52 +0100643 ctx->params.I_key_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100644 MBEDTLS_LMOTS_I_KEY_ID_LEN );
645
646 memcpy(key + MBEDTLS_LMOTS_PUBLIC_KEY_Q_LEAF_ID_OFFSET,
Raef Colesf5632d32022-09-01 09:56:52 +0100647 ctx->params.q_leaf_identifier,
Raef Coles01c71a12022-08-31 15:55:00 +0100648 MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
649
Raef Colesf5632d32022-09-01 09:56:52 +0100650 memcpy( key + MBEDTLS_LMOTS_PUBLIC_KEY_KEY_HASH_OFFSET, ctx->public_key,
Raef Colese9479a02022-09-01 16:06:35 +0100651 MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type) );
Raef Coles01c71a12022-08-31 15:55:00 +0100652
653 if( key_len != NULL )
654 {
Raef Colese9479a02022-09-01 16:06:35 +0100655 *key_len = MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type);
Raef Coles01c71a12022-08-31 15:55:00 +0100656 }
657
658 return( 0 );
659}
660
661int mbedtls_lmots_sign( mbedtls_lmots_private_t *ctx,
662 int (*f_rng)(void *, unsigned char *, size_t),
663 void *p_rng, const unsigned char *msg, size_t msg_size,
664 unsigned char *sig, size_t sig_size, size_t* sig_len )
665{
Raef Colese9479a02022-09-01 16:06:35 +0100666 unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX];
Raef Coles891c6132022-09-01 11:05:48 +0100667 /* Create a temporary buffer to prepare the signature in. This allows us to
668 * finish creating a signature (ensuring the process doesn't fail), and then
669 * erase the private key **before** writing any data into the sig parameter
670 * buffer. If data were directly written into the sig buffer, it might leak
671 * a partial signature on failure, which effectively compromises the private
672 * key.
673 */
Raef Colese9479a02022-09-01 16:06:35 +0100674 unsigned char tmp_sig[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
675 unsigned char tmp_c_random[MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN_MAX];
Raef Coles01c71a12022-08-31 15:55:00 +0100676 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
677
678 if ( msg == NULL && msg_size != 0 )
679 {
680 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
681 }
682
Raef Colese9479a02022-09-01 16:06:35 +0100683 if( sig_size < MBEDTLS_LMOTS_SIG_LEN(ctx->params.type) )
Raef Coles01c71a12022-08-31 15:55:00 +0100684 {
685 return( MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL );
686 }
687
688 /* Check that a private key is loaded */
Raef Colesf5632d32022-09-01 09:56:52 +0100689 if ( !ctx->have_private_key )
Raef Coles8ff6df52021-07-21 12:42:15 +0100690 {
Raef Coles7dce69a2022-08-24 14:07:06 +0100691 return( MBEDTLS_ERR_LMS_BAD_INPUT_DATA );
Raef Coles8ff6df52021-07-21 12:42:15 +0100692 }
693
Raef Colese9479a02022-09-01 16:06:35 +0100694 ret = f_rng( p_rng, tmp_c_random, MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type) );
Raef Coles8ff6df52021-07-21 12:42:15 +0100695 if ( ret )
696 {
697 return( ret );
698 }
699
Raef Colesf5632d32022-09-01 09:56:52 +0100700 ret = create_digit_array_with_checksum( &ctx->params,
Raef Coles01c71a12022-08-31 15:55:00 +0100701 msg, msg_size,
Raef Coles891c6132022-09-01 11:05:48 +0100702 tmp_c_random,
Raef Coles01c71a12022-08-31 15:55:00 +0100703 tmp_digit_array );
Raef Coles8ff6df52021-07-21 12:42:15 +0100704 if ( ret )
705 {
706 return( ret );
707 }
708
Raef Colese9479a02022-09-01 16:06:35 +0100709 ret = hash_digit_array( &ctx->params, (unsigned char *)ctx->private_key,
710 NULL, tmp_digit_array, (unsigned char *)tmp_sig );
Raef Coles8ff6df52021-07-21 12:42:15 +0100711 if ( ret )
712 {
713 return( ret );
714 }
715
Raef Colesf5632d32022-09-01 09:56:52 +0100716 unsigned_int_to_network_bytes( ctx->params.type,
Raef Coles01c71a12022-08-31 15:55:00 +0100717 MBEDTLS_LMOTS_TYPE_LEN,
718 sig + MBEDTLS_LMOTS_SIG_TYPE_OFFSET );
Raef Coles8ff6df52021-07-21 12:42:15 +0100719
720 /* We've got a valid signature now, so it's time to make sure the private
721 * key can't be reused.
722 */
Raef Colesf5632d32022-09-01 09:56:52 +0100723 ctx->have_private_key = 0;
724 mbedtls_platform_zeroize(ctx->private_key,
725 sizeof(ctx->private_key));
Raef Coles8ff6df52021-07-21 12:42:15 +0100726
Raef Coles891c6132022-09-01 11:05:48 +0100727 memcpy( sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET, tmp_c_random,
Raef Colese9479a02022-09-01 16:06:35 +0100728 MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(ctx->params.type) );
Raef Coles891c6132022-09-01 11:05:48 +0100729
Raef Colese9479a02022-09-01 16:06:35 +0100730 memcpy( sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(ctx->params.type), tmp_sig,
731 MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type)
732 * MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type) );
Raef Coles8ff6df52021-07-21 12:42:15 +0100733
Raef Coles01c71a12022-08-31 15:55:00 +0100734 if( sig_len != NULL )
Raef Coles8ff6df52021-07-21 12:42:15 +0100735 {
Raef Colese9479a02022-09-01 16:06:35 +0100736 *sig_len = MBEDTLS_LMOTS_SIG_LEN(ctx->params.type);
Raef Coles8ff6df52021-07-21 12:42:15 +0100737 }
738
739 return( 0 );
740}
741
Raef Colesab4f8742022-09-01 12:24:31 +0100742#endif /* MBEDTLS_LMS_PRIVATE */
Raef Coles7dce69a2022-08-24 14:07:06 +0100743#endif /* MBEDTLS_LMS_C */