LCOV - code coverage report
Current view: top level - credentials - GenerateChipX509Cert.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 210 210 100.0 %
Date: 2024-02-15 08:20:41 Functions: 18 18 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2021-2022 Project CHIP Authors
       4             :  *    All rights reserved.
       5             :  *
       6             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7             :  *    you may not use this file except in compliance with the License.
       8             :  *    You may obtain a copy of the License at
       9             :  *
      10             :  *        http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  *    Unless required by applicable law or agreed to in writing, software
      13             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  *    See the License for the specific language governing permissions and
      16             :  *    limitations under the License.
      17             :  */
      18             : 
      19             : /**
      20             :  *    @file
      21             :  *      This file implements methods for generating CHIP X.509 certificate.
      22             :  *
      23             :  */
      24             : 
      25             : #ifndef __STDC_LIMIT_MACROS
      26             : #define __STDC_LIMIT_MACROS
      27             : #endif
      28             : 
      29             : #include <algorithm>
      30             : #include <initializer_list>
      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/support/CodeUtils.h>
      40             : #include <lib/support/DLLUtil.h>
      41             : #include <protocols/Protocols.h>
      42             : 
      43             : namespace chip {
      44             : namespace Credentials {
      45             : 
      46             : using namespace chip::ASN1;
      47             : using namespace chip::Crypto;
      48             : using namespace chip::Protocols;
      49             : 
      50             : namespace {
      51             : 
      52             : enum IsCACert
      53             : {
      54             :     kCACert,
      55             :     kNotCACert,
      56             : };
      57             : 
      58         147 : CHIP_ERROR EncodeSubjectPublicKeyInfo(const Crypto::P256PublicKey & pubkey, ASN1Writer & writer)
      59             : {
      60         147 :     CHIP_ERROR err = CHIP_NO_ERROR;
      61             : 
      62         147 :     ASN1_START_SEQUENCE
      63             :     {
      64         147 :         ASN1_START_SEQUENCE
      65             :         {
      66         147 :             ASN1_ENCODE_OBJECT_ID(kOID_PubKeyAlgo_ECPublicKey);
      67         147 :             ASN1_ENCODE_OBJECT_ID(kOID_EllipticCurve_prime256v1);
      68             :         }
      69         147 :         ASN1_END_SEQUENCE;
      70             : 
      71         147 :         ReturnErrorOnFailure(writer.PutBitString(0, pubkey, static_cast<uint8_t>(pubkey.Length())));
      72             :     }
      73         147 :     ASN1_END_SEQUENCE;
      74             : 
      75         147 : exit:
      76         147 :     return err;
      77             : }
      78             : 
      79         142 : CHIP_ERROR EncodeAuthorityKeyIdentifierExtension(const Crypto::P256PublicKey & pubkey, ASN1Writer & writer)
      80             : {
      81         142 :     CHIP_ERROR err = CHIP_NO_ERROR;
      82             : 
      83         142 :     ASN1_START_SEQUENCE
      84             :     {
      85         142 :         ASN1_ENCODE_OBJECT_ID(kOID_Extension_AuthorityKeyIdentifier);
      86             : 
      87         142 :         ASN1_START_OCTET_STRING_ENCAPSULATED
      88             :         {
      89         142 :             ASN1_START_SEQUENCE
      90             :             {
      91             :                 uint8_t keyid[kSHA1_Hash_Length];
      92         142 :                 ReturnErrorOnFailure(Crypto::Hash_SHA1(pubkey, pubkey.Length(), keyid));
      93             : 
      94         142 :                 ReturnErrorOnFailure(
      95             :                     writer.PutOctetString(kASN1TagClass_ContextSpecific, 0, keyid, static_cast<uint8_t>(sizeof(keyid))));
      96             :             }
      97         142 :             ASN1_END_SEQUENCE;
      98             :         }
      99         142 :         ASN1_END_ENCAPSULATED;
     100             :     }
     101         142 :     ASN1_END_SEQUENCE;
     102             : 
     103         142 : exit:
     104         142 :     return err;
     105             : }
     106             : 
     107         142 : CHIP_ERROR EncodeSubjectKeyIdentifierExtension(const Crypto::P256PublicKey & pubkey, ASN1Writer & writer)
     108             : {
     109         142 :     CHIP_ERROR err = CHIP_NO_ERROR;
     110             : 
     111         142 :     ASN1_START_SEQUENCE
     112             :     {
     113         142 :         ASN1_ENCODE_OBJECT_ID(kOID_Extension_SubjectKeyIdentifier);
     114             : 
     115         142 :         ASN1_START_OCTET_STRING_ENCAPSULATED
     116             :         {
     117             :             uint8_t keyid[kSHA1_Hash_Length];
     118         142 :             ReturnErrorOnFailure(Crypto::Hash_SHA1(pubkey, pubkey.Length(), keyid));
     119             : 
     120         142 :             ReturnErrorOnFailure(writer.PutOctetString(keyid, static_cast<uint8_t>(sizeof(keyid))));
     121             :         }
     122         142 :         ASN1_END_ENCAPSULATED;
     123             :     }
     124         142 :     ASN1_END_SEQUENCE;
     125             : 
     126         142 : exit:
     127         142 :     return err;
     128             : }
     129             : 
     130          65 : CHIP_ERROR EncodeExtKeyUsageExtension(std::initializer_list<OID> keyPurposeOIDs, ASN1Writer & writer)
     131             : {
     132          65 :     CHIP_ERROR err = CHIP_NO_ERROR;
     133          65 :     ASN1_START_SEQUENCE
     134             :     {
     135          65 :         ASN1_ENCODE_OBJECT_ID(kOID_Extension_ExtendedKeyUsage);
     136             : 
     137             :         // ExtKeyUsage extension MUST be marked as critical.
     138          65 :         ASN1_ENCODE_BOOLEAN(true);
     139          65 :         ASN1_START_OCTET_STRING_ENCAPSULATED
     140             :         {
     141          65 :             ASN1_START_SEQUENCE
     142             :             {
     143         195 :                 for (auto && oid : keyPurposeOIDs)
     144             :                 {
     145         130 :                     ASN1_ENCODE_OBJECT_ID(oid);
     146             :                 }
     147             :             }
     148          65 :             ASN1_END_SEQUENCE;
     149             :         }
     150          65 :         ASN1_END_ENCAPSULATED;
     151             :     }
     152          65 :     ASN1_END_SEQUENCE;
     153             : 
     154          65 : exit:
     155          65 :     return err;
     156             : }
     157             : 
     158         147 : CHIP_ERROR EncodeKeyUsageExtension(BitFlags<KeyUsageFlags> keyUsageFlags, ASN1Writer & writer)
     159             : {
     160         147 :     CHIP_ERROR err = CHIP_NO_ERROR;
     161         147 :     ASN1_START_SEQUENCE
     162             :     {
     163         147 :         ASN1_ENCODE_OBJECT_ID(kOID_Extension_KeyUsage);
     164             : 
     165             :         // KeyUsage extension MUST be marked as critical.
     166         147 :         ASN1_ENCODE_BOOLEAN(true);
     167         147 :         ASN1_START_OCTET_STRING_ENCAPSULATED
     168             :         {
     169         147 :             ASN1_ENCODE_BIT_STRING(keyUsageFlags.Raw());
     170             :         }
     171         147 :         ASN1_END_ENCAPSULATED;
     172             :     }
     173         147 :     ASN1_END_SEQUENCE;
     174             : 
     175         147 : exit:
     176         147 :     return err;
     177             : }
     178             : 
     179         147 : CHIP_ERROR EncodeIsCAExtension(IsCACert isCA, ASN1Writer & writer)
     180             : {
     181         147 :     CHIP_ERROR err = CHIP_NO_ERROR;
     182         147 :     ASN1_START_SEQUENCE
     183             :     {
     184         147 :         ASN1_ENCODE_OBJECT_ID(kOID_Extension_BasicConstraints);
     185             : 
     186             :         // BasicConstraints extension MUST be marked as critical.
     187         147 :         ASN1_ENCODE_BOOLEAN(true);
     188             : 
     189         147 :         ASN1_START_OCTET_STRING_ENCAPSULATED
     190             :         {
     191         147 :             ASN1_START_SEQUENCE
     192             :             {
     193             :                 // cA BOOLEAN
     194         147 :                 if (isCA == kCACert)
     195             :                 {
     196             :                     // Encode the boolean only if isCA is true
     197          82 :                     ASN1_ENCODE_BOOLEAN(true);
     198             :                 }
     199             :             }
     200         147 :             ASN1_END_SEQUENCE;
     201             :         }
     202         147 :         ASN1_END_ENCAPSULATED;
     203             :     }
     204         147 :     ASN1_END_SEQUENCE;
     205             : 
     206         147 : exit:
     207         147 :     return err;
     208             : }
     209             : 
     210          82 : CHIP_ERROR EncodeCASpecificExtensions(ASN1Writer & writer)
     211             : {
     212          82 :     ReturnErrorOnFailure(EncodeIsCAExtension(kCACert, writer));
     213          82 :     ReturnErrorOnFailure(
     214             :         EncodeKeyUsageExtension(BitFlags<KeyUsageFlags>(KeyUsageFlags::kKeyCertSign, KeyUsageFlags::kCRLSign), writer));
     215          82 :     return CHIP_NO_ERROR;
     216             : }
     217             : 
     218          60 : CHIP_ERROR EncodeNOCSpecificExtensions(ASN1Writer & writer)
     219             : {
     220          60 :     ReturnErrorOnFailure(EncodeIsCAExtension(kNotCACert, writer));
     221          60 :     ReturnErrorOnFailure(EncodeKeyUsageExtension(KeyUsageFlags::kDigitalSignature, writer));
     222          60 :     ReturnErrorOnFailure(EncodeExtKeyUsageExtension({ kOID_KeyPurpose_ClientAuth, kOID_KeyPurpose_ServerAuth }, writer));
     223          60 :     return CHIP_NO_ERROR;
     224             : }
     225             : 
     226         142 : CHIP_ERROR EncodeFutureExtension(const Optional<FutureExtension> & futureExt, ASN1Writer & writer)
     227             : {
     228         142 :     CHIP_ERROR err = CHIP_NO_ERROR;
     229             : 
     230         142 :     VerifyOrReturnError(futureExt.HasValue(), CHIP_NO_ERROR);
     231             : 
     232           6 :     ASN1_START_SEQUENCE
     233             :     {
     234           6 :         ReturnErrorOnFailure(writer.PutObjectId(futureExt.Value().OID.data(), static_cast<uint16_t>(futureExt.Value().OID.size())));
     235             : 
     236           6 :         ASN1_START_OCTET_STRING_ENCAPSULATED
     237             :         {
     238           6 :             ReturnErrorOnFailure(writer.PutOctetString(futureExt.Value().Extension.data(),
     239             :                                                        static_cast<uint16_t>(futureExt.Value().Extension.size())));
     240             :         }
     241           6 :         ASN1_END_ENCAPSULATED;
     242             :     }
     243           6 :     ASN1_END_SEQUENCE;
     244             : 
     245           6 : exit:
     246           6 :     return err;
     247             : }
     248             : 
     249         142 : CHIP_ERROR EncodeExtensions(bool isCA, const Crypto::P256PublicKey & SKI, const Crypto::P256PublicKey & AKI,
     250             :                             const Optional<FutureExtension> & futureExt, ASN1Writer & writer)
     251             : {
     252         142 :     CHIP_ERROR err = CHIP_NO_ERROR;
     253             : 
     254         142 :     ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 3)
     255             :     {
     256         142 :         ASN1_START_SEQUENCE
     257             :         {
     258         142 :             if (isCA)
     259             :             {
     260          82 :                 ReturnErrorOnFailure(EncodeCASpecificExtensions(writer));
     261             :             }
     262             :             else
     263             :             {
     264          60 :                 ReturnErrorOnFailure(EncodeNOCSpecificExtensions(writer));
     265             :             }
     266             : 
     267         142 :             ReturnErrorOnFailure(EncodeSubjectKeyIdentifierExtension(SKI, writer));
     268             : 
     269         142 :             ReturnErrorOnFailure(EncodeAuthorityKeyIdentifierExtension(AKI, writer));
     270             : 
     271         142 :             ReturnErrorOnFailure(EncodeFutureExtension(futureExt, writer));
     272             :         }
     273         142 :         ASN1_END_SEQUENCE;
     274             :     }
     275         142 :     ASN1_END_CONSTRUCTED;
     276             : 
     277         142 : exit:
     278         142 :     return err;
     279             : }
     280             : 
     281         147 : CHIP_ERROR EncodeValidity(uint32_t validityStart, uint32_t validityEnd, ASN1Writer & writer)
     282             : {
     283         147 :     CHIP_ERROR err = CHIP_NO_ERROR;
     284             :     ASN1UniversalTime asn1Time;
     285             : 
     286         147 :     ASN1_START_SEQUENCE
     287             :     {
     288         147 :         ReturnErrorOnFailure(ChipEpochToASN1Time(validityStart, asn1Time));
     289         147 :         ASN1_ENCODE_TIME(asn1Time);
     290             : 
     291         147 :         ReturnErrorOnFailure(ChipEpochToASN1Time(validityEnd, asn1Time));
     292         147 :         ASN1_ENCODE_TIME(asn1Time);
     293             :     }
     294         147 :     ASN1_END_SEQUENCE;
     295             : 
     296         147 : exit:
     297         147 :     return err;
     298             : }
     299             : 
     300          71 : CHIP_ERROR EncodeChipECDSASignature(Crypto::P256ECDSASignature & signature, ASN1Writer & writer)
     301             : {
     302          71 :     CHIP_ERROR err = CHIP_NO_ERROR;
     303             : 
     304          71 :     ASN1_START_BIT_STRING_ENCAPSULATED
     305             :     {
     306             :         // Convert RAW signature to DER when generating X509 certs.
     307          71 :         P256ECDSASignatureSpan raw_sig(signature.Bytes());
     308          71 :         ReturnErrorOnFailure(ConvertECDSASignatureRawToDER(raw_sig, writer));
     309             :     }
     310          71 :     ASN1_END_ENCAPSULATED;
     311             : 
     312          71 : exit:
     313          71 :     return err;
     314             : }
     315             : 
     316         144 : CHIP_ERROR EncodeTBSCert(const X509CertRequestParams & requestParams, const Crypto::P256PublicKey & subjectPubkey,
     317             :                          const Crypto::P256PublicKey & issuerPubkey, ASN1Writer & writer)
     318             : {
     319         144 :     CHIP_ERROR err = CHIP_NO_ERROR;
     320             :     CertType certType;
     321             :     bool isCA;
     322             : 
     323         144 :     VerifyOrReturnError(requestParams.SerialNumber >= 0, CHIP_ERROR_INVALID_ARGUMENT);
     324         142 :     VerifyOrReturnError(requestParams.ValidityEnd == kNullCertTime || requestParams.ValidityEnd >= requestParams.ValidityStart,
     325             :                         CHIP_ERROR_INVALID_ARGUMENT);
     326             : 
     327         142 :     ReturnErrorOnFailure(requestParams.SubjectDN.GetCertType(certType));
     328         142 :     isCA = (certType == CertType::kICA || certType == CertType::kRoot);
     329             : 
     330         142 :     ASN1_START_SEQUENCE
     331             :     {
     332             :         // version [0] EXPLICIT Version DEFAULT v1
     333         142 :         ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     334             :         {
     335             :             // Version ::= INTEGER { v1(0), v2(1), v3(2) }
     336         142 :             ASN1_ENCODE_INTEGER(2);
     337             :         }
     338         142 :         ASN1_END_CONSTRUCTED;
     339             : 
     340         142 :         ReturnErrorOnFailure(writer.PutInteger(requestParams.SerialNumber));
     341             : 
     342         142 :         ASN1_START_SEQUENCE
     343             :         {
     344         142 :             ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
     345             :         }
     346         142 :         ASN1_END_SEQUENCE;
     347             : 
     348             :         // issuer Name
     349         142 :         ReturnErrorOnFailure(requestParams.IssuerDN.EncodeToASN1(writer));
     350             : 
     351             :         // validity Validity,
     352         142 :         ReturnErrorOnFailure(EncodeValidity(requestParams.ValidityStart, requestParams.ValidityEnd, writer));
     353             : 
     354             :         // subject Name
     355         142 :         ReturnErrorOnFailure(requestParams.SubjectDN.EncodeToASN1(writer));
     356             : 
     357         142 :         ReturnErrorOnFailure(EncodeSubjectPublicKeyInfo(subjectPubkey, writer));
     358             : 
     359             :         // certificate extensions
     360         142 :         ReturnErrorOnFailure(EncodeExtensions(isCA, subjectPubkey, issuerPubkey, requestParams.FutureExt, writer));
     361             :     }
     362         142 :     ASN1_END_SEQUENCE;
     363             : 
     364         142 : exit:
     365         142 :     return err;
     366             : }
     367             : 
     368             : } // namespace
     369             : 
     370           5 : CHIP_ERROR EncodeNetworkIdentityTBSCert(const P256PublicKey & pubkey, ASN1Writer & writer)
     371             : {
     372           5 :     CHIP_ERROR err = CHIP_NO_ERROR;
     373           5 :     ChipDN issuerAndSubject;
     374           5 :     InitNetworkIdentitySubject(issuerAndSubject);
     375             : 
     376           5 :     ASN1_START_SEQUENCE
     377             :     {
     378             :         // version [0] EXPLICIT Version DEFAULT v1
     379           5 :         ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
     380             :         {
     381           5 :             ASN1_ENCODE_INTEGER(2); // Version ::= INTEGER { v1(0), v2(1), v3(2) }
     382             :         }
     383           5 :         ASN1_END_CONSTRUCTED;
     384             : 
     385           5 :         ReturnErrorOnFailure(writer.PutInteger(kNetworkIdentitySerialNumber));
     386             : 
     387           5 :         ASN1_START_SEQUENCE
     388             :         {
     389           5 :             ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
     390             :         }
     391           5 :         ASN1_END_SEQUENCE;
     392             : 
     393             :         // issuer Name
     394           5 :         ReturnErrorOnFailure(issuerAndSubject.EncodeToASN1(writer));
     395             : 
     396             :         // validity Validity,
     397           5 :         ReturnErrorOnFailure(EncodeValidity(kNetworkIdentityNotBeforeTime, kNetworkIdentityNotAfterTime, writer));
     398             : 
     399             :         // subject Name
     400           5 :         ReturnErrorOnFailure(issuerAndSubject.EncodeToASN1(writer));
     401             : 
     402           5 :         ReturnErrorOnFailure(EncodeSubjectPublicKeyInfo(pubkey, writer));
     403             : 
     404             :         // certificate extensions
     405           5 :         ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 3)
     406             :         {
     407           5 :             ASN1_START_SEQUENCE
     408             :             {
     409           5 :                 EncodeIsCAExtension(kNotCACert, writer);
     410           5 :                 EncodeKeyUsageExtension(KeyUsageFlags::kDigitalSignature, writer);
     411           5 :                 EncodeExtKeyUsageExtension({ kOID_KeyPurpose_ClientAuth, kOID_KeyPurpose_ServerAuth }, writer);
     412             :             }
     413           5 :             ASN1_END_SEQUENCE;
     414             :         }
     415           5 :         ASN1_END_CONSTRUCTED;
     416             :     }
     417           5 :     ASN1_END_SEQUENCE;
     418             : 
     419           5 : exit:
     420           5 :     return err;
     421           5 : }
     422             : 
     423          73 : CHIP_ERROR NewChipX509Cert(const X509CertRequestParams & requestParams, const Crypto::P256PublicKey & subjectPubkey,
     424             :                            const Crypto::P256Keypair & issuerKeypair, MutableByteSpan & x509Cert)
     425             : {
     426          73 :     CHIP_ERROR err = CHIP_NO_ERROR;
     427             :     ASN1Writer writer;
     428          73 :     writer.Init(x509Cert);
     429             : 
     430          73 :     ReturnErrorOnFailure(EncodeTBSCert(requestParams, subjectPubkey, issuerKeypair.Pubkey(), writer));
     431             : 
     432          71 :     Crypto::P256ECDSASignature signature;
     433          71 :     ReturnErrorOnFailure(issuerKeypair.ECDSA_sign_msg(x509Cert.data(), writer.GetLengthWritten(), signature));
     434             : 
     435          71 :     writer.Init(x509Cert);
     436             : 
     437          71 :     ASN1_START_SEQUENCE
     438             :     {
     439          71 :         ReturnErrorOnFailure(EncodeTBSCert(requestParams, subjectPubkey, issuerKeypair.Pubkey(), writer));
     440             : 
     441          71 :         ASN1_START_SEQUENCE
     442             :         {
     443          71 :             ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
     444             :         }
     445          71 :         ASN1_END_SEQUENCE;
     446             : 
     447          71 :         ReturnErrorOnFailure(EncodeChipECDSASignature(signature, writer));
     448             :     }
     449          71 :     ASN1_END_SEQUENCE;
     450             : 
     451          71 :     x509Cert.reduce_size(writer.GetLengthWritten());
     452             : 
     453          71 : exit:
     454          71 :     return err;
     455          71 : }
     456             : 
     457          25 : DLL_EXPORT CHIP_ERROR NewRootX509Cert(const X509CertRequestParams & requestParams, const Crypto::P256Keypair & issuerKeypair,
     458             :                                       MutableByteSpan & x509Cert)
     459             : {
     460             :     CertType certType;
     461             : 
     462          25 :     ReturnErrorOnFailure(requestParams.SubjectDN.GetCertType(certType));
     463          25 :     VerifyOrReturnError(certType == CertType::kRoot, CHIP_ERROR_INVALID_ARGUMENT);
     464          24 :     VerifyOrReturnError(requestParams.SubjectDN.IsEqual(requestParams.IssuerDN), CHIP_ERROR_INVALID_ARGUMENT);
     465             : 
     466          23 :     return NewChipX509Cert(requestParams, issuerKeypair.Pubkey(), issuerKeypair, x509Cert);
     467             : }
     468             : 
     469          21 : DLL_EXPORT CHIP_ERROR NewICAX509Cert(const X509CertRequestParams & requestParams, const Crypto::P256PublicKey & subjectPubkey,
     470             :                                      const Crypto::P256Keypair & issuerKeypair, MutableByteSpan & x509Cert)
     471             : {
     472             :     CertType certType;
     473             : 
     474          21 :     ReturnErrorOnFailure(requestParams.SubjectDN.GetCertType(certType));
     475          21 :     VerifyOrReturnError(certType == CertType::kICA, CHIP_ERROR_INVALID_ARGUMENT);
     476             : 
     477          20 :     ReturnErrorOnFailure(requestParams.IssuerDN.GetCertType(certType));
     478          20 :     VerifyOrReturnError(certType == CertType::kRoot, CHIP_ERROR_INVALID_ARGUMENT);
     479             : 
     480          20 :     return NewChipX509Cert(requestParams, subjectPubkey, issuerKeypair, x509Cert);
     481             : }
     482             : 
     483          33 : DLL_EXPORT CHIP_ERROR NewNodeOperationalX509Cert(const X509CertRequestParams & requestParams,
     484             :                                                  const Crypto::P256PublicKey & subjectPubkey,
     485             :                                                  const Crypto::P256Keypair & issuerKeypair, MutableByteSpan & x509Cert)
     486             : {
     487             :     CertType certType;
     488             : 
     489          33 :     ReturnErrorOnFailure(requestParams.SubjectDN.GetCertType(certType));
     490          32 :     VerifyOrReturnError(certType == CertType::kNode, CHIP_ERROR_INVALID_ARGUMENT);
     491             : 
     492          31 :     ReturnErrorOnFailure(requestParams.IssuerDN.GetCertType(certType));
     493          31 :     VerifyOrReturnError(certType == CertType::kICA || certType == CertType::kRoot, CHIP_ERROR_INVALID_ARGUMENT);
     494             : 
     495          30 :     return NewChipX509Cert(requestParams, subjectPubkey, issuerKeypair, x509Cert);
     496             : }
     497             : 
     498             : } // namespace Credentials
     499             : } // namespace chip

Generated by: LCOV version 1.14