3 * Copyright (c) 2020-2021 Project CHIP Authors
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * This file defines a secure transport layer which adds encryption to data
22 * sent over a transport.
30 #include <core/CHIPCore.h>
31 #include <inet/IPAddress.h>
32 #include <inet/IPEndPointBasis.h>
33 #include <support/CodeUtils.h>
34 #include <support/DLLUtil.h>
35 #include <transport/AdminPairingTable.h>
36 #include <transport/PASESession.h>
37 #include <transport/PeerConnections.h>
38 #include <transport/SecureSession.h>
39 #include <transport/TransportMgr.h>
40 #include <transport/raw/Base.h>
41 #include <transport/raw/PeerAddress.h>
42 #include <transport/raw/Tuple.h>
46 class SecureSessionMgr;
48 class SecureSessionHandle
51 SecureSessionHandle() : mPeerNodeId(kAnyNodeId), mPeerKeyId(0), mAdmin(Transport::kUndefinedAdminId) {}
52 SecureSessionHandle(NodeId peerNodeId, uint16_t peerKeyId, Transport::AdminId admin) :
53 mPeerNodeId(peerNodeId), mPeerKeyId(peerKeyId), mAdmin(admin)
56 bool HasAdminId() const { return (mAdmin != Transport::kUndefinedAdminId); }
57 Transport::AdminId GetAdminId() const { return mAdmin; }
58 void SetAdminId(Transport::AdminId adminId) { mAdmin = adminId; }
60 bool operator==(const SecureSessionHandle & that) const
62 return mPeerNodeId == that.mPeerNodeId && mPeerKeyId == that.mPeerKeyId && mAdmin == that.mAdmin;
65 NodeId GetPeerNodeId() const { return mPeerNodeId; }
66 uint16_t GetPeerKeyId() const { return mPeerKeyId; }
69 friend class SecureSessionMgr;
72 // TODO: Re-evaluate the storing of Admin ID in SecureSessionHandle
73 // The Admin ID will not be available for PASE and group sessions. So need
74 // to identify an approach that'll allow looking up the corresponding information for
76 Transport::AdminId mAdmin;
81 * Tracks ownership of a encrypted packet buffer.
83 * EncryptedPacketBufferHandle is a kind of PacketBufferHandle class and used to hold a packet buffer
84 * object whose payload has already been encrypted.
86 class EncryptedPacketBufferHandle final : private System::PacketBufferHandle
89 EncryptedPacketBufferHandle() : mMsgId(0) {}
90 EncryptedPacketBufferHandle(EncryptedPacketBufferHandle && aBuffer) :
91 PacketBufferHandle(std::move(aBuffer)), mMsgId(aBuffer.mMsgId)
94 void operator=(EncryptedPacketBufferHandle && aBuffer)
96 PacketBufferHandle::operator=(std::move(aBuffer));
97 mMsgId = aBuffer.mMsgId;
100 uint32_t GetMsgId() const { return mMsgId; }
103 * Creates a copy of the data in this packet.
105 * Does NOT support chained buffers.
107 * @returns empty handle on allocation failure.
109 EncryptedPacketBufferHandle CloneData() { return EncryptedPacketBufferHandle(PacketBufferHandle::CloneData()); }
111 #ifdef CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API
113 * Extracts the (unencrypted) packet header from this encrypted packet
114 * buffer. Returns error if a packet header cannot be extracted (e.g. if
115 * there are not enough bytes in this packet buffer). After this call the
116 * buffer does not have a packet header. This API is meant for
117 * unit tests only. The CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API define
118 * should not be defined normally.
120 CHIP_ERROR ExtractPacketHeader(PacketHeader & aPacketHeader) { return aPacketHeader.DecodeAndConsume(*this); }
123 * Inserts a new (unencrypted) packet header in the encrypted packet buffer
124 * based on the given PacketHeader. This API is meant for
125 * unit tests only. The CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API define
126 * should not be defined normally.
128 CHIP_ERROR InsertPacketHeader(const PacketHeader & aPacketHeader) { return aPacketHeader.EncodeBeforeData(*this); }
129 #endif // CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API
132 // Allow SecureSessionMgr to assign or construct us from a PacketBufferHandle
133 friend class SecureSessionMgr;
135 EncryptedPacketBufferHandle(PacketBufferHandle && aBuffer) : PacketBufferHandle(std::move(aBuffer)), mMsgId(0) {}
137 void operator=(PacketBufferHandle && aBuffer)
139 PacketBufferHandle::operator=(std::move(aBuffer));
143 uint32_t mMsgId; // The message identifier of the CHIP message awaiting acknowledgment.
148 * This class provides a skeleton for the callback functions. The functions will be
149 * called by SecureSssionMgrBase object on specific events. If the user of SecureSessionMgr
150 * is interested in receiving these callbacks, they can specialize this class and handle
151 * each trigger in their implementation of this class.
153 class DLL_EXPORT SecureSessionMgrDelegate
158 * Called when a new message is received. The function must internally release the
159 * msgBuf after processing it.
161 * @param packetHeader The message header
162 * @param payloadHeader The payload header
163 * @param session The handle to the secure session
164 * @param msgBuf The received message
165 * @param mgr A pointer to the SecureSessionMgr
167 virtual void OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
168 SecureSessionHandle session, System::PacketBufferHandle msgBuf, SecureSessionMgr * mgr)
173 * Called when received message processing resulted in error
175 * @param error error code
176 * @param source network entity that sent the message
177 * @param mgr A pointer to the SecureSessionMgr
179 virtual void OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source, SecureSessionMgr * mgr) {}
183 * Called when a new pairing is being established
185 * @param session The handle to the secure session
186 * @param mgr A pointer to the SecureSessionMgr
188 virtual void OnNewConnection(SecureSessionHandle session, SecureSessionMgr * mgr) {}
192 * Called when a new connection is closing
194 * @param session The handle to the secure session
195 * @param mgr A pointer to the SecureSessionMgr
197 virtual void OnConnectionExpired(SecureSessionHandle session, SecureSessionMgr * mgr) {}
199 virtual ~SecureSessionMgrDelegate() {}
202 class DLL_EXPORT SecureSessionMgr : public TransportMgrDelegate
206 ~SecureSessionMgr() override;
209 * Whether the current node initiated the pairing, or it is responding to a pairing request.
211 enum class PairingDirection
213 kInitiator, /**< We initiated the pairing request. */
214 kResponder, /**< We are responding to the pairing request. */
219 * Send a message to a currently connected peer.
222 * msgBuf contains the data to be transmitted. If bufferRetainSlot is not null and this function
223 * returns success, the encrypted data that was sent, as well as various other information needed
224 * to retransmit it, will be stored in *bufferRetainSlot.
226 CHIP_ERROR SendMessage(SecureSessionHandle session, System::PacketBufferHandle && msgBuf);
227 CHIP_ERROR SendMessage(SecureSessionHandle session, PayloadHeader & payloadHeader, System::PacketBufferHandle && msgBuf,
228 EncryptedPacketBufferHandle * bufferRetainSlot = nullptr);
229 CHIP_ERROR SendEncryptedMessage(SecureSessionHandle session, EncryptedPacketBufferHandle msgBuf,
230 EncryptedPacketBufferHandle * bufferRetainSlot);
232 Transport::PeerConnectionState * GetPeerConnectionState(SecureSessionHandle session);
236 * Set the callback object.
239 * Release if there was an existing callback object
241 void SetDelegate(SecureSessionMgrDelegate * cb) { mCB = cb; }
245 * Establish a new pairing with a peer node
248 * This method sets up a new pairing with the peer node. It also
249 * establishes the security keys for secure communication with the
252 CHIP_ERROR NewPairing(const Optional<Transport::PeerAddress> & peerAddr, NodeId peerNodeId, PASESession * pairing,
253 PairingDirection direction, Transport::AdminId admin, Transport::Base * transport = nullptr);
257 * Return the System Layer pointer used by current SecureSessionMgr.
259 System::Layer * SystemLayer() { return mSystemLayer; }
263 * Initialize a Secure Session Manager
265 * @param localNodeId Node id for the current node
266 * @param systemLayer System, layer to use
267 * @param transportMgr Transport to use
268 * @param admins A table of device administrators
270 CHIP_ERROR Init(NodeId localNodeId, System::Layer * systemLayer, TransportMgrBase * transportMgr,
271 Transport::AdminPairingTable * admins);
275 * Shutdown the Secure Session Manager. This terminates this instance
276 * of the object and reset it's state.
284 * @param nodeId Node id for the current node
286 void SetLocalNodeID(NodeId nodeId) { mLocalNodeId = nodeId; }
290 * Return the transport type of current connection to the node with id peerNodeId.
291 * 'Transport::Type::kUndefined' will be returned if the connection to the specified
292 * peer node does not exist.
294 Transport::Type GetTransportType(NodeId peerNodeId);
299 * Handle received secure message. Implements TransportMgrDelegate
301 * @param header the received message header
302 * @param source the source address of the package
303 * @param msgBuf the buffer of (encrypted) payload
305 void OnMessageReceived(const PacketHeader & header, const Transport::PeerAddress & source,
306 System::PacketBufferHandle msgBuf) override;
310 * The State of a secure transport object.
314 kNotReady, /**< State before initialization. */
315 kInitialized, /**< State when the object is ready connect to other peers. */
318 enum class EncryptionState
321 kPayloadIsUnencrypted,
324 System::Layer * mSystemLayer = nullptr;
325 NodeId mLocalNodeId; // < Id of the current node
326 Transport::PeerConnections<CHIP_CONFIG_PEER_CONNECTION_POOL_SIZE> mPeerConnections; // < Active connections to other peers
327 State mState; // < Initialization state of the object
329 SecureSessionMgrDelegate * mCB = nullptr;
330 TransportMgrBase * mTransportMgr = nullptr;
331 Transport::AdminPairingTable * mAdmins = nullptr;
333 CHIP_ERROR SendMessage(SecureSessionHandle session, PayloadHeader & payloadHeader, PacketHeader & packetHeader,
334 System::PacketBufferHandle msgBuf, EncryptedPacketBufferHandle * bufferRetainSlot,
335 EncryptionState encryptionState);
337 /** Schedules a new oneshot timer for checking connection expiry. */
338 void ScheduleExpiryTimer();
340 /** Cancels any active timers for connection expiry checks. */
341 void CancelExpiryTimer();
344 * Called when a specific connection expires.
346 void HandleConnectionExpired(const Transport::PeerConnectionState & state);
349 * Callback for timer expiry check
351 static void ExpiryTimerCallback(System::Layer * layer, void * param, System::Error error);
354 namespace MessagePacketBuffer {
356 * Maximum size of a message footer, in bytes.
358 constexpr uint16_t kMaxFooterSize = kMaxTagLen;
361 * Allocates a packet buffer with space for message headers and footers.
363 * Fails and returns \c nullptr if no memory is available, or if the size requested is too large.
365 * @param[in] aAvailableSize Minimum number of octets to for application data.
367 * @return On success, a PacketBufferHandle to the allocated buffer. On fail, \c nullptr.
369 inline System::PacketBufferHandle New(size_t aAvailableSize)
371 static_assert(System::PacketBuffer::kMaxSize > kMaxFooterSize, "inadequate capacity");
372 if (aAvailableSize > System::PacketBuffer::kMaxSize - kMaxFooterSize)
374 return System::PacketBufferHandle();
376 return System::PacketBufferHandle::New(aAvailableSize + kMaxFooterSize);
380 * Allocates a packet buffer with initial contents.
382 * @param[in] aData Initial buffer contents.
383 * @param[in] aDataSize Size of initial buffer contents.
385 * @return On success, a PacketBufferHandle to the allocated buffer. On fail, \c nullptr.
387 inline System::PacketBufferHandle NewWithData(const void * aData, size_t aDataSize)
389 return System::PacketBufferHandle::NewWithData(aData, aDataSize, kMaxFooterSize);
393 * Check whether a packet buffer has enough space for a message footer.
395 * @returns true if there is space, false otherwise.
397 inline bool HasFooterSpace(const System::PacketBufferHandle & aBuffer)
399 return aBuffer->AvailableDataLength() >= kMaxFooterSize;
402 } // namespace MessagePacketBuffer