From f3872d7be665ed7021155ea72068d0226bef5d19 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Mon, 7 Sep 2020 12:27:15 +0200 Subject: [PATCH] Securing Rendezvous messages --- src/controller/CHIPDeviceController.cpp | 4 +- src/transport/BLE.cpp | 14 +- src/transport/RendezvousSession.cpp | 175 ++++++++++++++++++++++-- src/transport/RendezvousSession.h | 13 +- 4 files changed, 185 insertions(+), 21 deletions(-) diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 0ac76568181cdb..d27320599f4f17 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -312,17 +312,16 @@ CHIP_ERROR ChipDeviceController::SendMessage(void * appReqState, PacketBuffer * CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrExit(mRemoteDeviceId.HasValue(), err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(IsSecurelyConnected(), err = CHIP_ERROR_INCORRECT_STATE); mAppReqState = appReqState; if (mRendezvousSession != NULL) { - VerifyOrExit(IsConnected(), err = CHIP_ERROR_INCORRECT_STATE); err = mRendezvousSession->SendMessage(buffer); } else { - VerifyOrExit(IsSecurelyConnected(), err = CHIP_ERROR_INCORRECT_STATE); err = mSessionManager->SendMessage(mRemoteDeviceId.Value(), buffer); } exit: @@ -404,6 +403,7 @@ void ChipDeviceController::OnRendezvousError(CHIP_ERROR err) void ChipDeviceController::OnRendezvousConnectionOpened() { mPairingSession = mRendezvousSession->GetPairingSession(); + mConState = kConnectionState_SecureConnected; if (mOnNewConnection) { diff --git a/src/transport/BLE.cpp b/src/transport/BLE.cpp index a653ba8ae04f0e..f92fe37512c62b 100644 --- a/src/transport/BLE.cpp +++ b/src/transport/BLE.cpp @@ -127,18 +127,28 @@ CHIP_ERROR BLE::DelegateConnection(Ble::BleLayer * bleLayer, const uint16_t conn CHIP_ERROR BLE::SendMessage(const MessageHeader & header, const Transport::PeerAddress & address, System::PacketBuffer * msgBuf) { - CHIP_ERROR err = CHIP_NO_ERROR; + CHIP_ERROR err = CHIP_NO_ERROR; + const size_t headerSize = header.EncodeSizeBytes(); + size_t actualEncodedHeaderSize; VerifyOrExit(address.GetTransportType() == Type::kBle, err = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(mState == State::kInitialized, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mBleEndPoint != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(msgBuf->EnsureReservedSize(headerSize), err = CHIP_ERROR_NO_MEMORY); + + msgBuf->SetStart(msgBuf->Start() - headerSize); + + err = header.Encode(msgBuf->Start(), msgBuf->DataLength(), &actualEncodedHeaderSize); + SuccessOrExit(err); + + VerifyOrExit(headerSize == actualEncodedHeaderSize, err = CHIP_ERROR_INTERNAL); err = mBleEndPoint->Send(msgBuf); msgBuf = nullptr; SuccessOrExit(err); exit: - if (msgBuf != NULL) + if (msgBuf != nullptr) { System::PacketBuffer::Free(msgBuf); msgBuf = nullptr; diff --git a/src/transport/RendezvousSession.cpp b/src/transport/RendezvousSession.cpp index c4b57e8d82109a..b6ddd023a4671e 100644 --- a/src/transport/RendezvousSession.cpp +++ b/src/transport/RendezvousSession.cpp @@ -20,6 +20,7 @@ #include #include +static const size_t kMax_SecureSDU_Length = 1024; static constexpr uint32_t kSpake2p_Iteration_Count = 50000; static const char * kSpake2pKeyExchangeSalt = "SPAKE2P Key Exchange Salt"; @@ -64,13 +65,82 @@ RendezvousSession::~RendezvousSession() mDelegate = nullptr; } -CHIP_ERROR RendezvousSession::SendMessage(System::PacketBuffer * buffer) +CHIP_ERROR RendezvousSession::SendMessage(System::PacketBuffer * msgBuf) { - // Rendezvous does not use a MessageHeader yet, but the Transport::Base API expects one, so - // let build an empty one for now. + CHIP_ERROR err = CHIP_NO_ERROR; + err = mPairingInProgress ? SendPairingMessage(msgBuf) : SendSecureMessage(msgBuf); + if (err != CHIP_NO_ERROR) + { + mPairingInProgress ? OnPairingError(err) : OnRendezvousError(err); + } + + return err; +} + +CHIP_ERROR RendezvousSession::SendPairingMessage(System::PacketBuffer * msgBuf) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + MessageHeader header; + size_t headerSize = 0; + + VerifyOrExit(msgBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(msgBuf->Next() == nullptr, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH); + + err = header.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize); + SuccessOrExit(err); + + msgBuf->ConsumeHead(headerSize); + err = mTransport->SendMessage(header, Transport::PeerAddress::BLE(), msgBuf); + SuccessOrExit(err); + +exit: + return err; +} + +CHIP_ERROR RendezvousSession::SendSecureMessage(System::PacketBuffer * msgBuf) +{ + CHIP_ERROR err = CHIP_NO_ERROR; MessageHeader header; - CHIP_ERROR err = mTransport->SendMessage(header, Transport::PeerAddress::BLE(), buffer); + const size_t headerSize = header.EncryptedHeaderSizeBytes(); + size_t actualEncodedHeaderSize; + uint8_t * data = nullptr; + size_t totalLen = 0; + size_t taglen = 0; + + VerifyOrExit(msgBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(msgBuf->Next() == nullptr, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH); + VerifyOrExit(msgBuf->TotalLength() < kMax_SecureSDU_Length, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH); + + header + .SetSourceNodeId(mParams.GetLocalNodeId()) // + .SetMessageId(mSecureMessageIndex) // + .SetEncryptionKeyID(mPairingSession.GetLocalKeyId()) // + .SetPayloadLength(headerSize + msgBuf->TotalLength()); + + VerifyOrExit(msgBuf->EnsureReservedSize(headerSize), err = CHIP_ERROR_NO_MEMORY); + + msgBuf->SetStart(msgBuf->Start() - headerSize); + data = msgBuf->Start(); + totalLen = msgBuf->TotalLength(); + + err = header.EncodeEncryptedHeader(data, totalLen, &actualEncodedHeaderSize); + SuccessOrExit(err); + + err = mSecureSession.Encrypt(data, totalLen, data, header); + SuccessOrExit(err); + err = header.EncodeMACTag(&data[totalLen], kMaxTagLen, &taglen); + SuccessOrExit(err); + + msgBuf->SetDataLength(totalLen + taglen); + + err = mTransport->SendMessage(header, Transport::PeerAddress::BLE(), msgBuf); + SuccessOrExit(err); + + mSecureMessageIndex++; + msgBuf = nullptr; + +exit: return err; } @@ -83,6 +153,15 @@ void RendezvousSession::OnPairingError(CHIP_ERROR err) void RendezvousSession::OnPairingComplete() { mPairingInProgress = false; + + CHIP_ERROR err = mPairingSession.DeriveSecureSession((const unsigned char *) kSpake2pI2RSessionInfo, + strlen(kSpake2pI2RSessionInfo), mSecureSession); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Ble, "Failed to initialize a secure session: %s", ErrorStr(err)); + return; + } + mDelegate->OnRendezvousConnectionOpened(); } @@ -117,21 +196,89 @@ void RendezvousSession::OnRendezvousError(CHIP_ERROR err) mDelegate->OnRendezvousError(err); } -void RendezvousSession::OnRendezvousMessageReceived(PacketBuffer * buffer) +void RendezvousSession::OnRendezvousMessageReceived(PacketBuffer * msgBuf) { - if (mPairingInProgress) - { - MessageHeader header; - size_t headerSize = 0; - header.Decode(buffer->Start(), buffer->DataLength(), &headerSize); + CHIP_ERROR err = CHIP_NO_ERROR; - buffer->ConsumeHead(headerSize); - mPairingSession.HandlePeerMessage(header, buffer); + err = mPairingInProgress ? HandlePairingMessage(msgBuf) : HandleSecureMessage(msgBuf); + if (err != CHIP_NO_ERROR) + { + mPairingInProgress ? OnPairingError(err) : OnRendezvousError(err); } - else +} + +CHIP_ERROR RendezvousSession::HandlePairingMessage(PacketBuffer * msgBuf) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + MessageHeader header; + size_t headerSize = 0; + + err = header.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize); + SuccessOrExit(err); + + msgBuf->ConsumeHead(headerSize); + + err = mPairingSession.HandlePeerMessage(header, msgBuf); + SuccessOrExit(err); + +exit: + return err; +} + +CHIP_ERROR RendezvousSession::HandleSecureMessage(PacketBuffer * msgBuf) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + MessageHeader header; + size_t headerSize = 0; + uint8_t * data = nullptr; + uint8_t * plainText = nullptr; + uint16_t len = 0; + size_t decodedSize = 0; + size_t taglen = 0; + System::PacketBuffer * origMsg = nullptr; + + err = header.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize); + SuccessOrExit(err); + msgBuf->ConsumeHead(headerSize); + + headerSize = header.EncryptedHeaderSizeBytes(); + data = msgBuf->Start(); + len = msgBuf->TotalLength(); + +#if CHIP_SYSTEM_CONFIG_USE_LWIP + /* This is a workaround for the case where PacketBuffer payload is not + allocated as an inline buffer to PacketBuffer structure */ + origMsg = msgBuf; + msgBuf = PacketBuffer::NewWithAvailableSize(len); + msgBuf->SetDataLength(len, msgBuf); +#endif + plainText = msgBuf->Start(); + + err = header.DecodeMACTag(&data[header.GetPayloadLength()], kMaxTagLen, &taglen); + SuccessOrExit(err); + + len -= taglen; + msgBuf->SetDataLength(len); + + err = mSecureSession.Decrypt(data, len, plainText, header); + SuccessOrExit(err); + + err = header.DecodeEncryptedHeader(plainText, headerSize, &decodedSize); + SuccessOrExit(err); + VerifyOrExit(headerSize == decodedSize, err = CHIP_ERROR_INCORRECT_STATE); + + msgBuf->ConsumeHead(headerSize); + + mDelegate->OnRendezvousMessageReceived(msgBuf); + msgBuf = nullptr; + +exit: + if (origMsg != nullptr) { - mDelegate->OnRendezvousMessageReceived(buffer); + PacketBuffer::Free(origMsg); } + + return err; } CHIP_ERROR RendezvousSession::WaitForPairing(Optional nodeId, uint32_t setupPINCode) diff --git a/src/transport/RendezvousSession.h b/src/transport/RendezvousSession.h index 2dc41ca7a931cb..d789c6dc664091 100644 --- a/src/transport/RendezvousSession.h +++ b/src/transport/RendezvousSession.h @@ -49,7 +49,7 @@ class RendezvousSession : public SecurePairingSessionDelegate, public Rendezvous SecurePairingSession & GetPairingSession() { return mPairingSession; }; //////////// SecurePairingSessionDelegate Implementation /////////////// - virtual CHIP_ERROR SendMessage(System::PacketBuffer * buffer) override; + virtual CHIP_ERROR SendMessage(System::PacketBuffer * msgBuf) override; virtual void OnPairingError(CHIP_ERROR err) override; virtual void OnPairingComplete() override; @@ -60,16 +60,23 @@ class RendezvousSession : public SecurePairingSessionDelegate, public Rendezvous void OnRendezvousMessageReceived(PacketBuffer * buffer) override; private: + CHIP_ERROR SendPairingMessage(System::PacketBuffer * msgBug); + CHIP_ERROR HandlePairingMessage(System::PacketBuffer * msgBug); CHIP_ERROR Pair(Optional nodeId, uint32_t setupPINCode); CHIP_ERROR WaitForPairing(Optional nodeId, uint32_t setupPINCode); + CHIP_ERROR SendSecureMessage(System::PacketBuffer * msgBug); + CHIP_ERROR HandleSecureMessage(System::PacketBuffer * msgBuf); + Transport::Base * mTransport = nullptr; ///< Underlying transport RendezvousSessionDelegate * mDelegate = nullptr; ///< Underlying transport events const RendezvousParameters mParams; ///< Rendezvous configuration SecurePairingSession mPairingSession; - uint16_t mNextKeyId = 0; - bool mPairingInProgress = false; + SecureSession mSecureSession; + bool mPairingInProgress = false; + uint32_t mSecureMessageIndex = 0; + uint16_t mNextKeyId = 0; }; } // namespace chip