Skip to content

Commit 4e54c0d

Browse files
feat(cli): Adds --policyBinding ecdsa option (#352)
Only effective with `-t nano`, this enables the ECDSA binding type to verify the policy is attached to the key is as expected.
1 parent 031bbb7 commit 4e54c0d

File tree

5 files changed

+156
-83
lines changed

5 files changed

+156
-83
lines changed

cli/package-lock.json

Lines changed: 42 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/src/cli.ts

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ type LoggedAuthProvider = AuthProvider & {
3131
requestLog: HttpRequest[];
3232
};
3333

34-
const containerTypes = ['tdf3', 'nano', 'dataset'] as const;
34+
const bindingTypes = ['ecdsa', 'gmac'];
35+
36+
const containerTypes = ['tdf3', 'nano', 'dataset', 'ztdf'];
3537

3638
const parseJwt = (jwt: string, field = 1) => {
3739
return JSON.parse(Buffer.from(jwt.split('.')[field], 'base64').toString());
@@ -219,48 +221,52 @@ export const handleArgs = (args: string[]) => {
219221
})
220222
.implies('exchangeToken', 'clientId')
221223

222-
.option('containerType', {
223-
group: 'TDF Settings',
224-
alias: 't',
225-
choices: containerTypes,
226-
description: 'Container format',
227-
default: 'nano',
228-
})
229-
230-
.option('userId', {
231-
group: 'TDF Settings',
232-
type: 'string',
233-
description: 'Owner email address',
234-
})
235-
236224
// Examples
237225
.example('$0 --auth ClientID123:Cli3nt$ecret', '# OIDC client credentials')
238226

239227
.example('$0 --clientId ClientID123 --clientSecret Cli3nt$ecret', '# OIDC client credentials')
240228

241-
// POLICY
229+
// Policy, encryption, and container options
242230
.options({
243-
usersWithAccess: {
244-
alias: 'users-with-access',
245-
group: 'Encrypt Options',
246-
desc: 'Add users to the policy',
247-
type: 'string',
248-
default: '',
249-
validate: (users: string) => users.split(','),
250-
},
251231
attributes: {
252232
group: 'Encrypt Options',
253233
desc: 'Data attributes for the policy',
254234
type: 'string',
255235
default: '',
256236
validate: (attributes: string) => attributes.split(','),
257237
},
238+
containerType: {
239+
group: 'Encrypt Options',
240+
alias: 't',
241+
choices: containerTypes,
242+
description: 'Container format',
243+
default: 'nano',
244+
},
245+
policyBinding: {
246+
group: 'Encrypt Options',
247+
choices: bindingTypes,
248+
description: 'Policy Binding Type (nano only)',
249+
default: 'gmac',
250+
},
258251
mimeType: {
259252
group: 'Encrypt Options',
260253
desc: 'Mime type for the plain text file (only supported for ztdf)',
261254
type: 'string',
262255
default: '',
263256
},
257+
userId: {
258+
group: 'Encrypt Options',
259+
type: 'string',
260+
description: 'Owner email address',
261+
},
262+
usersWithAccess: {
263+
alias: 'users-with-access',
264+
group: 'Encrypt Options',
265+
desc: 'Add users to the policy',
266+
type: 'string',
267+
default: '',
268+
validate: (users: string) => users.split(','),
269+
},
264270
})
265271

266272
// COMMANDS
@@ -299,7 +305,7 @@ export const handleArgs = (args: string[]) => {
299305
log('DEBUG', `Initialized auth provider ${JSON.stringify(authProvider)}`);
300306

301307
const kasEndpoint = argv.kasEndpoint;
302-
if (argv.containerType === 'tdf3') {
308+
if (argv.containerType === 'tdf3' || argv.containerType == 'ztdf') {
303309
log('DEBUG', `TDF3 Client`);
304310
const client = new TDF3Client({
305311
allowedKases,
@@ -389,7 +395,7 @@ export const handleArgs = (args: string[]) => {
389395
const ignoreAllowList = !!argv.ignoreAllowList;
390396
const allowedKases = argv.allowList?.split(',');
391397

392-
if ('tdf3' === argv.containerType) {
398+
if ('tdf3' === argv.containerType || 'ztdf' === argv.containerType) {
393399
log('DEBUG', `TDF3 Client`);
394400
const client = new TDF3Client({
395401
allowedKases,
@@ -411,6 +417,7 @@ export const handleArgs = (args: string[]) => {
411417
}
412418
} else {
413419
const dpopEnabled = !!argv.dpop;
420+
const ecdsaBinding = argv.policyBinding.toLowerCase() == 'ecdsa';
414421
const client =
415422
argv.containerType === 'nano'
416423
? new NanoTDFClient({ allowedKases, authProvider, dpopEnabled, kasEndpoint })
@@ -425,7 +432,7 @@ export const handleArgs = (args: string[]) => {
425432
addParams(client, argv);
426433

427434
const buffer = await processDataIn(argv.file as string);
428-
const cyphertext = await client.encrypt(buffer);
435+
const cyphertext = await client.encrypt(buffer, { ecdsaBinding });
429436

430437
log('DEBUG', `Handle cyphertext output ${JSON.stringify(cyphertext)}`);
431438
if (argv.output) {

lib/src/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ export class NanoTDFDatasetClient extends Client {
221221
private unwrappedKey?: CryptoKey;
222222
private symmetricKey?: CryptoKey;
223223
private cachedHeader?: Header;
224+
private ecdsaBinding: boolean;
224225

225226
/**
226227
* Create new NanoTDF Dataset Client
@@ -256,9 +257,14 @@ export class NanoTDFDatasetClient extends Client {
256257
*
257258
* @param data to decrypt
258259
*/
259-
async encrypt(data: string | TypedArray | ArrayBuffer): Promise<ArrayBuffer> {
260+
async encrypt(
261+
data: string | TypedArray | ArrayBuffer,
262+
options?: EncryptOptions
263+
): Promise<ArrayBuffer> {
260264
// Intial encrypt
261265
if (this.keyIterationCount == 0) {
266+
const mergedOptions: EncryptOptions = { ...defaultOptions, ...options };
267+
this.ecdsaBinding = mergedOptions.ecdsaBinding;
262268
// For encrypt always generate the client ephemeralKeyPair
263269
const ephemeralKeyPair = await this.ephemeralKeyPair;
264270

@@ -298,7 +304,8 @@ export class NanoTDFDatasetClient extends Client {
298304
this.kasPubKey,
299305
ephemeralKeyPair,
300306
ivVector,
301-
data
307+
data,
308+
this.ecdsaBinding
302309
);
303310

304311
// Cache the header and increment the key iteration

0 commit comments

Comments
 (0)