From 7269ae84b77f4f2fc40159d50d72722c0e74a979 Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Thu, 9 Jun 2022 18:14:01 +1000 Subject: [PATCH] tests: expanding tests for root keypair changing Added some tests to check that a root keyPair change propagates properly. Also added tests for the change for existing and new node connections. #317 --- tests/PolykeyAgent.test.ts | 74 ++++++ tests/nodes/NodeConnection.test.ts | 362 +++++++++++++++++++++++++++++ 2 files changed, 436 insertions(+) diff --git a/tests/PolykeyAgent.test.ts b/tests/PolykeyAgent.test.ts index 9423050abf..7cb1f2fc75 100644 --- a/tests/PolykeyAgent.test.ts +++ b/tests/PolykeyAgent.test.ts @@ -1,4 +1,5 @@ import type { StateVersion } from '@/schema/types'; +import type { KeyManagerChangeData } from '@/keys/types'; import os from 'os'; import path from 'path'; import fs from 'fs'; @@ -9,6 +10,7 @@ import { Status } from '@/status'; import { Schema } from '@/schema'; import * as errors from '@/errors'; import config from '@/config'; +import { promise } from '@/utils/index'; import * as testUtils from './utils'; describe('PolykeyAgent', () => { @@ -175,4 +177,76 @@ describe('PolykeyAgent', () => { }), ).rejects.toThrow(errors.ErrorSchemaVersionTooOld); }); + test('renewRootKeyPair change event propagates', async () => { + const nodePath = `${dataDir}/polykey`; + let pkAgent: PolykeyAgent | undefined; + try { + pkAgent = await PolykeyAgent.createPolykeyAgent({ + password, + nodePath, + logger, + }); + const prom = promise(); + pkAgent.events.on( + PolykeyAgent.eventSymbols.KeyManager, + async (data: KeyManagerChangeData) => { + prom.resolveP(data); + }, + ); + await pkAgent.keyManager.renewRootKeyPair(password); + + await expect(prom.p).resolves.toBeDefined(); + } finally { + await pkAgent?.stop(); + await pkAgent?.destroy(); + } + }); + test('resetRootKeyPair change event propagates', async () => { + const nodePath = `${dataDir}/polykey`; + let pkAgent: PolykeyAgent | undefined; + try { + pkAgent = await PolykeyAgent.createPolykeyAgent({ + password, + nodePath, + logger, + }); + const prom = promise(); + pkAgent.events.on( + PolykeyAgent.eventSymbols.KeyManager, + async (data: KeyManagerChangeData) => { + prom.resolveP(data); + }, + ); + await pkAgent.keyManager.resetRootKeyPair(password); + + await expect(prom.p).resolves.toBeDefined(); + } finally { + await pkAgent?.stop(); + await pkAgent?.destroy(); + } + }); + test('resetRootCert change event propagates', async () => { + const nodePath = `${dataDir}/polykey`; + let pkAgent: PolykeyAgent | undefined; + try { + pkAgent = await PolykeyAgent.createPolykeyAgent({ + password, + nodePath, + logger, + }); + const prom = promise(); + pkAgent.events.on( + PolykeyAgent.eventSymbols.KeyManager, + async (data: KeyManagerChangeData) => { + prom.resolveP(data); + }, + ); + await pkAgent.keyManager.resetRootCert(); + + await expect(prom.p).resolves.toBeDefined(); + } finally { + await pkAgent?.stop(); + await pkAgent?.destroy(); + } + }); }); diff --git a/tests/nodes/NodeConnection.test.ts b/tests/nodes/NodeConnection.test.ts index dbd95397e9..b5bac69e54 100644 --- a/tests/nodes/NodeConnection.test.ts +++ b/tests/nodes/NodeConnection.test.ts @@ -174,6 +174,13 @@ describe(`${NodeConnection.name} test`, () => { }; } + const newTlsConfig = async (keyManager: KeyManager): Promise => { + return { + keyPrivatePem: keyManager.getRootKeyPairPem().privateKey, + certChainPem: await keyManager.getRootCertChainPem(), + }; + }; + beforeEach(async () => { // Server setup serverDataDir = await fs.promises.mkdtemp( @@ -852,4 +859,359 @@ describe(`${NodeConnection.name} test`, () => { }, global.defaultTimeout * 2, ); + + test('existing connection handles a resetRootKeyPair on sending side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await clientKeyManager.resetRootKeyPair(password); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('existing connection handles a renewRootKeyPair on sending side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await clientKeyManager.renewRootKeyPair(password); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('existing connection handles a resetRootCert on sending side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await clientKeyManager.resetRootCert(); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('existing connection handles a resetRootKeyPair on receiving side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await serverKeyManager.resetRootKeyPair(password); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('existing connection handles a renewRootKeyPair on receiving side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await serverKeyManager.renewRootKeyPair(password); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('existing connection handles a resetRootCert on receiving side', async () => { + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + + // Simulate key change + await serverKeyManager.resetRootCert(); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + // Try again + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a resetRootKeyPair on sending side', async () => { + let conn: NodeConnection | undefined; + try { + // Simulate key change + await clientKeyManager.resetRootKeyPair(password); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a renewRootKeyPair on sending side', async () => { + let conn: NodeConnection | undefined; + try { + // Simulate key change + await clientKeyManager.renewRootKeyPair(password); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a resetRootCert on sending side', async () => { + let conn: NodeConnection | undefined; + try { + // Simulate key change + await clientKeyManager.resetRootCert(); + clientProxy.setTLSConfig(await newTlsConfig(clientKeyManager)); + + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a resetRootKeyPair on receiving side', async () => { + // Simulate key change + await serverKeyManager.resetRootKeyPair(password); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + const connProm = NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + await expect(connProm).rejects.toThrow( + nodesErrors.ErrorNodeConnectionTimeout, + ); + + // Connect with the new NodeId + let conn: NodeConnection | undefined; + try { + conn = await NodeConnection.createNodeConnection({ + targetNodeId: serverKeyManager.getNodeId(), + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a renewRootKeyPair on receiving side', async () => { + let conn: NodeConnection | undefined; + try { + // Simulate key change + await serverKeyManager.renewRootKeyPair(password); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); + test('new connection handles a resetRootCert on receiving side', async () => { + let conn: NodeConnection | undefined; + try { + // Simulate key change + await serverKeyManager.resetRootCert(); + serverProxy.setTLSConfig(await newTlsConfig(serverKeyManager)); + + conn = await NodeConnection.createNodeConnection({ + targetNodeId: targetNodeId, + targetHost: localHost, + targetPort: targetPort, + proxy: clientProxy, + keyManager: clientKeyManager, + nodeConnectionManager: dummyNodeConnectionManager, + destroyCallback, + logger: logger, + clientFactory: async (args) => + GRPCClientAgent.createGRPCClientAgent(args), + timer: timerStart(2000), + }); + + const client = conn.getClient(); + await client.echo(new utilsPB.EchoMessage().setChallenge('hello!')); + } finally { + await conn?.destroy(); + } + }); });