[PATCH v1 07/11] Bluetooth: btnxpuart: Add device authentication

Neeraj Sanjay Kale posted 11 patches 1 week, 6 days ago
There is a newer version of this series
[PATCH v1 07/11] Bluetooth: btnxpuart: Add device authentication
Posted by Neeraj Sanjay Kale 1 week, 6 days ago
This implements secure device authentication during TLS 1.3-like
handshake with ECDSA signature verification.

The authentication flow:
- Derive handshake traffic secret from ECDH shared secret
- Decrypt device hello encrypted section using AES-GCM with traffic secret
- Extract ECDSA public key from firmware metadata for verification
- Verify device handshake signature to authenticate device identity
- Validate device finished message using calculated verify data
- Clear handshake traffic secret after successful authentication

This ensures only devices with valid private keys can complete the
handshake.

Key components added:
- AES-GCM encrypt/decrypt with traffic secret derived keys
- ECDSA P-256 signature verification using kernel crypto API
- X9.62 to P1363 signature format conversion
- TLS 1.3 finished message verification
- Secure memory cleanup of cryptographic material

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

diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index 3bff7758fa5e..bfe6a138d78d 100644
--- a/drivers/bluetooth/btnxpuart.c
+++ b/drivers/bluetooth/btnxpuart.c
@@ -27,6 +27,12 @@
 #include <crypto/hash.h>
 #include <crypto/kpp.h>
 #include <crypto/ecdh.h>
