blob: 57b38b960a91ebd400473f1f6481860da9016733 [file] [log] [blame]
/*
*
* Copyright (c) 2020 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.
*/
/**
* @file
* This file defines a secure transport layer which adds encryption to data
* sent over a transport.
*
*/
#pragma once
#include <utility>
#include <core/CHIPCore.h>
#include <inet/IPAddress.h>
#include <inet/IPEndPointBasis.h>
#include <support/CodeUtils.h>
#include <support/DLLUtil.h>
#include <transport/PeerConnections.h>
#include <transport/SecurePairingSession.h>
#include <transport/SecureSession.h>
#include <transport/TransportMgr.h>
#include <transport/raw/Base.h>
#include <transport/raw/PeerAddress.h>
#include <transport/raw/Tuple.h>
namespace chip {
class SecureSessionMgr;
class SecureSessionHandle
{
public:
SecureSessionHandle() : mPeerNodeId(kAnyNodeId), mPeerKeyId(0) {}
SecureSessionHandle(NodeId peerNodeId, uint16_t peerKeyId) : mPeerNodeId(peerNodeId), mPeerKeyId(peerKeyId) {}
bool operator==(const SecureSessionHandle & that) const
{
return mPeerNodeId == that.mPeerNodeId && mPeerKeyId == that.mPeerKeyId;
}
private:
friend class SecureSessionMgr;
NodeId mPeerNodeId;
uint16_t mPeerKeyId;
};
/**
* @brief
* Tracks ownership of a encrypted PacketBuffer.
*
* EncryptedPacketBufferHandle is a kind of PacketBufferHandle class and used to hold a PacketBuffer
* object whose payload has already been encrypted.
*/
class EncryptedPacketBufferHandle final : public System::PacketBufferHandle
{
public:
EncryptedPacketBufferHandle() : mMsgId(0) {}
EncryptedPacketBufferHandle(EncryptedPacketBufferHandle && aBuffer) :
PacketBufferHandle(std::move(aBuffer)), mMsgId(aBuffer.mMsgId)
{}
void operator=(EncryptedPacketBufferHandle && aBuffer)
{
PacketBufferHandle::operator=(std::move(aBuffer));
mMsgId = aBuffer.mMsgId;
}
uint32_t GetMsgId() const { return mMsgId; }
/**
* Creates a copy of the data in this packet.
*
* Does NOT support chained buffers.
*
* @returns empty handle on allocation failure.
*/
EncryptedPacketBufferHandle CloneData() { return EncryptedPacketBufferHandle(PacketBufferHandle::CloneData()); }
private:
// Allow SecureSessionMgr to assign or construct us from a PacketBufferHandle
friend class SecureSessionMgr;
EncryptedPacketBufferHandle(PacketBufferHandle && aBuffer) : PacketBufferHandle(std::move(aBuffer)), mMsgId(0) {}
void operator=(PacketBufferHandle && aBuffer)
{
PacketBufferHandle::operator=(std::move(aBuffer));
mMsgId = 0;
}
uint32_t mMsgId; // The message identifier of the CHIP message awaiting acknowledgment.
};
/**
* @brief
* This class provides a skeleton for the callback functions. The functions will be
* called by SecureSssionMgrBase object on specific events. If the user of SecureSessionMgr
* is interested in receiving these callbacks, they can specialize this class and handle
* each trigger in their implementation of this class.
*/
class DLL_EXPORT SecureSessionMgrDelegate
{
public:
/**
* @brief
* Called when a new message is received. The function must internally release the
* msgBuf after processing it.
*
* @param packetHeader The message header
* @param payloadHeader The payload header
* @param session The handle to the secure session
* @param msgBuf The received message
* @param mgr A pointer to the SecureSessionMgr
*/
virtual void OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
SecureSessionHandle session, System::PacketBufferHandle msgBuf, SecureSessionMgr * mgr)
{}
/**
* @brief
* Called when received message processing resulted in error
*
* @param error error code
* @param source network entity that sent the message
* @param mgr A pointer to the SecureSessionMgr
*/
virtual void OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source, SecureSessionMgr * mgr) {}
/**
* @brief
* Called when a new pairing is being established
*
* @param session The handle to the secure session
* @param mgr A pointer to the SecureSessionMgr
*/
virtual void OnNewConnection(SecureSessionHandle session, SecureSessionMgr * mgr) {}
/**
* @brief
* Called when a new connection is closing
*
* @param session The handle to the secure session
* @param mgr A pointer to the SecureSessionMgr
*/
virtual void OnConnectionExpired(SecureSessionHandle session, SecureSessionMgr * mgr) {}
virtual ~SecureSessionMgrDelegate() {}
};
class DLL_EXPORT SecureSessionMgr : public TransportMgrDelegate
{
public:
SecureSessionMgr();
~SecureSessionMgr() override;
/**
* @brief
* Send a message to a currently connected peer.
*
* @details
* msgBuf contains the data to be transmitted. If bufferRetainSlot is not null and this function
* returns success, the encrypted data that was sent, as well as various other information needed
* to retransmit it, will be stored in *bufferRetainSlot.
*/
CHIP_ERROR SendMessage(SecureSessionHandle session, System::PacketBufferHandle && msgBuf);
CHIP_ERROR SendMessage(SecureSessionHandle session, PayloadHeader & payloadHeader, System::PacketBufferHandle && msgBuf,
EncryptedPacketBufferHandle * bufferRetainSlot = nullptr);
CHIP_ERROR SendEncryptedMessage(SecureSessionHandle session, EncryptedPacketBufferHandle msgBuf,
EncryptedPacketBufferHandle * bufferRetainSlot);
Transport::PeerConnectionState * GetPeerConnectionState(SecureSessionHandle session);
/**
* @brief
* Set the callback object.
*
* @details
* Release if there was an existing callback object
*/
void SetDelegate(SecureSessionMgrDelegate * cb) { mCB = cb; }
/**
* @brief
* Establish a new pairing with a peer node
*
* @details
* This method sets up a new pairing with the peer node. It also
* establishes the security keys for secure communication with the
* peer node.
*/
CHIP_ERROR NewPairing(const Optional<Transport::PeerAddress> & peerAddr, NodeId peerNodeId, SecurePairingSession * pairing);
/**
* @brief
* Return the System Layer pointer used by current SecureSessionMgr.
*/
System::Layer * SystemLayer() { return mSystemLayer; }
/**
* @brief
* Initialize a Secure Session Manager
*
* @param localNodeId Node id for the current node
* @param systemLayer System, layer to use
* @param transportMgr Transport to use
*/
CHIP_ERROR Init(NodeId localNodeId, System::Layer * systemLayer, TransportMgrBase * transportMgr);
/**
* @brief
* Return the transport type of current connection to the node with id peerNodeId.
* 'Transport::Type::kUndefined' will be returned if the connection to the specified
* peer node does not exist.
*/
Transport::Type GetTransportType(NodeId peerNodeId);
protected:
/**
* @brief
* Handle received secure message. Implements TransportMgrDelegate
*
* @param header the received message header
* @param source the source address of the package
* @param msgBuf the buffer of (encrypted) payload
*/
void OnMessageReceived(const PacketHeader & header, const Transport::PeerAddress & source,
System::PacketBufferHandle msgBuf) override;
private:
/**
* The State of a secure transport object.
*/
enum class State
{
kNotReady, /**< State before initialization. */
kInitialized, /**< State when the object is ready connect to other peers. */
};
enum class EncryptionState
{
kPayloadIsEncrypted,
kPayloadIsUnencrypted,
};
System::Layer * mSystemLayer = nullptr;
NodeId mLocalNodeId; // < Id of the current node
Transport::PeerConnections<CHIP_CONFIG_PEER_CONNECTION_POOL_SIZE> mPeerConnections; // < Active connections to other peers
State mState; // < Initialization state of the object
SecureSessionMgrDelegate * mCB = nullptr;
TransportMgrBase * mTransportMgr = nullptr;
CHIP_ERROR EncryptPayload(Transport::PeerConnectionState * state, PayloadHeader & payloadHeader, PacketHeader & packetHeader,
System::PacketBufferHandle & msgBuf);
CHIP_ERROR SendMessage(SecureSessionHandle session, PayloadHeader & payloadHeader, PacketHeader & packetHeader,
System::PacketBufferHandle msgBuf, EncryptedPacketBufferHandle * bufferRetainSlot,
EncryptionState encryptionState);
/** Schedules a new oneshot timer for checking connection expiry. */
void ScheduleExpiryTimer();
/** Cancels any active timers for connection expiry checks. */
void CancelExpiryTimer();
/**
* Called when a specific connection expires.
*/
void HandleConnectionExpired(const Transport::PeerConnectionState & state);
/**
* Callback for timer expiry check
*/
static void ExpiryTimerCallback(System::Layer * layer, void * param, System::Error error);
};
} // namespace chip