Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[all-clusters-app] Add some command line options to modify what is returned by the CSRResponse #19461

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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