Skip to content

Commit 9d1ea8e

Browse files
handle rewrap response
1 parent f8a0ab9 commit 9d1ea8e

File tree

3 files changed

+67
-50
lines changed

3 files changed

+67
-50
lines changed

.github/workflows/format.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: '🤖 🎨'
2-
on:
3-
pull_request:
2+
# on:
3+
# pull_request:
44
jobs:
55
format:
66
runs-on: ubuntu-latest

lib/src/nanotdf/Client.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,24 @@ export default class Client {
300300
this.fulfillableObligationFQNs
301301
);
302302

303+
// Assume only one response and one result for now (V1 style)
304+
const result = rewrapResp.responses[0].results[0];
305+
let entityWrappedKey: Uint8Array<ArrayBufferLike>;
306+
switch (result.result.case) {
307+
case 'kasWrappedKey': {
308+
entityWrappedKey = result.result.value;
309+
break;
310+
}
311+
case 'error': {
312+
const errorMessage = result.result.value;
313+
throw new DecryptError(`KAS rewrap failed: ${errorMessage}`);
314+
}
315+
default: {
316+
throw new DecryptError('KAS rewrap response missing wrapped key');
317+
}
318+
}
319+
303320
// Extract the iv and ciphertext
304-
const entityWrappedKey = rewrapResp.entityWrappedKey;
305321
const ivLength =
306322
clientVersion == Client.SDK_INITIAL_RELEASE ? Client.INITIAL_RELEASE_IV_SIZE : Client.IV_SIZE;
307323
const iv = entityWrappedKey.subarray(0, ivLength);

lib/tdf3/src/tdf.ts

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,6 @@ export type RewrapRequest = {
197197

198198
export type KasPublicKeyFormat = 'pkcs8' | 'jwks';
199199

200-
export type RewrapResponse = {
201-
entityWrappedKey: string;
202-
sessionPublicKey: string;
203-
};
204-
205200
/**
206201
* If we have KAS url but not public key we can fetch it from KAS, fetching
207202
* the value from `${kas}/kas_public_key`.
@@ -791,19 +786,7 @@ async function unwrapKey({
791786

792787
const clientPublicKey = ephemeralEncryptionKeys.publicKey;
793788

794-
// TODO: how to handle defaults here?
795789
// Convert keySplitInfo to protobuf KeyAccess
796-
// const keyAccessProto = create(KeyAccessSchema, {
797-
// keyType: keySplitInfo.type || '',
798-
// kasUrl: keySplitInfo.url || '',
799-
// protocol: keySplitInfo.protocol || '',
800-
// wrappedKey: keySplitInfo.wrappedKey ? new Uint8Array(base64.decodeArrayBuffer(keySplitInfo.wrappedKey)) : new Uint8Array(),
801-
// policyBinding: keySplitInfo.policyBinding,
802-
// kid: keySplitInfo.kid || '',
803-
// splitId: keySplitInfo.sid || '',
804-
// encryptedMetadata: keySplitInfo.encryptedMetadata || '',
805-
// });
806-
807790
const keyAccessProto = create(KeyAccessSchema, {
808791
...(keySplitInfo.type && { keyType: keySplitInfo.type }),
809792
...(keySplitInfo.url && { kasUrl: keySplitInfo.url }),
@@ -847,39 +830,57 @@ async function unwrapKey({
847830
authProvider,
848831
fulfillableObligations
849832
);
850-
const { entityWrappedKey, metadata, sessionPublicKey } = rewrapResp;
833+
const { sessionPublicKey } = rewrapResp;
851834
const requiredObligations = getRequiredObligationFQNs(rewrapResp);
835+
// Assume only one response and one result for now (V1 style)
836+
const result = rewrapResp.responses[0].results[0];
837+
const metadata = result.metadata;
838+
// Handle the different cases of result.result
839+
switch (result.result.case) {
840+
case "kasWrappedKey": {
841+
const entityWrappedKey = result.result.value;
842+
843+
if (wrappingKeyAlgorithm === 'ec:secp256r1') {
844+
const serverEphemeralKey: CryptoKey = await pemPublicToCrypto(sessionPublicKey);
845+
const ekr = ephemeralEncryptionKeysRaw as CryptoKeyPair;
846+
const kek = await keyAgreement(ekr.privateKey, serverEphemeralKey, {
847+
hkdfSalt: await ztdfSalt,
848+
hkdfHash: 'SHA-256',
849+
});
850+
const wrappedKeyAndNonce = entityWrappedKey;
851+
const iv = wrappedKeyAndNonce.slice(0, 12);
852+
const wrappedKey = wrappedKeyAndNonce.slice(12);
852853

853-
if (wrappingKeyAlgorithm === 'ec:secp256r1') {
854-
const serverEphemeralKey: CryptoKey = await pemPublicToCrypto(sessionPublicKey);
855-
const ekr = ephemeralEncryptionKeysRaw as CryptoKeyPair;
856-
const kek = await keyAgreement(ekr.privateKey, serverEphemeralKey, {
857-
hkdfSalt: await ztdfSalt,
858-
hkdfHash: 'SHA-256',
859-
});
860-
const wrappedKeyAndNonce = entityWrappedKey;
861-
const iv = wrappedKeyAndNonce.slice(0, 12);
862-
const wrappedKey = wrappedKeyAndNonce.slice(12);
863-
864-
const dek = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, kek, wrappedKey);
865-
866-
return {
867-
key: new Uint8Array(dek),
868-
metadata,
869-
requiredObligations,
870-
};
871-
}
872-
const key = Binary.fromArrayBuffer(entityWrappedKey);
873-
const decryptedKeyBinary = await cryptoService.decryptWithPrivateKey(
874-
key,
875-
ephemeralEncryptionKeys.privateKey
876-
);
854+
const dek = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, kek, wrappedKey);
877855

878-
return {
879-
key: new Uint8Array(decryptedKeyBinary.asByteArray()),
880-
metadata,
881-
requiredObligations,
882-
};
856+
return {
857+
key: new Uint8Array(dek),
858+
metadata,
859+
requiredObligations,
860+
};
861+
}
862+
const key = Binary.fromArrayBuffer(entityWrappedKey);
863+
const decryptedKeyBinary = await cryptoService.decryptWithPrivateKey(
864+
key,
865+
ephemeralEncryptionKeys.privateKey
866+
);
867+
868+
return {
869+
key: new Uint8Array(decryptedKeyBinary.asByteArray()),
870+
metadata,
871+
requiredObligations,
872+
};
873+
}
874+
875+
case "error": {
876+
const errorMessage = result.result.value;
877+
throw new DecryptError(`KAS rewrap failed: ${errorMessage}`);
878+
}
879+
880+
default: {
881+
throw new DecryptError('KAS rewrap response missing wrapped key');
882+
}
883+
}
883884
}
884885

885886
let poolSize = 1;

0 commit comments

Comments
 (0)