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) 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 if (len < sizeof(*pk)) 126 return (FIDO_ERR_INVALID_ARGUMENT); 127 128 memcpy(pk, ptr, sizeof(*pk)); 129 130 return (FIDO_OK); 131 } 132 133 EVP_PKEY * 134 eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *k) 135 { 136 EVP_PKEY *pkey = NULL; 137 138 if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, k->x, 139 sizeof(k->x))) == NULL) 140 fido_log_debug("%s: EVP_PKEY_new_raw_public_key", __func__); 141 142 return (pkey); 143 } 144 145 int 146 eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey) 147 { 148 size_t len = 0; 149 150 if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 || 151 len != sizeof(pk->x)) 152 return (FIDO_ERR_INTERNAL); 153 if (EVP_PKEY_get_raw_public_key(pkey, pk->x, &len) != 1 || 154 len != sizeof(pk->x)) 155 return (FIDO_ERR_INTERNAL); 156 157 return (FIDO_OK); 158 } 159 160 int 161 eddsa_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey, 162 const fido_blob_t *sig) 163 { 164 EVP_MD_CTX *mdctx = NULL; 165 int ok = -1; 166 167 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519) { 168 fido_log_debug("%s: EVP_PKEY_base_id", __func__); 169 goto fail; 170 } 171 172 /* EVP_DigestVerify needs ints */ 173 if (dgst->len > INT_MAX || sig->len > INT_MAX) { 174 fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, 175 dgst->len, sig->len); 176 return (-1); 177 } 178 179 if ((mdctx = EVP_MD_CTX_new()) == NULL) { 180 fido_log_debug("%s: EVP_MD_CTX_new", __func__); 181 goto fail; 182 } 183 184 if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) { 185 fido_log_debug("%s: EVP_DigestVerifyInit", __func__); 186 goto fail; 187 } 188 189 if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr, 190 dgst->len) != 1) { 191 fido_log_debug("%s: EVP_DigestVerify", __func__); 192 goto fail; 193 } 194 195 ok = 0; 196 fail: 197 EVP_MD_CTX_free(mdctx); 198 199 return (ok); 200 } 201 202 int 203 eddsa_pk_verify_sig(const fido_blob_t *dgst, const eddsa_pk_t *pk, 204 const fido_blob_t *sig) 205 { 206 EVP_PKEY *pkey; 207 int ok = -1; 208 209 if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL || 210 eddsa_verify_sig(dgst, pkey, sig) < 0) { 211 fido_log_debug("%s: eddsa_verify_sig", __func__); 212 goto fail; 213 } 214 215 ok = 0; 216 fail: 217 EVP_PKEY_free(pkey); 218 219 return (ok); 220 } 221