@matter/protocol 0.16.0-alpha.0-20250909-aecad94f3 → 0.16.0-alpha.0-20250912-0d12bf718
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/interaction/InteractionClient.d.ts +3 -4
- package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionClient.js +3 -4
- package/dist/cjs/interaction/InteractionClient.js.map +1 -1
- package/dist/cjs/peer/PeerSet.d.ts +10 -3
- package/dist/cjs/peer/PeerSet.d.ts.map +1 -1
- package/dist/cjs/peer/PeerSet.js +32 -28
- package/dist/cjs/peer/PeerSet.js.map +1 -1
- package/dist/cjs/session/case/CaseClient.d.ts +8 -2
- package/dist/cjs/session/case/CaseClient.d.ts.map +1 -1
- package/dist/cjs/session/case/CaseClient.js +9 -8
- package/dist/cjs/session/case/CaseClient.js.map +2 -2
- package/dist/esm/interaction/InteractionClient.d.ts +3 -4
- package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionClient.js +3 -4
- package/dist/esm/interaction/InteractionClient.js.map +1 -1
- package/dist/esm/peer/PeerSet.d.ts +10 -3
- package/dist/esm/peer/PeerSet.d.ts.map +1 -1
- package/dist/esm/peer/PeerSet.js +32 -28
- package/dist/esm/peer/PeerSet.js.map +1 -1
- package/dist/esm/session/case/CaseClient.d.ts +8 -2
- package/dist/esm/session/case/CaseClient.d.ts.map +1 -1
- package/dist/esm/session/case/CaseClient.js +9 -8
- package/dist/esm/session/case/CaseClient.js.map +2 -2
- package/package.json +6 -6
- package/src/interaction/InteractionClient.ts +5 -7
- package/src/peer/PeerSet.ts +41 -30
- package/src/session/case/CaseClient.ts +22 -7
|
@@ -30,10 +30,11 @@ class CaseClient {
|
|
|
30
30
|
constructor(sessions) {
|
|
31
31
|
this.#sessions = sessions;
|
|
32
32
|
}
|
|
33
|
-
async pair(exchange, fabric, peerNodeId,
|
|
33
|
+
async pair(exchange, fabric, peerNodeId, options) {
|
|
34
|
+
const { expectedProcessingTime, caseAuthenticatedTags } = options ?? {};
|
|
34
35
|
const messenger = new CaseClientMessenger(exchange, expectedProcessingTime);
|
|
35
36
|
try {
|
|
36
|
-
return await this.#doPair(messenger, exchange, fabric, peerNodeId);
|
|
37
|
+
return await this.#doPair(messenger, exchange, fabric, peerNodeId, caseAuthenticatedTags);
|
|
37
38
|
} catch (error) {
|
|
38
39
|
if (!(error instanceof ChannelStatusResponseError || error instanceof RetransmissionLimitReachedError)) {
|
|
39
40
|
await messenger.sendError(SecureChannelStatusCode.InvalidParam);
|
|
@@ -41,7 +42,7 @@ class CaseClient {
|
|
|
41
42
|
throw error;
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
|
-
async #doPair(messenger, exchange, fabric, peerNodeId) {
|
|
45
|
+
async #doPair(messenger, exchange, fabric, peerNodeId, caseAuthenticatedTags) {
|
|
45
46
|
const { crypto } = fabric;
|
|
46
47
|
const initiatorRandom = crypto.randomBytes(32);
|
|
47
48
|
const initiatorSessionId = await this.#sessions.getNextAvailableSessionId();
|
|
@@ -84,7 +85,7 @@ class CaseClient {
|
|
|
84
85
|
sharedSecret,
|
|
85
86
|
fabric: fabric2,
|
|
86
87
|
sessionParameters: resumptionSessionParams,
|
|
87
|
-
caseAuthenticatedTags
|
|
88
|
+
caseAuthenticatedTags: caseAuthenticatedTags2
|
|
88
89
|
} = resumptionRecord;
|
|
89
90
|
const { responderSessionId: peerSessionId, resumptionId, resumeMic } = sigma2Resume;
|
|
90
91
|
const sessionParameters = {
|
|
@@ -105,7 +106,7 @@ class CaseClient {
|
|
|
105
106
|
isInitiator: true,
|
|
106
107
|
isResumption: true,
|
|
107
108
|
peerSessionParameters: sessionParameters,
|
|
108
|
-
caseAuthenticatedTags
|
|
109
|
+
caseAuthenticatedTags: caseAuthenticatedTags2
|
|
109
110
|
});
|
|
110
111
|
await messenger.sendSuccess();
|
|
111
112
|
this.#logNewSession("Resumed", secureSession, messenger, fabric2, peerNodeId);
|
|
@@ -191,7 +192,7 @@ class CaseClient {
|
|
|
191
192
|
const encrypted = crypto.encrypt(sigma3Key, encryptedData, TBE_DATA3_NONCE);
|
|
192
193
|
const sigma3Bytes = await messenger.sendSigma3({ encrypted });
|
|
193
194
|
await messenger.waitForSuccess("Sigma3-Success");
|
|
194
|
-
const
|
|
195
|
+
const sessionCaseAuthenticatedTags = caseAuthenticatedTags ?? resumptionRecord?.caseAuthenticatedTags;
|
|
195
196
|
const secureSessionSalt = Bytes.concat(
|
|
196
197
|
operationalIdentityProtectionKey,
|
|
197
198
|
await crypto.computeSha256([sigma1Bytes, sigma2Bytes, sigma3Bytes])
|
|
@@ -206,7 +207,7 @@ class CaseClient {
|
|
|
206
207
|
isInitiator: true,
|
|
207
208
|
isResumption: false,
|
|
208
209
|
peerSessionParameters,
|
|
209
|
-
caseAuthenticatedTags
|
|
210
|
+
caseAuthenticatedTags: sessionCaseAuthenticatedTags
|
|
210
211
|
});
|
|
211
212
|
this.#logNewSession("New", secureSession, messenger, fabric, peerNodeId);
|
|
212
213
|
resumptionRecord = {
|
|
@@ -215,7 +216,7 @@ class CaseClient {
|
|
|
215
216
|
sharedSecret,
|
|
216
217
|
resumptionId: peerResumptionId,
|
|
217
218
|
sessionParameters: secureSession.parameters,
|
|
218
|
-
caseAuthenticatedTags
|
|
219
|
+
caseAuthenticatedTags: sessionCaseAuthenticatedTags
|
|
219
220
|
};
|
|
220
221
|
}
|
|
221
222
|
await messenger.close();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/session/case/CaseClient.ts"],
|
|
4
|
-
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,YAAY;AACrB,SAAS,WAAW;AAEpB,SAAS,OAAO,YAAsB,QAAQ,WAAW,2BAA2B;AACpF,SAAS,mBAAmB;AAC5B,SAA0B,uCAAuC;AACjE,SAAS,kCAAkC;AAG3C,
|
|
5
|
-
"names": ["fabric"]
|
|
4
|
+
"mappings": "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",
|
|
5
|
+
"names": ["fabric", "caseAuthenticatedTags"]
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matter/protocol",
|
|
3
|
-
"version": "0.16.0-alpha.0-
|
|
3
|
+
"version": "0.16.0-alpha.0-20250912-0d12bf718",
|
|
4
4
|
"description": "Low-level APIs for Matter interaction",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"iot",
|
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
"#*": "./src/*"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@matter/general": "0.16.0-alpha.0-
|
|
44
|
-
"@matter/model": "0.16.0-alpha.0-
|
|
45
|
-
"@matter/types": "0.16.0-alpha.0-
|
|
43
|
+
"@matter/general": "0.16.0-alpha.0-20250912-0d12bf718",
|
|
44
|
+
"@matter/model": "0.16.0-alpha.0-20250912-0d12bf718",
|
|
45
|
+
"@matter/types": "0.16.0-alpha.0-20250912-0d12bf718"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@matter/tools": "0.16.0-alpha.0-
|
|
49
|
-
"@matter/testing": "0.16.0-alpha.0-
|
|
48
|
+
"@matter/tools": "0.16.0-alpha.0-20250912-0d12bf718",
|
|
49
|
+
"@matter/testing": "0.16.0-alpha.0-20250912-0d12bf718"
|
|
50
50
|
},
|
|
51
51
|
"files": [
|
|
52
52
|
"dist/**/*",
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
import { Specification } from "#model";
|
|
24
24
|
import { PeerAddress, PeerAddressMap } from "#peer/PeerAddress.js";
|
|
25
25
|
import { PeerDataStore } from "#peer/PeerAddressStore.js";
|
|
26
|
-
import {
|
|
26
|
+
import { PeerConnectionOptions, PeerSet } from "#peer/PeerSet.js";
|
|
27
27
|
import {
|
|
28
28
|
ArraySchema,
|
|
29
29
|
Attribute,
|
|
@@ -107,16 +107,14 @@ export class InteractionClientProvider {
|
|
|
107
107
|
|
|
108
108
|
async connect(
|
|
109
109
|
address: PeerAddress,
|
|
110
|
-
options: {
|
|
111
|
-
discoveryOptions: DiscoveryOptions;
|
|
110
|
+
options: PeerConnectionOptions & {
|
|
112
111
|
allowUnknownPeer?: boolean;
|
|
113
112
|
operationalAddress?: ServerAddressIp;
|
|
114
113
|
},
|
|
115
114
|
): Promise<InteractionClient> {
|
|
116
115
|
await this.#peers.ensureConnection(address, options);
|
|
117
116
|
|
|
118
|
-
|
|
119
|
-
return this.getInteractionClient(address, discoveryOptions);
|
|
117
|
+
return this.getInteractionClient(address, options);
|
|
120
118
|
}
|
|
121
119
|
|
|
122
120
|
async getInteractionClientForChannel(channel: MessageChannel): Promise<InteractionClient> {
|
|
@@ -130,7 +128,7 @@ export class InteractionClientProvider {
|
|
|
130
128
|
);
|
|
131
129
|
}
|
|
132
130
|
|
|
133
|
-
async getInteractionClient(address: PeerAddress,
|
|
131
|
+
async getInteractionClient(address: PeerAddress, options: PeerConnectionOptions = {}) {
|
|
134
132
|
let client = this.#clients.get(address);
|
|
135
133
|
if (client !== undefined) {
|
|
136
134
|
return client;
|
|
@@ -140,7 +138,7 @@ export class InteractionClientProvider {
|
|
|
140
138
|
const nodeStore = isGroupAddress ? undefined : this.#peers.get(address)?.dataStore;
|
|
141
139
|
await nodeStore?.construction; // Lazy initialize the data if not already done
|
|
142
140
|
|
|
143
|
-
const exchangeProvider = await this.#peers.exchangeProviderFor(address,
|
|
141
|
+
const exchangeProvider = await this.#peers.exchangeProviderFor(address, options);
|
|
144
142
|
|
|
145
143
|
client = new InteractionClient(
|
|
146
144
|
exchangeProvider,
|
package/src/peer/PeerSet.ts
CHANGED
|
@@ -45,7 +45,7 @@ import { CaseClient } from "#session/case/CaseClient.js";
|
|
|
45
45
|
import { SecureSession } from "#session/SecureSession.js";
|
|
46
46
|
import { Session } from "#session/Session.js";
|
|
47
47
|
import { SessionManager } from "#session/SessionManager.js";
|
|
48
|
-
import { GroupId, NodeId, SECURE_CHANNEL_PROTOCOL_ID, SecureChannelStatusCode } from "#types";
|
|
48
|
+
import { CaseAuthenticatedTag, GroupId, NodeId, SECURE_CHANNEL_PROTOCOL_ID, SecureChannelStatusCode } from "#types";
|
|
49
49
|
import { ControllerDiscovery, DiscoveryError, PairRetransmissionLimitReachedError } from "./ControllerDiscovery.js";
|
|
50
50
|
import { InteractionQueue } from "./InteractionQueue.js";
|
|
51
51
|
import { OperationalPeer } from "./OperationalPeer.js";
|
|
@@ -85,6 +85,14 @@ export interface DiscoveryOptions {
|
|
|
85
85
|
discoveryData?: DiscoveryData;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Extended discovery options that include case authenticated tags for peer connections.
|
|
90
|
+
*/
|
|
91
|
+
export interface PeerConnectionOptions {
|
|
92
|
+
discoveryOptions?: DiscoveryOptions;
|
|
93
|
+
caseAuthenticatedTags?: CaseAuthenticatedTag[];
|
|
94
|
+
}
|
|
95
|
+
|
|
88
96
|
interface RunningDiscovery {
|
|
89
97
|
type: NodeDiscoveryType;
|
|
90
98
|
promises?: (() => Promise<MessageChannel>)[];
|
|
@@ -247,8 +255,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
247
255
|
*/
|
|
248
256
|
async ensureConnection(
|
|
249
257
|
address: PeerAddress,
|
|
250
|
-
options: {
|
|
251
|
-
discoveryOptions: DiscoveryOptions;
|
|
258
|
+
options: PeerConnectionOptions & {
|
|
252
259
|
allowUnknownPeer?: boolean;
|
|
253
260
|
operationalAddress?: ServerAddressIp;
|
|
254
261
|
},
|
|
@@ -256,7 +263,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
256
263
|
address = PeerAddress(address);
|
|
257
264
|
|
|
258
265
|
const isGroupNode = PeerAddress.isGroup(address);
|
|
259
|
-
const {
|
|
266
|
+
const { allowUnknownPeer, operationalAddress } = options;
|
|
260
267
|
if (!this.#peersByAddress.has(address) && !allowUnknownPeer && !isGroupNode) {
|
|
261
268
|
throw new UnknownNodeError(`Cannot connect to unknown device ${PeerAddress(address)}`);
|
|
262
269
|
}
|
|
@@ -275,7 +282,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
275
282
|
const { promise, resolver, rejecter } = createPromise<MessageChannel>();
|
|
276
283
|
this.#runningPeerReconnections.set(address, { promise, rejecter });
|
|
277
284
|
|
|
278
|
-
this.#resume(address,
|
|
285
|
+
this.#resume(address, options, operationalAddress)
|
|
279
286
|
.then(channel => {
|
|
280
287
|
this.#runningPeerReconnections.delete(address);
|
|
281
288
|
resolver(channel);
|
|
@@ -292,7 +299,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
292
299
|
/**
|
|
293
300
|
* Obtain an exchange provider for the designated peer.
|
|
294
301
|
*/
|
|
295
|
-
async exchangeProviderFor(addressOrChannel: PeerAddress | MessageChannel,
|
|
302
|
+
async exchangeProviderFor(addressOrChannel: PeerAddress | MessageChannel, options: PeerConnectionOptions = {}) {
|
|
296
303
|
if (addressOrChannel instanceof MessageChannel) {
|
|
297
304
|
return new DedicatedChannelExchangeProvider(this.#exchanges, addressOrChannel);
|
|
298
305
|
}
|
|
@@ -306,10 +313,13 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
306
313
|
}
|
|
307
314
|
let initiallyConnected = this.#channels.hasChannel(address);
|
|
308
315
|
return new ReconnectableExchangeProvider(this.#exchanges, this.#channels, address, async () => {
|
|
316
|
+
const { caseAuthenticatedTags, discoveryOptions } = options;
|
|
317
|
+
|
|
309
318
|
if (!initiallyConnected && !this.#channels.hasChannel(address)) {
|
|
310
319
|
// We got an uninitialized node, so do the first connection as usual
|
|
311
320
|
await this.ensureConnection(address, {
|
|
312
321
|
discoveryOptions: { discoveryType: NodeDiscoveryType.None },
|
|
322
|
+
caseAuthenticatedTags,
|
|
313
323
|
});
|
|
314
324
|
initiallyConnected = true; // We only do this connection once, rest is handled in following code
|
|
315
325
|
if (this.#channels.hasChannel(address)) {
|
|
@@ -337,8 +347,9 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
337
347
|
throw new RetransmissionLimitReachedError(`No operational address found for ${PeerAddress(address)}`);
|
|
338
348
|
}
|
|
339
349
|
if (
|
|
340
|
-
(await this.#reconnectKnownAddress(address, operationalAddress, discoveryData,
|
|
341
|
-
|
|
350
|
+
(await this.#reconnectKnownAddress(address, operationalAddress, discoveryData, {
|
|
351
|
+
expectedProcessingTime: Seconds(2),
|
|
352
|
+
})) === undefined
|
|
342
353
|
) {
|
|
343
354
|
throw new RetransmissionLimitReachedError(`${PeerAddress(address)} is not reachable.`);
|
|
344
355
|
}
|
|
@@ -411,8 +422,8 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
411
422
|
* device is discovered again using its operational instance details.
|
|
412
423
|
* It returns the operational MessageChannel on success.
|
|
413
424
|
*/
|
|
414
|
-
async #resume(address: PeerAddress,
|
|
415
|
-
const { discoveryType } =
|
|
425
|
+
async #resume(address: PeerAddress, options: PeerConnectionOptions, tryOperationalAddress?: ServerAddressIp) {
|
|
426
|
+
const { discoveryOptions: { discoveryType } = {} } = options;
|
|
416
427
|
|
|
417
428
|
const operationalAddress =
|
|
418
429
|
tryOperationalAddress ??
|
|
@@ -421,7 +432,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
421
432
|
: this.#knownOperationalAddressFor(address));
|
|
422
433
|
|
|
423
434
|
try {
|
|
424
|
-
return await this.#connectOrDiscoverNode(address, operationalAddress,
|
|
435
|
+
return await this.#connectOrDiscoverNode(address, operationalAddress, options);
|
|
425
436
|
} catch (error) {
|
|
426
437
|
if (
|
|
427
438
|
(error instanceof DiscoveryError || error instanceof NoResponseTimeoutError) &&
|
|
@@ -439,14 +450,17 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
439
450
|
async #connectOrDiscoverNode(
|
|
440
451
|
address: PeerAddress,
|
|
441
452
|
operationalAddress?: ServerAddressIp,
|
|
442
|
-
|
|
453
|
+
options?: PeerConnectionOptions,
|
|
443
454
|
) {
|
|
444
455
|
address = PeerAddress(address);
|
|
445
456
|
const {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
457
|
+
discoveryOptions: {
|
|
458
|
+
discoveryType: requestedDiscoveryType = NodeDiscoveryType.FullDiscovery,
|
|
459
|
+
timeout,
|
|
460
|
+
discoveryData = this.#peersByAddress.get(address)?.discoveryData,
|
|
461
|
+
} = {},
|
|
462
|
+
caseAuthenticatedTags,
|
|
463
|
+
} = options ?? {};
|
|
450
464
|
if (timeout !== undefined && requestedDiscoveryType !== NodeDiscoveryType.TimedDiscovery) {
|
|
451
465
|
throw new ImplementationError("Cannot set timeout without timed discovery.");
|
|
452
466
|
}
|
|
@@ -486,7 +500,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
486
500
|
operationalAddress,
|
|
487
501
|
discoveryData,
|
|
488
502
|
// When we use a timeout for discovery also use this for reconnecting to the node
|
|
489
|
-
timeout,
|
|
503
|
+
{ expectedProcessingTime: timeout, caseAuthenticatedTags },
|
|
490
504
|
);
|
|
491
505
|
if (directReconnection !== undefined) {
|
|
492
506
|
return directReconnection;
|
|
@@ -533,6 +547,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
533
547
|
address,
|
|
534
548
|
lastOperationalAddress,
|
|
535
549
|
discoveryData,
|
|
550
|
+
{ caseAuthenticatedTags },
|
|
536
551
|
);
|
|
537
552
|
if (result !== undefined && reconnectionPollingTimer?.isRunning) {
|
|
538
553
|
reconnectionPollingTimer?.stop();
|
|
@@ -589,7 +604,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
589
604
|
return device !== undefined ? [device] : [];
|
|
590
605
|
},
|
|
591
606
|
async (operationalAddress, peer) => {
|
|
592
|
-
const result = await this.#pair(address, operationalAddress, peer);
|
|
607
|
+
const result = await this.#pair(address, operationalAddress, peer, { caseAuthenticatedTags });
|
|
593
608
|
await this.#addOrUpdatePeer(address, operationalAddress, {
|
|
594
609
|
...discoveryData,
|
|
595
610
|
...peer,
|
|
@@ -617,11 +632,12 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
617
632
|
address: PeerAddress,
|
|
618
633
|
operationalAddress: ServerAddressIp,
|
|
619
634
|
discoveryData?: DiscoveryData,
|
|
620
|
-
|
|
635
|
+
options?: CaseClient.PairOptions,
|
|
621
636
|
): Promise<MessageChannel | undefined> {
|
|
622
637
|
address = PeerAddress(address);
|
|
623
638
|
|
|
624
639
|
const { ip, port } = operationalAddress;
|
|
640
|
+
const { expectedProcessingTime } = options ?? {};
|
|
625
641
|
const startTime = Time.nowMs;
|
|
626
642
|
try {
|
|
627
643
|
logger.debug(
|
|
@@ -631,7 +647,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
631
647
|
: ""
|
|
632
648
|
}`,
|
|
633
649
|
);
|
|
634
|
-
const channel = await this.#pair(address, operationalAddress, discoveryData,
|
|
650
|
+
const channel = await this.#pair(address, operationalAddress, discoveryData, options);
|
|
635
651
|
await this.#addOrUpdatePeer(address, operationalAddress);
|
|
636
652
|
return channel;
|
|
637
653
|
} catch (error) {
|
|
@@ -675,7 +691,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
675
691
|
address: PeerAddress,
|
|
676
692
|
operationalServerAddress: ServerAddressIp,
|
|
677
693
|
discoveryData?: DiscoveryData,
|
|
678
|
-
|
|
694
|
+
options?: CaseClient.PairOptions,
|
|
679
695
|
) {
|
|
680
696
|
logger.debug(`Pair with ${address} at ${ServerAddress.urlFor(operationalServerAddress)}`);
|
|
681
697
|
const { ip, port } = operationalServerAddress;
|
|
@@ -710,7 +726,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
710
726
|
const operationalSecureSession = await this.#doCasePair(
|
|
711
727
|
new MessageChannel(operationalChannel, unsecureSession),
|
|
712
728
|
address,
|
|
713
|
-
|
|
729
|
+
options,
|
|
714
730
|
);
|
|
715
731
|
|
|
716
732
|
const channel = new MessageChannel(operationalChannel, operationalSecureSession);
|
|
@@ -729,19 +745,14 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
729
745
|
async #doCasePair(
|
|
730
746
|
unsecureMessageChannel: MessageChannel,
|
|
731
747
|
address: PeerAddress,
|
|
732
|
-
|
|
748
|
+
options?: CaseClient.PairOptions,
|
|
733
749
|
): Promise<SecureSession> {
|
|
734
750
|
const fabric = this.#sessions.fabricFor(address);
|
|
735
751
|
let exchange: MessageExchange | undefined;
|
|
736
752
|
try {
|
|
737
753
|
exchange = this.#exchanges.initiateExchangeWithChannel(unsecureMessageChannel, SECURE_CHANNEL_PROTOCOL_ID);
|
|
738
754
|
|
|
739
|
-
const { session, resumed } = await this.#caseClient.pair(
|
|
740
|
-
exchange,
|
|
741
|
-
fabric,
|
|
742
|
-
address.nodeId,
|
|
743
|
-
expectedProcessingTime,
|
|
744
|
-
);
|
|
755
|
+
const { session, resumed } = await this.#caseClient.pair(exchange, fabric, address.nodeId, options);
|
|
745
756
|
|
|
746
757
|
if (!resumed) {
|
|
747
758
|
// When the session was not resumed then most likely the device firmware got updated, so we clear the cache
|
|
@@ -761,7 +772,7 @@ export class PeerSet implements ImmutableSet<OperationalPeer>, ObservableSet<Ope
|
|
|
761
772
|
`Case client: Resumption record seems outdated for Fabric ${NodeId.toHexString(fabric.nodeId)} (index ${fabric.fabricIndex}) and PeerNode ${NodeId.toHexString(address.nodeId)}. Retrying pairing without resumption...`,
|
|
762
773
|
);
|
|
763
774
|
// An endless loop should not happen here, as the resumption record is deleted in the next step
|
|
764
|
-
return await this.#doCasePair(unsecureMessageChannel, address,
|
|
775
|
+
return await this.#doCasePair(unsecureMessageChannel, address, options);
|
|
765
776
|
}
|
|
766
777
|
}
|
|
767
778
|
throw error;
|
|
@@ -13,7 +13,7 @@ import { MessageExchange, RetransmissionLimitReachedError } from "#protocol/Mess
|
|
|
13
13
|
import { ChannelStatusResponseError } from "#securechannel/SecureChannelMessenger.js";
|
|
14
14
|
import { NodeSession } from "#session/NodeSession.js";
|
|
15
15
|
import { SessionManager } from "#session/SessionManager.js";
|
|
16
|
-
import { NodeId, SecureChannelStatusCode } from "#types";
|
|
16
|
+
import { CaseAuthenticatedTag, NodeId, SecureChannelStatusCode } from "#types";
|
|
17
17
|
import {
|
|
18
18
|
KDFSR1_KEY_INFO,
|
|
19
19
|
KDFSR2_INFO,
|
|
@@ -38,11 +38,12 @@ export class CaseClient {
|
|
|
38
38
|
this.#sessions = sessions;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
async pair(exchange: MessageExchange, fabric: Fabric, peerNodeId: NodeId,
|
|
41
|
+
async pair(exchange: MessageExchange, fabric: Fabric, peerNodeId: NodeId, options?: CaseClient.PairOptions) {
|
|
42
|
+
const { expectedProcessingTime, caseAuthenticatedTags } = options ?? {};
|
|
42
43
|
const messenger = new CaseClientMessenger(exchange, expectedProcessingTime);
|
|
43
44
|
|
|
44
45
|
try {
|
|
45
|
-
return await this.#doPair(messenger, exchange, fabric, peerNodeId);
|
|
46
|
+
return await this.#doPair(messenger, exchange, fabric, peerNodeId, caseAuthenticatedTags);
|
|
46
47
|
} catch (error) {
|
|
47
48
|
if (!(error instanceof ChannelStatusResponseError || error instanceof RetransmissionLimitReachedError)) {
|
|
48
49
|
await messenger.sendError(SecureChannelStatusCode.InvalidParam);
|
|
@@ -51,7 +52,13 @@ export class CaseClient {
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
async #doPair(
|
|
55
|
+
async #doPair(
|
|
56
|
+
messenger: CaseClientMessenger,
|
|
57
|
+
exchange: MessageExchange,
|
|
58
|
+
fabric: Fabric,
|
|
59
|
+
peerNodeId: NodeId,
|
|
60
|
+
caseAuthenticatedTags?: CaseAuthenticatedTag[],
|
|
61
|
+
) {
|
|
55
62
|
const { crypto } = fabric;
|
|
56
63
|
|
|
57
64
|
// Generate pairing info
|
|
@@ -221,7 +228,8 @@ export class CaseClient {
|
|
|
221
228
|
await messenger.waitForSuccess("Sigma3-Success");
|
|
222
229
|
|
|
223
230
|
// All good! Create secure session
|
|
224
|
-
|
|
231
|
+
// Configured CATs take precedence over resumption record ones
|
|
232
|
+
const sessionCaseAuthenticatedTags = caseAuthenticatedTags ?? resumptionRecord?.caseAuthenticatedTags;
|
|
225
233
|
const secureSessionSalt = Bytes.concat(
|
|
226
234
|
operationalIdentityProtectionKey,
|
|
227
235
|
await crypto.computeSha256([sigma1Bytes, sigma2Bytes, sigma3Bytes]),
|
|
@@ -236,7 +244,7 @@ export class CaseClient {
|
|
|
236
244
|
isInitiator: true,
|
|
237
245
|
isResumption: false,
|
|
238
246
|
peerSessionParameters,
|
|
239
|
-
caseAuthenticatedTags,
|
|
247
|
+
caseAuthenticatedTags: sessionCaseAuthenticatedTags,
|
|
240
248
|
});
|
|
241
249
|
this.#logNewSession("New", secureSession, messenger, fabric, peerNodeId);
|
|
242
250
|
resumptionRecord = {
|
|
@@ -245,7 +253,7 @@ export class CaseClient {
|
|
|
245
253
|
sharedSecret,
|
|
246
254
|
resumptionId: peerResumptionId,
|
|
247
255
|
sessionParameters: secureSession.parameters,
|
|
248
|
-
caseAuthenticatedTags,
|
|
256
|
+
caseAuthenticatedTags: sessionCaseAuthenticatedTags,
|
|
249
257
|
};
|
|
250
258
|
}
|
|
251
259
|
|
|
@@ -274,3 +282,10 @@ export class CaseClient {
|
|
|
274
282
|
);
|
|
275
283
|
}
|
|
276
284
|
}
|
|
285
|
+
|
|
286
|
+
export namespace CaseClient {
|
|
287
|
+
export interface PairOptions {
|
|
288
|
+
expectedProcessingTime?: Duration;
|
|
289
|
+
caseAuthenticatedTags?: CaseAuthenticatedTag[];
|
|
290
|
+
}
|
|
291
|
+
}
|