1
#include "source/common/tls/utility.h"
2

            
3
#include <fmt/format.h>
4
#include <fmt/ranges.h>
5

            
6
#include <cstdint>
7
#include <vector>
8

            
9
#include "source/common/common/assert.h"
10
#include "source/common/common/empty_string.h"
11
#include "source/common/common/safe_memcpy.h"
12
#include "source/common/network/address_impl.h"
13
#include "source/common/protobuf/utility.h"
14

            
15
#include "absl/strings/str_join.h"
16
#include "openssl/x509v3.h"
17

            
18
namespace Envoy {
19
namespace Extensions {
20
namespace TransportSockets {
21
namespace Tls {
22

            
23
static constexpr int MAX_OID_LENGTH = 256;
24

            
25
static constexpr absl::string_view SSL_ERROR_UNKNOWN_ERROR_MESSAGE = "UNKNOWN_ERROR";
26

            
27
Envoy::Ssl::CertificateDetailsPtr Utility::certificateDetails(X509* cert, const std::string& path,
28
12
                                                              TimeSource& time_source) {
29
12
  Envoy::Ssl::CertificateDetailsPtr certificate_details =
30
12
      std::make_unique<envoy::admin::v3::CertificateDetails>();
31
12
  certificate_details->set_path(path);
32
12
  certificate_details->set_serial_number(Utility::getSerialNumberFromCertificate(*cert));
33
12
  const auto days_until_expiry = Utility::getDaysUntilExpiration(cert, time_source).value_or(0);
34
12
  certificate_details->set_days_until_expiration(days_until_expiry);
35

            
36
12
  Protobuf::Timestamp* valid_from = certificate_details->mutable_valid_from();
37
12
  TimestampUtil::systemClockToTimestamp(Utility::getValidFrom(*cert), *valid_from);
38
12
  Protobuf::Timestamp* expiration_time = certificate_details->mutable_expiration_time();
39
12
  TimestampUtil::systemClockToTimestamp(Utility::getExpirationTime(*cert), *expiration_time);
40

            
41
12
  for (auto& dns_san : Utility::getSubjectAltNames(*cert, GEN_DNS)) {
42
6
    envoy::admin::v3::SubjectAlternateName& subject_alt_name =
43
6
        *certificate_details->add_subject_alt_names();
44
6
    subject_alt_name.set_dns(dns_san);
45
6
  }
46
12
  for (auto& uri_san : Utility::getSubjectAltNames(*cert, GEN_URI)) {
47
3
    envoy::admin::v3::SubjectAlternateName& subject_alt_name =
48
3
        *certificate_details->add_subject_alt_names();
49
3
    subject_alt_name.set_uri(uri_san);
50
3
  }
51
12
  for (auto& ip_san : Utility::getSubjectAltNames(*cert, GEN_IPADD)) {
52
2
    envoy::admin::v3::SubjectAlternateName& subject_alt_name =
53
2
        *certificate_details->add_subject_alt_names();
54
2
    subject_alt_name.set_ip_address(ip_san);
55
2
  }
56
12
  return certificate_details;
57
12
}
58

            
59
939
bool Utility::labelWildcardMatch(absl::string_view dns_label, absl::string_view pattern) {
60
939
  constexpr char glob = '*';
61
  // Check the special case of a single * pattern, as it's common.
62
939
  if (pattern.size() == 1 && pattern[0] == glob) {
63
925
    return true;
64
925
  }
65
  // Only valid if wildcard character appear once.
66
14
  if (std::count(pattern.begin(), pattern.end(), glob) == 1) {
67
11
    std::vector<absl::string_view> split_pattern = absl::StrSplit(pattern, glob);
68
11
    return (pattern.size() <= dns_label.size() + 1) &&
69
11
           absl::StartsWith(dns_label, split_pattern[0]) &&
70
11
           absl::EndsWith(dns_label, split_pattern[1]);
71
11
  }
72
3
  return false;
73
14
}
74

            
75
7141
bool Utility::dnsNameMatch(absl::string_view dns_name, absl::string_view pattern) {
76
  // A-label ACE prefix https://www.rfc-editor.org/rfc/rfc5890#section-2.3.2.5.
77
7141
  constexpr absl::string_view ACE_prefix = "xn--";
78
7141
  const std::string lower_case_dns_name = absl::AsciiStrToLower(dns_name);
79
7141
  const std::string lower_case_pattern = absl::AsciiStrToLower(pattern);
80
7141
  if (lower_case_dns_name == lower_case_pattern) {
81
2075
    return true;
82
2075
  }
83

            
84
5066
  std::vector<absl::string_view> split_pattern =
85
5066
      absl::StrSplit(lower_case_pattern, absl::MaxSplits('.', 1));
86
5066
  std::vector<absl::string_view> split_dns_name =
87
5066
      absl::StrSplit(lower_case_dns_name, absl::MaxSplits('.', 1));
88

            
89
  // dns name and pattern should contain more than 1 label to match.
90
5066
  if (split_pattern.size() < 2 || split_dns_name.size() < 2) {
91
25
    return false;
92
25
  }
93
  // Only the left-most label in the pattern contains wildcard '*' and is not an A-label.
94
5041
  if ((split_pattern[0].find('*') != absl::string_view::npos) &&
95
5041
      (split_pattern[1].find('*') == absl::string_view::npos) &&
96
5041
      (!absl::StartsWith(split_pattern[0], ACE_prefix))) {
97
950
    return (split_dns_name[1] == split_pattern[1]) &&
98
950
           labelWildcardMatch(split_dns_name[0], split_pattern[0]);
99
950
  }
100

            
101
4091
  return false;
102
5041
}
103

            
104
namespace {
105

            
106
enum class CertName { Issuer, Subject };
107

            
108
/**
109
 * Retrieves a name from a certificate and formats it as an RFC 2253 name.
110
 * @param cert the certificate.
111
 * @param desired_name the desired name (Issuer or Subject) to retrieve from the certificate.
112
 * @return std::string returns the desired name formatted as an RFC 2253 name.
113
 */
114
43
std::string getRFC2253NameFromCertificate(X509& cert, CertName desired_name) {
115
43
  bssl::UniquePtr<BIO> buf(BIO_new(BIO_s_mem()));
116
43
  RELEASE_ASSERT(buf != nullptr, "");
117

            
118
43
  const X509_NAME* name = nullptr;
119
43
  switch (desired_name) {
120
10
  case CertName::Issuer:
121
10
    name = X509_get_issuer_name(&cert);
122
10
    break;
123
33
  case CertName::Subject:
124
33
    name = X509_get_subject_name(&cert);
125
33
    break;
126
43
  }
127

            
128
  // flags=XN_FLAG_RFC2253 is the documented parameter for single-line output in RFC 2253 format.
129
  // Example from the RFC:
130
  //   * Single value per Relative Distinguished Name (RDN): CN=Steve Kille,O=Isode Limited,C=GB
131
  //   * Multivalue output in first RDN: OU=Sales+CN=J. Smith,O=Widget Inc.,C=US
132
  //   * Quoted comma in Organization: CN=L. Eagle,O=Sue\, Grabbit and Runn,C=GB
133
43
  X509_NAME_print_ex(buf.get(), name, 0 /* indent */, XN_FLAG_RFC2253);
134

            
135
43
  const uint8_t* data;
136
43
  size_t data_len;
137
43
  int rc = BIO_mem_contents(buf.get(), &data, &data_len);
138
43
  ASSERT(rc == 1);
139
43
  return {reinterpret_cast<const char*>(data), data_len};
140
43
}
141

            
142
/**
143
 * Parse well-known attribute values from a X509 distinguished name in certificate
144
 * @param cert the certificate.
145
 * @param desired_name the desired name (Issuer or Subject) to parse from the certificate.
146
 * @return Envoy::Ssl::ParsedX509NamePtr returns the struct contains the parsed values.
147
 */
148
5
Envoy::Ssl::ParsedX509NamePtr parseX509NameFromCertificate(X509& cert, CertName desired_name) {
149
5
  const X509_NAME* name = nullptr;
150
5
  switch (desired_name) {
151
1
  case CertName::Issuer:
152
1
    name = X509_get_issuer_name(&cert);
153
1
    break;
154
4
  case CertName::Subject:
155
4
    name = X509_get_subject_name(&cert);
156
4
    break;
157
5
  }
158

            
159
5
  auto parsed = std::make_unique<Envoy::Ssl::ParsedX509Name>();
160
5
  int cnt = X509_NAME_entry_count(name);
161
35
  for (int i = 0; i < cnt; i++) {
162
30
    const X509_NAME_ENTRY* ent = X509_NAME_get_entry(name, i);
163

            
164
30
    const ASN1_OBJECT* fn = X509_NAME_ENTRY_get_object(ent);
165
30
    int fn_nid = OBJ_obj2nid(fn);
166
30
    if (fn_nid != NID_commonName && fn_nid != NID_organizationName) {
167
20
      continue;
168
20
    }
169

            
170
10
    const ASN1_STRING* val = X509_NAME_ENTRY_get_data(ent);
171
10
    unsigned char* text = nullptr;
172
10
    int len = ASN1_STRING_to_UTF8(&text, val);
173
    // Len < 0 means we could not encode as UTF-8, just ignore it
174
    // len = 0 is empty string already, also ignore it
175
10
    if (len > 0) {
176
10
      auto str = std::string(reinterpret_cast<const char*>(text), len);
177
10
      switch (fn_nid) {
178
5
      case NID_commonName:
179
5
        parsed->commonName_ = std::move(str);
180
5
        break;
181
5
      case NID_organizationName:
182
5
        parsed->organizationName_.push_back(std::move(str));
183
5
        break;
184
10
      }
185
10
    }
186
10
    OPENSSL_free(text);
187
10
  }
188
5
  return parsed;
189
5
}
190

            
191
} // namespace
192

            
193
11245
const ASN1_TIME& epochASN1Time() {
194
11245
  static ASN1_TIME* e = []() -> ASN1_TIME* {
195
172
    ASN1_TIME* epoch = ASN1_TIME_new();
196
172
    const time_t epoch_time = 0;
197
172
    RELEASE_ASSERT(ASN1_TIME_set(epoch, epoch_time) != nullptr, "");
198
172
    return epoch;
199
172
  }();
200
11245
  return *e;
201
11245
}
202

            
203
8956
inline bssl::UniquePtr<ASN1_TIME> currentASN1Time(TimeSource& time_source) {
204
8956
  bssl::UniquePtr<ASN1_TIME> current_asn_time(ASN1_TIME_new());
205
8956
  const time_t current_time = std::chrono::system_clock::to_time_t(time_source.systemTime());
206
8956
  RELEASE_ASSERT(ASN1_TIME_set(current_asn_time.get(), current_time) != nullptr, "");
207
8956
  return current_asn_time;
208
8956
}
209

            
210
1227
std::string Utility::getSerialNumberFromCertificate(X509& cert) {
211
1227
  ASN1_INTEGER* serial_number = X509_get_serialNumber(&cert);
212
1227
  bssl::UniquePtr<BIGNUM> num_bn{BN_new()};
213
1227
  ASN1_INTEGER_to_BN(serial_number, num_bn.get());
214
1227
  char* char_serial_number = BN_bn2hex(num_bn.get());
215
1227
  if (char_serial_number != nullptr) {
216
1227
    std::string serial_number(char_serial_number);
217
1227
    OPENSSL_free(char_serial_number);
218
1227
    return serial_number;
219
1227
  }
220
  return "";
221
1227
}
222

            
223
3773
std::vector<std::string> Utility::getSubjectAltNames(X509& cert, int type) {
224
3773
  std::vector<std::string> subject_alt_names;
225
3773
  bssl::UniquePtr<GENERAL_NAMES> san_names(
226
3773
      static_cast<GENERAL_NAMES*>(X509_get_ext_d2i(&cert, NID_subject_alt_name, nullptr, nullptr)));
227
3773
  if (san_names == nullptr) {
228
44
    return subject_alt_names;
229
44
  }
230
11751
  for (const GENERAL_NAME* san : san_names.get()) {
231
11751
    if (san->type == type) {
232
5026
      subject_alt_names.push_back(generalNameAsString(san));
233
5026
    }
234
11751
  }
235
3729
  return subject_alt_names;
236
3773
}
237

            
238
11691
std::string Utility::generalNameAsString(const GENERAL_NAME* general_name) {
239
11691
  std::string san;
240
11691
  const ASN1_STRING* str = nullptr;
241
11691
  switch (general_name->type) {
242
9335
  case GEN_DNS:
243
9335
    str = general_name->d.dNSName;
244
9335
    san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(str)), ASN1_STRING_length(str));
245
9335
    break;
246
2294
  case GEN_URI:
247
2294
    str = general_name->d.uniformResourceIdentifier;
248
2294
    san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(str)), ASN1_STRING_length(str));
249
2294
    break;
250
3
  case GEN_EMAIL:
251
3
    str = general_name->d.rfc822Name;
252
3
    san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(str)), ASN1_STRING_length(str));
