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