Home | History | Annotate | Line # | Download | only in src
      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(__GNUC__)
     22 #define PRAGMA(s) _Pragma(s)
     23 #else
     24 #define PRAGMA(s)
     25 #endif
     26 
     27 static EVP_MD *
     28 rs256_get_EVP_MD(void)
     29 {
     30 PRAGMA("GCC diagnostic push")
     31 PRAGMA("GCC diagnostic ignored \"-Wcast-qual\"")
     32 	return ((EVP_MD *)EVP_sha256());
     33 PRAGMA("GCC diagnostic pop")
     34 }
     35 
     36 static int
     37 decode_bignum(const cbor_item_t *item, void *ptr, size_t len)
     38 {
     39 	if (cbor_isa_bytestring(item) == false ||
     40 	    cbor_bytestring_is_definite(item) == false ||
     41 	    cbor_bytestring_length(item) != len) {
     42 		fido_log_debug("%s: cbor type", __func__);
     43 		return (-1);
     44 	}
     45 
     46 	memcpy(ptr, cbor_bytestring_handle(item), len);
     47 
     48 	return (0);
     49 }
     50 
     51 static int
     52 decode_rsa_pubkey(const cbor_item_t *key, const cbor_item_t *val, void *arg)
     53 {
     54 	rs256_pk_t *k = arg;
     55 
     56 	if (cbor_isa_negint(key) == false ||
     57 	    cbor_int_get_width(key) != CBOR_INT_8)
     58 		return (0); /* ignore */
     59 
     60 	switch (cbor_get_uint8(key)) {
     61 	case 0: /* modulus */
     62 		return (decode_bignum(val, &k->n, sizeof(k->n)));
     63 	case 1: /* public exponent */
     64 		return (decode_bignum(val, &k->e, sizeof(k->e)));
     65 	}
     66 
     67 	return (0); /* ignore */
     68 }
     69 
     70 int
     71 rs256_pk_decode(const cbor_item_t *item, rs256_pk_t *k)
     72 {
     73 	if (cbor_isa_map(item) == false ||
     74 	    cbor_map_is_definite(item) == false ||
     75 	    cbor_map_iter(item, k, decode_rsa_pubkey) < 0) {
     76 		fido_log_debug("%s: cbor type", __func__);
     77 		return (-1);
     78 	}
     79 
     80 	return (0);
     81 }
     82 
     83 rs256_pk_t *
     84 rs256_pk_new(void)
     85 {
     86 	return (calloc(1, sizeof(rs256_pk_t)));
     87 }
     88 
     89 void
     90 rs256_pk_free(rs256_pk_t **pkp)
     91 {
     92 	rs256_pk_t *pk;
     93 
     94 	if (pkp == NULL || (pk = *pkp) == NULL)
     95 		return;
     96 
     97 	freezero(pk, sizeof(*pk));
     98 	*pkp = NULL;
     99 }
    100 
    101 int
    102 rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len)
    103 {
    104 	EVP_PKEY *pkey;
    105 
    106 	if (len < sizeof(*pk))
    107 		return (FIDO_ERR_INVALID_ARGUMENT);
    108 
    109 	memcpy(pk, ptr, sizeof(*pk));
    110 
    111 	if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
    112 		fido_log_debug("%s: rs256_pk_to_EVP_PKEY", __func__);
    113 		return (FIDO_ERR_INVALID_ARGUMENT);
    114 	}
    115 
    116 	EVP_PKEY_free(pkey);
    117 
    118 	return (FIDO_OK);
    119 }
    120 
    121 EVP_PKEY *
    122 rs256_pk_to_EVP_PKEY(const rs256_pk_t *k)
    123 {
    124 	RSA		*rsa = NULL;
    125 	EVP_PKEY	*pkey = NULL;
    126 	BIGNUM		*n = NULL;
    127 	BIGNUM		*e = NULL;
    128 	int		 ok = -1;
    129 
    130 	if ((n = BN_new()) == NULL || (e = BN_new()) == NULL)
    131 		goto fail;
    132 
    133 	if (BN_bin2bn(k->n, sizeof(k->n), n) == NULL ||
    134 	    BN_bin2bn(k->e, sizeof(k->e), e) == NULL) {
    135 		fido_log_debug("%s: BN_bin2bn", __func__);
    136 		goto fail;
    137 	}
    138 
    139 	if ((rsa = RSA_new()) == NULL || RSA_set0_key(rsa, n, e, NULL) == 0) {
    140 		fido_log_debug("%s: RSA_set0_key", __func__);
    141 		goto fail;
    142 	}
    143 
    144 	/* at this point, n and e belong to rsa */
    145 	n = NULL;
    146 	e = NULL;
    147 
    148 	if (RSA_bits(rsa) != 2048) {
    149 		fido_log_debug("%s: invalid key length", __func__);
    150 		goto fail;
    151 	}
    152 
    153 	if ((pkey = EVP_PKEY_new()) == NULL ||
    154 	    EVP_PKEY_assign_RSA(pkey, rsa) == 0) {
    155 		fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__);
    156 		goto fail;
    157 	}
    158 
    159 	rsa = NULL; /* at this point, rsa belongs to evp */
    160 
    161 	ok = 0;
    162 fail:
    163 	if (n != NULL)
    164 		BN_free(n);
    165 	if (e != NULL)
    166 		BN_free(e);
    167 	if (rsa != NULL)
    168 		RSA_free(rsa);
    169 	if (ok < 0 && pkey != NULL) {
    170 		EVP_PKEY_free(pkey);
    171 		pkey = NULL;
    172 	}
    173 
    174 	return (pkey);
    175 }
    176 
    177 int
    178 rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa)
    179 {
    180 	const BIGNUM	*n = NULL;
    181 	const BIGNUM	*e = NULL;
    182 	const BIGNUM	*d = NULL;
    183 	int		 k;
    184 
    185 	if (RSA_bits(rsa) != 2048) {
    186 		fido_log_debug("%s: invalid key length", __func__);
    187 		return (FIDO_ERR_INVALID_ARGUMENT);
    188 	}
    189 
    190 	RSA_get0_key(rsa, &n, &e, &d);
    191 
    192 	if (n == NULL || e == NULL) {
    193 		fido_log_debug("%s: RSA_get0_key", __func__);
    194 		return (FIDO_ERR_INTERNAL);
    195 	}
    196 
    197 	if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) ||
    198 	    (k = BN_num_bytes(e)) < 0 || (size_t)k > sizeof(pk->e)) {
    199 		fido_log_debug("%s: invalid key", __func__);
    200 		return (FIDO_ERR_INTERNAL);
    201 	}
    202 
    203 	if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) ||
    204 	    (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) {
    205 		fido_log_debug("%s: BN_bn2bin", __func__);
    206 		return (FIDO_ERR_INTERNAL);
    207 	}
    208 
    209 	return (FIDO_OK);
    210 }
    211 
    212 int
    213 rs256_pk_from_EVP_PKEY(rs256_pk_t *pk, const EVP_PKEY *pkey)
    214 {
    215 	const RSA *rsa;
    216 
    217 	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA ||
    218 	    (rsa = get0_RSA(pkey)) == NULL)
    219 		return (FIDO_ERR_INVALID_ARGUMENT);
    220 
    221 	return (rs256_pk_from_RSA(pk, rsa));
    222 }
    223 
    224 int
    225 rs256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
    226     const fido_blob_t *sig)
    227 {
    228 	EVP_PKEY_CTX	*pctx = NULL;
    229 	EVP_MD		*md = NULL;
    230 	int		 ok = -1;
    231 
    232 	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
    233 		fido_log_debug("%s: EVP_PKEY_base_id", __func__);
    234 		goto fail;
    235 	}
    236 
    237 	if ((md = rs256_get_EVP_MD()) == NULL) {
    238 		fido_log_debug("%s: rs256_get_EVP_MD", __func__);
    239 		goto fail;
    240 	}
    241 
    242 	if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
    243 	    EVP_PKEY_verify_init(pctx) != 1 ||
    244 	    EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 ||
    245 	    EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
    246 		fido_log_debug("%s: EVP_PKEY_CTX", __func__);
    247 		goto fail;
    248 	}
    249 
    250 	if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
    251 	    dgst->len) != 1) {
    252 		fido_log_debug("%s: EVP_PKEY_verify", __func__);
    253 		goto fail;
    254 	}
    255 
    256 	ok = 0;
    257 fail:
    258 	EVP_PKEY_CTX_free(pctx);
    259 
    260 	return (ok);
    261 }
    262 
    263 int
    264 rs256_pk_verify_sig(const fido_blob_t *dgst, const rs256_pk_t *pk,
    265     const fido_blob_t *sig)
    266 {
    267 	EVP_PKEY	*pkey;
    268 	int		 ok = -1;
    269 
    270 	if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
    271 	    rs256_verify_sig(dgst, pkey, sig) < 0) {
    272 		fido_log_debug("%s: rs256_verify_sig", __func__);
    273 		goto fail;
    274 	}
    275 
    276 	ok = 0;
    277 fail:
    278 	EVP_PKEY_free(pkey);
    279 
    280 	return (ok);
    281 }
    282