in src/recordlayer.js [238:292]
async recv(data) {
if (this._recvError !== null) {
throw this._recvError;
}
// For simplicity, we assume that the given data contains exactly one record.
// Peers using this library will send one record at a time over the websocket
// connection, and we can assume that the server-side websocket bridge will split
// up any traffic into individual records if we ever start interoperating with
// peers using a different TLS implementation.
// Similarly, we assume that handshake messages will not be fragmented across
// multiple records. This should be trivially true for the PSK-only mode used
// by this library, but we may want to relax it in future for interoperability
// with e.g. large ClientHello messages that contain lots of different options.
const buf = new BufferReader(data);
// The data to read is either a TLSPlaintext or TLSCiphertext struct,
// depending on whether record protection has been enabled yet:
//
// struct {
// ContentType type;
// ProtocolVersion legacy_record_version;
// uint16 length;
// opaque fragment[TLSPlaintext.length];
// } TLSPlaintext;
//
// struct {
// ContentType opaque_type = application_data; /* 23 */
// ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */
// uint16 length;
// opaque encrypted_record[TLSCiphertext.length];
// } TLSCiphertext;
//
let type = buf.readUint8();
// The spec says legacy_record_version "MUST be ignored for all purposes",
// but we know TLS1.3 implementations will only ever emit two possible values,
// so it seems useful to bail out early if we receive anything else.
const version = buf.readUint16();
if (version !== VERSION_TLS_1_2) {
// TLS1.0 is only acceptable on initial plaintext records.
if (this._recvDecryptState !== null || version !== VERSION_TLS_1_0) {
throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
}
}
const length = buf.readUint16();
let plaintext;
if (this._recvDecryptState === null || type === RECORD_TYPE.CHANGE_CIPHER_SPEC) {
[type, plaintext] = await this._readPlaintextRecord(type, length, buf);
} else {
[type, plaintext] = await this._readEncryptedRecord(type, length, buf);
}
// Sanity-check that we received exactly one record.
if (buf.hasMoreBytes()) {
throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
}
return [type, plaintext];
}