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/crypto.js ADDED
@@ -0,0 +1,383 @@
1
+ var { hmac: nobleHmac } = require('@noble/hashes/hmac');
2
+ var { hkdf, extract: hkdf_extract_noble, expand: hkdf_expand_noble } = require('@noble/hashes/hkdf');
3
+ var { sha256, sha384 } = require('@noble/hashes/sha2');
4
+ var { p256 } = require('@noble/curves/nist'); // אם תרצה להשתמש בהמשך
5
+ var { x25519 } = require('@noble/curves/ed25519'); // אם תרצה להשתמש בהמשך
6
+
7
+ var {
8
+ concatUint8Arrays,
9
+ } = require('./utils');
10
+
11
+
12
+
13
+ var TLS_CIPHER_SUITES = {
14
+ // ----------------------
15
+ // TLS 1.3 (RFC 8446)
16
+ // ----------------------
17
+ 0x1301: { // TLS_AES_128_GCM_SHA256
18
+ tls: 13,
19
+ kex: 'TLS13',
20
+ sig: 'TLS13',
21
+ cipher: 'AES_128_GCM',
22
+ aead: true,
23
+ keylen: 16,
24
+ ivlen: 12,
25
+ hash: 'sha256'
26
+ },
27
+ 0x1302: { // TLS_AES_256_GCM_SHA384
28
+ tls: 13,
29
+ kex: 'TLS13',
30
+ sig: 'TLS13',
31
+ cipher: 'AES_256_GCM',
32
+ aead: true,
33
+ keylen: 32,
34
+ ivlen: 12,
35
+ hash: 'sha384'
36
+ },
37
+ 0x1303: { // TLS_CHACHA20_POLY1305_SHA256
38
+ tls: 13,
39
+ kex: 'TLS13',
40
+ sig: 'TLS13',
41
+ cipher: 'CHACHA20_POLY1305',
42
+ aead: true,
43
+ keylen: 32,
44
+ ivlen: 12,
45
+ hash: 'sha256'
46
+ },
47
+
48
+ // ----------------------
49
+ // TLS 1.2 AEAD (GCM / CHACHA20)
50
+ // ----------------------
51
+ 0xC02F: { // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
52
+ tls: 12,
53
+ kex: 'ECDHE_RSA',
54
+ sig: 'RSA',
55
+ cipher: 'AES_128_GCM',
56
+ aead: true,
57
+ keylen: 16,
58
+ fixed_ivlen: 4,
59
+ record_ivlen: 8,
60
+ ivlen: 12,
61
+ hash: 'sha256'
62
+ },
63
+ 0xC030: { // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
64
+ tls: 12,
65
+ kex: 'ECDHE_RSA',
66
+ sig: 'RSA',
67
+ cipher: 'AES_256_GCM',
68
+ aead: true,
69
+ keylen: 32,
70
+ fixed_ivlen: 4,
71
+ record_ivlen: 8,
72
+ ivlen: 12,
73
+ hash: 'sha384'
74
+ },
75
+ 0xC02B: { // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
76
+ tls: 12,
77
+ kex: 'ECDHE_ECDSA',
78
+ sig: 'ECDSA',
79
+ cipher: 'AES_128_GCM',
80
+ aead: true,
81
+ keylen: 16,
82
+ fixed_ivlen: 4,
83
+ record_ivlen: 8,
84
+ ivlen: 12,
85
+ hash: 'sha256'
86
+ },
87
+ 0xC02C: { // TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
88
+ tls: 12,
89
+ kex: 'ECDHE_ECDSA',
90
+ sig: 'ECDSA',
91
+ cipher: 'AES_256_GCM',
92
+ aead: true,
93
+ keylen: 32,
94
+ fixed_ivlen: 4,
95
+ record_ivlen: 8,
96
+ ivlen: 12,
97
+ hash: 'sha384'
98
+ },
99
+ 0xCCA8: { // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
100
+ tls: 12,
101
+ kex: 'ECDHE_RSA',
102
+ sig: 'RSA',
103
+ cipher: 'CHACHA20_POLY1305',
104
+ aead: true,
105
+ keylen: 32,
106
+ fixed_ivlen: 4,
107
+ record_ivlen: 8,
108
+ ivlen: 12,
109
+ hash: 'sha256'
110
+ },
111
+ 0xCCA9: { // TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
112
+ tls: 12,
113
+ kex: 'ECDHE_ECDSA',
114
+ sig: 'ECDSA',
115
+ cipher: 'CHACHA20_POLY1305',
116
+ aead: true,
117
+ keylen: 32,
118
+ fixed_ivlen: 4,
119
+ record_ivlen: 8,
120
+ ivlen: 12,
121
+ hash: 'sha256'
122
+ },
123
+ 0xCCAA: { // TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
124
+ tls: 12,
125
+ kex: 'DHE_RSA',
126
+ sig: 'RSA',
127
+ cipher: 'CHACHA20_POLY1305',
128
+ aead: true,
129
+ keylen: 32,
130
+ fixed_ivlen: 4,
131
+ record_ivlen: 8,
132
+ ivlen: 12,
133
+ hash: 'sha256'
134
+ },
135
+ 0x009C: { // TLS_RSA_WITH_AES_128_GCM_SHA256
136
+ tls: 12,
137
+ kex: 'RSA',
138
+ sig: 'RSA',
139
+ cipher: 'AES_128_GCM',
140
+ aead: true,
141
+ keylen: 16,
142
+ fixed_ivlen: 4,
143
+ record_ivlen: 8,
144
+ ivlen: 12,
145
+ hash: 'sha256'
146
+ },
147
+ 0x009D: { // TLS_RSA_WITH_AES_256_GCM_SHA384
148
+ tls: 12,
149
+ kex: 'RSA',
150
+ sig: 'RSA',
151
+ cipher: 'AES_256_GCM',
152
+ aead: true,
153
+ keylen: 32,
154
+ fixed_ivlen: 4,
155
+ record_ivlen: 8,
156
+ ivlen: 12,
157
+ hash: 'sha384'
158
+ },
159
+
160
+ // ----------------------
161
+ // TLS 1.2 CBC (Legacy)
162
+ // ----------------------
163
+ 0xC013: { // TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
164
+ tls: 12,
165
+ kex: 'ECDHE_RSA',
166
+ sig: 'RSA',
167
+ cipher: 'AES_128_CBC',
168
+ aead: false,
169
+ keylen: 16,
170
+ ivlen: 16,
171
+ mac: 'sha1',
172
+ maclen: 20,
173
+ hash: 'sha256'
174
+ },
175
+ 0xC014: { // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
176
+ tls: 12,
177
+ kex: 'ECDHE_RSA',
178
+ sig: 'RSA',
179
+ cipher: 'AES_256_CBC',
180
+ aead: false,
181
+ keylen: 32,
182
+ ivlen: 16,
183
+ mac: 'sha1',
184
+ maclen: 20,
185
+ hash: 'sha256'
186
+ },
187
+ 0x003C: { // TLS_RSA_WITH_AES_128_CBC_SHA256
188
+ tls: 12,
189
+ kex: 'RSA',
190
+ sig: 'RSA',
191
+ cipher: 'AES_128_CBC',
192
+ aead: false,
193
+ keylen: 16,
194
+ ivlen: 16,
195
+ mac: 'sha256',
196
+ maclen: 32,
197
+ hash: 'sha256'
198
+ },
199
+ 0x003D: { // TLS_RSA_WITH_AES_256_CBC_SHA256
200
+ tls: 12,
201
+ kex: 'RSA',
202
+ sig: 'RSA',
203
+ cipher: 'AES_256_CBC',
204
+ aead: false,
205
+ keylen: 32,
206
+ ivlen: 16,
207
+ mac: 'sha256',
208
+ maclen: 32,
209
+ hash: 'sha256'
210
+ }
211
+ };
212
+
213
+
214
+
215
+
216
+
217
+ // --- Hash helpers: מקבלים מחרוזת ומחזירים פונקציית hash + outputLen ---
218
+ function getHashFn(hashName) {
219
+ if (hashName === 'sha256') return sha256;
220
+ if (hashName === 'sha384') return sha384;
221
+ throw new Error('Unsupported hash: ' + hashName);
222
+ }
223
+ function getHashLen(hashName) {
224
+ var fn = getHashFn(hashName);
225
+ return fn.outputLen|0;
226
+ }
227
+
228
+ // --- HMAC (עם noble) ---
229
+ function hmac(hashName, keyU8, dataU8) {
230
+ var hashFn = getHashFn(hashName);
231
+ return nobleHmac(hashFn, keyU8, dataU8); // Uint8Array
232
+ }
233
+
234
+ // --- HKDF wrappers (hash כמחרוזת) ---
235
+ function hkdf_extract(hashName, saltU8, ikmU8) {
236
+ var hashFn = getHashFn(hashName);
237
+ // extract(hash, ikm, salt?)
238
+ return hkdf_extract_noble(hashFn, ikmU8, saltU8);
239
+ }
240
+ function hkdf_expand(hashName, prkU8, infoU8, length) {
241
+ var hashFn = getHashFn(hashName);
242
+ // expand(hash, prk, info, length)
243
+ return hkdf_expand_noble(hashFn, prkU8, infoU8, length|0);
244
+ }
245
+
246
+ // --- TLS 1.3 label builder ---
247
+ function build_hkdf_label(label, context, length) {
248
+ var prefix = 'tls13 ';
249
+ var enc = new TextEncoder();
250
+ var full = enc.encode(prefix + label);
251
+ var info = new Uint8Array(2 + 1 + full.length + 1 + context.length);
252
+
253
+ // length (2 bytes BE)
254
+ info[0] = (length >>> 8) & 0xff;
255
+ info[1] = (length ) & 0xff;
256
+
257
+ // label
258
+ info[2] = full.length;
259
+ info.set(full, 3);
260
+
261
+ // context
262
+ var ofs = 3 + full.length;
263
+ info[ofs] = context.length;
264
+ info.set(context, ofs + 1);
265
+
266
+ return info;
267
+ }
268
+
269
+ function hkdf_expand_label(hashName, secret, label, context, length) {
270
+ var info = build_hkdf_label(label, context, length|0);
271
+ return hkdf_expand(hashName, secret, info, length|0);
272
+ }
273
+
274
+ // --- TLS 1.3: derive handshake secrets ---
275
+ function derive_handshake_traffic_secrets(hashName, shared_secret, transcript) {
276
+ var hashFn = getHashFn(hashName);
277
+
278
+ var hashLen = hashFn.outputLen|0;
279
+
280
+ var empty = new Uint8Array(0);
281
+ var zeros = new Uint8Array(hashLen); // "zeros" כ־salt בגודל hashLen
282
+
283
+ // early_secret = HKDF-Extract(zeros, PSK=empty) כשאין PSK
284
+ var early_secret = hkdf_extract(hashName, empty, zeros);
285
+
286
+ // derived_secret = HKDF-Expand-Label(early_secret, "derived", Hash(""), Hash.length)
287
+ var h_empty = hashFn(empty);
288
+ var derived_secret = hkdf_expand_label(hashName, early_secret, 'derived', h_empty, hashLen);
289
+
290
+ // handshake_secret = HKDF-Extract(derived_secret, shared_secret)
291
+ var handshake_secret = hkdf_extract(hashName, derived_secret, shared_secret);
292
+
293
+ // transcript_hash עד הנקודה הנוכחית
294
+
295
+ var transcript_hash = hashFn(transcript);
296
+
297
+ // תנועת handshake
298
+ var client_handshake_traffic_secret = hkdf_expand_label(hashName, handshake_secret, 'c hs traffic', transcript_hash, hashLen);
299
+ var server_handshake_traffic_secret = hkdf_expand_label(hashName, handshake_secret, 's hs traffic', transcript_hash, hashLen);
300
+
301
+ return {
302
+ handshake_secret: handshake_secret,
303
+ client_handshake_traffic_secret: client_handshake_traffic_secret,
304
+ server_handshake_traffic_secret: server_handshake_traffic_secret,
305
+ };
306
+ }
307
+
308
+ // --- TLS 1.3: derive application secrets ---
309
+ function derive_app_traffic_secrets(hashName, handshake_secret, transcript) {
310
+ var hashFn = getHashFn(hashName);
311
+ var hashLen = hashFn.outputLen|0;
312
+
313
+ var empty = new Uint8Array(0);
314
+ var zeros = new Uint8Array(hashLen);
315
+
316
+ // derived_secret = HKDF-Expand-Label(handshake_secret, "derived", Hash(""), Hash.length)
317
+ var h_empty = hashFn(empty);
318
+ var derived_secret = hkdf_expand_label(hashName, handshake_secret, 'derived', h_empty, hashLen);
319
+
320
+ // master_secret = HKDF-Extract(derived_secret, zeros)
321
+ var master_secret = hkdf_extract(hashName, derived_secret, zeros);
322
+
323
+ // hash של ה־transcript (עד Finished של ה־server בד"כ)
324
+ var transcript_hash = hashFn(transcript);
325
+
326
+ // תנועת application
327
+ var client_app_traffic_secret = hkdf_expand_label(hashName, master_secret, 'c ap traffic', transcript_hash, hashLen);
328
+ var server_app_traffic_secret = hkdf_expand_label(hashName, master_secret, 's ap traffic', transcript_hash, hashLen);
329
+
330
+ return {
331
+ client_app_traffic_secret: client_app_traffic_secret,
332
+ server_app_traffic_secret: server_app_traffic_secret,
333
+ master_secret: master_secret
334
+ };
335
+ }
336
+
337
+
338
+ function build_cert_verify_tbs(hashName, isServer, transcript){
339
+ if(isServer){
340
+ var label = new TextEncoder().encode("TLS 1.3, server CertificateVerify");
341
+ }else{
342
+ var label = new TextEncoder().encode("TLS 1.3, client CertificateVerify");
343
+ }
344
+ var separator = new Uint8Array([0x00]);
345
+ var padding = new Uint8Array(64).fill(0x20);
346
+
347
+ var hashFn = getHashFn(hashName);
348
+ var transcript_hash = hashFn(transcript);
349
+
350
+ return concatUint8Arrays([padding, label, separator, transcript_hash]);
351
+ }
352
+
353
+
354
+ function get_handshake_finished(hashName, traffic_secret, transcript) {
355
+ var hashFn = getHashFn(hashName);
356
+ var hashLen = hashFn.outputLen|0;
357
+
358
+ var empty = new Uint8Array(0);
359
+
360
+ var finished_key = hkdf_expand_label(hashName, traffic_secret, 'finished', empty, hashLen);
361
+ var transcript_hash = hashFn(transcript);
362
+ var verify_data=hmac(hashName, finished_key, transcript_hash);
363
+
364
+ return verify_data;
365
+ }
366
+
367
+ // --- Exports ---
368
+ if (typeof module !== 'undefined' && module.exports) {
369
+ module.exports = {
370
+ TLS_CIPHER_SUITES,
371
+ getHashFn,
372
+ getHashLen,
373
+ hmac,
374
+ hkdf_extract,
375
+ hkdf_expand,
376
+ build_hkdf_label,
377
+ hkdf_expand_label,
378
+ derive_handshake_traffic_secrets,
379
+ derive_app_traffic_secrets,
380
+ build_cert_verify_tbs,
381
+ get_handshake_finished
382
+ };
383
+ }
package/index.js ADDED
@@ -0,0 +1,15 @@
1
+
2
+ var TLSSession = require('./tls_session');
3
+ var TLSSocket = require('./tls_socket');
4
+ var createSecureContext = require('./secure_context');
5
+ //var {createServer} = require('./tls_server');
6
+ //var constants = require('./constants');
7
+
8
+ module.exports = {
9
+ TLSSession: TLSSession,
10
+ TLSSocket: TLSSocket,
11
+ createSecureContext: createSecureContext,
12
+ //createServer: createServer
13
+ //DEFAULT_CIPHERS: constants.DEFAULT_CIPHERS,
14
+ //DEFAULT_SIGALGS: constants.DEFAULT_SIGALGS
15
+ };
package/lemontls.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="993" height="200" stroke="none" stroke-linecap="round" stroke-linejoin="round" fill="#fff" fill-rule="evenodd"><g fill-rule="nonzero"><path d="M172.4 56.8v85.4c0 5.2-2.7 10-7 12.6l-72.6 42.8c-4.3 2.5-9.4 2.5-13.6 0L6.5 154.8c-4.3-2.6-7-7.4-7-12.6V56.8c0-5.2 2.7-10 7-12.6L79.2 1.4c4.2-2.5 9.3-2.5 13.6 0l72.6 42.8c4.3 2.6 7 7.4 7 12.6z" fill="#4f4f4f"/><path d="M94.5 35C86 41.6 86.8 49.2 87 55.8l2.4-.3-.1-3c.5 0 1-.2 1.6-.3 11.7-5.5 6.4-25 6.4-25C97.3 30 90 33.5 85 37c-4.7 3.5-4.8 9-3.8 11.2 1 1.5 2.2 2.6 3.8 3C84 40 94.5 35 94.5 35z" fill="#65cd76"/><path d="M86 55.4c-5.2.1-9.3 3-10.3 6.6-2.8 10.4-26.2 14.3-26.2 45.5s23.4 35 26.2 45.5c1 3.7 5 6.5 10.3 6.6 5.2-.1 9.3-2.8 10.3-6.6 2.8-10.4 26.2-14.3 26.2-45.5S99 72.4 96.2 62c-1-3.7-5-6.5-10.3-6.6zM66.6 91c-5 8-5 25 0 33 .6 1 .5 2.3-.4 3.2-.1.1-.4.2-.5.4-1.2.6-2.7.3-3.5-1a44 44 0 0 1 0-38.3c.8-1.2 2.3-1.6 3.5-1 1.2.8 1.6 2.3.8 3.5z" fill="#ffed24"/></g><path d="M240.7 147.3h46.6V172h-75V28.3h28.3v119zm131.5-31v7.4h-49.6q0 12.3 3 19.5 1 2.5 3.6 5 2.7 2.6 5.6 2.6 3 0 7.2-5 4.3-5 6.7-12l21.2 15q-5.6 10.3-17 18-11.4 7.6-18.3 7.6-7 0-20.2-11-13.3-11-16-17-3-6-3-30 0-24 3-30 2.8-6 16-17 13.2-11 19.4-11 6 0 19.3 11 13.3 10.8 16 17 3 6 3 29.6zm-49.6-12H346q-.7-10.8-2.2-13.6-1.5-2.8-4.7-5.4-3.2-2.7-6-2.7-2.7 0-6.2 5.4-3.5 5.5-4.3 16.3zm143.6-11.6v79.2h-27V95.5q0-3.5-3.7-7.3-3.7-3.8-6.3-3.8-2.5 0-8.3 5v82.4h-27V101q0-10.5-2.5-16.3-2.5-5.7-7.8-10L406 59q6.7 5.7 10 11.7 13.3-12 18.5-12 3 0 10 4.5 7 4.5 12.7 11 16.2-15.4 22.5-15.4 6.3 0 19 11.4 12.6 11.4 12.6 22.4v39.6q0 10.5 2.4 16.2 2.5 5.8 7.8 10l-22.5 16q-14.8-11.7-14.8-33.3V95.5q0-3.5-3.7-7.3-3.7-3.8-6-3.8-2.4 0-8.8 5.2.5 2 .5 3zm121.5 71.6q-12.6 10-18.5 10-6 0-18.6-10-12.6-10-15.5-15-4.3-7.6-4.3-33 0-25.2 4.3-32.6 3-5 15.5-15 12.6-10 18.6-10 6 0 18.5 10 12.6 10 15.5 15 4.3 7.4 4.3 32.6 0 25.3-4.3 33-3 5-15.5 15zM564 147.6q3.2 3 5 3 1.8 0 5-3 3.2-3 4.6-5.5 2.7-4.5 2.7-25.5 0-21-2.7-25.6-1.4-2.5-4.6-5.5-3.2-3-5-3-2 0-5 3-3 3-4.6 5.5-2.7 4.5-2.7 25.4 0 21 2.7 25.7 1.5 2.4 4.6 5.5zM654 93v78.7h-27V101q0-10.5-2.5-16.3-2.5-5.7-7.8-10L639.3 59q7.6 6.2 11.2 14.2 15.2-14.4 21.5-14.4 6.2 0 18.8 11.4 12.7 11.4 12.7 22.4v39.6q0 10.5 2.4 16.2 2.5 5.8 7.8 10l-22.5 15.8q-14.8-11.7-14.8-33.3V95.5q0-3.5-3.7-7.3-3.7-3.8-7-3.8-3.2 0-11.8 8.7z" fill="#4f4f4f"/><path d="M737.3 28.3H819V53h-26.6v119H764V53h-26.7V28.3zm115.4 119h46.6V172h-75V28.3h28.3v119zm52.8-10.7l22.8-15.6q3.2 9.6 10.4 17.6 7.2 8 10.2 8 3 0 6.3-2 3.4-2 5.3-4 2.6-3.3 2.6-10.3 0-7-3.2-8.6-4-3.5-16-9.2-11.8-5.8-22-12.4-10-6.7-12.8-13-2.8-6.3-2.8-16.5 0-10 4.5-17.7 4-6 17.5-16.5 13.3-10.6 19.7-10.6 11.2 0 25.8 11.8 14.6 11.8 18.5 26l-22.8 15.8q-3.3-9.6-10.5-17.7-7-8-10-8-3 0-6.5 1.8-3.5 2-5.6 4.7-2.2 2.7-2.2 9.4 0 6.7 4 9 3.3 3 15 9 30 16.4 35.3 26.7 2.2 3.7 2.2 14.7 0 11-4.5 18.5-4 6-17.4 16.5-13.3 10.6-19.7 10.6-11.3 0-25.8-11.8-14.6-11.8-18.5-26z" fill="#838383"/></svg>
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "lemon-tls",
3
+ "version": "0.1.0",
4
+ "description": "JavaScript TLS 1.3/1.2 implementation for Node.js, with full control over cryptographic keys and record layer",
5
+ "main": "index.js",
6
+ "type": "commonjs",
7
+ "keywords": [
8
+ "openssl",
9
+ "boringssl",
10
+ "cryptlib",
11
+ "rustls",
12
+ "low-level",
13
+ "https",
14
+ "ssl",
15
+ "tls",
16
+ "tls13",
17
+ "tls12",
18
+ "nodejs",
19
+ "javascript",
20
+ "crypto",
21
+ "x509",
22
+ "handshake",
23
+ "alpn",
24
+ "sni",
25
+ "hkdf",
26
+ "aead",
27
+ "quic",
28
+ "http3",
29
+ "dtls",
30
+ "sctp",
31
+ "secure",
32
+ "network",
33
+ "backend",
34
+ "server"
35
+ ],
36
+ "author": "colocohen",
37
+ "license": "Apache-2.0",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/colocohen/lemon-tls.git"
41
+ },
42
+ "bugs": {
43
+ "url": "https://github.com/colocohen/lemon-tls/issues"
44
+ },
45
+ "homepage": "https://github.com/colocohen/lemon-tls",
46
+ "funding": [
47
+ {
48
+ "type": "github",
49
+ "url": "https://github.com/sponsors/colocohen"
50
+ },
51
+ {
52
+ "type": "opencollective",
53
+ "url": "https://opencollective.com/colocohen"
54
+ }
55
+ ],
56
+ "dependencies": {
57
+ "@noble/curves": "^2.0.0",
58
+ "@noble/hashes": "^2.0.0",
59
+ "@stablelib/aes": "^2.0.1",
60
+ "@stablelib/gcm": "^2.0.1"
61
+ }
62
+ }
@@ -0,0 +1,196 @@
1
+ var fs = require('fs');
2
+ var path = require('path');
3
+ var crypto = require('crypto');
4
+
5
+ function looksLikePath(x) {
6
+ return typeof x === 'string' && (x.indexOf('\n') === -1) && (x.length < 4096) &&
7
+ (x.indexOf('-----BEGIN') === -1);
8
+ }
9
+
10
+ function readMaybeFile(x) {
11
+ if (x == null) return null;
12
+ if (looksLikePath(x)) return fs.readFileSync(path.resolve(String(x)));
13
+ if (Buffer.isBuffer(x)) return x;
14
+ if (x instanceof Uint8Array) return Buffer.from(x);
15
+ if (typeof x === 'string') return Buffer.from(x, 'utf8');
16
+ throw new Error('Unsupported input type (expected path/string/Buffer/Uint8Array).');
17
+ }
18
+
19
+ function isPEM(buf) {
20
+ if (!buf) return false;
21
+ var s = buf.toString('utf8');
22
+ return s.indexOf('-----BEGIN ') !== -1 && s.indexOf('-----END ') !== -1;
23
+ }
24
+
25
+ function splitPEMBlocks(pemText) {
26
+ var out = [];
27
+ var re = /-----BEGIN ([A-Z0-9 \-]+)-----([\s\S]*?)-----END \1-----/g;
28
+ var m;
29
+ while ((m = re.exec(pemText)) !== null) {
30
+ var typ = m[1].trim();
31
+ var b64 = m[2].replace(/[\r\n\s]/g, '');
32
+ var derBuf = Buffer.from(b64, 'base64');
33
+ out.push({ type: typ, der: new Uint8Array(derBuf) });
34
+ }
35
+ return out;
36
+ }
37
+
38
+ function ensureArray(x) { return x == null ? [] : (Array.isArray(x) ? x : [x]); }
39
+
40
+ function normalizeCA(caOption) {
41
+ var arr = ensureArray(caOption);
42
+ var ders = [];
43
+ for (var i = 0; i < arr.length; i++) {
44
+ var raw = readMaybeFile(arr[i]);
45
+ if (!raw) continue;
46
+ if (isPEM(raw)) {
47
+ var blocks = splitPEMBlocks(raw.toString('utf8'));
48
+ for (var j = 0; j < blocks.length; j++) {
49
+ if (blocks[j].type.indexOf('CERTIFICATE') !== -1) ders.push(blocks[j].der);
50
+ }
51
+ } else {
52
+ ders.push(new Uint8Array(raw));
53
+ }
54
+ }
55
+ return ders;
56
+ }
57
+
58
+ function makeX509FromDerOrPem(buf) {
59
+ return new crypto.X509Certificate(Buffer.from(buf));
60
+ }
61
+
62
+ function makePrivateKeyFromDerOrPem(buf, passphrase) {
63
+ if (isPEM(buf)) {
64
+ return crypto.createPrivateKey({ key: buf, format: 'pem', passphrase: passphrase });
65
+ } else {
66
+ var der = Buffer.from(buf), keyObj = null;
67
+ try {
68
+ keyObj = crypto.createPrivateKey({ key: der, format: 'der', type: 'pkcs8', passphrase: passphrase });
69
+ } catch (e1) {
70
+ try {
71
+ keyObj = crypto.createPrivateKey({ key: der, format: 'der', type: 'pkcs1', passphrase: passphrase });
72
+ } catch (e2) {
73
+ keyObj = crypto.createPrivateKey({ key: der, format: 'der', type: 'sec1', passphrase: passphrase });
74
+ }
75
+ }
76
+ return keyObj;
77
+ }
78
+ }
79
+
80
+ function exportKeyPkcs8Der(keyObj) {
81
+ return new Uint8Array(keyObj.export({ format: 'der', type: 'pkcs8' }));
82
+ }
83
+
84
+ function u8eq(a,b){ if (a.length!==b.length) return false; for (var i=0;i<a.length;i++) if (a[i]!==b[i]) return false; return true; }
85
+ function dedupeDerArray(arr) {
86
+ var out = [];
87
+ for (var i=0;i<arr.length;i++) {
88
+ var keep = true;
89
+ for (var j=0;j<out.length;j++) { if (u8eq(arr[i], out[j])) { keep = false; break; } }
90
+ if (keep) out.push(arr[i]);
91
+ }
92
+ return out;
93
+ }
94
+
95
+ /**
96
+ * createSecureContext(options)
97
+ * key/cert/ca יכולים להיות: path | Buffer | Uint8Array | string(PEM)
98
+ * מחזיר:
99
+ * - certificateChain: [{ cert: Uint8Array }, ...] // leaf תחילה, אח"כ intermediates
100
+ * - privateKey: Uint8Array // PKCS#8 DER
101
+ * - ca: Uint8Array[] // Trust store (לא משולח ללקוח)
102
+ * - ocsp: Uint8Array|null
103
+ * - ticketKeys: Uint8Array|null
104
+ * - certObjs, keyObj (עזרי debug/לוגיקה)
105
+ */
106
+ function createSecureContext(options) {
107
+ if (!options) options = {};
108
+
109
+ // --- תעודות (כולל שרשרת בתוך cert אם קיימת) ---
110
+ var certBlocksDer = [];
111
+ var certObjs = [];
112
+ if (options.cert != null) {
113
+ var cRaw = readMaybeFile(options.cert);
114
+ if (isPEM(cRaw)) {
115
+ var blocks = splitPEMBlocks(cRaw.toString('utf8'));
116
+ for (var i=0;i<blocks.length;i++) {
117
+ if (blocks[i].type.indexOf('CERTIFICATE') !== -1) {
118
+ certBlocksDer.push(blocks[i].der);
119
+ certObjs.push(makeX509FromDerOrPem(blocks[i].der));
120
+ }
121
+ }
122
+ } else {
123
+ var der = new Uint8Array(cRaw);
124
+ certBlocksDer.push(der);
125
+ certObjs.push(makeX509FromDerOrPem(der));
126
+ }
127
+ }
128
+
129
+ // --- מפתח פרטי ---
130
+ var keyObj = null;
131
+ var privateKey = null;
132
+ if (options.key != null) {
133
+ var kRaw = readMaybeFile(options.key);
134
+ keyObj = makePrivateKeyFromDerOrPem(kRaw, options.passphrase);
135
+ privateKey = exportKeyPkcs8Der(keyObj);
136
+ }
137
+
138
+ // אימות בסיסי (כאשר לא משתמשים ב־PFX)
139
+ if (!options.pfx) {
140
+ if (certBlocksDer.length === 0) throw new Error('createSecureContext: missing cert.');
141
+ if (!privateKey) throw new Error('createSecureContext: missing private key.');
142
+ }
143
+
144
+ // --- CA (Trust store) ---
145
+ var ca = normalizeCA(options.ca);
146
+
147
+ // --- OCSP stapling (אופציונלי) ---
148
+ var ocsp = null;
149
+ if (options.ocsp != null) ocsp = new Uint8Array(readMaybeFile(options.ocsp));
150
+
151
+ // --- Ticket keys (אופציונלי) ---
152
+ var ticketKeys = null;
153
+ if (options.ticketKeys != null) ticketKeys = new Uint8Array(readMaybeFile(options.ticketKeys));
154
+ // אפשרות: ליצור מפתחי ברירת מחדל כאן אם תרצה
155
+
156
+ // --- בניית שרשרת לשיגור ללקוח (leaf → intermediates) ---
157
+ var chainDer = dedupeDerArray(certBlocksDer);
158
+ var certificateChain = [];
159
+ for (var c=0;c<chainDer.length;c++) {
160
+ certificateChain.push({ cert: chainDer[c] });
161
+ }
162
+
163
+ // מידע עזר לזיהוי סוג המפתח הציבורי של ה-leaf
164
+ var leafPublicKeyType = null;
165
+ if (certObjs.length > 0 && certObjs[0].publicKey) {
166
+ try { leafPublicKeyType = certObjs[0].publicKey.asymmetricKeyType || null; } catch (e) { leafPublicKeyType = null; }
167
+ }
168
+
169
+ return {
170
+ // חומר לשכבת ההנדשייק/רקורד:
171
+ certificateChain: certificateChain, // [{ cert: DER(Uint8Array) }, ...]
172
+ privateKey: privateKey, // PKCS#8 DER (Uint8Array)
173
+ ca: ca, // Trust store (DER)
174
+ ocsp: ocsp, // DER (אם הוגדר)
175
+ ticketKeys: ticketKeys, // Uint8Array (אם הוגדר)
176
+
177
+ // עזרי debug/לוגיקה:
178
+ certObjs: certObjs, // [X509Certificate...]
179
+ keyObj: keyObj, // KeyObject
180
+ leafPublicKeyType: leafPublicKeyType,
181
+
182
+ // פרמטרים פרוטוקוליים (אחסון; אתה מפרש בזמן ה-handshake):
183
+ minVersion: String(options.minVersion || 'TLSv1.2'),
184
+ maxVersion: String(options.maxVersion || 'TLSv1.3'),
185
+ ciphers: options.ciphers || null,
186
+ sigalgs: options.sigalgs || null,
187
+ ecdhCurve: options.ecdhCurve || null,
188
+ honorCipherOrder: !!options.honorCipherOrder,
189
+
190
+ // תמיכה ב־PFX אם תרצה לטפל בזה בשכבה אחרת:
191
+ pfx: options.pfx ? new Uint8Array(readMaybeFile(options.pfx)) : null,
192
+ passphrase: options.passphrase ? String(options.passphrase) : null
193
+ };
194
+ }
195
+
196
+ module.exports = createSecureContext;
package/tls_server.js ADDED
File without changes