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