Skip to content

Commit 2197a47

Browse files
mcollinaaduh95
authored andcommitted
tls: normalize hostname for server identity checks
Signed-off-by: Matteo Collina <hello@matteocollina.com> PR-URL: nodejs-private/node-private#869 Backport-PR-URL: nodejs-private/node-private#893 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> CVE-ID: CVE-2026-48618 Refs: https://hackerone.com/reports/3688064
1 parent 2f62693 commit 2197a47

2 files changed

Lines changed: 22 additions & 7 deletions

File tree

lib/tls.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ const { canonicalizeIP } = internalBinding('cares_wrap');
6969
const tlsCommon = require('internal/tls/common');
7070
const tlsWrap = require('internal/tls/wrap');
7171
const { createSecurePair } = require('internal/tls/secure-pair');
72+
const { domainToASCII } = require('internal/url');
7273
const { validateString } = require('internal/validators');
7374

7475
const {
@@ -404,6 +405,11 @@ exports.checkServerIdentity = function checkServerIdentity(hostname, cert) {
404405
const ips = [];
405406

406407
hostname = '' + hostname;
408+
const hostnameASCII = domainToASCII(hostname);
409+
410+
// Remove trailing dots for error messages and matching.
411+
hostname = unfqdn(hostname);
412+
const hostnameASCIIWithoutFQDN = unfqdn(hostnameASCII);
407413

408414
if (altNames) {
409415
const splitAltNames = altNames.includes('"') ?
@@ -421,14 +427,14 @@ exports.checkServerIdentity = function checkServerIdentity(hostname, cert) {
421427
let valid = false;
422428
let reason = 'Unknown reason';
423429

424-
hostname = unfqdn(hostname); // Remove trailing dot for error messages.
425-
426-
if (net.isIP(hostname)) {
427-
valid = ips.includes(canonicalizeIP(hostname));
428-
if (!valid)
429-
reason = `IP: ${hostname} is not in the cert's list: ` + ips.join(', ');
430+
if (net.isIP(hostnameASCIIWithoutFQDN)) {
431+
valid = ips.includes(canonicalizeIP(hostnameASCIIWithoutFQDN));
432+
if (!valid) {
433+
reason =
434+
`IP: ${hostname} is not in the cert's list: ` + ips.join(', ');
435+
}
430436
} else if (dnsNames.length > 0 || subject?.CN) {
431-
const hostParts = splitHost(hostname);
437+
const hostParts = splitHost(hostnameASCIIWithoutFQDN);
432438
const wildcard = (pattern) => check(hostParts, pattern, true);
433439

434440
if (dnsNames.length > 0) {

test/parallel/test-tls-check-server-identity.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,15 @@ const tests = [
381381
error: 'Host: localhost. is not in the cert\'s altnames: ' +
382382
'DNS:a.com'
383383
},
384+
{
385+
host: 'foo。bar.example.com',
386+
cert: {
387+
subjectaltname: 'DNS:*.example.com',
388+
subject: {}
389+
},
390+
error: 'Host: foo。bar.example.com. is not in the cert\'s altnames: ' +
391+
'DNS:*.example.com'
392+
},
384393
// IDNA
385394
{
386395
host: 'xn--bcher-kva.example.com',

0 commit comments

Comments
 (0)