blob: 6d4e61159b7dea241df314cb03b5ff3593076c20 [file] [log] [blame]
/*
*
* Copyright (c) 2021-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.
*/
/**
* @file
* This file implements the command handler for the 'chip-cert' tool
* that generates a CHIP Certification Declaration.
*
*/
#include "chip-cert.h"
#include <credentials/CertificationDeclaration.h>
#include <string>
namespace {
using namespace chip;
using namespace chip::ASN1;
using namespace chip::ArgParser;
using namespace chip::Credentials;
using namespace chip::Crypto;
using namespace chip::TLV;
#define CMD_NAME "chip-cert gen-cd"
bool HandleOption(const char * progName, OptionSet * optSet, int id, const char * name, const char * arg);
// clang-format off
OptionDef gCmdOptionDefs[] =
{
{ "key", kArgumentRequired, 'K' },
{ "cert", kArgumentRequired, 'C' },
{ "out", kArgumentRequired, 'O' },
{ "format-version", kArgumentRequired, 'f' },
{ "vendor-id", kArgumentRequired, 'V' },
{ "product-id", kArgumentRequired, 'p' },
{ "device-type-id", kArgumentRequired, 'd' },
{ "certificate-id", kArgumentRequired, 'c' },
{ "security-level", kArgumentRequired, 'l' },
{ "security-info", kArgumentRequired, 'i' },
{ "version-number", kArgumentRequired, 'n' },
{ "certification-type", kArgumentRequired, 't' },
{ "dac-origin-vendor-id", kArgumentRequired, 'o' },
{ "dac-origin-product-id", kArgumentRequired, 'r' },
{ "authorized-paa-cert", kArgumentRequired, 'a' },
#if CHIP_CONFIG_INTERNAL_FLAG_GENERATE_DA_TEST_CASES
{ "ignore-error", kNoArgument, 'I' },
{ "error-type", kArgumentRequired, 'E' },
#endif
{ }
};
const char * const gCmdOptionHelp =
" -K, --key <file/str>\n"
"\n"
" File or string containing private key to be used to sign the Certification Declaration.\n"
"\n"
" -C, --cert <file/str>\n"
"\n"
" File or string containing certificate associated with the private key that is used\n"
" to sign the Certification Declaration. The Subject Key Identifier in the\n"
" certificate will be included in the signed Certification Declaration message.\n"
"\n"
" -O, --out <file/stdout>\n"
"\n"
" File to contain the signed Certification Declaration message.\n"
" If specified '-' then output is written to stdout.\n"
"\n"
" -f, --format-version <int>\n"
"\n"
" Format Version.\n"
"\n"
" -V, --vendor-id <hex-digits>\n"
"\n"
" Vendor Id (VID) in hex.\n"
"\n"
" -p, --product-id <hex-digits>\n"
"\n"
" Product Id (PID) in hex. Maximum 100 PID values can be specified.\n"
" Each PID value should have it's own -p or --product-id option selector.\n"
"\n"
" -d, --device-type-id <hex-digits>\n"
"\n"
" Device Type Id in hex.\n"
"\n"
" -c, --certificate-id <string>\n"
"\n"
" Certificate Id encoded as UTF8 string.\n"
"\n"
" -l, --security-level <hex-digits>\n"
"\n"
" Security Level in hex.\n"
"\n"
" -i, --security-info <hex-digits>\n"
"\n"
" Security Information in hex.\n"
"\n"
" -n, --version-number <hex-digits>\n"
"\n"
" Version Number in hex.\n"
"\n"
" -t, --certification-type <int>\n"
"\n"
" Certification Type. Valid values are:\n"
" 0 - Development and Test (default)\n"
" 1 - Provisional\n"
" 2 - Official\n"
"\n"
" -o, --dac-origin-vendor-id <hex-digits>\n"
"\n"
" DAC Origin Vendor Id in hex.\n"
"\n"
" -r, --dac-origin-product-id <hex-digits>\n"
"\n"
" DAC Origin Product Id in hex.\n"
"\n"
" -a, --authorized-paa-cert <file/str>\n"
"\n"
" File or string containing PAA certificate authorized to sign PAI which signs the DAC\n"
" for a product carrying this CD. This field is optional and if present, only specified\n"
" PAAs will be authorized to sign device's PAI for the lifetime of the generated CD.\n"
" Maximum 10 authorized PAA certificates can be specified.\n"
" Each PAA should have its own -a (--authorized-paa-cert) option selector.\n"
" The certificate can be in DER or PEM Form.\n"
" Note that only the Subject Key Identifier (SKID) value will be extracted\n"
" from the PAA certificate and put into CD Structure.\n"
"\n"
#if CHIP_CONFIG_INTERNAL_FLAG_GENERATE_DA_TEST_CASES
" -I, --ignore-error\n"
"\n"
" Ignore some input parameters error.\n"
" WARNING: This option makes it possible to circumvent Certification Declaration\n"
" structure/parameter requirement. This is required for negative testing of the attestation flow.\n"
" Because of this it SHOULD NEVER BE ENABLED IN PRODUCTION BUILDS.\n"
"\n"
" -E, --error-type <error-type>\n"
"\n"
" When specified injects specific error into the structure of generated Certification Declaration.\n"
" Note that 'ignore-error' option MUST be specified for this error injection to take effect.\n"
" Supported error types that can be injected are:\n"
" no-error - No error to inject.\n"
" format-version-missing - The CD TLV structure won't have format version field.\n"
" format-version-wrong - Format version will be set to 2 instead of required 1.\n"
" vid-missing - The CD TLV structure won't have vedor_id field.\n"
" vid-mismatch - The vendor_id field will have value that doesn't match the VID in DAC.\n"
" pid-array-missing - The CD TLV structure won't have product_id_array field.\n"
" pid-array-count0 - The product_id_array will be empty.\n"
" pid-array-count01-valid - The product_id_array field will have one valid PID value.\n"
" pid-array-count01-mismatch - The product_id_array field will have one PID value that doesn't match PID in DAC.\n"
" pid-array-count10-valid - The product_id_array field will have 10 PID values one of which is valid matches PID in DAC.\n"
" pid-array-count10-mismatch - The product_id_array field will have 10 PID values none of which matches the PID in DAC.\n"
" pid-array-count100-valid - The product_id_array field will have 100 PID values one of which is valid matches PID in DAC.\n"
" pid-array-count100-mismatch - The product_id_array field will have 100 PID values none of which matches the PID in DAC.\n"
" device-type-id-missing - The CD TLV structure won't have device_type_id field.\n"
" device-type-id-mismatch - device_type_id field won't match the value in the DCL entries associated with the VID and PID.\n"
" cert-id-missing - The CD TLV structure won't have certificate_id field.\n"
" cert-id-mismatch - The certificate_id field will contain value NOT allocated by the CSA.\n"
" cert-id-len-wrong - The certificate_id field will be truncated to have invalid length.\n"
" security-level-missing - The CD TLV structure won't have security_level field.\n"
" security-level-wrong - The security_level field will be set to invalid value (different from 0).\n"
" security-info-missing - The CD TLV structure won't have security_information field.\n"
" security-info-wrong - The security_information field will be set to invalid value (different from 0).\n"
" version-number-missing - The CD TLV structure won't have version_number field.\n"
" version-number-wrong - The version_number field will contain value NOT assigned by the CSA.\n"
" cert-type-missing - The CD TLV structure won't have certification_type field.\n"
" cert-type-wrong - The certification_type field will contain invalue value.\n"
" dac-origin-vid-present - The CD TLV structure will include optional dac_origin_vid field.\n"
" dac-origin-pid-present - The CD TLV structure will include optional dac_origin_pid field.\n"
" dac-origin-vid-pid-present - The CD TLV structure will include optional dac_origin_vid and dac_origin_pid fields.\n"
" dac-origin-vid-mismatch - The optional dac_origin_vid field will be present and won't match the VID in DAC.\n"
" dac-origin-pid-mismatch - The optional dac_origin_pid field will be present and won't match the PID in DAC.\n"
" authorized-paa-list-count0 - The authorized_paa_list will be empty TLV list.\n"
" authorized-paa-list-count1-valid - The authorized_paa_list will have one valid value.\n"
" authorized-paa-list-count2-valid - The authorized_paa_list will have two elements one of which is valid.\n"
" authorized-paa-list-count3-invalid - The authorized_paa_list will have three elements none of which is valid.\n"
" authorized-paa-list-count10-valid - The authorized_paa_list will have ten elements one of which is valid.\n"
" authorized-paa-list-count10-invalid- The authorized_paa_list will have ten elements none of which is valid.\n"
" signer-info-v2 - Signer Info version will be set to v2 instead of required v3.\n"
" signer-info-digest-algo - Use Signer Info SHA1 digest algorithm instead of required SHA256.\n"
" signer-info-skid - Inject error into SKID of a Signer Info signing certificate.\n"
" cms-v2 - CMS version will be set to v2 instead of required v3.\n"
" cms-digest-algo - Use SHA1 digest algorithm instead of required SHA256.\n"
" cms-sig-algo - Use ecdsa-with-SHA1 signature algorithm instead of required ecdsa-with-SHA256.\n"
" required secp256r1 (aka prime256v1).\n"
" cms-econtent-type - CMS eContentType is set to Microsoft Authenticode [MSAC] ( OID = { 1.3.6.1.4.1.311.2.1.4 } )\n"
" instead of required pkcs7_data.\n"
" cms-sig - Inject error into CMS signature.\n"
"\n"
#endif
;
OptionSet gCmdOptions =
{
HandleOption,
gCmdOptionDefs,
"COMMAND OPTIONS",
gCmdOptionHelp
};
HelpOptions gHelpOptions(
CMD_NAME,
"Usage: " CMD_NAME " [ <options...> ]\n",
CHIP_VERSION_STRING "\n" COPYRIGHT_STRING,
"Generate CD CMS Signed Message"
);
OptionSet *gCmdOptionSets[] =
{
&gCmdOptions,
&gHelpOptions,
nullptr
};
// clang-format on
/** Certification Declaration Error and Configuration Flags
*
* By default all methods (if none of the class setters were used) return valid
* certification declaration configuration parameter as described in the spec.
* These parameters can be modified to inject errors into cd structure.
*/
class CDStructConfig
{
public:
void EnableErrorTestCase() { mEnabled = true; }
void SetFormatVersionMissing() { mFlags.Set(CDConfigFlags::kFormatVersionMissing); }
void SetFormatVersionWrong() { mFlags.Set(CDConfigFlags::kFormatVersionWrong); }
void SetVIDMissing() { mFlags.Set(CDConfigFlags::kVIDMissing); }
void SetVIDWrong() { mFlags.Set(CDConfigFlags::kVIDWrong); }
void SetPIDArrayMissing() { mFlags.Set(CDConfigFlags::kPIDArrayMissing); }
void SetPIDArrayWrong() { mFlags.Set(CDConfigFlags::kPIDArrayWrong); }
void SetPIDArrayCount(uint8_t pidArrayCount) { mPIDArrayCount = pidArrayCount; }
void SetDeviceTypeIdMissing() { mFlags.Set(CDConfigFlags::kDeviceTypeIdMissing); }
void SetDeviceTypeIdWrong() { mFlags.Set(CDConfigFlags::kDeviceTypeIdWrong); }
void SetCertIdMissing() { mFlags.Set(CDConfigFlags::kCertIdMissing); }
void SetCertIdWrong() { mFlags.Set(CDConfigFlags::kCertIdWrong); }
void SetCertIdLenWrong() { mFlags.Set(CDConfigFlags::kCertIdLenWrong); }
void SetSecurityLevelMissing() { mFlags.Set(CDConfigFlags::kSecurityLevelMissing); }
void SetSecurityLevelWrong() { mFlags.Set(CDConfigFlags::kSecurityLevelWrong); }
void SetSecurityInfoMissing() { mFlags.Set(CDConfigFlags::kSecurityInfoMissing); }
void SetSecurityInfoWrong() { mFlags.Set(CDConfigFlags::kSecurityInfoWrong); }
void SetVersionNumberMissing() { mFlags.Set(CDConfigFlags::kVersionNumberMissing); }
void SetVersionNumberWrong() { mFlags.Set(CDConfigFlags::kVersionNumberWrong); }
void SetCertTypeMissing() { mFlags.Set(CDConfigFlags::kCertTypeMissing); }
void SetCertTypeWrong() { mFlags.Set(CDConfigFlags::kCertTypeWrong); }
void SetDACOriginVIDWrong() { mFlags.Set(CDConfigFlags::kDACOriginVID); }
void SetDACOriginPIDWrong() { mFlags.Set(CDConfigFlags::kDACOriginPID); }
void SetDACOriginVIDPresent() { mFlags.Set(CDConfigFlags::kDACOriginVIDPresent); }
void SetDACOriginPIDPresent() { mFlags.Set(CDConfigFlags::kDACOriginPIDPresent); }
void SetAuthPAAListPresent() { mFlags.Set(CDConfigFlags::kAuthPAAListPresent); }
void SetAuthPAAListWrong() { mFlags.Set(CDConfigFlags::kAuthPAAListWrong); }
void SetAuthPAAListCount(uint8_t authPAAListCount) { mAuthPAAListCount = authPAAListCount; }
void SetSignerInfoVersionWrong() { mFlags.Set(CDConfigFlags::kSignerInfoVersion); }
void SetSignerInfoDigestAlgoWrong() { mFlags.Set(CDConfigFlags::kSignerInfoDigestAlgo); }
void SetSignerInfoSKIDWrong() { mFlags.Set(CDConfigFlags::kSignerInfoSKID); }
void SetCMSVersionWrong() { mFlags.Set(CDConfigFlags::kCMSVersion); }
void SetCMSDigestAlgoWrong() { mFlags.Set(CDConfigFlags::kCMSDigestAlgo); }
void SetCMSSigAlgoWrong() { mFlags.Set(CDConfigFlags::kCMSSigAlgo); }
void SetCMSEContentTypeWrong() { mFlags.Set(CDConfigFlags::kCMSEContentType); }
void SetCMSSignatureWrong() { mFlags.Set(CDConfigFlags::kCMSSignature); }
bool IsErrorTestCaseEnabled() { return mEnabled; }
bool IsFormatVersionPresent() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kFormatVersionMissing)); }
uint8_t GetFormatVersion() { return (mEnabled && mFlags.Has(CDConfigFlags::kFormatVersionWrong)) ? 2 : 1; }
bool IsVIDPresent() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kVIDMissing)); }
bool IsVIDCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kVIDWrong)); }
bool IsPIDArrayPresent() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kPIDArrayMissing)); }
bool IsPIDArrayCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kPIDArrayWrong)); }
uint8_t GetPIDArrayCount() const { return mPIDArrayCount; }
bool IsDeviceTypeIdPresent() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kDeviceTypeIdMissing)); }
bool IsDeviceTypeIdCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kDeviceTypeIdWrong)); }
bool IsCertIdPresent() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kCertIdMissing)); }
bool IsCertIdCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kCertIdWrong)); }
bool IsCertIdLenCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kCertIdLenWrong)); }
bool IsSecurityLevelPresent() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kSecurityLevelMissing)); }
bool IsSecurityLevelCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kSecurityLevelWrong)); }
bool IsSecurityInfoPresent() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kSecurityInfoMissing)); }
bool IsSecurityInfoCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kSecurityInfoWrong)); }
bool IsVersionNumberPresent() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kVersionNumberMissing)); }
bool IsVersionNumberCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kVersionNumberWrong)); }
bool IsCertTypePresent() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kCertTypeMissing)); }
bool IsCertTypeCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kCertTypeWrong)); }
bool IsDACOriginVIDCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kDACOriginVID)); }
bool IsDACOriginPIDCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kDACOriginPID)); }
bool IsDACOriginVIDPresent() { return (mEnabled && mFlags.Has(CDConfigFlags::kDACOriginVIDPresent)); }
bool IsDACOriginPIDPresent() { return (mEnabled && mFlags.Has(CDConfigFlags::kDACOriginPIDPresent)); }
bool IsAuthPAAListPresent() { return (mFlags.Has(CDConfigFlags::kAuthPAAListPresent)); }
bool IsAuthPAAListCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kAuthPAAListWrong)); }
uint8_t GetAuthPAAListCount() const { return mAuthPAAListCount; }
bool IsSignerInfoVersionCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kSignerInfoVersion)); }
bool IsSignerInfoDigestAlgoCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kSignerInfoDigestAlgo)); }
bool IsSignerInfoSKIDCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kSignerInfoSKID)); }
bool IsCMSVersionCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kCMSVersion)); }
bool IsCMSDigestAlgoCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kCMSDigestAlgo)); }
bool IsCMSSigAlgoCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kCMSSigAlgo)); }
bool IsCMSEContentTypeCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kCMSEContentType)); }
bool IsCMSSignatureCorrect() { return (!mEnabled || !mFlags.Has(CDConfigFlags::kCMSSignature)); }
private:
enum class CDConfigFlags : uint64_t
{
kFormatVersionMissing = 0x0000000000000001,
kFormatVersionWrong = 0x0000000000000002,
kVIDMissing = 0x0000000000000004,
kVIDWrong = 0x0000000000000008,
kPIDArrayMissing = 0x0000000000000010,
kPIDArrayWrong = 0x0000000000000020,
kDeviceTypeIdMissing = 0x0000000000000040,
kDeviceTypeIdWrong = 0x0000000000000080,
kCertIdMissing = 0x0000000000000100,
kCertIdWrong = 0x0000000000000200,
kCertIdLenWrong = 0x0000000000000400,
kSecurityLevelMissing = 0x0000000000000800,
kSecurityLevelWrong = 0x0000000000001000,
kSecurityInfoMissing = 0x0000000000002000,
kSecurityInfoWrong = 0x0000000000004000,
kVersionNumberMissing = 0x0000000000008000,
kVersionNumberWrong = 0x0000000000010000,
kCertTypeMissing = 0x0000000000020000,
kCertTypeWrong = 0x0000000000040000,
kDACOriginVID = 0x0000000000080000,
kDACOriginPID = 0x0000000000100000,
kDACOriginVIDPresent = 0x0000000000200000,
kDACOriginPIDPresent = 0x0000000000400000,
kAuthPAAListPresent = 0x0000000000800000,
kAuthPAAListWrong = 0x0000000001000000,
kSignerInfoVersion = 0x0000000002000000,
kSignerInfoDigestAlgo = 0x0000000004000000,
kSignerInfoSKID = 0x0000000008000000,
kCMSVersion = 0x0000000010000000,
kCMSDigestAlgo = 0x0000000020000000,
kCMSSigAlgo = 0x0000000040000000,
kCMSEContentType = 0x0000000080000000,
kCMSSignature = 0x0000000100000000,
};
bool mEnabled = false;
chip::BitFlags<CDConfigFlags> mFlags;
uint8_t mPIDArrayCount = 1;
uint8_t mAuthPAAListCount = 1;
};
CertificationElements gCertElements;
const char * gCertFileNameOrStr = nullptr;
const char * gKeyFileNameOrStr = nullptr;
const char * gSignedCDFileName = nullptr;
CDStructConfig gCDConfig;
bool ExtractSKIDFromX509Cert(X509 * cert, ByteSpan & skid)
{
const ASN1_OCTET_STRING * skidString = X509_get0_subject_key_id(cert);
VerifyOrReturnError(skidString != nullptr, false);
VerifyOrReturnError(skidString->length == kKeyIdentifierLength, false);
VerifyOrReturnError(CanCastTo<size_t>(skidString->length), false);
skid = ByteSpan(skidString->data, static_cast<size_t>(skidString->length));
return true;
};
bool HandleOption(const char * progName, OptionSet * optSet, int id, const char * name, const char * arg)
{
switch (id)
{
case 'C':
gCertFileNameOrStr = arg;
break;
case 'K':
gKeyFileNameOrStr = arg;
break;
case 'O':
gSignedCDFileName = arg;
break;
case 'f':
if (!ParseInt(arg, gCertElements.FormatVersion, 16))
{
PrintArgError("%s: Invalid value specified for Format Version: %s\n", progName, arg);
return false;
}
break;
case 'V':
if (!ParseInt(arg, gCertElements.VendorId, 16) || gCertElements.VendorId == 0)
{
PrintArgError("%s: Invalid value specified for Vendor Id: %s\n", progName, arg);
return false;
}
break;
case 'p':
if (gCertElements.ProductIdsCount == ArraySize(gCertElements.ProductIds))
{
PrintArgError("%s: Too many Product Ids are specified: %s\n", progName, arg);
return false;
}
if (!ParseInt(arg, gCertElements.ProductIds[gCertElements.ProductIdsCount], 16) ||
gCertElements.ProductIds[gCertElements.ProductIdsCount] == 0)
{
PrintArgError("%s: Invalid value specified for Product Id: %s\n", progName, arg);
return false;
}
gCertElements.ProductIdsCount++;
break;
case 'd':
if (!ParseInt(arg, gCertElements.DeviceTypeId, 16))
{
PrintArgError("%s: Invalid value specified for Device Type Id: %s\n", progName, arg);
return false;
}
break;
case 'c':
if (strlen(arg) != kCertificateIdLength)
{
PrintArgError("%s: Invalid value specified for Certificate Id: %s\n", progName, arg);
return false;
}
memcpy(gCertElements.CertificateId, arg, strlen(arg));
gCertElements.CertificateId[kCertificateIdLength] = '\0';
break;
case 'l':
if (!ParseInt(arg, gCertElements.SecurityLevel, 16))
{
PrintArgError("%s: Invalid value specified for Security Level: %s\n", progName, arg);
return false;
}
break;
case 'i':
if (!ParseInt(arg, gCertElements.SecurityInformation, 16))
{
PrintArgError("%s: Invalid value specified for Security Information: %s\n", progName, arg);
return false;
}
break;
case 'n':
if (!ParseInt(arg, gCertElements.VersionNumber, 16))
{
PrintArgError("%s: Invalid value specified for Version Number: %s\n", progName, arg);
return false;
}
break;
case 't':
if (!ParseInt(arg, gCertElements.CertificationType) || gCertElements.CertificationType > 2)
{
PrintArgError("%s: Invalid value specified for Certification Type: %s\n", progName, arg);
return false;
}
break;
case 'o':
if (!ParseInt(arg, gCertElements.DACOriginVendorId, 16) || gCertElements.DACOriginVendorId == 0)
{
PrintArgError("%s: Invalid value specified for DAC Origin Vendor Id: %s\n", progName, arg);
return false;
}
gCertElements.DACOriginVIDandPIDPresent = true;
break;
case 'r':
if (!ParseInt(arg, gCertElements.DACOriginProductId, 16) || gCertElements.DACOriginProductId == 0)
{
PrintArgError("%s: Invalid value specified for DAC Origin Product Id: %s\n", progName, arg);
return false;
}
gCertElements.DACOriginVIDandPIDPresent = true;
break;
case 'a':
if (gCertElements.AuthorizedPAAListCount >= ArraySize(gCertElements.AuthorizedPAAList))
{
PrintArgError("%s: Too many Authorized PAA Certificates are specified: %s\n", progName, arg);
return false;
}
{
const char * fileNameOrStr = arg;
std::unique_ptr<X509, void (*)(X509 *)> cert(nullptr, &X509_free);
VerifyOrReturnError(ReadCert(fileNameOrStr, cert), false);
ByteSpan skid;
VerifyOrReturnError(ExtractSKIDFromX509Cert(cert.get(), skid), false);
memcpy(gCertElements.AuthorizedPAAList[gCertElements.AuthorizedPAAListCount++], skid.data(), skid.size());
}
break;
#if CHIP_CONFIG_INTERNAL_FLAG_GENERATE_DA_TEST_CASES
case 'I':
gCDConfig.EnableErrorTestCase();
break;
case 'E':
if (strcmp(arg, "format-version-missing") == 0)
{
gCDConfig.SetFormatVersionMissing();
}
else if (strcmp(arg, "format-version-wrong") == 0)
{
gCDConfig.SetFormatVersionWrong();
}
else if (strcmp(arg, "vid-missing") == 0)
{
gCDConfig.SetVIDMissing();
}
else if (strcmp(arg, "vid-mismatch") == 0)
{
gCDConfig.SetVIDWrong();
}
else if (strcmp(arg, "pid-array-missing") == 0)
{
gCDConfig.SetPIDArrayMissing();
}
else if (strcmp(arg, "pid-array-count0") == 0)
{
gCDConfig.SetPIDArrayCount(0);
}
else if (strcmp(arg, "pid-array-count01-valid") == 0)
{
gCDConfig.SetPIDArrayCount(1);
}
else if (strcmp(arg, "pid-array-count01-mismatch") == 0)
{
gCDConfig.SetPIDArrayCount(1);
gCDConfig.SetPIDArrayWrong();
}
else if (strcmp(arg, "pid-array-count10-valid") == 0)
{
gCDConfig.SetPIDArrayCount(10);
}
else if (strcmp(arg, "pid-array-count10-mismatch") == 0)
{
gCDConfig.SetPIDArrayCount(10);
gCDConfig.SetPIDArrayWrong();
}
else if (strcmp(arg, "pid-array-count100-valid") == 0)
{
gCDConfig.SetPIDArrayCount(100);
}
else if (strcmp(arg, "pid-array-count100-mismatch") == 0)
{
gCDConfig.SetPIDArrayCount(100);
gCDConfig.SetPIDArrayWrong();
}
else if (strcmp(arg, "device-type-id-missing") == 0)
{
gCDConfig.SetDeviceTypeIdMissing();
}
else if (strcmp(arg, "device-type-id-mismatch") == 0)
{
gCDConfig.SetDeviceTypeIdWrong();
}
else if (strcmp(arg, "cert-id-missing") == 0)
{
gCDConfig.SetCertIdMissing();
}
else if (strcmp(arg, "cert-id-mismatch") == 0)
{
gCDConfig.SetCertIdWrong();
}
else if (strcmp(arg, "cert-id-len-wrong") == 0)
{
gCDConfig.SetCertIdLenWrong();
}
else if (strcmp(arg, "security-level-missing") == 0)
{
gCDConfig.SetSecurityLevelMissing();
}
else if (strcmp(arg, "security-level-wrong") == 0)
{
gCDConfig.SetSecurityLevelWrong();
}
else if (strcmp(arg, "security-info-missing") == 0)
{
gCDConfig.SetSecurityInfoMissing();
}
else if (strcmp(arg, "security-info-wrong") == 0)
{
gCDConfig.SetSecurityInfoWrong();
}
else if (strcmp(arg, "version-number-missing") == 0)
{
gCDConfig.SetVersionNumberMissing();
}
else if (strcmp(arg, "version-number-wrong") == 0)
{
gCDConfig.SetVersionNumberWrong();
}
else if (strcmp(arg, "cert-type-missing") == 0)
{
gCDConfig.SetCertTypeMissing();
}
else if (strcmp(arg, "cert-type-wrong") == 0)
{
gCDConfig.SetCertTypeWrong();
}
else if (strcmp(arg, "dac-origin-vid-present") == 0)
{
gCDConfig.SetDACOriginVIDPresent();
}
else if (strcmp(arg, "dac-origin-pid-present") == 0)
{
gCDConfig.SetDACOriginPIDPresent();
}
else if (strcmp(arg, "dac-origin-vid-pid-present") == 0)
{
gCDConfig.SetDACOriginVIDPresent();
gCDConfig.SetDACOriginPIDPresent();
}
else if (strcmp(arg, "dac-origin-vid-mismatch") == 0)
{
gCDConfig.SetDACOriginVIDPresent();
gCDConfig.SetDACOriginPIDPresent();
gCDConfig.SetDACOriginVIDWrong();
}
else if (strcmp(arg, "dac-origin-pid-mismatch") == 0)
{
gCDConfig.SetDACOriginVIDPresent();
gCDConfig.SetDACOriginPIDPresent();
gCDConfig.SetDACOriginPIDWrong();
}
else if (strcmp(arg, "different-origin") == 0)
{
gCDConfig.SetDACOriginVIDPresent();
gCDConfig.SetDACOriginPIDPresent();
}
else if (strcmp(arg, "authorized-paa-list-count0") == 0)
{
gCDConfig.SetAuthPAAListPresent();
gCDConfig.SetAuthPAAListCount(0);
}
else if (strcmp(arg, "authorized-paa-list-count1-valid") == 0)
{
gCDConfig.SetAuthPAAListPresent();
gCDConfig.SetAuthPAAListCount(1);
}
else if (strcmp(arg, "authorized-paa-list-count2-valid") == 0)
{
gCDConfig.SetAuthPAAListPresent();
gCDConfig.SetAuthPAAListCount(2);
}
else if (strcmp(arg, "authorized-paa-list-count3-invalid") == 0)
{
gCDConfig.SetAuthPAAListCount(3);
gCDConfig.SetAuthPAAListPresent();
gCDConfig.SetAuthPAAListWrong();
}
else if (strcmp(arg, "authorized-paa-list-count10-valid") == 0)
{
gCDConfig.SetAuthPAAListPresent();
gCDConfig.SetAuthPAAListCount(10);
}
else if (strcmp(arg, "authorized-paa-list-count10-invalid") == 0)
{
gCDConfig.SetAuthPAAListCount(10);
gCDConfig.SetAuthPAAListPresent();
gCDConfig.SetAuthPAAListWrong();
}
else if (strcmp(arg, "signer-info-v2") == 0)
{
gCDConfig.SetSignerInfoVersionWrong();
}
else if (strcmp(arg, "signer-info-digest-algo") == 0)
{
gCDConfig.SetSignerInfoDigestAlgoWrong();
}
else if (strcmp(arg, "signer-info-skid") == 0)
{
gCDConfig.SetSignerInfoSKIDWrong();
}
else if (strcmp(arg, "cms-v2") == 0)
{
gCDConfig.SetCMSVersionWrong();
}
else if (strcmp(arg, "cms-digest-algo") == 0)
{
gCDConfig.SetCMSDigestAlgoWrong();
}
else if (strcmp(arg, "cms-sig-algo") == 0)
{
gCDConfig.SetCMSSigAlgoWrong();
}
else if (strcmp(arg, "cms-econtent-type") == 0)
{
gCDConfig.SetCMSEContentTypeWrong();
}
else if (strcmp(arg, "cms-sig") == 0)
{
gCDConfig.SetCMSSignatureWrong();
}
else if (strcmp(arg, "no-error") != 0)
{
PrintArgError("%s: Invalid value specified for the error type: %s\n", progName, arg);
return false;
}
break;
#endif
default:
PrintArgError("%s: Unhandled option: %s\n", progName, name);
return false;
}
return true;
}
static constexpr uint8_t sOID_ContentType_PKCS7Data[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
static constexpr uint8_t sOID_ContentType_MSAC[] = { 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x04 };
static constexpr uint8_t sOID_ContentType_PKCS7SignedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };
static constexpr uint8_t sOID_DigestAlgo_SHA256[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 };
static constexpr uint8_t sOID_DigestAlgo_SHA1[] = { 0x2B, 0x0E, 0x03, 0x02, 0x1A };
static constexpr uint8_t sOID_SigAlgo_ECDSAWithSHA1[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x01 };
/** Certification Declaration Element TLV Tags
*/
enum
{
kTag_FormatVersion = 0, /**< [ unsigned int ] Format version. */
kTag_VendorId = 1, /**< [ unsigned int ] Vedor identifier. */
kTag_ProductIdArray = 2, /**< [ array ] Product identifiers (each is unsigned int). */
kTag_DeviceTypeId = 3, /**< [ unsigned int ] Device Type identifier. */
kTag_CertificateId = 4, /**< [ UTF-8 string, length 19 ] Certificate identifier. */
kTag_SecurityLevel = 5, /**< [ unsigned int ] Security level. */
kTag_SecurityInformation = 6, /**< [ unsigned int ] Security information. */
kTag_VersionNumber = 7, /**< [ unsigned int ] Version number. */
kTag_CertificationType = 8, /**< [ unsigned int ] Certification Type. */
kTag_DACOriginVendorId = 9, /**< [ unsigned int, optional ] DAC origin vendor identifier. */
kTag_DACOriginProductId = 10, /**< [ unsigned int, optional ] DAC origin product identifier. */
kTag_AuthorizedPAAList = 11, /**< [ array, optional ] Authorized PAA List. */
};
CHIP_ERROR EncodeCertificationElements_Ignore_Error(const CertificationElements & certElements,
MutableByteSpan & encodedCertElements, CDStructConfig & cdConfig)
{
TLVWriter writer;
TLVType outerContainer1, outerContainer2;
writer.Init(encodedCertElements);
ReturnErrorOnFailure(writer.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainer1));
if (cdConfig.IsFormatVersionPresent())
{
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_FormatVersion), cdConfig.GetFormatVersion()));
}
if (cdConfig.IsVIDPresent())
{
if (cdConfig.IsVIDCorrect())
{
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_VendorId), certElements.VendorId));
}
else
{
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_VendorId), static_cast<uint16_t>(certElements.VendorId ^ UINT16_MAX)));
}
}
if (cdConfig.IsPIDArrayPresent())
{
ReturnErrorOnFailure(writer.StartContainer(ContextTag(kTag_ProductIdArray), kTLVType_Array, outerContainer2));
uint16_t pid =
cdConfig.IsPIDArrayCorrect() ? certElements.ProductIds[0] : static_cast<uint16_t>(certElements.ProductIds[0] + 1);
for (uint8_t i = 0; i < cdConfig.GetPIDArrayCount(); i++)
{
ReturnErrorOnFailure(writer.Put(AnonymousTag(), static_cast<uint16_t>(pid++)));
}
ReturnErrorOnFailure(writer.EndContainer(outerContainer2));
}
if (cdConfig.IsDeviceTypeIdPresent())
{
if (cdConfig.IsDeviceTypeIdCorrect())
{
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_DeviceTypeId), certElements.DeviceTypeId));
}
else
{
ReturnErrorOnFailure(
writer.Put(ContextTag(kTag_DeviceTypeId), static_cast<uint32_t>(certElements.DeviceTypeId ^ UINT32_MAX)));
}
}
if (cdConfig.IsCertIdPresent())
{
if (cdConfig.IsCertIdCorrect() && cdConfig.IsCertIdLenCorrect())
{
ReturnErrorOnFailure(writer.PutString(ContextTag(kTag_CertificateId), certElements.CertificateId));
}
else if (!cdConfig.IsCertIdCorrect())
{
ReturnErrorOnFailure(writer.PutString(ContextTag(kTag_CertificateId), "INV20141ZB330001-24"));
}
else
{
std::string cert_id(certElements.CertificateId);
cert_id += "1234";
ReturnErrorOnFailure(writer.PutString(ContextTag(kTag_CertificateId), cert_id.c_str()));
}
}
if (cdConfig.IsSecurityLevelPresent())
{
if (cdConfig.IsSecurityLevelCorrect())
{
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_SecurityLevel), certElements.SecurityLevel));
}
else
{
ReturnErrorOnFailure(
writer.Put(ContextTag(kTag_SecurityLevel), static_cast<uint8_t>(certElements.SecurityLevel ^ UINT8_MAX)));
}
}
if (cdConfig.IsSecurityInfoPresent())
{
if (cdConfig.IsSecurityInfoCorrect())
{
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_SecurityInformation), certElements.SecurityInformation));
}
else
{
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_SecurityInformation),
static_cast<uint16_t>(certElements.SecurityInformation ^ UINT16_MAX)));
}
}
if (cdConfig.IsVersionNumberPresent())
{
if (cdConfig.IsVersionNumberCorrect())
{
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_VersionNumber), certElements.VersionNumber));
}
else
{
ReturnErrorOnFailure(
writer.Put(ContextTag(kTag_VersionNumber), static_cast<uint16_t>(certElements.VersionNumber ^ UINT16_MAX)));
}
}
if (cdConfig.IsCertTypePresent())
{
if (cdConfig.IsCertTypeCorrect())
{
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_CertificationType), certElements.CertificationType));
}
else
{
ReturnErrorOnFailure(
writer.Put(ContextTag(kTag_CertificationType), static_cast<uint8_t>(certElements.CertificationType ^ UINT8_MAX)));
}
}
if (cdConfig.IsDACOriginVIDPresent())
{
if (cdConfig.IsDACOriginVIDCorrect() && certElements.DACOriginVIDandPIDPresent)
{
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_DACOriginVendorId), certElements.DACOriginVendorId));
}
else
{
uint16_t wrong_dac_origin_vid = 0x8008;
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_DACOriginVendorId), wrong_dac_origin_vid));
}
}
if (cdConfig.IsDACOriginPIDPresent())
{
if (cdConfig.IsDACOriginPIDCorrect() && certElements.DACOriginVIDandPIDPresent)
{
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_DACOriginProductId), certElements.DACOriginProductId));
}
else
{
uint16_t wrong_dac_origin_pid = 0xFF00;
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_DACOriginProductId), wrong_dac_origin_pid));
}
}
if (cdConfig.IsAuthPAAListPresent())
{
ReturnErrorOnFailure(writer.StartContainer(ContextTag(kTag_AuthorizedPAAList), kTLVType_Array, outerContainer2));
uint8_t wrong_kid[kKeyIdentifierLength] = { 0xF4, 0x44, 0xCA, 0xBB, 0xC5, 0x01, 0x65, 0x77, 0xAA, 0x8B,
0x44, 0xFF, 0xB9, 0x0F, 0xCC, 0xA1, 0x40, 0xFE, 0x66, 0x20 };
for (uint8_t i = 0; i < cdConfig.GetAuthPAAListCount(); i++)
{
if (cdConfig.IsAuthPAAListCorrect() && (i < certElements.AuthorizedPAAListCount))
{
ReturnErrorOnFailure(writer.Put(AnonymousTag(), ByteSpan(certElements.AuthorizedPAAList[i])));
}
else
{
wrong_kid[(i % kKeyIdentifierLength)] ^= 0xFF;
ReturnErrorOnFailure(writer.Put(AnonymousTag(), ByteSpan(wrong_kid)));
}
}
ReturnErrorOnFailure(writer.EndContainer(outerContainer2));
}
ReturnErrorOnFailure(writer.EndContainer(outerContainer1));
ReturnErrorOnFailure(writer.Finalize());
encodedCertElements.reduce_size(writer.GetLengthWritten());
return CHIP_NO_ERROR;
}
CHIP_ERROR EncodeEncapsulatedContent_Ignor_Error(const ByteSpan & cdContent, ASN1Writer & writer, CDStructConfig & cdConfig)
{
/**
* EncapsulatedContentInfo ::= SEQUENCE {
* eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1),
* eContent [0] EXPLICIT OCTET STRING cd_content }
*/
CHIP_ERROR err = CHIP_NO_ERROR;
ASN1_START_SEQUENCE
{
// eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1)
if (cdConfig.IsCMSEContentTypeCorrect())
{
ReturnErrorOnFailure(writer.PutObjectId(sOID_ContentType_PKCS7Data, sizeof(sOID_ContentType_PKCS7Data)));
}
else
{
ReturnErrorOnFailure(writer.PutObjectId(sOID_ContentType_MSAC, sizeof(sOID_ContentType_MSAC)));
}
// eContent [0] EXPLICIT OCTET STRING cd_content
ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
{
// OCTET STRING cd_content
ReturnErrorOnFailure(writer.PutOctetString(cdContent.data(), static_cast<uint16_t>(cdContent.size())));
}
ASN1_END_CONSTRUCTED;
}
ASN1_END_SEQUENCE;
exit:
return err;
}
CHIP_ERROR EncodeSignerInfo_Ignor_Error(const ByteSpan & signerKeyId, const P256ECDSASignature & signature, ASN1Writer & writer,
CDStructConfig & cdConfig)
{
/**
* SignerInfo ::= SEQUENCE {
* version INTEGER ( v3(3) ),
* subjectKeyIdentifier OCTET STRING,
* digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1),
* signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2),
* signature OCTET STRING }
*/
CHIP_ERROR err = CHIP_NO_ERROR;
ASN1_START_SET
{
ASN1_START_SEQUENCE
{
// version INTEGER ( v3(3) )
ASN1_ENCODE_INTEGER(cdConfig.IsSignerInfoVersionCorrect() ? 3 : 2);
// subjectKeyIdentifier OCTET STRING
if (cdConfig.IsSignerInfoSKIDCorrect())
{
ReturnErrorOnFailure(writer.PutOctetString(kASN1TagClass_ContextSpecific, 0, signerKeyId.data(),
static_cast<uint16_t>(signerKeyId.size())));
}
else
{
uint8_t wrong_skid[kKeyIdentifierLength];
memcpy(wrong_skid, signerKeyId.data(), signerKeyId.size());
wrong_skid[7] ^= 0xFF;
ReturnErrorOnFailure(writer.PutOctetString(kASN1TagClass_ContextSpecific, 0, wrong_skid, sizeof(wrong_skid)));
}
// digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
ASN1_START_SEQUENCE
{
if (cdConfig.IsSignerInfoDigestAlgoCorrect())
{
ReturnErrorOnFailure(writer.PutObjectId(sOID_DigestAlgo_SHA256, sizeof(sOID_DigestAlgo_SHA256)));
}
else
{
ReturnErrorOnFailure(writer.PutObjectId(sOID_DigestAlgo_SHA1, sizeof(sOID_DigestAlgo_SHA1)));
}
}
ASN1_END_SEQUENCE;
// signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2)
ASN1_START_SEQUENCE
{
if (cdConfig.IsCMSSigAlgoCorrect())
{
ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
}
else
{
ReturnErrorOnFailure(writer.PutObjectId(sOID_SigAlgo_ECDSAWithSHA1, sizeof(sOID_SigAlgo_ECDSAWithSHA1)));
}
}
ASN1_END_SEQUENCE;
uint8_t asn1SignatureBuf[kMax_ECDSA_Signature_Length_Der];
MutableByteSpan asn1Signature(asn1SignatureBuf);
ReturnErrorOnFailure(ConvertECDSASignatureRawToDER(P256ECDSASignatureSpan(signature.ConstBytes()), asn1Signature));
if (!cdConfig.IsCMSSignatureCorrect())
{
asn1SignatureBuf[10] ^= 0xFF;
}
// signature OCTET STRING
ReturnErrorOnFailure(writer.PutOctetString(asn1Signature.data(), static_cast<uint16_t>(asn1Signature.size())));
}
ASN1_END_SEQUENCE;
}
ASN1_END_SET;
exit:
return err;
}
CHIP_ERROR CMS_Sign_Ignore_Error(const ByteSpan & cdContent, const ByteSpan & signerKeyId, Crypto::P256Keypair & signerKeypair,
MutableByteSpan & signedMessage, CDStructConfig & cdConfig)
{
/**
* CertificationDeclaration ::= SEQUENCE {
* version INTEGER ( v3(3) ),
* digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1),
* encapContentInfo EncapsulatedContentInfo,
* signerInfo SignerInfo }
*/
CHIP_ERROR err = CHIP_NO_ERROR;
ASN1Writer writer;
uint32_t size = static_cast<uint32_t>(std::min(static_cast<size_t>(UINT32_MAX), signedMessage.size()));
writer.Init(signedMessage.data(), size);
ASN1_START_SEQUENCE
{
// OID identifies the CMS signed-data content type
ReturnErrorOnFailure(writer.PutObjectId(sOID_ContentType_PKCS7SignedData, sizeof(sOID_ContentType_PKCS7SignedData)));
ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
{
ASN1_START_SEQUENCE
{
// version INTEGER ( v3(3) )
ASN1_ENCODE_INTEGER(cdConfig.IsCMSVersionCorrect() ? 3 : 2);
// digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
ASN1_START_SET
{
ASN1_START_SEQUENCE
{
if (cdConfig.IsCMSDigestAlgoCorrect())
{
ReturnErrorOnFailure(writer.PutObjectId(sOID_DigestAlgo_SHA256, sizeof(sOID_DigestAlgo_SHA256)));
}
else
{
ReturnErrorOnFailure(writer.PutObjectId(sOID_DigestAlgo_SHA1, sizeof(sOID_DigestAlgo_SHA1)));
}
}
ASN1_END_SEQUENCE;
}
ASN1_END_SET;
// encapContentInfo EncapsulatedContentInfo
ReturnErrorOnFailure(EncodeEncapsulatedContent_Ignor_Error(cdContent, writer, cdConfig));
Crypto::P256ECDSASignature signature;
ReturnErrorOnFailure(signerKeypair.ECDSA_sign_msg(cdContent.data(), cdContent.size(), signature));
// signerInfo SignerInfo
ReturnErrorOnFailure(EncodeSignerInfo_Ignor_Error(signerKeyId, signature, writer, cdConfig));
}
ASN1_END_SEQUENCE;
}
ASN1_END_CONSTRUCTED;
}
ASN1_END_SEQUENCE;
signedMessage.reduce_size(writer.GetLengthWritten());
exit:
return err;
}
} // namespace
bool Cmd_GenCD(int argc, char * argv[])
{
if (argc == 1)
{
gHelpOptions.PrintBriefUsage(stderr);
return true;
}
VerifyOrReturnError(ParseArgs(CMD_NAME, argc, argv, gCmdOptionSets), false);
if (gCDConfig.IsErrorTestCaseEnabled())
{
fprintf(stderr,
"WARNING gen-cd: The ignor-error option is set. This option makes it possible to generate invalid certification "
"declaration.\n");
}
if (gKeyFileNameOrStr == nullptr)
{
fprintf(stderr, "Please specify the signing private key using the --key option.\n");
return false;
}
if (gCertFileNameOrStr == nullptr)
{
fprintf(stderr, "Please specify the signing certificate using the --cert option.\n");
return false;
}
if (gSignedCDFileName == nullptr)
{
fprintf(stderr, "Please specify the file name for the signed Certification Declaration using the --out option.\n");
return false;
}
if (strcmp(gSignedCDFileName, "-") != 0 && access(gSignedCDFileName, R_OK) == 0)
{
fprintf(stderr,
"Output signed CD file already exists (%s)\n"
"To replace the file, please remove it and re-run the command.\n",
gSignedCDFileName);
return false;
}
if (!gCDConfig.IsErrorTestCaseEnabled())
{
if (gCertElements.VendorId == 0 || gCertElements.ProductIdsCount == 0 || strlen(gCertElements.CertificateId) == 0 ||
gCertElements.VersionNumber == 0)
{
fprintf(stderr, "Please specify all mandatory CD elements.\n");
return false;
}
if (gCertElements.DACOriginVIDandPIDPresent &&
(gCertElements.DACOriginVendorId == 0 || gCertElements.DACOriginProductId == 0))
{
fprintf(stderr, "The DAC Origin Vendor Id and Product Id SHALL be specified together.\n");
return false;
}
}
{
std::unique_ptr<X509, void (*)(X509 *)> cert(nullptr, &X509_free);
std::unique_ptr<EVP_PKEY, void (*)(EVP_PKEY *)> key(EVP_PKEY_new(), &EVP_PKEY_free);
VerifyOrReturnError(ReadCert(gCertFileNameOrStr, cert), false);
VerifyOrReturnError(ReadKey(gKeyFileNameOrStr, key), false);
// Extract the subject key id from the X509 certificate.
ByteSpan signerKeyId;
VerifyOrReturnError(ExtractSKIDFromX509Cert(cert.get(), signerKeyId), false);
// Initialize P256Keypair from EVP_PKEY.
P256Keypair keypair;
{
P256SerializedKeypair serializedKeypair;
VerifyOrReturnError(SerializeKeyPair(key.get(), serializedKeypair), false);
VerifyOrReturnError(keypair.Deserialize(serializedKeypair) == CHIP_NO_ERROR, false);
}
// Encode CD TLV content.
uint8_t encodedCDBuf[kCertificationElements_TLVEncodedMaxLength];
MutableByteSpan encodedCD(encodedCDBuf);
if (gCDConfig.IsErrorTestCaseEnabled())
{
VerifyOrReturnError(EncodeCertificationElements_Ignore_Error(gCertElements, encodedCD, gCDConfig) == CHIP_NO_ERROR,
false);
}
else
{
VerifyOrReturnError(EncodeCertificationElements(gCertElements, encodedCD) == CHIP_NO_ERROR, false);
}
// Sign CD.
uint8_t signedMessageBuf[kMaxCMSSignedCDMessage];
MutableByteSpan signedMessage(signedMessageBuf);
if (gCDConfig.IsErrorTestCaseEnabled())
{
VerifyOrReturnError(CMS_Sign_Ignore_Error(encodedCD, signerKeyId, keypair, signedMessage, gCDConfig) == CHIP_NO_ERROR,
false);
}
else
{
VerifyOrReturnError(CMS_Sign(encodedCD, signerKeyId, keypair, signedMessage) == CHIP_NO_ERROR, false);
}
// Write to file.
VerifyOrReturnError(WriteDataIntoFile(gSignedCDFileName, signedMessage.data(), static_cast<uint32_t>(signedMessage.size()),
kDataFormat_Raw),
false);
}
return true;
}