Skip to content

Commit 81a2885

Browse files
passing unit tests
1 parent 25839b8 commit 81a2885

File tree

2 files changed

+83
-39
lines changed

2 files changed

+83
-39
lines changed

lib/tdf3/src/tdf.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,7 @@ async function unwrapKey({
798798
...(keySplitInfo.kid && { kid: keySplitInfo.kid }),
799799
...(keySplitInfo.sid && { splitId: keySplitInfo.sid }),
800800
...(keySplitInfo.encryptedMetadata && { encryptedMetadata: keySplitInfo.encryptedMetadata }),
801+
...(keySplitInfo.ephemeralPublicKey && { ephemeralPublicKey: keySplitInfo.ephemeralPublicKey }),
801802
});
802803

803804
// Create the protobuf request
@@ -811,9 +812,11 @@ async function unwrapKey({
811812
keyAccessObject: keyAccessProto,
812813
}),
813814
],
814-
policy: create(UnsignedRewrapRequest_WithPolicySchema, {
815-
id: 'policy',
816-
body: manifest.encryptionInformation.policy,
815+
...(manifest.encryptionInformation.policy && {
816+
policy: create(UnsignedRewrapRequest_WithPolicySchema, {
817+
id: 'policy',
818+
body: manifest.encryptionInformation.policy,
819+
}),
817820
}),
818821
}),
819822
],

lib/tests/server.ts

Lines changed: 77 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,19 @@ import { keyAgreement, pemPublicToCrypto } from '../src/nanotdf-crypto/index.js'
99
import { generateRandomNumber } from '../src/nanotdf-crypto/generateRandomNumber.js';
1010
import { removePemFormatting } from '../tdf3/src/crypto/crypto-utils.js';
1111
import { Binary } from '../tdf3/index.js';
12-
import { type KeyAccessObject } from '../tdf3/src/models/index.js';
1312
import { valueFor } from './web/policy/mock-attrs.js';
1413
import { AttributeAndValue } from '../src/policy/attributes.js';
1514
import { ztdfSalt } from '../tdf3/src/crypto/salt.js';
1615

16+
import { create, toJsonString, fromJson } from '@bufbuild/protobuf';
17+
import { ValueSchema } from "@bufbuild/protobuf/wkt";
18+
import {
19+
PolicyRewrapResultSchema,
20+
KeyAccessRewrapResultSchema,
21+
RewrapResponseSchema,
22+
UnsignedRewrapRequestSchema
23+
} from '../src/platform/kas/kas_pb.js';
24+
1725
const Mocks = getMocks();
1826

