1 /* 2 * Copyright (c) 2018-2022 Yubico AB. All rights reserved. 3 * Use of this source code is governed by a BSD-style 4 * license that can be found in the LICENSE file. 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8 #include <openssl/bn.h> 9 #include <openssl/ecdsa.h> 10 #include <openssl/obj_mac.h> 11 12 #include "fido.h" 13 #include "fido/es256.h" 14 15 #if OPENSSL_VERSION_NUMBER >= 0x30000000 16 #define get0_EC_KEY(x) EVP_PKEY_get0_EC_KEY((x)) 17 #else 18 #define get0_EC_KEY(x) EVP_PKEY_get0((x)) 19 #endif 20 21 static const int es256_nid = NID_X9_62_prime256v1; 22 23 static int 24 decode_coord(const cbor_item_t *item, void *xy, size_t xy_len) 25 { 26 if (cbor_isa_bytestring(item) == false || 27 cbor_bytestring_is_definite(item) == false || 28 cbor_bytestring_length(item) != xy_len) { 29 fido_log_debug("%s: cbor type", __func__); 30 return (-1); 31 } 32 33 memcpy(xy, cbor_bytestring_handle(item), xy_len); 34 35 return (0); 36 } 37 38 static int 39 decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg) 40 { 41 es256_pk_t *k = arg; 42 43 if (cbor_isa_negint(key) == false || 44 cbor_int_get_width(key) != CBOR_INT_8) 45 return (0); /* ignore */ 46 47 switch (cbor_get_uint8(key)) { 48 case 1: /* x coordinate */ 49 return (decode_coord(val, &k->x, sizeof(k->x))); 50 case 2: /* y coordinate */ 51 return (decode_coord(val, &k->y, sizeof(k->y))); 52 } 53 54 return (0); /* ignore */ 55 } 56 57 int 58 es256_pk_decode(const cbor_item_t *item, es256_pk_t *k) 59 { 60 if (cbor_isa_map(item) == false || 61 cbor_map_is_definite(item) == false || 62 cbor_map_iter(item, k, decode_pubkey_point) < 0) { 63 fido_log_debug("%s: cbor type", __func__); 64 return (-1); 65 } 66 67 return (0); 68 } 69 70 cbor_item_t * 71 es256_pk_encode(const es256_pk_t *pk, int ecdh) 72 { 73 cbor_item_t *item = NULL; 74 struct cbor_pair argv[5]; 75 int alg; 76 int ok = -1; 77 78 memset(argv, 0, sizeof(argv)); 79 80 if ((item = cbor_new_definite_map(5)) == NULL) 81 goto fail; 82 83 /* kty */ 84 if ((argv[0].key = cbor_build_uint8(1)) == NULL || 85 (argv[0].value = cbor_build_uint8(2)) == NULL || 86 !cbor_map_add(item, argv[0])) 87 goto fail; 88 89 /* 90 * "The COSEAlgorithmIdentifier used is -25 (ECDH-ES + 91 * HKDF-256) although this is NOT the algorithm actually 92 * used. Setting this to a different value may result in 93 * compatibility issues." 94 */ 95 if (ecdh) 96 alg = COSE_ECDH_ES256; 97 else 98 alg = COSE_ES256; 99 100 /* alg */ 101 if ((argv[1].key = cbor_build_uint8(3)) == NULL || 102 (argv[1].value = cbor_build_negint8((uint8_t)(-alg - 1))) == NULL || 103 !cbor_map_add(item, argv[1])) 104 goto fail; 105 106 /* crv */ 107 if ((argv[2].key = cbor_build_negint8(0)) == NULL || 108 (argv[2].value = cbor_build_uint8(1)) == NULL || 109 !cbor_map_add(item, argv[2])) 110 goto fail; 111 112 /* x */ 113 if ((argv[3].key = cbor_build_negint8(1)) == NULL || 114 (argv[3].value = cbor_build_bytestring(pk->x, 115 sizeof(pk->x))) == NULL || !cbor_map_add(item, argv[3])) 116 goto fail; 117 118 /* y */ 119 if ((argv[4].key = cbor_build_negint8(2)) == NULL || 120 (argv[4].value = cbor_build_bytestring(pk->y, 121 sizeof(pk->y))) == NULL || !cbor_map_add(item, argv[4])) 122 goto fail; 123 124 ok = 0; 125 fail: 126 if (ok < 0) { 127 if (item != NULL) { 128 cbor_decref(&item); 129 item = NULL; 130 } 131 } 132 133 for (size_t i = 0; i < 5; i++) { 134 if (argv[i].key) 135 cbor_decref(&argv[i].key); 136 if (argv[i].value) 137 cbor_decref(&argv[i].value); 138 } 139 140 return (item); 141 } 142 143 es256_sk_t * 144 es256_sk_new(void) 145 { 146 return (calloc(1, sizeof(es256_sk_t))); 147 } 148 149 void 150 es256_sk_free(es256_sk_t **skp) 151 { 152 es256_sk_t *sk; 153 154 if (skp == NULL || (sk = *skp) == NULL) 155 return; 156 157 freezero(sk, sizeof(*sk)); 158 *skp = NULL; 159 } 160 161 es256_pk_t * 162 es256_pk_new(void) 163 { 164 return (calloc(1, sizeof(es256_pk_t))); 165 } 166 167 void 168 es256_pk_free(es256_pk_t **pkp) 169 { 170 es256_pk_t *pk; 171 172 if (pkp == NULL || (pk = *pkp) == NULL) 173 return; 174 175 freezero(pk, sizeof(*pk)); 176 *pkp = NULL; 177 } 178 179 int 180 es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len) 181 { 182 const uint8_t *p = ptr; 183 EVP_PKEY *pkey; 184 185 if (len < sizeof(*pk)) 186 return (FIDO_ERR_INVALID_ARGUMENT); 187 188 if (len == sizeof(*pk) + 1 && *p == 0x04) 189 memcpy(pk, ++p, sizeof(*pk)); /* uncompressed format */ 190 else 191 memcpy(pk, ptr, sizeof(*pk)); /* libfido2 x||y format */ 192 193 if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { 194 fido_log_debug("%s: es256_pk_to_EVP_PKEY", __func__); 195 explicit_bzero(pk, sizeof(*pk)); 196 return (FIDO_ERR_INVALID_ARGUMENT); 197 } 198 199 EVP_PKEY_free(pkey); 200 201 return (FIDO_OK); 202 } 203 204 int 205 es256_pk_set_x(es256_pk_t *pk, const unsigned char *x) 206 { 207 memcpy(pk->x, x, sizeof(pk->x)); 208 209 return (0); 210 } 211 212 int 213 es256_pk_set_y(es256_pk_t *pk, const unsigned char *y) 214 { 215 memcpy(pk->y, y, sizeof(pk->y)); 216 217 return (0); 218 } 219 220 int 221 es256_sk_create(es256_sk_t *key) 222 { 223 EVP_PKEY_CTX *pctx = NULL; 224 EVP_PKEY_CTX *kctx = NULL; 225 EVP_PKEY *p = NULL; 226 EVP_PKEY *k = NULL; 227 const EC_KEY *ec; 228 const BIGNUM *d; 229 int n; 230 int ok = -1; 231 232 if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL || 233 EVP_PKEY_paramgen_init(pctx) <= 0 || 234 EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, es256_nid) <= 0 || 235 EVP_PKEY_paramgen(pctx, &p) <= 0) { 236 fido_log_debug("%s: EVP_PKEY_paramgen", __func__); 237 goto fail; 238 } 239 240 if ((kctx = EVP_PKEY_CTX_new(p, NULL)) == NULL || 241 EVP_PKEY_keygen_init(kctx) <= 0 || EVP_PKEY_keygen(kctx, &k) <= 0) { 242 fido_log_debug("%s: EVP_PKEY_keygen", __func__); 243 goto fail; 244 } 245 246 if ((ec = EVP_PKEY_get0_EC_KEY(k)) == NULL || 247 (d = EC_KEY_get0_private_key(ec)) == NULL || 248 (n = BN_num_bytes(d)) < 0 || (size_t)n > sizeof(key->d) || 249 (n = BN_bn2bin(d, key->d)) < 0 || (size_t)n > sizeof(key->d)) { 250 fido_log_debug("%s: EC_KEY_get0_private_key", __func__); 251 goto fail; 252 } 253 254 ok = 0; 255 fail: 256 if (p != NULL) 257 EVP_PKEY_free(p); 258 if (k != NULL) 259 EVP_PKEY_free(k); 260 if (pctx != NULL) 261 EVP_PKEY_CTX_free(pctx); 262 if (kctx != NULL) 263 EVP_PKEY_CTX_free(kctx); 264 265 return (ok); 266 } 267 268 EVP_PKEY * 269 es256_pk_to_EVP_PKEY(const es256_pk_t *k) 270 { 271 BN_CTX *bnctx = NULL; 272 EC_KEY *ec = NULL; 273 EC_POINT *q = NULL; 274 EVP_PKEY *pkey = NULL; 275 BIGNUM *x = NULL; 276 BIGNUM *y = NULL; 277 const EC_GROUP *g = NULL; 278 int ok = -1; 279 280 if ((bnctx = BN_CTX_new()) == NULL) 281 goto fail; 282 283 BN_CTX_start(bnctx); 284 285 if ((x = BN_CTX_get(bnctx)) == NULL || 286 (y = BN_CTX_get(bnctx)) == NULL) 287 goto fail; 288 289 if (BN_bin2bn(k->x, sizeof(k->x), x) == NULL || 290 BN_bin2bn(k->y, sizeof(k->y), y) == NULL) { 291 fido_log_debug("%s: BN_bin2bn", __func__); 292 goto fail; 293 } 294 295 if ((ec = EC_KEY_new_by_curve_name(es256_nid)) == NULL || 296 (g = EC_KEY_get0_group(ec)) == NULL) { 297 fido_log_debug("%s: EC_KEY init", __func__); 298 goto fail; 299 } 300 301 if ((q = EC_POINT_new(g)) == NULL || 302 EC_POINT_set_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 || 303 EC_KEY_set_public_key(ec, q) == 0) { 304 fido_log_debug("%s: EC_KEY_set_public_key", __func__); 305 goto fail; 306 } 307 308 if ((pkey = EVP_PKEY_new()) == NULL || 309 EVP_PKEY_assign_EC_KEY(pkey, ec) == 0) { 310 fido_log_debug("%s: EVP_PKEY_assign_EC_KEY", __func__); 311 goto fail; 312 } 313 314 ec = NULL; /* at this point, ec belongs to evp */ 315 316 ok = 0; 317 fail: 318 if (bnctx != NULL) { 319 BN_CTX_end(bnctx); 320 BN_CTX_free(bnctx); 321 } 322 323 if (ec != NULL) 324 EC_KEY_free(ec); 325 if (q != NULL) 326 EC_POINT_free(q); 327 328 if (ok < 0 && pkey != NULL) { 329 EVP_PKEY_free(pkey); 330 pkey = NULL; 331 } 332 333 return (pkey); 334 } 335 336 int 337 es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) 338 { 339 BN_CTX *bnctx = NULL; 340 BIGNUM *x = NULL; 341 BIGNUM *y = NULL; 342 const EC_POINT *q = NULL; 343 EC_GROUP *g = NULL; 344 size_t dx; 345 size_t dy; 346 int ok = FIDO_ERR_INTERNAL; 347 int nx; 348 int ny; 349 350 if ((q = EC_KEY_get0_public_key(ec)) == NULL || 351 (g = EC_GROUP_new_by_curve_name(es256_nid)) == NULL || 352 (bnctx = BN_CTX_new()) == NULL) 353 goto fail; 354 355 BN_CTX_start(bnctx); 356 357 if ((x = BN_CTX_get(bnctx)) == NULL || 358 (y = BN_CTX_get(bnctx)) == NULL) 359 goto fail; 360 361 if (EC_POINT_is_on_curve(g, q, bnctx) != 1) { 362 fido_log_debug("%s: EC_POINT_is_on_curve", __func__); 363 ok = FIDO_ERR_INVALID_ARGUMENT; 364 goto fail; 365 } 366 367 if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 || 368 (nx = BN_num_bytes(x)) < 0 || (size_t)nx > sizeof(pk->x) || 369 (ny = BN_num_bytes(y)) < 0 || (size_t)ny > sizeof(pk->y)) { 370 fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp", 371 __func__); 372 goto fail; 373 } 374 375 dx = sizeof(pk->x) - (size_t)nx; 376 dy = sizeof(pk->y) - (size_t)ny; 377 378 if ((nx = BN_bn2bin(x, pk->x + dx)) < 0 || (size_t)nx > sizeof(pk->x) || 379 (ny = BN_bn2bin(y, pk->y + dy)) < 0 || (size_t)ny > sizeof(pk->y)) { 380 fido_log_debug("%s: BN_bn2bin", __func__); 381 goto fail; 382 } 383 384 ok = FIDO_OK; 385 fail: 386 EC_GROUP_free(g); 387 388 if (bnctx != NULL) { 389 BN_CTX_end(bnctx); 390 BN_CTX_free(bnctx); 391 } 392 393 return (ok); 394 } 395 396 int 397 es256_pk_from_EVP_PKEY(es256_pk_t *pk, const EVP_PKEY *pkey) 398 { 399 const EC_KEY *ec; 400 401 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC || 402 (ec = get0_EC_KEY(pkey)) == NULL) 403 return (FIDO_ERR_INVALID_ARGUMENT); 404 405 return (es256_pk_from_EC_KEY(pk, ec)); 406 } 407 408 EVP_PKEY * 409 es256_sk_to_EVP_PKEY(const es256_sk_t *k) 410 { 411 BN_CTX *bnctx = NULL; 412 EC_KEY *ec = NULL; 413 EVP_PKEY *pkey = NULL; 414 BIGNUM *d = NULL; 415 int ok = -1; 416 417 if ((bnctx = BN_CTX_new()) == NULL) 418 goto fail; 419 420 BN_CTX_start(bnctx); 421 422 if ((d = BN_CTX_get(bnctx)) == NULL || 423 BN_bin2bn(k->d, sizeof(k->d), d) == NULL) { 424 fido_log_debug("%s: BN_bin2bn", __func__); 425 goto fail; 426 } 427 428 if ((ec = EC_KEY_new_by_curve_name(es256_nid)) == NULL || 429 EC_KEY_set_private_key(ec, d) == 0) { 430 fido_log_debug("%s: EC_KEY_set_private_key", __func__); 431 goto fail; 432 } 433 434 if ((pkey = EVP_PKEY_new()) == NULL || 435 EVP_PKEY_assign_EC_KEY(pkey, ec) == 0) { 436 fido_log_debug("%s: EVP_PKEY_assign_EC_KEY", __func__); 437 goto fail; 438 } 439 440 ec = NULL; /* at this point, ec belongs to evp */ 441 442 ok = 0; 443 fail: 444 if (bnctx != NULL) { 445 BN_CTX_end(bnctx); 446 BN_CTX_free(bnctx); 447 } 448 449 if (ec != NULL) 450 EC_KEY_free(ec); 451 452 if (ok < 0 && pkey != NULL) { 453 EVP_PKEY_free(pkey); 454 pkey = NULL; 455 } 456 457 return (pkey); 458 } 459 460 int 461 es256_derive_pk(const es256_sk_t *sk, es256_pk_t *pk) 462 { 463 BIGNUM *d = NULL; 464 EC_KEY *ec = NULL; 465 EC_POINT *q = NULL; 466 const EC_GROUP *g = NULL; 467 int ok = -1; 468 469 if ((d = BN_bin2bn(sk->d, (int)sizeof(sk->d), NULL)) == NULL || 470 (ec = EC_KEY_new_by_curve_name(es256_nid)) == NULL || 471 (g = EC_KEY_get0_group(ec)) == NULL || 472 (q = EC_POINT_new(g)) == NULL) { 473 fido_log_debug("%s: get", __func__); 474 goto fail; 475 } 476 477 if (EC_POINT_mul(g, q, d, NULL, NULL, NULL) == 0 || 478 EC_KEY_set_public_key(ec, q) == 0 || 479 es256_pk_from_EC_KEY(pk, ec) != FIDO_OK) { 480 fido_log_debug("%s: set", __func__); 481 goto fail; 482 } 483 484 ok = 0; 485 fail: 486 if (d != NULL) 487 BN_clear_free(d); 488 if (q != NULL) 489 EC_POINT_free(q); 490 if (ec != NULL) 491 EC_KEY_free(ec); 492 493 return (ok); 494 } 495 496 int 497 es256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey, 498 const fido_blob_t *sig) 499 { 500 EVP_PKEY_CTX *pctx = NULL; 501 int ok = -1; 502 503 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { 504 fido_log_debug("%s: EVP_PKEY_base_id", __func__); 505 goto fail; 506 } 507 508 if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL || 509 EVP_PKEY_verify_init(pctx) != 1 || 510 EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr, 511 dgst->len) != 1) { 512 fido_log_debug("%s: EVP_PKEY_verify", __func__); 513 goto fail; 514 } 515 516 ok = 0; 517 fail: 518 EVP_PKEY_CTX_free(pctx); 519 520 return (ok); 521 } 522 523 int 524 es256_pk_verify_sig(const fido_blob_t *dgst, const es256_pk_t *pk, 525 const fido_blob_t *sig) 526 { 527 EVP_PKEY *pkey; 528 int ok = -1; 529 530 if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL || 531 es256_verify_sig(dgst, pkey, sig) < 0) { 532 fido_log_debug("%s: es256_verify_sig", __func__); 533 goto fail; 534 } 535 536 ok = 0; 537 fail: 538 EVP_PKEY_free(pkey); 539 540 return (ok); 541 } 542