Bug 1768570 [wpt PR 34013] - Update wpt metadata, a=testonly
[gecko.git] / services / fxaccounts / FxAccountsPairingChannel.js
blobfeb82409ded1c5e25d11dda4383dded3795aa093
1 /*!
2  * 
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/.
6  * 
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.
10  * 
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.
13  * 
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
16  * 
17  * Bundle generated from https://github.com/mozilla/fxa-pairing-channel.git. Hash:c8ec3119920b4ffa833b, Chunkhash:378a5f51445e7aa7630e.
18  * 
19  */
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 = {};
38 /******/
39 /******/        // The require function
40 /******/        function __webpack_require__(moduleId) {
41 /******/
42 /******/                // Check if module is in cache
43 /******/                if(installedModules[moduleId]) {
44 /******/                        return installedModules[moduleId].exports;
45 /******/                }
46 /******/                // Create a new module (and put it into the cache)
47 /******/                var module = installedModules[moduleId] = {
48 /******/                        i: moduleId,
49 /******/                        l: false,
50 /******/                        exports: {}
51 /******/                };
52 /******/
53 /******/                // Execute the module function
54 /******/                modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
55 /******/
56 /******/                // Flag the module as loaded
57 /******/                module.l = true;
58 /******/
59 /******/                // Return the exports of the module
60 /******/                return module.exports;
61 /******/        }
62 /******/
63 /******/
64 /******/        // expose the modules object (__webpack_modules__)
65 /******/        __webpack_require__.m = modules;
66 /******/
67 /******/        // expose the module cache
68 /******/        __webpack_require__.c = installedModules;
69 /******/
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 });
74 /******/                }
75 /******/        };
76 /******/
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' });
81 /******/                }
82 /******/                Object.defineProperty(exports, '__esModule', { value: true });
83 /******/        };
84 /******/
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));
98 /******/                return ns;
99 /******/        };
100 /******/
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;
108 /******/        };
109 /******/
110 /******/        // Object.prototype.hasOwnProperty.call
111 /******/        __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
112 /******/
113 /******/        // __webpack_public_path__
114 /******/        __webpack_require__.p = "";
115 /******/
116 /******/
117 /******/        // Load entry module and return exports
118 /******/        return __webpack_require__(__webpack_require__.s = 0);
119 /******/ })
120 /************************************************************************/
121 /******/ ([
122 /* 0 */
123 /***/ (function(module, __webpack_exports__, __webpack_require__) {
125 "use strict";
126 // ESM COMPAT FLAG
127 __webpack_require__.r(__webpack_exports__);
129 // 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 = {
148   WARNING: 1,
149   FATAL: 2
152 const ALERT_DESCRIPTION = {
153   CLOSE_NOTIFY: 0,
154   UNEXPECTED_MESSAGE: 10,
155   BAD_RECORD_MAC: 20,
156   RECORD_OVERFLOW: 22,
157   HANDSHAKE_FAILURE: 40,
158   ILLEGAL_PARAMETER: 47,
159   DECODE_ERROR: 50,
160   DECRYPT_ERROR: 51,
161   PROTOCOL_VERSION: 70,
162   INTERNAL_ERROR: 80,
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})`;
174     }
175   }
176   return `UNKNOWN (${type})`;
179 class TLSAlert extends Error {
180   constructor(description, level) {
181     super(`TLS Alert: ${alertTypeToName(description)}`);
182     this.description = description;
183     this.level = level;
184   }
186   static fromBytes(bytes) {
187     if (bytes.byteLength !== 2) {
188       throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
189     }
190     switch (bytes[1]) {
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);
195         }
196         return new TLSCloseNotify();
197       default:
198         return new TLSError(bytes[1]);
199     }
200   }
202   toBytes() {
203     return new Uint8Array([this.level, this.description]);
204   }
207 class TLSCloseNotify extends TLSAlert {
208   constructor() {
209     super(ALERT_DESCRIPTION.CLOSE_NOTIFY, ALERT_LEVEL.WARNING);
210   }
213 class TLSError extends TLSAlert {
214   constructor(description = ALERT_DESCRIPTION.INTERNAL_ERROR) {
215     super(description, ALERT_LEVEL.FATAL);
216   }
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();
236 function noop() {}
238 function assert(cond, msg) {
239   if (! cond) {
240     throw new Error('assert failed: ' + msg);
241   }
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);
249   return value;
252 const EMPTY = new Uint8Array(0);
254 function zeros(n) {
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) {
266       s = '0' + s;
267     }
268     return s;
269   }).join('');
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) => {
275     if (n % 2 === 1) {
276       return hexstr[n - 1] + c;
277     } else {
278       return '';
279     }
280   }).filter(s => {
281     return !! s;
282   }).map(s => {
283     return parseInt(s, 16);
284   }));
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);
309   }
310   return bytes;
313 function bytesAreEqual(v1, v2) {
314   assertIsBytes(v1);
315   assertIsBytes(v2);
316   if (v1.length !== v2.length) {
317     return false;
318   }
319   for (let i = 0; i < v1.length; i++) {
320     if (v1[i] !== v2[i]) {
321       return false;
322     }
323   }
324   return true;
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 {
333   constructor(buf) {
334     this._buffer = buf;
335     this._dataview = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
336     this._pos = 0;
337   }
339   length() {
340     return this._buffer.byteLength;
341   }
343   tell() {
344     return this._pos;
345   }
347   seek(pos) {
348     if (pos < 0) {
349       throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
350     }
351     if (pos > this.length()) {
352       throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
353     }
354     this._pos = pos;
355   }
357   incr(offset) {
358     this.seek(this._pos + offset);
359   }
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:
378 //    const items = []
379 //    buf.readVector8(buf => {
380 //      items.push(buf.readUint16())
381 //    })
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 {
388   hasMoreBytes() {
389     return this.tell() < this.length();
390   }
392   readBytes(length) {
393     // This avoids copies by returning a view onto the existing buffer.
394     const start = this._buffer.byteOffset + this.tell();
395     this.incr(length);
396     return new Uint8Array(this._buffer.buffer, start, length);
397   }
399   _rangeErrorToAlert(cb) {
400     try {
401       return cb(this);
402     } catch (err) {
403       if (err instanceof RangeError) {
404         throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
405       }
406       throw err;
407     }
408   }
410   readUint8() {
411     return this._rangeErrorToAlert(() => {
412       const n = this._dataview.getUint8(this._pos);
413       this.incr(1);
414       return n;
415     });
416   }
418   readUint16() {
419     return this._rangeErrorToAlert(() => {
420       const n = this._dataview.getUint16(this._pos);
421       this.incr(2);
422       return n;
423     });
424   }
426   readUint24() {
427     return this._rangeErrorToAlert(() => {
428       let n = this._dataview.getUint16(this._pos);
429       n = (n << 8) | this._dataview.getUint8(this._pos + 2);
430       this.incr(3);
431       return n;
432     });
433   }
435   readUint32() {
436     return this._rangeErrorToAlert(() => {
437       const n = this._dataview.getUint32(this._pos);
438       this.incr(4);
439       return n;
440     });
441   }
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.
447     let n = 0;
448     while (contentsBuf.hasMoreBytes()) {
449       const prevPos = contentsBuf.tell();
450       cb(contentsBuf, n);
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);
454       }
455       n += 1;
456     }
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);
460     }
461   }
463   readVector8(cb) {
464     const length = this.readUint8();
465     return this._readVector(length, cb);
466   }
468   readVector16(cb) {
469     const length = this.readUint16();
470     return this._readVector(length, cb);
471   }
473   readVector24(cb) {
474     const length = this.readUint24();
475     return this._readVector(length, cb);
476   }
478   readVectorBytes8() {
479     return this.readBytes(this.readUint8());
480   }
482   readVectorBytes16() {
483     return this.readBytes(this.readUint16());
484   }
486   readVectorBytes24() {
487     return this.readBytes(this.readUint24());
488   }
492 class utils_BufferWriter extends utils_BufferWithPointer {
493   constructor(size = 1024) {
494     super(new Uint8Array(size));
495   }
497   _maybeGrow(n) {
498     const curSize = this._buffer.byteLength;
499     const newPos = this._pos + n;
500     const shortfall = newPos - curSize;
501     if (shortfall > 0) {
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);
509     }
510   }
512   slice(start = 0, end = this.tell()) {
513     if (end < 0) {
514       end = this.tell() + end;
515     }
516     if (start < 0) {
517       throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
518     }
519     if (end < 0) {
520       throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
521     }
522     if (end > this.length()) {
523       throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
524     }
525     return this._buffer.slice(start, end);
526   }
528   flush() {
529     const slice = this.slice();
530     this.seek(0);
531     return slice;
532   }
534   writeBytes(data) {
535     this._maybeGrow(data.byteLength);
536     this._buffer.set(data, this.tell());
537     this.incr(data.byteLength);
538   }
540   writeUint8(n) {
541     this._maybeGrow(1);
542     this._dataview.setUint8(this._pos, n);
543     this.incr(1);
544   }
546   writeUint16(n) {
547     this._maybeGrow(2);
548     this._dataview.setUint16(this._pos, n);
549     this.incr(2);
550   }
552   writeUint24(n) {
553     this._maybeGrow(3);
554     this._dataview.setUint16(this._pos, n >> 8);
555     this._dataview.setUint8(this._pos + 2, n & 0xFF);
556     this.incr(3);
557   }
559   writeUint32(n) {
560     this._maybeGrow(4);
561     this._dataview.setUint32(this._pos, n);
562     this.incr(4);
563   }
565   // These are helpers for writing the variable-length vector structure
566   // defined in https://tools.ietf.org/html/rfc8446#section-3.4.
567   //
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`.
572   //
573   // To write a variable-length vector of between 1 and 100 uint16 values,
574   // defined in the RFC like this:
575   //
576   //    uint16 items<2..200>;
577   //
578   // You would do something like this:
579   //
580   //    buf.writeVector8(buf => {
581   //      for (let item of items) {
582   //          buf.writeUint16(item)
583   //      }
584   //    })
585   //
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();
592     writeLength(0);
593     // Call the callback to write the vector items.
594     const bodyPos = this.tell();
595     cb(this);
596     const length = this.tell() - bodyPos;
597     if (length >= maxLength) {
598       throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
599     }
600     // Backfill the actual length field.
601     this.seek(lengthPos);
602     writeLength(length);
603     this.incr(length);
604     return length;
605   }
607   writeVector8(cb) {
608     return this._writeVector(Math.pow(2, 8), len => this.writeUint8(len), cb);
609   }
611   writeVector16(cb) {
612     return this._writeVector(Math.pow(2, 16), len => this.writeUint16(len), cb);
613   }
615   writeVector24(cb) {
616     return this._writeVector(Math.pow(2, 24), len => this.writeUint24(len), cb);
617   }
619   writeVectorBytes8(bytes) {
620     return this.writeVector8(buf => {
621       buf.writeBytes(bytes);
622     });
623   }
625   writeVectorBytes16(bytes) {
626     return this.writeVector16(buf => {
627       buf.writeBytes(bytes);
628     });
629   }
631   writeVectorBytes24(bytes) {
632     return this.writeVector24(buf => {
633       buf.writeBytes(bytes);
634     });
635   }
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
649 // API.
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({
666     additionalData,
667     iv,
668     name: 'AES-GCM',
669     tagLength: AEAD_SIZE_INFLATION * 8
670   }, key, plaintext);
671   return new Uint8Array(ciphertext);
674 async function decrypt(key, iv, ciphertext, additionalData) {
675   try {
676     const plaintext = await crypto.subtle.decrypt({
677       additionalData,
678       iv,
679       name: 'AES-GCM',
680       tagLength: AEAD_SIZE_INFLATION * 8
681     }, key, ciphertext);
682     return new Uint8Array(plaintext);
683   } catch (err) {
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);
687   }
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' },
697     name: 'HMAC',
698   }, false, ['sign']);
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' },
706     name: 'HMAC',
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);
712   }
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);
723   if (N <= 0) {
724     throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
725   }
726   if (N >= 255) {
727     throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
728   }
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++) {
733     input.writeBytes(T);
734     input.writeBytes(info);
735     input.writeUint8(i);
736     T = await hmac(prk, input.flush());
737     output.writeBytes(T);
738   }
739   return output.slice(0, length);
742 async function hkdfExpandLabel(secret, label, context, length) {
743   //  struct {
744   //    uint16 length = Length;
745   //    opaque label < 7..255 > = "tls13 " + Label;
746   //    opaque context < 0..255 > = Context;
747   //  } HkdfLabel;
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);
758   return 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 = {
784   PRE_SHARED_KEY: 41,
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:
793 //   struct {
794 //     ExtensionType extension_type;
795 //     opaque extension_data<0..2^16-1>;
796 //   } Extension;
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 {
804   get TYPE_TAG() {
805     throw new Error('not implemented');
806   }
808   static read(messageType, buf) {
809     const type = buf.readUint16();
810     let ext = {
811       TYPE_TAG: type,
812     };
813     buf.readVector16(buf => {
814       switch (type) {
815         case EXTENSION_TYPE.PRE_SHARED_KEY:
816           ext = extensions_PreSharedKeyExtension._read(messageType, buf);
817           break;
818         case EXTENSION_TYPE.SUPPORTED_VERSIONS:
819           ext = extensions_SupportedVersionsExtension._read(messageType, buf);
820           break;
821         case EXTENSION_TYPE.PSK_KEY_EXCHANGE_MODES:
822           ext = extensions_PskKeyExchangeModesExtension._read(messageType, buf);
823           break;
824         default:
825           // Skip over unrecognised extensions.
826           buf.incr(buf.length());
827       }
828       if (buf.hasMoreBytes()) {
829         throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
830       }
831     });
832     return ext;
833   }
835   write(messageType, buf) {
836     buf.writeUint16(this.TYPE_TAG);
837     buf.writeVector16(buf => {
838       this._write(messageType, buf);
839     });
840   }
842   static _read(messageType, buf) {
843     throw new Error('not implemented');
844   }
846   static _write(messageType, buf) {
847     throw new Error('not implemented');
848   }
851 // The PreSharedKey extension:
853 //  struct {
854 //    opaque identity<1..2^16-1>;
855 //    uint32 obfuscated_ticket_age;
856 //  } PskIdentity;
857 //  opaque PskBinderEntry<32..255>;
858 //  struct {
859 //    PskIdentity identities<7..2^16-1>;
860 //    PskBinderEntry binders<33..2^16-1>;
861 //  } OfferedPsks;
862 //  struct {
863 //    select(Handshake.msg_type) {
864 //      case client_hello: OfferedPsks;
865 //      case server_hello: uint16 selected_identity;
866 //    };
867 //  } PreSharedKeyExtension;
869 class extensions_PreSharedKeyExtension extends extensions_Extension {
870   constructor(identities, binders, selectedIdentity) {
871     super();
872     this.identities = identities;
873     this.binders = binders;
874     this.selectedIdentity = selectedIdentity;
875   }
877   get TYPE_TAG() {
878     return EXTENSION_TYPE.PRE_SHARED_KEY;
879   }
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);
890         });
891         buf.readVector16(buf => {
892           const binder = buf.readVectorBytes8();
893           if (binder.byteLength < HASH_LENGTH) {
894             throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
895           }
896           binders.push(binder);
897         });
898         if (identities.length !== binders.length) {
899           throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
900         }
901         break;
902       case HANDSHAKE_TYPE.SERVER_HELLO:
903         selectedIdentity = buf.readUint16();
904         break;
905       default:
906         throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
907     }
908     return new this(identities, binders, selectedIdentity);
909   }
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.
918           });
919         });
920         buf.writeVector16(buf => {
921           this.binders.forEach(pskBinder => {
922             buf.writeVectorBytes8(pskBinder);
923           });
924         });
925         break;
926       case HANDSHAKE_TYPE.SERVER_HELLO:
927         buf.writeUint16(this.selectedIdentity);
928         break;
929       default:
930         throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
931     }
932   }
936 // The SupportedVersions extension:
938 //  struct {
939 //    select(Handshake.msg_type) {
940 //      case client_hello:
941 //        ProtocolVersion versions < 2..254 >;
942 //      case server_hello:
943 //        ProtocolVersion selected_version;
944 //    };
945 //  } SupportedVersions;
947 class extensions_SupportedVersionsExtension extends extensions_Extension {
948   constructor(versions, selectedVersion) {
949     super();
950     this.versions = versions;
951     this.selectedVersion = selectedVersion;
952   }
954   get TYPE_TAG() {
955     return EXTENSION_TYPE.SUPPORTED_VERSIONS;
956   }
958   static _read(messageType, buf) {
959     let versions = null, selectedVersion = null;
960     switch (messageType) {
961       case HANDSHAKE_TYPE.CLIENT_HELLO:
962         versions = [];
963         buf.readVector8(buf => {
964           versions.push(buf.readUint16());
965         });
966         break;
967       case HANDSHAKE_TYPE.SERVER_HELLO:
968         selectedVersion = buf.readUint16();
969         break;
970       default:
971         throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
972     }
973     return new this(versions, selectedVersion);
974   }
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);
982           });
983         });
984         break;
985       case HANDSHAKE_TYPE.SERVER_HELLO:
986         buf.writeUint16(this.selectedVersion);
987         break;
988       default:
989         throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
990     }
991   }
995 class extensions_PskKeyExchangeModesExtension extends extensions_Extension {
996   constructor(modes) {
997     super();
998     this.modes = modes;
999   }
1001   get TYPE_TAG() {
1002     return EXTENSION_TYPE.PSK_KEY_EXCHANGE_MODES;
1003   }
1005   static _read(messageType, buf) {
1006     const modes = [];
1007     switch (messageType) {
1008       case HANDSHAKE_TYPE.CLIENT_HELLO:
1009         buf.readVector8(buf => {
1010           modes.push(buf.readUint8());
1011         });
1012         break;
1013       default:
1014         throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1015     }
1016     return new this(modes);
1017   }
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);
1025           });
1026         });
1027         break;
1028       default:
1029         throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
1030     }
1031   }
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/. */
1051 // Message parsing.
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 = {
1065   CLIENT_HELLO: 1,
1066   SERVER_HELLO: 2,
1067   NEW_SESSION_TICKET: 4,
1068   ENCRYPTED_EXTENSIONS: 8,
1069   FINISHED: 20,
1071 /* eslint-enable sorting/sort-object-props */
1073 // Base class for generic reading/writing of handshake messages,
1074 // which are all uniformly formatted as:
1076 //  struct {
1077 //    HandshakeType msg_type;    /* handshake type */
1078 //    uint24 length;             /* bytes in message */
1079 //    select(Handshake.msg_type) {
1080 //        ... type specific cases here ...
1081 //    };
1082 //  } Handshake;
1084 class messages_HandshakeMessage {
1086   get TYPE_TAG() {
1087     throw new Error('not implemented');
1088   }
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);
1097     }
1098     return msg;
1099   }
1101   toBytes() {
1102     const buf = new utils_BufferWriter();
1103     this.write(buf);
1104     return buf.flush();
1105   }
1107   static read(buf) {
1108     const type = buf.readUint8();
1109     let msg = null;
1110     buf.readVector24(buf => {
1111       switch (type) {
1112         case HANDSHAKE_TYPE.CLIENT_HELLO:
1113           msg = messages_ClientHello._read(buf);
1114           break;
1115         case HANDSHAKE_TYPE.SERVER_HELLO:
1116           msg = messages_ServerHello._read(buf);
1117           break;
1118         case HANDSHAKE_TYPE.NEW_SESSION_TICKET:
1119           msg = messages_NewSessionTicket._read(buf);
1120           break;
1121         case HANDSHAKE_TYPE.ENCRYPTED_EXTENSIONS:
1122           msg = EncryptedExtensions._read(buf);
1123           break;
1124         case HANDSHAKE_TYPE.FINISHED:
1125           msg = messages_Finished._read(buf);
1126           break;
1127       }
1128       if (buf.hasMoreBytes()) {
1129         throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
1130       }
1131     });
1132     if (msg === null) {
1133       throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1134     }
1135     return msg;
1136   }
1138   write(buf) {
1139     buf.writeUint8(this.TYPE_TAG);
1140     buf.writeVector24(buf => {
1141       this._write(buf);
1142     });
1143   }
1145   static _read(buf) {
1146     throw new Error('not implemented');
1147   }
1149   _write(buf) {
1150     throw new Error('not implemented');
1151   }
1153   // Some little helpers for reading a list of extensions,
1154   // which is uniformly represented as:
1155   //
1156   //   Extension extensions<8..2^16-1>;
1157   //
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);
1168       }
1169       extensions.set(ext.TYPE_TAG, ext);
1170       extensions.lastSeenExtension = ext.TYPE_TAG;
1171     });
1172     return extensions;
1173   }
1175   _writeExtensions(buf, extensions) {
1176     buf.writeVector16(buf => {
1177       extensions.forEach(ext => {
1178         ext.write(this.TYPE_TAG, buf);
1179       });
1180     });
1181   }
1185 // The ClientHello message:
1187 // struct {
1188 //   ProtocolVersion legacy_version = 0x0303;
1189 //   Random random;
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>;
1194 // } ClientHello;
1196 class messages_ClientHello extends messages_HandshakeMessage {
1198   constructor(random, sessionId, extensions) {
1199     super();
1200     this.random = random;
1201     this.sessionId = sessionId;
1202     this.extensions = extensions;
1203   }
1205   get TYPE_TAG() {
1206     return HANDSHAKE_TYPE.CLIENT_HELLO;
1207   }
1209   static _read(buf) {
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);
1214     }
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.
1221     let found = false;
1222     buf.readVector16(buf => {
1223       const cipherSuite = buf.readUint16();
1224       if (cipherSuite === TLS_AES_128_GCM_SHA256) {
1225         found = true;
1226       }
1227     });
1228     if (! found) {
1229       throw new TLSError(ALERT_DESCRIPTION.HANDSHAKE_FAILURE);
1230     }
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);
1237     }
1238     if (legacyCompressionMethods[0] !== 0x00) {
1239       throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1240     }
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);
1245     }
1246     if (extensions.get(EXTENSION_TYPE.SUPPORTED_VERSIONS).versions.indexOf(VERSION_TLS_1_3) === -1) {
1247       throw new TLSError(ALERT_DESCRIPTION.PROTOCOL_VERSION);
1248     }
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);
1253       }
1254     }
1255     return new this(random, sessionId, extensions);
1256   }
1258   _write(buf) {
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);
1265     });
1266     // A single zero byte for legacy_compression_methods
1267     buf.writeVectorBytes8(new Uint8Array(1));
1268     this._writeExtensions(buf, this.extensions);
1269   }
1273 // The ServerHello message:
1275 //  struct {
1276 //      ProtocolVersion legacy_version = 0x0303;    /* TLS v1.2 */
1277 //      Random random;
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 >;
1282 //  } ServerHello;
1284 class messages_ServerHello extends messages_HandshakeMessage {
1286   constructor(random, sessionId, extensions) {
1287     super();
1288     this.random = random;
1289     this.sessionId = sessionId;
1290     this.extensions = extensions;
1291   }
1293   get TYPE_TAG() {
1294     return HANDSHAKE_TYPE.SERVER_HELLO;
1295   }
1297   static _read(buf) {
1298     // Fixed value for legacy_version.
1299     if (buf.readUint16() !== VERSION_TLS_1_2) {
1300       throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1301     }
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);
1309     }
1310     // legacy_compression_method must be zero.
1311     if (buf.readUint8() !== 0) {
1312       throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1313     }
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);
1317     }
1318     if (extensions.get(EXTENSION_TYPE.SUPPORTED_VERSIONS).selectedVersion !== VERSION_TLS_1_3) {
1319       throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1320     }
1321     return new this(random, sessionId, extensions);
1322   }
1324   _write(buf) {
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
1331     buf.writeUint8(0);
1332     this._writeExtensions(buf, this.extensions);
1333   }
1337 // The EncryptedExtensions message:
1339 //  struct {
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) {
1348     super();
1349     this.extensions = extensions;
1350   }
1352   get TYPE_TAG() {
1353     return HANDSHAKE_TYPE.ENCRYPTED_EXTENSIONS;
1354   }
1356   static _read(buf) {
1357     const extensions = this._readExtensions(HANDSHAKE_TYPE.ENCRYPTED_EXTENSIONS, buf);
1358     return new this(extensions);
1359   }
1361   _write(buf) {
1362     this._writeExtensions(buf, this.extensions);
1363   }
1367 // The Finished message:
1369 // struct {
1370 //   opaque verify_data[Hash.length];
1371 // } Finished;
1373 class messages_Finished extends messages_HandshakeMessage {
1375   constructor(verifyData) {
1376     super();
1377     this.verifyData = verifyData;
1378   }
1380   get TYPE_TAG() {
1381     return HANDSHAKE_TYPE.FINISHED;
1382   }
1384   static _read(buf) {
1385     const verifyData = buf.readBytes(HASH_LENGTH);
1386     return new this(verifyData);
1387   }
1389   _write(buf) {
1390     buf.writeBytes(this.verifyData);
1391   }
1395 // The NewSessionTicket message:
1397 //   struct {
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) {
1410     super();
1411     this.ticketLifetime = ticketLifetime;
1412     this.ticketAgeAdd = ticketAgeAdd;
1413     this.ticketNonce = ticketNonce;
1414     this.ticket = ticket;
1415     this.extensions = extensions;
1416   }
1418   get TYPE_TAG() {
1419     return HANDSHAKE_TYPE.NEW_SESSION_TICKET;
1420   }
1422   static _read(buf) {
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);
1429     }
1430     const extensions = this._readExtensions(HANDSHAKE_TYPE.NEW_SESSION_TICKET, buf);
1431     return new this(ticketLifetime, ticketAgeAdd, ticketNonce, ticket, extensions);
1432   }
1434   _write(buf) {
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);
1440   }
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 {
1467   constructor(conn) {
1468     this.conn = conn;
1469   }
1471   async initialize() {
1472     // By default, nothing to do when entering the state.
1473   }
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);
1479   }
1481   async recvApplicationData(bytes) {
1482     throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1483   }
1485   async recvHandshakeMessage(msg) {
1486     throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1487   }
1489   async recvAlertMessage(alert) {
1490     switch (alert.description) {
1491       case ALERT_DESCRIPTION.CLOSE_NOTIFY:
1492         this.conn._closeForRecv(alert);
1493         throw alert;
1494       default:
1495         return await this.handleErrorAndRethrow(alert);
1496     }
1497   }
1499   async recvChangeCipherSpec(bytes) {
1500     throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1501   }
1503   async handleErrorAndRethrow(err) {
1504     let alert = err;
1505     if (! (alert instanceof TLSAlert)) {
1506       alert = new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
1507     }
1508     // Try to send error alert to the peer, but we may not
1509     // be able to if the outgoing connection was already closed.
1510     try {
1511       await this.conn._sendAlertMessage(alert);
1512     } catch (_) { }
1513     await this.conn._transition(ERROR, err);
1514     throw err;
1515   }
1517   async close() {
1518     const alert = new TLSCloseNotify();
1519     await this.conn._sendAlertMessage(alert);
1520     this.conn._closeForSend(alert);
1521   }
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');
1531   }
1532   async sendApplicationData(bytes) {
1533     throw new Error('uninitialized state');
1534   }
1535   async recvApplicationData(bytes) {
1536     throw new Error('uninitialized state');
1537   }
1538   async recvHandshakeMessage(msg) {
1539     throw new Error('uninitialized state');
1540   }
1541   async recvChangeCipherSpec(bytes) {
1542     throw new Error('uninitialized state');
1543   }
1544   async handleErrorAndRethrow(err) {
1545     throw err;
1546   }
1547   async close() {
1548     throw new Error('uninitialized state');
1549   }
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) {
1558     this.error = 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);
1563   }
1564   async sendApplicationData(bytes) {
1565     throw this.error;
1566   }
1567   async recvApplicationData(bytes) {
1568     throw this.error;
1569   }
1570   async recvHandshakeMessage(msg) {
1571     throw this.error;
1572   }
1573   async recvAlertMessage(err) {
1574     throw this.error;
1575   }
1576   async recvChangeCipherSpec(bytes) {
1577     throw this.error;
1578   }
1579   async handleErrorAndRethrow(err) {
1580     throw err;
1581   }
1582   async close() {
1583     throw this.error;
1584   }
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();
1594   }
1595   async sendApplicationData(bytes) {
1596     await this.conn._sendApplicationData(bytes);
1597   }
1598   async recvApplicationData(bytes) {
1599     return bytes;
1600   }
1601   async recvChangeCipherSpec(bytes) {
1602     throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1603   }
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);
1615     }
1616     if (bytes.byteLength !== 1 || bytes[0] !== 1) {
1617       throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1618     }
1619     this.conn._hasSeenChangeCipherSpec = true;
1620   }
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),
1651       [
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)]),
1655       ],
1656     );
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);
1671   }
1674 class states_CLIENT_WAIT_SH extends states_State {
1675   async initialize(sessionId) {
1676     this._sessionId = sessionId;
1677   }
1678   async recvHandshakeMessage(msg) {
1679     if (! (msg instanceof messages_ServerHello)) {
1680       throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1681     }
1682     if (! bytesAreEqual(msg.sessionId, this._sessionId)) {
1683       throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1684     }
1685     const pskExt = msg.extensions.get(EXTENSION_TYPE.PRE_SHARED_KEY);
1686     if (! pskExt) {
1687       throw new TLSError(ALERT_DESCRIPTION.MISSING_EXTENSION);
1688     }
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);
1692     }
1693     if (pskExt.selectedIdentity !== 0) {
1694       throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER);
1695     }
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);
1700   }
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);
1709     }
1710     // We do not support any EncryptedExtensions.
1711     if (msg.extensions.size !== 0) {
1712       throw new TLSError(ALERT_DESCRIPTION.UNSUPPORTED_EXTENSION);
1713     }
1714     const keyschedule = this.conn._keyschedule;
1715     const serverFinishedTranscript = keyschedule.getTranscript();
1716     await this.conn._transition(states_CLIENT_WAIT_FINISHED, serverFinishedTranscript);
1717   }
1720 class states_CLIENT_WAIT_FINISHED extends states_State {
1721   async initialize(serverFinishedTranscript) {
1722     this._serverFinishedTranscript = serverFinishedTranscript;
1723   }
1724   async recvHandshakeMessage(msg) {
1725     if (! (msg instanceof messages_Finished)) {
1726       throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1727     }
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);
1740   }
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
1747     // might send them.
1748     if (! (msg instanceof messages_NewSessionTicket)) {
1749       throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1750     }
1751   }
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);
1773     }
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);
1782     }
1783     if (pskModesExt.modes.indexOf(PSK_MODE_KE) === -1) {
1784       throw new TLSError(ALERT_DESCRIPTION.HANDSHAKE_FAILURE);
1785     }
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);
1789     }
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.
1798     }
1799     await keyschedule.verifyFinishedMAC(keyschedule.extBinderKey, pskExt.binders[pskIndex], transcript.slice(0, -pskBindersSize));
1800     await this.conn._transition(states_SERVER_NEGOTIATED, msg.sessionId, pskIndex);
1801   }
1804 class states_SERVER_NEGOTIATED extends states_MidHandshakeState {
1805   async initialize(sessionId, pskIndex) {
1806     await this.conn._sendHandshakeMessage(new messages_ServerHello(
1807       // Server random
1808       await getRandomBytes(32),
1809       sessionId,
1810       [
1811         new extensions_SupportedVersionsExtension(null, VERSION_TLS_1_3),
1812         new extensions_PreSharedKeyExtension(null, null, pskIndex),
1813       ]
1814     ));
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();
1818     }
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);
1838   }
1841 class states_SERVER_WAIT_FINISHED extends states_MidHandshakeState {
1842   async initialize(clientHandshakeTrafficSecret, clientFinishedTranscript) {
1843     this._clientHandshakeTrafficSecret = clientHandshakeTrafficSecret;
1844     this._clientFinishedTranscript = clientFinishedTranscript;
1845   }
1846   async recvHandshakeMessage(msg) {
1847     if (! (msg instanceof messages_Finished)) {
1848       throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
1849     }
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);
1855   }
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:
1879 //   UNINITIALIZED
1880 //       |
1881 //       | addPSK()
1882 //       v
1883 //   EARLY_SECRET
1884 //       |
1885 //       | addECDHE()
1886 //       v
1887 //   HANDSHAKE_SECRET
1888 //       |
1889 //       | finalize()
1890 //       v
1891 //   MASTER_SECRET
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 {
1902   constructor() {
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.
1908     this.secret = null;
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;
1915   }
1917   async addPSK(psk) {
1918     // Use the selected PSK (if any) to calculate the "early secret".
1919     if (psk === null) {
1920       psk = zeros(HASH_LENGTH);
1921     }
1922     if (this.stage !== STAGE_UNINITIALIZED) {
1923       throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
1924     }
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);
1929   }
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);
1935     }
1936     if (this.stage !== STAGE_EARLY_SECRET) {
1937       throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
1938     }
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);
1945   }
1947   async finalize() {
1948     if (this.stage !== STAGE_HANDSHAKE_SECRET) {
1949       throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
1950     }
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');
1957     this.secret = null;
1958   }
1960   addToTranscript(bytes) {
1961     this.transcript.writeBytes(bytes);
1962   }
1964   getTranscript() {
1965     return this.transcript.slice();
1966   }
1968   async deriveSecret(label, transcript = undefined) {
1969     transcript = transcript || this.getTranscript();
1970     return await hkdfExpandLabel(this.secret, label, await hash(transcript), HASH_LENGTH);
1971   }
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));
1977   }
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));
1983   }
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.
2004 //    });
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>)
2015 //    await rl.flush()
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) => {
2024 //      switch (type) {
2025 //        case RECORD_TYPE.APPLICATION_DATA:
2026 //          // do something with application data
2027 //        case RECORD_TYPE.HANDSHAKE:
2028 //          // do something with a handshake message
2029 //        default:
2030 //          // etc...
2031 //      }
2032 //    });
2041 /* eslint-disable sorting/sort-object-props */
2042 const RECORD_TYPE = {
2043   CHANGE_CIPHER_SPEC: 20,
2044   ALERT: 21,
2045   HANDSHAKE: 22,
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) {
2064     this.key = key;
2065     this.iv = iv;
2066     this.seqnum = 0;
2067   }
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);
2074   }
2076   nonce() {
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);
2085     this.seqnum += 1;
2086     if (this.seqnum > MAX_SEQUENCE_NUMBER) {
2087       throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
2088     }
2089     return nonce;
2090   }
2093 class recordlayer_EncryptionState extends recordlayer_CipherState {
2094   static async create(key) {
2095     return super.create(key, 'encrypt');
2096   }
2098   async encrypt(plaintext, additionalData) {
2099     return await encrypt(this.key, this.nonce(), plaintext, additionalData);
2100   }
2103 class recordlayer_DecryptionState extends recordlayer_CipherState {
2104   static async create(key) {
2105     return super.create(key, 'decrypt');
2106   }
2108   async decrypt(ciphertext, additionalData) {
2109     return await decrypt(this.key, this.nonce(), ciphertext, additionalData);
2110   }
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;
2124   }
2126   async setSendKey(key) {
2127     await this.flush();
2128     this._sendEncryptState = await recordlayer_EncryptionState.create(key);
2129   }
2131   async setRecvKey(key) {
2132     this._recvDecryptState = await recordlayer_DecryptionState.create(key);
2133   }
2135   async setSendError(err) {
2136     this._sendError = err;
2137   }
2139   async setRecvError(err) {
2140     this._recvError = err;
2141   }
2143   async send(type, data) {
2144     if (this._sendError !== null) {
2145       throw this._sendError;
2146     }
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);
2151     }
2152     // Flush if we're switching to a different record type.
2153     if (this._pendingRecordType && this._pendingRecordType !== type) {
2154       await this.flush();
2155     }
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) {
2159         await this.flush();
2160       }
2161     }
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);
2169     }
2170     this._pendingRecordBuf.writeBytes(data);
2171   }
2173   async flush() {
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;
2179     if (! type) {
2180       if (buf !== null) {
2181         throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR);
2182       }
2183       return;
2184     }
2185     if (this._sendError !== null) {
2186       throw this._sendError;
2187     }
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;
2196     }
2197     // Write the common header for either `TLSPlaintext` or `TLSCiphertext` record.
2198     const length = buf.tell() - RECORD_HEADER_SIZE + inflation;
2199     buf.seek(0);
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);
2208     } else {
2209       buf.incr(length);
2210     }
2211     this._pendingRecordBuf = null;
2212     this._pendingRecordType = 0;
2213     await this.sendCallback(buf.flush());
2214   }
2216   async recv(data) {
2217     if (this._recvError !== null) {
2218       throw this._recvError;
2219     }
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:
2232     //
2233     //    struct {
2234     //        ContentType type;
2235     //        ProtocolVersion legacy_record_version;
2236     //        uint16 length;
2237     //        opaque fragment[TLSPlaintext.length];
2238     //    } TLSPlaintext;
2239     //
2240     //    struct {
2241     //        ContentType opaque_type = application_data; /* 23 */
2242     //        ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */
2243     //        uint16 length;
2244     //        opaque encrypted_record[TLSCiphertext.length];
2245     //    } TLSCiphertext;
2246     //
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);
2256       }
2257     }
2258     const length = buf.readUint16();
2259     let plaintext;
2260     if (this._recvDecryptState === null || type === RECORD_TYPE.CHANGE_CIPHER_SPEC) {
2261       [type, plaintext] = await this._readPlaintextRecord(type, length, buf);
2262     } else {
2263       [type, plaintext] = await this._readEncryptedRecord(type, length, buf);
2264     }
2265     // Sanity-check that we received exactly one record.
2266     if (buf.hasMoreBytes()) {
2267       throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR);
2268     }
2269     return [type, plaintext];
2270   }
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);
2277     }
2278     return [type, buf.readBytes(length)];
2279   }
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);
2287     }
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);
2291     }
2292     // Decrypt and decode the contained `TLSInnerPlaintext` struct:
2293     //
2294     //    struct {
2295     //        opaque content[TLSPlaintext.length];
2296     //        ContentType type;
2297     //        uint8 zeros[length_of_padding];
2298     //    } TLSInnerPlaintext;
2299     //
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.
2308     let i;
2309     for (i = paddedPlaintext.byteLength - 1; i >= 0; i--) {
2310       if (paddedPlaintext[i] !== 0) {
2311         break;
2312       }
2313     }
2314     if (i < 0) {
2315       throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
2316     }
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);
2321     }
2322     return [type, paddedPlaintext.slice(0, i)];
2323   }
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.
2339 //    })
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)
2358 //      }
2359 //    })
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:
2370 //    try {
2371 //      data = await conn.recv(data);
2372 //    } catch (err) {
2373 //      if (! (err instanceof TLSCloseNotify) { throw err }
2374 //      do_something_to_cleanly_close_data_connection();
2375 //    }
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;
2396     });
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();
2403   }
2405   // Subclasses will override this with some async initialization logic.
2406   static async create(psk, pskId, sendCallback) {
2407     return new this(psk, pskId, sendCallback);
2408   }
2410   // These are the three public API methods that consumers can use
2411   // to send and receive data encrypted with TLS1.3.
2413   async send(data) {
2414     assertIsBytes(data);
2415     await this.connected;
2416     await this._synchronized(async () => {
2417       await this._state.sendApplicationData(data);
2418     });
2419   }
2421   async recv(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.
2428       switch (type) {
2429         case RECORD_TYPE.CHANGE_CIPHER_SPEC:
2430           await this._state.recvChangeCipherSpec(bytes);
2431           return null;
2432         case RECORD_TYPE.ALERT:
2433           await this._state.recvAlertMessage(TLSAlert.fromBytes(bytes));
2434           return null;
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);
2444           }
2445           do {
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;
2456           return null;
2457         default:
2458           throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE);
2459       }
2460     });
2461   }
2463   async close() {
2464     await this._synchronized(async () => {
2465       await this._state.close();
2466     });
2467   }
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.
2475   _synchronized(cb) {
2476     const nextPromise = this._lastPromise.then(() => {
2477       return cb();
2478     }).catch(async err => {
2479       if (err instanceof TLSCloseNotify) {
2480         throw err;
2481       }
2482       await this._state.handleErrorAndRethrow(err);
2483     });
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);
2487     return nextPromise;
2488   }
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();
2497   }
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();
2505   }
2507   async _sendHandshakeMessage(msg) {
2508     await this._sendHandshakeMessageBytes(msg.toBytes());
2509   }
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.
2516   }
2518   async _sendAlertMessage(err) {
2519     await this._recordlayer.send(RECORD_TYPE.ALERT, err.toBytes());
2520     await this._recordlayer.flush();
2521   }
2523   async _sendChangeCipherSpec() {
2524     await this._recordlayer.send(RECORD_TYPE.CHANGE_CIPHER_SPEC, new Uint8Array([0x01]));
2525     await this._recordlayer.flush();
2526   }
2528   async _setSendKey(key) {
2529     return await this._recordlayer.setSendKey(key);
2530   }
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);
2536     }
2537     return await this._recordlayer.setRecvKey(key);
2538   }
2540   _setConnectionSuccess() {
2541     if (this._onConnectionSuccess !== null) {
2542       this._onConnectionSuccess();
2543       this._onConnectionSuccess = null;
2544       this._onConnectionFailure = null;
2545     }
2546   }
2548   _setConnectionFailure(err) {
2549     if (this._onConnectionFailure !== null) {
2550       this._onConnectionFailure(err);
2551       this._onConnectionSuccess = null;
2552       this._onConnectionFailure = null;
2553     }
2554   }
2556   _closeForSend(alert) {
2557     this._recordlayer.setSendError(alert);
2558   }
2560   _closeForRecv(alert) {
2561     this._recordlayer.setRecvError(alert);
2562   }
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);
2569     return instance;
2570   }
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);
2577     return instance;
2578   }
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.
2586  */
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.
2598  * @private
2599  */
2602  * Private data for event wrappers.
2603  * @type {WeakMap<Event, PrivateData>}
2604  * @private
2605  */
2606 const privateData = new WeakMap();
2609  * Cache for wrapper classes.
2610  * @type {WeakMap<Object, Function>}
2611  * @private
2612  */
2613 const wrappers = new WeakMap();
2616  * Get private data.
2617  * @param {Event} event The event object to get private data.
2618  * @returns {PrivateData} The private data of the event.
2619  * @private
2620  */
2621 function pd(event) {
2622     const retv = privateData.get(event);
2623     console.assert(
2624         retv != null,
2625         "'this' is expected an Event object, but got",
2626         event
2627     );
2628     return retv
2632  * https://dom.spec.whatwg.org/#set-the-canceled-flag
2633  * @param data {PrivateData} private data.
2634  */
2635 function setCancelFlag(data) {
2636     if (data.passiveListener != null) {
2637         if (
2638             typeof console !== "undefined" &&
2639             typeof console.error === "function"
2640         ) {
2641             console.error(
2642                 "Unable to preventDefault inside passive event listener invocation.",
2643                 data.passiveListener
2644             );
2645         }
2646         return
2647     }
2648     if (!data.event.cancelable) {
2649         return
2650     }
2652     data.canceled = true;
2653     if (typeof data.event.preventDefault === "function") {
2654         data.event.preventDefault();
2655     }
2659  * @see https://dom.spec.whatwg.org/#interface-event
2660  * @private
2661  */
2663  * The event wrapper.
2664  * @constructor
2665  * @param {EventTarget} eventTarget The event target of this dispatching.
2666  * @param {Event|{type:string}} event The original event to wrap.
2667  */
2668 function Event(eventTarget, event) {
2669     privateData.set(this, {
2670         eventTarget,
2671         event,
2672         eventPhase: 2,
2673         currentTarget: eventTarget,
2674         canceled: false,
2675         stopped: false,
2676         immediateStopped: false,
2677         passiveListener: null,
2678         timeStamp: event.timeStamp || Date.now(),
2679     });
2681     // https://heycam.github.io/webidl/#Unforgeable
2682     Object.defineProperty(this, "isTrusted", { value: false, enumerable: true });
2684     // Define accessors
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));
2690         }
2691     }
2694 // Should be enumerable, but class methods are not enumerable.
2695 Event.prototype = {
2696     /**
2697      * The type of this event.
2698      * @type {string}
2699      */
2700     get type() {
2701         return pd(this).event.type
2702     },
2704     /**
2705      * The target of this event.
2706      * @type {EventTarget}
2707      */
2708     get target() {
2709         return pd(this).eventTarget
2710     },
2712     /**
2713      * The target of this event.
2714      * @type {EventTarget}
2715      */
2716     get currentTarget() {
2717         return pd(this).currentTarget
2718     },
2720     /**
2721      * @returns {EventTarget[]} The composed path of this event.
2722      */
2723     composedPath() {
2724         const currentTarget = pd(this).currentTarget;
2725         if (currentTarget == null) {
2726             return []
2727         }
2728         return [currentTarget]
2729     },
2731     /**
2732      * Constant of NONE.
2733      * @type {number}
2734      */
2735     get NONE() {
2736         return 0
2737     },
2739     /**
2740      * Constant of CAPTURING_PHASE.
2741      * @type {number}
2742      */
2743     get CAPTURING_PHASE() {
2744         return 1
2745     },
2747     /**
2748      * Constant of AT_TARGET.
2749      * @type {number}
2750      */
2751     get AT_TARGET() {
2752         return 2
2753     },
2755     /**
2756      * Constant of BUBBLING_PHASE.
2757      * @type {number}
2758      */
2759     get BUBBLING_PHASE() {
2760         return 3
2761     },
2763     /**
2764      * The target of this event.
2765      * @type {number}
2766      */
2767     get eventPhase() {
2768         return pd(this).eventPhase
2769     },
2771     /**
2772      * Stop event bubbling.
2773      * @returns {void}
2774      */
2775     stopPropagation() {
2776         const data = pd(this);
2778         data.stopped = true;
2779         if (typeof data.event.stopPropagation === "function") {
2780             data.event.stopPropagation();
2781         }
2782     },
2784     /**
2785      * Stop event bubbling.
2786      * @returns {void}
2787      */
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();
2795         }
2796     },
2798     /**
2799      * The flag to be bubbling.
2800      * @type {boolean}
2801      */
2802     get bubbles() {
2803         return Boolean(pd(this).event.bubbles)
2804     },
2806     /**
2807      * The flag to be cancelable.
2808      * @type {boolean}
2809      */
2810     get cancelable() {
2811         return Boolean(pd(this).event.cancelable)
2812     },
2814     /**
2815      * Cancel this event.
2816      * @returns {void}
2817      */
2818     preventDefault() {
2819         setCancelFlag(pd(this));
2820     },
2822     /**
2823      * The flag to indicate cancellation state.
2824      * @type {boolean}
2825      */
2826     get defaultPrevented() {
2827         return pd(this).canceled
2828     },
2830     /**
2831      * The flag to be composed.
2832      * @type {boolean}
2833      */
2834     get composed() {
2835         return Boolean(pd(this).event.composed)
2836     },
2838     /**
2839      * The unix time of this event.
2840      * @type {number}
2841      */
2842     get timeStamp() {
2843         return pd(this).timeStamp
2844     },
2846     /**
2847      * The target of this event.
2848      * @type {EventTarget}
2849      * @deprecated
2850      */
2851     get srcElement() {
2852         return pd(this).eventTarget
2853     },
2855     /**
2856      * The flag to stop event bubbling.
2857      * @type {boolean}
2858      * @deprecated
2859      */
2860     get cancelBubble() {
2861         return pd(this).stopped
2862     },
2863     set cancelBubble(value) {
2864         if (!value) {
2865             return
2866         }
2867         const data = pd(this);
2869         data.stopped = true;
2870         if (typeof data.event.cancelBubble === "boolean") {
2871             data.event.cancelBubble = true;
2872         }
2873     },
2875     /**
2876      * The flag to indicate cancellation state.
2877      * @type {boolean}
2878      * @deprecated
2879      */
2880     get returnValue() {
2881         return !pd(this).canceled
2882     },
2883     set returnValue(value) {
2884         if (!value) {
2885             setCancelFlag(pd(this));
2886         }
2887     },
2889     /**
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.
2894      * @deprecated
2895      */
2896     initEvent() {
2897         // Do nothing.
2898     },
2901 // `constructor` is not enumerable.
2902 Object.defineProperty(Event.prototype, "constructor", {
2903     value: Event,
2904     configurable: true,
2905     writable: true,
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.
2920  * @private
2921  */
2922 function defineRedirectDescriptor(key) {
2923     return {
2924         get() {
2925             return pd(this).event[key]
2926         },
2927         set(value) {
2928             pd(this).event[key] = value;
2929         },
2930         configurable: true,
2931         enumerable: true,
2932     }
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.
2939  * @private
2940  */
2941 function defineCallDescriptor(key) {
2942     return {
2943         value() {
2944             const event = pd(this).event;
2945             return event[key].apply(event, arguments)
2946         },
2947         configurable: true,
2948         enumerable: true,
2949     }
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.
2957  * @private
2958  */
2959 function defineWrapper(BaseEvent, proto) {
2960     const keys = Object.keys(proto);
2961     if (keys.length === 0) {
2962         return BaseEvent
2963     }
2965     /** CustomEvent */
2966     function CustomEvent(eventTarget, event) {
2967         BaseEvent.call(this, eventTarget, event);
2968     }
2970     CustomEvent.prototype = Object.create(BaseEvent.prototype, {
2971         constructor: { value: CustomEvent, configurable: true, writable: true },
2972     });
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,
2982                 key,
2983                 isFunc
2984                     ? defineCallDescriptor(key)
2985                     : defineRedirectDescriptor(key)
2986             );
2987         }
2988     }
2990     return CustomEvent
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.
2997  * @private
2998  */
2999 function getWrapper(proto) {
3000     if (proto == null || proto === Object.prototype) {
3001         return Event
3002     }
3004     let wrapper = wrappers.get(proto);
3005     if (wrapper == null) {
3006         wrapper = defineWrapper(getWrapper(Object.getPrototypeOf(proto)), proto);
3007         wrappers.set(proto, wrapper);
3008     }
3009     return 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.
3017  * @private
3018  */
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.
3028  * @private
3029  */
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.
3038  * @returns {void}
3039  * @private
3040  */
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.
3049  * @returns {void}
3050  * @private
3051  */
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.
3060  * @returns {void}
3061  * @private
3062  */
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
3074  * @private
3075  */
3078  * @type {WeakMap<object, Map<string, ListenerNode>>}
3079  * @private
3080  */
3081 const listenersMap = new WeakMap();
3083 // Listener types
3084 const CAPTURE = 1;
3085 const BUBBLE = 2;
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.
3092  */
3093 function isObject(x) {
3094     return x !== null && typeof x === "object" //eslint-disable-line no-restricted-syntax
3098  * Get listeners.
3099  * @param {EventTarget} eventTarget The event target to get.
3100  * @returns {Map<string, ListenerNode>} The listeners.
3101  * @private
3102  */
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."
3108         )
3109     }
3110     return listeners
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.
3117  * @private
3118  */
3119 function defineEventAttributeDescriptor(eventName) {
3120     return {
3121         get() {
3122             const listeners = getListeners(this);
3123             let node = listeners.get(eventName);
3124             while (node != null) {
3125                 if (node.listenerType === ATTRIBUTE) {
3126                     return node.listener
3127                 }
3128                 node = node.next;
3129             }
3130             return null
3131         },
3133         set(listener) {
3134             if (typeof listener !== "function" && !isObject(listener)) {
3135                 listener = null; // eslint-disable-line no-param-reassign
3136             }
3137             const listeners = getListeners(this);
3139             // Traverse to the tail while removing old value.
3140             let prev = null;
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);
3149                     } else {
3150                         listeners.delete(eventName);
3151                     }
3152                 } else {
3153                     prev = node;
3154                 }
3156                 node = node.next;
3157             }
3159             // Add new value.
3160             if (listener !== null) {
3161                 const newNode = {
3162                     listener,
3163                     listenerType: ATTRIBUTE,
3164                     passive: false,
3165                     once: false,
3166                     next: null,
3167                 };
3168                 if (prev === null) {
3169                     listeners.set(eventName, newNode);
3170                 } else {
3171                     prev.next = newNode;
3172                 }
3173             }
3174         },
3175         configurable: true,
3176         enumerable: true,
3177     }
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.
3184  * @returns {void}
3185  */
3186 function defineEventAttribute(eventTargetPrototype, eventName) {
3187     Object.defineProperty(
3188         eventTargetPrototype,
3189         `on${eventName}`,
3190         defineEventAttributeDescriptor(eventName)
3191     );
3195  * Define a custom EventTarget with event attributes.
3196  * @param {string[]} eventNames Event names for event attributes.
3197  * @returns {EventTarget} The custom EventTarget.
3198  * @private
3199  */
3200 function defineCustomEventTarget(eventNames) {
3201     /** CustomEventTarget */
3202     function CustomEventTarget() {
3203         EventTarget.call(this);
3204     }
3206     CustomEventTarget.prototype = Object.create(EventTarget.prototype, {
3207         constructor: {
3208             value: CustomEventTarget,
3209             configurable: true,
3210             writable: true,
3211         },
3212     });
3214     for (let i = 0; i < eventNames.length; ++i) {
3215         defineEventAttribute(CustomEventTarget.prototype, eventNames[i]);
3216     }
3218     return CustomEventTarget
3222  * EventTarget.
3224  * - This is constructor if no arguments.
3225  * - This is a function which returns a CustomEventTarget constructor if there are arguments.
3227  * For example:
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"]) {}
3233  */
3234 function EventTarget() {
3235     /*eslint-disable consistent-return */
3236     if (this instanceof EventTarget) {
3237         listenersMap.set(this, new Map());
3238         return
3239     }
3240     if (arguments.length === 1 && Array.isArray(arguments[0])) {
3241         return defineCustomEventTarget(arguments[0])
3242     }
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];
3247         }
3248         return defineCustomEventTarget(types)
3249     }
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 = {
3256     /**
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.
3261      * @returns {void}
3262      */
3263     addEventListener(eventName, listener, options) {
3264         if (listener == null) {
3265             return
3266         }
3267         if (typeof listener !== "function" && !isObject(listener)) {
3268             throw new TypeError("'listener' should be a function or an object.")
3269         }
3271         const listeners = getListeners(this);
3272         const optionsIsObj = isObject(options);
3273         const capture = optionsIsObj
3274             ? Boolean(options.capture)
3275             : Boolean(options);
3276         const listenerType = capture ? CAPTURE : BUBBLE;
3277         const newNode = {
3278             listener,
3279             listenerType,
3280             passive: optionsIsObj && Boolean(options.passive),
3281             once: optionsIsObj && Boolean(options.once),
3282             next: null,
3283         };
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);
3289             return
3290         }
3292         // Traverse to the tail while checking duplication..
3293         let prev = null;
3294         while (node != null) {
3295             if (
3296                 node.listener === listener &&
3297                 node.listenerType === listenerType
3298             ) {
3299                 // Should ignore duplication.
3300                 return
3301             }
3302             prev = node;
3303             node = node.next;
3304         }
3306         // Add it.
3307         prev.next = newNode;
3308     },
3310     /**
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.
3315      * @returns {void}
3316      */
3317     removeEventListener(eventName, listener, options) {
3318         if (listener == null) {
3319             return
3320         }
3322         const listeners = getListeners(this);
3323         const capture = isObject(options)
3324             ? Boolean(options.capture)
3325             : Boolean(options);
3326         const listenerType = capture ? CAPTURE : BUBBLE;
3328         let prev = null;
3329         let node = listeners.get(eventName);
3330         while (node != null) {
3331             if (
3332                 node.listener === listener &&
3333                 node.listenerType === listenerType
3334             ) {
3335                 if (prev !== null) {
3336                     prev.next = node.next;
3337                 } else if (node.next !== null) {
3338                     listeners.set(eventName, node.next);
3339                 } else {
3340                     listeners.delete(eventName);
3341                 }
3342                 return
3343             }
3345             prev = node;
3346             node = node.next;
3347         }
3348     },
3350     /**
3351      * Dispatch a given event.
3352      * @param {Event|{type:string}} event The event to dispatch.
3353      * @returns {boolean} `false` if canceled.
3354      */
3355     dispatchEvent(event) {
3356         if (event == null || typeof event.type !== "string") {
3357             throw new TypeError('"event.type" should be a string.')
3358         }
3360         // If listeners aren't registered, terminate.
3361         const listeners = getListeners(this);
3362         const eventName = event.type;
3363         let node = listeners.get(eventName);
3364         if (node == null) {
3365             return true
3366         }
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.
3373         let prev = null;
3374         while (node != null) {
3375             // Remove this listener if it's once
3376             if (node.once) {
3377                 if (prev !== null) {
3378                     prev.next = node.next;
3379                 } else if (node.next !== null) {
3380                     listeners.set(eventName, node.next);
3381                 } else {
3382                     listeners.delete(eventName);
3383                 }
3384             } else {
3385                 prev = node;
3386             }
3388             // Call this listener
3389             setPassiveListener(
3390                 wrappedEvent,
3391                 node.passive ? node.listener : null
3392             );
3393             if (typeof node.listener === "function") {
3394                 try {
3395                     node.listener.call(this, wrappedEvent);
3396                 } catch (err) {
3397                     if (
3398                         typeof console !== "undefined" &&
3399                         typeof console.error === "function"
3400                     ) {
3401                         console.error(err);
3402                     }
3403                 }
3404             } else if (
3405                 node.listenerType !== ATTRIBUTE &&
3406                 typeof node.listener.handleEvent === "function"
3407             ) {
3408                 node.listener.handleEvent(wrappedEvent);
3409             }
3411             // Break if `event.stopImmediatePropagation` was called.
3412             if (isStopped(wrappedEvent)) {
3413                 break
3414             }
3416             node = node.next;
3417         }
3418         setPassiveListener(wrappedEvent, null);
3419         setEventPhase(wrappedEvent, 0);
3420         setCurrentTarget(wrappedEvent, null);
3422         return !wrappedEvent.defaultPrevented
3423     },
3426 // `constructor` is not enumerable.
3427 Object.defineProperty(EventTarget.prototype, "constructor", {
3428     value: EventTarget,
3429     configurable: true,
3430     writable: true,
3433 // Ensure `eventTarget instanceof window.EventTarget` is `true`.
3434 if (
3435     typeof window !== "undefined" &&
3436     typeof window.EventTarget !== "undefined"
3437 ) {
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) {
3466     super();
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();
3474   }
3476   /**
3477    * Create a new pairing channel.
3478    *
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.
3482    *
3483    * @returns Promise<PairingChannel>
3484    */
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);
3490   }
3492   /**
3493    * Connect to an existing pairing channel.
3494    *
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).
3498    *
3499    * @returns Promise<PairingChannel>
3500    */
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);
3506   }
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
3512       let stopListening;
3513       const onConnectionError = async () => {
3514         stopListening();
3515         reject(new Error('Error while creating the pairing channel'));
3516       };
3517       const onFirstMessage = async event => {
3518         stopListening();
3519         try {
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));
3529           });
3530           const instance = new this(channelId, psk, socket, connection);
3531           resolve(instance);
3532         } catch (err) {
3533           reject(err);
3534         }
3535       };
3536       stopListening = () => {
3537         socket.removeEventListener('close', onConnectionError);
3538         socket.removeEventListener('error', onConnectionError);
3539         socket.removeEventListener('message', onFirstMessage);
3540       };
3541       socket.addEventListener('close', onConnectionError);
3542       socket.addEventListener('error', onConnectionError);
3543       socket.addEventListener('message', onFirstMessage);
3544     });
3545   }
3547   _setupListeners() {
3548     this._socket.addEventListener('message', async event => {
3549       try {
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', {
3557             detail: {
3558               data,
3559               sender: channelServerEnvelope.sender,
3560             },
3561           }));
3562         }
3563       } catch (error) {
3564         let event;
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) {
3571             this._shutdown();
3572           }
3573           event = new CustomEvent('close');
3574         } else {
3575           event = new CustomEvent('error', {
3576             detail: {
3577               error,
3578             }
3579           });
3580         }
3581         this.dispatchEvent(event);
3582       }
3583     });
3584     // Relay the WebSocket events.
3585     this._socket.addEventListener('error', () => {
3586       this._shutdown();
3587       // The dispatched event that we receive has no useful information.
3588       this.dispatchEvent(new CustomEvent('error', {
3589         detail: {
3590           error: new Error('WebSocket error.'),
3591         },
3592       }));
3593     });
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', () => {
3597       this._shutdown();
3598       if (! this._peerClosed) {
3599         this.dispatchEvent(new CustomEvent('error', {
3600           detail: {
3601             error: new Error('WebSocket unexpectedly closed'),
3602           }
3603         }));
3604       }
3605     });
3606   }
3608   /**
3609    * @param {Object} data
3610    */
3611   async send(data) {
3612     const payload = utf8ToBytes(JSON.stringify(data));
3613     await this._connection.send(payload);
3614   }
3616   async close() {
3617     this._selfClosed = true;
3618     await this._connection.close();
3619     try {
3620       // Ensure all queued bytes have been sent before closing the connection.
3621       let tries = 0;
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.');
3625         }
3626         await new Promise(res => setTimeout(res, CLOSE_FLUSH_BUFFER_INTERVAL_MS));
3627       }
3628     } finally {
3629       // If the peer hasn't closed, we might still receive some data.
3630       if (this._peerClosed) {
3631         this._shutdown();
3632       }
3633     }
3634   }
3636   _shutdown() {
3637     if (this._socket) {
3638       this._socket.close();
3639       this._socket = null;
3640       this._connection = null;
3641     }
3642   }
3644   get closed() {
3645     return (! this._socket) || (this._socket.readyState === 3);
3646   }
3648   get channelId() {
3649     return this._channelId;
3650   }
3652   get channelKey() {
3653     return this._channelKey;
3654   }
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,
3690   zeros: zeros,
3694 /***/ })
3695 /******/ ])["PairingChannel"];