@opentdf/sdk 0.9.0-beta.91 → 0.9.0-beta.93
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/cjs/src/access/access-fetch.js +1 -2
- package/dist/cjs/src/access/access-rpc.js +1 -3
- package/dist/cjs/src/access.js +1 -14
- package/dist/cjs/src/auth/auth.js +13 -10
- package/dist/cjs/src/auth/dpop.js +121 -0
- package/dist/cjs/src/auth/oidc-clientcredentials-provider.js +37 -3
- package/dist/cjs/src/auth/oidc-externaljwt-provider.js +37 -3
- package/dist/cjs/src/auth/oidc-refreshtoken-provider.js +37 -3
- package/dist/cjs/src/auth/oidc.js +10 -8
- package/dist/cjs/src/auth/providers.js +35 -12
- package/dist/cjs/src/crypto/index.js +16 -2
- package/dist/cjs/src/crypto/pemPublicToCrypto.js +17 -11
- package/dist/cjs/src/opentdf.js +40 -10
- package/dist/cjs/tdf3/index.js +4 -2
- package/dist/cjs/tdf3/src/assertions.js +71 -31
- package/dist/cjs/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
- package/dist/cjs/tdf3/src/ciphers/symmetric-cipher-base.js +4 -2
- package/dist/cjs/tdf3/src/client/index.js +23 -33
- package/dist/cjs/tdf3/src/crypto/crypto-utils.js +12 -5
- package/dist/cjs/tdf3/src/crypto/declarations.js +1 -1
- package/dist/cjs/tdf3/src/crypto/index.js +849 -88
- package/dist/cjs/tdf3/src/crypto/jose/jwt-claims-set.js +11 -0
- package/dist/cjs/tdf3/src/crypto/jose/validate-crit.js +8 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/buffer_utils.js +41 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/epoch.js +6 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/is_object.js +21 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.js +112 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/secs.js +60 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/validate_crit.js +38 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/util/errors.js +135 -0
- package/dist/cjs/tdf3/src/crypto/jwt.js +183 -0
- package/dist/cjs/tdf3/src/crypto/salt.js +14 -8
- package/dist/cjs/tdf3/src/models/encryption-information.js +17 -20
- package/dist/cjs/tdf3/src/models/key-access.js +43 -63
- package/dist/cjs/tdf3/src/tdf.js +75 -75
- package/dist/cjs/tdf3/src/utils/index.js +5 -39
- package/dist/types/src/access/access-fetch.d.ts.map +1 -1
- package/dist/types/src/access/access-rpc.d.ts.map +1 -1
- package/dist/types/src/access.d.ts +0 -5
- package/dist/types/src/access.d.ts.map +1 -1
- package/dist/types/src/auth/auth.d.ts +9 -6
- package/dist/types/src/auth/auth.d.ts.map +1 -1
- package/dist/types/src/auth/dpop.d.ts +60 -0
- package/dist/types/src/auth/dpop.d.ts.map +1 -0
- package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts +3 -2
- package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc-externaljwt-provider.d.ts +3 -2
- package/dist/types/src/auth/oidc-externaljwt-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts +3 -2
- package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc.d.ts +6 -4
- package/dist/types/src/auth/oidc.d.ts.map +1 -1
- package/dist/types/src/auth/providers.d.ts +5 -4
- package/dist/types/src/auth/providers.d.ts.map +1 -1
- package/dist/types/src/crypto/index.d.ts +2 -1
- package/dist/types/src/crypto/index.d.ts.map +1 -1
- package/dist/types/src/crypto/pemPublicToCrypto.d.ts +18 -0
- package/dist/types/src/crypto/pemPublicToCrypto.d.ts.map +1 -1
- package/dist/types/src/opentdf.d.ts +13 -4
- package/dist/types/src/opentdf.d.ts.map +1 -1
- package/dist/types/tdf3/index.d.ts +3 -3
- package/dist/types/tdf3/index.d.ts.map +1 -1
- package/dist/types/tdf3/src/assertions.d.ts +23 -8
- package/dist/types/tdf3/src/assertions.d.ts.map +1 -1
- package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts +3 -3
- package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts.map +1 -1
- package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts +4 -4
- package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts.map +1 -1
- package/dist/types/tdf3/src/client/builders.d.ts +2 -2
- package/dist/types/tdf3/src/client/builders.d.ts.map +1 -1
- package/dist/types/tdf3/src/client/index.d.ts +6 -5
- package/dist/types/tdf3/src/client/index.d.ts.map +1 -1
- package/dist/types/tdf3/src/crypto/crypto-utils.d.ts +14 -4
- package/dist/types/tdf3/src/crypto/crypto-utils.d.ts.map +1 -1
- package/dist/types/tdf3/src/crypto/declarations.d.ts +283 -18
- package/dist/types/tdf3/src/crypto/declarations.d.ts.map +1 -1
- package/dist/types/tdf3/src/crypto/index.d.ts +105 -28
- package/dist/types/tdf3/src/crypto/index.d.ts.map +1 -1
- package/dist/types/tdf3/src/crypto/jose/jwt-claims-set.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/jwt-claims-set.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/validate-crit.d.ts +5 -0
- package/dist/types/tdf3/src/crypto/jose/validate-crit.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/buffer_utils.d.ts +6 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/buffer_utils.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/epoch.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/epoch.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/is_object.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/is_object.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/secs.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/secs.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/validate_crit.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/validate_crit.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/util/errors.d.ts +76 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/util/errors.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jwt.d.ts +76 -0
- package/dist/types/tdf3/src/crypto/jwt.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/salt.d.ts +6 -1
- package/dist/types/tdf3/src/crypto/salt.d.ts.map +1 -1
- package/dist/types/tdf3/src/models/encryption-information.d.ts +4 -4
- package/dist/types/tdf3/src/models/encryption-information.d.ts.map +1 -1
- package/dist/types/tdf3/src/models/key-access.d.ts +8 -5
- package/dist/types/tdf3/src/models/key-access.d.ts.map +1 -1
- package/dist/types/tdf3/src/tdf.d.ts +8 -8
- package/dist/types/tdf3/src/tdf.d.ts.map +1 -1
- package/dist/types/tdf3/src/utils/index.d.ts +4 -3
- package/dist/types/tdf3/src/utils/index.d.ts.map +1 -1
- package/dist/web/src/access/access-fetch.js +3 -4
- package/dist/web/src/access/access-rpc.js +3 -5
- package/dist/web/src/access.js +1 -13
- package/dist/web/src/auth/auth.js +13 -10
- package/dist/web/src/auth/dpop.js +118 -0
- package/dist/web/src/auth/oidc-clientcredentials-provider.js +4 -3
- package/dist/web/src/auth/oidc-externaljwt-provider.js +4 -3
- package/dist/web/src/auth/oidc-refreshtoken-provider.js +4 -3
- package/dist/web/src/auth/oidc.js +11 -9
- package/dist/web/src/auth/providers.js +13 -12
- package/dist/web/src/crypto/index.js +4 -2
- package/dist/web/src/crypto/pemPublicToCrypto.js +11 -9
- package/dist/web/src/opentdf.js +7 -10
- package/dist/web/tdf3/index.js +3 -2
- package/dist/web/tdf3/src/assertions.js +71 -31
- package/dist/web/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
- package/dist/web/tdf3/src/ciphers/symmetric-cipher-base.js +4 -2
- package/dist/web/tdf3/src/client/index.js +25 -35
- package/dist/web/tdf3/src/crypto/crypto-utils.js +12 -5
- package/dist/web/tdf3/src/crypto/declarations.js +1 -1
- package/dist/web/tdf3/src/crypto/index.js +830 -84
- package/dist/web/tdf3/src/crypto/jose/jwt-claims-set.js +5 -0
- package/dist/web/tdf3/src/crypto/jose/validate-crit.js +3 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/buffer_utils.js +35 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/epoch.js +4 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/is_object.js +19 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.js +107 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/secs.js +58 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/validate_crit.js +36 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/util/errors.js +117 -0
- package/dist/web/tdf3/src/crypto/jwt.js +174 -0
- package/dist/web/tdf3/src/crypto/salt.js +13 -7
- package/dist/web/tdf3/src/models/encryption-information.js +11 -14
- package/dist/web/tdf3/src/models/key-access.js +44 -31
- package/dist/web/tdf3/src/tdf.js +71 -71
- package/dist/web/tdf3/src/utils/index.js +5 -6
- package/package.json +11 -4
- package/src/access/access-fetch.ts +2 -8
- package/src/access/access-rpc.ts +0 -7
- package/src/access.ts +0 -17
- package/src/auth/auth.ts +21 -12
- package/src/auth/dpop.ts +222 -0
- package/src/auth/oidc-clientcredentials-provider.ts +23 -15
- package/src/auth/oidc-externaljwt-provider.ts +23 -15
- package/src/auth/oidc-refreshtoken-provider.ts +23 -15
- package/src/auth/oidc.ts +21 -10
- package/src/auth/providers.ts +46 -29
- package/src/crypto/index.ts +21 -1
- package/src/crypto/pemPublicToCrypto.ts +11 -9
- package/src/opentdf.ts +19 -14
- package/tdf3/index.ts +32 -5
- package/tdf3/src/assertions.ts +99 -30
- package/tdf3/src/ciphers/aes-gcm-cipher.ts +7 -2
- package/tdf3/src/ciphers/symmetric-cipher-base.ts +7 -4
- package/tdf3/src/client/builders.ts +2 -2
- package/tdf3/src/client/index.ts +60 -59
- package/tdf3/src/crypto/crypto-utils.ts +15 -8
- package/tdf3/src/crypto/declarations.ts +338 -22
- package/tdf3/src/crypto/index.ts +1021 -118
- package/tdf3/src/crypto/jose/jwt-claims-set.ts +10 -0
- package/tdf3/src/crypto/jose/validate-crit.ts +9 -0
- package/tdf3/src/crypto/jose/vendor/lib/buffer_utils.ts +34 -0
- package/tdf3/src/crypto/jose/vendor/lib/epoch.ts +3 -0
- package/tdf3/src/crypto/jose/vendor/lib/is_object.ts +18 -0
- package/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.ts +106 -0
- package/tdf3/src/crypto/jose/vendor/lib/secs.ts +57 -0
- package/tdf3/src/crypto/jose/vendor/lib/validate_crit.ts +35 -0
- package/tdf3/src/crypto/jose/vendor/util/errors.ts +101 -0
- package/tdf3/src/crypto/jwt.ts +256 -0
- package/tdf3/src/crypto/salt.ts +16 -8
- package/tdf3/src/models/encryption-information.ts +14 -21
- package/tdf3/src/models/key-access.ts +57 -41
- package/tdf3/src/tdf.ts +110 -93
- package/tdf3/src/utils/index.ts +5 -6
package/src/auth/oidc.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { default as dpopFn } from 'dpop';
|
|
1
|
+
import { default as dpopFn } from './dpop.js';
|
|
2
2
|
import { HttpRequest, withHeaders } from './auth.js';
|
|
3
3
|
import { base64 } from '../encodings/index.js';
|
|
4
4
|
import { ConfigurationError, TdfError } from '../errors.js';
|
|
5
|
-
import {
|
|
5
|
+
import { rstrip } from '../utils.js';
|
|
6
|
+
import { type CryptoService, type KeyPair } from '../../tdf3/src/crypto/declarations.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Common fields used by all OIDC credentialing flows.
|
|
@@ -18,7 +19,7 @@ export type CommonCredentials = {
|
|
|
18
19
|
dpopEnabled?: boolean;
|
|
19
20
|
|
|
20
21
|
/** the client's public key, base64 encoded. Will be bound to the OIDC token. Deprecated. If not set in the constructor, */
|
|
21
|
-
signingKey?:
|
|
22
|
+
signingKey?: KeyPair;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -94,13 +95,15 @@ export class AccessToken {
|
|
|
94
95
|
tokenEndpoint: string;
|
|
95
96
|
userInfoEndpoint: string;
|
|
96
97
|
|
|
97
|
-
signingKey?:
|
|
98
|
+
signingKey?: KeyPair;
|
|
98
99
|
|
|
99
100
|
extraHeaders: Record<string, string> = {};
|
|
100
101
|
|
|
101
102
|
currentAccessToken?: string;
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
cryptoService: CryptoService;
|
|
105
|
+
|
|
106
|
+
constructor(cfg: OIDCCredentials, cryptoService: CryptoService, request?: typeof fetch) {
|
|
104
107
|
if (!cfg.clientId) {
|
|
105
108
|
throw new ConfigurationError(
|
|
106
109
|
'A Keycloak client identifier is currently required for all auth mechanisms'
|
|
@@ -121,6 +124,7 @@ export class AccessToken {
|
|
|
121
124
|
throw new ConfigurationError('Invalid oidc configuration');
|
|
122
125
|
}
|
|
123
126
|
this.config = cfg;
|
|
127
|
+
this.cryptoService = cryptoService;
|
|
124
128
|
this.request = request;
|
|
125
129
|
this.baseUrl = rstrip(cfg.oidcOrigin, '/');
|
|
126
130
|
this.tokenEndpoint = cfg.oidcTokenEndpoint || `${this.baseUrl}/protocol/openid-connect/token`;
|
|
@@ -140,7 +144,12 @@ export class AccessToken {
|
|
|
140
144
|
Authorization: `Bearer ${accessToken}`,
|
|
141
145
|
} as Record<string, string>;
|
|
142
146
|
if (this.config.dpopEnabled && this.signingKey) {
|
|
143
|
-
headers.DPoP = await dpopFn(
|
|
147
|
+
headers.DPoP = await dpopFn(
|
|
148
|
+
this.signingKey,
|
|
149
|
+
this.cryptoService,
|
|
150
|
+
this.userInfoEndpoint,
|
|
151
|
+
'POST'
|
|
152
|
+
);
|
|
144
153
|
}
|
|
145
154
|
const response = await (this.request || fetch)(this.userInfoEndpoint, {
|
|
146
155
|
headers,
|
|
@@ -165,9 +174,10 @@ export class AccessToken {
|
|
|
165
174
|
if (!this.signingKey) {
|
|
166
175
|
throw new ConfigurationError('No signature configured');
|
|
167
176
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
headers
|
|
177
|
+
// Export opaque public key to PEM format for header
|
|
178
|
+
const publicKeyPem = await this.cryptoService.exportPublicKeyPem(this.signingKey.publicKey);
|
|
179
|
+
headers['X-VirtruPubKey'] = base64.encode(publicKeyPem);
|
|
180
|
+
headers.DPoP = await dpopFn(this.signingKey, this.cryptoService, url, 'POST');
|
|
171
181
|
}
|
|
172
182
|
return (this.request || fetch)(url, {
|
|
173
183
|
method: 'POST',
|
|
@@ -251,7 +261,7 @@ export class AccessToken {
|
|
|
251
261
|
*
|
|
252
262
|
* Calling this function will trigger a forcible token refresh using the cached refresh token, and contact the auth server.
|
|
253
263
|
*/
|
|
254
|
-
async refreshTokenClaimsWithClientPubkeyIfNeeded(signingKey:
|
|
264
|
+
async refreshTokenClaimsWithClientPubkeyIfNeeded(signingKey: KeyPair): Promise<void> {
|
|
255
265
|
// If we already have a token, and the pubkey changes,
|
|
256
266
|
// we need to force a refresh now - otherwise
|
|
257
267
|
// we can wait until we create the token for the first time
|
|
@@ -299,6 +309,7 @@ export class AccessToken {
|
|
|
299
309
|
if (this.config.dpopEnabled && this.signingKey) {
|
|
300
310
|
const dpopToken = await dpopFn(
|
|
301
311
|
this.signingKey,
|
|
312
|
+
this.cryptoService,
|
|
302
313
|
httpReq.url,
|
|
303
314
|
httpReq.method,
|
|
304
315
|
/* nonce */ undefined,
|
package/src/auth/providers.ts
CHANGED
|
@@ -10,6 +10,8 @@ import { type AuthProvider } from './auth.js';
|
|
|
10
10
|
import { OIDCRefreshTokenProvider } from './oidc-refreshtoken-provider.js';
|
|
11
11
|
import { isBrowser } from '../utils.js';
|
|
12
12
|
import { ConfigurationError } from '../errors.js';
|
|
13
|
+
import { type CryptoService } from '../../tdf3/src/crypto/declarations.js';
|
|
14
|
+
import * as defaultCryptoService from '../../tdf3/src/crypto/index.js';
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
17
|
* Creates an OIDC Client Credentials Provider for non-browser contexts.
|
|
@@ -30,15 +32,19 @@ import { ConfigurationError } from '../errors.js';
|
|
|
30
32
|
*
|
|
31
33
|
*/
|
|
32
34
|
export const clientSecretAuthProvider = async (
|
|
33
|
-
clientConfig: ClientSecretCredentials
|
|
35
|
+
clientConfig: ClientSecretCredentials,
|
|
36
|
+
cryptoService: CryptoService = defaultCryptoService
|
|
34
37
|
): Promise<OIDCClientCredentialsProvider> => {
|
|
35
|
-
return new OIDCClientCredentialsProvider(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
return new OIDCClientCredentialsProvider(
|
|
39
|
+
{
|
|
40
|
+
clientId: clientConfig.clientId,
|
|
41
|
+
clientSecret: clientConfig.clientSecret,
|
|
42
|
+
oidcOrigin: clientConfig.oidcOrigin,
|
|
43
|
+
oidcTokenEndpoint: clientConfig.oidcTokenEndpoint,
|
|
44
|
+
oidcUserInfoEndpoint: clientConfig.oidcUserInfoEndpoint,
|
|
45
|
+
},
|
|
46
|
+
cryptoService
|
|
47
|
+
);
|
|
42
48
|
};
|
|
43
49
|
|
|
44
50
|
/**
|
|
@@ -58,15 +64,19 @@ export const clientSecretAuthProvider = async (
|
|
|
58
64
|
* {@link updateClientPublicKey}, which will force an explicit token refresh.
|
|
59
65
|
*/
|
|
60
66
|
export const externalAuthProvider = async (
|
|
61
|
-
clientConfig: ExternalJwtCredentials
|
|
67
|
+
clientConfig: ExternalJwtCredentials,
|
|
68
|
+
cryptoService: CryptoService = defaultCryptoService
|
|
62
69
|
): Promise<OIDCExternalJwtProvider> => {
|
|
63
|
-
return new OIDCExternalJwtProvider(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
return new OIDCExternalJwtProvider(
|
|
71
|
+
{
|
|
72
|
+
clientId: clientConfig.clientId,
|
|
73
|
+
externalJwt: clientConfig.externalJwt,
|
|
74
|
+
oidcOrigin: clientConfig.oidcOrigin,
|
|
75
|
+
oidcTokenEndpoint: clientConfig.oidcTokenEndpoint,
|
|
76
|
+
oidcUserInfoEndpoint: clientConfig.oidcUserInfoEndpoint,
|
|
77
|
+
},
|
|
78
|
+
cryptoService
|
|
79
|
+
);
|
|
70
80
|
};
|
|
71
81
|
|
|
72
82
|
/**
|
|
@@ -84,15 +94,19 @@ export const externalAuthProvider = async (
|
|
|
84
94
|
* {@link updateClientPublicKey} which will force an explicit token refresh
|
|
85
95
|
*/
|
|
86
96
|
export const refreshAuthProvider = async (
|
|
87
|
-
clientConfig: RefreshTokenCredentials
|
|
97
|
+
clientConfig: RefreshTokenCredentials,
|
|
98
|
+
cryptoService: CryptoService = defaultCryptoService
|
|
88
99
|
): Promise<OIDCRefreshTokenProvider> => {
|
|
89
|
-
return new OIDCRefreshTokenProvider(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
100
|
+
return new OIDCRefreshTokenProvider(
|
|
101
|
+
{
|
|
102
|
+
clientId: clientConfig.clientId,
|
|
103
|
+
refreshToken: clientConfig.refreshToken,
|
|
104
|
+
oidcOrigin: clientConfig.oidcOrigin,
|
|
105
|
+
oidcTokenEndpoint: clientConfig.oidcTokenEndpoint,
|
|
106
|
+
oidcUserInfoEndpoint: clientConfig.oidcUserInfoEndpoint,
|
|
107
|
+
},
|
|
108
|
+
cryptoService
|
|
109
|
+
);
|
|
96
110
|
};
|
|
97
111
|
|
|
98
112
|
/**
|
|
@@ -100,7 +114,10 @@ export const refreshAuthProvider = async (
|
|
|
100
114
|
* @param clientConfig OIDC client credentials
|
|
101
115
|
* @returns a promise for a new auth provider with the requested excahnge type
|
|
102
116
|
*/
|
|
103
|
-
export const clientAuthProvider = async (
|
|
117
|
+
export const clientAuthProvider = async (
|
|
118
|
+
clientConfig: OIDCCredentials,
|
|
119
|
+
cryptoService: CryptoService = defaultCryptoService
|
|
120
|
+
): Promise<AuthProvider> => {
|
|
104
121
|
if (!clientConfig.clientId) {
|
|
105
122
|
throw new ConfigurationError('Client ID must be provided to constructor');
|
|
106
123
|
}
|
|
@@ -116,13 +133,13 @@ export const clientAuthProvider = async (clientConfig: OIDCCredentials): Promise
|
|
|
116
133
|
//and provide us with a valid refresh token/clientId obtained from that process.
|
|
117
134
|
switch (clientConfig.exchange) {
|
|
118
135
|
case 'refresh': {
|
|
119
|
-
return refreshAuthProvider(clientConfig);
|
|
136
|
+
return refreshAuthProvider(clientConfig, cryptoService);
|
|
120
137
|
}
|
|
121
138
|
case 'external': {
|
|
122
|
-
return externalAuthProvider(clientConfig);
|
|
139
|
+
return externalAuthProvider(clientConfig, cryptoService);
|
|
123
140
|
}
|
|
124
141
|
case 'client': {
|
|
125
|
-
return clientSecretAuthProvider(clientConfig);
|
|
142
|
+
return clientSecretAuthProvider(clientConfig, cryptoService);
|
|
126
143
|
}
|
|
127
144
|
default:
|
|
128
145
|
throw new ConfigurationError(`Unsupported client type`);
|
|
@@ -136,7 +153,7 @@ export const clientAuthProvider = async (clientConfig: OIDCCredentials): Promise
|
|
|
136
153
|
'When using client credentials, must supply both client ID and client secret to constructor'
|
|
137
154
|
);
|
|
138
155
|
}
|
|
139
|
-
return clientSecretAuthProvider(clientConfig);
|
|
156
|
+
return clientSecretAuthProvider(clientConfig, cryptoService);
|
|
140
157
|
};
|
|
141
158
|
|
|
142
159
|
export * from './auth.js';
|
package/src/crypto/index.ts
CHANGED
|
@@ -6,5 +6,25 @@ export { generateKeyPair } from './generateKeyPair.js';
|
|
|
6
6
|
export { keyAgreement } from './keyAgreement.js';
|
|
7
7
|
export { default as exportCryptoKey } from './exportCryptoKey.js';
|
|
8
8
|
export { generateRandomNumber } from './generateRandomNumber.js';
|
|
9
|
-
export {
|
|
9
|
+
export {
|
|
10
|
+
pemPublicToCrypto,
|
|
11
|
+
pemCertToCrypto,
|
|
12
|
+
guessAlgorithmName,
|
|
13
|
+
guessCurveName,
|
|
14
|
+
toJwsAlg,
|
|
15
|
+
RSA_OID,
|
|
16
|
+
EC_OID,
|
|
17
|
+
P256_OID,
|
|
18
|
+
P384_OID,
|
|
19
|
+
P521_OID,
|
|
20
|
+
type AlgorithmName,
|
|
21
|
+
} from './pemPublicToCrypto.js';
|
|
10
22
|
export * as enums from './enums.js';
|
|
23
|
+
|
|
24
|
+
// PEM Formatting Utilities from tdf3
|
|
25
|
+
export {
|
|
26
|
+
formatAsPem,
|
|
27
|
+
removePemFormatting,
|
|
28
|
+
isPemKeyPair,
|
|
29
|
+
isCryptoKeyPair,
|
|
30
|
+
} from '../../tdf3/src/crypto/crypto-utils.js';
|
|
@@ -33,11 +33,12 @@ import { encodeArrayBuffer as hexEncodeArrayBuffer } from '../encodings/hex.js';
|
|
|
33
33
|
import { ConfigurationError, TdfError } from '../errors.js';
|
|
34
34
|
import { NamedCurve } from './enums.js';
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const
|
|
36
|
+
// OID constants for algorithm detection (hex-encoded ASN.1 OIDs)
|
|
37
|
+
export const RSA_OID = '06092a864886f70d010101';
|
|
38
|
+
export const EC_OID = '06072a8648ce3d0201';
|
|
39
|
+
export const P256_OID = '06082a8648ce3d030107';
|
|
40
|
+
export const P384_OID = '06052b81040022';
|
|
41
|
+
export const P521_OID = '06052b81040023';
|
|
41
42
|
const SHA_512 = 'SHA-512';
|
|
42
43
|
const SPKI = 'spki';
|
|
43
44
|
const CERT_BEGIN = '-----BEGIN CERTIFICATE-----';
|
|
@@ -47,7 +48,7 @@ const ECDH = 'ECDH';
|
|
|
47
48
|
const ECDSA = 'ECDSA';
|
|
48
49
|
const RSA_OAEP = 'RSA-OAEP';
|
|
49
50
|
const RSA_PSS = 'RSA-PSS';
|
|
50
|
-
type AlgorithmName = typeof ECDH | typeof ECDSA | typeof RSA_OAEP | typeof RSA_PSS;
|
|
51
|
+
export type AlgorithmName = typeof ECDH | typeof ECDSA | typeof RSA_OAEP | typeof RSA_PSS;
|
|
51
52
|
|
|
52
53
|
interface PemPublicToCryptoOptions {
|
|
53
54
|
name?: string;
|
|
@@ -71,7 +72,7 @@ function guessKeyUsages(algorithmName: AlgorithmName, usages?: KeyUsage[]): KeyU
|
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
function guessAlgorithmName(hex: string, algorithmName?: string): AlgorithmName {
|
|
75
|
+
export function guessAlgorithmName(hex: string, algorithmName?: string): AlgorithmName {
|
|
75
76
|
if (hex.includes(EC_OID)) {
|
|
76
77
|
if (!algorithmName || algorithmName === ECDH) {
|
|
77
78
|
return ECDH;
|
|
@@ -88,7 +89,7 @@ function guessAlgorithmName(hex: string, algorithmName?: string): AlgorithmName
|
|
|
88
89
|
throw new TypeError(`Invalid public key, ${algorithmName}`);
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
function guessCurveName(hex: string): NamedCurve {
|
|
92
|
+
export function guessCurveName(hex: string): NamedCurve {
|
|
92
93
|
if (hex.includes(P256_OID)) {
|
|
93
94
|
return NamedCurve.P256;
|
|
94
95
|
} else if (hex.includes(P384_OID)) {
|
|
@@ -155,9 +156,10 @@ export async function pemPublicToCrypto(
|
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
/**
|
|
159
|
+
* Detect JWS algorithm from hex-encoded key/certificate data.
|
|
158
160
|
* Look up JWK algorithm at https://github.com/panva/jose/issues/210
|
|
159
161
|
*/
|
|
160
|
-
function toJwsAlg(hex: string) {
|
|
162
|
+
export function toJwsAlg(hex: string) {
|
|
161
163
|
const a = guessAlgorithmName(hex);
|
|
162
164
|
if (a === ECDH) {
|
|
163
165
|
return 'ECDH-ES';
|
package/src/opentdf.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { ConfigurationError, InvalidFileError } from './errors.js';
|
|
|
3
3
|
export { Client as TDF3Client } from '../tdf3/src/client/index.js';
|
|
4
4
|
import { Chunker, fromSource, sourceToStream, type Source } from './seekable.js';
|
|
5
5
|
import { Client as TDF3Client } from '../tdf3/src/client/index.js';
|
|
6
|
+
import { type CryptoService, type KeyPair } from '../tdf3/src/crypto/declarations.js';
|
|
7
|
+
import * as DefaultCryptoService from '../tdf3/src/crypto/index.js';
|
|
6
8
|
import {
|
|
7
9
|
type Assertion,
|
|
8
10
|
AssertionConfig,
|
|
@@ -33,6 +35,7 @@ import { Policy } from '../tdf3/src/models/policy.js';
|
|
|
33
35
|
|
|
34
36
|
export {
|
|
35
37
|
type Assertion,
|
|
38
|
+
type CryptoService,
|
|
36
39
|
type EncryptionInformation,
|
|
37
40
|
type IntegrityAlgorithm,
|
|
38
41
|
type KasPublicKeyAlgorithm,
|
|
@@ -172,7 +175,14 @@ export type OpenTDFOptions = {
|
|
|
172
175
|
* These often must be registered via a DPoP flow with the IdP
|
|
173
176
|
* which is out of the scope of this library.
|
|
174
177
|
*/
|
|
175
|
-
dpopKeys?: Promise<
|
|
178
|
+
dpopKeys?: Promise<KeyPair>;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Optional custom CryptoService implementation.
|
|
182
|
+
* If not provided, defaults to the browser's native Web Crypto API.
|
|
183
|
+
* This allows injecting HSM-backed or other secure crypto implementations.
|
|
184
|
+
*/
|
|
185
|
+
cryptoService?: CryptoService;
|
|
176
186
|
};
|
|
177
187
|
|
|
178
188
|
/** A decorated readable stream. */
|
|
@@ -257,7 +267,9 @@ export class OpenTDF {
|
|
|
257
267
|
/** Default options for reading TDF objects. */
|
|
258
268
|
defaultReadOptions: Omit<ReadOptions, 'source'>;
|
|
259
269
|
/** The DPoP keys for this instance, if any. */
|
|
260
|
-
readonly dpopKeys: Promise<
|
|
270
|
+
readonly dpopKeys: Promise<KeyPair>;
|
|
271
|
+
/** The CryptoService implementation for this instance. */
|
|
272
|
+
readonly cryptoService: CryptoService;
|
|
261
273
|
/** The TDF3 client for encrypting and decrypting ZTDF files. */
|
|
262
274
|
readonly tdf3Client: TDF3Client;
|
|
263
275
|
|
|
@@ -269,6 +281,7 @@ export class OpenTDF {
|
|
|
269
281
|
disableDPoP,
|
|
270
282
|
policyEndpoint,
|
|
271
283
|
platformUrl,
|
|
284
|
+
cryptoService,
|
|
272
285
|
}: OpenTDFOptions) {
|
|
273
286
|
this.authProvider = authProvider;
|
|
274
287
|
this.defaultCreateOptions = defaultCreateOptions || {};
|
|
@@ -282,25 +295,17 @@ export class OpenTDF {
|
|
|
282
295
|
);
|
|
283
296
|
}
|
|
284
297
|
this.policyEndpoint = policyEndpoint || '';
|
|
298
|
+
this.cryptoService = cryptoService ?? DefaultCryptoService;
|
|
285
299
|
this.tdf3Client = new TDF3Client({
|
|
286
300
|
authProvider,
|
|
287
301
|
dpopKeys,
|
|
288
302
|
kasEndpoint: this.platformUrl || 'https://disallow.all.invalid',
|
|
289
303
|
platformUrl,
|
|
290
304
|
policyEndpoint,
|
|
305
|
+
cryptoService: this.cryptoService,
|
|
291
306
|
});
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
crypto.subtle.generateKey(
|
|
295
|
-
{
|
|
296
|
-
name: 'RSASSA-PKCS1-v1_5',
|
|
297
|
-
hash: 'SHA-256',
|
|
298
|
-
modulusLength: 2048,
|
|
299
|
-
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
|
300
|
-
},
|
|
301
|
-
true,
|
|
302
|
-
['sign', 'verify']
|
|
303
|
-
);
|
|
307
|
+
// Use CryptoService for key generation (returns opaque KeyPair)
|
|
308
|
+
this.dpopKeys = dpopKeys ?? this.cryptoService.generateSigningKeyPair();
|
|
304
309
|
}
|
|
305
310
|
|
|
306
311
|
/** Creates a new ZTDF stream. */
|
package/tdf3/index.ts
CHANGED
|
@@ -14,10 +14,23 @@ import {
|
|
|
14
14
|
} from './src/client/builders.js';
|
|
15
15
|
import { type ClientConfig, createSessionKeys } from './src/client/index.js';
|
|
16
16
|
import {
|
|
17
|
+
type AsymmetricSigningAlgorithm,
|
|
17
18
|
type CryptoService,
|
|
18
19
|
type DecryptResult,
|
|
20
|
+
type ECCurve,
|
|
19
21
|
type EncryptResult,
|
|
22
|
+
type HashAlgorithm,
|
|
23
|
+
type HkdfParams,
|
|
24
|
+
type KeyPair,
|
|
25
|
+
type KeyOptions,
|
|
26
|
+
type KeyAlgorithm,
|
|
20
27
|
type PemKeyPair,
|
|
28
|
+
type PrivateKey,
|
|
29
|
+
type PublicKey,
|
|
30
|
+
type PublicKeyInfo,
|
|
31
|
+
type SigningAlgorithm,
|
|
32
|
+
type SymmetricKey,
|
|
33
|
+
type SymmetricSigningAlgorithm,
|
|
21
34
|
} from './src/crypto/declarations.js';
|
|
22
35
|
import { Client, Errors, TDF3Client } from './src/index.js';
|
|
23
36
|
import {
|
|
@@ -35,18 +48,31 @@ import { type Chunker } from '../src/seekable.js';
|
|
|
35
48
|
export type {
|
|
36
49
|
AlgorithmName,
|
|
37
50
|
AlgorithmUrn,
|
|
51
|
+
AsymmetricSigningAlgorithm,
|
|
38
52
|
AuthProvider,
|
|
39
53
|
Chunker,
|
|
40
54
|
CryptoService,
|
|
55
|
+
DecryptKeyMiddleware,
|
|
41
56
|
DecryptResult,
|
|
57
|
+
DecryptStreamMiddleware,
|
|
58
|
+
ECCurve,
|
|
59
|
+
EncryptKeyMiddleware,
|
|
42
60
|
EncryptResult,
|
|
61
|
+
EncryptStreamMiddleware,
|
|
62
|
+
HashAlgorithm,
|
|
63
|
+
HkdfParams,
|
|
43
64
|
HttpMethod,
|
|
65
|
+
KeyPair,
|
|
66
|
+
KeyOptions,
|
|
67
|
+
KeyAlgorithm,
|
|
44
68
|
PemKeyPair,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
69
|
+
PrivateKey,
|
|
70
|
+
PublicKey,
|
|
71
|
+
PublicKeyInfo,
|
|
72
|
+
SigningAlgorithm,
|
|
49
73
|
SplitStep,
|
|
74
|
+
SymmetricKey,
|
|
75
|
+
SymmetricSigningAlgorithm,
|
|
50
76
|
};
|
|
51
77
|
|
|
52
78
|
export {
|
|
@@ -74,7 +100,8 @@ export {
|
|
|
74
100
|
version,
|
|
75
101
|
};
|
|
76
102
|
|
|
77
|
-
export
|
|
103
|
+
export { DefaultCryptoService as WebCryptoService } from './src/crypto/index.js';
|
|
104
|
+
// export the other methods from crypto/index.js that aren't part of CryptoService but are needed for JWT handling
|
|
78
105
|
export {
|
|
79
106
|
type CreateOptions,
|
|
80
107
|
type CreateZTDFOptions,
|
package/tdf3/src/assertions.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { canonicalizeEx } from 'json-canonicalize';
|
|
2
|
-
import { SignJWT, jwtVerify, importJWK, importX509 } from 'jose';
|
|
3
2
|
import { base64, hex } from '../../src/encodings/index.js';
|
|
4
3
|
import { ConfigurationError, IntegrityError, InvalidFileError } from '../../src/errors.js';
|
|
5
4
|
import { tdfSpecVersion, version as sdkVersion } from '../../src/version.js';
|
|
5
|
+
import {
|
|
6
|
+
type CryptoService,
|
|
7
|
+
type PrivateKey,
|
|
8
|
+
type PublicKey,
|
|
9
|
+
type SymmetricKey,
|
|
10
|
+
} from './crypto/declarations.js';
|
|
11
|
+
import { decodeProtectedHeader, signJwt, verifyJwt, type JwtHeader } from './crypto/jwt.js';
|
|
6
12
|
|
|
7
13
|
export type AssertionKeyAlg = 'ES256' | 'RS256' | 'HS256';
|
|
8
14
|
export type AssertionType = 'handling' | 'other';
|
|
@@ -41,39 +47,69 @@ export type AssertionPayload = {
|
|
|
41
47
|
/**
|
|
42
48
|
* Computes the SHA-256 hash of the assertion object, excluding the 'binding' and 'hash' properties.
|
|
43
49
|
*
|
|
50
|
+
* @param a - The assertion to hash
|
|
51
|
+
* @param cryptoService - The crypto service to use for hashing
|
|
44
52
|
* @returns the hexadecimal string representation of the hash
|
|
45
53
|
*/
|
|
46
|
-
export async function hash(a: Assertion): Promise<string> {
|
|
54
|
+
export async function hash(a: Assertion, cryptoService: CryptoService): Promise<string> {
|
|
47
55
|
const result = canonicalizeEx(a, {
|
|
48
56
|
exclude: ['binding', 'hash', 'sign', 'verify', 'signingKey'],
|
|
49
57
|
});
|
|
50
58
|
|
|
51
|
-
const
|
|
52
|
-
return hex.encodeArrayBuffer(
|
|
59
|
+
const hashBytes = await cryptoService.digest('SHA-256', new TextEncoder().encode(result));
|
|
60
|
+
return hex.encodeArrayBuffer(hashBytes.buffer);
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
/**
|
|
56
64
|
* Signs the given hash and signature using the provided key and sets the binding method and signature.
|
|
57
65
|
*
|
|
58
|
-
* @param
|
|
66
|
+
* @param thiz - The assertion to sign.
|
|
67
|
+
* @param assertionHash - The hash to be signed.
|
|
59
68
|
* @param sig - The signature to be signed.
|
|
60
|
-
* @param
|
|
61
|
-
* @
|
|
69
|
+
* @param key - The key used for signing.
|
|
70
|
+
* @param cryptoService - The crypto service to use for signing.
|
|
71
|
+
* @returns A promise that resolves to the signed assertion.
|
|
62
72
|
*/
|
|
63
73
|
async function sign(
|
|
64
74
|
thiz: Assertion,
|
|
65
75
|
assertionHash: string,
|
|
66
76
|
sig: string,
|
|
67
|
-
key: AssertionKey
|
|
77
|
+
key: AssertionKey,
|
|
78
|
+
cryptoService: CryptoService
|
|
68
79
|
): Promise<Assertion> {
|
|
69
80
|
const payload: AssertionPayload = {
|
|
70
81
|
assertionHash,
|
|
71
82
|
assertionSig: sig,
|
|
72
83
|
};
|
|
73
84
|
|
|
85
|
+
const header: JwtHeader = { alg: key.alg };
|
|
86
|
+
|
|
87
|
+
if (typeof key.key === 'object' && '_brand' in key.key && key.key._brand === 'PublicKey') {
|
|
88
|
+
throw new ConfigurationError(
|
|
89
|
+
'Cannot sign assertion with PublicKey. Use PrivateKey or SymmetricKey for signing.'
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let signingMaterial: PrivateKey | SymmetricKey;
|
|
94
|
+
if (typeof key.key === 'string') {
|
|
95
|
+
if (!cryptoService.importPrivateKey) {
|
|
96
|
+
throw new ConfigurationError(
|
|
97
|
+
'CryptoService does not support importing private keys. Cannot sign assertion with a PEM string. Use PrivateKey or SymmetricKey for signing.'
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
signingMaterial = await cryptoService.importPrivateKey(key.key, {
|
|
101
|
+
usage: 'sign',
|
|
102
|
+
extractable: false,
|
|
103
|
+
});
|
|
104
|
+
} else if (key.key instanceof Uint8Array) {
|
|
105
|
+
signingMaterial = await cryptoService.importSymmetricKey(key.key);
|
|
106
|
+
} else {
|
|
107
|
+
signingMaterial = key.key as PrivateKey | SymmetricKey;
|
|
108
|
+
}
|
|
109
|
+
|
|
74
110
|
let token: string;
|
|
75
111
|
try {
|
|
76
|
-
token = await
|
|
112
|
+
token = await signJwt(cryptoService, payload, signingMaterial, header);
|
|
77
113
|
} catch (error) {
|
|
78
114
|
throw new ConfigurationError(`Signing assertion failed: ${error.message}`, error);
|
|
79
115
|
}
|
|
@@ -107,36 +143,54 @@ export function isAssertionConfig(obj: unknown): obj is AssertionConfig {
|
|
|
107
143
|
/**
|
|
108
144
|
* Verifies the signature of the assertion using the provided key.
|
|
109
145
|
*
|
|
110
|
-
* @param
|
|
111
|
-
* @
|
|
112
|
-
* @
|
|
146
|
+
* @param thiz - The assertion to verify.
|
|
147
|
+
* @param aggregateHash - The aggregate hash for integrity checking.
|
|
148
|
+
* @param key - The key used for verification.
|
|
149
|
+
* @param isLegacyTDF - Whether this is a legacy TDF format.
|
|
150
|
+
* @param cryptoService - The crypto service to use for verification.
|
|
151
|
+
* @throws {InvalidFileError} If the verification fails.
|
|
152
|
+
* @throws {IntegrityError} If the integrity check fails.
|
|
113
153
|
*/
|
|
114
154
|
export async function verify(
|
|
115
155
|
thiz: Assertion,
|
|
116
156
|
aggregateHash: Uint8Array,
|
|
117
157
|
key: AssertionKey,
|
|
118
|
-
isLegacyTDF: boolean
|
|
158
|
+
isLegacyTDF: boolean,
|
|
159
|
+
cryptoService: CryptoService
|
|
119
160
|
): Promise<void> {
|
|
120
161
|
let payload: AssertionPayload;
|
|
121
162
|
try {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
163
|
+
// Parse JWT header to check for embedded keys (jwk or x5c)
|
|
164
|
+
const header = decodeProtectedHeader(thiz.binding.signature);
|
|
165
|
+
|
|
166
|
+
// Runtime check: ensure we have a verification key, not a signing key
|
|
167
|
+
if (typeof key.key === 'object' && '_brand' in key.key && key.key._brand === 'PrivateKey') {
|
|
168
|
+
throw new ConfigurationError(
|
|
169
|
+
'Cannot verify assertion with PrivateKey. Use PublicKey or SymmetricKey for verification.'
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
let verificationKey: string | Uint8Array | PublicKey | SymmetricKey = key.key;
|
|
173
|
+
|
|
174
|
+
if (header.jwk) {
|
|
175
|
+
// Convert embedded JWK to PEM
|
|
176
|
+
verificationKey = await cryptoService.jwkToPublicKeyPem(header.jwk as JsonWebKey);
|
|
177
|
+
} else if (header.x5c && Array.isArray(header.x5c) && header.x5c.length > 0) {
|
|
178
|
+
// Extract public key from X.509 certificate
|
|
179
|
+
const cert = `-----BEGIN CERTIFICATE-----\n${header.x5c[0]}\n-----END CERTIFICATE-----`;
|
|
180
|
+
verificationKey = await cryptoService.extractPublicKeyPem(cert);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const result = await verifyJwt(cryptoService, thiz.binding.signature, verificationKey, {
|
|
184
|
+
algorithms: [key.alg],
|
|
131
185
|
});
|
|
132
|
-
payload =
|
|
186
|
+
payload = result.payload as AssertionPayload;
|
|
133
187
|
} catch (error) {
|
|
134
188
|
throw new InvalidFileError(`Verifying assertion failed: ${error.message}`, error);
|
|
135
189
|
}
|
|
136
190
|
const { assertionHash, assertionSig } = payload;
|
|
137
191
|
|
|
138
192
|
// Get the hash of the assertion
|
|
139
|
-
const hashOfAssertion = await hash(thiz);
|
|
193
|
+
const hashOfAssertion = await hash(thiz, cryptoService);
|
|
140
194
|
|
|
141
195
|
// check if assertionHash is same as hashOfAssertion
|
|
142
196
|
if (hashOfAssertion !== assertionHash) {
|
|
@@ -164,13 +218,17 @@ export async function verify(
|
|
|
164
218
|
|
|
165
219
|
/**
|
|
166
220
|
* Creates an Assertion object with the specified properties.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
*
|
|
221
|
+
*
|
|
222
|
+
* @param aggregateHash - The aggregate hash for the assertion.
|
|
223
|
+
* @param assertionConfig - The configuration for the assertion.
|
|
224
|
+
* @param cryptoService - The crypto service to use for signing.
|
|
225
|
+
* @param targetVersion - The target TDF spec version.
|
|
226
|
+
* @returns The created assertion.
|
|
170
227
|
*/
|
|
171
228
|
export async function CreateAssertion(
|
|
172
229
|
aggregateHash: Uint8Array | string,
|
|
173
230
|
assertionConfig: AssertionConfig,
|
|
231
|
+
cryptoService: CryptoService,
|
|
174
232
|
targetVersion?: string
|
|
175
233
|
): Promise<Assertion> {
|
|
176
234
|
if (!assertionConfig.signingKey) {
|
|
@@ -187,7 +245,7 @@ export async function CreateAssertion(
|
|
|
187
245
|
binding: { method: '', signature: '' },
|
|
188
246
|
};
|
|
189
247
|
|
|
190
|
-
const assertionHash = await hash(a);
|
|
248
|
+
const assertionHash = await hash(a, cryptoService);
|
|
191
249
|
let encodedHash: string;
|
|
192
250
|
switch (targetVersion || '4.3.0') {
|
|
193
251
|
case '4.2.2':
|
|
@@ -212,12 +270,23 @@ export async function CreateAssertion(
|
|
|
212
270
|
throw new ConfigurationError(`Unsupported TDF spec version: [${targetVersion}]`);
|
|
213
271
|
}
|
|
214
272
|
|
|
215
|
-
return await sign(a, assertionHash, encodedHash, assertionConfig.signingKey);
|
|
273
|
+
return await sign(a, assertionHash, encodedHash, assertionConfig.signingKey, cryptoService);
|
|
216
274
|
}
|
|
217
275
|
|
|
276
|
+
// TODO: Split AssertionKey into two separate types:
|
|
277
|
+
// - AssertionSigningKey: key restricted to PrivateKey | SymmetricKey (no strings, no raw bytes)
|
|
278
|
+
// - AssertionVerificationKey: key restricted to string | PublicKey | SymmetricKey
|
|
279
|
+
// This would make the signing/verification distinction type-safe rather than relying on runtime checks.
|
|
280
|
+
// AssertionConfig.signingKey would use AssertionSigningKey; verify() and AssertionVerificationKeys would use AssertionVerificationKey.
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Key used for signing or verifying assertions.
|
|
284
|
+
* For asymmetric algorithms (RS256, ES256): PEM string, PrivateKey (for signing), or PublicKey (for verification).
|
|
285
|
+
* For symmetric algorithms (HS256): Uint8Array or SymmetricKey (opaque).
|
|
286
|
+
*/
|
|
218
287
|
export type AssertionKey = {
|
|
219
288
|
alg: AssertionKeyAlg;
|
|
220
|
-
key:
|
|
289
|
+
key: string | Uint8Array | PrivateKey | PublicKey | SymmetricKey;
|
|
221
290
|
};
|
|
222
291
|
|
|
223
292
|
// AssertionConfig is a shadow of Assertion with the addition of the signing key.
|