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