curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number - ssl

When I try to connect to any server (e.g. google.com) using curl (or libcurl) I get the error message:
curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number
Verbose output:
$ curl www.google.com --verbose
* Rebuilt URL to: www.google.com/
* Uses proxy env variable no_proxy == 'localhost,127.0.0.1,localaddress,.localdomain.com'
* Uses proxy env variable http_proxy == 'https://proxy.in.tum.de:8080'
* Trying 131.159.0.2...
* TCP_NODELAY set
* Connected to proxy.in.tum.de (131.159.0.2) port 8080 (#0)
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* error:1408F10B:SSL routines:ssl3_get_record:wrong version number
* Closing connection 0
curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number'
For some reason curl seems to use TLSv1.3 even if I force it to use TLSv1.2 with the command --tlsv1.2 (it will still print TLSv1.3 (OUT), ..."
I am using the newest version of both Curl and OpenSSL :
$ curl -V
curl 7.61.0-DEV (x86_64-pc-linux-gnu) libcurl/7.61.0-DEV OpenSSL/1.1.1 zlib/1.2.8
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP UnixSockets HTTPS-proxy
I think this is a problem related to my installation of the programms.
Can somebody explain to me what this error message means?

* Uses proxy env variable http_proxy == 'https://proxy.in.tum.de:8080'
^^^^^
The https:// is wrong, it should be http://. The proxy itself should be accessed by HTTP and not HTTPS even though the target URL is HTTPS. The proxy will nevertheless properly handle HTTPS connection and keep the end-to-end encryption. See HTTP CONNECT method for details how this is done.

If anyone is getting this error using Nginx, try adding the following to your server config:
server {
listen 443 ssl;
...
}
The issue stems from Nginx serving an HTTP server to a client expecting HTTPS on whatever port you're listening on. When you specify ssl in the listen directive, you clear this up on the server side.

This is a telltale error that you are serving HTTP from the HTTPS port.
You can easily test with telnet
telnet FQDN 443
GET / HTTP/1.0
[hit return twice]
and if you see regular HTTP document here [not some kind of error], you know that your configuration is incorrect and the responding server is not SSL encrypting the response.

Simple answer
If you are behind a proxy server, please set the proxy for curl. The curl is not able to connect to server so it shows wrong version number.
Set proxy by opening subl ~/.curlrc or use any other text editor. Then add the following line to file:
proxy= proxyserver:proxyport
For e.g. proxy = 10.8.0.1:8080
If you are not behind a proxy, make sure that the curlrc file does not contain the proxy settings.

Also check your /etc/hosts file. Wasted 2 hours on this. If you have an url rerouted to 127.0.0.1 or any other loopback, this will fail the ssl handshake.

In my case the cause of this error was that my web server was not configured to listen to IPv6 on SSL port 443. After enabling it the error disappeared.
Here's how you do it for Apache:
<VirtualHost ip.v4.address:443 ip:v::6:address:443>
...
</VirtualHost>
And for nginx:
listen 443 ssl http2;
listen [::]:443 ssl http2;

Thanks to #bret-weinraub,
I found that something is weird about the server's reply. After a bit of investigation, it turned out that I have a static IP in /etc/hosts file for the target domain and as they have changed their IP address I'm not getting to the correct server.

More simply in one line:
proxy=192.168.2.1:8080;curl -v example.com
eg. $proxy=192.168.2.1:8080;curl -v example.com
xxxxxxxxx-ASUS:~$ proxy=192.168.2.1:8080;curl -v https://google.com|head -c 15 % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
* Trying 172.217.163.46:443...
* TCP_NODELAY set
* Connected to google.com (172.217.163.46) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]

Another possible cause of this problem is if you have not enabled the virtual host's configuration file in Apache (or if you don't have that virtual host at all) and the default virtual host in Apache is only configured for non-SSL connections -- ie there's no default virtual host which can talk SSL. In this case because Apache is listening on port 443 the request for the virtual host that doesn't exist will arrive at the default virtual host -- but that virtual host doesn't speak SSL.

In the case of using MySQL CLI to connect to an external MySQL DB, depending on the version of MySQL, you can pass the --ssl-mode=disabled like:
$ mysql --ssl-mode=disabled -h yourhost.tld -p
Or simply in your client config, for example in /etc/my.cnf.d/client.cnf:
[client]
ssl-mode=DISABLED
This is for dev and sometimes security and these things can be forfeited in certain situations in a closed, private dev environment.

Related

Debugging curl SSL error 14094438 with Caddy

