Skip to content

Commit

Permalink
[crypto] Add support for CHIP_CONFIG_SECURITY_TEST_MODE. (#10163)
Browse files Browse the repository at this point in the history
* [crypto] Add support for CHIP_CONFIG_SECURITY_TEST_MODE.
* [crypto] Make CHIP_CONFIG_TEST_SHARED_SECRET_VALUE configurable.
* [crypto] Expand warning message for CONFIG_SECURITY_TEST_MODE flag.
  - Output warning message both at runtime log and compile-time message.
  - Expand message to itemize caveats of setting this flag:
    - All session keys will be overridden with a fixed, known key.
    - All nodes in fabric need to share setting of this flag.
  • Loading branch information
turon authored and pull[bot] committed Oct 6, 2021
1 parent 549fc9b commit 1066010
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 28 deletions.
3 changes: 1 addition & 2 deletions docs/QUICK_START.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ controller.

#### IP Pairing

`chip-tool pairing onnetwork 0 20202021 3840 ::1 5540` will use PASE over IP to
pair a device.
`chip-tool pairing onnetwork 34567890` will use PASE over IP to pair a device.

NOTE: to run both the Node and Controller as separate processes on the same
Linux or Mac machine, build the all-clusters-app with BLE disabled as follows:
Expand Down
17 changes: 17 additions & 0 deletions src/lib/core/CHIPConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,23 @@
#define CHIP_CONFIG_SECURITY_TEST_MODE 0
#endif // CHIP_CONFIG_SECURITY_TEST_MODE

/**
* @def CHIP_CONFIG_TEST_SHARED_SECRET_VALUE
*
* @brief
* Shared secret to use for unit tests or when CHIP_CONFIG_SECURITY_TEST_MODE is enabled.
*
* This parameter is 32 bytes to maximize entropy passed to the CryptoContext::InitWithSecret KDF,
* and can be initialized either as a raw string or array of bytes. The default test secret of
* "Test secret for key derivation." results in the following encryption keys:
*
* 5E DE D2 44 E5 53 2B 3C DC 23 40 9D BA D0 52 D2
* A9 E0 11 B1 73 7C 6D 4B 70 E4 C0 A2 FE 66 04 76
*/
#ifndef CHIP_CONFIG_TEST_SHARED_SECRET_VALUE
#define CHIP_CONFIG_TEST_SHARED_SECRET_VALUE "Test secret for key derivation."
#endif // CHIP_CONFIG_TEST_SHARED_SECRET_VALUE

/**
* @def CHIP_CONFIG_ENABLE_DNS_RESOLVER
*
Expand Down
2 changes: 1 addition & 1 deletion src/protocols/secure_channel/PASESession.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ class SecurePairingUsingTestSecret : public PairingSession
const char * GetR2ISessionInfo() const override { return "r2i"; }

private:
const char * kTestSecret = "Test secret for key derivation";
const char * kTestSecret = CHIP_CONFIG_TEST_SHARED_SECRET_VALUE;
};

typedef struct PASESessionSerialized
Expand Down
30 changes: 28 additions & 2 deletions src/transport/CryptoContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,43 @@ CHIP_ERROR CryptoContext::InitFromSecret(const ByteSpan & secret, const ByteSpan
infoLen = sizeof(RSEKeysInfo);
}

#if CHIP_CONFIG_SECURITY_TEST_MODE

// If enabled, override the generated session key with a known key pair
// to allow man-in-the-middle session key recovery for testing purposes.

#define TEST_SECRET_SIZE 32
constexpr uint8_t kTestSharedSecret[TEST_SECRET_SIZE] = CHIP_CONFIG_TEST_SHARED_SECRET_VALUE;
static_assert(sizeof(CHIP_CONFIG_TEST_SHARED_SECRET_VALUE) == TEST_SECRET_SIZE,
"CHIP_CONFIG_TEST_SHARED_SECRET_VALUE must be 32 bytes");
const ByteSpan & testSalt = ByteSpan(nullptr, 0);
(void) info;
(void) infoLen;

#pragma message \
"Warning: CONFIG_SECURITY_TEST_MODE=1 bypassing key negotiation... All sessions will use known, fixed test key. Node can only communicate with other nodes built with this flag set."
ChipLogError(SecureChannel,
"Warning: CONFIG_SECURITY_TEST_MODE=1 bypassing key negotiation... All sessions will use known, fixed test key. "
"Node can only communicate with other nodes built with this flag set.");

ReturnErrorOnFailure(mHKDF.HKDF_SHA256(kTestSharedSecret, TEST_SECRET_SIZE, testSalt.data(), testSalt.size(), SEKeysInfo,
sizeof(SEKeysInfo), &mKeys[0][0], sizeof(mKeys)));
#else

ReturnErrorOnFailure(
mHKDF.HKDF_SHA256(secret.data(), secret.size(), salt.data(), salt.size(), info, infoLen, &mKeys[0][0], sizeof(mKeys)));

#endif

mKeyAvailable = true;
mSessionRole = role;

return CHIP_NO_ERROR;
}

CHIP_ERROR CryptoContext::Init(const Crypto::P256Keypair & local_keypair, const Crypto::P256PublicKey & remote_public_key,
const ByteSpan & salt, SessionInfoType infoType, SessionRole role)
CHIP_ERROR CryptoContext::InitFromKeyPair(const Crypto::P256Keypair & local_keypair,
const Crypto::P256PublicKey & remote_public_key, const ByteSpan & salt,
SessionInfoType infoType, SessionRole role)
{

VerifyOrReturnError(mKeyAvailable == false, CHIP_ERROR_INCORRECT_STATE);
Expand Down
4 changes: 2 additions & 2 deletions src/transport/CryptoContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ class DLL_EXPORT CryptoContext
* @param role Role of the new session (initiator or responder)
* @return CHIP_ERROR The result of key derivation
*/
CHIP_ERROR Init(const Crypto::P256Keypair & local_keypair, const Crypto::P256PublicKey & remote_public_key,
const ByteSpan & salt, SessionInfoType infoType, SessionRole role);
CHIP_ERROR InitFromKeyPair(const Crypto::P256Keypair & local_keypair, const Crypto::P256PublicKey & remote_public_key,
const ByteSpan & salt, SessionInfoType infoType, SessionRole role);

/**
* @brief
Expand Down
42 changes: 21 additions & 21 deletions src/transport/tests/TestSecureSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,29 +46,29 @@ void SecureChannelInitTest(nlTestSuite * inSuite, void * inContext)

// Test all combinations of invalid parameters
NL_TEST_ASSERT(inSuite,
channel.Init(keypair, keypair2.Pubkey(), ByteSpan(nullptr, 10),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_ERROR_INVALID_ARGUMENT);
channel.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan(nullptr, 10),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_ERROR_INVALID_ARGUMENT);

// Test the channel is successfully created with valid parameters
NL_TEST_ASSERT(inSuite,
channel.Init(keypair, keypair2.Pubkey(), ByteSpan(nullptr, 0),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_NO_ERROR);
channel.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan(nullptr, 0),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_NO_ERROR);

// Test the channel cannot be reinitialized
NL_TEST_ASSERT(inSuite,
channel.Init(keypair, keypair2.Pubkey(), ByteSpan(nullptr, 0),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_ERROR_INCORRECT_STATE);
channel.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan(nullptr, 0),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_ERROR_INCORRECT_STATE);

// Test the channel can be initialized with valid salt
const char * salt = "Test Salt";
CryptoContext channel2;
NL_TEST_ASSERT(inSuite,
channel2.Init(keypair, keypair2.Pubkey(), ByteSpan((const uint8_t *) salt, sizeof(salt)),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_NO_ERROR);
channel2.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan((const uint8_t *) salt, sizeof(salt)),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_NO_ERROR);
}

void SecureChannelEncryptTest(nlTestSuite * inSuite, void * inContext)
Expand All @@ -92,9 +92,9 @@ void SecureChannelEncryptTest(nlTestSuite * inSuite, void * inContext)

const char * salt = "Test Salt";
NL_TEST_ASSERT(inSuite,
channel.Init(keypair, keypair2.Pubkey(), ByteSpan((const uint8_t *) salt, sizeof(salt)),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_NO_ERROR);
channel.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan((const uint8_t *) salt, sizeof(salt)),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_NO_ERROR);

// Test initialized channel, but invalid arguments
NL_TEST_ASSERT(inSuite, channel.Encrypt(nullptr, 0, nullptr, packetHeader, mac) == CHIP_ERROR_INVALID_ARGUMENT);
Expand Down Expand Up @@ -123,9 +123,9 @@ void SecureChannelDecryptTest(nlTestSuite * inSuite, void * inContext)
NL_TEST_ASSERT(inSuite, keypair2.Initialize() == CHIP_NO_ERROR);

NL_TEST_ASSERT(inSuite,
channel.Init(keypair, keypair2.Pubkey(), ByteSpan((const uint8_t *) salt, sizeof(salt)),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_NO_ERROR);
channel.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan((const uint8_t *) salt, sizeof(salt)),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kInitiator) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, channel.Encrypt(plain_text, sizeof(plain_text), encrypted, packetHeader, mac) == CHIP_NO_ERROR);

CryptoContext channel2;
Expand All @@ -135,9 +135,9 @@ void SecureChannelDecryptTest(nlTestSuite * inSuite, void * inContext)
channel2.Decrypt(encrypted, sizeof(plain_text), output, packetHeader, mac) ==
CHIP_ERROR_INVALID_USE_OF_SESSION_KEY);
NL_TEST_ASSERT(inSuite,
channel2.Init(keypair2, keypair.Pubkey(), ByteSpan((const uint8_t *) salt, sizeof(salt)),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kResponder) == CHIP_NO_ERROR);
channel2.InitFromKeyPair(keypair2, keypair.Pubkey(), ByteSpan((const uint8_t *) salt, sizeof(salt)),
CryptoContext::SessionInfoType::kSessionEstablishment,
CryptoContext::SessionRole::kResponder) == CHIP_NO_ERROR);

// Channel initialized, but invalid arguments to decrypt
NL_TEST_ASSERT(inSuite, channel2.Decrypt(nullptr, 0, nullptr, packetHeader, mac) == CHIP_ERROR_INVALID_ARGUMENT);
Expand Down

0 comments on commit 1066010

Please sign in to comment.