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