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