/src/PcapPlusPlus/Packet++/header/X509Decoder.h
Line | Count | Source |
1 | | #pragma once |
2 | | #include <chrono> |
3 | | #include "Asn1Codec.h" |
4 | | #include "CryptoDataReader.h" |
5 | | #include "X509ExtensionDataDecoder.h" |
6 | | |
7 | | /// @namespace pcpp |
8 | | /// The main namespace for the PcapPlusPlus lib |
9 | | namespace pcpp |
10 | | { |
11 | | /// @enum X509Version |
12 | | /// Represents the version of an X.509 certificate |
13 | | enum class X509Version : uint8_t |
14 | | { |
15 | | /// X.509 Version 1 |
16 | | V1 = 0, |
17 | | /// X.509 Version 2 |
18 | | V2 = 1, |
19 | | /// X.509 Version 3 |
20 | | V3 = 2, |
21 | | }; |
22 | | |
23 | | /// @class X509Algorithm |
24 | | /// Represents cryptographic algorithms used in X.509 certificates |
25 | | /// This class encapsulates various hashing and signature algorithms that can be used |
26 | | /// in X.509 certificates for signing and key exchange. |
27 | | class X509Algorithm |
28 | | { |
29 | | public: |
30 | | /// Define enum types and the corresponding int values |
31 | | enum Value : uint8_t |
32 | | { |
33 | | /// SHA-1 hashing algorithm |
34 | | SHA1, |
35 | | /// SHA-256 hashing algorithm |
36 | | SHA256, |
37 | | /// SHA-384 hashing algorithm |
38 | | SHA384, |
39 | | /// SHA-512 hashing algorithm |
40 | | SHA512, |
41 | | /// MD5 hashing algorithm (considered cryptographically broken) |
42 | | MD5, |
43 | | |
44 | | /// RSA encryption/signature algorithm |
45 | | RSA, |
46 | | /// RSA with SHA-1 signature algorithm |
47 | | RSAWithSHA1, |
48 | | /// RSA with SHA-256 signature algorithm |
49 | | RSAWithSHA256, |
50 | | /// RSA with SHA-384 signature algorithm |
51 | | RSAWithSHA384, |
52 | | /// RSA with SHA-512 signature algorithm |
53 | | RSAWithSHA512, |
54 | | /// RSA Probabilistic Signature Scheme (PSS) |
55 | | RSAPSS, |
56 | | |
57 | | /// Elliptic Curve Digital Signature Algorithm |
58 | | ECDSA, |
59 | | /// ECDSA with SHA-1 signature algorithm |
60 | | ECDSAWithSHA1, |
61 | | /// ECDSA with SHA-256 signature algorithm |
62 | | ECDSAWithSHA256, |
63 | | /// ECDSA with SHA-384 signature algorithm |
64 | | ECDSAWithSHA384, |
65 | | /// ECDSA with SHA-512 signature algorithm |
66 | | ECDSAWithSHA512, |
67 | | |
68 | | /// Digital Signature Algorithm |
69 | | DSA, |
70 | | /// DSA with SHA-1 signature algorithm |
71 | | DSAWithSHA1, |
72 | | /// DSA with SHA-256 signature algorithm |
73 | | DSAWithSHA256, |
74 | | |
75 | | /// EdDSA using Curve25519 (Ed25519) |
76 | | ED25519, |
77 | | /// EdDSA using Curve448 (Ed448) |
78 | | ED448, |
79 | | /// Diffie-Hellman key exchange algorithm |
80 | | DiffieHellman, |
81 | | |
82 | | /// Unknown or unsupported algorithm |
83 | | Unknown, |
84 | | }; |
85 | | |
86 | | X509Algorithm() = default; |
87 | | |
88 | | // cppcheck-suppress noExplicitConstructor |
89 | | /// Construct LdapOperationType from Value enum |
90 | | /// @param[in] value the operation type enum value |
91 | | constexpr X509Algorithm(Value value) : m_Value(value) |
92 | 0 | {} |
93 | | |
94 | | /// @return A string representation of the operation type |
95 | | std::string toString() const; |
96 | | |
97 | | /// @return The OID value of the operation type |
98 | | std::string getOidValue() const; |
99 | | |
100 | | /// A static method that creates LdapOperationType from an integer value |
101 | | /// @param[in] value The operation type integer value |
102 | | /// @return The operation type that corresponds to the integer value. If the integer value |
103 | | /// doesn't correspond to any operation type, LdapOperationType::Unknown is returned |
104 | | static X509Algorithm fromOidValue(const Asn1ObjectIdentifier& value); |
105 | | |
106 | | // Allow switch and comparisons. |
107 | | constexpr operator Value() const |
108 | 0 | { |
109 | 0 | return m_Value; |
110 | 0 | } |
111 | | |
112 | | // Prevent usage: if(LdapOperationType) |
113 | | explicit operator bool() const = delete; |
114 | | |
115 | | private: |
116 | | Value m_Value = Unknown; |
117 | | }; |
118 | | |
119 | | /// @class X520DistinguishedName |
120 | | /// Represents a distinguished name in an X.509 certificate |
121 | | class X520DistinguishedName |
122 | | { |
123 | | public: |
124 | | /// Define enum types and the corresponding int values |
125 | | enum Value : uint8_t |
126 | | { |
127 | | /// Common Name (CN) - Typically the fully qualified domain name (FQDN) |
128 | | CommonName, |
129 | | /// Surname (SN) - Family name of a person |
130 | | Surname, |
131 | | /// Serial Number - Serial number of the certificate |
132 | | SerialNumber, |
133 | | /// Country Name (C) - Two-letter ISO 3166-1 alpha-2 country code |
134 | | Country, |
135 | | /// Locality (L) - City or locality name |
136 | | Locality, |
137 | | /// State or Province Name (ST) - State or province name |
138 | | StateOrProvince, |
139 | | /// Organization Name (O) - Name of the organization |
140 | | Organization, |
141 | | /// Organizational Unit (OU) - Department or division within an organization |
142 | | OrganizationalUnit, |
143 | | /// Title - Job title or position |
144 | | Title, |
145 | | /// Given Name (GN) - First name of a person |
146 | | GivenName, |
147 | | /// Initials - Initials of a person's name |
148 | | Initials, |
149 | | /// Pseudonym - A person's nickname or alias |
150 | | Pseudonym, |
151 | | /// Generation Qualifier - A qualifier indicating a person's generation (e.g., Jr., Sr., III) |
152 | | GenerationQualifier, |
153 | | /// Distinguished Name Qualifier - Disambiguates similar distinguished names |
154 | | DnQualifier, |
155 | | /// Domain Component (DC) - Domain component in domain names (e.g., "example" in "example.com") |
156 | | DomainComponent, |
157 | | /// Email Address - Email address in the format user\@domain |
158 | | EmailAddress, |
159 | | /// Postal Code - Postal or ZIP code |
160 | | PostalCode, |
161 | | /// Street Address - Physical street address |
162 | | StreetAddress, |
163 | | /// Business Category - Type of business or organization |
164 | | BusinessCategory, |
165 | | /// Unknown or unsupported distinguished name type |
166 | | Unknown |
167 | | }; |
168 | | |
169 | | X520DistinguishedName() = default; |
170 | | |
171 | | // cppcheck-suppress noExplicitConstructor |
172 | | constexpr X520DistinguishedName(Value value) : m_Value(value) |
173 | 0 | {} |
174 | | |
175 | | /// @return A string representation of the distinguished name |
176 | | std::string toString() const; |
177 | | |
178 | | /// Gets the short name (abbreviation) of the distinguished name |
179 | | /// @return The short name (e.g., "CN" for CommonName) |
180 | | std::string getShortName() const; |
181 | | |
182 | | /// @return The OID value of the distinguished name |
183 | | std::string getOidValue() const; |
184 | | |
185 | | /// Creates an X520DistinguishedName from an OID value |
186 | | /// @param[in] value The ASN.1 object identifier |
187 | | /// @return The corresponding X520DistinguishedName value, or Unknown if no match is found |
188 | | static X520DistinguishedName fromOidValue(const Asn1ObjectIdentifier& value); |
189 | | |
190 | | // Allow switch and comparisons. |
191 | | constexpr operator Value() const |
192 | 0 | { |
193 | 0 | return m_Value; |
194 | 0 | } |
195 | | explicit operator bool() const = delete; |
196 | | |
197 | | private: |
198 | | Value m_Value = Unknown; |
199 | | }; |
200 | | |
201 | | /// @class X509ExtensionType |
202 | | /// Represents an X.509 extension type |
203 | | class X509ExtensionType |
204 | | { |
205 | | public: |
206 | | /// @enum Value |
207 | | /// Enumeration of supported X.509 extension types |
208 | | enum Value : uint8_t |
209 | | { |
210 | | /// Basic Constraints - Indicates if the subject is a CA and the maximum path length |
211 | | BasicConstraints, |
212 | | /// Key Usage - Defines the purpose of the key contained in the certificate |
213 | | KeyUsage, |
214 | | /// Extended Key Usage - Indicates one or more purposes for which the certified public key may be used |
215 | | ExtendedKeyUsage, |
216 | | /// Subject Key Identifier - Provides a means of identifying certificates that contain a particular public |
217 | | /// key |
218 | | SubjectKeyIdentifier, |
219 | | /// Authority Key Identifier - Identifies the public key used to verify the signature on this certificate |
220 | | AuthorityKeyIdentifier, |
221 | | /// Subject Alternative Name - Allows identities to be bound to the subject of the certificate |
222 | | SubjectAltName, |
223 | | /// Issuer Alternative Name - Allows additional identities to be associated with the issuer |
224 | | IssuerAltName, |
225 | | /// CRL Distribution Points - Identifies how CRL information is obtained |
226 | | CrlDistributionPoints, |
227 | | /// Authority Information Access - Describes how to access CA information and services |
228 | | AuthorityInfoAccess, |
229 | | /// Certificate Policies - Contains a sequence of one or more policy terms |
230 | | CertificatePolicies, |
231 | | /// Policy Mappings - Used in CA certificates to indicate that one or more policies can be considered |
232 | | /// equivalent |
233 | | PolicyMappings, |
234 | | /// Policy Constraints - Specifies constraints on path validation |
235 | | PolicyConstraints, |
236 | | /// Name Constraints - Indicates a name space within which all subject names in subsequent certificates must |
237 | | /// be located |
238 | | NameConstraints, |
239 | | /// Inhibit Any Policy - Indicates that the special anyPolicy OID is not considered an explicit match for |
240 | | /// other certificate policies |
241 | | InhibitAnyPolicy, |
242 | | /// Signed Certificate Timestamp - Contains a list of SCTs from Certificate Transparency logs |
243 | | CTPrecertificateSCTs, |
244 | | /// Subject Information Access - Describes how to access additional information about the subject |
245 | | SubjectInfoAccess, |
246 | | /// Freshest CRL - Identifies how delta CRL information is obtained |
247 | | FreshestCRL, |
248 | | /// TLS Feature - Indicates which TLS features are required for the certificate to be used |
249 | | TLSFeature, |
250 | | /// OCSP No Check - Indicates that an OCSP client should trust the certificate for OCSP signing |
251 | | OcspNoCheck, |
252 | | /// Subject Directory Attributes - Conveys identification attributes of the subject |
253 | | SubjectDirectoryAttributes, |
254 | | /// Unknown or unsupported extension type |
255 | | Unknown |
256 | | }; |
257 | | |
258 | | X509ExtensionType() = default; |
259 | | |
260 | | // cppcheck-suppress noExplicitConstructor |
261 | | /// Construct X509ExtensionType from Value enum |
262 | | /// @param[in] value the extension type enum value |
263 | | constexpr X509ExtensionType(Value value) : m_Value(value) |
264 | 0 | {} |
265 | | |
266 | | /// @return A string representation of the extension type |
267 | | std::string toString() const; |
268 | | |
269 | | /// @return The OID value of the extension |
270 | | std::string getOidValue() const; |
271 | | |
272 | | /// Creates an X509ExtensionType from an OID value |
273 | | /// @param[in] value The ASN.1 object identifier |
274 | | /// @return The corresponding X509ExtensionType value, or Unknown if no match is found |
275 | | static X509ExtensionType fromOidValue(const Asn1ObjectIdentifier& value); |
276 | | |
277 | | // Allow switch and comparisons. |
278 | | constexpr operator Value() const |
279 | 0 | { |
280 | 0 | return m_Value; |
281 | 0 | } |
282 | | explicit operator bool() const = delete; |
283 | | |
284 | | private: |
285 | | Value m_Value = Unknown; |
286 | | }; |
287 | | |
288 | | /// @class X509SerialNumber |
289 | | /// Represents the serial number of an X.509 certificate |
290 | | class X509SerialNumber |
291 | | { |
292 | | public: |
293 | | /// Constructs an X509SerialNumber from a serial number hex string |
294 | | /// @param[in] serialNumber The serial number as a hex string |
295 | | explicit X509SerialNumber(const std::string& serialNumber) : m_SerialNumber(serialNumber) |
296 | 0 | {} |
297 | | |
298 | | /// Converts the serial number to a formatted string |
299 | | /// @param[in] delimiter The delimiter to use between the bytes (default: ":") |
300 | | /// @return A formatted string representation of the serial number |
301 | | std::string toString(const std::string& delimiter = ":") const; |
302 | | |
303 | | private: |
304 | | std::string m_SerialNumber; |
305 | | }; |
306 | | |
307 | | /// @class X509Timestamp |
308 | | /// Represents a timestamp in an X.509 certificate |
309 | | class X509Timestamp |
310 | | { |
311 | | public: |
312 | | /// Constructs an X509Timestamp from an ASN.1 time record |
313 | | /// @param[in] timeRecord Pointer to the ASN.1 time record. Note: this class doesn't assume |
314 | | /// ownership over the record |
315 | | explicit X509Timestamp(Asn1TimeRecord* timeRecord) : m_Record(timeRecord) |
316 | 0 | {} |
317 | | |
318 | | /// Converts the timestamp to a formatted string |
319 | | /// @param[in] format The format string (strftime format, default: "%Y-%m-%d %H:%M:%S") |
320 | | /// @param[in] timezone The timezone to use in the format of "Z" for UTC or +=HHMM for other timezones |
321 | | /// (default: "Z" for UTC) |
322 | | /// @param[in] includeMilliseconds Whether to include milliseconds in the output |
323 | | /// @return A formatted string representation of the timestamp |
324 | | std::string toString(const std::string& format = "%Y-%m-%d %H:%M:%S", const std::string& timezone = "Z", |
325 | | bool includeMilliseconds = false) const; |
326 | | |
327 | | /// Gets the timestamp as a system_clock::time_point |
328 | | /// @param[in] timezone The timezone to use in the format of "Z" for UTC or +=HHMM for other timezones |
329 | | /// (default: "Z" for UTC) |
330 | | /// @return A time_point representing the timestamp |
331 | | std::chrono::system_clock::time_point getTimestamp(const std::string& timezone = "Z") const; |
332 | | |
333 | | private: |
334 | | Asn1TimeRecord* m_Record; |
335 | | }; |
336 | | |
337 | | /// @class X509Key |
338 | | /// Represents a key in an X.509 certificate |
339 | | class X509Key |
340 | | { |
341 | | public: |
342 | | /// Constructs an X509Key from a byte vector |
343 | | /// @param[in] key The key data as a vector of bytes |
344 | | explicit X509Key(const std::vector<uint8_t>& key) : m_Key(key) |
345 | 0 | {} |
346 | | |
347 | | /// Converts the key to a formatted string |
348 | | /// @param[in] delimiter The delimiter to use between the bytes (default: ":") |
349 | | /// @return A formatted string representation of the key |
350 | | std::string toString(const std::string& delimiter = ":") const; |
351 | | |
352 | | /// Gets the raw key bytes |
353 | | /// @return A const reference to the vector containing the key bytes |
354 | | const std::vector<uint8_t>& getBytes() const; |
355 | | |
356 | | private: |
357 | | std::vector<uint8_t> m_Key; |
358 | | }; |
359 | | |
360 | | /// @namespace X509Internal |
361 | | /// Internal implementation details for X.509 certificate parsing |
362 | | namespace X509Internal |
363 | | { |
364 | | // Forward declarations |
365 | | class X509Certificate; |
366 | | class X509TBSCertificate; |
367 | | class X509Name; |
368 | | class X509SubjectPublicKeyInfo; |
369 | | class X509Extension; |
370 | | class X509Extensions; |
371 | | |
372 | | /// @class X509Base |
373 | | /// @tparam Asn1RecordType The type of ASN.1 record this class wraps |
374 | | /// Base class for X.509 data structures that wrap ASN.1 records |
375 | | template <typename Asn1RecordType> class X509Base |
376 | | { |
377 | | protected: |
378 | 0 | explicit X509Base(Asn1RecordType* root) : m_Root(root) |
379 | 0 | {}Unexecuted instantiation: pcpp::X509Internal::X509Base<pcpp::Asn1SetRecord>::X509Base(pcpp::Asn1SetRecord*) Unexecuted instantiation: pcpp::X509Internal::X509Base<pcpp::Asn1ConstructedRecord>::X509Base(pcpp::Asn1ConstructedRecord*) Unexecuted instantiation: pcpp::X509Internal::X509Base<pcpp::Asn1SequenceRecord>::X509Base(pcpp::Asn1SequenceRecord*) |
380 | | |
381 | | Asn1RecordType* m_Root; |
382 | | }; |
383 | | |
384 | | /// @class X509VersionRecord |
385 | | /// Internal class for handling X.509 version records |
386 | | class X509VersionRecord : public X509Base<Asn1ConstructedRecord> |
387 | | { |
388 | | using X509Base::X509Base; |
389 | | friend class X509TBSCertificate; |
390 | | |
391 | | public: |
392 | | /// Gets the X.509 version from the version record |
393 | | /// @return The X.509 version |
394 | | X509Version getVersion() const; |
395 | | |
396 | | /// Checks if the given ASN.1 record is a valid version record |
397 | | /// @param[in] record The ASN.1 record to check |
398 | | /// @return true if the record is a valid version record, false otherwise |
399 | | static bool isValidVersionRecord(const Asn1Record* record); |
400 | | |
401 | | private: |
402 | | static constexpr int versionOffset = 0; |
403 | | }; |
404 | | |
405 | | /// @class X509RelativeDistinguishedName |
406 | | /// Internal class for handling X.509 Relative Distinguished Names (RDNs) |
407 | | class X509RelativeDistinguishedName : public X509Base<Asn1SetRecord> |
408 | | { |
409 | | using X509Base::X509Base; |
410 | | friend class X509Name; |
411 | | |
412 | | public: |
413 | | /// Gets the type of the RDN |
414 | | /// @return The X520DistinguishedName type of this RDN |
415 | | X520DistinguishedName getType() const; |
416 | | |
417 | | /// Gets the value of the RDN |
418 | | /// @return The string value of this RDN |
419 | | std::string getValue() const; |
420 | | |
421 | | private: |
422 | | static constexpr int typeOffset = 0; |
423 | | static constexpr int valueOffset = 1; |
424 | | |
425 | | Asn1Record* getRecord(int index) const; |
426 | | }; |
427 | | |
428 | | /// @class X509Name |
429 | | /// Internal class for handling X.509 distinguished names |
430 | | class X509Name : public X509Base<Asn1SequenceRecord> |
431 | | { |
432 | | using X509Base::X509Base; |
433 | | friend class X509TBSCertificate; |
434 | | |
435 | | public: |
436 | | /// Gets all Relative Distinguished Names (RDNs) in this name |
437 | | /// @return A vector of X509RelativeDistinguishedName objects |
438 | | std::vector<X509RelativeDistinguishedName> getRDNs() const; |
439 | | }; |
440 | | |
441 | | /// @class X509AlgorithmIdentifier |
442 | | /// Internal class for handling X.509 algorithm identifiers |
443 | | class X509AlgorithmIdentifier : public X509Base<Asn1SequenceRecord> |
444 | | { |
445 | | using X509Base::X509Base; |
446 | | friend class X509SubjectPublicKeyInfo; |
447 | | friend class X509TBSCertificate; |
448 | | friend class X509Certificate; |
449 | | |
450 | | public: |
451 | | /// Gets the algorithm represented by this identifier |
452 | | /// @return The X509Algorithm value |
453 | | X509Algorithm getAlgorithm() const; |
454 | | |
455 | | private: |
456 | | static constexpr int algorithmOffset = 0; |
457 | | }; |
458 | | |
459 | | /// @class X509Validity |
460 | | /// Internal class for handling X.509 certificate validity periods |
461 | | class X509Validity : public X509Base<Asn1SequenceRecord> |
462 | | { |
463 | | using X509Base::X509Base; |
464 | | friend class X509TBSCertificate; |
465 | | |
466 | | public: |
467 | | /// Gets the notBefore timestamp of the validity period |
468 | | /// @return The notBefore timestamp |
469 | | X509Timestamp getNotBefore() const; |
470 | | |
471 | | /// Gets the notAfter timestamp of the validity period |
472 | | /// @return The notAfter timestamp |
473 | | X509Timestamp getNotAfter() const; |
474 | | |
475 | | private: |
476 | | static constexpr int notBeforeOffset = 0; |
477 | | static constexpr int notAfterOffset = 1; |
478 | | }; |
479 | | |
480 | | /// @class X509SubjectPublicKeyInfo |
481 | | /// Internal class for handling X.509 subject public key information |
482 | | class X509SubjectPublicKeyInfo : public X509Base<Asn1SequenceRecord> |
483 | | { |
484 | | using X509Base::X509Base; |
485 | | friend class X509TBSCertificate; |
486 | | |
487 | | public: |
488 | | /// Gets the algorithm identifier for the public key |
489 | | /// @return The X509AlgorithmIdentifier for the public key |
490 | | X509AlgorithmIdentifier getAlgorithm() const; |
491 | | |
492 | | /// Gets the subject's public key |
493 | | /// @return The X509Key containing the public key |
494 | | X509Key getSubjectPublicKey() const; |
495 | | |
496 | | private: |
497 | | static constexpr int algorithmOffset = 0; |
498 | | static constexpr int subjectPublicKeyOffset = 1; |
499 | | }; |
500 | | |
501 | | /// @class X509Extension |
502 | | /// Internal class for handling X.509 extension records |
503 | | class X509Extension : public X509Base<Asn1SequenceRecord> |
504 | | { |
505 | | friend class X509Extensions; |
506 | | using X509Base::X509Base; |
507 | | |
508 | | public: |
509 | | /// Gets the type of this extension |
510 | | /// @return The X509ExtensionType of this extension |
511 | | X509ExtensionType getType() const; |
512 | | |
513 | | /// Checks if this extension is marked as critical |
514 | | /// @return true if the extension is critical, false otherwise |
515 | | bool isCritical() const; |
516 | | |
517 | | /// Gets the value of this extension |
518 | | /// @return The extension value as a string |
519 | | std::string getValue() const; |
520 | | |
521 | | private: |
522 | | static constexpr int extensionIdOffset = 0; |
523 | | |
524 | | int m_CriticalOffset = -1; |
525 | | int m_ExtensionValueOffset = 1; |
526 | | |
527 | | explicit X509Extension(Asn1SequenceRecord* root); |
528 | | }; |
529 | | |
530 | | /// @class X509Extensions |
531 | | /// Internal class for handling X.509 extensions record |
532 | | class X509Extensions : public X509Base<Asn1ConstructedRecord> |
533 | | { |
534 | | using X509Base::X509Base; |
535 | | friend class X509TBSCertificate; |
536 | | |
537 | | public: |
538 | | /// Gets all extensions in this record |
539 | | /// @return A vector of X509Extension objects |
540 | | std::vector<X509Extension> getExtensions() const; |
541 | | |
542 | | /// Checks if the given ASN.1 record is a valid extensions record |
543 | | /// @param[in] record The ASN.1 record to check |
544 | | /// @return true if the record is a valid extensions record, false otherwise |
545 | | static bool isValidExtensionsRecord(const Asn1Record* record); |
546 | | }; |
547 | | |
548 | | /// @class X509TBSCertificate |
549 | | /// Internal class for handling the To-Be-Signed (TBS) portion of an X.509 certificate |
550 | | class X509TBSCertificate : public X509Base<Asn1SequenceRecord> |
551 | | { |
552 | | using X509Base::X509Base; |
553 | | friend class X509Certificate; |
554 | | |
555 | | public: |
556 | | /// Gets the version of the TBS certificate |
557 | | /// @return The X509Version of the certificate |
558 | | X509Version getVersion() const; |
559 | | |
560 | | /// Gets the serial number of the TBS certificate |
561 | | /// @return The X509SerialNumber of the certificate |
562 | | X509SerialNumber getSerialNumber() const; |
563 | | |
564 | | /// Gets the signature algorithm of the TBS certificate |
565 | | /// @return The X509AlgorithmIdentifier for the signature |
566 | | X509AlgorithmIdentifier getSignature() const; |
567 | | |
568 | | /// Gets the issuer name from the TBS certificate |
569 | | /// @return The X509Name of the issuer |
570 | | X509Name getIssuer() const; |
571 | | |
572 | | /// Gets the validity period of the TBS certificate |
573 | | /// @return The X509Validity object containing notBefore and notAfter timestamps |
574 | | X509Validity getValidity() const; |
575 | | |
576 | | /// Gets the subject name from the TBS certificate |
577 | | /// @return The X509Name of the subject |
578 | | X509Name getSubject() const; |
579 | | |
580 | | /// Gets the subject's public key information |
581 | | /// @return The X509SubjectPublicKeyInfo containing the public key |
582 | | X509SubjectPublicKeyInfo getSubjectPublicKeyInfo() const; |
583 | | |
584 | | /// Gets the extensions from the TBS certificate |
585 | | /// @return A unique_ptr to X509Extensions, or nullptr if no extensions are present |
586 | | std::unique_ptr<X509Extensions> getExtensions() const; |
587 | | |
588 | | private: |
589 | | int m_VersionOffset = -1; |
590 | | int m_SerialNumberOffset = 0; |
591 | | int m_SignatureOffset = 1; |
592 | | int m_IssuerOffset = 2; |
593 | | int m_ValidityOffset = 3; |
594 | | int m_SubjectOffset = 4; |
595 | | int m_SubjectPublicKeyInfoOffset = 5; |
596 | | int m_IssuerUniqueID = -1; |
597 | | int m_SubjectUniqueID = -1; |
598 | | int m_ExtensionsOffset = -1; |
599 | | |
600 | | explicit X509TBSCertificate(Asn1SequenceRecord* root); |
601 | | }; |
602 | | |
603 | | /// @class X509Certificate |
604 | | /// Internal class for handling X.509 certificate parsing and encoding |
605 | | class X509Certificate |
606 | | { |
607 | | public: |
608 | | /// Gets the TBS (To Be Signed) portion of the certificate |
609 | | /// @return The X509TBSCertificate containing the TBS data |
610 | | X509TBSCertificate getTbsCertificate() const; |
611 | | |
612 | | /// Gets the signature algorithm used to sign the certificate |
613 | | /// @return The X509AlgorithmIdentifier for the signature |
614 | | X509AlgorithmIdentifier getSignatureAlgorithm() const; |
615 | | |
616 | | /// Gets the signature value from the certificate |
617 | | /// @return The X509Key containing the signature |
618 | | X509Key getSignature() const; |
619 | | |
620 | | /// Gets the root ASN.1 record of the certificate |
621 | | /// @return Pointer to the root ASN.1 sequence record |
622 | | Asn1SequenceRecord* getAsn1Root() const; |
623 | | |
624 | | /// Decodes an X.509 certificate from binary data |
625 | | /// @param[in] data Pointer to the binary certificate data |
626 | | /// @param[in] dataLen Length of the binary data |
627 | | /// @return A unique_ptr to the decoded X509Certificate, or nullptr on failure |
628 | | static std::unique_ptr<X509Certificate> decode(const uint8_t* data, size_t dataLen); |
629 | | |
630 | | /// Encodes the certificate to binary DER format |
631 | | /// @return A vector containing the DER-encoded certificate |
632 | | std::vector<uint8_t> encode(); |
633 | | |
634 | | private: |
635 | | static constexpr int tbsCertificateOffset = 0; |
636 | | static constexpr int signatureAlgorithmOffset = 1; |
637 | | static constexpr int signatureOffset = 2; |
638 | | |
639 | | explicit X509Certificate(std::unique_ptr<Asn1Record> root) : m_Root(std::move(root)) |
640 | 0 | {} |
641 | | |
642 | | std::unique_ptr<Asn1Record> m_Root; |
643 | | }; |
644 | | } // namespace X509Internal |
645 | | |
646 | | // Forward declarations |
647 | | class X509Certificate; |
648 | | |
649 | | /// @class X509Name |
650 | | /// Represents a name in an X.509 certificate |
651 | | class X509Name |
652 | | { |
653 | | friend class X509Certificate; |
654 | | |
655 | | public: |
656 | | /// @struct RDN |
657 | | /// Represents a Relative Distinguished Name (RDN) in an X.509 certificate |
658 | | struct RDN |
659 | | { |
660 | | X520DistinguishedName type; ///< The type of the distinguished name |
661 | | std::string value; ///< The value of the distinguished name |
662 | | |
663 | | /// Equality comparison operator |
664 | | bool operator==(const RDN& other) const |
665 | 0 | { |
666 | 0 | return type == other.type && value == other.value; |
667 | 0 | } |
668 | | |
669 | | /// Inequality comparison operator |
670 | | bool operator!=(const RDN& other) const |
671 | 0 | { |
672 | 0 | return !(*this == other); |
673 | 0 | } |
674 | | |
675 | | /// Stream output operator for RDN |
676 | | friend std::ostream& operator<<(std::ostream& os, const RDN& rdn) |
677 | 0 | { |
678 | 0 | os << "RDN{type=" << rdn.type.getShortName() << ", value=" << rdn.value << "}"; |
679 | 0 | return os; |
680 | 0 | } |
681 | | }; |
682 | | |
683 | | /// Converts the X509Name to a string representation, e.g C=US, ST=California, CN=example.com |
684 | | /// @param[in] delimiter The delimiter to use between RDNs (default: ", ") |
685 | | /// @return A string representation of the X509Name |
686 | | std::string toString(const std::string& delimiter = ", ") const; |
687 | | |
688 | | /// Gets the list of Relative Distinguished Names (RDNs) |
689 | | /// @return A vector of RDN objects |
690 | | const std::vector<RDN>& getRDNs() const |
691 | 0 | { |
692 | 0 | return m_RDNs; |
693 | 0 | } |
694 | | |
695 | | private: |
696 | | explicit X509Name(const X509Internal::X509Name& internalName); |
697 | | std::vector<RDN> m_RDNs; |
698 | | }; |
699 | | |
700 | | /// @class X509Extension |
701 | | /// Represents an X.509 extension |
702 | | class X509Extension |
703 | | { |
704 | | friend class X509Certificate; |
705 | | |
706 | | public: |
707 | | /// Gets the type of this X.509 extension |
708 | | /// @return The X509ExtensionType representing the extension type |
709 | | X509ExtensionType getType() const |
710 | 0 | { |
711 | 0 | return m_Type; |
712 | 0 | } |
713 | | |
714 | | /// Checks if this extension is marked as critical |
715 | | /// @return true if the extension is critical, false otherwise |
716 | | bool isCritical() const |
717 | 0 | { |
718 | 0 | return m_IsCritical; |
719 | 0 | } |
720 | | |
721 | | /// Gets the extension parsed data |
722 | | /// @return A unique_ptr to an object containing the parsed extension data if such class exists |
723 | | /// (not all extensions have parsed data classes), or nullptr if it doesn't |
724 | | std::unique_ptr<X509ExtensionData> getData() const; |
725 | | |
726 | | /// Gets the extension data as a hex string |
727 | | /// @return A string containing the extension data in hex format |
728 | | std::string getRawDataAsHexString() const |
729 | 0 | { |
730 | 0 | return m_Data; |
731 | 0 | } |
732 | | |
733 | | private: |
734 | | explicit X509Extension(const X509Internal::X509Extension& internalExtension); |
735 | | |
736 | | bool m_IsCritical; |
737 | | X509ExtensionType m_Type; |
738 | | std::string m_Data; |
739 | | }; |
740 | | |
741 | | /// @class X509Certificate |
742 | | /// Represents an X.509 certificate |
743 | | class X509Certificate : public internal::CryptoDataReader<X509Certificate> |
744 | | { |
745 | | public: |
746 | | /// Gets the version of the certificate |
747 | | /// @return The X509Version of the certificate |
748 | | X509Version getVersion() const; |
749 | | |
750 | | /// Gets the serial number of the certificate |
751 | | /// @return The certificate's serial number |
752 | | X509SerialNumber getSerialNumber() const; |
753 | | |
754 | | /// Gets the issuer of the certificate |
755 | | /// @return The certificate's issuer name |
756 | | X509Name getIssuer() const; |
757 | | |
758 | | /// Gets the subject of the certificate |
759 | | /// @return The certificate's subject name |
760 | | X509Name getSubject() const; |
761 | | |
762 | | /// Gets the notBefore timestamp of the certificate's validity period |
763 | | /// @return The notBefore timestamp |
764 | | X509Timestamp getNotBefore() const; |
765 | | |
766 | | /// Gets the notAfter timestamp of the certificate's validity period |
767 | | /// @return The notAfter timestamp |
768 | | X509Timestamp getNotAfter() const; |
769 | | |
770 | | /// Gets the public key algorithm used in the certificate |
771 | | /// @return The public key algorithm |
772 | | X509Algorithm getPublicKeyAlgorithm() const; |
773 | | |
774 | | /// Gets the public key from the certificate |
775 | | /// @return The public key |
776 | | X509Key getPublicKey() const; |
777 | | |
778 | | /// Gets the signature algorithm used to sign the certificate |
779 | | /// @return The signature algorithm |
780 | | X509Algorithm getSignatureAlgorithm() const; |
781 | | |
782 | | /// Gets the signature of the certificate |
783 | | /// @return The certificate's signature |
784 | | X509Key getSignature() const; |
785 | | |
786 | | /// Gets the list of extensions in the certificate |
787 | | /// @return A vector containing the certificate's extensions |
788 | | const std::vector<X509Extension>& getExtensions() const; |
789 | | |
790 | | /// Checks if the certificate has a specific extension |
791 | | /// @param[in] extensionType The extension type to check for |
792 | | /// @return true if the extension is present, false otherwise |
793 | | bool hasExtension(const X509ExtensionType& extensionType) const; |
794 | | |
795 | | /// Gets an extension by its type |
796 | | /// @param[in] extensionType The type of extension to get |
797 | | /// @return Pointer to the extension if found or nullptr otherwise |
798 | | const X509Extension* getExtension(X509ExtensionType extensionType) const; |
799 | | |
800 | | /// Converts the certificate to DER-encoded format |
801 | | /// @return A byte vector containing the DER-encoded data |
802 | | std::vector<uint8_t> toDER() const; |
803 | | |
804 | | /// Converts the certificate to PEM-encoded format |
805 | | /// @return A string containing the PEM-encoded data |
806 | | std::string toPEM() const; |
807 | | |
808 | | /// Converts the certificate to a JSON string representation |
809 | | /// @param[in] indent Number of spaces to use for indentation (-1 for no pretty printing) |
810 | | /// @return A JSON string representation of the certificate |
811 | | std::string toJson(int indent = -1) const; |
812 | | |
813 | | /// Gets the raw internal certificate object |
814 | | /// @return Pointer to the internal X509Certificate implementation |
815 | | const X509Internal::X509Certificate* getRawCertificate() const; |
816 | | |
817 | | // Prevent copying |
818 | | X509Certificate(const X509Certificate&) = delete; |
819 | | X509Certificate& operator=(const X509Certificate&) = delete; |
820 | | |
821 | | private: |
822 | | // Constructor/Destructor |
823 | | X509Certificate(uint8_t* derData, size_t derDataLen, bool ownDerData); |
824 | | X509Certificate(std::unique_ptr<uint8_t[]> derData, size_t derDataLen); |
825 | | |
826 | | friend class internal::CryptoDataReader<X509Certificate>; |
827 | | |
828 | | std::unique_ptr<X509Internal::X509Certificate> m_X509Internal; |
829 | | X509Internal::X509TBSCertificate m_TBSCertificate; |
830 | | mutable std::vector<X509Extension> m_Extensions; |
831 | | mutable bool m_ExtensionsParsed = false; |
832 | | std::unique_ptr<uint8_t[]> m_DerData; |
833 | | |
834 | | static constexpr const char* pemLabel = "CERTIFICATE"; |
835 | | }; |
836 | | } // namespace pcpp |