3 * Copyright (c) 2020-2021 Project CHIP Authors
4 * Copyright (c) 2019 Google LLC.
5 * Copyright (c) 2013-2017 Nest Labs, Inc.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
23 * This file implements objects for modeling and working with
28 #ifndef __STDC_LIMIT_MACROS
29 #define __STDC_LIMIT_MACROS
34 #include <asn1/ASN1.h>
35 #include <asn1/ASN1Macros.h>
36 #include <core/CHIPCore.h>
37 #include <core/CHIPSafeCasts.h>
38 #include <core/CHIPTLV.h>
39 #include <credentials/CHIPCert.h>
40 #include <protocols/Protocols.h>
41 #include <support/CHIPMem.h>
42 #include <support/CodeUtils.h>
43 #include <support/TimeUtils.h>
46 namespace Credentials {
48 using namespace chip::ASN1;
49 using namespace chip::TLV;
50 using namespace chip::Protocols;
51 using namespace chip::Crypto;
53 extern CHIP_ERROR DecodeConvertTBSCert(TLVReader & reader, ASN1Writer & writer, ChipCertificateData & certData);
54 extern CHIP_ERROR DecodeECDSASignature(TLVReader & reader, ChipCertificateData & certData);
56 ChipCertificateSet::ChipCertificateSet()
63 mMemoryAllocInternal = false;
66 ChipCertificateSet::~ChipCertificateSet()
71 CHIP_ERROR ChipCertificateSet::Init(uint8_t maxCertsArraySize, uint16_t decodeBufSize)
73 CHIP_ERROR err = CHIP_NO_ERROR;
75 VerifyOrExit(maxCertsArraySize > 0, err = CHIP_ERROR_INVALID_ARGUMENT);
76 mCerts = reinterpret_cast<ChipCertificateData *>(chip::Platform::MemoryAlloc(sizeof(ChipCertificateData) * maxCertsArraySize));
77 VerifyOrExit(mCerts != nullptr, err = CHIP_ERROR_NO_MEMORY);
79 VerifyOrExit(decodeBufSize > 0, err = CHIP_ERROR_INVALID_ARGUMENT);
80 mDecodeBuf = reinterpret_cast<uint8_t *>(chip::Platform::MemoryAlloc(decodeBufSize));
81 VerifyOrExit(mDecodeBuf != nullptr, err = CHIP_ERROR_NO_MEMORY);
84 mMaxCerts = maxCertsArraySize;
85 mDecodeBufSize = decodeBufSize;
86 mMemoryAllocInternal = true;
89 if (err != CHIP_NO_ERROR)
97 CHIP_ERROR ChipCertificateSet::Init(ChipCertificateData * certsArray, uint8_t certsArraySize, uint8_t * decodeBuf,
98 uint16_t decodeBufSize)
100 CHIP_ERROR err = CHIP_NO_ERROR;
102 VerifyOrExit(certsArray != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
103 VerifyOrExit(certsArraySize > 0, err = CHIP_ERROR_INVALID_ARGUMENT);
104 VerifyOrExit(decodeBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
105 VerifyOrExit(decodeBufSize > 0, err = CHIP_ERROR_INVALID_ARGUMENT);
109 mMaxCerts = certsArraySize;
110 mDecodeBuf = decodeBuf;
111 mDecodeBufSize = decodeBufSize;
112 mMemoryAllocInternal = false;
118 void ChipCertificateSet::Release()
120 if (mMemoryAllocInternal)
122 if (mCerts != nullptr)
125 chip::Platform::MemoryFree(mCerts);
128 if (mDecodeBuf != nullptr)
130 chip::Platform::MemoryFree(mDecodeBuf);
131 mDecodeBuf = nullptr;
136 void ChipCertificateSet::Clear()
138 for (int i = 0; i < mCertCount; i++)
140 mCerts[i].~ChipCertificateData();
146 CHIP_ERROR ChipCertificateSet::LoadCert(const uint8_t * chipCert, uint32_t chipCertLen, BitFlags<CertDecodeFlags> decodeFlags)
151 reader.Init(chipCert, chipCertLen);
152 reader.ImplicitProfileId = kProtocol_OpCredentials;
154 err = reader.Next(kTLVType_Structure, ProfileTag(kProtocol_OpCredentials, kTag_ChipCertificate));
157 err = LoadCert(reader, decodeFlags);
163 CHIP_ERROR ChipCertificateSet::LoadCert(TLVReader & reader, BitFlags<CertDecodeFlags> decodeFlags)
166 ASN1Writer writer; // ASN1Writer is used to encode TBS portion of the certificate for the purpose of signature
167 // validation, which should be performed on the TBS data encoded in ASN.1 DER form.
168 ChipCertificateData * cert = nullptr;
170 // Must be positioned on the structure element representing the certificate.
171 VerifyOrExit(reader.GetType() == kTLVType_Structure, err = CHIP_ERROR_INVALID_ARGUMENT);
173 // Verify we have room for the new certificate.
174 VerifyOrExit(mCertCount < mMaxCerts, err = CHIP_ERROR_NO_MEMORY);
176 cert = new (&mCerts[mCertCount]) ChipCertificateData();
179 TLVType containerType;
181 // Enter the certificate structure...
182 err = reader.EnterContainer(containerType);
185 // Initialize an ASN1Writer and convert the TBS (to-be-signed) portion of the certificate to ASN.1 DER
186 // encoding. At the same time, parse various components within the certificate and set the corresponding
187 // fields in the CertificateData object.
188 writer.Init(mDecodeBuf, mDecodeBufSize);
189 err = DecodeConvertTBSCert(reader, writer, *cert);
192 // Verify the cert has both the Subject Key Id and Authority Key Id extensions present.
193 // Only certs with both these extensions are supported for the purposes of certificate validation.
194 VerifyOrExit(cert->mCertFlags.HasAll(CertFlags::kExtPresent_SubjectKeyId, CertFlags::kExtPresent_AuthKeyId),
195 err = CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
197 // Verify the cert was signed with ECDSA-SHA256. This is the only signature algorithm currently supported.
198 VerifyOrExit(cert->mSigAlgoOID == kOID_SigAlgo_ECDSAWithSHA256, err = CHIP_ERROR_UNSUPPORTED_SIGNATURE_TYPE);
200 // If requested, generate the hash of the TBS portion of the certificate...
201 if (decodeFlags.Has(CertDecodeFlags::kGenerateTBSHash))
203 // Finish writing the ASN.1 DER encoding of the TBS certificate.
204 err = writer.Finalize();
207 // Generate a SHA hash of the encoded TBS certificate.
208 chip::Crypto::Hash_SHA256(mDecodeBuf, writer.GetLengthWritten(), cert->mTBSHash);
210 cert->mCertFlags.Set(CertFlags::kTBSHashPresent);
213 // Decode the certificate's signature...
214 err = DecodeECDSASignature(reader, *cert);
217 // Verify no more elements in the certificate.
218 err = reader.VerifyEndOfContainer();
221 err = reader.ExitContainer(containerType);
225 // If requested by the caller, mark the certificate as trusted.
226 if (decodeFlags.Has(CertDecodeFlags::kIsTrustAnchor))
228 cert->mCertFlags.Set(CertFlags::kIsTrustAnchor);
231 // Assign a default type for the certificate based on its subject and attributes.
232 err = DetermineCertType(*cert);
238 if (err != CHIP_NO_ERROR)
242 cert->~ChipCertificateData();
249 CHIP_ERROR ChipCertificateSet::LoadCerts(const uint8_t * chipCerts, uint32_t chipCertsLen, BitFlags<CertDecodeFlags> decodeFlags)
256 reader.Init(chipCerts, chipCertsLen);
257 reader.ImplicitProfileId = kProtocol_OpCredentials;
262 type = reader.GetType();
263 tag = reader.GetTag();
265 VerifyOrExit((type == kTLVType_Structure && tag == ProfileTag(kProtocol_OpCredentials, kTag_ChipCertificate)) ||
266 (type == kTLVType_Array && tag == ProfileTag(kProtocol_OpCredentials, kTag_ChipCertificateArray)),
267 err = CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
269 err = LoadCerts(reader, decodeFlags);
275 CHIP_ERROR ChipCertificateSet::LoadCerts(TLVReader & reader, BitFlags<CertDecodeFlags> decodeFlags)
278 uint8_t initialCertCount = mCertCount;
280 // If positioned on a structure, we assume that structure is a single certificate.
281 if (reader.GetType() == kTLVType_Structure)
283 err = LoadCert(reader, decodeFlags);
287 // Other we expect to be positioned on an Array that contains a sequence of
288 // zero or more certificates...
291 TLVType containerType;
293 err = reader.EnterContainer(containerType);
296 while ((err = reader.Next()) == CHIP_NO_ERROR)
298 VerifyOrExit(reader.GetTag() == AnonymousTag, err = CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
300 err = LoadCert(reader, decodeFlags);
303 if (err != CHIP_END_OF_TLV)
308 err = reader.ExitContainer(containerType);
313 if (err != CHIP_NO_ERROR)
315 for (uint8_t i = initialCertCount; i < mCertCount; i++)
317 mCerts[i].~ChipCertificateData();
319 mCertCount = initialCertCount;
325 CHIP_ERROR ChipCertificateSet::AddTrustedKey(uint64_t caId, OID curveOID, const uint8_t * pubKey, uint8_t pubKeyLen,
326 const uint8_t * pubKeyId, uint8_t pubKeyIdLen)
328 CHIP_ERROR err = CHIP_NO_ERROR;
329 ChipCertificateData * cert;
331 // Verify we have room for the new certificate.
332 VerifyOrExit(mCertCount < mMaxCerts, err = CHIP_ERROR_NO_MEMORY);
334 cert = new (&mCerts[mCertCount]) ChipCertificateData();
336 cert->mSubjectDN.mAttrOID = kOID_AttributeType_ChipCAId;
337 cert->mSubjectDN.mAttrValue.mChipId = caId;
338 cert->mIssuerDN = cert->mSubjectDN;
339 cert->mPubKeyCurveOID = curveOID;
340 cert->mPublicKey = pubKey;
341 cert->mPublicKeyLen = pubKeyLen;
342 cert->mSubjectKeyId.mId = pubKeyId;
343 cert->mSubjectKeyId.mLen = pubKeyIdLen;
344 cert->mAuthKeyId = cert->mSubjectKeyId;
345 cert->mCertType = kCertType_CA;
347 cert->mCertFlags.Set(CertFlags::kExtPresent_BasicConstraints);
348 cert->mCertFlags.Set(CertFlags::kExtPresent_KeyUsage);
349 cert->mCertFlags.Set(CertFlags::kExtPresent_SubjectKeyId);
350 cert->mCertFlags.Set(CertFlags::kExtPresent_AuthKeyId);
351 cert->mCertFlags.Set(CertFlags::kIsCA);
352 cert->mCertFlags.Set(CertFlags::kIsTrustAnchor);
354 cert->mKeyUsageFlags.Set(KeyUsageFlags::kKeyCertSign);
362 const ChipCertificateData * ChipCertificateSet::FindCert(const CertificateKeyId & subjectKeyId) const
364 for (uint8_t i = 0; i < mCertCount; i++)
366 ChipCertificateData & cert = mCerts[i];
367 if (cert.mSubjectKeyId.IsEqual(subjectKeyId))
376 bool ChipCertificateSet::IsCertInTheSet(const ChipCertificateData * cert) const
378 for (uint8_t i = 0; i < mCertCount; i++)
380 if (cert == &mCerts[i])
389 CHIP_ERROR ChipCertificateSet::ValidateCert(const ChipCertificateData * cert, ValidationContext & context)
393 VerifyOrExit(IsCertInTheSet(cert), err = CHIP_ERROR_INVALID_ARGUMENT);
395 context.mTrustAnchor = nullptr;
397 err = ValidateCert(cert, context, context.mValidateFlags, 0);
403 CHIP_ERROR ChipCertificateSet::FindValidCert(const ChipDN & subjectDN, const CertificateKeyId & subjectKeyId,
404 ValidationContext & context, ChipCertificateData *& cert)
408 context.mTrustAnchor = nullptr;
410 err = FindValidCert(subjectDN, subjectKeyId, context, context.mValidateFlags, 0, cert);
417 CHIP_ERROR ChipCertificateSet::VerifySignature(const ChipCertificateData * cert, const ChipCertificateData * caCert)
419 static constexpr size_t kMaxBytesForDeferredLenList = sizeof(uint8_t *) + // size of a single pointer in the deferred list
420 4 + // extra memory allocated for the deferred length field (kLengthFieldReserveSize - 1)
421 3; // the deferred length list is alligned to 32bit boundary
424 P256PublicKey caPublicKey;
425 P256ECDSASignature signature;
426 uint8_t tmpBuf[signature.Capacity() + kMaxBytesForDeferredLenList];
429 writer.Init(tmpBuf, static_cast<uint32_t>(sizeof(tmpBuf)));
431 // Ecdsa-Sig-Value ::= SEQUENCE
435 err = writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false, cert->mSignature.R, cert->mSignature.RLen);
439 err = writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false, cert->mSignature.S, cert->mSignature.SLen);
444 err = writer.Finalize();
447 VerifyOrExit(writer.GetLengthWritten() <= signature.Capacity(), err = CHIP_ERROR_BUFFER_TOO_SMALL);
449 memcpy(signature, tmpBuf, writer.GetLengthWritten());
450 err = signature.SetLength(writer.GetLengthWritten());
453 memcpy(caPublicKey, caCert->mPublicKey, caCert->mPublicKeyLen);
455 err = caPublicKey.ECDSA_validate_hash_signature(cert->mTBSHash, chip::Crypto::kSHA256_Hash_Length, signature);
462 CHIP_ERROR ChipCertificateSet::ValidateCert(const ChipCertificateData * cert, ValidationContext & context,
463 BitFlags<CertValidateFlags> validateFlags, uint8_t depth)
465 CHIP_ERROR err = CHIP_NO_ERROR;
466 ChipCertificateData * caCert = nullptr;
468 // If the depth is greater than 0 then the certificate is required to be a CA certificate...
471 // Verify the isCA flag is present.
472 VerifyOrExit(cert->mCertFlags.Has(CertFlags::kIsCA), err = CHIP_ERROR_CERT_USAGE_NOT_ALLOWED);
474 // Verify the key usage extension is present and contains the 'keyCertSign' flag.
475 VerifyOrExit(cert->mCertFlags.Has(CertFlags::kExtPresent_KeyUsage) && cert->mKeyUsageFlags.Has(KeyUsageFlags::kKeyCertSign),
476 err = CHIP_ERROR_CERT_USAGE_NOT_ALLOWED);
478 // Verify that the certificate type is set to "CA".
479 VerifyOrExit(cert->mCertType == kCertType_CA, err = CHIP_ERROR_WRONG_CERT_TYPE);
481 // If a path length constraint was included, verify the cert depth vs. the specified constraint.
483 // From the RFC, the path length constraint "gives the maximum number of non-self-issued
484 // intermediate certificates that may follow this certificate in a valid certification path.
485 // (Note: The last certificate in the certification path is not an intermediate certificate,
486 // and is not included in this limit...)"
488 if (cert->mCertFlags.Has(CertFlags::kPathLenConstraintPresent))
490 VerifyOrExit((depth - 1) <= cert->mPathLenConstraint, err = CHIP_ERROR_CERT_PATH_LEN_CONSTRAINT_EXCEEDED);
494 // Otherwise verify the desired certificate usages/purposes/type given in the validation context...
497 // If a set of desired key usages has been specified, verify that the key usage extension exists
498 // in the certificate and that the corresponding usages are supported.
499 if (context.mRequiredKeyUsages.HasAny())
501 VerifyOrExit(cert->mCertFlags.Has(CertFlags::kExtPresent_KeyUsage) &&
502 cert->mKeyUsageFlags.HasAll(context.mRequiredKeyUsages),
503 err = CHIP_ERROR_CERT_USAGE_NOT_ALLOWED);
506 // If a set of desired key purposes has been specified, verify that the extended key usage extension
507 // exists in the certificate and that the corresponding purposes are supported.
508 if (context.mRequiredKeyPurposes.HasAny())
510 VerifyOrExit(cert->mCertFlags.Has(CertFlags::kExtPresent_ExtendedKeyUsage) &&
511 cert->mKeyPurposeFlags.HasAll(context.mRequiredKeyPurposes),
512 err = CHIP_ERROR_CERT_USAGE_NOT_ALLOWED);
515 // If a required certificate type has been specified, verify it against the current certificate's type.
516 if (context.mRequiredCertType != kCertType_NotSpecified)
518 VerifyOrExit(cert->mCertType == context.mRequiredCertType, err = CHIP_ERROR_WRONG_CERT_TYPE);
522 // Verify the validity time of the certificate, if requested.
523 if (cert->mNotBeforeTime != 0 && !validateFlags.Has(CertValidateFlags::kIgnoreNotBefore))
525 VerifyOrExit(context.mEffectiveTime >= cert->mNotBeforeTime, err = CHIP_ERROR_CERT_NOT_VALID_YET);
527 if (cert->mNotAfterTime != 0 && !validateFlags.Has(CertValidateFlags::kIgnoreNotAfter))
529 VerifyOrExit(context.mEffectiveTime <= cert->mNotAfterTime, err = CHIP_ERROR_CERT_EXPIRED);
532 // If the certificate itself is trusted, then it is implicitly valid. Record this certificate as the trust
533 // anchor and return success.
534 if (cert->mCertFlags.Has(CertFlags::kIsTrustAnchor))
536 context.mTrustAnchor = cert;
537 ExitNow(err = CHIP_NO_ERROR);
540 // Otherwise we must validate the certificate by looking for a chain of valid certificates up to a trusted
541 // certificate known as the 'trust anchor'.
543 // Fail validation if the certificate is self-signed. Since we don't trust this certificate (see the check above) and
544 // it has no path we can follow to a trust anchor, it can't be considered valid.
545 if (cert->mIssuerDN.IsEqual(cert->mSubjectDN) && cert->mAuthKeyId.IsEqual(cert->mSubjectKeyId))
547 ExitNow(err = CHIP_ERROR_CERT_NOT_TRUSTED);
550 // Verify that the certificate depth is less than the total number of certificates. It is technically possible to create
551 // a circular chain of certificates. Limiting the maximum depth of the certificate path prevents infinite
552 // recursion in such a case.
553 VerifyOrExit(depth < mCertCount, err = CHIP_ERROR_CERT_PATH_TOO_LONG);
555 // Verify that a hash of the 'to-be-signed' portion of the certificate has been computed. We will need this to
556 // verify the cert's signature below.
557 VerifyOrExit(cert->mCertFlags.Has(CertFlags::kTBSHashPresent), err = CHIP_ERROR_INVALID_ARGUMENT);
559 // Search for a valid CA certificate that matches the Issuer DN and Authority Key Id of the current certificate.
560 // Fail if no acceptable certificate is found.
561 err = FindValidCert(cert->mIssuerDN, cert->mAuthKeyId, context, validateFlags, static_cast<uint8_t>(depth + 1), caCert);
562 if (err != CHIP_NO_ERROR)
564 ExitNow(err = CHIP_ERROR_CA_CERT_NOT_FOUND);
567 // Verify signature of the current certificate against public key of the CA certificate. If signature verification
568 // succeeds, the current certificate is valid.
569 err = VerifySignature(cert, caCert);
576 CHIP_ERROR ChipCertificateSet::FindValidCert(const ChipDN & subjectDN, const CertificateKeyId & subjectKeyId,
577 ValidationContext & context, BitFlags<CertValidateFlags> validateFlags, uint8_t depth,
578 ChipCertificateData *& cert)
582 // Default error if we don't find any matching cert.
583 err = (depth > 0) ? CHIP_ERROR_CA_CERT_NOT_FOUND : CHIP_ERROR_CERT_NOT_FOUND;
585 // Fail immediately if neither of the input criteria are specified.
586 if (subjectDN.IsEmpty() && subjectKeyId.IsEmpty())
591 // For each cert in the set...
592 for (uint8_t i = 0; i < mCertCount; i++)
594 ChipCertificateData * candidateCert = &mCerts[i];
596 // Skip the certificate if its subject DN and key id do not match the input criteria.
597 if (!subjectDN.IsEmpty() && !candidateCert->mSubjectDN.IsEqual(subjectDN))
601 if (!subjectKeyId.IsEmpty() && !candidateCert->mSubjectKeyId.IsEqual(subjectKeyId))
606 // Attempt to validate the cert. If the cert is valid, return it to the caller. Otherwise,
607 // save the returned error and continue searching. If there are no other matching certs this
608 // will be the error returned to the caller.
609 err = ValidateCert(candidateCert, context, validateFlags, depth);
610 if (err == CHIP_NO_ERROR)
612 cert = candidateCert;
623 ChipCertificateData::ChipCertificateData()
628 ChipCertificateData::~ChipCertificateData()
633 void ChipCertificateData::Clear()
637 mSubjectKeyId.Clear();
641 mPublicKey = nullptr;
646 mCertFlags.ClearAll();
647 mKeyUsageFlags.ClearAll();
648 mKeyPurposeFlags.ClearAll();
649 mPathLenConstraint = 0;
650 mCertType = kCertType_NotSpecified;
651 mSignature.R = nullptr;
653 mSignature.S = nullptr;
655 memset(mTBSHash, 0, sizeof(mTBSHash));
658 void ValidationContext::Reset()
661 mTrustAnchor = nullptr;
662 mSigningCert = nullptr;
663 mRequiredKeyUsages.ClearAll();
664 mRequiredKeyPurposes.ClearAll();
665 mValidateFlags.ClearAll();
666 mRequiredCertType = kCertType_NotSpecified;
669 CHIP_ERROR DetermineCertType(ChipCertificateData & cert)
671 CHIP_ERROR err = CHIP_NO_ERROR;
673 // If the certificate subject contains a ChipCAId attribute...
674 if (cert.mSubjectDN.mAttrOID == kOID_AttributeType_ChipCAId)
676 // Verify the BasicConstraints isCA flag is true.
677 VerifyOrExit(cert.mCertFlags.Has(CertFlags::kIsCA), err = CHIP_ERROR_CERT_USAGE_NOT_ALLOWED);
679 // Verify the key usage extension is present and contains the 'keyCertSign' flag.
680 VerifyOrExit(cert.mCertFlags.Has(CertFlags::kExtPresent_KeyUsage) && cert.mKeyUsageFlags.Has(KeyUsageFlags::kKeyCertSign),
681 err = CHIP_ERROR_CERT_USAGE_NOT_ALLOWED);
683 // Set the certificate type to CA.
684 cert.mCertType = kCertType_CA;
687 // If the certificate subject contains a ChipNodeId attribute set the certificate type to Node.
688 else if (cert.mSubjectDN.mAttrOID == kOID_AttributeType_ChipNodeId)
690 cert.mCertType = kCertType_Node;
693 // If the certificate subject contains a ChipSoftwarePublisherId attribute set the certificate type to FirmwareSigning.
694 else if (cert.mSubjectDN.mAttrOID == kOID_AttributeType_ChipSoftwarePublisherId)
696 cert.mCertType = kCertType_FirmwareSigning;
701 err = CHIP_ERROR_WRONG_CERT_TYPE;
708 bool ChipDN::IsEqual(const ChipDN & other) const
710 if (mAttrOID == kOID_Unknown || mAttrOID == kOID_NotSpecified || mAttrOID != other.mAttrOID)
715 if (IsChipIdX509Attr(mAttrOID))
717 return mAttrValue.mChipId == other.mAttrValue.mChipId;
721 return (mAttrValue.mString.mLen == other.mAttrValue.mString.mLen &&
722 memcmp(mAttrValue.mString.mValue, other.mAttrValue.mString.mValue, mAttrValue.mString.mLen) == 0);
726 bool CertificateKeyId::IsEqual(const CertificateKeyId & other) const
728 return mId != nullptr && other.mId != nullptr && mLen == other.mLen && memcmp(mId, other.mId, mLen) == 0;
731 DLL_EXPORT CHIP_ERROR ASN1ToChipEpochTime(const chip::ASN1::ASN1UniversalTime & asn1Time, uint32_t & epochTime)
733 CHIP_ERROR err = CHIP_NO_ERROR;
735 // X.509/RFC5280 defines the special time 99991231235959Z to mean 'no well-defined expiration date'.
736 // In CHIP certificate it is represented as a CHIP Epoch UTC time value of 0 sec (2020-01-01 00:00:00 UTC).
737 if ((asn1Time.Year == kX509NoWellDefinedExpirationDateYear) && (asn1Time.Month == kMonthsPerYear) &&
738 (asn1Time.Day == kMaxDaysPerMonth) && (asn1Time.Hour == kHoursPerDay - 1) && (asn1Time.Minute == kMinutesPerHour - 1) &&
739 (asn1Time.Second == kSecondsPerMinute - 1))
741 epochTime = kNullCertTime;
745 if (!CalendarToChipEpochTime(asn1Time.Year, asn1Time.Month, asn1Time.Day, asn1Time.Hour, asn1Time.Minute, asn1Time.Second,
748 ExitNow(err = ASN1_ERROR_UNSUPPORTED_ENCODING);
756 DLL_EXPORT CHIP_ERROR ChipEpochToASN1Time(uint32_t epochTime, chip::ASN1::ASN1UniversalTime & asn1Time)
758 // X.509/RFC5280 defines the special time 99991231235959Z to mean 'no well-defined expiration date'.
759 // In CHIP certificate it is represented as a CHIP Epoch time value of 0 secs (2020-01-01 00:00:00 UTC).
760 if (epochTime == kNullCertTime)
762 asn1Time.Year = kX509NoWellDefinedExpirationDateYear;
763 asn1Time.Month = kMonthsPerYear;
764 asn1Time.Day = kMaxDaysPerMonth;
765 asn1Time.Hour = kHoursPerDay - 1;
766 asn1Time.Minute = kMinutesPerHour - 1;
767 asn1Time.Second = kSecondsPerMinute - 1;
771 ChipEpochToCalendarTime(epochTime, asn1Time.Year, asn1Time.Month, asn1Time.Day, asn1Time.Hour, asn1Time.Minute,
775 return CHIP_NO_ERROR;
778 } // namespace Credentials