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