summaryrefslogtreecommitdiff
path: root/src/ecdh.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ecdh.c')
-rw-r--r--src/ecdh.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/ecdh.c b/src/ecdh.c
new file mode 100644
index 0000000..7f25c7b
--- /dev/null
+++ b/src/ecdh.c
@@ -0,0 +1,121 @@
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
13static int
14do_ecdh(const es256_sk_t *sk, const es256_pk_t *pk, fido_blob_t **ecdh)
15{
16 EVP_PKEY *pk_evp = NULL;
17 EVP_PKEY *sk_evp = NULL;
18 EVP_PKEY_CTX *ctx = NULL;
19 fido_blob_t *secret = NULL;
20 int ok = -1;
21
22 *ecdh = NULL;
23
24 /* allocate blobs for secret & ecdh */
25 if ((secret = fido_blob_new()) == NULL ||
26 (*ecdh = fido_blob_new()) == NULL)
27 goto fail;
28
29 /* wrap the keys as openssl objects */
30 if ((pk_evp = es256_pk_to_EVP_PKEY(pk)) == NULL ||
31 (sk_evp = es256_sk_to_EVP_PKEY(sk)) == NULL) {
32 fido_log_debug("%s: es256_to_EVP_PKEY", __func__);
33 goto fail;
34 }
35
36 /* set ecdh parameters */
37 if ((ctx = EVP_PKEY_CTX_new(sk_evp, NULL)) == NULL ||
38 EVP_PKEY_derive_init(ctx) <= 0 ||
39 EVP_PKEY_derive_set_peer(ctx, pk_evp) <= 0) {
40 fido_log_debug("%s: EVP_PKEY_derive_init", __func__);
41 goto fail;
42 }
43
44 /* perform ecdh */
45 if (EVP_PKEY_derive(ctx, NULL, &secret->len) <= 0 ||
46 (secret->ptr = calloc(1, secret->len)) == NULL ||
47 EVP_PKEY_derive(ctx, secret->ptr, &secret->len) <= 0) {
48 fido_log_debug("%s: EVP_PKEY_derive", __func__);
49 goto fail;
50 }
51
52 /* use sha256 as a kdf on the resulting secret */
53 (*ecdh)->len = SHA256_DIGEST_LENGTH;
54 if (((*ecdh)->ptr = calloc(1, (*ecdh)->len)) == NULL ||
55 SHA256(secret->ptr, secret->len, (*ecdh)->ptr) != (*ecdh)->ptr) {
56 fido_log_debug("%s: sha256", __func__);
57 goto fail;
58 }
59
60 ok = 0;
61fail:
62 if (pk_evp != NULL)
63 EVP_PKEY_free(pk_evp);
64 if (sk_evp != NULL)
65 EVP_PKEY_free(sk_evp);
66 if (ctx != NULL)
67 EVP_PKEY_CTX_free(ctx);
68 if (ok < 0)
69 fido_blob_free(ecdh);
70
71 fido_blob_free(&secret);
72
73 return (ok);
74}
75
76int
77fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh)
78{
79 es256_sk_t *sk = NULL; /* our private key */
80 es256_pk_t *ak = NULL; /* authenticator's public key */
81 int r;
82
83 *pk = NULL; /* our public key; returned */
84 *ecdh = NULL; /* shared ecdh secret; returned */
85
86 if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) {
87 r = FIDO_ERR_INTERNAL;
88 goto fail;
89 }
90
91 if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) {
92 fido_log_debug("%s: es256_derive_pk", __func__);
93 r = FIDO_ERR_INTERNAL;
94 goto fail;
95 }
96
97 if ((ak = es256_pk_new()) == NULL ||
98 fido_dev_authkey(dev, ak) != FIDO_OK) {
99 fido_log_debug("%s: fido_dev_authkey", __func__);
100 r = FIDO_ERR_INTERNAL;
101 goto fail;
102 }
103
104 if (do_ecdh(sk, ak, ecdh) < 0) {
105 fido_log_debug("%s: do_ecdh", __func__);
106 r = FIDO_ERR_INTERNAL;
107 goto fail;
108 }
109
110 r = FIDO_OK;
111fail:
112 es256_sk_free(&sk);
113 es256_pk_free(&ak);
114
115 if (r != FIDO_OK) {
116 es256_pk_free(pk);
117 fido_blob_free(ecdh);
118 }
119
120 return (r);
121}