Skip to content

Commit

Permalink
fix(agent): Check subnet canister ranges (#580)
Browse files Browse the repository at this point in the history
* Verify the canister subnet ranges for a certificate

* Don't check subnet ranges for reading management canister state

* Update usage of Certificate.verify in e2e test

* Fix how root keys are determined

* Change the expected error in the MITM test

Co-authored-by: Kyle Peacock <kylpeacock@gmail.com>
  • Loading branch information
oggy-dfin and krpeacock committed Jun 28, 2022
1 parent 6eb97f2 commit da5be58
Show file tree
Hide file tree
Showing 10 changed files with 332 additions and 110 deletions.
10 changes: 10 additions & 0 deletions docs/generated/changelog.html
Expand Up @@ -10,6 +10,16 @@
<h1>Agent-JS Changelog</h1>

<section>
<h2>Version 0.12.0</h2>
<ul>
<li>
Changed the certificate verification interface and fixed its logic. The public constructor
is now static and asynchronous. There is no separate verification method, the check is
done automatically in the constructor and newly also checks that the delegation is
authoritative for the given canister ID, as required by the Internet Computer interface
specification.
</li>
</ul>
<h2>Version 0.11.2</h2>
<ul>
<li>
Expand Down
13 changes: 8 additions & 5 deletions e2e/node/basic/basic.test.ts
Expand Up @@ -10,13 +10,16 @@ test('read_state', async () => {
const resolvedAgent = await agent;
const now = Date.now() / 1000;
const path = [new TextEncoder().encode('time')];
const response = await resolvedAgent.readState(Principal.fromHex('00000000000000000001'), {
const canisterId = Principal.fromHex('00000000000000000001');
const response = await resolvedAgent.readState(canisterId, {
paths: [path],
});
const cert = new Certificate(response, resolvedAgent);

expect(() => cert.lookup(path)).toThrow(/Cannot lookup unverified certificate/);
expect(await cert.verify()).toBe(true);
if (resolvedAgent.rootKey == null) throw new Error(`The agent doesn't have a root key yet`);
const cert = await Certificate.create({
certificate: response.certificate,
rootKey: resolvedAgent.rootKey,
canisterId: canisterId,
});
expect(cert.lookup([new TextEncoder().encode('Time')])).toBe(undefined);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const rawTime = cert.lookup(path)!;
Expand Down
2 changes: 1 addition & 1 deletion e2e/node/basic/mitm.test.ts
Expand Up @@ -11,6 +11,6 @@ if (!process.env['MITM']) {
jest.setTimeout(30000);
mitmTest('mitm greet', async () => {
const { actor: counter } = await counterCanister();
await expect(counter.greet('counter')).rejects.toThrow(/Fail to verify certificate/);
await expect(counter.greet('counter')).rejects.toThrow(/Invalid certificate/);
expect(await counter.queryGreet('counter')).toEqual('Hullo, counter!');
});
113 changes: 58 additions & 55 deletions package-lock.json

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

12 changes: 5 additions & 7 deletions packages/agent/src/canisterStatus/index.ts
Expand Up @@ -87,13 +87,11 @@ export const request = async (options: {
const response = await agent.readState(canisterId, {
paths: [encodedPaths[index]],
});
const cert = new Certificate(response, agent);
const verified = await cert.verify();
if (!verified) {
throw new Error(
'There was a problem certifying the response data. Please verify your connection to the mainnet, or be sure to call fetchRootKey on your agent if you are developing locally',
);
}
const cert = await Certificate.create({
certificate: response.certificate,
rootKey: agent.rootKey,
canisterId: canisterId,
});

const data = cert.lookup(encodePath(uniquePaths[index], canisterId));
if (!data) {
Expand Down

0 comments on commit da5be58

Please sign in to comment.