Matter SDK Coverage Report
Current view: top level - credentials - CHIPCertToX509.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 98.1 % 270 265
Test Date: 2025-01-17 19:00:11 Functions: 95.0 % 20 19

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

Generated by: LCOV version 2.0-1