Coverage Report

Created: 2026-08-31 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/X509ExtensionDataDecoder.cpp
Line
Count
Source
1
#include "X509ExtensionDataDecoder.h"
2
#include "GeneralUtils.h"
3
#include <unordered_map>
4
5
namespace pcpp
6
{
7
  std::string X509ExtendedKeyUsagePurpose::toString() const
8
0
  {
9
0
    switch (m_Value)
10
0
    {
11
0
    case ServerAuth:
12
0
      return "ServerAuth";
13
0
    case ClientAuth:
14
0
      return "ClientAuth";
15
0
    case CodeSigning:
16
0
      return "CodeSigning";
17
0
    case EmailProtection:
18
0
      return "EmailProtection";
19
0
    case TimeStamping:
20
0
      return "TimeStamping";
21
0
    case OCSPSigning:
22
0
      return "OCSPSigning";
23
0
    case IPSecEndSystem:
24
0
      return "IPSecEndSystem";
25
0
    case IPSecTunnel:
26
0
      return "IPSecTunnel";
27
0
    case IPSecUser:
28
0
      return "IPSecUser";
29
0
    case AnyExtendedKeyUsage:
30
0
      return "AnyExtendedKeyUsage";
31
0
    case SmartCardLogon:
32
0
      return "SmartCardLogon";
33
0
    case EncryptedFileSystem:
34
0
      return "EncryptedFileSystem";
35
0
    case DocumentSigning:
36
0
      return "DocumentSigning";
37
0
    default:
38
0
      return "Unknown";
39
0
    }
40
0
  }
41
42
  std::string X509ExtendedKeyUsagePurpose::getOidValue() const
43
0
  {
44
0
    switch (m_Value)
45
0
    {
46
0
    case ServerAuth:
47
0
      return "1.3.6.1.5.5.7.3.1";
48
0
    case ClientAuth:
49
0
      return "1.3.6.1.5.5.7.3.2";
50
0
    case CodeSigning:
51
0
      return "1.3.6.1.5.5.7.3.3";
52
0
    case EmailProtection:
53
0
      return "1.3.6.1.5.5.7.3.4";
54
0
    case TimeStamping:
55
0
      return "1.3.6.1.5.5.7.3.8";
56
0
    case OCSPSigning:
57
0
      return "1.3.6.1.5.5.7.3.9";
58
0
    case IPSecEndSystem:
59
0
      return "1.3.6.1.5.5.7.3.5";
60
0
    case IPSecTunnel:
61
0
      return "1.3.6.1.5.5.7.3.6";
62
0
    case IPSecUser:
63
0
      return "1.3.6.1.5.5.7.3.7";
64
0
    case AnyExtendedKeyUsage:
65
0
      return "2.5.29.37.0";
66
0
    case SmartCardLogon:
67
0
      return "1.3.6.1.4.1.311.20.2.2";
68
0
    case EncryptedFileSystem:
69
0
      return "1.3.6.1.4.1.311.10.3.4";
70
0
    case DocumentSigning:
71
0
      return "1.3.6.1.4.1.311.10.3.12";
72
0
    default:
73
0
      return "0.0";
74
0
    }
75
0
  }
76
77
  static const std::unordered_map<std::string, X509ExtendedKeyUsagePurpose::Value>
78
      X509ExtendedKeyUsagePurposeOidMap = {
79
        { "1.3.6.1.5.5.7.3.1",       X509ExtendedKeyUsagePurpose::ServerAuth          },
80
        { "1.3.6.1.5.5.7.3.2",       X509ExtendedKeyUsagePurpose::ClientAuth          },
81
        { "1.3.6.1.5.5.7.3.3",       X509ExtendedKeyUsagePurpose::CodeSigning         },
82
        { "1.3.6.1.5.5.7.3.4",       X509ExtendedKeyUsagePurpose::EmailProtection     },
83
        { "1.3.6.1.5.5.7.3.8",       X509ExtendedKeyUsagePurpose::TimeStamping        },
84
        { "1.3.6.1.5.5.7.3.9",       X509ExtendedKeyUsagePurpose::OCSPSigning         },
85
        { "1.3.6.1.5.5.7.3.5",       X509ExtendedKeyUsagePurpose::IPSecEndSystem      },
86
        { "1.3.6.1.5.5.7.3.6",       X509ExtendedKeyUsagePurpose::IPSecTunnel         },
87
        { "1.3.6.1.5.5.7.3.7",       X509ExtendedKeyUsagePurpose::IPSecUser           },
88
        { "2.5.29.37.0",             X509ExtendedKeyUsagePurpose::AnyExtendedKeyUsage },
89
        { "1.3.6.1.4.1.311.20.2.2",  X509ExtendedKeyUsagePurpose::SmartCardLogon      },
90
        { "1.3.6.1.4.1.311.10.3.4",  X509ExtendedKeyUsagePurpose::EncryptedFileSystem },
91
        { "1.3.6.1.4.1.311.10.3.12", X509ExtendedKeyUsagePurpose::DocumentSigning     },
92
        { "0.0",                 X509ExtendedKeyUsagePurpose::Unknown             },
93
    };
94
95
  X509ExtendedKeyUsagePurpose X509ExtendedKeyUsagePurpose::fromOidValue(const Asn1ObjectIdentifier& value)
96
0
  {
97
0
    auto it = X509ExtendedKeyUsagePurposeOidMap.find(value.toString());
98
0
    if (it != X509ExtendedKeyUsagePurposeOidMap.end())
99
0
    {
100
0
      return { it->second };
101
0
    }
102
103
0
    return { Unknown };
104
0
  }
105
106
  template <class Asn1RecordType>
107
  static Asn1RecordType* castRecordAs(Asn1Record* record, const std::string& extensionName,
108
                                      const std::string& fieldName)
109
0
  {
110
0
    try
111
0
    {
112
0
      return record->castAs<Asn1RecordType>();
113
0
    }
114
0
    catch (const std::bad_cast&)
115
0
    {
116
0
      throw std::runtime_error("Invalid X509 certificate " + extensionName + " extension data: " + fieldName);
117
0
    }
118
0
  }
Unexecuted instantiation: X509ExtensionDataDecoder.cpp:pcpp::Asn1SequenceRecord* pcpp::castRecordAs<pcpp::Asn1SequenceRecord>(pcpp::Asn1Record*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: X509ExtensionDataDecoder.cpp:pcpp::Asn1BooleanRecord* pcpp::castRecordAs<pcpp::Asn1BooleanRecord>(pcpp::Asn1Record*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: X509ExtensionDataDecoder.cpp:pcpp::Asn1IntegerRecord* pcpp::castRecordAs<pcpp::Asn1IntegerRecord>(pcpp::Asn1Record*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: X509ExtensionDataDecoder.cpp:pcpp::Asn1OctetStringRecord* pcpp::castRecordAs<pcpp::Asn1OctetStringRecord>(pcpp::Asn1Record*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: X509ExtensionDataDecoder.cpp:pcpp::Asn1BitStringRecord* pcpp::castRecordAs<pcpp::Asn1BitStringRecord>(pcpp::Asn1Record*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
119
120
  template <class Asn1RecordType>
121
  static Asn1RecordType* getSubRecordAndCast(Asn1ConstructedRecord* record, int index,
122
                                             const std::string& extensionName, const std::string& fieldName)
123
0
  {
124
0
    try
125
0
    {
126
0
      return castRecordAs<Asn1RecordType>(record->getSubRecords().at(index), extensionName, fieldName);
127
0
    }
128
0
    catch (const std::out_of_range&)
129
0
    {
130
0
      throw std::runtime_error("Invalid X509 certificate " + extensionName + " extension data: " + fieldName);
131
0
    }
132
0
  }
Unexecuted instantiation: X509ExtensionDataDecoder.cpp:pcpp::Asn1BooleanRecord* pcpp::getSubRecordAndCast<pcpp::Asn1BooleanRecord>(pcpp::Asn1ConstructedRecord*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: X509ExtensionDataDecoder.cpp:pcpp::Asn1IntegerRecord* pcpp::getSubRecordAndCast<pcpp::Asn1IntegerRecord>(pcpp::Asn1ConstructedRecord*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
133
134
  namespace X509Internal
135
  {
136
    std::unique_ptr<Asn1Record> X509ExtensionDataDecoder::decodeAsn1Data(const std::string& rawData,
137
                                                                         std::vector<uint8_t>& rawDataBytes)
138
0
    {
139
0
      rawDataBytes.resize(rawData.length() / 2);
140
      // A malformed hex string may decode into fewer bytes than the buffer size
141
0
      rawDataBytes.resize(hexStringToByteArray(rawData, rawDataBytes.data(), rawDataBytes.size()));
142
0
      return Asn1Record::decode(rawDataBytes.data(), rawDataBytes.size());
143
0
    }
144
145
    std::unique_ptr<X509BasicConstraintsDataDecoder> X509BasicConstraintsDataDecoder::create(
146
        const std::string& rawData)
147
0
    {
148
0
      std::vector<uint8_t> rawDataBytes;
149
0
      auto record = decodeAsn1Data(rawData, rawDataBytes);
150
0
      auto basicConstraintsRecord = castRecordAs<Asn1SequenceRecord>(record.get(), "Basic Constraints", "Value");
151
0
      bool isCA = false;
152
0
      uint8_t pathLenConstraint = 0;
153
0
      if (basicConstraintsRecord->getSubRecords().size() > isCAOffset)
154
0
      {
155
0
        isCA = getSubRecordAndCast<Asn1BooleanRecord>(basicConstraintsRecord, isCAOffset, "Basic Constraints",
156
0
                                                      "Is CA")
157
0
                   ->getValue();
158
0
      }
159
0
      if (basicConstraintsRecord->getSubRecords().size() > pathLenConstraintOffset)
160
0
      {
161
0
        pathLenConstraint =
162
0
            getSubRecordAndCast<Asn1IntegerRecord>(basicConstraintsRecord, pathLenConstraintOffset,
163
0
                                                   "Basic Constraints", "Path Length Constraint")
164
0
                ->getIntValue<uint8_t>();
165
0
      }
166
167
0
      return std::unique_ptr<X509BasicConstraintsDataDecoder>(
168
0
          new X509BasicConstraintsDataDecoder(isCA, pathLenConstraint));
169
0
    }
170
171
    std::unique_ptr<X509SubjectKeyIdentifierDataDecoder> X509SubjectKeyIdentifierDataDecoder::create(
172
        const std::string& rawData)
173
0
    {
174
0
      std::vector<uint8_t> rawDataBytes;
175
0
      auto record = decodeAsn1Data(rawData, rawDataBytes);
176
0
      auto keyIdentifier =
177
0
          castRecordAs<Asn1OctetStringRecord>(record.get(), "Subject Key Identifier", "Key Identifier")
178
0
              ->getValue();
179
0
      return std::unique_ptr<X509SubjectKeyIdentifierDataDecoder>(
180
0
          new X509SubjectKeyIdentifierDataDecoder(keyIdentifier));
181
0
    }
182
183
    std::unique_ptr<X509KeyUsageDataDecoder> X509KeyUsageDataDecoder::create(const std::string& rawData)
184
0
    {
185
0
      std::vector<uint8_t> rawDataBytes;
186
0
      auto record = decodeAsn1Data(rawData, rawDataBytes);
187
0
      auto keyUsage = castRecordAs<Asn1BitStringRecord>(record.get(), "Key Usage", "Key Usage")->getValue();
188
0
      return std::unique_ptr<X509KeyUsageDataDecoder>(new X509KeyUsageDataDecoder(keyUsage));
189
0
    }
190
191
    std::unique_ptr<X509ExtendedKeyUsageDataDecoder> X509ExtendedKeyUsageDataDecoder::create(
192
        const std::string& rawData)
193
0
    {
194
0
      std::vector<uint8_t> rawDataBytes;
195
0
      auto record = decodeAsn1Data(rawData, rawDataBytes);
196
0
      auto extendedKeyUsageRecord =
197
0
          castRecordAs<Asn1SequenceRecord>(record.get(), "Extended Key Usage", "Purposes List");
198
0
      auto result = std::unique_ptr<X509ExtendedKeyUsageDataDecoder>(new X509ExtendedKeyUsageDataDecoder());
199
0
      for (const auto& subRecord : extendedKeyUsageRecord->getSubRecords())
200
0
      {
201
0
        result->m_ExtendedKeyUsagePurposes.push_back(
202
0
            subRecord->castAs<Asn1ObjectIdentifierRecord>()->getValue());
203
0
      }
204
205
0
      return result;
206
0
    }
207
  }  // namespace X509Internal
208
209
  X509BasicConstraintsExtension::X509BasicConstraintsExtension(const std::string& rawExtensionData)
210
0
  {
211
0
    auto dataDecoder = X509Internal::X509BasicConstraintsDataDecoder::create(rawExtensionData);
212
0
    m_IsCA = dataDecoder->isCA();
213
0
    m_PathLenConstraint = dataDecoder->getPathLenConstraint();
214
0
  }
215
216
  X509SubjectKeyIdentifierExtension::X509SubjectKeyIdentifierExtension(const std::string& rawExtensionData)
217
0
  {
218
0
    auto dataDecoder = X509Internal::X509SubjectKeyIdentifierDataDecoder::create(rawExtensionData);
219
0
    m_KeyIdentifier = dataDecoder->getKeyIdentifier();
220
0
  }
221
222
  X509KeyUsageExtension::X509KeyUsageExtension(const std::string& rawExtensionData)
223
0
  {
224
0
    auto dataDecoder = X509Internal::X509KeyUsageDataDecoder::create(rawExtensionData);
225
0
    m_BitString = dataDecoder->getKeyUsage();
226
0
  }
227
228
  bool X509KeyUsageExtension::isBitSet(size_t location) const
229
0
  {
230
0
    if (m_BitString.size() < location + 1)
231
0
    {
232
0
      return false;
233
0
    }
234
235
0
    return m_BitString[m_BitString.size() - 1 - location] == '1';
236
0
  }
237
238
  bool X509KeyUsageExtension::isDigitalSignature() const
239
0
  {
240
0
    return isBitSet(digitalSignatureLocation);
241
0
  }
242
243
  bool X509KeyUsageExtension::isNonRepudiation() const
244
0
  {
245
0
    return isBitSet(nonRepudiationLocation);
246
0
  }
247
248
  bool X509KeyUsageExtension::isKeyEncipherment() const
249
0
  {
250
0
    return isBitSet(keyEnciphermentLocation);
251
0
  }
252
253
  bool X509KeyUsageExtension::isDataEncipherment() const
254
0
  {
255
0
    return isBitSet(dataEnciphermentLocation);
256
0
  }
257
258
  bool X509KeyUsageExtension::isKeyAgreement() const
259
0
  {
260
0
    return isBitSet(keyAgreementLocation);
261
0
  }
262
263
  bool X509KeyUsageExtension::isKeyCertSign() const
264
0
  {
265
0
    return isBitSet(keyCertSignLocation);
266
0
  }
267
268
  bool X509KeyUsageExtension::isCRLSign() const
269
0
  {
270
0
    return isBitSet(crlSignLocation);
271
0
  }
272
273
  bool X509KeyUsageExtension::isEncipherOnly() const
274
0
  {
275
0
    return isBitSet(encipherOnlyLocation);
276
0
  }
277
278
  bool X509KeyUsageExtension::isDecipherOnly() const
279
0
  {
280
0
    return isBitSet(decipherOnlyLocation);
281
0
  }
282
283
  X509ExtendedKeyUsageExtension::X509ExtendedKeyUsageExtension(const std::string& rawExtensionData)
284
0
  {
285
0
    auto dataDecoder = X509Internal::X509ExtendedKeyUsageDataDecoder::create(rawExtensionData);
286
0
    for (const auto& purpose : dataDecoder->getExtendedKeyUsagePurposes())
287
0
    {
288
0
      m_Purposes.push_back(X509ExtendedKeyUsagePurpose::fromOidValue(purpose));
289
0
    }
290
0
  }
291
}  // namespace pcpp