xref: /freebsd/contrib/libfido2/src/eddsa.c (revision 2ccfa855)
10afa8e06SEd Maste /*
23e696dfbSEd Maste  * Copyright (c) 2019-2021 Yubico AB. All rights reserved.
30afa8e06SEd Maste  * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste  * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste  */
70afa8e06SEd Maste 
80afa8e06SEd Maste #include <openssl/bn.h>
90afa8e06SEd Maste #include <openssl/obj_mac.h>
100afa8e06SEd Maste 
110afa8e06SEd Maste #include "fido.h"
120afa8e06SEd Maste #include "fido/eddsa.h"
130afa8e06SEd Maste 
14*2ccfa855SEd Maste #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3070000f
150afa8e06SEd Maste EVP_PKEY *
EVP_PKEY_new_raw_public_key(int type,ENGINE * e,const unsigned char * key,size_t keylen)160afa8e06SEd Maste EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *key,
170afa8e06SEd Maste     size_t keylen)
180afa8e06SEd Maste {
190afa8e06SEd Maste 	(void)type;
200afa8e06SEd Maste 	(void)e;
210afa8e06SEd Maste 	(void)key;
220afa8e06SEd Maste 	(void)keylen;
230afa8e06SEd Maste 
240afa8e06SEd Maste 	fido_log_debug("%s: unimplemented", __func__);
250afa8e06SEd Maste 
260afa8e06SEd Maste 	return (NULL);
270afa8e06SEd Maste }
280afa8e06SEd Maste 
290afa8e06SEd Maste int
EVP_PKEY_get_raw_public_key(const EVP_PKEY * pkey,unsigned char * pub,size_t * len)300afa8e06SEd Maste EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub,
310afa8e06SEd Maste     size_t *len)
320afa8e06SEd Maste {
330afa8e06SEd Maste 	(void)pkey;
340afa8e06SEd Maste 	(void)pub;
350afa8e06SEd Maste 	(void)len;
360afa8e06SEd Maste 
370afa8e06SEd Maste 	fido_log_debug("%s: unimplemented", __func__);
380afa8e06SEd Maste 
390afa8e06SEd Maste 	return (0);
400afa8e06SEd Maste }
413e696dfbSEd Maste #endif /* LIBRESSL_VERSION_NUMBER */
420afa8e06SEd Maste 
433e696dfbSEd Maste #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3040000f
440afa8e06SEd Maste int
EVP_DigestVerify(EVP_MD_CTX * ctx,const unsigned char * sigret,size_t siglen,const unsigned char * tbs,size_t tbslen)450afa8e06SEd Maste EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen,
460afa8e06SEd Maste     const unsigned char *tbs, size_t tbslen)
470afa8e06SEd Maste {
480afa8e06SEd Maste 	(void)ctx;
490afa8e06SEd Maste 	(void)sigret;
500afa8e06SEd Maste 	(void)siglen;
510afa8e06SEd Maste 	(void)tbs;
520afa8e06SEd Maste 	(void)tbslen;
530afa8e06SEd Maste 
540afa8e06SEd Maste 	fido_log_debug("%s: unimplemented", __func__);
550afa8e06SEd Maste 
560afa8e06SEd Maste 	return (0);
570afa8e06SEd Maste }
583e696dfbSEd Maste #endif /* LIBRESSL_VERSION_NUMBER < 0x3040000f */
590afa8e06SEd Maste 
600afa8e06SEd Maste static int
decode_coord(const cbor_item_t * item,void * xy,size_t xy_len)610afa8e06SEd Maste decode_coord(const cbor_item_t *item, void *xy, size_t xy_len)
620afa8e06SEd Maste {
630afa8e06SEd Maste 	if (cbor_isa_bytestring(item) == false ||
640afa8e06SEd Maste 	    cbor_bytestring_is_definite(item) == false ||
650afa8e06SEd Maste 	    cbor_bytestring_length(item) != xy_len) {
660afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
670afa8e06SEd Maste 		return (-1);
680afa8e06SEd Maste 	}
690afa8e06SEd Maste 
700afa8e06SEd Maste 	memcpy(xy, cbor_bytestring_handle(item), xy_len);
710afa8e06SEd Maste 
720afa8e06SEd Maste 	return (0);
730afa8e06SEd Maste }
740afa8e06SEd Maste 
750afa8e06SEd Maste static int
decode_pubkey_point(const cbor_item_t * key,const cbor_item_t * val,void * arg)760afa8e06SEd Maste decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg)
770afa8e06SEd Maste {
780afa8e06SEd Maste 	eddsa_pk_t *k = arg;
790afa8e06SEd Maste 
800afa8e06SEd Maste 	if (cbor_isa_negint(key) == false ||
810afa8e06SEd Maste 	    cbor_int_get_width(key) != CBOR_INT_8)
820afa8e06SEd Maste 		return (0); /* ignore */
830afa8e06SEd Maste 
840afa8e06SEd Maste 	switch (cbor_get_uint8(key)) {
850afa8e06SEd Maste 	case 1: /* x coordinate */
860afa8e06SEd Maste 		return (decode_coord(val, &k->x, sizeof(k->x)));
870afa8e06SEd Maste 	}
880afa8e06SEd Maste 
890afa8e06SEd Maste 	return (0); /* ignore */
900afa8e06SEd Maste }
910afa8e06SEd Maste 
920afa8e06SEd Maste int
eddsa_pk_decode(const cbor_item_t * item,eddsa_pk_t * k)930afa8e06SEd Maste eddsa_pk_decode(const cbor_item_t *item, eddsa_pk_t *k)
940afa8e06SEd Maste {
950afa8e06SEd Maste 	if (cbor_isa_map(item) == false ||
960afa8e06SEd Maste 	    cbor_map_is_definite(item) == false ||
970afa8e06SEd Maste 	    cbor_map_iter(item, k, decode_pubkey_point) < 0) {
980afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
990afa8e06SEd Maste 		return (-1);
1000afa8e06SEd Maste 	}
1010afa8e06SEd Maste 
1020afa8e06SEd Maste 	return (0);
1030afa8e06SEd Maste }
1040afa8e06SEd Maste 
1050afa8e06SEd Maste eddsa_pk_t *
eddsa_pk_new(void)1060afa8e06SEd Maste eddsa_pk_new(void)
1070afa8e06SEd Maste {
1080afa8e06SEd Maste 	return (calloc(1, sizeof(eddsa_pk_t)));
1090afa8e06SEd Maste }
1100afa8e06SEd Maste 
1110afa8e06SEd Maste void
eddsa_pk_free(eddsa_pk_t ** pkp)1120afa8e06SEd Maste eddsa_pk_free(eddsa_pk_t **pkp)
1130afa8e06SEd Maste {
1140afa8e06SEd Maste 	eddsa_pk_t *pk;
1150afa8e06SEd Maste 
1160afa8e06SEd Maste 	if (pkp == NULL || (pk = *pkp) == NULL)
1170afa8e06SEd Maste 		return;
1180afa8e06SEd Maste 
1190afa8e06SEd Maste 	freezero(pk, sizeof(*pk));
1200afa8e06SEd Maste 	*pkp = NULL;
1210afa8e06SEd Maste }
1220afa8e06SEd Maste 
1230afa8e06SEd Maste int
eddsa_pk_from_ptr(eddsa_pk_t * pk,const void * ptr,size_t len)1240afa8e06SEd Maste eddsa_pk_from_ptr(eddsa_pk_t *pk, const void *ptr, size_t len)
1250afa8e06SEd Maste {
126*2ccfa855SEd Maste 	EVP_PKEY *pkey;
127*2ccfa855SEd Maste 
1280afa8e06SEd Maste 	if (len < sizeof(*pk))
1290afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
1300afa8e06SEd Maste 
1310afa8e06SEd Maste 	memcpy(pk, ptr, sizeof(*pk));
1320afa8e06SEd Maste 
133*2ccfa855SEd Maste 	if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
134*2ccfa855SEd Maste 		fido_log_debug("%s: eddsa_pk_to_EVP_PKEY", __func__);
135*2ccfa855SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
136*2ccfa855SEd Maste 	}
137*2ccfa855SEd Maste 
138*2ccfa855SEd Maste 	EVP_PKEY_free(pkey);
139*2ccfa855SEd Maste 
1400afa8e06SEd Maste 	return (FIDO_OK);
1410afa8e06SEd Maste }
1420afa8e06SEd Maste 
1430afa8e06SEd Maste EVP_PKEY *
eddsa_pk_to_EVP_PKEY(const eddsa_pk_t * k)1440afa8e06SEd Maste eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *k)
1450afa8e06SEd Maste {
1460afa8e06SEd Maste 	EVP_PKEY *pkey = NULL;
1470afa8e06SEd Maste 
1480afa8e06SEd Maste 	if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, k->x,
1490afa8e06SEd Maste 	    sizeof(k->x))) == NULL)
1500afa8e06SEd Maste 		fido_log_debug("%s: EVP_PKEY_new_raw_public_key", __func__);
1510afa8e06SEd Maste 
1520afa8e06SEd Maste 	return (pkey);
1530afa8e06SEd Maste }
1540afa8e06SEd Maste 
1550afa8e06SEd Maste int
eddsa_pk_from_EVP_PKEY(eddsa_pk_t * pk,const EVP_PKEY * pkey)1560afa8e06SEd Maste eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey)
1570afa8e06SEd Maste {
1580afa8e06SEd Maste 	size_t len = 0;
1590afa8e06SEd Maste 
160*2ccfa855SEd Maste 	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519)
161*2ccfa855SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
1620afa8e06SEd Maste 	if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 ||
1630afa8e06SEd Maste 	    len != sizeof(pk->x))
1640afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
1650afa8e06SEd Maste 	if (EVP_PKEY_get_raw_public_key(pkey, pk->x, &len) != 1 ||
1660afa8e06SEd Maste 	    len != sizeof(pk->x))
1670afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
1680afa8e06SEd Maste 
1690afa8e06SEd Maste 	return (FIDO_OK);
1700afa8e06SEd Maste }
171f540a430SEd Maste 
172f540a430SEd Maste int
eddsa_verify_sig(const fido_blob_t * dgst,EVP_PKEY * pkey,const fido_blob_t * sig)173f540a430SEd Maste eddsa_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
174f540a430SEd Maste     const fido_blob_t *sig)
175f540a430SEd Maste {
176f540a430SEd Maste 	EVP_MD_CTX	*mdctx = NULL;
177f540a430SEd Maste 	int		 ok = -1;
178f540a430SEd Maste 
179f540a430SEd Maste 	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519) {
180f540a430SEd Maste 		fido_log_debug("%s: EVP_PKEY_base_id", __func__);
181f540a430SEd Maste 		goto fail;
182f540a430SEd Maste 	}
183f540a430SEd Maste 
184f540a430SEd Maste 	/* EVP_DigestVerify needs ints */
185f540a430SEd Maste 	if (dgst->len > INT_MAX || sig->len > INT_MAX) {
186f540a430SEd Maste 		fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
187f540a430SEd Maste 		    dgst->len, sig->len);
188f540a430SEd Maste 		return (-1);
189f540a430SEd Maste 	}
190f540a430SEd Maste 
191f540a430SEd Maste 	if ((mdctx = EVP_MD_CTX_new()) == NULL) {
192f540a430SEd Maste 		fido_log_debug("%s: EVP_MD_CTX_new", __func__);
193f540a430SEd Maste 		goto fail;
194f540a430SEd Maste 	}
195f540a430SEd Maste 
196f540a430SEd Maste 	if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
197f540a430SEd Maste 		fido_log_debug("%s: EVP_DigestVerifyInit", __func__);
198f540a430SEd Maste 		goto fail;
199f540a430SEd Maste 	}
200f540a430SEd Maste 
201f540a430SEd Maste 	if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr,
202f540a430SEd Maste 	    dgst->len) != 1) {
203f540a430SEd Maste 		fido_log_debug("%s: EVP_DigestVerify", __func__);
204f540a430SEd Maste 		goto fail;
205f540a430SEd Maste 	}
206f540a430SEd Maste 
207f540a430SEd Maste 	ok = 0;
208f540a430SEd Maste fail:
209f540a430SEd Maste 	EVP_MD_CTX_free(mdctx);
210f540a430SEd Maste 
211f540a430SEd Maste 	return (ok);
212f540a430SEd Maste }
213f540a430SEd Maste 
214f540a430SEd Maste int
eddsa_pk_verify_sig(const fido_blob_t * dgst,const eddsa_pk_t * pk,const fido_blob_t * sig)215f540a430SEd Maste eddsa_pk_verify_sig(const fido_blob_t *dgst, const eddsa_pk_t *pk,
216f540a430SEd Maste     const fido_blob_t *sig)
217f540a430SEd Maste {
218f540a430SEd Maste 	EVP_PKEY	*pkey;
219f540a430SEd Maste 	int		 ok = -1;
220f540a430SEd Maste 
221f540a430SEd Maste 	if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL ||
222f540a430SEd Maste 	    eddsa_verify_sig(dgst, pkey, sig) < 0) {
223f540a430SEd Maste 		fido_log_debug("%s: eddsa_verify_sig", __func__);
224f540a430SEd Maste 		goto fail;
225f540a430SEd Maste 	}
226f540a430SEd Maste 
227f540a430SEd Maste 	ok = 0;
228f540a430SEd Maste fail:
229f540a430SEd Maste 	EVP_PKEY_free(pkey);
230f540a430SEd Maste 
231f540a430SEd Maste 	return (ok);
232f540a430SEd Maste }
233