/* * * Copyright (c) 2022 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Options.h" #include #include #include #include #include using namespace chip; using namespace chip::app; using namespace chip::app::Clusters::OperationalCredentials::Commands; constexpr size_t kMaxResponseLength = 900; constexpr size_t kCSRNonceLength = 32; namespace { CHIP_ERROR ConstructCustomNOCSRElements(TLV::TLVWriter & writer, TLV::Tag tag, const ByteSpan & nocsrElements, CSRResponseOptions & options) { ByteSpan csr; ByteSpan csrNonce; ByteSpan vendorReserved1; ByteSpan vendorReserved2; ByteSpan vendorReserved3; ReturnErrorOnFailure( Credentials::DeconstructNOCSRElements(nocsrElements, csr, csrNonce, vendorReserved1, vendorReserved2, vendorReserved3)); // Add 10 bytes of possible overhead to allow the generation of content longer than the allowed maximum of RESP_MAX. // 10 has been choosen to leave enough space for the possible TLV overhead when adding the additional data. uint8_t nocsrElementsData[kMaxResponseLength + 10]; MutableByteSpan nocsrElementsSpan(nocsrElementsData); TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified; TLV::TLVWriter tlvWriter; tlvWriter.Init(nocsrElementsSpan); ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType)); // Update CSR if (options.csrIncorrectType) { ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), true)); } else { ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), csr)); } // Update CSRNonce if (options.csrNonceIncorrectType) { ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), true)); } else if (options.csrNonceInvalid) { uint8_t csrNonceInvalid[kCSRNonceLength] = {}; memcpy(csrNonceInvalid, csrNonce.data(), csrNonce.size()); std::reverse(csrNonceInvalid, csrNonceInvalid + sizeof(csrNonceInvalid)); ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), ByteSpan(csrNonceInvalid))); } else if (options.csrNonceTooLong) { uint8_t csrNonceTooLong[kCSRNonceLength + 1] = {}; memcpy(csrNonceTooLong, csrNonce.data(), csrNonce.size()); ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), ByteSpan(csrNonceTooLong))); } else { ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), csrNonce)); } // Add vendorReserved1 if present if (!vendorReserved1.empty()) { ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), vendorReserved1)); } // Add vendorReserved2 if present if (!vendorReserved2.empty()) { ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), vendorReserved2)); } // Add vendorReserved3 if present if (!vendorReserved3.empty()) { ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(5), vendorReserved3)); } // Add additional data if (options.nocsrElementsTooLong) { size_t len = kMaxResponseLength - tlvWriter.GetLengthWritten(); ReturnLogErrorOnFailure(tlvWriter.Put(TLV::ContextTag(6), ByteSpan(nocsrElementsData, len))); } ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); ReturnErrorOnFailure(tlvWriter.Finalize()); return DataModel::Encode(writer, tag, nocsrElementsSpan.SubSpan(0, tlvWriter.GetLengthWritten())); } CHIP_ERROR ConstructCustomAttestationSignature(TLV::TLVWriter & writer, TLV::Tag tag, const ByteSpan & attestationSignature, CSRResponseOptions & options) { if (options.attestationSignatureIncorrectType) { return DataModel::Encode(writer, tag, true); } if (options.attestationSignatureInvalid) { uint8_t invalidAttestationSignature[Crypto::kP256_ECDSA_Signature_Length_Raw] = {}; memcpy(invalidAttestationSignature, attestationSignature.data(), attestationSignature.size()); std::reverse(invalidAttestationSignature, invalidAttestationSignature + sizeof(invalidAttestationSignature)); return DataModel::Encode(writer, tag, ByteSpan(invalidAttestationSignature)); } return DataModel::Encode(writer, tag, attestationSignature); } } // namespace namespace chip { namespace app { namespace DataModel { template <> CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, const CSRResponse::Type & responseData) { auto tag1 = TLV::ContextTag(CSRResponse::Fields::kNOCSRElements); auto tag2 = TLV::ContextTag(CSRResponse::Fields::kAttestationSignature); auto & options = LinuxDeviceOptions::GetInstance().mCSRResponseOptions; TLV::TLVType outer; ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Structure, outer)); ReturnErrorOnFailure(ConstructCustomNOCSRElements(writer, tag1, responseData.NOCSRElements, options)); ReturnErrorOnFailure(ConstructCustomAttestationSignature(writer, tag2, responseData.attestationSignature, options)); ReturnErrorOnFailure(writer.EndContainer(outer)); return CHIP_NO_ERROR; } } // namespace DataModel } // namespace app } // namespace chip