@opentdf/sdk 0.9.0-rc.82 → 0.10.0-beta.95

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.
Files changed (207) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/src/access/access-fetch.js +1 -2
  3. package/dist/cjs/src/access/access-rpc.js +1 -3
  4. package/dist/cjs/src/access.js +1 -14
  5. package/dist/cjs/src/auth/auth.js +13 -10
  6. package/dist/cjs/src/auth/dpop.js +121 -0
  7. package/dist/cjs/src/auth/oidc-clientcredentials-provider.js +37 -3
  8. package/dist/cjs/src/auth/oidc-externaljwt-provider.js +37 -3
  9. package/dist/cjs/src/auth/oidc-refreshtoken-provider.js +37 -3
  10. package/dist/cjs/src/auth/oidc.js +10 -8
  11. package/dist/cjs/src/auth/providers.js +35 -12
  12. package/dist/cjs/src/crypto/enums.js +1 -1
  13. package/dist/cjs/src/crypto/index.js +16 -2
  14. package/dist/cjs/src/crypto/pemPublicToCrypto.js +24 -20
  15. package/dist/cjs/src/errors.js +14 -2
  16. package/dist/cjs/src/index.js +8 -2
  17. package/dist/cjs/src/opentdf.js +50 -13
  18. package/dist/cjs/src/policy/discovery.js +188 -0
  19. package/dist/cjs/src/version.js +2 -2
  20. package/dist/cjs/tdf3/index.js +4 -2
  21. package/dist/cjs/tdf3/src/assertions.js +71 -31
  22. package/dist/cjs/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
  23. package/dist/cjs/tdf3/src/ciphers/symmetric-cipher-base.js +4 -2
  24. package/dist/cjs/tdf3/src/client/index.js +23 -33
  25. package/dist/cjs/tdf3/src/crypto/crypto-utils.js +12 -5
  26. package/dist/cjs/tdf3/src/crypto/declarations.js +1 -1
  27. package/dist/cjs/tdf3/src/crypto/index.js +849 -88
  28. package/dist/cjs/tdf3/src/crypto/jose/jwt-claims-set.js +11 -0
  29. package/dist/cjs/tdf3/src/crypto/jose/validate-crit.js +8 -0
  30. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/buffer_utils.js +41 -0
  31. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/epoch.js +6 -0
  32. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/is_object.js +21 -0
  33. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.js +112 -0
  34. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/secs.js +60 -0
  35. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/validate_crit.js +38 -0
  36. package/dist/cjs/tdf3/src/crypto/jose/vendor/util/errors.js +135 -0
  37. package/dist/cjs/tdf3/src/crypto/jwt.js +183 -0
  38. package/dist/cjs/tdf3/src/crypto/salt.js +14 -8
  39. package/dist/cjs/tdf3/src/models/encryption-information.js +17 -20
  40. package/dist/cjs/tdf3/src/models/key-access.js +43 -63
  41. package/dist/cjs/tdf3/src/tdf.js +75 -75
  42. package/dist/cjs/tdf3/src/utils/index.js +5 -39
  43. package/dist/types/src/access/access-fetch.d.ts.map +1 -1
  44. package/dist/types/src/access/access-rpc.d.ts.map +1 -1
  45. package/dist/types/src/access.d.ts +0 -5
  46. package/dist/types/src/access.d.ts.map +1 -1
  47. package/dist/types/src/auth/auth.d.ts +9 -6
  48. package/dist/types/src/auth/auth.d.ts.map +1 -1
  49. package/dist/types/src/auth/dpop.d.ts +60 -0
  50. package/dist/types/src/auth/dpop.d.ts.map +1 -0
  51. package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts +3 -2
  52. package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts.map +1 -1
  53. package/dist/types/src/auth/oidc-externaljwt-provider.d.ts +3 -2
  54. package/dist/types/src/auth/oidc-externaljwt-provider.d.ts.map +1 -1
  55. package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts +3 -2
  56. package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts.map +1 -1
  57. package/dist/types/src/auth/oidc.d.ts +6 -4
  58. package/dist/types/src/auth/oidc.d.ts.map +1 -1
  59. package/dist/types/src/auth/providers.d.ts +5 -4
  60. package/dist/types/src/auth/providers.d.ts.map +1 -1
  61. package/dist/types/src/crypto/enums.d.ts +1 -1
  62. package/dist/types/src/crypto/index.d.ts +2 -1
  63. package/dist/types/src/crypto/index.d.ts.map +1 -1
  64. package/dist/types/src/crypto/pemPublicToCrypto.d.ts +18 -0
  65. package/dist/types/src/crypto/pemPublicToCrypto.d.ts.map +1 -1
  66. package/dist/types/src/errors.d.ts +8 -0
  67. package/dist/types/src/errors.d.ts.map +1 -1
  68. package/dist/types/src/index.d.ts +2 -1
  69. package/dist/types/src/index.d.ts.map +1 -1
  70. package/dist/types/src/opentdf.d.ts +26 -7
  71. package/dist/types/src/opentdf.d.ts.map +1 -1
  72. package/dist/types/src/policy/discovery.d.ts +74 -0
  73. package/dist/types/src/policy/discovery.d.ts.map +1 -0
  74. package/dist/types/src/version.d.ts +1 -1
  75. package/dist/types/src/version.d.ts.map +1 -1
  76. package/dist/types/tdf3/index.d.ts +3 -3
  77. package/dist/types/tdf3/index.d.ts.map +1 -1
  78. package/dist/types/tdf3/src/assertions.d.ts +23 -8
  79. package/dist/types/tdf3/src/assertions.d.ts.map +1 -1
  80. package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts +3 -3
  81. package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts.map +1 -1
  82. package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts +4 -4
  83. package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts.map +1 -1
  84. package/dist/types/tdf3/src/client/builders.d.ts +2 -2
  85. package/dist/types/tdf3/src/client/builders.d.ts.map +1 -1
  86. package/dist/types/tdf3/src/client/index.d.ts +6 -5
  87. package/dist/types/tdf3/src/client/index.d.ts.map +1 -1
  88. package/dist/types/tdf3/src/crypto/crypto-utils.d.ts +14 -4
  89. package/dist/types/tdf3/src/crypto/crypto-utils.d.ts.map +1 -1
  90. package/dist/types/tdf3/src/crypto/declarations.d.ts +283 -18
  91. package/dist/types/tdf3/src/crypto/declarations.d.ts.map +1 -1
  92. package/dist/types/tdf3/src/crypto/index.d.ts +105 -28
  93. package/dist/types/tdf3/src/crypto/index.d.ts.map +1 -1
  94. package/dist/types/tdf3/src/crypto/jose/jwt-claims-set.d.ts +3 -0
  95. package/dist/types/tdf3/src/crypto/jose/jwt-claims-set.d.ts.map +1 -0
  96. package/dist/types/tdf3/src/crypto/jose/validate-crit.d.ts +5 -0
  97. package/dist/types/tdf3/src/crypto/jose/validate-crit.d.ts.map +1 -0
  98. package/dist/types/tdf3/src/crypto/jose/vendor/lib/buffer_utils.d.ts +6 -0
  99. package/dist/types/tdf3/src/crypto/jose/vendor/lib/buffer_utils.d.ts.map +1 -0
  100. package/dist/types/tdf3/src/crypto/jose/vendor/lib/epoch.d.ts +3 -0
  101. package/dist/types/tdf3/src/crypto/jose/vendor/lib/epoch.d.ts.map +1 -0
  102. package/dist/types/tdf3/src/crypto/jose/vendor/lib/is_object.d.ts +3 -0
  103. package/dist/types/tdf3/src/crypto/jose/vendor/lib/is_object.d.ts.map +1 -0
  104. package/dist/types/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.d.ts +3 -0
  105. package/dist/types/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.d.ts.map +1 -0
  106. package/dist/types/tdf3/src/crypto/jose/vendor/lib/secs.d.ts +3 -0
  107. package/dist/types/tdf3/src/crypto/jose/vendor/lib/secs.d.ts.map +1 -0
  108. package/dist/types/tdf3/src/crypto/jose/vendor/lib/validate_crit.d.ts +3 -0
  109. package/dist/types/tdf3/src/crypto/jose/vendor/lib/validate_crit.d.ts.map +1 -0
  110. package/dist/types/tdf3/src/crypto/jose/vendor/util/errors.d.ts +76 -0
  111. package/dist/types/tdf3/src/crypto/jose/vendor/util/errors.d.ts.map +1 -0
  112. package/dist/types/tdf3/src/crypto/jwt.d.ts +76 -0
  113. package/dist/types/tdf3/src/crypto/jwt.d.ts.map +1 -0
  114. package/dist/types/tdf3/src/crypto/salt.d.ts +6 -1
  115. package/dist/types/tdf3/src/crypto/salt.d.ts.map +1 -1
  116. package/dist/types/tdf3/src/models/encryption-information.d.ts +4 -4
  117. package/dist/types/tdf3/src/models/encryption-information.d.ts.map +1 -1
  118. package/dist/types/tdf3/src/models/key-access.d.ts +8 -5
  119. package/dist/types/tdf3/src/models/key-access.d.ts.map +1 -1
  120. package/dist/types/tdf3/src/tdf.d.ts +8 -8
  121. package/dist/types/tdf3/src/tdf.d.ts.map +1 -1
  122. package/dist/types/tdf3/src/utils/index.d.ts +4 -3
  123. package/dist/types/tdf3/src/utils/index.d.ts.map +1 -1
  124. package/dist/web/src/access/access-fetch.js +3 -4
  125. package/dist/web/src/access/access-rpc.js +3 -5
  126. package/dist/web/src/access.js +1 -13
  127. package/dist/web/src/auth/auth.js +13 -10
  128. package/dist/web/src/auth/dpop.js +118 -0
  129. package/dist/web/src/auth/oidc-clientcredentials-provider.js +4 -3
  130. package/dist/web/src/auth/oidc-externaljwt-provider.js +4 -3
  131. package/dist/web/src/auth/oidc-refreshtoken-provider.js +4 -3
  132. package/dist/web/src/auth/oidc.js +11 -9
  133. package/dist/web/src/auth/providers.js +13 -12
  134. package/dist/web/src/crypto/enums.js +1 -1
  135. package/dist/web/src/crypto/index.js +4 -2
  136. package/dist/web/src/crypto/pemPublicToCrypto.js +18 -18
  137. package/dist/web/src/errors.js +12 -1
  138. package/dist/web/src/index.js +3 -2
  139. package/dist/web/src/opentdf.js +17 -13
  140. package/dist/web/src/policy/discovery.js +182 -0
  141. package/dist/web/src/version.js +2 -2
  142. package/dist/web/tdf3/index.js +3 -2
  143. package/dist/web/tdf3/src/assertions.js +71 -31
  144. package/dist/web/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
  145. package/dist/web/tdf3/src/ciphers/symmetric-cipher-base.js +4 -2
  146. package/dist/web/tdf3/src/client/index.js +25 -35
  147. package/dist/web/tdf3/src/crypto/crypto-utils.js +12 -5
  148. package/dist/web/tdf3/src/crypto/declarations.js +1 -1
  149. package/dist/web/tdf3/src/crypto/index.js +830 -84
  150. package/dist/web/tdf3/src/crypto/jose/jwt-claims-set.js +5 -0
  151. package/dist/web/tdf3/src/crypto/jose/validate-crit.js +3 -0
  152. package/dist/web/tdf3/src/crypto/jose/vendor/lib/buffer_utils.js +35 -0
  153. package/dist/web/tdf3/src/crypto/jose/vendor/lib/epoch.js +4 -0
  154. package/dist/web/tdf3/src/crypto/jose/vendor/lib/is_object.js +19 -0
  155. package/dist/web/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.js +107 -0
  156. package/dist/web/tdf3/src/crypto/jose/vendor/lib/secs.js +58 -0
  157. package/dist/web/tdf3/src/crypto/jose/vendor/lib/validate_crit.js +36 -0
  158. package/dist/web/tdf3/src/crypto/jose/vendor/util/errors.js +117 -0
  159. package/dist/web/tdf3/src/crypto/jwt.js +174 -0
  160. package/dist/web/tdf3/src/crypto/salt.js +13 -7
  161. package/dist/web/tdf3/src/models/encryption-information.js +11 -14
  162. package/dist/web/tdf3/src/models/key-access.js +44 -31
  163. package/dist/web/tdf3/src/tdf.js +71 -71
  164. package/dist/web/tdf3/src/utils/index.js +5 -6
  165. package/package.json +11 -4
  166. package/src/access/access-fetch.ts +2 -8
  167. package/src/access/access-rpc.ts +0 -7
  168. package/src/access.ts +0 -17
  169. package/src/auth/auth.ts +21 -12
  170. package/src/auth/dpop.ts +222 -0
  171. package/src/auth/oidc-clientcredentials-provider.ts +23 -15
  172. package/src/auth/oidc-externaljwt-provider.ts +23 -15
  173. package/src/auth/oidc-refreshtoken-provider.ts +23 -15
  174. package/src/auth/oidc.ts +21 -10
  175. package/src/auth/providers.ts +46 -29
  176. package/src/crypto/enums.ts +1 -1
  177. package/src/crypto/index.ts +21 -1
  178. package/src/crypto/pemPublicToCrypto.ts +18 -20
  179. package/src/errors.ts +9 -0
  180. package/src/index.ts +7 -0
  181. package/src/opentdf.ts +36 -17
  182. package/src/policy/discovery.ts +222 -0
  183. package/src/version.ts +1 -1
  184. package/tdf3/index.ts +32 -5
  185. package/tdf3/src/assertions.ts +99 -30
  186. package/tdf3/src/ciphers/aes-gcm-cipher.ts +7 -2
  187. package/tdf3/src/ciphers/symmetric-cipher-base.ts +7 -4
  188. package/tdf3/src/client/builders.ts +2 -2
  189. package/tdf3/src/client/index.ts +60 -59
  190. package/tdf3/src/crypto/crypto-utils.ts +15 -8
  191. package/tdf3/src/crypto/declarations.ts +338 -22
  192. package/tdf3/src/crypto/index.ts +1021 -118
  193. package/tdf3/src/crypto/jose/jwt-claims-set.ts +10 -0
  194. package/tdf3/src/crypto/jose/validate-crit.ts +9 -0
  195. package/tdf3/src/crypto/jose/vendor/lib/buffer_utils.ts +34 -0
  196. package/tdf3/src/crypto/jose/vendor/lib/epoch.ts +3 -0
  197. package/tdf3/src/crypto/jose/vendor/lib/is_object.ts +18 -0
  198. package/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.ts +106 -0
  199. package/tdf3/src/crypto/jose/vendor/lib/secs.ts +57 -0
  200. package/tdf3/src/crypto/jose/vendor/lib/validate_crit.ts +35 -0
  201. package/tdf3/src/crypto/jose/vendor/util/errors.ts +101 -0
  202. package/tdf3/src/crypto/jwt.ts +256 -0
  203. package/tdf3/src/crypto/salt.ts +16 -8
  204. package/tdf3/src/models/encryption-information.ts +14 -21
  205. package/tdf3/src/models/key-access.ts +57 -41
  206. package/tdf3/src/tdf.ts +110 -93
  207. 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 { cryptoPublicToPem, rstrip } from '../utils.js';
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?: CryptoKeyPair;
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?: CryptoKeyPair;
98
+ signingKey?: KeyPair;
98
99
 