Caddy thinks everything is fine:
{"level":"info","ts":...,"logger":"tls.issuance.acme.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-v02.api.letsencrypt.org/acme/order/.../..."}
{"level":"info","ts":...,"logger":"tls.issuance.acme.acme_client","msg":"successfully downloaded available certificate chains","count":2,"first_url":"https://acme-v02.api.letsencrypt.org/acme/cert/..."}
{"level":"info","ts":...,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"service.internal.example.com"}
{"level":"info","ts":...,"logger":"tls.obtain","msg":"releasing lock","identifier":"service.internal.example.com"}
Inside the Caddy container:
# curl https://localhost/ -H "Host: service.internal.example.com" -v
* Trying 127.0.0.1:443...
* Connected to localhost (127.0.0.1) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS alert, internal error (592):
* error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
* Closing connection 0
curl: (35) error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
Caddyfile:
{
acme_dns cloudflare ... # github.com/caddy-dns/cloudflare
}
service.internal.example.com {
reverse_proxy localhost:1234 # curl localhost:1234 works
}
Wget throws the same error text with a slightly different error number:
# wget https://localhost/ --header "Host: service.internal.example.com" -v
--...-- https://localhost/
Resolving localhost (localhost)... 127.0.0.1, ::1
Connecting to localhost (localhost)|127.0.0.1|:443... connected.
OpenSSL: error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
Unable to establish SSL connection.
Thanks to #Buffoonism, I've tried:
$ curl https://service.internal.example.com --resolve service.internal.example.com:443:127.0.0.1
This call (inside the Caddy container) has a successful 200 response. I've backed out to the server and same result:
$ curl https://service.internal.example.com --resolve service.internal.example.com:443:10.1.2.3.4 # works
So, this seems to be my clue: a host header of service.internal.example.com fails, but curl's resolve flag works.
I'm not sure what my next steps are
It looks like a TLS SNI thing. Because you connect to localhost, curl and wget will be sending a TLS SNI of localhost, not service.internal.example.com. Which means the server rejects it.
As an alternative approach, use curl's resolve option to pin the address to the domain:
curl https://service.internal.example.com --resolve service.internal.example.com:443:127.0.0.1

Unable to connect curl on HTTPS

