Skip to content

Commit

Permalink
Merge pull request #9 from chris-wood/caw/deterministic-key-config
Browse files Browse the repository at this point in the history
Add a deterministic KeyConfig variant
  • Loading branch information
chris-wood authored Jun 9, 2023
2 parents 5eff12c + 06fbffd commit bfd40a0
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 2 deletions.
19 changes: 19 additions & 0 deletions src/ohttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,25 @@ export class KeyConfig {
}
}

export class DeterministicKeyConfig extends KeyConfig {
constructor(keyId: number, ikm: Uint8Array) {
super(keyId);
if (keyId < 0 || keyId > 255) {
throw new InvalidConfigIdError(invalidKeyIdErrorString);
}
this.keyId = keyId;
this.kem = Kem.DhkemX25519HkdfSha256;
this.kdf = Kdf.HkdfSha256;
this.aead = Aead.Aes128Gcm;
const suite = new CipherSuite({
kem: this.kem,
kdf: this.kdf,
aead: this.aead,
});
this.keyPair = suite.deriveKeyPair(ikm);
}
}

export class PublicKeyConfig {
public keyId: number;
public kem: Kem;
Expand Down
69 changes: 67 additions & 2 deletions test/ohttp.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
import { assertEquals, assertStrictEquals } from "testing/asserts.ts";
import {
assertEquals,
assertNotEquals,
assertStrictEquals,
} from "testing/asserts.ts";
import { describe, it } from "testing/bdd.ts";

import { Client, ClientConstructor, KeyConfig, Server } from "../src/ohttp.ts";
import { loadCrypto } from "../src/webCrypto.ts";
import {
Client,
ClientConstructor,
DeterministicKeyConfig,
KeyConfig,
Server,
} from "../src/ohttp.ts";

async function randomBytes(l: number): Promise<Uint8Array> {
const buffer = new Uint8Array(l);
const cryptoApi = await loadCrypto();
cryptoApi.getRandomValues(buffer);
return buffer;
}

describe("test OHTTP end-to-end", () => {
it("Happy Path", async () => {
Expand Down Expand Up @@ -87,4 +105,51 @@ describe("test OHTTP end-to-end", () => {
const body = await finalResponse.arrayBuffer();
assertStrictEquals(new TextDecoder().decode(new Uint8Array(body)), "baz");
});

it("Happy Path with a deterministic KeyConfig", async () => {
const keyId = 0x01;
const seed = await randomBytes(32);

// Create a pair of servers with the same config and make sure they result in the same public key configuration
const keyConfig = new DeterministicKeyConfig(keyId, seed);
const server = new Server(keyConfig);
const sameConfig = new DeterministicKeyConfig(keyId, seed);
const sameServer = new Server(sameConfig);
const diffConfig = new KeyConfig(keyId);
const diffServer = new Server(diffConfig);

const configA = await server.encodeKeyConfig();
const configB = await sameServer.encodeKeyConfig();
const configC = await diffServer.encodeKeyConfig();
assertEquals(configA, configB);
assertNotEquals(configA, configC);

const publicKeyConfig = await keyConfig.publicConfig();

const requestUrl = "https://target.example/query?foo=bar";
const request = new Request(requestUrl);
const response = new Response("baz", {
headers: { "Content-Type": "text/plain" },
});

const client = new Client(publicKeyConfig);
const requestContext = await client.encapsulateRequest(request);
const clientRequest = requestContext.request;
const encodedClientRequest = clientRequest.encode();

const responseContext = await server.decodeAndDecapsulate(
encodedClientRequest,
);
const receivedRequest = responseContext.request();
assertStrictEquals(receivedRequest.url, "https://target.example/query");

const serverResponse = await responseContext.encapsulateResponse(response);

const finalResponse = await requestContext.decapsulateResponse(
serverResponse,
);
assertStrictEquals(finalResponse.headers.get("Content-Type"), "text/plain");
const body = await finalResponse.arrayBuffer();
assertStrictEquals(new TextDecoder().decode(new Uint8Array(body)), "baz");
});
});

0 comments on commit bfd40a0

Please sign in to comment.