Merge pull request #38 from microsoft/beejones/add-unit-tests
Beejones/add unit tests
This commit is contained in:
Коммит
f21da34940
|
@ -1,3 +1,16 @@
|
|||
# version 1.1.12-preview.1
|
||||
## Keyvault exportKey did not add the kid in the jwk.
|
||||
**Type of change:** engineering
|
||||
**Customer impact:** low
|
||||
|
||||
## async functions no longer throw but reject an Error
|
||||
**Type of change:** engineering
|
||||
**Customer impact:** low
|
||||
|
||||
## Round one to come to 100% line coverage.
|
||||
**Type of change:** engineering
|
||||
**Customer impact:** low
|
||||
|
||||
# version 1.1.12-preview.0
|
||||
## Remove all console.log calls from the SDK
|
||||
**Type of change:** engineering
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "verifiablecredentials-crypto-sdk-typescript-keystore",
|
||||
"version": "1.1.12-preview.0",
|
||||
"version": "1.1.12-preview.1",
|
||||
"description": "Package for managing keys in a key store.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -35,7 +35,7 @@
|
|||
"typescript": "4.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.1",
|
||||
"@types/node": "14.6.2",
|
||||
"base64url": "^3.0.1",
|
||||
"clone": "^2.1.2",
|
||||
|
|
|
@ -40,11 +40,19 @@ describe('KeyStoreInMemory', () => {
|
|||
y: 'AAEE',
|
||||
alg: 'ECDSA'
|
||||
};
|
||||
|
||||
let list = await keyStore.list();
|
||||
expect(list).toEqual({});
|
||||
|
||||
(<any>keyStore).store = new Map<string, any>();
|
||||
(<any>keyStore).store.set('1', undefined);
|
||||
expect(await keyStore.list()).toEqual({});
|
||||
|
||||
await keyStore.save(new KeyReference('1'), key1);
|
||||
await keyStore.save(new KeyReference('1'), key2);
|
||||
await keyStore.save(new KeyReference('2'), <PublicKey>key3);
|
||||
await keyStore.save(new KeyReference('3'), <PublicKey>key4);
|
||||
let list = await keyStore.list();
|
||||
list = await keyStore.list();
|
||||
|
||||
// tslint:disable-next-line: no-backbone-get-set-outside-model
|
||||
expect(list['1'].kids.length).toEqual(2);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "verifiablecredentials-crypto-sdk-typescript-keys",
|
||||
"version": "1.1.12-preview.0",
|
||||
"version": "1.1.12-preview.1",
|
||||
"description": "Package for managing keys in the DID space.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "verifiablecredentials-crypto-sdk-typescript-plugin-cryptofactory-suites",
|
||||
"version": "1.1.12-preview.0",
|
||||
"version": "1.1.12-preview.1",
|
||||
"description": "Package crypto factory suites.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -36,9 +36,9 @@
|
|||
"typescript": "4.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-elliptic": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-elliptic": "1.1.12-preview.1",
|
||||
"base64url": "^3.0.1",
|
||||
"clone": "2.1.2",
|
||||
"webcrypto-core": "1.1.8"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "verifiablecredentials-crypto-sdk-typescript-plugin-elliptic",
|
||||
"version": "1.1.12-preview.0",
|
||||
"version": "1.1.12-preview.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/VerifiableCredentials-Crypto-SDK-Typescript.git"
|
||||
|
@ -29,7 +29,7 @@
|
|||
"elliptic": "6.5.3",
|
||||
"minimalistic-crypto-utils": "1.0.1",
|
||||
"sha.js": "^2.4.11",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.1",
|
||||
"webcrypto-core": "1.1.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -115,7 +115,7 @@ export default class EllipticEcDsaProvider extends EllipticDsaProvider {
|
|||
async onExportKey (format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
//const ec = this.getCurve((<any>key.algorithm).namedCurve);
|
||||
if (format !== 'jwk') {
|
||||
throw new Error(`Export key only supports jwk`);
|
||||
return Promise.reject(new Error(`Export key only supports jwk`));
|
||||
}
|
||||
|
||||
const cryptoKey: any = (<EllipticCurveKey> key).key;
|
||||
|
@ -151,7 +151,7 @@ export default class EllipticEcDsaProvider extends EllipticDsaProvider {
|
|||
async onImportKey (format: KeyFormat,
|
||||
keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
if (format !== 'jwk') {
|
||||
throw new Error(`Import key only supports jwk`);
|
||||
return Promise.reject(new Error(`Import key only supports jwk`));
|
||||
}
|
||||
const ec = this.getCurve(algorithm.namedCurve);
|
||||
const jwkKey: JsonWebKey = <JsonWebKey> keyData;
|
||||
|
|
|
@ -116,7 +116,7 @@ export default class EllipticEdDsaProvider extends EllipticDsaProvider {
|
|||
async onImportKey(format: KeyFormat,
|
||||
keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
if (format !== 'jwk') {
|
||||
throw new Error(`Import key only supports jwk`);
|
||||
return Promise.reject(new Error(`Import key only supports jwk`));
|
||||
}
|
||||
const ec = this.getCurve(algorithm.namedCurve);
|
||||
const jwkKey: any = <JsonWebKey>keyData;
|
||||
|
@ -144,7 +144,7 @@ export default class EllipticEdDsaProvider extends EllipticDsaProvider {
|
|||
async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
//const ec = this.getCurve((<any>key.algorithm).namedCurve);
|
||||
if (format !== 'jwk') {
|
||||
throw new Error(`Export key only supports jwk`);
|
||||
return Promise.reject(new Error(`Export key only supports jwk`));
|
||||
}
|
||||
|
||||
const ecKey: any = (<EllipticCurveKey>key).key;
|
||||
|
|
|
@ -21,12 +21,6 @@ export default class SubtleCryptoElliptic extends SubtleCrypto implements ISubtl
|
|||
this.providers.set(<ProviderCrypto>new EllipticEcDsaProvider(crypto));
|
||||
this.providers.set(new EllipticEdDsaProvider(crypto));
|
||||
}
|
||||
|
||||
checkRequiredArguments(args: any[], size: number, methodName: string) {
|
||||
if (methodName !== 'generateKey' && args.length !== size) {
|
||||
throw new TypeError(`Failed to execute '${methodName}' on 'SubtleCrypto': ${size} arguments required, but only ${args.length} present`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the @class SubtleCrypto implementation for the nodes environment
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import SubtleCryptoElliptic from '../src/SubtleCryptoElliptic';
|
||||
import { Subtle } from 'verifiablecredentials-crypto-sdk-typescript-plugin';
|
||||
|
||||
describe('SubtleCryptoElliptic', () => {
|
||||
it('should create a SubtleCryptoElliptic', () => {
|
||||
const subtleCryptoElliptic = new SubtleCryptoElliptic(new Subtle());
|
||||
expect(subtleCryptoElliptic.getSubtleCrypto().constructor.name).toEqual('SubtleCryptoElliptic');
|
||||
});
|
||||
|
||||
it('should test algorithmTransform', () => {
|
||||
let subtle = new SubtleCryptoElliptic(new Subtle());
|
||||
let alg: any = {test: 'name'};
|
||||
expect(subtle.algorithmTransform(alg)).toEqual(alg);
|
||||
alg = {foo: 'fighters'};
|
||||
expect(subtle.algorithmTransform(alg)).toEqual(alg);
|
||||
});
|
||||
it('should test keyImportTransform', () => {
|
||||
let subtle: any = new SubtleCryptoElliptic(new Subtle());
|
||||
let jwk: any = {test: 'name'};
|
||||
expect(subtle.keyImportTransform(jwk)).toEqual(jwk);
|
||||
jwk = {foo: 'fighters'};
|
||||
expect(subtle.keyImportTransform(jwk)).toEqual(jwk);
|
||||
});
|
||||
it('should test keyExportTransform', () => {
|
||||
let subtle: any = new SubtleCryptoElliptic(new Subtle());
|
||||
let jwk: any = {test: 'name'};
|
||||
expect(subtle.keyExportTransform(jwk)).toEqual(jwk);
|
||||
jwk = {foo: 'fighters'};
|
||||
expect(subtle.keyExportTransform(jwk)).toEqual(jwk);
|
||||
});
|
||||
});
|
|
@ -6,6 +6,7 @@
|
|||
import { SubtleCryptoElliptic, EllipticCurveKey } from '../src/index';
|
||||
import base64url from 'base64url';
|
||||
import { Subtle } from 'verifiablecredentials-crypto-sdk-typescript-plugin';
|
||||
import EllipticEdDsaProvider from '../src/EllipticEdDsaProvider';
|
||||
|
||||
|
||||
const algGenerate = {
|
||||
|
@ -289,4 +290,11 @@ describe('ed25519 - EdDSA', () => {
|
|||
});
|
||||
expect(throws).toEqual(true);
|
||||
});
|
||||
|
||||
it('should instantiate EllipticEdDsaProvider', () => {
|
||||
const ellipticEdDsaProvider = new EllipticEdDsaProvider(crypto);
|
||||
expect(ellipticEdDsaProvider.getCurve('ed25519')).toBeDefined();
|
||||
expect(() => ellipticEdDsaProvider.getCurve('SECP256K1')).toThrowError(`The requested curve 'SECP256K1' is not supported in EllipticEcDsaProvider`);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
import SubtleCryptoElliptic from '../src/SubtleCryptoElliptic';
|
||||
import EllipticCurveKey from '../src/EllipticCurveKey';
|
||||
import { Subtle } from 'verifiablecredentials-crypto-sdk-typescript-plugin';
|
||||
import EllipticEcDsaProvider from '../src/EllipticEcDsaProvider';
|
||||
// tslint:disable:mocha-no-side-effect-code
|
||||
const EC = require('elliptic').ec;
|
||||
|
||||
|
@ -124,4 +125,45 @@ describe('secp256k1 - ECDSA', () => {
|
|||
});
|
||||
expect(throws).toEqual(true);
|
||||
});
|
||||
|
||||
it('should instantiate EllipticEcDsaProvider', () => {
|
||||
const ellipticEcDsaProvider = new EllipticEcDsaProvider(crypto);
|
||||
expect(ellipticEcDsaProvider.getCurve('SECP256K1')).toBeDefined();
|
||||
expect(() => ellipticEcDsaProvider.getCurve('EdDSA')).toThrowError(`The requested curve 'EdDSA' is not supported in EllipticEcDsaProvider`);
|
||||
});
|
||||
|
||||
it('should generate key in EllipticEcDsaProvider', async () => {
|
||||
const ellipticEcDsaProvider = new EllipticEcDsaProvider(crypto);
|
||||
const ec = ellipticEcDsaProvider.getCurve('SECP256K1');
|
||||
const keyPair = ec.genKeyPair();
|
||||
const genKeyPairSpy: jasmine.Spy = spyOn(ec, 'genKeyPair').and.callFake(() => {
|
||||
delete keyPair.pub;
|
||||
return keyPair;
|
||||
});
|
||||
const algGenerate = {
|
||||
name: 'ECDSA',
|
||||
namedCurve: 'secp256k1'
|
||||
};
|
||||
expect((<CryptoKeyPair>await ellipticEcDsaProvider.generateKey(algGenerate, true, ['sign'])).privateKey).toBeDefined();
|
||||
|
||||
genKeyPairSpy.and.callFake(() => {
|
||||
keyPair.pub = keyPair.getPublic();
|
||||
return keyPair;
|
||||
});
|
||||
expect((<CryptoKeyPair>await ellipticEcDsaProvider.generateKey(algGenerate, true, ['sign'])).privateKey).toBeDefined();
|
||||
});
|
||||
|
||||
it('should sign/verify in EllipticEcDsaProvider', async () => {
|
||||
const ellipticEcDsaProvider = new EllipticEcDsaProvider(crypto);
|
||||
let algGenerate: any = {
|
||||
name: 'ECDSA',
|
||||
namedCurve: 'secp256k1',
|
||||
hash: undefined
|
||||
};
|
||||
const keyPair = (<CryptoKeyPair>await ellipticEcDsaProvider.generateKey(algGenerate, true, ['sign', 'verify']));
|
||||
let signature = await ellipticEcDsaProvider.sign(algGenerate, keyPair.privateKey, new Uint8Array([1, 2, 3]));
|
||||
expect(signature).toBeDefined();
|
||||
expect(await ellipticEcDsaProvider.verify(algGenerate, keyPair.publicKey, signature, new Uint8Array([1, 2, 3])));
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "verifiablecredentials-crypto-sdk-typescript-plugin-factory",
|
||||
"description": "Factory Package for crypto plugins.",
|
||||
"version": "1.1.12-preview.0",
|
||||
"version": "1.1.12-preview.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/VerifiableCredentials-Crypto-SDK-Typescript.git"
|
||||
|
@ -39,10 +39,10 @@
|
|||
"dependencies": {
|
||||
"@azure/identity": "1.0.0",
|
||||
"lru-cache": "6.0.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-cryptofactory-suites": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-keyvault": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-cryptofactory-suites": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-keyvault": "1.1.12-preview.1",
|
||||
"@types/node": "14.6.2",
|
||||
"webcrypto-core": "1.1.8"
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "verifiablecredentials-crypto-sdk-typescript-plugin-keyvault",
|
||||
"version": "1.1.12-preview.0",
|
||||
"version": "1.1.12-preview.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/VerifiableCredentials-Crypto-SDK-Typescript.git"
|
||||
|
@ -50,10 +50,10 @@
|
|||
"@azure/keyvault-keys": "4.0.2",
|
||||
"@azure/keyvault-secrets": "4.0.2",
|
||||
"lru-cache": "6.0.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-elliptic": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-elliptic": "1.1.12-preview.1",
|
||||
"base64url": "3.0.1",
|
||||
"clone": "2.1.2",
|
||||
"webcrypto-core": "1.1.8"
|
||||
|
|
|
@ -135,7 +135,7 @@ export default class KeyStoreKeyVault implements IKeyStore {
|
|||
keyContainerItem = options.publicKeyOnly ?
|
||||
new RsaPublicKey(version.key ? version.key : version.value as any) : new RsaPrivateKey(version.key ? version.key : version.value as any);
|
||||
} else {
|
||||
throw new Error(`Non supported key type ${kty}`);
|
||||
return Promise.reject(new Error(`Non supported key type ${kty}`));
|
||||
}
|
||||
} else {
|
||||
if (kty === 'EC') {
|
||||
|
@ -159,15 +159,14 @@ export default class KeyStoreKeyVault implements IKeyStore {
|
|||
}
|
||||
|
||||
if (!container) {
|
||||
throw new Error(`The secret with reference '${keyName}' has not usable secrets`);
|
||||
return Promise.reject(new Error(`The secret with reference '${keyName}' has not usable secrets`));
|
||||
}
|
||||
|
||||
return container;
|
||||
} catch (e) {
|
||||
console.error(`Could not retrieve ${JSON.stringify(keyReference)}. Error: ${e}`);
|
||||
throw e;
|
||||
return Promise.reject(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,7 +178,7 @@ export default class KeyStoreKeyVault implements IKeyStore {
|
|||
*/
|
||||
async save(keyReference: KeyReference, key: CryptographicKey | string, options: KeyStoreOptions = new KeyStoreOptions()): Promise<void> {
|
||||
if (!keyReference || !keyReference.keyReference) {
|
||||
throw new Error(`Key reference needs to be specified`);
|
||||
return Promise.reject(new Error(`Key reference needs to be specified`));
|
||||
}
|
||||
const keyName = keyReference.remoteKeyReference || keyReference.keyReference;
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ export default class KeyVaultEcdsaProvider extends KeyVaultProvider {
|
|||
|
||||
const kid = (<any>key.algorithm).kid;
|
||||
if (!kid) {
|
||||
throw new CryptoError(algorithm, 'Missing kid in algortihm');
|
||||
return Promise.reject(new CryptoError(algorithm, 'Missing kid in algortihm'));
|
||||
}
|
||||
|
||||
const client = (<KeyStoreKeyVault>this.keyStore).getCryptoClient(kid);
|
||||
|
@ -65,7 +65,7 @@ export default class KeyVaultEcdsaProvider extends KeyVaultProvider {
|
|||
// Added for legacy. Used by keys generated with crv: SECP256K1
|
||||
signature = await client.sign(<any>'ECDSA256', new Uint8Array(hash));
|
||||
} else {
|
||||
throw exception;
|
||||
return Promise.reject(exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,28 +85,28 @@ export default class KeyVaultEcdsaProvider extends KeyVaultProvider {
|
|||
jwk: JsonWebKey, _algorithm: EcKeyImportParams, _extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
|
||||
if (format !== 'jwk') {
|
||||
throw new Error(`Import key only supports jwk`);
|
||||
return Promise.reject(new Error(`Import key only supports jwk`));
|
||||
}
|
||||
|
||||
if (jwk.kty?.toUpperCase() !== 'EC') {
|
||||
throw new Error(`Import key only supports kty EC`);
|
||||
return Promise.reject(new Error(`Import key only supports kty EC`));
|
||||
}
|
||||
|
||||
if (jwk.crv?.toUpperCase() === 'SECP256K1') {
|
||||
jwk.crv = 'P-256K';
|
||||
} else if (jwk.crv?.toUpperCase() !== 'P-256K') {
|
||||
throw new Error(`Import key only supports crv P-256K`);
|
||||
return Promise.reject(new Error(`Import key only supports crv P-256K`));
|
||||
}
|
||||
|
||||
if (!jwk.kid && jwk.kid!.startsWith('https://')) {
|
||||
throw new Error(`Imported key must have a kid in the format https://<vault>/keys/<name>/<version>`);
|
||||
if (!(jwk.kid && jwk.kid.startsWith('https://'))) {
|
||||
return Promise.reject(new Error(`Imported key must have a kid in the format https://<vault>/keys/<name>/<version>`));
|
||||
}
|
||||
|
||||
const kidParts = jwk.kid!.split('/');
|
||||
let secretType: boolean = kidParts[3] === 'secrets';
|
||||
|
||||
if (!['keys', 'secrets'].includes(kidParts[3])) {
|
||||
throw new Error(`Imported key must be of type keys or secrets`);
|
||||
if (!(kidParts.length >= 5 && ['keys', 'secrets'].includes(kidParts[3]))) {
|
||||
return Promise.reject(new Error(`Imported key must be of type keys or secrets`));
|
||||
}
|
||||
|
||||
if (kidParts.length <= 5) {
|
||||
|
@ -189,8 +189,13 @@ export default class KeyVaultEcdsaProvider extends KeyVaultProvider {
|
|||
*/
|
||||
async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey> {
|
||||
if (format !== 'jwk') {
|
||||
throw new Error(`Export key only supports jwk`);
|
||||
return Promise.reject(new Error(`Export key only supports jwk`));
|
||||
}
|
||||
return <Promise<JsonWebKey>>this.subtle.exportKey(format, key);
|
||||
|
||||
const jwk: any = await this.subtle.exportKey(format, key);
|
||||
if (!jwk.kid) {
|
||||
jwk.kid = (<any>key.algorithm).kid;
|
||||
}
|
||||
return <Promise<JsonWebKey>>jwk;
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ export default class KeyVaultRsaOaepProvider extends KeyVaultProvider {
|
|||
async onDecrypt (algorithm: Algorithm, key: CryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
const kid = (<any>key.algorithm).kid;
|
||||
if (!kid) {
|
||||
throw new CryptoError(algorithm, 'Missing kid in algortihm');
|
||||
return Promise.reject(new CryptoError(algorithm, 'Missing kid in algortihm'));
|
||||
}
|
||||
|
||||
const client = (<KeyStoreKeyVault>this.keyStore).getCryptoClient(kid);
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { ClientSecretCredential } from '@azure/identity';
|
||||
import { KeyReference, KeyStoreInMemory } from 'verifiablecredentials-crypto-sdk-typescript-keystore';
|
||||
import { CryptoFactoryScope, Subtle } from 'verifiablecredentials-crypto-sdk-typescript-plugin';
|
||||
import { CryptoFactoryKeyVault, KeyStoreKeyVault } from '../src';
|
||||
|
||||
describe('CryptoFactoryKeyVault', () => {
|
||||
it('should create a CryptoFactoryKeyVault', () => {
|
||||
const cache = new KeyStoreInMemory();
|
||||
const credential = new ClientSecretCredential('tenant', 'clientid', 'secret');
|
||||
const keyStore = new KeyStoreKeyVault(credential, 'https://example.vault.com', cache);
|
||||
const subtle = new Subtle();
|
||||
|
||||
const crypto = new CryptoFactoryKeyVault(keyStore, subtle);
|
||||
expect(crypto.getMessageSigner('ES256K', CryptoFactoryScope.Private, new KeyReference('key', 'key')).constructor.name).toEqual('SubtleCryptoKeyVault');
|
||||
expect(crypto.getMessageSigner('ECDSA', CryptoFactoryScope.Private, new KeyReference('key', 'key')).constructor.name).toEqual('SubtleCryptoKeyVault');
|
||||
expect(crypto.getKeyEncrypter('RSA-OAEP-256', CryptoFactoryScope.Private, new KeyReference('key', 'key')).constructor.name).toEqual('SubtleCryptoKeyVault');
|
||||
expect(crypto.getKeyEncrypter('RSA-OAEP', CryptoFactoryScope.Private, new KeyReference('key', 'key')).constructor.name).toEqual('SubtleCryptoKeyVault');
|
||||
expect(crypto.getMessageSigner('RSASSA-PKCS1-v1_5', CryptoFactoryScope.Private, new KeyReference('key', 'key')).constructor.name).toEqual('Subtle');
|
||||
})
|
||||
});
|
|
@ -12,6 +12,8 @@ import { KeyClient } from '@azure/keyvault-keys';
|
|||
import { SecretClient } from '@azure/keyvault-secrets';
|
||||
import { CryptoKey } from 'webcrypto-core';
|
||||
import Credentials from './Credentials';
|
||||
import base64url from 'base64url';
|
||||
const clone = require('clone');
|
||||
|
||||
// Sample config
|
||||
const tenantId = Credentials.tenantGuid;
|
||||
|
@ -44,10 +46,22 @@ afterEach(() => {
|
|||
describe('KeyStoreKeyVault', () => {
|
||||
const alg = { name: 'ECDSA', namedCurve: 'SECP256K1', hash: { name: 'SHA-256' } };
|
||||
if (!keyVaultEnable) {
|
||||
console.log('Key vault is enabled. Add your credentials to Credentials.ts')
|
||||
console.log('Key vault is not enabled. Add your credentials to Credentials.ts')
|
||||
return;
|
||||
}
|
||||
|
||||
it('should create an instance', () => {
|
||||
const cache = new KeyStoreInMemory();
|
||||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
let vault = 'https://example.keyvault.com';
|
||||
let keyStore = new KeyStoreKeyVault(credential, vault, cache);
|
||||
expect(keyStore.cache).toEqual(cache);
|
||||
expect((<any>keyStore).vaultUri).toEqual(vault + '/');
|
||||
keyStore = new KeyStoreKeyVault(credential, vault + '/', cache);
|
||||
expect(keyStore.cache).toEqual(cache);
|
||||
expect((<any>keyStore).vaultUri).toEqual(vault + '/');
|
||||
});
|
||||
|
||||
it('should list a named generated key', async () => {
|
||||
const name = 'KvTest-KeyStoreKeyVault' + Math.random().toString(10).substr(2);
|
||||
const cache = new KeyStoreInMemory();
|
||||
|
@ -58,7 +72,9 @@ describe('KeyStoreKeyVault', () => {
|
|||
await provider.onGenerateKey(alg, false, ['sign'], { keyReference: new KeyReference(name) });
|
||||
let list = await keyStore.list('key', new KeyStoreOptions({ latestVersion: false }));
|
||||
expect(list[name]).toBeDefined();
|
||||
const key = await keyStore.get(new KeyReference(name, 'key'), new KeyStoreOptions({ latestVersion: false }));
|
||||
// Two requests should hit cache
|
||||
let key = await keyStore.get(new KeyReference(name, 'key'), new KeyStoreOptions({ latestVersion: false }));
|
||||
key = await keyStore.get(new KeyReference(name, 'key'), new KeyStoreOptions({ latestVersion: false }));
|
||||
expect(key).toBeDefined();
|
||||
expect((await cache.list())[name]).toBeDefined();
|
||||
} finally {
|
||||
|
@ -66,6 +82,93 @@ describe('KeyStoreKeyVault', () => {
|
|||
}
|
||||
});
|
||||
|
||||
it('should list a named stored secret k', async () => {
|
||||
const name = 'KvTest-KeyStoreKeyVault' + Math.random().toString(10).substr(2);
|
||||
const cache = new KeyStoreInMemory();
|
||||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
try {
|
||||
const secret1 = base64url.encode(name);
|
||||
const secret2 = base64url.encode(name + '2');
|
||||
|
||||
//save two versions
|
||||
await keyStore.save(new KeyReference(name), secret1);
|
||||
await keyStore.save(new KeyReference(name), secret2);
|
||||
|
||||
let list = await keyStore.list('secret', new KeyStoreOptions({ latestVersion: false }));
|
||||
expect(list[name]).toBeDefined();
|
||||
|
||||
// get latest version only
|
||||
let key = await keyStore.get(new KeyReference(name, 'secret'), new KeyStoreOptions({ latestVersion: true }));
|
||||
expect(key.keys.length).toEqual(1);
|
||||
//TODO BUG. k is reported as object
|
||||
expect((await cache.list())[name]).toBeDefined();
|
||||
|
||||
// get all versions
|
||||
key = await keyStore.get(new KeyReference(name, 'secret'), new KeyStoreOptions({ latestVersion: false }));
|
||||
expect(key.keys.length).toEqual(2);
|
||||
} finally {
|
||||
await (<SecretClient>keyStore.getKeyStoreClient('secret')).beginDeleteSecret(name);
|
||||
}
|
||||
});
|
||||
it('should list a named stored secret with EC', async () => {
|
||||
let cleaned = false;
|
||||
const name = 'KvTest-KeyStoreKeyVault' + Math.random().toString(10).substr(2);
|
||||
const cache = new KeyStoreInMemory();
|
||||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
const subtle = new Subtle();
|
||||
try {
|
||||
|
||||
const keyPair = <CryptoKeyPair>await subtle.generateKey(<EcKeyGenParams>{ name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' } }, true, ["sign", "verify"]);
|
||||
const jwk: any = await subtle.exportKey('jwk', keyPair.privateKey);
|
||||
|
||||
//save two versions
|
||||
await keyStore.save(new KeyReference(name), jwk);
|
||||
|
||||
// save okp version
|
||||
let okp = clone(jwk);
|
||||
okp.kty = 'OKP';
|
||||
await keyStore.save(new KeyReference(name), jwk);
|
||||
|
||||
let list = await keyStore.list('secret', new KeyStoreOptions({ latestVersion: false }));
|
||||
expect(list[name]).toBeDefined();
|
||||
|
||||
// get latest version only, second should
|
||||
let key = await keyStore.get(new KeyReference(name, 'secret'), new KeyStoreOptions({ latestVersion: true }));
|
||||
key = await keyStore.get(new KeyReference(name, 'secret'), new KeyStoreOptions({ latestVersion: true }));
|
||||
expect(key.keys.length).toEqual(1);
|
||||
//TODO BUG. k is reported as object
|
||||
expect((await cache.list())[name]).toBeDefined();
|
||||
|
||||
// get all versions
|
||||
key = await keyStore.get(new KeyReference(name, 'secret'), new KeyStoreOptions({ latestVersion: false }));
|
||||
expect(key.keys.length).toEqual(2);
|
||||
|
||||
// get public key only
|
||||
key = await keyStore.get(new KeyReference(name, 'secret'), new KeyStoreOptions({ publicKeyOnly: true }));
|
||||
expect(key.keys.length).toEqual(1);
|
||||
|
||||
// negative cases
|
||||
cleaned = true;
|
||||
await (<SecretClient>keyStore.getKeyStoreClient('secret')).beginDeleteSecret(name);
|
||||
const getKeyStoreClientSpy: jasmine.Spy = spyOn(keyStore, 'getKeyStoreClient').and.callFake(() => {
|
||||
throw new Error('some error');
|
||||
});
|
||||
try {
|
||||
await keyStore.get(new KeyReference(name, 'secret'), new KeyStoreOptions({ latestVersion: true }));
|
||||
fail('get should have thrown');
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual('some error');
|
||||
|
||||
}
|
||||
} finally {
|
||||
if (!cleaned) {
|
||||
await (<SecretClient>keyStore.getKeyStoreClient('secret')).beginDeleteSecret(name);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should list a specific version of the key', async () => {
|
||||
const name = 'KvTest-KeyStoreKeyVault' + Math.random().toString(10).substr(2);
|
||||
const cache = new KeyStoreInMemory();
|
||||
|
@ -78,11 +181,11 @@ describe('KeyStoreKeyVault', () => {
|
|||
await provider.onGenerateKey(alg, false, ['sign'], { keyReference: new KeyReference(name) });
|
||||
|
||||
let parts = (<any>keyPair.publicKey.algorithm).kid.split('/');
|
||||
const keyName = `${parts[parts.length-2]}/${parts[parts.length-1]}`;
|
||||
const keyName = `${parts[parts.length - 2]}/${parts[parts.length - 1]}`;
|
||||
|
||||
let list = await keyStore.list('key', new KeyStoreOptions({ latestVersion: false }));
|
||||
expect(list[name].kids[0].includes(keyName) || list[name].kids[1].includes(keyName)).toBeTruthy();
|
||||
const key = await keyStore.get(new KeyReference(name, 'key',keyName), new KeyStoreOptions({ latestVersion: false }));
|
||||
const key = await keyStore.get(new KeyReference(name, 'key', keyName), new KeyStoreOptions({ latestVersion: false }));
|
||||
expect(key.keys.length).toEqual(1);
|
||||
console.log(`name: ${keyName}`);
|
||||
console.log(`${JSON.stringify(key.keys[0])}`);
|
||||
|
@ -114,17 +217,20 @@ describe('KeyStoreKeyVault', () => {
|
|||
const cache = new KeyStoreInMemory();
|
||||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
let throwed = false;
|
||||
await keyStore.save(new KeyReference(name, 'secret'), 'abcdefg');
|
||||
let list = await keyStore.list('secret', new KeyStoreOptions({ latestVersion: false }));
|
||||
expect(list[name]).toBeDefined();
|
||||
try {
|
||||
await keyStore.save(new KeyReference(name, 'secret'), 'abcdefg');
|
||||
let list = await keyStore.list('secret', new KeyStoreOptions({ latestVersion: false }));
|
||||
expect(list[name]).toBeDefined();
|
||||
await cache.get(new KeyReference(name, 'secret'));
|
||||
expect(throwed).toBeTruthy();
|
||||
fail('Should have thrown during get: should set a secret');
|
||||
} catch (err) {
|
||||
throwed = true;
|
||||
expect(err.message).toEqual(`${name} not found`)
|
||||
|
||||
}
|
||||
try {
|
||||
await keyStore.save(<any>undefined, '');
|
||||
fail('Should have thrown during save: should set a secret');
|
||||
} catch (err) {
|
||||
expect(err.message).toEqual(`Key reference needs to be specified`)
|
||||
} finally {
|
||||
await (<SecretClient>keyStore.getKeyStoreClient('secret')).beginDeleteSecret(name);
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ import KeyVaultEcdsaProvider from '../src/plugin/KeyVaultEcdsaProvider';
|
|||
import KeyVaultRsaOaepProvider from '../src/plugin/KeyVaultRsaOaepProvider';
|
||||
import { KeyStoreOptions, KeyStoreInMemory, KeyReference } from 'verifiablecredentials-crypto-sdk-typescript-keystore';
|
||||
import { KeyClient } from '@azure/keyvault-keys';
|
||||
import { Subtle, CryptoFactoryScope, IKeyGenerationOptions } from 'verifiablecredentials-crypto-sdk-typescript-plugin';
|
||||
import { Subtle, IKeyGenerationOptions } from 'verifiablecredentials-crypto-sdk-typescript-plugin';
|
||||
import Credentials from './Credentials';
|
||||
import { KeyVaultProvider, CryptoFactoryKeyVault, SubtleCryptoKeyVault } from '../src';
|
||||
import { KeyVaultProvider, SubtleCryptoKeyVault } from '../src';
|
||||
const clone = require('clone');
|
||||
|
||||
// Sample config
|
||||
|
@ -20,7 +20,7 @@ const clientSecret = encodeURI(Credentials.clientSecret);
|
|||
const vaultUri = Credentials.vaultUri;
|
||||
const keyVaultEnable = vaultUri.startsWith('https://');
|
||||
|
||||
const subtle = new Subtle();
|
||||
const subtleCrypto = new Subtle();
|
||||
const random = (length: number) => Math.random().toString(36).substring(2, length + 2);
|
||||
const logging = require('adal-node').Logging;
|
||||
logging.setLoggingOptions({
|
||||
|
@ -43,7 +43,7 @@ afterEach(() => {
|
|||
|
||||
describe('KeyVaultPlugin', () => {
|
||||
if (!keyVaultEnable) {
|
||||
console.log('Key vault is enabled. Add your credentials to Credentials.ts')
|
||||
console.log('Key vault is not enabled. Add your credentials to Credentials.ts')
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -53,13 +53,25 @@ describe('KeyVaultPlugin', () => {
|
|||
const cache = new KeyStoreInMemory();
|
||||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
const plugin = new KeyVaultEcdsaProvider(subtle, keyStore);
|
||||
const plugin = new KeyVaultEcdsaProvider(subtleCrypto, keyStore);
|
||||
try {
|
||||
const result: CryptoKeyPair = await plugin.onGenerateKey(alg, false, ['sign']);
|
||||
expect((<any>result.publicKey).algorithm.namedCurve).toEqual('K-256');
|
||||
expect(result.publicKey.algorithm.name).toEqual('ECDSA');
|
||||
expect((<any>result.publicKey.algorithm).kid.startsWith('https')).toBeTruthy();
|
||||
expect((<any>result.publicKey.algorithm).kid.includes(name)).toBeTruthy();
|
||||
const keypair: CryptoKeyPair = await plugin.onGenerateKey(alg, false, ['sign']);
|
||||
expect((<any>keypair.publicKey).algorithm.namedCurve).toEqual('K-256');
|
||||
expect(keypair.publicKey.algorithm.name).toEqual('ECDSA');
|
||||
expect((<any>keypair.publicKey.algorithm).kid.startsWith('https')).toBeTruthy();
|
||||
expect((<any>keypair.publicKey.algorithm).kid.includes(name)).toBeTruthy();
|
||||
|
||||
const jwk: any = await plugin.exportKey('jwk', keypair.publicKey);
|
||||
expect(jwk.kid.startsWith('https://')).toBeTruthy();
|
||||
|
||||
// negative cases
|
||||
try {
|
||||
await plugin.exportKey('raw', keypair.publicKey);
|
||||
fail('export key raw should fail');
|
||||
} catch(exception) {
|
||||
expect(exception.message).toEqual('Export key only supports jwk');
|
||||
}
|
||||
|
||||
} finally {
|
||||
await (<KeyClient>keyStore.getKeyStoreClient('key')).beginDeleteKey(name);
|
||||
}
|
||||
|
@ -70,7 +82,7 @@ describe('KeyVaultPlugin', () => {
|
|||
const cache = new KeyStoreInMemory();
|
||||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
const plugin = new KeyVaultEcdsaProvider(subtle, keyStore);
|
||||
const plugin = new KeyVaultEcdsaProvider(subtleCrypto, keyStore);
|
||||
try {
|
||||
let keyReference = new KeyReference(name, 'key');
|
||||
let curve = 'P-256K';
|
||||
|
@ -91,7 +103,7 @@ describe('KeyVaultPlugin', () => {
|
|||
const cache = new KeyStoreInMemory();
|
||||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
const plugin = new KeyVaultEcdsaProvider(subtle, keyStore);
|
||||
const plugin = new KeyVaultEcdsaProvider(subtleCrypto, keyStore);
|
||||
try {
|
||||
|
||||
let keyReference = new KeyReference(name, 'key', remoteName);
|
||||
|
@ -113,19 +125,42 @@ describe('KeyVaultPlugin', () => {
|
|||
const cache = new KeyStoreInMemory();
|
||||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
const subtle = new SubtleCryptoKeyVault(new Subtle(), keyStore);
|
||||
const subtleKv = new SubtleCryptoKeyVault(new Subtle(), keyStore);
|
||||
try {
|
||||
|
||||
const keyReference = new KeyReference(name, 'key', remoteName);
|
||||
const curve = 'P-256K';
|
||||
const alg = { name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' } };
|
||||
const keypair = await subtle.generateKey(alg, false, ['sign', 'verify'], { keyReference, curve });
|
||||
const keypair = await subtleKv.generateKey(alg, false, ['sign', 'verify'], { keyReference, curve });
|
||||
const payload = Buffer.from('hello Houston');
|
||||
const signature = await subtle.sign(alg, keypair.publicKey, payload);
|
||||
const signature = await subtleKv.sign(alg, keypair.publicKey, payload);
|
||||
expect(signature.byteLength).toEqual(64);
|
||||
|
||||
const jwk = await subtle.exportKey('jwk', keypair.publicKey);
|
||||
const jwk = await subtleKv.exportKey('jwk', keypair.publicKey);
|
||||
expect(jwk.kty).toEqual('EC');
|
||||
|
||||
// negative cases
|
||||
let publicKey = clone(keypair.publicKey);
|
||||
delete (<any>publicKey.algorithm).kid;
|
||||
try {
|
||||
await subtleKv.sign(alg, publicKey, payload);
|
||||
fail('sign should throw');
|
||||
} catch(exception) {
|
||||
expect(exception.message).toEqual('Missing kid in algortihm');
|
||||
}
|
||||
|
||||
let getCryptoClientSpy: jasmine.Spy = spyOn(keyStore, 'getCryptoClient').and.callFake(() => {
|
||||
return {
|
||||
sign: () => Promise.reject(new Error('spy signing error'))
|
||||
};
|
||||
});
|
||||
try {
|
||||
await subtleKv.sign(alg, keypair.publicKey, payload);
|
||||
fail('sign should throw');
|
||||
} catch(exception) {
|
||||
expect(exception.message).toEqual('spy signing error');
|
||||
}
|
||||
|
||||
} finally {
|
||||
await (<KeyClient>keyStore.getKeyStoreClient('key')).beginDeleteKey(remoteName);
|
||||
}
|
||||
|
@ -139,7 +174,7 @@ describe('KeyVaultPlugin', () => {
|
|||
try {
|
||||
let list = await keyStore.list('key', new KeyStoreOptions({ latestVersion: false }));
|
||||
const versions = list[name];
|
||||
const plugin = new KeyVaultEcdsaProvider(subtle, keyStore);
|
||||
const plugin = new KeyVaultEcdsaProvider(subtleCrypto, keyStore);
|
||||
|
||||
// Generate EC
|
||||
let keyPair: CryptoKeyPair = await plugin.onGenerateKey(alg, false, ['sign', 'verify']);
|
||||
|
@ -183,7 +218,7 @@ describe('KeyVaultPlugin', () => {
|
|||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
try {
|
||||
const plugin = new KeyVaultEcdsaProvider(subtle, keyStore);
|
||||
const plugin = new KeyVaultEcdsaProvider(subtleCrypto, keyStore);
|
||||
|
||||
const payload = Buffer.from('test');
|
||||
console.log(payload);
|
||||
|
@ -198,8 +233,8 @@ describe('KeyVaultPlugin', () => {
|
|||
const webCryptoAlg = clone(alg);
|
||||
webCryptoAlg.namedCurve = 'K-256';
|
||||
const jwk = await (await cache.get(new KeyReference(name, 'key'), keyPair.publicKey)).getKey<JsonWebKey>();
|
||||
const cryptoKey = await subtle.importKey('jwk', jwk, webCryptoAlg, true, ['verify']);
|
||||
const result = await subtle.verify(webCryptoAlg, cryptoKey, Buffer.from(signature), payload);
|
||||
const cryptoKey = await subtleCrypto.importKey('jwk', jwk, webCryptoAlg, true, ['verify']);
|
||||
const result = await subtleCrypto.verify(webCryptoAlg, cryptoKey, Buffer.from(signature), payload);
|
||||
expect(result).toBeTruthy();
|
||||
expect((await cache.list())[name]).toBeDefined();
|
||||
} finally {
|
||||
|
@ -215,15 +250,15 @@ describe('KeyVaultPlugin', () => {
|
|||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
try {
|
||||
const plugin = new KeyVaultEcdsaProvider(subtle, keyStore);
|
||||
const plugin = new KeyVaultEcdsaProvider(subtleCrypto, keyStore);
|
||||
|
||||
const payload = Buffer.from('test');
|
||||
console.log(payload);
|
||||
|
||||
// import reference key
|
||||
const keyReference = new KeyReference(name, 'key');
|
||||
let cryptoKey: any = <CryptoKey>await subtle.generateKey(alg, true, ['sign'], { keyReference });
|
||||
let jwk: any = await subtle.exportKey('jwk', cryptoKey.privateKey);
|
||||
let cryptoKey: any = <CryptoKey>await subtleCrypto.generateKey(alg, true, ['sign'], { keyReference });
|
||||
let jwk: any = await subtleCrypto.exportKey('jwk', cryptoKey.privateKey);
|
||||
jwk.kid = name;
|
||||
|
||||
await keyStore.save(keyReference, jwk, new KeyStoreOptions());
|
||||
|
@ -231,17 +266,65 @@ describe('KeyVaultPlugin', () => {
|
|||
|
||||
const cachedPublic = await (await cache.get(keyReference)).getKey<JsonWebKey>();
|
||||
|
||||
cryptoKey = await plugin.importKey('jwk', cachedPublic, alg, false, ['sign', 'verify']);
|
||||
const signature = await plugin.onSign(alg, cryptoKey, payload);
|
||||
cryptoKey = await plugin.importKey('jwk', cachedPublic, alg, false, ['sign']);
|
||||
const signature = await plugin.sign(alg, cryptoKey, payload);
|
||||
|
||||
// Set verify key
|
||||
const webCryptoAlg = clone(alg);
|
||||
webCryptoAlg.namedCurve = 'K-256';
|
||||
jwk = (await cache.get(new KeyReference(name, 'key'), new KeyStoreOptions({ publicKeyOnly: true }))).getKey<JsonWebKey>();
|
||||
cryptoKey = await subtle.importKey('jwk', jwk, webCryptoAlg, true, ['verify']);
|
||||
const result = await subtle.verify(webCryptoAlg, cryptoKey, signature, payload);
|
||||
cryptoKey = await subtleCrypto.importKey('jwk', jwk, webCryptoAlg, true, ['verify']);
|
||||
const result = await subtleCrypto.verify(webCryptoAlg, cryptoKey, signature, payload);
|
||||
expect(result).toBeTruthy();
|
||||
expect((await cache.list())[name]).toBeDefined();
|
||||
|
||||
// negative cases
|
||||
try {
|
||||
await plugin.importKey('raw', new Uint8Array([1,2,3,4]), webCryptoAlg, true, ['sign']);
|
||||
fail('import raw should fail');
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual('Import key only supports jwk');
|
||||
}
|
||||
let clonedJwk = clone(jwk);
|
||||
clonedJwk.kty = 'RSA'
|
||||
try {
|
||||
await plugin.importKey('jwk', clonedJwk, webCryptoAlg, true, ['sign']);
|
||||
fail('import RSA should fail');
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual('Import key only supports kty EC');
|
||||
}
|
||||
clonedJwk = clone(jwk);
|
||||
clonedJwk.crv = 'ed25519';
|
||||
try {
|
||||
await plugin.importKey('jwk', clonedJwk, webCryptoAlg, true, ['sign']);
|
||||
fail('import crv should fail');
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual('Import key only supports crv P-256K');
|
||||
}
|
||||
clonedJwk = clone(jwk);
|
||||
delete clonedJwk.kid;
|
||||
try {
|
||||
await plugin.importKey('jwk', clonedJwk, webCryptoAlg, true, ['sign']);
|
||||
fail('import crv should fail');
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual('Imported key must have a kid in the format https://<vault>/keys/<name>/<version>');
|
||||
}
|
||||
clonedJwk = clone(jwk);
|
||||
clonedJwk.kid = 'vaultUri';
|
||||
try {
|
||||
await plugin.importKey('jwk', clonedJwk, webCryptoAlg, true, ['sign']);
|
||||
fail('import crv should fail');
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual('Imported key must have a kid in the format https://<vault>/keys/<name>/<version>');
|
||||
}
|
||||
clonedJwk = clone(jwk);
|
||||
clonedJwk.kid = 'https://vault.com';
|
||||
try {
|
||||
await plugin.importKey('jwk', clonedJwk, webCryptoAlg, true, ['sign']);
|
||||
fail('import crv should fail');
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual('Imported key must be of type keys or secrets');
|
||||
}
|
||||
} finally {
|
||||
await (<KeyClient>keyStore.getKeyStoreClient('key')).beginDeleteKey(name);
|
||||
}
|
||||
|
@ -266,7 +349,7 @@ describe('KeyVaultPlugin', () => {
|
|||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
try {
|
||||
const plugin = new KeyVaultEcdsaProvider(subtle, keyStore);
|
||||
const plugin = new KeyVaultEcdsaProvider(subtleCrypto, keyStore);
|
||||
|
||||
// Generate EC
|
||||
let keyReference = new KeyReference(name, 'key');
|
||||
|
@ -303,19 +386,31 @@ describe('rsa-oaep', () => {
|
|||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
try {
|
||||
const plugin = new KeyVaultRsaOaepProvider(subtle, keyStore);
|
||||
const plugin = new KeyVaultRsaOaepProvider(subtleCrypto, keyStore);
|
||||
const payload = Buffer.from('hello houston');
|
||||
|
||||
// generate key
|
||||
const keyPair: CryptoKeyPair = await plugin.onGenerateKey(alg, false, ['decrypt', 'encrypt']);
|
||||
|
||||
// Encrypt with subtle
|
||||
const cipher = await subtle.encrypt(alg, keyPair.publicKey, payload);
|
||||
const cipher = await subtleCrypto.encrypt(alg, keyPair.publicKey, payload);
|
||||
|
||||
// decrypt with key vault
|
||||
const decrypt = await plugin.onDecrypt(alg, keyPair.publicKey, cipher);
|
||||
expect(Buffer.from(decrypt)).toEqual(payload);
|
||||
expect((await cache.list())[name]).toBeDefined();
|
||||
|
||||
// negative cases
|
||||
let clonedPk = clone(keyPair.publicKey);
|
||||
delete clonedPk.algorithm.kid;
|
||||
|
||||
try {
|
||||
await plugin.decrypt(alg, clonedPk, cipher);
|
||||
fail('decrypt RSA should fail');
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual('Missing kid in algortihm');
|
||||
}
|
||||
|
||||
} finally {
|
||||
await (<KeyClient>keyStore.getKeyStoreClient('key')).beginDeleteKey(name);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { KeyStoreInMemory } from 'verifiablecredentials-crypto-sdk-typescript-keystore';
|
||||
import { KeyStoreKeyVault, SubtleCryptoKeyVault } from '../src';
|
||||
import { ClientSecretCredential } from '@azure/identity';
|
||||
import { Subtle } from 'verifiablecredentials-crypto-sdk-typescript-plugin';
|
||||
import Credentials from './Credentials';
|
||||
|
||||
describe('SubtleCryptoKeyVault', () => {
|
||||
// Sample config
|
||||
const tenantId = Credentials.tenantGuid;
|
||||
const clientId = Credentials.clientId;
|
||||
const clientSecret = encodeURI(Credentials.clientSecret);
|
||||
const vaultUri = Credentials.vaultUri;
|
||||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
const keyVaultEnable = vaultUri.startsWith('https://');
|
||||
|
||||
const cache = new KeyStoreInMemory();
|
||||
const keyStore = new KeyStoreKeyVault(credential, vaultUri, cache);
|
||||
const subtle = new Subtle();
|
||||
const subtleKv: any = new SubtleCryptoKeyVault(subtle, keyStore);
|
||||
|
||||
if (!keyVaultEnable) {
|
||||
console.log('Key vault is not enabled. Add your credentials to Credentials.ts')
|
||||
return;
|
||||
}
|
||||
|
||||
const genKey = async () => {
|
||||
const cryptoKey = await subtleKv.generateKey(<EcKeyGenParams>{ name: "ECDSA", hash: { name: "SHA-256" }, namedCurve: 'secp256k1' }, true, ["sign", "verify"]);
|
||||
return cryptoKey;
|
||||
}
|
||||
|
||||
it('should create instance', () => {
|
||||
let subtleKv: any = new SubtleCryptoKeyVault(subtle, keyStore);
|
||||
expect(subtleKv.getSubtleCrypto().constructor.name).toEqual('SubtleCryptoKeyVault');
|
||||
});
|
||||
|
||||
it('should generate key', async () => {
|
||||
const cryptoKey = await genKey();
|
||||
expect(cryptoKey).toBeDefined();
|
||||
});
|
||||
|
||||
it('should test algorithmTransform', () => {
|
||||
let alg: any = {test: 'name'};
|
||||
expect(subtleKv.algorithmTransform(alg)).toEqual(alg);
|
||||
alg = {foo: 'fighters'};
|
||||
expect(subtleKv.algorithmTransform(alg)).toEqual(alg);
|
||||
});
|
||||
it('should test keyImportTransform', () => {
|
||||
let jwk: any = { test: 'name' };
|
||||
expect(subtleKv.keyImportTransform(jwk)).toEqual(jwk);
|
||||
jwk = { foo: 'fighters' };
|
||||
expect(subtleKv.keyImportTransform(jwk)).toEqual(jwk);
|
||||
jwk = { crv: 'P-256K' };
|
||||
expect(subtleKv.keyImportTransform(jwk)).toEqual({ crv: 'SECP256K1' });
|
||||
jwk = { crv: 'SECP256K1' };
|
||||
expect(subtleKv.keyImportTransform(jwk)).toEqual({ crv: 'SECP256K1' });
|
||||
jwk = { crv: 'XXX' };
|
||||
expect(subtleKv.keyImportTransform(jwk)).toEqual({ crv: 'XXX' });
|
||||
|
||||
});
|
||||
it('should test keyExportTransform', () => {
|
||||
let jwk: any = { test: 'name' };
|
||||
expect(subtleKv.keyExportTransform(jwk)).toEqual(jwk);
|
||||
jwk = { foo: 'fighters' };
|
||||
expect(subtleKv.keyExportTransform(jwk)).toEqual(jwk);
|
||||
jwk = { crv: 'P-256K' };
|
||||
expect(subtleKv.keyExportTransform(jwk)).toEqual({ crv: 'SECP256K1' });
|
||||
jwk = { crv: 'K-256' };
|
||||
expect(subtleKv.keyExportTransform(jwk)).toEqual({ crv: 'SECP256K1' });
|
||||
jwk = { crv: 'SECP256K1' };
|
||||
expect(subtleKv.keyExportTransform(jwk)).toEqual({ crv: 'SECP256K1' });
|
||||
});
|
||||
});
|
|
@ -36,9 +36,9 @@ export default class CryptoHelpers {
|
|||
case 'SHA-384':
|
||||
case 'SHA-512':
|
||||
return cryptoFactory.getMessageDigest(jwa, scope, keyReference);
|
||||
}
|
||||
|
||||
throw new Error(`Algorithm '${JSON.stringify(algorithm)}' is not supported`);
|
||||
default:
|
||||
throw new Error(`Algorithm '${JSON.stringify(algorithm)}' is not supported. Should be unreachable`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,7 +82,7 @@ export default class CryptoHelpers {
|
|||
return { name: 'HMAC', hash: { name: `SHA-${jwa.toUpperCase().replace('HS', '')}` } };
|
||||
}
|
||||
|
||||
throw new Error(`Algorithm ${JSON.stringify(jwa)} is not supported`);
|
||||
throw new Error(`Algorithm '${jwa}' is not supported`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,7 +91,7 @@ export default class CryptoHelpers {
|
|||
* @param hash Optional hash for the algorithm
|
||||
*/
|
||||
public static webCryptoToJwa(algorithm: any): string {
|
||||
const hash: string = algorithm.hash || algorithm.name || 'SHA-256';
|
||||
const hash: string = algorithm.hash || algorithm.name;
|
||||
switch (algorithm.name.toUpperCase()) {
|
||||
case 'RSASSA-PKCS1-V1_5':
|
||||
return `RS${CryptoHelpers.getHash(hash)}`;
|
||||
|
@ -105,7 +105,7 @@ export default class CryptoHelpers {
|
|||
return `RSA-OAEP-256`;
|
||||
case 'AES-GCM':
|
||||
const length = algorithm.length || 128;
|
||||
return `A${length}GCMKW`;
|
||||
return `A${length}GCM`;
|
||||
|
||||
case 'HMAC':
|
||||
return `HS256`;
|
||||
|
@ -124,7 +124,7 @@ export default class CryptoHelpers {
|
|||
* @param algorithm used for signature
|
||||
*/
|
||||
public static getKeyImportAlgorithm(algorithm: CryptoAlgorithm, jwk: PublicKey | JsonWebKey): string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams {
|
||||
const hash = (<any>algorithm).hash || (<any>algorithm).name || 'SHA-256';
|
||||
const hash = (<any>algorithm).hash || (<any>algorithm).name;
|
||||
const name = algorithm.name;
|
||||
switch (algorithm.name.toUpperCase()) {
|
||||
case 'RSASSA-PKCS1-V1_5':
|
||||
|
@ -151,7 +151,7 @@ export default class CryptoHelpers {
|
|||
if (hash.name) {
|
||||
return (hash.name).toUpperCase().replace('SHA-', '');
|
||||
}
|
||||
return (hash || 'SHA-256').toUpperCase().replace('SHA-', '');
|
||||
return '256';
|
||||
}
|
||||
|
||||
private static getRegexMatch(matches: RegExpExecArray, index: number): string {
|
||||
|
|
|
@ -46,7 +46,7 @@ const SUPPORTED_CURVES = ['K-256', 'P-256K', 'secp256k1', 'ed25519'];
|
|||
const pairwiseKeySeed = await crypto.sign(alg, key, Buffer.from(peerId));
|
||||
|
||||
if (SUPPORTED_CURVES.indexOf(algorithm.namedCurve) === -1) {
|
||||
throw new CryptoError(algorithm, `Curve ${algorithm.namedCurve} is not supported`);
|
||||
return Promise.reject(new CryptoError(algorithm, `Curve ${algorithm.namedCurve} is not supported`));
|
||||
}
|
||||
|
||||
let privateKey = new BN(Buffer.from(pairwiseKeySeed));
|
||||
|
|
|
@ -50,7 +50,7 @@ import EcPairwiseKey from "./EcPairwiseKey";
|
|||
return RsaPairwiseKey.generate(this.cryptoFactory, personaMasterKey, <RsaHashedKeyGenParams>algorithm, peerId);
|
||||
|
||||
default:
|
||||
throw new CryptoError(algorithm, `Pairwise key for type '${keyType}' is not supported.`);
|
||||
return Promise.reject(new CryptoError(algorithm, `Pairwise key for type '${keyType}' is not supported.`));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ type PrimeDelegate = Array<(cryptoFactory: CryptoFactory, inx: number, key: Buff
|
|||
// This method is currently breaking the subtle crypto pattern and needs to be fixed to be platform independent
|
||||
|
||||
// Set the key size
|
||||
const keySize = algorithm.modulusLength || 1024;
|
||||
const keySize = algorithm.modulusLength || 2048;
|
||||
|
||||
// Get deterministic base number for p
|
||||
const peerIdBuffer = Buffer.from(peerId);
|
||||
|
|
|
@ -24,7 +24,7 @@ import { ISubtleCrypto } from './index';
|
|||
// tslint:disable-next-line:no-typeof-undefined
|
||||
if (typeof window !== 'undefined') {
|
||||
// return browser api
|
||||
return <SubtleCrypto>window.crypto.subtle;
|
||||
return <SubtleCrypto>(window.crypto?.subtle);
|
||||
}
|
||||
|
||||
throw new CryptoError(<any>{}, 'window is not defined. Must be defined in browser.')
|
||||
|
|
|
@ -68,7 +68,7 @@ export default class SubtleCryptoExtension extends Subtle implements ISubtleCryp
|
|||
const format: string = (<any>algorithm).format;
|
||||
if (isElliptic && signature.byteLength <= 64 && format) {
|
||||
if (format.toUpperCase() !== 'DER') {
|
||||
throw new CryptoError(algorithm, 'Only DER format supported for signature');
|
||||
return Promise.reject(new CryptoError(algorithm, 'Only DER format supported for signature'));
|
||||
}
|
||||
|
||||
// DER format needed for signature, specied in algorithm
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "verifiablecredentials-crypto-sdk-typescript-plugin",
|
||||
"version": "1.1.12-preview.0",
|
||||
"version": "1.1.12-preview.1",
|
||||
"description": "Package for plugeable crypto based on subtle crypto.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -35,8 +35,8 @@
|
|||
"typescript": "4.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.1",
|
||||
"@peculiar/webcrypto": "1.1.3",
|
||||
"@types/node": "14.6.2",
|
||||
"base64url": "^3.0.1",
|
||||
|
|
|
@ -31,7 +31,7 @@ describe('CryptoFactory', () => {
|
|||
it('should change a crypto suite item',() => {
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
|
||||
const factory = new CryptoFactory(keyStore, SubtleCryptoNode.getSubtleCrypto());
|
||||
let factory = new CryptoFactory(keyStore, SubtleCryptoNode.getSubtleCrypto());
|
||||
const algorithm = 'ES256K-tobeinvented';
|
||||
const subtleCrypto = new SubtleCryptoMock();
|
||||
let keyReference = new KeyReference('', 'secret');
|
||||
|
@ -39,6 +39,11 @@ describe('CryptoFactory', () => {
|
|||
let keyEncrypters: any = factory.getKeyEncrypter(algorithm, CryptoFactoryScope.All, keyReference);
|
||||
expect(keyEncrypters.ID).toBeUndefined();
|
||||
|
||||
factory.addKeyEncrypter(algorithm, {subtleCrypto: subtleCrypto, scope: CryptoFactoryScope.All, keyStoreType: ['secret']});
|
||||
keyEncrypters = factory.getKeyEncrypter(algorithm, CryptoFactoryScope.Private, new KeyReference('', 'test'));
|
||||
expect(keyEncrypters.ID).toBeUndefined();
|
||||
|
||||
factory = new CryptoFactory(keyStore, SubtleCryptoNode.getSubtleCrypto());
|
||||
factory.addKeyEncrypter(algorithm, {subtleCrypto: subtleCrypto, scope: CryptoFactoryScope.Private, keyStoreType: ['secret']});
|
||||
keyEncrypters = factory.getKeyEncrypter(algorithm, CryptoFactoryScope.Private, keyReference);
|
||||
expect(keyEncrypters.ID).toEqual('SubtleCryptoMock');
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
import { SubtleCryptoNode, CryptoFactory, CryptoFactoryScope, CryptoHelpers } from '../lib/index';
|
||||
import { KeyStoreInMemory, KeyReference } from 'verifiablecredentials-crypto-sdk-typescript-keystore';
|
||||
|
||||
describe('CryptoHelpers', () => {
|
||||
it('should return getSubtleCryptoForAlgorithm', () => {
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
let factory = new CryptoFactory(keyStore, SubtleCryptoNode.getSubtleCrypto());
|
||||
let keyReference = new KeyReference('', 'secret');
|
||||
let subtle = CryptoHelpers.getSubtleCryptoForAlgorithm(factory, {name: 'RSASSA-PKCS1-V1_5'}, CryptoFactoryScope.All, keyReference);
|
||||
expect(subtle.constructor.name).toEqual('Subtle');
|
||||
subtle = CryptoHelpers.getSubtleCryptoForAlgorithm(factory, {name: 'ECDSA'}, CryptoFactoryScope.All, keyReference);
|
||||
expect(subtle.constructor.name).toEqual('Subtle');
|
||||
subtle = CryptoHelpers.getSubtleCryptoForAlgorithm(factory, {name: 'EdDSA'}, CryptoFactoryScope.All, keyReference);
|
||||
expect(subtle.constructor.name).toEqual('Subtle');
|
||||
subtle = CryptoHelpers.getSubtleCryptoForAlgorithm(factory, {name: 'RSA-OAEP'}, CryptoFactoryScope.All, keyReference);
|
||||
expect(subtle.constructor.name).toEqual('Subtle');
|
||||
subtle = CryptoHelpers.getSubtleCryptoForAlgorithm(factory, {name: 'RSA-OAEP-256'}, CryptoFactoryScope.All, keyReference);
|
||||
expect(subtle.constructor.name).toEqual('Subtle');
|
||||
subtle = CryptoHelpers.getSubtleCryptoForAlgorithm(factory, {name: 'AES-GCM'}, CryptoFactoryScope.All, keyReference);
|
||||
expect(subtle.constructor.name).toEqual('Subtle');
|
||||
subtle = CryptoHelpers.getSubtleCryptoForAlgorithm(factory, {name: 'HMAC'}, CryptoFactoryScope.All, keyReference);
|
||||
expect(subtle.constructor.name).toEqual('Subtle');
|
||||
subtle = CryptoHelpers.getSubtleCryptoForAlgorithm(factory, {name: 'SHA-256'}, CryptoFactoryScope.All, keyReference);
|
||||
expect(subtle.constructor.name).toEqual('Subtle');
|
||||
subtle = CryptoHelpers.getSubtleCryptoForAlgorithm(factory, {name: 'SHA-384'}, CryptoFactoryScope.All, keyReference);
|
||||
expect(subtle.constructor.name).toEqual('Subtle');
|
||||
subtle = CryptoHelpers.getSubtleCryptoForAlgorithm(factory, {name: 'SHA-512'}, CryptoFactoryScope.All, keyReference);
|
||||
expect(subtle.constructor.name).toEqual('Subtle');
|
||||
|
||||
// Negative cases
|
||||
expect(() => CryptoHelpers.getSubtleCryptoForAlgorithm(factory, {name: 'SHA1'}, CryptoFactoryScope.All, keyReference)).toThrowError(`Algorithm '{"name":"SHA1"}' is not supported`);
|
||||
|
||||
const testSpy = { name: 'SHA-1' };
|
||||
const webCryptoToJwaSpy: jasmine.Spy = spyOn(CryptoHelpers, 'webCryptoToJwa').and.callFake(() => 'SHA-1');
|
||||
expect(() => CryptoHelpers.getSubtleCryptoForAlgorithm(factory, <any>testSpy, CryptoFactoryScope.All, keyReference)).toThrowError(`Algorithm '{"name":"SHA-1"}' is not supported. Should be unreachable`);
|
||||
});
|
||||
it('should return jwaToWebCrypto', () => {
|
||||
expect(CryptoHelpers.jwaToWebCrypto('Rs256')).toEqual({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256'} });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('Rs384')).toEqual({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-384'} });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('Rs512')).toEqual({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-512'} });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('RSA-OAEP-256')).toEqual({ name: 'RSA-OAEP', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: 'SHA-256' });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('RSA-OAEP')).toEqual({ name: 'RSA-OAEP', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: 'SHA-256' });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('A128GCM', [0,1,2], [3,4,5])).toEqual({ name: 'AES-GCM', iv: [0, 1, 2], additionalData: [3,4,5], tagLength: 128, length: 128});
|
||||
expect(CryptoHelpers.jwaToWebCrypto('A192GCM', [0,1,2], [3,4,5])).toEqual({ name: 'AES-GCM', iv: [0, 1, 2], additionalData: [3,4,5], tagLength: 128, length: 192});
|
||||
expect(CryptoHelpers.jwaToWebCrypto('A256GCM', [0,1,2], [3,4,5])).toEqual({ name: 'AES-GCM', iv: [0, 1, 2], additionalData: [3,4,5], tagLength: 128, length: 256});
|
||||
expect(CryptoHelpers.jwaToWebCrypto('Es256k')).toEqual({ name: 'ECDSA', namedCurve: 'secp256k1', crv: 'secp256k1', hash: { name: 'SHA-256' } });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('EdDSA')).toEqual({ name: 'EdDSA', namedCurve: 'ed25519', crv: 'ed25519', hash: { name: 'SHA-256' } });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('SHA-256')).toEqual({ hash: { name: 'SHA-256'} });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('SHA-384')).toEqual({ hash: { name: 'SHA-384'} });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('SHA-512')).toEqual({ hash: { name: 'SHA-512'} });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('HS256')).toEqual({ name: 'HMAC', hash: { name: 'SHA-256'} });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('HS384')).toEqual({ name: 'HMAC', hash: { name: 'SHA-384'} });
|
||||
expect(CryptoHelpers.jwaToWebCrypto('HS512')).toEqual({ name: 'HMAC', hash: { name: 'SHA-512'} });
|
||||
|
||||
// Negative cases
|
||||
expect(() => CryptoHelpers.jwaToWebCrypto('SHA1')).toThrowError(`Algorithm 'SHA1' is not supported`);
|
||||
});
|
||||
|
||||
it('should return webCryptoToJwa', () => {
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256'} })).toEqual('RS256');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-384'} })).toEqual('RS384');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-512'} })).toEqual('RS512');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'RSA-OAEP', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: 'SHA-256' })).toEqual('RSA-OAEP-256');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'RSA-OAEP', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: 'SHA-256' })).toEqual('RSA-OAEP-256');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'AES-GCM', iv: [0, 1, 2], additionalData: [3,4,5], tagLength: 128, length: 128})).toEqual('A128GCM');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'AES-GCM', iv: [0, 1, 2], additionalData: [3,4,5], tagLength: 128, length: 192})).toEqual('A192GCM');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'AES-GCM', iv: [0, 1, 2], additionalData: [3,4,5], tagLength: 128, length: 256})).toEqual('A256GCM');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'ECDSA', namedCurve: 'secp256k1', crv: 'secp256k1', hash: { name: 'SHA-256' } })).toEqual('ES256K');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'EdDSA', namedCurve: 'ed25519', crv: 'ed25519', hash: { name: 'SHA-256' } })).toEqual('EdDSA');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'SHA-256' })).toEqual('SHA-256');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'SHA-384' })).toEqual('SHA-384');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'SHA-512' })).toEqual('SHA-512');
|
||||
expect(CryptoHelpers.webCryptoToJwa({ name: 'HMAC', hash: { name: 'SHA-256'} })).toEqual('HS256');
|
||||
|
||||
// Negative cases
|
||||
expect(() => CryptoHelpers.webCryptoToJwa({ name: 'SHA1' })).toThrowError(`Algorithm '{"name":"SHA1"}' is not supported`);
|
||||
});
|
||||
|
||||
it('should return getKeyImportAlgorithm', () => {
|
||||
let jwk: any = {crv: 'secp256k1'};
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256'} }, jwk)).toEqual(<any>{ name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256'} });
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-384'} }, jwk)).toEqual(<any>{ name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-384'} });
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-512'} }, jwk)).toEqual(<any>{ name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-512'} });
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'RSA-OAEP', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: 'SHA-256' }, jwk)).toEqual(<any>{ name: 'RSA-OAEP', hash: 'SHA-256' });
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'RSA-OAEP', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: 'SHA-256' }, jwk)).toEqual(<any>{ name: 'RSA-OAEP', hash: 'SHA-256' });
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'ECDSA', namedCurve: 'secp256k1', crv: 'secp256k1', hash: { name: 'SHA-256' } }, jwk)).toEqual(<any>{ name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' } });
|
||||
jwk = {crv: 'ed25519'};
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'EdDSA', namedCurve: 'ed25519', crv: 'ed25519', hash: { name: 'SHA-256' } }, jwk)).toEqual(<any>{ name: 'EdDSA', namedCurve: 'ed25519', hash: { name: 'SHA-256' } });
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'SHA-256' }, jwk)).toEqual(<any>{ name: 'SHA-256', hash: 'SHA-256' });
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'SHA-384' }, jwk)).toEqual(<any>{ name: 'SHA-384', hash: 'SHA-384' });
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'SHA-512' }, jwk)).toEqual(<any>{ name: 'SHA-512', hash: 'SHA-512' });
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'HMAC', hash: { name: 'SHA-256'} }, jwk)).toEqual(<any>{ name: 'HMAC', hash: { name: 'SHA-256'} });
|
||||
expect(CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'AES-GCM'}, jwk)).toEqual(<any>{ name: 'AES-GCM' });
|
||||
|
||||
// Negative cases
|
||||
expect(() => CryptoHelpers.getKeyImportAlgorithm(<any>{ name: 'SHA-1'}, jwk)).toThrowError(`Algorithm '{"name":"SHA-1"}' is not supported`);
|
||||
});
|
||||
it('should test getHash', () => {
|
||||
expect((<any>CryptoHelpers).getHash({'test': ''})).toEqual('256');
|
||||
})
|
||||
});
|
|
@ -8,6 +8,7 @@ import {CryptoFactory, SubtleCryptoExtension, SubtleCryptoNode, PairwiseKey } fr
|
|||
import { KeyStoreInMemory, KeyReference } from 'verifiablecredentials-crypto-sdk-typescript-keystore';
|
||||
import { PrivateKey, EcPrivateKey, OctKey, KeyContainer } from 'verifiablecredentials-crypto-sdk-typescript-keys';
|
||||
import base64url from 'base64url';
|
||||
import RsaPairwiseKey from '../lib/Pairwise/RsaPairwiseKey';
|
||||
|
||||
class Helpers {
|
||||
// Make sure we generate the same pairwise key
|
||||
|
@ -235,4 +236,13 @@ describe('PairwiseKey', () => {
|
|||
expect(1).toBe(results.filter(element => element === pairwiseKey.d).length);
|
||||
}
|
||||
});
|
||||
|
||||
it('should generate RSA pairwise', async () =>{
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
const cryptoFactory = new CryptoFactory(keyStore, new SubtleCryptoNode().getSubtleCrypto());
|
||||
|
||||
const alg = { name: 'RSASSA-PKCS1-v1_5', publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' }};
|
||||
const rsaPairwiseKey: any = await RsaPairwiseKey.generate(cryptoFactory, Buffer.from('seed'), <any>alg, 'peer');
|
||||
expect(base64url.toBuffer(rsaPairwiseKey.n).byteLength).toEqual(256);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { Subtle } from '../lib';
|
||||
|
||||
describe('Subtle', () => {
|
||||
it('should create instance', () => {
|
||||
let subtle: any = new Subtle();
|
||||
expect(subtle.getSubtleCrypto().constructor.name).toEqual('Subtle');
|
||||
});
|
||||
it('should test algorithmTransform', () => {
|
||||
let subtle = new Subtle();
|
||||
let alg: any = { test: 'name' };
|
||||
expect(subtle.algorithmTransform(alg)).toEqual(alg);
|
||||
alg = { namedCurve: 'P-256K' };
|
||||
expect(subtle.algorithmTransform(alg)).toEqual({ namedCurve: 'K-256' });
|
||||
alg = { namedCurve: 'SECP256K1' };
|
||||
expect(subtle.algorithmTransform(alg)).toEqual({ namedCurve: 'K-256' });
|
||||
alg = { crv: 'P-256K' };
|
||||
expect(subtle.algorithmTransform(alg)).toEqual({ crv: 'K-256' });
|
||||
alg = { crv: 'SECP256K1' };
|
||||
expect(subtle.algorithmTransform(alg)).toEqual({ crv: 'K-256' });
|
||||
alg = { crv: 'XXX' };
|
||||
expect(subtle.algorithmTransform(alg)).toEqual({ crv: 'XXX' });
|
||||
});
|
||||
it('should test keyImportTransform', () => {
|
||||
let subtle: any = new Subtle();
|
||||
let jwk: any = { test: 'name' };
|
||||
expect(subtle.keyImportTransform(jwk)).toEqual(jwk);
|
||||
jwk = { foo: 'fighters' };
|
||||
expect(subtle.keyImportTransform(jwk)).toEqual(jwk);
|
||||
jwk = { crv: 'P-256K' };
|
||||
expect(subtle.keyImportTransform(jwk)).toEqual({ crv: 'K-256' });
|
||||
jwk = { crv: 'SECP256K1' };
|
||||
expect(subtle.keyImportTransform(jwk)).toEqual({ crv: 'K-256' });
|
||||
jwk = { crv: 'XXX' };
|
||||
expect(subtle.keyImportTransform(jwk)).toEqual({ crv: 'XXX' });
|
||||
|
||||
});
|
||||
it('should test keyExportTransform', () => {
|
||||
let subtle: any = new Subtle();
|
||||
let jwk: any = { test: 'name' };
|
||||
expect(subtle.keyExportTransform(jwk)).toEqual(jwk);
|
||||
jwk = { foo: 'fighters' };
|
||||
expect(subtle.keyExportTransform(jwk)).toEqual(jwk);
|
||||
jwk = { crv: 'P-256K' };
|
||||
expect(subtle.keyExportTransform(jwk)).toEqual({ crv: 'SECP256K1' });
|
||||
jwk = { crv: 'K-256' };
|
||||
expect(subtle.keyExportTransform(jwk)).toEqual({ crv: 'SECP256K1' });
|
||||
jwk = { crv: 'SECP256K1' };
|
||||
expect(subtle.keyExportTransform(jwk)).toEqual({ crv: 'SECP256K1' });
|
||||
});
|
||||
it('should test digest', async() => {
|
||||
let subtle: any = new Subtle();
|
||||
let alg: any = { name: 'SHA-256' };
|
||||
expect(await subtle.digest(alg, new Uint8Array([1,2,3,4]))).toBeDefined();
|
||||
});
|
||||
it('should test generate/export', async() => {
|
||||
let subtle = new Subtle();
|
||||
let alg: any = { name: "HMAC", hash: {name: "SHA-256"} };
|
||||
const key = <CryptoKey>await subtle.generateKey(alg, true, ['sign']);
|
||||
expect(key).toBeDefined();
|
||||
let jwk: any = await subtle.exportKey('raw', key);
|
||||
expect(new Uint8Array(jwk)[0]).toBeDefined();
|
||||
let cryptoKey = await subtle.importKey('raw', jwk, alg, true, ['sign']);
|
||||
expect(cryptoKey).toBeDefined();
|
||||
jwk = await subtle.exportKey('jwk', key);
|
||||
expect(jwk.k).toBeDefined();
|
||||
jwk = await subtle.importKey('jwk', jwk, alg, true, ['sign']);
|
||||
expect(jwk.type).toEqual('secret');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
import { SubtleCryptoBrowser, Subtle } from '../lib';
|
||||
|
||||
describe('SubtleCryptoBrowser', () => {
|
||||
it('should create a SubtleCryptoBrowser', () => {
|
||||
|
||||
const subtleBrowser = new SubtleCryptoBrowser();
|
||||
expect(() => subtleBrowser.getSubtleCrypto()).toThrowError('window is not defined. Must be defined in browser.');
|
||||
expect(() => SubtleCryptoBrowser.getSubtleCrypto()).toThrowError('window is not defined. Must be defined in browser.');
|
||||
});
|
||||
it('should test algorithmTransform', () => {
|
||||
let subtle = new SubtleCryptoBrowser();
|
||||
let alg: any = {test: 'name'};
|
||||
expect(subtle.algorithmTransform(alg)).toEqual(alg);
|
||||
alg = {foo: 'fighters'};
|
||||
expect(subtle.algorithmTransform(alg)).toEqual(alg);
|
||||
});
|
||||
it('should test keyImportTransform', () => {
|
||||
let subtle: any = new SubtleCryptoBrowser();
|
||||
let jwk: any = {test: 'name'};
|
||||
expect(subtle.keyImportTransform(jwk)).toEqual(jwk);
|
||||
jwk = {foo: 'fighters'};
|
||||
expect(subtle.keyImportTransform(jwk)).toEqual(jwk);
|
||||
});
|
||||
it('should test keyExportTransform', () => {
|
||||
let subtle: any = new SubtleCryptoBrowser();
|
||||
let jwk: any = {test: 'name'};
|
||||
expect(subtle.keyExportTransform(jwk)).toEqual(jwk);
|
||||
jwk = {foo: 'fighters'};
|
||||
expect(subtle.keyExportTransform(jwk)).toEqual(jwk);
|
||||
});
|
||||
});
|
|
@ -1,9 +0,0 @@
|
|||
import { SubtleCryptoBrowser } from '../lib';
|
||||
|
||||
describe('SubtleCryptoBrowser', () => {
|
||||
it('should create a SubtleCryptoBrowser', () => {
|
||||
|
||||
const subtleBrowser = new SubtleCryptoBrowser();
|
||||
expect(() => subtleBrowser.getSubtleCrypto()).toThrowError('window is not defined. Must be defined in browser.');
|
||||
});
|
||||
});
|
|
@ -6,7 +6,8 @@ import { SubtleCryptoNode, CryptoFactory, CryptoFactoryScope, CryptoHelpers, Sub
|
|||
import { KeyStoreInMemory, KeyReference } from 'verifiablecredentials-crypto-sdk-typescript-keystore';
|
||||
import EcPrivateKey from 'verifiablecredentials-crypto-sdk-typescript-keys/dist/lib/ec/EcPrivateKey';
|
||||
import { PublicKey } from 'verifiablecredentials-crypto-sdk-typescript-keys';
|
||||
|
||||
import base64url from 'base64url';
|
||||
const clone = require('clone');
|
||||
|
||||
describe('SubtleCryptoExtension', () => {
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
|
@ -15,12 +16,26 @@ describe('SubtleCryptoExtension', () => {
|
|||
|
||||
it('should generate an ECDSA key', async () => {
|
||||
const alg = CryptoHelpers.jwaToWebCrypto('Es256K');
|
||||
const key: any = <CryptoKey>await generator.generateKey(
|
||||
let key: any = <CryptoKey>await generator.generateKey(
|
||||
alg,
|
||||
true,
|
||||
['sign', 'verify']
|
||||
);
|
||||
const jwk = await cryptoFactory.defaultCrypto.exportKey('jwk', key.privateKey);
|
||||
let jwk = await cryptoFactory.defaultCrypto.exportKey('jwk', key.privateKey);
|
||||
expect(jwk.d).toBeDefined();
|
||||
expect(jwk.x).toBeDefined();
|
||||
expect(jwk.y).toBeDefined();
|
||||
expect(jwk.kty).toEqual('EC');
|
||||
|
||||
// pairwise
|
||||
const keyReference = new KeyReference('seed');
|
||||
await keyStore.save(keyReference, base64url(Buffer.from('ABCDEFG')));
|
||||
jwk = await generator.generatePairwiseKey(
|
||||
alg,
|
||||
'seed',
|
||||
'persona',
|
||||
'peer'
|
||||
);
|
||||
expect(jwk.d).toBeDefined();
|
||||
expect(jwk.x).toBeDefined();
|
||||
expect(jwk.y).toBeDefined();
|
||||
|
@ -52,9 +67,11 @@ describe('SubtleCryptoExtension', () => {
|
|||
expect(jwk.k).toBeDefined();
|
||||
expect(jwk.kty).toEqual('oct');
|
||||
});
|
||||
it('should sign a message', async () => {
|
||||
|
||||
it('should sign a message with ECDSA', async () => {
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
const factory = new CryptoFactory(keyStore, SubtleCryptoNode.getSubtleCrypto());
|
||||
const crypto = SubtleCryptoNode.getSubtleCrypto();
|
||||
const factory = new CryptoFactory(keyStore, crypto);
|
||||
const subtle = new SubtleCryptoExtension(factory);
|
||||
const alg = { name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' }, format: 'DER' };
|
||||
|
||||
|
@ -63,17 +80,126 @@ describe('SubtleCryptoExtension', () => {
|
|||
const payload = Buffer.from('test');
|
||||
let signature = await subtle.signByKeyStore(alg, new KeyReference('key'), payload);
|
||||
expect(signature.byteLength).toBeGreaterThan(65);
|
||||
const publicKey = (await keyStore.get(new KeyReference('key'), {publicKeyOnly: true})).getKey<PublicKey>();
|
||||
const publicKey = (await keyStore.get(new KeyReference('key'), { publicKeyOnly: true })).getKey<PublicKey>();
|
||||
let result = await subtle.verifyByJwk(alg, publicKey, signature, payload);
|
||||
expect(result).toBeTruthy();
|
||||
|
||||
// verify by passing in crypto key
|
||||
const cryptoKey = await subtle.importKey('jwk', <any>jwk, alg, true, ['sign', 'verify']);
|
||||
let keyReference = new KeyReference('non-saved', 'signing', '', cryptoKey)
|
||||
signature = await subtle.signByKeyStore(alg, keyReference, payload);
|
||||
expect(signature.byteLength).toBeGreaterThan(65);
|
||||
result = await subtle.verifyByJwk(alg, publicKey, signature, payload);
|
||||
expect(result).toBeTruthy();
|
||||
|
||||
// without DER
|
||||
delete (<any>alg).format;
|
||||
signature = await subtle.signByKeyStore(alg, new KeyReference('key'), payload);
|
||||
expect(signature.byteLength).toBeLessThanOrEqual(64);
|
||||
result = await subtle.verifyByJwk(alg, publicKey, signature, payload);
|
||||
expect(result).toBeTruthy();
|
||||
|
||||
// without DER if the underlying algorithm provides DER
|
||||
const signSpy: jasmine.Spy = spyOn(crypto, 'sign').and.callFake((alg: any) => {
|
||||
(<any>alg).format = 'DER';
|
||||
const r = new Uint8Array(32);
|
||||
r.fill(0xff);
|
||||
const s = new Uint8Array(32);
|
||||
s.fill(0xff);
|
||||
|
||||
return Promise.resolve(SubtleCryptoExtension.toDer([r, s]));
|
||||
});
|
||||
signature = await subtle.signByKeyStore(alg, keyReference, payload);
|
||||
expect(signature.byteLength).toBeLessThanOrEqual(64);
|
||||
|
||||
// negative cases
|
||||
// Only DER format supported for signature
|
||||
const modifiedAlg = clone(alg);
|
||||
(<any>modifiedAlg).format = 'DER';
|
||||
(<any>modifiedAlg).name = 'EdDSA';
|
||||
signSpy.and.callFake((alg: any) => {
|
||||
(<any>alg).format = 'XXX';
|
||||
return Promise.resolve(new ArrayBuffer(64));
|
||||
});
|
||||
try {
|
||||
await subtle.signByKeyStore(modifiedAlg, keyReference, payload);
|
||||
fail('Should throw signature error');
|
||||
} catch (exception) {
|
||||
console.log('test');
|
||||
expect(exception.message).toEqual('Only DER format supported for signature');
|
||||
}
|
||||
|
||||
// Verify failure
|
||||
const verifySpy: jasmine.Spy = spyOn(crypto, 'verify').and.callFake(() => {
|
||||
return Promise.resolve(false);
|
||||
});
|
||||
result = await subtle.verifyByJwk(alg, publicKey, signature, payload);
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
const getKeyImportAlgorithmSpy: jasmine.Spy = spyOn(CryptoHelpers, 'getKeyImportAlgorithm').and.callFake((alg: any) => {
|
||||
// change the algorithm will break the signature
|
||||
const keyImportAlgorithm = clone(alg);
|
||||
alg.name = 'EDDSA';
|
||||
return keyImportAlgorithm;
|
||||
});
|
||||
const importSpy: jasmine.Spy = spyOn(crypto, 'importKey').and.callFake(() => {
|
||||
return Promise.resolve(cryptoKey);
|
||||
});
|
||||
result = await subtle.verifyByJwk(alg, publicKey, signature, payload);
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should sign a message with RSA', async () => {
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
const crypto = SubtleCryptoNode.getSubtleCrypto();
|
||||
const factory = new CryptoFactory(keyStore, crypto);
|
||||
const subtle = new SubtleCryptoExtension(factory);
|
||||
const alg = { name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: 'SHA-256' }};
|
||||
let keyReference = new KeyReference('key');
|
||||
|
||||
const keyPair = <CryptoKeyPair>(await subtle.generateKey(alg, true, ['sign', 'verify']));
|
||||
const publicJwk = await subtle.exportKey('jwk', keyPair.publicKey);
|
||||
const privateJwk = await subtle.exportKey('jwk', keyPair.privateKey);
|
||||
await keyStore.save(keyReference, <any>privateJwk);
|
||||
|
||||
const payload = Buffer.from('test');
|
||||
let signature = await subtle.signByKeyStore(alg, keyReference, payload);
|
||||
expect(signature.byteLength).toEqual(256);
|
||||
const publicKey = (await keyStore.get(keyReference, { publicKeyOnly: true })).getKey<PublicKey>();
|
||||
let result = await subtle.verifyByJwk(alg, publicKey, signature, payload);
|
||||
expect(result).toBeTruthy();
|
||||
|
||||
// Verify failure
|
||||
const verifySpy: jasmine.Spy = spyOn(crypto, 'verify').and.callFake(() => {
|
||||
return Promise.resolve(false);
|
||||
});
|
||||
result = await subtle.verifyByJwk(alg, publicKey, signature, payload);
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should encrypt a message with RSA', async () => {
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
const crypto = SubtleCryptoNode.getSubtleCrypto();
|
||||
const factory = new CryptoFactory(keyStore, crypto);
|
||||
const subtle = new SubtleCryptoExtension(factory);
|
||||
const alg = { name: 'RSA-OAEP', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: 'SHA-256' };
|
||||
let keyReference = new KeyReference('key');
|
||||
|
||||
const keyPair = <CryptoKeyPair>(await subtle.generateKey(alg, true, ['encrypt', 'decrypt']));
|
||||
const publicJwk = await subtle.exportKey('jwk', keyPair.publicKey);
|
||||
const privateJwk = await subtle.exportKey('jwk', keyPair.privateKey);
|
||||
await keyStore.save(keyReference, <any>privateJwk);
|
||||
|
||||
const payload = Buffer.from('test');
|
||||
let cipher = await subtle.encryptByJwk(alg, publicJwk, payload);
|
||||
expect(cipher).toBeDefined();
|
||||
|
||||
let decrypted = await subtle.decryptByKeyStore(alg, keyReference, cipher);
|
||||
expect(new Uint8Array(decrypted)).toEqual(new Uint8Array(payload));
|
||||
decrypted = await subtle.decryptByJwk(alg, privateJwk, cipher);
|
||||
expect(new Uint8Array(decrypted)).toEqual(new Uint8Array(payload));
|
||||
});
|
||||
|
||||
it('should sign a message with key reference options', async () => {
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
const factory = new CryptoFactory(keyStore, SubtleCryptoNode.getSubtleCrypto());
|
||||
|
@ -85,7 +211,7 @@ describe('SubtleCryptoExtension', () => {
|
|||
const payload = Buffer.from('test');
|
||||
let signature = await subtle.signByKeyStore(alg, new KeyReference('key'), payload);
|
||||
expect(signature.byteLength).toBeGreaterThan(65);
|
||||
const publicKey = (await keyStore.get(new KeyReference('key'), {publicKeyOnly: true})).getKey<PublicKey>();
|
||||
const publicKey = (await keyStore.get(new KeyReference('key'), { publicKeyOnly: true })).getKey<PublicKey>();
|
||||
let result = await subtle.verifyByJwk(alg, publicKey, signature, payload);
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
@ -102,6 +228,15 @@ describe('SubtleCryptoExtension', () => {
|
|||
expect(Buffer.from(der).toString('hex').toUpperCase()).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should fail to decode DER', () => {
|
||||
const signature = new Uint8Array(64);
|
||||
signature.fill(0xff);
|
||||
expect(() => SubtleCryptoExtension.fromDer(signature)).toThrowError('No DER format to decode');
|
||||
|
||||
signature[0] = 0x30;
|
||||
expect(() => SubtleCryptoExtension.fromDer(signature)).toThrowError('Marker on index 2 must be 0x02');
|
||||
});
|
||||
|
||||
it('should correctly roundtrip from R||S signature to DER signature', () => {
|
||||
|
||||
const scenarios = [
|
||||
|
@ -200,7 +335,7 @@ describe('SubtleCryptoExtension', () => {
|
|||
// roundtrip back to R||S
|
||||
const derArray = new Uint8Array(der);
|
||||
const roundtripRS = SubtleCryptoExtension.fromDer(derArray);
|
||||
const r = SubtleCryptoExtension.toPaddedNumber(roundtripRS[0]);
|
||||
const r = SubtleCryptoExtension.toPaddedNumber(roundtripRS[0], 32);
|
||||
const s = SubtleCryptoExtension.toPaddedNumber(roundtripRS[1]);
|
||||
const rsHex = Buffer.from(r).toString('hex').toUpperCase() + Buffer.from(s).toString('hex').toUpperCase();
|
||||
expect(rsHex).toEqual(scenario.rs, scenario.scenario + " back to R||S");
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { SubtleCryptoNode, CryptoFactory, CryptoFactoryScope, CryptoHelpers, SubtleCryptoExtension } from '../lib';
|
||||
import { KeyStoreInMemory, KeyReference } from 'verifiablecredentials-crypto-sdk-typescript-keystore';
|
||||
import EcPrivateKey from 'verifiablecredentials-crypto-sdk-typescript-keys/dist/lib/ec/EcPrivateKey';
|
||||
import { PublicKey, JsonWebKey } from 'verifiablecredentials-crypto-sdk-typescript-keys';
|
||||
import base64url from 'base64url';
|
||||
|
||||
describe('SubtleCryptoNode', () => {
|
||||
it('should create instance', () => {
|
||||
let subtle: any = new SubtleCryptoNode();
|
||||
expect(subtle.getSubtleCrypto().constructor.name).toEqual('Subtle');
|
||||
expect(SubtleCryptoNode.getSubtleCrypto().constructor.name).toEqual('Subtle');
|
||||
});
|
||||
it('should test algorithmTransform', () => {
|
||||
let subtle = new SubtleCryptoNode();
|
||||
let alg: any = {test: 'name'};
|
||||
expect(subtle.algorithmTransform(alg)).toEqual(alg);
|
||||
alg = {foo: 'fighters'};
|
||||
expect(subtle.algorithmTransform(alg)).toEqual(alg);
|
||||
});
|
||||
it('should test keyImportTransform', () => {
|
||||
let subtle: any = new SubtleCryptoNode();
|
||||
let jwk: any = {test: 'name'};
|
||||
expect(subtle.keyImportTransform(jwk)).toEqual(jwk);
|
||||
jwk = {foo: 'fighters'};
|
||||
expect(subtle.keyImportTransform(jwk)).toEqual(jwk);
|
||||
});
|
||||
it('should test keyExportTransform', () => {
|
||||
let subtle: any = new SubtleCryptoNode();
|
||||
let jwk: any = {test: 'name'};
|
||||
expect(subtle.keyExportTransform(jwk)).toEqual(jwk);
|
||||
jwk = {foo: 'fighters'};
|
||||
expect(subtle.keyExportTransform(jwk)).toEqual(jwk);
|
||||
});
|
||||
});
|
|
@ -107,7 +107,7 @@ export default class JoseProtocol implements IPayloadProtection {
|
|||
const cipher: JweToken = JweToken.fromCryptoToken(token, options);
|
||||
return cipher.serialize(protocolFormat);
|
||||
default:
|
||||
throw new CryptoProtocolError(JoseConstants.Jose, `Serialization format '${format}' is not supported`);
|
||||
throw new CryptoProtocolError(JoseConstants.Jose, `Serialization format '${protocolFormat}' is not supported`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ export default class JoseProtocol implements IPayloadProtection {
|
|||
const jweProtectOptions = JweToken.fromPayloadProtectionOptions(options);
|
||||
return JweToken.toCryptoToken(protocolFormat, JweToken.deserialize(token, jweProtectOptions), options);
|
||||
default:
|
||||
throw new CryptoProtocolError(JoseConstants.Jose, `Serialization format '${format}' is not supported`);
|
||||
throw new CryptoProtocolError(JoseConstants.Jose, `Serialization format '${protocolFormat}' is not supported`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -443,7 +443,7 @@ export default class JweToken implements IJweGeneralJson {
|
|||
let keyEncryptionAlgorithm: string | undefined = publicKey.alg;
|
||||
if (!keyEncryptionAlgorithm) {
|
||||
if (publicKey.kty == KeyType.EC) {
|
||||
throw new Error('EC encryption not implemented');
|
||||
return Promise.reject(new Error('EC encryption not implemented'));
|
||||
} else {
|
||||
// Default RSA algorithm
|
||||
keyEncryptionAlgorithm = JoseConstants.RsaOaep256;
|
||||
|
@ -553,7 +553,7 @@ export default class JweToken implements IJweGeneralJson {
|
|||
}
|
||||
|
||||
if (!contentEncryptionKey) {
|
||||
throw new CryptoProtocolError(JoseConstants.Jwe, 'Cannot decrypt the content encryption key because of missing key');
|
||||
return Promise.reject(new CryptoProtocolError(JoseConstants.Jwe, 'Cannot decrypt the content encryption key because of missing key'));
|
||||
}
|
||||
|
||||
// Decrypt content
|
||||
|
|
|
@ -559,10 +559,10 @@ export default class JwsToken implements IJwsGeneralJson {
|
|||
}
|
||||
|
||||
if (!alg) {
|
||||
throw new CryptoProtocolError(
|
||||
return Promise.reject(new CryptoProtocolError(
|
||||
JoseConstants.Jws,
|
||||
'Unable to validate signature as no signature algorithm has been specified in the header.'
|
||||
);
|
||||
));
|
||||
}
|
||||
const algorithm = CryptoHelpers.jwaToWebCrypto(alg);
|
||||
const encodedProtected = !protectedHeader ? '' : JoseHelpers.encodeHeader(protectedHeader);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "verifiablecredentials-crypto-sdk-typescript-protocol-jose",
|
||||
"version": "1.1.12-preview.0",
|
||||
"version": "1.1.12-preview.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/VerifiableCredentials-Crypto-SDK-Typescript.git"
|
||||
|
@ -28,6 +28,7 @@
|
|||
"devDependencies": {
|
||||
"@types/jasmine": "^2.8.9",
|
||||
"@types/node": "14.6.2",
|
||||
"clone": "^2.1.2",
|
||||
"jasmine": "3.6.3",
|
||||
"jasmine-reporters": "^2.3.2",
|
||||
"jasmine-spec-reporter": "^6.0.0",
|
||||
|
@ -39,11 +40,11 @@
|
|||
"typescript": "4.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-protocols-common": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-cryptofactory-suites": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-protocols-common": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-cryptofactory-suites": "1.1.12-preview.1",
|
||||
"base64url": "^3.0.1",
|
||||
"typescript-map": "0.0.7",
|
||||
"webcrypto-core": "1.1.8"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
import { JoseHelpers } from "../lib/index";
|
||||
import { CryptoProtocolError } from 'verifiablecredentials-crypto-sdk-typescript-protocols-common';
|
||||
import { KeyType } from 'verifiablecredentials-crypto-sdk-typescript-keys';
|
||||
import { JoseConstants, KeyType, KeyUse } from 'verifiablecredentials-crypto-sdk-typescript-keys';
|
||||
import { TSMap } from 'typescript-map';
|
||||
|
||||
describe('JoseHelpers', () => {
|
||||
|
@ -46,9 +46,21 @@ describe('JoseHelpers', () => {
|
|||
it(`should return the key type for 'EC' via JWA`, () => {
|
||||
expect(JoseHelpers.createTypeViaJwa('ES256K')).toEqual(KeyType.EC);
|
||||
});
|
||||
|
||||
|
||||
it(`should return the key type for 'RSA' via JWA`, () => {
|
||||
expect(JoseHelpers.createTypeViaJwa('RS256')).toEqual(KeyType.RSA);
|
||||
});
|
||||
|
||||
|
||||
it('should create use via jwa', () => {
|
||||
expect(JoseHelpers.createUseViaJwa(JoseConstants.Rs256)).toEqual(KeyUse.Signature);
|
||||
expect(JoseHelpers.createUseViaJwa(JoseConstants.Rs384)).toEqual(KeyUse.Signature);
|
||||
expect(JoseHelpers.createUseViaJwa(JoseConstants.Rs512)).toEqual(KeyUse.Signature);
|
||||
expect(JoseHelpers.createUseViaJwa(JoseConstants.RsaOaep)).toEqual(KeyUse.Encryption);
|
||||
expect(JoseHelpers.createUseViaJwa(JoseConstants.Es256K)).toEqual(KeyUse.Signature);
|
||||
expect(JoseHelpers.createUseViaJwa('EdDSA')).toEqual(KeyUse.Signature);
|
||||
|
||||
expect(() => JoseHelpers.createUseViaJwa(JoseConstants.AesGcm128)).toThrowError(`The algorithm 'AES-GCM' is not supported`);
|
||||
expect(() => JoseHelpers.createUseViaJwa(JoseConstants.AesGcm192)).toThrowError(`The algorithm 'AES-GCM' is not supported`);
|
||||
expect(() => JoseHelpers.createUseViaJwa(JoseConstants.AesGcm256)).toThrowError(`The algorithm 'AES-GCM' is not supported`);
|
||||
})
|
||||
});
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import { TSMap } from "typescript-map";
|
||||
import { JoseConstants } from "verifiablecredentials-crypto-sdk-typescript-keys";
|
||||
import { KeyStoreInMemory } from "verifiablecredentials-crypto-sdk-typescript-keystore";
|
||||
import { CryptoFactory, SubtleCryptoNode } from "verifiablecredentials-crypto-sdk-typescript-plugin";
|
||||
import { IPayloadProtectionOptions } from "verifiablecredentials-crypto-sdk-typescript-protocols-common";
|
||||
import { JoseProtocol, JoseToken } from "../lib";
|
||||
|
||||
describe('JoseToken', () => {
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
const cryptoFactory = new CryptoFactory(keyStore, SubtleCryptoNode.getSubtleCrypto())
|
||||
const options: IPayloadProtectionOptions = {
|
||||
cryptoFactory,
|
||||
options: new TSMap<string, any>([
|
||||
[JoseConstants.optionProtectedHeader, new TSMap([['typ', 'JWT']])]
|
||||
]),
|
||||
payloadProtection: new JoseProtocol()
|
||||
};
|
||||
|
||||
it('should instantiate a token', () => {
|
||||
let token = new JoseToken(options);
|
||||
expect(() => token.tokenFormat()).toThrowError('The token format is not found');
|
||||
|
||||
token.set(JoseConstants.tokenFormat, 'JwsCompactJson');
|
||||
expect(token.tokenFormat()).toEqual('JwsCompactJson');
|
||||
})
|
||||
});
|
|
@ -4,11 +4,12 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { JwsToken, JoseConstants, IJwsSigningOptions, JoseProtocol } from '../lib/index'
|
||||
import { IPayloadProtectionOptions } from 'verifiablecredentials-crypto-sdk-typescript-protocols-common';
|
||||
import { KeyStoreInMemory, ProtectionFormat, KeyReference, KeyStoreOptions } from 'verifiablecredentials-crypto-sdk-typescript-keystore';
|
||||
import { CryptoProtocolError, IPayloadProtectionOptions } from 'verifiablecredentials-crypto-sdk-typescript-protocols-common';
|
||||
import { KeyStoreInMemory, ProtectionFormat, KeyReference, KeyStoreOptions, CryptoError } from 'verifiablecredentials-crypto-sdk-typescript-keystore';
|
||||
import { CryptoFactory, SubtleCryptoNode, SubtleCryptoExtension } from 'verifiablecredentials-crypto-sdk-typescript-plugin';
|
||||
import { OctKey, PublicKey, KeyContainer } from 'verifiablecredentials-crypto-sdk-typescript-keys';
|
||||
import { TSMap } from "typescript-map";
|
||||
const clone = require('clone');
|
||||
|
||||
describe('JwsToken', () => {
|
||||
it('should create a jws token', async () => {
|
||||
|
@ -18,20 +19,59 @@ describe('JwsToken', () => {
|
|||
await keyStore.save(new KeyReference(seedReference), new OctKey('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'));
|
||||
const subtle = SubtleCryptoNode.getSubtleCrypto();
|
||||
const options: IJwsSigningOptions = {
|
||||
algorithm: <Algorithm> { name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' } },
|
||||
cryptoFactory: new CryptoFactory(keyStore, subtle)
|
||||
};
|
||||
const generate = new SubtleCryptoExtension(options.cryptoFactory);
|
||||
algorithm: <Algorithm>{ name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' } },
|
||||
cryptoFactory: new CryptoFactory(keyStore, subtle)
|
||||
};
|
||||
const generate = new SubtleCryptoExtension(options.cryptoFactory);
|
||||
|
||||
const privateKey = await generate.generatePairwiseKey(options.algorithm, seedReference, 'did:personaId', 'did:peerId');
|
||||
(<any>privateKey).alg = 'ES256K';
|
||||
(<any>privateKey).defaultSignAlgorithm = 'ES256K';
|
||||
|
||||
await keyStore.save(new KeyReference('key'), privateKey);
|
||||
const jwsToken = new JwsToken(options);
|
||||
const signature = await jwsToken.sign(new KeyReference('key'), Buffer.from(payload), ProtectionFormat.JwsGeneralJson);
|
||||
expect(signature).toBeDefined();
|
||||
const privateKey = await generate.generatePairwiseKey(options.algorithm, seedReference, 'did:personaId', 'did:peerId');
|
||||
(<any>privateKey).alg = 'ES256K';
|
||||
(<any>privateKey).defaultSignAlgorithm = 'ES256K';
|
||||
|
||||
await keyStore.save(new KeyReference('key'), privateKey);
|
||||
const jwsToken = new JwsToken(options);
|
||||
const signature = await jwsToken.sign(new KeyReference('key'), Buffer.from(payload), ProtectionFormat.JwsGeneralJson);
|
||||
expect(signature).toBeDefined();
|
||||
|
||||
expect(jwsToken.serialize()).toBeDefined();
|
||||
expect(jwsToken.serialize(ProtectionFormat.JwsGeneralJson)).toBeDefined();
|
||||
|
||||
// negative cases
|
||||
expect(() => jwsToken.serialize(<any>'aaa')).toThrow(new CryptoProtocolError(JoseConstants.Jws,`The format 'JwsGeneralJson' is not supported`));
|
||||
/*
|
||||
let clonedJwsToken: JwsToken = clone(jwsToken);
|
||||
clonedJwsToken.signatures[0] = <any>undefined;
|
||||
expect(() => jwsToken.serialize()).toThrowError(`The format 'JwsGeneralJson' is not supported`);
|
||||
*/
|
||||
});
|
||||
it('should create a jws token in compact', async () => {
|
||||
const payload = 'test payload';
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
const seedReference = 'seed';
|
||||
await keyStore.save(new KeyReference(seedReference), new OctKey('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'));
|
||||
const subtle = SubtleCryptoNode.getSubtleCrypto();
|
||||
const options: IJwsSigningOptions = {
|
||||
algorithm: <Algorithm>{ name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' } },
|
||||
cryptoFactory: new CryptoFactory(keyStore, subtle)
|
||||
};
|
||||
const generate = new SubtleCryptoExtension(options.cryptoFactory);
|
||||
|
||||
const privateKey = (<CryptoKeyPair>await generate.generateKey(options.algorithm, true, ['sign', 'verify'])).privateKey;
|
||||
const jwk: any = await generate.exportKey('jwk', privateKey);
|
||||
|
||||
(<any>jwk).alg = 'ES256K';
|
||||
(<any>jwk).defaultSignAlgorithm = 'ES256K';
|
||||
|
||||
await keyStore.save(new KeyReference('key'), jwk);
|
||||
const jwsToken = new JwsToken(options);
|
||||
const signature = await jwsToken.sign(new KeyReference('key'), Buffer.from(payload), ProtectionFormat.JwsCompactJson);
|
||||
expect(signature).toBeDefined();
|
||||
const serialized = signature.serialize();
|
||||
expect(serialized.split('.').length).toEqual(3);
|
||||
const token = JwsToken.deserialize(serialized);
|
||||
expect(token.payload.length).toEqual(12);
|
||||
});
|
||||
|
||||
it('should create a jws token with JWT header', async () => {
|
||||
const payload = 'test payload';
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
|
@ -39,20 +79,20 @@ describe('JwsToken', () => {
|
|||
await keyStore.save(new KeyReference(seedReference), new OctKey('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'));
|
||||
const subtle = SubtleCryptoNode.getSubtleCrypto();
|
||||
const options: IJwsSigningOptions = {
|
||||
protected: new TSMap([['typ', 'JWT']]),
|
||||
algorithm: <Algorithm> { name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' } },
|
||||
cryptoFactory: new CryptoFactory(keyStore, subtle)
|
||||
};
|
||||
const generate = new SubtleCryptoExtension(options.cryptoFactory);
|
||||
protected: new TSMap([['typ', 'JWT']]),
|
||||
algorithm: <Algorithm>{ name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' } },
|
||||
cryptoFactory: new CryptoFactory(keyStore, subtle)
|
||||
};
|
||||
const generate = new SubtleCryptoExtension(options.cryptoFactory);
|
||||
|
||||
const privateKey = await generate.generatePairwiseKey(options.algorithm, seedReference, 'did:personaId', 'did:peerId');
|
||||
(<any>privateKey).alg = 'ES256K';
|
||||
(<any>privateKey).defaultSignAlgorithm = 'ES256K';
|
||||
|
||||
await keyStore.save(new KeyReference('key'), privateKey);
|
||||
const jwsToken = new JwsToken(options);
|
||||
const signature = await jwsToken.sign(new KeyReference('key'), Buffer.from(payload), ProtectionFormat.JwsGeneralJson);
|
||||
expect((<TSMap<string, string>>signature.signatures[0].protected).get('typ')).toEqual('JWT');
|
||||
const privateKey = await generate.generatePairwiseKey(options.algorithm, seedReference, 'did:personaId', 'did:peerId');
|
||||
(<any>privateKey).alg = 'ES256K';
|
||||
(<any>privateKey).defaultSignAlgorithm = 'ES256K';
|
||||
|
||||
await keyStore.save(new KeyReference('key'), privateKey);
|
||||
const jwsToken = new JwsToken(options);
|
||||
const signature = await jwsToken.sign(new KeyReference('key'), Buffer.from(payload), ProtectionFormat.JwsGeneralJson);
|
||||
expect((<TSMap<string, string>>signature.signatures[0].protected).get('typ')).toEqual('JWT');
|
||||
});
|
||||
it('should create a jws token by means of key reference options', async () => {
|
||||
const payload = 'test payload';
|
||||
|
@ -61,36 +101,36 @@ describe('JwsToken', () => {
|
|||
await keyStore.save(new KeyReference(seedReference), new OctKey('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'));
|
||||
const subtle = SubtleCryptoNode.getSubtleCrypto();
|
||||
const options: IJwsSigningOptions = {
|
||||
algorithm: <Algorithm> { name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' } },
|
||||
cryptoFactory: new CryptoFactory(keyStore, subtle)
|
||||
};
|
||||
const generate = new SubtleCryptoExtension(options.cryptoFactory);
|
||||
algorithm: <Algorithm>{ name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' } },
|
||||
cryptoFactory: new CryptoFactory(keyStore, subtle)
|
||||
};
|
||||
const generate = new SubtleCryptoExtension(options.cryptoFactory);
|
||||
|
||||
const privateKey = await generate.generatePairwiseKey(options.algorithm, seedReference, 'did:personaId', 'did:peerId');
|
||||
(<any>privateKey).alg = 'ES256K';
|
||||
(<any>privateKey).defaultSignAlgorithm = 'ES256K';
|
||||
|
||||
await keyStore.save(new KeyReference('key'), privateKey);
|
||||
const jwsToken = new JwsToken(options);
|
||||
const signature = await jwsToken.sign(new KeyReference('key'), Buffer.from(payload), ProtectionFormat.JwsGeneralJson);
|
||||
expect(signature).toBeDefined();
|
||||
const privateKey = await generate.generatePairwiseKey(options.algorithm, seedReference, 'did:personaId', 'did:peerId');
|
||||
(<any>privateKey).alg = 'ES256K';
|
||||
(<any>privateKey).defaultSignAlgorithm = 'ES256K';
|
||||
|
||||
await keyStore.save(new KeyReference('key'), privateKey);
|
||||
const jwsToken = new JwsToken(options);
|
||||
const signature = await jwsToken.sign(new KeyReference('key'), Buffer.from(payload), ProtectionFormat.JwsGeneralJson);
|
||||
expect(signature).toBeDefined();
|
||||
});
|
||||
it('should create, validate and serialize a JwsToken', async () => {
|
||||
const payload = 'The true sign of intelligence is not knowledge but imagination.';
|
||||
const payload = 'The true sign of intelligence is not knowledge but imagination.';
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
await keyStore.save(new KeyReference('seed'), new OctKey('ABEE'));
|
||||
const cryptoFactory = new CryptoFactory(keyStore, SubtleCryptoNode.getSubtleCrypto())
|
||||
const options: IPayloadProtectionOptions = {
|
||||
cryptoFactory,
|
||||
options: new TSMap<string, any>([
|
||||
[JoseConstants.optionProtectedHeader, new TSMap([['typ', 'JWT']]) ]
|
||||
]),
|
||||
payloadProtection: new JoseProtocol()
|
||||
cryptoFactory,
|
||||
options: new TSMap<string, any>([
|
||||
[JoseConstants.optionProtectedHeader, new TSMap([['typ', 'JWT']])]
|
||||
]),
|
||||
payloadProtection: new JoseProtocol()
|
||||
};
|
||||
|
||||
|
||||
const alg = { name: 'RSASSA-PKCS1-V1_5', hash: 'SHA-256', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]) };
|
||||
const generator = new SubtleCryptoExtension(cryptoFactory);
|
||||
const privateKey = await generator.generatePairwiseKey(alg, 'seed', 'persona','peer');
|
||||
const privateKey = await generator.generatePairwiseKey(alg, 'seed', 'persona', 'peer');
|
||||
expect((<any>privateKey).alg).toBeUndefined();
|
||||
(<any>privateKey).alg = 'RS256';
|
||||
await keyStore.save(new KeyReference('key'), privateKey);
|
||||
|
@ -116,9 +156,11 @@ describe('JwsToken', () => {
|
|||
expect(deSignatures[0].protected).toEqual(signatures[0].protected);
|
||||
expect(deSignatures[0].signature).toEqual(signatures[0].signature);
|
||||
expect(deserialized.get(JoseConstants.tokenPayload)).toEqual(signature.get(JoseConstants.tokenPayload));
|
||||
let staticDeserialize = JoseProtocol.deserialize(serialized, options);
|
||||
expect(deserialized).toEqual(staticDeserialize);
|
||||
|
||||
// validate
|
||||
const publicKeyContainer = (await keyStore.get(new KeyReference('key'), new KeyStoreOptions({publicKeyOnly: true}))).getKey<PublicKey>();
|
||||
const publicKeyContainer = (await keyStore.get(new KeyReference('key'), new KeyStoreOptions({ publicKeyOnly: true }))).getKey<PublicKey>();
|
||||
const result = await options.payloadProtection.verify([publicKeyContainer], Buffer.from(payload), signature, options);
|
||||
expect(result.result).toBeTruthy();
|
||||
|
||||
|
@ -128,130 +170,161 @@ describe('JwsToken', () => {
|
|||
expect(parsed['payload']).toBeDefined();
|
||||
expect(parsed['protected']).toBeDefined();
|
||||
expect(parsed['signature']).toBeDefined();
|
||||
|
||||
|
||||
deserialized = options.payloadProtection.deserialize(serialized, 'JwsFlatJson', options);
|
||||
deSignatures = deserialized.get(JoseConstants.tokenSignatures);
|
||||
expect(deSignatures[0].protected).toEqual(signatures[0].protected);
|
||||
expect(deSignatures[0].signature).toEqual(signatures[0].signature);
|
||||
expect(deserialized.get(JoseConstants.tokenPayload)).toEqual(signature.get(JoseConstants.tokenPayload));
|
||||
staticDeserialize = JoseProtocol.deserialize(serialized, options);
|
||||
expect(deserialized).toEqual(staticDeserialize);
|
||||
|
||||
// Compact serialization
|
||||
serialized = options.payloadProtection.serialize(signature, 'JwsCompactJson', options);
|
||||
parsed = serialized.split('.');
|
||||
expect(parsed.length).toEqual(3);
|
||||
|
||||
deserialized = options.payloadProtection.deserialize(serialized, 'JwsCompactJson', options);
|
||||
deSignatures = deserialized.get(JoseConstants.tokenSignatures);
|
||||
expect(deSignatures[0].protected).toEqual(signatures[0].protected);
|
||||
expect(deSignatures[0].signature).toEqual(signatures[0].signature);
|
||||
expect(deserialized.get(JoseConstants.tokenPayload)).toEqual(signature.get(JoseConstants.tokenPayload));
|
||||
staticDeserialize = JoseProtocol.deserialize(serialized, options);
|
||||
expect(deserialized).toEqual(staticDeserialize);
|
||||
|
||||
// negative cases
|
||||
let getProtectionFormatSpy: jasmine.Spy = spyOn(<JoseProtocol>options.payloadProtection, 'getProtectionFormat').and.callFake(() => {
|
||||
throw new Error('spy bad format');
|
||||
});
|
||||
try {
|
||||
options.payloadProtection.serialize(signature, 'JwsCompactJson', options);
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual('spy bad format');
|
||||
}
|
||||
try {
|
||||
options.payloadProtection.deserialize(serialized, 'JwsCompactJson', options);
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual('spy bad format');
|
||||
}
|
||||
getProtectionFormatSpy.and.callFake(() => {
|
||||
return 'aaa';
|
||||
});
|
||||
try {
|
||||
options.payloadProtection.serialize(signature, 'JwsCompactJson', options);
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual( `Serialization format 'aaa' is not supported`);
|
||||
}
|
||||
try {
|
||||
options.payloadProtection.deserialize(serialized, 'JwsCompactJson', options);
|
||||
} catch (exception) {
|
||||
expect(exception.message).toEqual(`Serialization format 'aaa' is not supported`);
|
||||
}
|
||||
});
|
||||
|
||||
// tslint:disable-next-line: max-func-body-length
|
||||
it('should set headers in JwsToken', async () => {
|
||||
const payload = 'The true sign of intelligence is not knowledge but imagination.';
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
await keyStore.save(new KeyReference('seed'), new OctKey('ABEE'));
|
||||
const cryptoFactory = new CryptoFactory(keyStore, SubtleCryptoNode.getSubtleCrypto())
|
||||
const options: IPayloadProtectionOptions = {
|
||||
cryptoFactory: cryptoFactory,
|
||||
options: new TSMap<string, any>([
|
||||
[JoseConstants.optionHeader, new TSMap([['test', 'ES256K']])],
|
||||
[JoseConstants.optionProtectedHeader, new TSMap([['test', 'elo'], ['kid', 'random']])]
|
||||
]),
|
||||
payloadProtection: new JoseProtocol()
|
||||
};
|
||||
|
||||
const alg = { name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' }, format: 'DER' };
|
||||
const generator = new SubtleCryptoExtension(cryptoFactory);
|
||||
const privateKey = await generator.generatePairwiseKey(alg, 'seed', 'persona', 'peer');
|
||||
(<any>privateKey).alg = 'ES256K';
|
||||
await keyStore.save(new KeyReference('key'), privateKey);
|
||||
let publicKey = await keyStore.get(new KeyReference('key'));
|
||||
|
||||
// sign
|
||||
const signature = await options.payloadProtection.sign(new KeyReference('key'), Buffer.from(payload), 'JwsGeneralJson', options);
|
||||
const signatures = signature.get(JoseConstants.tokenSignatures);
|
||||
expect(signatures[0].protected.get('test')).toEqual('elo');
|
||||
expect(signatures[0].protected.get('kid')).toEqual('random');
|
||||
expect(signatures[0].header.get('test')).toEqual('ES256K');
|
||||
expect(signatures[0].signature).toBeDefined();
|
||||
expect(signature.get(JoseConstants.tokenPayload)).toEqual(Buffer.from(payload));
|
||||
|
||||
// serialize
|
||||
let serialized = options.payloadProtection.serialize(signature, 'JwsGeneralJson', options);
|
||||
let parsed = JSON.parse(serialized);
|
||||
expect(parsed['payload']).toBeDefined();
|
||||
expect(parsed['signatures']).toBeDefined();
|
||||
|
||||
// deserialize
|
||||
let deserialized = options.payloadProtection.deserialize(serialized, 'JwsGeneralJson', options);
|
||||
let deSignatures = deserialized.get(JoseConstants.tokenSignatures);
|
||||
expect(deSignatures[0].protected).toEqual(signatures[0].protected);
|
||||
expect(deSignatures[0].header).toEqual(signatures[0].header);
|
||||
expect(deSignatures[0].signature).toEqual(signatures[0].signature);
|
||||
expect(deserialized.get(JoseConstants.tokenPayload)).toEqual(signature.get(JoseConstants.tokenPayload));
|
||||
|
||||
// validate
|
||||
const publicKeyContainer = (await keyStore.get(new KeyReference('key'), new KeyStoreOptions({ publicKeyOnly: true }))).getKey<PublicKey>();
|
||||
const result = await options.payloadProtection.verify([publicKeyContainer], Buffer.from(payload), signature, options);
|
||||
expect(result.result).toBeTruthy();
|
||||
|
||||
// Flat serialization
|
||||
serialized = options.payloadProtection.serialize(signature, 'JwsFlatJson', options);
|
||||
parsed = JSON.parse(serialized);
|
||||
expect(parsed['payload']).toBeDefined();
|
||||
expect(parsed['protected']).toBeDefined();
|
||||
expect(parsed['header']).toBeDefined();
|
||||
expect(parsed['signature']).toBeDefined();
|
||||
|
||||
deserialized = options.payloadProtection.deserialize(serialized, 'JwsFlatJson', options);
|
||||
deSignatures = deserialized.get(JoseConstants.tokenSignatures);
|
||||
expect(deSignatures[0].protected).toEqual(signatures[0].protected);
|
||||
expect(deSignatures[0].header).toEqual(signatures[0].header);
|
||||
expect(deSignatures[0].signature).toEqual(signatures[0].signature);
|
||||
expect(deserialized.get(JoseConstants.tokenPayload)).toEqual(signature.get(JoseConstants.tokenPayload));
|
||||
|
||||
// Compact serialization
|
||||
serialized = options.payloadProtection.serialize(signature, 'JwsCompactJson', options);
|
||||
parsed = serialized.split('.');
|
||||
expect(parsed.length).toEqual(3);
|
||||
|
||||
|
||||
deserialized = options.payloadProtection.deserialize(serialized, 'JwsCompactJson', options);
|
||||
deSignatures = deserialized.get(JoseConstants.tokenSignatures);
|
||||
expect(deSignatures[0].protected).toEqual(signatures[0].protected);
|
||||
expect(deSignatures[0].signature).toEqual(signatures[0].signature);
|
||||
expect(deserialized.get(JoseConstants.tokenPayload)).toEqual(signature.get(JoseConstants.tokenPayload));
|
||||
|
||||
});
|
||||
// negative cases
|
||||
let throwed = false;
|
||||
try {
|
||||
options.payloadProtection.serialize(signature, 'bluesky', options);
|
||||
} catch (err) {
|
||||
throwed = true;
|
||||
expect(err.message).toEqual(`Format 'bluesky' is not supported`);
|
||||
}
|
||||
expect(throwed).toBeTruthy();
|
||||
|
||||
// tslint:disable-next-line: max-func-body-length
|
||||
it('should set headers in JwsToken', async () => {
|
||||
const payload = 'The true sign of intelligence is not knowledge but imagination.';
|
||||
const keyStore = new KeyStoreInMemory();
|
||||
await keyStore.save(new KeyReference('seed'), new OctKey('ABEE'));
|
||||
const cryptoFactory = new CryptoFactory(keyStore, SubtleCryptoNode.getSubtleCrypto())
|
||||
const options: IPayloadProtectionOptions = {
|
||||
cryptoFactory: cryptoFactory,
|
||||
options: new TSMap<string, any>([
|
||||
[JoseConstants.optionHeader, new TSMap([['test', 'ES256K']]) ],
|
||||
[JoseConstants.optionProtectedHeader, new TSMap([['test', 'elo'], ['kid', 'random']]) ]
|
||||
]),
|
||||
payloadProtection: new JoseProtocol()
|
||||
};
|
||||
|
||||
const alg = { name: 'ECDSA', namedCurve: 'secp256k1', hash: { name: 'SHA-256' }, format: 'DER' };
|
||||
const generator = new SubtleCryptoExtension(cryptoFactory);
|
||||
const privateKey = await generator.generatePairwiseKey(alg, 'seed', 'persona','peer');
|
||||
(<any>privateKey).alg = 'ES256K';
|
||||
await keyStore.save(new KeyReference('key'), privateKey);
|
||||
let publicKey = await keyStore.get(new KeyReference('key'));
|
||||
throwed = false;
|
||||
try {
|
||||
options.payloadProtection.deserialize(serialized, 'bluesky', options);
|
||||
} catch (err) {
|
||||
throwed = true;
|
||||
expect(err.message).toEqual(`Format 'bluesky' is not supported`);
|
||||
}
|
||||
expect(throwed).toBeTruthy();
|
||||
|
||||
// sign
|
||||
const signature = await options.payloadProtection.sign(new KeyReference('key'), Buffer.from(payload), 'JwsGeneralJson', options);
|
||||
const signatures = signature.get(JoseConstants.tokenSignatures);
|
||||
expect(signatures[0].protected.get('test')).toEqual('elo');
|
||||
expect(signatures[0].protected.get('kid')).toEqual('random');
|
||||
expect(signatures[0].header.get('test')).toEqual('ES256K');
|
||||
expect(signatures[0].signature).toBeDefined();
|
||||
expect(signature.get(JoseConstants.tokenPayload)).toEqual(Buffer.from(payload));
|
||||
|
||||
// serialize
|
||||
let serialized = options.payloadProtection.serialize(signature, 'JwsGeneralJson', options);
|
||||
let parsed = JSON.parse(serialized);
|
||||
expect(parsed['payload']).toBeDefined();
|
||||
expect(parsed['signatures']).toBeDefined();
|
||||
|
||||
// deserialize
|
||||
let deserialized = options.payloadProtection.deserialize(serialized, 'JwsGeneralJson', options);
|
||||
let deSignatures = deserialized.get(JoseConstants.tokenSignatures);
|
||||
expect(deSignatures[0].protected).toEqual(signatures[0].protected);
|
||||
expect(deSignatures[0].header).toEqual(signatures[0].header);
|
||||
expect(deSignatures[0].signature).toEqual(signatures[0].signature);
|
||||
expect(deserialized.get(JoseConstants.tokenPayload)).toEqual(signature.get(JoseConstants.tokenPayload));
|
||||
|
||||
// validate
|
||||
const publicKeyContainer = (await keyStore.get(new KeyReference('key'), new KeyStoreOptions({publicKeyOnly: true}))).getKey<PublicKey>();
|
||||
const result = await options.payloadProtection.verify([publicKeyContainer], Buffer.from(payload), signature, options);
|
||||
expect(result.result).toBeTruthy();
|
||||
|
||||
// Flat serialization
|
||||
serialized = options.payloadProtection.serialize(signature, 'JwsFlatJson', options);
|
||||
parsed = JSON.parse(serialized);
|
||||
expect(parsed['payload']).toBeDefined();
|
||||
expect(parsed['protected']).toBeDefined();
|
||||
expect(parsed['header']).toBeDefined();
|
||||
expect(parsed['signature']).toBeDefined();
|
||||
|
||||
deserialized = options.payloadProtection.deserialize(serialized, 'JwsFlatJson', options);
|
||||
deSignatures = deserialized.get(JoseConstants.tokenSignatures);
|
||||
expect(deSignatures[0].protected).toEqual(signatures[0].protected);
|
||||
expect(deSignatures[0].header).toEqual(signatures[0].header);
|
||||
expect(deSignatures[0].signature).toEqual(signatures[0].signature);
|
||||
expect(deserialized.get(JoseConstants.tokenPayload)).toEqual(signature.get(JoseConstants.tokenPayload));
|
||||
|
||||
// Compact serialization
|
||||
serialized = options.payloadProtection.serialize(signature, 'JwsCompactJson', options);
|
||||
parsed = serialized.split('.');
|
||||
expect(parsed.length).toEqual(3);
|
||||
|
||||
deserialized = options.payloadProtection.deserialize(serialized, 'JwsCompactJson', options);
|
||||
deSignatures = deserialized.get(JoseConstants.tokenSignatures);
|
||||
expect(deSignatures[0].protected).toEqual(signatures[0].protected);
|
||||
expect(deSignatures[0].signature).toEqual(signatures[0].signature);
|
||||
expect(deserialized.get(JoseConstants.tokenPayload)).toEqual(signature.get(JoseConstants.tokenPayload));
|
||||
|
||||
// negative cases
|
||||
let throwed = false;
|
||||
try {
|
||||
options.payloadProtection.serialize(signature, 'bluesky', options);
|
||||
} catch (err) {
|
||||
throwed = true;
|
||||
expect(err.message).toEqual(`Format 'bluesky' is not supported`);
|
||||
}
|
||||
expect(throwed).toBeTruthy();
|
||||
|
||||
throwed = false;
|
||||
try {
|
||||
options.payloadProtection.deserialize(serialized, 'bluesky', options);
|
||||
} catch (err) {
|
||||
throwed = true;
|
||||
expect(err.message).toEqual(`Format 'bluesky' is not supported`);
|
||||
}
|
||||
expect(throwed).toBeTruthy();
|
||||
|
||||
const sigs = signature.get(JoseConstants.tokenSignatures);
|
||||
sigs[0].protected.set('alg', '');
|
||||
throwed = false;
|
||||
try {
|
||||
await options.payloadProtection.verify([publicKey], Buffer.from(payload), signature, options);
|
||||
} catch (err) {
|
||||
expect(err.message).toEqual('Unable to validate signature as no signature algorithm has been specified in the header.');
|
||||
throwed = true;
|
||||
}
|
||||
expect(throwed).toBeTruthy();
|
||||
});
|
||||
const sigs = signature.get(JoseConstants.tokenSignatures);
|
||||
sigs[0].protected.set('alg', '');
|
||||
throwed = false;
|
||||
try {
|
||||
await options.payloadProtection.verify([publicKey], Buffer.from(payload), signature, options);
|
||||
} catch (err) {
|
||||
expect(err.message).toEqual('Unable to validate signature as no signature algorithm has been specified in the header.');
|
||||
throwed = true;
|
||||
}
|
||||
expect(throwed).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "verifiablecredentials-crypto-sdk-typescript-protocols-common",
|
||||
"version": "1.1.12-preview.0",
|
||||
"version": "1.1.12-preview.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/VerifiableCredentials-Crypto-SDK-Typescript.git"
|
||||
|
@ -39,9 +39,9 @@
|
|||
"typescript": "4.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.1",
|
||||
"base64url": "3.0.1",
|
||||
"typescript-map": "0.0.7",
|
||||
"webcrypto-core": "1.1.8"
|
||||
|
|
|
@ -20,11 +20,11 @@ export default class LongFormDid {
|
|||
// See https://github.com/diafygi/webcrypto-examples for examples how to use the W3C web Crypto stamdard
|
||||
|
||||
if (!this.crypto.builder.signingKeyReference) {
|
||||
throw new Error(`No signing key reference. Use CryptoBuilder.useSigningKeyReference.`)
|
||||
return Promise.reject(new Error(`No signing key reference. Use CryptoBuilder.useSigningKeyReference.`));
|
||||
}
|
||||
|
||||
if (!this.crypto.builder.recoveryKeyReference) {
|
||||
throw new Error(`No recovery key reference. Use CryptoBuilder.useRecoveryKeyReference.`)
|
||||
return Promise.reject(new Error(`No recovery key reference. Use CryptoBuilder.useRecoveryKeyReference.`));
|
||||
}
|
||||
|
||||
let signingPublic = await (await this.crypto.builder.keyStore.get(this.crypto.builder.signingKeyReference, new KeyStoreOptions({publicKeyOnly: true}))).getKey<JsonWebKey>();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "verifiablecredentials-crypto-sdk-typescript",
|
||||
"version": "1.1.12-preview.0",
|
||||
"version": "1.1.12-preview.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/VerifiableCredentials-Crypto-SDK-Typescript.git"
|
||||
|
@ -53,15 +53,15 @@
|
|||
"jsonld": "2.0.2",
|
||||
"typescript-map": "0.0.7",
|
||||
"uuid": "^8.3.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-cryptofactory-suites": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-elliptic": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-factory": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-keyvault": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-protocol-jose": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-protocols-common": "1.1.12-preview.0",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keys": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-keystore": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-cryptofactory-suites": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-elliptic": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-factory": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-plugin-keyvault": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-protocol-jose": "1.1.12-preview.1",
|
||||
"verifiablecredentials-crypto-sdk-typescript-protocols-common": "1.1.12-preview.1",
|
||||
"webcrypto-core": "1.1.8"
|
||||
},
|
||||
"nyc": {
|
||||
|
|
Загрузка…
Ссылка в новой задаче