Of course we cannot always share details about our work with customers, but nevertheless it is nice to show our technical achievements and share some of our implemented solutions.
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.
Right after the reverse proxy server was upgraded, the communication with the upstream server (a J2EE application running on Java 8) stopped working.
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....
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)
---
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 |
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
---