lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251118142025.1982263-7-neeraj.sanjaykale@nxp.com>
Date: Tue, 18 Nov 2025 19:50:19 +0530
From: Neeraj Sanjay Kale <neeraj.sanjaykale@....com>
To: marcel@...tmann.org,
	luiz.dentz@...il.com
Cc: linux-bluetooth@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	amitkumar.karwar@....com,
	sherry.sun@....com,
	dmitrii.lebed@....com,
	neeraj.sanjaykale@....com
Subject: [PATCH v1 06/11] Bluetooth: btnxpuart: Add TLS device hello processing

This implements device hello message processing to derive handshake
traffic secrets:

- Add HKDF-SHA256 functions for TLS 1.3 traffic secret derivation
  following RFC 5869/8446
- Extract device ECDH public key and compute shared secret using
  KPP API with host private key and device public key
- Derive handshake traffic secret from ECDH shared secret
  following TLS 1.3 key schedule
- Validate device hello message and update handshake hash state

The handshake traffic secret enables decryption of the
device_finish portion within the device_hello message.

Signed-off-by: Neeraj Sanjay Kale <neeraj.sanjaykale@....com>
---
 drivers/bluetooth/btnxpuart.c | 274 +++++++++++++++++++++++++++++++++-
 1 file changed, 270 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index 44073eae0df3..3bff7758fa5e 100644
--- a/drivers/bluetooth/btnxpuart.c
+++ b/drivers/bluetooth/btnxpuart.c
@@ -150,8 +150,9 @@
 #define FW_METADATA_TLV_ECDSA_KEY	0x50
 #define FW_METADATA_FLAG_BT		0x02
 
-#define NXP_FW_UUID_SIZE           16
-#define NXP_FW_ECDSA_PUBKEY_SIZE   65
+#define NXP_FW_UUID_SIZE		16
+#define NXP_FW_ECDH_PUBKEY_SIZE		64
+#define NXP_FW_ECDSA_PUBKEY_SIZE	65
 
 struct ps_data {
 	u8    target_ps_mode;	/* ps mode to be set */
@@ -203,8 +204,11 @@ struct btnxpuart_crypto {
 	struct crypto_shash *tls_handshake_hash_tfm;
 	struct shash_desc *tls_handshake_hash_desc;
 	struct crypto_kpp *kpp;
+	uint8_t ecdh_public[NXP_FW_ECDH_PUBKEY_SIZE];	/* ECDH public key, Key negotiation */
 	u8 ecdsa_public[NXP_FW_ECDSA_PUBKEY_SIZE];	/* ECDSA public key, Authentication*/
 	u8 fw_uuid[NXP_FW_UUID_SIZE];
+	u8 handshake_h2_hash[SHA256_DIGEST_SIZE];
+	u8 handshake_secret[SHA256_DIGEST_SIZE];
 };
 
 struct btnxpuart_dev {
@@ -396,6 +400,11 @@ union nxp_set_bd_addr_payload {
 #define NXP_TLS_VERSION			1
 
 #define NXP_TLS_ECDH_PUBLIC_KEY_SIZE	64
+#define NXP_DEVICE_UUID_LEN		16
+#define NXP_ENC_AUTH_TAG_SIZE		16
+
+#define NXP_TLS_LABEL(str)		str, strlen(str)
+#define NXP_TLS_DEVICE_HS_TS_LABEL	NXP_TLS_LABEL("D HS TS")
 
 enum nxp_tls_signature_algorithm {
 	NXP_TLS_ECDSA_SECP256R1_SHA256 = 0x0403,
@@ -440,6 +449,38 @@ union nxp_tls_host_hello_payload {
 	u8 buf[113];
 };
 
+struct nxp_tls_device_info {
+	__le16 chip_id;
+	__le16 device_flags;
+	u8 reserved[4];
+	u8 uuid[NXP_DEVICE_UUID_LEN];
+};
+
+struct nxp_tls_signature {
+	u8 sig[64];        /* P-256 ECDSA signature, two points */
+};
+
+struct nxp_tls_finished {
+	u8 verify_data[32];
+};
+
+struct nxp_tls_device_hello {
+	struct nxp_tls_message_hdr hdr;
+	__le32 reserved;
+	u8 random[32];
+	u8 pubkey[NXP_TLS_ECDH_PUBLIC_KEY_SIZE];
+	/* Encrypted portion */
+	struct {
+		struct nxp_tls_device_info device_info;
+		struct nxp_tls_signature device_handshake_sig;   /* TLS Certificate Verify */
+		struct nxp_tls_finished device_finished;
+	} enc;
+	u8 auth_tag[NXP_ENC_AUTH_TAG_SIZE];   /* Auth tag for the encrypted portion */
+};
+
+#define DEVICE_HELLO_SIG_CUTOFF_POS \
+	offsetof(struct nxp_tls_device_hello, enc)
+
 /* FW Meta Data */
 struct fw_metadata_hdr {
 	__le32 cmd;
@@ -1698,7 +1739,7 @@ static int nxp_generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64
 }
 
 static inline void nxp_tls_hdr_init(struct nxp_tls_message_hdr *hdr, size_t len,
-				   enum nxp_tls_message_id id)
+				    enum nxp_tls_message_id id)
 {
 	hdr->magic = cpu_to_le32(NXP_TLS_MAGIC);
 	hdr->len = cpu_to_le16((u16)len);
@@ -1785,11 +1826,222 @@ static struct sk_buff *nxp_host_do_hello(struct hci_dev *hdev)
 		return skb;
 }
 
+static int nxp_crypto_shash_final(struct shash_desc *desc, u8 *out)
+{
+	struct shash_desc *desc_tmp = kzalloc(sizeof(struct shash_desc) +
+					      crypto_shash_descsize(desc->tfm),
+					      GFP_KERNEL);
+
+	if (!desc_tmp)
+		return -ENOMEM;
+
+	crypto_shash_export(desc, desc_tmp);
+	crypto_shash_final(desc, out);
+	crypto_shash_import(desc, desc_tmp);
+	kfree(desc_tmp);
+
+	return 0;
+}
+
+static int nxp_compute_shared_secret(struct crypto_kpp *tfm, const u8 public_key[64], u8 secret[32])
+{
+	DECLARE_CRYPTO_WAIT(result);
+	struct kpp_request *req;
+	struct scatterlist src, dst;
+	int err;
+
+	req = kpp_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		pr_err("Failed to allocate memory for KPP request\n");
+		return -ENOMEM;
+	}
+
+	sg_init_one(&src, public_key, 64);
+	sg_init_one(&dst, secret, 32);
+	kpp_request_set_input(req, &src, 64);
+	kpp_request_set_output(req, &dst, 32);
+	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				 crypto_req_done, &result);
+	err = crypto_kpp_compute_shared_secret(req);
+	err = crypto_wait_req(err, &result);
+	if (err < 0) {
+		pr_err("alg: ecdh: compute shared secret failed. err %d\n", err);
+		goto free_all;
+	}
+
+free_all:
+	kpp_request_free(req);
+	return err;
+}
+
+static int nxp_hkdf_sha256_extract(const void *salt, size_t salt_len,
+				    const void *ikm, size_t ikm_len,
+				    u8 result[SHA256_DIGEST_SIZE])
+{
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	u8 zeroes[SHA256_DIGEST_SIZE] = {0};
+	int ret = 0;
+
+	tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
+	if (IS_ERR(tfm))
+		return PTR_ERR(tfm);
+
+	desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
+	if (!desc) {
+		crypto_free_shash(tfm);
+		return -ENOMEM;
+	}
+
+	desc->tfm = tfm;
+
+	/* RFC 5869: If salt is empty, use HashLen zero octets */
+	if (salt_len == 0)
+		ret = crypto_shash_setkey(tfm, zeroes, SHA256_DIGEST_SIZE);
+	else
+		ret = crypto_shash_setkey(tfm, salt, salt_len);
+
+	if (ret)
+		goto cleanup;
+
+	ret = crypto_shash_init(desc);
+	if (ret)
+		goto cleanup;
+
+	ret = crypto_shash_update(desc, ikm, ikm_len);
+	if (ret)
+		goto cleanup;
+
+	ret = crypto_shash_final(desc, result);
+
+cleanup:
+	kfree(desc);
+	crypto_free_shash(tfm);
+	return ret;
+}
+
+static int nxp_hkdf_expand_label(const u8 secret[SHA256_DIGEST_SIZE],
+				 const char *label, size_t label_size,
+				 u8 *context, size_t context_size,
+				 void *output, size_t output_size)
+{
+	struct crypto_shash *tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
+	struct shash_desc *desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(tfm),
+					  GFP_KERNEL);
+	u8 hmac_out[SHA256_DIGEST_SIZE];
+	u16 length = output_size;
+	u8 one = 0x01;
+
+	if (IS_ERR(tfm)) {
+		pr_err("Failed to alloc shash for HMAC\n");
+		return -ENOMEM;
+	}
+
+	if (!desc) {
+		crypto_free_shash(tfm);
+		return -ENOMEM;
+	}
+
+	crypto_shash_setkey(tfm, secret, SHA256_DIGEST_SIZE);
+	desc->tfm = tfm;
+
+	crypto_shash_init(desc);
+	crypto_shash_update(desc, (u8 *)&length, sizeof(length));
+	crypto_shash_update(desc, label, label_size);
+
+	if (context && context_size > 0)
+		crypto_shash_update(desc, context, context_size);
+
+	/* RFC 5869: HKDF-Expand counter starts at 0x01 */
+	crypto_shash_update(desc, &one, sizeof(one));
+	crypto_shash_final(desc, hmac_out);
+
+	memcpy(output, hmac_out, output_size);
+
+	kfree(desc);
+	crypto_free_shash(tfm);
+	return 0;
+}
+
+static int nxp_hkdf_derive_secret(u8 secret[32], const char *label, size_t label_size,
+				  u8 context[SHA256_DIGEST_SIZE],
+				  u8 output[SHA256_DIGEST_SIZE])
+{
+	return nxp_hkdf_expand_label(secret, label, label_size, context, SHA256_DIGEST_SIZE,
+				     output, SHA256_DIGEST_SIZE);
+}
+
+static int nxp_process_device_hello(struct hci_dev *hdev, struct nxp_tls_device_hello *msg)
+{
+	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+	struct nxp_tls_message_hdr *hdr;
+	u8 hs_traffic_secret[SHA256_DIGEST_SIZE];
+	u8 *shared_secret = NULL;
+	int ret;
+
+	if (!msg)
+		return -EINVAL;
+
+	hdr = &msg->hdr;
+
+	if (le32_to_cpu(hdr->magic) != NXP_TLS_MAGIC ||
+	    le16_to_cpu(hdr->len) != sizeof(*msg) ||
+	    hdr->message_id != NXP_TLS_DEVICE_HELLO ||
+	    hdr->protocol_version != NXP_TLS_VERSION) {
+		bt_dev_err(hdev, "Invalid device hello header");
+		return -EINVAL;
+	}
+
+	shared_secret = kzalloc(32, GFP_KERNEL);
+	if (!shared_secret)
+		return -ENOMEM;
+
+	ret = crypto_shash_update(nxpdev->crypto.tls_handshake_hash_desc, (u8 *)msg,
+			    DEVICE_HELLO_SIG_CUTOFF_POS);
+	if (ret)
+		goto fail;
+
+	ret = nxp_crypto_shash_final(nxpdev->crypto.tls_handshake_hash_desc,
+				     nxpdev->crypto.handshake_h2_hash);
+	if (ret)
+		goto fail;
+
+	memcpy(nxpdev->crypto.ecdh_public, msg->pubkey, NXP_FW_ECDH_PUBKEY_SIZE);
+
+	ret = nxp_compute_shared_secret(nxpdev->crypto.kpp, nxpdev->crypto.ecdh_public,
+				  shared_secret);
+	if (ret)
+		goto fail;
+
+	ret = nxp_hkdf_sha256_extract(NULL, 0, shared_secret, 32,
+				      nxpdev->crypto.handshake_secret);
+	if (ret)
+		goto fail;
+
+	ret = nxp_hkdf_derive_secret(nxpdev->crypto.handshake_secret,
+				     NXP_TLS_DEVICE_HS_TS_LABEL,
+				     nxpdev->crypto.handshake_h2_hash,
+				     hs_traffic_secret);
+	if (ret)
+		goto fail;
+
+	/* TODO: Verify Signature in Device Hello using ECDSA Public Key
+	 * extracted from the FW metadata.
+	 */
+
+fail:
+	memset(shared_secret, 0, 32);
+	kfree(shared_secret);
+	return ret;
+}
+
 static int nxp_authenticate_device(struct hci_dev *hdev)
 {
 	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+	struct nxp_tls_device_hello *device_hello;
 	size_t desc_size = 0;
 	struct sk_buff *skb;
+	u8 *status;
 	int ret = 0;
 
 	nxpdev->crypto.tls_handshake_hash_tfm = crypto_alloc_shash("sha256", 0, 0);
@@ -1819,9 +2071,23 @@ static int nxp_authenticate_device(struct hci_dev *hdev)
 		goto free_kpp;
 	}
 
+	status = skb_pull_data(skb, 1);
+	if (*status)
+		goto free_skb;
+
+	if (skb->len != sizeof(struct nxp_tls_device_hello)) {
+		bt_dev_err(hdev, "Invalid Device Hello Length: %d", skb->len);
+		goto free_skb;
+	}
+
+	device_hello = skb_pull_data(skb, sizeof(*device_hello));
+	ret = nxp_process_device_hello(hdev, device_hello);
+	if (ret)
+		goto free_skb;
+
 	/* TODO: Implement actual TLS handshake protocol
 	 * This will include:
-	 * 1. Handle Device hello message exchange
+	 * 1. Send Host Finish TLS message
 	 * 2. Master secret and traffic key derivation
 	 */
 
-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