Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ 1/2] smp-tester: Expect the identity key in Pairing Requests
@ 2026-10-24 11:25 Brandon Williams
  2026-10-24 11:25 ` [PATCH BlueZ 2/2] smp-tester: Add identity key distribution tests Brandon Williams
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Brandon Williams @ 2026-10-24 11:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Brandon Williams

The kernel distributes its identity address whenever it bonds over LE
("Bluetooth: SMP: distribute the identity address when bonding"), so
its Pairing Requests set IdKey in the initiator key distribution.

Assisted-by: Claude:claude-opus-5-5
---

Notes:
    These go with the kernel series "[PATCH 0/2] Bluetooth: SMP: distribute
    the identity address when bonding", sent to this list. Against
    bluetooth-next 47d4d9f67e92 under QEMU (arm64, TCG): without the kernel
    patches the four client tests updated here and both new tests fail;
    with them smp-tester passes 10/10 in each of 10 runs. make check passes.
    
    Tool use: written with an AI coding assistant (Claude Code, Claude
    Opus 5.5) together with the kernel series; see its cover letter.
    
    I read both test changes, including why the keys the kernel distributes
    are not compared, and ran the device tests described in the kernel cover
    letter myself.

 tools/smp-tester.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/smp-tester.c b/tools/smp-tester.c
index 581f3a233..cde1211af 100644
--- a/tools/smp-tester.c
+++ b/tools/smp-tester.c
@@ -327,7 +327,7 @@ static const uint8_t smp_basic_req_1[] = {	0x01,	/* Pairing Request */
 						0x00,	/* OOB Flag */
 						0x01,	/* Bonding - no MITM */
 						0x10,	/* Max key size */
-						0x05,	/* Init. key dist. */
+						0x07,	/* Init. key dist. */
 						0x05,	/* Rsp. key dist. */
 };
 static const uint8_t smp_basic_req_1_rsp[] = {	0x02,	/* Pairing Response */
@@ -375,7 +375,7 @@ static const uint8_t smp_basic_req_2[] = {	0x01,	/* Pairing Request */
 						0x00,	/* OOB Flag */
 						0x05,	/* Bonding - MITM */
 						0x10,	/* Max key size */
-						0x05,	/* Init. key dist. */
+						0x07,	/* Init. key dist. */
 						0x05,	/* Rsp. key dist. */
 };
 
@@ -414,7 +414,7 @@ static const uint8_t smp_sc_req_1[] = {	0x01,	/* Pairing Request */
 					0x00,	/* OOB Flag */
 					0x29,	/* Bonding - no MITM, SC, CT2 */
 					0x10,	/* Max key size */
-					0x0d,	/* Init. key dist. */
+					0x0f,	/* Init. key dist. */
 					0x0d,	/* Rsp. key dist. */
 };
 
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH BlueZ 2/2] smp-tester: Add identity key distribution tests
  2026-10-24 11:25 [PATCH BlueZ 1/2] smp-tester: Expect the identity key in Pairing Requests Brandon Williams
@ 2026-10-24 11:25 ` Brandon Williams
  2026-10-24 14:16 ` [BlueZ,1/2] smp-tester: Expect the identity key in Pairing Requests bluez.test.bot
  2026-10-26 17:23 ` [PATCH BlueZ 1/2] " Brandon Williams
  2 siblings, 0 replies; 4+ messages in thread
From: Brandon Williams @ 2026-10-24 11:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Brandon Williams

Add server tests where the kernel bonds without privacy:

- Identity Key 1: the kernel distributes an all-zero IRK and the
  controller's identity address when the initiator asks for its
  identity key.
- Identity Key 2: the kernel does not store an all-zero IRK from the
  initiator and still completes bonding.

These need the kernel patches "Bluetooth: SMP: distribute the identity
address when bonding" and "Bluetooth: SMP: ignore an all-zero IRK".

The keys distributed by the kernel are random, so they are not compared,
and request list entries can now only wait for a PDU.

Assisted-by: Claude:claude-opus-5-5
---
 tools/smp-tester.c | 177 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 174 insertions(+), 3 deletions(-)

