Skip to content

Commit 4e752f6

Browse files
committed
quic: support hostname verification
Signed-off-by: James M Snell <jasnell@gmail.com>
1 parent fd6831a commit 4e752f6

5 files changed

Lines changed: 37 additions & 1 deletion

File tree

lib/internal/quic/quic.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5133,6 +5133,11 @@ function processSessionOptions(options, config = kEmptyObject) {
51335133
// client SSL_CTX. For 'auto' and 'manual' modes, the handshake
51345134
// completes regardless and the result is handled in JS.
51355135
verifyPeerStrict: verifyPeer === 'strict',
5136+
// Enable hostname verification for 'strict' and 'auto' modes.
5137+
// SSL_set1_host tells OpenSSL to verify the server certificate's
5138+
// SAN/CN matches the servername. Without this, a valid cert for
5139+
// any domain would be accepted.
5140+
verifyHostname: verifyPeer !== 'manual',
51365141
},
51375142
verifyPeer,
51385143
qlog,

src/quic/bindingdata.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ class SessionManager;
169169
V(unacknowledged_packet_threshold, "unacknowledgedPacketThreshold") \
170170
V(validate_address, "validateAddress") \
171171
V(verify_client, "verifyClient") \
172+
V(verify_hostname, "verifyHostname") \
172173
V(verify_peer_strict, "verifyPeerStrict") \
173174
V(verify_private_key, "verifyPrivateKey") \
174175
V(version, "version")

src/quic/streams.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,7 @@ void Stream::EmitClose(const QuicError& error) {
18911891
}
18921892

18931893
void Stream::EmitHeaders() {
1894+
STAT_RECORD_TIMESTAMP(Stats, received_at);
18941895
// state()->wants_headers will be set from the javascript side if the
18951896
// stream object has a handler for the headers event.
18961897
if (!env()->can_call_into_js() || !state()->wants_headers) {

src/quic/tlscontext.cc

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,18 @@ bool OSSLContext::set_hostname(std::string_view hostname) const {
261261
const_cast<char*>(name.c_str())) == 1;
262262
}
263263

264+
bool OSSLContext::set_verify_hostname(std::string_view hostname) const {
265+
// SSL_set1_host tells OpenSSL to verify the peer certificate's
266+
// subject name (SAN/CN) matches this hostname. This is separate
267+
// from SSL_set_tlsext_host_name which only sets the SNI extension.
268+
static const char* kDefaultHostname = "localhost";
269+
if (hostname.empty()) {
270+
return SSL_set1_host(*this, kDefaultHostname) == 1;
271+
} else {
272+
return SSL_set1_host(*this, hostname.data()) == 1;
273+
}
274+
}
275+
264276
bool OSSLContext::set_early_data_enabled() const {
265277
return SSL_set_quic_tls_early_data_enabled(*this, 1) == 1;
266278
}
@@ -714,7 +726,8 @@ Maybe<TLSContext::Options> TLSContext::Options::From(Environment* env,
714726
env, &options, params, state.name##_string())
715727

716728
if (!SET(verify_client) || !SET(reject_unauthorized) ||
717-
!SET(verify_peer_strict) || !SET(enable_early_data) ||
729+
!SET(verify_hostname) || !SET(verify_peer_strict) ||
730+
!SET(enable_early_data) ||
718731
!SET(enable_tls_trace) || !SET(alpn) || !SET(servername) ||
719732
!SET(ciphers) || !SET(groups) || !SET(verify_private_key) ||
720733
!SET(keylog) || !SET(port) || !SET(authoritative) ||
@@ -854,6 +867,14 @@ void TLSSession::Initialize(
854867
return;
855868
}
856869

870+
if (options.verify_hostname) {
871+
if (!ossl_context_.set_verify_hostname(options.servername)) {
872+
validation_error_ = "Failed to set verify hostname";
873+
ossl_context_.reset();
874+
return;
875+
}
876+
}
877+
857878
if (maybeSessionTicket.has_value()) {
858879
const auto& sessionTicket = *maybeSessionTicket;
859880
uv_buf_t buf = sessionTicket.ticket();

src/quic/tlscontext.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class OSSLContext final {
5151

5252
bool set_alpn_protocols(std::string_view protocols) const;
5353
bool set_hostname(std::string_view hostname) const;
54+
bool set_verify_hostname(std::string_view hostname) const;
5455
bool set_early_data_enabled() const;
5556
bool set_transport_params(const ngtcp2_vec& tp) const;
5657

@@ -215,6 +216,13 @@ class TLSContext final : public MemoryRetainer,
215216
// by the client side.
216217
bool verify_peer_strict = false;
217218

219+
// When true, OpenSSL verifies that the server's certificate matches
220+
// the servername (hostname verification via SSL_set1_host). Should
221+
// be true for 'strict' and 'auto' verifyPeer modes, false for
222+
// 'manual'. Without this, a valid certificate for any domain would
223+
// be accepted. This option is only used by the client side.
224+
bool verify_hostname = false;
225+
218226
// When true (the default), the server accepts 0-RTT early data
219227
// from clients with valid session tickets. When false, early data
220228
// is disabled and clients must complete a full handshake before

0 commit comments

Comments
 (0)