From 63e86791658a91371a8ab9215fba2b2af45acdf3 Mon Sep 17 00:00:00 2001 From: Alex Tsitsiura Date: Tue, 8 Nov 2022 16:09:23 +0200 Subject: [PATCH] [Telink] Add Telink factory data & Update every image to 0.6.06 (#23502) * [Telink] Add Factory Data functionality * [Telink] Add CHIP license attribution * [Telink]: Update every image to 0.6.06 --- .devcontainer/devcontainer.json | 2 +- .github/workflows/bloat_check.yaml | 2 +- .github/workflows/build.yaml | 6 +- .github/workflows/chef.yaml | 6 +- .github/workflows/cirque.yaml | 4 +- .github/workflows/doxygen.yaml | 2 +- .github/workflows/examples-ameba.yaml | 2 +- .../workflows/examples-cc13x2x7_26x2x7.yaml | 2 +- .github/workflows/examples-efr32.yaml | 2 +- .github/workflows/examples-esp32.yaml | 4 +- .github/workflows/examples-infineon.yaml | 2 +- .github/workflows/examples-k32w.yaml | 2 +- .github/workflows/examples-linux-arm.yaml | 2 +- .github/workflows/examples-linux-imx.yaml | 2 +- .../workflows/examples-linux-standalone.yaml | 2 +- .github/workflows/examples-mbed.yaml | 2 +- .github/workflows/examples-mw320.yaml | 2 +- .github/workflows/examples-nrfconnect.yaml | 2 +- .github/workflows/examples-qpg.yaml | 2 +- .github/workflows/examples-telink.yaml | 2 +- .github/workflows/examples-tizen.yaml | 2 +- .github/workflows/full-android.yaml | 2 +- .github/workflows/fuzzing-build.yaml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/qemu.yaml | 2 +- .github/workflows/release_artifacts.yaml | 4 +- .github/workflows/smoketest-android.yaml | 2 +- .github/workflows/tests.yaml | 4 +- .github/workflows/unit_integration_test.yaml | 2 +- .github/workflows/zap_regeneration.yaml | 2 +- .github/workflows/zap_templates.yaml | 2 +- config/telink/chip-module/CMakeLists.txt | 84 ++- config/telink/chip-module/Kconfig | 208 +++++++- .../chip-module/generate_factory_data.cmake | 194 +++++++ config/telink/chip-module/make_gn_args.py | 73 +++ .../telink/boards/tlsr9518adk80d.overlay | 35 -- .../light-switch-app/telink/include/AppTask.h | 10 +- examples/light-switch-app/telink/prj.conf | 6 +- .../light-switch-app/telink/src/AppTask.cpp | 74 +-- .../telink/boards/tlsr9518adk80d.overlay | 35 -- .../lighting-app/telink/include/AppTask.h | 12 +- examples/lighting-app/telink/prj.conf | 6 +- examples/lighting-app/telink/src/AppTask.cpp | 77 +-- integrations/cloudbuild/build-all.yaml | 4 +- integrations/cloudbuild/chef.yaml | 6 +- integrations/cloudbuild/smoke-test.yaml | 14 +- .../generate_telink_chip_factory_data.py | 492 ++++++++++++++++++ .../tools/telink/telink_factory_data.schema | 147 ++++++ .../tools/telink/telink_generate_partition.py | 169 ++++++ src/platform/telink/BUILD.gn | 16 + .../telink/CHIPDevicePlatformConfig.h | 106 +++- src/platform/telink/FactoryDataParser.c | 167 ++++++ src/platform/telink/FactoryDataParser.h | 78 +++ src/platform/telink/FactoryDataProvider.cpp | 341 ++++++++++++ src/platform/telink/FactoryDataProvider.h | 117 +++++ src/platform/telink/args.gni | 7 +- src/platform/telink/telink-mbedtls-config.h | 31 +- 57 files changed, 2355 insertions(+), 232 deletions(-) create mode 100644 config/telink/chip-module/generate_factory_data.cmake create mode 100755 config/telink/chip-module/make_gn_args.py delete mode 100644 examples/light-switch-app/telink/boards/tlsr9518adk80d.overlay delete mode 100644 examples/lighting-app/telink/boards/tlsr9518adk80d.overlay create mode 100644 scripts/tools/telink/generate_telink_chip_factory_data.py create mode 100644 scripts/tools/telink/telink_factory_data.schema create mode 100644 scripts/tools/telink/telink_generate_partition.py create mode 100644 src/platform/telink/FactoryDataParser.c create mode 100644 src/platform/telink/FactoryDataParser.h create mode 100644 src/platform/telink/FactoryDataProvider.cpp create mode 100644 src/platform/telink/FactoryDataProvider.h diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6847480b51a5b9..b5da6c153e4d7f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -17,7 +17,7 @@ "build": { "dockerfile": "Dockerfile", "args": { - "BUILD_VERSION": "0.6.03" + "BUILD_VERSION": "0.6.06" } }, "remoteUser": "vscode", diff --git a/.github/workflows/bloat_check.yaml b/.github/workflows/bloat_check.yaml index 4849a8df42021b..78f56124d0ba5e 100644 --- a/.github/workflows/bloat_check.yaml +++ b/.github/workflows/bloat_check.yaml @@ -30,7 +30,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 steps: - uses: Wandalen/wretry.action@v1.0.15 diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 750506bbf62a7c..19f1b969c2592b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -32,7 +32,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 volumes: - "/tmp/log_output:/tmp/test_logs" options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0 @@ -133,7 +133,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 volumes: - "/tmp/log_output:/tmp/test_logs" options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0 @@ -287,7 +287,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 volumes: - "/tmp/log_output:/tmp/test_logs" options: --sysctl "net.ipv6.conf.all.disable_ipv6=0 diff --git a/.github/workflows/chef.yaml b/.github/workflows/chef.yaml index 9484e01243754b..a473a39fc18102 100644 --- a/.github/workflows/chef.yaml +++ b/.github/workflows/chef.yaml @@ -29,7 +29,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 options: --user root steps: @@ -57,7 +57,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-esp32:0.6.05 + image: connectedhomeip/chip-build-esp32:0.6.06 options: --user root steps: @@ -85,7 +85,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-nrf-platform:0.6.05 + image: connectedhomeip/chip-build-nrf-platform:0.6.06 options: --user root steps: diff --git a/.github/workflows/cirque.yaml b/.github/workflows/cirque.yaml index 78d501293a33ad..c91c437b8b22fb 100644 --- a/.github/workflows/cirque.yaml +++ b/.github/workflows/cirque.yaml @@ -29,7 +29,7 @@ jobs: timeout-minutes: 90 env: - DOCKER_RUN_VERSION: 0.6.05 + DOCKER_RUN_VERSION: 0.6.06 GITHUB_CACHE_PATH: /tmp/cirque-cache/ runs-on: ubuntu-latest @@ -38,7 +38,7 @@ jobs: # need to run with privilege, which isn't supported by job.XXX.contaner # https://github.com/actions/container-action/issues/2 # container: - # image: connectedhomeip/chip-build-cirque:0.6.05 + # image: connectedhomeip/chip-build-cirque:0.6.06 # volumes: # - "/tmp:/tmp" # - "/dev/pts:/dev/pts" diff --git a/.github/workflows/doxygen.yaml b/.github/workflows/doxygen.yaml index 075154910b4e2a..1d33bd9b8708da 100644 --- a/.github/workflows/doxygen.yaml +++ b/.github/workflows/doxygen.yaml @@ -82,7 +82,7 @@ jobs: runs-on: ubuntu-20.04 container: - image: connectedhomeip/chip-build-doxygen:0.6.05 + image: connectedhomeip/chip-build-doxygen:0.6.06 if: github.actor != 'restyled-io[bot]' diff --git a/.github/workflows/examples-ameba.yaml b/.github/workflows/examples-ameba.yaml index 0f22ae0b5b73ad..50506da74c6c17 100644 --- a/.github/workflows/examples-ameba.yaml +++ b/.github/workflows/examples-ameba.yaml @@ -32,7 +32,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-ameba:0.6.05 + image: connectedhomeip/chip-build-ameba:0.6.06 options: --user root steps: diff --git a/.github/workflows/examples-cc13x2x7_26x2x7.yaml b/.github/workflows/examples-cc13x2x7_26x2x7.yaml index 26a35488aa620f..78e06bbaa04cc9 100644 --- a/.github/workflows/examples-cc13x2x7_26x2x7.yaml +++ b/.github/workflows/examples-cc13x2x7_26x2x7.yaml @@ -34,7 +34,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-ti:0.6.05 + image: connectedhomeip/chip-build-ti:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/.github/workflows/examples-efr32.yaml b/.github/workflows/examples-efr32.yaml index 5bf7067b231077..ace5165dcc98f3 100644 --- a/.github/workflows/examples-efr32.yaml +++ b/.github/workflows/examples-efr32.yaml @@ -35,7 +35,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-efr32:0.6.05 + image: connectedhomeip/chip-build-efr32:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/.github/workflows/examples-esp32.yaml b/.github/workflows/examples-esp32.yaml index 0da3c73d34794d..4fa36a41dedb6f 100644 --- a/.github/workflows/examples-esp32.yaml +++ b/.github/workflows/examples-esp32.yaml @@ -31,7 +31,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-esp32:0.6.05 + image: connectedhomeip/chip-build-esp32:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" @@ -119,7 +119,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-esp32:0.6.05 + image: connectedhomeip/chip-build-esp32:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" diff --git a/.github/workflows/examples-infineon.yaml b/.github/workflows/examples-infineon.yaml index 3bd67ff377bb2f..0cf077b3c11acc 100644 --- a/.github/workflows/examples-infineon.yaml +++ b/.github/workflows/examples-infineon.yaml @@ -32,7 +32,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-infineon:0.6.05 + image: connectedhomeip/chip-build-infineon:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/.github/workflows/examples-k32w.yaml b/.github/workflows/examples-k32w.yaml index f62da3a00e23d2..ce7088d499a346 100644 --- a/.github/workflows/examples-k32w.yaml +++ b/.github/workflows/examples-k32w.yaml @@ -34,7 +34,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-k32w:0.6.05 + image: connectedhomeip/chip-build-k32w:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/.github/workflows/examples-linux-arm.yaml b/.github/workflows/examples-linux-arm.yaml index 51fae3f86e6e37..c38d8389e617a7 100644 --- a/.github/workflows/examples-linux-arm.yaml +++ b/.github/workflows/examples-linux-arm.yaml @@ -31,7 +31,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-crosscompile:0.6.05 + image: connectedhomeip/chip-build-crosscompile:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" diff --git a/.github/workflows/examples-linux-imx.yaml b/.github/workflows/examples-linux-imx.yaml index 81d8d60537ea90..1c17f0b6ddaae7 100644 --- a/.github/workflows/examples-linux-imx.yaml +++ b/.github/workflows/examples-linux-imx.yaml @@ -31,7 +31,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-imx:0.6.05 + image: connectedhomeip/chip-build-imx:0.6.06 steps: - uses: Wandalen/wretry.action@v1.0.15 diff --git a/.github/workflows/examples-linux-standalone.yaml b/.github/workflows/examples-linux-standalone.yaml index 38438ecfea0b8a..77fe6ceb4674b1 100644 --- a/.github/workflows/examples-linux-standalone.yaml +++ b/.github/workflows/examples-linux-standalone.yaml @@ -34,7 +34,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" diff --git a/.github/workflows/examples-mbed.yaml b/.github/workflows/examples-mbed.yaml index f7a69bd3de3054..1e38a7f3271924 100644 --- a/.github/workflows/examples-mbed.yaml +++ b/.github/workflows/examples-mbed.yaml @@ -37,7 +37,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-mbed-os:0.6.05 + image: connectedhomeip/chip-build-mbed-os:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" diff --git a/.github/workflows/examples-mw320.yaml b/.github/workflows/examples-mw320.yaml index 93c2327ba3ad74..9f54ec8ae2dbf8 100755 --- a/.github/workflows/examples-mw320.yaml +++ b/.github/workflows/examples-mw320.yaml @@ -34,7 +34,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/.github/workflows/examples-nrfconnect.yaml b/.github/workflows/examples-nrfconnect.yaml index c6b729f3776855..f46b3e87426b06 100644 --- a/.github/workflows/examples-nrfconnect.yaml +++ b/.github/workflows/examples-nrfconnect.yaml @@ -34,7 +34,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-nrf-platform:0.6.05 + image: connectedhomeip/chip-build-nrf-platform:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" diff --git a/.github/workflows/examples-qpg.yaml b/.github/workflows/examples-qpg.yaml index 56656a645da7cd..86db7a309b5fd2 100644 --- a/.github/workflows/examples-qpg.yaml +++ b/.github/workflows/examples-qpg.yaml @@ -34,7 +34,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/.github/workflows/examples-telink.yaml b/.github/workflows/examples-telink.yaml index e20c2690686a19..366cf0857a484a 100644 --- a/.github/workflows/examples-telink.yaml +++ b/.github/workflows/examples-telink.yaml @@ -32,7 +32,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-telink:0.6.05 + image: connectedhomeip/chip-build-telink:0.6.06 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" diff --git a/.github/workflows/examples-tizen.yaml b/.github/workflows/examples-tizen.yaml index 47c9e880deae69..c2c39674a65b98 100644 --- a/.github/workflows/examples-tizen.yaml +++ b/.github/workflows/examples-tizen.yaml @@ -32,7 +32,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-tizen:0.6.05 + image: connectedhomeip/chip-build-tizen:0.6.06 options: --user root volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" diff --git a/.github/workflows/full-android.yaml b/.github/workflows/full-android.yaml index 176f2ac65a1d81..b3c961edec832e 100644 --- a/.github/workflows/full-android.yaml +++ b/.github/workflows/full-android.yaml @@ -34,7 +34,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-android:0.6.05 + image: connectedhomeip/chip-build-android:0.6.06 volumes: - "/tmp/log_output:/tmp/test_logs" diff --git a/.github/workflows/fuzzing-build.yaml b/.github/workflows/fuzzing-build.yaml index b9267d9a5e9afc..6caf55c05773d1 100644 --- a/.github/workflows/fuzzing-build.yaml +++ b/.github/workflows/fuzzing-build.yaml @@ -31,7 +31,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 volumes: - "/tmp/log_output:/tmp/test_logs" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2b4fe4a91150d4..6bb491ff0fb9d7 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -28,7 +28,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 steps: - uses: Wandalen/wretry.action@v1.0.15 diff --git a/.github/workflows/qemu.yaml b/.github/workflows/qemu.yaml index eb083791dd2a93..ab7eb29d38338a 100644 --- a/.github/workflows/qemu.yaml +++ b/.github/workflows/qemu.yaml @@ -34,7 +34,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-esp32-qemu:0.6.05 + image: connectedhomeip/chip-build-esp32-qemu:0.6.06 volumes: - "/tmp/log_output:/tmp/test_logs" diff --git a/.github/workflows/release_artifacts.yaml b/.github/workflows/release_artifacts.yaml index 6bc9abad9d117f..f2124e828a81f5 100644 --- a/.github/workflows/release_artifacts.yaml +++ b/.github/workflows/release_artifacts.yaml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build-esp32:0.6.05 + image: connectedhomeip/chip-build-esp32:0.6.06 steps: - uses: Wandalen/wretry.action@v1.0.15 @@ -75,7 +75,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build-efr32:0.6.05 + image: connectedhomeip/chip-build-efr32:0.6.06 steps: - uses: Wandalen/wretry.action@v1.0.15 name: Checkout diff --git a/.github/workflows/smoketest-android.yaml b/.github/workflows/smoketest-android.yaml index af5c8c7d565482..7065d26f8e5f06 100644 --- a/.github/workflows/smoketest-android.yaml +++ b/.github/workflows/smoketest-android.yaml @@ -34,7 +34,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-android:0.6.05 + image: connectedhomeip/chip-build-android:0.6.06 volumes: - "/tmp/log_output:/tmp/test_logs" diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 0e88bb57277978..b6c4ab72f129d3 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -44,7 +44,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0 net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1" @@ -347,7 +347,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0 net.ipv4.conf.all.forwarding=0 net.ipv6.conf.all.forwarding=0" diff --git a/.github/workflows/unit_integration_test.yaml b/.github/workflows/unit_integration_test.yaml index c2875c49d52538..4be02d8c89895d 100644 --- a/.github/workflows/unit_integration_test.yaml +++ b/.github/workflows/unit_integration_test.yaml @@ -37,7 +37,7 @@ jobs: runs-on: ubuntu-latest container: - image: connectedhomeip/chip-build:0.6.05 + image: connectedhomeip/chip-build:0.6.06 volumes: - "/tmp/log_output:/tmp/test_logs" options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0 net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1" diff --git a/.github/workflows/zap_regeneration.yaml b/.github/workflows/zap_regeneration.yaml index 9f76f042d7f136..19e44cbddb9ee7 100644 --- a/.github/workflows/zap_regeneration.yaml +++ b/.github/workflows/zap_regeneration.yaml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-20.04 container: - image: connectedhomeip/chip-build-zap:0.6.05 + image: connectedhomeip/chip-build-zap:0.6.06 defaults: run: shell: sh diff --git a/.github/workflows/zap_templates.yaml b/.github/workflows/zap_templates.yaml index 0a16f8e6ede8e7..03aafce5908a54 100644 --- a/.github/workflows/zap_templates.yaml +++ b/.github/workflows/zap_templates.yaml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-20.04 container: - image: connectedhomeip/chip-build-zap:0.6.05 + image: connectedhomeip/chip-build-zap:0.6.06 defaults: run: shell: sh diff --git a/config/telink/chip-module/CMakeLists.txt b/config/telink/chip-module/CMakeLists.txt index f6d93210b4a416..6ef6ac2c882238 100644 --- a/config/telink/chip-module/CMakeLists.txt +++ b/config/telink/chip-module/CMakeLists.txt @@ -28,6 +28,7 @@ if (CONFIG_CHIP) include(ExternalProject) include(../../zephyr/ota-image.cmake) include(../../zephyr/zephyr-util.cmake) +include(generate_factory_data.cmake) # ============================================================================== # Declare configuration variables and define constants @@ -45,7 +46,7 @@ list(APPEND CHIP_CFLAGS_CC) # CHIP libraries that the application should be linked with list(APPEND CHIP_LIBRARIES) -# GN meta-build system arguments in the form of 'key1 = value1\nkey2 = value2...' string +# GN meta-build system arguments passed to the make_gn_args.py script string(APPEND CHIP_GN_ARGS) # C/C++ compiler flags which should not be forwarded to CHIP @@ -67,28 +68,27 @@ set(CHIP_CFLAG_EXCLUDES # ============================================================================== macro(chip_gn_arg_import FILE) - string(APPEND CHIP_GN_ARGS "import(\"${FILE}\")\n") + string(APPEND CHIP_GN_ARGS "--module\n${FILE}\n") endmacro() macro(chip_gn_arg_string ARG STRING) - string(APPEND CHIP_GN_ARGS "${ARG} = \"${STRING}\"\n") + string(APPEND CHIP_GN_ARGS "--arg-string\n${ARG}\n${STRING}\n") endmacro() -macro(chip_gn_arg_bool ARG BOOLEAN) - if (${BOOLEAN}) - string(APPEND CHIP_GN_ARGS "${ARG} = true\n") +macro(chip_gn_arg_bool ARG) + if (${ARGN}) + string(APPEND CHIP_GN_ARGS "--arg\n${ARG}\ntrue\n") else() - string(APPEND CHIP_GN_ARGS "${ARG} = false\n") + string(APPEND CHIP_GN_ARGS "--arg\n${ARG}\nfalse\n") endif() endmacro() macro(chip_gn_arg_cflags ARG CFLAGS) - set(CFLAG_EXCLUDES "[") - foreach(cflag ${CHIP_CFLAG_EXCLUDES}) - string(APPEND CFLAG_EXCLUDES "\"${cflag}\", ") - endforeach() - string(APPEND CFLAG_EXCLUDES "]") - string(APPEND CHIP_GN_ARGS "${ARG} = filter_exclude(string_split(\"${CFLAGS}\"), ${CFLAG_EXCLUDES})\n") + string(APPEND CHIP_GN_ARGS "--arg-cflags\n${ARG}\n${CFLAGS}\n") +endmacro() + +macro(chip_gn_arg ARG VALUE) + string(APPEND CHIP_GN_ARGS "--arg\n${ARG}\n${VALUE}\n") endmacro() # ============================================================================== @@ -197,8 +197,6 @@ chip_gn_arg_cflags("target_cflags_cc" ${CHIP_CFLAGS_CC}) chip_gn_arg_string("zephyr_ar" ${CMAKE_AR}) chip_gn_arg_string("zephyr_cc" ${CMAKE_C_COMPILER}) chip_gn_arg_string("zephyr_cxx" ${CMAKE_CXX_COMPILER}) -chip_gn_arg_string("chip_project_config_include" "${CHIP_PROJECT_CONFIG}") -chip_gn_arg_string("chip_system_project_config_include" "${CHIP_PROJECT_CONFIG}") chip_gn_arg_bool ("is_debug" CONFIG_DEBUG) chip_gn_arg_bool ("chip_enable_openthread" CONFIG_NET_L2_OPENTHREAD) chip_gn_arg_bool ("chip_openthread_ftd" CONFIG_OPENTHREAD_FTD) @@ -208,16 +206,32 @@ chip_gn_arg_bool ("chip_build_tests" CONFIG_CHIP_BUILD_TE chip_gn_arg_bool ("chip_inet_config_enable_tcp_endpoint" CONFIG_CHIP_BUILD_TESTS) chip_gn_arg_bool ("chip_build_libshell" CONFIG_CHIP_LIB_SHELL) +if (CONFIG_CHIP_FACTORY_DATA) + chip_gn_arg_bool ("chip_use_transitional_commissionable_data_provider" "false") + chip_gn_arg_bool ("chip_enable_factory_data" "true") +elseif (CONFIG_CHIP_FACTORY_DATA_CUSTOM_BACKEND) + chip_gn_arg_bool ("chip_use_transitional_commissionable_data_provider" "false") +endif() + +if (CONFIG_CHIP_ROTATING_DEVICE_ID) + chip_gn_arg_bool("chip_enable_rotating_device_id" "true") + chip_gn_arg_bool("chip_enable_additional_data_advertising" "true") +endif() + if (CONFIG_CHIP_ENABLE_DNSSD_SRP) chip_gn_arg_string("chip_mdns" "platform") endif() +if (CHIP_PROJECT_CONFIG) + chip_gn_arg_string("chip_project_config_include" ${CHIP_PROJECT_CONFIG}) + chip_gn_arg_string("chip_system_project_config_include" ${CHIP_PROJECT_CONFIG}) +endif() if (CONFIG_CHIP_EXAMPLE_DEVICE_INFO_PROVIDER) chip_gn_arg_bool("chip_build_example_providers" "true") list(APPEND CHIP_LIBRARIES -lMatterDeviceInfoProviderExample) endif() -file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/args.gn CONTENT ${CHIP_GN_ARGS}) +file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/args.tmp" CONTENT ${CHIP_GN_ARGS}) # ============================================================================== # Define 'chip-gn' target that builds CHIP library(ies) with GN build system @@ -227,13 +241,17 @@ ExternalProject_Add( PREFIX ${CMAKE_CURRENT_BINARY_DIR} SOURCE_DIR ${CHIP_ROOT} BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} - CONFIGURE_COMMAND ${GN_EXECUTABLE} + CONFIGURE_COMMAND "" + BUILD_COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/make_gn_args.py + @args.tmp > args.gn && + ${GN_EXECUTABLE} --root=${CHIP_ROOT} --root-target=${GN_ROOT_TARGET} --dotfile=${GN_ROOT_TARGET}/.gn --script-executable=${Python3_EXECUTABLE} - gen --check --fail-on-unused-args ${CMAKE_CURRENT_BINARY_DIR} - BUILD_COMMAND ninja + --export-compile-commands + gen --check --fail-on-unused-args . && + ninja INSTALL_COMMAND "" BUILD_BYPRODUCTS ${CHIP_LIBRARIES} BUILD_ALWAYS TRUE @@ -288,11 +306,11 @@ if (CONFIG_CHIP_OTA_IMAGE_BUILD) west sign -t imgtool -p ${ZEPHYR_BASE}/../bootloader/mcuboot/scripts/imgtool.py -d ${PROJECT_BINARY_DIR}/.. -- --key ${ZEPHYR_BASE}/../bootloader/mcuboot/root-rsa-2048.pem ) - add_custom_target(final_bin ALL + add_custom_target(merge_mcuboot ALL COMMAND - dd if=${PROJECT_BINARY_DIR}/../modules/chip-module/build_mcuboot/zephyr/zephyr.bin of=${PROJECT_BINARY_DIR}/zephyr_final.bin + dd if=${PROJECT_BINARY_DIR}/../modules/chip-module/build_mcuboot/zephyr/zephyr.bin of=${PROJECT_BINARY_DIR}/zephyr.bin COMMAND - dd if=${PROJECT_BINARY_DIR}/zephyr.signed.bin of=${PROJECT_BINARY_DIR}/zephyr_final.bin bs=1024 seek=64 + dd if=${PROJECT_BINARY_DIR}/zephyr.signed.bin of=${PROJECT_BINARY_DIR}/zephyr.bin bs=1024 seek=64 ) chip_ota_image(chip-ota-image @@ -301,8 +319,28 @@ if (CONFIG_CHIP_OTA_IMAGE_BUILD) ) add_dependencies(west_sign ${ZEPHYR_FINAL_EXECUTABLE}) - add_dependencies(final_bin west_sign) + add_dependencies(merge_mcuboot west_sign) add_dependencies(chip-ota-image west_sign) endif() +if (CONFIG_CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE) + add_custom_target(merge_factory_data ALL + COMMAND + dd if=${PROJECT_BINARY_DIR}/factory_data.bin of=${PROJECT_BINARY_DIR}/zephyr.bin bs=1024 seek=976 + ) +if (CONFIG_CHIP_OTA_IMAGE_BUILD) + add_dependencies(merge_factory_data merge_mcuboot) +else() + add_dependencies(merge_factory_data ${ZEPHYR_FINAL_EXECUTABLE}) +endif() +endif() + +# ============================================================================== +# Define 'factory_data' target for generating a factory data partition +# ============================================================================== + +if (CONFIG_CHIP_FACTORY_DATA_BUILD) + telink_generate_factory_data() +endif() + endif() # CONFIG_CHIP diff --git a/config/telink/chip-module/Kconfig b/config/telink/chip-module/Kconfig index e02dee92dfccb7..366c43d8eac6db 100644 --- a/config/telink/chip-module/Kconfig +++ b/config/telink/chip-module/Kconfig @@ -59,4 +59,210 @@ config CHIP_EXAMPLE_DEVICE_INFO_PROVIDER # Enable getting reboot reasons information config HWINFO bool - default y \ No newline at end of file + default y + +config CHIP_FACTORY_DATA + bool "Enable Factory Data support" + select ZCBOR + help + Enables support for reading factory data from flash memory partition. + It requires factory_data partition to exist. + +config CHIP_FACTORY_DATA_CUSTOM_BACKEND + bool "Enable Factory Data custom backend" + depends on !CHIP_FACTORY_DATA + help + Enables user custom factory data implementation. It cannot be used + with the CHIP_FACTORY_DATA that enabled default Telink factory data + implementation. + +config CHIP_FACTORY_DATA_BUILD + bool "Enable Factory Data build" + default n + help + Enables generation of factory data during the building. + It requires factory_data partition to exist. + As a result a new output file factory_data.bin will be created. + +config CHIP_FACTORY_DATA_VERSION + int + default 1 + help + The Factory data version contains a current version of a factory data + parameter set that the user cannot change. + After moving to the next version of the factory data set, change the default value. + This config is used to validate the version of a factory data set on a device-side + with the version of factory data saved in the Flash memory. + +if CHIP_FACTORY_DATA_BUILD + +# Factory data definitions +config CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE + bool "Enable merging generated factory data with the build target .bin file" + default y + help + Enables merging generated factory data with the build target zephyr.bin file. + As a result, output file zephyr.bin will consist of all partitions including + factory data. + +# Use default certificates without generating or providing them +config CHIP_FACTORY_DATA_USE_DEFAULT_CERTS + bool "Use default certificates located in Matter repository" + default y + help + Pre-generated certificates can be used for development purpose. + This config includes default pre-generated certificates + which are located in credentials/development/attestation/ directory + instead of generating new ones. + If this config is set to `n` new certificates will be generated. + +# Configs for SPAKE2 generation +config CHIP_FACTORY_DATA_GENERATE_SPAKE2_VERIFIER + bool "Enable spake2 verifier generation" + help + Enables generation of spake2 verifier according to + given iteration counter, salt and passcode. + To generate Spake2 verifier a spake2p executable must be available + from system variables environment. + +config CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID + bool "Enable generation of a new Rotating device id unique id" + default y + help + Enables generation of a new Rotating device id unique id. + +endif #CHIP_FACTORY_DATA_BUILD + +# Factory data parameters +config CHIP_DEVICE_SERIAL_NUMBER + string "Serial number of device" + default "11223344556677889900" + help + A serial number parameter defines an unique number of manufactured device. + Maximum length of serial number is 32 characters. + +config CHIP_DEVICE_VENDOR_NAME + string "Human-readable vendor name" + default "Telink Semiconductor" + help + A human-readable vendor name which provides a simple string + containing identification of device's vendor for the Content APP. + This information should be included in the Matter Basic Cluster. + +config CHIP_DEVICE_PRODUCT_NAME + string "Human-readable product name" + default "not-specified" + help + A human-readable product name which provides a simple string + containing identification of the product for the Content APP. + +config CHIP_DEVICE_MANUFACTURING_DATE + string "Manufacturing date in ISO 8601" + default "2022-01-01" + help + A manufacturing date specifies the date that the device was manufactured. + The format used for providing a manufacturing date is ISO 8601 e.g. YYYY-MM-DD. + +config CHIP_DEVICE_HARDWARE_VERSION + int "Integer representation of hardware version" + default 0 + help + A hardware version number specifies the version number + of the hardware of the device. The meaning of its value, + and the versioning scheme, are vendor defined. + +config CHIP_DEVICE_HARDWARE_VERSION_STRING + string "user-friendly string representation of hardware version" + default "prerelease" + help + A hardware version string parameter specifies the version + of the hardware of the device as a more user-friendly value + than that represented by the hardware version integer value. + The meaning of its value, and the versioning scheme, are + vendor defined. + +config CHIP_DEVICE_DISCRIMINATOR + hex "Device pairing discriminator" + default 0xF00 + help + A 12-bit value matching the field of the same name in + the setup code. Discriminator is used during + a discovery process. + +config CHIP_DEVICE_SPAKE2_PASSCODE + int "Spake2+ passcode" + default 20202021 + range 1 99999998 + help + A pairing passcode is a 27-bit unsigned integer which serves + as a proof of possession during commissioning. + Its value shall be restricted to the values 0x0000001 to 0x5F5E0FE + (00000001 to 99999998 in decimal), excluding the invalid Passcode values: + - 00000000, 11111111, 22222222, 33333333, 44444444, 55555555, + 66666666, 77777777, 88888888, 99999999, 12345678, 87654321. + +config CHIP_DEVICE_SPAKE2_IT + int "Spake2+ iteration count" + default 1000 + help + The Spake2 iteration count is associated with the ephemeral + PAKE passcode verifier to be used for the commissioning. + The iteration count is used as a crypto parameter to process + spake2 verifier. + +config CHIP_DEVICE_SPAKE2_SALT + string "Spake2+ salt in string format" + default "U1BBS0UyUCBLZXkgU2FsdA==" + help + The spake2 salt is random data that is used as an additional input + to a one-way function that “hashes” data. + A new salt should be randomly generated for each password. + The minimum length of spake2 salt is 16 Bytes. + The maximum length of spake2 salt is 32 Bytes. + +config CHIP_DEVICE_SPAKE2_TEST_VERIFIER + string "Testing spake2+ verifier" + default "uWFwqugDNGiEck/po7KHwwMwwqZgN10XuyBajPGuyzUEV/iree4lOrao5GuwnlQ65CJzbeUB49s31EH+NEkg0JVI5MGCQGMMT/SRPFNRODm3wH/MBiehuFc6FJ/NH6Rmzw==" + help + The spake 2 verifier generated using default SPAKE2 salt, + iteration count and passcode. This value can be used for development + or testing purposes. + Generated with: + spake2p gen-verifier -o - -i 1000 -s "U1BBS0UyUCBLZXkgU2FsdA==" -p 20202021 + +config CHIP_DEVICE_ROTATING_DEVICE_UID + string "A rotating device id unique id" + default "91a9c12a7c80700a31ddcfa7fce63e44" + help + A device rotating id unique id which will be generated if + this config is not set in prj.conf file. + +config CHIP_DEVICE_ENABLE_KEY + string "Enable Key for triggering test actions on device" + default "00112233445566778899AABBCCDDEEFF" + help + The Enable Key is a 128-bit value that triggers test action + while invoking the TestEventTrigger Command. + Pattern: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + This value is used during Certification Tests, + and should not be present on production devices. + +config CHIP_CERTIFICATION_DECLARATION_STORAGE + bool "Enable storing Certification Declaration" + depends on CHIP_FACTORY_DATA + help + Enables storing Certification Declaration in Zephyr settings + instead of using hardcoded value from firmware. It also adds + support for including new Certification Declaration into a firmware + update image package sent via OTA Software Update. + +if CHIP_CERTIFICATION_DECLARATION_STORAGE + +config CHIP_CERTIFiCATION_DECLARATION_OTA_IMAGE_ID + int "Certification declaration OTA image id" + default 205 #0xcd + help + The image id of Certification Declaration image + for sending it via OTA Software Update purposes. + +endif diff --git a/config/telink/chip-module/generate_factory_data.cmake b/config/telink/chip-module/generate_factory_data.cmake new file mode 100644 index 00000000000000..ff9514e6707481 --- /dev/null +++ b/config/telink/chip-module/generate_factory_data.cmake @@ -0,0 +1,194 @@ +# +# Copyright (c) 2022 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. +# + + +# Create a JSON file based on factory data given via kConfigs. +# +# This function creates a list of arguments for external script and then run it to write a JSON file. +# Created JSON file can be checked using JSON SCHEMA file if it is provided. +# +# This script can be manipulated using following kConfigs: +# - To merge generated factory data with final zephyr.hex file set kConfig CONFIG_CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE=y +# - To use default certification paths set CONFIG_CHIP_FACTORY_DATA_USE_DEFAULTS_CERTS_PATH=y +# +# During generation process a some file will be created in zephyr's build directory: +# - .json a file containing all factory data written in JSON format. +# +# [Args]: +# factory_data_target - a name for target to generate factory_data. +# script_path - a path to script that makes a JSON factory data file from given arguments. +# schema_path - a path to JSON schema file which can be used to verify generated factory data JSON file. +# This argument is optional, if you don't want to verify the JSON file put it empty "". +# output_path - a path to output directory, where created JSON file will be stored. +function(telink_create_factory_data_json factory_data_target script_path schema_path output_path) + +# set script args for future purpose +set(script_args) +## generate all script arguments +string(APPEND script_args "--sn \"${CONFIG_CHIP_DEVICE_SERIAL_NUMBER}\"\n") +string(APPEND script_args "--date \"${CONFIG_CHIP_DEVICE_MANUFACTURING_DATE}\"\n") +string(APPEND script_args "--vendor_id ${CONFIG_CHIP_DEVICE_VENDOR_ID}\n") +string(APPEND script_args "--product_id ${CONFIG_CHIP_DEVICE_PRODUCT_ID}\n") +string(APPEND script_args "--vendor_name \"${CONFIG_CHIP_DEVICE_VENDOR_NAME}\"\n") +string(APPEND script_args "--product_name \"${CONFIG_CHIP_DEVICE_PRODUCT_NAME}\"\n") +string(APPEND script_args "--hw_ver ${CONFIG_CHIP_DEVICE_HARDWARE_VERSION}\n") +string(APPEND script_args "--hw_ver_str \"${CONFIG_CHIP_DEVICE_HARDWARE_VERSION_STRING}\"\n") + +# check if Rotating Device Id Unique Id should be generated +if(NOT CONFIG_CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID) + if(NOT DEFINED CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID) + message(FATAL_ERROR "CHIP_DEVICE_ROTATING_DEVICE_UID was not provided. To generate it use CONFIG_CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID=y") + else() + string(APPEND script_args "--rd_uid \"${CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID}\"\n") + endif() +else() + string(APPEND script_args "--generate_rd_uid\n") +endif() + +# for development purpose user can use default certs instead of generating or providing them +if(CONFIG_CHIP_FACTORY_DATA_USE_DEFAULT_CERTS) + # convert decimal PID to its hexadecimal representation to find out certification files in repository + math(EXPR LOCAL_PID "${CONFIG_CHIP_DEVICE_PRODUCT_ID}" OUTPUT_FORMAT HEXADECIMAL) + string(SUBSTRING ${LOCAL_PID} 2 -1 raw_pid) + # all certs are located in ${CHIP_ROOT}/credentials/development/attestation + # it can be used during development without need to generate new certifications + string(APPEND script_args "--dac_cert \"${CHIP_ROOT}/credentials/development/attestation/Matter-Development-DAC-${raw_pid}-Cert.der\"\n") + string(APPEND script_args "--dac_key \"${CHIP_ROOT}/credentials/development/attestation/Matter-Development-DAC-${raw_pid}-Key.der\"\n") + string(APPEND script_args "--pai_cert \"${CHIP_ROOT}/credentials/development/attestation/Matter-Development-PAI-noPID-Cert.der\"\n") +else() + find_program(chip_cert_exe NAMES chip-cert REQUIRED) + string(APPEND script_args "--gen_cd\n") + string(APPEND script_args "--chip_cert_path ${chip_cert_exe}\n") +endif() + +# add Password-Authenticated Key Exchange parameters +string(APPEND script_args "--spake2_it \"${CONFIG_CHIP_DEVICE_SPAKE2_IT}\"\n") +string(APPEND script_args "--spake2_salt \"${CONFIG_CHIP_DEVICE_SPAKE2_SALT}\"\n") +string(APPEND script_args "--discriminator ${CONFIG_CHIP_DEVICE_DISCRIMINATOR}\n") +string(APPEND script_args "--passcode ${CONFIG_CHIP_DEVICE_SPAKE2_PASSCODE}\n") +string(APPEND script_args "--overwrite\n") + +# check if spake2 verifier should be generated using script +if(CONFIG_CHIP_FACTORY_DATA_GENERATE_SPAKE2_VERIFIER) + # request script to generate a new spake2_verifier + # by adding an argument to script_args + find_program(spake_exe NAMES spake2p REQUIRED) + string(APPEND script_args "--spake2p_path ${spake_exe}\n") +else() + # Spake2 verifier should be provided using kConfig + string(APPEND script_args "--spake2_verifier \"${CONFIG_CHIP_DEVICE_SPAKE2_TEST_VERIFIER}\"\n") +endif() + +if(CONFIG_CHIP_DEVICE_ENABLE_KEY) +# Add optional EnableKey that triggers user-specific action. +string(APPEND script_args "--enable_key \"${CONFIG_CHIP_DEVICE_ENABLE_KEY}\"\n") +endif() + +# Set output JSON file and path to SCHEMA file to validate generated factory data +set(factory_data_json ${output_path}/${factory_data_target}.json) +string(APPEND script_args "-o \"${factory_data_json}\"\n") +string(APPEND script_args "-s \"${schema_path}\"\n") + +# execute first script to create a JSON file +separate_arguments(separated_script_args NATIVE_COMMAND ${script_args}) +add_custom_command( + OUTPUT ${factory_data_json} + DEPENDS ${FACTORY_DATA_SCRIPT_PATH} + COMMAND ${Python3_EXECUTABLE} ${FACTORY_DATA_SCRIPT_PATH} ${separated_script_args} + COMMENT "Generating new Factory Data..." + ) +add_custom_target(${factory_data_target} ALL + DEPENDS ${factory_data_json} + ) + +endfunction() + + +# Create a .hex file with factory data in CBOR format. +# +# This function creates a .hex and .cbor files from given JSON factory data file. +# +# +# During generation process some files will be created in zephyr's build directory: +# - .hex a file containing all factory data in CBOR format. +# - .bin a binary file containing all raw factory data in CBOR format. +# - .cbor a file containing all factory data in CBOR format. +# +# [Args]: +# factory_data_hex_target - a name for target to generate factory data HEX file. +# factory_data_target - a name for target to generate factory data JSON file. +# script_path - a path to script that makes a factory data .hex file from given arguments. +# output_path - a path to output directory, where created JSON file will be stored. +function(telink_create_factory_data_hex_file factory_data_hex_target factory_data_target script_path output_path) + +# Pass the argument list via file +set(cbor_script_args "-i ${output_path}/${factory_data_target}.json\n") +string(APPEND cbor_script_args "-o ${output_path}/${factory_data_target}\n") +# get partition address and offset from partition manager during compilation +string(APPEND cbor_script_args "--offset 0xf4000\n") +string(APPEND cbor_script_args "--size 0x1000\n") +string(APPEND cbor_script_args "-r\n") + +# execute second script to create a hex file containing factory data in cbor format +separate_arguments(separated_cbor_script_args NATIVE_COMMAND ${cbor_script_args}) +set(factory_data_hex ${output_path}/${factory_data_target}.hex) + +add_custom_command(OUTPUT ${factory_data_hex} + COMMAND ${Python3_EXECUTABLE} ${script_path} ${separated_cbor_script_args} + COMMENT "Generating factory data HEX file..." + DEPENDS ${factory_data_target} ${script_path} + ) +add_custom_target(${factory_data_hex_target} ALL + DEPENDS ${factory_data_hex} + ) + +endfunction() + +# Generate factory data partition using given args +# +# +# During generation process a some file will be created in zephyr's build directory: +# - merged.hex a file containing firmware and factory data merged to single file +# - factory_data.hex a file containing only a factory data partition including proper offset +# +function(telink_generate_factory_data) + +find_package(Python REQUIRED) + +# CHIP_ROOT must be provided as a reference set all localization of scripts +if(NOT CHIP_ROOT) +message(FATAL_ERROR "CHIP_ROOT variable is not set, please add it to CMakeLists.txt file") +endif() + +# Localize all scripts needed to generate factory data partition +set(FACTORY_DATA_SCRIPT_PATH ${CHIP_ROOT}/scripts/tools/telink/generate_telink_chip_factory_data.py) +set(GENERATE_CBOR_SCRIPT_PATH ${CHIP_ROOT}/scripts/tools/telink/telink_generate_partition.py) +set(FACTORY_DATA_SCHEMA_PATH ${CHIP_ROOT}/scripts/tools/telink/telink_factory_data.schema) +set(OUTPUT_FILE_PATH ${APPLICATION_BINARY_DIR}/zephyr) + +# create a JSON file with all factory data +telink_create_factory_data_json(factory_data + ${FACTORY_DATA_SCRIPT_PATH} + ${FACTORY_DATA_SCHEMA_PATH} + ${OUTPUT_FILE_PATH}) + +# create a .hex file with factory data in CBOR format based on the JSON file created previously +telink_create_factory_data_hex_file(factory_data_hex + factory_data + ${GENERATE_CBOR_SCRIPT_PATH} + ${OUTPUT_FILE_PATH}) + +endfunction() diff --git a/config/telink/chip-module/make_gn_args.py b/config/telink/chip-module/make_gn_args.py new file mode 100755 index 00000000000000..f30cd459a6e7d4 --- /dev/null +++ b/config/telink/chip-module/make_gn_args.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 + +# +# Copyright (c) 2021 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. +# + +import argparse +import re +import sys + +GN_SPECIAL_CHARACTERS = r'(["$\\])' +GN_CFLAG_EXCLUDES = [ + '-fno-asynchronous-unwind-tables', + '-fno-common', + '-fno-defer-pop', + '-fno-reorder-functions', + '-ffunction-sections', + '-fdata-sections', + '-g*', + '-O*', + '-W*', +] + + +def escape_strings(gn_args): + return [[key, re.sub(GN_SPECIAL_CHARACTERS, r'\\\1', value)] for key, value in gn_args] + + +def write_gn_args(args): + if args.module: + sys.stdout.write('import("{}")\n'.format(args.module)) + + for key, value in args.arg: + sys.stdout.write('{} = {}\n'.format(key, value)) + + for key, value in args.arg_string: + sys.stdout.write('{} = "{}"\n'.format(key, value)) + + cflag_excludes = ', '.join(['"{}"'.format(exclude) + for exclude in GN_CFLAG_EXCLUDES]) + + for key, value in args.arg_cflags: + sys.stdout.write('{} = filter_exclude(string_split("{}"), [{}])\n'.format( + key, value, cflag_excludes)) + + +def main(): + parser = argparse.ArgumentParser(fromfile_prefix_chars='@') + parser.add_argument('--module', action='store') + parser.add_argument('--arg', action='append', nargs=2, default=[]) + parser.add_argument('--arg-string', action='append', nargs=2, default=[]) + parser.add_argument('--arg-cflags', action='append', nargs=2, default=[]) + args = parser.parse_args() + args.arg_string = escape_strings(args.arg_string) + args.arg_cflags = escape_strings(args.arg_cflags) + write_gn_args(args) + + +if __name__ == "__main__": + main() diff --git a/examples/light-switch-app/telink/boards/tlsr9518adk80d.overlay b/examples/light-switch-app/telink/boards/tlsr9518adk80d.overlay deleted file mode 100644 index 613584d2908fba..00000000000000 --- a/examples/light-switch-app/telink/boards/tlsr9518adk80d.overlay +++ /dev/null @@ -1,35 +0,0 @@ -&flash { - /delete-node/ partitions; -}; - -&flash { - reg = <0x20000000 0x100000>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 0x10000>; - }; - slot0_partition: partition@10000 { - label = "image-0"; - reg = <0x10000 0x70000>; - }; - slot1_partition: partition@80000 { - label = "image-1"; - reg = <0x80000 0x70000>; - }; - scratch_partition: partition@f0000 { - label = "image-scratch"; - reg = <0xf0000 0x4000>; - }; - storage_partition: partition@f4000 { - label = "storage"; - reg = <0xf4000 0x0000b000>; - /* region <0xff000 0x1000> is reserved for Telink B91 SDK's data */ - }; - }; -}; diff --git a/examples/light-switch-app/telink/include/AppTask.h b/examples/light-switch-app/telink/include/AppTask.h index 7fd67ff34abdad..6cf0a330cf2317 100755 --- a/examples/light-switch-app/telink/include/AppTask.h +++ b/examples/light-switch-app/telink/include/AppTask.h @@ -24,6 +24,10 @@ #include +#if CONFIG_CHIP_FACTORY_DATA +#include +#endif + #include struct k_timer; @@ -48,7 +52,6 @@ class AppTask private: friend AppTask & GetAppTask(void); - CHIP_ERROR Init(); static void ActionInitiated(AppTask::Action_t aAction, int32_t aActor); @@ -74,6 +77,11 @@ class AppTask static void ThreadProvisioningHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); static AppTask sAppTask; + +#if CONFIG_CHIP_FACTORY_DATA + // chip::DeviceLayer::FactoryDataProvider mFactoryDataProvider; + chip::DeviceLayer::FactoryDataProvider mFactoryDataProvider; +#endif }; inline AppTask & GetAppTask(void) diff --git a/examples/light-switch-app/telink/prj.conf b/examples/light-switch-app/telink/prj.conf index 05b92e9169eb6e..1366c5f0e952fb 100755 --- a/examples/light-switch-app/telink/prj.conf +++ b/examples/light-switch-app/telink/prj.conf @@ -54,4 +54,8 @@ CONFIG_CHIP_DEVICE_SOFTWARE_VERSION_STRING="2022" CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART=y # CHIP shell -CONFIG_CHIP_LIB_SHELL=n \ No newline at end of file +CONFIG_CHIP_LIB_SHELL=n + +# Disable factory data support. +CONFIG_CHIP_FACTORY_DATA=n +CONFIG_CHIP_FACTORY_DATA_BUILD=n \ No newline at end of file diff --git a/examples/light-switch-app/telink/src/AppTask.cpp b/examples/light-switch-app/telink/src/AppTask.cpp index e8d3d0049dc095..7e1c792018b885 100644 --- a/examples/light-switch-app/telink/src/AppTask.cpp +++ b/examples/light-switch-app/telink/src/AppTask.cpp @@ -23,27 +23,19 @@ #include "ButtonManager.h" #include "LEDWidget.h" #include "binding-handler.h" -#include -#include - -#include #include "ThreadUtil.h" +#include #include #include #include #include -#include - +#include +#include #include #include - -#include - #include -#include -#include #include #if CONFIG_CHIP_OTA_REQUESTOR @@ -57,12 +49,22 @@ LOG_MODULE_DECLARE(app); +using namespace ::chip; +using namespace ::chip::app; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; + namespace { constexpr int kAppEventQueueSize = 10; constexpr uint8_t kButtonPushEvent = 1; constexpr uint8_t kButtonReleaseEvent = 0; +// NOTE! This key is for test/certification only and should not be available in production devices! +// If CONFIG_CHIP_FACTORY_DATA is enabled, this value is read from the factory data. +uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); LEDWidget sStatusLED; @@ -112,15 +114,11 @@ Identify sIdentify = { } // namespace -using namespace ::chip::Credentials; -using namespace ::chip::DeviceLayer; -using namespace ::chip::DeviceLayer::Internal; - AppTask AppTask::sAppTask; CHIP_ERROR AppTask::Init() { - CHIP_ERROR ret; + CHIP_ERROR err; LOG_INF("Current Software Version: %u, %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION, CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); @@ -133,15 +131,30 @@ CHIP_ERROR AppTask::Init() InitButtons(); - // Init ZCL Data Model and start server - static chip::CommonCaseDeviceServerInitParams initParams; - (void) initParams.InitializeStaticResourcesBeforeServerInit(); - chip::Server::GetInstance().Init(initParams); - - // Initialize device attestation config + // Initialize CHIP server +#if CONFIG_CHIP_FACTORY_DATA + ReturnErrorOnFailure(mFactoryDataProvider.Init()); + SetDeviceInstanceInfoProvider(&mFactoryDataProvider); + SetDeviceAttestationCredentialsProvider(&mFactoryDataProvider); + SetCommissionableDataProvider(&mFactoryDataProvider); + // Read EnableKey from the factory data. + MutableByteSpan enableKey(sTestEventTriggerEnableKey); + err = mFactoryDataProvider.GetEnableKey(enableKey); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("mFactoryDataProvider.GetEnableKey() failed. Could not delegate a test event trigger"); + memset(sTestEventTriggerEnableKey, 0, sizeof(sTestEventTriggerEnableKey)); + } +#else SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); +#endif - gExampleDeviceInfoProvider.SetStorageDelegate(&chip::Server::GetInstance().GetPersistentStorage()); + static CommonCaseDeviceServerInitParams initParams; + // static OTATestEventTriggerDelegate testEventTriggerDelegate{ ByteSpan(sTestEventTriggerEnableKey) }; + (void) initParams.InitializeStaticResourcesBeforeServerInit(); + // initParams.testEventTriggerDelegate = &testEventTriggerDelegate; + ReturnErrorOnFailure(chip::Server::GetInstance().Init(initParams)); + gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage()); chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); #if CONFIG_CHIP_OTA_REQUESTOR @@ -151,11 +164,11 @@ CHIP_ERROR AppTask::Init() ConfigurationMgr().LogDeviceConfig(); // Configure Bindings - ret = InitBindingHandler(); - if (ret != CHIP_NO_ERROR) + err = InitBindingHandler(); + if (err != CHIP_NO_ERROR) { LOG_ERR("InitBindingHandler() failed"); - return ret; + return err; } PrintOnboardingCodes(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); @@ -165,14 +178,13 @@ CHIP_ERROR AppTask::Init() // between the main and the CHIP threads. PlatformMgr().AddEventHandler(ChipEventHandler, 0); - ret = ConnectivityMgr().SetBLEDeviceName("TelinkSwitch"); - if (ret != CHIP_NO_ERROR) + err = ConnectivityMgr().SetBLEDeviceName("TelinkSwitch"); + if (err != CHIP_NO_ERROR) { LOG_ERR("Fail to set BLE device name"); - return ret; } - return CHIP_NO_ERROR; + return err; } CHIP_ERROR AppTask::StartApp() @@ -255,7 +267,7 @@ void AppTask::StartThreadHandler(AppEvent * aEvent) if (!chip::DeviceLayer::ConnectivityMgr().IsThreadProvisioned()) { // Switch context from BLE to Thread - BLEManagerImpl sInstance; + Internal::BLEManagerImpl sInstance; sInstance.SwitchToIeee802154(); StartDefaultThreadNetwork(); LOG_INF("Device is not commissioned to a Thread network. Starting with the default configuration."); diff --git a/examples/lighting-app/telink/boards/tlsr9518adk80d.overlay b/examples/lighting-app/telink/boards/tlsr9518adk80d.overlay deleted file mode 100644 index 613584d2908fba..00000000000000 --- a/examples/lighting-app/telink/boards/tlsr9518adk80d.overlay +++ /dev/null @@ -1,35 +0,0 @@ -&flash { - /delete-node/ partitions; -}; - -&flash { - reg = <0x20000000 0x100000>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 0x10000>; - }; - slot0_partition: partition@10000 { - label = "image-0"; - reg = <0x10000 0x70000>; - }; - slot1_partition: partition@80000 { - label = "image-1"; - reg = <0x80000 0x70000>; - }; - scratch_partition: partition@f0000 { - label = "image-scratch"; - reg = <0xf0000 0x4000>; - }; - storage_partition: partition@f4000 { - label = "storage"; - reg = <0xf4000 0x0000b000>; - /* region <0xff000 0x1000> is reserved for Telink B91 SDK's data */ - }; - }; -}; diff --git a/examples/lighting-app/telink/include/AppTask.h b/examples/lighting-app/telink/include/AppTask.h index d926c5286f41f3..0b1b588654aa13 100644 --- a/examples/lighting-app/telink/include/AppTask.h +++ b/examples/lighting-app/telink/include/AppTask.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2022 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,6 +23,10 @@ #include +#if CONFIG_CHIP_FACTORY_DATA +#include +#endif + #include struct k_timer; @@ -38,7 +42,6 @@ class AppTask private: friend AppTask & GetAppTask(void); - CHIP_ERROR Init(); static void ActionInitiated(LightingManager::Action_t aAction, int32_t aActor); @@ -64,6 +67,11 @@ class AppTask static void ThreadProvisioningHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); static AppTask sAppTask; + +#if CONFIG_CHIP_FACTORY_DATA + // chip::DeviceLayer::FactoryDataProvider mFactoryDataProvider; + chip::DeviceLayer::FactoryDataProvider mFactoryDataProvider; +#endif }; inline AppTask & GetAppTask(void) diff --git a/examples/lighting-app/telink/prj.conf b/examples/lighting-app/telink/prj.conf index 3e94168f31df3d..3de670dd34bf07 100644 --- a/examples/lighting-app/telink/prj.conf +++ b/examples/lighting-app/telink/prj.conf @@ -54,4 +54,8 @@ CONFIG_CHIP_DEVICE_SOFTWARE_VERSION_STRING="2022" CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART=y # CHIP shell -CONFIG_CHIP_LIB_SHELL=n \ No newline at end of file +CONFIG_CHIP_LIB_SHELL=n + +# Disable factory data support. +CONFIG_CHIP_FACTORY_DATA=n +CONFIG_CHIP_FACTORY_DATA_BUILD=n \ No newline at end of file diff --git a/examples/lighting-app/telink/src/AppTask.cpp b/examples/lighting-app/telink/src/AppTask.cpp index fd9eabc82976e5..00db77cd01c89a 100644 --- a/examples/lighting-app/telink/src/AppTask.cpp +++ b/examples/lighting-app/telink/src/AppTask.cpp @@ -23,28 +23,20 @@ #include "ButtonManager.h" #include "LEDWidget.h" #include "LightingManager.h" -#include -#include - -#include #include "ThreadUtil.h" +#include #include #include #include #include #include -#include - +#include +#include #include #include - -#include - #include -#include -#include #include #if CONFIG_CHIP_OTA_REQUESTOR @@ -58,6 +50,11 @@ LOG_MODULE_DECLARE(app); +using namespace ::chip; +using namespace ::chip::app; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; + namespace { constexpr int kAppEventQueueSize = 10; @@ -66,6 +63,11 @@ constexpr uint8_t kButtonReleaseEvent = 0; constexpr uint8_t kDefaultMinLevel = 0; constexpr uint8_t kDefaultMaxLevel = 254; +// NOTE! This key is for test/certification only and should not be available in production devices! +// If CONFIG_CHIP_FACTORY_DATA is enabled, this value is read from the factory data. +uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); LEDWidget sStatusLED; @@ -115,18 +117,10 @@ Identify sIdentify = { } // namespace -using namespace ::chip; -using namespace ::chip::app; -using namespace ::chip::Credentials; -using namespace ::chip::DeviceLayer; -using namespace ::chip::DeviceLayer::Internal; - AppTask AppTask::sAppTask; CHIP_ERROR AppTask::Init() { - CHIP_ERROR ret; - LOG_INF("Current Software Version: %u, %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION, CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); @@ -145,23 +139,39 @@ CHIP_ERROR AppTask::Init() uint8_t maxLightLevel = kDefaultMaxLevel; Clusters::LevelControl::Attributes::MaxLevel::Get(1, &maxLightLevel); - ret = LightingMgr().Init(LIGHTING_PWM_DEVICE, LIGHTING_PWM_CHANNEL, minLightLevel, maxLightLevel, maxLightLevel); - if (ret != CHIP_NO_ERROR) + CHIP_ERROR err = LightingMgr().Init(LIGHTING_PWM_DEVICE, LIGHTING_PWM_CHANNEL, minLightLevel, maxLightLevel, maxLightLevel); + if (err != CHIP_NO_ERROR) { LOG_ERR("Failed to int lighting manager"); - return ret; + return err; } LightingMgr().SetCallbacks(ActionInitiated, ActionCompleted); - // Init ZCL Data Model and start server - static chip::CommonCaseDeviceServerInitParams initParams; - (void) initParams.InitializeStaticResourcesBeforeServerInit(); - chip::Server::GetInstance().Init(initParams); - - // Initialize device attestation config + // Initialize CHIP server +#if CONFIG_CHIP_FACTORY_DATA + ReturnErrorOnFailure(mFactoryDataProvider.Init()); + SetDeviceInstanceInfoProvider(&mFactoryDataProvider); + SetDeviceAttestationCredentialsProvider(&mFactoryDataProvider); + SetCommissionableDataProvider(&mFactoryDataProvider); + // Read EnableKey from the factory data. + MutableByteSpan enableKey(sTestEventTriggerEnableKey); + err = mFactoryDataProvider.GetEnableKey(enableKey); + if (err != CHIP_NO_ERROR) + { + LOG_ERR("mFactoryDataProvider.GetEnableKey() failed. Could not delegate a test event trigger"); + memset(sTestEventTriggerEnableKey, 0, sizeof(sTestEventTriggerEnableKey)); + } +#else SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); +#endif + + static CommonCaseDeviceServerInitParams initParams; + // static OTATestEventTriggerDelegate testEventTriggerDelegate{ ByteSpan(sTestEventTriggerEnableKey) }; + (void) initParams.InitializeStaticResourcesBeforeServerInit(); + // initParams.testEventTriggerDelegate = &testEventTriggerDelegate; + ReturnErrorOnFailure(chip::Server::GetInstance().Init(initParams)); - gExampleDeviceInfoProvider.SetStorageDelegate(&chip::Server::GetInstance().GetPersistentStorage()); + gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage()); chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); #if CONFIG_CHIP_OTA_REQUESTOR @@ -176,14 +186,13 @@ CHIP_ERROR AppTask::Init() // between the main and the CHIP threads. PlatformMgr().AddEventHandler(ChipEventHandler, 0); - ret = ConnectivityMgr().SetBLEDeviceName("TelinkLight"); - if (ret != CHIP_NO_ERROR) + err = ConnectivityMgr().SetBLEDeviceName("TelinkLight"); + if (err != CHIP_NO_ERROR) { LOG_ERR("Fail to set BLE device name"); - return ret; } - return CHIP_NO_ERROR; + return err; } CHIP_ERROR AppTask::StartApp() @@ -274,7 +283,7 @@ void AppTask::StartThreadHandler(AppEvent * aEvent) if (!chip::DeviceLayer::ConnectivityMgr().IsThreadProvisioned()) { // Switch context from BLE to Thread - BLEManagerImpl sInstance; + Internal::BLEManagerImpl sInstance; sInstance.SwitchToIeee802154(); StartDefaultThreadNetwork(); LOG_INF("Device is not commissioned to a Thread network. Starting with the default configuration."); diff --git a/integrations/cloudbuild/build-all.yaml b/integrations/cloudbuild/build-all.yaml index 17c343b0b0b2b2..e0dbcfaa61467c 100644 --- a/integrations/cloudbuild/build-all.yaml +++ b/integrations/cloudbuild/build-all.yaml @@ -6,7 +6,7 @@ steps: - "--init" - "--recursive" id: Submodules - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" env: - PW_ENVIRONMENT_ROOT=/pwenv args: @@ -21,7 +21,7 @@ steps: path: /pwenv timeout: 900s - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" env: - PW_ENVIRONMENT_ROOT=/pwenv args: diff --git a/integrations/cloudbuild/chef.yaml b/integrations/cloudbuild/chef.yaml index d8cf8c82655b3b..7abdf02bf9d3c9 100644 --- a/integrations/cloudbuild/chef.yaml +++ b/integrations/cloudbuild/chef.yaml @@ -1,5 +1,5 @@ steps: - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" env: - PW_ENVIRONMENT_ROOT=/pwenv args: @@ -12,7 +12,7 @@ steps: path: /pwenv timeout: 2700s - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" env: - PW_ENVIRONMENT_ROOT=/pwenv args: @@ -26,7 +26,7 @@ steps: - name: pwenv path: /pwenv - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" env: - PW_ENVIRONMENT_ROOT=/pwenv args: diff --git a/integrations/cloudbuild/smoke-test.yaml b/integrations/cloudbuild/smoke-test.yaml index 23cec5dec9f84a..a5d491519965b2 100644 --- a/integrations/cloudbuild/smoke-test.yaml +++ b/integrations/cloudbuild/smoke-test.yaml @@ -1,5 +1,5 @@ steps: - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" entrypoint: "bash" args: - "-c" @@ -7,7 +7,7 @@ steps: git config --global --add safe.directory "*" git submodule update --init --recursive id: Submodules - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" env: - PW_ENVIRONMENT_ROOT=/pwenv args: @@ -22,7 +22,7 @@ steps: path: /pwenv timeout: 900s - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" id: ESP32 env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -41,7 +41,7 @@ steps: - name: pwenv path: /pwenv - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" id: NRFConnect env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -62,7 +62,7 @@ steps: - name: pwenv path: /pwenv - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" id: EFR32 env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -84,7 +84,7 @@ steps: - name: pwenv path: /pwenv - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" id: Linux env: - PW_ENVIRONMENT_ROOT=/pwenv @@ -142,7 +142,7 @@ steps: - name: pwenv path: /pwenv - - name: "connectedhomeip/chip-build-vscode:0.6.05" + - name: "connectedhomeip/chip-build-vscode:0.6.06" id: Android env: - PW_ENVIRONMENT_ROOT=/pwenv diff --git a/scripts/tools/telink/generate_telink_chip_factory_data.py b/scripts/tools/telink/generate_telink_chip_factory_data.py new file mode 100644 index 00000000000000..2ec9b888accbc9 --- /dev/null +++ b/scripts/tools/telink/generate_telink_chip_factory_data.py @@ -0,0 +1,492 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2022 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. +# + +from os.path import exists +import os +import sys +import json +import jsonschema +import secrets +import argparse +import subprocess +import logging as log +import base64 +from collections import namedtuple +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.serialization import load_der_private_key + +# A user can not change the factory data version and must be coherent with +# the factory data version set in the Telink platform Kconfig file (CHIP_FACTORY_DATA_VERSION). +FACTORY_DATA_VERSION = 1 + +MATTER_ROOT = os.path.dirname(os.path.realpath(__file__))[:-len("/scripts/tools/telink")] +HEX_PREFIX = "hex:" +PUB_KEY_PREFIX = b'\x04' +INVALID_PASSCODES = [00000000, 11111111, 22222222, 33333333, 44444444, + 55555555, 66666666, 77777777, 88888888, 99999999, 12345678, 87654321] + + +def get_raw_private_key_der(der_file: str, password: str): + """ Split given der file to get separated key pair consisting of public and private keys. + + Args: + der_file (str): Path to .der file containing public and private keys + password (str): Password to decrypt Keys. It can be None, and then KEY is not encrypted. + + Returns: + hex string: return a hex string containing extracted and decrypted private KEY from given .der file. + """ + try: + with open(der_file, 'rb') as file: + key_data = file.read() + if password is None: + log.warning("KEY password has not been provided. It means that DAC key is not encrypted.") + keys = load_der_private_key(key_data, password, backend=default_backend()) + private_key = keys.private_numbers().private_value.to_bytes(32, byteorder='big') + + return private_key + + except IOError or ValueError: + return None + + +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, + paa_cert_path: str = None, + paa_key_path: str = None): + """ + 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 get from /credentials/test/attestation directory + in the Matter repository. + + 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 thee output directory. Defaults to False. + paa_cert_path (str, optional): provide PAA certification path. Defaults to None - a path will be set to /credentials/test/attestation directory. + paa_key_path (str, optional): provide PAA key path. Defaults to None - a path will be set to /credentials/test/attestation directory. + + Returns: + dictionary: ["PAI_CERT": (str), + "DAC_CERT": (str), + "DAC_KEY": (str)] + """ + + 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" + PAA_PATH = paa_cert_path if paa_cert_path != None else MATTER_ROOT + "/credentials/test/attestation/Chip-Test-PAA-NoVID-Cert.pem" + PAA_KEY_PATH = paa_key_path if paa_key_path != None else MATTER_ROOT + "/credentials/test/attestation/Chip-Test-PAA-NoVID-Key.pem" + + attestation_certs = namedtuple("attestation_certs", ["dac_cert", "dac_key", "pai_cert"]) + + log.info("Generating new certificates using chip-cert...") + + if generate_cd: + # generate Certification Declaration + cmd = [chip_cert_exe, "gen-cd", + "--key", CD_KEY_PATH, + "--cert", CD_PATH, + "--out", output + "/CD.der", + "--format-version", "1", + "--vendor-id", hex(vendor_id), + "--product-id", hex(product_id), + "--device-type-id", "0", + "--certificate-id", "FFFFFFFFFFFFFFFFFFF", + "--security-level", "0", + "--security-info", "0", + "--certification-type", str(cd_type), + "--version-number", "0xFFFF", + ] + subprocess.run(cmd) + + new_certificates = {"PAI_CERT": output + "/PAI_cert", + "PAI_KEY": output + "/PAI_key", + "DAC_CERT": output + "/DAC_cert", + "DAC_KEY": output + "/DAC_key" + } + + # generate PAI + cmd = [chip_cert_exe, "gen-att-cert", + "-t", "i", + "-c", device_name, + "-V", hex(vendor_id), + "-C", PAA_PATH, + "-K", PAA_KEY_PATH, + "-o", new_certificates["PAI_CERT"] + ".pem", + "-O", new_certificates["PAI_KEY"] + ".pem", + "-l", str(10000), + ] + subprocess.run(cmd) + + # generate DAC + cmd = [chip_cert_exe, "gen-att-cert", + "-t", "d", + "-c", device_name, + "-V", hex(vendor_id), + "-P", hex(product_id), + "-C", new_certificates["PAI_CERT"] + ".pem", + "-K", new_certificates["PAI_KEY"] + ".pem", + "-o", new_certificates["DAC_CERT"] + ".pem", + "-O", new_certificates["DAC_KEY"] + ".pem", + "-l", str(10000), + ] + subprocess.run(cmd) + + # convert 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, + cert_v + ".pem", + cert_v + ".der", + "--x509-der", + ] + subprocess.run(cmd) + + return attestation_certs(new_certificates["DAC_CERT"] + ".der", + new_certificates["DAC_KEY"] + ".der", + new_certificates["PAI_CERT"] + ".der") + + +def gen_spake2p_params(spake2p_path: str, passcode: int, it: int, salt: bytes) -> dict: + """ Generate Spake2+ params using external spake2p tool + + Args: + spake2p_path (str): path to spake2p executable + passcode (int): Pairing passcode using in Spake2+ + it (int): Iteration counter for Spake2+ verifier generation + salt (str): Salt used to generate Spake2+ verifier + + Returns: + dict: dictionary containing passcode, it, salt, and generated Verifier + """ + + cmd = [ + spake2p_path, 'gen-verifier', + '--iteration-count', str(it), + '--salt', base64.b64encode(salt), + '--pin-code', str(passcode), + '--out', '-', + ] + output = subprocess.check_output(cmd) + output = output.decode('utf-8').splitlines() + return dict(zip(output[0].split(','), output[1].split(','))) + + +class FactoryDataGenerator: + """ + Class to generate factory data from given arguments and generate a JSON file + + """ + + def __init__(self, arguments) -> None: + """ + Args: + arguments (any):All input arguments parsed using ArgParse + """ + self._args = arguments + self._factory_data = list() + self._user_data = dict() + + try: + self._validate_args() + except AssertionError as e: + log.error(e) + sys.exit(-1) + + def _validate_args(self): + if self._args.user: + try: + self._user_data = json.loads(self._args.user) + except json.decoder.JSONDecodeError as e: + raise AssertionError("Provided wrong user data, this is not a JSON format! {}".format(e)) + assert (self._args.spake2_verifier or (self._args.passcode and self._args.spake2p_path)), \ + "Cannot find Spake2+ verifier, to generate a new one please provide passcode (--passcode) and path to spake2p tool (--spake2p_path)" + assert (self._args.chip_cert_path or (self._args.dac_cert and self._args.pai_cert and self._args.dac_key)), \ + "Cannot find paths to DAC or PAI certificates .der files. To generate a new ones please provide a path to chip-cert executable (--chip_cert_path)" + assert self._args.output.endswith(".json"), \ + "Output path doesn't contain .json file path. ({})".format(self._args.output) + assert not (self._args.passcode in INVALID_PASSCODES), \ + "Provided invalid passcode!" + + def generate_json(self): + """ + This function generates JSON data, .json file and validates it. + + To validate generated JSON data a scheme must be provided within script's arguments. + + - In the first part, if the rotating device id unique id has been not provided + as an argument, it will be created. + - If user-provided passcode and Spake2+ verifier have been not provided + as an argument, it will be created using an external script + - Passcode is not stored in JSON by default. To store it for debugging purposes, add --include_passcode argument. + - Validating output JSON is not mandatory, but highly recommended. + + """ + # generate missing data if needed + if not self._args.rd_uid: + if self._args.generate_rd_uid: + rd_uid = self._generate_rotating_device_uid() + else: + # rotating device ID unique ID was not provided, so do not store it in factory data. + rd_uid = None + else: + rd_uid = HEX_PREFIX + self._args.rd_uid + + if not self._args.spake2_verifier: + spake_2_verifier = self._generate_spake2_verifier() + else: + spake_2_verifier = self._args.spake2_verifier + + # convert salt to bytestring to be coherent with Spake2+ verifier type + spake_2_salt = self._args.spake2_salt + + if self._args.chip_cert_path: + certs = gen_test_certs(self._args.chip_cert_path, + self._args.output[:self._args.output.rfind("/")], + self._args.vendor_id, + self._args.product_id, + self._args.vendor_name + "_" + self._args.product_name, + self._args.gen_cd, + self._args.cd_type, + self._args.paa_cert, + self._args.paa_key) + dac_cert = certs.dac_cert + pai_cert = certs.pai_cert + dac_key = certs.dac_key + else: + dac_cert = self._args.dac_cert + dac_key = self._args.dac_key + pai_cert = self._args.pai_cert + + # try to read DAC public and private keys + dac_priv_key = get_raw_private_key_der(dac_key, self._args.dac_key_password) + if dac_priv_key is None: + log.error("Cannot read DAC keys from : {}".format(dac_key)) + sys.exit(-1) + + try: + json_file = open(self._args.output, "w+") + except FileNotFoundError: + print("Cannot create JSON file in this location: {}".format(self._args.output)) + sys.exit(-1) + with json_file: + # serialize data + self._add_entry("version", FACTORY_DATA_VERSION) + self._add_entry("sn", self._args.sn) + self._add_entry("vendor_id", self._args.vendor_id) + self._add_entry("product_id", self._args.product_id) + self._add_entry("vendor_name", self._args.vendor_name) + self._add_entry("product_name", self._args.product_name) + self._add_entry("date", self._args.date) + self._add_entry("hw_ver", self._args.hw_ver) + self._add_entry("hw_ver_str", self._args.hw_ver_str) + self._add_entry("dac_cert", self._process_der(dac_cert)) + self._add_entry("dac_key", dac_priv_key) + self._add_entry("pai_cert", self._process_der(pai_cert)) + if self._args.include_passcode: + self._add_entry("passcode", self._args.passcode) + self._add_entry("spake2_it", self._args.spake2_it) + self._add_entry("spake2_salt", spake_2_salt) + self._add_entry("spake2_verifier", spake_2_verifier) + self._add_entry("discriminator", self._args.discriminator) + if rd_uid: + self._add_entry("rd_uid", rd_uid) + if self._args.enable_key: + self._add_entry("enable_key", HEX_PREFIX + self._args.enable_key) + if self._args.user: + self._add_entry("user", self._args.user) + + factory_data_dict = dict(self._factory_data) + + json_object = json.dumps(factory_data_dict) + is_json_valid = True + + if self._args.schema: + is_json_valid = self._validate_output_json(json_object) + else: + log.warning("JSON Schema file has not been provided, the output file can be wrong. Be aware of that.") + try: + if is_json_valid: + json_file.write(json_object) + except IOError as e: + log.error("Cannot save output file into directory: {}".format(self._args.output)) + + def _add_entry(self, name: str, value: any): + """ Add single entry to list of tuples ("key", "value") """ + if(isinstance(value, bytes) or isinstance(value, bytearray)): + value = HEX_PREFIX + value.hex() + if value or (isinstance(value, int) and value == 0): + log.debug("Adding entry '{}' with size {} and type {}".format(name, sys.getsizeof(value), type(value))) + self._factory_data.append((name, value)) + + def _generate_spake2_verifier(self): + """ If verifier has not been provided in arguments list it should be generated via external script """ + spake2_params = gen_spake2p_params(self._args.spake2p_path, self._args.passcode, + self._args.spake2_it, self._args.spake2_salt) + return base64.b64decode(spake2_params["Verifier"]) + + def _generate_rotating_device_uid(self): + """ If rotating device unique ID has not been provided it should be generated """ + log.warning("Cannot find rotating device UID in provided arguments list. A new one will be generated.") + rdu = secrets.token_bytes(16) + log.info("\n\nThe new rotate device UID: {}\n".format(rdu.hex())) + return rdu + + def _validate_output_json(self, output_json: str): + """ + Validate output JSON data with provided .scheme file + This function will raise error if JSON does not match schema. + + """ + try: + with open(self._args.schema) as schema_file: + log.info("Validating JSON with schema...") + schema = json.loads(schema_file.read()) + validator = jsonschema.Draft202012Validator(schema=schema) + validator.validate(instance=json.loads(output_json)) + except IOError as e: + log.error("Provided JSON schema file is wrong: {}".format(self._args.schema)) + return False + else: + log.info("Validate OK") + return True + + def _process_der(self, path: str): + log.debug("Processing der file...") + try: + with open(path, 'rb') as f: + data = f.read() + return data + except IOError as e: + log.error(e) + raise e + + +def main(): + parser = argparse.ArgumentParser(description="Telink Factory Data NVS generator tool") + + def allow_any_int(i): return int(i, 0) + def base64_str(s): return base64.b64decode(s) + + mandatory_arguments = parser.add_argument_group("Mandatory keys", "These arguments must be provided to generate JSON file") + optional_arguments = parser.add_argument_group( + "Optional keys", "These arguments are optional and they depend on the user-purpose") + parser.add_argument("-s", "--schema", type=str, + help="JSON schema file to validate JSON output data") + parser.add_argument("-o", "--output", type=str, required=True, + help="Output path to store .json file, e.g. my_dir/output.json") + parser.add_argument("-v", "--verbose", action="store_true", + help="Run this script with DEBUG logging level") + parser.add_argument("--include_passcode", action="store_true", + help="Include passcode in factory data. By default, it is used only for generating Spake2+ verifier.") + parser.add_argument("--overwrite", action="store_true", + help="If output JSON file exist this argument allows to generate new factory data and overwrite it.") + # Json known-keys values + # mandatory keys + mandatory_arguments.add_argument("--sn", type=str, required=True, + help="[ascii string] Serial number of a device which can be used to identify \ + the serial number field in the Matter certificate structure. \ + Maximum length of serial number is 20 bytes. \ + Strings longer than 20 bytes will be declined in script") + mandatory_arguments.add_argument("--vendor_id", type=allow_any_int, + help="[int | hex int] Provide Vendor Identification Number") + mandatory_arguments.add_argument("--product_id", type=allow_any_int, + help="[int | hex int] Provide Product Identification Number") + mandatory_arguments.add_argument("--vendor_name", type=str, + help="[string] provide human-readable vendor name") + mandatory_arguments.add_argument("--product_name", type=str, + help="[string] provide human-readable product name") + mandatory_arguments.add_argument("--date", type=str, required=True, + help="[ascii string] Provide manufacturing date \ + A manufacturing date specifies the date that the Node was manufactured. \ + Used format for providing a manufacturing date is ISO 8601 e.g. YYYY-MM-DD.") + mandatory_arguments.add_argument("--hw_ver", type=allow_any_int, required=True, + help="[int | hex int] Provide hardware version in int format.") + mandatory_arguments.add_argument("--hw_ver_str", type=str, required=True, + help="[ascii string] Provide hardware version in string format.") + mandatory_arguments.add_argument("--spake2_it", type=allow_any_int, required=True, + help="[int | hex int] Provide Spake2+ iteration count.") + mandatory_arguments.add_argument("--spake2_salt", type=base64_str, required=True, + help="[base64 string] Provide Spake2+ salt.") + mandatory_arguments.add_argument("--discriminator", type=allow_any_int, required=True, + help="[int] Provide BLE pairing discriminator. \ + A 12-bit value matching the field of the same name in \ + the setup code. Discriminator is used during a discovery process.") + + # optional keys + optional_arguments.add_argument("--chip_cert_path", type=str, + help="Generate DAC and PAI certificates instead giving a path to .der files. This option requires a path to chip-cert executable." + "By default You can find spake2p in connectedhomeip/src/tools/chip-cert directory and build it there.") + optional_arguments.add_argument("--dac_cert", type=str, + help="[.der] Provide the path to .der file containing DAC certificate.") + optional_arguments.add_argument("--dac_key", type=str, + help="[.der] Provide the path to .der file containing DAC keys.") + optional_arguments.add_argument("--generate_rd_uid", action="store_true", + help="Generate a new rotating device unique ID, print it out to console output and store it in factory data.") + optional_arguments.add_argument("--dac_key_password", type=str, + help="Provide a password to decode dac key. If dac key is not encrypted do not provide this argument.") + optional_arguments.add_argument("--pai_cert", type=str, + help="[.der] Provide the path to .der file containing PAI certificate.") + optional_arguments.add_argument("--rd_uid", type=str, + help="[hex string] [128-bit hex-encoded] Provide the rotating device unique ID. If this argument is not provided a new rotating device id unique id will be generated.") + optional_arguments.add_argument("--passcode", type=allow_any_int, + help="[int | hex] Default PASE session passcode. (This is mandatory to generate Spake2+ verifier).") + optional_arguments.add_argument("--spake2p_path", type=str, + help="[string] Provide a path to spake2p. By default You can find spake2p in connectedhomeip/src/tools/spake2p directory and build it there.") + optional_arguments.add_argument("--spake2_verifier", type=base64_str, + help="[base64 string] Provide Spake2+ verifier without generating it.") + optional_arguments.add_argument("--enable_key", type=str, + help="[hex string] [128-bit hex-encoded] The Enable Key is a 128-bit value that triggers manufacturer-specific action while invoking the TestEventTrigger Command." + "This value is used during Certification Tests, and should not be present on production devices.") + optional_arguments.add_argument("--user", type=str, + help="[string] Provide additional user-specific keys in JSON format: {'name_1': 'value_1', 'name_2': 'value_2', ... 'name_n', 'value_n'}.") + optional_arguments.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. This certificate will not be included to the factory data.") + optional_arguments.add_argument("--cd_type", type=int, default=1, + help="[int] Type of generated Certification Declaration: 0 - development, 1 - provisional, 2 - official") + optional_arguments.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 stored in the Matter repository will be used.") + optional_arguments.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 stored in the Matter repository will be used.") + args = parser.parse_args() + + if args.verbose: + log.basicConfig(format='[%(asctime)s][%(levelname)s] %(message)s', level=log.DEBUG) + else: + log.basicConfig(format='[%(levelname)s] %(message)s', level=log.INFO) + + # check if json file already exist + if(exists(args.output) and not args.overwrite): + log.error("Output file: {} already exist, to create a new one add argument '--overwrite'. By default overwriting is disabled".format(args.output)) + return + + generator = FactoryDataGenerator(args) + generator.generate_json() + + +if __name__ == "__main__": + main() diff --git a/scripts/tools/telink/telink_factory_data.schema b/scripts/tools/telink/telink_factory_data.schema new file mode 100644 index 00000000000000..16ffcc68dbd47b --- /dev/null +++ b/scripts/tools/telink/telink_factory_data.schema @@ -0,0 +1,147 @@ +{ + "$id": "Telink_Factory_Data_schema", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "A representation of all factory data used in Matter's Telink device", + "type": "object", + "required": [ + "version", + "sn", + "vendor_id", + "product_id", + "vendor_name", + "product_name", + "date", + "hw_ver", + "hw_ver_str", + "dac_cert", + "dac_key", + "pai_cert", + "spake2_it", + "spake2_salt", + "spake2_verifier", + "discriminator" + ], + "properties": { + "version": { + "description": "Current version of the factory data set", + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "sn": { + "description": "Serial number of device", + "type": "string", + "maxLength": 32 + }, + "vendor_id": { + "description": "Vendor Identifier", + "type": "integer", + "minimum": 0, + "maximum": 65524 + }, + "product_id": { + "description": "Product Identifier", + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "vendor_name": { + "description": "human-readable vendor name", + "type": "string", + "maxLength": 32 + }, + "product_name": { + "description": "human-readable product name", + "type": "string", + "maxLength": 32 + }, + "date": { + "description": "Manufacturing date according to ISO 8601 in notation YYYY-MM-DD", + "type": "string", + "format": "date" + }, + "hw_ver": { + "description": "Hardware version - integer", + "type": "integer", + "minimum": 0, + "maximum": 65536 + }, + "hw_ver_str": { + "description": "A string representation of hardware version", + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "rd_uid": { + "description": "A randomly-generated 128-bit or longer octet string. Length has been expanded with 'hex:' prefix", + "type": "string", + "pattern:": "^hex:{1}", + "minLength": 20, + "minLength": 5, + "maxLength": 36 + }, + "dac_cert": { + "description": "DAC certificate in hex-string format", + "type": "string", + "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}", + "minLength": 5, + "maxLength": 1204 + }, + "dac_key": { + "description": "DAC Private Key in hex-string format", + "type": "string", + "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}", + "minLength": 68, + "maxLength": 68 + }, + "pai_cert": { + "description": "PAI certificate in hex-string format", + "type": "string", + "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}", + "minLength": 5, + "maxLength": 1204 + }, + "passcode": { + "description": "A default PASE session passcode", + "type": "integer", + "minimum": 1, + "maximum": 99999998 + }, + "spake2_it": { + "description": "An Iteration counter for the Symmetric Password-Authenticated Key Exchange", + "type": "integer", + "minimum": 1000, + "maximum": 100000 + }, + "spake2_salt": { + "description": "A key-derivation function for the Symmetric Password-Authenticated Key Exchange.", + "type": "string", + "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}", + "minLength": 36, + "maxLength": 68 + }, + "spake2_verifier": { + "description": "A verifier for the Symmetric Password-Authenticated Key Exchange", + "type": "string", + "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}", + "minLength": 97 + }, + "discriminator": { + "description": "The Discriminator value helps to further identify potential devices during the setup process.", + "type": "integer", + "minimum": 0, + "maximum": 4095 + }, + "enable_key": { + "description": "The Enable Key is a 128-bit value that triggers manufacturer-specific action while invoking the TestEventTrigger Command", + "type": "string", + "pattern": "^hex:{1}([0-9A-Fa-f]){32}", + "minLength": 36, + "maxLength": 36 + }, + "user": { + "description": "A user-specific additional data which should be added to factory data. This should be a Json format.", + "type": "object" + } + } +} \ No newline at end of file diff --git a/scripts/tools/telink/telink_generate_partition.py b/scripts/tools/telink/telink_generate_partition.py new file mode 100644 index 00000000000000..ddd3b63acc4a7f --- /dev/null +++ b/scripts/tools/telink/telink_generate_partition.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2022 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 codecs +import sys +from intelhex import IntelHex +import argparse +import json +import logging as log +import cbor2 as cbor + +HEX_PREFIX = "hex:" + + +class PartitionCreator: + """ + Class to create telink partition containing FactoryData + + :param offset: This is a partition offset where data will be stored in device's flash memory + :param length: This is a maximum partition size + :param input: This is a path to input JSON file + :param output: This is a path to output directory + + """ + + def __init__(self, offset: int, length: int, input: str, output: str) -> None: + self._ih = IntelHex() + self._length = length + self._offset = offset + self._data_ready = False + self._output = output + self._input = input + try: + self.__data_to_save = self._convert_to_dict(self._load_json()) + except IOError: + sys.exit(-1) + + def generate_cbor(self): + """ + Generates .cbor file using cbor2 library. + It generate a CBORTag 55799 which is user-specific tag + + """ + if self.__data_to_save: + # prepare raw data from Json + cbor_data = cbor.dumps(self.__data_to_save) + return cbor_data + + def create_hex(self, data: bytes): + """ + Creates .hex file from CBOR. + This file can be write directly to device. + + """ + if len(data) > self._length: + raise ValueError("generated CBOR file exceeds declared maximum partition size! {} > {}".format(len(data), self._length)) + self._ih.putsz(self._offset, data) + self._ih.write_hex_file(self._output + ".hex", True) + self._data_ready = True + return True + + def create_bin(self): + """ + Creates raw binary data of created previously .hex file + + """ + if not self._data_ready: + log.error("Please create hex file first!") + return False + self._ih.tobinfile(self._output + ".bin") + return True + + @staticmethod + def _convert_to_dict(data): + """ + Converts a list containing tuples ("key_name", "key_value") to a dictionary + + If "key_value" of data entry is a string-type variable and contains a HEX_PREFIX algorithm decodes it + to hex format to be sure that a cbor file will contain proper bytes. + + If "key_value" of data entry is a dictionary, algorithm appends it to the created dictionary. + """ + output_dict = dict() + for entry in data: + if not isinstance(entry, dict): + log.debug("Processing entry {}".format(entry)) + if isinstance(data[entry], str) and data[entry].startswith(HEX_PREFIX): + output_dict[entry] = codecs.decode(data[entry][len(HEX_PREFIX):], "hex") + elif isinstance(data[entry], str): + output_dict[entry] = data[entry].encode("utf-8") + else: + output_dict[entry] = data[entry] + else: + output_dict[entry] = entry + return output_dict + + def _load_json(self): + """ + Loads file containing a JSON data and converts it to JSON format + + :raises IOError: if provided JSON file can not be read out. + """ + try: + with open(self._input, "rb") as json_file: + return json.loads(json_file.read()) + except IOError as e: + log.error("Can not read Json file {}".format(self._input)) + raise e + + +def print_flashing_help(): + print("\nTo flash the generated hex/bin containing factory data, use BDT tool") + + +def main(): + + def allow_any_int(i): return int(i, 0) + + parser = argparse.ArgumentParser(description="Telink Factory Data NVS partition generator tool") + parser.add_argument("-i", "--input", type=str, required=True, + help="Path to input .json file") + parser.add_argument("-o", "--output", type=str, required=True, + help="Prefix for output file paths, e.g. setting dir/output causes creation of the following files: dir/output.hex, and dir/output.bin") + parser.add_argument("--offset", type=allow_any_int, required=True, + help="Partition offset - an address in device's NVM memory, where factory data will be stored") + parser.add_argument("--size", type=allow_any_int, required=True, + help="The maximum partition size") + parser.add_argument("-v", "--verbose", action="store_true", + help="Run this script with DEBUG logging level") + parser.add_argument("-r", "--raw", action="store_true", + help="Do not print flashing help and other logs, only generate a .hex file. It can be useful when the script is used by other script.") + args = parser.parse_args() + + if args.verbose: + log.basicConfig(format='[%(asctime)s][%(levelname)s] %(message)s', level=log.DEBUG) + elif args.raw: + log.basicConfig(format='%(message)s', level=log.ERROR) + else: + log.basicConfig(format='[%(asctime)s] %(message)s', level=log.INFO) + + partition_creator = PartitionCreator(args.offset, args.size, args.input, args.output) + cbor_data = partition_creator.generate_cbor() + try: + if not args.raw: + print("Generating .hex file: {}.hex with offset: {} and size: {}".format(args.output, hex(args.offset), hex(args.size))) + if partition_creator.create_hex(cbor_data) and partition_creator.create_bin(): + if not args.raw: + print_flashing_help() + except ValueError as e: + log.error(e) + sys.exit(-1) + + +if __name__ == "__main__": + main() diff --git a/src/platform/telink/BUILD.gn b/src/platform/telink/BUILD.gn index d5644b09f5ceb0..b13a9d185ee8dd 100644 --- a/src/platform/telink/BUILD.gn +++ b/src/platform/telink/BUILD.gn @@ -16,6 +16,7 @@ import("//build_overrides/chip.gni") import("//build_overrides/telink.gni") import("${chip_root}/src/platform/device.gni") +import("${chip_root}/src/platform/telink/args.gni") assert(chip_device_platform == "telink") @@ -48,11 +49,26 @@ static_library("telink") { deps = [] + public = [ + "${chip_root}/src/credentials/CHIPCert.h", + "${chip_root}/src/credentials/CertificationDeclaration.h", + "${chip_root}/src/credentials/DeviceAttestationCredsProvider.h", + ] + public_deps = [ "${chip_root}/src/platform:platform_base", "${telink_sdk_build_root}", ] + if (chip_enable_factory_data) { + sources += [ + "FactoryDataParser.c", + "FactoryDataParser.h", + "FactoryDataProvider.cpp", + "FactoryDataProvider.h", + ] + } + if (chip_enable_openthread) { sources += [ "../OpenThread/OpenThreadUtils.cpp", diff --git a/src/platform/telink/CHIPDevicePlatformConfig.h b/src/platform/telink/CHIPDevicePlatformConfig.h index 8241a10bc534f8..4f45252aa2865b 100644 --- a/src/platform/telink/CHIPDevicePlatformConfig.h +++ b/src/platform/telink/CHIPDevicePlatformConfig.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2022 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. @@ -27,6 +27,42 @@ // ==================== Platform Adaptations ==================== +#ifndef CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER +#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER CONFIG_CHIP_DEVICE_SERIAL_NUMBER +#endif + +#ifndef CHIP_DEVICE_CONFIG_TEST_MANUFACTURING_DATE +#define CHIP_DEVICE_CONFIG_TEST_MANUFACTURING_DATE CONFIG_CHIP_DEVICE_MANUFACTURING_DATE +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION +#define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION CONFIG_CHIP_DEVICE_HARDWARE_VERSION +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE CONFIG_CHIP_DEVICE_PAIRING_PASSCODE +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR CONFIG_CHIP_DEVICE_DISCRIMINATOR +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING +#define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING CONFIG_CHIP_DEVICE_HARDWARE_VERSION_STRING +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT +#define CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT CONFIG_CHIP_DEVICE_SPAKE2_IT +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT +#define CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT CONFIG_CHIP_DEVICE_SPAKE2_SALT +#endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER +#define CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER CONFIG_CHIP_DEVICE_SPAKE2_TEST_VERIFIER +#endif + #ifndef CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID #define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID CONFIG_CHIP_DEVICE_VENDOR_ID #endif @@ -35,8 +71,12 @@ #define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID CONFIG_CHIP_DEVICE_PRODUCT_ID #endif -#ifdef CONFIG_CHIP_DEVICE_TYPE -#define CHIP_DEVICE_CONFIG_DEVICE_TYPE CONFIG_CHIP_DEVICE_TYPE +#ifndef CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME +#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME CONFIG_CHIP_DEVICE_VENDOR_NAME +#endif + +#ifndef CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME +#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME CONFIG_CHIP_DEVICE_PRODUCT_NAME #endif #ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION @@ -80,6 +120,58 @@ #endif // !defined(CONFIG_CHIP_MALLOC_SYS_HEAP) && defined(CONFIG_NEWLIB_LIBC) #endif // CHIP_DEVICE_CONFIG_HEAP_STATISTICS_MALLINFO +#ifndef CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION +//-> format_version = 1 +//-> vendor_id = 0xFFF1 +//-> product_id_array = [ 0x8000, 0x8001, 0x8002, 0x8003, 0x8004, 0x8005, 0x8006, 0x8007, 0x8008, 0x8009, 0x800A, 0x800B, +// 0x800C, 0x800D, 0x800E, 0x800F, 0x8010, 0x8011, 0x8012, 0x8013, 0x8014, 0x8015, 0x8016, 0x8017, 0x8018, 0x8019, 0x801A, +// 0x801B, 0x801C, 0x801D, 0x801E, 0x801F, 0x8020, 0x8021, 0x8022, 0x8023, 0x8024, 0x8025, 0x8026, 0x8027, 0x8028, 0x8029, +// 0x802A, 0x802B, 0x802C, 0x802D, 0x802E, 0x802F, 0x8030, 0x8031, 0x8032, 0x8033, 0x8034, 0x8035, 0x8036, 0x8037, 0x8038, +// 0x8039, 0x803A, 0x803B, 0x803C, 0x803D, 0x803E, 0x803F, 0x8040, 0x8041, 0x8042, 0x8043, 0x8044, 0x8045, 0x8046, 0x8047, +// 0x8048, 0x8049, 0x804A, 0x804B, 0x804C, 0x804D, 0x804E, 0x804F, 0x8050, 0x8051, 0x8052, 0x8053, 0x8054, 0x8055, 0x8056, +// 0x8057, 0x8058, 0x8059, 0x805A, 0x805B, 0x805C, 0x805D, 0x805E, 0x805F, 0x8060, 0x8061, 0x8062, 0x8063 ] +//-> device_type_id = 0x0016 +//-> certificate_id = "ZIG20142ZB330003-24" +//-> security_level = 0 +//-> security_information = 0 +//-> version_number = 0x2694 +//-> certification_type = 0 +//-> dac_origin_vendor_id is not present +//-> dac_origin_product_id is not present +#define CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION \ + { \ + 0x30, 0x82, 0x02, 0x19, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0x0a, 0x30, \ + 0x82, 0x02, 0x06, 0x02, 0x01, 0x03, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, \ + 0x02, 0x01, 0x30, 0x82, 0x01, 0x71, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, \ + 0x01, 0x62, 0x04, 0x82, 0x01, 0x5e, 0x15, 0x24, 0x00, 0x01, 0x25, 0x01, 0xf1, 0xff, 0x36, 0x02, 0x05, 0x00, 0x80, \ + 0x05, 0x01, 0x80, 0x05, 0x02, 0x80, 0x05, 0x03, 0x80, 0x05, 0x04, 0x80, 0x05, 0x05, 0x80, 0x05, 0x06, 0x80, 0x05, \ + 0x07, 0x80, 0x05, 0x08, 0x80, 0x05, 0x09, 0x80, 0x05, 0x0a, 0x80, 0x05, 0x0b, 0x80, 0x05, 0x0c, 0x80, 0x05, 0x0d, \ + 0x80, 0x05, 0x0e, 0x80, 0x05, 0x0f, 0x80, 0x05, 0x10, 0x80, 0x05, 0x11, 0x80, 0x05, 0x12, 0x80, 0x05, 0x13, 0x80, \ + 0x05, 0x14, 0x80, 0x05, 0x15, 0x80, 0x05, 0x16, 0x80, 0x05, 0x17, 0x80, 0x05, 0x18, 0x80, 0x05, 0x19, 0x80, 0x05, \ + 0x1a, 0x80, 0x05, 0x1b, 0x80, 0x05, 0x1c, 0x80, 0x05, 0x1d, 0x80, 0x05, 0x1e, 0x80, 0x05, 0x1f, 0x80, 0x05, 0x20, \ + 0x80, 0x05, 0x21, 0x80, 0x05, 0x22, 0x80, 0x05, 0x23, 0x80, 0x05, 0x24, 0x80, 0x05, 0x25, 0x80, 0x05, 0x26, 0x80, \ + 0x05, 0x27, 0x80, 0x05, 0x28, 0x80, 0x05, 0x29, 0x80, 0x05, 0x2a, 0x80, 0x05, 0x2b, 0x80, 0x05, 0x2c, 0x80, 0x05, \ + 0x2d, 0x80, 0x05, 0x2e, 0x80, 0x05, 0x2f, 0x80, 0x05, 0x30, 0x80, 0x05, 0x31, 0x80, 0x05, 0x32, 0x80, 0x05, 0x33, \ + 0x80, 0x05, 0x34, 0x80, 0x05, 0x35, 0x80, 0x05, 0x36, 0x80, 0x05, 0x37, 0x80, 0x05, 0x38, 0x80, 0x05, 0x39, 0x80, \ + 0x05, 0x3a, 0x80, 0x05, 0x3b, 0x80, 0x05, 0x3c, 0x80, 0x05, 0x3d, 0x80, 0x05, 0x3e, 0x80, 0x05, 0x3f, 0x80, 0x05, \ + 0x40, 0x80, 0x05, 0x41, 0x80, 0x05, 0x42, 0x80, 0x05, 0x43, 0x80, 0x05, 0x44, 0x80, 0x05, 0x45, 0x80, 0x05, 0x46, \ + 0x80, 0x05, 0x47, 0x80, 0x05, 0x48, 0x80, 0x05, 0x49, 0x80, 0x05, 0x4a, 0x80, 0x05, 0x4b, 0x80, 0x05, 0x4c, 0x80, \ + 0x05, 0x4d, 0x80, 0x05, 0x4e, 0x80, 0x05, 0x4f, 0x80, 0x05, 0x50, 0x80, 0x05, 0x51, 0x80, 0x05, 0x52, 0x80, 0x05, \ + 0x53, 0x80, 0x05, 0x54, 0x80, 0x05, 0x55, 0x80, 0x05, 0x56, 0x80, 0x05, 0x57, 0x80, 0x05, 0x58, 0x80, 0x05, 0x59, \ + 0x80, 0x05, 0x5a, 0x80, 0x05, 0x5b, 0x80, 0x05, 0x5c, 0x80, 0x05, 0x5d, 0x80, 0x05, 0x5e, 0x80, 0x05, 0x5f, 0x80, \ + 0x05, 0x60, 0x80, 0x05, 0x61, 0x80, 0x05, 0x62, 0x80, 0x05, 0x63, 0x80, 0x18, 0x24, 0x03, 0x16, 0x2c, 0x04, 0x13, \ + 0x5a, 0x49, 0x47, 0x32, 0x30, 0x31, 0x34, 0x32, 0x5a, 0x42, 0x33, 0x33, 0x30, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x34, \ + 0x24, 0x05, 0x00, 0x24, 0x06, 0x00, 0x25, 0x07, 0x94, 0x26, 0x24, 0x08, 0x00, 0x18, 0x31, 0x7d, 0x30, 0x7b, 0x02, \ + 0x01, 0x03, 0x80, 0x14, 0x62, 0xfa, 0x82, 0x33, 0x59, 0xac, 0xfa, 0xa9, 0x96, 0x3e, 0x1c, 0xfa, 0x14, 0x0a, 0xdd, \ + 0xf5, 0x04, 0xf3, 0x71, 0x60, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, \ + 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x04, 0x47, 0x30, 0x45, 0x02, 0x20, 0x24, 0xe5, \ + 0xd1, 0xf4, 0x7a, 0x7d, 0x7b, 0x0d, 0x20, 0x6a, 0x26, 0xef, 0x69, 0x9b, 0x7c, 0x97, 0x57, 0xb7, 0x2d, 0x46, 0x90, \ + 0x89, 0xde, 0x31, 0x92, 0xe6, 0x78, 0xc7, 0x45, 0xe7, 0xf6, 0x0c, 0x02, 0x21, 0x00, 0xf8, 0xaa, 0x2f, 0xa7, 0x11, \ + 0xfc, 0xb7, 0x9b, 0x97, 0xe3, 0x97, 0xce, 0xda, 0x66, 0x7b, 0xae, 0x46, 0x4e, 0x2b, 0xd3, 0xff, 0xdf, 0xc3, 0xcc, \ + 0xed, 0x7a, 0xa8, 0xca, 0x5f, 0x4c, 0x1a, 0x7c \ + } +#endif + // ========== Platform-specific Configuration Overrides ========= #ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY @@ -111,3 +203,11 @@ #define CHIP_DEVICE_CONFIG_ENABLE_THREAD_COMMISSIONABLE_DISCOVERY 1 #endif // CONFIG_CHIP_ENABLE_DNS_CLIENT #endif // CONFIG_CHIP_ENABLE_DNSSD_SRP + +#ifdef CONFIG_CHIP_DEVICE_TYPE +#define CHIP_DEVICE_CONFIG_DEVICE_TYPE CONFIG_CHIP_DEVICE_TYPE +#endif // CONFIG_CHIP_DEVICE_TYPE + +#ifdef CONFIG_CHIP_EXTENDED_DISCOVERY +#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 +#endif // CONFIG_CHIP_EXTENDED_DISCOVERY diff --git a/src/platform/telink/FactoryDataParser.c b/src/platform/telink/FactoryDataParser.c new file mode 100644 index 00000000000000..e89cf3b85d4c95 --- /dev/null +++ b/src/platform/telink/FactoryDataParser.c @@ -0,0 +1,167 @@ +/* + * + * Copyright (c) 2022 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. + */ + +#include "FactoryDataParser.h" + +#include +#include + +#include +#include + +#define MAX_FACTORY_DATA_NESTING_LEVEL 3 + +LOG_MODULE_DECLARE(app, CONFIG_MATTER_LOG_LEVEL); + +static inline bool uint16_decode(zcbor_state_t * states, uint16_t * value) +{ + uint32_t u32; + + if (zcbor_uint32_decode(states, &u32)) + { + *value = (uint16_t) u32; + return true; + } + + return false; +} + +bool ParseFactoryData(uint8_t * buffer, uint16_t bufferSize, struct FactoryData * factoryData) +{ + memset(factoryData, 0, sizeof(*factoryData)); + ZCBOR_STATE_D(states, MAX_FACTORY_DATA_NESTING_LEVEL, buffer, bufferSize, 1); + + bool res = zcbor_map_start_decode(states); + struct zcbor_string currentString; + + while (res) + { + res = zcbor_tstr_decode(states, ¤tString); + + if (!res) + { + res = true; + break; + } + + if (strncmp("version", (const char *) currentString.value, currentString.len) == 0) + { + res = res && uint16_decode(states, &factoryData->version); + } + else if (strncmp("hw_ver", (const char *) currentString.value, currentString.len) == 0) + { + res = res && uint16_decode(states, &factoryData->hw_ver); + factoryData->hwVerPresent = res; + } + else if (strncmp("spake2_it", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_uint32_decode(states, &factoryData->spake2_it); + } + else if (strncmp("vendor_id", (const char *) currentString.value, currentString.len) == 0) + { + res = res && uint16_decode(states, &factoryData->vendor_id); + factoryData->vendorIdPresent = res; + } + else if (strncmp("product_id", (const char *) currentString.value, currentString.len) == 0) + { + res = res && uint16_decode(states, &factoryData->product_id); + factoryData->productIdPresent = res; + } + else if (strncmp("discriminator", (const char *) currentString.value, currentString.len) == 0) + { + res = res && uint16_decode(states, &factoryData->discriminator); + factoryData->discriminatorPresent = res; + } + else if (strncmp("passcode", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_uint32_decode(states, &factoryData->passcode); + } + else if (strncmp("sn", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->sn); + } + else if (strncmp("date", (const char *) currentString.value, currentString.len) == 0) + { + // Date format is YYYY-MM-DD, so format needs to be validated and string parse to integer parts. + struct zcbor_string date; + res = res && zcbor_bstr_decode(states, &date); + if (date.len == 10 && isdigit(date.value[0]) && isdigit(date.value[1]) && isdigit(date.value[2]) && + isdigit(date.value[3]) && date.value[4] == '-' && isdigit(date.value[5]) && isdigit(date.value[6]) && + date.value[7] == '-' && isdigit(date.value[8]) && isdigit(date.value[9])) + { + factoryData->date_year = + 1000 * (date.value[0] - '0') + 100 * (date.value[1] - '0') + 10 * (date.value[2] - '0') + date.value[3] - '0'; + factoryData->date_month = 10 * (date.value[5] - '0') + date.value[6] - '0'; + factoryData->date_day = 10 * (date.value[8] - '0') + date.value[9] - '0'; + } + else + { + LOG_ERR("Parsing error - wrong date format"); + } + } + else if (strncmp("hw_ver_str", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->hw_ver_str); + } + else if (strncmp("rd_uid", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->rd_uid); + } + else if (strncmp("dac_cert", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->dac_cert); + } + else if (strncmp("dac_key", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->dac_priv_key); + } + else if (strncmp("pai_cert", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->pai_cert); + } + else if (strncmp("spake2_salt", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->spake2_salt); + } + else if (strncmp("spake2_verifier", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->spake2_verifier); + } + else if (strncmp("vendor_name", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->vendor_name); + } + else if (strncmp("product_name", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->product_name); + } + else if (strncmp("enable_key", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->enable_key); + } + else if (strncmp("user", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->user); + } + else + { + res = res && zcbor_any_skip(states, NULL); + } + } + + return res && zcbor_list_map_end_force_decode(states); +} diff --git a/src/platform/telink/FactoryDataParser.h b/src/platform/telink/FactoryDataParser.h new file mode 100644 index 00000000000000..156010ab66c527 --- /dev/null +++ b/src/platform/telink/FactoryDataParser.h @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2022 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. + */ + +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct FactoryDataString +{ + void * data; + size_t len; +}; + +struct FactoryData +{ + uint16_t version; + struct FactoryDataString sn; + uint16_t date_year; + uint8_t date_month; + uint8_t date_day; + uint16_t vendor_id; + uint16_t product_id; + struct FactoryDataString vendor_name; + struct FactoryDataString product_name; + uint16_t hw_ver; + struct FactoryDataString hw_ver_str; + struct FactoryDataString rd_uid; + struct FactoryDataString dac_cert; + struct FactoryDataString dac_priv_key; + struct FactoryDataString pai_cert; + uint32_t spake2_it; + struct FactoryDataString spake2_salt; + struct FactoryDataString spake2_verifier; + uint16_t discriminator; + uint32_t passcode; + struct FactoryDataString enable_key; + struct FactoryDataString user; + + bool vendorIdPresent; + bool productIdPresent; + bool hwVerPresent; + bool discriminatorPresent; +}; + +/** + * @brief Parses raw factory data into the factory data structure. + * + * @param[in] buffer Buffer containing raw factory data. + * @param[in] bufferSize Size of factory data. + * @param[out] factoryData address of object to be filled with parsed factory data. + * + * @returns true on success, false otherwise. + */ +bool ParseFactoryData(uint8_t * buffer, uint16_t bufferSize, struct FactoryData * factoryData); + +#ifdef __cplusplus +} +#endif diff --git a/src/platform/telink/FactoryDataProvider.cpp b/src/platform/telink/FactoryDataProvider.cpp new file mode 100644 index 00000000000000..38592270b1f4a0 --- /dev/null +++ b/src/platform/telink/FactoryDataProvider.cpp @@ -0,0 +1,341 @@ +/* + * + * Copyright (c) 2022 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. + */ + +#include "FactoryDataProvider.h" +#include "CHIPDevicePlatformConfig.h" +#include + +#if CONFIG_CHIP_CERTIFICATION_DECLARATION_STORAGE +#include +#include +#endif + +#include + +namespace chip { +namespace { + +CHIP_ERROR LoadKeypairFromRaw(ByteSpan privateKey, ByteSpan publicKey, Crypto::P256Keypair & keypair) +{ + Crypto::P256SerializedKeypair serializedKeypair; + ReturnErrorOnFailure(serializedKeypair.SetLength(privateKey.size() + publicKey.size())); + memcpy(serializedKeypair.Bytes(), publicKey.data(), publicKey.size()); + memcpy(serializedKeypair.Bytes() + publicKey.size(), privateKey.data(), privateKey.size()); + return keypair.Deserialize(serializedKeypair); +} +} // namespace + +namespace DeviceLayer { + +template +CHIP_ERROR FactoryDataProvider::Init() +{ + uint8_t * factoryData = nullptr; + size_t factoryDataSize; + + CHIP_ERROR error = mFlashFactoryData.ProtectFactoryDataPartitionAgainstWrite(); + + // Protection against write for external storage is not supported. + if (error == CHIP_ERROR_NOT_IMPLEMENTED) + { + ChipLogProgress(DeviceLayer, "The device does not support hardware protection against write."); + error = CHIP_NO_ERROR; + } + else if (error != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Failed to protect the factory data partition."); + return error; + } + + error = mFlashFactoryData.GetFactoryDataPartition(factoryData, factoryDataSize); + + if (error != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Failed to read factory data partition"); + return error; + } + + if (!ParseFactoryData(factoryData, factoryDataSize, &mFactoryData)) + { + ChipLogError(DeviceLayer, "Failed to parse factory data"); + return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + } + + // Check if factory data version is correct + if (mFactoryData.version != CONFIG_CHIP_FACTORY_DATA_VERSION) + { + ChipLogError(DeviceLayer, "Factory data version mismatch. Flash version: %d vs code version: %d", mFactoryData.version, + CONFIG_CHIP_FACTORY_DATA_VERSION); + return CHIP_ERROR_VERSION_MISMATCH; + } + + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetCertificationDeclaration(MutableByteSpan & outBuffer) +{ +#if CONFIG_CHIP_CERTIFICATION_DECLARATION_STORAGE + size_t cdLen = 0; + + if (Internal::ZephyrConfig::ReadConfigValueBin(Internal::ZephyrConfig::kConfigKey_CertificationDeclaration, + reinterpret_cast(outBuffer.data()), outBuffer.size(), + cdLen) == CHIP_NO_ERROR) + { + outBuffer.reduce_size(cdLen); + return CHIP_NO_ERROR; + } +#endif + constexpr uint8_t kCdForAllExamples[] = CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION; + + return CopySpanToMutableSpan(ByteSpan{ kCdForAllExamples }, outBuffer); +} + +template +CHIP_ERROR FactoryDataProvider::GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) +{ + out_firmware_info_buffer.reduce_size(0); + + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetDeviceAttestationCert(MutableByteSpan & outBuffer) +{ + ReturnErrorCodeIf(outBuffer.size() < mFactoryData.dac_cert.len, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorCodeIf(!mFactoryData.dac_cert.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + + memcpy(outBuffer.data(), mFactoryData.dac_cert.data, mFactoryData.dac_cert.len); + + outBuffer.reduce_size(mFactoryData.dac_cert.len); + + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetProductAttestationIntermediateCert(MutableByteSpan & outBuffer) +{ + ReturnErrorCodeIf(outBuffer.size() < mFactoryData.pai_cert.len, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorCodeIf(!mFactoryData.pai_cert.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + + memcpy(outBuffer.data(), mFactoryData.pai_cert.data, mFactoryData.pai_cert.len); + + outBuffer.reduce_size(mFactoryData.pai_cert.len); + + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::SignWithDeviceAttestationKey(const ByteSpan & messageToSign, + MutableByteSpan & outSignBuffer) +{ + Crypto::P256ECDSASignature signature; + Crypto::P256Keypair keypair; + + VerifyOrReturnError(outSignBuffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorCodeIf(!mFactoryData.dac_cert.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + ReturnErrorCodeIf(!mFactoryData.dac_priv_key.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + + // Extract public key from DAC cert. + ByteSpan dacCertSpan{ reinterpret_cast(mFactoryData.dac_cert.data), mFactoryData.dac_cert.len }; + chip::Crypto::P256PublicKey dacPublicKey; + + ReturnErrorOnFailure(chip::Crypto::ExtractPubkeyFromX509Cert(dacCertSpan, dacPublicKey)); + ReturnErrorOnFailure( + LoadKeypairFromRaw(ByteSpan(reinterpret_cast(mFactoryData.dac_priv_key.data), mFactoryData.dac_priv_key.len), + ByteSpan(dacPublicKey.Bytes(), dacPublicKey.Length()), keypair)); + ReturnErrorOnFailure(keypair.ECDSA_sign_msg(messageToSign.data(), messageToSign.size(), signature)); + + return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer); +} + +template +CHIP_ERROR FactoryDataProvider::GetSetupDiscriminator(uint16_t & setupDiscriminator) +{ + VerifyOrReturnError(mFactoryData.discriminatorPresent, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + setupDiscriminator = mFactoryData.discriminator; + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::SetSetupDiscriminator(uint16_t setupDiscriminator) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +template +CHIP_ERROR FactoryDataProvider::GetSpake2pIterationCount(uint32_t & iterationCount) +{ + ReturnErrorCodeIf(mFactoryData.spake2_it == 0, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + iterationCount = mFactoryData.spake2_it; + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetSpake2pSalt(MutableByteSpan & saltBuf) +{ + ReturnErrorCodeIf(saltBuf.size() < mFactoryData.spake2_salt.len, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorCodeIf(!mFactoryData.spake2_salt.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + + memcpy(saltBuf.data(), mFactoryData.spake2_salt.data, mFactoryData.spake2_salt.len); + + saltBuf.reduce_size(mFactoryData.spake2_salt.len); + + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & verifierLen) +{ + ReturnErrorCodeIf(verifierBuf.size() < mFactoryData.spake2_verifier.len, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorCodeIf(!mFactoryData.spake2_verifier.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + + memcpy(verifierBuf.data(), mFactoryData.spake2_verifier.data, mFactoryData.spake2_verifier.len); + + verifierLen = mFactoryData.spake2_verifier.len; + + verifierBuf.reduce_size(verifierLen); + + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetSetupPasscode(uint32_t & setupPasscode) +{ + ReturnErrorCodeIf(mFactoryData.passcode == 0, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + setupPasscode = mFactoryData.passcode; + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::SetSetupPasscode(uint32_t setupPasscode) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +template +CHIP_ERROR FactoryDataProvider::GetVendorName(char * buf, size_t bufSize) +{ + ReturnErrorCodeIf(bufSize < mFactoryData.vendor_name.len + 1, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorCodeIf(!mFactoryData.vendor_name.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + + memcpy(buf, mFactoryData.vendor_name.data, mFactoryData.vendor_name.len); + buf[mFactoryData.vendor_name.len] = 0; + + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetVendorId(uint16_t & vendorId) +{ + VerifyOrReturnError(mFactoryData.vendorIdPresent, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + vendorId = mFactoryData.vendor_id; + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetProductName(char * buf, size_t bufSize) +{ + ReturnErrorCodeIf(bufSize < mFactoryData.product_name.len + 1, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorCodeIf(!mFactoryData.product_name.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + + memcpy(buf, mFactoryData.product_name.data, mFactoryData.product_name.len); + buf[mFactoryData.product_name.len] = 0; + + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetProductId(uint16_t & productId) +{ + VerifyOrReturnError(mFactoryData.productIdPresent, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + productId = mFactoryData.product_id; + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetSerialNumber(char * buf, size_t bufSize) +{ + ReturnErrorCodeIf(bufSize < mFactoryData.sn.len + 1, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorCodeIf(!mFactoryData.sn.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + + memcpy(buf, mFactoryData.sn.data, mFactoryData.sn.len); + buf[mFactoryData.sn.len] = 0; + + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) +{ + VerifyOrReturnError(mFactoryData.date_year != 0, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + year = mFactoryData.date_year; + month = mFactoryData.date_month; + day = mFactoryData.date_day; + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetHardwareVersion(uint16_t & hardwareVersion) +{ + VerifyOrReturnError(mFactoryData.hwVerPresent, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + hardwareVersion = mFactoryData.hw_ver; + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetHardwareVersionString(char * buf, size_t bufSize) +{ + ReturnErrorCodeIf(bufSize < mFactoryData.hw_ver_str.len + 1, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorCodeIf(!mFactoryData.hw_ver_str.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + + memcpy(buf, mFactoryData.hw_ver_str.data, mFactoryData.hw_ver_str.len); + buf[mFactoryData.hw_ver_str.len] = 0; + + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) +{ + ReturnErrorCodeIf(uniqueIdSpan.size() < mFactoryData.rd_uid.len, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorCodeIf(!mFactoryData.rd_uid.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + + memcpy(uniqueIdSpan.data(), mFactoryData.rd_uid.data, mFactoryData.rd_uid.len); + + return CHIP_NO_ERROR; +} + +template +CHIP_ERROR FactoryDataProvider::GetEnableKey(MutableByteSpan & enableKey) +{ + ReturnErrorCodeIf(!mFactoryData.enable_key.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + ReturnErrorCodeIf(enableKey.size() < mFactoryData.enable_key.len, CHIP_ERROR_BUFFER_TOO_SMALL); + + memcpy(enableKey.data(), mFactoryData.enable_key.data, mFactoryData.enable_key.len); + + enableKey.reduce_size(mFactoryData.enable_key.len); + + return CHIP_NO_ERROR; +} + +// Fully instantiate the template class in whatever compilation unit includes this file. +// template class FactoryDataProvider; +template class FactoryDataProvider; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/telink/FactoryDataProvider.h b/src/platform/telink/FactoryDataProvider.h new file mode 100644 index 00000000000000..79d34a6b9fdd84 --- /dev/null +++ b/src/platform/telink/FactoryDataProvider.h @@ -0,0 +1,117 @@ +/* + * + * Copyright (c) 2022 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +#include "FactoryDataParser.h" + +namespace chip { +namespace DeviceLayer { + +struct InternalFlashFactoryData +{ + CHIP_ERROR GetFactoryDataPartition(uint8_t *& data, size_t & dataSize) + { + data = reinterpret_cast(FLASH_AREA_OFFSET(factory_data)); + dataSize = FLASH_AREA_SIZE(factory_data); + return CHIP_NO_ERROR; + } + + CHIP_ERROR ProtectFactoryDataPartitionAgainstWrite() { return CHIP_ERROR_NOT_IMPLEMENTED; } +}; + +struct ExternalFlashFactoryData +{ + CHIP_ERROR GetFactoryDataPartition(uint8_t *& data, size_t & dataSize) + { + int ret = flash_read(mFlashDevice, FLASH_AREA_OFFSET(factory_data), mFactoryDataBuffer, FLASH_AREA_SIZE(factory_data)); + + if (ret != 0) + { + return CHIP_ERROR_READ_FAILED; + } + + data = mFactoryDataBuffer; + dataSize = FLASH_AREA_SIZE(factory_data); + + return CHIP_NO_ERROR; + } + + CHIP_ERROR ProtectFactoryDataPartitionAgainstWrite() { return CHIP_ERROR_NOT_IMPLEMENTED; } + + const struct device * mFlashDevice = DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller)); + uint8_t mFactoryDataBuffer[FLASH_AREA_SIZE(factory_data)]; +}; + +template +class FactoryDataProvider : public chip::Credentials::DeviceAttestationCredentialsProvider, + public CommissionableDataProvider, + public DeviceInstanceInfoProvider +{ +public: + CHIP_ERROR Init(); + + // ===== Members functions that implement the DeviceAttestationCredentialsProvider + CHIP_ERROR GetCertificationDeclaration(MutableByteSpan & outBuffer) override; + CHIP_ERROR GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) override; + CHIP_ERROR GetDeviceAttestationCert(MutableByteSpan & outBuffer) override; + CHIP_ERROR GetProductAttestationIntermediateCert(MutableByteSpan & outBuffer) override; + CHIP_ERROR SignWithDeviceAttestationKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer) override; + + // ===== Members functions that implement the CommissionableDataProvider + CHIP_ERROR GetSetupDiscriminator(uint16_t & setupDiscriminator) override; + CHIP_ERROR SetSetupDiscriminator(uint16_t setupDiscriminator) override; + CHIP_ERROR GetSpake2pIterationCount(uint32_t & iterationCount) override; + CHIP_ERROR GetSpake2pSalt(MutableByteSpan & saltBuf) override; + CHIP_ERROR GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & verifierLen) override; + CHIP_ERROR GetSetupPasscode(uint32_t & setupPasscode) override; + CHIP_ERROR SetSetupPasscode(uint32_t setupPasscode) override; + + // ===== Members functions that implement the DeviceInstanceInfoProvider + CHIP_ERROR GetVendorName(char * buf, size_t bufSize) override; + CHIP_ERROR GetVendorId(uint16_t & vendorId) override; + CHIP_ERROR GetProductName(char * buf, size_t bufSize) override; + CHIP_ERROR GetProductId(uint16_t & productId) override; + CHIP_ERROR GetSerialNumber(char * buf, size_t bufSize) override; + CHIP_ERROR GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) override; + CHIP_ERROR GetHardwareVersion(uint16_t & hardwareVersion) override; + CHIP_ERROR GetHardwareVersionString(char * buf, size_t bufSize) override; + CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override; + + // ===== Members functions that are platform-specific + CHIP_ERROR GetEnableKey(MutableByteSpan & enableKey); + +private: + static constexpr uint16_t kFactoryDataPartitionSize = FLASH_AREA_SIZE(factory_data); + static constexpr uint32_t kFactoryDataPartitionAddress = FLASH_AREA_OFFSET(factory_data); + static constexpr uint8_t kDACPrivateKeyLength = 32; + static constexpr uint8_t kDACPublicKeyLength = 65; + + struct FactoryData mFactoryData; + FlashFactoryData mFlashFactoryData; +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/telink/args.gni b/src/platform/telink/args.gni index 1ff86d0b38c074..a8307083a7d217 100644 --- a/src/platform/telink/args.gni +++ b/src/platform/telink/args.gni @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Project CHIP Authors +# Copyright (c) 2022 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. @@ -15,3 +15,8 @@ chip_device_platform = "telink" chip_inet_config_enable_ipv4 = false + +declare_args() { + # Enable factory data support + chip_enable_factory_data = false +} diff --git a/src/platform/telink/telink-mbedtls-config.h b/src/platform/telink/telink-mbedtls-config.h index d0de1d19734a4f..0a37b4a632e274 100644 --- a/src/platform/telink/telink-mbedtls-config.h +++ b/src/platform/telink/telink-mbedtls-config.h @@ -1,20 +1,25 @@ -/****************************************************************************** - * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK") - * 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 + * Copyright (c) 2022 Project CHIP Authors * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 * - * 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. + * 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. + */ + +/** + * @file + * Telink mbedtls configuration file. + * + */ #ifndef MBEDTLS_TSLR9_CONF_H #define MBEDTLS_TSLR9_CONF_H