Coverage Report

Created: 2025-08-26 07:54

/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