@joclaim/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/README.md +221 -0
- package/lib/crypto/common.d.ts +3 -0
- package/lib/crypto/common.js +26 -0
- package/lib/crypto/index.d.ts +3 -0
- package/lib/crypto/index.js +4 -0
- package/lib/crypto/insecure-rand.d.ts +1 -0
- package/lib/crypto/insecure-rand.js +9 -0
- package/lib/crypto/pure-js.d.ts +2 -0
- package/lib/crypto/pure-js.js +144 -0
- package/lib/crypto/webcrypto.d.ts +3 -0
- package/lib/crypto/webcrypto.js +310 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +4 -0
- package/lib/make-tls-client.d.ts +74 -0
- package/lib/make-tls-client.js +657 -0
- package/lib/scripts/build-jsc.d.ts +1 -0
- package/lib/scripts/build-jsc.js +20 -0
- package/lib/scripts/ca-template.d.ts +5 -0
- package/lib/scripts/ca-template.js +6 -0
- package/lib/scripts/fallbacks/crypto.d.ts +4 -0
- package/lib/scripts/fallbacks/crypto.js +2 -0
- package/lib/scripts/handshake.d.ts +1 -0
- package/lib/scripts/handshake.js +61 -0
- package/lib/scripts/jsc.d.ts +28 -0
- package/lib/scripts/jsc.js +92 -0
- package/lib/scripts/update-ca-certs.d.ts +1 -0
- package/lib/scripts/update-ca-certs.js +29 -0
- package/lib/types/crypto.d.ts +62 -0
- package/lib/types/crypto.js +1 -0
- package/lib/types/index.d.ts +15 -0
- package/lib/types/index.js +4 -0
- package/lib/types/logger.d.ts +6 -0
- package/lib/types/logger.js +1 -0
- package/lib/types/tls.d.ts +141 -0
- package/lib/types/tls.js +1 -0
- package/lib/types/x509.d.ts +32 -0
- package/lib/types/x509.js +1 -0
- package/lib/utils/additional-root-cas.d.ts +1 -0
- package/lib/utils/additional-root-cas.js +197 -0
- package/lib/utils/client-hello.d.ts +23 -0
- package/lib/utils/client-hello.js +167 -0
- package/lib/utils/constants.d.ts +239 -0
- package/lib/utils/constants.js +244 -0
- package/lib/utils/decryption-utils.d.ts +64 -0
- package/lib/utils/decryption-utils.js +166 -0
- package/lib/utils/finish-messages.d.ts +11 -0
- package/lib/utils/finish-messages.js +49 -0
- package/lib/utils/generics.d.ts +35 -0
- package/lib/utils/generics.js +146 -0
- package/lib/utils/index.d.ts +18 -0
- package/lib/utils/index.js +18 -0
- package/lib/utils/key-share.d.ts +13 -0
- package/lib/utils/key-share.js +72 -0
- package/lib/utils/key-update.d.ts +2 -0
- package/lib/utils/key-update.js +14 -0
- package/lib/utils/logger.d.ts +2 -0
- package/lib/utils/logger.js +15 -0
- package/lib/utils/make-queue.d.ts +3 -0
- package/lib/utils/make-queue.js +22 -0
- package/lib/utils/mozilla-root-cas.d.ts +5 -0
- package/lib/utils/mozilla-root-cas.js +4459 -0
- package/lib/utils/packets.d.ts +51 -0
- package/lib/utils/packets.js +148 -0
- package/lib/utils/parse-alert.d.ts +7 -0
- package/lib/utils/parse-alert.js +28 -0
- package/lib/utils/parse-certificate.d.ts +29 -0
- package/lib/utils/parse-certificate.js +188 -0
- package/lib/utils/parse-client-hello.d.ts +11 -0
- package/lib/utils/parse-client-hello.js +39 -0
- package/lib/utils/parse-extensions.d.ts +11 -0
- package/lib/utils/parse-extensions.js +74 -0
- package/lib/utils/parse-server-hello.d.ts +10 -0
- package/lib/utils/parse-server-hello.js +52 -0
- package/lib/utils/session-ticket.d.ts +17 -0
- package/lib/utils/session-ticket.js +51 -0
- package/lib/utils/wrapped-record.d.ts +25 -0
- package/lib/utils/wrapped-record.js +191 -0
- package/lib/utils/x509.d.ts +5 -0
- package/lib/utils/x509.js +124 -0
- package/package.json +82 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Socket } from 'net';
|
|
2
|
+
import { pino } from 'pino';
|
|
3
|
+
import { makeTLSClient, uint8ArrayToBinaryStr } from "../index.js";
|
|
4
|
+
const LOGGER = pino();
|
|
5
|
+
LOGGER.level = process.env.LOG_LEVEL || 'info';
|
|
6
|
+
const host = readArg('--host');
|
|
7
|
+
if (!host) {
|
|
8
|
+
console.error('Please provide a host to connect to using --host <hostname>');
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
const port = Number(readArg('--port') || 443);
|
|
12
|
+
const socket = new Socket();
|
|
13
|
+
await new Promise((resolve, reject) => {
|
|
14
|
+
const tls = makeTLSClient({
|
|
15
|
+
host,
|
|
16
|
+
verifyServerCertificate: true,
|
|
17
|
+
logger: LOGGER,
|
|
18
|
+
// write raw bytes to the socket
|
|
19
|
+
write({ header, content }) {
|
|
20
|
+
socket.write(header);
|
|
21
|
+
socket.write(content);
|
|
22
|
+
},
|
|
23
|
+
async onHandshake() {
|
|
24
|
+
console.log('handshake completed successfully');
|
|
25
|
+
await tls.end();
|
|
26
|
+
socket.end();
|
|
27
|
+
},
|
|
28
|
+
onApplicationData(plaintext) {
|
|
29
|
+
const str = uint8ArrayToBinaryStr(plaintext);
|
|
30
|
+
console.log('received application data: ', str);
|
|
31
|
+
},
|
|
32
|
+
onTlsEnd(error) {
|
|
33
|
+
if (error) {
|
|
34
|
+
reject(error);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
resolve();
|
|
38
|
+
console.error('TLS connect ended: ', error);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
socket.on('data', tls.handleReceivedBytes);
|
|
42
|
+
// start handshake as soon as the socket connects
|
|
43
|
+
socket.once('connect', () => tls.startHandshake());
|
|
44
|
+
socket.once('error', (err) => reject(err));
|
|
45
|
+
socket.once('close', () => {
|
|
46
|
+
console.log('Socket closed');
|
|
47
|
+
if (!tls.isHandshakeDone()) {
|
|
48
|
+
reject(new Error('Handshake was not completed before socket closed'));
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
// use the TCP socket to connect to the server
|
|
52
|
+
socket.connect({ host, port });
|
|
53
|
+
});
|
|
54
|
+
console.log(`Connected to ${host} successfully`);
|
|
55
|
+
function readArg(arg) {
|
|
56
|
+
const index = process.argv.indexOf(arg);
|
|
57
|
+
if (index === -1) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
return process.argv[index + 1] || '';
|
|
61
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import '../utils/additional-root-cas.js';
|
|
2
|
+
declare global {
|
|
3
|
+
function readline(): string;
|
|
4
|
+
function print(...args: any[]): void;
|
|
5
|
+
function quit(): void;
|
|
6
|
+
type JscIncomingCmd = {
|
|
7
|
+
type: 'exit';
|
|
8
|
+
} | {
|
|
9
|
+
type: 'send';
|
|
10
|
+
dataB64: string;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'send-application-data';
|
|
13
|
+
dataB64: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: 'connect';
|
|
16
|
+
host: string;
|
|
17
|
+
rootCAs?: string[];
|
|
18
|
+
};
|
|
19
|
+
type JscOutgoingCmd = {
|
|
20
|
+
type: 'send-application-data';
|
|
21
|
+
dataB64: string;
|
|
22
|
+
} | {
|
|
23
|
+
type: 'send';
|
|
24
|
+
dataB64: string;
|
|
25
|
+
} | {
|
|
26
|
+
type: 'handshake-done';
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// CLI script that can be run via javascriptcore (jsc)
|
|
2
|
+
// used to test that the TLS client works in the pure jsc environment
|
|
3
|
+
// pls build via esbuild first
|
|
4
|
+
import '../utils/additional-root-cas.js';
|
|
5
|
+
import { setCryptoImplementation } from "../crypto/index.js";
|
|
6
|
+
import { pureJsCrypto } from "../crypto/pure-js.js";
|
|
7
|
+
import { makeTLSClient } from "../make-tls-client.js";
|
|
8
|
+
import { concatenateUint8Arrays } from "../utils/generics.js";
|
|
9
|
+
setCryptoImplementation(pureJsCrypto);
|
|
10
|
+
async function main() {
|
|
11
|
+
print('specify the host to connect to '
|
|
12
|
+
+ '(e.g. {"type":"connect", "host":"localhost:443"}):"}');
|
|
13
|
+
const initCmd = readCmd();
|
|
14
|
+
if (initCmd.type !== 'connect') {
|
|
15
|
+
throw new Error('Expected connect command');
|
|
16
|
+
}
|
|
17
|
+
if (initCmd.rootCAs?.length) {
|
|
18
|
+
TLS_ADDITIONAL_ROOT_CA_LIST.push(...initCmd.rootCAs);
|
|
19
|
+
print(`Added ${initCmd.rootCAs.length} additional root CAs`);
|
|
20
|
+
}
|
|
21
|
+
const tls = makeTLSClient({
|
|
22
|
+
host: initCmd.host,
|
|
23
|
+
logger: {
|
|
24
|
+
info: (...args) => print('[INFO]', ...args),
|
|
25
|
+
debug: (...args) => print('[DEBUG]', ...args),
|
|
26
|
+
trace: () => { },
|
|
27
|
+
warn: (...args) => print('[WARN]', ...args),
|
|
28
|
+
error: (...args) => print('[ERROR]', ...args),
|
|
29
|
+
},
|
|
30
|
+
write({ header, content }) {
|
|
31
|
+
writeCmd({
|
|
32
|
+
type: 'send',
|
|
33
|
+
dataB64: bytesToB64(concatenateUint8Arrays([header, content]))
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
onApplicationData(plaintext) {
|
|
37
|
+
writeCmd({ type: 'send-application-data', dataB64: bytesToB64(plaintext) });
|
|
38
|
+
},
|
|
39
|
+
onTlsEnd(error) {
|
|
40
|
+
print('TLS ended:', error);
|
|
41
|
+
if (error) {
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
quit();
|
|
45
|
+
},
|
|
46
|
+
onHandshake() {
|
|
47
|
+
writeCmd({ type: 'handshake-done' });
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
await tls.startHandshake();
|
|
51
|
+
let cmd;
|
|
52
|
+
while (cmd = readCmd(), cmd.type !== 'exit') {
|
|
53
|
+
if (cmd.type === 'send') {
|
|
54
|
+
const data = base64ToBytes(cmd.dataB64);
|
|
55
|
+
await tls.handleReceivedBytes(data);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (cmd.type === 'send-application-data') {
|
|
59
|
+
const data = base64ToBytes(cmd.dataB64);
|
|
60
|
+
await tls.write(data);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
print('done ✅');
|
|
65
|
+
}
|
|
66
|
+
function base64ToBytes(b64) {
|
|
67
|
+
const binary = atob(b64);
|
|
68
|
+
const bytes = new Uint8Array(binary.length);
|
|
69
|
+
for (let i = 0; i < binary.length; i++) {
|
|
70
|
+
bytes[i] = binary.charCodeAt(i);
|
|
71
|
+
}
|
|
72
|
+
return bytes;
|
|
73
|
+
}
|
|
74
|
+
function bytesToB64(bytes) {
|
|
75
|
+
let binary = '';
|
|
76
|
+
for (const byte of bytes) {
|
|
77
|
+
binary += String.fromCharCode(byte);
|
|
78
|
+
}
|
|
79
|
+
return btoa(binary);
|
|
80
|
+
}
|
|
81
|
+
function readCmd() {
|
|
82
|
+
const cmd = readline();
|
|
83
|
+
return JSON.parse(cmd);
|
|
84
|
+
}
|
|
85
|
+
function writeCmd(cmd) {
|
|
86
|
+
print(JSON.stringify(cmd));
|
|
87
|
+
}
|
|
88
|
+
main()
|
|
89
|
+
.catch(err => {
|
|
90
|
+
print('error in main fn: ', err.message, '\n', err.stack || err);
|
|
91
|
+
quit();
|
|
92
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { parse } from 'csv-parse/sync';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import { loadX509FromPem } from "../utils/index.js";
|
|
4
|
+
async function main() {
|
|
5
|
+
const resp = await fetch('https://ccadb.my.salesforce-sites.com/mozilla/IncludedCACertificateReportPEMCSV');
|
|
6
|
+
const csv = await resp.text();
|
|
7
|
+
const records = parse(csv, {
|
|
8
|
+
columns: true,
|
|
9
|
+
// eslint-disable-next-line camelcase
|
|
10
|
+
skip_empty_lines: true
|
|
11
|
+
});
|
|
12
|
+
const data = fs.readFileSync('src/scripts/ca-template.ts', 'utf8');
|
|
13
|
+
let certs = '';
|
|
14
|
+
for (const record of records) {
|
|
15
|
+
let pem = record['PEM Info'];
|
|
16
|
+
pem = pem.slice(1, -1); //remove ' at the beginning and end
|
|
17
|
+
pem = pem.replaceAll(/\s+\n/sgi, '\n'); //remove trailing spaces in some certs
|
|
18
|
+
//validate
|
|
19
|
+
const cert = loadX509FromPem(pem);
|
|
20
|
+
if (!cert.isWithinValidity()) {
|
|
21
|
+
throw new Error('certificate is not within validity period');
|
|
22
|
+
}
|
|
23
|
+
pem = '`' + pem + '`, //' + record['Common Name or Certificate Name'] + '\n';
|
|
24
|
+
certs += pem;
|
|
25
|
+
}
|
|
26
|
+
const newData = data.replace('\'<<CERTIFICATES>>\'', certs);
|
|
27
|
+
fs.writeFileSync('src/utils/mozilla-root-cas.ts', Buffer.from(newData));
|
|
28
|
+
}
|
|
29
|
+
main().then();
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export type Key = unknown;
|
|
2
|
+
export type AuthenticatedSymmetricCryptoAlgorithm = 'AES-256-GCM' | 'AES-128-GCM' | 'CHACHA20-POLY1305';
|
|
3
|
+
export type SymmetricCryptoAlgorithm = 'AES-128-CBC';
|
|
4
|
+
export type AsymmetricCryptoAlgorithm = 'X25519' | 'P-256' | 'P-384';
|
|
5
|
+
export type AsymmetricEncDecAlgorithm = 'RSA-PCKS1_5';
|
|
6
|
+
export type SignatureAlgorithm = 'RSA-PSS-SHA256' | 'ECDSA-SECP384R1-SHA256' | 'ECDSA-SECP384R1-SHA384' | 'ECDSA-SECP256R1-SHA256' | 'ECDSA-SECP256R1-SHA384' | 'RSA-PKCS1-SHA512' | 'RSA-PKCS1-SHA384' | 'RSA-PKCS1-SHA256' | 'RSA-PKCS1-SHA1';
|
|
7
|
+
export type HashAlgorithm = 'SHA-256' | 'SHA-384' | 'SHA-1';
|
|
8
|
+
type Awaitable<T> = T | Promise<T>;
|
|
9
|
+
type CryptOptions<K = Key> = {
|
|
10
|
+
key: K;
|
|
11
|
+
iv: Uint8Array;
|
|
12
|
+
data: Uint8Array;
|
|
13
|
+
};
|
|
14
|
+
type AuthenticatedCryptOptions<K = Key> = {
|
|
15
|
+
key: K;
|
|
16
|
+
iv: Uint8Array;
|
|
17
|
+
data: Uint8Array;
|
|
18
|
+
aead: Uint8Array;
|
|
19
|
+
};
|
|
20
|
+
type VerifyOptions<K = Key> = {
|
|
21
|
+
data: Uint8Array;
|
|
22
|
+
signature: Uint8Array;
|
|
23
|
+
publicKey: K;
|
|
24
|
+
};
|
|
25
|
+
export type KeyPair<K = Key> = {
|
|
26
|
+
pubKey: K;
|
|
27
|
+
privKey: K;
|
|
28
|
+
};
|
|
29
|
+
export type Crypto<K> = {
|
|
30
|
+
importKey(alg: AuthenticatedSymmetricCryptoAlgorithm | SymmetricCryptoAlgorithm, raw: Uint8Array, empty?: unknown): Awaitable<K>;
|
|
31
|
+
importKey(alg: HashAlgorithm, raw: Uint8Array, empty?: unknown): Awaitable<K>;
|
|
32
|
+
importKey(alg: SignatureAlgorithm | AsymmetricEncDecAlgorithm, raw: Uint8Array, type: 'public'): Awaitable<K>;
|
|
33
|
+
importKey(alg: AsymmetricCryptoAlgorithm, raw: Uint8Array, type: 'private' | 'public'): Awaitable<K>;
|
|
34
|
+
exportKey(key: K): Awaitable<Uint8Array>;
|
|
35
|
+
generateKeyPair(alg: AsymmetricCryptoAlgorithm): Awaitable<KeyPair<K>>;
|
|
36
|
+
calculateSharedSecret(alg: AsymmetricCryptoAlgorithm, privateKey: K, publicKey: K): Awaitable<Uint8Array>;
|
|
37
|
+
randomBytes(length: number): Uint8Array;
|
|
38
|
+
asymmetricEncrypt(cipherSuite: AsymmetricEncDecAlgorithm, opts: {
|
|
39
|
+
publicKey: K;
|
|
40
|
+
data: Uint8Array;
|
|
41
|
+
}): Awaitable<Uint8Array>;
|
|
42
|
+
/**
|
|
43
|
+
* Encrypts data with the given cipher suite and options.
|
|
44
|
+
* Expects padding has already been applied to the data.
|
|
45
|
+
*/
|
|
46
|
+
encrypt(cipherSuite: SymmetricCryptoAlgorithm, opts: CryptOptions<K>): Awaitable<Uint8Array>;
|
|
47
|
+
decrypt(cipherSuite: SymmetricCryptoAlgorithm, opts: CryptOptions<K>): Awaitable<Uint8Array>;
|
|
48
|
+
authenticatedEncrypt(cipherSuite: AuthenticatedSymmetricCryptoAlgorithm, opts: AuthenticatedCryptOptions<K>): Awaitable<{
|
|
49
|
+
ciphertext: Uint8Array;
|
|
50
|
+
authTag: Uint8Array;
|
|
51
|
+
}>;
|
|
52
|
+
authenticatedDecrypt(cipherSuite: AuthenticatedSymmetricCryptoAlgorithm, opts: AuthenticatedCryptOptions<K> & {
|
|
53
|
+
authTag: Uint8Array;
|
|
54
|
+
}): Awaitable<{
|
|
55
|
+
plaintext: Uint8Array;
|
|
56
|
+
}>;
|
|
57
|
+
verify(alg: SignatureAlgorithm, opts: VerifyOptions<K>): Awaitable<boolean>;
|
|
58
|
+
hash(alg: HashAlgorithm, data: Uint8Array): Awaitable<Uint8Array>;
|
|
59
|
+
hmac(alg: HashAlgorithm, key: K, data: Uint8Array): Awaitable<Uint8Array>;
|
|
60
|
+
extract(alg: HashAlgorithm, hashLength: number, ikm: Uint8Array, salt: Uint8Array | string): Awaitable<Uint8Array>;
|
|
61
|
+
};
|
|
62
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { X509Certificate } from './x509.ts';
|
|
2
|
+
export * from './x509.ts';
|
|
3
|
+
export * from './tls.ts';
|
|
4
|
+
export * from './crypto.ts';
|
|
5
|
+
export * from './logger.ts';
|
|
6
|
+
declare global {
|
|
7
|
+
const TLS_ADDITIONAL_ROOT_CA_LIST: string[];
|
|
8
|
+
/**
|
|
9
|
+
* Store fetched intermediate certificates typically fetched via
|
|
10
|
+
* the AIA extension here to avoid refetching
|
|
11
|
+
*/
|
|
12
|
+
const TLS_INTERMEDIATE_CA_CACHE: {
|
|
13
|
+
[url: string]: X509Certificate;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { CONTENT_TYPE_MAP, SUPPORTED_CIPHER_SUITE_MAP, SUPPORTED_NAMED_CURVE_MAP, SUPPORTED_SIGNATURE_ALGS_MAP, TLS_PROTOCOL_VERSION_MAP } from '../utils/constants.ts';
|
|
2
|
+
import type { Key } from './crypto.ts';
|
|
3
|
+
import type { Logger } from './logger.ts';
|
|
4
|
+
import type { X509Certificate } from './x509.ts';
|
|
5
|
+
export type TLSProtocolVersion = keyof typeof TLS_PROTOCOL_VERSION_MAP;
|
|
6
|
+
export type CipherSuite = keyof typeof SUPPORTED_CIPHER_SUITE_MAP;
|
|
7
|
+
export type TLSPacket = {
|
|
8
|
+
header: Uint8Array;
|
|
9
|
+
content: Uint8Array;
|
|
10
|
+
};
|
|
11
|
+
export type TLSKeyType = keyof typeof SUPPORTED_NAMED_CURVE_MAP | 'RSA';
|
|
12
|
+
export type SupportedExtensionServerData = {
|
|
13
|
+
'ALPN': string;
|
|
14
|
+
'SUPPORTED_VERSIONS': TLSProtocolVersion;
|
|
15
|
+
'KEY_SHARE': {
|
|
16
|
+
type: keyof typeof SUPPORTED_NAMED_CURVE_MAP;
|
|
17
|
+
publicKey: Uint8Array;
|
|
18
|
+
};
|
|
19
|
+
'PRE_SHARED_KEY': {
|
|
20
|
+
supported: boolean;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export type SupportedExtensionClientData = {
|
|
24
|
+
'SERVER_NAME': {
|
|
25
|
+
type: number;
|
|
26
|
+
serverName: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export type TLSPacketContext = {
|
|
30
|
+
type: 'plaintext';
|
|
31
|
+
} | {
|
|
32
|
+
type: 'ciphertext';
|
|
33
|
+
encKey: Key;
|
|
34
|
+
/** IV for the session. Computed at handshake */
|
|
35
|
+
fixedIv: Uint8Array;
|
|
36
|
+
/** Actual IV used in the cipher process */
|
|
37
|
+
iv: Uint8Array;
|
|
38
|
+
macKey?: Key;
|
|
39
|
+
recordNumber: number;
|
|
40
|
+
contentType?: keyof typeof CONTENT_TYPE_MAP;
|
|
41
|
+
/**
|
|
42
|
+
* Ciphertext of the record
|
|
43
|
+
* includes the content type,
|
|
44
|
+
* and authTag/MAC
|
|
45
|
+
*/
|
|
46
|
+
ciphertext: Uint8Array;
|
|
47
|
+
plaintext: Uint8Array;
|
|
48
|
+
};
|
|
49
|
+
export type TLSProcessContext = {
|
|
50
|
+
version: TLSProtocolVersion;
|
|
51
|
+
};
|
|
52
|
+
export type TLSHelloBaseOptions = {
|
|
53
|
+
/** Only allow connecting via these TLS versions */
|
|
54
|
+
supportedProtocolVersions?: TLSProtocolVersion[];
|
|
55
|
+
/** the cipher suites the client will claim it supports */
|
|
56
|
+
cipherSuites?: (keyof typeof SUPPORTED_CIPHER_SUITE_MAP)[];
|
|
57
|
+
/** the named curves the client will claim it supports */
|
|
58
|
+
namedCurves?: (keyof typeof SUPPORTED_NAMED_CURVE_MAP)[];
|
|
59
|
+
/**
|
|
60
|
+
* the signature algorithms the client will claim it supports
|
|
61
|
+
* Only used in TLS 1.3
|
|
62
|
+
*/
|
|
63
|
+
signatureAlgorithms?: (keyof typeof SUPPORTED_SIGNATURE_ALGS_MAP)[];
|
|
64
|
+
/**
|
|
65
|
+
* Write to the application layer protocols extension.
|
|
66
|
+
* Specify which protocols the client supports
|
|
67
|
+
*/
|
|
68
|
+
applicationLayerProtocols?: string[];
|
|
69
|
+
};
|
|
70
|
+
export type TLSConnectionOptions = TLSHelloBaseOptions & {
|
|
71
|
+
/**
|
|
72
|
+
* if true, an out of band PSK (pre-shared key)
|
|
73
|
+
* will be generated before connecting via the verifier node
|
|
74
|
+
* */
|
|
75
|
+
generateOutOfBandSession?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* if false, the server certificate will not be verified
|
|
78
|
+
* Use with caution; without server certificate verification
|
|
79
|
+
* it is super easy to MITM the connection & reveal any secrets
|
|
80
|
+
*/
|
|
81
|
+
verifyServerCertificate?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* if provided, the server certificate will be verified against these root CAs
|
|
84
|
+
*/
|
|
85
|
+
rootCAs?: X509Certificate[];
|
|
86
|
+
/**
|
|
87
|
+
* Fetch certificate bytes from a URL
|
|
88
|
+
* Used when the AIA extension is present in a certificate
|
|
89
|
+
* to fetch the issuer certificate
|
|
90
|
+
*/
|
|
91
|
+
fetchCertificateBytes?(url: string): Promise<Uint8Array>;
|
|
92
|
+
};
|
|
93
|
+
export type TLSClientOptions = TLSConnectionOptions & TLSEventHandlers & {
|
|
94
|
+
/** the hostname of the server to connect to */
|
|
95
|
+
host: string;
|
|
96
|
+
/**
|
|
97
|
+
* should it expect the last bytes of a wrapped-record
|
|
98
|
+
* to have an auth tag
|
|
99
|
+
* @default true
|
|
100
|
+
* */
|
|
101
|
+
expectAuthTagInWrappedRecord?: boolean;
|
|
102
|
+
logger?: Logger;
|
|
103
|
+
write(packet: TLSPacket, ctx: TLSPacketContext): Promise<void> | void;
|
|
104
|
+
};
|
|
105
|
+
export type TLSPresharedKey = {
|
|
106
|
+
identity: Uint8Array;
|
|
107
|
+
ticketAge: number;
|
|
108
|
+
finishKey: Key;
|
|
109
|
+
earlySecret: Uint8Array;
|
|
110
|
+
cipherSuite: keyof typeof SUPPORTED_CIPHER_SUITE_MAP;
|
|
111
|
+
};
|
|
112
|
+
export type TLSSessionTicket = {
|
|
113
|
+
expiresAt: Date;
|
|
114
|
+
lifetimeS: number;
|
|
115
|
+
ticketAgeAddMs: number;
|
|
116
|
+
nonce: Uint8Array;
|
|
117
|
+
ticket: Uint8Array;
|
|
118
|
+
extensions: Uint8Array;
|
|
119
|
+
};
|
|
120
|
+
export type TLSHandshakeOptions = {
|
|
121
|
+
random?: Uint8Array;
|
|
122
|
+
psk?: TLSPresharedKey;
|
|
123
|
+
};
|
|
124
|
+
export type TLSEventHandlers = {
|
|
125
|
+
onHandshake?(): void;
|
|
126
|
+
onRecvCertificates?(obj: {
|
|
127
|
+
certificates: X509Certificate[];
|
|
128
|
+
}): void;
|
|
129
|
+
/** Called before any packet is processed */
|
|
130
|
+
onRead?(packet: TLSPacket, ctx: TLSPacketContext): void;
|
|
131
|
+
onApplicationData?(plaintext: Uint8Array): void;
|
|
132
|
+
onTlsEnd?(error?: Error): void;
|
|
133
|
+
onSessionTicket?(ticket: TLSSessionTicket): void;
|
|
134
|
+
};
|
|
135
|
+
export type TLSPacketWithType = {
|
|
136
|
+
type: number;
|
|
137
|
+
packet: TLSPacket;
|
|
138
|
+
};
|
|
139
|
+
export type PacketProcessor = {
|
|
140
|
+
onData(data: Uint8Array): Generator<TLSPacketWithType>;
|
|
141
|
+
};
|
package/lib/types/tls.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type PrivateKey = string;
|
|
2
|
+
export type CertificatePublicKey = {
|
|
3
|
+
/**
|
|
4
|
+
* public key in DER format
|
|
5
|
+
* DER => Uint8Array
|
|
6
|
+
*/
|
|
7
|
+
buffer: Uint8Array;
|
|
8
|
+
algorithm: string;
|
|
9
|
+
};
|
|
10
|
+
export type X509Certificate<T = any> = {
|
|
11
|
+
internal: T;
|
|
12
|
+
/**
|
|
13
|
+
* Checks new Date() is in the validity period
|
|
14
|
+
* of the certificate, basically outside notBefore and notAfter
|
|
15
|
+
*/
|
|
16
|
+
isWithinValidity(): boolean;
|
|
17
|
+
getSubjectField(key: string): string[];
|
|
18
|
+
getAlternativeDNSNames(): string[];
|
|
19
|
+
isIssuer(ofCert: X509Certificate<T>): boolean;
|
|
20
|
+
getPublicKey(): CertificatePublicKey;
|
|
21
|
+
/**
|
|
22
|
+
* Get the Authority Information Access extension value,
|
|
23
|
+
* tells us where to get issuer certificate from
|
|
24
|
+
*/
|
|
25
|
+
getAIAExtension(): string | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* verify this certificate issued the certificate passed
|
|
28
|
+
* @param otherCert the supposedly issued certificate to verify
|
|
29
|
+
* */
|
|
30
|
+
verifyIssued(otherCert: X509Certificate<T>): boolean | Promise<boolean>;
|
|
31
|
+
serialiseToPem(): string;
|
|
32
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|