lemon-tls 0.1.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/tls_session.js ADDED
@@ -0,0 +1,1441 @@
1
+ var nobleHashes={
2
+ hmac: require("@noble/hashes/hmac.js")['hmac'],
3
+ hkdf: require("@noble/hashes/hkdf.js")['hkdf'],
4
+ hkdf_extract: require("@noble/hashes/hkdf.js")['extract'],
5
+ hkdf_expand: require("@noble/hashes/hkdf.js")['expand'],
6
+ sha256: require("@noble/hashes/sha2.js")['sha256'],
7
+ };
8
+
9
+ var { p256 } = require('@noble/curves/nist.js');
10
+ var { x25519 } = require('@noble/curves/ed25519');
11
+ var { sha256, sha384 } = require('@noble/hashes/sha2');
12
+
13
+ var crypto = require('crypto');
14
+
15
+ var {
16
+ TLS_CIPHER_SUITES,
17
+ build_cert_verify_tbs,
18
+ get_handshake_finished,
19
+ derive_handshake_traffic_secrets,
20
+ derive_app_traffic_secrets
21
+ } = require('./crypto');
22
+
23
+
24
+ var {
25
+ concatUint8Arrays,
26
+ arraybufferEqual,
27
+ arraysEqual
28
+ } = require('./utils');
29
+
30
+
31
+ var wire = require('./wire');
32
+
33
+ /** מינימל-Emitter בסגנון שלך */
34
+ function Emitter(){
35
+ var listeners = {};
36
+ return {
37
+ on: function(name, fn){ (listeners[name] = listeners[name] || []).push(fn); },
38
+ emit: function(name){
39
+ var args = Array.prototype.slice.call(arguments, 1);
40
+ var arr = listeners[name] || [];
41
+ for (var i=0;i<arr.length;i++){ try{ arr[i].apply(null, args); }catch(e){} }
42
+ }
43
+ };
44
+ }
45
+
46
+
47
+
48
+
49
+
50
+
51
+ function arrOrDefault(a, d){
52
+ return (a && a.length) ? a.slice(0) : d.slice(0);
53
+ }
54
+ function arrOrNull(a){
55
+ return (a && a.length) ? a.slice(0) : null;
56
+ }
57
+
58
+
59
+ function normalizeHello(hello) {
60
+ var out = {
61
+ // Basics
62
+ message: hello.message, // 'client_hello' | 'server_hello'
63
+ legacy_version: hello.legacy_version, // 0x0303
64
+ version: hello.version || hello.version_hint || null,
65
+ random: hello.random || null, // Uint8Array(32)
66
+ session_id: hello.session_id || null, // Uint8Array
67
+
68
+ // Negotiation fields
69
+ cipher_suites: hello.cipher_suites || null, // ClientHello array
70
+ cipher_suite: hello.cipher_suite || null, // ServerHello selected
71
+ legacy_compression: hello.legacy_compression || null,
72
+
73
+ // Commonly used extensions (flattened)
74
+ sni: null, // string
75
+ alpn: null, // string[]
76
+ key_shares: null, // Client: array of {group, key_exchange}; Server: {group, key_exchange}
77
+ supported_versions: null, // Client: number[]; Server: number
78
+ signature_algorithms: null, // number[]
79
+ supported_groups: null, // number[]
80
+
81
+ // TLS 1.2 / misc
82
+ renegotiation_info: null, // Uint8Array
83
+ status_request: null, // raw/decoded if available
84
+ max_fragment_length: null, // number or enum
85
+ signature_algorithms_cert: null, // number[]
86
+ certificate_authorities: null, // raw/decoded if available
87
+ sct: null, // SignedCertificateTimestamp list (raw/decoded)
88
+ heartbeat: null, // heartbeat mode
89
+ use_srtp: null, // SRTP profiles
90
+
91
+ // TLS 1.3 specific
92
+ cookie: null, // Uint8Array
93
+ early_data: null, // true/params if present
94
+ psk_key_exchange_modes: null, // number[]
95
+
96
+ // Raw list of extensions
97
+ extensions: hello.extensions || [],
98
+
99
+ // Bucket for anything unmapped
100
+ unknown: []
101
+ };
102
+
103
+ if (!hello.extensions) {
104
+ return out;
105
+ }
106
+
107
+ for (var i = 0; i < hello.extensions.length; i++) {
108
+ var e = hello.extensions[i];
109
+ var val = (e.value !== undefined && e.value !== null) ? e.value : null;
110
+
111
+ switch (e.name) {
112
+ case 'SERVER_NAME':
113
+ out.sni = val; // string
114
+ break;
115
+
116
+ case 'ALPN':
117
+ out.alpn = val; // string[]
118
+ break;
119
+
120
+ case 'KEY_SHARE':
121
+ out.key_shares = val; // client: array, server: object
122
+ break;
123
+
124
+ case 'SUPPORTED_VERSIONS':
125
+ out.supported_versions = val; // array or number
126
+ break;
127
+
128
+ case 'SIGNATURE_ALGORITHMS':
129
+ out.signature_algorithms = val; // number[]
130
+ break;
131
+
132
+ case 'SUPPORTED_GROUPS':
133
+ out.supported_groups = val; // number[]
134
+ break;
135
+
136
+ // ---- TLS 1.2 & misc ----
137
+ case 'RENEGOTIATION_INFO':
138
+ out.renegotiation_info = val; // Uint8Array
139
+ break;
140
+
141
+ case 'STATUS_REQUEST':
142
+ out.status_request = val; // currently raw unless a decoder is added
143
+ break;
144
+
145
+ case 'MAX_FRAGMENT_LENGTH':
146
+ out.max_fragment_length = val; // number/enum (decoder not implemented yet)
147
+ break;
148
+
149
+ case 'SIGNATURE_ALGORITHMS_CERT':
150
+ out.signature_algorithms_cert = val; // number[]
151
+ break;
152
+
153
+ case 'CERTIFICATE_AUTHORITIES':
154
+ out.certificate_authorities = val; // raw list unless decoder added
155
+ break;
156
+
157
+ case 'SCT':
158
+ out.sct = val; // raw/decoded SCT list
159
+ break;
160
+
161
+ case 'HEARTBEAT':
162
+ out.heartbeat = val; // heartbeat mode
163
+ break;
164
+
165
+ case 'USE_SRTP':
166
+ out.use_srtp = val; // SRTP params
167
+ break;
168
+
169
+ // ---- TLS 1.3 ----
170
+ case 'COOKIE':
171
+ out.cookie = val; // Uint8Array
172
+ break;
173
+
174
+ case 'EARLY_DATA':
175
+ out.early_data = (val === null) ? true : val; // presence indicates support
176
+ break;
177
+
178
+ case 'PSK_KEY_EXCHANGE_MODES':
179
+ out.psk_key_exchange_modes = val; // number[]
180
+ break;
181
+
182
+ default:
183
+ out.unknown.push(e);
184
+ }
185
+ }
186
+
187
+ // --- פוסט-פרוסס: השלמות ל-1.2 כשאין ext SUPPORTED_VERSIONS ---
188
+ if (out.supported_versions == null) {
189
+ if (out.message === 'client_hello' && typeof out.legacy_version === 'number') {
190
+ // ב-1.2 הקליינט לא שולח ext, נשתול מערך עם הגרסה ה"מורשת" (לרוב 0x0303)
191
+ out.supported_versions = [out.legacy_version|0];
192
+ } else if (out.message === 'server_hello' && typeof out.legacy_version === 'number') {
193
+ // בסרבר: הגרסה הנבחרת נמצאת בשדה הישן; שמור גם ב-version
194
+ if (out.version == null) out.version = out.legacy_version|0;
195
+ out.supported_versions = out.version; // שמור סכימה: בסרבר זה "number"
196
+ }
197
+ }
198
+
199
+ // גם אם אין KEY_SHARE ב-1.2, נרצה אינדיקציה ריקה במקום null (קוד downstream נקי יותר)
200
+ if (out.key_shares == null && out.message === 'client_hello') {
201
+ out.key_shares = []; // ב-1.2 ה-ECDHE יבוא ב-ServerKeyExchange, לא כאן
202
+ }
203
+
204
+ return out;
205
+ }
206
+
207
+
208
+
209
+ function normalizeOptions(opts){
210
+ opts = opts || {};
211
+ var out = {
212
+ minVersion: opts.minVersion || null,
213
+ maxVersion: opts.maxVersion || null,
214
+
215
+ cipherPreference: arrOrDefault(opts.cipherPreference, null),
216
+ groupPreference: arrOrDefault(opts.groupPreference, null),
217
+ sigAlgPreference: arrOrDefault(opts.sigAlgPreference, null),
218
+
219
+ ALPNProtocols: arrOrNull(opts.ALPNProtocols),
220
+
221
+ requestCert: !!opts.requestCert,
222
+ rejectUnauthorized: !!opts.rejectUnauthorized,
223
+
224
+ secureContext: opts.secureContext || null,
225
+ isServer: !!opts.isServer
226
+ };
227
+
228
+ // ודא min<=max
229
+ if (out.minVersion > out.maxVersion){
230
+ var t = out.minVersion; out.minVersion = out.maxVersion; out.maxVersion = t;
231
+ }
232
+
233
+ return out;
234
+ }
235
+
236
+ function TLSSession(options){
237
+ if (!(this instanceof TLSSession)) return new TLSSession(options);
238
+ options = options || {};
239
+
240
+ var ev = Emitter();
241
+
242
+ var context = {
243
+ state: 'new', //new | negotiating | ...
244
+ isServer: !!options.isServer,
245
+
246
+ SNICallback: options.SNICallback || null,
247
+
248
+ local_versions: [], // [0x0304, 0x0303, ...]
249
+ local_cipher_suites: [], //[0x1303, 0x1301, 0x1302]
250
+ local_alpns: [], // ['h3','h2','http/1.1', ...]
251
+ local_groups: [], //[0x001D, 0x0017, 0x0018]// x25519, secp256r1, secp384r1
252
+ local_signature_algorithms: [], //[0x0403, 0x0804, 0x0805] //ecdsa_secp256r1_sha256 (0x0403), rsa_pss_rsae_sha256 (0x0804), rsa_pss_rsae_sha384 (0x0805)
253
+ local_extensions: [], // [{ type, data }, ...]
254
+
255
+ local_key_share_public: null, // Uint8Array (pubkey שנשלח)
256
+ local_key_share_private: null, // Uint8Array (privkey זמני)
257
+
258
+ // REMOTE (מה שהצד המרוחק שלח/מציע)
259
+ remote_versions: [],
260
+ remote_cipher_suites: [],
261
+ remote_alpns: [],
262
+ remote_groups: [],
263
+ remote_signature_algorithms: [],
264
+ remote_extensions: [],
265
+ remote_key_shares: [],
266
+ remote_sni: null,
267
+ remote_session_id: null,
268
+ remote_random: null,
269
+
270
+
271
+ // SELECTED (מה שנקבע בפועל)
272
+ selected_version: null, // 0x0304 / 0x0303
273
+ selected_cipher_suite: null, // למשל 0x1301
274
+ selected_alpn: null, // 'h3'/'h2'/... או null
275
+ selected_group: null, // למשל 0x001D
276
+ selected_signature_algorithm: null, // למשל 0x0804
277
+ selected_extensions: [], // [type,...] או [{type,dataConfirmed}]
278
+ selected_sni: null, // string|null
279
+ selected_session_id: null, // TLS 1.2 בלבד
280
+
281
+ // שאר מצב/מפתחות/תעודות/תזמון
282
+ transcript: [], // Handshake inner messages
283
+
284
+ local_random: null,
285
+
286
+
287
+ //whats already sent?
288
+ hello_sent: false,
289
+ encrypted_exts_sent: false,
290
+ cert_sent: false,
291
+ cert_verify_sent: false,
292
+ finished_sent: false,
293
+
294
+ message_sent_seq: 0,
295
+
296
+ remote_finished: null,
297
+ expected_remote_finished: null,
298
+ remote_finished_ok: false,
299
+
300
+ local_key_share_private: null,
301
+ local_key_share_public: null,
302
+ ecdhe_shared_secret: null,
303
+
304
+ handshake_secret: null,
305
+
306
+ client_handshake_traffic_secret: null,
307
+ server_handshake_traffic_secret: null,
308
+
309
+ client_app_traffic_secret: null,
310
+ server_app_traffic_secret: null,
311
+
312
+ local_cert_chain: null,
313
+ remote_cert_chain: null,
314
+
315
+ selected_cert: null,
316
+
317
+ cert_private_key: null
318
+ };
319
+
320
+ function process_income_message(data){
321
+
322
+ var message = wire.parse_message(data);
323
+
324
+ if (message.type == wire.TLS_MESSAGE_TYPE.CLIENT_HELLO || message.type == wire.TLS_MESSAGE_TYPE.SERVER_HELLO) {
325
+ var hello = wire.parse_hello(message.type, message.body);
326
+
327
+ var info = normalizeHello(hello);
328
+ //console.log(info);
329
+ context.transcript.push(data);
330
+
331
+ set_context({
332
+ remote_random: info.random || null,
333
+ remote_sni: info.sni || null,
334
+ remote_session_id: info.session_id || null, // TLS 1.2 בעיקר
335
+ remote_cipher_suites: info.cipher_suites || [],
336
+ remote_alpns: info.alpn || [],
337
+ remote_key_shares: info.key_shares || [],
338
+ remote_versions: info.supported_versions || [],
339
+ remote_signature_algorithms: info.signature_algorithms || [],
340
+ remote_groups: info.supported_groups || [],
341
+ remote_extensions: info.extensions || [],
342
+ });
343
+
344
+ ev.emit('hello');
345
+
346
+ if(typeof context.SNICallback=='function'){
347
+ context.SNICallback(context.remote_sni, function (err, creds) {
348
+ if (!err && creds) {
349
+ set_context({
350
+ local_cert_chain: creds.certificateChain,
351
+ cert_private_key: creds.privateKey
352
+ });
353
+ } else {
354
+ //console.log('No TLS credentials for', current_params.sni);
355
+ }
356
+ });
357
+ }
358
+
359
+
360
+ } else if (message.type == wire.TLS_MESSAGE_TYPE.FINISHED) {
361
+
362
+ set_context({
363
+ remote_finished: message.body
364
+ });
365
+
366
+ }
367
+
368
+ }
369
+
370
+
371
+ function set_context(options){
372
+ var has_changed=false;
373
+
374
+ var fields=[
375
+ 'local_versions',
376
+ 'local_cipher_suites',
377
+ 'local_alpns',
378
+ 'local_groups',
379
+ 'local_signature_algorithms',
380
+ 'local_extensions',
381
+
382
+ 'remote_versions',
383
+ 'remote_cipher_suites',
384
+ 'remote_alpns',
385
+ 'remote_groups',
386
+ 'remote_signature_algorithms',
387
+ 'remote_extensions',
388
+ 'remote_key_shares',
389
+ 'remote_sni',
390
+ 'remote_session_id',
391
+ 'remote_random',
392
+
393
+ 'selected_version',
394
+ 'selected_cipher_suite',
395
+ 'selected_alpn',
396
+ 'selected_group',
397
+ 'selected_signature_algorithm',
398
+ 'selected_extensions',
399
+ 'selected_sni',
400
+ 'selected_session_id',
401
+
402
+
403
+ 'local_key_share_public',
404
+ 'local_key_share_private',
405
+ 'ecdhe_shared_secret',
406
+
407
+ 'server_handshake_traffic_secret',
408
+ 'client_handshake_traffic_secret',
409
+
410
+ 'server_app_traffic_secret',
411
+ 'client_app_traffic_secret',
412
+
413
+ 'local_cert_chain',
414
+ 'remote_cert_chain',
415
+
416
+ 'cert_private_key',
417
+
418
+ 'remote_finished_ok',
419
+ 'remote_finished',
420
+ 'expected_remote_finished'
421
+ ];
422
+
423
+ var prev={};
424
+
425
+
426
+ if (options && typeof options === 'object'){
427
+
428
+ if('local_versions' in options){
429
+ if(arraysEqual(options.local_versions,context.local_versions)==false){
430
+ prev['local_versions']=context['local_versions'];
431
+ context.local_versions=options.local_versions;
432
+ has_changed=true;
433
+ }
434
+ }
435
+
436
+ if('local_cipher_suites' in options){
437
+ if(arraysEqual(options.local_cipher_suites,context.local_cipher_suites)==false){
438
+ prev['local_cipher_suites']=context['local_cipher_suites'];
439
+ context.local_cipher_suites=options.local_cipher_suites;
440
+ has_changed=true;
441
+ }
442
+ }
443
+
444
+ if('local_alpns' in options){
445
+ if(arraysEqual(options.local_alpns,context.local_alpns)==false){
446
+ prev['local_alpns']=context['local_alpns'];
447
+ context.local_alpns=options.local_alpns;
448
+ has_changed=true;
449
+ }
450
+ }
451
+
452
+ if('local_groups' in options){
453
+ if(arraysEqual(options.local_groups,context.local_groups)==false){
454
+ prev['local_groups']=context['local_groups'];
455
+ context.local_groups=options.local_groups;
456
+ has_changed=true;
457
+ }
458
+ }
459
+
460
+ if('local_signature_algorithms' in options){
461
+ if(arraysEqual(options.local_signature_algorithms,context.local_signature_algorithms)==false){
462
+ prev['local_signature_algorithms']=context['local_signature_algorithms'];
463
+ context.local_signature_algorithms=options.local_signature_algorithms;
464
+ has_changed=true;
465
+ }
466
+ }
467
+
468
+ if('local_extensions' in options){
469
+ if(arraysEqual(options.local_extensions,context.local_extensions)==false){
470
+ prev['local_extensions']=context['local_extensions'];
471
+ context.local_extensions=options.local_extensions;
472
+ has_changed=true;
473
+ }
474
+ }
475
+
476
+ if('local_key_share_public' in options){
477
+ if((context.local_key_share_public==null && options.local_key_share_public!==null) || !arraybufferEqual(options.local_key_share_public.buffer,context.local_key_share_public.buffer)){
478
+ prev['local_key_share_public']=context['local_key_share_public'];
479
+ context.local_key_share_public=options.local_key_share_public;
480
+ has_changed=true;
481
+ }
482
+ }
483
+
484
+ if('local_key_share_private' in options){
485
+ if((context.local_key_share_private==null && options.local_key_share_private!==null) || !arraybufferEqual(options.local_key_share_private.buffer,context.local_key_share_private.buffer)){
486
+ prev['local_key_share_private']=context['local_key_share_private'];
487
+ context.local_key_share_private=options.local_key_share_private;
488
+ has_changed=true;
489
+ }
490
+ }
491
+
492
+ if('remote_versions' in options){
493
+ if(arraysEqual(options.remote_versions,context.remote_versions)==false){
494
+ prev['remote_versions']=context['remote_versions'];
495
+ context.remote_versions=options.remote_versions;
496
+ has_changed=true;
497
+ }
498
+ }
499
+
500
+ if('remote_cipher_suites' in options){
501
+ if(arraysEqual(options.remote_cipher_suites,context.remote_cipher_suites)==false){
502
+ prev['remote_cipher_suites']=context['remote_cipher_suites'];
503
+ context.remote_cipher_suites=options.remote_cipher_suites;
504
+ has_changed=true;
505
+ }
506
+ }
507
+
508
+ if('remote_alpns' in options){
509
+ if(arraysEqual(options.remote_alpns,context.remote_alpns)==false){
510
+ prev['remote_alpns']=context['remote_alpns'];
511
+ context.remote_alpns=options.remote_alpns;
512
+ has_changed=true;
513
+ }
514
+ }
515
+
516
+ if('remote_groups' in options){
517
+ if(arraysEqual(options.remote_groups,context.remote_groups)==false){
518
+ prev['remote_groups']=context['remote_groups'];
519
+ context.remote_groups=options.remote_groups;
520
+ has_changed=true;
521
+ }
522
+ }
523
+
524
+ if('remote_signature_algorithms' in options){
525
+ if(arraysEqual(options.remote_signature_algorithms,context.remote_signature_algorithms)==false){
526
+ prev['remote_signature_algorithms']=context['remote_signature_algorithms'];
527
+ context.remote_signature_algorithms=options.remote_signature_algorithms;
528
+ has_changed=true;
529
+ }
530
+ }
531
+
532
+ if('remote_extensions' in options){
533
+ if(arraysEqual(options.remote_extensions,context.remote_extensions)==false){
534
+ prev['remote_extensions']=context['remote_extensions'];
535
+ context.remote_extensions=options.remote_extensions;
536
+ has_changed=true;
537
+ }
538
+ }
539
+
540
+ if('remote_key_shares' in options){
541
+ if(arraysEqual(options.remote_key_shares,context.remote_key_shares)==false){
542
+ prev['remote_key_shares']=context['remote_key_shares'];
543
+ context.remote_key_shares=options.remote_key_shares;
544
+ has_changed=true;
545
+ }
546
+ }
547
+
548
+ if('remote_sni' in options){
549
+ if(options.remote_sni!==context.remote_sni){
550
+ prev['remote_sni']=context['remote_sni'];
551
+ context.remote_sni=options.remote_sni;
552
+ has_changed=true;
553
+ }
554
+ }
555
+
556
+ if('remote_session_id' in options){
557
+ if((context.remote_session_id==null && options.remote_session_id!==null) || !arraybufferEqual(options.remote_session_id.buffer,context.remote_session_id.buffer)){
558
+ prev['remote_session_id']=context['remote_session_id'];
559
+ context.remote_session_id=options.remote_session_id;
560
+ has_changed=true;
561
+ }
562
+ }
563
+
564
+ if('remote_random' in options){
565
+ if((context.remote_random==null && options.remote_random!==null) || !arraybufferEqual(options.remote_random.buffer,context.remote_random.buffer)){
566
+ prev['remote_random']=context['remote_random'];
567
+ context.remote_random=options.remote_random;
568
+ has_changed=true;
569
+ }
570
+ }
571
+
572
+ if('selected_version' in options){
573
+ if(options.selected_version!==context.selected_version){
574
+ prev['selected_version']=context['selected_version'];
575
+ context.selected_version=options.selected_version;
576
+ has_changed=true;
577
+ }
578
+ }
579
+
580
+ if('selected_cipher_suite' in options){
581
+ if(options.selected_cipher_suite!==context.selected_cipher_suite){
582
+ prev['selected_cipher_suite']=context['selected_cipher_suite'];
583
+ context.selected_cipher_suite=options.selected_cipher_suite;
584
+ has_changed=true;
585
+ }
586
+ }
587
+
588
+ if('selected_alpn' in options){
589
+ if(options.selected_alpn!==context.selected_alpn){
590
+ prev['selected_alpn']=context['selected_alpn'];
591
+ context.selected_alpn=options.selected_alpn;
592
+ has_changed=true;
593
+ }
594
+ }
595
+
596
+ if('selected_group' in options){
597
+ if(options.selected_group!==context.selected_group){
598
+ prev['selected_group']=context['selected_group'];
599
+ context.selected_group=options.selected_group;
600
+ has_changed=true;
601
+ }
602
+ }
603
+
604
+ if('selected_signature_algorithm' in options){
605
+ if(options.selected_signature_algorithm!==context.selected_signature_algorithm){
606
+ prev['selected_signature_algorithm']=context['selected_signature_algorithm'];
607
+ context.selected_signature_algorithm=options.selected_signature_algorithm;
608
+ has_changed=true;
609
+ }
610
+ }
611
+
612
+ if('selected_extensions' in options){
613
+ if(arraysEqual(options.selected_extensions,context.selected_extensions)==false){
614
+ prev['selected_extensions']=context['selected_extensions'];
615
+ context.selected_extensions=options.selected_extensions;
616
+ has_changed=true;
617
+ }
618
+ }
619
+
620
+ if('selected_sni' in options){
621
+ if(options.selected_sni!==context.selected_sni){
622
+ prev['selected_sni']=context['selected_sni'];
623
+ context.selected_sni=options.selected_sni;
624
+ has_changed=true;
625
+ }
626
+ }
627
+
628
+ if('selected_session_id' in options){
629
+ if((context.selected_session_id==null && options.selected_session_id!==null) || !arraybufferEqual(options.selected_session_id.buffer,context.selected_session_id.buffer)){
630
+ prev['selected_session_id']=context['selected_session_id'];
631
+ context.selected_session_id=options.selected_session_id;
632
+ has_changed=true;
633
+ }
634
+ }
635
+
636
+
637
+
638
+
639
+ if('ecdhe_shared_secret' in options){
640
+ if(context.ecdhe_shared_secret==null && options.ecdhe_shared_secret!==null){
641
+ prev['ecdhe_shared_secret']=context['ecdhe_shared_secret'];
642
+ context.ecdhe_shared_secret=options.ecdhe_shared_secret;
643
+ has_changed=true;
644
+ }
645
+ }
646
+
647
+ if('handshake_secret' in options){
648
+ if(context.handshake_secret==null && options.handshake_secret!==null){
649
+ prev['handshake_secret']=context['handshake_secret'];
650
+ context.handshake_secret=options.handshake_secret;
651
+ has_changed=true;
652
+ }
653
+ }
654
+
655
+
656
+ if('client_handshake_traffic_secret' in options){
657
+ if(context.client_handshake_traffic_secret==null && options.client_handshake_traffic_secret!==null){
658
+ prev['client_handshake_traffic_secret']=context['client_handshake_traffic_secret'];
659
+ context.client_handshake_traffic_secret=options.client_handshake_traffic_secret;
660
+ has_changed=true;
661
+ }
662
+ }
663
+
664
+ if('server_handshake_traffic_secret' in options){
665
+ if(context.server_handshake_traffic_secret==null && options.server_handshake_traffic_secret!==null){
666
+ prev['server_handshake_traffic_secret']=context['server_handshake_traffic_secret'];
667
+ context.server_handshake_traffic_secret=options.server_handshake_traffic_secret;
668
+ has_changed=true;
669
+ }
670
+ }
671
+
672
+ if('client_app_traffic_secret' in options){
673
+ if(context.client_app_traffic_secret==null && options.client_app_traffic_secret!==null){
674
+ prev['client_app_traffic_secret']=context['client_app_traffic_secret'];
675
+ context.client_app_traffic_secret=options.client_app_traffic_secret;
676
+ has_changed=true;
677
+ }
678
+ }
679
+
680
+ if('server_app_traffic_secret' in options){
681
+ if(context.server_app_traffic_secret==null && options.server_app_traffic_secret!==null){
682
+ prev['server_app_traffic_secret']=context['server_app_traffic_secret'];
683
+ context.server_app_traffic_secret=options.server_app_traffic_secret;
684
+ has_changed=true;
685
+ }
686
+ }
687
+
688
+
689
+
690
+ if('local_cert_chain' in options){
691
+ if(context.local_cert_chain==null && options.local_cert_chain!==null){
692
+ prev['local_cert_chain']=context['local_cert_chain'];
693
+ context.local_cert_chain=options.local_cert_chain;
694
+ has_changed=true;
695
+ }
696
+ }
697
+
698
+ if('cert_private_key' in options){
699
+ if(context.cert_private_key==null && options.cert_private_key!==null){
700
+ prev['cert_private_key']=context['cert_private_key'];
701
+ context.cert_private_key=options.cert_private_key;
702
+ has_changed=true;
703
+ }
704
+ }
705
+
706
+ if('expected_remote_finished' in options){
707
+ if(context.expected_remote_finished==null && options.expected_remote_finished!==null){
708
+ prev['expected_remote_finished']=context['expected_remote_finished'];
709
+ context.expected_remote_finished=options.expected_remote_finished;
710
+ has_changed=true;
711
+ }
712
+ }
713
+
714
+ if('remote_finished' in options){
715
+ if(context.remote_finished==null && options.remote_finished!==null){
716
+ prev['remote_finished']=context['remote_finished'];
717
+ context.remote_finished=options.remote_finished;
718
+ has_changed=true;
719
+ }
720
+ }
721
+
722
+ if('remote_finished_ok' in options){
723
+ if(context.remote_finished_ok!==options.remote_finished_ok){
724
+ prev['remote_finished_ok']=context['remote_finished_ok'];
725
+ context.remote_finished_ok=options.remote_finished_ok;
726
+ has_changed=true;
727
+ }
728
+ }
729
+
730
+
731
+
732
+
733
+ }
734
+
735
+
736
+ if(has_changed==true){
737
+
738
+ var params_to_set = {};
739
+
740
+ if (
741
+ !arraysEqual(context.local_versions, prev.local_versions) ||
742
+ !arraysEqual(context.remote_versions, prev.remote_versions) ||
743
+
744
+ !arraysEqual(context.local_cipher_suites, prev.local_cipher_suites) ||
745
+ !arraysEqual(context.remote_cipher_suites, prev.remote_cipher_suites) ||
746
+
747
+ !arraysEqual(context.local_alpns, prev.local_alpns) ||
748
+ !arraysEqual(context.remote_alpns, prev.remote_alpns) ||
749
+
750
+ !arraysEqual(context.local_groups, prev.local_groups) ||
751
+ !arraysEqual(context.remote_groups, prev.remote_groups) ||
752
+
753
+ !arraysEqual(context.local_signature_algorithms, prev.local_signature_algorithms) ||
754
+ !arraysEqual(context.remote_signature_algorithms, prev.remote_signature_algorithms) ||
755
+
756
+ // הרחבות כלליות
757
+ !arraysEqual(context.local_extensions, prev.local_extensions) ||
758
+ //!arraysEqual(context.local_ee_extensions, prev.local_ee_extensions) || // TLS 1.3 EE
759
+ //!arraysEqual(context.remote_extensions_all, prev.remote_extensions_all) ||
760
+ //!arraysEqual(context.remote_extensions_unknown, prev.remote_extensions_unknown) ||
761
+
762
+ // key_shares הם מערך של אובייקטים {group, pubkey} → deep compare
763
+ !arraysEqual(context.remote_key_shares, prev.remote_key_shares) ||
764
+
765
+ // session_id הוא Uint8Array → בדיקה ייעודית
766
+ !arraybufferEqual(context.remote_session_id.buffer, prev.remote_session_id.buffer) ||
767
+
768
+ // סניפים/מחרוזות פשוט
769
+ context.remote_sni !== prev.remote_sni ||
770
+ 1==1
771
+ ) {
772
+
773
+
774
+
775
+ // === גרסה ===
776
+ if (context.selected_version == null && context.local_versions.length > 0 && context.remote_versions.length > 0) {
777
+ for (var i = 0; i < context.local_versions.length; i++) {
778
+ var v = context.local_versions[i] | 0;
779
+ for (var j = 0; j < context.remote_versions.length; j++) {
780
+ if ((context.remote_versions[j] | 0) == v) {
781
+ params_to_set['selected_version'] = v;
782
+ break;
783
+ }
784
+ }
785
+ if ('selected_version' in params_to_set==true && params_to_set.selected_version !== null) break;
786
+ }
787
+
788
+ if('selected_version' in params_to_set==false || params_to_set.selected_version==null){
789
+ //console.log('no match version...');
790
+ }
791
+ }
792
+
793
+ // === Cipher Suite ===
794
+ if (context.selected_cipher_suite == null && context.local_cipher_suites.length > 0 && context.remote_cipher_suites.length > 0) {
795
+
796
+ for (var i2 = 0; i2 < context.local_cipher_suites.length; i2++) {
797
+ var cs = context.local_cipher_suites[i2] | 0;
798
+ for (var j2 = 0; j2 < context.remote_cipher_suites.length; j2++) {
799
+
800
+ if ((context.remote_cipher_suites[j2] | 0) == cs) {
801
+ params_to_set['selected_cipher_suite'] = cs;
802
+ break;
803
+ }
804
+ }
805
+ if ('selected_cipher_suite' in params_to_set==true && params_to_set.selected_cipher_suite !== null) break;
806
+ }
807
+
808
+ if('selected_cipher_suite' in params_to_set==false || params_to_set.selected_cipher_suite==null){
809
+ //console.log('no match cipher_suites...');
810
+ }
811
+ }
812
+
813
+ // === ALPN ===
814
+ if (context.selected_alpn == null && context.local_alpns && context.remote_alpns) {
815
+ // עבור על הרשימה המקומית לפי סדר עדיפויות
816
+ for (var a = 0; a < context.local_alpns.length; a++) {
817
+ var cand = context.local_alpns[a];
818
+ for (var b = 0; b < context.remote_alpns.length; b++) {
819
+ if (context.remote_alpns[b] === cand) {
820
+ params_to_set['selected_alpn'] = cand;
821
+ break;
822
+ }
823
+ }
824
+ if ('selected_alpn' in params_to_set==true && params_to_set.selected_alpn !== null) break;
825
+ }
826
+ }
827
+
828
+ // === Group (ECDHE) ===
829
+ if (context.selected_group == null){
830
+ if (context.selected_version == wire.TLS_VERSION.TLS1_3) {
831
+ if(context.local_groups.length > 0 && context.remote_key_shares.length > 0) {
832
+ for (var g = 0; g < context.local_groups.length; g++) {
833
+ var grp = context.local_groups[g] | 0;
834
+ for (var k = 0; k < context.remote_key_shares.length; k++) {
835
+ var ent = context.remote_key_shares[k];
836
+ if ((ent.group | 0) === grp) {
837
+ params_to_set['selected_group'] = grp;
838
+ params_to_set['remote_key_share_selected_public'] = ent.pubkey || ent.key_exchange || null;
839
+ break;
840
+ }
841
+ }
842
+ if ('selected_group' in params_to_set==true && params_to_set.selected_group !== null) break;
843
+ }
844
+ if (!params_to_set.selected_group && context.selected_version === wire.TLS_VERSION.TLS1_3) {
845
+ params_to_set['need_hrr'] = true; // HelloRetryRequest אם לא נמצא group
846
+ }
847
+
848
+ if('selected_group' in params_to_set==false || params_to_set.selected_group==null){
849
+ //console.log('no match selected_group...');
850
+ }
851
+ }
852
+ }else if(context.selected_version == wire.TLS_VERSION.TLS1_2){
853
+ //console.log('...remote_groups...');
854
+
855
+ // 1.2 – לבחור עקום מתוך supported_groups של הלקוח (אין key_share)
856
+ if (context.local_groups.length > 0 && context.remote_groups.length > 0) {
857
+ for (let grp of context.local_groups) {
858
+ if (context.remote_groups.some(g => (g|0) === (grp|0))) {
859
+ params_to_set.selected_group = grp|0;
860
+ break;
861
+ }
862
+ }
863
+
864
+ if('selected_group' in params_to_set==false || params_to_set.selected_group==null){
865
+ //console.log('no match selected_group...');
866
+ }
867
+ }
868
+
869
+ }
870
+
871
+ }
872
+
873
+ // === Signature Algorithm ===
874
+ if (context.selected_signature_algorithm == null && context.local_signature_algorithms.length > 0 && context.remote_signature_algorithms.length > 0) {
875
+ for (var s = 0; s < context.local_signature_algorithms.length; s++) {
876
+ var sa = context.local_signature_algorithms[s] | 0;
877
+ for (var t = 0; t < context.remote_signature_algorithms.length; t++) {
878
+ if ((context.remote_signature_algorithms[t] | 0) === sa) {
879
+ params_to_set['selected_signature_algorithm'] = sa;
880
+ break;
881
+ }
882
+ }
883
+ if ('selected_signature_algorithm' in params_to_set==true && params_to_set.selected_signature_algorithm != null) break;
884
+ }
885
+
886
+ if('selected_signature_algorithm' in params_to_set==false || params_to_set.selected_signature_algorithm==null){
887
+ //console.log('no match selected_signature_algorithm...');
888
+ }
889
+ }
890
+
891
+ // === SNI ===
892
+ if (context.selected_sni == null) {
893
+ params_to_set['selected_sni'] = context.remote_sni || null;
894
+ }
895
+
896
+ // === Session ID (TLS 1.2 בלבד) ===
897
+ if (context.selected_session_id == null) {
898
+ params_to_set['selected_session_id'] = context.remote_session_id || new Uint8Array(0);
899
+ }
900
+
901
+ // === Extensions ===
902
+ if (context.selected_extensions == null && 1==2) {
903
+ var sel = [];
904
+ var allowed = {};
905
+ if (context.local_extensions) {
906
+ for (var lx = 0; lx < context.local_extensions.length; lx++) {
907
+ var lt = context.local_extensions[lx] && context.local_extensions[lx].type;
908
+ if (typeof lt === 'number') allowed[lt | 0] = true;
909
+ }
910
+ }
911
+ if (context.local_ee_extensions) {
912
+ for (var ex = 0; ex < context.local_ee_extensions.length; ex++) {
913
+ var et = context.local_ee_extensions[ex] && context.local_ee_extensions[ex].type;
914
+ if (typeof et === 'number') allowed[et | 0] = true;
915
+ }
916
+ }
917
+ if (context.remote_extensions_all) {
918
+ for (var rx = 0; rx < context.remote_extensions_all.length; rx++) {
919
+ var rt = context.remote_extensions_all[rx] && context.remote_extensions_all[rx].type;
920
+ if (typeof rt === 'number' && allowed[rt | 0]) {
921
+ sel.push(rt | 0);
922
+ }
923
+ }
924
+ }
925
+ if (params_to_set.selected_version === wire.TLS_VERSION.TLS1_3) {
926
+ if (sel.indexOf(0x002b) === -1) sel.push(0x002b); // supported_versions
927
+ if (sel.indexOf(0x0033) === -1) sel.push(0x0033); // key_share
928
+ }
929
+ params_to_set['selected_extensions'] = sel;
930
+ }
931
+
932
+
933
+ //console.log(params_to_set);
934
+
935
+ }
936
+
937
+ //יצירת מפתח תלוי ב GROUP
938
+ if(context.selected_group !== null && context.local_key_share_private === null && context.local_key_share_public === null) {
939
+
940
+ if (context.selected_version === wire.TLS_VERSION.TLS1_3) {
941
+ var client_public_key = null;
942
+ for (var i=0; i<context.remote_key_shares.length; i++){
943
+ if ((context.remote_key_shares[i].group|0) === (context.selected_group|0)){
944
+ client_public_key = context.remote_key_shares[i].pubkey || context.remote_key_shares[i].key_exchange || null;
945
+ break;
946
+ }
947
+ }
948
+
949
+ if(client_public_key!==null){
950
+ // כאן ליצור את זוג המפתחות (priv/pub) בהתאם לקבוצה
951
+
952
+ if (context.selected_group === 0x001d) { // X25519
953
+
954
+ // דרישות פורמט: client_public_key צריך להיות באורך 32 בייטים
955
+ // (נמנעים כאן מטיפול שגיאות כרגע)
956
+ var local_key_share_private = new Uint8Array(crypto.randomBytes(32));
957
+ var local_key_share_public = x25519.getPublicKey(local_key_share_private);
958
+ var ecdhe_shared_secret = x25519.getSharedSecret(local_key_share_private, client_public_key);
959
+ // אפשר לבצע strip של ה־first byte אם הספרייה מחזירה 32/33 — תלוי במימוש.
960
+
961
+ params_to_set['local_key_share_private']=local_key_share_private;
962
+ params_to_set['local_key_share_public']=local_key_share_public;
963
+ params_to_set['ecdhe_shared_secret']=ecdhe_shared_secret;
964
+
965
+
966
+
967
+ } else if (context.selected_group === 0x0017) { // secp256r1 (P-256)
968
+ //console.log('P-256');
969
+
970
+ var local_key_share_private = p256.utils.randomPrivateKey();
971
+ var local_key_share_public = p256.getPublicKey(priv, false); // uncompressed 65B
972
+
973
+ var clientPoint = p256.ProjectivePoint.fromHex(client_public_key);
974
+ // נקודת השיתוף = priv * clientPoint
975
+ var sharedPoint = clientPoint.multiply(BigInt('0x' + Buffer.from(priv).toString('hex')));
976
+ // שליפת הקואורדינטה X כ-32 בתים big-endian:
977
+ var affine = sharedPoint.toAffine(); // { x: bigint, y: bigint }
978
+ var xHex = affine.x.toString(16).padStart(64, '0'); // 32B hex
979
+ var ecdhe_shared_secret = Uint8Array.from(Buffer.from(xHex, 'hex')); // ← הסוד ל-TLS הוא X בלבד
980
+
981
+ params_to_set['local_key_share_private']=local_key_share_private;
982
+ params_to_set['local_key_share_public']=local_key_share_public;
983
+ params_to_set['ecdhe_shared_secret']=ecdhe_shared_secret;
984
+ }
985
+
986
+ }
987
+ }else if(context.selected_version === wire.TLS_VERSION.TLS1_2){
988
+
989
+ //console.log('@@@ 2');
990
+ // רק ליצור (priv/pub) עבור ServerKeyExchange
991
+ if (context.selected_group === 0x001d) { // X25519
992
+ const priv = new Uint8Array(crypto.randomBytes(32));
993
+ const pub = x25519.getPublicKey(priv);
994
+ params_to_set.local_key_share_private = priv;
995
+ params_to_set.local_key_share_public = pub;
996
+ // אל תחשב shared כאן; תחכה ל-ClientKeyExchange
997
+ } else if (context.selected_group === 0x0017) { // P-256
998
+ const priv = p256.utils.randomPrivateKey();
999
+ const pub = p256.getPublicKey(priv, false); // 65B uncompressed
1000
+ params_to_set.local_key_share_private = priv;
1001
+ params_to_set.local_key_share_public = pub;
1002
+ }
1003
+ }
1004
+
1005
+ }
1006
+
1007
+
1008
+
1009
+
1010
+
1011
+
1012
+ if (context.selected_version !== prev.selected_version || context.selected_cipher_suite !== prev.selected_cipher_suite || context.selected_session_id !== prev.selected_session_id || context.selected_group !== prev.selected_group || context.local_key_share_public !== prev.local_key_share_public){
1013
+ // build_server_hello... 1.3...
1014
+
1015
+ var can_send_hello=false;
1016
+ if(context.hello_sent==false){
1017
+ if(context.selected_version!==null && context.selected_cipher_suite!==null && context.selected_session_id!==null){
1018
+ if(context.selected_version === wire.TLS_VERSION.TLS1_3){
1019
+ if(context.local_key_share_public!==null && context.selected_group !== null){
1020
+ can_send_hello=true;
1021
+ }
1022
+ }else if(context.selected_version === wire.TLS_VERSION.TLS1_2){
1023
+ can_send_hello=true;
1024
+ }
1025
+ }
1026
+ }
1027
+
1028
+ if(can_send_hello==true){
1029
+ if(context.local_random==null){
1030
+ context.local_random=new Uint8Array(crypto.randomBytes(32));
1031
+ }
1032
+
1033
+ var build_message_params=null;
1034
+
1035
+ if(context.selected_version==wire.TLS_VERSION.TLS1_3){
1036
+
1037
+ build_message_params={
1038
+ type: 'server_hello',
1039
+ version: context.selected_version,
1040
+ random: context.local_random,
1041
+ session_id: context.remote_session_id,
1042
+ cipher_suite: context.selected_cipher_suite, // TLS_AES_128_GCM_SHA256
1043
+ extensions: [
1044
+ {
1045
+ type: 'SUPPORTED_VERSIONS',
1046
+ value: wire.TLS_VERSION.TLS1_3
1047
+ },
1048
+ {
1049
+ type: 'KEY_SHARE',
1050
+ value: {
1051
+ group: context.selected_group,
1052
+ key_exchange: context.local_key_share_public
1053
+ }
1054
+ }
1055
+ ]
1056
+ };
1057
+
1058
+
1059
+ }else if(context.selected_version==wire.TLS_VERSION.TLS1_2){
1060
+
1061
+ // ⚠️ אין SUPPORTED_VERSIONS/KEY_SHARE בתוך ServerHello של TLS 1.2.
1062
+ // מומלץ לכלול renegotiation_info (ריק בהנדשייק ראשון) ו-extended_master_secret (type=23).
1063
+ // ALPN (type=16) – אופציונלי: אם נבחר למשל 'http/1.1' או 'h2'.
1064
+
1065
+ var ext_list = [
1066
+ // RFC 5746 – initial handshake: value ריק (vec<1> באורך 0)
1067
+ { type: 'RENEGOTIATION_INFO', value: new Uint8Array(0) },
1068
+
1069
+ // RFC 7627 – extended_master_secret (type 23) – ערך ריק.
1070
+ // מאחר ואין encoder רשום אצלנו ל-23, נשתמש ישירות ב-data ריק:
1071
+ { type: 23, data: new Uint8Array(0) }
1072
+ ];
1073
+
1074
+ if (context.alpn_selected) {
1075
+ // RFC 7301 – ב-ServerHello מוחזר פרוטוקול אחד
1076
+ ext_list.push({ type: 'ALPN', value: [ String(context.alpn_selected) ] });
1077
+ }
1078
+
1079
+ build_message_params = {
1080
+ type: 'server_hello',
1081
+ version: context.selected_version,
1082
+ random: context.local_random,
1083
+ session_id: context.remote_session_id || new Uint8Array(0), // מקובל להדהד את ה-session_id של הלקוח
1084
+ cipher_suite: context.selected_cipher_suite, // למשל 0xC02F (ECDHE_RSA_WITH_AES_128_GCM_SHA256)
1085
+ // compression_method תמיד 0 ב-1.2 אצלנו; ה-builder כבר כותב 0.
1086
+ extensions: ext_list
1087
+ };
1088
+
1089
+ }
1090
+
1091
+ if(build_message_params!==null){
1092
+
1093
+ //console.log('sent server hello...')
1094
+ var message_data = wire.build_message(build_message_params);
1095
+
1096
+ context.transcript.push(message_data);
1097
+
1098
+ context.hello_sent=true;
1099
+
1100
+ ev.emit('message',0,context.message_sent_seq,'hello',message_data);
1101
+
1102
+ context.message_sent_seq++;
1103
+ }
1104
+ }
1105
+
1106
+ }
1107
+
1108
+
1109
+
1110
+ if (context.selected_version === wire.TLS_VERSION.TLS1_3){
1111
+ if(context.selected_cipher_suite !== null && (context.ecdhe_shared_secret !== null)){// || context.selected_psk !== null
1112
+
1113
+ var d = derive_handshake_traffic_secrets(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash, context.ecdhe_shared_secret, concatUint8Arrays(context.transcript));
1114
+
1115
+ params_to_set['handshake_secret']=d.handshake_secret;
1116
+
1117
+ params_to_set['client_handshake_traffic_secret']=d.client_handshake_traffic_secret;
1118
+ params_to_set['server_handshake_traffic_secret']=d.server_handshake_traffic_secret;
1119
+
1120
+
1121
+ }
1122
+ }
1123
+
1124
+
1125
+ if (context.selected_version === wire.TLS_VERSION.TLS1_3){
1126
+ if(context.encrypted_exts_sent==false && context.hello_sent==true && context.server_handshake_traffic_secret!==null){
1127
+
1128
+ var extensions=[];
1129
+ if(context.selected_alpn!==null){
1130
+ extensions.push({ type: 'ALPN', value: [context.selected_alpn] });
1131
+ }
1132
+
1133
+ //console.log('extensions:');
1134
+ //console.log(extensions);
1135
+
1136
+ for(var i in context.local_extensions){
1137
+ extensions.push(context.local_extensions[i]);
1138
+ }
1139
+
1140
+ var message_data = wire.build_message({
1141
+ type: 'encrypted_extensions',
1142
+ extensions: extensions
1143
+ });
1144
+
1145
+ //console.log('message_data:');
1146
+ //console.log(message_data);
1147
+
1148
+ context.transcript.push(message_data);
1149
+
1150
+ context.encrypted_exts_sent=true;
1151
+
1152
+ ev.emit('message',1,context.message_sent_seq,'encrypted_extensions',message_data);
1153
+
1154
+ context.message_sent_seq++;
1155
+
1156
+ }
1157
+ }
1158
+
1159
+
1160
+ if(context.cert_sent==false && context.local_cert_chain!==null){
1161
+ if((context.selected_version === wire.TLS_VERSION.TLS1_3 && context.encrypted_exts_sent==true && context.server_handshake_traffic_secret!==null) || (context.selected_version === wire.TLS_VERSION.TLS1_2 && context.hello_sent==true)){
1162
+
1163
+ var message_data = wire.build_message({
1164
+ type: 'certificate',
1165
+ version: context.selected_version,
1166
+ entries: context.local_cert_chain
1167
+ });
1168
+ context.transcript.push(message_data);
1169
+
1170
+ context.cert_sent=true;
1171
+
1172
+ if (context.selected_version === wire.TLS_VERSION.TLS1_3){
1173
+ ev.emit('message',1,context.message_sent_seq,'certificate',message_data);
1174
+ }else{
1175
+ ev.emit('message',0,context.message_sent_seq,'certificate',message_data);
1176
+ }
1177
+
1178
+ context.message_sent_seq++;
1179
+
1180
+
1181
+ }
1182
+ }
1183
+
1184
+
1185
+ if (context.selected_version === wire.TLS_VERSION.TLS1_3){
1186
+ if(context.cert_sent==true && context.cert_verify_sent==false && context.local_cert_chain!==null && context.server_handshake_traffic_secret!==null){
1187
+
1188
+ var tbs_data = build_cert_verify_tbs(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash,true,concatUint8Arrays(context.transcript));
1189
+
1190
+ var cert_private_key_obj = crypto.createPrivateKey({
1191
+ key: Buffer.from(context.cert_private_key),
1192
+ format: 'der',
1193
+ type: 'pkcs8',
1194
+ });
1195
+
1196
+ var SIG = {
1197
+ ECDSA_P256_SHA256: 0x0403,
1198
+ ECDSA_P384_SHA384: 0x0503,
1199
+ ECDSA_P521_SHA512: 0x0603,
1200
+ RSA_PSS_SHA256: 0x0804,
1201
+ RSA_PSS_SHA384: 0x0805,
1202
+ RSA_PSS_SHA512: 0x0806,
1203
+ ED25519: 0x0807,
1204
+ ED448: 0x0808
1205
+ };
1206
+
1207
+ var candidates=[];
1208
+ if (cert_private_key_obj.asymmetricKeyType === 'ed25519') candidates.push(SIG.ED25519);
1209
+ if (cert_private_key_obj.asymmetricKeyType === 'ed448') candidates.push(SIG.ED448);
1210
+ if (cert_private_key_obj.asymmetricKeyType === 'rsa') candidates.push(SIG.RSA_PSS_SHA256, SIG.RSA_PSS_SHA384, SIG.RSA_PSS_SHA512); // TLS 1.3 → רק PSS
1211
+
1212
+ if (cert_private_key_obj.asymmetricKeyType === 'ec') {
1213
+ var c = (cert_private_key_obj.asymmetricKeyDetails && cert_private_key_obj.asymmetricKeyDetails && cert_private_key_obj.asymmetricKeyDetails.namedCurve) || '';
1214
+ if (c === 'prime256v1') candidates.push(SIG.ECDSA_P256_SHA256);
1215
+ if (c === 'secp384r1') candidates.push(SIG.ECDSA_P384_SHA384);
1216
+ if (c === 'secp521r1') candidates.push(SIG.ECDSA_P521_SHA512);
1217
+ }
1218
+
1219
+ //console.log(candidates);
1220
+
1221
+ var preference_order = [
1222
+ SIG.ED25519,
1223
+ SIG.ED448,
1224
+ SIG.ECDSA_P256_SHA256,
1225
+ SIG.ECDSA_P384_SHA384,
1226
+ SIG.ECDSA_P521_SHA512,
1227
+ SIG.RSA_PSS_SHA256,
1228
+ SIG.RSA_PSS_SHA384,
1229
+ SIG.RSA_PSS_SHA512
1230
+ ];
1231
+
1232
+ var selected_scheme = null;
1233
+ for (var s of preference_order) {
1234
+ if (context.remote_signature_algorithms.includes(s)==true && candidates.includes(s)==true) {
1235
+ selected_scheme = s;
1236
+ break;
1237
+ }
1238
+ }
1239
+
1240
+ var sig_data=null;
1241
+
1242
+ switch (selected_scheme) {
1243
+ case SIG.ED25519:
1244
+ sig_data = new Uint8Array(crypto.sign(null, tbs_data, cert_private_key_obj));
1245
+ break;
1246
+
1247
+ case SIG.ECDSA_P256_SHA256:
1248
+ sig_data = new Uint8Array(crypto.sign('sha256', tbs_data, cert_private_key_obj));
1249
+ break;
1250
+
1251
+ case SIG.ECDSA_P384_SHA384:
1252
+ sig_data = new Uint8Array(crypto.sign('sha384', tbs_data, cert_private_key_obj));
1253
+ break;
1254
+
1255
+ case SIG.ECDSA_P521_SHA512:
1256
+ sig_data = new Uint8Array(crypto.sign('sha512', tbs_data, cert_private_key_obj));
1257
+ break;
1258
+
1259
+ case SIG.RSA_PSS_SHA256:
1260
+ sig_data = new Uint8Array(crypto.sign('sha256', tbs_data, {
1261
+ key: cert_private_key_obj,
1262
+ padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
1263
+ saltLength: 32
1264
+ }));
1265
+ break;
1266
+
1267
+ case SIG.RSA_PSS_SHA384:
1268
+ sig_data = new Uint8Array(crypto.sign('sha384', tbs_data, {
1269
+ key: cert_private_key_obj,
1270
+ padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
1271
+ saltLength: 48
1272
+ }));
1273
+ break;
1274
+
1275
+ case SIG.RSA_PSS_SHA512:
1276
+ sig_data = new Uint8Array(crypto.sign('sha512', tbs_data, {
1277
+ key: cert_private_key_obj,
1278
+ padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
1279
+ saltLength: 64
1280
+ }));
1281
+ break;
1282
+ }
1283
+
1284
+
1285
+ //console.log('sig_data:');
1286
+ //console.log(sig_data);
1287
+
1288
+ if(sig_data){
1289
+
1290
+ var message_data = wire.build_message({
1291
+ type: 'certificate_verify',
1292
+ scheme: selected_scheme,
1293
+ signature: sig_data
1294
+ });
1295
+
1296
+
1297
+
1298
+ //console.log(message_data);
1299
+ //console.log('certificate_verify sent!');
1300
+ context.transcript.push(message_data);
1301
+
1302
+ context.cert_verify_sent=true;
1303
+
1304
+ ev.emit('message',1,context.message_sent_seq,'certificate_verify',message_data);
1305
+
1306
+ context.message_sent_seq++;
1307
+ }else{
1308
+
1309
+ //..
1310
+ }
1311
+
1312
+
1313
+
1314
+
1315
+ }
1316
+ }
1317
+
1318
+ if (context.selected_version === wire.TLS_VERSION.TLS1_3){
1319
+ if(context.cert_verify_sent==true && context.finished_sent==false && context.local_cert_chain!==null && context.server_handshake_traffic_secret!==null){
1320
+
1321
+ var finished_data=get_handshake_finished(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash,context.server_handshake_traffic_secret,concatUint8Arrays(context.transcript));
1322
+
1323
+ var message_data = wire.build_message({
1324
+ type: 'finished',
1325
+ data: finished_data
1326
+ });
1327
+
1328
+ context.transcript.push(message_data);
1329
+
1330
+ context.finished_sent=true;
1331
+
1332
+ ev.emit('message',1,context.message_sent_seq,'finished',message_data);
1333
+
1334
+ context.message_sent_seq++;
1335
+
1336
+
1337
+ }
1338
+ }
1339
+
1340
+ if (context.selected_version === wire.TLS_VERSION.TLS1_3){
1341
+ if(context.finished_sent==true && context.handshake_secret!==null && context.server_app_traffic_secret==null){
1342
+
1343
+ var d2 = derive_app_traffic_secrets(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash, context.handshake_secret, concatUint8Arrays(context.transcript));
1344
+
1345
+ params_to_set['handshake_secret']=null;
1346
+
1347
+ params_to_set['client_app_traffic_secret']=d2.client_app_traffic_secret;
1348
+ params_to_set['server_app_traffic_secret']=d2.server_app_traffic_secret;
1349
+
1350
+ }
1351
+ }
1352
+
1353
+ //בניית פינישד צפוי
1354
+ if (context.selected_version === wire.TLS_VERSION.TLS1_3){
1355
+ if(context.finished_sent==true && context.expected_remote_finished==null && context.client_handshake_traffic_secret!==null){
1356
+
1357
+ params_to_set['expected_remote_finished']=get_handshake_finished(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash,context.client_handshake_traffic_secret,concatUint8Arrays(context.transcript));
1358
+
1359
+ }
1360
+ }
1361
+
1362
+ if (context.selected_version === wire.TLS_VERSION.TLS1_3){
1363
+ if(context.remote_finished_ok==false && context.remote_finished!==null && context.expected_remote_finished!==null){
1364
+
1365
+ if(arraybufferEqual(context.remote_finished.buffer,context.expected_remote_finished.buffer)==true){
1366
+
1367
+ context.transcript.push(context.remote_finished);
1368
+
1369
+ context.remote_finished_ok=true;
1370
+
1371
+ context.remote_finished=null;
1372
+ context.expected_remote_finished=null;
1373
+
1374
+ //console.log('finished ok!!!...');
1375
+
1376
+
1377
+ }else{
1378
+ context.remote_finished=null;
1379
+
1380
+ //console.log('finished fail...');
1381
+ }
1382
+
1383
+ }
1384
+ }
1385
+
1386
+ if (context.selected_version === wire.TLS_VERSION.TLS1_3){
1387
+ if(context.remote_finished_ok==true && context.server_app_traffic_secret!==null){
1388
+
1389
+ ev.emit('secureConnect');
1390
+
1391
+ }
1392
+ }
1393
+
1394
+
1395
+
1396
+ set_context(params_to_set);
1397
+ }
1398
+ }
1399
+
1400
+
1401
+ function close(){
1402
+
1403
+ }
1404
+
1405
+ var api = {
1406
+ context: context,
1407
+
1408
+ on: function(name, fn){ ev.on(name, fn); },
1409
+
1410
+ message: process_income_message,
1411
+
1412
+ set_context: set_context,
1413
+
1414
+
1415
+ close: close,
1416
+
1417
+ //getProtocol: getProtocol,
1418
+
1419
+ getCipher: function(){
1420
+ // TODO: { name, standardName, keyLen, aead } אחרי נגושיאציה
1421
+ return null;
1422
+ },
1423
+
1424
+ getPeerCertificate: function(detailed){
1425
+ void detailed;
1426
+ // TODO: להחזיר ch cert או null
1427
+ return context.peerCert;
1428
+ },
1429
+
1430
+ exportKeyingMaterial: function(length, label, context){
1431
+ void length; void label; void context;
1432
+ // TODO: HKDF-Expand-Label על traffic secret מתאים (RFC8446)
1433
+ return new Uint8Array(0);
1434
+ }
1435
+ };
1436
+
1437
+ for (var k in api) if (Object.prototype.hasOwnProperty.call(api,k)) this[k] = api[k];
1438
+ return this;
1439
+ }
1440
+
1441
+ module.exports = TLSSession;