diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index b445ab88ce434c..c97f2c17090b64 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -103,6 +103,7 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack() factoryInitParams.operationalKeystore = &mOperationalKeystore; factoryInitParams.opCertStore = &mOpCertStore; factoryInitParams.enableServerInteractions = NeedsOperationalAdvertising(); + factoryInitParams.sessionKeystore = &mSessionKeystore; // Init group data provider that will be used for all group keys and IPKs for the // chip-tool-configured fabrics. This is OK to do once since the fabric tables @@ -110,6 +111,7 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack() // Different commissioner implementations may want to use alternate implementations // of GroupDataProvider for injection through factoryInitParams. sGroupDataProvider.SetStorageDelegate(&mDefaultStorage); + sGroupDataProvider.SetSessionKeystore(factoryInitParams.sessionKeystore); ReturnLogErrorOnFailure(sGroupDataProvider.Init()); chip::Credentials::SetGroupDataProvider(&sGroupDataProvider); factoryInitParams.groupDataProvider = &sGroupDataProvider; diff --git a/examples/chip-tool/commands/common/CHIPCommand.h b/examples/chip-tool/commands/common/CHIPCommand.h index ee46ada917b944..cbe09472f3ea8d 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.h +++ b/examples/chip-tool/commands/common/CHIPCommand.h @@ -29,6 +29,7 @@ #include #include #include +#include #pragma once @@ -139,6 +140,7 @@ class CHIPCommand : public Command #endif // CONFIG_USE_LOCAL_STORAGE chip::PersistentStorageOperationalKeystore mOperationalKeystore; chip::Credentials::PersistentStorageOpCertStore mOpCertStore; + chip::Crypto::RawKeySessionKeystore mSessionKeystore; static chip::Credentials::GroupDataProviderImpl sGroupDataProvider; CredentialIssuerCommands * mCredIssuerCmds; diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index f5bcce727d6489..1ad6c3212b84cc 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -28,7 +28,6 @@ #include #include -#include #include #include diff --git a/examples/platform/linux/CommissionerMain.cpp b/examples/platform/linux/CommissionerMain.cpp index fca5222acce4a7..f59ff10325c156 100644 --- a/examples/platform/linux/CommissionerMain.cpp +++ b/examples/platform/linux/CommissionerMain.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -122,6 +123,7 @@ MyServerStorageDelegate gServerStorage; ExampleOperationalCredentialsIssuer gOpCredsIssuer; NodeId gLocalId = kMaxOperationalNodeId; Credentials::GroupDataProviderImpl gGroupDataProvider; +Crypto::RawKeySessionKeystore gSessionKeystore; CHIP_ERROR InitCommissioner(uint16_t commissionerPort, uint16_t udcListenPort, FabricId fabricId) { @@ -132,8 +134,10 @@ CHIP_ERROR InitCommissioner(uint16_t commissionerPort, uint16_t udcListenPort, F factoryParams.listenPort = commissionerPort; factoryParams.fabricIndependentStorage = &gServerStorage; factoryParams.fabricTable = &Server::GetInstance().GetFabricTable(); + factoryParams.sessionKeystore = &gSessionKeystore; gGroupDataProvider.SetStorageDelegate(&gServerStorage); + gGroupDataProvider.SetSessionKeystore(factoryParams.sessionKeystore); ReturnErrorOnFailure(gGroupDataProvider.Init()); factoryParams.groupDataProvider = &gGroupDataProvider; diff --git a/examples/platform/nxp/se05x/linux/AppMain.cpp b/examples/platform/nxp/se05x/linux/AppMain.cpp index 6129298cbf3853..9d83e354cce466 100644 --- a/examples/platform/nxp/se05x/linux/AppMain.cpp +++ b/examples/platform/nxp/se05x/linux/AppMain.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -292,13 +293,14 @@ int ChipLinuxAppInit(int argc, char * const argv[], OptionSet * customOptions) struct CommonCaseDeviceServerInitParams_Se05x : public CommonCaseDeviceServerInitParams { - CHIP_ERROR InitializeStaticResourcesBeforeServerInit() override + CHIP_ERROR InitializeStaticResourcesBeforeServerInit() { static chip::KvsPersistentStorageDelegate sKvsPersistenStorageDelegate; static chip::PersistentStorageOperationalKeystoreHSM sPersistentStorageOperationalKeystore; static chip::Credentials::PersistentStorageOpCertStore sPersistentStorageOpCertStore; static chip::Credentials::GroupDataProviderImpl sGroupDataProvider; static IgnoreCertificateValidityPolicy sDefaultCertValidityPolicy; + static chip::Crypto::DefaultSessionKeystore sSessionKeystore; #if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION static chip::SimpleSessionResumptionStorage sSessionResumptionStorage; @@ -333,8 +335,12 @@ struct CommonCaseDeviceServerInitParams_Se05x : public CommonCaseDeviceServerIni this->opCertStore = &sPersistentStorageOpCertStore; } + // Session Keystore injection + this->sessionKeystore = &sSessionKeystore; + // Group Data provider injection sGroupDataProvider.SetStorageDelegate(this->persistentStorageDelegate); + sGroupDataProvider.SetSessionKeystore(this->sessionKeystore); ReturnErrorOnFailure(sGroupDataProvider.Init()); this->groupDataProvider = &sGroupDataProvider; diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index 56c02358b0ec97..fa11ff0a71b044 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -123,6 +123,7 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams) VerifyOrExit(initParams.accessDelegate != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(initParams.aclStorage != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(initParams.groupDataProvider != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(initParams.sessionKeystore != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(initParams.operationalKeystore != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(initParams.opCertStore != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); @@ -205,7 +206,8 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams) #endif SuccessOrExit(err); - err = mSessions.Init(&DeviceLayer::SystemLayer(), &mTransports, &mMessageCounterManager, mDeviceStorage, &GetFabricTable()); + err = mSessions.Init(&DeviceLayer::SystemLayer(), &mTransports, &mMessageCounterManager, mDeviceStorage, &GetFabricTable(), + *initParams.sessionKeystore); SuccessOrExit(err); err = mFabricDelegate.Init(this); @@ -538,4 +540,18 @@ void Server::ResumeSubscriptions() } #endif +KvsPersistentStorageDelegate CommonCaseDeviceServerInitParams::sKvsPersistenStorageDelegate; +PersistentStorageOperationalKeystore CommonCaseDeviceServerInitParams::sPersistentStorageOperationalKeystore; +Credentials::PersistentStorageOpCertStore CommonCaseDeviceServerInitParams::sPersistentStorageOpCertStore; +Credentials::GroupDataProviderImpl CommonCaseDeviceServerInitParams::sGroupDataProvider; +IgnoreCertificateValidityPolicy CommonCaseDeviceServerInitParams::sDefaultCertValidityPolicy; +#if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION +SimpleSessionResumptionStorage CommonCaseDeviceServerInitParams::sSessionResumptionStorage; +#endif +#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS +app::SimpleSubscriptionResumptionStorage CommonCaseDeviceServerInitParams::sSubscriptionResumptionStorage; +#endif +app::DefaultAclStorage CommonCaseDeviceServerInitParams::sAclStorage; +Crypto::DefaultSessionKeystore CommonCaseDeviceServerInitParams::sSessionKeystore; + } // namespace chip diff --git a/src/app/server/Server.h b/src/app/server/Server.h index 638c918cb46ca1..e1a8a6cd9847a5 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -85,8 +86,7 @@ using ServerTransportMgr = chip::TransportMgropCertStore = &sPersistentStorageOpCertStore; } + // Session Keystore injection + this->sessionKeystore = &sSessionKeystore; + // Group Data provider injection sGroupDataProvider.SetStorageDelegate(this->persistentStorageDelegate); + sGroupDataProvider.SetSessionKeystore(this->sessionKeystore); ReturnErrorOnFailure(sGroupDataProvider.Init()); this->groupDataProvider = &sGroupDataProvider; @@ -291,6 +283,21 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams return CHIP_NO_ERROR; } + +private: + static KvsPersistentStorageDelegate sKvsPersistenStorageDelegate; + static PersistentStorageOperationalKeystore sPersistentStorageOperationalKeystore; + static Credentials::PersistentStorageOpCertStore sPersistentStorageOpCertStore; + static Credentials::GroupDataProviderImpl sGroupDataProvider; + static IgnoreCertificateValidityPolicy sDefaultCertValidityPolicy; +#if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION + static SimpleSessionResumptionStorage sSessionResumptionStorage; +#endif +#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS + static app::SimpleSubscriptionResumptionStorage sSubscriptionResumptionStorage; +#endif + static app::DefaultAclStorage sAclStorage; + static Crypto::DefaultSessionKeystore sSessionKeystore; }; /** @@ -342,6 +349,8 @@ class Server Credentials::GroupDataProvider * GetGroupDataProvider() { return mGroupsProvider; } + Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } + #if CONFIG_NETWORK_LAYER_BLE Ble::BleLayer * GetBleLayerObject() { return mBleLayer; } #endif @@ -556,6 +565,7 @@ class Server app::SubscriptionResumptionStorage * mSubscriptionResumptionStorage; Credentials::CertificateValidityPolicy * mCertificateValidityPolicy; Credentials::GroupDataProvider * mGroupsProvider; + Crypto::SessionKeystore * mSessionKeystore; app::DefaultAttributePersistenceProvider mAttributePersister; GroupDataProviderListener mListener; ServerFabricDelegate mFabricDelegate; diff --git a/src/app/tests/TestWriteInteraction.cpp b/src/app/tests/TestWriteInteraction.cpp index 6026333050665c..4729f9e71b10f5 100644 --- a/src/app/tests/TestWriteInteraction.cpp +++ b/src/app/tests/TestWriteInteraction.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ constexpr uint16_t kMaxGroupsPerFabric = 5; constexpr uint16_t kMaxGroupKeysPerFabric = 8; chip::TestPersistentStorageDelegate gTestStorage; +chip::Crypto::DefaultSessionKeystore gSessionKeystore; chip::Credentials::GroupDataProviderImpl gGroupsProvider(kMaxGroupsPerFabric, kMaxGroupKeysPerFabric); } // namespace @@ -1042,6 +1044,7 @@ int Test_Setup(void * inContext) TestContext & ctx = *static_cast(inContext); gTestStorage.ClearStorage(); gGroupsProvider.SetStorageDelegate(&gTestStorage); + gGroupsProvider.SetSessionKeystore(&gSessionKeystore); VerifyOrReturnError(CHIP_NO_ERROR == gGroupsProvider.Init(), FAILURE); chip::Credentials::SetGroupDataProvider(&gGroupsProvider); diff --git a/src/app/tests/integration/chip_im_initiator.cpp b/src/app/tests/integration/chip_im_initiator.cpp index 5457bbb3fd79ef..3f822623e49b91 100644 --- a/src/app/tests/integration/chip_im_initiator.cpp +++ b/src/app/tests/integration/chip_im_initiator.cpp @@ -716,7 +716,7 @@ int main(int argc, char * argv[]) SuccessOrExit(err); err = gSessionManager.Init(&chip::DeviceLayer::SystemLayer(), &gTransportManager, &gMessageCounterManager, &gStorage, - &gFabricTable); + &gFabricTable, gSessionKeystore); SuccessOrExit(err); err = gExchangeManager.Init(&gSessionManager); diff --git a/src/app/tests/integration/chip_im_responder.cpp b/src/app/tests/integration/chip_im_responder.cpp index 34978611e4f3bf..03215e52fbe31b 100644 --- a/src/app/tests/integration/chip_im_responder.cpp +++ b/src/app/tests/integration/chip_im_responder.cpp @@ -197,7 +197,7 @@ int main(int argc, char * argv[]) SuccessOrExit(err); err = gSessionManager.Init(&chip::DeviceLayer::SystemLayer(), &gTransportManager, &gMessageCounterManager, &gStorage, - &gFabricTable); + &gFabricTable, gSessionKeystore); SuccessOrExit(err); err = gExchangeManager.Init(&gSessionManager); diff --git a/src/app/tests/integration/common.cpp b/src/app/tests/integration/common.cpp index 5b3c231d3f9459..87627aeb9fddf0 100644 --- a/src/app/tests/integration/common.cpp +++ b/src/app/tests/integration/common.cpp @@ -43,6 +43,7 @@ chip::SessionHolder gSession; chip::TestPersistentStorageDelegate gStorage; chip::PersistentStorageOperationalKeystore gOperationalKeystore; chip::Credentials::PersistentStorageOpCertStore gOpCertStore; +chip::Crypto::DefaultSessionKeystore gSessionKeystore; void InitializeChip() { diff --git a/src/app/tests/integration/common.h b/src/app/tests/integration/common.h index 2b1865561c259a..4766b9d6160500 100644 --- a/src/app/tests/integration/common.h +++ b/src/app/tests/integration/common.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,7 @@ extern chip::SessionManager gSessionManager; extern chip::secure_channel::MessageCounterManager gMessageCounterManager; extern chip::SessionHolder gSession; extern chip::TestPersistentStorageDelegate gStorage; +extern chip::Crypto::DefaultSessionKeystore gSessionKeystore; constexpr chip::NodeId kTestNodeId = 0x1ULL; constexpr chip::NodeId kTestNodeId1 = 0x2ULL; diff --git a/src/controller/CHIPDeviceControllerFactory.cpp b/src/controller/CHIPDeviceControllerFactory.cpp index 25457368d945a3..1261b0f7af5db5 100644 --- a/src/controller/CHIPDeviceControllerFactory.cpp +++ b/src/controller/CHIPDeviceControllerFactory.cpp @@ -86,6 +86,7 @@ CHIP_ERROR DeviceControllerFactory::InitSystemState() params.fabricIndependentStorage = mFabricIndependentStorage; params.enableServerInteractions = mEnableServerInteractions; params.groupDataProvider = mSystemState->GetGroupDataProvider(); + params.sessionKeystore = mSystemState->GetSessionKeystore(); params.fabricTable = mSystemState->Fabrics(); params.operationalKeystore = mOperationalKeystore; params.opCertStore = mOpCertStore; @@ -129,6 +130,7 @@ CHIP_ERROR DeviceControllerFactory::InitSystemState(FactoryInitParams params) // OperationalCertificateStore needs to be provided to init the fabric table if fabric table is // not provided wholesale. ReturnErrorCodeIf((params.fabricTable == nullptr) && (params.opCertStore == nullptr), CHIP_ERROR_INVALID_ARGUMENT); + ReturnErrorCodeIf(params.sessionKeystore == nullptr, CHIP_ERROR_INVALID_ARGUMENT); #if CONFIG_NETWORK_LAYER_BLE #if CONFIG_DEVICE_LAYER @@ -166,6 +168,7 @@ CHIP_ERROR DeviceControllerFactory::InitSystemState(FactoryInitParams params) stateParams.exchangeMgr = chip::Platform::New(); stateParams.messageCounterManager = chip::Platform::New(); stateParams.groupDataProvider = params.groupDataProvider; + stateParams.sessionKeystore = params.sessionKeystore; // if no fabricTable was provided, create one and track it in stateParams for cleanup stateParams.fabricTable = params.fabricTable; @@ -198,7 +201,7 @@ CHIP_ERROR DeviceControllerFactory::InitSystemState(FactoryInitParams params) ReturnErrorOnFailure(stateParams.sessionMgr->Init(stateParams.systemLayer, stateParams.transportMgr, stateParams.messageCounterManager, params.fabricIndependentStorage, - stateParams.fabricTable)); + stateParams.fabricTable, *stateParams.sessionKeystore)); ReturnErrorOnFailure(stateParams.exchangeMgr->Init(stateParams.sessionMgr)); ReturnErrorOnFailure(stateParams.messageCounterManager->Init(stateParams.exchangeMgr)); ReturnErrorOnFailure(stateParams.unsolicitedStatusHandler->Init(stateParams.exchangeMgr)); diff --git a/src/controller/CHIPDeviceControllerFactory.h b/src/controller/CHIPDeviceControllerFactory.h index 351580ebf7715e..fd77c3779017a9 100644 --- a/src/controller/CHIPDeviceControllerFactory.h +++ b/src/controller/CHIPDeviceControllerFactory.h @@ -94,15 +94,16 @@ struct SetupParams CommissioningDelegate * defaultCommissioner = nullptr; }; -// TODO everything other than the fabric storage, group data provider, OperationalKeystore -// and OperationalCertificateStore here should be removed. We're blocked because of the -// need to support !CHIP_DEVICE_LAYER +// TODO everything other than the fabric storage, group data provider, OperationalKeystore, +// OperationalCertificateStore and SessionKeystore here should be removed. We're blocked +// because of the need to support !CHIP_DEVICE_LAYER struct FactoryInitParams { System::Layer * systemLayer = nullptr; PersistentStorageDelegate * fabricIndependentStorage = nullptr; Credentials::CertificateValidityPolicy * certificateValidityPolicy = nullptr; Credentials::GroupDataProvider * groupDataProvider = nullptr; + Crypto::SessionKeystore * sessionKeystore = nullptr; Inet::EndPointManager * tcpEndPointManager = nullptr; Inet::EndPointManager * udpEndPointManager = nullptr; FabricTable * fabricTable = nullptr; diff --git a/src/controller/CHIPDeviceControllerSystemState.h b/src/controller/CHIPDeviceControllerSystemState.h index 8cf83063464c5c..739b9f113754d9 100644 --- a/src/controller/CHIPDeviceControllerSystemState.h +++ b/src/controller/CHIPDeviceControllerSystemState.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +82,7 @@ struct DeviceControllerSystemStateParams Ble::BleLayer * bleLayer = nullptr; #endif Credentials::GroupDataProvider * groupDataProvider = nullptr; + Crypto::SessionKeystore * sessionKeystore = nullptr; // Params that will be deallocated via Platform::Delete in // DeviceControllerSystemState::Shutdown. @@ -126,7 +128,8 @@ class DeviceControllerSystemState mMessageCounterManager(params.messageCounterManager), mFabrics(params.fabricTable), mCASEServer(params.caseServer), mCASESessionManager(params.caseSessionManager), mSessionSetupPool(params.sessionSetupPool), mCASEClientPool(params.caseClientPool), mGroupDataProvider(params.groupDataProvider), - mFabricTableDelegate(params.fabricTableDelegate), mSessionResumptionStorage(std::move(params.sessionResumptionStorage)) + mSessionKeystore(params.sessionKeystore), mFabricTableDelegate(params.fabricTableDelegate), + mSessionResumptionStorage(std::move(params.sessionResumptionStorage)) { #if CONFIG_NETWORK_LAYER_BLE mBleLayer = params.bleLayer; @@ -165,7 +168,7 @@ class DeviceControllerSystemState return mSystemLayer != nullptr && mUDPEndPointManager != nullptr && mTransportMgr != nullptr && mSessionMgr != nullptr && mUnsolicitedStatusHandler != nullptr && mExchangeMgr != nullptr && mMessageCounterManager != nullptr && mFabrics != nullptr && mCASESessionManager != nullptr && mSessionSetupPool != nullptr && mCASEClientPool != nullptr && - mGroupDataProvider != nullptr; + mGroupDataProvider != nullptr && mSessionKeystore != nullptr; }; System::Layer * SystemLayer() const { return mSystemLayer; }; @@ -181,6 +184,7 @@ class DeviceControllerSystemState #endif CASESessionManager * CASESessionMgr() const { return mCASESessionManager; } Credentials::GroupDataProvider * GetGroupDataProvider() const { return mGroupDataProvider; } + Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } void SetTempFabricTable(FabricTable * tempFabricTable) { mTempFabricTable = tempFabricTable; } private: @@ -203,6 +207,7 @@ class DeviceControllerSystemState SessionSetupPool * mSessionSetupPool = nullptr; CASEClientPool * mCASEClientPool = nullptr; Credentials::GroupDataProvider * mGroupDataProvider = nullptr; + Crypto::SessionKeystore * mSessionKeystore = nullptr; FabricTable::Delegate * mFabricTableDelegate = nullptr; Platform::UniquePtr mSessionResumptionStorage; diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp index 701d6d6683aad7..b9fe506bb2d617 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.cpp +++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp @@ -177,8 +177,10 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew( setupParams.operationalCredentialsDelegate = opCredsIssuer; setupParams.defaultCommissioner = &wrapper->mAutoCommissioner; initParams.fabricIndependentStorage = wrapperStorage; + initParams.sessionKeystore = &wrapper->mSessionKeystore; wrapper->mGroupDataProvider.SetStorageDelegate(wrapperStorage); + wrapper->mGroupDataProvider.SetSessionKeystore(initParams.sessionKeystore); CommissioningParameters params = wrapper->mAutoCommissioner.GetCommissioningParameters(); params.SetFailsafeTimerSeconds(failsafeTimerSeconds); diff --git a/src/controller/java/AndroidDeviceControllerWrapper.h b/src/controller/java/AndroidDeviceControllerWrapper.h index 3267f7fc4519b5..0700591bf77580 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.h +++ b/src/controller/java/AndroidDeviceControllerWrapper.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -205,6 +206,8 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel chip::Credentials::GroupDataProviderImpl mGroupDataProvider; // TODO: This may need to be injected as an OperationalCertificateStore * chip::Credentials::PersistentStorageOpCertStore mOpCertStore; + // TODO: This may need to be injected as a SessionKeystore* + chip::Crypto::RawKeySessionKeystore mSessionKeystore; JavaVM * mJavaVM = nullptr; jobject mJavaObjectRef = nullptr; diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index 0be9b561ab0b51..e9cf070756f207 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -102,6 +103,7 @@ chip::Controller::ScriptDevicePairingDelegate sPairingDelegate; chip::Controller::ScriptPairingDeviceDiscoveryDelegate sPairingDeviceDiscoveryDelegate; chip::Credentials::GroupDataProviderImpl sGroupDataProvider; chip::Credentials::PersistentStorageOpCertStore sPersistentStorageOpCertStore; +chip::Crypto::RawKeySessionKeystore sSessionKeystore; // NOTE: Remote device ID is in sync with the echo server device id // At some point, we may want to add an option to connect to a device without @@ -231,8 +233,10 @@ PyChipError pychip_DeviceController_StackInit(Controller::Python::StorageAdapter FactoryInitParams factoryParams; factoryParams.fabricIndependentStorage = storageAdapter; + factoryParams.sessionKeystore = &sSessionKeystore; sGroupDataProvider.SetStorageDelegate(storageAdapter); + sGroupDataProvider.SetSessionKeystore(factoryParams.sessionKeystore); PyReturnErrorOnFailure(ToPyChipError(sGroupDataProvider.Init())); factoryParams.groupDataProvider = &sGroupDataProvider; diff --git a/src/controller/python/chip/internal/CommissionerImpl.cpp b/src/controller/python/chip/internal/CommissionerImpl.cpp index 25102783ac223f..c95bdaa7c12059 100644 --- a/src/controller/python/chip/internal/CommissionerImpl.cpp +++ b/src/controller/python/chip/internal/CommissionerImpl.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +99,7 @@ ScriptDevicePairingDelegate gPairingDelegate; chip::Credentials::GroupDataProviderImpl gGroupDataProvider; chip::Credentials::PersistentStorageOpCertStore gPersistentStorageOpCertStore; chip::Controller::ExampleOperationalCredentialsIssuer gOperationalCredentialsIssuer; +chip::Crypto::RawKeySessionKeystore gSessionKeystore; } // namespace @@ -132,9 +134,11 @@ extern "C" chip::Controller::DeviceCommissioner * pychip_internal_Commissioner_N chip::Credentials::SetDeviceAttestationVerifier(chip::Credentials::GetDefaultDACVerifier(testingRootStore)); factoryParams.fabricIndependentStorage = &gServerStorage; + factoryParams.sessionKeystore = &gSessionKeystore; // Initialize group data provider for local group key state and IPKs gGroupDataProvider.SetStorageDelegate(&gServerStorage); + gGroupDataProvider.SetSessionKeystore(factoryParams.sessionKeystore); err = gGroupDataProvider.Init(); SuccessOrExit(err); factoryParams.groupDataProvider = &gGroupDataProvider; diff --git a/src/credentials/GroupDataProviderImpl.cpp b/src/credentials/GroupDataProviderImpl.cpp index 3ebbb6575255c1..36e9baaef398aa 100644 --- a/src/credentials/GroupDataProviderImpl.cpp +++ b/src/credentials/GroupDataProviderImpl.cpp @@ -817,7 +817,7 @@ constexpr size_t GroupDataProviderImpl::kIteratorsMax; CHIP_ERROR GroupDataProviderImpl::Init() { - if (mStorage == nullptr) + if (mStorage == nullptr || mSessionKeystore == nullptr) { return CHIP_ERROR_INCORRECT_STATE; } @@ -1747,9 +1747,7 @@ Crypto::SymmetricKeyContext * GroupDataProviderImpl::GetKeyContext(FabricIndex f Crypto::GroupOperationalCredentials * creds = keyset.GetCurrentGroupCredentials(); if (nullptr != creds) { - return mGroupKeyContexPool.CreateObject( - *this, ByteSpan(creds->encryption_key, Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES), creds->hash, - ByteSpan(creds->privacy_key, Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES)); + return mGroupKeyContexPool.CreateObject(*this, creds->encryption_key, creds->hash, creds->privacy_key); } } } @@ -1789,8 +1787,7 @@ CHIP_ERROR GroupDataProviderImpl::GetIpkKeySet(FabricIndex fabric_index, KeySet void GroupDataProviderImpl::GroupKeyContext::Release() { - memset(mEncryptionKey, 0, sizeof(mEncryptionKey)); - memset(mPrivacyKey, 0, sizeof(mPrivacyKey)); + ReleaseKeys(); mProvider.mGroupKeyContexPool.ReleaseObject(this); } @@ -1799,8 +1796,8 @@ CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::MessageEncrypt(const ByteSpan MutableByteSpan & ciphertext) const { uint8_t * output = ciphertext.data(); - return Crypto::AES_CCM_encrypt(plaintext.data(), plaintext.size(), aad.data(), aad.size(), mEncryptionKey, - Crypto::kAES_CCM128_Key_Length, nonce.data(), nonce.size(), output, mic.data(), mic.size()); + return Crypto::AES_CCM_encrypt(plaintext.data(), plaintext.size(), aad.data(), aad.size(), mEncryptionKey, nonce.data(), + nonce.size(), output, mic.data(), mic.size()); } CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::MessageDecrypt(const ByteSpan & ciphertext, const ByteSpan & aad, @@ -1809,21 +1806,19 @@ CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::MessageDecrypt(const ByteSpan { uint8_t * output = plaintext.data(); return Crypto::AES_CCM_decrypt(ciphertext.data(), ciphertext.size(), aad.data(), aad.size(), mic.data(), mic.size(), - mEncryptionKey, Crypto::kAES_CCM128_Key_Length, nonce.data(), nonce.size(), output); + mEncryptionKey, nonce.data(), nonce.size(), output); } CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::PrivacyEncrypt(const ByteSpan & input, const ByteSpan & nonce, MutableByteSpan & output) const { - return Crypto::AES_CTR_crypt(input.data(), input.size(), mPrivacyKey, Crypto::kAES_CCM128_Key_Length, nonce.data(), - nonce.size(), output.data()); + return Crypto::AES_CTR_crypt(input.data(), input.size(), mPrivacyKey, nonce.data(), nonce.size(), output.data()); } CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::PrivacyDecrypt(const ByteSpan & input, const ByteSpan & nonce, MutableByteSpan & output) const { - return Crypto::AES_CTR_crypt(input.data(), input.size(), mPrivacyKey, Crypto::kAES_CCM128_Key_Length, nonce.data(), - nonce.size(), output.data()); + return Crypto::AES_CTR_crypt(input.data(), input.size(), mPrivacyKey, nonce.data(), nonce.size(), output.data()); } GroupDataProviderImpl::GroupSessionIterator * GroupDataProviderImpl::IterateGroupSessions(uint16_t session_id) @@ -1928,8 +1923,7 @@ bool GroupDataProviderImpl::GroupSessionIteratorImpl::Next(GroupSession & output Crypto::GroupOperationalCredentials & creds = keyset.operational_keys[mKeyIndex++]; if (creds.hash == mSessionId) { - mGroupKeyContext.SetKey(ByteSpan(creds.encryption_key, sizeof(creds.encryption_key)), mSessionId); - mGroupKeyContext.SetPrivacyKey(ByteSpan(creds.privacy_key, sizeof(creds.privacy_key))); + mGroupKeyContext.Initialize(creds.encryption_key, mSessionId, creds.privacy_key); output.fabric_index = fabric.fabric_index; output.group_id = mapping.group_id; output.security_policy = keyset.policy; @@ -1943,6 +1937,7 @@ bool GroupDataProviderImpl::GroupSessionIteratorImpl::Next(GroupSession & output void GroupDataProviderImpl::GroupSessionIteratorImpl::Release() { + mGroupKeyContext.ReleaseKeys(); mProvider.mGroupSessionsIterator.ReleaseObject(this); } diff --git a/src/credentials/GroupDataProviderImpl.h b/src/credentials/GroupDataProviderImpl.h index 73c8bc2faadb24..5c1d0d67e3417f 100644 --- a/src/credentials/GroupDataProviderImpl.h +++ b/src/credentials/GroupDataProviderImpl.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include @@ -42,6 +43,9 @@ class GroupDataProviderImpl : public GroupDataProvider */ void SetStorageDelegate(PersistentStorageDelegate * storage); + void SetSessionKeystore(Crypto::SessionKeystore * keystore) { mSessionKeystore = keystore; } + Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } + CHIP_ERROR Init() override; void Finish() override; @@ -152,23 +156,35 @@ class GroupDataProviderImpl : public GroupDataProvider public: GroupKeyContext(GroupDataProviderImpl & provider) : mProvider(provider) {} - GroupKeyContext(GroupDataProviderImpl & provider, const ByteSpan & encryptionKey, uint16_t hash, - const ByteSpan & privacyKey) : + GroupKeyContext(GroupDataProviderImpl & provider, const Crypto::Aes128KeyByteArray & encryptionKey, uint16_t hash, + const Crypto::Aes128KeyByteArray & privacyKey) : mProvider(provider) + { - SetKey(encryptionKey, hash); - SetPrivacyKey(privacyKey); + Initialize(encryptionKey, hash, privacyKey); } - void SetKey(const ByteSpan & encryptionKey, uint16_t hash) + void Initialize(const Crypto::Aes128KeyByteArray & encryptionKey, uint16_t hash, + const Crypto::Aes128KeyByteArray & privacyKey) { + ReleaseKeys(); mKeyHash = hash; - memcpy(mEncryptionKey, encryptionKey.data(), std::min(encryptionKey.size(), sizeof(mEncryptionKey))); + // TODO: Load group keys to the session keystore upon loading from persistent storage + // + // Group keys should be transformed into a key handle as soon as possible or even + // the key storage should be taken over by SessionKeystore interface, but this looks + // like more work, so let's use the transitional code below for now. + + Crypto::SessionKeystore * keystore = mProvider.GetSessionKeystore(); + keystore->CreateKey(encryptionKey, mEncryptionKey); + keystore->CreateKey(privacyKey, mPrivacyKey); } - void SetPrivacyKey(const ByteSpan & privacyKey) + void ReleaseKeys() { - memcpy(mPrivacyKey, privacyKey.data(), std::min(privacyKey.size(), sizeof(mPrivacyKey))); + Crypto::SessionKeystore * keystore = mProvider.GetSessionKeystore(); + keystore->DestroyKey(mEncryptionKey); + keystore->DestroyKey(mPrivacyKey); } uint16_t GetKeyHash() override { return mKeyHash; } @@ -184,9 +200,9 @@ class GroupDataProviderImpl : public GroupDataProvider protected: GroupDataProviderImpl & mProvider; - uint16_t mKeyHash = 0; - uint8_t mEncryptionKey[Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES] = { 0 }; - uint8_t mPrivacyKey[Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES] = { 0 }; + uint16_t mKeyHash = 0; + Crypto::Aes128KeyHandle mEncryptionKey; + Crypto::Aes128KeyHandle mPrivacyKey; }; class KeySetIteratorImpl : public KeySetIterator @@ -230,7 +246,8 @@ class GroupDataProviderImpl : public GroupDataProvider bool IsInitialized() { return (mStorage != nullptr); } CHIP_ERROR RemoveEndpoints(FabricIndex fabric_index, GroupId group_id); - chip::PersistentStorageDelegate * mStorage = nullptr; + PersistentStorageDelegate * mStorage = nullptr; + Crypto::SessionKeystore * mSessionKeystore = nullptr; ObjectPool mGroupInfoIterators; ObjectPool mGroupKeyIterators; ObjectPool mEndpointIterators; diff --git a/src/credentials/tests/TestGroupDataProvider.cpp b/src/credentials/tests/TestGroupDataProvider.cpp index deafdf5958de3a..56a6424557b8a4 100644 --- a/src/credentials/tests/TestGroupDataProvider.cpp +++ b/src/credentials/tests/TestGroupDataProvider.cpp @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -1196,6 +1197,7 @@ void TestGroupDecryption(nlTestSuite * apSuite, void * apContext) namespace { static chip::TestPersistentStorageDelegate sDelegate; +static chip::Crypto::DefaultSessionKeystore sSessionKeystore; static GroupDataProviderImpl sProvider(chip::app::TestGroups::kMaxGroupsPerFabric, chip::app::TestGroups::kMaxGroupKeysPerFabric); static EpochKey kEpochKeys0[] = { @@ -1228,6 +1230,7 @@ int Test_Setup(void * inContext) // Initialize Group Data Provider sProvider.SetStorageDelegate(&sDelegate); + sProvider.SetSessionKeystore(&sSessionKeystore); sProvider.SetListener(&chip::app::TestGroups::sListener); VerifyOrReturnError(CHIP_NO_ERROR == sProvider.Init(), FAILURE); SetGroupDataProvider(&sProvider); diff --git a/src/crypto/BUILD.gn b/src/crypto/BUILD.gn index bcf20280c0551e..d97c89737c15bc 100644 --- a/src/crypto/BUILD.gn +++ b/src/crypto/BUILD.gn @@ -69,6 +69,7 @@ source_set("public_headers") { sources = [ "CHIPCryptoPAL.h", "OperationalKeystore.h", + "SessionKeystore.h", ] public_deps = [ @@ -126,9 +127,7 @@ if (chip_crypto == "openssl") { ] public_deps = [ ":public_headers" ] - external_mbedtls = current_os == "zephyr" - - if (!external_mbedtls) { + if (!chip_external_mbedtls) { public_deps += [ "${mbedtls_root}:mbedtls" ] } } @@ -139,12 +138,25 @@ static_library("crypto") { sources = [ "CHIPCryptoPAL.cpp", + "DefaultSessionKeystore.h", "PersistentStorageOperationalKeystore.cpp", "PersistentStorageOperationalKeystore.h", "RandUtils.cpp", "RandUtils.h", ] + if (chip_crypto == "psa") { + sources += [ + "PSASessionKeystore.cpp", + "PSASessionKeystore.h", + ] + } else { + sources += [ + "RawKeySessionKeystore.cpp", + "RawKeySessionKeystore.h", + ] + } + public_configs = [] cflags = [ "-Wconversion" ] diff --git a/src/crypto/CHIPCryptoPAL.cpp b/src/crypto/CHIPCryptoPAL.cpp index ca15a30b9cf33c..69c3f575867ab6 100644 --- a/src/crypto/CHIPCryptoPAL.cpp +++ b/src/crypto/CHIPCryptoPAL.cpp @@ -706,14 +706,14 @@ CHIP_ERROR EcdsaAsn1SignatureToRaw(size_t fe_length_bytes, const ByteSpan & asn1 return CHIP_NO_ERROR; } -CHIP_ERROR AES_CTR_crypt(const uint8_t * input, size_t input_length, const uint8_t * key, size_t key_length, const uint8_t * nonce, +CHIP_ERROR AES_CTR_crypt(const uint8_t * input, size_t input_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * output) { // Discard tag portion of CCM to apply only CTR mode encryption/decryption. constexpr size_t kTagLen = Crypto::kAES_CCM128_Tag_Length; uint8_t tag[kTagLen]; - return AES_CCM_encrypt(input, input_length, nullptr, 0, key, key_length, nonce, nonce_length, output, tag, kTagLen); + return AES_CCM_encrypt(input, input_length, nullptr, 0, key, nonce, nonce_length, output, tag, kTagLen); } CHIP_ERROR GenerateCompressedFabricId(const Crypto::P256PublicKey & root_public_key, uint64_t fabric_id, diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 7a5cb1f191d706..6df3dc3a631572 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -345,6 +346,11 @@ class SensitiveDataFixedBuffer */ FixedByteSpan Span() const { return FixedByteSpan(mBytes); } + /** + * @brief Returns capacity of the buffer + */ + static constexpr size_t Capacity() { return kCapacity; } + private: uint8_t mBytes[kCapacity]; }; @@ -355,6 +361,8 @@ using P256ECDHDerivedSecret = SensitiveDataBuffer; using IdentityProtectionKey = SensitiveDataFixedBuffer; using IdentityProtectionKeySpan = FixedByteSpan; +using AttestationChallenge = SensitiveDataFixedBuffer; + class P256PublicKey : public ECPKey { public: @@ -541,6 +549,54 @@ class P256Keypair : public P256KeypairBase bool mInitialized = false; }; +using Aes128KeyByteArray = uint8_t[CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES]; + +/** + * @brief Platform-specific AES key + * + * The class represents AES key used by Matter stack either in the form of raw key material or key + * reference, depending on the platform. To achieve that, it contains an opaque context that can be + * cast to a concrete representation used by the given platform. Note that currently Matter uses + * 128-bit symmetric keys only. + */ +class Aes128KeyHandle +{ +public: + Aes128KeyHandle() = default; + ~Aes128KeyHandle() { ClearSecretData(mContext.mOpaque); } + + Aes128KeyHandle(const Aes128KeyHandle &) = delete; + Aes128KeyHandle(Aes128KeyHandle &&) = delete; + void operator=(const Aes128KeyHandle &) = delete; + void operator=(Aes128KeyHandle &&) = delete; + + /** + * @brief Get internal context cast to the desired key representation + */ + template + const T & As() const + { + return *SafePointerCast(&mContext); + } + + /** + * @brief Get internal context cast to the desired, mutable key representation + */ + template + T & AsMutable() + { + return *SafePointerCast(&mContext); + } + +private: + static constexpr size_t kContextSize = CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES; + + struct alignas(uintptr_t) OpaqueContext + { + uint8_t mOpaque[kContextSize] = {}; + } mContext; +}; + /** * @brief Convert a raw ECDSA signature to ASN.1 signature (per X9.62) as used by TLS libraries. * @@ -612,7 +668,6 @@ CHIP_ERROR ConvertIntegerRawToDerWithoutTag(const ByteSpan & raw_integer, Mutabl * @param aad Additional authentication data * @param aad_length Length of additional authentication data * @param key Encryption key - * @param key_length Length of encryption key (in bytes) * @param nonce Encryption nonce * @param nonce_length Length of encryption nonce * @param ciphertext Buffer to write ciphertext into. Caller must ensure this is large enough to hold the ciphertext @@ -621,7 +676,7 @@ CHIP_ERROR ConvertIntegerRawToDerWithoutTag(const ByteSpan & raw_integer, Mutabl * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise * */ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, - const uint8_t * key, size_t key_length, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, + const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, uint8_t * tag, size_t tag_length); /** @@ -639,14 +694,13 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c * @param tag Tag to use to decrypt * @param tag_length Length of tag * @param key Decryption key - * @param key_length Length of Decryption key (in bytes) * @param nonce Encryption nonce * @param nonce_length Length of encryption nonce * @param plaintext Buffer to write plaintext into * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length, const uint8_t * aad, size_t aad_length, - const uint8_t * tag, size_t tag_length, const uint8_t * key, size_t key_length, const uint8_t * nonce, + const uint8_t * tag, size_t tag_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * plaintext); /** @@ -660,13 +714,12 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length, * @param input Input text to encrypt/decrypt * @param input_length Length of ciphertext * @param key Decryption key - * @param key_length Length of Decryption key (in bytes) * @param nonce Encryption nonce * @param nonce_length Length of encryption nonce * @param output Buffer to write output into * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ -CHIP_ERROR AES_CTR_crypt(const uint8_t * input, size_t input_length, const uint8_t * key, size_t key_length, const uint8_t * nonce, +CHIP_ERROR AES_CTR_crypt(const uint8_t * input, size_t input_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * output); /** diff --git a/src/crypto/CHIPCryptoPALOpenSSL.cpp b/src/crypto/CHIPCryptoPALOpenSSL.cpp index f914b2a59b742e..ad3180447e8022 100644 --- a/src/crypto/CHIPCryptoPALOpenSSL.cpp +++ b/src/crypto/CHIPCryptoPALOpenSSL.cpp @@ -147,7 +147,7 @@ static int _compareDaysAndSeconds(const int days, const int seconds) } CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, - const uint8_t * key, size_t key_length, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, + const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, uint8_t * tag, size_t tag_length) { #if CHIP_CRYPTO_BORINGSSL @@ -187,12 +187,9 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c } } - VerifyOrExit(key_length == kAES_CCM128_Key_Length, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit((plaintext_length != 0) || ciphertext_was_null, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(plaintext != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(ciphertext != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key_length == kAES_CCM128_Key_Length, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(CanCastTo(nonce_length), error = CHIP_ERROR_INVALID_ARGUMENT); @@ -207,7 +204,7 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c #if CHIP_CRYPTO_BORINGSSL aead = EVP_aead_aes_128_ccm_matter(); - context = EVP_AEAD_CTX_new(aead, Uint8::to_const_uchar(key), key_length, tag_length); + context = EVP_AEAD_CTX_new(aead, key.As(), sizeof(Aes128KeyByteArray), tag_length); VerifyOrExit(context != nullptr, error = CHIP_ERROR_NO_MEMORY); result = EVP_AEAD_CTX_seal_scatter(context, ciphertext, tag, &written_tag_len, tag_length, nonce, nonce_length, plaintext, @@ -234,7 +231,8 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL); // Pass in key + nonce - result = EVP_EncryptInit_ex(context, nullptr, nullptr, Uint8::to_const_uchar(key), Uint8::to_const_uchar(nonce)); + static_assert(kAES_CCM128_Key_Length == sizeof(Aes128KeyByteArray), "Unexpected key length"); + result = EVP_EncryptInit_ex(context, nullptr, nullptr, key.As(), Uint8::to_const_uchar(nonce)); VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL); // Pass in plain text length @@ -284,7 +282,7 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c } CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length, const uint8_t * aad, size_t aad_length, - const uint8_t * tag, size_t tag_length, const uint8_t * key, size_t key_length, const uint8_t * nonce, + const uint8_t * tag, size_t tag_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * plaintext) { #if CHIP_CRYPTO_BORINGSSL @@ -332,15 +330,13 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length, VerifyOrExit(tag_length == 8 || tag_length == 12 || tag_length == CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, error = CHIP_ERROR_INVALID_ARGUMENT); #endif // CHIP_CRYPTO_BORINGSSL - VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key_length == kAES_CCM128_Key_Length, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); #if CHIP_CRYPTO_BORINGSSL aead = EVP_aead_aes_128_ccm_matter(); - context = EVP_AEAD_CTX_new(aead, Uint8::to_const_uchar(key), key_length, tag_length); + context = EVP_AEAD_CTX_new(aead, key.As(), sizeof(Aes128KeyByteArray), tag_length); VerifyOrExit(context != nullptr, error = CHIP_ERROR_NO_MEMORY); result = EVP_AEAD_CTX_open_gather(context, plaintext, nonce, nonce_length, ciphertext, ciphertext_length, tag, tag_length, aad, @@ -370,7 +366,8 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length, VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL); // Pass in key + nonce - result = EVP_DecryptInit_ex(context, nullptr, nullptr, Uint8::to_const_uchar(key), Uint8::to_const_uchar(nonce)); + static_assert(kAES_CCM128_Key_Length == sizeof(Aes128KeyByteArray), "Unexpected key length"); + result = EVP_DecryptInit_ex(context, nullptr, nullptr, key.As(), Uint8::to_const_uchar(nonce)); VerifyOrExit(result == 1, error = CHIP_ERROR_INTERNAL); // Pass in cipher text length diff --git a/src/crypto/CHIPCryptoPALPSA.cpp b/src/crypto/CHIPCryptoPALPSA.cpp index 1a063a97cb7cee..3fc7c31e5dd4f2 100644 --- a/src/crypto/CHIPCryptoPALPSA.cpp +++ b/src/crypto/CHIPCryptoPALPSA.cpp @@ -107,112 +107,82 @@ bool isValidTag(const uint8_t * tag, size_t tag_length) } // namespace CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, - const uint8_t * key, size_t key_length, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, + const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, uint8_t * tag, size_t tag_length) { - VerifyOrReturnError(isBufferNonEmpty(key, key_length), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(isBufferNonEmpty(nonce, nonce_length), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(isValidTag(tag, tag_length), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError((ciphertext != nullptr && plaintext != nullptr) || plaintext_length == 0, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(aad != nullptr || aad_length == 0, CHIP_ERROR_INVALID_ARGUMENT); const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length); - CHIP_ERROR error = CHIP_NO_ERROR; psa_status_t status = PSA_SUCCESS; - psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT; - psa_key_id_t keyId = 0; psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; size_t out_length; size_t tag_out_length; - psa_set_key_type(&attrs, PSA_KEY_TYPE_AES); - psa_set_key_algorithm(&attrs, algorithm); - psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_ENCRYPT); - - status = psa_import_key(&attrs, key, key_length, &keyId); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - - status = psa_aead_encrypt_setup(&operation, keyId, algorithm); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_aead_encrypt_setup(&operation, key.As(), algorithm); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); status = psa_aead_set_lengths(&operation, aad_length, plaintext_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); status = psa_aead_set_nonce(&operation, nonce, nonce_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); status = psa_aead_update_ad(&operation, aad, aad_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); status = psa_aead_update(&operation, plaintext, plaintext_length, ciphertext, PSA_AEAD_UPDATE_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm, plaintext_length), &out_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); ciphertext += out_length; status = psa_aead_finish(&operation, ciphertext, PSA_AEAD_FINISH_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm), &out_length, tag, tag_length, &tag_out_length); - VerifyOrExit(status == PSA_SUCCESS && tag_length == tag_out_length, error = CHIP_ERROR_INTERNAL); - -exit: - psa_destroy_key(keyId); - psa_reset_key_attributes(&attrs); + VerifyOrReturnError(status == PSA_SUCCESS && tag_length == tag_out_length, CHIP_ERROR_INTERNAL); - return error; + return CHIP_NO_ERROR; } CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length, const uint8_t * aad, size_t aad_length, - const uint8_t * tag, size_t tag_length, const uint8_t * key, size_t key_length, const uint8_t * nonce, + const uint8_t * tag, size_t tag_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * plaintext) { - VerifyOrReturnError(isBufferNonEmpty(key, key_length), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(isBufferNonEmpty(nonce, nonce_length), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(isValidTag(tag, tag_length), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError((ciphertext != nullptr && plaintext != nullptr) || ciphertext_length == 0, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(aad != nullptr || aad_length == 0, CHIP_ERROR_INVALID_ARGUMENT); const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length); - CHIP_ERROR error = CHIP_NO_ERROR; psa_status_t status = PSA_SUCCESS; - psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT; - psa_key_id_t keyId = 0; psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; size_t outLength; - psa_set_key_type(&attrs, PSA_KEY_TYPE_AES); - psa_set_key_algorithm(&attrs, algorithm); - psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_DECRYPT); - - status = psa_import_key(&attrs, key, key_length, &keyId); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - - status = psa_aead_decrypt_setup(&operation, keyId, algorithm); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_aead_decrypt_setup(&operation, key.As(), algorithm); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); status = psa_aead_set_lengths(&operation, aad_length, ciphertext_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); status = psa_aead_set_nonce(&operation, nonce, nonce_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); status = psa_aead_update_ad(&operation, aad, aad_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); status = psa_aead_update(&operation, ciphertext, ciphertext_length, plaintext, PSA_AEAD_UPDATE_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm, ciphertext_length), &outLength); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); plaintext += outLength; status = psa_aead_verify(&operation, plaintext, PSA_AEAD_VERIFY_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm), &outLength, tag, tag_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - -exit: - psa_destroy_key(keyId); - psa_reset_key_attributes(&attrs); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - return error; + return CHIP_NO_ERROR; } CHIP_ERROR Hash_SHA256(const uint8_t * data, const size_t data_length, uint8_t * out_buffer) @@ -310,40 +280,67 @@ void Hash_SHA256_stream::Clear() psa_hash_abort(toHashOperation(&mContext)); } -CHIP_ERROR HKDF_sha::HKDF_SHA256(const uint8_t * secret, const size_t secret_length, const uint8_t * salt, const size_t salt_length, - const uint8_t * info, const size_t info_length, uint8_t * out_buffer, size_t out_length) +CHIP_ERROR PsaKdf::Init(psa_algorithm_t algorithm, const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info) { - VerifyOrReturnError(isBufferNonEmpty(secret, secret_length), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(isBufferNonEmpty(info, info_length), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(isBufferNonEmpty(out_buffer, out_length), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(salt != nullptr || salt_length == 0, CHIP_ERROR_INVALID_ARGUMENT); + psa_status_t status = PSA_SUCCESS; + psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT; - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_SUCCESS; - psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; + psa_set_key_type(&attrs, PSA_KEY_TYPE_DERIVE); + psa_set_key_algorithm(&attrs, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_DERIVE); - status = psa_key_derivation_setup(&operation, PSA_ALG_HKDF(PSA_ALG_SHA_256)); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_import_key(&attrs, secret.data(), secret.size(), &mSecretKeyId); + psa_reset_key_attributes(&attrs); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + status = psa_key_derivation_setup(&mOperation, algorithm); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - if (salt_length > 0) + if (salt.size() > 0) { - status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, salt, salt_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_SALT, salt.data(), salt.size()); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); } - status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SECRET, secret, secret_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_key_derivation_input_key(&mOperation, PSA_KEY_DERIVATION_INPUT_SECRET, mSecretKeyId); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_INFO, info, info_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_INFO, info.data(), info.size()); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - status = psa_key_derivation_output_bytes(&operation, out_buffer, out_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + return CHIP_NO_ERROR; +} -exit: - psa_key_derivation_abort(&operation); +CHIP_ERROR PsaKdf::DeriveBytes(const MutableByteSpan & output) +{ + psa_status_t status = psa_key_derivation_output_bytes(&mOperation, output.data(), output.size()); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - return error; + return CHIP_NO_ERROR; +} + +CHIP_ERROR PsaKdf::DeriveKey(const psa_key_attributes_t & attributes, psa_key_id_t & keyId) +{ + psa_status_t status = psa_key_derivation_output_key(&attributes, &mOperation, &keyId); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR HKDF_sha::HKDF_SHA256(const uint8_t * secret, const size_t secret_length, const uint8_t * salt, const size_t salt_length, + const uint8_t * info, const size_t info_length, uint8_t * out_buffer, size_t out_length) +{ + VerifyOrReturnError(isBufferNonEmpty(secret, secret_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(isBufferNonEmpty(info, info_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(isBufferNonEmpty(out_buffer, out_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(salt != nullptr || salt_length == 0, CHIP_ERROR_INVALID_ARGUMENT); + + PsaKdf kdf; + + ReturnErrorOnFailure(kdf.Init(PSA_ALG_HKDF(PSA_ALG_SHA_256), ByteSpan(secret, secret_length), ByteSpan(salt, salt_length), + ByteSpan(info, info_length))); + + return kdf.DeriveBytes(MutableByteSpan(out_buffer, out_length)); } CHIP_ERROR HMAC_sha::HMAC_SHA256(const uint8_t * key, size_t key_length, const uint8_t * message, size_t message_length, @@ -508,7 +505,7 @@ CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_len CHIP_ERROR error = CHIP_NO_ERROR; psa_status_t status = PSA_SUCCESS; size_t outputLen = 0; - const PSAP256KeypairContext & context = toConstPSAContext(mKeypair); + const PsaP256KeypairContext & context = ToConstPsaContext(mKeypair); status = psa_sign_message(context.key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256), msg, msg_length, out_signature.Bytes(), out_signature.Capacity(), &outputLen); @@ -585,7 +582,7 @@ CHIP_ERROR P256Keypair::ECDH_derive_secret(const P256PublicKey & remote_public_k CHIP_ERROR error = CHIP_NO_ERROR; psa_status_t status = PSA_SUCCESS; - const PSAP256KeypairContext & context = toConstPSAContext(mKeypair); + const PsaP256KeypairContext & context = ToConstPsaContext(mKeypair); const size_t outputSize = (out_secret.Length() == 0) ? out_secret.Capacity() : out_secret.Length(); size_t outputLength; @@ -638,7 +635,7 @@ CHIP_ERROR P256Keypair::Initialize(ECPKeyTarget key_target) CHIP_ERROR error = CHIP_NO_ERROR; psa_status_t status = PSA_SUCCESS; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - PSAP256KeypairContext & context = toPSAContext(mKeypair); + PsaP256KeypairContext & context = ToPsaContext(mKeypair); size_t publicKeyLength = 0; // Type based on ECC with the elliptic curve SECP256r1 -> PSA_ECC_FAMILY_SECP_R1 @@ -680,7 +677,7 @@ CHIP_ERROR P256Keypair::Serialize(P256SerializedKeypair & output) const { CHIP_ERROR error = CHIP_NO_ERROR; psa_status_t status = PSA_SUCCESS; - const PSAP256KeypairContext & context = toConstPSAContext(mKeypair); + const PsaP256KeypairContext & context = ToConstPsaContext(mKeypair); const size_t outputSize = output.Length() == 0 ? output.Capacity() : output.Length(); Encoding::BufferWriter bbuf(output.Bytes(), outputSize); uint8_t privateKey[kP256_PrivateKey_Length]; @@ -708,7 +705,7 @@ CHIP_ERROR P256Keypair::Deserialize(P256SerializedKeypair & input) CHIP_ERROR error = CHIP_NO_ERROR; psa_status_t status = PSA_SUCCESS; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - PSAP256KeypairContext & context = toPSAContext(mKeypair); + PsaP256KeypairContext & context = ToPsaContext(mKeypair); Encoding::BufferWriter bbuf(mPublicKey, mPublicKey.Length()); Clear(); @@ -736,7 +733,7 @@ void P256Keypair::Clear() { if (mInitialized) { - PSAP256KeypairContext & context = toPSAContext(mKeypair); + PsaP256KeypairContext & context = ToPsaContext(mKeypair); psa_destroy_key(context.key_id); memset(&context, 0, sizeof(context)); mInitialized = false; @@ -1710,5 +1707,84 @@ CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCe return error; } +namespace { + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +CHIP_ERROR ExtractRawSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + uint8_t * p = nullptr; + size_t len = 0; + mbedtls_x509_crt mbedCertificate; + + ReturnErrorCodeIf(certificate.empty(), CHIP_ERROR_INVALID_ARGUMENT); + + mbedtls_x509_crt_init(&mbedCertificate); + result = mbedtls_x509_crt_parse(&mbedCertificate, Uint8::to_const_uchar(certificate.data()), certificate.size()); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); + p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); + + VerifyOrExit(len <= subject.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(subject.data(), p, len); + subject.reduce_size(len); + +exit: + logMbedTLSError(result); + mbedtls_x509_crt_free(&mbedCertificate); + + return error; +} +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) + +} // namespace + +CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, const ByteSpan * candidateCertificates, + size_t candidateCertificatesCount, ByteSpan & outCertificate) +{ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + constexpr size_t kMaxCertificateSubjectLength = 150; + uint8_t referenceSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t referenceSKIDBuf[kSubjectKeyIdentifierLength]; + MutableByteSpan referenceSubject(referenceSubjectBuf); + MutableByteSpan referenceSKID(referenceSKIDBuf); + + outCertificate = referenceCertificate; + + ReturnErrorCodeIf(candidateCertificates == nullptr || candidateCertificatesCount == 0, CHIP_NO_ERROR); + + ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(referenceCertificate, referenceSubject)); + ReturnErrorOnFailure(ExtractSKIDFromX509Cert(referenceCertificate, referenceSKID)); + + for (size_t i = 0; i < candidateCertificatesCount; i++) + { + const ByteSpan candidateCertificate = candidateCertificates[i]; + uint8_t candidateSubjectBuf[kMaxCertificateSubjectLength]; + uint8_t candidateSKIDBuf[kSubjectKeyIdentifierLength]; + MutableByteSpan candidateSubject(candidateSubjectBuf); + MutableByteSpan candidateSKID(candidateSKIDBuf); + + ReturnErrorOnFailure(ExtractRawSubjectFromX509Cert(candidateCertificate, candidateSubject)); + ReturnErrorOnFailure(ExtractSKIDFromX509Cert(candidateCertificate, candidateSKID)); + + if (referenceSKID.data_equal(candidateSKID) && referenceSubject.data_equal(candidateSubject)) + { + outCertificate = candidateCertificate; + return CHIP_NO_ERROR; + } + } + + return CHIP_NO_ERROR; +#else + (void) referenceCertificate; + (void) candidateCertificates; + (void) candidateCertificatesCount; + (void) outCertificate; + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif // defined(MBEDTLS_X509_CRT_PARSE_C) +} + } // namespace Crypto } // namespace chip diff --git a/src/crypto/CHIPCryptoPALPSA.h b/src/crypto/CHIPCryptoPALPSA.h index 6774cef7622378..1a64c1f8794dfa 100644 --- a/src/crypto/CHIPCryptoPALPSA.h +++ b/src/crypto/CHIPCryptoPALPSA.h @@ -16,6 +16,14 @@ * limitations under the License. */ +/** + * @file + * Header file that contains private definitions used by PSA crypto backend. + * + * This file should not be included directly by the application. Instead, use + * cryptographic primitives defined in CHIPCryptoPAL.h or SessionKeystore.h. + */ + #pragma once #include "CHIPCryptoPAL.h" @@ -28,54 +36,112 @@ namespace chip { namespace Crypto { /** - * @def CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE + * @def CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE * - * @brief - * Base for PSA key identifier range used by Matter. + * @brief + * Base of the PSA key identifier range used by Matter. * - * Cryptographic keys stored in the PSA Internal Trusted Storage must have - * a user-assigned identifer from the range PSA_KEY_ID_USER_MIN to - * PSA_KEY_ID_USER_MAX. This option allows to override the base used to derive - * key identifiers used by Matter to avoid overlapping with other firmware - * components that also use PSA crypto API. The default value was selected - * not to interfere with OpenThread's default base that is 0x20000. + * Cryptographic keys stored in the PSA Internal Trusted Storage must have + * a user-assigned identifer from the range PSA_KEY_ID_USER_MIN to + * PSA_KEY_ID_USER_MAX. This option allows to override the base used to derive + * key identifiers used by Matter to avoid overlapping with other firmware + * components that also use PSA crypto API. The default value was selected + * not to interfere with OpenThread's default base that is 0x20000. * - * Note that volatile keys like ephemeral keys used for ECDH have identifiers - * auto-assigned by the PSA backend. + * Note that volatile keys like ephemeral keys used for ECDH have identifiers + * auto-assigned by the PSA backend. */ #ifndef CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE #define CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE 0x30000 #endif // CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE -static_assert(CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE >= PSA_KEY_ID_USER_MIN && - CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE <= PSA_KEY_ID_USER_MAX, - "PSA key ID base out of allowed range"); - +/** + * @brief Defines subranges of the PSA key identifier space used by Matter. + */ enum class KeyIdBase : psa_key_id_t { - // Define key ID range for Node Operational Certificate private keys - Operational = CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE + Minimum = CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE, + Operational = Minimum, ///< Base of the PSA key ID range for Node Operational Certificate private keys + Maximum = Operational + kMaxValidFabricIndex, }; +static_assert(to_underlying(KeyIdBase::Minimum) >= PSA_KEY_ID_USER_MIN && to_underlying(KeyIdBase::Maximum) <= PSA_KEY_ID_USER_MAX, + "PSA key ID base out of allowed range"); + +/** + * @brief Calculates PSA key ID for Node Operational Certificate private key for the given fabric. + */ constexpr psa_key_id_t MakeOperationalKeyId(FabricIndex fabricIndex) { return to_underlying(KeyIdBase::Operational) + static_cast(fabricIndex); } -struct PSAP256KeypairContext +/** + * @brief Concrete P256 keypair context used by PSA crypto backend. + */ +struct PsaP256KeypairContext { psa_key_id_t key_id; }; -static inline PSAP256KeypairContext & toPSAContext(P256KeypairContext & context) +inline PsaP256KeypairContext & ToPsaContext(P256KeypairContext & context) { - return *SafePointerCast(&context); + return *SafePointerCast(&context); } -static inline const PSAP256KeypairContext & toConstPSAContext(const P256KeypairContext & context) +inline const PsaP256KeypairContext & ToConstPsaContext(const P256KeypairContext & context) { - return *SafePointerCast(&context); + return *SafePointerCast(&context); } +/** + * @brief Wrapper for PSA key derivation API. + */ +class PsaKdf +{ +public: + ~PsaKdf() + { + psa_key_derivation_abort(&mOperation); + psa_destroy_key(mSecretKeyId); + } + + /** + * @brief Initializes the key derivation operation. + */ + CHIP_ERROR Init(psa_algorithm_t algorithm, const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info); + + /** + * @brief Derives raw key material from the operation. + * + * This method together with @p DeriveKeys can be called multiple times to + * derive several keys. + * + * @param[out] output Span that provides location and length for the derived key material. + * + * @retval CHIP_NO_ERROR On success. + * @retval CHIP_ERROR_INTERNAL On PSA crypto API error. + */ + CHIP_ERROR DeriveBytes(const MutableByteSpan & output); + + /** + * @brief Derives a key from the operation. + * + * This method together with @p DeriveBytes can be called multiple times to + * derive several keys. + * + * @param[in] attributes Attributes of the derived key. + * @param[out] keyId PSA key ID of the derived key. + * + * @retval CHIP_NO_ERROR On success. + * @retval CHIP_ERROR_INTERNAL On PSA crypto API error. + */ + CHIP_ERROR DeriveKey(const psa_key_attributes_t & attributes, psa_key_id_t & keyId); + +private: + psa_key_id_t mSecretKeyId = 0; + psa_key_derivation_operation_t mOperation = PSA_KEY_DERIVATION_OPERATION_INIT; +}; + } // namespace Crypto } // namespace chip diff --git a/src/crypto/CHIPCryptoPALmbedTLS.cpp b/src/crypto/CHIPCryptoPALmbedTLS.cpp index 95c44e43a0241c..324f9a3aca442a 100644 --- a/src/crypto/CHIPCryptoPALmbedTLS.cpp +++ b/src/crypto/CHIPCryptoPALmbedTLS.cpp @@ -108,18 +108,8 @@ static bool _isValidTagLength(size_t tag_length) return false; } -static bool _isValidKeyLength(size_t length) -{ - // 16 bytes key for AES-CCM-128, 32 for AES-CCM-256 - if (length == 16 || length == 32) - { - return true; - } - return false; -} - CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, - const uint8_t * key, size_t key_length, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, + const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, uint8_t * tag, size_t tag_length) { CHIP_ERROR error = CHIP_NO_ERROR; @@ -130,8 +120,6 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c VerifyOrExit(plaintext != nullptr || plaintext_length == 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(ciphertext != nullptr || plaintext_length == 0, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(_isValidKeyLength(key_length), error = CHIP_ERROR_UNSUPPORTED_ENCRYPTION_TYPE); VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); @@ -141,10 +129,8 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c VerifyOrExit(aad != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); } - // Size of key = key_length * number of bits in a byte (8) - // Cast is safe because we called _isValidKeyLength above. - result = - mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, Uint8::to_const_uchar(key), static_cast(key_length * 8)); + // Size of key is expressed in bits, hence the multiplication by 8. + result = mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, key.As(), sizeof(Aes128KeyByteArray) * 8); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); // Encrypt @@ -160,7 +146,7 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c } CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, const uint8_t * aad, size_t aad_len, - const uint8_t * tag, size_t tag_length, const uint8_t * key, size_t key_length, const uint8_t * nonce, + const uint8_t * tag, size_t tag_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * plaintext) { CHIP_ERROR error = CHIP_NO_ERROR; @@ -173,8 +159,6 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, co VerifyOrExit(ciphertext != nullptr || ciphertext_len == 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(_isValidKeyLength(key_length), error = CHIP_ERROR_UNSUPPORTED_ENCRYPTION_TYPE); VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); if (aad_len > 0) @@ -182,10 +166,8 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, co VerifyOrExit(aad != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); } - // Size of key = key_length * number of bits in a byte (8) - // Cast is safe because we called _isValidKeyLength above. - result = - mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, Uint8::to_const_uchar(key), static_cast(key_length * 8)); + // Size of key is expressed in bits, hence the multiplication by 8. + result = mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, key.As(), sizeof(Aes128KeyByteArray) * 8); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); // Decrypt diff --git a/src/crypto/DefaultSessionKeystore.h b/src/crypto/DefaultSessionKeystore.h new file mode 100644 index 00000000000000..8fa6121af5c20d --- /dev/null +++ b/src/crypto/DefaultSessionKeystore.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#if CHIP_HAVE_CONFIG_H +#include +#endif + +#if CHIP_CRYPTO_PSA +#include +#else +#include +#endif + +namespace chip { +namespace Crypto { + +// Define DefaultSessionKeystore type alias to reduce boilerplate code related to the fact that +// when the PSA crypto backend is used, AES encryption/decryption function assume that the input +// key handle carries a key reference instead of raw key material, so PSASessionKeystore must be +// used instead of RawKeySessionKeystore to initialize the key handle. +#if CHIP_CRYPTO_PSA +using DefaultSessionKeystore = PSASessionKeystore; +#else +using DefaultSessionKeystore = RawKeySessionKeystore; +#endif + +} // namespace Crypto +} // namespace chip diff --git a/src/crypto/PSAOperationalKeystore.cpp b/src/crypto/PSAOperationalKeystore.cpp index ccde8d1d9eb667..980994696e3047 100644 --- a/src/crypto/PSAOperationalKeystore.cpp +++ b/src/crypto/PSAOperationalKeystore.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Project CHIP Authors + * Copyright (c) 2023 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,7 +26,7 @@ namespace Crypto { PSAOperationalKeystore::PersistentP256Keypair::PersistentP256Keypair(FabricIndex fabricIndex) { - toPSAContext(mKeypair).key_id = MakeOperationalKeyId(fabricIndex); + ToPsaContext(mKeypair).key_id = MakeOperationalKeyId(fabricIndex); mInitialized = true; } @@ -34,12 +34,12 @@ PSAOperationalKeystore::PersistentP256Keypair::~PersistentP256Keypair() { // This class requires explicit control of the key lifetime. Therefore, clear the key ID // to prevent it from being destroyed by the base class destructor. - toPSAContext(mKeypair).key_id = 0; + ToPsaContext(mKeypair).key_id = 0; } inline psa_key_id_t PSAOperationalKeystore::PersistentP256Keypair::GetKeyId() const { - return toConstPSAContext(mKeypair).key_id; + return ToConstPsaContext(mKeypair).key_id; } bool PSAOperationalKeystore::PersistentP256Keypair::Exists() const diff --git a/src/crypto/PSAOperationalKeystore.h b/src/crypto/PSAOperationalKeystore.h index a0937c257e2ca8..89c3edc7fe7607 100644 --- a/src/crypto/PSAOperationalKeystore.h +++ b/src/crypto/PSAOperationalKeystore.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Project CHIP Authors + * Copyright (c) 2023 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/crypto/PSASessionKeystore.cpp b/src/crypto/PSASessionKeystore.cpp new file mode 100644 index 00000000000000..0b8a237a9d405b --- /dev/null +++ b/src/crypto/PSASessionKeystore.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PSASessionKeystore.h" + +#include + +#include + +namespace chip { +namespace Crypto { + +namespace { + +class AesKeyAttributes +{ +public: + AesKeyAttributes() + { + constexpr psa_algorithm_t kAlgorithm = PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8); + + psa_set_key_type(&mAttrs, PSA_KEY_TYPE_AES); + psa_set_key_algorithm(&mAttrs, kAlgorithm); + psa_set_key_usage_flags(&mAttrs, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_bits(&mAttrs, CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES * 8); + } + + ~AesKeyAttributes() { psa_reset_key_attributes(&mAttrs); } + + const psa_key_attributes_t & Get() { return mAttrs; } + +private: + psa_key_attributes_t mAttrs = PSA_KEY_ATTRIBUTES_INIT; +}; + +} // namespace + +CHIP_ERROR PSASessionKeystore::CreateKey(const Aes128KeyByteArray & keyMaterial, Aes128KeyHandle & key) +{ + // Destroy the old key if already allocated + psa_destroy_key(key.As()); + + AesKeyAttributes attrs; + psa_status_t status = psa_import_key(&attrs.Get(), keyMaterial, sizeof(Aes128KeyByteArray), &key.AsMutable()); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PSASessionKeystore::DeriveKey(const P256ECDHDerivedSecret & secret, const ByteSpan & salt, const ByteSpan & info, + Aes128KeyHandle & key) +{ + PsaKdf kdf; + ReturnErrorOnFailure(kdf.Init(PSA_ALG_HKDF(PSA_ALG_SHA_256), secret.Span(), salt, info)); + + AesKeyAttributes attrs; + + return kdf.DeriveKey(attrs.Get(), key.AsMutable()); +} + +CHIP_ERROR PSASessionKeystore::DeriveSessionKeys(const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info, + Aes128KeyHandle & i2rKey, Aes128KeyHandle & r2iKey, + AttestationChallenge & attestationChallenge) +{ + PsaKdf kdf; + ReturnErrorOnFailure(kdf.Init(PSA_ALG_HKDF(PSA_ALG_SHA_256), secret, salt, info)); + + CHIP_ERROR error; + AesKeyAttributes attrs; + + SuccessOrExit(error = kdf.DeriveKey(attrs.Get(), i2rKey.AsMutable())); + SuccessOrExit(error = kdf.DeriveKey(attrs.Get(), r2iKey.AsMutable())); + SuccessOrExit(error = kdf.DeriveBytes(MutableByteSpan(attestationChallenge.Bytes(), AttestationChallenge::Capacity()))); + +exit: + if (error != CHIP_NO_ERROR) + { + DestroyKey(i2rKey); + DestroyKey(r2iKey); + } + + return error; +} + +void PSASessionKeystore::DestroyKey(Aes128KeyHandle & key) +{ + auto & keyId = key.AsMutable(); + + psa_destroy_key(keyId); + keyId = 0; +} + +} // namespace Crypto +} // namespace chip diff --git a/src/crypto/PSASessionKeystore.h b/src/crypto/PSASessionKeystore.h new file mode 100644 index 00000000000000..c448d7923a6575 --- /dev/null +++ b/src/crypto/PSASessionKeystore.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace chip { +namespace Crypto { + +class PSASessionKeystore : public SessionKeystore +{ +public: + CHIP_ERROR CreateKey(const Aes128KeyByteArray & keyMaterial, Aes128KeyHandle & key) override; + CHIP_ERROR DeriveKey(const P256ECDHDerivedSecret & secret, const ByteSpan & salt, const ByteSpan & info, + Aes128KeyHandle & key) override; + CHIP_ERROR DeriveSessionKeys(const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info, Aes128KeyHandle & i2rKey, + Aes128KeyHandle & r2iKey, AttestationChallenge & attestationChallenge) override; + void DestroyKey(Aes128KeyHandle & key) override; +}; + +} // namespace Crypto +} // namespace chip diff --git a/src/crypto/RawKeySessionKeystore.cpp b/src/crypto/RawKeySessionKeystore.cpp new file mode 100644 index 00000000000000..97666569345d04 --- /dev/null +++ b/src/crypto/RawKeySessionKeystore.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +namespace chip { +namespace Crypto { + +#ifdef ENABLE_HSM_HKDF +using HKDF_sha_crypto = HKDF_shaHSM; +#else +using HKDF_sha_crypto = HKDF_sha; +#endif + +CHIP_ERROR RawKeySessionKeystore::CreateKey(const Aes128KeyByteArray & keyMaterial, Aes128KeyHandle & key) +{ + memcpy(key.AsMutable(), keyMaterial, sizeof(Aes128KeyByteArray)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR RawKeySessionKeystore::DeriveKey(const P256ECDHDerivedSecret & secret, const ByteSpan & salt, const ByteSpan & info, + Aes128KeyHandle & key) +{ + HKDF_sha_crypto hkdf; + + return hkdf.HKDF_SHA256(secret.ConstBytes(), secret.Length(), salt.data(), salt.size(), info.data(), info.size(), + key.AsMutable(), sizeof(Aes128KeyByteArray)); +} + +CHIP_ERROR RawKeySessionKeystore::DeriveSessionKeys(const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info, + Aes128KeyHandle & i2rKey, Aes128KeyHandle & r2iKey, + AttestationChallenge & attestationChallenge) +{ + HKDF_sha_crypto hkdf; + uint8_t keyMaterial[2 * sizeof(Aes128KeyByteArray) + AttestationChallenge::Capacity()]; + + ReturnErrorOnFailure(hkdf.HKDF_SHA256(secret.data(), secret.size(), salt.data(), salt.size(), info.data(), info.size(), + keyMaterial, sizeof(keyMaterial))); + + Encoding::LittleEndian::Reader reader(keyMaterial, sizeof(keyMaterial)); + + return reader.ReadBytes(i2rKey.AsMutable(), sizeof(Aes128KeyByteArray)) + .ReadBytes(r2iKey.AsMutable(), sizeof(Aes128KeyByteArray)) + .ReadBytes(attestationChallenge.Bytes(), AttestationChallenge::Capacity()) + .StatusCode(); +} + +void RawKeySessionKeystore::DestroyKey(Aes128KeyHandle & key) +{ + ClearSecretData(key.AsMutable()); +} + +} // namespace Crypto +} // namespace chip diff --git a/src/crypto/RawKeySessionKeystore.h b/src/crypto/RawKeySessionKeystore.h new file mode 100644 index 00000000000000..c8db3eda069518 --- /dev/null +++ b/src/crypto/RawKeySessionKeystore.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace chip { +namespace Crypto { + +class RawKeySessionKeystore : public SessionKeystore +{ +public: + CHIP_ERROR CreateKey(const Aes128KeyByteArray & keyMaterial, Aes128KeyHandle & key) override; + CHIP_ERROR DeriveKey(const P256ECDHDerivedSecret & secret, const ByteSpan & salt, const ByteSpan & info, + Aes128KeyHandle & key) override; + CHIP_ERROR DeriveSessionKeys(const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info, Aes128KeyHandle & i2rKey, + Aes128KeyHandle & r2iKey, AttestationChallenge & attestationChallenge) override; + void DestroyKey(Aes128KeyHandle & key) override; +}; + +} // namespace Crypto +} // namespace chip diff --git a/src/crypto/SessionKeystore.h b/src/crypto/SessionKeystore.h new file mode 100644 index 00000000000000..edc31dc788dbea --- /dev/null +++ b/src/crypto/SessionKeystore.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace Crypto { + +/** + * @brief Interface for deriving session keys and managing their lifetime. + * + * The session keystore interface provides an abstraction that allows the application to store + * session keys in a secure environment. It uses the concept of key handles that isolate the + * application from the actual key material. + */ +class SessionKeystore +{ +public: + virtual ~SessionKeystore() {} + + /** + * @brief Import raw key material and return a key handle. + * + * @note This method should only be used when using the raw key material in the Matter stack + * cannot be avoided. Ideally, crypto interfaces should allow platforms to perform all the + * cryptographic operations in a secure environment. + * + * If the method returns no error, the application is responsible for destroying the handle + * using DestroyKey() method when the key is no longer needed. + */ + virtual CHIP_ERROR CreateKey(const Aes128KeyByteArray & keyMaterial, Aes128KeyHandle & key) = 0; + + /** + * @brief Derive key from a shared secret. + * + * Use HKDF as defined in the Matter specification to derive an AES key from the shared secret. + * + * If the method returns no error, the application is responsible for destroying the handle + * using DestroyKey() method when the key is no longer needed. + */ + virtual CHIP_ERROR DeriveKey(const P256ECDHDerivedSecret & secret, const ByteSpan & salt, const ByteSpan & info, + Aes128KeyHandle & key) = 0; + + /** + * @brief Derive session keys from a shared secret. + * + * Use HKDF as defined in the Matter specification to derive AES keys for both directions, and + * the attestation challenge from the shared secret. + * + * If the method returns no error, the application is responsible for destroying the handles + * using DestroyKey() method when the keys are no longer needed. On failure, the method must + * release all handles that it allocated so far. + */ + virtual CHIP_ERROR DeriveSessionKeys(const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info, + Aes128KeyHandle & i2rKey, Aes128KeyHandle & r2iKey, + AttestationChallenge & attestationChallenge) = 0; + + /** + * @brief Destroy key. + * + * The method can take an uninitialized handle in which case it is a no-op. + * As a result of calling this method, the handle is put in the uninitialized state. + */ + virtual void DestroyKey(Aes128KeyHandle & key) = 0; +}; + +/** + * @brief RAII class to hold a temporary key handle that is destroyed on scope exit. + */ +class AutoReleaseSessionKey +{ +public: + explicit AutoReleaseSessionKey(SessionKeystore & keystore) : mKeystore(keystore) {} + ~AutoReleaseSessionKey() { mKeystore.DestroyKey(mKeyHandle); } + + Aes128KeyHandle & KeyHandle() { return mKeyHandle; } + +private: + SessionKeystore & mKeystore; + Aes128KeyHandle mKeyHandle; +}; + +} // namespace Crypto +} // namespace chip diff --git a/src/crypto/tests/BUILD.gn b/src/crypto/tests/BUILD.gn index 7e41fe86fae985..ea3ee0dc124f5d 100644 --- a/src/crypto/tests/BUILD.gn +++ b/src/crypto/tests/BUILD.gn @@ -44,7 +44,10 @@ chip_test_suite("tests") { "TestCryptoLayer.h", ] - test_sources = [ "TestGroupOperationalCredentials.cpp" ] + test_sources = [ + "TestGroupOperationalCredentials.cpp", + "TestSessionKeystore.cpp", + ] if (chip_crypto == "psa") { test_sources += [ "TestPSAOpKeyStore.cpp" ] diff --git a/src/crypto/tests/CHIPCryptoPALTest.cpp b/src/crypto/tests/CHIPCryptoPALTest.cpp index ffbc72090f5beb..f8d4b476d719c4 100644 --- a/src/crypto/tests/CHIPCryptoPALTest.cpp +++ b/src/crypto/tests/CHIPCryptoPALTest.cpp @@ -36,6 +36,7 @@ #include "SPAKE2P_RFC_test_vectors.h" #include +#include #if CHIP_CRYPTO_HSM #include #endif @@ -165,6 +166,9 @@ static int test_entropy_source(void * data, uint8_t * output, size_t len, size_t return 0; } +constexpr size_t KEY_LENGTH = Crypto::kAES_CCM128_Key_Length; +constexpr size_t NONCE_LENGTH = Crypto::kAES_CCM128_Nonce_Length; + struct AesCtrTestEntry { const uint8_t * key; ///< Key to use for AES-CTR-128 encryption/decryption -- 16 byte length @@ -204,8 +208,23 @@ const AesCtrTestEntry theAesCtrTestVector[] = { } }; -constexpr size_t KEY_LENGTH = Crypto::kAES_CCM128_Key_Length; -constexpr size_t NONCE_LENGTH = Crypto::kAES_CCM128_Nonce_Length; +struct TestAesKey +{ +public: + TestAesKey(nlTestSuite * inSuite, const uint8_t * keyBytes, size_t keyLength) + { + Crypto::Aes128KeyByteArray keyMaterial; + memcpy(&keyMaterial, keyBytes, keyLength); + + CHIP_ERROR err = keystore.CreateKey(keyMaterial, key); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + } + + ~TestAesKey() { keystore.DestroyKey(key); } + + DefaultSessionKeystore keystore; + Aes128KeyHandle key; +}; static void TestAES_CTR_128_Encrypt(nlTestSuite * inSuite, const AesCtrTestEntry * vector) { @@ -213,8 +232,9 @@ static void TestAES_CTR_128_Encrypt(nlTestSuite * inSuite, const AesCtrTestEntry outBuffer.Alloc(vector->ciphertextLen); NL_TEST_ASSERT(inSuite, outBuffer); - CHIP_ERROR err = AES_CTR_crypt(vector->plaintext, vector->plaintextLen, vector->key, KEY_LENGTH, vector->nonce, NONCE_LENGTH, - outBuffer.Get()); + TestAesKey key(inSuite, vector->key, KEY_LENGTH); + + CHIP_ERROR err = AES_CTR_crypt(vector->plaintext, vector->plaintextLen, key.key, vector->nonce, NONCE_LENGTH, outBuffer.Get()); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); bool outputMatches = memcmp(outBuffer.Get(), vector->ciphertext, vector->ciphertextLen) == 0; @@ -231,8 +251,10 @@ static void TestAES_CTR_128_Decrypt(nlTestSuite * inSuite, const AesCtrTestEntry outBuffer.Alloc(vector->plaintextLen); NL_TEST_ASSERT(inSuite, outBuffer); - CHIP_ERROR err = AES_CTR_crypt(vector->ciphertext, vector->ciphertextLen, vector->key, KEY_LENGTH, vector->nonce, NONCE_LENGTH, - outBuffer.Get()); + TestAesKey key(inSuite, vector->key, KEY_LENGTH); + + CHIP_ERROR err = + AES_CTR_crypt(vector->ciphertext, vector->ciphertextLen, key.key, vector->nonce, NONCE_LENGTH, outBuffer.Get()); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); bool outputMatches = memcmp(outBuffer.Get(), vector->plaintext, vector->plaintextLen) == 0; @@ -277,8 +299,10 @@ static void TestAES_CCM_128EncryptTestVectors(nlTestSuite * inSuite, void * inCo out_tag.Alloc(vector->tag_len); NL_TEST_ASSERT(inSuite, out_tag); - CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, vector->key, vector->key_len, - vector->nonce, vector->nonce_len, out_ct.Get(), out_tag.Get(), vector->tag_len); + TestAesKey key(inSuite, vector->key, vector->key_len); + + CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, key.key, vector->nonce, + vector->nonce_len, out_ct.Get(), out_tag.Get(), vector->tag_len); NL_TEST_ASSERT(inSuite, err == vector->result); if (vector->result == CHIP_NO_ERROR) @@ -315,8 +339,11 @@ static void TestAES_CCM_128DecryptTestVectors(nlTestSuite * inSuite, void * inCo chip::Platform::ScopedMemoryBuffer out_pt; out_pt.Alloc(vector->pt_len); NL_TEST_ASSERT(inSuite, out_pt); + + TestAesKey key(inSuite, vector->key, vector->key_len); + CHIP_ERROR err = AES_CCM_decrypt(vector->ct, vector->ct_len, vector->aad, vector->aad_len, vector->tag, vector->tag_len, - vector->key, vector->key_len, vector->nonce, vector->nonce_len, out_pt.Get()); + key.key, vector->nonce, vector->nonce_len, out_pt.Get()); NL_TEST_ASSERT(inSuite, err == vector->result); if (vector->result == CHIP_NO_ERROR) @@ -333,33 +360,6 @@ static void TestAES_CCM_128DecryptTestVectors(nlTestSuite * inSuite, void * inCo NL_TEST_ASSERT(inSuite, numOfTestsRan > 0); } -static void TestAES_CCM_128EncryptNilKey(nlTestSuite * inSuite, void * inContext) -{ - HeapChecker heapChecker(inSuite); - int numOfTestVectors = ArraySize(ccm_128_test_vectors); - int numOfTestsRan = 0; - for (int vectorIndex = 0; vectorIndex < numOfTestVectors; vectorIndex++) - { - const ccm_128_test_vector * vector = ccm_128_test_vectors[vectorIndex]; - if (vector->pt_len > 0) - { - numOfTestsRan++; - chip::Platform::ScopedMemoryBuffer out_ct; - out_ct.Alloc(vector->ct_len); - NL_TEST_ASSERT(inSuite, out_ct); - chip::Platform::ScopedMemoryBuffer out_tag; - out_tag.Alloc(vector->tag_len); - NL_TEST_ASSERT(inSuite, out_tag); - - CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, nullptr, 0, vector->nonce, - vector->nonce_len, out_ct.Get(), out_tag.Get(), vector->tag_len); - NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); - break; - } - } - NL_TEST_ASSERT(inSuite, numOfTestsRan > 0); -} - static void TestAES_CCM_128EncryptInvalidNonceLen(nlTestSuite * inSuite, void * inContext) { HeapChecker heapChecker(inSuite); @@ -378,8 +378,10 @@ static void TestAES_CCM_128EncryptInvalidNonceLen(nlTestSuite * inSuite, void * out_tag.Alloc(vector->tag_len); NL_TEST_ASSERT(inSuite, out_tag); - CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, vector->key, vector->key_len, - vector->nonce, 0, out_ct.Get(), out_tag.Get(), vector->tag_len); + TestAesKey key(inSuite, vector->key, vector->key_len); + + CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, key.key, vector->nonce, 0, + out_ct.Get(), out_tag.Get(), vector->tag_len); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -405,31 +407,10 @@ static void TestAES_CCM_128EncryptInvalidTagLen(nlTestSuite * inSuite, void * in out_tag.Alloc(vector->tag_len); NL_TEST_ASSERT(inSuite, out_tag); - CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, vector->key, vector->key_len, - vector->nonce, vector->nonce_len, out_ct.Get(), out_tag.Get(), 13); - NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); - break; - } - } - NL_TEST_ASSERT(inSuite, numOfTestsRan > 0); -} + TestAesKey key(inSuite, vector->key, vector->key_len); -static void TestAES_CCM_128DecryptInvalidKey(nlTestSuite * inSuite, void * inContext) -{ - HeapChecker heapChecker(inSuite); - int numOfTestVectors = ArraySize(ccm_128_test_vectors); - int numOfTestsRan = 0; - for (int vectorIndex = 0; vectorIndex < numOfTestVectors; vectorIndex++) - { - const ccm_128_test_vector * vector = ccm_128_test_vectors[vectorIndex]; - if (vector->pt_len > 0) - { - numOfTestsRan++; - Platform::ScopedMemoryBuffer out_pt; - out_pt.Alloc(vector->pt_len); - NL_TEST_ASSERT(inSuite, out_pt); - CHIP_ERROR err = AES_CCM_decrypt(vector->ct, vector->ct_len, vector->aad, vector->aad_len, vector->tag, vector->tag_len, - nullptr, 0, vector->nonce, vector->nonce_len, out_pt.Get()); + CHIP_ERROR err = AES_CCM_encrypt(vector->pt, vector->pt_len, vector->aad, vector->aad_len, key.key, vector->nonce, + vector->nonce_len, out_ct.Get(), out_tag.Get(), 13); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -451,8 +432,11 @@ static void TestAES_CCM_128DecryptInvalidNonceLen(nlTestSuite * inSuite, void * Platform::ScopedMemoryBuffer out_pt; out_pt.Alloc(vector->pt_len); NL_TEST_ASSERT(inSuite, out_pt); + + TestAesKey key(inSuite, vector->key, vector->key_len); + CHIP_ERROR err = AES_CCM_decrypt(vector->ct, vector->ct_len, vector->aad, vector->aad_len, vector->tag, vector->tag_len, - vector->key, vector->key_len, vector->nonce, 0, out_pt.Get()); + key.key, vector->nonce, 0, out_pt.Get()); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); break; } @@ -2531,10 +2515,8 @@ static const nlTest sTests[] = { NL_TEST_DEF("Test encrypting AES-CCM-128 test vectors", TestAES_CCM_128EncryptTestVectors), NL_TEST_DEF("Test decrypting AES-CCM-128 test vectors", TestAES_CCM_128DecryptTestVectors), - NL_TEST_DEF("Test encrypting AES-CCM-128 using nil key", TestAES_CCM_128EncryptNilKey), NL_TEST_DEF("Test encrypting AES-CCM-128 using invalid nonce", TestAES_CCM_128EncryptInvalidNonceLen), NL_TEST_DEF("Test encrypting AES-CCM-128 using invalid tag", TestAES_CCM_128EncryptInvalidTagLen), - NL_TEST_DEF("Test decrypting AES-CCM-128 invalid key", TestAES_CCM_128DecryptInvalidKey), NL_TEST_DEF("Test decrypting AES-CCM-128 invalid nonce", TestAES_CCM_128DecryptInvalidNonceLen), NL_TEST_DEF("Test encrypt/decrypt AES-CTR-128 test vectors", TestAES_CTR_128CryptTestVectors), NL_TEST_DEF("Test ASN.1 signature conversion routines", TestAsn1Conversions), diff --git a/src/crypto/tests/TestSessionKeystore.cpp b/src/crypto/tests/TestSessionKeystore.cpp new file mode 100644 index 00000000000000..a1f786d51a3dc1 --- /dev/null +++ b/src/crypto/tests/TestSessionKeystore.cpp @@ -0,0 +1,227 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AES_CCM_128_test_vectors.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if CHIP_CRYPTO_PSA +#include +#endif + +using namespace chip; +using namespace chip::Crypto; + +namespace { + +using TestSessionKeystoreImpl = DefaultSessionKeystore; + +struct DeriveKeyTestVector +{ + // KDF parameters + const char * secret; + const char * salt; + const char * info; + // AES CTR input + uint8_t plaintext[16]; + uint8_t nonce[13]; + // Expected AES CTR output + uint8_t ciphertext[16]; +}; + +struct DeriveSessionKeysTestVector +{ + // KDF parameters + const char * secret; + const char * salt; + const char * info; + // AES CTR input + uint8_t plaintext[16]; + uint8_t nonce[13]; + // Expected AES CTR output + uint8_t i2rCiphertext[16]; + uint8_t r2iCiphertext[16]; + uint8_t attestationChallenge[16]; +}; + +DeriveKeyTestVector deriveKeyTestVectors[] = { + { + .secret = "secret", + .salt = "salt123", + .info = "info123", + // derived key: a134e284e8628486f4d620a711f3cb50 + .plaintext = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .nonce = { 0 }, + .ciphertext = { 0x62, 0x1b, 0x8d, 0x7a, 0x6f, 0xea, 0x7f, 0xca, 0x03, 0x64, 0x21, 0xb4, 0x3c, 0xbc, 0xa9, 0xbb }, + }, +}; + +DeriveSessionKeysTestVector deriveSessionKeysTestVectors[] = { + { + .secret = "secret", + .salt = "salt123", + .info = "info123", + // derived keys: a134e284e8628486f4d620a711f3cb50 + // 8a84a74c1550cf1dc57e5f8a099dcf37 + // 739184dd1465856473706661f5116be5 + .plaintext = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + .nonce = { 0 }, + .i2rCiphertext = { 0x62, 0x1b, 0x8d, 0x7a, 0x6f, 0xea, 0x7f, 0xca, 0x03, 0x64, 0x21, 0xb4, 0x3c, 0xbc, 0xa9, 0xbb }, + .r2iCiphertext = { 0x65, 0x90, 0xf8, 0xab, 0x85, 0x55, 0x02, 0xcf, 0x87, 0xc5, 0xd9, 0x45, 0x75, 0xcd, 0xdb, 0x01 }, + .attestationChallenge = { 0x73, 0x91, 0x84, 0xdd, 0x14, 0x65, 0x85, 0x64, 0x73, 0x70, 0x66, 0x61, 0xf5, 0x11, 0x6b, 0xe5 }, + }, +}; + +ByteSpan ToSpan(const char * str) +{ + return ByteSpan(reinterpret_cast(str), strlen(str)); +} + +void TestBasicImport(nlTestSuite * inSuite, void * inContext) +{ + TestSessionKeystoreImpl keystore; + + // Verify that keys imported to the keystore behave as expected. + for (const ccm_128_test_vector * testPtr : ccm_128_test_vectors) + { + const ccm_128_test_vector & test = *testPtr; + + Aes128KeyByteArray keyMaterial; + memcpy(keyMaterial, test.key, test.key_len); + + Aes128KeyHandle keyHandle; + NL_TEST_ASSERT_SUCCESS(inSuite, keystore.CreateKey(keyMaterial, keyHandle)); + + Platform::ScopedMemoryBuffer ciphertext; + Platform::ScopedMemoryBuffer tag; + NL_TEST_ASSERT(inSuite, ciphertext.Alloc(test.ct_len)); + NL_TEST_ASSERT(inSuite, tag.Alloc(test.tag_len)); + NL_TEST_ASSERT(inSuite, + AES_CCM_encrypt(test.pt, test.pt_len, test.aad, test.aad_len, keyHandle, test.nonce, test.nonce_len, + ciphertext.Get(), tag.Get(), test.tag_len) == test.result); + NL_TEST_ASSERT(inSuite, memcmp(ciphertext.Get(), test.ct, test.ct_len) == 0); + NL_TEST_ASSERT(inSuite, memcmp(tag.Get(), test.tag, test.tag_len) == 0); + + keystore.DestroyKey(keyHandle); + } +} + +void TestDeriveKey(nlTestSuite * inSuite, void * inContext) +{ + TestSessionKeystoreImpl keystore; + + for (const DeriveKeyTestVector & test : deriveKeyTestVectors) + { + P256ECDHDerivedSecret secret; + memcpy(secret.Bytes(), test.secret, strlen(test.secret)); + secret.SetLength(strlen(test.secret)); + + Aes128KeyHandle keyHandle; + NL_TEST_ASSERT_SUCCESS(inSuite, keystore.DeriveKey(secret, ToSpan(test.salt), ToSpan(test.info), keyHandle)); + + uint8_t ciphertext[sizeof(test.ciphertext)]; + NL_TEST_ASSERT_SUCCESS( + inSuite, AES_CTR_crypt(test.plaintext, sizeof(test.plaintext), keyHandle, test.nonce, sizeof(test.nonce), ciphertext)); + NL_TEST_ASSERT(inSuite, memcmp(ciphertext, test.ciphertext, sizeof(test.ciphertext)) == 0); + + keystore.DestroyKey(keyHandle); + } +} + +void TestDeriveSessionKeys(nlTestSuite * inSuite, void * inContext) +{ + TestSessionKeystoreImpl keystore; + + for (const DeriveSessionKeysTestVector & test : deriveSessionKeysTestVectors) + { + P256ECDHDerivedSecret secret; + memcpy(secret.Bytes(), test.secret, strlen(test.secret)); + secret.SetLength(strlen(test.secret)); + + Aes128KeyHandle i2r; + Aes128KeyHandle r2i; + AttestationChallenge challenge; + NL_TEST_ASSERT_SUCCESS( + inSuite, keystore.DeriveSessionKeys(ToSpan(test.secret), ToSpan(test.salt), ToSpan(test.info), i2r, r2i, challenge)); + + uint8_t ciphertext[sizeof(test.i2rCiphertext)]; + + // Test I2R key + NL_TEST_ASSERT_SUCCESS( + inSuite, AES_CTR_crypt(test.plaintext, sizeof(test.plaintext), i2r, test.nonce, sizeof(test.nonce), ciphertext)); + NL_TEST_ASSERT(inSuite, memcmp(ciphertext, test.i2rCiphertext, sizeof(test.i2rCiphertext)) == 0); + + // Test R2I key + NL_TEST_ASSERT_SUCCESS( + inSuite, AES_CTR_crypt(test.plaintext, sizeof(test.plaintext), r2i, test.nonce, sizeof(test.nonce), ciphertext)); + NL_TEST_ASSERT(inSuite, memcmp(ciphertext, test.r2iCiphertext, sizeof(test.r2iCiphertext)) == 0); + + // Check attestation challenge + NL_TEST_ASSERT(inSuite, memcmp(challenge.Bytes(), test.attestationChallenge, sizeof(test.attestationChallenge)) == 0); + + keystore.DestroyKey(i2r); + keystore.DestroyKey(r2i); + } +} + +const nlTest sTests[] = { NL_TEST_DEF("Test basic import", TestBasicImport), NL_TEST_DEF("Test derive key", TestDeriveKey), + NL_TEST_DEF("Test derive session keys", TestDeriveSessionKeys), NL_TEST_SENTINEL() }; + +int Test_Setup(void * inContext) +{ + CHIP_ERROR error = Platform::MemoryInit(); + VerifyOrReturnError(error == CHIP_NO_ERROR, FAILURE); + +#if CHIP_CRYPTO_PSA + psa_crypto_init(); +#endif + + return SUCCESS; +} + +int Test_Teardown(void * inContext) +{ + Platform::MemoryShutdown(); + + return SUCCESS; +} + +} // namespace + +/** + * Main + */ +int TestSessionKeystore() +{ + nlTestSuite theSuite = { "SessionKeystore tests", &sTests[0], Test_Setup, Test_Teardown }; + + // Run test suite againt one context. + nlTestRunner(&theSuite, nullptr); + return nlTestRunnerStats(&theSuite); +} + +CHIP_REGISTER_TEST_SUITE(TestSessionKeystore) diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm index 885b118a31cc65..b47f192520bc61 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ static NSString * const kErrorCertStoreInit = @"Init failure while initializing persistent storage operational certificate store"; static NSString * const kErrorCDCertStoreInit = @"Init failure while initializing Certificate Declaration Signing Keys store"; static NSString * const kErrorOtaProviderInit = @"Init failure while creating an OTA provider delegate"; +static NSString * const kErrorSessionKeystoreInit = @"Init failure while initializing session keystore"; static bool sExitHandlerRegistered = false; static void ShutdownOnExit() { [[MTRDeviceControllerFactory sharedInstance] stopControllerFactory]; } @@ -70,6 +72,7 @@ @interface MTRDeviceControllerFactory () @property (readonly) MTRPersistentStorageDelegateBridge * persistentStorageDelegateBridge; @property (readonly) MTRAttestationTrustStoreBridge * attestationTrustStoreBridge; @property (readonly) MTROTAProviderDelegateBridge * otaProviderDelegateBridge; +@property (readonly) Crypto::RawKeySessionKeystore * sessionKeystore; // We use TestPersistentStorageDelegate just to get an in-memory store to back // our group data provider impl. We initialize this store correctly on every // controller startup, so don't need to actually persist it. @@ -115,6 +118,11 @@ - (instancetype)init _chipWorkQueue = DeviceLayer::PlatformMgrImpl().GetWorkQueue(); _controllerFactory = &DeviceControllerFactory::GetInstance(); + _sessionKeystore = new chip::Crypto::RawKeySessionKeystore(); + if ([self checkForInitError:(_sessionKeystore != nullptr) logMsg:kErrorSessionKeystoreInit]) { + return nil; + } + _groupStorageDelegate = new chip::TestPersistentStorageDelegate(); if ([self checkForInitError:(_groupStorageDelegate != nullptr) logMsg:kErrorGroupProviderInit]) { return nil; @@ -127,6 +135,7 @@ - (instancetype)init } _groupDataProvider->SetStorageDelegate(_groupStorageDelegate); + _groupDataProvider->SetSessionKeystore(_sessionKeystore); CHIP_ERROR errorCode = _groupDataProvider->Init(); if ([self checkForInitError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorGroupProviderInit]) { return nil; @@ -186,6 +195,11 @@ - (void)cleanupInitObjects delete _groupStorageDelegate; _groupStorageDelegate = nullptr; } + + if (_sessionKeystore) { + delete _sessionKeystore; + _sessionKeystore = nullptr; + } } - (void)cleanupStartupObjects @@ -375,6 +389,7 @@ - (BOOL)startControllerFactory:(MTRDeviceControllerFactoryParams *)startupParams } params.groupDataProvider = _groupDataProvider; + params.sessionKeystore = _sessionKeystore; params.fabricIndependentStorage = _persistentStorageDelegateBridge; params.operationalKeystore = _keystore; params.opCertStore = _opCertStore; diff --git a/src/messaging/tests/MessagingContext.cpp b/src/messaging/tests/MessagingContext.cpp index a6955aaf88acaa..295518d0811006 100644 --- a/src/messaging/tests/MessagingContext.cpp +++ b/src/messaging/tests/MessagingContext.cpp @@ -48,7 +48,8 @@ CHIP_ERROR MessagingContext::Init(TransportMgrBase * transport, IOContext * ioCo ReturnErrorOnFailure(mFabricTable.Init(initParams)); - ReturnErrorOnFailure(mSessionManager.Init(&GetSystemLayer(), transport, &mMessageCounterManager, &mStorage, &mFabricTable)); + ReturnErrorOnFailure( + mSessionManager.Init(&GetSystemLayer(), transport, &mMessageCounterManager, &mStorage, &mFabricTable, mSessionKeystore)); ReturnErrorOnFailure(mExchangeManager.Init(&mSessionManager)); ReturnErrorOnFailure(mMessageCounterManager.Init(&mExchangeManager)); diff --git a/src/messaging/tests/MessagingContext.h b/src/messaging/tests/MessagingContext.h index fea896bdaa153a..156bb78bf3609e 100644 --- a/src/messaging/tests/MessagingContext.h +++ b/src/messaging/tests/MessagingContext.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include @@ -131,6 +132,7 @@ class MessagingContext : public PlatformMemoryUser Messaging::ExchangeManager & GetExchangeManager() { return mExchangeManager; } secure_channel::MessageCounterManager & GetMessageCounterManager() { return mMessageCounterManager; } FabricTable & GetFabricTable() { return mFabricTable; } + Crypto::DefaultSessionKeystore & GetSessionKeystore() { return mSessionKeystore; } FabricIndex GetAliceFabricIndex() { return mAliceFabricIndex; } FabricIndex GetBobFabricIndex() { return mBobFabricIndex; } @@ -182,6 +184,7 @@ class MessagingContext : public PlatformMemoryUser chip::TestPersistentStorageDelegate mStorage; // for SessionManagerInit chip::PersistentStorageOperationalKeystore mOpKeyStore; chip::Credentials::PersistentStorageOpCertStore mOpCertStore; + chip::Crypto::DefaultSessionKeystore mSessionKeystore; FabricIndex mAliceFabricIndex = kUndefinedFabricIndex; FabricIndex mBobFabricIndex = kUndefinedFabricIndex; diff --git a/src/messaging/tests/echo/common.cpp b/src/messaging/tests/echo/common.cpp index 22a21ca391c95c..146854083de2e9 100644 --- a/src/messaging/tests/echo/common.cpp +++ b/src/messaging/tests/echo/common.cpp @@ -35,6 +35,7 @@ chip::SessionManager gSessionManager; chip::Messaging::ExchangeManager gExchangeManager; chip::secure_channel::MessageCounterManager gMessageCounterManager; chip::TestPersistentStorageDelegate gStorage; +chip::Crypto::DefaultSessionKeystore gSessionKeystore; void InitializeChip() { diff --git a/src/messaging/tests/echo/common.h b/src/messaging/tests/echo/common.h index ba02d83df3a2b6..03d2431d3b7a8a 100644 --- a/src/messaging/tests/echo/common.h +++ b/src/messaging/tests/echo/common.h @@ -25,6 +25,7 @@ #pragma once #include +#include #include #include #include @@ -39,6 +40,7 @@ extern chip::SessionManager gSessionManager; extern chip::Messaging::ExchangeManager gExchangeManager; extern chip::secure_channel::MessageCounterManager gMessageCounterManager; extern chip::TestPersistentStorageDelegate gStorage; +extern chip::Crypto::DefaultSessionKeystore gSessionKeystore; void InitializeChip(void); void ShutdownChip(void); diff --git a/src/messaging/tests/echo/echo_requester.cpp b/src/messaging/tests/echo/echo_requester.cpp index 2635b3fdc81670..58b827d7914d53 100644 --- a/src/messaging/tests/echo/echo_requester.cpp +++ b/src/messaging/tests/echo/echo_requester.cpp @@ -227,7 +227,7 @@ int main(int argc, char * argv[]) SuccessOrExit(err); err = gSessionManager.Init(&chip::DeviceLayer::SystemLayer(), &gTCPManager, &gMessageCounterManager, &gStorage, - &gFabricTable); + &gFabricTable, gSessionKeystore); SuccessOrExit(err); } else @@ -238,7 +238,7 @@ int main(int argc, char * argv[]) SuccessOrExit(err); err = gSessionManager.Init(&chip::DeviceLayer::SystemLayer(), &gUDPManager, &gMessageCounterManager, &gStorage, - &gFabricTable); + &gFabricTable, gSessionKeystore); SuccessOrExit(err); } diff --git a/src/messaging/tests/echo/echo_responder.cpp b/src/messaging/tests/echo/echo_responder.cpp index 846680c20f8563..9d449e1ec5c579 100644 --- a/src/messaging/tests/echo/echo_responder.cpp +++ b/src/messaging/tests/echo/echo_responder.cpp @@ -93,7 +93,7 @@ int main(int argc, char * argv[]) SuccessOrExit(err); err = gSessionManager.Init(&chip::DeviceLayer::SystemLayer(), &gTCPManager, &gMessageCounterManager, &gStorage, - &gFabricTable); + &gFabricTable, gSessionKeystore); SuccessOrExit(err); } else @@ -103,7 +103,7 @@ int main(int argc, char * argv[]) SuccessOrExit(err); err = gSessionManager.Init(&chip::DeviceLayer::SystemLayer(), &gUDPManager, &gMessageCounterManager, &gStorage, - &gFabricTable); + &gFabricTable, gSessionKeystore); SuccessOrExit(err); } diff --git a/src/platform/nxp/common/crypto/CHIPCryptoPALTinyCrypt.cpp b/src/platform/nxp/common/crypto/CHIPCryptoPALTinyCrypt.cpp index b7866f97af1de5..4bf07e11a93ffc 100644 --- a/src/platform/nxp/common/crypto/CHIPCryptoPALTinyCrypt.cpp +++ b/src/platform/nxp/common/crypto/CHIPCryptoPALTinyCrypt.cpp @@ -123,18 +123,8 @@ static bool _isValidTagLength(size_t tag_length) return false; } -static bool _isValidKeyLength(size_t length) -{ - // 16 bytes key for AES-CCM-128, 32 for AES-CCM-256 - if (length == 16 || length == 32) - { - return true; - } - return false; -} - CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, - const uint8_t * key, size_t key_length, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, + const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, uint8_t * tag, size_t tag_length) { CHIP_ERROR error = CHIP_NO_ERROR; @@ -145,8 +135,6 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c VerifyOrExit(plaintext != nullptr || plaintext_length == 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(ciphertext != nullptr || plaintext_length == 0, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(_isValidKeyLength(key_length), error = CHIP_ERROR_UNSUPPORTED_ENCRYPTION_TYPE); VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); @@ -156,10 +144,8 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c VerifyOrExit(aad != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); } - // Size of key = key_length * number of bits in a byte (8) - // Cast is safe because we called _isValidKeyLength above. - result = - mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, Uint8::to_const_uchar(key), static_cast(key_length * 8)); + // Size of key is expressed in bits, hence the multiplication by 8. + result = mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, key.As(), sizeof(Aes128KeyByteArray) * 8); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); // Encrypt @@ -175,7 +161,7 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c } CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, const uint8_t * aad, size_t aad_len, - const uint8_t * tag, size_t tag_length, const uint8_t * key, size_t key_length, const uint8_t * nonce, + const uint8_t * tag, size_t tag_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * plaintext) { CHIP_ERROR error = CHIP_NO_ERROR; @@ -188,8 +174,6 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, co VerifyOrExit(ciphertext != nullptr || ciphertext_len == 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(_isValidKeyLength(key_length), error = CHIP_ERROR_UNSUPPORTED_ENCRYPTION_TYPE); VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); if (aad_len > 0) @@ -197,10 +181,8 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, co VerifyOrExit(aad != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); } - // Size of key = key_length * number of bits in a byte (8) - // Cast is safe because we called _isValidKeyLength above. - result = - mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, Uint8::to_const_uchar(key), static_cast(key_length * 8)); + // Size of key is expressed in bits, hence the multiplication by 8. + result = mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, key.As(), sizeof(Aes128KeyByteArray) * 8); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); // Decrypt diff --git a/src/platform/nxp/k32w/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp b/src/platform/nxp/k32w/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp index 9c706e396575ee..032438dd042101 100644 --- a/src/platform/nxp/k32w/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp +++ b/src/platform/nxp/k32w/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp @@ -114,18 +114,8 @@ static bool _isValidTagLength(size_t tag_length) return false; } -static bool _isValidKeyLength(size_t length) -{ - // 16 bytes key for AES-CCM-128, 32 for AES-CCM-256 - if (length == 16 || length == 32) - { - return true; - } - return false; -} - CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, - const uint8_t * key, size_t key_length, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, + const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, uint8_t * tag, size_t tag_length) { CHIP_ERROR error = CHIP_NO_ERROR; @@ -136,8 +126,6 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c VerifyOrExit(plaintext != nullptr || plaintext_length == 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(ciphertext != nullptr || plaintext_length == 0, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(_isValidKeyLength(key_length), error = CHIP_ERROR_UNSUPPORTED_ENCRYPTION_TYPE); VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); @@ -147,10 +135,8 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c VerifyOrExit(aad != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); } - // Size of key = key_length * number of bits in a byte (8) - // Cast is safe because we called _isValidKeyLength above. - result = - mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, Uint8::to_const_uchar(key), static_cast(key_length * 8)); + // Size of key is expressed in bits, hence the multiplication by 8. + result = mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, key.As(), sizeof(Aes128KeyByteArray) * 8); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); // Encrypt @@ -166,7 +152,7 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c } CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, const uint8_t * aad, size_t aad_len, - const uint8_t * tag, size_t tag_length, const uint8_t * key, size_t key_length, const uint8_t * nonce, + const uint8_t * tag, size_t tag_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * plaintext) { CHIP_ERROR error = CHIP_NO_ERROR; @@ -179,8 +165,6 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, co VerifyOrExit(ciphertext != nullptr || ciphertext_len == 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(_isValidKeyLength(key_length), error = CHIP_ERROR_UNSUPPORTED_ENCRYPTION_TYPE); VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); if (aad_len > 0) @@ -188,10 +172,8 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, co VerifyOrExit(aad != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); } - // Size of key = key_length * number of bits in a byte (8) - // Cast is safe because we called _isValidKeyLength above. - result = - mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, Uint8::to_const_uchar(key), static_cast(key_length * 8)); + // Size of key is expressed in bits, hence the multiplication by 8. + result = mbedtls_ccm_setkey(&context, MBEDTLS_CIPHER_ID_AES, key.As(), sizeof(Aes128KeyByteArray) * 8); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); // Decrypt diff --git a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp index 6972da95aff7a8..955b4489906887 100644 --- a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp +++ b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp @@ -158,7 +158,7 @@ static int timeCompare(mbedtls_x509_time * t1, mbedtls_x509_time * t2) } CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, - const uint8_t * key, size_t key_length, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, + const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, uint8_t * tag, size_t tag_length) { CHIP_ERROR error = CHIP_NO_ERROR; @@ -169,9 +169,6 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c bool allocated_buffer = false; VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key_length == kAES_CCM128_Key_Length, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key_length == kAES_CCM128_Key_Length, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(CanCastTo(nonce_length), error = CHIP_ERROR_INVALID_ARGUMENT); @@ -188,12 +185,12 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c psa_crypto_init(); psa_set_key_type(&attr, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attr, key_length * 8); + psa_set_key_bits(&attr, sizeof(Aes128KeyByteArray) * 8); psa_set_key_algorithm(&attr, PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8)); psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT); status = psa_driver_wrapper_aead_encrypt( - &attr, Uint8::to_const_uchar(key), key_length, PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), + &attr, key.As(), sizeof(Aes128KeyByteArray), PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), Uint8::to_const_uchar(nonce), nonce_length, Uint8::to_const_uchar(aad), aad_length, Uint8::to_const_uchar(plaintext), plaintext_length, allocated_buffer ? buffer : ciphertext, plaintext_length + tag_length, &output_length); @@ -217,7 +214,7 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c } CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, const uint8_t * aad, size_t aad_len, - const uint8_t * tag, size_t tag_length, const uint8_t * key, size_t key_length, const uint8_t * nonce, + const uint8_t * tag, size_t tag_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * plaintext) { CHIP_ERROR error = CHIP_NO_ERROR; @@ -229,8 +226,6 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, co VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key_length == kAES_CCM128_Key_Length, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); @@ -245,7 +240,7 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, co psa_crypto_init(); psa_set_key_type(&attr, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attr, key_length * 8); + psa_set_key_bits(&attr, sizeof(Aes128KeyByteArray) * 8); psa_set_key_algorithm(&attr, PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8)); psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DECRYPT); @@ -256,7 +251,7 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, co } status = psa_driver_wrapper_aead_decrypt( - &attr, Uint8::to_const_uchar(key), key_length, PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), + &attr, key.As(), sizeof(Aes128KeyByteArray), PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), Uint8::to_const_uchar(nonce), nonce_length, Uint8::to_const_uchar(aad), aad_len, allocated_buffer ? buffer : ciphertext, ciphertext_len + tag_length, plaintext, ciphertext_len, &output_length); diff --git a/src/protocols/secure_channel/CASESession.cpp b/src/protocols/secure_channel/CASESession.cpp index 7c00272155624e..3e3cbda767847d 100644 --- a/src/protocols/secure_channel/CASESession.cpp +++ b/src/protocols/secure_channel/CASESession.cpp @@ -103,7 +103,6 @@ using namespace Protocols::SecureChannel; constexpr uint8_t kKDFSR2Info[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x32 }; constexpr uint8_t kKDFSR3Info[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x33 }; -constexpr size_t kKDFInfoLength = sizeof(kKDFSR2Info); constexpr uint8_t kKDFS1RKeyInfo[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x31, 0x5f, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65 }; constexpr uint8_t kKDFS2RKeyInfo[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x32, 0x5f, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65 }; @@ -119,12 +118,6 @@ constexpr uint8_t kTBEData3_Nonce[] = constexpr size_t kTBEDataNonceLength = sizeof(kTBEData2_Nonce); static_assert(sizeof(kTBEData2_Nonce) == sizeof(kTBEData3_Nonce), "TBEData2_Nonce and TBEData3_Nonce must be same size"); -#ifdef ENABLE_HSM_HKDF -using HKDF_sha_crypto = HKDF_shaHSM; -#else -using HKDF_sha_crypto = HKDF_sha; -#endif - // Amounts of time to allow for server-side processing of messages. // // These timeout values only allow for the server-side processing and assume that any transport-specific @@ -190,6 +183,7 @@ CHIP_ERROR CASESession::Init(SessionManager & sessionManager, Credentials::Certi { VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(mGroupDataProvider != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(sessionManager.GetSessionKeystore() != nullptr, CHIP_ERROR_INVALID_ARGUMENT); Clear(); @@ -331,8 +325,9 @@ CHIP_ERROR CASESession::DeriveSecureSession(CryptoContext & session) const VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_BUFFER_TOO_SMALL); } - ReturnErrorOnFailure(session.InitFromSecret(mSharedSecret.Span(), ByteSpan(msg_salt), - CryptoContext::SessionInfoType::kSessionEstablishment, mRole)); + ReturnErrorOnFailure(session.InitFromSecret(*mSessionManager->GetSessionKeystore(), mSharedSecret.Span(), + ByteSpan(msg_salt), CryptoContext::SessionInfoType::kSessionEstablishment, + mRole)); return CHIP_NO_ERROR; } @@ -347,8 +342,8 @@ CHIP_ERROR CASESession::DeriveSecureSession(CryptoContext & session) const VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_BUFFER_TOO_SMALL); } - ReturnErrorOnFailure(session.InitFromSecret(mSharedSecret.Span(), ByteSpan(msg_salt), - CryptoContext::SessionInfoType::kSessionResumption, mRole)); + ReturnErrorOnFailure(session.InitFromSecret(*mSessionManager->GetSessionKeystore(), mSharedSecret.Span(), + ByteSpan(msg_salt), CryptoContext::SessionInfoType::kSessionResumption, mRole)); return CHIP_NO_ERROR; } @@ -757,10 +752,8 @@ CHIP_ERROR CASESession::SendSigma2() MutableByteSpan saltSpan(msg_salt); ReturnErrorOnFailure(ConstructSaltSigma2(ByteSpan(msg_rand), mEphemeralKey->Pubkey(), ByteSpan(mIPK), saltSpan)); - HKDF_sha_crypto mHKDF; - uint8_t sr2k[CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES]; - ReturnErrorOnFailure(mHKDF.HKDF_SHA256(mSharedSecret.ConstBytes(), mSharedSecret.Length(), saltSpan.data(), saltSpan.size(), - kKDFSR2Info, kKDFInfoLength, sr2k, CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES)); + AutoReleaseSessionKey sr2k(*mSessionManager->GetSessionKeystore()); + ReturnErrorOnFailure(DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR2Info), sr2k)); // Construct Sigma2 TBS Data size_t msg_r2_signed_len = @@ -817,10 +810,9 @@ CHIP_ERROR CASESession::SendSigma2() msg_r2_signed_enc_len = static_cast(tlvWriter.GetLengthWritten()); // Generate the encrypted data blob - ReturnErrorOnFailure(AES_CCM_encrypt(msg_R2_Encrypted.Get(), msg_r2_signed_enc_len, nullptr, 0, sr2k, - CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, kTBEData2_Nonce, kTBEDataNonceLength, - msg_R2_Encrypted.Get(), msg_R2_Encrypted.Get() + msg_r2_signed_enc_len, - CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES)); + ReturnErrorOnFailure(AES_CCM_encrypt(msg_R2_Encrypted.Get(), msg_r2_signed_enc_len, nullptr, 0, sr2k.KeyHandle(), + kTBEData2_Nonce, kTBEDataNonceLength, msg_R2_Encrypted.Get(), + msg_R2_Encrypted.Get() + msg_r2_signed_enc_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES)); // Construct Sigma2 Msg const size_t mrpParamsSize = mLocalMRPConfig.HasValue() ? TLV::EstimateStructOverhead(sizeof(uint16_t), sizeof(uint16_t)) : 0; @@ -959,7 +951,7 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg) size_t max_msg_r2_signed_enc_len; constexpr size_t kCaseOverheadForFutureTbeData = 128; - uint8_t sr2k[CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES]; + AutoReleaseSessionKey sr2k(*mSessionManager->GetSessionKeystore()); P256ECDSASignature tbsData2Signature; @@ -1010,13 +1002,8 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg) // Generate the S2K key { MutableByteSpan saltSpan(msg_salt); - err = ConstructSaltSigma2(ByteSpan(responderRandom), mRemotePubKey, ByteSpan(mIPK), saltSpan); - SuccessOrExit(err); - - HKDF_sha_crypto mHKDF; - err = mHKDF.HKDF_SHA256(mSharedSecret.ConstBytes(), mSharedSecret.Length(), saltSpan.data(), saltSpan.size(), kKDFSR2Info, - kKDFInfoLength, sr2k, CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES); - SuccessOrExit(err); + SuccessOrExit(err = ConstructSaltSigma2(ByteSpan(responderRandom), mRemotePubKey, ByteSpan(mIPK), saltSpan)); + SuccessOrExit(err = DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR2Info), sr2k)); } SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ buf, buflen })); @@ -1038,9 +1025,8 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg) msg_r2_encrypted_len = msg_r2_encrypted_len_with_tag - CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES; SuccessOrExit(err = AES_CCM_decrypt(msg_R2_Encrypted.Get(), msg_r2_encrypted_len, nullptr, 0, - msg_R2_Encrypted.Get() + msg_r2_encrypted_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, sr2k, - CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, kTBEData2_Nonce, kTBEDataNonceLength, - msg_R2_Encrypted.Get())); + msg_R2_Encrypted.Get() + msg_r2_encrypted_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, + sr2k.KeyHandle(), kTBEData2_Nonce, kTBEDataNonceLength, msg_R2_Encrypted.Get())); decryptedDataTlvReader.Init(msg_R2_Encrypted.Get(), msg_r2_encrypted_len); containerType = TLV::kTLVType_Structure; @@ -1126,7 +1112,7 @@ CHIP_ERROR CASESession::SendSigma3() uint8_t msg_salt[kIPKSize + kSHA256_Hash_Length]; - uint8_t sr3k[CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES]; + AutoReleaseSessionKey sr3k(*mSessionManager->GetSessionKeystore()); chip::Platform::ScopedMemoryBuffer msg_R3_Signed; size_t msg_r3_signed_len; @@ -1201,20 +1187,14 @@ CHIP_ERROR CASESession::SendSigma3() // Generate S3K key { MutableByteSpan saltSpan(msg_salt); - err = ConstructSaltSigma3(ByteSpan(mIPK), saltSpan); - SuccessOrExit(err); - - HKDF_sha_crypto mHKDF; - err = mHKDF.HKDF_SHA256(mSharedSecret.ConstBytes(), mSharedSecret.Length(), saltSpan.data(), saltSpan.size(), kKDFSR3Info, - kKDFInfoLength, sr3k, CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES); - SuccessOrExit(err); + SuccessOrExit(err = ConstructSaltSigma3(ByteSpan(mIPK), saltSpan)); + SuccessOrExit(err = DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR3Info), sr3k)); } // Generated Encrypted data blob - err = AES_CCM_encrypt(msg_R3_Encrypted.Get(), msg_r3_encrypted_len, nullptr, 0, sr3k, CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, - kTBEData3_Nonce, kTBEDataNonceLength, msg_R3_Encrypted.Get(), - msg_R3_Encrypted.Get() + msg_r3_encrypted_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES); - SuccessOrExit(err); + SuccessOrExit(err = AES_CCM_encrypt(msg_R3_Encrypted.Get(), msg_r3_encrypted_len, nullptr, 0, sr3k.KeyHandle(), kTBEData3_Nonce, + kTBEDataNonceLength, msg_R3_Encrypted.Get(), msg_R3_Encrypted.Get() + msg_r3_encrypted_len, + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES)); // Generate Sigma3 Msg data_len = TLV::EstimateStructOverhead(CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, msg_r3_encrypted_len); @@ -1310,7 +1290,7 @@ CHIP_ERROR CASESession::HandleSigma3a(System::PacketBufferHandle && msg) size_t msg_r3_encrypted_len_with_tag = 0; size_t max_msg_r3_signed_enc_len; - uint8_t sr3k[CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES]; + AutoReleaseSessionKey sr3k(*mSessionManager->GetSessionKeystore()); uint8_t msg_salt[kIPKSize + kSHA256_Hash_Length]; @@ -1360,22 +1340,16 @@ CHIP_ERROR CASESession::HandleSigma3a(System::PacketBufferHandle && msg) // Step 1 { MutableByteSpan saltSpan(msg_salt); - err = ConstructSaltSigma3(ByteSpan(mIPK), saltSpan); - SuccessOrExit(err); - - HKDF_sha_crypto mHKDF; - err = mHKDF.HKDF_SHA256(mSharedSecret.ConstBytes(), mSharedSecret.Length(), saltSpan.data(), saltSpan.size(), - kKDFSR3Info, kKDFInfoLength, sr3k, CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES); - SuccessOrExit(err); + SuccessOrExit(err = ConstructSaltSigma3(ByteSpan(mIPK), saltSpan)); + SuccessOrExit(err = DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR3Info), sr3k)); } SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ buf, bufLen })); // Step 2 - Decrypt data blob SuccessOrExit(err = AES_CCM_decrypt(msg_R3_Encrypted.Get(), msg_r3_encrypted_len, nullptr, 0, - msg_R3_Encrypted.Get() + msg_r3_encrypted_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, sr3k, - CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, kTBEData3_Nonce, kTBEDataNonceLength, - msg_R3_Encrypted.Get())); + msg_R3_Encrypted.Get() + msg_r3_encrypted_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, + sr3k.KeyHandle(), kTBEData3_Nonce, kTBEDataNonceLength, msg_R3_Encrypted.Get())); decryptedDataTlvReader.Init(msg_R3_Encrypted.Get(), msg_r3_encrypted_len); containerType = TLV::kTLVType_Structure; @@ -1563,6 +1537,11 @@ CHIP_ERROR CASESession::HandleSigma3c(Sigma3Work & work) return err; } +CHIP_ERROR CASESession::DeriveSigmaKey(const ByteSpan & salt, const ByteSpan & info, AutoReleaseSessionKey & key) const +{ + return mSessionManager->GetSessionKeystore()->DeriveKey(mSharedSecret, salt, info, key.KeyHandle()); +} + CHIP_ERROR CASESession::ConstructSaltSigma2(const ByteSpan & rand, const Crypto::P256PublicKey & pubkey, const ByteSpan & ipk, MutableByteSpan & salt) { @@ -1603,10 +1582,8 @@ CHIP_ERROR CASESession::ConstructSaltSigma3(const ByteSpan & ipk, MutableByteSpa } CHIP_ERROR CASESession::ConstructSigmaResumeKey(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID, - const ByteSpan & skInfo, const ByteSpan & nonce, MutableByteSpan & resumeKey) + const ByteSpan & skInfo, const ByteSpan & nonce, AutoReleaseSessionKey & resumeKey) { - VerifyOrReturnError(resumeKey.size() >= CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, CHIP_ERROR_BUFFER_TOO_SMALL); - constexpr size_t saltSize = kSigmaParamRandomNumberSize + SessionResumptionStorage::kResumptionIdSize; uint8_t salt[saltSize]; @@ -1619,11 +1596,7 @@ CHIP_ERROR CASESession::ConstructSigmaResumeKey(const ByteSpan & initiatorRandom size_t saltWritten = 0; VerifyOrReturnError(bbuf.Fit(saltWritten), CHIP_ERROR_BUFFER_TOO_SMALL); - HKDF_sha_crypto mHKDF; - ReturnErrorOnFailure(mHKDF.HKDF_SHA256(mSharedSecret.ConstBytes(), mSharedSecret.Length(), salt, saltWritten, skInfo.data(), - skInfo.size(), resumeKey.data(), CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES)); - resumeKey.reduce_size(CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES); - return CHIP_NO_ERROR; + return DeriveSigmaKey(ByteSpan(salt, saltWritten), skInfo, resumeKey); } CHIP_ERROR CASESession::GenerateSigmaResumeMIC(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID, @@ -1631,13 +1604,10 @@ CHIP_ERROR CASESession::GenerateSigmaResumeMIC(const ByteSpan & initiatorRandom, { VerifyOrReturnError(resumeMIC.size() >= CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_BUFFER_TOO_SMALL); - uint8_t srk[CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES]; - MutableByteSpan resumeKey(srk); - - ReturnErrorOnFailure(ConstructSigmaResumeKey(initiatorRandom, resumptionID, skInfo, nonce, resumeKey)); - - ReturnErrorOnFailure(AES_CCM_encrypt(nullptr, 0, nullptr, 0, resumeKey.data(), resumeKey.size(), nonce.data(), nonce.size(), - nullptr, resumeMIC.data(), CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES)); + AutoReleaseSessionKey srk(*mSessionManager->GetSessionKeystore()); + ReturnErrorOnFailure(ConstructSigmaResumeKey(initiatorRandom, resumptionID, skInfo, nonce, srk)); + ReturnErrorOnFailure(AES_CCM_encrypt(nullptr, 0, nullptr, 0, srk.KeyHandle(), nonce.data(), nonce.size(), nullptr, + resumeMIC.data(), CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES)); resumeMIC.reduce_size(CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES); return CHIP_NO_ERROR; @@ -1648,13 +1618,10 @@ CHIP_ERROR CASESession::ValidateSigmaResumeMIC(const ByteSpan & resumeMIC, const { VerifyOrReturnError(resumeMIC.size() == CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_BUFFER_TOO_SMALL); - uint8_t srk[CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES]; - MutableByteSpan resumeKey(srk); - - ReturnErrorOnFailure(ConstructSigmaResumeKey(initiatorRandom, resumptionID, skInfo, nonce, resumeKey)); - - ReturnErrorOnFailure(AES_CCM_decrypt(nullptr, 0, nullptr, 0, resumeMIC.data(), resumeMIC.size(), resumeKey.data(), - resumeKey.size(), nonce.data(), nonce.size(), nullptr)); + AutoReleaseSessionKey srk(*mSessionManager->GetSessionKeystore()); + ReturnErrorOnFailure(ConstructSigmaResumeKey(initiatorRandom, resumptionID, skInfo, nonce, srk)); + ReturnErrorOnFailure(AES_CCM_decrypt(nullptr, 0, nullptr, 0, resumeMIC.data(), resumeMIC.size(), srk.KeyHandle(), nonce.data(), + nonce.size(), nullptr)); return CHIP_NO_ERROR; } diff --git a/src/protocols/secure_channel/CASESession.h b/src/protocols/secure_channel/CASESession.h index 844425d655f41b..1800fef789d775 100644 --- a/src/protocols/secure_channel/CASESession.h +++ b/src/protocols/secure_channel/CASESession.h @@ -231,6 +231,7 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, CHIP_ERROR SendSigma2Resume(); + CHIP_ERROR DeriveSigmaKey(const ByteSpan & salt, const ByteSpan & info, Crypto::AutoReleaseSessionKey & key) const; CHIP_ERROR ConstructSaltSigma2(const ByteSpan & rand, const Crypto::P256PublicKey & pubkey, const ByteSpan & ipk, MutableByteSpan & salt); CHIP_ERROR ConstructTBSData(const ByteSpan & senderNOC, const ByteSpan & senderICAC, const ByteSpan & senderPubKey, @@ -238,7 +239,7 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, CHIP_ERROR ConstructSaltSigma3(const ByteSpan & ipk, MutableByteSpan & salt); CHIP_ERROR ConstructSigmaResumeKey(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID, const ByteSpan & skInfo, - const ByteSpan & nonce, MutableByteSpan & resumeKey); + const ByteSpan & nonce, Crypto::AutoReleaseSessionKey & resumeKey); CHIP_ERROR GenerateSigmaResumeMIC(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID, const ByteSpan & skInfo, const ByteSpan & nonce, MutableByteSpan & resumeMIC); diff --git a/src/protocols/secure_channel/PASESession.cpp b/src/protocols/secure_channel/PASESession.cpp index 16139a1f9301a3..9be51e42ed90e2 100644 --- a/src/protocols/secure_channel/PASESession.cpp +++ b/src/protocols/secure_channel/PASESession.cpp @@ -111,6 +111,7 @@ void PASESession::Clear() CHIP_ERROR PASESession::Init(SessionManager & sessionManager, uint32_t setupCode, SessionEstablishmentDelegate * delegate) { + VerifyOrReturnError(sessionManager.GetSessionKeystore() != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT); // Reset any state maintained by PASESession object (in case it's being reused for pairing) @@ -257,7 +258,7 @@ void PASESession::OnResponseTimeout(ExchangeContext * ec) CHIP_ERROR PASESession::DeriveSecureSession(CryptoContext & session) const { VerifyOrReturnError(mPairingComplete, CHIP_ERROR_INCORRECT_STATE); - return session.InitFromSecret(ByteSpan(mKe, mKeLen), ByteSpan(nullptr, 0), + return session.InitFromSecret(*mSessionManager->GetSessionKeystore(), ByteSpan(mKe, mKeLen), ByteSpan(nullptr, 0), CryptoContext::SessionInfoType::kSessionEstablishment, mRole); } diff --git a/src/protocols/secure_channel/tests/TestCASESession.cpp b/src/protocols/secure_channel/tests/TestCASESession.cpp index fb881cb60579d9..a863b3ca57dae8 100644 --- a/src/protocols/secure_channel/tests/TestCASESession.cpp +++ b/src/protocols/secure_channel/tests/TestCASESession.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -79,7 +80,7 @@ class TemporarySessionManager NL_TEST_ASSERT(suite, CHIP_NO_ERROR == mSessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &ctx.GetMessageCounterManager(), - &mStorage, &ctx.GetFabricTable())); + &mStorage, &ctx.GetFabricTable(), ctx.GetSessionKeystore())); // The setup here is really weird: we are using one session manager for // the actual messages we send (the PASE handshake, so the // unauthenticated sessions) and a different one for allocating the PASE @@ -194,12 +195,14 @@ FabricTable gCommissionerFabrics; FabricIndex gCommissionerFabricIndex; GroupDataProviderImpl gCommissionerGroupDataProvider; TestPersistentStorageDelegate gCommissionerStorageDelegate; +Crypto::DefaultSessionKeystore gCommissionerSessionKeystore; FabricTable gDeviceFabrics; FabricIndex gDeviceFabricIndex; GroupDataProviderImpl gDeviceGroupDataProvider; TestPersistentStorageDelegate gDeviceStorageDelegate; TestOperationalKeystore gDeviceOperationalKeystore; +Crypto::DefaultSessionKeystore gDeviceSessionKeystore; Credentials::PersistentStorageOpCertStore gCommissionerOpCertStore; Credentials::PersistentStorageOpCertStore gDeviceOpCertStore; @@ -233,6 +236,7 @@ CHIP_ERROR InitCredentialSets() { gCommissionerStorageDelegate.ClearStorage(); gCommissionerGroupDataProvider.SetStorageDelegate(&gCommissionerStorageDelegate); + gCommissionerGroupDataProvider.SetSessionKeystore(&gCommissionerSessionKeystore); ReturnErrorOnFailure(gCommissionerGroupDataProvider.Init()); FabricInfo commissionerFabric; @@ -261,6 +265,7 @@ CHIP_ERROR InitCredentialSets() gDeviceStorageDelegate.ClearStorage(); gDeviceGroupDataProvider.SetStorageDelegate(&gDeviceStorageDelegate); + gDeviceGroupDataProvider.SetSessionKeystore(&gDeviceSessionKeystore); ReturnErrorOnFailure(gDeviceGroupDataProvider.Init()); FabricInfo deviceFabric; diff --git a/src/protocols/secure_channel/tests/TestPASESession.cpp b/src/protocols/secure_channel/tests/TestPASESession.cpp index 85e7bb8429c212..66a6a74d2d9dc0 100644 --- a/src/protocols/secure_channel/tests/TestPASESession.cpp +++ b/src/protocols/secure_channel/tests/TestPASESession.cpp @@ -119,7 +119,7 @@ class TemporarySessionManager NL_TEST_ASSERT(suite, CHIP_NO_ERROR == mSessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &ctx.GetMessageCounterManager(), - &mStorage, &ctx.GetFabricTable())); + &mStorage, &ctx.GetFabricTable(), ctx.GetSessionKeystore())); // The setup here is really weird: we are using one session manager for // the actual messages we send (the PASE handshake, so the // unauthenticated sessions) and a different one for allocating the PASE diff --git a/src/transport/CryptoContext.cpp b/src/transport/CryptoContext.cpp index 44306bf3be0bde..6b39af59696028 100644 --- a/src/transport/CryptoContext.cpp +++ b/src/transport/CryptoContext.cpp @@ -23,6 +23,7 @@ */ #include +#include #include #include #include @@ -50,39 +51,34 @@ constexpr uint8_t RSEKeysInfo[] = { 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x using namespace Crypto; -#ifdef ENABLE_HSM_HKDF -using HKDF_sha_crypto = HKDF_shaHSM; -#else -using HKDF_sha_crypto = HKDF_sha; -#endif - CryptoContext::CryptoContext() : mKeyAvailable(false) {} CryptoContext::~CryptoContext() { - for (auto & key : mKeys) + if (mKeystore) { - ClearSecretData(key, sizeof(CryptoKey)); + mKeystore->DestroyKey(mEncryptionKey); + mKeystore->DestroyKey(mDecryptionKey); } + + mKeystore = nullptr; mKeyContext = nullptr; } -CHIP_ERROR CryptoContext::InitFromSecret(const ByteSpan & secret, const ByteSpan & salt, SessionInfoType infoType, SessionRole role) +CHIP_ERROR CryptoContext::InitFromSecret(SessionKeystore & keystore, const ByteSpan & secret, const ByteSpan & salt, + SessionInfoType infoType, SessionRole role) { - HKDF_sha_crypto mHKDF; VerifyOrReturnError(mKeyAvailable == false, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(secret.data() != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(secret.size() > 0, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError((salt.size() == 0) || (salt.data() != nullptr), CHIP_ERROR_INVALID_ARGUMENT); - const uint8_t * info = SEKeysInfo; - size_t infoLen = sizeof(SEKeysInfo); + ByteSpan info = (infoType == SessionInfoType::kSessionResumption) ? ByteSpan(RSEKeysInfo) : ByteSpan(SEKeysInfo); - if (infoType == SessionInfoType::kSessionResumption) - { - info = RSEKeysInfo; - infoLen = sizeof(RSEKeysInfo); - } + // If the secure session is created by session initiator, use the I2R key to encrypt + // messages being transmitted. Otherwise, use the R2I key. + auto & i2rKey = (role == SessionRole::kInitiator) ? mEncryptionKey : mDecryptionKey; + auto & r2iKey = (role == SessionRole::kInitiator) ? mDecryptionKey : mEncryptionKey; #if CHIP_CONFIG_SECURITY_TEST_MODE @@ -94,7 +90,6 @@ CHIP_ERROR CryptoContext::InitFromSecret(const ByteSpan & secret, const ByteSpan "CHIP_CONFIG_TEST_SHARED_SECRET_VALUE must be 32 bytes"); const ByteSpan & testSalt = ByteSpan(nullptr, 0); (void) info; - (void) infoLen; #warning \ "Warning: CHIP_CONFIG_SECURITY_TEST_MODE=1 bypassing key negotiation... All sessions will use known, fixed test key, and NodeID=0 in NONCE. Node can only communicate with other nodes built with this flag set. Requires build flag 'treat_warnings_as_errors=false'." @@ -104,22 +99,22 @@ CHIP_ERROR CryptoContext::InitFromSecret(const ByteSpan & secret, const ByteSpan "and NodeID=0 in NONCE. " "Node can only communicate with other nodes built with this flag set."); - ReturnErrorOnFailure(mHKDF.HKDF_SHA256(kTestSharedSecret, CHIP_CONFIG_TEST_SHARED_SECRET_LENGTH, testSalt.data(), - testSalt.size(), SEKeysInfo, sizeof(SEKeysInfo), &mKeys[0][0], sizeof(mKeys))); + ReturnErrorOnFailure(keystore.DeriveSessionKeys(ByteSpan(kTestSharedSecret), testSalt, ByteSpan(SEKeysInfo), i2rKey, r2iKey, + mAttestationChallenge)); #else - ReturnErrorOnFailure( - mHKDF.HKDF_SHA256(secret.data(), secret.size(), salt.data(), salt.size(), info, infoLen, &mKeys[0][0], sizeof(mKeys))); + ReturnErrorOnFailure(keystore.DeriveSessionKeys(secret, salt, info, i2rKey, r2iKey, mAttestationChallenge)); #endif mKeyAvailable = true; mSessionRole = role; + mKeystore = &keystore; return CHIP_NO_ERROR; } -CHIP_ERROR CryptoContext::InitFromKeyPair(const Crypto::P256Keypair & local_keypair, +CHIP_ERROR CryptoContext::InitFromKeyPair(SessionKeystore & keystore, const Crypto::P256Keypair & local_keypair, const Crypto::P256PublicKey & remote_public_key, const ByteSpan & salt, SessionInfoType infoType, SessionRole role) { @@ -129,7 +124,7 @@ CHIP_ERROR CryptoContext::InitFromKeyPair(const Crypto::P256Keypair & local_keyp P256ECDHDerivedSecret secret; ReturnErrorOnFailure(local_keypair.ECDH_derive_secret(remote_public_key, secret)); - return InitFromSecret(secret.Span(), salt, infoType, role); + return InitFromSecret(keystore, secret.Span(), salt, infoType, role); } CHIP_ERROR CryptoContext::BuildNonce(NonceView nonce, uint8_t securityFlags, uint32_t messageCounter, NodeId nodeId) @@ -202,18 +197,8 @@ CHIP_ERROR CryptoContext::Encrypt(const uint8_t * input, size_t input_length, ui else { VerifyOrReturnError(mKeyAvailable, CHIP_ERROR_INVALID_USE_OF_SESSION_KEY); - KeyUsage usage = kR2IKey; - - // Message is encrypted before sending. If the secure session was created by session - // initiator, we'll use I2R key to encrypt the message that's being transmitted. - // Otherwise, we'll use R2I key, as the responder is sending the message. - if (mSessionRole == SessionRole::kInitiator) - { - usage = kI2RKey; - } - - ReturnErrorOnFailure(AES_CCM_encrypt(input, input_length, AAD, aadLen, mKeys[usage], Crypto::kAES_CCM128_Key_Length, - nonce.data(), nonce.size(), output, tag, taglen)); + ReturnErrorOnFailure( + AES_CCM_encrypt(input, input_length, AAD, aadLen, mEncryptionKey, nonce.data(), nonce.size(), output, tag, taglen)); } mac.SetTag(&header, tag, taglen); @@ -247,18 +232,8 @@ CHIP_ERROR CryptoContext::Decrypt(const uint8_t * input, size_t input_length, ui else { VerifyOrReturnError(mKeyAvailable, CHIP_ERROR_INVALID_USE_OF_SESSION_KEY); - KeyUsage usage = kI2RKey; - - // Message is decrypted on receive. If the secure session was created by session - // initiator, we'll use R2I key to decrypt the message (as it was sent by responder). - // Otherwise, we'll use I2R key, as the responder is sending the message. - if (mSessionRole == SessionRole::kInitiator) - { - usage = kR2IKey; - } - - ReturnErrorOnFailure(AES_CCM_decrypt(input, input_length, AAD, aadLen, tag, taglen, mKeys[usage], - Crypto::kAES_CCM128_Key_Length, nonce.data(), nonce.size(), output)); + ReturnErrorOnFailure( + AES_CCM_decrypt(input, input_length, AAD, aadLen, tag, taglen, mDecryptionKey, nonce.data(), nonce.size(), output)); } return CHIP_NO_ERROR; } diff --git a/src/transport/CryptoContext.h b/src/transport/CryptoContext.h index 9ab7b1383ca95e..ca2100b455c631 100644 --- a/src/transport/CryptoContext.h +++ b/src/transport/CryptoContext.h @@ -26,6 +26,7 @@ #pragma once #include +#include #include #include #include @@ -44,22 +45,22 @@ class DLL_EXPORT CryptoContext CryptoContext(); ~CryptoContext(); - CryptoContext(CryptoContext &&) = default; - CryptoContext(const CryptoContext &) = default; - CryptoContext(Crypto::SymmetricKeyContext * context) : mKeyContext(context){}; - CryptoContext & operator=(const CryptoContext &) = default; - CryptoContext & operator=(CryptoContext &&) = default; + CryptoContext(CryptoContext &&) = delete; + CryptoContext(const CryptoContext &) = delete; + explicit CryptoContext(Crypto::SymmetricKeyContext * context) : mKeyContext(context) {} + CryptoContext & operator=(const CryptoContext &) = delete; + CryptoContext & operator=(CryptoContext &&) = delete; /** * Whether the current node initiated the session, or it is responded to a session request. */ - enum class SessionRole + enum class SessionRole : uint8_t { kInitiator, /**< We initiated the session. */ kResponder, /**< We responded to the session request. */ }; - enum class SessionInfoType + enum class SessionInfoType : uint8_t { kSessionEstablishment, /**< A new secure session is established. */ kSessionResumption, /**< An old session is being resumed. */ @@ -70,6 +71,7 @@ class DLL_EXPORT CryptoContext * Derive a shared key. The derived key will be used for encrypting/decrypting * data exchanged on the secure channel. * + * @param keystore Session keystore for management of symmetric encryption keys * @param local_keypair A reference to local ECP keypair * @param remote_public_key A reference to peer's public key * @param salt A reference to the initial salt used for deriving the keys @@ -77,21 +79,24 @@ class DLL_EXPORT CryptoContext * @param role Role of the new session (initiator or responder) * @return CHIP_ERROR The result of key derivation */ - CHIP_ERROR InitFromKeyPair(const Crypto::P256Keypair & local_keypair, const Crypto::P256PublicKey & remote_public_key, - const ByteSpan & salt, SessionInfoType infoType, SessionRole role); + CHIP_ERROR InitFromKeyPair(Crypto::SessionKeystore & keystore, const Crypto::P256Keypair & local_keypair, + const Crypto::P256PublicKey & remote_public_key, const ByteSpan & salt, SessionInfoType infoType, + SessionRole role); /** * @brief * Derive a shared key. The derived key will be used for encrypting/decrypting * data exchanged on the secure channel. * + * @param keystore Session keystore for management of symmetric encryption keys * @param secret A reference to the shared secret * @param salt A reference to the initial salt used for deriving the keys * @param infoType The info buffer to use for deriving session keys * @param role Role of the new session (initiator or responder) * @return CHIP_ERROR The result of key derivation */ - CHIP_ERROR InitFromSecret(const ByteSpan & secret, const ByteSpan & salt, SessionInfoType infoType, SessionRole role); + CHIP_ERROR InitFromSecret(Crypto::SessionKeystore & keystore, const ByteSpan & secret, const ByteSpan & salt, + SessionInfoType infoType, SessionRole role); /** @brief Build a Nonce buffer using given parameters for encrypt or decrypt. */ static CHIP_ERROR BuildNonce(NonceView nonce, uint8_t securityFlags, uint32_t messageCounter, NodeId nodeId); @@ -136,7 +141,7 @@ class DLL_EXPORT CryptoContext CHIP_ERROR PrivacyDecrypt(const uint8_t * input, size_t input_length, uint8_t * output, const PacketHeader & header, const MessageAuthenticationCode & mac) const; - ByteSpan GetAttestationChallenge() const { return ByteSpan(mKeys[kAttestationChallengeKey], Crypto::kAES_CCM128_Key_Length); } + ByteSpan GetAttestationChallenge() const { return mAttestationChallenge.Span(); } /** * @brief @@ -152,20 +157,13 @@ class DLL_EXPORT CryptoContext bool IsResponder() const { return mKeyAvailable && mSessionRole == SessionRole::kResponder; } private: - typedef uint8_t CryptoKey[Crypto::kAES_CCM128_Key_Length]; - - enum KeyUsage - { - kI2RKey = 0, - kR2IKey = 1, - kAttestationChallengeKey = 2, - kNumCryptoKeys = 3 - }; - SessionRole mSessionRole; bool mKeyAvailable; - CryptoKey mKeys[KeyUsage::kNumCryptoKeys]; + Crypto::Aes128KeyHandle mEncryptionKey; + Crypto::Aes128KeyHandle mDecryptionKey; + Crypto::AttestationChallenge mAttestationChallenge; + Crypto::SessionKeystore * mKeystore = nullptr; Crypto::SymmetricKeyContext * mKeyContext = nullptr; // Use unencrypted header as additional authenticated data (AAD) during encryption and decryption. diff --git a/src/transport/SessionManager.cpp b/src/transport/SessionManager.cpp index 56f3d16db5039c..e3c424fee20dc0 100644 --- a/src/transport/SessionManager.cpp +++ b/src/transport/SessionManager.cpp @@ -79,7 +79,8 @@ SessionManager::~SessionManager() CHIP_ERROR SessionManager::Init(System::Layer * systemLayer, TransportMgrBase * transportMgr, Transport::MessageCounterManagerInterface * messageCounterManager, - chip::PersistentStorageDelegate * storageDelegate, FabricTable * fabricTable) + chip::PersistentStorageDelegate * storageDelegate, FabricTable * fabricTable, + Crypto::SessionKeystore & sessionKeystore) { VerifyOrReturnError(mState == State::kNotReady, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(transportMgr != nullptr, CHIP_ERROR_INVALID_ARGUMENT); @@ -92,6 +93,7 @@ CHIP_ERROR SessionManager::Init(System::Layer * systemLayer, TransportMgrBase * mTransportMgr = transportMgr; mMessageCounterManager = messageCounterManager; mFabricTable = fabricTable; + mSessionKeystore = &sessionKeystore; mSecureSessions.Init(); @@ -512,7 +514,7 @@ CHIP_ERROR SessionManager::InjectPaseSessionWithTestKey(SessionHolder & sessionH size_t secretLen = CHIP_CONFIG_TEST_SHARED_SECRET_LENGTH; ByteSpan secret(reinterpret_cast(CHIP_CONFIG_TEST_SHARED_SECRET_VALUE), secretLen); ReturnErrorOnFailure(secureSession->GetCryptoContext().InitFromSecret( - secret, ByteSpan(nullptr, 0), CryptoContext::SessionInfoType::kSessionEstablishment, role)); + *mSessionKeystore, secret, ByteSpan(nullptr, 0), CryptoContext::SessionInfoType::kSessionEstablishment, role)); secureSession->GetSessionMessageCounter().GetPeerMessageCounter().SetCounter(Transport::PeerMessageCounter::kInitialSyncValue); sessionHolder.Grab(session.Value()); return CHIP_NO_ERROR; @@ -533,7 +535,7 @@ CHIP_ERROR SessionManager::InjectCaseSessionWithTestKey(SessionHolder & sessionH size_t secretLen = CHIP_CONFIG_TEST_SHARED_SECRET_LENGTH; ByteSpan secret(reinterpret_cast(CHIP_CONFIG_TEST_SHARED_SECRET_VALUE), secretLen); ReturnErrorOnFailure(secureSession->GetCryptoContext().InitFromSecret( - secret, ByteSpan(nullptr, 0), CryptoContext::SessionInfoType::kSessionEstablishment, role)); + *mSessionKeystore, secret, ByteSpan(nullptr, 0), CryptoContext::SessionInfoType::kSessionEstablishment, role)); secureSession->GetSessionMessageCounter().GetPeerMessageCounter().SetCounter(Transport::PeerMessageCounter::kInitialSyncValue); sessionHolder.Grab(session.Value()); return CHIP_NO_ERROR; diff --git a/src/transport/SessionManager.h b/src/transport/SessionManager.h index 29f72c7a6ac2b7..87b9174750bbfa 100644 --- a/src/transport/SessionManager.h +++ b/src/transport/SessionManager.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -379,13 +380,17 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTabl * @brief * Initialize a Secure Session Manager * - * @param systemLayer System, layer to use + * @param systemLayer System layer to use * @param transportMgr Transport to use * @param messageCounterManager The message counter manager + * @param storageDelegate Persistent storage implementation + * @param fabricTable Fabric table to hold information about joined fabrics + * @param sessionKeystore Session keystore for management of symmetric encryption keys */ CHIP_ERROR Init(System::Layer * systemLayer, TransportMgrBase * transportMgr, Transport::MessageCounterManagerInterface * messageCounterManager, - chip::PersistentStorageDelegate * storageDelegate, FabricTable * fabricTable); + chip::PersistentStorageDelegate * storageDelegate, FabricTable * fabricTable, + Crypto::SessionKeystore & sessionKeystore); /** * @brief @@ -446,6 +451,8 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTabl FabricTable * GetFabricTable() const { return mFabricTable; } + Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } + private: /** * The State of a secure transport object. @@ -462,8 +469,9 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTabl kPayloadIsUnencrypted, }; - System::Layer * mSystemLayer = nullptr; - FabricTable * mFabricTable = nullptr; + System::Layer * mSystemLayer = nullptr; + FabricTable * mFabricTable = nullptr; + Crypto::SessionKeystore * mSessionKeystore = nullptr; Transport::UnauthenticatedSessionTable mUnauthenticatedSessions; Transport::SecureSessionTable mSecureSessions; State mState; // < Initialization state of the object diff --git a/src/transport/tests/TestSecureSession.cpp b/src/transport/tests/TestSecureSession.cpp index 67b3f68b5d785f..d6efc341ee4fc9 100644 --- a/src/transport/tests/TestSecureSession.cpp +++ b/src/transport/tests/TestSecureSession.cpp @@ -24,11 +24,12 @@ #include #include +#include #include -#include - #include #include +#include + #include using namespace chip; @@ -36,6 +37,7 @@ using namespace Crypto; void SecureChannelInitTest(nlTestSuite * inSuite, void * inContext) { + Crypto::DefaultSessionKeystore sessionKeystore; CryptoContext channel; P256Keypair keypair; @@ -46,19 +48,19 @@ void SecureChannelInitTest(nlTestSuite * inSuite, void * inContext) // Test all combinations of invalid parameters NL_TEST_ASSERT(inSuite, - channel.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan(nullptr, 10), + channel.InitFromKeyPair(sessionKeystore, 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.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan(nullptr, 0), + channel.InitFromKeyPair(sessionKeystore, 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.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan(nullptr, 0), + channel.InitFromKeyPair(sessionKeystore, keypair, keypair2.Pubkey(), ByteSpan(nullptr, 0), CryptoContext::SessionInfoType::kSessionEstablishment, CryptoContext::SessionRole::kInitiator) == CHIP_ERROR_INCORRECT_STATE); @@ -66,13 +68,15 @@ void SecureChannelInitTest(nlTestSuite * inSuite, void * inContext) const char * salt = "Test Salt"; CryptoContext channel2; NL_TEST_ASSERT(inSuite, - channel2.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan((const uint8_t *) salt, strlen(salt)), + channel2.InitFromKeyPair(sessionKeystore, keypair, keypair2.Pubkey(), + ByteSpan((const uint8_t *) salt, strlen(salt)), CryptoContext::SessionInfoType::kSessionEstablishment, CryptoContext::SessionRole::kInitiator) == CHIP_NO_ERROR); } void SecureChannelEncryptTest(nlTestSuite * inSuite, void * inContext) { + Crypto::DefaultSessionKeystore sessionKeystore; CryptoContext channel; const uint8_t plain_text[] = { 0x86, 0x74, 0x64, 0xe5, 0x0b, 0xd4, 0x0d, 0x90, 0xe1, 0x17, 0xa3, 0x2d, 0x4b, 0xd4, 0xe1, 0xe6 }; uint8_t output[128]; @@ -99,7 +103,8 @@ void SecureChannelEncryptTest(nlTestSuite * inSuite, void * inContext) const char * salt = "Test Salt"; NL_TEST_ASSERT(inSuite, - channel.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan((const uint8_t *) salt, strlen(salt)), + channel.InitFromKeyPair(sessionKeystore, keypair, keypair2.Pubkey(), + ByteSpan((const uint8_t *) salt, strlen(salt)), CryptoContext::SessionInfoType::kSessionEstablishment, CryptoContext::SessionRole::kInitiator) == CHIP_NO_ERROR); @@ -115,6 +120,7 @@ void SecureChannelEncryptTest(nlTestSuite * inSuite, void * inContext) void SecureChannelDecryptTest(nlTestSuite * inSuite, void * inContext) { + Crypto::DefaultSessionKeystore sessionKeystore; CryptoContext channel; const uint8_t plain_text[] = { 0x86, 0x74, 0x64, 0xe5, 0x0b, 0xd4, 0x0d, 0x90, 0xe1, 0x17, 0xa3, 0x2d, 0x4b, 0xd4, 0xe1, 0xe6 }; uint8_t encrypted[128]; @@ -137,7 +143,8 @@ void SecureChannelDecryptTest(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, keypair2.Initialize(ECPKeyTarget::ECDH) == CHIP_NO_ERROR); NL_TEST_ASSERT(inSuite, - channel.InitFromKeyPair(keypair, keypair2.Pubkey(), ByteSpan((const uint8_t *) salt, strlen(salt)), + channel.InitFromKeyPair(sessionKeystore, keypair, keypair2.Pubkey(), + ByteSpan((const uint8_t *) salt, strlen(salt)), CryptoContext::SessionInfoType::kSessionEstablishment, CryptoContext::SessionRole::kInitiator) == CHIP_NO_ERROR); NL_TEST_ASSERT(inSuite, channel.Encrypt(plain_text, sizeof(plain_text), encrypted, nonce, packetHeader, mac) == CHIP_NO_ERROR); @@ -149,7 +156,8 @@ void SecureChannelDecryptTest(nlTestSuite * inSuite, void * inContext) channel2.Decrypt(encrypted, sizeof(plain_text), output, nonce, packetHeader, mac) == CHIP_ERROR_INVALID_USE_OF_SESSION_KEY); NL_TEST_ASSERT(inSuite, - channel2.InitFromKeyPair(keypair2, keypair.Pubkey(), ByteSpan((const uint8_t *) salt, strlen(salt)), + channel2.InitFromKeyPair(sessionKeystore, keypair2, keypair.Pubkey(), + ByteSpan((const uint8_t *) salt, strlen(salt)), CryptoContext::SessionInfoType::kSessionEstablishment, CryptoContext::SessionRole::kResponder) == CHIP_NO_ERROR); diff --git a/src/transport/tests/TestSessionManager.cpp b/src/transport/tests/TestSessionManager.cpp index fcc4d7621b3af9..12dc46ae360cc6 100644 --- a/src/transport/tests/TestSessionManager.cpp +++ b/src/transport/tests/TestSessionManager.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -130,12 +131,13 @@ void CheckSimpleInitTest(nlTestSuite * inSuite, void * inContext) SessionManager sessionManager; secure_channel::MessageCounterManager gMessageCounterManager; chip::TestPersistentStorageDelegate deviceStorage; + chip::Crypto::DefaultSessionKeystore sessionKeystore; NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == fabricTableHolder.Init()); NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &gMessageCounterManager, &deviceStorage, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); } void CheckMessageTest(nlTestSuite * inSuite, void * inContext) @@ -158,6 +160,7 @@ void CheckMessageTest(nlTestSuite * inSuite, void * inContext) SessionManager sessionManager; secure_channel::MessageCounterManager gMessageCounterManager; chip::TestPersistentStorageDelegate deviceStorage; + chip::Crypto::DefaultSessionKeystore sessionKeystore; FabricTable & fabricTable = fabricTableHolder.GetFabricTable(); FabricIndex aliceFabricIndex = kUndefinedFabricIndex; FabricIndex bobFabricIndex = kUndefinedFabricIndex; @@ -166,7 +169,7 @@ void CheckMessageTest(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &gMessageCounterManager, &deviceStorage, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); callback.mSuite = inSuite; @@ -266,6 +269,7 @@ void SendEncryptedPacketTest(nlTestSuite * inSuite, void * inContext) SessionManager sessionManager; secure_channel::MessageCounterManager gMessageCounterManager; chip::TestPersistentStorageDelegate deviceStorage; + chip::Crypto::DefaultSessionKeystore sessionKeystore; FabricTable & fabricTable = fabricTableHolder.GetFabricTable(); FabricIndex aliceFabricIndex = kUndefinedFabricIndex; FabricIndex bobFabricIndex = kUndefinedFabricIndex; @@ -274,7 +278,7 @@ void SendEncryptedPacketTest(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &gMessageCounterManager, &deviceStorage, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); callback.mSuite = inSuite; @@ -359,6 +363,7 @@ void SendBadEncryptedPacketTest(nlTestSuite * inSuite, void * inContext) SessionManager sessionManager; secure_channel::MessageCounterManager gMessageCounterManager; chip::TestPersistentStorageDelegate deviceStorage; + chip::Crypto::DefaultSessionKeystore sessionKeystore; FabricTable & fabricTable = fabricTableHolder.GetFabricTable(); FabricIndex aliceFabricIndex = kUndefinedFabricIndex; FabricIndex bobFabricIndex = kUndefinedFabricIndex; @@ -367,7 +372,7 @@ void SendBadEncryptedPacketTest(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &gMessageCounterManager, &deviceStorage, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); callback.mSuite = inSuite; @@ -490,6 +495,7 @@ void SendPacketWithOldCounterTest(nlTestSuite * inSuite, void * inContext) SessionManager sessionManager; secure_channel::MessageCounterManager gMessageCounterManager; chip::TestPersistentStorageDelegate deviceStorage; + chip::Crypto::DefaultSessionKeystore sessionKeystore; FabricTable & fabricTable = fabricTableHolder.GetFabricTable(); FabricIndex aliceFabricIndex = kUndefinedFabricIndex; FabricIndex bobFabricIndex = kUndefinedFabricIndex; @@ -498,7 +504,7 @@ void SendPacketWithOldCounterTest(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &gMessageCounterManager, &deviceStorage, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); callback.mSuite = inSuite; @@ -597,6 +603,7 @@ void SendPacketWithTooOldCounterTest(nlTestSuite * inSuite, void * inContext) SessionManager sessionManager; secure_channel::MessageCounterManager gMessageCounterManager; chip::TestPersistentStorageDelegate deviceStorage; + chip::Crypto::DefaultSessionKeystore sessionKeystore; FabricTable & fabricTable = fabricTableHolder.GetFabricTable(); FabricIndex aliceFabricIndex = kUndefinedFabricIndex; FabricIndex bobFabricIndex = kUndefinedFabricIndex; @@ -605,7 +612,7 @@ void SendPacketWithTooOldCounterTest(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &gMessageCounterManager, &deviceStorage, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); callback.mSuite = inSuite; sessionManager.SetMessageDelegate(&callback); @@ -709,12 +716,13 @@ void SessionAllocationTest(nlTestSuite * inSuite, void * inContext) secure_channel::MessageCounterManager messageCounterManager; TestPersistentStorageDelegate deviceStorage1, deviceStorage2; - + chip::Crypto::DefaultSessionKeystore sessionKeystore; SessionManager sessionManager; + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &messageCounterManager, &deviceStorage1, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); // Allocate a session. uint16_t sessionId1; @@ -753,7 +761,7 @@ void SessionAllocationTest(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &messageCounterManager, &deviceStorage2, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); // Allocate a single session so we know what random id we are starting at. { @@ -845,6 +853,7 @@ void SessionCounterExhaustedTest(nlTestSuite * inSuite, void * inContext) SessionManager sessionManager; secure_channel::MessageCounterManager gMessageCounterManager; chip::TestPersistentStorageDelegate deviceStorage; + chip::Crypto::DefaultSessionKeystore sessionKeystore; FabricTable & fabricTable = fabricTableHolder.GetFabricTable(); FabricIndex aliceFabricIndex = kUndefinedFabricIndex; FabricIndex bobFabricIndex = kUndefinedFabricIndex; @@ -853,7 +862,7 @@ void SessionCounterExhaustedTest(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &gMessageCounterManager, &deviceStorage, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); Transport::PeerAddress peer(Transport::PeerAddress::UDP(addr, CHIP_PORT)); @@ -925,14 +934,14 @@ static void SessionShiftingTest(nlTestSuite * inSuite, void * inContext) FabricTableHolder fabricTableHolder; secure_channel::MessageCounterManager messageCounterManager; TestPersistentStorageDelegate deviceStorage; - + chip::Crypto::DefaultSessionKeystore sessionKeystore; SessionManager sessionManager; NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == fabricTableHolder.Init()); NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &messageCounterManager, &deviceStorage, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); Transport::PeerAddress peer(Transport::PeerAddress::UDP(addr, CHIP_PORT)); @@ -1005,14 +1014,14 @@ static void TestFindSecureSessionForNode(nlTestSuite * inSuite, void * inContext FabricTableHolder fabricTableHolder; secure_channel::MessageCounterManager messageCounterManager; TestPersistentStorageDelegate deviceStorage; - + chip::Crypto::DefaultSessionKeystore sessionKeystore; SessionManager sessionManager; NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == fabricTableHolder.Init()); NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &messageCounterManager, &deviceStorage, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); Transport::PeerAddress peer(Transport::PeerAddress::UDP(addr, CHIP_PORT)); diff --git a/src/transport/tests/TestSessionManagerDispatch.cpp b/src/transport/tests/TestSessionManagerDispatch.cpp index 72b8a2e27a4905..4e320961267bd7 100644 --- a/src/transport/tests/TestSessionManagerDispatch.cpp +++ b/src/transport/tests/TestSessionManagerDispatch.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -417,6 +418,7 @@ constexpr uint16_t kMaxGroupsPerFabric = 5; constexpr uint16_t kMaxGroupKeysPerFabric = 8; static chip::TestPersistentStorageDelegate sStorageDelegate; +static chip::Crypto::DefaultSessionKeystore sSessionKeystore; static GroupDataProviderImpl sProvider(kMaxGroupsPerFabric, kMaxGroupKeysPerFabric); class FabricTableHolder { @@ -436,6 +438,7 @@ class FabricTableHolder // Initialize Group Data Provider sProvider.SetStorageDelegate(&sStorageDelegate); + sProvider.SetSessionKeystore(&sSessionKeystore); // sProvider.SetListener(&chip::app::TestGroups::sListener); ReturnErrorOnFailure(sProvider.Init()); Credentials::SetGroupDataProvider(&sProvider); @@ -507,12 +510,13 @@ void TestSessionManagerInit(nlTestSuite * inSuite, TestContext & ctx, SessionMan static FabricTableHolder fabricTableHolder; static secure_channel::MessageCounterManager gMessageCounterManager; static chip::TestPersistentStorageDelegate deviceStorage; + static chip::Crypto::DefaultSessionKeystore sessionKeystore; NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == fabricTableHolder.Init()); NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == sessionManager.Init(&ctx.GetSystemLayer(), &ctx.GetTransportMgr(), &gMessageCounterManager, &deviceStorage, - &fabricTableHolder.GetFabricTable())); + &fabricTableHolder.GetFabricTable(), sessionKeystore)); } // constexpr chip::FabricId kFabricId1 = 0x2906C908D115D362;