Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented CASEServer to fetch credentials, and wait for SigmaR1 #6791

Merged
merged 3 commits into from
May 14, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indexing and lookup up by Admin ID breaks scoping. Per the spec, the admin must be located based upon the root PK of the root CA for the requesting agent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. We can do that as part of multi admin feature.
Would you prefer if I updated the above comment as part of this PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A TODO seems appropriate. It doesn't have to happen now. I'm just pointing out that this code does not appear to be compliant with the 4.369 Validate Sigma1 algorithm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
78 changes: 78 additions & 0 deletions src/protocols/secure_channel/CASEServer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
*
* 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;

void Cleanup();
pan-apple marked this conversation as resolved.
Show resolved Hide resolved

uint16_t GetNextKeyId() const { return mNextKeyId; }
void SetNextKeyId(uint16_t id) { mNextKeyId = id; }
pan-apple marked this conversation as resolved.
Show resolved Hide resolved

//// 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;
Comment on lines +67 to +68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that we end up having to make copies of this stuff is not great. Ideally we would just hold on to the right admin and use these things in-place from there. Followup for that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am expecting some refactor/cleanup once CASE state machine is hooked up on controller and device side. A lot of these overheads will iron out at that point.


CHIP_ERROR InitCASEHandshake(Messaging::ExchangeContext * ec);
};

} // 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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So here, if we stored the certs as a ChipCertificateSet to start with, couldn't we just return a const ref to it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am expecting some refactor/cleanup once CASE state machine is hooked up on controller and device side. A lot of these overheads will iron out at that point.

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