|
| 1 | +/* |
| 2 | + This file is part of the UNOR4USBBridge project. |
| 3 | +
|
| 4 | + Copyright (c) 2024 Arduino SA |
| 5 | +
|
| 6 | + This Source Code Form is subject to the terms of the Mozilla Public |
| 7 | + License, v. 2.0. If a copy of the MPL was not distributed with this |
| 8 | + file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| 9 | +*/ |
| 10 | + |
| 11 | +/****************************************************************************** |
| 12 | + INCLUDE |
| 13 | + ******************************************************************************/ |
| 14 | +#include <Arduino_DebugUtils.h> |
| 15 | + |
| 16 | +#include "mbedtls/pk.h" |
| 17 | +#include "mbedtls/ctr_drbg.h" |
| 18 | +#include "mbedtls/entropy.h" |
| 19 | + |
| 20 | +#include "mbedtls/error.h" |
| 21 | +#include "mbedtls/asn1.h" |
| 22 | +#include "mbedtls/asn1write.h" |
| 23 | +#include "mbedtls/sha256.h" |
| 24 | + |
| 25 | +#include "SSE.h" |
| 26 | + |
| 27 | +/****************************************************************************** |
| 28 | + LOCAL MODULE FUNCTIONS |
| 29 | + ******************************************************************************/ |
| 30 | + |
| 31 | +/* |
| 32 | + * Keep an eye on this new implementation from mbedtls not yet merged |
| 33 | + * https://github.com/Mbed-TLS/mbedtls/pull/8703/files |
| 34 | + */ |
| 35 | + |
| 36 | +/* |
| 37 | + * https://github.com/Mbed-TLS/mbedtls/blob/aa3fa98bc4a99d21a973b891bf7bda9a27647068/library/pk_wrap.c#L543 |
| 38 | + * An ASN.1 encoded signature is a sequence of two ASN.1 integers. Parse one of |
| 39 | + * those integers and convert it to the fixed-length encoding expected by PSA. |
| 40 | + */ |
| 41 | +static int extract_ecdsa_sig_int(unsigned char **from, const unsigned char *end, |
| 42 | + unsigned char *to, size_t to_len) |
| 43 | +{ |
| 44 | + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| 45 | + size_t unpadded_len, padding_len; |
| 46 | + |
| 47 | + if ((ret = mbedtls_asn1_get_tag(from, end, &unpadded_len, |
| 48 | + MBEDTLS_ASN1_INTEGER)) != 0) { |
| 49 | + return ret; |
| 50 | + } |
| 51 | + |
| 52 | + while (unpadded_len > 0 && **from == 0x00) { |
| 53 | + (*from)++; |
| 54 | + unpadded_len--; |
| 55 | + } |
| 56 | + |
| 57 | + if (unpadded_len > to_len || unpadded_len == 0) { |
| 58 | + return MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; |
| 59 | + } |
| 60 | + |
| 61 | + padding_len = to_len - unpadded_len; |
| 62 | + memset(to, 0x00, padding_len); |
| 63 | + memcpy(to + padding_len, *from, unpadded_len); |
| 64 | + (*from) += unpadded_len; |
| 65 | + |
| 66 | + return 0; |
| 67 | +} |
| 68 | + |
| 69 | +/* |
| 70 | + * https://github.com/Mbed-TLS/mbedtls/blob/aa3fa98bc4a99d21a973b891bf7bda9a27647068/library/pk_wrap.c#L576 |
| 71 | + * Convert a signature from an ASN.1 sequence of two integers |
| 72 | + * to a raw {r,s} buffer. Note: the provided sig buffer must be at least |
| 73 | + * twice as big as int_size. |
| 74 | + */ |
| 75 | +static int extract_ecdsa_sig(unsigned char **p, const unsigned char *end, |
| 76 | + unsigned char *sig, size_t int_size) |
| 77 | +{ |
| 78 | + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| 79 | + size_t tmp_size; |
| 80 | + |
| 81 | + if ((ret = mbedtls_asn1_get_tag(p, end, &tmp_size, |
| 82 | + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { |
| 83 | + return ret; |
| 84 | + } |
| 85 | + |
| 86 | + /* Extract r */ |
| 87 | + if ((ret = extract_ecdsa_sig_int(p, end, sig, int_size)) != 0) { |
| 88 | + return ret; |
| 89 | + } |
| 90 | + /* Extract s */ |
| 91 | + if ((ret = extract_ecdsa_sig_int(p, end, sig + int_size, int_size)) != 0) { |
| 92 | + return ret; |
| 93 | + } |
| 94 | + |
| 95 | + return 0; |
| 96 | +} |
| 97 | + |
| 98 | +/* |
| 99 | + * https://github.com/Mbed-TLS/mbedtls/blob/47c74a477378ec3f0d1ba80547db836e078fa3a0/library/ecdsa.c#L609 |
| 100 | + * Convert a signature (given by context) to ASN.1 |
| 101 | + */ |
| 102 | +static int ecdsa_signature_to_asn1(const mbedtls_mpi *r, const mbedtls_mpi *s, |
| 103 | + unsigned char *sig, size_t sig_size, |
| 104 | + size_t *slen) |
| 105 | +{ |
| 106 | + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
| 107 | + unsigned char buf[MBEDTLS_ECDSA_MAX_LEN] = { 0 }; |
| 108 | + unsigned char *p = buf + sizeof(buf); |
| 109 | + size_t len = 0; |
| 110 | + |
| 111 | + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_mpi(&p, buf, s)); |
| 112 | + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_mpi(&p, buf, r)); |
| 113 | + |
| 114 | + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&p, buf, len)); |
| 115 | + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&p, buf, |
| 116 | + MBEDTLS_ASN1_CONSTRUCTED | |
| 117 | + MBEDTLS_ASN1_SEQUENCE)); |
| 118 | + |
| 119 | + if (len > sig_size) { |
| 120 | + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; |
| 121 | + } |
| 122 | + |
| 123 | + memcpy(sig, p, len); |
| 124 | + *slen = len; |
| 125 | + |
| 126 | + return 0; |
| 127 | +} |
| 128 | + |
| 129 | + |
| 130 | +/****************************************************************************** |
| 131 | + PUBLIC MEMBER FUNCTIONS |
| 132 | + ******************************************************************************/ |
| 133 | + |
| 134 | +int Arduino_UNOWIFIR4_SSE::generateECKeyPair(unsigned char* derKey, int maxLen) |
| 135 | +{ |
| 136 | + int ret = 1; |
| 137 | + mbedtls_pk_context key; |
| 138 | + mbedtls_ctr_drbg_context ctr_drbg; |
| 139 | + mbedtls_entropy_context entropy; |
| 140 | + const char *pers = "gen_key"; |
| 141 | + unsigned char mbedtls_buf[SSE_EC256_DER_PRI_KEY_LENGTH] = { 0 }; |
| 142 | + |
| 143 | + mbedtls_pk_init(&key); |
| 144 | + mbedtls_entropy_init(&entropy); |
| 145 | + mbedtls_ctr_drbg_init(&ctr_drbg); |
| 146 | + |
| 147 | + if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers))) != 0) { |
| 148 | + DEBUG_ERROR(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%04x\n", (unsigned int) -ret); |
| 149 | + goto exit; |
| 150 | + } |
| 151 | + |
| 152 | + if ((ret = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type((mbedtls_pk_type_t) MBEDTLS_PK_ECKEY))) != 0) { |
| 153 | + DEBUG_ERROR(" failed\n ! mbedtls_pk_setup returned -0x%04x", (unsigned int) -ret); |
| 154 | + goto exit; |
| 155 | + } |
| 156 | + |
| 157 | + if ((ret = mbedtls_ecp_gen_key((mbedtls_ecp_group_id) MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(key), mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { |
| 158 | + DEBUG_ERROR(" failed\n ! mbedtls_ecp_gen_key returned -0x%04x", (unsigned int) -ret); |
| 159 | + goto exit; |
| 160 | + } |
| 161 | + |
| 162 | + if ((ret = mbedtls_pk_write_key_der(&key, mbedtls_buf, sizeof(mbedtls_buf))) < 0) { |
| 163 | + DEBUG_ERROR(" failed\n ! mbedtls_pk_write_key_der returned -0x%04x", (unsigned int) -ret); |
| 164 | + goto exit; |
| 165 | + } |
| 166 | + |
| 167 | + if (ret > maxLen) { |
| 168 | + DEBUG_ERROR(" failed\n ! output buffer too small operation needs 0x%04x bytes", (unsigned int) ret); |
| 169 | + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; |
| 170 | + goto exit; |
| 171 | + } |
| 172 | + |
| 173 | + /* Copy data from the end of mbedtls_buf buffer to der output */ |
| 174 | + memcpy(derKey, &mbedtls_buf[sizeof(mbedtls_buf) - ret], ret); |
| 175 | + |
| 176 | +exit: |
| 177 | + mbedtls_ctr_drbg_free(&ctr_drbg); |
| 178 | + mbedtls_entropy_free(&entropy); |
| 179 | + mbedtls_pk_free(&key); |
| 180 | + |
| 181 | + return ret; |
| 182 | +} |
| 183 | + |
| 184 | +int Arduino_UNOWIFIR4_SSE::exportECKeyXY(const unsigned char* derKey, int derLen, unsigned char* pubXY) |
| 185 | +{ |
| 186 | + int ret = 1; |
| 187 | + mbedtls_pk_context key; |
| 188 | + mbedtls_ecp_keypair *ecp; |
| 189 | + |
| 190 | + mbedtls_pk_init(&key); |
| 191 | + |
| 192 | + /* Check if we can use parse public key */ |
| 193 | + if ((ret = mbedtls_pk_parse_key(&key, derKey, derLen, NULL, 0)) != 0) { |
| 194 | + DEBUG_ERROR(" failed\n ! mbedtls_pk_parse_key returned -0x%04x", (unsigned int) -ret); |
| 195 | + goto exit; |
| 196 | + } |
| 197 | + |
| 198 | + if (mbedtls_pk_get_type(&key) != MBEDTLS_PK_ECKEY) { |
| 199 | + DEBUG_ERROR(" failed\n ! Not an EC KEY"); |
| 200 | + goto exit; |
| 201 | + } |
| 202 | + |
| 203 | + /* Get elliptic curve point */ |
| 204 | + ecp = mbedtls_pk_ec(key); |
| 205 | + if ((ret = mbedtls_mpi_write_binary(&ecp->Q.X, &pubXY[0], SSE_EC256_X_LENGTH)) != 0) { |
| 206 | + DEBUG_ERROR(" failed\n ! mbedtls_mpi_write_binary Q.X returned -0x%04x", (unsigned int) -ret); |
| 207 | + goto exit; |
| 208 | + } |
| 209 | + |
| 210 | + if ((ret = mbedtls_mpi_write_binary(&ecp->Q.Y, &pubXY[SSE_EC256_X_LENGTH], SSE_EC256_Y_LENGTH)) != 0) { |
| 211 | + DEBUG_ERROR(" failed\n ! mbedtls_mpi_write_binary Q.XYreturned -0x%04x", (unsigned int) -ret); |
| 212 | + goto exit; |
| 213 | + } |
| 214 | + |
| 215 | + /* Success */ |
| 216 | + ret = SSE_EC256_PUB_KEY_LENGTH; |
| 217 | + |
| 218 | +exit: |
| 219 | + mbedtls_pk_free(&key); |
| 220 | + return ret; |
| 221 | +} |
| 222 | + |
| 223 | +int Arduino_UNOWIFIR4_SSE::importECKeyXY(const unsigned char* pubXY, unsigned char* derKey, int maxLen) |
| 224 | +{ |
| 225 | + int ret = 1; |
| 226 | + mbedtls_pk_context key; |
| 227 | + unsigned char mbedtls_buf[SSE_EC256_DER_PUB_KEY_LENGTH] = { 0 }; |
| 228 | + mbedtls_ecp_keypair* ecp; |
| 229 | + |
| 230 | + mbedtls_pk_init(&key); |
| 231 | + |
| 232 | + if ((ret = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type((mbedtls_pk_type_t) MBEDTLS_PK_ECKEY))) != 0) { |
| 233 | + DEBUG_ERROR(" failed\n ! mbedtls_pk_setup returned -0x%04x", (unsigned int) -ret); |
| 234 | + goto exit; |
| 235 | + } |
| 236 | + |
| 237 | + if (mbedtls_pk_get_type(&key) != MBEDTLS_PK_ECKEY) { |
| 238 | + DEBUG_ERROR(" failed\n ! Not an EC KEY"); |
| 239 | + goto exit; |
| 240 | + } |
| 241 | + |
| 242 | + ecp = mbedtls_pk_ec(key); |
| 243 | + |
| 244 | + if (( ret = mbedtls_ecp_group_load(&ecp->grp, MBEDTLS_ECP_DP_SECP256R1)) != 0) { |
| 245 | + DEBUG_ERROR(" failed\n ! mbedtls_ecp_group_load returned -0x%04x", (unsigned int) -ret); |
| 246 | + goto exit; |
| 247 | + } |
| 248 | + |
| 249 | + /* |
| 250 | + * Add uncompressed flag {0x04 | X | Y } |
| 251 | + * https://github.com/Mbed-TLS/mbedtls/blob/f660c7c92308b6080f8ca97fa1739370d1b2fab5/include/psa/crypto.h#L783 |
| 252 | + */ |
| 253 | + mbedtls_buf[0] = 0x04; memcpy(&mbedtls_buf[1], pubXY, SSE_EC256_PUB_KEY_LENGTH); |
| 254 | + |
| 255 | + if (( ret = mbedtls_ecp_point_read_binary(&ecp->grp, &ecp->Q, mbedtls_buf, SSE_EC256_PUB_KEY_LENGTH + 1)) != 0) { |
| 256 | + DEBUG_ERROR(" failed\n ! mbedtls_ecp_point_read_binary returned -0x%04x", (unsigned int) -ret); |
| 257 | + goto exit; |
| 258 | + } |
| 259 | + |
| 260 | + if ((ret = mbedtls_pk_write_pubkey_der(&key, mbedtls_buf, sizeof(mbedtls_buf))) < 0) { |
| 261 | + DEBUG_ERROR(" failed\n ! mbedtls_pk_write_pubkey_der returned -0x%04x", (unsigned int) -ret); |
| 262 | + goto exit; |
| 263 | + } |
| 264 | + |
| 265 | + if (ret > maxLen) { |
| 266 | + DEBUG_ERROR(" failed\n ! output buffer too small operation needs 0x%04x bytes", (unsigned int) ret); |
| 267 | + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; |
| 268 | + goto exit; |
| 269 | + } |
| 270 | + |
| 271 | + /* Copy data from the end of mbedtls_buf buffer to der output */ |
| 272 | + memcpy(derKey, &mbedtls_buf[sizeof(mbedtls_buf) - ret], ret); |
| 273 | + |
| 274 | +exit: |
| 275 | + mbedtls_pk_free(&key); |
| 276 | + return ret; |
| 277 | +} |
| 278 | + |
| 279 | +int Arduino_UNOWIFIR4_SSE::sha256(const unsigned char* message, int len, unsigned char* sha256) |
| 280 | +{ |
| 281 | + int ret = 1; |
| 282 | + |
| 283 | + if((ret = mbedtls_sha256_ret(message, len, sha256, 0)) != 0) { |
| 284 | + DEBUG_ERROR(" failed\n ! mbedtls_sha256_ret returned -0x%04x\n", (unsigned int) -ret); |
| 285 | + return ret; |
| 286 | + } |
| 287 | + return SSE_SHA256_LENGTH; |
| 288 | +} |
| 289 | + |
| 290 | +int Arduino_UNOWIFIR4_SSE::sign(const unsigned char* derKey, int derLen, const unsigned char* sha256, unsigned char* sigRS) |
| 291 | +{ |
| 292 | + int ret = 1; |
| 293 | + mbedtls_pk_context key; |
| 294 | + mbedtls_ctr_drbg_context ctr_drbg; |
| 295 | + mbedtls_entropy_context entropy; |
| 296 | + unsigned char mbedtls_buf[MBEDTLS_PK_SIGNATURE_MAX_SIZE] = { 0 }; |
| 297 | + unsigned char *p = (unsigned char *)&mbedtls_buf[0]; |
| 298 | + const char *pers = "gen_key"; |
| 299 | + size_t sig_size = 0; |
| 300 | + |
| 301 | + mbedtls_pk_init(&key); |
| 302 | + mbedtls_entropy_init(&entropy); |
| 303 | + mbedtls_ctr_drbg_init(&ctr_drbg); |
| 304 | + |
| 305 | + if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers))) != 0) { |
| 306 | + DEBUG_ERROR(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%04x\n", (unsigned int) -ret); |
| 307 | + goto exit; |
| 308 | + } |
| 309 | + |
| 310 | + /* verify if work using only private key*/ |
| 311 | + if ((ret = mbedtls_pk_parse_key(&key, derKey, derLen, NULL, 0)) != 0) { |
| 312 | + DEBUG_ERROR(" failed\n ! mbedtls_pk_parse_key returned -0x%04x", (unsigned int) -ret); |
| 313 | + goto exit; |
| 314 | + } |
| 315 | + |
| 316 | + if ((ret = mbedtls_pk_sign(&key, MBEDTLS_MD_SHA256, sha256, 0, mbedtls_buf, &sig_size, mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { |
| 317 | + DEBUG_ERROR(" failed\n ! mbedtls_pk_sign returned -0x%04x", (unsigned int) -ret); |
| 318 | + goto exit; |
| 319 | + } |
| 320 | + |
| 321 | +#if SSE_DEBUG_ENABLED |
| 322 | + log_v("SSE::sign: der signature"); |
| 323 | + log_buf_v(mbedtls_buf, sig_size); |
| 324 | +#endif |
| 325 | + |
| 326 | + /* Extract {r,s} values from DER signature */ |
| 327 | + extract_ecdsa_sig(&p, &mbedtls_buf[sig_size], sigRS, SSE_EC256_R_LENGTH); |
| 328 | + ret = SSE_EC256_SIGNATURE_LENGTH; |
| 329 | + |
| 330 | +exit: |
| 331 | + mbedtls_ctr_drbg_free(&ctr_drbg); |
| 332 | + mbedtls_pk_free(&key); |
| 333 | + return ret; |
| 334 | +} |
| 335 | + |
| 336 | +int Arduino_UNOWIFIR4_SSE::verify(const unsigned char* derKey, int derLen, const unsigned char* sha256, const unsigned char* sigRS) |
| 337 | +{ |
| 338 | + int ret = 1; |
| 339 | + mbedtls_pk_context key; |
| 340 | + unsigned char mbedtls_buf[MBEDTLS_PK_SIGNATURE_MAX_SIZE] = { 0 }; |
| 341 | + mbedtls_mpi r,s; |
| 342 | + size_t sig_size = 0; |
| 343 | + |
| 344 | + mbedtls_mpi_init(&r); |
| 345 | + mbedtls_mpi_init(&s); |
| 346 | + mbedtls_pk_init(&key); |
| 347 | + |
| 348 | + /* Verify is only public key is needed */ |
| 349 | + if ((ret = mbedtls_pk_parse_public_key(&key, derKey, derLen)) != 0) { |
| 350 | + DEBUG_ERROR(" failed\n ! mbedtls_pk_parse_public_key returned -0x%04x", (unsigned int) -ret); |
| 351 | + goto exit; |
| 352 | + } |
| 353 | + |
| 354 | +#if SSE_DEBUG_ENABLED |
| 355 | + log_v("SSE::verify: sha256"); |
| 356 | + log_buf_v((const uint8_t *)sha256, SSE_SHA256_LENGTH); |
| 357 | + log_v("SSE::verify: compressed signature"); |
| 358 | + log_buf_v((const uint8_t *)sigRS, SSE_EC256_SIGNATURE_LENGTH); |
| 359 | +#endif |
| 360 | + |
| 361 | + /* Convert signature {r,s} values to DER */ |
| 362 | + mbedtls_mpi_read_binary( &r, sigRS, SSE_EC256_R_LENGTH ); |
| 363 | + mbedtls_mpi_read_binary( &s, sigRS + SSE_EC256_R_LENGTH, SSE_EC256_S_LENGTH ); |
| 364 | + ecdsa_signature_to_asn1(&r, &s, mbedtls_buf, MBEDTLS_PK_SIGNATURE_MAX_SIZE, &sig_size); |
| 365 | + |
| 366 | +#if SSE_DEBUG_ENABLED |
| 367 | + log_v("SSE::verify: der signature"); |
| 368 | + log_buf_v((const uint8_t *)mbedtls_buf, sig_size); |
| 369 | +#endif |
| 370 | + |
| 371 | + if ((ret = mbedtls_pk_verify(&key, MBEDTLS_MD_SHA256, sha256, SSE_SHA256_LENGTH, mbedtls_buf, sig_size)) != 0) { |
| 372 | + DEBUG_ERROR(" failed\n ! mbedtls_pk_verify returned -0x%04x", (unsigned int) -ret); |
| 373 | + goto exit; |
| 374 | + } |
| 375 | + |
| 376 | +exit: |
| 377 | + mbedtls_pk_free(&key); |
| 378 | + return ret; |
| 379 | +} |
| 380 | + |
| 381 | +Preferences sse; |
0 commit comments