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 Command TLV Types. 158 * 159 */ 160 enum CommandTlvType : 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 kTlvGetProvisioningURL = 13, ///< TCAT provisioning URL query TLV 172 kTlvPresentPskdHash = 16, ///< TCAT commissioner rights elevation request TLV using PSKd hash 173 kTlvPresentPskcHash = 17, ///< TCAT commissioner rights elevation request TLV using PSKc hash 174 kTlvPresentInstallCodeHash = 18, ///< TCAT commissioner rights elevation request TLV using install code 175 kTlvRequestRandomNumChallenge = 19, ///< TCAT random number challenge query TLV 176 kTlvRequestPskdHash = 20, ///< TCAT PSKd hash request TLV 177 178 // Command Class Commissioning 179 kTlvSetActiveOperationalDataset = 32, ///< TCAT active operational dataset TLV 180 kTlvSetActiveOperationalDatasetAlternative = 33, ///< TCAT active operational dataset alternative #1 TLV 181 kTlvGetProvisioningTlvs = 36, ///< TCAT provisioning TLVs query TLV 182 kTlvGetCommissionerCertificate = 37, ///< TCAT commissioner certificate query TLV 183 kTlvGetDiagnosticTlvs = 38, ///< TCAT diagnostics TLVs query TLV 184 kTlvStartThreadInterface = 39, ///< TCAT start thread interface request TLV 185 kTlvStopThreadInterface = 40, ///< TCAT stop thread interface request TLV 186 187 // Command Class Extraction 188 kTlvGetActiveOperationalDataset = 64, ///< TCAT active oerational dataset query TLV 189 kTlvGetActiveOperationalDatasetAlternative = 65, ///< TCAT active oerational dataset alternative #1 query TLV 190 191 // Command Class Decommissioning 192 kTlvDecommission = 96, ///< TCAT decommission request TLV 193 194 // Command Class Application 195 kTlvSelectApplicationLayerUdp = 128, ///< TCAT select UDP protocol application layer request TLV 196 kTlvSelectApplicationLayerTcp = 129, ///< TCAT select TCP protocol application layer request TLV 197 kTlvSendApplicationData = 130, ///< TCAT send application data TLV 198 kTlvSendVendorSpecificData = 159, ///< TCAT send vendor specific command or data TLV 199 200 // Command Class CCM 201 kTlvSetLDevIdOperationalCert = 160, ///< TCAT LDevID operational certificate TLV 202 kTlvSetLDevIdPrivateKey = 161, ///< TCAT LDevID operational certificate pricate key TLV 203 kTlvSetDomainCaCert = 162, ///< TCAT domain CA certificate TLV 204 }; 205 206 /** 207 * TCAT Response Types. 208 * 209 */ 210 enum StatusCode : uint8_t 211 { 212 kStatusSuccess = OT_TCAT_STATUS_SUCCESS, ///< Command or request was successfully processed 213 kStatusUnsupported = OT_TCAT_STATUS_UNSUPPORTED, ///< Requested command or received TLV is not supported 214 kStatusParseError = OT_TCAT_STATUS_PARSE_ERROR, ///< Request / command could not be parsed correctly 215 kStatusValueError = OT_TCAT_STATUS_VALUE_ERROR, ///< The value of the transmitted TLV has an error 216 kStatusGeneralError = OT_TCAT_STATUS_GENERAL_ERROR, ///< An error not matching any other category occurred 217 kStatusBusy = OT_TCAT_STATUS_BUSY, ///< Command cannot be executed because the resource is busy 218 kStatusUndefined = OT_TCAT_STATUS_UNDEFINED, ///< The requested value, data or service is not defined 219 ///< (currently) or not present 220 kStatusHashError = OT_TCAT_STATUS_HASH_ERROR, ///< The hash value presented by the commissioner was incorrect 221 kStatusUnauthorized = 222 OT_TCAT_STATUS_UNAUTHORIZED, ///< Sender does not have sufficient authorization for the given command 223 }; 224 225 /** 226 * Represents TCAT application protocol. 227 * 228 */ 229 enum TcatApplicationProtocol : uint8_t 230 { 231 kApplicationProtocolNone = 232 OT_TCAT_APPLICATION_PROTOCOL_NONE, ///< Message which has been sent without activating the TCAT agent 233 kApplicationProtocolUdp = OT_TCAT_APPLICATION_PROTOCOL_STATUS, ///< Message directed to a UDP service 234 kApplicationProtocolTcp = OT_TCAT_APPLICATION_PROTOCOL_TCP, ///< Message directed to a TCP service 235 }; 236 237 /** 238 * Represents a TCAT certificate V3 extension attribute (OID 1.3.6.1.4.1.44970.x). 239 * 240 */ 241 enum TcatCertificateAttribute 242 { 243 kCertificateDomainName = 1, 244 kCertificateThreadVersion = 2, 245 kCertificateAuthorizationField = 3, 246 kCertificateNetworkName = 4, 247 kCertificateExtendedPanId = 5, 248 }; 249 250 /** 251 * Represents TCAT status. 252 * 253 */ 254 enum State : uint8_t 255 { 256 kStateDisabled, 257 kStateEnabled, 258 kStateConnected, 259 }; 260 261 /** 262 * Represents Device ID type. 263 * 264 */ 265 enum TcatDeviceIdType : uint8_t 266 { 267 kTcatDeviceIdEmpty = OT_TCAT_DEVICE_ID_EMPTY, 268 kTcatDeviceIdOui24 = OT_TCAT_DEVICE_ID_OUI24, 269 kTcatDeviceIdOui36 = OT_TCAT_DEVICE_ID_OUI36, 270 kTcatDeviceIdDiscriminator = OT_TCAT_DEVICE_ID_DISCRIMINATOR, 271 kTcatDeviceIdIanaPen = OT_TCAT_DEVICE_ID_IANAPEN, 272 }; 273 274 /** 275 * Initializes the TCAT agent object. 276 * 277 * @param[in] aInstance A reference to the OpenThread instance. 278 * 279 */ 280 explicit TcatAgent(Instance &aInstance); 281 282 /** 283 * Enables the TCAT agent. 284 * 285 * @param[in] aAppDataReceiveCallback A pointer to a function that is called when the user data is received. 286 * @param[in] aHandler A pointer to a function that is called when the join operation completes. 287 * @param[in] aContext A context pointer. 288 * 289 * @retval kErrorNone Successfully started the TCAT agent. 290 * @retval kErrorFailed Failed to start due to missing vendor info. 291 * 292 */ 293 Error Start(AppDataReceiveCallback aAppDataReceiveCallback, JoinCallback aHandler, void *aContext); 294 295 /** 296 * Stops the TCAT agent. 297 * 298 */ 299 void Stop(void); 300 301 /** 302 * Set the TCAT Vendor Info object 303 * 304 * @param[in] aVendorInfo A pointer to the Vendor Information (must remain valid after the method call). 305 * 306 */ 307 Error SetTcatVendorInfo(const VendorInfo &aVendorInfo); 308 309 /** 310 * Indicates whether or not the TCAT agent is enabled. 311 * 312 * @retval TRUE The TCAT agent is enabled. 313 * @retval FALSE The TCAT agent is not enabled. 314 * 315 */ IsEnabled(void) const316 bool IsEnabled(void) const { return mState != kStateDisabled; } 317 318 /** 319 * Indicates whether or not the TCAT agent is connected. 320 * 321 * @retval TRUE The TCAT agent is connected with a TCAT commissioner. 322 * @retval FALSE The TCAT agent is not connected. 323 * 324 */ IsConnected(void) const325 bool IsConnected(void) const { return mState == kStateConnected; } 326 327 /** 328 * Indicates whether or not a TCAT command class is authorized for use. 329 * 330 * @param[in] aCommandClass Command class to subject to authorization check. 331 * 332 * @retval TRUE The command class is authorized for use by the present TCAT commissioner. 333 * @retval FALSE The command class is not authorized for use. 334 * 335 */ 336 bool IsCommandClassAuthorized(CommandClass aCommandClass) const; 337 338 /** 339 * Gets TCAT advertisement data. 340 * 341 * @param[out] aLen Advertisement data length (up to OT_TCAT_ADVERTISEMENT_MAX_LEN). 342 * @param[out] aAdvertisementData Advertisement data. 343 * 344 * @retval kErrorNone Successfully retrieved the TCAT advertisement data. 345 * @retval kErrorInvalidArgs The data could not be retrieved, or aAdvertisementData is null. 346 * 347 */ 348 Error GetAdvertisementData(uint16_t &aLen, uint8_t *aAdvertisementData); 349 350 private: 351 Error Connected(MeshCoP::SecureTransport &aTlsContext); 352 void Disconnected(void); 353 354 Error HandleSingleTlv(const Message &aIncomingMessage, Message &aOutgoingMessage); 355 Error HandleSetActiveOperationalDataset(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength); 356 Error HandleDecomission(void); 357 Error HandlePing(const Message &aIncomingMessage, 358 Message &aOutgoingMessage, 359 uint16_t aOffset, 360 uint16_t aLength, 361 bool &response); 362 Error HandleGetNetworkName(Message &aOutgoingMessage, bool &response); 363 Error HandleGetDeviceId(Message &aOutgoingMessage, bool &response); 364 Error HandleGetExtPanId(Message &aOutgoingMessage, bool &response); 365 Error HandleGetProvisioningUrl(Message &aOutgoingMessage, bool &response); 366 Error HandleStartThreadInterface(void); 367 368 bool CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissionerCommandClassFlags, 369 CommandClassFlags aDeviceCommandClassFlags, 370 Dataset *aDataset) const; 371 bool CanProcessTlv(uint8_t aTlvType) const; 372 CommandClass GetCommandClass(uint8_t aTlvType) const; 373 374 static constexpr uint16_t kJoinerUdpPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT; 375 static constexpr uint16_t kPingPayloadMaxLength = 512; 376 static constexpr uint16_t kProvisioningUrlMaxLength = 64; 377 static constexpr uint16_t kTcatMaxDeviceIdSize = OT_TCAT_MAX_DEVICEID_SIZE; 378 379 JoinerPskd mJoinerPskd; 380 const VendorInfo *mVendorInfo; 381 Callback<JoinCallback> mJoinCallback; 382 Callback<AppDataReceiveCallback> mAppDataReceiveCallback; 383 CertificateAuthorizationField mCommissionerAuthorizationField; 384 CertificateAuthorizationField mDeviceAuthorizationField; 385 TcatApplicationProtocol mCurrentApplicationProtocol; 386 NetworkName mCommissionerNetworkName; 387 NetworkName mCommissionerDomainName; 388 ExtendedPanId mCommissionerExtendedPanId; 389 char mCurrentServiceName[OT_TCAT_MAX_SERVICE_NAME_LENGTH + 1]; 390 State mState; 391 bool mCommissionerHasNetworkName : 1; 392 bool mCommissionerHasDomainName : 1; 393 bool mCommissionerHasExtendedPanId : 1; 394 395 friend class Ble::BleSecure; 396 }; 397 398 } // namespace MeshCoP 399 400 DefineCoreType(otTcatVendorInfo, MeshCoP::TcatAgent::VendorInfo); 401 402 DefineMapEnum(otTcatApplicationProtocol, MeshCoP::TcatAgent::TcatApplicationProtocol); 403 DefineMapEnum(otTcatAdvertisedDeviceIdType, MeshCoP::TcatAgent::TcatDeviceIdType); 404 405 // Command class TLVs 406 typedef UintTlvInfo<MeshCoP::TcatAgent::kTlvResponseWithStatus, uint8_t> ResponseWithStatusTlv; 407 408 /** 409 * Represent Device Type and Status 410 * 411 */ 412 struct DeviceTypeAndStatus 413 { 414 uint8_t mRsv : 1; 415 bool mMultiradioSupport : 1; 416 bool mStoresActiveOpertonalDataset : 1; 417 bool mIsCommisionned : 1; 418 bool mThreadNetworkActive : 1; 419 bool mIsBorderRouter : 1; 420 bool mRxOnWhenIdle : 1; 421 bool mDeviceType : 1; 422 }; 423 424 static constexpr uint8_t kTlvVendorOui24Length = 3; 425 static constexpr uint8_t kTlvVendorOui36Length = 5; 426 static constexpr uint8_t kTlvDeviceDiscriminatorLength = 5; 427 static constexpr uint8_t kTlvBleLinkCapabilitiesLength = 1; 428 static constexpr uint8_t kTlvDeviceTypeAndStatusLength = 1; 429 static constexpr uint8_t kTlvVendorIanaPenLength = 4; 430 431 enum TcatAdvertisementTlvType : uint8_t 432 { 433 kTlvVendorOui24 = 1, ///< TCAT vendor OUI 24 434 kTlvVendorOui36 = 2, ///< TCAT vendor OUI 36 435 kTlvDeviceDiscriminator = 3, ///< TCAT random vendor discriminator 436 kTlvDeviceTypeAndStatus = 4, ///< TCAT Thread device type and status 437 kTlvBleLinkCapabilities = 5, ///< TCAT BLE link capabilities of device 438 kTlvVendorIanaPen = 6, ///< TCAT Vendor IANA PEN 439 }; 440 441 } // namespace ot 442 443 #endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE 444 445 #endif // TCAT_AGENT_HPP_ 446