1a8e1175bSopenharmony_ci/*
2a8e1175bSopenharmony_ci *  The LMS stateful-hash public-key signature scheme
3a8e1175bSopenharmony_ci *
4a8e1175bSopenharmony_ci *  Copyright The Mbed TLS Contributors
5a8e1175bSopenharmony_ci *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6a8e1175bSopenharmony_ci */
7a8e1175bSopenharmony_ci
8a8e1175bSopenharmony_ci/*
9a8e1175bSopenharmony_ci *  The following sources were referenced in the design of this implementation
10a8e1175bSopenharmony_ci *  of the LMS algorithm:
11a8e1175bSopenharmony_ci *
12a8e1175bSopenharmony_ci *  [1] IETF RFC8554
13a8e1175bSopenharmony_ci *      D. McGrew, M. Curcio, S.Fluhrer
14a8e1175bSopenharmony_ci *      https://datatracker.ietf.org/doc/html/rfc8554
15a8e1175bSopenharmony_ci *
16a8e1175bSopenharmony_ci *  [2] NIST Special Publication 800-208
17a8e1175bSopenharmony_ci *      David A. Cooper et. al.
18a8e1175bSopenharmony_ci *      https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-208.pdf
19a8e1175bSopenharmony_ci */
20a8e1175bSopenharmony_ci
21a8e1175bSopenharmony_ci#include "common.h"
22a8e1175bSopenharmony_ci
23a8e1175bSopenharmony_ci#if defined(MBEDTLS_LMS_C)
24a8e1175bSopenharmony_ci
25a8e1175bSopenharmony_ci#include <string.h>
26a8e1175bSopenharmony_ci
27a8e1175bSopenharmony_ci#include "lmots.h"
28a8e1175bSopenharmony_ci
29a8e1175bSopenharmony_ci#include "psa/crypto.h"
30a8e1175bSopenharmony_ci#include "psa_util_internal.h"
31a8e1175bSopenharmony_ci#include "mbedtls/lms.h"
32a8e1175bSopenharmony_ci#include "mbedtls/error.h"
33a8e1175bSopenharmony_ci#include "mbedtls/platform_util.h"
34a8e1175bSopenharmony_ci
35a8e1175bSopenharmony_ci#include "mbedtls/platform.h"
36a8e1175bSopenharmony_ci
37a8e1175bSopenharmony_ci/* Define a local translating function to save code size by not using too many
38a8e1175bSopenharmony_ci * arguments in each translating place. */
39a8e1175bSopenharmony_cistatic int local_err_translation(psa_status_t status)
40a8e1175bSopenharmony_ci{
41a8e1175bSopenharmony_ci    return psa_status_to_mbedtls(status, psa_to_lms_errors,
42a8e1175bSopenharmony_ci                                 ARRAY_LENGTH(psa_to_lms_errors),
43a8e1175bSopenharmony_ci                                 psa_generic_status_to_mbedtls);
44a8e1175bSopenharmony_ci}
45a8e1175bSopenharmony_ci#define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status)
46a8e1175bSopenharmony_ci
47a8e1175bSopenharmony_ci#define SIG_Q_LEAF_ID_OFFSET     (0)
48a8e1175bSopenharmony_ci#define SIG_OTS_SIG_OFFSET       (SIG_Q_LEAF_ID_OFFSET + \
49a8e1175bSopenharmony_ci                                  MBEDTLS_LMOTS_Q_LEAF_ID_LEN)
50a8e1175bSopenharmony_ci#define SIG_TYPE_OFFSET(otstype) (SIG_OTS_SIG_OFFSET   + \
51a8e1175bSopenharmony_ci                                  MBEDTLS_LMOTS_SIG_LEN(otstype))
52a8e1175bSopenharmony_ci#define SIG_PATH_OFFSET(otstype) (SIG_TYPE_OFFSET(otstype) + \
53a8e1175bSopenharmony_ci                                  MBEDTLS_LMS_TYPE_LEN)
54a8e1175bSopenharmony_ci
55a8e1175bSopenharmony_ci#define PUBLIC_KEY_TYPE_OFFSET      (0)
56a8e1175bSopenharmony_ci#define PUBLIC_KEY_OTSTYPE_OFFSET   (PUBLIC_KEY_TYPE_OFFSET + \
57a8e1175bSopenharmony_ci                                     MBEDTLS_LMS_TYPE_LEN)
58a8e1175bSopenharmony_ci#define PUBLIC_KEY_I_KEY_ID_OFFSET  (PUBLIC_KEY_OTSTYPE_OFFSET  + \
59a8e1175bSopenharmony_ci                                     MBEDTLS_LMOTS_TYPE_LEN)
60a8e1175bSopenharmony_ci#define PUBLIC_KEY_ROOT_NODE_OFFSET (PUBLIC_KEY_I_KEY_ID_OFFSET + \
61a8e1175bSopenharmony_ci                                     MBEDTLS_LMOTS_I_KEY_ID_LEN)
62a8e1175bSopenharmony_ci
63a8e1175bSopenharmony_ci
64a8e1175bSopenharmony_ci/* Currently only support H=10 */
65a8e1175bSopenharmony_ci#define H_TREE_HEIGHT_MAX                  10
66a8e1175bSopenharmony_ci#define MERKLE_TREE_NODE_AM(type)          ((size_t) 1 << (MBEDTLS_LMS_H_TREE_HEIGHT(type) + 1u))
67a8e1175bSopenharmony_ci#define MERKLE_TREE_LEAF_NODE_AM(type)     ((size_t) 1 << MBEDTLS_LMS_H_TREE_HEIGHT(type))
68a8e1175bSopenharmony_ci#define MERKLE_TREE_INTERNAL_NODE_AM(type) ((unsigned int) \
69a8e1175bSopenharmony_ci                                            (1u << MBEDTLS_LMS_H_TREE_HEIGHT(type)))
70a8e1175bSopenharmony_ci
71a8e1175bSopenharmony_ci#define D_CONST_LEN           (2)
72a8e1175bSopenharmony_cistatic const unsigned char D_LEAF_CONSTANT_BYTES[D_CONST_LEN] = { 0x82, 0x82 };
73a8e1175bSopenharmony_cistatic const unsigned char D_INTR_CONSTANT_BYTES[D_CONST_LEN] = { 0x83, 0x83 };
74a8e1175bSopenharmony_ci
75a8e1175bSopenharmony_ci
76a8e1175bSopenharmony_ci/* Calculate the value of a leaf node of the Merkle tree (which is a hash of a
77a8e1175bSopenharmony_ci * public key and some other parameters like the leaf index). This function
78a8e1175bSopenharmony_ci * implements RFC8554 section 5.3, in the case where r >= 2^h.
79a8e1175bSopenharmony_ci *
80a8e1175bSopenharmony_ci *  params              The LMS parameter set, the underlying LMOTS
81a8e1175bSopenharmony_ci *                      parameter set, and I value which describe the key
82a8e1175bSopenharmony_ci *                      being used.
83a8e1175bSopenharmony_ci *
84a8e1175bSopenharmony_ci *  pub_key             The public key of the private whose index
85a8e1175bSopenharmony_ci *                      corresponds to the index of this leaf node. This
86a8e1175bSopenharmony_ci *                      is a hash output.
87a8e1175bSopenharmony_ci *
88a8e1175bSopenharmony_ci *  r_node_idx          The index of this node in the Merkle tree. Note
89a8e1175bSopenharmony_ci *                      that the root node of the Merkle tree is
90a8e1175bSopenharmony_ci *                      1-indexed.
91a8e1175bSopenharmony_ci *
92a8e1175bSopenharmony_ci *  out                 The output node value, which is a hash output.
93a8e1175bSopenharmony_ci */
94a8e1175bSopenharmony_cistatic int create_merkle_leaf_value(const mbedtls_lms_parameters_t *params,
95a8e1175bSopenharmony_ci                                    unsigned char *pub_key,
96a8e1175bSopenharmony_ci                                    unsigned int r_node_idx,
97a8e1175bSopenharmony_ci                                    unsigned char *out)
98a8e1175bSopenharmony_ci{
99a8e1175bSopenharmony_ci    psa_hash_operation_t op;
100a8e1175bSopenharmony_ci    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
101a8e1175bSopenharmony_ci    size_t output_hash_len;
102a8e1175bSopenharmony_ci    unsigned char r_node_idx_bytes[4];
103a8e1175bSopenharmony_ci
104a8e1175bSopenharmony_ci    op = psa_hash_operation_init();
105a8e1175bSopenharmony_ci    status = psa_hash_setup(&op, PSA_ALG_SHA_256);
106a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
107a8e1175bSopenharmony_ci        goto exit;
108a8e1175bSopenharmony_ci    }
109a8e1175bSopenharmony_ci
110a8e1175bSopenharmony_ci    status = psa_hash_update(&op, params->I_key_identifier,
111a8e1175bSopenharmony_ci                             MBEDTLS_LMOTS_I_KEY_ID_LEN);
112a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
113a8e1175bSopenharmony_ci        goto exit;
114a8e1175bSopenharmony_ci    }
115a8e1175bSopenharmony_ci
116a8e1175bSopenharmony_ci    MBEDTLS_PUT_UINT32_BE(r_node_idx, r_node_idx_bytes, 0);
117a8e1175bSopenharmony_ci    status = psa_hash_update(&op, r_node_idx_bytes, 4);
118a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
119a8e1175bSopenharmony_ci        goto exit;
120a8e1175bSopenharmony_ci    }
121a8e1175bSopenharmony_ci
122a8e1175bSopenharmony_ci    status = psa_hash_update(&op, D_LEAF_CONSTANT_BYTES, D_CONST_LEN);
123a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
124a8e1175bSopenharmony_ci        goto exit;
125a8e1175bSopenharmony_ci    }
126a8e1175bSopenharmony_ci
127a8e1175bSopenharmony_ci    status = psa_hash_update(&op, pub_key,
128a8e1175bSopenharmony_ci                             MBEDTLS_LMOTS_N_HASH_LEN(params->otstype));
129a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
130a8e1175bSopenharmony_ci        goto exit;
131a8e1175bSopenharmony_ci    }
132a8e1175bSopenharmony_ci
133a8e1175bSopenharmony_ci    status = psa_hash_finish(&op, out, MBEDTLS_LMS_M_NODE_BYTES(params->type),
134a8e1175bSopenharmony_ci                             &output_hash_len);
135a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
136a8e1175bSopenharmony_ci        goto exit;
137a8e1175bSopenharmony_ci    }
138a8e1175bSopenharmony_ci
139a8e1175bSopenharmony_ciexit:
140a8e1175bSopenharmony_ci    psa_hash_abort(&op);
141a8e1175bSopenharmony_ci
142a8e1175bSopenharmony_ci    return PSA_TO_MBEDTLS_ERR(status);
143a8e1175bSopenharmony_ci}
144a8e1175bSopenharmony_ci
145a8e1175bSopenharmony_ci/* Calculate the value of an internal node of the Merkle tree (which is a hash
146a8e1175bSopenharmony_ci * of a public key and some other parameters like the node index). This function
147a8e1175bSopenharmony_ci * implements RFC8554 section 5.3, in the case where r < 2^h.
148a8e1175bSopenharmony_ci *
149a8e1175bSopenharmony_ci *  params              The LMS parameter set, the underlying LMOTS
150a8e1175bSopenharmony_ci *                      parameter set, and I value which describe the key
151a8e1175bSopenharmony_ci *                      being used.
152a8e1175bSopenharmony_ci *
153a8e1175bSopenharmony_ci *  left_node           The value of the child of this node which is on
154a8e1175bSopenharmony_ci *                      the left-hand side. As with all nodes on the
155a8e1175bSopenharmony_ci *                      Merkle tree, this is a hash output.
156a8e1175bSopenharmony_ci *
157a8e1175bSopenharmony_ci *  right_node          The value of the child of this node which is on
158a8e1175bSopenharmony_ci *                      the right-hand side. As with all nodes on the
159a8e1175bSopenharmony_ci *                      Merkle tree, this is a hash output.
160a8e1175bSopenharmony_ci *
161a8e1175bSopenharmony_ci *  r_node_idx          The index of this node in the Merkle tree. Note
162a8e1175bSopenharmony_ci *                      that the root node of the Merkle tree is
163a8e1175bSopenharmony_ci *                      1-indexed.
164a8e1175bSopenharmony_ci *
165a8e1175bSopenharmony_ci *  out                 The output node value, which is a hash output.
166a8e1175bSopenharmony_ci */
167a8e1175bSopenharmony_cistatic int create_merkle_internal_value(const mbedtls_lms_parameters_t *params,
168a8e1175bSopenharmony_ci                                        const unsigned char *left_node,
169a8e1175bSopenharmony_ci                                        const unsigned char *right_node,
170a8e1175bSopenharmony_ci                                        unsigned int r_node_idx,
171a8e1175bSopenharmony_ci                                        unsigned char *out)
172a8e1175bSopenharmony_ci{
173a8e1175bSopenharmony_ci    psa_hash_operation_t op;
174a8e1175bSopenharmony_ci    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
175a8e1175bSopenharmony_ci    size_t output_hash_len;
176a8e1175bSopenharmony_ci    unsigned char r_node_idx_bytes[4];
177a8e1175bSopenharmony_ci
178a8e1175bSopenharmony_ci    op = psa_hash_operation_init();
179a8e1175bSopenharmony_ci    status = psa_hash_setup(&op, PSA_ALG_SHA_256);
180a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
181a8e1175bSopenharmony_ci        goto exit;
182a8e1175bSopenharmony_ci    }
183a8e1175bSopenharmony_ci
184a8e1175bSopenharmony_ci    status = psa_hash_update(&op, params->I_key_identifier,
185a8e1175bSopenharmony_ci                             MBEDTLS_LMOTS_I_KEY_ID_LEN);
186a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
187a8e1175bSopenharmony_ci        goto exit;
188a8e1175bSopenharmony_ci    }
189a8e1175bSopenharmony_ci
190a8e1175bSopenharmony_ci    MBEDTLS_PUT_UINT32_BE(r_node_idx, r_node_idx_bytes, 0);
191a8e1175bSopenharmony_ci    status = psa_hash_update(&op, r_node_idx_bytes, 4);
192a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
193a8e1175bSopenharmony_ci        goto exit;
194a8e1175bSopenharmony_ci    }
195a8e1175bSopenharmony_ci
196a8e1175bSopenharmony_ci    status = psa_hash_update(&op, D_INTR_CONSTANT_BYTES, D_CONST_LEN);
197a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
198a8e1175bSopenharmony_ci        goto exit;
199a8e1175bSopenharmony_ci    }
200a8e1175bSopenharmony_ci
201a8e1175bSopenharmony_ci    status = psa_hash_update(&op, left_node,
202a8e1175bSopenharmony_ci                             MBEDTLS_LMS_M_NODE_BYTES(params->type));
203a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
204a8e1175bSopenharmony_ci        goto exit;
205a8e1175bSopenharmony_ci    }
206a8e1175bSopenharmony_ci
207a8e1175bSopenharmony_ci    status = psa_hash_update(&op, right_node,
208a8e1175bSopenharmony_ci                             MBEDTLS_LMS_M_NODE_BYTES(params->type));
209a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
210a8e1175bSopenharmony_ci        goto exit;
211a8e1175bSopenharmony_ci    }
212a8e1175bSopenharmony_ci
213a8e1175bSopenharmony_ci    status = psa_hash_finish(&op, out, MBEDTLS_LMS_M_NODE_BYTES(params->type),
214a8e1175bSopenharmony_ci                             &output_hash_len);
215a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
216a8e1175bSopenharmony_ci        goto exit;
217a8e1175bSopenharmony_ci    }
218a8e1175bSopenharmony_ci
219a8e1175bSopenharmony_ciexit:
220a8e1175bSopenharmony_ci    psa_hash_abort(&op);
221a8e1175bSopenharmony_ci
222a8e1175bSopenharmony_ci    return PSA_TO_MBEDTLS_ERR(status);
223a8e1175bSopenharmony_ci}
224a8e1175bSopenharmony_ci
225a8e1175bSopenharmony_civoid mbedtls_lms_public_init(mbedtls_lms_public_t *ctx)
226a8e1175bSopenharmony_ci{
227a8e1175bSopenharmony_ci    memset(ctx, 0, sizeof(*ctx));
228a8e1175bSopenharmony_ci}
229a8e1175bSopenharmony_ci
230a8e1175bSopenharmony_civoid mbedtls_lms_public_free(mbedtls_lms_public_t *ctx)
231a8e1175bSopenharmony_ci{
232a8e1175bSopenharmony_ci    mbedtls_platform_zeroize(ctx, sizeof(*ctx));
233a8e1175bSopenharmony_ci}
234a8e1175bSopenharmony_ci
235a8e1175bSopenharmony_ciint mbedtls_lms_import_public_key(mbedtls_lms_public_t *ctx,
236a8e1175bSopenharmony_ci                                  const unsigned char *key, size_t key_size)
237a8e1175bSopenharmony_ci{
238a8e1175bSopenharmony_ci    mbedtls_lms_algorithm_type_t type;
239a8e1175bSopenharmony_ci    mbedtls_lmots_algorithm_type_t otstype;
240a8e1175bSopenharmony_ci
241a8e1175bSopenharmony_ci    type = (mbedtls_lms_algorithm_type_t) MBEDTLS_GET_UINT32_BE(key, PUBLIC_KEY_TYPE_OFFSET);
242a8e1175bSopenharmony_ci    if (type != MBEDTLS_LMS_SHA256_M32_H10) {
243a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
244a8e1175bSopenharmony_ci    }
245a8e1175bSopenharmony_ci    ctx->params.type = type;
246a8e1175bSopenharmony_ci
247a8e1175bSopenharmony_ci    if (key_size != MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type)) {
248a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
249a8e1175bSopenharmony_ci    }
250a8e1175bSopenharmony_ci
251a8e1175bSopenharmony_ci    otstype = (mbedtls_lmots_algorithm_type_t)
252a8e1175bSopenharmony_ci              MBEDTLS_GET_UINT32_BE(key, PUBLIC_KEY_OTSTYPE_OFFSET);
253a8e1175bSopenharmony_ci    if (otstype != MBEDTLS_LMOTS_SHA256_N32_W8) {
254a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
255a8e1175bSopenharmony_ci    }
256a8e1175bSopenharmony_ci    ctx->params.otstype = otstype;
257a8e1175bSopenharmony_ci
258a8e1175bSopenharmony_ci    memcpy(ctx->params.I_key_identifier,
259a8e1175bSopenharmony_ci           key + PUBLIC_KEY_I_KEY_ID_OFFSET,
260a8e1175bSopenharmony_ci           MBEDTLS_LMOTS_I_KEY_ID_LEN);
261a8e1175bSopenharmony_ci    memcpy(ctx->T_1_pub_key, key + PUBLIC_KEY_ROOT_NODE_OFFSET,
262a8e1175bSopenharmony_ci           MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type));
263a8e1175bSopenharmony_ci
264a8e1175bSopenharmony_ci    ctx->have_public_key = 1;
265a8e1175bSopenharmony_ci
266a8e1175bSopenharmony_ci    return 0;
267a8e1175bSopenharmony_ci}
268a8e1175bSopenharmony_ci
269a8e1175bSopenharmony_ciint mbedtls_lms_export_public_key(const mbedtls_lms_public_t *ctx,
270a8e1175bSopenharmony_ci                                  unsigned char *key,
271a8e1175bSopenharmony_ci                                  size_t key_size, size_t *key_len)
272a8e1175bSopenharmony_ci{
273a8e1175bSopenharmony_ci    if (key_size < MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type)) {
274a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
275a8e1175bSopenharmony_ci    }
276a8e1175bSopenharmony_ci
277a8e1175bSopenharmony_ci    if (!ctx->have_public_key) {
278a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
279a8e1175bSopenharmony_ci    }
280a8e1175bSopenharmony_ci
281a8e1175bSopenharmony_ci    MBEDTLS_PUT_UINT32_BE(ctx->params.type, key, PUBLIC_KEY_TYPE_OFFSET);
282a8e1175bSopenharmony_ci    MBEDTLS_PUT_UINT32_BE(ctx->params.otstype, key, PUBLIC_KEY_OTSTYPE_OFFSET);
283a8e1175bSopenharmony_ci    memcpy(key + PUBLIC_KEY_I_KEY_ID_OFFSET,
284a8e1175bSopenharmony_ci           ctx->params.I_key_identifier,
285a8e1175bSopenharmony_ci           MBEDTLS_LMOTS_I_KEY_ID_LEN);
286a8e1175bSopenharmony_ci    memcpy(key +PUBLIC_KEY_ROOT_NODE_OFFSET,
287a8e1175bSopenharmony_ci           ctx->T_1_pub_key,
288a8e1175bSopenharmony_ci           MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type));
289a8e1175bSopenharmony_ci
290a8e1175bSopenharmony_ci    if (key_len != NULL) {
291a8e1175bSopenharmony_ci        *key_len = MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type);
292a8e1175bSopenharmony_ci    }
293a8e1175bSopenharmony_ci
294a8e1175bSopenharmony_ci    return 0;
295a8e1175bSopenharmony_ci}
296a8e1175bSopenharmony_ci
297a8e1175bSopenharmony_ciint mbedtls_lms_verify(const mbedtls_lms_public_t *ctx,
298a8e1175bSopenharmony_ci                       const unsigned char *msg, size_t msg_size,
299a8e1175bSopenharmony_ci                       const unsigned char *sig, size_t sig_size)
300a8e1175bSopenharmony_ci{
301a8e1175bSopenharmony_ci    unsigned int q_leaf_identifier;
302a8e1175bSopenharmony_ci    unsigned char Kc_candidate_ots_pub_key[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
303a8e1175bSopenharmony_ci    unsigned char Tc_candidate_root_node[MBEDTLS_LMS_M_NODE_BYTES_MAX];
304a8e1175bSopenharmony_ci    unsigned int height;
305a8e1175bSopenharmony_ci    unsigned int curr_node_id;
306a8e1175bSopenharmony_ci    unsigned int parent_node_id;
307a8e1175bSopenharmony_ci    const unsigned char *left_node;
308a8e1175bSopenharmony_ci    const unsigned char *right_node;
309a8e1175bSopenharmony_ci    mbedtls_lmots_parameters_t ots_params;
310a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
311a8e1175bSopenharmony_ci
312a8e1175bSopenharmony_ci    if (!ctx->have_public_key) {
313a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
314a8e1175bSopenharmony_ci    }
315a8e1175bSopenharmony_ci
316a8e1175bSopenharmony_ci    if (ctx->params.type
317a8e1175bSopenharmony_ci        != MBEDTLS_LMS_SHA256_M32_H10) {
318a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
319a8e1175bSopenharmony_ci    }
320a8e1175bSopenharmony_ci
321a8e1175bSopenharmony_ci    if (ctx->params.otstype
322a8e1175bSopenharmony_ci        != MBEDTLS_LMOTS_SHA256_N32_W8) {
323a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
324a8e1175bSopenharmony_ci    }
325a8e1175bSopenharmony_ci
326a8e1175bSopenharmony_ci    if (sig_size != MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)) {
327a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_VERIFY_FAILED;
328a8e1175bSopenharmony_ci    }
329a8e1175bSopenharmony_ci
330a8e1175bSopenharmony_ci    if (sig_size < SIG_OTS_SIG_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
331a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_VERIFY_FAILED;
332a8e1175bSopenharmony_ci    }
333a8e1175bSopenharmony_ci
334a8e1175bSopenharmony_ci    if (MBEDTLS_GET_UINT32_BE(sig, SIG_OTS_SIG_OFFSET + MBEDTLS_LMOTS_SIG_TYPE_OFFSET)
335a8e1175bSopenharmony_ci        != MBEDTLS_LMOTS_SHA256_N32_W8) {
336a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_VERIFY_FAILED;
337a8e1175bSopenharmony_ci    }
338a8e1175bSopenharmony_ci
339a8e1175bSopenharmony_ci    if (sig_size < SIG_TYPE_OFFSET(ctx->params.otstype) + MBEDTLS_LMS_TYPE_LEN) {
340a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_VERIFY_FAILED;
341a8e1175bSopenharmony_ci    }
342a8e1175bSopenharmony_ci
343a8e1175bSopenharmony_ci    if (MBEDTLS_GET_UINT32_BE(sig, SIG_TYPE_OFFSET(ctx->params.otstype))
344a8e1175bSopenharmony_ci        != MBEDTLS_LMS_SHA256_M32_H10) {
345a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_VERIFY_FAILED;
346a8e1175bSopenharmony_ci    }
347a8e1175bSopenharmony_ci
348a8e1175bSopenharmony_ci
349a8e1175bSopenharmony_ci    q_leaf_identifier = MBEDTLS_GET_UINT32_BE(sig, SIG_Q_LEAF_ID_OFFSET);
350a8e1175bSopenharmony_ci
351a8e1175bSopenharmony_ci    if (q_leaf_identifier >= MERKLE_TREE_LEAF_NODE_AM(ctx->params.type)) {
352a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_VERIFY_FAILED;
353a8e1175bSopenharmony_ci    }
354a8e1175bSopenharmony_ci
355a8e1175bSopenharmony_ci    memcpy(ots_params.I_key_identifier,
356a8e1175bSopenharmony_ci           ctx->params.I_key_identifier,
357a8e1175bSopenharmony_ci           MBEDTLS_LMOTS_I_KEY_ID_LEN);
358a8e1175bSopenharmony_ci    MBEDTLS_PUT_UINT32_BE(q_leaf_identifier, ots_params.q_leaf_identifier, 0);
359a8e1175bSopenharmony_ci    ots_params.type = ctx->params.otstype;
360a8e1175bSopenharmony_ci
361a8e1175bSopenharmony_ci    ret = mbedtls_lmots_calculate_public_key_candidate(&ots_params,
362a8e1175bSopenharmony_ci                                                       msg,
363a8e1175bSopenharmony_ci                                                       msg_size,
364a8e1175bSopenharmony_ci                                                       sig + SIG_OTS_SIG_OFFSET,
365a8e1175bSopenharmony_ci                                                       MBEDTLS_LMOTS_SIG_LEN(ctx->params.otstype),
366a8e1175bSopenharmony_ci                                                       Kc_candidate_ots_pub_key,
367a8e1175bSopenharmony_ci                                                       sizeof(Kc_candidate_ots_pub_key),
368a8e1175bSopenharmony_ci                                                       NULL);
369a8e1175bSopenharmony_ci    if (ret != 0) {
370a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_VERIFY_FAILED;
371a8e1175bSopenharmony_ci    }
372a8e1175bSopenharmony_ci
373a8e1175bSopenharmony_ci    create_merkle_leaf_value(
374a8e1175bSopenharmony_ci        &ctx->params,
375a8e1175bSopenharmony_ci        Kc_candidate_ots_pub_key,
376a8e1175bSopenharmony_ci        MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + q_leaf_identifier,
377a8e1175bSopenharmony_ci        Tc_candidate_root_node);
378a8e1175bSopenharmony_ci
379a8e1175bSopenharmony_ci    curr_node_id = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) +
380a8e1175bSopenharmony_ci                   q_leaf_identifier;
381a8e1175bSopenharmony_ci
382a8e1175bSopenharmony_ci    for (height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT(ctx->params.type);
383a8e1175bSopenharmony_ci         height++) {
384a8e1175bSopenharmony_ci        parent_node_id = curr_node_id / 2;
385a8e1175bSopenharmony_ci
386a8e1175bSopenharmony_ci        /* Left/right node ordering matters for the hash */
387a8e1175bSopenharmony_ci        if (curr_node_id & 1) {
388a8e1175bSopenharmony_ci            left_node = sig + SIG_PATH_OFFSET(ctx->params.otstype) +
389a8e1175bSopenharmony_ci                        height * MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
390a8e1175bSopenharmony_ci            right_node = Tc_candidate_root_node;
391a8e1175bSopenharmony_ci        } else {
392a8e1175bSopenharmony_ci            left_node = Tc_candidate_root_node;
393a8e1175bSopenharmony_ci            right_node = sig + SIG_PATH_OFFSET(ctx->params.otstype) +
394a8e1175bSopenharmony_ci                         height * MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
395a8e1175bSopenharmony_ci        }
396a8e1175bSopenharmony_ci
397a8e1175bSopenharmony_ci        create_merkle_internal_value(&ctx->params, left_node, right_node,
398a8e1175bSopenharmony_ci                                     parent_node_id, Tc_candidate_root_node);
399a8e1175bSopenharmony_ci
400a8e1175bSopenharmony_ci        curr_node_id /= 2;
401a8e1175bSopenharmony_ci    }
402a8e1175bSopenharmony_ci
403a8e1175bSopenharmony_ci    if (memcmp(Tc_candidate_root_node, ctx->T_1_pub_key,
404a8e1175bSopenharmony_ci               MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type))) {
405a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_VERIFY_FAILED;
406a8e1175bSopenharmony_ci    }
407a8e1175bSopenharmony_ci
408a8e1175bSopenharmony_ci    return 0;
409a8e1175bSopenharmony_ci}
410a8e1175bSopenharmony_ci
411a8e1175bSopenharmony_ci#if defined(MBEDTLS_LMS_PRIVATE)
412a8e1175bSopenharmony_ci
413a8e1175bSopenharmony_ci/* Calculate a full Merkle tree based on a private key. This function
414a8e1175bSopenharmony_ci * implements RFC8554 section 5.3, and is used to generate a public key (as the
415a8e1175bSopenharmony_ci * public key is the root node of the Merkle tree).
416a8e1175bSopenharmony_ci *
417a8e1175bSopenharmony_ci *  ctx                 The LMS private context, containing a parameter
418a8e1175bSopenharmony_ci *                      set and private key material consisting of both
419a8e1175bSopenharmony_ci *                      public and private OTS.
420a8e1175bSopenharmony_ci *
421a8e1175bSopenharmony_ci *  tree                The output tree, which is 2^(H + 1) hash outputs.
422a8e1175bSopenharmony_ci *                      In the case of H=10 we have 2048 tree nodes (of
423a8e1175bSopenharmony_ci *                      which 1024 of them are leaf nodes). Note that
424a8e1175bSopenharmony_ci *                      because the Merkle tree root is 1-indexed, the 0
425a8e1175bSopenharmony_ci *                      index tree node is never used.
426a8e1175bSopenharmony_ci */
427a8e1175bSopenharmony_cistatic int calculate_merkle_tree(const mbedtls_lms_private_t *ctx,
428a8e1175bSopenharmony_ci                                 unsigned char *tree)
429a8e1175bSopenharmony_ci{
430a8e1175bSopenharmony_ci    unsigned int priv_key_idx;
431a8e1175bSopenharmony_ci    unsigned int r_node_idx;
432a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
433a8e1175bSopenharmony_ci
434a8e1175bSopenharmony_ci    /* First create the leaf nodes, in ascending order */
435a8e1175bSopenharmony_ci    for (priv_key_idx = 0;
436a8e1175bSopenharmony_ci         priv_key_idx < MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type);
437a8e1175bSopenharmony_ci         priv_key_idx++) {
438a8e1175bSopenharmony_ci        r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + priv_key_idx;
439a8e1175bSopenharmony_ci
440a8e1175bSopenharmony_ci        ret = create_merkle_leaf_value(&ctx->params,
441a8e1175bSopenharmony_ci                                       ctx->ots_public_keys[priv_key_idx].public_key,
442a8e1175bSopenharmony_ci                                       r_node_idx,
443a8e1175bSopenharmony_ci                                       &tree[r_node_idx * MBEDTLS_LMS_M_NODE_BYTES(
444a8e1175bSopenharmony_ci                                                 ctx->params.type)]);
445a8e1175bSopenharmony_ci        if (ret != 0) {
446a8e1175bSopenharmony_ci            return ret;
447a8e1175bSopenharmony_ci        }
448a8e1175bSopenharmony_ci    }
449a8e1175bSopenharmony_ci
450a8e1175bSopenharmony_ci    /* Then the internal nodes, in reverse order so that we can guarantee the
451a8e1175bSopenharmony_ci     * parent has been created */
452a8e1175bSopenharmony_ci    for (r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) - 1;
453a8e1175bSopenharmony_ci         r_node_idx > 0;
454a8e1175bSopenharmony_ci         r_node_idx--) {
455a8e1175bSopenharmony_ci        ret = create_merkle_internal_value(&ctx->params,
456a8e1175bSopenharmony_ci                                           &tree[(r_node_idx * 2) *
457a8e1175bSopenharmony_ci                                                 MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)],
458a8e1175bSopenharmony_ci                                           &tree[(r_node_idx * 2 + 1) *
459a8e1175bSopenharmony_ci                                                 MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)],
460a8e1175bSopenharmony_ci                                           r_node_idx,
461a8e1175bSopenharmony_ci                                           &tree[r_node_idx *
462a8e1175bSopenharmony_ci                                                 MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)]);
463a8e1175bSopenharmony_ci        if (ret != 0) {
464a8e1175bSopenharmony_ci            return ret;
465a8e1175bSopenharmony_ci        }
466a8e1175bSopenharmony_ci    }
467a8e1175bSopenharmony_ci
468a8e1175bSopenharmony_ci    return 0;
469a8e1175bSopenharmony_ci}
470a8e1175bSopenharmony_ci
471a8e1175bSopenharmony_ci/* Calculate a path from a leaf node of the Merkle tree to the root of the tree,
472a8e1175bSopenharmony_ci * and return the full path. This function implements RFC8554 section 5.4.1, as
473a8e1175bSopenharmony_ci * the Merkle path is the main component of an LMS signature.
474a8e1175bSopenharmony_ci *
475a8e1175bSopenharmony_ci *  ctx                 The LMS private context, containing a parameter
476a8e1175bSopenharmony_ci *                      set and private key material consisting of both
477a8e1175bSopenharmony_ci *                      public and private OTS.
478a8e1175bSopenharmony_ci *
479a8e1175bSopenharmony_ci *  leaf_node_id        Which leaf node to calculate the path from.
480a8e1175bSopenharmony_ci *
481a8e1175bSopenharmony_ci *  path                The output path, which is H hash outputs.
482a8e1175bSopenharmony_ci */
483a8e1175bSopenharmony_cistatic int get_merkle_path(mbedtls_lms_private_t *ctx,
484a8e1175bSopenharmony_ci                           unsigned int leaf_node_id,
485a8e1175bSopenharmony_ci                           unsigned char *path)
486a8e1175bSopenharmony_ci{
487a8e1175bSopenharmony_ci    const size_t node_bytes = MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
488a8e1175bSopenharmony_ci    unsigned int curr_node_id = leaf_node_id;
489a8e1175bSopenharmony_ci    unsigned int adjacent_node_id;
490a8e1175bSopenharmony_ci    unsigned char *tree = NULL;
491a8e1175bSopenharmony_ci    unsigned int height;
492a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
493a8e1175bSopenharmony_ci
494a8e1175bSopenharmony_ci    tree = mbedtls_calloc((size_t) MERKLE_TREE_NODE_AM(ctx->params.type),
495a8e1175bSopenharmony_ci                          node_bytes);
496a8e1175bSopenharmony_ci    if (tree == NULL) {
497a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_ALLOC_FAILED;
498a8e1175bSopenharmony_ci    }
499a8e1175bSopenharmony_ci
500a8e1175bSopenharmony_ci    ret = calculate_merkle_tree(ctx, tree);
501a8e1175bSopenharmony_ci    if (ret != 0) {
502a8e1175bSopenharmony_ci        goto exit;
503a8e1175bSopenharmony_ci    }
504a8e1175bSopenharmony_ci
505a8e1175bSopenharmony_ci    for (height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT(ctx->params.type);
506a8e1175bSopenharmony_ci         height++) {
507a8e1175bSopenharmony_ci        adjacent_node_id = curr_node_id ^ 1;
508a8e1175bSopenharmony_ci
509a8e1175bSopenharmony_ci        memcpy(&path[height * node_bytes],
510a8e1175bSopenharmony_ci               &tree[adjacent_node_id * node_bytes], node_bytes);
511a8e1175bSopenharmony_ci
512a8e1175bSopenharmony_ci        curr_node_id >>= 1;
513a8e1175bSopenharmony_ci    }
514a8e1175bSopenharmony_ci
515a8e1175bSopenharmony_ci    ret = 0;
516a8e1175bSopenharmony_ci
517a8e1175bSopenharmony_ciexit:
518a8e1175bSopenharmony_ci    mbedtls_zeroize_and_free(tree, node_bytes *
519a8e1175bSopenharmony_ci                             (size_t) MERKLE_TREE_NODE_AM(ctx->params.type));
520a8e1175bSopenharmony_ci
521a8e1175bSopenharmony_ci    return ret;
522a8e1175bSopenharmony_ci}
523a8e1175bSopenharmony_ci
524a8e1175bSopenharmony_civoid mbedtls_lms_private_init(mbedtls_lms_private_t *ctx)
525a8e1175bSopenharmony_ci{
526a8e1175bSopenharmony_ci    memset(ctx, 0, sizeof(*ctx));
527a8e1175bSopenharmony_ci}
528a8e1175bSopenharmony_ci
529a8e1175bSopenharmony_civoid mbedtls_lms_private_free(mbedtls_lms_private_t *ctx)
530a8e1175bSopenharmony_ci{
531a8e1175bSopenharmony_ci    unsigned int idx;
532a8e1175bSopenharmony_ci
533a8e1175bSopenharmony_ci    if (ctx->have_private_key) {
534a8e1175bSopenharmony_ci        if (ctx->ots_private_keys != NULL) {
535a8e1175bSopenharmony_ci            for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
536a8e1175bSopenharmony_ci                mbedtls_lmots_private_free(&ctx->ots_private_keys[idx]);
537a8e1175bSopenharmony_ci            }
538a8e1175bSopenharmony_ci        }
539a8e1175bSopenharmony_ci
540a8e1175bSopenharmony_ci        if (ctx->ots_public_keys != NULL) {
541a8e1175bSopenharmony_ci            for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
542a8e1175bSopenharmony_ci                mbedtls_lmots_public_free(&ctx->ots_public_keys[idx]);
543a8e1175bSopenharmony_ci            }
544a8e1175bSopenharmony_ci        }
545a8e1175bSopenharmony_ci
546a8e1175bSopenharmony_ci        mbedtls_free(ctx->ots_private_keys);
547a8e1175bSopenharmony_ci        mbedtls_free(ctx->ots_public_keys);
548a8e1175bSopenharmony_ci    }
549a8e1175bSopenharmony_ci
550a8e1175bSopenharmony_ci    mbedtls_platform_zeroize(ctx, sizeof(*ctx));
551a8e1175bSopenharmony_ci}
552a8e1175bSopenharmony_ci
553a8e1175bSopenharmony_ci
554a8e1175bSopenharmony_ciint mbedtls_lms_generate_private_key(mbedtls_lms_private_t *ctx,
555a8e1175bSopenharmony_ci                                     mbedtls_lms_algorithm_type_t type,
556a8e1175bSopenharmony_ci                                     mbedtls_lmots_algorithm_type_t otstype,
557a8e1175bSopenharmony_ci                                     int (*f_rng)(void *, unsigned char *, size_t),
558a8e1175bSopenharmony_ci                                     void *p_rng, const unsigned char *seed,
559a8e1175bSopenharmony_ci                                     size_t seed_size)
560a8e1175bSopenharmony_ci{
561a8e1175bSopenharmony_ci    unsigned int idx = 0;
562a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
563a8e1175bSopenharmony_ci
564a8e1175bSopenharmony_ci    if (type != MBEDTLS_LMS_SHA256_M32_H10) {
565a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
566a8e1175bSopenharmony_ci    }
567a8e1175bSopenharmony_ci
568a8e1175bSopenharmony_ci    if (otstype != MBEDTLS_LMOTS_SHA256_N32_W8) {
569a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
570a8e1175bSopenharmony_ci    }
571a8e1175bSopenharmony_ci
572a8e1175bSopenharmony_ci    if (ctx->have_private_key) {
573a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
574a8e1175bSopenharmony_ci    }
575a8e1175bSopenharmony_ci
576a8e1175bSopenharmony_ci    ctx->params.type = type;
577a8e1175bSopenharmony_ci    ctx->params.otstype = otstype;
578a8e1175bSopenharmony_ci    ctx->have_private_key = 1;
579a8e1175bSopenharmony_ci
580a8e1175bSopenharmony_ci    ret = f_rng(p_rng,
581a8e1175bSopenharmony_ci                ctx->params.I_key_identifier,
582a8e1175bSopenharmony_ci                MBEDTLS_LMOTS_I_KEY_ID_LEN);
583a8e1175bSopenharmony_ci    if (ret != 0) {
584a8e1175bSopenharmony_ci        goto exit;
585a8e1175bSopenharmony_ci    }
586a8e1175bSopenharmony_ci
587a8e1175bSopenharmony_ci    /* Requires a cast to size_t to avoid an implicit cast warning on certain
588a8e1175bSopenharmony_ci     * platforms (particularly Windows) */
589a8e1175bSopenharmony_ci    ctx->ots_private_keys = mbedtls_calloc((size_t) MERKLE_TREE_LEAF_NODE_AM(ctx->params.type),
590a8e1175bSopenharmony_ci                                           sizeof(*ctx->ots_private_keys));
591a8e1175bSopenharmony_ci    if (ctx->ots_private_keys == NULL) {
592a8e1175bSopenharmony_ci        ret = MBEDTLS_ERR_LMS_ALLOC_FAILED;
593a8e1175bSopenharmony_ci        goto exit;
594a8e1175bSopenharmony_ci    }
595a8e1175bSopenharmony_ci
596a8e1175bSopenharmony_ci    /* Requires a cast to size_t to avoid an implicit cast warning on certain
597a8e1175bSopenharmony_ci     * platforms (particularly Windows) */
598a8e1175bSopenharmony_ci    ctx->ots_public_keys = mbedtls_calloc((size_t) MERKLE_TREE_LEAF_NODE_AM(ctx->params.type),
599a8e1175bSopenharmony_ci                                          sizeof(*ctx->ots_public_keys));
600a8e1175bSopenharmony_ci    if (ctx->ots_public_keys == NULL) {
601a8e1175bSopenharmony_ci        ret = MBEDTLS_ERR_LMS_ALLOC_FAILED;
602a8e1175bSopenharmony_ci        goto exit;
603a8e1175bSopenharmony_ci    }
604a8e1175bSopenharmony_ci
605a8e1175bSopenharmony_ci    for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
606a8e1175bSopenharmony_ci        mbedtls_lmots_private_init(&ctx->ots_private_keys[idx]);
607a8e1175bSopenharmony_ci        mbedtls_lmots_public_init(&ctx->ots_public_keys[idx]);
608a8e1175bSopenharmony_ci    }
609a8e1175bSopenharmony_ci
610a8e1175bSopenharmony_ci
611a8e1175bSopenharmony_ci    for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
612a8e1175bSopenharmony_ci        ret = mbedtls_lmots_generate_private_key(&ctx->ots_private_keys[idx],
613a8e1175bSopenharmony_ci                                                 otstype,
614a8e1175bSopenharmony_ci                                                 ctx->params.I_key_identifier,
615a8e1175bSopenharmony_ci                                                 idx, seed, seed_size);
616a8e1175bSopenharmony_ci        if (ret != 0) {
617a8e1175bSopenharmony_ci            goto exit;
618a8e1175bSopenharmony_ci        }
619a8e1175bSopenharmony_ci
620a8e1175bSopenharmony_ci        ret = mbedtls_lmots_calculate_public_key(&ctx->ots_public_keys[idx],
621a8e1175bSopenharmony_ci                                                 &ctx->ots_private_keys[idx]);
622a8e1175bSopenharmony_ci        if (ret != 0) {
623a8e1175bSopenharmony_ci            goto exit;
624a8e1175bSopenharmony_ci        }
625a8e1175bSopenharmony_ci    }
626a8e1175bSopenharmony_ci
627a8e1175bSopenharmony_ci    ctx->q_next_usable_key = 0;
628a8e1175bSopenharmony_ci
629a8e1175bSopenharmony_ciexit:
630a8e1175bSopenharmony_ci    if (ret != 0) {
631a8e1175bSopenharmony_ci        mbedtls_lms_private_free(ctx);
632a8e1175bSopenharmony_ci    }
633a8e1175bSopenharmony_ci
634a8e1175bSopenharmony_ci    return ret;
635a8e1175bSopenharmony_ci}
636a8e1175bSopenharmony_ci
637a8e1175bSopenharmony_ciint mbedtls_lms_calculate_public_key(mbedtls_lms_public_t *ctx,
638a8e1175bSopenharmony_ci                                     const mbedtls_lms_private_t *priv_ctx)
639a8e1175bSopenharmony_ci{
640a8e1175bSopenharmony_ci    const size_t node_bytes = MBEDTLS_LMS_M_NODE_BYTES(priv_ctx->params.type);
641a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
642a8e1175bSopenharmony_ci    unsigned char *tree = NULL;
643a8e1175bSopenharmony_ci
644a8e1175bSopenharmony_ci    if (!priv_ctx->have_private_key) {
645a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
646a8e1175bSopenharmony_ci    }
647a8e1175bSopenharmony_ci
648a8e1175bSopenharmony_ci    if (priv_ctx->params.type
649a8e1175bSopenharmony_ci        != MBEDTLS_LMS_SHA256_M32_H10) {
650a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
651a8e1175bSopenharmony_ci    }
652a8e1175bSopenharmony_ci
653a8e1175bSopenharmony_ci    if (priv_ctx->params.otstype
654a8e1175bSopenharmony_ci        != MBEDTLS_LMOTS_SHA256_N32_W8) {
655a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
656a8e1175bSopenharmony_ci    }
657a8e1175bSopenharmony_ci
658a8e1175bSopenharmony_ci    tree = mbedtls_calloc((size_t) MERKLE_TREE_NODE_AM(priv_ctx->params.type),
659a8e1175bSopenharmony_ci                          node_bytes);
660a8e1175bSopenharmony_ci    if (tree == NULL) {
661a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_ALLOC_FAILED;
662a8e1175bSopenharmony_ci    }
663a8e1175bSopenharmony_ci
664a8e1175bSopenharmony_ci    memcpy(&ctx->params, &priv_ctx->params,
665a8e1175bSopenharmony_ci           sizeof(mbedtls_lmots_parameters_t));
666a8e1175bSopenharmony_ci
667a8e1175bSopenharmony_ci    ret = calculate_merkle_tree(priv_ctx, tree);
668a8e1175bSopenharmony_ci    if (ret != 0) {
669a8e1175bSopenharmony_ci        goto exit;
670a8e1175bSopenharmony_ci    }
671a8e1175bSopenharmony_ci
672a8e1175bSopenharmony_ci    /* Root node is always at position 1, due to 1-based indexing */
673a8e1175bSopenharmony_ci    memcpy(ctx->T_1_pub_key, &tree[node_bytes], node_bytes);
674a8e1175bSopenharmony_ci
675a8e1175bSopenharmony_ci    ctx->have_public_key = 1;
676a8e1175bSopenharmony_ci
677a8e1175bSopenharmony_ci    ret = 0;
678a8e1175bSopenharmony_ci
679a8e1175bSopenharmony_ciexit:
680a8e1175bSopenharmony_ci    mbedtls_zeroize_and_free(tree, node_bytes *
681a8e1175bSopenharmony_ci                             (size_t) MERKLE_TREE_NODE_AM(priv_ctx->params.type));
682a8e1175bSopenharmony_ci
683a8e1175bSopenharmony_ci    return ret;
684a8e1175bSopenharmony_ci}
685a8e1175bSopenharmony_ci
686a8e1175bSopenharmony_ci
687a8e1175bSopenharmony_ciint mbedtls_lms_sign(mbedtls_lms_private_t *ctx,
688a8e1175bSopenharmony_ci                     int (*f_rng)(void *, unsigned char *, size_t),
689a8e1175bSopenharmony_ci                     void *p_rng, const unsigned char *msg,
690a8e1175bSopenharmony_ci                     unsigned int msg_size, unsigned char *sig, size_t sig_size,
691a8e1175bSopenharmony_ci                     size_t *sig_len)
692a8e1175bSopenharmony_ci{
693a8e1175bSopenharmony_ci    uint32_t q_leaf_identifier;
694a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
695a8e1175bSopenharmony_ci
696a8e1175bSopenharmony_ci    if (!ctx->have_private_key) {
697a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
698a8e1175bSopenharmony_ci    }
699a8e1175bSopenharmony_ci
700a8e1175bSopenharmony_ci    if (sig_size < MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)) {
701a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
702a8e1175bSopenharmony_ci    }
703a8e1175bSopenharmony_ci
704a8e1175bSopenharmony_ci    if (ctx->params.type != MBEDTLS_LMS_SHA256_M32_H10) {
705a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
706a8e1175bSopenharmony_ci    }
707a8e1175bSopenharmony_ci
708a8e1175bSopenharmony_ci    if (ctx->params.otstype
709a8e1175bSopenharmony_ci        != MBEDTLS_LMOTS_SHA256_N32_W8) {
710a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
711a8e1175bSopenharmony_ci    }
712a8e1175bSopenharmony_ci
713a8e1175bSopenharmony_ci    if (ctx->q_next_usable_key >= MERKLE_TREE_LEAF_NODE_AM(ctx->params.type)) {
714a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_OUT_OF_PRIVATE_KEYS;
715a8e1175bSopenharmony_ci    }
716a8e1175bSopenharmony_ci
717a8e1175bSopenharmony_ci
718a8e1175bSopenharmony_ci    q_leaf_identifier = ctx->q_next_usable_key;
719a8e1175bSopenharmony_ci    /* This new value must _always_ be written back to the disk before the
720a8e1175bSopenharmony_ci     * signature is returned.
721a8e1175bSopenharmony_ci     */
722a8e1175bSopenharmony_ci    ctx->q_next_usable_key += 1;
723a8e1175bSopenharmony_ci
724a8e1175bSopenharmony_ci    if (MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)
725a8e1175bSopenharmony_ci        < SIG_OTS_SIG_OFFSET) {
726a8e1175bSopenharmony_ci        return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
727a8e1175bSopenharmony_ci    }
728a8e1175bSopenharmony_ci
729a8e1175bSopenharmony_ci    ret = mbedtls_lmots_sign(&ctx->ots_private_keys[q_leaf_identifier],
730a8e1175bSopenharmony_ci                             f_rng,
731a8e1175bSopenharmony_ci                             p_rng,
732a8e1175bSopenharmony_ci                             msg,
733a8e1175bSopenharmony_ci                             msg_size,
734a8e1175bSopenharmony_ci                             sig + SIG_OTS_SIG_OFFSET,
735a8e1175bSopenharmony_ci                             MBEDTLS_LMS_SIG_LEN(ctx->params.type,
736a8e1175bSopenharmony_ci                                                 ctx->params.otstype) - SIG_OTS_SIG_OFFSET,
737a8e1175bSopenharmony_ci                             NULL);
738a8e1175bSopenharmony_ci    if (ret != 0) {
739a8e1175bSopenharmony_ci        return ret;
740a8e1175bSopenharmony_ci    }
741a8e1175bSopenharmony_ci
742a8e1175bSopenharmony_ci    MBEDTLS_PUT_UINT32_BE(ctx->params.type, sig, SIG_TYPE_OFFSET(ctx->params.otstype));
743a8e1175bSopenharmony_ci    MBEDTLS_PUT_UINT32_BE(q_leaf_identifier, sig, SIG_Q_LEAF_ID_OFFSET);
744a8e1175bSopenharmony_ci
745a8e1175bSopenharmony_ci    ret = get_merkle_path(ctx,
746a8e1175bSopenharmony_ci                          MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + q_leaf_identifier,
747a8e1175bSopenharmony_ci                          sig + SIG_PATH_OFFSET(ctx->params.otstype));
748a8e1175bSopenharmony_ci    if (ret != 0) {
749a8e1175bSopenharmony_ci        return ret;
750a8e1175bSopenharmony_ci    }
751a8e1175bSopenharmony_ci
752a8e1175bSopenharmony_ci    if (sig_len != NULL) {
753a8e1175bSopenharmony_ci        *sig_len = MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype);
754a8e1175bSopenharmony_ci    }
755a8e1175bSopenharmony_ci
756a8e1175bSopenharmony_ci
757a8e1175bSopenharmony_ci    return 0;
758a8e1175bSopenharmony_ci}
759a8e1175bSopenharmony_ci
760a8e1175bSopenharmony_ci#endif /* defined(MBEDTLS_LMS_PRIVATE) */
761a8e1175bSopenharmony_ci#endif /* defined(MBEDTLS_LMS_C) */
762