253
3
    break;
254
31
  case GEN_IPADD: {
255
31
    if (general_name->d.ip->length == 4) {
256
22
      sockaddr_in sin;
257
22
      memset(&sin, 0, sizeof(sin));
258
22
      sin.sin_port = 0;
259
22
      sin.sin_family = AF_INET;
260
22
      safeMemcpyUnsafeSrc(&sin.sin_addr, general_name->d.ip->data);
261
22
      san = Network::Address::Ipv4Instance::sockaddrToString(sin);
262
22
    } else if (general_name->d.ip->length == 16) {
263
9
      sockaddr_in6 sin6;
264
9
      memset(&sin6, 0, sizeof(sin6));
265
9
      sin6.sin6_port = 0;
266
9
      sin6.sin6_family = AF_INET6;
267
9
      safeMemcpyUnsafeSrc(&sin6.sin6_addr, general_name->d.ip->data);
268
9
      san = Network::Address::Ipv6Instance::sockaddrToString(sin6);
269
9
    }
270
31
    break;
271
  }
272
28
  case GEN_OTHERNAME: {
273
28
    const ASN1_TYPE* value = general_name->d.otherName->value;
274
28
    if (value == nullptr) {
275
      break;
276
    }
277
28
    switch (value->type) {
278
1
    case V_ASN1_NULL:
279
1
      break;
280
1
    case V_ASN1_BOOLEAN:
281
1
      san = value->value.boolean ? "true" : "false";
282
1
      break;
283
1
    case V_ASN1_ENUMERATED:
284
2
    case V_ASN1_INTEGER: {
285
2
      bssl::UniquePtr<BIGNUM> san_bn{BN_new()};
286
2
      value->type == V_ASN1_ENUMERATED
287
2
          ? ASN1_ENUMERATED_to_BN(value->value.enumerated, san_bn.get())
288
2
          : ASN1_INTEGER_to_BN(value->value.integer, san_bn.get());
289
2
      char* san_char = BN_bn2dec(san_bn.get());
290
2
      if (san_char != nullptr) {
291
2
        san.assign(san_char);
292
2
        OPENSSL_free(san_char);
293
2
      }
294
2
      break;
295
1
    }
296
1
    case V_ASN1_OBJECT: {
297
1
      char tmp_obj[MAX_OID_LENGTH];
298
1
      int obj_len = OBJ_obj2txt(tmp_obj, MAX_OID_LENGTH, value->value.object, 1);
299
1
      if (obj_len > MAX_OID_LENGTH || obj_len < 0) {
300
        break;
301
      }
302
1
      san.assign(tmp_obj);
303
1
      break;
304
1
    }
305
3
    case V_ASN1_BIT_STRING: {
306
3
      const ASN1_BIT_STRING* tmp_str = value->value.bit_string;
307
3
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
308
3
                 ASN1_STRING_length(tmp_str));
309
3
      break;
310
1
    }
311
1
    case V_ASN1_OCTET_STRING: {
312
1
      const ASN1_OCTET_STRING* tmp_str = value->value.octet_string;
313
1
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
314
1
                 ASN1_STRING_length(tmp_str));
315
1
      break;
316
1
    }
