11cb0ef41Sopenharmony_ci/* eslint-disable node-core/crypto-check */ 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci'use strict'; 41cb0ef41Sopenharmony_ciconst crypto = require('crypto'); 51cb0ef41Sopenharmony_ciconst net = require('net'); 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciexports.ccs = Buffer.from('140303000101', 'hex'); 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciclass TestTLSSocket extends net.Socket { 101cb0ef41Sopenharmony_ci constructor(server_cert) { 111cb0ef41Sopenharmony_ci super(); 121cb0ef41Sopenharmony_ci this.server_cert = server_cert; 131cb0ef41Sopenharmony_ci this.version = Buffer.from('0303', 'hex'); 141cb0ef41Sopenharmony_ci this.handshake_list = []; 151cb0ef41Sopenharmony_ci // AES128-GCM-SHA256 161cb0ef41Sopenharmony_ci this.ciphers = Buffer.from('000002009c0', 'hex'); 171cb0ef41Sopenharmony_ci this.pre_primary_secret = 181cb0ef41Sopenharmony_ci Buffer.concat([this.version, crypto.randomBytes(46)]); 191cb0ef41Sopenharmony_ci this.primary_secret = null; 201cb0ef41Sopenharmony_ci this.write_seq = 0; 211cb0ef41Sopenharmony_ci this.client_random = crypto.randomBytes(32); 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci this.on('handshake', (msg) => { 241cb0ef41Sopenharmony_ci this.handshake_list.push(msg); 251cb0ef41Sopenharmony_ci }); 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ci this.on('server_random', (server_random) => { 281cb0ef41Sopenharmony_ci this.primary_secret = PRF12('sha256', this.pre_primary_secret, 291cb0ef41Sopenharmony_ci 'primary secret', 301cb0ef41Sopenharmony_ci Buffer.concat([this.client_random, 311cb0ef41Sopenharmony_ci server_random]), 321cb0ef41Sopenharmony_ci 48); 331cb0ef41Sopenharmony_ci const key_block = PRF12('sha256', this.primary_secret, 341cb0ef41Sopenharmony_ci 'key expansion', 351cb0ef41Sopenharmony_ci Buffer.concat([server_random, 361cb0ef41Sopenharmony_ci this.client_random]), 371cb0ef41Sopenharmony_ci 40); 381cb0ef41Sopenharmony_ci this.client_writeKey = key_block.slice(0, 16); 391cb0ef41Sopenharmony_ci this.client_writeIV = key_block.slice(32, 36); 401cb0ef41Sopenharmony_ci }); 411cb0ef41Sopenharmony_ci } 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci createClientHello() { 441cb0ef41Sopenharmony_ci const compressions = Buffer.from('0100', 'hex'); // null 451cb0ef41Sopenharmony_ci const msg = addHandshakeHeader(0x01, Buffer.concat([ 461cb0ef41Sopenharmony_ci this.version, this.client_random, this.ciphers, compressions, 471cb0ef41Sopenharmony_ci ])); 481cb0ef41Sopenharmony_ci this.emit('handshake', msg); 491cb0ef41Sopenharmony_ci return addRecordHeader(0x16, msg); 501cb0ef41Sopenharmony_ci } 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci createClientKeyExchange() { 531cb0ef41Sopenharmony_ci const encrypted_pre_primary_secret = crypto.publicEncrypt({ 541cb0ef41Sopenharmony_ci key: this.server_cert, 551cb0ef41Sopenharmony_ci padding: crypto.constants.RSA_PKCS1_PADDING, 561cb0ef41Sopenharmony_ci }, this.pre_primary_secret); 571cb0ef41Sopenharmony_ci const length = Buffer.alloc(2); 581cb0ef41Sopenharmony_ci length.writeUIntBE(encrypted_pre_primary_secret.length, 0, 2); 591cb0ef41Sopenharmony_ci const msg = addHandshakeHeader(0x10, Buffer.concat([ 601cb0ef41Sopenharmony_ci length, encrypted_pre_primary_secret])); 611cb0ef41Sopenharmony_ci this.emit('handshake', msg); 621cb0ef41Sopenharmony_ci return addRecordHeader(0x16, msg); 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ci createFinished() { 661cb0ef41Sopenharmony_ci const shasum = crypto.createHash('sha256'); 671cb0ef41Sopenharmony_ci shasum.update(Buffer.concat(this.handshake_list)); 681cb0ef41Sopenharmony_ci const message_hash = shasum.digest(); 691cb0ef41Sopenharmony_ci const r = PRF12('sha256', this.primary_secret, 701cb0ef41Sopenharmony_ci 'client finished', message_hash, 12); 711cb0ef41Sopenharmony_ci const msg = addHandshakeHeader(0x14, r); 721cb0ef41Sopenharmony_ci this.emit('handshake', msg); 731cb0ef41Sopenharmony_ci return addRecordHeader(0x16, msg); 741cb0ef41Sopenharmony_ci } 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci createIllegalHandshake() { 771cb0ef41Sopenharmony_ci const illegal_handshake = Buffer.alloc(5); 781cb0ef41Sopenharmony_ci return addRecordHeader(0x16, illegal_handshake); 791cb0ef41Sopenharmony_ci } 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci parseTLSFrame(buf) { 821cb0ef41Sopenharmony_ci let offset = 0; 831cb0ef41Sopenharmony_ci const record = buf.slice(offset, 5); 841cb0ef41Sopenharmony_ci const type = record[0]; 851cb0ef41Sopenharmony_ci const length = record.slice(3, 5).readUInt16BE(0); 861cb0ef41Sopenharmony_ci offset += 5; 871cb0ef41Sopenharmony_ci let remaining = buf.slice(offset, offset + length); 881cb0ef41Sopenharmony_ci if (type === 0x16) { 891cb0ef41Sopenharmony_ci do { 901cb0ef41Sopenharmony_ci remaining = this.parseTLSHandshake(remaining); 911cb0ef41Sopenharmony_ci } while (remaining.length > 0); 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci offset += length; 941cb0ef41Sopenharmony_ci return buf.slice(offset); 951cb0ef41Sopenharmony_ci } 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci parseTLSHandshake(buf) { 981cb0ef41Sopenharmony_ci let offset = 0; 991cb0ef41Sopenharmony_ci const handshake_type = buf[offset]; 1001cb0ef41Sopenharmony_ci if (handshake_type === 0x02) { 1011cb0ef41Sopenharmony_ci const server_random = buf.slice(6, 6 + 32); 1021cb0ef41Sopenharmony_ci this.emit('server_random', server_random); 1031cb0ef41Sopenharmony_ci } 1041cb0ef41Sopenharmony_ci offset += 1; 1051cb0ef41Sopenharmony_ci const length = buf.readUIntBE(offset, 3); 1061cb0ef41Sopenharmony_ci offset += 3; 1071cb0ef41Sopenharmony_ci const handshake = buf.slice(0, offset + length); 1081cb0ef41Sopenharmony_ci this.emit('handshake', handshake); 1091cb0ef41Sopenharmony_ci offset += length; 1101cb0ef41Sopenharmony_ci const remaining = buf.slice(offset); 1111cb0ef41Sopenharmony_ci return remaining; 1121cb0ef41Sopenharmony_ci } 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci encrypt(plain) { 1151cb0ef41Sopenharmony_ci const type = plain.slice(0, 1); 1161cb0ef41Sopenharmony_ci const version = plain.slice(1, 3); 1171cb0ef41Sopenharmony_ci const nonce = crypto.randomBytes(8); 1181cb0ef41Sopenharmony_ci const iv = Buffer.concat([this.client_writeIV.slice(0, 4), nonce]); 1191cb0ef41Sopenharmony_ci const bob = crypto.createCipheriv('aes-128-gcm', this.client_writeKey, iv); 1201cb0ef41Sopenharmony_ci const write_seq = Buffer.alloc(8); 1211cb0ef41Sopenharmony_ci write_seq.writeUInt32BE(this.write_seq++, 4); 1221cb0ef41Sopenharmony_ci const aad = Buffer.concat([write_seq, plain.slice(0, 5)]); 1231cb0ef41Sopenharmony_ci bob.setAAD(aad); 1241cb0ef41Sopenharmony_ci const encrypted1 = bob.update(plain.slice(5)); 1251cb0ef41Sopenharmony_ci const encrypted = Buffer.concat([encrypted1, bob.final()]); 1261cb0ef41Sopenharmony_ci const tag = bob.getAuthTag(); 1271cb0ef41Sopenharmony_ci const length = Buffer.alloc(2); 1281cb0ef41Sopenharmony_ci length.writeUInt16BE(nonce.length + encrypted.length + tag.length, 0); 1291cb0ef41Sopenharmony_ci return Buffer.concat([type, version, length, nonce, encrypted, tag]); 1301cb0ef41Sopenharmony_ci } 1311cb0ef41Sopenharmony_ci} 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_cifunction addRecordHeader(type, frame) { 1341cb0ef41Sopenharmony_ci const record_layer = Buffer.from('0003030000', 'hex'); 1351cb0ef41Sopenharmony_ci record_layer[0] = type; 1361cb0ef41Sopenharmony_ci record_layer.writeUInt16BE(frame.length, 3); 1371cb0ef41Sopenharmony_ci return Buffer.concat([record_layer, frame]); 1381cb0ef41Sopenharmony_ci} 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_cifunction addHandshakeHeader(type, msg) { 1411cb0ef41Sopenharmony_ci const handshake_header = Buffer.alloc(4); 1421cb0ef41Sopenharmony_ci handshake_header[0] = type; 1431cb0ef41Sopenharmony_ci handshake_header.writeUIntBE(msg.length, 1, 3); 1441cb0ef41Sopenharmony_ci return Buffer.concat([handshake_header, msg]); 1451cb0ef41Sopenharmony_ci} 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_cifunction PRF12(algo, secret, label, seed, size) { 1481cb0ef41Sopenharmony_ci const newSeed = Buffer.concat([Buffer.from(label, 'utf8'), seed]); 1491cb0ef41Sopenharmony_ci return P_hash(algo, secret, newSeed, size); 1501cb0ef41Sopenharmony_ci} 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_cifunction P_hash(algo, secret, seed, size) { 1531cb0ef41Sopenharmony_ci const result = Buffer.alloc(size); 1541cb0ef41Sopenharmony_ci let hmac = crypto.createHmac(algo, secret); 1551cb0ef41Sopenharmony_ci hmac.update(seed); 1561cb0ef41Sopenharmony_ci let a = hmac.digest(); 1571cb0ef41Sopenharmony_ci let j = 0; 1581cb0ef41Sopenharmony_ci while (j < size) { 1591cb0ef41Sopenharmony_ci hmac = crypto.createHmac(algo, secret); 1601cb0ef41Sopenharmony_ci hmac.update(a); 1611cb0ef41Sopenharmony_ci hmac.update(seed); 1621cb0ef41Sopenharmony_ci const b = hmac.digest(); 1631cb0ef41Sopenharmony_ci let todo = b.length; 1641cb0ef41Sopenharmony_ci if (j + todo > size) { 1651cb0ef41Sopenharmony_ci todo = size - j; 1661cb0ef41Sopenharmony_ci } 1671cb0ef41Sopenharmony_ci b.copy(result, j, 0, todo); 1681cb0ef41Sopenharmony_ci j += todo; 1691cb0ef41Sopenharmony_ci hmac = crypto.createHmac(algo, secret); 1701cb0ef41Sopenharmony_ci hmac.update(a); 1711cb0ef41Sopenharmony_ci a = hmac.digest(); 1721cb0ef41Sopenharmony_ci } 1731cb0ef41Sopenharmony_ci return result; 1741cb0ef41Sopenharmony_ci} 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ciexports.TestTLSSocket = TestTLSSocket; 177