xref: /freebsd/contrib/libfido2/src/rs256.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
10afa8e06SEd Maste /*
2*2ccfa855SEd Maste  * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
30afa8e06SEd Maste  * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste  * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste  */
70afa8e06SEd Maste 
80afa8e06SEd Maste #include <openssl/bn.h>
90afa8e06SEd Maste #include <openssl/rsa.h>
100afa8e06SEd Maste #include <openssl/obj_mac.h>
110afa8e06SEd Maste 
120afa8e06SEd Maste #include "fido.h"
130afa8e06SEd Maste #include "fido/rs256.h"
140afa8e06SEd Maste 
15*2ccfa855SEd Maste #if OPENSSL_VERSION_NUMBER >= 0x30000000
16*2ccfa855SEd Maste #define get0_RSA(x)	EVP_PKEY_get0_RSA((x))
17*2ccfa855SEd Maste #else
18*2ccfa855SEd Maste #define get0_RSA(x)	EVP_PKEY_get0((x))
19*2ccfa855SEd Maste #endif
20*2ccfa855SEd Maste 
21*2ccfa855SEd Maste #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL
22f540a430SEd Maste static EVP_MD *
rs256_get_EVP_MD(void)23f540a430SEd Maste rs256_get_EVP_MD(void)
240afa8e06SEd Maste {
25f540a430SEd Maste 	const EVP_MD *from;
26f540a430SEd Maste 	EVP_MD *to = NULL;
270afa8e06SEd Maste 
28f540a430SEd Maste 	if ((from = EVP_sha256()) != NULL && (to = malloc(sizeof(*to))) != NULL)
29f540a430SEd Maste 		memcpy(to, from, sizeof(*to));
300afa8e06SEd Maste 
31f540a430SEd Maste 	return (to);
320afa8e06SEd Maste }
330afa8e06SEd Maste 
340afa8e06SEd Maste static void
rs256_free_EVP_MD(EVP_MD * md)35f540a430SEd Maste rs256_free_EVP_MD(EVP_MD *md)
360afa8e06SEd Maste {
37f540a430SEd Maste 	freezero(md, sizeof(*md));
380afa8e06SEd Maste }
39f540a430SEd Maste #elif OPENSSL_VERSION_NUMBER >= 0x30000000
40f540a430SEd Maste static EVP_MD *
rs256_get_EVP_MD(void)41f540a430SEd Maste rs256_get_EVP_MD(void)
42f540a430SEd Maste {
43f540a430SEd Maste 	return (EVP_MD_fetch(NULL, "SHA2-256", NULL));
44f540a430SEd Maste }
45f540a430SEd Maste 
46f540a430SEd Maste static void
rs256_free_EVP_MD(EVP_MD * md)47f540a430SEd Maste rs256_free_EVP_MD(EVP_MD *md)
48f540a430SEd Maste {
49f540a430SEd Maste 	EVP_MD_free(md);
50f540a430SEd Maste }
51f540a430SEd Maste #else
52f540a430SEd Maste static EVP_MD *
rs256_get_EVP_MD(void)53f540a430SEd Maste rs256_get_EVP_MD(void)
54f540a430SEd Maste {
55f540a430SEd Maste 	const EVP_MD *md;
56f540a430SEd Maste 
57f540a430SEd Maste 	if ((md = EVP_sha256()) == NULL)
58f540a430SEd Maste 		return (NULL);
59f540a430SEd Maste 
60f540a430SEd Maste 	return (EVP_MD_meth_dup(md));
61f540a430SEd Maste }
62f540a430SEd Maste 
63f540a430SEd Maste static void
rs256_free_EVP_MD(EVP_MD * md)64f540a430SEd Maste rs256_free_EVP_MD(EVP_MD *md)
65f540a430SEd Maste {
66f540a430SEd Maste 	EVP_MD_meth_free(md);
67f540a430SEd Maste }
68f540a430SEd Maste #endif /* LIBRESSL_VERSION_NUMBER */
690afa8e06SEd Maste 
700afa8e06SEd Maste static int
decode_bignum(const cbor_item_t * item,void * ptr,size_t len)710afa8e06SEd Maste decode_bignum(const cbor_item_t *item, void *ptr, size_t len)
720afa8e06SEd Maste {
730afa8e06SEd Maste 	if (cbor_isa_bytestring(item) == false ||
740afa8e06SEd Maste 	    cbor_bytestring_is_definite(item) == false ||
750afa8e06SEd Maste 	    cbor_bytestring_length(item) != len) {
760afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
770afa8e06SEd Maste 		return (-1);
780afa8e06SEd Maste 	}
790afa8e06SEd Maste 
800afa8e06SEd Maste 	memcpy(ptr, cbor_bytestring_handle(item), len);
810afa8e06SEd Maste 
820afa8e06SEd Maste 	return (0);
830afa8e06SEd Maste }
840afa8e06SEd Maste 
850afa8e06SEd Maste static int
decode_rsa_pubkey(const cbor_item_t * key,const cbor_item_t * val,void * arg)860afa8e06SEd Maste decode_rsa_pubkey(const cbor_item_t *key, const cbor_item_t *val, void *arg)
870afa8e06SEd Maste {
880afa8e06SEd Maste 	rs256_pk_t *k = arg;
890afa8e06SEd Maste 
900afa8e06SEd Maste 	if (cbor_isa_negint(key) == false ||
910afa8e06SEd Maste 	    cbor_int_get_width(key) != CBOR_INT_8)
920afa8e06SEd Maste 		return (0); /* ignore */
930afa8e06SEd Maste 
940afa8e06SEd Maste 	switch (cbor_get_uint8(key)) {
950afa8e06SEd Maste 	case 0: /* modulus */
960afa8e06SEd Maste 		return (decode_bignum(val, &k->n, sizeof(k->n)));
970afa8e06SEd Maste 	case 1: /* public exponent */
980afa8e06SEd Maste 		return (decode_bignum(val, &k->e, sizeof(k->e)));
990afa8e06SEd Maste 	}
1000afa8e06SEd Maste 
1010afa8e06SEd Maste 	return (0); /* ignore */
1020afa8e06SEd Maste }
1030afa8e06SEd Maste 
1040afa8e06SEd Maste int
rs256_pk_decode(const cbor_item_t * item,rs256_pk_t * k)1050afa8e06SEd Maste rs256_pk_decode(const cbor_item_t *item, rs256_pk_t *k)
1060afa8e06SEd Maste {
1070afa8e06SEd Maste 	if (cbor_isa_map(item) == false ||
1080afa8e06SEd Maste 	    cbor_map_is_definite(item) == false ||
1090afa8e06SEd Maste 	    cbor_map_iter(item, k, decode_rsa_pubkey) < 0) {
1100afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
1110afa8e06SEd Maste 		return (-1);
1120afa8e06SEd Maste 	}
1130afa8e06SEd Maste 
1140afa8e06SEd Maste 	return (0);
1150afa8e06SEd Maste }
1160afa8e06SEd Maste 
1170afa8e06SEd Maste rs256_pk_t *
rs256_pk_new(void)1180afa8e06SEd Maste rs256_pk_new(void)
1190afa8e06SEd Maste {
1200afa8e06SEd Maste 	return (calloc(1, sizeof(rs256_pk_t)));
1210afa8e06SEd Maste }
1220afa8e06SEd Maste 
1230afa8e06SEd Maste void
rs256_pk_free(rs256_pk_t ** pkp)1240afa8e06SEd Maste rs256_pk_free(rs256_pk_t **pkp)
1250afa8e06SEd Maste {
1260afa8e06SEd Maste 	rs256_pk_t *pk;
1270afa8e06SEd Maste 
1280afa8e06SEd Maste 	if (pkp == NULL || (pk = *pkp) == NULL)
1290afa8e06SEd Maste 		return;
1300afa8e06SEd Maste 
1310afa8e06SEd Maste 	freezero(pk, sizeof(*pk));
1320afa8e06SEd Maste 	*pkp = NULL;
1330afa8e06SEd Maste }
1340afa8e06SEd Maste 
1350afa8e06SEd Maste int
rs256_pk_from_ptr(rs256_pk_t * pk,const void * ptr,size_t len)1360afa8e06SEd Maste rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len)
1370afa8e06SEd Maste {
138*2ccfa855SEd Maste 	EVP_PKEY *pkey;
139*2ccfa855SEd Maste 
1400afa8e06SEd Maste 	if (len < sizeof(*pk))
1410afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
1420afa8e06SEd Maste 
1430afa8e06SEd Maste 	memcpy(pk, ptr, sizeof(*pk));
1440afa8e06SEd Maste 
145*2ccfa855SEd Maste 	if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
146*2ccfa855SEd Maste 		fido_log_debug("%s: rs256_pk_to_EVP_PKEY", __func__);
147*2ccfa855SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
148*2ccfa855SEd Maste 	}
149*2ccfa855SEd Maste 
150*2ccfa855SEd Maste 	EVP_PKEY_free(pkey);
151*2ccfa855SEd Maste 
1520afa8e06SEd Maste 	return (FIDO_OK);
1530afa8e06SEd Maste }
1540afa8e06SEd Maste 
1550afa8e06SEd Maste EVP_PKEY *
rs256_pk_to_EVP_PKEY(const rs256_pk_t * k)1560afa8e06SEd Maste rs256_pk_to_EVP_PKEY(const rs256_pk_t *k)
1570afa8e06SEd Maste {
1580afa8e06SEd Maste 	RSA		*rsa = NULL;
1590afa8e06SEd Maste 	EVP_PKEY	*pkey = NULL;
1600afa8e06SEd Maste 	BIGNUM		*n = NULL;
1610afa8e06SEd Maste 	BIGNUM		*e = NULL;
1620afa8e06SEd Maste 	int		 ok = -1;
1630afa8e06SEd Maste 
1640afa8e06SEd Maste 	if ((n = BN_new()) == NULL || (e = BN_new()) == NULL)
1650afa8e06SEd Maste 		goto fail;
1660afa8e06SEd Maste 
1670afa8e06SEd Maste 	if (BN_bin2bn(k->n, sizeof(k->n), n) == NULL ||
1680afa8e06SEd Maste 	    BN_bin2bn(k->e, sizeof(k->e), e) == NULL) {
1690afa8e06SEd Maste 		fido_log_debug("%s: BN_bin2bn", __func__);
1700afa8e06SEd Maste 		goto fail;
1710afa8e06SEd Maste 	}
1720afa8e06SEd Maste 
1730afa8e06SEd Maste 	if ((rsa = RSA_new()) == NULL || RSA_set0_key(rsa, n, e, NULL) == 0) {
1740afa8e06SEd Maste 		fido_log_debug("%s: RSA_set0_key", __func__);
1750afa8e06SEd Maste 		goto fail;
1760afa8e06SEd Maste 	}
1770afa8e06SEd Maste 
1780afa8e06SEd Maste 	/* at this point, n and e belong to rsa */
1790afa8e06SEd Maste 	n = NULL;
1800afa8e06SEd Maste 	e = NULL;
1810afa8e06SEd Maste 
182*2ccfa855SEd Maste 	if (RSA_bits(rsa) != 2048) {
183*2ccfa855SEd Maste 		fido_log_debug("%s: invalid key length", __func__);
184*2ccfa855SEd Maste 		goto fail;
185*2ccfa855SEd Maste 	}
186*2ccfa855SEd Maste 
1870afa8e06SEd Maste 	if ((pkey = EVP_PKEY_new()) == NULL ||
1880afa8e06SEd Maste 	    EVP_PKEY_assign_RSA(pkey, rsa) == 0) {
1890afa8e06SEd Maste 		fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__);
1900afa8e06SEd Maste 		goto fail;
1910afa8e06SEd Maste 	}
1920afa8e06SEd Maste 
1930afa8e06SEd Maste 	rsa = NULL; /* at this point, rsa belongs to evp */
1940afa8e06SEd Maste 
1950afa8e06SEd Maste 	ok = 0;
1960afa8e06SEd Maste fail:
1970afa8e06SEd Maste 	if (n != NULL)
1980afa8e06SEd Maste 		BN_free(n);
1990afa8e06SEd Maste 	if (e != NULL)
2000afa8e06SEd Maste 		BN_free(e);
2010afa8e06SEd Maste 	if (rsa != NULL)
2020afa8e06SEd Maste 		RSA_free(rsa);
2030afa8e06SEd Maste 	if (ok < 0 && pkey != NULL) {
2040afa8e06SEd Maste 		EVP_PKEY_free(pkey);
2050afa8e06SEd Maste 		pkey = NULL;
2060afa8e06SEd Maste 	}
2070afa8e06SEd Maste 
2080afa8e06SEd Maste 	return (pkey);
2090afa8e06SEd Maste }
2100afa8e06SEd Maste 
2110afa8e06SEd Maste int
rs256_pk_from_RSA(rs256_pk_t * pk,const RSA * rsa)2120afa8e06SEd Maste rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa)
2130afa8e06SEd Maste {
2140afa8e06SEd Maste 	const BIGNUM	*n = NULL;
2150afa8e06SEd Maste 	const BIGNUM	*e = NULL;
2160afa8e06SEd Maste 	const BIGNUM	*d = NULL;
2170afa8e06SEd Maste 	int		 k;
2180afa8e06SEd Maste 
2190afa8e06SEd Maste 	if (RSA_bits(rsa) != 2048) {
2200afa8e06SEd Maste 		fido_log_debug("%s: invalid key length", __func__);
2210afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
2220afa8e06SEd Maste 	}
2230afa8e06SEd Maste 
2240afa8e06SEd Maste 	RSA_get0_key(rsa, &n, &e, &d);
2250afa8e06SEd Maste 
2260afa8e06SEd Maste 	if (n == NULL || e == NULL) {
2270afa8e06SEd Maste 		fido_log_debug("%s: RSA_get0_key", __func__);
2280afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
2290afa8e06SEd Maste 	}
2300afa8e06SEd Maste 
2310afa8e06SEd Maste 	if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) ||
2320afa8e06SEd Maste 	    (k = BN_num_bytes(e)) < 0 || (size_t)k > sizeof(pk->e)) {
2330afa8e06SEd Maste 		fido_log_debug("%s: invalid key", __func__);
2340afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
2350afa8e06SEd Maste 	}
2360afa8e06SEd Maste 
2370afa8e06SEd Maste 	if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) ||
2380afa8e06SEd Maste 	    (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) {
2390afa8e06SEd Maste 		fido_log_debug("%s: BN_bn2bin", __func__);
2400afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
2410afa8e06SEd Maste 	}
2420afa8e06SEd Maste 
2430afa8e06SEd Maste 	return (FIDO_OK);
2440afa8e06SEd Maste }
245f540a430SEd Maste 
246f540a430SEd Maste int
rs256_pk_from_EVP_PKEY(rs256_pk_t * pk,const EVP_PKEY * pkey)247f540a430SEd Maste rs256_pk_from_EVP_PKEY(rs256_pk_t *pk, const EVP_PKEY *pkey)
248f540a430SEd Maste {
249*2ccfa855SEd Maste 	const RSA *rsa;
250f540a430SEd Maste 
251f540a430SEd Maste 	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA ||
252*2ccfa855SEd Maste 	    (rsa = get0_RSA(pkey)) == NULL)
253f540a430SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
254f540a430SEd Maste 
255f540a430SEd Maste 	return (rs256_pk_from_RSA(pk, rsa));
256f540a430SEd Maste }
257f540a430SEd Maste 
258f540a430SEd Maste int
rs256_verify_sig(const fido_blob_t * dgst,EVP_PKEY * pkey,const fido_blob_t * sig)259f540a430SEd Maste rs256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
260f540a430SEd Maste     const fido_blob_t *sig)
261f540a430SEd Maste {
262f540a430SEd Maste 	EVP_PKEY_CTX	*pctx = NULL;
263f540a430SEd Maste 	EVP_MD		*md = NULL;
264f540a430SEd Maste 	int		 ok = -1;
265f540a430SEd Maste 
266f540a430SEd Maste 	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
267f540a430SEd Maste 		fido_log_debug("%s: EVP_PKEY_base_id", __func__);
268f540a430SEd Maste 		goto fail;
269f540a430SEd Maste 	}
270f540a430SEd Maste 
271f540a430SEd Maste 	if ((md = rs256_get_EVP_MD()) == NULL) {
272f540a430SEd Maste 		fido_log_debug("%s: rs256_get_EVP_MD", __func__);
273f540a430SEd Maste 		goto fail;
274f540a430SEd Maste 	}
275f540a430SEd Maste 
276f540a430SEd Maste 	if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
277f540a430SEd Maste 	    EVP_PKEY_verify_init(pctx) != 1 ||
278f540a430SEd Maste 	    EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 ||
279f540a430SEd Maste 	    EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
280f540a430SEd Maste 		fido_log_debug("%s: EVP_PKEY_CTX", __func__);
281f540a430SEd Maste 		goto fail;
282f540a430SEd Maste 	}
283f540a430SEd Maste 
284f540a430SEd Maste 	if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
285f540a430SEd Maste 	    dgst->len) != 1) {
286f540a430SEd Maste 		fido_log_debug("%s: EVP_PKEY_verify", __func__);
287f540a430SEd Maste 		goto fail;
288f540a430SEd Maste 	}
289f540a430SEd Maste 
290f540a430SEd Maste 	ok = 0;
291f540a430SEd Maste fail:
292f540a430SEd Maste 	EVP_PKEY_CTX_free(pctx);
293f540a430SEd Maste 	rs256_free_EVP_MD(md);
294f540a430SEd Maste 
295f540a430SEd Maste 	return (ok);
296f540a430SEd Maste }
297f540a430SEd Maste 
298f540a430SEd Maste int
rs256_pk_verify_sig(const fido_blob_t * dgst,const rs256_pk_t * pk,const fido_blob_t * sig)299f540a430SEd Maste rs256_pk_verify_sig(const fido_blob_t *dgst, const rs256_pk_t *pk,
300f540a430SEd Maste     const fido_blob_t *sig)
301f540a430SEd Maste {
302f540a430SEd Maste 	EVP_PKEY	*pkey;
303f540a430SEd Maste 	int		 ok = -1;
304f540a430SEd Maste 
305f540a430SEd Maste 	if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
306f540a430SEd Maste 	    rs256_verify_sig(dgst, pkey, sig) < 0) {
307f540a430SEd Maste 		fido_log_debug("%s: rs256_verify_sig", __func__);
308f540a430SEd Maste 		goto fail;
309f540a430SEd Maste 	}
310f540a430SEd Maste 
311f540a430SEd Maste 	ok = 0;
312f540a430SEd Maste fail:
313f540a430SEd Maste 	EVP_PKEY_free(pkey);
314f540a430SEd Maste 
315f540a430SEd Maste 	return (ok);
316f540a430SEd Maste }
317