Skip to content

Commit 1a7352f

Browse files
mykrupprestyled-commits
authored andcommitted
[Silabs] Port platform specific Multi-Chip OTA work (project-chip#34440)
* Pull request project-chip#1836: Cherry multi ota Merge in WMN_TOOLS/matter from cherry-multi-ota to silabs_slc_1.3 Squashed commit of the following: commit 4320bb46571658bc44fb82345348265def394991 Author: Michael Rupp <michael.rupp@silabs.com> Date: Fri May 10 14:26:07 2024 -0400 remove some unwanted diffs in provision files commit be160931dc600de7e7ead378b70d6a43c3945e46 Author: Michael Rupp <michael.rupp@silabs.com> Date: Fri May 10 14:24:25 2024 -0400 revert changes to generator.project.mak commit 14b6605887166e6d5284a61feb2bf407d850bdcf Author: Michael Rupp <michael.rupp@silabs.com> Date: Fri May 10 13:06:12 2024 -0400 revert NVM key changes and script changes ... and 8 more commits * Restyled by whitespace * Restyled by clang-format * Restyled by gn * Restyled by autopep8 * remove unused libs caught by linter * update doctree with new readmes * rerun CI, cirque failing for unknown reasons * fix include guards in provision examples * Restyled by clang-format --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent aebaedb commit 1a7352f

27 files changed

+1145
-89
lines changed

docs/tools/index.md

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ Source files for these tools are located at `scripts/tools`.
4949
:maxdepth: 1
5050
5151
../scripts/tools/silabs/README
52+
../scripts/tools/silabs/ota/README
53+
../scripts/tools/silabs/factory_data_generator/README
5254
5355
```
5456

examples/platform/silabs/provision/ProvisionStorageDefault.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
#include <platform/silabs/MigrationManager.h>
2929
#include <platform/silabs/SilabsConfig.h>
3030
#include <silabs_creds.h>
31+
#ifdef OTA_ENCRYPTION_ENABLE
32+
#include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
33+
#endif // OTA_ENCRYPTION_ENABLE
3134
#ifdef SLI_SI91X_MCU_INTERFACE
3235
#include <sl_si91x_common_flash_intf.h>
3336
#else
@@ -659,7 +662,7 @@ CHIP_ERROR Storage::SetOtaTlvEncryptionKey(const ByteSpan & value)
659662
ReturnErrorOnFailure(key.Import(value.data(), value.size()));
660663
return SilabsConfig::WriteConfigValue(SilabsConfig::kOtaTlvEncryption_KeyId, key.GetId());
661664
}
662-
#endif
665+
#endif // OTA_ENCRYPTION_ENABLE
663666

664667
/**
665668
* @brief Reads the test event trigger key from NVM. If the key isn't present, returns default value if defined.

examples/platform/silabs/provision/ProvisionStorageFlash.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
#include <platform/CHIPDeviceConfig.h>
2626
#include <platform/silabs/SilabsConfig.h>
2727
#include <string.h>
28+
#ifdef OTA_ENCRYPTION_ENABLE
29+
#include <platform/silabs/multi-ota/OtaTlvEncryptionKey.h>
30+
#endif // OTA_ENCRYPTION_ENABLE
2831

2932
using namespace chip::Credentials;
3033

@@ -708,7 +711,7 @@ CHIP_ERROR Storage::SetOtaTlvEncryptionKey(const ByteSpan & value)
708711
{
709712
return CHIP_ERROR_NOT_IMPLEMENTED;
710713
}
711-
#endif
714+
#endif // OTA_ENCRYPTION_ENABLE
712715

713716
CHIP_ERROR Storage::GetTestEventTriggerKey(MutableByteSpan & keySpan)
714717
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Silabs Factory Data Generator
2+
3+
## Tool implementation
4+
5+
The tool comprises of two files: `default.py`, `custom.py`
6+
7+
### `default.py`
8+
9+
Defines the base `InputArgument` class and its derived classes that will be
10+
referenced as **default classes**.
11+
12+
`InputArgument` offers an abstract interface in the form of three methods:
13+
`key()`, `length()`, `encode()`, that will be used to generate the `(K, L, V)`
14+
tuple through the public `output()` method. Each custom class should implement
15+
the abstract interface, if its direct parent does not offer a relevant
16+
implementation.
17+
18+
### `custom.py`
19+
20+
Defines classes for each argument that should generate data in the output binary
21+
(will be referenced as **custom classes**). Please note that each new class
22+
should derive from a default class, not from `InputArgument` directly.
23+
24+
### How to add a new argument
25+
26+
Example of defining a new argument class in `custom.py`:
27+
28+
```
29+
class FooArgument(BarArgument):
30+
def __init__(self, arg):
31+
super().__init__(arg)
32+
33+
def key(self):
34+
return <unique key identifier>
35+
36+
def length(self):
37+
return <actual length of data>
38+
39+
def encode(self):
40+
return <data as encoded bytes>
41+
42+
def custom_function(self):
43+
pass
44+
```
45+
46+
where `BarArgument` is one of the **default classes**. Please note that a user
47+
can define additional methods if needed (e.g. `custom_function`; also see
48+
`generate_private_key` from `DacPKey` class).
49+
50+
Then use this class in `generate.py` to create a `FooArgument` object from an
51+
option:
52+
53+
```
54+
parser.add_argument("--foo", required=True, type=FooArgument,
55+
help="[int | hex] Foo argument.")
56+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright (c) 2022 Project CHIP Authors
4+
# All rights reserved.
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
19+
'''This file should contain custom classes derived any class from default.py.
20+
21+
Each class implemented here should describe an input parameter and should
22+
implement the InputArgument abstract interface, if its base class does not
23+
already offer an implementation or if there is a need of a custom behavior.
24+
25+
Example of defining a new argument class:
26+
27+
class FooArgument(IntArgument):
28+
def __init__(self, arg):
29+
super().__init__(arg)
30+
31+
def key(self):
32+
return <unique key identifier>
33+
34+
def length(self):
35+
return <actual length of data>
36+
37+
def encode(self):
38+
return <data as encoded bytes>
39+
40+
def custom_function(self):
41+
pass
42+
43+
Then use this class in generate.py to create a FooArgument object from an
44+
option:
45+
46+
parser.add_argument("--foo", required=True, type=FooArgument,
47+
help="[int | hex] Foo argument.")
48+
'''
49+
50+
from cryptography.hazmat.backends import default_backend
51+
from cryptography.hazmat.primitives.serialization import load_der_private_key
52+
from default import FileArgument
53+
54+
55+
class DacPKey(FileArgument):
56+
57+
def __init__(self, arg):
58+
super().__init__(arg)
59+
self.private_key = None
60+
61+
def key(self):
62+
return 1
63+
64+
def length(self):
65+
assert (self.private_key is not None)
66+
return len(self.private_key)
67+
68+
def encode(self):
69+
assert (self.private_key is not None)
70+
return self.private_key
71+
72+
def generate_private_key(self, password, use_sss_blob=True):
73+
if use_sss_blob:
74+
self.private_key = self.val
75+
else:
76+
keys = load_der_private_key(self.val, password, backend=default_backend())
77+
self.private_key = keys.private_numbers().private_value.to_bytes(
78+
32, byteorder='big'
79+
)
80+
81+
82+
class DacCert(FileArgument):
83+
84+
def __init__(self, arg):
85+
super().__init__(arg)
86+
87+
def key(self):
88+
return 2
89+
90+
91+
class PaiCert(FileArgument):
92+
93+
def __init__(self, arg):
94+
super().__init__(arg)
95+
96+
def key(self):
97+
return 3
98+
99+
100+
class CertDeclaration(FileArgument):
101+
102+
def __init__(self, arg):
103+
super().__init__(arg)
104+
105+
def key(self):
106+
return 4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright (c) 2022 Project CHIP Authors
4+
# All rights reserved.
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
'''This file should contain default argument classes.
19+
20+
Base class is InputArgument. It defines the abstract interface to be
21+
implemented and offers a way to compute a KLV value through output().
22+
Other classes that derive InputArgument directly will be referenced
23+
as default classes throughout the docstrings.
24+
25+
The default classes should not be used to instantiate arguments.
26+
If one wants to add another argument, a custom class should be derived
27+
from one of the default classes.
28+
'''
29+
30+
import base64
31+
import logging
32+
33+
34+
class InputArgument:
35+
'''Base class for any input argument that will be added to KLV.
36+
37+
The user will define its arguments as instances of InputArgument
38+
by setting the "type" attribute of ArgumentParser add_argument to
39+
an instance of a derived class. This means that all derived classes
40+
must accept an additional "arg" parameter in the constructor. In the
41+
end, the list of arguments will be parsed into objects derived from
42+
InputArgument (or default derived classes), which decouples the object
43+
creation from its processing.
44+
45+
Abstract methods:
46+
key: Should be overwritten by final classes to return a "magic number".
47+
length: Can be overwritten by default classes to specify a default value
48+
(e.g. int arguments with a default length value of 4); can also
49+
be overwritten by final classes to specify a custom value for a
50+
certain argument.
51+
encode: Should be overwritten to generate the correct bytes array from
52+
its internal value.
53+
54+
Main usage is to iterate over an iterable entity of InputArguments and call
55+
the output() method to generate the (K, L, V) tuple. Note that the output()
56+
method should not be implemented, since its a common functionality across
57+
all InputArgument classes.
58+
'''
59+
60+
def __init__(self):
61+
self.val = None
62+
63+
def key(self):
64+
logging.error("key() should be implemented in derived classes.")
65+
66+
def length(self):
67+
logging.error("length() should be implemented in derived classes.")
68+
69+
def encode(self):
70+
logging.error("encode() should be implemented in derived classes.")
71+
72+
def output(self):
73+
out = (self.key(), self.length(), self.encode())
74+
logging.info("'{}' length: {}".format(type(self).__name__, self.length()))
75+
return out
76+
77+
78+
class IntArgument(InputArgument):
79+
80+
def __init__(self, arg):
81+
super().__init__()
82+
self.val = int(arg, 0)
83+
84+
def length(self):
85+
return 4
86+
87+
def encode(self):
88+
return self.val.to_bytes(self.length(), "little")
89+
90+
91+
class Base64Argument(InputArgument):
92+
93+
def __init__(self, arg):
94+
super().__init__()
95+
self.val = base64.b64decode(arg)
96+
97+
def length(self):
98+
return len(self.encode())
99+
100+
def encode(self):
101+
return base64.b64encode(self.val)
102+
103+
104+
class StrArgument(InputArgument):
105+
106+
def __init__(self, arg):
107+
super().__init__()
108+
self.val = str(arg)
109+
110+
def length(self):
111+
return len(self.encode())
112+
113+
def encode(self):
114+
return str.encode(self.val)
115+
116+
def max_length(self):
117+
return 32
118+
119+
120+
class FileArgument(InputArgument):
121+
122+
def __init__(self, arg):
123+
super().__init__()
124+
with open(arg, "rb") as _file:
125+
self.val = _file.read()
126+
127+
def length(self):
128+
return len(self.val)
129+
130+
def encode(self):
131+
return self.val

scripts/tools/silabs/ota/README.md

+6-9
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ python3 ./scripts/tools/silabs/ota/ota_multi_image_tool.py create -v 0xDEAD -p 0
2525
```
2626

2727
followed by \*_custom options_- and a positional argument (should be last) that
28-
specifies the output file. Please see the `create_ota_images.sh` for some
29-
reference commands.
28+
specifies the output file.
3029

3130
The list of **custom options**:
3231

@@ -38,19 +37,17 @@ The list of **custom options**:
3837
--app-version-str --> Application version string. Same as above.
3938
--app-build-date --> Application build date. Same as above.
4039
41-
# SSBL options
42-
--bl-input-file --> Path to the SSBL binary.
43-
--bl-version --> SSBL version.
44-
--bl-version-str --> SSBL version string.
45-
--bl-build-date --> SSBL build date.
46-
4740
# Factory data options
4841
--factory-data --> If set, enables the generation of factory data.
4942
--cert_declaration --> Certification Declaration.
5043
--dac_cert --> DAC certificate.
5144
--dac_key --> DAC private key.
5245
--pai_cert --> PAI certificate.
5346
47+
# Encryption options
48+
--enc_enable --> Enable ota encryption
49+
--input_ota_key --> 16 Byte AES key
50+
5451
# Custom TLV options
5552
--json --> Path to a JSON file following ota_payload.schema
5653
```
@@ -67,5 +64,5 @@ processing.
6764
When defining a custom processor, a user is able to also specify the custom
6865
format of the TLV by creating a JSON file based on the `ota_payload.schema`. The
6966
tool offers support for describing multiple TLV in the same JSON file. Please
70-
see the `examples/ota_max_entries_example.json` for a multi-app + SSBL example.
67+
see the `examples/ota_custom_entries_example.json` for a multi-binary example.
7168
Option `--json` must be used to specify the path to the JSON file.
Binary file not shown.

0 commit comments

Comments
 (0)