lemon-tls 0.6.0 → 0.7.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
@@ -17,6 +17,36 @@ const DTLS_VERSION = {
17
17
  DTLS1_3: 0xFEFC
18
18
  };
19
19
 
20
+ /**
21
+ * Does `v` denote the TLS 1.3 *message* format?
22
+ *
23
+ * SINGLE SOURCE OF TRUTH for every "is this 1.3?" branch in this file.
24
+ * The reason it has to exist: DTLS 1.3 is TLS 1.3 at the message layer, but
25
+ * its version constant is 0xFEFC, not 0x0304. Every `v === TLS_VERSION.TLS1_3`
26
+ * comparison is therefore silently FALSE for DTLS 1.3, and silently selects
27
+ * the legacy TLS 1.2 encoding of whatever message is being built.
28
+ *
29
+ * That is not hypothetical: build_certificate below did exactly this, so a
30
+ * DTLS 1.3 server emitted a TLS 1.2 Certificate (no certificate_request_context,
31
+ * no per-entry extensions vector). The peer parsed byte 0 as the context length
32
+ * — which happened to be 0x00 and so passed — then read the next three bytes as
33
+ * certificate_list length and got a value far past the end of the message.
34
+ * BoringSSL answers that with decode_error(50).
35
+ *
36
+ * It only ever bit the server role, because the client-side Certificate call
37
+ * sites hardcode TLS_VERSION.TLS1_3 instead of passing the negotiated version.
38
+ * Two copies of this library also agree with each other, because
39
+ * parse_certificate sniffs both encodings — so only a conforming peer objects.
40
+ */
41
+ function is_tls13_wire(v) {
42
+ return v === TLS_VERSION.TLS1_3 || v === DTLS_VERSION.DTLS1_3;
43
+ }
44
+
45
+ /** Companion to is_tls13_wire for the 1.2 message format. */
46
+ function is_tls12_wire(v) {
47
+ return v === TLS_VERSION.TLS1_2 || v === DTLS_VERSION.DTLS1_2;
48
+ }
49
+
20
50
  const TLS_CONTENT_TYPE = {
21
51
  CHANGE_CIPHER_SPEC: 20,
22
52
  ALERT: 21,
@@ -146,6 +176,25 @@ function w_u48(buf, off, v) {
146
176
  return off;
147
177
  }
148
178
 
179
+ /**
180
+ * 64-bit big-endian write. Split into two 32-bit halves rather than using
181
+ * BigInt: DTLS epochs and sequence numbers are both far below 2^53, so Number
182
+ * arithmetic is exact here and roughly an order of magnitude faster.
183
+ */
184
+ function w_u64(buf, off, v) {
185
+ let hi = Math.floor(v / 0x100000000);
186
+ let lo = v >>> 0;
187
+ buf[off++] = (hi >>> 24) & 0xFF;
188
+ buf[off++] = (hi >>> 16) & 0xFF;
189
+ buf[off++] = (hi >>> 8) & 0xFF;
190
+ buf[off++] = (hi ) & 0xFF;
191
+ buf[off++] = (lo >>> 24) & 0xFF;
192
+ buf[off++] = (lo >>> 16) & 0xFF;
193
+ buf[off++] = (lo >>> 8) & 0xFF;
194
+ buf[off++] = (lo ) & 0xFF;
195
+ return off;
196
+ }
197
+
149
198
  function w_bytes(buf, off, b) {
150
199
  buf.set(b, off);
151
200
  return off + b.length;
@@ -1151,6 +1200,14 @@ function build_certificate(params) {
1151
1200
  // TLS 1.3 → מחזיר: request_context (vec<1>) || certificate_list (vec<3> של [ cert(vec<3>) || extensions(vec<2>) ]*)
1152
1201
  // TLS 1.2 → מחזיר: certificate_list (vec<3> של cert(vec<3>)*), מתעלם מ-extensions/request_context
1153
1202
 
1203
+ // NOTE the asymmetry with build_certificate_request, which defaults to
1204
+ // TLS1_3. Both defaults are kept as they were, because callers outside this
1205
+ // file may rely on them; every call site inside the library passes `version`
1206
+ // explicitly, so the default is never actually exercised here. What matters
1207
+ // is that the branch below asks is_tls13_wire(v), not v === TLS1_3 — the
1208
+ // mismatched defaults are what made the two messages in the SAME server
1209
+ // flight come out in two different encodings, which is why this stayed
1210
+ // hidden for so long.
1154
1211
  let v = params.version || TLS_VERSION.TLS1_2;
1155
1212
 
1156
1213
  // Normalize to entries[] always
@@ -1161,8 +1218,14 @@ function build_certificate(params) {
1161
1218
  }
1162
1219
  if (!entries) entries = [];
1163
1220
 
1164
- if (v === TLS_VERSION.TLS1_3) {
1165
- let ctx = toU8(params.request_context || new Uint8Array(0));
1221
+ if (is_tls13_wire(v)) {
1222
+ // Accept either spelling of the context field. build_tls_message callers
1223
+ // pass `certificate_request_context` (the RFC 8446 field name); this
1224
+ // builder originally read only `request_context`, so the value was
1225
+ // dropped without a word. Harmless during the initial handshake, where
1226
+ // the context is always empty — but post-handshake client authentication
1227
+ // is identified BY that context, so it would have failed silently.
1228
+ let ctx = toU8(params.request_context || params.certificate_request_context || new Uint8Array(0));
1166
1229
 
1167
1230
  let entryParts = [];
1168
1231
  for (let i = 0; i < entries.length; i++) {
@@ -1400,8 +1463,10 @@ function parse_new_session_ticket(body) {
1400
1463
  function build_certificate_request(params) {
1401
1464
  let v = params && params.version || TLS_VERSION.TLS1_3;
1402
1465
 
1403
- if (v === TLS_VERSION.TLS1_3) {
1404
- let ctx = toU8((params && params.request_context) || new Uint8Array(0));
1466
+ if (is_tls13_wire(v)) {
1467
+ // Same dual-spelling accommodation as build_certificate above.
1468
+ let ctx = toU8((params && (params.request_context || params.certificate_request_context)) ||
1469
+ new Uint8Array(0));
1405
1470
 
1406
1471
  // RFC 8446 §4.3.2: "The 'signature_algorithms' extension MUST be specified"
1407
1472
  // in a TLS 1.3 CertificateRequest.
@@ -1869,6 +1934,8 @@ function parse_hello_verify_request(body) {
1869
1934
  export {
1870
1935
  TLS_VERSION,
1871
1936
  DTLS_VERSION,
1937
+ is_tls13_wire,
1938
+ is_tls12_wire,
1872
1939
  TLS_CONTENT_TYPE,
1873
1940
  TLS_ALERT_LEVEL,
1874
1941
  TLS_ALERT,
@@ -1879,6 +1946,7 @@ export {
1879
1946
  w_u16,
1880
1947
  w_u24,
1881
1948
  w_u48,
1949
+ w_u64,
1882
1950
  w_bytes,
1883
1951
  r_u8,
1884
1952
  r_u16,