diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index a6a2c29886c134..641b60f465b0fe 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -285,6 +286,7 @@ class ServerRendezvousAdvertisementDelegate : public RendezvousAdvertisementDele DemoTransportMgr gTransports; SecureSessionMgr gSessions; RendezvousServer gRendezvousServer; +CASEServer gCASEServer; Messaging::ExchangeManager gExchangeMgr; ServerRendezvousAdvertisementDelegate gAdvDelegate; @@ -567,6 +569,9 @@ void InitServer(AppDelegate * delegate) err = gExchangeMgr.RegisterUnsolicitedMessageHandlerForProtocol(Protocols::ServiceProvisioning::Id, &gCallbacks); VerifyOrExit(err == CHIP_NO_ERROR, err = CHIP_ERROR_NO_UNSOLICITED_MESSAGE_HANDLER); + err = gCASEServer.ListenForSessionEstablishment(&gExchangeMgr, &gTransports, &gSessions, &GetGlobalAdminPairingTable()); + SuccessOrExit(err); + exit: if (err != CHIP_NO_ERROR) { diff --git a/src/protocols/secure_channel/BUILD.gn b/src/protocols/secure_channel/BUILD.gn index 79be1cbd38accc..09497a95919c2a 100644 --- a/src/protocols/secure_channel/BUILD.gn +++ b/src/protocols/secure_channel/BUILD.gn @@ -4,6 +4,8 @@ static_library("secure_channel") { output_name = "libSecureChannel" sources = [ + "CASEServer.cpp", + "CASEServer.h", "CASESession.cpp", "CASESession.h", "PASESession.cpp", diff --git a/src/protocols/secure_channel/CASEServer.cpp b/src/protocols/secure_channel/CASEServer.cpp new file mode 100644 index 00000000000000..98567927251fbd --- /dev/null +++ b/src/protocols/secure_channel/CASEServer.cpp @@ -0,0 +1,119 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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 +#include +#include +#include + +using namespace ::chip::Inet; +using namespace ::chip::Transport; + +namespace chip { + +CHIP_ERROR CASEServer::ListenForSessionEstablishment(Messaging::ExchangeManager * exchangeManager, TransportMgrBase * transportMgr, + SecureSessionMgr * sessionMgr, Transport::AdminPairingTable * admins) +{ + VerifyOrReturnError(transportMgr != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(exchangeManager != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(sessionMgr != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(admins != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + mSessionMgr = sessionMgr; + mAdmins = admins; + mExchangeManager = exchangeManager; + + ReturnErrorOnFailure(mPairingSession.MessageDispatch().Init(transportMgr)); + + ReturnErrorOnFailure( + mExchangeManager->RegisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_SigmaR1, this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR CASEServer::InitCASEHandshake(Messaging::ExchangeContext * ec) +{ + ReturnErrorCodeIf(ec == nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + // Lookup the admin that corresponds to the CASE session setup request. + // Each admin provisions their own credentials on the device. So it's essential to + // use the correct operational certificates for CASE session setup. + mAdminId = ec->GetSecureSession().GetAdminId(); + ReturnErrorCodeIf(mAdminId == Transport::kUndefinedAdminId, CHIP_ERROR_INVALID_ARGUMENT); + + Transport::AdminPairingInfo * admin = mAdmins->FindAdminWithId(mAdminId); + ReturnErrorCodeIf(admin == nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + ReturnErrorOnFailure(admin->GetOperationalCertificateSet(mCertificates)); + + mCredentials.Release(); + ReturnErrorOnFailure(mCredentials.Init(&mCertificates, mCertificates.GetCertCount())); + + // Setup CASE state machine using the credentials for the current admin. + ReturnErrorOnFailure(mPairingSession.ListenForSessionEstablishment(&mCredentials, mNextKeyId++, this)); + + // Hand over the exchange context to the CASE session. + ec->SetDelegate(&mPairingSession); + + return CHIP_NO_ERROR; +} + +void CASEServer::OnMessageReceived(Messaging::ExchangeContext * ec, const PacketHeader & packetHeader, + const PayloadHeader & payloadHeader, System::PacketBufferHandle payload) +{ + ReturnOnFailure(InitCASEHandshake(ec)); + mPairingSession.OnMessageReceived(ec, packetHeader, payloadHeader, std::move(payload)); + + // TODO - Enable multiple concurrent CASE session establishment + // This will prevent CASEServer to process another CASE session establishment request until the current + // one completes (successfully or failed) + mExchangeManager->UnregisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_SigmaR1); +} + +void CASEServer::Cleanup() +{ + // Let's re-register for CASE SigmaR1 message, so that the next CASE session setup request can be processed. + mExchangeManager->RegisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_SigmaR1, this); + mAdminId = Transport::kUndefinedAdminId; + mCredentials.Release(); +} + +void CASEServer::OnSessionEstablishmentError(CHIP_ERROR err) +{ + ChipLogProgress(AppServer, "CASE Session establishment failed: %s", ErrorStr(err)); + Cleanup(); +} + +void CASEServer::OnSessionEstablished() +{ + ChipLogProgress(AppServer, "CASE Session established. Setting up the secure channel."); + CHIP_ERROR err = + mSessionMgr->NewPairing(Optional::Value(mPairingSession.PeerConnection().GetPeerAddress()), + mPairingSession.PeerConnection().GetPeerNodeId(), &mPairingSession, + SecureSession::SessionRole::kResponder, mAdminId, nullptr); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Ble, "Failed in setting up secure channel: err %s", ErrorStr(err)); + OnSessionEstablishmentError(err); + return; + } + + ChipLogProgress(AppServer, "CASE secure channel is available now."); + Cleanup(); +} +} // namespace chip diff --git a/src/protocols/secure_channel/CASEServer.h b/src/protocols/secure_channel/CASEServer.h new file mode 100644 index 00000000000000..9aa05389dcbe54 --- /dev/null +++ b/src/protocols/secure_channel/CASEServer.h @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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 +#include + +namespace chip { + +class CASEServer : public SessionEstablishmentDelegate, public Messaging::ExchangeDelegateBase +{ +public: + CASEServer() {} + ~CASEServer() + { + if (mExchangeManager != nullptr) + { + mExchangeManager->UnregisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_SigmaR1); + } + + mCredentials.Release(); + } + + CHIP_ERROR ListenForSessionEstablishment(Messaging::ExchangeManager * exchangeManager, TransportMgrBase * transportMgr, + SecureSessionMgr * sessionMgr, Transport::AdminPairingTable * admins); + + //////////// SessionEstablishmentDelegate Implementation /////////////// + void OnSessionEstablishmentError(CHIP_ERROR error) override; + void OnSessionEstablished() override; + + //// ExchangeDelegate Implementation //// + void OnMessageReceived(Messaging::ExchangeContext * ec, const PacketHeader & packetHeader, const PayloadHeader & payloadHeader, + System::PacketBufferHandle payload) override; + void OnResponseTimeout(Messaging::ExchangeContext * ec) override {} + Messaging::ExchangeMessageDispatch * GetMessageDispatch(Messaging::ReliableMessageMgr * reliableMessageManager, + SecureSessionMgr * sessionMgr) override + { + return mPairingSession.GetMessageDispatch(reliableMessageManager, sessionMgr); + } + +private: + Messaging::ExchangeManager * mExchangeManager = nullptr; + + CASESession mPairingSession; + uint16_t mNextKeyId = 0; + SecureSessionMgr * mSessionMgr = nullptr; + + Transport::AdminId mAdminId = Transport::kUndefinedAdminId; + + Transport::AdminPairingTable * mAdmins = nullptr; + ChipCertificateSet mCertificates; + OperationalCredentialSet mCredentials; + + CHIP_ERROR InitCASEHandshake(Messaging::ExchangeContext * ec); + void Cleanup(); +}; + +} // namespace chip diff --git a/src/protocols/secure_channel/CASESession.cpp b/src/protocols/secure_channel/CASESession.cpp index 043add497812f4..2c1648597f2d27 100644 --- a/src/protocols/secure_channel/CASESession.cpp +++ b/src/protocols/secure_channel/CASESession.cpp @@ -211,8 +211,8 @@ CHIP_ERROR CASESession::Init(OperationalCredentialSet * operationalCredentialSet } CHIP_ERROR -CASESession::WaitForSessionEstablishment(OperationalCredentialSet * operationalCredentialSet, uint16_t myKeyId, - SessionEstablishmentDelegate * delegate) +CASESession::ListenForSessionEstablishment(OperationalCredentialSet * operationalCredentialSet, uint16_t myKeyId, + SessionEstablishmentDelegate * delegate) { ReturnErrorOnFailure(Init(operationalCredentialSet, myKeyId, delegate)); diff --git a/src/protocols/secure_channel/CASESession.h b/src/protocols/secure_channel/CASESession.h index 0f4d8979ca5901..80422e8040acec 100644 --- a/src/protocols/secure_channel/CASESession.h +++ b/src/protocols/secure_channel/CASESession.h @@ -93,8 +93,8 @@ class DLL_EXPORT CASESession : public Messaging::ExchangeDelegateBase, public Pa * * @return CHIP_ERROR The result of initialization */ - CHIP_ERROR WaitForSessionEstablishment(OperationalCredentialSet * operationalCredentialSet, uint16_t myKeyId, - SessionEstablishmentDelegate * delegate); + CHIP_ERROR ListenForSessionEstablishment(OperationalCredentialSet * operationalCredentialSet, uint16_t myKeyId, + SessionEstablishmentDelegate * delegate); /** * @brief diff --git a/src/protocols/secure_channel/tests/TestCASESession.cpp b/src/protocols/secure_channel/tests/TestCASESession.cpp index 4c7dc4096f83b1..fc34a6479602a1 100644 --- a/src/protocols/secure_channel/tests/TestCASESession.cpp +++ b/src/protocols/secure_channel/tests/TestCASESession.cpp @@ -108,8 +108,8 @@ void CASE_SecurePairingWaitTest(nlTestSuite * inSuite, void * inContext) TestCASESecurePairingDelegate delegate; CASESession pairing; - NL_TEST_ASSERT(inSuite, pairing.WaitForSessionEstablishment(&accessoryDevOpCred, 0, nullptr) == CHIP_ERROR_INVALID_ARGUMENT); - NL_TEST_ASSERT(inSuite, pairing.WaitForSessionEstablishment(&accessoryDevOpCred, 0, &delegate) == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, pairing.ListenForSessionEstablishment(&accessoryDevOpCred, 0, nullptr) == CHIP_ERROR_INVALID_ARGUMENT); + NL_TEST_ASSERT(inSuite, pairing.ListenForSessionEstablishment(&accessoryDevOpCred, 0, &delegate) == CHIP_NO_ERROR); } void CASE_SecurePairingStartTest(nlTestSuite * inSuite, void * inContext) @@ -169,7 +169,7 @@ void CASE_SecurePairingHandshakeTestCommon(nlTestSuite * inSuite, void * inConte ExchangeContext * contextCommissioner = ctx.NewExchangeToLocal(&pairingCommissioner); NL_TEST_ASSERT(inSuite, - pairingAccessory.WaitForSessionEstablishment(&accessoryDevOpCred, 0, &delegateAccessory) == CHIP_NO_ERROR); + pairingAccessory.ListenForSessionEstablishment(&accessoryDevOpCred, 0, &delegateAccessory) == CHIP_NO_ERROR); NL_TEST_ASSERT(inSuite, pairingCommissioner.EstablishSession(Transport::PeerAddress(Transport::Type::kBle), &commissionerDevOpCred, 1, 0, contextCommissioner, &delegateCommissioner) == CHIP_NO_ERROR); diff --git a/src/transport/AdminPairingTable.cpp b/src/transport/AdminPairingTable.cpp index 8e91c0d2e89f7a..1cf91a65b7721e 100644 --- a/src/transport/AdminPairingTable.cpp +++ b/src/transport/AdminPairingTable.cpp @@ -25,6 +25,8 @@ #include namespace chip { +using namespace Credentials; +using namespace Crypto; namespace Transport { @@ -49,7 +51,7 @@ CHIP_ERROR AdminPairingInfo::StoreIntoKVS(PersistentStorageDelegate * kvs) } else { - Crypto::P256Keypair keypair; + P256Keypair keypair; SuccessOrExit(err = keypair.Initialize()); SuccessOrExit(err = keypair.Serialize(info->mOperationalKey)); } @@ -115,7 +117,7 @@ CHIP_ERROR AdminPairingInfo::FetchFromKVS(PersistentStorageDelegate * kvs) if (mOperationalKey == nullptr) { - mOperationalKey = chip::Platform::New(); + mOperationalKey = chip::Platform::New(); } VerifyOrExit(mOperationalKey != nullptr, err = CHIP_ERROR_NO_MEMORY); SuccessOrExit(err = mOperationalKey->Deserialize(info->mOperationalKey)); @@ -160,13 +162,13 @@ CHIP_ERROR AdminPairingInfo::GenerateKey(AdminId id, char * key, size_t len) return CHIP_NO_ERROR; } -CHIP_ERROR AdminPairingInfo::SetOperationalKey(const Crypto::P256Keypair & key) +CHIP_ERROR AdminPairingInfo::SetOperationalKey(const P256Keypair & key) { - Crypto::P256SerializedKeypair serialized; + P256SerializedKeypair serialized; ReturnErrorOnFailure(key.Serialize(serialized)); if (mOperationalKey == nullptr) { - mOperationalKey = chip::Platform::New(); + mOperationalKey = chip::Platform::New(); } VerifyOrReturnError(mOperationalKey != nullptr, CHIP_ERROR_NO_MEMORY); return mOperationalKey->Deserialize(serialized); @@ -248,6 +250,20 @@ CHIP_ERROR AdminPairingInfo::SetOperationalCert(const ByteSpan & cert) return CHIP_NO_ERROR; } +CHIP_ERROR AdminPairingInfo::GetOperationalCertificateSet(ChipCertificateSet & certSet) +{ + constexpr uint8_t kMaxNumCertsInOpCreds = 3; + ReturnErrorOnFailure(certSet.Init(kMaxNumCertsInOpCreds, kMaxChipCertSize * kMaxNumCertsInOpCreds)); + + ReturnErrorOnFailure( + certSet.LoadCert(mRootCert, mRootCertLen, + BitFlags(CertDecodeFlags::kIsTrustAnchor).Set(CertDecodeFlags::kGenerateTBSHash))); + // TODO - Add support of ICA certificates + ReturnErrorOnFailure( + certSet.LoadCert(mOperationalCert, mOpCertLen, BitFlags(CertDecodeFlags::kGenerateTBSHash))); + return CHIP_NO_ERROR; +} + AdminPairingInfo * AdminPairingTable::AssignAdminId(AdminId adminId) { for (size_t i = 0; i < CHIP_CONFIG_MAX_DEVICE_ADMINS; i++) diff --git a/src/transport/AdminPairingTable.h b/src/transport/AdminPairingTable.h index de093167b92f61..e8ff316dd6bf65 100644 --- a/src/transport/AdminPairingTable.h +++ b/src/transport/AdminPairingTable.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -42,11 +43,6 @@ constexpr char kAdminTableCountKey[] = "CHIPAdminNextId"; constexpr uint16_t kMaxChipCertSize = 600; -struct OperationalCredentials -{ - uint32_t placeholder; -}; - struct AccessControlList { uint32_t placeholder; @@ -100,9 +96,7 @@ class DLL_EXPORT AdminPairingInfo CHIP_ERROR SetOperationalCert(const chip::ByteSpan & cert); CHIP_ERROR SetRootCert(const chip::ByteSpan & cert); - const OperationalCredentials & GetOperationalCreds() const { return mOpCred; } - OperationalCredentials & GetOperationalCreds() { return mOpCred; } - void SetOperationalCreds(const OperationalCredentials & creds) { mOpCred = creds; } + CHIP_ERROR GetOperationalCertificateSet(Credentials::ChipCertificateSet & certSet); const AccessControlList & GetACL() const { return mACL; } AccessControlList & GetACL() { return mACL; } @@ -131,12 +125,11 @@ class DLL_EXPORT AdminPairingInfo friend class AdminPairingTable; private: - AdminId mAdmin = kUndefinedAdminId; NodeId mNodeId = kUndefinedNodeId; FabricId mFabricId = kUndefinedFabricId; + AdminId mAdmin = kUndefinedAdminId; uint16_t mVendorId = kUndefinedVendorId; - OperationalCredentials mOpCred; AccessControlList mACL; Crypto::P256Keypair * mOperationalKey = nullptr;