diff --git a/tools/smp-tester.c b/tools/smp-tester.c
index cde1211af..1f66bf54a 100644
--- a/tools/smp-tester.c
+++ b/tools/smp-tester.c
@@ -62,6 +62,7 @@ struct test_data {
 	uint8_t local_sk[32];
 	uint8_t dhkey[32];
 	int unmet_conditions;
+	unsigned int new_ltk_id;
 };
 
 struct smp_req_rsp {
@@ -80,6 +81,8 @@ struct smp_data {
 	uint8_t expect_hci_len;
 	const void * (*expect_hci_func)(uint8_t *len);
 	bool sc;
+	bool load_irks;
+	bool expect_no_irk;
 };
 
 static void print_debug(const char *str, void *user_data)
@@ -459,6 +462,93 @@ static const struct smp_data smp_client_sc_req_2_test = {
 	.sc = true,
 };
 
+static const uint8_t smp_enc_info[17] = { 0x06 };
+static const uint8_t smp_central_ident[11] = { 0x07 };
+static const uint8_t smp_ident_info_zero[17] = { 0x08 };
+static const uint8_t smp_ident_addr_info[8] = { 0x09 };
+static const uint8_t smp_sign_info[17] = { 0x0a };
+
+static const uint8_t smp_id_req_1[] = {	0x01,	/* Pairing Request */
+					0x03,	/* NoInputNoOutput */
+					0x00,	/* OOB Flag */
+					0x01,	/* Bonding - no MITM */
+					0x10,	/* Max key size */
+					0x05,	/* Init. key dist. */
+					0x07,	/* Rsp. key dist. */
+};
+static const uint8_t smp_id_req_1_rsp[] = {	0x02,	/* Pairing Response */
+						0x03,	/* NoInputNoOutput */
+						0x00,	/* OOB Flag */
+						0x01,	/* Bonding - no MITM */
+						0x10,	/* Max key size */
+						0x05,	/* Init. key dist. */
+						0x07,	/* Rsp. key dist. */
+};
+
+/* Without privacy the identity key is an all-zero IRK and the identity
+ * address of the controller.
+ */
+static const struct smp_req_rsp srv_id_req_1[] = {
+	{ smp_id_req_1, sizeof(smp_id_req_1),
+			smp_id_req_1_rsp, sizeof(smp_id_req_1_rsp) },
+	{ smp_confirm_req_1, sizeof(smp_confirm_req_1),
+			smp_confirm_req_1, sizeof(smp_confirm_req_1) },
+	{ smp_random_req_1, sizeof(smp_random_req_1),
+			smp_random_req_1, sizeof(smp_random_req_1) },
+	{ NULL, 0, smp_enc_info, sizeof(smp_enc_info) },
+	{ NULL, 0, smp_central_ident, sizeof(smp_central_ident) },
+	{ NULL, 0, smp_ident_info_zero, sizeof(smp_ident_info_zero) },
+	{ NULL, 0, smp_ident_addr_info, sizeof(smp_ident_addr_info) },
+	{ NULL, 0, smp_sign_info, sizeof(smp_sign_info) },
+};
+
+static const struct smp_data smp_server_id_req_1_test = {
+	.req = srv_id_req_1,
+	.req_count = G_N_ELEMENTS(srv_id_req_1),
+};
+
+static const uint8_t smp_id_req_2[] = {	0x01,	/* Pairing Request */
+					0x03,	/* NoInputNoOutput */
+					0x00,	/* OOB Flag */
+					0x01,	/* Bonding - no MITM */
+					0x10,	/* Max key size */
+					0x07,	/* Init. key dist. */
+					0x05,	/* Rsp. key dist. */
+};
+static const uint8_t smp_id_req_2_rsp[] = {	0x02,	/* Pairing Response */
+						0x03,	/* NoInputNoOutput */
+						0x00,	/* OOB Flag */
+						0x01,	/* Bonding - no MITM */
+						0x10,	/* Max key size */
+						0x07,	/* Init. key dist. */
+						0x05,	/* Rsp. key dist. */
+};
+
+/* An all-zero IRK resolves no address, so it must not be stored */
+static const struct smp_req_rsp srv_id_req_2[] = {
+	{ smp_id_req_2, sizeof(smp_id_req_2),
+			smp_id_req_2_rsp, sizeof(smp_id_req_2_rsp) },
+	{ smp_confirm_req_1, sizeof(smp_confirm_req_1),
+			smp_confirm_req_1, sizeof(smp_confirm_req_1) },
+	{ smp_random_req_1, sizeof(smp_random_req_1),
+			smp_random_req_1, sizeof(smp_random_req_1) },
+	{ NULL, 0, smp_enc_info, sizeof(smp_enc_info) },
+	{ NULL, 0, smp_central_ident, sizeof(smp_central_ident) },
+	{ NULL, 0, smp_sign_info, sizeof(smp_sign_info) },
+	{ smp_enc_info, sizeof(smp_enc_info), NULL, 0 },
+	{ smp_central_ident, sizeof(smp_central_ident), NULL, 0 },
+	{ smp_ident_info_zero, sizeof(smp_ident_info_zero), NULL, 0 },
+	{ smp_ident_addr_info, sizeof(smp_ident_addr_info), NULL, 0 },
+	{ smp_sign_info, sizeof(smp_sign_info), NULL, 0 },
+};
+
+static const struct smp_data smp_server_id_req_2_test = {
+	.req = srv_id_req_2,
+	.req_count = G_N_ELEMENTS(srv_id_req_2),
+	.load_irks = true,
+	.expect_no_irk = true,
+};
+
 static void client_connectable_complete(uint16_t opcode, uint8_t status,
 					const void *param, uint8_t len,
 					void *user_data)
@@ -578,6 +668,16 @@ static const void *get_pdu(const uint8_t *pdu, size_t len)
 		buf[0] = pdu[0];
 		memcpy(&buf[1], data->prnd, 16);
 		return buf;
+	case 0x09: /* Identity Address Information */
+		buf[0] = pdu[0];
+		if (data->out) {
+			buf[1] = data->ia_type;
+			memcpy(&buf[2], data->ia, 6);
+		} else {
+			buf[1] = data->ra_type;
+			memcpy(&buf[2], data->ra, 6);
+		}
+		return buf;
 	case 0x0c: /* Public Key */
 		buf[0] = pdu[0];
 		memcpy(&buf[1], data->local_pk, 64);
@@ -589,6 +689,20 @@ static const void *get_pdu(const uint8_t *pdu, size_t len)
 	return pdu;
 }
 
