Skip to content

Commit

Permalink
feat(sdk): Allows skipping verification (#371)
Browse files Browse the repository at this point in the history
Also:

- Removes all refs to node:buffer I could find
  - removes the polyfill from the web-test-runner, to make sure we aren't accidentally including it (at least in things that covers)
  - updates all .spec and .test files, in turn
  - renames a bunch of things called `buffer` to something else so I can search for this easier
-  feat(cli): Adds --assertions to cli for testing encrypting with assertions
-  feat(cli): Adds --no-verify-assertions to cli for testing decrypt without verifying assertions (for invalid or unverifiable assertions)
  • Loading branch information
dmihalcik-virtru authored Oct 28, 2024
1 parent 406e6fb commit 8529461
Show file tree
Hide file tree
Showing 31 changed files with 420 additions and 466 deletions.
53 changes: 4 additions & 49 deletions cli/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 43 additions & 6 deletions cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import {
} from '@opentdf/client';
import { CLIError, Level, log } from './logger.js';
import { webcrypto } from 'crypto';
import * as assertions from '@opentdf/client/assertions';
import { attributeFQNsAsValues } from '@opentdf/client/nano';
import { base64 } from '@opentdf/client/encodings';

type AuthToProcess = {
auth?: string;
Expand All @@ -37,8 +39,9 @@ const bindingTypes = ['ecdsa', 'gmac'];
const containerTypes = ['tdf3', 'nano', 'dataset', 'ztdf'];

const parseJwt = (jwt: string, field = 1) => {
return JSON.parse(Buffer.from(jwt.split('.')[field], 'base64').toString());
return JSON.parse(base64.decode(jwt.split('.')[field]));
};

const parseJwtComplete = (jwt: string) => {
return { header: parseJwt(jwt, 0), payload: parseJwt(jwt) };
};
Expand Down Expand Up @@ -113,12 +116,33 @@ function addParams(client: AnyNanoClient, argv: Partial<mainArgs>) {

async function tdf3DecryptParamsFor(argv: Partial<mainArgs>): Promise<DecryptParams> {
const c = new DecryptParamsBuilder();
if (argv.noVerifyAssertions) {
c.withNoVerifyAssertions(true);
}
c.setFileSource(await openAsBlob(argv.file as string));
return c.build();
}

function parseAssertionConfig(s: string): assertions.AssertionConfig[] {
const u = JSON.parse(s);
// if u is null or empty, return an empty array
if (!u) {
return [];
}
const a = Array.isArray(u) ? u : [u];
for (const assertion of a) {
if (!assertions.isAssertionConfig(assertion)) {
throw new CLIError('CRITICAL', `invalid assertion config ${JSON.stringify(assertion)}`);
}
}
return a;
}

async function tdf3EncryptParamsFor(argv: Partial<mainArgs>): Promise<EncryptParams> {
const c = new EncryptParamsBuilder();
if (argv.assertions?.length) {
c.withAssertions(parseAssertionConfig(argv.assertions));
}
if (argv.attributes?.length) {
c.setAttributes(argv.attributes.split(','));
}
Expand Down Expand Up @@ -201,13 +225,19 @@ export const handleArgs = (args: string[]) => {
group: 'Security:',
desc: 'allowed KAS origins, comma separated; defaults to [kasEndpoint]',
type: 'string',
validate: (attributes: string) => attributes.split(','),
validate: (uris: string) => uris.split(','),
})
.option('ignoreAllowList', {
group: 'Security:',
desc: 'disable KAS allowlist feature for decrypt',
type: 'boolean',
})
.option('noVerifyAssertions', {
alias: 'no-verify-assertions',
group: 'Security',
desc: 'Do not verify assertions',
type: 'boolean',
})
.option('auth', {
group: 'OAuth and OIDC:',
type: 'string',
Expand Down Expand Up @@ -252,6 +282,13 @@ export const handleArgs = (args: string[]) => {

// Policy, encryption, and container options
.options({
assertions: {
group: 'Encrypt Options:',
desc: 'ZTDF assertion config objects',
type: 'string',
default: '',
validate: parseAssertionConfig,
},
attributes: {
group: 'Encrypt Options:',
desc: 'Data attributes for the policy',
Expand Down Expand Up @@ -413,9 +450,9 @@ export const handleArgs = (args: string[]) => {

log('DEBUG', 'Handle output.');
if (argv.output) {
await writeFile(argv.output, Buffer.from(plaintext));
await writeFile(argv.output, new Uint8Array(plaintext));
} else {
console.log(Buffer.from(plaintext).toString('utf8'));
console.log(new TextDecoder().decode(plaintext));
}
}
const lastRequest = authProvider.requestLog[authProvider.requestLog.length - 1];
Expand Down Expand Up @@ -503,9 +540,9 @@ export const handleArgs = (args: string[]) => {

log('DEBUG', `Handle cyphertext output ${JSON.stringify(cyphertext)}`);
if (argv.output) {
await writeFile(argv.output, Buffer.from(cyphertext));
await writeFile(argv.output, new Uint8Array(cyphertext));
} else {
console.log(Buffer.from(cyphertext).toString('base64'));
console.log(base64.encodeArrayBuffer(cyphertext));
}
}
}
Expand Down
24 changes: 1 addition & 23 deletions lib/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@
"require": "./dist/cjs/tdf3/index.js",
"import": "./dist/web/tdf3/index.js"
},
"./assertions": {
"default": {
"types": "./dist/types/tdf3/src/assertions.d.ts",
"require": "./dist/cjs/tdf3/src/assertions.js",
"import": "./dist/web/tdf3/src/assertions.js"
}
},
"./encodings": {
"default": {
"types": "./dist/types/src/encodings/index.d.ts",
Expand Down Expand Up @@ -64,7 +71,6 @@
"axios-retry": "^3.9.0",
"base64-js": "^1.5.1",
"browser-fs-access": "^0.34.1",
"buffer": "^6.0.3",
"buffer-crc32": "^0.2.13",
"dpop": "^1.2.0",
"eventemitter3": "^5.0.1",
Expand Down
20 changes: 10 additions & 10 deletions lib/src/nanotdf/models/Header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,28 +232,28 @@ export default class Header {
/**
* Copy the contents of the header to buffer
*/
copyToBuffer(buffer: Uint8Array): void {
if (this.length > buffer.length) {
copyToBuffer(target: Uint8Array): void {
if (this.length > target.length) {
throw new InvalidFileError('invalid buffer size to copy tdf header');
}

let offset = 0;

// Write Magic number and version
buffer.set(this.magicNumberVersion, 0);
target.set(this.magicNumberVersion, 0);
offset += this.magicNumberVersion.length;

// Write kas resource locator
const kasResourceLocatorBuf = this.kas.toBuffer();
buffer.set(kasResourceLocatorBuf, offset);
target.set(kasResourceLocatorBuf, offset);
offset += kasResourceLocatorBuf.length;

// Write ECC & Binding Mode
const ecdsaBinding = this.useECDSABinding ? 1 : 0;
const eccBingingMode = (ecdsaBinding << 7) | this.ephemeralCurveName;
const eccBingingModeAsByte = new Uint8Array(1);
eccBingingModeAsByte[0] = eccBingingMode;
buffer.set(eccBingingModeAsByte, offset);
target.set(eccBingingModeAsByte, offset);
offset += eccBingingModeAsByte.length;

// Write symmetric & payload config
Expand All @@ -262,16 +262,16 @@ export default class Header {
(isSignatureEnable << 7) | this.signatureCurveName | this.symmetricCipher;
const symmetricPayloadConfigAsByte = new Uint8Array(1);
symmetricPayloadConfigAsByte[0] = symmetricPayloadConfig;
buffer.set(symmetricPayloadConfigAsByte, offset);
target.set(symmetricPayloadConfigAsByte, offset);
offset += symmetricPayloadConfigAsByte.length;

// Write the policy
const policyBuffer = this.policy.toBuffer();
buffer.set(policyBuffer, offset);
target.set(policyBuffer, offset);
offset += policyBuffer.length;

// Write the ephemeral public key
buffer.set(this.ephemeralPublicKey, offset);
target.set(this.ephemeralPublicKey, offset);
}

/**
Expand Down Expand Up @@ -304,8 +304,8 @@ export default class Header {
*/
toBuffer(): ArrayBuffer {
const arrayBuffer = new ArrayBuffer(this.length);
const buffer = new Uint8Array(arrayBuffer);
this.copyToBuffer(buffer);
const target = new Uint8Array(arrayBuffer);
this.copyToBuffer(target);
return arrayBuffer;
}

Expand Down
12 changes: 6 additions & 6 deletions lib/src/nanotdf/models/Payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ export default class Payload {
/**
* Copy the contents of the signature to buffer
*/
copyToBuffer(buffer: Uint8Array): void {
if (this.length > buffer.length) {
copyToBuffer(target: Uint8Array): void {
if (this.length > target.length) {
throw new Error('internal: invalid buffer size to copy payload');
}

Expand All @@ -188,9 +188,9 @@ export default class Payload {
payloadSizeAsBg[1] = lengthAsUint24[1];
payloadSizeAsBg[2] = lengthAsUint24[0];

buffer.set(payloadSizeAsBg, 0);
buffer.set(this.iv, payloadSizeAsBg.length);
buffer.set(this.ciphertext, payloadSizeAsBg.length + this.iv.length);
buffer.set(this.authTag, payloadSizeAsBg.length + this.iv.length + this.ciphertext.length);
target.set(payloadSizeAsBg, 0);
target.set(this.iv, payloadSizeAsBg.length);
target.set(this.ciphertext, payloadSizeAsBg.length + this.iv.length);
target.set(this.authTag, payloadSizeAsBg.length + this.iv.length + this.ciphertext.length);
}
}
12 changes: 6 additions & 6 deletions lib/src/nanotdf/models/Policy/EmbeddedPolicy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ class EmbeddedPolicy extends AbstractPolicy implements EmbeddedPolicyInterface {
* Return the content of the policy
*/
override toBuffer(): Uint8Array {
const buffer = new Uint8Array(this.getLength());
const target = new Uint8Array(this.getLength());

if (this.content.length > EmbeddedPolicy.MAX_POLICY_SIZE) {
throw new ConfigurationError("TDF Policy can't be more that 2^16");
}

buffer.set([this.type], 0);
target.set([this.type], 0);

// Write the policy length, assuming the host system is little endian
// TODO: There should be better way to convert to big endian
Expand All @@ -86,15 +86,15 @@ class EmbeddedPolicy extends AbstractPolicy implements EmbeddedPolicyInterface {
const policyContentSizeAsBg = new Uint8Array(2);
policyContentSizeAsBg[0] = temp[1];
policyContentSizeAsBg[1] = temp[0];
buffer.set(policyContentSizeAsBg, 1);
target.set(policyContentSizeAsBg, 1);

// Write the policy content
buffer.set(this.content, policyContentSizeAsBg.length + 1);
target.set(this.content, policyContentSizeAsBg.length + 1);

// Write the binding.
buffer.set(this.binding, this.content.length + policyContentSizeAsBg.length + 1);
target.set(this.binding, this.content.length + policyContentSizeAsBg.length + 1);

return buffer;
return target;
}
}

Expand Down
Loading

0 comments on commit 8529461

Please sign in to comment.