Skip to content

Commit

Permalink
[NXP][k32w1] Remove the need for extra DAC private key conversion bin…
Browse files Browse the repository at this point in the history
…ary (project-chip#32699)

* [NXP][k32w1] Add SSS DAC private key conversion at init / Use plain-text DAC key

 * Do SSS DAC private key conversion at initialization if needed.
 * Do not use extra SSS conversion binary anymore.
 * Add option to use DAC private key in plain text.

Signed-off-by: Andrei Menzopol <andrei.menzopol@nxp.com>

* [NXP][k32w1] Update manufacturing flow to not use chip_convert_dac_private_key

 * Using chip_convert_dac_private_key option is not needed anymore.
 * Use chip_use_plain_dac_key=true for plain-text DAC private key.

Signed-off-by: Andrei Menzopol <andrei.menzopol@nxp.com>

* [NXP][k32w1] Remove example_convert_dac_private_key.jlink

 * Using chip_convert_dac_private_key option is not needed anymore,
 making the jlink script obsolete.

Signed-off-by: Andrei Menzopol <andrei.menzopol@nxp.com>

* Restyled by prettier-markdown

* Restyled by prettier-markdown

* Check SSS_ExportBlob return status

Signed-off-by: Andrei Menzopol <andrei.menzopol@nxp.com>

---------

Signed-off-by: Andrei Menzopol <andrei.menzopol@nxp.com>
Co-authored-by: Restyled.io <commits@restyled.io>
  • Loading branch information
andrei-menzopol and restyled-commits authored Apr 3, 2024
1 parent dfb8bb9 commit 15a7070
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 71 deletions.
28 changes: 10 additions & 18 deletions docs/guides/nxp_manufacturing_flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,26 +215,15 @@ converted to an encrypted blob. This blob will overwrite the DAC private key in
factory data and will be imported in the `SSS` at initialization, by the factory
data provider instance.

The conversion process shall happen at manufacturing time and should be run one
time only:

- Write factory data binary.
- Build the application with
`chip_with_factory_data=1 chip_convert_dac_private_key=1` set.
- Write the application to the board and let it run.

After the conversion process:
The application will check at initialization whether the DAC private key has
been converted or not and convert it if needed. However, the conversion process
should be done at manufacturing time for security reasons.

- Make sure the application is built with `chip_with_factory_data=1`, but
without `chip_convert_dac_private_key` arg, since conversion already
happened.
- Write the application to the board.

If you are using Jlink, you can see a conversion script example in:
There is no need for an extra binary.

```shell
./scripts/tools/nxp/factory_data_generator/k32w1/example_convert_dac_private_key.jlink
```
- Write factory data binary.
- Build the application with `chip_with_factory_data=1` set.
- Write the application to the board and use it as usual.

Factory data should now contain a corresponding encrypted blob instead of the
DAC private key.
Expand All @@ -251,6 +240,9 @@ python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLz
Please note that `--dac_key` now points to a binary file that contains the
encrypted blob.

The user can use the DAC private in plain text instead of using the `SSS` by
adding the following gn argument `chip_use_plain_dac_key=true`.

### 6.2 RW61X

Supported platforms:
Expand Down

This file was deleted.

10 changes: 6 additions & 4 deletions src/platform/nxp/k32w/k32w1/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ static_library("nxp_platform") {
"ram_storage.h",
]

if (chip_use_plain_dac_key) {
defines += [ "CHIP_USE_PLAIN_DAC_KEY=1" ]
} else {
defines += [ "CHIP_USE_PLAIN_DAC_KEY=0" ]
}

public = [
"${chip_root}/src/credentials/DeviceAttestationCredsProvider.h",
"${chip_root}/src/credentials/examples/DeviceAttestationCredsExample.h",
Expand Down Expand Up @@ -107,10 +113,6 @@ static_library("nxp_platform") {
"${chip_root}/src/credentials/CHIPCert.h",
"${chip_root}/src/credentials/CertificationDeclaration.h",
]

if (chip_convert_dac_private_key == 1) {
defines += [ "CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY=1" ]
}
}

public_deps += [ "${mbedtls_root}:mbedtls" ]
Expand Down
83 changes: 70 additions & 13 deletions src/platform/nxp/k32w/k32w1/FactoryDataProviderImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,30 @@
* limitations under the License.
*/

#include <platform/nxp/k32w/k32w1/FactoryDataProviderImpl.h>

#if CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY
#include "fsl_adapter_flash.h"
#endif
#include <platform/nxp/k32w/k32w1/FactoryDataProviderImpl.h>

namespace chip {
namespace DeviceLayer {

#if !CHIP_USE_PLAIN_DAC_KEY
// SSS adds 24 bytes of metadata when creating the blob
static constexpr size_t kSssBlobMetadataLength = 24;
static constexpr size_t kPrivateKeyBlobLength = Crypto::kP256_PrivateKey_Length + kSssBlobMetadataLength;
#endif

FactoryDataProviderImpl::~FactoryDataProviderImpl()
{
#if !CHIP_USE_PLAIN_DAC_KEY
SSS_KEY_OBJ_FREE(&mContext);
#endif
}

CHIP_ERROR FactoryDataProviderImpl::Init()
{
CHIP_ERROR error = CHIP_NO_ERROR;

#if CHIP_DEVICE_CONFIG_ENABLE_SSS_API_TEST
#if CHIP_DEVICE_CONFIG_ENABLE_SSS_API_TEST && !CHIP_USE_PLAIN_DAC_KEY
SSS_RunApiTest();
#endif

Expand All @@ -47,16 +48,56 @@ CHIP_ERROR FactoryDataProviderImpl::Init()
ChipLogError(DeviceLayer, "Factory data init failed with: %s", ErrorStr(error));
}

#if !CHIP_USE_PLAIN_DAC_KEY
ReturnErrorOnFailure(SSS_InitContext());
#if CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY
ReturnErrorOnFailure(SSS_ConvertDacKey());
ReturnErrorOnFailure(Validate());
#endif
ReturnErrorOnFailure(SSS_ImportPrivateKeyBlob());
#endif

return error;
}

#if CHIP_USE_PLAIN_DAC_KEY
CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer)
{
CHIP_ERROR error = CHIP_NO_ERROR;
Crypto::P256ECDSASignature signature;
Crypto::P256Keypair keypair;
Crypto::P256SerializedKeypair serializedKeypair;
uint8_t keyBuf[Crypto::kP256_PrivateKey_Length];
MutableByteSpan dacPrivateKeySpan(keyBuf);
uint16_t keySize = 0;

VerifyOrExit(!outSignBuffer.empty(), error = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(!messageToSign.empty(), error = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(outSignBuffer.size() >= signature.Capacity(), error = CHIP_ERROR_BUFFER_TOO_SMALL);

/* Get private key of DAC certificate from reserved section */
error = SearchForId(FactoryDataId::kDacPrivateKeyId, dacPrivateKeySpan.data(), dacPrivateKeySpan.size(), keySize);
SuccessOrExit(error);
dacPrivateKeySpan.reduce_size(keySize);
VerifyOrExit(keySize == Crypto::kP256_PrivateKey_Length, error = CHIP_ERROR_WRONG_KEY_TYPE);

/* Only the private key is used when signing */
error = serializedKeypair.SetLength(Crypto::kP256_PublicKey_Length + dacPrivateKeySpan.size());
SuccessOrExit(error);
memcpy(serializedKeypair.Bytes() + Crypto::kP256_PublicKey_Length, dacPrivateKeySpan.data(), dacPrivateKeySpan.size());

error = keypair.Deserialize(serializedKeypair);
SuccessOrExit(error);

error = keypair.ECDSA_sign_msg(messageToSign.data(), messageToSign.size(), signature);
SuccessOrExit(error);

error = CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer);

exit:
/* Sanitize temporary buffer */
memset(keyBuf, 0, Crypto::kP256_PrivateKey_Length);
return error;
}

#else
CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer)
{
Crypto::P256ECDSASignature signature;
Expand Down Expand Up @@ -118,18 +159,25 @@ CHIP_ERROR FactoryDataProviderImpl::SSS_Sign(uint8_t * digest, Crypto::P256ECDSA
return error;
}

#if CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY
CHIP_ERROR FactoryDataProviderImpl::SSS_ConvertDacKey()
{
size_t blobSize = kPrivateKeyBlobLength;
size_t newSize = sizeof(FactoryDataProvider::Header) + mHeader.size + kSssBlobMetadataLength;
uint8_t blob[kPrivateKeyBlobLength] = { 0 };
uint8_t * data = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(newSize));
uint32_t offset = 0;
bool convNeeded = true;

VerifyOrReturnError(data != nullptr, CHIP_ERROR_INTERNAL);

ReturnErrorOnFailure(SSS_ExportBlob(blob, &blobSize, offset));
ReturnErrorOnFailure(SSS_ExportBlob(blob, &blobSize, offset, convNeeded));
if (!convNeeded)
{
ChipLogError(DeviceLayer, "SSS: DAC private key already converted to blob");
chip::Platform::MemoryFree(data);
return CHIP_NO_ERROR;
}

ChipLogError(DeviceLayer, "SSS: extracted blob from DAC private key");

hal_flash_status_t status = HAL_FlashRead(kFactoryDataStart, newSize - kSssBlobMetadataLength, data);
Expand All @@ -149,22 +197,31 @@ CHIP_ERROR FactoryDataProviderImpl::SSS_ConvertDacKey()
chip::Platform::MemoryFree(data);
ChipLogError(DeviceLayer, "SSS: sanitized RAM cache");

ReturnErrorOnFailure(Validate());

return CHIP_NO_ERROR;
}

CHIP_ERROR FactoryDataProviderImpl::SSS_ExportBlob(uint8_t * data, size_t * dataLen, uint32_t & offset)
CHIP_ERROR FactoryDataProviderImpl::SSS_ExportBlob(uint8_t * data, size_t * dataLen, uint32_t & offset, bool & isNeeded)
{
CHIP_ERROR error = CHIP_NO_ERROR;
auto res = kStatus_SSS_Success;

uint8_t keyBuf[Crypto::kP256_PrivateKey_Length];
uint8_t keyBuf[kPrivateKeyBlobLength];
MutableByteSpan dacPrivateKeySpan(keyBuf);
uint16_t keySize = 0;
isNeeded = true;

error = SearchForId(FactoryDataId::kDacPrivateKeyId, dacPrivateKeySpan.data(), dacPrivateKeySpan.size(), keySize, &offset);
SuccessOrExit(error);
dacPrivateKeySpan.reduce_size(keySize);

if (keySize == kPrivateKeyBlobLength)
{
isNeeded = false;
return CHIP_NO_ERROR;
}

res = SSS_KEY_STORE_SET_KEY(&mContext, dacPrivateKeySpan.data(), Crypto::kP256_PrivateKey_Length, keySize * 8,
kSSS_KeyPart_Private);
VerifyOrExit(res == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL);
Expand Down Expand Up @@ -197,7 +254,6 @@ CHIP_ERROR FactoryDataProviderImpl::ReplaceWithBlob(uint8_t * data, uint8_t * bl

return CHIP_NO_ERROR;
}
#endif // CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY

#if CHIP_DEVICE_CONFIG_ENABLE_SSS_API_TEST

Expand Down Expand Up @@ -298,6 +354,7 @@ void FactoryDataProviderImpl::SSS_RunApiTest()
SSS_KEY_OBJ_FREE(&mContext);
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_SSS_API_TEST
#endif // CHIP_USE_PLAIN_DAC_KEY

} // namespace DeviceLayer
} // namespace chip
28 changes: 9 additions & 19 deletions src/platform/nxp/k32w/k32w1/FactoryDataProviderImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,8 @@
#include <crypto/CHIPCryptoPAL.h>
#include <platform/nxp/k32w/common/FactoryDataProvider.h>