+static bool verify_ident_addr(const uint8_t *pdu)
+{
+	struct test_data *data = tester_get_data();
+	const uint8_t *addr = data->out ? data->ra : data->ia;
+	uint8_t addr_type = data->out ? data->ra_type : data->ia_type;
+
+	if (pdu[1] != addr_type || memcmp(&pdu[2], addr, 6)) {
+		tester_warn("Unexpected identity address");
+		return false;
+	}
+
+	return true;
+}
+
 static bool verify_random(const uint8_t rnd[16])
 {
 	struct test_data *data = tester_get_data();
@@ -680,6 +794,15 @@ static void smp_server(const void *data, uint16_t len, void *user_data)
 		ecdh_shared_secret(test_data->remote_pk, test_data->local_sk,
 							test_data->dhkey);
 		goto next;
+	case 0x06: /* Encryption Information */
+	case 0x07: /* Central Identification */
+	case 0x0a: /* Signing Information */
+		/* The keys are random */
+		goto next;
+	case 0x09: /* Identity Address Information */
+		if (!verify_ident_addr(data))
+			goto failed;
+		goto next;
 	default:
 		break;
 	}
@@ -698,9 +821,12 @@ next:
 
 		req = &smp->req[test_data->counter];
 
-		pdu = get_pdu(req->send, req->send_len);
-		bthost_send_cid(bthost, test_data->handle, SMP_CID, pdu,
-								req->send_len);
+		if (req->send) {
+			pdu = get_pdu(req->send, req->send_len);
+			bthost_send_cid(bthost, test_data->handle, SMP_CID,
+							pdu, req->send_len);
+		}
+
 		if (req->expect)
 			break;
 		else
@@ -871,6 +997,16 @@ static void setup_powered_server(const void *test_data)
 				sizeof(param), param, NULL, NULL, NULL);
 	mgmt_send(data->mgmt, MGMT_OP_SET_ADVERTISING, data->mgmt_index,
 				sizeof(param), param, NULL, NULL, NULL);
+	if (smp->load_irks) {
+		struct mgmt_cp_load_irks cp;
+
+		/* Loading IRKs, as bluetoothd does, makes the kernel accept
+		 * identity keys from the remote device.
+		 */
+		memset(&cp, 0, sizeof(cp));
+		mgmt_send(data->mgmt, MGMT_OP_LOAD_IRKS, data->mgmt_index,
+				sizeof(cp), &cp, NULL, NULL, NULL);
+	}
 	if (smp->sc) {
 		mgmt_send(data->mgmt, MGMT_OP_SET_SECURE_CONN,
 				data->mgmt_index, sizeof(param), param, NULL,
@@ -883,6 +1019,25 @@ static void setup_powered_server(const void *test_data)
 			NULL, NULL);
 }
 
