Line data Source code
1 : #include "source/common/ssl/certificate_validation_context_config_impl.h" 2 : 3 : #include "envoy/common/exception.h" 4 : #include "envoy/config/core/v3/extension.pb.h" 5 : #include "envoy/extensions/transport_sockets/tls/v3/cert.pb.h" 6 : #include "envoy/extensions/transport_sockets/tls/v3/common.pb.h" 7 : 8 : #include "source/common/common/empty_string.h" 9 : #include "source/common/common/fmt.h" 10 : #include "source/common/common/logger.h" 11 : #include "source/common/config/datasource.h" 12 : 13 : #include "spdlog/spdlog.h" 14 : 15 : namespace Envoy { 16 : namespace Ssl { 17 : 18 : static const std::string INLINE_STRING = "<inline>"; 19 : 20 : CertificateValidationContextConfigImpl::CertificateValidationContextConfigImpl( 21 : const envoy::extensions::transport_sockets::tls::v3::CertificateValidationContext& config, 22 : Api::Api& api) 23 : : ca_cert_(Config::DataSource::read(config.trusted_ca(), true, api)), 24 : ca_cert_path_(Config::DataSource::getPath(config.trusted_ca()) 25 : .value_or(ca_cert_.empty() ? EMPTY_STRING : INLINE_STRING)), 26 : certificate_revocation_list_(Config::DataSource::read(config.crl(), true, api)), 27 : certificate_revocation_list_path_( 28 : Config::DataSource::getPath(config.crl()) 29 : .value_or(certificate_revocation_list_.empty() ? EMPTY_STRING : INLINE_STRING)), 30 : subject_alt_name_matchers_(getSubjectAltNameMatchers(config)), 31 : verify_certificate_hash_list_(config.verify_certificate_hash().begin(), 32 : config.verify_certificate_hash().end()), 33 : verify_certificate_spki_list_(config.verify_certificate_spki().begin(), 34 : config.verify_certificate_spki().end()), 35 : allow_expired_certificate_(config.allow_expired_certificate()), 36 : trust_chain_verification_(config.trust_chain_verification()), 37 : custom_validator_config_( 38 : config.has_custom_validator_config() 39 : ? absl::make_optional<envoy::config::core::v3::TypedExtensionConfig>( 40 : config.custom_validator_config()) 41 : : absl::nullopt), 42 : api_(api), only_verify_leaf_cert_crl_(config.only_verify_leaf_cert_crl()), 43 : max_verify_depth_(config.has_max_verify_depth() 44 : ? absl::optional<uint32_t>(config.max_verify_depth().value()) 45 0 : : absl::nullopt) {} 46 : 47 : absl::StatusOr<std::unique_ptr<CertificateValidationContextConfigImpl>> 48 : CertificateValidationContextConfigImpl::create( 49 : const envoy::extensions::transport_sockets::tls::v3::CertificateValidationContext& context, 50 0 : Api::Api& api) { 51 0 : auto config = std::unique_ptr<CertificateValidationContextConfigImpl>( 52 0 : new CertificateValidationContextConfigImpl(context, api)); 53 0 : absl::Status status = config->initialize(); 54 0 : if (status.ok()) { 55 0 : return config; 56 0 : } 57 0 : return status; 58 0 : } 59 : 60 0 : absl::Status CertificateValidationContextConfigImpl::initialize() { 61 0 : if (ca_cert_.empty() && custom_validator_config_ == absl::nullopt) { 62 0 : if (!certificate_revocation_list_.empty()) { 63 0 : return absl::InvalidArgumentError(fmt::format("Failed to load CRL from {} without trusted CA", 64 0 : certificateRevocationListPath())); 65 0 : } 66 0 : if (!subject_alt_name_matchers_.empty()) { 67 0 : return absl::InvalidArgumentError("SAN-based verification of peer certificates without " 68 0 : "trusted CA is insecure and not allowed"); 69 0 : } 70 0 : if (allow_expired_certificate_) { 71 0 : return absl::InvalidArgumentError( 72 0 : "Certificate validity period is always ignored without trusted CA"); 73 0 : } 74 0 : } 75 0 : return absl::OkStatus(); 76 0 : } 77 : 78 : std::vector<envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher> 79 : CertificateValidationContextConfigImpl::getSubjectAltNameMatchers( 80 0 : const envoy::extensions::transport_sockets::tls::v3::CertificateValidationContext& config) { 81 0 : std::vector<envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher> 82 0 : subject_alt_name_matchers(config.match_typed_subject_alt_names().begin(), 83 0 : config.match_typed_subject_alt_names().end()); 84 : // If typed subject alt name matchers are provided in the config, don't check 85 : // for the deprecated non-typed field. 86 0 : if (!subject_alt_name_matchers.empty()) { 87 : // Warn that we're ignoring the deprecated san matcher field, if both are 88 : // specified. 89 0 : if (!config.match_subject_alt_names().empty()) { 90 0 : ENVOY_LOG_MISC(warn, 91 0 : "Ignoring match_subject_alt_names as match_typed_subject_alt_names is also " 92 0 : "specified, and the former is deprecated."); 93 0 : } 94 0 : return subject_alt_name_matchers; 95 0 : } 96 : // Handle deprecated string type san matchers without san type specified, by 97 : // creating a matcher for each supported type. 98 0 : for (const envoy::type::matcher::v3::StringMatcher& matcher : config.match_subject_alt_names()) { 99 0 : static constexpr std::array< 100 0 : envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::SanType, 4> 101 0 : san_types{envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::DNS, 102 0 : envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::URI, 103 0 : envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::EMAIL, 104 0 : envoy::extensions::transport_sockets::tls::v3::SubjectAltNameMatcher::IP_ADDRESS}; 105 0 : for (const auto san_type : san_types) { 106 0 : subject_alt_name_matchers.emplace_back(); 107 0 : subject_alt_name_matchers.back().set_san_type(san_type); 108 0 : *subject_alt_name_matchers.back().mutable_matcher() = matcher; 109 0 : } 110 0 : } 111 0 : return subject_alt_name_matchers; 112 0 : } 113 : 114 : } // namespace Ssl 115 : } // namespace Envoy