Skip to content

Commit

Permalink
Updated Device to Get PASE Verifier from Memory.
Browse files Browse the repository at this point in the history
Also removed one version of the PASESession::WaitForPairing() API, which
gets PIN Code as an input. Left only one version, which gets Verifier as
an input.
  • Loading branch information
emargolis authored and woody-apple committed Feb 8, 2022
1 parent b5dae1e commit fbeccc1
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 65 deletions.
24 changes: 17 additions & 7 deletions src/app/server/CommissioningWindowManager.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2021 Project CHIP Authors
* Copyright (c) 2021-2022 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -186,13 +186,23 @@ CHIP_ERROR CommissioningWindowManager::OpenCommissioningWindow()
}
else
{
uint32_t pinCode;
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSetupPinCode(pinCode));
uint32_t iterationCount = 0;
uint8_t salt[kPBKDFMaximumSaltLen] = { 0 };
size_t saltLen = 0;
PASEVerifierSerialized serializedVerifier = { 0 };
size_t serializedVerifierLen = 0;
PASEVerifier verifier;

ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSpake2pIterationCount(iterationCount));
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSpake2pSalt(salt, sizeof(salt), saltLen));
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSpake2pVerifier(serializedVerifier, kSpake2pSerializedVerifierSize,
serializedVerifierLen));
VerifyOrReturnError(kSpake2pSerializedVerifierSize == serializedVerifierLen, CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorOnFailure(verifier.Deserialize(ByteSpan(serializedVerifier)));

ReturnErrorOnFailure(mPairingSession.WaitForPairing(
pinCode, kSpake2p_Iteration_Count,
ByteSpan(reinterpret_cast<const uint8_t *>(kSpake2pKeyExchangeSalt), strlen(kSpake2pKeyExchangeSalt)), keyID,
Optional<ReliableMessageProtocolConfig>::Value(GetLocalMRPConfig()), this));
ReturnErrorOnFailure(
mPairingSession.WaitForPairing(verifier, iterationCount, ByteSpan(salt, saltLen), kDefaultCommissioningPasscodeId,
keyID, Optional<ReliableMessageProtocolConfig>::Value(GetLocalMRPConfig()), this));
}

ReturnErrorOnFailure(StartAdvertisement());
Expand Down
5 changes: 4 additions & 1 deletion src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,10 @@ CHIP_ERROR DeviceController::OpenCommissioningWindowInternal()

