-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(PrivateKey): Expose provider instead of entire Crypto object (#478)
Needed in relaycorp/awala-keystore-cloud-js#35
- Loading branch information
Showing
14 changed files
with
138 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,19 @@ | ||
import { Crypto } from '@peculiar/webcrypto'; | ||
|
||
import { PrivateKey } from './PrivateKey'; | ||
import { MockAesKwProvider } from './webcrypto/_test_utils'; | ||
import { AwalaAesKwProvider } from './webcrypto/AwalaAesKwProvider'; | ||
|
||
describe('constructor', () => { | ||
const CRYPTO = new Crypto(); | ||
const PROVIDER = new AwalaAesKwProvider(new MockAesKwProvider()); | ||
|
||
test('Key type should be private', () => { | ||
const key = new PrivateKey(CRYPTO); | ||
const key = new PrivateKey(PROVIDER); | ||
|
||
expect(key.type).toEqual('private'); | ||
}); | ||
|
||
test('Crypto should be honoured', () => { | ||
const key = new PrivateKey(CRYPTO); | ||
test('Provider should be honoured', () => { | ||
const key = new PrivateKey(PROVIDER); | ||
|
||
expect(key.crypto).toEqual(CRYPTO); | ||
expect(key.provider).toEqual(PROVIDER); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,23 @@ | ||
import { Crypto as BaseCrypto } from '@peculiar/webcrypto'; | ||
import { getCiphers } from 'crypto'; | ||
import { AesKwProvider, SubtleCrypto } from 'webcrypto-core'; | ||
import { AesKwProvider, ProviderCrypto, SubtleCrypto } from 'webcrypto-core'; | ||
|
||
import { AwalaAesKwProvider } from './AwalaAesKwProvider'; | ||
|
||
export class AwalaCrypto extends BaseCrypto { | ||
constructor() { | ||
constructor(customProviders: readonly ProviderCrypto[] = []) { | ||
super(); | ||
|
||
const providers = (this.subtle as SubtleCrypto).providers; | ||
|
||
const doesNodejsSupportAesKw = getCiphers().includes('id-aes128-wrap'); | ||
if (!doesNodejsSupportAesKw) { | ||
// This must be running on Electron, so let's use a pure JavaScript implementation of AES-KW: | ||
// https://github.com/relaycorp/relaynet-core-js/issues/367 | ||
const providers = (this.subtle as SubtleCrypto).providers; | ||
const nodejsAesKwProvider = providers.get('AES-KW') as AesKwProvider; | ||
providers.set(new AwalaAesKwProvider(nodejsAesKwProvider)); | ||
} | ||
|
||
customProviders.forEach((p) => providers.set(p)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { AesKwProvider } from 'webcrypto-core'; | ||
|
||
export class MockAesKwProvider extends AesKwProvider { | ||
public readonly onGenerateKey = jest.fn(); | ||
public readonly onExportKey = jest.fn(); | ||
public readonly onImportKey = jest.fn(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { SubtleCrypto } from 'webcrypto-core'; | ||
|
||
import { PrivateKey } from '../PrivateKey'; | ||
import { MockAesKwProvider } from './_test_utils'; | ||
import { getEngineForPrivateKey } from './engine'; | ||
|
||
describe('getEngine', () => { | ||
const PROVIDER = new MockAesKwProvider(); | ||
|
||
test('undefined should be returned if CryptoKey is used', () => { | ||
const engine = getEngineForPrivateKey(null as unknown as CryptoKey); | ||
|
||
expect(engine).toBeUndefined(); | ||
}); | ||
|
||
test('Nameless engine should be returned if PrivateKey is used', () => { | ||
const key = new PrivateKey(PROVIDER); | ||
|
||
const engine = getEngineForPrivateKey(key); | ||
|
||
expect(engine?.name).toBeEmpty(); | ||
}); | ||
|
||
test('Engine crypto should use provider from private key', () => { | ||
const key = new PrivateKey(PROVIDER); | ||
|
||
const engine = getEngineForPrivateKey(key); | ||
|
||
expect((engine?.crypto.subtle as SubtleCrypto).providers.get(PROVIDER.name)).toBe(PROVIDER); | ||
}); | ||
|
||
test('Same engine should be returned if multiple keys share provider', () => { | ||
// This is to check engines are being cached | ||
const key1 = new PrivateKey(PROVIDER); | ||
const key2 = new PrivateKey(PROVIDER); | ||
|
||
const engine1 = getEngineForPrivateKey(key1); | ||
const engine2 = getEngineForPrivateKey(key2); | ||
|
||
expect(engine1).toBe(engine2); | ||
}); | ||
|
||
test('Different engines should be returned if keys use different providers', () => { | ||
const key1 = new PrivateKey(PROVIDER); | ||
const key2 = new PrivateKey(new MockAesKwProvider()); | ||
|
||
const engine1 = getEngineForPrivateKey(key1); | ||
const engine2 = getEngineForPrivateKey(key2); | ||
|
||
expect(engine1).not.toBe(engine2); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { CryptoEngine } from 'pkijs'; | ||
import { ProviderCrypto } from 'webcrypto-core'; | ||
|
||
import { PrivateKey } from '../PrivateKey'; | ||
import { AwalaCrypto } from './AwalaCrypto'; | ||
|
||
const ENGINE_BY_PROVIDER = new WeakMap<ProviderCrypto, CryptoEngine>(); | ||
|
||
/** | ||
* Generate and cache PKI.js engine for specified private key. | ||
*/ | ||
export function getEngineForPrivateKey( | ||
privateKey: PrivateKey | CryptoKey, | ||
): CryptoEngine | undefined { | ||
if (!(privateKey instanceof PrivateKey)) { | ||
return undefined; | ||
} | ||
|
||
const cachedEngine = ENGINE_BY_PROVIDER.get(privateKey.provider); | ||
if (cachedEngine) { | ||
return cachedEngine; | ||
} | ||
|
||
const crypto = new AwalaCrypto([privateKey.provider]); | ||
const engine = new CryptoEngine({ crypto }); | ||
ENGINE_BY_PROVIDER.set(privateKey.provider, engine); | ||
return engine; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters