Skip to content

Commit 17e0545

Browse files
committed
wip: completed cross signed claimNetworkAccess logic
1 parent 07292a1 commit 17e0545

File tree

4 files changed

+115
-58
lines changed

4 files changed

+115
-58
lines changed

src/claims/payloads/claimNetworkAccess.ts

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import type { Claim, SignedClaim } from '../types.js';
22
import type { NodeId, NodeIdEncoded } from '../../ids/types.js';
33
import type { SignedTokenEncoded } from '../../tokens/types.js';
4-
import type Token from '../../tokens/Token.js';
4+
import * as claimNetworkAuthorityUtils from './claimNetworkAuthority.js';
5+
import Token from '../../tokens/Token.js';
56
import * as tokensSchema from '../../tokens/schemas/index.js';
67
import * as ids from '../../ids/index.js';
78
import * as claimsUtils from '../utils.js';
89
import * as tokensUtils from '../../tokens/utils.js';
910
import * as validationErrors from '../../validation/errors.js';
1011
import * as utils from '../../utils/index.js';
12+
import * as nodesUtils from '../../nodes/utils.js';
13+
import * as keysUtils from '../../keys/utils/index.js';
1114

1215
/**
1316
* Asserts that a node is a part of a network
@@ -17,7 +20,7 @@ interface ClaimNetworkAccess extends Claim {
1720
iss: NodeIdEncoded;
1821
sub: NodeIdEncoded;
1922
network: string;
20-
signedClaimNetworkAuthorityEncoded?: SignedTokenEncoded;
23+
signedClaimNetworkAuthorityEncoded: SignedTokenEncoded;
2124
}
2225

2326
function assertClaimNetworkAccess(
@@ -87,12 +90,69 @@ function parseSignedClaimNetworkAccess(
8790

8891
function verifyClaimNetworkAccess(
8992
networkNodeId: NodeId,
90-
targetNodeId: NodeId,
93+
subjectNodeId: NodeId,
9194
network: string,
92-
token: Token<ClaimNetworkAccess>,
95+
tokenClaimNetworkAccess: Token<ClaimNetworkAccess>,
9396
): void {
9497
// TODO: complete
95-
console.log(token);
98+
// for the network authority claim.
99+
// 1. check network is correct
100+
// 2. issuer matches network public key
101+
// 3. subject matches the current node
102+
// 4. signed both by issuer and subject
103+
104+
const signedClaim =
105+
claimNetworkAuthorityUtils.parseSignedClaimNetworkAuthority(
106+
tokenClaimNetworkAccess.payload.signedClaimNetworkAuthorityEncoded,
107+
);
108+
const claimNetworkAuthority = Token.fromSigned(signedClaim);
109+
const issuerNodeId = nodesUtils.decodeNodeId(
110+
tokenClaimNetworkAccess.payload.iss,
111+
);
112+
if (issuerNodeId == null) throw Error('TMP IMP issuerNodeId is null');
113+
claimNetworkAuthorityUtils.verifyClaimNetworkAuthority(
114+
networkNodeId,
115+
issuerNodeId,
116+
network,
117+
claimNetworkAuthority,
118+
);
119+
// For the access claim
120+
// 1. issuer is current node
121+
// 2. subject is target node
122+
// 3. is signed by both the target and issuer
123+
124+
// Issuer should be the subject of the ClaimNetworkAuthority and signed by it
125+
const claimNetworkAuthoritySub = claimNetworkAuthority.payload.sub;
126+
const nodeIdIss = tokenClaimNetworkAccess.payload.iss;
127+
if (nodeIdIss !== claimNetworkAuthoritySub) {
128+
throw Error(
129+
'TMP IMP Issuer NodeIdEncoded does not match the expected network id',
130+
);
131+
}
132+
const networkPublicKey = keysUtils.publicKeyFromNodeId(issuerNodeId);
133+
if (!tokenClaimNetworkAccess.verifyWithPublicKey(networkPublicKey)) {
134+
throw Error('TMP IMP Token was not signed by the issuer node');
135+
}
136+
137+
// Subject should be the target node and signed by it
138+
const targetNodeIdEncoded = nodesUtils.encodeNodeId(subjectNodeId);
139+
const nodeIdSub = tokenClaimNetworkAccess.payload.sub;
140+
if (nodeIdSub !== targetNodeIdEncoded) {
141+
throw Error(
142+
'TMP IMP Subject NodeIdEncoded does not match the expected subject node',
143+
);
144+
}
145+
const targetPublicKey = keysUtils.publicKeyFromNodeId(subjectNodeId);
146+
147+
if (!tokenClaimNetworkAccess.verifyWithPublicKey(targetPublicKey)) {
148+
throw Error('TMP IMP Token was not signed by the subject node');
149+
}
150+
151+
// Checking if the network name matches
152+
const networkName = tokenClaimNetworkAccess.payload.network;
153+
if (networkName !== network) {
154+
throw Error('TMP IMP Network name does not match the expected network');
155+
}
96156
}
97157

98158
export {

src/claims/payloads/claimNetworkAuthority.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type { NodeId, NodeIdEncoded } from '../../ids/types.js';
33
import type Token from '../../tokens/Token.js';
44
import * as ids from '../../ids/index.js';
55
import * as claimsUtils from '../utils.js';
6-
import * as tokensUtils from '../../tokens/utils.js';
76
import * as validationErrors from '../../validation/errors.js';
87
import * as utils from '../../utils/index.js';
98
import * as nodesUtils from '../../nodes/utils.js';
@@ -66,7 +65,7 @@ function parseClaimNetworkAuthority(
6665
function parseSignedClaimNetworkAuthority(
6766
signedClaimNetworkNodeEncoded: unknown,
6867
): SignedClaim<ClaimNetworkAuthority> {
69-
const signedClaim = tokensUtils.parseSignedToken(
68+
const signedClaim = claimsUtils.parseSignedClaim(
7069
signedClaimNetworkNodeEncoded,
7170
);
7271
assertClaimNetworkAuthority(signedClaim.payload);

src/nodes/NodeManager.ts

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,12 +1586,11 @@ class NodeManager<Manifest extends AgentClientManifestNodeManager> {
15861586
);
15871587
}
15881588

1589-
// TODO: Steps:
1590-
// 1. validate claimNetworkAuthority
1591-
// 2. construct claim
1592-
// 3. In the signing hook make a call to the target node and hand it over for signing.
1593-
// 4. validate returned claim and return it in signing hook.
1594-
// 5. return new claim and id.
1589+
// 1. validate claimNetworkAuthority
1590+
// 2. construct claim
1591+
// 3. In the signing hook make a call to the target node and hand it over for signing.
1592+
// 4. validate returned claim and return it in signing hook.
1593+
// 5. return new claim and id.
15951594

15961595
// Validating that the ClaimNetworkAuthority is correct.
15971596
const networkNodeId = nodesUtils.decodeNodeId(
@@ -1608,11 +1607,12 @@ class NodeManager<Manifest extends AgentClientManifestNodeManager> {
16081607
const encodedNetworkAuthority = claimsUtils.generateSignedClaim(
16091608
claimNetworkAuthority.toSigned(),
16101609
);
1610+
const subjectNodeId = this.keyRing.getNodeId();
16111611
const [claimId, signedClaim] = await this.sigchain.addClaim(
16121612
{
16131613
typ: 'ClaimNetworkAccess',
16141614
iss: nodesUtils.encodeNodeId(targetNodeId),
1615-
sub: nodesUtils.encodeNodeId(this.keyRing.getNodeId()),
1615+
sub: nodesUtils.encodeNodeId(subjectNodeId),
16161616
network,
16171617
signedClaimNetworkAuthorityEncoded: encodedNetworkAuthority,
16181618
},
@@ -1627,7 +1627,7 @@ class NodeManager<Manifest extends AgentClientManifestNodeManager> {
16271627
const stream = await client.methods.nodesClaimNetworkSign();
16281628
const writer = stream.writable.getWriter();
16291629
const reader = stream.readable.getReader();
1630-
let fullySignedToken: Token<Claim>;
1630+
let fullySignedToken: Token<ClaimNetworkAccess>;
16311631
try {
16321632
await writer.write({
16331633
signedTokenEncoded: halfSignedClaimEncoded,
@@ -1639,41 +1639,41 @@ class NodeManager<Manifest extends AgentClientManifestNodeManager> {
16391639
}
16401640
const receivedClaim = readStatus.value;
16411641
// We need to re-construct the token from the message
1642-
const signedClaim = claimsUtils.parseSignedClaim(
1643-
receivedClaim.signedTokenEncoded,
1642+
const recivedClaimNetworkAccess =
1643+
claimNetworkAccessUtils.parseSignedClaimNetworkAccess(
1644+
receivedClaim.signedTokenEncoded,
1645+
);
1646+
fullySignedToken = Token.fromSigned(recivedClaimNetworkAccess);
1647+
claimNetworkAccessUtils.verifyClaimNetworkAccess(
1648+
networkNodeId,
1649+
subjectNodeId,
1650+
network,
1651+
fullySignedToken,
16441652
);
1645-
fullySignedToken = Token.fromSigned(signedClaim);
1646-
// Check that the signatures are correct
1647-
const targetNodePublicKey =
1648-
keysUtils.publicKeyFromNodeId(targetNodeId);
1649-
if (
1650-
!fullySignedToken.verifyWithPublicKey(
1651-
this.keyRing.keyPair.publicKey,
1652-
) ||
1653-
!fullySignedToken.verifyWithPublicKey(targetNodePublicKey)
1654-
) {
1655-
throw new claimsErrors.ErrorDoublySignedClaimVerificationFailed();
1656-
}
1657-
1658-
// TODO: Verify the claim's network authority is correct.
16591653

16601654
// Next stage is to process the claim for the other node
16611655
const readStatus2 = await reader.read();
16621656
if (readStatus2.done) {
16631657
throw new claimsErrors.ErrorEmptyStream();
16641658
}
16651659
const receivedClaimRemote = readStatus2.value;
1660+
16661661
// We need to re-construct the token from the message
1667-
const signedClaimRemote = claimsUtils.parseSignedClaim(
1668-
receivedClaimRemote.signedTokenEncoded,
1669-
);
1662+
const signedClaimRemote =
1663+
claimNetworkAccessUtils.parseSignedClaimNetworkAccess(
1664+
receivedClaimRemote.signedTokenEncoded,
1665+
);
16701666
// This is a singly signed claim,
16711667
// we want to verify it before signing and sending back
16721668
const signedTokenRemote = Token.fromSigned(signedClaimRemote);
1673-
if (!signedTokenRemote.verifyWithPublicKey(targetNodePublicKey)) {
1674-
throw new claimsErrors.ErrorSinglySignedClaimVerificationFailed();
1675-
}
16761669
signedTokenRemote.signWithPrivateKey(this.keyRing.keyPair);
1670+
// Verify everything is correct
1671+
claimNetworkAccessUtils.verifyClaimNetworkAccess(
1672+
networkNodeId,
1673+
subjectNodeId,
1674+
network,
1675+
signedTokenRemote,
1676+
);
16771677
// 4. X <- responds with double signing the X signed claim <- Y
16781678
const agentClaimedMessageRemote = claimsUtils.generateSignedClaim(
16791679
signedTokenRemote.toSigned(),
@@ -1692,14 +1692,14 @@ class NodeManager<Manifest extends AgentClientManifestNodeManager> {
16921692
throw e;
16931693
}
16941694
return fullySignedToken;
1695-
throw Error('TMP IMP not implemented.');
16961695
});
16971696
},
16981697
tran,
16991698
);
17001699
return [claimId, signedClaim as SignedClaim<ClaimNetworkAccess>];
17011700
}
17021701

1702+
// TODO: This needs to check the ACL to see if we should actually help create the claim.
17031703
public async *handleClaimNetwork(
17041704
requestingNodeId: NodeId,
17051705
input: AsyncIterableIterator<AgentRPCRequestParams<AgentClaimMessage>>,
@@ -1756,7 +1756,7 @@ class NodeManager<Manifest extends AgentClientManifestNodeManager> {
17561756
utils.promise<SignedTokenEncoded>();
17571757
const claimP = this.sigchain.addClaim(
17581758
{
1759-
typ: 'claimNetworkAccess',
1759+
typ: 'ClaimNetworkAccess',
17601760
iss: nodesUtils.encodeNodeId(this.keyRing.getNodeId()),
17611761
sub: nodesUtils.encodeNodeId(requestingNodeId),
17621762
network: this.claimNetworkAuthority.payload.network,

tests/nodes/NodeManager.test.ts

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -993,7 +993,10 @@ describe(`${NodeManager.name}`, () => {
993993
expect(await nodeGraphPeer.nodesTotal()).toBe(0);
994994
});
995995

996-
test('creating a claimNetworkAccess token', async () => {
996+
// TODO tests
997+
// 1. claiming a network should fail if issuer doesn't have a valid claimNetworkAuthority
998+
// 2. Claming a network should fail if issuer doesn't allow the requesting node access.
999+
test('creating a claimNetworkAccess token and verifying it', async () => {
9971000
const nodeIdTarget = keyRingPeer.getNodeId();
9981001
await nodeGraph.setNodeContactAddressData(
9991002
nodeIdTarget,
@@ -1030,24 +1033,19 @@ describe(`${NodeManager.name}`, () => {
10301033
return claim;
10311034
},
10321035
);
1033-
try {
1034-
const result = await nodeManager.claimNetwork(
1035-
nodeIdTarget,
1036-
network,
1037-
Token.fromSigned(claimNetworkAuthority),
1038-
);
1039-
const [, signedClaim] = result;
1040-
const token = Token.fromSigned(signedClaim);
1041-
claimNetworkAccessUtils.verifyClaimNetworkAccess(
1042-
networkNodeId,
1043-
keyRingPeer.getNodeId(),
1044-
network,
1045-
token,
1046-
);
1047-
} catch (e) {
1048-
console.error(e);
1049-
throw e;
1050-
}
1036+
const result = await nodeManager.claimNetwork(
1037+
nodeIdTarget,
1038+
network,
1039+
Token.fromSigned(claimNetworkAuthority),
1040+
);
1041+
const [, signedClaim] = result;
1042+
const token = Token.fromSigned(signedClaim);
1043+
claimNetworkAccessUtils.verifyClaimNetworkAccess(
1044+
networkNodeId,
1045+
keyRing.getNodeId(),
1046+
network,
1047+
token,
1048+
);
10511049
});
10521050
});
10531051
describe('with 1 peer and mdns', () => {

0 commit comments

Comments
 (0)