• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     typedef otHandleTcatApplicationDataReceive AppDataReceiveCallback;
73 
74     /**
75      * Pointer to call to notify the completion of a join operation.
76      *
77      * Please see otHandleTcatJoin for details.
78      */
79     typedef otHandleTcatJoin JoinCallback;
80 
81     /**
82      * Represents a TCAT command class.
83      */
84     enum CommandClass
85     {
86         kGeneral            = OT_TCAT_COMMAND_CLASS_GENERAL,         ///< TCAT commands related to general operations
87         kCommissioning      = OT_TCAT_COMMAND_CLASS_COMMISSIONING,   ///< TCAT commands related to commissioning
88         kExtraction         = OT_TCAT_COMMAND_CLASS_EXTRACTION,      ///< TCAT commands related to key extraction
89         kTlvDecommissioning = OT_TCAT_COMMAND_CLASS_DECOMMISSIONING, ///< TCAT commands related to de-commissioning
90         kApplication        = OT_TCAT_COMMAND_CLASS_APPLICATION,     ///< TCAT commands related to application layer
91         kInvalid ///< TCAT command belongs to reserved pool or is invalid
92     };
93 
94     /**
95      * The certificate authorization field header type to indicate the type and version of the certificate.
96      */
97     enum CertificateAuthorizationFieldHeader : uint8_t
98     {
99         kCommissionerFlag = 1 << 0, ///< TCAT commissioner ('1') or device ('0')
100         kHeaderVersion    = 0xD0,   ///< Header version (3 bits)
101     };
102 
103     /**
104      * The command class flag type to indicate which requirements apply for a given command class.
105      */
106     enum CommandClassFlags : uint8_t
107     {
108         kAccessFlag        = 1 << 0, ///< Access to the command class (device: without without additional requirements).
109         kPskdFlag          = 1 << 1, ///< Access requires proof-of-possession of the device's PSKd
110         kNetworkNameFlag   = 1 << 2, ///< Access requires matching network name
111         kExtendedPanIdFlag = 1 << 3, ///< Access requires matching XPANID
112         kThreadDomainFlag  = 1 << 4, ///< Access requires matching XPANID
113         kPskcFlag          = 1 << 5, ///< Access requires proof-of-possession of the device's PSKc
114     };
115 
116     /**
117      *
118      * Represents a data structure for storing TCAT Commissioner authorization information in the
119      * certificate ASN.1 field 1.3.6.1.4.1.44970.3.
120      */
121     OT_TOOL_PACKED_BEGIN
122     struct CertificateAuthorizationField
123     {
124         CertificateAuthorizationFieldHeader mHeader;               ///< Typ and version
125         CommandClassFlags                   mCommissioningFlags;   ///< Command class flags
126         CommandClassFlags                   mExtractionFlags;      ///< Command class flags
127         CommandClassFlags                   mDecommissioningFlags; ///< Command class flags
128         CommandClassFlags                   mApplicationFlags;     ///< Command class flags
129 
130     } OT_TOOL_PACKED_END;
131 
132     typedef CertificateAuthorizationField CertificateAuthorizationField;
133 
134     /**
135      * Represents the TCAT vendor information.
136      */
137     class VendorInfo : public otTcatVendorInfo
138     {
139     public:
140         /**
141          * Validates whether the TCAT vendor information is valid.
142          *
143          * @returns Whether the parameters are valid.
144          */
145         bool IsValid(void) const;
146     };
147 
148     /**
149      * TCAT Command TLV Types.
150      */
151     enum CommandTlvType : uint8_t
152     {
153         // Command Class General
154         kTlvResponseWithStatus        = 1,  ///< TCAT response with status value TLV
155         kTlvResponseWithPayload       = 2,  ///< TCAT response with payload TLV
156         kTlvResponseEvent             = 3,  ///< TCAT response event TLV (reserved)
157         kTlvGetNetworkName            = 8,  ///< TCAT network name query TLV
158         kTlvDisconnect                = 9,  ///< TCAT disconnect request TLV
159         kTlvPing                      = 10, ///< TCAT ping request TLV
160         kTlvGetDeviceId               = 11, ///< TCAT device ID query TLV
161         kTlvGetExtendedPanID          = 12, ///< TCAT extended PAN ID query TLV
162         kTlvGetProvisioningURL        = 13, ///< TCAT provisioning URL query TLV
163         kTlvPresentPskdHash           = 16, ///< TCAT commissioner rights elevation request TLV using PSKd hash
164         kTlvPresentPskcHash           = 17, ///< TCAT commissioner rights elevation request TLV using PSKc hash
165         kTlvPresentInstallCodeHash    = 18, ///< TCAT commissioner rights elevation request TLV using install code
166         kTlvRequestRandomNumChallenge = 19, ///< TCAT random number challenge query TLV
167         kTlvRequestPskdHash           = 20, ///< TCAT PSKd hash request TLV
168 
169         // Command Class Commissioning
170         kTlvSetActiveOperationalDataset            = 32, ///< TCAT active operational dataset TLV
171         kTlvSetActiveOperationalDatasetAlternative = 33, ///< TCAT active operational dataset alternative #1 TLV
172         kTlvGetProvisioningTlvs                    = 36, ///< TCAT provisioning TLVs query TLV
173         kTlvGetCommissionerCertificate             = 37, ///< TCAT commissioner certificate query TLV
174         kTlvGetDiagnosticTlvs                      = 38, ///< TCAT diagnostics TLVs query TLV
175         kTlvStartThreadInterface                   = 39, ///< TCAT start thread interface request TLV
176         kTlvStopThreadInterface                    = 40, ///< TCAT stop thread interface request TLV
177 
178         // Command Class Extraction
179         kTlvGetActiveOperationalDataset            = 64, ///< TCAT active oerational dataset query TLV
180         kTlvGetActiveOperationalDatasetAlternative = 65, ///< TCAT active oerational dataset alternative #1 query TLV
181 
182         // Command Class Decommissioning
183         kTlvDecommission = 96, ///< TCAT decommission request TLV
184 
185         // Command Class Application
186         kTlvSelectApplicationLayerUdp = 128, ///< TCAT select UDP protocol application layer request TLV
187         kTlvSelectApplicationLayerTcp = 129, ///< TCAT select TCP protocol application layer request TLV
188         kTlvSendApplicationData       = 130, ///< TCAT send application data TLV
189         kTlvSendVendorSpecificData    = 159, ///< TCAT send vendor specific command or data TLV
190 
191         // Command Class CCM
192         kTlvSetLDevIdOperationalCert = 160, ///< TCAT LDevID operational certificate TLV
193         kTlvSetLDevIdPrivateKey      = 161, ///< TCAT LDevID operational certificate pricate key TLV
194         kTlvSetDomainCaCert          = 162, ///< TCAT domain CA certificate TLV
195     };
196 
197     /**
198      * TCAT Response Types.
199      */
200     enum StatusCode : uint8_t
201     {
202         kStatusSuccess      = OT_TCAT_STATUS_SUCCESS,       ///< Command or request was successfully processed
203         kStatusUnsupported  = OT_TCAT_STATUS_UNSUPPORTED,   ///< Requested command or received TLV is not supported
204         kStatusParseError   = OT_TCAT_STATUS_PARSE_ERROR,   ///< Request / command could not be parsed correctly
205         kStatusValueError   = OT_TCAT_STATUS_VALUE_ERROR,   ///< The value of the transmitted TLV has an error
206         kStatusGeneralError = OT_TCAT_STATUS_GENERAL_ERROR, ///< An error not matching any other category occurred
207         kStatusBusy         = OT_TCAT_STATUS_BUSY,          ///< Command cannot be executed because the resource is busy
208         kStatusUndefined    = OT_TCAT_STATUS_UNDEFINED,     ///< The requested value, data or service is not defined
209                                                             ///< (currently) or not present
210         kStatusHashError = OT_TCAT_STATUS_HASH_ERROR, ///< The hash value presented by the commissioner was incorrect
211         kStatusUnauthorized =
212             OT_TCAT_STATUS_UNAUTHORIZED, ///< Sender does not have sufficient authorization for the given command
213     };
214 
215     /**
216      * Represents TCAT application protocol.
217      */
218     enum TcatApplicationProtocol : uint8_t
219     {
220         kApplicationProtocolNone =
221             OT_TCAT_APPLICATION_PROTOCOL_NONE, ///< Message which has been sent without activating the TCAT agent
222         kApplicationProtocolUdp = OT_TCAT_APPLICATION_PROTOCOL_STATUS, ///< Message directed to a UDP service
223         kApplicationProtocolTcp = OT_TCAT_APPLICATION_PROTOCOL_TCP,    ///< Message directed to a TCP service
224     };
225 
226     /**
227      * Represents a TCAT certificate V3 extension attribute (OID 1.3.6.1.4.1.44970.x).
228      */
229     enum TcatCertificateAttribute
230     {
231         kCertificateDomainName         = 1,
232         kCertificateThreadVersion      = 2,
233         kCertificateAuthorizationField = 3,
234         kCertificateNetworkName        = 4,
235         kCertificateExtendedPanId      = 5,
236     };
237 
238     /**
239      * Represents TCAT status.
240      */
241     enum State : uint8_t
242     {
243         kStateDisabled,
244         kStateEnabled,
245         kStateConnected,
246     };
247 
248     /**
249      * Represents Device ID type.
250      */
251     enum TcatDeviceIdType : uint8_t
252     {
253         kTcatDeviceIdEmpty         = OT_TCAT_DEVICE_ID_EMPTY,
254         kTcatDeviceIdOui24         = OT_TCAT_DEVICE_ID_OUI24,
255         kTcatDeviceIdOui36         = OT_TCAT_DEVICE_ID_OUI36,
256         kTcatDeviceIdDiscriminator = OT_TCAT_DEVICE_ID_DISCRIMINATOR,
257         kTcatDeviceIdIanaPen       = OT_TCAT_DEVICE_ID_IANAPEN,
258     };
259 
260     /**
261      * Initializes the TCAT agent object.
262      *
263      * @param[in]  aInstance     A reference to the OpenThread instance.
264      */
265     explicit TcatAgent(Instance &aInstance);
266 
267     /**
268      * Enables the TCAT agent.
269      *
270      * @param[in] aAppDataReceiveCallback   A pointer to a function that is called when the user data is received.
271      * @param[in] aHandler                  A pointer to a function that is called when the join operation completes.
272      * @param[in] aContext                  A context pointer.
273      *
274      * @retval kErrorNone        Successfully started the TCAT agent.
275      * @retval kErrorFailed      Failed to start due to missing vendor info.
276      */
277     Error Start(AppDataReceiveCallback aAppDataReceiveCallback, JoinCallback aHandler, void *aContext);
278 
279     /**
280      * Stops the TCAT agent.
281      */
282     void Stop(void);
283 
284     /**
285      * Set the TCAT Vendor Info object
286      *
287      * @param[in] aVendorInfo A pointer to the Vendor Information (must remain valid after the method call).
288      */
289     Error SetTcatVendorInfo(const VendorInfo &aVendorInfo);
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      */
IsEnabled(void) const297     bool IsEnabled(void) const { return mState != kStateDisabled; }
298 
299     /**
300      * Indicates whether or not the TCAT agent is connected.
301      *
302      * @retval TRUE   The TCAT agent is connected with a TCAT commissioner.
303      * @retval FALSE  The TCAT agent is not connected.
304      */
IsConnected(void) const305     bool IsConnected(void) const { return mState == kStateConnected; }
306 
307     /**
308      * Indicates whether or not a TCAT command class is authorized for use.
309      *
310      * @param[in] aCommandClass Command class to subject to authorization check.
311      *
312      * @retval TRUE   The command class is authorized for use by the present TCAT commissioner.
313      * @retval FALSE  The command class is not authorized for use.
314      */
315     bool IsCommandClassAuthorized(CommandClass aCommandClass) const;
316 
317     /**
318      * Gets TCAT advertisement data.
319      *
320      * @param[out] aLen               Advertisement data length (up to OT_TCAT_ADVERTISEMENT_MAX_LEN).
321      * @param[out] aAdvertisementData Advertisement data.
322      *
323      * @retval kErrorNone           Successfully retrieved the TCAT advertisement data.
324      * @retval kErrorInvalidArgs    The data could not be retrieved, or aAdvertisementData is null.
325      */
326     Error GetAdvertisementData(uint16_t &aLen, uint8_t *aAdvertisementData);
327 
328     /**
329      * @brief Gets the Install Code Verify Status during the current session.
330      *
331      * @retval TRUE  The install code was correctly verified.
332      * @retval FALSE The install code was not verified.
333      */
GetInstallCodeVerifyStatus(void) const334     bool GetInstallCodeVerifyStatus(void) const { return mInstallCodeVerified; }
335 
336 private:
337     Error Connected(MeshCoP::Tls::Extension &aTls);
338     void  Disconnected(void);
339 
340     Error HandleSingleTlv(const Message &aIncomingMessage, Message &aOutgoingMessage);
341     Error HandleSetActiveOperationalDataset(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength);
342     Error HandleGetActiveOperationalDataset(Message &aOutgoingMessage, bool &aResponse);
343     Error HandleDecomission(void);
344     Error HandlePing(const Message &aIncomingMessage,
345                      Message       &aOutgoingMessage,
346                      uint16_t       aOffset,
347                      uint16_t       aLength,
348                      bool          &aResponse);
349     Error HandleGetNetworkName(Message &aOutgoingMessage, bool &aResponse);
350     Error HandleGetDeviceId(Message &aOutgoingMessage, bool &aResponse);
351     Error HandleGetExtPanId(Message &aOutgoingMessage, bool &aResponse);
352     Error HandleGetProvisioningUrl(Message &aOutgoingMessage, bool &aResponse);
353     Error HandlePresentPskdHash(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength);
354     Error HandlePresentPskcHash(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength);
355     Error HandlePresentInstallCodeHash(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength);
356     Error HandleRequestRandomNumberChallenge(Message &aOutgoingMessage, bool &aResponse);
357     Error HandleRequestPskdHash(const Message &aIncomingMessage,
358                                 Message       &aOutgoingMessage,
359                                 uint16_t       aOffset,
360                                 uint16_t       aLength,
361                                 bool          &aResponse);
362     Error HandleStartThreadInterface(void);
363     Error HandleGetCommissionerCertificate(Message &aOutgoingMessage, bool &aResponse);
364 
365     Error VerifyHash(const Message &aIncomingMessage,
366                      uint16_t       aOffset,
367                      uint16_t       aLength,
368                      const void    *aBuf,
369                      size_t         aBufLen);
370     void  CalculateHash(uint64_t aChallenge, const char *aBuf, size_t aBufLen, Crypto::HmacSha256::Hash &aHash);
371 
372     bool CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissionerCommandClassFlags,
373                                              CommandClassFlags aDeviceCommandClassFlags,
374                                              Dataset          *aDataset) const;
375 
376     bool         CanProcessTlv(uint8_t aTlvType) const;
377     CommandClass GetCommandClass(uint8_t aTlvType) const;
378 
379     static constexpr uint16_t kJoinerUdpPort             = OPENTHREAD_CONFIG_JOINER_UDP_PORT;
380     static constexpr uint16_t kPingPayloadMaxLength      = 512;
381     static constexpr uint16_t kProvisioningUrlMaxLength  = 64;
382     static constexpr uint16_t kMaxPskdLength             = OT_JOINER_MAX_PSKD_LENGTH;
383     static constexpr uint16_t kTcatMaxDeviceIdSize       = OT_TCAT_MAX_DEVICEID_SIZE;
384     static constexpr uint16_t kInstallCodeMaxSize        = 255;
385     static constexpr uint16_t kCommissionerCertMaxLength = 1024;
386 
387     JoinerPskd                       mJoinerPskd;
388     const VendorInfo                *mVendorInfo;
389     Callback<JoinCallback>           mJoinCallback;
390     Callback<AppDataReceiveCallback> mAppDataReceiveCallback;
391     CertificateAuthorizationField    mCommissionerAuthorizationField;
392     CertificateAuthorizationField    mDeviceAuthorizationField;
393     TcatApplicationProtocol          mCurrentApplicationProtocol;
394     NetworkName                      mCommissionerNetworkName;
395     NetworkName                      mCommissionerDomainName;
396     ExtendedPanId                    mCommissionerExtendedPanId;
397     char                             mCurrentServiceName[OT_TCAT_MAX_SERVICE_NAME_LENGTH + 1];
398     State                            mState;
399     bool                             mCommissionerHasNetworkName : 1;
400     bool                             mCommissionerHasDomainName : 1;
401     bool                             mCommissionerHasExtendedPanId : 1;
402     uint64_t                         mRandomChallenge;
403     bool                             mPskdVerified : 1;
404     bool                             mPskcVerified : 1;
405     bool                             mInstallCodeVerified : 1;
406 
407     friend class Ble::BleSecure;
408 };
409 
410 } // namespace MeshCoP
411 
412 DefineCoreType(otTcatVendorInfo, MeshCoP::TcatAgent::VendorInfo);
413 
414 DefineMapEnum(otTcatApplicationProtocol, MeshCoP::TcatAgent::TcatApplicationProtocol);
415 DefineMapEnum(otTcatAdvertisedDeviceIdType, MeshCoP::TcatAgent::TcatDeviceIdType);
416 
417 // Command class TLVs
418 typedef UintTlvInfo<MeshCoP::TcatAgent::kTlvResponseWithStatus, uint8_t> ResponseWithStatusTlv;
419 
420 /**
421  * Represent Device Type and Status
422  */
423 struct DeviceTypeAndStatus
424 {
425     uint8_t mRsv : 1;
426     bool    mMultiradioSupport : 1;
427     bool    mStoresActiveOpertonalDataset : 1;
428     bool    mIsCommisionned : 1;
429     bool    mThreadNetworkActive : 1;
430     bool    mIsBorderRouter : 1;
431     bool    mRxOnWhenIdle : 1;
432     bool    mDeviceType : 1;
433 };
434 
435 static constexpr uint8_t kTlvVendorOui24Length         = 3;
436 static constexpr uint8_t kTlvVendorOui36Length         = 5;
437 static constexpr uint8_t kTlvDeviceDiscriminatorLength = 5;
438 static constexpr uint8_t kTlvBleLinkCapabilitiesLength = 1;
439 static constexpr uint8_t kTlvDeviceTypeAndStatusLength = 1;
440 static constexpr uint8_t kTlvVendorIanaPenLength       = 4;
441 
442 enum TcatAdvertisementTlvType : uint8_t
443 {
444     kTlvVendorOui24         = 1, ///< TCAT vendor OUI 24
445     kTlvVendorOui36         = 2, ///< TCAT vendor OUI 36
446     kTlvDeviceDiscriminator = 3, ///< TCAT random vendor discriminator
447     kTlvDeviceTypeAndStatus = 4, ///< TCAT Thread device type and status
448     kTlvBleLinkCapabilities = 5, ///< TCAT BLE link capabilities of device
449     kTlvVendorIanaPen       = 6, ///< TCAT Vendor IANA PEN
450 };
451 
452 } // namespace ot
453 
454 #endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
455 
456 #endif // TCAT_AGENT_HPP_
457