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/tls_session.js
CHANGED
|
@@ -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') {
|
|
@@ -350,11 +367,12 @@ function TLSSession(options){
|
|
|
350
367
|
version: 0x0303,
|
|
351
368
|
random: context.local_random,
|
|
352
369
|
session_id: context.local_session_id,
|
|
370
|
+
cookie: context.dtls_cookie,
|
|
353
371
|
cipher_suite: context.local_supported_cipher_suites,
|
|
354
372
|
extensions: extensions,
|
|
355
373
|
});
|
|
356
374
|
|
|
357
|
-
|
|
375
|
+
pushTranscript(ch2);
|
|
358
376
|
ev.emit('message', 0, context.message_sent_seq, 'hello', ch2);
|
|
359
377
|
context.message_sent_seq++;
|
|
360
378
|
}
|
|
@@ -368,7 +386,9 @@ function TLSSession(options){
|
|
|
368
386
|
remote_random: message.random || null,
|
|
369
387
|
remote_sni: message.sni || null,
|
|
370
388
|
remote_session_id: message.session_id || null,
|
|
371
|
-
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] : []),
|
|
372
392
|
remote_supported_alpns: message.alpn || [],
|
|
373
393
|
remote_supported_cipher_suites: message.cipher_suites || [],
|
|
374
394
|
remote_supported_signature_algorithms: message.signature_algorithms || [],
|
|
@@ -396,21 +416,27 @@ function TLSSession(options){
|
|
|
396
416
|
|
|
397
417
|
}else if(message.type=='client_key_exchange' || message.type=='server_key_exchange'){
|
|
398
418
|
|
|
399
|
-
|
|
419
|
+
pushTranscript(data);
|
|
400
420
|
|
|
401
421
|
if ([0xC02F,0xC02B,0xC030,0xC02C,0xC013,0xC014,0xC009,0xC00A].includes(context.selected_cipher_suite)==true) {//ECDHE
|
|
402
422
|
|
|
403
423
|
// ServerKeyExchange carries the group; ClientKeyExchange does not (server already chose it)
|
|
404
424
|
let kex_group = message.group || context.selected_group;
|
|
405
425
|
|
|
406
|
-
|
|
426
|
+
let kex_updates = {
|
|
407
427
|
add_remote_key_groups: [
|
|
408
428
|
{
|
|
409
429
|
group: kex_group,
|
|
410
430
|
public_key: message.public_key
|
|
411
431
|
}
|
|
412
432
|
],
|
|
413
|
-
}
|
|
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);
|
|
414
440
|
|
|
415
441
|
}else if ([0x009E,0x009F,0x0033,0x0039,0x0067,0x006B].includes(context.selected_cipher_suite)==true) {//DHE
|
|
416
442
|
|
|
@@ -426,7 +452,7 @@ function TLSSession(options){
|
|
|
426
452
|
|
|
427
453
|
}else if(message.type=='server_hello_done'){
|
|
428
454
|
|
|
429
|
-
|
|
455
|
+
pushTranscript(data);
|
|
430
456
|
|
|
431
457
|
|
|
432
458
|
set_context({
|
|
@@ -435,7 +461,7 @@ function TLSSession(options){
|
|
|
435
461
|
|
|
436
462
|
}else if(message.type=='encrypted_extensions'){
|
|
437
463
|
|
|
438
|
-
|
|
464
|
+
pushTranscript(data);
|
|
439
465
|
|
|
440
466
|
set_context({
|
|
441
467
|
remote_supported_groups: message.supported_groups || [],
|
|
@@ -443,7 +469,7 @@ function TLSSession(options){
|
|
|
443
469
|
|
|
444
470
|
}else if(message.type=='certificate'){
|
|
445
471
|
|
|
446
|
-
|
|
472
|
+
pushTranscript(data);
|
|
447
473
|
|
|
448
474
|
set_context({
|
|
449
475
|
remote_cert_chain: message.entries,
|
|
@@ -458,7 +484,7 @@ function TLSSession(options){
|
|
|
458
484
|
|
|
459
485
|
}else if(message.type=='certificate_verify'){
|
|
460
486
|
|
|
461
|
-
|
|
487
|
+
pushTranscript(data);
|
|
462
488
|
|
|
463
489
|
}else if(message.type=='finished'){
|
|
464
490
|
|
|
@@ -487,7 +513,7 @@ function TLSSession(options){
|
|
|
487
513
|
}else if(message.type=='key_update'){
|
|
488
514
|
|
|
489
515
|
// Peer is updating their traffic secret (we update our read key)
|
|
490
|
-
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)){
|
|
491
517
|
let hashName = TLS_CIPHER_SUITES[context.selected_cipher_suite].hash;
|
|
492
518
|
let hashLen = getHashLen(hashName);
|
|
493
519
|
let newRemoteSecret = hkdf_expand_label(hashName, context.remote_app_traffic_secret, 'traffic upd', new Uint8Array(0), hashLen);
|
|
@@ -512,7 +538,7 @@ function TLSSession(options){
|
|
|
512
538
|
|
|
513
539
|
// Server is requesting a client certificate (TLS 1.3)
|
|
514
540
|
if(!context.isServer){
|
|
515
|
-
|
|
541
|
+
pushTranscript(data);
|
|
516
542
|
context.certificateRequested = true;
|
|
517
543
|
context.certificateRequestContext = message.certificate_request_context || new Uint8Array(0);
|
|
518
544
|
context.certificateRequestSigAlgs = message.signature_algorithms || [];
|
|
@@ -871,7 +897,10 @@ function TLSSession(options){
|
|
|
871
897
|
}
|
|
872
898
|
}
|
|
873
899
|
|
|
874
|
-
|
|
900
|
+
if('dtls_cookie' in options){
|
|
901
|
+
context.dtls_cookie=options.dtls_cookie;
|
|
902
|
+
has_changed=true;
|
|
903
|
+
}
|
|
875
904
|
|
|
876
905
|
|
|
877
906
|
}
|
|
@@ -901,6 +930,16 @@ function TLSSession(options){
|
|
|
901
930
|
|
|
902
931
|
if('selected_version' in params_to_set==false || params_to_set.selected_version==null){
|
|
903
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
|
+
}
|
|
904
943
|
}
|
|
905
944
|
|
|
906
945
|
//select selected_cipher...
|
|
@@ -1050,7 +1089,7 @@ function TLSSession(options){
|
|
|
1050
1089
|
if(context.isServer==true){
|
|
1051
1090
|
|
|
1052
1091
|
// HelloRetryRequest: if we selected a group but client didn't send a key_share for it
|
|
1053
|
-
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) &&
|
|
1054
1093
|
context.selected_group !== null && context.selected_cipher_suite !== null &&
|
|
1055
1094
|
!(context.selected_group in context.remote_key_groups)){
|
|
1056
1095
|
|
|
@@ -1065,12 +1104,12 @@ function TLSSession(options){
|
|
|
1065
1104
|
// Build and send HRR (it's a ServerHello with magic random)
|
|
1066
1105
|
let hrr_body = wire.build_hello_retry_request({
|
|
1067
1106
|
cipher_suite: context.selected_cipher_suite,
|
|
1068
|
-
selected_version:
|
|
1107
|
+
selected_version: context.selected_version,
|
|
1069
1108
|
selected_group: context.selected_group,
|
|
1070
1109
|
session_id: context.remote_session_id,
|
|
1071
1110
|
});
|
|
1072
1111
|
let hrr_data = wire.build_message(wire.TLS_MESSAGE_TYPE.SERVER_HELLO, hrr_body);
|
|
1073
|
-
|
|
1112
|
+
pushTranscript(hrr_data);
|
|
1074
1113
|
|
|
1075
1114
|
ev.emit('message', 0, context.message_sent_seq, 'hello_retry_request', hrr_data);
|
|
1076
1115
|
context.message_sent_seq++;
|
|
@@ -1090,14 +1129,14 @@ function TLSSession(options){
|
|
|
1090
1129
|
if(context.hello_sent==false){
|
|
1091
1130
|
|
|
1092
1131
|
if(context.selected_version!==null && context.selected_cipher_suite!==null && context.selected_session_id!==null){
|
|
1093
|
-
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)){
|
|
1094
1133
|
if(context.selected_group in context.local_key_groups==true && context.local_key_groups[context.selected_group].public_key!==null){
|
|
1095
1134
|
// After HRR, don't send ServerHello until CH2 provides the requested key_share
|
|
1096
1135
|
if (!context.helloRetried || (context.selected_group in context.remote_key_groups)) {
|
|
1097
1136
|
can_send_hello=true;
|
|
1098
1137
|
}
|
|
1099
1138
|
}
|
|
1100
|
-
}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)){
|
|
1101
1140
|
can_send_hello=true;
|
|
1102
1141
|
}
|
|
1103
1142
|
}
|
|
@@ -1111,12 +1150,12 @@ function TLSSession(options){
|
|
|
1111
1150
|
|
|
1112
1151
|
let build_message_params=null;
|
|
1113
1152
|
|
|
1114
|
-
if(context.selected_version
|
|
1153
|
+
if((context.selected_version === wire.TLS_VERSION.TLS1_3 || context.selected_version === wire.DTLS_VERSION.DTLS1_3)){
|
|
1115
1154
|
|
|
1116
1155
|
let shExtensions = [
|
|
1117
1156
|
{
|
|
1118
1157
|
type: 'SUPPORTED_VERSIONS',
|
|
1119
|
-
value:
|
|
1158
|
+
value: context.selected_version
|
|
1120
1159
|
},
|
|
1121
1160
|
{
|
|
1122
1161
|
type: 'KEY_SHARE',
|
|
@@ -1142,7 +1181,7 @@ function TLSSession(options){
|
|
|
1142
1181
|
};
|
|
1143
1182
|
|
|
1144
1183
|
|
|
1145
|
-
}else if(context.selected_version
|
|
1184
|
+
}else if((context.selected_version === wire.TLS_VERSION.TLS1_2 || context.selected_version === wire.DTLS_VERSION.DTLS1_2)){
|
|
1146
1185
|
|
|
1147
1186
|
|
|
1148
1187
|
// TLS 1.2 ServerHello: no SUPPORTED_VERSIONS or KEY_SHARE.
|
|
@@ -1184,7 +1223,7 @@ function TLSSession(options){
|
|
|
1184
1223
|
|
|
1185
1224
|
let message_data = build_tls_message(build_message_params);
|
|
1186
1225
|
|
|
1187
|
-
|
|
1226
|
+
pushTranscript(message_data);
|
|
1188
1227
|
|
|
1189
1228
|
context.hello_sent=true;
|
|
1190
1229
|
|
|
@@ -1204,7 +1243,7 @@ function TLSSession(options){
|
|
|
1204
1243
|
|
|
1205
1244
|
//get base_secret
|
|
1206
1245
|
if (context.base_secret==null && context.selected_cipher_suite !== null){
|
|
1207
|
-
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)){
|
|
1208
1247
|
|
|
1209
1248
|
let hashName = TLS_CIPHER_SUITES[context.selected_cipher_suite].hash;
|
|
1210
1249
|
let result;
|
|
@@ -1226,7 +1265,7 @@ function TLSSession(options){
|
|
|
1226
1265
|
params_to_set['remote_handshake_traffic_secret']=result.server_handshake_traffic_secret;
|
|
1227
1266
|
}
|
|
1228
1267
|
|
|
1229
|
-
}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){
|
|
1230
1269
|
if(context.ecdhe_shared_secret !== null){
|
|
1231
1270
|
|
|
1232
1271
|
|
|
@@ -1246,7 +1285,11 @@ function TLSSession(options){
|
|
|
1246
1285
|
if(context.isServer || context.key_exchange_sent){
|
|
1247
1286
|
let hashFn = getHashFn(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash);
|
|
1248
1287
|
|
|
1249
|
-
|
|
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));
|
|
1250
1293
|
|
|
1251
1294
|
let master_secret = tls12_prf(context.ecdhe_shared_secret, "extended master secret", transcript_hash, 48, TLS_CIPHER_SUITES[context.selected_cipher_suite].hash);
|
|
1252
1295
|
|
|
@@ -1270,7 +1313,7 @@ function TLSSession(options){
|
|
|
1270
1313
|
|
|
1271
1314
|
|
|
1272
1315
|
//send encrypted_extensions...
|
|
1273
|
-
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)){
|
|
1274
1317
|
if(context.encrypted_exts_sent==false && context.hello_sent==true && context.local_handshake_traffic_secret!==null){
|
|
1275
1318
|
|
|
1276
1319
|
let extensions=[];
|
|
@@ -1288,7 +1331,7 @@ function TLSSession(options){
|
|
|
1288
1331
|
extensions: extensions
|
|
1289
1332
|
});
|
|
1290
1333
|
|
|
1291
|
-
|
|
1334
|
+
pushTranscript(message_data);
|
|
1292
1335
|
|
|
1293
1336
|
context.encrypted_exts_sent=true;
|
|
1294
1337
|
|
|
@@ -1302,31 +1345,31 @@ function TLSSession(options){
|
|
|
1302
1345
|
|
|
1303
1346
|
//send certificate... (skip for PSK resumption — no cert needed)
|
|
1304
1347
|
// But first: send CertificateRequest if requestCert is set (TLS 1.3 only, between EE and Cert)
|
|
1305
|
-
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){
|
|
1306
1349
|
let cr_data = build_tls_message({
|
|
1307
1350
|
type: 'certificate_request',
|
|
1308
1351
|
certificate_request_context: new Uint8Array(0),
|
|
1309
1352
|
signature_algorithms: context.local_supported_signature_algorithms,
|
|
1310
1353
|
});
|
|
1311
|
-
|
|
1354
|
+
pushTranscript(cr_data);
|
|
1312
1355
|
context.certificateRequestSent = true;
|
|
1313
1356
|
ev.emit('message', 1, context.message_sent_seq, 'certificate_request', cr_data);
|
|
1314
1357
|
context.message_sent_seq++;
|
|
1315
1358
|
}
|
|
1316
1359
|
|
|
1317
1360
|
if(context.isServer==true && context.cert_sent==false && context.local_cert_chain!==null && !context.psk_accepted){
|
|
1318
|
-
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)){
|
|
1319
1362
|
|
|
1320
1363
|
let message_data = build_tls_message({
|
|
1321
1364
|
type: 'certificate',
|
|
1322
1365
|
version: context.selected_version,
|
|
1323
1366
|
entries: context.local_cert_chain
|
|
1324
1367
|
});
|
|
1325
|
-
|
|
1368
|
+
pushTranscript(message_data);
|
|
1326
1369
|
|
|
1327
1370
|
context.cert_sent=true;
|
|
1328
1371
|
|
|
1329
|
-
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)){
|
|
1330
1373
|
ev.emit('message',1,context.message_sent_seq,'certificate',message_data);
|
|
1331
1374
|
}else{
|
|
1332
1375
|
ev.emit('message',0,context.message_sent_seq,'certificate',message_data);
|
|
@@ -1344,7 +1387,7 @@ function TLSSession(options){
|
|
|
1344
1387
|
|
|
1345
1388
|
|
|
1346
1389
|
//send certificate verify...
|
|
1347
|
-
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)){
|
|
1348
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){
|
|
1349
1392
|
|
|
1350
1393
|
let tbs_data = build_cert_verify_tbs(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash,true,concatUint8Arrays(context.transcript));
|
|
@@ -1454,7 +1497,7 @@ function TLSSession(options){
|
|
|
1454
1497
|
|
|
1455
1498
|
|
|
1456
1499
|
|
|
1457
|
-
|
|
1500
|
+
pushTranscript(message_data);
|
|
1458
1501
|
|
|
1459
1502
|
context.cert_verify_sent=true;
|
|
1460
1503
|
|
|
@@ -1477,26 +1520,90 @@ function TLSSession(options){
|
|
|
1477
1520
|
|
|
1478
1521
|
|
|
1479
1522
|
// client/server key exchange - 1.2 only...
|
|
1480
|
-
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)) {
|
|
1481
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){
|
|
1482
1525
|
|
|
1483
1526
|
if (context.isServer==false && context.remote_hello_done==true) {
|
|
1484
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
|
+
|
|
1485
1562
|
let public_key = context.local_key_groups[context.selected_group].public_key;
|
|
1486
1563
|
|
|
1487
1564
|
let message_data = build_tls_message({
|
|
1488
1565
|
type: 'client_key_exchange',
|
|
1489
1566
|
public_key: public_key,
|
|
1490
1567
|
});
|
|
1491
|
-
|
|
1568
|
+
pushTranscript(message_data);
|
|
1492
1569
|
|
|
1493
1570
|
// Set via params_to_set to trigger re-evaluation (EMS needs this)
|
|
1494
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;
|
|
1495
1575
|
|
|
1496
1576
|
ev.emit('message', 0, context.message_sent_seq, 'client_key_exchange', message_data);
|
|
1497
1577
|
|
|
1498
1578
|
context.message_sent_seq++;
|
|
1499
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
|
+
|
|
1500
1607
|
|
|
1501
1608
|
}else if (context.isServer==true && context.cert_sent == true) {
|
|
1502
1609
|
|
|
@@ -1528,7 +1635,7 @@ function TLSSession(options){
|
|
|
1528
1635
|
sig_alg: scheme12,
|
|
1529
1636
|
signature: sig_data
|
|
1530
1637
|
});
|
|
1531
|
-
|
|
1638
|
+
pushTranscript(message_data);
|
|
1532
1639
|
|
|
1533
1640
|
context.key_exchange_sent = true;
|
|
1534
1641
|
|
|
@@ -1541,16 +1648,16 @@ function TLSSession(options){
|
|
|
1541
1648
|
}
|
|
1542
1649
|
|
|
1543
1650
|
//server hello done - 1.2 only...
|
|
1544
|
-
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)){
|
|
1545
1652
|
if(context.hello_done_sent==false && context.key_exchange_sent==true){
|
|
1546
1653
|
|
|
1547
1654
|
let message_data = build_tls_message({
|
|
1548
1655
|
type: 'server_hello_done'});
|
|
1549
|
-
|
|
1656
|
+
pushTranscript(message_data);
|
|
1550
1657
|
|
|
1551
1658
|
context.hello_done_sent=true;
|
|
1552
1659
|
|
|
1553
|
-
ev.emit('message',0,context.message_sent_seq,'
|
|
1660
|
+
ev.emit('message',0,context.message_sent_seq,'server_hello_done',message_data);
|
|
1554
1661
|
|
|
1555
1662
|
context.message_sent_seq++;
|
|
1556
1663
|
|
|
@@ -1574,7 +1681,7 @@ function TLSSession(options){
|
|
|
1574
1681
|
entries: certCtx.certificateChain,
|
|
1575
1682
|
certificate_request_context: context.certificateRequestContext || new Uint8Array(0),
|
|
1576
1683
|
});
|
|
1577
|
-
|
|
1684
|
+
pushTranscript(cert_data);
|
|
1578
1685
|
ev.emit('message', 1, context.message_sent_seq, 'certificate', cert_data);
|
|
1579
1686
|
context.message_sent_seq++;
|
|
1580
1687
|
|
|
@@ -1588,7 +1695,7 @@ function TLSSession(options){
|
|
|
1588
1695
|
scheme: scheme,
|
|
1589
1696
|
signature: signature,
|
|
1590
1697
|
});
|
|
1591
|
-
|
|
1698
|
+
pushTranscript(cv_data);
|
|
1592
1699
|
ev.emit('message', 1, context.message_sent_seq, 'certificate_verify', cv_data);
|
|
1593
1700
|
context.message_sent_seq++;
|
|
1594
1701
|
} else {
|
|
@@ -1599,7 +1706,7 @@ function TLSSession(options){
|
|
|
1599
1706
|
entries: [],
|
|
1600
1707
|
certificate_request_context: context.certificateRequestContext || new Uint8Array(0),
|
|
1601
1708
|
});
|
|
1602
|
-
|
|
1709
|
+
pushTranscript(cert_data);
|
|
1603
1710
|
ev.emit('message', 1, context.message_sent_seq, 'certificate', cert_data);
|
|
1604
1711
|
context.message_sent_seq++;
|
|
1605
1712
|
}
|
|
@@ -1609,7 +1716,7 @@ function TLSSession(options){
|
|
|
1609
1716
|
// base_secret may be null after app secrets are derived, so we also check handshake secret.
|
|
1610
1717
|
if (context.finished_sent==false && context.selected_cipher_suite!==null && (context.base_secret!==null || context.local_handshake_traffic_secret!==null)){
|
|
1611
1718
|
|
|
1612
|
-
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){
|
|
1613
1720
|
|
|
1614
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)){
|
|
1615
1722
|
|
|
@@ -1621,7 +1728,7 @@ function TLSSession(options){
|
|
|
1621
1728
|
data: finished_data
|
|
1622
1729
|
});
|
|
1623
1730
|
|
|
1624
|
-
|
|
1731
|
+
pushTranscript(message_data);
|
|
1625
1732
|
|
|
1626
1733
|
context.finished_sent=true;
|
|
1627
1734
|
|
|
@@ -1631,7 +1738,7 @@ function TLSSession(options){
|
|
|
1631
1738
|
|
|
1632
1739
|
}
|
|
1633
1740
|
|
|
1634
|
-
}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)){
|
|
1635
1742
|
|
|
1636
1743
|
if((context.isServer==true && context.remote_finished_ok==true) || (context.isServer==false && context.key_exchange_sent==true)){
|
|
1637
1744
|
|
|
@@ -1651,7 +1758,7 @@ function TLSSession(options){
|
|
|
1651
1758
|
data: finished_data
|
|
1652
1759
|
});
|
|
1653
1760
|
|
|
1654
|
-
|
|
1761
|
+
pushTranscript(message_data);
|
|
1655
1762
|
|
|
1656
1763
|
context.finished_sent=true;
|
|
1657
1764
|
|
|
@@ -1666,7 +1773,7 @@ function TLSSession(options){
|
|
|
1666
1773
|
}
|
|
1667
1774
|
|
|
1668
1775
|
//get app traffic secret...
|
|
1669
|
-
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)){
|
|
1670
1777
|
if(context.base_secret!==null && context.local_app_traffic_secret==null && context.remote_app_traffic_secret==null){
|
|
1671
1778
|
|
|
1672
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)){
|
|
@@ -1692,7 +1799,7 @@ function TLSSession(options){
|
|
|
1692
1799
|
//expected_remote_finished...
|
|
1693
1800
|
if (context.expected_remote_finished==null && context.selected_cipher_suite!==null){
|
|
1694
1801
|
|
|
1695
|
-
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){
|
|
1696
1803
|
|
|
1697
1804
|
if((context.isServer==true && context.finished_sent==true) || (context.isServer==false && context.remote_finished !== null)){
|
|
1698
1805
|
|
|
@@ -1700,7 +1807,7 @@ function TLSSession(options){
|
|
|
1700
1807
|
|
|
1701
1808
|
}
|
|
1702
1809
|
|
|
1703
|
-
}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){
|
|
1704
1811
|
|
|
1705
1812
|
if(context.remote_finished!==null){
|
|
1706
1813
|
|
|
@@ -1736,7 +1843,7 @@ function TLSSession(options){
|
|
|
1736
1843
|
data: context.remote_finished
|
|
1737
1844
|
});
|
|
1738
1845
|
|
|
1739
|
-
|
|
1846
|
+
pushTranscript(message_data);
|
|
1740
1847
|
|
|
1741
1848
|
params_to_set['remote_finished_ok']=true;
|
|
1742
1849
|
|
|
@@ -1755,13 +1862,13 @@ function TLSSession(options){
|
|
|
1755
1862
|
|
|
1756
1863
|
|
|
1757
1864
|
|
|
1758
|
-
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))){
|
|
1759
1866
|
context.state='connected';
|
|
1760
1867
|
context.handshakeEndTime = Date.now();
|
|
1761
1868
|
ev.emit('secureConnect');
|
|
1762
1869
|
|
|
1763
1870
|
// TLS 1.3: compute resumption_master_secret (both client and server need it)
|
|
1764
|
-
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) {
|
|
1765
1872
|
let hashName = TLS_CIPHER_SUITES[context.selected_cipher_suite].hash;
|
|
1766
1873
|
context.resumption_master_secret = derive_resumption_master_secret(
|
|
1767
1874
|
hashName, context.tls13_master_secret, concatUint8Arrays(context.transcript)
|
|
@@ -1769,7 +1876,7 @@ function TLSSession(options){
|
|
|
1769
1876
|
}
|
|
1770
1877
|
|
|
1771
1878
|
// TLS 1.3 server: send NewSessionTicket
|
|
1772
|
-
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) {
|
|
1773
1880
|
context.session_ticket_sent = true;
|
|
1774
1881
|
|
|
1775
1882
|
let hashName = TLS_CIPHER_SUITES[context.selected_cipher_suite].hash;
|
|
@@ -2044,6 +2151,7 @@ function TLSSession(options){
|
|
|
2044
2151
|
version: 0x0303,
|
|
2045
2152
|
random: context.local_random,
|
|
2046
2153
|
session_id: context.local_session_id,
|
|
2154
|
+
cookie: context.dtls_cookie,
|
|
2047
2155
|
cipher_suite: context.local_supported_cipher_suites,
|
|
2048
2156
|
extensions: extensions
|
|
2049
2157
|
};
|
|
@@ -2068,13 +2176,14 @@ function TLSSession(options){
|
|
|
2068
2176
|
version: 0x0303,
|
|
2069
2177
|
random: context.local_random,
|
|
2070
2178
|
session_id: context.local_session_id,
|
|
2179
|
+
cookie: context.dtls_cookie,
|
|
2071
2180
|
cipher_suite: context.local_supported_cipher_suites,
|
|
2072
2181
|
extensions: extensions
|
|
2073
2182
|
};
|
|
2074
2183
|
message_data = build_tls_message(build_message_params);
|
|
2075
2184
|
}
|
|
2076
2185
|
|
|
2077
|
-
|
|
2186
|
+
pushTranscript(message_data);
|
|
2078
2187
|
|
|
2079
2188
|
context.hello_sent=true;
|
|
2080
2189
|
|
|
@@ -2218,7 +2327,7 @@ function TLSSession(options){
|
|
|
2218
2327
|
let cipherInfo = context.selected_cipher_suite ? TLS_CIPHER_SUITES[context.selected_cipher_suite] : null;
|
|
2219
2328
|
return {
|
|
2220
2329
|
version: context.selected_version,
|
|
2221
|
-
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,
|
|
2222
2331
|
cipher: context.selected_cipher_suite,
|
|
2223
2332
|
cipherName: cipherInfo ? cipherInfo.name : null,
|
|
2224
2333
|
group: context.selected_group,
|
|
@@ -2255,7 +2364,7 @@ function TLSSession(options){
|
|
|
2255
2364
|
|
|
2256
2365
|
/** Request a TLS 1.3 Key Update. requestPeer=true means ask the other side to update too. */
|
|
2257
2366
|
requestKeyUpdate: function(requestPeer){
|
|
2258
|
-
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;
|
|
2259
2368
|
let hashName = TLS_CIPHER_SUITES[context.selected_cipher_suite].hash;
|
|
2260
2369
|
let hashLen = getHashLen(hashName);
|
|
2261
2370
|
|