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