1927
function range(start: number, end: number): Uint8Array {
@@ -24,18 +32,6 @@ function range(start: number, end: number): Uint8Array {
2432
return new Uint8Array(result);
2533
}
2634

27-
type RewrapBody = {
28-
algorithm: 'RS256' | 'ec:secp256r1';
29-
keyAccess: KeyAccessObject & {
30-
header?: string;
31-
};
32-
policy: string;
33-
clientPublicKey: string;
34-
// testing only
35-
invalidKey: string;
36-
invalidField: string;
37-
};
38-
3935
function concat(b: ArrayBufferView[]) {
4036
const length = b.reduce((lk, ak) => lk + ak.byteLength, 0);
4137
const buf = new Uint8Array(length);
@@ -164,33 +160,34 @@ const kas: RequestListener = async (req, res) => {
164160
return;
165161
}
166162

167-
const rewrap = JSON.parse(requestBody as string) as RewrapBody;
163+
const rewrap = fromJson(UnsignedRewrapRequestSchema, JSON.parse(requestBody as string));
168164
console.log('[INFO]: rewrap request body: ', rewrap);
169165
const clientPublicKey = await pemPublicToCrypto(rewrap.clientPublicKey);
170166
if (!clientPublicKey || clientPublicKey.type !== 'public') {
171167
res.writeHead(400);
172168
res.end('{"error": "Invalid client public key"}');
173169
return;
174170
}
175-
const isZTDF = !rewrap.keyAccess.header;
171+
const kaoheader = rewrap.requests?.[0]?.keyAccessObjects?.[0]?.keyAccessObject?.header;
172+
const isZTDF = !kaoheader || kaoheader.length === 0;
176173
if (isZTDF) {
177-
if (!rewrap.keyAccess.wrappedKey) {
174+
const wk = rewrap.requests?.[0]?.keyAccessObjects?.[0]?.keyAccessObject?.wrappedKey;
175+
if (!wk || wk.length === 0) {
178176
res.writeHead(400);
179177
res.end('{"error": "Invalid wrapped key"}');
180178
return;
181179
}
182-
const wk = base64.decodeArrayBuffer(rewrap.keyAccess.wrappedKey);
183-
const isECWrapped = rewrap.keyAccess.kid == 'e1';
180+
const isECWrapped = rewrap.requests?.[0]?.keyAccessObjects?.[0]?.keyAccessObject?.kid == 'e1';
184181
// Decrypt the wrapped key from TDF3
185182
let dek: Binary;
186183
if (isECWrapped) {
187-
if (!rewrap.keyAccess.ephemeralPublicKey) {
184+
if (!rewrap.requests?.[0]?.keyAccessObjects?.[0]?.keyAccessObject?.ephemeralPublicKey) {
188185
res.writeHead(400);
189186
res.end('{"error": "Nil ephemeral public key"}');
190187
return;
191188
}
192189
const ephemeralKey: CryptoKey = await pemPublicToCrypto(
193-
rewrap.keyAccess.ephemeralPublicKey
190+
rewrap.requests?.[0]?.keyAccessObjects?.[0]?.keyAccessObject?.ephemeralPublicKey
194191
);
195192
const kasPrivateKeyBytes = base64.decodeArrayBuffer(
196193
removePemFormatting(Mocks.kasECPrivateKey)
@@ -215,13 +212,27 @@ const kas: RequestListener = async (req, res) => {
215212
}
216213
if (clientPublicKey.algorithm.name == 'RSA-OAEP') {
217214
const cek = await encryptWithPublicKey(dek, rewrap.clientPublicKey);
218-
const reply = {
219-
entityWrappedKey: base64.encodeArrayBuffer(cek.asArrayBuffer()),
220-
metadata: { hello: 'world' },
221-
};
215+
const reply = create(RewrapResponseSchema, {
216+
responses: [
217+
create(PolicyRewrapResultSchema, {
218+
results: [
219+
create(KeyAccessRewrapResultSchema, {
220+
metadata: {"hello": create(ValueSchema, {
221+
kind: { case: "stringValue", value: "world" }
222+
})},
223+
result: {
224+
case: "kasWrappedKey",
225+
value: new Uint8Array(cek.asArrayBuffer()),
226+
},
227+
keyAccessObjectId: rewrap.requests?.[0]?.keyAccessObjects?.[0]?.keyAccessObjectId || '',
228+
}),
229+
],
230+
}),
231+
],
232+
})
222233
res.statusCode = 200;
223234
res.setHeader('Content-Type', 'application/json');
224-
res.end(JSON.stringify(reply));
235+
res.end(toJsonString(RewrapResponseSchema, reply));
225236
return;
226237
}
227238
const sessionKeyPair = await crypto.subtle.generateKey(
@@ -241,19 +252,34 @@ const kas: RequestListener = async (req, res) => {
241252
const entityWrappedKey = new Uint8Array(iv.length + cek.byteLength);
242253
entityWrappedKey.set(iv);
243254
entityWrappedKey.set(new Uint8Array(cek), iv.length);
244-
const reply = {
245-
entityWrappedKey: base64.encodeArrayBuffer(entityWrappedKey),
246-
metadata: { hello: 'world' },
247-
};
255+
const reply = create(RewrapResponseSchema, {
256+
responses: [
257+
create(PolicyRewrapResultSchema, {
258+
results: [
259+
create(KeyAccessRewrapResultSchema, {
260+
metadata: {"hello": create(ValueSchema, {
261+
kind: { case: "stringValue", value: "world" }
262+
})},
263+
result: {
264+
case: "kasWrappedKey",
265+
value: entityWrappedKey,
266+
},
267+
keyAccessObjectId: rewrap.requests?.[0]?.keyAccessObjects?.[0]?.keyAccessObjectId || '',
268+
}),
269+
],
270+
}),
271+
],
272+
})
273+
248274
res.statusCode = 200;
249275
res.setHeader('Content-Type', 'application/json');
250-
res.end(JSON.stringify(reply));
276+
res.end(toJsonString(RewrapResponseSchema, reply));
251277
return;
252278
}
253279
// nanotdf
254280
console.log('[INFO] nano rewrap request body: ', rewrap);
255281
const { header } = Header.parse(
256-
new Uint8Array(base64.decodeArrayBuffer(rewrap?.keyAccess?.header || ''))
282+
kaoheader || new Uint8Array(base64.decodeArrayBuffer('')),
257283
);
258284
// TODO convert header.ephemeralCurveName to namedCurve
259285
const nanoPublicKey = await crypto.subtle.importKey(
@@ -309,14 +335,29 @@ const kas: RequestListener = async (req, res) => {
309335
const entityWrappedKey = new Uint8Array(iv.length + cekBytes.length);
310336
entityWrappedKey.set(iv);
311337
entityWrappedKey.set(cekBytes, iv.length);
312-
const reply = {
313-
entityWrappedKey: base64.encodeArrayBuffer(entityWrappedKey),
338+
const reply = create(RewrapResponseSchema, {
314339
sessionPublicKey: Mocks.kasECCert,
315-
metadata: { hello: 'people of earth' },
316-
};
340+
responses: [
341+
create(PolicyRewrapResultSchema, {
342+
results: [
343+
create(KeyAccessRewrapResultSchema, {
344+
metadata: {"hello": create(ValueSchema, {
345+
kind: { case: "stringValue", value: "people of earth" }
346+
})},
347+
result: {
348+
case: "kasWrappedKey",
349+
value: entityWrappedKey,
350+
},
351+
keyAccessObjectId: rewrap.requests?.[0]?.keyAccessObjects?.[0]?.keyAccessObjectId || '',
352+
}),
353+
],
354+
}),
355+
],
356+
});
357+
317358
res.statusCode = 200;
318359
res.setHeader('Content-Type', 'application/json');
319-
res.end(JSON.stringify(reply));
360+
res.end(toJsonString(RewrapResponseSchema, reply));
320361
return;
321362
} else if (url.pathname === '/file') {
322363
if (req.method !== 'GET') {

0 commit comments

Comments
 (0)