317
1
    case V_ASN1_PRINTABLESTRING: {
318
1
      const ASN1_PRINTABLESTRING* tmp_str = value->value.printablestring;
319
1
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
320
1
                 ASN1_STRING_length(tmp_str));
321
1
      break;
322
1
    }
323
1
    case V_ASN1_T61STRING: {
324
1
      const ASN1_T61STRING* tmp_str = value->value.t61string;
325
1
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
326
1
                 ASN1_STRING_length(tmp_str));
327
1
      break;
328
1
    }
329
1
    case V_ASN1_IA5STRING: {
330
1
      const ASN1_IA5STRING* tmp_str = value->value.ia5string;
331
1
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
332
1
                 ASN1_STRING_length(tmp_str));
333
1
      break;
334
1
    }
335
1
    case V_ASN1_GENERALSTRING: {
336
1
      const ASN1_GENERALSTRING* tmp_str = value->value.generalstring;
337
1
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
338
1
                 ASN1_STRING_length(tmp_str));
339
1
      break;
340
1
    }
341
2
    case V_ASN1_BMPSTRING: {
342
      // `ASN1_BMPSTRING` is encoded using `UTF-16`, which needs conversion to UTF-8.
343
2
      unsigned char* tmp = nullptr;
344
2
      int length = ASN1_STRING_to_UTF8(&tmp, value->value.bmpstring);
345
2
      if (length < 0) {
346
        break;
347
      }
348
2
      san.assign(reinterpret_cast<const char*>(tmp), length);
349
2
      OPENSSL_free(tmp);
350
2
      break;
351
2
    }