99
100
  extraHeaders: Record<string, string> = {};
100
101
 
101
102
  currentAccessToken?: string;
102
103
 
103
- constructor(cfg: OIDCCredentials, request?: typeof fetch) {
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(this.signingKey, this.userInfoEndpoint, 'POST');
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
- const clientPubKey = await cryptoPublicToPem(this.signingKey.publicKey);
169
- headers['X-VirtruPubKey'] = base64.encode(clientPubKey);
170
- headers.DPoP = await dpopFn(this.signingKey, url, 'POST');
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: CryptoKeyPair): Promise<void> {
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,
@@ -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
- clientId: clientConfig.clientId,
37
- clientSecret: clientConfig.clientSecret,
38
- oidcOrigin: clientConfig.oidcOrigin,
39
- oidcTokenEndpoint: clientConfig.oidcTokenEndpoint,
40
- oidcUserInfoEndpoint: clientConfig.oidcUserInfoEndpoint,
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
- clientId: clientConfig.clientId,
65
- externalJwt: clientConfig.externalJwt,
66
- oidcOrigin: clientConfig.oidcOrigin,
67
- oidcTokenEndpoint: clientConfig.oidcTokenEndpoint,
68
- oidcUserInfoEndpoint: clientConfig.oidcUserInfoEndpoint,
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
- clientId: clientConfig.clientId,
91
- refreshToken: clientConfig.refreshToken,
92
- oidcOrigin: clientConfig.oidcOrigin,
93
- oidcTokenEndpoint: clientConfig.oidcTokenEndpoint,
94
- oidcUserInfoEndpoint: clientConfig.oidcUserInfoEndpoint,
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 (clientConfig: OIDCCredentials): Promise<AuthProvider> => {
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';
@@ -10,7 +10,7 @@ export enum AlgorithmName {
10
10
  export enum NamedCurve {
11
11
  P256 = 'P-256',
12
12
  P384 = 'P-384',
13
- P512 = 'P-512',
13
+ P521 = 'P-521',
14
14
  }
15
15
 
16
16
  export enum CipherType {
@@ -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 { pemPublicToCrypto, pemCertToCrypto } from './pemPublicToCrypto.js';
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';
@@ -31,27 +31,24 @@ import * as base64 from '../encodings/base64.js';
31
31
  import { importX509 } from 'jose';
32
32
  import { encodeArrayBuffer as hexEncodeArrayBuffer } from '../encodings/hex.js';
33
33
  import { ConfigurationError, TdfError } from '../errors.js';
34
+ import { NamedCurve } from './enums.js';
34
35
 
35
- const RSA_OID = '06092a864886f70d010101';
36
- const EC_OID = '06072a8648ce3d0201';
37
- const P256_OID = '06082a8648ce3d030107';
38
- const P384_OID = '06052b81040022';
39
- const P521_OID = '06052b81040023';
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';
40
42
  const SHA_512 = 'SHA-512';
41
43
  const SPKI = 'spki';
42
44
  const CERT_BEGIN = '-----BEGIN CERTIFICATE-----';
43
45
  const CERT_END = '-----END CERTIFICATE-----';
44
46
 
45
- const P_256 = 'P-256';
46
- const P_384 = 'P-384';
47
- const P_512 = 'P-512';
48
- type CurveName = typeof P_256 | typeof P_384 | typeof P_512;
49
-
50
47
  const ECDH = 'ECDH';
51
48
  const ECDSA = 'ECDSA';
52
49
  const RSA_OAEP = 'RSA-OAEP';
53
50
  const RSA_PSS = 'RSA-PSS';
54
- 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;
55
52
 
56
53
  interface PemPublicToCryptoOptions {
57
54
  name?: string;
@@ -75,7 +72,7 @@ function guessKeyUsages(algorithmName: AlgorithmName, usages?: KeyUsage[]): KeyU
75
72
  }
76
73
  }
77
74
 
78
- function guessAlgorithmName(hex: string, algorithmName?: string): AlgorithmName {
75
+ export function guessAlgorithmName(hex: string, algorithmName?: string): AlgorithmName {
79
76
  if (hex.includes(EC_OID)) {
80
77
  if (!algorithmName || algorithmName === ECDH) {
81
78
  return ECDH;
@@ -92,13 +89,13 @@ function guessAlgorithmName(hex: string, algorithmName?: string): AlgorithmName
92
89
  throw new TypeError(`Invalid public key, ${algorithmName}`);
93
90
  }
94
91
 
95
- function guessCurveName(hex: string): CurveName {
92
+ export function guessCurveName(hex: string): NamedCurve {
96
93
  if (hex.includes(P256_OID)) {
97
- return P_256;
94
+ return NamedCurve.P256;
98
95
  } else if (hex.includes(P384_OID)) {
99
- return P_384;
96
+ return NamedCurve.P384;
100
97
  } else if (hex.includes(P521_OID)) {
101
- return P_512;
98
+ return NamedCurve.P521;
102
99
  }
103
100
  throw new TdfError('Unsupported curve name or invalid key');
104
101
  }
@@ -159,19 +156,20 @@ export async function pemPublicToCrypto(
159
156
  }
160
157
 
161
158
  /**
159
+ * Detect JWS algorithm from hex-encoded key/certificate data.
162
160
  * Look up JWK algorithm at https://github.com/panva/jose/issues/210
163
161
  */
164
- function toJwsAlg(hex: string) {
162
+ export function toJwsAlg(hex: string) {
165
163
  const a = guessAlgorithmName(hex);
166
164
  if (a === ECDH) {
167
165
  return 'ECDH-ES';
168
166
  } else if (a === ECDSA) {
169
167
  switch (guessCurveName(hex)) {
170
- case 'P-256':
168
+ case NamedCurve.P256:
171
169
  return 'ES256';
172
- case 'P-384':
170
+ case NamedCurve.P384:
173
171
  return 'ES384';
174
- case 'P-512':
172
+ case NamedCurve.P521:
175
173
  return 'ES512';
176
174
  }
177
175
  } else if (a === RSA_OAEP) {
package/src/errors.ts CHANGED
@@ -119,3 +119,12 @@ export class PermissionDeniedError extends TdfError {
119
119
  export class UnsupportedFeatureError extends TdfError {
120
120
  override name = 'UnsupportedFeatureError';
121
121
  }
122
+
123
+ /**
124
+ * One or more attribute value FQNs were not found on the platform.
125
+ * Thrown by {@link validateAttributes} and {@link validateAttributeValue} when the platform
126
+ * does not recognize the requested FQNs.
127
+ */
128
+ export class AttributeNotFoundError extends TdfError {
129
+ override name = 'AttributeNotFoundError';
130
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  export { type AuthProvider, type HttpMethod, HttpRequest, withHeaders } from './auth/auth.js';
2
2
  export * as AuthProviders from './auth/providers.js';
3
3
  export { attributeFQNsAsValues } from './policy/api.js';
4
+ export {
5
+ listAttributes,
6
+ validateAttributes,
7
+ attributeExists,
8
+ attributeValueExists,
9
+ } from './policy/discovery.js';
4
10
  export { version, clientType, tdfSpecVersion } from './version.js';
5
11
  export { PlatformClient, type PlatformClientOptions, type PlatformServices } from './platform.js';
6
12
  export * from './opentdf.js';
@@ -12,6 +18,7 @@ export {
12
18
  DecryptError,
13
19
  NetworkError,
14
20
  AttributeValidationError,
21
+ AttributeNotFoundError,
15
22
  ConfigurationError,
16
23
  } from './errors.js';
17
24
  export * from './seekable.js';
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,
@@ -96,7 +99,10 @@ export type SplitStep = {
96
99
  sid?: string;
97
100
  };
98
101
 
99
- /** Options specific to the ZTDF container format. */
102
+ /**
103
+ * Options specific to the ZTDF container format.
104
+ * @deprecated Use {@link CreateTDFOptions} instead.
105
+ */
100
106
  export type CreateZTDFOptions = CreateOptions & {
101
107
  /** Configuration for bound metadata. */
102
108
  assertionConfigs?: AssertionConfig[];
@@ -123,6 +129,9 @@ export type CreateZTDFOptions = CreateOptions & {
123
129
  tdfSpecVersion?: '4.2.2' | '4.3.0';
124
130
  };
125
131
 
132
+ /** Options for creating a TDF. */
133
+ export type CreateTDFOptions = CreateZTDFOptions;
134
+
126
135
  /** Settings for decrypting any variety of TDF file. */
127
136
  export type ReadOptions = {
128
137
  /** The ciphertext source. */
@@ -172,7 +181,14 @@ export type OpenTDFOptions = {
172
181
  * These often must be registered via a DPoP flow with the IdP
173
182
  * which is out of the scope of this library.
174
183
  */
175
- dpopKeys?: Promise<CryptoKeyPair>;
184
+ dpopKeys?: Promise<KeyPair>;
185
+
186
+ /**
187
+ * Optional custom CryptoService implementation.
188
+ * If not provided, defaults to the browser's native Web Crypto API.
189
+ * This allows injecting HSM-backed or other secure crypto implementations.
190
+ */
191
+ cryptoService?: CryptoService;
176
192
  };
177
193
 
178
194
  /** A decorated readable stream. */
@@ -235,7 +251,7 @@ export type TDFReader = {
235
251
  * platformUrl: 'https://platform.example.com',
236
252
  * });
237
253
  *
238
- * const cipherText = await client.createZTDF({
254
+ * const cipherText = await client.createTDF({
239
255
  * source: { type: 'stream', location: source },
240
256
  * autoconfigure: false,
241
257
  * });
@@ -257,7 +273,9 @@ export class OpenTDF {
257
273
  /** Default options for reading TDF objects. */
258
274
  defaultReadOptions: Omit<ReadOptions, 'source'>;
259
275
  /** The DPoP keys for this instance, if any. */
260
- readonly dpopKeys: Promise<CryptoKeyPair>;
276
+ readonly dpopKeys: Promise<KeyPair>;
277
+ /** The CryptoService implementation for this instance. */
278
+ readonly cryptoService: CryptoService;
261
279
  /** The TDF3 client for encrypting and decrypting ZTDF files. */
262
280
  readonly tdf3Client: TDF3Client;
263
281
 
@@ -269,6 +287,7 @@ export class OpenTDF {
269
287
  disableDPoP,
270
288
  policyEndpoint,
271
289
  platformUrl,
290
+ cryptoService,
272
291
  }: OpenTDFOptions) {
273
292
  this.authProvider = authProvider;
274
293
  this.defaultCreateOptions = defaultCreateOptions || {};
@@ -282,28 +301,28 @@ export class OpenTDF {
282
301
  );
283
302
  }
284
303
  this.policyEndpoint = policyEndpoint || '';
304
+ this.cryptoService = cryptoService ?? DefaultCryptoService;
285
305
  this.tdf3Client = new TDF3Client({
286
306
  authProvider,
287
307
  dpopKeys,
288
308
  kasEndpoint: this.platformUrl || 'https://disallow.all.invalid',
289
309
  platformUrl,
290
310
  policyEndpoint,
311
+ cryptoService: this.cryptoService,
291
312
  });
292
- this.dpopKeys =
293
- dpopKeys ??
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
- );
313
+ // Use CryptoService for key generation (returns opaque KeyPair)
314
+ this.dpopKeys = dpopKeys ?? this.cryptoService.generateSigningKeyPair();
315
+ }
316
+
317
+ /** Creates a new TDF stream. */
318
+ async createTDF(opts: CreateTDFOptions): Promise<DecoratedStream> {
319
+ return this.createZTDF(opts);
304
320
  }
305
321
 
306
- /** Creates a new ZTDF stream. */
322
+ /**
323
+ * Creates a new TDF stream.
324
+ * @deprecated Use {@link createTDF} instead.
325
+ */
307
326
  async createZTDF(opts: CreateZTDFOptions): Promise<DecoratedStream> {
308
327
  opts = { ...this.defaultCreateOptions, ...opts };
309
328
  const oldStream = await this.tdf3Client.encrypt({