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