352
2
    case V_ASN1_UNIVERSALSTRING: {
353
      // `ASN1_UNIVERSALSTRING` is encoded using `UCS-4`, which needs conversion to UTF-8.
354
2
      unsigned char* tmp = nullptr;
355
2
      int length = ASN1_STRING_to_UTF8(&tmp, value->value.universalstring);
356
2
      if (length < 0) {
357
        break;
358
      }
359
2
      san.assign(reinterpret_cast<const char*>(tmp), length);
360
2
      OPENSSL_free(tmp);
361
2
      break;
362
2
    }
363
1
    case V_ASN1_UTCTIME: {
364
1
      const ASN1_UTCTIME* tmp_str = value->value.utctime;
365
1
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
366
1
                 ASN1_STRING_length(tmp_str));
367
1
      break;
368
2
    }
369
1
    case V_ASN1_GENERALIZEDTIME: {
370
1
      const ASN1_GENERALIZEDTIME* tmp_str = value->value.generalizedtime;
371
1
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
372
1
                 ASN1_STRING_length(tmp_str));
373
1
      break;
374
2
    }
375
1
    case V_ASN1_VISIBLESTRING: {
376
1
      const ASN1_VISIBLESTRING* tmp_str = value->value.visiblestring;
377
1
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
378
1
                 ASN1_STRING_length(tmp_str));
