diff --git a/config/telink/chip-module/generate_factory_data.cmake b/config/telink/chip-module/generate_factory_data.cmake index ff9514e6707481..72d99e450bbf2c 100644 --- a/config/telink/chip-module/generate_factory_data.cmake +++ b/config/telink/chip-module/generate_factory_data.cmake @@ -63,10 +63,11 @@ 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) + string(TOUPPER ${raw_pid} raw_pid_upper) # 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 "--dac_cert \"${CHIP_ROOT}/credentials/development/attestation/Matter-Development-DAC-${raw_pid_upper}-Cert.der\"\n") + string(APPEND script_args "--dac_key \"${CHIP_ROOT}/credentials/development/attestation/Matter-Development-DAC-${raw_pid_upper}-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) @@ -79,6 +80,7 @@ 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 "--include_passcode\n") string(APPEND script_args "--overwrite\n") # check if spake2 verifier should be generated using script diff --git a/scripts/tools/telink/generate_telink_chip_factory_data.py b/scripts/tools/telink/generate_telink_chip_factory_data.py index 2ec9b888accbc9..7605184700461a 100644 --- a/scripts/tools/telink/generate_telink_chip_factory_data.py +++ b/scripts/tools/telink/generate_telink_chip_factory_data.py @@ -171,29 +171,25 @@ def gen_test_certs(chip_cert_exe: str, 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 +def gen_spake2p_verifier(passcode: int, it: int, salt: bytes) -> str: + """ Generate Spake2+ verifier using SPAKE2+ Python 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 + verifier encoded in Base64 """ cmd = [ - spake2p_path, 'gen-verifier', + os.path.join(MATTER_ROOT, 'scripts/tools/spake2p/spake2p.py'), 'gen-verifier', + '--passcode', str(passcode), + '--salt', base64.b64encode(salt).decode('ascii'), '--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(','))) + return subprocess.check_output(cmd) class FactoryDataGenerator: @@ -223,8 +219,8 @@ def _validate_args(self): 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.spake2_verifier or self._args.passcode, \ + "Cannot find Spake2+ verifier, to generate a new one please provide passcode (--passcode)" 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"), \ @@ -301,6 +297,9 @@ def generate_json(self): 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("product_label", self._args.product_label) + self._add_entry("product_url", self._args.product_url) + self._add_entry("part_number", self._args.part_number) 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) @@ -345,9 +344,7 @@ def _add_entry(self, name: str, value: any): 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"]) + return base64.b64decode(gen_spake2p_verifier(self._args.passcode, self._args.spake2_it, self._args.spake2_salt)) def _generate_rotating_device_uid(self): """ If rotating device unique ID has not been provided it should be generated """ @@ -438,9 +435,15 @@ def base64_str(s): return base64.b64decode(s) the setup code. Discriminator is used during a discovery process.") # optional keys + optional_arguments.add_argument("--product_url", type=str, + help="[string] provide link to product-specific web page") + optional_arguments.add_argument("--product_label", type=str, + help="[string] provide human-readable product label") + optional_arguments.add_argument("--part_number", type=str, + help="[string] provide human-readable product number") 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.") + "By default you can find chip-cert 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, @@ -455,8 +458,6 @@ def base64_str(s): return base64.b64decode(s) 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, diff --git a/scripts/tools/telink/telink_factory_data.schema b/scripts/tools/telink/telink_factory_data.schema index 16ffcc68dbd47b..561bf4d5d72682 100644 --- a/scripts/tools/telink/telink_factory_data.schema +++ b/scripts/tools/telink/telink_factory_data.schema @@ -55,10 +55,28 @@ "type": "string", "maxLength": 32 }, + "product_label": { + "description": "more user-friendly human-readable product name", + "type": "string", + "maxLength": 64 + }, + "product_url": { + "description": "link to product-specific web page", + "type": "string", + "maxLength": 256 + }, + "part_number": { + "description": "human-readable vendor assigned part number", + "type": "string", + "maxLength": 32 + }, "date": { "description": "Manufacturing date according to ISO 8601 in notation YYYY-MM-DD", "type": "string", - "format": "date" + "format": "date", + "minLength": 10, + "maxLength": 10, + "pattern": "^\\d{4}-\\d{2}-\\d{2}$" }, "hw_ver": { "description": "Hardware version - integer", @@ -75,30 +93,29 @@ "rd_uid": { "description": "A randomly-generated 128-bit or longer octet string. Length has been expanded with 'hex:' prefix", "type": "string", - "pattern:": "^hex:{1}", + "pattern": "^hex:([0-9A-Fa-f]{2}){16,}$", "minLength": 20, - "minLength": 5, - "maxLength": 36 + "minLength": 36 }, "dac_cert": { "description": "DAC certificate in hex-string format", "type": "string", - "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}", - "minLength": 5, + "pattern": "^hex:([0-9A-Fa-f]{2})+$", + "minLength": 6, "maxLength": 1204 }, "dac_key": { "description": "DAC Private Key in hex-string format", "type": "string", - "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}", + "pattern": "^hex:([0-9A-Fa-f]{2}){32}$", "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, + "pattern": "^hex:([0-9A-Fa-f]{2})+$", + "minLength": 6, "maxLength": 1204 }, "passcode": { @@ -116,14 +133,14 @@ "spake2_salt": { "description": "A key-derivation function for the Symmetric Password-Authenticated Key Exchange.", "type": "string", - "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}", + "pattern": "^hex:([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,}", + "pattern": "^hex:([0-9A-Fa-f]{2})+$", "minLength": 97 }, "discriminator": { @@ -135,7 +152,7 @@ "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}", + "pattern": "^hex:([0-9A-Fa-f]{2}){16}$", "minLength": 36, "maxLength": 36 }, @@ -144,4 +161,4 @@ "type": "object" } } -} \ No newline at end of file +} diff --git a/src/platform/telink/CHIPDevicePlatformConfig.h b/src/platform/telink/CHIPDevicePlatformConfig.h index 4f45252aa2865b..6af8812f70d5a8 100644 --- a/src/platform/telink/CHIPDevicePlatformConfig.h +++ b/src/platform/telink/CHIPDevicePlatformConfig.h @@ -40,7 +40,7 @@ #endif #ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE -#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE CONFIG_CHIP_DEVICE_PAIRING_PASSCODE +#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE CONFIG_CHIP_DEVICE_SPAKE2_PASSCODE #endif #ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR diff --git a/src/platform/telink/FactoryDataParser.c b/src/platform/telink/FactoryDataParser.c index e89cf3b85d4c95..87107753a71711 100644 --- a/src/platform/telink/FactoryDataParser.c +++ b/src/platform/telink/FactoryDataParser.c @@ -149,6 +149,18 @@ bool ParseFactoryData(uint8_t * buffer, uint16_t bufferSize, struct FactoryData { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->product_name); } + else if (strncmp("part_number", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->part_number); + } + else if (strncmp("product_url", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->product_url); + } + else if (strncmp("product_label", (const char *) currentString.value, currentString.len) == 0) + { + res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->product_label); + } else if (strncmp("enable_key", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->enable_key); diff --git a/src/platform/telink/FactoryDataParser.h b/src/platform/telink/FactoryDataParser.h index 156010ab66c527..9c87589560d469 100644 --- a/src/platform/telink/FactoryDataParser.h +++ b/src/platform/telink/FactoryDataParser.h @@ -42,6 +42,9 @@ struct FactoryData uint16_t product_id; struct FactoryDataString vendor_name; struct FactoryDataString product_name; + struct FactoryDataString part_number; + struct FactoryDataString product_url; + struct FactoryDataString product_label; uint16_t hw_ver; struct FactoryDataString hw_ver_str; struct FactoryDataString rd_uid; diff --git a/src/platform/telink/FactoryDataProvider.cpp b/src/platform/telink/FactoryDataProvider.cpp index 38592270b1f4a0..77bacdca379dd8 100644 --- a/src/platform/telink/FactoryDataProvider.cpp +++ b/src/platform/telink/FactoryDataProvider.cpp @@ -37,6 +37,18 @@ CHIP_ERROR LoadKeypairFromRaw(ByteSpan privateKey, ByteSpan publicKey, Crypto::P memcpy(serializedKeypair.Bytes() + publicKey.size(), privateKey.data(), privateKey.size()); return keypair.Deserialize(serializedKeypair); } + +CHIP_ERROR GetFactoryDataString(const FactoryDataString & str, char * buf, size_t bufSize) +{ + ReturnErrorCodeIf(bufSize < str.len + 1, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorCodeIf(!str.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + + memcpy(buf, str.data, str.len); + buf[str.len] = 0; + + return CHIP_NO_ERROR; +} + } // namespace namespace DeviceLayer { @@ -230,13 +242,7 @@ CHIP_ERROR FactoryDataProvider::SetSetupPasscode(uint32_t setu 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; + return GetFactoryDataString(mFactoryData.vendor_name, buf, bufSize); } template @@ -250,13 +256,7 @@ CHIP_ERROR FactoryDataProvider::GetVendorId(uint16_t & vendorI 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; + return GetFactoryDataString(mFactoryData.product_name, buf, bufSize); } template @@ -268,15 +268,27 @@ CHIP_ERROR FactoryDataProvider::GetProductId(uint16_t & produc } template -CHIP_ERROR FactoryDataProvider::GetSerialNumber(char * buf, size_t bufSize) +CHIP_ERROR FactoryDataProvider::GetPartNumber(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); + return GetFactoryDataString(mFactoryData.part_number, buf, bufSize); +} - memcpy(buf, mFactoryData.sn.data, mFactoryData.sn.len); - buf[mFactoryData.sn.len] = 0; +template +CHIP_ERROR FactoryDataProvider::GetProductURL(char * buf, size_t bufSize) +{ + return GetFactoryDataString(mFactoryData.product_url, buf, bufSize); +} - return CHIP_NO_ERROR; +template +CHIP_ERROR FactoryDataProvider::GetProductLabel(char * buf, size_t bufSize) +{ + return GetFactoryDataString(mFactoryData.product_label, buf, bufSize); +} + +template +CHIP_ERROR FactoryDataProvider::GetSerialNumber(char * buf, size_t bufSize) +{ + return GetFactoryDataString(mFactoryData.sn, buf, bufSize); } template @@ -300,13 +312,7 @@ CHIP_ERROR FactoryDataProvider::GetHardwareVersion(uint16_t & 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; + return GetFactoryDataString(mFactoryData.hw_ver_str, buf, bufSize); } template diff --git a/src/platform/telink/FactoryDataProvider.h b/src/platform/telink/FactoryDataProvider.h index 79d34a6b9fdd84..040a0d44ca9ba8 100644 --- a/src/platform/telink/FactoryDataProvider.h +++ b/src/platform/telink/FactoryDataProvider.h @@ -94,6 +94,9 @@ class FactoryDataProvider : public chip::Credentials::DeviceAttestationCredentia 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 GetPartNumber(char * buf, size_t bufSize) override; + CHIP_ERROR GetProductURL(char * buf, size_t bufSize) override; + CHIP_ERROR GetProductLabel(char * buf, size_t bufSize) 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;