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