lemon-tls 0.1.0 → 0.2.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/src/crypto.js ADDED
@@ -0,0 +1,580 @@
1
+
2
+ import {
3
+ concatUint8Arrays
4
+ } from './utils.js';
5
+
6
+ import crypto from 'node:crypto';
7
+
8
+
9
+ // ============================================================
10
+ // Cipher suite registry
11
+ // ============================================================
12
+
13
+ const TLS_CIPHER_SUITES = {
14
+ // ----------------------
15
+ // TLS 1.3 (RFC 8446)
16
+ // ----------------------
17
+ 0x1301: { // TLS_AES_128_GCM_SHA256
18
+ name: 'TLS_AES_128_GCM_SHA256', standardName: 'TLS_AES_128_GCM_SHA256',
19
+ tls: 13,
20
+ kex: 'TLS13',
21
+ sig: 'TLS13',
22
+ cipher: 'AES_128_GCM',
23
+ aead: true,
24
+ keylen: 16,
25
+ ivlen: 12,
26
+ hash: 'sha256'
27
+ },
28
+ 0x1302: { // TLS_AES_256_GCM_SHA384
29
+ name: 'TLS_AES_256_GCM_SHA384', standardName: 'TLS_AES_256_GCM_SHA384',
30
+ tls: 13,
31
+ kex: 'TLS13',
32
+ sig: 'TLS13',
33
+ cipher: 'AES_256_GCM',
34
+ aead: true,
35
+ keylen: 32,
36
+ ivlen: 12,
37
+ hash: 'sha384'
38
+ },
39
+ 0x1303: { // TLS_CHACHA20_POLY1305_SHA256
40
+ name: 'TLS_CHACHA20_POLY1305_SHA256', standardName: 'TLS_CHACHA20_POLY1305_SHA256',
41
+ tls: 13,
42
+ kex: 'TLS13',
43
+ sig: 'TLS13',
44
+ cipher: 'CHACHA20_POLY1305',
45
+ aead: true,
46
+ keylen: 32,
47
+ ivlen: 12,
48
+ hash: 'sha256'
49
+ },
50
+
51
+ // ----------------------
52
+ // TLS 1.2 AEAD (GCM / CHACHA20)
53
+ // ----------------------
54
+ 0xC02F: { // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
55
+ name: 'ECDHE-RSA-AES128-GCM-SHA256', standardName: 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256',
56
+ tls: 12,
57
+ kex: 'ECDHE_RSA',
58
+ sig: 'RSA',
59
+ cipher: 'AES_128_GCM',
60
+ aead: true,
61
+ keylen: 16,
62
+ fixed_ivlen: 4,
63
+ record_ivlen: 8,
64
+ ivlen: 12,
65
+ hash: 'sha256'
66
+ },
67
+ 0xC030: { // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
68
+ name: 'ECDHE-RSA-AES256-GCM-SHA384', standardName: 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384',
69
+ tls: 12,
70
+ kex: 'ECDHE_RSA',
71
+ sig: 'RSA',
72
+ cipher: 'AES_256_GCM',
73
+ aead: true,
74
+ keylen: 32,
75
+ fixed_ivlen: 4,
76
+ record_ivlen: 8,
77
+ ivlen: 12,
78
+ hash: 'sha384'
79
+ },
80
+ 0xC02B: { // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
81
+ name: 'ECDHE-ECDSA-AES128-GCM-SHA256', standardName: 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',
82
+ tls: 12,
83
+ kex: 'ECDHE_ECDSA',
84
+ sig: 'ECDSA',
85
+ cipher: 'AES_128_GCM',
86
+ aead: true,
87
+ keylen: 16,
88
+ fixed_ivlen: 4,
89
+ record_ivlen: 8,
90
+ ivlen: 12,
91
+ hash: 'sha256'
92
+ },
93
+ 0xC02C: { // TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
94
+ name: 'ECDHE-ECDSA-AES256-GCM-SHA384', standardName: 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384',
95
+ tls: 12,
96
+ kex: 'ECDHE_ECDSA',
97
+ sig: 'ECDSA',
98
+ cipher: 'AES_256_GCM',
99
+ aead: true,
100
+ keylen: 32,
101
+ fixed_ivlen: 4,
102
+ record_ivlen: 8,
103
+ ivlen: 12,
104
+ hash: 'sha384'
105
+ },
106
+ 0xCCA8: { // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
107
+ name: 'ECDHE-RSA-CHACHA20-POLY1305', standardName: 'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256',
108
+ tls: 12,
109
+ kex: 'ECDHE_RSA',
110
+ sig: 'RSA',
111
+ cipher: 'CHACHA20_POLY1305',
112
+ aead: true,
113
+ keylen: 32,
114
+ fixed_ivlen: 12,
115
+ record_ivlen: 0,
116
+ ivlen: 12,
117
+ hash: 'sha256'
118
+ },
119
+ 0xCCA9: { // TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
120
+ name: 'ECDHE-ECDSA-CHACHA20-POLY1305', standardName: 'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256',
121
+ tls: 12,
122
+ kex: 'ECDHE_ECDSA',
123
+ sig: 'ECDSA',
124
+ cipher: 'CHACHA20_POLY1305',
125
+ aead: true,
126
+ keylen: 32,
127
+ fixed_ivlen: 12,
128
+ record_ivlen: 0,
129
+ ivlen: 12,
130
+ hash: 'sha256'
131
+ },
132
+ 0xCCAA: { // TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
133
+ tls: 12,
134
+ kex: 'DHE_RSA',
135
+ sig: 'RSA',
136
+ cipher: 'CHACHA20_POLY1305',
137
+ aead: true,
138
+ keylen: 32,
139
+ fixed_ivlen: 4,
140
+ record_ivlen: 8,
141
+ ivlen: 12,
142
+ hash: 'sha256'
143
+ },
144
+ 0x009C: { // TLS_RSA_WITH_AES_128_GCM_SHA256
145
+ name: 'AES128-GCM-SHA256', standardName: 'TLS_RSA_WITH_AES_128_GCM_SHA256',
146
+ tls: 12,
147
+ kex: 'RSA',
148
+ sig: 'RSA',
149
+ cipher: 'AES_128_GCM',
150
+ aead: true,
151
+ keylen: 16,
152
+ fixed_ivlen: 4,
153
+ record_ivlen: 8,
154
+ ivlen: 12,
155
+ hash: 'sha256'
156
+ },
157
+ 0x009D: { // TLS_RSA_WITH_AES_256_GCM_SHA384
158
+ name: 'AES256-GCM-SHA384', standardName: 'TLS_RSA_WITH_AES_256_GCM_SHA384',
159
+ tls: 12,
160
+ kex: 'RSA',
161
+ sig: 'RSA',
162
+ cipher: 'AES_256_GCM',
163
+ aead: true,
164
+ keylen: 32,
165
+ fixed_ivlen: 4,
166
+ record_ivlen: 8,
167
+ ivlen: 12,
168
+ hash: 'sha384'
169
+ },
170
+
171
+ // ----------------------
172
+ // TLS 1.2 CBC (Legacy)
173
+ // ----------------------
174
+ 0xC013: { // TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
175
+ tls: 12,
176
+ kex: 'ECDHE_RSA',
177
+ sig: 'RSA',
178
+ cipher: 'AES_128_CBC',
179
+ aead: false,
180
+ keylen: 16,
181
+ ivlen: 16,
182
+ mac: 'sha1',
183
+ maclen: 20,
184
+ hash: 'sha256'
185
+ },
186
+ 0xC014: { // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
187
+ tls: 12,
188
+ kex: 'ECDHE_RSA',
189
+ sig: 'RSA',
190
+ cipher: 'AES_256_CBC',
191
+ aead: false,
192
+ keylen: 32,
193
+ ivlen: 16,
194
+ mac: 'sha1',
195
+ maclen: 20,
196
+ hash: 'sha256'
197
+ },
198
+ 0x003C: { // TLS_RSA_WITH_AES_128_CBC_SHA256
199
+ tls: 12,
200
+ kex: 'RSA',
201
+ sig: 'RSA',
202
+ cipher: 'AES_128_CBC',
203
+ aead: false,
204
+ keylen: 16,
205
+ ivlen: 16,
206
+ mac: 'sha256',
207
+ maclen: 32,
208
+ hash: 'sha256'
209
+ },
210
+ 0x003D: { // TLS_RSA_WITH_AES_256_CBC_SHA256
211
+ tls: 12,
212
+ kex: 'RSA',
213
+ sig: 'RSA',
214
+ cipher: 'AES_256_CBC',
215
+ aead: false,
216
+ keylen: 32,
217
+ ivlen: 16,
218
+ mac: 'sha256',
219
+ maclen: 32,
220
+ hash: 'sha256'
221
+ }
222
+ };
223
+
224
+
225
+ // ============================================================
226
+ // Hash helpers
227
+ // Drop-in for noble: callable as hashFn(data) with .outputLen
228
+ // ============================================================
229
+
230
+ function makeHashFn(algorithm, outputLen) {
231
+ let fn = function (data) {
232
+ return new Uint8Array(crypto.createHash(algorithm).update(data).digest());
233
+ };
234
+ fn.outputLen = outputLen;
235
+ return fn;
236
+ }
237
+
238
+ let sha256 = makeHashFn('sha256', 32);
239
+ let sha384 = makeHashFn('sha384', 48);
240
+
241
+ function getHashFn(hashName) {
242
+ if (hashName === 'sha256') return sha256;
243
+ if (hashName === 'sha384') return sha384;
244
+ throw new Error('Unsupported hash: ' + hashName);
245
+ }
246
+
247
+ function getHashLen(hashName) {
248
+ return getHashFn(hashName).outputLen | 0;
249
+ }
250
+
251
+
252
+ // ============================================================
253
+ // HMAC
254
+ // ============================================================
255
+
256
+ function hmac(hashName, keyU8, dataU8) {
257
+ return new Uint8Array(
258
+ crypto.createHmac(hashName, keyU8).update(dataU8).digest()
259
+ );
260
+ }
261
+
262
+
263
+ // ============================================================
264
+ // HKDF Extract / Expand (RFC 5869)
265
+ // ============================================================
266
+
267
+ function hkdf_extract(hashName, saltU8, ikmU8) {
268
+ // RFC 5869 section 2.2: if salt not provided, set to HashLen zeros
269
+ let hashLen = getHashLen(hashName);
270
+ let salt = (saltU8.length === 0) ? Buffer.alloc(hashLen) : saltU8;
271
+ return new Uint8Array(
272
+ crypto.createHmac(hashName, salt).update(ikmU8).digest()
273
+ );
274
+ }
275
+
276
+ function hkdf_expand(hashName, prkU8, infoU8, length) {
277
+ let hashLen = getHashLen(hashName);
278
+ let N = Math.ceil(length / hashLen);
279
+ let output = Buffer.alloc(N * hashLen);
280
+ let prev = Buffer.alloc(0);
281
+
282
+ for (let i = 1; i <= N; i++) {
283
+ let h = crypto.createHmac(hashName, prkU8);
284
+ h.update(prev);
285
+ h.update(infoU8);
286
+ h.update(Buffer.from([i]));
287
+ prev = h.digest();
288
+ prev.copy(output, (i - 1) * hashLen);
289
+ }
290
+
291
+ return new Uint8Array(output.subarray(0, length));
292
+ }
293
+
294
+
295
+ // ============================================================
296
+ // TLS 1.3 HKDF-Expand-Label (RFC 8446 section 7.1)
297
+ // ============================================================
298
+
299
+ function build_hkdf_label(label, context, length) {
300
+ let prefix = 'tls13 ';
301
+ let enc = new TextEncoder();
302
+ let full = enc.encode(prefix + label);
303
+ const info = new Uint8Array(2 + 1 + full.length + 1 + context.length);
304
+
305
+ info[0] = (length >>> 8) & 0xff;
306
+ info[1] = (length ) & 0xff;
307
+ info[2] = full.length;
308
+ info.set(full, 3);
309
+
310
+ let ofs = 3 + full.length;
311
+ info[ofs] = context.length;
312
+ info.set(context, ofs + 1);
313
+
314
+ return info;
315
+ }
316
+
317
+ function hkdf_expand_label(hashName, secret, label, context, length) {
318
+ let info = build_hkdf_label(label, context, length | 0);
319
+ return hkdf_expand(hashName, secret, info, length | 0);
320
+ }
321
+
322
+
323
+ // ============================================================
324
+ // TLS 1.3: derive handshake traffic secrets
325
+ // ============================================================
326
+
327
+ function derive_handshake_traffic_secrets(hashName, shared_secret, transcript) {
328
+ let hashFn = getHashFn(hashName);
329
+ let hashLen = hashFn.outputLen | 0;
330
+ const empty = new Uint8Array(0);
331
+ const zeros = new Uint8Array(hashLen);
332
+
333
+ let early_secret = hkdf_extract(hashName, empty, zeros);
334
+ let h_empty = hashFn(empty);
335
+ let derived_secret = hkdf_expand_label(hashName, early_secret, 'derived', h_empty, hashLen);
336
+ let handshake_secret = hkdf_extract(hashName, derived_secret, shared_secret);
337
+ let transcript_hash = hashFn(transcript);
338
+ let client_handshake_traffic_secret = hkdf_expand_label(hashName, handshake_secret, 'c hs traffic', transcript_hash, hashLen);
339
+ let server_handshake_traffic_secret = hkdf_expand_label(hashName, handshake_secret, 's hs traffic', transcript_hash, hashLen);
340
+
341
+ return {
342
+ handshake_secret: handshake_secret,
343
+ client_handshake_traffic_secret: client_handshake_traffic_secret,
344
+ server_handshake_traffic_secret: server_handshake_traffic_secret,
345
+ };
346
+ }
347
+
348
+
349
+ // ============================================================
350
+ // TLS 1.3: derive application traffic secrets
351
+ // ============================================================
352
+
353
+ function derive_app_traffic_secrets(hashName, handshake_secret, transcript) {
354
+ let hashFn = getHashFn(hashName);
355
+ let hashLen = hashFn.outputLen | 0;
356
+ const empty = new Uint8Array(0);
357
+ const zeros = new Uint8Array(hashLen);
358
+
359
+ let h_empty = hashFn(empty);
360
+ let derived_secret = hkdf_expand_label(hashName, handshake_secret, 'derived', h_empty, hashLen);
361
+ let master_secret = hkdf_extract(hashName, derived_secret, zeros);
362
+ let transcript_hash = hashFn(transcript);
363
+ let client_app_traffic_secret = hkdf_expand_label(hashName, master_secret, 'c ap traffic', transcript_hash, hashLen);
364
+ let server_app_traffic_secret = hkdf_expand_label(hashName, master_secret, 's ap traffic', transcript_hash, hashLen);
365
+
366
+ return {
367
+ client_app_traffic_secret: client_app_traffic_secret,
368
+ server_app_traffic_secret: server_app_traffic_secret,
369
+ master_secret: master_secret
370
+ };
371
+ }
372
+
373
+
374
+ // ============================================================
375
+ // TLS 1.3: resumption master secret (RFC 8446 §7.1)
376
+ // ============================================================
377
+
378
+ /**
379
+ * Derive the resumption_master_secret from the master_secret.
380
+ * transcript = all handshake messages including both Finished.
381
+ */
382
+ function derive_resumption_master_secret(hashName, master_secret, transcript) {
383
+ let hashFn = getHashFn(hashName);
384
+ let hashLen = hashFn.outputLen | 0;
385
+ let transcript_hash = hashFn(transcript);
386
+ return hkdf_expand_label(hashName, master_secret, 'res master', transcript_hash, hashLen);
387
+ }
388
+
389
+ /**
390
+ * Derive PSK from a resumption_master_secret + ticket_nonce.
391
+ * Used by the server when creating a ticket, and by the client when resuming.
392
+ */
393
+ function derive_psk(hashName, resumption_master_secret, ticket_nonce) {
394
+ let hashLen = getHashFn(hashName).outputLen | 0;
395
+ return hkdf_expand_label(hashName, resumption_master_secret, 'resumption', ticket_nonce, hashLen);
396
+ }
397
+
398
+ /**
399
+ * Derive the binder_key for PSK binders in ClientHello.
400
+ * For resumption PSK, label is "res binder".
401
+ * For external PSK, label is "ext binder".
402
+ */
403
+ function derive_binder_key(hashName, psk, isExternal) {
404
+ let hashFn = getHashFn(hashName);
405
+ let hashLen = hashFn.outputLen | 0;
406
+ const empty = new Uint8Array(0);
407
+ const zeros = new Uint8Array(hashLen);
408
+
409
+ let early_secret = hkdf_extract(hashName, empty, psk);
410
+ let h_empty = hashFn(empty);
411
+ let label = isExternal ? 'ext binder' : 'res binder';
412
+ return hkdf_expand_label(hashName, early_secret, label, h_empty, hashLen);
413
+ }
414
+
415
+ /**
416
+ * Compute a PSK binder value.
417
+ * binder_key = derive_binder_key(...)
418
+ * transcript = ClientHello up to (but not including) the binders list.
419
+ */
420
+ function compute_psk_binder(hashName, binder_key, truncated_transcript) {
421
+ let hashFn = getHashFn(hashName);
422
+ let transcript_hash = hashFn(truncated_transcript);
423
+ return hmac(hashName, binder_key, transcript_hash);
424
+ }
425
+
426
+ /**
427
+ * Derive handshake secrets for a PSK-based handshake (with ECDHE).
428
+ * Uses the PSK as input to early_secret instead of zeros.
429
+ */
430
+ function derive_handshake_traffic_secrets_psk(hashName, psk, shared_secret, transcript) {
431
+ let hashFn = getHashFn(hashName);
432
+ let hashLen = hashFn.outputLen | 0;
433
+ const empty = new Uint8Array(0);
434
+
435
+ let early_secret = hkdf_extract(hashName, empty, psk);
436
+ let h_empty = hashFn(empty);
437
+ let derived_secret = hkdf_expand_label(hashName, early_secret, 'derived', h_empty, hashLen);
438
+ let handshake_secret = hkdf_extract(hashName, derived_secret, shared_secret);
439
+ let transcript_hash = hashFn(transcript);
440
+ let client_handshake_traffic_secret = hkdf_expand_label(hashName, handshake_secret, 'c hs traffic', transcript_hash, hashLen);
441
+ let server_handshake_traffic_secret = hkdf_expand_label(hashName, handshake_secret, 's hs traffic', transcript_hash, hashLen);
442
+
443
+ return {
444
+ handshake_secret: handshake_secret,
445
+ client_handshake_traffic_secret: client_handshake_traffic_secret,
446
+ server_handshake_traffic_secret: server_handshake_traffic_secret,
447
+ };
448
+ }
449
+
450
+
451
+ // ============================================================
452
+ // TLS 1.2 PRF (RFC 5246 section 5)
453
+ // ============================================================
454
+
455
+ function tls12_prf(secret, labelStr, seed, outLen, hashName) {
456
+ let label = new TextEncoder().encode(labelStr);
457
+ let fullSeed = concatUint8Arrays([label, seed]);
458
+
459
+ let a = fullSeed;
460
+ let out = new Uint8Array(0);
461
+
462
+ while (out.length < outLen) {
463
+ a = hmac(hashName, secret, a);
464
+ let block = hmac(hashName, secret, concatUint8Arrays([a, fullSeed]));
465
+ const tmp = new Uint8Array(out.length + block.length);
466
+ tmp.set(out, 0);
467
+ tmp.set(block, out.length);
468
+ out = tmp;
469
+ }
470
+
471
+ return out.slice(0, outLen);
472
+ }
473
+
474
+
475
+ // ============================================================
476
+ // TLS 1.2: key_block from master_secret
477
+ // ============================================================
478
+
479
+ function tls_derive_from_master_secret_tls12(master_secret, server_random, client_random, cipher_suite) {
480
+ let p = TLS_CIPHER_SUITES[cipher_suite];
481
+ if (!p || p.tls !== 12) throw new Error('cipher suite not TLS 1.2 or not mapped');
482
+
483
+ let hashName = p.hash;
484
+ let macLen = p.aead ? 0 : (p.maclen || 0);
485
+ let ivFromKbLen = p.aead ? (p.fixed_ivlen || 0) : 0;
486
+ let need = (2 * macLen) + (2 * p.keylen) + (2 * ivFromKbLen);
487
+
488
+ let key_block = tls12_prf(
489
+ master_secret,
490
+ "key expansion",
491
+ concatUint8Arrays([server_random, client_random]),
492
+ need,
493
+ hashName
494
+ );
495
+
496
+ let off = 0;
497
+ let c_mac = null, s_mac = null;
498
+
499
+ if (!p.aead && macLen > 0) {
500
+ c_mac = key_block.slice(off, off + macLen); off += macLen;
501
+ s_mac = key_block.slice(off, off + macLen); off += macLen;
502
+ }
503
+
504
+ let c_key = key_block.slice(off, off + p.keylen); off += p.keylen;
505
+ let s_key = key_block.slice(off, off + p.keylen); off += p.keylen;
506
+
507
+ let c_iv_salt = ivFromKbLen ? key_block.slice(off, off + ivFromKbLen) : null; off += ivFromKbLen;
508
+ let s_iv_salt = ivFromKbLen ? key_block.slice(off, off + ivFromKbLen) : null; off += ivFromKbLen;
509
+
510
+ return {
511
+ client_mac: c_mac,
512
+ server_mac: s_mac,
513
+ client_key: c_key,
514
+ server_key: s_key,
515
+ client_iv: c_iv_salt,
516
+ server_iv: s_iv_salt,
517
+ aead: !!p.aead,
518
+ cipher: p.cipher,
519
+ prf_hash: hashName,
520
+ key_len: p.keylen,
521
+ fixed_ivlen: ivFromKbLen,
522
+ record_ivlen: p.aead ? (p.record_ivlen || 0) : 16
523
+ };
524
+ }
525
+
526
+
527
+ // ============================================================
528
+ // TLS 1.3 CertificateVerify — to-be-signed construction
529
+ // ============================================================
530
+
531
+ function build_cert_verify_tbs(hashName, isServer, transcript) {
532
+ let label = new TextEncoder().encode(
533
+ isServer ? "TLS 1.3, server CertificateVerify" : "TLS 1.3, client CertificateVerify"
534
+ );
535
+ const separator = new Uint8Array([0x00]);
536
+ const padding = new Uint8Array(64).fill(0x20);
537
+ let transcript_hash = getHashFn(hashName)(transcript);
538
+
539
+ return concatUint8Arrays([padding, label, separator, transcript_hash]);
540
+ }
541
+
542
+
543
+ // ============================================================
544
+ // TLS 1.3 Finished verify_data
545
+ // ============================================================
546
+
547
+ function get_handshake_finished(hashName, traffic_secret, transcript) {
548
+ let hashLen = getHashLen(hashName);
549
+ const empty = new Uint8Array(0);
550
+ let finished_key = hkdf_expand_label(hashName, traffic_secret, 'finished', empty, hashLen);
551
+ let transcript_hash = getHashFn(hashName)(transcript);
552
+ return hmac(hashName, finished_key, transcript_hash);
553
+ }
554
+
555
+
556
+ // ============================================================
557
+ // Exports — identical API surface
558
+ // ============================================================
559
+
560
+ export {
561
+ TLS_CIPHER_SUITES,
562
+ getHashFn,
563
+ getHashLen,
564
+ hmac,
565
+ hkdf_extract,
566
+ hkdf_expand,
567
+ build_hkdf_label,
568
+ hkdf_expand_label,
569
+ tls_derive_from_master_secret_tls12,
570
+ tls12_prf,
571
+ derive_handshake_traffic_secrets,
572
+ derive_app_traffic_secrets,
573
+ derive_resumption_master_secret,
574
+ derive_psk,
575
+ derive_binder_key,
576
+ compute_psk_binder,
577
+ derive_handshake_traffic_secrets_psk,
578
+ build_cert_verify_tbs,
579
+ get_handshake_finished
580
+ };