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