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