11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ciif (!common.hasCrypto)
51cb0ef41Sopenharmony_ci  common.skip('missing crypto');
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ciconst assert = require('assert');
81cb0ef41Sopenharmony_ciconst { X509Certificate } = require('crypto');
91cb0ef41Sopenharmony_ciconst tls = require('tls');
101cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciconst { hasOpenSSL3 } = common;
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ci// Test that all certificate chains provided by the reporter are rejected.
151cb0ef41Sopenharmony_ci{
161cb0ef41Sopenharmony_ci  const rootPEM = fixtures.readSync('x509-escaping/google/root.pem');
171cb0ef41Sopenharmony_ci  const intermPEM = fixtures.readSync('x509-escaping/google/intermediate.pem');
181cb0ef41Sopenharmony_ci  const keyPEM = fixtures.readSync('x509-escaping/google/key.pem');
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ci  const numLeaves = 5;
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci  for (let i = 0; i < numLeaves; i++) {
231cb0ef41Sopenharmony_ci    const name = `x509-escaping/google/leaf${i}.pem`;
241cb0ef41Sopenharmony_ci    const leafPEM = fixtures.readSync(name, 'utf8');
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci    const server = tls.createServer({
271cb0ef41Sopenharmony_ci      key: keyPEM,
281cb0ef41Sopenharmony_ci      cert: leafPEM + intermPEM,
291cb0ef41Sopenharmony_ci    }, common.mustNotCall()).listen(common.mustCall(() => {
301cb0ef41Sopenharmony_ci      const { port } = server.address();
311cb0ef41Sopenharmony_ci      const socket = tls.connect(port, {
321cb0ef41Sopenharmony_ci        ca: rootPEM,
331cb0ef41Sopenharmony_ci        servername: 'nodejs.org',
341cb0ef41Sopenharmony_ci      }, common.mustNotCall());
351cb0ef41Sopenharmony_ci      socket.on('error', common.mustCall());
361cb0ef41Sopenharmony_ci    })).unref();
371cb0ef41Sopenharmony_ci  }
381cb0ef41Sopenharmony_ci}
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci// Test escaping rules for subject alternative names.
411cb0ef41Sopenharmony_ci{
421cb0ef41Sopenharmony_ci  const expectedSANs = [
431cb0ef41Sopenharmony_ci    'DNS:"good.example.com\\u002c DNS:evil.example.com"',
441cb0ef41Sopenharmony_ci    // URIs should not require escaping.
451cb0ef41Sopenharmony_ci    'URI:http://example.com/',
461cb0ef41Sopenharmony_ci    'URI:http://example.com/?a=b&c=d',
471cb0ef41Sopenharmony_ci    // Unless they contain commas.
481cb0ef41Sopenharmony_ci    'URI:"http://example.com/a\\u002cb"',
491cb0ef41Sopenharmony_ci    // Percent encoding should not require escaping.
501cb0ef41Sopenharmony_ci    'URI:http://example.com/a%2Cb',
511cb0ef41Sopenharmony_ci    // Malicious attempts should be escaped.
521cb0ef41Sopenharmony_ci    'URI:"http://example.com/a\\u002c DNS:good.example.com"',
531cb0ef41Sopenharmony_ci    // Non-ASCII characters in DNS names should be treated as Latin-1.
541cb0ef41Sopenharmony_ci    'DNS:"ex\\u00e4mple.com"',
551cb0ef41Sopenharmony_ci    // It should not be possible to cause unescaping without escaping.
561cb0ef41Sopenharmony_ci    'DNS:"\\"evil.example.com\\""',
571cb0ef41Sopenharmony_ci    // IPv4 addresses should be represented as usual.
581cb0ef41Sopenharmony_ci    'IP Address:8.8.8.8',
591cb0ef41Sopenharmony_ci    'IP Address:8.8.4.4',
601cb0ef41Sopenharmony_ci    // For backward-compatibility, include invalid IP address lengths.
611cb0ef41Sopenharmony_ci    hasOpenSSL3 ? 'IP Address:<invalid length=5>' : 'IP Address:<invalid>',
621cb0ef41Sopenharmony_ci    hasOpenSSL3 ? 'IP Address:<invalid length=6>' : 'IP Address:<invalid>',
631cb0ef41Sopenharmony_ci    // IPv6 addresses are represented as OpenSSL does.
641cb0ef41Sopenharmony_ci    'IP Address:A0B:C0D:E0F:0:0:0:7A7B:7C7D',
651cb0ef41Sopenharmony_ci    // Regular email addresses don't require escaping.
661cb0ef41Sopenharmony_ci    'email:foo@example.com',
671cb0ef41Sopenharmony_ci    // ... but should be escaped if they contain commas.
681cb0ef41Sopenharmony_ci    'email:"foo@example.com\\u002c DNS:good.example.com"',
691cb0ef41Sopenharmony_ci    // New versions of Node.js use RFC2253 to print DirName entries, which
701cb0ef41Sopenharmony_ci    // almost always results in commas, which should be escaped properly.
711cb0ef41Sopenharmony_ci    'DirName:"L=Hannover\\u002cC=DE"',
721cb0ef41Sopenharmony_ci    // Node.js unsets ASN1_STRFLGS_ESC_MSB to prevent unnecessarily escaping
731cb0ef41Sopenharmony_ci    // Unicode characters, so Unicode characters should be preserved.
741cb0ef41Sopenharmony_ci    'DirName:"L=München\\u002cC=DE"',
751cb0ef41Sopenharmony_ci    'DirName:"L=Berlin\\\\\\u002c DNS:good.example.com\\u002cC=DE"',
761cb0ef41Sopenharmony_ci    // Node.js also unsets ASN1_STRFLGS_ESC_CTRL and relies on JSON-compatible
771cb0ef41Sopenharmony_ci    // escaping rules to safely escape control characters.
781cb0ef41Sopenharmony_ci    'DirName:"L=Berlin\\\\\\u002c DNS:good.example.com\\u0000' +
791cb0ef41Sopenharmony_ci      'evil.example.com\\u002cC=DE"',
801cb0ef41Sopenharmony_ci    'DirName:"L=Berlin\\\\\\u002c DNS:good.example.com\\\\\\\\\\u0000' +
811cb0ef41Sopenharmony_ci      'evil.example.com\\u002cC=DE"',
821cb0ef41Sopenharmony_ci    'DirName:"L=Berlin\\u000d\\u000a\\u002cC=DE"',
831cb0ef41Sopenharmony_ci    'DirName:"L=Berlin/CN=good.example.com\\u002cC=DE"',
841cb0ef41Sopenharmony_ci    // Even OIDs that are well-known (such as the following, which is
851cb0ef41Sopenharmony_ci    // sha256WithRSAEncryption) should be represented numerically only.
861cb0ef41Sopenharmony_ci    'Registered ID:1.2.840.113549.1.1.11',
871cb0ef41Sopenharmony_ci    // This is an OID that will likely never be assigned to anything, thus
881cb0ef41Sopenharmony_ci    // OpenSSL should not know it.
891cb0ef41Sopenharmony_ci    'Registered ID:1.3.9999.12.34',
901cb0ef41Sopenharmony_ci    hasOpenSSL3 ?
911cb0ef41Sopenharmony_ci      'othername:XmppAddr:abc123' :
921cb0ef41Sopenharmony_ci      'othername:<unsupported>',
931cb0ef41Sopenharmony_ci    hasOpenSSL3 ?
941cb0ef41Sopenharmony_ci      'othername:"XmppAddr:abc123\\u002c DNS:good.example.com"' :
951cb0ef41Sopenharmony_ci      'othername:<unsupported>',
961cb0ef41Sopenharmony_ci    hasOpenSSL3 ?
971cb0ef41Sopenharmony_ci      'othername:"XmppAddr:good.example.com\\u0000abc123"' :
981cb0ef41Sopenharmony_ci      'othername:<unsupported>',
991cb0ef41Sopenharmony_ci    // This is unsupported because the OID is not recognized.
1001cb0ef41Sopenharmony_ci    'othername:<unsupported>',
1011cb0ef41Sopenharmony_ci    hasOpenSSL3 ? 'othername:SRVName:abc123' : 'othername:<unsupported>',
1021cb0ef41Sopenharmony_ci    // This is unsupported because it is an SRVName with a UTF8String value,
1031cb0ef41Sopenharmony_ci    // which is not allowed for SRVName.
1041cb0ef41Sopenharmony_ci    'othername:<unsupported>',
1051cb0ef41Sopenharmony_ci    hasOpenSSL3 ?
1061cb0ef41Sopenharmony_ci      'othername:"SRVName:abc\\u0000def"' :
1071cb0ef41Sopenharmony_ci      'othername:<unsupported>',
1081cb0ef41Sopenharmony_ci  ];
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci  const serverKey = fixtures.readSync('x509-escaping/server-key.pem', 'utf8');
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  for (let i = 0; i < expectedSANs.length; i++) {
1131cb0ef41Sopenharmony_ci    const pem = fixtures.readSync(`x509-escaping/alt-${i}-cert.pem`, 'utf8');
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci    // Test the subjectAltName property of the X509Certificate API.
1161cb0ef41Sopenharmony_ci    const cert = new X509Certificate(pem);
1171cb0ef41Sopenharmony_ci    assert.strictEqual(cert.subjectAltName, expectedSANs[i]);
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci    // Test that the certificate obtained by checkServerIdentity has the correct
1201cb0ef41Sopenharmony_ci    // subjectaltname property.
1211cb0ef41Sopenharmony_ci    const server = tls.createServer({
1221cb0ef41Sopenharmony_ci      key: serverKey,
1231cb0ef41Sopenharmony_ci      cert: pem,
1241cb0ef41Sopenharmony_ci    }, common.mustCall((conn) => {
1251cb0ef41Sopenharmony_ci      conn.destroy();
1261cb0ef41Sopenharmony_ci      server.close();
1271cb0ef41Sopenharmony_ci    })).listen(common.mustCall(() => {
1281cb0ef41Sopenharmony_ci      const { port } = server.address();
1291cb0ef41Sopenharmony_ci      tls.connect(port, {
1301cb0ef41Sopenharmony_ci        ca: pem,
1311cb0ef41Sopenharmony_ci        servername: 'example.com',
1321cb0ef41Sopenharmony_ci        checkServerIdentity: (hostname, peerCert) => {
1331cb0ef41Sopenharmony_ci          assert.strictEqual(hostname, 'example.com');
1341cb0ef41Sopenharmony_ci          assert.strictEqual(peerCert.subjectaltname, expectedSANs[i]);
1351cb0ef41Sopenharmony_ci        },
1361cb0ef41Sopenharmony_ci      }, common.mustCall());
1371cb0ef41Sopenharmony_ci    }));
1381cb0ef41Sopenharmony_ci  }
1391cb0ef41Sopenharmony_ci}
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci// Test escaping rules for authority info access.
1421cb0ef41Sopenharmony_ci{
1431cb0ef41Sopenharmony_ci  const expectedInfoAccess = [
1441cb0ef41Sopenharmony_ci    {
1451cb0ef41Sopenharmony_ci      text: 'OCSP - URI:"http://good.example.com/\\u000a' +
1461cb0ef41Sopenharmony_ci            'OCSP - URI:http://evil.example.com/"',
1471cb0ef41Sopenharmony_ci      legacy: {
1481cb0ef41Sopenharmony_ci        'OCSP - URI': [
1491cb0ef41Sopenharmony_ci          'http://good.example.com/\nOCSP - URI:http://evil.example.com/',
1501cb0ef41Sopenharmony_ci        ],
1511cb0ef41Sopenharmony_ci      },
1521cb0ef41Sopenharmony_ci    },
1531cb0ef41Sopenharmony_ci    {
1541cb0ef41Sopenharmony_ci      text: 'CA Issuers - URI:"http://ca.example.com/\\u000a' +
1551cb0ef41Sopenharmony_ci            'OCSP - URI:http://evil.example.com"\n' +
1561cb0ef41Sopenharmony_ci            'OCSP - DNS:"good.example.com\\u000a' +
1571cb0ef41Sopenharmony_ci            'OCSP - URI:http://ca.nodejs.org/ca.cert"',
1581cb0ef41Sopenharmony_ci      legacy: {
1591cb0ef41Sopenharmony_ci        'CA Issuers - URI': [
1601cb0ef41Sopenharmony_ci          'http://ca.example.com/\nOCSP - URI:http://evil.example.com',
1611cb0ef41Sopenharmony_ci        ],
1621cb0ef41Sopenharmony_ci        'OCSP - DNS': [
1631cb0ef41Sopenharmony_ci          'good.example.com\nOCSP - URI:http://ca.nodejs.org/ca.cert',
1641cb0ef41Sopenharmony_ci        ],
1651cb0ef41Sopenharmony_ci      },
1661cb0ef41Sopenharmony_ci    },
1671cb0ef41Sopenharmony_ci    {
1681cb0ef41Sopenharmony_ci      text: '1.3.9999.12.34 - URI:http://ca.example.com/',
1691cb0ef41Sopenharmony_ci      legacy: {
1701cb0ef41Sopenharmony_ci        '1.3.9999.12.34 - URI': [
1711cb0ef41Sopenharmony_ci          'http://ca.example.com/',
1721cb0ef41Sopenharmony_ci        ],
1731cb0ef41Sopenharmony_ci      },
1741cb0ef41Sopenharmony_ci    },
1751cb0ef41Sopenharmony_ci    hasOpenSSL3 ? {
1761cb0ef41Sopenharmony_ci      text: 'OCSP - othername:XmppAddr:good.example.com\n' +
1771cb0ef41Sopenharmony_ci            'OCSP - othername:<unsupported>\n' +
1781cb0ef41Sopenharmony_ci            'OCSP - othername:SRVName:abc123',
1791cb0ef41Sopenharmony_ci      legacy: {
1801cb0ef41Sopenharmony_ci        'OCSP - othername': [
1811cb0ef41Sopenharmony_ci          'XmppAddr:good.example.com',
1821cb0ef41Sopenharmony_ci          '<unsupported>',
1831cb0ef41Sopenharmony_ci          'SRVName:abc123',
1841cb0ef41Sopenharmony_ci        ],
1851cb0ef41Sopenharmony_ci      },
1861cb0ef41Sopenharmony_ci    } : {
1871cb0ef41Sopenharmony_ci      text: 'OCSP - othername:<unsupported>\n' +
1881cb0ef41Sopenharmony_ci            'OCSP - othername:<unsupported>\n' +
1891cb0ef41Sopenharmony_ci            'OCSP - othername:<unsupported>',
1901cb0ef41Sopenharmony_ci      legacy: {
1911cb0ef41Sopenharmony_ci        'OCSP - othername': [
1921cb0ef41Sopenharmony_ci          '<unsupported>',
1931cb0ef41Sopenharmony_ci          '<unsupported>',
1941cb0ef41Sopenharmony_ci          '<unsupported>',
1951cb0ef41Sopenharmony_ci        ],
1961cb0ef41Sopenharmony_ci      },
1971cb0ef41Sopenharmony_ci    },
1981cb0ef41Sopenharmony_ci    hasOpenSSL3 ? {
1991cb0ef41Sopenharmony_ci      text: 'OCSP - othername:"XmppAddr:good.example.com\\u0000abc123"',
2001cb0ef41Sopenharmony_ci      legacy: {
2011cb0ef41Sopenharmony_ci        'OCSP - othername': [
2021cb0ef41Sopenharmony_ci          'XmppAddr:good.example.com\0abc123',
2031cb0ef41Sopenharmony_ci        ],
2041cb0ef41Sopenharmony_ci      },
2051cb0ef41Sopenharmony_ci    } : {
2061cb0ef41Sopenharmony_ci      text: 'OCSP - othername:<unsupported>',
2071cb0ef41Sopenharmony_ci      legacy: {
2081cb0ef41Sopenharmony_ci        'OCSP - othername': [
2091cb0ef41Sopenharmony_ci          '<unsupported>',
2101cb0ef41Sopenharmony_ci        ],
2111cb0ef41Sopenharmony_ci      },
2121cb0ef41Sopenharmony_ci    },
2131cb0ef41Sopenharmony_ci  ];
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci  const serverKey = fixtures.readSync('x509-escaping/server-key.pem', 'utf8');
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ci  for (let i = 0; i < expectedInfoAccess.length; i++) {
2181cb0ef41Sopenharmony_ci    const pem = fixtures.readSync(`x509-escaping/info-${i}-cert.pem`, 'utf8');
2191cb0ef41Sopenharmony_ci    const expected = expectedInfoAccess[i];
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci    // Test the subjectAltName property of the X509Certificate API.
2221cb0ef41Sopenharmony_ci    const cert = new X509Certificate(pem);
2231cb0ef41Sopenharmony_ci    assert.strictEqual(cert.infoAccess,
2241cb0ef41Sopenharmony_ci                       `${expected.text}${hasOpenSSL3 ? '' : '\n'}`);
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci    // Test that the certificate obtained by checkServerIdentity has the correct
2271cb0ef41Sopenharmony_ci    // subjectaltname property.
2281cb0ef41Sopenharmony_ci    const server = tls.createServer({
2291cb0ef41Sopenharmony_ci      key: serverKey,
2301cb0ef41Sopenharmony_ci      cert: pem,
2311cb0ef41Sopenharmony_ci    }, common.mustCall((conn) => {
2321cb0ef41Sopenharmony_ci      conn.destroy();
2331cb0ef41Sopenharmony_ci      server.close();
2341cb0ef41Sopenharmony_ci    })).listen(common.mustCall(() => {
2351cb0ef41Sopenharmony_ci      const { port } = server.address();
2361cb0ef41Sopenharmony_ci      tls.connect(port, {
2371cb0ef41Sopenharmony_ci        ca: pem,
2381cb0ef41Sopenharmony_ci        servername: 'example.com',
2391cb0ef41Sopenharmony_ci        checkServerIdentity: (hostname, peerCert) => {
2401cb0ef41Sopenharmony_ci          assert.strictEqual(hostname, 'example.com');
2411cb0ef41Sopenharmony_ci          assert.deepStrictEqual(peerCert.infoAccess,
2421cb0ef41Sopenharmony_ci                                 Object.assign(Object.create(null),
2431cb0ef41Sopenharmony_ci                                               expected.legacy));
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci          // toLegacyObject() should also produce the same properties. However,
2461cb0ef41Sopenharmony_ci          // the X509Certificate is not aware of the chain, so we need to add
2471cb0ef41Sopenharmony_ci          // the circular issuerCertificate reference manually for the assertion
2481cb0ef41Sopenharmony_ci          // to be true.
2491cb0ef41Sopenharmony_ci          const obj = cert.toLegacyObject();
2501cb0ef41Sopenharmony_ci          assert.strictEqual(obj.issuerCertificate, undefined);
2511cb0ef41Sopenharmony_ci          obj.issuerCertificate = obj;
2521cb0ef41Sopenharmony_ci          assert.deepStrictEqual(peerCert, obj);
2531cb0ef41Sopenharmony_ci        },
2541cb0ef41Sopenharmony_ci      }, common.mustCall());
2551cb0ef41Sopenharmony_ci    }));
2561cb0ef41Sopenharmony_ci  }
2571cb0ef41Sopenharmony_ci}
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ci// Test escaping rules for the subject field.
2601cb0ef41Sopenharmony_ci{
2611cb0ef41Sopenharmony_ci  const expectedSubjects = [
2621cb0ef41Sopenharmony_ci    {
2631cb0ef41Sopenharmony_ci      text: 'L=Somewhere\nCN=evil.example.com',
2641cb0ef41Sopenharmony_ci      legacy: {
2651cb0ef41Sopenharmony_ci        L: 'Somewhere',
2661cb0ef41Sopenharmony_ci        CN: 'evil.example.com',
2671cb0ef41Sopenharmony_ci      },
2681cb0ef41Sopenharmony_ci    },
2691cb0ef41Sopenharmony_ci    {
2701cb0ef41Sopenharmony_ci      text: 'L=Somewhere\\00evil.example.com',
2711cb0ef41Sopenharmony_ci      legacy: {
2721cb0ef41Sopenharmony_ci        L: 'Somewhere\0evil.example.com',
2731cb0ef41Sopenharmony_ci      },
2741cb0ef41Sopenharmony_ci    },
2751cb0ef41Sopenharmony_ci    {
2761cb0ef41Sopenharmony_ci      text: 'L=Somewhere\\0ACN=evil.example.com',
2771cb0ef41Sopenharmony_ci      legacy: {
2781cb0ef41Sopenharmony_ci        L: 'Somewhere\nCN=evil.example.com'
2791cb0ef41Sopenharmony_ci      },
2801cb0ef41Sopenharmony_ci    },
2811cb0ef41Sopenharmony_ci    {
2821cb0ef41Sopenharmony_ci      text: 'L=Somewhere\\, CN = evil.example.com',
2831cb0ef41Sopenharmony_ci      legacy: {
2841cb0ef41Sopenharmony_ci        L: 'Somewhere, CN = evil.example.com'
2851cb0ef41Sopenharmony_ci      },
2861cb0ef41Sopenharmony_ci    },
2871cb0ef41Sopenharmony_ci    {
2881cb0ef41Sopenharmony_ci      text: 'L=Somewhere/CN=evil.example.com',
2891cb0ef41Sopenharmony_ci      legacy: {
2901cb0ef41Sopenharmony_ci        L: 'Somewhere/CN=evil.example.com'
2911cb0ef41Sopenharmony_ci      },
2921cb0ef41Sopenharmony_ci    },
2931cb0ef41Sopenharmony_ci    {
2941cb0ef41Sopenharmony_ci      text: 'L=München\\\\\\0ACN=evil.example.com',
2951cb0ef41Sopenharmony_ci      legacy: {
2961cb0ef41Sopenharmony_ci        L: 'München\\\nCN=evil.example.com'
2971cb0ef41Sopenharmony_ci      }
2981cb0ef41Sopenharmony_ci    },
2991cb0ef41Sopenharmony_ci    {
3001cb0ef41Sopenharmony_ci      text: 'L=Somewhere + CN=evil.example.com',
3011cb0ef41Sopenharmony_ci      legacy: {
3021cb0ef41Sopenharmony_ci        L: 'Somewhere',
3031cb0ef41Sopenharmony_ci        CN: 'evil.example.com',
3041cb0ef41Sopenharmony_ci      }
3051cb0ef41Sopenharmony_ci    },
3061cb0ef41Sopenharmony_ci    {
3071cb0ef41Sopenharmony_ci      text: 'L=Somewhere \\+ CN=evil.example.com',
3081cb0ef41Sopenharmony_ci      legacy: {
3091cb0ef41Sopenharmony_ci        L: 'Somewhere + CN=evil.example.com'
3101cb0ef41Sopenharmony_ci      }
3111cb0ef41Sopenharmony_ci    },
3121cb0ef41Sopenharmony_ci    // Observe that the legacy representation cannot properly distinguish
3131cb0ef41Sopenharmony_ci    // between multi-value RDNs and multiple single-value RDNs.
3141cb0ef41Sopenharmony_ci    {
3151cb0ef41Sopenharmony_ci      text: 'L=L1 + L=L2\nL=L3',
3161cb0ef41Sopenharmony_ci      legacy: {
3171cb0ef41Sopenharmony_ci        L: ['L1', 'L2', 'L3']
3181cb0ef41Sopenharmony_ci      },
3191cb0ef41Sopenharmony_ci    },
3201cb0ef41Sopenharmony_ci    {
3211cb0ef41Sopenharmony_ci      text: 'L=L1\nL=L2\nL=L3',
3221cb0ef41Sopenharmony_ci      legacy: {
3231cb0ef41Sopenharmony_ci        L: ['L1', 'L2', 'L3']
3241cb0ef41Sopenharmony_ci      },
3251cb0ef41Sopenharmony_ci    },
3261cb0ef41Sopenharmony_ci  ];
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_ci  const serverKey = fixtures.readSync('x509-escaping/server-key.pem', 'utf8');
3291cb0ef41Sopenharmony_ci
3301cb0ef41Sopenharmony_ci  for (let i = 0; i < expectedSubjects.length; i++) {
3311cb0ef41Sopenharmony_ci    const pem = fixtures.readSync(`x509-escaping/subj-${i}-cert.pem`, 'utf8');
3321cb0ef41Sopenharmony_ci    const expected = expectedSubjects[i];
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci    // Test the subject property of the X509Certificate API.
3351cb0ef41Sopenharmony_ci    const cert = new X509Certificate(pem);
3361cb0ef41Sopenharmony_ci    assert.strictEqual(cert.subject, expected.text);
3371cb0ef41Sopenharmony_ci    // The issuer MUST be the same as the subject since the cert is self-signed.
3381cb0ef41Sopenharmony_ci    assert.strictEqual(cert.issuer, expected.text);
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ci    // Test that the certificate obtained by checkServerIdentity has the correct
3411cb0ef41Sopenharmony_ci    // subject property.
3421cb0ef41Sopenharmony_ci    const server = tls.createServer({
3431cb0ef41Sopenharmony_ci      key: serverKey,
3441cb0ef41Sopenharmony_ci      cert: pem,
3451cb0ef41Sopenharmony_ci    }, common.mustCall((conn) => {
3461cb0ef41Sopenharmony_ci      conn.destroy();
3471cb0ef41Sopenharmony_ci      server.close();
3481cb0ef41Sopenharmony_ci    })).listen(common.mustCall(() => {
3491cb0ef41Sopenharmony_ci      const { port } = server.address();
3501cb0ef41Sopenharmony_ci      tls.connect(port, {
3511cb0ef41Sopenharmony_ci        ca: pem,
3521cb0ef41Sopenharmony_ci        servername: 'example.com',
3531cb0ef41Sopenharmony_ci        checkServerIdentity: (hostname, peerCert) => {
3541cb0ef41Sopenharmony_ci          assert.strictEqual(hostname, 'example.com');
3551cb0ef41Sopenharmony_ci          const expectedObject = Object.assign(Object.create(null),
3561cb0ef41Sopenharmony_ci                                               expected.legacy);
3571cb0ef41Sopenharmony_ci          assert.deepStrictEqual(peerCert.subject, expectedObject);
3581cb0ef41Sopenharmony_ci          // The issuer MUST be the same as the subject since the cert is
3591cb0ef41Sopenharmony_ci          // self-signed. Otherwise, OpenSSL would have already rejected the
3601cb0ef41Sopenharmony_ci          // certificate while connecting to the TLS server.
3611cb0ef41Sopenharmony_ci          assert.deepStrictEqual(peerCert.issuer, expectedObject);
3621cb0ef41Sopenharmony_ci
3631cb0ef41Sopenharmony_ci          // toLegacyObject() should also produce the same properties. However,
3641cb0ef41Sopenharmony_ci          // the X509Certificate is not aware of the chain, so we need to add
3651cb0ef41Sopenharmony_ci          // the circular issuerCertificate reference manually for the assertion
3661cb0ef41Sopenharmony_ci          // to be true.
3671cb0ef41Sopenharmony_ci          const obj = cert.toLegacyObject();
3681cb0ef41Sopenharmony_ci          assert.strictEqual(obj.issuerCertificate, undefined);
3691cb0ef41Sopenharmony_ci          obj.issuerCertificate = obj;
3701cb0ef41Sopenharmony_ci          assert.deepStrictEqual(peerCert, obj);
3711cb0ef41Sopenharmony_ci        },
3721cb0ef41Sopenharmony_ci      }, common.mustCall());
3731cb0ef41Sopenharmony_ci    }));
3741cb0ef41Sopenharmony_ci  }
3751cb0ef41Sopenharmony_ci}
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ci// The internal parsing logic must match the JSON specification exactly.
3781cb0ef41Sopenharmony_ci{
3791cb0ef41Sopenharmony_ci  // This list is partially based on V8's own JSON tests.
3801cb0ef41Sopenharmony_ci  const invalidJSON = [
3811cb0ef41Sopenharmony_ci    '"\\a invalid escape"',
3821cb0ef41Sopenharmony_ci    '"\\v invalid escape"',
3831cb0ef41Sopenharmony_ci    '"\\\' invalid escape"',
3841cb0ef41Sopenharmony_ci    '"\\x42 invalid escape"',
3851cb0ef41Sopenharmony_ci    '"\\u202 invalid escape"',
3861cb0ef41Sopenharmony_ci    '"\\012 invalid escape"',
3871cb0ef41Sopenharmony_ci    '"Unterminated string',
3881cb0ef41Sopenharmony_ci    '"Unterminated string\\"',
3891cb0ef41Sopenharmony_ci    '"Unterminated string\\\\\\"',
3901cb0ef41Sopenharmony_ci    '"\u0000 control character"',
3911cb0ef41Sopenharmony_ci    '"\u001e control character"',
3921cb0ef41Sopenharmony_ci    '"\u001f control character"',
3931cb0ef41Sopenharmony_ci  ];
3941cb0ef41Sopenharmony_ci
3951cb0ef41Sopenharmony_ci  for (const invalidStringLiteral of invalidJSON) {
3961cb0ef41Sopenharmony_ci    // Usually, checkServerIdentity returns an error upon verification failure.
3971cb0ef41Sopenharmony_ci    // In this case, however, it should throw an error since this is not a
3981cb0ef41Sopenharmony_ci    // verification error. Node.js itself will never produce invalid JSON string
3991cb0ef41Sopenharmony_ci    // literals, so this can only happen when users construct invalid subject
4001cb0ef41Sopenharmony_ci    // alternative name strings (that do not follow escaping rules).
4011cb0ef41Sopenharmony_ci    assert.throws(() => {
4021cb0ef41Sopenharmony_ci      tls.checkServerIdentity('example.com', {
4031cb0ef41Sopenharmony_ci        subjectaltname: `DNS:${invalidStringLiteral}`,
4041cb0ef41Sopenharmony_ci      });
4051cb0ef41Sopenharmony_ci    }, {
4061cb0ef41Sopenharmony_ci      code: 'ERR_TLS_CERT_ALTNAME_FORMAT',
4071cb0ef41Sopenharmony_ci      message: 'Invalid subject alternative name string'
4081cb0ef41Sopenharmony_ci    });
4091cb0ef41Sopenharmony_ci  }
4101cb0ef41Sopenharmony_ci}
4111cb0ef41Sopenharmony_ci
4121cb0ef41Sopenharmony_ci// While node does not produce commas within SAN entries, it should parse them
4131cb0ef41Sopenharmony_ci// correctly (i.e., not simply split at commas).
4141cb0ef41Sopenharmony_ci{
4151cb0ef41Sopenharmony_ci  // Regardless of the quotes, splitting this SAN string at commas would
4161cb0ef41Sopenharmony_ci  // cause checkServerIdentity to see 'DNS:b.example.com' and thus to accept
4171cb0ef41Sopenharmony_ci  // the certificate for b.example.com.
4181cb0ef41Sopenharmony_ci  const san = 'DNS:"a.example.com, DNS:b.example.com, DNS:c.example.com"';
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ci  // This is what node used to do, and which is not correct!
4211cb0ef41Sopenharmony_ci  const hostname = 'b.example.com';
4221cb0ef41Sopenharmony_ci  assert.strictEqual(san.split(', ')[1], `DNS:${hostname}`);
4231cb0ef41Sopenharmony_ci
4241cb0ef41Sopenharmony_ci  // The new implementation should parse the string correctly.
4251cb0ef41Sopenharmony_ci  const err = tls.checkServerIdentity(hostname, { subjectaltname: san });
4261cb0ef41Sopenharmony_ci  assert(err);
4271cb0ef41Sopenharmony_ci  assert.strictEqual(err.code, 'ERR_TLS_CERT_ALTNAME_INVALID');
4281cb0ef41Sopenharmony_ci  assert.strictEqual(err.message, 'Hostname/IP does not match certificate\'s ' +
4291cb0ef41Sopenharmony_ci                                  'altnames: Host: b.example.com. is not in ' +
4301cb0ef41Sopenharmony_ci                                  'the cert\'s altnames: DNS:"a.example.com, ' +
4311cb0ef41Sopenharmony_ci                                  'DNS:b.example.com, DNS:c.example.com"');
4321cb0ef41Sopenharmony_ci}
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ci// The subject MUST be ignored if a dNSName subject alternative name exists.
4351cb0ef41Sopenharmony_ci{
4361cb0ef41Sopenharmony_ci  const key = fixtures.readKey('incorrect_san_correct_subject-key.pem');
4371cb0ef41Sopenharmony_ci  const cert = fixtures.readKey('incorrect_san_correct_subject-cert.pem');
4381cb0ef41Sopenharmony_ci
4391cb0ef41Sopenharmony_ci  // The hostname is the CN, but not a SAN entry.
4401cb0ef41Sopenharmony_ci  const servername = 'good.example.com';
4411cb0ef41Sopenharmony_ci  const certX509 = new X509Certificate(cert);
4421cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.subject, `CN=${servername}`);
4431cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.subjectAltName, 'DNS:evil.example.com');
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_ci  // The newer X509Certificate API allows customizing this behavior:
4461cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.checkHost(servername), undefined);
4471cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.checkHost(servername, { subject: 'default' }),
4481cb0ef41Sopenharmony_ci                     undefined);
4491cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.checkHost(servername, { subject: 'always' }),
4501cb0ef41Sopenharmony_ci                     servername);
4511cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.checkHost(servername, { subject: 'never' }),
4521cb0ef41Sopenharmony_ci                     undefined);
4531cb0ef41Sopenharmony_ci
4541cb0ef41Sopenharmony_ci  // Try connecting to a server that uses the self-signed certificate.
4551cb0ef41Sopenharmony_ci  const server = tls.createServer({ key, cert }, common.mustNotCall());
4561cb0ef41Sopenharmony_ci  server.listen(common.mustCall(() => {
4571cb0ef41Sopenharmony_ci    const { port } = server.address();
4581cb0ef41Sopenharmony_ci    const socket = tls.connect(port, {
4591cb0ef41Sopenharmony_ci      ca: cert,
4601cb0ef41Sopenharmony_ci      servername,
4611cb0ef41Sopenharmony_ci    }, common.mustNotCall());
4621cb0ef41Sopenharmony_ci    socket.on('error', common.mustCall((err) => {
4631cb0ef41Sopenharmony_ci      assert.strictEqual(err.code, 'ERR_TLS_CERT_ALTNAME_INVALID');
4641cb0ef41Sopenharmony_ci      assert.strictEqual(err.message, 'Hostname/IP does not match ' +
4651cb0ef41Sopenharmony_ci                                      "certificate's altnames: Host: " +
4661cb0ef41Sopenharmony_ci                                      "good.example.com. is not in the cert's" +
4671cb0ef41Sopenharmony_ci                                      ' altnames: DNS:evil.example.com');
4681cb0ef41Sopenharmony_ci    }));
4691cb0ef41Sopenharmony_ci  })).unref();
4701cb0ef41Sopenharmony_ci}
4711cb0ef41Sopenharmony_ci
4721cb0ef41Sopenharmony_ci// The subject MUST NOT be ignored if no dNSName subject alternative name
4731cb0ef41Sopenharmony_ci// exists, even if other subject alternative names exist.
4741cb0ef41Sopenharmony_ci{
4751cb0ef41Sopenharmony_ci  const key = fixtures.readKey('irrelevant_san_correct_subject-key.pem');
4761cb0ef41Sopenharmony_ci  const cert = fixtures.readKey('irrelevant_san_correct_subject-cert.pem');
4771cb0ef41Sopenharmony_ci
4781cb0ef41Sopenharmony_ci  // The hostname is the CN, but there is no dNSName SAN entry.
4791cb0ef41Sopenharmony_ci  const servername = 'good.example.com';
4801cb0ef41Sopenharmony_ci  const certX509 = new X509Certificate(cert);
4811cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.subject, `CN=${servername}`);
4821cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.subjectAltName, 'IP Address:1.2.3.4');
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_ci  // The newer X509Certificate API allows customizing this behavior:
4851cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.checkHost(servername), servername);
4861cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.checkHost(servername, { subject: 'default' }),
4871cb0ef41Sopenharmony_ci                     servername);
4881cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.checkHost(servername, { subject: 'always' }),
4891cb0ef41Sopenharmony_ci                     servername);
4901cb0ef41Sopenharmony_ci  assert.strictEqual(certX509.checkHost(servername, { subject: 'never' }),
4911cb0ef41Sopenharmony_ci                     undefined);
4921cb0ef41Sopenharmony_ci
4931cb0ef41Sopenharmony_ci  // Connect to a server that uses the self-signed certificate.
4941cb0ef41Sopenharmony_ci  const server = tls.createServer({ key, cert }, common.mustCall((socket) => {
4951cb0ef41Sopenharmony_ci    socket.destroy();
4961cb0ef41Sopenharmony_ci    server.close();
4971cb0ef41Sopenharmony_ci  })).listen(common.mustCall(() => {
4981cb0ef41Sopenharmony_ci    const { port } = server.address();
4991cb0ef41Sopenharmony_ci    tls.connect(port, {
5001cb0ef41Sopenharmony_ci      ca: cert,
5011cb0ef41Sopenharmony_ci      servername,
5021cb0ef41Sopenharmony_ci    }, common.mustCall());
5031cb0ef41Sopenharmony_ci  }));
5041cb0ef41Sopenharmony_ci}
505