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