Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): Adds kao.schemaVersion #416

Merged
merged 2 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion lib/tdf3/src/models/key-access.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { Policy } from './policy.js';

export type KeyAccessType = 'remote' | 'wrapped';

export const schemaVersion = '1.0';

export function isRemote(keyAccessJSON: KeyAccess | KeyAccessObject): boolean {
return keyAccessJSON.type === 'remote';
}
Expand Down Expand Up @@ -48,6 +50,7 @@ export class Wrapped {
alg: 'HS256',
hash: base64.encode(policyBinding),
},
schemaVersion,
};
if (this.kid) {
this.keyAccessObject.kid = this.kid;
Expand All @@ -62,16 +65,69 @@ export class Wrapped {

export type KeyAccess = Wrapped;

/**
* A KeyAccess object stores all information about how an object key OR one key split is stored.
*/
export type KeyAccessObject = {
sid?: string;
/**
* Specifies how the key is stored. Possible Values:
* **wrapped**: The wrapped key is stored as part of the manifest.
* **remote**: [Unsupported] The wrapped key (see below) is stored remotely and is thus not part of the final TDF manifest.
*/
type: KeyAccessType;

/**
* A key split (or share) identifier.
* To allow sharing a key across several access domains,
* the KAO supports a 'Split Identifier'.
* To reconstruct such a key when encryptionInformation type is 'split',
* use the xor operation to combine one of each separate sid.
*/
sid?: string;

/**
* A locator for a Key Access service capable of granting access to the wrapped key.
*/
url: string;

/**
* Additional information for the Key Access service to identify how to unwrap the key.
*/
kid?: string;

/**
* The protocol used to access the key.
*/
protocol: 'kas';

/**
* The symmetric key used to encrypt the payload.
* It is encrypted using the public key of the KAS,
* then base64 encoded.
*/
wrappedKey?: string;

/**
* An object that contains a keyed hash that will provide cryptographic integrity on the policy object,
* such that it cannot be modified or copied to another TDF
* without invalidating the binding.
* Specifically, you would have to have access to the key in order to overwrite the policy.
*/
policyBinding?: {
alg: string;
hash: string;
};

/**
* Metadata associated with the TDF and the request.
* The contents of the metadata are freeform,
* and are used to pass information from the client to the KAS.
* The metadata stored here should not be used for primary access decisions.
*/
encryptedMetadata?: string;

/**
* Version information for the KAO format.
*/
schemaVersion?: string;
};
9 changes: 8 additions & 1 deletion lib/tests/web/roundtrip.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,14 @@ describe('Local roundtrip Tests', () => {
source: { type: 'chunker', location: fromString('hello world') },
});
const cipherManifest = await cipherTextStream.manifest;
expect(cipherManifest?.encryptionInformation?.keyAccess[0]?.url).to.equal(kasEndpoint);
const kao = cipherManifest?.encryptionInformation?.keyAccess[0];
expect(kao).to.contain({
url: kasEndpoint,
kid: 'r1',
type: 'wrapped',
protocol: 'kas',
schemaVersion: '1.0',
});
const cipherTextArray = new Uint8Array(await new Response(cipherTextStream).arrayBuffer());

const nanotdfParsed = await client.read({
Expand Down
Loading