]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
Bluetooth: btintel: Add support for hybrid signature for ScP2 onwards
authorKiran K <kiran.k@intel.com>
Sat, 28 Feb 2026 09:12:31 +0000 (14:42 +0530)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Fri, 10 Apr 2026 14:27:08 +0000 (10:27 -0400)
If FW image has hybrid signature (ECDSA and LMS) then send CSS header,
ECDSA public key, ECDSA signature, LMS public key, LMS signature and
command buffer to device.

Signed-off-by: Kiran K <kiran.k@intel.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
drivers/bluetooth/btintel.c

index ab146894ba4e4ea572374498ba27a43f872fe7b5..39e16dcca0ce41fd84b87ccd3dd4e17f2f4f8b6a 100644 (file)
@@ -35,6 +35,19 @@ enum {
        DSM_SET_RESET_METHOD = 3,
 };
 
+/* Hybrid ECDSA + LMS */
+#define BTINTEL_RSA_HEADER_VER         0x00010000
+#define BTINTEL_ECDSA_HEADER_VER       0x00020000
+#define BTINTEL_HYBRID_HEADER_VER      0x00069700
+#define BTINTEL_ECDSA_OFFSET           128
+#define BTINTEL_CSS_HEADER_SIZE                128
+#define BTINTEL_ECDSA_PUB_KEY_SIZE     96
+#define BTINTEL_ECDSA_SIG_SIZE         96
+#define BTINTEL_LMS_OFFSET             320
+#define BTINTEL_LMS_PUB_KEY_SIZE       52
+#define BTINTEL_LMS_SIG_SIZE           1744
+#define BTINTEL_CMD_BUFFER_OFFSET      2116
+
 #define BTINTEL_BT_DOMAIN              0x12
 #define BTINTEL_SAR_LEGACY             0
 #define BTINTEL_SAR_INC_PWR            1
@@ -510,8 +523,8 @@ int btintel_version_info_tlv(struct hci_dev *hdev,
                        return -EINVAL;
                }
 
-               /* Secure boot engine type should be either 1 (ECDSA) or 0 (RSA) */
-               if (version->sbe_type > 0x01) {
+               /* Secure boot engine type can be 0 (RSA), 1 (ECDSA), 2 (LMS), 3 (ECDSA + LMS) */
+               if (version->sbe_type > 0x03) {
                        bt_dev_err(hdev, "Unsupported Intel secure boot engine type (0x%x)",
                                   version->sbe_type);
                        return -EINVAL;
@@ -1030,6 +1043,48 @@ static int btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev,
        return 0;
 }
 
+static int btintel_sfi_hybrid_header_secure_send(struct hci_dev *hdev,
+                                                const struct firmware *fw)
+{
+       int err;
+
+       err = btintel_secure_send(hdev, 0x00, BTINTEL_CSS_HEADER_SIZE, fw->data);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to send firmware CSS header (%d)", err);
+               return err;
+       }
+
+       err = btintel_secure_send(hdev, 0x03, BTINTEL_ECDSA_PUB_KEY_SIZE,
+                                 fw->data + BTINTEL_ECDSA_OFFSET);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to send firmware ECDSA pkey (%d)", err);
+               return err;
+       }
+
+       err = btintel_secure_send(hdev, 0x02, BTINTEL_ECDSA_SIG_SIZE,
+                                 fw->data + BTINTEL_ECDSA_OFFSET + BTINTEL_ECDSA_PUB_KEY_SIZE);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to send firmware ECDSA signature (%d)", err);
+               return err;
+       }
+
+       err = btintel_secure_send(hdev, 0x05, BTINTEL_LMS_PUB_KEY_SIZE,
+                                 fw->data + BTINTEL_LMS_OFFSET);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to send firmware LMS pkey (%d)", err);
+               return err;
+       }
+
+       err = btintel_secure_send(hdev, 0x04, BTINTEL_LMS_SIG_SIZE,
+                                 fw->data + BTINTEL_LMS_OFFSET + BTINTEL_LMS_PUB_KEY_SIZE);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to send firmware LMS signature (%d)", err);
+               return err;
+       }
+
+       return 0;
+}
+
 static int btintel_download_firmware_payload(struct hci_dev *hdev,
                                             const struct firmware *fw,
                                             size_t offset)
@@ -1203,11 +1258,12 @@ static int btintel_download_fw_tlv(struct hci_dev *hdev,
         * Command Buffer.
         *
         * CSS Header byte positions 0x08 to 0x0B represent the CSS Header
-        * version: RSA(0x00010000) , ECDSA (0x00020000)
+        * version: RSA(0x00010000) , ECDSA (0x00020000) , HYBRID (0x00069700)
         */
        css_header_ver = get_unaligned_le32(fw->data + CSS_HEADER_OFFSET);
-       if (css_header_ver != 0x00010000) {
-               bt_dev_err(hdev, "Invalid CSS Header version");
+       if (css_header_ver != BTINTEL_RSA_HEADER_VER &&
+           css_header_ver != BTINTEL_HYBRID_HEADER_VER) {
+               bt_dev_err(hdev, "Invalid CSS Header version: 0x%8.8x", css_header_ver);
                return -EINVAL;
        }
 
@@ -1225,15 +1281,15 @@ static int btintel_download_fw_tlv(struct hci_dev *hdev,
                err = btintel_download_firmware_payload(hdev, fw, RSA_HEADER_LEN);
                if (err)
                        return err;
-       } else if (hw_variant >= 0x17) {
+       } else if (hw_variant >= 0x17 && css_header_ver == BTINTEL_RSA_HEADER_VER) {
                /* Check if CSS header for ECDSA follows the RSA header */
                if (fw->data[ECDSA_OFFSET] != 0x06)
                        return -EINVAL;
 
                /* Check if the CSS Header version is ECDSA(0x00020000) */
                css_header_ver = get_unaligned_le32(fw->data + ECDSA_OFFSET + CSS_HEADER_OFFSET);
-               if (css_header_ver != 0x00020000) {
-                       bt_dev_err(hdev, "Invalid CSS Header version");
+               if (css_header_ver != BTINTEL_ECDSA_HEADER_VER) {
+                       bt_dev_err(hdev, "Invalid CSS Header version: 0x%8.8x", css_header_ver);
                        return -EINVAL;
                }
 
@@ -1256,6 +1312,14 @@ static int btintel_download_fw_tlv(struct hci_dev *hdev,
                        if (err)
                                return err;
                }
+       } else if (hw_variant >= 0x20 && css_header_ver == BTINTEL_HYBRID_HEADER_VER) {
+               err = btintel_sfi_hybrid_header_secure_send(hdev, fw);
+               if (err)
+                       return err;
+
+               err = btintel_download_firmware_payload(hdev, fw, BTINTEL_CMD_BUFFER_OFFSET);
+               if (err)
+                       return err;
        }
        return 0;
 }