Home | History | Annotate | Line # | Download | only in src
      1      1.1  christos /*
      2  1.1.1.2  christos  * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
      3      1.1  christos  * Use of this source code is governed by a BSD-style
      4      1.1  christos  * license that can be found in the LICENSE file.
      5  1.1.1.3  christos  * SPDX-License-Identifier: BSD-2-Clause
      6      1.1  christos  */
      7      1.1  christos 
      8      1.1  christos #include <openssl/evp.h>
      9      1.1  christos #include <openssl/sha.h>
     10  1.1.1.2  christos #if defined(LIBRESSL_VERSION_NUMBER)
     11  1.1.1.2  christos #include <openssl/hkdf.h>
     12  1.1.1.3  christos #else
     13  1.1.1.2  christos #include <openssl/kdf.h>
     14  1.1.1.2  christos #endif
     15      1.1  christos 
     16      1.1  christos #include "fido.h"
     17      1.1  christos #include "fido/es256.h"
     18      1.1  christos 
     19  1.1.1.3  christos #if defined(LIBRESSL_VERSION_NUMBER)
     20      1.1  christos static int
     21  1.1.1.2  christos hkdf_sha256(uint8_t *key, const char *info, const fido_blob_t *secret)
     22      1.1  christos {
     23  1.1.1.2  christos 	const EVP_MD *md;
     24  1.1.1.2  christos 	uint8_t salt[32];
     25      1.1  christos 
     26  1.1.1.2  christos 	memset(salt, 0, sizeof(salt));
     27  1.1.1.2  christos 	if ((md = EVP_sha256()) == NULL ||
     28  1.1.1.2  christos 	    HKDF(key, SHA256_DIGEST_LENGTH, md, secret->ptr, secret->len, salt,
     29  1.1.1.2  christos 	    sizeof(salt), (const uint8_t *)info, strlen(info)) != 1)
     30  1.1.1.2  christos 		return -1;
     31  1.1.1.2  christos 
     32  1.1.1.2  christos 	return 0;
     33  1.1.1.2  christos }
     34  1.1.1.2  christos #else
     35  1.1.1.2  christos static int
     36  1.1.1.2  christos hkdf_sha256(uint8_t *key, char *info, fido_blob_t *secret)
     37  1.1.1.2  christos {
     38  1.1.1.2  christos 	const EVP_MD *const_md;
     39  1.1.1.2  christos 	EVP_MD *md = NULL;
     40  1.1.1.2  christos 	EVP_PKEY_CTX *ctx = NULL;
     41  1.1.1.2  christos 	size_t keylen = SHA256_DIGEST_LENGTH;
     42  1.1.1.2  christos 	uint8_t	salt[32];
     43  1.1.1.2  christos 	int ok = -1;
     44  1.1.1.2  christos 
     45  1.1.1.2  christos 	memset(salt, 0, sizeof(salt));
     46  1.1.1.2  christos 	if (secret->len > INT_MAX || strlen(info) > INT_MAX) {
     47  1.1.1.2  christos 		fido_log_debug("%s: invalid param", __func__);
     48  1.1.1.2  christos 		goto fail;
     49  1.1.1.2  christos 	}
     50  1.1.1.2  christos 	if ((const_md = EVP_sha256()) == NULL ||
     51  1.1.1.2  christos 	    (md = EVP_MD_meth_dup(const_md)) == NULL ||
     52  1.1.1.2  christos 	    (ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL)) == NULL) {
     53  1.1.1.2  christos 		fido_log_debug("%s: init", __func__);
     54  1.1.1.2  christos 		goto fail;
     55  1.1.1.2  christos 	}
     56  1.1.1.2  christos 	if (EVP_PKEY_derive_init(ctx) < 1 ||
     57  1.1.1.2  christos 	    EVP_PKEY_CTX_set_hkdf_md(ctx, md) < 1 ||
     58  1.1.1.2  christos 	    EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, sizeof(salt)) < 1 ||
     59  1.1.1.2  christos 	    EVP_PKEY_CTX_set1_hkdf_key(ctx, secret->ptr, (int)secret->len) < 1 ||
     60  1.1.1.3  christos 	    EVP_PKEY_CTX_add1_hkdf_info(ctx, (void *)info, (int)strlen(info)) < 1) {
     61  1.1.1.2  christos 		fido_log_debug("%s: EVP_PKEY_CTX", __func__);
     62  1.1.1.2  christos 		goto fail;
     63  1.1.1.2  christos 	}
     64  1.1.1.2  christos 	if (EVP_PKEY_derive(ctx, key, &keylen) < 1) {
     65  1.1.1.2  christos 		fido_log_debug("%s: EVP_PKEY_derive", __func__);
     66  1.1.1.2  christos 		goto fail;
     67  1.1.1.2  christos 	}
     68  1.1.1.2  christos 
     69  1.1.1.2  christos 	ok = 0;
     70  1.1.1.2  christos fail:
     71  1.1.1.2  christos 	if (md != NULL)
     72  1.1.1.2  christos 		EVP_MD_meth_free(md);
     73  1.1.1.2  christos 	if (ctx != NULL)
     74  1.1.1.2  christos 		EVP_PKEY_CTX_free(ctx);
     75  1.1.1.2  christos 
     76  1.1.1.2  christos 	return ok;
     77  1.1.1.2  christos }
     78  1.1.1.3  christos #endif /* defined(LIBRESSL_VERSION_NUMBER) */
     79  1.1.1.2  christos 
     80  1.1.1.2  christos static int
     81  1.1.1.2  christos kdf(uint8_t prot, fido_blob_t *key, /* const */ fido_blob_t *secret)
     82  1.1.1.2  christos {
     83  1.1.1.2  christos 	char hmac_info[] = "CTAP2 HMAC key"; /* const */
     84  1.1.1.2  christos 	char aes_info[] = "CTAP2 AES key"; /* const */
     85  1.1.1.2  christos 
     86  1.1.1.2  christos 	switch (prot) {
     87  1.1.1.2  christos 	case CTAP_PIN_PROTOCOL1:
     88  1.1.1.2  christos 		/* use sha256 on the resulting secret */
     89  1.1.1.2  christos 		key->len = SHA256_DIGEST_LENGTH;
     90  1.1.1.2  christos 		if ((key->ptr = calloc(1, key->len)) == NULL ||
     91  1.1.1.2  christos 		    SHA256(secret->ptr, secret->len, key->ptr) != key->ptr) {
     92  1.1.1.2  christos 			fido_log_debug("%s: SHA256", __func__);
     93  1.1.1.2  christos 			return -1;
     94  1.1.1.2  christos 		}
     95  1.1.1.2  christos 		break;
     96  1.1.1.2  christos 	case CTAP_PIN_PROTOCOL2:
     97  1.1.1.2  christos 		/* use two instances of hkdf-sha256 on the resulting secret */
     98  1.1.1.2  christos 		key->len = 2 * SHA256_DIGEST_LENGTH;
     99  1.1.1.2  christos 		if ((key->ptr = calloc(1, key->len)) == NULL ||
    100  1.1.1.2  christos 		    hkdf_sha256(key->ptr, hmac_info, secret) < 0 ||
    101  1.1.1.2  christos 		    hkdf_sha256(key->ptr + SHA256_DIGEST_LENGTH, aes_info,
    102  1.1.1.2  christos 		    secret) < 0) {
    103  1.1.1.2  christos 			fido_log_debug("%s: hkdf", __func__);
    104  1.1.1.2  christos 			return -1;
    105  1.1.1.2  christos 		}
    106  1.1.1.2  christos 		break;
    107  1.1.1.2  christos 	default:
    108  1.1.1.2  christos 		fido_log_debug("%s: unknown pin protocol %u", __func__, prot);
    109  1.1.1.2  christos 		return -1;
    110  1.1.1.2  christos 	}
    111  1.1.1.2  christos 
    112  1.1.1.2  christos 	return 0;
    113  1.1.1.2  christos }
    114  1.1.1.2  christos 
    115  1.1.1.2  christos static int
    116  1.1.1.2  christos do_ecdh(const fido_dev_t *dev, const es256_sk_t *sk, const es256_pk_t *pk,
    117  1.1.1.2  christos     fido_blob_t **ecdh)
    118  1.1.1.2  christos {
    119  1.1.1.2  christos 	EVP_PKEY *pk_evp = NULL;
    120  1.1.1.2  christos 	EVP_PKEY *sk_evp = NULL;
    121  1.1.1.2  christos 	EVP_PKEY_CTX *ctx = NULL;
    122  1.1.1.2  christos 	fido_blob_t *secret = NULL;
    123  1.1.1.2  christos 	int ok = -1;
    124      1.1  christos 
    125  1.1.1.2  christos 	*ecdh = NULL;
    126      1.1  christos 	if ((secret = fido_blob_new()) == NULL ||
    127      1.1  christos 	    (*ecdh = fido_blob_new()) == NULL)
    128      1.1  christos 		goto fail;
    129      1.1  christos 	if ((pk_evp = es256_pk_to_EVP_PKEY(pk)) == NULL ||
    130      1.1  christos 	    (sk_evp = es256_sk_to_EVP_PKEY(sk)) == NULL) {
    131      1.1  christos 		fido_log_debug("%s: es256_to_EVP_PKEY", __func__);
    132      1.1  christos 		goto fail;
    133      1.1  christos 	}
    134      1.1  christos 	if ((ctx = EVP_PKEY_CTX_new(sk_evp, NULL)) == NULL ||
    135      1.1  christos 	    EVP_PKEY_derive_init(ctx) <= 0 ||
    136      1.1  christos 	    EVP_PKEY_derive_set_peer(ctx, pk_evp) <= 0) {
    137      1.1  christos 		fido_log_debug("%s: EVP_PKEY_derive_init", __func__);
    138      1.1  christos 		goto fail;
    139      1.1  christos 	}
    140      1.1  christos 	if (EVP_PKEY_derive(ctx, NULL, &secret->len) <= 0 ||
    141      1.1  christos 	    (secret->ptr = calloc(1, secret->len)) == NULL ||
    142      1.1  christos 	    EVP_PKEY_derive(ctx, secret->ptr, &secret->len) <= 0) {
    143      1.1  christos 		fido_log_debug("%s: EVP_PKEY_derive", __func__);
    144      1.1  christos 		goto fail;
    145      1.1  christos 	}
    146  1.1.1.2  christos 	if (kdf(fido_dev_get_pin_protocol(dev), *ecdh, secret) < 0) {
    147  1.1.1.2  christos 		fido_log_debug("%s: kdf", __func__);
    148      1.1  christos 		goto fail;
    149      1.1  christos 	}
    150      1.1  christos 
    151      1.1  christos 	ok = 0;
    152      1.1  christos fail:
    153      1.1  christos 	if (pk_evp != NULL)
    154      1.1  christos 		EVP_PKEY_free(pk_evp);
    155      1.1  christos 	if (sk_evp != NULL)
    156      1.1  christos 		EVP_PKEY_free(sk_evp);
    157      1.1  christos 	if (ctx != NULL)
    158      1.1  christos 		EVP_PKEY_CTX_free(ctx);
    159      1.1  christos 	if (ok < 0)
    160      1.1  christos 		fido_blob_free(ecdh);
    161      1.1  christos 
    162      1.1  christos 	fido_blob_free(&secret);
    163      1.1  christos 
    164  1.1.1.2  christos 	return ok;
    165      1.1  christos }
    166      1.1  christos 
    167      1.1  christos int
    168  1.1.1.3  christos fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh, int *ms)
    169      1.1  christos {
    170  1.1.1.2  christos 	es256_sk_t *sk = NULL; /* our private key */
    171  1.1.1.2  christos 	es256_pk_t *ak = NULL; /* authenticator's public key */
    172  1.1.1.2  christos 	int r;
    173      1.1  christos 
    174  1.1.1.2  christos 	*pk = NULL;
    175  1.1.1.2  christos 	*ecdh = NULL;
    176      1.1  christos 	if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) {
    177      1.1  christos 		r = FIDO_ERR_INTERNAL;
    178      1.1  christos 		goto fail;
    179      1.1  christos 	}
    180      1.1  christos 	if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) {
    181      1.1  christos 		fido_log_debug("%s: es256_derive_pk", __func__);
    182      1.1  christos 		r = FIDO_ERR_INTERNAL;
    183      1.1  christos 		goto fail;
    184      1.1  christos 	}
    185      1.1  christos 	if ((ak = es256_pk_new()) == NULL ||
    186  1.1.1.3  christos 	    fido_dev_authkey(dev, ak, ms) != FIDO_OK) {
    187      1.1  christos 		fido_log_debug("%s: fido_dev_authkey", __func__);
    188      1.1  christos 		r = FIDO_ERR_INTERNAL;
    189      1.1  christos 		goto fail;
    190      1.1  christos 	}
    191  1.1.1.2  christos 	if (do_ecdh(dev, sk, ak, ecdh) < 0) {
    192      1.1  christos 		fido_log_debug("%s: do_ecdh", __func__);
    193      1.1  christos 		r = FIDO_ERR_INTERNAL;
    194      1.1  christos 		goto fail;
    195      1.1  christos 	}
    196      1.1  christos 
    197      1.1  christos 	r = FIDO_OK;
    198      1.1  christos fail:
    199      1.1  christos 	es256_sk_free(&sk);
    200      1.1  christos 	es256_pk_free(&ak);
    201      1.1  christos 
    202      1.1  christos 	if (r != FIDO_OK) {
    203      1.1  christos 		es256_pk_free(pk);
    204      1.1  christos 		fido_blob_free(ecdh);
    205      1.1  christos 	}
    206      1.1  christos 
    207  1.1.1.2  christos 	return r;
    208      1.1  christos }
    209