+static void new_irk_callback(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	tester_warn("Unexpected New IRK event");
+	tester_test_failed();
+}
+
+static void new_ltk_callback(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = user_data;
+
+	/* The kernel reports a new IRK before the new LTKs */
+	tester_print("New LTK event");
+
+	mgmt_unregister(data->mgmt, data->new_ltk_id);
+	test_condition_complete(data);
+}
+
 static void test_server(const void *test_data)
 {
 	struct test_data *data = tester_get_data();
@@ -897,6 +1052,16 @@ static void test_server(const void *test_data)
 	bthost_set_connect_cb(bthost, smp_new_conn, data);
 	test_add_condition(data);
 
+	if (smp->expect_no_irk) {
+		mgmt_register(data->mgmt, MGMT_EV_NEW_IRK, data->mgmt_index,
+					new_irk_callback, data, NULL);
+		data->new_ltk_id = mgmt_register(data->mgmt,
+					MGMT_EV_NEW_LONG_TERM_KEY,
+					data->mgmt_index, new_ltk_callback,
+					data, NULL);
+		test_add_condition(data);
+	}
+
 	bthost_hci_connect(bthost, data->ra, BDADDR_LE_PUBLIC);
 
 	if (smp->expect_hci_command) {
@@ -923,6 +1088,12 @@ int main(int argc, char *argv[])
 	test_smp("SMP Server - Invalid Request 3",
 					&smp_server_nval_req_3_test,
 					setup_powered_server, test_server);
+	test_smp("SMP Server - Identity Key 1",
+					&smp_server_id_req_1_test,
+					setup_powered_server, test_server);
+	test_smp("SMP Server - Identity Key 2",
+					&smp_server_id_req_2_test,
+					setup_powered_server, test_server);
 
 	test_smp("SMP Client - Basic Request 1",
 					&smp_client_basic_req_1_test,
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* RE: [BlueZ,1/2] smp-tester: Expect the identity key in Pairing Requests
  2026-10-24 11:25 [PATCH BlueZ 1/2] smp-tester: Expect the identity key in Pairing Requests Brandon Williams
  2026-10-24 11:25 ` [PATCH BlueZ 2/2] smp-tester: Add identity key distribution tests Brandon Williams
@ 2026-10-24 14:16 ` bluez.test.bot
  2026-10-26 17:23 ` [PATCH BlueZ 1/2] " Brandon Williams
  2 siblings, 0 replies; 4+ messages in thread
From: bluez.test.bot @ 2026-10-24 14:16 UTC (permalink / raw)
  To: linux-bluetooth, turbine.bmw

[-- Attachment #1: Type: text/plain, Size: 1100 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/series/1192642/

---Test result---

Test Summary:
CheckPatch                    PASS      0.94 seconds
GitLint                       FAIL      0.58 seconds
BuildEll                      PASS      17.89 seconds
BluezMake                     PASS      264.23 seconds
CheckSmatch                   PASS      233.69 seconds
bluezmakeextell               PASS      87.41 seconds
TestFunctional                PASS      1023.40 seconds
IncrementalBuild              PASS      267.16 seconds
ScanBuild                     PASS      927.38 seconds

Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,1/2] smp-tester: Expect the identity key in Pairing Requests

16: B2 Line has trailing whitespace: "    "
19: B2 Line has trailing whitespace: "    "


https://github.com/bluez/bluez/pull/2708

---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH BlueZ 1/2] smp-tester: Expect the identity key in Pairing Requests
  2026-10-24 11:25 [PATCH BlueZ 1/2] smp-tester: Expect the identity key in Pairing Requests Brandon Williams
  2026-10-24 11:25 ` [PATCH BlueZ 2/2] smp-tester: Add identity key distribution tests Brandon Williams
  2026-10-24 14:16 ` [BlueZ,1/2] smp-tester: Expect the identity key in Pairing Requests bluez.test.bot
@ 2026-10-26 17:23 ` Brandon Williams
  2 siblings, 0 replies; 4+ messages in thread
From: Brandon Williams @ 2026-10-26 17:23 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Brandon Williams

Hi,

Withdrawn along with the kernel series it tests, please drop.

Thanks,
Brandon

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-26 17:23 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-24 11:25 [PATCH BlueZ 1/2] smp-tester: Expect the identity key in Pairing Requests Brandon Williams
2026-10-24 11:25 ` [PATCH BlueZ 2/2] smp-tester: Add identity key distribution tests Brandon Williams
2026-10-24 14:16 ` [BlueZ,1/2] smp-tester: Expect the identity key in Pairing Requests bluez.test.bot
2026-10-26 17:23 ` [PATCH BlueZ 1/2] " Brandon Williams

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox