Skip to content

Commit 560a46b

Browse files
Linux: Implement PDC support in WiFiDriver / ConnectivityManagerImpl (project-chip#31983)
* Use DecodeChipCert instead of LoadCert in chip-cert print-cert LoadCert performs additional checks (only relevant to operational certs) that prevent PDC identities from being printed. * Simplify CHIPCert test vector code * Add ConvertECDSAKeypairRawToDER to CHIPCert * Linux: Make WiFiNetwork struct private, add helpers - Make WiFiNetwork struct private - Move static_asserts to where the fields are defined - Add Empty() and Match() helpers to WiFiNetwork - Validate index parameter in ReorderNetwork() - Use CHIP_ERROR_FORMAT * Linux: Implement PDC support in WiFiDriver / ConnectivityManagerImpl * Address review comments * Clear handled err before the next call
1 parent 7be9d88 commit 560a46b

15 files changed

+569
-294
lines changed

src/credentials/CHIPCert.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,48 @@ CHIP_ERROR ConvertECDSASignatureRawToDER(P256ECDSASignatureSpan rawSig, ASN1Writ
12031203
return err;
12041204
}
12051205

1206+
CHIP_ERROR ConvertECDSAKeypairRawToDER(const P256SerializedKeypair & rawKeypair, MutableByteSpan & outDerKeypair)
1207+
{
1208+
CHIP_ERROR err = CHIP_NO_ERROR;
1209+
1210+
// The raw key pair contains the public key followed by the private key
1211+
VerifyOrReturnError(rawKeypair.Length() == kP256_PublicKey_Length + kP256_PrivateKey_Length, CHIP_ERROR_INVALID_ARGUMENT);
1212+
FixedByteSpan<kP256_PublicKey_Length> publicKey(rawKeypair.ConstBytes());
1213+
FixedByteSpan<kP256_PrivateKey_Length> privateKey(rawKeypair.ConstBytes() + kP256_PublicKey_Length);
1214+
1215+
ASN1Writer writer;
1216+
writer.Init(outDerKeypair);
1217+
1218+
// ECPrivateKey ::= SEQUENCE
1219+
ASN1_START_SEQUENCE
1220+
{
1221+
// version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1)
1222+
ASN1_ENCODE_INTEGER(1);
1223+
1224+
// privateKey OCTET STRING
1225+
ASN1_ENCODE_OCTET_STRING(privateKey.data(), privateKey.size());
1226+
1227+
// parameters [0] ECParameters {{ NamedCurve }} OPTIONAL
1228+
ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0);
1229+
{
1230+
ASN1_ENCODE_OBJECT_ID(kOID_EllipticCurve_prime256v1);
1231+
}
1232+
ASN1_END_CONSTRUCTED;
1233+
1234+
// publicKey [1] BIT STRING OPTIONAL
1235+
ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 1);
1236+
{
1237+
ReturnErrorOnFailure(writer.PutBitString(0, publicKey.data(), publicKey.size()));
1238+
}
1239+
ASN1_END_CONSTRUCTED;
1240+
}
1241+
ASN1_END_SEQUENCE;
1242+
1243+
outDerKeypair.reduce_size(writer.GetLengthWritten());
1244+
exit:
1245+
return err;
1246+
}
1247+
12061248
CHIP_ERROR ExtractNodeIdFabricIdFromOpCert(const ChipCertificateData & opcert, NodeId * outNodeId, FabricId * outFabricId)
12071249
{
12081250
// Since we assume the cert is pre-validated, we are going to assume that

src/credentials/CHIPCert.h

+14
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ static constexpr uint32_t kMaxDERCertLength = 600;
5757
// As per spec section 11.24 (Wi-Fi Authentication with Per-Device Credentials)
5858
inline constexpr uint32_t kMaxCHIPCompactNetworkIdentityLength = 137;
5959

60+
// Length of a ASN.1 DER encoded ECPrivateKey structure (RFC 5915) for a P256 key pair.
61+
inline constexpr uint32_t kP256ECPrivateKeyDERLength = 121;
62+
6063
/** Data Element Tags for the CHIP Certificate
6164
*/
6265
enum
@@ -730,6 +733,17 @@ CHIP_ERROR ConvertECDSASignatureRawToDER(P256ECDSASignatureSpan rawSig, ASN1::AS
730733
*/
731734
CHIP_ERROR ConvertECDSASignatureDERToRaw(ASN1::ASN1Reader & reader, chip::TLV::TLVWriter & writer, uint64_t tag);
732735

736+
/**
737+
* @brief Convert a raw ECDSA P256 key pair to an ASN.1 DER encoded ECPrivateKey structure (RFC 5915).
738+
*
739+
* @param rawKeypair The raw P256 key pair.
740+
* @param outDerKeypair Output buffer to receive the ASN.1 DER encoded key pair.
741+
* Must have a capacity of at least `kP256ECPrivateKeyDERLength` bytes.
742+
*
743+
* @retval #CHIP_NO_ERROR If the key pair was successfully converted, or a CHIP_ERROR otherwise.
744+
*/
745+
CHIP_ERROR ConvertECDSAKeypairRawToDER(const Crypto::P256SerializedKeypair & rawKeypair, MutableByteSpan & outDerKeypair);
746+
733747
/**
734748
* Extract the Fabric ID from an operational certificate that has already been
735749
* parsed.

src/credentials/tests/CHIPCert_test_vectors.cpp

+86-200
Large diffs are not rendered by default.

src/credentials/tests/CHIPCert_test_vectors.h

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include <credentials/CHIPCert.h>
3030
#include <credentials/CHIPCertificateSet.h>
31+
#include <crypto/CHIPCryptoPAL.h>
3132
#include <lib/support/CodeUtils.h>
3233

3334
namespace chip {
@@ -72,6 +73,8 @@ enum class TestCertLoadFlags : uint8_t
7273
extern CHIP_ERROR GetTestCert(TestCert certType, BitFlags<TestCertLoadFlags> certLoadFlags, ByteSpan & cert);
7374
extern const char * GetTestCertName(TestCert certType);
7475
extern CHIP_ERROR GetTestCertPubkey(TestCert certType, ByteSpan & pubkey);
76+
extern CHIP_ERROR GetTestCertPrivkey(TestCert certType, ByteSpan & privkey);
77+
extern CHIP_ERROR GetTestCertKeypair(TestCert certType, Crypto::P256SerializedKeypair & keypair);
7578
extern CHIP_ERROR GetTestCertSKID(TestCert certType, ByteSpan & skid);
7679
extern CHIP_ERROR GetTestCertAKID(TestCert certType, ByteSpan & akid);
7780

@@ -213,6 +216,7 @@ extern const ByteSpan sTestCert_PDCID01_PrivateKey;
213216
extern const ByteSpan sTestCert_PDCID01_SubjectKeyId; // empty
214217
extern const ByteSpan sTestCert_PDCID01_AuthorityKeyId; // empty
215218
extern const ByteSpan sTestCert_PDCID01_KeyId;
219+
extern const ByteSpan sTestCert_PDCID01_KeypairDER;
216220

217221
} // namespace TestCerts
218222
} // namespace chip

src/credentials/tests/TestChipCert.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <lib/core/TLV.h>
3434
#include <lib/support/CHIPMem.h>
3535
#include <lib/support/CodeUtils.h>
36+
#include <lib/support/UnitTestExtendedAssertions.h>
3637
#include <lib/support/UnitTestRegistration.h>
3738

3839
#include <nlunit-test.h>
@@ -2191,6 +2192,20 @@ static void TestChipCert_PDCIdentityGeneration(nlTestSuite * inSuite, void * inC
21912192
NL_TEST_ASSERT(inSuite, ValidateChipNetworkIdentity(tlvCert) == CHIP_NO_ERROR);
21922193
}
21932194

2195+
static void TestChipCert_KeypairConversion(nlTestSuite * inSuite, void * inContext)
2196+
{
2197+
P256SerializedKeypair keypair;
2198+
NL_TEST_ASSERT_SUCCESS(inSuite, GetTestCertKeypair(kPDCID01, keypair));
2199+
2200+
uint8_t buffer[kP256ECPrivateKeyDERLength];
2201+
MutableByteSpan keypairDer(buffer);
2202+
NL_TEST_ASSERT_SUCCESS(inSuite, ConvertECDSAKeypairRawToDER(keypair, keypairDer));
2203+
2204+
// Technically the curve name and public key are optional in the DER format,
2205+
// but both our code and standard tools include them, so we can just compare.
2206+
NL_TEST_ASSERT(inSuite, keypairDer.data_equal(sTestCert_PDCID01_KeypairDER));
2207+
}
2208+
21942209
/**
21952210
* Set up the test suite.
21962211
*/
@@ -2251,6 +2266,7 @@ static const nlTest sTests[] = {
22512266
NL_TEST_DEF("Test extracting PublicKey and SKID from chip certificate", TestChipCert_ExtractPublicKeyAndSKID),
22522267
NL_TEST_DEF("Test PDC Identity Validation", TestChipCert_PDCIdentityValidation),
22532268
NL_TEST_DEF("Test PDC Identity Generation", TestChipCert_PDCIdentityGeneration),
2269+
NL_TEST_DEF("Test keypair conversion", TestChipCert_KeypairConversion),
22542270
NL_TEST_SENTINEL()
22552271
};
22562272
// clang-format on

src/crypto/CHIPCryptoPAL.h

+3
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,9 @@ struct alignas(size_t) P256KeypairContext
484484
uint8_t mBytes[kMAX_P256Keypair_Context_Size];
485485
};
486486

487+
/**
488+
* A serialized P256 key pair is the concatenation of the public and private keys, in that order.
489+
*/
487490
using P256SerializedKeypair = SensitiveDataBuffer<kP256_PublicKey_Length + kP256_PrivateKey_Length>;
488491

489492
class P256KeypairBase : public ECPKeypair<P256PublicKey, P256ECDHDerivedSecret, P256ECDSASignature>

src/include/platform/NetworkCommissioning.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,8 @@ class WiFiDriver : public Internal::WirelessDriver
351351
/**
352352
* @brief Signs the specified message with the private key of a Network Client Identity.
353353
*/
354-
virtual CHIP_ERROR SignWithClientIdentity(uint8_t networkIndex, ByteSpan & message, Crypto::P256ECDSASignature & outSignature)
354+
virtual CHIP_ERROR SignWithClientIdentity(uint8_t networkIndex, const ByteSpan & message,
355+
Crypto::P256ECDSASignature & outSignature)
355356
{
356357
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
357358
}

src/platform/Linux/BUILD.gn

+4-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ static_library("Linux") {
7373
"SystemTimeSupport.cpp",
7474
]
7575

76-
deps = [ "${chip_root}/src/setup_payload" ]
76+
deps = [
77+
"${chip_root}/src/credentials:credentials_header",
78+
"${chip_root}/src/setup_payload",
79+
]
7780

7881
if (!chip_use_external_logging) {
7982
sources += [ "Logging.cpp" ]

0 commit comments

Comments
 (0)