blob: 2a65ca3fa8fab262bc844490bc80f8c9e4191c50 [file] [log] [blame]
Salvatore Benedetto58771c1c2017-04-24 13:13:20 +01001/*
2 * ECDH helper functions - KPP wrappings
3 *
4 * Copyright (C) 2017 Intel Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation;
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
11 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
14 * CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 * ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
20 * COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
21 * SOFTWARE IS DISCLAIMED.
22 */
23#include "ecdh_helper.h"
24
25#include <linux/random.h>
26#include <linux/scatterlist.h>
27#include <crypto/kpp.h>
28#include <crypto/ecdh.h>
29
30struct ecdh_completion {
31 struct completion completion;
32 int err;
33};
34
35static void ecdh_complete(struct crypto_async_request *req, int err)
36{
37 struct ecdh_completion *res = req->data;
38
39 if (err == -EINPROGRESS)
40 return;
41
42 res->err = err;
43 complete(&res->completion);
44}
45
46static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits)
47{
48 int i;
49
50 for (i = 0; i < ndigits; i++)
51 out[i] = __swab64(in[ndigits - 1 - i]);
52}
53
54bool compute_ecdh_secret(const u8 public_key[64], const u8 private_key[32],
55 u8 secret[32])
56{
57 struct crypto_kpp *tfm;
58 struct kpp_request *req;
59 struct ecdh p;
60 struct ecdh_completion result;
61 struct scatterlist src, dst;
Salvatore Benedetto763d9a32017-04-25 16:59:47 +010062 u8 *tmp, *buf;
Salvatore Benedetto58771c1c2017-04-24 13:13:20 +010063 unsigned int buf_len;
64 int err = -ENOMEM;
65
Salvatore Benedetto763d9a32017-04-25 16:59:47 +010066 tmp = kmalloc(64, GFP_KERNEL);
67 if (!tmp)
68 return false;
69
Salvatore Benedetto58771c1c2017-04-24 13:13:20 +010070 tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
71 if (IS_ERR(tfm)) {
72 pr_err("alg: kpp: Failed to load tfm for kpp: %ld\n",
73 PTR_ERR(tfm));
Salvatore Benedetto763d9a32017-04-25 16:59:47 +010074 goto free_tmp;
Salvatore Benedetto58771c1c2017-04-24 13:13:20 +010075 }
76
77 req = kpp_request_alloc(tfm, GFP_KERNEL);
78 if (!req)
79 goto free_kpp;
80
81 init_completion(&result.completion);
82
83 /* Security Manager Protocol holds digits in litte-endian order
84 * while ECC API expect big-endian data
85 */
86 swap_digits((u64 *)private_key, (u64 *)tmp, 4);
87 p.key = (char *)tmp;
88 p.key_size = 32;
89 /* Set curve_id */
90 p.curve_id = ECC_CURVE_NIST_P256;
91 buf_len = crypto_ecdh_key_len(&p);
92 buf = kmalloc(buf_len, GFP_KERNEL);
93 if (!buf) {
94 pr_err("alg: kpp: Failed to allocate %d bytes for buf\n",
95 buf_len);
96 goto free_req;
97 }
98 crypto_ecdh_encode_key(buf, buf_len, &p);
99
100 /* Set A private Key */
101 err = crypto_kpp_set_secret(tfm, (void *)buf, buf_len);
102 if (err)
103 goto free_all;
104
105 swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */
106 swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */
107
108 sg_init_one(&src, tmp, 64);
109 sg_init_one(&dst, secret, 32);
110 kpp_request_set_input(req, &src, 64);
111 kpp_request_set_output(req, &dst, 32);
112 kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
113 ecdh_complete, &result);
114 err = crypto_kpp_compute_shared_secret(req);
115 if (err == -EINPROGRESS) {
116 wait_for_completion(&result.completion);
117 err = result.err;
118 }
119 if (err < 0) {
120 pr_err("alg: ecdh: compute shared secret failed. err %d\n",
121 err);
122 goto free_all;
123 }
124
125 swap_digits((u64 *)secret, (u64 *)tmp, 4);
126 memcpy(secret, tmp, 32);
127
128free_all:
129 kzfree(buf);
130free_req:
131 kpp_request_free(req);
132free_kpp:
133 crypto_free_kpp(tfm);
Salvatore Benedetto763d9a32017-04-25 16:59:47 +0100134free_tmp:
135 kfree(tmp);
Salvatore Benedetto58771c1c2017-04-24 13:13:20 +0100136 return (err == 0);
137}
138
139bool generate_ecdh_keys(u8 public_key[64], u8 private_key[32])
140{
141 struct crypto_kpp *tfm;
142 struct kpp_request *req;
143 struct ecdh p;
144 struct ecdh_completion result;
145 struct scatterlist dst;
Salvatore Benedetto763d9a32017-04-25 16:59:47 +0100146 u8 *tmp, *buf;
Salvatore Benedetto58771c1c2017-04-24 13:13:20 +0100147 unsigned int buf_len;
148 int err = -ENOMEM;
149 const unsigned short max_tries = 16;
150 unsigned short tries = 0;
151
Salvatore Benedetto763d9a32017-04-25 16:59:47 +0100152 tmp = kmalloc(64, GFP_KERNEL);
153 if (!tmp)
154 return false;
155
Salvatore Benedetto58771c1c2017-04-24 13:13:20 +0100156 tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
157 if (IS_ERR(tfm)) {
158 pr_err("alg: kpp: Failed to load tfm for kpp: %ld\n",
159 PTR_ERR(tfm));
Salvatore Benedetto763d9a32017-04-25 16:59:47 +0100160 goto free_tmp;
Salvatore Benedetto58771c1c2017-04-24 13:13:20 +0100161 }
162
163 req = kpp_request_alloc(tfm, GFP_KERNEL);
164 if (!req)
165 goto free_kpp;
166
167 init_completion(&result.completion);
168
169 /* Set curve_id */
170 p.curve_id = ECC_CURVE_NIST_P256;
171 p.key_size = 32;
172 buf_len = crypto_ecdh_key_len(&p);
173 buf = kmalloc(buf_len, GFP_KERNEL);
174 if (!buf) {
175 pr_err("alg: kpp: Failed to allocate %d bytes for buf\n",
176 buf_len);
177 goto free_req;
178 }
179
180 do {
181 if (tries++ >= max_tries)
182 goto free_all;
183
184 get_random_bytes(private_key, 32);
185
186 /* Set private Key */
187 p.key = (char *)private_key;
188 crypto_ecdh_encode_key(buf, buf_len, &p);
189 err = crypto_kpp_set_secret(tfm, buf, buf_len);
190 if (err)
191 goto free_all;
192
193 sg_init_one(&dst, tmp, 64);
Marcel Holtmannf9583152017-04-30 06:51:40 -0700194 kpp_request_set_input(req, NULL, 0);
Salvatore Benedetto58771c1c2017-04-24 13:13:20 +0100195 kpp_request_set_output(req, &dst, 64);
196 kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
197 ecdh_complete, &result);
198
199 err = crypto_kpp_generate_public_key(req);
200
201 if (err == -EINPROGRESS) {
202 wait_for_completion(&result.completion);
203 err = result.err;
204 }
205
206 /* Private key is not valid. Regenerate */
207 if (err == -EINVAL)
208 continue;
209
210 if (err < 0)
211 goto free_all;
212 else
213 break;
214
215 } while (true);
216
217 /* Keys are handed back in little endian as expected by Security
218 * Manager Protocol
219 */
220 swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */
221 swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */
222 swap_digits((u64 *)private_key, (u64 *)tmp, 4);
223 memcpy(private_key, tmp, 32);
224
225free_all:
226 kzfree(buf);
227free_req:
228 kpp_request_free(req);
229free_kpp:
230 crypto_free_kpp(tfm);
Salvatore Benedetto763d9a32017-04-25 16:59:47 +0100231free_tmp:
232 kfree(tmp);
Salvatore Benedetto58771c1c2017-04-24 13:13:20 +0100233 return (err == 0);
234}