FxAccountsPairingChannel.sys.mjs (115421B)
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 */ 20 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. 24 25 import { setTimeout } from "resource://gre/modules/Timer.sys.mjs"; 26 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; 31 32 export var FxAccountsPairingChannel = 33 /******/ (function(modules) { // webpackBootstrap 34 /******/ // The module cache 35 /******/ var installedModules = {}; 36 /******/ 37 /******/ // The require function 38 /******/ function __webpack_require__(moduleId) { 39 /******/ 40 /******/ // Check if module is in cache 41 /******/ if(installedModules[moduleId]) { 42 /******/ return installedModules[moduleId].exports; 43 /******/ } 44 /******/ // Create a new module (and put it into the cache) 45 /******/ var module = installedModules[moduleId] = { 46 /******/ i: moduleId, 47 /******/ l: false, 48 /******/ exports: {} 49 /******/ }; 50 /******/ 51 /******/ // Execute the module function 52 /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 53 /******/ 54 /******/ // Flag the module as loaded 55 /******/ module.l = true; 56 /******/ 57 /******/ // Return the exports of the module 58 /******/ return module.exports; 59 /******/ } 60 /******/ 61 /******/ 62 /******/ // expose the modules object (__webpack_modules__) 63 /******/ __webpack_require__.m = modules; 64 /******/ 65 /******/ // expose the module cache 66 /******/ __webpack_require__.c = installedModules; 67 /******/ 68 /******/ // define getter function for harmony exports 69 /******/ __webpack_require__.d = function(exports, name, getter) { 70 /******/ if(!__webpack_require__.o(exports, name)) { 71 /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 72 /******/ } 73 /******/ }; 74 /******/ 75 /******/ // define __esModule on exports 76 /******/ __webpack_require__.r = function(exports) { 77 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 78 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 79 /******/ } 80 /******/ Object.defineProperty(exports, '__esModule', { value: true }); 81 /******/ }; 82 /******/ 83 /******/ // create a fake namespace object 84 /******/ // mode & 1: value is a module id, require it 85 /******/ // mode & 2: merge all properties of value into the ns 86 /******/ // mode & 4: return value when already ns object 87 /******/ // mode & 8|1: behave like require 88 /******/ __webpack_require__.t = function(value, mode) { 89 /******/ if(mode & 1) value = __webpack_require__(value); 90 /******/ if(mode & 8) return value; 91 /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 92 /******/ var ns = Object.create(null); 93 /******/ __webpack_require__.r(ns); 94 /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 95 /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 96 /******/ return ns; 97 /******/ }; 98 /******/ 99 /******/ // getDefaultExport function for compatibility with non-harmony modules 100 /******/ __webpack_require__.n = function(module) { 101 /******/ var getter = module && module.__esModule ? 102 /******/ function getDefault() { return module['default']; } : 103 /******/ function getModuleExports() { return module; }; 104 /******/ __webpack_require__.d(getter, 'a', getter); 105 /******/ return getter; 106 /******/ }; 107 /******/ 108 /******/ // Object.prototype.hasOwnProperty.call 109 /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 110 /******/ 111 /******/ // __webpack_public_path__ 112 /******/ __webpack_require__.p = ""; 113 /******/ 114 /******/ 115 /******/ // Load entry module and return exports 116 /******/ return __webpack_require__(__webpack_require__.s = 0); 117 /******/ }) 118 /************************************************************************/ 119 /******/ ([ 120 /* 0 */ 121 /***/ (function(module, __webpack_exports__, __webpack_require__) { 122 123 "use strict"; 124 // ESM COMPAT FLAG 125 __webpack_require__.r(__webpack_exports__); 126 127 // EXPORTS 128 __webpack_require__.d(__webpack_exports__, "PairingChannel", function() { return /* binding */ src_PairingChannel; }); 129 __webpack_require__.d(__webpack_exports__, "base64urlToBytes", function() { return /* reexport */ base64urlToBytes; }); 130 __webpack_require__.d(__webpack_exports__, "bytesToBase64url", function() { return /* reexport */ bytesToBase64url; }); 131 __webpack_require__.d(__webpack_exports__, "bytesToHex", function() { return /* reexport */ bytesToHex; }); 132 __webpack_require__.d(__webpack_exports__, "bytesToUtf8", function() { return /* reexport */ bytesToUtf8; }); 133 __webpack_require__.d(__webpack_exports__, "hexToBytes", function() { return /* reexport */ hexToBytes; }); 134 __webpack_require__.d(__webpack_exports__, "TLSCloseNotify", function() { return /* reexport */ TLSCloseNotify; }); 135 __webpack_require__.d(__webpack_exports__, "TLSError", function() { return /* reexport */ TLSError; }); 136 __webpack_require__.d(__webpack_exports__, "utf8ToBytes", function() { return /* reexport */ utf8ToBytes; }); 137 __webpack_require__.d(__webpack_exports__, "_internals", function() { return /* binding */ _internals; }); 138 139 // CONCATENATED MODULE: ./src/alerts.js 140 /* This Source Code Form is subject to the terms of the Mozilla Public 141 * License, v. 2.0. If a copy of the MPL was not distributed with this 142 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 143 144 /* eslint-disable sorting/sort-object-props */ 145 const ALERT_LEVEL = { 146 WARNING: 1, 147 FATAL: 2 148 }; 149 150 const ALERT_DESCRIPTION = { 151 CLOSE_NOTIFY: 0, 152 UNEXPECTED_MESSAGE: 10, 153 BAD_RECORD_MAC: 20, 154 RECORD_OVERFLOW: 22, 155 HANDSHAKE_FAILURE: 40, 156 ILLEGAL_PARAMETER: 47, 157 DECODE_ERROR: 50, 158 DECRYPT_ERROR: 51, 159 PROTOCOL_VERSION: 70, 160 INTERNAL_ERROR: 80, 161 MISSING_EXTENSION: 109, 162 UNSUPPORTED_EXTENSION: 110, 163 UNKNOWN_PSK_IDENTITY: 115, 164 NO_APPLICATION_PROTOCOL: 120, 165 }; 166 /* eslint-enable sorting/sort-object-props */ 167 168 function alertTypeToName(type) { 169 for (const name in ALERT_DESCRIPTION) { 170 if (ALERT_DESCRIPTION[name] === type) { 171 return `${name} (${type})`; 172 } 173 } 174 return `UNKNOWN (${type})`; 175 } 176 177 class TLSAlert extends Error { 178 constructor(description, level) { 179 super(`TLS Alert: ${alertTypeToName(description)}`); 180 this.description = description; 181 this.level = level; 182 } 183 184 static fromBytes(bytes) { 185 if (bytes.byteLength !== 2) { 186 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 187 } 188 switch (bytes[1]) { 189 case ALERT_DESCRIPTION.CLOSE_NOTIFY: 190 if (bytes[0] !== ALERT_LEVEL.WARNING) { 191 // Close notifications should be fatal. 192 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 193 } 194 return new TLSCloseNotify(); 195 default: 196 return new TLSError(bytes[1]); 197 } 198 } 199 200 toBytes() { 201 return new Uint8Array([this.level, this.description]); 202 } 203 } 204 205 class TLSCloseNotify extends TLSAlert { 206 constructor() { 207 super(ALERT_DESCRIPTION.CLOSE_NOTIFY, ALERT_LEVEL.WARNING); 208 } 209 } 210 211 class TLSError extends TLSAlert { 212 constructor(description = ALERT_DESCRIPTION.INTERNAL_ERROR) { 213 super(description, ALERT_LEVEL.FATAL); 214 } 215 } 216 217 // CONCATENATED MODULE: ./src/utils.js 218 /* This Source Code Form is subject to the terms of the Mozilla Public 219 * License, v. 2.0. If a copy of the MPL was not distributed with this 220 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 221 222 223 224 // 225 // Various low-level utility functions. 226 // 227 // These are mostly conveniences for working with Uint8Arrays as 228 // the primitive "bytes" type. 229 // 230 231 const UTF8_ENCODER = new TextEncoder(); 232 const UTF8_DECODER = new TextDecoder(); 233 234 function noop() {} 235 236 function assert(cond, msg) { 237 if (! cond) { 238 throw new Error('assert failed: ' + msg); 239 } 240 } 241 242 function assertIsBytes(value, msg = 'value must be a Uint8Array') { 243 // Using `value instanceof Uint8Array` seems to fail in Firefox chrome code 244 // for inscrutable reasons, so we do a less direct check. 245 assert(ArrayBuffer.isView(value), msg); 246 assert(value.BYTES_PER_ELEMENT === 1, msg); 247 return value; 248 } 249 250 const EMPTY = new Uint8Array(0); 251 252 function zeros(n) { 253 return new Uint8Array(n); 254 } 255 256 function arrayToBytes(value) { 257 return new Uint8Array(value); 258 } 259 260 function bytesToHex(bytes) { 261 return Array.prototype.map.call(bytes, byte => { 262 let s = byte.toString(16); 263 if (s.length === 1) { 264 s = '0' + s; 265 } 266 return s; 267 }).join(''); 268 } 269 270 function hexToBytes(hexstr) { 271 assert(hexstr.length % 2 === 0, 'hexstr.length must be even'); 272 return new Uint8Array(Array.prototype.map.call(hexstr, (c, n) => { 273 if (n % 2 === 1) { 274 return hexstr[n - 1] + c; 275 } else { 276 return ''; 277 } 278 }).filter(s => { 279 return !! s; 280 }).map(s => { 281 return parseInt(s, 16); 282 })); 283 } 284 285 function bytesToUtf8(bytes) { 286 return UTF8_DECODER.decode(bytes); 287 } 288 289 function utf8ToBytes(str) { 290 return UTF8_ENCODER.encode(str); 291 } 292 293 function bytesToBase64url(bytes) { 294 // XXX TODO: try to use something constant-time, in case calling code 295 // uses it to encode secrets? 296 const charCodes = String.fromCharCode.apply(String, bytes); 297 return btoa(charCodes).replace(/\+/g, '-').replace(/\//g, '_'); 298 } 299 300 function base64urlToBytes(str) { 301 // XXX TODO: try to use something constant-time, in case calling code 302 // uses it to decode secrets? 303 str = atob(str.replace(/-/g, '+').replace(/_/g, '/')); 304 const bytes = new Uint8Array(str.length); 305 for (let i = 0; i < str.length; i++) { 306 bytes[i] = str.charCodeAt(i); 307 } 308 return bytes; 309 } 310 311 function bytesAreEqual(v1, v2) { 312 assertIsBytes(v1); 313 assertIsBytes(v2); 314 if (v1.length !== v2.length) { 315 return false; 316 } 317 for (let i = 0; i < v1.length; i++) { 318 if (v1[i] !== v2[i]) { 319 return false; 320 } 321 } 322 return true; 323 } 324 325 // The `BufferReader` and `BufferWriter` classes are helpers for dealing with the 326 // binary struct format that's used for various TLS message. Think of them as a 327 // buffer with a pointer to the "current position" and a bunch of helper methods 328 // to read/write structured data and advance said pointer. 329 330 class utils_BufferWithPointer { 331 constructor(buf) { 332 this._buffer = buf; 333 this._dataview = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); 334 this._pos = 0; 335 } 336 337 length() { 338 return this._buffer.byteLength; 339 } 340 341 tell() { 342 return this._pos; 343 } 344 345 seek(pos) { 346 if (pos < 0) { 347 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 348 } 349 if (pos > this.length()) { 350 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 351 } 352 this._pos = pos; 353 } 354 355 incr(offset) { 356 this.seek(this._pos + offset); 357 } 358 } 359 360 // The `BufferReader` class helps you read structured data from a byte array. 361 // It offers methods for reading both primitive values, and the variable-length 362 // vector structures defined in https://tools.ietf.org/html/rfc8446#section-3.4. 363 // 364 // Such vectors are represented as a length followed by the concatenated 365 // bytes of each item, and the size of the length field is determined by 366 // the maximum allowed number of bytes in the vector. For example 367 // to read a vector that may contain up to 65535 bytes, use `readVector16`. 368 // 369 // To read a variable-length vector of between 1 and 100 uint16 values, 370 // defined in the RFC like this: 371 // 372 // uint16 items<2..200>; 373 // 374 // You would do something like this: 375 // 376 // const items = [] 377 // buf.readVector8(buf => { 378 // items.push(buf.readUint16()) 379 // }) 380 // 381 // The various `read` will throw `DECODE_ERROR` if you attempt to read path 382 // the end of the buffer, or past the end of a variable-length list. 383 // 384 class utils_BufferReader extends utils_BufferWithPointer { 385 386 hasMoreBytes() { 387 return this.tell() < this.length(); 388 } 389 390 readBytes(length) { 391 // This avoids copies by returning a view onto the existing buffer. 392 const start = this._buffer.byteOffset + this.tell(); 393 this.incr(length); 394 return new Uint8Array(this._buffer.buffer, start, length); 395 } 396 397 _rangeErrorToAlert(cb) { 398 try { 399 return cb(this); 400 } catch (err) { 401 if (err instanceof RangeError) { 402 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 403 } 404 throw err; 405 } 406 } 407 408 readUint8() { 409 return this._rangeErrorToAlert(() => { 410 const n = this._dataview.getUint8(this._pos); 411 this.incr(1); 412 return n; 413 }); 414 } 415 416 readUint16() { 417 return this._rangeErrorToAlert(() => { 418 const n = this._dataview.getUint16(this._pos); 419 this.incr(2); 420 return n; 421 }); 422 } 423 424 readUint24() { 425 return this._rangeErrorToAlert(() => { 426 let n = this._dataview.getUint16(this._pos); 427 n = (n << 8) | this._dataview.getUint8(this._pos + 2); 428 this.incr(3); 429 return n; 430 }); 431 } 432 433 readUint32() { 434 return this._rangeErrorToAlert(() => { 435 const n = this._dataview.getUint32(this._pos); 436 this.incr(4); 437 return n; 438 }); 439 } 440 441 _readVector(length, cb) { 442 const contentsBuf = new utils_BufferReader(this.readBytes(length)); 443 const expectedEnd = this.tell(); 444 // Keep calling the callback until we've consumed the expected number of bytes. 445 let n = 0; 446 while (contentsBuf.hasMoreBytes()) { 447 const prevPos = contentsBuf.tell(); 448 cb(contentsBuf, n); 449 // Check that the callback made forward progress, otherwise we'll infinite loop. 450 if (contentsBuf.tell() <= prevPos) { 451 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 452 } 453 n += 1; 454 } 455 // Check that the callback correctly consumed the vector's entire contents. 456 if (this.tell() !== expectedEnd) { 457 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 458 } 459 } 460 461 readVector8(cb) { 462 const length = this.readUint8(); 463 return this._readVector(length, cb); 464 } 465 466 readVector16(cb) { 467 const length = this.readUint16(); 468 return this._readVector(length, cb); 469 } 470 471 readVector24(cb) { 472 const length = this.readUint24(); 473 return this._readVector(length, cb); 474 } 475 476 readVectorBytes8() { 477 return this.readBytes(this.readUint8()); 478 } 479 480 readVectorBytes16() { 481 return this.readBytes(this.readUint16()); 482 } 483 484 readVectorBytes24() { 485 return this.readBytes(this.readUint24()); 486 } 487 } 488 489 490 class utils_BufferWriter extends utils_BufferWithPointer { 491 constructor(size = 1024) { 492 super(new Uint8Array(size)); 493 } 494 495 _maybeGrow(n) { 496 const curSize = this._buffer.byteLength; 497 const newPos = this._pos + n; 498 const shortfall = newPos - curSize; 499 if (shortfall > 0) { 500 // Classic grow-by-doubling, up to 4kB max increment. 501 // This formula was not arrived at by any particular science. 502 const incr = Math.min(curSize, 4 * 1024); 503 const newbuf = new Uint8Array(curSize + Math.ceil(shortfall / incr) * incr); 504 newbuf.set(this._buffer, 0); 505 this._buffer = newbuf; 506 this._dataview = new DataView(newbuf.buffer, newbuf.byteOffset, newbuf.byteLength); 507 } 508 } 509 510 slice(start = 0, end = this.tell()) { 511 if (end < 0) { 512 end = this.tell() + end; 513 } 514 if (start < 0) { 515 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 516 } 517 if (end < 0) { 518 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 519 } 520 if (end > this.length()) { 521 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 522 } 523 return this._buffer.slice(start, end); 524 } 525 526 flush() { 527 const slice = this.slice(); 528 this.seek(0); 529 return slice; 530 } 531 532 writeBytes(data) { 533 this._maybeGrow(data.byteLength); 534 this._buffer.set(data, this.tell()); 535 this.incr(data.byteLength); 536 } 537 538 writeUint8(n) { 539 this._maybeGrow(1); 540 this._dataview.setUint8(this._pos, n); 541 this.incr(1); 542 } 543 544 writeUint16(n) { 545 this._maybeGrow(2); 546 this._dataview.setUint16(this._pos, n); 547 this.incr(2); 548 } 549 550 writeUint24(n) { 551 this._maybeGrow(3); 552 this._dataview.setUint16(this._pos, n >> 8); 553 this._dataview.setUint8(this._pos + 2, n & 0xFF); 554 this.incr(3); 555 } 556 557 writeUint32(n) { 558 this._maybeGrow(4); 559 this._dataview.setUint32(this._pos, n); 560 this.incr(4); 561 } 562 563 // These are helpers for writing the variable-length vector structure 564 // defined in https://tools.ietf.org/html/rfc8446#section-3.4. 565 // 566 // Such vectors are represented as a length followed by the concatenated 567 // bytes of each item, and the size of the length field is determined by 568 // the maximum allowed size of the vector. For example to write a vector 569 // that may contain up to 65535 bytes, use `writeVector16`. 570 // 571 // To write a variable-length vector of between 1 and 100 uint16 values, 572 // defined in the RFC like this: 573 // 574 // uint16 items<2..200>; 575 // 576 // You would do something like this: 577 // 578 // buf.writeVector8(buf => { 579 // for (let item of items) { 580 // buf.writeUint16(item) 581 // } 582 // }) 583 // 584 // The helper will automatically take care of writing the appropriate 585 // length field once the callback completes. 586 587 _writeVector(maxLength, writeLength, cb) { 588 // Initially, write the length field as zero. 589 const lengthPos = this.tell(); 590 writeLength(0); 591 // Call the callback to write the vector items. 592 const bodyPos = this.tell(); 593 cb(this); 594 const length = this.tell() - bodyPos; 595 if (length >= maxLength) { 596 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 597 } 598 // Backfill the actual length field. 599 this.seek(lengthPos); 600 writeLength(length); 601 this.incr(length); 602 return length; 603 } 604 605 writeVector8(cb) { 606 return this._writeVector(Math.pow(2, 8), len => this.writeUint8(len), cb); 607 } 608 609 writeVector16(cb) { 610 return this._writeVector(Math.pow(2, 16), len => this.writeUint16(len), cb); 611 } 612 613 writeVector24(cb) { 614 return this._writeVector(Math.pow(2, 24), len => this.writeUint24(len), cb); 615 } 616 617 writeVectorBytes8(bytes) { 618 return this.writeVector8(buf => { 619 buf.writeBytes(bytes); 620 }); 621 } 622 623 writeVectorBytes16(bytes) { 624 return this.writeVector16(buf => { 625 buf.writeBytes(bytes); 626 }); 627 } 628 629 writeVectorBytes24(bytes) { 630 return this.writeVector24(buf => { 631 buf.writeBytes(bytes); 632 }); 633 } 634 } 635 636 // CONCATENATED MODULE: ./src/crypto.js 637 /* This Source Code Form is subject to the terms of the Mozilla Public 638 * License, v. 2.0. If a copy of the MPL was not distributed with this 639 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 640 641 // 642 // Low-level crypto primitives. 643 // 644 // This file implements the AEAD encrypt/decrypt and hashing routines 645 // for the TLS_AES_128_GCM_SHA256 ciphersuite. They are (thankfully) 646 // fairly light-weight wrappers around what's available via the WebCrypto 647 // API. 648 // 649 650 651 652 653 const AEAD_SIZE_INFLATION = 16; 654 const KEY_LENGTH = 16; 655 const IV_LENGTH = 12; 656 const HASH_LENGTH = 32; 657 658 async function prepareKey(key, mode) { 659 return crypto.subtle.importKey('raw', key, { name: 'AES-GCM' }, false, [mode]); 660 } 661 662 async function encrypt(key, iv, plaintext, additionalData) { 663 const ciphertext = await crypto.subtle.encrypt({ 664 additionalData, 665 iv, 666 name: 'AES-GCM', 667 tagLength: AEAD_SIZE_INFLATION * 8 668 }, key, plaintext); 669 return new Uint8Array(ciphertext); 670 } 671 672 async function decrypt(key, iv, ciphertext, additionalData) { 673 try { 674 const plaintext = await crypto.subtle.decrypt({ 675 additionalData, 676 iv, 677 name: 'AES-GCM', 678 tagLength: AEAD_SIZE_INFLATION * 8 679 }, key, ciphertext); 680 return new Uint8Array(plaintext); 681 } catch (err) { 682 // Yes, we really do throw 'decrypt_error' when failing to verify a HMAC, 683 // and a 'bad_record_mac' error when failing to decrypt. 684 throw new TLSError(ALERT_DESCRIPTION.BAD_RECORD_MAC); 685 } 686 } 687 688 async function hash(message) { 689 return new Uint8Array(await crypto.subtle.digest({ name: 'SHA-256' }, message)); 690 } 691 692 async function hmac(keyBytes, message) { 693 const key = await crypto.subtle.importKey('raw', keyBytes, { 694 hash: { name: 'SHA-256' }, 695 name: 'HMAC', 696 }, false, ['sign']); 697 const sig = await crypto.subtle.sign({ name: 'HMAC' }, key, message); 698 return new Uint8Array(sig); 699 } 700 701 async function verifyHmac(keyBytes, signature, message) { 702 const key = await crypto.subtle.importKey('raw', keyBytes, { 703 hash: { name: 'SHA-256' }, 704 name: 'HMAC', 705 }, false, ['verify']); 706 if (! (await crypto.subtle.verify({ name: 'HMAC' }, key, signature, message))) { 707 // Yes, we really do throw 'decrypt_error' when failing to verify a HMAC, 708 // and a 'bad_record_mac' error when failing to decrypt. 709 throw new TLSError(ALERT_DESCRIPTION.DECRYPT_ERROR); 710 } 711 } 712 713 async function hkdfExtract(salt, ikm) { 714 // Ref https://tools.ietf.org/html/rfc5869#section-2.2 715 return await hmac(salt, ikm); 716 } 717 718 async function hkdfExpand(prk, info, length) { 719 // Ref https://tools.ietf.org/html/rfc5869#section-2.3 720 const N = Math.ceil(length / HASH_LENGTH); 721 if (N <= 0) { 722 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 723 } 724 if (N >= 255) { 725 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 726 } 727 const input = new utils_BufferWriter(); 728 const output = new utils_BufferWriter(); 729 let T = new Uint8Array(0); 730 for (let i = 1; i <= N; i++) { 731 input.writeBytes(T); 732 input.writeBytes(info); 733 input.writeUint8(i); 734 T = await hmac(prk, input.flush()); 735 output.writeBytes(T); 736 } 737 return output.slice(0, length); 738 } 739 740 async function hkdfExpandLabel(secret, label, context, length) { 741 // struct { 742 // uint16 length = Length; 743 // opaque label < 7..255 > = "tls13 " + Label; 744 // opaque context < 0..255 > = Context; 745 // } HkdfLabel; 746 const hkdfLabel = new utils_BufferWriter(); 747 hkdfLabel.writeUint16(length); 748 hkdfLabel.writeVectorBytes8(utf8ToBytes('tls13 ' + label)); 749 hkdfLabel.writeVectorBytes8(context); 750 return hkdfExpand(secret, hkdfLabel.flush(), length); 751 } 752 753 async function getRandomBytes(size) { 754 const bytes = new Uint8Array(size); 755 crypto.getRandomValues(bytes); 756 return bytes; 757 } 758 759 // CONCATENATED MODULE: ./src/extensions.js 760 /* This Source Code Form is subject to the terms of the Mozilla Public 761 * License, v. 2.0. If a copy of the MPL was not distributed with this 762 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 763 764 // 765 // Extension parsing. 766 // 767 // This file contains some helpers for reading/writing the various kinds 768 // of Extension that might appear in a HandshakeMessage. 769 // 770 // "Extensions" are how TLS signals the presence of particular bits of optional 771 // functionality in the protocol. Lots of parts of TLS1.3 that don't seem like 772 // they're optional are implemented in terms of an extension, IIUC because that's 773 // what was needed for a clean deployment in amongst earlier versions of the protocol. 774 // 775 776 777 778 779 780 /* eslint-disable sorting/sort-object-props */ 781 const EXTENSION_TYPE = { 782 PRE_SHARED_KEY: 41, 783 SUPPORTED_VERSIONS: 43, 784 PSK_KEY_EXCHANGE_MODES: 45, 785 }; 786 /* eslint-enable sorting/sort-object-props */ 787 788 // Base class for generic reading/writing of extensions, 789 // which are all uniformly formatted as: 790 // 791 // struct { 792 // ExtensionType extension_type; 793 // opaque extension_data<0..2^16-1>; 794 // } Extension; 795 // 796 // Extensions always appear inside of a handshake message, 797 // and their internal structure may differ based on the 798 // type of that message. 799 800 class extensions_Extension { 801 802 get TYPE_TAG() { 803 throw new Error('not implemented'); 804 } 805 806 static read(messageType, buf) { 807 const type = buf.readUint16(); 808 let ext = { 809 TYPE_TAG: type, 810 }; 811 buf.readVector16(buf => { 812 switch (type) { 813 case EXTENSION_TYPE.PRE_SHARED_KEY: 814 ext = extensions_PreSharedKeyExtension._read(messageType, buf); 815 break; 816 case EXTENSION_TYPE.SUPPORTED_VERSIONS: 817 ext = extensions_SupportedVersionsExtension._read(messageType, buf); 818 break; 819 case EXTENSION_TYPE.PSK_KEY_EXCHANGE_MODES: 820 ext = extensions_PskKeyExchangeModesExtension._read(messageType, buf); 821 break; 822 default: 823 // Skip over unrecognised extensions. 824 buf.incr(buf.length()); 825 } 826 if (buf.hasMoreBytes()) { 827 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 828 } 829 }); 830 return ext; 831 } 832 833 write(messageType, buf) { 834 buf.writeUint16(this.TYPE_TAG); 835 buf.writeVector16(buf => { 836 this._write(messageType, buf); 837 }); 838 } 839 840 static _read(messageType, buf) { 841 throw new Error('not implemented'); 842 } 843 844 static _write(messageType, buf) { 845 throw new Error('not implemented'); 846 } 847 } 848 849 // The PreSharedKey extension: 850 // 851 // struct { 852 // opaque identity<1..2^16-1>; 853 // uint32 obfuscated_ticket_age; 854 // } PskIdentity; 855 // opaque PskBinderEntry<32..255>; 856 // struct { 857 // PskIdentity identities<7..2^16-1>; 858 // PskBinderEntry binders<33..2^16-1>; 859 // } OfferedPsks; 860 // struct { 861 // select(Handshake.msg_type) { 862 // case client_hello: OfferedPsks; 863 // case server_hello: uint16 selected_identity; 864 // }; 865 // } PreSharedKeyExtension; 866 867 class extensions_PreSharedKeyExtension extends extensions_Extension { 868 constructor(identities, binders, selectedIdentity) { 869 super(); 870 this.identities = identities; 871 this.binders = binders; 872 this.selectedIdentity = selectedIdentity; 873 } 874 875 get TYPE_TAG() { 876 return EXTENSION_TYPE.PRE_SHARED_KEY; 877 } 878 879 static _read(messageType, buf) { 880 let identities = null, binders = null, selectedIdentity = null; 881 switch (messageType) { 882 case HANDSHAKE_TYPE.CLIENT_HELLO: 883 identities = []; binders = []; 884 buf.readVector16(buf => { 885 const identity = buf.readVectorBytes16(); 886 buf.readBytes(4); // Skip over the ticket age. 887 identities.push(identity); 888 }); 889 buf.readVector16(buf => { 890 const binder = buf.readVectorBytes8(); 891 if (binder.byteLength < HASH_LENGTH) { 892 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 893 } 894 binders.push(binder); 895 }); 896 if (identities.length !== binders.length) { 897 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 898 } 899 break; 900 case HANDSHAKE_TYPE.SERVER_HELLO: 901 selectedIdentity = buf.readUint16(); 902 break; 903 default: 904 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 905 } 906 return new this(identities, binders, selectedIdentity); 907 } 908 909 _write(messageType, buf) { 910 switch (messageType) { 911 case HANDSHAKE_TYPE.CLIENT_HELLO: 912 buf.writeVector16(buf => { 913 this.identities.forEach(pskId => { 914 buf.writeVectorBytes16(pskId); 915 buf.writeUint32(0); // Zero for "tag age" field. 916 }); 917 }); 918 buf.writeVector16(buf => { 919 this.binders.forEach(pskBinder => { 920 buf.writeVectorBytes8(pskBinder); 921 }); 922 }); 923 break; 924 case HANDSHAKE_TYPE.SERVER_HELLO: 925 buf.writeUint16(this.selectedIdentity); 926 break; 927 default: 928 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 929 } 930 } 931 } 932 933 934 // The SupportedVersions extension: 935 // 936 // struct { 937 // select(Handshake.msg_type) { 938 // case client_hello: 939 // ProtocolVersion versions < 2..254 >; 940 // case server_hello: 941 // ProtocolVersion selected_version; 942 // }; 943 // } SupportedVersions; 944 945 class extensions_SupportedVersionsExtension extends extensions_Extension { 946 constructor(versions, selectedVersion) { 947 super(); 948 this.versions = versions; 949 this.selectedVersion = selectedVersion; 950 } 951 952 get TYPE_TAG() { 953 return EXTENSION_TYPE.SUPPORTED_VERSIONS; 954 } 955 956 static _read(messageType, buf) { 957 let versions = null, selectedVersion = null; 958 switch (messageType) { 959 case HANDSHAKE_TYPE.CLIENT_HELLO: 960 versions = []; 961 buf.readVector8(buf => { 962 versions.push(buf.readUint16()); 963 }); 964 break; 965 case HANDSHAKE_TYPE.SERVER_HELLO: 966 selectedVersion = buf.readUint16(); 967 break; 968 default: 969 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 970 } 971 return new this(versions, selectedVersion); 972 } 973 974 _write(messageType, buf) { 975 switch (messageType) { 976 case HANDSHAKE_TYPE.CLIENT_HELLO: 977 buf.writeVector8(buf => { 978 this.versions.forEach(version => { 979 buf.writeUint16(version); 980 }); 981 }); 982 break; 983 case HANDSHAKE_TYPE.SERVER_HELLO: 984 buf.writeUint16(this.selectedVersion); 985 break; 986 default: 987 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 988 } 989 } 990 } 991 992 993 class extensions_PskKeyExchangeModesExtension extends extensions_Extension { 994 constructor(modes) { 995 super(); 996 this.modes = modes; 997 } 998 999 get TYPE_TAG() { 1000 return EXTENSION_TYPE.PSK_KEY_EXCHANGE_MODES; 1001 } 1002 1003 static _read(messageType, buf) { 1004 const modes = []; 1005 switch (messageType) { 1006 case HANDSHAKE_TYPE.CLIENT_HELLO: 1007 buf.readVector8(buf => { 1008 modes.push(buf.readUint8()); 1009 }); 1010 break; 1011 default: 1012 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 1013 } 1014 return new this(modes); 1015 } 1016 1017 _write(messageType, buf) { 1018 switch (messageType) { 1019 case HANDSHAKE_TYPE.CLIENT_HELLO: 1020 buf.writeVector8(buf => { 1021 this.modes.forEach(mode => { 1022 buf.writeUint8(mode); 1023 }); 1024 }); 1025 break; 1026 default: 1027 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 1028 } 1029 } 1030 } 1031 1032 // CONCATENATED MODULE: ./src/constants.js 1033 /* This Source Code Form is subject to the terms of the Mozilla Public 1034 * License, v. 2.0. If a copy of the MPL was not distributed with this 1035 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1036 1037 const VERSION_TLS_1_0 = 0x0301; 1038 const VERSION_TLS_1_2 = 0x0303; 1039 const VERSION_TLS_1_3 = 0x0304; 1040 const TLS_AES_128_GCM_SHA256 = 0x1301; 1041 const PSK_MODE_KE = 0; 1042 1043 // CONCATENATED MODULE: ./src/messages.js 1044 /* This Source Code Form is subject to the terms of the Mozilla Public 1045 * License, v. 2.0. If a copy of the MPL was not distributed with this 1046 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1047 1048 // 1049 // Message parsing. 1050 // 1051 // Herein we have code for reading and writing the various Handshake 1052 // messages involved in the TLS protocol. 1053 // 1054 1055 1056 1057 1058 1059 1060 1061 /* eslint-disable sorting/sort-object-props */ 1062 const HANDSHAKE_TYPE = { 1063 CLIENT_HELLO: 1, 1064 SERVER_HELLO: 2, 1065 NEW_SESSION_TICKET: 4, 1066 ENCRYPTED_EXTENSIONS: 8, 1067 FINISHED: 20, 1068 }; 1069 /* eslint-enable sorting/sort-object-props */ 1070 1071 // Base class for generic reading/writing of handshake messages, 1072 // which are all uniformly formatted as: 1073 // 1074 // struct { 1075 // HandshakeType msg_type; /* handshake type */ 1076 // uint24 length; /* bytes in message */ 1077 // select(Handshake.msg_type) { 1078 // ... type specific cases here ... 1079 // }; 1080 // } Handshake; 1081 1082 class messages_HandshakeMessage { 1083 1084 get TYPE_TAG() { 1085 throw new Error('not implemented'); 1086 } 1087 1088 static fromBytes(bytes) { 1089 // Each handshake message has a type and length prefix, per 1090 // https://tools.ietf.org/html/rfc8446#appendix-B.3 1091 const buf = new utils_BufferReader(bytes); 1092 const msg = this.read(buf); 1093 if (buf.hasMoreBytes()) { 1094 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 1095 } 1096 return msg; 1097 } 1098 1099 toBytes() { 1100 const buf = new utils_BufferWriter(); 1101 this.write(buf); 1102 return buf.flush(); 1103 } 1104 1105 static read(buf) { 1106 const type = buf.readUint8(); 1107 let msg = null; 1108 buf.readVector24(buf => { 1109 switch (type) { 1110 case HANDSHAKE_TYPE.CLIENT_HELLO: 1111 msg = messages_ClientHello._read(buf); 1112 break; 1113 case HANDSHAKE_TYPE.SERVER_HELLO: 1114 msg = messages_ServerHello._read(buf); 1115 break; 1116 case HANDSHAKE_TYPE.NEW_SESSION_TICKET: 1117 msg = messages_NewSessionTicket._read(buf); 1118 break; 1119 case HANDSHAKE_TYPE.ENCRYPTED_EXTENSIONS: 1120 msg = EncryptedExtensions._read(buf); 1121 break; 1122 case HANDSHAKE_TYPE.FINISHED: 1123 msg = messages_Finished._read(buf); 1124 break; 1125 } 1126 if (buf.hasMoreBytes()) { 1127 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 1128 } 1129 }); 1130 if (msg === null) { 1131 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1132 } 1133 return msg; 1134 } 1135 1136 write(buf) { 1137 buf.writeUint8(this.TYPE_TAG); 1138 buf.writeVector24(buf => { 1139 this._write(buf); 1140 }); 1141 } 1142 1143 static _read(buf) { 1144 throw new Error('not implemented'); 1145 } 1146 1147 _write(buf) { 1148 throw new Error('not implemented'); 1149 } 1150 1151 // Some little helpers for reading a list of extensions, 1152 // which is uniformly represented as: 1153 // 1154 // Extension extensions<8..2^16-1>; 1155 // 1156 // Recognized extensions are returned as a Map from extension type 1157 // to extension data object, with a special `lastSeenExtension` 1158 // property to make it easy to check which one came last. 1159 1160 static _readExtensions(messageType, buf) { 1161 const extensions = new Map(); 1162 buf.readVector16(buf => { 1163 const ext = extensions_Extension.read(messageType, buf); 1164 if (extensions.has(ext.TYPE_TAG)) { 1165 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 1166 } 1167 extensions.set(ext.TYPE_TAG, ext); 1168 extensions.lastSeenExtension = ext.TYPE_TAG; 1169 }); 1170 return extensions; 1171 } 1172 1173 _writeExtensions(buf, extensions) { 1174 buf.writeVector16(buf => { 1175 extensions.forEach(ext => { 1176 ext.write(this.TYPE_TAG, buf); 1177 }); 1178 }); 1179 } 1180 } 1181 1182 1183 // The ClientHello message: 1184 // 1185 // struct { 1186 // ProtocolVersion legacy_version = 0x0303; 1187 // Random random; 1188 // opaque legacy_session_id<0..32>; 1189 // CipherSuite cipher_suites<2..2^16-2>; 1190 // opaque legacy_compression_methods<1..2^8-1>; 1191 // Extension extensions<8..2^16-1>; 1192 // } ClientHello; 1193 1194 class messages_ClientHello extends messages_HandshakeMessage { 1195 1196 constructor(random, sessionId, extensions) { 1197 super(); 1198 this.random = random; 1199 this.sessionId = sessionId; 1200 this.extensions = extensions; 1201 } 1202 1203 get TYPE_TAG() { 1204 return HANDSHAKE_TYPE.CLIENT_HELLO; 1205 } 1206 1207 static _read(buf) { 1208 // The legacy_version field may indicate an earlier version of TLS 1209 // for backwards compatibility, but must not predate TLS 1.0! 1210 if (buf.readUint16() < VERSION_TLS_1_0) { 1211 throw new TLSError(ALERT_DESCRIPTION.PROTOCOL_VERSION); 1212 } 1213 // The random bytes provided by the peer. 1214 const random = buf.readBytes(32); 1215 // Read legacy_session_id, so the server can echo it. 1216 const sessionId = buf.readVectorBytes8(); 1217 // We only support a single ciphersuite, but the peer may offer several. 1218 // Scan the list to confirm that the one we want is present. 1219 let found = false; 1220 buf.readVector16(buf => { 1221 const cipherSuite = buf.readUint16(); 1222 if (cipherSuite === TLS_AES_128_GCM_SHA256) { 1223 found = true; 1224 } 1225 }); 1226 if (! found) { 1227 throw new TLSError(ALERT_DESCRIPTION.HANDSHAKE_FAILURE); 1228 } 1229 // legacy_compression_methods must be a single zero byte for TLS1.3 ClientHellos. 1230 // It can be non-zero in previous versions of TLS, but we're not going to 1231 // make a successful handshake with such versions, so better to just bail out now. 1232 const legacyCompressionMethods = buf.readVectorBytes8(); 1233 if (legacyCompressionMethods.byteLength !== 1) { 1234 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 1235 } 1236 if (legacyCompressionMethods[0] !== 0x00) { 1237 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 1238 } 1239 // Read and check the extensions. 1240 const extensions = this._readExtensions(HANDSHAKE_TYPE.CLIENT_HELLO, buf); 1241 if (! extensions.has(EXTENSION_TYPE.SUPPORTED_VERSIONS)) { 1242 throw new TLSError(ALERT_DESCRIPTION.MISSING_EXTENSION); 1243 } 1244 if (extensions.get(EXTENSION_TYPE.SUPPORTED_VERSIONS).versions.indexOf(VERSION_TLS_1_3) === -1) { 1245 throw new TLSError(ALERT_DESCRIPTION.PROTOCOL_VERSION); 1246 } 1247 // Was the PreSharedKey extension the last one? 1248 if (extensions.has(EXTENSION_TYPE.PRE_SHARED_KEY)) { 1249 if (extensions.lastSeenExtension !== EXTENSION_TYPE.PRE_SHARED_KEY) { 1250 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 1251 } 1252 } 1253 return new this(random, sessionId, extensions); 1254 } 1255 1256 _write(buf) { 1257 buf.writeUint16(VERSION_TLS_1_2); 1258 buf.writeBytes(this.random); 1259 buf.writeVectorBytes8(this.sessionId); 1260 // Our single supported ciphersuite 1261 buf.writeVector16(buf => { 1262 buf.writeUint16(TLS_AES_128_GCM_SHA256); 1263 }); 1264 // A single zero byte for legacy_compression_methods 1265 buf.writeVectorBytes8(new Uint8Array(1)); 1266 this._writeExtensions(buf, this.extensions); 1267 } 1268 } 1269 1270 1271 // The ServerHello message: 1272 // 1273 // struct { 1274 // ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */ 1275 // Random random; 1276 // opaque legacy_session_id_echo<0..32>; 1277 // CipherSuite cipher_suite; 1278 // uint8 legacy_compression_method = 0; 1279 // Extension extensions < 6..2 ^ 16 - 1 >; 1280 // } ServerHello; 1281 1282 class messages_ServerHello extends messages_HandshakeMessage { 1283 1284 constructor(random, sessionId, extensions) { 1285 super(); 1286 this.random = random; 1287 this.sessionId = sessionId; 1288 this.extensions = extensions; 1289 } 1290 1291 get TYPE_TAG() { 1292 return HANDSHAKE_TYPE.SERVER_HELLO; 1293 } 1294 1295 static _read(buf) { 1296 // Fixed value for legacy_version. 1297 if (buf.readUint16() !== VERSION_TLS_1_2) { 1298 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 1299 } 1300 // Random bytes from the server. 1301 const random = buf.readBytes(32); 1302 // It should have echoed our vector for legacy_session_id. 1303 const sessionId = buf.readVectorBytes8(); 1304 // It should have selected our single offered ciphersuite. 1305 if (buf.readUint16() !== TLS_AES_128_GCM_SHA256) { 1306 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 1307 } 1308 // legacy_compression_method must be zero. 1309 if (buf.readUint8() !== 0) { 1310 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 1311 } 1312 const extensions = this._readExtensions(HANDSHAKE_TYPE.SERVER_HELLO, buf); 1313 if (! extensions.has(EXTENSION_TYPE.SUPPORTED_VERSIONS)) { 1314 throw new TLSError(ALERT_DESCRIPTION.MISSING_EXTENSION); 1315 } 1316 if (extensions.get(EXTENSION_TYPE.SUPPORTED_VERSIONS).selectedVersion !== VERSION_TLS_1_3) { 1317 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 1318 } 1319 return new this(random, sessionId, extensions); 1320 } 1321 1322 _write(buf) { 1323 buf.writeUint16(VERSION_TLS_1_2); 1324 buf.writeBytes(this.random); 1325 buf.writeVectorBytes8(this.sessionId); 1326 // Our single supported ciphersuite 1327 buf.writeUint16(TLS_AES_128_GCM_SHA256); 1328 // A single zero byte for legacy_compression_method 1329 buf.writeUint8(0); 1330 this._writeExtensions(buf, this.extensions); 1331 } 1332 } 1333 1334 1335 // The EncryptedExtensions message: 1336 // 1337 // struct { 1338 // Extension extensions < 0..2 ^ 16 - 1 >; 1339 // } EncryptedExtensions; 1340 // 1341 // We don't actually send any EncryptedExtensions, 1342 // but still have to send an empty message. 1343 1344 class EncryptedExtensions extends messages_HandshakeMessage { 1345 constructor(extensions) { 1346 super(); 1347 this.extensions = extensions; 1348 } 1349 1350 get TYPE_TAG() { 1351 return HANDSHAKE_TYPE.ENCRYPTED_EXTENSIONS; 1352 } 1353 1354 static _read(buf) { 1355 const extensions = this._readExtensions(HANDSHAKE_TYPE.ENCRYPTED_EXTENSIONS, buf); 1356 return new this(extensions); 1357 } 1358 1359 _write(buf) { 1360 this._writeExtensions(buf, this.extensions); 1361 } 1362 } 1363 1364 1365 // The Finished message: 1366 // 1367 // struct { 1368 // opaque verify_data[Hash.length]; 1369 // } Finished; 1370 1371 class messages_Finished extends messages_HandshakeMessage { 1372 1373 constructor(verifyData) { 1374 super(); 1375 this.verifyData = verifyData; 1376 } 1377 1378 get TYPE_TAG() { 1379 return HANDSHAKE_TYPE.FINISHED; 1380 } 1381 1382 static _read(buf) { 1383 const verifyData = buf.readBytes(HASH_LENGTH); 1384 return new this(verifyData); 1385 } 1386 1387 _write(buf) { 1388 buf.writeBytes(this.verifyData); 1389 } 1390 } 1391 1392 1393 // The NewSessionTicket message: 1394 // 1395 // struct { 1396 // uint32 ticket_lifetime; 1397 // uint32 ticket_age_add; 1398 // opaque ticket_nonce < 0..255 >; 1399 // opaque ticket < 1..2 ^ 16 - 1 >; 1400 // Extension extensions < 0..2 ^ 16 - 2 >; 1401 // } NewSessionTicket; 1402 // 1403 // We don't actually make use of these, but we need to be able 1404 // to accept them and do basic validation. 1405 1406 class messages_NewSessionTicket extends messages_HandshakeMessage { 1407 constructor(ticketLifetime, ticketAgeAdd, ticketNonce, ticket, extensions) { 1408 super(); 1409 this.ticketLifetime = ticketLifetime; 1410 this.ticketAgeAdd = ticketAgeAdd; 1411 this.ticketNonce = ticketNonce; 1412 this.ticket = ticket; 1413 this.extensions = extensions; 1414 } 1415 1416 get TYPE_TAG() { 1417 return HANDSHAKE_TYPE.NEW_SESSION_TICKET; 1418 } 1419 1420 static _read(buf) { 1421 const ticketLifetime = buf.readUint32(); 1422 const ticketAgeAdd = buf.readUint32(); 1423 const ticketNonce = buf.readVectorBytes8(); 1424 const ticket = buf.readVectorBytes16(); 1425 if (ticket.byteLength < 1) { 1426 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 1427 } 1428 const extensions = this._readExtensions(HANDSHAKE_TYPE.NEW_SESSION_TICKET, buf); 1429 return new this(ticketLifetime, ticketAgeAdd, ticketNonce, ticket, extensions); 1430 } 1431 1432 _write(buf) { 1433 buf.writeUint32(this.ticketLifetime); 1434 buf.writeUint32(this.ticketAgeAdd); 1435 buf.writeVectorBytes8(this.ticketNonce); 1436 buf.writeVectorBytes16(this.ticket); 1437 this._writeExtensions(buf, this.extensions); 1438 } 1439 } 1440 1441 // CONCATENATED MODULE: ./src/states.js 1442 /* This Source Code Form is subject to the terms of the Mozilla Public 1443 * License, v. 2.0. If a copy of the MPL was not distributed with this 1444 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1445 1446 1447 1448 1449 1450 1451 1452 1453 // 1454 // State-machine for TLS Handshake Management. 1455 // 1456 // Internally, we manage the TLS connection by explicitly modelling the 1457 // client and server state-machines from RFC8446. You can think of 1458 // these `State` objects as little plugins for the `Connection` class 1459 // that provide different behaviours of `send` and `receive` depending 1460 // on the state of the connection. 1461 // 1462 1463 class states_State { 1464 1465 constructor(conn) { 1466 this.conn = conn; 1467 } 1468 1469 async initialize() { 1470 // By default, nothing to do when entering the state. 1471 } 1472 1473 async sendApplicationData(bytes) { 1474 // By default, assume we're not ready to send yet and the caller 1475 // should be blocking on the connection promise before reaching here. 1476 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 1477 } 1478 1479 async recvApplicationData(bytes) { 1480 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1481 } 1482 1483 async recvHandshakeMessage(msg) { 1484 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1485 } 1486 1487 async recvAlertMessage(alert) { 1488 switch (alert.description) { 1489 case ALERT_DESCRIPTION.CLOSE_NOTIFY: 1490 this.conn._closeForRecv(alert); 1491 throw alert; 1492 default: 1493 return await this.handleErrorAndRethrow(alert); 1494 } 1495 } 1496 1497 async recvChangeCipherSpec(bytes) { 1498 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1499 } 1500 1501 async handleErrorAndRethrow(err) { 1502 let alert = err; 1503 if (! (alert instanceof TLSAlert)) { 1504 alert = new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 1505 } 1506 // Try to send error alert to the peer, but we may not 1507 // be able to if the outgoing connection was already closed. 1508 try { 1509 await this.conn._sendAlertMessage(alert); 1510 } catch (_) { } 1511 await this.conn._transition(ERROR, err); 1512 throw err; 1513 } 1514 1515 async close() { 1516 const alert = new TLSCloseNotify(); 1517 await this.conn._sendAlertMessage(alert); 1518 this.conn._closeForSend(alert); 1519 } 1520 1521 } 1522 1523 // A special "guard" state to prevent us from using 1524 // an improperly-initialized Connection. 1525 1526 class UNINITIALIZED extends states_State { 1527 async initialize() { 1528 throw new Error('uninitialized state'); 1529 } 1530 async sendApplicationData(bytes) { 1531 throw new Error('uninitialized state'); 1532 } 1533 async recvApplicationData(bytes) { 1534 throw new Error('uninitialized state'); 1535 } 1536 async recvHandshakeMessage(msg) { 1537 throw new Error('uninitialized state'); 1538 } 1539 async recvChangeCipherSpec(bytes) { 1540 throw new Error('uninitialized state'); 1541 } 1542 async handleErrorAndRethrow(err) { 1543 throw err; 1544 } 1545 async close() { 1546 throw new Error('uninitialized state'); 1547 } 1548 } 1549 1550 // A special "error" state for when something goes wrong. 1551 // This state never transitions to another state, effectively 1552 // terminating the connection. 1553 1554 class ERROR extends states_State { 1555 async initialize(err) { 1556 this.error = err; 1557 this.conn._setConnectionFailure(err); 1558 // Unceremoniously shut down the record layer on error. 1559 this.conn._recordlayer.setSendError(err); 1560 this.conn._recordlayer.setRecvError(err); 1561 } 1562 async sendApplicationData(bytes) { 1563 throw this.error; 1564 } 1565 async recvApplicationData(bytes) { 1566 throw this.error; 1567 } 1568 async recvHandshakeMessage(msg) { 1569 throw this.error; 1570 } 1571 async recvAlertMessage(err) { 1572 throw this.error; 1573 } 1574 async recvChangeCipherSpec(bytes) { 1575 throw this.error; 1576 } 1577 async handleErrorAndRethrow(err) { 1578 throw err; 1579 } 1580 async close() { 1581 throw this.error; 1582 } 1583 } 1584 1585 // The "connected" state, for when the handshake is complete 1586 // and we're ready to send application-level data. 1587 // The logic for this is largely symmetric between client and server. 1588 1589 class states_CONNECTED extends states_State { 1590 async initialize() { 1591 this.conn._setConnectionSuccess(); 1592 } 1593 async sendApplicationData(bytes) { 1594 await this.conn._sendApplicationData(bytes); 1595 } 1596 async recvApplicationData(bytes) { 1597 return bytes; 1598 } 1599 async recvChangeCipherSpec(bytes) { 1600 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1601 } 1602 } 1603 1604 // A base class for states that occur in the middle of the handshake 1605 // (that is, between ClientHello and Finished). These states may receive 1606 // CHANGE_CIPHER_SPEC records for b/w compat reasons, which must contain 1607 // exactly a single 0x01 byte and must otherwise be ignored. 1608 1609 class states_MidHandshakeState extends states_State { 1610 async recvChangeCipherSpec(bytes) { 1611 if (this.conn._hasSeenChangeCipherSpec) { 1612 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1613 } 1614 if (bytes.byteLength !== 1 || bytes[0] !== 1) { 1615 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1616 } 1617 this.conn._hasSeenChangeCipherSpec = true; 1618 } 1619 } 1620 1621 // These states implement (part of) the client state-machine from 1622 // https://tools.ietf.org/html/rfc8446#appendix-A.1 1623 // 1624 // Since we're only implementing a small subset of TLS1.3, 1625 // we only need a small subset of the handshake. It basically goes: 1626 // 1627 // * send ClientHello 1628 // * receive ServerHello 1629 // * receive EncryptedExtensions 1630 // * receive server Finished 1631 // * send client Finished 1632 // 1633 // We include some unused states for completeness, so that it's easier 1634 // to check the implementation against the diagrams in the RFC. 1635 1636 class states_CLIENT_START extends states_State { 1637 async initialize() { 1638 const keyschedule = this.conn._keyschedule; 1639 await keyschedule.addPSK(this.conn.psk); 1640 // Construct a ClientHello message with our single PSK. 1641 // We can't know the PSK binder value yet, so we initially write zeros. 1642 const clientHello = new messages_ClientHello( 1643 // Client random salt. 1644 await getRandomBytes(32), 1645 // Random legacy_session_id; we *could* send an empty string here, 1646 // but sending a random one makes it easier to be compatible with 1647 // the data emitted by tlslite-ng for test-case generation. 1648 await getRandomBytes(32), 1649 [ 1650 new extensions_SupportedVersionsExtension([VERSION_TLS_1_3]), 1651 new extensions_PskKeyExchangeModesExtension([PSK_MODE_KE]), 1652 new extensions_PreSharedKeyExtension([this.conn.pskId], [zeros(HASH_LENGTH)]), 1653 ], 1654 ); 1655 const buf = new utils_BufferWriter(); 1656 clientHello.write(buf); 1657 // Now that we know what the ClientHello looks like, 1658 // go back and calculate the appropriate PSK binder value. 1659 // We only support a single PSK, so the length of the binders field is the 1660 // length of the hash plus one for rendering it as a variable-length byte array, 1661 // plus two for rendering the variable-length list of PSK binders. 1662 const PSK_BINDERS_SIZE = HASH_LENGTH + 1 + 2; 1663 const truncatedTranscript = buf.slice(0, buf.tell() - PSK_BINDERS_SIZE); 1664 const pskBinder = await keyschedule.calculateFinishedMAC(keyschedule.extBinderKey, truncatedTranscript); 1665 buf.incr(-HASH_LENGTH); 1666 buf.writeBytes(pskBinder); 1667 await this.conn._sendHandshakeMessageBytes(buf.flush()); 1668 await this.conn._transition(states_CLIENT_WAIT_SH, clientHello.sessionId); 1669 } 1670 } 1671 1672 class states_CLIENT_WAIT_SH extends states_State { 1673 async initialize(sessionId) { 1674 this._sessionId = sessionId; 1675 } 1676 async recvHandshakeMessage(msg) { 1677 if (! (msg instanceof messages_ServerHello)) { 1678 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1679 } 1680 if (! bytesAreEqual(msg.sessionId, this._sessionId)) { 1681 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 1682 } 1683 const pskExt = msg.extensions.get(EXTENSION_TYPE.PRE_SHARED_KEY); 1684 if (! pskExt) { 1685 throw new TLSError(ALERT_DESCRIPTION.MISSING_EXTENSION); 1686 } 1687 // We expect only the SUPPORTED_VERSIONS and PRE_SHARED_KEY extensions. 1688 if (msg.extensions.size !== 2) { 1689 throw new TLSError(ALERT_DESCRIPTION.UNSUPPORTED_EXTENSION); 1690 } 1691 if (pskExt.selectedIdentity !== 0) { 1692 throw new TLSError(ALERT_DESCRIPTION.ILLEGAL_PARAMETER); 1693 } 1694 await this.conn._keyschedule.addECDHE(null); 1695 await this.conn._setSendKey(this.conn._keyschedule.clientHandshakeTrafficSecret); 1696 await this.conn._setRecvKey(this.conn._keyschedule.serverHandshakeTrafficSecret); 1697 await this.conn._transition(states_CLIENT_WAIT_EE); 1698 } 1699 } 1700 1701 class states_CLIENT_WAIT_EE extends states_MidHandshakeState { 1702 async recvHandshakeMessage(msg) { 1703 // We don't make use of any encrypted extensions, but we still 1704 // have to wait for the server to send the (empty) list of them. 1705 if (! (msg instanceof EncryptedExtensions)) { 1706 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1707 } 1708 // We do not support any EncryptedExtensions. 1709 if (msg.extensions.size !== 0) { 1710 throw new TLSError(ALERT_DESCRIPTION.UNSUPPORTED_EXTENSION); 1711 } 1712 const keyschedule = this.conn._keyschedule; 1713 const serverFinishedTranscript = keyschedule.getTranscript(); 1714 await this.conn._transition(states_CLIENT_WAIT_FINISHED, serverFinishedTranscript); 1715 } 1716 } 1717 1718 class states_CLIENT_WAIT_FINISHED extends states_State { 1719 async initialize(serverFinishedTranscript) { 1720 this._serverFinishedTranscript = serverFinishedTranscript; 1721 } 1722 async recvHandshakeMessage(msg) { 1723 if (! (msg instanceof messages_Finished)) { 1724 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1725 } 1726 // Verify server Finished MAC. 1727 const keyschedule = this.conn._keyschedule; 1728 await keyschedule.verifyFinishedMAC(keyschedule.serverHandshakeTrafficSecret, msg.verifyData, this._serverFinishedTranscript); 1729 // Send our own Finished message in return. 1730 // This must be encrypted with the handshake traffic key, 1731 // but must not appear in the transcript used to calculate the application keys. 1732 const clientFinishedMAC = await keyschedule.calculateFinishedMAC(keyschedule.clientHandshakeTrafficSecret); 1733 await keyschedule.finalize(); 1734 await this.conn._sendHandshakeMessage(new messages_Finished(clientFinishedMAC)); 1735 await this.conn._setSendKey(keyschedule.clientApplicationTrafficSecret); 1736 await this.conn._setRecvKey(keyschedule.serverApplicationTrafficSecret); 1737 await this.conn._transition(states_CLIENT_CONNECTED); 1738 } 1739 } 1740 1741 class states_CLIENT_CONNECTED extends states_CONNECTED { 1742 async recvHandshakeMessage(msg) { 1743 // A connected client must be prepared to accept NewSessionTicket 1744 // messages. We never use them, but other server implementations 1745 // might send them. 1746 if (! (msg instanceof messages_NewSessionTicket)) { 1747 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1748 } 1749 } 1750 } 1751 1752 // These states implement (part of) the server state-machine from 1753 // https://tools.ietf.org/html/rfc8446#appendix-A.2 1754 // 1755 // Since we're only implementing a small subset of TLS1.3, 1756 // we only need a small subset of the handshake. It basically goes: 1757 // 1758 // * receive ClientHello 1759 // * send ServerHello 1760 // * send empty EncryptedExtensions 1761 // * send server Finished 1762 // * receive client Finished 1763 // 1764 // We include some unused states for completeness, so that it's easier 1765 // to check the implementation against the diagrams in the RFC. 1766 1767 class states_SERVER_START extends states_State { 1768 async recvHandshakeMessage(msg) { 1769 if (! (msg instanceof messages_ClientHello)) { 1770 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1771 } 1772 // In the spec, this is where we select connection parameters, and maybe 1773 // tell the client to try again if we can't find a compatible set. 1774 // Since we only support a fixed cipherset, the only thing to "negotiate" 1775 // is whether they provided an acceptable PSK. 1776 const pskExt = msg.extensions.get(EXTENSION_TYPE.PRE_SHARED_KEY); 1777 const pskModesExt = msg.extensions.get(EXTENSION_TYPE.PSK_KEY_EXCHANGE_MODES); 1778 if (! pskExt || ! pskModesExt) { 1779 throw new TLSError(ALERT_DESCRIPTION.MISSING_EXTENSION); 1780 } 1781 if (pskModesExt.modes.indexOf(PSK_MODE_KE) === -1) { 1782 throw new TLSError(ALERT_DESCRIPTION.HANDSHAKE_FAILURE); 1783 } 1784 const pskIndex = pskExt.identities.findIndex(pskId => bytesAreEqual(pskId, this.conn.pskId)); 1785 if (pskIndex === -1) { 1786 throw new TLSError(ALERT_DESCRIPTION.UNKNOWN_PSK_IDENTITY); 1787 } 1788 await this.conn._keyschedule.addPSK(this.conn.psk); 1789 // Validate the PSK binder. 1790 const keyschedule = this.conn._keyschedule; 1791 const transcript = keyschedule.getTranscript(); 1792 // Calculate size occupied by the PSK binders. 1793 let pskBindersSize = 2; // Vector16 representation overhead. 1794 for (const binder of pskExt.binders) { 1795 pskBindersSize += binder.byteLength + 1; // Vector8 representation overhead. 1796 } 1797 await keyschedule.verifyFinishedMAC(keyschedule.extBinderKey, pskExt.binders[pskIndex], transcript.slice(0, -pskBindersSize)); 1798 await this.conn._transition(states_SERVER_NEGOTIATED, msg.sessionId, pskIndex); 1799 } 1800 } 1801 1802 class states_SERVER_NEGOTIATED extends states_MidHandshakeState { 1803 async initialize(sessionId, pskIndex) { 1804 await this.conn._sendHandshakeMessage(new messages_ServerHello( 1805 // Server random 1806 await getRandomBytes(32), 1807 sessionId, 1808 [ 1809 new extensions_SupportedVersionsExtension(null, VERSION_TLS_1_3), 1810 new extensions_PreSharedKeyExtension(null, null, pskIndex), 1811 ] 1812 )); 1813 // If the client sent a non-empty sessionId, the server *must* send a change-cipher-spec for b/w compat. 1814 if (sessionId.byteLength > 0) { 1815 await this.conn._sendChangeCipherSpec(); 1816 } 1817 // We can now transition to the encrypted part of the handshake. 1818 const keyschedule = this.conn._keyschedule; 1819 await keyschedule.addECDHE(null); 1820 await this.conn._setSendKey(keyschedule.serverHandshakeTrafficSecret); 1821 await this.conn._setRecvKey(keyschedule.clientHandshakeTrafficSecret); 1822 // Send an empty EncryptedExtensions message. 1823 await this.conn._sendHandshakeMessage(new EncryptedExtensions([])); 1824 // Send the Finished message. 1825 const serverFinishedMAC = await keyschedule.calculateFinishedMAC(keyschedule.serverHandshakeTrafficSecret); 1826 await this.conn._sendHandshakeMessage(new messages_Finished(serverFinishedMAC)); 1827 // We can now *send* using the application traffic key, 1828 // but have to wait to receive the client Finished before receiving under that key. 1829 // We need to remember the handshake state from before the client Finished 1830 // in order to successfully verify the client Finished. 1831 const clientFinishedTranscript = await keyschedule.getTranscript(); 1832 const clientHandshakeTrafficSecret = keyschedule.clientHandshakeTrafficSecret; 1833 await keyschedule.finalize(); 1834 await this.conn._setSendKey(keyschedule.serverApplicationTrafficSecret); 1835 await this.conn._transition(states_SERVER_WAIT_FINISHED, clientHandshakeTrafficSecret, clientFinishedTranscript); 1836 } 1837 } 1838 1839 class states_SERVER_WAIT_FINISHED extends states_MidHandshakeState { 1840 async initialize(clientHandshakeTrafficSecret, clientFinishedTranscript) { 1841 this._clientHandshakeTrafficSecret = clientHandshakeTrafficSecret; 1842 this._clientFinishedTranscript = clientFinishedTranscript; 1843 } 1844 async recvHandshakeMessage(msg) { 1845 if (! (msg instanceof messages_Finished)) { 1846 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 1847 } 1848 const keyschedule = this.conn._keyschedule; 1849 await keyschedule.verifyFinishedMAC(this._clientHandshakeTrafficSecret, msg.verifyData, this._clientFinishedTranscript); 1850 this._clientHandshakeTrafficSecret = this._clientFinishedTranscript = null; 1851 await this.conn._setRecvKey(keyschedule.clientApplicationTrafficSecret); 1852 await this.conn._transition(states_CONNECTED); 1853 } 1854 } 1855 1856 // CONCATENATED MODULE: ./src/keyschedule.js 1857 /* This Source Code Form is subject to the terms of the Mozilla Public 1858 * License, v. 2.0. If a copy of the MPL was not distributed with this 1859 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1860 1861 // TLS1.3 Key Schedule. 1862 // 1863 // In this file we implement the "key schedule" from 1864 // https://tools.ietf.org/html/rfc8446#section-7.1, which 1865 // defines how to calculate various keys as the handshake 1866 // state progresses. 1867 1868 1869 1870 1871 1872 1873 1874 // The `KeySchedule` class progresses through three stages corresponding 1875 // to the three phases of the TLS1.3 key schedule: 1876 // 1877 // UNINITIALIZED 1878 // | 1879 // | addPSK() 1880 // v 1881 // EARLY_SECRET 1882 // | 1883 // | addECDHE() 1884 // v 1885 // HANDSHAKE_SECRET 1886 // | 1887 // | finalize() 1888 // v 1889 // MASTER_SECRET 1890 // 1891 // It will error out if the calling code attempts to add key material 1892 // in the wrong order. 1893 1894 const STAGE_UNINITIALIZED = 0; 1895 const STAGE_EARLY_SECRET = 1; 1896 const STAGE_HANDSHAKE_SECRET = 2; 1897 const STAGE_MASTER_SECRET = 3; 1898 1899 class keyschedule_KeySchedule { 1900 constructor() { 1901 this.stage = STAGE_UNINITIALIZED; 1902 // WebCrypto doesn't support a rolling hash construct, so we have to 1903 // keep the entire message transcript in memory. 1904 this.transcript = new utils_BufferWriter(); 1905 // This tracks the main secret from with other keys are derived at each stage. 1906 this.secret = null; 1907 // And these are all the various keys we'll derive as the handshake progresses. 1908 this.extBinderKey = null; 1909 this.clientHandshakeTrafficSecret = null; 1910 this.serverHandshakeTrafficSecret = null; 1911 this.clientApplicationTrafficSecret = null; 1912 this.serverApplicationTrafficSecret = null; 1913 } 1914 1915 async addPSK(psk) { 1916 // Use the selected PSK (if any) to calculate the "early secret". 1917 if (psk === null) { 1918 psk = zeros(HASH_LENGTH); 1919 } 1920 if (this.stage !== STAGE_UNINITIALIZED) { 1921 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 1922 } 1923 this.stage = STAGE_EARLY_SECRET; 1924 this.secret = await hkdfExtract(zeros(HASH_LENGTH), psk); 1925 this.extBinderKey = await this.deriveSecret('ext binder', EMPTY); 1926 this.secret = await this.deriveSecret('derived', EMPTY); 1927 } 1928 1929 async addECDHE(ecdhe) { 1930 // Mix in the ECDHE output (if any) to calculate the "handshake secret". 1931 if (ecdhe === null) { 1932 ecdhe = zeros(HASH_LENGTH); 1933 } 1934 if (this.stage !== STAGE_EARLY_SECRET) { 1935 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 1936 } 1937 this.stage = STAGE_HANDSHAKE_SECRET; 1938 this.extBinderKey = null; 1939 this.secret = await hkdfExtract(this.secret, ecdhe); 1940 this.clientHandshakeTrafficSecret = await this.deriveSecret('c hs traffic'); 1941 this.serverHandshakeTrafficSecret = await this.deriveSecret('s hs traffic'); 1942 this.secret = await this.deriveSecret('derived', EMPTY); 1943 } 1944 1945 async finalize() { 1946 if (this.stage !== STAGE_HANDSHAKE_SECRET) { 1947 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 1948 } 1949 this.stage = STAGE_MASTER_SECRET; 1950 this.clientHandshakeTrafficSecret = null; 1951 this.serverHandshakeTrafficSecret = null; 1952 this.secret = await hkdfExtract(this.secret, zeros(HASH_LENGTH)); 1953 this.clientApplicationTrafficSecret = await this.deriveSecret('c ap traffic'); 1954 this.serverApplicationTrafficSecret = await this.deriveSecret('s ap traffic'); 1955 this.secret = null; 1956 } 1957 1958 addToTranscript(bytes) { 1959 this.transcript.writeBytes(bytes); 1960 } 1961 1962 getTranscript() { 1963 return this.transcript.slice(); 1964 } 1965 1966 async deriveSecret(label, transcript = undefined) { 1967 transcript = transcript || this.getTranscript(); 1968 return await hkdfExpandLabel(this.secret, label, await hash(transcript), HASH_LENGTH); 1969 } 1970 1971 async calculateFinishedMAC(baseKey, transcript = undefined) { 1972 transcript = transcript || this.getTranscript(); 1973 const finishedKey = await hkdfExpandLabel(baseKey, 'finished', EMPTY, HASH_LENGTH); 1974 return await hmac(finishedKey, await hash(transcript)); 1975 } 1976 1977 async verifyFinishedMAC(baseKey, mac, transcript = undefined) { 1978 transcript = transcript || this.getTranscript(); 1979 const finishedKey = await hkdfExpandLabel(baseKey, 'finished', EMPTY, HASH_LENGTH); 1980 await verifyHmac(finishedKey, mac, await hash(transcript)); 1981 } 1982 } 1983 1984 // CONCATENATED MODULE: ./src/recordlayer.js 1985 /* This Source Code Form is subject to the terms of the Mozilla Public 1986 * License, v. 2.0. If a copy of the MPL was not distributed with this 1987 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1988 1989 // 1990 // This file implements the "record layer" for TLS1.3, as defined in 1991 // https://tools.ietf.org/html/rfc8446#section-5. 1992 // 1993 // The record layer is responsible for encrypting/decrypting bytes to be 1994 // sent over the wire, including stateful management of sequence numbers 1995 // for the incoming and outgoing stream. 1996 // 1997 // The main interface is the RecordLayer class, which takes a callback function 1998 // sending data and can be used like so: 1999 // 2000 // rl = new RecordLayer(async function send_encrypted_data(data) { 2001 // // application-specific sending logic here. 2002 // }); 2003 // 2004 // // Records are sent and received in plaintext by default, 2005 // // until you specify the key to use. 2006 // await rl.setSendKey(key) 2007 // 2008 // // Send some data by specifying the record type and the bytes. 2009 // // Where allowed by the record type, it will be buffered until 2010 // // explicitly flushed, and then sent by calling the callback. 2011 // await rl.send(RECORD_TYPE.HANDSHAKE, <bytes for a handshake message>) 2012 // await rl.send(RECORD_TYPE.HANDSHAKE, <bytes for another handshake message>) 2013 // await rl.flush() 2014 // 2015 // // Separate keys are used for sending and receiving. 2016 // rl.setRecvKey(key); 2017 // 2018 // // When data is received, push it into the RecordLayer 2019 // // and pass a callback that will be called with a [type, bytes] 2020 // // pair for each message parsed from the data. 2021 // rl.recv(dataReceivedFromPeer, async (type, bytes) => { 2022 // switch (type) { 2023 // case RECORD_TYPE.APPLICATION_DATA: 2024 // // do something with application data 2025 // case RECORD_TYPE.HANDSHAKE: 2026 // // do something with a handshake message 2027 // default: 2028 // // etc... 2029 // } 2030 // }); 2031 // 2032 2033 2034 2035 2036 2037 2038 2039 /* eslint-disable sorting/sort-object-props */ 2040 const RECORD_TYPE = { 2041 CHANGE_CIPHER_SPEC: 20, 2042 ALERT: 21, 2043 HANDSHAKE: 22, 2044 APPLICATION_DATA: 23, 2045 }; 2046 /* eslint-enable sorting/sort-object-props */ 2047 2048 // Encrypting at most 2^24 records will force us to stay 2049 // below data limits on AES-GCM encryption key use, and also 2050 // means we can accurately represent the sequence number as 2051 // a javascript double. 2052 const MAX_SEQUENCE_NUMBER = Math.pow(2, 24); 2053 const MAX_RECORD_SIZE = Math.pow(2, 14); 2054 const MAX_ENCRYPTED_RECORD_SIZE = MAX_RECORD_SIZE + 256; 2055 const RECORD_HEADER_SIZE = 5; 2056 2057 // These are some helper classes to manage the encryption/decryption state 2058 // for a particular key. 2059 2060 class recordlayer_CipherState { 2061 constructor(key, iv) { 2062 this.key = key; 2063 this.iv = iv; 2064 this.seqnum = 0; 2065 } 2066 2067 static async create(baseKey, mode) { 2068 // Derive key and iv per https://tools.ietf.org/html/rfc8446#section-7.3 2069 const key = await prepareKey(await hkdfExpandLabel(baseKey, 'key', EMPTY, KEY_LENGTH), mode); 2070 const iv = await hkdfExpandLabel(baseKey, 'iv', EMPTY, IV_LENGTH); 2071 return new this(key, iv); 2072 } 2073 2074 nonce() { 2075 // Ref https://tools.ietf.org/html/rfc8446#section-5.3: 2076 // * left-pad the sequence number with zeros to IV_LENGTH 2077 // * xor with the provided iv 2078 // Our sequence numbers are always less than 2^24, so fit in a Uint32 2079 // in the last 4 bytes of the nonce. 2080 const nonce = this.iv.slice(); 2081 const dv = new DataView(nonce.buffer, nonce.byteLength - 4, 4); 2082 dv.setUint32(0, dv.getUint32(0) ^ this.seqnum); 2083 this.seqnum += 1; 2084 if (this.seqnum > MAX_SEQUENCE_NUMBER) { 2085 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 2086 } 2087 return nonce; 2088 } 2089 } 2090 2091 class recordlayer_EncryptionState extends recordlayer_CipherState { 2092 static async create(key) { 2093 return super.create(key, 'encrypt'); 2094 } 2095 2096 async encrypt(plaintext, additionalData) { 2097 return await encrypt(this.key, this.nonce(), plaintext, additionalData); 2098 } 2099 } 2100 2101 class recordlayer_DecryptionState extends recordlayer_CipherState { 2102 static async create(key) { 2103 return super.create(key, 'decrypt'); 2104 } 2105 2106 async decrypt(ciphertext, additionalData) { 2107 return await decrypt(this.key, this.nonce(), ciphertext, additionalData); 2108 } 2109 } 2110 2111 // The main RecordLayer class. 2112 2113 class recordlayer_RecordLayer { 2114 constructor(sendCallback) { 2115 this.sendCallback = sendCallback; 2116 this._sendEncryptState = null; 2117 this._sendError = null; 2118 this._recvDecryptState = null; 2119 this._recvError = null; 2120 this._pendingRecordType = 0; 2121 this._pendingRecordBuf = null; 2122 } 2123 2124 async setSendKey(key) { 2125 await this.flush(); 2126 this._sendEncryptState = await recordlayer_EncryptionState.create(key); 2127 } 2128 2129 async setRecvKey(key) { 2130 this._recvDecryptState = await recordlayer_DecryptionState.create(key); 2131 } 2132 2133 async setSendError(err) { 2134 this._sendError = err; 2135 } 2136 2137 async setRecvError(err) { 2138 this._recvError = err; 2139 } 2140 2141 async send(type, data) { 2142 if (this._sendError !== null) { 2143 throw this._sendError; 2144 } 2145 // Forbid sending data that doesn't fit into a single record. 2146 // We do not support fragmentation over multiple records. 2147 if (data.byteLength > MAX_RECORD_SIZE) { 2148 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 2149 } 2150 // Flush if we're switching to a different record type. 2151 if (this._pendingRecordType && this._pendingRecordType !== type) { 2152 await this.flush(); 2153 } 2154 // Flush if we would overflow the max size of a record. 2155 if (this._pendingRecordBuf !== null) { 2156 if (this._pendingRecordBuf.tell() + data.byteLength > MAX_RECORD_SIZE) { 2157 await this.flush(); 2158 } 2159 } 2160 // Start a new pending record if necessary. 2161 // We reserve space at the start of the buffer for the record header, 2162 // which is conveniently always a fixed size. 2163 if (this._pendingRecordBuf === null) { 2164 this._pendingRecordType = type; 2165 this._pendingRecordBuf = new utils_BufferWriter(); 2166 this._pendingRecordBuf.incr(RECORD_HEADER_SIZE); 2167 } 2168 this._pendingRecordBuf.writeBytes(data); 2169 } 2170 2171 async flush() { 2172 // If there's nothing to flush, bail out early. 2173 // Don't throw `_sendError` if we're not sending anything, because `flush()` 2174 // can be called when we're trying to transition into an error state. 2175 const buf = this._pendingRecordBuf; 2176 let type = this._pendingRecordType; 2177 if (! type) { 2178 if (buf !== null) { 2179 throw new TLSError(ALERT_DESCRIPTION.INTERNAL_ERROR); 2180 } 2181 return; 2182 } 2183 if (this._sendError !== null) { 2184 throw this._sendError; 2185 } 2186 // If we're encrypting, turn the existing buffer contents into a `TLSInnerPlaintext` by 2187 // appending the type. We don't do any zero-padding, although the spec allows it. 2188 let inflation = 0, innerPlaintext = null; 2189 if (this._sendEncryptState !== null) { 2190 buf.writeUint8(type); 2191 innerPlaintext = buf.slice(RECORD_HEADER_SIZE); 2192 inflation = AEAD_SIZE_INFLATION; 2193 type = RECORD_TYPE.APPLICATION_DATA; 2194 } 2195 // Write the common header for either `TLSPlaintext` or `TLSCiphertext` record. 2196 const length = buf.tell() - RECORD_HEADER_SIZE + inflation; 2197 buf.seek(0); 2198 buf.writeUint8(type); 2199 buf.writeUint16(VERSION_TLS_1_2); 2200 buf.writeUint16(length); 2201 // Followed by different payload depending on encryption status. 2202 if (this._sendEncryptState !== null) { 2203 const additionalData = buf.slice(0, RECORD_HEADER_SIZE); 2204 const ciphertext = await this._sendEncryptState.encrypt(innerPlaintext, additionalData); 2205 buf.writeBytes(ciphertext); 2206 } else { 2207 buf.incr(length); 2208 } 2209 this._pendingRecordBuf = null; 2210 this._pendingRecordType = 0; 2211 await this.sendCallback(buf.flush()); 2212 } 2213 2214 async recv(data) { 2215 if (this._recvError !== null) { 2216 throw this._recvError; 2217 } 2218 // For simplicity, we assume that the given data contains exactly one record. 2219 // Peers using this library will send one record at a time over the websocket 2220 // connection, and we can assume that the server-side websocket bridge will split 2221 // up any traffic into individual records if we ever start interoperating with 2222 // peers using a different TLS implementation. 2223 // Similarly, we assume that handshake messages will not be fragmented across 2224 // multiple records. This should be trivially true for the PSK-only mode used 2225 // by this library, but we may want to relax it in future for interoperability 2226 // with e.g. large ClientHello messages that contain lots of different options. 2227 const buf = new utils_BufferReader(data); 2228 // The data to read is either a TLSPlaintext or TLSCiphertext struct, 2229 // depending on whether record protection has been enabled yet: 2230 // 2231 // struct { 2232 // ContentType type; 2233 // ProtocolVersion legacy_record_version; 2234 // uint16 length; 2235 // opaque fragment[TLSPlaintext.length]; 2236 // } TLSPlaintext; 2237 // 2238 // struct { 2239 // ContentType opaque_type = application_data; /* 23 */ 2240 // ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */ 2241 // uint16 length; 2242 // opaque encrypted_record[TLSCiphertext.length]; 2243 // } TLSCiphertext; 2244 // 2245 let type = buf.readUint8(); 2246 // The spec says legacy_record_version "MUST be ignored for all purposes", 2247 // but we know TLS1.3 implementations will only ever emit two possible values, 2248 // so it seems useful to bail out early if we receive anything else. 2249 const version = buf.readUint16(); 2250 if (version !== VERSION_TLS_1_2) { 2251 // TLS1.0 is only acceptable on initial plaintext records. 2252 if (this._recvDecryptState !== null || version !== VERSION_TLS_1_0) { 2253 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 2254 } 2255 } 2256 const length = buf.readUint16(); 2257 let plaintext; 2258 if (this._recvDecryptState === null || type === RECORD_TYPE.CHANGE_CIPHER_SPEC) { 2259 [type, plaintext] = await this._readPlaintextRecord(type, length, buf); 2260 } else { 2261 [type, plaintext] = await this._readEncryptedRecord(type, length, buf); 2262 } 2263 // Sanity-check that we received exactly one record. 2264 if (buf.hasMoreBytes()) { 2265 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 2266 } 2267 return [type, plaintext]; 2268 } 2269 2270 // Helper to read an unencrypted `TLSPlaintext` struct 2271 2272 async _readPlaintextRecord(type, length, buf) { 2273 if (length > MAX_RECORD_SIZE) { 2274 throw new TLSError(ALERT_DESCRIPTION.RECORD_OVERFLOW); 2275 } 2276 return [type, buf.readBytes(length)]; 2277 } 2278 2279 // Helper to read an encrypted `TLSCiphertext` struct, 2280 // decrypting it into plaintext. 2281 2282 async _readEncryptedRecord(type, length, buf) { 2283 if (length > MAX_ENCRYPTED_RECORD_SIZE) { 2284 throw new TLSError(ALERT_DESCRIPTION.RECORD_OVERFLOW); 2285 } 2286 // The outer type for encrypted records is always APPLICATION_DATA. 2287 if (type !== RECORD_TYPE.APPLICATION_DATA) { 2288 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 2289 } 2290 // Decrypt and decode the contained `TLSInnerPlaintext` struct: 2291 // 2292 // struct { 2293 // opaque content[TLSPlaintext.length]; 2294 // ContentType type; 2295 // uint8 zeros[length_of_padding]; 2296 // } TLSInnerPlaintext; 2297 // 2298 // The additional data for the decryption is the `TLSCiphertext` record 2299 // header, which is a fixed size and immediately prior to current buffer position. 2300 buf.incr(-RECORD_HEADER_SIZE); 2301 const additionalData = buf.readBytes(RECORD_HEADER_SIZE); 2302 const ciphertext = buf.readBytes(length); 2303 const paddedPlaintext = await this._recvDecryptState.decrypt(ciphertext, additionalData); 2304 // We have to scan backwards over the zero padding at the end of the struct 2305 // in order to find the non-zero `type` byte. 2306 let i; 2307 for (i = paddedPlaintext.byteLength - 1; i >= 0; i--) { 2308 if (paddedPlaintext[i] !== 0) { 2309 break; 2310 } 2311 } 2312 if (i < 0) { 2313 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 2314 } 2315 type = paddedPlaintext[i]; 2316 // `change_cipher_spec` records must always be plaintext. 2317 if (type === RECORD_TYPE.CHANGE_CIPHER_SPEC) { 2318 throw new TLSError(ALERT_DESCRIPTION.DECODE_ERROR); 2319 } 2320 return [type, paddedPlaintext.slice(0, i)]; 2321 } 2322 } 2323 2324 // CONCATENATED MODULE: ./src/tlsconnection.js 2325 /* This Source Code Form is subject to the terms of the Mozilla Public 2326 * License, v. 2.0. If a copy of the MPL was not distributed with this 2327 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 2328 2329 // The top-level APIs offered by this module are `ClientConnection` and 2330 // `ServerConnection` classes, which provide authenticated and encrypted 2331 // communication via the "externally-provisioned PSK" mode of TLS1.3. 2332 // They each take a callback to be used for sending data to the remote peer, 2333 // and operate like this: 2334 // 2335 // conn = await ClientConnection.create(psk, pskId, async function send_data_to_server(data) { 2336 // // application-specific sending logic here. 2337 // }) 2338 // 2339 // // Send data to the server by calling `send`, 2340 // // which will use the callback provided in the constructor. 2341 // // A single `send()` by the application may result in multiple 2342 // // invokations of the callback. 2343 // 2344 // await conn.send('application-level data') 2345 // 2346 // // When data is received from the server, push it into 2347 // // the connection and let it return any decrypted app-level data. 2348 // // There might not be any app-level data if it was a protocol control 2349 // // message, and the receipt of the data might trigger additional calls 2350 // // to the send callback for protocol control purposes. 2351 // 2352 // serverSocket.on('data', async encrypted_data => { 2353 // const plaintext = await conn.recv(data) 2354 // if (plaintext !== null) { 2355 // do_something_with_app_level_data(plaintext) 2356 // } 2357 // }) 2358 // 2359 // // It's good practice to explicitly close the connection 2360 // // when finished. This will send a "closed" notification 2361 // // to the server. 2362 // 2363 // await conn.close() 2364 // 2365 // // When the peer sends a "closed" notification it will show up 2366 // // as a `TLSCloseNotify` exception from recv: 2367 // 2368 // try { 2369 // data = await conn.recv(data); 2370 // } catch (err) { 2371 // if (! (err instanceof TLSCloseNotify) { throw err } 2372 // do_something_to_cleanly_close_data_connection(); 2373 // } 2374 // 2375 // The `ServerConnection` API operates similarly; the distinction is mainly 2376 // in which side is expected to send vs receieve during the protocol handshake. 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 class tlsconnection_Connection { 2388 constructor(psk, pskId, sendCallback) { 2389 this.psk = assertIsBytes(psk); 2390 this.pskId = assertIsBytes(pskId); 2391 this.connected = new Promise((resolve, reject) => { 2392 this._onConnectionSuccess = resolve; 2393 this._onConnectionFailure = reject; 2394 }); 2395 this._state = new UNINITIALIZED(this); 2396 this._handshakeRecvBuffer = null; 2397 this._hasSeenChangeCipherSpec = false; 2398 this._recordlayer = new recordlayer_RecordLayer(sendCallback); 2399 this._keyschedule = new keyschedule_KeySchedule(); 2400 this._lastPromise = Promise.resolve(); 2401 } 2402 2403 // Subclasses will override this with some async initialization logic. 2404 static async create(psk, pskId, sendCallback) { 2405 return new this(psk, pskId, sendCallback); 2406 } 2407 2408 // These are the three public API methods that consumers can use 2409 // to send and receive data encrypted with TLS1.3. 2410 2411 async send(data) { 2412 assertIsBytes(data); 2413 await this.connected; 2414 await this._synchronized(async () => { 2415 await this._state.sendApplicationData(data); 2416 }); 2417 } 2418 2419 async recv(data) { 2420 assertIsBytes(data); 2421 return await this._synchronized(async () => { 2422 // Decrypt the data using the record layer. 2423 // We expect to receive precisely one record at a time. 2424 const [type, bytes] = await this._recordlayer.recv(data); 2425 // Dispatch based on the type of the record. 2426 switch (type) { 2427 case RECORD_TYPE.CHANGE_CIPHER_SPEC: 2428 await this._state.recvChangeCipherSpec(bytes); 2429 return null; 2430 case RECORD_TYPE.ALERT: 2431 await this._state.recvAlertMessage(TLSAlert.fromBytes(bytes)); 2432 return null; 2433 case RECORD_TYPE.APPLICATION_DATA: 2434 return await this._state.recvApplicationData(bytes); 2435 case RECORD_TYPE.HANDSHAKE: 2436 // Multiple handshake messages may be coalesced into a single record. 2437 // Store the in-progress record buffer on `this` so that we can guard 2438 // against handshake messages that span a change in keys. 2439 this._handshakeRecvBuffer = new utils_BufferReader(bytes); 2440 if (! this._handshakeRecvBuffer.hasMoreBytes()) { 2441 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 2442 } 2443 do { 2444 // Each handshake messages has a type and length prefix, per 2445 // https://tools.ietf.org/html/rfc8446#appendix-B.3 2446 this._handshakeRecvBuffer.incr(1); 2447 const mlength = this._handshakeRecvBuffer.readUint24(); 2448 this._handshakeRecvBuffer.incr(-4); 2449 const messageBytes = this._handshakeRecvBuffer.readBytes(mlength + 4); 2450 this._keyschedule.addToTranscript(messageBytes); 2451 await this._state.recvHandshakeMessage(messages_HandshakeMessage.fromBytes(messageBytes)); 2452 } while (this._handshakeRecvBuffer.hasMoreBytes()); 2453 this._handshakeRecvBuffer = null; 2454 return null; 2455 default: 2456 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 2457 } 2458 }); 2459 } 2460 2461 async close() { 2462 await this._synchronized(async () => { 2463 await this._state.close(); 2464 }); 2465 } 2466 2467 // Ensure that async functions execute one at a time, 2468 // by waiting for the previous call to `_synchronized()` to complete 2469 // before starting a new one. This helps ensure that we complete 2470 // one state-machine transition before starting to do the next. 2471 // It's also a convenient place to catch and alert on errors. 2472 2473 _synchronized(cb) { 2474 const nextPromise = this._lastPromise.then(() => { 2475 return cb(); 2476 }).catch(async err => { 2477 if (err instanceof TLSCloseNotify) { 2478 throw err; 2479 } 2480 await this._state.handleErrorAndRethrow(err); 2481 }); 2482 // We don't want to hold on to the return value or error, 2483 // just synchronize on the fact that it completed. 2484 this._lastPromise = nextPromise.then(noop, noop); 2485 return nextPromise; 2486 } 2487 2488 // This drives internal transition of the state-machine, 2489 // ensuring that the new state is properly initialized. 2490 2491 async _transition(State, ...args) { 2492 this._state = new State(this); 2493 await this._state.initialize(...args); 2494 await this._recordlayer.flush(); 2495 } 2496 2497 // These are helpers to allow the State to manipulate the recordlayer 2498 // and send out various types of data. 2499 2500 async _sendApplicationData(bytes) { 2501 await this._recordlayer.send(RECORD_TYPE.APPLICATION_DATA, bytes); 2502 await this._recordlayer.flush(); 2503 } 2504 2505 async _sendHandshakeMessage(msg) { 2506 await this._sendHandshakeMessageBytes(msg.toBytes()); 2507 } 2508 2509 async _sendHandshakeMessageBytes(bytes) { 2510 this._keyschedule.addToTranscript(bytes); 2511 await this._recordlayer.send(RECORD_TYPE.HANDSHAKE, bytes); 2512 // Don't flush after each handshake message, since we can probably 2513 // coalesce multiple messages into a single record. 2514 } 2515 2516 async _sendAlertMessage(err) { 2517 await this._recordlayer.send(RECORD_TYPE.ALERT, err.toBytes()); 2518 await this._recordlayer.flush(); 2519 } 2520 2521 async _sendChangeCipherSpec() { 2522 await this._recordlayer.send(RECORD_TYPE.CHANGE_CIPHER_SPEC, new Uint8Array([0x01])); 2523 await this._recordlayer.flush(); 2524 } 2525 2526 async _setSendKey(key) { 2527 return await this._recordlayer.setSendKey(key); 2528 } 2529 2530 async _setRecvKey(key) { 2531 // Handshake messages that change keys must be on a record boundary. 2532 if (this._handshakeRecvBuffer && this._handshakeRecvBuffer.hasMoreBytes()) { 2533 throw new TLSError(ALERT_DESCRIPTION.UNEXPECTED_MESSAGE); 2534 } 2535 return await this._recordlayer.setRecvKey(key); 2536 } 2537 2538 _setConnectionSuccess() { 2539 if (this._onConnectionSuccess !== null) { 2540 this._onConnectionSuccess(); 2541 this._onConnectionSuccess = null; 2542 this._onConnectionFailure = null; 2543 } 2544 } 2545 2546 _setConnectionFailure(err) { 2547 if (this._onConnectionFailure !== null) { 2548 this._onConnectionFailure(err); 2549 this._onConnectionSuccess = null; 2550 this._onConnectionFailure = null; 2551 } 2552 } 2553 2554 _closeForSend(alert) { 2555 this._recordlayer.setSendError(alert); 2556 } 2557 2558 _closeForRecv(alert) { 2559 this._recordlayer.setRecvError(alert); 2560 } 2561 } 2562 2563 class tlsconnection_ClientConnection extends tlsconnection_Connection { 2564 static async create(psk, pskId, sendCallback) { 2565 const instance = await super.create(psk, pskId, sendCallback); 2566 await instance._transition(states_CLIENT_START); 2567 return instance; 2568 } 2569 } 2570 2571 class tlsconnection_ServerConnection extends tlsconnection_Connection { 2572 static async create(psk, pskId, sendCallback) { 2573 const instance = await super.create(psk, pskId, sendCallback); 2574 await instance._transition(states_SERVER_START); 2575 return instance; 2576 } 2577 } 2578 2579 // CONCATENATED MODULE: ./node_modules/event-target-shim/dist/event-target-shim.mjs 2580 /** 2581 * @author Toru Nagashima <https://github.com/mysticatea> 2582 * @copyright 2015 Toru Nagashima. All rights reserved. 2583 * See LICENSE file in root directory for full license. 2584 */ 2585 /** 2586 * @typedef {object} PrivateData 2587 * @property {EventTarget} eventTarget The event target. 2588 * @property {{type:string}} event The original event object. 2589 * @property {number} eventPhase The current event phase. 2590 * @property {EventTarget|null} currentTarget The current event target. 2591 * @property {boolean} canceled The flag to prevent default. 2592 * @property {boolean} stopped The flag to stop propagation. 2593 * @property {boolean} immediateStopped The flag to stop propagation immediately. 2594 * @property {Function|null} passiveListener The listener if the current listener is passive. Otherwise this is null. 2595 * @property {number} timeStamp The unix time. 2596 * @private 2597 */ 2598 2599 /** 2600 * Private data for event wrappers. 2601 * @type {WeakMap<Event, PrivateData>} 2602 * @private 2603 */ 2604 const privateData = new WeakMap(); 2605 2606 /** 2607 * Cache for wrapper classes. 2608 * @type {WeakMap<Object, Function>} 2609 * @private 2610 */ 2611 const wrappers = new WeakMap(); 2612 2613 /** 2614 * Get private data. 2615 * @param {Event} event The event object to get private data. 2616 * @returns {PrivateData} The private data of the event. 2617 * @private 2618 */ 2619 function pd(event) { 2620 const retv = privateData.get(event); 2621 console.assert( 2622 retv != null, 2623 "'this' is expected an Event object, but got", 2624 event 2625 ); 2626 return retv 2627 } 2628 2629 /** 2630 * https://dom.spec.whatwg.org/#set-the-canceled-flag 2631 * @param data {PrivateData} private data. 2632 */ 2633 function setCancelFlag(data) { 2634 if (data.passiveListener != null) { 2635 if ( 2636 typeof console !== "undefined" && 2637 typeof console.error === "function" 2638 ) { 2639 console.error( 2640 "Unable to preventDefault inside passive event listener invocation.", 2641 data.passiveListener 2642 ); 2643 } 2644 return 2645 } 2646 if (!data.event.cancelable) { 2647 return 2648 } 2649 2650 data.canceled = true; 2651 if (typeof data.event.preventDefault === "function") { 2652 data.event.preventDefault(); 2653 } 2654 } 2655 2656 /** 2657 * @see https://dom.spec.whatwg.org/#interface-event 2658 * @private 2659 */ 2660 /** 2661 * The event wrapper. 2662 * @constructor 2663 * @param {EventTarget} eventTarget The event target of this dispatching. 2664 * @param {Event|{type:string}} event The original event to wrap. 2665 */ 2666 function Event(eventTarget, event) { 2667 privateData.set(this, { 2668 eventTarget, 2669 event, 2670 eventPhase: 2, 2671 currentTarget: eventTarget, 2672 canceled: false, 2673 stopped: false, 2674 immediateStopped: false, 2675 passiveListener: null, 2676 timeStamp: event.timeStamp || Date.now(), 2677 }); 2678 2679 // https://heycam.github.io/webidl/#Unforgeable 2680 Object.defineProperty(this, "isTrusted", { value: false, enumerable: true }); 2681 2682 // Define accessors 2683 const keys = Object.keys(event); 2684 for (let i = 0; i < keys.length; ++i) { 2685 const key = keys[i]; 2686 if (!(key in this)) { 2687 Object.defineProperty(this, key, defineRedirectDescriptor(key)); 2688 } 2689 } 2690 } 2691 2692 // Should be enumerable, but class methods are not enumerable. 2693 Event.prototype = { 2694 /** 2695 * The type of this event. 2696 * @type {string} 2697 */ 2698 get type() { 2699 return pd(this).event.type 2700 }, 2701 2702 /** 2703 * The target of this event. 2704 * @type {EventTarget} 2705 */ 2706 get target() { 2707 return pd(this).eventTarget 2708 }, 2709 2710 /** 2711 * The target of this event. 2712 * @type {EventTarget} 2713 */ 2714 get currentTarget() { 2715 return pd(this).currentTarget 2716 }, 2717 2718 /** 2719 * @returns {EventTarget[]} The composed path of this event. 2720 */ 2721 composedPath() { 2722 const currentTarget = pd(this).currentTarget; 2723 if (currentTarget == null) { 2724 return [] 2725 } 2726 return [currentTarget] 2727 }, 2728 2729 /** 2730 * Constant of NONE. 2731 * @type {number} 2732 */ 2733 get NONE() { 2734 return 0 2735 }, 2736 2737 /** 2738 * Constant of CAPTURING_PHASE. 2739 * @type {number} 2740 */ 2741 get CAPTURING_PHASE() { 2742 return 1 2743 }, 2744 2745 /** 2746 * Constant of AT_TARGET. 2747 * @type {number} 2748 */ 2749 get AT_TARGET() { 2750 return 2 2751 }, 2752 2753 /** 2754 * Constant of BUBBLING_PHASE. 2755 * @type {number} 2756 */ 2757 get BUBBLING_PHASE() { 2758 return 3 2759 }, 2760 2761 /** 2762 * The target of this event. 2763 * @type {number} 2764 */ 2765 get eventPhase() { 2766 return pd(this).eventPhase 2767 }, 2768 2769 /** 2770 * Stop event bubbling. 2771 * @returns {void} 2772 */ 2773 stopPropagation() { 2774 const data = pd(this); 2775 2776 data.stopped = true; 2777 if (typeof data.event.stopPropagation === "function") { 2778 data.event.stopPropagation(); 2779 } 2780 }, 2781 2782 /** 2783 * Stop event bubbling. 2784 * @returns {void} 2785 */ 2786 stopImmediatePropagation() { 2787 const data = pd(this); 2788 2789 data.stopped = true; 2790 data.immediateStopped = true; 2791 if (typeof data.event.stopImmediatePropagation === "function") { 2792 data.event.stopImmediatePropagation(); 2793 } 2794 }, 2795 2796 /** 2797 * The flag to be bubbling. 2798 * @type {boolean} 2799 */ 2800 get bubbles() { 2801 return Boolean(pd(this).event.bubbles) 2802 }, 2803 2804 /** 2805 * The flag to be cancelable. 2806 * @type {boolean} 2807 */ 2808 get cancelable() { 2809 return Boolean(pd(this).event.cancelable) 2810 }, 2811 2812 /** 2813 * Cancel this event. 2814 * @returns {void} 2815 */ 2816 preventDefault() { 2817 setCancelFlag(pd(this)); 2818 }, 2819 2820 /** 2821 * The flag to indicate cancellation state. 2822 * @type {boolean} 2823 */ 2824 get defaultPrevented() { 2825 return pd(this).canceled 2826 }, 2827 2828 /** 2829 * The flag to be composed. 2830 * @type {boolean} 2831 */ 2832 get composed() { 2833 return Boolean(pd(this).event.composed) 2834 }, 2835 2836 /** 2837 * The unix time of this event. 2838 * @type {number} 2839 */ 2840 get timeStamp() { 2841 return pd(this).timeStamp 2842 }, 2843 2844 /** 2845 * The target of this event. 2846 * @type {EventTarget} 2847 * @deprecated 2848 */ 2849 get srcElement() { 2850 return pd(this).eventTarget 2851 }, 2852 2853 /** 2854 * The flag to stop event bubbling. 2855 * @type {boolean} 2856 * @deprecated 2857 */ 2858 get cancelBubble() { 2859 return pd(this).stopped 2860 }, 2861 set cancelBubble(value) { 2862 if (!value) { 2863 return 2864 } 2865 const data = pd(this); 2866 2867 data.stopped = true; 2868 if (typeof data.event.cancelBubble === "boolean") { 2869 data.event.cancelBubble = true; 2870 } 2871 }, 2872 2873 /** 2874 * The flag to indicate cancellation state. 2875 * @type {boolean} 2876 * @deprecated 2877 */ 2878 get returnValue() { 2879 return !pd(this).canceled 2880 }, 2881 set returnValue(value) { 2882 if (!value) { 2883 setCancelFlag(pd(this)); 2884 } 2885 }, 2886 2887 /** 2888 * Initialize this event object. But do nothing under event dispatching. 2889 * @param {string} type The event type. 2890 * @param {boolean} [bubbles=false] The flag to be possible to bubble up. 2891 * @param {boolean} [cancelable=false] The flag to be possible to cancel. 2892 * @deprecated 2893 */ 2894 initEvent() { 2895 // Do nothing. 2896 }, 2897 }; 2898 2899 // `constructor` is not enumerable. 2900 Object.defineProperty(Event.prototype, "constructor", { 2901 value: Event, 2902 configurable: true, 2903 writable: true, 2904 }); 2905 2906 // Ensure `event instanceof window.Event` is `true`. 2907 if (typeof window !== "undefined" && typeof window.Event !== "undefined") { 2908 Object.setPrototypeOf(Event.prototype, window.Event.prototype); 2909 2910 // Make association for wrappers. 2911 wrappers.set(window.Event.prototype, Event); 2912 } 2913 2914 /** 2915 * Get the property descriptor to redirect a given property. 2916 * @param {string} key Property name to define property descriptor. 2917 * @returns {PropertyDescriptor} The property descriptor to redirect the property. 2918 * @private 2919 */ 2920 function defineRedirectDescriptor(key) { 2921 return { 2922 get() { 2923 return pd(this).event[key] 2924 }, 2925 set(value) { 2926 pd(this).event[key] = value; 2927 }, 2928 configurable: true, 2929 enumerable: true, 2930 } 2931 } 2932 2933 /** 2934 * Get the property descriptor to call a given method property. 2935 * @param {string} key Property name to define property descriptor. 2936 * @returns {PropertyDescriptor} The property descriptor to call the method property. 2937 * @private 2938 */ 2939 function defineCallDescriptor(key) { 2940 return { 2941 value() { 2942 const event = pd(this).event; 2943 return event[key].apply(event, arguments) 2944 }, 2945 configurable: true, 2946 enumerable: true, 2947 } 2948 } 2949 2950 /** 2951 * Define new wrapper class. 2952 * @param {Function} BaseEvent The base wrapper class. 2953 * @param {Object} proto The prototype of the original event. 2954 * @returns {Function} The defined wrapper class. 2955 * @private 2956 */ 2957 function defineWrapper(BaseEvent, proto) { 2958 const keys = Object.keys(proto); 2959 if (keys.length === 0) { 2960 return BaseEvent 2961 } 2962 2963 /** CustomEvent */ 2964 function CustomEvent(eventTarget, event) { 2965 BaseEvent.call(this, eventTarget, event); 2966 } 2967 2968 CustomEvent.prototype = Object.create(BaseEvent.prototype, { 2969 constructor: { value: CustomEvent, configurable: true, writable: true }, 2970 }); 2971 2972 // Define accessors. 2973 for (let i = 0; i < keys.length; ++i) { 2974 const key = keys[i]; 2975 if (!(key in BaseEvent.prototype)) { 2976 const descriptor = Object.getOwnPropertyDescriptor(proto, key); 2977 const isFunc = typeof descriptor.value === "function"; 2978 Object.defineProperty( 2979 CustomEvent.prototype, 2980 key, 2981 isFunc 2982 ? defineCallDescriptor(key) 2983 : defineRedirectDescriptor(key) 2984 ); 2985 } 2986 } 2987 2988 return CustomEvent 2989 } 2990 2991 /** 2992 * Get the wrapper class of a given prototype. 2993 * @param {Object} proto The prototype of the original event to get its wrapper. 2994 * @returns {Function} The wrapper class. 2995 * @private 2996 */ 2997 function getWrapper(proto) { 2998 if (proto == null || proto === Object.prototype) { 2999 return Event 3000 } 3001 3002 let wrapper = wrappers.get(proto); 3003 if (wrapper == null) { 3004 wrapper = defineWrapper(getWrapper(Object.getPrototypeOf(proto)), proto); 3005 wrappers.set(proto, wrapper); 3006 } 3007 return wrapper 3008 } 3009 3010 /** 3011 * Wrap a given event to management a dispatching. 3012 * @param {EventTarget} eventTarget The event target of this dispatching. 3013 * @param {Object} event The event to wrap. 3014 * @returns {Event} The wrapper instance. 3015 * @private 3016 */ 3017 function wrapEvent(eventTarget, event) { 3018 const Wrapper = getWrapper(Object.getPrototypeOf(event)); 3019 return new Wrapper(eventTarget, event) 3020 } 3021 3022 /** 3023 * Get the immediateStopped flag of a given event. 3024 * @param {Event} event The event to get. 3025 * @returns {boolean} The flag to stop propagation immediately. 3026 * @private 3027 */ 3028 function isStopped(event) { 3029 return pd(event).immediateStopped 3030 } 3031 3032 /** 3033 * Set the current event phase of a given event. 3034 * @param {Event} event The event to set current target. 3035 * @param {number} eventPhase New event phase. 3036 * @returns {void} 3037 * @private 3038 */ 3039 function setEventPhase(event, eventPhase) { 3040 pd(event).eventPhase = eventPhase; 3041 } 3042 3043 /** 3044 * Set the current target of a given event. 3045 * @param {Event} event The event to set current target. 3046 * @param {EventTarget|null} currentTarget New current target. 3047 * @returns {void} 3048 * @private 3049 */ 3050 function setCurrentTarget(event, currentTarget) { 3051 pd(event).currentTarget = currentTarget; 3052 } 3053 3054 /** 3055 * Set a passive listener of a given event. 3056 * @param {Event} event The event to set current target. 3057 * @param {Function|null} passiveListener New passive listener. 3058 * @returns {void} 3059 * @private 3060 */ 3061 function setPassiveListener(event, passiveListener) { 3062 pd(event).passiveListener = passiveListener; 3063 } 3064 3065 /** 3066 * @typedef {object} ListenerNode 3067 * @property {Function} listener 3068 * @property {1|2|3} listenerType 3069 * @property {boolean} passive 3070 * @property {boolean} once 3071 * @property {ListenerNode|null} next 3072 * @private 3073 */ 3074 3075 /** 3076 * @type {WeakMap<object, Map<string, ListenerNode>>} 3077 * @private 3078 */ 3079 const listenersMap = new WeakMap(); 3080 3081 // Listener types 3082 const CAPTURE = 1; 3083 const BUBBLE = 2; 3084 const ATTRIBUTE = 3; 3085 3086 /** 3087 * Check whether a given value is an object or not. 3088 * @param {any} x The value to check. 3089 * @returns {boolean} `true` if the value is an object. 3090 */ 3091 function isObject(x) { 3092 return x !== null && typeof x === "object" //eslint-disable-line no-restricted-syntax 3093 } 3094 3095 /** 3096 * Get listeners. 3097 * @param {EventTarget} eventTarget The event target to get. 3098 * @returns {Map<string, ListenerNode>} The listeners. 3099 * @private 3100 */ 3101 function getListeners(eventTarget) { 3102 const listeners = listenersMap.get(eventTarget); 3103 if (listeners == null) { 3104 throw new TypeError( 3105 "'this' is expected an EventTarget object, but got another value." 3106 ) 3107 } 3108 return listeners 3109 } 3110 3111 /** 3112 * Get the property descriptor for the event attribute of a given event. 3113 * @param {string} eventName The event name to get property descriptor. 3114 * @returns {PropertyDescriptor} The property descriptor. 3115 * @private 3116 */ 3117 function defineEventAttributeDescriptor(eventName) { 3118 return { 3119 get() { 3120 const listeners = getListeners(this); 3121 let node = listeners.get(eventName); 3122 while (node != null) { 3123 if (node.listenerType === ATTRIBUTE) { 3124 return node.listener 3125 } 3126 node = node.next; 3127 } 3128 return null 3129 }, 3130 3131 set(listener) { 3132 if (typeof listener !== "function" && !isObject(listener)) { 3133 listener = null; // eslint-disable-line no-param-reassign 3134 } 3135 const listeners = getListeners(this); 3136 3137 // Traverse to the tail while removing old value. 3138 let prev = null; 3139 let node = listeners.get(eventName); 3140 while (node != null) { 3141 if (node.listenerType === ATTRIBUTE) { 3142 // Remove old value. 3143 if (prev !== null) { 3144 prev.next = node.next; 3145 } else if (node.next !== null) { 3146 listeners.set(eventName, node.next); 3147 } else { 3148 listeners.delete(eventName); 3149 } 3150 } else { 3151 prev = node; 3152 } 3153 3154 node = node.next; 3155 } 3156 3157 // Add new value. 3158 if (listener !== null) { 3159 const newNode = { 3160 listener, 3161 listenerType: ATTRIBUTE, 3162 passive: false, 3163 once: false, 3164 next: null, 3165 }; 3166 if (prev === null) { 3167 listeners.set(eventName, newNode); 3168 } else { 3169 prev.next = newNode; 3170 } 3171 } 3172 }, 3173 configurable: true, 3174 enumerable: true, 3175 } 3176 } 3177 3178 /** 3179 * Define an event attribute (e.g. `eventTarget.onclick`). 3180 * @param {Object} eventTargetPrototype The event target prototype to define an event attrbite. 3181 * @param {string} eventName The event name to define. 3182 * @returns {void} 3183 */ 3184 function defineEventAttribute(eventTargetPrototype, eventName) { 3185 Object.defineProperty( 3186 eventTargetPrototype, 3187 `on${eventName}`, 3188 defineEventAttributeDescriptor(eventName) 3189 ); 3190 } 3191 3192 /** 3193 * Define a custom EventTarget with event attributes. 3194 * @param {string[]} eventNames Event names for event attributes. 3195 * @returns {EventTarget} The custom EventTarget. 3196 * @private 3197 */ 3198 function defineCustomEventTarget(eventNames) { 3199 /** CustomEventTarget */ 3200 function CustomEventTarget() { 3201 EventTarget.call(this); 3202 } 3203 3204 CustomEventTarget.prototype = Object.create(EventTarget.prototype, { 3205 constructor: { 3206 value: CustomEventTarget, 3207 configurable: true, 3208 writable: true, 3209 }, 3210 }); 3211 3212 for (let i = 0; i < eventNames.length; ++i) { 3213 defineEventAttribute(CustomEventTarget.prototype, eventNames[i]); 3214 } 3215 3216 return CustomEventTarget 3217 } 3218 3219 /** 3220 * EventTarget. 3221 * 3222 * - This is constructor if no arguments. 3223 * - This is a function which returns a CustomEventTarget constructor if there are arguments. 3224 * 3225 * For example: 3226 * 3227 * class A extends EventTarget {} 3228 * class B extends EventTarget("message") {} 3229 * class C extends EventTarget("message", "error") {} 3230 * class D extends EventTarget(["message", "error"]) {} 3231 */ 3232 function EventTarget() { 3233 /*eslint-disable consistent-return */ 3234 if (this instanceof EventTarget) { 3235 listenersMap.set(this, new Map()); 3236 return 3237 } 3238 if (arguments.length === 1 && Array.isArray(arguments[0])) { 3239 return defineCustomEventTarget(arguments[0]) 3240 } 3241 if (arguments.length > 0) { 3242 const types = new Array(arguments.length); 3243 for (let i = 0; i < arguments.length; ++i) { 3244 types[i] = arguments[i]; 3245 } 3246 return defineCustomEventTarget(types) 3247 } 3248 throw new TypeError("Cannot call a class as a function") 3249 /*eslint-enable consistent-return */ 3250 } 3251 3252 // Should be enumerable, but class methods are not enumerable. 3253 EventTarget.prototype = { 3254 /** 3255 * Add a given listener to this event target. 3256 * @param {string} eventName The event name to add. 3257 * @param {Function} listener The listener to add. 3258 * @param {boolean|{capture?:boolean,passive?:boolean,once?:boolean}} [options] The options for this listener. 3259 * @returns {void} 3260 */ 3261 addEventListener(eventName, listener, options) { 3262 if (listener == null) { 3263 return 3264 } 3265 if (typeof listener !== "function" && !isObject(listener)) { 3266 throw new TypeError("'listener' should be a function or an object.") 3267 } 3268 3269 const listeners = getListeners(this); 3270 const optionsIsObj = isObject(options); 3271 const capture = optionsIsObj 3272 ? Boolean(options.capture) 3273 : Boolean(options); 3274 const listenerType = capture ? CAPTURE : BUBBLE; 3275 const newNode = { 3276 listener, 3277 listenerType, 3278 passive: optionsIsObj && Boolean(options.passive), 3279 once: optionsIsObj && Boolean(options.once), 3280 next: null, 3281 }; 3282 3283 // Set it as the first node if the first node is null. 3284 let node = listeners.get(eventName); 3285 if (node === undefined) { 3286 listeners.set(eventName, newNode); 3287 return 3288 } 3289 3290 // Traverse to the tail while checking duplication.. 3291 let prev = null; 3292 while (node != null) { 3293 if ( 3294 node.listener === listener && 3295 node.listenerType === listenerType 3296 ) { 3297 // Should ignore duplication. 3298 return 3299 } 3300 prev = node; 3301 node = node.next; 3302 } 3303 3304 // Add it. 3305 prev.next = newNode; 3306 }, 3307 3308 /** 3309 * Remove a given listener from this event target. 3310 * @param {string} eventName The event name to remove. 3311 * @param {Function} listener The listener to remove. 3312 * @param {boolean|{capture?:boolean,passive?:boolean,once?:boolean}} [options] The options for this listener. 3313 * @returns {void} 3314 */ 3315 removeEventListener(eventName, listener, options) { 3316 if (listener == null) { 3317 return 3318 } 3319 3320 const listeners = getListeners(this); 3321 const capture = isObject(options) 3322 ? Boolean(options.capture) 3323 : Boolean(options); 3324 const listenerType = capture ? CAPTURE : BUBBLE; 3325 3326 let prev = null; 3327 let node = listeners.get(eventName); 3328 while (node != null) { 3329 if ( 3330 node.listener === listener && 3331 node.listenerType === listenerType 3332 ) { 3333 if (prev !== null) { 3334 prev.next = node.next; 3335 } else if (node.next !== null) { 3336 listeners.set(eventName, node.next); 3337 } else { 3338 listeners.delete(eventName); 3339 } 3340 return 3341 } 3342 3343 prev = node; 3344 node = node.next; 3345 } 3346 }, 3347 3348 /** 3349 * Dispatch a given event. 3350 * @param {Event|{type:string}} event The event to dispatch. 3351 * @returns {boolean} `false` if canceled. 3352 */ 3353 dispatchEvent(event) { 3354 if (event == null || typeof event.type !== "string") { 3355 throw new TypeError('"event.type" should be a string.') 3356 } 3357 3358 // If listeners aren't registered, terminate. 3359 const listeners = getListeners(this); 3360 const eventName = event.type; 3361 let node = listeners.get(eventName); 3362 if (node == null) { 3363 return true 3364 } 3365 3366 // Since we cannot rewrite several properties, so wrap object. 3367 const wrappedEvent = wrapEvent(this, event); 3368 3369 // This doesn't process capturing phase and bubbling phase. 3370 // This isn't participating in a tree. 3371 let prev = null; 3372 while (node != null) { 3373 // Remove this listener if it's once 3374 if (node.once) { 3375 if (prev !== null) { 3376 prev.next = node.next; 3377 } else if (node.next !== null) { 3378 listeners.set(eventName, node.next); 3379 } else { 3380 listeners.delete(eventName); 3381 } 3382 } else { 3383 prev = node; 3384 } 3385 3386 // Call this listener 3387 setPassiveListener( 3388 wrappedEvent, 3389 node.passive ? node.listener : null 3390 ); 3391 if (typeof node.listener === "function") { 3392 try { 3393 node.listener.call(this, wrappedEvent); 3394 } catch (err) { 3395 if ( 3396 typeof console !== "undefined" && 3397 typeof console.error === "function" 3398 ) { 3399 console.error(err); 3400 } 3401 } 3402 } else if ( 3403 node.listenerType !== ATTRIBUTE && 3404 typeof node.listener.handleEvent === "function" 3405 ) { 3406 node.listener.handleEvent(wrappedEvent); 3407 } 3408 3409 // Break if `event.stopImmediatePropagation` was called. 3410 if (isStopped(wrappedEvent)) { 3411 break 3412 } 3413 3414 node = node.next; 3415 } 3416 setPassiveListener(wrappedEvent, null); 3417 setEventPhase(wrappedEvent, 0); 3418 setCurrentTarget(wrappedEvent, null); 3419 3420 return !wrappedEvent.defaultPrevented 3421 }, 3422 }; 3423 3424 // `constructor` is not enumerable. 3425 Object.defineProperty(EventTarget.prototype, "constructor", { 3426 value: EventTarget, 3427 configurable: true, 3428 writable: true, 3429 }); 3430 3431 // Ensure `eventTarget instanceof window.EventTarget` is `true`. 3432 if ( 3433 typeof window !== "undefined" && 3434 typeof window.EventTarget !== "undefined" 3435 ) { 3436 Object.setPrototypeOf(EventTarget.prototype, window.EventTarget.prototype); 3437 } 3438 3439 /* harmony default export */ var event_target_shim = (EventTarget); 3440 3441 3442 // CONCATENATED MODULE: ./src/index.js 3443 /* This Source Code Form is subject to the terms of the Mozilla Public 3444 * License, v. 2.0. If a copy of the MPL was not distributed with this 3445 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 3446 3447 // A wrapper that combines a WebSocket to the channelserver 3448 // with some client-side encryption for securing the channel. 3449 // 3450 // This code is responsible for the event handling and the consumer API. 3451 // All the details of encrypting the messages are delegated to`./tlsconnection.js`. 3452 3453 3454 3455 3456 3457 3458 3459 const CLOSE_FLUSH_BUFFER_INTERVAL_MS = 200; 3460 const CLOSE_FLUSH_BUFFER_MAX_TRIES = 5; 3461 3462 class src_PairingChannel extends EventTarget { 3463 constructor(channelId, channelKey, socket, connection) { 3464 super(); 3465 this._channelId = channelId; 3466 this._channelKey = channelKey; 3467 this._socket = socket; 3468 this._connection = connection; 3469 this._selfClosed = false; 3470 this._peerClosed = false; 3471 this._setupListeners(); 3472 } 3473 3474 /** 3475 * Create a new pairing channel. 3476 * 3477 * This will open a channel on the channelserver, and generate a random client-side 3478 * encryption key. When the promise resolves, `this.channelId` and `this.channelKey` 3479 * can be transferred to another client to allow it to securely connect to the channel. 3480 * 3481 * @returns Promise<PairingChannel> 3482 */ 3483 static create(channelServerURI) { 3484 const wsURI = new URL('/v1/ws/', channelServerURI).href; 3485 const channelKey = crypto.getRandomValues(new Uint8Array(32)); 3486 // The one who creates the channel plays the role of 'server' in the underlying TLS exchange. 3487 return this._makePairingChannel(wsURI, tlsconnection_ServerConnection, channelKey); 3488 } 3489 3490 /** 3491 * Connect to an existing pairing channel. 3492 * 3493 * This will connect to a channel on the channelserver previously established by 3494 * another client calling `create`. The `channelId` and `channelKey` must have been 3495 * obtained via some out-of-band mechanism (such as by scanning from a QR code). 3496 * 3497 * @returns Promise<PairingChannel> 3498 */ 3499 static connect(channelServerURI, channelId, channelKey) { 3500 const wsURI = new URL(`/v1/ws/${channelId}`, channelServerURI).href; 3501 // The one who connects to an existing channel plays the role of 'client' 3502 // in the underlying TLS exchange. 3503 return this._makePairingChannel(wsURI, tlsconnection_ClientConnection, channelKey); 3504 } 3505 3506 static _makePairingChannel(wsUri, ConnectionClass, psk) { 3507 const socket = new WebSocket(wsUri); 3508 return new Promise((resolve, reject) => { 3509 // eslint-disable-next-line prefer-const 3510 let stopListening; 3511 const onConnectionError = async () => { 3512 stopListening(); 3513 reject(new Error('Error while creating the pairing channel')); 3514 }; 3515 const onFirstMessage = async event => { 3516 stopListening(); 3517 try { 3518 // The channelserver echos back the channel id, and we use it as an 3519 // additional input to the TLS handshake via the "psk id" field. 3520 const {channelid: channelId} = JSON.parse(event.data); 3521 const pskId = utf8ToBytes(channelId); 3522 const connection = await ConnectionClass.create(psk, pskId, data => { 3523 // Send data by forwarding it via the channelserver websocket. 3524 // The TLS connection gives us `data` as raw bytes, but channelserver 3525 // expects b64urlsafe strings, because it wraps them in a JSON object envelope. 3526 socket.send(bytesToBase64url(data)); 3527 }); 3528 const instance = new this(channelId, psk, socket, connection); 3529 resolve(instance); 3530 } catch (err) { 3531 reject(err); 3532 } 3533 }; 3534 stopListening = () => { 3535 socket.removeEventListener('close', onConnectionError); 3536 socket.removeEventListener('error', onConnectionError); 3537 socket.removeEventListener('message', onFirstMessage); 3538 }; 3539 socket.addEventListener('close', onConnectionError); 3540 socket.addEventListener('error', onConnectionError); 3541 socket.addEventListener('message', onFirstMessage); 3542 }); 3543 } 3544 3545 _setupListeners() { 3546 this._socket.addEventListener('message', async event => { 3547 try { 3548 // When we receive data from the channelserver, pump it through the TLS connection 3549 // to decrypt it, then echo it back out to consumers as an event. 3550 const channelServerEnvelope = JSON.parse(event.data); 3551 const payload = await this._connection.recv(base64urlToBytes(channelServerEnvelope.message)); 3552 if (payload !== null) { 3553 const data = JSON.parse(bytesToUtf8(payload)); 3554 this.dispatchEvent(new CustomEvent('message', { 3555 detail: { 3556 data, 3557 sender: channelServerEnvelope.sender, 3558 }, 3559 })); 3560 } 3561 } catch (error) { 3562 let event; 3563 // The underlying TLS connection will signal a clean shutdown of the channel 3564 // by throwing a special error, because it doesn't really have a better 3565 // signally mechanism available. 3566 if (error instanceof TLSCloseNotify) { 3567 this._peerClosed = true; 3568 if (this._selfClosed) { 3569 this._shutdown(); 3570 } 3571 event = new CustomEvent('close'); 3572 } else { 3573 event = new CustomEvent('error', { 3574 detail: { 3575 error, 3576 } 3577 }); 3578 } 3579 this.dispatchEvent(event); 3580 } 3581 }); 3582 // Relay the WebSocket events. 3583 this._socket.addEventListener('error', () => { 3584 this._shutdown(); 3585 // The dispatched event that we receive has no useful information. 3586 this.dispatchEvent(new CustomEvent('error', { 3587 detail: { 3588 error: new Error('WebSocket error.'), 3589 }, 3590 })); 3591 }); 3592 // In TLS, the peer has to explicitly send a close notification, 3593 // which we dispatch above. Unexpected socket close is an error. 3594 this._socket.addEventListener('close', () => { 3595 this._shutdown(); 3596 if (! this._peerClosed) { 3597 this.dispatchEvent(new CustomEvent('error', { 3598 detail: { 3599 error: new Error('WebSocket unexpectedly closed'), 3600 } 3601 })); 3602 } 3603 }); 3604 } 3605 3606 /** 3607 * @param {Object} data 3608 */ 3609 async send(data) { 3610 const payload = utf8ToBytes(JSON.stringify(data)); 3611 await this._connection.send(payload); 3612 } 3613 3614 async close() { 3615 this._selfClosed = true; 3616 await this._connection.close(); 3617 try { 3618 // Ensure all queued bytes have been sent before closing the connection. 3619 let tries = 0; 3620 while (this._socket.bufferedAmount > 0) { 3621 if (++tries > CLOSE_FLUSH_BUFFER_MAX_TRIES) { 3622 throw new Error('Could not flush the outgoing buffer in time.'); 3623 } 3624 await new Promise(res => setTimeout(res, CLOSE_FLUSH_BUFFER_INTERVAL_MS)); 3625 } 3626 } finally { 3627 // If the peer hasn't closed, we might still receive some data. 3628 if (this._peerClosed) { 3629 this._shutdown(); 3630 } 3631 } 3632 } 3633 3634 _shutdown() { 3635 if (this._socket) { 3636 this._socket.close(); 3637 this._socket = null; 3638 this._connection = null; 3639 } 3640 } 3641 3642 get closed() { 3643 return (! this._socket) || (this._socket.readyState === 3); 3644 } 3645 3646 get channelId() { 3647 return this._channelId; 3648 } 3649 3650 get channelKey() { 3651 return this._channelKey; 3652 } 3653 } 3654 3655 // Re-export helpful utilities for calling code to use. 3656 3657 3658 // For running tests using the built bundle, 3659 // expose a bunch of implementation details. 3660 3661 3662 3663 3664 3665 3666 3667 const _internals = { 3668 arrayToBytes: arrayToBytes, 3669 BufferReader: utils_BufferReader, 3670 BufferWriter: utils_BufferWriter, 3671 bytesAreEqual: bytesAreEqual, 3672 bytesToHex: bytesToHex, 3673 bytesToUtf8: bytesToUtf8, 3674 ClientConnection: tlsconnection_ClientConnection, 3675 Connection: tlsconnection_Connection, 3676 DecryptionState: recordlayer_DecryptionState, 3677 EncryptedExtensions: EncryptedExtensions, 3678 EncryptionState: recordlayer_EncryptionState, 3679 Finished: messages_Finished, 3680 HASH_LENGTH: HASH_LENGTH, 3681 hexToBytes: hexToBytes, 3682 hkdfExpand: hkdfExpand, 3683 KeySchedule: keyschedule_KeySchedule, 3684 NewSessionTicket: messages_NewSessionTicket, 3685 RecordLayer: recordlayer_RecordLayer, 3686 ServerConnection: tlsconnection_ServerConnection, 3687 utf8ToBytes: utf8ToBytes, 3688 zeros: zeros, 3689 }; 3690 3691 3692 /***/ }) 3693 /******/ ])["PairingChannel"]; 3694 3695 // Keep the windowless browser alive, so that WebSocket doesn't become a 3696 // dead wrapper. 3697 FxAccountsPairingChannel._browser = browser;