Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
Evgeny Margolis | 20c1f60 | 2022-01-26 06:09:18 -0800 | [diff] [blame] | 3 | * Copyright (c) 2020-2022 Project CHIP Authors |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 4 | * Copyright (c) 2019 Google LLC. |
| 5 | * Copyright (c) 2013-2017 Nest Labs, Inc. |
| 6 | * All rights reserved. |
| 7 | * |
| 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 |
| 11 | * |
| 12 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 13 | * |
| 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. |
| 19 | */ |
| 20 | |
| 21 | /** |
| 22 | * @file |
| 23 | * This file defines data types and objects for modeling and |
| 24 | * working with CHIP certificates. |
| 25 | * |
| 26 | */ |
| 27 | |
| 28 | #pragma once |
| 29 | |
Zang MingJie | 53dd583 | 2021-09-03 03:05:16 +0800 | [diff] [blame] | 30 | #include <cstdint> |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 31 | #include <string.h> |
| 32 | |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 33 | #include <crypto/CHIPCryptoPAL.h> |
Zang MingJie | 53dd583 | 2021-09-03 03:05:16 +0800 | [diff] [blame] | 34 | #include <lib/asn1/ASN1.h> |
Evgeny Margolis | ed367ec | 2021-12-13 12:31:04 -0800 | [diff] [blame] | 35 | #include <lib/core/CASEAuthTag.h> |
Zang MingJie | 53dd583 | 2021-09-03 03:05:16 +0800 | [diff] [blame] | 36 | #include <lib/core/CHIPConfig.h> |
Evgeny Margolis | ea87cc6 | 2021-11-29 22:08:00 -0800 | [diff] [blame] | 37 | #include <lib/core/DataModelTypes.h> |
Boris Zbarsky | 8af9981 | 2021-07-15 01:58:05 -0400 | [diff] [blame] | 38 | #include <lib/core/PeerId.h> |
Martin Turon | 82bfcd5 | 2023-01-09 13:30:38 -0800 | [diff] [blame] | 39 | #include <lib/core/TLV.h> |
Zang MingJie | 53dd583 | 2021-09-03 03:05:16 +0800 | [diff] [blame] | 40 | #include <lib/support/BitFlags.h> |
| 41 | #include <lib/support/DLLUtil.h> |
| 42 | #include <lib/support/Span.h> |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 43 | |
| 44 | namespace chip { |
| 45 | namespace Credentials { |
| 46 | |
Tennessee Carmel-Veilleux | ab5734c | 2021-11-27 12:08:31 -0500 | [diff] [blame] | 47 | static constexpr uint32_t kKeyIdentifierLength = static_cast<uint32_t>(Crypto::kSubjectKeyIdentifierLength); |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 48 | static constexpr uint32_t kChip32bitAttrUTF8Length = 8; |
| 49 | static constexpr uint32_t kChip64bitAttrUTF8Length = 16; |
Evgeny Margolis | fbc9596 | 2021-02-17 10:23:44 -0800 | [diff] [blame] | 50 | static constexpr uint16_t kX509NoWellDefinedExpirationDateYear = 9999; |
Evgeny Margolis | ac22f1b | 2021-02-10 11:30:02 -0800 | [diff] [blame] | 51 | |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 52 | // As per specifications (6.3.5. Node Operational Credentials Certificates) |
Pankaj Garg | da45346 | 2021-06-22 19:53:34 -0700 | [diff] [blame] | 53 | static constexpr uint32_t kMaxCHIPCertLength = 400; |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 54 | static constexpr uint32_t kMaxDERCertLength = 600; |
Pankaj Garg | da45346 | 2021-06-22 19:53:34 -0700 | [diff] [blame] | 55 | |
Evgeny Margolis | 2f03d3a | 2021-07-03 07:08:23 -0700 | [diff] [blame] | 56 | // The decode buffer is used to reconstruct TBS section of X.509 certificate, which doesn't include signature. |
Tennessee Carmel-Veilleux | 51a49a9 | 2021-07-14 16:05:06 -0400 | [diff] [blame] | 57 | static constexpr uint32_t kMaxCHIPCertDecodeBufLength = kMaxDERCertLength - Crypto::kMax_ECDSA_Signature_Length_Der; |
Evgeny Margolis | 2f03d3a | 2021-07-03 07:08:23 -0700 | [diff] [blame] | 58 | |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 59 | /** Data Element Tags for the CHIP Certificate |
| 60 | */ |
| 61 | enum |
| 62 | { |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 63 | // ---- Context-specific Tags for ChipCertificate Structure ---- |
| 64 | kTag_SerialNumber = 1, /**< [ byte string ] Certificate serial number, in BER integer encoding. */ |
| 65 | kTag_SignatureAlgorithm = 2, /**< [ unsigned int ] Enumerated value identifying the certificate signature algorithm. */ |
| 66 | kTag_Issuer = 3, /**< [ list ] The issuer distinguished name of the certificate. */ |
| 67 | kTag_NotBefore = 4, /**< [ unsigned int ] Certificate validity period start (certificate date format). */ |
| 68 | kTag_NotAfter = 5, /**< [ unsigned int ] Certificate validity period end (certificate date format). */ |
| 69 | kTag_Subject = 6, /**< [ list ] The subject distinguished name of the certificate. */ |
| 70 | kTag_PublicKeyAlgorithm = 7, /**< [ unsigned int ] Identifies the algorithm with which the public key can be used. */ |
| 71 | kTag_EllipticCurveIdentifier = 8, /**< [ unsigned int ] For EC certs, identifies the elliptic curve used. */ |
| 72 | kTag_EllipticCurvePublicKey = 9, /**< [ byte string ] The elliptic curve public key, in X9.62 encoded format. */ |
Evgeny Margolis | e09e11b | 2021-04-19 10:57:13 -0700 | [diff] [blame] | 73 | kTag_Extensions = 10, /**< [ list ] Certificate extensions. */ |
Evgeny Margolis | 85eb604 | 2021-06-08 10:39:09 -0700 | [diff] [blame] | 74 | kTag_ECDSASignature = 11, /**< [ byte string ] The ECDSA signature for the certificate. */ |
Evgeny Margolis | e09e11b | 2021-04-19 10:57:13 -0700 | [diff] [blame] | 75 | |
| 76 | // ---- Context-specific Tags for certificate extensions ---- |
| 77 | kTag_BasicConstraints = 1, /**< [ structure ] Identifies whether the subject of the certificate is a CA. */ |
| 78 | kTag_KeyUsage = 2, /**< [ unsigned int ] Bits identifying key usage, per RFC5280. */ |
| 79 | kTag_ExtendedKeyUsage = 3, /**< [ array ] Enumerated values giving the purposes for which the public key can be used. */ |
| 80 | kTag_SubjectKeyIdentifier = 4, /**< [ byte string ] Identifier of the certificate's public key. */ |
| 81 | kTag_AuthorityKeyIdentifier = 5, /**< [ byte string ] Identifier of the public key used to sign the certificate. */ |
Evgeny Margolis | bf61e87 | 2021-06-24 16:00:01 -0700 | [diff] [blame] | 82 | kTag_FutureExtension = 6, /**< [ byte string ] Arbitrary extension. DER encoded SEQUENCE as in X.509 form. */ |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 83 | |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 84 | // ---- Context-specific Tags for BasicConstraints Structure ---- |
Evgeny Margolis | ac22f1b | 2021-02-10 11:30:02 -0800 | [diff] [blame] | 85 | kTag_BasicConstraints_IsCA = 1, /**< [ boolean ] True if the certificate can be used to verify certificate |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 86 | signatures. */ |
Evgeny Margolis | ac22f1b | 2021-02-10 11:30:02 -0800 | [diff] [blame] | 87 | kTag_BasicConstraints_PathLenConstraint = 2, /**< [ unsigned int ] Maximum number of subordinate intermediate certificates. */ |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 88 | }; |
| 89 | |
| 90 | /** Identifies the purpose or application of certificate |
| 91 | * |
| 92 | * A certificate type is a label that describes a certificate's purpose or application. |
| 93 | * Certificate types are not carried as attributes of the corresponding certificates, but |
| 94 | * rather are derived from the certificate's structure and/or the context in which it is used. |
| 95 | * The certificate type enumeration includes a set of pre-defined values describing commonly |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 96 | * used certificate applications. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 97 | * |
| 98 | * Certificate types are primarily used in the implementation of access control policies, |
| 99 | * where access to application features is influenced by the type of certificate presented |
| 100 | * by a requester. |
| 101 | * |
| 102 | * @note Cert type is an API data type only; it should never be sent over-the-wire. |
| 103 | */ |
Karsten Sperling | 441aad7 | 2023-08-19 02:33:09 +1200 | [diff] [blame] | 104 | enum class CertType : uint8_t |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 105 | { |
Karsten Sperling | 441aad7 | 2023-08-19 02:33:09 +1200 | [diff] [blame] | 106 | kNotSpecified = 0x00, /**< The certificate's type has not been specified. */ |
| 107 | kRoot = 0x01, /**< A CHIP Root certificate. */ |
| 108 | kICA = 0x02, /**< A CHIP Intermediate CA certificate. */ |
| 109 | kNode = 0x03, /**< A CHIP node certificate. */ |
| 110 | kFirmwareSigning = 0x04, /**< A CHIP firmware signing certificate. Note that CHIP doesn't |
| 111 | specify how firmware images are signed and implementation of |
| 112 | firmware image signing is manufacturer-specific. The CHIP |
| 113 | certificate format supports encoding of firmware signing |
| 114 | certificates if chosen by the manufacturer to use them. */ |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 115 | }; |
| 116 | |
| 117 | /** X.509 Certificate Key Purpose Flags |
| 118 | * |
| 119 | * The flags order must match the enumeration order of corresponding kOID_KeyPurpose values. |
| 120 | */ |
| 121 | enum class KeyPurposeFlags : uint8_t |
| 122 | { |
| 123 | kServerAuth = 0x01, /**< Extended key usage is server authentication. */ |
| 124 | kClientAuth = 0x02, /**< Extended key usage is client authentication. */ |
| 125 | kCodeSigning = 0x04, /**< Extended key usage is code signing. */ |
| 126 | kEmailProtection = 0x08, /**< Extended key usage is email protection. */ |
| 127 | kTimeStamping = 0x10, /**< Extended key usage is time stamping. */ |
| 128 | kOCSPSigning = 0x20, /**< Extended key usage is OCSP signing. */ |
| 129 | }; |
| 130 | |
| 131 | /** X.509 Certificate Key Usage Flags |
| 132 | */ |
| 133 | enum class KeyUsageFlags : uint16_t |
| 134 | { |
| 135 | kDigitalSignature = 0x0001, /**< Key usage is digital signature. */ |
| 136 | kNonRepudiation = 0x0002, /**< Key usage is non-repudiation. */ |
| 137 | kKeyEncipherment = 0x0004, /**< Key usage is key encipherment. */ |
| 138 | kDataEncipherment = 0x0008, /**< Key usage is data encipherment. */ |
| 139 | kKeyAgreement = 0x0010, /**< Key usage is key agreement. */ |
| 140 | kKeyCertSign = 0x0020, /**< Key usage is key cert signing. */ |
| 141 | kCRLSign = 0x0040, /**< Key usage is CRL signing. */ |
| 142 | kEncipherOnly = 0x0080, /**< Key usage is encipher only. */ |
| 143 | kDecipherOnly = 0x0100, /**< Key usage is decipher only. */ |
| 144 | }; |
| 145 | |
| 146 | /** CHIP Certificate Flags |
| 147 | * |
| 148 | * Contains information about a certificate that has been loaded into a ChipCertificateData object. |
| 149 | */ |
| 150 | enum class CertFlags : uint16_t |
| 151 | { |
| 152 | kExtPresent_BasicConstraints = 0x0001, /**< Basic constraints extension is present in the certificate. */ |
Evgeny Margolis | ac22f1b | 2021-02-10 11:30:02 -0800 | [diff] [blame] | 153 | kExtPresent_KeyUsage = 0x0002, /**< Key usage extension is present in the certificate. */ |
| 154 | kExtPresent_ExtendedKeyUsage = 0x0004, /**< Extended key usage extension is present in the certificate. */ |
| 155 | kExtPresent_SubjectKeyId = 0x0008, /**< Subject key identifier extension is present in the certificate. */ |
| 156 | kExtPresent_AuthKeyId = 0x0010, /**< Authority key identifier extension is present in the certificate. */ |
Evgeny Margolis | ba9c503 | 2021-04-21 21:47:27 -0700 | [diff] [blame] | 157 | kExtPresent_FutureIsCritical = 0x0020, /**< Future extension marked as critical is present in the certificate. */ |
| 158 | kPathLenConstraintPresent = 0x0040, /**< Path length constraint is present in the certificate. */ |
| 159 | kIsCA = 0x0080, /**< Indicates that certificate is a CA certificate. */ |
| 160 | kIsTrustAnchor = 0x0100, /**< Indicates that certificate is a trust anchor. */ |
| 161 | kTBSHashPresent = 0x0200, /**< Indicates that TBS hash of the certificate was generated and stored. */ |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 162 | }; |
| 163 | |
| 164 | /** CHIP Certificate Decode Flags |
| 165 | * |
| 166 | * Contains information specifying how a certificate should be decoded. |
| 167 | */ |
| 168 | enum class CertDecodeFlags : uint8_t |
| 169 | { |
| 170 | kGenerateTBSHash = 0x01, /**< Indicates that to-be-signed (TBS) hash of the certificate should be calculated when certificate is |
| 171 | loaded. The TBS hash is then used to validate certificate signature. Normally, all certificates |
| 172 | (except trust anchor) in the certificate validation chain require TBS hash. */ |
| 173 | kIsTrustAnchor = 0x02, /**< Indicates that the corresponding certificate is trust anchor. */ |
| 174 | }; |
| 175 | |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 176 | enum |
| 177 | { |
| 178 | kNullCertTime = 0 |
| 179 | }; |
| 180 | |
| 181 | /** |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 182 | * @struct ChipRDN |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 183 | * |
| 184 | * @brief |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 185 | * A data structure representing a Relative Distinguished Name (RDN) in a CHIP certificate. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 186 | */ |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 187 | struct ChipRDN |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 188 | { |
Evgeny Margolis | 20c1f60 | 2022-01-26 06:09:18 -0800 | [diff] [blame] | 189 | CharSpan mString; /**< Attribute value when encoded as a string. */ |
| 190 | uint64_t mChipVal; /**< CHIP specific DN attribute value. */ |
| 191 | chip::ASN1::OID mAttrOID = chip::ASN1::kOID_NotSpecified; /**< DN attribute CHIP OID. */ |
| 192 | bool mAttrIsPrintableString; /**< Specifies if attribute is a printable string type. */ |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 193 | |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 194 | bool IsEqual(const ChipRDN & other) const; |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 195 | bool IsEmpty() const { return mAttrOID == chip::ASN1::kOID_NotSpecified; } |
Tennessee Carmel-Veilleux | eba8dee | 2022-08-29 15:40:07 -0400 | [diff] [blame] | 196 | void Clear() |
| 197 | { |
| 198 | mAttrOID = chip::ASN1::kOID_NotSpecified; |
| 199 | mAttrIsPrintableString = false; |
| 200 | mChipVal = 0; |
| 201 | mString = CharSpan{}; |
| 202 | } |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 203 | }; |
| 204 | |
| 205 | /** |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 206 | * @brief |
| 207 | * A data structure representing a Distinguished Name (DN) in a CHIP certificate. |
| 208 | */ |
| 209 | class ChipDN |
| 210 | { |
| 211 | public: |
| 212 | ChipDN(); |
| 213 | ~ChipDN(); |
| 214 | |
| 215 | void Clear(); |
| 216 | |
| 217 | /** |
| 218 | * @brief Add CHIP-specific attribute to the DN. |
| 219 | * |
| 220 | * @param oid CHIP-specific OID for DN attribute. |
| 221 | * @param val CHIP-specific DN attribute value. |
| 222 | * |
| 223 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 224 | **/ |
| 225 | CHIP_ERROR AddAttribute(chip::ASN1::OID oid, uint64_t val); |
| 226 | |
| 227 | /** |
Evgeny Margolis | a8dcee4 | 2022-03-23 09:50:37 -0700 | [diff] [blame] | 228 | * @brief Add CASE Authenticated Tags (CATs) attributes to the DN. |
| 229 | * |
| 230 | * @param cats Array of CAT values. |
| 231 | * |
| 232 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 233 | **/ |
| 234 | CHIP_ERROR AddCATs(const chip::CATValues & cats); |
| 235 | |
| 236 | /** |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 237 | * @brief Add string attribute to the DN. |
| 238 | * |
| 239 | * @param oid String OID for DN attribute. |
Evgeny Margolis | baf2ca0 | 2021-10-26 18:42:29 -0700 | [diff] [blame] | 240 | * @param val A CharSpan object containing a pointer and length of the DN string attribute |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 241 | * buffer. The value in the buffer should remain valid while the object is in use. |
Evgeny Margolis | 20c1f60 | 2022-01-26 06:09:18 -0800 | [diff] [blame] | 242 | * @param isPrintableString Specifies if attribute ASN1 type is a printable string. |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 243 | * |
| 244 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 245 | **/ |
Evgeny Margolis | 20c1f60 | 2022-01-26 06:09:18 -0800 | [diff] [blame] | 246 | CHIP_ERROR AddAttribute(chip::ASN1::OID oid, CharSpan val, bool isPrintableString); |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 247 | |
Evgeny Margolis | 8720d46 | 2022-04-11 09:53:48 -0700 | [diff] [blame] | 248 | inline CHIP_ERROR AddAttribute_CommonName(CharSpan val, bool isPrintableString) |
| 249 | { |
| 250 | return AddAttribute(ASN1::kOID_AttributeType_CommonName, val, isPrintableString); |
| 251 | } |
| 252 | inline CHIP_ERROR AddAttribute_Surname(CharSpan val, bool isPrintableString) |
| 253 | { |
| 254 | return AddAttribute(ASN1::kOID_AttributeType_Surname, val, isPrintableString); |
| 255 | } |
| 256 | inline CHIP_ERROR AddAttribute_SerialNumber(CharSpan val, bool isPrintableString) |
| 257 | { |
| 258 | return AddAttribute(ASN1::kOID_AttributeType_SerialNumber, val, isPrintableString); |
| 259 | } |
| 260 | inline CHIP_ERROR AddAttribute_CountryName(CharSpan val, bool isPrintableString) |
| 261 | { |
| 262 | return AddAttribute(ASN1::kOID_AttributeType_CountryName, val, isPrintableString); |
| 263 | } |
| 264 | inline CHIP_ERROR AddAttribute_LocalityName(CharSpan val, bool isPrintableString) |
| 265 | { |
| 266 | return AddAttribute(ASN1::kOID_AttributeType_LocalityName, val, isPrintableString); |
| 267 | } |
| 268 | inline CHIP_ERROR AddAttribute_StateOrProvinceName(CharSpan val, bool isPrintableString) |
| 269 | { |
| 270 | return AddAttribute(ASN1::kOID_AttributeType_StateOrProvinceName, val, isPrintableString); |
| 271 | } |
| 272 | inline CHIP_ERROR AddAttribute_OrganizationName(CharSpan val, bool isPrintableString) |
| 273 | { |
| 274 | return AddAttribute(ASN1::kOID_AttributeType_OrganizationName, val, isPrintableString); |
| 275 | } |
| 276 | inline CHIP_ERROR AddAttribute_OrganizationalUnitName(CharSpan val, bool isPrintableString) |
| 277 | { |
| 278 | return AddAttribute(ASN1::kOID_AttributeType_OrganizationalUnitName, val, isPrintableString); |
| 279 | } |
| 280 | inline CHIP_ERROR AddAttribute_Title(CharSpan val, bool isPrintableString) |
| 281 | { |
| 282 | return AddAttribute(ASN1::kOID_AttributeType_Title, val, isPrintableString); |
| 283 | } |
| 284 | inline CHIP_ERROR AddAttribute_Name(CharSpan val, bool isPrintableString) |
| 285 | { |
| 286 | return AddAttribute(ASN1::kOID_AttributeType_Name, val, isPrintableString); |
| 287 | } |
| 288 | inline CHIP_ERROR AddAttribute_GivenName(CharSpan val, bool isPrintableString) |
| 289 | { |
| 290 | return AddAttribute(ASN1::kOID_AttributeType_GivenName, val, isPrintableString); |
| 291 | } |
| 292 | inline CHIP_ERROR AddAttribute_Initials(CharSpan val, bool isPrintableString) |
| 293 | { |
| 294 | return AddAttribute(ASN1::kOID_AttributeType_Initials, val, isPrintableString); |
| 295 | } |
| 296 | inline CHIP_ERROR AddAttribute_GenerationQualifier(CharSpan val, bool isPrintableString) |
| 297 | { |
| 298 | return AddAttribute(ASN1::kOID_AttributeType_GenerationQualifier, val, isPrintableString); |
| 299 | } |
| 300 | inline CHIP_ERROR AddAttribute_DNQualifier(CharSpan val, bool isPrintableString) |
| 301 | { |
| 302 | return AddAttribute(ASN1::kOID_AttributeType_DNQualifier, val, isPrintableString); |
| 303 | } |
| 304 | inline CHIP_ERROR AddAttribute_Pseudonym(CharSpan val, bool isPrintableString) |
| 305 | { |
| 306 | return AddAttribute(ASN1::kOID_AttributeType_Pseudonym, val, isPrintableString); |
| 307 | } |
| 308 | inline CHIP_ERROR AddAttribute_DomainComponent(CharSpan val, bool isPrintableString) |
| 309 | { |
| 310 | return AddAttribute(ASN1::kOID_AttributeType_DomainComponent, val, isPrintableString); |
| 311 | } |
| 312 | inline CHIP_ERROR AddAttribute_MatterNodeId(uint64_t val) { return AddAttribute(ASN1::kOID_AttributeType_MatterNodeId, val); } |
| 313 | inline CHIP_ERROR AddAttribute_MatterFirmwareSigningId(uint64_t val) |
| 314 | { |
| 315 | return AddAttribute(ASN1::kOID_AttributeType_MatterFirmwareSigningId, val); |
| 316 | } |
| 317 | inline CHIP_ERROR AddAttribute_MatterICACId(uint64_t val) { return AddAttribute(ASN1::kOID_AttributeType_MatterICACId, val); } |
| 318 | inline CHIP_ERROR AddAttribute_MatterRCACId(uint64_t val) { return AddAttribute(ASN1::kOID_AttributeType_MatterRCACId, val); } |
| 319 | inline CHIP_ERROR AddAttribute_MatterFabricId(uint64_t val) |
| 320 | { |
| 321 | return AddAttribute(ASN1::kOID_AttributeType_MatterFabricId, val); |
| 322 | } |
| 323 | inline CHIP_ERROR AddAttribute_MatterCASEAuthTag(CASEAuthTag val) |
| 324 | { |
| 325 | return AddAttribute(ASN1::kOID_AttributeType_MatterCASEAuthTag, val); |
| 326 | } |
| 327 | |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 328 | /** |
| 329 | * @brief Determine type of a CHIP certificate. |
| 330 | * This method performs an assessment of a certificate's type based on the structure |
| 331 | * of its subject DN. |
| 332 | * |
| 333 | * @param certType A reference to the certificate type value. |
| 334 | * |
| 335 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 336 | **/ |
Karsten Sperling | 441aad7 | 2023-08-19 02:33:09 +1200 | [diff] [blame] | 337 | CHIP_ERROR GetCertType(CertType & certType) const; |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 338 | |
Joseph Kelly | da45bb3 | 2021-06-02 23:38:33 -0400 | [diff] [blame] | 339 | /** |
| 340 | * @brief Retrieve the ID of a CHIP certificate. |
| 341 | * |
| 342 | * @param certId A reference to the certificate ID value. |
| 343 | * |
| 344 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 345 | **/ |
Lazar Kovacic | 16f8061 | 2021-06-18 06:50:51 +0200 | [diff] [blame] | 346 | CHIP_ERROR GetCertChipId(uint64_t & certId) const; |
Joseph Kelly | da45bb3 | 2021-06-02 23:38:33 -0400 | [diff] [blame] | 347 | |
Joseph Kelly | 410b9f9 | 2021-07-28 10:20:48 -0400 | [diff] [blame] | 348 | /** |
| 349 | * @brief Retrieve the Fabric ID of a CHIP certificate. |
| 350 | **/ |
| 351 | CHIP_ERROR GetCertFabricId(uint64_t & fabricId) const; |
| 352 | |
Evgeny Margolis | 20c1f60 | 2022-01-26 06:09:18 -0800 | [diff] [blame] | 353 | /** |
Evgeny Margolis | 7c69523 | 2022-03-28 13:12:38 -0700 | [diff] [blame] | 354 | * @brief Encode ChipDN attributes in TLV form. |
| 355 | **/ |
| 356 | CHIP_ERROR EncodeToTLV(chip::TLV::TLVWriter & writer, TLV::Tag tag) const; |
| 357 | |
| 358 | /** |
Evgeny Margolis | 20c1f60 | 2022-01-26 06:09:18 -0800 | [diff] [blame] | 359 | * @brief Decode ChipDN attributes from TLV encoded format. |
| 360 | * |
| 361 | * @param reader A TLVReader positioned at the ChipDN TLV list. |
| 362 | **/ |
| 363 | CHIP_ERROR DecodeFromTLV(chip::TLV::TLVReader & reader); |
| 364 | |
| 365 | /** |
| 366 | * @brief Encode ChipDN attributes in ASN1 form. |
| 367 | **/ |
| 368 | CHIP_ERROR EncodeToASN1(ASN1::ASN1Writer & writer) const; |
| 369 | |
Evgeny Margolis | 7c69523 | 2022-03-28 13:12:38 -0700 | [diff] [blame] | 370 | /** |
| 371 | * @brief Decode ChipDN attributes from ASN1 encoded format. |
| 372 | * |
| 373 | * @param reader A ASN1Reader positioned at the ChipDN ASN1 list. |
| 374 | **/ |
| 375 | CHIP_ERROR DecodeFromASN1(ASN1::ASN1Reader & reader); |
| 376 | |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 377 | bool IsEqual(const ChipDN & other) const; |
| 378 | |
| 379 | /** |
| 380 | * @brief Determine if DN is empty (doesn't have DN attributes). |
| 381 | * |
| 382 | * @return true if DN is empty, false otherwise. |
| 383 | **/ |
| 384 | bool IsEmpty() const { return RDNCount() == 0; } |
| 385 | |
Tennessee Carmel-Veilleux | 6ba2a09 | 2022-04-07 09:12:12 -0400 | [diff] [blame] | 386 | static_assert((CHIP_CONFIG_CERT_MAX_RDN_ATTRIBUTES) >= 5, "Spec requires at least 5 RDN to be supported per Matter TLV cert"); |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 387 | ChipRDN rdn[CHIP_CONFIG_CERT_MAX_RDN_ATTRIBUTES]; |
| 388 | |
| 389 | uint8_t RDNCount() const; |
| 390 | }; |
| 391 | |
| 392 | /** |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 393 | * @brief A data structure for holding a certificate key identifier, without the ownership of it. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 394 | */ |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 395 | using CertificateKeyId = FixedByteSpan<kKeyIdentifierLength>; |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 396 | |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 397 | /** |
| 398 | * @brief A data structure for holding a P256 ECDSA signature, without the ownership of it. |
| 399 | */ |
| 400 | using P256ECDSASignatureSpan = FixedByteSpan<Crypto::kP256_ECDSA_Signature_Length_Raw>; |
| 401 | |
| 402 | /** |
| 403 | * @brief A data structure for holding a P256 Public Key, without the ownership of it. |
| 404 | */ |
Boris Zbarsky | dfd71fe | 2022-04-14 23:29:44 -0400 | [diff] [blame] | 405 | using P256PublicKeySpan = FixedByteSpan<Crypto::kP256_PublicKey_Length>; |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 406 | |
| 407 | /** |
| 408 | * @brief A data structure for holding a P256 Integer, without the ownership of it. |
| 409 | */ |
| 410 | using P256IntegerSpan = FixedByteSpan<Crypto::kP256_FE_Length>; |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 411 | |
| 412 | /** |
| 413 | * @struct ChipCertificateData |
| 414 | * |
| 415 | * @brief |
| 416 | * In-memory representation of data extracted from a CHIP certificate. |
| 417 | * |
| 418 | * Some of the fields in this structure are pointers to the fields in the original |
| 419 | * CHIP certificate. That CHIP certificate is stored in a separate buffer and it is |
| 420 | * required that data in that buffer remains valid while the corresponding |
| 421 | * ChipCertificateData structure is used. |
| 422 | */ |
| 423 | struct ChipCertificateData |
| 424 | { |
| 425 | ChipCertificateData(); |
| 426 | ~ChipCertificateData(); |
| 427 | |
| 428 | void Clear(); |
Pankaj Garg | c2cc13d | 2021-05-27 12:23:25 -0700 | [diff] [blame] | 429 | bool IsEqual(const ChipCertificateData & other) const; |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 430 | |
Joseph Kelly | da45bb3 | 2021-06-02 23:38:33 -0400 | [diff] [blame] | 431 | ByteSpan mCertificate; /**< Original raw buffer data. */ |
Kevin Schoedel | 8ea423a | 2021-03-11 11:49:18 -0500 | [diff] [blame] | 432 | ChipDN mSubjectDN; /**< Certificate Subject DN. */ |
| 433 | ChipDN mIssuerDN; /**< Certificate Issuer DN. */ |
| 434 | CertificateKeyId mSubjectKeyId; /**< Certificate Subject public key identifier. */ |
| 435 | CertificateKeyId mAuthKeyId; /**< Certificate Authority public key identifier. */ |
| 436 | uint32_t mNotBeforeTime; /**< Certificate validity: Not Before field. */ |
| 437 | uint32_t mNotAfterTime; /**< Certificate validity: Not After field. */ |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 438 | P256PublicKeySpan mPublicKey; /**< Certificate public key. */ |
Kevin Schoedel | 8ea423a | 2021-03-11 11:49:18 -0500 | [diff] [blame] | 439 | uint16_t mPubKeyCurveOID; /**< Public key Elliptic Curve CHIP OID. */ |
| 440 | uint16_t mPubKeyAlgoOID; /**< Public key algorithm CHIP OID. */ |
| 441 | uint16_t mSigAlgoOID; /**< Certificate signature algorithm CHIP OID. */ |
| 442 | BitFlags<CertFlags> mCertFlags; /**< Certificate data flags. */ |
| 443 | BitFlags<KeyUsageFlags> mKeyUsageFlags; /**< Certificate key usage extensions flags. */ |
| 444 | BitFlags<KeyPurposeFlags> mKeyPurposeFlags; /**< Certificate extended key usage extensions flags. */ |
| 445 | uint8_t mPathLenConstraint; /**< Basic constraint: path length. */ |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 446 | P256ECDSASignatureSpan mSignature; /**< Certificate signature. */ |
Evgeny Margolis | 85eb604 | 2021-06-08 10:39:09 -0700 | [diff] [blame] | 447 | |
| 448 | uint8_t mTBSHash[Crypto::kSHA256_Hash_Length]; /**< Certificate TBS hash. */ |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 449 | }; |
| 450 | |
| 451 | /** |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 452 | * @brief Decode CHIP certificate. |
| 453 | * It is required that the CHIP certificate in the chipCert buffer stays valid while |
| 454 | * the certData is used. |
| 455 | * |
| 456 | * @param chipCert Buffer containing CHIP certificate. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 457 | * @param certData Structure containing data extracted from the CHIP certificate. |
| 458 | * |
| 459 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 460 | **/ |
Evgeny Margolis | 3640d36 | 2021-08-16 13:30:28 -0700 | [diff] [blame] | 461 | CHIP_ERROR DecodeChipCert(const ByteSpan chipCert, ChipCertificateData & certData); |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 462 | |
| 463 | /** |
| 464 | * @brief Decode CHIP certificate. |
| 465 | * It is required that the CHIP certificate in the reader's underlying buffer stays valid while |
| 466 | * the certData is used. |
| 467 | * |
| 468 | * @param reader A TLVReader positioned at the CHIP certificate TLV structure. |
| 469 | * @param certData Structure containing data extracted from the CHIP certificate. |
| 470 | * |
| 471 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 472 | **/ |
| 473 | CHIP_ERROR DecodeChipCert(chip::TLV::TLVReader & reader, ChipCertificateData & certData); |
| 474 | |
| 475 | /** |
| 476 | * @brief Decode CHIP Distinguished Name (DN). |
| 477 | * It is required that the CHIP DN in the reader's underlying buffer stays valid while |
| 478 | * the dn structure is used. |
| 479 | * |
| 480 | * @param reader A TLVReader positioned at the CHIP DN TLV structure. |
| 481 | * @param dn Distinguished Name structure. |
| 482 | * |
| 483 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 484 | **/ |
| 485 | CHIP_ERROR DecodeChipDN(chip::TLV::TLVReader & reader, ChipDN & dn); |
| 486 | |
| 487 | /** |
| 488 | * @brief Convert standard X.509 certificate to CHIP certificate. |
| 489 | * |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 490 | * @param x509Cert CHIP X.509 DER encoded certificate. |
Evgeny Margolis | 3640d36 | 2021-08-16 13:30:28 -0700 | [diff] [blame] | 491 | * @param chipCert Buffer to store converted certificate in CHIP format. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 492 | * |
| 493 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 494 | **/ |
Evgeny Margolis | 3640d36 | 2021-08-16 13:30:28 -0700 | [diff] [blame] | 495 | CHIP_ERROR ConvertX509CertToChipCert(const ByteSpan x509Cert, MutableByteSpan & chipCert); |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 496 | |
| 497 | /** |
| 498 | * @brief Convert CHIP certificate to the standard X.509 DER encoded certificate. |
| 499 | * |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 500 | * @param chipCert CHIP certificate in CHIP TLV encoding. |
Andrei Litvin | 0fcf173 | 2021-08-20 17:50:27 -0400 | [diff] [blame] | 501 | * @param x509Cert Buffer to store converted certificate in X.509 DER format. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 502 | * |
| 503 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 504 | **/ |
Evgeny Margolis | 3640d36 | 2021-08-16 13:30:28 -0700 | [diff] [blame] | 505 | CHIP_ERROR ConvertChipCertToX509Cert(const ByteSpan chipCert, MutableByteSpan & x509Cert); |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 506 | |
Evgeny Margolis | ed040c2 | 2022-07-15 07:30:09 -0700 | [diff] [blame] | 507 | /** |
| 508 | * Validate CHIP Root CA Certificate (RCAC) in ByteSpan TLV-encoded form. |
| 509 | * This function performs RCAC parsing, checks SubjectDN validity, verifies that SubjectDN |
| 510 | * and IssuerDN are equal, verifies that SKID and AKID are equal, validates certificate signature. |
| 511 | * |
| 512 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 513 | */ |
| 514 | CHIP_ERROR ValidateChipRCAC(const ByteSpan & rcac); |
| 515 | |
Evgeny Margolis | cfdb308 | 2022-08-23 06:41:28 -0700 | [diff] [blame] | 516 | struct FutureExtension |
| 517 | { |
| 518 | ByteSpan OID; |
| 519 | ByteSpan Extension; |
| 520 | }; |
| 521 | |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 522 | struct X509CertRequestParams |
| 523 | { |
| 524 | int64_t SerialNumber; |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 525 | uint32_t ValidityStart; |
| 526 | uint32_t ValidityEnd; |
Evgeny Margolis | 20c1f60 | 2022-01-26 06:09:18 -0800 | [diff] [blame] | 527 | ChipDN SubjectDN; |
| 528 | ChipDN IssuerDN; |
Evgeny Margolis | cfdb308 | 2022-08-23 06:41:28 -0700 | [diff] [blame] | 529 | Optional<FutureExtension> FutureExt; |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 530 | }; |
| 531 | |
| 532 | /** |
| 533 | * @brief Generate a new X.509 DER encoded Root CA certificate |
| 534 | * |
| 535 | * @param requestParams Certificate request parameters. |
| 536 | * @param issuerKeypair The certificate signing key |
Pankaj Garg | 7b00057 | 2021-08-13 20:14:29 -0700 | [diff] [blame] | 537 | * @param x509Cert Buffer to store signed certificate in X.509 DER format. |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 538 | * |
| 539 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 540 | **/ |
Pankaj Garg | 7b00057 | 2021-08-13 20:14:29 -0700 | [diff] [blame] | 541 | CHIP_ERROR NewRootX509Cert(const X509CertRequestParams & requestParams, Crypto::P256Keypair & issuerKeypair, |
| 542 | MutableByteSpan & x509Cert); |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 543 | |
| 544 | /** |
| 545 | * @brief Generate a new X.509 DER encoded Intermediate CA certificate |
| 546 | * |
| 547 | * @param requestParams Certificate request parameters. |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 548 | * @param subjectPubkey The public key of subject |
| 549 | * @param issuerKeypair The certificate signing key |
Pankaj Garg | 7b00057 | 2021-08-13 20:14:29 -0700 | [diff] [blame] | 550 | * @param x509Cert Buffer to store signed certificate in X.509 DER format. |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 551 | * |
| 552 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 553 | **/ |
Evgeny Margolis | 20c1f60 | 2022-01-26 06:09:18 -0800 | [diff] [blame] | 554 | CHIP_ERROR NewICAX509Cert(const X509CertRequestParams & requestParams, const Crypto::P256PublicKey & subjectPubkey, |
| 555 | Crypto::P256Keypair & issuerKeypair, MutableByteSpan & x509Cert); |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 556 | |
| 557 | /** |
| 558 | * @brief Generate a new X.509 DER encoded Node operational certificate |
| 559 | * |
| 560 | * @param requestParams Certificate request parameters. |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 561 | * @param subjectPubkey The public key of subject |
| 562 | * @param issuerKeypair The certificate signing key |
Pankaj Garg | 7b00057 | 2021-08-13 20:14:29 -0700 | [diff] [blame] | 563 | * @param x509Cert Buffer to store signed certificate in X.509 DER format. |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 564 | * |
| 565 | * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise |
| 566 | **/ |
Evgeny Margolis | 20c1f60 | 2022-01-26 06:09:18 -0800 | [diff] [blame] | 567 | CHIP_ERROR NewNodeOperationalX509Cert(const X509CertRequestParams & requestParams, const Crypto::P256PublicKey & subjectPubkey, |
| 568 | Crypto::P256Keypair & issuerKeypair, MutableByteSpan & x509Cert); |
Pankaj Garg | 237cfd0 | 2021-05-03 14:32:48 -0700 | [diff] [blame] | 569 | |
| 570 | /** |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 571 | * @brief |
Michael Sandstedt | 8cc291d | 2022-06-07 10:02:58 -0500 | [diff] [blame] | 572 | * Convert a certificate date/time (in the form of an ASN.1 universal time structure) into a CHIP Epoch time. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 573 | * |
| 574 | * @note |
| 575 | * This function makes no attempt to verify the correct range of the input time other than year. |
| 576 | * Therefore callers must make sure the supplied values are valid prior to invocation. |
| 577 | * |
Evgeny Margolis | fbc9596 | 2021-02-17 10:23:44 -0800 | [diff] [blame] | 578 | * @param asn1Time The calendar date/time to be converted. |
Michael Sandstedt | 8cc291d | 2022-06-07 10:02:58 -0500 | [diff] [blame] | 579 | * @param epochTime A reference to an integer that will receive CHIP Epoch time. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 580 | * |
| 581 | * @retval #CHIP_NO_ERROR If the input time was successfully converted. |
| 582 | * @retval #ASN1_ERROR_UNSUPPORTED_ENCODING If the input time contained a year value that could not |
Evgeny Margolis | fbc9596 | 2021-02-17 10:23:44 -0800 | [diff] [blame] | 583 | * be represented in a CHIP epoch UTC time value. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 584 | **/ |
Evgeny Margolis | fbc9596 | 2021-02-17 10:23:44 -0800 | [diff] [blame] | 585 | CHIP_ERROR ASN1ToChipEpochTime(const chip::ASN1::ASN1UniversalTime & asn1Time, uint32_t & epochTime); |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 586 | |
| 587 | /** |
| 588 | * @brief |
Evgeny Margolis | fbc9596 | 2021-02-17 10:23:44 -0800 | [diff] [blame] | 589 | * Convert a CHIP epoch UTC time into an ASN.1 universal time structure. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 590 | * |
Evgeny Margolis | fbc9596 | 2021-02-17 10:23:44 -0800 | [diff] [blame] | 591 | * @param epochTime A CHIP epoch UTC time to be converted. |
| 592 | * @param asn1Time A reference to an ASN1UniversalTime structure to receive the date/time. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 593 | * |
Evgeny Margolis | fbc9596 | 2021-02-17 10:23:44 -0800 | [diff] [blame] | 594 | * @retval #CHIP_NO_ERROR If the input time was successfully converted. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 595 | */ |
Evgeny Margolis | fbc9596 | 2021-02-17 10:23:44 -0800 | [diff] [blame] | 596 | CHIP_ERROR ChipEpochToASN1Time(uint32_t epochTime, chip::ASN1::ASN1UniversalTime & asn1Time); |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 597 | |
| 598 | /** |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 599 | * @return True if the OID represents a CHIP-defined 64-bit distinguished named attribute. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 600 | **/ |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 601 | inline bool IsChip64bitDNAttr(chip::ASN1::OID oid) |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 602 | { |
Evgeny Margolis | 8720d46 | 2022-04-11 09:53:48 -0700 | [diff] [blame] | 603 | return (oid == chip::ASN1::kOID_AttributeType_MatterNodeId || oid == chip::ASN1::kOID_AttributeType_MatterFirmwareSigningId || |
| 604 | oid == chip::ASN1::kOID_AttributeType_MatterICACId || oid == chip::ASN1::kOID_AttributeType_MatterRCACId || |
| 605 | oid == chip::ASN1::kOID_AttributeType_MatterFabricId); |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 606 | } |
| 607 | |
| 608 | /** |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 609 | * @return True if the OID represents a CHIP-defined 32-bit distinguished named attribute. |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 610 | **/ |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 611 | inline bool IsChip32bitDNAttr(chip::ASN1::OID oid) |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 612 | { |
Evgeny Margolis | 8720d46 | 2022-04-11 09:53:48 -0700 | [diff] [blame] | 613 | return (oid == chip::ASN1::kOID_AttributeType_MatterCASEAuthTag); |
Evgeny Margolis | 7d33476 | 2021-04-14 09:25:47 -0700 | [diff] [blame] | 614 | } |
| 615 | |
| 616 | /** |
| 617 | * @return True if the OID represents a CHIP-defined distinguished named attribute. |
| 618 | **/ |
| 619 | inline bool IsChipDNAttr(chip::ASN1::OID oid) |
| 620 | { |
| 621 | return (IsChip64bitDNAttr(oid) || IsChip32bitDNAttr(oid)); |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 622 | } |
| 623 | |
Evgeny Margolis | 85eb604 | 2021-06-08 10:39:09 -0700 | [diff] [blame] | 624 | /** |
| 625 | * @brief Convert an ASN.1 DER encoded integer to a raw big-endian integer. |
| 626 | * |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 627 | * @param derInt P256 integer in ASN.1 DER encoded form. |
Evgeny Margolis | 85eb604 | 2021-06-08 10:39:09 -0700 | [diff] [blame] | 628 | * @param rawInt Buffer to store converted raw integer. |
| 629 | * @param rawIntLen The length of the converted raw integer. |
| 630 | * |
| 631 | * @retval #CHIP_NO_ERROR If the integer value was successfully converted. |
| 632 | */ |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 633 | CHIP_ERROR ConvertIntegerDERToRaw(ByteSpan derInt, uint8_t * rawInt, const uint16_t rawIntLen); |
Evgeny Margolis | 85eb604 | 2021-06-08 10:39:09 -0700 | [diff] [blame] | 634 | |
| 635 | /** |
Evgeny Margolis | 85eb604 | 2021-06-08 10:39:09 -0700 | [diff] [blame] | 636 | * @brief Convert a raw CHIP signature to an ASN.1 DER encoded signature structure. |
| 637 | * |
Evgeny Margolis | 8e86c9e | 2021-09-15 21:22:30 -0700 | [diff] [blame] | 638 | * @param[in] rawSig P256 ECDSA signature in raw form. |
| 639 | * @param[in,out] derSig Output buffer to receive the converted ASN.1 DER encoded signature. |
| 640 | * `derSig` must be at least `kMax_ECDSA_Signature_Length_Der` bytes long. |
| 641 | * The `derSig` size will be set to the actual DER encoded signature length on success. |
Evgeny Margolis | 85eb604 | 2021-06-08 10:39:09 -0700 | [diff] [blame] | 642 | * |
| 643 | * @retval #CHIP_NO_ERROR If the signature value was successfully converted. |
| 644 | */ |
Evgeny Margolis | 8e86c9e | 2021-09-15 21:22:30 -0700 | [diff] [blame] | 645 | CHIP_ERROR ConvertECDSASignatureRawToDER(P256ECDSASignatureSpan rawSig, MutableByteSpan & derSig); |
Evgeny Margolis | 85eb604 | 2021-06-08 10:39:09 -0700 | [diff] [blame] | 646 | |
| 647 | /** |
| 648 | * @brief Convert a raw CHIP ECDSA signature to an ASN.1 DER encoded signature structure. |
| 649 | * |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 650 | * @param rawSig P256 ECDSA signature in raw form. |
Evgeny Margolis | 85eb604 | 2021-06-08 10:39:09 -0700 | [diff] [blame] | 651 | * @param writer A reference to the ASN1Writer to store ASN.1 DER encoded signature. |
| 652 | * |
| 653 | * @retval #CHIP_NO_ERROR If the signature value was successfully converted. |
| 654 | */ |
Evgeny Margolis | 08b5650 | 2021-06-30 21:34:42 -0700 | [diff] [blame] | 655 | CHIP_ERROR ConvertECDSASignatureRawToDER(P256ECDSASignatureSpan rawSig, ASN1::ASN1Writer & writer); |
Evgeny Margolis | 85eb604 | 2021-06-08 10:39:09 -0700 | [diff] [blame] | 656 | |
| 657 | /** |
| 658 | * @brief Convert an ASN.1 DER encoded ECDSA signature to a raw CHIP signature. |
| 659 | * |
| 660 | * @param reader A reference to the ASN1Reader positioned at the beginning of the |
| 661 | * DER encoded ECDSA signature. |
| 662 | * @param writer A reference to the TLVWriter to store TLV encoded ECDSA signature element. |
| 663 | * @param tag Tag to use for TLV encoded signature. |
| 664 | * |
| 665 | * @retval #CHIP_NO_ERROR If the signature value was successfully converted. |
| 666 | */ |
| 667 | CHIP_ERROR ConvertECDSASignatureDERToRaw(ASN1::ASN1Reader & reader, chip::TLV::TLVWriter & writer, uint64_t tag); |
| 668 | |
Boris Zbarsky | 8af9981 | 2021-07-15 01:58:05 -0400 | [diff] [blame] | 669 | /** |
Michael Sandstedt | 54b5b69 | 2022-01-27 10:51:40 -0600 | [diff] [blame] | 670 | * Extract the Fabric ID from an operational certificate that has already been |
| 671 | * parsed. |
Pankaj Garg | 5e3f4f6 | 2021-08-19 08:58:48 -0700 | [diff] [blame] | 672 | * |
| 673 | * This function can be used to extract Fabric ID from an ICA certificate. |
Pankaj Garg | 6efec20 | 2021-08-25 10:47:29 -0700 | [diff] [blame] | 674 | * These certificates may not contain a NodeID, so ExtractNodeIdFabricIdFromOpCert() |
Pankaj Garg | 5e3f4f6 | 2021-08-19 08:58:48 -0700 | [diff] [blame] | 675 | * cannot be used for such certificates. |
| 676 | * |
Evgeny Margolis | c1b5648 | 2022-03-10 11:02:32 -0800 | [diff] [blame] | 677 | * @return CHIP_ERROR_NOT_FOUND if the passed-in cert does not have RDN |
Pankaj Garg | 5e3f4f6 | 2021-08-19 08:58:48 -0700 | [diff] [blame] | 678 | * corresponding to FabricID. |
| 679 | */ |
| 680 | CHIP_ERROR ExtractFabricIdFromCert(const ChipCertificateData & cert, FabricId * fabricId); |
| 681 | |
| 682 | /** |
Pankaj Garg | 6efec20 | 2021-08-25 10:47:29 -0700 | [diff] [blame] | 683 | * Extract Node ID and Fabric ID from an operational certificate that has already been |
Boris Zbarsky | 8af9981 | 2021-07-15 01:58:05 -0400 | [diff] [blame] | 684 | * parsed. |
| 685 | * |
Evgeny Margolis | c1b5648 | 2022-03-10 11:02:32 -0800 | [diff] [blame] | 686 | * @return CHIP_ERROR_NOT_FOUND if the passed-in cert does not have at |
Boris Zbarsky | 8af9981 | 2021-07-15 01:58:05 -0400 | [diff] [blame] | 687 | * least one NodeId RDN and one FabricId RDN in the Subject DN. No other |
| 688 | * validation (e.g. checkign that there is exactly one RDN of each type) is |
| 689 | * performed. |
| 690 | */ |
Pankaj Garg | 6efec20 | 2021-08-25 10:47:29 -0700 | [diff] [blame] | 691 | CHIP_ERROR ExtractNodeIdFabricIdFromOpCert(const ChipCertificateData & opcert, NodeId * nodeId, FabricId * fabricId); |
Boris Zbarsky | 8af9981 | 2021-07-15 01:58:05 -0400 | [diff] [blame] | 692 | |
| 693 | /** |
Michael Sandstedt | 87d3698 | 2022-01-24 12:38:13 -0600 | [diff] [blame] | 694 | * Extract Node ID, Fabric ID and Compressed Fabric ID from an operational |
C Freeman | 09a4921 | 2022-01-24 21:19:43 -0500 | [diff] [blame] | 695 | * certificate and its associated root certificate. |
Michael Sandstedt | 87d3698 | 2022-01-24 12:38:13 -0600 | [diff] [blame] | 696 | * |
| 697 | * @return CHIP_ERROR on failure or CHIP_NO_ERROR otherwise. |
| 698 | */ |
C Freeman | 09a4921 | 2022-01-24 21:19:43 -0500 | [diff] [blame] | 699 | CHIP_ERROR ExtractNodeIdFabricIdCompressedFabricIdFromOpCerts(ByteSpan rcac, ByteSpan noc, CompressedFabricId & compressedFabricId, |
| 700 | FabricId & fabricId, NodeId & nodeId); |
Michael Sandstedt | 87d3698 | 2022-01-24 12:38:13 -0600 | [diff] [blame] | 701 | |
| 702 | /** |
| 703 | * Extract Node ID and Compressed Fabric ID from an operational certificate |
C Freeman | 09a4921 | 2022-01-24 21:19:43 -0500 | [diff] [blame] | 704 | * and its associated root certificate. |
Michael Sandstedt | 87d3698 | 2022-01-24 12:38:13 -0600 | [diff] [blame] | 705 | * |
| 706 | * @return CHIP_ERROR on failure or CHIP_NO_ERROR otherwise. |
| 707 | */ |
C Freeman | 09a4921 | 2022-01-24 21:19:43 -0500 | [diff] [blame] | 708 | CHIP_ERROR ExtractNodeIdCompressedFabricIdFromOpCerts(ByteSpan rcac, ByteSpan noc, CompressedFabricId & compressedFabricId, |
| 709 | NodeId & nodeId); |
Michael Sandstedt | 87d3698 | 2022-01-24 12:38:13 -0600 | [diff] [blame] | 710 | |
| 711 | /** |
Evgeny Margolis | ea87cc6 | 2021-11-29 22:08:00 -0800 | [diff] [blame] | 712 | * Extract CASE Authenticated Tags from an operational certificate in ByteSpan TLV-encoded form. |
| 713 | * |
| 714 | * All values in the 'cats' struct will be set either to a valid CAT value or zero (undefined) value. |
| 715 | * |
| 716 | * @return CHIP_ERROR_INVALID_ARGUMENT if the passed-in cert is not NOC. |
| 717 | * @return CHIP_ERROR_BUFFER_TOO_SMALL if there are too many CATs in the NOC |
| 718 | */ |
| 719 | CHIP_ERROR ExtractCATsFromOpCert(const ByteSpan & opcert, CATValues & cats); |
| 720 | |
| 721 | /** |
Evgeny Margolis | 3838790 | 2021-11-12 11:01:21 -0800 | [diff] [blame] | 722 | * Extract CASE Authenticated Tags from an operational certificate that has already been |
| 723 | * parsed. |
| 724 | * |
Evgeny Margolis | ea87cc6 | 2021-11-29 22:08:00 -0800 | [diff] [blame] | 725 | * All values in the 'cats' struct will be set either to a valid CAT value or to the kUndefinedCAT value. |
Evgeny Margolis | 3838790 | 2021-11-12 11:01:21 -0800 | [diff] [blame] | 726 | * |
| 727 | * @return CHIP_ERROR_INVALID_ARGUMENT if the passed-in cert is not NOC. |
| 728 | * @return CHIP_ERROR_BUFFER_TOO_SMALL if the passed-in CATs array is too small. |
| 729 | */ |
Evgeny Margolis | ea87cc6 | 2021-11-29 22:08:00 -0800 | [diff] [blame] | 730 | CHIP_ERROR ExtractCATsFromOpCert(const ChipCertificateData & opcert, CATValues & cats); |
Evgeny Margolis | 3838790 | 2021-11-12 11:01:21 -0800 | [diff] [blame] | 731 | |
| 732 | /** |
Evgeny Margolis | ed040c2 | 2022-07-15 07:30:09 -0700 | [diff] [blame] | 733 | * Extract Fabric ID from an operational certificate in ByteSpan TLV-encoded |
Michael Sandstedt | 54b5b69 | 2022-01-27 10:51:40 -0600 | [diff] [blame] | 734 | * form. This does not perform any sort of validation on the certificate |
| 735 | * structure other than parsing it. |
| 736 | * |
| 737 | * Can return any error that can be returned from parsing the cert or from the |
| 738 | * ChipCertificateData* version of ExtractNodeIdFabricIdFromOpCert. |
| 739 | */ |
| 740 | CHIP_ERROR ExtractFabricIdFromCert(const ByteSpan & opcert, FabricId * fabricId); |
| 741 | |
| 742 | /** |
Pankaj Garg | 6efec20 | 2021-08-25 10:47:29 -0700 | [diff] [blame] | 743 | * Extract Node ID and Fabric ID from an operational certificate in ByteSpan TLV-encoded |
Boris Zbarsky | 8af9981 | 2021-07-15 01:58:05 -0400 | [diff] [blame] | 744 | * form. This does not perform any sort of validation on the certificate |
| 745 | * structure other than parsing it. |
| 746 | * |
| 747 | * Can return any error that can be returned from parsing the cert or from the |
Pankaj Garg | 6efec20 | 2021-08-25 10:47:29 -0700 | [diff] [blame] | 748 | * ChipCertificateData* version of ExtractNodeIdFabricIdFromOpCert. |
Boris Zbarsky | 8af9981 | 2021-07-15 01:58:05 -0400 | [diff] [blame] | 749 | */ |
Pankaj Garg | 6efec20 | 2021-08-25 10:47:29 -0700 | [diff] [blame] | 750 | CHIP_ERROR ExtractNodeIdFabricIdFromOpCert(const ByteSpan & opcert, NodeId * nodeId, FabricId * fabricId); |
Boris Zbarsky | 8af9981 | 2021-07-15 01:58:05 -0400 | [diff] [blame] | 751 | |
| 752 | /** |
Evgeny Margolis | aff4433 | 2021-09-14 16:14:47 -0700 | [diff] [blame] | 753 | * Extract Public Key from a chip certificate in ByteSpan TLV-encoded form. |
| 754 | * This does not perform any sort of validation on the certificate structure |
Evgeny Margolis | 7c69523 | 2022-03-28 13:12:38 -0700 | [diff] [blame] | 755 | * other than parsing it. |
Boris Zbarsky | 8af9981 | 2021-07-15 01:58:05 -0400 | [diff] [blame] | 756 | * |
Evgeny Margolis | aff4433 | 2021-09-14 16:14:47 -0700 | [diff] [blame] | 757 | * Can return any error that can be returned from parsing the cert. |
Boris Zbarsky | 8af9981 | 2021-07-15 01:58:05 -0400 | [diff] [blame] | 758 | */ |
Evgeny Margolis | aff4433 | 2021-09-14 16:14:47 -0700 | [diff] [blame] | 759 | CHIP_ERROR ExtractPublicKeyFromChipCert(const ByteSpan & chipCert, P256PublicKeySpan & publicKey); |
| 760 | |
| 761 | /** |
Michael Sandstedt | 8cc291d | 2022-06-07 10:02:58 -0500 | [diff] [blame] | 762 | * Extract Not Before Time from a chip certificate in ByteSpan TLV-encoded form. |
| 763 | * Output format is seconds referenced from the CHIP epoch. |
| 764 | * |
Michael Sandstedt | 8cc291d | 2022-06-07 10:02:58 -0500 | [diff] [blame] | 765 | * This does not perform any sort of validation on the certificate structure |
| 766 | * other than parsing it. |
| 767 | * |
| 768 | * @param chipCert CHIP certificate in TLV-encoded form |
| 769 | * @param notBeforeChipEpochTime (out) certificate NotBefore time as seconds from the CHIP epoch |
| 770 | * @return CHIP_NO_ERROR if certificate parsing was successful, else an appropriate CHIP_ERROR |
| 771 | */ |
| 772 | CHIP_ERROR ExtractNotBeforeFromChipCert(const ByteSpan & chipCert, chip::System::Clock::Seconds32 & notBeforeChipEpochTime); |
| 773 | |
| 774 | /** |
Evgeny Margolis | aff4433 | 2021-09-14 16:14:47 -0700 | [diff] [blame] | 775 | * Extract Subject Key Identifier from a chip certificate in ByteSpan TLV-encoded form. |
| 776 | * This does not perform any sort of validation on the certificate structure |
Evgeny Margolis | 7c69523 | 2022-03-28 13:12:38 -0700 | [diff] [blame] | 777 | * other than parsing it. |
Evgeny Margolis | aff4433 | 2021-09-14 16:14:47 -0700 | [diff] [blame] | 778 | * |
| 779 | * Can return any error that can be returned from parsing the cert. |
| 780 | */ |
| 781 | CHIP_ERROR ExtractSKIDFromChipCert(const ByteSpan & chipCert, CertificateKeyId & skid); |
Boris Zbarsky | 8af9981 | 2021-07-15 01:58:05 -0400 | [diff] [blame] | 782 | |
Evgeny Margolis | 7c69523 | 2022-03-28 13:12:38 -0700 | [diff] [blame] | 783 | /** |
| 784 | * Extract Subject Distinguished Name (DN) from a chip certificate in ByteSpan TLV-encoded form. |
| 785 | * It is required that the certificate in the chipCert buffer stays valid while the `dn` output is used. |
| 786 | * |
| 787 | * Can return any error that can be returned from parsing the cert. |
| 788 | */ |
| 789 | CHIP_ERROR ExtractSubjectDNFromChipCert(const ByteSpan & chipCert, ChipDN & dn); |
| 790 | |
| 791 | /** |
| 792 | * Extract Subject Distinguished Name (DN) from a chip certificate in ByteSpan X509 DER-encoded form. |
| 793 | * It is required that the certificate in the chipCert buffer stays valid while the `dn` output is used. |
| 794 | * |
| 795 | * Can return any error that can be returned from converting and parsing the cert. |
| 796 | */ |
| 797 | CHIP_ERROR ExtractSubjectDNFromX509Cert(const ByteSpan & x509Cert, ChipDN & dn); |
| 798 | |
Evgeny Margolis | 5353858 | 2021-01-12 09:14:24 -0800 | [diff] [blame] | 799 | } // namespace Credentials |
| 800 | } // namespace chip |