Skip to content

Commit ebda734

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 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> CVE-ID: CVE-2026-48618 Refs: https://hackerone.com/reports/3688064
1 parent 6bc17a6 commit ebda734

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
@@ -68,6 +68,7 @@ const { Buffer } = require('buffer');
6868
const { canonicalizeIP } = internalBinding('cares_wrap');
6969
const tlsCommon = require('internal/tls/common');
7070
const tlsWrap = require('internal/tls/wrap');
71+
const { domainToASCII } = require('internal/url');
7172
const { validateString } = require('internal/validators');
7273

7374
const {
@@ -403,6 +404,11 @@ exports.checkServerIdentity = function checkServerIdentity(hostname, cert) {
403404
const ips = [];
404405

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

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

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

433439
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)