ERR_SSL_SSLV3_ALERT_HANDSHAKE_FAILURE / ERR_TLS_CERT_ALTNAME_INVALID with dns interceptor and requestTls #3988
Open
Description
Bug Description
When using the requestTls
option (specifically rejectUnauthorized
) in conjunction with the DNS interceptor (interceptors.dns()
), multiple SSL errors are thrown. The behavior changes depending on the configuration:
- If I remove
.compose([interceptors.dns()])
, the issue disappears, and everything works fine. - If I remove
requestTls
completely, it also works fine even with.compose([interceptors.dns()])
. - If I keep
requestTls
but remove onlyrejectUnauthorized: true
(just{ requestTls: {} }
), the error persists when.compose([interceptors.dns()])
is used.
This suggests an interaction between requestTls
and the DNS interceptor that causes SSL issues.
Reproducible By
Example 1: (issue)
import { ProxyAgent, Agent, fetch, interceptors } from 'undici'
async function main () {
await fetch('https://api.ipify.org', {
dispatcher: new Agent()
.compose([interceptors.dns()])
}).then(async x => console.log('My IP:', await x.text()))
await fetch('https://api.ipify.org', {
dispatcher: new ProxyAgent({
uri: 'http://localhost:18080'
})
.compose([interceptors.dns()])
}).then(async x => console.log('Proxy IP:', await x.text()))
const response = await fetch('https://api.ipify.org', {
dispatcher: new ProxyAgent({
uri: 'http://localhost:18080',
requestTls: {
rejectUnauthorized: true
}
})
.compose([interceptors.dns()])
}).then(x => x.text())
console.log('Ip with rejectUnauthorized: true', response)
}
main ()
Result:
My IP: [REDACTED].212.[REDACTED].76
Proxy IP: [REDACTED].111.[REDACTED].50
/home/[REDACTED]/undici-altname-ssl-issue/node_modules/undici/index.js:120
Error.captureStackTrace(err)
^
TypeError: fetch failed
at fetch (/home/[REDACTED]/undici-altname-ssl-issue/node_modules/undici/index.js:120:13)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async main (file:///home/[REDACTED]/undici-altname-ssl-issue/index.js:16:20) {
[cause]: [Error: 40C8661E52720000:error:0A000410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1590:SSL alert number 40
] {
library: 'SSL routines',
reason: 'sslv3 alert handshake failure',
code: 'ERR_SSL_SSLV3_ALERT_HANDSHAKE_FAILURE'
}
}
Example two: (issue)
import { ProxyAgent, Agent, fetch, interceptors } from 'undici'
async function main () {
await fetch('https://api.ipify.org', {
dispatcher: new Agent()
.compose([interceptors.dns()])
}).then(async x => console.log('My IP:', await x.text()))
await fetch('https://api.ipify.org', {
dispatcher: new ProxyAgent({
uri: 'http://localhost:18080'
})
.compose([interceptors.dns()])
}).then(async x => console.log('Proxy IP:', await x.text()))
const response = await fetch('https://wikipedia.org', {
dispatcher: new ProxyAgent({
uri: 'http://localhost:18080',
requestTls: {
rejectUnauthorized: true
}
})
.compose([interceptors.dns()])
}).then(x => x.text())
console.log(response)
}
main ()
Result:
Click me to show large log
My IP: [REDACTED].212.[REDACTED].76
Proxy IP: [REDACTED].111.[REDACTED].50
/home/[REDACTED]/undici-altname-ssl-issue/node_modules/undici/index.js:120
Error.captureStackTrace(err)
^
TypeError: fetch failed
at fetch (/home/[REDACTED]/undici-altname-ssl-issue/node_modules/undici/index.js:120:13)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async main (file:///home/[REDACTED]/undici-altname-ssl-issue/index.js:16:20) {
[cause]: Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: IP: 185.15.59.224 is not in the cert's list:
at Object.checkServerIdentity (node:tls:337:12)
at TLSSocket.onConnectSecure (node:_tls_wrap:1684:27)
at TLSSocket.emit (node:events:518:28)
at TLSSocket._finishInit (node:_tls_wrap:1085:8)
at ssl.onhandshakedone (node:_tls_wrap:871:12) {
code: 'ERR_TLS_CERT_ALTNAME_INVALID',
reason: "IP: 185.15.59.224 is not in the cert's list: ",
host: '185.15.59.224',
cert: {
subject: [Object: null prototype] {
C: 'US',
ST: 'California',
L: 'San Francisco',
O: 'Wikimedia Foundation, Inc.',
CN: '*.wikipedia.org'
},
issuer: [Object: null prototype] {
C: 'US',
O: 'DigiCert Inc',
CN: 'DigiCert TLS Hybrid ECC SHA384 2020 CA1'
},
subjectaltname: 'DNS:*.wikipedia.org, DNS:wikimedia.org, DNS:mediawiki.org, DNS:wikibooks.org, DNS:wikidata.org, DNS:wikinews.org, DNS:wikiquote.org, DNS:wikisource.org, DNS:wikiversity.org, DNS:wikivoyage.org, DNS:wiktionary.org, DNS:wikimediafoundation.org, DNS:w.wiki, DNS:wmfusercontent.org, DNS:*.m.wikipedia.org, DNS:*.wikimedia.org, DNS:*.m.wikimedia.org, DNS:*.planet.wikimedia.org, DNS:*.mediawiki.org, DNS:*.m.mediawiki.org, DNS:*.wikibooks.org, DNS:*.m.wikibooks.org, DNS:*.wikidata.org, DNS:*.m.wikidata.org, DNS:*.wikinews.org, DNS:*.m.wikinews.org, DNS:*.wikiquote.org, DNS:*.m.wikiquote.org, DNS:*.wikisource.org, DNS:*.m.wikisource.org, DNS:*.wikiversity.org, DNS:*.m.wikiversity.org, DNS:*.wikivoyage.org, DNS:*.m.wikivoyage.org, DNS:*.wiktionary.org, DNS:*.m.wiktionary.org, DNS:*.wikimediafoundation.org, DNS:*.wmfusercontent.org, DNS:wikipedia.org, DNS:wikifunctions.org, DNS:*.wikifunctions.org',
infoAccess: [Object: null prototype] {
'OCSP - URI': [ 'http://ocsp.digicert.com' ],
'CA Issuers - URI': [
'http://cacerts.digicert.com/DigiCertTLSHybridECCSHA3842020CA1-1.crt'
]
},
ca: false,
bits: 256,
pubkey: Buffer(65) [Uint8Array] [
4, 41, 254, 247, 2, 121, 201, 130, 181, 38, 68,
233, 201, 191, 6, 62, 207, 73, 162, 210, 234, 254,
49, 84, 227, 83, 221, 123, 239, 33, 121, 35, 168,
32, 215, 30, 57, 116, 191, 92, 15, 133, 107, 161,
108, 81, 133, 72, 194, 184, 17, 16, 168, 195, 45,
229, 34, 8, 190, 171, 64, 207, 60, 68, 14
],
asn1Curve: 'prime256v1',
nistCurve: 'P-256',
valid_from: 'Sep 26 00:00:00 2024 GMT',
valid_to: 'Oct 17 23:59:59 2025 GMT',
fingerprint: '0B:3A:AB:D4:5E:55:A4:08:2B:F7:C1:DA:63:37:75:F1:EB:04:6E:A5',
fingerprint256: '40:62:FB:AE:31:5E:7D:29:B8:24:32:78:9D:DC:4B:99:1D:AB:8B:54:ED:DF:76:C8:12:98:9E:22:F1:BA:FD:59',
fingerprint512: 'CB:B4:E6:61:67:8C:FC:EB:DE:DD:11:1D:4E:B3:A2:4D:2C:49:3D:16:66:5F:36:F4:17:7A:AA:CA:9B:D7:6B:F3:09:48:7F:1B:1F:67:22:02:2D:4B:7D:A4:FC:A5:E5:4F:1F:60:E3:AB:48:2B:42:CB:E7:45:16:89:E9:A5:DE:64',
ext_key_usage: [ '1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2' ],
serialNumber: '0C745DCAE53F59103BEDA2477CCCE73A',
raw: Buffer(2126) [Uint8Array] [
48, 130, 8, 74, 48, 130, 7, 207, 160, 3, 2, 1,
2, 2, 16, 12, 116, 93, 202, 229, 63, 89, 16, 59,
237, 162, 71, 124, 204, 231, 58, 48, 10, 6, 8, 42,
134, 72, 206, 61, 4, 3, 3, 48, 86, 49, 11, 48,
9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 21,
48, 19, 6, 3, 85, 4, 10, 19, 12, 68, 105, 103,
105, 67, 101, 114, 116, 32, 73, 110, 99, 49, 48, 48,
46, 6, 3, 85, 4, 3, 19, 39, 68, 105, 103, 105,
67, 101, 114, 116,
... 2026 more items
],
issuerCertificate: {
subject: [Object: null prototype] {
C: 'US',
O: 'DigiCert Inc',
CN: 'DigiCert TLS Hybrid ECC SHA384 2020 CA1'
},
issuer: [Object: null prototype] {
C: 'US',
O: 'DigiCert Inc',
OU: 'www.digicert.com',
CN: 'DigiCert Global Root CA'
},
infoAccess: [Object: null prototype] {
'OCSP - URI': [ 'http://ocsp.digicert.com' ],
'CA Issuers - URI': [ 'http://cacerts.digicert.com/DigiCertGlobalRootCA.crt' ]
},
ca: true,
bits: 384,
pubkey: Buffer(97) [Uint8Array] [
4, 193, 27, 198, 154, 91, 152, 217, 164, 41, 160, 233,
212, 4, 181, 219, 235, 166, 178, 108, 85, 192, 255, 237,
152, 198, 73, 47, 6, 39, 81, 203, 191, 112, 193, 5,
122, 195, 177, 157, 135, 137, 186, 173, 180, 19, 23, 201,
168, 180, 131, 200, 184, 144, 209, 204, 116, 53, 54, 60,
131, 114, 176, 181, 208, 247, 34, 105, 200, 241, 128, 196,
123, 64, 143, 207, 104, 135, 38, 92, 57, 137, 241, 77,
145, 77, 218, 137, 139, 228, 3, 195, 67, 229, 191, 47,
115
],
asn1Curve: 'secp384r1',
nistCurve: 'P-384',
valid_from: 'Apr 14 00:00:00 2021 GMT',
valid_to: 'Apr 13 23:59:59 2031 GMT',
fingerprint: 'AE:C1:3C:DD:5E:A6:A3:99:8A:EC:14:AC:33:1A:D9:6B:ED:BB:77:0F',
fingerprint256: 'F7:A9:A1:B2:FD:96:4A:3F:26:70:BD:66:8D:56:1F:B7:C5:5D:3A:A9:AB:83:91:E7:E1:69:70:2D:B8:A3:DB:CF',
fingerprint512: 'A9:0D:FF:FB:4B:1C:A3:01:3F:B2:D2:78:3F:AB:A7:B8:03:1E:25:08:08:19:28:63:76:D4:12:EB:97:D3:A5:66:2D:C0:5D:4E:C4:0A:77:29:89:72:0D:F8:2A:7B:67:92:65:56:6D:13:75:F0:0C:85:50:C6:83:03:B8:6A:C0:35',
ext_key_usage: [ '1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2' ],
serialNumber: '07F2F35C87A877AF7AEFE947993525BD',
raw: Buffer(1051) [Uint8Array] [
48, 130, 4, 23, 48, 130, 2, 255, 160, 3, 2, 1,
2, 2, 16, 7, 242, 243, 92, 135, 168, 119, 175, 122,
239, 233, 71, 153, 53, 37, 189, 48, 13, 6, 9, 42,
134, 72, 134, 247, 13, 1, 1, 12, 5, 0, 48, 97,
49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85,
83, 49, 21, 48, 19, 6, 3, 85, 4, 10, 19, 12,
68, 105, 103, 105, 67, 101, 114, 116, 32, 73, 110, 99,
49, 25, 48, 23, 6, 3, 85, 4, 11, 19, 16, 119,
119, 119, 46, 100,
... 951 more items
],
issuerCertificate: <ref *1> {
subject: [Object: null prototype] {
C: 'US',
O: 'DigiCert Inc',
OU: 'www.digicert.com',
CN: 'DigiCert Global Root CA'
},
issuer: [Object: null prototype] {
C: 'US',
O: 'DigiCert Inc',
OU: 'www.digicert.com',
CN: 'DigiCert Global Root CA'
},
ca: true,
modulus: 'E23BE11172DEA8A4D3A357AA50A28F0B7790C9A2A5EE12CE965B010920CC0193A74E30B753F743C46900579DE28D22DD870640008109CECE1B83BFDFCD3B7146E2D666C705B37627168F7B9E1E957DEEB748A308DAD6AF7A0C3906657F4A5D1FBC17F8ABBEEE28D7747F7A78995985686E5C23324BBF4EC0E85A6DE370BF7710BFFC01F685D9A844105832A97518D5D1A2BE47E2276AF49A33F84908608BD45FB43A84BFA1AA4A4C7D3ECF4F5F6C765EA04B37919EDC22E66DCE141A8E6ACBFECDB3146417C75B299E32BFF2EEFAD30B42D4ABB74132DA0CD4EFF881D5BB8D583FB51BE84928A270DA3104DDF7B216F24C0A4E07A8ED4A3D5EB57FA390C3AF27',
bits: 2048,
exponent: '0x10001',
pubkey: Buffer(294) [Uint8Array] [
48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134,
247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0,
48, 130, 1, 10, 2, 130, 1, 1, 0, 226, 59, 225,
17, 114, 222, 168, 164, 211, 163, 87, 170, 80, 162, 143,
11, 119, 144, 201, 162, 165, 238, 18, 206, 150, 91, 1,
9, 32, 204, 1, 147, 167, 78, 48, 183, 83, 247, 67,
196, 105, 0, 87, 157, 226, 141, 34, 221, 135, 6, 64,
0, 129, 9, 206, 206, 27, 131, 191, 223, 205, 59, 113,
70, 226, 214, 102,
... 194 more items
],
valid_from: 'Nov 10 00:00:00 2006 GMT',
valid_to: 'Nov 10 00:00:00 2031 GMT',
fingerprint: 'A8:98:5D:3A:65:E5:E5:C4:B2:D7:D6:6D:40:C6:DD:2F:B1:9C:54:36',
fingerprint256: '43:48:A0:E9:44:4C:78:CB:26:5E:05:8D:5E:89:44:B4:D8:4F:96:62:BD:26:DB:25:7F:89:34:A4:43:C7:01:61',
fingerprint512: '53:B4:44:E5:65:18:32:01:A6:1E:EB:46:12:09:B2:DC:30:89:5E:EC:A4:87:23:8D:15:A0:26:73:5F:22:9A:81:9E:5B:19:CB:D7:E2:FA:27:68:AB:2A:64:F6:EB:CD:9D:1E:72:13:41:C9:ED:5D:D0:9F:C0:D5:E4:3D:68:BC:A7',
serialNumber: '083BE056904246B1A1756AC95991C74A',
raw: Buffer(947) [Uint8Array] [
48, 130, 3, 175, 48, 130, 2, 151, 160, 3, 2, 1,
2, 2, 16, 8, 59, 224, 86, 144, 66, 70, 177, 161,
117, 106, 201, 89, 145, 199, 74, 48, 13, 6, 9, 42,
134, 72, 134, 247, 13, 1, 1, 5, 5, 0, 48, 97,
49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85,
83, 49, 21, 48, 19, 6, 3, 85, 4, 10, 19, 12,
68, 105, 103, 105, 67, 101, 114, 116, 32, 73, 110, 99,
49, 25, 48, 23, 6, 3, 85, 4, 11, 19, 16, 119,
119, 119, 46, 100,
... 847 more items
],
issuerCertificate: [Circular *1]
}
}
}
}
}
Expected Behavior
The request should succeed without SSL errors when using requestTls and the DNS interceptor together.
Environment
Ubuntu 22.04.5 LTS x86_64
v20.12.2
undici 7.2.0
Additional context
This issue occurs whether requestTls
is { rejectUnauthorized: true }
or simply {}
. It appears the combination of requestTls
and interceptors.dns()
triggers unexpected behavior.