blob: 76bcc19af064e4d11a972fbcb77051d3db47dc8c [file] [log] [blame]
Raef Coles8ff6df52021-07-21 12:42:15 +01001/*
2 * The LMS stateful-hash 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 LMS 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 Coles5127e852022-10-07 10:35:56 +010035#if defined(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 "psa/crypto.h"
42
Raef Coles8ff6df52021-07-21 12:42:15 +010043#include "mbedtls/lms.h"
Raef Coles8ff6df52021-07-21 12:42:15 +010044#include "mbedtls/error.h"
45#include "mbedtls/platform_util.h"
46
Raef Coles8ff6df52021-07-21 12:42:15 +010047#include "mbedtls/platform.h"
Raef Coles8ff6df52021-07-21 12:42:15 +010048
Raef Coles57d53282022-09-27 11:30:51 +010049#define SIG_Q_LEAF_ID_OFFSET (0)
50#define SIG_OTS_SIG_OFFSET (SIG_Q_LEAF_ID_OFFSET + \
51 MBEDTLS_LMOTS_Q_LEAF_ID_LEN)
52#define SIG_TYPE_OFFSET(otstype) (SIG_OTS_SIG_OFFSET + \
53 MBEDTLS_LMOTS_SIG_LEN(otstype))
54#define SIG_PATH_OFFSET(otstype) (SIG_TYPE_OFFSET(otstype) + \
55 MBEDTLS_LMS_TYPE_LEN)
Raef Coles01c71a12022-08-31 15:55:00 +010056
Raef Coles57d53282022-09-27 11:30:51 +010057#define PUBLIC_KEY_TYPE_OFFSET (0)
58#define PUBLIC_KEY_OTSTYPE_OFFSET (PUBLIC_KEY_TYPE_OFFSET + \
59 MBEDTLS_LMS_TYPE_LEN)
60#define PUBLIC_KEY_I_KEY_ID_OFFSET (PUBLIC_KEY_OTSTYPE_OFFSET + \
61 MBEDTLS_LMOTS_TYPE_LEN)
62#define PUBLIC_KEY_ROOT_NODE_OFFSET (PUBLIC_KEY_I_KEY_ID_OFFSET + \
63 MBEDTLS_LMOTS_I_KEY_ID_LEN)
Raef Coles01c71a12022-08-31 15:55:00 +010064
65
Raef Colese9479a02022-09-01 16:06:35 +010066/* Currently only support H=10 */
Raef Coles57d53282022-09-27 11:30:51 +010067#define H_TREE_HEIGHT_MAX 10
Moritz Fischera6a94ad2022-11-12 08:28:04 -080068#define MERKLE_TREE_NODE_AM(type) ((size_t) 1 << (MBEDTLS_LMS_H_TREE_HEIGHT(type) + 1u))
69#define MERKLE_TREE_LEAF_NODE_AM(type) ((size_t) 1 << MBEDTLS_LMS_H_TREE_HEIGHT(type))
70#define MERKLE_TREE_INTERNAL_NODE_AM(type) ((size_t) 1 << MBEDTLS_LMS_H_TREE_HEIGHT(type))
Raef Coles8ff6df52021-07-21 12:42:15 +010071
72#define D_CONST_LEN (2)
Gilles Peskine449bd832023-01-11 14:50:10 +010073static const unsigned char D_LEAF_CONSTANT_BYTES[D_CONST_LEN] = { 0x82, 0x82 };
74static const unsigned char D_INTR_CONSTANT_BYTES[D_CONST_LEN] = { 0x83, 0x83 };
Raef Coles8ff6df52021-07-21 12:42:15 +010075
Raef Coles0a967cc2022-09-02 17:46:15 +010076
Raef Coles285d44b2022-10-10 15:44:17 +010077/* Calculate the value of a leaf node of the Merkle tree (which is a hash of a
Raef Coles0a967cc2022-09-02 17:46:15 +010078 * public key and some other parameters like the leaf index). This function
79 * implements RFC8554 section 5.3, in the case where r >= 2^h.
80 *
Raef Coles98d6e222022-09-23 09:04:04 +010081 * params The LMS parameter set, the underlying LMOTS
82 * parameter set, and I value which describe the key
83 * being used.
Raef Coles0a967cc2022-09-02 17:46:15 +010084 *
Raef Coles98d6e222022-09-23 09:04:04 +010085 * pub_key The public key of the private whose index
86 * corresponds to the index of this leaf node. This
87 * is a hash output.
Raef Coles0a967cc2022-09-02 17:46:15 +010088 *
Raef Coles285d44b2022-10-10 15:44:17 +010089 * r_node_idx The index of this node in the Merkle tree. Note
90 * that the root node of the Merkle tree is
Raef Coles98d6e222022-09-23 09:04:04 +010091 * 1-indexed.
Raef Coles0a967cc2022-09-02 17:46:15 +010092 *
Raef Coles98d6e222022-09-23 09:04:04 +010093 * out The output node value, which is a hash output.
Raef Coles0a967cc2022-09-02 17:46:15 +010094 */
Gilles Peskine449bd832023-01-11 14:50:10 +010095static int create_merkle_leaf_value(const mbedtls_lms_parameters_t *params,
96 unsigned char *pub_key,
97 unsigned int r_node_idx,
98 unsigned char *out)
Raef Coles8ff6df52021-07-21 12:42:15 +010099{
Raef Colesc8f96042022-08-25 13:49:54 +0100100 psa_hash_operation_t op;
Raef Colesbe0c2f92022-10-07 11:27:35 +0100101 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
Raef Colesc8f96042022-08-25 13:49:54 +0100102 size_t output_hash_len;
Raef Coles8ff6df52021-07-21 12:42:15 +0100103 unsigned char r_node_idx_bytes[4];
Raef Coles8ff6df52021-07-21 12:42:15 +0100104
Gilles Peskine449bd832023-01-11 14:50:10 +0100105 op = psa_hash_operation_init();
106 status = psa_hash_setup(&op, PSA_ALG_SHA_256);
107 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100108 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100109 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100110
Gilles Peskine449bd832023-01-11 14:50:10 +0100111 status = psa_hash_update(&op, params->I_key_identifier,
112 MBEDTLS_LMOTS_I_KEY_ID_LEN);
113 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100114 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100115 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100116
Gilles Peskine449bd832023-01-11 14:50:10 +0100117 mbedtls_lms_unsigned_int_to_network_bytes(r_node_idx, 4, r_node_idx_bytes);
118 status = psa_hash_update(&op, r_node_idx_bytes, 4);
119 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100120 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100121 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100122
Gilles Peskine449bd832023-01-11 14:50:10 +0100123 status = psa_hash_update(&op, D_LEAF_CONSTANT_BYTES, D_CONST_LEN);
124 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100125 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100126 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100127
Gilles Peskine449bd832023-01-11 14:50:10 +0100128 status = psa_hash_update(&op, pub_key,
129 MBEDTLS_LMOTS_N_HASH_LEN(params->otstype));
130 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100131 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100132 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100133
Gilles Peskine449bd832023-01-11 14:50:10 +0100134 status = psa_hash_finish(&op, out, MBEDTLS_LMS_M_NODE_BYTES(params->type),
135 &output_hash_len);
136 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100137 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100138 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100139
Raef Coles01c71a12022-08-31 15:55:00 +0100140exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100141 psa_hash_abort(&op);
Raef Coles8ff6df52021-07-21 12:42:15 +0100142
Gilles Peskine449bd832023-01-11 14:50:10 +0100143 return mbedtls_lms_error_from_psa(status);
Raef Coles8ff6df52021-07-21 12:42:15 +0100144}
145
Raef Coles285d44b2022-10-10 15:44:17 +0100146/* Calculate the value of an internal node of the Merkle tree (which is a hash
Raef Coles0a967cc2022-09-02 17:46:15 +0100147 * of a public key and some other parameters like the node index). This function
148 * implements RFC8554 section 5.3, in the case where r < 2^h.
149 *
Raef Coles98d6e222022-09-23 09:04:04 +0100150 * params The LMS parameter set, the underlying LMOTS
151 * parameter set, and I value which describe the key
152 * being used.
Raef Coles0a967cc2022-09-02 17:46:15 +0100153 *
Raef Coles98d6e222022-09-23 09:04:04 +0100154 * left_node The value of the child of this node which is on
155 * the left-hand side. As with all nodes on the
Raef Coles285d44b2022-10-10 15:44:17 +0100156 * Merkle tree, this is a hash output.
Raef Coles0a967cc2022-09-02 17:46:15 +0100157 *
Raef Coles98d6e222022-09-23 09:04:04 +0100158 * right_node The value of the child of this node which is on
159 * the right-hand side. As with all nodes on the
Raef Coles285d44b2022-10-10 15:44:17 +0100160 * Merkle tree, this is a hash output.
Raef Coles0a967cc2022-09-02 17:46:15 +0100161 *
Raef Coles285d44b2022-10-10 15:44:17 +0100162 * r_node_idx The index of this node in the Merkle tree. Note
163 * that the root node of the Merkle tree is
Raef Coles98d6e222022-09-23 09:04:04 +0100164 * 1-indexed.
Raef Coles0a967cc2022-09-02 17:46:15 +0100165 *
Raef Coles98d6e222022-09-23 09:04:04 +0100166 * out The output node value, which is a hash output.
Raef Coles0a967cc2022-09-02 17:46:15 +0100167 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100168static int create_merkle_internal_value(const mbedtls_lms_parameters_t *params,
169 const unsigned char *left_node,
170 const unsigned char *right_node,
171 unsigned int r_node_idx,
172 unsigned char *out)
Raef Coles8ff6df52021-07-21 12:42:15 +0100173{
Raef Colesc8f96042022-08-25 13:49:54 +0100174 psa_hash_operation_t op;
Raef Colesbe0c2f92022-10-07 11:27:35 +0100175 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
Raef Colesc8f96042022-08-25 13:49:54 +0100176 size_t output_hash_len;
Raef Coles8ff6df52021-07-21 12:42:15 +0100177 unsigned char r_node_idx_bytes[4];
Raef Coles8ff6df52021-07-21 12:42:15 +0100178
Gilles Peskine449bd832023-01-11 14:50:10 +0100179 op = psa_hash_operation_init();
180 status = psa_hash_setup(&op, PSA_ALG_SHA_256);
181 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100182 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100183 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100184
Gilles Peskine449bd832023-01-11 14:50:10 +0100185 status = psa_hash_update(&op, params->I_key_identifier,
186 MBEDTLS_LMOTS_I_KEY_ID_LEN);
187 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100188 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100189 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100190
Gilles Peskine449bd832023-01-11 14:50:10 +0100191 mbedtls_lms_unsigned_int_to_network_bytes(r_node_idx, 4, r_node_idx_bytes);
192 status = psa_hash_update(&op, r_node_idx_bytes, 4);
193 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100194 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100195 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100196
Gilles Peskine449bd832023-01-11 14:50:10 +0100197 status = psa_hash_update(&op, D_INTR_CONSTANT_BYTES, D_CONST_LEN);
198 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100199 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100200 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100201
Gilles Peskine449bd832023-01-11 14:50:10 +0100202 status = psa_hash_update(&op, left_node,
203 MBEDTLS_LMS_M_NODE_BYTES(params->type));
204 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100205 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100206 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100207
Gilles Peskine449bd832023-01-11 14:50:10 +0100208 status = psa_hash_update(&op, right_node,
209 MBEDTLS_LMS_M_NODE_BYTES(params->type));
210 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100211 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100212 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100213
Gilles Peskine449bd832023-01-11 14:50:10 +0100214 status = psa_hash_finish(&op, out, MBEDTLS_LMS_M_NODE_BYTES(params->type),
215 &output_hash_len);
216 if (status != PSA_SUCCESS) {
Raef Coles01c71a12022-08-31 15:55:00 +0100217 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100218 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100219
Raef Coles01c71a12022-08-31 15:55:00 +0100220exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100221 psa_hash_abort(&op);
Raef Coles8ff6df52021-07-21 12:42:15 +0100222
Gilles Peskine449bd832023-01-11 14:50:10 +0100223 return mbedtls_lms_error_from_psa(status);
Raef Coles8ff6df52021-07-21 12:42:15 +0100224}
225
Gilles Peskine449bd832023-01-11 14:50:10 +0100226void mbedtls_lms_public_init(mbedtls_lms_public_t *ctx)
Raef Coles8ff6df52021-07-21 12:42:15 +0100227{
Gilles Peskine449bd832023-01-11 14:50:10 +0100228 memset(ctx, 0, sizeof(*ctx));
Raef Coles8ff6df52021-07-21 12:42:15 +0100229}
230
Gilles Peskine449bd832023-01-11 14:50:10 +0100231void mbedtls_lms_public_free(mbedtls_lms_public_t *ctx)
Raef Coles8ff6df52021-07-21 12:42:15 +0100232{
Gilles Peskine449bd832023-01-11 14:50:10 +0100233 mbedtls_platform_zeroize(ctx, sizeof(*ctx));
Raef Coles8ff6df52021-07-21 12:42:15 +0100234}
235
Gilles Peskine449bd832023-01-11 14:50:10 +0100236int mbedtls_lms_import_public_key(mbedtls_lms_public_t *ctx,
237 const unsigned char *key, size_t key_size)
Raef Coles8ff6df52021-07-21 12:42:15 +0100238{
Raef Coles01c71a12022-08-31 15:55:00 +0100239 mbedtls_lms_algorithm_type_t type;
240 mbedtls_lmots_algorithm_type_t otstype;
241
Gilles Peskine449bd832023-01-11 14:50:10 +0100242 type = mbedtls_lms_network_bytes_to_unsigned_int(MBEDTLS_LMS_TYPE_LEN,
243 key + PUBLIC_KEY_TYPE_OFFSET);
244 if (type != MBEDTLS_LMS_SHA256_M32_H10) {
245 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100246 }
Raef Colesf5632d32022-09-01 09:56:52 +0100247 ctx->params.type = type;
Raef Coles8ff6df52021-07-21 12:42:15 +0100248
Gilles Peskine449bd832023-01-11 14:50:10 +0100249 if (key_size != MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type)) {
250 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Colese89488d2022-10-07 16:06:35 +0100251 }
252
Gilles Peskine449bd832023-01-11 14:50:10 +0100253 otstype = mbedtls_lms_network_bytes_to_unsigned_int(MBEDTLS_LMOTS_TYPE_LEN,
254 key + PUBLIC_KEY_OTSTYPE_OFFSET);
255 if (otstype != MBEDTLS_LMOTS_SHA256_N32_W8) {
256 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles01c71a12022-08-31 15:55:00 +0100257 }
Raef Colesf5632d32022-09-01 09:56:52 +0100258 ctx->params.otstype = otstype;
Raef Coles01c71a12022-08-31 15:55:00 +0100259
Gilles Peskine449bd832023-01-11 14:50:10 +0100260 memcpy(ctx->params.I_key_identifier,
261 key + PUBLIC_KEY_I_KEY_ID_OFFSET,
262 MBEDTLS_LMOTS_I_KEY_ID_LEN);
263 memcpy(ctx->T_1_pub_key, key + PUBLIC_KEY_ROOT_NODE_OFFSET,
264 MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type));
Raef Coles01c71a12022-08-31 15:55:00 +0100265
Raef Colesf5632d32022-09-01 09:56:52 +0100266 ctx->have_public_key = 1;
Raef Coles8ff6df52021-07-21 12:42:15 +0100267
Gilles Peskine449bd832023-01-11 14:50:10 +0100268 return 0;
Raef Coles8ff6df52021-07-21 12:42:15 +0100269}
270
Gilles Peskine449bd832023-01-11 14:50:10 +0100271int mbedtls_lms_export_public_key(const mbedtls_lms_public_t *ctx,
272 unsigned char *key,
273 size_t key_size, size_t *key_len)
Raef Coles370cc432022-10-07 16:07:33 +0100274{
Gilles Peskine449bd832023-01-11 14:50:10 +0100275 if (key_size < MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type)) {
276 return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
Raef Coles370cc432022-10-07 16:07:33 +0100277 }
278
Gilles Peskine449bd832023-01-11 14:50:10 +0100279 if (!ctx->have_public_key) {
280 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles370cc432022-10-07 16:07:33 +0100281 }
282
283 mbedtls_lms_unsigned_int_to_network_bytes(
Gilles Peskine449bd832023-01-11 14:50:10 +0100284 ctx->params.type,
285 MBEDTLS_LMS_TYPE_LEN, key + PUBLIC_KEY_TYPE_OFFSET);
286 mbedtls_lms_unsigned_int_to_network_bytes(ctx->params.otstype,
287 MBEDTLS_LMOTS_TYPE_LEN,
288 key + PUBLIC_KEY_OTSTYPE_OFFSET);
289 memcpy(key + PUBLIC_KEY_I_KEY_ID_OFFSET,
290 ctx->params.I_key_identifier,
291 MBEDTLS_LMOTS_I_KEY_ID_LEN);
292 memcpy(key +PUBLIC_KEY_ROOT_NODE_OFFSET,
293 ctx->T_1_pub_key,
294 MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type));
Raef Coles370cc432022-10-07 16:07:33 +0100295
Gilles Peskine449bd832023-01-11 14:50:10 +0100296 if (key_len != NULL) {
Raef Coles370cc432022-10-07 16:07:33 +0100297 *key_len = MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type);
298 }
299
Gilles Peskine449bd832023-01-11 14:50:10 +0100300 return 0;
Raef Coles370cc432022-10-07 16:07:33 +0100301}
302
Gilles Peskine449bd832023-01-11 14:50:10 +0100303int mbedtls_lms_verify(const mbedtls_lms_public_t *ctx,
304 const unsigned char *msg, size_t msg_size,
305 const unsigned char *sig, size_t sig_size)
Raef Coles8ff6df52021-07-21 12:42:15 +0100306{
307 unsigned int q_leaf_identifier;
Raef Colese9479a02022-09-01 16:06:35 +0100308 unsigned char Kc_candidate_ots_pub_key[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
309 unsigned char Tc_candidate_root_node[MBEDTLS_LMS_M_NODE_BYTES_MAX];
Raef Coles8ff6df52021-07-21 12:42:15 +0100310 unsigned int height;
311 unsigned int curr_node_id;
312 unsigned int parent_node_id;
Gilles Peskine449bd832023-01-11 14:50:10 +0100313 const unsigned char *left_node;
314 const unsigned char *right_node;
Raef Coles01c71a12022-08-31 15:55:00 +0100315 mbedtls_lmots_parameters_t ots_params;
Raef Coles8ff6df52021-07-21 12:42:15 +0100316 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
317
Gilles Peskine449bd832023-01-11 14:50:10 +0100318 if (!ctx->have_public_key) {
319 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100320 }
321
Gilles Peskine449bd832023-01-11 14:50:10 +0100322 if (ctx->params.type
323 != MBEDTLS_LMS_SHA256_M32_H10) {
324 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100325 }
326
Gilles Peskine449bd832023-01-11 14:50:10 +0100327 if (ctx->params.otstype
328 != MBEDTLS_LMOTS_SHA256_N32_W8) {
329 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100330 }
331
Gilles Peskine449bd832023-01-11 14:50:10 +0100332 if (sig_size != MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)) {
333 return MBEDTLS_ERR_LMS_VERIFY_FAILED;
Raef Colesfaf59ba2022-10-10 15:40:56 +0100334 }
335
Gilles Peskine449bd832023-01-11 14:50:10 +0100336 if (sig_size < SIG_OTS_SIG_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
337 return MBEDTLS_ERR_LMS_VERIFY_FAILED;
Raef Colesfaf59ba2022-10-10 15:40:56 +0100338 }
339
Gilles Peskine449bd832023-01-11 14:50:10 +0100340 if (mbedtls_lms_network_bytes_to_unsigned_int(MBEDTLS_LMOTS_TYPE_LEN,
341 sig + SIG_OTS_SIG_OFFSET +
342 MBEDTLS_LMOTS_SIG_TYPE_OFFSET)
343 != MBEDTLS_LMOTS_SHA256_N32_W8) {
344 return MBEDTLS_ERR_LMS_VERIFY_FAILED;
Raef Coles8ff6df52021-07-21 12:42:15 +0100345 }
346
Gilles Peskine449bd832023-01-11 14:50:10 +0100347 if (sig_size < SIG_TYPE_OFFSET(ctx->params.otstype) + MBEDTLS_LMS_TYPE_LEN) {
348 return MBEDTLS_ERR_LMS_VERIFY_FAILED;
Raef Colesfaf59ba2022-10-10 15:40:56 +0100349 }
350
Gilles Peskine449bd832023-01-11 14:50:10 +0100351 if (mbedtls_lms_network_bytes_to_unsigned_int(MBEDTLS_LMS_TYPE_LEN,
352 sig + SIG_TYPE_OFFSET(ctx->params.otstype))
353 != MBEDTLS_LMS_SHA256_M32_H10) {
354 return MBEDTLS_ERR_LMS_VERIFY_FAILED;
Raef Coles8ff6df52021-07-21 12:42:15 +0100355 }
356
357
Raef Colesad054252022-09-27 10:59:16 +0100358 q_leaf_identifier = mbedtls_lms_network_bytes_to_unsigned_int(
Gilles Peskine449bd832023-01-11 14:50:10 +0100359 MBEDTLS_LMOTS_Q_LEAF_ID_LEN, sig + SIG_Q_LEAF_ID_OFFSET);
Raef Coles8ff6df52021-07-21 12:42:15 +0100360
Gilles Peskine449bd832023-01-11 14:50:10 +0100361 if (q_leaf_identifier >= MERKLE_TREE_LEAF_NODE_AM(ctx->params.type)) {
362 return MBEDTLS_ERR_LMS_VERIFY_FAILED;
Raef Coles8ff6df52021-07-21 12:42:15 +0100363 }
364
Gilles Peskine449bd832023-01-11 14:50:10 +0100365 memcpy(ots_params.I_key_identifier,
366 ctx->params.I_key_identifier,
367 MBEDTLS_LMOTS_I_KEY_ID_LEN);
368 mbedtls_lms_unsigned_int_to_network_bytes(q_leaf_identifier,
Raef Colesad054252022-09-27 10:59:16 +0100369 MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
Gilles Peskine449bd832023-01-11 14:50:10 +0100370 ots_params.q_leaf_identifier);
Raef Colesf5632d32022-09-01 09:56:52 +0100371 ots_params.type = ctx->params.otstype;
Raef Coles01c71a12022-08-31 15:55:00 +0100372
Gilles Peskine449bd832023-01-11 14:50:10 +0100373 ret = mbedtls_lmots_calculate_public_key_candidate(&ots_params,
374 msg,
375 msg_size,
376 sig + SIG_OTS_SIG_OFFSET,
377 MBEDTLS_LMOTS_SIG_LEN(ctx->params.otstype),
378 Kc_candidate_ots_pub_key,
379 sizeof(Kc_candidate_ots_pub_key),
380 NULL);
381 if (ret != 0) {
382 return MBEDTLS_ERR_LMS_VERIFY_FAILED;
Raef Coles8ff6df52021-07-21 12:42:15 +0100383 }
384
Raef Colesebd35b52022-09-01 11:52:17 +0100385 create_merkle_leaf_value(
Gilles Peskine449bd832023-01-11 14:50:10 +0100386 &ctx->params,
387 Kc_candidate_ots_pub_key,
388 MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + q_leaf_identifier,
389 Tc_candidate_root_node);
Raef Coles8ff6df52021-07-21 12:42:15 +0100390
Raef Coles366d67d2022-09-01 17:23:12 +0100391 curr_node_id = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) +
392 q_leaf_identifier;
Raef Coles8ff6df52021-07-21 12:42:15 +0100393
Gilles Peskine449bd832023-01-11 14:50:10 +0100394 for (height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT(ctx->params.type);
395 height++) {
Raef Coles8ff6df52021-07-21 12:42:15 +0100396 parent_node_id = curr_node_id / 2;
397
398 /* Left/right node ordering matters for the hash */
Gilles Peskine449bd832023-01-11 14:50:10 +0100399 if (curr_node_id & 1) {
Raef Coles57d53282022-09-27 11:30:51 +0100400 left_node = sig + SIG_PATH_OFFSET(ctx->params.otstype) +
Raef Colese9479a02022-09-01 16:06:35 +0100401 height * MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
Raef Coles01c71a12022-08-31 15:55:00 +0100402 right_node = Tc_candidate_root_node;
Gilles Peskine449bd832023-01-11 14:50:10 +0100403 } else {
Raef Coles8ff6df52021-07-21 12:42:15 +0100404 left_node = Tc_candidate_root_node;
Raef Coles57d53282022-09-27 11:30:51 +0100405 right_node = sig + SIG_PATH_OFFSET(ctx->params.otstype) +
Raef Colese9479a02022-09-01 16:06:35 +0100406 height * MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
Raef Coles8ff6df52021-07-21 12:42:15 +0100407 }
408
Gilles Peskine449bd832023-01-11 14:50:10 +0100409 create_merkle_internal_value(&ctx->params, left_node, right_node,
410 parent_node_id, Tc_candidate_root_node);
Raef Coles8ff6df52021-07-21 12:42:15 +0100411
412 curr_node_id /= 2;
413 }
414
Gilles Peskine449bd832023-01-11 14:50:10 +0100415 if (memcmp(Tc_candidate_root_node, ctx->T_1_pub_key,
416 MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type))) {
417 return MBEDTLS_ERR_LMS_VERIFY_FAILED;
Raef Coles8ff6df52021-07-21 12:42:15 +0100418 }
419
Gilles Peskine449bd832023-01-11 14:50:10 +0100420 return 0;
Raef Coles8ff6df52021-07-21 12:42:15 +0100421}
422
Raef Coles5127e852022-10-07 10:35:56 +0100423#if defined(MBEDTLS_LMS_PRIVATE)
Raef Colesab4f8742022-09-01 12:24:31 +0100424
Raef Coles285d44b2022-10-10 15:44:17 +0100425/* Calculate a full Merkle tree based on a private key. This function
Raef Coles0a967cc2022-09-02 17:46:15 +0100426 * implements RFC8554 section 5.3, and is used to generate a public key (as the
Raef Coles285d44b2022-10-10 15:44:17 +0100427 * public key is the root node of the Merkle tree).
Raef Coles0a967cc2022-09-02 17:46:15 +0100428 *
Raef Coles98d6e222022-09-23 09:04:04 +0100429 * ctx The LMS private context, containing a parameter
430 * set and private key material consisting of both
431 * public and private OTS.
Raef Coles0a967cc2022-09-02 17:46:15 +0100432 *
Raef Coles98d6e222022-09-23 09:04:04 +0100433 * tree The output tree, which is 2^(H + 1) hash outputs.
434 * In the case of H=10 we have 2048 tree nodes (of
435 * which 1024 of them are leaf nodes). Note that
Raef Coles285d44b2022-10-10 15:44:17 +0100436 * because the Merkle tree root is 1-indexed, the 0
Raef Coles98d6e222022-09-23 09:04:04 +0100437 * index tree node is never used.
Raef Coles0a967cc2022-09-02 17:46:15 +0100438 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100439static int calculate_merkle_tree(const mbedtls_lms_private_t *ctx,
440 unsigned char *tree)
Raef Colesab4f8742022-09-01 12:24:31 +0100441{
442 unsigned int priv_key_idx;
443 unsigned int r_node_idx;
444 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
445
446 /* First create the leaf nodes, in ascending order */
Gilles Peskine449bd832023-01-11 14:50:10 +0100447 for (priv_key_idx = 0;
Raef Colese9479a02022-09-01 16:06:35 +0100448 priv_key_idx < MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type);
Gilles Peskine449bd832023-01-11 14:50:10 +0100449 priv_key_idx++) {
Raef Colese9479a02022-09-01 16:06:35 +0100450 r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + priv_key_idx;
Raef Colesab4f8742022-09-01 12:24:31 +0100451
Gilles Peskine449bd832023-01-11 14:50:10 +0100452 ret = create_merkle_leaf_value(&ctx->params,
453 ctx->ots_public_keys[priv_key_idx].public_key,
454 r_node_idx,
455 &tree[r_node_idx * MBEDTLS_LMS_M_NODE_BYTES(
456 ctx->params.type)]);
457 if (ret != 0) {
458 return ret;
Raef Colesab4f8742022-09-01 12:24:31 +0100459 }
460 }
461
462 /* Then the internal nodes, in reverse order so that we can guarantee the
463 * parent has been created */
Gilles Peskine449bd832023-01-11 14:50:10 +0100464 for (r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) - 1;
Raef Colese9479a02022-09-01 16:06:35 +0100465 r_node_idx > 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100466 r_node_idx--) {
467 ret = create_merkle_internal_value(&ctx->params,
468 &tree[(r_node_idx * 2) *
469 MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)],
470 &tree[(r_node_idx * 2 + 1) *
471 MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)],
472 r_node_idx,
473 &tree[r_node_idx *
474 MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)]);
475 if (ret != 0) {
476 return ret;
Raef Colesab4f8742022-09-01 12:24:31 +0100477 }
478 }
479
Gilles Peskine449bd832023-01-11 14:50:10 +0100480 return 0;
Raef Colesab4f8742022-09-01 12:24:31 +0100481}
482
Raef Coles285d44b2022-10-10 15:44:17 +0100483/* Calculate a path from a leaf node of the Merkle tree to the root of the tree,
Raef Coles0a967cc2022-09-02 17:46:15 +0100484 * and return the full path. This function implements RFC8554 section 5.4.1, as
Raef Coles285d44b2022-10-10 15:44:17 +0100485 * the Merkle path is the main component of an LMS signature.
Raef Coles0a967cc2022-09-02 17:46:15 +0100486 *
Raef Coles98d6e222022-09-23 09:04:04 +0100487 * ctx The LMS private context, containing a parameter
488 * set and private key material consisting of both
489 * public and private OTS.
Raef Coles0a967cc2022-09-02 17:46:15 +0100490 *
Raef Coles98d6e222022-09-23 09:04:04 +0100491 * leaf_node_id Which leaf node to calculate the path from.
Raef Coles0a967cc2022-09-02 17:46:15 +0100492 *
Raef Coles75b4c772022-10-10 13:58:28 +0100493 * path The output path, which is H hash outputs.
Raef Coles0a967cc2022-09-02 17:46:15 +0100494 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100495static int get_merkle_path(mbedtls_lms_private_t *ctx,
496 unsigned int leaf_node_id,
497 unsigned char *path)
Raef Colesab4f8742022-09-01 12:24:31 +0100498{
Moritz Fischera6a94ad2022-11-12 08:28:04 -0800499 const size_t node_bytes = MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
Raef Colesab4f8742022-09-01 12:24:31 +0100500 unsigned int curr_node_id = leaf_node_id;
501 unsigned int adjacent_node_id;
Moritz Fischera6a94ad2022-11-12 08:28:04 -0800502 unsigned char *tree = NULL;
Raef Colesab4f8742022-09-01 12:24:31 +0100503 unsigned int height;
504 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
505
Gilles Peskine449bd832023-01-11 14:50:10 +0100506 tree = mbedtls_calloc(MERKLE_TREE_NODE_AM(ctx->params.type),
507 node_bytes);
508 if (tree == NULL) {
Moritz Fischera6a94ad2022-11-12 08:28:04 -0800509 return MBEDTLS_ERR_LMS_ALLOC_FAILED;
510 }
511
Gilles Peskine449bd832023-01-11 14:50:10 +0100512 ret = calculate_merkle_tree(ctx, tree);
513 if (ret != 0) {
Raef Coles142e5772022-10-12 10:47:27 +0100514 goto exit;
Raef Colesab4f8742022-09-01 12:24:31 +0100515 }
516
Gilles Peskine449bd832023-01-11 14:50:10 +0100517 for (height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT(ctx->params.type);
518 height++) {
Raef Colesab4f8742022-09-01 12:24:31 +0100519 adjacent_node_id = curr_node_id ^ 1;
520
Gilles Peskine449bd832023-01-11 14:50:10 +0100521 memcpy(&path[height * node_bytes],
522 &tree[adjacent_node_id * node_bytes], node_bytes);
Raef Colesab4f8742022-09-01 12:24:31 +0100523
Gilles Peskine449bd832023-01-11 14:50:10 +0100524 curr_node_id >>= 1;
Raef Colesab4f8742022-09-01 12:24:31 +0100525 }
526
Raef Coles142e5772022-10-12 10:47:27 +0100527 ret = 0;
528
529exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100530 mbedtls_platform_zeroize(tree, node_bytes *
531 MERKLE_TREE_NODE_AM(ctx->params.type));
532 mbedtls_free(tree);
Raef Coles142e5772022-10-12 10:47:27 +0100533
Gilles Peskine449bd832023-01-11 14:50:10 +0100534 return ret;
Raef Colesab4f8742022-09-01 12:24:31 +0100535}
536
Gilles Peskine449bd832023-01-11 14:50:10 +0100537void mbedtls_lms_private_init(mbedtls_lms_private_t *ctx)
Raef Coles8ff6df52021-07-21 12:42:15 +0100538{
Gilles Peskine449bd832023-01-11 14:50:10 +0100539 memset(ctx, 0, sizeof(*ctx));
Raef Coles01c71a12022-08-31 15:55:00 +0100540}
Raef Coles8ff6df52021-07-21 12:42:15 +0100541
Gilles Peskine449bd832023-01-11 14:50:10 +0100542void mbedtls_lms_private_free(mbedtls_lms_private_t *ctx)
Raef Coles01c71a12022-08-31 15:55:00 +0100543{
544 unsigned int idx;
545
Gilles Peskine449bd832023-01-11 14:50:10 +0100546 if (ctx->have_private_key) {
547 if (ctx->ots_private_keys != NULL) {
548 for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
549 mbedtls_lmots_private_free(&ctx->ots_private_keys[idx]);
Raef Colescbd02ad2022-10-13 14:11:49 +0100550 }
Raef Coles01c71a12022-08-31 15:55:00 +0100551 }
552
Gilles Peskine449bd832023-01-11 14:50:10 +0100553 if (ctx->ots_public_keys != NULL) {
554 for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
555 mbedtls_lmots_public_free(&ctx->ots_public_keys[idx]);
Raef Colescbd02ad2022-10-13 14:11:49 +0100556 }
557 }
558
Gilles Peskine449bd832023-01-11 14:50:10 +0100559 mbedtls_free(ctx->ots_private_keys);
560 mbedtls_free(ctx->ots_public_keys);
Raef Coles8ff6df52021-07-21 12:42:15 +0100561 }
562
Gilles Peskine449bd832023-01-11 14:50:10 +0100563 mbedtls_platform_zeroize(ctx, sizeof(*ctx));
Raef Coles01c71a12022-08-31 15:55:00 +0100564}
Raef Coles8ff6df52021-07-21 12:42:15 +0100565
Raef Coles01c71a12022-08-31 15:55:00 +0100566
Gilles Peskine449bd832023-01-11 14:50:10 +0100567int mbedtls_lms_generate_private_key(mbedtls_lms_private_t *ctx,
568 mbedtls_lms_algorithm_type_t type,
569 mbedtls_lmots_algorithm_type_t otstype,
570 int (*f_rng)(void *, unsigned char *, size_t),
571 void *p_rng, const unsigned char *seed,
572 size_t seed_size)
Raef Coles01c71a12022-08-31 15:55:00 +0100573{
574 unsigned int idx = 0;
Raef Coles01c71a12022-08-31 15:55:00 +0100575 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
576
Gilles Peskine449bd832023-01-11 14:50:10 +0100577 if (type != MBEDTLS_LMS_SHA256_M32_H10) {
578 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100579 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100580
Gilles Peskine449bd832023-01-11 14:50:10 +0100581 if (otstype != MBEDTLS_LMOTS_SHA256_N32_W8) {
582 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100583 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100584
Gilles Peskine449bd832023-01-11 14:50:10 +0100585 if (ctx->have_private_key) {
586 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles01c71a12022-08-31 15:55:00 +0100587 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100588
Raef Colesf5632d32022-09-01 09:56:52 +0100589 ctx->params.type = type;
590 ctx->params.otstype = otstype;
Raef Colescbd02ad2022-10-13 14:11:49 +0100591 ctx->have_private_key = 1;
Raef Coles01c71a12022-08-31 15:55:00 +0100592
Gilles Peskine449bd832023-01-11 14:50:10 +0100593 ret = f_rng(p_rng,
594 ctx->params.I_key_identifier,
595 MBEDTLS_LMOTS_I_KEY_ID_LEN);
596 if (ret != 0) {
Raef Coles3f6cdd72022-10-07 14:07:59 +0100597 goto exit;
598 }
Raef Coles01c71a12022-08-31 15:55:00 +0100599
Raef Coles45c4ff92022-10-12 15:22:48 +0100600 /* Requires a cast to size_t to avoid an implicit cast warning on certain
601 * platforms (particularly Windows) */
Gilles Peskine449bd832023-01-11 14:50:10 +0100602 ctx->ots_private_keys = mbedtls_calloc((size_t) MERKLE_TREE_LEAF_NODE_AM(ctx->params.type),
603 sizeof(*ctx->ots_private_keys));
604 if (ctx->ots_private_keys == NULL) {
Raef Coles01c71a12022-08-31 15:55:00 +0100605 ret = MBEDTLS_ERR_LMS_ALLOC_FAILED;
606 goto exit;
607 }
608
Raef Coles45c4ff92022-10-12 15:22:48 +0100609 /* Requires a cast to size_t to avoid an implicit cast warning on certain
610 * platforms (particularly Windows) */
Gilles Peskine449bd832023-01-11 14:50:10 +0100611 ctx->ots_public_keys = mbedtls_calloc((size_t) MERKLE_TREE_LEAF_NODE_AM(ctx->params.type),
612 sizeof(*ctx->ots_public_keys));
613 if (ctx->ots_public_keys == NULL) {
Raef Coles01c71a12022-08-31 15:55:00 +0100614 ret = MBEDTLS_ERR_LMS_ALLOC_FAILED;
615 goto exit;
616 }
617
Gilles Peskine449bd832023-01-11 14:50:10 +0100618 for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
619 mbedtls_lmots_private_init(&ctx->ots_private_keys[idx]);
620 mbedtls_lmots_public_init(&ctx->ots_public_keys[idx]);
Raef Coles01c71a12022-08-31 15:55:00 +0100621 }
622
623
Gilles Peskine449bd832023-01-11 14:50:10 +0100624 for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
625 ret = mbedtls_lmots_generate_private_key(&ctx->ots_private_keys[idx],
626 otstype,
627 ctx->params.I_key_identifier,
628 idx, seed, seed_size);
629 if (ret != 0) {
Raef Coles01c71a12022-08-31 15:55:00 +0100630 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100631 }
Raef Coles01c71a12022-08-31 15:55:00 +0100632
Gilles Peskine449bd832023-01-11 14:50:10 +0100633 ret = mbedtls_lmots_calculate_public_key(&ctx->ots_public_keys[idx],
634 &ctx->ots_private_keys[idx]);
635 if (ret != 0) {
Raef Coles01c71a12022-08-31 15:55:00 +0100636 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100637 }
Raef Coles01c71a12022-08-31 15:55:00 +0100638 }
639
Raef Colesf5632d32022-09-01 09:56:52 +0100640 ctx->q_next_usable_key = 0;
Raef Coles01c71a12022-08-31 15:55:00 +0100641
642exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100643 if (ret != 0) {
Raef Colesdc8fb792022-10-07 13:27:54 +0100644 mbedtls_lms_private_free(ctx);
Raef Coles01c71a12022-08-31 15:55:00 +0100645 }
Raef Coles8ff6df52021-07-21 12:42:15 +0100646
Gilles Peskine449bd832023-01-11 14:50:10 +0100647 return ret;
Raef Coles8ff6df52021-07-21 12:42:15 +0100648}
649
Gilles Peskine449bd832023-01-11 14:50:10 +0100650int mbedtls_lms_calculate_public_key(mbedtls_lms_public_t *ctx,
651 const mbedtls_lms_private_t *priv_ctx)
Raef Coles8ff6df52021-07-21 12:42:15 +0100652{
Moritz Fischera6a94ad2022-11-12 08:28:04 -0800653 const size_t node_bytes = MBEDTLS_LMS_M_NODE_BYTES(priv_ctx->params.type);
Raef Coles8ff6df52021-07-21 12:42:15 +0100654 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Moritz Fischera6a94ad2022-11-12 08:28:04 -0800655 unsigned char *tree = NULL;
Raef Coles8ff6df52021-07-21 12:42:15 +0100656
Gilles Peskine449bd832023-01-11 14:50:10 +0100657 if (!priv_ctx->have_private_key) {
658 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100659 }
660
Gilles Peskine449bd832023-01-11 14:50:10 +0100661 if (priv_ctx->params.type
662 != MBEDTLS_LMS_SHA256_M32_H10) {
663 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100664 }
665
Gilles Peskine449bd832023-01-11 14:50:10 +0100666 if (priv_ctx->params.otstype
667 != MBEDTLS_LMOTS_SHA256_N32_W8) {
668 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100669 }
670
Gilles Peskine449bd832023-01-11 14:50:10 +0100671 tree = mbedtls_calloc(MERKLE_TREE_NODE_AM(priv_ctx->params.type),
672 node_bytes);
673 if (tree == NULL) {
Moritz Fischera6a94ad2022-11-12 08:28:04 -0800674 return MBEDTLS_ERR_LMS_ALLOC_FAILED;
675 }
676
Gilles Peskine449bd832023-01-11 14:50:10 +0100677 memcpy(&ctx->params, &priv_ctx->params,
678 sizeof(mbedtls_lmots_parameters_t));
Raef Coles8ff6df52021-07-21 12:42:15 +0100679
Gilles Peskine449bd832023-01-11 14:50:10 +0100680 ret = calculate_merkle_tree(priv_ctx, tree);
681 if (ret != 0) {
Raef Coles142e5772022-10-12 10:47:27 +0100682 goto exit;
Raef Coles8ff6df52021-07-21 12:42:15 +0100683 }
684
685 /* Root node is always at position 1, due to 1-based indexing */
Gilles Peskine449bd832023-01-11 14:50:10 +0100686 memcpy(ctx->T_1_pub_key, &tree[node_bytes], node_bytes);
Raef Coles8ff6df52021-07-21 12:42:15 +0100687
Raef Colesf5632d32022-09-01 09:56:52 +0100688 ctx->have_public_key = 1;
Raef Coles8ff6df52021-07-21 12:42:15 +0100689
Raef Coles142e5772022-10-12 10:47:27 +0100690 ret = 0;
691
692exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100693 mbedtls_platform_zeroize(tree, node_bytes *
694 MERKLE_TREE_NODE_AM(priv_ctx->params.type));
695 mbedtls_free(tree);
Raef Coles142e5772022-10-12 10:47:27 +0100696
Gilles Peskine449bd832023-01-11 14:50:10 +0100697 return ret;
Raef Coles8ff6df52021-07-21 12:42:15 +0100698}
699
Raef Coles01c71a12022-08-31 15:55:00 +0100700
Gilles Peskine449bd832023-01-11 14:50:10 +0100701int mbedtls_lms_sign(mbedtls_lms_private_t *ctx,
702 int (*f_rng)(void *, unsigned char *, size_t),
703 void *p_rng, const unsigned char *msg,
704 unsigned int msg_size, unsigned char *sig, size_t sig_size,
705 size_t *sig_len)
Raef Coles01c71a12022-08-31 15:55:00 +0100706{
707 uint32_t q_leaf_identifier;
Raef Coles8ff6df52021-07-21 12:42:15 +0100708 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
709
Gilles Peskine449bd832023-01-11 14:50:10 +0100710 if (!ctx->have_private_key) {
711 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100712 }
713
Gilles Peskine449bd832023-01-11 14:50:10 +0100714 if (sig_size < MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)) {
715 return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
Raef Coles01c71a12022-08-31 15:55:00 +0100716 }
717
Gilles Peskine449bd832023-01-11 14:50:10 +0100718 if (ctx->params.type != MBEDTLS_LMS_SHA256_M32_H10) {
719 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100720 }
721
Gilles Peskine449bd832023-01-11 14:50:10 +0100722 if (ctx->params.otstype
723 != MBEDTLS_LMOTS_SHA256_N32_W8) {
724 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles8ff6df52021-07-21 12:42:15 +0100725 }
726
Gilles Peskine449bd832023-01-11 14:50:10 +0100727 if (ctx->q_next_usable_key >= MERKLE_TREE_LEAF_NODE_AM(ctx->params.type)) {
728 return MBEDTLS_ERR_LMS_OUT_OF_PRIVATE_KEYS;
Raef Coles8ff6df52021-07-21 12:42:15 +0100729 }
730
731
Raef Colesf5632d32022-09-01 09:56:52 +0100732 q_leaf_identifier = ctx->q_next_usable_key;
Raef Coles01c71a12022-08-31 15:55:00 +0100733 /* This new value must _always_ be written back to the disk before the
734 * signature is returned.
735 */
Raef Colesf5632d32022-09-01 09:56:52 +0100736 ctx->q_next_usable_key += 1;
Raef Coles8ff6df52021-07-21 12:42:15 +0100737
Gilles Peskine449bd832023-01-11 14:50:10 +0100738 if (MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)
739 < SIG_OTS_SIG_OFFSET) {
740 return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
Raef Coles1fb2f322022-10-10 11:23:07 +0100741 }
742
Gilles Peskine449bd832023-01-11 14:50:10 +0100743 ret = mbedtls_lmots_sign(&ctx->ots_private_keys[q_leaf_identifier],
744 f_rng,
745 p_rng,
746 msg,
747 msg_size,
748 sig + SIG_OTS_SIG_OFFSET,
749 MBEDTLS_LMS_SIG_LEN(ctx->params.type,
750 ctx->params.otstype) - SIG_OTS_SIG_OFFSET,
751 NULL);
752 if (ret != 0) {
753 return ret;
Raef Coles8ff6df52021-07-21 12:42:15 +0100754 }
755
Gilles Peskine449bd832023-01-11 14:50:10 +0100756 mbedtls_lms_unsigned_int_to_network_bytes(ctx->params.type,
757 MBEDTLS_LMS_TYPE_LEN,
758 sig + SIG_TYPE_OFFSET(ctx->params.otstype));
759 mbedtls_lms_unsigned_int_to_network_bytes(q_leaf_identifier,
760 MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
761 sig + SIG_Q_LEAF_ID_OFFSET);
Raef Coles01c71a12022-08-31 15:55:00 +0100762
Gilles Peskine449bd832023-01-11 14:50:10 +0100763 ret = get_merkle_path(ctx,
764 MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + q_leaf_identifier,
765 sig + SIG_PATH_OFFSET(ctx->params.otstype));
766 if (ret != 0) {
767 return ret;
Raef Coles01c71a12022-08-31 15:55:00 +0100768 }
769
Gilles Peskine449bd832023-01-11 14:50:10 +0100770 if (sig_len != NULL) {
Raef Colese9479a02022-09-01 16:06:35 +0100771 *sig_len = MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype);
Raef Coles01c71a12022-08-31 15:55:00 +0100772 }
773
774
Gilles Peskine449bd832023-01-11 14:50:10 +0100775 return 0;
Raef Coles8ff6df52021-07-21 12:42:15 +0100776}
777
Raef Coles5127e852022-10-07 10:35:56 +0100778#endif /* defined(MBEDTLS_LMS_PRIVATE) */
779#endif /* defined(MBEDTLS_LMS_C) */