@opentdf/sdk 0.4.0-beta.19 → 0.4.0-beta.22
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/auth/oidc-clientcredentials-provider.js +4 -2
- package/dist/cjs/src/auth/oidc-externaljwt-provider.js +5 -3
- package/dist/cjs/src/auth/oidc-refreshtoken-provider.js +5 -3
- package/dist/cjs/src/auth/oidc.js +9 -8
- package/dist/cjs/src/auth/providers.js +7 -1
- package/dist/cjs/src/opentdf.js +2 -1
- package/dist/cjs/src/platform/entityresolution/entity_resolution_pb.js +1 -1
- package/dist/cjs/src/platform/policy/attributes/attributes_pb.js +2 -2
- package/dist/cjs/src/platform/policy/kasregistry/key_access_server_registry_pb.js +36 -5
- package/dist/cjs/src/platform/policy/namespaces/namespaces_pb.js +2 -3
- package/dist/cjs/src/platform/policy/objects_pb.js +85 -42
- package/dist/cjs/src/platform/policy/registeredresources/registered_resources_pb.js +20 -15
- package/dist/cjs/src/platform/policy/resourcemapping/resource_mapping_pb.js +2 -3
- package/dist/cjs/src/platform/policy/subjectmapping/subject_mapping_pb.js +2 -3
- package/dist/cjs/src/platform/policy/unsafe/unsafe_pb.js +2 -4
- package/dist/cjs/src/policy/granter.js +75 -48
- package/dist/cjs/tdf3/src/client/builders.js +1 -1
- package/dist/cjs/tdf3/src/client/index.js +199 -53
- package/dist/cjs/tdf3/src/client/validation.js +3 -3
- package/dist/cjs/tdf3/src/tdf.js +8 -2
- package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts +1 -1
- package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc-externaljwt-provider.d.ts +1 -1
- package/dist/types/src/auth/oidc-externaljwt-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts +1 -1
- package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc.d.ts +4 -0
- package/dist/types/src/auth/oidc.d.ts.map +1 -1
- package/dist/types/src/auth/providers.d.ts.map +1 -1
- package/dist/types/src/opentdf.d.ts.map +1 -1
- package/dist/types/src/platform/entityresolution/entity_resolution_pb.d.ts +4 -0
- package/dist/types/src/platform/entityresolution/entity_resolution_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/attributes/attributes_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/kasregistry/key_access_server_registry_pb.d.ts +181 -24
- package/dist/types/src/platform/policy/kasregistry/key_access_server_registry_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/namespaces/namespaces_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/objects_pb.d.ts +195 -27
- package/dist/types/src/platform/policy/objects_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/registeredresources/registered_resources_pb.d.ts +67 -0
- package/dist/types/src/platform/policy/registeredresources/registered_resources_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/resourcemapping/resource_mapping_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/subjectmapping/subject_mapping_pb.d.ts.map +1 -1
- package/dist/types/src/platform/policy/unsafe/unsafe_pb.d.ts +0 -1
- package/dist/types/src/platform/policy/unsafe/unsafe_pb.d.ts.map +1 -1
- package/dist/types/src/policy/granter.d.ts +11 -6
- package/dist/types/src/policy/granter.d.ts.map +1 -1
- package/dist/types/tdf3/src/client/builders.d.ts +1 -0
- package/dist/types/tdf3/src/client/builders.d.ts.map +1 -1
- package/dist/types/tdf3/src/client/index.d.ts +11 -3
- package/dist/types/tdf3/src/client/index.d.ts.map +1 -1
- package/dist/types/tdf3/src/client/validation.d.ts +3 -3
- package/dist/types/tdf3/src/client/validation.d.ts.map +1 -1
- package/dist/types/tdf3/src/tdf.d.ts +1 -1
- package/dist/types/tdf3/src/tdf.d.ts.map +1 -1
- package/dist/web/src/auth/oidc-clientcredentials-provider.js +4 -2
- package/dist/web/src/auth/oidc-externaljwt-provider.js +5 -3
- package/dist/web/src/auth/oidc-refreshtoken-provider.js +5 -3
- package/dist/web/src/auth/oidc.js +9 -8
- package/dist/web/src/auth/providers.js +7 -1
- package/dist/web/src/opentdf.js +2 -1
- package/dist/web/src/platform/entityresolution/entity_resolution_pb.js +1 -1
- package/dist/web/src/platform/policy/attributes/attributes_pb.js +2 -2
- package/dist/web/src/platform/policy/kasregistry/key_access_server_registry_pb.js +34 -4
- package/dist/web/src/platform/policy/namespaces/namespaces_pb.js +2 -3
- package/dist/web/src/platform/policy/objects_pb.js +84 -41
- package/dist/web/src/platform/policy/registeredresources/registered_resources_pb.js +19 -14
- package/dist/web/src/platform/policy/resourcemapping/resource_mapping_pb.js +2 -3
- package/dist/web/src/platform/policy/subjectmapping/subject_mapping_pb.js +2 -3
- package/dist/web/src/platform/policy/unsafe/unsafe_pb.js +2 -4
- package/dist/web/src/policy/granter.js +75 -48
- package/dist/web/tdf3/src/client/builders.js +1 -1
- package/dist/web/tdf3/src/client/index.js +201 -56
- package/dist/web/tdf3/src/client/validation.js +3 -3
- package/dist/web/tdf3/src/tdf.js +8 -2
- package/package.json +1 -1
- package/src/auth/oidc-clientcredentials-provider.ts +4 -0
- package/src/auth/oidc-externaljwt-provider.ts +5 -1
- package/src/auth/oidc-refreshtoken-provider.ts +5 -1
- package/src/auth/oidc.ts +12 -7
- package/src/auth/providers.ts +6 -0
- package/src/opentdf.ts +1 -1
- package/src/platform/entityresolution/entity_resolution_pb.ts +4 -0
- package/src/platform/policy/attributes/attributes_pb.ts +1 -1
- package/src/platform/policy/kasregistry/key_access_server_registry_pb.ts +206 -28
- package/src/platform/policy/namespaces/namespaces_pb.ts +1 -2
- package/src/platform/policy/objects_pb.ts +248 -53
- package/src/platform/policy/registeredresources/registered_resources_pb.ts +80 -13
- package/src/platform/policy/resourcemapping/resource_mapping_pb.ts +1 -2
- package/src/platform/policy/subjectmapping/subject_mapping_pb.ts +1 -2
- package/src/platform/policy/unsafe/unsafe_pb.ts +1 -3
- package/src/policy/granter.ts +82 -56
- package/tdf3/src/client/builders.ts +1 -0
- package/tdf3/src/client/index.ts +278 -73
- package/tdf3/src/client/validation.ts +2 -2
- package/tdf3/src/tdf.ts +8 -1
package/tdf3/src/client/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { v4 } from 'uuid';
|
|
2
2
|
import {
|
|
3
|
-
ZipReader,
|
|
4
|
-
streamToBuffer,
|
|
5
3
|
keyMiddleware as defaultKeyMiddleware,
|
|
4
|
+
streamToBuffer,
|
|
5
|
+
ZipReader,
|
|
6
6
|
} from '../utils/index.js';
|
|
7
7
|
import { base64 } from '../../../src/encodings/index.js';
|
|
8
8
|
import {
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
type EncryptConfiguration,
|
|
11
11
|
fetchKasPublicKey,
|
|
12
12
|
loadTDFStream,
|
|
13
|
-
validatePolicyObject,
|
|
14
13
|
readStream,
|
|
14
|
+
validatePolicyObject,
|
|
15
15
|
writeStream,
|
|
16
16
|
} from '../tdf.js';
|
|
17
17
|
import { unwrapHtml } from '../utils/unwrap.js';
|
|
@@ -27,22 +27,18 @@ import {
|
|
|
27
27
|
} from '../../../src/utils.js';
|
|
28
28
|
|
|
29
29
|
import {
|
|
30
|
-
type EncryptParams,
|
|
31
30
|
type DecryptParams,
|
|
32
|
-
|
|
31
|
+
DecryptParamsBuilder,
|
|
32
|
+
type DecryptSource,
|
|
33
33
|
type DecryptStreamMiddleware,
|
|
34
|
+
DEFAULT_SEGMENT_SIZE,
|
|
34
35
|
type EncryptKeyMiddleware,
|
|
36
|
+
type EncryptParams,
|
|
37
|
+
EncryptParamsBuilder,
|
|
35
38
|
type EncryptStreamMiddleware,
|
|
36
|
-
type
|
|
39
|
+
type Scope,
|
|
37
40
|
} from './builders.js';
|
|
38
41
|
import { DecoratedReadableStream } from './DecoratedReadableStream.js';
|
|
39
|
-
|
|
40
|
-
import {
|
|
41
|
-
DEFAULT_SEGMENT_SIZE,
|
|
42
|
-
DecryptParamsBuilder,
|
|
43
|
-
type DecryptSource,
|
|
44
|
-
EncryptParamsBuilder,
|
|
45
|
-
} from './builders.js';
|
|
46
42
|
import {
|
|
47
43
|
fetchKeyAccessServers,
|
|
48
44
|
type KasPublicKeyInfo,
|
|
@@ -62,8 +58,8 @@ import {
|
|
|
62
58
|
} from '../models/index.js';
|
|
63
59
|
import { plan } from '../../../src/policy/granter.js';
|
|
64
60
|
import { attributeFQNsAsValues } from '../../../src/policy/api.js';
|
|
65
|
-
import { type Value } from '../../../src/policy/attributes.js';
|
|
66
61
|
import { type Chunker, fromBuffer, fromSource } from '../../../src/seekable.js';
|
|
62
|
+
import { Algorithm, SimpleKasKey } from '../../../src/platform/policy/objects_pb.js';
|
|
67
63
|
|
|
68
64
|
const GLOBAL_BYTE_LIMIT = 64 * 1000 * 1000 * 1000; // 64 GB, see WS-9363.
|
|
69
65
|
|
|
@@ -72,6 +68,11 @@ const defaultClientConfig = { oidcOrigin: '', cryptoService: defaultCryptoServic
|
|
|
72
68
|
|
|
73
69
|
const getFirstTwoBytes = async (chunker: Chunker) => new TextDecoder().decode(await chunker(0, 2));
|
|
74
70
|
|
|
71
|
+
async function algorithmFromPEM(pem: string) {
|
|
72
|
+
const k: CryptoKey = await pemToCryptoPublicKey(pem);
|
|
73
|
+
return keyAlgorithmToPublicKeyAlgorithm(k);
|
|
74
|
+
}
|
|
75
|
+
|
|
75
76
|
// Convert a PEM string to a CryptoKey
|
|
76
77
|
export const resolveKasInfo = async (
|
|
77
78
|
pem: string,
|
|
@@ -227,6 +228,95 @@ function asPolicy(scope: Scope): Policy {
|
|
|
227
228
|
};
|
|
228
229
|
}
|
|
229
230
|
|
|
231
|
+
type KasKeyInfoCache = [
|
|
232
|
+
...Parameters<typeof fetchKasPublicKey>,
|
|
233
|
+
keyInfoPromise: ReturnType<typeof fetchKasPublicKey>,
|
|
234
|
+
][];
|
|
235
|
+
|
|
236
|
+
export function findEntryInCache(
|
|
237
|
+
cache: KasKeyInfoCache,
|
|
238
|
+
...params: Parameters<typeof fetchKasPublicKey>
|
|
239
|
+
) {
|
|
240
|
+
const [wantedKas, wantedAlgorithm, wantedKid] = params;
|
|
241
|
+
for (const item of cache) {
|
|
242
|
+
const [itemKas, itemAlgorithm, itemKid, itemKeyInfoPromise] = item;
|
|
243
|
+
if (itemKas !== wantedKas) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
// This makes undefined only match with undefined (base key).
|
|
247
|
+
// We could potentially consider any key a match if undefined algorithm?
|
|
248
|
+
if (itemAlgorithm !== wantedAlgorithm) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (wantedKid && itemKid !== wantedKid) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
return itemKeyInfoPromise;
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const fetchKasKeyWithCache = (
|
|
260
|
+
cache: KasKeyInfoCache,
|
|
261
|
+
...params: Parameters<typeof fetchKasPublicKey>
|
|
262
|
+
): ReturnType<typeof fetchKasPublicKey> => {
|
|
263
|
+
const cachedEntry = findEntryInCache(cache, ...params);
|
|
264
|
+
if (cachedEntry !== null) {
|
|
265
|
+
return cachedEntry;
|
|
266
|
+
}
|
|
267
|
+
const keyInfoPromise = fetchKasPublicKey(...params);
|
|
268
|
+
cache.push([...params, keyInfoPromise]);
|
|
269
|
+
return keyInfoPromise;
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
function algorithmEnumValueToString(algorithmEnumValue: Algorithm) {
|
|
273
|
+
switch (algorithmEnumValue) {
|
|
274
|
+
case Algorithm.RSA_2048:
|
|
275
|
+
return 'rsa:2048';
|
|
276
|
+
case Algorithm.RSA_4096:
|
|
277
|
+
return 'rsa:4096';
|
|
278
|
+
case Algorithm.EC_P256:
|
|
279
|
+
return 'ec:secp256r1';
|
|
280
|
+
case Algorithm.EC_P384:
|
|
281
|
+
return 'ec:secp384r1';
|
|
282
|
+
case Algorithm.EC_P521:
|
|
283
|
+
return 'ec:secp521r1';
|
|
284
|
+
case Algorithm.UNSPECIFIED:
|
|
285
|
+
// Not entirely sure undefined is correct here, but since we need to generate a key for our cache
|
|
286
|
+
// synchonously, it seems to be the best approach for now.
|
|
287
|
+
return undefined;
|
|
288
|
+
default:
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const putKasKeyIntoCache = (
|
|
294
|
+
cache: KasKeyInfoCache,
|
|
295
|
+
kasKey: Omit<SimpleKasKey, 'publicKey'> & {
|
|
296
|
+
publicKey: Exclude<SimpleKasKey['publicKey'], undefined>;
|
|
297
|
+
}
|
|
298
|
+
): ReturnType<typeof fetchKasPublicKey> => {
|
|
299
|
+
const algorithmString = algorithmEnumValueToString(kasKey.publicKey.algorithm);
|
|
300
|
+
const cachedEntry = findEntryInCache(cache, kasKey.kasUri, algorithmString, kasKey.publicKey.kid);
|
|
301
|
+
if (cachedEntry) {
|
|
302
|
+
return cachedEntry;
|
|
303
|
+
}
|
|
304
|
+
const keyInfoPromise = (async function () {
|
|
305
|
+
const keyPromise = pemToCryptoPublicKey(kasKey.publicKey.pem);
|
|
306
|
+
const key = await keyPromise;
|
|
307
|
+
const algorithm = keyAlgorithmToPublicKeyAlgorithm(key);
|
|
308
|
+
return {
|
|
309
|
+
algorithm: algorithm,
|
|
310
|
+
key: keyPromise,
|
|
311
|
+
kid: kasKey.publicKey.kid,
|
|
312
|
+
publicKey: kasKey.publicKey.pem,
|
|
313
|
+
url: kasKey.kasUri,
|
|
314
|
+
};
|
|
315
|
+
})();
|
|
316
|
+
cache.push([kasKey.kasUri, algorithmString, kasKey.publicKey.kid, keyInfoPromise]);
|
|
317
|
+
return keyInfoPromise;
|
|
318
|
+
};
|
|
319
|
+
|
|
230
320
|
export class Client {
|
|
231
321
|
readonly cryptoService: CryptoService;
|
|
232
322
|
|
|
@@ -252,7 +342,7 @@ export class Client {
|
|
|
252
342
|
*/
|
|
253
343
|
readonly platformUrl?: string;
|
|
254
344
|
|
|
255
|
-
readonly
|
|
345
|
+
readonly kasKeyInfoCache: KasKeyInfoCache = [];
|
|
256
346
|
|
|
257
347
|
readonly easEndpoint?: string;
|
|
258
348
|
|
|
@@ -360,11 +450,13 @@ export class Client {
|
|
|
360
450
|
cryptoService: this.cryptoService,
|
|
361
451
|
dpopKeys: clientConfig.dpopKeys,
|
|
362
452
|
});
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** Necessary only for testing. A dependency-injection approach should be preferred, but that is difficult currently */
|
|
456
|
+
_doFetchKasKeyWithCache(
|
|
457
|
+
...params: Parameters<typeof fetchKasKeyWithCache>
|
|
458
|
+
): ReturnType<typeof fetchKasKeyWithCache> {
|
|
459
|
+
return fetchKasKeyWithCache(...params);
|
|
368
460
|
}
|
|
369
461
|
|
|
370
462
|
/**
|
|
@@ -396,62 +488,165 @@ export class Client {
|
|
|
396
488
|
mimeType = 'unknown',
|
|
397
489
|
windowSize = DEFAULT_SEGMENT_SIZE,
|
|
398
490
|
keyMiddleware = defaultKeyMiddleware,
|
|
491
|
+
splitPlan: preconfiguredSplitPlan,
|
|
399
492
|
streamMiddleware = async (stream: DecoratedReadableStream) => stream,
|
|
400
493
|
tdfSpecVersion,
|
|
401
494
|
wrappingKeyAlgorithm,
|
|
402
495
|
} = opts;
|
|
403
496
|
const scope = opts.scope ?? { attributes: [], dissem: [] };
|
|
404
497
|
|
|
498
|
+
for (const attributeValue of scope.attributeValues || []) {
|
|
499
|
+
for (const kasKey of attributeValue.kasKeys) {
|
|
500
|
+
if (kasKey.publicKey !== undefined) {
|
|
501
|
+
await putKasKeyIntoCache(this.kasKeyInfoCache, {
|
|
502
|
+
// TypeScript is silly and cannot infer that publicKey is not undefined, without re-referencing it like this, even though we checked already.
|
|
503
|
+
...kasKey,
|
|
504
|
+
publicKey: kasKey.publicKey,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
405
510
|
const policyObject = asPolicy(scope);
|
|
406
511
|
validatePolicyObject(policyObject);
|
|
407
512
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
513
|
+
const splitPlan: {
|
|
514
|
+
kas: string;
|
|
515
|
+
kid?: string;
|
|
516
|
+
pem: string;
|
|
517
|
+
sid?: string;
|
|
518
|
+
}[] = [];
|
|
519
|
+
if (preconfiguredSplitPlan) {
|
|
520
|
+
for (const preconfiguredSplit of preconfiguredSplitPlan) {
|
|
521
|
+
const kasPublicKeyInfo = await this._doFetchKasKeyWithCache(
|
|
522
|
+
this.kasKeyInfoCache,
|
|
523
|
+
preconfiguredSplit.kas,
|
|
524
|
+
wrappingKeyAlgorithm,
|
|
525
|
+
preconfiguredSplit.kid
|
|
526
|
+
);
|
|
527
|
+
splitPlan.push({
|
|
528
|
+
kas: kasPublicKeyInfo.url,
|
|
529
|
+
kid: kasPublicKeyInfo.kid,
|
|
530
|
+
pem: kasPublicKeyInfo.publicKey,
|
|
531
|
+
sid: preconfiguredSplit.sid,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
} else if (autoconfigure) {
|
|
535
|
+
const attributeValues = scope.attributeValues ?? [];
|
|
536
|
+
if (!scope.attributes) {
|
|
537
|
+
scope.attributes = attributeValues.map(({ fqn }) => fqn);
|
|
538
|
+
}
|
|
539
|
+
const attributeFQNs = (scope.attributes ?? []).map((attribute) =>
|
|
540
|
+
typeof attribute === 'string' ? attribute : attribute.attribute
|
|
541
|
+
);
|
|
542
|
+
const fqnsWithoutValues = attributeFQNs.filter((fqn) =>
|
|
543
|
+
attributeValues.every((av) => av.fqn !== fqn)
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
if (fqnsWithoutValues.length) {
|
|
547
|
+
// Hydrate missing avs from policy endpoint given the fqns
|
|
548
|
+
if (!this.platformUrl) {
|
|
549
|
+
throw new ConfigurationError('platformUrl not set in TDF3 Client constructor');
|
|
421
550
|
}
|
|
422
|
-
|
|
423
|
-
this.
|
|
551
|
+
const fetchedFQNValues = await attributeFQNsAsValues(
|
|
552
|
+
this.platformUrl,
|
|
424
553
|
this.authProvider as AuthProvider,
|
|
425
|
-
...
|
|
554
|
+
...fqnsWithoutValues
|
|
426
555
|
);
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
scope.attributes = avs.map(({ fqn }) => fqn);
|
|
431
|
-
}
|
|
556
|
+
fetchedFQNValues.forEach((fetchedValue) => {
|
|
557
|
+
attributeValues.push(fetchedValue);
|
|
558
|
+
});
|
|
432
559
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
)
|
|
560
|
+
|
|
561
|
+
const hasAllFQNs = attributeFQNs.every((fqn) =>
|
|
562
|
+
attributeValues.some((attributeValue) => attributeValue.fqn === fqn)
|
|
563
|
+
);
|
|
564
|
+
if (attributeFQNs.length != attributeValues.length || !hasAllFQNs) {
|
|
437
565
|
throw new ConfigurationError(
|
|
438
|
-
`Attribute mismatch between [${
|
|
439
|
-
|
|
566
|
+
`Attribute mismatch between [${attributeFQNs}] and explicit values ${JSON.stringify(
|
|
567
|
+
attributeValues.map(({ fqn }) => fqn)
|
|
440
568
|
)}`
|
|
441
569
|
);
|
|
442
570
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
571
|
+
|
|
572
|
+
for (const attributeValue of attributeValues) {
|
|
573
|
+
for (const kasKey of attributeValue.kasKeys) {
|
|
574
|
+
if (kasKey.publicKey !== undefined) {
|
|
575
|
+
await putKasKeyIntoCache(this.kasKeyInfoCache, {
|
|
576
|
+
// TypeScript is silly and cannot infer that publicKey is not undefined, without re-referencing it like this, even though we checked already.
|
|
577
|
+
...kasKey,
|
|
578
|
+
publicKey: kasKey.publicKey,
|
|
579
|
+
});
|
|
451
580
|
}
|
|
452
581
|
}
|
|
453
|
-
|
|
454
|
-
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
const detailedPlan = plan(attributeValues);
|
|
585
|
+
for (const item of detailedPlan) {
|
|
586
|
+
if ('kid' in item.kas) {
|
|
587
|
+
const pemAlgorithm = await algorithmFromPEM(item.kas.pem);
|
|
588
|
+
const kasPublicKeyInfo = await this._doFetchKasKeyWithCache(
|
|
589
|
+
this.kasKeyInfoCache,
|
|
590
|
+
item.kas.kasUri,
|
|
591
|
+
pemAlgorithm,
|
|
592
|
+
item.kas.kid
|
|
593
|
+
);
|
|
594
|
+
splitPlan.push({
|
|
595
|
+
kas: kasPublicKeyInfo.url,
|
|
596
|
+
kid: kasPublicKeyInfo.kid,
|
|
597
|
+
pem: kasPublicKeyInfo.publicKey,
|
|
598
|
+
sid: item.sid,
|
|
599
|
+
});
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if (!item.kas.publicKey) {
|
|
604
|
+
const kasPublicKeyInfo = await this._doFetchKasKeyWithCache(
|
|
605
|
+
this.kasKeyInfoCache,
|
|
606
|
+
item.kas.uri,
|
|
607
|
+
wrappingKeyAlgorithm,
|
|
608
|
+
undefined
|
|
609
|
+
);
|
|
610
|
+
splitPlan.push({
|
|
611
|
+
kas: kasPublicKeyInfo.url,
|
|
612
|
+
kid: kasPublicKeyInfo.kid,
|
|
613
|
+
pem: kasPublicKeyInfo.publicKey,
|
|
614
|
+
sid: item.sid,
|
|
615
|
+
});
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
switch (item.kas.publicKey.publicKey.case) {
|
|
620
|
+
case 'remote':
|
|
621
|
+
const kasPublicKeyInfo = await this._doFetchKasKeyWithCache(
|
|
622
|
+
this.kasKeyInfoCache,
|
|
623
|
+
item.kas.publicKey.publicKey.value,
|
|
624
|
+
wrappingKeyAlgorithm,
|
|
625
|
+
undefined
|
|
626
|
+
);
|
|
627
|
+
splitPlan.push({
|
|
628
|
+
kas: kasPublicKeyInfo.url,
|
|
629
|
+
kid: kasPublicKeyInfo.kid,
|
|
630
|
+
pem: kasPublicKeyInfo.publicKey,
|
|
631
|
+
sid: item.sid,
|
|
632
|
+
});
|
|
633
|
+
break;
|
|
634
|
+
|
|
635
|
+
case 'cached':
|
|
636
|
+
for (const cachedPublicKey of item.kas.publicKey.publicKey.value.keys) {
|
|
637
|
+
splitPlan.push({
|
|
638
|
+
kas: item.kas.uri,
|
|
639
|
+
kid: cachedPublicKey.kid,
|
|
640
|
+
pem: cachedPublicKey.pem,
|
|
641
|
+
sid: item.sid,
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
break;
|
|
645
|
+
|
|
646
|
+
default:
|
|
647
|
+
throw new Error(`Unknown public key type: ${item.kas.publicKey.publicKey.case}`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
455
650
|
}
|
|
456
651
|
|
|
457
652
|
// TODO: Refactor underlying builder to remove some of this unnecessary config.
|
|
@@ -462,37 +657,47 @@ export class Client {
|
|
|
462
657
|
? maxByteLimit
|
|
463
658
|
: opts.byteLimit;
|
|
464
659
|
const encryptionInformation = new SplitKey(new AesGcmCipher(this.cryptoService));
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
660
|
+
if (splitPlan.length === 0) {
|
|
661
|
+
const kasPublicKeyInfo = await this._doFetchKasKeyWithCache(
|
|
662
|
+
this.kasKeyInfoCache,
|
|
663
|
+
opts.defaultKASEndpoint ?? this.kasEndpoint,
|
|
664
|
+
wrappingKeyAlgorithm,
|
|
665
|
+
undefined
|
|
666
|
+
);
|
|
667
|
+
splitPlan.push({
|
|
668
|
+
kas: kasPublicKeyInfo.url,
|
|
669
|
+
kid: kasPublicKeyInfo.kid,
|
|
670
|
+
pem: kasPublicKeyInfo.publicKey,
|
|
671
|
+
});
|
|
672
|
+
}
|
|
468
673
|
encryptionInformation.keyAccess = await Promise.all(
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
}
|
|
473
|
-
const kasPublicKey = await Promise.any(this.kasKeys[kas]);
|
|
474
|
-
if (kasPublicKey.algorithm !== wrappingKeyAlgorithm) {
|
|
674
|
+
splitPlan.map(async ({ kas, kid, pem, sid }) => {
|
|
675
|
+
const algorithm = await algorithmFromPEM(pem);
|
|
676
|
+
if (algorithm !== wrappingKeyAlgorithm) {
|
|
475
677
|
console.warn(
|
|
476
|
-
`Mismatched wrapping key algorithm: [${
|
|
678
|
+
`Mismatched wrapping key algorithm: [${algorithm}] is not requested type, [${wrappingKeyAlgorithm}]`
|
|
477
679
|
);
|
|
478
680
|
}
|
|
479
681
|
let type: KeyAccessType;
|
|
480
|
-
switch (
|
|
682
|
+
switch (algorithm) {
|
|
481
683
|
case 'rsa:2048':
|
|
684
|
+
case 'rsa:4096':
|
|
482
685
|
type = 'wrapped';
|
|
483
686
|
break;
|
|
687
|
+
case 'ec:secp384r1':
|
|
688
|
+
case 'ec:secp521r1':
|
|
484
689
|
case 'ec:secp256r1':
|
|
485
690
|
type = 'ec-wrapped';
|
|
486
691
|
break;
|
|
487
692
|
default:
|
|
488
|
-
throw new ConfigurationError(`Unsupported algorithm ${
|
|
693
|
+
throw new ConfigurationError(`Unsupported algorithm ${algorithm}`);
|
|
489
694
|
}
|
|
490
695
|
return buildKeyAccess({
|
|
491
|
-
alg:
|
|
696
|
+
alg: algorithm,
|
|
492
697
|
type,
|
|
493
|
-
url:
|
|
494
|
-
kid:
|
|
495
|
-
publicKey:
|
|
698
|
+
url: kas,
|
|
699
|
+
kid: kid,
|
|
700
|
+
publicKey: pem,
|
|
496
701
|
metadata,
|
|
497
702
|
sid,
|
|
498
703
|
});
|
|
@@ -21,10 +21,10 @@ const IP_HOST_PORT = '([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}:[0-9]{1
|
|
|
21
21
|
const HOST = `(${HOST_PORT}|${WWW_HOST}|${IP_HOST_PORT})`;
|
|
22
22
|
|
|
23
23
|
// validate attr name be like `/attr/<attr_name>`
|
|
24
|
-
export const ATTR_NAME = `(/${ATTR_NAME_PROP_NAME}/[a-zA-Z0-9][a-zA-Z0-9-]
|
|
24
|
+
export const ATTR_NAME = `(/${ATTR_NAME_PROP_NAME}/(%[0-9a-fA-F][0-9a-fA-F]|[a-zA-Z0-9])+((%[0-9a-fA-F][0-9a-fA-F]|[a-zA-Z0-9-])+[a-zA-Z0-9])?)`;
|
|
25
25
|
|
|
26
26
|
// validate value pattern
|
|
27
|
-
export const ATTR_VALUE = `(/${ATTR_VALUE_PROP_NAME}/[a-zA-Z0-9][a-zA-Z0-9-]
|
|
27
|
+
export const ATTR_VALUE = `(/${ATTR_VALUE_PROP_NAME}/(%[0-9a-fA-F][0-9a-fA-F]|[a-zA-Z0-9])+((%[0-9a-fA-F][0-9a-fA-F]|[a-zA-Z0-9-])+[a-zA-Z0-9])?)`;
|
|
28
28
|
|
|
29
29
|
// validate attribute authority e.g. https://example.com
|
|
30
30
|
const ATTR_AUTHORITY_PATTERN = `(${SCHEME}${HOST})`;
|
package/tdf3/src/tdf.ts
CHANGED
|
@@ -197,8 +197,15 @@ export type RewrapResponse = {
|
|
|
197
197
|
*/
|
|
198
198
|
export async function fetchKasPublicKey(
|
|
199
199
|
kas: string,
|
|
200
|
-
algorithm?: KasPublicKeyAlgorithm
|
|
200
|
+
algorithm?: KasPublicKeyAlgorithm,
|
|
201
|
+
kid?: string
|
|
201
202
|
): Promise<KasPublicKeyInfo> {
|
|
203
|
+
if (kid) {
|
|
204
|
+
// Some specific thing for fetching a key by kid?
|
|
205
|
+
// Currently this is just "using" `kid` so TypeScript doesn't complain and
|
|
206
|
+
// we can use the type for our cache parameters.
|
|
207
|
+
// So this empty `if` is actually doing something.
|
|
208
|
+
}
|
|
202
209
|
return fetchKasPubKeyV2(kas, algorithm);
|
|
203
210
|
}
|
|
204
211
|
|