Skip to content

Commit

Permalink
Linux: Implement PDC support in WiFiDriver / ConnectivityManagerImpl (#…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
ksperling-apple authored Feb 8, 2024
1 parent 7be9d88 commit 560a46b
Show file tree
Hide file tree
Showing 15 changed files with 569 additions and 294 deletions.
42 changes: 42 additions & 0 deletions src/credentials/CHIPCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,48 @@ CHIP_ERROR ConvertECDSASignatureRawToDER(P256ECDSASignatureSpan rawSig, ASN1Writ
return err;
}

CHIP_ERROR ConvertECDSAKeypairRawToDER(const P256SerializedKeypair & rawKeypair, MutableByteSpan & outDerKeypair)
{
CHIP_ERROR err = CHIP_NO_ERROR;

// The raw key pair contains the public key followed by the private key
VerifyOrReturnError(rawKeypair.Length() == kP256_PublicKey_Length + kP256_PrivateKey_Length, CHIP_ERROR_INVALID_ARGUMENT);
FixedByteSpan<kP256_PublicKey_Length> publicKey(rawKeypair.ConstBytes());
FixedByteSpan<kP256_PrivateKey_Length> privateKey(rawKeypair.ConstBytes() + kP256_PublicKey_Length);

ASN1Writer writer;
writer.Init(outDerKeypair);

// ECPrivateKey ::= SEQUENCE
ASN1_START_SEQUENCE
{
// version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1)
ASN1_ENCODE_INTEGER(1);

// privateKey OCTET STRING
ASN1_ENCODE_OCTET_STRING(privateKey.data(), privateKey.size());

// parameters [0] ECParameters {{ NamedCurve }} OPTIONAL
ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0);
{
ASN1_ENCODE_OBJECT_ID(kOID_EllipticCurve_prime256v1);
}
ASN1_END_CONSTRUCTED;

// publicKey [1] BIT STRING OPTIONAL
ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 1);
{
ReturnErrorOnFailure(writer.PutBitString(0, publicKey.data(), publicKey.size()));
}
ASN1_END_CONSTRUCTED;
}
ASN1_END_SEQUENCE;

outDerKeypair.reduce_size(writer.GetLengthWritten());
exit:
return err;
}

