Skip to content

Commit

Permalink
chore(kms-local): rename parameters of sign() method & separate sig…
Browse files Browse the repository at this point in the history
…ning code into methods
  • Loading branch information
mirceanis committed Jun 1, 2021
1 parent 402e151 commit ec5c276
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 59 deletions.
10 changes: 6 additions & 4 deletions packages/core/src/types/IKeyManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,17 @@ export interface IKeyManagerDecryptJWEArgs {
*/
export interface IKeyManagerSignArgs {
/**
* Key ID
* The key handle, as returned during `keyManagerCreateKey`
*/
kid: string
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`
*/
alg?: string
algorithm?: string

/**
* Data to sign
Expand All @@ -105,7 +107,7 @@ export interface IKeyManagerSignArgs {
/**
* If the data is a "string" then you can specify which encoding is used. Default is "utf-8"
*/
enc?: 'utf-8' | 'base16' | 'base64' | 'hex'
encoding?: 'utf-8' | 'base16' | 'base64' | 'hex'

[x: string]: any
}
Expand Down
6 changes: 3 additions & 3 deletions packages/did-provider-ethr/src/kms-eth-signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ export class KmsEthereumSigner extends Signer {
delete tx.from
}
const signature = await this.context.agent.keyManagerSign({
kid: this.controllerKey.kid,
keyRef: this.controllerKey.kid,
data: serialize(<UnsignedTransaction>tx),
alg: 'eth_signTransaction',
enc: 'base16',
algorithm: 'eth_signTransaction',
encoding: 'base16',
})
return signature
}
Expand Down
2 changes: 1 addition & 1 deletion packages/key-manager/src/key-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export class KeyManager implements IAgentPlugin {

/** {@inheritDoc @veramo/core#IKeyManager.keyManagerSign} */
async keyManagerSign(args: IKeyManagerSignArgs): Promise<string> {
const { kid, data, alg, enc, extras } = args
const { keyRef: kid, data, algorithm: alg, encoding: enc, extras } = args
const key = await this.store.get({ kid })
let dataBytes
const encoding = enc || 'utf-8'
Expand Down
137 changes: 90 additions & 47 deletions packages/kms-local/src/key-management-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class KeyManagementSystem extends AbstractKeyManagementSystem {
}
break
default:
throw Error('Key type not supported: ' + type)
throw Error('not_supported: Key type not supported: ' + type)
}

debug('Created key', type, key.publicKeyHex)
Expand Down Expand Up @@ -78,69 +78,112 @@ export class KeyManagementSystem extends AbstractKeyManagementSystem {
return unpackMessage.message
}

async sign({
key,
alg,
data,
extras,
}: {
key: IKey
alg?: string
data: Uint8Array
extras?: KMSSignerExtras
}): Promise<string> {
async sign({ key, alg, data }: { key: IKey; alg?: string; data: Uint8Array }): Promise<string> {
//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' && (typeof alg === 'undefined' || ['Ed25519', 'EdDSA'].includes(alg))) {
const signer = EdDSASigner(key.privateKeyHex)
const signature = await signer(data)
//base64url encoded string
return signature as string
return await this.signEdDSA(key.privateKeyHex, data)
} else if (key.type === 'Secp256k1') {
if (typeof alg === 'undefined' || ['ES256K', 'ES256K-R'].includes(alg)) {
const signer = ES256KSigner(key.privateKeyHex, alg === 'ES256K-R')
const signature = await signer(data)
//base64url encoded string
return signature as string
return await this.signES256K(key.privateKeyHex, alg, data)
} else if (['eth_signTransaction', 'signTransaction', 'signTx'].includes(alg)) {
const {v, r, s, type, ...tx} = parse(data)
const wallet = new Wallet(key.privateKeyHex)
const signedRawTransaction = await wallet.signTransaction(<TransactionRequest>tx)
//HEX encoded string, 0x prefixed
return signedRawTransaction
return await this.eth_signTransaction(key.privateKeyHex, data)
} else if (alg === 'eth_signMessage') {
const wallet = new Wallet(key.privateKeyHex)
const signature = await wallet.signMessage(data)
//HEX encoded string, 0x prefixed
return signature
return await this.eth_signMessage(key.privateKeyHex, data)
} else if (['eth_signTypedData', 'EthereumEip712Signature2021'].includes(alg)) {
let msg, msgDomain, msgTypes
const serializedData = toUtf8String(data)
let jsonData = JSON.parse(serializedData)
if (typeof jsonData.domain === 'object' && typeof jsonData.types === 'object') {
const { domain = undefined, types = undefined, message = undefined } = { ...extras, ...jsonData }
msg = message || jsonData
msgDomain = domain
msgTypes = types
}
if (typeof msgDomain !== 'object' || typeof msgTypes !== 'object') {
throw Error(`invalid_arguments: Cannot sign typed data. 'domain' and 'types' must be provided`)
}
const wallet = new Wallet(key.privateKeyHex)

const signature = await wallet._signTypedData(msgDomain, msgTypes, msg)
//HEX encoded string
return signature
return await this.eth_signTypedData(key.privateKeyHex, data)
}
}
throw Error(`not_supported: Cannot sign ${alg} 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 = <Eip712Payload>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(<TransactionRequest>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<string> {
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<string> {
const signer = ES256KSigner(privateKeyHex, alg === 'ES256K-R')
const signature = await signer(data)
//base64url encoded string
return signature as string
}
}

interface KMSSignerExtras {
domain?: TypedDataDomain
types?: Record<string, TypedDataField[]>
transaction?: TransactionRequest
[x: string]: any
}

type Eip712Payload = {
domain: TypedDataDomain
types: Record<string, TypedDataField[]>
primaryType: string
message: Record<string, any>
}
8 changes: 4 additions & 4 deletions packages/selective-disclosure/src/action-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ 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) => {
let dataString, enc: 'base16' | undefined
let dataString, encoding: 'base16' | undefined
if (typeof(data) === 'string') {
dataString = data
enc = undefined
encoding = undefined
} else {
dataString = Buffer.from(data).toString("hex"),
enc = 'base16'
encoding = 'base16'
}
return context.agent.keyManagerSign({ kid: key.kid, data: dataString, enc })
return context.agent.keyManagerSign({ keyRef: key.kid, data: dataString, encoding })
}
const jwt = await createJWT(
{
Expand Down

0 comments on commit ec5c276

Please sign in to comment.