if (mCommissioningWindowOption != CommissioningWindowOption::kOriginalSetupCode)
{
ByteSpan salt(Uint8::from_const_char(kSpake2pKeyExchangeSalt), strlen(kSpake2pKeyExchangeSalt));
// TODO: Salt should be provided as an input or it should be randomly generated when
// the PIN is randomly generated.
const char kSpake2pKeyExchangeSalt[] = "SPAKE2P Key Salt";
ByteSpan salt(Uint8::from_const_char(kSpake2pKeyExchangeSalt), sizeof(kSpake2pKeyExchangeSalt));
bool randomSetupPIN = (mCommissioningWindowOption == CommissioningWindowOption::kTokenWithRandomPIN);
PASEVerifier verifier;

Expand Down
38 changes: 10 additions & 28 deletions src/protocols/secure_channel/PASESession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ const char * kSpake2pContext = "CHIP PAKE V1 Commissioning";
const char * kSpake2pI2RSessionInfo = "Commissioning I2R Key";
const char * kSpake2pR2ISessionInfo = "Commissioning R2I Key";

const char * kSpake2pKeyExchangeSalt = "SPAKE2P Key Salt";

// Wait at most 30 seconds for the response from the peer.
// This timeout value assumes the underlying transport is reliable.
// The session establishment fails if the response is not received with in timeout window.
Expand Down Expand Up @@ -248,32 +246,31 @@ CHIP_ERROR PASESession::GeneratePASEVerifier(PASEVerifier & verifier, uint32_t p
CHIP_ERROR PASESession::SetupSpake2p(uint32_t pbkdf2IterCount, const ByteSpan & salt)
{
TRACE_EVENT_SCOPE("SetupSpake2p", "PASESession");
uint8_t context[kSHA256_Hash_Length] = {
0,
};
uint8_t context[kSHA256_Hash_Length] = { 0 };

if (mComputeVerifier)
{
ReturnErrorOnFailure(PASESession::ComputePASEVerifier(mSetupPINCode, pbkdf2IterCount, salt, mPASEVerifier));
}

MutableByteSpan contextSpan{ context, sizeof(context) };
MutableByteSpan contextSpan{ context };

ReturnErrorOnFailure(mCommissioningHash.Finish(contextSpan));
ReturnErrorOnFailure(mSpake2p.Init(contextSpan.data(), contextSpan.size()));

return CHIP_NO_ERROR;
}

CHIP_ERROR PASESession::WaitForPairing(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const ByteSpan & salt,
uint16_t mySessionId, Optional<ReliableMessageProtocolConfig> mrpConfig,
SessionEstablishmentDelegate * delegate)
CHIP_ERROR PASESession::WaitForPairing(const PASEVerifier & verifier, uint32_t pbkdf2IterCount, const ByteSpan & salt,
PasscodeId passcodeID, uint16_t mySessionId,
Optional<ReliableMessageProtocolConfig> mrpConfig, SessionEstablishmentDelegate * delegate)
{
// Return early on error here, as we have not initialized any state yet
ReturnErrorCodeIf(salt.empty(), CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorCodeIf(salt.data() == nullptr, CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorCodeIf(salt.size() < kPBKDFMinimumSaltLen || salt.size() > kPBKDFMaximumSaltLen, CHIP_ERROR_INVALID_ARGUMENT);

CHIP_ERROR err = Init(mySessionId, mySetUpPINCode, delegate);
CHIP_ERROR err = Init(mySessionId, 0, delegate);
// From here onwards, let's go to exit on error, as some state might have already
// been initialized
SuccessOrExit(err);
Expand All @@ -291,13 +288,14 @@ CHIP_ERROR PASESession::WaitForPairing(uint32_t mySetUpPINCode, uint32_t pbkdf2I
VerifyOrExit(mSalt != nullptr, err = CHIP_ERROR_NO_MEMORY);

memmove(mSalt, salt.data(), mSaltLength);
memmove(&mPASEVerifier, &verifier, sizeof(verifier));

mIterationCount = pbkdf2IterCount;

mIterationCount = pbkdf2IterCount;
mNextExpectedMsg = MsgType::PBKDFParamRequest;
mPairingComplete = false;
mPasscodeID = kDefaultCommissioningPasscodeId;
mLocalMRPConfig = mrpConfig;
mComputeVerifier = false;

SetPeerNodeId(NodeIdFromPAKEKeyId(mPasscodeID));

Expand All @@ -311,22 +309,6 @@ CHIP_ERROR PASESession::WaitForPairing(uint32_t mySetUpPINCode, uint32_t pbkdf2I
return err;
}

CHIP_ERROR PASESession::WaitForPairing(const PASEVerifier & verifier, uint32_t pbkdf2IterCount, const ByteSpan & salt,
PasscodeId passcodeID, uint16_t mySessionId,
Optional<ReliableMessageProtocolConfig> mrpConfig, SessionEstablishmentDelegate * delegate)
{
ReturnErrorCodeIf(passcodeID == 0, CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorOnFailure(WaitForPairing(0, pbkdf2IterCount, salt, mySessionId, mrpConfig, delegate));

memmove(&mPASEVerifier, &verifier, sizeof(verifier));
mComputeVerifier = false;
mPasscodeID = passcodeID;

SetPeerNodeId(NodeIdFromPAKEKeyId(mPasscodeID));

return CHIP_NO_ERROR;
}

CHIP_ERROR PASESession::Pair(const Transport::PeerAddress peerAddress, uint32_t peerSetUpPINCode, uint16_t mySessionId,
Optional<ReliableMessageProtocolConfig> mrpConfig, Messaging::ExchangeContext * exchangeCtxt,
SessionEstablishmentDelegate * delegate)
Expand Down
17 changes: 0 additions & 17 deletions src/protocols/secure_channel/PASESession.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,8 @@ namespace chip {

extern const char * kSpake2pI2RSessionInfo;
extern const char * kSpake2pR2ISessionInfo;
extern const char * kSpake2pKeyExchangeSalt;

constexpr uint16_t kPBKDFParamRandomNumberSize = 32;
constexpr uint32_t kSpake2p_Iteration_Count = 100;

// Specifications section 3.9. Password-Based Key Derivation Function
constexpr uint32_t kPBKDFMinimumIterations = 1000;
Expand Down Expand Up @@ -110,21 +108,6 @@ class DLL_EXPORT PASESession : public Messaging::ExchangeDelegate, public Pairin
// should not need to be told their peer node ID
using PairingSession::SetPeerNodeId;

/**
* @brief
* Initialize using setup PIN code and wait for pairing requests.
*
* @param mySetUpPINCode Setup PIN code of the local device
* @param pbkdf2IterCount Iteration count for PBKDF2 function
* @param salt Salt to be used for SPAKE2P operation
* @param mySessionId Session ID to be assigned to the secure session on the peer node
* @param delegate Callback object
*
* @return CHIP_ERROR The result of initialization
*/
CHIP_ERROR WaitForPairing(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const ByteSpan & salt, uint16_t mySessionId,
Optional<ReliableMessageProtocolConfig> mrpConfig, SessionEstablishmentDelegate * delegate);

/**
* @brief
* Initialize using PASE verifier and wait for pairing requests.
Expand Down
41 changes: 29 additions & 12 deletions src/protocols/secure_channel/tests/TestPASESession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ using namespace chip::Protocols;

namespace {

// Test Set #01 of Spake2p Parameters (PIN Code, Iteration Count, Salt, and matching Verifier):
constexpr uint32_t sTestSpake2p01_PinCode = 20202021;
constexpr uint32_t sTestSpake2p01_IterationCount = 1000;
constexpr uint8_t sTestSpake2p01_Salt[] = { 0x53, 0x50, 0x41, 0x4B, 0x45, 0x32, 0x50, 0x20,
0x4B, 0x65, 0x79, 0x20, 0x53, 0x61, 0x6C, 0x74 };
constexpr PASEVerifier sTestSpake2p01_PASEVerifier = { .mW0 = { 0xab, 0xa6, 0x0c, 0x30, 0x41, 0x6b, 0x8f, 0x41, 0x77, 0xf5,
0xe1, 0x6a, 0xd5, 0x14, 0xcf, 0xd9, 0x57, 0x75, 0x13, 0xf0,
0x2f, 0xd6, 0x05, 0x06, 0xb1, 0x04, 0x9d, 0x0f, 0x2c, 0x73,
Expand Down Expand Up @@ -114,19 +119,29 @@ void SecurePairingWaitTest(nlTestSuite * inSuite, void * inContext)
gLoopback.Reset();

NL_TEST_ASSERT(inSuite,
pairing.WaitForPairing(1234, 500, ByteSpan(nullptr, 0), 0, Optional<ReliableMessageProtocolConfig>::Missing(),
pairing.WaitForPairing(sTestSpake2p01_PASEVerifier, sTestSpake2p01_IterationCount, ByteSpan(nullptr, 0),
kDefaultCommissioningPasscodeId, 0, Optional<ReliableMessageProtocolConfig>::Missing(),
&delegate) == CHIP_ERROR_INVALID_ARGUMENT);
ctx.DrainAndServiceIO();

NL_TEST_ASSERT(inSuite,
pairing.WaitForPairing(1234, 500, ByteSpan((const uint8_t *) "saltSalt", 8), 0,
Optional<ReliableMessageProtocolConfig>::Missing(),
pairing.WaitForPairing(sTestSpake2p01_PASEVerifier, sTestSpake2p01_IterationCount,
ByteSpan(reinterpret_cast<const uint8_t *>("saltSalt"), 8),
kDefaultCommissioningPasscodeId, 0, Optional<ReliableMessageProtocolConfig>::Missing(),
nullptr) == CHIP_ERROR_INVALID_ARGUMENT);
ctx.DrainAndServiceIO();

NL_TEST_ASSERT(inSuite,
pairing.WaitForPairing(1234, 500, ByteSpan((const uint8_t *) "saltSalt", 8), 0,
Optional<ReliableMessageProtocolConfig>::Missing(), &delegate) == CHIP_NO_ERROR);
pairing.WaitForPairing(sTestSpake2p01_PASEVerifier, sTestSpake2p01_IterationCount,
ByteSpan(reinterpret_cast<const uint8_t *>("saltSalt"), 8),
kDefaultCommissioningPasscodeId, 0, Optional<ReliableMessageProtocolConfig>::Missing(),
&delegate) == CHIP_ERROR_INVALID_ARGUMENT);
ctx.DrainAndServiceIO();

NL_TEST_ASSERT(inSuite,
pairing.WaitForPairing(sTestSpake2p01_PASEVerifier, sTestSpake2p01_IterationCount, ByteSpan(sTestSpake2p01_Salt),
kDefaultCommissioningPasscodeId, 0, Optional<ReliableMessageProtocolConfig>::Missing(),
&delegate) == CHIP_NO_ERROR);
ctx.DrainAndServiceIO();
}

Expand All @@ -144,12 +159,12 @@ void SecurePairingStartTest(nlTestSuite * inSuite, void * inContext)
ExchangeContext * context = ctx.NewUnauthenticatedExchangeToBob(&pairing);

NL_TEST_ASSERT(inSuite,
pairing.Pair(Transport::PeerAddress(Transport::Type::kBle), 1234, 0,
pairing.Pair(Transport::PeerAddress(Transport::Type::kBle), sTestSpake2p01_PinCode, 0,
Optional<ReliableMessageProtocolConfig>::Missing(), nullptr, nullptr) != CHIP_NO_ERROR);

gLoopback.Reset();
NL_TEST_ASSERT(inSuite,
pairing.Pair(Transport::PeerAddress(Transport::Type::kBle), 1234, 0,
pairing.Pair(Transport::PeerAddress(Transport::Type::kBle), sTestSpake2p01_PinCode, 0,
Optional<ReliableMessageProtocolConfig>::Missing(), context, &delegate) == CHIP_NO_ERROR);
ctx.DrainAndServiceIO();

Expand All @@ -167,7 +182,7 @@ void SecurePairingStartTest(nlTestSuite * inSuite, void * inContext)
PASESession pairing1;
ExchangeContext * context1 = ctx.NewUnauthenticatedExchangeToBob(&pairing1);
NL_TEST_ASSERT(inSuite,
pairing1.Pair(Transport::PeerAddress(Transport::Type::kBle), 1234, 0,
pairing1.Pair(Transport::PeerAddress(Transport::Type::kBle), sTestSpake2p01_PinCode, 0,
Optional<ReliableMessageProtocolConfig>::Missing(), context1,
&delegate) == CHIP_ERROR_BAD_REQUEST);
ctx.DrainAndServiceIO();
Expand Down Expand Up @@ -207,13 +222,14 @@ void SecurePairingHandshakeTestCommon(nlTestSuite * inSuite, void * inContext, P
Protocols::SecureChannel::MsgType::PBKDFParamRequest, &pairingAccessory) == CHIP_NO_ERROR);

NL_TEST_ASSERT(inSuite,
pairingAccessory.WaitForPairing(1234, 500, ByteSpan((const uint8_t *) "saltSALTsaltSALT", 16), 0,
pairingAccessory.WaitForPairing(sTestSpake2p01_PASEVerifier, sTestSpake2p01_IterationCount,
ByteSpan(sTestSpake2p01_Salt), kDefaultCommissioningPasscodeId, 0,
mrpAccessoryConfig, &delegateAccessory) == CHIP_NO_ERROR);
ctx.DrainAndServiceIO();

NL_TEST_ASSERT(inSuite,
pairingCommissioner.Pair(Transport::PeerAddress(Transport::Type::kBle), 1234, 0, mrpCommissionerConfig,
contextCommissioner, &delegateCommissioner) == CHIP_NO_ERROR);
pairingCommissioner.Pair(Transport::PeerAddress(Transport::Type::kBle), sTestSpake2p01_PinCode, 0,
mrpCommissionerConfig, contextCommissioner, &delegateCommissioner) == CHIP_NO_ERROR);
ctx.DrainAndServiceIO();

while (gLoopback.mMessageDropped)
Expand Down Expand Up @@ -333,7 +349,8 @@ void SecurePairingFailedHandshake(nlTestSuite * inSuite, void * inContext)
Protocols::SecureChannel::MsgType::PBKDFParamRequest, &pairingAccessory) == CHIP_NO_ERROR);

NL_TEST_ASSERT(inSuite,
pairingAccessory.WaitForPairing(1234, 500, ByteSpan((const uint8_t *) "saltSALTsaltSALT", 16), 0,
pairingAccessory.WaitForPairing(sTestSpake2p01_PASEVerifier, sTestSpake2p01_IterationCount,
ByteSpan(sTestSpake2p01_Salt), kDefaultCommissioningPasscodeId, 0,
Optional<ReliableMessageProtocolConfig>::Missing(),
&delegateAccessory) == CHIP_NO_ERROR);
ctx.DrainAndServiceIO();
Expand Down

0 comments on commit fbeccc1

Please sign in to comment.