Skip to content

Commit e873dd5

Browse files
ArekBalysNordicrestyled-commits
authored andcommittedMar 19, 2024
[nrfconnect] Refactor of the factory data support (project-chip#32354)
* [nrfconnect] Refactor of the factory data support Refactored Factory Data Support: - Added some useful tips to the Factory Data Guide. - The SPAKE2+ verifier is now generated by default with each build. - The Test Certification Declaration can now be generated separately and no longer requires the generation of the DAC and PAI certificates. - The Rotating Device ID Unique ID can be used and generated only if the CONFIG_CHIP_ROTATING_DEVICE_ID is set to 'y'. * Restyled by prettier-markdown --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 4ec0a47 commit e873dd5

File tree

4 files changed

+168
-76
lines changed

4 files changed

+168
-76
lines changed
 

‎config/nrfconnect/chip-module/Kconfig

+6
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ choice CHIP_FACTORY_DATA_CERT_SOURCE
206206

207207
endchoice
208208

209+
config CHIP_FACTORY_DATA_GENERATE_CD
210+
bool "Generates Certification Declaration to the output build directory"
211+
help
212+
Generates the new Certification Declaration and stores it to the output build directory.
213+
209214
if CHIP_FACTORY_DATA_CERT_SOURCE_USER
210215

211216
config CHIP_FACTORY_DATA_USER_CERTS_DAC_CERT
@@ -230,6 +235,7 @@ endif # CHIP_FACTORY_DATA_CERT_SOURCE_USER
230235
# Configs for SPAKE2+ generation
231236
config CHIP_FACTORY_DATA_GENERATE_SPAKE2_VERIFIER
232237
bool "Generate SPAKE2+ verifier"
238+
default y
233239
help
234240
Enables the generation of the SPAKE2+ verifier for the configured SPAKE2+
235241
passcode, iteration count and salt.

‎config/nrfconnect/chip-module/generate_factory_data.cmake

+26-17
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,25 @@ string(APPEND script_args "--hw_ver ${CONFIG_CHIP_DEVICE_HARDWARE_VERSION}\n")
4848
string(APPEND script_args "--hw_ver_str \"${CONFIG_CHIP_DEVICE_HARDWARE_VERSION_STRING}\"\n")
4949

5050
# check if Rotating Device Id Unique Id should be generated
51-
if(NOT CONFIG_CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID)
52-
if(NOT DEFINED CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID)
53-
message(FATAL_ERROR "CHIP_DEVICE_ROTATING_DEVICE_UID was not provided. To generate it use CONFIG_CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID=y")
51+
if(CONFIG_CHIP_ROTATING_DEVICE_ID)
52+
if(NOT CONFIG_CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID)
53+
if(NOT DEFINED CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID)
54+
message(FATAL_ERROR "CHIP_DEVICE_ROTATING_DEVICE_UID was not provided. To generate it use CONFIG_CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID=y")
55+
else()
56+
string(APPEND script_args "--rd_uid \"${CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID}\"\n")
57+
endif()
5458
else()
55-
string(APPEND script_args "--rd_uid \"${CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID}\"\n")
59+
string(APPEND script_args "--generate_rd_uid\n")
5660
endif()
57-
else()
58-
string(APPEND script_args "--generate_rd_uid\n")
61+
endif()
62+
63+
if(CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_GENERATED OR CONFIG_CHIP_FACTORY_DATA_GENERATE_CD)
64+
find_program(chip_cert_exe NAMES chip-cert REQUIRED)
65+
string(APPEND script_args "--chip_cert_path ${chip_cert_exe}\n")
66+
endif()
67+
68+
if(CONFIG_CHIP_FACTORY_DATA_GENERATE_CD)
69+
string(APPEND script_args "--gen_cd\n")
5970
endif()
6071

6172
# for development purpose user can use default certs instead of generating or providing them
@@ -77,10 +88,8 @@ elseif(CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_USER)
7788
string(APPEND script_args "--dac_cert \"${CONFIG_CHIP_FACTORY_DATA_USER_CERTS_DAC_CERT}\"\n")
7889
string(APPEND script_args "--dac_key \"${CONFIG_CHIP_FACTORY_DATA_USER_CERTS_DAC_KEY}\"\n")
7990
string(APPEND script_args "--pai_cert \"${CONFIG_CHIP_FACTORY_DATA_USER_CERTS_PAI_CERT}\"\n")
80-
else()
81-
find_program(chip_cert_exe NAMES chip-cert REQUIRED)
82-
string(APPEND script_args "--gen_cd\n")
83-
string(APPEND script_args "--chip_cert_path ${chip_cert_exe}\n")
91+
elseif(CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_GENERATED)
92+
string(APPEND script_args "--gen_certs\n")
8493
endif()
8594

8695
# add Password-Authenticated Key Exchange parameters
@@ -90,8 +99,14 @@ string(APPEND script_args "--discriminator ${CONFIG_CHIP_DEVICE_DISCRIMINATOR}\n
9099
string(APPEND script_args "--passcode ${CONFIG_CHIP_DEVICE_SPAKE2_PASSCODE}\n")
91100
string(APPEND script_args "--include_passcode\n")
92101
string(APPEND script_args "--overwrite\n")
93-
string(APPEND script_args "--product_finish ${CONFIG_CHIP_DEVICE_PRODUCT_FINISH}\n")
102+
# check if spake2 verifier should be generated using script
103+
if(NOT CONFIG_CHIP_FACTORY_DATA_GENERATE_SPAKE2_VERIFIER)
104+
# Spake2 verifier should be provided using kConfig
105+
string(APPEND script_args "--spake2_verifier \"${CONFIG_CHIP_DEVICE_SPAKE2_TEST_VERIFIER}\"\n")
106+
endif()
94107

108+
# Product appearance
109+
string(APPEND script_args "--product_finish ${CONFIG_CHIP_DEVICE_PRODUCT_FINISH}\n")
95110
if(CONFIG_CHIP_DEVICE_PRODUCT_COLOR)
96111
string(APPEND script_args "--product_color ${CONFIG_CHIP_DEVICE_PRODUCT_COLOR}\n")
97112
endif()
@@ -100,12 +115,6 @@ if(CONFIG_CHIP_FACTORY_DATA_GENERATE_ONBOARDING_CODES)
100115
string(APPEND script_args "--generate_onboarding\n")
101116
endif()
102117

103-
# check if spake2 verifier should be generated using script
104-
if(NOT CONFIG_CHIP_FACTORY_DATA_GENERATE_SPAKE2_VERIFIER)
105-
# Spake2 verifier should be provided using kConfig
106-
string(APPEND script_args "--spake2_verifier \"${CONFIG_CHIP_DEVICE_SPAKE2_TEST_VERIFIER}\"\n")
107-
endif()
108-
109118
if(CONFIG_CHIP_DEVICE_ENABLE_KEY)
110119
# Add optional EnableKey that triggers user-specific action.
111120
string(APPEND script_args "--enable_key \"${CONFIG_CHIP_DEVICE_ENABLE_KEY}\"\n")

‎docs/guides/nrfconnect_factory_data_configuration.md

+63-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ data secure by applying hardware write protection.
5151
- [Building an example with factory data](#building-an-example-with-factory-data)
5252
- [Providing factory data parameters as a build argument list](#providing-factory-data-parameters-as-a-build-argument-list)
5353
- [Setting factory data parameters using interactive Kconfig interfaces](#setting-factory-data-parameters-using-interactive-kconfig-interfaces)
54+
- [Default Kconfig values and developing aspects](#default-kconfig-values-and-developing-aspects)
5455
- [Programming factory data](#programming-factory-data)
5556
- [Using own factory data implementation](#using-own-factory-data-implementation)
5657

@@ -272,6 +273,7 @@ To use this script, complete the following steps:
272273
273274
```
274275
--chip_cert_path <path to chip-cert executable>
276+
--gen_certs
275277
```
276278
277279
> **Note:** To generate new certificates, you need the `chip-cert`
@@ -293,7 +295,7 @@ To use this script, complete the following steps:
293295
--rd_uid <rotating device ID unique ID>
294296
```
295297
296-
- Generate a new ID and provide it ():
298+
- (optional) Generate a new ID and provide it:
297299
298300
```
299301
--generate_rd_uid
@@ -328,6 +330,17 @@ To use this script, complete the following steps:
328330
--product_color <color>
329331
```
330332
333+
j. (optional) Generate Certification Declaration for testing purposes
334+
335+
```
336+
--chip_cert_path <path to chip-cert executable>
337+
--gen_cd
338+
```
339+
340+
> **Note:** To generate new Certification Declaration, you need the
341+
> `chip-cert` executable. See the note at the end of this section to learn
342+
> how to get it.
343+
331344
4. Run the script using the prepared list of arguments:
332345
333346
```
@@ -794,6 +807,55 @@ snippet:
794807
> interfaces, read the
795808
> [Kconfig documentation](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/build/kconfig/menuconfig.html).
796809
810+
### Default Kconfig values and developing aspects
811+
812+
Each factory data parameter has its default value reflected in the Kconfig. The
813+
list below shows some Kconfig settings that are configured in the nRF Connect
814+
build system and have an impact on the application. You can modify them to
815+
achieve the desired behavior of your application.
816+
817+
- The device uses the test certificates located in the
818+
`credentials/development/attestation/` directory, which are generated using
819+
all default values. If you want to change the default `vendor_id`,
820+
`product_id`, `vendor_name`, or `device_name` and generate new test
821+
certificates, add the `CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_GENERATED=y`
822+
Kconfig option. Remember to build the `chip-cert` application and add it to
823+
the system PATH.
824+
825+
For developing a production-ready product, you need to write the
826+
certificates obtained during the certification process. To do this, add the
827+
`CONFIG_CHIP_FACTORY_DATA_CERT_SOURCE_USER=y` Kconfig option and set the
828+
appropriate paths for the following Kconfig options:
829+
830+
- `CONFIG_CHIP_FACTORY_DATA_USER_CERTS_DAC_CERT`
831+
- `CONFIG_CHIP_FACTORY_DATA_USER_CERTS_DAC_KEY`
832+
- `CONFIG_CHIP_FACTORY_DATA_USER_CERTS_PAI_CERT`
833+
834+
- By default, the SPAKE2+ verifier is generated during each example's build.
835+
This means that this value will change automatically if you change any of
836+
the following parameters:
837+
838+
- `CONFIG_CHIP_DEVICE_SPAKE2_PASSCODE`
839+
- `CONFIG_CHIP_DEVICE_SPAKE2_SALT`
840+
- `CONFIG_CHIP_DEVICE_SPAKE2_IT`
841+
842+
You can disable the generation of the SPAKE2+ verifier by setting the
843+
`CONFIG_CHIP_FACTORY_DATA_GENERATE_SPAKE2_VERIFIER=n` Kconfig option. Then,
844+
you will need to provide the externally-generated SPAKE2+ verifier using the
845+
`CONFIG_CHIP_DEVICE_SPAKE2_TEST_VERIFIER` Kconfig value.
846+
847+
- Generating the rotating device ID unique ID is disabled by default, but you
848+
can enable it by setting the `CONFIG_CHIP_ROTATING_DEVICE_ID=y` and
849+
`CONFIG_CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID=y` Kconfig values.
850+
Moreover, if you set the `CONFIG_CHIP_ROTATING_DEVICE_ID` Kconfig option to
851+
`y` and disable the `CONFIG_CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID`
852+
Kconfig option, you will need to provide it manually using the
853+
`CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID` Kconfig value.
854+
855+
- You can generate the test Certification Declaration by using the
856+
`CONFIG_CHIP_FACTORY_DATA_GENERATE_CD=y` Kconfig option. Remember to build
857+
the `chip-cert` application and add it to the system PATH.
858+
797859
<hr>
798860
799861
## Programming factory data

‎scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py

+73-58
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ def gen_test_certs(chip_cert_exe: str,
102102
generate_cd: bool = False,
103103
cd_type: int = 1,
104104
paa_cert_path: str = None,
105-
paa_key_path: str = None):
105+
paa_key_path: str = None,
106+
generate_all_certs: bool = False):
106107
"""
107108
Generate Matter certificates according to given Vendor ID and Product ID using the chip-cert executable.
108109
To use own Product Attestation Authority certificate provide paa_cert_path and paa_key_path arguments.
@@ -120,6 +121,7 @@ def gen_test_certs(chip_cert_exe: str,
120121
/credentials/test/attestation directory.
121122
paa_key_path (str, optional): provide PAA key path. Defaults to None - a path will be set to
122123
/credentials/test/attestation directory.
124+
generate_all_certs: Generate the new DAC and PAI certificates
123125
124126
Returns:
125127
dictionary: ["PAI_CERT": (str)<path to PAI cert .der file>,
@@ -136,9 +138,10 @@ def gen_test_certs(chip_cert_exe: str,
136138

137139
attestation_certs = namedtuple("attestation_certs", ["dac_cert", "dac_key", "pai_cert"])
138140

139-
log.info("Generating new certificates using chip-cert...")
140-
141141
if generate_cd:
142+
143+
log.info("Generating new Certification Declaration using chip-cert...")
144+
142145
# generate Certification Declaration
143146
cmd = [chip_cert_exe, "gen-cd",
144147
"--key", CD_KEY_PATH,
@@ -162,47 +165,52 @@ def gen_test_certs(chip_cert_exe: str,
162165
"DAC_KEY": output + "/DAC_key"
163166
}
164167

165-
# generate PAI
166-
cmd = [chip_cert_exe, "gen-att-cert",
167-
"-t", "i",
168-
"-c", device_name,
169-
"-V", hex(vendor_id),
170-
"-C", PAA_PATH,
171-
"-K", PAA_KEY_PATH,
172-
"-o", new_certificates["PAI_CERT"] + ".pem",
173-
"-O", new_certificates["PAI_KEY"] + ".pem",
174-
"-l", str(10000),
175-
]
176-
subprocess.run(cmd)
177-
178-
# generate DAC
179-
cmd = [chip_cert_exe, "gen-att-cert",
180-
"-t", "d",
181-
"-c", device_name,
182-
"-V", hex(vendor_id),
183-
"-P", hex(product_id),
184-
"-C", new_certificates["PAI_CERT"] + ".pem",
185-
"-K", new_certificates["PAI_KEY"] + ".pem",
186-
"-o", new_certificates["DAC_CERT"] + ".pem",
187-
"-O", new_certificates["DAC_KEY"] + ".pem",
188-
"-l", str(10000),
189-
]
190-
subprocess.run(cmd)
191-
192-
# convert to .der files
193-
for cert_k, cert_v in new_certificates.items():
194-
action_type = "convert-cert" if cert_k.find("CERT") != -1 else "convert-key"
195-
log.info(cert_v + ".der")
196-
cmd = [chip_cert_exe, action_type,
197-
cert_v + ".pem",
198-
cert_v + ".der",
199-
"--x509-der",
168+
if generate_all_certs:
169+
log.info("Generating new PAI and DAC certificates using chip-cert...")
170+
171+
# generate PAI
172+
cmd = [chip_cert_exe, "gen-att-cert",
173+
"-t", "i",
174+
"-c", device_name,
175+
"-V", hex(vendor_id),
176+
"-C", PAA_PATH,
177+
"-K", PAA_KEY_PATH,
178+
"-o", new_certificates["PAI_CERT"] + ".pem",
179+
"-O", new_certificates["PAI_KEY"] + ".pem",
180+
"-l", str(10000),
181+
]
182+
subprocess.run(cmd)
183+
184+
# generate DAC
185+
cmd = [chip_cert_exe, "gen-att-cert",
186+
"-t", "d",
187+
"-c", device_name,
188+
"-V", hex(vendor_id),
189+
"-P", hex(product_id),
190+
"-C", new_certificates["PAI_CERT"] + ".pem",
191+
"-K", new_certificates["PAI_KEY"] + ".pem",
192+
"-o", new_certificates["DAC_CERT"] + ".pem",
193+
"-O", new_certificates["DAC_KEY"] + ".pem",
194+
"-l", str(10000),
200195
]
201196
subprocess.run(cmd)
202197

203-
return attestation_certs(new_certificates["DAC_CERT"] + ".der",
204-
new_certificates["DAC_KEY"] + ".der",
205-
new_certificates["PAI_CERT"] + ".der")
198+
# convert to .der files
199+
for cert_k, cert_v in new_certificates.items():
200+
action_type = "convert-cert" if cert_k.find("CERT") != -1 else "convert-key"
201+
log.info(cert_v + ".der")
202+
cmd = [chip_cert_exe, action_type,
203+
cert_v + ".pem",
204+
cert_v + ".der",
205+
"--x509-der",
206+
]
207+
subprocess.run(cmd)
208+
209+
return attestation_certs(new_certificates["DAC_CERT"] + ".der",
210+
new_certificates["DAC_KEY"] + ".der",
211+
new_certificates["PAI_CERT"] + ".der")
212+
213+
return attestation_certs(None, None, None)
206214

207215

208216
class FactoryDataGenerator:
@@ -234,8 +242,8 @@ def _validate_args(self):
234242
raise AssertionError("Provided wrong user data, this is not a JSON format! {}".format(e))
235243
assert self._args.spake2_verifier or self._args.passcode, \
236244
"Cannot find Spake2+ verifier, to generate a new one please provide passcode (--passcode)"
237-
assert (self._args.chip_cert_path or (self._args.dac_cert and self._args.pai_cert and self._args.dac_key)), \
238-
"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)"
245+
assert ((self._args.gen_certs and self._args.chip_cert_path) or (self._args.dac_cert and self._args.pai_cert and self._args.dac_key)), \
246+
"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) and add --gen_certs argument"
239247
assert self._args.output.endswith(".json"), \
240248
"Output path doesn't contain .json file path. ({})".format(self._args.output)
241249
assert not (self._args.passcode in INVALID_PASSCODES), \
@@ -273,23 +281,27 @@ def generate_json(self):
273281
# convert salt to bytestring to be coherent with Spake2+ verifier type
274282
spake_2_salt = self._args.spake2_salt
275283

276-
if self._args.chip_cert_path:
277-
certs = gen_test_certs(self._args.chip_cert_path,
278-
self._args.output[:self._args.output.rfind("/")],
279-
self._args.vendor_id,
280-
self._args.product_id,
281-
self._args.vendor_name + "_" + self._args.product_name,
282-
self._args.gen_cd,
283-
self._args.cd_type,
284-
self._args.paa_cert,
285-
self._args.paa_key)
286-
dac_cert = certs.dac_cert
287-
pai_cert = certs.pai_cert
288-
dac_key = certs.dac_key
289-
else:
284+
certs = gen_test_certs(self._args.chip_cert_path,
285+
self._args.output[:self._args.output.rfind("/")],
286+
self._args.vendor_id,
287+
self._args.product_id,
288+
self._args.vendor_name + "_" + self._args.product_name,
289+
self._args.gen_cd,
290+
self._args.cd_type,
291+
self._args.paa_cert,
292+
self._args.paa_key,
293+
self._args.gen_certs)
294+
295+
dac_cert = certs.dac_cert
296+
pai_cert = certs.pai_cert
297+
dac_key = certs.dac_key
298+
299+
if not dac_cert:
290300
dac_cert = self._args.dac_cert
291-
dac_key = self._args.dac_key
301+
if not pai_cert:
292302
pai_cert = self._args.pai_cert
303+
if not dac_key:
304+
dac_key = self._args.dac_key
293305

294306
# try to read DAC public and private keys
295307
dac_priv_key = get_raw_private_key_der(dac_key, self._args.dac_key_password)
@@ -364,6 +376,7 @@ def _add_entry(self, name: str, value: any):
364376

365377
def _generate_spake2_verifier(self):
366378
""" If verifier has not been provided in arguments list it should be generated via external script """
379+
log.info("Generating SPAKE2+ Verifier...")
367380
return generate_verifier(self._args.passcode, self._args.spake2_salt, self._args.spake2_it)
368381

369382
def _generate_rotating_device_uid(self):
@@ -479,6 +492,8 @@ def base64_str(s): return base64.b64decode(s)
479492
"This option requires a path to chip-cert executable."
480493
"By default you can find chip-cert in connectedhomeip/src/tools/chip-cert directory "
481494
"and build it there."))
495+
optional_arguments.add_argument("--gen_certs", action="store_true",
496+
help="Generate a new DAC nad PAI certificates")
482497
optional_arguments.add_argument("--dac_cert", type=str,
483498
help="[.der] Provide the path to .der file containing DAC certificate.")
484499
optional_arguments.add_argument("--dac_key", type=str,

0 commit comments

Comments
 (0)
Please sign in to comment.