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/LICENSE +201 -0
- package/README.md +185 -0
- package/crypto.js +383 -0
- package/index.js +15 -0
- package/lemontls.svg +1 -0
- package/package.json +62 -0
- package/secure_context.js +196 -0
- package/tls_server.js +0 -0
- package/tls_session.js +1441 -0
- package/tls_socket.js +456 -0
- package/utils.js +88 -0
- package/wire.js +1672 -0
package/tls_socket.js
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
|
|
2
|
+
var TLSSession = require('./tls_session');
|
|
3
|
+
|
|
4
|
+
var { AES } = require('@stablelib/aes');
|
|
5
|
+
var { GCM } = require('@stablelib/gcm');
|
|
6
|
+
|
|
7
|
+
var {
|
|
8
|
+
TLS_CIPHER_SUITES,
|
|
9
|
+
hkdf_expand_label
|
|
10
|
+
} = require('./crypto');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
function Emitter(){
|
|
15
|
+
var listeners = {};
|
|
16
|
+
return {
|
|
17
|
+
on: function(name, fn){ (listeners[name] = listeners[name] || []).push(fn); },
|
|
18
|
+
emit: function(name){
|
|
19
|
+
var args = Array.prototype.slice.call(arguments, 1);
|
|
20
|
+
var arr = listeners[name] || [];
|
|
21
|
+
for (var i=0;i<arr.length;i++){ try{ arr[i].apply(null, args); }catch(e){} }
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// TLS ContentType
|
|
27
|
+
var CT = { CHANGE_CIPHER_SPEC:20, ALERT:21, HANDSHAKE:22, APPLICATION_DATA:23 };
|
|
28
|
+
// legacy_record_version בשדה כותרת הרשומה (TLS 1.3 שומר 0x0303)
|
|
29
|
+
var REC_VERSION = 0x0303;
|
|
30
|
+
|
|
31
|
+
// ==== עזרי המרה ====
|
|
32
|
+
function toBuf(u8){ return Buffer.isBuffer(u8) ? u8 : Buffer.from(u8 || []); }
|
|
33
|
+
function toU8(buf){ return (buf instanceof Uint8Array) ? buf : new Uint8Array(buf || []); }
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
function tls_derive_from_tls_secrets(traffic_secret, cipher_suite){
|
|
38
|
+
|
|
39
|
+
var empty = new Uint8Array(0);
|
|
40
|
+
|
|
41
|
+
var key = hkdf_expand_label(TLS_CIPHER_SUITES[cipher_suite].hash, traffic_secret, 'key', empty, TLS_CIPHER_SUITES[cipher_suite].keylen);
|
|
42
|
+
|
|
43
|
+
var iv = hkdf_expand_label(TLS_CIPHER_SUITES[cipher_suite].hash, traffic_secret, 'iv', empty, 12);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
key: key,
|
|
47
|
+
iv: iv,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
function get_nonce(iv,seq) {
|
|
53
|
+
|
|
54
|
+
var seq_buf = new Uint8Array(12); // all zero
|
|
55
|
+
var view = new DataView(seq_buf.buffer);
|
|
56
|
+
view.setBigUint64(4, BigInt(seq)); // offset 4, 64-bit BE
|
|
57
|
+
|
|
58
|
+
var nonce = new Uint8Array(12);
|
|
59
|
+
for (var i = 0; i < 12; i++) {
|
|
60
|
+
nonce[i] = iv[i] ^ seq_buf[i];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return nonce;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function encrypt_tls_record(innerType, plaintext, key, nonce) {
|
|
67
|
+
const aes = new AES(key);
|
|
68
|
+
const gcm = new GCM(aes);
|
|
69
|
+
|
|
70
|
+
// TLSInnerPlaintext = content || content_type || padding(0x00…)
|
|
71
|
+
const full_plaintext = new Uint8Array(plaintext.length + 1);
|
|
72
|
+
full_plaintext.set(plaintext);
|
|
73
|
+
full_plaintext[plaintext.length] = innerType; // ← אל תשכח לבחור נכון
|
|
74
|
+
|
|
75
|
+
// AAD = [ 0x17, 0x03, 0x03, len_hi, len_lo ]
|
|
76
|
+
// len = ciphertext.length כולל tag = full_plaintext.length + 16 (ב-GCM)
|
|
77
|
+
const aad = new Uint8Array(5);
|
|
78
|
+
aad[0] = 0x17;
|
|
79
|
+
aad[1] = 0x03; aad[2] = 0x03;
|
|
80
|
+
const recLen = full_plaintext.length + 16; // tag=16
|
|
81
|
+
aad[3] = (recLen >>> 8) & 0xff;
|
|
82
|
+
aad[4] = (recLen ) & 0xff;
|
|
83
|
+
|
|
84
|
+
// הצפנה אחת עם AAD הנכון
|
|
85
|
+
const ciphertext = gcm.seal(nonce, full_plaintext, aad); // אמור להחזיר ct||tag
|
|
86
|
+
return ciphertext;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
function decrypt_tls_record(ciphertext, key, nonce) {
|
|
92
|
+
// הקמה: AES + GCM
|
|
93
|
+
var aes = new AES(key);
|
|
94
|
+
var gcm = new GCM(aes);
|
|
95
|
+
|
|
96
|
+
// AAD לפי TLS 1.3: 0x17 (application_data), גרסה 0x0303, ואורך ה-ciphertext
|
|
97
|
+
var aad = new Uint8Array(5);
|
|
98
|
+
aad[0] = 0x17; // record type תמיד 0x17 אחרי הצפנה
|
|
99
|
+
aad[1] = 0x03; aad[2] = 0x03; // "גרסת" הרשומה (TLS 1.2 בפועל לשכבת הרשומה)
|
|
100
|
+
var len = ciphertext.length;
|
|
101
|
+
aad[3] = (len >> 8) & 0xff;
|
|
102
|
+
aad[4] = len & 0xff;
|
|
103
|
+
|
|
104
|
+
// פתיחה (אימות + פענוח). אם ה-tag לא תקף, תחזור null/undefined לפי המימוש
|
|
105
|
+
var full_plaintext = gcm.open(nonce, ciphertext, aad);
|
|
106
|
+
if (!full_plaintext) {
|
|
107
|
+
throw new Error('GCM authentication failed (bad tag)');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return full_plaintext;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function parse_tls_inner_plaintext(full_plaintext) {
|
|
114
|
+
var j = full_plaintext.length - 1;
|
|
115
|
+
while (j >= 0 && full_plaintext[j] === 0x00) { j--; }
|
|
116
|
+
if (j < 0) throw new Error('Malformed TLSInnerPlaintext (no content type)');
|
|
117
|
+
|
|
118
|
+
var content_type = full_plaintext[j];
|
|
119
|
+
var content = full_plaintext.slice(0, j); // חיתוך אמיתי
|
|
120
|
+
return { content_type: content_type, content: content };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
// ==== TLSSocket ====
|
|
125
|
+
function TLSSocket(duplex, options){
|
|
126
|
+
if (!(this instanceof TLSSocket)) return new TLSSocket(duplex, options);
|
|
127
|
+
options = options || {};
|
|
128
|
+
|
|
129
|
+
var ev = Emitter();
|
|
130
|
+
|
|
131
|
+
var context = {
|
|
132
|
+
|
|
133
|
+
options: options,
|
|
134
|
+
|
|
135
|
+
// transport (Duplex) שמחובר מבחוץ
|
|
136
|
+
transport: (duplex && typeof duplex.write === 'function') ? duplex : null,
|
|
137
|
+
|
|
138
|
+
// TLSSession פנימי בלבד
|
|
139
|
+
session: new TLSSession({
|
|
140
|
+
isServer: !!options.isServer,
|
|
141
|
+
servername: options.servername,
|
|
142
|
+
ALPNProtocols: options.ALPNProtocols || null,
|
|
143
|
+
SNICallback: options.SNICallback || null
|
|
144
|
+
}),
|
|
145
|
+
|
|
146
|
+
// Handshake write
|
|
147
|
+
handshake_write_key: null,
|
|
148
|
+
handshake_write_iv: null,
|
|
149
|
+
handshake_write_seq: 0,
|
|
150
|
+
handshake_write_aead: null,
|
|
151
|
+
|
|
152
|
+
// Handshake read
|
|
153
|
+
handshake_read_key: null,
|
|
154
|
+
handshake_read_iv: null,
|
|
155
|
+
handshake_read_seq: 0,
|
|
156
|
+
handshake_read_aead: null,
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
// Application write
|
|
160
|
+
app_write_key: null,
|
|
161
|
+
app_write_iv: null,
|
|
162
|
+
app_write_seq: 0,
|
|
163
|
+
app_write_aead: null,
|
|
164
|
+
|
|
165
|
+
// Application read
|
|
166
|
+
app_read_key: null,
|
|
167
|
+
app_read_iv: null,
|
|
168
|
+
app_read_seq: 0,
|
|
169
|
+
app_read_aead: null,
|
|
170
|
+
|
|
171
|
+
using_app_keys: false,
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
// באפרים ותורים
|
|
177
|
+
readBuffer: Buffer.alloc(0),
|
|
178
|
+
appWriteQueue: [],
|
|
179
|
+
|
|
180
|
+
// מצבים כלליים
|
|
181
|
+
destroyed: false,
|
|
182
|
+
secureEstablished: false,
|
|
183
|
+
|
|
184
|
+
// legacy record version (TLS1.3)
|
|
185
|
+
rec_version: 0x0303
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
// === שכבת הרשומות (Record Layer) ===
|
|
190
|
+
function writeRecord(type, payload){
|
|
191
|
+
if (!context.transport) throw new Error('No transport attached to TLSSocket');
|
|
192
|
+
var rec = Buffer.allocUnsafe(5 + payload.length);
|
|
193
|
+
rec.writeUInt8(type, 0);
|
|
194
|
+
rec.writeUInt16BE(context.rec_version, 1);
|
|
195
|
+
rec.writeUInt16BE(payload.length, 3);
|
|
196
|
+
payload.copy(rec, 5);
|
|
197
|
+
try { context.transport.write(rec); } catch(e){ ev.emit('error', e); }
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function writeAppData(plain){
|
|
201
|
+
//console.log('...');
|
|
202
|
+
|
|
203
|
+
if(context.session.context.server_app_traffic_secret!==null){
|
|
204
|
+
if(context.app_write_key==null || context.app_write_iv==null){
|
|
205
|
+
var d=tls_derive_from_tls_secrets(context.session.context.server_app_traffic_secret,context.session.context.selected_cipher_suite);
|
|
206
|
+
|
|
207
|
+
context.app_write_key=d.key;
|
|
208
|
+
context.app_write_iv=d.iv;
|
|
209
|
+
}
|
|
210
|
+
}else{
|
|
211
|
+
//console.log('no key yet...');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
var enc1 = encrypt_tls_record(CT.APPLICATION_DATA,plain, context.app_write_key, get_nonce(context.app_write_iv,context.app_write_seq));
|
|
215
|
+
|
|
216
|
+
context.app_write_seq++;
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
|
|
220
|
+
//console.log(enc1);
|
|
221
|
+
|
|
222
|
+
writeRecord(CT.APPLICATION_DATA, Buffer.from(enc1));
|
|
223
|
+
} catch(e){
|
|
224
|
+
ev.emit('error', e);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function processCiphertext(body){
|
|
230
|
+
|
|
231
|
+
var out=null;
|
|
232
|
+
|
|
233
|
+
if(context.using_app_keys==true){
|
|
234
|
+
|
|
235
|
+
if(context.session.context.client_app_traffic_secret!==null){
|
|
236
|
+
if(context.app_read_key==null || context.app_read_iv==null){
|
|
237
|
+
var d=tls_derive_from_tls_secrets(context.session.context.client_app_traffic_secret,context.session.context.selected_cipher_suite);
|
|
238
|
+
|
|
239
|
+
context.app_read_key=d.key;
|
|
240
|
+
context.app_read_iv=d.iv;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
out = decrypt_tls_record(body, context.app_read_key, get_nonce(context.app_read_iv,context.app_read_seq));
|
|
244
|
+
|
|
245
|
+
context.app_read_seq++;
|
|
246
|
+
|
|
247
|
+
}else{
|
|
248
|
+
//...
|
|
249
|
+
}
|
|
250
|
+
}else{
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
if(context.session.context.client_handshake_traffic_secret!==null){
|
|
254
|
+
if(context.handshake_read_key==null || context.handshake_read_iv==null){
|
|
255
|
+
var d=tls_derive_from_tls_secrets(context.session.context.client_handshake_traffic_secret,context.session.context.selected_cipher_suite);
|
|
256
|
+
|
|
257
|
+
context.handshake_read_key=d.key;
|
|
258
|
+
context.handshake_read_iv=d.iv;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
out = decrypt_tls_record(body, context.handshake_read_key, get_nonce(context.handshake_read_iv,context.handshake_read_seq));
|
|
262
|
+
|
|
263
|
+
context.handshake_read_seq++;
|
|
264
|
+
|
|
265
|
+
}else{
|
|
266
|
+
//...
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
if(out!==null){
|
|
272
|
+
var {content_type, content} = parse_tls_inner_plaintext(out);
|
|
273
|
+
|
|
274
|
+
if (content_type === CT.HANDSHAKE || content_type === CT.ALERT) {
|
|
275
|
+
//var cls = usingApp ? 2 : 1; // 1=handshake-keys, 2=app-keys
|
|
276
|
+
try { context.session.message(new Uint8Array(content)); } catch(e){ ev.emit('error', e); }
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (content_type === CT.APPLICATION_DATA) { ev.emit('data', content); return; }
|
|
281
|
+
if (content_type === CT.CHANGE_CIPHER_SPEC) { return; }
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
function parseRecordsAndDispatch(){
|
|
290
|
+
while (context.readBuffer.length >= 5) {
|
|
291
|
+
var type = context.readBuffer.readUInt8(0);
|
|
292
|
+
var ver = context.readBuffer.readUInt16BE(1);
|
|
293
|
+
var len = context.readBuffer.readUInt16BE(3);
|
|
294
|
+
if (context.readBuffer.length < 5 + len) break;
|
|
295
|
+
|
|
296
|
+
var body = context.readBuffer.slice(5, 5+len);
|
|
297
|
+
context.readBuffer = context.readBuffer.slice(5+len);
|
|
298
|
+
|
|
299
|
+
if (type === CT.APPLICATION_DATA) {
|
|
300
|
+
try { processCiphertext(body); } catch(e){ ev.emit('error', e); }
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (type === CT.HANDSHAKE || type === CT.ALERT || type === CT.CHANGE_CIPHER_SPEC) {
|
|
305
|
+
try { context.session.message(new Uint8Array(body)); } catch(e){ ev.emit('error', e); }
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
function bindTransport(){
|
|
313
|
+
if (!context.transport) return;
|
|
314
|
+
context.transport.on('data', function(chunk){
|
|
315
|
+
context.readBuffer = Buffer.concat([context.readBuffer, chunk]);
|
|
316
|
+
parseRecordsAndDispatch();
|
|
317
|
+
});
|
|
318
|
+
context.transport.on('error', function(err){ ev.emit('error', err); });
|
|
319
|
+
context.transport.on('close', function(){ ev.emit('close'); });
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
context.session.on('message', function(epoch, seq, type, data){
|
|
323
|
+
var buf = toBuf(data || []);
|
|
324
|
+
|
|
325
|
+
if (epoch === 0) {
|
|
326
|
+
// ברור (ClientHello/ServerHello/CCS/Alert מוקדם)
|
|
327
|
+
writeRecord(CT.HANDSHAKE, buf);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (epoch === 1) {
|
|
332
|
+
|
|
333
|
+
//need to create it...
|
|
334
|
+
if(context.session.context.server_handshake_traffic_secret!==null){
|
|
335
|
+
|
|
336
|
+
if(context.handshake_write_key==null || context.handshake_write_iv==null){
|
|
337
|
+
var d=tls_derive_from_tls_secrets(context.session.context.server_handshake_traffic_secret,context.session.context.selected_cipher_suite);
|
|
338
|
+
|
|
339
|
+
context.handshake_write_key=d.key;
|
|
340
|
+
context.handshake_write_iv=d.iv;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
var enc1 = encrypt_tls_record(CT.HANDSHAKE, buf, context.handshake_write_key, get_nonce(context.handshake_write_iv,context.handshake_write_seq));
|
|
345
|
+
|
|
346
|
+
context.handshake_write_seq++;
|
|
347
|
+
|
|
348
|
+
try {
|
|
349
|
+
//var enc1 = aeadEncrypt(context.handshake_write_key, context.handshake_write_iv, TLS_CIPHER_SUITES[context.session.context.selected_cipher_suite].cipher, context.handshake_write_seq, 0x0304, CT.HANDSHAKE, buf);
|
|
350
|
+
|
|
351
|
+
//console.log(enc1);
|
|
352
|
+
|
|
353
|
+
writeRecord(CT.APPLICATION_DATA, Buffer.from(enc1));
|
|
354
|
+
} catch(e){
|
|
355
|
+
ev.emit('error', e);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
}else{
|
|
359
|
+
ev.emit('error', new Error('Missing handshake write keys'));
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (epoch === 2) {
|
|
364
|
+
// Post-Handshake מוצפן (inner_type=HANDSHAKE) תחת מפתחות Application
|
|
365
|
+
if (!context.application_write) { ev.emit('error', new Error('Missing application write keys')); return; }
|
|
366
|
+
try {
|
|
367
|
+
var enc2 = aeadEncrypt(context.application_write, CT.HANDSHAKE, buf);
|
|
368
|
+
writeRecord(CT.APPLICATION_DATA, enc2);
|
|
369
|
+
} catch(e){ ev.emit('error', e); }
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
context.session.on('hello', function(info){
|
|
376
|
+
|
|
377
|
+
context.rec_version = 0x0303; // TLS 1.3 legacy record version
|
|
378
|
+
|
|
379
|
+
context.session.set_context({
|
|
380
|
+
|
|
381
|
+
local_versions: [0x0304],
|
|
382
|
+
local_alpns: ['http/1.1'],
|
|
383
|
+
local_groups: [0x001d, 0x0017, 0x0018],
|
|
384
|
+
local_cipher_suites: [
|
|
385
|
+
0x1301,
|
|
386
|
+
0x1302,
|
|
387
|
+
0xC02F, // ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
|
388
|
+
0xC030, // ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
|
389
|
+
0xCCA8 // ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (אם מימשת)
|
|
390
|
+
],
|
|
391
|
+
|
|
392
|
+
// ---- אלגוריתמי חתימה (TLS 1.2 → RSA-PKCS1, לא PSS) ----
|
|
393
|
+
// 0x0401 = rsa_pkcs1_sha256, 0x0501 = rsa_pkcs1_sha384, 0x0601 = rsa_pkcs1_sha512
|
|
394
|
+
local_signature_algorithms: [0x0401, 0x0501, 0x0601],
|
|
395
|
+
// אופציונלי (לטובת חלק מהלקוחות): אותו דבר גם ל-signature_algorithms_cert
|
|
396
|
+
local_signature_algorithms_cert: [0x0401, 0x0501, 0x0601],
|
|
397
|
+
|
|
398
|
+
//local_cert_chain: [{ cert: new Uint8Array(cert.raw)}],
|
|
399
|
+
//cert_private_key: new Uint8Array(private_key_der)
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
context.session.on('secureConnect', function(){
|
|
404
|
+
context.using_app_keys=true;
|
|
405
|
+
ev.emit('secureConnect');
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// אם הועבר duplex בבנאי — להתחיל לקלוט
|
|
409
|
+
if (context.transport) {
|
|
410
|
+
bindTransport();
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// === API ציבורי (ללא חשיפת session) ===
|
|
414
|
+
var api = {
|
|
415
|
+
on: function(name, fn){ ev.on(name, fn); },
|
|
416
|
+
|
|
417
|
+
setSocket: function(duplex2){
|
|
418
|
+
if (!duplex2 || typeof duplex2.write !== 'function') throw new Error('setSocket expects a Duplex-like stream');
|
|
419
|
+
context.transport = duplex2;
|
|
420
|
+
bindTransport();
|
|
421
|
+
},
|
|
422
|
+
|
|
423
|
+
write: function(data){
|
|
424
|
+
if (context.destroyed) return false;
|
|
425
|
+
var buf = toBuf(data);
|
|
426
|
+
if (!context.using_app_keys) { context.appWriteQueue.push(buf); return true; }
|
|
427
|
+
return writeAppData(buf);
|
|
428
|
+
},
|
|
429
|
+
|
|
430
|
+
end: function(data){
|
|
431
|
+
if (context.destroyed) return;
|
|
432
|
+
if (typeof data !== 'undefined' && data !== null) api.write(data);
|
|
433
|
+
try { context.transport && context.transport.end && context.transport.end(); } catch(e){}
|
|
434
|
+
},
|
|
435
|
+
|
|
436
|
+
destroy: function(){
|
|
437
|
+
if (context.destroyed) return;
|
|
438
|
+
context.destroyed = true;
|
|
439
|
+
try { context.transport && context.transport.destroy && context.transport.destroy(); } catch(e){}
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
getCipher: function(){
|
|
443
|
+
var cs = context.session && context.session.context && context.session.context.selected_cipher_suite;
|
|
444
|
+
return { name: cs || 'TLS_AES_128_GCM_SHA256', version: 'TLSv1.3' };
|
|
445
|
+
},
|
|
446
|
+
getPeerCertificate: function(){ return null; },
|
|
447
|
+
authorized: function(){ return true; }
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
for (var k in api) if (Object.prototype.hasOwnProperty.call(api,k)) this[k] = api[k];
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
return this;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
module.exports = TLSSocket;
|
package/utils.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
|
|
2
|
+
function concatUint8Arrays(arrays) {
|
|
3
|
+
var totalLength = 0;
|
|
4
|
+
for (var i = 0; i < arrays.length; i++) {
|
|
5
|
+
totalLength += arrays[i].length;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
var result = new Uint8Array(totalLength);
|
|
9
|
+
var offset = 0;
|
|
10
|
+
|
|
11
|
+
for (var i = 0; i < arrays.length; i++) {
|
|
12
|
+
result.set(arrays[i], offset);
|
|
13
|
+
offset += arrays[i].length;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function arraybufferEqual(buf1, buf2) {
|
|
20
|
+
//if (buf1 === buf2) {
|
|
21
|
+
//return true;
|
|
22
|
+
//}
|
|
23
|
+
|
|
24
|
+
if (buf1.byteLength !== buf2.byteLength) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var view1 = new DataView(buf1);
|
|
29
|
+
var view2 = new DataView(buf2);
|
|
30
|
+
|
|
31
|
+
for (let i = 0; i < buf1.byteLength; i++) {
|
|
32
|
+
if (view1.getUint8(i) !== view2.getUint8(i)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function arraysEqual(a, b) {
|
|
41
|
+
//if (a === b) return true;
|
|
42
|
+
if (a == null || b == null) return false;
|
|
43
|
+
if (a.length !== b.length) return false;
|
|
44
|
+
|
|
45
|
+
// If you don't care about the order of the elements inside
|
|
46
|
+
// the array, you should sort both arrays here.
|
|
47
|
+
// Please note that calling sort on an array will modify that array.
|
|
48
|
+
// you might want to clone your array first.
|
|
49
|
+
|
|
50
|
+
for (var i = 0; i < a.length; ++i) {
|
|
51
|
+
if(typeof a[i] !== 'undefined' && typeof b[i] !== 'undefined' && a[i]!==null && b[i]!==null && typeof a[i].byteLength == 'number' && typeof b[i].byteLength == 'number'){
|
|
52
|
+
if(arraybufferEqual(a[i],b[i])==false){
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}else{
|
|
56
|
+
if(typeof a[i]=='string' && typeof b[i]=='string'){
|
|
57
|
+
if (a[i] !== b[i]){
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}else if(a[i].constructor==RegExp && typeof b[i]=='string'){
|
|
61
|
+
if(a[i].test(b[i])==false){
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}else if(typeof a[i]=='string' && b[i].constructor==RegExp){
|
|
65
|
+
if(b[i].test(a[i])==false){
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
//}else if(a[i] instanceof Object && b[i] instanceof Object && Object.keys(a[i]).length>0 && Object.keys(b[i]).length>0){
|
|
69
|
+
//if(_this.objectEquals(a[i],b[i])==false){
|
|
70
|
+
// return false;
|
|
71
|
+
//}
|
|
72
|
+
}else{
|
|
73
|
+
if (a[i] !== b[i]){
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
module.exports = {
|
|
85
|
+
concatUint8Arrays,
|
|
86
|
+
arraybufferEqual,
|
|
87
|
+
arraysEqual
|
|
88
|
+
};
|