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/index.js +21 -6
- package/package.json +3 -10
- package/src/crypto.js +12 -1
- package/src/dtls_session.js +865 -0
- package/src/dtls_socket.js +263 -0
- package/src/record.js +486 -4
- package/src/session/message.js +6 -3
- package/src/tls_session.js +166 -57
- package/src/wire.js +142 -11
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(
|
|
760
|
+
function build_hello(params) {
|
|
743
761
|
params = params || {};
|
|
762
|
+
let kind = params.kind;
|
|
744
763
|
|
|
745
|
-
let
|
|
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 +
|
|
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(
|
|
807
|
-
let
|
|
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
|
+
};
|