Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement azure keyvault rest client #56

Merged
merged 47 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
432339a
chore: eSim support
sanderPostma Nov 25, 2024
d6230d8
chore: Musap attributes fix
sanderPostma Nov 26, 2024
dc69703
feat: implement azure keyvault rest client
jcmelati Nov 30, 2024
1bfa3ec
chore: update README
jcmelati Nov 30, 2024
6c161c5
chore: clean import
jcmelati Nov 30, 2024
3202b33
Merge remote-tracking branch 'origin/develop' into feature/SPRIND-124…
sanderPostma Dec 1, 2024
14a58a4
chore: lockfile
sanderPostma Dec 1, 2024
2bd7082
chore: add js-client to kms-azure-rest-client
jcmelati Dec 2, 2024
dcef76d
chore: add kms azure packages to tsconfig
jcmelati Dec 2, 2024
2dccda3
chore: update js-client code
jcmelati Dec 2, 2024
d067c14
chore: remove dependency
jcmelati Dec 2, 2024
9a3fda9
chore: disable kms rest client tests
jcmelati Dec 2, 2024
c910295
chore: remove kms rest client tests
jcmelati Dec 2, 2024
b26781d
chore: fix client import
jcmelati Dec 2, 2024
cc5ad63
fix pnpm lock
jcmelati Dec 2, 2024
b968166
fix: remove random uuid
jcmelati Dec 2, 2024
1359016
chore: replace unallowed character for azure kms
jcmelati Dec 2, 2024
ffb8097
chore: replace unallowed character for azure kms
jcmelati Dec 2, 2024
6e14c61
chore: fix publicKeyHex
jcmelati Dec 2, 2024
3cf0fd3
chore: fix publicKeyHex
jcmelati Dec 2, 2024
4dff1ad
chore: fix publicKeyHex
jcmelati Dec 2, 2024
627e21f
chore: fix publicKeyHex
jcmelati Dec 2, 2024
45808cb
chore: fix publicKeyHex
jcmelati Dec 2, 2024
6ff7b2a
chore: fix publicKeyHex
jcmelati Dec 2, 2024
d7397c3
chore: fix publicKeyHex
jcmelati Dec 2, 2024
65f9e91
Merge branch 'develop' into feature/OIDF-69
jcmelati Dec 2, 2024
742b3eb
chore: fix publicKeyHex using jwkToRawHexKey
jcmelati Dec 2, 2024
39b2dd6
chore: fix publicKeyHex using jwkToRawHexKey
jcmelati Dec 2, 2024
a3972fa
chore: fix publicKeyHex using ecJwkToRawHexKey
jcmelati Dec 2, 2024
d6d4499
chore: fix publicKeyHex using ecJwkToRawHexKey
jcmelati Dec 2, 2024
a70fbb6
chore: fix publicKeyHex using jwkToRawHexKey
jcmelati Dec 2, 2024
3a629cd
chore: fix creteKey return object
jcmelati Dec 2, 2024
6a9aa53
chore: fix creteKey return object
jcmelati Dec 2, 2024
0ffefd5
chore: use u8a to decode uint8 to string
jcmelati Dec 2, 2024
3ae9bd8
chore: fix createIdentifier genreation
jcmelati Dec 3, 2024
f67be2d
Merge branch 'develop' into feature/OIDF-69
jcmelati Dec 3, 2024
217de7e
chore: createKey; send bound key for external keys
sanderPostma Dec 3, 2024
661e959
chore: KMS management functions in SphereonKeyManager
sanderPostma Dec 3, 2024
9a6d90e
chore: MUSAP ecc_ed25519 support
sanderPostma Dec 3, 2024
16f0df8
chore: MUSAP correct key.algorithm at signing
sanderPostma Dec 3, 2024
42ba7ee
Merge remote-tracking branch 'origin/develop' into feature/SPRIND-124…
sanderPostma Dec 3, 2024
8f9e94e
Merge branch 'feature/SPRIND-124_esim' into feature/OIDF-69
jcmelati Dec 3, 2024
3bac089
chore: removed defaultKms from DID providers
sanderPostma Dec 3, 2024
dccb084
chore: removed defaultKms from DID providers
sanderPostma Dec 3, 2024
10d34a9
chore: removed defaultKms from DID providers
sanderPostma Dec 3, 2024
b7b9f07
chore: add ts-ignore on undefined kms
jcmelati Dec 4, 2024
2e28f29
chore: remove test
jcmelati Dec 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 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,7 +23,7 @@ export class JwkDIDProvider extends AbstractIdentifierProvider {
async createIdentifier(args: ICreateIdentifierArgs, context: IRequiredContext): Promise<Omit<IIdentifier, 'provider'>> {
const key = await importProvidedOrGeneratedKey(
{
kms: args.kms ?? this.defaultKms,
kms: args.kms ?? this.defaultKms ?? '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather have a ts-ignore here. Our KMS handles it correctly when no KMS is provided. Using an empty string will result in errors

alias: args.alias,
options: args.options,
},
Expand Down
6 changes: 3 additions & 3 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,7 +67,7 @@ export class SphereonKeyDidProvider extends AbstractIdentifierProvider {

const key = await importProvidedOrGeneratedKey(
{
kms: kms ?? this.kms,
kms: kms ?? this.kms ?? '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather have a ts-ignore here. Our KMS handles it correctly when no KMS is provided. Using an empty string will result in errors

alias: alias,
options: { ...options, type: keyType },
},
Expand Down
10 changes: 5 additions & 5 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,7 +48,7 @@ export class OydDIDProvider extends AbstractIdentifierProvider {
const keyType: OydDidSupportedKeyTypes = options?.keyType || 'Ed25519'
const key = await this.holdKeys(
{
kms: kms || this.defaultKms,
kms: kms || this.defaultKms || '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather have a ts-ignore here. Our KMS handles it correctly when no KMS is provided. Using an empty string will result in errors

options: {
keyType,
kid: didDoc.did + '#key-doc',
Expand Down Expand Up @@ -102,7 +102,7 @@ export class OydDIDProvider extends AbstractIdentifierProvider {
private async holdKeys(args: OydDidHoldKeysArgs, context: IContext): Promise<IKey> {
if (args.options.privateKeyHex) {
return context.agent.keyManagerImport({
kms: args.kms || this.defaultKms,
kms: args.kms || this.defaultKms || '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather have a ts-ignore here. Our KMS handles it correctly when no KMS is provided. Using an empty string will result in errors

type: args.options.keyType,
kid: args.options.kid,
privateKeyHex: args.options.privateKeyHex,
Expand All @@ -113,7 +113,7 @@ export class OydDIDProvider extends AbstractIdentifierProvider {
}
return context.agent.keyManagerCreate({
type: args.options.keyType,
kms: args.kms || this.defaultKms,
kms: args.kms || this.defaultKms || '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather have a ts-ignore here. Our KMS handles it correctly when no KMS is provided. Using an empty string will result in errors

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
Loading