diff --git a/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.h b/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.h index 9714fc52831dba..4b73be4fe40e26 100644 --- a/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.h +++ b/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.h @@ -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); } diff --git a/src/app/clusters/administrator-commissioning-server/administrator-commissioning-server.cpp b/src/app/clusters/administrator-commissioning-server/administrator-commissioning-server.cpp index 16732722b3539f..3643a7c88e4138 100644 --- a/src/app/clusters/administrator-commissioning-server/administrator-commissioning-server.cpp +++ b/src/app/clusters/administrator-commissioning-server/administrator-commissioning-server.cpp @@ -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)); diff --git a/src/app/server/CommissioningWindowManager.cpp b/src/app/server/CommissioningWindowManager.cpp index 6b1d600fdfb7f9..5880b0581d9a7e 100644 --- a/src/app/server/CommissioningWindowManager.cpp +++ b/src/app/server/CommissioningWindowManager.cpp @@ -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( diff --git a/src/app/server/CommissioningWindowManager.h b/src/app/server/CommissioningWindowManager.h index 5ea69702a1e547..e893f78f823278 100644 --- a/src/app/server/CommissioningWindowManager.h +++ b/src/app/server/CommissioningWindowManager.h @@ -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 diff --git a/src/app/tests/TestCommissionManager.cpp b/src/app/tests/TestCommissionManager.cpp index ea337a779b06b2..8e7331c24072fc 100644 --- a/src/app/tests/TestCommissionManager.cpp +++ b/src/app/tests/TestCommissionManager.cpp @@ -118,8 +118,8 @@ void CheckCommissioningWindowManagerEnhancedWindowTask(intptr_t context) NL_TEST_ASSERT(suite, err == CHIP_NO_ERROR); uint16_t newDiscriminator = static_cast(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; diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 564744d794feaf..8027028ba14328 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -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(passcodeId), verifierBytes, params); diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 1fc36ddd9fc9dd..b2b48f7883a589 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -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. */ diff --git a/src/include/platform/internal/GenericConfigurationManagerImpl.cpp b/src/include/platform/internal/GenericConfigurationManagerImpl.cpp index 1ec4aa122e8add..7b7b27ead6edfe 100644 --- a/src/include/platform/internal/GenericConfigurationManagerImpl.cpp +++ b/src/include/platform/internal/GenericConfigurationManagerImpl.cpp @@ -27,6 +27,7 @@ #define GENERIC_CONFIGURATION_MANAGER_IMPL_CPP #include +#include #include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #if CHIP_DEVICE_CONFIG_ENABLE_THREAD #include @@ -332,9 +332,11 @@ CHIP_ERROR GenericConfigurationManagerImpl::GetSpake2pIterationCoun template CHIP_ERROR GenericConfigurationManagerImpl::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; @@ -359,9 +361,12 @@ CHIP_ERROR GenericConfigurationManagerImpl::GetSpake2pSalt(uint8_t template CHIP_ERROR GenericConfigurationManagerImpl::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; diff --git a/src/protocols/secure_channel/PASESession.cpp b/src/protocols/secure_channel/PASESession.cpp index d9e616d9440c4d..f42a52a5ae6ef4 100644 --- a/src/protocols/secure_channel/PASESession.cpp +++ b/src/protocols/secure_channel/PASESession.cpp @@ -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 @@ -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)); diff --git a/src/protocols/secure_channel/PASESession.h b/src/protocols/secure_channel/PASESession.h index 8cd01feb909826..bc15eb08fecd71 100644 --- a/src/protocols/secure_channel/PASESession.h +++ b/src/protocols/secure_channel/PASESession.h @@ -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; @@ -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]; @@ -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: diff --git a/src/protocols/secure_channel/tests/TestPASESession.cpp b/src/protocols/secure_channel/tests/TestPASESession.cpp index c8b63b1a8b4525..ac910655e4acf4 100644 --- a/src/protocols/secure_channel/tests/TestPASESession.cpp +++ b/src/protocols/secure_channel/tests/TestPASESession.cpp @@ -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 diff --git a/src/tools/spake2p/Cmd_GenVerifier.cpp b/src/tools/spake2p/Cmd_GenVerifier.cpp index 87dea156847df9..2feea540ad46da 100644 --- a/src/tools/spake2p/Cmd_GenVerifier.cpp +++ b/src/tools/spake2p/Cmd_GenVerifier.cpp @@ -168,7 +168,8 @@ 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; @@ -176,7 +177,8 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char 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; @@ -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; @@ -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); @@ -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))