1 /*
2  * Copyright (c) 2017 Nordic Semiconductor ASA
3  * Copyright (c) 2015 Intel Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <stdint.h>
9 
10 #include <zephyr/sys/byteorder.h>
11 #include <zephyr/sys/check.h>
12 #include <zephyr/bluetooth/hci.h>
13 
14 #include <psa/crypto.h>
15 
16 #include "long_wq.h"
17 #include "ecc.h"
18 #include "hci_core.h"
19 
20 #define LOG_LEVEL CONFIG_BT_HCI_CORE_LOG_LEVEL
21 #include <zephyr/logging/log.h>
22 LOG_MODULE_REGISTER(bt_ecc);
23 
24 static uint8_t pub_key[BT_PUB_KEY_LEN];
25 static sys_slist_t pub_key_cb_slist;
26 static bt_dh_key_cb_t dh_key_cb;
27 
28 static void generate_pub_key(struct k_work *work);
29 static void generate_dh_key(struct k_work *work);
30 K_WORK_DEFINE(pub_key_work, generate_pub_key);
31 K_WORK_DEFINE(dh_key_work, generate_dh_key);
32 
33 enum {
34 	PENDING_PUB_KEY,
35 	PENDING_DHKEY,
36 
37 	/* Total number of flags - must be at the end of the enum */
38 	NUM_FLAGS,
39 };
40 
41 static ATOMIC_DEFINE(flags, NUM_FLAGS);
42 
43 static struct {
44 	uint8_t private_key_be[BT_PRIV_KEY_LEN];
45 
46 	union {
47 		uint8_t public_key_be[BT_PUB_KEY_LEN];
48 		uint8_t dhkey_be[BT_DH_KEY_LEN];
49 	};
50 } ecc;
51 
52 /* based on Core Specification 4.2 Vol 3. Part H 2.3.5.6.1 */
53 static const uint8_t debug_private_key_be[BT_PRIV_KEY_LEN] = {
54 	0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38,
55 	0x74, 0xc9, 0xb3, 0xe3, 0xd2, 0x10, 0x3f, 0x50,
56 	0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99,
57 	0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd,
58 };
59 
60 static const uint8_t debug_public_key[BT_PUB_KEY_LEN] = {
61 	/* X */
62 	0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
63 	0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
64 	0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
65 	0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20,
66 	/* Y */
67 	0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74,
68 	0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76,
69 	0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63,
70 	0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc
71 };
72 
bt_pub_key_is_debug(uint8_t * cmp_pub_key)73 bool bt_pub_key_is_debug(uint8_t *cmp_pub_key)
74 {
75 	return memcmp(cmp_pub_key, debug_public_key, BT_PUB_KEY_LEN) == 0;
76 }
77 
bt_pub_key_is_valid(const uint8_t key[BT_PUB_KEY_LEN])78 bool bt_pub_key_is_valid(const uint8_t key[BT_PUB_KEY_LEN])
79 {
80 	uint8_t key_be[BT_PUB_KEY_LEN + 1];
81 	psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
82 	psa_status_t ret;
83 	psa_key_id_t handle;
84 
85 	psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
86 	psa_set_key_bits(&attr, 256);
87 	psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DERIVE);
88 	psa_set_key_algorithm(&attr, PSA_ALG_ECDH);
89 
90 	/* PSA expects secp256r1 public key to start with a predefined 0x04 byte */
91 	key_be[0] = 0x04;
92 	sys_memcpy_swap(&key_be[1], key, BT_PUB_KEY_COORD_LEN);
93 	sys_memcpy_swap(&key_be[1 + BT_PUB_KEY_COORD_LEN], &key[BT_PUB_KEY_COORD_LEN],
94 			BT_PUB_KEY_COORD_LEN);
95 
96 	ret = psa_import_key(&attr, key_be, sizeof(key_be), &handle);
97 	psa_reset_key_attributes(&attr);
98 
99 	if (ret == PSA_SUCCESS) {
100 		psa_destroy_key(handle);
101 		return true;
102 	}
103 
104 	LOG_ERR("psa_import_key() returned status %d", ret);
105 	return false;
106 }
107 
set_key_attributes(psa_key_attributes_t * attr)108 static void set_key_attributes(psa_key_attributes_t *attr)
109 {
110 	psa_set_key_type(attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
111 	psa_set_key_bits(attr, 256);
112 	psa_set_key_usage_flags(attr, PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_DERIVE);
113 	psa_set_key_algorithm(attr, PSA_ALG_ECDH);
114 }
115 
generate_pub_key(struct k_work * work)116 static void generate_pub_key(struct k_work *work)
117 {
118 	psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
119 	struct bt_pub_key_cb *cb;
120 	psa_key_id_t key_id;
121 	uint8_t tmp_pub_key_buf[BT_PUB_KEY_LEN + 1];
122 	size_t tmp_len;
123 	int err;
124 	psa_status_t ret;
125 
126 	set_key_attributes(&attr);
127 
128 	ret = psa_generate_key(&attr, &key_id);
129 	if (ret != PSA_SUCCESS) {
130 		LOG_ERR("Failed to generate ECC key %d", ret);
131 		err = BT_HCI_ERR_UNSPECIFIED;
132 		goto done;
133 	}
134 
135 	ret = psa_export_public_key(key_id, tmp_pub_key_buf, sizeof(tmp_pub_key_buf), &tmp_len);
136 	if (ret != PSA_SUCCESS) {
137 		LOG_ERR("Failed to export ECC public key %d", ret);
138 		err = BT_HCI_ERR_UNSPECIFIED;
139 		goto done;
140 	}
141 	/* secp256r1 PSA exported public key has an extra 0x04 predefined byte at
142 	 * the beginning of the buffer which is not part of the coordinate so
143 	 * we remove that.
144 	 */
145 	memcpy(ecc.public_key_be, &tmp_pub_key_buf[1], BT_PUB_KEY_LEN);
146 
147 	ret = psa_export_key(key_id, ecc.private_key_be, BT_PRIV_KEY_LEN, &tmp_len);
148 	if (ret != PSA_SUCCESS) {
149 		LOG_ERR("Failed to export ECC private key %d", ret);
150 		err = BT_HCI_ERR_UNSPECIFIED;
151 		goto done;
152 	}
153 
154 	ret = psa_destroy_key(key_id);
155 	if (ret != PSA_SUCCESS) {
156 		LOG_ERR("Failed to destroy ECC key ID %d", ret);
157 		err = BT_HCI_ERR_UNSPECIFIED;
158 		goto done;
159 	}
160 
161 	sys_memcpy_swap(pub_key, ecc.public_key_be, BT_PUB_KEY_COORD_LEN);
162 	sys_memcpy_swap(&pub_key[BT_PUB_KEY_COORD_LEN],
163 			&ecc.public_key_be[BT_PUB_KEY_COORD_LEN], BT_PUB_KEY_COORD_LEN);
164 
165 	atomic_set_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY);
166 	err = 0;
167 
168 done:
169 	atomic_clear_bit(flags, PENDING_PUB_KEY);
170 
171 	/* Change to cooperative priority while we do the callbacks */
172 	k_sched_lock();
173 
174 	SYS_SLIST_FOR_EACH_CONTAINER(&pub_key_cb_slist, cb, node) {
175 		if (cb->func) {
176 			cb->func(err ? NULL : pub_key);
177 		}
178 	}
179 
180 	sys_slist_init(&pub_key_cb_slist);
181 
182 	k_sched_unlock();
183 }
184 
generate_dh_key(struct k_work * work)185 static void generate_dh_key(struct k_work *work)
186 {
187 	int err;
188 
189 	psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
190 	psa_key_id_t key_id;
191 	psa_status_t ret;
192 	/* PSA expects secp256r1 public key to start with a predefined 0x04 byte
193 	 * at the beginning the buffer.
194 	 */
195 	uint8_t tmp_pub_key_buf[BT_PUB_KEY_LEN + 1] = { 0x04 };
196 	size_t tmp_len;
197 
198 	set_key_attributes(&attr);
199 
200 	const uint8_t *priv_key = (IS_ENABLED(CONFIG_BT_USE_DEBUG_KEYS) ?
201 				   debug_private_key_be :
202 				   ecc.private_key_be);
203 	ret = psa_import_key(&attr, priv_key, BT_PRIV_KEY_LEN, &key_id);
204 	if (ret != PSA_SUCCESS) {
205 		err = -EIO;
206 		LOG_ERR("Failed to import the private key for key agreement %d", ret);
207 		goto exit;
208 	}
209 
210 	memcpy(&tmp_pub_key_buf[1], ecc.public_key_be, BT_PUB_KEY_LEN);
211 	ret = psa_raw_key_agreement(PSA_ALG_ECDH, key_id, tmp_pub_key_buf, sizeof(tmp_pub_key_buf),
212 				    ecc.dhkey_be, BT_DH_KEY_LEN, &tmp_len);
213 	if (ret != PSA_SUCCESS) {
214 		err = -EIO;
215 		LOG_ERR("Raw key agreement failed %d", ret);
216 		goto exit;
217 	}
218 
219 	ret = psa_destroy_key(key_id);
220 	if (ret != PSA_SUCCESS) {
221 		LOG_ERR("Failed to destroy the key %d", ret);
222 		err = -EIO;
223 		goto exit;
224 	}
225 
226 	err = 0;
227 
228 exit:
229 	/* Change to cooperative priority while we do the callback */
230 	k_sched_lock();
231 
232 	if (dh_key_cb) {
233 		bt_dh_key_cb_t cb = dh_key_cb;
234 
235 		dh_key_cb = NULL;
236 		atomic_clear_bit(flags, PENDING_DHKEY);
237 
238 		if (err) {
239 			cb(NULL);
240 		} else {
241 			uint8_t dhkey[BT_DH_KEY_LEN];
242 
243 			sys_memcpy_swap(dhkey, ecc.dhkey_be, sizeof(ecc.dhkey_be));
244 			cb(dhkey);
245 		}
246 	}
247 
248 	k_sched_unlock();
249 }
250 
bt_pub_key_gen(struct bt_pub_key_cb * new_cb)251 int bt_pub_key_gen(struct bt_pub_key_cb *new_cb)
252 {
253 	struct bt_pub_key_cb *cb;
254 
255 	if (IS_ENABLED(CONFIG_BT_USE_DEBUG_KEYS)) {
256 		atomic_set_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY);
257 		__ASSERT_NO_MSG(new_cb->func != NULL);
258 		new_cb->func(debug_public_key);
259 		return 0;
260 	}
261 
262 	if (!new_cb) {
263 		return -EINVAL;
264 	}
265 
266 	SYS_SLIST_FOR_EACH_CONTAINER(&pub_key_cb_slist, cb, node) {
267 		if (cb == new_cb) {
268 			LOG_DBG("Callback already registered");
269 			return -EALREADY;
270 		}
271 	}
272 
273 	if (atomic_test_bit(flags, PENDING_DHKEY)) {
274 		LOG_WRN("Busy performing another ECDH operation");
275 		return -EBUSY;
276 	}
277 
278 	sys_slist_prepend(&pub_key_cb_slist, &new_cb->node);
279 
280 	if (atomic_test_and_set_bit(flags, PENDING_PUB_KEY)) {
281 		return 0;
282 	}
283 
284 	atomic_clear_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY);
285 
286 	if (IS_ENABLED(CONFIG_BT_LONG_WQ)) {
287 		bt_long_wq_submit(&pub_key_work);
288 	} else {
289 		k_work_submit(&pub_key_work);
290 	}
291 
292 	return 0;
293 }
294 
bt_pub_key_hci_disrupted(void)295 void bt_pub_key_hci_disrupted(void)
296 {
297 	struct bt_pub_key_cb *cb;
298 
299 	atomic_clear_bit(flags, PENDING_PUB_KEY);
300 
301 	SYS_SLIST_FOR_EACH_CONTAINER(&pub_key_cb_slist, cb, node) {
302 		if (cb->func) {
303 			cb->func(NULL);
304 		}
305 	}
306 
307 	sys_slist_init(&pub_key_cb_slist);
308 }
309 
bt_pub_key_get(void)310 const uint8_t *bt_pub_key_get(void)
311 {
312 	if (IS_ENABLED(CONFIG_BT_USE_DEBUG_KEYS)) {
313 		return debug_public_key;
314 	}
315 
316 	if (atomic_test_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY)) {
317 		return pub_key;
318 	}
319 
320 	return NULL;
321 }
322 
bt_dh_key_gen(const uint8_t remote_pk[BT_PUB_KEY_LEN],bt_dh_key_cb_t cb)323 int bt_dh_key_gen(const uint8_t remote_pk[BT_PUB_KEY_LEN], bt_dh_key_cb_t cb)
324 {
325 	if (dh_key_cb == cb) {
326 		return -EALREADY;
327 	}
328 
329 	if (!atomic_test_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY)) {
330 		return -EADDRNOTAVAIL;
331 	}
332 
333 	if (dh_key_cb ||
334 	    atomic_test_bit(flags, PENDING_PUB_KEY) ||
335 	    atomic_test_and_set_bit(flags, PENDING_DHKEY)) {
336 		return -EBUSY;
337 	}
338 
339 	dh_key_cb = cb;
340 
341 	/* Convert X and Y coordinates from little-endian to
342 	 * big-endian (expected by the crypto API).
343 	 */
344 	sys_memcpy_swap(ecc.public_key_be, remote_pk, BT_PUB_KEY_COORD_LEN);
345 	sys_memcpy_swap(&ecc.public_key_be[BT_PUB_KEY_COORD_LEN],
346 			&remote_pk[BT_PUB_KEY_COORD_LEN], BT_PUB_KEY_COORD_LEN);
347 
348 	if (IS_ENABLED(CONFIG_BT_LONG_WQ)) {
349 		bt_long_wq_submit(&dh_key_work);
350 	} else {
351 		k_work_submit(&dh_key_work);
352 	}
353 
354 	return 0;
355 }
356 
357 #ifdef ZTEST_UNITTEST
bt_ecc_get_public_key(void)358 uint8_t const *bt_ecc_get_public_key(void)
359 {
360 	return pub_key;
361 }
362 
bt_ecc_get_internal_debug_public_key(void)363 uint8_t const *bt_ecc_get_internal_debug_public_key(void)
364 {
365 	return debug_public_key;
366 }
367 
bt_ecc_get_pub_key_cb_slist(void)368 sys_slist_t *bt_ecc_get_pub_key_cb_slist(void)
369 {
370 	return &pub_key_cb_slist;
371 }
372 
bt_ecc_get_dh_key_cb(void)373 bt_dh_key_cb_t *bt_ecc_get_dh_key_cb(void)
374 {
375 	return &dh_key_cb;
376 }
377 #endif /* ZTEST_UNITTEST */
378