Home | History | Annotate | Line # | Download | only in src
      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