Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2018 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 | | |
10 | | #include "fido.h" |
11 | | #include "fido/es256.h" |
12 | | |
13 | | static int |
14 | | do_ecdh(const es256_sk_t *sk, const es256_pk_t *pk, fido_blob_t **ecdh) |
15 | 3.29k | { |
16 | 3.29k | EVP_PKEY *pk_evp = NULL; |
17 | 3.29k | EVP_PKEY *sk_evp = NULL; |
18 | 3.29k | EVP_PKEY_CTX *ctx = NULL; |
19 | 3.29k | fido_blob_t *secret = NULL; |
20 | 3.29k | int ok = -1; |
21 | 3.29k | |
22 | 3.29k | *ecdh = NULL; |
23 | 3.29k | |
24 | 3.29k | /* allocate blobs for secret & ecdh */ |
25 | 3.29k | if ((secret = fido_blob_new()) == NULL || |
26 | 3.29k | (*ecdh = fido_blob_new()) == NULL) |
27 | 3.29k | goto fail; |
28 | 3.27k | |
29 | 3.27k | /* wrap the keys as openssl objects */ |
30 | 3.27k | if ((pk_evp = es256_pk_to_EVP_PKEY(pk)) == NULL || |
31 | 3.27k | (sk_evp = es256_sk_to_EVP_PKEY(sk)) == NULL) { |
32 | 302 | fido_log_debug("%s: es256_to_EVP_PKEY", __func__); |
33 | 302 | goto fail; |
34 | 302 | } |
35 | 2.96k | |
36 | 2.96k | /* set ecdh parameters */ |
37 | 2.96k | if ((ctx = EVP_PKEY_CTX_new(sk_evp, NULL)) == NULL || |
38 | 2.96k | EVP_PKEY_derive_init(ctx) <= 0 || |
39 | 2.96k | EVP_PKEY_derive_set_peer(ctx, pk_evp) <= 0) { |
40 | 32 | fido_log_debug("%s: EVP_PKEY_derive_init", __func__); |
41 | 32 | goto fail; |
42 | 32 | } |
43 | 2.93k | |
44 | 2.93k | /* perform ecdh */ |
45 | 2.93k | if (EVP_PKEY_derive(ctx, NULL, &secret->len) <= 0 || |
46 | 2.93k | (secret->ptr = calloc(1, secret->len)) == NULL || |
47 | 2.93k | EVP_PKEY_derive(ctx, secret->ptr, &secret->len) <= 0) { |
48 | 9 | fido_log_debug("%s: EVP_PKEY_derive", __func__); |
49 | 9 | goto fail; |
50 | 9 | } |
51 | 2.92k | |
52 | 2.92k | /* use sha256 as a kdf on the resulting secret */ |
53 | 2.92k | (*ecdh)->len = SHA256_DIGEST_LENGTH; |
54 | 2.92k | if (((*ecdh)->ptr = calloc(1, (*ecdh)->len)) == NULL || |
55 | 2.92k | SHA256(secret->ptr, secret->len, (*ecdh)->ptr) != (*ecdh)->ptr) { |
56 | 15 | fido_log_debug("%s: sha256", __func__); |
57 | 15 | goto fail; |
58 | 15 | } |
59 | 2.91k | |
60 | 2.91k | ok = 0; |
61 | 3.29k | fail: |
62 | 3.29k | if (pk_evp != NULL) |
63 | 3.29k | EVP_PKEY_free(pk_evp); |
64 | 3.29k | if (sk_evp != NULL) |
65 | 3.29k | EVP_PKEY_free(sk_evp); |
66 | 3.29k | if (ctx != NULL) |
67 | 3.29k | EVP_PKEY_CTX_free(ctx); |
68 | 3.29k | if (ok < 0) |
69 | 377 | fido_blob_free(ecdh); |
70 | 3.29k | |
71 | 3.29k | fido_blob_free(&secret); |
72 | 3.29k | |
73 | 3.29k | return (ok); |
74 | 2.91k | } |
75 | | |
76 | | int |
77 | | fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh) |
78 | 5.01k | { |
79 | 5.01k | es256_sk_t *sk = NULL; /* our private key */ |
80 | 5.01k | es256_pk_t *ak = NULL; /* authenticator's public key */ |
81 | 5.01k | int r; |
82 | 5.01k | |
83 | 5.01k | *pk = NULL; /* our public key; returned */ |
84 | 5.01k | *ecdh = NULL; /* shared ecdh secret; returned */ |
85 | 5.01k | |
86 | 5.01k | if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) { |
87 | 32 | r = FIDO_ERR_INTERNAL; |
88 | 32 | goto fail; |
89 | 32 | } |
90 | 4.97k | |
91 | 4.97k | if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) { |
92 | 340 | fido_log_debug("%s: es256_derive_pk", __func__); |
93 | 340 | r = FIDO_ERR_INTERNAL; |
94 | 340 | goto fail; |
95 | 340 | } |
96 | 4.63k | |
97 | 4.63k | if ((ak = es256_pk_new()) == NULL || |
98 | 4.63k | fido_dev_authkey(dev, ak) != FIDO_OK) { |
99 | 1.34k | fido_log_debug("%s: fido_dev_authkey", __func__); |
100 | 1.34k | r = FIDO_ERR_INTERNAL; |
101 | 1.34k | goto fail; |
102 | 1.34k | } |
103 | 3.29k | |
104 | 3.29k | if (do_ecdh(sk, ak, ecdh) < 0) { |
105 | 377 | fido_log_debug("%s: do_ecdh", __func__); |
106 | 377 | r = FIDO_ERR_INTERNAL; |
107 | 377 | goto fail; |
108 | 377 | } |
109 | 2.91k | |
110 | 2.91k | r = FIDO_OK; |
111 | 5.01k | fail: |
112 | 5.01k | es256_sk_free(&sk); |
113 | 5.01k | es256_pk_free(&ak); |
114 | 5.01k | |
115 | 5.01k | if (r != FIDO_OK) { |
116 | 2.09k | es256_pk_free(pk); |
117 | 2.09k | fido_blob_free(ecdh); |
118 | 2.09k | } |
119 | 5.01k | |
120 | 5.01k | return (r); |
121 | 2.91k | } |