379
1
      break;
380
2
    }
381
5
    case V_ASN1_UTF8STRING: {
382
5
      const ASN1_UTF8STRING* tmp_str = value->value.utf8string;
383
5
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
384
5
                 ASN1_STRING_length(tmp_str));
385
5
      break;
386
2
    }
387
2
    case V_ASN1_SET: {
388
2
      const ASN1_STRING* tmp_str = value->value.set;
389
2
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
390
2
                 ASN1_STRING_length(tmp_str));
391
2
      break;
392
2
    }
393
1
    case V_ASN1_SEQUENCE: {
394
1
      const ASN1_STRING* tmp_str = value->value.sequence;
395
1
      san.assign(reinterpret_cast<const char*>(ASN1_STRING_get0_data(tmp_str)),
396
1
                 ASN1_STRING_length(tmp_str));
397
1
      break;
398
2
    }
399
    default:
400
      break;
401
28
    }
402
28
  }
403
11691
  }
404
11691
  return san;
405
11691
}
406

            
407
10
std::string Utility::getIssuerFromCertificate(X509& cert) {
408
10
  return getRFC2253NameFromCertificate(cert, CertName::Issuer);
409
10
}
410

            
411
33
std::string Utility::getSubjectFromCertificate(X509& cert) {
412
33
  return getRFC2253NameFromCertificate(cert, CertName::Subject);
413
33
}
414

            
415
1
Envoy::Ssl::ParsedX509NamePtr Utility::parseIssuerFromCertificate(X509& cert) {
416
1
  return parseX509NameFromCertificate(cert, CertName::Issuer);
417
1
}
418

            
419
4
Envoy::Ssl::ParsedX509NamePtr Utility::parseSubjectFromCertificate(X509& cert) {
420
4
  return parseX509NameFromCertificate(cert, CertName::Subject);
421
4
}
422

            
423
11198
std::chrono::seconds Utility::getExpirationUnixTime(const X509* cert) {
424
11198
  if (cert == nullptr) {
425
37
    return std::chrono::seconds::max();
426
37
  }
427
  // Obtain the expiration time as system time
428
11161
  SystemTime expiration_time = Utility::getExpirationTime(*cert);
429

            
430
  // Convert the time to duration since epoch
431
11161
  return std::chrono::duration_cast<std::chrono::seconds>(expiration_time.time_since_epoch());
432
11198
}
433

            
434
absl::optional<uint32_t> Utility::getDaysUntilExpiration(const X509* cert,
435
12457
                                                         TimeSource& time_source) {
436
12457
  if (cert == nullptr) {
437
3501
    return absl::make_optional(std::numeric_limits<uint32_t>::max());
438
3501
  }
439
8956
  int days, seconds;
440
8956
  if (ASN1_TIME_diff(&days, &seconds, currentASN1Time(time_source).get(),
441
8956
                     X509_get0_notAfter(cert))) {
442
8956
    if (days >= 0 && seconds >= 0) {
443
8948
      return absl::make_optional(days);
444
8948
    }
445
8956
  }
446
8
  return absl::nullopt;
447
8956
}
448

            
449
6
std::vector<std::string> Utility::getCertificateExtensionOids(X509& cert) {
450
6
  std::vector<std::string> extension_oids;
451

            
452
6
  int count = X509_get_ext_count(&cert);
453
29
  for (int pos = 0; pos < count; pos++) {
454
23
    const X509_EXTENSION* extension = X509_get_ext(&cert, pos);
455
23
    RELEASE_ASSERT(extension != nullptr, "");
456

            
457
23
    char oid[MAX_OID_LENGTH];
458
23
    int obj_len = OBJ_obj2txt(oid, MAX_OID_LENGTH, X509_EXTENSION_get_object(extension),
459
23
                              1 /* always_return_oid */);
460
23
    if (obj_len > 0 && obj_len < MAX_OID_LENGTH) {
461
23
      extension_oids.push_back(oid);
462
23
    }
463
23
  }
464
6
  return extension_oids;
465
6
}
466

            
467
absl::string_view Utility::getCertificateExtensionValue(X509& cert,
468
5179
                                                        absl::string_view extension_name) {
469
5179
  bssl::UniquePtr<ASN1_OBJECT> oid(
470
5179
      OBJ_txt2obj(std::string(extension_name).c_str(), 1 /* don't search names */));
471
5179
  if (oid == nullptr) {
472
2
    return {};
473
2
  }
474

            
475
5177
  int pos = X509_get_ext_by_OBJ(&cert, oid.get(), -1);
476
5177
  if (pos < 0) {
477
5171
    return {};
478
5171
  }
479

            
480
6
  const X509_EXTENSION* extension = X509_get_ext(&cert, pos);
481
6
  if (extension == nullptr) {
482
    return {};
483
  }
484

            
485
6
  const ASN1_OCTET_STRING* octet_string = X509_EXTENSION_get_data(extension);
486
6
  RELEASE_ASSERT(octet_string != nullptr, "");
487

            
488
  // Return the entire DER-encoded value for this extension. Correct decoding depends on
489
  // knowledge of the expected structure of the extension's value.
490
6
  const unsigned char* octet_string_data = ASN1_STRING_get0_data(octet_string);
491
6
  const int octet_string_length = ASN1_STRING_length(octet_string);
492

            
493
6
  return {reinterpret_cast<const char*>(octet_string_data),
494
6
          static_cast<absl::string_view::size_type>(octet_string_length)};
495
6
}
496

            
497
14
SystemTime Utility::getValidFrom(const X509& cert) {
498
14
  int days, seconds;
499
14
  int rc = ASN1_TIME_diff(&days, &seconds, &epochASN1Time(), X509_get0_notBefore(&cert));
500
14
  ASSERT(rc == 1);
501
  // Casting to <time_t (64bit)> to prevent multiplication overflow when certificate valid-from date
502
  // beyond 2038-01-19T03:14:08Z.
503
14
  return std::chrono::system_clock::from_time_t(static_cast<time_t>(days) * 24 * 60 * 60 + seconds);
504
14
}
505

            
506
11231
SystemTime Utility::getExpirationTime(const X509& cert) {
507
11231
  int days, seconds;
508
11231
  int rc = ASN1_TIME_diff(&days, &seconds, &epochASN1Time(), X509_get0_notAfter(&cert));
509
11231
  ASSERT(rc == 1);
510
  // Casting to <time_t (64bit)> to prevent multiplication overflow when certificate not-after date
511
  // beyond 2038-01-19T03:14:08Z.
512
11231
  return std::chrono::system_clock::from_time_t(static_cast<time_t>(days) * 24 * 60 * 60 + seconds);
513
11231
}
514

            
515
42
absl::optional<std::string> Utility::getLastCryptoError() {
516
42
  auto err = ERR_get_error();
517

            
518
42
  if (err != 0) {
519
40
    char errbuf[256];
520

            
521
40
    ERR_error_string_n(err, errbuf, sizeof(errbuf));
522
40
    return std::string(errbuf);
523
40
  }
524

            
525
2
  return absl::nullopt;
526
42
}
527

            
528
92
absl::string_view Utility::getErrorDescription(int err) {
529
92
  const char* description = SSL_error_description(err);
530
92
  if (description) {
531
91
    return description;
532
91
  }
533

            
534
1
  IS_ENVOY_BUG("BoringSSL error had occurred: SSL_error_description() returned nullptr");
535
1
  return SSL_ERROR_UNKNOWN_ERROR_MESSAGE;
536
92
}
537

            
538
34
std::string Utility::getX509VerificationErrorInfo(X509_STORE_CTX* ctx) {
539
34
  const int n = X509_STORE_CTX_get_error(ctx);
540
34
  const int depth = X509_STORE_CTX_get_error_depth(ctx);
541
34
  std::string error_details =
542
34
      absl::StrCat("X509_verify_cert: certificate verification error at depth ", depth, ": ");
543

            
544
34
  if (n == X509_V_ERR_UNABLE_TO_GET_CRL || n == X509_V_ERR_CRL_NOT_YET_VALID ||
545
34
      n == X509_V_ERR_CRL_HAS_EXPIRED || n == X509_V_ERR_CERT_REVOKED) {
546
11
    const std::string crl_error_msg =
547
11
        fmt::format("certificate revocation check against provided CRLs failed: {}",
548
11
                    X509_verify_cert_error_string(n));
549
11
    absl::StrAppend(&error_details, crl_error_msg);
550
11
    X509* cert = X509_STORE_CTX_get_current_cert(ctx);
551
11
    if (cert != nullptr) {
552
11
      std::vector<std::string> crldps = getCertificateCrlDpsForLogging(cert);
553
11
      if (!crldps.empty()) {
554
1
        const std::string error_msg =
555
1
            fmt::format(", certificate CRL distribution points: [{}]", fmt::join(crldps, ", "));
556
1
        absl::StrAppend(&error_details, error_msg);
557
1
      }
558
11
    }
559
25
  } else {
560
23
    absl::StrAppend(&error_details, X509_verify_cert_error_string(n));
561
23
  }
562

            
563
34
  return error_details;
564
34
}
565

            
566
std::vector<std::string> Utility::mapX509Stack(stack_st_X509& stack,
567
7
                                               std::function<std::string(X509&)> field_extractor) {
568
7
  std::vector<std::string> result;
569
7
  if (sk_X509_num(&stack) <= 0) {
570
1
    IS_ENVOY_BUG("x509 stack is empty or NULL");
571
1
    return result;
572
1
  }
573
6
  if (field_extractor == nullptr) {
574
1
    IS_ENVOY_BUG("field_extractor is nullptr");
575
1
    return result;
576
1
  }
577

            
578
14
  for (uint64_t i = 0; i < sk_X509_num(&stack); i++) {
579
9
    X509* cert = sk_X509_value(&stack, i);
580
9
    if (!cert) {
581
1
      result.push_back(""); // Add an empty string so it's clear something was omitted.
582
8
    } else {
583
8
      result.push_back(field_extractor(*cert));
584
8
    }
585
9
  }
586

            
587
5
  return result;
588
6
}
589

            
590
9
std::vector<std::string> Utility::getCertificateSansForLogging(X509* cert) {
591
9
  std::vector<std::string> sans;
592
  // X509_get_ext_d2i should be available in all supported BoringSSL versions.
593
9
  bssl::UniquePtr<GENERAL_NAMES> san_names(
594
9
      static_cast<GENERAL_NAMES*>(X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr)));
