]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libfido2/src/es256.c
file: upgrade to 5.41.
[FreeBSD/FreeBSD.git] / contrib / libfido2 / src / es256.c
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 }