Software:
Homegrown Perl-5.34.1 (not perlbrew) Net-SSLeay 1.92 IO-Socket-SSL 2.074
[Apologies for lack of pastebin, no access from this location]
The "proxy tunnel" is HTTP, but the local firewall rules require that the connection be initiated with 'https'.
Making the connection via IO::Socket::INET and promoting it or sans handshake and performing it late don't seem to work around the proxy/tunnel issues, so I'm guessing this must require a separate socket.
Q: What is a working approach for handling the "http proxy tunnel" using IO::Socket::SSL, possibly with some other modules?
I'd prefer to avoid LWP::UserAgent if its possible, I just cannot find anything on CPAN that seems to deal with the issues.
Examples:
(1) curl --verbose
Attempting a connection from a RHEL6 platform through an intranet firewall to an HTTPS service. The service is a 'hello world' server intended to validate the SSL connection. It works from Firefox on an intranet host (not the same one as I'm using for IO::Socket:SSL). Using curl fails to connect, but shows the "proxy tunnel" (hosts and IP's munged).
curl --verbose 'https://foo.bar.net/bim/bam'
* Trying 10.10.10.10...
* Connected to 10.10.10.10 (10.10.10.10) port 80 (#0)
* Establish HTTP proxy tunnel to foo.bar.net:443
> CONNECT foo.bar.net:443 HTTP/1.1
> Host: foo.bar.net:443
> User-Agent: curl/7.44.0
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 503 Service Unavailable
< Cache-Control: no-cache
< X-XSS-Protection: 1
< Connection: close
< Content-Type: text/html; charset=utf-8
< Content-Length: 750
< Pragma: no-cache
< Set-Cookie: frobnicate; path=/; Httponly
<
* Received HTTP code 503 from proxy after CONNECT
* Closing connection 0
curl: (56) Received HTTP code 503 from proxy after CONNECT
(2) IO:Socket::SSL alone
The tunnel doesn't appear to be transparent:
41: $IO::Socket::SSL::DEBUG = 3;
42: IO::Socket::SSL->new
43: (
44: PeerAddr => $auth
45: , PeerPort => 'https'
46: )
DB<1>
DEBUG: .../IO/Socket/SSL.pm:2961: new ctx 54179840
DEBUG: .../IO/Socket/SSL.pm:704: socket not yet connected
DEBUG: .../IO/Socket/SSL.pm:706: socket connected
DEBUG: .../IO/Socket/SSL.pm:729: ssl handshake not started
DEBUG: .../IO/Socket/SSL.pm:771: using SNI with hostname foo.bar.com
DEBUG: .../IO/Socket/SSL.pm:806: request OCSP stapling
DEBUG: .../IO/Socket/SSL.pm:836: call Net::SSLeay::connect
DEBUG: .../IO/Socket/SSL.pm:2852: did not get stapled OCSP response
DEBUG: .../IO/Socket/SSL.pm:2805: ok=0 [0] /C=US/O=DigiCert Inc/CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1/C=US/ST=New York/L=Someplace/O=Foo Bar, Inc./CN=foo.bar.com
DEBUG: .../IO/Socket/SSL.pm:839: done Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:842: SSL connect attempt failed
DEBUG: .../IO/Socket/SSL.pm:842: local error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
DEBUG: .../IO/Socket/SSL.pm:845: fatal SSL error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
DEBUG: ...inux/IO/Socket.pm:50: ignoring less severe local error 'IO::Socket::IP configuration failed', keep 'SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed'
DEBUG: .../IO/Socket/SSL.pm:3010: free ctx 54179840 open=
DEBUG: .../IO/Socket/SSL.pm:3014: free ctx 54179840 callback
DEBUG: .../IO/Socket/SSL.pm:3021: OK free ctx 54179840
not ok 1 - Direct: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed.
The POD for IO::Socket::SSL has two suggestions for possibly working around this situation:
(3) INET socket + Promotion:
my $sock = IO::Socket::INET->new(...) or die $!;
IO::Socket::SSL->start_SSL($sock,%sslargs) or die $SSL_ERROR;
$sock->stop_SSL or die $SSL_ERROR;
41: my $sock
42: = IO::Socket::INET->new
43: (
44: PeerAddr => $auth
45: , PeerPort => 'https'
46: )
47: or die "INET: $IO::Socket::errstr\n";
49: IO::Socket::SSL->start_SSL
50: (
51: $sock
52: , 'PeerPort' => 'https'
53: )
54: or die "SSL: $SSL_ERROR\n";
DB<1>
DEBUG: .../IO/Socket/SSL.pm:2961: new ctx 58865232
DEBUG: .../IO/Socket/SSL.pm:1561: start handshake
DEBUG: .../IO/Socket/SSL.pm:729: ssl handshake not started
DEBUG: .../IO/Socket/SSL.pm:774: not using SNI because hostname is unknown
DEBUG: .../IO/Socket/SSL.pm:806: request OCSP stapling
DEBUG: .../IO/Socket/SSL.pm:836: call Net::SSLeay::connect
DEBUG: .../IO/Socket/SSL.pm:2852: did not get stapled OCSP response
DEBUG: .../IO/Socket/SSL.pm:2805: ok=0 [0] /C=US/O=DigiCert Inc/CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1/C=US/ST=New York/L=Edgewood/O=Foo Bar, Inc./CN=foo.bar.com
DEBUG: .../IO/Socket/SSL.pm:839: done Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:842: SSL connect attempt failed
DEBUG: .../IO/Socket/SSL.pm:842: local error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
DEBUG: .../IO/Socket/SSL.pm:845: fatal SSL error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
DEBUG: .../IO/Socket/SSL.pm:1984: downgrading SSL only, not closing socket
DEBUG: .../IO/Socket/SSL.pm:3010: free ctx 58865232 open=
DEBUG: .../IO/Socket/SSL.pm:3014: free ctx 58865232 callback
DEBUG: .../IO/Socket/SSL.pm:3021: OK free ctx 58865232
BRCC::FM::Test::(bin/socket-check:55):
(4) SSL socket with delayed handshake:
41: my $sock
42: = IO::Socket::SSL->new
43: (
44: PeerAddr => $auth
45: , PeerPort => 'https'
46: , SSL_startHandshake => 0
47: )
48: or die "SSL: $SSL_ERROR";
DB<1>
DEBUG: .../IO/Socket/SSL.pm:2961: new ctx 43293280
DEBUG: .../IO/Socket/SSL.pm:704: socket not yet connected
DEBUG: .../IO/Socket/SSL.pm:706: socket connected
BRCC::FM::Test::(bin/socket-check:50):
50: $sock->connect_SSL
51: or die "Connect: $SSL_ERROR";
DB<1>
DEBUG: .../IO/Socket/SSL.pm:729: ssl handshake not started
DEBUG: .../IO/Socket/SSL.pm:771: using SNI with hostname foo.bar.com
DEBUG: .../IO/Socket/SSL.pm:806: request OCSP stapling
DEBUG: .../IO/Socket/SSL.pm:836: call Net::SSLeay::connect
DEBUG: .../IO/Socket/SSL.pm:2852: did not get stapled OCSP response
DEBUG: .../IO/Socket/SSL.pm:2805: ok=0 [0] /C=US/O=DigiCert Inc/CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1/C=US/ST=New York/L=Edgewood/O=Foo Bar, Inc./CN=foo.bar.com
DEBUG: .../IO/Socket/SSL.pm:839: done Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:842: SSL connect attempt failed
DEBUG: .../IO/Socket/SSL.pm:842: local error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
DEBUG: .../IO/Socket/SSL.pm:845: fatal SSL error: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
DEBUG: .../IO/Socket/SSL.pm:3010: free ctx 43293280 open=
DEBUG: .../IO/Socket/SSL.pm:3014: free ctx 43293280 callback
DEBUG: .../IO/Socket/SSL.pm:3021: OK free ctx 43293280
(5) Disabling SSL_verify_mode didn't get much further with ssl_handshake turned on:
41: my $sock
42: = IO::Socket::SSL->new
43: (
44: PeerAddr => $auth
45: , PeerPort => 'https'
46: , SSL_startHandshake => 1
47: , SSL_verify_mode => 0
48: )
49: or die "SSL: $SSL_ERROR";
DB<1>
DEBUG: .../IO/Socket/SSL.pm:2537: new ctx 50291120
DEBUG: .../IO/Socket/SSL.pm:529: socket not yet connected
DEBUG: .../IO/Socket/SSL.pm:531: socket connected
DEBUG: .../IO/Socket/SSL.pm:553: ssl handshake not started
DEBUG: .../IO/Socket/SSL.pm:586: using SNI with hostname foo.bar.com
DEBUG: .../IO/Socket/SSL.pm:653: Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:1769: SSL connect attempt failed
DEBUG: .../IO/Socket/SSL.pm:1774: SSL connect attempt failed error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
DEBUG: .../IO/Socket/SSL.pm:659: fatal SSL error: SSL connect attempt failed error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
DEBUG: .../IO/Socket/SSL.pm:1758: IO::Socket::INET configuration failed
DEBUG: .../IO/Socket/SSL.pm:2570: free ctx 50291120 open=50291120
DEBUG: .../IO/Socket/SSL.pm:2582: OK free ctx 50291120
(6) Delaying the handshake gets the same result:
41: my $sock
42: = IO::Socket::SSL->new
43: (
44: PeerAddr => $auth
45: , PeerPort => 'https'
46: , SSL_startHandshake => 0
47: , SSL_verify_mode => 0
48: )
49: or die "SSL: $SSL_ERROR";
DB<1>
DEBUG: .../IO/Socket/SSL.pm:2537: new ctx 42963376
DEBUG: .../IO/Socket/SSL.pm:529: socket not yet connected
DEBUG: .../IO/Socket/SSL.pm:531: socket connected
BRCC::FM::Test::(bin/socket-check:51):
51: $sock->connect_SSL
52: or die "Connect: $SSL_ERROR";
DB<1>
DEBUG: .../IO/Socket/SSL.pm:553: ssl handshake not started
DEBUG: .../IO/Socket/SSL.pm:586: using SNI with hostname foo.bar.net
DEBUG: .../IO/Socket/SSL.pm:653: Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:1769: SSL connect attempt failed
DEBUG: .../IO/Socket/SSL.pm:1774: SSL connect attempt failed error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
DEBUG: .../IO/Socket/SSL.pm:659: fatal SSL error: SSL connect attempt failed error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
DEBUG: .../IO/Socket/SSL.pm:2570: free ctx 42963376 open=42963376
DEBUG: .../IO/Socket/SSL.pm:2582: OK free ctx 42963376
SSL_verify_mode => 0to disable certificate validation as a quick workaround. But this should not be done in production because it opens the connection up for man in the middle attacks.