1 /* 2 * Copyright (c) 2019-2021 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/obj_mac.h> 10 11 #include "fido.h" 12 #include "fido/eddsa.h" 13 14 #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3070000f 15 EVP_PKEY * 16 EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *key, 17 size_t keylen) 18 { 19 (void)type; 20 (void)e; 21 (void)key; 22 (void)keylen; 23 24 fido_log_debug("%s: unimplemented", __func__); 25 26 return (NULL); 27 } 28 29 int 30 EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub, 31 size_t *len) 32 { 33 (void)pkey; 34 (void)pub; 35 (void)len; 36 37 fido_log_debug("%s: unimplemented", __func__); 38 39 return (0); 40 } 41 #endif /* LIBRESSL_VERSION_NUMBER */ 42 43 #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3040000f 44 int 45 EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, 46 const unsigned char *tbs, size_t tbslen) 47 { 48 (void)ctx; 49 (void)sigret; 50 (void)siglen; 51 (void)tbs; 52 (void)tbslen; 53 54 fido_log_debug("%s: unimplemented", __func__); 55 56 return (0); 57 } 58 #endif /* LIBRESSL_VERSION_NUMBER < 0x3040000f */ 59 60 static int 61 decode_coord(const cbor_item_t *item, void *xy, size_t xy_len) 62 { 63 if (cbor_isa_bytestring(item) == false || 64 cbor_bytestring_is_definite(item) == false || 65 cbor_bytestring_length(item) != xy_len) { 66 fido_log_debug("%s: cbor type", __func__); 67 return (-1); 68 } 69 70 memcpy(xy, cbor_bytestring_handle(item), xy_len); 71 72 return (0); 73 } 74 75 static int 76 decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg) 77 { 78 eddsa_pk_t *k = arg; 79 80 if (cbor_isa_negint(key) == false || 81 cbor_int_get_width(key) != CBOR_INT_8) 82 return (0); /* ignore */ 83 84 switch (cbor_get_uint8(key)) { 85 case 1: /* x coordinate */ 86 return (decode_coord(val, &k->x, sizeof(k->x))); 87 } 88 89 return (0); /* ignore */ 90 } 91 92 int 93 eddsa_pk_decode(const cbor_item_t *item, eddsa_pk_t *k) 94 { 95 if (cbor_isa_map(item) == false || 96 cbor_map_is_definite(item) == false || 97 cbor_map_iter(item, k, decode_pubkey_point) < 0) { 98 fido_log_debug("%s: cbor type", __func__); 99 return (-1); 100 } 101 102 return (0); 103 } 104 105 eddsa_pk_t * 106 eddsa_pk_new(void) 107 { 108 return (calloc(1, sizeof(eddsa_pk_t))); 109 } 110 111 void 112 eddsa_pk_free(eddsa_pk_t **pkp) 113 { 114 eddsa_pk_t *pk; 115 116 if (pkp == NULL || (pk = *pkp) == NULL) 117 return; 118 119 freezero(pk, sizeof(*pk)); 120 *pkp = NULL; 121 } 122 123 int 124 eddsa_pk_from_ptr(eddsa_pk_t *pk, const void *ptr, size_t len) 125 { 126 EVP_PKEY *pkey; 127 128 if (len < sizeof(*pk)) 129 return (FIDO_ERR_INVALID_ARGUMENT); 130 131 memcpy(pk, ptr, sizeof(*pk)); 132 133 if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { 134 fido_log_debug("%s: eddsa_pk_to_EVP_PKEY", __func__); 135 return (FIDO_ERR_INVALID_ARGUMENT); 136 } 137 138 EVP_PKEY_free(pkey); 139 140 return (FIDO_OK); 141 } 142 143 EVP_PKEY * 144 eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *k) 145 { 146 EVP_PKEY *pkey = NULL; 147 148 if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, k->x, 149 sizeof(k->x))) == NULL) 150 fido_log_debug("%s: EVP_PKEY_new_raw_public_key", __func__); 151 152 return (pkey); 153 } 154 155 int 156 eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey) 157 { 158 size_t len = 0; 159 160 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519) 161 return (FIDO_ERR_INVALID_ARGUMENT); 162 if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 || 163 len != sizeof(pk->x)) 164 return (FIDO_ERR_INTERNAL); 165 if (EVP_PKEY_get_raw_public_key(pkey, pk->x, &len) != 1 || 166 len != sizeof(pk->x)) 167 return (FIDO_ERR_INTERNAL); 168 169 return (FIDO_OK); 170 } 171 172 int 173 eddsa_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey, 174 const fido_blob_t *sig) 175 { 176 EVP_MD_CTX *mdctx = NULL; 177 int ok = -1; 178 179 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519) { 180 fido_log_debug("%s: EVP_PKEY_base_id", __func__); 181 goto fail; 182 } 183 184 /* EVP_DigestVerify needs ints */ 185 if (dgst->len > INT_MAX || sig->len > INT_MAX) { 186 fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, 187 dgst->len, sig->len); 188 return (-1); 189 } 190 191 if ((mdctx = EVP_MD_CTX_new()) == NULL) { 192 fido_log_debug("%s: EVP_MD_CTX_new", __func__); 193 goto fail; 194 } 195 196 if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) { 197 fido_log_debug("%s: EVP_DigestVerifyInit", __func__); 198 goto fail; 199 } 200 201 if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr, 202 dgst->len) != 1) { 203 fido_log_debug("%s: EVP_DigestVerify", __func__); 204 goto fail; 205 } 206 207 ok = 0; 208 fail: 209 EVP_MD_CTX_free(mdctx); 210 211 return (ok); 212 } 213 214 int 215 eddsa_pk_verify_sig(const fido_blob_t *dgst, const eddsa_pk_t *pk, 216 const fido_blob_t *sig) 217 { 218 EVP_PKEY *pkey; 219 int ok = -1; 220 221 if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL || 222 eddsa_verify_sig(dgst, pkey, sig) < 0) { 223 fido_log_debug("%s: eddsa_verify_sig", __func__); 224 goto fail; 225 } 226 227 ok = 0; 228 fail: 229 EVP_PKEY_free(pkey); 230 231 return (ok); 232 } 233