Skip to content

Commit

Permalink
Merge pull request #56 from Sphereon-Opensource/feature/OIDF-69
Browse files Browse the repository at this point in the history
feat: implement azure keyvault rest client
  • Loading branch information
nklomp authored Dec 4, 2024
2 parents 4ae483d + 2e28f29 commit 650ee51
Show file tree
Hide file tree
Showing 69 changed files with 3,964 additions and 1,294 deletions.
5 changes: 3 additions & 2 deletions packages/did-provider-jwk/src/jwk-did-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ const debug = Debug('sphereon:did-provider-jwk')
* @public
*/
export class JwkDIDProvider extends AbstractIdentifierProvider {
private readonly defaultKms: string
private readonly defaultKms?: string

constructor(options: { defaultKms: string }) {
constructor(options: { defaultKms?: string }) {
super()
this.defaultKms = options.defaultKms
}
Expand All @@ -23,6 +23,7 @@ export class JwkDIDProvider extends AbstractIdentifierProvider {
async createIdentifier(args: ICreateIdentifierArgs, context: IRequiredContext): Promise<Omit<IIdentifier, 'provider'>> {
const key = await importProvidedOrGeneratedKey(
{
// @ts-ignore
kms: args.kms ?? this.defaultKms,
alias: args.alias,
options: args.options,
Expand Down
5 changes: 3 additions & 2 deletions packages/did-provider-key/src/SphereonKeyDidProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ const keyCodecs = {
} as const

export class SphereonKeyDidProvider extends AbstractIdentifierProvider {
private readonly kms: string
private readonly kms?: string

constructor(options: { defaultKms: string }) {
constructor(options: { defaultKms?: string }) {
super()
this.kms = options.defaultKms
}
Expand Down Expand Up @@ -67,6 +67,7 @@ export class SphereonKeyDidProvider extends AbstractIdentifierProvider {

const key = await importProvidedOrGeneratedKey(
{
// @ts-ignore
kms: kms ?? this.kms,
alias: alias,
options: { ...options, type: keyType },
Expand Down
7 changes: 5 additions & 2 deletions packages/did-provider-oyd/src/oyd-did-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ type IContext = IAgentContext<IKeyManager>
* @public
*/
export class OydDIDProvider extends AbstractIdentifierProvider {
private defaultKms: string
private defaultKms?: string

constructor(options: { defaultKms: string }) {
constructor(options: { defaultKms?: string }) {
super()
this.defaultKms = options.defaultKms
}
Expand Down Expand Up @@ -48,6 +48,7 @@ export class OydDIDProvider extends AbstractIdentifierProvider {
const keyType: OydDidSupportedKeyTypes = options?.keyType || 'Ed25519'
const key = await this.holdKeys(
{
// @ts-ignore
kms: kms || this.defaultKms,
options: {
keyType,
Expand Down Expand Up @@ -102,6 +103,7 @@ export class OydDIDProvider extends AbstractIdentifierProvider {
private async holdKeys(args: OydDidHoldKeysArgs, context: IContext): Promise<IKey> {
if (args.options.privateKeyHex) {
return context.agent.keyManagerImport({
// @ts-ignore
kms: args.kms || this.defaultKms,
type: args.options.keyType,
kid: args.options.kid,
Expand All @@ -113,6 +115,7 @@ export class OydDIDProvider extends AbstractIdentifierProvider {
}
return context.agent.keyManagerCreate({
type: args.options.keyType,
// @ts-ignore
kms: args.kms || this.defaultKms,
meta: {
algorithms: ['Ed25519'],
Expand Down
12 changes: 6 additions & 6 deletions packages/did-utils/src/did-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,12 @@ export const getPrimaryIdentifier = async (context: IAgentContext<IDIDManager>,
}

export const createIdentifier = async (context: IAgentContext<IDIDManager>, opts?: CreateIdentifierOpts): Promise<IIdentifier> => {
return await context.agent.didManagerCreate({
kms: await getKms(context, opts?.createOpts?.kms),
...(opts?.method && {provider: `${DID_PREFIX}${opts?.method}`}),
alias: opts?.createOpts?.alias ?? `${IdentifierAliasEnum.PRIMARY}-${opts?.method}-${opts?.createOpts?.options?.type}-${new Date().toUTCString()}`,
options: opts?.createOpts?.options,
})
return await context.agent.didManagerCreate({
kms: await getKms(context, opts?.createOpts?.kms),
...(opts?.method && { provider: `${DID_PREFIX}${opts?.method}` }),
alias: opts?.createOpts?.alias ?? `${IdentifierAliasEnum.PRIMARY}-${opts?.method}-${opts?.createOpts?.options?.type}-${new Date().getTime()}`,
options: opts?.createOpts?.options,
})
}

export const getFirstKeyWithRelationFromDIDDoc = async (
Expand Down
28 changes: 22 additions & 6 deletions packages/key-manager/src/agent/SphereonKeyManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ export class SphereonKeyManager extends VeramoKeyManager {
// local store reference, given the superclass store is private, and we need additional functions/calls
private kmsStore: AbstractKeyStore
private readonly availableKmses: Record<string, AbstractKeyManagementSystem>
public readonly defaultKms: string
public _defaultKms: string
readonly kmsMethods: ISphereonKeyManager

constructor(options: { store: AbstractKeyStore; kms: Record<string, AbstractKeyManagementSystem>; defaultKms?: string }) {
super({ store: options.store, kms: options.kms })
this.kmsStore = options.store
this.availableKmses = options.kms
this.defaultKms = options.defaultKms ?? Object.keys(this.availableKmses)[0]
if (!Object.keys(this.availableKmses).includes(this.defaultKms)) {
this._defaultKms = options.defaultKms ?? Object.keys(this.availableKmses)[0]
if (!Object.keys(this.availableKmses).includes(this._defaultKms)) {
throw Error(`Default KMS needs to be listed in the kms object as well. Found kms-es: ${Object.keys(this.availableKmses).join(',')}`)
}
const methods = this.methods
Expand All @@ -47,11 +47,11 @@ export class SphereonKeyManager extends VeramoKeyManager {
}

keyManagerGetDefaultKeyManagementSystem(): Promise<string> {
return Promise.resolve(this.defaultKms)
return Promise.resolve(this._defaultKms)
}

override async keyManagerCreate(args: ISphereonKeyManagerCreateArgs): Promise<ManagedKeyInfo> {
const kms = this.getKmsByName(args.kms ?? this.defaultKms)
const kms = this.getKmsByName(args.kms ?? this._defaultKms)
const meta: KeyMetadata = { ...args.meta, ...(args.opts && { opts: args.opts }) }
if (hasKeyOptions(meta) && meta.opts?.ephemeral && !meta.opts.expiration?.removalDate) {
// Make sure we set a delete date on an ephemeral key
Expand All @@ -61,7 +61,7 @@ export class SphereonKeyManager extends VeramoKeyManager {
}
}
const partialKey = await kms.createKey({ type: args.type, meta })
const key: IKey = { ...partialKey, kms: args.kms ?? this.defaultKms }
const key: IKey = { ...partialKey, kms: args.kms ?? this._defaultKms }
key.meta = { ...meta, ...key.meta }
key.meta.jwkThumbprint = key.meta.jwkThumbprint ?? calculateJwkThumbprintForKey({ key })

Expand Down Expand Up @@ -149,4 +149,20 @@ export class SphereonKeyManager extends VeramoKeyManager {
}
}
}


get defaultKms(): string {
return this._defaultKms
}

set defaultKms(kms: string) {
if (!Object.keys(this.availableKmses).includes(kms)) {
throw Error(`Default KMS needs to be listed in the kms object as well. Found kms-es: ${Object.keys(this.availableKmses).join(',')}`)
}
this._defaultKms = kms
}

setKms(name: string, kms: AbstractKeyManagementSystem): void {
this.availableKmses[name] = kms
}
}
10 changes: 10 additions & 0 deletions packages/kms-azure-rest-client/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# [0.26.0](https://github.com/Sphereon-OpenSource/SSI-SDK-crypto-extensions/compare/v0.25.0...v0.26.0) (2024-11-26)

### Features

- create kms-azure plugin structure ([61e1a61](https://github.com/Sphereon-OpenSource/SSI-SDK-crypto-extensions/commit/61e1a61f7442acf376d5cc6e39cdacdc336b8aa3))
Empty file.
123 changes: 123 additions & 0 deletions packages/kms-azure-rest-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<!--suppress HtmlDeprecatedAttribute -->
<h1 align="center">
<br>
<a href="https://www.sphereon.com"><img src="https://sphereon.com/content/themes/sphereon/assets/img/logo.svg" alt="Sphereon" width="400"></a>
<br>Sphereon's Azure KeyVault Key Management System REST Client Plugin
<br>
</h1>

## Overview

This module provides a Key Management System (KMS) wrapper that enables the use of Azure Key Vault REST client functionalities within your application. It extends the capabilities of the `AbstractKeyManagementSystem` by integrating with Azure's robust key management features. This ensures that key generation, signing, and verification operations are handled securely and efficiently, aligning with Veramo's key management functions.

## Available Functions

- `createKey`
- `sign`
- `verify`

## Installation

To install the module, use the following command:

```bash
yarn add @sphereon/ssi-sdk-ext.kms-azure-rest-client
```

## Usage

### Creating a Key

To create a key, you need to specify the key type and optionally provide metadata, such as a key alias. Below is an example of how to create a key using the `AzureKeyVaultKeyManagementSystemRestClient`:

```typescript
import { AzureKeyVaultKeyManagementSystemRestClient } from '@sphereon/kms-azure-rest-client'

const options = {
applicationId: 'azure-keyvault-test',
vaultUrl: 'https://example.vault.azure.net/',
apiKey: 'your-api-key-here',
}

const keyManagementSystem = new AzureKeyVaultKeyManagementSystemRestClient(options)

async function createKeyExample() {
try {
const key = await keyManagementSystem.createKey({
type: 'Secp256r1',
meta: { keyAlias: 'my-secure-key' },
})

console.log('Key created:', key)
} catch (error) {
console.error('Error creating key:', error)
}
}

createKeyExample()
```

### Signing Data

To sign data, provide the key reference (`kid`) and the data to be signed:

```typescript
async function signExample() {
try {
const signature = await keyManagementSystem.sign({
keyRef: { kid: 'your-key-id' },
data: new TextEncoder().encode('data-to-sign'),
})

console.log('Signature:', signature)
} catch (error) {
console.error('Error signing data:', error)
}
}

signExample()
```

### Verifying Data

To verify data, provide the key reference (`kid`), the data, and the signature:

```typescript
async function verifyExample() {
try {
const isValid = await keyManagementSystem.verify({
keyRef: { kid: 'your-key-id' },
data: new TextEncoder().encode('data-to-verify'),
signature: 'signature-to-verify',
})

console.log('Is signature valid?', isValid)
} catch (error) {
console.error('Error verifying signature:', error)
}
}

verifyExample()
```

## Configuration

The `AzureKeyVaultKeyManagementSystemRestClient` requires the following configuration options:

- `applicationId`: A unique identifier for your application.
- `vaultUrl`: The base URL of your Azure Key Vault.
- `apiKey`: The API key for authenticating requests.

## Limitations

This implementation currently supports the following key operations:

- `createKey`
- `sign`
- `verify`

Additional functionalities like `sharedSecret`, `importKey`, `deleteKey`, and `listKeys` are not implemented in this version and will throw an error if called.

## License

This project is licensed under the [MIT License](LICENSE).
43 changes: 43 additions & 0 deletions packages/kms-azure-rest-client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "@sphereon/ssi-sdk-ext.kms-azure-rest-client",
"description": "Sphereon SSI-SDK plugin for Azure KeyVault Key Management System.",
"version": "0.26.0",
"source": "src/index.ts",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc --build",
"build:clean": "tsc --build --clean && tsc --build"
},
"dependencies": {
"@sphereon/ssi-sdk-ext.did-utils": "workspace:*",
"@sphereon/ssi-sdk-ext.key-utils": "workspace:*",
"@sphereon/ssi-types": "0.30.2-feature.SDK.41.oidf.support.286",
"@veramo/core": "4.2.0",
"@veramo/key-manager": "4.2.0",
"uint8arrays": "^3.1.1"
},
"devDependencies": {
"@types/text-encoding": "0.0.39"
},
"files": [
"dist/**/*",
"src/**/*",
"README.md",
"LICENSE"
],
"private": false,
"publishConfig": {
"access": "public"
},
"repository": "[email protected]:Sphereon-OpenSource/SSI-SDK-crypto-extensions.git",
"author": "Sphereon <[email protected]>",
"license": "Apache-2.0",
"keywords": [
"azure",
"keyvault",
"key-management",
"react-native",
"Veramo"
]
}
Loading

0 comments on commit 650ee51

Please sign in to comment.