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 | ||
58771c1c SB |
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 | ||
c0153b0b TA |
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 | */ | |
a2976416 | 44 | int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64], |
c0153b0b | 45 | u8 secret[32]) |
58771c1c | 46 | { |
fe93d841 | 47 | DECLARE_CRYPTO_WAIT(result); |
58771c1c | 48 | struct kpp_request *req; |
c0153b0b | 49 | u8 *tmp; |
58771c1c | 50 | struct scatterlist src, dst; |
a2976416 | 51 | int err; |
58771c1c | 52 | |
763d9a30 SB |
53 | tmp = kmalloc(64, GFP_KERNEL); |
54 | if (!tmp) | |
a2976416 | 55 | return -ENOMEM; |
763d9a30 | 56 | |
58771c1c | 57 | req = kpp_request_alloc(tfm, GFP_KERNEL); |
a2976416 TA |
58 | if (!req) { |
59 | err = -ENOMEM; | |
47eb2ac8 | 60 | goto free_tmp; |
a2976416 | 61 | } |
58771c1c | 62 | |
58771c1c SB |
63 | swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */ |
64 | swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */ | |
65 | ||
66 | sg_init_one(&src, tmp, 64); | |
67 | sg_init_one(&dst, secret, 32); | |
68 | kpp_request_set_input(req, &src, 64); | |
69 | kpp_request_set_output(req, &dst, 32); | |
70 | kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, | |
fe93d841 | 71 | crypto_req_done, &result); |
58771c1c | 72 | err = crypto_kpp_compute_shared_secret(req); |
fe93d841 | 73 | err = crypto_wait_req(err, &result); |
58771c1c SB |
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((u64 *)secret, (u64 *)tmp, 4); | |
81 | memcpy(secret, tmp, 32); | |
82 | ||
83 | free_all: | |
58771c1c | 84 | kpp_request_free(req); |
763d9a30 | 85 | free_tmp: |
453431a5 | 86 | kfree_sensitive(tmp); |
a2976416 | 87 | return err; |
58771c1c SB |
88 | } |
89 | ||
c0153b0b TA |
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 | ||
c0153b0b TA |
108 | if (private_key) { |
109 | tmp = kmalloc(32, GFP_KERNEL); | |
110 | if (!tmp) | |
111 | return -ENOMEM; | |
112 | swap_digits((u64 *)private_key, (u64 *)tmp, 4); | |
113 | p.key = tmp; | |
114 | p.key_size = 32; | |
115 | } | |
116 | ||
117 | buf_len = crypto_ecdh_key_len(&p); | |
118 | buf = kmalloc(buf_len, GFP_KERNEL); | |
119 | if (!buf) { | |
120 | err = -ENOMEM; | |
121 | goto free_tmp; | |
122 | } | |
123 | ||
124 | err = crypto_ecdh_encode_key(buf, buf_len, &p); | |
125 | if (err) | |
126 | goto free_all; | |
127 | ||
128 | err = crypto_kpp_set_secret(tfm, buf, buf_len); | |
129 | /* fall through */ | |
130 | free_all: | |
453431a5 | 131 | kfree_sensitive(buf); |
c0153b0b | 132 | free_tmp: |
453431a5 | 133 | kfree_sensitive(tmp); |
c0153b0b TA |
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]) | |
58771c1c | 146 | { |
fe93d841 | 147 | DECLARE_CRYPTO_WAIT(result); |
58771c1c | 148 | struct kpp_request *req; |
c0153b0b | 149 | u8 *tmp; |
58771c1c | 150 | struct scatterlist dst; |
a2976416 | 151 | int err; |
58771c1c | 152 | |
763d9a30 SB |
153 | tmp = kmalloc(64, GFP_KERNEL); |
154 | if (!tmp) | |
a2976416 | 155 | return -ENOMEM; |
763d9a30 | 156 | |
58771c1c | 157 | req = kpp_request_alloc(tfm, GFP_KERNEL); |
a2976416 TA |
158 | if (!req) { |
159 | err = -ENOMEM; | |
47eb2ac8 | 160 | goto free_tmp; |
a2976416 | 161 | } |
58771c1c | 162 | |
c0153b0b TA |
163 | sg_init_one(&dst, tmp, 64); |
164 | kpp_request_set_input(req, NULL, 0); | |
165 | kpp_request_set_output(req, &dst, 64); | |
166 | kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, | |
fe93d841 | 167 | crypto_req_done, &result); |
58771c1c | 168 | |
c0153b0b | 169 | err = crypto_kpp_generate_public_key(req); |
fe93d841 | 170 | err = crypto_wait_req(err, &result); |
c0153b0b TA |
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. | |
58771c1c SB |
176 | */ |
177 | swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */ | |
178 | swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */ | |
58771c1c SB |
179 | |
180 | free_all: | |
58771c1c | 181 | kpp_request_free(req); |
763d9a30 SB |
182 | free_tmp: |
183 | kfree(tmp); | |
a2976416 | 184 | return err; |
58771c1c | 185 | } |
c0153b0b TA |
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 | } |