1
#include "source/common/quic/quic_server_transport_socket_factory.h"
2

            
3
#include <memory>
4

            
5
#include "envoy/extensions/transport_sockets/quic/v3/quic_transport.pb.validate.h"
6

            
7
#include "source/common/quic/envoy_quic_utils.h"
8
#include "source/common/runtime/runtime_features.h"
9
#include "source/common/tls/server_context_config_impl.h"
10
#include "source/common/tls/server_context_impl.h"
11

            
12
namespace Envoy {
13
namespace Quic {
14

            
15
absl::StatusOr<Network::DownstreamTransportSocketFactoryPtr>
16
QuicServerTransportSocketConfigFactory::createTransportSocketFactory(
17
    const Protobuf::Message& config, Server::Configuration::TransportSocketFactoryContext& context,
18
2129
    const std::vector<std::string>& server_names) {
19
2129
  auto quic_transport = MessageUtil::downcastAndValidate<
20
2129
      const envoy::extensions::transport_sockets::quic::v3::QuicDownstreamTransport&>(
21
2129
      config, context.messageValidationVisitor());
22
2129
  absl::StatusOr<std::unique_ptr<Extensions::TransportSockets::Tls::ServerContextConfigImpl>>
23
2129
      server_config_or_error = Extensions::TransportSockets::Tls::ServerContextConfigImpl::create(
24
2129
          quic_transport.downstream_tls_context(), context, server_names, true);
25
2129
  RETURN_IF_NOT_OK(server_config_or_error.status());
26
2127
  auto server_config = std::move(server_config_or_error.value());
27
  // TODO(RyanTheOptimist): support TLS client authentication.
28
2127
  if (server_config->requireClientCertificate()) {
29
1
    return absl::InvalidArgumentError("TLS Client Authentication is not supported over QUIC");
30
1
  }
31

            
32
2126
  auto factory_or_error = QuicServerTransportSocketFactory::create(
33
2126
      PROTOBUF_GET_WRAPPED_OR_DEFAULT(quic_transport, enable_early_data, true),
34
2126
      context.statsScope(), std::move(server_config),
35
2126
      context.serverFactoryContext().sslContextManager());
36
2126
  RETURN_IF_NOT_OK(factory_or_error.status());
37
2126
  (*factory_or_error)->initialize();
38
2126
  return std::move(*factory_or_error);
39
2126
}
40

            
41
namespace {
42
absl::Status initializeQuicCertAndKey(Ssl::TlsContext& context,
43
2136
                                      const Ssl::TlsCertificateConfig& /*cert_config*/) {
44
  // Convert the certificate chain loaded into the context into PEM, as that is what the QUICHE
45
  // API expects. By using the version already loaded, instead of loading it from the source,
46
  // we can reuse all the code that loads from different formats, allows using passwords on the key,
47
  // etc.
48
2136
  std::vector<std::string> chain;
49
2137
  auto process_one_cert = [&](X509* cert) {
50
2137
    bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
51
2137
    int result = PEM_write_bio_X509(bio.get(), cert);
52
2137
    ASSERT(result == 1);
53
2137
    BUF_MEM* buf_mem = nullptr;
54
2137
    result = BIO_get_mem_ptr(bio.get(), &buf_mem);
55
2137
    std::string cert_str(buf_mem->data, buf_mem->length);
56
2137
    std::istringstream pem_stream(cert_str);
57
2137
    auto pem_result = quic::ReadNextPemMessage(&pem_stream);
58
2137
    if (pem_result.status != quic::PemReadResult::Status::kOk) {
59
      return absl::InvalidArgumentError(
60
          "Error loading certificate in QUIC context: error from ReadNextPemMessage");
61
    }
62
2137
    chain.push_back(std::move(pem_result.contents));
63
2137
    return absl::OkStatus();
64
2137
  };
65

            
66
2136
  RETURN_IF_NOT_OK(process_one_cert(SSL_CTX_get0_certificate(context.ssl_ctx_.get())));
67

            
68
2136
  STACK_OF(X509)* chain_stack = nullptr;
69
2136
  int result = SSL_CTX_get0_chain_certs(context.ssl_ctx_.get(), &chain_stack);
70
2136
  ASSERT(result == 1);
71
2137
  for (size_t i = 0; i < sk_X509_num(chain_stack); i++) {
72
1
    RETURN_IF_NOT_OK(process_one_cert(sk_X509_value(chain_stack, i)));
73
1
  }
74

            
75
2136
  quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain> cert_chain(
76
2136
      new quic::ProofSource::Chain(chain));
77

            
78
2136
  std::string error_details;
79
2136
  bssl::UniquePtr<EVP_PKEY> pub_key(X509_get_pubkey(context.cert_chain_.get()));
80
2136
  int sign_alg = deduceSignatureAlgorithmFromPublicKey(pub_key.get(), &error_details);
81
2136
  if (sign_alg == 0) {
82
    return absl::InvalidArgumentError(
83
        absl::StrCat("Failed to deduce signature algorithm from public key: ", error_details));
84
  }
85

            
86
2136
  context.quic_cert_ = std::move(cert_chain);
87

            
88
2136
  bssl::UniquePtr<EVP_PKEY> privateKey(
89
2136
      bssl::UpRef(SSL_CTX_get0_privatekey(context.ssl_ctx_.get())));
90
2136
  std::unique_ptr<quic::CertificatePrivateKey> pem_key =
91
2136
      std::make_unique<quic::CertificatePrivateKey>(std::move(privateKey));
92
2136
  if (pem_key == nullptr) {
93
    return absl::InvalidArgumentError("Failed to load QUIC private key.");
94
  }
95

            
96
2136
  context.quic_private_key_ = std::move(pem_key);
97
2136
  return absl::OkStatus();
98
2136
}
99
} // namespace
100

            
101
absl::StatusOr<std::unique_ptr<QuicServerTransportSocketFactory>>
102
QuicServerTransportSocketFactory::create(bool enable_early_data, Stats::Scope& store,
103
                                         Ssl::ServerContextConfigPtr config,
104
2155
                                         Envoy::Ssl::ContextManager& manager) {
105
2155
  absl::Status creation_status = absl::OkStatus();
106
2155
  auto ret = std::unique_ptr<QuicServerTransportSocketFactory>(new QuicServerTransportSocketFactory(
107
2155
      enable_early_data, store, std::move(config), manager, creation_status));
108
2155
  RETURN_IF_NOT_OK(creation_status);
109
2155
  return ret;
110
2155
}
111

            
112
QuicServerTransportSocketFactory::QuicServerTransportSocketFactory(
113
    bool enable_early_data, Stats::Scope& scope, Ssl::ServerContextConfigPtr config,
114
    Envoy::Ssl::ContextManager& manager, absl::Status& creation_status)
115
2155
    : QuicTransportSocketFactoryBase(scope, "server"), manager_(manager), stats_scope_(scope),
116
2155
      config_(std::move(config)), enable_early_data_(enable_early_data) {
117
2155
  auto ctx_or_error = createSslServerContext();
118
2155
  SET_AND_RETURN_IF_NOT_OK(ctx_or_error.status(), creation_status);
119
2155
  ssl_ctx_ = *ctx_or_error;
120
2155
}
121

            
122
2155
QuicServerTransportSocketFactory::~QuicServerTransportSocketFactory() {
123
2155
  manager_.removeContext(ssl_ctx_);
124
2155
}
125

            
126
absl::StatusOr<Envoy::Ssl::ServerContextSharedPtr>
127
2186
QuicServerTransportSocketFactory::createSslServerContext() const {
128
2186
  auto context_or_error =
129
2186
      manager_.createSslServerContext(stats_scope_, *config_, initializeQuicCertAndKey);
130
2186
  RETURN_IF_NOT_OK(context_or_error.status());
131
2184
  return *context_or_error;
132
2186
}
133

            
134
1553
ProtobufTypes::MessagePtr QuicServerTransportSocketConfigFactory::createEmptyConfigProto() {
135
1553
  return std::make_unique<
136
1553
      envoy::extensions::transport_sockets::quic::v3::QuicDownstreamTransport>();
137
1553
}
138

            
139
2131
void QuicServerTransportSocketFactory::initialize() {
140
2135
  config_->setSecretUpdateCallback([this]() {
141
    // The callback also updates config_ with the new secret.
142
31
    return onSecretUpdated();
143
31
  });
144
2131
  if (!config_->alpnProtocols().empty()) {
145
26
    supported_alpns_ = absl::StrSplit(config_->alpnProtocols(), ',');
146
26
  }
147
2131
}
148

            
149
std::pair<quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain>,
150
          std::shared_ptr<quic::CertificatePrivateKey>>
151
QuicServerTransportSocketFactory::getTlsCertificateAndKey(absl::string_view sni,
152
4730
                                                          bool* cert_matched_sni) const {
153
  // onSecretUpdated() could be invoked in the middle of checking the existence of , and using,
154
  // ssl_ctx. Capture ssl_ctx_ into a local variable so that we check and use the same ssl_ctx.
155
4730
  Envoy::Ssl::ServerContextSharedPtr ssl_ctx;
156
4730
  {
157
4730
    absl::ReaderMutexLock l(ssl_ctx_mu_);
158
4730
    ssl_ctx = ssl_ctx_;
159
4730
  }
160
4730
  if (!ssl_ctx) {
161
3
    ENVOY_LOG(warn, "SDS hasn't finished updating Ssl context config yet.");
162
3
    stats_.downstream_context_secrets_not_ready_.inc();
163
3
    *cert_matched_sni = false;
164
3
    return {};
165
3
  }
166
4727
  auto ctx =
167
4727
      std::dynamic_pointer_cast<Extensions::TransportSockets::Tls::ServerContextImpl>(ssl_ctx);
168
4727
  auto [tls_context, ocsp_staple_action] =
169
4727
      ctx->findTlsContext(sni, Ssl::CurveNIDVector{NID_X9_62_prime256v1} /* TODO: ecdsa_capable */,
170
4727
                          false /* TODO: ocsp_capable */, cert_matched_sni);
171

            
172
  // Thread safety note: accessing the tls_context requires holding a shared_ptr to the ``ssl_ctx``.
173
  // Both of these members are themselves reference counted, so it is safe to use them after
174
  // ``ssl_ctx`` goes out of scope after the function returns.
175
4727
  return {tls_context.quic_cert_, tls_context.quic_private_key_};
176
4730
}
177

            
178
31
absl::Status QuicServerTransportSocketFactory::onSecretUpdated() {
179
31
  ENVOY_LOG(debug, "Secret is updated.");
180

            
181
31
  auto ctx_or_error = createSslServerContext();
182
31
  RETURN_IF_NOT_OK(ctx_or_error.status());
183
29
  {
184
29
    absl::WriterMutexLock l(ssl_ctx_mu_);
185
29
    std::swap(*ctx_or_error, ssl_ctx_);
186
29
  }
187
29
  manager_.removeContext(*ctx_or_error);
188

            
189
29
  stats_.context_config_update_by_sds_.inc();
190
29
  return absl::OkStatus();
191
31
}
192

            
193
REGISTER_FACTORY(QuicServerTransportSocketConfigFactory,
194
                 Server::Configuration::DownstreamTransportSocketConfigFactory);
195

            
196
} // namespace Quic
197
} // namespace Envoy