Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[nrfconnect] Created a CMAKE script to generate factory data #19153

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions config/nrfconnect/chip-module/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,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
Expand Down Expand Up @@ -350,4 +351,12 @@ if (CONFIG_CHIP_OTA_IMAGE_BUILD)
add_dependencies(chip-ota-image dfu_multi_image_pkg)
endif()

# ==============================================================================
# Define 'factory_data' target for generating a factory data partition
# ==============================================================================

if(CONFIG_CHIP_FACTORY_DATA_BUILD)
nrfconnect_generate_factory_data()
endif()

endif() # CONFIG_CHIP
152 changes: 152 additions & 0 deletions config/nrfconnect/chip-module/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,155 @@ config CHIP_DEBUG_SYMBOLS
default y
help
Build the application with debug symbols.

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 in the partition manager
configuration file pm_static.yml.
As a result a new output file factory_data.hex will be created.

if CHIP_FACTORY_DATA_BUILD

# Factory data definitions
config CHIP_MERGE_FACTORY_DATA_WITH_FIRMWARE
bool "Enable merging generated factory data with the build target .hex file"
default y
help
Enables merging generated factory data with the build target merged.hex file.
As a result, a new output file merged.hex will consist of all partitions including
factory data.

# Use default certificates without generating or providing them
config CHIP_FACTORY_DATA_USE_DEFAULTS_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 "Nordic Semiconductor ASA"
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.
206 changes: 206 additions & 0 deletions config/nrfconnect/chip-module/generate_factory_data.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
#
# 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_MERGE_FACTORY_DATA_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:
# - <factory_data_target>.args a file containing arguments for nrfconnect_generate_partition.py script.
# - <factory_data_target>.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(nrfconnect_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()
endif()

# for development purpose user can use default certs instead of generating or providing them
if(CONFIG_CHIP_FACTORY_DATA_USE_DEFAULTS_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()
# try to generate a new DAC and PAI certs and DAC key
# request script to generate a new certificates
# by adding an argument to script_args
find_program(chip-cert NAMES chip-cert)
if(NOT chip-cert)
message(FATAL_ERROR "Could not find chip_cert_path executable in PATH")
endif()
string(APPEND script_args "--chip_cert_path ${chip-cert}\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")

# 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)
if(NOT spake_exe)
message(FATAL_ERROR "Could not find spake2p executable in PATH")
endif()
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()

# Set output JSON file and path to SCHEMA file to validate generated factory data
string(APPEND script_args "-o \"${output_path}/${factory_data_target}.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_target(${factory_data_target} ALL
COMMAND ${Python3_EXECUTABLE} ${FACTORY_DATA_SCRIPT_PATH} ${separated_script_args}
COMMENT "Generating new Factory Data..."
)

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:
# - <factory_data_target>_cbor.args a file containing arguments for nrfconnect_generate_partition.py script.
# - <factory_data_target>.hex a file containing all factory data in CBOR format.
# - <factory_data_target>.bin a binary file containing all raw factory data in CBOR format.
# - <factory_data_target>.cbor a file containing all factory data in CBOR format.
#
# [Args]:
# factory_data_target - a name for target to generate factory_data.
# 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.
# output_hex - an output variable to store a .hex file. This variable can be used to merge with firmware .hex file.
function(nrfconnect_create_factory_data_hex_file factory_data_target script_path output_path output_hex)

# 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 $<TARGET_PROPERTY:partition_manager,PM_FACTORY_DATA_ADDRESS>\n")
string(APPEND cbor_script_args "--size $<TARGET_PROPERTY:partition_manager,PM_FACTORY_DATA_OFFSET>\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)

# return output hex to parent scope
set(${output_hex} ${factory_data_hex} PARENT_SCOPE)
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}
)

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(nrfconnect_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/nrfconnect/generate_nrfconnect_chip_factory_data.py)
set(GENERATE_CBOR_SCRIPT_PATH ${CHIP_ROOT}/scripts/tools/nrfconnect/nrfconnect_generate_partition.py)
SET(MERGE_HEX_SCRIPT_PATH ${CHIP_ROOT}/config/nrfconnect/chip-module/merge_factory_data.py)
set(FACTORY_DATA_SCHEMA_PATH ${CHIP_ROOT}/scripts/tools/nrfconnect/nrfconnect_factory_data.schema)
set(OUTPUT_FILE_PATH ${APPLICATION_BINARY_DIR}/zephyr)

# create a JSON file with all factory data
nrfconnect_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
nrfconnect_create_factory_data_hex_file(factory_data
${GENERATE_CBOR_SCRIPT_PATH}
${OUTPUT_FILE_PATH}
factory_data_hex)

if(CONFIG_CHIP_MERGE_FACTORY_DATA_WITH_FIRMWARE)
# set custom target for merging factory_data hex file
add_custom_target(factory_data_merge
DEPENDS ${factory_data_hex}
)
set_property(GLOBAL PROPERTY
factory_data_PM_HEX_FILE
${factory_data_hex}
)
set_property(GLOBAL PROPERTY
${parent_slot}_PM_TARGET
${target_name}_merge
)
endif()


endfunction()
Loading