Skip to content

Commit c0153b0

Browse files
ambarusholtmann
authored andcommitted
Bluetooth: let the crypto subsystem generate the ecc privkey
That Bluetooth SMP knows about the private key is pointless, since the detection of debug key usage is actually via the public key portion. With this patch, the Bluetooth SMP will stop keeping a copy of the ecdh private key and will let the crypto subsystem to generate and handle the ecdh private key, potentially benefiting of hardware ecc private key generation and retention. The loop that tries to generate a correct private key is now removed and we trust the crypto subsystem to generate a correct private key. This backup logic should be done in crypto, if really needed. Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
1 parent 168ed65 commit c0153b0

File tree

4 files changed

+147
-128
lines changed

4 files changed

+147
-128
lines changed

net/bluetooth/ecdh_helper.c

Lines changed: 102 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,21 @@ static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits)
4949
out[i] = __swab64(in[ndigits - 1 - i]);
5050
}
5151

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+
*/
5260
int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64],
53-
const u8 private_key[32], u8 secret[32])
61+
u8 secret[32])
5462
{
5563
struct kpp_request *req;
56-
struct ecdh p;
64+
u8 *tmp;
5765
struct ecdh_completion result;
5866
struct scatterlist src, dst;
59-
u8 *tmp, *buf;
60-
unsigned int buf_len;
6167
int err;
6268

6369
tmp = kmalloc(64, GFP_KERNEL);
@@ -72,28 +78,6 @@ int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64],
7278

7379
init_completion(&result.completion);
7480

75-
/* Security Manager Protocol holds digits in litte-endian order
76-
* while ECC API expect big-endian data
77-
*/
78-
swap_digits((u64 *)private_key, (u64 *)tmp, 4);
79-
p.key = (char *)tmp;
80-
p.key_size = 32;
81-
/* Set curve_id */
82-
p.curve_id = ECC_CURVE_NIST_P256;
83-
buf_len = crypto_ecdh_key_len(&p);
84-
buf = kmalloc(buf_len, GFP_KERNEL);
85-
if (!buf) {
86-
err = -ENOMEM;
87-
goto free_req;
88-
}
89-
90-
crypto_ecdh_encode_key(buf, buf_len, &p);
91-
92-
/* Set A private Key */
93-
err = crypto_kpp_set_secret(tfm, (void *)buf, buf_len);
94-
if (err)
95-
goto free_all;
96-
9781
swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */
9882
swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */
9983

@@ -118,26 +102,76 @@ int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64],
118102
memcpy(secret, tmp, 32);
119103

120104
free_all:
121-
kzfree(buf);
122-
free_req:
123105
kpp_request_free(req);
124106
free_tmp:
125107
kzfree(tmp);
126108
return err;
127109
}
128110

129-
int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64],
130-
u8 private_key[32])
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])
131169
{
132170
struct kpp_request *req;
133-
struct ecdh p;
171+
u8 *tmp;
134172
struct ecdh_completion result;
135173
struct scatterlist dst;
136-
u8 *tmp, *buf;
137-
unsigned int buf_len;
138174
int err;
139-
const unsigned short max_tries = 16;
140-
unsigned short tries = 0;
141175

142176
tmp = kmalloc(64, GFP_KERNEL);
143177
if (!tmp)
@@ -150,63 +184,47 @@ int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64],
150184
}
151185

152186
init_completion(&result.completion);
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);
153192

154-
/* Set curve_id */
155-
p.curve_id = ECC_CURVE_NIST_P256;
156-
p.key_size = 32;
157-
buf_len = crypto_ecdh_key_len(&p);
158-
buf = kmalloc(buf_len, GFP_KERNEL);
159-
if (!buf)
160-
goto free_req;
161-
162-
do {
163-
if (tries++ >= max_tries)
164-
goto free_all;
165-
166-
/* Set private Key */
167-
p.key = (char *)private_key;
168-
crypto_ecdh_encode_key(buf, buf_len, &p);
169-
err = crypto_kpp_set_secret(tfm, buf, buf_len);
170-
if (err)
171-
goto free_all;
172-
173-
sg_init_one(&dst, tmp, 64);
174-
kpp_request_set_input(req, NULL, 0);
175-
kpp_request_set_output(req, &dst, 64);
176-
kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
177-
ecdh_complete, &result);
178-
179-
err = crypto_kpp_generate_public_key(req);
180-
181-
if (err == -EINPROGRESS) {
182-
wait_for_completion(&result.completion);
183-
err = result.err;
184-
}
185-
186-
/* Private key is not valid. Regenerate */
187-
if (err == -EINVAL)
188-
continue;
189-
190-
if (err < 0)
191-
goto free_all;
192-
else
193-
break;
194-
195-
} while (true);
196-
197-
/* Keys are handed back in little endian as expected by Security
198-
* Manager Protocol
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.
199203
*/
200204
swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */
201205
swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */
202-
swap_digits((u64 *)private_key, (u64 *)tmp, 4);
203-
memcpy(private_key, tmp, 32);
204206

205207
free_all:
206-
kzfree(buf);
207-
free_req:
208208
kpp_request_free(req);
209209
free_tmp:
210210
kfree(tmp);
211211
return err;
212212
}
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+
}

net/bluetooth/ecdh_helper.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
#include <crypto/kpp.h>
2424
#include <linux/types.h>
2525

26-
int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 pub_a[64],
27-
const u8 priv_b[32], u8 secret[32]);
28-
int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64],
29-
u8 private_key[32]);
26+
int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 pair_public_key[64],
27+
u8 secret[32]);
28+
int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 *private_key);
29+
int generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64]);
30+
int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64]);

net/bluetooth/selftest.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,11 @@ static int __init test_ecdh_sample(struct crypto_kpp *tfm, const u8 priv_a[32],
152152
dhkey_a = &tmp[0];
153153
dhkey_b = &tmp[32];
154154

155-
ret = compute_ecdh_secret(tfm, pub_b, priv_a, dhkey_a);
155+
ret = set_ecdh_privkey(tfm, priv_a);
156156
if (ret)
157157
goto out;
158158

159-
ret = compute_ecdh_secret(tfm, pub_a, priv_b, dhkey_b);
159+
ret = compute_ecdh_secret(tfm, pub_b, dhkey_a);
160160
if (ret)
161161
goto out;
162162

@@ -165,9 +165,17 @@ static int __init test_ecdh_sample(struct crypto_kpp *tfm, const u8 priv_a[32],
165165
goto out;
166166
}
167167

168+
ret = set_ecdh_privkey(tfm, priv_b);
169+
if (ret)
170+
goto out;
171+
172+
ret = compute_ecdh_secret(tfm, pub_a, dhkey_b);
173+
if (ret)
174+
goto out;
175+
168176
if (memcmp(dhkey_b, dhkey, 32))
169177
ret = -EINVAL;
170-
178+
/* fall through*/
171179
out:
172180
kfree(tmp);
173181
return ret;

0 commit comments

Comments
 (0)