lemon-tls 0.2.1 → 0.2.2

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
@@ -11,6 +11,12 @@ const TLS_VERSION = {
11
11
  TLS1_3: 0x0304
12
12
  };
13
13
 
14
+ const DTLS_VERSION = {
15
+ DTLS1_0: 0xFEFF,
16
+ DTLS1_2: 0xFEFD,
17
+ DTLS1_3: 0xFEFC
18
+ };
19
+
14
20
  const TLS_CONTENT_TYPE = {
15
21
  CHANGE_CIPHER_SPEC: 20,
16
22
  ALERT: 21,
@@ -125,6 +131,18 @@ function w_u24(buf, off, v) {
125
131
  return off;
126
132
  }
127
133
 
134
+ function w_u48(buf, off, v) {
135
+ let hi = Math.floor(v / 0x100000000);
136
+ let lo = v >>> 0;
137
+ buf[off++] = (hi >>> 8) & 0xFF;
138
+ buf[off++] = hi & 0xFF;
139
+ buf[off++] = (lo >>> 24) & 0xFF;
140
+ buf[off++] = (lo >>> 16) & 0xFF;
141
+ buf[off++] = (lo >>> 8) & 0xFF;
142
+ buf[off++] = lo & 0xFF;
143
+ return off;
144
+ }
145
+
128
146
  function w_bytes(buf, off, b) {
129
147
  buf.set(b, off);
130
148
  return off + b.length;
@@ -739,10 +757,13 @@ function parse_extensions(buf) {
739
757
 
740
758
 
741
759
  /* ================================ Hello I/O ================================ */
742
- function build_hello(kind, params) {
760
+ function build_hello(params) {
743
761
  params = params || {};
762
+ let kind = params.kind;
744
763
 
745
- let legacy_version = TLS_VERSION.TLS1_2; // even for TLS1.3 legacy fields
764
+ let isDtls = (params.cookie !== undefined) ||
765
+ (params.version !== undefined && (params.version & 0xFF00) === 0xFE00);
766
+ let legacy_version = isDtls ? DTLS_VERSION.DTLS1_2 : TLS_VERSION.TLS1_2;
746
767
 
747
768
  let sid = toU8(params.session_id || "");
748
769
  if (sid.length > 32) sid = sid.subarray(0, 32);
@@ -767,8 +788,19 @@ function build_hello(kind, params) {
767
788
  oc = w_u8(compBlock, oc, comp[j]);
768
789
  }
769
790
 
791
+ // DTLS cookie field (between session_id and cipher_suites)
792
+ let cookieBuf = null;
793
+ if (params.cookie !== undefined) {
794
+ let cookie = toU8(params.cookie);
795
+ cookieBuf = new Uint8Array(1 + cookie.length);
796
+ cookieBuf[0] = cookie.length;
797
+ if (cookie.length > 0) cookieBuf.set(cookie, 1);
798
+ }
799
+
770
800
  const out = new Uint8Array(
771
- 2 + 32 + 1 + sid.length + csBlock.length + compBlock.length + extsBuf.length
801
+ 2 + 32 + 1 + sid.length +
802
+ (cookieBuf ? cookieBuf.length : 0) +
803
+ csBlock.length + compBlock.length + extsBuf.length
772
804
  );
773
805
 
774
806
  let off = 0;
@@ -776,6 +808,7 @@ function build_hello(kind, params) {
776
808
  off = w_bytes(out, off, params.random);
777
809
  off = w_u8(out, off, sid.length);
778
810
  off = w_bytes(out, off, sid);
811
+ if (cookieBuf) off = w_bytes(out, off, cookieBuf);
779
812
  off = w_bytes(out, off, csBlock);
780
813
  off = w_bytes(out, off, compBlock);
781
814
  off = w_bytes(out, off, extsBuf);
@@ -803,11 +836,13 @@ function build_hello(kind, params) {
803
836
  throw new Error('build_hello: kind must be "client" or "server"');
804
837
  }
805
838
 
806
- function parse_hello(hsType, body) {
807
- let isClient = (hsType === TLS_MESSAGE_TYPE.CLIENT_HELLO || hsType === 'client_hello');
839
+ function parse_hello(params) {
840
+ let hsType = params.kind;
841
+ let body = params.body;
842
+ let isClient = (hsType === 'client' || hsType === TLS_MESSAGE_TYPE.CLIENT_HELLO || hsType === 'client_hello');
808
843
  let off = 0;
809
844
 
810
- // --- שדות משותפים ---
845
+ // --- shared fields ---
811
846
  let legacy_version; [legacy_version, off] = r_u16(body, off);
812
847
  let random; [random, off] = r_bytes(body, off, 32);
813
848
  let sidLen; [sidLen, off] = r_u8(body, off);
@@ -817,8 +852,20 @@ function parse_hello(hsType, body) {
817
852
  let legacy_compression = [];
818
853
  let type = isClient ? 'client_hello' : 'server_hello';
819
854
 
855
+ // DTLS cookie — auto-detect by version (DTLS versions have 0xFE in high byte)
856
+ let dtls_cookie = null;
857
+ let isDTLS = (legacy_version & 0xFF00) === 0xFE00;
858
+
820
859
  if (isClient) {
821
860
  // --- ClientHello ---
861
+ // DTLS ClientHello has a cookie field between session_id and cipher_suites
862
+ if (isDTLS) {
863
+ let cookieLen; [cookieLen, off] = r_u8(body, off);
864
+ if (cookieLen > 0) {
865
+ [dtls_cookie, off] = r_bytes(body, off, cookieLen);
866
+ }
867
+ }
868
+
822
869
  let csLen; [csLen, off] = r_u16(body, off);
823
870
  let csEnd = off + csLen;
824
871
  while (off < csEnd) {
@@ -858,9 +905,10 @@ function parse_hello(hsType, body) {
858
905
  version: version, // single (u16)
859
906
  random: random, // single (Uint8Array(32))
860
907
  session_id: session_id, // single (Uint8Array)
908
+ dtls_cookie: dtls_cookie, // Uint8Array or null (DTLS only)
861
909
  cipher_suites: cipher_suites, // array
862
910
  legacy_compression: legacy_compression, // array
863
- extensions: extensions // array (לא נוגעים בפנים)
911
+ extensions: extensions // array
864
912
  };
865
913
  }
866
914
 
@@ -1456,9 +1504,89 @@ function parse_key_update(body) {
1456
1504
  }
1457
1505
 
1458
1506
 
1507
+ /* ============================== DTLS Handshake Message ============================== */
1508
+
1509
+ /**
1510
+ * Build a DTLS handshake message from a TLS message.
1511
+ * Adds 8-byte reconstruction header: msg_seq(2) + frag_offset(3) + frag_length(3).
1512
+ *
1513
+ * tls_msg: Uint8Array — TLS format: type(1) + length(3) + body
1514
+ * msg_seq: u16 — handshake message sequence number
1515
+ * frag_offset: optional, defaults to 0
1516
+ * frag_length: optional, defaults to full body length
1517
+ */
1518
+ function build_dtls_handshake(tls_msg, msg_seq, frag_offset, frag_length) {
1519
+ let type = tls_msg[0];
1520
+ let total_length = (tls_msg[1] << 16) | (tls_msg[2] << 8) | tls_msg[3];
1521
+ let body = tls_msg.subarray(4);
1522
+
1523
+ if (frag_offset === undefined) frag_offset = 0;
1524
+ if (frag_length === undefined) frag_length = body.length;
1525
+
1526
+ let frag_body = body.subarray(frag_offset, frag_offset + frag_length);
1527
+
1528
+ let out = new Uint8Array(12 + frag_body.length);
1529
+ let off = 0;
1530
+ off = w_u8(out, off, type);
1531
+ off = w_u24(out, off, total_length);
1532
+ off = w_u16(out, off, msg_seq);
1533
+ off = w_u24(out, off, frag_offset);
1534
+ off = w_u24(out, off, frag_length);
1535
+ off = w_bytes(out, off, frag_body);
1536
+ return out;
1537
+ }
1538
+
1539
+ /**
1540
+ * Parse a DTLS handshake message.
1541
+ * Returns { type, length, msg_seq, frag_offset, frag_length, body }.
1542
+ */
1543
+ function parse_dtls_handshake(buf) {
1544
+ let off = 0;
1545
+ let type; [type, off] = r_u8(buf, off);
1546
+ let length; [length, off] = r_u24(buf, off);
1547
+ let msg_seq; [msg_seq, off] = r_u16(buf, off);
1548
+ let frag_offset;[frag_offset, off]= r_u24(buf, off);
1549
+ let frag_length;[frag_length, off]= r_u24(buf, off);
1550
+ let body; [body, off] = r_bytes(buf, off, frag_length);
1551
+ return { type, length, msg_seq, frag_offset, frag_length, body };
1552
+ }
1553
+
1554
+
1555
+ /* ============================== DTLS 1.2 HelloVerifyRequest ============================== */
1556
+
1557
+ /**
1558
+ * Build HelloVerifyRequest body (DTLS 1.2 — message type 3).
1559
+ * params: { server_version?, cookie: Uint8Array }
1560
+ */
1561
+ function build_hello_verify_request(params) {
1562
+ let version = (params && params.server_version) || DTLS_VERSION.DTLS1_2;
1563
+ let cookie = toU8(params && params.cookie || new Uint8Array(0));
1564
+ let out = new Uint8Array(2 + 1 + cookie.length);
1565
+ let off = 0;
1566
+ off = w_u16(out, off, version);
1567
+ off = w_u8(out, off, cookie.length);
1568
+ if (cookie.length > 0) off = w_bytes(out, off, cookie);
1569
+ return out;
1570
+ }
1571
+
1572
+ /**
1573
+ * Parse HelloVerifyRequest body.
1574
+ * Returns { server_version, cookie }.
1575
+ */
1576
+ function parse_hello_verify_request(body) {
1577
+ let off = 0;
1578
+ let server_version; [server_version, off] = r_u16(body, off);
1579
+ let cookieLen; [cookieLen, off] = r_u8(body, off);
1580
+ let cookie = new Uint8Array(0);
1581
+ if (cookieLen > 0) { [cookie, off] = r_bytes(body, off, cookieLen); }
1582
+ return { server_version, cookie };
1583
+ }
1584
+
1585
+
1459
1586
  /* ================================ Exports ================================= */
1460
1587
  export {
1461
1588
  TLS_VERSION,
1589
+ DTLS_VERSION,
1462
1590
  TLS_CONTENT_TYPE,
1463
1591
  TLS_ALERT_LEVEL,
1464
1592
  TLS_ALERT,
@@ -1468,6 +1596,7 @@ export {
1468
1596
  w_u8,
1469
1597
  w_u16,
1470
1598
  w_u24,
1599
+ w_u48,
1471
1600
  w_bytes,
1472
1601
  r_u8,
1473
1602
  r_u16,
@@ -1516,8 +1645,10 @@ export {
1516
1645
 
1517
1646
  build_key_update,
1518
1647
  parse_key_update,
1519
- };
1520
-
1521
-
1522
-
1523
1648
 
1649
+ // DTLS
1650
+ build_dtls_handshake,
1651
+ parse_dtls_handshake,
1652
+ build_hello_verify_request,
1653
+ parse_hello_verify_request,
1654
+ };