595
9
  if (san_names != nullptr) {
596
22
    for (const GENERAL_NAME* general_name : san_names.get()) {
597
22
      sans.push_back(Utility::generalNameAsString(general_name));
598
22
    }
599
8
  }
600
9
  return sans;
601
9
}
602

            
603
14
std::vector<std::string> Utility::getCertificateCrlDpsForLogging(X509* cert) {
604
14
  std::vector<std::string> crldps;
605
14
  bssl::UniquePtr<CRL_DIST_POINTS> dist_points(static_cast<CRL_DIST_POINTS*>(
606
14
      X509_get_ext_d2i(cert, NID_crl_distribution_points, nullptr, nullptr)));
607
14
  if (dist_points != nullptr) {
608
5
    for (const DIST_POINT* dp : dist_points.get()) {
609
5
      if (dp->distpoint != nullptr && dp->distpoint->type == 0) {
610
5
        GENERAL_NAMES* names = dp->distpoint->name.fullname;
611
5
        if (names != nullptr) {
612
5
          for (const GENERAL_NAME* general_name : names) {
613
5
            crldps.push_back(Utility::generalNameAsString(general_name));
614
5
          }
615
5
        }
616
5
      }
617
5
    }
618
3
  }
619
14
  return crldps;
620
14
}
621

            
622
} // namespace Tls
623
} // namespace TransportSockets
624
} // namespace Extensions
625
} // namespace Envoy