Coverage Report

Created: 2025-09-27 08:03

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
0
      hexStringToByteArray(rawData, rawDataBytes.data(), rawData.length() / 2);
141
0
      return Asn1Record::decode(rawDataBytes.data(), rawData.size());
142
0
    }
143
144
    std::unique_ptr<X509BasicConstraintsDataDecoder> X509BasicConstraintsDataDecoder::create(
145
        const std::string& rawData)
146
0
    {
147
0
      std::vector<uint8_t> rawDataBytes;
148
0
      auto record = decodeAsn1Data(rawData, rawDataBytes);
149
0
      auto basicConstraintsRecord = castRecordAs<Asn1SequenceRecord>(record.get(), "Basic Constraints", "Value");
150
0
      bool isCA = false;
151
0
      uint8_t pathLenConstraint = 0;
152
0
      if (basicConstraintsRecord->getSubRecords().size() > isCAOffset)
153
0
      {
154
0
        isCA = getSubRecordAndCast<Asn1BooleanRecord>(basicConstraintsRecord, isCAOffset, "Basic Constraints",
155
0
                                                      "Is CA")
156
0
                   ->getValue();
157
0
      }
158
0
      if (basicConstraintsRecord->getSubRecords().size() > pathLenConstraintOffset)
159
0
      {
160
0
        pathLenConstraint =
161
0
            getSubRecordAndCast<Asn1IntegerRecord>(basicConstraintsRecord, pathLenConstraintOffset,
162
0
                                                   "Basic Constraints", "Path Length Constraint")
163
0
                ->getIntValue<uint8_t>();
164
0
      }
165
166
0
      return std::unique_ptr<X509BasicConstraintsDataDecoder>(
167
0
          new X509BasicConstraintsDataDecoder(isCA, pathLenConstraint));
168
0
    }
169
170
    std::unique_ptr<X509SubjectKeyIdentifierDataDecoder> X509SubjectKeyIdentifierDataDecoder::create(
171
        const std::string& rawData)
172
0
    {
173
0
      std::vector<uint8_t> rawDataBytes;
174
0
      auto record = decodeAsn1Data(rawData, rawDataBytes);
175
0
      auto keyIdentifier =
176
0
          castRecordAs<Asn1OctetStringRecord>(record.get(), "Subject Key Identifier", "Key Identifier")
177
0
              ->getValue();
178
0
      return std::unique_ptr<X509SubjectKeyIdentifierDataDecoder>(
179
0
          new X509SubjectKeyIdentifierDataDecoder(keyIdentifier));
180
0
    }
181
182
    std::unique_ptr<X509KeyUsageDataDecoder> X509KeyUsageDataDecoder::create(const std::string& rawData)
183
0
    {
184
0
      std::vector<uint8_t> rawDataBytes;
185
0
      auto record = decodeAsn1Data(rawData, rawDataBytes);
186
0
      auto keyUsage = castRecordAs<Asn1BitStringRecord>(record.get(), "Key Usage", "Key Usage")->getValue();
187
0
      return std::unique_ptr<X509KeyUsageDataDecoder>(new X509KeyUsageDataDecoder(keyUsage));
188
0
    }
189
190
    std::unique_ptr<X509ExtendedKeyUsageDataDecoder> X509ExtendedKeyUsageDataDecoder::create(
191
        const std::string& rawData)
192
0
    {
193
0
      std::vector<uint8_t> rawDataBytes;
194
0
      auto record = decodeAsn1Data(rawData, rawDataBytes);
195
0
      auto extendedKeyUsageRecord =
196
0
          castRecordAs<Asn1SequenceRecord>(record.get(), "Extended Key Usage", "Purposes List");
197
0
      auto result = std::unique_ptr<X509ExtendedKeyUsageDataDecoder>(new X509ExtendedKeyUsageDataDecoder());
198
0
      for (const auto& subRecord : extendedKeyUsageRecord->getSubRecords())
199
0
      {
200
0
        result->m_ExtendedKeyUsagePurposes.push_back(
201
0
            subRecord->castAs<Asn1ObjectIdentifierRecord>()->getValue());
202
0
      }
203
204
0
      return result;
205
0
    }
