xref: /optee_os/lib/libmbedtls/mbedtls/library/lmots.c (revision 32b3180828fa15a49ccc86ecb4be9d274c140c89)
1*32b31808SJens Wiklander /*
2*32b31808SJens Wiklander  * The LM-OTS one-time public-key signature scheme
3*32b31808SJens Wiklander  *
4*32b31808SJens Wiklander  * Copyright The Mbed TLS Contributors
5*32b31808SJens Wiklander  *  SPDX-License-Identifier: Apache-2.0
6*32b31808SJens Wiklander  *
7*32b31808SJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8*32b31808SJens Wiklander  *  not use this file except in compliance with the License.
9*32b31808SJens Wiklander  *  You may obtain a copy of the License at
10*32b31808SJens Wiklander  *
11*32b31808SJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12*32b31808SJens Wiklander  *
13*32b31808SJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14*32b31808SJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15*32b31808SJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*32b31808SJens Wiklander  *  See the License for the specific language governing permissions and
17*32b31808SJens Wiklander  *  limitations under the License.
18*32b31808SJens Wiklander  */
19*32b31808SJens Wiklander 
20*32b31808SJens Wiklander /*
21*32b31808SJens Wiklander  *  The following sources were referenced in the design of this implementation
22*32b31808SJens Wiklander  *  of the LM-OTS algorithm:
23*32b31808SJens Wiklander  *
24*32b31808SJens Wiklander  *  [1] IETF RFC8554
25*32b31808SJens Wiklander  *      D. McGrew, M. Curcio, S.Fluhrer
26*32b31808SJens Wiklander  *      https://datatracker.ietf.org/doc/html/rfc8554
27*32b31808SJens Wiklander  *
28*32b31808SJens Wiklander  *  [2] NIST Special Publication 800-208
29*32b31808SJens Wiklander  *      David A. Cooper et. al.
30*32b31808SJens Wiklander  *      https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-208.pdf
31*32b31808SJens Wiklander  */
32*32b31808SJens Wiklander 
33*32b31808SJens Wiklander #include "common.h"
34*32b31808SJens Wiklander 
35*32b31808SJens Wiklander #if defined(MBEDTLS_LMS_C)
36*32b31808SJens Wiklander 
37*32b31808SJens Wiklander #include <string.h>
38*32b31808SJens Wiklander 
39*32b31808SJens Wiklander #include "lmots.h"
40*32b31808SJens Wiklander 
41*32b31808SJens Wiklander #include "mbedtls/lms.h"
42*32b31808SJens Wiklander #include "mbedtls/platform_util.h"
43*32b31808SJens Wiklander #include "mbedtls/error.h"
44*32b31808SJens Wiklander #include "mbedtls/psa_util.h"
45*32b31808SJens Wiklander 
46*32b31808SJens Wiklander #include "psa/crypto.h"
47*32b31808SJens Wiklander 
48*32b31808SJens Wiklander #define PSA_TO_MBEDTLS_ERR(status) PSA_TO_MBEDTLS_ERR_LIST(status,   \
49*32b31808SJens Wiklander                                                            psa_to_lms_errors,             \
50*32b31808SJens Wiklander                                                            psa_generic_status_to_mbedtls)
51*32b31808SJens Wiklander 
52*32b31808SJens Wiklander #define PUBLIC_KEY_TYPE_OFFSET     (0)
53*32b31808SJens Wiklander #define PUBLIC_KEY_I_KEY_ID_OFFSET (PUBLIC_KEY_TYPE_OFFSET + \
54*32b31808SJens Wiklander                                     MBEDTLS_LMOTS_TYPE_LEN)
55*32b31808SJens Wiklander #define PUBLIC_KEY_Q_LEAF_ID_OFFSET (PUBLIC_KEY_I_KEY_ID_OFFSET + \
56*32b31808SJens Wiklander                                      MBEDTLS_LMOTS_I_KEY_ID_LEN)
57*32b31808SJens Wiklander #define PUBLIC_KEY_KEY_HASH_OFFSET (PUBLIC_KEY_Q_LEAF_ID_OFFSET + \
58*32b31808SJens Wiklander                                     MBEDTLS_LMOTS_Q_LEAF_ID_LEN)
59*32b31808SJens Wiklander 
60*32b31808SJens Wiklander /* We only support parameter sets that use 8-bit digits, as it does not require
61*32b31808SJens Wiklander  * translation logic between digits and bytes */
62*32b31808SJens Wiklander #define W_WINTERNITZ_PARAMETER (8u)
63*32b31808SJens Wiklander #define CHECKSUM_LEN           (2)
64*32b31808SJens Wiklander #define I_DIGIT_IDX_LEN        (2)
65*32b31808SJens Wiklander #define J_HASH_IDX_LEN         (1)
66*32b31808SJens Wiklander #define D_CONST_LEN            (2)
67*32b31808SJens Wiklander 
68*32b31808SJens Wiklander #define DIGIT_MAX_VALUE        ((1u << W_WINTERNITZ_PARAMETER) - 1u)
69*32b31808SJens Wiklander 
70*32b31808SJens Wiklander #define D_CONST_LEN            (2)
71*32b31808SJens Wiklander static const unsigned char D_PUBLIC_CONSTANT_BYTES[D_CONST_LEN] = { 0x80, 0x80 };
72*32b31808SJens Wiklander static const unsigned char D_MESSAGE_CONSTANT_BYTES[D_CONST_LEN] = { 0x81, 0x81 };
73*32b31808SJens Wiklander 
74*32b31808SJens Wiklander #if defined(MBEDTLS_TEST_HOOKS)
75*32b31808SJens Wiklander int (*mbedtls_lmots_sign_private_key_invalidated_hook)(unsigned char *) = NULL;
76*32b31808SJens Wiklander #endif /* defined(MBEDTLS_TEST_HOOKS) */
77*32b31808SJens Wiklander 
78*32b31808SJens Wiklander void mbedtls_lms_unsigned_int_to_network_bytes(unsigned int val, size_t len,
79*32b31808SJens Wiklander                                                unsigned char *bytes)
80*32b31808SJens Wiklander {
81*32b31808SJens Wiklander     size_t idx;
82*32b31808SJens Wiklander 
83*32b31808SJens Wiklander     for (idx = 0; idx < len; idx++) {
84*32b31808SJens Wiklander         bytes[idx] = (val >> ((len - 1 - idx) * 8)) & 0xFF;
85*32b31808SJens Wiklander     }
86*32b31808SJens Wiklander }
87*32b31808SJens Wiklander 
88*32b31808SJens Wiklander unsigned int mbedtls_lms_network_bytes_to_unsigned_int(size_t len,
89*32b31808SJens Wiklander                                                        const unsigned char *bytes)
90*32b31808SJens Wiklander {
91*32b31808SJens Wiklander     size_t idx;
92*32b31808SJens Wiklander     unsigned int val = 0;
93*32b31808SJens Wiklander 
94*32b31808SJens Wiklander     for (idx = 0; idx < len; idx++) {
95*32b31808SJens Wiklander         val |= ((unsigned int) bytes[idx]) << (8 * (len - 1 - idx));
96*32b31808SJens Wiklander     }
97*32b31808SJens Wiklander 
98*32b31808SJens Wiklander     return val;
99*32b31808SJens Wiklander }
100*32b31808SJens Wiklander 
101*32b31808SJens Wiklander /* Calculate the checksum digits that are appended to the end of the LMOTS digit
102*32b31808SJens Wiklander  * string. See NIST SP800-208 section 3.1 or RFC8554 Algorithm 2 for details of
103*32b31808SJens Wiklander  * the checksum algorithm.
104*32b31808SJens Wiklander  *
105*32b31808SJens Wiklander  *  params              The LMOTS parameter set, I and q values which
106*32b31808SJens Wiklander  *                      describe the key being used.
107*32b31808SJens Wiklander  *
108*32b31808SJens Wiklander  *  digest              The digit string to create the digest from. As
109*32b31808SJens Wiklander  *                      this does not contain a checksum, it is the same
110*32b31808SJens Wiklander  *                      size as a hash output.
111*32b31808SJens Wiklander  */
112*32b31808SJens Wiklander static unsigned short lmots_checksum_calculate(const mbedtls_lmots_parameters_t *params,
113*32b31808SJens Wiklander                                                const unsigned char *digest)
114*32b31808SJens Wiklander {
115*32b31808SJens Wiklander     size_t idx;
116*32b31808SJens Wiklander     unsigned sum = 0;
117*32b31808SJens Wiklander 
118*32b31808SJens Wiklander     for (idx = 0; idx < MBEDTLS_LMOTS_N_HASH_LEN(params->type); idx++) {
119*32b31808SJens Wiklander         sum += DIGIT_MAX_VALUE - digest[idx];
120*32b31808SJens Wiklander     }
121*32b31808SJens Wiklander 
122*32b31808SJens Wiklander     return sum;
123*32b31808SJens Wiklander }
124*32b31808SJens Wiklander 
125*32b31808SJens Wiklander /* Create the string of digest digits (in the base determined by the Winternitz
126*32b31808SJens Wiklander  * parameter with the checksum appended to the end (Q || cksm(Q)). See NIST
127*32b31808SJens Wiklander  * SP800-208 section 3.1 or RFC8554 Algorithm 3 step 5 (also used in Algorithm
128*32b31808SJens Wiklander  * 4b step 3) for details.
129*32b31808SJens Wiklander  *
130*32b31808SJens Wiklander  *  params              The LMOTS parameter set, I and q values which
131*32b31808SJens Wiklander  *                      describe the key being used.
132*32b31808SJens Wiklander  *
133*32b31808SJens Wiklander  *  msg                 The message that will be hashed to create the
134*32b31808SJens Wiklander  *                      digest.
135*32b31808SJens Wiklander  *
136*32b31808SJens Wiklander  *  msg_size            The size of the message.
137*32b31808SJens Wiklander  *
138*32b31808SJens Wiklander  *  C_random_value      The random value that will be combined with the
139*32b31808SJens Wiklander  *                      message digest. This is always the same size as a
140*32b31808SJens Wiklander  *                      hash output for whichever hash algorithm is
141*32b31808SJens Wiklander  *                      determined by the parameter set.
142*32b31808SJens Wiklander  *
143*32b31808SJens Wiklander  *  output              An output containing the digit string (+
144*32b31808SJens Wiklander  *                      checksum) of length P digits (in the case of
145*32b31808SJens Wiklander  *                      MBEDTLS_LMOTS_SHA256_N32_W8, this means it is of
146*32b31808SJens Wiklander  *                      size P bytes).
147*32b31808SJens Wiklander  */
148*32b31808SJens Wiklander static int create_digit_array_with_checksum(const mbedtls_lmots_parameters_t *params,
149*32b31808SJens Wiklander                                             const unsigned char *msg,
150*32b31808SJens Wiklander                                             size_t msg_len,
151*32b31808SJens Wiklander                                             const unsigned char *C_random_value,
152*32b31808SJens Wiklander                                             unsigned char *out)
153*32b31808SJens Wiklander {
154*32b31808SJens Wiklander     psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
155*32b31808SJens Wiklander     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
156*32b31808SJens Wiklander     size_t output_hash_len;
157*32b31808SJens Wiklander     unsigned short checksum;
158*32b31808SJens Wiklander 
159*32b31808SJens Wiklander     status = psa_hash_setup(&op, PSA_ALG_SHA_256);
160*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
161*32b31808SJens Wiklander         goto exit;
162*32b31808SJens Wiklander     }
163*32b31808SJens Wiklander 
164*32b31808SJens Wiklander     status = psa_hash_update(&op, params->I_key_identifier,
165*32b31808SJens Wiklander                              MBEDTLS_LMOTS_I_KEY_ID_LEN);
166*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
167*32b31808SJens Wiklander         goto exit;
168*32b31808SJens Wiklander     }
169*32b31808SJens Wiklander 
170*32b31808SJens Wiklander     status = psa_hash_update(&op, params->q_leaf_identifier,
171*32b31808SJens Wiklander                              MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
172*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
173*32b31808SJens Wiklander         goto exit;
174*32b31808SJens Wiklander     }
175*32b31808SJens Wiklander 
176*32b31808SJens Wiklander     status = psa_hash_update(&op, D_MESSAGE_CONSTANT_BYTES, D_CONST_LEN);
177*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
178*32b31808SJens Wiklander         goto exit;
179*32b31808SJens Wiklander     }
180*32b31808SJens Wiklander 
181*32b31808SJens Wiklander     status = psa_hash_update(&op, C_random_value,
182*32b31808SJens Wiklander                              MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(params->type));
183*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
184*32b31808SJens Wiklander         goto exit;
185*32b31808SJens Wiklander     }
186*32b31808SJens Wiklander 
187*32b31808SJens Wiklander     status = psa_hash_update(&op, msg, msg_len);
188*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
189*32b31808SJens Wiklander         goto exit;
190*32b31808SJens Wiklander     }
191*32b31808SJens Wiklander 
192*32b31808SJens Wiklander     status = psa_hash_finish(&op, out,
193*32b31808SJens Wiklander                              MBEDTLS_LMOTS_N_HASH_LEN(params->type),
194*32b31808SJens Wiklander                              &output_hash_len);
195*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
196*32b31808SJens Wiklander         goto exit;
197*32b31808SJens Wiklander     }
198*32b31808SJens Wiklander 
199*32b31808SJens Wiklander     checksum = lmots_checksum_calculate(params, out);
200*32b31808SJens Wiklander     mbedtls_lms_unsigned_int_to_network_bytes(checksum, CHECKSUM_LEN,
201*32b31808SJens Wiklander                                               out + MBEDTLS_LMOTS_N_HASH_LEN(params->type));
202*32b31808SJens Wiklander 
203*32b31808SJens Wiklander exit:
204*32b31808SJens Wiklander     psa_hash_abort(&op);
205*32b31808SJens Wiklander 
206*32b31808SJens Wiklander     return PSA_TO_MBEDTLS_ERR(status);
207*32b31808SJens Wiklander }
208*32b31808SJens Wiklander 
209*32b31808SJens Wiklander /* Hash each element of the string of digits (+ checksum), producing a hash
210*32b31808SJens Wiklander  * output for each element. This is used in several places (by varying the
211*32b31808SJens Wiklander  * hash_idx_min/max_values) in order to calculate a public key from a private
212*32b31808SJens Wiklander  * key (RFC8554 Algorithm 1 step 4), in order to sign a message (RFC8554
213*32b31808SJens Wiklander  * Algorithm 3 step 5), and to calculate a public key candidate from a
214*32b31808SJens Wiklander  * signature and message (RFC8554 Algorithm 4b step 3).
215*32b31808SJens Wiklander  *
216*32b31808SJens Wiklander  *  params              The LMOTS parameter set, I and q values which
217*32b31808SJens Wiklander  *                      describe the key being used.
218*32b31808SJens Wiklander  *
219*32b31808SJens Wiklander  *  x_digit_array       The array of digits (of size P, 34 in the case of
220*32b31808SJens Wiklander  *                      MBEDTLS_LMOTS_SHA256_N32_W8).
221*32b31808SJens Wiklander  *
222*32b31808SJens Wiklander  *  hash_idx_min_values An array of the starting values of the j iterator
223*32b31808SJens Wiklander  *                      for each of the members of the digit array. If
224*32b31808SJens Wiklander  *                      this value in NULL, then all iterators will start
225*32b31808SJens Wiklander  *                      at 0.
226*32b31808SJens Wiklander  *
227*32b31808SJens Wiklander  *  hash_idx_max_values An array of the upper bound values of the j
228*32b31808SJens Wiklander  *                      iterator for each of the members of the digit
229*32b31808SJens Wiklander  *                      array. If this value in NULL, then iterator is
230*32b31808SJens Wiklander  *                      bounded to be less than 2^w - 1 (255 in the case
231*32b31808SJens Wiklander  *                      of MBEDTLS_LMOTS_SHA256_N32_W8)
232*32b31808SJens Wiklander  *
233*32b31808SJens Wiklander  *  output              An array containing a hash output for each member
234*32b31808SJens Wiklander  *                      of the digit string P. In the case of
235*32b31808SJens Wiklander  *                      MBEDTLS_LMOTS_SHA256_N32_W8, this is of size 32 *
236*32b31808SJens Wiklander  *                      34.
237*32b31808SJens Wiklander  */
238*32b31808SJens Wiklander static int hash_digit_array(const mbedtls_lmots_parameters_t *params,
239*32b31808SJens Wiklander                             const unsigned char *x_digit_array,
240*32b31808SJens Wiklander                             const unsigned char *hash_idx_min_values,
241*32b31808SJens Wiklander                             const unsigned char *hash_idx_max_values,
242*32b31808SJens Wiklander                             unsigned char *output)
243*32b31808SJens Wiklander {
244*32b31808SJens Wiklander     unsigned int i_digit_idx;
245*32b31808SJens Wiklander     unsigned char i_digit_idx_bytes[I_DIGIT_IDX_LEN];
246*32b31808SJens Wiklander     unsigned int j_hash_idx;
247*32b31808SJens Wiklander     unsigned char j_hash_idx_bytes[J_HASH_IDX_LEN];
248*32b31808SJens Wiklander     unsigned int j_hash_idx_min;
249*32b31808SJens Wiklander     unsigned int j_hash_idx_max;
250*32b31808SJens Wiklander     psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
251*32b31808SJens Wiklander     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
252*32b31808SJens Wiklander     size_t output_hash_len;
253*32b31808SJens Wiklander     unsigned char tmp_hash[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
254*32b31808SJens Wiklander 
255*32b31808SJens Wiklander     for (i_digit_idx = 0;
256*32b31808SJens Wiklander          i_digit_idx < MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(params->type);
257*32b31808SJens Wiklander          i_digit_idx++) {
258*32b31808SJens Wiklander 
259*32b31808SJens Wiklander         memcpy(tmp_hash,
260*32b31808SJens Wiklander                &x_digit_array[i_digit_idx * MBEDTLS_LMOTS_N_HASH_LEN(params->type)],
261*32b31808SJens Wiklander                MBEDTLS_LMOTS_N_HASH_LEN(params->type));
262*32b31808SJens Wiklander 
263*32b31808SJens Wiklander         j_hash_idx_min = hash_idx_min_values != NULL ?
264*32b31808SJens Wiklander                          hash_idx_min_values[i_digit_idx] : 0;
265*32b31808SJens Wiklander         j_hash_idx_max = hash_idx_max_values != NULL ?
266*32b31808SJens Wiklander                          hash_idx_max_values[i_digit_idx] : DIGIT_MAX_VALUE;
267*32b31808SJens Wiklander 
268*32b31808SJens Wiklander         for (j_hash_idx = j_hash_idx_min;
269*32b31808SJens Wiklander              j_hash_idx < j_hash_idx_max;
270*32b31808SJens Wiklander              j_hash_idx++) {
271*32b31808SJens Wiklander             status = psa_hash_setup(&op, PSA_ALG_SHA_256);
272*32b31808SJens Wiklander             if (status != PSA_SUCCESS) {
273*32b31808SJens Wiklander                 goto exit;
274*32b31808SJens Wiklander             }
275*32b31808SJens Wiklander 
276*32b31808SJens Wiklander             status = psa_hash_update(&op,
277*32b31808SJens Wiklander                                      params->I_key_identifier,
278*32b31808SJens Wiklander                                      MBEDTLS_LMOTS_I_KEY_ID_LEN);
279*32b31808SJens Wiklander             if (status != PSA_SUCCESS) {
280*32b31808SJens Wiklander                 goto exit;
281*32b31808SJens Wiklander             }
282*32b31808SJens Wiklander 
283*32b31808SJens Wiklander             status = psa_hash_update(&op,
284*32b31808SJens Wiklander                                      params->q_leaf_identifier,
285*32b31808SJens Wiklander                                      MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
286*32b31808SJens Wiklander             if (status != PSA_SUCCESS) {
287*32b31808SJens Wiklander                 goto exit;
288*32b31808SJens Wiklander             }
289*32b31808SJens Wiklander 
290*32b31808SJens Wiklander             mbedtls_lms_unsigned_int_to_network_bytes(i_digit_idx,
291*32b31808SJens Wiklander                                                       I_DIGIT_IDX_LEN,
292*32b31808SJens Wiklander                                                       i_digit_idx_bytes);
293*32b31808SJens Wiklander             status = psa_hash_update(&op, i_digit_idx_bytes, I_DIGIT_IDX_LEN);
294*32b31808SJens Wiklander             if (status != PSA_SUCCESS) {
295*32b31808SJens Wiklander                 goto exit;
296*32b31808SJens Wiklander             }
297*32b31808SJens Wiklander 
298*32b31808SJens Wiklander             mbedtls_lms_unsigned_int_to_network_bytes(j_hash_idx,
299*32b31808SJens Wiklander                                                       J_HASH_IDX_LEN,
300*32b31808SJens Wiklander                                                       j_hash_idx_bytes);
301*32b31808SJens Wiklander             status = psa_hash_update(&op, j_hash_idx_bytes, J_HASH_IDX_LEN);
302*32b31808SJens Wiklander             if (status != PSA_SUCCESS) {
303*32b31808SJens Wiklander                 goto exit;
304*32b31808SJens Wiklander             }
305*32b31808SJens Wiklander 
306*32b31808SJens Wiklander             status = psa_hash_update(&op, tmp_hash,
307*32b31808SJens Wiklander                                      MBEDTLS_LMOTS_N_HASH_LEN(params->type));
308*32b31808SJens Wiklander             if (status != PSA_SUCCESS) {
309*32b31808SJens Wiklander                 goto exit;
310*32b31808SJens Wiklander             }
311*32b31808SJens Wiklander 
312*32b31808SJens Wiklander             status = psa_hash_finish(&op, tmp_hash, sizeof(tmp_hash),
313*32b31808SJens Wiklander                                      &output_hash_len);
314*32b31808SJens Wiklander             if (status != PSA_SUCCESS) {
315*32b31808SJens Wiklander                 goto exit;
316*32b31808SJens Wiklander             }
317*32b31808SJens Wiklander 
318*32b31808SJens Wiklander             psa_hash_abort(&op);
319*32b31808SJens Wiklander         }
320*32b31808SJens Wiklander 
321*32b31808SJens Wiklander         memcpy(&output[i_digit_idx * MBEDTLS_LMOTS_N_HASH_LEN(params->type)],
322*32b31808SJens Wiklander                tmp_hash, MBEDTLS_LMOTS_N_HASH_LEN(params->type));
323*32b31808SJens Wiklander     }
324*32b31808SJens Wiklander 
325*32b31808SJens Wiklander exit:
326*32b31808SJens Wiklander     psa_hash_abort(&op);
327*32b31808SJens Wiklander     mbedtls_platform_zeroize(tmp_hash, sizeof(tmp_hash));
328*32b31808SJens Wiklander 
329*32b31808SJens Wiklander     return PSA_TO_MBEDTLS_ERR(status);
330*32b31808SJens Wiklander }
331*32b31808SJens Wiklander 
332*32b31808SJens Wiklander /* Combine the hashes of the digit array into a public key. This is used in
333*32b31808SJens Wiklander  * in order to calculate a public key from a private key (RFC8554 Algorithm 1
334*32b31808SJens Wiklander  * step 4), and to calculate a public key candidate from a signature and message
335*32b31808SJens Wiklander  * (RFC8554 Algorithm 4b step 3).
336*32b31808SJens Wiklander  *
337*32b31808SJens Wiklander  *  params           The LMOTS parameter set, I and q values which describe
338*32b31808SJens Wiklander  *                   the key being used.
339*32b31808SJens Wiklander  *  y_hashed_digits  The array of hashes, one hash for each digit of the
340*32b31808SJens Wiklander  *                   symbol array (which is of size P, 34 in the case of
341*32b31808SJens Wiklander  *                   MBEDTLS_LMOTS_SHA256_N32_W8)
342*32b31808SJens Wiklander  *
343*32b31808SJens Wiklander  *  pub_key          The output public key (or candidate public key in
344*32b31808SJens Wiklander  *                   case this is being run as part of signature
345*32b31808SJens Wiklander  *                   verification), in the form of a hash output.
346*32b31808SJens Wiklander  */
347*32b31808SJens Wiklander static int public_key_from_hashed_digit_array(const mbedtls_lmots_parameters_t *params,
348*32b31808SJens Wiklander                                               const unsigned char *y_hashed_digits,
349*32b31808SJens Wiklander                                               unsigned char *pub_key)
350*32b31808SJens Wiklander {
351*32b31808SJens Wiklander     psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
352*32b31808SJens Wiklander     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
353*32b31808SJens Wiklander     size_t output_hash_len;
354*32b31808SJens Wiklander 
355*32b31808SJens Wiklander     status = psa_hash_setup(&op, PSA_ALG_SHA_256);
356*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
357*32b31808SJens Wiklander         goto exit;
358*32b31808SJens Wiklander     }
359*32b31808SJens Wiklander 
360*32b31808SJens Wiklander     status = psa_hash_update(&op,
361*32b31808SJens Wiklander                              params->I_key_identifier,
362*32b31808SJens Wiklander                              MBEDTLS_LMOTS_I_KEY_ID_LEN);
363*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
364*32b31808SJens Wiklander         goto exit;
365*32b31808SJens Wiklander     }
366*32b31808SJens Wiklander 
367*32b31808SJens Wiklander     status = psa_hash_update(&op, params->q_leaf_identifier,
368*32b31808SJens Wiklander                              MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
369*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
370*32b31808SJens Wiklander         goto exit;
371*32b31808SJens Wiklander     }
372*32b31808SJens Wiklander 
373*32b31808SJens Wiklander     status = psa_hash_update(&op, D_PUBLIC_CONSTANT_BYTES, D_CONST_LEN);
374*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
375*32b31808SJens Wiklander         goto exit;
376*32b31808SJens Wiklander     }
377*32b31808SJens Wiklander 
378*32b31808SJens Wiklander     status = psa_hash_update(&op, y_hashed_digits,
379*32b31808SJens Wiklander                              MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(params->type) *
380*32b31808SJens Wiklander                              MBEDTLS_LMOTS_N_HASH_LEN(params->type));
381*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
382*32b31808SJens Wiklander         goto exit;
383*32b31808SJens Wiklander     }
384*32b31808SJens Wiklander 
385*32b31808SJens Wiklander     status = psa_hash_finish(&op, pub_key,
386*32b31808SJens Wiklander                              MBEDTLS_LMOTS_N_HASH_LEN(params->type),
387*32b31808SJens Wiklander                              &output_hash_len);
388*32b31808SJens Wiklander     if (status != PSA_SUCCESS) {
389*32b31808SJens Wiklander 
390*32b31808SJens Wiklander exit:
391*32b31808SJens Wiklander         psa_hash_abort(&op);
392*32b31808SJens Wiklander     }
393*32b31808SJens Wiklander 
394*32b31808SJens Wiklander     return PSA_TO_MBEDTLS_ERR(status);
395*32b31808SJens Wiklander }
396*32b31808SJens Wiklander 
397*32b31808SJens Wiklander #if !defined(MBEDTLS_DEPRECATED_REMOVED)
398*32b31808SJens Wiklander int mbedtls_lms_error_from_psa(psa_status_t status)
399*32b31808SJens Wiklander {
400*32b31808SJens Wiklander     switch (status) {
401*32b31808SJens Wiklander         case PSA_SUCCESS:
402*32b31808SJens Wiklander             return 0;
403*32b31808SJens Wiklander         case PSA_ERROR_HARDWARE_FAILURE:
404*32b31808SJens Wiklander             return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED;
405*32b31808SJens Wiklander         case PSA_ERROR_NOT_SUPPORTED:
406*32b31808SJens Wiklander             return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
407*32b31808SJens Wiklander         case PSA_ERROR_BUFFER_TOO_SMALL:
408*32b31808SJens Wiklander             return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
409*32b31808SJens Wiklander         case PSA_ERROR_INVALID_ARGUMENT:
410*32b31808SJens Wiklander             return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
411*32b31808SJens Wiklander         default:
412*32b31808SJens Wiklander             return MBEDTLS_ERR_ERROR_GENERIC_ERROR;
413*32b31808SJens Wiklander     }
414*32b31808SJens Wiklander }
415*32b31808SJens Wiklander #endif /* !MBEDTLS_DEPRECATED_REMOVED */
416*32b31808SJens Wiklander 
417*32b31808SJens Wiklander void mbedtls_lmots_public_init(mbedtls_lmots_public_t *ctx)
418*32b31808SJens Wiklander {
419*32b31808SJens Wiklander     memset(ctx, 0, sizeof(*ctx));
420*32b31808SJens Wiklander }
421*32b31808SJens Wiklander 
422*32b31808SJens Wiklander void mbedtls_lmots_public_free(mbedtls_lmots_public_t *ctx)
423*32b31808SJens Wiklander {
424*32b31808SJens Wiklander     mbedtls_platform_zeroize(ctx, sizeof(*ctx));
425*32b31808SJens Wiklander }
426*32b31808SJens Wiklander 
427*32b31808SJens Wiklander int mbedtls_lmots_import_public_key(mbedtls_lmots_public_t *ctx,
428*32b31808SJens Wiklander                                     const unsigned char *key, size_t key_len)
429*32b31808SJens Wiklander {
430*32b31808SJens Wiklander     if (key_len < MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
431*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
432*32b31808SJens Wiklander     }
433*32b31808SJens Wiklander 
434*32b31808SJens Wiklander     ctx->params.type =
435*32b31808SJens Wiklander         mbedtls_lms_network_bytes_to_unsigned_int(MBEDTLS_LMOTS_TYPE_LEN,
436*32b31808SJens Wiklander                                                   key + MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
437*32b31808SJens Wiklander 
438*32b31808SJens Wiklander     if (key_len != MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type)) {
439*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
440*32b31808SJens Wiklander     }
441*32b31808SJens Wiklander 
442*32b31808SJens Wiklander     memcpy(ctx->params.I_key_identifier,
443*32b31808SJens Wiklander            key + PUBLIC_KEY_I_KEY_ID_OFFSET,
444*32b31808SJens Wiklander            MBEDTLS_LMOTS_I_KEY_ID_LEN);
445*32b31808SJens Wiklander 
446*32b31808SJens Wiklander     memcpy(ctx->params.q_leaf_identifier,
447*32b31808SJens Wiklander            key + PUBLIC_KEY_Q_LEAF_ID_OFFSET,
448*32b31808SJens Wiklander            MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
449*32b31808SJens Wiklander 
450*32b31808SJens Wiklander     memcpy(ctx->public_key,
451*32b31808SJens Wiklander            key + PUBLIC_KEY_KEY_HASH_OFFSET,
452*32b31808SJens Wiklander            MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
453*32b31808SJens Wiklander 
454*32b31808SJens Wiklander     ctx->have_public_key = 1;
455*32b31808SJens Wiklander 
456*32b31808SJens Wiklander     return 0;
457*32b31808SJens Wiklander }
458*32b31808SJens Wiklander 
459*32b31808SJens Wiklander int mbedtls_lmots_export_public_key(const mbedtls_lmots_public_t *ctx,
460*32b31808SJens Wiklander                                     unsigned char *key, size_t key_size,
461*32b31808SJens Wiklander                                     size_t *key_len)
462*32b31808SJens Wiklander {
463*32b31808SJens Wiklander     if (key_size < MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type)) {
464*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
465*32b31808SJens Wiklander     }
466*32b31808SJens Wiklander 
467*32b31808SJens Wiklander     if (!ctx->have_public_key) {
468*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
469*32b31808SJens Wiklander     }
470*32b31808SJens Wiklander 
471*32b31808SJens Wiklander     mbedtls_lms_unsigned_int_to_network_bytes(ctx->params.type,
472*32b31808SJens Wiklander                                               MBEDTLS_LMOTS_TYPE_LEN,
473*32b31808SJens Wiklander                                               key + MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
474*32b31808SJens Wiklander 
475*32b31808SJens Wiklander     memcpy(key + PUBLIC_KEY_I_KEY_ID_OFFSET,
476*32b31808SJens Wiklander            ctx->params.I_key_identifier,
477*32b31808SJens Wiklander            MBEDTLS_LMOTS_I_KEY_ID_LEN);
478*32b31808SJens Wiklander 
479*32b31808SJens Wiklander     memcpy(key + PUBLIC_KEY_Q_LEAF_ID_OFFSET,
480*32b31808SJens Wiklander            ctx->params.q_leaf_identifier,
481*32b31808SJens Wiklander            MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
482*32b31808SJens Wiklander 
483*32b31808SJens Wiklander     memcpy(key + PUBLIC_KEY_KEY_HASH_OFFSET, ctx->public_key,
484*32b31808SJens Wiklander            MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
485*32b31808SJens Wiklander 
486*32b31808SJens Wiklander     if (key_len != NULL) {
487*32b31808SJens Wiklander         *key_len = MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type);
488*32b31808SJens Wiklander     }
489*32b31808SJens Wiklander 
490*32b31808SJens Wiklander     return 0;
491*32b31808SJens Wiklander }
492*32b31808SJens Wiklander 
493*32b31808SJens Wiklander int mbedtls_lmots_calculate_public_key_candidate(const mbedtls_lmots_parameters_t *params,
494*32b31808SJens Wiklander                                                  const unsigned char  *msg,
495*32b31808SJens Wiklander                                                  size_t msg_size,
496*32b31808SJens Wiklander                                                  const unsigned char *sig,
497*32b31808SJens Wiklander                                                  size_t sig_size,
498*32b31808SJens Wiklander                                                  unsigned char *out,
499*32b31808SJens Wiklander                                                  size_t out_size,
500*32b31808SJens Wiklander                                                  size_t *out_len)
501*32b31808SJens Wiklander {
502*32b31808SJens Wiklander     unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX];
503*32b31808SJens Wiklander     unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
504*32b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
505*32b31808SJens Wiklander 
506*32b31808SJens Wiklander     if (msg == NULL && msg_size != 0) {
507*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
508*32b31808SJens Wiklander     }
509*32b31808SJens Wiklander 
510*32b31808SJens Wiklander     if (sig_size != MBEDTLS_LMOTS_SIG_LEN(params->type) ||
511*32b31808SJens Wiklander         out_size < MBEDTLS_LMOTS_N_HASH_LEN(params->type)) {
512*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
513*32b31808SJens Wiklander     }
514*32b31808SJens Wiklander 
515*32b31808SJens Wiklander     ret = create_digit_array_with_checksum(params, msg, msg_size,
516*32b31808SJens Wiklander                                            sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET,
517*32b31808SJens Wiklander                                            tmp_digit_array);
518*32b31808SJens Wiklander     if (ret) {
519*32b31808SJens Wiklander         return ret;
520*32b31808SJens Wiklander     }
521*32b31808SJens Wiklander 
522*32b31808SJens Wiklander     ret = hash_digit_array(params,
523*32b31808SJens Wiklander                            sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(params->type),
524*32b31808SJens Wiklander                            tmp_digit_array, NULL, (unsigned char *) y_hashed_digits);
525*32b31808SJens Wiklander     if (ret) {
526*32b31808SJens Wiklander         return ret;
527*32b31808SJens Wiklander     }
528*32b31808SJens Wiklander 
529*32b31808SJens Wiklander     ret = public_key_from_hashed_digit_array(params,
530*32b31808SJens Wiklander                                              (unsigned char *) y_hashed_digits,
531*32b31808SJens Wiklander                                              out);
532*32b31808SJens Wiklander     if (ret) {
533*32b31808SJens Wiklander         return ret;
534*32b31808SJens Wiklander     }
535*32b31808SJens Wiklander 
536*32b31808SJens Wiklander     if (out_len != NULL) {
537*32b31808SJens Wiklander         *out_len = MBEDTLS_LMOTS_N_HASH_LEN(params->type);
538*32b31808SJens Wiklander     }
539*32b31808SJens Wiklander 
540*32b31808SJens Wiklander     return 0;
541*32b31808SJens Wiklander }
542*32b31808SJens Wiklander 
543*32b31808SJens Wiklander int mbedtls_lmots_verify(const mbedtls_lmots_public_t *ctx,
544*32b31808SJens Wiklander                          const unsigned char *msg, size_t msg_size,
545*32b31808SJens Wiklander                          const unsigned char *sig, size_t sig_size)
546*32b31808SJens Wiklander {
547*32b31808SJens Wiklander     unsigned char Kc_public_key_candidate[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
548*32b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
549*32b31808SJens Wiklander 
550*32b31808SJens Wiklander     if (msg == NULL && msg_size != 0) {
551*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
552*32b31808SJens Wiklander     }
553*32b31808SJens Wiklander 
554*32b31808SJens Wiklander     if (!ctx->have_public_key) {
555*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
556*32b31808SJens Wiklander     }
557*32b31808SJens Wiklander 
558*32b31808SJens Wiklander     if (ctx->params.type != MBEDTLS_LMOTS_SHA256_N32_W8) {
559*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
560*32b31808SJens Wiklander     }
561*32b31808SJens Wiklander 
562*32b31808SJens Wiklander     if (sig_size < MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
563*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_VERIFY_FAILED;
564*32b31808SJens Wiklander     }
565*32b31808SJens Wiklander 
566*32b31808SJens Wiklander     if (mbedtls_lms_network_bytes_to_unsigned_int(MBEDTLS_LMOTS_TYPE_LEN,
567*32b31808SJens Wiklander                                                   sig + MBEDTLS_LMOTS_SIG_TYPE_OFFSET) !=
568*32b31808SJens Wiklander         MBEDTLS_LMOTS_SHA256_N32_W8) {
569*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_VERIFY_FAILED;
570*32b31808SJens Wiklander     }
571*32b31808SJens Wiklander 
572*32b31808SJens Wiklander     ret = mbedtls_lmots_calculate_public_key_candidate(&ctx->params,
573*32b31808SJens Wiklander                                                        msg, msg_size, sig, sig_size,
574*32b31808SJens Wiklander                                                        Kc_public_key_candidate,
575*32b31808SJens Wiklander                                                        MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type),
576*32b31808SJens Wiklander                                                        NULL);
577*32b31808SJens Wiklander     if (ret) {
578*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_VERIFY_FAILED;
579*32b31808SJens Wiklander     }
580*32b31808SJens Wiklander 
581*32b31808SJens Wiklander     if (memcmp(&Kc_public_key_candidate, ctx->public_key,
582*32b31808SJens Wiklander                sizeof(ctx->public_key))) {
583*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_VERIFY_FAILED;
584*32b31808SJens Wiklander     }
585*32b31808SJens Wiklander 
586*32b31808SJens Wiklander     return 0;
587*32b31808SJens Wiklander }
588*32b31808SJens Wiklander 
589*32b31808SJens Wiklander #if defined(MBEDTLS_LMS_PRIVATE)
590*32b31808SJens Wiklander 
591*32b31808SJens Wiklander void mbedtls_lmots_private_init(mbedtls_lmots_private_t *ctx)
592*32b31808SJens Wiklander {
593*32b31808SJens Wiklander     memset(ctx, 0, sizeof(*ctx));
594*32b31808SJens Wiklander }
595*32b31808SJens Wiklander 
596*32b31808SJens Wiklander void mbedtls_lmots_private_free(mbedtls_lmots_private_t *ctx)
597*32b31808SJens Wiklander {
598*32b31808SJens Wiklander     mbedtls_platform_zeroize(ctx,
599*32b31808SJens Wiklander                              sizeof(*ctx));
600*32b31808SJens Wiklander }
601*32b31808SJens Wiklander 
602*32b31808SJens Wiklander int mbedtls_lmots_generate_private_key(mbedtls_lmots_private_t *ctx,
603*32b31808SJens Wiklander                                        mbedtls_lmots_algorithm_type_t type,
604*32b31808SJens Wiklander                                        const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
605*32b31808SJens Wiklander                                        uint32_t q_leaf_identifier,
606*32b31808SJens Wiklander                                        const unsigned char *seed,
607*32b31808SJens Wiklander                                        size_t seed_size)
608*32b31808SJens Wiklander {
609*32b31808SJens Wiklander     psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
610*32b31808SJens Wiklander     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
611*32b31808SJens Wiklander     size_t output_hash_len;
612*32b31808SJens Wiklander     unsigned int i_digit_idx;
613*32b31808SJens Wiklander     unsigned char i_digit_idx_bytes[2];
614*32b31808SJens Wiklander     unsigned char const_bytes[1];
615*32b31808SJens Wiklander 
616*32b31808SJens Wiklander     if (ctx->have_private_key) {
617*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
618*32b31808SJens Wiklander     }
619*32b31808SJens Wiklander 
620*32b31808SJens Wiklander     if (type != MBEDTLS_LMOTS_SHA256_N32_W8) {
621*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
622*32b31808SJens Wiklander     }
623*32b31808SJens Wiklander 
624*32b31808SJens Wiklander     ctx->params.type = type;
625*32b31808SJens Wiklander 
626*32b31808SJens Wiklander     memcpy(ctx->params.I_key_identifier,
627*32b31808SJens Wiklander            I_key_identifier,
628*32b31808SJens Wiklander            sizeof(ctx->params.I_key_identifier));
629*32b31808SJens Wiklander 
630*32b31808SJens Wiklander     mbedtls_lms_unsigned_int_to_network_bytes(q_leaf_identifier,
631*32b31808SJens Wiklander                                               MBEDTLS_LMOTS_Q_LEAF_ID_LEN,
632*32b31808SJens Wiklander                                               ctx->params.q_leaf_identifier);
633*32b31808SJens Wiklander 
634*32b31808SJens Wiklander     mbedtls_lms_unsigned_int_to_network_bytes(0xFF, sizeof(const_bytes),
635*32b31808SJens Wiklander                                               const_bytes);
636*32b31808SJens Wiklander 
637*32b31808SJens Wiklander     for (i_digit_idx = 0;
638*32b31808SJens Wiklander          i_digit_idx < MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type);
639*32b31808SJens Wiklander          i_digit_idx++) {
640*32b31808SJens Wiklander         status = psa_hash_setup(&op, PSA_ALG_SHA_256);
641*32b31808SJens Wiklander         if (status != PSA_SUCCESS) {
642*32b31808SJens Wiklander             goto exit;
643*32b31808SJens Wiklander         }
644*32b31808SJens Wiklander 
645*32b31808SJens Wiklander         status = psa_hash_update(&op,
646*32b31808SJens Wiklander                                  ctx->params.I_key_identifier,
647*32b31808SJens Wiklander                                  sizeof(ctx->params.I_key_identifier));
648*32b31808SJens Wiklander         if (status != PSA_SUCCESS) {
649*32b31808SJens Wiklander             goto exit;
650*32b31808SJens Wiklander         }
651*32b31808SJens Wiklander 
652*32b31808SJens Wiklander         status = psa_hash_update(&op,
653*32b31808SJens Wiklander                                  ctx->params.q_leaf_identifier,
654*32b31808SJens Wiklander                                  MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
655*32b31808SJens Wiklander         if (status != PSA_SUCCESS) {
656*32b31808SJens Wiklander             goto exit;
657*32b31808SJens Wiklander         }
658*32b31808SJens Wiklander 
659*32b31808SJens Wiklander         mbedtls_lms_unsigned_int_to_network_bytes(i_digit_idx, I_DIGIT_IDX_LEN,
660*32b31808SJens Wiklander                                                   i_digit_idx_bytes);
661*32b31808SJens Wiklander         status = psa_hash_update(&op, i_digit_idx_bytes, I_DIGIT_IDX_LEN);
662*32b31808SJens Wiklander         if (status != PSA_SUCCESS) {
663*32b31808SJens Wiklander             goto exit;
664*32b31808SJens Wiklander         }
665*32b31808SJens Wiklander 
666*32b31808SJens Wiklander         status = psa_hash_update(&op, const_bytes, sizeof(const_bytes));
667*32b31808SJens Wiklander         if (status != PSA_SUCCESS) {
668*32b31808SJens Wiklander             goto exit;
669*32b31808SJens Wiklander         }
670*32b31808SJens Wiklander 
671*32b31808SJens Wiklander         status = psa_hash_update(&op, seed, seed_size);
672*32b31808SJens Wiklander         if (status != PSA_SUCCESS) {
673*32b31808SJens Wiklander             goto exit;
674*32b31808SJens Wiklander         }
675*32b31808SJens Wiklander 
676*32b31808SJens Wiklander         status = psa_hash_finish(&op,
677*32b31808SJens Wiklander                                  ctx->private_key[i_digit_idx],
678*32b31808SJens Wiklander                                  MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type),
679*32b31808SJens Wiklander                                  &output_hash_len);
680*32b31808SJens Wiklander         if (status != PSA_SUCCESS) {
681*32b31808SJens Wiklander             goto exit;
682*32b31808SJens Wiklander         }
683*32b31808SJens Wiklander 
684*32b31808SJens Wiklander         psa_hash_abort(&op);
685*32b31808SJens Wiklander     }
686*32b31808SJens Wiklander 
687*32b31808SJens Wiklander     ctx->have_private_key = 1;
688*32b31808SJens Wiklander 
689*32b31808SJens Wiklander exit:
690*32b31808SJens Wiklander     psa_hash_abort(&op);
691*32b31808SJens Wiklander 
692*32b31808SJens Wiklander     return PSA_TO_MBEDTLS_ERR(status);
693*32b31808SJens Wiklander }
694*32b31808SJens Wiklander 
695*32b31808SJens Wiklander int mbedtls_lmots_calculate_public_key(mbedtls_lmots_public_t *ctx,
696*32b31808SJens Wiklander                                        const mbedtls_lmots_private_t *priv_ctx)
697*32b31808SJens Wiklander {
698*32b31808SJens Wiklander     unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
699*32b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
700*32b31808SJens Wiklander 
701*32b31808SJens Wiklander     /* Check that a private key is loaded */
702*32b31808SJens Wiklander     if (!priv_ctx->have_private_key) {
703*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
704*32b31808SJens Wiklander     }
705*32b31808SJens Wiklander 
706*32b31808SJens Wiklander     ret = hash_digit_array(&priv_ctx->params,
707*32b31808SJens Wiklander                            (unsigned char *) priv_ctx->private_key, NULL,
708*32b31808SJens Wiklander                            NULL, (unsigned char *) y_hashed_digits);
709*32b31808SJens Wiklander     if (ret) {
710*32b31808SJens Wiklander         goto exit;
711*32b31808SJens Wiklander     }
712*32b31808SJens Wiklander 
713*32b31808SJens Wiklander     ret = public_key_from_hashed_digit_array(&priv_ctx->params,
714*32b31808SJens Wiklander                                              (unsigned char *) y_hashed_digits,
715*32b31808SJens Wiklander                                              ctx->public_key);
716*32b31808SJens Wiklander     if (ret) {
717*32b31808SJens Wiklander         goto exit;
718*32b31808SJens Wiklander     }
719*32b31808SJens Wiklander 
720*32b31808SJens Wiklander     memcpy(&ctx->params, &priv_ctx->params,
721*32b31808SJens Wiklander            sizeof(ctx->params));
722*32b31808SJens Wiklander 
723*32b31808SJens Wiklander     ctx->have_public_key = 1;
724*32b31808SJens Wiklander 
725*32b31808SJens Wiklander exit:
726*32b31808SJens Wiklander     mbedtls_platform_zeroize(y_hashed_digits, sizeof(y_hashed_digits));
727*32b31808SJens Wiklander 
728*32b31808SJens Wiklander     return ret;
729*32b31808SJens Wiklander }
730*32b31808SJens Wiklander 
731*32b31808SJens Wiklander int mbedtls_lmots_sign(mbedtls_lmots_private_t *ctx,
732*32b31808SJens Wiklander                        int (*f_rng)(void *, unsigned char *, size_t),
733*32b31808SJens Wiklander                        void *p_rng, const unsigned char *msg, size_t msg_size,
734*32b31808SJens Wiklander                        unsigned char *sig, size_t sig_size, size_t *sig_len)
735*32b31808SJens Wiklander {
736*32b31808SJens Wiklander     unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX];
737*32b31808SJens Wiklander     /* Create a temporary buffer to prepare the signature in. This allows us to
738*32b31808SJens Wiklander      * finish creating a signature (ensuring the process doesn't fail), and then
739*32b31808SJens Wiklander      * erase the private key **before** writing any data into the sig parameter
740*32b31808SJens Wiklander      * buffer. If data were directly written into the sig buffer, it might leak
741*32b31808SJens Wiklander      * a partial signature on failure, which effectively compromises the private
742*32b31808SJens Wiklander      * key.
743*32b31808SJens Wiklander      */
744*32b31808SJens Wiklander     unsigned char tmp_sig[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
745*32b31808SJens Wiklander     unsigned char tmp_c_random[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
746*32b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
747*32b31808SJens Wiklander 
748*32b31808SJens Wiklander     if (msg == NULL && msg_size != 0) {
749*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
750*32b31808SJens Wiklander     }
751*32b31808SJens Wiklander 
752*32b31808SJens Wiklander     if (sig_size < MBEDTLS_LMOTS_SIG_LEN(ctx->params.type)) {
753*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
754*32b31808SJens Wiklander     }
755*32b31808SJens Wiklander 
756*32b31808SJens Wiklander     /* Check that a private key is loaded */
757*32b31808SJens Wiklander     if (!ctx->have_private_key) {
758*32b31808SJens Wiklander         return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
759*32b31808SJens Wiklander     }
760*32b31808SJens Wiklander 
761*32b31808SJens Wiklander     ret = f_rng(p_rng, tmp_c_random,
762*32b31808SJens Wiklander                 MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
763*32b31808SJens Wiklander     if (ret) {
764*32b31808SJens Wiklander         return ret;
765*32b31808SJens Wiklander     }
766*32b31808SJens Wiklander 
767*32b31808SJens Wiklander     ret = create_digit_array_with_checksum(&ctx->params,
768*32b31808SJens Wiklander                                            msg, msg_size,
769*32b31808SJens Wiklander                                            tmp_c_random,
770*32b31808SJens Wiklander                                            tmp_digit_array);
771*32b31808SJens Wiklander     if (ret) {
772*32b31808SJens Wiklander         goto exit;
773*32b31808SJens Wiklander     }
774*32b31808SJens Wiklander 
775*32b31808SJens Wiklander     ret = hash_digit_array(&ctx->params, (unsigned char *) ctx->private_key,
776*32b31808SJens Wiklander                            NULL, tmp_digit_array, (unsigned char *) tmp_sig);
777*32b31808SJens Wiklander     if (ret) {
778*32b31808SJens Wiklander         goto exit;
779*32b31808SJens Wiklander     }
780*32b31808SJens Wiklander 
781*32b31808SJens Wiklander     mbedtls_lms_unsigned_int_to_network_bytes(ctx->params.type,
782*32b31808SJens Wiklander                                               MBEDTLS_LMOTS_TYPE_LEN,
783*32b31808SJens Wiklander                                               sig + MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
784*32b31808SJens Wiklander 
785*32b31808SJens Wiklander     /* Test hook to check if sig is being written to before we invalidate the
786*32b31808SJens Wiklander      * private key.
787*32b31808SJens Wiklander      */
788*32b31808SJens Wiklander #if defined(MBEDTLS_TEST_HOOKS)
789*32b31808SJens Wiklander     if (mbedtls_lmots_sign_private_key_invalidated_hook != NULL) {
790*32b31808SJens Wiklander         ret = (*mbedtls_lmots_sign_private_key_invalidated_hook)(sig);
791*32b31808SJens Wiklander         if (ret != 0) {
792*32b31808SJens Wiklander             return ret;
793*32b31808SJens Wiklander         }
794*32b31808SJens Wiklander     }
795*32b31808SJens Wiklander #endif /* defined(MBEDTLS_TEST_HOOKS) */
796*32b31808SJens Wiklander 
797*32b31808SJens Wiklander     /* We've got a valid signature now, so it's time to make sure the private
798*32b31808SJens Wiklander      * key can't be reused.
799*32b31808SJens Wiklander      */
800*32b31808SJens Wiklander     ctx->have_private_key = 0;
801*32b31808SJens Wiklander     mbedtls_platform_zeroize(ctx->private_key,
802*32b31808SJens Wiklander                              sizeof(ctx->private_key));
803*32b31808SJens Wiklander 
804*32b31808SJens Wiklander     memcpy(sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET, tmp_c_random,
805*32b31808SJens Wiklander            MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(ctx->params.type));
806*32b31808SJens Wiklander 
807*32b31808SJens Wiklander     memcpy(sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(ctx->params.type), tmp_sig,
808*32b31808SJens Wiklander            MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type)
809*32b31808SJens Wiklander            * MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
810*32b31808SJens Wiklander 
811*32b31808SJens Wiklander     if (sig_len != NULL) {
812*32b31808SJens Wiklander         *sig_len = MBEDTLS_LMOTS_SIG_LEN(ctx->params.type);
813*32b31808SJens Wiklander     }
814*32b31808SJens Wiklander 
815*32b31808SJens Wiklander     ret = 0;
816*32b31808SJens Wiklander 
817*32b31808SJens Wiklander exit:
818*32b31808SJens Wiklander     mbedtls_platform_zeroize(tmp_digit_array, sizeof(tmp_digit_array));
819*32b31808SJens Wiklander     mbedtls_platform_zeroize(tmp_sig, sizeof(tmp_sig));
820*32b31808SJens Wiklander 
821*32b31808SJens Wiklander     return ret;
822*32b31808SJens Wiklander }
823*32b31808SJens Wiklander 
824*32b31808SJens Wiklander #endif /* defined(MBEDTLS_LMS_PRIVATE) */
825*32b31808SJens Wiklander #endif /* defined(MBEDTLS_LMS_C) */
826