blob: 7c3bef2b3494805b9685e057fe562044f3bd26a0 [file] [log] [blame]
/*
*
* Copyright (c) 2021 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 data types, objects and APIs for
* working with Certification Declaration elements.
*/
#include <inttypes.h>
#include <stddef.h>
#include <credentials/CertificationDeclaration.h>
#include <crypto/CHIPCryptoPAL.h>
#include <lib/core/CHIPCore.h>
#include <lib/core/CHIPSafeCasts.h>
#include <lib/core/CHIPTLV.h>
#include <lib/support/SafeInt.h>
namespace chip {
namespace Credentials {
using namespace chip::ASN1;
using namespace chip::TLV;
using namespace chip::Crypto;
static constexpr uint8_t sOID_ContentType_PKCS7Data[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
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_SigAlgo_ECDSAWithSHA256[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 };
/** Certification Declaration Element TLV Tags
*/
enum
{
kTag_VendorId = 1, /**< [ unsigned int ] Vedor identifier. */
kTag_ProductIds = 2, /**< [ array ] Product identifiers (each is unsigned int). */
kTag_ServerCategoryId = 3, /**< [ unsigned int ] Server category identifier. */
kTag_ClientCategoryId = 4, /**< [ unsigned int ] Client category 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. */
};
CHIP_ERROR EncodeCertificationElements(const CertificationElements & certElements, MutableByteSpan & encodedCertElements)
{
TLVWriter writer;
TLVType outerContainer1, outerContainer2;
writer.Init(encodedCertElements);
ReturnErrorOnFailure(writer.StartContainer(AnonymousTag, kTLVType_Structure, outerContainer1));
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_VendorId), certElements.VendorId));
VerifyOrReturnError(certElements.ProductIdsCount > 0, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(certElements.ProductIdsCount < kMaxProductIdsCountPerCD, CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorOnFailure(writer.StartContainer(ContextTag(kTag_ProductIds), kTLVType_Array, outerContainer2));
for (uint8_t i = 0; i < certElements.ProductIdsCount; i++)
{
ReturnErrorOnFailure(writer.Put(AnonymousTag, certElements.ProductIds[i]));
}
ReturnErrorOnFailure(writer.EndContainer(outerContainer2));
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_ServerCategoryId), certElements.ServerCategoryId));
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_ClientCategoryId), certElements.ClientCategoryId));
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_SecurityLevel), certElements.SecurityLevel));
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_SecurityInformation), certElements.SecurityInformation));
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_VersionNumber), certElements.VersionNumber));
ReturnErrorOnFailure(writer.Put(ContextTag(kTag_CertificationType), certElements.CertificationType));
ReturnErrorOnFailure(writer.EndContainer(outerContainer1));
ReturnErrorOnFailure(writer.Finalize());
encodedCertElements.reduce_size(writer.GetLengthWritten());
return CHIP_NO_ERROR;
}
CHIP_ERROR DecodeCertificationElements(const ByteSpan & encodedCertElements, CertificationElements & certElements)
{
TLVReader reader;
TLVType outerContainer1, outerContainer2;
uint64_t element;
reader.Init(encodedCertElements);
ReturnErrorOnFailure(reader.Next(kTLVType_Structure, AnonymousTag));
ReturnErrorOnFailure(reader.EnterContainer(outerContainer1));
ReturnErrorOnFailure(reader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_VendorId)));
ReturnErrorOnFailure(reader.Get(element));
VerifyOrReturnError(CanCastTo<uint16_t>(element), CHIP_ERROR_INVALID_TLV_ELEMENT);
certElements.VendorId = static_cast<uint16_t>(element);
ReturnErrorOnFailure(reader.Next(kTLVType_Array, ContextTag(kTag_ProductIds)));
ReturnErrorOnFailure(reader.EnterContainer(outerContainer2));
certElements.ProductIdsCount = 0;
while (reader.Next(kTLVType_UnsignedInteger, AnonymousTag) == CHIP_NO_ERROR)
{
ReturnErrorOnFailure(reader.Get(element));
VerifyOrReturnError(CanCastTo<uint16_t>(element), CHIP_ERROR_INVALID_TLV_ELEMENT);
certElements.ProductIds[certElements.ProductIdsCount++] = static_cast<uint16_t>(element);
}
ReturnErrorOnFailure(reader.VerifyEndOfContainer());
ReturnErrorOnFailure(reader.ExitContainer(outerContainer2));
ReturnErrorOnFailure(reader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_ServerCategoryId)));
ReturnErrorOnFailure(reader.Get(element));
VerifyOrReturnError(CanCastTo<uint16_t>(element), CHIP_ERROR_INVALID_TLV_ELEMENT);
certElements.ServerCategoryId = static_cast<uint16_t>(element);
ReturnErrorOnFailure(reader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_ClientCategoryId)));
ReturnErrorOnFailure(reader.Get(element));
VerifyOrReturnError(CanCastTo<uint16_t>(element), CHIP_ERROR_INVALID_TLV_ELEMENT);
certElements.ClientCategoryId = static_cast<uint16_t>(element);
ReturnErrorOnFailure(reader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_SecurityLevel)));
ReturnErrorOnFailure(reader.Get(element));
VerifyOrReturnError(CanCastTo<uint8_t>(element), CHIP_ERROR_INVALID_TLV_ELEMENT);
certElements.SecurityLevel = static_cast<uint8_t>(element);
ReturnErrorOnFailure(reader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_SecurityInformation)));
ReturnErrorOnFailure(reader.Get(element));
VerifyOrReturnError(CanCastTo<uint16_t>(element), CHIP_ERROR_INVALID_TLV_ELEMENT);
certElements.SecurityInformation = static_cast<uint16_t>(element);
ReturnErrorOnFailure(reader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_VersionNumber)));
ReturnErrorOnFailure(reader.Get(element));
VerifyOrReturnError(CanCastTo<uint16_t>(element), CHIP_ERROR_INVALID_TLV_ELEMENT);
certElements.VersionNumber = static_cast<uint16_t>(element);
ReturnErrorOnFailure(reader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_CertificationType)));
ReturnErrorOnFailure(reader.Get(element));
VerifyOrReturnError(CanCastTo<uint8_t>(element), CHIP_ERROR_INVALID_TLV_ELEMENT);
certElements.CertificationType = static_cast<uint8_t>(element);
ReturnErrorOnFailure(reader.VerifyEndOfContainer());
ReturnErrorOnFailure(reader.ExitContainer(outerContainer1));
ReturnErrorOnFailure(reader.VerifyEndOfContainer());
return CHIP_NO_ERROR;
}
namespace {
CHIP_ERROR EncodeEncapsulatedContent(const ByteSpan & cdContent, ASN1Writer & writer)
{
/**
* 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)
ReturnErrorOnFailure(writer.PutObjectId(sOID_ContentType_PKCS7Data, sizeof(sOID_ContentType_PKCS7Data)));
// 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 DecodeEncapsulatedContent(ASN1Reader & reader, ByteSpan & cdContent)
{
/**
* 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_PARSE_ENTER_SEQUENCE
{
// eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1)
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
VerifyOrReturnError(ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_ContentType_PKCS7Data)),
ASN1_ERROR_UNSUPPORTED_ENCODING);
// eContent [0] EXPLICIT OCTET STRING cd_content
ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
{
// OCTET STRING cd_content
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
cdContent = ByteSpan(reader.GetValue(), reader.GetValueLen());
}
ASN1_EXIT_CONSTRUCTED;
}
ASN1_EXIT_SEQUENCE;
exit:
return err;
}
CHIP_ERROR EncodeSignerInfo(const ByteSpan & signerKeyId, const P256ECDSASignature & signature, ASN1Writer & writer)
{
/**
* 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(3);
// subjectKeyIdentifier OCTET STRING
ReturnErrorOnFailure(writer.PutOctetString(kASN1TagClass_ContextSpecific, 0, signerKeyId.data(),
static_cast<uint16_t>(signerKeyId.size())));
// digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
ASN1_START_SEQUENCE
{
ReturnErrorOnFailure(writer.PutObjectId(sOID_DigestAlgo_SHA256, sizeof(sOID_DigestAlgo_SHA256)));
}
ASN1_END_SEQUENCE;
// signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2)
ASN1_START_SEQUENCE { ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256); }
ASN1_END_SEQUENCE;
uint8_t asn1SignatureBuf[kMax_ECDSA_Signature_Length_Der];
MutableByteSpan asn1Signature(asn1SignatureBuf);
ReturnErrorOnFailure(EcdsaRawSignatureToAsn1(kP256_FE_Length, ByteSpan(signature, signature.Length()), asn1Signature));
// 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 DecodeSignerInfo(ASN1Reader & reader, ByteSpan & signerKeyId, P256ECDSASignature & signature)
{
/**
* 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_PARSE_ENTER_SET
{
ASN1_PARSE_ENTER_SEQUENCE
{
// version INTEGER ( v3(3) )
{
int64_t version;
ASN1_PARSE_INTEGER(version);
// Verify that the CMS version is v3
VerifyOrExit(version == 3, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
}
// subjectKeyIdentifier OCTET STRING
ASN1_PARSE_ELEMENT(kASN1TagClass_ContextSpecific, 0);
signerKeyId = ByteSpan(reader.GetValue(), reader.GetValueLen());
// digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
ASN1_PARSE_ENTER_SEQUENCE
{
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
VerifyOrReturnError(ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_DigestAlgo_SHA256)),
ASN1_ERROR_UNSUPPORTED_ENCODING);
}
ASN1_EXIT_SEQUENCE;
// signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2)
ASN1_PARSE_ENTER_SEQUENCE
{
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
VerifyOrReturnError(
ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_SigAlgo_ECDSAWithSHA256)),
ASN1_ERROR_UNSUPPORTED_ENCODING);
}
ASN1_EXIT_SEQUENCE;
// signature OCTET STRING
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
MutableByteSpan signatureSpan(signature, signature.Capacity());
ReturnErrorOnFailure(
EcdsaAsn1SignatureToRaw(kP256_FE_Length, ByteSpan(reader.GetValue(), reader.GetValueLen()), signatureSpan));
ReturnErrorOnFailure(signature.SetLength(signatureSpan.size()));
}
ASN1_EXIT_SEQUENCE;
}
ASN1_EXIT_SET;
exit:
return err;
}
} // namespace
CHIP_ERROR CMS_Sign(const ByteSpan & cdContent, const ByteSpan & signerKeyId, Crypto::P256Keypair & signerKeypair,
MutableByteSpan & signedMessage)
{
/**
* 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(3);
// digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
ASN1_START_SET
{
ASN1_START_SEQUENCE
{
ReturnErrorOnFailure(writer.PutObjectId(sOID_DigestAlgo_SHA256, sizeof(sOID_DigestAlgo_SHA256)));
}
ASN1_END_SEQUENCE;
}
ASN1_END_SET;
// encapContentInfo EncapsulatedContentInfo
ReturnErrorOnFailure(EncodeEncapsulatedContent(cdContent, writer));
Crypto::P256ECDSASignature signature;
ReturnErrorOnFailure(signerKeypair.ECDSA_sign_msg(cdContent.data(), cdContent.size(), signature));
// signerInfo SignerInfo
ReturnErrorOnFailure(EncodeSignerInfo(signerKeyId, signature, writer));
}
ASN1_END_SEQUENCE;
}
ASN1_END_CONSTRUCTED;
}
ASN1_END_SEQUENCE;
signedMessage.reduce_size(writer.GetLengthWritten());
exit:
return err;
}
CHIP_ERROR CMS_Verify(const ByteSpan & signedMessage, const ByteSpan & signerX509Cert, ByteSpan & cdContent)
{
P256PublicKey signerPubkey;
ReturnErrorOnFailure(ExtractPubkeyFromX509Cert(signerX509Cert, signerPubkey));
return CMS_Verify(signedMessage, signerPubkey, cdContent);
}
CHIP_ERROR CMS_Verify(const ByteSpan & signedMessage, const Crypto::P256PublicKey & signerPubkey, ByteSpan & cdContent)
{
CHIP_ERROR err = CHIP_NO_ERROR;
ASN1Reader reader;
uint32_t size = signedMessage.size() > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(signedMessage.size());
reader.Init(signedMessage.data(), size);
// SignedData ::= SEQUENCE
ASN1_PARSE_ENTER_SEQUENCE
{
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
// id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
// OID identifies the CMS signed-data content type
VerifyOrReturnError(
ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_ContentType_PKCS7SignedData)),
ASN1_ERROR_UNSUPPORTED_ENCODING);
// version [0] EXPLICIT Version DEFAULT v3
ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
{
ASN1_PARSE_ENTER_SEQUENCE
{
// Version ::= INTEGER { v3(3) }
int64_t version;
ASN1_PARSE_INTEGER(version);
// Verify that the CMS version is v3
VerifyOrExit(version == 3, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
// digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
ASN1_PARSE_ENTER_SET
{
ASN1_PARSE_ENTER_SEQUENCE
{
ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
VerifyOrReturnError(
ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_DigestAlgo_SHA256)),
ASN1_ERROR_UNSUPPORTED_ENCODING);
}
ASN1_EXIT_SEQUENCE;
}
ASN1_EXIT_SET;
// encapContentInfo EncapsulatedContentInfo
ReturnErrorOnFailure(DecodeEncapsulatedContent(reader, cdContent));
// signerInfo SignerInfo
ByteSpan signerKeyId;
P256ECDSASignature signature;
ReturnErrorOnFailure(DecodeSignerInfo(reader, signerKeyId, signature));
// Validate CD Signature
ReturnErrorOnFailure(signerPubkey.ECDSA_validate_msg_signature(cdContent.data(), cdContent.size(), signature));
}
ASN1_EXIT_SEQUENCE;
}
ASN1_EXIT_CONSTRUCTED;
}
ASN1_EXIT_SEQUENCE;
exit:
return err;
}
CHIP_ERROR CMS_ExtractKeyId(const ByteSpan & signedMessage, ByteSpan & signerKeyId)
{
CHIP_ERROR err = CHIP_NO_ERROR;
ASN1Reader reader;
uint32_t size = signedMessage.size() > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(signedMessage.size());
reader.Init(signedMessage.data(), size);
// SignedData ::= SEQUENCE
ASN1_PARSE_ENTER_SEQUENCE
{
// id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
// OID identifies the CMS signed-data content type
ASN1_PARSE_ANY;
// version [0] EXPLICIT Version DEFAULT v3
ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
{
ASN1_PARSE_ENTER_SEQUENCE
{
// Version ::= INTEGER { v3(3) }
ASN1_PARSE_ANY;
// digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
ASN1_PARSE_ANY;
// encapContentInfo EncapsulatedContentInfo
ASN1_PARSE_ANY;
// signerInfo SignerInfo
P256ECDSASignature signature;
ReturnErrorOnFailure(DecodeSignerInfo(reader, signerKeyId, signature));
}
ASN1_EXIT_SEQUENCE;
}
ASN1_EXIT_CONSTRUCTED;
}
ASN1_EXIT_SEQUENCE;
exit:
return err;
}
CHIP_ERROR CMS_ExtractCDContent(const ByteSpan & signedMessage, ByteSpan & cdContent)
{
CHIP_ERROR err = CHIP_NO_ERROR;
ASN1Reader reader;
uint32_t size = signedMessage.size() > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(signedMessage.size());
reader.Init(signedMessage.data(), size);
// SignedData ::= SEQUENCE
ASN1_PARSE_ENTER_SEQUENCE
{
// id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
// OID identifies the CMS signed-data content type
ASN1_PARSE_ANY;
// version [0] EXPLICIT Version DEFAULT v3
ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
{
ASN1_PARSE_ENTER_SEQUENCE
{
// Version ::= INTEGER { v3(3) }
ASN1_PARSE_ANY;
// digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
ASN1_PARSE_ANY;
// encapContentInfo EncapsulatedContentInfo
ReturnErrorOnFailure(DecodeEncapsulatedContent(reader, cdContent));
// signerInfo SignerInfo
ASN1_PARSE_ANY;
}
ASN1_EXIT_SEQUENCE;
}
ASN1_EXIT_CONSTRUCTED;
}
ASN1_EXIT_SEQUENCE;
exit:
return err;
}
} // namespace Credentials
} // namespace chip