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