206
  }  // namespace X509Internal
207
208
  X509BasicConstraintsExtension::X509BasicConstraintsExtension(const std::string& rawExtensionData)
209
0
  {
210
0
    auto dataDecoder = X509Internal::X509BasicConstraintsDataDecoder::create(rawExtensionData);
211
0
    m_IsCA = dataDecoder->isCA();
212
0
    m_PathLenConstraint = dataDecoder->getPathLenConstraint();
213
0
  }
214
215
  X509SubjectKeyIdentifierExtension::X509SubjectKeyIdentifierExtension(const std::string& rawExtensionData)
216
0
  {
217
0
    auto dataDecoder = X509Internal::X509SubjectKeyIdentifierDataDecoder::create(rawExtensionData);
218
0
    m_KeyIdentifier = dataDecoder->getKeyIdentifier();
219
0
  }
220
221
  X509KeyUsageExtension::X509KeyUsageExtension(const std::string& rawExtensionData)
222
0
  {
223
0
    auto dataDecoder = X509Internal::X509KeyUsageDataDecoder::create(rawExtensionData);
224
0
    m_BitString = dataDecoder->getKeyUsage();
225
0
  }
226
227
  bool X509KeyUsageExtension::isBitSet(size_t location) const
228
0
  {
229
0
    if (m_BitString.size() < location + 1)
230
0
    {
231
0
      return false;
232
0
    }
233
234
0
    return m_BitString[m_BitString.size() - 1 - location] == '1';
235
0
  }
236
237
  bool X509KeyUsageExtension::isDigitalSignature() const
238
0
  {
239
0
    return isBitSet(digitalSignatureLocation);
240
0
  }
241
242
  bool X509KeyUsageExtension::isNonRepudiation() const
243
0
  {
244
0
    return isBitSet(nonRepudiationLocation);
245
0
  }
246
247
  bool X509KeyUsageExtension::isKeyEncipherment() const
248
0
  {
249
0
    return isBitSet(keyEnciphermentLocation);
250
0
  }
251
252
  bool X509KeyUsageExtension::isDataEncipherment() const
253
0
  {
254
0
    return isBitSet(dataEnciphermentLocation);
255
0
  }
256
257
  bool X509KeyUsageExtension::isKeyAgreement() const
258
0
  {
259
0
    return isBitSet(keyAgreementLocation);
260
0
  }
261
262
  bool X509KeyUsageExtension::isKeyCertSign() const
263
0
  {
264
0
    return isBitSet(keyCertSignLocation);
265
0
  }
266
267
  bool X509KeyUsageExtension::isCRLSign() const
268
0
  {
269
0
    return isBitSet(crlSignLocation);
270
0
  }
271
272
  bool X509KeyUsageExtension::isEncipherOnly() const
273
0
  {
274
0
    return isBitSet(encipherOnlyLocation);
275
0
  }
276
277
  bool X509KeyUsageExtension::isDecipherOnly() const
278
0
  {
279
0
    return isBitSet(decipherOnlyLocation);
280
0
  }
281
282
  X509ExtendedKeyUsageExtension::X509ExtendedKeyUsageExtension(const std::string& rawExtensionData)
283
0
  {
284
0
    auto dataDecoder = X509Internal::X509ExtendedKeyUsageDataDecoder::create(rawExtensionData);
285
0
    for (const auto& purpose : dataDecoder->getExtendedKeyUsagePurposes())
286
0
    {
287
0
      m_Purposes.push_back(X509ExtendedKeyUsagePurpose::fromOidValue(purpose));
288
0
    }
289
0
  }
290
}  // namespace pcpp