LCOV - code coverage report
Current view: top level - credentials - CHIPCertFromX509.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 217 224 96.9 %
Date: 2024-02-15 08:20:41 Functions: 8 8 100.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 standard X.509
      23             :  *      certificate to a CHIP TLV-encoded certificate.
      24             :  *
      25             :  */
      26             : 
      27             : #ifndef __STDC_LIMIT_MACROS
      28             : #define __STDC_LIMIT_MACROS
      29             : #endif
      30             : 
      31             : #include <stddef.h>
      32             : 
      33             : #include <credentials/CHIPCert.h>
      34             : #include <lib/asn1/ASN1.h>
      35             : #include <lib/asn1/ASN1Macros.h>
      36             : #include <lib/core/CHIPCore.h>
      37             : #include <lib/core/CHIPSafeCasts.h>
      38             : #include <lib/core/Optional.h>
      39             : #include <lib/core/TLV.h>
      40             : #include <lib/support/BytesToHex.h>
      41             : #include <lib/support/CodeUtils.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         257 : static CHIP_ERROR ConvertDistinguishedName(ASN1Reader & reader, TLVWriter & writer, Tag tag)
      54             : {
      55         257 :     ChipDN dn;
      56         257 :     ReturnErrorOnFailure(dn.DecodeFromASN1(reader));
      57         250 :     return dn.EncodeToTLV(writer, tag);
      58         257 : }
      59             : 
      60         132 : static CHIP_ERROR ConvertValidity(ASN1Reader & reader, TLVWriter & writer)
      61             : {
      62             :     CHIP_ERROR err;
      63             :     ASN1UniversalTime asn1Time;
      64             :     uint32_t chipEpochTimeNotBefore;
      65             :     uint32_t chipEpochTimeNotAfter;
      66             : 
      67         132 :     ASN1_PARSE_ENTER_SEQUENCE
      68             :     {
      69         132 :         ASN1_PARSE_TIME(asn1Time);
      70         129 :         ReturnErrorOnFailure(ASN1ToChipEpochTime(asn1Time, chipEpochTimeNotBefore));
      71             : 
      72         129 :         ASN1_PARSE_TIME(asn1Time);
      73         126 :         ReturnErrorOnFailure(ASN1ToChipEpochTime(asn1Time, chipEpochTimeNotAfter));
      74             : 
      75             :         // Perform this check if NotAfter value is different from Never-Expire value.
      76         126 :         if (chipEpochTimeNotAfter != kNullCertTime)
      77             :         {
      78         122 :             VerifyOrReturnError(chipEpochTimeNotBefore < chipEpochTimeNotAfter, ASN1_ERROR_INVALID_ENCODING);
      79             :         }
      80             : 
      81         123 :         ReturnErrorOnFailure(writer.Put(ContextTag(kTag_NotBefore), chipEpochTimeNotBefore));
      82         123 :         ReturnErrorOnFailure(writer.Put(ContextTag(kTag_NotAfter), chipEpochTimeNotAfter));
      83             :     }
      84         123 :     ASN1_EXIT_SEQUENCE;
      85             : 
      86         129 : exit:
      87         129 :     return err;
      88             : }
      89             : 
      90         117 : static CHIP_ERROR ConvertSubjectPublicKeyInfo(ASN1Reader & reader, TLVWriter & writer)
      91             : {
      92             :     CHIP_ERROR err;
      93             :     OID pubKeyAlgoOID, pubKeyCurveOID;
      94             : 
      95             :     // subjectPublicKeyInfo SubjectPublicKeyInfo,
      96         117 :     ASN1_PARSE_ENTER_SEQUENCE
      97             :     {
      98             :         // algorithm AlgorithmIdentifier,
      99             :         // AlgorithmIdentifier ::= SEQUENCE
     100         117 :         ASN1_PARSE_ENTER_SEQUENCE
     101             :         {
     102             :             // algorithm OBJECT IDENTIFIER,
     103         117 :             ASN1_PARSE_OBJECT_ID(pubKeyAlgoOID);
     104             : 
     105             :             // Verify that the algorithm type is supported.
     106         117 :             VerifyOrExit(pubKeyAlgoOID == kOID_PubKeyAlgo_ECPublicKey, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     107             : 
     108         117 :             err = writer.Put(ContextTag(kTag_PublicKeyAlgorithm), GetOIDEnum(pubKeyAlgoOID));
     109         117 :             SuccessOrExit(err);
     110             : 
     111             :             // EcpkParameters ::= CHOICE {
     112             :             //     ecParameters  ECParameters,
     113             :             //     namedCurve    OBJECT IDENTIFIER,
     114             :             //     implicitlyCA  NULL }
     115         117 :             ASN1_PARSE_ANY;
     116             : 
     117             :             // ecParameters and implicitlyCA not supported.
     118         117 :             if (reader.GetClass() == kASN1TagClass_Universal && reader.GetTag() == kASN1UniversalTag_Sequence)
     119             :             {
     120           0 :                 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     121             :             }
     122         117 :             if (reader.GetClass() == kASN1TagClass_Universal && reader.GetTag() == kASN1UniversalTag_Null)
     123             :             {
     124           0 :                 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     125             :             }
     126             : 
     127         117 :             ASN1_VERIFY_TAG(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
     128             : 
     129         117 :             ASN1_GET_OBJECT_ID(pubKeyCurveOID);
     130             : 
     131             :             // Verify the curve name is recognized.
     132         117 :             VerifyOrExit(GetOIDCategory(pubKeyCurveOID) == kOIDCategory_EllipticCurve, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     133             : 
     134         114 :             err = writer.Put(ContextTag(kTag_EllipticCurveIdentifier), GetOIDEnum(pubKeyCurveOID));
     135         114 :             SuccessOrExit(err);
     136             :         }
     137         114 :         ASN1_EXIT_SEQUENCE;
     138             : 
     139             :         // subjectPublicKey BIT STRING
     140         114 :         ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_BitString);
     141             : 
     142             :         // Verify public key length.
     143         114 :         VerifyOrExit(reader.GetValueLen() > 0, err = ASN1_ERROR_INVALID_ENCODING);
     144             : 
     145             :         // The first byte is Unused Bit Count value, which should be zero.
     146         114 :         VerifyOrExit(reader.GetValue()[0] == 0, err = ASN1_ERROR_INVALID_ENCODING);
     147             : 
     148             :         // Copy the X9.62 encoded EC point into the CHIP certificate as a byte string.
     149             :         // Skip the first Unused Bit Count byte.
     150         114 :         err = writer.PutBytes(ContextTag(kTag_EllipticCurvePublicKey), reader.GetValue() + 1, reader.GetValueLen() - 1);
     151         114 :         SuccessOrExit(err);
     152             :     }
     153         114 :     ASN1_EXIT_SEQUENCE;
     154             : 
     155         117 : exit:
     156         117 :     return err;
     157             : }
     158             : 
     159         461 : static CHIP_ERROR ConvertExtension(ASN1Reader & reader, TLVWriter & writer)
     160             : {
     161             :     CHIP_ERROR err;
     162             :     TLVType outerContainer;
     163             :     OID extensionOID;
     164         461 :     bool critical = false;
     165             :     const uint8_t * extensionSequence;
     166             :     uint32_t extensionSequenceLen;
     167             : 
     168         461 :     err = reader.GetConstructedType(extensionSequence, extensionSequenceLen);
     169         461 :     SuccessOrExit(err);
     170             : 
     171             :     // Extension ::= SEQUENCE
     172         461 :     ASN1_ENTER_SEQUENCE
     173             :     {
     174             :         // extnID OBJECT IDENTIFIER,
     175         461 :         ASN1_PARSE_OBJECT_ID(extensionOID);
     176             : 
     177             :         // The kOID_Unknown will be interpreted and encoded as future-extension.
     178         461 :         if (extensionOID != kOID_Unknown)
     179             :         {
     180         453 :             VerifyOrExit(GetOIDCategory(extensionOID) == kOIDCategory_Extension, err = ASN1_ERROR_INVALID_ENCODING);
     181             :         }
     182             : 
     183             :         // critical BOOLEAN DEFAULT FALSE,
     184         461 :         ASN1_PARSE_ANY;
     185         461 :         if (reader.GetClass() == kASN1TagClass_Universal && reader.GetTag() == kASN1UniversalTag_Boolean)
     186             :         {
     187         253 :             ASN1_GET_BOOLEAN(critical);
     188             : 
     189         253 :             VerifyOrExit(critical, err = ASN1_ERROR_INVALID_ENCODING);
     190             : 
     191         253 :             ASN1_PARSE_ANY;
     192             :         }
     193             : 
     194             :         // extnValue OCTET STRING
     195             :         //           -- contains the DER encoding of an ASN.1 value
     196             :         //           -- corresponding to the extension type identified
     197             :         //           -- by extnID
     198         461 :         ASN1_ENTER_ENCAPSULATED(kASN1TagClass_Universal, kASN1UniversalTag_OctetString)
     199             :         {
     200         461 :             if (extensionOID == kOID_Extension_AuthorityKeyIdentifier)
     201             :             {
     202             :                 // This extension MUST be marked as non-critical.
     203          93 :                 VerifyOrExit(!critical, err = ASN1_ERROR_INVALID_ENCODING);
     204             : 
     205             :                 // AuthorityKeyIdentifier ::= SEQUENCE
     206          93 :                 ASN1_PARSE_ENTER_SEQUENCE
     207             :                 {
     208          93 :                     err = reader.Next();
     209          93 :                     SuccessOrExit(err);
     210             : 
     211             :                     // keyIdentifier [0] IMPLICIT KeyIdentifier,
     212             :                     // KeyIdentifier ::= OCTET STRING
     213          93 :                     VerifyOrExit(reader.GetClass() == kASN1TagClass_ContextSpecific && reader.GetTag() == 0,
     214             :                                  err = ASN1_ERROR_INVALID_ENCODING);
     215             : 
     216          93 :                     VerifyOrExit(reader.IsConstructed() == false, err = ASN1_ERROR_INVALID_ENCODING);
     217          93 :                     VerifyOrExit(reader.GetValueLen() == kKeyIdentifierLength, err = ASN1_ERROR_INVALID_ENCODING);
     218             : 
     219          90 :                     err = writer.PutBytes(ContextTag(kTag_AuthorityKeyIdentifier), reader.GetValue(), reader.GetValueLen());
     220          90 :                     SuccessOrExit(err);
     221             : 
     222          89 :                     err = reader.Next();
     223          89 :                     VerifyOrExit(err == ASN1_END, err = ASN1_ERROR_INVALID_ENCODING);
     224             :                 }
     225          89 :                 ASN1_EXIT_SEQUENCE;
     226             :             }
     227         368 :             else if (extensionOID == kOID_Extension_SubjectKeyIdentifier)
     228             :             {
     229             :                 // This extension MUST be marked as non-critical.
     230          96 :                 VerifyOrExit(!critical, err = ASN1_ERROR_INVALID_ENCODING);
     231             : 
     232             :                 // SubjectKeyIdentifier ::= KeyIdentifier
     233             :                 // KeyIdentifier ::= OCTET STRING
     234          96 :                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
     235             : 
     236          96 :                 VerifyOrExit(reader.GetValueLen() == kKeyIdentifierLength, err = ASN1_ERROR_INVALID_ENCODING);
     237             : 
     238          93 :                 err = writer.PutBytes(ContextTag(kTag_SubjectKeyIdentifier), reader.GetValue(), reader.GetValueLen());
     239          93 :                 SuccessOrExit(err);
     240             :             }
     241         272 :             else if (extensionOID == kOID_Extension_KeyUsage)
     242             :             {
     243             :                 // This extension MUST be marked as critical.
     244         104 :                 VerifyOrExit(critical, err = ASN1_ERROR_INVALID_ENCODING);
     245             : 
     246             :                 // KeyUsage ::= BIT STRING
     247          98 :                 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_BitString);
     248             : 
     249             :                 uint32_t keyUsageBits;
     250          98 :                 err = reader.GetBitString(keyUsageBits);
     251          98 :                 SuccessOrExit(err);
     252          98 :                 VerifyOrExit(CanCastTo<uint16_t>(keyUsageBits), err = ASN1_ERROR_INVALID_ENCODING);
     253             : 
     254             :                 // Check that only supported flags are set.
     255          98 :                 BitFlags<KeyUsageFlags> keyUsageFlags(static_cast<uint16_t>(keyUsageBits));
     256          98 :                 VerifyOrExit(keyUsageFlags.HasOnly(
     257             :                                  KeyUsageFlags::kDigitalSignature, KeyUsageFlags::kNonRepudiation, KeyUsageFlags::kKeyEncipherment,
     258             :                                  KeyUsageFlags::kDataEncipherment, KeyUsageFlags::kKeyAgreement, KeyUsageFlags::kKeyCertSign,
     259             :                                  KeyUsageFlags::kCRLSign, KeyUsageFlags::kEncipherOnly, KeyUsageFlags::kEncipherOnly),
     260             :                              err = ASN1_ERROR_INVALID_ENCODING);
     261             : 
     262          98 :                 err = writer.Put(ContextTag(kTag_KeyUsage), keyUsageBits);
     263          98 :                 SuccessOrExit(err);
     264             :             }
     265         168 :             else if (extensionOID == kOID_Extension_BasicConstraints)
     266             :             {
     267             :                 // This extension MUST be marked as critical.
     268         114 :                 VerifyOrExit(critical, err = ASN1_ERROR_INVALID_ENCODING);
     269             : 
     270             :                 // BasicConstraints ::= SEQUENCE
     271         108 :                 ASN1_PARSE_ENTER_SEQUENCE
     272             :                 {
     273         108 :                     bool isCA                 = false;
     274         108 :                     int64_t pathLenConstraint = -1;
     275             : 
     276             :                     // cA BOOLEAN DEFAULT FALSE
     277         108 :                     err = reader.Next();
     278         168 :                     if (err == CHIP_NO_ERROR && reader.GetClass() == kASN1TagClass_Universal &&
     279          60 :                         reader.GetTag() == kASN1UniversalTag_Boolean)
     280             :                     {
     281          60 :                         ASN1_GET_BOOLEAN(isCA);
     282             : 
     283          56 :                         VerifyOrExit(isCA, err = ASN1_ERROR_INVALID_ENCODING);
     284             : 
     285          56 :                         err = reader.Next();
     286             :                     }
     287             : 
     288             :                     // pathLenConstraint INTEGER (0..MAX) OPTIONAL
     289         115 :                     if (err == CHIP_NO_ERROR && reader.GetClass() == kASN1TagClass_Universal &&
     290           7 :                         reader.GetTag() == kASN1UniversalTag_Integer)
     291             :                     {
     292           7 :                         ASN1_GET_INTEGER(pathLenConstraint);
     293             : 
     294           7 :                         VerifyOrExit(CanCastTo<uint8_t>(pathLenConstraint), err = ASN1_ERROR_INVALID_ENCODING);
     295             : 
     296             :                         // pathLenConstraint is present only when cA is TRUE
     297           7 :                         VerifyOrExit(isCA, err = ASN1_ERROR_INVALID_ENCODING);
     298             :                     }
     299             : 
     300         104 :                     err = writer.StartContainer(ContextTag(kTag_BasicConstraints), kTLVType_Structure, outerContainer);
     301         104 :                     SuccessOrExit(err);
     302             : 
     303             :                     // Set also when cA is FALSE
     304         104 :                     err = writer.PutBoolean(ContextTag(kTag_BasicConstraints_IsCA), isCA);
     305         104 :                     SuccessOrExit(err);
     306             : 
     307         104 :                     if (pathLenConstraint != -1)
     308             :                     {
     309           3 :                         err = writer.Put(ContextTag(kTag_BasicConstraints_PathLenConstraint),
     310             :                                          static_cast<uint8_t>(pathLenConstraint));
     311           3 :                         SuccessOrExit(err);
     312             :                     }
     313             : 
     314         104 :                     err = writer.EndContainer(outerContainer);
     315         104 :                     SuccessOrExit(err);
     316             :                 }
     317         104 :                 ASN1_EXIT_SEQUENCE;
     318             :             }
     319          54 :             else if (extensionOID == kOID_Extension_ExtendedKeyUsage)
     320             :             {
     321             :                 // This extension MUST be marked as critical.
     322          46 :                 VerifyOrExit(critical, err = ASN1_ERROR_INVALID_ENCODING);
     323             : 
     324          46 :                 err = writer.StartContainer(ContextTag(kTag_ExtendedKeyUsage), kTLVType_Array, outerContainer);
     325          46 :                 SuccessOrExit(err);
     326             : 
     327             :                 // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
     328          46 :                 ASN1_PARSE_ENTER_SEQUENCE
     329             :                 {
     330         137 :                     while ((err = reader.Next()) == CHIP_NO_ERROR)
     331             :                     {
     332             :                         // KeyPurposeId ::= OBJECT IDENTIFIER
     333             :                         OID keyPurposeOID;
     334          91 :                         ASN1_GET_OBJECT_ID(keyPurposeOID);
     335             : 
     336          91 :                         VerifyOrExit(keyPurposeOID != kOID_Unknown, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     337          91 :                         VerifyOrExit(GetOIDCategory(keyPurposeOID) == kOIDCategory_KeyPurpose, err = ASN1_ERROR_INVALID_ENCODING);
     338             : 
     339          91 :                         err = writer.Put(AnonymousTag(), GetOIDEnum(keyPurposeOID));
     340          91 :                         SuccessOrExit(err);
     341             :                     }
     342          46 :                     if (err != ASN1_END)
     343             :                     {
     344           0 :                         SuccessOrExit(err);
     345             :                     }
     346             :                 }
     347          46 :                 ASN1_EXIT_SEQUENCE;
     348             : 
     349          46 :                 err = writer.EndContainer(outerContainer);
     350          46 :                 SuccessOrExit(err);
     351             :             }
     352             :             // Any other extension is treated as FutureExtension
     353             :             else
     354             :             {
     355           8 :                 err = writer.PutBytes(ContextTag(kTag_FutureExtension), extensionSequence, extensionSequenceLen);
     356           8 :                 SuccessOrExit(err);
     357             : 
     358           8 :                 ASN1_PARSE_ANY;
     359             :             }
     360             :         }
     361         438 :         ASN1_EXIT_ENCAPSULATED;
     362             :     }
     363         438 :     ASN1_EXIT_SEQUENCE;
     364             : 
     365         461 : exit:
     366         461 :     return err;
     367             : }
     368             : 
     369         114 : static CHIP_ERROR ConvertExtensions(ASN1Reader & reader, TLVWriter & writer)
     370             : {
     371             :     CHIP_ERROR err;
     372             :     TLVType containerType;
     373             : 
     374         114 :     err = writer.StartContainer(ContextTag(kTag_Extensions), kTLVType_List, containerType);
     375         114 :     SuccessOrExit(err);
     376             : 
     377             :     // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
     378         114 :     ASN1_PARSE_ENTER_SEQUENCE
     379             :     {
     380         552 :         while ((err = reader.Next()) == CHIP_NO_ERROR)
     381             :         {
     382         461 :             err = ConvertExtension(reader, writer);
     383         461 :             SuccessOrExit(err);
     384             :         }
     385             : 
     386          91 :         if (err != ASN1_END)
     387             :         {
     388           0 :             SuccessOrExit(err);
     389             :         }
     390             :     }
     391          91 :     ASN1_EXIT_SEQUENCE;
     392             : 
     393          91 :     err = writer.EndContainer(containerType);
     394          91 :     SuccessOrExit(err);
     395             : 
     396         114 : exit:
     397         114 :     return err;
     398             : }
     399             : 
     400          91 : CHIP_ERROR ConvertECDSASignatureDERToRaw(ASN1Reader & reader, TLVWriter & writer, Tag tag)
     401             : {
     402          91 :     CHIP_ERROR err = CHIP_NO_ERROR;
     403             :     uint8_t rawSig[kP256_ECDSA_Signature_Length_Raw];
     404             : 
     405             :     // Per RFC3279, the ECDSA signature value is encoded in DER encapsulated in the signatureValue BIT STRING.
     406          91 :     ASN1_ENTER_ENCAPSULATED(kASN1TagClass_Universal, kASN1UniversalTag_BitString)
     407             :     {
     408             :         // Ecdsa-Sig-Value ::= SEQUENCE
     409          91 :         ASN1_PARSE_ENTER_SEQUENCE
     410             :         {
     411             :             // r INTEGER
     412          91 :             ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_Integer);
     413          91 :             ReturnErrorOnFailure(
     414             :                 ConvertIntegerDERToRaw(ByteSpan(reader.GetValue(), reader.GetValueLen()), rawSig, kP256_FE_Length));
     415             : 
     416             :             // s INTEGER
     417          91 :             ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_Integer);
     418          91 :             ReturnErrorOnFailure(ConvertIntegerDERToRaw(ByteSpan(reader.GetValue(), reader.GetValueLen()), rawSig + kP256_FE_Length,
     419             :                                                         kP256_FE_Length));
     420             :         }
     421          91 :         ASN1_EXIT_SEQUENCE;
     422             :     }
     423          91 :     ASN1_EXIT_ENCAPSULATED;
     424             : 
     425          91 :     ReturnErrorOnFailure(writer.PutBytes(tag, rawSig, kP256_ECDSA_Signature_Length_Raw));
     426             : 
     427          90 : exit:
     428          90 :     return err;
     429             : }
     430             : 
     431         140 : static CHIP_ERROR ConvertCertificate(ASN1Reader & reader, TLVWriter & writer, Tag tag)
     432             : {
     433             :     CHIP_ERROR err;
     434             :     int64_t version;
     435             :     OID sigAlgoOID;
     436             :     TLVType containerType;
     437             : 
     438         140 :     err = writer.StartContainer(tag, kTLVType_Structure, containerType);
     439         140 :     SuccessOrExit(err);
     440             : 
     441             :     // Certificate ::= SEQUENCE
     442         140 :     ASN1_PARSE_ENTER_SEQUENCE
     443             :     {
     444             :         // tbsCertificate TBSCertificate,
     445             :         // TBSCertificate ::= SEQUENCE
     446         140 :         ASN1_PARSE_ENTER_SEQUENCE
     447             :         {
     448             :             // version [0] EXPLICIT Version DEFAULT v1
     449         140 :             ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     450             :             {
     451             :                 // Version ::= INTEGER { v1(0), v2(1), v3(2) }
     452         140 :                 ASN1_PARSE_INTEGER(version);
     453             : 
     454             :                 // Verify that the X.509 certificate version is v3
     455         140 :                 VerifyOrExit(version == 2, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     456             :             }
     457         137 :             ASN1_EXIT_CONSTRUCTED;
     458             : 
     459             :             // serialNumber CertificateSerialNumber
     460             :             // CertificateSerialNumber ::= INTEGER
     461         137 :             ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_Integer);
     462         137 :             err = writer.PutBytes(ContextTag(kTag_SerialNumber), reader.GetValue(), reader.GetValueLen());
     463         137 :             SuccessOrExit(err);
     464             : 
     465             :             // signature AlgorithmIdentifier
     466             :             // AlgorithmIdentifier ::= SEQUENCE
     467         137 :             ASN1_PARSE_ENTER_SEQUENCE
     468             :             {
     469             :                 // algorithm OBJECT IDENTIFIER,
     470         137 :                 ASN1_PARSE_OBJECT_ID(sigAlgoOID);
     471             : 
     472         137 :                 VerifyOrExit(sigAlgoOID == kOID_SigAlgo_ECDSAWithSHA256, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     473             : 
     474         134 :                 err = writer.Put(ContextTag(kTag_SignatureAlgorithm), GetOIDEnum(sigAlgoOID));
     475         134 :                 SuccessOrExit(err);
     476             :             }
     477         134 :             ASN1_EXIT_SEQUENCE;
     478             : 
     479             :             // issuer Name
     480         134 :             err = ConvertDistinguishedName(reader, writer, ContextTag(kTag_Issuer));
     481         134 :             SuccessOrExit(err);
     482             : 
     483             :             // validity Validity,
     484         132 :             err = ConvertValidity(reader, writer);
     485         132 :             SuccessOrExit(err);
     486             : 
     487             :             // subject Name,
     488         123 :             err = ConvertDistinguishedName(reader, writer, ContextTag(kTag_Subject));
     489         123 :             SuccessOrExit(err);
     490             : 
     491         117 :             err = ConvertSubjectPublicKeyInfo(reader, writer);
     492         117 :             SuccessOrExit(err);
     493             : 
     494         114 :             err = reader.Next();
     495             : 
     496             :             // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
     497             :             // Not supported.
     498         114 :             if (err == CHIP_NO_ERROR && reader.GetClass() == kASN1TagClass_ContextSpecific && reader.GetTag() == 1)
     499             :             {
     500           0 :                 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     501             :             }
     502             : 
     503             :             // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
     504             :             // Not supported.
     505         114 :             if (err == CHIP_NO_ERROR && reader.GetClass() == kASN1TagClass_ContextSpecific && reader.GetTag() == 2)
     506             :             {
     507           0 :                 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     508             :             }
     509             : 
     510             :             // extensions [3] EXPLICIT Extensions OPTIONAL
     511         114 :             if (err == CHIP_NO_ERROR && reader.GetClass() == kASN1TagClass_ContextSpecific && reader.GetTag() == 3)
     512             :             {
     513         114 :                 ASN1_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 3)
     514             :                 {
     515         114 :                     err = ConvertExtensions(reader, writer);
     516         114 :                     SuccessOrExit(err);
     517             :                 }
     518          91 :                 ASN1_EXIT_CONSTRUCTED;
     519             : 
     520          91 :                 err = reader.Next();
     521             :             }
     522             : 
     523          91 :             if (err != ASN1_END)
     524             :             {
     525           0 :                 ExitNow();
     526             :             }
     527             :         }
     528          91 :         ASN1_EXIT_SEQUENCE;
     529             : 
     530             :         // signatureAlgorithm AlgorithmIdentifier
     531             :         // AlgorithmIdentifier ::= SEQUENCE
     532          91 :         ASN1_PARSE_ENTER_SEQUENCE
     533             :         {
     534             :             OID localSigAlgoOID;
     535             : 
     536             :             // algorithm OBJECT IDENTIFIER,
     537          91 :             ASN1_PARSE_OBJECT_ID(localSigAlgoOID);
     538             : 
     539             :             // Verify that the signatureAlgorithm is the same as the "signature" field in TBSCertificate.
     540          91 :             VerifyOrExit(localSigAlgoOID == sigAlgoOID, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
     541             :         }
     542          91 :         ASN1_EXIT_SEQUENCE;
     543             : 
     544             :         // signatureValue BIT STRING
     545          91 :         ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_BitString);
     546             : 
     547          91 :         ReturnErrorOnFailure(ConvertECDSASignatureDERToRaw(reader, writer, ContextTag(kTag_ECDSASignature)));
     548             :     }
     549          90 :     ASN1_EXIT_SEQUENCE;
     550             : 
     551          90 :     err = writer.EndContainer(containerType);
     552          90 :     SuccessOrExit(err);
     553             : 
     554         139 : exit:
     555         139 :     return err;
     556             : }
     557             : 
     558         140 : CHIP_ERROR ConvertX509CertToChipCert(const ByteSpan x509Cert, MutableByteSpan & chipCert)
     559             : {
     560             :     ASN1Reader reader;
     561         140 :     TLVWriter writer;
     562             : 
     563         140 :     VerifyOrReturnError(!x509Cert.empty(), CHIP_ERROR_INVALID_ARGUMENT);
     564         140 :     VerifyOrReturnError(CanCastTo<uint32_t>(x509Cert.size()), CHIP_ERROR_INVALID_ARGUMENT);
     565             : 
     566         140 :     reader.Init(x509Cert);
     567             : 
     568         140 :     writer.Init(chipCert);
     569             : 
     570         140 :     ReturnErrorOnFailure(ConvertCertificate(reader, writer, AnonymousTag()));
     571             : 
     572          90 :     ReturnErrorOnFailure(writer.Finalize());
     573             : 
     574          90 :     chipCert.reduce_size(writer.GetLengthWritten());
     575             : 
     576          90 :     return CHIP_NO_ERROR;
     577             : }
     578             : 
     579             : } // namespace Credentials
     580             : } // namespace chip

Generated by: LCOV version 1.14