lemon-tls 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/wire.js CHANGED
@@ -42,6 +42,17 @@ function is_tls13_wire(v) {
42
42
  return v === TLS_VERSION.TLS1_3 || v === DTLS_VERSION.DTLS1_3;
43
43
  }
44
44
 
45
+ /** A version's node:tls name ('TLSv1.3', 'DTLSv1.2' …), or null. */
46
+ function version_name(v) {
47
+ switch (v) {
48
+ case TLS_VERSION.TLS1_3: return 'TLSv1.3';
49
+ case TLS_VERSION.TLS1_2: return 'TLSv1.2';
50
+ case DTLS_VERSION.DTLS1_3: return 'DTLSv1.3';
51
+ case DTLS_VERSION.DTLS1_2: return 'DTLSv1.2';
52
+ }
53
+ return null;
54
+ }
55
+
45
56
  /** Companion to is_tls13_wire for the 1.2 message format. */
46
57
  function is_tls12_wire(v) {
47
58
  return v === TLS_VERSION.TLS1_2 || v === DTLS_VERSION.DTLS1_2;
@@ -56,8 +67,8 @@ const TLS_CONTENT_TYPE = {
56
67
 
57
68
  // The largest one handshake message may be, as its header declares it, or a
58
69
  // CompressedCertificate decompressed to. OpenSSL allows a ClientHello of
59
- // 128 KB and certificate chains up to 100 KB (max_cert_list); QUIC's CRYPTO
60
- // buffer in QUICO is 64 KB. The 24-bit length would allow 16 MB — memory a
70
+ // 128 KB and certificate chains up to 100 KB (max_cert_list). The 24-bit
71
+ // length would allow 16 MB — memory a
61
72
  // peer could make us hold, or inflate a few hundred bytes into, before it
62
73
  // has proven anything. A maxHandshakeSize below it lowers it.
63
74
  const HANDSHAKE_MESSAGE_MAX = 128 * 1024;
@@ -74,6 +85,7 @@ const TLS_ALERT = {
74
85
  RECORD_OVERFLOW: 22,
75
86
  HANDSHAKE_FAILURE: 40,
76
87
  BAD_CERTIFICATE: 42,
88
+ UNSUPPORTED_CERTIFICATE: 43,
77
89
  CERTIFICATE_EXPIRED: 45,
78
90
  CERTIFICATE_UNKNOWN: 46,
79
91
  ILLEGAL_PARAMETER: 47,
@@ -87,6 +99,7 @@ const TLS_ALERT = {
87
99
  USER_CANCELED: 90,
88
100
  MISSING_EXTENSION: 109,
89
101
  UNSUPPORTED_EXTENSION: 110,
102
+ NO_RENEGOTIATION: 100,
90
103
  UNRECOGNIZED_NAME: 112,
91
104
  CERTIFICATE_REQUIRED: 116,
92
105
  NO_APPLICATION_PROTOCOL: 120,
@@ -99,6 +112,8 @@ const TLS_MESSAGE_TYPE = {
99
112
  NEW_SESSION_TICKET: 4,
100
113
  END_OF_EARLY_DATA: 5,
101
114
  ENCRYPTED_EXTENSIONS: 8,
115
+ REQUEST_CONNECTION_ID: 9, // DTLS 1.3 (RFC 9147 §5.8.4)
116
+ NEW_CONNECTION_ID: 10, // DTLS 1.3 (RFC 9147 §5.8.3)
102
117
  CERTIFICATE: 11,
103
118
  SERVER_KEY_EXCHANGE: 12,
104
119
  CERTIFICATE_REQUEST: 13,
@@ -136,6 +151,7 @@ const TLS_EXT = {
136
151
  PADDING: 21,
137
152
  EXTENDED_MASTER_SECRET: 23,
138
153
  COMPRESS_CERTIFICATE: 27, // RFC 8879
154
+ RECORD_SIZE_LIMIT: 28, // RFC 8449
139
155
  SESSION_TICKET: 35,
140
156
  PRE_SHARED_KEY: 41,
141
157
  EARLY_DATA: 42,
@@ -147,6 +163,7 @@ const TLS_EXT = {
147
163
  POST_HANDSHAKE_AUTH: 49,
148
164
  SIGNATURE_ALGORITHMS_CERT: 50,
149
165
  KEY_SHARE: 51,
166
+ CONNECTION_ID: 54, // RFC 9146 (DTLS)
150
167
  RENEGOTIATION_INFO: 0xFF01
151
168
  };
152
169
 
@@ -295,6 +312,27 @@ function veclen(lenBytes, inner) {
295
312
  throw new Error('veclen only supports 1/2/3');
296
313
  }
297
314
 
315
+ /**
316
+ * A list of fixed-size items — u8 or u16 each — in a vector that fills the
317
+ * extension exactly (RFC 8446 §3.4): declared length = what follows it, a
318
+ * whole number of items, at least `min` of them (the vector's floor:
319
+ * `<2..2^16-2>` is one u16 item). One reader for every such list, since each
320
+ * decoder had its own loop that read past the declared length, accepted an
321
+ * odd length, an empty list, or bytes after it.
322
+ */
323
+ function readItemList(data, lenBytes, itemBytes, min, name) {
324
+ let n, off;
325
+ [n, off] = lenBytes === 1 ? r_u8(data, 0) : r_u16(data, 0);
326
+ if (off + n !== data.length) throw parseError(name + ': list of ' + n + ' bytes in an extension of ' + (data.length - off));
327
+ if (n % itemBytes !== 0) throw parseError(name + ': list of ' + n + ' bytes, not a whole number of items');
328
+ if (n / itemBytes < min) throw parseError(name + ': empty list');
329
+ let out = [];
330
+ for (let i = 0; i < n; i += itemBytes) {
331
+ out.push(itemBytes === 2 ? ((data[off + i] << 8) | data[off + i + 1]) >>> 0 : data[off + i]);
332
+ }
333
+ return out;
334
+ }
335
+
298
336
  function readVec(buf, off, lenBytes) {
299
337
  let n, off2 = off;
300
338
 
@@ -346,8 +384,29 @@ exts.STATUS_REQUEST.encode = function (value) {
346
384
  if (value && value.ocsp) return new Uint8Array([1, 0, 0, 0, 0]);
347
385
  return new Uint8Array(0);
348
386
  };
349
- exts.STATUS_REQUEST.decode = function (data) {
350
- if (data.length === 0) return {};
387
+ // RFC 6066 §8. In a ServerHello (TLS 1.2) the extension_data is empty: a
388
+ // bare "a CertificateStatus follows". In a ClientHello, a
389
+ // CertificateStatusRequest: status_type, then for ocsp(1) responder_id_list
390
+ // <0..2^16-1> and request_extensions<0..2^16-1>, and nothing after them. Bytes
391
+ // left over were taken as an offer all the same.
392
+ exts.STATUS_REQUEST.decode = function (data, kind) {
393
+ if (kind === 'server_hello') {
394
+ if (data.length !== 0) throw parseError('status_request: ' + data.length + ' bytes in a ServerHello, which carries none');
395
+ return {};
396
+ }
397
+ // Elsewhere (a TLS 1.3 Certificate entry holds a CertificateStatus, read
398
+ // by parse_certificate_status; a CertificateRequest's is empty).
399
+ if (kind !== 'client_hello') return data.length === 0 ? {} : { status_type: data[0] };
400
+ if (data.length === 0) throw parseError('status_request: empty');
401
+ if (data[0] === 1) {
402
+ let off = 1;
403
+ for (let v = 0; v < 2; v++) {
404
+ if (off + 2 > data.length) throw parseError('status_request: truncated');
405
+ off += 2 + ((data[off] << 8) | data[off + 1]);
406
+ if (off > data.length) throw parseError('status_request: truncated');
407
+ }
408
+ if (off !== data.length) throw parseError('status_request: ' + (data.length - off) + ' trailing bytes');
409
+ }
351
410
  return { status_type: data[0] };
352
411
  };
353
412
 
@@ -484,12 +543,19 @@ exts.SERVER_NAME.decode = function (data) {
484
543
  // other half of the grammar.
485
544
  if (!data || data.length === 0) return null;
486
545
 
546
+ // From a client: server_name_list<1..2^16-1> filling the extension, each
547
+ // name non-empty (HostName<1..2^16-1>), at most one of each name_type
548
+ // (RFC 6066 §3). A list cut short, overrunning, with bytes after it, an
549
+ // empty host_name or two of them were all taken.
487
550
  let off = 0;
488
551
  let list;
489
552
  [list, off] = readVec(data, off, 2);
553
+ if (off !== data.length) throw parseError('server_name: bytes after the server_name_list');
554
+ if (list.length === 0) throw parseError('server_name: empty server_name_list');
490
555
 
491
556
  let off2 = 0;
492
557
  let host = "";
558
+ let seenTypes = {};
493
559
 
494
560
  while (off2 < list.length) {
495
561
  let typ;
@@ -501,7 +567,10 @@ exts.SERVER_NAME.decode = function (data) {
501
567
  let v;
502
568
  [v, off2] = r_bytes(list, off2, l);
503
569
 
570
+ if (seenTypes[typ]) throw parseError('server_name: two names of type ' + typ);
571
+ seenTypes[typ] = true;
504
572
  if (typ === 0) {
573
+ if (l === 0) throw parseError('server_name: empty host_name');
505
574
  host = (new TextDecoder()).decode(v);
506
575
  }
507
576
  }
@@ -533,26 +602,12 @@ exts.SUPPORTED_VERSIONS.encode = function (value) {
533
602
  return body;
534
603
  };
535
604
 
536
- exts.SUPPORTED_VERSIONS.decode = function (data) {
537
- // ServerHello form: 2 bytes
538
- if (data.length === 2) {
539
- let v, off = 0;
540
- [v, off] = r_u16(data, off);
541
- return [v]; // return the selected version (number)
542
- }
543
-
544
- // ClientHello form: vector<1> of versions (u16 each)
545
- let off2 = 0;
546
- let n;
547
- [n, off2] = r_u8(data, off2);
548
-
549
- let out = [];
550
- for (let i = 0; i < n; i += 2) {
551
- let vv;
552
- [vv, off2] = r_u16(data, off2);
553
- out.push(vv);
554
- }
555
- return out; // return the array directly
605
+ exts.SUPPORTED_VERSIONS.decode = function (data, kind) {
606
+ // ClientHello form: versions<2..254>, one u16 each.
607
+ if (kind === 'client_hello') return readItemList(data, 1, 2, 1, 'supported_versions');
608
+ // ServerHello / HelloRetryRequest form: selected_version, 2 bytes.
609
+ if (data.length !== 2) throw parseError('supported_versions: selected_version of ' + data.length + ' bytes');
610
+ return [((data[0] << 8) | data[1]) >>> 0];
556
611
  };
557
612
 
558
613
  /* ---------------------------- SUPPORTED_GROUPS (10) ---------------------------- */
@@ -570,17 +625,7 @@ exts.SUPPORTED_GROUPS.encode = function (value) {
570
625
  };
571
626
 
572
627
  exts.SUPPORTED_GROUPS.decode = function (data) {
573
- let off = 0;
574
- let n;
575
- [n, off] = r_u16(data, off);
576
-
577
- let out = [];
578
- for (let i = 0; i < n; i += 2) {
579
- let g;
580
- [g, off] = r_u16(data, off);
581
- out.push(g);
582
- }
583
- return out; // array of named groups
628
+ return readItemList(data, 2, 2, 1, 'supported_groups'); // named_group_list<2..2^16-1>
584
629
  };
585
630
 
586
631
  /* ---------------------------- EC_POINT_FORMATS (11) ---------------------------- */
@@ -624,17 +669,8 @@ exts.SIGNATURE_ALGORITHMS.encode = function (value) {
624
669
  };
625
670
 
626
671
  exts.SIGNATURE_ALGORITHMS.decode = function (data) {
627
- let off = 0;
628
- let n;
629
- [n, off] = r_u16(data, off);
630
-
631
- let out = [];
632
- for (let i = 0; i < n; i += 2) {
633
- let a;
634
- [a, off] = r_u16(data, off);
635
- out.push(a);
636
- }
637
- return out; // array of sigalgs (u16)
672
+ // supported_signature_algorithms<2..2^16-2>: an empty or odd list was taken.
673
+ return readItemList(data, 2, 2, 1, 'signature_algorithms');
638
674
  };
639
675
 
640
676
  /* ------------------------ PSK_KEY_EXCHANGE_MODES (45) ------------------------ */
@@ -652,17 +688,7 @@ exts.PSK_KEY_EXCHANGE_MODES.encode = function (value) {
652
688
  };
653
689
 
654
690
  exts.PSK_KEY_EXCHANGE_MODES.decode = function (data) {
655
- let off = 0;
656
- let n;
657
- [n, off] = r_u8(data, off);
658
-
659
- let out = [];
660
- for (let i = 0; i < n; i++) {
661
- let m;
662
- [m, off] = r_u8(data, off);
663
- out.push(m);
664
- }
665
- return out; // array of modes (u8)
691
+ return readItemList(data, 1, 1, 1, 'psk_key_exchange_modes'); // ke_modes<1..255>
666
692
  };
667
693
 
668
694
  /* ------------------------------- PRE_SHARED_KEY (41) ------------------------------- */
@@ -730,28 +756,37 @@ exts.PRE_SHARED_KEY.decode = function (data) {
730
756
  return { selected: sel };
731
757
  }
732
758
 
733
- // ClientHello: identities + binders
759
+ // ClientHello: identities<7..2^16-1>, then binders<33..2^16-1>, which
760
+ // fill the rest exactly (RFC 8446 §4.2.11): PskIdentity is identity<1..>
761
+ // and a 4-byte age; PskBinderEntry<32..255>.
734
762
  let idLen;
735
763
  [idLen, off] = r_u16(data, off);
736
764
  let idEnd = off + idLen;
765
+ if (idEnd > data.length) throw parseError('pre_shared_key: identities overrun the extension');
737
766
  let identities = [];
738
767
  while (off < idEnd) {
739
768
  let idL;
740
769
  [idL, off] = r_u16(data, off);
770
+ if (idL === 0) throw parseError('pre_shared_key: empty identity');
771
+ if (off + idL + 4 > idEnd) throw parseError('pre_shared_key: an identity overruns the list');
741
772
  let identity;
742
773
  [identity, off] = r_bytes(data, off, idL);
743
774
  let age = (data[off] << 24) | (data[off+1] << 16) | (data[off+2] << 8) | data[off+3];
744
775
  off += 4;
745
776
  identities.push({ identity: identity, age: age >>> 0 });
746
777
  }
778
+ if (identities.length === 0) throw parseError('pre_shared_key: no identities');
747
779
 
748
780
  let binderLen;
749
781
  [binderLen, off] = r_u16(data, off);
750
782
  let binderEnd = off + binderLen;
783
+ if (binderEnd !== data.length) throw parseError('pre_shared_key: binders do not fill the extension');
751
784
  let binders = [];
752
785
  while (off < binderEnd) {
753
786
  let bL;
754
787
  [bL, off] = r_u8(data, off);
788
+ if (bL < 32) throw parseError('pre_shared_key: binder of ' + bL + ' bytes, fewer than 32');
789
+ if (off + bL > binderEnd) throw parseError('pre_shared_key: a binder overruns the list');
755
790
  let binder;
756
791
  [binder, off] = r_bytes(data, off, bL);
757
792
  binders.push(binder);
@@ -893,6 +928,7 @@ exts.ALPN.decode = function (data) {
893
928
  let end = off + n;
894
929
  if (end > data.length) throw parseError('ALPN list length exceeds extension body');
895
930
  if (end < data.length) throw parseError('trailing data after ALPN protocol list');
931
+ if (n === 0) throw parseError('ALPN: empty protocol_name_list'); // <2..2^16-1>
896
932
 
897
933
  let out = [];
898
934
 
@@ -927,6 +963,7 @@ exts.RENEGOTIATION_INFO.decode = function (data) {
927
963
  let off = 0;
928
964
  let v;
929
965
  [v, off] = readVec(data, off, 1);
966
+ if (off !== data.length) throw parseError('renegotiation_info: bytes after renegotiated_connection');
930
967
  return v; // return raw bytes (Uint8Array)
931
968
  };
932
969
 
@@ -940,6 +977,7 @@ exts.COOKIE.decode = function (data) {
940
977
  let off = 0;
941
978
  let v;
942
979
  [v, off] = readVec(data, off, 2);
980
+ if (off !== data.length || v.length === 0) throw parseError('cookie: not one non-empty cookie<1..2^16-1>');
943
981
  return v; // Uint8Array — opaque cookie
944
982
  };
945
983
 
@@ -962,6 +1000,8 @@ exts.EXTENDED_MASTER_SECRET.encode = function (value) {
962
1000
  };
963
1001
 
964
1002
  exts.EXTENDED_MASTER_SECRET.decode = function (data) {
1003
+ // "extension_data field ... is empty" (RFC 7627 §5.1).
1004
+ if (data && data.length !== 0) throw parseError('extended_master_secret with ' + data.length + ' bytes of data');
965
1005
  return true; // presence is the signal
966
1006
  };
967
1007
  /* ============================= Extensions helpers ============================= */
@@ -1201,15 +1241,21 @@ function parse_hello(params) {
1201
1241
  let legacy_version; [legacy_version, off] = r_u16(body, off);
1202
1242
  let random; [random, off] = r_bytes(body, off, 32);
1203
1243
  let sidLen; [sidLen, off] = r_u8(body, off);
1244
+ // legacy_session_id<0..32> (RFC 8446 §4.1.2, RFC 5246 §7.4.1.2).
1245
+ if (sidLen > 32) throw parseError('session_id of ' + sidLen + ' bytes, more than 32');
1204
1246
  let session_id; [session_id, off] = r_bytes(body, off, sidLen);
1205
1247
 
1206
1248
  let cipher_suites = [];
1207
1249
  let legacy_compression = [];
1208
1250
  let type = isClient ? 'client_hello' : 'server_hello';
1209
1251
 
1210
- // DTLS cookie — auto-detect by version (DTLS versions have 0xFE in high byte)
1252
+ // DTLS or TLS: the transport's to say (params.dtls), not the hello's — a
1253
+ // TLS ClientHello with legacy_version (254,254) was read as a DTLS one, a
1254
+ // cookie field looked for where the cipher suites are: decode_error, for a
1255
+ // hello that offers TLS 1.2. Guessed from the version only when the caller
1256
+ // does not say.
1211
1257
  let dtls_cookie = null;
1212
- let isDTLS = (legacy_version & 0xFF00) === 0xFE00;
1258
+ let isDTLS = (typeof params.dtls === 'boolean') ? params.dtls : (legacy_version & 0xFF00) === 0xFE00;
1213
1259
 
1214
1260
  if (isClient) {
1215
1261
  // --- ClientHello ---
@@ -1221,7 +1267,17 @@ function parse_hello(params) {
1221
1267
  }
1222
1268
  }
1223
1269
 
1270
+ // cipher_suites<2..2^16-2> (RFC 8446 §4.1.2, RFC 5246 §7.4.1.2): never
1271
+ // empty, whole suites only, inside the message. An empty list was taken
1272
+ // (and the server, with nothing to choose, sent nothing); an odd length
1273
+ // read a byte past it.
1274
+ // (params.lenient: a hello read to be fingerprinted — JA4 has a form
1275
+ // for an empty list — not to be answered.)
1224
1276
  let csLen; [csLen, off] = r_u16(body, off);
1277
+ if (off + csLen > body.length || (!params.lenient && (csLen < 2 || (csLen & 1) !== 0))) {
1278
+ throw parseError('ClientHello cipher_suites: length ' + csLen);
1279
+ }
1280
+ if (params.lenient) csLen -= csLen & 1;
1225
1281
  let csEnd = off + csLen;
1226
1282
  while (off < csEnd) {
1227
1283
  let cs; [cs, off] = r_u16(body, off);
@@ -1261,6 +1317,7 @@ function parse_hello(params) {
1261
1317
  random: random, // single (Uint8Array(32))
1262
1318
  session_id: session_id, // single (Uint8Array)
1263
1319
  dtls_cookie: dtls_cookie, // Uint8Array or null (DTLS only)
1320
+ dtls: isDTLS,
1264
1321
  cipher_suites: cipher_suites, // array
1265
1322
  legacy_compression: legacy_compression, // array
1266
1323
  extensions: extensions // array
@@ -1396,73 +1453,49 @@ function parse_compressed_certificate(body) {
1396
1453
  return { algorithm: algorithm, uncompressed_length: uncompressed_length, compressed: body.subarray(8) };
1397
1454
  }
1398
1455
 
1399
- function parse_certificate(body) {
1400
- // always returns:
1401
- // {
1402
- // version: TLS_VERSION.TLS1_2 | TLS_VERSION.TLS1_3,
1403
- // request_context?: Uint8Array, // רק ב-1.3
1404
- // entries: [ { cert: Uint8Array, extensions?: any[] } ] // ב-1.2 אין extensions
1405
- // }
1406
-
1407
- // Try to detect TLS 1.3: rc(vec<1>) ואז list(vec<3> של [cert(vec<3>) || exts(vec<2>)]*)
1408
- if (body && body.length >= 4) {
1409
- let off = 0;
1410
- let rcLen; [rcLen, off] = r_u8(body, off); // 1 byte
1411
- const afterCtx = off + rcLen; // off מצביע אחרי rcLen (כלומר 1)
1412
- if (afterCtx + 3 <= body.length) {
1413
- let listLen, off2 = afterCtx; // התחלת certificate_list
1414
- [listLen, off2] = r_u24(body, off2); // 3 bytes
1415
- if (afterCtx + 3 + listLen === body.length) {
1416
- // looks like valid TLS 1.3
1417
- const request_context = body.subarray(off, off + rcLen);
1418
- off = off2;
1419
- const end = off2 + listLen;
1420
-
1421
- const entries = [];
1422
- while (off < end) {
1423
- let certLen; [certLen, off] = r_u24(body, off); // cert_data vec<3>
1424
- let cert; [cert, off] = r_bytes(body, off, certLen);
1425
-
1426
- let extLen; [extLen, off] = r_u16(body, off); // extensions vec<2>
1427
- let extRaw; [extRaw, off] = r_bytes(body, off, extLen);
1428
-
1429
- // extRaw is the list body (prefix already consumed above), so use
1430
- // the list parser — parse_extensions() would misread the first two
1431
- // bytes of the first extension as a vector length.
1432
- const extensions = parse_extension_list(extRaw);
1433
- entries.push({ cert, extensions });
1434
- }
1435
-
1436
- return {
1437
- version: TLS_VERSION.TLS1_3,
1438
- request_context,
1439
- entries
1440
- };
1441
- }
1442
- }
1456
+ /**
1457
+ * A Certificate message's body, as the version negotiated has it:
1458
+ * TLS 1.3 (RFC 8446 §4.4.2): certificate_request_context<0..2^8-1>, then
1459
+ * certificate_list<0..2^24-1> of { cert_data<1..2^24-1>,
1460
+ * extensions<0..2^16-1> };
1461
+ * TLS 1.2 (RFC 5246 §7.4.2): certificate_list<0..2^24-1> of
1462
+ * ASN.1Cert<1..2^24-1>.
1463
+ * Every length exact — the list ends the message, each entry inside the
1464
+ * list — or decode_error.
1465
+ *
1466
+ * The version was guessed from the bytes: a body that read as 1.3 was
1467
+ * taken as 1.3, and anything else as 1.2 with its list length unchecked
1468
+ * ("graceful recovery") — a TLS 1.2 Certificate whose length was wrong was
1469
+ * taken (tlsfuzzer). The session always knows which it negotiated.
1470
+ *
1471
+ * Returns { version, request_context? (1.3), entries: [{ cert,
1472
+ * extensions? (1.3) }] }.
1473
+ */
1474
+ function parse_certificate(body, tls13) {
1475
+ let off = 0, request_context;
1476
+ if (tls13) {
1477
+ let rcLen; [rcLen, off] = r_u8(body, off);
1478
+ [request_context, off] = r_bytes(body, off, rcLen);
1443
1479
  }
1444
-
1445
- // otherwise: TLS 1.2 — certificate_list(vec<3>) של cert(vec<3>)* ללא הרחבות
1446
- let off3 = 0;
1447
- let listLen2; [listLen2, off3] = r_u24(body, off3);
1448
-
1449
- const end2 = off3 + listLen2;
1450
- if (end2 !== body.length) {
1451
- // graceful recovery: אם האורך לא תואם, ננסה לפחות לא לקרוס (אפשר גם לזרוק שגיאה)
1452
- // throw new Error('Bad TLS1.2 Certificate length');
1480
+ let listLen; [listLen, off] = r_u24(body, off);
1481
+ if (off + listLen !== body.length) {
1482
+ throw parseError('Certificate: certificate_list of ' + listLen + ' bytes in ' + (body.length - off));
1453
1483
  }
1454
-
1455
- const entries12 = [];
1456
- while (off3 < Math.min(end2, body.length)) {
1457
- let len3; [len3, off3] = r_u24(body, off3);
1458
- let cert; [cert, off3] = r_bytes(body, off3, len3);
1459
- entries12.push({ cert }); // no per-entry extensions in 1.2
1484
+ const entries = [];
1485
+ while (off < body.length) {
1486
+ let certLen; [certLen, off] = r_u24(body, off);
1487
+ if (certLen === 0) throw parseError('Certificate: an empty certificate in the list');
1488
+ let cert; [cert, off] = r_bytes(body, off, certLen);
1489
+ if (!tls13) { entries.push({ cert }); continue; }
1490
+ let extLen; [extLen, off] = r_u16(body, off);
1491
+ let extRaw; [extRaw, off] = r_bytes(body, off, extLen);
1492
+ // extRaw is the list body (prefix already consumed above), so use
1493
+ // the list parser — parse_extensions() would misread the first two
1494
+ // bytes of the first extension as a vector length.
1495
+ entries.push({ cert, extensions: parse_extension_list(extRaw) });
1460
1496
  }
1461
-
1462
- return {
1463
- version: TLS_VERSION.TLS1_2,
1464
- entries: entries12
1465
- };
1497
+ return tls13 ? { version: TLS_VERSION.TLS1_3, request_context, entries }
1498
+ : { version: TLS_VERSION.TLS1_2, entries };
1466
1499
  }
1467
1500
 
1468
1501
 
@@ -1499,7 +1532,9 @@ function parse_certificate_verify(body) {
1499
1532
 
1500
1533
  // The signature vector ends the message; anything after it is framing junk.
1501
1534
  if (off !== body.length) throw parseError('trailing data after CertificateVerify signature');
1502
- if (slen === 0) throw parseError('empty CertificateVerify signature');
1535
+ // An empty signature is well formed (signature<0..2^16-1>, RFC 8446
1536
+ // §4.4.3; RFC 5246 §4.7) and does not verify: decrypt_error, from the
1537
+ // check — not decode_error here (tlsfuzzer).
1503
1538
 
1504
1539
  return { scheme: alg, signature: sig };
1505
1540
  }
@@ -1548,6 +1583,8 @@ function build_new_session_ticket(p) {
1548
1583
  function parse_new_session_ticket(body) {
1549
1584
  let off = 0;
1550
1585
 
1586
+ // The two u32s were read without a bounds check: a short body read as 0s.
1587
+ if (body.length < 8) throw parseError('NewSessionTicket: truncated');
1551
1588
  let lifetime = (body[off]<<24 | body[off+1]<<16 | body[off+2]<<8 | body[off+3]) >>> 0; off+=4;
1552
1589
  let age_add = (body[off]<<24 | body[off+1]<<16 | body[off+2]<<8 | body[off+3]) >>> 0; off+=4;
1553
1590
 
@@ -1567,8 +1604,10 @@ function parse_new_session_ticket(body) {
1567
1604
  // format; what a session then DOES with a ticket is policy and lives above.
1568
1605
  if (tlen === 0) throw parseError('NewSessionTicket carries an empty ticket');
1569
1606
 
1570
- let extBuf = body.subarray(off);
1571
- let extensions = extBuf.length ? parse_extensions(extBuf) : [];
1607
+ // extensions<0..2^16-2> is part of the structure (RFC 8446 §4.6.1): it
1608
+ // must be there, and it ends the message (parse_extensions refuses bytes
1609
+ // after it). A body that stopped after the ticket passed as "no extensions".
1610
+ let extensions = parse_extensions(body.subarray(off));
1572
1611
 
1573
1612
  return {
1574
1613
  ticket_lifetime: lifetime,
@@ -1757,7 +1796,10 @@ function build_hello_retry_request(params) {
1757
1796
  // params: { cipher_suite, selected_version, selected_group, session_id?, cookie?, other_exts? }
1758
1797
  let rnd = TLS13_HRR_RANDOM;
1759
1798
  let sid = (params && params.session_id) ? toU8(params.session_id) : new Uint8Array(0);
1760
- let legacy_version = TLS_VERSION.TLS1_2;
1799
+ // The HelloRetryRequest is a ServerHello (RFC 8446 §4.1.4), with the same
1800
+ // legacy_version: 0x0303 over TLS, {254,253} over DTLS 1.3 (RFC 9147 §5.3).
1801
+ let legacy_version = (params && params.selected_version === DTLS_VERSION.DTLS1_3)
1802
+ ? DTLS_VERSION.DTLS1_2 : TLS_VERSION.TLS1_2;
1761
1803
 
1762
1804
  let extList = [];
1763
1805
  // supported_versions (selected)
@@ -1850,31 +1892,10 @@ function parse_server_key_exchange(body) {
1850
1892
  return { kex: 'ECDHE', group: group, public_key: pub, sig_alg: sig_alg, signature: sig };
1851
1893
  }
1852
1894
 
1853
- // Basic DHE: dh_p<2>, dh_g<2>, dh_Ys<2>, then SignatureAndHashAlgorithm + signature<2>
1854
- let pLen;
1855
- [pLen, off] = r_u16(body, off);
1856
- let dh_p;
1857
- [dh_p, off] = r_bytes(body, off, pLen);
1858
-
1859
- let gLen;
1860
- [gLen, off] = r_u16(body, off);
1861
- let dh_g;
1862
- [dh_g, off] = r_bytes(body, off, gLen);
1863
-
1864
- let yLen;
1865
- [yLen, off] = r_u16(body, off);
1866
- let dh_Ys;
1867
- [dh_Ys, off] = r_bytes(body, off, yLen);
1868
-
1869
- let sig_alg2;
1870
- [sig_alg2, off] = r_u16(body, off);
1871
-
1872
- let s2len;
1873
- [s2len, off] = r_u16(body, off);
1874
- let sig2;
1875
- [sig2, off] = r_bytes(body, off, s2len);
1876
-
1877
- return { kex: 'DHE', dh_p: dh_p, dh_g: dh_g, dh_Ys: dh_Ys, sig_alg: sig_alg2, signature: sig2 };
1895
+ // Not a named curve (RFC 8422 §5.4: the only ECCurveType a TLS 1.2 ECDHE
1896
+ // ServerKeyExchange may carry). DHE parameters were read here once — from
1897
+ // the wrong offset — for suites this library no longer has.
1898
+ throw parseError('ServerKeyExchange: ECCurveType ' + curve_type + ', not named_curve', TLS_ALERT.ILLEGAL_PARAMETER);
1878
1899
  }
1879
1900
 
1880
1901
  /* ============================== TLS 1.2 ClientKeyExchange ============================== */
@@ -1915,10 +1936,13 @@ function build_new_session_ticket_tls12(p) {
1915
1936
  off = w_bytes(out, off, ticket);
1916
1937
  return out;
1917
1938
  }
1939
+ // RFC 5077 §3.3: ticket_lifetime_hint, ticket<0..2^16-1>, nothing after.
1918
1940
  function parse_new_session_ticket_tls12(body) {
1919
1941
  let off=0;
1942
+ if (body.length < 4) throw parseError('NewSessionTicket: truncated');
1920
1943
  let hint = (body[off]<<24 | body[off+1]<<16 | body[off+2]<<8 | body[off+3])>>>0; off+=4;
1921
1944
  let tlen; [tlen,off]=r_u16(body,off); let t; [t,off]=r_bytes(body,off,tlen);
1945
+ if (off !== body.length) throw parseError('NewSessionTicket: ' + (body.length - off) + ' trailing bytes');
1922
1946
  return { ticket_lifetime_hint: hint, ticket: t };
1923
1947
  }
1924
1948
 
@@ -1977,11 +2001,14 @@ function build_key_update(request_update) {
1977
2001
  }
1978
2002
 
1979
2003
  /**
1980
- * Parse KeyUpdate message body.
1981
- * Returns { request_update: 0|1 }
2004
+ * Parse KeyUpdate message body (RFC 8446 §4.6.3): one byte, 0 or 1.
2005
+ * Returns { request_update: 0|1 }. Another length: decode_error; another
2006
+ * value: illegal_parameter ("MUST" — it was read as 0, and a 2 passed).
1982
2007
  */
1983
2008
  function parse_key_update(body) {
1984
- return { request_update: body[0] || 0 };
2009
+ if (!body || body.length !== 1) throw parseError('KeyUpdate of ' + (body ? body.length : 0) + ' bytes, not 1');
2010
+ if (body[0] > 1) throw parseError('KeyUpdate request_update ' + body[0] + ', not 0 or 1', TLS_ALERT.ILLEGAL_PARAMETER);
2011
+ return { request_update: body[0] };
1985
2012
  }
1986
2013
 
1987
2014
 
@@ -2004,15 +2031,22 @@ function build_dtls_handshake(tls_msg, msg_seq, frag_offset, frag_length) {
2004
2031
  if (frag_offset === undefined) frag_offset = 0;
2005
2032
  if (frag_length === undefined) frag_length = body.length;
2006
2033
 
2007
- let frag_body = body.subarray(frag_offset, frag_offset + frag_length);
2034
+ return build_dtls_fragment(type, total_length, msg_seq, frag_offset, body.subarray(frag_offset, frag_offset + frag_length));
2035
+ }
2008
2036
 
2037
+ /**
2038
+ * One fragment of a DTLS handshake message (RFC 6347 §4.2.2, RFC 9147
2039
+ * §5.2): its 12-byte header — type, the whole message's length, message_seq,
2040
+ * the fragment's offset and length — and its bytes.
2041
+ */
2042
+ function build_dtls_fragment(type, total_length, msg_seq, frag_offset, frag_body) {
2009
2043
  let out = new Uint8Array(12 + frag_body.length);
2010
2044
  let off = 0;
2011
2045
  off = w_u8(out, off, type);
2012
2046
  off = w_u24(out, off, total_length);
2013
2047
  off = w_u16(out, off, msg_seq);
2014
2048
  off = w_u24(out, off, frag_offset);
2015
- off = w_u24(out, off, frag_length);
2049
+ off = w_u24(out, off, frag_body.length);
2016
2050
  off = w_bytes(out, off, frag_body);
2017
2051
  return out;
2018
2052
  }
@@ -2054,23 +2088,102 @@ function build_hello_verify_request(params) {
2054
2088
  * Parse HelloVerifyRequest body.
2055
2089
  * Returns { server_version, cookie }.
2056
2090
  */
2091
+ // RFC 6347 §4.2.1: server_version, then cookie<0..2^8-1> — and nothing
2092
+ // after it (decode_error). Trailing bytes were ignored.
2057
2093
  function parse_hello_verify_request(body) {
2058
2094
  let off = 0;
2059
2095
  let server_version; [server_version, off] = r_u16(body, off);
2060
2096
  let cookieLen; [cookieLen, off] = r_u8(body, off);
2061
2097
  let cookie = new Uint8Array(0);
2062
2098
  if (cookieLen > 0) { [cookie, off] = r_bytes(body, off, cookieLen); }
2099
+ if (off !== body.length) throw parseError('HelloVerifyRequest: ' + (body.length - off) + ' trailing bytes');
2063
2100
  return { server_version, cookie };
2064
2101
  }
2065
2102
 
2066
2103
 
2067
2104
  /* ================================ Exports ================================= */
2105
+
2106
+ // Warning alerts taken in a row, nothing else between: BoringSSL's limit
2107
+ // (BoGo TooManyWarningAlerts).
2108
+ const MAX_WARNING_ALERTS = 4;
2109
+
2110
+ // The most plaintext a record carries (RFC 8446 §5.1, RFC 5246 §6.2.1):
2111
+ // 2^14 — TLS and DTLS, both directions. One constant for every layer that
2112
+ // cuts or checks records (TLSSession, TLSSocket, DTLSSession).
2113
+ const MAX_RECORD_PLAINTEXT = 16384;
2114
+
2115
+ /**
2116
+ * What an alert record from the peer says — one reading for TLS over TCP and
2117
+ * DTLS, which each had their own and disagreed (an empty alert, a level that
2118
+ * is neither, user_canceled at the fatal level). Two bytes, a level of 1 or
2119
+ * 2 (RFC 8446 §6, RFC 5246 §7.2); an empty one is a zero-length fragment
2120
+ * (§5.1 forbids them for alerts): unexpected_message; another length,
2121
+ * decode_error; another level, illegal_parameter — each as
2122
+ * { error: { alert, message } }. Otherwise { level, desc, fatal }:
2123
+ * in TLS 1.3 every alert but close_notify and user_canceled is fatal,
2124
+ * "regardless of the AlertLevel" (§6.2, §6); before it, the level says.
2125
+ */
2126
+ function read_peer_alert(body, is13) {
2127
+ if (!body || body.length === 0) return { error: { alert: TLS_ALERT.UNEXPECTED_MESSAGE, message: 'empty alert record' } };
2128
+ if (body.length !== 2) return { error: { alert: TLS_ALERT.DECODE_ERROR, message: 'alert of ' + body.length + ' bytes, not 2' } };
2129
+ let level = body[0], desc = body[1];
2130
+ if (level !== TLS_ALERT_LEVEL.WARNING && level !== TLS_ALERT_LEVEL.FATAL) {
2131
+ return { error: { alert: TLS_ALERT.ILLEGAL_PARAMETER, message: 'alert of level ' + level } };
2132
+ }
2133
+ let fatal = is13 ? (desc !== TLS_ALERT.CLOSE_NOTIFY && desc !== TLS_ALERT.USER_CANCELED) : level === TLS_ALERT_LEVEL.FATAL;
2134
+ return { level: level, desc: desc, fatal: fatal };
2135
+ }
2136
+
2137
+ // An alert's name, lowercase as the RFC writes it ('record_overflow'), or null.
2138
+ function alert_name(desc) {
2139
+ for (const k in TLS_ALERT) if (TLS_ALERT[k] === desc) return k.toLowerCase();
2140
+ return null;
2141
+ }
2142
+
2143
+ /**
2144
+ * A fatal alert of OURS, as every layer reports it — TLSSession, TLSSocket
2145
+ * and DTLSSession alike, which gave a bare Error, one with a code, and one
2146
+ * with neither: the message, err.alert (what we sent), err.code —
2147
+ * ERR_SSL_<ALERT> (OpenSSL's reason codes as node:tls has them:
2148
+ * ERR_SSL_RECORD_OVERFLOW, ERR_SSL_UNEXPECTED_MESSAGE …) unless a more
2149
+ * precise one is given (ERR_TLS_CERT_PIN_MISMATCH). An error that already
2150
+ * has them keeps its own.
2151
+ */
2152
+ function local_alert_error(desc, message, code) {
2153
+ const err = message instanceof Error ? message : new Error(message);
2154
+ if (err.alert === undefined) err.alert = desc;
2155
+ if (!err.code) err.code = code || ('ERR_SSL_' + (alert_name(desc) || 'alert_' + desc).toUpperCase());
2156
+ return err;
2157
+ }
2158
+
2159
+ /**
2160
+ * A fatal alert the peer sent, as the error both transports report it — TLS
2161
+ * over TCP and DTLS alike: 'peer sent fatal alert: <name> (<code>)',
2162
+ * code ERR_TLS_ALERT_RECEIVED, err.alert the code. DTLS reported
2163
+ * 'DTLS alert: level=2 desc=121', no code, no name.
2164
+ */
2165
+ function peer_alert_error(desc) {
2166
+ const err = new Error('peer sent fatal alert: ' + (alert_name(desc) || 'alert') + ' (' + desc + ')');
2167
+ err.code = 'ERR_TLS_ALERT_RECEIVED';
2168
+ err.alert = desc;
2169
+ return err;
2170
+ }
2171
+
2068
2172
  export {
2173
+ build_dtls_fragment,
2174
+ parseError,
2175
+ local_alert_error,
2176
+ alert_name,
2177
+ peer_alert_error,
2178
+ read_peer_alert,
2179
+ MAX_WARNING_ALERTS,
2180
+ MAX_RECORD_PLAINTEXT,
2069
2181
  HANDSHAKE_MESSAGE_MAX,
2070
2182
  TLS_VERSION,
2071
2183
  DTLS_VERSION,
2072
2184
  is_tls13_wire,
2073
2185
  is_tls12_wire,
2186
+ version_name,
2074
2187
  TLS_CONTENT_TYPE,
2075
2188
  TLS_ALERT_LEVEL,
2076
2189
  TLS_ALERT,