lemon-tls 0.2.0 → 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/ecdh.js +25 -1
- package/src/session/message.js +6 -3
- package/src/tls_session.js +258 -71
- package/src/wire.js +174 -19
package/src/tls_session.js
CHANGED
|
@@ -28,7 +28,7 @@ import * as wire from './wire.js';
|
|
|
28
28
|
// Extracted modules
|
|
29
29
|
import { pick_scheme, sign_with_scheme } from './session/signing.js';
|
|
30
30
|
import createSecureContext from './secure_context.js';
|
|
31
|
-
import { x25519_get_public_key, x25519_get_shared_secret, p256_generate_keypair, p256_get_shared_secret } from './session/ecdh.js';
|
|
31
|
+
import { x25519_get_public_key, x25519_get_shared_secret, p256_generate_keypair, p256_get_shared_secret, p384_generate_keypair, p384_get_shared_secret } from './session/ecdh.js';
|
|
32
32
|
import { build_tls_message, parse_tls_message } from './session/message.js';
|
|
33
33
|
|
|
34
34
|
|
|
@@ -57,7 +57,7 @@ function TLSSession(options){
|
|
|
57
57
|
|
|
58
58
|
//local stuff...
|
|
59
59
|
local_sni: options.servername || null,
|
|
60
|
-
local_session_id: null,
|
|
60
|
+
local_session_id: 'sessionId' in options ? options.sessionId : null,
|
|
61
61
|
|
|
62
62
|
local_random: null,
|
|
63
63
|
local_extensions: [],
|
|
@@ -108,6 +108,7 @@ function TLSSession(options){
|
|
|
108
108
|
|
|
109
109
|
|
|
110
110
|
transcript: [],
|
|
111
|
+
transcriptHook: null, // DTLSSession sets this to transform transcript entries
|
|
111
112
|
|
|
112
113
|
|
|
113
114
|
//both
|
|
@@ -162,6 +163,9 @@ function TLSSession(options){
|
|
|
162
163
|
// HelloRetryRequest
|
|
163
164
|
helloRetried: false, // true if HRR was sent/received
|
|
164
165
|
|
|
166
|
+
// DTLS cookie (set by DTLSSession via set_context)
|
|
167
|
+
dtls_cookie: undefined, // Uint8Array or undefined
|
|
168
|
+
|
|
165
169
|
// TLS 1.3 resumption
|
|
166
170
|
tls13_master_secret: null,
|
|
167
171
|
resumption_master_secret: null,
|
|
@@ -173,6 +177,19 @@ function TLSSession(options){
|
|
|
173
177
|
isResumed: false, // true if PSK was accepted
|
|
174
178
|
};
|
|
175
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Push a handshake message to the transcript.
|
|
182
|
+
* If a transcriptHook is set (by DTLSSession), it transforms the data first.
|
|
183
|
+
* This allows DTLS 1.2 to store DTLS-format entries (with reconstruction data)
|
|
184
|
+
* while TLS and DTLS 1.3 store standard TLS-format entries.
|
|
185
|
+
*/
|
|
186
|
+
function pushTranscript(data) {
|
|
187
|
+
if (context.transcriptHook) {
|
|
188
|
+
data = context.transcriptHook(data);
|
|
189
|
+
}
|
|
190
|
+
context.transcript.push(data);
|
|
191
|
+
}
|
|
192
|
+
|
|
176
193
|
function process_income_message(data){
|
|
177
194
|
|
|
178
195
|
// Track handshake start time
|
|
@@ -192,7 +209,7 @@ function TLSSession(options){
|
|
|
192
209
|
|
|
193
210
|
if((context.isServer==false && message.type=='server_hello') || (context.isServer==true && message.type=='client_hello')){
|
|
194
211
|
|
|
195
|
-
|
|
212
|
+
pushTranscript(data);
|
|
196
213
|
|
|
197
214
|
// Save raw ClientHello + emit event (server side)
|
|
198
215
|
if (context.isServer && message.type === 'client_hello') {
|
|
@@ -267,19 +284,26 @@ function TLSSession(options){
|
|
|
267
284
|
if (!hrrCipher) hrrCipher = 0x1301;
|
|
268
285
|
let hashName = TLS_CIPHER_SUITES[hrrCipher] ? TLS_CIPHER_SUITES[hrrCipher].hash : 'sha256';
|
|
269
286
|
|
|
270
|
-
// Replace transcript: CH1 → message_hash
|
|
287
|
+
// Replace transcript: CH1 → message_hash (RFC 8446 §4.4.1)
|
|
288
|
+
// BUG FIX: The HRR was already pushed to transcript at the top of this block (line 195).
|
|
289
|
+
// We must remove it before hashing, since message_hash = Hash(ClientHello1) only.
|
|
290
|
+
let hrrData = context.transcript.pop(); // remove HRR
|
|
271
291
|
let ch1_hash = getHashFn(hashName)(concatUint8Arrays(context.transcript));
|
|
272
292
|
let message_hash = wire.build_message(wire.TLS_MESSAGE_TYPE.MESSAGE_HASH, ch1_hash);
|
|
273
|
-
context.transcript = [message_hash,
|
|
293
|
+
context.transcript = [message_hash, hrrData]; // message_hash + HRR
|
|
274
294
|
|
|
275
|
-
// Find the requested group from HRR
|
|
295
|
+
// Find the requested group from HRR key_share extension
|
|
296
|
+
// After wire.js fix, key_groups contains [{group: N, key_exchange: empty}] for HRR
|
|
276
297
|
let requestedGroup = null;
|
|
277
|
-
if (message.
|
|
278
|
-
requestedGroup = message.supported_groups[0];
|
|
279
|
-
} else if (message.key_groups && message.key_groups.length > 0) {
|
|
298
|
+
if (message.key_groups && message.key_groups.length > 0) {
|
|
280
299
|
requestedGroup = message.key_groups[0].group;
|
|
300
|
+
} else if (message.supported_groups && message.supported_groups.length > 0) {
|
|
301
|
+
requestedGroup = message.supported_groups[0];
|
|
281
302
|
}
|
|
282
303
|
|
|
304
|
+
// Extract cookie from HRR (if present, must be echoed in CH2)
|
|
305
|
+
let hrrCookie = message.cookie || null;
|
|
306
|
+
|
|
283
307
|
if (requestedGroup) {
|
|
284
308
|
// Generate key for the requested group
|
|
285
309
|
let newKeyGroup = null;
|
|
@@ -292,31 +316,63 @@ function TLSSession(options){
|
|
|
292
316
|
let kp = p256_generate_keypair();
|
|
293
317
|
newKeyGroup = { group: requestedGroup, public_key: kp.public_key, private_key: kp.private_key };
|
|
294
318
|
context.local_key_groups[requestedGroup] = { public_key: kp.public_key, private_key: kp.private_key };
|
|
319
|
+
} else if (requestedGroup === 0x0018) {
|
|
320
|
+
let kp = p384_generate_keypair();
|
|
321
|
+
newKeyGroup = { group: requestedGroup, public_key: kp.public_key, private_key: kp.private_key };
|
|
322
|
+
context.local_key_groups[requestedGroup] = { public_key: kp.public_key, private_key: kp.private_key };
|
|
295
323
|
}
|
|
296
324
|
|
|
297
325
|
if (newKeyGroup) {
|
|
298
|
-
// Build and send new ClientHello (CH2) with
|
|
326
|
+
// Build and send new ClientHello (CH2) with:
|
|
327
|
+
// - key_share for requested group
|
|
328
|
+
// - cookie (if HRR included one)
|
|
329
|
+
// - ALPN (same as CH1)
|
|
330
|
+
// - custom extensions (QUIC transport params etc.)
|
|
331
|
+
// - same cipher_suites, session_id, random as CH1
|
|
299
332
|
let extensions = [
|
|
300
333
|
{ type: 'SUPPORTED_VERSIONS', value: context.local_supported_versions },
|
|
301
334
|
{ type: 'SUPPORTED_GROUPS', value: context.local_supported_groups },
|
|
302
335
|
{ type: 'KEY_SHARE', value: [{ group: requestedGroup, key_exchange: newKeyGroup.public_key }] },
|
|
303
|
-
{ type: 'SIGNATURE_ALGORITHMS', value:
|
|
304
|
-
|
|
336
|
+
{ type: 'SIGNATURE_ALGORITHMS', value: [
|
|
337
|
+
// Must match CH1 exactly (RFC 8446 §4.1.2)
|
|
338
|
+
0x0804, 0x0805, 0x0806,
|
|
339
|
+
0x0403, 0x0503, 0x0603,
|
|
340
|
+
0x0807, 0x0808,
|
|
341
|
+
0x0401, 0x0501, 0x0601
|
|
342
|
+
] },
|
|
305
343
|
{ type: 'RENEGOTIATION_INFO', value: new Uint8Array(0) },
|
|
306
|
-
{ type: 23, data: new Uint8Array(0) },
|
|
344
|
+
{ type: 23, data: new Uint8Array(0) }, // extended_master_secret
|
|
307
345
|
];
|
|
346
|
+
|
|
347
|
+
// SNI (must be first)
|
|
308
348
|
if (context.local_sni) extensions.unshift({ type: 'SERVER_NAME', value: context.local_sni });
|
|
309
349
|
|
|
350
|
+
// ALPN (same as CH1 — required for QUIC/h3)
|
|
351
|
+
if (context.local_supported_alpns && context.local_supported_alpns.length > 0) {
|
|
352
|
+
extensions.push({ type: 'ALPN', value: context.local_supported_alpns });
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Cookie from HRR (RFC 8446 §4.2.2 — MUST echo if present)
|
|
356
|
+
if (hrrCookie) {
|
|
357
|
+
extensions.push({ type: 'COOKIE', value: hrrCookie });
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Custom extensions (e.g. QUIC transport params 0x39)
|
|
361
|
+
for (let ci in context.local_extensions) {
|
|
362
|
+
extensions.push(context.local_extensions[ci]);
|
|
363
|
+
}
|
|
364
|
+
|
|
310
365
|
let ch2 = build_tls_message({
|
|
311
366
|
type: 'client_hello',
|
|
312
367
|
version: 0x0303,
|
|
313
368
|
random: context.local_random,
|
|
314
369
|
session_id: context.local_session_id,
|
|
370
|
+
cookie: context.dtls_cookie,
|
|
315
371
|
cipher_suite: context.local_supported_cipher_suites,
|
|
316
372
|
extensions: extensions,
|
|
317
373
|
});
|
|
318
374
|
|
|
319
|
-
|
|
375
|
+
pushTranscript(ch2);
|
|
320
376
|
ev.emit('message', 0, context.message_sent_seq, 'hello', ch2);
|
|
321
377
|
context.message_sent_seq++;
|
|
322
378
|
}
|
|
@@ -330,7 +386,9 @@ function TLSSession(options){
|
|
|
330
386
|
remote_random: message.random || null,
|
|
331
387
|
remote_sni: message.sni || null,
|
|
332
388
|
remote_session_id: message.session_id || null,
|
|
333
|
-
remote_supported_versions: message.supported_versions
|
|
389
|
+
remote_supported_versions: (message.supported_versions && message.supported_versions.length > 0)
|
|
390
|
+
? message.supported_versions
|
|
391
|
+
: (message.legacy_version ? [message.legacy_version] : []),
|
|
334
392
|
remote_supported_alpns: message.alpn || [],
|
|
335
393
|
remote_supported_cipher_suites: message.cipher_suites || [],
|
|
336
394
|
remote_supported_signature_algorithms: message.signature_algorithms || [],
|
|
@@ -358,21 +416,27 @@ function TLSSession(options){
|
|
|
358
416
|
|
|
359
417
|
}else if(message.type=='client_key_exchange' || message.type=='server_key_exchange'){
|
|
360
418
|
|
|
361
|
-
|
|
419
|
+
pushTranscript(data);
|
|
362
420
|
|
|
363
421
|
if ([0xC02F,0xC02B,0xC030,0xC02C,0xC013,0xC014,0xC009,0xC00A].includes(context.selected_cipher_suite)==true) {//ECDHE
|
|
364
422
|
|
|
365
423
|
// ServerKeyExchange carries the group; ClientKeyExchange does not (server already chose it)
|
|
366
424
|
let kex_group = message.group || context.selected_group;
|
|
367
425
|
|
|
368
|
-
|
|
426
|
+
let kex_updates = {
|
|
369
427
|
add_remote_key_groups: [
|
|
370
428
|
{
|
|
371
429
|
group: kex_group,
|
|
372
430
|
public_key: message.public_key
|
|
373
431
|
}
|
|
374
432
|
],
|
|
375
|
-
}
|
|
433
|
+
};
|
|
434
|
+
// TLS 1.2 client: selected_group isn't set from ServerHello (no supported_groups ext).
|
|
435
|
+
// Set it from the SKE group so the reactive loop can generate a keypair and build CKE.
|
|
436
|
+
if (context.selected_group === null && kex_group) {
|
|
437
|
+
kex_updates.selected_group = kex_group;
|
|
438
|
+
}
|
|
439
|
+
set_context(kex_updates);
|
|
376
440
|
|
|
377
441
|
}else if ([0x009E,0x009F,0x0033,0x0039,0x0067,0x006B].includes(context.selected_cipher_suite)==true) {//DHE
|
|
378
442
|
|
|
@@ -388,7 +452,7 @@ function TLSSession(options){
|
|
|
388
452
|
|
|
389
453
|
}else if(message.type=='server_hello_done'){
|
|
390
454
|
|
|
391
|
-
|
|
455
|
+
pushTranscript(data);
|
|
392
456
|
|
|
393
457
|
|
|
394
458
|
set_context({
|
|
@@ -397,7 +461,7 @@ function TLSSession(options){
|
|
|
397
461
|
|
|
398
462
|
}else if(message.type=='encrypted_extensions'){
|
|
399
463
|
|
|
400
|
-
|
|
464
|
+
pushTranscript(data);
|
|
401
465
|
|
|
402
466
|
set_context({
|
|
403
467
|
remote_supported_groups: message.supported_groups || [],
|
|
@@ -405,7 +469,7 @@ function TLSSession(options){
|
|
|
405
469
|
|
|
406
470
|
}else if(message.type=='certificate'){
|
|
407
471
|
|
|
408
|
-
|
|
472
|
+
pushTranscript(data);
|
|
409
473
|
|
|
410
474
|
set_context({
|
|
411
475
|
remote_cert_chain: message.entries,
|
|
@@ -420,7 +484,7 @@ function TLSSession(options){
|
|
|
420
484
|
|
|
421
485
|
}else if(message.type=='certificate_verify'){
|
|
422
486
|
|
|
423
|
-
|
|
487
|
+
pushTranscript(data);
|
|
424
488
|
|
|
425
489
|
}else if(message.type=='finished'){
|
|
426
490
|
|
|
@@ -449,7 +513,7 @@ function TLSSession(options){
|
|
|
449
513
|
}else if(message.type=='key_update'){
|
|
450
514
|
|
|
451
515
|
// Peer is updating their traffic secret (we update our read key)
|
|
452
|
-
if(context.state==='connected' && context.selected_version === wire.TLS_VERSION.TLS1_3){
|
|
516
|
+
if(context.state==='connected' && (context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3)){
|
|
453
517
|
let hashName = TLS_CIPHER_SUITES[context.selected_cipher_suite].hash;
|
|
454
518
|
let hashLen = getHashLen(hashName);
|
|
455
519
|
let newRemoteSecret = hkdf_expand_label(hashName, context.remote_app_traffic_secret, 'traffic upd', new Uint8Array(0), hashLen);
|
|
@@ -474,7 +538,7 @@ function TLSSession(options){
|
|
|
474
538
|
|
|
475
539
|
// Server is requesting a client certificate (TLS 1.3)
|
|
476
540
|
if(!context.isServer){
|
|
477
|
-
|
|
541
|
+
pushTranscript(data);
|
|
478
542
|
context.certificateRequested = true;
|
|
479
543
|
context.certificateRequestContext = message.certificate_request_context || new Uint8Array(0);
|
|
480
544
|
context.certificateRequestSigAlgs = message.signature_algorithms || [];
|
|
@@ -780,6 +844,9 @@ function TLSSession(options){
|
|
|
780
844
|
if(context.remote_app_traffic_secret==null && options.remote_app_traffic_secret!==null){
|
|
781
845
|
context.remote_app_traffic_secret=options.remote_app_traffic_secret;
|
|
782
846
|
has_changed=true;
|
|
847
|
+
if(context.local_app_traffic_secret!==null){
|
|
848
|
+
ev.emit('appSecrets', context.local_app_traffic_secret, context.remote_app_traffic_secret);
|
|
849
|
+
}
|
|
783
850
|
}
|
|
784
851
|
}
|
|
785
852
|
|
|
@@ -787,6 +854,9 @@ function TLSSession(options){
|
|
|
787
854
|
if(context.local_app_traffic_secret==null && options.local_app_traffic_secret!==null){
|
|
788
855
|
context.local_app_traffic_secret=options.local_app_traffic_secret;
|
|
789
856
|
has_changed=true;
|
|
857
|
+
if(context.remote_app_traffic_secret!==null){
|
|
858
|
+
ev.emit('appSecrets', context.local_app_traffic_secret, context.remote_app_traffic_secret);
|
|
859
|
+
}
|
|
790
860
|
}
|
|
791
861
|
}
|
|
792
862
|
|
|
@@ -827,7 +897,10 @@ function TLSSession(options){
|
|
|
827
897
|
}
|
|
828
898
|
}
|
|
829
899
|
|
|
830
|
-
|
|
900
|
+
if('dtls_cookie' in options){
|
|
901
|
+
context.dtls_cookie=options.dtls_cookie;
|
|
902
|
+
has_changed=true;
|
|
903
|
+
}
|
|
831
904
|
|
|
832
905
|
|
|
833
906
|
}
|
|
@@ -857,6 +930,16 @@ function TLSSession(options){
|
|
|
857
930
|
|
|
858
931
|
if('selected_version' in params_to_set==false || params_to_set.selected_version==null){
|
|
859
932
|
}
|
|
933
|
+
|
|
934
|
+
// TLS 1.2: clear key_share groups from ClientHello.
|
|
935
|
+
// key_share is a TLS 1.3 extension; in TLS 1.2, keys come from CKE/SKE.
|
|
936
|
+
// Without this, the server would compute the shared secret too early
|
|
937
|
+
// (using CH key_share instead of waiting for CKE).
|
|
938
|
+
if (context.isServer && params_to_set.selected_version !== null &&
|
|
939
|
+
params_to_set.selected_version !== wire.TLS_VERSION.TLS1_3 &&
|
|
940
|
+
params_to_set.selected_version !== wire.DTLS_VERSION.DTLS1_3) {
|
|
941
|
+
context.remote_key_groups = {};
|
|
942
|
+
}
|
|
860
943
|
}
|
|
861
944
|
|
|
862
945
|
//select selected_cipher...
|
|
@@ -948,6 +1031,20 @@ function TLSSession(options){
|
|
|
948
1031
|
}
|
|
949
1032
|
];
|
|
950
1033
|
|
|
1034
|
+
} else if (context.selected_group === 0x0018) {
|
|
1035
|
+
|
|
1036
|
+
let kp = p384_generate_keypair();
|
|
1037
|
+
let private_key = kp.private_key;
|
|
1038
|
+
let public_key = kp.public_key;
|
|
1039
|
+
|
|
1040
|
+
params_to_set['add_local_key_groups']=[
|
|
1041
|
+
{
|
|
1042
|
+
group: context.selected_group,
|
|
1043
|
+
private_key: private_key,
|
|
1044
|
+
public_key: public_key
|
|
1045
|
+
}
|
|
1046
|
+
];
|
|
1047
|
+
|
|
951
1048
|
}
|
|
952
1049
|
|
|
953
1050
|
|
|
@@ -974,6 +1071,12 @@ function TLSSession(options){
|
|
|
974
1071
|
|
|
975
1072
|
params_to_set['ecdhe_shared_secret']=ecdhe_shared_secret;
|
|
976
1073
|
|
|
1074
|
+
} else if (context.selected_group === 0x0018) { // secp384r1 (P-384)
|
|
1075
|
+
|
|
1076
|
+
let ecdhe_shared_secret = p384_get_shared_secret(local_private_key, remote_public_key);
|
|
1077
|
+
|
|
1078
|
+
params_to_set['ecdhe_shared_secret']=ecdhe_shared_secret;
|
|
1079
|
+
|
|
977
1080
|
}
|
|
978
1081
|
|
|
979
1082
|
}
|
|
@@ -986,7 +1089,7 @@ function TLSSession(options){
|
|
|
986
1089
|
if(context.isServer==true){
|
|
987
1090
|
|
|
988
1091
|
// HelloRetryRequest: if we selected a group but client didn't send a key_share for it
|
|
989
|
-
if(context.hello_sent==false && !context.helloRetried && context.selected_version === wire.TLS_VERSION.TLS1_3 &&
|
|
1092
|
+
if(context.hello_sent==false && !context.helloRetried && (context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3) &&
|
|
990
1093
|
context.selected_group !== null && context.selected_cipher_suite !== null &&
|
|
991
1094
|
!(context.selected_group in context.remote_key_groups)){
|
|
992
1095
|
|
|
@@ -1001,11 +1104,12 @@ function TLSSession(options){
|
|
|
1001
1104
|
// Build and send HRR (it's a ServerHello with magic random)
|
|
1002
1105
|
let hrr_body = wire.build_hello_retry_request({
|
|
1003
1106
|
cipher_suite: context.selected_cipher_suite,
|
|
1004
|
-
selected_version:
|
|
1107
|
+
selected_version: context.selected_version,
|
|
1005
1108
|
selected_group: context.selected_group,
|
|
1109
|
+
session_id: context.remote_session_id,
|
|
1006
1110
|
});
|
|
1007
1111
|
let hrr_data = wire.build_message(wire.TLS_MESSAGE_TYPE.SERVER_HELLO, hrr_body);
|
|
1008
|
-
|
|
1112
|
+
pushTranscript(hrr_data);
|
|
1009
1113
|
|
|
1010
1114
|
ev.emit('message', 0, context.message_sent_seq, 'hello_retry_request', hrr_data);
|
|
1011
1115
|
context.message_sent_seq++;
|
|
@@ -1025,11 +1129,14 @@ function TLSSession(options){
|
|
|
1025
1129
|
if(context.hello_sent==false){
|
|
1026
1130
|
|
|
1027
1131
|
if(context.selected_version!==null && context.selected_cipher_suite!==null && context.selected_session_id!==null){
|
|
1028
|
-
if(context.selected_version === wire.TLS_VERSION.TLS1_3){
|
|
1132
|
+
if((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3)){
|
|
1029
1133
|
if(context.selected_group in context.local_key_groups==true && context.local_key_groups[context.selected_group].public_key!==null){
|
|
1030
|
-
|
|
1134
|
+
// After HRR, don't send ServerHello until CH2 provides the requested key_share
|
|
1135
|
+
if (!context.helloRetried || (context.selected_group in context.remote_key_groups)) {
|
|
1136
|
+
can_send_hello=true;
|
|
1137
|
+
}
|
|
1031
1138
|
}
|
|
1032
|
-
}else if(context.selected_version === wire.TLS_VERSION.TLS1_2){
|
|
1139
|
+
}else if((context.selected_version === wire.TLS_VERSION.TLS1_2 || context.selected_version === wire.DTLS_VERSION.DTLS1_2)){
|
|
1033
1140
|
can_send_hello=true;
|
|
1034
1141
|
}
|
|
1035
1142
|
}
|
|
@@ -1043,12 +1150,12 @@ function TLSSession(options){
|
|
|
1043
1150
|
|
|
1044
1151
|
let build_message_params=null;
|
|
1045
1152
|
|
|
1046
|
-
if(context.selected_version
|
|
1153
|
+
if((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3)){
|
|
1047
1154
|
|
|
1048
1155
|
let shExtensions = [
|
|
1049
1156
|
{
|
|
1050
1157
|
type: 'SUPPORTED_VERSIONS',
|
|
1051
|
-
value:
|
|
1158
|
+
value: context.selected_version
|
|
1052
1159
|
},
|
|
1053
1160
|
{
|
|
1054
1161
|
type: 'KEY_SHARE',
|
|
@@ -1074,7 +1181,7 @@ function TLSSession(options){
|
|
|
1074
1181
|
};
|
|
1075
1182
|
|
|
1076
1183
|
|
|
1077
|
-
}else if(context.selected_version
|
|
1184
|
+
}else if((context.selected_version === wire.TLS_VERSION.TLS1_2 || context.selected_version === wire.DTLS_VERSION.DTLS1_2)){
|
|
1078
1185
|
|
|
1079
1186
|
|
|
1080
1187
|
// TLS 1.2 ServerHello: no SUPPORTED_VERSIONS or KEY_SHARE.
|
|
@@ -1116,7 +1223,7 @@ function TLSSession(options){
|
|
|
1116
1223
|
|
|
1117
1224
|
let message_data = build_tls_message(build_message_params);
|
|
1118
1225
|
|
|
1119
|
-
|
|
1226
|
+
pushTranscript(message_data);
|
|
1120
1227
|
|
|
1121
1228
|
context.hello_sent=true;
|
|
1122
1229
|
|
|
@@ -1136,7 +1243,7 @@ function TLSSession(options){
|
|
|
1136
1243
|
|
|
1137
1244
|
//get base_secret
|
|
1138
1245
|
if (context.base_secret==null && context.selected_cipher_suite !== null){
|
|
1139
|
-
if(context.selected_version
|
|
1246
|
+
if((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3) && (context.ecdhe_shared_secret !== null)){
|
|
1140
1247
|
|
|
1141
1248
|
let hashName = TLS_CIPHER_SUITES[context.selected_cipher_suite].hash;
|
|
1142
1249
|
let result;
|
|
@@ -1158,7 +1265,7 @@ function TLSSession(options){
|
|
|
1158
1265
|
params_to_set['remote_handshake_traffic_secret']=result.server_handshake_traffic_secret;
|
|
1159
1266
|
}
|
|
1160
1267
|
|
|
1161
|
-
}else if(context.selected_version === wire.TLS_VERSION.TLS1_2 && context.local_random!==null && context.remote_random!==null){
|
|
1268
|
+
}else if((context.selected_version === wire.TLS_VERSION.TLS1_2 || context.selected_version === wire.DTLS_VERSION.DTLS1_2) && context.local_random!==null && context.remote_random!==null){
|
|
1162
1269
|
if(context.ecdhe_shared_secret !== null){
|
|
1163
1270
|
|
|
1164
1271
|
|
|
@@ -1178,7 +1285,11 @@ function TLSSession(options){
|
|
|
1178
1285
|
if(context.isServer || context.key_exchange_sent){
|
|
1179
1286
|
let hashFn = getHashFn(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash);
|
|
1180
1287
|
|
|
1181
|
-
|
|
1288
|
+
// Use snapshot up to CKE if available (excludes CertificateVerify)
|
|
1289
|
+
let emsTranscript = context._emsTranscriptLen
|
|
1290
|
+
? context.transcript.slice(0, context._emsTranscriptLen)
|
|
1291
|
+
: context.transcript;
|
|
1292
|
+
let transcript_hash = hashFn(concatUint8Arrays(emsTranscript));
|
|
1182
1293
|
|
|
1183
1294
|
let master_secret = tls12_prf(context.ecdhe_shared_secret, "extended master secret", transcript_hash, 48, TLS_CIPHER_SUITES[context.selected_cipher_suite].hash);
|
|
1184
1295
|
|
|
@@ -1202,7 +1313,7 @@ function TLSSession(options){
|
|
|
1202
1313
|
|
|
1203
1314
|
|
|
1204
1315
|
//send encrypted_extensions...
|
|
1205
|
-
if (context.isServer==true && context.selected_version === wire.TLS_VERSION.TLS1_3){
|
|
1316
|
+
if (context.isServer==true && (context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3)){
|
|
1206
1317
|
if(context.encrypted_exts_sent==false && context.hello_sent==true && context.local_handshake_traffic_secret!==null){
|
|
1207
1318
|
|
|
1208
1319
|
let extensions=[];
|
|
@@ -1220,7 +1331,7 @@ function TLSSession(options){
|
|
|
1220
1331
|
extensions: extensions
|
|
1221
1332
|
});
|
|
1222
1333
|
|
|
1223
|
-
|
|
1334
|
+
pushTranscript(message_data);
|
|
1224
1335
|
|
|
1225
1336
|
context.encrypted_exts_sent=true;
|
|
1226
1337
|
|
|
@@ -1234,31 +1345,31 @@ function TLSSession(options){
|
|
|
1234
1345
|
|
|
1235
1346
|
//send certificate... (skip for PSK resumption — no cert needed)
|
|
1236
1347
|
// But first: send CertificateRequest if requestCert is set (TLS 1.3 only, between EE and Cert)
|
|
1237
|
-
if(context.isServer==true && context.requestCert==true && !context.certificateRequestSent && context.encrypted_exts_sent==true && context.local_handshake_traffic_secret!==null && context.selected_version === wire.TLS_VERSION.TLS1_3 && !context.psk_accepted){
|
|
1348
|
+
if(context.isServer==true && context.requestCert==true && !context.certificateRequestSent && context.encrypted_exts_sent==true && context.local_handshake_traffic_secret!==null && (context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3) && !context.psk_accepted){
|
|
1238
1349
|
let cr_data = build_tls_message({
|
|
1239
1350
|
type: 'certificate_request',
|
|
1240
1351
|
certificate_request_context: new Uint8Array(0),
|
|
1241
1352
|
signature_algorithms: context.local_supported_signature_algorithms,
|
|
1242
1353
|
});
|
|
1243
|
-
|
|
1354
|
+
pushTranscript(cr_data);
|
|
1244
1355
|
context.certificateRequestSent = true;
|
|
1245
1356
|
ev.emit('message', 1, context.message_sent_seq, 'certificate_request', cr_data);
|
|
1246
1357
|
context.message_sent_seq++;
|
|
1247
1358
|
}
|
|
1248
1359
|
|
|
1249
1360
|
if(context.isServer==true && context.cert_sent==false && context.local_cert_chain!==null && !context.psk_accepted){
|
|
1250
|
-
if((context.selected_version === wire.TLS_VERSION.TLS1_3 && context.encrypted_exts_sent==true && context.local_handshake_traffic_secret!==null) || (context.selected_version === wire.TLS_VERSION.TLS1_2 && context.hello_sent==true)){
|
|
1361
|
+
if(((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3) && context.encrypted_exts_sent==true && context.local_handshake_traffic_secret!==null) || ((context.selected_version === wire.TLS_VERSION.TLS1_2 || context.selected_version === wire.DTLS_VERSION.DTLS1_2) && context.hello_sent==true)){
|
|
1251
1362
|
|
|
1252
1363
|
let message_data = build_tls_message({
|
|
1253
1364
|
type: 'certificate',
|
|
1254
1365
|
version: context.selected_version,
|
|
1255
1366
|
entries: context.local_cert_chain
|
|
1256
1367
|
});
|
|
1257
|
-
|
|
1368
|
+
pushTranscript(message_data);
|
|
1258
1369
|
|
|
1259
1370
|
context.cert_sent=true;
|
|
1260
1371
|
|
|
1261
|
-
if (context.selected_version === wire.TLS_VERSION.TLS1_3){
|
|
1372
|
+
if ((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3)){
|
|
1262
1373
|
ev.emit('message',1,context.message_sent_seq,'certificate',message_data);
|
|
1263
1374
|
}else{
|
|
1264
1375
|
ev.emit('message',0,context.message_sent_seq,'certificate',message_data);
|
|
@@ -1276,7 +1387,7 @@ function TLSSession(options){
|
|
|
1276
1387
|
|
|
1277
1388
|
|
|
1278
1389
|
//send certificate verify...
|
|
1279
|
-
if (context.isServer==true && context.selected_version === wire.TLS_VERSION.TLS1_3){
|
|
1390
|
+
if (context.isServer==true && (context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3)){
|
|
1280
1391
|
if(context.cert_sent==true && context.cert_verify_sent==false && context.local_cert_chain!==null && context.local_handshake_traffic_secret!==null && context.selected_cipher_suite!==null){
|
|
1281
1392
|
|
|
1282
1393
|
let tbs_data = build_cert_verify_tbs(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash,true,concatUint8Arrays(context.transcript));
|
|
@@ -1386,7 +1497,7 @@ function TLSSession(options){
|
|
|
1386
1497
|
|
|
1387
1498
|
|
|
1388
1499
|
|
|
1389
|
-
|
|
1500
|
+
pushTranscript(message_data);
|
|
1390
1501
|
|
|
1391
1502
|
context.cert_verify_sent=true;
|
|
1392
1503
|
|
|
@@ -1409,26 +1520,90 @@ function TLSSession(options){
|
|
|
1409
1520
|
|
|
1410
1521
|
|
|
1411
1522
|
// client/server key exchange - 1.2 only...
|
|
1412
|
-
if (context.key_exchange_sent == false && context.selected_version
|
|
1523
|
+
if (context.key_exchange_sent == false && (context.selected_version === wire.TLS_VERSION.TLS1_2 || context.selected_version === wire.DTLS_VERSION.DTLS1_2)) {
|
|
1413
1524
|
if(context.selected_group!==null && context.selected_group in context.local_key_groups==true && context.local_key_groups[context.selected_group].public_key!==null){
|
|
1414
1525
|
|
|
1415
1526
|
if (context.isServer==false && context.remote_hello_done==true) {
|
|
1416
1527
|
|
|
1528
|
+
// TLS 1.2: send Certificate before CKE if server requested client auth
|
|
1529
|
+
if (context.certificateRequested && !context.clientCertSent) {
|
|
1530
|
+
context.clientCertSent = true;
|
|
1531
|
+
|
|
1532
|
+
// Build TLS 1.2 Certificate message
|
|
1533
|
+
let certEntries = [];
|
|
1534
|
+
if (context.local_cert_chain && context.local_cert_chain.length > 0) {
|
|
1535
|
+
certEntries = context.local_cert_chain;
|
|
1536
|
+
}
|
|
1537
|
+
// TLS 1.2 Certificate: certificate_list<0..2^24-1>
|
|
1538
|
+
// Each entry: cert_length<3> + cert_der
|
|
1539
|
+
let totalLen = 0;
|
|
1540
|
+
for (let ci = 0; ci < certEntries.length; ci++) {
|
|
1541
|
+
totalLen += 3 + certEntries[ci].cert.length;
|
|
1542
|
+
}
|
|
1543
|
+
let certBody = new Uint8Array(3 + totalLen);
|
|
1544
|
+
certBody[0] = (totalLen >> 16) & 0xff;
|
|
1545
|
+
certBody[1] = (totalLen >> 8) & 0xff;
|
|
1546
|
+
certBody[2] = totalLen & 0xff;
|
|
1547
|
+
let off = 3;
|
|
1548
|
+
for (let ci = 0; ci < certEntries.length; ci++) {
|
|
1549
|
+
let der = certEntries[ci].cert;
|
|
1550
|
+
certBody[off] = (der.length >> 16) & 0xff;
|
|
1551
|
+
certBody[off+1] = (der.length >> 8) & 0xff;
|
|
1552
|
+
certBody[off+2] = der.length & 0xff;
|
|
1553
|
+
certBody.set(der, off + 3);
|
|
1554
|
+
off += 3 + der.length;
|
|
1555
|
+
}
|
|
1556
|
+
let cert_data = wire.build_message(wire.TLS_MESSAGE_TYPE.CERTIFICATE, certBody);
|
|
1557
|
+
pushTranscript(cert_data);
|
|
1558
|
+
ev.emit('message', 0, context.message_sent_seq, 'certificate', cert_data);
|
|
1559
|
+
context.message_sent_seq++;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1417
1562
|
let public_key = context.local_key_groups[context.selected_group].public_key;
|
|
1418
1563
|
|
|
1419
1564
|
let message_data = build_tls_message({
|
|
1420
1565
|
type: 'client_key_exchange',
|
|
1421
1566
|
public_key: public_key,
|
|
1422
1567
|
});
|
|
1423
|
-
|
|
1568
|
+
pushTranscript(message_data);
|
|
1424
1569
|
|
|
1425
1570
|
// Set via params_to_set to trigger re-evaluation (EMS needs this)
|
|
1426
1571
|
params_to_set['key_exchange_sent'] = true;
|
|
1572
|
+
|
|
1573
|
+
// Save transcript length for EMS: session_hash includes up to CKE only (RFC 7627)
|
|
1574
|
+
context._emsTranscriptLen = context.transcript.length;
|
|
1427
1575
|
|
|
1428
1576
|
ev.emit('message', 0, context.message_sent_seq, 'client_key_exchange', message_data);
|
|
1429
1577
|
|
|
1430
1578
|
context.message_sent_seq++;
|
|
1431
1579
|
|
|
1580
|
+
// TLS 1.2 CertificateVerify: if we sent a non-empty Certificate, prove we own the private key
|
|
1581
|
+
if (context.certificateRequested && context.cert_private_key && context.local_cert_chain && context.local_cert_chain.length > 0) {
|
|
1582
|
+
// sign_with_scheme hashes internally, so pass RAW transcript (not pre-hashed)
|
|
1583
|
+
let transcript_data = concatUint8Arrays(context.transcript);
|
|
1584
|
+
|
|
1585
|
+
// Pick scheme matching our cert + server's requested algorithms
|
|
1586
|
+
let cert_key_obj = crypto.createPrivateKey({ key: Buffer.from(context.cert_private_key), format: 'der', type: 'pkcs8' });
|
|
1587
|
+
let reqAlgs = context.certificateRequestSigAlgs.length > 0
|
|
1588
|
+
? context.certificateRequestSigAlgs
|
|
1589
|
+
: context.local_supported_signature_algorithms;
|
|
1590
|
+
let scheme = pick_scheme(wire.TLS_VERSION.TLS1_2, cert_key_obj, reqAlgs);
|
|
1591
|
+
let signature = sign_with_scheme(wire.TLS_VERSION.TLS1_2, scheme, transcript_data, cert_key_obj);
|
|
1592
|
+
|
|
1593
|
+
// Build CertificateVerify: scheme(2) + sig_length(2) + sig
|
|
1594
|
+
let cvBody = new Uint8Array(2 + 2 + signature.length);
|
|
1595
|
+
cvBody[0] = (scheme >> 8) & 0xff;
|
|
1596
|
+
cvBody[1] = scheme & 0xff;
|
|
1597
|
+
cvBody[2] = (signature.length >> 8) & 0xff;
|
|
1598
|
+
cvBody[3] = signature.length & 0xff;
|
|
1599
|
+
cvBody.set(signature, 4);
|
|
1600
|
+
|
|
1601
|
+
let cv_data = wire.build_message(wire.TLS_MESSAGE_TYPE.CERTIFICATE_VERIFY, cvBody);
|
|
1602
|
+
pushTranscript(cv_data);
|
|
1603
|
+
ev.emit('message', 0, context.message_sent_seq, 'certificate_verify', cv_data);
|
|
1604
|
+
context.message_sent_seq++;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1432
1607
|
|
|
1433
1608
|
}else if (context.isServer==true && context.cert_sent == true) {
|
|
1434
1609
|
|
|
@@ -1460,7 +1635,7 @@ function TLSSession(options){
|
|
|
1460
1635
|
sig_alg: scheme12,
|
|
1461
1636
|
signature: sig_data
|
|
1462
1637
|
});
|
|
1463
|
-
|
|
1638
|
+
pushTranscript(message_data);
|
|
1464
1639
|
|
|
1465
1640
|
context.key_exchange_sent = true;
|
|
1466
1641
|
|
|
@@ -1473,16 +1648,16 @@ function TLSSession(options){
|
|
|
1473
1648
|
}
|
|
1474
1649
|
|
|
1475
1650
|
//server hello done - 1.2 only...
|
|
1476
|
-
if(context.isServer==true && context.selected_version
|
|
1651
|
+
if(context.isServer==true && (context.selected_version === wire.TLS_VERSION.TLS1_2 || context.selected_version === wire.DTLS_VERSION.DTLS1_2)){
|
|
1477
1652
|
if(context.hello_done_sent==false && context.key_exchange_sent==true){
|
|
1478
1653
|
|
|
1479
1654
|
let message_data = build_tls_message({
|
|
1480
1655
|
type: 'server_hello_done'});
|
|
1481
|
-
|
|
1656
|
+
pushTranscript(message_data);
|
|
1482
1657
|
|
|
1483
1658
|
context.hello_done_sent=true;
|
|
1484
1659
|
|
|
1485
|
-
ev.emit('message',0,context.message_sent_seq,'
|
|
1660
|
+
ev.emit('message',0,context.message_sent_seq,'server_hello_done',message_data);
|
|
1486
1661
|
|
|
1487
1662
|
context.message_sent_seq++;
|
|
1488
1663
|
|
|
@@ -1506,7 +1681,7 @@ function TLSSession(options){
|
|
|
1506
1681
|
entries: certCtx.certificateChain,
|
|
1507
1682
|
certificate_request_context: context.certificateRequestContext || new Uint8Array(0),
|
|
1508
1683
|
});
|
|
1509
|
-
|
|
1684
|
+
pushTranscript(cert_data);
|
|
1510
1685
|
ev.emit('message', 1, context.message_sent_seq, 'certificate', cert_data);
|
|
1511
1686
|
context.message_sent_seq++;
|
|
1512
1687
|
|
|
@@ -1520,7 +1695,7 @@ function TLSSession(options){
|
|
|
1520
1695
|
scheme: scheme,
|
|
1521
1696
|
signature: signature,
|
|
1522
1697
|
});
|
|
1523
|
-
|
|
1698
|
+
pushTranscript(cv_data);
|
|
1524
1699
|
ev.emit('message', 1, context.message_sent_seq, 'certificate_verify', cv_data);
|
|
1525
1700
|
context.message_sent_seq++;
|
|
1526
1701
|
} else {
|
|
@@ -1531,7 +1706,7 @@ function TLSSession(options){
|
|
|
1531
1706
|
entries: [],
|
|
1532
1707
|
certificate_request_context: context.certificateRequestContext || new Uint8Array(0),
|
|
1533
1708
|
});
|
|
1534
|
-
|
|
1709
|
+
pushTranscript(cert_data);
|
|
1535
1710
|
ev.emit('message', 1, context.message_sent_seq, 'certificate', cert_data);
|
|
1536
1711
|
context.message_sent_seq++;
|
|
1537
1712
|
}
|
|
@@ -1541,7 +1716,7 @@ function TLSSession(options){
|
|
|
1541
1716
|
// base_secret may be null after app secrets are derived, so we also check handshake secret.
|
|
1542
1717
|
if (context.finished_sent==false && context.selected_cipher_suite!==null && (context.base_secret!==null || context.local_handshake_traffic_secret!==null)){
|
|
1543
1718
|
|
|
1544
|
-
if(context.selected_version === wire.TLS_VERSION.TLS1_3 && context.local_handshake_traffic_secret!==null){
|
|
1719
|
+
if((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3) && context.local_handshake_traffic_secret!==null){
|
|
1545
1720
|
|
|
1546
1721
|
if((context.isServer==false && context.remote_finished_ok==true && context.local_app_traffic_secret!==null && context.remote_app_traffic_secret!==null) || (context.isServer==true && context.cert_verify_sent==true && context.local_cert_chain!==null) || (context.isServer==true && context.psk_accepted==true && context.encrypted_exts_sent==true)){
|
|
1547
1722
|
|
|
@@ -1553,7 +1728,7 @@ function TLSSession(options){
|
|
|
1553
1728
|
data: finished_data
|
|
1554
1729
|
});
|
|
1555
1730
|
|
|
1556
|
-
|
|
1731
|
+
pushTranscript(message_data);
|
|
1557
1732
|
|
|
1558
1733
|
context.finished_sent=true;
|
|
1559
1734
|
|
|
@@ -1563,7 +1738,7 @@ function TLSSession(options){
|
|
|
1563
1738
|
|
|
1564
1739
|
}
|
|
1565
1740
|
|
|
1566
|
-
}else if(context.selected_version === wire.TLS_VERSION.TLS1_2){
|
|
1741
|
+
}else if((context.selected_version === wire.TLS_VERSION.TLS1_2 || context.selected_version === wire.DTLS_VERSION.DTLS1_2)){
|
|
1567
1742
|
|
|
1568
1743
|
if((context.isServer==true && context.remote_finished_ok==true) || (context.isServer==false && context.key_exchange_sent==true)){
|
|
1569
1744
|
|
|
@@ -1583,7 +1758,7 @@ function TLSSession(options){
|
|
|
1583
1758
|
data: finished_data
|
|
1584
1759
|
});
|
|
1585
1760
|
|
|
1586
|
-
|
|
1761
|
+
pushTranscript(message_data);
|
|
1587
1762
|
|
|
1588
1763
|
context.finished_sent=true;
|
|
1589
1764
|
|
|
@@ -1598,7 +1773,7 @@ function TLSSession(options){
|
|
|
1598
1773
|
}
|
|
1599
1774
|
|
|
1600
1775
|
//get app traffic secret...
|
|
1601
|
-
if (context.selected_version === wire.TLS_VERSION.TLS1_3){
|
|
1776
|
+
if ((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3)){
|
|
1602
1777
|
if(context.base_secret!==null && context.local_app_traffic_secret==null && context.remote_app_traffic_secret==null){
|
|
1603
1778
|
|
|
1604
1779
|
if((context.isServer==true && context.finished_sent==true && context.remote_finished_ok==false) || (context.isServer==false && context.finished_sent==false && context.remote_finished_ok==true)){
|
|
@@ -1624,7 +1799,7 @@ function TLSSession(options){
|
|
|
1624
1799
|
//expected_remote_finished...
|
|
1625
1800
|
if (context.expected_remote_finished==null && context.selected_cipher_suite!==null){
|
|
1626
1801
|
|
|
1627
|
-
if(context.selected_version
|
|
1802
|
+
if((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3) && context.remote_handshake_traffic_secret!==null){
|
|
1628
1803
|
|
|
1629
1804
|
if((context.isServer==true && context.finished_sent==true) || (context.isServer==false && context.remote_finished !== null)){
|
|
1630
1805
|
|
|
@@ -1632,7 +1807,7 @@ function TLSSession(options){
|
|
|
1632
1807
|
|
|
1633
1808
|
}
|
|
1634
1809
|
|
|
1635
|
-
}else if(context.selected_version === wire.TLS_VERSION.TLS1_2 && context.base_secret!==null){
|
|
1810
|
+
}else if((context.selected_version === wire.TLS_VERSION.TLS1_2 || context.selected_version === wire.DTLS_VERSION.DTLS1_2) && context.base_secret!==null){
|
|
1636
1811
|
|
|
1637
1812
|
if(context.remote_finished!==null){
|
|
1638
1813
|
|
|
@@ -1668,7 +1843,7 @@ function TLSSession(options){
|
|
|
1668
1843
|
data: context.remote_finished
|
|
1669
1844
|
});
|
|
1670
1845
|
|
|
1671
|
-
|
|
1846
|
+
pushTranscript(message_data);
|
|
1672
1847
|
|
|
1673
1848
|
params_to_set['remote_finished_ok']=true;
|
|
1674
1849
|
|
|
@@ -1687,13 +1862,13 @@ function TLSSession(options){
|
|
|
1687
1862
|
|
|
1688
1863
|
|
|
1689
1864
|
|
|
1690
|
-
if(context.state!=='connected' && context.remote_finished_ok==true && ((context.selected_version === wire.TLS_VERSION.TLS1_3 && context.local_app_traffic_secret!==null && context.remote_app_traffic_secret!==null) || context.selected_version === wire.TLS_VERSION.TLS1_2)){
|
|
1865
|
+
if(context.state!=='connected' && context.remote_finished_ok==true && (((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3) && context.local_app_traffic_secret!==null && context.remote_app_traffic_secret!==null) || (context.selected_version === wire.TLS_VERSION.TLS1_2 || context.selected_version === wire.DTLS_VERSION.DTLS1_2))){
|
|
1691
1866
|
context.state='connected';
|
|
1692
1867
|
context.handshakeEndTime = Date.now();
|
|
1693
1868
|
ev.emit('secureConnect');
|
|
1694
1869
|
|
|
1695
1870
|
// TLS 1.3: compute resumption_master_secret (both client and server need it)
|
|
1696
|
-
if (context.selected_version === wire.TLS_VERSION.TLS1_3 && context.tls13_master_secret && !context.resumption_master_secret) {
|
|
1871
|
+
if ((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3) && context.tls13_master_secret && !context.resumption_master_secret) {
|
|
1697
1872
|
let hashName = TLS_CIPHER_SUITES[context.selected_cipher_suite].hash;
|
|
1698
1873
|
context.resumption_master_secret = derive_resumption_master_secret(
|
|
1699
1874
|
hashName, context.tls13_master_secret, concatUint8Arrays(context.transcript)
|
|
@@ -1701,7 +1876,7 @@ function TLSSession(options){
|
|
|
1701
1876
|
}
|
|
1702
1877
|
|
|
1703
1878
|
// TLS 1.3 server: send NewSessionTicket
|
|
1704
|
-
if (context.selected_version === wire.TLS_VERSION.TLS1_3 && context.isServer && !context.session_ticket_sent && !context.noTickets && context.resumption_master_secret) {
|
|
1879
|
+
if ((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3) && context.isServer && !context.session_ticket_sent && !context.noTickets && context.resumption_master_secret) {
|
|
1705
1880
|
context.session_ticket_sent = true;
|
|
1706
1881
|
|
|
1707
1882
|
let hashName = TLS_CIPHER_SUITES[context.selected_cipher_suite].hash;
|
|
@@ -1926,6 +2101,16 @@ function TLSSession(options){
|
|
|
1926
2101
|
extensions.unshift({ type: 'SERVER_NAME', value: context.local_sni });
|
|
1927
2102
|
}
|
|
1928
2103
|
|
|
2104
|
+
// Add ALPN if provided (e.g. 'h3' for QUIC)
|
|
2105
|
+
if (context.local_supported_alpns && context.local_supported_alpns.length > 0) {
|
|
2106
|
+
extensions.push({ type: 'ALPN', value: context.local_supported_alpns });
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
// Add custom extensions (e.g. QUIC transport params 0x39)
|
|
2110
|
+
for (let i in context.local_extensions) {
|
|
2111
|
+
extensions.push(context.local_extensions[i]);
|
|
2112
|
+
}
|
|
2113
|
+
|
|
1929
2114
|
// PSK resumption: check if session/psk was provided
|
|
1930
2115
|
let pskData = options.session || options.psk || null;
|
|
1931
2116
|
let message_data;
|
|
@@ -1966,6 +2151,7 @@ function TLSSession(options){
|
|
|
1966
2151
|
version: 0x0303,
|
|
1967
2152
|
random: context.local_random,
|
|
1968
2153
|
session_id: context.local_session_id,
|
|
2154
|
+
cookie: context.dtls_cookie,
|
|
1969
2155
|
cipher_suite: context.local_supported_cipher_suites,
|
|
1970
2156
|
extensions: extensions
|
|
1971
2157
|
};
|
|
@@ -1990,13 +2176,14 @@ function TLSSession(options){
|
|
|
1990
2176
|
version: 0x0303,
|
|
1991
2177
|
random: context.local_random,
|
|
1992
2178
|
session_id: context.local_session_id,
|
|
2179
|
+
cookie: context.dtls_cookie,
|
|
1993
2180
|
cipher_suite: context.local_supported_cipher_suites,
|
|
1994
2181
|
extensions: extensions
|
|
1995
2182
|
};
|
|
1996
2183
|
message_data = build_tls_message(build_message_params);
|
|
1997
2184
|
}
|
|
1998
2185
|
|
|
1999
|
-
|
|
2186
|
+
pushTranscript(message_data);
|
|
2000
2187
|
|
|
2001
2188
|
context.hello_sent=true;
|
|
2002
2189
|
|
|
@@ -2140,11 +2327,11 @@ function TLSSession(options){
|
|
|
2140
2327
|
let cipherInfo = context.selected_cipher_suite ? TLS_CIPHER_SUITES[context.selected_cipher_suite] : null;
|
|
2141
2328
|
return {
|
|
2142
2329
|
version: context.selected_version,
|
|
2143
|
-
versionName: context.selected_version === 0x0304 ? 'TLSv1.3' : context.selected_version === 0x0303 ? 'TLSv1.2' : null,
|
|
2330
|
+
versionName: context.selected_version === 0x0304 ? 'TLSv1.3' : context.selected_version === 0xFEFC ? 'DTLSv1.3' : context.selected_version === 0x0303 ? 'TLSv1.2' : context.selected_version === 0xFEFD ? 'DTLSv1.2' : null,
|
|
2144
2331
|
cipher: context.selected_cipher_suite,
|
|
2145
2332
|
cipherName: cipherInfo ? cipherInfo.name : null,
|
|
2146
2333
|
group: context.selected_group,
|
|
2147
|
-
groupName: context.selected_group === 0x001d ? 'X25519' : context.selected_group === 0x0017 ? 'P-256' : null,
|
|
2334
|
+
groupName: context.selected_group === 0x001d ? 'X25519' : context.selected_group === 0x0017 ? 'P-256' : context.selected_group === 0x0018 ? 'P-384' : null,
|
|
2148
2335
|
signatureAlgorithm: context.selected_signature_algorithm,
|
|
2149
2336
|
alpn: context.selected_alpn,
|
|
2150
2337
|
sni: context.selected_sni || context.local_sni,
|
|
@@ -2177,7 +2364,7 @@ function TLSSession(options){
|
|
|
2177
2364
|
|
|
2178
2365
|
/** Request a TLS 1.3 Key Update. requestPeer=true means ask the other side to update too. */
|
|
2179
2366
|
requestKeyUpdate: function(requestPeer){
|
|
2180
|
-
if (context.state !== 'connected' || context.selected_version !== wire.TLS_VERSION.TLS1_3) return;
|
|
2367
|
+
if (context.state !== 'connected' || (context.selected_version !== wire.TLS_VERSION.TLS1_3 && context.selected_version !== wire.DTLS_VERSION.DTLS1_3)) return;
|
|
2181
2368
|
let hashName = TLS_CIPHER_SUITES[context.selected_cipher_suite].hash;
|
|
2182
2369
|
let hashLen = getHashLen(hashName);
|
|
2183
2370
|
|