Coverage Report

Created: 2021-07-20 18:14

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