Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
robert-cronin committed Sep 7, 2020
1 parent cdf4b5e commit b1be443
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 109 deletions.
92 changes: 9 additions & 83 deletions src/lib/keys/pki/PublicKeyInfrastructure.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import path from 'path';
import { pki } from 'node-forge';
import Vault from '../../vaults/Vault';

type EDKeyPair = {
publicKey: pki.ed25519.NativeBuffer;
privateKey: pki.ed25519.NativeBuffer;
}

type TLSCredentials = { privateKey: string, certificate: string, caCertificate: string }
type TLSCredentials = { privateKey: string, certificate: string, rootCertificate: string }
/**
* This class manages X.509 certificates for secure and authenticated communication between peers.
*/
Expand All @@ -19,7 +13,7 @@ class PublicKeyInfrastructure {
pkiVault: Vault

// certificate signed by another
private keypair: EDKeyPair
private keypair: pki.rsa.KeyPair
private certificate?: pki.Certificate


Expand All @@ -31,22 +25,24 @@ class PublicKeyInfrastructure {


public get TLSClientCredentials(): TLSCredentials | undefined {
console.log(this.certificate);
if (this.certificate) {
return {
privateKey: pki.privateKeyToPem(this.keypair.privateKey),
certificate: pki.certificateToPem(this.certificate),
caCertificate: this.CACertificates
rootCertificate: this.CACertificates
}
}
}


public get TLSServerCredentials(): TLSCredentials | undefined {
console.log(this.certificate);
if (this.certificate) {
return {
privateKey: pki.privateKeyToPem(this.keypair.privateKey),
certificate: pki.certificateToPem(this.certificate),
caCertificate: this.CACertificates
rootCertificate: this.CACertificates
}
}
}
Expand All @@ -56,7 +52,7 @@ class PublicKeyInfrastructure {

// root CA
private rootCertificate: pki.Certificate
private rootKeypair: EDKeyPair
private rootKeypair: pki.rsa.KeyPair
public get RootCert(): string {
return pki.certificateToPem(this.rootCertificate)
}
Expand All @@ -78,8 +74,6 @@ class PublicKeyInfrastructure {
) {
const certificate = pki.createCertificate();
certificate.publicKey = this.rootKeypair.publicKey;
// alternatively set public key from a csr
//cert.publicKey = csr.publicKey;
certificate.serialNumber = '01';
certificate.validity.notBefore = new Date();
certificate.validity.notAfter = new Date();
Expand All @@ -96,8 +90,6 @@ class PublicKeyInfrastructure {
},
];
certificate.setSubject(attrs);
// alternatively set subject from a csr
//cert.setSubject(csr.subject.attributes);
certificate.setIssuer(attrs);
certificate.setExtensions([
{
Expand Down Expand Up @@ -260,14 +252,14 @@ class PublicKeyInfrastructure {
this.keypair = JSON.parse(this.pkiVault.getSecret('keypair').toString())
} else {
// create the keypair if it doesn't exist
this.keypair = pki.ed25519.generateKeyPair()
this.keypair = pki.rsa.generateKeyPair()
}

if (this.pkiVault.secretExists('root_keypair')) {
this.rootKeypair = JSON.parse(this.pkiVault.getSecret('root_keypair').toString())
} else {
// create the keys if it doesn't exist
this.rootKeypair = pki.ed25519.generateKeyPair()
this.rootKeypair = pki.rsa.generateKeyPair()
}

// load certificates
Expand Down Expand Up @@ -330,69 +322,3 @@ class PublicKeyInfrastructure {

export default PublicKeyInfrastructure;
export { TLSCredentials }




// const peer1 = new PublicKeyInfrastructure()

// const peer2 = new PublicKeyInfrastructure()
// const peer2Cert = peer1.handleCSR(peer2.createCSR('localhost', 'pass'))
// console.log(peer2Cert);

// const key = pki.privateKeyToPem(peer2.keys.privateKey)
// const cert = peer2Cert



// // const cert = PublicKeyInfrastructure.createX509Certificate()
// // const csr = PublicKeyInfrastructure.createCSR()
// // console.log(csr);

// // console.log(cert.certPem.toString());
// // console.log(cert.keyPem.toString());
// // console.log(fs.readFileSync('./tmp/secrets/peer1/server.key').toString());
// // console.log(fs.readFileSync('./tmp/secrets/peer1/server.crt').toString());


// // const options1: http.ServerOptions = {
// // key: fs.readFileSync('./tmp/secrets/peer1/server.key'),
// // cert: fs.readFileSync('./tmp/secrets/peer1/server.crt')
// // }

// const options2: http.ServerOptions = {
// key,
// cert,
// }

// // http.createServer(options1, (req, res) => {
// // res.writeHead(200);
// // res.end("hello world 1\n");
// // }).listen(8000)

// // set up the mock ca server
// http.createServer(options2, (req, res) => {
// res.writeHead(200);
// res.end("hello world 2\n");
// }).listen(8002)

// const req = http.request({
// host: 'localhost',
// port: 8002,
// path: '/',
// method: 'GET',
// ca: [peer1.RootCert]
// }, (res) => {
// console.log('statusCode:', res.statusCode);
// console.log('headers:', res.headers);

// res.on('data', (d) => {
// process.stdout.write(d);
// });
// })

// req.on('error', (e) => {
// console.error(e);
// });

// req.end()
2 changes: 1 addition & 1 deletion src/lib/peers/peer-connection/PeerConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class PeerConnection {
const credentials = keyManager.pki.TLSClientCredentials;
if (credentials) {
this.credentials = grpc.credentials.createSsl(
Buffer.from(credentials.caCertificate),
Buffer.from(credentials.rootCertificate),
Buffer.from(credentials.privateKey),
Buffer.from(credentials.certificate)
);
Expand Down
6 changes: 3 additions & 3 deletions src/lib/peers/peer-connection/PeerServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ class PeerServer {
});

// Create the server credentials. SSL only if ca cert exists
const credentials = keyManager.pki.TLSClientCredentials;
const credentials = keyManager.pki.TLSServerCredentials;
if (credentials) {
this.credentials = grpc.ServerCredentials.createSsl(
Buffer.from(credentials.caCertificate),
Buffer.from(credentials.rootCertificate),
[
{
private_key: Buffer.from(credentials.privateKey),
cert_chain: Buffer.from(credentials.caCertificate),
cert_chain: Buffer.from(credentials.certificate),
},
],
true
Expand Down
110 changes: 88 additions & 22 deletions tests/lib/peers/PKI.test.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,113 @@
import fs from 'fs'
import os from 'os'
import Polykey from "../../../src/lib/Polykey"
import net from 'net'
import http from 'https'
import crypto from 'crypto'
import { randomString } from '../../../src/lib/utils'
import KeyManager from '../../../src/lib/keys/KeyManager'
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 peerA: Polykey
let pkiA: PublicKeyInfrastructure

let tempDirPeerB: string
let peerB: Polykey
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 keyManager
const keyManagerA = new KeyManager(tempDirPeerA, fs)
await keyManagerA.generateKeyPair('John Smith', '[email protected]', 'some passphrase', 1024, true)

// Initialize polykey
peerA = new Polykey(
tempDirPeerA,
fs,
keyManagerA
)
while (!peerA.peerManager.peerServer.started) {
await new Promise((resolve, reject) => {
setTimeout(() => resolve(), 500)
})
}
// 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 })
})

describe('Peer Connections', () => {
test('can connect securely to another peer and send data back and forth', async done => {
done()
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 = <net.AddressInfo>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()
})
})
})

0 comments on commit b1be443

Please sign in to comment.