I am trying to connect to server B from server A using curl (https). I have already tried with -k and it doesn't work.
I have looked into several posts and I spotted blog on this link but still issue exists.
When I do a curl from server A, I am getting following error:
* Rebuilt URL to: https://x.x.x.x:8443/
* Hostname was NOT found in DNS cache
* Trying x.x.x.x...
* Connected to x.x.x.x (x.x.x.x) port 8443 (#0)
* successfully set certificate verify locations:
* CAfile: /tmp/cert_test/certRepo
CApath: /etc/ssl/certs/
* SSLv3, TLS handshake, Client hello (1):
* error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol
* Closing connection 0
curl: (35) error:140770FC:**SSL routines:SSL23_GET_SERVER_HELLO:**unknown protocol
I went on the server B (https://x.x.x.x:8443/) from the browser and downloaded the root, intermediate and the client certificate. As suggested in the blog, I have created a new folder and combined all the public certs into one directory and tried to execute the curl command
curl -v --cacert /tmp/cert_test/certRepo https://x.x.x.x:8443
I am getting GET_SERVER_HELLO:unknown protocol
any thoughts?
Curl version from the Client machine:
curl 7.37.0 (x86_64-suse-linux-gnu)
libcurl/7.37.0 OpenSSL/0.9.8j
zlib/1.2.7
libidn/1.10
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smtp smtps telnet
tftp
Features: GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz
I am very sure the server is using TLSv1.2.
you did not post your curl/libssl version, but my best guess is that you're using an ancient build of a ssl/tls library, and/or an ancient version of curl which does not support whatever version of ssl/tls that server us ysubg. update your libssl and curl and try again. also post the output of curl --version.
PS, if you're on linux, you can get rough curl+openssl compile instructions here.

How to construct CURL FTPS command in Windows 10 Command Prompt for FTP with TLS

I'm on Windows 10 Professional Plus
I have a CURL command in DOS that works fine for standard FTP on Port 21
Once I'm in the folder C:\Program Files\cURL\bin> I issue the command:
curl -v -T (C:\folders\file_to_be_transferred.pdf) ftp://(username):(password)#(host.top_level_domain.com)/file_to_be_transferred.pdf
I'm trying to transfer the file using FTP over TLS. When I change FTP to FTPS and change the command to:
curl -v -T (C:\folders\file_to_be_transferred.pdf) ftps://(username):(password)#(host.top_level_domain.com)/file_to_be_transferred.pdf
I get the following response from CURL:
* Hostname was NOT found in DNS cache
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 999.999.999.999...
* Connected to host.top_level_domain.com (999.999.999.999) port 21 (#0)
* successfully set certificate verify locations:
* CAfile: C:\Program Files\cURL\bin\curl-ca-bundle.crt
CApath: none
* SSLv3, TLS handshake, Client hello (1):
} [data not shown]
* error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol
* Closing connection 0
curl: (35) error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol
When I request the CURL version using CURL -V I get the following response:
curl 7.39.0 (x86_64-pc-win32) libcurl/7.39.0 OpenSSL/1.0.1g zlib/1.2.8 WinIDN libssh2/1.4.3 Protocols: dict file ftp ftps gopher http https imap imaps ldap pop3 pop3s rtsp scp sftp smtp smtps telnet tftp Features: AsynchDNS IDN IPv6 Largefile SSPI SPNEGO NTLM SSL libz
How do I enable TLS over FTP with CURL on Windows 10?
Thanks for looking at this.
I resolved the problem. It was how I referenced the certificates. Earlier I had transferred the certificate generated by the FileZilla Server (certificate.crt) to the Windows Client. I placed that certificate file in the folder C:\Program Files\cURL\bin. Also, I copied the contents of certificate.crt and appended it to the existing certificate called curl-ca-bundle.crt. Appending the new certificate to that bundle file is very important. That was my problem. Now, when I reference only the FileZilla_Server generated certificate in the client's CURL command, the transfer works. It seems that cURL will always reference the curl-ca-bundle.crt file in addition to what is referenced in the command line. The logs referenced the details of the SSLv3 handshake. Also I restructured the command a little bit to make it more readable. Here it is:
curl --user username:password --cert "C:\Program Files\cURL\bin\certificate.crt" -v -T C:\folder_and_file_to_be_transferred.pdf ftps://host.top_level_domain.com/filename.pdf
By the way, the default port for FTPS is 990. On the router I had to open up port 990 and the port range 20101-20120. I did NOT have to open up port 21 since I was using ftpS.
I hope this helps someone else.

What's the equivalent of "RedirectMatch" from Apache using Traefik?

I'm trying to set up a frontend redirect using Traefik, but the docs don't explain how to do so.
I have an existing VirtualHost configuration in Apache that does this via:
ServerName jira.mycompany.com
RedirectMatch /.* https://mycompany.atlassian.net/
I thought that I should be able to do the same thing via my routes.toml file, like so:
[frontends]
[frontends.jira]
backend = "jira"
[frontends.jira.redirect]
regex = "^https?://jira.mycompany.com/(.*)"
replacement = "https://mycompany.atlassian.net/$1"
[backends]
[backend.jira]
[backend.jira.servers.primary]
url = "https://mycompany.atlassian.net"
However, trying to connect to https://jira.mycompany.com gives me an SSL protocol error.
curl -v tells me the following:
Toms-iMac:~ tgolden$ curl -v https://jira.mycompany.com
* Rebuilt URL to: https://jira.mycompany.com/
* Trying <external IP>...
* TCP_NODELAY set
* Connected to jira.mycompany.com (<external IP>) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:#STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS alert, Server hello (2):
* error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error
* stopped the pause stream!
* Closing connection 0
curl: (35) error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error
What am I missing here?
I tried adding a "Host:jira.mycompany.com" rule as well as SSLRedirect and SSLTemporaryRedirect headers as well -- no dice.
The reason for the SSL error was due to my Traefik configuration using the deprecated acme.ondemand parameter. For an unrelated reason, the ACME challenge failed when trying to get a certificate for jira.mycompany.com, which caused the SSL handshake to fail.
I'm surprised the failed challenge for ondemand wouldn't fall back to the self-signed Traefik cert, but since the parameter was deprecated it shouldn't be as surprising.
Once I resolved this issue (ignoring the cert issue for the moment) the redirect worked as expected.

Nginx load balancer upstream SSL and Docker

I'm trying to balance between differents Docker containers, each Docker container has an Nginx and the web server has an SSL certificate.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b1364b46632c web "/usr/bin/supervisord" 22 minutes ago Up 21 minutes 0.0.0.0:8001->443/tcp webserver01
b1364b46632c web "/usr/bin/supervisord" 22 minutes ago Up 21 minutes 0.0.0.0:8002->443/tcp webserver02
And my Nginx load balancer configuration, /etc/nginx/conf.d/default.conf
upstream pool_webservers {
server localhost:8001;
server localhost:8002;
}
server {
listen 443;
location / {
proxy_pass https://pool_webservers;
}
}
I can't make it works, if I run a curl -vvv https://localhost:8001 or curl -vvv https://localhost:8002 the server response fine with the SSL certificate, but if a run a curl -vvv https://localhost:443, returns
$ curl -vvv https://localhost:443
* Rebuilt URL to: https://localhost:443/
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* NSS error -12263 (SSL_ERROR_RX_RECORD_TOO_LONG)
* SSL received a record that exceeded the maximum permissible length.
* Closing connection 0
curl: (35) SSL received a record that exceeded the maximum permissible length.
Thanks!
UPDATE 1:
I was reading and the best solution, it's add the SSL certificate on the side of the load balancer, and the Docker containers (nginx web server) without the certificate.
Like this:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ec14fa21ef3d dignajar/bludit "/usr/bin/supervisord" 2 hours ago Up 2 hours 0.0.0.0:8001->80/tcp webserver01
ac14fa21ef1a dignajar/bludit "/usr/bin/supervisord" 2 hours ago Up 2 hours 0.0.0.0:8002->80/tcp webserver02
Here is my virtual host for Nginx, with the SSL certificate of mydomain.
upstream pool_webservers {
server localhost:8001;
server localhost:8002;
}
server {
listen 443 ssl;
server_name mydomain.here.com;
ssl_certificate /etc/...;
ssl_certificate_key /etc/...;
....
location / {
proxy_pass http://pool_webservers;
}
}
PD: have everything on the same server is not good idea, it's just for this example.
change the listen line to specify ssl?
listen 443 ssl;