I want to disable tls 1.3 and use specific cipher suites when sending request using npm request package inside my electron app.
I found when I run it by "npm start" which actaully is "electron ."(my function is in main process), it sents tls client handshake message with an extra field "extension_supported_versions" saying supporting tls1.3. And carrying 46 cypher suites.
If it is ran by "node test.js", then only 18 cipher suites is sent out.
Reuqest package version is 2.88.0 in both cases. I wonder why such difference exists. Seems electron did something to impact the cipher suite selection process of request package.
"ELectron ."
Frame 80754: 305 bytes on wire (2440 bits), 305 bytes captured (2440 bits) on interface 0
Ethernet II, Src: IntelCor_18:36:61 (78:0c:b8:18:36:61), Dst: Tp-LinkT_9d:52:bc (bc:46:99:9d:52:bc)
Internet Protocol Version 4, Src: 192.168.1.101, Dst: 27.148.140.18
Transmission Control Protocol, Src Port: 53505, Dst Port: 443, Seq: 1, Ack: 1, Len: 251
Transport Layer Security
TLSv1.3 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 246
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 242
Version: TLS 1.2 (0x0303)
Random: b5e74f961551b2deda4486f6d138b97c0d12419b756cda10…
Session ID Length: 32
Session ID: 4e7b9be07d3d89c6e9d9ffb7bbb6fbf971b5d2912f9e8584…
Cipher Suites Length: 36
Cipher Suites (18 suites)
Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
Cipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a)
Compression Methods Length: 1
Compression Methods (1 method)
Extensions Length: 133
Extension: server_name (len=17)
Type: server_name (0)
Length: 17
Server Name Indication extension
Server Name list length: 15
Server Name Type: host_name (0)
Server Name length: 12
Server Name: api.nike.com
Extension: extended_master_secret (len=0)
Type: extended_master_secret (23)
Length: 0
Extension: renegotiation_info (len=1)
Type: renegotiation_info (65281)
Length: 1
Renegotiation Info extension
Extension: supported_groups (len=8)
Type: supported_groups (10)
Length: 8
Supported Groups List Length: 6
Supported Groups (3 groups)
Extension: ec_point_formats (len=2)
Type: ec_point_formats (11)
Length: 2
EC point formats Length: 1
Elliptic curves point formats (1)
Extension: session_ticket (len=0)
Type: session_ticket (35)
Length: 0
Data (0 bytes)
Extension: signature_algorithms (len=20)
Type: signature_algorithms (13)
Length: 20
Signature Hash Algorithms Length: 18
Signature Hash Algorithms (9 algorithms)
Extension: key_share (len=38)
Type: key_share (51)
Length: 38
Key Share extension
Extension: psk_key_exchange_modes (len=2)
Type: psk_key_exchange_modes (45)
Length: 2
PSK Key Exchange Modes Length: 1
PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1)
Extension: supported_versions (len=5)
Type: supported_versions (43)
Length: 5
Supported Versions length: 4
Supported Version: TLS 1.3 (0x0304)
Supported Version: TLS 1.2 (0x0303)
"Node test.js"
Frame 80283: 287 bytes on wire (2296 bits), 287 bytes captured (2296 bits) on interface 0
Ethernet II, Src: IntelCor_18:36:61 (78:0c:b8:18:36:61), Dst: Tp-LinkT_9d:52:bc (bc:46:99:9d:52:bc)
Internet Protocol Version 4, Src: 192.168.1.101, Dst: 27.155.111.241
Transmission Control Protocol, Src Port: 53496, Dst Port: 443, Seq: 1, Ack: 1, Len: 233
Transport Layer Security
TLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 228
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 224
Version: TLS 1.2 (0x0303)
Random: 0193f22cc60e33bca73d481c887826386fda6bd2cfb12e48…
Session ID Length: 0
Cipher Suites Length: 92
Cipher Suites (46 suites)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)
Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x0067)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)
Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x006b)
Cipher Suite: TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 (0x00a3)
Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
Cipher Suite: TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xccaa)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 (0xc0af)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CCM (0xc0ad)
Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CCM_8 (0xc0a3)
Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CCM (0xc09f)
Cipher Suite: TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 (0x00a2)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 (0xc0ae)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CCM (0xc0ac)
Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CCM_8 (0xc0a2)
Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CCM (0xc09e)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024)
Cipher Suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 (0x006a)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023)
Cipher Suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 (0x0040)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)
Cipher Suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA (0x0038)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)
Cipher Suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA (0x0032)
Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
Cipher Suite: TLS_RSA_WITH_AES_256_CCM_8 (0xc0a1)
Cipher Suite: TLS_RSA_WITH_AES_256_CCM (0xc09d)
Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
Cipher Suite: TLS_RSA_WITH_AES_128_CCM_8 (0xc0a0)
Cipher Suite: TLS_RSA_WITH_AES_128_CCM (0xc09c)
Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 (0x003d)
Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c)
Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)
Compression Methods Length: 1
Compression Methods (1 method)
Extensions Length: 91
Extension: server_name (len=17)
Type: server_name (0)
Length: 17
Server Name Indication extension
Server Name list length: 15
Server Name Type: host_name (0)
Server Name length: 12
Server Name: api.nike.com
Extension: ec_point_formats (len=4)
Type: ec_point_formats (11)
Length: 4
EC point formats Length: 3
Elliptic curves point formats (3)
Extension: supported_groups (len=10)
Type: supported_groups (10)
Length: 10
Supported Groups List Length: 8
Supported Groups (4 groups)
Extension: session_ticket (len=0)
Type: session_ticket (35)
Length: 0
Data (0 bytes)
Extension: encrypt_then_mac (len=0)
Type: encrypt_then_mac (22)
Length: 0
Extension: extended_master_secret (len=0)
Type: extended_master_secret (23)
Length: 0
Extension: signature_algorithms (len=32)
Type: signature_algorithms (13)
Length: 32
Signature Hash Algorithms Length: 30
Signature Hash Algorithms (15 algorithms)
You can downgrade to tls1.2 by specifying method "TLSv1_2_method":
var https = require('https');
var options = {
hostname: 'example.com',
port: 443,
path: '/',
method: 'GET',
secureProtocol:'TLSv1_2_method'
};
const req = https.request(options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (d) => {
process.stdout.write(d);
});
});
And if the server is part of your project I would advice to fix server side instead of crippling your client app.
Related
Here's my webserver, most parts not included in favor of being concise.
server.js
const https = require('https');
const app = require('express')();
const port = 1000;
const options = {
key : getKey(),
cert: getCert(),
ciphers: getCiphers(),
passphrase: "abcd",
rejectUnauthorized: true,
requestCert: true
};
const server = https.createServer(options, app);
server.on('clientError', function (err) {
console.log('received client error');
console.log({err});
})
server.on('connection', function (err) {
console.log('client connected');
})
server.listen(port);
To test my server, I run a connection commands with openssl
openssl s_client -connect localhost:1000 \
-servername localhost \
-CAfile etc/root-cert/ca.cert.pem \
-cert etc/certs/client.cert.pem \
-key etc/private/client.key.pem
This returns the following output, which indicates that the TLS connection was successful (as far as I'm aware):
CONNECTED(00000005)
depth=2 C = US, ST = California, O = Hackysack, CN = Hackysack Root CA
verify return:1
depth=1 C = US, ST = California, O = Hackysack, CN = Hackysack Intermediate CA
verify return:1
depth=0 C = US, ST = California, O = Hackysack, CN = localhost
verify return:1
write W BLOCK
---
Certificate chain
0 s:/C=US/ST=California/O=Hackysack/CN=localhost
i:/C=US/ST=California/O=Hackysack/CN=Hackysack Intermediate CA
1 s:/C=US/ST=California/O=Hackysack/CN=Hackysack Intermediate CA
i:/C=US/ST=California/O=Hackysack/CN=Hackysack Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
[Long cert file here]
-----END CERTIFICATE-----
subject=/C=US/ST=California/O=Hackysack/CN=localhost
issuer=/C=US/ST=California/O=Hackysack/CN=Hackysack Intermediate CA
---
No client certificate CA names sent
Server Temp Key: ECDH, X25519, 253 bits
---
SSL handshake has read 3400 bytes and written 2061 bytes
---
New, TLSv1/SSLv3, Cipher is AEAD-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.3
Cipher : AEAD-AES128-GCM-SHA256
Session-ID:
Session-ID-ctx:
Master-Key:
Start Time: 1674855496
Timeout : 7200 (sec)
Verify return code: 0 (ok)
---
read:errno=0
However, in my server terminal logs I see that I receive a clientError when trying to make this call via HTTPS request.
{
err: Error: socket hang up
at connResetException (internal/errors.js:639:14)
at TLSSocket.onSocketClose (_tls_wrap.js:1063:23)
at TLSSocket.emit (events.js:412:35)
at net.js:686:12
at Socket.done (_tls_wrap.js:564:7)
at Object.onceWrapper (events.js:520:26)
at Socket.emit (events.js:400:28)
at TCP.<anonymous> (net.js:686:12) {
code: 'ECONNRESET'
}
}
Here's my client request:
const https = require('https');
const options = {
hostname: 'localhost',
port: 1000,
method: "POST",
path: "/test",
cert: getClientCert(),
key: getClientKey(),
passphrase: "abcd",
ciphers: getCiphers()
ca: getCA(),
}
const request = https.request(options);
I noticed this error only started happening when I included requestCert: true when I created the server. I think something must be going wrong with my client side for this to be the case. The main problem with debugging this is that I'm not receiving a good error when it fails the handshake.
How can I better debug this issue?
i've created my own CA and intermediate CA with openssl.
On my Zyxel AP i've created an csr.
I signed the csr through my intermediate CA and imported the server
cert to my zyxel AP.
I've also uploaded the fullchain root CA (CA and Intermediate) to my zyxel AP.
I'm using ubuntu so i've installed fullchain CA in my cerstore (/usr/local/share/ca-certificates | update update-ca-certificates)
I also imported the fullchain CA in my Browser Cert Store (tested with firefox, brave)....
But when i now call up the webgui from my AP i get the follwing message:
SSL_ERROR_BAD_CERT_DOMAIN
This happens for all browsers.
When i check with curl or openssl, everything looks good:
curl -vvI https://zyxel.home.arpa
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 handshake, Server hello (2):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_CHACHA20_POLY1305_SHA256
.
.
.
SSL certificate verify ok.
openssl s_client -CAfile ca-chain-bundle.cert.pem https://zyxel.home.arpa
New, TLSv1.3, Cipher is TLS_CHACHA20_POLY1305_SHA256
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
What can i try to fix this browser issue?
Edit 1:
without CAfile:
openssl s_client -connect zyxel.home.arpa:443
.
.
verify error:num=20:unable to get local issuer certificate
.
verify error:num=21:unable to verify the first certificate
.
Edit 2:
# President James K. Polk, here are the output of the server crt:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 37:5b:25:e6:31:1b:7e:f7:63:14:30:e1:b6:ca:d2:11:a2:83:44:1c
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = DE, ST = Home, O = Home Inc., CN = Home Intermediate-CA, emailAddress = admin#home.sh
Validity
Not Before: Nov 22 20:20:47 2022 GMT
Not After : Nov 22 20:20:47 2023 GMT
Subject: CN = zyxel.home.arpa, C = DE, ST = Home, L = Home, O = Home Inc, OU = IT
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:aa:be:cf:97:ad:fd:da:1a:9b:c4:af:9a:07:ac:
b7:08:bb:e3:eb:b8:d0:dc:fc:34:bf:8c:c8:5b:3f:
37:a7:20:7d:7e:eb:c9:e1:ce:c6:a8:84:2a:a3:35:
74:83:c9:62:94:ad:92:5b:c5:54:99:9e:14:c9:2b:
73:44:75:06:de:d4:dc:13:a6:0c:8c:b6:d9:84:e2:
1e:51:f8:2f:83:3c:62:95:ca:32:39:07:2b:81:41:
f9:88:08:95:fb:f9:c2:10:f0:de:25:b6:e2:83:f0:
f2:86:41:7d:5d:09:91:3b:04:b8:5f:74:b7:f5:2e:
e8:fa:9b:f5:17:a7:ef:d1:45:ed:05:8e:f3:8e:c3:
a1:96:42:9d:dd:ef:2f:03:81:97:b9:c5:df:9c:41:
3b:b6:9d:7b:09:a0:bf:ad:e8:6a:e2:05:ef:2b:fc:
67:4d:5a:dd:a4:ba:7b:58:a8:65:53:08:06:60:00:
08:85:12:34:31:9b:93:27:d2:35:75:00:f0:01:f5:
58:7f:1a:e5:1f:e5:08:8a:14:ca:c4:17:4d:90:ec:
30:7a:38:3e:ad:90:db:08:46:35:c4:6e:a7:8e:81:
77:eb:15:47:50:7e:d1:71:d5:09:38:64:c3:fa:08:
2a:31:a0:bd:87:0b:70:27:b3:42:fe:20:de:b1:be:
87:a9
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Server
Netscape Comment:
OpenSSL Generated Server Certificate
X509v3 Subject Key Identifier:
F5:D6:9B:95:CA:2C:8E:41:92:5F:3E:3E:9C:D5:31:CE:6A:D0:F8:95
X509v3 Authority Key Identifier:
keyid:25:0C:ED:3A:E1:A0:B9:86:A0:FB:43:9F:20:F0:F4:C0:5E:85:C4:D7
DirName:/C=DE/ST=Home/L=Home/O=Home Inc./CN=Home Root-CA/emailAddress=admin#home.sh
serial:01
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
and here's the output ofthe generated csr on the zyxel AP:
Certificate Request:
Data:
Version: 1 (0x0)
Subject: CN = zyxel.home.arpa, C = DE, ST = Home, L = Home, O = Home Inc, OU = IT
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:aa:be:cf:97:ad:fd:da:1a:9b:c4:af:9a:07:ac:
b7:08:bb:e3:eb:b8:d0:dc:fc:34:bf:8c:c8:5b:3f:
37:a7:20:7d:7e:eb:c9:e1:ce:c6:a8:84:2a:a3:35:
74:83:c9:62:94:ad:92:5b:c5:54:99:9e:14:c9:2b:
73:44:75:06:de:d4:dc:13:a6:0c:8c:b6:d9:84:e2:
1e:51:f8:2f:83:3c:62:95:ca:32:39:07:2b:81:41:
f9:88:08:95:fb:f9:c2:10:f0:de:25:b6:e2:83:f0:
f2:86:41:7d:5d:09:91:3b:04:b8:5f:74:b7:f5:2e:
e8:fa:9b:f5:17:a7:ef:d1:45:ed:05:8e:f3:8e:c3:
a1:96:42:9d:dd:ef:2f:03:81:97:b9:c5:df:9c:41:
3b:b6:9d:7b:09:a0:bf:ad:e8:6a:e2:05:ef:2b:fc:
67:4d:5a:dd:a4:ba:7b:58:a8:65:53:08:06:60:00:
08:85:12:34:31:9b:93:27:d2:35:75:00:f0:01:f5:
58:7f:1a:e5:1f:e5:08:8a:14:ca:c4:17:4d:90:ec:
30:7a:38:3e:ad:90:db:08:46:35:c4:6e:a7:8e:81:
77:eb:15:47:50:7e:d1:71:d5:09:38:64:c3:fa:08:
2a:31:a0:bd:87:0b:70:27:b3:42:fe:20:de:b1:be:
87:a9
Exponent: 65537 (0x10001)
Attributes:
Netscape Comment :OpenSSL Generated Certificate
Requested Extensions:
X509v3 Subject Key Identifier:
F5:D6:9B:95:CA:2C:8E:41:92:5F:3E:3E:9C:D5:31:CE:6A:D0:F8:95
X509v3 Key Usage: critical
Digital Signature, Key Encipherment, Data Encipherment, Certificate Sign
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Server Authentication
X509v3 Subject Alternative Name:
othername: UPN::zyxel.home.arpa, DNS:zyxel.home.arpa
Signature Algorithm: sha512WithRSAEncryption
Signature Value:
1b:04:05:e6:02:89:4d:1d:67:a4:bb:15:06:20:93:58:c3:2b:
72:3c:e0:39:cd:f0:ea:6e:3a:db:33:02:3e:fa:ca:67:ec:e4:
58:a5:cf:ad:c0:51:b1:bb:0d:22:3f:a5:fc:ac:d1:e9:90:d6:
71:71:5d:dc:56:f1:14:21:cb:a3:53:be:0a:32:43:8f:8a:74:
55:08:e3:1d:44:7d:72:f3:94:7f:1a:99:71:b7:97:be:a6:ff:
a8:cf:95:f5:3b:c3:c6:6c:e3:ef:d9:39:8d:03:17:2e:15:2c:
92:ee:00:88:5f:23:21:a4:ac:27:c6:66:00:a5:5d:89:8d:f3:
87:43:34:35:16:e4:bd:72:38:ba:2c:27:f4:c9:08:22:aa:86:
21:6c:98:9f:4b:2b:7e:5e:6a:aa:5c:19:80:29:32:6d:4f:78:
1d:db:5b:1d:a1:bc:31:86:e9:65:af:ee:30:35:12:ce:d4:18:
b1:06:57:e3:da:f6:63:b0:48:53:64:0a:4b:ca:2a:20:d6:5d:
90:1a:bf:af:bb:d3:18:e8:5e:42:2f:3f:c8:96:20:63:66:9e:
2e:b1:2a:fa:82:f6:ba:d0:d3:7f:e7:a5:5d:f5:3a:fb:a9:b0:
54:a5:0a:14:48:8a:37:1e:e8:32:6c:73:7d:4c:af:dc:21:bc:
24:60:9e:2c
Solution:
i forgot to add the Subject Alt Name part into my openssl.cnf (thanks for the hint President James K. Polk):
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = #alt_names
[alt_names]
IP.1 = IP
DNS.1 = DNS NAME
I am currently working on a VSCode extension that internally makes some API calls to a HTTPS protected endpoint. On Linux and Mac OS the extension works as expected but on Windows machines axios, the internal HTTP client used to make the API calls, is rejecting those requests due to the certificates being expired. When I access the API endpoint though via Firefox, Chrome and even Edge the certificates seems find.
I have upgraded Node to 16.14.0 and also to 17.6.0 but the problem still remains. As the API is only accessible through our VPN, with my VPN activated of course, I used testssl.sh to verify that the whole trust-chain is still valid:
Testing protocols via sockets except NPN+ALPN
SSLv2 not offered (OK)
SSLv3 not offered (OK)
TLS 1 not offered
TLS 1.1 not offered
TLS 1.2 offered (OK)
TLS 1.3 offered (OK): final
NPN/SPDY not offered
ALPN/HTTP2 h2, http/1.1 (offered)
Testing cipher categories
NULL ciphers (no encryption) not offered (OK)
Anonymous NULL Ciphers (no authentication) not offered (OK)
Export ciphers (w/o ADH+NULL) not offered (OK)
LOW: 64 Bit + DES, RC[2,4] (w/o export) not offered (OK)
Triple DES Ciphers / IDEA not offered
Obsolete CBC ciphers (AES, ARIA etc.) offered
Strong encryption (AEAD ciphers) offered (OK)
Testing robust (perfect) forward secrecy, (P)FS -- omitting Null Authentication/Encryption, 3DES, RC4
PFS is offered (OK) TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES256-SHA
DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA TLS_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA256
ECDHE-RSA-AES128-SHA DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA
Elliptic curves offered: prime256v1 secp384r1 secp521r1 X25519 X448
DH group offered: HAProxy (2048 bits)
Testing server preferences
Has server cipher order? yes (OK) -- TLS 1.3 and below
Negotiated protocol TLSv1.3
Negotiated cipher TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Cipher order
TLSv1.2: ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA
ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA
TLSv1.3: TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256
...
Certificate Validity (UTC) 65 >= 30 days (2022-02-01 08:18 --> 2022-05-02 08:18)
...
The other certificates in the trustchain are also valid and not expired at all.
Axios is used within an own HttpClient class that looks like this:
export class HttpClient {
private readonly instance: AxiosInstance;
constructor() {
this.instance = axios.create();
}
async asyncGet<T>(url: string): Promise<Response<T>> {
return this.instance.get<T>(url)
.then(axiosResponse => {
...
})
.catch(error => {
console.error(error);
throw error;
});
}
}
I also tried the https
const options: https:RequestOptions = {
hostname: '...',
port: 443,
path: '/...',
method: 'GET'
};
const request = https.request(url, options, (res: IncomingMessage) => {
console.log(`statusCode: ${res.statusCode ? res.statusCode : 'undefined'}`);
res.on('data', d => {
process.stdout.write(d as string);
}
});
request.on('error', error => {
console.error(error);
};
request.end();
analog to the samples given in the NodeJS documentation and tls
const socket = tls.connect(443, hostname, undefined, () => {
console.log('Connected to ' + hostname);
console.log('TLS.connect', socket.authorized ? 'authorized' : 'unauthorized');
console.log('Cipher: ' + JSON.stringify(socket.getCipher()));
console.log('Protocol: ' + JSON.stringify(socket.getProtocol()));
const peerCert: tls.DetailedPeerCertificate = socket.getPeerCertificate(true);
console.log(`Peer-Cert ${JSON.stringify(peerCert.subject)} - valid from: ${peerCert ? peerCert.valid_from : 'invalid'} valid till: ${peerCert ? peerCert.valid_to : 'invalid'}`);
const issuerCert = peerCert.issuerCertificate;
console.log(`issuer-Cert ${JSON.stringify(issuerCert.subject)} - valid from: ${issuerCert ? issuerCert.valid_from : 'invalid'} valid till: ${issuerCert ? issuerCert.valid_to : 'invalid'}`);
const rootCert = issuerCert.issuerCertificate;
console.log(`root-Cert ${JSON.stringify(rootCert.subject)} - valid from: ${rootCert ? rootCert.valid_from : 'invalid'} valid till: ${rootCert ? rootCert.valid_to : 'invalid'}`);
});
as proposed in this answer.
Both axios and https return an error like this:
{
"message": "certificate has expired",
"name": "Error",
"stack": "Error: certificate has expired\n\tat TLSSocket.onConnectSecure (_tls_wrap.js:1497:34)\n\tat TLSSocket.emit (events.js:315:20)\n\tat TLSSocket._finishInit (_tls_wrap.js:932:8)\n\tat TLSWrap.onhandshakedone (_tls_wrap.js:706:12)\n\tat TLSWrap.callbackTrampoline (internal/async_hooks.js:131:14)",
"config": {
"transitional": {
"silentJSONParsing": true,
"forcedJSONParsing": true,
"clarifyTimeoutError": false
},
"transformRequest": [
"null"
],
"transformResponse": [
"null"
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1,
"headers": {
"Accept": "application/json, text/plain, */*",
"user-Agent": "axios/0.26.0"
},
"method": "get",
"url": "https://..."
},
"code": "CERT_HAS_EXPIRED",
"status": null
}
with a more human-readable stacktrace:
Error: certificate has expired
at TLSSocket.onConnectSecure (_tls_wrap.js:1497:34)
at TLSSocket.emit (events.js:315:20)
at TLSSocket._finishInit (_tls_wrap.js:932:8)
at TLSWrap.onhandshakedone (_tls_wrap.js:706:12)
at TLSWrap.callbackTrampoline (internal/async_hooks.js:131:14)
while for tls I get the following output:
Connected to ...
TLS.connect authorized
Cipher: {"name":"TLS_CHACHA20_POLY1305_SHA256","standardName":"TLS_CHACHA20_POLY1305_SHA256","version":"TLSv1/SSLv3"}
Protocol: "TLSv1.3"
Peer-Cert {"CN": "*...."} - valid from: Feb 1 08:18:23 2022 GMT valid till: May 2 08:18:22 2022 GMT
issuer-Cert {"C":"US","O":"Let's Encrypt","CN":"R3"} - valid from Sep 4 00:00:00 2020 GMT valid till: Sep 15 16:00:00 2025 GMT
root-Cert {"C":"US","O":"Internet Security Research Group","CN":"ISRG Root X1"} - valid from: Jan 20 19:14:03 2021 GMT valid till: Sep 30 18:14:03 2024 GMT
So tls seems to be able to connect to the API server and perform the SSL/TLS handshake, but https and axios somehow fail.
I also stumbled upon this question here, which seems to be related, but as I am already on the latest NodeJS release (as well as any dependency used in the extension is on the most recent version) and this error only occurs on Windows (mostly 10, unsure if and how many users actually use Windows 11) machines I think the question deserves its own spot here on SO.
In order to rule out a lack of common supported ciphers between the Windows and Node.js based tls implementation and the nginx managed server side, I also checked the available ciphers in Node via node -p crypto.constants.defaultCoreCipherList which returns a list like this:
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_GCM_SHA256
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-ECDSA-AES256-GCM-SHA384
DHE-RSA-AES128-GCM-SHA256
ECDHE-RSA-AES128-SHA256
DHE-RSA-AES128-SHA256
ECDHE-RSA-AES256-SHA384
DHE-RSA-AES256-SHA384
ECDHE-RSA-AES256-SHA256
DHE-RSA-AES256-SHA256
HIGH
!aNULL
!eNULL
!EXPORT
!DES
!RC4
!MD5
!PSK
!SRP
!CAMELLIA
which indicates that enough ciphers would overlap between client and server.
Why do I still get a certificate expired error on Windows machines with axios/https
when Linux and MacOS work just fine with these settings and tls is able to connect to the remote API sucessfully even on Windows machines?
I'm using HttpClient of .net core with with:
clientHandler.ClientCertificates.Add(cert);
_clientHandler.ServerCertificateCustomValidationCallback=VerifyServerCertificate;
_clientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
_clientHandler.SslProtocols= SslProtocols.Tls13;
HttpClient Client = new HttpClient(_clientHandler);
on the node side (I have node version v12.8.0) I set the server options like this:
var options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-crt.pem'),
ca: fs.readFileSync(config.ca),
requestCert: true,
rejectUnauthorized: true,
enableTrace: true,
minVersion: 'TLSv1.3',
maxVersion: 'TLSv1.3'
};
here's the tls trace:
Received Record
Header:
Version = TLS 1.0 (0x301)
Content Type = Handshake (22)
Length = 223
ClientHello, Length=219
client_version=0x303 (TLS 1.2)
Random:
gmt_unix_time=0xEEC5687E
random_bytes (len=28): 24761EF6E5B5B89F5333E9BCF87A28E55A4B598DDB0848049 A66DA26
session_id (len=0):
cipher_suites (len=56)
{0xC0, 0x2C} TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
{0xC0, 0x30} TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
{0x00, 0x9F} TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
{0xCC, 0xA9} TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
{0xCC, 0xA8} TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
{0xCC, 0xAA} TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
{0xC0, 0x2B} TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
{0xC0, 0x2F} TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
{0x00, 0x9E} TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
{0xC0, 0x24} TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
{0xC0, 0x28} TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
{0x00, 0x6B} TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
{0xC0, 0x23} TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
{0xC0, 0x27} TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
{0x00, 0x67} TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
{0xC0, 0x0A} TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
{0xC0, 0x14} TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
{0x00, 0x39} TLS_DHE_RSA_WITH_AES_256_CBC_SHA
{0xC0, 0x09} TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
{0xC0, 0x13} TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
{0x00, 0x33} TLS_DHE_RSA_WITH_AES_128_CBC_SHA
{0x00, 0x9D} TLS_RSA_WITH_AES_256_GCM_SHA384
{0x00, 0x9C} TLS_RSA_WITH_AES_128_GCM_SHA256
{0x00, 0x3D} TLS_RSA_WITH_AES_256_CBC_SHA256
{0x00, 0x3C} TLS_RSA_WITH_AES_128_CBC_SHA256
{0x00, 0x35} TLS_RSA_WITH_AES_256_CBC_SHA
{0x00, 0x2F} TLS_RSA_WITH_AES_128_CBC_SHA
{0x00, 0xFF} TLS_EMPTY_RENEGOTIATION_INFO_SCSV
compression_methods (len=1)
No Compression (0x00)
extensions, length = 122
extension_type=server_name(0), length=30
0000 - 00 1c 00 00 19 74 65 73-74 2e 61 72 74 69 73 .....test.artis
000f - 61 6e 6d 65 64 69 63 61-6c 2e 63 6f 2e 69 6c anmedical.co.il
extension_type=ec_point_formats(11), length=4
uncompressed (0)
ansiX962_compressed_prime (1)
ansiX962_compressed_char2 (2)
extension_type=supported_groups(10), length=10
ecdh_x25519 (29)
secp256r1 (P-256) (23)
secp521r1 (P-521) (25)
secp384r1 (P-384) (24)
extension_type=signature_algorithms(13), length=32
rsa_pkcs1_sha512 (0x0601)
dsa_sha512 (0x0602)
ecdsa_secp521r1_sha512 (0x0603)
rsa_pkcs1_sha384 (0x0501)
dsa_sha384 (0x0502)
ecdsa_secp384r1_sha384 (0x0503)
rsa_pkcs1_sha256 (0x0401)
dsa_sha256 (0x0402)
ecdsa_secp256r1_sha256 (0x0403)
rsa_pkcs1_sha224 (0x0301)
dsa_sha224 (0x0302)
ecdsa_sha224 (0x0303)
rsa_pkcs1_sha1 (0x0201)
dsa_sha1 (0x0202)
ecdsa_sha1 (0x0203)
extension_type=next_proto_neg(13172), length=0
extension_type=application_layer_protocol_negotiation(16), length=14
h2
http/1.1
extension_type=encrypt_then_mac(22), length=0
extension_type=extended_master_secret(23), length=0
Sent Record
Header:
Version = TLS 1.2 (0x303)
Content Type = Alert (21)
Length = 2
Level=fatal(2), description=protocol version(70)
The error on the c# side is: The client and server cannot communicate, because they do not possess a common algorithm.
Why is node using tls1.2 when I set the minVersion to 1.3?
According to .NET Core 3 documentation (https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0), TLS 1.3 is not yet supported in Windows or macOS (only Linux, with OpenSSL v1.1.1 or above).
If the client was using TLS 1.3 then it should say so in the 7th line of the trace. Your NodeJS server is behaving properly. It's the one rejecting the connection because the client is actually trying to connect using TLS 1.2.
I try to only use 256bit cipher suites only with following setup:
const https = require('https');
const fs = require('fs');
const constants = require('constants');
const serverKey = 'server.key';
const serverCrt = 'server.crt';
httpsOptions = {
key: fs.readFileSync(serverKey),
cert: fs.readFileSync(serverCrt),
secureOptions: constants.SSL_OP_NO_TLSv1 | constants.SSL_OP_NO_TLSv1_1,
ciphers: [
'ECDHE-ECDSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES256-GCM-SHA384',
"HIGH",
"!aNULL",
"!eNULL",
"!EXPORT",
"!DES",
"!RC4",
"!MD5",
"!PSK",
"!SRP",
"!CAMELLIA"
].join(':')
};
https.createServer(httpsOptions, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
However sslscan and ssllabs.com (my blog is using the same httpsOptions) testing show I still have
128bit ciphers
NON-GCM ciphers
Following is out put from sslscan:
[23:13:03]JS#JS-Mac-mini ~> sslscan localhost:8000
Version: 1.11.8
OpenSSL 1.0.2k 26 Jan 2017
OpenSSL version does not support SSLv2
SSLv2 ciphers will not be detected
Testing SSL server localhost on port 8000
TLS Fallback SCSV:
Server supports TLS Fallback SCSV
TLS renegotiation:
Session renegotiation not supported
TLS Compression:
Compression disabled
Heartbleed:
TLS 1.2 not vulnerable to heartbleed
TLS 1.1 not vulnerable to heartbleed
TLS 1.0 not vulnerable to heartbleed
Supported Server Cipher(s):
Preferred TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384 Curve P-256 DHE 256
Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA384 Curve P-256 DHE 256
Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256
Accepted TLSv1.2 256 bits AES256-GCM-SHA384
Accepted TLSv1.2 256 bits AES256-SHA256
Accepted TLSv1.2 256 bits AES256-SHA
Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-GCM-SHA256 Curve P-256 DHE 256
Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA256 Curve P-256 DHE 256
Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256
Accepted TLSv1.2 128 bits AES128-GCM-SHA256
Accepted TLSv1.2 128 bits AES128-SHA256
Accepted TLSv1.2 128 bits AES128-SHA
SSL Certificate:
Signature Algorithm: sha256WithRSAEncryption
RSA Key Strength: 2048
Subject: localhost
Issuer: localhost
Not valid before: Jun 13 19:06:29 2016 GMT
Not valid after: Jun 13 19:06:29 2017 GMT
I expect to see only the following ciphers:
Preferred TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384 Curve P-256 DHE 256
You're including HIGH in your SSL cipher configuration, which includes all the ciphers that OpenSSL considers high strength (128bit or above), and then you're excluding some specific other groups of ciphers. Remove HIGH and you'll just get the ciphers you want.
You can see what's in each group in OpenSSL from the command line with $ openssl ciphers -v HIGH
Alternatively you might just be able to specify the ciphers you want, and remove everything else.
add !AES128 to disable these 128bit ciphers.
sample:
ciphers: "ECDHE-RSA-AES256-GCM-SHA384:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA:HIGH:!AES128"
then supported ciphers will be:
Supported Server Cipher(s):
Accepted TLSv1 256 bits ECDHE-RSA-AES256-SHA
Accepted TLSv1 256 bits AES256-SHA
Accepted TLS11 256 bits ECDHE-RSA-AES256-SHA
Accepted TLS11 256 bits AES256-SHA
Accepted TLS12 256 bits ECDHE-RSA-AES256-GCM-SHA384
Accepted TLS12 256 bits ECDHE-RSA-AES256-SHA384
Accepted TLS12 256 bits ECDHE-RSA-AES256-SHA
Accepted TLS12 256 bits AES256-GCM-SHA384
Accepted TLS12 256 bits AES256-SHA256
Accepted TLS12 256 bits AES256-SHA