[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251118142025.1982263-8-neeraj.sanjaykale@nxp.com>
Date: Tue, 18 Nov 2025 19:50:20 +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 07/11] Bluetooth: btnxpuart: Add device authentication
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@....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
Powered by blists - more mailing lists