Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2020 Project CHIP Authors 4 : * 5 : * Licensed under the Apache License, Version 2.0 (the "License"); 6 : * you may not use this file except in compliance with the License. 7 : * You may obtain a copy of the License at 8 : * 9 : * http://www.apache.org/licenses/LICENSE-2.0 10 : * 11 : * Unless required by applicable law or agreed to in writing, software 12 : * distributed under the License is distributed on an "AS IS" BASIS, 13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 : * See the License for the specific language governing permissions and 15 : * limitations under the License. 16 : */ 17 : 18 : /** 19 : * @file 20 : * The implementation of the Setup Payload. Currently only needed to 21 : * verify the validity of a Setup Payload 22 : */ 23 : 24 : #include "SetupPayload.h" 25 : 26 : #include <lib/core/CHIPCore.h> 27 : #include <lib/core/CHIPVendorIdentifiers.hpp> 28 : #include <lib/core/TLV.h> 29 : #include <lib/core/TLVData.h> 30 : #include <lib/core/TLVUtilities.h> 31 : #include <lib/support/CodeUtils.h> 32 : #include <utility> 33 : 34 : namespace chip { 35 : 36 : // Spec 5.1.4.2 CHIPCommon tag numbers are in the range [0x00, 0x7F] 37 43 : bool SetupPayload::IsCommonTag(uint8_t tag) 38 : { 39 43 : return tag < 0x80; 40 : } 41 : 42 : // Spec 5.1.4.1 Manufacture-specific tag numbers are in the range [0x80, 0xFF] 43 24 : bool SetupPayload::IsVendorTag(uint8_t tag) 44 : { 45 24 : return !IsCommonTag(tag); 46 : } 47 : 48 : // Check the Setup Payload for validity 49 : // 50 : // `vendor_id` and `product_id` are allowed all of uint16_t 51 37 : bool PayloadContents::isValidQRCodePayload() const 52 : { 53 : // 3-bit value specifying the QR code payload version. 54 37 : if (version >= 1 << kVersionFieldLengthInBits) 55 : { 56 1 : return false; 57 : } 58 : 59 36 : if (static_cast<uint8_t>(commissioningFlow) > static_cast<uint8_t>((1 << kCommissioningFlowFieldLengthInBits) - 1)) 60 : { 61 1 : return false; 62 : } 63 : 64 : // Device Commissioning Flow 65 : // 0: Standard commissioning flow: such a device, when uncommissioned, always enters commissioning mode upon power-up, subject 66 : // to the rules in [ref_Announcement_Commencement]. 1: User-intent commissioning flow: user action required to enter 67 : // commissioning mode. 2: Custom commissioning flow: interaction with a vendor-specified means is needed before commissioning. 68 : // 3: Reserved 69 35 : if (commissioningFlow != CommissioningFlow::kStandard && commissioningFlow != CommissioningFlow::kUserActionRequired && 70 2 : commissioningFlow != CommissioningFlow::kCustom) 71 : { 72 0 : return false; 73 : } 74 : 75 35 : chip::RendezvousInformationFlags allvalid(RendezvousInformationFlag::kBLE, RendezvousInformationFlag::kOnNetwork, 76 : RendezvousInformationFlag::kSoftAP); 77 35 : if (!rendezvousInformation.HasValue() || !rendezvousInformation.Value().HasOnly(allvalid)) 78 : { 79 3 : return false; 80 : } 81 : 82 : // Discriminator validity is enforced by the SetupDiscriminator class. 83 : 84 32 : if (setUpPINCode >= 1 << kSetupPINCodeFieldLengthInBits) 85 : { 86 1 : return false; 87 : } 88 : 89 31 : return CheckPayloadCommonConstraints(); 90 : } 91 : 92 12 : bool PayloadContents::isValidManualCode() const 93 : { 94 : // Discriminator validity is enforced by the SetupDiscriminator class. 95 : 96 12 : if (setUpPINCode >= 1 << kSetupPINCodeFieldLengthInBits) 97 : { 98 0 : return false; 99 : } 100 : 101 12 : return CheckPayloadCommonConstraints(); 102 : } 103 : 104 43 : bool PayloadContents::IsValidSetupPIN(uint32_t setupPIN) 105 : { 106 : // SHALL be restricted to the values 0x0000001 to 0x5F5E0FE (00000001 to 99999998 in decimal), excluding the invalid Passcode 107 : // values. 108 43 : if (setupPIN == kSetupPINCodeUndefinedValue || setupPIN > kSetupPINCodeMaximumValue || setupPIN == 11111111 || 109 42 : setupPIN == 22222222 || setupPIN == 33333333 || setupPIN == 44444444 || setupPIN == 55555555 || setupPIN == 66666666 || 110 42 : setupPIN == 77777777 || setupPIN == 88888888 || setupPIN == 12345678 || setupPIN == 87654321) 111 : { 112 1 : return false; 113 : } 114 : 115 42 : return true; 116 : } 117 : 118 43 : bool PayloadContents::CheckPayloadCommonConstraints() const 119 : { 120 : // A version not equal to 0 would be invalid for v1 and would indicate new format (e.g. version 2) 121 43 : if (version != 0) 122 : { 123 0 : return false; 124 : } 125 : 126 43 : if (!IsValidSetupPIN(setUpPINCode)) 127 : { 128 1 : return false; 129 : } 130 : 131 : // VendorID must be unspecified (0) or in valid range expected. 132 42 : if (!IsVendorIdValidOperationally(vendorID) && (vendorID != VendorId::Unspecified)) 133 : { 134 0 : return false; 135 : } 136 : 137 : // A value of 0x0000 SHALL NOT be assigned to a product since Product ID = 0x0000 is used for these specific cases: 138 : // * To announce an anonymized Product ID as part of device discovery 139 : // * To indicate an OTA software update file applies to multiple Product IDs equally. 140 : // * To avoid confusion when presenting the Onboarding Payload for ECM with multiple nodes 141 42 : if (productID == 0 && vendorID != VendorId::Unspecified) 142 : { 143 0 : return false; 144 : } 145 : 146 42 : return true; 147 : } 148 : 149 22 : bool PayloadContents::operator==(PayloadContents & input) const 150 : { 151 22 : return (this->version == input.version && this->vendorID == input.vendorID && this->productID == input.productID && 152 44 : this->commissioningFlow == input.commissioningFlow && this->rendezvousInformation == input.rendezvousInformation && 153 66 : this->discriminator == input.discriminator && this->setUpPINCode == input.setUpPINCode); 154 : } 155 : 156 11 : CHIP_ERROR SetupPayload::addOptionalVendorData(uint8_t tag, std::string data) 157 : { 158 11 : OptionalQRCodeInfo info; 159 11 : info.tag = tag; 160 11 : info.type = optionalQRCodeInfoTypeString; 161 11 : info.data = std::move(data); 162 : 163 11 : return addOptionalVendorData(info); 164 11 : } 165 : 166 6 : CHIP_ERROR SetupPayload::addOptionalVendorData(uint8_t tag, int32_t data) 167 : { 168 6 : OptionalQRCodeInfo info; 169 6 : info.tag = tag; 170 6 : info.type = optionalQRCodeInfoTypeInt32; 171 6 : info.int32 = data; 172 : 173 6 : return addOptionalVendorData(info); 174 6 : } 175 : 176 58 : std::vector<OptionalQRCodeInfo> SetupPayload::getAllOptionalVendorData() const 177 : { 178 58 : std::vector<OptionalQRCodeInfo> returnedOptionalInfo; 179 80 : for (auto & entry : optionalVendorData) 180 : { 181 22 : returnedOptionalInfo.push_back(entry.second); 182 : } 183 58 : return returnedOptionalInfo; 184 : } 185 : 186 4 : CHIP_ERROR SetupPayload::removeOptionalVendorData(uint8_t tag) 187 : { 188 4 : VerifyOrReturnError(optionalVendorData.find(tag) != optionalVendorData.end(), CHIP_ERROR_KEY_NOT_FOUND); 189 2 : optionalVendorData.erase(tag); 190 : 191 2 : return CHIP_NO_ERROR; 192 : } 193 : 194 7 : CHIP_ERROR SetupPayload::addSerialNumber(std::string serialNumber) 195 : { 196 7 : OptionalQRCodeInfoExtension info; 197 7 : info.tag = kSerialNumberTag; 198 7 : info.type = optionalQRCodeInfoTypeString; 199 7 : info.data = std::move(serialNumber); 200 : 201 7 : return addOptionalExtensionData(info); 202 7 : } 203 : 204 2 : CHIP_ERROR SetupPayload::addSerialNumber(uint32_t serialNumber) 205 : { 206 2 : OptionalQRCodeInfoExtension info; 207 2 : info.tag = kSerialNumberTag; 208 2 : info.type = optionalQRCodeInfoTypeUInt32; 209 2 : info.uint32 = serialNumber; 210 : 211 2 : return addOptionalExtensionData(info); 212 2 : } 213 : 214 4 : CHIP_ERROR SetupPayload::getSerialNumber(std::string & outSerialNumber) const 215 : { 216 4 : CHIP_ERROR err = CHIP_NO_ERROR; 217 4 : OptionalQRCodeInfoExtension info; 218 4 : ReturnErrorOnFailure(getOptionalExtensionData(kSerialNumberTag, info)); 219 : 220 2 : switch (info.type) 221 : { 222 1 : case (optionalQRCodeInfoTypeString): 223 1 : outSerialNumber = info.data; 224 1 : break; 225 1 : case (optionalQRCodeInfoTypeUInt32): 226 1 : outSerialNumber = std::to_string(info.uint32); 227 1 : break; 228 0 : default: 229 0 : err = CHIP_ERROR_INVALID_ARGUMENT; 230 0 : break; 231 : } 232 : 233 2 : return err; 234 4 : } 235 : 236 3 : CHIP_ERROR SetupPayload::removeSerialNumber() 237 : { 238 3 : VerifyOrReturnError(optionalExtensionData.find(kSerialNumberTag) != optionalExtensionData.end(), CHIP_ERROR_KEY_NOT_FOUND); 239 1 : optionalExtensionData.erase(kSerialNumberTag); 240 : 241 1 : return CHIP_NO_ERROR; 242 : } 243 : 244 21 : CHIP_ERROR SetupPayload::addOptionalVendorData(const OptionalQRCodeInfo & info) 245 : { 246 21 : VerifyOrReturnError(IsVendorTag(info.tag), CHIP_ERROR_INVALID_ARGUMENT); 247 19 : optionalVendorData[info.tag] = info; 248 : 249 19 : return CHIP_NO_ERROR; 250 : } 251 : 252 12 : CHIP_ERROR SetupPayload::addOptionalExtensionData(const OptionalQRCodeInfoExtension & info) 253 : { 254 12 : VerifyOrReturnError(IsCommonTag(info.tag), CHIP_ERROR_INVALID_ARGUMENT); 255 12 : optionalExtensionData[info.tag] = info; 256 : 257 12 : return CHIP_NO_ERROR; 258 : } 259 : 260 4 : CHIP_ERROR SetupPayload::getOptionalVendorData(uint8_t tag, OptionalQRCodeInfo & info) 261 : { 262 4 : VerifyOrReturnError(optionalVendorData.find(tag) != optionalVendorData.end(), CHIP_ERROR_KEY_NOT_FOUND); 263 4 : info = optionalVendorData[tag]; 264 : 265 4 : return CHIP_NO_ERROR; 266 : } 267 : 268 7 : CHIP_ERROR SetupPayload::getOptionalExtensionData(uint8_t tag, OptionalQRCodeInfoExtension & info) const 269 : { 270 7 : const auto it = optionalExtensionData.find(tag); 271 7 : VerifyOrReturnError(it != optionalExtensionData.end(), CHIP_ERROR_KEY_NOT_FOUND); 272 5 : info = it->second; 273 5 : return CHIP_NO_ERROR; 274 : } 275 : 276 3 : optionalQRCodeInfoType SetupPayload::getNumericTypeFor(uint8_t tag) 277 : { 278 3 : optionalQRCodeInfoType elemType = optionalQRCodeInfoTypeUnknown; 279 : 280 3 : if (IsVendorTag(tag)) 281 : { 282 2 : elemType = optionalQRCodeInfoTypeInt32; 283 : } 284 1 : else if (tag == kSerialNumberTag) 285 : { 286 1 : elemType = optionalQRCodeInfoTypeUInt32; 287 : } 288 : 289 3 : return elemType; 290 : } 291 : 292 51 : std::vector<OptionalQRCodeInfoExtension> SetupPayload::getAllOptionalExtensionData() 293 : { 294 51 : std::vector<OptionalQRCodeInfoExtension> returnedOptionalInfo; 295 66 : for (auto & entry : optionalExtensionData) 296 : { 297 15 : returnedOptionalInfo.push_back(entry.second); 298 : } 299 51 : return returnedOptionalInfo; 300 : } 301 : 302 20 : bool SetupPayload::operator==(SetupPayload & input) 303 : { 304 20 : std::vector<OptionalQRCodeInfo> inputOptionalVendorData; 305 20 : std::vector<OptionalQRCodeInfoExtension> inputOptionalExtensionData; 306 : 307 20 : VerifyOrReturnError(PayloadContents::operator==(input), false); 308 : 309 19 : inputOptionalVendorData = input.getAllOptionalVendorData(); 310 19 : VerifyOrReturnError(optionalVendorData.size() == inputOptionalVendorData.size(), false); 311 : 312 23 : for (const OptionalQRCodeInfo & inputInfo : inputOptionalVendorData) 313 : { 314 4 : OptionalQRCodeInfo info; 315 4 : CHIP_ERROR err = getOptionalVendorData(inputInfo.tag, info); 316 4 : VerifyOrReturnError(err == CHIP_NO_ERROR, false); 317 4 : VerifyOrReturnError(inputInfo.type == info.type, false); 318 4 : VerifyOrReturnError(inputInfo.data == info.data, false); 319 4 : VerifyOrReturnError(inputInfo.int32 == info.int32, false); 320 4 : } 321 : 322 19 : inputOptionalExtensionData = input.getAllOptionalExtensionData(); 323 19 : VerifyOrReturnError(optionalExtensionData.size() == inputOptionalExtensionData.size(), false); 324 : 325 22 : for (const OptionalQRCodeInfoExtension & inputInfo : inputOptionalExtensionData) 326 : { 327 3 : OptionalQRCodeInfoExtension info; 328 3 : CHIP_ERROR err = getOptionalExtensionData(inputInfo.tag, info); 329 3 : VerifyOrReturnError(err == CHIP_NO_ERROR, false); 330 3 : VerifyOrReturnError(inputInfo.type == info.type, false); 331 3 : VerifyOrReturnError(inputInfo.data == info.data, false); 332 3 : VerifyOrReturnError(inputInfo.int32 == info.int32, false); 333 3 : VerifyOrReturnError(inputInfo.int64 == info.int64, false); 334 3 : VerifyOrReturnError(inputInfo.uint32 == info.uint32, false); 335 3 : VerifyOrReturnError(inputInfo.uint64 == info.uint64, false); 336 3 : } 337 : 338 19 : return true; 339 20 : } 340 : 341 : } // namespace chip