+#include <linux/scatterlist.h>
+#include <linux/completion.h>
+#include <crypto/aes.h>
+#include <crypto/gcm.h>
+#include <crypto/aead.h>
+#include <crypto/public_key.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -204,11 +210,13 @@ 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 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 completion completion;
+	int decrypt_result;
 };
 
 struct btnxpuart_dev {
@@ -405,6 +413,10 @@ union nxp_set_bd_addr_payload {
 
 #define NXP_TLS_LABEL(str)		str, strlen(str)
 #define NXP_TLS_DEVICE_HS_TS_LABEL	NXP_TLS_LABEL("D HS TS")
+#define NXP_TLS_KEYING_IV_LABEL		NXP_TLS_LABEL("iv")
+#define NXP_TLS_KEYING_KEY_LABEL	NXP_TLS_LABEL("key")
+#define NXP_TLS_FINISHED_LABEL		NXP_TLS_LABEL("finished")
+#define NXP_TLS_HOST_HS_TS_LABEL	NXP_TLS_LABEL("H HS TS")
 
 enum nxp_tls_signature_algorithm {
 	NXP_TLS_ECDSA_SECP256R1_SHA256 = 0x0403,
@@ -478,9 +490,42 @@ struct nxp_tls_device_hello {
 	u8 auth_tag[NXP_ENC_AUTH_TAG_SIZE];   /* Auth tag for the encrypted portion */
 };
 
+struct nxp_tls_data_add {
+	u8 version;        /* NXP_TLS_VERSION */
+	u8 reserved[5];    /* zeroes */
+	__le16 len;
+};
+
+struct nxp_tls_host_finished {
+	struct nxp_tls_message_hdr hdr;
+	__le32 reserved;
+	/* Encrypted portion */
+	struct {
+		struct nxp_tls_signature reserved2;
+		struct nxp_tls_finished host_finished;
+	} enc;
+	u8 auth_tag[NXP_ENC_AUTH_TAG_SIZE];   /* Auth tag for the encrypted portion */
+};
+
+union nxp_tls_host_finished_payload {
+	struct {
+		u8 msg_type;
+		struct nxp_tls_host_finished host_finished;
+	} __packed;
+	u8 buf[125];
+};
+
 #define DEVICE_HELLO_SIG_CUTOFF_POS \
 	offsetof(struct nxp_tls_device_hello, enc)
 
+#define DEVICE_HELLO_FINISHED_ENC_CUTOFF_POS \
+	(offsetof(struct nxp_tls_device_hello, enc.device_finished) - \
+	DEVICE_HELLO_SIG_CUTOFF_POS)
+
+
+#define HOST_FINISHED_CUTOFF_POS \
+	offsetof(struct nxp_tls_host_finished, enc.host_finished)
+
 /* FW Meta Data */
 struct fw_metadata_hdr {
 	__le32 cmd;
@@ -1700,6 +1745,37 @@ static void nxp_get_fw_version(struct hci_dev *hdev)
 }
 
 /* Secure Interface */
+static int nxp_get_pub_key(struct hci_dev *hdev,
+		      const struct nxp_tls_device_info *device_info,
+		      u8 ecdsa_pub_key[NXP_FW_ECDSA_PUBKEY_SIZE])
+{
+	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+	const char *fw_name;
+
+	if (ecdsa_pub_key[0] == 0x04)
+		return 0;
+
+	fw_name = nxp_get_fw_name_from_chipid(hdev, device_info->chip_id,
+					      device_info->device_flags);
+	if (nxp_request_firmware(hdev, fw_name, NULL))
+		return -ENOENT;
+
+	nxp_process_fw_meta_data(hdev, nxpdev->fw);
+	release_firmware(nxpdev->fw);
+	memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
+
+	if (memcmp(nxpdev->crypto.fw_uuid, device_info->uuid, 16) ||
+	    nxpdev->crypto.ecdsa_public[0] != 0x04) {
+		bt_dev_err(hdev,
+			   "UUID check failed while trying to read ECDSA public key from FW.");
+		return -EBADF;
+	}
+
+	memcpy(ecdsa_pub_key, nxpdev->crypto.ecdsa_public, 65);
+
+	return 0;
+}
+
 static int nxp_generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64])
 {
 	DECLARE_CRYPTO_WAIT(result);
@@ -1971,6 +2047,320 @@ static int nxp_hkdf_derive_secret(u8 secret[32], const char *label, size_t label
 				     output, SHA256_DIGEST_SIZE);
 }
 
+/*
+ * The digital signature is computed over the concatenation of:
+ *  -  A string that consists of octet 32 (0x20) repeated 64 times
+ *  -  The context string
+ *  -  A single 0 byte which serves as the separator
+ *  -  The content to be signed
+ */
+static int nxp_handshake_sig_hash(const u8 transcript_hash[SHA256_DIGEST_SIZE],
+				   const char *context, size_t context_len,
+				   u8 output_hash[SHA256_DIGEST_SIZE])
+{
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	const u8 zero = 0;
+
+	tfm = crypto_alloc_shash("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;
+
+	memset(output_hash, 0x20, SHA256_DIGEST_SIZE);
+
+	crypto_shash_init(desc);
+	/* 2x hash size = block size of 0x20 */
+	crypto_shash_update(desc, output_hash, SHA256_DIGEST_SIZE);
+	crypto_shash_update(desc, output_hash, SHA256_DIGEST_SIZE);
+
+	crypto_shash_update(desc, context, context_len);
+	crypto_shash_update(desc, &zero, sizeof(zero));
+
+	crypto_shash_update(desc, transcript_hash, SHA256_DIGEST_SIZE);
+	crypto_shash_final(desc, output_hash);
+
+	kfree(desc);
+	crypto_free_shash(tfm);
+	return 0;
+}
+
+
+static void nxp_aead_complete(void *req, int err)
+{
+	struct btnxpuart_crypto *crypto = req;
+
+	crypto->decrypt_result = err;
+	complete(&crypto->completion);
+}
+
+static int nxp_aes_gcm_decrypt(struct hci_dev *hdev, void *buf, size_t size,
+			       u8 auth_tag[16], u8 key[AES_KEYSIZE_128],
+			       u8 iv[GCM_AES_IV_SIZE])
+{
+	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+	struct crypto_aead *tfm;
+	struct aead_request *req;
+	struct scatterlist src, dst;
+	struct nxp_tls_data_add aad = {
+		.version = NXP_TLS_VERSION,
+		.len = (u16)size
+	};
+	u8 *ciphertext;
+	u8 *plaintext;
+	int ret = 0;
+
+	ciphertext = kzalloc(sizeof(aad) + size + NXP_ENC_AUTH_TAG_SIZE,
+				 GFP_KERNEL);
+	if (!ciphertext)
+		return -ENOMEM;
+
+	plaintext = kzalloc(size + NXP_ENC_AUTH_TAG_SIZE, GFP_KERNEL);
+	if (!plaintext) {
+		ret = -ENOMEM;
+		goto free_ciphertext;
+	}
+
+	memcpy(ciphertext, &aad, sizeof(aad));
+	memcpy(ciphertext + sizeof(aad), buf, size);
+	memcpy(ciphertext + sizeof(aad) + size, auth_tag, NXP_ENC_AUTH_TAG_SIZE);
+
+	tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
+	if (IS_ERR(tfm)) {
+		ret = PTR_ERR(tfm);
+		goto free_plaintext;
+	}
+
+	crypto_aead_setkey(tfm, key, AES_KEYSIZE_128);
+	crypto_aead_setauthsize(tfm, NXP_ENC_AUTH_TAG_SIZE);
+
+	req = aead_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		ret = -ENOMEM;
+		goto free_tfm;
+	}
+
+	sg_init_one(&src, ciphertext, sizeof(aad) + size + NXP_ENC_AUTH_TAG_SIZE);
+	sg_init_one(&dst, plaintext, size + NXP_ENC_AUTH_TAG_SIZE);
+	init_completion(&nxpdev->crypto.completion);
+
+	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				  nxp_aead_complete, &nxpdev->crypto);
+	aead_request_set_crypt(req, &src, &dst, size + NXP_ENC_AUTH_TAG_SIZE, iv);
+	aead_request_set_ad(req, sizeof(aad));
+
+	ret = crypto_aead_decrypt(req);
+	if (ret == -EINPROGRESS || ret == -EBUSY) {
+		wait_for_completion(&nxpdev->crypto.completion);
+		ret = nxpdev->crypto.decrypt_result;
+	}
+	if (!ret)
+		memcpy(buf, plaintext + sizeof(aad), size);
+
+	aead_request_free(req);
+free_tfm:
+	crypto_free_aead(tfm);
+free_plaintext:
+	kfree(plaintext);
+free_ciphertext:
+	kfree(ciphertext);
+	return ret;
+}
+
+static int nxp_aes_gcm_encrypt(struct hci_dev *hdev, void *buf, size_t size, u8 auth_tag[16],
+			       u8 key[AES_KEYSIZE_128], u8 iv[GCM_AES_IV_SIZE])
+{
+	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+	struct crypto_aead *tfm;
+	struct aead_request *req;
+	struct scatterlist src, dst;
+	struct nxp_tls_data_add aad = {
+		.version = NXP_TLS_VERSION,
+		.len = (u16)size
+	};
+	u8 *ciphertext;
+	u8 *plaintext;
+	int ret = 0;
+
+	ciphertext = kzalloc(sizeof(aad) + size + NXP_ENC_AUTH_TAG_SIZE,
+				 GFP_KERNEL);
+	if (!ciphertext)
+		return -ENOMEM;
+
+	plaintext = kzalloc(size + NXP_ENC_AUTH_TAG_SIZE, GFP_KERNEL);
+	if (!plaintext) {
+		ret = -ENOMEM;
+		goto free_ciphertext;
+	}
+
+	memcpy(plaintext, &aad, sizeof(aad));
+	memcpy(plaintext + sizeof(aad), buf, size);
+
+	tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
+	if (IS_ERR(tfm)) {
+		ret = PTR_ERR(tfm);
+		goto free_plaintext;
+	}
+
+	crypto_aead_setkey(tfm, key, AES_KEYSIZE_128);
+	crypto_aead_setauthsize(tfm, NXP_ENC_AUTH_TAG_SIZE);
+
+	req = aead_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		ret = -ENOMEM;
+		goto free_tfm;
+	}
+
+	sg_init_one(&src, plaintext, size + NXP_ENC_AUTH_TAG_SIZE);
+	sg_init_one(&dst, ciphertext, sizeof(aad) + size + NXP_ENC_AUTH_TAG_SIZE);
+	init_completion(&nxpdev->crypto.completion);
+
+	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				  nxp_aead_complete, &nxpdev->crypto);
+	aead_request_set_crypt(req, &src, &dst, size, iv);
+	aead_request_set_ad(req, sizeof(aad));
+
+	ret = crypto_aead_encrypt(req);
+	if (ret == -EINPROGRESS || ret == -EBUSY) {
+		wait_for_completion(&nxpdev->crypto.completion);
+		ret = nxpdev->crypto.decrypt_result;
+	}
+	if (!ret) {
+		memcpy(buf, ciphertext + sizeof(aad), size);
+		memcpy(auth_tag, ciphertext + size + sizeof(aad), NXP_ENC_AUTH_TAG_SIZE);
+	}
+
+	aead_request_free(req);
+free_tfm:
+	crypto_free_aead(tfm);
+free_plaintext:
+	kfree(plaintext);
+free_ciphertext:
+	kfree(ciphertext);
+	return ret;
+}
+
+static int nxp_handshake_decrypt_verify(struct hci_dev *hdev, void *buf, size_t size,
+					u8 auth_tag[16],
+					u8 traffic_secret[SHA256_DIGEST_SIZE])
+{
+	u8 key[AES_KEYSIZE_128] = {0};
+	u8 iv[GCM_AES_IV_SIZE] = {0};
+
+	nxp_hkdf_expand_label(traffic_secret, NXP_TLS_KEYING_KEY_LABEL, NULL, 0,
+			      key, AES_KEYSIZE_128);
+	nxp_hkdf_expand_label(traffic_secret, NXP_TLS_KEYING_IV_LABEL, NULL, 0,
+			      iv, GCM_AES_IV_SIZE);
+
+	return nxp_aes_gcm_decrypt(hdev, buf, size, auth_tag, key, iv);
+}
+
+static int nxp_handshake_encrypt(struct hci_dev *hdev, void *buf,
+				 size_t size, u8 auth_tag[16],
+				 u8 traffic_secret[SHA256_DIGEST_SIZE])
+{
+	u8 key[AES_KEYSIZE_128] = {0};
+	u8 iv[GCM_AES_IV_SIZE] = {0};
+
+	nxp_hkdf_expand_label(traffic_secret, NXP_TLS_KEYING_KEY_LABEL, NULL,
+			      0, key, AES_KEYSIZE_128);
+	nxp_hkdf_expand_label(traffic_secret, NXP_TLS_KEYING_IV_LABEL, NULL,
+			      0, iv, GCM_AES_IV_SIZE);
+
+	return nxp_aes_gcm_encrypt(hdev, buf, size, auth_tag, key, iv);
+}
+
+static int nxp_p256_ecdsa_verify(const u8 sig[64], const u8 pub[65],
+				const u8 *hash, size_t hash_len)
+{
+	struct public_key_signature sig_info = {0};
+	struct public_key pub_key = {0};
+	int ret;
+
+	sig_info.s = (u8 *)sig;
+	sig_info.s_size = 64;
+	sig_info.digest = (u8 *)hash;
+	sig_info.digest_size = hash_len;
+	sig_info.pkey_algo = "ecdsa";
+	sig_info.hash_algo = "sha256";
+	sig_info.encoding = "p1363";
+
+	pub_key.key = (void *)pub;
+	pub_key.keylen = 65;
+	pub_key.algo = OID_id_ecPublicKey;
+	pub_key.key_is_private = false;
+	pub_key.pkey_algo = "ecdsa-nist-p256";
+	pub_key.id_type = NULL;
+
+	ret = public_key_verify_signature(&pub_key, &sig_info);
+	if (ret)
+		pr_err("ECDSA signature verification failed: %d\n", ret);
+
+	return ret;
+}
+
+static int nxp_device_hello_sig_verify(struct hci_dev *hdev, struct nxp_tls_device_hello *msg)
+{
+	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+	u8 hash_sig[SHA256_DIGEST_SIZE];
+
+	nxp_handshake_sig_hash(nxpdev->crypto.handshake_h2_hash,
+			       "D HS SIG", 8, hash_sig);
+	return nxp_p256_ecdsa_verify(msg->enc.device_handshake_sig.sig,
+				nxpdev->crypto.ecdsa_public,
+				hash_sig, SHA256_DIGEST_SIZE);
+}
+
+static int nxp_write_finished(struct hci_dev *hdev,
+			       const u8 hs_traffic_secret[SHA256_DIGEST_SIZE],
+			       u8 verify_data[SHA256_DIGEST_SIZE])
+{
+	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+	u8 transcript_hash[SHA256_DIGEST_SIZE];
+	u8 finished_key[SHA256_DIGEST_SIZE];
+	int ret = 0;
+
+	ret = nxp_crypto_shash_final(nxpdev->crypto.tls_handshake_hash_desc,
+				     transcript_hash);
+	if (ret)
+		return ret;
+
+	ret = nxp_hkdf_expand_label(hs_traffic_secret, NXP_TLS_FINISHED_LABEL,
+				    NULL, 0, finished_key, sizeof(finished_key));
+	if (ret)
+		return ret;
+
+	nxp_hkdf_sha256_extract(finished_key, SHA256_DIGEST_SIZE, transcript_hash,
+				SHA256_DIGEST_SIZE, verify_data);
+
+	return 0;
+}
+
+static int nxp_verify_device_finished(struct hci_dev *hdev,
+				      struct nxp_tls_device_hello *msg,
+				      const u8 hs_traffic_secret[SHA256_DIGEST_SIZE])
+{
+	u8 verify_data[SHA256_DIGEST_SIZE] = {0};
+	int ret = 0;
+
+	ret = nxp_write_finished(hdev, hs_traffic_secret, verify_data);
+	if (ret)
+		return ret;
+
+	if (memcmp(verify_data, msg->enc.device_finished.verify_data,
+		      SHA256_DIGEST_SIZE))
+		return -EBADMSG;
+
+	return 0;
+}
+
 static int nxp_process_device_hello(struct hci_dev *hdev, struct nxp_tls_device_hello *msg)
 {
 	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
@@ -2025,9 +2415,51 @@ static int nxp_process_device_hello(struct hci_dev *hdev, struct nxp_tls_device_
 	if (ret)
 		goto fail;
 
-	/* TODO: Verify Signature in Device Hello using ECDSA Public Key
-	 * extracted from the FW metadata.
+	ret = nxp_handshake_decrypt_verify(hdev, &msg->enc, sizeof(msg->enc),
+					   msg->auth_tag, hs_traffic_secret);
+	if (ret)
+		goto fail;
+
+	/*
+	 * Verify ECDSA signature handshake_sig using Device's public key from FW metadata.
+	 *
+	 * This is the key point where Device authentication happens:
+	 * - Host generates a random (HostHello.random)
+	 * - Device signs the entire handshake (incl. Host's random) with its
+	 *   private key (DeviceHello.device_handshake_sig)
+	 * - Host now verifies ECDSA signature generated by device using Device's
+	 *   public key
+	 *
+	 * Only the device that possesses the proper private key could sign the
+	 * Host's random.
+	 * If the device is an impostor and does not pose a valid private key,
+	 * the handshake will fail at this point.
 	 */
+	ret = nxp_get_pub_key(hdev, &msg->enc.device_info, nxpdev->crypto.ecdsa_public);
+	if (ret)
+		goto fail;
+
+	ret = nxp_device_hello_sig_verify(hdev, msg);
+	if (ret)
+		goto fail;
+
+	ret = crypto_shash_update(nxpdev->crypto.tls_handshake_hash_desc,
+				  (u8 *)&msg->enc,
+				  DEVICE_HELLO_FINISHED_ENC_CUTOFF_POS);
+	if (ret)
+		goto fail;
+
+	ret = nxp_verify_device_finished(hdev, msg, hs_traffic_secret);
+	if (ret)
+		goto fail;
+
+	ret = crypto_shash_update(nxpdev->crypto.tls_handshake_hash_desc,
+				  (u8 *)&msg->enc.device_finished,
+				  sizeof(msg->enc.device_finished));
+	if (ret)
+		goto fail;
+
+	memset(hs_traffic_secret, 0, SHA256_DIGEST_SIZE);
 
 fail:
 	memset(shared_secret, 0, 32);
@@ -2035,6 +2467,64 @@ static int nxp_process_device_hello(struct hci_dev *hdev, struct nxp_tls_device_
 	return ret;
 }
 
+static int nxp_host_do_finished(struct hci_dev *hdev)
+{
+	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+	union nxp_tls_host_finished_payload finished;
+	struct nxp_tls_host_finished *msg = &finished.host_finished;
+	u8 hs_traffic_secret[SHA256_DIGEST_SIZE];
+	struct sk_buff *skb;
+	u8 *status;
+	int ret = 0;
+
+	memset(msg, 0, sizeof(*msg));
+	nxp_tls_hdr_init(&msg->hdr, sizeof(*msg), NXP_TLS_HOST_FINISHED);
+
+	crypto_shash_update(nxpdev->crypto.tls_handshake_hash_desc,
+			    (u8 *)msg, HOST_FINISHED_CUTOFF_POS);
+
+	ret = nxp_hkdf_derive_secret(nxpdev->crypto.handshake_secret,
+				     NXP_TLS_HOST_HS_TS_LABEL,
+				     nxpdev->crypto.handshake_h2_hash,
+				     hs_traffic_secret);
+	if (ret)
+		return ret;
+
+	ret = nxp_write_finished(hdev, hs_traffic_secret,
+				 msg->enc.host_finished.verify_data);
+	if (ret)
+		return ret;
+
+	crypto_shash_update(nxpdev->crypto.tls_handshake_hash_desc,
+			    (u8 *)&msg->enc.host_finished, sizeof(msg->enc.host_finished));
+
+	nxp_handshake_encrypt(hdev, &msg->enc, sizeof(msg->enc),
+			      msg->auth_tag, hs_traffic_secret);
+
+	finished.msg_type = 0x01;
+
+	skb = __hci_cmd_sync(hdev, HCI_NXP_SHI_ENCRYPT,
+			     sizeof(finished), finished.buf,
+			     HCI_CMD_TIMEOUT);
+	if (IS_ERR(skb)) {
+		bt_dev_err(hdev, "Host Finished error %ld", PTR_ERR(skb));
+		return PTR_ERR(skb);
+	}
+	status = skb_pull_data(skb, 1);
+	if (!status) {
+		ret = -EIO;
+		goto fail;
+	}
+	if (*status) {
+		ret = -EIO;
+		bt_dev_err(hdev, "Host Finished status error: %d", *status);
+	}
+
+fail:
+	kfree_skb(skb);
+	return ret;
+}
+
 static int nxp_authenticate_device(struct hci_dev *hdev)
 {
 	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
@@ -2085,10 +2575,13 @@ static int nxp_authenticate_device(struct hci_dev *hdev)
 	if (ret)
 		goto free_skb;
 
+	ret = nxp_host_do_finished(hdev);
+	if (ret)
+		goto free_skb;
+
 	/* TODO: Implement actual TLS handshake protocol
 	 * This will include:
-	 * 1. Send Host Finish TLS message
-	 * 2. Master secret and traffic key derivation
+	 * 1. Master secret and traffic key derivation
 	 */
 
 free_skb:
-- 
2.43.0
Re: [PATCH v1 07/11] Bluetooth: btnxpuart: Add device authentication
Posted by kernel test robot 1 week, 2 days ago
Hi Neeraj,

kernel test robot noticed the following build warnings:

[auto build test WARNING on bluetooth/master]
[also build test WARNING on bluetooth-next/master linus/master v6.18-rc6 next-20251121]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Neeraj-Sanjay-Kale/Bluetooth-btnxpuart-Add-firmware-metadata-parsing-for-secure-interface/20251118-223605
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git master
patch link:    https://lore.kernel.org/r/20251118142025.1982263-8-neeraj.sanjaykale%40nxp.com
patch subject: [PATCH v1 07/11] Bluetooth: btnxpuart: Add device authentication
config: arm-randconfig-001-20251122 (https://download.01.org/0day-ci/archive/20251122/202511221835.jzKFsvPM-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 9e9fe08b16ea2c4d9867fb4974edf2a3776d6ece)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251122/202511221835.jzKFsvPM-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511221835.jzKFsvPM-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/bluetooth/btnxpuart.c:459:29: warning: field host_hello within 'struct nxp_tls_host_hello_payload::(anonymous at drivers/bluetooth/btnxpuart.c:457:2)' is less aligned than 'struct nxp_tls_host_hello' and is usually due to 'struct nxp_tls_host_hello_payload::(anonymous at drivers/bluetooth/btnxpuart.c:457:2)' being packed, which can lead to unaligned accesses [-Wunaligned-access]
     459 |                 struct nxp_tls_host_hello host_hello;
         |                                           ^
>> drivers/bluetooth/btnxpuart.c:513:32: warning: field host_finished within 'struct nxp_tls_host_finished_payload::(anonymous at drivers/bluetooth/btnxpuart.c:511:2)' is less aligned than 'struct nxp_tls_host_finished' and is usually due to 'struct nxp_tls_host_finished_payload::(anonymous at drivers/bluetooth/btnxpuart.c:511:2)' being packed, which can lead to unaligned accesses [-Wunaligned-access]
     513 |                 struct nxp_tls_host_finished host_finished;
         |                                              ^
   2 warnings generated.


vim +513 drivers/bluetooth/btnxpuart.c

   455	
   456	union nxp_tls_host_hello_payload {
   457		struct {
   458			u8 msg_type;
 > 459			struct nxp_tls_host_hello host_hello;
   460		} __packed;
   461		u8 buf[113];
   462	};
   463	
   464	struct nxp_tls_device_info {
   465		__le16 chip_id;
   466		__le16 device_flags;
   467		u8 reserved[4];
   468		u8 uuid[NXP_DEVICE_UUID_LEN];
   469	};
   470	
   471	struct nxp_tls_signature {
   472		u8 sig[64];        /* P-256 ECDSA signature, two points */
   473	};
   474	
   475	struct nxp_tls_finished {
   476		u8 verify_data[32];
   477	};
   478	
   479	struct nxp_tls_device_hello {
   480		struct nxp_tls_message_hdr hdr;
   481		__le32 reserved;
   482		u8 random[32];
   483		u8 pubkey[NXP_TLS_ECDH_PUBLIC_KEY_SIZE];
   484		/* Encrypted portion */
   485		struct {
   486			struct nxp_tls_device_info device_info;
   487			struct nxp_tls_signature device_handshake_sig;   /* TLS Certificate Verify */
   488			struct nxp_tls_finished device_finished;
   489		} enc;
   490		u8 auth_tag[NXP_ENC_AUTH_TAG_SIZE];   /* Auth tag for the encrypted portion */
   491	};
   492	
   493	struct nxp_tls_data_add {
   494		u8 version;        /* NXP_TLS_VERSION */
   495		u8 reserved[5];    /* zeroes */
   496		__le16 len;
   497	};
   498	
   499	struct nxp_tls_host_finished {
   500		struct nxp_tls_message_hdr hdr;
   501		__le32 reserved;
   502		/* Encrypted portion */
   503		struct {
   504			struct nxp_tls_signature reserved2;
   505			struct nxp_tls_finished host_finished;
   506		} enc;
   507		u8 auth_tag[NXP_ENC_AUTH_TAG_SIZE];   /* Auth tag for the encrypted portion */
   508	};
   509	
   510	union nxp_tls_host_finished_payload {
   511		struct {
   512			u8 msg_type;
 > 513			struct nxp_tls_host_finished host_finished;
   514		} __packed;
   515		u8 buf[125];
   516	};
   517	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH v1 07/11] Bluetooth: btnxpuart: Add device authentication
Posted by kernel test robot 1 week, 4 days ago
Hi Neeraj,

kernel test robot noticed the following build warnings:

[auto build test WARNING on bluetooth/master]
[also build test WARNING on bluetooth-next/master linus/master v6.18-rc6]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Neeraj-Sanjay-Kale/Bluetooth-btnxpuart-Add-firmware-metadata-parsing-for-secure-interface/20251118-223605
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git master
patch link:    https://lore.kernel.org/r/20251118142025.1982263-8-neeraj.sanjaykale%40nxp.com
patch subject: [PATCH v1 07/11] Bluetooth: btnxpuart: Add device authentication
config: i386-randconfig-061-20251120 (https://download.01.org/0day-ci/archive/20251120/202511202234.PN8Zn4v7-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251120/202511202234.PN8Zn4v7-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511202234.PN8Zn4v7-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
   drivers/bluetooth/btnxpuart.c:1433:55: sparse: sparse: restricted __le32 degrades to integer
   drivers/bluetooth/btnxpuart.c:1441:27: sparse: sparse: restricted __le32 degrades to integer
   drivers/bluetooth/btnxpuart.c:1446:47: sparse: sparse: restricted __le32 degrades to integer
   drivers/bluetooth/btnxpuart.c:1447:32: sparse: sparse: restricted __le32 degrades to integer
   drivers/bluetooth/btnxpuart.c:1450:26: sparse: sparse: restricted __le32 degrades to integer
   drivers/bluetooth/btnxpuart.c:1529:17: sparse: sparse: restricted __le32 degrades to integer
>> drivers/bluetooth/btnxpuart.c:1758:64: sparse: sparse: incorrect type in argument 2 (different base types) @@     expected unsigned short [usertype] chipid @@     got restricted __le16 const [usertype] chip_id @@
   drivers/bluetooth/btnxpuart.c:1758:64: sparse:     expected unsigned short [usertype] chipid
   drivers/bluetooth/btnxpuart.c:1758:64: sparse:     got restricted __le16 const [usertype] chip_id
>> drivers/bluetooth/btnxpuart.c:1759:58: sparse: sparse: incorrect type in argument 3 (different base types) @@     expected unsigned char [usertype] loader_ver @@     got restricted __le16 const [usertype] device_flags @@
   drivers/bluetooth/btnxpuart.c:1759:58: sparse:     expected unsigned char [usertype] loader_ver
   drivers/bluetooth/btnxpuart.c:1759:58: sparse:     got restricted __le16 const [usertype] device_flags
>> drivers/bluetooth/btnxpuart.c:2114:25: sparse: sparse: incorrect type in initializer (different base types) @@     expected restricted __le16 [usertype] len @@     got unsigned short [usertype] @@
   drivers/bluetooth/btnxpuart.c:2114:25: sparse:     expected restricted __le16 [usertype] len
   drivers/bluetooth/btnxpuart.c:2114:25: sparse:     got unsigned short [usertype]
   drivers/bluetooth/btnxpuart.c:2186:25: sparse: sparse: incorrect type in initializer (different base types) @@     expected restricted __le16 [usertype] len @@     got unsigned short [usertype] @@
   drivers/bluetooth/btnxpuart.c:2186:25: sparse:     expected restricted __le16 [usertype] len
   drivers/bluetooth/btnxpuart.c:2186:25: sparse:     got unsigned short [usertype]

vim +1758 drivers/bluetooth/btnxpuart.c

  1746	
  1747	/* Secure Interface */
  1748	static int nxp_get_pub_key(struct hci_dev *hdev,
  1749			      const struct nxp_tls_device_info *device_info,
  1750			      u8 ecdsa_pub_key[NXP_FW_ECDSA_PUBKEY_SIZE])
  1751	{
  1752		struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
  1753		const char *fw_name;
  1754	
  1755		if (ecdsa_pub_key[0] == 0x04)
  1756			return 0;
  1757	
> 1758		fw_name = nxp_get_fw_name_from_chipid(hdev, device_info->chip_id,
> 1759						      device_info->device_flags);
  1760		if (nxp_request_firmware(hdev, fw_name, NULL))
  1761			return -ENOENT;
  1762	
  1763		nxp_process_fw_meta_data(hdev, nxpdev->fw);
  1764		release_firmware(nxpdev->fw);
  1765		memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
  1766	
  1767		if (memcmp(nxpdev->crypto.fw_uuid, device_info->uuid, 16) ||
  1768		    nxpdev->crypto.ecdsa_public[0] != 0x04) {
  1769			bt_dev_err(hdev,
  1770				   "UUID check failed while trying to read ECDSA public key from FW.");
  1771			return -EBADF;
  1772		}
  1773	
  1774		memcpy(ecdsa_pub_key, nxpdev->crypto.ecdsa_public, 65);
  1775	
  1776		return 0;
  1777	}
  1778	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki