Skip to content

Commit

Permalink
[Telink] fix factory data as pr project-chip#23385 (project-chip#23559)
Browse files Browse the repository at this point in the history
  • Loading branch information
s07641069 authored and adbridge committed Nov 17, 2022
1 parent 12e8e24 commit 98b7bc2
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 62 deletions.
6 changes: 4 additions & 2 deletions config/telink/chip-module/generate_factory_data.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
39 changes: 20 additions & 19 deletions scripts/tools/telink/generate_telink_chip_factory_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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"), \
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 """
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
43 changes: 30 additions & 13 deletions scripts/tools/telink/telink_factory_data.schema
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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": {
Expand All @@ -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": {
Expand All @@ -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
},
Expand All @@ -144,4 +161,4 @@
"type": "object"
}
}
}
}
2 changes: 1 addition & 1 deletion src/platform/telink/CHIPDevicePlatformConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions src/platform/telink/FactoryDataParser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions src/platform/telink/FactoryDataParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
60 changes: 33 additions & 27 deletions src/platform/telink/FactoryDataProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -230,13 +242,7 @@ CHIP_ERROR FactoryDataProvider<FlashFactoryData>::SetSetupPasscode(uint32_t setu
template <class FlashFactoryData>
CHIP_ERROR FactoryDataProvider<FlashFactoryData>::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 <class FlashFactoryData>
Expand All @@ -250,13 +256,7 @@ CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetVendorId(uint16_t & vendorI
template <class FlashFactoryData>
CHIP_ERROR FactoryDataProvider<FlashFactoryData>::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 <class FlashFactoryData>
Expand All @@ -268,15 +268,27 @@ CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetProductId(uint16_t & produc
}

template <class FlashFactoryData>
CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetSerialNumber(char * buf, size_t bufSize)
CHIP_ERROR FactoryDataProvider<FlashFactoryData>::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 <class FlashFactoryData>
CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetProductURL(char * buf, size_t bufSize)
{
return GetFactoryDataString(mFactoryData.product_url, buf, bufSize);
}

return CHIP_NO_ERROR;
template <class FlashFactoryData>
CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetProductLabel(char * buf, size_t bufSize)
{
return GetFactoryDataString(mFactoryData.product_label, buf, bufSize);
}

template <class FlashFactoryData>
CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetSerialNumber(char * buf, size_t bufSize)
{
return GetFactoryDataString(mFactoryData.sn, buf, bufSize);
}

template <class FlashFactoryData>
Expand All @@ -300,13 +312,7 @@ CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetHardwareVersion(uint16_t &
template <class FlashFactoryData>
CHIP_ERROR FactoryDataProvider<FlashFactoryData>::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 <class FlashFactoryData>
Expand Down
3 changes: 3 additions & 0 deletions src/platform/telink/FactoryDataProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 98b7bc2

Please sign in to comment.