Commit | Line | Data |
---|---|---|
58771c1c SB |
1 | /* |
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 | ||
58771c1c | 25 | #include <linux/scatterlist.h> |
58771c1c SB |
26 | #include <crypto/ecdh.h> |
27 | ||
28 | struct ecdh_completion { | |
29 | struct completion completion; | |
30 | int err; | |
31 | }; | |
32 | ||
33 | static void ecdh_complete(struct crypto_async_request *req, int err) | |
34 | { | |
35 | struct ecdh_completion *res = req->data; | |
36 | ||
37 | if (err == -EINPROGRESS) | |
38 | return; | |
39 | ||
40 | res->err = err; | |
41 | complete(&res->completion); | |
42 | } | |
43 | ||
44 | static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits) | |
45 | { | |
46 | int i; | |
47 | ||
48 | for (i = 0; i < ndigits; i++) | |
49 | out[i] = __swab64(in[ndigits - 1 - i]); | |
50 | } | |
51 | ||
c0153b0b TA |
52 | /* compute_ecdh_secret() - function assumes that the private key was |
53 | * already set. | |
54 | * @tfm: KPP tfm handle allocated with crypto_alloc_kpp(). | |
55 | * @public_key: pair's ecc public key. | |
56 | * secret: memory where the ecdh computed shared secret will be saved. | |
57 | * | |
58 | * Return: zero on success; error code in case of error. | |
59 | */ | |
a2976416 | 60 | int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64], |
c0153b0b | 61 | u8 secret[32]) |
58771c1c | 62 | { |
58771c1c | 63 | struct kpp_request *req; |
c0153b0b | 64 | u8 *tmp; |
58771c1c SB |
65 | struct ecdh_completion result; |
66 | struct scatterlist src, dst; | |
a2976416 | 67 | int err; |
58771c1c | 68 | |
763d9a30 SB |
69 | tmp = kmalloc(64, GFP_KERNEL); |
70 | if (!tmp) | |
a2976416 | 71 | return -ENOMEM; |
763d9a30 | 72 | |
58771c1c | 73 | req = kpp_request_alloc(tfm, GFP_KERNEL); |
a2976416 TA |
74 | if (!req) { |
75 | err = -ENOMEM; | |
47eb2ac8 | 76 | goto free_tmp; |
a2976416 | 77 | } |
58771c1c SB |
78 | |
79 | init_completion(&result.completion); | |
80 | ||
58771c1c SB |
81 | swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */ |
82 | swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */ | |
83 | ||
84 | sg_init_one(&src, tmp, 64); | |
85 | sg_init_one(&dst, secret, 32); | |
86 | kpp_request_set_input(req, &src, 64); | |
87 | kpp_request_set_output(req, &dst, 32); | |
88 | kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, | |
89 | ecdh_complete, &result); | |
90 | err = crypto_kpp_compute_shared_secret(req); | |
91 | if (err == -EINPROGRESS) { | |
92 | wait_for_completion(&result.completion); | |
93 | err = result.err; | |
94 | } | |
95 | if (err < 0) { | |
96 | pr_err("alg: ecdh: compute shared secret failed. err %d\n", | |
97 | err); | |
98 | goto free_all; | |
99 | } | |
100 | ||
101 | swap_digits((u64 *)secret, (u64 *)tmp, 4); | |
102 | memcpy(secret, tmp, 32); | |
103 | ||
104 | free_all: | |
58771c1c | 105 | kpp_request_free(req); |
763d9a30 | 106 | free_tmp: |
168ed654 | 107 | kzfree(tmp); |
a2976416 | 108 | return err; |
58771c1c SB |
109 | } |
110 | ||
c0153b0b TA |
111 | /* set_ecdh_privkey() - set or generate ecc private key. |
112 | * | |
113 | * Function generates an ecc private key in the crypto subsystem when receiving | |
114 | * a NULL private key or sets the received key when not NULL. | |
115 | * | |
116 | * @tfm: KPP tfm handle allocated with crypto_alloc_kpp(). | |
117 | * @private_key: user's ecc private key. When not NULL, the key is expected | |
118 | * in little endian format. | |
119 | * | |
120 | * Return: zero on success; error code in case of error. | |
121 | */ | |
122 | int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 private_key[32]) | |
123 | { | |
124 | u8 *buf, *tmp = NULL; | |
125 | unsigned int buf_len; | |
126 | int err; | |
127 | struct ecdh p = {0}; | |
128 | ||
129 | p.curve_id = ECC_CURVE_NIST_P256; | |
130 | ||
131 | if (private_key) { | |
132 | tmp = kmalloc(32, GFP_KERNEL); | |
133 | if (!tmp) | |
134 | return -ENOMEM; | |
135 | swap_digits((u64 *)private_key, (u64 *)tmp, 4); | |
136 | p.key = tmp; | |
137 | p.key_size = 32; | |
138 | } | |
139 | ||
140 | buf_len = crypto_ecdh_key_len(&p); | |
141 | buf = kmalloc(buf_len, GFP_KERNEL); | |
142 | if (!buf) { | |
143 | err = -ENOMEM; | |
144 | goto free_tmp; | |
145 | } | |
146 | ||
147 | err = crypto_ecdh_encode_key(buf, buf_len, &p); | |
148 | if (err) | |
149 | goto free_all; | |
150 | ||
151 | err = crypto_kpp_set_secret(tfm, buf, buf_len); | |
152 | /* fall through */ | |
153 | free_all: | |
154 | kzfree(buf); | |
155 | free_tmp: | |
156 | kzfree(tmp); | |
157 | return err; | |
158 | } | |
159 | ||
160 | /* generate_ecdh_public_key() - function assumes that the private key was | |
161 | * already set. | |
162 | * | |
163 | * @tfm: KPP tfm handle allocated with crypto_alloc_kpp(). | |
164 | * @public_key: memory where the computed ecc public key will be saved. | |
165 | * | |
166 | * Return: zero on success; error code in case of error. | |
167 | */ | |
168 | int generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64]) | |
58771c1c | 169 | { |
58771c1c | 170 | struct kpp_request *req; |
c0153b0b | 171 | u8 *tmp; |
58771c1c SB |
172 | struct ecdh_completion result; |
173 | struct scatterlist dst; | |
a2976416 | 174 | int err; |
58771c1c | 175 | |
763d9a30 SB |
176 | tmp = kmalloc(64, GFP_KERNEL); |
177 | if (!tmp) | |
a2976416 | 178 | return -ENOMEM; |
763d9a30 | 179 | |
58771c1c | 180 | req = kpp_request_alloc(tfm, GFP_KERNEL); |
a2976416 TA |
181 | if (!req) { |
182 | err = -ENOMEM; | |
47eb2ac8 | 183 | goto free_tmp; |
a2976416 | 184 | } |
58771c1c SB |
185 | |
186 | init_completion(&result.completion); | |
c0153b0b TA |
187 | sg_init_one(&dst, tmp, 64); |
188 | kpp_request_set_input(req, NULL, 0); | |
189 | kpp_request_set_output(req, &dst, 64); | |
190 | kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, | |
191 | ecdh_complete, &result); | |
58771c1c | 192 | |
c0153b0b TA |
193 | err = crypto_kpp_generate_public_key(req); |
194 | if (err == -EINPROGRESS) { | |
195 | wait_for_completion(&result.completion); | |
196 | err = result.err; | |
197 | } | |
198 | if (err < 0) | |
199 | goto free_all; | |
200 | ||
201 | /* The public key is handed back in little endian as expected by | |
202 | * the Security Manager Protocol. | |
58771c1c SB |
203 | */ |
204 | swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */ | |
205 | swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */ | |
58771c1c SB |
206 | |
207 | free_all: | |
58771c1c | 208 | kpp_request_free(req); |
763d9a30 SB |
209 | free_tmp: |
210 | kfree(tmp); | |
a2976416 | 211 | return err; |
58771c1c | 212 | } |
c0153b0b TA |
213 | |
214 | /* generate_ecdh_keys() - generate ecc key pair. | |
215 | * | |
216 | * @tfm: KPP tfm handle allocated with crypto_alloc_kpp(). | |
217 | * @public_key: memory where the computed ecc public key will be saved. | |
218 | * | |
219 | * Return: zero on success; error code in case of error. | |
220 | */ | |
221 | int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64]) | |
222 | { | |
223 | int err; | |
224 | ||
225 | err = set_ecdh_privkey(tfm, NULL); | |
226 | if (err) | |
227 | return err; | |
228 | ||
229 | return generate_ecdh_public_key(tfm, public_key); | |
230 | } |