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
decode_coord(const cbor_item_t * item,void * xy,size_t xy_len)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
decode_pubkey_point(const cbor_item_t * key,const cbor_item_t * val,void * arg)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
es256_pk_decode(const cbor_item_t * item,es256_pk_t * k)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 *
es256_pk_encode(const es256_pk_t * pk,int ecdh)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 *
es256_sk_new(void)134 es256_sk_new(void)
135 {
136 return (calloc(1, sizeof(es256_sk_t)));
137 }
138
139 void
es256_sk_free(es256_sk_t ** skp)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 *
es256_pk_new(void)152 es256_pk_new(void)
153 {
154 return (calloc(1, sizeof(es256_pk_t)));
155 }
156
157 void
es256_pk_free(es256_pk_t ** pkp)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
es256_pk_from_ptr(es256_pk_t * pk,const void * ptr,size_t len)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
es256_pk_set_x(es256_pk_t * pk,const unsigned char * x)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
es256_pk_set_y(es256_pk_t * pk,const unsigned char * y)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
es256_sk_create(es256_sk_t * key)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 *
es256_pk_to_EVP_PKEY(const es256_pk_t * k)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
es256_pk_from_EC_KEY(es256_pk_t * pk,const EC_KEY * ec)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 *
es256_sk_to_EVP_PKEY(const es256_sk_t * k)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
es256_derive_pk(const es256_sk_t * sk,es256_pk_t * pk)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