async _readEncryptedRecord()

in src/recordlayer.js [306:345]


  async _readEncryptedRecord(type, length, buf) {
    if (length > MAX_ENCRYPTED_RECORD_SIZE) {
      throw new TLSError(ALERT_DESCRIPTION.RECORD_OVERFLOW);
    }
    // The outer type for encrypted records is always APPLICATION_DATA.
    if (type !== RECORD_TYPE.APPLICATION_DATA) {
      throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
    }
    // Decrypt and decode the contained `TLSInnerPlaintext` struct:
    //
    //    struct {
    //        opaque content[TLSPlaintext.length];
    //        ContentType type;
    //        uint8 zeros[length_of_padding];
    //    } TLSInnerPlaintext;
    //
    // The additional data for the decryption is the `TLSCiphertext` record
    // header, which is a fixed size and immediately prior to current buffer position.
    buf.incr(-RECORD_HEADER_SIZE);
    const additionalData = buf.readBytes(RECORD_HEADER_SIZE);
    const ciphertext = buf.readBytes(length);
    const paddedPlaintext = await this._recvDecryptState.decrypt(ciphertext, additionalData);
    // We have to scan backwards over the zero padding at the end of the struct
    // in order to find the non-zero `type` byte.
    let i;
    for (i = paddedPlaintext.byteLength - 1; i >= 0; i--) {
      if (paddedPlaintext[i] !== 0) {
        break;
      }
    }
    if (i < 0) {
      throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
    }
    type = paddedPlaintext[i];
    // `change_cipher_spec` records must always be plaintext.
    if (type === RECORD_TYPE.CHANGE_CIPHER_SPEC) {
      throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
    }
    return [type, paddedPlaintext.slice(0, i)];
  }