jcs's openbsd hax
openbsd
at jcs 231 lines 4.8 kB view raw
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 14EVP_PKEY * 15EVP_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 28int 29EVP_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 43int 44EVP_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 59static int 60decode_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 74static int 75decode_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 91int 92eddsa_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 104eddsa_pk_t * 105eddsa_pk_new(void) 106{ 107 return (calloc(1, sizeof(eddsa_pk_t))); 108} 109 110void 111eddsa_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 122int 123eddsa_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 142EVP_PKEY * 143eddsa_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 154int 155eddsa_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 171int 172eddsa_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; 207fail: 208 EVP_MD_CTX_free(mdctx); 209 210 return (ok); 211} 212 213int 214eddsa_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; 227fail: 228 EVP_PKEY_free(pkey); 229 230 return (ok); 231}