Nginx reverse proxy error: SSL alert number 47 while SSL handshaking to upstream

Written by - 0 comments

Published on - Listed in Nginx Security TLS


After a Nginx reverse proxy was upgraded from Ubuntu 16.04 to 20.04 (which also upgrades Nginx from 1.10.0 to 1.18.0) problems with upstream servers using encrypted HTTPS were seen.

Besides the usual suspects, meaning Nginx configuration changes after upgrading Ubuntu from 16.04 to 20.04, another problem source comes into play when using https to connect to upstream servers: OpenSSL.

Connection to https upstream not working anymore

Right after the reverse proxy server was upgraded, the communication with the upstream server (a J2EE application running on Java 8) stopped working.

SSL handshake error after reverse proxy OS upgrade

The end users received a 503 error from the reverse proxy, in the error logs a SSL handshake error was logged for each request:

ck@reverseproxy1:~$ cat /var/log/nginx/app.example.com.error.log
2021/06/18 08:42:54 [error] 3572193#3572193: *25015655 SSL_do_handshake() failed (SSL: error:14094417:SSL routines:ssl3_read_bytes:sslv3 alert illegal parameter:SSL alert number 47) while SSL handshaking to upstream, client: 31.10.153.242, server: app.example.com, request: "GET /console-selfservice HTTP/2.0", upstream: "https://10.10.23.45:7004/console-selfservice", host: "app.example.com"

Even a manual curl launched from the reverseproxy1 machine (now running Ubuntu 20.04) didn't work anymore:

ck@reverseproxy1:~$ curl https://10.10.23.45:7004 -v
*   Trying 10.10.23.45:7004...
* TCP_NODELAY set
* Connected to 10.10.23.45 (10.10.23.45) port 7004 (#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
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS alert, illegal parameter (559):
* error:14094417:SSL routines:ssl3_read_bytes:sslv3 alert illegal parameter
* Closing connection 0
curl: (35) error:14094417:SSL routines:ssl3_read_bytes:sslv3 alert illegal parameter

And even with a manual openssl connect the communication wouldn't work:

ck@reverseproxy1:~$ openssl s_client -connect 10.10.23.45:7004
CONNECTED(00000003)
139787141846336:error:14094417:SSL routines:ssl3_read_bytes:sslv3 alert illegal parameter:../ssl/record/rec_layer_s3.c:1543:SSL alert number 47
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 283 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---

Again the illegal parameter is showing up....

Outdated SSL/TLS protocols?

The first thought was that the (dated) upstream application was maybe still using outdated SSL/TLS protocols, such as SSLv3 and TLSv1. This would actually explain the communication problems as these protocols were disabled in newer OpenSSL versions. Now that OpenSSL 1.1.1f is installed on the upgraded Ubuntu 20.04, the minimum protocol is (by default) set to TLSv1.2 for all TLS libraries.

But a manual check using openssl revealed that the J2EE application in fact responds to TLSv1.2:

j2eeserver:/ # openssl s_client -connect localhost:7004
CONNECTED(00000003)
[...]
---
No client certificate CA names sent
Peer signing digest: SHA1
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 2323 bytes and written 419 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: 60CC92015D97DDFF8690496B48EC4C8BE2BEBD637568A136DE77C913F70EC683
    Session-ID-ctx:
    Master-Key: 7EBCAEA44CECD2A9202BD86EBA9539CCE945B05587574AFA0EB3F71C9B54F0CB9611D16E7C996033BA015433F67C48E0
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1624019457
    Timeout   : 300 (sec)
    Verify return code: 19 (self signed certificate in certificate chain)
---

Looking at the OpenSSL SECLEVEL

But the Ubuntu 20.04 OpenSSL settings don't only affect the SSL/TLS protocols, but also the SSL/TLS ciphers to use for encrypted communications. Over the years, previously secure ciphers can suddenly change to insecure as vulnerabilities and performant crypto-crackers come up. As the ciphers from the application server are defined by a Java 8 application, it is more than likely that the used ciphers are meanwhile deemed insecure and the TLS libraries (which are used by Nginx, too) refuse the communication. 

Note: A kind of similar problem was also experienced in a Perl script which was unable to connect to a TLS 1.2 URL.

By overwriting the hard-coded OpenSSL defaults and allowing less secure ciphers, the TLS libraries should be able to communicate with deprecated/insecure ciphers again. At the end of /etc/ssl/openssl.cnf append the following content:

ck@reverseproxy1:~$ tail -n 10 /etc/ssl/openssl.cnf

[ default_conf ]

ssl_conf = ssl_sect

[ssl_sect]

system_default = ssl_default_sect

[ssl_default_sect]
MinProtocol = TLSv1
CipherString = DEFAULT:@SECLEVEL=1

By setting SECLEVEL to 1, this tells OpenSSL to accept RSA, DSA and DH keys with a size of 1024bit. Also RC4 cipher suites are allowed. Here's a quick overview of the different OpenSSL security levels:

 SECLEVEL  Security bit size
 Ciphers  Protocol
 0  no restrictions
 no restrictions
 no restrictions
 1
 Any parameters offering below 80 bits of security are excluded. As a result RSA, DSA and DH keys shorter than 1024 bits and ECC keys shorter than 160 bits are prohibited.
 All export cipher suites are prohibited since they all offer less than 80 bits of security. Any cipher suite using MD5 for the MAC is also prohibited.
 SSL version 2 is prohibited.
 2
 Security level set to 112 bits of security. As a result RSA, DSA and DH keys shorter than 2048 bits and ECC keys shorter than 224 bits are prohibited.
 Any cipher suite using RC4 is also prohibited.
 SSL version 3 is not allowed.
 3
 Security level set to 128 bits of security. As a result RSA, DSA and DH keys shorter than 3072 bits and ECC keys shorter than 256 bits are prohibited.
 Cipher suites not offering forward secrecy are prohibited
 TLS versions below 1.1 are not permitted
 4
 Security level set to 192 bits of security. As a result RSA, DSA and DH keys shorter than 7680 bits and ECC keys shorter than 384 bits are prohibited.
 Cipher suites using SHA1 for the MAC are prohibited.
 TLS versions below 1.2 are not permitted.
 5
 Security level set to 256 bits of security. As a result RSA, DSA and DH keys shorter than 15360 bits and ECC keys shorter than 512 bits are prohibited.
 same as Level 4
same as Level 4

Validation of the workaround

As soon as /etc/ssl/openssl.cnf was adjusted, the communication from the reverse proxy to the upstream server worked again. This could be verified using openssl from the reverse proxy again:

ck@reverseproxy1:~$ openssl s_client -connect 10.10.23.45:7004 -showcerts
CONNECTED(00000003)
[...]
---
No client certificate CA names sent
Peer signing digest: SHA1
Peer signature type: RSA
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 2323 bytes and written 451 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384

    Session-ID: 60D0A7D5BD6FC993327ACBCE333A2D4668347DA320EE3F0A6F3DF8FA53BC97BD
    Session-ID-ctx:
    Master-Key: F3F1CE2B89522292492CB2F937877066FAAFDDEF1B833BA99691482EEFE3A80820DFFF3B7C77D6DAF01DC108DB21A2B0
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1624287197
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
---



Add a comment

Show form to leave a comment

Comments (newest first)

No comments yet.

RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Office   OpenSearch   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder