Skip to content

Commit 5fa1868

Browse files
karesclaude
andcommitted
avoid double hostname verification in post_connection_check
After connect verifies the hostname (via verify_hostname), stash it on the socket. A subsequent post_connection_check for the same hostname (e.g. from net/http) returns immediately instead of re-checking. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 44bce7d commit 5fa1868

2 files changed

Lines changed: 13 additions & 4 deletions

File tree

lib/openssl/ssl.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,13 @@ def sysclose
427427
# This method MUST be called after calling #connect to ensure that the
428428
# hostname of a remote peer has been verified.
429429
def post_connection_check(hostname)
430+
# If connect already verified this hostname (via verify_hostname), skip.
431+
# Avoids double-verification in libraries that call post_connection_check.
432+
if defined?(@verified_hostname) && @verified_hostname == hostname
433+
@verified_hostname = nil
434+
return true
435+
end
436+
430437
if peer_cert.nil?
431438
msg = "Peer verification enabled, but no certificate received."
432439
if using_anon_cipher?

src/main/java/org/jruby/ext/openssl/SSLSocket.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -326,9 +326,7 @@ private IRubyObject connectImpl(final ThreadContext context, final boolean block
326326
// during the handshake (ossl_ssl.c ossl_ssl_verify_callback, depth 0).
327327
// JSSE has no equivalent hook, so we check after the handshake completes.
328328
// This is functionally equivalent — connect raises SSLError on mismatch.
329-
// Note: net/http and net/imap also call post_connection_check explicitly,
330-
// so this may double-check in those cases (harmless, same result).
331-
verifyHostnameIfRequired(context);
329+
verifyHostnameConnectionCheck(context);
332330

333331
return this;
334332
}
@@ -419,7 +417,7 @@ private IRubyObject acceptImpl(final ThreadContext context, final boolean blocki
419417
return this;
420418
}
421419

422-
private void verifyHostnameIfRequired(final ThreadContext context) {
420+
private void verifyHostnameConnectionCheck(final ThreadContext context) {
423421
final IRubyObject verifyHostname = sslContext.getInstanceVariable("@verify_hostname");
424422
if (verifyHostname == null || !verifyHostname.isTrue()) return;
425423

@@ -429,6 +427,10 @@ private void verifyHostnameIfRequired(final ThreadContext context) {
429427
// delegates to post_connection_check (defined in Ruby) which calls
430428
// OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
431429
callMethod(context, "post_connection_check", hostname);
430+
431+
// stash verified hostname so a subsequent explicit post_connection_check
432+
// (e.g. from net/http) does not execute the check twice (to match MRI)
433+
setInstanceVariable("@verified_hostname", hostname);
432434
}
433435

434436
final IRubyObject verify_mode(final ThreadContext context) {

0 commit comments

Comments
 (0)