3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 * The following bundle is from an external repository at github.com/mozilla/fxa-pairing-channel,
8 * it implements a shared library for two javascript environments to create an encrypted and authenticated
9 * communication channel by sharing a secret key and by relaying messages through a websocket server.
11 * It is used by the Firefox Accounts pairing flow, with one side of the channel being web
12 * content from https://accounts.firefox.com and the other side of the channel being chrome native code.
14 * This uses the event-target-shim node library published under the MIT license:
15 * https://github.com/mysticatea/event-target-shim/blob/master/LICENSE
17 * Bundle generated from https://github.com/mozilla/fxa-pairing-channel.git. Hash:c8ec3119920b4ffa833b, Chunkhash:378a5f51445e7aa7630e.
21 // This header provides a little bit of plumbing to use `FxAccountsPairingChannel`
22 // from Firefox browser code, hence the presence of these privileged browser APIs.
23 // If you're trying to use this from ordinary web content you're in for a bad time.
25 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
26 const {setTimeout} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
27 // We cannot use WebSocket from chrome code without a window,
28 // see https://bugzilla.mozilla.org/show_bug.cgi?id=784686
29 const browser = Services.appShell.createWindowlessBrowser(true);
30 const {WebSocket} = browser.document.ownerGlobal;
32 const EXPORTED_SYMBOLS = ["FxAccountsPairingChannel"];
34 var FxAccountsPairingChannel =
35 /******/ (function(modules) { // webpackBootstrap
36 /******/ // The module cache
37 /******/ var installedModules = {};
39 /******/ // The require function
40 /******/ function __webpack_require__(moduleId) {
42 /******/ // Check if module is in cache
43 /******/ if(installedModules[moduleId]) {
44 /******/ return installedModules[moduleId].exports;
46 /******/ // Create a new module (and put it into the cache)
47 /******/ var module = installedModules[moduleId] = {
53 /******/ // Execute the module function
54 /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
56 /******/ // Flag the module as loaded
57 /******/ module.l = true;
59 /******/ // Return the exports of the module
60 /******/ return module.exports;
64 /******/ // expose the modules object (__webpack_modules__)
65 /******/ __webpack_require__.m = modules;
67 /******/ // expose the module cache
68 /******/ __webpack_require__.c = installedModules;
70 /******/ // define getter function for harmony exports
71 /******/ __webpack_require__.d = function(exports, name, getter) {
72 /******/ if(!__webpack_require__.o(exports, name)) {
73 /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
77 /******/ // define __esModule on exports
78 /******/ __webpack_require__.r = function(exports) {
79 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
80 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
82 /******/ Object.defineProperty(exports, '__esModule', { value: true });
85 /******/ // create a fake namespace object
86 /******/ // mode & 1: value is a module id, require it
87 /******/ // mode & 2: merge all properties of value into the ns
88 /******/ // mode & 4: return value when already ns object
89 /******/ // mode & 8|1: behave like require
90 /******/ __webpack_require__.t = function(value, mode) {
91 /******/ if(mode & 1) value = __webpack_require__(value);
92 /******/ if(mode & 8) return value;
93 /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
94 /******/ var ns = Object.create(null);
95 /******/ __webpack_require__.r(ns);
96 /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
97 /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
101 /******/ // getDefaultExport function for compatibility with non-harmony modules
102 /******/ __webpack_require__.n = function(module) {
103 /******/ var getter = module && module.__esModule ?
104 /******/ function getDefault() { return module['default']; } :
105 /******/ function getModuleExports() { return module; };
106 /******/ __webpack_require__.d(getter, 'a', getter);
107 /******/ return getter;
110 /******/ // Object.prototype.hasOwnProperty.call
111 /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
113 /******/ // __webpack_public_path__
114 /******/ __webpack_require__.p = "";
117 /******/ // Load entry module and return exports
118 /******/ return __webpack_require__(__webpack_require__.s = 0);
120 /************************************************************************/
123 /***/ (function(module, __webpack_exports__, __webpack_require__) {
127 __webpack_require__.r(__webpack_exports__);
130 __webpack_require__.d(__webpack_exports__, "PairingChannel", function() { return /* binding */ src_PairingChannel; });
131 __webpack_require__.d(__webpack_exports__, "base64urlToBytes", function() { return /* reexport */ base64urlToBytes; });
132 __webpack_require__.d(__webpack_exports__, "bytesToBase64url", function() { return /* reexport */ bytesToBase64url; });
133 __webpack_require__.d(__webpack_exports__, "bytesToHex", function() { return /* reexport */ bytesToHex; });
134 __webpack_require__.d(__webpack_exports__, "bytesToUtf8", function() { return /* reexport */ bytesToUtf8; });
135 __webpack_require__.d(__webpack_exports__, "hexToBytes", function() { return /* reexport */ hexToBytes; });
136 __webpack_require__.d(__webpack_exports__, "TLSCloseNotify", function() { return /* reexport */ TLSCloseNotify; });
137 __webpack_require__.d(__webpack_exports__, "TLSError", function() { return /* reexport */ TLSError; });
138 __webpack_require__.d(__webpack_exports__, "utf8ToBytes", function() { return /* reexport */ utf8ToBytes; });
139 __webpack_require__.d(__webpack_exports__, "_internals", function() { return /* binding */ _internals; });
141 // CONCATENATED MODULE: ./src/alerts.js
142 /* This Source Code Form is subject to the terms of the Mozilla Public
143 * License, v. 2.0. If a copy of the MPL was not distributed with this
144 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
146 /* eslint-disable sorting/sort-object-props */
147 const ALERT_LEVEL = {
152 const ALERT_DESCRIPTION = {
154 UNEXPECTED_MESSAGE: 10,
157 HANDSHAKE_FAILURE: 40,
158 ILLEGAL_PARAMETER: 47,
161 PROTOCOL_VERSION: 70,
163 MISSING_EXTENSION: 109,
164 UNSUPPORTED_EXTENSION: 110,
165 UNKNOWN_PSK_IDENTITY: 115,
166 NO_APPLICATION_PROTOCOL: 120,
168 /* eslint-enable sorting/sort-object-props */
170 function alertTypeToName(type) {
171 for (const name in ALERT_DESCRIPTION) {
172 if (ALERT_DESCRIPTION[name] === type) {
173 return `${name} (${type})`;
176 return `UNKNOWN (${type})`;
179 class TLSAlert extends Error {
180 constructor(description, level) {
181 super(`TLS Alert: ${alertTypeToName(description)}`);
182 this.description = description;
186 static fromBytes(bytes) {
187 if (bytes.byteLength !== 2) {
188 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
191 case ALERT_DESCRIPTION.CLOSE_NOTIFY:
192 if (bytes[0] !== ALERT_LEVEL.WARNING) {
193 // Close notifications should be fatal.
194 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
196 return new TLSCloseNotify();
198 return new TLSError(bytes[1]);
203 return new Uint8Array([this.level, this.description]);
207 class TLSCloseNotify extends TLSAlert {
209 super(ALERT_DESCRIPTION.CLOSE_NOTIFY, ALERT_LEVEL.WARNING);
213 class TLSError extends TLSAlert {
214 constructor(description = ALERT_DESCRIPTION.INTERNAL_ERROR) {
215 super(description, ALERT_LEVEL.FATAL);
219 // CONCATENATED MODULE: ./src/utils.js
220 /* This Source Code Form is subject to the terms of the Mozilla Public
221 * License, v. 2.0. If a copy of the MPL was not distributed with this
222 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
227 // Various low-level utility functions.
229 // These are mostly conveniences for working with Uint8Arrays as
230 // the primitive "bytes" type.
233 const UTF8_ENCODER = new TextEncoder();
234 const UTF8_DECODER = new TextDecoder();
238 function assert(cond, msg) {
240 throw new Error('assert failed: ' + msg);
244 function assertIsBytes(value, msg = 'value must be a Uint8Array') {
245 // Using `value instanceof Uint8Array` seems to fail in Firefox chrome code
246 // for inscrutable reasons, so we do a less direct check.
247 assert(ArrayBuffer.isView(value), msg);
248 assert(value.BYTES_PER_ELEMENT === 1, msg);
252 const EMPTY = new Uint8Array(0);
255 return new Uint8Array(n);
258 function arrayToBytes(value) {
259 return new Uint8Array(value);
262 function bytesToHex(bytes) {
263 return Array.prototype.map.call(bytes, byte => {
264 let s = byte.toString(16);
265 if (s.length === 1) {
272 function hexToBytes(hexstr) {
273 assert(hexstr.length % 2 === 0, 'hexstr.length must be even');
274 return new Uint8Array(Array.prototype.map.call(hexstr, (c, n) => {
276 return hexstr[n - 1] + c;
283 return parseInt(s, 16);
287 function bytesToUtf8(bytes) {
288 return UTF8_DECODER.decode(bytes);
291 function utf8ToBytes(str) {
292 return UTF8_ENCODER.encode(str);
295 function bytesToBase64url(bytes) {
296 // XXX TODO: try to use something constant-time, in case calling code
297 // uses it to encode secrets?
298 const charCodes = String.fromCharCode.apply(String, bytes);
299 return btoa(charCodes).replace(/\+/g, '-').replace(/\//g, '_');
302 function base64urlToBytes(str) {
303 // XXX TODO: try to use something constant-time, in case calling code
304 // uses it to decode secrets?
305 str = atob(str.replace(/-/g, '+').replace(/_/g, '/'));
306 const bytes = new Uint8Array(str.length);
307 for (let i = 0; i < str.length; i++) {
308 bytes[i] = str.charCodeAt(i);
313 function bytesAreEqual(v1, v2) {
316 if (v1.length !== v2.length) {
319 for (let i = 0; i < v1.length; i++) {
320 if (v1[i] !== v2[i]) {
327 // The `BufferReader` and `BufferWriter` classes are helpers for dealing with the
328 // binary struct format that's used for various TLS message. Think of them as a
329 // buffer with a pointer to the "current position" and a bunch of helper methods
330 // to read/write structured data and advance said pointer.
332 class utils_BufferWithPointer {
335 this._dataview = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
340 return this._buffer.byteLength;
349 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
351 if (pos > this.length()) {
352 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
358 this.seek(this._pos + offset);
362 // The `BufferReader` class helps you read structured data from a byte array.
363 // It offers methods for reading both primitive values, and the variable-length
364 // vector structures defined in https://tools.ietf.org/html/rfc8446#section-3.4.
366 // Such vectors are represented as a length followed by the concatenated
367 // bytes of each item, and the size of the length field is determined by
368 // the maximum allowed number of bytes in the vector. For example
369 // to read a vector that may contain up to 65535 bytes, use `readVector16`.
371 // To read a variable-length vector of between 1 and 100 uint16 values,
372 // defined in the RFC like this:
374 // uint16 items<2..200>;
376 // You would do something like this:
379 // buf.readVector8(buf => {
380 // items.push(buf.readUint16())
383 // The various `read` will throw `DECODE_ERROR` if you attempt to read path
384 // the end of the buffer, or past the end of a variable-length list.
386 class utils_BufferReader extends utils_BufferWithPointer {
389 return this.tell() < this.length();
393 // This avoids copies by returning a view onto the existing buffer.
394 const start = this._buffer.byteOffset + this.tell();
396 return new Uint8Array(this._buffer.buffer, start, length);
399 _rangeErrorToAlert(cb) {
403 if (err instanceof RangeError) {
404 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
411 return this._rangeErrorToAlert(() => {
412 const n = this._dataview.getUint8(this._pos);
419 return this._rangeErrorToAlert(() => {
420 const n = this._dataview.getUint16(this._pos);
427 return this._rangeErrorToAlert(() => {
428 let n = this._dataview.getUint16(this._pos);
429 n = (n << 8) | this._dataview.getUint8(this._pos + 2);
436 return this._rangeErrorToAlert(() => {
437 const n = this._dataview.getUint32(this._pos);
443 _readVector(length, cb) {
444 const contentsBuf = new utils_BufferReader(this.readBytes(length));
445 const expectedEnd = this.tell();
446 // Keep calling the callback until we've consumed the expected number of bytes.
448 while (contentsBuf.hasMoreBytes()) {
449 const prevPos = contentsBuf.tell();
451 // Check that the callback made forward progress, otherwise we'll infinite loop.
452 if (contentsBuf.tell() <= prevPos) {
453 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
457 // Check that the callback correctly consumed the vector's entire contents.
458 if (this.tell() !== expectedEnd) {
459 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
464 const length = this.readUint8();
465 return this._readVector(length, cb);
469 const length = this.readUint16();
470 return this._readVector(length, cb);
474 const length = this.readUint24();
475 return this._readVector(length, cb);
479 return this.readBytes(this.readUint8());
482 readVectorBytes16() {
483 return this.readBytes(this.readUint16());
486 readVectorBytes24() {
487 return this.readBytes(this.readUint24());
492 class utils_BufferWriter extends utils_BufferWithPointer {
493 constructor(size = 1024) {
494 super(new Uint8Array(size));
498 const curSize = this._buffer.byteLength;
499 const newPos = this._pos + n;
500 const shortfall = newPos - curSize;
502 // Classic grow-by-doubling, up to 4kB max increment.
503 // This formula was not arrived at by any particular science.
504 const incr = Math.min(curSize, 4 * 1024);
505 const newbuf = new Uint8Array(curSize + Math.ceil(shortfall / incr) * incr);
506 newbuf.set(this._buffer, 0);
507 this._buffer = newbuf;
508 this._dataview = new DataView(newbuf.buffer, newbuf.byteOffset, newbuf.byteLength);
512 slice(start = 0, end = this.tell()) {
514 end = this.tell() + end;
517 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
520 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
522 if (end > this.length()) {
523 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
525 return this._buffer.slice(start, end);
529 const slice = this.slice();
535 this._maybeGrow(data.byteLength);
536 this._buffer.set(data, this.tell());
537 this.incr(data.byteLength);
542 this._dataview.setUint8(this._pos, n);
548 this._dataview.setUint16(this._pos, n);
554 this._dataview.setUint16(this._pos, n >> 8);
555 this._dataview.setUint8(this._pos + 2, n & 0xFF);
561 this._dataview.setUint32(this._pos, n);
565 // These are helpers for writing the variable-length vector structure
566 // defined in https://tools.ietf.org/html/rfc8446#section-3.4.
568 // Such vectors are represented as a length followed by the concatenated
569 // bytes of each item, and the size of the length field is determined by
570 // the maximum allowed size of the vector. For example to write a vector
571 // that may contain up to 65535 bytes, use `writeVector16`.
573 // To write a variable-length vector of between 1 and 100 uint16 values,
574 // defined in the RFC like this:
576 // uint16 items<2..200>;
578 // You would do something like this:
580 // buf.writeVector8(buf => {
581 // for (let item of items) {
582 // buf.writeUint16(item)
586 // The helper will automatically take care of writing the appropriate
587 // length field once the callback completes.
589 _writeVector(maxLength, writeLength, cb) {
590 // Initially, write the length field as zero.
591 const lengthPos = this.tell();
593 // Call the callback to write the vector items.
594 const bodyPos = this.tell();
596 const length = this.tell() - bodyPos;
597 if (length >= maxLength) {
598 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
600 // Backfill the actual length field.
601 this.seek(lengthPos);
608 return this._writeVector(Math.pow(2, 8), len => this.writeUint8(len), cb);
612 return this._writeVector(Math.pow(2, 16), len => this.writeUint16(len), cb);
616 return this._writeVector(Math.pow(2, 24), len => this.writeUint24(len), cb);
619 writeVectorBytes8(bytes) {
620 return this.writeVector8(buf => {
621 buf.writeBytes(bytes);
625 writeVectorBytes16(bytes) {
626 return this.writeVector16(buf => {
627 buf.writeBytes(bytes);
631 writeVectorBytes24(bytes) {
632 return this.writeVector24(buf => {
633 buf.writeBytes(bytes);
638 // CONCATENATED MODULE: ./src/crypto.js
639 /* This Source Code Form is subject to the terms of the Mozilla Public
640 * License, v. 2.0. If a copy of the MPL was not distributed with this
641 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
644 // Low-level crypto primitives.
646 // This file implements the AEAD encrypt/decrypt and hashing routines
647 // for the TLS_AES_128_GCM_SHA256 ciphersuite. They are (thankfully)
648 // fairly light-weight wrappers around what's available via the WebCrypto
655 const AEAD_SIZE_INFLATION = 16;
656 const KEY_LENGTH = 16;
657 const IV_LENGTH = 12;
658 const HASH_LENGTH = 32;
660 async function prepareKey(key, mode) {
661 return crypto.subtle.importKey('raw', key, { name: 'AES-GCM' }, false, [mode]);
664 async function encrypt(key, iv, plaintext, additionalData) {
665 const ciphertext = await crypto.subtle.encrypt({
669 tagLength: AEAD_SIZE_INFLATION * 8
671 return new Uint8Array(ciphertext);
674 async function decrypt(key, iv, ciphertext, additionalData) {
676 const plaintext = await crypto.subtle.decrypt({
680 tagLength: AEAD_SIZE_INFLATION * 8
682 return new Uint8Array(plaintext);
684 // Yes, we really do throw 'decrypt_error' when failing to verify a HMAC,
685 // and a 'bad_record_mac' error when failing to decrypt.
686 throw new TLSError(ALERT_DESCRIPTION.BAD_RECORD_MAC);
690 async function hash(message) {
691 return new Uint8Array(await crypto.subtle.digest({ name: 'SHA-256' }, message));
694 async function hmac(keyBytes, message) {
695 const key = await crypto.subtle.importKey('raw', keyBytes, {
696 hash: { name: 'SHA-256' },
699 const sig = await crypto.subtle.sign({ name: 'HMAC' }, key, message);
700 return new Uint8Array(sig);
703 async function verifyHmac(keyBytes, signature, message) {
704 const key = await crypto.subtle.importKey('raw', keyBytes, {
705 hash: { name: 'SHA-256' },
707 }, false, ['verify']);
708 if (! await crypto.subtle.verify({ name: 'HMAC' }, key, signature, message)) {
709 // Yes, we really do throw 'decrypt_error' when failing to verify a HMAC,
710 // and a 'bad_record_mac' error when failing to decrypt.
711 throw new TLSError(ALERT_DESCRIPTION.DECRYPT_ERROR);
715 async function hkdfExtract(salt, ikm) {
716 // Ref https://tools.ietf.org/html/rfc5869#section-2.2
717 return await hmac(salt, ikm);
720 async function hkdfExpand(prk, info, length) {
721 // Ref https://tools.ietf.org/html/rfc5869#section-2.3
722 const N = Math.ceil(length / HASH_LENGTH);
724 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
727 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
729 const input = new utils_BufferWriter();
730 const output = new utils_BufferWriter();
731 let T = new Uint8Array(0);
732 for (let i = 1; i <= N; i++) {
734 input.writeBytes(info);
736 T = await hmac(prk, input.flush());
737 output.writeBytes(T);
739 return output.slice(0, length);
742 async function hkdfExpandLabel(secret, label, context, length) {
744 // uint16 length = Length;
745 // opaque label < 7..255 > = "tls13 " + Label;
746 // opaque context < 0..255 > = Context;
748 const hkdfLabel = new utils_BufferWriter();
749 hkdfLabel.writeUint16(length);
750 hkdfLabel.writeVectorBytes8(utf8ToBytes('tls13 ' + label));
751 hkdfLabel.writeVectorBytes8(context);
752 return hkdfExpand(secret, hkdfLabel.flush(), length);
755 async function getRandomBytes(size) {
756 const bytes = new Uint8Array(size);
757 crypto.getRandomValues(bytes);
761 // CONCATENATED MODULE: ./src/extensions.js
762 /* This Source Code Form is subject to the terms of the Mozilla Public
763 * License, v. 2.0. If a copy of the MPL was not distributed with this
764 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
767 // Extension parsing.
769 // This file contains some helpers for reading/writing the various kinds
770 // of Extension that might appear in a HandshakeMessage.
772 // "Extensions" are how TLS signals the presence of particular bits of optional
773 // functionality in the protocol. Lots of parts of TLS1.3 that don't seem like
774 // they're optional are implemented in terms of an extension, IIUC because that's
775 // what was needed for a clean deployment in amongst earlier versions of the protocol.
782 /* eslint-disable sorting/sort-object-props */
783 const EXTENSION_TYPE = {
785 SUPPORTED_VERSIONS: 43,
786 PSK_KEY_EXCHANGE_MODES: 45,
788 /* eslint-enable sorting/sort-object-props */
790 // Base class for generic reading/writing of extensions,
791 // which are all uniformly formatted as:
794 // ExtensionType extension_type;
795 // opaque extension_data<0..2^16-1>;
798 // Extensions always appear inside of a handshake message,
799 // and their internal structure may differ based on the
800 // type of that message.
802 class extensions_Extension {
805 throw new Error('not implemented');
808 static read(messageType, buf) {
809 const type = buf.readUint16();
813 buf.readVector16(buf => {
815 case EXTENSION_TYPE.PRE_SHARED_KEY:
816 ext = extensions_PreSharedKeyExtension._read(messageType, buf);
818 case EXTENSION_TYPE.SUPPORTED_VERSIONS:
819 ext = extensions_SupportedVersionsExtension._read(messageType, buf);
821 case EXTENSION_TYPE.PSK_KEY_EXCHANGE_MODES:
822 ext = extensions_PskKeyExchangeModesExtension._read(messageType, buf);
825 // Skip over unrecognised extensions.
826 buf.incr(buf.length());
828 if (buf.hasMoreBytes()) {
829 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
835 write(messageType, buf) {
836 buf.writeUint16(this.TYPE_TAG);
837 buf.writeVector16(buf => {
838 this._write(messageType, buf);
842 static _read(messageType, buf) {
843 throw new Error('not implemented');
846 static _write(messageType, buf) {
847 throw new Error('not implemented');
851 // The PreSharedKey extension:
854 // opaque identity<1..2^16-1>;
855 // uint32 obfuscated_ticket_age;
857 // opaque PskBinderEntry<32..255>;
859 // PskIdentity identities<7..2^16-1>;
860 // PskBinderEntry binders<33..2^16-1>;
863 // select(Handshake.msg_type) {
864 // case client_hello: OfferedPsks;
865 // case server_hello: uint16 selected_identity;
867 // } PreSharedKeyExtension;
869 class extensions_PreSharedKeyExtension extends extensions_Extension {
870 constructor(identities, binders, selectedIdentity) {
872 this.identities = identities;
873 this.binders = binders;
874 this.selectedIdentity = selectedIdentity;
878 return EXTENSION_TYPE.PRE_SHARED_KEY;
881 static _read(messageType, buf) {
882 let identities = null, binders = null, selectedIdentity = null;
883 switch (messageType) {
884 case HANDSHAKE_TYPE.CLIENT_HELLO:
885 identities = []; binders = [];
886 buf.readVector16(buf => {
887 const identity = buf.readVectorBytes16();
888 buf.readBytes(4); // Skip over the ticket age.
889 identities.push(identity);
891 buf.readVector16(buf => {
892 const binder = buf.readVectorBytes8();
893 if (binder.byteLength < HASH_LENGTH) {
894 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
896 binders.push(binder);
898 if (identities.length !== binders.length) {
899 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
902 case HANDSHAKE_TYPE.SERVER_HELLO:
903 selectedIdentity = buf.readUint16();
906 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
908 return new this(identities, binders, selectedIdentity);
911 _write(messageType, buf) {
912 switch (messageType) {
913 case HANDSHAKE_TYPE.CLIENT_HELLO:
914 buf.writeVector16(buf => {
915 this.identities.forEach(pskId => {
916 buf.writeVectorBytes16(pskId);
917 buf.writeUint32(0); // Zero for "tag age" field.
920 buf.writeVector16(buf => {
921 this.binders.forEach(pskBinder => {
922 buf.writeVectorBytes8(pskBinder);
926 case HANDSHAKE_TYPE.SERVER_HELLO:
927 buf.writeUint16(this.selectedIdentity);
930 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
936 // The SupportedVersions extension:
939 // select(Handshake.msg_type) {
940 // case client_hello:
941 // ProtocolVersion versions < 2..254 >;
942 // case server_hello:
943 // ProtocolVersion selected_version;
945 // } SupportedVersions;
947 class extensions_SupportedVersionsExtension extends extensions_Extension {
948 constructor(versions, selectedVersion) {
950 this.versions = versions;
951 this.selectedVersion = selectedVersion;
955 return EXTENSION_TYPE.SUPPORTED_VERSIONS;
958 static _read(messageType, buf) {
959 let versions = null, selectedVersion = null;
960 switch (messageType) {
961 case HANDSHAKE_TYPE.CLIENT_HELLO:
963 buf.readVector8(buf => {
964 versions.push(buf.readUint16());
967 case HANDSHAKE_TYPE.SERVER_HELLO:
968 selectedVersion = buf.readUint16();
971 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
973 return new this(versions, selectedVersion);
976 _write(messageType, buf) {
977 switch (messageType) {
978 case HANDSHAKE_TYPE.CLIENT_HELLO:
979 buf.writeVector8(buf => {
980 this.versions.forEach(version => {
981 buf.writeUint16(version);
985 case HANDSHAKE_TYPE.SERVER_HELLO:
986 buf.writeUint16(this.selectedVersion);
989 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
995 class extensions_PskKeyExchangeModesExtension extends extensions_Extension {
1002 return EXTENSION_TYPE.PSK_KEY_EXCHANGE_MODES;
1005 static _read(messageType, buf) {
1007 switch (messageType) {
1008 case HANDSHAKE_TYPE.CLIENT_HELLO:
1009 buf.readVector8(buf => {
1010 modes.push(buf.readUint8());
1014 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1016 return new this(modes);
1019 _write(messageType, buf) {
1020 switch (messageType) {
1021 case HANDSHAKE_TYPE.CLIENT_HELLO:
1022 buf.writeVector8(buf => {
1023 this.modes.forEach(mode => {
1024 buf.writeUint8(mode);
1029 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
1034 // CONCATENATED MODULE: ./src/constants.js
1035 /* This Source Code Form is subject to the terms of the Mozilla Public
1036 * License, v. 2.0. If a copy of the MPL was not distributed with this
1037 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
1039 const VERSION_TLS_1_0 = 0x0301;
1040 const VERSION_TLS_1_2 = 0x0303;
1041 const VERSION_TLS_1_3 = 0x0304;
1042 const TLS_AES_128_GCM_SHA256 = 0x1301;
1043 const PSK_MODE_KE = 0;
1045 // CONCATENATED MODULE: ./src/messages.js
1046 /* This Source Code Form is subject to the terms of the Mozilla Public
1047 * License, v. 2.0. If a copy of the MPL was not distributed with this
1048 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
1053 // Herein we have code for reading and writing the various Handshake
1054 // messages involved in the TLS protocol.
1063 /* eslint-disable sorting/sort-object-props */
1064 const HANDSHAKE_TYPE = {
1067 NEW_SESSION_TICKET: 4,
1068 ENCRYPTED_EXTENSIONS: 8,
1071 /* eslint-enable sorting/sort-object-props */
1073 // Base class for generic reading/writing of handshake messages,
1074 // which are all uniformly formatted as:
1077 // HandshakeType msg_type; /* handshake type */
1078 // uint24 length; /* bytes in message */
1079 // select(Handshake.msg_type) {
1080 // ... type specific cases here ...
1084 class messages_HandshakeMessage {
1087 throw new Error('not implemented');
1090 static fromBytes(bytes) {
1091 // Each handshake message has a type and length prefix, per
1092 // https://tools.ietf.org/html/rfc8446#appendix-B.3
1093 const buf = new utils_BufferReader(bytes);
1094 const msg = this.read(buf);
1095 if (buf.hasMoreBytes()) {
1096 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
1102 const buf = new utils_BufferWriter();
1108 const type = buf.readUint8();
1110 buf.readVector24(buf => {
1112 case HANDSHAKE_TYPE.CLIENT_HELLO:
1113 msg = messages_ClientHello._read(buf);
1115 case HANDSHAKE_TYPE.SERVER_HELLO:
1116 msg = messages_ServerHello._read(buf);
1118 case HANDSHAKE_TYPE.NEW_SESSION_TICKET:
1119 msg = messages_NewSessionTicket._read(buf);
1121 case HANDSHAKE_TYPE.ENCRYPTED_EXTENSIONS:
1122 msg = EncryptedExtensions._read(buf);
1124 case HANDSHAKE_TYPE.FINISHED:
1125 msg = messages_Finished._read(buf);
1128 if (buf.hasMoreBytes()) {
1129 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
1133 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1139 buf.writeUint8(this.TYPE_TAG);
1140 buf.writeVector24(buf => {
1146 throw new Error('not implemented');
1150 throw new Error('not implemented');
1153 // Some little helpers for reading a list of extensions,
1154 // which is uniformly represented as:
1156 // Extension extensions<8..2^16-1>;
1158 // Recognized extensions are returned as a Map from extension type
1159 // to extension data object, with a special `lastSeenExtension`
1160 // property to make it easy to check which one came last.
1162 static _readExtensions(messageType, buf) {
1163 const extensions = new Map();
1164 buf.readVector16(buf => {
1165 const ext = extensions_Extension.read(messageType, buf);
1166 if (extensions.has(ext.TYPE_TAG)) {
1167 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
1169 extensions.set(ext.TYPE_TAG, ext);
1170 extensions.lastSeenExtension = ext.TYPE_TAG;
1175 _writeExtensions(buf, extensions) {
1176 buf.writeVector16(buf => {
1177 extensions.forEach(ext => {
1178 ext.write(this.TYPE_TAG, buf);
1185 // The ClientHello message:
1188 // ProtocolVersion legacy_version = 0x0303;
1190 // opaque legacy_session_id<0..32>;
1191 // CipherSuite cipher_suites<2..2^16-2>;
1192 // opaque legacy_compression_methods<1..2^8-1>;
1193 // Extension extensions<8..2^16-1>;
1196 class messages_ClientHello extends messages_HandshakeMessage {
1198 constructor(random, sessionId, extensions) {
1200 this.random = random;
1201 this.sessionId = sessionId;
1202 this.extensions = extensions;
1206 return HANDSHAKE_TYPE.CLIENT_HELLO;
1210 // The legacy_version field may indicate an earlier version of TLS
1211 // for backwards compatibility, but must not predate TLS 1.0!
1212 if (buf.readUint16() < VERSION_TLS_1_0) {
1213 throw new TLSError(ALERT_DESCRIPTION.PROTOCOL_VERSION);
1215 // The random bytes provided by the peer.
1216 const random = buf.readBytes(32);
1217 // Read legacy_session_id, so the server can echo it.
1218 const sessionId = buf.readVectorBytes8();
1219 // We only support a single ciphersuite, but the peer may offer several.
1220 // Scan the list to confirm that the one we want is present.
1222 buf.readVector16(buf => {
1223 const cipherSuite = buf.readUint16();
1224 if (cipherSuite === TLS_AES_128_GCM_SHA256) {
1229 throw new TLSError(ALERT_DESCRIPTION.HANDSHAKE_FAILURE);
1231 // legacy_compression_methods must be a single zero byte for TLS1.3 ClientHellos.
1232 // It can be non-zero in previous versions of TLS, but we're not going to
1233 // make a successful handshake with such versions, so better to just bail out now.
1234 const legacyCompressionMethods = buf.readVectorBytes8();
1235 if (legacyCompressionMethods.byteLength !== 1) {
1236 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1238 if (legacyCompressionMethods[0] !== 0x00) {
1239 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1241 // Read and check the extensions.
1242 const extensions = this._readExtensions(HANDSHAKE_TYPE.CLIENT_HELLO, buf);
1243 if (! extensions.has(EXTENSION_TYPE.SUPPORTED_VERSIONS)) {
1244 throw new TLSError(ALERT_DESCRIPTION.MISSING_EXTENSION);
1246 if (extensions.get(EXTENSION_TYPE.SUPPORTED_VERSIONS).versions.indexOf(VERSION_TLS_1_3) === -1) {
1247 throw new TLSError(ALERT_DESCRIPTION.PROTOCOL_VERSION);
1249 // Was the PreSharedKey extension the last one?
1250 if (extensions.has(EXTENSION_TYPE.PRE_SHARED_KEY)) {
1251 if (extensions.lastSeenExtension !== EXTENSION_TYPE.PRE_SHARED_KEY) {
1252 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1255 return new this(random, sessionId, extensions);
1259 buf.writeUint16(VERSION_TLS_1_2);
1260 buf.writeBytes(this.random);
1261 buf.writeVectorBytes8(this.sessionId);
1262 // Our single supported ciphersuite
1263 buf.writeVector16(buf => {
1264 buf.writeUint16(TLS_AES_128_GCM_SHA256);
1266 // A single zero byte for legacy_compression_methods
1267 buf.writeVectorBytes8(new Uint8Array(1));
1268 this._writeExtensions(buf, this.extensions);
1273 // The ServerHello message:
1276 // ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */
1278 // opaque legacy_session_id_echo<0..32>;
1279 // CipherSuite cipher_suite;
1280 // uint8 legacy_compression_method = 0;
1281 // Extension extensions < 6..2 ^ 16 - 1 >;
1284 class messages_ServerHello extends messages_HandshakeMessage {
1286 constructor(random, sessionId, extensions) {
1288 this.random = random;
1289 this.sessionId = sessionId;
1290 this.extensions = extensions;
1294 return HANDSHAKE_TYPE.SERVER_HELLO;
1298 // Fixed value for legacy_version.
1299 if (buf.readUint16() !== VERSION_TLS_1_2) {
1300 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1302 // Random bytes from the server.
1303 const random = buf.readBytes(32);
1304 // It should have echoed our vector for legacy_session_id.
1305 const sessionId = buf.readVectorBytes8();
1306 // It should have selected our single offered ciphersuite.
1307 if (buf.readUint16() !== TLS_AES_128_GCM_SHA256) {
1308 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1310 // legacy_compression_method must be zero.
1311 if (buf.readUint8() !== 0) {
1312 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1314 const extensions = this._readExtensions(HANDSHAKE_TYPE.SERVER_HELLO, buf);
1315 if (! extensions.has(EXTENSION_TYPE.SUPPORTED_VERSIONS)) {
1316 throw new TLSError(ALERT_DESCRIPTION.MISSING_EXTENSION);
1318 if (extensions.get(EXTENSION_TYPE.SUPPORTED_VERSIONS).selectedVersion !== VERSION_TLS_1_3) {
1319 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1321 return new this(random, sessionId, extensions);
1325 buf.writeUint16(VERSION_TLS_1_2);
1326 buf.writeBytes(this.random);
1327 buf.writeVectorBytes8(this.sessionId);
1328 // Our single supported ciphersuite
1329 buf.writeUint16(TLS_AES_128_GCM_SHA256);
1330 // A single zero byte for legacy_compression_method
1332 this._writeExtensions(buf, this.extensions);
1337 // The EncryptedExtensions message:
1340 // Extension extensions < 0..2 ^ 16 - 1 >;
1341 // } EncryptedExtensions;
1343 // We don't actually send any EncryptedExtensions,
1344 // but still have to send an empty message.
1346 class EncryptedExtensions extends messages_HandshakeMessage {
1347 constructor(extensions) {
1349 this.extensions = extensions;
1353 return HANDSHAKE_TYPE.ENCRYPTED_EXTENSIONS;
1357 const extensions = this._readExtensions(HANDSHAKE_TYPE.ENCRYPTED_EXTENSIONS, buf);
1358 return new this(extensions);
1362 this._writeExtensions(buf, this.extensions);
1367 // The Finished message:
1370 // opaque verify_data[Hash.length];
1373 class messages_Finished extends messages_HandshakeMessage {
1375 constructor(verifyData) {
1377 this.verifyData = verifyData;
1381 return HANDSHAKE_TYPE.FINISHED;
1385 const verifyData = buf.readBytes(HASH_LENGTH);
1386 return new this(verifyData);
1390 buf.writeBytes(this.verifyData);
1395 // The NewSessionTicket message:
1398 // uint32 ticket_lifetime;
1399 // uint32 ticket_age_add;
1400 // opaque ticket_nonce < 0..255 >;
1401 // opaque ticket < 1..2 ^ 16 - 1 >;
1402 // Extension extensions < 0..2 ^ 16 - 2 >;
1403 // } NewSessionTicket;
1405 // We don't actually make use of these, but we need to be able
1406 // to accept them and do basic validation.
1408 class messages_NewSessionTicket extends messages_HandshakeMessage {
1409 constructor(ticketLifetime, ticketAgeAdd, ticketNonce, ticket, extensions) {
1411 this.ticketLifetime = ticketLifetime;
1412 this.ticketAgeAdd = ticketAgeAdd;
1413 this.ticketNonce = ticketNonce;
1414 this.ticket = ticket;
1415 this.extensions = extensions;
1419 return HANDSHAKE_TYPE.NEW_SESSION_TICKET;
1423 const ticketLifetime = buf.readUint32();
1424 const ticketAgeAdd = buf.readUint32();
1425 const ticketNonce = buf.readVectorBytes8();
1426 const ticket = buf.readVectorBytes16();
1427 if (ticket.byteLength < 1) {
1428 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
1430 const extensions = this._readExtensions(HANDSHAKE_TYPE.NEW_SESSION_TICKET, buf);
1431 return new this(ticketLifetime, ticketAgeAdd, ticketNonce, ticket, extensions);
1435 buf.writeUint32(this.ticketLifetime);
1436 buf.writeUint32(this.ticketAgeAdd);
1437 buf.writeVectorBytes8(this.ticketNonce);
1438 buf.writeVectorBytes16(this.ticket);
1439 this._writeExtensions(buf, this.extensions);
1443 // CONCATENATED MODULE: ./src/states.js
1444 /* This Source Code Form is subject to the terms of the Mozilla Public
1445 * License, v. 2.0. If a copy of the MPL was not distributed with this
1446 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
1456 // State-machine for TLS Handshake Management.
1458 // Internally, we manage the TLS connection by explicitly modelling the
1459 // client and server state-machines from RFC8446. You can think of
1460 // these `State` objects as little plugins for the `Connection` class
1461 // that provide different behaviours of `send` and `receive` depending
1462 // on the state of the connection.
1465 class states_State {
1471 async initialize() {
1472 // By default, nothing to do when entering the state.
1475 async sendApplicationData(bytes) {
1476 // By default, assume we're not ready to send yet and the caller
1477 // should be blocking on the connection promise before reaching here.
1478 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
1481 async recvApplicationData(bytes) {
1482 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1485 async recvHandshakeMessage(msg) {
1486 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1489 async recvAlertMessage(alert) {
1490 switch (alert.description) {
1491 case ALERT_DESCRIPTION.CLOSE_NOTIFY:
1492 this.conn._closeForRecv(alert);
1495 return await this.handleErrorAndRethrow(alert);
1499 async recvChangeCipherSpec(bytes) {
1500 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1503 async handleErrorAndRethrow(err) {
1505 if (! (alert instanceof TLSAlert)) {
1506 alert = new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
1508 // Try to send error alert to the peer, but we may not
1509 // be able to if the outgoing connection was already closed.
1511 await this.conn._sendAlertMessage(alert);
1513 await this.conn._transition(ERROR, err);
1518 const alert = new TLSCloseNotify();
1519 await this.conn._sendAlertMessage(alert);
1520 this.conn._closeForSend(alert);
1525 // A special "guard" state to prevent us from using
1526 // an improperly-initialized Connection.
1528 class UNINITIALIZED extends states_State {
1529 async initialize() {
1530 throw new Error('uninitialized state');
1532 async sendApplicationData(bytes) {
1533 throw new Error('uninitialized state');
1535 async recvApplicationData(bytes) {
1536 throw new Error('uninitialized state');
1538 async recvHandshakeMessage(msg) {
1539 throw new Error('uninitialized state');
1541 async recvChangeCipherSpec(bytes) {
1542 throw new Error('uninitialized state');
1544 async handleErrorAndRethrow(err) {
1548 throw new Error('uninitialized state');
1552 // A special "error" state for when something goes wrong.
1553 // This state never transitions to another state, effectively
1554 // terminating the connection.
1556 class ERROR extends states_State {
1557 async initialize(err) {
1559 this.conn._setConnectionFailure(err);
1560 // Unceremoniously shut down the record layer on error.
1561 this.conn._recordlayer.setSendError(err);
1562 this.conn._recordlayer.setRecvError(err);
1564 async sendApplicationData(bytes) {
1567 async recvApplicationData(bytes) {
1570 async recvHandshakeMessage(msg) {
1573 async recvAlertMessage(err) {
1576 async recvChangeCipherSpec(bytes) {
1579 async handleErrorAndRethrow(err) {
1587 // The "connected" state, for when the handshake is complete
1588 // and we're ready to send application-level data.
1589 // The logic for this is largely symmetric between client and server.
1591 class states_CONNECTED extends states_State {
1592 async initialize() {
1593 this.conn._setConnectionSuccess();
1595 async sendApplicationData(bytes) {
1596 await this.conn._sendApplicationData(bytes);
1598 async recvApplicationData(bytes) {
1601 async recvChangeCipherSpec(bytes) {
1602 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1606 // A base class for states that occur in the middle of the handshake
1607 // (that is, between ClientHello and Finished). These states may receive
1608 // CHANGE_CIPHER_SPEC records for b/w compat reasons, which must contain
1609 // exactly a single 0x01 byte and must otherwise be ignored.
1611 class states_MidHandshakeState extends states_State {
1612 async recvChangeCipherSpec(bytes) {
1613 if (this.conn._hasSeenChangeCipherSpec) {
1614 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1616 if (bytes.byteLength !== 1 || bytes[0] !== 1) {
1617 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1619 this.conn._hasSeenChangeCipherSpec = true;
1623 // These states implement (part of) the client state-machine from
1624 // https://tools.ietf.org/html/rfc8446#appendix-A.1
1626 // Since we're only implementing a small subset of TLS1.3,
1627 // we only need a small subset of the handshake. It basically goes:
1629 // * send ClientHello
1630 // * receive ServerHello
1631 // * receive EncryptedExtensions
1632 // * receive server Finished
1633 // * send client Finished
1635 // We include some unused states for completeness, so that it's easier
1636 // to check the implementation against the diagrams in the RFC.
1638 class states_CLIENT_START extends states_State {
1639 async initialize() {
1640 const keyschedule = this.conn._keyschedule;
1641 await keyschedule.addPSK(this.conn.psk);
1642 // Construct a ClientHello message with our single PSK.
1643 // We can't know the PSK binder value yet, so we initially write zeros.
1644 const clientHello = new messages_ClientHello(
1645 // Client random salt.
1646 await getRandomBytes(32),
1647 // Random legacy_session_id; we *could* send an empty string here,
1648 // but sending a random one makes it easier to be compatible with
1649 // the data emitted by tlslite-ng for test-case generation.
1650 await getRandomBytes(32),
1652 new extensions_SupportedVersionsExtension([VERSION_TLS_1_3]),
1653 new extensions_PskKeyExchangeModesExtension([PSK_MODE_KE]),
1654 new extensions_PreSharedKeyExtension([this.conn.pskId], [zeros(HASH_LENGTH)]),
1657 const buf = new utils_BufferWriter();
1658 clientHello.write(buf);
1659 // Now that we know what the ClientHello looks like,
1660 // go back and calculate the appropriate PSK binder value.
1661 // We only support a single PSK, so the length of the binders field is the
1662 // length of the hash plus one for rendering it as a variable-length byte array,
1663 // plus two for rendering the variable-length list of PSK binders.
1664 const PSK_BINDERS_SIZE = HASH_LENGTH + 1 + 2;
1665 const truncatedTranscript = buf.slice(0, buf.tell() - PSK_BINDERS_SIZE);
1666 const pskBinder = await keyschedule.calculateFinishedMAC(keyschedule.extBinderKey, truncatedTranscript);
1667 buf.incr(-HASH_LENGTH);
1668 buf.writeBytes(pskBinder);
1669 await this.conn._sendHandshakeMessageBytes(buf.flush());
1670 await this.conn._transition(states_CLIENT_WAIT_SH, clientHello.sessionId);
1674 class states_CLIENT_WAIT_SH extends states_State {
1675 async initialize(sessionId) {
1676 this._sessionId = sessionId;
1678 async recvHandshakeMessage(msg) {
1679 if (! (msg instanceof messages_ServerHello)) {
1680 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1682 if (! bytesAreEqual(msg.sessionId, this._sessionId)) {
1683 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1685 const pskExt = msg.extensions.get(EXTENSION_TYPE.PRE_SHARED_KEY);
1687 throw new TLSError(ALERT_DESCRIPTION.MISSING_EXTENSION);
1689 // We expect only the SUPPORTED_VERSIONS and PRE_SHARED_KEY extensions.
1690 if (msg.extensions.size !== 2) {
1691 throw new TLSError(ALERT_DESCRIPTION.UNSUPPORTED_EXTENSION);
1693 if (pskExt.selectedIdentity !== 0) {
1694 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1696 await this.conn._keyschedule.addECDHE(null);
1697 await this.conn._setSendKey(this.conn._keyschedule.clientHandshakeTrafficSecret);
1698 await this.conn._setRecvKey(this.conn._keyschedule.serverHandshakeTrafficSecret);
1699 await this.conn._transition(states_CLIENT_WAIT_EE);
1703 class states_CLIENT_WAIT_EE extends states_MidHandshakeState {
1704 async recvHandshakeMessage(msg) {
1705 // We don't make use of any encrypted extensions, but we still
1706 // have to wait for the server to send the (empty) list of them.
1707 if (! (msg instanceof EncryptedExtensions)) {
1708 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1710 // We do not support any EncryptedExtensions.
1711 if (msg.extensions.size !== 0) {
1712 throw new TLSError(ALERT_DESCRIPTION.UNSUPPORTED_EXTENSION);
1714 const keyschedule = this.conn._keyschedule;
1715 const serverFinishedTranscript = keyschedule.getTranscript();
1716 await this.conn._transition(states_CLIENT_WAIT_FINISHED, serverFinishedTranscript);
1720 class states_CLIENT_WAIT_FINISHED extends states_State {
1721 async initialize(serverFinishedTranscript) {
1722 this._serverFinishedTranscript = serverFinishedTranscript;
1724 async recvHandshakeMessage(msg) {
1725 if (! (msg instanceof messages_Finished)) {
1726 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1728 // Verify server Finished MAC.
1729 const keyschedule = this.conn._keyschedule;
1730 await keyschedule.verifyFinishedMAC(keyschedule.serverHandshakeTrafficSecret, msg.verifyData, this._serverFinishedTranscript);
1731 // Send our own Finished message in return.
1732 // This must be encrypted with the handshake traffic key,
1733 // but must not appear in the transcript used to calculate the application keys.
1734 const clientFinishedMAC = await keyschedule.calculateFinishedMAC(keyschedule.clientHandshakeTrafficSecret);
1735 await keyschedule.finalize();
1736 await this.conn._sendHandshakeMessage(new messages_Finished(clientFinishedMAC));
1737 await this.conn._setSendKey(keyschedule.clientApplicationTrafficSecret);
1738 await this.conn._setRecvKey(keyschedule.serverApplicationTrafficSecret);
1739 await this.conn._transition(states_CLIENT_CONNECTED);
1743 class states_CLIENT_CONNECTED extends states_CONNECTED {
1744 async recvHandshakeMessage(msg) {
1745 // A connected client must be prepared to accept NewSessionTicket
1746 // messages. We never use them, but other server implementations
1748 if (! (msg instanceof messages_NewSessionTicket)) {
1749 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1754 // These states implement (part of) the server state-machine from
1755 // https://tools.ietf.org/html/rfc8446#appendix-A.2
1757 // Since we're only implementing a small subset of TLS1.3,
1758 // we only need a small subset of the handshake. It basically goes:
1760 // * receive ClientHello
1761 // * send ServerHello
1762 // * send empty EncryptedExtensions
1763 // * send server Finished
1764 // * receive client Finished
1766 // We include some unused states for completeness, so that it's easier
1767 // to check the implementation against the diagrams in the RFC.
1769 class states_SERVER_START extends states_State {
1770 async recvHandshakeMessage(msg) {
1771 if (! (msg instanceof messages_ClientHello)) {
1772 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1774 // In the spec, this is where we select connection parameters, and maybe
1775 // tell the client to try again if we can't find a compatible set.
1776 // Since we only support a fixed cipherset, the only thing to "negotiate"
1777 // is whether they provided an acceptable PSK.
1778 const pskExt = msg.extensions.get(EXTENSION_TYPE.PRE_SHARED_KEY);
1779 const pskModesExt = msg.extensions.get(EXTENSION_TYPE.PSK_KEY_EXCHANGE_MODES);
1780 if (! pskExt || ! pskModesExt) {
1781 throw new TLSError(ALERT_DESCRIPTION.MISSING_EXTENSION);
1783 if (pskModesExt.modes.indexOf(PSK_MODE_KE) === -1) {
1784 throw new TLSError(ALERT_DESCRIPTION.HANDSHAKE_FAILURE);
1786 const pskIndex = pskExt.identities.findIndex(pskId => bytesAreEqual(pskId, this.conn.pskId));
1787 if (pskIndex === -1) {
1788 throw new TLSError(ALERT_DESCRIPTION.UNKNOWN_PSK_IDENTITY);
1790 await this.conn._keyschedule.addPSK(this.conn.psk);
1791 // Validate the PSK binder.
1792 const keyschedule = this.conn._keyschedule;
1793 const transcript = keyschedule.getTranscript();
1794 // Calculate size occupied by the PSK binders.
1795 let pskBindersSize = 2; // Vector16 representation overhead.
1796 for (const binder of pskExt.binders) {
1797 pskBindersSize += binder.byteLength + 1; // Vector8 representation overhead.
1799 await keyschedule.verifyFinishedMAC(keyschedule.extBinderKey, pskExt.binders[pskIndex], transcript.slice(0, -pskBindersSize));
1800 await this.conn._transition(states_SERVER_NEGOTIATED, msg.sessionId, pskIndex);
1804 class states_SERVER_NEGOTIATED extends states_MidHandshakeState {
1805 async initialize(sessionId, pskIndex) {
1806 await this.conn._sendHandshakeMessage(new messages_ServerHello(
1808 await getRandomBytes(32),
1811 new extensions_SupportedVersionsExtension(null, VERSION_TLS_1_3),
1812 new extensions_PreSharedKeyExtension(null, null, pskIndex),
1815 // If the client sent a non-empty sessionId, the server *must* send a change-cipher-spec for b/w compat.
1816 if (sessionId.byteLength > 0) {
1817 await this.conn._sendChangeCipherSpec();
1819 // We can now transition to the encrypted part of the handshake.
1820 const keyschedule = this.conn._keyschedule;
1821 await keyschedule.addECDHE(null);
1822 await this.conn._setSendKey(keyschedule.serverHandshakeTrafficSecret);
1823 await this.conn._setRecvKey(keyschedule.clientHandshakeTrafficSecret);
1824 // Send an empty EncryptedExtensions message.
1825 await this.conn._sendHandshakeMessage(new EncryptedExtensions([]));
1826 // Send the Finished message.
1827 const serverFinishedMAC = await keyschedule.calculateFinishedMAC(keyschedule.serverHandshakeTrafficSecret);
1828 await this.conn._sendHandshakeMessage(new messages_Finished(serverFinishedMAC));
1829 // We can now *send* using the application traffic key,
1830 // but have to wait to receive the client Finished before receiving under that key.
1831 // We need to remember the handshake state from before the client Finished
1832 // in order to successfully verify the client Finished.
1833 const clientFinishedTranscript = await keyschedule.getTranscript();
1834 const clientHandshakeTrafficSecret = keyschedule.clientHandshakeTrafficSecret;
1835 await keyschedule.finalize();
1836 await this.conn._setSendKey(keyschedule.serverApplicationTrafficSecret);
1837 await this.conn._transition(states_SERVER_WAIT_FINISHED, clientHandshakeTrafficSecret, clientFinishedTranscript);
1841 class states_SERVER_WAIT_FINISHED extends states_MidHandshakeState {
1842 async initialize(clientHandshakeTrafficSecret, clientFinishedTranscript) {
1843 this._clientHandshakeTrafficSecret = clientHandshakeTrafficSecret;
1844 this._clientFinishedTranscript = clientFinishedTranscript;
1846 async recvHandshakeMessage(msg) {
1847 if (! (msg instanceof messages_Finished)) {
1848 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1850 const keyschedule = this.conn._keyschedule;
1851 await keyschedule.verifyFinishedMAC(this._clientHandshakeTrafficSecret, msg.verifyData, this._clientFinishedTranscript);
1852 this._clientHandshakeTrafficSecret = this._clientFinishedTranscript = null;
1853 await this.conn._setRecvKey(keyschedule.clientApplicationTrafficSecret);
1854 await this.conn._transition(states_CONNECTED);
1858 // CONCATENATED MODULE: ./src/keyschedule.js
1859 /* This Source Code Form is subject to the terms of the Mozilla Public
1860 * License, v. 2.0. If a copy of the MPL was not distributed with this
1861 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
1863 // TLS1.3 Key Schedule.
1865 // In this file we implement the "key schedule" from
1866 // https://tools.ietf.org/html/rfc8446#section-7.1, which
1867 // defines how to calculate various keys as the handshake
1868 // state progresses.
1876 // The `KeySchedule` class progresses through three stages corresponding
1877 // to the three phases of the TLS1.3 key schedule:
1893 // It will error out if the calling code attempts to add key material
1894 // in the wrong order.
1896 const STAGE_UNINITIALIZED = 0;
1897 const STAGE_EARLY_SECRET = 1;
1898 const STAGE_HANDSHAKE_SECRET = 2;
1899 const STAGE_MASTER_SECRET = 3;
1901 class keyschedule_KeySchedule {
1903 this.stage = STAGE_UNINITIALIZED;
1904 // WebCrypto doesn't support a rolling hash construct, so we have to
1905 // keep the entire message transcript in memory.
1906 this.transcript = new utils_BufferWriter();
1907 // This tracks the main secret from with other keys are derived at each stage.
1909 // And these are all the various keys we'll derive as the handshake progresses.
1910 this.extBinderKey = null;
1911 this.clientHandshakeTrafficSecret = null;
1912 this.serverHandshakeTrafficSecret = null;
1913 this.clientApplicationTrafficSecret = null;
1914 this.serverApplicationTrafficSecret = null;
1918 // Use the selected PSK (if any) to calculate the "early secret".
1920 psk = zeros(HASH_LENGTH);
1922 if (this.stage !== STAGE_UNINITIALIZED) {
1923 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
1925 this.stage = STAGE_EARLY_SECRET;
1926 this.secret = await hkdfExtract(zeros(HASH_LENGTH), psk);
1927 this.extBinderKey = await this.deriveSecret('ext binder', EMPTY);
1928 this.secret = await this.deriveSecret('derived', EMPTY);
1931 async addECDHE(ecdhe) {
1932 // Mix in the ECDHE output (if any) to calculate the "handshake secret".
1933 if (ecdhe === null) {
1934 ecdhe = zeros(HASH_LENGTH);
1936 if (this.stage !== STAGE_EARLY_SECRET) {
1937 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
1939 this.stage = STAGE_HANDSHAKE_SECRET;
1940 this.extBinderKey = null;
1941 this.secret = await hkdfExtract(this.secret, ecdhe);
1942 this.clientHandshakeTrafficSecret = await this.deriveSecret('c hs traffic');
1943 this.serverHandshakeTrafficSecret = await this.deriveSecret('s hs traffic');
1944 this.secret = await this.deriveSecret('derived', EMPTY);
1948 if (this.stage !== STAGE_HANDSHAKE_SECRET) {
1949 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
1951 this.stage = STAGE_MASTER_SECRET;
1952 this.clientHandshakeTrafficSecret = null;
1953 this.serverHandshakeTrafficSecret = null;
1954 this.secret = await hkdfExtract(this.secret, zeros(HASH_LENGTH));
1955 this.clientApplicationTrafficSecret = await this.deriveSecret('c ap traffic');
1956 this.serverApplicationTrafficSecret = await this.deriveSecret('s ap traffic');
1960 addToTranscript(bytes) {
1961 this.transcript.writeBytes(bytes);
1965 return this.transcript.slice();
1968 async deriveSecret(label, transcript = undefined) {
1969 transcript = transcript || this.getTranscript();
1970 return await hkdfExpandLabel(this.secret, label, await hash(transcript), HASH_LENGTH);
1973 async calculateFinishedMAC(baseKey, transcript = undefined) {
1974 transcript = transcript || this.getTranscript();
1975 const finishedKey = await hkdfExpandLabel(baseKey, 'finished', EMPTY, HASH_LENGTH);
1976 return await hmac(finishedKey, await hash(transcript));
1979 async verifyFinishedMAC(baseKey, mac, transcript = undefined) {
1980 transcript = transcript || this.getTranscript();
1981 const finishedKey = await hkdfExpandLabel(baseKey, 'finished', EMPTY, HASH_LENGTH);
1982 await verifyHmac(finishedKey, mac, await hash(transcript));
1986 // CONCATENATED MODULE: ./src/recordlayer.js
1987 /* This Source Code Form is subject to the terms of the Mozilla Public
1988 * License, v. 2.0. If a copy of the MPL was not distributed with this
1989 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
1992 // This file implements the "record layer" for TLS1.3, as defined in
1993 // https://tools.ietf.org/html/rfc8446#section-5.
1995 // The record layer is responsible for encrypting/decrypting bytes to be
1996 // sent over the wire, including stateful management of sequence numbers
1997 // for the incoming and outgoing stream.
1999 // The main interface is the RecordLayer class, which takes a callback function
2000 // sending data and can be used like so:
2002 // rl = new RecordLayer(async function send_encrypted_data(data) {
2003 // // application-specific sending logic here.
2006 // // Records are sent and received in plaintext by default,
2007 // // until you specify the key to use.
2008 // await rl.setSendKey(key)
2010 // // Send some data by specifying the record type and the bytes.
2011 // // Where allowed by the record type, it will be buffered until
2012 // // explicitly flushed, and then sent by calling the callback.
2013 // await rl.send(RECORD_TYPE.HANDSHAKE, <bytes for a handshake message>)
2014 // await rl.send(RECORD_TYPE.HANDSHAKE, <bytes for another handshake message>)
2017 // // Separate keys are used for sending and receiving.
2018 // rl.setRecvKey(key);
2020 // // When data is received, push it into the RecordLayer
2021 // // and pass a callback that will be called with a [type, bytes]
2022 // // pair for each message parsed from the data.
2023 // rl.recv(dataReceivedFromPeer, async (type, bytes) => {
2025 // case RECORD_TYPE.APPLICATION_DATA:
2026 // // do something with application data
2027 // case RECORD_TYPE.HANDSHAKE:
2028 // // do something with a handshake message
2041 /* eslint-disable sorting/sort-object-props */
2042 const RECORD_TYPE = {
2043 CHANGE_CIPHER_SPEC: 20,
2046 APPLICATION_DATA: 23,
2048 /* eslint-enable sorting/sort-object-props */
2050 // Encrypting at most 2^24 records will force us to stay
2051 // below data limits on AES-GCM encryption key use, and also
2052 // means we can accurately represent the sequence number as
2053 // a javascript double.
2054 const MAX_SEQUENCE_NUMBER = Math.pow(2, 24);
2055 const MAX_RECORD_SIZE = Math.pow(2, 14);
2056 const MAX_ENCRYPTED_RECORD_SIZE = MAX_RECORD_SIZE + 256;
2057 const RECORD_HEADER_SIZE = 5;
2059 // These are some helper classes to manage the encryption/decryption state
2060 // for a particular key.
2062 class recordlayer_CipherState {
2063 constructor(key, iv) {
2069 static async create(baseKey, mode) {
2070 // Derive key and iv per https://tools.ietf.org/html/rfc8446#section-7.3
2071 const key = await prepareKey(await hkdfExpandLabel(baseKey, 'key', EMPTY, KEY_LENGTH), mode);
2072 const iv = await hkdfExpandLabel(baseKey, 'iv', EMPTY, IV_LENGTH);
2073 return new this(key, iv);
2077 // Ref https://tools.ietf.org/html/rfc8446#section-5.3:
2078 // * left-pad the sequence number with zeros to IV_LENGTH
2079 // * xor with the provided iv
2080 // Our sequence numbers are always less than 2^24, so fit in a Uint32
2081 // in the last 4 bytes of the nonce.
2082 const nonce = this.iv.slice();
2083 const dv = new DataView(nonce.buffer, nonce.byteLength - 4, 4);
2084 dv.setUint32(0, dv.getUint32(0) ^ this.seqnum);
2086 if (this.seqnum > MAX_SEQUENCE_NUMBER) {
2087 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
2093 class recordlayer_EncryptionState extends recordlayer_CipherState {
2094 static async create(key) {
2095 return super.create(key, 'encrypt');
2098 async encrypt(plaintext, additionalData) {
2099 return await encrypt(this.key, this.nonce(), plaintext, additionalData);
2103 class recordlayer_DecryptionState extends recordlayer_CipherState {
2104 static async create(key) {
2105 return super.create(key, 'decrypt');
2108 async decrypt(ciphertext, additionalData) {
2109 return await decrypt(this.key, this.nonce(), ciphertext, additionalData);
2113 // The main RecordLayer class.
2115 class recordlayer_RecordLayer {
2116 constructor(sendCallback) {
2117 this.sendCallback = sendCallback;
2118 this._sendEncryptState = null;
2119 this._sendError = null;
2120 this._recvDecryptState = null;
2121 this._recvError = null;
2122 this._pendingRecordType = 0;
2123 this._pendingRecordBuf = null;
2126 async setSendKey(key) {
2128 this._sendEncryptState = await recordlayer_EncryptionState.create(key);
2131 async setRecvKey(key) {
2132 this._recvDecryptState = await recordlayer_DecryptionState.create(key);
2135 async setSendError(err) {
2136 this._sendError = err;
2139 async setRecvError(err) {
2140 this._recvError = err;
2143 async send(type, data) {
2144 if (this._sendError !== null) {
2145 throw this._sendError;
2147 // Forbid sending data that doesn't fit into a single record.
2148 // We do not support fragmentation over multiple records.
2149 if (data.byteLength > MAX_RECORD_SIZE) {
2150 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
2152 // Flush if we're switching to a different record type.
2153 if (this._pendingRecordType && this._pendingRecordType !== type) {
2156 // Flush if we would overflow the max size of a record.
2157 if (this._pendingRecordBuf !== null) {
2158 if (this._pendingRecordBuf.tell() + data.byteLength > MAX_RECORD_SIZE) {
2162 // Start a new pending record if necessary.
2163 // We reserve space at the start of the buffer for the record header,
2164 // which is conveniently always a fixed size.
2165 if (this._pendingRecordBuf === null) {
2166 this._pendingRecordType = type;
2167 this._pendingRecordBuf = new utils_BufferWriter();
2168 this._pendingRecordBuf.incr(RECORD_HEADER_SIZE);
2170 this._pendingRecordBuf.writeBytes(data);
2174 // If there's nothing to flush, bail out early.
2175 // Don't throw `_sendError` if we're not sending anything, because `flush()`
2176 // can be called when we're trying to transition into an error state.
2177 const buf = this._pendingRecordBuf;
2178 let type = this._pendingRecordType;
2181 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
2185 if (this._sendError !== null) {
2186 throw this._sendError;
2188 // If we're encrypting, turn the existing buffer contents into a `TLSInnerPlaintext` by
2189 // appending the type. We don't do any zero-padding, although the spec allows it.
2190 let inflation = 0, innerPlaintext = null;
2191 if (this._sendEncryptState !== null) {
2192 buf.writeUint8(type);
2193 innerPlaintext = buf.slice(RECORD_HEADER_SIZE);
2194 inflation = AEAD_SIZE_INFLATION;
2195 type = RECORD_TYPE.APPLICATION_DATA;
2197 // Write the common header for either `TLSPlaintext` or `TLSCiphertext` record.
2198 const length = buf.tell() - RECORD_HEADER_SIZE + inflation;
2200 buf.writeUint8(type);
2201 buf.writeUint16(VERSION_TLS_1_2);
2202 buf.writeUint16(length);
2203 // Followed by different payload depending on encryption status.
2204 if (this._sendEncryptState !== null) {
2205 const additionalData = buf.slice(0, RECORD_HEADER_SIZE);
2206 const ciphertext = await this._sendEncryptState.encrypt(innerPlaintext, additionalData);
2207 buf.writeBytes(ciphertext);
2211 this._pendingRecordBuf = null;
2212 this._pendingRecordType = 0;
2213 await this.sendCallback(buf.flush());
2217 if (this._recvError !== null) {
2218 throw this._recvError;
2220 // For simplicity, we assume that the given data contains exactly one record.
2221 // Peers using this library will send one record at a time over the websocket
2222 // connection, and we can assume that the server-side websocket bridge will split
2223 // up any traffic into individual records if we ever start interoperating with
2224 // peers using a different TLS implementation.
2225 // Similarly, we assume that handshake messages will not be fragmented across
2226 // multiple records. This should be trivially true for the PSK-only mode used
2227 // by this library, but we may want to relax it in future for interoperability
2228 // with e.g. large ClientHello messages that contain lots of different options.
2229 const buf = new utils_BufferReader(data);
2230 // The data to read is either a TLSPlaintext or TLSCiphertext struct,
2231 // depending on whether record protection has been enabled yet:
2234 // ContentType type;
2235 // ProtocolVersion legacy_record_version;
2237 // opaque fragment[TLSPlaintext.length];
2241 // ContentType opaque_type = application_data; /* 23 */
2242 // ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */
2244 // opaque encrypted_record[TLSCiphertext.length];
2247 let type = buf.readUint8();
2248 // The spec says legacy_record_version "MUST be ignored for all purposes",
2249 // but we know TLS1.3 implementations will only ever emit two possible values,
2250 // so it seems useful to bail out early if we receive anything else.
2251 const version = buf.readUint16();
2252 if (version !== VERSION_TLS_1_2) {
2253 // TLS1.0 is only acceptable on initial plaintext records.
2254 if (this._recvDecryptState !== null || version !== VERSION_TLS_1_0) {
2255 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
2258 const length = buf.readUint16();
2260 if (this._recvDecryptState === null || type === RECORD_TYPE.CHANGE_CIPHER_SPEC) {
2261 [type, plaintext] = await this._readPlaintextRecord(type, length, buf);
2263 [type, plaintext] = await this._readEncryptedRecord(type, length, buf);
2265 // Sanity-check that we received exactly one record.
2266 if (buf.hasMoreBytes()) {
2267 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
2269 return [type, plaintext];
2272 // Helper to read an unencrypted `TLSPlaintext` struct
2274 async _readPlaintextRecord(type, length, buf) {
2275 if (length > MAX_RECORD_SIZE) {
2276 throw new TLSError(ALERT_DESCRIPTION.RECORD_OVERFLOW);
2278 return [type, buf.readBytes(length)];
2281 // Helper to read an encrypted `TLSCiphertext` struct,
2282 // decrypting it into plaintext.
2284 async _readEncryptedRecord(type, length, buf) {
2285 if (length > MAX_ENCRYPTED_RECORD_SIZE) {
2286 throw new TLSError(ALERT_DESCRIPTION.RECORD_OVERFLOW);
2288 // The outer type for encrypted records is always APPLICATION_DATA.
2289 if (type !== RECORD_TYPE.APPLICATION_DATA) {
2290 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
2292 // Decrypt and decode the contained `TLSInnerPlaintext` struct:
2295 // opaque content[TLSPlaintext.length];
2296 // ContentType type;
2297 // uint8 zeros[length_of_padding];
2298 // } TLSInnerPlaintext;
2300 // The additional data for the decryption is the `TLSCiphertext` record
2301 // header, which is a fixed size and immediately prior to current buffer position.
2302 buf.incr(-RECORD_HEADER_SIZE);
2303 const additionalData = buf.readBytes(RECORD_HEADER_SIZE);
2304 const ciphertext = buf.readBytes(length);
2305 const paddedPlaintext = await this._recvDecryptState.decrypt(ciphertext, additionalData);
2306 // We have to scan backwards over the zero padding at the end of the struct
2307 // in order to find the non-zero `type` byte.
2309 for (i = paddedPlaintext.byteLength - 1; i >= 0; i--) {
2310 if (paddedPlaintext[i] !== 0) {
2315 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
2317 type = paddedPlaintext[i];
2318 // `change_cipher_spec` records must always be plaintext.
2319 if (type === RECORD_TYPE.CHANGE_CIPHER_SPEC) {
2320 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
2322 return [type, paddedPlaintext.slice(0, i)];
2326 // CONCATENATED MODULE: ./src/tlsconnection.js
2327 /* This Source Code Form is subject to the terms of the Mozilla Public
2328 * License, v. 2.0. If a copy of the MPL was not distributed with this
2329 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
2331 // The top-level APIs offered by this module are `ClientConnection` and
2332 // `ServerConnection` classes, which provide authenticated and encrypted
2333 // communication via the "externally-provisioned PSK" mode of TLS1.3.
2334 // They each take a callback to be used for sending data to the remote peer,
2335 // and operate like this:
2337 // conn = await ClientConnection.create(psk, pskId, async function send_data_to_server(data) {
2338 // // application-specific sending logic here.
2341 // // Send data to the server by calling `send`,
2342 // // which will use the callback provided in the constructor.
2343 // // A single `send()` by the application may result in multiple
2344 // // invokations of the callback.
2346 // await conn.send('application-level data')
2348 // // When data is received from the server, push it into
2349 // // the connection and let it return any decrypted app-level data.
2350 // // There might not be any app-level data if it was a protocol control
2351 // // message, and the receipt of the data might trigger additional calls
2352 // // to the send callback for protocol control purposes.
2354 // serverSocket.on('data', async encrypted_data => {
2355 // const plaintext = await conn.recv(data)
2356 // if (plaintext !== null) {
2357 // do_something_with_app_level_data(plaintext)
2361 // // It's good practice to explicitly close the connection
2362 // // when finished. This will send a "closed" notification
2363 // // to the server.
2365 // await conn.close()
2367 // // When the peer sends a "closed" notification it will show up
2368 // // as a `TLSCloseNotify` exception from recv:
2371 // data = await conn.recv(data);
2373 // if (! (err instanceof TLSCloseNotify) { throw err }
2374 // do_something_to_cleanly_close_data_connection();
2377 // The `ServerConnection` API operates similarly; the distinction is mainly
2378 // in which side is expected to send vs receieve during the protocol handshake.
2389 class tlsconnection_Connection {
2390 constructor(psk, pskId, sendCallback) {
2391 this.psk = assertIsBytes(psk);
2392 this.pskId = assertIsBytes(pskId);
2393 this.connected = new Promise((resolve, reject) => {
2394 this._onConnectionSuccess = resolve;
2395 this._onConnectionFailure = reject;
2397 this._state = new UNINITIALIZED(this);
2398 this._handshakeRecvBuffer = null;
2399 this._hasSeenChangeCipherSpec = false;
2400 this._recordlayer = new recordlayer_RecordLayer(sendCallback);
2401 this._keyschedule = new keyschedule_KeySchedule();
2402 this._lastPromise = Promise.resolve();
2405 // Subclasses will override this with some async initialization logic.
2406 static async create(psk, pskId, sendCallback) {
2407 return new this(psk, pskId, sendCallback);
2410 // These are the three public API methods that consumers can use
2411 // to send and receive data encrypted with TLS1.3.
2414 assertIsBytes(data);
2415 await this.connected;
2416 await this._synchronized(async () => {
2417 await this._state.sendApplicationData(data);
2422 assertIsBytes(data);
2423 return await this._synchronized(async () => {
2424 // Decrypt the data using the record layer.
2425 // We expect to receive precisely one record at a time.
2426 const [type, bytes] = await this._recordlayer.recv(data);
2427 // Dispatch based on the type of the record.
2429 case RECORD_TYPE.CHANGE_CIPHER_SPEC:
2430 await this._state.recvChangeCipherSpec(bytes);
2432 case RECORD_TYPE.ALERT:
2433 await this._state.recvAlertMessage(TLSAlert.fromBytes(bytes));
2435 case RECORD_TYPE.APPLICATION_DATA:
2436 return await this._state.recvApplicationData(bytes);
2437 case RECORD_TYPE.HANDSHAKE:
2438 // Multiple handshake messages may be coalesced into a single record.
2439 // Store the in-progress record buffer on `this` so that we can guard
2440 // against handshake messages that span a change in keys.
2441 this._handshakeRecvBuffer = new utils_BufferReader(bytes);
2442 if (! this._handshakeRecvBuffer.hasMoreBytes()) {
2443 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
2446 // Each handshake messages has a type and length prefix, per
2447 // https://tools.ietf.org/html/rfc8446#appendix-B.3
2448 this._handshakeRecvBuffer.incr(1);
2449 const mlength = this._handshakeRecvBuffer.readUint24();
2450 this._handshakeRecvBuffer.incr(-4);
2451 const messageBytes = this._handshakeRecvBuffer.readBytes(mlength + 4);
2452 this._keyschedule.addToTranscript(messageBytes);
2453 await this._state.recvHandshakeMessage(messages_HandshakeMessage.fromBytes(messageBytes));
2454 } while (this._handshakeRecvBuffer.hasMoreBytes());
2455 this._handshakeRecvBuffer = null;
2458 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
2464 await this._synchronized(async () => {
2465 await this._state.close();
2469 // Ensure that async functions execute one at a time,
2470 // by waiting for the previous call to `_synchronized()` to complete
2471 // before starting a new one. This helps ensure that we complete
2472 // one state-machine transition before starting to do the next.
2473 // It's also a convenient place to catch and alert on errors.
2476 const nextPromise = this._lastPromise.then(() => {
2478 }).catch(async err => {
2479 if (err instanceof TLSCloseNotify) {
2482 await this._state.handleErrorAndRethrow(err);
2484 // We don't want to hold on to the return value or error,
2485 // just synchronize on the fact that it completed.
2486 this._lastPromise = nextPromise.then(noop, noop);
2490 // This drives internal transition of the state-machine,
2491 // ensuring that the new state is properly initialized.
2493 async _transition(State, ...args) {
2494 this._state = new State(this);
2495 await this._state.initialize(...args);
2496 await this._recordlayer.flush();
2499 // These are helpers to allow the State to manipulate the recordlayer
2500 // and send out various types of data.
2502 async _sendApplicationData(bytes) {
2503 await this._recordlayer.send(RECORD_TYPE.APPLICATION_DATA, bytes);
2504 await this._recordlayer.flush();
2507 async _sendHandshakeMessage(msg) {
2508 await this._sendHandshakeMessageBytes(msg.toBytes());
2511 async _sendHandshakeMessageBytes(bytes) {
2512 this._keyschedule.addToTranscript(bytes);
2513 await this._recordlayer.send(RECORD_TYPE.HANDSHAKE, bytes);
2514 // Don't flush after each handshake message, since we can probably
2515 // coalesce multiple messages into a single record.
2518 async _sendAlertMessage(err) {
2519 await this._recordlayer.send(RECORD_TYPE.ALERT, err.toBytes());
2520 await this._recordlayer.flush();
2523 async _sendChangeCipherSpec() {
2524 await this._recordlayer.send(RECORD_TYPE.CHANGE_CIPHER_SPEC, new Uint8Array([0x01]));
2525 await this._recordlayer.flush();
2528 async _setSendKey(key) {
2529 return await this._recordlayer.setSendKey(key);
2532 async _setRecvKey(key) {
2533 // Handshake messages that change keys must be on a record boundary.
2534 if (this._handshakeRecvBuffer && this._handshakeRecvBuffer.hasMoreBytes()) {
2535 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
2537 return await this._recordlayer.setRecvKey(key);
2540 _setConnectionSuccess() {
2541 if (this._onConnectionSuccess !== null) {
2542 this._onConnectionSuccess();
2543 this._onConnectionSuccess = null;
2544 this._onConnectionFailure = null;
2548 _setConnectionFailure(err) {
2549 if (this._onConnectionFailure !== null) {
2550 this._onConnectionFailure(err);
2551 this._onConnectionSuccess = null;
2552 this._onConnectionFailure = null;
2556 _closeForSend(alert) {
2557 this._recordlayer.setSendError(alert);
2560 _closeForRecv(alert) {
2561 this._recordlayer.setRecvError(alert);
2565 class tlsconnection_ClientConnection extends tlsconnection_Connection {
2566 static async create(psk, pskId, sendCallback) {
2567 const instance = await super.create(psk, pskId, sendCallback);
2568 await instance._transition(states_CLIENT_START);
2573 class tlsconnection_ServerConnection extends tlsconnection_Connection {
2574 static async create(psk, pskId, sendCallback) {
2575 const instance = await super.create(psk, pskId, sendCallback);
2576 await instance._transition(states_SERVER_START);
2581 // CONCATENATED MODULE: ./node_modules/event-target-shim/dist/event-target-shim.mjs
2583 * @author Toru Nagashima <https://github.com/mysticatea>
2584 * @copyright 2015 Toru Nagashima. All rights reserved.
2585 * See LICENSE file in root directory for full license.
2588 * @typedef {object} PrivateData
2589 * @property {EventTarget} eventTarget The event target.
2590 * @property {{type:string}} event The original event object.
2591 * @property {number} eventPhase The current event phase.
2592 * @property {EventTarget|null} currentTarget The current event target.
2593 * @property {boolean} canceled The flag to prevent default.
2594 * @property {boolean} stopped The flag to stop propagation.
2595 * @property {boolean} immediateStopped The flag to stop propagation immediately.
2596 * @property {Function|null} passiveListener The listener if the current listener is passive. Otherwise this is null.
2597 * @property {number} timeStamp The unix time.
2602 * Private data for event wrappers.
2603 * @type {WeakMap<Event, PrivateData>}
2606 const privateData = new WeakMap();
2609 * Cache for wrapper classes.
2610 * @type {WeakMap<Object, Function>}
2613 const wrappers = new WeakMap();
2617 * @param {Event} event The event object to get private data.
2618 * @returns {PrivateData} The private data of the event.
2621 function pd(event) {
2622 const retv = privateData.get(event);
2625 "'this' is expected an Event object, but got",
2632 * https://dom.spec.whatwg.org/#set-the-canceled-flag
2633 * @param data {PrivateData} private data.
2635 function setCancelFlag(data) {
2636 if (data.passiveListener != null) {
2638 typeof console !== "undefined" &&
2639 typeof console.error === "function"
2642 "Unable to preventDefault inside passive event listener invocation.",
2643 data.passiveListener
2648 if (!data.event.cancelable) {
2652 data.canceled = true;
2653 if (typeof data.event.preventDefault === "function") {
2654 data.event.preventDefault();
2659 * @see https://dom.spec.whatwg.org/#interface-event
2663 * The event wrapper.
2665 * @param {EventTarget} eventTarget The event target of this dispatching.
2666 * @param {Event|{type:string}} event The original event to wrap.
2668 function Event(eventTarget, event) {
2669 privateData.set(this, {
2673 currentTarget: eventTarget,
2676 immediateStopped: false,
2677 passiveListener: null,
2678 timeStamp: event.timeStamp || Date.now(),
2681 // https://heycam.github.io/webidl/#Unforgeable
2682 Object.defineProperty(this, "isTrusted", { value: false, enumerable: true });
2685 const keys = Object.keys(event);
2686 for (let i = 0; i < keys.length; ++i) {
2687 const key = keys[i];
2688 if (!(key in this)) {
2689 Object.defineProperty(this, key, defineRedirectDescriptor(key));
2694 // Should be enumerable, but class methods are not enumerable.
2697 * The type of this event.
2701 return pd(this).event.type
2705 * The target of this event.
2706 * @type {EventTarget}
2709 return pd(this).eventTarget
2713 * The target of this event.
2714 * @type {EventTarget}
2716 get currentTarget() {
2717 return pd(this).currentTarget
2721 * @returns {EventTarget[]} The composed path of this event.
2724 const currentTarget = pd(this).currentTarget;
2725 if (currentTarget == null) {
2728 return [currentTarget]
2740 * Constant of CAPTURING_PHASE.
2743 get CAPTURING_PHASE() {
2748 * Constant of AT_TARGET.
2756 * Constant of BUBBLING_PHASE.
2759 get BUBBLING_PHASE() {
2764 * The target of this event.
2768 return pd(this).eventPhase
2772 * Stop event bubbling.
2776 const data = pd(this);
2778 data.stopped = true;
2779 if (typeof data.event.stopPropagation === "function") {
2780 data.event.stopPropagation();
2785 * Stop event bubbling.
2788 stopImmediatePropagation() {
2789 const data = pd(this);
2791 data.stopped = true;
2792 data.immediateStopped = true;
2793 if (typeof data.event.stopImmediatePropagation === "function") {
2794 data.event.stopImmediatePropagation();
2799 * The flag to be bubbling.
2803 return Boolean(pd(this).event.bubbles)
2807 * The flag to be cancelable.
2811 return Boolean(pd(this).event.cancelable)
2815 * Cancel this event.
2819 setCancelFlag(pd(this));
2823 * The flag to indicate cancellation state.
2826 get defaultPrevented() {
2827 return pd(this).canceled
2831 * The flag to be composed.
2835 return Boolean(pd(this).event.composed)
2839 * The unix time of this event.
2843 return pd(this).timeStamp
2847 * The target of this event.
2848 * @type {EventTarget}
2852 return pd(this).eventTarget
2856 * The flag to stop event bubbling.
2860 get cancelBubble() {
2861 return pd(this).stopped
2863 set cancelBubble(value) {
2867 const data = pd(this);
2869 data.stopped = true;
2870 if (typeof data.event.cancelBubble === "boolean") {
2871 data.event.cancelBubble = true;
2876 * The flag to indicate cancellation state.
2881 return !pd(this).canceled
2883 set returnValue(value) {
2885 setCancelFlag(pd(this));
2890 * Initialize this event object. But do nothing under event dispatching.
2891 * @param {string} type The event type.
2892 * @param {boolean} [bubbles=false] The flag to be possible to bubble up.
2893 * @param {boolean} [cancelable=false] The flag to be possible to cancel.
2901 // `constructor` is not enumerable.
2902 Object.defineProperty(Event.prototype, "constructor", {
2908 // Ensure `event instanceof window.Event` is `true`.
2909 if (typeof window !== "undefined" && typeof window.Event !== "undefined") {
2910 Object.setPrototypeOf(Event.prototype, window.Event.prototype);
2912 // Make association for wrappers.
2913 wrappers.set(window.Event.prototype, Event);
2917 * Get the property descriptor to redirect a given property.
2918 * @param {string} key Property name to define property descriptor.
2919 * @returns {PropertyDescriptor} The property descriptor to redirect the property.
2922 function defineRedirectDescriptor(key) {
2925 return pd(this).event[key]
2928 pd(this).event[key] = value;
2936 * Get the property descriptor to call a given method property.
2937 * @param {string} key Property name to define property descriptor.
2938 * @returns {PropertyDescriptor} The property descriptor to call the method property.
2941 function defineCallDescriptor(key) {
2944 const event = pd(this).event;
2945 return event[key].apply(event, arguments)
2953 * Define new wrapper class.
2954 * @param {Function} BaseEvent The base wrapper class.
2955 * @param {Object} proto The prototype of the original event.
2956 * @returns {Function} The defined wrapper class.
2959 function defineWrapper(BaseEvent, proto) {
2960 const keys = Object.keys(proto);
2961 if (keys.length === 0) {
2966 function CustomEvent(eventTarget, event) {
2967 BaseEvent.call(this, eventTarget, event);
2970 CustomEvent.prototype = Object.create(BaseEvent.prototype, {
2971 constructor: { value: CustomEvent, configurable: true, writable: true },
2974 // Define accessors.
2975 for (let i = 0; i < keys.length; ++i) {
2976 const key = keys[i];
2977 if (!(key in BaseEvent.prototype)) {
2978 const descriptor = Object.getOwnPropertyDescriptor(proto, key);
2979 const isFunc = typeof descriptor.value === "function";
2980 Object.defineProperty(
2981 CustomEvent.prototype,
2984 ? defineCallDescriptor(key)
2985 : defineRedirectDescriptor(key)
2994 * Get the wrapper class of a given prototype.
2995 * @param {Object} proto The prototype of the original event to get its wrapper.
2996 * @returns {Function} The wrapper class.
2999 function getWrapper(proto) {
3000 if (proto == null || proto === Object.prototype) {
3004 let wrapper = wrappers.get(proto);
3005 if (wrapper == null) {
3006 wrapper = defineWrapper(getWrapper(Object.getPrototypeOf(proto)), proto);
3007 wrappers.set(proto, wrapper);
3013 * Wrap a given event to management a dispatching.
3014 * @param {EventTarget} eventTarget The event target of this dispatching.
3015 * @param {Object} event The event to wrap.
3016 * @returns {Event} The wrapper instance.
3019 function wrapEvent(eventTarget, event) {
3020 const Wrapper = getWrapper(Object.getPrototypeOf(event));
3021 return new Wrapper(eventTarget, event)
3025 * Get the immediateStopped flag of a given event.
3026 * @param {Event} event The event to get.
3027 * @returns {boolean} The flag to stop propagation immediately.
3030 function isStopped(event) {
3031 return pd(event).immediateStopped
3035 * Set the current event phase of a given event.
3036 * @param {Event} event The event to set current target.
3037 * @param {number} eventPhase New event phase.
3041 function setEventPhase(event, eventPhase) {
3042 pd(event).eventPhase = eventPhase;
3046 * Set the current target of a given event.
3047 * @param {Event} event The event to set current target.
3048 * @param {EventTarget|null} currentTarget New current target.
3052 function setCurrentTarget(event, currentTarget) {
3053 pd(event).currentTarget = currentTarget;
3057 * Set a passive listener of a given event.
3058 * @param {Event} event The event to set current target.
3059 * @param {Function|null} passiveListener New passive listener.
3063 function setPassiveListener(event, passiveListener) {
3064 pd(event).passiveListener = passiveListener;
3068 * @typedef {object} ListenerNode
3069 * @property {Function} listener
3070 * @property {1|2|3} listenerType
3071 * @property {boolean} passive
3072 * @property {boolean} once
3073 * @property {ListenerNode|null} next
3078 * @type {WeakMap<object, Map<string, ListenerNode>>}
3081 const listenersMap = new WeakMap();
3086 const ATTRIBUTE = 3;
3089 * Check whether a given value is an object or not.
3090 * @param {any} x The value to check.
3091 * @returns {boolean} `true` if the value is an object.
3093 function isObject(x) {
3094 return x !== null && typeof x === "object" //eslint-disable-line no-restricted-syntax
3099 * @param {EventTarget} eventTarget The event target to get.
3100 * @returns {Map<string, ListenerNode>} The listeners.
3103 function getListeners(eventTarget) {
3104 const listeners = listenersMap.get(eventTarget);
3105 if (listeners == null) {
3106 throw new TypeError(
3107 "'this' is expected an EventTarget object, but got another value."
3114 * Get the property descriptor for the event attribute of a given event.
3115 * @param {string} eventName The event name to get property descriptor.
3116 * @returns {PropertyDescriptor} The property descriptor.
3119 function defineEventAttributeDescriptor(eventName) {
3122 const listeners = getListeners(this);
3123 let node = listeners.get(eventName);
3124 while (node != null) {
3125 if (node.listenerType === ATTRIBUTE) {
3126 return node.listener
3134 if (typeof listener !== "function" && !isObject(listener)) {
3135 listener = null; // eslint-disable-line no-param-reassign
3137 const listeners = getListeners(this);
3139 // Traverse to the tail while removing old value.
3141 let node = listeners.get(eventName);
3142 while (node != null) {
3143 if (node.listenerType === ATTRIBUTE) {
3144 // Remove old value.
3145 if (prev !== null) {
3146 prev.next = node.next;
3147 } else if (node.next !== null) {
3148 listeners.set(eventName, node.next);
3150 listeners.delete(eventName);
3160 if (listener !== null) {
3163 listenerType: ATTRIBUTE,
3168 if (prev === null) {
3169 listeners.set(eventName, newNode);
3171 prev.next = newNode;
3181 * Define an event attribute (e.g. `eventTarget.onclick`).
3182 * @param {Object} eventTargetPrototype The event target prototype to define an event attrbite.
3183 * @param {string} eventName The event name to define.
3186 function defineEventAttribute(eventTargetPrototype, eventName) {
3187 Object.defineProperty(
3188 eventTargetPrototype,
3190 defineEventAttributeDescriptor(eventName)
3195 * Define a custom EventTarget with event attributes.
3196 * @param {string[]} eventNames Event names for event attributes.
3197 * @returns {EventTarget} The custom EventTarget.
3200 function defineCustomEventTarget(eventNames) {
3201 /** CustomEventTarget */
3202 function CustomEventTarget() {
3203 EventTarget.call(this);
3206 CustomEventTarget.prototype = Object.create(EventTarget.prototype, {
3208 value: CustomEventTarget,
3214 for (let i = 0; i < eventNames.length; ++i) {
3215 defineEventAttribute(CustomEventTarget.prototype, eventNames[i]);
3218 return CustomEventTarget
3224 * - This is constructor if no arguments.
3225 * - This is a function which returns a CustomEventTarget constructor if there are arguments.
3229 * class A extends EventTarget {}
3230 * class B extends EventTarget("message") {}
3231 * class C extends EventTarget("message", "error") {}
3232 * class D extends EventTarget(["message", "error"]) {}
3234 function EventTarget() {
3235 /*eslint-disable consistent-return */
3236 if (this instanceof EventTarget) {
3237 listenersMap.set(this, new Map());
3240 if (arguments.length === 1 && Array.isArray(arguments[0])) {
3241 return defineCustomEventTarget(arguments[0])
3243 if (arguments.length > 0) {
3244 const types = new Array(arguments.length);
3245 for (let i = 0; i < arguments.length; ++i) {
3246 types[i] = arguments[i];
3248 return defineCustomEventTarget(types)
3250 throw new TypeError("Cannot call a class as a function")
3251 /*eslint-enable consistent-return */
3254 // Should be enumerable, but class methods are not enumerable.
3255 EventTarget.prototype = {
3257 * Add a given listener to this event target.
3258 * @param {string} eventName The event name to add.
3259 * @param {Function} listener The listener to add.
3260 * @param {boolean|{capture?:boolean,passive?:boolean,once?:boolean}} [options] The options for this listener.
3263 addEventListener(eventName, listener, options) {
3264 if (listener == null) {
3267 if (typeof listener !== "function" && !isObject(listener)) {
3268 throw new TypeError("'listener' should be a function or an object.")
3271 const listeners = getListeners(this);
3272 const optionsIsObj = isObject(options);
3273 const capture = optionsIsObj
3274 ? Boolean(options.capture)
3276 const listenerType = capture ? CAPTURE : BUBBLE;
3280 passive: optionsIsObj && Boolean(options.passive),
3281 once: optionsIsObj && Boolean(options.once),
3285 // Set it as the first node if the first node is null.
3286 let node = listeners.get(eventName);
3287 if (node === undefined) {
3288 listeners.set(eventName, newNode);
3292 // Traverse to the tail while checking duplication..
3294 while (node != null) {
3296 node.listener === listener &&
3297 node.listenerType === listenerType
3299 // Should ignore duplication.
3307 prev.next = newNode;
3311 * Remove a given listener from this event target.
3312 * @param {string} eventName The event name to remove.
3313 * @param {Function} listener The listener to remove.
3314 * @param {boolean|{capture?:boolean,passive?:boolean,once?:boolean}} [options] The options for this listener.
3317 removeEventListener(eventName, listener, options) {
3318 if (listener == null) {
3322 const listeners = getListeners(this);
3323 const capture = isObject(options)
3324 ? Boolean(options.capture)
3326 const listenerType = capture ? CAPTURE : BUBBLE;
3329 let node = listeners.get(eventName);
3330 while (node != null) {
3332 node.listener === listener &&
3333 node.listenerType === listenerType
3335 if (prev !== null) {
3336 prev.next = node.next;
3337 } else if (node.next !== null) {
3338 listeners.set(eventName, node.next);
3340 listeners.delete(eventName);
3351 * Dispatch a given event.
3352 * @param {Event|{type:string}} event The event to dispatch.
3353 * @returns {boolean} `false` if canceled.
3355 dispatchEvent(event) {
3356 if (event == null || typeof event.type !== "string") {
3357 throw new TypeError('"event.type" should be a string.')
3360 // If listeners aren't registered, terminate.
3361 const listeners = getListeners(this);
3362 const eventName = event.type;
3363 let node = listeners.get(eventName);
3368 // Since we cannot rewrite several properties, so wrap object.
3369 const wrappedEvent = wrapEvent(this, event);
3371 // This doesn't process capturing phase and bubbling phase.
3372 // This isn't participating in a tree.
3374 while (node != null) {
3375 // Remove this listener if it's once
3377 if (prev !== null) {
3378 prev.next = node.next;
3379 } else if (node.next !== null) {
3380 listeners.set(eventName, node.next);
3382 listeners.delete(eventName);
3388 // Call this listener
3391 node.passive ? node.listener : null
3393 if (typeof node.listener === "function") {
3395 node.listener.call(this, wrappedEvent);
3398 typeof console !== "undefined" &&
3399 typeof console.error === "function"
3405 node.listenerType !== ATTRIBUTE &&
3406 typeof node.listener.handleEvent === "function"
3408 node.listener.handleEvent(wrappedEvent);
3411 // Break if `event.stopImmediatePropagation` was called.
3412 if (isStopped(wrappedEvent)) {
3418 setPassiveListener(wrappedEvent, null);
3419 setEventPhase(wrappedEvent, 0);
3420 setCurrentTarget(wrappedEvent, null);
3422 return !wrappedEvent.defaultPrevented
3426 // `constructor` is not enumerable.
3427 Object.defineProperty(EventTarget.prototype, "constructor", {
3433 // Ensure `eventTarget instanceof window.EventTarget` is `true`.
3435 typeof window !== "undefined" &&
3436 typeof window.EventTarget !== "undefined"
3438 Object.setPrototypeOf(EventTarget.prototype, window.EventTarget.prototype);
3441 /* harmony default export */ var event_target_shim = (EventTarget);
3444 // CONCATENATED MODULE: ./src/index.js
3445 /* This Source Code Form is subject to the terms of the Mozilla Public
3446 * License, v. 2.0. If a copy of the MPL was not distributed with this
3447 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
3449 // A wrapper that combines a WebSocket to the channelserver
3450 // with some client-side encryption for securing the channel.
3452 // This code is responsible for the event handling and the consumer API.
3453 // All the details of encrypting the messages are delegated to`./tlsconnection.js`.
3461 const CLOSE_FLUSH_BUFFER_INTERVAL_MS = 200;
3462 const CLOSE_FLUSH_BUFFER_MAX_TRIES = 5;
3464 class src_PairingChannel extends EventTarget {
3465 constructor(channelId, channelKey, socket, connection) {
3467 this._channelId = channelId;
3468 this._channelKey = channelKey;
3469 this._socket = socket;
3470 this._connection = connection;
3471 this._selfClosed = false;
3472 this._peerClosed = false;
3473 this._setupListeners();
3477 * Create a new pairing channel.
3479 * This will open a channel on the channelserver, and generate a random client-side
3480 * encryption key. When the promise resolves, `this.channelId` and `this.channelKey`
3481 * can be transferred to another client to allow it to securely connect to the channel.
3483 * @returns Promise<PairingChannel>
3485 static create(channelServerURI) {
3486 const wsURI = new URL('/v1/ws/', channelServerURI).href;
3487 const channelKey = crypto.getRandomValues(new Uint8Array(32));
3488 // The one who creates the channel plays the role of 'server' in the underlying TLS exchange.
3489 return this._makePairingChannel(wsURI, tlsconnection_ServerConnection, channelKey);
3493 * Connect to an existing pairing channel.
3495 * This will connect to a channel on the channelserver previously established by
3496 * another client calling `create`. The `channelId` and `channelKey` must have been
3497 * obtained via some out-of-band mechanism (such as by scanning from a QR code).
3499 * @returns Promise<PairingChannel>
3501 static connect(channelServerURI, channelId, channelKey) {
3502 const wsURI = new URL(`/v1/ws/${channelId}`, channelServerURI).href;
3503 // The one who connects to an existing channel plays the role of 'client'
3504 // in the underlying TLS exchange.
3505 return this._makePairingChannel(wsURI, tlsconnection_ClientConnection, channelKey);
3508 static _makePairingChannel(wsUri, ConnectionClass, psk) {
3509 const socket = new WebSocket(wsUri);
3510 return new Promise((resolve, reject) => {
3511 // eslint-disable-next-line prefer-const
3513 const onConnectionError = async () => {
3515 reject(new Error('Error while creating the pairing channel'));
3517 const onFirstMessage = async event => {
3520 // The channelserver echos back the channel id, and we use it as an
3521 // additional input to the TLS handshake via the "psk id" field.
3522 const {channelid: channelId} = JSON.parse(event.data);
3523 const pskId = utf8ToBytes(channelId);
3524 const connection = await ConnectionClass.create(psk, pskId, data => {
3525 // Send data by forwarding it via the channelserver websocket.
3526 // The TLS connection gives us `data` as raw bytes, but channelserver
3527 // expects b64urlsafe strings, because it wraps them in a JSON object envelope.
3528 socket.send(bytesToBase64url(data));
3530 const instance = new this(channelId, psk, socket, connection);
3536 stopListening = () => {
3537 socket.removeEventListener('close', onConnectionError);
3538 socket.removeEventListener('error', onConnectionError);
3539 socket.removeEventListener('message', onFirstMessage);
3541 socket.addEventListener('close', onConnectionError);
3542 socket.addEventListener('error', onConnectionError);
3543 socket.addEventListener('message', onFirstMessage);
3548 this._socket.addEventListener('message', async event => {
3550 // When we receive data from the channelserver, pump it through the TLS connection
3551 // to decrypt it, then echo it back out to consumers as an event.
3552 const channelServerEnvelope = JSON.parse(event.data);
3553 const payload = await this._connection.recv(base64urlToBytes(channelServerEnvelope.message));
3554 if (payload !== null) {
3555 const data = JSON.parse(bytesToUtf8(payload));
3556 this.dispatchEvent(new CustomEvent('message', {
3559 sender: channelServerEnvelope.sender,
3565 // The underlying TLS connection will signal a clean shutdown of the channel
3566 // by throwing a special error, because it doesn't really have a better
3567 // signally mechanism available.
3568 if (error instanceof TLSCloseNotify) {
3569 this._peerClosed = true;
3570 if (this._selfClosed) {
3573 event = new CustomEvent('close');
3575 event = new CustomEvent('error', {
3581 this.dispatchEvent(event);
3584 // Relay the WebSocket events.
3585 this._socket.addEventListener('error', () => {
3587 // The dispatched event that we receive has no useful information.
3588 this.dispatchEvent(new CustomEvent('error', {
3590 error: new Error('WebSocket error.'),
3594 // In TLS, the peer has to explicitly send a close notification,
3595 // which we dispatch above. Unexpected socket close is an error.
3596 this._socket.addEventListener('close', () => {
3598 if (! this._peerClosed) {
3599 this.dispatchEvent(new CustomEvent('error', {
3601 error: new Error('WebSocket unexpectedly closed'),
3609 * @param {Object} data
3612 const payload = utf8ToBytes(JSON.stringify(data));
3613 await this._connection.send(payload);
3617 this._selfClosed = true;
3618 await this._connection.close();
3620 // Ensure all queued bytes have been sent before closing the connection.
3622 while (this._socket.bufferedAmount > 0) {
3623 if (++tries > CLOSE_FLUSH_BUFFER_MAX_TRIES) {
3624 throw new Error('Could not flush the outgoing buffer in time.');
3626 await new Promise(res => setTimeout(res, CLOSE_FLUSH_BUFFER_INTERVAL_MS));
3629 // If the peer hasn't closed, we might still receive some data.
3630 if (this._peerClosed) {
3638 this._socket.close();
3639 this._socket = null;
3640 this._connection = null;
3645 return (! this._socket) || (this._socket.readyState === 3);
3649 return this._channelId;
3653 return this._channelKey;
3657 // Re-export helpful utilities for calling code to use.
3660 // For running tests using the built bundle,
3661 // expose a bunch of implementation details.
3669 const _internals = {
3670 arrayToBytes: arrayToBytes,
3671 BufferReader: utils_BufferReader,
3672 BufferWriter: utils_BufferWriter,
3673 bytesAreEqual: bytesAreEqual,
3674 bytesToHex: bytesToHex,
3675 bytesToUtf8: bytesToUtf8,
3676 ClientConnection: tlsconnection_ClientConnection,
3677 Connection: tlsconnection_Connection,
3678 DecryptionState: recordlayer_DecryptionState,
3679 EncryptedExtensions: EncryptedExtensions,
3680 EncryptionState: recordlayer_EncryptionState,
3681 Finished: messages_Finished,
3682 HASH_LENGTH: HASH_LENGTH,
3683 hexToBytes: hexToBytes,
3684 hkdfExpand: hkdfExpand,
3685 KeySchedule: keyschedule_KeySchedule,
3686 NewSessionTicket: messages_NewSessionTicket,
3687 RecordLayer: recordlayer_RecordLayer,
3688 ServerConnection: tlsconnection_ServerConnection,
3689 utf8ToBytes: utf8ToBytes,
3695 /******/ ])["PairingChannel"];