1ba9bdd8bSchristos /*
2*2d40c451Schristos * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
3ba9bdd8bSchristos * Use of this source code is governed by a BSD-style
4ba9bdd8bSchristos * license that can be found in the LICENSE file.
5*2d40c451Schristos * SPDX-License-Identifier: BSD-2-Clause
6ba9bdd8bSchristos */
7ba9bdd8bSchristos
8ba9bdd8bSchristos #include <openssl/bn.h>
9ba9bdd8bSchristos #include <openssl/rsa.h>
10ba9bdd8bSchristos #include <openssl/obj_mac.h>
11ba9bdd8bSchristos
12ba9bdd8bSchristos #include "fido.h"
13ba9bdd8bSchristos #include "fido/rs256.h"
14ba9bdd8bSchristos
15*2d40c451Schristos #if OPENSSL_VERSION_NUMBER >= 0x30000000
16*2d40c451Schristos #define get0_RSA(x) EVP_PKEY_get0_RSA((x))
17*2d40c451Schristos #else
18*2d40c451Schristos #define get0_RSA(x) EVP_PKEY_get0((x))
19*2d40c451Schristos #endif
20ba9bdd8bSchristos
21*2d40c451Schristos #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL
22*2d40c451Schristos static EVP_MD *
rs256_get_EVP_MD(void)23*2d40c451Schristos rs256_get_EVP_MD(void)
24ba9bdd8bSchristos {
25*2d40c451Schristos const EVP_MD *from;
26*2d40c451Schristos EVP_MD *to = NULL;
27ba9bdd8bSchristos
28*2d40c451Schristos if ((from = EVP_sha256()) != NULL && (to = malloc(sizeof(*to))) != NULL)
29*2d40c451Schristos memcpy(to, from, sizeof(*to));
30*2d40c451Schristos
31*2d40c451Schristos return (to);
32ba9bdd8bSchristos }
33ba9bdd8bSchristos
34ba9bdd8bSchristos static void
rs256_free_EVP_MD(EVP_MD * md)35*2d40c451Schristos rs256_free_EVP_MD(EVP_MD *md)
36ba9bdd8bSchristos {
37*2d40c451Schristos freezero(md, sizeof(*md));
38ba9bdd8bSchristos }
39*2d40c451Schristos #elif OPENSSL_VERSION_NUMBER >= 0x30000000
40*2d40c451Schristos static EVP_MD *
rs256_get_EVP_MD(void)41*2d40c451Schristos rs256_get_EVP_MD(void)
42*2d40c451Schristos {
43*2d40c451Schristos return (EVP_MD_fetch(NULL, "SHA2-256", NULL));
44*2d40c451Schristos }
45*2d40c451Schristos
46*2d40c451Schristos static void
rs256_free_EVP_MD(EVP_MD * md)47*2d40c451Schristos rs256_free_EVP_MD(EVP_MD *md)
48*2d40c451Schristos {
49*2d40c451Schristos EVP_MD_free(md);
50*2d40c451Schristos }
51*2d40c451Schristos #else
52*2d40c451Schristos static EVP_MD *
rs256_get_EVP_MD(void)53*2d40c451Schristos rs256_get_EVP_MD(void)
54*2d40c451Schristos {
55*2d40c451Schristos const EVP_MD *md;
56*2d40c451Schristos
57*2d40c451Schristos if ((md = EVP_sha256()) == NULL)
58*2d40c451Schristos return (NULL);
59*2d40c451Schristos
60*2d40c451Schristos return (EVP_MD_meth_dup(md));
61*2d40c451Schristos }
62*2d40c451Schristos
63*2d40c451Schristos static void
rs256_free_EVP_MD(EVP_MD * md)64*2d40c451Schristos rs256_free_EVP_MD(EVP_MD *md)
65*2d40c451Schristos {
66*2d40c451Schristos EVP_MD_meth_free(md);
67*2d40c451Schristos }
68*2d40c451Schristos #endif /* LIBRESSL_VERSION_NUMBER */
69ba9bdd8bSchristos
70ba9bdd8bSchristos static int
decode_bignum(const cbor_item_t * item,void * ptr,size_t len)71ba9bdd8bSchristos decode_bignum(const cbor_item_t *item, void *ptr, size_t len)
72ba9bdd8bSchristos {
73ba9bdd8bSchristos if (cbor_isa_bytestring(item) == false ||
74ba9bdd8bSchristos cbor_bytestring_is_definite(item) == false ||
75ba9bdd8bSchristos cbor_bytestring_length(item) != len) {
76ba9bdd8bSchristos fido_log_debug("%s: cbor type", __func__);
77ba9bdd8bSchristos return (-1);
78ba9bdd8bSchristos }
79ba9bdd8bSchristos
80ba9bdd8bSchristos memcpy(ptr, cbor_bytestring_handle(item), len);
81ba9bdd8bSchristos
82ba9bdd8bSchristos return (0);
83ba9bdd8bSchristos }
84ba9bdd8bSchristos
85ba9bdd8bSchristos static int
decode_rsa_pubkey(const cbor_item_t * key,const cbor_item_t * val,void * arg)86ba9bdd8bSchristos decode_rsa_pubkey(const cbor_item_t *key, const cbor_item_t *val, void *arg)
87ba9bdd8bSchristos {
88ba9bdd8bSchristos rs256_pk_t *k = arg;
89ba9bdd8bSchristos
90ba9bdd8bSchristos if (cbor_isa_negint(key) == false ||
91ba9bdd8bSchristos cbor_int_get_width(key) != CBOR_INT_8)
92ba9bdd8bSchristos return (0); /* ignore */
93ba9bdd8bSchristos
94ba9bdd8bSchristos switch (cbor_get_uint8(key)) {
95ba9bdd8bSchristos case 0: /* modulus */
96ba9bdd8bSchristos return (decode_bignum(val, &k->n, sizeof(k->n)));
97ba9bdd8bSchristos case 1: /* public exponent */
98ba9bdd8bSchristos return (decode_bignum(val, &k->e, sizeof(k->e)));
99ba9bdd8bSchristos }
100ba9bdd8bSchristos
101ba9bdd8bSchristos return (0); /* ignore */
102ba9bdd8bSchristos }
103ba9bdd8bSchristos
104ba9bdd8bSchristos int
rs256_pk_decode(const cbor_item_t * item,rs256_pk_t * k)105ba9bdd8bSchristos rs256_pk_decode(const cbor_item_t *item, rs256_pk_t *k)
106ba9bdd8bSchristos {
107ba9bdd8bSchristos if (cbor_isa_map(item) == false ||
108ba9bdd8bSchristos cbor_map_is_definite(item) == false ||
109ba9bdd8bSchristos cbor_map_iter(item, k, decode_rsa_pubkey) < 0) {
110ba9bdd8bSchristos fido_log_debug("%s: cbor type", __func__);
111ba9bdd8bSchristos return (-1);
112ba9bdd8bSchristos }
113ba9bdd8bSchristos
114ba9bdd8bSchristos return (0);
115ba9bdd8bSchristos }
116ba9bdd8bSchristos
117ba9bdd8bSchristos rs256_pk_t *
rs256_pk_new(void)118ba9bdd8bSchristos rs256_pk_new(void)
119ba9bdd8bSchristos {
120ba9bdd8bSchristos return (calloc(1, sizeof(rs256_pk_t)));
121ba9bdd8bSchristos }
122ba9bdd8bSchristos
123ba9bdd8bSchristos void
rs256_pk_free(rs256_pk_t ** pkp)124ba9bdd8bSchristos rs256_pk_free(rs256_pk_t **pkp)
125ba9bdd8bSchristos {
126ba9bdd8bSchristos rs256_pk_t *pk;
127ba9bdd8bSchristos
128ba9bdd8bSchristos if (pkp == NULL || (pk = *pkp) == NULL)
129ba9bdd8bSchristos return;
130ba9bdd8bSchristos
13195dbdf32Schristos freezero(pk, sizeof(*pk));
132ba9bdd8bSchristos *pkp = NULL;
133ba9bdd8bSchristos }
134ba9bdd8bSchristos
135ba9bdd8bSchristos int
rs256_pk_from_ptr(rs256_pk_t * pk,const void * ptr,size_t len)136ba9bdd8bSchristos rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len)
137ba9bdd8bSchristos {
138*2d40c451Schristos EVP_PKEY *pkey;
139*2d40c451Schristos
140ba9bdd8bSchristos if (len < sizeof(*pk))
141ba9bdd8bSchristos return (FIDO_ERR_INVALID_ARGUMENT);
142ba9bdd8bSchristos
143ba9bdd8bSchristos memcpy(pk, ptr, sizeof(*pk));
144ba9bdd8bSchristos
145*2d40c451Schristos if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
146*2d40c451Schristos fido_log_debug("%s: rs256_pk_to_EVP_PKEY", __func__);
147*2d40c451Schristos return (FIDO_ERR_INVALID_ARGUMENT);
148*2d40c451Schristos }
149*2d40c451Schristos
150*2d40c451Schristos EVP_PKEY_free(pkey);
151*2d40c451Schristos
152ba9bdd8bSchristos return (FIDO_OK);
153ba9bdd8bSchristos }
154ba9bdd8bSchristos
155ba9bdd8bSchristos EVP_PKEY *
rs256_pk_to_EVP_PKEY(const rs256_pk_t * k)156ba9bdd8bSchristos rs256_pk_to_EVP_PKEY(const rs256_pk_t *k)
157ba9bdd8bSchristos {
158ba9bdd8bSchristos RSA *rsa = NULL;
159ba9bdd8bSchristos EVP_PKEY *pkey = NULL;
160ba9bdd8bSchristos BIGNUM *n = NULL;
161ba9bdd8bSchristos BIGNUM *e = NULL;
162ba9bdd8bSchristos int ok = -1;
163ba9bdd8bSchristos
164ba9bdd8bSchristos if ((n = BN_new()) == NULL || (e = BN_new()) == NULL)
165ba9bdd8bSchristos goto fail;
166ba9bdd8bSchristos
167ba9bdd8bSchristos if (BN_bin2bn(k->n, sizeof(k->n), n) == NULL ||
168ba9bdd8bSchristos BN_bin2bn(k->e, sizeof(k->e), e) == NULL) {
169ba9bdd8bSchristos fido_log_debug("%s: BN_bin2bn", __func__);
170ba9bdd8bSchristos goto fail;
171ba9bdd8bSchristos }
172ba9bdd8bSchristos
173ba9bdd8bSchristos if ((rsa = RSA_new()) == NULL || RSA_set0_key(rsa, n, e, NULL) == 0) {
174ba9bdd8bSchristos fido_log_debug("%s: RSA_set0_key", __func__);
175ba9bdd8bSchristos goto fail;
176ba9bdd8bSchristos }
177ba9bdd8bSchristos
178ba9bdd8bSchristos /* at this point, n and e belong to rsa */
179ba9bdd8bSchristos n = NULL;
180ba9bdd8bSchristos e = NULL;
181ba9bdd8bSchristos
182*2d40c451Schristos if (RSA_bits(rsa) != 2048) {
183*2d40c451Schristos fido_log_debug("%s: invalid key length", __func__);
184*2d40c451Schristos goto fail;
185*2d40c451Schristos }
186*2d40c451Schristos
187ba9bdd8bSchristos if ((pkey = EVP_PKEY_new()) == NULL ||
188ba9bdd8bSchristos EVP_PKEY_assign_RSA(pkey, rsa) == 0) {
189ba9bdd8bSchristos fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__);
190ba9bdd8bSchristos goto fail;
191ba9bdd8bSchristos }
192ba9bdd8bSchristos
193ba9bdd8bSchristos rsa = NULL; /* at this point, rsa belongs to evp */
194ba9bdd8bSchristos
195ba9bdd8bSchristos ok = 0;
196ba9bdd8bSchristos fail:
197ba9bdd8bSchristos if (n != NULL)
198ba9bdd8bSchristos BN_free(n);
199ba9bdd8bSchristos if (e != NULL)
200ba9bdd8bSchristos BN_free(e);
201ba9bdd8bSchristos if (rsa != NULL)
202ba9bdd8bSchristos RSA_free(rsa);
203ba9bdd8bSchristos if (ok < 0 && pkey != NULL) {
204ba9bdd8bSchristos EVP_PKEY_free(pkey);
205ba9bdd8bSchristos pkey = NULL;
206ba9bdd8bSchristos }
207ba9bdd8bSchristos
208ba9bdd8bSchristos return (pkey);
209ba9bdd8bSchristos }
210ba9bdd8bSchristos
211ba9bdd8bSchristos int
rs256_pk_from_RSA(rs256_pk_t * pk,const RSA * rsa)212ba9bdd8bSchristos rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa)
213ba9bdd8bSchristos {
214ba9bdd8bSchristos const BIGNUM *n = NULL;
215ba9bdd8bSchristos const BIGNUM *e = NULL;
216ba9bdd8bSchristos const BIGNUM *d = NULL;
217ba9bdd8bSchristos int k;
218ba9bdd8bSchristos
219ba9bdd8bSchristos if (RSA_bits(rsa) != 2048) {
220ba9bdd8bSchristos fido_log_debug("%s: invalid key length", __func__);
221ba9bdd8bSchristos return (FIDO_ERR_INVALID_ARGUMENT);
222ba9bdd8bSchristos }
223ba9bdd8bSchristos
224ba9bdd8bSchristos RSA_get0_key(rsa, &n, &e, &d);
225ba9bdd8bSchristos
226ba9bdd8bSchristos if (n == NULL || e == NULL) {
227ba9bdd8bSchristos fido_log_debug("%s: RSA_get0_key", __func__);
228ba9bdd8bSchristos return (FIDO_ERR_INTERNAL);
229ba9bdd8bSchristos }
230ba9bdd8bSchristos
231ba9bdd8bSchristos if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) ||
232ba9bdd8bSchristos (k = BN_num_bytes(e)) < 0 || (size_t)k > sizeof(pk->e)) {
233ba9bdd8bSchristos fido_log_debug("%s: invalid key", __func__);
234ba9bdd8bSchristos return (FIDO_ERR_INTERNAL);
235ba9bdd8bSchristos }
236ba9bdd8bSchristos
237ba9bdd8bSchristos if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) ||
238ba9bdd8bSchristos (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) {
239ba9bdd8bSchristos fido_log_debug("%s: BN_bn2bin", __func__);
240ba9bdd8bSchristos return (FIDO_ERR_INTERNAL);
241ba9bdd8bSchristos }
242ba9bdd8bSchristos
243ba9bdd8bSchristos return (FIDO_OK);
244ba9bdd8bSchristos }
245*2d40c451Schristos
246*2d40c451Schristos int
rs256_pk_from_EVP_PKEY(rs256_pk_t * pk,const EVP_PKEY * pkey)247*2d40c451Schristos rs256_pk_from_EVP_PKEY(rs256_pk_t *pk, const EVP_PKEY *pkey)
248*2d40c451Schristos {
249*2d40c451Schristos const RSA *rsa;
250*2d40c451Schristos
251*2d40c451Schristos if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA ||
252*2d40c451Schristos (rsa = get0_RSA(pkey)) == NULL)
253*2d40c451Schristos return (FIDO_ERR_INVALID_ARGUMENT);
254*2d40c451Schristos
255*2d40c451Schristos return (rs256_pk_from_RSA(pk, rsa));
256*2d40c451Schristos }
257*2d40c451Schristos
258*2d40c451Schristos int
rs256_verify_sig(const fido_blob_t * dgst,EVP_PKEY * pkey,const fido_blob_t * sig)259*2d40c451Schristos rs256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
260*2d40c451Schristos const fido_blob_t *sig)
261*2d40c451Schristos {
262*2d40c451Schristos EVP_PKEY_CTX *pctx = NULL;
263*2d40c451Schristos EVP_MD *md = NULL;
264*2d40c451Schristos int ok = -1;
265*2d40c451Schristos
266*2d40c451Schristos if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
267*2d40c451Schristos fido_log_debug("%s: EVP_PKEY_base_id", __func__);
268*2d40c451Schristos goto fail;
269*2d40c451Schristos }
270*2d40c451Schristos
271*2d40c451Schristos if ((md = rs256_get_EVP_MD()) == NULL) {
272*2d40c451Schristos fido_log_debug("%s: rs256_get_EVP_MD", __func__);
273*2d40c451Schristos goto fail;
274*2d40c451Schristos }
275*2d40c451Schristos
276*2d40c451Schristos if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
277*2d40c451Schristos EVP_PKEY_verify_init(pctx) != 1 ||
278*2d40c451Schristos EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 ||
279*2d40c451Schristos EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
280*2d40c451Schristos fido_log_debug("%s: EVP_PKEY_CTX", __func__);
281*2d40c451Schristos goto fail;
282*2d40c451Schristos }
283*2d40c451Schristos
284*2d40c451Schristos if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
285*2d40c451Schristos dgst->len) != 1) {
286*2d40c451Schristos fido_log_debug("%s: EVP_PKEY_verify", __func__);
287*2d40c451Schristos goto fail;
288*2d40c451Schristos }
289*2d40c451Schristos
290*2d40c451Schristos ok = 0;
291*2d40c451Schristos fail:
292*2d40c451Schristos EVP_PKEY_CTX_free(pctx);
293*2d40c451Schristos rs256_free_EVP_MD(md);
294*2d40c451Schristos
295*2d40c451Schristos return (ok);
296*2d40c451Schristos }
297*2d40c451Schristos
298*2d40c451Schristos int
rs256_pk_verify_sig(const fido_blob_t * dgst,const rs256_pk_t * pk,const fido_blob_t * sig)299*2d40c451Schristos rs256_pk_verify_sig(const fido_blob_t *dgst, const rs256_pk_t *pk,
300*2d40c451Schristos const fido_blob_t *sig)
301*2d40c451Schristos {
302*2d40c451Schristos EVP_PKEY *pkey;
303*2d40c451Schristos int ok = -1;
304*2d40c451Schristos
305*2d40c451Schristos if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
306*2d40c451Schristos rs256_verify_sig(dgst, pkey, sig) < 0) {
307*2d40c451Schristos fido_log_debug("%s: rs256_verify_sig", __func__);
308*2d40c451Schristos goto fail;
309*2d40c451Schristos }
310*2d40c451Schristos
311*2d40c451Schristos ok = 0;
312*2d40c451Schristos fail:
313*2d40c451Schristos EVP_PKEY_free(pkey);
314*2d40c451Schristos
315*2d40c451Schristos return (ok);
316*2d40c451Schristos }
317