1 /*
2  *  Copyright (c) 2023, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *  Implements the TCAT Agent service.
32  */
33 
34 #ifndef TCAT_AGENT_HPP_
35 #define TCAT_AGENT_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
40 
41 #include <openthread/tcat.h>
42 #include <openthread/platform/ble.h>
43 
44 #include "common/as_core_type.hpp"
45 #include "common/callback.hpp"
46 #include "common/locator.hpp"
47 #include "common/log.hpp"
48 #include "common/message.hpp"
49 #include "common/non_copyable.hpp"
50 #include "mac/mac_types.hpp"
51 #include "meshcop/dataset.hpp"
52 #include "meshcop/meshcop.hpp"
53 #include "meshcop/meshcop_tlvs.hpp"
54 #include "meshcop/secure_transport.hpp"
55 
56 namespace ot {
57 
58 namespace Ble {
59 class BleSecure;
60 }
61 
62 namespace MeshCoP {
63 
64 class TcatAgent : public InstanceLocator, private NonCopyable
65 {
66 public:
67     /**
68      * Pointer to call when application data was received over the TLS connection.
69      *
70      *  Please see otHandleTcatApplicationDataReceive for details.
71      *
72      */
73     typedef otHandleTcatApplicationDataReceive AppDataReceiveCallback;
74 
75     /**
76      * Pointer to call to notify the completion of a join operation.
77      *
78      * Please see otHandleTcatJoin for details.
79      *
80      */
81     typedef otHandleTcatJoin JoinCallback;
82 
83     /**
84      * Represents a TCAT command class.
85      *
86      */
87     enum CommandClass
88     {
89         kGeneral            = OT_TCAT_COMMAND_CLASS_GENERAL,         ///< TCAT commands related to general operations
90         kCommissioning      = OT_TCAT_COMMAND_CLASS_COMMISSIONING,   ///< TCAT commands related to commissioning
91         kExtraction         = OT_TCAT_COMMAND_CLASS_EXTRACTION,      ///< TCAT commands related to key extraction
92         kTlvDecommissioning = OT_TCAT_COMMAND_CLASS_DECOMMISSIONING, ///< TCAT commands related to de-commissioning
93         kApplication        = OT_TCAT_COMMAND_CLASS_APPLICATION,     ///< TCAT commands related to application layer
94         kInvalid ///< TCAT command belongs to reserved pool or is invalid
95     };
96 
97     /**
98      * The certificate authorization field header type to indicate the type and version of the certificate.
99      *
100      */
101     enum CertificateAuthorizationFieldHeader : uint8_t
102     {
103         kCommissionerFlag = 1 << 0, ///< TCAT commissioner ('1') or device ('0')
104         kHeaderVersion    = 0xD0,   ///< Header version (3 bits)
105     };
106 
107     /**
108      * The command class flag type to indicate which requirements apply for a given command class.
109      *
110      */
111     enum CommandClassFlags : uint8_t
112     {
113         kAccessFlag        = 1 << 0, ///< Access to the command class (device: without without additional requirements).
114         kPskdFlag          = 1 << 1, ///< Access requires proof-of-possession of the device's PSKd
115         kNetworkNameFlag   = 1 << 2, ///< Access requires matching network name
116         kExtendedPanIdFlag = 1 << 3, ///< Access requires matching XPANID
117         kThreadDomainFlag  = 1 << 4, ///< Access requires matching XPANID
118         kPskcFlag          = 1 << 5, ///< Access requires proof-of-possession of the device's PSKc
119     };
120 
121     /**
122      *
123      * Represents a data structure for storing TCAT Commissioner authorization information in the
124      * certificate ASN.1 field 1.3.6.1.4.1.44970.3.
125      *
126      */
127     OT_TOOL_PACKED_BEGIN
128     struct CertificateAuthorizationField
129     {
130         CertificateAuthorizationFieldHeader mHeader;               ///< Typ and version
131         CommandClassFlags                   mCommissioningFlags;   ///< Command class flags
132         CommandClassFlags                   mExtractionFlags;      ///< Command class flags
133         CommandClassFlags                   mDecommissioningFlags; ///< Command class flags
134         CommandClassFlags                   mApplicationFlags;     ///< Command class flags
135 
136     } OT_TOOL_PACKED_END;
137 
138     typedef CertificateAuthorizationField CertificateAuthorizationField;
139 
140     /**
141      * Represents the TCAT vendor information.
142      *
143      */
144     class VendorInfo : public otTcatVendorInfo
145     {
146     public:
147         /**
148          * Validates whether the TCAT vendor information is valid.
149          *
150          * @returns Whether the parameters are valid.
151          *
152          */
153         bool IsValid(void) const;
154     };
155 
156     /**
157      * TCAT TLV Types.
158      *
159      */
160     enum TlvType : uint8_t
161     {
162         // Command Class General
163         kTlvResponseWithStatus        = 1,  ///< TCAT response with status value TLV
164         kTlvResponseWithPayload       = 2,  ///< TCAT response with payload TLV
165         kTlvResponseEvent             = 3,  ///< TCAT response event TLV (reserved)
166         kTlvGetNetworkName            = 8,  ///< TCAT network name query TLV
167         kTlvDisconnect                = 9,  ///< TCAT disconnect request TLV
168         kTlvPing                      = 10, ///< TCAT ping request TLV
169         kTlvGetDeviceId               = 11, ///< TCAT device ID query TLV
170         kTlvGetExtendedPanID          = 12, ///< TCAT extended PAN ID query TLV
171         kTlvPresentPskdHash           = 16, ///< TCAT commissioner rights elevation request TLV using PSKd hash
172         kTlvPresentPskcHash           = 17, ///< TCAT commissioner rights elevation request TLV using PSKc hash
173         kTlvPresentInstallCodeHash    = 18, ///< TCAT commissioner rights elevation request TLV using install code
174         kTlvRequestRandomNumChallenge = 19, ///< TCAT random number challenge query TLV
175         kTlvRequestPskdHash           = 20, ///< TCAT PSKd hash request TLV
176 
177         // Command Class Commissioning
178         kTlvSetActiveOperationalDataset            = 32, ///< TCAT active operational dataset TLV
179         kTlvSetActiveOperationalDatasetAlternative = 33, ///< TCAT active operational dataset alternative #1 TLV
180         kTlvGetProvisioningTlvs                    = 36, ///< TCAT provisioning TLVs query TLV
181         kTlvGetCommissionerCertificate             = 37, ///< TCAT commissioner certificate query TLV
182         kTlvGetDiagnosticTlvs                      = 38, ///< TCAT diagnostics TLVs query TLV
183         kTlvStartThreadInterface                   = 39, ///< TCAT start thread interface request TLV
184         kTlvStopThreadInterface                    = 40, ///< TCAT stop thread interface request TLV
185 
186         // Command Class Extraction
187         kTlvGetActiveOperationalDataset            = 64, ///< TCAT active oerational dataset query TLV
188         kTlvGetActiveOperationalDatasetAlternative = 65, ///< TCAT active oerational dataset alternative #1 query TLV
189 
190         // Command Class Decommissioning
191         kTlvDecommission = 96, ///< TCAT decommission request TLV
192 
193         // Command Class Application
194         kTlvSelectApplicationLayerUdp = 128, ///< TCAT select UDP protocol application layer request TLV
195         kTlvSelectApplicationLayerTcp = 129, ///< TCAT select TCP protocol application layer request TLV
196         kTlvSendApplicationData       = 130, ///< TCAT send application data TLV
197         kTlvSendVendorSpecificData    = 159, ///< TCAT send vendor specific command or data TLV
198 
199         // Command Class CCM
200         kTlvSetLDevIdOperationalCert = 160, ///< TCAT LDevID operational certificate TLV
201         kTlvSetLDevIdPrivateKey      = 161, ///< TCAT LDevID operational certificate pricate key TLV
202         kTlvSetDomainCaCert          = 162, ///< TCAT domain CA certificate TLV
203     };
204 
205     /**
206      * TCAT Response Types.
207      *
208      */
209     enum StatusCode : uint8_t
210     {
211         kStatusSuccess      = OT_TCAT_STATUS_SUCCESS,       ///< Command or request was successfully processed
212         kStatusUnsupported  = OT_TCAT_STATUS_UNSUPPORTED,   ///< Requested command or received TLV is not supported
213         kStatusParseError   = OT_TCAT_STATUS_PARSE_ERROR,   ///< Request / command could not be parsed correctly
214         kStatusValueError   = OT_TCAT_STATUS_VALUE_ERROR,   ///< The value of the transmitted TLV has an error
215         kStatusGeneralError = OT_TCAT_STATUS_GENERAL_ERROR, ///< An error not matching any other category occurred
216         kStatusBusy         = OT_TCAT_STATUS_BUSY,          ///< Command cannot be executed because the resource is busy
217         kStatusUndefined    = OT_TCAT_STATUS_UNDEFINED,     ///< The requested value, data or service is not defined
218                                                             ///< (currently) or not present
219         kStatusHashError = OT_TCAT_STATUS_HASH_ERROR, ///< The hash value presented by the commissioner was incorrect
220         kStatusUnauthorized =
221             OT_TCAT_STATUS_UNAUTHORIZED, ///< Sender does not have sufficient authorization for the given command
222     };
223 
224     /**
225      * Represents TCAT application protocol.
226      *
227      */
228     enum TcatApplicationProtocol : uint8_t
229     {
230         kApplicationProtocolNone =
231             OT_TCAT_APPLICATION_PROTOCOL_NONE, ///< Message which has been sent without activating the TCAT agent
232         kApplicationProtocolUdp = OT_TCAT_APPLICATION_PROTOCOL_STATUS, ///< Message directed to a UDP service
233         kApplicationProtocolTcp = OT_TCAT_APPLICATION_PROTOCOL_TCP,    ///< Message directed to a TCP service
234     };
235 
236     /**
237      * Represents a TCAT certificate V3 extension attribute (OID 1.3.6.1.4.1.44970.x).
238      *
239      */
240     enum TcatCertificateAttribute
241     {
242         kCertificateDomainName         = 1,
243         kCertificateAuthorizationField = 3,
244         kCertificateNetworkName        = 4,
245         kCertificateExtendedPanId      = 5,
246     };
247 
248     /**
249      * Represents TCAT status.
250      *
251      */
252     enum State : uint8_t
253     {
254         kStateDisabled,
255         kStateEnabled,
256         kStateConnected,
257     };
258 
259     /**
260      * Initializes the Joiner object.
261      *
262      * @param[in]  aInstance     A reference to the OpenThread instance.
263      *
264      */
265     explicit TcatAgent(Instance &aInstance);
266 
267     /**
268      * Enables the TCAT protocol.
269      *
270      * @param[in] aVendorInfo               A pointer to the Vendor Information (must remain valid after the method
271      * call, may be NULL).
272      * @param[in] aAppDataReceiveCallback   A pointer to a function that is called when the user data is received.
273      * @param[in] aHandler                  A pointer to a function that is called when the join operation completes.
274      * @param[in] aContext                  A context pointer.
275      *
276      * @retval kErrorNone           Successfully started the TCAT agent.
277      * @retval kErrorInvalidArgs    The aVendorInfo is invalid.
278      *
279      */
280     Error Start(const VendorInfo      &aVendorInfo,
281                 AppDataReceiveCallback aAppDataReceiveCallback,
282                 JoinCallback           aHandler,
283                 void                  *aContext);
284 
285     /**
286      * Stops the TCAT protocol.
287      *
288      */
289     void Stop(void);
290 
291     /**
292      * Indicates whether or not the TCAT agent is enabled.
293      *
294      * @retval TRUE   The TCAT agent is enabled.
295      * @retval FALSE  The TCAT agent is not enabled.
296      *
297      */
IsEnabled(void) const298     bool IsEnabled(void) const { return mState != kStateDisabled; }
299 
300     /**
301      * Indicates whether or not the TCAT agent is connected.
302      *
303      * @retval TRUE   The TCAT agent is connected.
304      * @retval FALSE  The TCAT agent is not connected.
305      *
306      */
IsConnected(void) const307     bool IsConnected(void) const { return mState == kStateConnected; }
308 
309     /**
310      * Indicates whether or not a command class is authorized.
311      *
312      * @param[in] aCommandClass Command class to subject for authorization check.
313      *
314      * @retval TRUE   The command class is authorized.
315      * @retval FALSE  The command class is not authorized.
316      *
317      */
318     bool IsCommandClassAuthorized(CommandClass aCommandClass) const;
319 
320 private:
321     Error Connected(MeshCoP::SecureTransport &aTlsContext);
322     void  Disconnected(void);
323 
324     Error HandleSingleTlv(const Message &aIncommingMessage, Message &aOutgoingMessage);
325     Error HandleSetActiveOperationalDataset(const Message &aIncommingMessage, uint16_t aOffset, uint16_t aLength);
326     Error HandleStartThreadInterface(void);
327 
328 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
329     void LogError(const char *aActionText, Error aError);
330 #else
LogError(const char *,Error)331     void LogError(const char *, Error) {}
332 #endif
333 
334     bool         CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissionerCommandClassFlags,
335                                                      CommandClassFlags aDeviceCommandClassFlags,
336                                                      Dataset          *aDataset) const;
337     bool         CanProcessTlv(uint8_t aTlvType) const;
338     CommandClass GetCommandClass(uint8_t aTlvType) const;
339 
340     static constexpr uint16_t kJoinerUdpPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT;
341 
342     JoinerPskd                       mJoinerPskd;
343     const VendorInfo                *mVendorInfo;
344     Callback<JoinCallback>           mJoinCallback;
345     Callback<AppDataReceiveCallback> mAppDataReceiveCallback;
346     CertificateAuthorizationField    mCommissionerAuthorizationField;
347     CertificateAuthorizationField    mDeviceAuthorizationField;
348     TcatApplicationProtocol          mCurrentApplicationProtocol;
349     NetworkName                      mCommissionerNetworkName;
350     NetworkName                      mCommissionerDomainName;
351     ExtendedPanId                    mCommissionerExtendedPanId;
352     char                             mCurrentServiceName[OT_TCAT_MAX_SERVICE_NAME_LENGTH + 1];
353     State                            mState;
354     bool                             mAlreadyCommissioned : 1;
355     bool                             mCommissionerHasNetworkName : 1;
356     bool                             mCommissionerHasDomainName : 1;
357     bool                             mCommissionerHasExtendedPanId : 1;
358 
359     friend class Ble::BleSecure;
360 };
361 
362 } // namespace MeshCoP
363 
364 DefineCoreType(otTcatVendorInfo, MeshCoP::TcatAgent::VendorInfo);
365 
366 DefineMapEnum(otTcatApplicationProtocol, MeshCoP::TcatAgent::TcatApplicationProtocol);
367 
368 typedef UintTlvInfo<MeshCoP::TcatAgent::kTlvResponseWithStatus, uint8_t> ResponseWithStatusTlv;
369 
370 } // namespace ot
371 
372 #endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
373 
374 #endif // TCAT_AGENT_HPP_
375