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