From 2e1e7a77f1c796444373664651b64e5b78613d45 Mon Sep 17 00:00:00 2001 From: Robert Cronin Date: Wed, 9 Sep 2020 12:02:33 +0800 Subject: [PATCH] wip --- src/lib/keys/KeyManager.ts | 15 +- src/lib/keys/pki/PublicKeyInfrastructure.ts | 132 ++++++----- src/lib/vaults/Vault.ts | 44 ++++ src/lib/vaults/VaultManager.ts | 23 +- tests/lib/keys/PKI.test.ts | 235 ++++++++++++++++++++ tests/lib/peers/PKI.test.ts | 113 ---------- 6 files changed, 366 insertions(+), 196 deletions(-) create mode 100644 tests/lib/keys/PKI.test.ts delete mode 100644 tests/lib/peers/PKI.test.ts diff --git a/src/lib/keys/KeyManager.ts b/src/lib/keys/KeyManager.ts index fc8e279ba5..b9abd5dcfb 100644 --- a/src/lib/keys/KeyManager.ts +++ b/src/lib/keys/KeyManager.ts @@ -6,7 +6,7 @@ import crypto from 'crypto'; import { promisify } from 'util'; import { Pool, ModuleThread } from 'threads'; import { KeyManagerWorker } from '../keys/KeyManagerWorker'; -import PublicKeyInfrastructure, { TLSCredentials } from './pki/PublicKeyInfrastructure'; +import PublicKeyInfrastructure from './pki/PublicKeyInfrastructure'; type KeyManagerMetadata = { privateKeyPath: string | null; @@ -18,8 +18,6 @@ type KeyPair = { public: string | null; }; -type PKInfo = { key: Buffer | null; cert: Buffer | null; caCert: Buffer | null }; - class KeyManager { private primaryKeyPair: KeyPair = { private: null, public: null }; private primaryIdentity?: Object; @@ -36,9 +34,6 @@ class KeyManager { private metadata: KeyManagerMetadata = { privateKeyPath: null, publicKeyPath: null, - // pkiKeyPath: null, - // pkiCertPath: null, - // caCertPath: null, }; ///////// @@ -76,14 +71,14 @@ class KeyManager { ///////// // PKI // ///////// - let pkiVaultKey: Buffer + let pkiSymmetricKey: Buffer if (this.hasKey('polykey_pki_vault_key')) { - pkiVaultKey = this.getKey('polykey_pki_vault_key') + pkiSymmetricKey = this.getKey('polykey_pki_vault_key') } else { - pkiVaultKey = this.generateKeySync('polykey_pki_vault_key', 'sf', true) + pkiSymmetricKey = this.generateKeySync('polykey_pki_vault_key', 'sf', true) } - this.pki = new PublicKeyInfrastructure(polyKeyPath, pkiVaultKey, process.env.PK_HOST ?? 'localhost') + this.pki = new PublicKeyInfrastructure(polyKeyPath, pkiSymmetricKey, process.env.PK_HOST ?? 'localhost') } public get identityLoaded(): boolean { diff --git a/src/lib/keys/pki/PublicKeyInfrastructure.ts b/src/lib/keys/pki/PublicKeyInfrastructure.ts index f8ccdf4aed..6e1199c1a0 100644 --- a/src/lib/keys/pki/PublicKeyInfrastructure.ts +++ b/src/lib/keys/pki/PublicKeyInfrastructure.ts @@ -1,5 +1,7 @@ +import fs from 'fs' +import path from 'path' import { pki } from 'node-forge'; -import Vault from '../../vaults/Vault'; +import { EncryptedFS } from 'encryptedfs'; type TLSCredentials = { privateKey: string, certificate: string, rootCertificate: string } /** @@ -9,8 +11,8 @@ class PublicKeyInfrastructure { commonName: string; // pki vault - polykeyPath: string - pkiVault: Vault + pkiPath: string + pkiEfs: EncryptedFS // certificate signed by another private keypair: pki.rsa.KeyPair @@ -25,7 +27,6 @@ class PublicKeyInfrastructure { public get TLSClientCredentials(): TLSCredentials | undefined { - console.log(this.certificate); if (this.certificate) { return { privateKey: pki.privateKeyToPem(this.keypair.privateKey), @@ -37,7 +38,6 @@ class PublicKeyInfrastructure { public get TLSServerCredentials(): TLSCredentials | undefined { - console.log(this.certificate); if (this.certificate) { return { privateKey: pki.privateKeyToPem(this.keypair.privateKey), @@ -62,10 +62,17 @@ class PublicKeyInfrastructure { symmetricKey: Buffer, commonName: string ) { - this.polykeyPath = polykeyPath - this.pkiVault = new Vault('.pkiVault', symmetricKey, polykeyPath) + // create efs instance + const vfsInstance = new (require('virtualfs').VirtualFS)(); + this.pkiEfs = new EncryptedFS( + symmetricKey, + vfsInstance, + vfsInstance, + fs, + process + ); + this.pkiPath = path.join(polykeyPath, '.pki') this.commonName = commonName - this.loadMetadata() } @@ -211,21 +218,51 @@ class PublicKeyInfrastructure { cert.setSubject(csr.subject.attributes); cert.setIssuer(this.rootCertificate.issuer.attributes); + cert.publicKey = csr.publicKey; + cert.setExtensions([...(csr.extensions ?? []), { name: 'basicConstraints', - cA: false - }, { + cA: true, + }, + { name: 'keyUsage', keyCertSign: true, digitalSignature: true, nonRepudiation: true, keyEncipherment: true, - dataEncipherment: true - } + dataEncipherment: true, + }, + { + name: 'extKeyUsage', + serverAuth: true, + clientAuth: true, + codeSigning: true, + emailProtection: true, + timeStamping: true, + }, + { + name: 'nsCertType', + client: true, + server: true, + email: true, + objsign: true, + sslCA: true, + emailCA: true, + objCA: true, + }, + { + name: 'subjectAltName', + altNames: { + type: 7, // IP + ip: '127.0.0.1', + }, + }, + { + name: 'subjectKeyIdentifier', + }, ]); - cert.publicKey = csr.publicKey; // self-sign certificate cert.sign(this.keypair.privateKey); @@ -247,27 +284,37 @@ class PublicKeyInfrastructure { // ===== Helper methods ===== // private loadMetadata(): void { - // load keypairs - if (this.pkiVault.secretExists('keypair')) { - this.keypair = JSON.parse(this.pkiVault.getSecret('keypair').toString()) + // make the pkiPath directory + this.pkiEfs.mkdirSync(this.pkiPath, { recursive: true }) + + // load keypair + const keypairPath = path.join(this.pkiPath, 'keypair') + if (this.pkiEfs.existsSync(keypairPath)) { + this.keypair = JSON.parse(this.pkiEfs.readFileSync(keypairPath).toString()) } else { // create the keypair if it doesn't exist this.keypair = pki.rsa.generateKeyPair() } - if (this.pkiVault.secretExists('root_keypair')) { - this.rootKeypair = JSON.parse(this.pkiVault.getSecret('root_keypair').toString()) + // load root keypair + const rootKeypairPath = path.join(this.pkiPath, 'root_keypair') + if (this.pkiEfs.existsSync(rootKeypairPath)) { + this.rootKeypair = JSON.parse(this.pkiEfs.readFileSync(rootKeypairPath).toString()) } else { - // create the keys if it doesn't exist + // create the keypair if it doesn't exist this.rootKeypair = pki.rsa.generateKeyPair() } - // load certificates - if (this.pkiVault.secretExists('certificate')) { - this.certificate = pki.certificateFromPem(this.pkiVault.getSecret('certificate').toString()) + // load certificate + const certificatePath = path.join(this.pkiPath, 'certificate') + if (this.pkiEfs.existsSync(certificatePath)) { + this.certificate = pki.certificateFromPem(this.pkiEfs.readFileSync(certificatePath).toString()) } - if (this.pkiVault.secretExists('root_certificate')) { - this.rootCertificate = pki.certificateFromPem(this.pkiVault.getSecret('root_certificate').toString()) + + // load root certificate + const rootCertificatePath = path.join(this.pkiPath, 'root_certificate') + if (this.pkiEfs.existsSync(rootCertificatePath)) { + this.rootCertificate = pki.certificateFromPem(this.pkiEfs.readFileSync(rootCertificatePath).toString()) } else { // create the certificate if it doesn't exist this.rootCertificate = this.createCACertificate() @@ -275,8 +322,9 @@ class PublicKeyInfrastructure { // CA store const parsedCertificates: pki.Certificate[] = [] - if (this.pkiVault.secretExists('ca_store_certificates')) { - const certificates: string[] = JSON.parse(this.pkiVault.getSecret('ca_store_certificates').toString()) + const caStorePath = path.join(this.pkiPath, 'ca_store_certificates') + if (this.pkiEfs.existsSync(caStorePath)) { + const certificates: string[] = JSON.parse(this.pkiEfs.readFileSync(caStorePath).toString()) parsedCertificates.push(...certificates.map((c) => pki.certificateFromPem(c))) } this.CAStore = pki.createCaStore(parsedCertificates) @@ -287,36 +335,18 @@ class PublicKeyInfrastructure { private writeMetadata(): void { // write keypairs - if (this.pkiVault.secretExists('keypair')) { - this.pkiVault.updateSecret('keypair', Buffer.from(JSON.stringify(this.keypair))) - } else { - // add if it doesn't exist - this.pkiVault.addSecret('keypair', Buffer.from(JSON.stringify(this.keypair))) - } - if (this.pkiVault.secretExists('root_keypair')) { - this.pkiVault.updateSecret('root_keypair', Buffer.from(JSON.stringify(this.rootKeypair))) - } else { - // add if it doesn't exist - this.pkiVault.addSecret('root_keypair', Buffer.from(JSON.stringify(this.rootKeypair))) - } + this.pkiEfs.writeFileSync(path.join(this.pkiPath, 'keypair'), Buffer.from(JSON.stringify(this.keypair))) + this.pkiEfs.writeFileSync(path.join(this.pkiPath, 'root_keypair'), Buffer.from(JSON.stringify(this.rootKeypair))) // write certificates if (this.certificate) { - const certificate = Buffer.from(pki.certificateToPem(this.certificate)) - if (this.pkiVault.secretExists('certificate')) { - this.pkiVault.updateSecret('certificate', certificate) - } else { - // add if it doesn't exist - this.pkiVault.addSecret('certificate', certificate) - } + this.pkiEfs.writeFileSync(path.join(this.pkiPath, 'certificate'), Buffer.from(pki.certificateToPem(this.certificate))) } + this.pkiEfs.writeFileSync(path.join(this.pkiPath, 'root_certificate'), Buffer.from(pki.certificateToPem(this.rootCertificate))) - const rootCertificate = Buffer.from(pki.certificateToPem(this.rootCertificate)) - if (this.pkiVault.secretExists('root_certificate')) { - this.pkiVault.updateSecret('root_certificate', rootCertificate) - } else { - this.pkiVault.addSecret('root_certificate', rootCertificate) - } + // write ca store + const certsJson = JSON.stringify(this.CAStore.listAllCertificates().map((c) => pki.certificateToPem(c))) + this.pkiEfs.writeFileSync(path.join(this.pkiPath, 'ca_store_certificates'), certsJson) } } diff --git a/src/lib/vaults/Vault.ts b/src/lib/vaults/Vault.ts index 6b510aa51c..da6fc9aed1 100644 --- a/src/lib/vaults/Vault.ts +++ b/src/lib/vaults/Vault.ts @@ -42,6 +42,42 @@ class Vault { this.loadMetadata(); } + async initializeVault(): Promise { + // Init repository for vault + const efs = this.EncryptedFS; + const fileSystem = { promises: efs.promises }; + // first make sure its not already initialized + try { + const statusMatrix = await git.statusMatrix({ + fs: fileSystem, + dir:this.vaultPath + }) + if (statusMatrix == undefined) { + return + } + } catch (error) { + return + } + + await git.init({ + fs: fileSystem, + dir: this.vaultPath, + }); + + // Initial commit + await git.commit({ + fs: fileSystem, + dir: this.vaultPath, + author: { + name: this.name, + }, + message: 'init commit', + }); + // Write packed-refs file because isomorphic git goes searching for it + // and apparently its not autogenerated + efs.writeFileSync(Path.join(this.vaultPath, '.git', 'packed-refs'), '# pack-refs with: peeled fully-peeled sorted'); + } + /** * Returns the Encrypted File System used for vault operations */ @@ -72,13 +108,21 @@ class Vault { } const writePath = Path.join(this.vaultPath, secretName); // Write secret + console.log(writePath); + await this.efs.promises.writeFile(writePath, secret, {}); // Update secrets map this.secrets.set(secretName, secret); + console.log('heyyyyy'); + // Auto commit message await this.commitChanges(`Add secret: ${secretName}`, secretName, 'added'); } catch (error) { release(); + console.log('skdksndfkjsdnfksjdnf'); + console.log(error); + + throw error; } finally { release(); diff --git a/src/lib/vaults/VaultManager.ts b/src/lib/vaults/VaultManager.ts index 05f0a302a3..fbf1d0ee4d 100644 --- a/src/lib/vaults/VaultManager.ts +++ b/src/lib/vaults/VaultManager.ts @@ -119,28 +119,7 @@ class VaultManager { // Create vault const vault = new Vault(vaultName, vaultKey, this.polykeyPath); - - // Init repository for vault - const vaultPath = Path.join(this.polykeyPath, vaultName); - const efs = vault.EncryptedFS; - const fileSystem = { promises: efs.promises }; - await git.init({ - fs: fileSystem, - dir: vaultPath, - }); - - // Initial commit - await git.commit({ - fs: fileSystem, - dir: vaultPath, - author: { - name: vaultName, - }, - message: 'init commit', - }); - // Write packed-refs file because isomorphic git goes searching for it - // and apparently its not autogenerated - efs.writeFileSync(Path.join(vaultPath, '.git', 'packed-refs'), '# pack-refs with: peeled fully-peeled sorted'); + await vault.initializeVault() // Set vault this.vaults.set(vaultName, vault); diff --git a/tests/lib/keys/PKI.test.ts b/tests/lib/keys/PKI.test.ts new file mode 100644 index 0000000000..e949f4a384 --- /dev/null +++ b/tests/lib/keys/PKI.test.ts @@ -0,0 +1,235 @@ +import fs from 'fs' +import os from 'os' +import net from 'net' +import http from 'https' +import crypto from 'crypto' +import forge from 'node-forge' +import { randomString } from '../../../src/lib/utils' +import PublicKeyInfrastructure, { TLSCredentials } from '../../../src/lib/keys/pki/PublicKeyInfrastructure' + +// TODO: part of adding PKI functionality to polykey +describe('PKI testing', () => { + let tempDirPeerCA: string + let pkiCA: PublicKeyInfrastructure + + let tempDirPeerA: string + let pkiA: PublicKeyInfrastructure + + let tempDirPeerB: string + let pkiB: PublicKeyInfrastructure + + beforeAll(async () => { + // ======== CA PEER ======== // + // Define temp directory + tempDirPeerCA = fs.mkdtempSync(`${os.tmpdir}/pktest${randomString()}`) + + // Create pki + const keyCA = crypto.pbkdf2Sync('passphrase', crypto.randomBytes(16), 10000, 256 / 8, 'sha256') + pkiCA = new PublicKeyInfrastructure(tempDirPeerCA, keyCA, 'localhost') + + // ======== PEER A ======== // + // Define temp directory + tempDirPeerA = fs.mkdtempSync(`${os.tmpdir}/pktest${randomString()}`) + + // Create pki + const keyA = crypto.pbkdf2Sync('passphrase', crypto.randomBytes(16), 10000, 256 / 8, 'sha256') + pkiA = new PublicKeyInfrastructure(tempDirPeerA, keyA, 'localhost') + pkiA.addCA(pkiCA.RootCert) + + // ======== PEER B ======== // + // Define temp directory + tempDirPeerB = fs.mkdtempSync(`${os.tmpdir}/pktest${randomString()}`) + + // Create pki + const keyB = crypto.pbkdf2Sync('passphrase', crypto.randomBytes(16), 10000, 256 / 8, 'sha256') + pkiB = new PublicKeyInfrastructure(tempDirPeerB, keyB, 'localhost') + pkiB.addCA(pkiCA.RootCert) + }) + + afterAll(() => { + fs.rmdirSync(tempDirPeerA, { recursive: true }) + fs.rmdirSync(tempDirPeerB, { recursive: true }) + }) + + test('can request a certificate from a ca peer', () => { + const csr = pkiA.createCSR('localhost', 'passphrase') + const certificate = pkiCA.handleCSR(csr) + expect(certificate).not.toEqual(undefined) + }) + + describe('Transport Layer Security', () => { + let tlsServerCredentials: TLSCredentials + let tlsClientCredentials: TLSCredentials + + beforeAll(() => { + // request certificates from CA for both pkiA and pkiB + // ==== PEER A ==== // + const csrA = pkiA.createCSR('server', 'passphrase') + pkiA.importCertificate(pkiCA.handleCSR(csrA)) + // ==== PEER B ==== // + const csrB = pkiB.createCSR('client', 'passphrase') + pkiB.importCertificate(pkiCA.handleCSR(csrB)) + + // pkiA will provide the server credentials and pkiB will provide the client credentials + tlsServerCredentials = pkiA.TLSServerCredentials! + tlsClientCredentials = pkiB.TLSClientCredentials! + }) + + test('can use certificates to create an mtls connection', done => { + // set up the mock server + const randomSecureMessage = `random-secure-message: ${randomString()}\n` + const server = http.createServer({ + key: tlsServerCredentials!.privateKey, + cert: tlsServerCredentials!.certificate, + ca: [pkiCA!.RootCert], + requestCert: true + }, (req, res) => { + res.writeHead(200); + res.end(randomSecureMessage); + }).listen(0) + const serverAddress = server.address() + + const req = http.request({ + host: serverAddress.address, + port: serverAddress.port, + path: '/', + method: 'GET', + key: tlsClientCredentials!.privateKey, + cert: tlsClientCredentials!.certificate, + ca: [pkiCA!.RootCert], + rejectUnauthorized: false + }, (res) => { + res.on('data', (d) => { + expect(d.toString()).toEqual(randomSecureMessage) + done() + }); + }) + + req.on('error', (e) => { + console.log(e); + + expect(e).toBeUndefined() + done() + }); + + req.end() + }) + + test('node forge tls test work with custom certificates', done => { + + const end: any = {}; + + let success = false; + + // create TLS client + end.client = forge.tls.createConnection({ + server: false, + caStore: [forge.pki.certificateFromPem(tlsServerCredentials.certificate)], + sessionCache: {}, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA + ], + virtualHost: 'server', + verify: function (c, verified, depth, certs) { + console.log( + 'TLS Client verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + + '\", verified: ' + verified + '...'); + return verified; + }, + connected: function (c) { + console.log('Client connected...'); + + // send message to server + setTimeout(function () { + c.prepareHeartbeatRequest('heartbeat'); + c.prepare('Hello Server'); + }, 1); + }, + getCertificate: function (c, hint) { + console.log('Client getting certificate ...'); + return tlsClientCredentials.certificate; + }, + getPrivateKey: function (c, cert) { + return tlsClientCredentials.privateKey; + }, + tlsDataReady: function (c) { + // send TLS data to server + end.server.process(c.tlsData.getBytes()); + }, + dataReady: function (c) { + var response = c.data.getBytes(); + console.log('Client received \"' + response + '\"'); + success = (response === 'Hello Client'); + expect(success).toEqual(true) + c.close(); + }, + heartbeatReceived: function (c, payload) { + console.log('Client received heartbeat: ' + payload.getBytes()); + }, + closed: function (c) { + expect(success).toEqual(true) + done() + }, + error: function (c, error) { + console.log('Client error: ' + error.message); + } + }); + + // create TLS server + end.server = forge.tls.createConnection({ + server: true, + caStore: [forge.pki.certificateFromPem(tlsClientCredentials.certificate)], + sessionCache: {}, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + connected: function (c) { + console.log('Server connected'); + c.prepareHeartbeatRequest('heartbeat'); + }, + verifyClient: true, + verify: function (c, verified, depth, certs) { + console.log( + 'Server verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + + '\", verified: ' + verified + '...'); + return verified; + }, + getCertificate: function (c, hint) { + console.log('Server getting certificate for \"' + hint[0] + '\"...'); + return tlsServerCredentials.certificate; + }, + getPrivateKey: function (c, cert) { + return tlsServerCredentials.privateKey; + }, + tlsDataReady: function (c) { + // send TLS data to client + end.client.process(c.tlsData.getBytes()); + }, + dataReady: function (c) { + console.log('Server received \"' + c.data.getBytes() + '\"'); + + // send response + c.prepare('Hello Client'); + c.close(); + }, + heartbeatReceived: function (c, payload) { + console.log('Server received heartbeat: ' + payload.getBytes()); + }, + closed: function (c) { + console.log('Server disconnected.'); + }, + error: function (c, error) { + console.log('Server error: ' + error.message); + } + }); + + console.log('created TLS client and server, doing handshake...'); + end.client.handshake(); + }) + }) +}) diff --git a/tests/lib/peers/PKI.test.ts b/tests/lib/peers/PKI.test.ts deleted file mode 100644 index 10cc0ad8e0..0000000000 --- a/tests/lib/peers/PKI.test.ts +++ /dev/null @@ -1,113 +0,0 @@ -import fs from 'fs' -import os from 'os' -import net from 'net' -import http from 'https' -import crypto from 'crypto' -import { randomString } from '../../../src/lib/utils' -import PublicKeyInfrastructure, { TLSCredentials } from '../../../src/lib/keys/pki/PublicKeyInfrastructure' - -// TODO: part of adding PKI functionality to polykey -describe('PKI', () => { - let tempDirPeerCA: string - let pkiCA: PublicKeyInfrastructure - - let tempDirPeerA: string - let pkiA: PublicKeyInfrastructure - - let tempDirPeerB: string - let pkiB: PublicKeyInfrastructure - - beforeAll(async () => { - // ======== CA PEER ======== // - // Define temp directory - tempDirPeerCA = fs.mkdtempSync(`${os.tmpdir}/pktest${randomString()}`) - - // Create pki - const keyCA = crypto.pbkdf2Sync('passphrase', crypto.randomBytes(16), 10000, 256 / 8, 'sha256') - pkiCA = new PublicKeyInfrastructure(tempDirPeerCA, keyCA, 'localhost') - - // ======== PEER A ======== // - // Define temp directory - tempDirPeerA = fs.mkdtempSync(`${os.tmpdir}/pktest${randomString()}`) - - // Create pki - const keyA = crypto.pbkdf2Sync('passphrase', crypto.randomBytes(16), 10000, 256 / 8, 'sha256') - pkiA = new PublicKeyInfrastructure(tempDirPeerA, keyA, 'localhost') - pkiA.addCA(pkiCA.RootCert) - - // ======== PEER B ======== // - // Define temp directory - tempDirPeerB = fs.mkdtempSync(`${os.tmpdir}/pktest${randomString()}`) - - // Create pki - const keyB = crypto.pbkdf2Sync('passphrase', crypto.randomBytes(16), 10000, 256 / 8, 'sha256') - pkiB = new PublicKeyInfrastructure(tempDirPeerB, keyB, 'localhost') - pkiB.addCA(pkiCA.RootCert) - }) - - afterAll(() => { - fs.rmdirSync(tempDirPeerA, { recursive: true }) - fs.rmdirSync(tempDirPeerB, { recursive: true }) - }) - - test('can request a certificate from a ca peer', () => { - const csr = pkiA.createCSR('localhost', 'passphrase') - const certificate = pkiCA.handleCSR(csr) - expect(certificate).not.toEqual(undefined) - }) - - describe('Transport Layer Security', () => { - let tlsServerCredentials: TLSCredentials | undefined - let tlsClientCredentials: TLSCredentials | undefined - - beforeAll(() => { - // request certificates from CA for both pkiA and pkiB - // ==== PEER A ==== // - const csrA = pkiA.createCSR('localhost', 'passphrase') - pkiA.importCertificate(pkiCA.handleCSR(csrA)) - // ==== PEER B ==== // - const csrB = pkiB.createCSR('localhost', 'passphrase') - pkiB.importCertificate(pkiCA.handleCSR(csrB)) - - // pkiA will provide the server credentials and pkiB will provide the client credentials - tlsServerCredentials = pkiA.TLSServerCredentials - tlsClientCredentials = pkiB.TLSClientCredentials - }) - - test('can use certificates to create an mtls connection', done => { - // set up the mock server - const randomSecureMessage = `random-secure-message: ${randomString()}\n` - const server = http.createServer({ - key: tlsServerCredentials!.privateKey, - cert: tlsServerCredentials!.certificate, - ca: [tlsServerCredentials!.rootCertificate] - }, (req, res) => { - res.writeHead(200); - res.end(randomSecureMessage); - }).listen(0) - const serverAddress = server.address() - - const req = http.request({ - host: serverAddress.address, - port: serverAddress.port, - path: '/', - method: 'GET', - key: tlsClientCredentials!.privateKey, - cert: tlsClientCredentials!.certificate, - ca: [pkiCA!.RootCert] - }, (res) => { - res.on('data', (d) => { - expect(d).toEqual(randomSecureMessage) - done() - }); - }) - - req.on('error', (e) => { - expect(e).toBeUndefined() - done() - }); - - req.end() - }) - }) -})