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 "ecc.h"
17 #include "hci_core.h"
18
19 #define LOG_LEVEL CONFIG_BT_HCI_CORE_LOG_LEVEL
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(bt_ecc);
22
23 static uint8_t pub_key[BT_PUB_KEY_LEN];
24 static sys_slist_t pub_key_cb_slist;
25 static bt_dh_key_cb_t dh_key_cb;
26
27 static const uint8_t debug_public_key[BT_PUB_KEY_LEN] = {
28 /* X */
29 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
30 0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
31 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
32 0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20,
33 /* Y */
34 0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74,
35 0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76,
36 0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63,
37 0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc
38 };
39
bt_pub_key_is_debug(uint8_t * cmp_pub_key)40 bool bt_pub_key_is_debug(uint8_t *cmp_pub_key)
41 {
42 return memcmp(cmp_pub_key, debug_public_key, BT_PUB_KEY_LEN) == 0;
43 }
44
bt_pub_key_is_valid(const uint8_t key[BT_PUB_KEY_LEN])45 bool bt_pub_key_is_valid(const uint8_t key[BT_PUB_KEY_LEN])
46 {
47 uint8_t key_be[BT_PUB_KEY_LEN + 1];
48 psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
49 psa_status_t ret;
50 psa_key_id_t handle;
51
52 psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
53 psa_set_key_bits(&attr, 256);
54 psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DERIVE);
55 psa_set_key_algorithm(&attr, PSA_ALG_ECDH);
56
57 /* PSA expects secp256r1 public key to start with a predefined 0x04 byte */
58 key_be[0] = 0x04;
59 sys_memcpy_swap(&key_be[1], key, BT_PUB_KEY_COORD_LEN);
60 sys_memcpy_swap(&key_be[1 + BT_PUB_KEY_COORD_LEN], &key[BT_PUB_KEY_COORD_LEN],
61 BT_PUB_KEY_COORD_LEN);
62
63 ret = psa_import_key(&attr, key_be, sizeof(key_be), &handle);
64 psa_reset_key_attributes(&attr);
65
66 if (ret == PSA_SUCCESS) {
67 psa_destroy_key(handle);
68 return true;
69 }
70
71 return false;
72 }
73
bt_pub_key_gen(struct bt_pub_key_cb * new_cb)74 int bt_pub_key_gen(struct bt_pub_key_cb *new_cb)
75 {
76 struct bt_pub_key_cb *cb;
77 int err;
78
79 /*
80 * We check for both "LE Read Local P-256 Public Key" and
81 * "LE Generate DH Key" support here since both commands are needed for
82 * ECC support. If "LE Generate DH Key" is not supported then there
83 * is no point in reading local public key.
84 */
85 if (!BT_CMD_TEST(bt_dev.supported_commands, 34, 1) ||
86 !BT_CMD_TEST(bt_dev.supported_commands, 34, 2)) {
87 LOG_WRN("ECC HCI commands not available");
88 return -ENOTSUP;
89 }
90
91 if (IS_ENABLED(CONFIG_BT_USE_DEBUG_KEYS)) {
92 if (!BT_CMD_TEST(bt_dev.supported_commands, 41, 2)) {
93 LOG_WRN("ECC Debug keys HCI command not available");
94 } else {
95 atomic_set_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY);
96 __ASSERT_NO_MSG(new_cb->func != NULL);
97 new_cb->func(debug_public_key);
98 return 0;
99 }
100 }
101
102 if (!new_cb) {
103 return -EINVAL;
104 }
105
106 SYS_SLIST_FOR_EACH_CONTAINER(&pub_key_cb_slist, cb, node) {
107 if (cb == new_cb) {
108 LOG_WRN("Callback already registered");
109 return -EALREADY;
110 }
111 }
112
113 sys_slist_prepend(&pub_key_cb_slist, &new_cb->node);
114
115 if (atomic_test_and_set_bit(bt_dev.flags, BT_DEV_PUB_KEY_BUSY)) {
116 return 0;
117 }
118
119 atomic_clear_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY);
120
121 err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_P256_PUBLIC_KEY, NULL, NULL);
122 if (err) {
123
124 LOG_ERR("Sending LE P256 Public Key command failed");
125 atomic_clear_bit(bt_dev.flags, BT_DEV_PUB_KEY_BUSY);
126
127 SYS_SLIST_FOR_EACH_CONTAINER(&pub_key_cb_slist, cb, node) {
128 if (cb->func) {
129 cb->func(NULL);
130 }
131 }
132
133 sys_slist_init(&pub_key_cb_slist);
134 return err;
135 }
136
137 return 0;
138 }
139
bt_pub_key_hci_disrupted(void)140 void bt_pub_key_hci_disrupted(void)
141 {
142 struct bt_pub_key_cb *cb;
143
144 atomic_clear_bit(bt_dev.flags, BT_DEV_PUB_KEY_BUSY);
145
146 SYS_SLIST_FOR_EACH_CONTAINER(&pub_key_cb_slist, cb, node) {
147 if (cb->func) {
148 cb->func(NULL);
149 }
150 }
151
152 sys_slist_init(&pub_key_cb_slist);
153 }
154
bt_pub_key_get(void)155 const uint8_t *bt_pub_key_get(void)
156 {
157 if (IS_ENABLED(CONFIG_BT_USE_DEBUG_KEYS) &&
158 BT_CMD_TEST(bt_dev.supported_commands, 41, 2)) {
159 return debug_public_key;
160 }
161
162 if (atomic_test_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY)) {
163 return pub_key;
164 }
165
166 return NULL;
167 }
168
hci_generate_dhkey_v1(const uint8_t * remote_pk)169 static int hci_generate_dhkey_v1(const uint8_t *remote_pk)
170 {
171 struct bt_hci_cp_le_generate_dhkey *cp;
172 struct net_buf *buf;
173
174 buf = bt_hci_cmd_create(BT_HCI_OP_LE_GENERATE_DHKEY, sizeof(*cp));
175 if (!buf) {
176 return -ENOBUFS;
177 }
178
179 cp = net_buf_add(buf, sizeof(*cp));
180 memcpy(cp->key, remote_pk, sizeof(cp->key));
181
182 return bt_hci_cmd_send_sync(BT_HCI_OP_LE_GENERATE_DHKEY, buf, NULL);
183 }
184
hci_generate_dhkey_v2(const uint8_t * remote_pk,uint8_t key_type)185 static int hci_generate_dhkey_v2(const uint8_t *remote_pk, uint8_t key_type)
186 {
187 struct bt_hci_cp_le_generate_dhkey_v2 *cp;
188 struct net_buf *buf;
189
190 buf = bt_hci_cmd_create(BT_HCI_OP_LE_GENERATE_DHKEY_V2, sizeof(*cp));
191 if (!buf) {
192 return -ENOBUFS;
193 }
194
195 cp = net_buf_add(buf, sizeof(*cp));
196 memcpy(cp->key, remote_pk, sizeof(cp->key));
197 cp->key_type = key_type;
198
199 return bt_hci_cmd_send_sync(BT_HCI_OP_LE_GENERATE_DHKEY_V2, buf, NULL);
200 }
201
bt_dh_key_gen(const uint8_t remote_pk[BT_PUB_KEY_LEN],bt_dh_key_cb_t cb)202 int bt_dh_key_gen(const uint8_t remote_pk[BT_PUB_KEY_LEN], bt_dh_key_cb_t cb)
203 {
204 int err;
205
206 if (dh_key_cb == cb) {
207 return -EALREADY;
208 }
209
210 if (dh_key_cb || atomic_test_bit(bt_dev.flags, BT_DEV_PUB_KEY_BUSY)) {
211 return -EBUSY;
212 }
213
214 if (!atomic_test_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY)) {
215 return -EADDRNOTAVAIL;
216 }
217
218 dh_key_cb = cb;
219
220 if (IS_ENABLED(CONFIG_BT_USE_DEBUG_KEYS) &&
221 BT_CMD_TEST(bt_dev.supported_commands, 41, 2)) {
222 err = hci_generate_dhkey_v2(remote_pk,
223 BT_HCI_LE_KEY_TYPE_DEBUG);
224 } else {
225 err = hci_generate_dhkey_v1(remote_pk);
226 }
227
228 if (err) {
229 dh_key_cb = NULL;
230 LOG_WRN("Failed to generate DHKey (err %d)", err);
231 return err;
232 }
233
234 return 0;
235 }
236
bt_hci_evt_le_pkey_complete(struct net_buf * buf)237 void bt_hci_evt_le_pkey_complete(struct net_buf *buf)
238 {
239 struct bt_hci_evt_le_p256_public_key_complete *evt = (void *)buf->data;
240 struct bt_pub_key_cb *cb;
241
242 LOG_DBG("status: 0x%02x %s", evt->status, bt_hci_err_to_str(evt->status));
243
244 atomic_clear_bit(bt_dev.flags, BT_DEV_PUB_KEY_BUSY);
245
246 if (!evt->status) {
247 memcpy(pub_key, evt->key, BT_PUB_KEY_LEN);
248 atomic_set_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY);
249 }
250
251 SYS_SLIST_FOR_EACH_CONTAINER(&pub_key_cb_slist, cb, node) {
252 if (cb->func) {
253 cb->func(evt->status ? NULL : pub_key);
254 }
255 }
256
257 sys_slist_init(&pub_key_cb_slist);
258 }
259
bt_hci_evt_le_dhkey_complete(struct net_buf * buf)260 void bt_hci_evt_le_dhkey_complete(struct net_buf *buf)
261 {
262 struct bt_hci_evt_le_generate_dhkey_complete *evt = (void *)buf->data;
263
264 LOG_DBG("status: 0x%02x %s", evt->status, bt_hci_err_to_str(evt->status));
265
266 if (dh_key_cb) {
267 bt_dh_key_cb_t cb = dh_key_cb;
268
269 dh_key_cb = NULL;
270 cb(evt->status ? NULL : evt->dhkey);
271 }
272 }
273
274 #ifdef ZTEST_UNITTEST
bt_ecc_get_public_key(void)275 uint8_t const *bt_ecc_get_public_key(void)
276 {
277 return pub_key;
278 }
279
bt_ecc_get_internal_debug_public_key(void)280 uint8_t const *bt_ecc_get_internal_debug_public_key(void)
281 {
282 return debug_public_key;
283 }
284
bt_ecc_get_pub_key_cb_slist(void)285 sys_slist_t *bt_ecc_get_pub_key_cb_slist(void)
286 {
287 return &pub_key_cb_slist;
288 }
289
bt_ecc_get_dh_key_cb(void)290 bt_dh_key_cb_t *bt_ecc_get_dh_key_cb(void)
291 {
292 return &dh_key_cb;
293 }
294 #endif /* ZTEST_UNITTEST */
295