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