xref: /freebsd-src/contrib/libfido2/src/ecdh.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
10afa8e06SEd Maste /*
20afa8e06SEd Maste  * Copyright (c) 2018-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/evp.h>
90afa8e06SEd Maste #include <openssl/sha.h>
100afa8e06SEd Maste #if defined(LIBRESSL_VERSION_NUMBER)
110afa8e06SEd Maste #include <openssl/hkdf.h>
12f540a430SEd Maste #else
130afa8e06SEd Maste #include <openssl/kdf.h>
140afa8e06SEd Maste #endif
150afa8e06SEd Maste 
160afa8e06SEd Maste #include "fido.h"
170afa8e06SEd Maste #include "fido/es256.h"
180afa8e06SEd Maste 
19f540a430SEd Maste #if defined(LIBRESSL_VERSION_NUMBER)
200afa8e06SEd Maste static int
hkdf_sha256(uint8_t * key,const char * info,const fido_blob_t * secret)210afa8e06SEd Maste hkdf_sha256(uint8_t *key, const char *info, const fido_blob_t *secret)
220afa8e06SEd Maste {
230afa8e06SEd Maste 	const EVP_MD *md;
240afa8e06SEd Maste 	uint8_t salt[32];
250afa8e06SEd Maste 
260afa8e06SEd Maste 	memset(salt, 0, sizeof(salt));
270afa8e06SEd Maste 	if ((md = EVP_sha256()) == NULL ||
280afa8e06SEd Maste 	    HKDF(key, SHA256_DIGEST_LENGTH, md, secret->ptr, secret->len, salt,
290afa8e06SEd Maste 	    sizeof(salt), (const uint8_t *)info, strlen(info)) != 1)
300afa8e06SEd Maste 		return -1;
310afa8e06SEd Maste 
320afa8e06SEd Maste 	return 0;
330afa8e06SEd Maste }
340afa8e06SEd Maste #else
350afa8e06SEd Maste static int
hkdf_sha256(uint8_t * key,char * info,fido_blob_t * secret)360afa8e06SEd Maste hkdf_sha256(uint8_t *key, char *info, fido_blob_t *secret)
370afa8e06SEd Maste {
380afa8e06SEd Maste 	const EVP_MD *const_md;
390afa8e06SEd Maste 	EVP_MD *md = NULL;
400afa8e06SEd Maste 	EVP_PKEY_CTX *ctx = NULL;
410afa8e06SEd Maste 	size_t keylen = SHA256_DIGEST_LENGTH;
420afa8e06SEd Maste 	uint8_t	salt[32];
430afa8e06SEd Maste 	int ok = -1;
440afa8e06SEd Maste 
450afa8e06SEd Maste 	memset(salt, 0, sizeof(salt));
460afa8e06SEd Maste 	if (secret->len > INT_MAX || strlen(info) > INT_MAX) {
470afa8e06SEd Maste 		fido_log_debug("%s: invalid param", __func__);
480afa8e06SEd Maste 		goto fail;
490afa8e06SEd Maste 	}
500afa8e06SEd Maste 	if ((const_md = EVP_sha256()) == NULL ||
510afa8e06SEd Maste 	    (md = EVP_MD_meth_dup(const_md)) == NULL ||
520afa8e06SEd Maste 	    (ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL)) == NULL) {
530afa8e06SEd Maste 		fido_log_debug("%s: init", __func__);
540afa8e06SEd Maste 		goto fail;
550afa8e06SEd Maste 	}
560afa8e06SEd Maste 	if (EVP_PKEY_derive_init(ctx) < 1 ||
570afa8e06SEd Maste 	    EVP_PKEY_CTX_set_hkdf_md(ctx, md) < 1 ||
580afa8e06SEd Maste 	    EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, sizeof(salt)) < 1 ||
590afa8e06SEd Maste 	    EVP_PKEY_CTX_set1_hkdf_key(ctx, secret->ptr, (int)secret->len) < 1 ||
60f540a430SEd Maste 	    EVP_PKEY_CTX_add1_hkdf_info(ctx, (void *)info, (int)strlen(info)) < 1) {
610afa8e06SEd Maste 		fido_log_debug("%s: EVP_PKEY_CTX", __func__);
620afa8e06SEd Maste 		goto fail;
630afa8e06SEd Maste 	}
640afa8e06SEd Maste 	if (EVP_PKEY_derive(ctx, key, &keylen) < 1) {
650afa8e06SEd Maste 		fido_log_debug("%s: EVP_PKEY_derive", __func__);
660afa8e06SEd Maste 		goto fail;
670afa8e06SEd Maste 	}
680afa8e06SEd Maste 
690afa8e06SEd Maste 	ok = 0;
700afa8e06SEd Maste fail:
710afa8e06SEd Maste 	if (md != NULL)
720afa8e06SEd Maste 		EVP_MD_meth_free(md);
730afa8e06SEd Maste 	if (ctx != NULL)
740afa8e06SEd Maste 		EVP_PKEY_CTX_free(ctx);
750afa8e06SEd Maste 
760afa8e06SEd Maste 	return ok;
770afa8e06SEd Maste }
78f540a430SEd Maste #endif /* defined(LIBRESSL_VERSION_NUMBER) */
790afa8e06SEd Maste 
800afa8e06SEd Maste static int
kdf(uint8_t prot,fido_blob_t * key,fido_blob_t * secret)810afa8e06SEd Maste kdf(uint8_t prot, fido_blob_t *key, /* const */ fido_blob_t *secret)
820afa8e06SEd Maste {
830afa8e06SEd Maste 	char hmac_info[] = "CTAP2 HMAC key"; /* const */
840afa8e06SEd Maste 	char aes_info[] = "CTAP2 AES key"; /* const */
850afa8e06SEd Maste 
860afa8e06SEd Maste 	switch (prot) {
870afa8e06SEd Maste 	case CTAP_PIN_PROTOCOL1:
880afa8e06SEd Maste 		/* use sha256 on the resulting secret */
890afa8e06SEd Maste 		key->len = SHA256_DIGEST_LENGTH;
900afa8e06SEd Maste 		if ((key->ptr = calloc(1, key->len)) == NULL ||
910afa8e06SEd Maste 		    SHA256(secret->ptr, secret->len, key->ptr) != key->ptr) {
920afa8e06SEd Maste 			fido_log_debug("%s: SHA256", __func__);
930afa8e06SEd Maste 			return -1;
940afa8e06SEd Maste 		}
950afa8e06SEd Maste 		break;
960afa8e06SEd Maste 	case CTAP_PIN_PROTOCOL2:
970afa8e06SEd Maste 		/* use two instances of hkdf-sha256 on the resulting secret */
980afa8e06SEd Maste 		key->len = 2 * SHA256_DIGEST_LENGTH;
990afa8e06SEd Maste 		if ((key->ptr = calloc(1, key->len)) == NULL ||
1000afa8e06SEd Maste 		    hkdf_sha256(key->ptr, hmac_info, secret) < 0 ||
1010afa8e06SEd Maste 		    hkdf_sha256(key->ptr + SHA256_DIGEST_LENGTH, aes_info,
1020afa8e06SEd Maste 		    secret) < 0) {
1030afa8e06SEd Maste 			fido_log_debug("%s: hkdf", __func__);
1040afa8e06SEd Maste 			return -1;
1050afa8e06SEd Maste 		}
1060afa8e06SEd Maste 		break;
1070afa8e06SEd Maste 	default:
1080afa8e06SEd Maste 		fido_log_debug("%s: unknown pin protocol %u", __func__, prot);
1090afa8e06SEd Maste 		return -1;
1100afa8e06SEd Maste 	}
1110afa8e06SEd Maste 
1120afa8e06SEd Maste 	return 0;
1130afa8e06SEd Maste }
1140afa8e06SEd Maste 
1150afa8e06SEd Maste static int
do_ecdh(const fido_dev_t * dev,const es256_sk_t * sk,const es256_pk_t * pk,fido_blob_t ** ecdh)1160afa8e06SEd Maste do_ecdh(const fido_dev_t *dev, const es256_sk_t *sk, const es256_pk_t *pk,
1170afa8e06SEd Maste     fido_blob_t **ecdh)
1180afa8e06SEd Maste {
1190afa8e06SEd Maste 	EVP_PKEY *pk_evp = NULL;
1200afa8e06SEd Maste 	EVP_PKEY *sk_evp = NULL;
1210afa8e06SEd Maste 	EVP_PKEY_CTX *ctx = NULL;
1220afa8e06SEd Maste 	fido_blob_t *secret = NULL;
1230afa8e06SEd Maste 	int ok = -1;
1240afa8e06SEd Maste 
1250afa8e06SEd Maste 	*ecdh = NULL;
1260afa8e06SEd Maste 	if ((secret = fido_blob_new()) == NULL ||
1270afa8e06SEd Maste 	    (*ecdh = fido_blob_new()) == NULL)
1280afa8e06SEd Maste 		goto fail;
1290afa8e06SEd Maste 	if ((pk_evp = es256_pk_to_EVP_PKEY(pk)) == NULL ||
1300afa8e06SEd Maste 	    (sk_evp = es256_sk_to_EVP_PKEY(sk)) == NULL) {
1310afa8e06SEd Maste 		fido_log_debug("%s: es256_to_EVP_PKEY", __func__);
1320afa8e06SEd Maste 		goto fail;
1330afa8e06SEd Maste 	}
1340afa8e06SEd Maste 	if ((ctx = EVP_PKEY_CTX_new(sk_evp, NULL)) == NULL ||
1350afa8e06SEd Maste 	    EVP_PKEY_derive_init(ctx) <= 0 ||
1360afa8e06SEd Maste 	    EVP_PKEY_derive_set_peer(ctx, pk_evp) <= 0) {
1370afa8e06SEd Maste 		fido_log_debug("%s: EVP_PKEY_derive_init", __func__);
1380afa8e06SEd Maste 		goto fail;
1390afa8e06SEd Maste 	}
1400afa8e06SEd Maste 	if (EVP_PKEY_derive(ctx, NULL, &secret->len) <= 0 ||
1410afa8e06SEd Maste 	    (secret->ptr = calloc(1, secret->len)) == NULL ||
1420afa8e06SEd Maste 	    EVP_PKEY_derive(ctx, secret->ptr, &secret->len) <= 0) {
1430afa8e06SEd Maste 		fido_log_debug("%s: EVP_PKEY_derive", __func__);
1440afa8e06SEd Maste 		goto fail;
1450afa8e06SEd Maste 	}
1460afa8e06SEd Maste 	if (kdf(fido_dev_get_pin_protocol(dev), *ecdh, secret) < 0) {
1470afa8e06SEd Maste 		fido_log_debug("%s: kdf", __func__);
1480afa8e06SEd Maste 		goto fail;
1490afa8e06SEd Maste 	}
1500afa8e06SEd Maste 
1510afa8e06SEd Maste 	ok = 0;
1520afa8e06SEd Maste fail:
1530afa8e06SEd Maste 	if (pk_evp != NULL)
1540afa8e06SEd Maste 		EVP_PKEY_free(pk_evp);
1550afa8e06SEd Maste 	if (sk_evp != NULL)
1560afa8e06SEd Maste 		EVP_PKEY_free(sk_evp);
1570afa8e06SEd Maste 	if (ctx != NULL)
1580afa8e06SEd Maste 		EVP_PKEY_CTX_free(ctx);
1590afa8e06SEd Maste 	if (ok < 0)
1600afa8e06SEd Maste 		fido_blob_free(ecdh);
1610afa8e06SEd Maste 
1620afa8e06SEd Maste 	fido_blob_free(&secret);
1630afa8e06SEd Maste 
1640afa8e06SEd Maste 	return ok;
1650afa8e06SEd Maste }
1660afa8e06SEd Maste 
1670afa8e06SEd Maste int
fido_do_ecdh(fido_dev_t * dev,es256_pk_t ** pk,fido_blob_t ** ecdh,int * ms)168f540a430SEd Maste fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh, int *ms)
1690afa8e06SEd Maste {
1700afa8e06SEd Maste 	es256_sk_t *sk = NULL; /* our private key */
1710afa8e06SEd Maste 	es256_pk_t *ak = NULL; /* authenticator's public key */
1720afa8e06SEd Maste 	int r;
1730afa8e06SEd Maste 
1740afa8e06SEd Maste 	*pk = NULL;
1750afa8e06SEd Maste 	*ecdh = NULL;
1760afa8e06SEd Maste 	if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) {
1770afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
1780afa8e06SEd Maste 		goto fail;
1790afa8e06SEd Maste 	}
1800afa8e06SEd Maste 	if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) {
1810afa8e06SEd Maste 		fido_log_debug("%s: es256_derive_pk", __func__);
1820afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
1830afa8e06SEd Maste 		goto fail;
1840afa8e06SEd Maste 	}
1850afa8e06SEd Maste 	if ((ak = es256_pk_new()) == NULL ||
186f540a430SEd Maste 	    fido_dev_authkey(dev, ak, ms) != FIDO_OK) {
1870afa8e06SEd Maste 		fido_log_debug("%s: fido_dev_authkey", __func__);
1880afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
1890afa8e06SEd Maste 		goto fail;
1900afa8e06SEd Maste 	}
1910afa8e06SEd Maste 	if (do_ecdh(dev, sk, ak, ecdh) < 0) {
1920afa8e06SEd Maste 		fido_log_debug("%s: do_ecdh", __func__);
1930afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
1940afa8e06SEd Maste 		goto fail;
1950afa8e06SEd Maste 	}
1960afa8e06SEd Maste 
1970afa8e06SEd Maste 	r = FIDO_OK;
1980afa8e06SEd Maste fail:
1990afa8e06SEd Maste 	es256_sk_free(&sk);
2000afa8e06SEd Maste 	es256_pk_free(&ak);
2010afa8e06SEd Maste 
2020afa8e06SEd Maste 	if (r != FIDO_OK) {
2030afa8e06SEd Maste 		es256_pk_free(pk);
2040afa8e06SEd Maste 		fido_blob_free(ecdh);
2050afa8e06SEd Maste 	}
2060afa8e06SEd Maste 
2070afa8e06SEd Maste 	return r;
2080afa8e06SEd Maste }
209