443262006894f98f2e8a214eda1640ba18ac6e9a
[platform/upstream/connectedhomeip.git] / src / transport / SecureSessionMgr.h
1 /*
2  *
3  *    Copyright (c) 2020-2021 Project CHIP Authors
4  *    All rights reserved.
5  *
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
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19 /**
20  * @file
21  *   This file defines a secure transport layer which adds encryption to data
22  *   sent over a transport.
23  *
24  */
25
26 #pragma once
27
28 #include <utility>
29
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>
43
44 namespace chip {
45
46 class SecureSessionMgr;
47
48 class SecureSessionHandle
49 {
50 public:
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)
54     {}
55
56     bool HasAdminId() const { return (mAdmin != Transport::kUndefinedAdminId); }
57     Transport::AdminId GetAdminId() const { return mAdmin; }
58     void SetAdminId(Transport::AdminId adminId) { mAdmin = adminId; }
59
60     bool operator==(const SecureSessionHandle & that) const
61     {
62         return mPeerNodeId == that.mPeerNodeId && mPeerKeyId == that.mPeerKeyId && mAdmin == that.mAdmin;
63     }
64
65     NodeId GetPeerNodeId() const { return mPeerNodeId; }
66     uint16_t GetPeerKeyId() const { return mPeerKeyId; }
67
68 private:
69     friend class SecureSessionMgr;
70     NodeId mPeerNodeId;
71     uint16_t mPeerKeyId;
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
75     //       such sessions.
76     Transport::AdminId mAdmin;
77 };
78
79 /**
80  * @brief
81  *  Tracks ownership of a encrypted packet buffer.
82  *
83  *  EncryptedPacketBufferHandle is a kind of PacketBufferHandle class and used to hold a packet buffer
84  *  object whose payload has already been encrypted.
85  */
86 class EncryptedPacketBufferHandle final : private System::PacketBufferHandle
87 {
88 public:
89     EncryptedPacketBufferHandle() : mMsgId(0) {}
90     EncryptedPacketBufferHandle(EncryptedPacketBufferHandle && aBuffer) :
91         PacketBufferHandle(std::move(aBuffer)), mMsgId(aBuffer.mMsgId)
92     {}
93
94     void operator=(EncryptedPacketBufferHandle && aBuffer)
95     {
96         PacketBufferHandle::operator=(std::move(aBuffer));
97         mMsgId                      = aBuffer.mMsgId;
98     }
99
100     uint32_t GetMsgId() const { return mMsgId; }
101
102     /**
103      * Creates a copy of the data in this packet.
104      *
105      * Does NOT support chained buffers.
106      *
107      * @returns empty handle on allocation failure.
108      */
109     EncryptedPacketBufferHandle CloneData() { return EncryptedPacketBufferHandle(PacketBufferHandle::CloneData()); }
110
111 #ifdef CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API
112     /**
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.
119      */
120     CHIP_ERROR ExtractPacketHeader(PacketHeader & aPacketHeader) { return aPacketHeader.DecodeAndConsume(*this); }
121
122     /**
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.
127      */
128     CHIP_ERROR InsertPacketHeader(const PacketHeader & aPacketHeader) { return aPacketHeader.EncodeBeforeData(*this); }
129 #endif // CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API
130
131 private:
132     // Allow SecureSessionMgr to assign or construct us from a PacketBufferHandle
133     friend class SecureSessionMgr;
134
135     EncryptedPacketBufferHandle(PacketBufferHandle && aBuffer) : PacketBufferHandle(std::move(aBuffer)), mMsgId(0) {}
136
137     void operator=(PacketBufferHandle && aBuffer)
138     {
139         PacketBufferHandle::operator=(std::move(aBuffer));
140         mMsgId                      = 0;
141     }
142
143     uint32_t mMsgId; // The message identifier of the CHIP message awaiting acknowledgment.
144 };
145
146 /**
147  * @brief
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.
152  */
153 class DLL_EXPORT SecureSessionMgrDelegate
154 {
155 public:
156     /**
157      * @brief
158      *   Called when a new message is received. The function must internally release the
159      *   msgBuf after processing it.
160      *
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
166      */
167     virtual void OnMessageReceived(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
168                                    SecureSessionHandle session, System::PacketBufferHandle msgBuf, SecureSessionMgr * mgr)
169     {}
170
171     /**
172      * @brief
173      *   Called when received message processing resulted in error
174      *
175      * @param error   error code
176      * @param source  network entity that sent the message
177      * @param mgr     A pointer to the SecureSessionMgr
178      */
179     virtual void OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source, SecureSessionMgr * mgr) {}
180
181     /**
182      * @brief
183      *   Called when a new pairing is being established
184      *
185      * @param session The handle to the secure session
186      * @param mgr     A pointer to the SecureSessionMgr
187      */
188     virtual void OnNewConnection(SecureSessionHandle session, SecureSessionMgr * mgr) {}
189
190     /**
191      * @brief
192      *   Called when a new connection is closing
193      *
194      * @param session The handle to the secure session
195      * @param mgr     A pointer to the SecureSessionMgr
196      */
197     virtual void OnConnectionExpired(SecureSessionHandle session, SecureSessionMgr * mgr) {}
198
199     virtual ~SecureSessionMgrDelegate() {}
200 };
201
202 class DLL_EXPORT SecureSessionMgr : public TransportMgrDelegate
203 {
204 public:
205     SecureSessionMgr();
206     ~SecureSessionMgr() override;
207
208     /**
209      *    Whether the current node initiated the pairing, or it is responding to a pairing request.
210      */
211     enum class PairingDirection
212     {
213         kInitiator, /**< We initiated the pairing request. */
214         kResponder, /**< We are responding to the pairing request. */
215     };
216
217     /**
218      * @brief
219      *   Send a message to a currently connected peer.
220      *
221      * @details
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.
225      */
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);
231
232     Transport::PeerConnectionState * GetPeerConnectionState(SecureSessionHandle session);
233
234     /**
235      * @brief
236      *   Set the callback object.
237      *
238      * @details
239      *   Release if there was an existing callback object
240      */
241     void SetDelegate(SecureSessionMgrDelegate * cb) { mCB = cb; }
242
243     /**
244      * @brief
245      *   Establish a new pairing with a peer node
246      *
247      * @details
248      *   This method sets up a new pairing with the peer node. It also
249      *   establishes the security keys for secure communication with the
250      *   peer node.
251      */
252     CHIP_ERROR NewPairing(const Optional<Transport::PeerAddress> & peerAddr, NodeId peerNodeId, PASESession * pairing,
253                           PairingDirection direction, Transport::AdminId admin, Transport::Base * transport = nullptr);
254
255     /**
256      * @brief
257      *   Return the System Layer pointer used by current SecureSessionMgr.
258      */
259     System::Layer * SystemLayer() { return mSystemLayer; }
260
261     /**
262      * @brief
263      *   Initialize a Secure Session Manager
264      *
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
269      */
270     CHIP_ERROR Init(NodeId localNodeId, System::Layer * systemLayer, TransportMgrBase * transportMgr,
271                     Transport::AdminPairingTable * admins);
272
273     /**
274      * @brief
275      *   Set local node ID
276      *
277      * @param nodeId    Node id for the current node
278      */
279     void SetLocalNodeID(NodeId nodeId) { mLocalNodeId = nodeId; }
280
281     /**
282      * @brief
283      *   Return the transport type of current connection to the node with id peerNodeId.
284      *   'Transport::Type::kUndefined' will be returned if the connection to the specified
285      *   peer node does not exist.
286      */
287     Transport::Type GetTransportType(NodeId peerNodeId);
288
289 protected:
290     /**
291      * @brief
292      *   Handle received secure message. Implements TransportMgrDelegate
293      *
294      * @param header    the received message header
295      * @param source    the source address of the package
296      * @param msgBuf    the buffer of (encrypted) payload
297      */
298     void OnMessageReceived(const PacketHeader & header, const Transport::PeerAddress & source,
299                            System::PacketBufferHandle msgBuf) override;
300
301 private:
302     /**
303      *    The State of a secure transport object.
304      */
305     enum class State
306     {
307         kNotReady,    /**< State before initialization. */
308         kInitialized, /**< State when the object is ready connect to other peers. */
309     };
310
311     enum class EncryptionState
312     {
313         kPayloadIsEncrypted,
314         kPayloadIsUnencrypted,
315     };
316
317     System::Layer * mSystemLayer = nullptr;
318     NodeId mLocalNodeId;                                                                // < Id of the current node
319     Transport::PeerConnections<CHIP_CONFIG_PEER_CONNECTION_POOL_SIZE> mPeerConnections; // < Active connections to other peers
320     State mState;                                                                       // < Initialization state of the object
321
322     SecureSessionMgrDelegate * mCB         = nullptr;
323     TransportMgrBase * mTransportMgr       = nullptr;
324     Transport::AdminPairingTable * mAdmins = nullptr;
325
326     CHIP_ERROR SendMessage(SecureSessionHandle session, PayloadHeader & payloadHeader, PacketHeader & packetHeader,
327                            System::PacketBufferHandle msgBuf, EncryptedPacketBufferHandle * bufferRetainSlot,
328                            EncryptionState encryptionState);
329
330     /** Schedules a new oneshot timer for checking connection expiry. */
331     void ScheduleExpiryTimer();
332
333     /** Cancels any active timers for connection expiry checks. */
334     void CancelExpiryTimer();
335
336     /**
337      * Called when a specific connection expires.
338      */
339     void HandleConnectionExpired(const Transport::PeerConnectionState & state);
340
341     /**
342      * Callback for timer expiry check
343      */
344     static void ExpiryTimerCallback(System::Layer * layer, void * param, System::Error error);
345 };
346
347 namespace MessagePacketBuffer {
348 /**
349  * Maximum size of a message footer, in bytes.
350  */
351 constexpr uint16_t kMaxFooterSize = kMaxTagLen;
352
353 /**
354  * Allocates a packet buffer with space for message headers and footers.
355  *
356  *  Fails and returns \c nullptr if no memory is available, or if the size requested is too large.
357  *
358  *  @param[in]  aAvailableSize  Minimum number of octets to for application data.
359  *
360  *  @return     On success, a PacketBufferHandle to the allocated buffer. On fail, \c nullptr.
361  */
362 inline System::PacketBufferHandle New(size_t aAvailableSize)
363 {
364     static_assert(System::PacketBuffer::kMaxSize > kMaxFooterSize, "inadequate capacity");
365     if (aAvailableSize > System::PacketBuffer::kMaxSize - kMaxFooterSize)
366     {
367         return System::PacketBufferHandle();
368     }
369     return System::PacketBufferHandle::New(aAvailableSize + kMaxFooterSize);
370 }
371
372 /**
373  * Allocates a packet buffer with initial contents.
374  *
375  *  @param[in]  aData           Initial buffer contents.
376  *  @param[in]  aDataSize       Size of initial buffer contents.
377  *
378  *  @return     On success, a PacketBufferHandle to the allocated buffer. On fail, \c nullptr.
379  */
380 inline System::PacketBufferHandle NewWithData(const void * aData, size_t aDataSize)
381 {
382     return System::PacketBufferHandle::NewWithData(aData, aDataSize, kMaxFooterSize);
383 }
384
385 /**
386  * Check whether a packet buffer has enough space for a message footer.
387  *
388  * @returns true if there is space, false otherwise.
389  */
390 inline bool HasFooterSpace(const System::PacketBufferHandle & aBuffer)
391 {
392     return aBuffer->AvailableDataLength() >= kMaxFooterSize;
393 }
394
395 } // namespace MessagePacketBuffer
396
397 } // namespace chip