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