#if !CHIP_USE_PLAIN_DAC_KEY
#include "sss_crypto.h"

/* This flag should be defined when the factory data contains
* the DAC private key in plain text. It usually occurs in
* manufacturing.
*
* The init phase will use S200 to export an encrypted blob,
* then overwrite the private key section from internal flash.
*
* Should be used one time only for securing the private key.
* The manufacturer will then flash the real image, which shall
* not define this flag.
*/
#ifndef CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY
#define CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY 0
#endif

/* This flag should be defined to run SSS_RunApiTest tests.
Expand All @@ -59,12 +46,13 @@ class FactoryDataProviderImpl : public FactoryDataProvider
CHIP_ERROR SignWithDacKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer) override;

private:
#if !CHIP_USE_PLAIN_DAC_KEY

CHIP_ERROR SSS_InitContext();
CHIP_ERROR SSS_ImportPrivateKeyBlob();
CHIP_ERROR SSS_Sign(uint8_t * digest, Crypto::P256ECDSASignature & signature);
#if CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY
/*!
* \brief Convert DAC private key to an SSS encrypted blob and update factory data
* \brief Convert DAC private key to an SSS encrypted blob and update factory data if not already done
*
* @note This API should be called in manufacturing process context to replace
* DAC private key with an SSS encrypted blob. The conversion will be a
Expand All @@ -74,15 +62,16 @@ class FactoryDataProviderImpl : public FactoryDataProvider
CHIP_ERROR SSS_ConvertDacKey();

/*!
* \brief Export an SSS encrypted blob from the DAC private key found in factory data
* \brief Check and export an SSS encrypted blob from the DAC private key found in factory data if needed
*
* @param data Pointer to an allocated buffer
* @param dataLen Pointer to a variable that will store the blob length
* @param offset Offset of private key from the start of factory data payload address (after header)
* @param isNeeded Will be set to true if conversion is needed
*
* @retval #CHIP_NO_ERROR if conversion to blob was successful.
*/
CHIP_ERROR SSS_ExportBlob(uint8_t * data, size_t * dataLen, uint32_t & offset);
CHIP_ERROR SSS_ExportBlob(uint8_t * data, size_t * dataLen, uint32_t & offset, bool & isNeeded);

/*!
* \brief Replace DAC private key with the specified SSS encrypted blob
Expand All @@ -97,12 +86,13 @@ class FactoryDataProviderImpl : public FactoryDataProvider
* @retval #CHIP_NO_ERROR if conversion to blob was successful.
*/
CHIP_ERROR ReplaceWithBlob(uint8_t * data, uint8_t * blob, size_t blobLen, uint32_t offset);
#endif

#if CHIP_DEVICE_CONFIG_ENABLE_SSS_API_TEST
void SSS_RunApiTest();
#endif

sss_sscp_object_t mContext;
#endif // CHIP_USE_PLAIN_DAC_KEY
};

} // namespace DeviceLayer
Expand Down
2 changes: 1 addition & 1 deletion src/platform/nxp/k32w/k32w1/args.gni
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import("//build_overrides/openthread.gni")
declare_args() {
chip_with_ot_cli = 0
chip_with_low_power = 0
chip_convert_dac_private_key = 0
sdk_release = 1
chip_use_plain_dac_key = false
}

nxp_platform = "k32w/k32w1"
Expand Down

0 comments on commit 15a7070

Please sign in to comment.