@sphereon/ssi-sdk.kms-rest 0.36.1-next.47 → 0.36.1-next.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +151 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +152 -84
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/RestKeyManagementSystem.ts +131 -80
- package/src/types/index.ts +2 -0
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
calculateJwkThumbprint,
|
|
3
|
+
isHashString,
|
|
4
|
+
joseAlgorithmToDigest,
|
|
5
|
+
shaHasher,
|
|
6
|
+
signatureAlgorithmFromKeyType,
|
|
7
|
+
signatureAlgorithmToJoseAlgorithm,
|
|
8
|
+
toJwk,
|
|
9
|
+
x25519PublicHexFromPrivateHex,
|
|
10
|
+
type X509Opts,
|
|
11
|
+
} from '@sphereon/ssi-sdk-ext.key-utils'
|
|
2
12
|
import { hexToPEM, jwkToPEM, pemCertChainTox5c, PEMToHex, PEMToJwk } from '@sphereon/ssi-sdk-ext.x509-utils'
|
|
3
13
|
import type { ManagedKeyInfo as RestManagedKeyInfo } from '@sphereon/ssi-sdk.kms-rest-client'
|
|
4
14
|
import {
|
|
@@ -27,13 +37,17 @@ interface KeyManagementSystemOptions {
|
|
|
27
37
|
applicationId: string
|
|
28
38
|
baseUrl: string
|
|
29
39
|
providerId?: string
|
|
40
|
+
tenantId?: string
|
|
41
|
+
userId?: string
|
|
30
42
|
authOpts?: RestClientAuthenticationOpts
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
export class RestKeyManagementSystem extends AbstractKeyManagementSystem {
|
|
34
46
|
private client: KmsRestClient
|
|
35
47
|
private readonly id: string
|
|
36
|
-
private providerId: string | undefined
|
|
48
|
+
private readonly providerId: string | undefined
|
|
49
|
+
private readonly tenantId: string | undefined
|
|
50
|
+
private readonly userId: string | undefined
|
|
37
51
|
|
|
38
52
|
constructor(options: KeyManagementSystemOptions) {
|
|
39
53
|
super()
|
|
@@ -45,18 +59,26 @@ export class RestKeyManagementSystem extends AbstractKeyManagementSystem {
|
|
|
45
59
|
|
|
46
60
|
this.id = options.applicationId
|
|
47
61
|
this.providerId = options.providerId
|
|
62
|
+
this.tenantId = options.tenantId
|
|
63
|
+
this.userId = options.userId
|
|
48
64
|
this.client = new KmsRestClient(config)
|
|
49
65
|
}
|
|
50
66
|
|
|
51
67
|
async createKey(args: CreateKeyArgs): Promise<ManagedKeyInfo> {
|
|
52
68
|
const { type, meta } = args
|
|
53
69
|
|
|
54
|
-
const
|
|
70
|
+
const joseAlg = signatureAlgorithmFromKeyType({
|
|
71
|
+
type,
|
|
72
|
+
algorithms: meta?.algorithms as string[] | undefined,
|
|
73
|
+
})
|
|
74
|
+
const signatureAlgorithm = this.mapJoseToRestSignatureAlgorithm(joseAlg)
|
|
55
75
|
const options = {
|
|
56
76
|
use: meta && 'keyUsage' in meta ? this.mapKeyUsage(meta.keyUsage) : JwkUse.Sig,
|
|
57
77
|
alg: signatureAlgorithm,
|
|
58
78
|
keyOperations: meta && meta.keyOperations ? this.mapKeyOperations(meta.keyOperations as string[]) : [KeyOperations.Sign],
|
|
59
79
|
...(meta && 'keyAlias' in meta && meta.keyAlias ? { alias: meta.keyAlias } : {}),
|
|
80
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
81
|
+
...(this.userId && { userId: this.userId }),
|
|
60
82
|
}
|
|
61
83
|
|
|
62
84
|
const key = this.providerId
|
|
@@ -68,7 +90,7 @@ export class RestKeyManagementSystem extends AbstractKeyManagementSystem {
|
|
|
68
90
|
|
|
69
91
|
const jwk = {
|
|
70
92
|
...key.keyPair.jose.publicJwk,
|
|
71
|
-
alg: key.keyPair.jose.publicJwk.alg ?
|
|
93
|
+
alg: key.keyPair.jose.publicJwk.alg ? signatureAlgorithmToJoseAlgorithm(key.keyPair.jose.publicJwk.alg) : undefined,
|
|
72
94
|
} satisfies JWK
|
|
73
95
|
|
|
74
96
|
const kid = key.keyPair.kid ?? key.keyPair.jose.publicJwk.kid
|
|
@@ -85,7 +107,7 @@ export class RestKeyManagementSystem extends AbstractKeyManagementSystem {
|
|
|
85
107
|
algorithms: [key.keyPair.jose.publicJwk.alg ?? 'PS256'],
|
|
86
108
|
jwkThumbprint: calculateJwkThumbprint({
|
|
87
109
|
jwk,
|
|
88
|
-
digestAlgorithm:
|
|
110
|
+
digestAlgorithm: jwk.alg ? joseAlgorithmToDigest(jwk.alg) : 'sha256',
|
|
89
111
|
}),
|
|
90
112
|
},
|
|
91
113
|
publicKeyHex: Buffer.from(key.keyPair.jose.publicJwk.toString(), 'utf8').toString('base64'),
|
|
@@ -94,15 +116,20 @@ export class RestKeyManagementSystem extends AbstractKeyManagementSystem {
|
|
|
94
116
|
|
|
95
117
|
async importKey(args: ImportKeyArgs): Promise<ManagedKeyInfo> {
|
|
96
118
|
const { type } = args
|
|
97
|
-
const signatureAlgorithm = this.mapKeyTypeToSignatureAlgorithm(type)
|
|
98
119
|
const importKey = this.mapImportKey(args)
|
|
99
120
|
|
|
100
121
|
const result = this.providerId
|
|
101
122
|
? await this.client.methods.kmsClientProviderStoreKey({
|
|
102
123
|
...importKey.key,
|
|
103
124
|
providerId: this.providerId,
|
|
125
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
126
|
+
...(this.userId && { userId: this.userId }),
|
|
127
|
+
})
|
|
128
|
+
: await this.client.methods.kmsClientStoreKey({
|
|
129
|
+
...importKey.key,
|
|
130
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
131
|
+
...(this.userId && { userId: this.userId }),
|
|
104
132
|
})
|
|
105
|
-
: await this.client.methods.kmsClientStoreKey(importKey.key)
|
|
106
133
|
|
|
107
134
|
return {
|
|
108
135
|
kid: importKey.kid,
|
|
@@ -113,7 +140,7 @@ export class RestKeyManagementSystem extends AbstractKeyManagementSystem {
|
|
|
113
140
|
algorithms: [result.keyInfo.key.alg ?? 'PS256'],
|
|
114
141
|
jwkThumbprint: calculateJwkThumbprint({
|
|
115
142
|
jwk: importKey.publicKeyJwk,
|
|
116
|
-
digestAlgorithm:
|
|
143
|
+
digestAlgorithm: importKey.publicKeyJwk.alg ? joseAlgorithmToDigest(importKey.publicKeyJwk.alg) : 'sha256',
|
|
117
144
|
}),
|
|
118
145
|
},
|
|
119
146
|
publicKeyHex: Buffer.from(result.keyInfo.key.toString(), 'utf8').toString('base64'),
|
|
@@ -127,14 +154,27 @@ export class RestKeyManagementSystem extends AbstractKeyManagementSystem {
|
|
|
127
154
|
? await this.client.methods.kmsClientProviderDeleteKey({
|
|
128
155
|
aliasOrKid: kid,
|
|
129
156
|
providerId: this.providerId,
|
|
157
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
158
|
+
...(this.userId && { userId: this.userId }),
|
|
159
|
+
})
|
|
160
|
+
: await this.client.methods.kmsClientDeleteKey({
|
|
161
|
+
aliasOrKid: kid,
|
|
162
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
163
|
+
...(this.userId && { userId: this.userId }),
|
|
130
164
|
})
|
|
131
|
-
: await this.client.methods.kmsClientDeleteKey({ aliasOrKid: kid })
|
|
132
165
|
}
|
|
133
166
|
|
|
134
167
|
async listKeys(): Promise<ManagedKeyInfo[]> {
|
|
135
168
|
const keys = this.providerId
|
|
136
|
-
? await this.client.methods.kmsClientProviderListKeys({
|
|
137
|
-
|
|
169
|
+
? await this.client.methods.kmsClientProviderListKeys({
|
|
170
|
+
providerId: this.providerId,
|
|
171
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
172
|
+
...(this.userId && { userId: this.userId }),
|
|
173
|
+
})
|
|
174
|
+
: await this.client.methods.kmsClientListKeys({
|
|
175
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
176
|
+
...(this.userId && { userId: this.userId }),
|
|
177
|
+
})
|
|
138
178
|
|
|
139
179
|
const restKeys = ListKeysResponseToJSONTyped(keys, false).keyInfos
|
|
140
180
|
|
|
@@ -163,7 +203,7 @@ export class RestKeyManagementSystem extends AbstractKeyManagementSystem {
|
|
|
163
203
|
jwk,
|
|
164
204
|
jwkThumbprint: calculateJwkThumbprint({
|
|
165
205
|
jwk: jwk as JWK,
|
|
166
|
-
digestAlgorithm: restKey.
|
|
206
|
+
digestAlgorithm: restKey.key.alg ? joseAlgorithmToDigest(restKey.key.alg) : 'sha256',
|
|
167
207
|
}),
|
|
168
208
|
alias: restKey.alias,
|
|
169
209
|
providerId: restKey.providerId,
|
|
@@ -195,35 +235,84 @@ export class RestKeyManagementSystem extends AbstractKeyManagementSystem {
|
|
|
195
235
|
}
|
|
196
236
|
|
|
197
237
|
async sign(args: SignArgs): Promise<string> {
|
|
198
|
-
const { keyRef, data } = args
|
|
238
|
+
const { keyRef, data, algorithm = 'SHA-256' } = args
|
|
199
239
|
const key = this.providerId
|
|
200
240
|
? await this.client.methods.kmsClientProviderGetKey({
|
|
201
241
|
aliasOrKid: keyRef.kid,
|
|
202
242
|
providerId: this.providerId,
|
|
243
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
244
|
+
...(this.userId && { userId: this.userId }),
|
|
245
|
+
})
|
|
246
|
+
: await this.client.methods.kmsClientGetKey({
|
|
247
|
+
aliasOrKid: keyRef.kid,
|
|
248
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
249
|
+
...(this.userId && { userId: this.userId }),
|
|
203
250
|
})
|
|
204
|
-
|
|
251
|
+
|
|
252
|
+
// Check if this is an EdDSA/Ed25519 key - these algorithms MUST sign the raw message, not a hash
|
|
253
|
+
const keyAlg = key.keyInfo.key.alg
|
|
254
|
+
const isEdDSA = keyAlg === 'EdDSA' || keyAlg === 'ED25519' || key.keyInfo.key.crv === 'Ed25519'
|
|
255
|
+
|
|
256
|
+
let dataToBeSigned: Uint8Array
|
|
257
|
+
if (isEdDSA) {
|
|
258
|
+
// EdDSA signatures are computed over the raw message (PureEdDSA)
|
|
259
|
+
// The algorithm internally handles hashing with SHA-512
|
|
260
|
+
dataToBeSigned = data
|
|
261
|
+
} else {
|
|
262
|
+
// For other algorithms (RSA, ECDSA), hash the data before signing
|
|
263
|
+
// with remote signing we are not going to send the whole data over the network, we need to hash it (unless we already get a hash)
|
|
264
|
+
dataToBeSigned = isHashString(data)
|
|
265
|
+
? data
|
|
266
|
+
: shaHasher(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength), algorithm)
|
|
267
|
+
}
|
|
205
268
|
|
|
206
269
|
const signingResult = await this.client.methods.kmsClientCreateRawSignature({
|
|
207
270
|
keyInfo: key.keyInfo,
|
|
208
|
-
input: toString(
|
|
271
|
+
input: toString(dataToBeSigned, 'base64'),
|
|
272
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
273
|
+
...(this.userId && { userId: this.userId }),
|
|
209
274
|
})
|
|
210
275
|
|
|
211
276
|
return signingResult.signature
|
|
212
277
|
}
|
|
213
278
|
|
|
214
279
|
async verify(args: VerifyArgs): Promise<boolean> {
|
|
215
|
-
const { keyRef, data, signature } = args
|
|
280
|
+
const { keyRef, data, signature, algorithm = 'SHA-256' } = args
|
|
216
281
|
const key = this.providerId
|
|
217
282
|
? await this.client.methods.kmsClientProviderGetKey({
|
|
218
283
|
aliasOrKid: keyRef.kid,
|
|
219
284
|
providerId: this.providerId,
|
|
285
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
286
|
+
...(this.userId && { userId: this.userId }),
|
|
287
|
+
})
|
|
288
|
+
: await this.client.methods.kmsClientGetKey({
|
|
289
|
+
aliasOrKid: keyRef.kid,
|
|
290
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
291
|
+
...(this.userId && { userId: this.userId }),
|
|
220
292
|
})
|
|
221
|
-
|
|
293
|
+
|
|
294
|
+
// Check if this is an EdDSA/Ed25519 key - these algorithms MUST verify the raw message, not a hash
|
|
295
|
+
const keyAlg = key.keyInfo.key.alg
|
|
296
|
+
const isEdDSA = keyAlg === 'EdDSA' || keyAlg === 'ED25519' || key.keyInfo.key.crv === 'Ed25519'
|
|
297
|
+
|
|
298
|
+
let dataToBeVerified: Uint8Array
|
|
299
|
+
if (isEdDSA) {
|
|
300
|
+
// EdDSA signatures are verified over the raw message (PureEdDSA)
|
|
301
|
+
dataToBeVerified = data
|
|
302
|
+
} else {
|
|
303
|
+
// For other algorithms (RSA, ECDSA), hash the data before verifying
|
|
304
|
+
// with remote signing we are not going to send the whole data over the network, we need to hash it (unless we already get a hash)
|
|
305
|
+
dataToBeVerified = isHashString(data)
|
|
306
|
+
? data
|
|
307
|
+
: shaHasher(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength), algorithm)
|
|
308
|
+
}
|
|
222
309
|
|
|
223
310
|
const verification = await this.client.methods.kmsClientIsValidRawSignature({
|
|
224
311
|
keyInfo: key.keyInfo,
|
|
225
|
-
input: toString(
|
|
312
|
+
input: toString(dataToBeVerified, 'base64'),
|
|
226
313
|
signature,
|
|
314
|
+
...(this.tenantId && { tenantId: this.tenantId }),
|
|
315
|
+
...(this.userId && { userId: this.userId }),
|
|
227
316
|
})
|
|
228
317
|
|
|
229
318
|
return verification.isValid
|
|
@@ -233,23 +322,6 @@ export class RestKeyManagementSystem extends AbstractKeyManagementSystem {
|
|
|
233
322
|
throw new Error('sharedSecret is not implemented for REST KMS.')
|
|
234
323
|
}
|
|
235
324
|
|
|
236
|
-
private signatureAlgorithmToDigestAlgorithm = (signatureAlgorithm: SignatureAlgorithm): 'sha256' | 'sha512' => {
|
|
237
|
-
switch (signatureAlgorithm) {
|
|
238
|
-
case SignatureAlgorithm.EcdsaSha256:
|
|
239
|
-
case SignatureAlgorithm.RsaSsaPssSha256Mgf1:
|
|
240
|
-
case SignatureAlgorithm.EckaDhSha256:
|
|
241
|
-
case SignatureAlgorithm.HmacSha256:
|
|
242
|
-
case SignatureAlgorithm.Es256K:
|
|
243
|
-
return 'sha256'
|
|
244
|
-
case SignatureAlgorithm.EcdsaSha512:
|
|
245
|
-
case SignatureAlgorithm.HmacSha512:
|
|
246
|
-
case SignatureAlgorithm.RsaSsaPssSha512Mgf1:
|
|
247
|
-
return 'sha512'
|
|
248
|
-
default:
|
|
249
|
-
throw new Error(`Signature algorithm ${signatureAlgorithm} is not supported by REST KMS`)
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
325
|
private mapKeyUsage = (usage: string): JwkUse => {
|
|
254
326
|
switch (usage) {
|
|
255
327
|
case 'sig':
|
|
@@ -261,53 +333,32 @@ export class RestKeyManagementSystem extends AbstractKeyManagementSystem {
|
|
|
261
333
|
}
|
|
262
334
|
}
|
|
263
335
|
|
|
264
|
-
private
|
|
265
|
-
switch (type) {
|
|
266
|
-
case 'Secp256r1':
|
|
267
|
-
return SignatureAlgorithm.EcdsaSha256
|
|
268
|
-
case 'RSA':
|
|
269
|
-
return SignatureAlgorithm.RsaSsaPssSha256Mgf1
|
|
270
|
-
case 'X25519':
|
|
271
|
-
return SignatureAlgorithm.EckaDhSha256
|
|
272
|
-
default:
|
|
273
|
-
throw new Error(`Key type ${type} is not supported by REST KMS`)
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
private mapJoseAlgorithm = (alg: string): JoseSignatureAlgorithm => {
|
|
336
|
+
private mapJoseToRestSignatureAlgorithm = (alg: JoseSignatureAlgorithm): SignatureAlgorithm => {
|
|
278
337
|
switch (alg) {
|
|
279
|
-
case
|
|
280
|
-
return
|
|
281
|
-
case
|
|
282
|
-
return
|
|
283
|
-
case
|
|
284
|
-
return
|
|
285
|
-
case
|
|
286
|
-
return
|
|
287
|
-
case
|
|
288
|
-
return
|
|
289
|
-
case
|
|
290
|
-
return
|
|
291
|
-
case
|
|
292
|
-
return
|
|
293
|
-
case
|
|
294
|
-
return
|
|
295
|
-
case
|
|
296
|
-
return
|
|
297
|
-
case
|
|
298
|
-
return
|
|
299
|
-
case
|
|
300
|
-
return
|
|
301
|
-
case 'PS256':
|
|
302
|
-
return JoseSignatureAlgorithm.PS256
|
|
303
|
-
case 'PS384':
|
|
304
|
-
return JoseSignatureAlgorithm.PS384
|
|
305
|
-
case 'PS512':
|
|
306
|
-
return JoseSignatureAlgorithm.PS512
|
|
307
|
-
case 'none':
|
|
308
|
-
return JoseSignatureAlgorithm.none
|
|
338
|
+
case JoseSignatureAlgorithm.RS256:
|
|
339
|
+
return SignatureAlgorithm.RsaSha256
|
|
340
|
+
case JoseSignatureAlgorithm.RS384:
|
|
341
|
+
return SignatureAlgorithm.RsaSha384
|
|
342
|
+
case JoseSignatureAlgorithm.RS512:
|
|
343
|
+
return SignatureAlgorithm.RsaSha512
|
|
344
|
+
case JoseSignatureAlgorithm.PS256:
|
|
345
|
+
return SignatureAlgorithm.RsaSsaPssSha256Mgf1
|
|
346
|
+
case JoseSignatureAlgorithm.PS384:
|
|
347
|
+
return SignatureAlgorithm.RsaSsaPssSha384Mgf1
|
|
348
|
+
case JoseSignatureAlgorithm.PS512:
|
|
349
|
+
return SignatureAlgorithm.RsaSsaPssSha512Mgf1
|
|
350
|
+
case JoseSignatureAlgorithm.ES256:
|
|
351
|
+
return SignatureAlgorithm.EcdsaSha256
|
|
352
|
+
case JoseSignatureAlgorithm.ES384:
|
|
353
|
+
return SignatureAlgorithm.EcdsaSha384
|
|
354
|
+
case JoseSignatureAlgorithm.ES512:
|
|
355
|
+
return SignatureAlgorithm.EcdsaSha512
|
|
356
|
+
case JoseSignatureAlgorithm.ES256K:
|
|
357
|
+
return SignatureAlgorithm.Es256K
|
|
358
|
+
case JoseSignatureAlgorithm.EdDSA:
|
|
359
|
+
return SignatureAlgorithm.Ed25519
|
|
309
360
|
default:
|
|
310
|
-
throw new Error(`
|
|
361
|
+
throw new Error(`JOSE algorithm ${alg} not supported by REST KMS`)
|
|
311
362
|
}
|
|
312
363
|
}
|
|
313
364
|
|
package/src/types/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type CreateKeyArgs = {
|
|
|
15
15
|
export type SignArgs = {
|
|
16
16
|
keyRef: Pick<IKey, 'kid'>
|
|
17
17
|
data: Uint8Array
|
|
18
|
+
algorithm?: string
|
|
18
19
|
[x: string]: any
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -22,6 +23,7 @@ export type VerifyArgs = {
|
|
|
22
23
|
keyRef: Pick<IKey, 'kid'>
|
|
23
24
|
data: Uint8Array
|
|
24
25
|
signature: string
|
|
26
|
+
algorithm?: string
|
|
25
27
|
[x: string]: any
|
|
26
28
|
}
|
|
27
29
|
|