1
#include "source/common/tls/cert_validator/default_validator.h"
2

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

            
6
#include <algorithm>
7
#include <array>
8
#include <climits>
9
#include <cstdint>
10
#include <deque>
11
#include <functional>
12
#include <string>
13
#include <vector>
14

            
15
#include "envoy/network/transport_socket.h"
16
#include "envoy/ssl/context.h"
17
#include "envoy/ssl/context_config.h"
18
#include "envoy/ssl/private_key/private_key.h"
19
#include "envoy/ssl/ssl_socket_extended_info.h"
20

            
21
#include "source/common/common/assert.h"
22
#include "source/common/common/base64.h"
23
#include "source/common/common/fmt.h"
24
#include "source/common/common/hex.h"
25
#include "source/common/common/matchers.h"
26
#include "source/common/common/utility.h"
27
#include "source/common/config/utility.h"
28
#include "source/common/network/address_impl.h"
29
#include "source/common/protobuf/utility.h"
30
#include "source/common/runtime/runtime_features.h"
31
#include "source/common/stats/symbol_table.h"
32
#include "source/common/stats/utility.h"
33
#include "source/common/tls/aws_lc_compat.h"
34
#include "source/common/tls/cert_validator/cert_validator.h"
35
#include "source/common/tls/cert_validator/factory.h"
36
#include "source/common/tls/stats.h"
37
#include "source/common/tls/utility.h"
38

            
39
#include "absl/synchronization/mutex.h"
40
#include "openssl/ssl.h"
41
#include "openssl/x509v3.h"
42

            
43
namespace Envoy {
44
namespace Extensions {
45
namespace TransportSockets {
46
namespace Tls {
47

            
48
DefaultCertValidator::DefaultCertValidator(
49
    const Envoy::Ssl::CertificateValidationContextConfig* config, SslStats& stats,
50
    Server::Configuration::CommonFactoryContext& context)
51
7013
    : config_(config), stats_(stats), context_(context),
52
7013
      auto_sni_san_match_(config_ != nullptr ? config_->autoSniSanMatch() : false) {
53
7013
  if (config_ != nullptr) {
54
5973
    allow_untrusted_certificate_ = config_->trustChainVerification() ==
55
5973
                                   envoy::extensions::transport_sockets::tls::v3::
56
5973
                                       CertificateValidationContext::ACCEPT_UNTRUSTED;
57
5973
  }
58
7013
};
59

            
60
absl::StatusOr<int> DefaultCertValidator::initializeSslContexts(std::vector<SSL_CTX*> contexts,
61
                                                                bool provides_certificates,
62
7002
                                                                Stats::Scope& scope) {
63

            
64
7002
  int verify_mode = SSL_VERIFY_NONE;
65
7002
  int verify_mode_validation_context = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
66

            
67
7002
  if (config_ != nullptr) {
68
5971
    envoy::extensions::transport_sockets::tls::v3::CertificateValidationContext::
69
5971
        TrustChainVerification verification = config_->trustChainVerification();
70
5971
    if (verification == envoy::extensions::transport_sockets::tls::v3::
71
5971
                            CertificateValidationContext::ACCEPT_UNTRUSTED) {
72
6
      verify_mode = SSL_VERIFY_PEER; // Ensure client-certs will be requested even if we have
73
                                     // nothing to verify against
74
6
      verify_mode_validation_context = SSL_VERIFY_PEER;
75
6
    }
76
5971
  }
77

            
78
7002
  if (config_ != nullptr && !config_->caCert().empty() && !provides_certificates) {
79
5930
    ca_file_path_ = config_->caCertPath();
80
5930
    bssl::UniquePtr<BIO> bio(
81
5930
        BIO_new_mem_buf(const_cast<char*>(config_->caCert().data()), config_->caCert().size()));
82
5930
    RELEASE_ASSERT(bio != nullptr, "");
83
    // Based on BoringSSL's X509_load_cert_crl_file().
84
5930
    bssl::UniquePtr<STACK_OF(X509_INFO)> list(
85
5930
        PEM_X509_INFO_read_bio(bio.get(), nullptr, nullptr, nullptr));
86
5930
    if (list == nullptr) {
87
1
      return absl::InvalidArgumentError(
88
1
          absl::StrCat("Failed to load trusted CA certificates from ", config_->caCertPath()));
89
1
    }
90

            
91
5973
    for (auto& ctx : contexts) {
92
5973
      X509_STORE* store = SSL_CTX_get_cert_store(ctx);
93
5973
      X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN);
94
5973
      bool has_crl = false;
95
6000
      for (const X509_INFO* item : list.get()) {
96
5997
        if (item->x509) {
97
5995
          X509_STORE_add_cert(store, item->x509);
98
5995
          if (ca_cert_ == nullptr) {
99
5926
            X509_up_ref(item->x509);
100
5926
            ca_cert_.reset(item->x509);
101
5926
          }
102
5995
        }
103
5997
        if (item->crl) {
104
10
          X509_STORE_add_crl(store, item->crl);
105
10
          has_crl = true;
106
10
        }
107
5997
      }
108
5973
      if (ca_cert_ == nullptr) {
109
3
        return absl::InvalidArgumentError(
110
3
            absl::StrCat("Failed to load trusted CA certificates from ", config_->caCertPath()));
111
3
      }
112
5970
      if (has_crl) {
113
8
        X509_STORE_set_flags(store, config_->onlyVerifyLeafCertificateCrl()
114
8
                                        ? X509_V_FLAG_CRL_CHECK
115
8
                                        : X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
116
8
      }
117
5970
      verify_mode = SSL_VERIFY_PEER;
118
5970
      verify_trusted_ca_ = true;
119

            
120
5970
      if (config_->allowExpiredCertificate()) {
121
18
        X509_STORE_set_flags(store, X509_V_FLAG_NO_CHECK_TIME);
122
18
      }
123
5970
    }
124
5929
  }
125

            
126
  // Disallow insecure configuration.
127
6998
  if (config_ != nullptr && config_->autoSniSanMatch() && !verify_trusted_ca_) {
128
1
    return absl::InvalidArgumentError(
129
1
        "'auto_sni_san_validation' was configured without configuring a trusted CA");
130
1
  }
131

            
132
6997
  if (config_ != nullptr && !config_->certificateRevocationList().empty()) {
133
26
    bssl::UniquePtr<BIO> bio(
134
26
        BIO_new_mem_buf(const_cast<char*>(config_->certificateRevocationList().data()),
135
26
                        config_->certificateRevocationList().size()));
136
26
    RELEASE_ASSERT(bio != nullptr, "");
137

            
138
    // Based on BoringSSL's X509_load_cert_crl_file().
139
26
    bssl::UniquePtr<STACK_OF(X509_INFO)> list(
140
26
        PEM_X509_INFO_read_bio(bio.get(), nullptr, nullptr, nullptr));
141
26
    if (list == nullptr) {
142
3
      return absl::InvalidArgumentError(
143
3
          absl::StrCat("Failed to load CRL from ", config_->certificateRevocationListPath()));
144
3
    }
145

            
146
23
    for (auto& ctx : contexts) {
147
23
      X509_STORE* store = SSL_CTX_get_cert_store(ctx);
148
23
      X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN);
149
25
      for (const X509_INFO* item : list.get()) {
150
25
        if (item->crl) {
151
25
          X509_STORE_add_crl(store, item->crl);
152
25
        }
153
25
      }
154
23
      X509_STORE_set_flags(store, config_->onlyVerifyLeafCertificateCrl()
155
23
                                      ? X509_V_FLAG_CRL_CHECK
156
23
                                      : X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
157
23
    }
158
23
  }
159

            
160
6994
  const Envoy::Ssl::CertificateValidationContextConfig* cert_validation_config = config_;
161
6994
  if (cert_validation_config != nullptr) {
162
5963
    if (!cert_validation_config->subjectAltNameMatchers().empty()) {
163
1596
      for (const envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher& matcher :
164
5147
           cert_validation_config->subjectAltNameMatchers()) {
165
5147
        auto san_matcher = createStringSanMatcher(matcher, context_);
166
5147
        if (san_matcher == nullptr) {
167
1
          return absl::InvalidArgumentError(
168
1
              absl::StrCat("Failed to create string SAN matcher of type ", matcher.san_type()));
169
1
        }
170
5146
        subject_alt_name_matchers_.emplace_back(std::move(san_matcher));
171
5146
      }
172
1595
      verify_mode = verify_mode_validation_context;
173
1595
    }
174

            
175
5962
    if (!cert_validation_config->verifyCertificateHashList().empty()) {
176
1414
      for (auto hash : cert_validation_config->verifyCertificateHashList()) {
177
        // Remove colons from the 95 chars long colon-separated "fingerprint"
178
        // in order to get the hex-encoded string.
179
1414
        if (hash.size() == 95) {
180
1348
          hash.erase(std::remove(hash.begin(), hash.end(), ':'), hash.end());
181
1348
        }
182
1414
        const auto& decoded = Hex::decode(hash);
183
1414
        if (decoded.size() != SHA256_DIGEST_LENGTH) {
184
1
          return absl::InvalidArgumentError(absl::StrCat("Invalid hex-encoded SHA-256 ", hash));
185
1
        }
186
1413
        verify_certificate_hash_list_.push_back(decoded);
187
1413
      }
188
1402
      verify_mode = verify_mode_validation_context;
189
1402
    }
190

            
191
5961
    if (!cert_validation_config->verifyCertificateSpkiList().empty()) {
192
52
      for (const auto& hash : cert_validation_config->verifyCertificateSpkiList()) {
193
52
        const auto decoded = Base64::decode(hash);
194
52
        if (decoded.size() != SHA256_DIGEST_LENGTH) {
195
1
          return absl::InvalidArgumentError(absl::StrCat("Invalid base64-encoded SHA-256 ", hash));
196
1
        }
197
51
        verify_certificate_spki_list_.emplace_back(decoded.begin(), decoded.end());
198
51
      }
199
32
      verify_mode = verify_mode_validation_context;
200
32
    }
201
5961
  }
202

            
203
6991
  initializeCertExpirationStats(scope);
204

            
205
6991
  return verify_mode;
206
6994
}
207

            
208
bool DefaultCertValidator::verifyCertAndUpdateStatus(
209
    X509* leaf_cert, absl::string_view sni,
210
    const Network::TransportSocketOptions* transport_socket_options,
211
    const CertValidator::ExtraValidationContext& validation_context,
212
    Envoy::Ssl::ClientValidationStatus& detailed_status, std::string* error_details,
213
4092
    uint8_t* out_alert) {
214

            
215
4092
  std::vector<SanMatcherPtr> match_sni_san;
216
4092
  OptRef<const std::vector<std::string>> verify_san_override;
217
4092
  OptRef<const std::vector<SanMatcherPtr>> match_san_override;
218
4092
  if (transport_socket_options != nullptr &&
219
4092
      !transport_socket_options->verifySubjectAltNameListOverride().empty()) {
220
    // TODO(ggreenway): this validation should be part of `match_sni_san` so that the type is
221
    // validated as a DNS SAN, but this change will require a runtime flag for the behavior change.
222
60
    verify_san_override = transport_socket_options->verifySubjectAltNameListOverride();
223
4089
  } else if (auto_sni_san_match_ && !sni.empty()) {
224
2
    match_sni_san.emplace_back(std::make_unique<DnsExactStringSanMatcher>(sni));
225
2
    match_san_override = match_sni_san;
226
2
  }
227
4092
  Envoy::Ssl::ClientValidationStatus validated =
228
4092
      verifyCertificate(leaf_cert, verify_san_override.value_or(std::vector<std::string>()),
229
4092
                        match_san_override.value_or(subject_alt_name_matchers_),
230
4092
                        validation_context.callbacks != nullptr
231
4092
                            ? makeOptRef(validation_context.callbacks->connection().streamInfo())
232
4092
                            : absl::nullopt,
233
4092
                        error_details, out_alert);
234

            
235
4092
  if (detailed_status == Envoy::Ssl::ClientValidationStatus::NotValidated ||
236
4092
      validated != Envoy::Ssl::ClientValidationStatus::NotValidated) {
237
2689
    detailed_status = validated;
238
2689
  }
239

            
240
  // If `trusted_ca` exists, it is already verified in the code above. Thus, we just need to make
241
  // sure the verification for other validation context configurations doesn't fail (i.e. either
242
  // `NotValidated` or `Validated`). If `trusted_ca` doesn't exist, we will need to make sure
243
  // other configurations are verified and the verification succeed.
244
4092
  const bool success = verify_trusted_ca_
245
4092
                           ? validated != Envoy::Ssl::ClientValidationStatus::Failed
246
4092
                           : validated == Envoy::Ssl::ClientValidationStatus::Validated;
247

            
248
4092
  return (allow_untrusted_certificate_ || success);
249
4092
}
250

            
251
Envoy::Ssl::ClientValidationStatus
252
DefaultCertValidator::verifyCertificate(X509* cert, const std::vector<std::string>& verify_san_list,
253
                                        const std::vector<SanMatcherPtr>& subject_alt_name_matchers,
254
                                        OptRef<const StreamInfo::StreamInfo> stream_info,
255
4096
                                        std::string* error_details, uint8_t* out_alert) {
256
4096
  Envoy::Ssl::ClientValidationStatus validated = Envoy::Ssl::ClientValidationStatus::NotValidated;
257
4096
  if (!verify_san_list.empty()) {
258
60
    if (!verifySubjectAltName(cert, verify_san_list)) {
259
4
      const std::string error_msg = fmt::format(
260
4
          "verify cert failed: verify SAN list, expected SANs: [{}], certificate SANs: [{}]",
261
4
          fmt::join(verify_san_list, ", "),
262
4
          fmt::join(Utility::getCertificateSansForLogging(cert), ", "));
263

            
264
4
      if (error_details != nullptr) {
265
4
        *error_details = error_msg;
266
4
      }
267
4
      ENVOY_LOG(debug, error_msg);
268
4
      stats_.fail_verify_san_.inc();
269
4
      return Envoy::Ssl::ClientValidationStatus::Failed;
270
4
    }
271
56
    validated = Envoy::Ssl::ClientValidationStatus::Validated;
272
56
  }
273

            
274
4092
  if (!subject_alt_name_matchers.empty()) {
275
2377
    if (!matchSubjectAltName(cert, stream_info, subject_alt_name_matchers)) {
276
5
      const std::string error_msg =
277
5
          fmt::format("verify cert failed: SAN matcher, certificate SANs are [{}]",
278
5
                      fmt::join(Utility::getCertificateSansForLogging(cert), ", "));
279
5
      if (error_details != nullptr) {
280
5
        *error_details = error_msg;
281
5
      }
282
5
      ENVOY_LOG(debug, error_msg);
283
5
      stats_.fail_verify_san_.inc();
284
5
      return Envoy::Ssl::ClientValidationStatus::Failed;
285
5
    }
286
2372
    validated = Envoy::Ssl::ClientValidationStatus::Validated;
287
2372
  }
288

            
289
4087
  if (!verify_certificate_hash_list_.empty() || !verify_certificate_spki_list_.empty()) {
290
254
    const bool valid_certificate_hash =
291
254
        !verify_certificate_hash_list_.empty() &&
292
254
        verifyCertificateHashList(cert, verify_certificate_hash_list_);
293
254
    const bool valid_certificate_spki =
294
254
        !verify_certificate_spki_list_.empty() &&
295
254
        verifyCertificateSpkiList(cert, verify_certificate_spki_list_);
296

            
297
254
    if (!valid_certificate_hash && !valid_certificate_spki) {
298
13
      if (out_alert != nullptr) {
299
13
        *out_alert = SSL_AD_BAD_CERTIFICATE_HASH_VALUE;
300
13
      }
301
13
      const char* error = "verify cert failed: cert hash and spki";
302
13
      if (error_details != nullptr) {
303
13
        *error_details = error;
304
13
      }
305
13
      ENVOY_LOG(debug, error);
306
13
      stats_.fail_verify_cert_hash_.inc();
307
13
      return Envoy::Ssl::ClientValidationStatus::Failed;
308
13
    }
309

            
310
241
    validated = Envoy::Ssl::ClientValidationStatus::Validated;
311
241
  }
312

            
313
4074
  return validated;
314
4087
}
315

            
316
ValidationResults DefaultCertValidator::doVerifyCertChain(
317
    STACK_OF(X509)& cert_chain, Ssl::ValidateResultCallbackPtr /*callback*/,
318
    const Network::TransportSocketOptionsConstSharedPtr& transport_socket_options, SSL_CTX& ssl_ctx,
319
    const CertValidator::ExtraValidationContext& context, bool is_server,
320
4121
    absl::string_view host_name) {
321
4121
  if (sk_X509_num(&cert_chain) == 0) {
322
2
    stats_.fail_verify_error_.inc();
323
2
    const char* error = "verify cert failed: empty cert chain";
324
2
    ENVOY_LOG(debug, error);
325
2
    return {ValidationResults::ValidationStatus::Failed,
326
2
            Envoy::Ssl::ClientValidationStatus::NoClientCertificate, absl::nullopt, error};
327
2
  }
328
4119
  Envoy::Ssl::ClientValidationStatus detailed_status =
329
4119
      Envoy::Ssl::ClientValidationStatus::NotValidated;
330
4119
  X509* leaf_cert = sk_X509_value(&cert_chain, 0);
331
4119
  ASSERT(leaf_cert);
332
4119
  if (verify_trusted_ca_) {
333
4093
    X509_STORE* verify_store = SSL_CTX_get_cert_store(&ssl_ctx);
334
4093
    ASSERT(verify_store);
335
4093
    bssl::UniquePtr<X509_STORE_CTX> ctx(X509_STORE_CTX_new());
336
4093
    if (!ctx || !X509_STORE_CTX_init(ctx.get(), verify_store, leaf_cert, &cert_chain) ||
337
        // We need to inherit the verify parameters. These can be determined by
338
        // the context: if it's a server it will verify SSL client certificates or
339
        // vice versa.
340
4093
        !X509_STORE_CTX_set_default(ctx.get(), is_server ? "ssl_client" : "ssl_server") ||
341
        // Anything non-default in "param" should overwrite anything in the ctx.
342
4093
        !X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(ctx.get()),
343
4093
                                SSL_CTX_get0_param(&ssl_ctx))) {
344
      OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB);
345
      const char* error = "verify cert failed: init and setup X509_STORE_CTX";
346
      stats_.fail_verify_error_.inc();
347
      ENVOY_LOG(debug, error);
348
      return {ValidationResults::ValidationStatus::Failed,
349
              Envoy::Ssl::ClientValidationStatus::Failed, absl::nullopt, error};
350
    }
351
4093
    const bool verify_succeeded = (X509_verify_cert(ctx.get()) == 1);
352

            
353
4093
    if (!verify_succeeded) {
354
27
      const std::string error =
355
27
          absl::StrCat("verify cert failed: ", Utility::getX509VerificationErrorInfo(ctx.get()));
356
27
      stats_.fail_verify_error_.inc();
357
27
      ENVOY_LOG(debug, error);
358
27
      if (allow_untrusted_certificate_) {
359
1
        return ValidationResults{ValidationResults::ValidationStatus::Successful,
360
1
                                 Envoy::Ssl::ClientValidationStatus::Failed, absl::nullopt,
361
1
                                 absl::nullopt};
362
1
      }
363
26
      return {ValidationResults::ValidationStatus::Failed,
364
26
              Envoy::Ssl::ClientValidationStatus::Failed,
365
26
              SSL_alert_from_verify_result(X509_STORE_CTX_get_error(ctx.get())), error};
366
27
    }
367
4066
    detailed_status = Envoy::Ssl::ClientValidationStatus::Validated;
368
4066
  }
369
4092
  std::string error_details;
370
4092
  uint8_t tls_alert = SSL_AD_CERTIFICATE_UNKNOWN;
371
4092
  const bool succeeded =
372
4092
      verifyCertAndUpdateStatus(leaf_cert, host_name, transport_socket_options.get(), context,
373
4092
                                detailed_status, &error_details, &tls_alert);
374
4092
  return succeeded ? ValidationResults{ValidationResults::ValidationStatus::Successful,
375
4071
                                       detailed_status, absl::nullopt, absl::nullopt}
376
4092
                   : ValidationResults{ValidationResults::ValidationStatus::Failed, detailed_status,
377
21
                                       tls_alert, error_details};
378
4119
}
379

            
380
bool DefaultCertValidator::verifySubjectAltName(X509* cert,
381
64
                                                const std::vector<std::string>& subject_alt_names) {
382
64
  bssl::UniquePtr<GENERAL_NAMES> san_names(
383
64
      static_cast<GENERAL_NAMES*>(X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr)));
384
64
  if (san_names == nullptr) {
385
    return false;
386
  }
387
78
  for (const GENERAL_NAME* general_name : san_names.get()) {
388
78
    const std::string san = Utility::generalNameAsString(general_name);
389
80
    for (auto& config_san : subject_alt_names) {
390
80
      if (general_name->type == GEN_DNS ? Utility::dnsNameMatch(config_san, san.c_str())
391
80
                                        : config_san == san) {
392
58
        return true;
393
58
      }
394
80
    }
395
78
  }
396
6
  return false;
397
64
}
398

            
399
bool DefaultCertValidator::matchSubjectAltName(
400
    X509* cert, OptRef<const StreamInfo::StreamInfo> stream_info,
401
2407
    const std::vector<SanMatcherPtr>& subject_alt_name_matchers) {
402
2407
  bssl::UniquePtr<GENERAL_NAMES> san_names(
403
2407
      static_cast<GENERAL_NAMES*>(X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr)));
404
2407
  if (san_names == nullptr) {
405
2
    return false;
406
2
  }
407
4444
  for (const auto& config_san_matcher : subject_alt_name_matchers) {
408
10655
    for (const GENERAL_NAME* general_name : san_names.get()) {
409
10655
      if (stream_info) {
410
10503
        if (config_san_matcher->match(general_name, stream_info.ref())) {
411
2368
          return true;
412
2368
        }
413
10640
      } else if (config_san_matcher->match(general_name)) {
414
28
        return true;
415
28
      }
416
10655
    }
417
4444
  }
418
9
  return false;
419
2405
}
420

            
421
bool DefaultCertValidator::verifyCertificateSpkiList(
422
19
    X509* cert, const std::vector<std::vector<uint8_t>>& expected_hashes) {
423
19
  X509_PUBKEY* pubkey = X509_get_X509_PUBKEY(cert);
424
19
  if (pubkey == nullptr) {
425
    return false;
426
  }
427
19
  uint8_t* spki = nullptr;
428
19
  const int len = i2d_X509_PUBKEY(pubkey, &spki);
429
19
  if (len < 0) {
430
    return false;
431
  }
432
19
  bssl::UniquePtr<uint8_t> free_spki(spki);
433

            
434
19
  std::vector<uint8_t> computed_hash(SHA256_DIGEST_LENGTH);
435
19
  SHA256(spki, len, computed_hash.data());
436

            
437
32
  for (const auto& expected_hash : expected_hashes) {
438
32
    if (computed_hash == expected_hash) {
439
11
      return true;
440
11
    }
441
32
  }
442
8
  return false;
443
19
}
444

            
445
bool DefaultCertValidator::verifyCertificateHashList(
446
243
    X509* cert, const std::vector<std::vector<uint8_t>>& expected_hashes) {
447
243
  std::vector<uint8_t> computed_hash(SHA256_DIGEST_LENGTH);
448
243
  unsigned int n;
449
243
  X509_digest(cert, EVP_sha256(), computed_hash.data(), &n);
450
243
  RELEASE_ASSERT(n == computed_hash.size(), "");
451

            
452
254
  for (const auto& expected_hash : expected_hashes) {
453
254
    if (computed_hash == expected_hash) {
454
230
      return true;
455
230
    }
456
254
  }
457
13
  return false;
458
243
}
459

            
460
void DefaultCertValidator::updateDigestForSessionId(bssl::ScopedEVP_MD_CTX& md,
461
                                                    uint8_t hash_buffer[EVP_MAX_MD_SIZE],
462
3456
                                                    unsigned hash_length) {
463
3456
  int rc;
464

            
465
  // Hash all the settings that affect whether the server will allow/accept
466
  // the client connection. This ensures that the client is always validated against
467
  // the correct settings, even if session resumption across different listeners
468
  // is enabled.
469
3456
  if (ca_cert_ != nullptr) {
470
2746
    rc = X509_digest(ca_cert_.get(), EVP_sha256(), hash_buffer, &hash_length);
471
2746
    RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
472
2746
    RELEASE_ASSERT(hash_length == SHA256_DIGEST_LENGTH,
473
2746
                   fmt::format("invalid SHA256 hash length {}", hash_length));
474

            
475
2746
    rc = EVP_DigestUpdate(md.get(), hash_buffer, hash_length);
476
2746
    RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
477
2746
  }
478

            
479
3456
  for (const auto& hash : verify_certificate_hash_list_) {
480
1378
    rc = EVP_DigestUpdate(md.get(), hash.data(),
481
1378
                          hash.size() *
482
1378
                              sizeof(std::remove_reference<decltype(hash)>::type::value_type));
483
1378
    RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
484
1378
  }
485

            
486
3456
  for (const auto& hash : verify_certificate_spki_list_) {
487
51
    rc = EVP_DigestUpdate(md.get(), hash.data(),
488
51
                          hash.size() *
489
51
                              sizeof(std::remove_reference<decltype(hash)>::type::value_type));
490
51
    RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
491
51
  }
492

            
493
3456
  rc = EVP_DigestUpdate(md.get(), &verify_trusted_ca_, sizeof(verify_trusted_ca_));
494
3456
  RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
495

            
496
3456
  if (config_ != nullptr) {
497
2779
    for (const auto& matcher : config_->subjectAltNameMatchers()) {
498
45
      size_t hash = MessageUtil::hash(matcher);
499
45
      rc = EVP_DigestUpdate(md.get(), &hash, sizeof(hash));
500
45
      RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
501
45
    }
502

            
503
2767
    const std::string& crl = config_->certificateRevocationList();
504
2767
    if (!crl.empty()) {
505
23
      rc = EVP_DigestUpdate(md.get(), crl.data(), crl.length());
506
23
      RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
507
23
    }
508

            
509
2767
    bool allow_expired = config_->allowExpiredCertificate();
510
2767
    rc = EVP_DigestUpdate(md.get(), &allow_expired, sizeof(allow_expired));
511
2767
    RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
512

            
513
2767
    auto trust_chain_verification = config_->trustChainVerification();
514
2767
    rc = EVP_DigestUpdate(md.get(), &trust_chain_verification, sizeof(trust_chain_verification));
515
2767
    RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
516

            
517
2767
    auto only_leaf_crl = config_->onlyVerifyLeafCertificateCrl();
518
2767
    rc = EVP_DigestUpdate(md.get(), &only_leaf_crl, sizeof(only_leaf_crl));
519
2767
    RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
520

            
521
2767
    auto max_verify_depth_opt = config_->maxVerifyDepth();
522
2767
    if (max_verify_depth_opt.has_value()) {
523
6
      auto max_verify_depth = *max_verify_depth_opt;
524
6
      rc = EVP_DigestUpdate(md.get(), &max_verify_depth, sizeof(max_verify_depth));
525
6
      RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
526
6
    }
527

            
528
2767
    bool auto_sni_san_match = config_->autoSniSanMatch();
529
2767
    rc = EVP_DigestUpdate(md.get(), &auto_sni_san_match, sizeof(auto_sni_san_match));
530
2767
    RELEASE_ASSERT(rc == 1, Utility::getLastCryptoError().value_or(""));
531
2767
  }
532
3456
}
533

            
534
absl::Status DefaultCertValidator::addClientValidationContext(SSL_CTX* ctx,
535
3549
                                                              bool require_client_cert) {
536
3549
  if (config_ == nullptr || config_->caCert().empty()) {
537
741
    return absl::OkStatus();
538
741
  }
539

            
540
2808
  bssl::UniquePtr<BIO> bio(
541
2808
      BIO_new_mem_buf(const_cast<char*>(config_->caCert().data()), config_->caCert().size()));
542
2808
  RELEASE_ASSERT(bio != nullptr, "");
543
  // Based on BoringSSL's SSL_add_file_cert_subjects_to_stack().
544
  // Use a generic lambda to be compatible with BoringSSL before and after
545
  // https://boringssl-review.googlesource.com/c/boringssl/+/56190
546
2808
  bssl::UniquePtr<STACK_OF(X509_NAME)> list(
547
2808
      sk_X509_NAME_new([](auto* a, auto* b) -> int { return X509_NAME_cmp(*a, *b); }));
548
2808
  RELEASE_ASSERT(list != nullptr, "");
549
5639
  for (;;) {
550
5639
    bssl::UniquePtr<X509> cert(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
551
5639
    if (cert == nullptr) {
552
2808
      break;
553
2808
    }
554
2831
    const X509_NAME* name = X509_get_subject_name(cert.get());
555
2831
    if (name == nullptr) {
556
      return absl::InvalidArgumentError(absl::StrCat(
557
          "Failed to load trusted client CA certificates from ", config_->caCertPath()));
558
    }
559
    // Check for duplicates.
560
2831
    if (sk_X509_NAME_find(list.get(), nullptr, name)) {
561
      continue;
562
    }
563

            
564
2831
    bssl::UniquePtr<X509_NAME> name_dup(X509_NAME_dup(name));
565
2831
    if (name_dup == nullptr || !sk_X509_NAME_push(list.get(), name_dup.release())) {
566
      return absl::InvalidArgumentError(absl::StrCat(
567
          "Failed to load trusted client CA certificates from ", config_->caCertPath()));
568
    }
569
2831
  }
570

            
571
  // Check for EOF.
572
2808
  const uint32_t err = ERR_peek_last_error();
573
2808
  if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
574
2808
    ERR_clear_error();
575
2808
  } else {
576
    return absl::InvalidArgumentError(
577
        absl::StrCat("Failed to load trusted client CA certificates from ", config_->caCertPath()));
578
  }
579
2808
  SSL_CTX_set_client_CA_list(ctx, list.release());
580

            
581
2808
  if (require_client_cert) {
582
31
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
583
31
  }
584
  // Set the verify_depth
585
2808
  if (config_->maxVerifyDepth().has_value()) {
586
7
    uint32_t max_verify_depth = std::min(config_->maxVerifyDepth().value(), uint32_t{INT_MAX});
587
    // Older BoringSSLs behave like OpenSSL 1.0.x and exclude the leaf from the
588
    // depth but include the trust anchor. Newer BoringSSLs match OpenSSL 1.1.x
589
    // and later in excluding both the leaf and trust anchor. `maxVerifyDepth`
590
    // documents the older behavior, so adjust the value to match.
591
7
    max_verify_depth = max_verify_depth > 0 ? max_verify_depth - 1 : 0;
592
7
    SSL_CTX_set_verify_depth(ctx, static_cast<int>(max_verify_depth));
593
7
  }
594
2808
  return absl::OkStatus();
595
2808
}
596

            
597
9
Envoy::Ssl::CertificateDetailsPtr DefaultCertValidator::getCaCertInformation() const {
598
9
  if (ca_cert_ == nullptr) {
599
3
    return nullptr;
600
3
  }
601
6
  return Utility::certificateDetails(ca_cert_.get(), getCaFileName(), context_.timeSource());
602
9
}
603

            
604
6991
void DefaultCertValidator::initializeCertExpirationStats(Stats::Scope& scope) {
605
  // Early return if no config
606
6991
  if (config_ == nullptr) {
607
1031
    return;
608
1031
  }
609

            
610
5960
  Stats::Gauge& expiration_gauge = createCertificateExpirationGauge(scope, config_->caCertName());
611
5960
  expiration_gauge.set(Utility::getExpirationUnixTime(ca_cert_.get()).count());
612
5960
}
613

            
614
6141
absl::optional<uint32_t> DefaultCertValidator::daysUntilFirstCertExpires() const {
615
6141
  return Utility::getDaysUntilExpiration(ca_cert_.get(), context_.timeSource());
616
6141
}
617

            
618
class DefaultCertValidatorFactory : public CertValidatorFactory {
619
public:
620
  absl::StatusOr<CertValidatorPtr>
621
  createCertValidator(const Envoy::Ssl::CertificateValidationContextConfig* config, SslStats& stats,
622
                      Server::Configuration::CommonFactoryContext& context,
623
6991
                      Stats::Scope& /*scope*/) override {
624
6991
    return std::make_unique<DefaultCertValidator>(config, stats, context);
625
6991
  }
626

            
627
1318
  std::string name() const override { return "envoy.tls.cert_validator.default"; }
628
};
629

            
630
REGISTER_FACTORY(DefaultCertValidatorFactory, CertValidatorFactory);
631

            
632
} // namespace Tls
633
} // namespace TransportSockets
634
} // namespace Extensions
635
} // namespace Envoy