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 * 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 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 * 41 rs256_get_EVP_MD(void) 42 { 43 return (EVP_MD_fetch(NULL, "SHA2-256", NULL)); 44 } 45 46 static void 47 rs256_free_EVP_MD(EVP_MD *md) 48 { 49 EVP_MD_free(md); 50 } 51 #else 52 static EVP_MD * 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 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 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 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 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 * 118 rs256_pk_new(void) 119 { 120 return (calloc(1, sizeof(rs256_pk_t))); 121 } 122 123 void 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 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 * 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 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 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 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 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