Skip to content

Commit

Permalink
Implemented CASEServer to fetch credentials, and wait for SigmaR1 (#6791
Browse files Browse the repository at this point in the history
)
  • Loading branch information
pan-apple authored and pull[bot] committed Sep 13, 2021
1 parent c18460c commit 1650252
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 22 deletions.
5 changes: 5 additions & 0 deletions src/app/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <messaging/ExchangeMgr.h>
#include <platform/CHIPDeviceLayer.h>
#include <platform/KeyValueStoreManager.h>
#include <protocols/secure_channel/CASEServer.h>
#include <protocols/secure_channel/MessageCounterManager.h>
#include <setup_payload/SetupPayload.h>
#include <support/CodeUtils.h>
Expand Down Expand Up @@ -285,6 +286,7 @@ class ServerRendezvousAdvertisementDelegate : public RendezvousAdvertisementDele
DemoTransportMgr gTransports;
SecureSessionMgr gSessions;
RendezvousServer gRendezvousServer;
CASEServer gCASEServer;
Messaging::ExchangeManager gExchangeMgr;
ServerRendezvousAdvertisementDelegate gAdvDelegate;

Expand Down Expand Up @@ -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)
{
Expand Down
2 changes: 2 additions & 0 deletions src/protocols/secure_channel/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ static_library("secure_channel") {
output_name = "libSecureChannel"

sources = [
"CASEServer.cpp",
"CASEServer.h",
"CASESession.cpp",
"CASESession.h",
"PASESession.cpp",
Expand Down
119 changes: 119 additions & 0 deletions src/protocols/secure_channel/CASEServer.cpp
Original file line number Diff line number Diff line change
@@ -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 <protocols/secure_channel/CASEServer.h>

#include <core/CHIPError.h>
#include <support/CodeUtils.h>
#include <support/SafeInt.h>
#include <transport/SecureSessionMgr.h>

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<Transport::PeerAddress>::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
74 changes: 74 additions & 0 deletions src/protocols/secure_channel/CASEServer.h
Original file line number Diff line number Diff line change
@@ -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 <messaging/ExchangeDelegate.h>
#include <messaging/ExchangeMgr.h>
#include <protocols/secure_channel/CASESession.h>

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
4 changes: 2 additions & 2 deletions src/protocols/secure_channel/CASESession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
4 changes: 2 additions & 2 deletions src/protocols/secure_channel/CASESession.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions src/protocols/secure_channel/tests/TestCASESession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
26 changes: 21 additions & 5 deletions src/transport/AdminPairingTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include <transport/AdminPairingTable.h>

namespace chip {
using namespace Credentials;
using namespace Crypto;

namespace Transport {

Expand All @@ -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));
}
Expand Down Expand Up @@ -115,7 +117,7 @@ CHIP_ERROR AdminPairingInfo::FetchFromKVS(PersistentStorageDelegate * kvs)

if (mOperationalKey == nullptr)
{
mOperationalKey = chip::Platform::New<Crypto::P256Keypair>();
mOperationalKey = chip::Platform::New<P256Keypair>();
}
VerifyOrExit(mOperationalKey != nullptr, err = CHIP_ERROR_NO_MEMORY);
SuccessOrExit(err = mOperationalKey->Deserialize(info->mOperationalKey));
Expand Down Expand Up @@ -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<Crypto::P256Keypair>();
mOperationalKey = chip::Platform::New<P256Keypair>();
}
VerifyOrReturnError(mOperationalKey != nullptr, CHIP_ERROR_NO_MEMORY);
return mOperationalKey->Deserialize(serialized);
Expand Down Expand Up @@ -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>(CertDecodeFlags::kIsTrustAnchor).Set(CertDecodeFlags::kGenerateTBSHash)));
// TODO - Add support of ICA certificates
ReturnErrorOnFailure(
certSet.LoadCert(mOperationalCert, mOpCertLen, BitFlags<CertDecodeFlags>(CertDecodeFlags::kGenerateTBSHash)));
return CHIP_NO_ERROR;
}

AdminPairingInfo * AdminPairingTable::AssignAdminId(AdminId adminId)
{
for (size_t i = 0; i < CHIP_CONFIG_MAX_DEVICE_ADMINS; i++)
Expand Down
13 changes: 3 additions & 10 deletions src/transport/AdminPairingTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include <app/util/basic-types.h>
#include <core/CHIPPersistentStorageDelegate.h>
#include <credentials/CHIPCert.h>
#include <crypto/CHIPCryptoPAL.h>
#include <support/CHIPMem.h>
#include <support/DLLUtil.h>
Expand All @@ -42,11 +43,6 @@ constexpr char kAdminTableCountKey[] = "CHIPAdminNextId";

constexpr uint16_t kMaxChipCertSize = 600;

struct OperationalCredentials
{
uint32_t placeholder;
};

struct AccessControlList
{
uint32_t placeholder;
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 1650252

Please sign in to comment.