xref: /freebsd/contrib/libfido2/src/rs256.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
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