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