Skip to content

Commit

Permalink
Fix Dependency Loop Error Introduced with project-chip#14676 (project…
Browse files Browse the repository at this point in the history
…-chip#15127)

Moved some of the Spake2p defines to the CHIPCryptoPAL.h
  • Loading branch information
emargolis authored Feb 17, 2022
1 parent b03bc9f commit a80c9f8
Show file tree
Hide file tree
Showing 12 changed files with 79 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class OpenCommissioningWindowCommand : public CHIPCommand
AddArgument("node-id", 0, UINT64_MAX, &mNodeId);
AddArgument("option", 0, 2, &mCommissioningWindowOption);
AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
AddArgument("iteration", chip::kPBKDFMinimumIterations, chip::kPBKDFMaximumIterations, &mIteration);
AddArgument("iteration", chip::Crypto::kSpake2pPBKDFMinimumIterations, chip::Crypto::kSpake2pPBKDFMaximumIterations,
&mIteration);
AddArgument("discriminator", 0, 4096, &mDiscriminator);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,14 @@ bool emberAfAdministratorCommissioningClusterOpenCommissioningWindowCallback(
VerifyOrExit(Server::GetInstance().GetCommissioningWindowManager().CommissioningWindowStatus() ==
CommissioningWindowStatus::kWindowNotOpen,
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_BUSY));
VerifyOrExit(iterations >= kPBKDFMinimumIterations, status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
VerifyOrExit(iterations <= kPBKDFMaximumIterations, status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
VerifyOrExit(salt.size() >= kPBKDFMinimumSaltLen, status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
VerifyOrExit(salt.size() <= kPBKDFMaximumSaltLen, status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
VerifyOrExit(iterations >= Crypto::kSpake2pPBKDFMinimumIterations,
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
VerifyOrExit(iterations <= Crypto::kSpake2pPBKDFMaximumIterations,
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
VerifyOrExit(salt.size() >= Crypto::kSpake2pPBKDFMinimumSaltLen,
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
VerifyOrExit(salt.size() <= Crypto::kSpake2pPBKDFMaximumSaltLen,
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
VerifyOrExit(commissioningTimeout <= kMaxCommissionioningTimeoutSeconds,
status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
VerifyOrExit(discriminator <= kMaxDiscriminatorValue, status.Emplace(StatusCode::EMBER_ZCL_STATUS_CODE_PAKE_PARAMETER_ERROR));
Expand Down
16 changes: 8 additions & 8 deletions src/app/server/CommissioningWindowManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,18 +187,18 @@ CHIP_ERROR CommissioningWindowManager::OpenCommissioningWindow()
}
else
{
uint32_t iterationCount = 0;
uint8_t salt[kPBKDFMaximumSaltLen] = { 0 };
size_t saltLen = 0;
PASEVerifierSerialized serializedVerifier = { 0 };
size_t serializedVerifierLen = 0;
uint32_t iterationCount = 0;
uint8_t salt[Crypto::kSpake2pPBKDFMaximumSaltLen] = { 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(DeviceLayer::ConfigurationMgr().GetSpake2pVerifier(
serializedVerifier, Crypto::kSpake2pSerializedVerifierSize, serializedVerifierLen));
VerifyOrReturnError(Crypto::kSpake2pSerializedVerifierSize == serializedVerifierLen, CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorOnFailure(verifier.Deserialize(ByteSpan(serializedVerifier)));

ReturnErrorOnFailure(
Expand Down
2 changes: 1 addition & 1 deletion src/app/server/CommissioningWindowManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class CommissioningWindowManager : public SessionEstablishmentDelegate
PasscodeId mECMPasscodeID = kDefaultCommissioningPasscodeId;
uint32_t mECMIterations = 0;
uint32_t mECMSaltLength = 0;
uint8_t mECMSalt[kPBKDFMaximumSaltLen];
uint8_t mECMSalt[Crypto::kSpake2pPBKDFMaximumSaltLen];
};

} // namespace chip
4 changes: 2 additions & 2 deletions src/app/tests/TestCommissionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ void CheckCommissioningWindowManagerEnhancedWindowTask(intptr_t context)
NL_TEST_ASSERT(suite, err == CHIP_NO_ERROR);
uint16_t newDiscriminator = static_cast<uint16_t>(originDiscriminator + 1);
chip::PASEVerifier verifier;
constexpr uint32_t kIterations = chip::kPBKDFMinimumIterations;
uint8_t salt[chip::kPBKDFMinimumSaltLen];
constexpr uint32_t kIterations = chip::Crypto::kSpake2pPBKDFMinimumIterations;
uint8_t salt[chip::Crypto::kSpake2pPBKDFMinimumSaltLen];
chip::ByteSpan saltData(salt);
constexpr chip::PasscodeId kPasscodeID = 1;
uint16_t currentDiscriminator;
Expand Down
3 changes: 2 additions & 1 deletion src/controller/java/CHIPDeviceController-JNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,8 @@ JNI_METHOD(jobject, computePaseVerifier)
err = verifier.Serialize(serializedVerifierSpan);
SuccessOrExit(err);

err = JniReferences::GetInstance().N2J_ByteArray(env, serializedVerifier, kSpake2pSerializedVerifierSize, verifierBytes);
err =
JniReferences::GetInstance().N2J_ByteArray(env, serializedVerifier, Crypto::kSpake2pSerializedVerifierSize, verifierBytes);
SuccessOrExit(err);

err = N2J_PaseVerifierParams(env, setupPincode, static_cast<jlong>(passcodeId), verifierBytes, params);
Expand Down
20 changes: 20 additions & 0 deletions src/crypto/CHIPCryptoPAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,26 @@ const uint8_t spake2p_N_p256[65] = {
0xd3, 0x60, 0x34, 0x80, 0x8c, 0xd5, 0x64, 0x49, 0x0b, 0x1e, 0x65, 0x6e, 0xdb, 0xe7,
};

/** @brief Spake2p parameters.
*
* Specifications section 3.9. Password-Based Key Derivation Function
* Specifications section 5.1.1.6
**/
constexpr uint32_t kSpake2pPBKDFMinimumIterations = 1000;
constexpr uint32_t kSpake2pPBKDFMaximumIterations = 100000;
constexpr uint32_t kSpake2pPBKDFMinimumSaltLen = 16;
constexpr uint32_t kSpake2pPBKDFMaximumSaltLen = 32;

/** @brief Serialized format of the PASE Verifier components.
*
* This is used when the Verifier should be presented in a serialized form.
* For example, when it is generated using PBKDF function, when stored in the
* memory or when sent over the wire.
* The serialized format is concatentation of { W0, L } verifier components
* as per Specifications section 3.10. Password-Authenticated Key Exchange.
**/
constexpr size_t kSpake2pSerializedVerifierSize = kP256_FE_Length + kP256_Point_Length;

/**
* Spake2+ state machine to ensure proper execution of the protocol.
*/
Expand Down
19 changes: 12 additions & 7 deletions src/include/platform/internal/GenericConfigurationManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#define GENERIC_CONFIGURATION_MANAGER_IMPL_CPP

#include <ble/CHIPBleServiceData.h>
#include <crypto/CHIPCryptoPAL.h>
#include <inttypes.h>
#include <lib/core/CHIPConfig.h>
#include <lib/support/Base64.h>
Expand All @@ -35,7 +36,6 @@
#include <lib/support/ScopedBuffer.h>
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <platform/internal/GenericConfigurationManagerImpl.h>
#include <protocols/secure_channel/PASESession.h>

#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
#include <platform/ThreadStackManager.h>
Expand Down Expand Up @@ -332,9 +332,11 @@ CHIP_ERROR GenericConfigurationManagerImpl<ConfigClass>::GetSpake2pIterationCoun
template <class ConfigClass>
CHIP_ERROR GenericConfigurationManagerImpl<ConfigClass>::GetSpake2pSalt(uint8_t * buf, size_t bufSize, size_t & saltLen)
{
CHIP_ERROR err = CHIP_NO_ERROR;
char saltB64[BASE64_ENCODED_LEN(chip::kPBKDFMaximumSaltLen) + 1] = { 0 };
size_t saltB64Len = 0;
static constexpr size_t kSpake2pSalt_MaxBase64Len = BASE64_ENCODED_LEN(chip::Crypto::kSpake2pPBKDFMaximumSaltLen) + 1;

CHIP_ERROR err = CHIP_NO_ERROR;
char saltB64[kSpake2pSalt_MaxBase64Len] = { 0 };
size_t saltB64Len = 0;

err = ReadConfigValueStr(ConfigClass::kConfigKey_Spake2pSalt, saltB64, sizeof(saltB64), saltB64Len);
err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
Expand All @@ -359,9 +361,12 @@ CHIP_ERROR GenericConfigurationManagerImpl<ConfigClass>::GetSpake2pSalt(uint8_t
template <class ConfigClass>
CHIP_ERROR GenericConfigurationManagerImpl<ConfigClass>::GetSpake2pVerifier(uint8_t * buf, size_t bufSize, size_t & verifierLen)
{
CHIP_ERROR err = CHIP_NO_ERROR;
char verifierB64[BASE64_ENCODED_LEN(chip::kSpake2pSerializedVerifierSize) + 1] = { 0 };
size_t verifierB64Len = 0;
static constexpr size_t kSpake2pSerializedVerifier_MaxBase64Len =
BASE64_ENCODED_LEN(chip::Crypto::kSpake2pSerializedVerifierSize) + 1;

CHIP_ERROR err = CHIP_NO_ERROR;
char verifierB64[kSpake2pSerializedVerifier_MaxBase64Len] = { 0 };
size_t verifierB64Len = 0;

err = ReadConfigValueStr(ConfigClass::kConfigKey_Spake2pVerifier, verifierB64, sizeof(verifierB64), verifierB64Len);
err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
Expand Down
9 changes: 5 additions & 4 deletions src/protocols/secure_channel/PASESession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ CHIP_ERROR PASESession::WaitForPairing(const PASEVerifier & verifier, uint32_t p
// 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);
ReturnErrorCodeIf(salt.size() < Crypto::kSpake2pPBKDFMinimumSaltLen || salt.size() > Crypto::kSpake2pPBKDFMaximumSaltLen,
CHIP_ERROR_INVALID_ARGUMENT);

CHIP_ERROR err = Init(mySessionId, kSetupPINCodeUndefinedValue, delegate);
// From here onwards, let's go to exit on error, as some state might have already
Expand Down Expand Up @@ -974,19 +975,19 @@ CHIP_ERROR PASESession::OnMessageReceived(ExchangeContext * exchange, const Payl

CHIP_ERROR PASEVerifier::Serialize(MutableByteSpan & outSerialized)
{
VerifyOrReturnError(outSerialized.size() >= kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(outSerialized.size() >= Crypto::kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT);

memcpy(&outSerialized.data()[0], mW0, sizeof(mW0));
memcpy(&outSerialized.data()[sizeof(mW0)], mL, sizeof(mL));

outSerialized.reduce_size(kSpake2pSerializedVerifierSize);
outSerialized.reduce_size(Crypto::kSpake2pSerializedVerifierSize);

return CHIP_NO_ERROR;
}

CHIP_ERROR PASEVerifier::Deserialize(ByteSpan inSerialized)
{
VerifyOrReturnError(inSerialized.size() >= kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(inSerialized.size() >= Crypto::kSpake2pSerializedVerifierSize, CHIP_ERROR_INVALID_ARGUMENT);

memcpy(mW0, &inSerialized.data()[0], sizeof(mW0));
memcpy(mL, &inSerialized.data()[sizeof(mW0)], sizeof(mL));
Expand Down
20 changes: 2 additions & 18 deletions src/protocols/secure_channel/PASESession.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,6 @@ extern const char * kSpake2pR2ISessionInfo;

constexpr uint16_t kPBKDFParamRandomNumberSize = 32;

// Specifications section 3.9. Password-Based Key Derivation Function
constexpr uint32_t kPBKDFMinimumIterations = 1000;
constexpr uint32_t kPBKDFMaximumIterations = 100000;
constexpr uint32_t kPBKDFMinimumSaltLen = 16;
constexpr uint32_t kPBKDFMaximumSaltLen = 32;

// Specifications section 5.1.1.6
constexpr uint32_t kSetupPINCodeMaximumValue = 99999998;
constexpr uint32_t kSetupPINCodeUndefinedValue = 0;

Expand All @@ -75,17 +68,6 @@ struct PASESessionSerializable
uint16_t mPeerSessionId;
};

/** @brief Serialized format of the PASE Verifier components.
*
* This is used when the Verifier should be presented in a serialized form.
* For example, when it is generated using PBKDF function, when stored in the
* memory or when sent over the wire.
* The serialized format is concatentation of 'W0' and 'L' verifier components:
* { PASEVerifier.mW0[kP256_FE_Length], PASEVerifier.mL[kP256_Point_Length] }
**/
constexpr size_t kSpake2pSerializedVerifierSize = kP256_FE_Length + kP256_Point_Length;
typedef uint8_t PASEVerifierSerialized[kSpake2pSerializedVerifierSize];

struct PASEVerifier
{
uint8_t mW0[kP256_FE_Length];
Expand All @@ -95,6 +77,8 @@ struct PASEVerifier
CHIP_ERROR Deserialize(ByteSpan inSerialized);
};

typedef uint8_t PASEVerifierSerialized[Crypto::kSpake2pSerializedVerifierSize];

class DLL_EXPORT PASESession : public Messaging::ExchangeDelegate, public PairingSession
{
public:
Expand Down
10 changes: 6 additions & 4 deletions src/protocols/secure_channel/tests/TestPASESession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,15 +445,17 @@ void PASEVerifierSerializeTest(nlTestSuite * inSuite, void * inContext)
PASEVerifierSerialized serializedVerifier;
MutableByteSpan serializedVerifierSpan(serializedVerifier);
NL_TEST_ASSERT(inSuite, verifier.Serialize(serializedVerifierSpan) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, serializedVerifierSpan.size() == kSpake2pSerializedVerifierSize);
NL_TEST_ASSERT(inSuite, memcmp(serializedVerifier, sTestSpake2p01_SerializedVerifier, kSpake2pSerializedVerifierSize) == 0);
NL_TEST_ASSERT(inSuite, serializedVerifierSpan.size() == Crypto::kSpake2pSerializedVerifierSize);
NL_TEST_ASSERT(inSuite,
memcmp(serializedVerifier, sTestSpake2p01_SerializedVerifier, Crypto::kSpake2pSerializedVerifierSize) == 0);

PASEVerifierSerialized serializedVerifier2;
MutableByteSpan serializedVerifier2Span(serializedVerifier2);
NL_TEST_ASSERT(inSuite, chip::Crypto::DRBG_get_bytes(serializedVerifier, kSpake2pSerializedVerifierSize) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite,
chip::Crypto::DRBG_get_bytes(serializedVerifier, Crypto::kSpake2pSerializedVerifierSize) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, verifier.Deserialize(ByteSpan(serializedVerifier)) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, verifier.Serialize(serializedVerifier2Span) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, memcmp(serializedVerifier, serializedVerifier2, kSpake2pSerializedVerifierSize) == 0);
NL_TEST_ASSERT(inSuite, memcmp(serializedVerifier, serializedVerifier2, Crypto::kSpake2pSerializedVerifierSize) == 0);
}

// Test Suite
Expand Down
18 changes: 11 additions & 7 deletions src/tools/spake2p/Cmd_GenVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,15 +168,17 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char

case 'i':
if (!ParseInt(arg, gIterationCount) ||
!(gIterationCount >= chip::kPBKDFMinimumIterations && gIterationCount <= chip::kPBKDFMaximumIterations))
!(gIterationCount >= chip::Crypto::kSpake2pPBKDFMinimumIterations &&
gIterationCount <= chip::Crypto::kSpake2pPBKDFMaximumIterations))
{
PrintArgError("%s: Invalid value specified for the iteration-count parameter: %s\n", progName, arg);
return false;
}
break;

case 'l':
if (!ParseInt(arg, gSaltLen) || !(gSaltLen >= chip::kPBKDFMinimumSaltLen && gSaltLen <= chip::kPBKDFMaximumSaltLen))
if (!ParseInt(arg, gSaltLen) ||
!(gSaltLen >= chip::Crypto::kSpake2pPBKDFMinimumSaltLen && gSaltLen <= chip::Crypto::kSpake2pPBKDFMaximumSaltLen))
{
PrintArgError("%s: Invalid value specified for salt length parameter: %s\n", progName, arg);
return false;
Expand All @@ -185,7 +187,8 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char

case 's':
gSalt = arg;
if (!(strlen(gSalt) >= chip::kPBKDFMinimumSaltLen && strlen(gSalt) <= chip::kPBKDFMaximumSaltLen))
if (!(strlen(gSalt) >= chip::Crypto::kSpake2pPBKDFMinimumSaltLen &&
strlen(gSalt) <= chip::Crypto::kSpake2pPBKDFMaximumSaltLen))
{
fprintf(stderr, "%s: Invalid legth of the specified salt parameter: %s\n", progName, arg);
return false;
Expand Down Expand Up @@ -268,7 +271,7 @@ bool Cmd_GenVerifier(int argc, char * argv[])

for (uint32_t i = 0; i < gCount; i++)
{
uint8_t salt[chip::kPBKDFMaximumSaltLen];
uint8_t salt[chip::Crypto::kSpake2pPBKDFMaximumSaltLen];
if (gSalt == nullptr)
{
CHIP_ERROR err = chip::Crypto::DRBG_get_bytes(salt, gSaltLen);
Expand Down Expand Up @@ -301,12 +304,13 @@ bool Cmd_GenVerifier(int argc, char * argv[])
return false;
}

char saltB64[BASE64_ENCODED_LEN(chip::kPBKDFMaximumSaltLen) + 1];
char saltB64[BASE64_ENCODED_LEN(chip::Crypto::kSpake2pPBKDFMaximumSaltLen) + 1];
uint32_t saltB64Len = chip::Base64Encode32(salt, gSaltLen, saltB64);
saltB64[saltB64Len] = '\0';

char verifierB64[BASE64_ENCODED_LEN(chip::kSpake2pSerializedVerifierSize) + 1];
uint32_t verifierB64Len = chip::Base64Encode32(serializedVerifier, chip::kSpake2pSerializedVerifierSize, verifierB64);
char verifierB64[BASE64_ENCODED_LEN(chip::Crypto::kSpake2pSerializedVerifierSize) + 1];
uint32_t verifierB64Len =
chip::Base64Encode32(serializedVerifier, chip::Crypto::kSpake2pSerializedVerifierSize, verifierB64);
verifierB64[verifierB64Len] = '\0';

if (fprintf(outFile, "%d,%08d,%d,%s,%s\n", i, gPinCode, gIterationCount, saltB64, verifierB64) < 0 || ferror(outFile))
Expand Down

0 comments on commit a80c9f8

Please sign in to comment.