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