diff --git a/.github/workflows/examples-k32w.yaml b/.github/workflows/examples-k32w.yaml index 5d811a986c757a..e2854c2e297f38 100644 --- a/.github/workflows/examples-k32w.yaml +++ b/.github/workflows/examples-k32w.yaml @@ -37,7 +37,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: ghcr.io/project-chip/chip-build-k32w:26 + image: ghcr.io/project-chip/chip-build-k32w:27 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/docs/guides/nxp_manufacturing_flow.md b/docs/guides/nxp_manufacturing_flow.md index 141f90c8b8b57c..64bafd53c89329 100644 --- a/docs/guides/nxp_manufacturing_flow.md +++ b/docs/guides/nxp_manufacturing_flow.md @@ -11,108 +11,91 @@ using the procedure described below. ## 1. Prerequisites -Build `chip-cert` tool: - -``` -cd src/tools/chip-cert -gn gen out -ninja -C out -``` - -Build `spake2p` tool: +Generate build files from Matter root folder by running: ``` -cd src/tool/spake2p gn gen out -ninja -C out ``` -### Environment variables - -A user can customize the certificate generation by setting some environment -variables that are used within the utility scripts. Please note that the values -below are just an example and should be modified accordingly: +Build `chip-cert` tool: ``` -export FACTORY_DATA_DEST=path/factory/data/dest -export DEVICE_TYPE=100 -export DATE=$(date +"%F") -export TIME=$(date +"%T") -export LIFETIME="7305" -export VID="1037" -export PID="A220" +ninja -C out chip-cert ``` -`FACTORY_DATA_DEST` is the path where all factory related data is generated. - -`DEVICE_TYPE` should be updated according to the application device type (0x0100 -for the provided K32W0 lighting app). - -Additionally, `PAA_CERT` and `PAA_KEY` paths can be specified to use an already -existent **PAA**: +Build `spake2p` tool: ``` -export PAA_CERT=path/certs/Chip-PAA-NXP-Cert.pem -export PAA_KEY=path/certs/Chip-PAA-NXP-Key.pem +ninja -C out spake2p ``` ## 2. Generate ### a. Certificates -``` -./scripts/tools/nxp/generate_cert.sh ./src/tools/chip-cert/out/chip-cert -``` +To generate the different certificates, NXP provides a Python script +`scripts/tools/nxp/generate_certs.py`. This script will always generate the PAI +and DAC certificates/keys. It can also generate the Certification Declaration +and the PAA certificate/key depending on the parameters. -The output of the script is the **DAC**, **PAI** and **PAA** certificates. If -`FACTORY_DATA_DEST` is set, the certificates will be moved there. The **DAC** -and **PAI** certificates will be written in a special section of the internal -flash, while the **PAA** will be used by `chip-tool` as trust anchor. Please -note that for _real production manufacturing_ the "production PAA" is trusted -via the **DCL** rather than through the generated **PAA** certificate. The -**PAI** certificate may also have a different lifecycle. +| Parameter | Description | Type | Required | +| ------------------ | ------------------------------------------------------------------------------------------------- | ---------------------- | -------- | +| `--chip_cert_path` | Path to chip-cert executable | string | Yes | +| `--output` | Output path to store certificates | string | Yes | +| `--vendor_id` | Vendor Identification Number | integer or hex integer | Yes | +| `--product_id` | Product Identification Number | integer or hex integer | Yes | +| `--vendor_name` | Human-readable vendor name | string | Yes | +| `--product_name` | Human-readable product name | string | Yes | +| `--gen_cd` | Use this option to enable Certificate Declaration generation | boolean | No | +| `--cd_type` | Type of generated Certification Declaration: `0` - development, `1` - provisional, `2` - official | integer | No | +| `--device_type` | The primary device type implemented by the node | int | No | +| `--paa_cert` | Path to the Product Attestation Authority (PAA) certificate. Will be generated if not provided. | string | No | +| `--paa_key` | Path to the Product Attestation Authority (PAA) key. Will be generated if not provided. | string | No | +| `--valid_from` | The start date for the certificate's validity period. | string | No | +| `--lifetime` | The lifetime for the certificates, in whole days. | string | No | -### b. Certification declaration (CD) +You can also run the following command to get more details on the parameters and +their default value (if applicable): -``` -./src/tools/chip-cert/out/chip-cert gen-cd --key ./credentials/test/certification-declaration/Chip-Test-CD-Signing-Key.pem --cert ./credentials/test/certification-declaration/Chip-Test-CD-Signing-Cert.pem --out $FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID.der --format-version 1 --vendor-id "0x$VID" --product-id "0x$PID" --device-type-id "0x$DEVICE_TYPE" --certificate-id "ZIG20142ZB330003-24" --security-level 0 --security-info 0 --version-number 9876 --certification-type 1 +```shell +python scripts/tools/nxp/generate_certs.py --help ``` -The command above is extracted from `./credentials/test/gen-test-cds.sh` script. -The CD generation uses predefined key and certificate found in -`./credentials/test/certification-declaration`. This **CSA** certificate is also -hard-coded as Trust Anchor in the current `chip-tool` version. +Example of a command that will generate CD, PAA, PAI and DAC certificates and +keys in both .pem and .der formats: -By default, the CD is added to the factory data section. In order to have it -integrated in the application binary, set -`CHIP_USE_DEVICE_CONFIG_CERTIFICATION_DECLARATION` to 1 in the application's -CHIPProjectConfig.h file. +```shell +python scripts/tools/nxp/generate_certs.py --gen_cd --cd_type 1 --chip_cert_path ./out/chip-cert --vendor_id 0x1037 --product_id 0xA220 --vendor_name "NXP Semiconductors" --product_name all-clusters-app --device_type 65535 --output . +``` + +> **Note**: the commands provided in this guide are just for the example and +> shall be adapted to your use case accordingly ### c. Provisioning data Generate new provisioning data and convert all the data to a binary (unencrypted data): -``` -python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLzwHdN3DZZLBaL2iVGhQi/OoQwIwJRQV4rpEalbA= -p 14014 -d 1000 --vid "0x$VID" --pid "0x$PID" --vendor_name "NXP Semiconductors" --product_name "Lighting app" --serial_num "12345678" --date "$DATE" --hw_version 1 --hw_version_str "1.0" --cert_declaration $FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID.der --dac_cert $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Cert.der --dac_key $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Key.der --pai_cert $FACTORY_DATA_DEST/Chip-PAI-NXP-$VID-$PID-Cert.der --spake2p_path ./src/tools/spake2p/out/spake2p --unique_id "00112233445566778899aabbccddeeff" --out $FACTORY_DATA_DEST/factory_data.bin +```shell +python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLzwHdN3DZZLBaL2iVGhQi/OoQwIwJRQV4rpEalbA= -p 14014 -d 1000 --vid 0x1037 --pid 0xA220 --vendor_name "NXP Semiconductors" --product_name "Lighting app" --serial_num "12345678" --date "2023-01-01" --hw_version 1 --hw_version_str "1.0" --cert_declaration ./Chip-Test-CD-1037-A220.der --dac_cert ./Chip-DAC-NXP-1037-A220-Cert.der --dac_key ./Chip-DAC-NXP-1037-A220-Key.der --pai_cert ./Chip-PAI-NXP-1037-A220-Cert.der --spake2p_path ./out/spake2p --unique_id "00112233445566778899aabbccddeeff" --out ./factory_data.bin ``` Same example as above, but with an already generated verifier passed as input: -``` -python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLzwHdN3DZZLBaL2iVGhQi/OoQwIwJRQV4rpEalbA= -p 14014 -d 1000 --vid "0x$VID" --pid "0x$PID" --vendor_name "NXP Semiconductors" --product_name "Lighting app" --serial_num "12345678" --date "$DATE" --hw_version 1 --hw_version_str "1.0" --cert_declaration $FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID.der --dac_cert $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Cert.der --dac_key $FACTORY_DATA_DEST/Chip-DAC-NXP-$VID-$PID-Key.der --pai_cert $FACTORY_DATA_DEST/Chip-PAI-NXP-$VID-$PID-Cert.der --spake2p_path ./src/tools/spake2p/out/spake2p --spake2p_verifier ivD5n3L2t5+zeFt6SjW7BhHRF30gFXWZVvvXgDxgCNcE+BGuTA5AUaVm3qDZBcMMKn1a6CakI4SxyPUnJr0CpJ4pwpr0DvpTlkQKqaRvkOQfAQ1XDyf55DuavM5KVGdDrg== --unique_id "00112233445566778899aabbccddeeff" --out $FACTORY_DATA_DEST/factory_data.bin +```shell +python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLzwHdN3DZZLBaL2iVGhQi/OoQwIwJRQV4rpEalbA= -p 14014 -d 1000 --vid "0x1037" --pid "0xA220" --vendor_name "NXP Semiconductors" --product_name "Lighting app" --serial_num "12345678" --date "2023-01-01" --hw_version 1 --hw_version_str "1.0" --cert_declaration ./Chip-Test-CD-1037-A220.der --dac_cert ./Chip-DAC-NXP-1037-A220-Cert.der --dac_key ./Chip-DAC-NXP-1037-A220-Key.der --pai_cert ./Chip-PAI-NXP-1037-A220-Cert.der --spake2p_path ./out/spake2p --spake2p_verifier ivD5n3L2t5+zeFt6SjW7BhHRF30gFXWZVvvXgDxgCNcE+BGuTA5AUaVm3qDZBcMMKn1a6CakI4SxyPUnJr0CpJ4pwpr0DvpTlkQKqaRvkOQfAQ1XDyf55DuavM5KVGdDrg== --unique_id "00112233445566778899aabbccddeeff" --out ./factory_data.bin ``` Generate new provisioning data and convert all the data to a binary (encrypted data with the AES key). Add the following option to one of the above examples: -``` +```shell --aes128_key 2B7E151628AED2A6ABF7158809CF4F3C ``` Here is the interpretation of the **required** parameters: -``` +```shell -i -> SPAKE2+ iteration -s -> SPAKE2+ salt (passed as base64 encoded string) -p -> SPAKE2+ passcode @@ -127,7 +110,7 @@ Here is the interpretation of the **required** parameters: --dac_cert -> path to the DAC (der format) location --dac_key -> path to the DAC key (der format) location --pai_cert -> path to the PAI (der format) location ---spake2p_path -> path to the spake2p tool (compile it from ./src/tools/spake2p) +--spake2p_path -> path to the spake2p tool --out -> name of the binary that will be used for storing all the generated data @@ -135,18 +118,24 @@ Here is the interpretation of the **required** parameters: Here is the interpretation of the **optional** parameters: -``` ---dac_key_password -> Password to decode DAC key ---spake2p_verifier -> SPAKE2+ verifier (passed as base64 encoded string). If this option is set, - all SPAKE2+ inputs will be encoded in the final binary. The spake2p tool - will not be used to generate a new verifier on the fly. ---aes128_key -> 128 bits AES key used to encrypt the whole dataset ---date -> Manufacturing Date (YYYY-MM-DD format) ---part_number -> Part number as string ---product_url -> Product URL as string ---product_label -> Product label as string ---serial_num -> Serial Number ---unique_id -> Unique id used for rotating device id generation +```shell +--dac_key_password -> Password to decode DAC key +--dac_key_use_sss_blob -> Used when --dac_key contains a path to an encrypted blob, instead of the + actual DAC private key. The blob metadata size is 24, so the total length + of the resulting value is private key length (32) + 24 = 56. False by default. +--spake2p_verifier -> SPAKE2+ verifier (passed as base64 encoded string). If this option is set, + all SPAKE2+ inputs will be encoded in the final binary. The spake2p tool + will not be used to generate a new verifier on the fly. +--aes128_key -> 128 bits AES key used to encrypt the whole dataset. Please make sure + that the target application/board supports this feature: it has access to + the private key and implements a mechanism which can be used to decrypt + the factory data information. +--date -> Manufacturing Date (YYYY-MM-DD format) +--part_number -> Part number as string +--product_url -> Product URL as string +--product_label -> Product label as string +--serial_num -> Serial Number +--unique_id -> Unique id used for rotating device id generation ``` ## 3. Write provisioning data @@ -154,10 +143,20 @@ Here is the interpretation of the **optional** parameters: For the **K32W0x1** variants, the binary needs to be written in the internal flash at location **0x9D600** using `DK6Programmer.exe`: -``` +```shell DK6Programmer.exe -Y -V2 -s -P 1000000 -Y -p FLASH@0x9D600="factory_data.bin" ``` +For **K32W1** platform, the binary needs to be written in the internal flash at +location given by `__MATTER_FACTORY_DATA_START`, using `JLink`: + +``` +loadfile factory_data.bin 0xf4000 +``` + +where `0xf4000` is the value of `__MATTER_FACTORY_DATA_START` in the +corresponding .map file (can be different if using a custom linker script). + For the **RT1060**, **RT1170** and **RW61X** platform, the binary needs to be written using `MCUXpresso Flash Tool GUI` at the address value corresponding to `__FACTORY_DATA_START` (the map file of the application should be checked to get @@ -169,13 +168,13 @@ Use `chip_with_factory_data=1` when compiling to enable factory data usage. Run chip-tool with a new PAA: -``` +```shell ./chip-tool pairing ble-thread 2 hex: $hex_value 14014 1000 --paa-trust-store-path /home/ubuntu/certs/paa ``` Here is the interpretation of the parameters: -``` +```shell --paa-trust-store-path -> path to the generated PAA (der format) ``` @@ -195,4 +194,51 @@ certificates generated by `OpenSSL 1.1.1l`. Also, demo **DAC**, **PAI** and **PAA** certificates needed in case `chip_with_factory_data=1` is used can be found in -`./scripts/tools/nxp/demo_generated_certs`. +`./scripts/tools/nxp/demo_generated_certs`. + +## 6. Increased security for DAC private key + +Supported platforms: + +- K32W1 - `src/plaftorm/nxp/k32w/k32w1/FactoryDataProviderImpl.h` + +For platforms that have a secure subsystem (`SSS`), the DAC private key can be +converted to an encrypted blob. This blob will overwrite the DAC private key in +factory data and will be imported in the `SSS` at initialization, by the factory +data provider instance. + +The conversion process shall happen at manufacturing time and should be run one +time only: + +- Write factory data binary. +- Build the application with + `chip_with_factory_data=1 chip_convert_dac_private_key=1` set. +- Write the application to the board and let it run. + +After the conversion process: + +- Make sure the application is built with `chip_with_factory_data=1`, but + without `chip_convert_dac_private_key` arg, since conversion already + happened. +- Write the application to the board. + +If you are using Jlink, you can see a conversion script example in: + +```shell +./scripts/tools/nxp/factory_data_generator/k32w1/example_convert_dac_private_key.jlink +``` + +Factory data should now contain a corresponding encrypted blob instead of the +DAC private key. + +If an encrypted blob of the DAC private key is already available (e.g. obtained +previously, using other methods), then the conversion process shall be skipped. +Instead, option `--dac_key_use_sss_blob` can be used in the factory data +generation command: + +```shell +python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLzwHdN3DZZLBaL2iVGhQi/OoQwIwJRQV4rpEalbA= -p 14014 -d 1000 --vid "0x1037" --pid "0xA221" --vendor_name "NXP Semiconductors" --product_name "Lighting app" --serial_num "12345678" --date "2023-01-01" --hw_version 1 --hw_version_str "1.0" --cert_declaration ./Chip-Test-CD-1037-A221.der --dac_cert ./Chip-DAC-NXP-1037-A221-Cert.der --dac_key ./Chip-DAC-NXP-1037-A221-Key-encrypted-blob.bin --pai_cert ./Chip-PAI-NXP-1037-A221-Cert.der --spake2p_path ./out/spake2p --unique_id "00112233445566778899aabbccddeeff" --dac_key_use_sss_blob --out ./factory_data_with_blob.bin +``` + +Please note that `--dac_key` now points to a binary file that contains the +encrypted blob. diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/BUILD.gn b/examples/contact-sensor-app/nxp/k32w/k32w0/BUILD.gn index e4c15436b3bd86..36f52d917f22db 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/BUILD.gn +++ b/examples/contact-sensor-app/nxp/k32w/k32w0/BUILD.gn @@ -25,6 +25,7 @@ import("${chip_root}/src/platform/device.gni") declare_args() { chip_software_version = 0 + chip_simple_hash_verification = 0 } if (chip_pw_tokenizer_logging) { @@ -177,6 +178,10 @@ action("binsign") { script = "${k32w0_platform_dir}/scripts/sign-outdir.py" output_name = "bignsign.log" outputs = [ "${root_build_dir}/${output_name}" ] + + if (chip_simple_hash_verification == 1) { + args = [ "--simple-hash" ] + } } group("default") { diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/README.md b/examples/contact-sensor-app/nxp/k32w/k32w0/README.md index 9f92bc0d795142..f616ddfeeca4f9 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/README.md +++ b/examples/contact-sensor-app/nxp/k32w/k32w0/README.md @@ -440,6 +440,10 @@ SSBL demo application can be imported from the `Quickstart panel`: ![SSBL Application Select](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_select.JPG) +### Features + +#### Multi image + To support multi-image OTA feature, the SSBL project must be compiled using the following defines: @@ -457,6 +461,24 @@ Optionally, add the following defines: ![SSBL_MULTI_IMAGE](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_multi_image.JPG) +#### Simple hash verification + +When secure boot is not used, a simple hash can be appended at the end of the +image for integrity check. Applications should be built with +`chip_simple_hash_verification=1`. + +To support simple hash verification feature, the SSBL project must be compiled +with: + +- `gSimpleHashVerification=1` + +and update the post-build command to use simple hash verification instead of the +default options. Go to +`Project -> Properties -> C/C++ Build -> Settings -> Build steps` and press +`Edit` under `Post-build steps` subsection. The command should look similar to: + +![SSBL_SIMPLE_HASH_VERIFICATION](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_simple_hash.JPG) + Once compiled, the required SSBL file is called `k32w061dk6_ssbl.bin`. ![SSBL_BIN](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_bin.JPG) diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/args.gni b/examples/contact-sensor-app/nxp/k32w/k32w0/args.gni index 4f4bba4b47cf07..02a388daab9e1a 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/args.gni +++ b/examples/contact-sensor-app/nxp/k32w/k32w0/args.gni @@ -22,3 +22,7 @@ k32w0_sdk_target = get_label_info(":sdk", "label_no_toolchain") chip_enable_ota_requestor = true chip_stack_lock_tracking = "fatal" chip_enable_ble = true + +chip_enable_icd_server = true +chip_persist_subscriptions = true +chip_subscription_timeout_resumption = true diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h b/examples/contact-sensor-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h index 7d435215252b0e..b48b97c55e6f94 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h +++ b/examples/contact-sensor-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h @@ -59,6 +59,11 @@ #define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0x1037 #define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0xA220 +// Set the following define to use the Certification Declaration from below and not use it stored in factory data section +#ifndef CHIP_USE_DEVICE_CONFIG_CERTIFICATION_DECLARATION +#define CHIP_USE_DEVICE_CONFIG_CERTIFICATION_DECLARATION 0 +#endif + #ifndef CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION //-> format_version = 1 //-> vendor_id = 0x1037 @@ -188,8 +193,7 @@ #define CHIP_CONFIG_MAX_FABRICS 5 // 5 is the minimum number of supported fabrics #define CHIP_DEVICE_CONFIG_ENABLE_SED 1 -#define CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL 1000_ms32 -#define CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL 100_ms32 + /** * @def CHIP_IM_MAX_NUM_COMMAND_HANDLER * diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/main/AppTask.cpp b/examples/contact-sensor-app/nxp/k32w/k32w0/main/AppTask.cpp index a3656550b9434c..484ddce1b7ce1b 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/main/AppTask.cpp +++ b/examples/contact-sensor-app/nxp/k32w/k32w0/main/AppTask.cpp @@ -45,6 +45,8 @@ #include #endif +#include "BLEManagerImpl.h" + #include "Keyboard.h" #include "LED.h" #include "LEDWidget.h" @@ -123,6 +125,18 @@ CHIP_ERROR AppTask::StartAppTask() return err; } +static void app_gap_callback(gapGenericEvent_t * event) +{ + /* This callback is called in the context of BLE task, so event processing + * should be posted to app task. */ +} + +static void app_gatt_callback(deviceId_t id, gattServerEvent_t * event) +{ + /* This callback is called in the context of BLE task, so event processing + * should be posted to app task. */ +} + #if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR static void CheckOtaEntry() { @@ -240,6 +254,17 @@ CHIP_ERROR AppTask::Init() K32W_LOG("Current Software Version: %s, %" PRIu32, currentSoftwareVer, currentVersion); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + /* SSBL will always be seen as booting from address 0, thanks to the remapping mechanism. + * This means the SSBL version will always offset from address 0. */ + extern uint32_t __MATTER_SSBL_VERSION_START[]; + K32W_LOG("Current SSBL Version: %ld. Found at address 0x%lx", *((uint32_t *) __MATTER_SSBL_VERSION_START), + (uint32_t) __MATTER_SSBL_VERSION_START); +#endif + + auto & bleManager = chip::DeviceLayer::Internal::BLEMgrImpl(); + bleManager.RegisterAppCallbacks(app_gap_callback, app_gatt_callback); + return err; } diff --git a/examples/contact-sensor-app/nxp/k32w/k32w1/main/AppTask.cpp b/examples/contact-sensor-app/nxp/k32w/k32w1/main/AppTask.cpp index bce7374d7ea7ef..c7acba0f3ee1cb 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w1/main/AppTask.cpp +++ b/examples/contact-sensor-app/nxp/k32w/k32w1/main/AppTask.cpp @@ -46,6 +46,8 @@ #include #endif +#include + #include "K32W1PersistentStorageOpKeystore.h" #include "LEDWidget.h" @@ -106,6 +108,18 @@ static BDXDownloader gDownloader __attribute__((section(".data"))); constexpr uint16_t requestedOtaBlockSize = 1024; #endif +static void app_gap_callback(gapGenericEvent_t * event) +{ + /* This callback is called in the context of BLE task, so event processing + * should be posted to app task. */ +} + +static void app_gatt_callback(deviceId_t id, gattServerEvent_t * event) +{ + /* This callback is called in the context of BLE task, so event processing + * should be posted to app task. */ +} + CHIP_ERROR AppTask::StartAppTask() { CHIP_ERROR err = CHIP_NO_ERROR; @@ -188,6 +202,9 @@ CHIP_ERROR AppTask::Init() K32W_LOG("Current Software Version: %s, %d", currentSoftwareVer, currentVersion); + auto & bleManager = chip::DeviceLayer::Internal::BLEMgrImpl(); + bleManager.RegisterAppCallbacks(app_gap_callback, app_gatt_callback); + return err; } diff --git a/examples/lighting-app/nxp/k32w/k32w0/BUILD.gn b/examples/lighting-app/nxp/k32w/k32w0/BUILD.gn index 2ee2e42a24259e..a71bf63dc6d4e0 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/BUILD.gn +++ b/examples/lighting-app/nxp/k32w/k32w0/BUILD.gn @@ -25,6 +25,7 @@ import("${chip_root}/src/platform/device.gni") declare_args() { chip_software_version = 0 + chip_simple_hash_verification = 0 } if (chip_pw_tokenizer_logging) { @@ -170,6 +171,10 @@ action("binsign") { script = "${k32w0_platform_dir}/scripts/sign-outdir.py" output_name = "bignsign.log" outputs = [ "${root_build_dir}/${output_name}" ] + + if (chip_simple_hash_verification == 1) { + args = [ "--simple-hash" ] + } } group("default") { diff --git a/examples/lighting-app/nxp/k32w/k32w0/README.md b/examples/lighting-app/nxp/k32w/k32w0/README.md index 829d4bd1e70223..b43a08622eb330 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/README.md +++ b/examples/lighting-app/nxp/k32w/k32w0/README.md @@ -457,6 +457,10 @@ SSBL demo application can be imported from the `Quickstart panel`: ![SSBL Application Select](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_select.JPG) +### Features + +#### Multi image + To support multi-image OTA feature, the SSBL project must be compiled using the following defines: @@ -474,6 +478,24 @@ Optionally, add the following defines: ![SSBL_MULTI_IMAGE](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_multi_image.JPG) +#### Simple hash verification + +When secure boot is not used, a simple hash can be appended at the end of the +image for integrity check. Applications should be built with +`chip_simple_hash_verification=1`. + +To support simple hash verification feature, the SSBL project must be compiled +with: + +- `gSimpleHashVerification=1` + +and update the post-build command to use simple hash verification instead of the +default options. Go to +`Project -> Properties -> C/C++ Build -> Settings -> Build steps` and press +`Edit` under `Post-build steps` subsection. The command should look similar to: + +![SSBL_SIMPLE_HASH_VERIFICATION](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_simple_hash.JPG) + Once compiled, the required SSBL file is called `k32w061dk6_ssbl.bin`. ![SSBL_BIN](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_bin.JPG) diff --git a/examples/lighting-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h b/examples/lighting-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h index 63abce6c8c0682..10019a4268cad2 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h +++ b/examples/lighting-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h @@ -59,6 +59,11 @@ #define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0x1037 #define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0xA220 +// Set the following define to use the Certification Declaration from below and not use it stored in factory data section +#ifndef CHIP_USE_DEVICE_CONFIG_CERTIFICATION_DECLARATION +#define CHIP_USE_DEVICE_CONFIG_CERTIFICATION_DECLARATION 0 +#endif + #ifndef CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION //-> format_version = 1 //-> vendor_id = 0x1037 diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp b/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp index 02656ae62299c7..e63c35a1489ee0 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp +++ b/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp @@ -249,6 +249,14 @@ CHIP_ERROR AppTask::Init() K32W_LOG("Current Software Version: %s, %" PRIu32, currentSoftwareVer, currentVersion); +#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR + /* SSBL will always be seen as booting from address 0, thanks to the remapping mechanism. + * This means the SSBL version will always offset from address 0. */ + extern uint32_t __MATTER_SSBL_VERSION_START[]; + K32W_LOG("Current SSBL Version: %ld. Found at address 0x%lx", *((uint32_t *) __MATTER_SSBL_VERSION_START), + (uint32_t) __MATTER_SSBL_VERSION_START); +#endif + return err; } @@ -897,11 +905,24 @@ void AppTask::PostTurnOnActionRequest(int32_t aActor, LightingManager::Action_t void AppTask::PostEvent(const AppEvent * aEvent) { + portBASE_TYPE taskToWake = pdFALSE; if (sAppEventQueue != NULL) { - if (!xQueueSend(sAppEventQueue, aEvent, 1)) + if (__get_IPSR()) { - K32W_LOG("Failed to post event to app task event queue"); + if (!xQueueSendToFrontFromISR(sAppEventQueue, aEvent, &taskToWake)) + { + K32W_LOG("Failed to post event to app task event queue"); + } + + portYIELD_FROM_ISR(taskToWake); + } + else + { + if (!xQueueSend(sAppEventQueue, aEvent, 1)) + { + K32W_LOG("Failed to post event to app task event queue"); + } } } } diff --git a/examples/lock-app/nxp/k32w/k32w0/args.gni b/examples/lock-app/nxp/k32w/k32w0/args.gni index dd8543b45f9f8f..a733921b547e38 100644 --- a/examples/lock-app/nxp/k32w/k32w0/args.gni +++ b/examples/lock-app/nxp/k32w/k32w0/args.gni @@ -21,3 +21,7 @@ k32w0_sdk_target = get_label_info(":sdk", "label_no_toolchain") chip_stack_lock_tracking = "fatal" chip_enable_ble = true + +chip_enable_icd_server = true +chip_persist_subscriptions = true +chip_subscription_timeout_resumption = true diff --git a/examples/lock-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h b/examples/lock-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h index 046b005f78da73..c74714bded920f 100644 --- a/examples/lock-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h +++ b/examples/lock-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h @@ -59,6 +59,11 @@ #define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0x1037 #define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0xA220 +// Set the following define to use the Certification Declaration from below and not use it stored in factory data section +#ifndef CHIP_USE_DEVICE_CONFIG_CERTIFICATION_DECLARATION +#define CHIP_USE_DEVICE_CONFIG_CERTIFICATION_DECLARATION 0 +#endif + #ifndef CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION //-> format_version = 1 //-> vendor_id = 0x1037 @@ -179,8 +184,6 @@ #define CHIP_CONFIG_MAX_FABRICS 5 // 5 is the minimum number of supported fabrics #define CHIP_DEVICE_CONFIG_ENABLE_SED 1 -#define CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL 1000_ms32 -#define CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL 100_ms32 /** * CHIP_CONFIG_EVENT_LOGGING_DEFAULT_IMPORTANCE diff --git a/examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld b/examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld index c7a2e4009865e5..d3ea6ac41daf78 100644 --- a/examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld +++ b/examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld @@ -432,8 +432,13 @@ SECTIONS __StackLimit = _vStackTop - STACK_SIZE; - __FACTORY_DATA_START = FACTORY_DATA_START_ADDRESS; - __FACTORY_DATA_SIZE = m_factory_data_size; + __MATTER_FACTORY_DATA_START = FACTORY_DATA_START_ADDRESS; + __MATTER_FACTORY_DATA_SIZE = m_factory_data_size; + + /* The .ro_version section inside SSBL is set after the .m_interrupts sections, + * which is assumed to never change, so the offset remains the same across different + * SSBL versions. This symbol is used in Matter Application to retrieve the SSBL version. */ + __MATTER_SSBL_VERSION_START = 0x00000120; ASSERT(((m_app_start + m_app_size + m_app_meta_data + m_factory_data_size + m_flash_config_size) <= m_int_flash_size), "Internal flash capacity exceeded") diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_simple_hash.JPG b/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_simple_hash.JPG new file mode 100755 index 00000000000000..9ec701b0bb1d86 Binary files /dev/null and b/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_simple_hash.JPG differ diff --git a/examples/platform/nxp/k32w/k32w0/scripts/sign-outdir.py b/examples/platform/nxp/k32w/k32w0/scripts/sign-outdir.py index 577cc2424fd5b9..dfaf912ae5283d 100644 --- a/examples/platform/nxp/k32w/k32w0/scripts/sign-outdir.py +++ b/examples/platform/nxp/k32w/k32w0/scripts/sign-outdir.py @@ -1,17 +1,36 @@ +import argparse import os import subprocess -if os.environ["NXP_K32W0_SDK_ROOT"] != "": - sign_images_path = os.environ["NXP_K32W0_SDK_ROOT"] + "/tools/imagetool/sign_images.sh" -else: - sign_images_path = os.getcwd() + "/../../../../../../third_party/nxp/k32w0_sdk/repo/core/tools/imagetool/sign_images.sh" -# Give execute permission if needed -if os.access(sign_images_path, os.X_OK) is False: - os.chmod(sign_images_path, 0o766) +def main(args): + if os.environ["NXP_K32W0_SDK_ROOT"] != "": + sign_images_path = os.environ["NXP_K32W0_SDK_ROOT"] + "/tools/imagetool/sign_images.sh" + else: + sign_images_path = os.getcwd() + "/../../../../../../../third_party/nxp/k32w0_sdk/repo/core/tools/imagetool/sign_images.sh" -# Convert script to unix format if needed -subprocess.call("(file " + sign_images_path + " | grep CRLF > /dev/null) && (dos2unix " + sign_images_path + ")", shell=True) + # Give execute permission if needed + if os.access(sign_images_path, os.X_OK) is False: + os.chmod(sign_images_path, 0o766) -# Call sign_images.sh script with the output directory -subprocess.call(sign_images_path + " " + os.getcwd(), shell=True) + # Convert script to unix format if needed + subprocess.call("(file " + sign_images_path + " | grep CRLF > /dev/null) && (dos2unix " + sign_images_path + ")", shell=True) + + # Call sign_images.sh script with the output directory + cmd = sign_images_path + " " + os.getcwd() + if args.simple_hash: + cmd = cmd + " -SimpleHashVerification" + + subprocess.call(cmd, shell=True) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "--simple-hash", + help="When enabled, adds a hash of the whole image at the end of the binary.", + action="store_true" + ) + args = parser.parse_args() + + main(args) diff --git a/scripts/tools/nxp/factory_data_generator/generate.py b/scripts/tools/nxp/factory_data_generator/generate.py index daf1b5d1267cb7..a203ac9dee749e 100755 --- a/scripts/tools/nxp/factory_data_generator/generate.py +++ b/scripts/tools/nxp/factory_data_generator/generate.py @@ -27,6 +27,14 @@ SetupPasscode, StrArgument, UniqueId, VendorId, VendorName, Verifier) from default import InputArgument +# A magic value used in the factory data integrity check. +# The value will be checked at runtime, before verifying the +# factory data integrity. Factory data header has the following format: +# | hash id (4 bytes) | size (4 bytes) | hash (4 bytes) | +# If the hash id check fails, it means the factory data is either missing +# or has become corrupted. +HASH_ID = "CE47BA5E" + def set_logger(): stdout_handler = logging.StreamHandler(stream=sys.stdout) @@ -155,9 +163,9 @@ def to_bin(self, klv, out, aes128_key): fullContentCipher = size.to_bytes(4, "little") + fullContentCipher # Add hash id - hashId = bytearray.fromhex("CE47BA5E") + hashId = bytearray.fromhex(HASH_ID) hashId.reverse() - fullContentCipher = hashId.reverse() + fullContentCipher + fullContentCipher = hashId + fullContentCipher size = len(fullContentCipher) diff --git a/scripts/tools/nxp/generate_certs.py b/scripts/tools/nxp/generate_certs.py new file mode 100644 index 00000000000000..7a98f7138ebe05 --- /dev/null +++ b/scripts/tools/nxp/generate_certs.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import argparse +import logging as log +import os +import subprocess + +MATTER_ROOT = os.path.dirname(os.path.realpath(f"{__file__}/../../../")) + + +def gen_test_certs(chip_cert_exe: str, + output: str, + vendor_id: int, + product_id: int, + device_name: str, + generate_cd: bool = False, + cd_type: int = 1, + device_type: int = 1, + paa_cert_path: str = None, + paa_key_path: str = None, + valid_from: str = "2023-01-01 00:00:00", + lifetime: str = "7305"): + """ + Generate Matter certificates according to given Vendor ID and Product ID using the chip-cert executable. + To use own Product Attestation Authority certificate provide paa_cert_path and paa_key_path arguments. + Without providing these arguments a PAA certificate will be generated in the output directory. + + Args: + chip_cert_exe (str): path to chip-cert executable + output (str): output path to store a newly generated certificates (CD, DAC, PAI) + vendor_id (int): an identification number specific to Vendor + product_id (int): an identification number specific to Product + device_name (str): human-readable device name + generate_cd (bool, optional): Generate Certificate Declaration and store it in the output directory. Defaults to False. + paa_cert_path (str, optional): provide PAA certification path. Defaults to None - the certificate and key will + be generated. + paa_key_path (str, optional): provide PAA key path. Defaults to None - the certificate and key will be generated. + """ + + CD_PATH = MATTER_ROOT + "/credentials/test/certification-declaration/Chip-Test-CD-Signing-Cert.pem" + CD_KEY_PATH = MATTER_ROOT + "/credentials/test/certification-declaration/Chip-Test-CD-Signing-Key.pem" + + log.info("Generating new certificates using chip-cert...") + + if generate_cd: + log.info("Generating Certification Declaration...") + cmd = [chip_cert_exe, "gen-cd", + "--key", CD_KEY_PATH, + "--cert", CD_PATH, + "--out", output + "/Chip-Test-CD-" + f'{vendor_id:X}' + "-" + f'{product_id:X}' + ".der", + "--format-version", "1", + "--vendor-id", hex(vendor_id), + "--product-id", hex(product_id), + "--device-type-id", hex(device_type), + "--certificate-id", "ZIG20142ZB330003-24", + "--security-level", "0", + "--security-info", "0", + "--certification-type", str(cd_type), + "--version-number", "9876", + ] + subprocess.run(cmd) + + new_certificates = { + "PAA_CERT": output + "/Chip-PAA-NXP-Cert", + "PAA_KEY": output + "/Chip-PAA-NXP-Key", + "PAI_CERT": output + "/Chip-PAI-NXP-" + f'{vendor_id:X}' + "-" + f'{product_id:X}' + "-Cert", + "PAI_KEY": output + "/Chip-PAI-NXP-" + f'{vendor_id:X}' + "-" + f'{product_id:X}' + "-Key", + "DAC_CERT": output + "/Chip-DAC-NXP-" + f'{vendor_id:X}' + "-" + f'{product_id:X}' + "-Cert", + "DAC_KEY": output + "/Chip-DAC-NXP-" + f'{vendor_id:X}' + "-" + f'{product_id:X}' + "-Key", + } + + if ((paa_cert_path is None) or (paa_key_path is None)): + log.info("Generating PAA certificate...") + cmd = [ + chip_cert_exe, "gen-att-cert", + "--type", "a", + "--subject-cn", device_name, + "--out", new_certificates["PAA_CERT"] + ".pem", + "--out-key", new_certificates["PAA_KEY"] + ".pem", + "--valid-from", valid_from, + "--lifetime", lifetime + ] + subprocess.run(cmd) + PAA_PATH = new_certificates["PAA_CERT"] + ".pem" + PAA_KEY_PATH = new_certificates["PAA_KEY"] + ".pem" + else: + PAA_PATH = paa_cert_path + PAA_KEY_PATH = paa_key_path + log.info("Using PAA certificate: " + PAA_PATH) + log.info("using PAA key: " + PAA_KEY_PATH) + + log.info("Generating PAI certificate...") + cmd = [ + chip_cert_exe, "gen-att-cert", + "--type", "i", + "--subject-cn", device_name, + "--subject-vid", hex(vendor_id), + "--ca-cert", PAA_PATH, + "--ca-key", PAA_KEY_PATH, + "--out", new_certificates["PAI_CERT"] + ".pem", + "--out-key", new_certificates["PAI_KEY"] + ".pem", + "--valid-from", valid_from, + "--lifetime", lifetime + ] + subprocess.run(cmd) + + log.info("Generating DAC certificate...") + cmd = [ + chip_cert_exe, "gen-att-cert", + "--type", "d", + "--subject-cn", device_name, + "--subject-vid", hex(vendor_id), + "--subject-pid", hex(product_id), + "--ca-cert", new_certificates["PAI_CERT"] + ".pem", + "--ca-key", new_certificates["PAI_KEY"] + ".pem", + "--out", new_certificates["DAC_CERT"] + ".pem", + "--out-key", new_certificates["DAC_KEY"] + ".pem", + "--valid-from", valid_from, + "--lifetime", lifetime + ] + subprocess.run(cmd) + + log.info("Converting to .der files...") + for cert_k, cert_v in new_certificates.items(): + action_type = "convert-cert" if cert_k.find("CERT") != -1 else "convert-key" + log.info(cert_v + ".der") + cmd = [ + chip_cert_exe, + action_type, + "--x509-der", + cert_v + ".pem", + cert_v + ".der", + ] + subprocess.run(cmd) + + +def main(): + parser = argparse.ArgumentParser(description="NXP CHIP Certificates generator") + + def allow_any_int(i): return int(i, 0) + + parser.add_argument("--chip_cert_path", type=str, required=True, + help=("This tool requires a path to chip-cert executable. " + "By default you can find chip-cert in connectedhomeip/src/tools/chip-cert directory " + "and build it there.")) + parser.add_argument("-o", "--output", type=str, required=True, + help="Output path to store certificates, e.g. /path/to/my/dir") + parser.add_argument("--vendor_id", type=allow_any_int, required=True, + help="[int | hex int] Provide Vendor Identification Number") + parser.add_argument("--product_id", type=allow_any_int, required=True, + help="[int | hex int] Provide Product Identification Number") + parser.add_argument("--vendor_name", type=str, required=True, + help="[string] provide human-readable vendor name") + parser.add_argument("--product_name", type=str, required=True, + help="[string] provide human-readable product name") + parser.add_argument("--gen_cd", action="store_true", default=False, + help=("Generate a new Certificate Declaration in .der format according to used Vendor ID " + "and Product ID.")) + parser.add_argument("--cd_type", type=int, default=1, + help=("[int] Type of generated Certification Declaration: " + "0 - development, 1 - provisional, 2 - official")) + parser.add_argument("--device_type", type=int, default=0, + help=("[int] Provides the primary device type implemented by the node. " + "This must be one of the device type identifiers defined in the Matter Device Library " + "specification.")) + parser.add_argument("--paa_cert", type=str, + help=("Provide a path to the Product Attestation Authority (PAA) certificate to generate " + "the PAI certificate. Without providing it, a testing PAA certificate will be generated.")) + parser.add_argument("--paa_key", type=str, + help=("Provide a path to the Product Attestation Authority (PAA) key to generate " + "the PAI certificate. Without providing it, a testing PAA key will be generated.")) + parser.add_argument("--valid_from", type=str, default="2023-01-01 00:00:00", + help=("The start date for the certificate's validity period in" + "--
[ :: ] format. Default to 2023-01-01 00:00:00")) + parser.add_argument("--lifetime", type=str, default="7305", + help=("The lifetime for the new certificate, in whole days. Default to 7305 days.")) + args = parser.parse_args() + + log.basicConfig(format='[%(levelname)s] %(message)s', level=log.INFO) + + gen_test_certs(args.chip_cert_path, + args.output, + args.vendor_id, + args.product_id, + args.vendor_name + " " + args.product_name, + args.gen_cd, + args.cd_type, + args.device_type, + args.paa_cert, + args.paa_key, + args.valid_from, + args.lifetime) + + +if __name__ == "__main__": + main() diff --git a/scripts/tools/nxp/ota/crypto_utils.py b/scripts/tools/nxp/ota/crypto_utils.py new file mode 100755 index 00000000000000..dbab140cf57cf9 --- /dev/null +++ b/scripts/tools/nxp/ota/crypto_utils.py @@ -0,0 +1,487 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2023 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +""" +A pure python (slow) implementation of rijndael with a decent interface + +To include - + +from rijndael import rijndael + +To do a key setup - + +r = rijndael(key, block_size = 16) + +key must be a string of length 16, 24, or 32 +blocksize must be 16, 24, or 32. Default is 16 + +To use - + +ciphertext = r.encrypt(plaintext) +plaintext = r.decrypt(ciphertext) + +If any strings are of the wrong length a ValueError is thrown +""" +# ported from the Java reference code by Bram Cohen, April 2001 +# this code is public domain, unless someone makes +# an intellectual property claim against the reference +# code, in which case it can be made public domain by +# deleting all the comments and renaming all the variables + +import copy +import logging +import struct + +shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]], + [[0, 0], [1, 5], [2, 4], [3, 3]], + [[0, 0], [1, 7], [3, 5], [4, 4]]] + +# [keysize][block_size] +num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}} + +A = [[1, 1, 1, 1, 1, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 0], + [0, 0, 0, 1, 1, 1, 1, 1], + [1, 0, 0, 0, 1, 1, 1, 1], + [1, 1, 0, 0, 0, 1, 1, 1], + [1, 1, 1, 0, 0, 0, 1, 1], + [1, 1, 1, 1, 0, 0, 0, 1]] + +# produce log and alog tables, needed for multiplying in the +# field GF(2^m) (generator = 3) +alog = [1] +for i in range(255): + j = (alog[-1] << 1) ^ alog[-1] + if j & 0x100 != 0: + j ^= 0x11B + alog.append(j) + +log = [0] * 256 +for i in range(1, 255): + log[alog[i]] = i + + +# multiply two elements of GF(2^m) +def mul(a, b): + if a == 0 or b == 0: + return 0 + return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255] # noqa: F821 + + +# substitution box based on F^{-1}(x) +box = [[0] * 8 for i in range(256)] +box[1][7] = 1 +for i in range(2, 256): + j = alog[255 - log[i]] + for t in range(8): + box[i][t] = (j >> (7 - t)) & 0x01 + +B = [0, 1, 1, 0, 0, 0, 1, 1] + +# affine transform: box[i] <- B + A*box[i] +cox = [[0] * 8 for i in range(256)] +for i in range(256): + for t in range(8): + cox[i][t] = B[t] + for j in range(8): + cox[i][t] ^= A[t][j] * box[i][j] + +# S-boxes and inverse S-boxes +S = [0] * 256 +Si = [0] * 256 +for i in range(256): + S[i] = cox[i][0] << 7 + for t in range(1, 8): + S[i] ^= cox[i][t] << (7-t) + Si[S[i] & 0xFF] = i + +# T-boxes +G = [[2, 1, 1, 3], + [3, 2, 1, 1], + [1, 3, 2, 1], + [1, 1, 3, 2]] + +AA = [[0] * 8 for i in range(4)] + +for i in range(4): + for j in range(4): + AA[i][j] = G[i][j] + AA[i][i+4] = 1 + +for i in range(4): + pivot = AA[i][i] + if pivot == 0: + t = i + 1 + while AA[t][i] == 0 and t < 4: + t += 1 + assert t != 4, 'G matrix must be invertible' + for j in range(8): + AA[i][j], AA[t][j] = AA[t][j], AA[i][j] + pivot = AA[i][i] + for j in range(8): + if AA[i][j] != 0: + AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255] + for t in range(4): + if i != t: + for j in range(i+1, 8): + AA[t][j] ^= mul(AA[i][j], AA[t][i]) + AA[t][i] = 0 + +iG = [[0] * 4 for i in range(4)] + +for i in range(4): + for j in range(4): + iG[i][j] = AA[i][j + 4] + + +def mul4(a, bs): + if a == 0: + return 0 + r = 0 + for b in bs: + r <<= 8 + if b != 0: + r = r | mul(a, b) # noqa: F821 + return r + + +T1 = [] +T2 = [] +T3 = [] +T4 = [] +T5 = [] +T6 = [] +T7 = [] +T8 = [] +U1 = [] +U2 = [] +U3 = [] +U4 = [] + +for t in range(256): + s = S[t] + T1.append(mul4(s, G[0])) + T2.append(mul4(s, G[1])) + T3.append(mul4(s, G[2])) + T4.append(mul4(s, G[3])) + + s = Si[t] + T5.append(mul4(s, iG[0])) + T6.append(mul4(s, iG[1])) + T7.append(mul4(s, iG[2])) + T8.append(mul4(s, iG[3])) + + U1.append(mul4(t, iG[0])) + U2.append(mul4(t, iG[1])) + U3.append(mul4(t, iG[2])) + U4.append(mul4(t, iG[3])) + +# round constants +rcon = [1] +r = 1 +for t in range(1, 30): + r = mul(2, r) + rcon.append(r) + +del A +del AA +del pivot +del B +del G +del box +del log +del alog +del i +del j +del r +del s +del t +del mul +del mul4 +del cox +del iG + + +class rijndael: + def __init__(self, key, block_size=16): + if block_size != 16 and block_size != 24 and block_size != 32: + raise ValueError('Invalid block size: ' + str(block_size)) + if len(key) != 16 and len(key) != 24 and len(key) != 32: + raise ValueError('Invalid key size: ' + str(len(key))) + self.block_size = block_size + + ROUNDS = num_rounds[len(key)][block_size] + BC = int(block_size / 4) + + # encryption round keys + Ke = [[0] * BC for i in range(ROUNDS + 1)] + # decryption round keys + Kd = [[0] * BC for i in range(ROUNDS + 1)] + ROUND_KEY_COUNT = (ROUNDS + 1) * BC + KC = int(len(key) / 4) + + # copy user material bytes into temporary ints + tk = [] + for i in range(0, KC): + tk.append((key[i * 4] << 24) | (key[i * 4 + 1] << 16) | + (key[i * 4 + 2] << 8) | key[i * 4 + 3]) + + # copy values into round key arrays + t = 0 + j = 0 + while j < KC and t < ROUND_KEY_COUNT: + Ke[int(t / BC)][t % BC] = tk[j] + Kd[ROUNDS - int(t / BC)][t % BC] = tk[j] + j += 1 + t += 1 + tt = 0 + rconpointer = 0 + while t < ROUND_KEY_COUNT: + # extrapolate using phi (the round key evolution function) + tt = tk[KC - 1] + tk[0] ^= (S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^ \ + (S[(tt >> 8) & 0xFF] & 0xFF) << 16 ^ \ + (S[tt & 0xFF] & 0xFF) << 8 ^ \ + (S[(tt >> 24) & 0xFF] & 0xFF) ^ \ + (rcon[rconpointer] & 0xFF) << 24 + rconpointer += 1 + if KC != 8: + for i in range(1, KC): + tk[i] ^= tk[i-1] + else: + for i in range(1, KC / 2): + tk[i] ^= tk[i-1] + tt = tk[KC / 2 - 1] + tk[KC / 2] ^= (S[tt & 0xFF] & 0xFF) ^ \ + (S[(tt >> 8) & 0xFF] & 0xFF) << 8 ^ \ + (S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \ + (S[(tt >> 24) & 0xFF] & 0xFF) << 24 + for i in range(KC / 2 + 1, KC): + tk[i] ^= tk[i-1] + # copy values into round key arrays + j = 0 + while j < KC and t < ROUND_KEY_COUNT: + Ke[int(t / BC)][t % BC] = tk[j] + Kd[ROUNDS - int(t / BC)][t % BC] = tk[j] + j += 1 + t += 1 + # inverse MixColumn where needed + for r in range(1, ROUNDS): + for j in range(BC): + tt = Kd[r][j] + Kd[r][j] = U1[(tt >> 24) & 0xFF] ^ \ + U2[(tt >> 16) & 0xFF] ^ \ + U3[(tt >> 8) & 0xFF] ^ \ + U4[tt & 0xFF] + self.Ke = Ke + self.Kd = Kd + + def encrypt(self, plaintext): + if len(plaintext) != self.block_size: + raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext))) + Ke = self.Ke + + BC = int(self.block_size / 4) + ROUNDS = len(Ke) - 1 + if BC == 4: + SC = 0 + elif BC == 6: + SC = 1 + else: + SC = 2 + s1 = shifts[SC][1][0] + s2 = shifts[SC][2][0] + s3 = shifts[SC][3][0] + a = [0] * BC + # temporary work array + t = [] + # plaintext to ints + key + for i in range(BC): + t.append((ord(plaintext[i * 4]) << 24 | + ord(plaintext[i * 4 + 1]) << 16 | + ord(plaintext[i * 4 + 2]) << 8 | + ord(plaintext[i * 4 + 3])) ^ Ke[0][i]) + # apply round transforms + for r in range(1, ROUNDS): + for i in range(BC): + a[i] = (T1[(t[i] >> 24) & 0xFF] ^ + T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^ + T3[(t[(i + s2) % BC] >> 8) & 0xFF] ^ + T4[t[(i + s3) % BC] & 0xFF]) ^ Ke[r][i] + t = copy.copy(a) + # last round is special + result = [] + for i in range(BC): + tt = Ke[ROUNDS][i] + result.append((S[(t[i] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((S[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((S[t[(i + s3) % BC] & 0xFF] ^ tt) & 0xFF) + return ''.join(list(map(chr, result))) + + def decrypt(self, ciphertext): + if len(ciphertext) != self.block_size: + raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(ciphertext))) + Kd = self.Kd + + BC = int(self.block_size / 4) + ROUNDS = len(Kd) - 1 + if BC == 4: + SC = 0 + elif BC == 6: + SC = 1 + else: + SC = 2 + s1 = shifts[SC][1][1] + s2 = shifts[SC][2][1] + s3 = shifts[SC][3][1] + a = [0] * BC + # temporary work array + t = [0] * BC + # ciphertext to ints + key + for i in range(BC): + t[i] = (ord(ciphertext[i * 4]) << 24 | + ord(ciphertext[i * 4 + 1]) << 16 | + ord(ciphertext[i * 4 + 2]) << 8 | + ord(ciphertext[i * 4 + 3])) ^ Kd[0][i] + # apply round transforms + for r in range(1, ROUNDS): + for i in range(BC): + a[i] = (T5[(t[i] >> 24) & 0xFF] ^ + T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^ + T7[(t[(i + s2) % BC] >> 8) & 0xFF] ^ + T8[t[(i + s3) % BC] & 0xFF]) ^ Kd[r][i] + t = copy.copy(a) + # last round is special + result = [] + for i in range(BC): + tt = Kd[ROUNDS][i] + result.append((Si[(t[i] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((Si[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((Si[t[(i + s3) % BC] & 0xFF] ^ tt) & 0xFF) + return ''.join(map(chr, result)) + + +def encryptFlashData(nonce, key, data, imageLen): + encyptedBlock = '' + if (imageLen % 16) != 0: + for x in range(16 - (imageLen % 16)): + data = data + bytes([255]) + imageLen = len(data) + + r = rijndael(key, block_size=16) + + for x in range(int(imageLen / 16)): + # use nonce value to create encrypted chunk + encryptNonce = '' + for i in nonce: + tempString = "%08x" % i + y = 0 + while y < 8: + encryptNonce = encryptNonce + chr(int(tempString[y:y+2], 16)) + y = y + 2 + encChunk = r.encrypt(encryptNonce) + + # increment the nonce value + if (nonce[3] == 0xffffffff): + nonce[3] = 0 + else: + nonce[3] += 1 + + # xor encypted junk with data chunk + chunk = data[x*16:(x+1)*16] # Read 16 byte chucks. 128 bits + + lchunk = chunk + lencChunk = list(map(ord, encChunk)) + + loutChunk = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + for i in range(16): + loutChunk[i] = lchunk[i] ^ lencChunk[i] + encyptedBlock = encyptedBlock + chr(lchunk[i] ^ lencChunk[i]) + + return (encyptedBlock) + + +def aParsePassKeyString(sPassKey): + lstu32Passkey = [0, 0, 0, 0] + + try: + lstStrPassKey = sPassKey.split(",") + + except Exception: + sPassKey = "0x00000000, 0x00000000, 0x00000000, 0x00000000" + lstStrPassKey = sPassKey.split(",") + + if len(lstStrPassKey) == 4: + for i in range(4): + if "0x" in lstStrPassKey[i]: + lstu32Passkey[i] = int(lstStrPassKey[i], 16) + else: + lstu32Passkey[i] = int(lstStrPassKey[i], 10) + + logging.info(f"\t-key: {lstu32Passkey[0]}, {lstu32Passkey[1]}, {lstu32Passkey[2]}, {lstu32Passkey[3]}") + abEncryptKey = struct.pack(">LLLL", lstu32Passkey[0], + lstu32Passkey[1], + lstu32Passkey[2], + lstu32Passkey[3]) + return abEncryptKey + + +def aParseNonce(sNonceValue): + lstu32Nonce = [0, 0, 0, 0] + + try: + lstStrNonce = sNonceValue.split(",") + + except Exception: + sNonceValue = "0x00000000, 0x00000000, 0x00000000, 0x00000000" + lstStrNonce = sNonceValue.split(",") + + if len(lstStrNonce) == 4: + for i in range(4): + if "0x" in lstStrNonce[i]: + lstu32Nonce[i] = int(lstStrNonce[i], 16) + else: + lstu32Nonce[i] = int(lstStrNonce[i], 10) + + logging.info(f"Nonce : {lstu32Nonce[0]}, {lstu32Nonce[1]}, {lstu32Nonce[2]}, {lstu32Nonce[3]}") + + return lstu32Nonce + + +def encryptData(sSrcData, sPassKey, aPassIv): + + sKeyString = sPassKey.strip() + assert len(sKeyString) == 32, 'the length of encryption key should be equal to 32' + sPassString = "0x" + sKeyString[:8] + ',' + "0x" + sKeyString[8:16] + \ + ',' + "0x" + sKeyString[16:24] + ',' + "0x" + sKeyString[24:32] + aPassKey = aParsePassKeyString(sPassString) + + sIvString = aPassIv.strip() + sPassString = "0x" + sIvString[:8] + ',' + "0x" + sIvString[8:16] + \ + ',' + "0x" + sIvString[16:24] + ',' + "0x" + sIvString[24:32] + aNonce = aParseNonce(sPassString) + + logging.info("Started Encrypting with key[{}] ......".format(sPassKey)) + + encryptedData = encryptFlashData(aNonce, aPassKey, sSrcData, len(sSrcData)) + + logging.info("Done") + + return encryptedData diff --git a/scripts/tools/nxp/ota/ota_image_tool.py b/scripts/tools/nxp/ota/ota_image_tool.py index bf796f1010119f..64715d784aeecd 100755 --- a/scripts/tools/nxp/ota/ota_image_tool.py +++ b/scripts/tools/nxp/ota/ota_image_tool.py @@ -36,6 +36,7 @@ import os import sys +import crypto_utils import jsonschema sys.path.insert(0, os.path.join( @@ -55,6 +56,8 @@ OTA_BOOTLOADER_TLV_TEMP = os.path.join(os.path.dirname(__file__), "ota_temp_ssbl_tlv.bin") OTA_FACTORY_TLV_TEMP = os.path.join(os.path.dirname(__file__), "ota_temp_factory_tlv.bin") +INITIALIZATION_VECTOR = "00000010111213141516171800000000" + class TAG: APPLICATION = 1 @@ -92,8 +95,15 @@ def generate_factory_data(args: object): if fields: writer = TLVWriter() writer.put(None, fields) - payload = generate_header(TAG.FACTORY_DATA, len(writer.encoding)) - payload += writer.encoding + logging.info(f"factory data encryption enable: {args.enc_enable}") + if args.enc_enable: + enc_factory_data = crypto_utils.encryptData(writer.encoding, args.input_ota_key, INITIALIZATION_VECTOR) + enc_factory_data1 = bytes([ord(x) for x in enc_factory_data]) + payload = generate_header(TAG.FACTORY_DATA, len(enc_factory_data1)) + payload += enc_factory_data1 + else: + payload = generate_header(TAG.FACTORY_DATA, len(writer.encoding)) + payload += writer.encoding write_to_temp(OTA_FACTORY_TLV_TEMP, payload) @@ -126,12 +136,23 @@ def generate_app(args: object): logging.info("App descriptor information:") descriptor = generate_descriptor(args.app_version, args.app_version_str, args.app_build_date) - file_size = os.path.getsize(args.app_input_file) - payload = generate_header(TAG.APPLICATION, len(descriptor) + file_size) + descriptor + logging.info(f"App encryption enable: {args.enc_enable}") + if args.enc_enable: + inputFile = open(args.app_input_file, "rb") + enc_file = crypto_utils.encryptData(inputFile.read(), args.input_ota_key, INITIALIZATION_VECTOR) + enc_file1 = bytes([ord(x) for x in enc_file]) + file_size = len(enc_file1) + payload = generate_header(TAG.APPLICATION, len(descriptor) + file_size) + descriptor + enc_file1 + else: + file_size = os.path.getsize(args.app_input_file) + logging.info(f"file size: {file_size}") + payload = generate_header(TAG.APPLICATION, len(descriptor) + file_size) + descriptor write_to_temp(OTA_APP_TLV_TEMP, payload) - - return [OTA_APP_TLV_TEMP, args.app_input_file] + if args.enc_enable: + return [OTA_APP_TLV_TEMP] + else: + return [OTA_APP_TLV_TEMP, args.app_input_file] def generate_bootloader(args: object): @@ -141,12 +162,23 @@ def generate_bootloader(args: object): logging.info("SSBL descriptor information:") descriptor = generate_descriptor(args.bl_version, args.bl_version_str, args.bl_build_date) - file_size = os.path.getsize(args.bl_input_file) - payload = generate_header(TAG.BOOTLOADER, len(descriptor) + file_size) + descriptor + logging.info(f"Bootloader encryption enable: {args.enc_enable}") + if args.enc_enable: + inputFile = open(args.bl_input_file, "rb") + enc_file = crypto_utils.encryptData(inputFile.read(), args.input_ota_key, INITIALIZATION_VECTOR) + enc_file1 = bytes([ord(x) for x in enc_file]) + file_size = len(enc_file1) + payload = generate_header(TAG.BOOTLOADER, len(descriptor) + file_size) + descriptor + enc_file1 + else: + file_size = os.path.getsize(args.bl_input_file) + logging.info(f"file size: {file_size}") + payload = generate_header(TAG.BOOTLOADER, len(descriptor) + file_size) + descriptor write_to_temp(OTA_BOOTLOADER_TLV_TEMP, payload) - - return [OTA_BOOTLOADER_TLV_TEMP, args.bl_input_file] + if args.enc_enable: + return [OTA_BOOTLOADER_TLV_TEMP] + else: + return [OTA_BOOTLOADER_TLV_TEMP, args.bl_input_file] def validate_json(data: str): @@ -231,6 +263,9 @@ def create_image(args: object): for filename in glob.glob(os.path.dirname(__file__) + "/ota_temp_*"): os.remove(filename) + if args.enc_enable: + for filename in glob.glob(os.path.dirname(__file__) + "/enc_ota_temp_*"): + os.remove(filename) def main(): @@ -302,6 +337,10 @@ def any_base_int(s): return int(s, 0) # Path to input JSON file which describes custom TLVs. create_parser.add_argument('--json', help="[path] Path to the JSON describing custom TLVs") + create_parser.add_argument('--enc_enable', action="store_true", help='enable ota encryption') + create_parser.add_argument('--input_ota_key', type=str, default="1234567890ABCDEFA1B2C3D4E5F6F1B4", + help='Input OTA Encryption KEY (string:16Bytes)') + create_parser.add_argument('-i', '--input_files', default=list(), help='Path to input image payload file') create_parser.add_argument('output_file', help='Path to output image file') diff --git a/src/platform/nxp/k32w/common/BLEManagerCommon.cpp b/src/platform/nxp/k32w/common/BLEManagerCommon.cpp index 65b2f68cb20e90..5d20035aa99940 100644 --- a/src/platform/nxp/k32w/common/BLEManagerCommon.cpp +++ b/src/platform/nxp/k32w/common/BLEManagerCommon.cpp @@ -172,11 +172,11 @@ CHIP_ERROR BLEManagerCommon::_Init() xTimerCreate("bleTimeoutTmr", pdMS_TO_TICKS(CHIP_BLE_KW_CONN_TIMEOUT), pdFALSE, (void *) 0, blekw_connection_timeout_cb); VerifyOrExit(connectionTimeout != NULL, err = CHIP_ERROR_INCORRECT_STATE); + sImplInstance = GetImplInstance(); + /* BLE platform code initialization */ SuccessOrExit(err = InitHostController(&blekw_generic_cb)); - sImplInstance = GetImplInstance(); - /* Register the GATT server callback */ VerifyOrExit(GattServer_RegisterCallback(blekw_gatt_server_cb) == gBleSuccess_c, err = CHIP_ERROR_INCORRECT_STATE); @@ -914,6 +914,13 @@ void BLEManagerCommon::DoBleProcessing(void) } } +void BLEManagerCommon::RegisterAppCallbacks(BLECallbackDelegate::GapGenericCallback gapCallback, + BLECallbackDelegate::GattServerCallback gattCallback) +{ + callbackDelegate.gapCallback = gapCallback; + callbackDelegate.gattCallback = gattCallback; +} + void BLEManagerCommon::HandleConnectEvent(blekw_msg_t * msg) { uint8_t deviceId = msg->data.u8; @@ -1078,6 +1085,11 @@ void BLEManagerCommon::blekw_generic_cb(gapGenericEvent_t * pGenericEvent) /* Call BLE Conn Manager */ BleConnManager_GenericEvent(pGenericEvent); + if (sImplInstance->callbackDelegate.gapCallback) + { + sImplInstance->callbackDelegate.gapCallback(pGenericEvent); + } + switch (pGenericEvent->eventType) { case gInternalError_c: @@ -1162,6 +1174,9 @@ void BLEManagerCommon::blekw_gap_connection_cb(deviceId_t deviceId, gapConnectio if (pConnectionEvent->eventType == gConnEvtConnected_c) { +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + PWR_DisallowDeviceToSleep(); +#endif #if CHIP_DEVICE_CONFIG_BLE_SET_PHY_2M_REQ ChipLogProgress(DeviceLayer, "BLE K32W: Trying to set the PHY to 2M"); @@ -1220,6 +1235,11 @@ void BLEManagerCommon::blekw_stop_connection_timeout(void) void BLEManagerCommon::blekw_gatt_server_cb(deviceId_t deviceId, gattServerEvent_t * pServerEvent) { + if (sImplInstance->callbackDelegate.gattCallback) + { + sImplInstance->callbackDelegate.gattCallback(deviceId, pServerEvent); + } + switch (pServerEvent->eventType) { case gEvtMtuChanged_c: { diff --git a/src/platform/nxp/k32w/common/BLEManagerCommon.h b/src/platform/nxp/k32w/common/BLEManagerCommon.h index d8a6561e50b380..32ccdd762cdea4 100644 --- a/src/platform/nxp/k32w/common/BLEManagerCommon.h +++ b/src/platform/nxp/k32w/common/BLEManagerCommon.h @@ -45,10 +45,20 @@ namespace chip { namespace DeviceLayer { namespace Internal { -typedef void (*ble_generic_cb_fp)(gapGenericEvent_t * pGenericEvent); - using namespace chip::Ble; +/** + * A delegate class that can be used by the application to subscribe to BLE events. + */ +struct BLECallbackDelegate +{ + using GapGenericCallback = void (*)(gapGenericEvent_t * event); + using GattServerCallback = void (*)(deviceId_t id, gattServerEvent_t * event); + + GapGenericCallback gapCallback = nullptr; + GattServerCallback gattCallback = nullptr; +}; + /** * Base class for different platform implementations (K32W0 and K32W1 for now). */ @@ -221,9 +231,13 @@ class BLEManagerCommon : public BLEManager, protected BleLayer, private BlePlatf static bool blekw_stop_connection_internal(BLE_CONNECTION_OBJECT conId); public: - virtual CHIP_ERROR InitHostController(ble_generic_cb_fp cb_fp) = 0; - virtual BLEManagerCommon * GetImplInstance() = 0; + virtual CHIP_ERROR InitHostController(BLECallbackDelegate::GapGenericCallback cb_fp) = 0; + virtual BLEManagerCommon * GetImplInstance() = 0; void DoBleProcessing(void); + + BLECallbackDelegate callbackDelegate; + void RegisterAppCallbacks(BLECallbackDelegate::GapGenericCallback gapCallback, + BLECallbackDelegate::GattServerCallback gattCallback); }; inline BLEManager::CHIPoBLEServiceMode BLEManagerCommon::_GetCHIPoBLEServiceMode(void) diff --git a/src/platform/nxp/k32w/common/CHIPDevicePlatformRamStorageConfig.h b/src/platform/nxp/k32w/common/CHIPDevicePlatformRamStorageConfig.h index 58c1c73bba5b73..33c68807ca7af9 100644 --- a/src/platform/nxp/k32w/common/CHIPDevicePlatformRamStorageConfig.h +++ b/src/platform/nxp/k32w/common/CHIPDevicePlatformRamStorageConfig.h @@ -145,3 +145,14 @@ #define kNvmId_FactoryDataBackup (uint16_t) 0x7000 #endif #endif // CONFIG_CHIP_LOAD_REAL_FACTORY_DATA + +/** + * @def kKVS_RamBufferSize + * + * Size of KVS values RAM storage buffer. + * This value is empirical, based on some minimal resource requirements tests. + * Applications should overwrite this value if necessary. + */ +#ifndef kKVS_RamBufferSize +#define kKVS_RamBufferSize (12 * 1024) +#endif diff --git a/src/platform/nxp/k32w/common/FactoryDataProvider.cpp b/src/platform/nxp/k32w/common/FactoryDataProvider.cpp index 98bb1653210601..315811cbf32442 100644 --- a/src/platform/nxp/k32w/common/FactoryDataProvider.cpp +++ b/src/platform/nxp/k32w/common/FactoryDataProvider.cpp @@ -40,8 +40,8 @@ static constexpr size_t kSpake2pSerializedVerifier_MaxBase64Len = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_VerifierSerialized_Length) + 1; static constexpr size_t kSpake2pSalt_MaxBase64Len = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length) + 1; -uint32_t FactoryDataProvider::kFactoryDataStart = (uint32_t) __FACTORY_DATA_START; -uint32_t FactoryDataProvider::kFactoryDataSize = (uint32_t) __FACTORY_DATA_SIZE; +uint32_t FactoryDataProvider::kFactoryDataStart = (uint32_t) __MATTER_FACTORY_DATA_START; +uint32_t FactoryDataProvider::kFactoryDataSize = (uint32_t) __MATTER_FACTORY_DATA_SIZE; uint32_t FactoryDataProvider::kFactoryDataPayloadStart = kFactoryDataStart + sizeof(FactoryDataProvider::Header); FactoryDataProvider::FactoryDataProvider() @@ -123,11 +123,17 @@ CHIP_ERROR FactoryDataProvider::SearchForId(uint8_t searchedType, uint8_t * pBuf CHIP_ERROR FactoryDataProvider::GetCertificationDeclaration(MutableByteSpan & outBuffer) { +#if CHIP_USE_DEVICE_CONFIG_CERTIFICATION_DECLARATION + constexpr uint8_t kCdForAllExamples[] = CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION; + + return CopySpanToMutableSpan(ByteSpan{ kCdForAllExamples }, outBuffer); +#else uint16_t declarationSize = 0; ReturnErrorOnFailure(SearchForId(FactoryDataId::kCertDeclarationId, outBuffer.data(), outBuffer.size(), declarationSize)); outBuffer.reduce_size(declarationSize); return CHIP_NO_ERROR; +#endif } CHIP_ERROR FactoryDataProvider::GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) diff --git a/src/platform/nxp/k32w/common/FactoryDataProvider.h b/src/platform/nxp/k32w/common/FactoryDataProvider.h index db10a8f6accb23..99b9a1e039cf34 100644 --- a/src/platform/nxp/k32w/common/FactoryDataProvider.h +++ b/src/platform/nxp/k32w/common/FactoryDataProvider.h @@ -26,8 +26,8 @@ #include "CHIPPlatformConfig.h" /* Grab symbol for the base address from the linker file. */ -extern uint32_t __FACTORY_DATA_START[]; -extern uint32_t __FACTORY_DATA_SIZE[]; +extern uint32_t __MATTER_FACTORY_DATA_START[]; +extern uint32_t __MATTER_FACTORY_DATA_SIZE[]; namespace chip { namespace DeviceLayer { diff --git a/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp b/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp index 16493144c632be..c80bf64eaa357b 100644 --- a/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp +++ b/src/platform/nxp/k32w/common/OTAImageProcessorImpl.cpp @@ -28,7 +28,7 @@ using namespace chip::DeviceLayer; using namespace ::chip::DeviceLayer::Internal; -#if USE_SMU2_AS_SYSTEM_MEMORY +#if USE_SMU2_STATIC // The attribute specifier should not be changed. static chip::OTAImageProcessorImpl gImageProcessor __attribute__((section(".smu2"))); #else diff --git a/src/platform/nxp/k32w/common/OTATlvProcessor.cpp b/src/platform/nxp/k32w/common/OTATlvProcessor.cpp index 40b068b446ead5..7571e693728c00 100644 --- a/src/platform/nxp/k32w/common/OTATlvProcessor.cpp +++ b/src/platform/nxp/k32w/common/OTATlvProcessor.cpp @@ -22,9 +22,15 @@ #include #include - +#if OTA_ENCRYPTION_ENABLE +#include "OtaUtils.h" +#include "rom_aes.h" +#endif namespace chip { +#if OTA_ENCRYPTION_ENABLE +constexpr uint8_t au8Iv[] = { 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x00, 0x00, 0x00 }; +#endif CHIP_ERROR OTATlvProcessor::Process(ByteSpan & block) { CHIP_ERROR status = CHIP_NO_ERROR; @@ -57,6 +63,9 @@ void OTATlvProcessor::ClearInternal() mLength = 0; mProcessedLength = 0; mWasSelected = false; +#if OTA_ENCRYPTION_ENABLE + mIVOffset = 0; +#endif } bool OTATlvProcessor::IsError(CHIP_ERROR & status) @@ -93,4 +102,75 @@ CHIP_ERROR OTADataAccumulator::Accumulate(ByteSpan & block) return CHIP_NO_ERROR; } +#if OTA_ENCRYPTION_ENABLE +CHIP_ERROR OTATlvProcessor::vOtaProcessInternalEncryption(MutableByteSpan & block) +{ + uint8_t iv[16]; + uint8_t key[16]; + uint8_t dataOut[16] = { 0 }; + uint32_t u32IVCount; + uint32_t Offset = 0; + uint8_t data; + tsReg128 sKey; + aesContext_t Context; + + memcpy(iv, au8Iv, sizeof(au8Iv)); + + u32IVCount = (((uint32_t) iv[12]) << 24) | (((uint32_t) iv[13]) << 16) | (((uint32_t) iv[14]) << 8) | (iv[15]); + u32IVCount += (mIVOffset >> 4); + + iv[12] = (uint8_t) ((u32IVCount >> 24) & 0xff); + iv[13] = (uint8_t) ((u32IVCount >> 16) & 0xff); + iv[14] = (uint8_t) ((u32IVCount >> 8) & 0xff); + iv[15] = (uint8_t) (u32IVCount & 0xff); + + size_t len = strlen(OTA_ENCRYPTION_KEY); + + if (len != 32) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + for (size_t i = 0; i < len; i += 2) + { + char hex[3] = { OTA_ENCRYPTION_KEY[i], OTA_ENCRYPTION_KEY[i + 1], '\0' }; + key[i / 2] = (uint8_t) strtol(hex, NULL, 16); + } + ByteSpan KEY = ByteSpan(key); + Encoding::LittleEndian::Reader reader_key(KEY.data(), KEY.size()); + ReturnErrorOnFailure(reader_key.Read32(&sKey.u32register0) + .Read32(&sKey.u32register1) + .Read32(&sKey.u32register2) + .Read32(&sKey.u32register3) + .StatusCode()); + + while (Offset + 16 <= block.size()) + { + /*Encrypt the IV*/ + Context.mode = AES_MODE_ECB_ENCRYPT; + Context.pSoftwareKey = (uint32_t *) &sKey; + AES_128_ProcessBlocks(&Context, (uint32_t *) &iv[0], (uint32_t *) &dataOut[0], 1); + + /* Decrypt a block of the buffer */ + for (uint8_t i = 0; i < 16; i++) + { + data = block[Offset + i] ^ dataOut[i]; + memcpy(&block[Offset + i], &data, sizeof(uint8_t)); + } + + /* increment the IV for the next block */ + u32IVCount++; + + iv[12] = (uint8_t) ((u32IVCount >> 24) & 0xff); + iv[13] = (uint8_t) ((u32IVCount >> 16) & 0xff); + iv[14] = (uint8_t) ((u32IVCount >> 8) & 0xff); + iv[15] = (uint8_t) (u32IVCount & 0xff); + + Offset += 16; /* increment the buffer offset */ + mIVOffset += 16; + } + + return CHIP_NO_ERROR; +} +#endif } // namespace chip diff --git a/src/platform/nxp/k32w/common/OTATlvProcessor.h b/src/platform/nxp/k32w/common/OTATlvProcessor.h index 1968f983eda14b..e412e1cdd1c5fa 100644 --- a/src/platform/nxp/k32w/common/OTATlvProcessor.h +++ b/src/platform/nxp/k32w/common/OTATlvProcessor.h @@ -90,6 +90,9 @@ class OTATlvProcessor void SetLength(uint32_t length) { mLength = length; } void SetWasSelected(bool selected) { mWasSelected = selected; } bool WasSelected() { return mWasSelected; } +#if OTA_ENCRYPTION_ENABLE + CHIP_ERROR vOtaProcessInternalEncryption(MutableByteSpan & block); +#endif protected: /** @@ -121,6 +124,10 @@ class OTATlvProcessor bool IsError(CHIP_ERROR & status); +#if OTA_ENCRYPTION_ENABLE + /*ota decryption*/ + uint32_t mIVOffset = 0; +#endif uint32_t mLength = 0; uint32_t mProcessedLength = 0; bool mWasSelected = false; @@ -140,6 +147,7 @@ class OTADataAccumulator CHIP_ERROR Accumulate(ByteSpan & block); inline uint8_t * data() { return mBuffer.Get(); } + inline uint32_t GetThreshold() { return mThreshold; } private: uint32_t mThreshold; diff --git a/src/platform/nxp/k32w/k32w0/BLEManagerImpl.cpp b/src/platform/nxp/k32w/k32w0/BLEManagerImpl.cpp index a7bc09d524360e..af56961cf23dc1 100644 --- a/src/platform/nxp/k32w/k32w0/BLEManagerImpl.cpp +++ b/src/platform/nxp/k32w/k32w0/BLEManagerImpl.cpp @@ -51,7 +51,7 @@ BLEManagerCommon * BLEManagerImpl::GetImplInstance() { return &BLEManagerImpl::sInstance; } -CHIP_ERROR BLEManagerImpl::InitHostController(ble_generic_cb_fp cb_fp) +CHIP_ERROR BLEManagerImpl::InitHostController(BLECallbackDelegate::GapGenericCallback cb_fp) { CHIP_ERROR err = CHIP_NO_ERROR; diff --git a/src/platform/nxp/k32w/k32w0/BLEManagerImpl.h b/src/platform/nxp/k32w/k32w0/BLEManagerImpl.h index 52fd69007d9aa0..eb8a25804804d1 100644 --- a/src/platform/nxp/k32w/k32w0/BLEManagerImpl.h +++ b/src/platform/nxp/k32w/k32w0/BLEManagerImpl.h @@ -44,7 +44,7 @@ class BLEManagerImpl : public BLEManagerCommon // the implementation methods provided by this class. friend BLEManager; - CHIP_ERROR InitHostController(ble_generic_cb_fp cb_fp) override; + CHIP_ERROR InitHostController(BLECallbackDelegate::GapGenericCallback cb_fp) override; BLEManagerCommon * GetImplInstance() override; private: diff --git a/src/platform/nxp/k32w/k32w0/CHIPDevicePlatformConfig.h b/src/platform/nxp/k32w/k32w0/CHIPDevicePlatformConfig.h index 0f6258fe9cd824..0c849ccc4989aa 100644 --- a/src/platform/nxp/k32w/k32w0/CHIPDevicePlatformConfig.h +++ b/src/platform/nxp/k32w/k32w0/CHIPDevicePlatformConfig.h @@ -176,6 +176,18 @@ #define CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT 1 #endif +#if CHIP_DEVICE_CONFIG_ENABLE_SED + +#ifndef CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL +#define CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL chip::System::Clock::Milliseconds32(NXP_OT_IDLE_INTERVAL) +#endif // CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL + +#ifndef CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL +#define CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL chip::System::Clock::Milliseconds32(NXP_OT_ACTIVE_INTERVAL) +#endif // CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL + +#endif + #define CHIP_DEVICE_CONFIG_ENABLE_TEST_SETUP_PARAMS 1 #include diff --git a/src/platform/nxp/k32w/k32w0/CHIPPlatformConfig.h b/src/platform/nxp/k32w/k32w0/CHIPPlatformConfig.h index 6971c329fa37c6..2f582b28171996 100644 --- a/src/platform/nxp/k32w/k32w0/CHIPPlatformConfig.h +++ b/src/platform/nxp/k32w/k32w0/CHIPPlatformConfig.h @@ -77,4 +77,28 @@ #define WDM_PUBLISHER_MAX_NOTIFIES_IN_FLIGHT 2 #endif // WDM_PUBLISHER_MAX_NOTIFIES_IN_FLIGHT +#if NXP_ICD_ENABLED + +#ifndef CHIP_CONFIG_ICD_IDLE_MODE_INTERVAL_SEC +#define CHIP_CONFIG_ICD_IDLE_MODE_INTERVAL_SEC NXP_IDLE_MODE_INTERVAL +#endif // CHIP_CONFIG_ICD_IDLE_MODE_INTERVAL_SEC + +#ifndef CHIP_CONFIG_ICD_ACTIVE_MODE_INTERVAL_MS +#define CHIP_CONFIG_ICD_ACTIVE_MODE_INTERVAL_MS NXP_ACTIVE_MODE_INTERVAL +#endif // CHIP_CONFIG_ICD_ACTIVE_MODE_INTERVAL_MS + +#ifndef CHIP_CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS +#define CHIP_CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS NXP_ACTIVE_MODE_THRESHOLD +#endif // CHIP_CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS + +#ifndef CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC +#define CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC NXP_ICD_SUPPORTED_CLIENTS_PER_FABRIC +#endif // CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC + +#ifndef CHIP_CONFIG_SYNCHRONOUS_REPORTS_ENABLED +#define CHIP_CONFIG_SYNCHRONOUS_REPORTS_ENABLED 1 +#endif + +#endif + #include "platform/nxp/common/CHIPNXPPlatformDefaultConfig.h" diff --git a/src/platform/nxp/k32w/k32w0/KeyValueStoreManagerImpl.cpp b/src/platform/nxp/k32w/k32w0/KeyValueStoreManagerImpl.cpp index 8b3e7491eec3bb..0cf81fa9bf1749 100644 --- a/src/platform/nxp/k32w/k32w0/KeyValueStoreManagerImpl.cpp +++ b/src/platform/nxp/k32w/k32w0/KeyValueStoreManagerImpl.cpp @@ -81,8 +81,8 @@ CHIP_ERROR KeyValueStoreManagerImpl::Init() { ChipLogProgress(DeviceLayer, "Cannot init KVS keys storage with id: %d. Error: %s", kNvmId_KvsKeys, ErrorStr(err)); } - // Set values storage to max RAM buffer size as a temporary fix for TC-RR-1.1. - err = sValuesStorage.Init(kRamBufferMaxAllocSize, true); + // Set values storage to a big RAM buffer size as a temporary fix for TC-RR-1.1. + err = sValuesStorage.Init(kKVS_RamBufferSize, true); if (err != CHIP_NO_ERROR) { ChipLogProgress(DeviceLayer, "Cannot init KVS values storage with id: %d. Error: %s", kNvmId_KvsValues, ErrorStr(err)); diff --git a/src/platform/nxp/k32w/k32w0/Logging.cpp b/src/platform/nxp/k32w/k32w0/Logging.cpp index b00366999023ee..537ceed1181694 100644 --- a/src/platform/nxp/k32w/k32w0/Logging.cpp +++ b/src/platform/nxp/k32w/k32w0/Logging.cpp @@ -45,7 +45,7 @@ void GetMessageString(char * buf, uint8_t bufLen, const char * module, uint8_t c */ assert(bufLen >= (timestamp_max_len_bytes + category_max_len_bytes + (strlen(module) + 2) + 1)); - writtenLen = snprintf(buf, bufLen, "[%" PRIu32, otPlatAlarmMilliGetNow()); + writtenLen = snprintf(buf, bufLen, "[%ld]", otPlatAlarmMilliGetNow()); bufLen -= writtenLen; buf += writtenLen; diff --git a/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.cpp b/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.cpp index dbf7d09c892de4..438623dbc97d2f 100644 --- a/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.cpp +++ b/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.cpp @@ -49,6 +49,10 @@ CHIP_ERROR OTAFactoryDataProcessor::ProcessInternal(ByteSpan & block) CHIP_ERROR error = CHIP_NO_ERROR; ReturnErrorOnFailure(mAccumulator.Accumulate(block)); +#if OTA_ENCRYPTION_ENABLE + MutableByteSpan mBlock = MutableByteSpan(mAccumulator.data(), mAccumulator.GetThreshold()); + OTATlvProcessor::vOtaProcessInternalEncryption(mBlock); +#endif error = DecodeTlv(); if (error != CHIP_NO_ERROR) diff --git a/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.cpp b/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.cpp index cf26fc8c2149ea..760c9ef2eec8fc 100644 --- a/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.cpp +++ b/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include "OtaSupport.h" @@ -29,6 +30,9 @@ CHIP_ERROR OTAFirmwareProcessor::Init() { ReturnErrorCodeIf(mCallbackProcessDescriptor == nullptr, CHIP_OTA_PROCESSOR_CB_NOT_REGISTERED); mAccumulator.Init(sizeof(Descriptor)); +#if OTA_ENCRYPTION_ENABLE + mUnalignmentNum = 0; +#endif ReturnErrorCodeIf(gOtaSuccess_c != OTA_ClientInit(), CHIP_OTA_PROCESSOR_CLIENT_INIT); auto offset = OTA_GetCurrentEepromAddressOffset(); @@ -48,6 +52,9 @@ CHIP_ERROR OTAFirmwareProcessor::Clear() OTATlvProcessor::ClearInternal(); mAccumulator.Clear(); mDescriptorProcessed = false; +#if OTA_ENCRYPTION_ENABLE + mUnalignmentNum = 0; +#endif return CHIP_NO_ERROR; } @@ -57,7 +64,32 @@ CHIP_ERROR OTAFirmwareProcessor::ProcessInternal(ByteSpan & block) if (!mDescriptorProcessed) { ReturnErrorOnFailure(ProcessDescriptor(block)); +#if OTA_ENCRYPTION_ENABLE + /* 16 bytes to used to store undecrypted data because of unalignment */ + mAccumulator.Init(requestedOtaMaxBlockSize + 16); +#endif } +#if OTA_ENCRYPTION_ENABLE + MutableByteSpan mBlock = MutableByteSpan(mAccumulator.data(), mAccumulator.GetThreshold()); + memcpy(&mBlock[0], &mBlock[requestedOtaMaxBlockSize], mUnalignmentNum); + memcpy(&mBlock[mUnalignmentNum], block.data(), block.size()); + + if (mUnalignmentNum + block.size() < requestedOtaMaxBlockSize) + { + uint32_t mAlignmentNum = (mUnalignmentNum + block.size()) / 16; + mAlignmentNum = mAlignmentNum * 16; + mUnalignmentNum = (mUnalignmentNum + block.size()) % 16; + memcpy(&mBlock[requestedOtaMaxBlockSize], &mBlock[mAlignmentNum], mUnalignmentNum); + mBlock.reduce_size(mAlignmentNum); + } + else + { + mUnalignmentNum = mUnalignmentNum + block.size() - requestedOtaMaxBlockSize; + mBlock.reduce_size(requestedOtaMaxBlockSize); + } + + OTATlvProcessor::vOtaProcessInternalEncryption(mBlock); +#endif auto status = OTA_MakeHeadRoomForNextBlock(requestedOtaMaxBlockSize, OTAImageProcessorImpl::FetchNextData, 0); if (gOtaSuccess_c != status) @@ -65,8 +97,11 @@ CHIP_ERROR OTAFirmwareProcessor::ProcessInternal(ByteSpan & block) ChipLogError(SoftwareUpdate, "Failed to make room for next block. Status: %d", status); return CHIP_OTA_PROCESSOR_MAKE_ROOM; } - +#if OTA_ENCRYPTION_ENABLE + status = OTA_PushImageChunk((uint8_t *) mBlock.data(), (uint16_t) mBlock.size(), NULL, NULL); +#else status = OTA_PushImageChunk((uint8_t *) block.data(), (uint16_t) block.size(), NULL, NULL); +#endif if (gOtaSuccess_c != status) { ChipLogError(SoftwareUpdate, "Failed to write image block. Status: %d", status); diff --git a/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.h b/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.h index bc12394598ac89..885dc239dd22b3 100644 --- a/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.h +++ b/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.h @@ -45,6 +45,9 @@ class OTAFirmwareProcessor : public OTATlvProcessor OTADataAccumulator mAccumulator; bool mDescriptorProcessed = false; +#if OTA_ENCRYPTION_ENABLE + uint32_t mUnalignmentNum; +#endif }; } // namespace chip diff --git a/src/platform/nxp/k32w/k32w1/BLEManagerImpl.cpp b/src/platform/nxp/k32w/k32w1/BLEManagerImpl.cpp index daac54fb5a16e7..95a69b717c4af0 100644 --- a/src/platform/nxp/k32w/k32w1/BLEManagerImpl.cpp +++ b/src/platform/nxp/k32w/k32w1/BLEManagerImpl.cpp @@ -41,7 +41,7 @@ BLEManagerCommon * BLEManagerImpl::GetImplInstance() return &BLEManagerImpl::sInstance; } -CHIP_ERROR BLEManagerImpl::InitHostController(ble_generic_cb_fp cb_fp) +CHIP_ERROR BLEManagerImpl::InitHostController(BLECallbackDelegate::GapGenericCallback cb_fp) { CHIP_ERROR err = CHIP_NO_ERROR; diff --git a/src/platform/nxp/k32w/k32w1/BLEManagerImpl.h b/src/platform/nxp/k32w/k32w1/BLEManagerImpl.h index 7aa4e9f1604b42..bef927c8275350 100644 --- a/src/platform/nxp/k32w/k32w1/BLEManagerImpl.h +++ b/src/platform/nxp/k32w/k32w1/BLEManagerImpl.h @@ -49,7 +49,7 @@ class BLEManagerImpl final : public BLEManagerCommon // the implementation methods provided by this class. friend BLEManager; - CHIP_ERROR InitHostController(ble_generic_cb_fp cb_fp) override; + CHIP_ERROR InitHostController(BLECallbackDelegate::GapGenericCallback cb_fp) override; BLEManagerCommon * GetImplInstance() override; private: diff --git a/third_party/nxp/k32w0_sdk/k32w0_sdk.gni b/third_party/nxp/k32w0_sdk/k32w0_sdk.gni index e8858022e20516..ab37141606f19a 100644 --- a/third_party/nxp/k32w0_sdk/k32w0_sdk.gni +++ b/third_party/nxp/k32w0_sdk/k32w0_sdk.gni @@ -47,6 +47,21 @@ declare_args() { chip_enable_ota_factory_data_processor = 0 chip_with_pdm_encryption = 1 ota_custom_entry_address = "0x000C1000" + use_antenna_diversity = 0 + + #ICD Matter Configuration flags + + chip_ot_idle_interval_ms = 2000 # 2s Idle Intervals + chip_ot_active_interval_ms = 500 # 500ms Active Intervals + + nxp_idle_mode_interval_s = 600 # 10min Idle Mode Interval + nxp_active_mode_interval_ms = 10000 # 10s Active Mode Interval + nxp_active_mode_threshold_ms = 1000 # 1s Active Mode Threshold + nxp_icd_supported_clients_per_fabric = 2 # 2 registration slots per fabric + + chip_with_ota_encryption = 0 + chip_with_ota_key = "1234567890ABCDEFA1B2C3D4E5F6F1B4" + chip_with_sdk_package = 1 } assert(k32w0_sdk_root != "", "k32w0_sdk_root must be specified") @@ -132,6 +147,12 @@ template("k32w0_sdk") { chip_with_ntag = 0 } + if (k32w0_sdk_root == "${chip_root}/third_party/nxp/k32w0_sdk/repo/core" || + k32w0_sdk_root == "/opt/sdk/core") { + chip_with_sdk_package = 0 + } else { + chip_with_sdk_package = 1 + } print("device:", device) print("board:", board) print("ntag:", chip_with_ntag) @@ -153,6 +174,7 @@ template("k32w0_sdk") { print("ECC crypto lib: ", chip_crypto_flavor) } + print("chip_with_sdk_package:", chip_with_sdk_package) device_lowercase = string_replace(board, "dk6", "") sdk_target_name = target_name @@ -204,26 +226,7 @@ template("k32w0_sdk") { "${k32w0_sdk_root}/components/serial_manager", "${k32w0_sdk_root}/components/uart", "${k32w0_sdk_root}/devices/${device}", - "${k32w0_sdk_root}/devices/K32W061/drivers", - "${k32w0_sdk_root}/drivers/common", - "${k32w0_sdk_root}/drivers/lpc_gpio", - "${k32w0_sdk_root}/drivers/aes", - "${k32w0_sdk_root}/drivers/jn_iocon", - "${k32w0_sdk_root}/drivers/lpc_adc", - "${k32w0_sdk_root}/drivers/aes", - "${k32w0_sdk_root}/drivers/jn_flash", - "${k32w0_sdk_root}/drivers/sha", - "${k32w0_sdk_root}/drivers/flexcomm", - "${k32w0_sdk_root}/drivers/lpc_dma", - "${k32w0_sdk_root}/drivers/pint", - "${k32w0_sdk_root}/drivers/inputmux", - "${k32w0_sdk_root}/drivers/spifi", - "${k32w0_sdk_root}/drivers/jn_rtc", - "${k32w0_sdk_root}/drivers/fmeas", - "${k32w0_sdk_root}/drivers/jn_rng", - "${k32w0_sdk_root}/drivers/ctimer", - "${k32w0_sdk_root}/drivers/wwdt", - "${k32w0_sdk_root}/drivers/gint", + "${k32w0_sdk_root}/utilities/debug_console/str", "${k32w0_sdk_root}/utilities/debug_console", "${k32w0_sdk_root}/devices/${device}/utilities", @@ -267,6 +270,32 @@ template("k32w0_sdk") { "${k32w0_sdk_root}/rtos/amazon-freertos/lib/include/private", "${k32w0_sdk_root}/rtos/amazon-freertos/lib/third_party/unity/src", ] + if (chip_with_sdk_package == 1) { + _sdk_include_dirs += [ "${k32w0_sdk_root}/devices/${device}/drivers" ] + } else { + _sdk_include_dirs += [ + "${k32w0_sdk_root}/devices/K32W061/drivers", + "${k32w0_sdk_root}/drivers/common", + "${k32w0_sdk_root}/drivers/lpc_gpio", + "${k32w0_sdk_root}/drivers/aes", + "${k32w0_sdk_root}/drivers/jn_iocon", + "${k32w0_sdk_root}/drivers/lpc_adc", + "${k32w0_sdk_root}/drivers/aes", + "${k32w0_sdk_root}/drivers/jn_flash", + "${k32w0_sdk_root}/drivers/sha", + "${k32w0_sdk_root}/drivers/flexcomm", + "${k32w0_sdk_root}/drivers/lpc_dma", + "${k32w0_sdk_root}/drivers/pint", + "${k32w0_sdk_root}/drivers/inputmux", + "${k32w0_sdk_root}/drivers/spifi", + "${k32w0_sdk_root}/drivers/jn_rtc", + "${k32w0_sdk_root}/drivers/fmeas", + "${k32w0_sdk_root}/drivers/jn_rng", + "${k32w0_sdk_root}/drivers/ctimer", + "${k32w0_sdk_root}/drivers/wwdt", + "${k32w0_sdk_root}/drivers/gint", + ] + } libs = [ "${k32w0_sdk_root}/middleware/wireless/ble_controller/lib/lib_ble_controller_peripheral_commissioning.a", @@ -317,6 +346,7 @@ template("k32w0_sdk") { "gAppUseBonding_d=0", "gAppUsePairing_d=0", "gAppUsePrivacy_d=0", + "gController_ReducedRxThoughput=1", "gPasskeyValue_c=999999", "gSupportBle=1", "SUPPORT_FOR_BLE=1", @@ -324,6 +354,9 @@ template("k32w0_sdk") { "gConnPhyUpdateReqTxPhySettings_c=(gLePhy2MFlag_c)", "gConnPhyUpdateReqRxPhySettings_c=(gLePhy2MFlag_c)", "gConnPhyUpdateReqPhyOptions_c=(gLeCodingNoPreference_c)", + "BLE_HIGH_TX_POWER=0", + "gAdvertisingPowerLeveldBm_c=0", + "gConnectPowerLeveldBm_c=0", "DUAL_MODE_APP=1", "gMainThreadStackSize_c=5096", "HEAP_SIZE=gTotalHeapSize_c", @@ -332,6 +365,15 @@ template("k32w0_sdk") { "gSecLibUseSha256Alt_d=1", "gOTA_UseSecLibAes=1", "gResetSystemReset_d=1", + + # TODO: move these platform specific defines to args.gni + "NXP_OT_IDLE_INTERVAL=${chip_ot_idle_interval_ms}", + "NXP_OT_ACTIVE_INTERVAL=${chip_ot_active_interval_ms}", + "NXP_ICD_ENABLED=1", + "NXP_ACTIVE_MODE_THRESHOLD=${nxp_active_mode_threshold_ms}", + "NXP_ACTIVE_MODE_INTERVAL=${nxp_active_mode_interval_ms}", + "NXP_IDLE_MODE_INTERVAL=${nxp_idle_mode_interval_s}", + "NXP_ICD_SUPPORTED_CLIENTS_PER_FABRIC=${nxp_icd_supported_clients_per_fabric}", ] # If OTA default processors are enabled, then OTA custom entry structure @@ -372,6 +414,15 @@ template("k32w0_sdk") { defines += [ "PDM_ENCRYPTION=0" ] } + if (chip_with_ota_encryption == 1) { + defines += [ + "OTA_ENCRYPTION_ENABLE=1", + "OTA_ENCRYPTION_KEY=\"${chip_with_ota_key}\"", + ] + } else { + defines += [ "OTA_ENCRYPTION_ENABLE=0" ] + } + if (chip_mdns == "platform") { defines += [ "OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE=1", @@ -539,27 +590,6 @@ template("k32w0_sdk") { "${k32w0_sdk_root}/components/uart/usart_adapter.c", "${k32w0_sdk_root}/devices/${device}/mcuxpresso/startup_${device_lowercase}.c", "${k32w0_sdk_root}/devices/${device}/system_${device}.c", - "${k32w0_sdk_root}/devices/K32W061/drivers/fsl_clock.c", - "${k32w0_sdk_root}/devices/K32W061/drivers/fsl_power.c", - "${k32w0_sdk_root}/devices/K32W061/drivers/fsl_reset.c", - "${k32w0_sdk_root}/devices/K32W061/drivers/fsl_wtimer.c", - "${k32w0_sdk_root}/drivers/aes/fsl_aes.c", - "${k32w0_sdk_root}/drivers/common/fsl_common.c", - "${k32w0_sdk_root}/drivers/ctimer/fsl_ctimer.c", - "${k32w0_sdk_root}/drivers/flexcomm/fsl_flexcomm.c", - "${k32w0_sdk_root}/drivers/flexcomm/fsl_i2c.c", - "${k32w0_sdk_root}/drivers/flexcomm/fsl_i2c_freertos.c", - "${k32w0_sdk_root}/drivers/flexcomm/fsl_usart.c", - "${k32w0_sdk_root}/drivers/fmeas/fsl_fmeas.c", - "${k32w0_sdk_root}/drivers/inputmux/fsl_inputmux.c", - "${k32w0_sdk_root}/drivers/jn_flash/fsl_flash.c", - "${k32w0_sdk_root}/drivers/jn_rng/fsl_rng.c", - "${k32w0_sdk_root}/drivers/jn_rtc/fsl_rtc.c", - "${k32w0_sdk_root}/drivers/lpc_adc/fsl_adc.c", - "${k32w0_sdk_root}/drivers/lpc_gpio/fsl_gpio.c", - "${k32w0_sdk_root}/drivers/pint/fsl_pint.c", - "${k32w0_sdk_root}/drivers/sha/fsl_sha.c", - "${k32w0_sdk_root}/drivers/spifi/fsl_spifi.c", "${k32w0_sdk_root}/middleware/wireless/ble_controller/config/controller_config.c", "${k32w0_sdk_root}/middleware/wireless/bluetooth/application/common/ble_conn_manager.c", "${k32w0_sdk_root}/middleware/wireless/bluetooth/application/common/ble_host_tasks.c", @@ -599,9 +629,60 @@ template("k32w0_sdk") { "${k32w0_sdk_root}/rtos/amazon-freertos/lib/FreeRTOS/queue.c", "${k32w0_sdk_root}/rtos/amazon-freertos/lib/FreeRTOS/tasks.c", "${k32w0_sdk_root}/rtos/amazon-freertos/lib/FreeRTOS/timers.c", - "${k32w0_sdk_root}/utilities/debug_console/fsl_debug_console.c", - "${k32w0_sdk_root}/utilities/debug_console/str/fsl_str.c", ] + if (chip_with_sdk_package == 1) { + sources += [ + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_adc.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_aes.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_clock.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_common.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_ctimer.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_flash.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_flexcomm.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_fmeas.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_gpio.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_i2c.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_i2c_freertos.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_inputmux.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_pint.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_power.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_reset.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_rng.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_rtc.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_sha.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_spifi.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_usart.c", + "${k32w0_sdk_root}/devices/${device}/drivers/fsl_wtimer.c", + "${k32w0_sdk_root}/devices/${device}/utilities/debug_console/fsl_debug_console.c", + "${k32w0_sdk_root}/devices/${device}/utilities/str/fsl_str.c", + ] + } else { + sources += [ + "${k32w0_sdk_root}/devices/K32W061/drivers/fsl_clock.c", + "${k32w0_sdk_root}/devices/K32W061/drivers/fsl_power.c", + "${k32w0_sdk_root}/devices/K32W061/drivers/fsl_reset.c", + "${k32w0_sdk_root}/devices/K32W061/drivers/fsl_wtimer.c", + "${k32w0_sdk_root}/drivers/aes/fsl_aes.c", + "${k32w0_sdk_root}/drivers/common/fsl_common.c", + "${k32w0_sdk_root}/drivers/ctimer/fsl_ctimer.c", + "${k32w0_sdk_root}/drivers/flexcomm/fsl_flexcomm.c", + "${k32w0_sdk_root}/drivers/flexcomm/fsl_i2c.c", + "${k32w0_sdk_root}/drivers/flexcomm/fsl_i2c_freertos.c", + "${k32w0_sdk_root}/drivers/flexcomm/fsl_usart.c", + "${k32w0_sdk_root}/drivers/fmeas/fsl_fmeas.c", + "${k32w0_sdk_root}/drivers/inputmux/fsl_inputmux.c", + "${k32w0_sdk_root}/drivers/jn_flash/fsl_flash.c", + "${k32w0_sdk_root}/drivers/jn_rng/fsl_rng.c", + "${k32w0_sdk_root}/drivers/jn_rtc/fsl_rtc.c", + "${k32w0_sdk_root}/drivers/lpc_adc/fsl_adc.c", + "${k32w0_sdk_root}/drivers/lpc_gpio/fsl_gpio.c", + "${k32w0_sdk_root}/drivers/pint/fsl_pint.c", + "${k32w0_sdk_root}/drivers/sha/fsl_sha.c", + "${k32w0_sdk_root}/drivers/spifi/fsl_spifi.c", + "${k32w0_sdk_root}/utilities/debug_console/fsl_debug_console.c", + "${k32w0_sdk_root}/utilities/debug_console/str/fsl_str.c", + ] + } if (chip_with_DK6) { sources += [ diff --git a/third_party/nxp/k32w0_sdk/repo/manifest/west.yml b/third_party/nxp/k32w0_sdk/repo/manifest/west.yml index 3a00791908f057..0febc2e377bd1e 100644 --- a/third_party/nxp/k32w0_sdk/repo/manifest/west.yml +++ b/third_party/nxp/k32w0_sdk/repo/manifest/west.yml @@ -11,7 +11,7 @@ manifest: remote: nxpmicro projects: - name: mcux-sdk - revision: b1ce670e8433142a3c78dca7f4597326eb5f5342 + revision: 7219c54f5dbd5a8636242f9f1771ddb70be146c9 path: core - name: amazon-freertos url: https://github.com/NXP/amazon-freertos.git @@ -23,7 +23,7 @@ manifest: revision: 15458495823165de372f62c3dad621a8da6c86e3 - name: framework url: https://github.com/NXP/mcux-sdk-middleware-connectivity-framework.git - revision: a45ed24bc5f8d54312c4d9243c4423d226084412 + revision: 2ccc3df70ee5b73c451fceee13e6172518412518 path: core/middleware/wireless/framework - name: ble_controller url: https://github.com/NXP/mcux-sdk-middleware-bluetooth-controller.git @@ -35,9 +35,9 @@ manifest: path: core/middleware/wireless/bluetooth - name: ieee-802.15.4 url: https://github.com/NXP/mcux-sdk-middleware-ieee_802.15.4.git - revision: 7cca871d58e53c78a703a39b269c4366b03f26e4 + revision: e8c96197346a7e37ce3a872096a22bf4aee47e3d path: core/middleware/wireless/ieee-802.15.4 - name: examples url: https://github.com/nxp-mcuxpresso/mcux-sdk-examples.git - revision: 39eed09d6a8485dcf365a24cd6ef957e7cc6fbf8 + revision: 6735550f5a41dfb997d4dd3ce6eebfe1f1d41054 path: core/boards diff --git a/third_party/openthread/ot-nxp b/third_party/openthread/ot-nxp index 57422f917ad1ab..eb23212ca1e329 160000 --- a/third_party/openthread/ot-nxp +++ b/third_party/openthread/ot-nxp @@ -1 +1 @@ -Subproject commit 57422f917ad1abc65919435558cd836c8f7bada7 +Subproject commit eb23212ca1e329a29c95c29c09438c8f2256d5c6