11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ciconst common = require('../common'); 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ciif (!common.hasCrypto) 51cb0ef41Sopenharmony_ci common.skip('missing crypto'); 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciconst assert = require('assert'); 81cb0ef41Sopenharmony_ciconst tls = require('tls'); 91cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures'); 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_cifunction loadPEM(n) { 121cb0ef41Sopenharmony_ci return fixtures.readKey(`${n}.pem`); 131cb0ef41Sopenharmony_ci} 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ciconst serverIP = common.localhostIPv4; 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_cifunction checkResults(result, expected) { 181cb0ef41Sopenharmony_ci assert.strictEqual(result.server.ALPN, expected.server.ALPN); 191cb0ef41Sopenharmony_ci assert.strictEqual(result.client.ALPN, expected.client.ALPN); 201cb0ef41Sopenharmony_ci} 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_cifunction runTest(clientsOptions, serverOptions, cb) { 231cb0ef41Sopenharmony_ci serverOptions.key = loadPEM('agent2-key'); 241cb0ef41Sopenharmony_ci serverOptions.cert = loadPEM('agent2-cert'); 251cb0ef41Sopenharmony_ci const results = []; 261cb0ef41Sopenharmony_ci let clientIndex = 0; 271cb0ef41Sopenharmony_ci let serverIndex = 0; 281cb0ef41Sopenharmony_ci const server = tls.createServer(serverOptions, function(c) { 291cb0ef41Sopenharmony_ci results[serverIndex++].server = { ALPN: c.alpnProtocol }; 301cb0ef41Sopenharmony_ci }); 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_ci server.listen(0, serverIP, function() { 331cb0ef41Sopenharmony_ci connectClient(clientsOptions); 341cb0ef41Sopenharmony_ci }); 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ci function connectClient(options) { 371cb0ef41Sopenharmony_ci const opt = options.shift(); 381cb0ef41Sopenharmony_ci opt.port = server.address().port; 391cb0ef41Sopenharmony_ci opt.host = serverIP; 401cb0ef41Sopenharmony_ci opt.rejectUnauthorized = false; 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci results[clientIndex] = {}; 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci function startNextClient() { 451cb0ef41Sopenharmony_ci if (options.length) { 461cb0ef41Sopenharmony_ci clientIndex++; 471cb0ef41Sopenharmony_ci connectClient(options); 481cb0ef41Sopenharmony_ci } else { 491cb0ef41Sopenharmony_ci server.close(); 501cb0ef41Sopenharmony_ci server.on('close', () => { 511cb0ef41Sopenharmony_ci cb(results); 521cb0ef41Sopenharmony_ci }); 531cb0ef41Sopenharmony_ci } 541cb0ef41Sopenharmony_ci } 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci const client = tls.connect(opt, function() { 571cb0ef41Sopenharmony_ci results[clientIndex].client = { ALPN: client.alpnProtocol }; 581cb0ef41Sopenharmony_ci client.end(); 591cb0ef41Sopenharmony_ci startNextClient(); 601cb0ef41Sopenharmony_ci }).on('error', function(err) { 611cb0ef41Sopenharmony_ci results[clientIndex].client = { error: err }; 621cb0ef41Sopenharmony_ci startNextClient(); 631cb0ef41Sopenharmony_ci }); 641cb0ef41Sopenharmony_ci } 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci} 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci// Server: ALPN, Client: ALPN 691cb0ef41Sopenharmony_cifunction Test1() { 701cb0ef41Sopenharmony_ci const serverOptions = { 711cb0ef41Sopenharmony_ci ALPNProtocols: ['a', 'b', 'c'], 721cb0ef41Sopenharmony_ci }; 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci const clientsOptions = [{ 751cb0ef41Sopenharmony_ci ALPNProtocols: ['a', 'b', 'c'], 761cb0ef41Sopenharmony_ci }, { 771cb0ef41Sopenharmony_ci ALPNProtocols: ['c', 'b', 'e'], 781cb0ef41Sopenharmony_ci }, { 791cb0ef41Sopenharmony_ci ALPNProtocols: ['first-priority-unsupported', 'x', 'y'], 801cb0ef41Sopenharmony_ci }]; 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci runTest(clientsOptions, serverOptions, function(results) { 831cb0ef41Sopenharmony_ci // 'a' is selected by ALPN 841cb0ef41Sopenharmony_ci checkResults(results[0], 851cb0ef41Sopenharmony_ci { server: { ALPN: 'a' }, 861cb0ef41Sopenharmony_ci client: { ALPN: 'a' } }); 871cb0ef41Sopenharmony_ci // 'b' is selected by ALPN 881cb0ef41Sopenharmony_ci checkResults(results[1], 891cb0ef41Sopenharmony_ci { server: { ALPN: 'b' }, 901cb0ef41Sopenharmony_ci client: { ALPN: 'b' } }); 911cb0ef41Sopenharmony_ci // Nothing is selected by ALPN 921cb0ef41Sopenharmony_ci checkResults(results[2], 931cb0ef41Sopenharmony_ci { server: { ALPN: false }, 941cb0ef41Sopenharmony_ci client: { ALPN: false } }); 951cb0ef41Sopenharmony_ci // execute next test 961cb0ef41Sopenharmony_ci Test2(); 971cb0ef41Sopenharmony_ci }); 981cb0ef41Sopenharmony_ci} 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci// Server: ALPN, Client: Nothing 1011cb0ef41Sopenharmony_cifunction Test2() { 1021cb0ef41Sopenharmony_ci const serverOptions = { 1031cb0ef41Sopenharmony_ci ALPNProtocols: ['a', 'b', 'c'], 1041cb0ef41Sopenharmony_ci }; 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci const clientsOptions = [{}, {}, {}]; 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci runTest(clientsOptions, serverOptions, function(results) { 1091cb0ef41Sopenharmony_ci // Nothing is selected by ALPN 1101cb0ef41Sopenharmony_ci checkResults(results[0], 1111cb0ef41Sopenharmony_ci { server: { ALPN: false }, 1121cb0ef41Sopenharmony_ci client: { ALPN: false } }); 1131cb0ef41Sopenharmony_ci // Nothing is selected by ALPN 1141cb0ef41Sopenharmony_ci checkResults(results[1], 1151cb0ef41Sopenharmony_ci { server: { ALPN: false }, 1161cb0ef41Sopenharmony_ci client: { ALPN: false } }); 1171cb0ef41Sopenharmony_ci // Nothing is selected by ALPN 1181cb0ef41Sopenharmony_ci checkResults(results[2], 1191cb0ef41Sopenharmony_ci { server: { ALPN: false }, 1201cb0ef41Sopenharmony_ci client: { ALPN: false } }); 1211cb0ef41Sopenharmony_ci // execute next test 1221cb0ef41Sopenharmony_ci Test3(); 1231cb0ef41Sopenharmony_ci }); 1241cb0ef41Sopenharmony_ci} 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci// Server: Nothing, Client: ALPN 1271cb0ef41Sopenharmony_cifunction Test3() { 1281cb0ef41Sopenharmony_ci const serverOptions = {}; 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci const clientsOptions = [{ 1311cb0ef41Sopenharmony_ci ALPNrotocols: ['a', 'b', 'c'], 1321cb0ef41Sopenharmony_ci }, { 1331cb0ef41Sopenharmony_ci ALPNProtocols: ['c', 'b', 'e'], 1341cb0ef41Sopenharmony_ci }, { 1351cb0ef41Sopenharmony_ci ALPNProtocols: ['first-priority-unsupported', 'x', 'y'], 1361cb0ef41Sopenharmony_ci }]; 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci runTest(clientsOptions, serverOptions, function(results) { 1391cb0ef41Sopenharmony_ci // nothing is selected 1401cb0ef41Sopenharmony_ci checkResults(results[0], { server: { ALPN: false }, 1411cb0ef41Sopenharmony_ci client: { ALPN: false } }); 1421cb0ef41Sopenharmony_ci // nothing is selected 1431cb0ef41Sopenharmony_ci checkResults(results[1], { server: { ALPN: false }, 1441cb0ef41Sopenharmony_ci client: { ALPN: false } }); 1451cb0ef41Sopenharmony_ci // nothing is selected 1461cb0ef41Sopenharmony_ci checkResults(results[2], 1471cb0ef41Sopenharmony_ci { server: { ALPN: false }, 1481cb0ef41Sopenharmony_ci client: { ALPN: false } }); 1491cb0ef41Sopenharmony_ci // execute next test 1501cb0ef41Sopenharmony_ci Test4(); 1511cb0ef41Sopenharmony_ci }); 1521cb0ef41Sopenharmony_ci} 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci// Server: Nothing, Client: Nothing 1551cb0ef41Sopenharmony_cifunction Test4() { 1561cb0ef41Sopenharmony_ci const serverOptions = {}; 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci const clientsOptions = [{}, {}, {}]; 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci runTest(clientsOptions, serverOptions, function(results) { 1611cb0ef41Sopenharmony_ci // nothing is selected 1621cb0ef41Sopenharmony_ci checkResults(results[0], { server: { ALPN: false }, 1631cb0ef41Sopenharmony_ci client: { ALPN: false } }); 1641cb0ef41Sopenharmony_ci // nothing is selected 1651cb0ef41Sopenharmony_ci checkResults(results[1], { server: { ALPN: false }, 1661cb0ef41Sopenharmony_ci client: { ALPN: false } }); 1671cb0ef41Sopenharmony_ci // nothing is selected 1681cb0ef41Sopenharmony_ci checkResults(results[2], 1691cb0ef41Sopenharmony_ci { server: { ALPN: false }, 1701cb0ef41Sopenharmony_ci client: { ALPN: false } }); 1711cb0ef41Sopenharmony_ci }); 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci TestALPNCallback(); 1741cb0ef41Sopenharmony_ci} 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_cifunction TestALPNCallback() { 1771cb0ef41Sopenharmony_ci // Server always selects the client's 2nd preference: 1781cb0ef41Sopenharmony_ci const serverOptions = { 1791cb0ef41Sopenharmony_ci ALPNCallback: common.mustCall(({ protocols }) => { 1801cb0ef41Sopenharmony_ci return protocols[1]; 1811cb0ef41Sopenharmony_ci }, 2) 1821cb0ef41Sopenharmony_ci }; 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci const clientsOptions = [{ 1851cb0ef41Sopenharmony_ci ALPNProtocols: ['a', 'b', 'c'], 1861cb0ef41Sopenharmony_ci }, { 1871cb0ef41Sopenharmony_ci ALPNProtocols: ['a'], 1881cb0ef41Sopenharmony_ci }]; 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci runTest(clientsOptions, serverOptions, function(results) { 1911cb0ef41Sopenharmony_ci // Callback picks 2nd preference => picks 'b' 1921cb0ef41Sopenharmony_ci checkResults(results[0], 1931cb0ef41Sopenharmony_ci { server: { ALPN: 'b' }, 1941cb0ef41Sopenharmony_ci client: { ALPN: 'b' } }); 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci // Callback picks 2nd preference => undefined => ALPN rejected: 1971cb0ef41Sopenharmony_ci assert.strictEqual(results[1].server, undefined); 1981cb0ef41Sopenharmony_ci assert.strictEqual(results[1].client.error.code, 'ECONNRESET'); 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci TestBadALPNCallback(); 2011cb0ef41Sopenharmony_ci }); 2021cb0ef41Sopenharmony_ci} 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_cifunction TestBadALPNCallback() { 2051cb0ef41Sopenharmony_ci // Server always returns a fixed invalid value: 2061cb0ef41Sopenharmony_ci const serverOptions = { 2071cb0ef41Sopenharmony_ci ALPNCallback: common.mustCall(() => 'http/5') 2081cb0ef41Sopenharmony_ci }; 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci const clientsOptions = [{ 2111cb0ef41Sopenharmony_ci ALPNProtocols: ['http/1', 'h2'], 2121cb0ef41Sopenharmony_ci }]; 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci process.once('uncaughtException', common.mustCall((error) => { 2151cb0ef41Sopenharmony_ci assert.strictEqual(error.code, 'ERR_TLS_ALPN_CALLBACK_INVALID_RESULT'); 2161cb0ef41Sopenharmony_ci })); 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_ci runTest(clientsOptions, serverOptions, function(results) { 2191cb0ef41Sopenharmony_ci // Callback returns 'http/5' => doesn't match client ALPN => error & reset 2201cb0ef41Sopenharmony_ci assert.strictEqual(results[0].server, undefined); 2211cb0ef41Sopenharmony_ci assert.strictEqual(results[0].client.error.code, 'ECONNRESET'); 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_ci TestALPNOptionsCallback(); 2241cb0ef41Sopenharmony_ci }); 2251cb0ef41Sopenharmony_ci} 2261cb0ef41Sopenharmony_ci 2271cb0ef41Sopenharmony_cifunction TestALPNOptionsCallback() { 2281cb0ef41Sopenharmony_ci // Server sets two incompatible ALPN options: 2291cb0ef41Sopenharmony_ci assert.throws(() => tls.createServer({ 2301cb0ef41Sopenharmony_ci ALPNCallback: () => 'a', 2311cb0ef41Sopenharmony_ci ALPNProtocols: ['b', 'c'] 2321cb0ef41Sopenharmony_ci }), (error) => error.code === 'ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS'); 2331cb0ef41Sopenharmony_ci} 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ciTest1(); 236