LCOV - code coverage report
Current view: top level - credentials - CHIPCertToX509.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 263 268 98.1 %
Date: 2024-02-15 08:20:41 Functions: 19 20 95.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020-2022 Project CHIP Authors
       4             :  *    Copyright (c) 2013-2017 Nest Labs, Inc.
       5             :  *    All rights reserved.
       6             :  *
       7             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       8             :  *    you may not use this file except in compliance with the License.
       9             :  *    You may obtain a copy of the License at
      10             :  *
      11             :  *        http://www.apache.org/licenses/LICENSE-2.0
      12             :  *
      13             :  *    Unless required by applicable law or agreed to in writing, software
      14             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      15             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16             :  *    See the License for the specific language governing permissions and
      17             :  *    limitations under the License.
      18             :  */
      19             : 
      20             : /**
      21             :  *    @file
      22             :  *      This file implements methods for converting a CHIP
      23             :  *      TLV-encoded certificate to a standard X.509 certificate.
      24             :  *
      25             :  */
      26             : 
      27             : #ifndef __STDC_LIMIT_MACROS
      28             : #define __STDC_LIMIT_MACROS
      29             : #endif
      30             : 
      31             : #include <inttypes.h>
      32             : #include <stddef.h>
      33             : 
      34             : #include <credentials/CHIPCert_Internal.h>
      35             : #include <lib/asn1/ASN1.h>
      36             : #include <lib/asn1/ASN1Macros.h>
      37             : #include <lib/core/CHIPCore.h>
      38             : #include <lib/core/CHIPSafeCasts.h>
      39             : #include <lib/core/TLV.h>
      40             : #include <lib/support/CodeUtils.h>
      41             : #include <lib/support/DLLUtil.h>
      42             : #include <lib/support/SafeInt.h>
      43             : #include <protocols/Protocols.h>
      44             : 
      45             : namespace chip {
      46             : namespace Credentials {
      47             : 
      48             : using namespace chip::ASN1;
      49             : using namespace chip::TLV;
      50             : using namespace chip::Protocols;
      51             : using namespace chip::Crypto;
      52             : 
      53        5220 : static CHIP_ERROR DecodeConvertDN(TLVReader & reader, ASN1Writer & writer, ChipDN & dn)
      54             : {
      55        5220 :     ReturnErrorOnFailure(dn.DecodeFromTLV(reader));
      56        5199 :     ReturnErrorOnFailure(dn.EncodeToASN1(writer));
      57        5198 :     return CHIP_NO_ERROR;
      58             : }
      59             : 
      60        2625 : static CHIP_ERROR DecodeConvertValidity(TLVReader & reader, ASN1Writer & writer, ChipCertificateData & certData)
      61             : {
      62             :     CHIP_ERROR err;
      63             :     ASN1UniversalTime asn1Time;
      64             : 
      65        2625 :     ASN1_START_SEQUENCE
      66             :     {
      67        2625 :         ReturnErrorOnFailure(reader.Next(ContextTag(kTag_NotBefore)));
      68        2616 :         ReturnErrorOnFailure(reader.Get(certData.mNotBeforeTime));
      69        2616 :         ReturnErrorOnFailure(ChipEpochToASN1Time(certData.mNotBeforeTime, asn1Time));
      70        2616 :         ASN1_ENCODE_TIME(asn1Time);
      71             : 
      72        2616 :         ReturnErrorOnFailure(reader.Next(ContextTag(kTag_NotAfter)));
      73        2607 :         ReturnErrorOnFailure(reader.Get(certData.mNotAfterTime));
      74        2607 :         ReturnErrorOnFailure(ChipEpochToASN1Time(certData.mNotAfterTime, asn1Time));
      75        2607 :         ASN1_ENCODE_TIME(asn1Time);
      76             : 
      77             :         // Perform this check if NotAfter value is different from Never-Expire value.
      78        2607 :         if (certData.mNotAfterTime != kNullCertTime)
      79             :         {
      80        2595 :             VerifyOrReturnError(certData.mNotBeforeTime < certData.mNotAfterTime, CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
      81             :         }
      82             :     }
      83        2598 :     ASN1_END_SEQUENCE;
      84             : 
      85        2598 : exit:
      86        2598 :     return err;
      87             : }
      88             : 
      89        2573 : static CHIP_ERROR DecodeConvertSubjectPublicKeyInfo(TLVReader & reader, ASN1Writer & writer, ChipCertificateData & certData)
      90             : {
      91             :     CHIP_ERROR err;
      92             :     uint8_t pubKeyAlgoId, pubKeyCurveId;
      93             : 
      94        2573 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_PublicKeyAlgorithm)));
      95        2573 :     ReturnErrorOnFailure(reader.Get(pubKeyAlgoId));
      96             : 
      97        2573 :     certData.mPubKeyAlgoOID = GetOID(kOIDCategory_PubKeyAlgo, pubKeyAlgoId);
      98        2573 :     VerifyOrReturnError(certData.mPubKeyAlgoOID == kOID_PubKeyAlgo_ECPublicKey, CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
      99             : 
     100        2573 :     ReturnErrorOnFailure(reader.Next(ContextTag(kTag_EllipticCurveIdentifier)));
     101        2573 :     ReturnErrorOnFailure(reader.Get(pubKeyCurveId));
     102             : 
     103        2573 :     certData.mPubKeyCurveOID = GetOID(kOIDCategory_EllipticCurve, pubKeyCurveId);
     104        2573 :     VerifyOrReturnError(certData.mPubKeyCurveOID == kOID_EllipticCurve_prime256v1, CHIP_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
     105             : 
     106             :     // subjectPublicKeyInfo SubjectPublicKeyInfo,
     107        2564 :     ASN1_START_SEQUENCE
     108             :     {
     109             :         // algorithm AlgorithmIdentifier,
     110             :         // AlgorithmIdentifier ::= SEQUENCE
     111        2564 :         ASN1_START_SEQUENCE
     112             :         {
     113             :             // algorithm OBJECT IDENTIFIER,
     114        2564 :             ASN1_ENCODE_OBJECT_ID(certData.mPubKeyAlgoOID);
     115             : 
     116             :             // EcpkParameters ::= CHOICE {
     117             :             //     ecParameters  ECParameters,
     118             :             //     namedCurve    OBJECT IDENTIFIER,
     119             :             //     implicitlyCA  NULL }
     120             :             //
     121             :             // (Only namedCurve supported).
     122             :             //
     123        2563 :             ASN1_ENCODE_OBJECT_ID(certData.mPubKeyCurveOID);
     124             :         }
     125        2563 :         ASN1_END_SEQUENCE;
     126             : 
     127        2563 :         ReturnErrorOnFailure(reader.Next(kTLVType_ByteString, ContextTag(kTag_EllipticCurvePublicKey)));
     128        2563 :         ReturnErrorOnFailure(reader.Get(certData.mPublicKey));
     129             : 
     130             :         static_assert(P256PublicKeySpan().size() <= UINT16_MAX, "Public key size doesn't fit in a uint16_t");
     131             : 
     132             :         // For EC certs, the subjectPublicKey BIT STRING contains the X9.62 encoded EC point.
     133        2563 :         ReturnErrorOnFailure(writer.PutBitString(0, certData.mPublicKey.data(), static_cast<uint16_t>(certData.mPublicKey.size())));
     134             :     }
     135        2563 :     ASN1_END_SEQUENCE;
     136             : 
     137        2564 : exit:
     138        2564 :     return err;
     139             : }
     140             : 
     141        2528 : static CHIP_ERROR DecodeConvertAuthorityKeyIdentifierExtension(TLVReader & reader, ASN1Writer & writer,
     142             :                                                                ChipCertificateData & certData)
     143             : {
     144             :     CHIP_ERROR err;
     145             : 
     146        2528 :     certData.mCertFlags.Set(CertFlags::kExtPresent_AuthKeyId);
     147             : 
     148             :     // AuthorityKeyIdentifier extension MUST be marked as non-critical (default).
     149             : 
     150             :     // AuthorityKeyIdentifier ::= SEQUENCE
     151        2528 :     ASN1_START_SEQUENCE
     152             :     {
     153             :         // keyIdentifier [0] IMPLICIT KeyIdentifier
     154             :         // KeyIdentifier ::= OCTET STRING
     155        2528 :         ReturnErrorOnFailure(reader.Expect(kTLVType_ByteString, ContextTag(kTag_AuthorityKeyIdentifier)));
     156        2528 :         ReturnErrorOnFailure(reader.Get(certData.mAuthKeyId));
     157             : 
     158             :         static_assert(CertificateKeyId().size() <= UINT16_MAX, "Authority key id size doesn't fit in a uint16_t");
     159             : 
     160        2519 :         ReturnErrorOnFailure(writer.PutOctetString(kASN1TagClass_ContextSpecific, 0, certData.mAuthKeyId.data(),
     161             :                                                    static_cast<uint16_t>(certData.mAuthKeyId.size())));
     162             :     }
     163        2519 :     ASN1_END_SEQUENCE;
     164             : 
     165        2519 : exit:
     166        2519 :     return err;
     167             : }
     168             : 
     169        2538 : static CHIP_ERROR DecodeConvertSubjectKeyIdentifierExtension(TLVReader & reader, ASN1Writer & writer,
     170             :                                                              ChipCertificateData & certData)
     171             : {
     172        2538 :     certData.mCertFlags.Set(CertFlags::kExtPresent_SubjectKeyId);
     173             : 
     174             :     // SubjectKeyIdentifier extension MUST be marked as non-critical (default).
     175             : 
     176             :     // SubjectKeyIdentifier ::= KeyIdentifier
     177             :     // KeyIdentifier ::= OCTET STRING
     178        2538 :     ReturnErrorOnFailure(reader.Expect(kTLVType_ByteString, ContextTag(kTag_SubjectKeyIdentifier)));
     179        2538 :     ReturnErrorOnFailure(reader.Get(certData.mSubjectKeyId));
     180             : 
     181             :     static_assert(CertificateKeyId().size() <= UINT16_MAX, "Subject key id size doesn't fit in a uint16_t");
     182             : 
     183        2529 :     ReturnErrorOnFailure(
     184             :         writer.PutOctetString(certData.mSubjectKeyId.data(), static_cast<uint16_t>(certData.mSubjectKeyId.size())));
     185             : 
     186        2528 :     return CHIP_NO_ERROR;
     187             : }
     188             : 
     189        2550 : static CHIP_ERROR DecodeConvertKeyUsageExtension(TLVReader & reader, ASN1Writer & writer, ChipCertificateData & certData)
     190             : {
     191             :     CHIP_ERROR err;
     192             :     uint16_t keyUsageBits;
     193             : 
     194        2550 :     certData.mCertFlags.Set(CertFlags::kExtPresent_KeyUsage);
     195             : 
     196             :     // KeyUsage ::= BIT STRING
     197        2550 :     ReturnErrorOnFailure(reader.Expect(ContextTag(kTag_KeyUsage)));
     198        2550 :     ReturnErrorOnFailure(reader.Get(keyUsageBits));
     199             : 
     200             :     {
     201        2550 :         BitFlags<KeyUsageFlags> keyUsageFlags(keyUsageBits);
     202        2550 :         VerifyOrReturnError(
     203             :             keyUsageFlags.HasOnly(KeyUsageFlags::kDigitalSignature, KeyUsageFlags::kNonRepudiation, KeyUsageFlags::kKeyEncipherment,
     204             :                                   KeyUsageFlags::kDataEncipherment, KeyUsageFlags::kKeyAgreement, KeyUsageFlags::kKeyCertSign,
     205             :                                   KeyUsageFlags::kCRLSign, KeyUsageFlags::kEncipherOnly, KeyUsageFlags::kEncipherOnly),
     206             :             CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
     207             : 
     208        2550 :         ASN1_ENCODE_BIT_STRING(keyUsageBits);
     209             : 
     210        2550 :         certData.mKeyUsageFlags = keyUsageFlags;
     211             :     }
     212             : 
     213        2550 : exit:
     214        2550 :     return err;
     215             : }
     216             : 
     217        2559 : static CHIP_ERROR DecodeConvertBasicConstraintsExtension(TLVReader & reader, ASN1Writer & writer, ChipCertificateData & certData)
     218             : {
     219             :     CHIP_ERROR err;
     220             :     TLVType outerContainer;
     221             : 
     222        2559 :     certData.mCertFlags.Set(CertFlags::kExtPresent_BasicConstraints);
     223             : 
     224             :     // BasicConstraints ::= SEQUENCE
     225        2559 :     ASN1_START_SEQUENCE
     226             :     {
     227        2559 :         ReturnErrorOnFailure(reader.Expect(kTLVType_Structure, ContextTag(kTag_BasicConstraints)));
     228        2559 :         ReturnErrorOnFailure(reader.EnterContainer(outerContainer));
     229             : 
     230             :         // cA BOOLEAN DEFAULT FALSE
     231             :         {
     232             :             bool isCA;
     233        2559 :             ReturnErrorOnFailure(reader.Next(ContextTag(kTag_BasicConstraints_IsCA)));
     234        2550 :             ReturnErrorOnFailure(reader.Get(isCA));
     235             : 
     236        2550 :             if (isCA)
     237             :             {
     238        1600 :                 ASN1_ENCODE_BOOLEAN(true);
     239        1600 :                 certData.mCertFlags.Set(CertFlags::kIsCA);
     240             :             }
     241             : 
     242        2550 :             err = reader.Next();
     243        2550 :             VerifyOrReturnError(err == CHIP_NO_ERROR || err == CHIP_END_OF_TLV, err);
     244             :         }
     245             : 
     246             :         // pathLenConstraint INTEGER (0..MAX) OPTIONAL
     247        2550 :         if (reader.GetTag() == ContextTag(kTag_BasicConstraints_PathLenConstraint))
     248             :         {
     249          51 :             ReturnErrorOnFailure(reader.Get(certData.mPathLenConstraint));
     250             : 
     251          51 :             ASN1_ENCODE_INTEGER(certData.mPathLenConstraint);
     252             : 
     253          51 :             certData.mCertFlags.Set(CertFlags::kPathLenConstraintPresent);
     254             : 
     255          51 :             err = reader.Next();
     256          51 :             VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
     257             :         }
     258             : 
     259        2550 :         ReturnErrorOnFailure(reader.VerifyEndOfContainer());
     260        2550 :         ReturnErrorOnFailure(reader.ExitContainer(outerContainer));
     261             :     }
     262        2550 :     ASN1_END_SEQUENCE;
     263             : 
     264        2550 : exit:
     265        2550 :     return err;
     266             : }
     267             : 
     268         950 : static CHIP_ERROR DecodeConvertExtendedKeyUsageExtension(TLVReader & reader, ASN1Writer & writer, ChipCertificateData & certData)
     269             : {
     270             :     CHIP_ERROR err;
     271             :     TLVType outerContainer;
     272             : 
     273         950 :     certData.mCertFlags.Set(CertFlags::kExtPresent_ExtendedKeyUsage);
     274             : 
     275             :     // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
     276         950 :     ASN1_START_SEQUENCE
     277             :     {
     278         950 :         ReturnErrorOnFailure(reader.Expect(kTLVType_Array, ContextTag(kTag_ExtendedKeyUsage)));
     279         950 :         ReturnErrorOnFailure(reader.EnterContainer(outerContainer));
     280             : 
     281        2846 :         while ((err = reader.Next(AnonymousTag())) == CHIP_NO_ERROR)
     282             :         {
     283             :             uint8_t keyPurposeId;
     284        1896 :             ReturnErrorOnFailure(reader.Get(keyPurposeId));
     285             : 
     286             :             // KeyPurposeId ::= OBJECT IDENTIFIER
     287        1896 :             ASN1_ENCODE_OBJECT_ID(GetOID(kOIDCategory_KeyPurpose, keyPurposeId));
     288             : 
     289        1896 :             certData.mKeyPurposeFlags.Set(static_cast<KeyPurposeFlags>(0x01 << (keyPurposeId - 1)));
     290             :         }
     291         950 :         VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
     292         950 :         ReturnErrorOnFailure(reader.ExitContainer(outerContainer));
     293             :     }
     294         950 :     ASN1_END_SEQUENCE;
     295             : 
     296         950 : exit:
     297         950 :     return err;
     298             : }
     299             : 
     300          63 : static CHIP_ERROR DecodeConvertFutureExtension(TLVReader & tlvReader, ASN1Writer & writer, ChipCertificateData & certData)
     301             : {
     302             :     CHIP_ERROR err;
     303          63 :     ByteSpan extensionSequence;
     304             :     ASN1Reader reader;
     305             : 
     306          63 :     ReturnErrorOnFailure(tlvReader.Expect(kTLVType_ByteString, ContextTag(kTag_FutureExtension)));
     307          63 :     ReturnErrorOnFailure(tlvReader.Get(extensionSequence));
     308             : 
     309          63 :     reader.Init(extensionSequence);
     310             : 
     311             :     // Extension ::= SEQUENCE
     312          63 :     ASN1_PARSE_ENTER_SEQUENCE
     313             :     {
     314             :         OID extensionOID;
     315          63 :         bool critical = false;
     316             : 
     317          63 :         ASN1_PARSE_OBJECT_ID(extensionOID);
     318             : 
     319          63 :         VerifyOrReturnError(extensionOID == kOID_Unknown, ASN1_ERROR_UNSUPPORTED_ENCODING);
     320             : 
     321             :         // critical BOOLEAN DEFAULT FALSE,
     322          63 :         ASN1_PARSE_ANY;
     323          63 :         if (reader.GetClass() == kASN1TagClass_Universal && reader.GetTag() == kASN1UniversalTag_Boolean)
     324             :         {
     325          12 :             ASN1_GET_BOOLEAN(critical);
     326             : 
     327          12 :             if (critical)
     328             :             {
     329          12 :                 certData.mCertFlags.Set(CertFlags::kExtPresent_FutureIsCritical);
     330             :             }
     331             : 
     332          12 :             ASN1_PARSE_ANY;
     333             :         }
     334             :     }
     335          63 :     ASN1_EXIT_SEQUENCE;
     336             : 
     337          63 :     VerifyOrReturnError(CanCastTo<uint16_t>(extensionSequence.size()), ASN1_ERROR_INVALID_ENCODING);
     338             : 
     339             :     // FutureExtension SEQUENCE
     340          63 :     ReturnErrorOnFailure(writer.PutConstructedType(extensionSequence.data(), static_cast<uint16_t>(extensionSequence.size())));
     341             : 
     342          63 : exit:
     343          63 :     return err;
     344             : }
     345             : 
     346       11191 : static CHIP_ERROR DecodeConvertExtension(TLVReader & reader, ASN1Writer & writer, ChipCertificateData & certData)
     347             : {
     348       11191 :     CHIP_ERROR err = CHIP_NO_ERROR;
     349             :     Tag tlvTag;
     350             :     uint32_t extensionTagNum;
     351             : 
     352       11191 :     tlvTag = reader.GetTag();
     353       11191 :     VerifyOrReturnError(IsContextTag(tlvTag), CHIP_ERROR_INVALID_TLV_TAG);
     354       11190 :     extensionTagNum = TagNumFromTag(tlvTag);
     355             : 
     356       11190 :     if (extensionTagNum == kTag_FutureExtension)
     357             :     {
     358          63 :         ReturnErrorOnFailure(DecodeConvertFutureExtension(reader, writer, certData));
     359             :     }
     360             :     else
     361             :     {
     362             :         // Extension ::= SEQUENCE
     363       11127 :         ASN1_START_SEQUENCE
     364             :         {
     365             :             // extnID OBJECT IDENTIFIER,
     366       11127 :             ASN1_ENCODE_OBJECT_ID(GetOID(kOIDCategory_Extension, static_cast<uint8_t>(extensionTagNum)));
     367             : 
     368             :             // BasicConstraints, KeyUsage and ExtKeyUsage extensions MUST be marked as critical.
     369       11125 :             if (extensionTagNum == kTag_KeyUsage || extensionTagNum == kTag_BasicConstraints ||
     370             :                 extensionTagNum == kTag_ExtendedKeyUsage)
     371             :             {
     372        6059 :                 ASN1_ENCODE_BOOLEAN(true);
     373             :             }
     374             : 
     375             :             // extnValue OCTET STRING
     376             :             //           -- contains the DER encoding of an ASN.1 value
     377             :             //           -- corresponding to the extension type identified
     378             :             //           -- by extnID
     379       11125 :             ASN1_START_OCTET_STRING_ENCAPSULATED
     380             :             {
     381       11125 :                 if (extensionTagNum == kTag_AuthorityKeyIdentifier)
     382             :                 {
     383        2528 :                     ReturnErrorOnFailure(DecodeConvertAuthorityKeyIdentifierExtension(reader, writer, certData));
     384             :                 }
     385        8597 :                 else if (extensionTagNum == kTag_SubjectKeyIdentifier)
     386             :                 {
     387        2538 :                     ReturnErrorOnFailure(DecodeConvertSubjectKeyIdentifierExtension(reader, writer, certData));
     388             :                 }
     389        6059 :                 else if (extensionTagNum == kTag_KeyUsage)
     390             :                 {
     391        2550 :                     ReturnErrorOnFailure(DecodeConvertKeyUsageExtension(reader, writer, certData));
     392             :                 }
     393        3509 :                 else if (extensionTagNum == kTag_BasicConstraints)
     394             :                 {
     395        2559 :                     ReturnErrorOnFailure(DecodeConvertBasicConstraintsExtension(reader, writer, certData));
     396             :                 }
     397         950 :                 else if (extensionTagNum == kTag_ExtendedKeyUsage)
     398             :                 {
     399         950 :                     ReturnErrorOnFailure(DecodeConvertExtendedKeyUsageExtension(reader, writer, certData));
     400             :                 }
     401             :                 else
     402             :                 {
     403           0 :                     return CHIP_ERROR_UNSUPPORTED_CERT_FORMAT;
     404             :                 }
     405             :             }
     406       11097 :             ASN1_END_ENCAPSULATED;
     407             :         }
     408       11097 :         ASN1_END_SEQUENCE;
     409             :     }
     410             : 
     411       11162 : exit:
     412       11162 :     return err;
     413             : }
     414             : 
     415        2563 : static CHIP_ERROR DecodeConvertExtensions(TLVReader & reader, ASN1Writer & writer, ChipCertificateData & certData)
     416             : {
     417             :     CHIP_ERROR err;
     418             :     TLVType outerContainer;
     419             : 
     420        2563 :     ReturnErrorOnFailure(reader.Next(kTLVType_List, ContextTag(kTag_Extensions)));
     421        2563 :     ReturnErrorOnFailure(reader.EnterContainer(outerContainer));
     422             : 
     423             :     // extensions [3] EXPLICIT Extensions OPTIONAL
     424        2563 :     ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 3)
     425             :     {
     426             :         // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
     427        2563 :         ASN1_START_SEQUENCE
     428             :         {
     429             :             // Read certificate extension in the List.
     430       13723 :             while ((err = reader.Next()) == CHIP_NO_ERROR)
     431             :             {
     432       11191 :                 ReturnErrorOnFailure(DecodeConvertExtension(reader, writer, certData));
     433             :             }
     434        2532 :             VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
     435             :         }
     436        2532 :         ASN1_END_SEQUENCE;
     437             :     }
     438        2532 :     ASN1_END_CONSTRUCTED;
     439             : 
     440        2532 :     ReturnErrorOnFailure(reader.ExitContainer(outerContainer));
     441             : 
     442        2532 : exit:
     443        2532 :     return err;
     444             : }
     445             : 
     446        2536 : static CHIP_ERROR DecodeECDSASignature(TLVReader & reader, ChipCertificateData & certData)
     447             : {
     448        2536 :     ReturnErrorOnFailure(reader.Next(kTLVType_ByteString, ContextTag(kTag_ECDSASignature)));
     449        2536 :     ReturnErrorOnFailure(reader.Get(certData.mSignature));
     450        2536 :     return CHIP_NO_ERROR;
     451             : }
     452             : 
     453        2536 : static CHIP_ERROR DecodeConvertECDSASignature(TLVReader & reader, ASN1Writer & writer, ChipCertificateData & certData)
     454             : {
     455        2536 :     CHIP_ERROR err = CHIP_NO_ERROR;
     456             : 
     457        2536 :     ReturnErrorOnFailure(DecodeECDSASignature(reader, certData));
     458             : 
     459             :     // Converting the signature is a bit of work, so explicitly check if we have a null writer
     460        2536 :     ReturnErrorCodeIf(writer.IsNullWriter(), CHIP_NO_ERROR);
     461             : 
     462             :     // signatureValue BIT STRING
     463             :     // Per RFC3279, the ECDSA signature value is encoded in DER encapsulated in the signatureValue BIT STRING.
     464          20 :     ASN1_START_BIT_STRING_ENCAPSULATED
     465             :     {
     466          20 :         ReturnErrorOnFailure(ConvertECDSASignatureRawToDER(certData.mSignature, writer));
     467             :     }
     468          20 :     ASN1_END_ENCAPSULATED;
     469             : 
     470          20 : exit:
     471          20 :     return err;
     472             : }
     473             : 
     474             : /**
     475             :  * @brief Decode and convert the To-Be-Signed (TBS) portion of the CHIP certificate
     476             :  *        into X.509 DER encoded form.
     477             :  *
     478             :  * @param reader    A TLVReader positioned at the beginning of the TBS portion
     479             :  *                  (certificate serial number) of the CHIP certificates.
     480             :  * @param writer    A reference to the ASN1Writer to store DER encoded TBS portion of
     481             :  *                  the CHIP certificate.
     482             :  * @param certData  Structure containing data extracted from the TBS portion of the
     483             :  *                  CHIP certificate.
     484             :  *
     485             :  * Note: The reader must be positioned on the SerialNumber element.
     486             :  *
     487             :  * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
     488             :  **/
     489        2658 : static CHIP_ERROR DecodeConvertTBSCert(TLVReader & reader, ASN1Writer & writer, ChipCertificateData & certData)
     490             : {
     491             :     CHIP_ERROR err;
     492             : 
     493             :     // tbsCertificate TBSCertificate,
     494             :     // TBSCertificate ::= SEQUENCE
     495        2658 :     ASN1_START_SEQUENCE
     496             :     {
     497             :         // version [0] EXPLICIT Version DEFAULT v1
     498        2658 :         ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     499             :         {
     500             :             // Version ::= INTEGER { v1(0), v2(1), v3(2) }
     501        2658 :             ASN1_ENCODE_INTEGER(2);
     502             :         }
     503        2658 :         ASN1_END_CONSTRUCTED;
     504             : 
     505             :         // serialNumber CertificateSerialNumber
     506             :         // CertificateSerialNumber ::= INTEGER
     507        2658 :         ReturnErrorOnFailure(reader.Expect(kTLVType_ByteString, ContextTag(kTag_SerialNumber)));
     508        2649 :         ReturnErrorOnFailure(reader.Get(certData.mSerialNumber));
     509        2649 :         ReturnErrorOnFailure(writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false,
     510             :                                              certData.mSerialNumber.data(), static_cast<uint16_t>(certData.mSerialNumber.size())));
     511             : 
     512             :         // signature AlgorithmIdentifier
     513             :         // AlgorithmIdentifier ::= SEQUENCE
     514        2649 :         ASN1_START_SEQUENCE
     515             :         {
     516             :             uint8_t sigAlgoId;
     517        2649 :             ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SignatureAlgorithm)));
     518        2649 :             ReturnErrorOnFailure(reader.Get(sigAlgoId));
     519             : 
     520        2649 :             certData.mSigAlgoOID = GetOID(kOIDCategory_SigAlgo, sigAlgoId);
     521        2649 :             ASN1_ENCODE_OBJECT_ID(certData.mSigAlgoOID);
     522             :         }
     523        2640 :         ASN1_END_SEQUENCE;
     524             : 
     525             :         // issuer Name
     526        2640 :         ReturnErrorOnFailure(reader.Next(kTLVType_List, ContextTag(kTag_Issuer)));
     527        2631 :         ReturnErrorOnFailure(DecodeConvertDN(reader, writer, certData.mIssuerDN));
     528             : 
     529             :         // validity Validity,
     530        2625 :         ReturnErrorOnFailure(DecodeConvertValidity(reader, writer, certData));
     531             : 
     532             :         // subject Name
     533        2598 :         ReturnErrorOnFailure(reader.Next(kTLVType_List, ContextTag(kTag_Subject)));
     534        2589 :         ReturnErrorOnFailure(DecodeConvertDN(reader, writer, certData.mSubjectDN));
     535             : 
     536             :         // subjectPublicKeyInfo SubjectPublicKeyInfo,
     537        2573 :         ReturnErrorOnFailure(DecodeConvertSubjectPublicKeyInfo(reader, writer, certData));
     538             : 
     539             :         // certificate extensions
     540        2563 :         ReturnErrorOnFailure(DecodeConvertExtensions(reader, writer, certData));
     541             :     }
     542        2532 :     ASN1_END_SEQUENCE;
     543             : 
     544        2541 : exit:
     545        2541 :     return err;
     546             : }
     547             : 
     548             : /**
     549             :  * Variant of DecodeConvertTBSCert that handles reading a compact-pdc-identity
     550             :  * where only the subject public key is actually encoded. All other values are
     551             :  * populated / written as the well-known values mandated by the specification.
     552             :  *
     553             :  * Note: The reader must be positioned on the EllipticCurvePublicKey element.
     554             :  */
     555           5 : static CHIP_ERROR DecodeConvertTBSCertCompactIdentity(TLVReader & reader, ASN1Writer & writer, ChipCertificateData & certData)
     556             : {
     557             :     // Decode the public key, everything else is rigid
     558           5 :     ReturnErrorOnFailure(reader.Expect(kTLVType_ByteString, ContextTag(kTag_EllipticCurvePublicKey)));
     559           5 :     ReturnErrorOnFailure(reader.Get(certData.mPublicKey));
     560             : 
     561             :     // Populate rigid ChipCertificateData fields
     562           5 :     certData.mSerialNumber = kNetworkIdentitySerialNumberBytes;
     563           5 :     certData.mSigAlgoOID   = kOID_SigAlgo_ECDSAWithSHA256;
     564           5 :     InitNetworkIdentitySubject(certData.mIssuerDN);
     565           5 :     certData.mNotBeforeTime = kNetworkIdentityNotBeforeTime;
     566           5 :     certData.mNotAfterTime  = kNetworkIdentityNotAfterTime;
     567           5 :     InitNetworkIdentitySubject(certData.mSubjectDN);
     568           5 :     certData.mPubKeyAlgoOID  = kOID_PubKeyAlgo_ECPublicKey;
     569           5 :     certData.mPubKeyCurveOID = kOID_EllipticCurve_prime256v1;
     570           5 :     certData.mCertFlags.Set(CertFlags::kExtPresent_BasicConstraints);
     571           5 :     certData.mCertFlags.Set(CertFlags::kExtPresent_KeyUsage);
     572           5 :     certData.mKeyUsageFlags = kNetworkIdentityKeyUsage;
     573           5 :     certData.mCertFlags.Set(CertFlags::kExtPresent_ExtendedKeyUsage);
     574           5 :     certData.mKeyPurposeFlags = kNetworkIdentityKeyPurpose;
     575             : 
     576           5 :     if (!writer.IsNullWriter())
     577             :     {
     578           4 :         ReturnErrorOnFailure(EncodeNetworkIdentityTBSCert(certData.mPublicKey, writer));
     579             :     }
     580           5 :     return CHIP_NO_ERROR;
     581             : }
     582             : 
     583             : /**
     584             :  * Decode a CHIP TLV certificate and convert it to X.509 DER form.
     585             :  *
     586             :  * This helper function takes separate ASN1Writers for the whole Certificate
     587             :  * and the TBSCertificate, to allow the caller to control which part (if any)
     588             :  * to capture.
     589             :  *
     590             :  * If `writer` is NOT a null writer, then `tbsWriter` MUST be a reference
     591             :  * to the same writer, otherwise the overall Certificate written will not be
     592             :  * valid.
     593             :  */
     594        2663 : static CHIP_ERROR DecodeConvertCert(TLVReader & reader, ASN1Writer & writer, ASN1Writer & tbsWriter, ChipCertificateData & certData)
     595             : {
     596             :     CHIP_ERROR err;
     597             :     TLVType containerType;
     598             : 
     599        2663 :     if (reader.GetType() == kTLVType_NotSpecified)
     600             :     {
     601        2663 :         ReturnErrorOnFailure(reader.Next());
     602             :     }
     603        2663 :     ReturnErrorOnFailure(reader.Expect(kTLVType_Structure, AnonymousTag()));
     604        2663 :     ReturnErrorOnFailure(reader.EnterContainer(containerType));
     605             : 
     606             :     // Certificate ::= SEQUENCE
     607        2663 :     ASN1_START_SEQUENCE
     608             :     {
     609             :         // tbsCertificate TBSCertificate,
     610        2663 :         reader.Next();
     611        2663 :         if (reader.GetTag() == ContextTag(kTag_EllipticCurvePublicKey))
     612             :         {
     613             :             // If the struct starts with the ec-pub-key we're dealing with a
     614             :             // Network (Client) Identity in compact-pdc-identity format.
     615           5 :             DecodeConvertTBSCertCompactIdentity(reader, tbsWriter, certData);
     616             :         }
     617             :         else
     618             :         {
     619        2658 :             ReturnErrorOnFailure(DecodeConvertTBSCert(reader, tbsWriter, certData));
     620             :         }
     621             : 
     622             :         // signatureAlgorithm   AlgorithmIdentifier
     623             :         // AlgorithmIdentifier ::= SEQUENCE
     624        2537 :         ASN1_START_SEQUENCE
     625             :         {
     626        2537 :             ASN1_ENCODE_OBJECT_ID(static_cast<OID>(certData.mSigAlgoOID));
     627             :         }
     628        2536 :         ASN1_END_SEQUENCE;
     629             : 
     630             :         // signatureValue BIT STRING
     631        2536 :         ReturnErrorOnFailure(DecodeConvertECDSASignature(reader, writer, certData));
     632             :     }
     633        2536 :     ASN1_END_SEQUENCE;
     634             : 
     635             :     // Verify no more elements in certificate.
     636        2536 :     ReturnErrorOnFailure(reader.VerifyEndOfContainer());
     637        2536 :     ReturnErrorOnFailure(reader.ExitContainer(containerType));
     638             : 
     639        2537 : exit:
     640        2537 :     return err;
     641             : }
     642             : 
     643          64 : DLL_EXPORT CHIP_ERROR ConvertChipCertToX509Cert(const ByteSpan chipCert, MutableByteSpan & x509Cert)
     644             : {
     645             :     TLVReader reader;
     646             :     ASN1Writer writer;
     647          64 :     ChipCertificateData certData;
     648             : 
     649          64 :     reader.Init(chipCert);
     650             : 
     651          64 :     writer.Init(x509Cert);
     652             : 
     653          64 :     certData.Clear();
     654             : 
     655          64 :     ReturnErrorOnFailure(DecodeConvertCert(reader, writer, writer, certData));
     656             : 
     657          20 :     x509Cert.reduce_size(writer.GetLengthWritten());
     658             : 
     659          20 :     return CHIP_NO_ERROR;
     660          64 : }
     661             : 
     662         307 : CHIP_ERROR DecodeChipCert(const ByteSpan chipCert, ChipCertificateData & certData, BitFlags<CertDecodeFlags> decodeFlags)
     663             : {
     664             :     TLVReader reader;
     665             : 
     666         307 :     reader.Init(chipCert);
     667         307 :     return DecodeChipCert(reader, certData, decodeFlags);
     668             : }
     669             : 
     670        2599 : CHIP_ERROR DecodeChipCert(TLVReader & reader, ChipCertificateData & certData, BitFlags<CertDecodeFlags> decodeFlags)
     671             : {
     672             :     ASN1Writer nullWriter;
     673        2599 :     nullWriter.InitNullWriter();
     674             : 
     675        2599 :     certData.Clear();
     676             : 
     677        2599 :     if (decodeFlags.Has(CertDecodeFlags::kGenerateTBSHash))
     678             :     {
     679             :         // Create a buffer and writer to capture the TBS (to-be-signed) portion of the certificate
     680             :         // when we decode (and convert) the certificate, so we can hash it to create the TBSHash.
     681        1472 :         chip::Platform::ScopedMemoryBuffer<uint8_t> asn1TBSBuf;
     682        1472 :         VerifyOrReturnError(asn1TBSBuf.Alloc(kMaxCHIPCertDecodeBufLength), CHIP_ERROR_NO_MEMORY);
     683             :         ASN1Writer tbsWriter;
     684        1472 :         tbsWriter.Init(asn1TBSBuf.Get(), kMaxCHIPCertDecodeBufLength);
     685             : 
     686        1472 :         ReturnErrorOnFailure(DecodeConvertCert(reader, nullWriter, tbsWriter, certData));
     687             : 
     688             :         // Hash the encoded TBS certificate. Only SHA256 is supported.
     689        1430 :         VerifyOrReturnError(certData.mSigAlgoOID == kOID_SigAlgo_ECDSAWithSHA256, CHIP_ERROR_UNSUPPORTED_SIGNATURE_TYPE);
     690        1430 :         ReturnErrorOnFailure(Hash_SHA256(asn1TBSBuf.Get(), tbsWriter.GetLengthWritten(), certData.mTBSHash));
     691        1430 :         certData.mCertFlags.Set(CertFlags::kTBSHashPresent);
     692        1472 :     }
     693             :     else
     694             :     {
     695        1127 :         ReturnErrorOnFailure(DecodeConvertCert(reader, nullWriter, nullWriter, certData));
     696             :     }
     697             : 
     698             :     // If requested by the caller, mark the certificate as trusted.
     699        2516 :     if (decodeFlags.Has(CertDecodeFlags::kIsTrustAnchor))
     700             :     {
     701         713 :         certData.mCertFlags.Set(CertFlags::kIsTrustAnchor);
     702             :     }
     703             : 
     704        2516 :     return CHIP_NO_ERROR;
     705             : }
     706             : 
     707           0 : CHIP_ERROR DecodeChipDN(TLVReader & reader, ChipDN & dn)
     708             : {
     709             :     ASN1Writer writer;
     710             : 
     711           0 :     writer.InitNullWriter();
     712             : 
     713           0 :     dn.Clear();
     714             : 
     715           0 :     return DecodeConvertDN(reader, writer, dn);
     716             : }
     717             : 
     718             : } // namespace Credentials
     719             : } // namespace chip

Generated by: LCOV version 1.14