Skip to content

Commit

Permalink
[all-clusters-app] Add some command line options to modify what is re…
Browse files Browse the repository at this point in the history
…turned by the CSRResponse (#19461)

* [examples/platform/linux - Testing] Add some command line options to modify what is returned by the CSRResponse

* Add additional checks related to RESP_MAX into the DefaultDeviceAttestationVerifier
  • Loading branch information
vivien-apple authored and pull[bot] committed Oct 30, 2023
1 parent cdfb941 commit 1755250
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 25 deletions.
6 changes: 4 additions & 2 deletions examples/all-clusters-app/linux/AppOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <app/server/CommissioningWindowManager.h>
#include <app/server/Server.h>

using namespace chip::ArgParser;

using chip::ArgParser::OptionDef;
using chip::ArgParser::OptionSet;
using chip::ArgParser::PrintArgError;
Expand Down Expand Up @@ -55,8 +57,8 @@ bool AppOptions::HandleOptions(const char * program, OptionSet * options, int id
OptionSet * AppOptions::GetOptions()
{
static OptionDef optionsDef[] = {
{ "dac_provider", chip::ArgParser::kArgumentRequired, kOptionDacProviderFilePath },
{ "min_commissioning_timeout", chip::ArgParser::kArgumentRequired, kOptionMinCommissioningTimeout },
{ "dac_provider", kArgumentRequired, kOptionDacProviderFilePath },
{ "min_commissioning_timeout", kArgumentRequired, kOptionMinCommissioningTimeout },
{},
};

Expand Down
2 changes: 2 additions & 0 deletions examples/platform/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ source_set("app-main") {
"LinuxCommissionableDataProvider.h",
"Options.cpp",
"Options.h",
"testing/CustomCSRResponse.cpp",
"testing/CustomCSRResponse.h",
]

defines = []
Expand Down
96 changes: 73 additions & 23 deletions examples/platform/linux/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,36 @@ LinuxDeviceOptions gDeviceOptions;
// Follow the code style of command line arguments in case we need to add more options in the future.
enum
{
kDeviceOption_BleDevice = 0x1000,
kDeviceOption_WiFi = 0x1001,
kDeviceOption_Thread = 0x1002,
kDeviceOption_Version = 0x1003,
kDeviceOption_VendorID = 0x1004,
kDeviceOption_ProductID = 0x1005,
kDeviceOption_CustomFlow = 0x1006,
kDeviceOption_Capabilities = 0x1007,
kDeviceOption_Discriminator = 0x1008,
kDeviceOption_Passcode = 0x1009,
kDeviceOption_SecuredDevicePort = 0x100a,
kDeviceOption_SecuredCommissionerPort = 0x100b,
kDeviceOption_UnsecuredCommissionerPort = 0x100c,
kDeviceOption_Command = 0x100d,
kDeviceOption_PICS = 0x100e,
kDeviceOption_KVS = 0x100f,
kDeviceOption_InterfaceId = 0x1010,
kDeviceOption_Spake2pVerifierBase64 = 0x1011,
kDeviceOption_Spake2pSaltBase64 = 0x1012,
kDeviceOption_Spake2pIterations = 0x1013,
kDeviceOption_TraceFile = 0x1014,
kDeviceOption_TraceLog = 0x1015,
kDeviceOption_TraceDecode = 0x1016,
kDeviceOption_BleDevice = 0x1000,
kDeviceOption_WiFi = 0x1001,
kDeviceOption_Thread = 0x1002,
kDeviceOption_Version = 0x1003,
kDeviceOption_VendorID = 0x1004,
kDeviceOption_ProductID = 0x1005,
kDeviceOption_CustomFlow = 0x1006,
kDeviceOption_Capabilities = 0x1007,
kDeviceOption_Discriminator = 0x1008,
kDeviceOption_Passcode = 0x1009,
kDeviceOption_SecuredDevicePort = 0x100a,
kDeviceOption_SecuredCommissionerPort = 0x100b,
kDeviceOption_UnsecuredCommissionerPort = 0x100c,
kDeviceOption_Command = 0x100d,
kDeviceOption_PICS = 0x100e,
kDeviceOption_KVS = 0x100f,
kDeviceOption_InterfaceId = 0x1010,
kDeviceOption_Spake2pVerifierBase64 = 0x1011,
kDeviceOption_Spake2pSaltBase64 = 0x1012,
kDeviceOption_Spake2pIterations = 0x1013,
kDeviceOption_TraceFile = 0x1014,
kDeviceOption_TraceLog = 0x1015,
kDeviceOption_TraceDecode = 0x1016,
kOptionCSRResponseCSRIncorrectType = 0x1017,
kOptionCSRResponseCSRNonceIncorrectType = 0x1018,
kOptionCSRResponseCSRNonceTooLong = 0x1019,
kOptionCSRResponseCSRNonceInvalid = 0x101a,
kOptionCSRResponseNOCSRElementsTooLong = 0x101b,
kOptionCSRResponseAttestationSignatureIncorrectType = 0x101c,
kOptionCSRResponseAttestationSignatureInvalid = 0x101d,
};

constexpr unsigned kAppUsageLength = 64;
Expand Down Expand Up @@ -98,6 +105,13 @@ OptionDef sDeviceOptionDefs[] = {
{ "trace_log", kArgumentRequired, kDeviceOption_TraceLog },
{ "trace_decode", kArgumentRequired, kDeviceOption_TraceDecode },
#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
{ "cert_error_csr_incorrect_type", kNoArgument, kOptionCSRResponseCSRIncorrectType },
{ "cert_error_csr_nonce_incorrect_type", kNoArgument, kOptionCSRResponseCSRNonceIncorrectType },
{ "cert_error_csr_nonce_too_long", kNoArgument, kOptionCSRResponseCSRNonceTooLong },
{ "cert_error_csr_nonce_invalid", kNoArgument, kOptionCSRResponseCSRNonceInvalid },
{ "cert_error_nocsrelements_too_long", kNoArgument, kOptionCSRResponseNOCSRElementsTooLong },
{ "cert_error_attestation_signature_incorrect_type", kNoArgument, kOptionCSRResponseAttestationSignatureIncorrectType },
{ "cert_error_attestation_signature_invalid", kNoArgument, kOptionCSRResponseAttestationSignatureInvalid },
{}
};

Expand Down Expand Up @@ -183,6 +197,20 @@ const char * sDeviceOptionHelp =
" --trace_decode <1/0>\n"
" A value of 1 enables traces decoding, 0 disables this (default 0).\n"
#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
" --cert_error_csr_incorrect_type\n"
" Configure the CSRResponse to be built with an invalid CSR type.\n"
" --cert_error_csr_nonce_incorrect_type\n"
" Configure the CSRResponse to be built with an invalid CSRNonce type.\n"
" --cert_error_csr_nonce_too_long\n"
" Configure the CSRResponse to be built with a CSRNonce that is longer than expected.\n"
" --cert_error_csr_nonce_invalid\n"
" Configure the CSRResponse to be built with a CSRNonce that does not match the CSRNonce from the CSRRequest.\n"
" --cert_error_nocsrelements_too_long\n"
" Configure the CSRResponse to contains an NOCSRElements larger than the allowed RESP_MAX.\n"
" --cert_error_attestation_signature_incorrect_type\n"
" Configure the CSRResponse to be build with an invalid AttestationSignature type.\n"
" --cert_error_attestation_signature_invalid\n"
" Configure the CSRResponse to be build with an AttestationSignature that does not match what is expected.\n"
"\n";

bool Base64ArgToVector(const char * arg, size_t maxSize, std::vector<uint8_t> & outVector)
Expand Down Expand Up @@ -386,6 +414,28 @@ bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier,
break;
#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED

case kOptionCSRResponseCSRIncorrectType:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrIncorrectType = true;
break;
case kOptionCSRResponseCSRNonceIncorrectType:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrNonceIncorrectType = true;
break;
case kOptionCSRResponseCSRNonceTooLong:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrNonceTooLong = true;
break;
case kOptionCSRResponseCSRNonceInvalid:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrNonceInvalid = true;
break;
case kOptionCSRResponseNOCSRElementsTooLong:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.nocsrElementsTooLong = true;
break;
case kOptionCSRResponseAttestationSignatureIncorrectType:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.attestationSignatureIncorrectType = true;
break;
case kOptionCSRResponseAttestationSignatureInvalid:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.attestationSignatureInvalid = true;
break;

default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName);
retval = false;
Expand Down
2 changes: 2 additions & 0 deletions examples/platform/linux/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <setup_payload/SetupPayload.h>

#include <credentials/DeviceAttestationCredsProvider.h>
#include <testing/CustomCSRResponse.h>

struct LinuxDeviceOptions
{
Expand All @@ -57,6 +58,7 @@ struct LinuxDeviceOptions
bool traceStreamToLogEnabled = false;
chip::Optional<std::string> traceStreamFilename;
chip::Credentials::DeviceAttestationCredentialsProvider * dacProvider = nullptr;
chip::CSRResponseOptions mCSRResponseOptions;

static LinuxDeviceOptions & GetInstance();
};
Expand Down
165 changes: 165 additions & 0 deletions examples/platform/linux/testing/CustomCSRResponse.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
*
* 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 <algorithm>
#include <app-common/zap-generated/cluster-objects.h>
#include <app/data-model/Encode.h>
#include <credentials/DeviceAttestationConstructor.h>
#include <crypto/CHIPCryptoPAL.h>

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(to_underlying(CSRResponse::Fields::kNOCSRElements));
auto tag2 = TLV::ContextTag(to_underlying(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
32 changes: 32 additions & 0 deletions examples/platform/linux/testing/CustomCSRResponse.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
*
* 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.
*/

namespace chip {

struct CSRResponseOptions
{
bool csrIncorrectType = false;
bool csrNonceIncorrectType = false;
bool csrNonceTooLong = false;
bool csrNonceInvalid = false;
bool nocsrElementsTooLong = false;
bool attestationSignatureIncorrectType = false;
bool attestationSignatureInvalid = false;
};

} // namespace chip
Loading

0 comments on commit 1755250

Please sign in to comment.