CHIP_ERROR ExtractNodeIdFabricIdFromOpCert(const ChipCertificateData & opcert, NodeId * outNodeId, FabricId * outFabricId)
{
// Since we assume the cert is pre-validated, we are going to assume that
Expand Down
14 changes: 14 additions & 0 deletions src/credentials/CHIPCert.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ static constexpr uint32_t kMaxDERCertLength = 600;
// As per spec section 11.24 (Wi-Fi Authentication with Per-Device Credentials)
inline constexpr uint32_t kMaxCHIPCompactNetworkIdentityLength = 137;

// Length of a ASN.1 DER encoded ECPrivateKey structure (RFC 5915) for a P256 key pair.
inline constexpr uint32_t kP256ECPrivateKeyDERLength = 121;

/** Data Element Tags for the CHIP Certificate
*/
enum
Expand Down Expand Up @@ -730,6 +733,17 @@ CHIP_ERROR ConvertECDSASignatureRawToDER(P256ECDSASignatureSpan rawSig, ASN1::AS
*/
CHIP_ERROR ConvertECDSASignatureDERToRaw(ASN1::ASN1Reader & reader, chip::TLV::TLVWriter & writer, uint64_t tag);

/**
* @brief Convert a raw ECDSA P256 key pair to an ASN.1 DER encoded ECPrivateKey structure (RFC 5915).
*
* @param rawKeypair The raw P256 key pair.
* @param outDerKeypair Output buffer to receive the ASN.1 DER encoded key pair.
* Must have a capacity of at least `kP256ECPrivateKeyDERLength` bytes.
*
* @retval #CHIP_NO_ERROR If the key pair was successfully converted, or a CHIP_ERROR otherwise.
*/
CHIP_ERROR ConvertECDSAKeypairRawToDER(const Crypto::P256SerializedKeypair & rawKeypair, MutableByteSpan & outDerKeypair);

/**
* Extract the Fabric ID from an operational certificate that has already been
* parsed.
Expand Down
286 changes: 86 additions & 200 deletions src/credentials/tests/CHIPCert_test_vectors.cpp

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/credentials/tests/CHIPCert_test_vectors.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include <credentials/CHIPCert.h>
#include <credentials/CHIPCertificateSet.h>
#include <crypto/CHIPCryptoPAL.h>
#include <lib/support/CodeUtils.h>

namespace chip {
Expand Down Expand Up @@ -72,6 +73,8 @@ enum class TestCertLoadFlags : uint8_t
extern CHIP_ERROR GetTestCert(TestCert certType, BitFlags<TestCertLoadFlags> certLoadFlags, ByteSpan & cert);
extern const char * GetTestCertName(TestCert certType);
extern CHIP_ERROR GetTestCertPubkey(TestCert certType, ByteSpan & pubkey);
extern CHIP_ERROR GetTestCertPrivkey(TestCert certType, ByteSpan & privkey);
extern CHIP_ERROR GetTestCertKeypair(TestCert certType, Crypto::P256SerializedKeypair & keypair);
extern CHIP_ERROR GetTestCertSKID(TestCert certType, ByteSpan & skid);
extern CHIP_ERROR GetTestCertAKID(TestCert certType, ByteSpan & akid);

Expand Down Expand Up @@ -213,6 +216,7 @@ extern const ByteSpan sTestCert_PDCID01_PrivateKey;
extern const ByteSpan sTestCert_PDCID01_SubjectKeyId; // empty
extern const ByteSpan sTestCert_PDCID01_AuthorityKeyId; // empty
extern const ByteSpan sTestCert_PDCID01_KeyId;
extern const ByteSpan sTestCert_PDCID01_KeypairDER;

} // namespace TestCerts
} // namespace chip
16 changes: 16 additions & 0 deletions src/credentials/tests/TestChipCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <lib/core/TLV.h>
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/UnitTestExtendedAssertions.h>
#include <lib/support/UnitTestRegistration.h>

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

static void TestChipCert_KeypairConversion(nlTestSuite * inSuite, void * inContext)
{
P256SerializedKeypair keypair;
NL_TEST_ASSERT_SUCCESS(inSuite, GetTestCertKeypair(kPDCID01, keypair));

uint8_t buffer[kP256ECPrivateKeyDERLength];
MutableByteSpan keypairDer(buffer);
NL_TEST_ASSERT_SUCCESS(inSuite, ConvertECDSAKeypairRawToDER(keypair, keypairDer));

// Technically the curve name and public key are optional in the DER format,
// but both our code and standard tools include them, so we can just compare.
NL_TEST_ASSERT(inSuite, keypairDer.data_equal(sTestCert_PDCID01_KeypairDER));
}

/**
* Set up the test suite.
*/
Expand Down Expand Up @@ -2251,6 +2266,7 @@ static const nlTest sTests[] = {
NL_TEST_DEF("Test extracting PublicKey and SKID from chip certificate", TestChipCert_ExtractPublicKeyAndSKID),
NL_TEST_DEF("Test PDC Identity Validation", TestChipCert_PDCIdentityValidation),
NL_TEST_DEF("Test PDC Identity Generation", TestChipCert_PDCIdentityGeneration),
NL_TEST_DEF("Test keypair conversion", TestChipCert_KeypairConversion),
NL_TEST_SENTINEL()
};
// clang-format on
Expand Down
3 changes: 3 additions & 0 deletions src/crypto/CHIPCryptoPAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,9 @@ struct alignas(size_t) P256KeypairContext
uint8_t mBytes[kMAX_P256Keypair_Context_Size];
};

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

class P256KeypairBase : public ECPKeypair<P256PublicKey, P256ECDHDerivedSecret, P256ECDSASignature>
Expand Down
3 changes: 2 additions & 1 deletion src/include/platform/NetworkCommissioning.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,8 @@ class WiFiDriver : public Internal::WirelessDriver
/**
* @brief Signs the specified message with the private key of a Network Client Identity.
*/
virtual CHIP_ERROR SignWithClientIdentity(uint8_t networkIndex, ByteSpan & message, Crypto::P256ECDSASignature & outSignature)
virtual CHIP_ERROR SignWithClientIdentity(uint8_t networkIndex, const ByteSpan & message,
Crypto::P256ECDSASignature & outSignature)
{
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}
Expand Down
5 changes: 4 additions & 1 deletion src/platform/Linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ static_library("Linux") {
"SystemTimeSupport.cpp",
]

deps = [ "${chip_root}/src/setup_payload" ]
deps = [
"${chip_root}/src/credentials:credentials_header",
"${chip_root}/src/setup_payload",
]

if (!chip_use_external_logging) {
sources += [ "Logging.cpp" ]
Expand Down
Loading

0 comments on commit 560a46b

Please sign in to comment.