diff --git a/.vscode/settings.json b/.vscode/settings.json index 3662b3700..b8b47cbab 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,7 @@ { - "typescript.tsdk": "node_modules/typescript/lib" + "typescript.tsdk": "node_modules/typescript/lib", + "cSpell.words": [ + "arrayify", + "ethersproject" + ] } \ No newline at end of file diff --git a/__tests__/shared/keyManager.ts b/__tests__/shared/keyManager.ts index 246f7fc18..7c60d6266 100644 --- a/__tests__/shared/keyManager.ts +++ b/__tests__/shared/keyManager.ts @@ -1,4 +1,7 @@ +import { TKeyType } from '@veramo/core' import { TAgent, IDIDManager, IKeyManager, IAgentOptions } from '../../packages/core/src' +import { ICredentialIssuer } from '@veramo/credential-w3c/src' +import { serialize } from '@ethersproject/transactions' type ConfiguredAgent = TAgent @@ -179,8 +182,8 @@ export default (testContext: { transaction: { to: '0xce31a19193d4b23f4e9d6163d7247243bAF801c3', value: 300000, - gas: 43092000, - gasPrice: '20000000000', + gasLimit: 43092000, + gasPrice: 20000000000, nonce: 1, }, }) @@ -218,5 +221,117 @@ export default (testContext: { // expect(decrypted).toEqual(message) // }) + + describe('using Secp256k1 testvectors', () => { + const importedKey = { + kid: + '04155ee0cbefeecd80de63a62b4ed8f0f97ac22a58f76a265903b9acab79bf018c7037e2bd897812170c92a4c978d6a10481491a37299d74c4bd412a111a4ac875', + kms: 'local', + type: 'Secp256k1', + publicKeyHex: + '04155ee0cbefeecd80de63a62b4ed8f0f97ac22a58f76a265903b9acab79bf018c7037e2bd897812170c92a4c978d6a10481491a37299d74c4bd412a111a4ac875', + privateKeyHex: '31d1ec15ff8110442012fef0d1af918c0e09b2e2ab821bba52ecc85f8655ec63', + } + + beforeAll(async () => { + const imported = await agent.keyManagerImport(importedKey) + }) + + it('should sign JWT using legacy method', async () => { + const signature = await agent.keyManagerSignJWT({ + kid: importedKey.kid, + data: 'bla.bla', + }) + expect(signature).toEqual( + 'pNAFkgmuKhqMbb_6Km--ZmY7UCkWunWUuNajSfF6rv5lEa5nNXCU7cnZBZVptU7u8h150qetqkqUaahAf-Cepw', + ) + }) + + it('should sign EthTX using legacy method', async () => { + const rawTx = await agent.keyManagerSignEthTX({ + kid: importedKey.kid, + transaction: { + to: '0xce31a19193d4b23f4e9d6163d7247243bAF801c3', + value: 300000, + gasLimit: 43092000, + gasPrice: 20000000000, + nonce: 1, + }, + }) + expect(rawTx).toEqual( + '0xf869018504a817c800840291882094ce31a19193d4b23f4e9d6163d7247243baf801c3830493e0801ba0f16e2206290181c3feaa04051dad19089105c24339dbdf0d80147b48a59fa152a0770e8751ec77ccc78e8b207023f168444f7cfb67055c55c70ef75234458a3d51', + ) + }) + + it('should sign JWT using generic signer', async () => { + const signature = await agent.keyManagerSign({ + algorithm: 'ES256K', + data: 'bla.bla', + encoding: 'utf-8', + keyRef: importedKey.kid, + }) + expect(signature).toEqual( + 'pNAFkgmuKhqMbb_6Km--ZmY7UCkWunWUuNajSfF6rv5lEa5nNXCU7cnZBZVptU7u8h150qetqkqUaahAf-Cepw', + ) + }) + + it('should sign EthTX using generic signer', async () => { + const txData = serialize({ + to: '0xce31a19193d4b23f4e9d6163d7247243bAF801c3', + value: 300000, + gasLimit: 43092000, + gasPrice: 20000000000, + nonce: 1, + }) + + const rawTx = await agent.keyManagerSign({ + algorithm: 'eth_signTransaction', + data: txData, + encoding: 'hex', + keyRef: importedKey.kid, + }) + + expect(rawTx).toEqual( + '0xf869018504a817c800840291882094ce31a19193d4b23f4e9d6163d7247243baf801c3830493e0801ba0f16e2206290181c3feaa04051dad19089105c24339dbdf0d80147b48a59fa152a0770e8751ec77ccc78e8b207023f168444f7cfb67055c55c70ef75234458a3d51', + ) + }) + }) + + describe('using Ed25519 testvectors', () => { + const importedKey = { + kid: 'ea75250531f6834328ac210618253288e4c54632962a9708ca82e4a399f79000', + kms: 'local', + type: 'Ed25519', + publicKeyHex: 'ea75250531f6834328ac210618253288e4c54632962a9708ca82e4a399f79000', + privateKeyHex: + '65f341541643070564bb48d9fc10556f2dec246fa056e436a8ec1cdef8c74766ea75250531f6834328ac210618253288e4c54632962a9708ca82e4a399f79000', + } + + beforeAll(async () => { + const imported = await agent.keyManagerImport(importedKey) + }) + + it('should sign JWT using legacy method', async () => { + const signature = await agent.keyManagerSignJWT({ + kid: importedKey.kid, + data: 'bla.bla', + }) + expect(signature).toEqual( + '_2P0iukN2CPH1nQ6LeBm1zQHHp3U4wSYDrpeWTWkp7yuzJex6O60Z4OhdfD5I9WPHV734US8n5vyD2VDbT1UCg', + ) + }) + + it('should sign JWT using generic signer', async () => { + const signature = await agent.keyManagerSign({ + keyRef: importedKey.kid, + data: 'bla.bla', + algorithm: 'EdDSA', + encoding: 'utf-8', + }) + expect(signature).toEqual( + '_2P0iukN2CPH1nQ6LeBm1zQHHp3U4wSYDrpeWTWkp7yuzJex6O60Z4OhdfD5I9WPHV734US8n5vyD2VDbT1UCg', + ) + }) + }) }) } diff --git a/__tests__/shared/verifiableData.ts b/__tests__/shared/verifiableData.ts index 144a2d1c8..4caa099c2 100644 --- a/__tests__/shared/verifiableData.ts +++ b/__tests__/shared/verifiableData.ts @@ -2,6 +2,7 @@ import { TAgent, IDIDManager, IIdentifier, IDataStore } from '../../packages/cor import { IDataStoreORM } from '../../packages/data-store/src' import { ICredentialIssuer } from '../../packages/credential-w3c/src' import { decodeJWT } from 'did-jwt' +import { TKeyType } from '@veramo/core' type ConfiguredAgent = TAgent @@ -239,5 +240,51 @@ export default (testContext: { }), ).rejects.toThrow('Verifiable presentation not found') }) + + describe('using testvectors', () => { + const importedDID = { + did: 'did:ethr:rinkeby:0x03155ee0cbefeecd80de63a62b4ed8f0f97ac22a58f76a265903b9acab79bf018c', + provider: 'did:ethr:rinkeby', + controllerKeyId: + '04155ee0cbefeecd80de63a62b4ed8f0f97ac22a58f76a265903b9acab79bf018c7037e2bd897812170c92a4c978d6a10481491a37299d74c4bd412a111a4ac875', + keys: [ + { + kid: + '04155ee0cbefeecd80de63a62b4ed8f0f97ac22a58f76a265903b9acab79bf018c7037e2bd897812170c92a4c978d6a10481491a37299d74c4bd412a111a4ac875', + kms: 'local', + type: 'Secp256k1', + publicKeyHex: + '04155ee0cbefeecd80de63a62b4ed8f0f97ac22a58f76a265903b9acab79bf018c7037e2bd897812170c92a4c978d6a10481491a37299d74c4bd412a111a4ac875', + privateKeyHex: '31d1ec15ff8110442012fef0d1af918c0e09b2e2ab821bba52ecc85f8655ec63', + }, + ], + services: [], + } + + beforeAll(async () => { + const imported = await agent.didManagerImport(importedDID) + }) + + it('signs JWT with ES256K', async () => { + const credentialInput = { + credentialSubject: { id: 'did:example:subject', name: 'Alice' }, + issuer: { id: importedDID.did }, + } + const { proof, issuanceDate, ...comparableOutput } = await agent.createVerifiableCredential({ + credential: credentialInput, + proofFormat: 'jwt', + save: false, + removeOriginalFields: true, + }) + expect(comparableOutput).toEqual({ + credentialSubject: { name: 'Alice', id: 'did:example:subject' }, + issuer: { + id: 'did:ethr:rinkeby:0x03155ee0cbefeecd80de63a62b4ed8f0f97ac22a58f76a265903b9acab79bf018c', + }, + type: ['VerifiableCredential'], + '@context': ['https://www.w3.org/2018/credentials/v1'], + }) + }) + }) }) } diff --git a/packages/cli/default/default.yml b/packages/cli/default/default.yml index d36ed704f..43630dd5b 100644 --- a/packages/cli/default/default.yml +++ b/packages/cli/default/default.yml @@ -13,6 +13,7 @@ constants: - keyManagerImport - keyManagerEncryptJWE - keyManagerDecryptJWE + - keyManagerSign - keyManagerSignJWT - keyManagerSignEthTX - didManagerGetProviders diff --git a/packages/core/plugin.schema.json b/packages/core/plugin.schema.json index c8b87c794..26c1d8c17 100644 --- a/packages/core/plugin.schema.json +++ b/packages/core/plugin.schema.json @@ -17,7 +17,7 @@ "required": [ "didUrl" ], - "description": "Input arguments for {@link IResolver.resolveDid | resolveDid}" + "description": "Input arguments for {@link IResolver.resolveDid | resolveDid }" }, "DIDResolutionOptions": { "type": "object", @@ -349,7 +349,7 @@ "description": "Key Management System" }, "meta": { - "type": "object", + "$ref": "#/components/schemas/KeyMetadata", "description": "Optional. Key meta data" } }, @@ -357,7 +357,7 @@ "type", "kms" ], - "description": "Input arguments for {@link IKeyManager.keyManagerCreate | keyManagerCreate}" + "description": "Input arguments for {@link IKeyManager.keyManagerCreate | keyManagerCreate }" }, "TKeyType": { "type": "string", @@ -367,6 +367,17 @@ ], "description": "Cryptographic key type" }, + "KeyMetadata": { + "type": "object", + "properties": { + "algorithms": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "IKey": { "type": "object", "properties": { @@ -393,13 +404,13 @@ "meta": { "anyOf": [ { - "type": "object" + "$ref": "#/components/schemas/KeyMetadata" }, { "type": "null" } ], - "description": "Optional. Key metadata. Can be used to store auth data to access remote kms" + "description": "Optional. Key metadata. This should be used to determine which algorithms are supported." } }, "required": [ @@ -426,7 +437,7 @@ "kid", "data" ], - "description": "Input arguments for {@link IKeyManager.keyManagerDecryptJWE | keyManagerDecryptJWE}" + "description": "Input arguments for {@link IKeyManager.keyManagerDecryptJWE | keyManagerDecryptJWE }" }, "IKeyManagerDeleteArgs": { "type": "object", @@ -439,7 +450,7 @@ "required": [ "kid" ], - "description": "Input arguments for {@link IKeyManager.keyManagerDelete | keyManagerDelete}" + "description": "Input arguments for {@link IKeyManager.keyManagerDelete | keyManagerDelete }" }, "IKeyManagerEncryptJWEArgs": { "type": "object", @@ -470,13 +481,13 @@ "meta": { "anyOf": [ { - "type": "object" + "$ref": "#/components/schemas/KeyMetadata" }, { "type": "null" } ], - "description": "Optional. Key metadata. Can be used to store auth data to access remote kms" + "description": "Optional. Key metadata. This should be used to determine which algorithms are supported." } }, "required": [ @@ -496,7 +507,7 @@ "to", "data" ], - "description": "Input arguments for {@link IKeyManager.keyManagerEncryptJWE | keyManagerEncryptJWE}" + "description": "Input arguments for {@link IKeyManager.keyManagerEncryptJWE | keyManagerEncryptJWE }" }, "IKeyManagerGetArgs": { "type": "object", @@ -509,7 +520,39 @@ "required": [ "kid" ], - "description": "Input arguments for {@link IKeyManager.keyManagerGet | keyManagerGet}" + "description": "Input arguments for {@link IKeyManager.keyManagerGet | keyManagerGet }" + }, + "IKeyManagerSignArgs": { + "type": "object", + "properties": { + "keyRef": { + "type": "string", + "description": "The key handle, as returned during `keyManagerCreateKey`" + }, + "algorithm": { + "type": "string", + "description": "The algorithm to use for signing. This must be one of the algorithms supported by the KMS for this key type.\n\nThe algorithm used here should match one of the names listed in `IKey.meta.algorithms`" + }, + "data": { + "type": "string", + "description": "Data to sign" + }, + "encoding": { + "type": "string", + "enum": [ + "utf-8", + "base16", + "base64", + "hex" + ], + "description": "If the data is a \"string\" then you can specify which encoding is used. Default is \"utf-8\"" + } + }, + "required": [ + "keyRef", + "data" + ], + "description": "Input arguments for {@link IKeyManager.keyManagerSign | keyManagerSign }" }, "IKeyManagerSignEthTXArgs": { "type": "object", @@ -527,7 +570,7 @@ "kid", "transaction" ], - "description": "Input arguments for {@link IKeyManager.keyManagerSignEthTX | keyManagerSignEthTX}" + "description": "Input arguments for {@link IKeyManager.keyManagerSignEthTX | keyManagerSignEthTX }" }, "IKeyManagerSignJWTArgs": { "type": "object", @@ -592,7 +635,7 @@ "kid", "data" ], - "description": "Input arguments for {@link IKeyManager.keyManagerSignJWT | keyManagerSignJWT}" + "description": "Input arguments for {@link IKeyManager.keyManagerSignJWT | keyManagerSignJWT }" } }, "methods": { @@ -662,6 +705,15 @@ "type": "boolean" } }, + "keyManagerSign": { + "description": "Generates a signature according to the algorithm specified.", + "arguments": { + "$ref": "#/components/schemas/IKeyManagerSignArgs" + }, + "returnType": { + "type": "string" + } + }, "keyManagerSignEthTX": { "description": "Signs Ethereum transaction", "arguments": { @@ -706,7 +758,7 @@ "did", "key" ], - "description": "Input arguments for {@link IDIDManager.didManagerAddKey | didManagerAddKey}" + "description": "Input arguments for {@link IDIDManager.didManagerAddKey | didManagerAddKey }" }, "IKey": { "type": "object", @@ -734,13 +786,13 @@ "meta": { "anyOf": [ { - "type": "object" + "$ref": "#/components/schemas/KeyMetadata" }, { "type": "null" } ], - "description": "Optional. Key metadata. Can be used to store auth data to access remote kms" + "description": "Optional. Key metadata. This should be used to determine which algorithms are supported." } }, "required": [ @@ -759,6 +811,17 @@ ], "description": "Cryptographic key type" }, + "KeyMetadata": { + "type": "object", + "properties": { + "algorithms": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "IDIDManagerAddServiceArgs": { "type": "object", "properties": { @@ -779,7 +842,7 @@ "did", "service" ], - "description": "Input arguments for {@link IDIDManager.didManagerAddService | didManagerAddService}" + "description": "Input arguments for {@link IDIDManager.didManagerAddService | didManagerAddService }" }, "IService": { "type": "object", @@ -828,7 +891,7 @@ "description": "Optional. Identifier provider specific options" } }, - "description": "Input arguments for {@link IDIDManager.didManagerCreate | didManagerCreate}" + "description": "Input arguments for {@link IDIDManager.didManagerCreate | didManagerCreate }" }, "IIdentifier": { "type": "object", @@ -883,7 +946,7 @@ "required": [ "did" ], - "description": "Input arguments for {@link IDIDManager.didManagerDelete | didManagerDelete}" + "description": "Input arguments for {@link IDIDManager.didManagerDelete | didManagerDelete }" }, "IDIDManagerFindArgs": { "type": "object", @@ -897,7 +960,7 @@ "description": "Optional. Provider" } }, - "description": "Input arguments for {@link IDIDManager.didManagerFind | didManagerFind}" + "description": "Input arguments for {@link IDIDManager.didManagerFind | didManagerFind }" }, "IDIDManagerGetArgs": { "type": "object", @@ -910,7 +973,7 @@ "required": [ "did" ], - "description": "Input arguments for {@link IDIDManager.didManagerGet | didManagerGet}" + "description": "Input arguments for {@link IDIDManager.didManagerGet | didManagerGet }" }, "IDIDManagerGetByAliasArgs": { "type": "object", @@ -927,7 +990,7 @@ "required": [ "alias" ], - "description": "Input arguments for {@link IDIDManager.didManagerGetByAlias | didManagerGetByAlias}" + "description": "Input arguments for {@link IDIDManager.didManagerGetByAlias | didManagerGetByAlias }" }, "IDIDManagerGetOrCreateArgs": { "type": "object", @@ -952,7 +1015,7 @@ "required": [ "alias" ], - "description": "Input arguments for {@link IDIDManager.didManagerGetOrCreate | didManagerGetOrCreate}" + "description": "Input arguments for {@link IDIDManager.didManagerGetOrCreate | didManagerGetOrCreate }" }, "IDIDManagerRemoveKeyArgs": { "type": "object", @@ -974,7 +1037,7 @@ "did", "kid" ], - "description": "Input arguments for {@link IDIDManager.didManagerRemoveKey | didManagerRemoveKey}" + "description": "Input arguments for {@link IDIDManager.didManagerRemoveKey | didManagerRemoveKey }" }, "IDIDManagerRemoveServiceArgs": { "type": "object", @@ -996,7 +1059,7 @@ "did", "id" ], - "description": "Input arguments for {@link IDIDManager.didManagerRemoveService | didManagerRemoveService}" + "description": "Input arguments for {@link IDIDManager.didManagerRemoveService | didManagerRemoveService }" }, "IDIDManagerSetAliasArgs": { "type": "object", @@ -1014,7 +1077,7 @@ "did", "alias" ], - "description": "Input arguments for {@link IDIDManager.didManagerSetAlias | didManagerSetAlias}" + "description": "Input arguments for {@link IDIDManager.didManagerSetAlias | didManagerSetAlias }" } }, "methods": { @@ -1158,7 +1221,7 @@ "required": [ "id" ], - "description": "Input arguments for {@link IDataStore.dataStoreGetMessage | dataStoreGetMessage}" + "description": "Input arguments for {@link IDataStore.dataStoreGetMessage | dataStoreGetMessage }" }, "IMessage": { "type": "object", @@ -1344,7 +1407,7 @@ "credentialSubject", "proof" ], - "description": "Verifiable Credential {@link https://github.com/decentralized-identifier/did-jwt-vc}" + "description": "Verifiable Credential {@link https://github.com/decentralized-identifier/did-jwt-vc }" }, "VerifiablePresentation": { "type": "object", @@ -1402,7 +1465,7 @@ "verifiableCredential", "proof" ], - "description": "Verifiable Presentation {@link https://github.com/decentralized-identifier/did-jwt-vc}" + "description": "Verifiable Presentation {@link https://github.com/decentralized-identifier/did-jwt-vc }" }, "IDataStoreGetVerifiableCredentialArgs": { "type": "object", @@ -1415,7 +1478,7 @@ "required": [ "hash" ], - "description": "Input arguments for {@link IDataStore.dataStoreGetVerifiableCredential | dataStoreGetVerifiableCredential}" + "description": "Input arguments for {@link IDataStore.dataStoreGetVerifiableCredential | dataStoreGetVerifiableCredential }" }, "IDataStoreGetVerifiablePresentationArgs": { "type": "object", @@ -1428,7 +1491,7 @@ "required": [ "hash" ], - "description": "Input arguments for {@link IDataStore.dataStoreGetVerifiablePresentation | dataStoreGetVerifiablePresentation}" + "description": "Input arguments for {@link IDataStore.dataStoreGetVerifiablePresentation | dataStoreGetVerifiablePresentation }" }, "IDataStoreSaveMessageArgs": { "type": "object", @@ -1441,7 +1504,7 @@ "required": [ "message" ], - "description": "Input arguments for {@link IDataStore.dataStoreSaveMessage | dataStoreSaveMessage}" + "description": "Input arguments for {@link IDataStore.dataStoreSaveMessage | dataStoreSaveMessage }" }, "IDataStoreSaveVerifiableCredentialArgs": { "type": "object", @@ -1454,7 +1517,7 @@ "required": [ "verifiableCredential" ], - "description": "Input arguments for {@link IDataStore.dataStoreSaveVerifiableCredential | dataStoreSaveVerifiableCredential}" + "description": "Input arguments for {@link IDataStore.dataStoreSaveVerifiableCredential | dataStoreSaveVerifiableCredential }" }, "IDataStoreSaveVerifiablePresentationArgs": { "type": "object", @@ -1467,7 +1530,7 @@ "required": [ "verifiablePresentation" ], - "description": "Input arguments for {@link IDataStore.dataStoreSaveVerifiablePresentation | dataStoreSaveVerifiablePresentation}" + "description": "Input arguments for {@link IDataStore.dataStoreSaveVerifiablePresentation | dataStoreSaveVerifiablePresentation }" } }, "methods": { @@ -1547,13 +1610,13 @@ }, "save": { "type": "boolean", - "description": "Optional. If set to `true`, the message will be saved using {@link IDataStore.dataStoreSaveMessage | dataStoreSaveMessage}" + "description": "Optional. If set to `true`, the message will be saved using {@link IDataStore.dataStoreSaveMessage | dataStoreSaveMessage }" } }, "required": [ "raw" ], - "description": "Input arguments for {@link IMessageHandler.handleMessage | handleMessage}" + "description": "Input arguments for {@link IMessageHandler.handleMessage | handleMessage }" }, "IMetaData": { "type": "object", @@ -1739,7 +1802,7 @@ "credentialSubject", "proof" ], - "description": "Verifiable Credential {@link https://github.com/decentralized-identifier/did-jwt-vc}" + "description": "Verifiable Credential {@link https://github.com/decentralized-identifier/did-jwt-vc }" }, "VerifiablePresentation": { "type": "object", @@ -1797,7 +1860,7 @@ "verifiableCredential", "proof" ], - "description": "Verifiable Presentation {@link https://github.com/decentralized-identifier/did-jwt-vc}" + "description": "Verifiable Presentation {@link https://github.com/decentralized-identifier/did-jwt-vc }" } }, "methods": { diff --git a/packages/core/src/types/IIdentifier.ts b/packages/core/src/types/IIdentifier.ts index 111036370..0d306ad63 100644 --- a/packages/core/src/types/IIdentifier.ts +++ b/packages/core/src/types/IIdentifier.ts @@ -71,9 +71,14 @@ export interface IKey { privateKeyHex?: string /** - * Optional. Key metadata. Can be used to store auth data to access remote kms + * Optional. Key metadata. This should be used to determine which algorithms are supported. */ - meta?: object | null + meta?: KeyMetadata | null +} + +export interface KeyMetadata { + algorithms?: string[] + [x: string]: any } /** diff --git a/packages/core/src/types/IKeyManager.ts b/packages/core/src/types/IKeyManager.ts index c412d8a0c..c6ce78a53 100644 --- a/packages/core/src/types/IKeyManager.ts +++ b/packages/core/src/types/IKeyManager.ts @@ -1,5 +1,5 @@ import { IPluginMethodMap } from './IAgent' -import { TKeyType, IKey } from './IIdentifier' +import { TKeyType, IKey, KeyMetadata } from './IIdentifier' /** * Input arguments for {@link IKeyManager.keyManagerCreate | keyManagerCreate} @@ -19,7 +19,7 @@ export interface IKeyManagerCreateArgs { /** * Optional. Key meta data */ - meta?: object + meta?: KeyMetadata } /** @@ -81,6 +81,37 @@ export interface IKeyManagerDecryptJWEArgs { data: string } +/** + * Input arguments for {@link IKeyManager.keyManagerSign | keyManagerSign} + * @public + */ +export interface IKeyManagerSignArgs { + /** + * The key handle, as returned during `keyManagerCreateKey` + */ + keyRef: string + + /** + * The algorithm to use for signing. + * This must be one of the algorithms supported by the KMS for this key type. + * + * The algorithm used here should match one of the names listed in `IKey.meta.algorithms` + */ + algorithm?: string + + /** + * Data to sign + */ + data: string + + /** + * If the data is a "string" then you can specify which encoding is used. Default is "utf-8" + */ + encoding?: 'utf-8' | 'base16' | 'base64' | 'hex' + + [x: string]: any +} + /** * Input arguments for {@link IKeyManager.keyManagerSignJWT | keyManagerSignJWT} * @public @@ -143,6 +174,13 @@ export interface IKeyManager extends IPluginMethodMap { */ keyManagerImport(args: IKey): Promise + /** + * Generates a signature according to the algorithm specified. + * @throws `Error("not_supported")` if the KMS does not support the operation or if the key does not match the algorithm. + * @param args + */ + keyManagerSign(args: IKeyManagerSignArgs): Promise + /** * Encrypts data * @beta diff --git a/packages/credential-w3c/src/__tests__/action-handler.test.ts b/packages/credential-w3c/src/__tests__/action-handler.test.ts index f7fd9774c..9c8d50958 100644 --- a/packages/credential-w3c/src/__tests__/action-handler.test.ts +++ b/packages/credential-w3c/src/__tests__/action-handler.test.ts @@ -1,10 +1,4 @@ -import { - W3CCredential, - VerifiableCredential, - IIdentifier, - W3CPresentation, - VerifiablePresentation, -} from '@veramo/core' +import { W3CCredential, VerifiableCredential, IIdentifier, W3CPresentation } from '@veramo/core' const mockDidJwtVc = { createVerifiableCredentialJwt: jest.fn().mockReturnValue('mockVcJwt'), @@ -28,10 +22,10 @@ const mockIdentifiers: IIdentifier[] = [ kid: 'kid1', publicKeyHex: 'pub', type: 'Secp256k1', - kms: 'mock' - } + kms: 'mock', + }, ], - services: [] + services: [], }, { did: 'did:example:222', @@ -42,11 +36,11 @@ const mockIdentifiers: IIdentifier[] = [ kid: 'kid2', publicKeyHex: 'pub', type: 'Secp256k1', - kms: 'mock' - } + kms: 'mock', + }, ], - services: [] - }, + services: [], + }, { did: 'did:example:333', provider: 'mock', @@ -56,11 +50,11 @@ const mockIdentifiers: IIdentifier[] = [ kid: 'kid3', publicKeyHex: 'pub', type: 'Ed25519', - kms: 'mock' - } + kms: 'mock', + }, ], - services: [] - } + services: [], + }, ] const w3c = new CredentialIssuer() @@ -70,23 +64,21 @@ let agent = { availableMethods: jest.fn(), resolveDid: jest.fn(), emit: jest.fn(), - keyManagerSignJWT: jest.fn().mockImplementation(async (args): Promise => 'mockJWT'), + keyManagerSign: jest.fn().mockImplementation(async (args): Promise => 'mockJWT'), dataStoreSaveVerifiableCredential: jest.fn().mockImplementation(async (args): Promise => true), dataStoreSaveVerifiablePresentation: jest.fn().mockImplementation(async (args): Promise => true), getSchema: jest.fn(), - didManagerGet: jest.fn() + didManagerGet: jest.fn(), } describe('@veramo/credential-w3c', () => { - test.each(mockIdentifiers)('handles createVerifiableCredential', async (mockIdentifier) => { - expect.assertions(3*mockIdentifiers.length) - + expect.assertions(3 * mockIdentifiers.length) + agent.didManagerGet = jest.fn().mockImplementation(async (args): Promise => mockIdentifier) const context: IContext = { agent: agent } - - for (let otherMockIdentifier of mockIdentifiers) { + for (let otherMockIdentifier of mockIdentifiers) { const credential: W3CCredential = { '@context': ['https://www.w3.org/2018/credentials/v1', 'https://www.w3.org/2020/demo/4342323'], type: ['VerifiableCredential', 'PublicProfile'], @@ -117,13 +109,13 @@ describe('@veramo/credential-w3c', () => { expect(context.agent.dataStoreSaveVerifiableCredential).toBeCalledWith({ verifiableCredential: 'mockCredential', }) - expect(vc).toEqual('mockCredential') + expect(vc).toEqual('mockCredential') } }) test.each(mockIdentifiers)('handles createVerifiablePresentation', async (mockIdentifier) => { - expect.assertions(3*mockIdentifiers.length) - + expect.assertions(3 * mockIdentifiers.length) + agent.didManagerGet = jest.fn().mockImplementation(async (args): Promise => mockIdentifier) const context: IContext = { agent: agent } @@ -147,7 +139,7 @@ describe('@veramo/credential-w3c', () => { jwt: 'mockJWT', }, } - + const presentation: W3CPresentation = { '@context': ['https://www.w3.org/2018/credentials/v1'], type: ['VerifiablePresentation'], @@ -156,7 +148,7 @@ describe('@veramo/credential-w3c', () => { issuanceDate: new Date().toISOString(), verifiableCredential: [credential], } - + const vp = await w3c.createVerifiablePresentation( { presentation, @@ -165,7 +157,7 @@ describe('@veramo/credential-w3c', () => { }, context, ) - + expect(context.agent.didManagerGet).toBeCalledWith({ did: mockIdentifier.did }) expect(context.agent.dataStoreSaveVerifiablePresentation).toBeCalledWith({ verifiablePresentation: 'mockPresentation', diff --git a/packages/credential-w3c/src/action-handler.ts b/packages/credential-w3c/src/action-handler.ts index b694c8ff5..a36da88f8 100644 --- a/packages/credential-w3c/src/action-handler.ts +++ b/packages/credential-w3c/src/action-handler.ts @@ -10,6 +10,7 @@ import { VerifiableCredential, VerifiablePresentation, IDataStore, + IKey, } from '@veramo/core' import { @@ -186,7 +187,7 @@ export type IContext = IAgentContext< IResolver & Pick & Pick & - Pick + Pick > /** @@ -225,12 +226,12 @@ export class CredentialIssuer implements IAgentPlugin { const key = identifier.keys.find((k) => k.type === 'Secp256k1' || k.type === 'Ed25519') if (!key) throw Error('No signing key for ' + identifier.did) //FIXME: Throw an `unsupported_format` error if the `args.proofFormat` is not `jwt` - const signer = (data: string | Uint8Array) => context.agent.keyManagerSignJWT({ kid: key.kid, data }) debug('Signing VP with', identifier.did) let alg = 'ES256K' if (key.type === 'Ed25519') { alg = 'EdDSA' } + const signer = wrapSigner(context, key, alg) const jwt = await createVerifiablePresentationJwt( presentation, @@ -270,13 +271,12 @@ export class CredentialIssuer implements IAgentPlugin { const key = identifier.keys.find((k) => k.type === 'Secp256k1' || k.type === 'Ed25519') if (!key) throw Error('No signing key for ' + identifier.did) //FIXME: Throw an `unsupported_format` error if the `args.proofFormat` is not `jwt` - const signer = (data: string | Uint8Array) => context.agent.keyManagerSignJWT({ kid: key.kid, data }) - debug('Signing VC with', identifier.did) let alg = 'ES256K' if (key.type === 'Ed25519') { alg = 'EdDSA' } + const signer = wrapSigner(context, key, alg) const jwt = await createVerifiableCredentialJwt( credential, { did: identifier.did, signer, alg }, @@ -296,3 +296,10 @@ export class CredentialIssuer implements IAgentPlugin { } } } + +function wrapSigner(context: IAgentContext>, key: IKey, algorithm?: string) { + return async (data: string | Uint8Array) => { + const result = await context.agent.keyManagerSign({ keyRef: key.kid, data: data, algorithm }) + return result + } +} diff --git a/packages/data-store/plugin.schema.json b/packages/data-store/plugin.schema.json index 2c48c5231..b53026084 100644 --- a/packages/data-store/plugin.schema.json +++ b/packages/data-store/plugin.schema.json @@ -151,13 +151,13 @@ "meta": { "anyOf": [ { - "type": "object" + "$ref": "#/components/schemas/KeyMetadata" }, { "type": "null" } ], - "description": "Optional. Key metadata. Can be used to store auth data to access remote kms" + "description": "Optional. Key metadata. This should be used to determine which algorithms are supported." } }, "required": [ @@ -176,6 +176,17 @@ ], "description": "Cryptographic key type" }, + "KeyMetadata": { + "type": "object", + "properties": { + "algorithms": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "IService": { "type": "object", "properties": { @@ -482,7 +493,7 @@ "credentialSubject", "proof" ], - "description": "Verifiable Credential {@link https://github.com/decentralized-identifier/did-jwt-vc}" + "description": "Verifiable Credential {@link https://github.com/decentralized-identifier/did-jwt-vc }" }, "VerifiablePresentation": { "type": "object", @@ -540,7 +551,7 @@ "verifiableCredential", "proof" ], - "description": "Verifiable Presentation {@link https://github.com/decentralized-identifier/did-jwt-vc}" + "description": "Verifiable Presentation {@link https://github.com/decentralized-identifier/did-jwt-vc }" }, "FindCredentialsArgs": { "$ref": "#/components/schemas/FindArgs-TCredentialColumns" diff --git a/packages/data-store/src/entities/key.ts b/packages/data-store/src/entities/key.ts index 4777bbcef..010a0196b 100644 --- a/packages/data-store/src/entities/key.ts +++ b/packages/data-store/src/entities/key.ts @@ -1,3 +1,4 @@ +import { KeyMetadata } from '@veramo/core' import { Entity, Column, PrimaryColumn, BaseEntity, ManyToOne } from 'typeorm' import { Identifier } from './identifier' @@ -24,8 +25,19 @@ export class Key extends BaseEntity { @Column({ nullable: true }) privateKeyHex?: string - @Column({ type: 'simple-json', nullable: true }) - meta?: object | null + @Column({ + type: 'simple-json', + nullable: true, + transformer: { + to: (value: any): KeyMetadata | null => { + return value + }, + from: (value: KeyMetadata | null): object | null => { + return value + }, + }, + }) + meta?: KeyMetadata | null @ManyToOne((type) => Identifier, (identifier) => identifier.keys) //@ts-ignore diff --git a/packages/data-store/src/identifier/did-store.ts b/packages/data-store/src/identifier/did-store.ts index 11bd4e8cd..f25365ac1 100644 --- a/packages/data-store/src/identifier/did-store.ts +++ b/packages/data-store/src/identifier/did-store.ts @@ -47,6 +47,7 @@ export class DIDStore extends AbstractDIDStore { type: k.type, kms: k.kms, publicKeyHex: k.publicKeyHex, + meta: k.meta })), } if (identifier.alias) { diff --git a/packages/did-comm/plugin.schema.json b/packages/did-comm/plugin.schema.json index bd1e28b28..1f86baa36 100644 --- a/packages/did-comm/plugin.schema.json +++ b/packages/did-comm/plugin.schema.json @@ -54,7 +54,7 @@ "required": [ "data" ], - "description": "Input arguments for {@link IDIDComm.sendMessageDIDCommAlpha1}" + "description": "Input arguments for {@link IDIDComm.sendMessageDIDCommAlpha1 }" }, "IMessage": { "type": "object", @@ -240,7 +240,7 @@ "credentialSubject", "proof" ], - "description": "Verifiable Credential {@link https://github.com/decentralized-identifier/did-jwt-vc}" + "description": "Verifiable Credential {@link https://github.com/decentralized-identifier/did-jwt-vc }" }, "VerifiablePresentation": { "type": "object", @@ -298,7 +298,7 @@ "verifiableCredential", "proof" ], - "description": "Verifiable Presentation {@link https://github.com/decentralized-identifier/did-jwt-vc}" + "description": "Verifiable Presentation {@link https://github.com/decentralized-identifier/did-jwt-vc }" } }, "methods": { diff --git a/packages/did-provider-ethr/package.json b/packages/did-provider-ethr/package.json index 4049d2565..802a06298 100644 --- a/packages/did-provider-ethr/package.json +++ b/packages/did-provider-ethr/package.json @@ -9,13 +9,17 @@ "extract-api": "yarn veramo dev extract-api" }, "dependencies": { + "@ethersproject/abstract-provider": "^5.1.0", + "@ethersproject/abstract-signer": "^5.1.0", + "@ethersproject/address": "^5.1.0", + "@ethersproject/bytes": "^5.1.0", + "@ethersproject/properties": "^5.1.0", "@ethersproject/signing-key": "^5.1.0", + "@ethersproject/transactions": "^5.1.1", "@veramo/core": "^1.2.0", "@veramo/did-manager": "^1.2.0", "debug": "^4.1.1", - "ethjs-provider-signer": "^0.1.4", - "ethr-did": "2.1.4", - "js-sha3": "^0.8.0" + "ethr-did": "2.1.4" }, "devDependencies": { "@types/debug": "4.1.5", diff --git a/packages/did-provider-ethr/src/ethr-did-provider.ts b/packages/did-provider-ethr/src/ethr-did-provider.ts index 04aa0e7be..6fc6a1f12 100644 --- a/packages/did-provider-ethr/src/ethr-did-provider.ts +++ b/packages/did-provider-ethr/src/ethr-did-provider.ts @@ -1,22 +1,22 @@ import { IIdentifier, IKey, IService, IAgentContext, IKeyManager } from '@veramo/core' import { AbstractIdentifierProvider } from '@veramo/did-manager' -import { keccak_256 } from 'js-sha3' +import { Provider } from '@ethersproject/abstract-provider' +import { JsonRpcProvider } from '@ethersproject/providers' +import { computePublicKey } from '@ethersproject/signing-key' +import { computeAddress } from '@ethersproject/transactions' +import { KmsEthereumSigner } from './kms-eth-signer' import Debug from 'debug' import { EthrDID } from 'ethr-did' -import { computePublicKey } from '@ethersproject/signing-key' -const SignerProvider = require('ethjs-provider-signer') const debug = Debug('veramo:did-provider-ethr') -type IContext = IAgentContext +export type IRequiredContext = IAgentContext /** * Helper method that can computes the ethereumAddress corresponding to a secp256k1 public key. * @param hexPublicKey A hex encoded public key, prefixed with `0x` */ export function toEthereumAddress(hexPublicKey: string): string { - return `0x${Buffer.from(keccak_256.arrayBuffer(Buffer.from(hexPublicKey.slice(2), 'hex'))) - .slice(-20) - .toString('hex')}` + return computeAddress('0x' + hexPublicKey) } /** @@ -26,7 +26,7 @@ export function toEthereumAddress(hexPublicKey: string): string { export class EthrDIDProvider extends AbstractIdentifierProvider { private defaultKms: string private network: string - private web3Provider?: any + private web3Provider?: Provider private rpcUrl?: string private gas?: number private ttl?: number @@ -36,7 +36,7 @@ export class EthrDIDProvider extends AbstractIdentifierProvider { defaultKms: string network: string rpcUrl?: string - web3Provider?: object + web3Provider?: Provider ttl?: number gas?: number registry?: string @@ -45,7 +45,10 @@ export class EthrDIDProvider extends AbstractIdentifierProvider { this.defaultKms = options.defaultKms this.network = options.network this.rpcUrl = options.rpcUrl - this.web3Provider = options.web3Provider + this.web3Provider = options.web3Provider + if (typeof this.web3Provider === 'undefined') { + this.web3Provider = new JsonRpcProvider(this.rpcUrl, this.network) + } this.ttl = options.ttl this.gas = options.gas this.registry = options.registry @@ -53,7 +56,7 @@ export class EthrDIDProvider extends AbstractIdentifierProvider { async createIdentifier( { kms, options }: { kms?: string; options?: any }, - context: IContext, + context: IRequiredContext, ): Promise> { const key = await context.agent.keyManagerCreate({ kms: kms || this.defaultKms, type: 'Secp256k1' }) const compressedPublicKey = computePublicKey(`0x${key.publicKeyHex}`, true) @@ -67,65 +70,54 @@ export class EthrDIDProvider extends AbstractIdentifierProvider { return identifier } - async deleteIdentifier(identifier: IIdentifier, context: IContext): Promise { + async deleteIdentifier(identifier: IIdentifier, context: IRequiredContext): Promise { for (const { kid } of identifier.keys) { await context.agent.keyManagerDelete({ kid }) } return true } - private getWeb3Provider({ controllerKeyId }: IIdentifier, context: IContext) { - if (!this.web3Provider && !this.rpcUrl) throw Error('Web3Provider or rpcUrl required') - if (!controllerKeyId) throw Error('ControllerKeyId does not exist') - - const web3Provider = - this.web3Provider || - new SignerProvider(this.rpcUrl, { - signTransaction: ( - transaction: object, - callback: (error: string | null, signature?: string) => void, - ) => { - context.agent - .keyManagerSignEthTX({ kid: controllerKeyId, transaction }) - .then((signature) => callback(null, signature)) - .catch((error) => callback(error)) - }, - }) - return web3Provider + private async getEthrDidController(identifier: IIdentifier, context: IRequiredContext) { + if (identifier.controllerKeyId == null) { + throw new Error('invalid_argument: identifier does not list a `controllerKeyId`') + } + const controllerKey = await context.agent.keyManagerGet({ kid: identifier.controllerKeyId }) + if (typeof controllerKey === 'undefined') { + throw new Error('invalid_argument: identifier.controllerKeyId is not managed by this agent') + } + return new EthrDID({ + identifier: identifier.did, + provider: this.web3Provider, + chainNameOrId: this.network, + rpcUrl: this.rpcUrl, + registry: this.registry, + txSigner: new KmsEthereumSigner(controllerKey, context, this.web3Provider), + }) } async addKey( { identifier, key, options }: { identifier: IIdentifier; key: IKey; options?: any }, - context: IContext, + context: IRequiredContext, ): Promise { - const ethrDid = new EthrDID({ - identifier: identifier.did, - provider: this.getWeb3Provider(identifier, context), - registry: this.registry, - }) - + const ethrDid = await this.getEthrDidController(identifier, context) const usg = 'veriKey' const attribute = 'did/pub/' + key.type + '/' + usg + '/hex' const value = '0x' + key.publicKeyHex const ttl = options?.ttl || this.ttl - const gas = options?.gas || this.gas + const gasLimit = options?.gas || this.gas - debug('ethrDid.setAttribute %o', { attribute, value, ttl, gas }) + debug('ethrDid.setAttribute %o', { attribute, value, ttl, gas: gasLimit }) - const txHash = await ethrDid.setAttribute(attribute, value, ttl, gas) + const txHash = await ethrDid.setAttribute(attribute, value, ttl, gasLimit) debug({ txHash }) return txHash } async addService( { identifier, service, options }: { identifier: IIdentifier; service: IService; options?: any }, - context: IContext, + context: IRequiredContext, ): Promise { - const ethrDid = new EthrDID({ - identifier: identifier.did, - provider: this.getWeb3Provider(identifier, context), - registry: this.registry, - }) + const ethrDid = await this.getEthrDidController(identifier, context) const attribute = 'did/svc/' + service.type const value = service.serviceEndpoint @@ -141,13 +133,9 @@ export class EthrDIDProvider extends AbstractIdentifierProvider { async removeKey( args: { identifier: IIdentifier; kid: string; options?: any }, - context: IContext, + context: IRequiredContext, ): Promise { - const ethrDid = new EthrDID({ - identifier: args.identifier.did, - provider: this.getWeb3Provider(args.identifier, context), - registry: this.registry, - }) + const ethrDid = await this.getEthrDidController(args.identifier, context) const key = args.identifier.keys.find((k) => k.kid === args.kid) if (!key) throw Error('Key not found') @@ -164,13 +152,9 @@ export class EthrDIDProvider extends AbstractIdentifierProvider { async removeService( args: { identifier: IIdentifier; id: string; options?: any }, - context: IContext, + context: IRequiredContext, ): Promise { - const ethrDid = new EthrDID({ - identifier: args.identifier.did, - provider: this.getWeb3Provider(args.identifier, context), - registry: this.registry, - }) + const ethrDid = await this.getEthrDidController(args.identifier, context) const service = args.identifier.services.find((s) => s.id === args.id) if (!service) throw Error('Service not found') diff --git a/packages/did-provider-ethr/src/kms-eth-signer.ts b/packages/did-provider-ethr/src/kms-eth-signer.ts new file mode 100644 index 000000000..10d4c0e27 --- /dev/null +++ b/packages/did-provider-ethr/src/kms-eth-signer.ts @@ -0,0 +1,55 @@ +import { TransactionRequest, Provider } from '@ethersproject/abstract-provider' +import { Signer } from '@ethersproject/abstract-signer' +import { getAddress } from '@ethersproject/address' +import { Bytes } from '@ethersproject/bytes' +import { Deferrable, resolveProperties } from '@ethersproject/properties' +import { computeAddress, serialize, UnsignedTransaction } from '@ethersproject/transactions' +import { IRequiredContext } from './ethr-did-provider' +import { IKey } from '@veramo/core' + +/** + * Creates an `@ethersproject/abstract-signer` implementation by wrapping + * a veramo agent with a key-manager that should be capable of `eth_signTransaction` + */ +export class KmsEthereumSigner extends Signer { + private context: IRequiredContext + private controllerKey: IKey + readonly provider?: Provider + + constructor(controllerKey: IKey, context: IRequiredContext, provider?: Provider) { + super() + this.controllerKey = controllerKey + this.context = context + this.provider = provider + } + + async getAddress(): Promise { + return computeAddress('0x' + this.controllerKey.publicKeyHex) + } + + async signTransaction(transaction: Deferrable): Promise { + const tx = await resolveProperties(transaction) + if (tx.from != null) { + const thisAddress = await this.getAddress() + if (getAddress(tx.from) !== thisAddress) { + throw new Error(`transaction from address mismatch ${transaction.from} != ${thisAddress}`) + } + delete tx.from + } + const signature = await this.context.agent.keyManagerSign({ + keyRef: this.controllerKey.kid, + data: serialize(tx), + algorithm: 'eth_signTransaction', + encoding: 'base16', + }) + return signature + } + + signMessage(message: string | Bytes): Promise { + throw new Error('not_implemented: signMessage() Method not implemented by KmsEthereumSigner.') + } + + connect(provider: Provider): Signer { + return new KmsEthereumSigner(this.controllerKey, this.context, provider) + } +} diff --git a/packages/did-resolver/src/__tests__/integration.test.ts b/packages/did-resolver/src/__tests__/integration.test.ts index f45b997ab..ed2a5409d 100644 --- a/packages/did-resolver/src/__tests__/integration.test.ts +++ b/packages/did-resolver/src/__tests__/integration.test.ts @@ -32,7 +32,7 @@ describe('@veramo/did-resolver', () => { expect.assertions(1) await expect(resolverPlugin.resolveDid({ didUrl: 'did:web:did.actor:alice' })).resolves.toEqual({ didDocument: { - '@context': ["https://w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2018/v1"], + '@context': ['https://w3.org/ns/did/v1', 'https://w3id.org/security/suites/ed25519-2018/v1'], id: 'did:web:did.actor:alice', publicKey: [ { diff --git a/packages/key-manager/src/abstract-key-management-system.ts b/packages/key-manager/src/abstract-key-management-system.ts index 1f92fd86c..46022149f 100644 --- a/packages/key-manager/src/abstract-key-management-system.ts +++ b/packages/key-manager/src/abstract-key-management-system.ts @@ -1,10 +1,37 @@ import { IKey, TKeyType } from '@veramo/core' +import { arrayify } from '@ethersproject/bytes' +import { serialize, Transaction } from '@ethersproject/transactions' +import * as u8a from 'uint8arrays' export abstract class AbstractKeyManagementSystem { abstract createKey(args: { type: TKeyType; meta?: any }): Promise> abstract deleteKey(args: { kid: string }): Promise abstract encryptJWE(args: { key: IKey; to: Omit; data: string }): Promise abstract decryptJWE(args: { key: IKey; data: string }): Promise - abstract signJWT(args: { key: IKey; data: string | Uint8Array }): Promise - abstract signEthTX(args: { key: IKey; transaction: object }): Promise + + /**@deprecated please use `sign({key, alg: 'eth_signTransaction', data: arrayify(serialize(transaction))})` instead */ + async signEthTX({ key, transaction }: { key: IKey; transaction: object }): Promise { + const { v, r, s, type, ...tx } = transaction + const data = arrayify(serialize(tx)) + const algorithm = 'eth_signTransaction' + const signedTxHexString = this.sign({ key, data, algorithm }) + return signedTxHexString + } + + /**@deprecated please use `sign({key, data})` instead, with `Uint8Array` data */ + async signJWT({ key, data }: { key: IKey; data: string | Uint8Array }): Promise { + let dataBytes: Uint8Array + if (typeof data === 'string') { + try { + dataBytes = arrayify(data, { allowMissingPrefix: true }) + } catch (e) { + dataBytes = u8a.fromString(data, 'utf-8') + } + } else { + dataBytes = data + } + return this.sign({ key, data: dataBytes }) + } + + abstract sign(args: { key: IKey; algorithm?: string; data: Uint8Array; [x: string]: any }): Promise } diff --git a/packages/key-manager/src/key-manager.ts b/packages/key-manager/src/key-manager.ts index 7a03b1f6c..dc7c86f36 100644 --- a/packages/key-manager/src/key-manager.ts +++ b/packages/key-manager/src/key-manager.ts @@ -12,7 +12,9 @@ import { IKeyManagerSignJWTArgs, IKeyManagerSignEthTXArgs, schema, + IKeyManagerSignArgs, } from '@veramo/core' +import * as u8a from 'uint8arrays' /** * Agent plugin that provides {@link @veramo/core#IKeyManager} methods @@ -43,6 +45,7 @@ export class KeyManager implements IAgentPlugin { keyManagerDecryptJWE: this.keyManagerDecryptJWE.bind(this), keyManagerSignJWT: this.keyManagerSignJWT.bind(this), keyManagerSignEthTX: this.keyManagerSignEthTX.bind(this), + keyManagerSign: this.keyManagerSign.bind(this), } } @@ -105,12 +108,31 @@ export class KeyManager implements IAgentPlugin { } /** {@inheritDoc @veramo/core#IKeyManager.keyManagerSignJWT} */ - async keyManagerSignJWT({ kid, data }: IKeyManagerSignJWTArgs): Promise< string> { + async keyManagerSignJWT({ kid, data }: IKeyManagerSignJWTArgs): Promise { const key = await this.store.get({ kid }) const kms = this.getKms(key.kms) return kms.signJWT({ key, data }) } + /** {@inheritDoc @veramo/core#IKeyManager.keyManagerSign} */ + async keyManagerSign(args: IKeyManagerSignArgs): Promise { + const { keyRef, data, algorithm, encoding, ...extras } = { encoding: 'utf-8', ...args } + const key = await this.store.get({ kid: keyRef }) + let dataBytes + if (typeof data === 'string') { + if (encoding === 'base16' || encoding === 'hex') { + const preData = data.startsWith('0x') ? data.substring(2) : data + dataBytes = u8a.fromString(preData, 'base16') + } else { + dataBytes = u8a.fromString(data, <'utf-8'>encoding) + } + } else { + dataBytes = data + } + const kms = this.getKms(key.kms) + return kms.sign({ key, algorithm, data: dataBytes, ...extras }) + } + /** {@inheritDoc @veramo/core#IKeyManager.keyManagerSignEthTX} */ async keyManagerSignEthTX({ kid, transaction }: IKeyManagerSignEthTXArgs): Promise { const key = await this.store.get({ kid }) diff --git a/packages/kms-local-react-native/package.json b/packages/kms-local-react-native/package.json index 164fc47ed..d19b8701e 100644 --- a/packages/kms-local-react-native/package.json +++ b/packages/kms-local-react-native/package.json @@ -9,20 +9,24 @@ "extract-api": "yarn veramo dev extract-api" }, "dependencies": { + "@ethersproject/abstract-provider": "^5.1.0", + "@ethersproject/abstract-signer": "^5.1.0", + "@ethersproject/bytes": "^5.1.0", + "@ethersproject/strings": "^5.1.0", + "@ethersproject/transactions": "^5.1.1", + "@ethersproject/wallet": "^5.1.0", "@veramo/core": "^1.2.0", "@veramo/key-manager": "^1.2.0", "base-58": "^0.0.1", "debug": "^4.1.1", "did-jwt": "5.5.2", - "elliptic": "6.5.4", - "ethjs-signer": "^0.1.1" + "uint8arrays": "^2.1.5" }, "peerDependencies": { "react-native-sodium": "*" }, "devDependencies": { "@types/debug": "4.1.5", - "@types/ethjs-signer": "0.1.0", "react-native-sodium": "0.3.9", "typescript": "4.3.2" }, diff --git a/packages/kms-local-react-native/src/key-management-system.ts b/packages/kms-local-react-native/src/key-management-system.ts index a83212401..acd235b89 100644 --- a/packages/kms-local-react-native/src/key-management-system.ts +++ b/packages/kms-local-react-native/src/key-management-system.ts @@ -1,12 +1,14 @@ import { TKeyType, IKey } from '@veramo/core' import { AbstractKeyManagementSystem } from '@veramo/key-manager' -import sodium from 'react-native-sodium' -import { EdDSASigner, ES256KSigner, NaclSigner } from 'did-jwt' -const EC = require('elliptic').ec -const secp256k1 = new EC('secp256k1') +import sodium from 'libsodium-wrappers' +import { EdDSASigner, ES256KSigner } from 'did-jwt' +import { TypedDataDomain, TypedDataField } from '@ethersproject/abstract-signer' +import { TransactionRequest } from '@ethersproject/abstract-provider' +import { toUtf8String } from '@ethersproject/strings' +import { parse } from '@ethersproject/transactions' +import { Wallet } from '@ethersproject/wallet' import { DIDComm } from './didcomm' const didcomm = new DIDComm() -import { sign } from 'ethjs-signer' import Debug from 'debug' const debug = Debug('veramo:react-native-libsodium:kms') @@ -23,19 +25,27 @@ export class KeyManagementSystem extends AbstractKeyManagementSystem { kid: Buffer.from(keyPairEd25519.publicKey).toString('hex'), publicKeyHex: Buffer.from(keyPairEd25519.publicKey).toString('hex'), privateKeyHex: Buffer.from(keyPairEd25519.privateKey).toString('hex'), + meta: { + algorithms: ['Ed25519', 'EdDSA'], + }, } break case 'Secp256k1': - const keyPairSecp256k1 = secp256k1.genKeyPair() + const keyPair = Wallet.createRandom()._signingKey() + const publicKeyHex = keyPair.publicKey.substring(2) + const privateKeyHex = keyPair.privateKey.substring(2) key = { type, - kid: keyPairSecp256k1.getPublic('hex'), - publicKeyHex: keyPairSecp256k1.getPublic('hex'), - privateKeyHex: keyPairSecp256k1.getPrivate('hex'), + kid: publicKeyHex, + publicKeyHex, + privateKeyHex, + meta: { + algorithms: ['ES256K', 'ES256K-R', 'eth_signTransaction', 'eth_signTypedData', 'eth_signMessage'], + }, } break default: - throw Error('Key type not supported: ' + type) + throw Error('not_supported: Key type not supported: ' + type) } debug('Created key', type, key.publicKeyHex) @@ -68,21 +78,106 @@ export class KeyManagementSystem extends AbstractKeyManagementSystem { return unpackMessage.message } - async signEthTX({ key, transaction }: { key: IKey; transaction: object }): Promise { - return sign(transaction, '0x' + key.privateKeyHex) - } - - async signJWT({ key, data }: { key: IKey; data: string }): Promise< string> { + async sign({ key, algorithm, data }: { key: IKey; algorithm?: string; data: Uint8Array }): Promise { + //FIXME: KMS implementation should not rely on private keys being provided, but rather manage their own keys if (!key.privateKeyHex) throw Error('No private key for kid: ' + key.kid) - if (key.type === 'Ed25519') { - const signer = EdDSASigner(key.privateKeyHex) - return (signer(data) as any) as string + if (key.type === 'Ed25519' && (typeof algorithm === 'undefined' || ['Ed25519', 'EdDSA'].includes(algorithm))) { + return await this.signEdDSA(key.privateKeyHex, data) } else if (key.type === 'Secp256k1') { - const signer = ES256KSigner(key.privateKeyHex) - return signer(data) as unknown as string - } else { - throw Error('Cannot sign JWT with key of type ' + key.type) + if (typeof algorithm === 'undefined' || ['ES256K', 'ES256K-R'].includes(algorithm)) { + return await this.signES256K(key.privateKeyHex, algorithm, data) + } else if (['eth_signTransaction', 'signTransaction', 'signTx'].includes(algorithm)) { + return await this.eth_signTransaction(key.privateKeyHex, data) + } else if (algorithm === 'eth_signMessage') { + return await this.eth_signMessage(key.privateKeyHex, data) + } else if (['eth_signTypedData', 'EthereumEip712Signature2021'].includes(algorithm)) { + return await this.eth_signTypedData(key.privateKeyHex, data) + } + } + throw Error(`not_supported: Cannot sign ${algorithm} using key of type ${key.type}`) + } + + /** + * @returns a `0x` prefixed hex string representing the signed EIP712 data + */ + private async eth_signTypedData(privateKeyHex: string, data: Uint8Array) { + let msg, msgDomain, msgTypes + const serializedData = toUtf8String(data) + try { + let jsonData = JSON.parse(serializedData) + if (typeof jsonData.domain === 'object' && typeof jsonData.types === 'object') { + const { domain, types, message } = jsonData + msg = message + msgDomain = domain + msgTypes = types + } else { + // next check will throw since the data couldn't be parsed + } + } catch (e) { + // next check will throw since the data couldn't be parsed } + if (typeof msgDomain !== 'object' || typeof msgTypes !== 'object' || typeof msg !== 'object') { + throw Error( + `invalid_arguments: Cannot sign typed data. 'domain', 'types', and 'message' must be provided`, + ) + } + const wallet = new Wallet(privateKeyHex) + + const signature = await wallet._signTypedData(msgDomain, msgTypes, msg) + //HEX encoded string + return signature + } + + /** + * @returns a `0x` prefixed hex string representing the signed message + */ + private async eth_signMessage(privateKeyHex: string, rawMessageBytes: Uint8Array) { + const wallet = new Wallet(privateKeyHex) + const signature = await wallet.signMessage(rawMessageBytes) + //HEX encoded string, 0x prefixed + return signature } + + /** + * @returns a `0x` prefixed hex string representing the signed raw transaction + */ + private async eth_signTransaction(privateKeyHex: string, rlpTransaction: Uint8Array) { + const { v, r, s, type, ...tx } = parse(rlpTransaction) + const wallet = new Wallet(privateKeyHex) + const signedRawTransaction = await wallet.signTransaction(tx) + //HEX encoded string, 0x prefixed + return signedRawTransaction + } + + /** + * @returns a base64url encoded signature for the `EdDSA` alg + */ + private async signEdDSA(key: string, data: Uint8Array): Promise { + const signer = EdDSASigner(key) + const signature = await signer(data) + //base64url encoded string + return signature as string + } + + /** + * @returns a base64url encoded signature for the `ES256K` or `ES256K-R` alg + */ + private async signES256K( + privateKeyHex: string, + alg: string | undefined, + data: Uint8Array, + ): Promise { + const signer = ES256KSigner(privateKeyHex, alg === 'ES256K-R') + const signature = await signer(data) + //base64url encoded string + return signature as string + } +} + +type Eip712Payload = { + domain: TypedDataDomain + types: Record + primaryType: string + message: Record } diff --git a/packages/kms-local/package.json b/packages/kms-local/package.json index a8cba441c..9a3b93326 100644 --- a/packages/kms-local/package.json +++ b/packages/kms-local/package.json @@ -9,18 +9,22 @@ "extract-api": "yarn veramo dev extract-api" }, "dependencies": { + "@ethersproject/abstract-provider": "^5.1.0", + "@ethersproject/abstract-signer": "^5.1.0", + "@ethersproject/bytes": "^5.1.0", + "@ethersproject/strings": "^5.1.0", + "@ethersproject/transactions": "^5.1.1", + "@ethersproject/wallet": "^5.1.0", "@veramo/core": "^1.2.0", "@veramo/key-manager": "^1.2.0", "base-58": "^0.0.1", "debug": "^4.1.1", "did-jwt": "5.5.2", - "elliptic": "6.5.4", - "ethjs-signer": "^0.1.1", - "libsodium-wrappers": "^0.7.8" + "libsodium-wrappers": "^0.7.8", + "uint8arrays": "^2.1.5" }, "devDependencies": { "@types/debug": "4.1.5", - "@types/ethjs-signer": "0.1.0", "@types/libsodium-wrappers": "0.7.9", "typescript": "4.3.2" }, diff --git a/packages/kms-local/src/key-management-system.ts b/packages/kms-local/src/key-management-system.ts index 1ccbdfb48..9064fff77 100644 --- a/packages/kms-local/src/key-management-system.ts +++ b/packages/kms-local/src/key-management-system.ts @@ -2,11 +2,13 @@ import { TKeyType, IKey } from '@veramo/core' import { AbstractKeyManagementSystem } from '@veramo/key-manager' import sodium from 'libsodium-wrappers' import { EdDSASigner, ES256KSigner } from 'did-jwt' -const EC = require('elliptic').ec -const secp256k1 = new EC('secp256k1') +import { TypedDataDomain, TypedDataField } from '@ethersproject/abstract-signer' +import { TransactionRequest } from '@ethersproject/abstract-provider' +import { toUtf8String } from '@ethersproject/strings' +import { parse } from '@ethersproject/transactions' +import { Wallet } from '@ethersproject/wallet' import { DIDComm } from './didcomm' const didcomm = new DIDComm() -import { sign } from 'ethjs-signer' import Debug from 'debug' const debug = Debug('veramo:sodium:kms') @@ -23,19 +25,27 @@ export class KeyManagementSystem extends AbstractKeyManagementSystem { kid: Buffer.from(keyPairEd25519.publicKey).toString('hex'), publicKeyHex: Buffer.from(keyPairEd25519.publicKey).toString('hex'), privateKeyHex: Buffer.from(keyPairEd25519.privateKey).toString('hex'), + meta: { + algorithms: ['Ed25519', 'EdDSA'], + }, } break case 'Secp256k1': - const keyPairSecp256k1 = secp256k1.genKeyPair() + const keyPair = Wallet.createRandom()._signingKey() + const publicKeyHex = keyPair.publicKey.substring(2) + const privateKeyHex = keyPair.privateKey.substring(2) key = { type, - kid: keyPairSecp256k1.getPublic('hex'), - publicKeyHex: keyPairSecp256k1.getPublic('hex'), - privateKeyHex: keyPairSecp256k1.getPrivate('hex'), + kid: publicKeyHex, + publicKeyHex, + privateKeyHex, + meta: { + algorithms: ['ES256K', 'ES256K-R', 'eth_signTransaction', 'eth_signTypedData', 'eth_signMessage'], + }, } break default: - throw Error('Key type not supported: ' + type) + throw Error('not_supported: Key type not supported: ' + type) } debug('Created key', type, key.publicKeyHex) @@ -68,21 +78,106 @@ export class KeyManagementSystem extends AbstractKeyManagementSystem { return unpackMessage.message } - async signEthTX({ key, transaction }: { key: IKey; transaction: object }): Promise { - return sign(transaction, '0x' + key.privateKeyHex) - } - - async signJWT({ key, data }: { key: IKey; data: string | Uint8Array }): Promise { + async sign({ key, algorithm, data }: { key: IKey; algorithm?: string; data: Uint8Array }): Promise { + //FIXME: KMS implementation should not rely on private keys being provided, but rather manage their own keys if (!key.privateKeyHex) throw Error('No private key for kid: ' + key.kid) - if (key.type === 'Ed25519') { - const signer = EdDSASigner(key.privateKeyHex) - return (signer(data) as any) as string + if (key.type === 'Ed25519' && (typeof algorithm === 'undefined' || ['Ed25519', 'EdDSA'].includes(algorithm))) { + return await this.signEdDSA(key.privateKeyHex, data) } else if (key.type === 'Secp256k1') { - const signer = ES256KSigner(key.privateKeyHex) - return (signer(data) as any) as string - } else { - throw Error('Cannot sign JWT with key of type ' + key.type) + if (typeof algorithm === 'undefined' || ['ES256K', 'ES256K-R'].includes(algorithm)) { + return await this.signES256K(key.privateKeyHex, algorithm, data) + } else if (['eth_signTransaction', 'signTransaction', 'signTx'].includes(algorithm)) { + return await this.eth_signTransaction(key.privateKeyHex, data) + } else if (algorithm === 'eth_signMessage') { + return await this.eth_signMessage(key.privateKeyHex, data) + } else if (['eth_signTypedData', 'EthereumEip712Signature2021'].includes(algorithm)) { + return await this.eth_signTypedData(key.privateKeyHex, data) + } + } + throw Error(`not_supported: Cannot sign ${algorithm} using key of type ${key.type}`) + } + + /** + * @returns a `0x` prefixed hex string representing the signed EIP712 data + */ + private async eth_signTypedData(privateKeyHex: string, data: Uint8Array) { + let msg, msgDomain, msgTypes + const serializedData = toUtf8String(data) + try { + let jsonData = JSON.parse(serializedData) + if (typeof jsonData.domain === 'object' && typeof jsonData.types === 'object') { + const { domain, types, message } = jsonData + msg = message + msgDomain = domain + msgTypes = types + } else { + // next check will throw since the data couldn't be parsed + } + } catch (e) { + // next check will throw since the data couldn't be parsed } + if (typeof msgDomain !== 'object' || typeof msgTypes !== 'object' || typeof msg !== 'object') { + throw Error( + `invalid_arguments: Cannot sign typed data. 'domain', 'types', and 'message' must be provided`, + ) + } + const wallet = new Wallet(privateKeyHex) + + const signature = await wallet._signTypedData(msgDomain, msgTypes, msg) + //HEX encoded string + return signature + } + + /** + * @returns a `0x` prefixed hex string representing the signed message + */ + private async eth_signMessage(privateKeyHex: string, rawMessageBytes: Uint8Array) { + const wallet = new Wallet(privateKeyHex) + const signature = await wallet.signMessage(rawMessageBytes) + //HEX encoded string, 0x prefixed + return signature } + + /** + * @returns a `0x` prefixed hex string representing the signed raw transaction + */ + private async eth_signTransaction(privateKeyHex: string, rlpTransaction: Uint8Array) { + const { v, r, s, type, ...tx } = parse(rlpTransaction) + const wallet = new Wallet(privateKeyHex) + const signedRawTransaction = await wallet.signTransaction(tx) + //HEX encoded string, 0x prefixed + return signedRawTransaction + } + + /** + * @returns a base64url encoded signature for the `EdDSA` alg + */ + private async signEdDSA(key: string, data: Uint8Array): Promise { + const signer = EdDSASigner(key) + const signature = await signer(data) + //base64url encoded string + return signature as string + } + + /** + * @returns a base64url encoded signature for the `ES256K` or `ES256K-R` alg + */ + private async signES256K( + privateKeyHex: string, + alg: string | undefined, + data: Uint8Array, + ): Promise { + const signer = ES256KSigner(privateKeyHex, alg === 'ES256K-R') + const signature = await signer(data) + //base64url encoded string + return signature as string + } +} + +type Eip712Payload = { + domain: TypedDataDomain + types: Record + primaryType: string + message: Record } diff --git a/packages/selective-disclosure/plugin.schema.json b/packages/selective-disclosure/plugin.schema.json index b5813db01..a435b1aa6 100644 --- a/packages/selective-disclosure/plugin.schema.json +++ b/packages/selective-disclosure/plugin.schema.json @@ -97,7 +97,7 @@ "verifiableCredential", "proof" ], - "description": "Verifiable Presentation {@link https://github.com/decentralized-identifier/did-jwt-vc}" + "description": "Verifiable Presentation {@link https://github.com/decentralized-identifier/did-jwt-vc }" }, "VerifiableCredential": { "type": "object", @@ -174,7 +174,7 @@ "credentialSubject", "proof" ], - "description": "Verifiable Credential {@link https://github.com/decentralized-identifier/did-jwt-vc}" + "description": "Verifiable Credential {@link https://github.com/decentralized-identifier/did-jwt-vc }" }, "ICreateSelectiveDisclosureRequestArgs": { "type": "object", @@ -240,11 +240,11 @@ }, "credentialType": { "type": "string", - "description": "The credential type. See {@link https://www.w3.org/TR/vc-data-model/#types | W3C Credential Types}" + "description": "The credential type. See {@link https://www.w3.org/TR/vc-data-model/#types | W3C Credential Types }" }, "credentialContext": { "type": "string", - "description": "The credential context. See {@link https://www.w3.org/TR/vc-data-model/#contexts | W3C Credential Context}" + "description": "The credential context. See {@link https://www.w3.org/TR/vc-data-model/#contexts | W3C Credential Context }" }, "claimType": { "type": "string", @@ -345,11 +345,11 @@ }, "credentialType": { "type": "string", - "description": "The credential type. See {@link https://www.w3.org/TR/vc-data-model/#types | W3C Credential Types}" + "description": "The credential type. See {@link https://www.w3.org/TR/vc-data-model/#types | W3C Credential Types }" }, "credentialContext": { "type": "string", - "description": "The credential context. See {@link https://www.w3.org/TR/vc-data-model/#contexts | W3C Credential Context}" + "description": "The credential context. See {@link https://www.w3.org/TR/vc-data-model/#contexts | W3C Credential Context }" }, "claimType": { "type": "string", diff --git a/packages/selective-disclosure/src/action-handler.ts b/packages/selective-disclosure/src/action-handler.ts index 9e78bcb22..1835ba4f8 100644 --- a/packages/selective-disclosure/src/action-handler.ts +++ b/packages/selective-disclosure/src/action-handler.ts @@ -67,7 +67,17 @@ export class SelectiveDisclosure implements IAgentPlugin { const key = identifier.keys.find((k) => k.type === 'Secp256k1') if (!key) throw Error('Signing key not found') - const signer = (data: string | Uint8Array) => context.agent.keyManagerSignJWT({ kid: key.kid, data }) + const signer = (data: string | Uint8Array) => { + let dataString, encoding: 'base16' | undefined + if (typeof(data) === 'string') { + dataString = data + encoding = undefined + } else { + dataString = Buffer.from(data).toString("hex"), + encoding = 'base16' + } + return context.agent.keyManagerSign({ keyRef: key.kid, data: dataString, encoding }) + } const jwt = await createJWT( { type: 'sdr', diff --git a/yarn.lock b/yarn.lock index 4e13e1bbc..12ec46739 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2727,13 +2727,6 @@ resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd" integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ== -"@types/ethjs-signer@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@types/ethjs-signer/-/ethjs-signer-0.1.0.tgz#0960ba391a254d51dbef83f423dc7efa1cd081c4" - integrity sha512-Bom/6SlljFQexWsxYnMLcR18kQxUcqqfXWct7c1ZMNXYzyNNsF5RP60x7cdAhURnlYEmiTGCTO58YEhe063YbA== - dependencies: - "@types/node" "*" - "@types/express-serve-static-core@*": version "4.17.16" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.16.tgz#56626e2f60bdd9a5193bc84a1042a506eeb69da7" @@ -3573,11 +3566,6 @@ bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -bn.js@4.11.6: - version "4.11.6" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" - integrity sha1-UzRK2xRhehP26N0s4okF0cC6MhU= - bn.js@^4.0.0, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" @@ -3650,7 +3638,7 @@ braces@^3.0.1: dependencies: fill-range "^7.0.1" -brorand@^1.0.1, brorand@^1.1.0: +brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= @@ -5037,19 +5025,9 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.723: - version "1.3.741" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.741.tgz#dc1024b19b31e27fb2c8c0a1f120cb05fc6ca695" - integrity sha512-4i3T0cwnHo1O4Mnp9JniEco8bZiXoqbm3PhW5hv7uu8YLg35iajYrRnNyKFaN8/8SSTskU2hYqVTeYVPceSpUA== - -elliptic@6.3.2: - version "6.3.2" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.2.tgz#e4c81e0829cf0a65ab70e998b8232723b5c1bc48" - integrity sha1-5MgeCCnPCmWrcOmYuCMnI7XBvEg= - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - inherits "^2.0.1" + version "1.3.743" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.743.tgz#fcec24d6d647cb84fd796b42caa1b4039a180894" + integrity sha512-K2wXfo9iZQzNJNx67+Pld0DRF+9bYinj62gXCdgPhcu1vidwVuLPHQPPFnCdO55njWigXXpfBiT90jGUPbw8Zg== elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: version "6.5.4" @@ -5231,64 +5209,6 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -ethjs-format@0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/ethjs-format/-/ethjs-format-0.1.8.tgz#925ecdd965ea72a2a2daf2a122e5bf80b5ad522a" - integrity sha1-kl7N2WXqcqKi2vKhIuW/gLWtUio= - dependencies: - bn.js "4.11.6" - ethjs-schema "0.1.4" - ethjs-util "0.1.3" - is-hex-prefixed "1.0.0" - number-to-bn "1.7.0" - strip-hex-prefix "1.0.0" - -ethjs-provider-http@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-provider-http/-/ethjs-provider-http-0.1.6.tgz#1ec5d9b4be257ef1d56a500b22a741985e889420" - integrity sha1-HsXZtL4lfvHValALIqdBmF6IlCA= - dependencies: - xhr2 "0.1.3" - -ethjs-provider-signer@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/ethjs-provider-signer/-/ethjs-provider-signer-0.1.4.tgz#6bd5cb38a8d5b0ddf46ac1e23a60eea1716171ae" - integrity sha1-a9XLOKjVsN30asHiOmDuoXFhca4= - dependencies: - ethjs-provider-http "0.1.6" - ethjs-rpc "0.1.2" - -ethjs-rpc@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ethjs-rpc/-/ethjs-rpc-0.1.2.tgz#39a3456b51c59aeeafb5ba556589a59f2da88d26" - integrity sha1-OaNFa1HFmu6vtbpVZYmlny2ojSY= - dependencies: - ethjs-format "0.1.8" - -ethjs-schema@0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/ethjs-schema/-/ethjs-schema-0.1.4.tgz#0323a16333b1ace9a8f1d696a6ee63448fdd455f" - integrity sha1-AyOhYzOxrOmo8daWpu5jRI/dRV8= - -ethjs-signer@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ethjs-signer/-/ethjs-signer-0.1.1.tgz#0af77961e29ee458603aabd3660b8868d3386441" - integrity sha1-Cvd5YeKe5FhgOqvTZguIaNM4ZEE= - dependencies: - elliptic "6.3.2" - js-sha3 "0.5.5" - number-to-bn "1.1.0" - rlp "2.0.0" - strip-hex-prefix "1.0.0" - -ethjs-util@0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.3.tgz#dfd5ea4a400dc5e421a889caf47e081ada78bb55" - integrity sha1-39XqSkANxeQhqInK9H4IGtp4u1U= - dependencies: - is-hex-prefixed "1.0.0" - strip-hex-prefix "1.0.0" - ethr-did-registry@^0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/ethr-did-registry/-/ethr-did-registry-0.0.3.tgz#f363d2c73cb9572b57bd7a5c9c90c88485feceb5" @@ -6721,11 +6641,6 @@ is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" -is-hex-prefixed@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" - integrity sha1-fY035q135dEnFIkTxXPggtd39VQ= - is-installed-globally@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" @@ -7400,11 +7315,6 @@ jju@~1.4.0: resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" integrity sha1-o6vicYryQaKykE+EpiWXDzia4yo= -js-sha3@0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.5.tgz#baf0c0e8c54ad5903447df96ade7a4a1bca79a4a" - integrity sha1-uvDA6MVK1ZA0R9+Wreekobynmko= - js-sha3@0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" @@ -9212,23 +9122,6 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -number-to-bn@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.1.0.tgz#51a3387c5bc68035ab4058c626132f767d9d08bf" - integrity sha1-UaM4fFvGgDWrQFjGJhMvdn2dCL8= - dependencies: - bn.js "4.11.6" - is-hex-prefixed "1.0.0" - strip-hex-prefix "1.0.0" - -number-to-bn@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" - integrity sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA= - dependencies: - bn.js "4.11.6" - strip-hex-prefix "1.0.0" - nwsapi@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" @@ -10630,11 +10523,6 @@ rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" -rlp@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.0.0.tgz#9db384ff4b89a8f61563d92395d8625b18f3afb0" - integrity sha1-nbOE/0uJqPYVY9kjldhiWxjzr7A= - rsvp@^3.5.0: version "3.6.2" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" @@ -11349,13 +11237,6 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-hex-prefix@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" - integrity sha1-DF8VX+8RUTczd96du1iNoFUA428= - dependencies: - is-hex-prefixed "1.0.0" - strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" @@ -11934,6 +11815,13 @@ uint8arrays@^2.1.3: multibase "^4.0.1" web-encoding "^1.1.0" +uint8arrays@^2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-2.1.5.tgz#9e6e6377a9463d5eba4620a3f0450f7eb389a351" + integrity sha512-CSR7AO+4AHUeSOnZ/NBNCElDeWfRh9bXtOck27083kc7SznmmHIhNEkEOCQOn0wvrIMjS3IH0TNLR16vuc46mA== + dependencies: + multibase "^4.0.1" + umask@^1.1.0, umask@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" @@ -12404,11 +12292,6 @@ xdg-basedir@^3.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= -xhr2@0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.3.tgz#cbfc4759a69b4a888e78cf4f20b051038757bd11" - integrity sha1-y/xHWaabSoiOeM9PILBRA4dXvRE= - xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"