@matter/protocol 0.14.0-alpha.0-20250525-d6ada0d45 → 0.14.0-alpha.0-20250528-ad0054c84
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/fabric/FabricManager.d.ts.map +1 -1
- package/dist/cjs/fabric/FabricManager.js +1 -1
- package/dist/cjs/fabric/FabricManager.js.map +1 -1
- package/dist/cjs/session/case/CaseClient.d.ts.map +1 -1
- package/dist/cjs/session/case/CaseClient.js +11 -0
- package/dist/cjs/session/case/CaseClient.js.map +1 -1
- package/dist/cjs/session/case/CaseServer.d.ts +0 -1
- package/dist/cjs/session/case/CaseServer.d.ts.map +1 -1
- package/dist/cjs/session/case/CaseServer.js +205 -163
- package/dist/cjs/session/case/CaseServer.js.map +2 -2
- package/dist/esm/fabric/FabricManager.d.ts.map +1 -1
- package/dist/esm/fabric/FabricManager.js +1 -2
- package/dist/esm/fabric/FabricManager.js.map +1 -1
- package/dist/esm/session/case/CaseClient.d.ts.map +1 -1
- package/dist/esm/session/case/CaseClient.js +12 -1
- package/dist/esm/session/case/CaseClient.js.map +1 -1
- package/dist/esm/session/case/CaseServer.d.ts +0 -1
- package/dist/esm/session/case/CaseServer.d.ts.map +1 -1
- package/dist/esm/session/case/CaseServer.js +206 -164
- package/dist/esm/session/case/CaseServer.js.map +2 -2
- package/package.json +6 -6
- package/src/fabric/FabricManager.ts +1 -2
- package/src/session/case/CaseClient.ts +12 -1
- package/src/session/case/CaseServer.ts +255 -192
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Bytes, Crypto, Logger, PublicKey, UnexpectedDataError } from "#general";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { Bytes, Crypto, CryptoDecryptError, Logger, PublicKey, UnexpectedDataError } from "#general";
|
|
8
|
+
import { TlvSessionParameters } from "#session/pase/PaseMessages.js";
|
|
9
|
+
import { ResumptionRecord, SessionManager } from "#session/SessionManager.js";
|
|
10
|
+
import { NodeId, ProtocolStatusCode, SECURE_CHANNEL_PROTOCOL_ID, TypeFromSchema } from "#types";
|
|
10
11
|
import { TlvOperationalCertificate } from "../../certificate/CertificateManager.js";
|
|
11
12
|
import { FabricManager, FabricNotFoundError } from "../../fabric/FabricManager.js";
|
|
12
13
|
import { MessageExchange } from "../../protocol/MessageExchange.js";
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
RESUME2_MIC_NONCE,
|
|
22
23
|
TBE_DATA2_NONCE,
|
|
23
24
|
TBE_DATA3_NONCE,
|
|
25
|
+
TlvCaseSigma1,
|
|
24
26
|
TlvEncryptedDataSigma2,
|
|
25
27
|
TlvEncryptedDataSigma3,
|
|
26
28
|
TlvSignedData,
|
|
@@ -44,7 +46,7 @@ export class CaseServer implements ProtocolHandler {
|
|
|
44
46
|
async onNewExchange(exchange: MessageExchange) {
|
|
45
47
|
const messenger = new CaseServerMessenger(exchange);
|
|
46
48
|
try {
|
|
47
|
-
await this
|
|
49
|
+
await this.#handleSigma1(messenger);
|
|
48
50
|
} catch (error) {
|
|
49
51
|
logger.error("An error occurred during the commissioning", error);
|
|
50
52
|
|
|
@@ -61,211 +63,272 @@ export class CaseServer implements ProtocolHandler {
|
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
async #handleSigma1(messenger: CaseServerMessenger) {
|
|
65
67
|
logger.info(`Received pairing request from ${messenger.getChannelName()}`);
|
|
66
|
-
// Generate pairing info
|
|
67
|
-
const responderRandom = Crypto.getRandom();
|
|
68
68
|
|
|
69
|
-
//
|
|
69
|
+
// Initialize context with information from peer
|
|
70
70
|
const { sigma1Bytes, sigma1 } = await messenger.readSigma1();
|
|
71
|
-
const {
|
|
72
|
-
initiatorSessionId: peerSessionId,
|
|
73
|
-
resumptionId: peerResumptionId,
|
|
74
|
-
initiatorResumeMic: peerResumeMic,
|
|
75
|
-
destinationId,
|
|
76
|
-
initiatorRandom: peerRandom,
|
|
77
|
-
initiatorEcdhPublicKey: peerEcdhPublicKey,
|
|
78
|
-
initiatorSessionParams,
|
|
79
|
-
} = sigma1;
|
|
80
|
-
|
|
81
|
-
// Try to resume a previous session
|
|
82
|
-
const resumptionId = Crypto.getRandomData(16);
|
|
83
|
-
|
|
84
71
|
const resumptionRecord =
|
|
85
|
-
|
|
86
|
-
? this.#sessions.findResumptionRecordById(
|
|
72
|
+
sigma1.resumptionId !== undefined && sigma1.initiatorResumeMic !== undefined
|
|
73
|
+
? this.#sessions.findResumptionRecordById(sigma1.resumptionId)
|
|
87
74
|
: undefined;
|
|
88
|
-
// We try to resume the session
|
|
89
|
-
if (peerResumptionId !== undefined && peerResumeMic !== undefined && resumptionRecord !== undefined) {
|
|
90
|
-
const { sharedSecret, fabric, peerNodeId, caseAuthenticatedTags } = resumptionRecord;
|
|
91
|
-
const peerResumeKey = await Crypto.hkdf(
|
|
92
|
-
sharedSecret,
|
|
93
|
-
Bytes.concat(peerRandom, peerResumptionId),
|
|
94
|
-
KDFSR1_KEY_INFO,
|
|
95
|
-
);
|
|
96
|
-
Crypto.decrypt(peerResumeKey, peerResumeMic, RESUME1_MIC_NONCE);
|
|
97
|
-
|
|
98
|
-
// All good! Create secure session
|
|
99
|
-
const responderSessionId = await this.#sessions.getNextAvailableSessionId();
|
|
100
|
-
const secureSessionSalt = Bytes.concat(peerRandom, peerResumptionId);
|
|
101
|
-
const secureSession = await this.#sessions.createSecureSession({
|
|
102
|
-
sessionId: responderSessionId,
|
|
103
|
-
fabric,
|
|
104
|
-
peerNodeId,
|
|
105
|
-
peerSessionId,
|
|
106
|
-
sharedSecret,
|
|
107
|
-
salt: secureSessionSalt,
|
|
108
|
-
isInitiator: false,
|
|
109
|
-
isResumption: true,
|
|
110
|
-
peerSessionParameters: initiatorSessionParams,
|
|
111
|
-
caseAuthenticatedTags,
|
|
112
|
-
});
|
|
113
75
|
|
|
114
|
-
|
|
115
|
-
const resumeSalt = Bytes.concat(peerRandom, resumptionId);
|
|
116
|
-
const resumeKey = await Crypto.hkdf(sharedSecret, resumeSalt, KDFSR2_KEY_INFO);
|
|
117
|
-
const resumeMic = Crypto.encrypt(resumeKey, new Uint8Array(0), RESUME2_MIC_NONCE);
|
|
118
|
-
try {
|
|
119
|
-
await messenger.sendSigma2Resume({
|
|
120
|
-
resumptionId,
|
|
121
|
-
resumeMic,
|
|
122
|
-
responderSessionId,
|
|
123
|
-
responderSessionParams: this.#sessions.sessionParameters, // responder session parameters
|
|
124
|
-
});
|
|
125
|
-
} catch (error) {
|
|
126
|
-
// If we fail to send the resume, we destroy the session
|
|
127
|
-
await secureSession.destroy(false);
|
|
128
|
-
throw error;
|
|
129
|
-
}
|
|
76
|
+
const context = new Sigma1Context(messenger, sigma1Bytes, sigma1, resumptionRecord);
|
|
130
77
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
78
|
+
// Attempt resumption
|
|
79
|
+
if (await this.#resume(context)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Attempt sigma2 negotiation
|
|
84
|
+
if (await this.#generateSigma2(context)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
logger.info(
|
|
89
|
+
`Invalid resumption ID or resume MIC received from ${messenger.getChannelName()}`,
|
|
90
|
+
context.peerResumptionId,
|
|
91
|
+
context.peerResumeMic,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
throw new UnexpectedDataError("Invalid resumption ID or resume MIC.");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async #resume(cx: Sigma1Context) {
|
|
98
|
+
if (cx.peerResumptionId === undefined || cx.peerResumeMic === undefined || cx.resumptionRecord === undefined) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const { sharedSecret, fabric, peerNodeId, caseAuthenticatedTags } = cx.resumptionRecord;
|
|
103
|
+
const peerResumeKey = await Crypto.hkdf(
|
|
104
|
+
sharedSecret,
|
|
105
|
+
Bytes.concat(cx.peerRandom, cx.peerResumptionId),
|
|
106
|
+
KDFSR1_KEY_INFO,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
Crypto.decrypt(peerResumeKey, cx.peerResumeMic, RESUME1_MIC_NONCE);
|
|
111
|
+
} catch (e) {
|
|
112
|
+
CryptoDecryptError.accept(e);
|
|
113
|
+
|
|
114
|
+
// Clear resumption and initiate negotiate new connection
|
|
115
|
+
cx.peerResumptionId = cx.peerResumeMic = undefined;
|
|
116
|
+
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// All good! Create secure session
|
|
121
|
+
const responderSessionId = await this.#sessions.getNextAvailableSessionId();
|
|
122
|
+
const secureSessionSalt = Bytes.concat(cx.peerRandom, cx.peerResumptionId);
|
|
123
|
+
const secureSession = await this.#sessions.createSecureSession({
|
|
124
|
+
sessionId: responderSessionId,
|
|
125
|
+
fabric,
|
|
126
|
+
peerNodeId,
|
|
127
|
+
peerSessionId: cx.peerSessionId,
|
|
128
|
+
sharedSecret,
|
|
129
|
+
salt: secureSessionSalt,
|
|
130
|
+
isInitiator: false,
|
|
131
|
+
isResumption: true,
|
|
132
|
+
peerSessionParameters: cx.peerSessionParams,
|
|
133
|
+
caseAuthenticatedTags,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Generate sigma 2 resume
|
|
137
|
+
const resumeSalt = Bytes.concat(cx.peerRandom, cx.localResumptionId);
|
|
138
|
+
const resumeKey = await Crypto.hkdf(sharedSecret, resumeSalt, KDFSR2_KEY_INFO);
|
|
139
|
+
const resumeMic = Crypto.encrypt(resumeKey, new Uint8Array(0), RESUME2_MIC_NONCE);
|
|
140
|
+
try {
|
|
141
|
+
await cx.messenger.sendSigma2Resume({
|
|
142
|
+
resumptionId: cx.localResumptionId,
|
|
143
|
+
resumeMic,
|
|
179
144
|
responderSessionId,
|
|
180
|
-
responderEcdhPublicKey,
|
|
181
|
-
encrypted,
|
|
182
145
|
responderSessionParams: this.#sessions.sessionParameters, // responder session parameters
|
|
183
146
|
});
|
|
147
|
+
} catch (error) {
|
|
148
|
+
// If we fail to send the resume, we destroy the session
|
|
149
|
+
await secureSession.destroy(false);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
184
152
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
);
|
|
194
|
-
const sigma3Key = await Crypto.hkdf(sharedSecret, sigma3Salt, KDFSR3_INFO);
|
|
195
|
-
const peerDecryptedData = Crypto.decrypt(sigma3Key, peerEncrypted, TBE_DATA3_NONCE);
|
|
196
|
-
const {
|
|
197
|
-
nodeOpCert: peerNewOpCert,
|
|
198
|
-
intermediateCACert: peerIntermediateCACert,
|
|
199
|
-
signature: peerSignature,
|
|
200
|
-
} = TlvEncryptedDataSigma3.decode(peerDecryptedData);
|
|
201
|
-
|
|
202
|
-
await fabric.verifyCredentials(peerNewOpCert, peerIntermediateCACert);
|
|
203
|
-
|
|
204
|
-
const peerSignatureData = TlvSignedData.encode({
|
|
205
|
-
nodeOpCert: peerNewOpCert,
|
|
206
|
-
intermediateCACert: peerIntermediateCACert,
|
|
207
|
-
ecdhPublicKey: peerEcdhPublicKey,
|
|
208
|
-
peerEcdhPublicKey: responderEcdhPublicKey,
|
|
209
|
-
});
|
|
210
|
-
const {
|
|
211
|
-
ellipticCurvePublicKey: peerPublicKey,
|
|
212
|
-
subject: { fabricId: peerFabricId, nodeId: peerNodeId, caseAuthenticatedTags },
|
|
213
|
-
} = TlvOperationalCertificate.decode(peerNewOpCert);
|
|
153
|
+
logger.info(
|
|
154
|
+
`Session ${secureSession.id} resumed with ${cx.messenger.getChannelName()} for Fabric ${NodeId.toHexString(
|
|
155
|
+
fabric.nodeId,
|
|
156
|
+
)} (index ${fabric.fabricIndex}) and PeerNode ${NodeId.toHexString(peerNodeId)}`,
|
|
157
|
+
"with CATs",
|
|
158
|
+
caseAuthenticatedTags,
|
|
159
|
+
);
|
|
160
|
+
cx.resumptionRecord.resumptionId = cx.localResumptionId; /* Update the ID */
|
|
214
161
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
162
|
+
// Wait for success on the peer side
|
|
163
|
+
await cx.messenger.waitForSuccess("Sigma2Resume-Success");
|
|
218
164
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
isInitiator: false,
|
|
234
|
-
isResumption: false,
|
|
235
|
-
peerSessionParameters: initiatorSessionParams,
|
|
236
|
-
caseAuthenticatedTags,
|
|
237
|
-
});
|
|
238
|
-
logger.info(
|
|
239
|
-
`Session ${secureSession.id} created with ${messenger.getChannelName()} for Fabric ${NodeId.toHexString(
|
|
240
|
-
fabric.nodeId,
|
|
241
|
-
)} (index ${fabric.fabricIndex}) and PeerNode ${NodeId.toHexString(peerNodeId)}`,
|
|
242
|
-
"with CATs",
|
|
243
|
-
caseAuthenticatedTags,
|
|
244
|
-
);
|
|
245
|
-
await messenger.sendSuccess();
|
|
246
|
-
|
|
247
|
-
const resumptionRecord = {
|
|
248
|
-
peerNodeId,
|
|
249
|
-
fabric,
|
|
250
|
-
sharedSecret,
|
|
251
|
-
resumptionId,
|
|
252
|
-
sessionParameters: secureSession.parameters,
|
|
253
|
-
caseAuthenticatedTags,
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
await messenger.close();
|
|
257
|
-
await this.#sessions.saveResumptionRecord(resumptionRecord);
|
|
258
|
-
} else {
|
|
259
|
-
logger.info(
|
|
260
|
-
`Invalid resumption ID or resume MIC received from ${messenger.getChannelName()}`,
|
|
261
|
-
peerResumptionId,
|
|
262
|
-
peerResumeMic,
|
|
263
|
-
);
|
|
264
|
-
throw new UnexpectedDataError("Invalid resumption ID or resume MIC.");
|
|
165
|
+
await cx.messenger.close();
|
|
166
|
+
await this.#sessions.saveResumptionRecord(cx.resumptionRecord);
|
|
167
|
+
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async #generateSigma2(cx: Sigma1Context) {
|
|
172
|
+
if (
|
|
173
|
+
// No resumption attempted is OK
|
|
174
|
+
!(cx.peerResumptionId === undefined && cx.peerResumeMic === undefined) &&
|
|
175
|
+
// Resumption attempted with no record on our side is OK
|
|
176
|
+
!(cx.peerResumptionId !== undefined && cx.peerResumeMic !== undefined && cx.resumptionRecord === undefined)
|
|
177
|
+
) {
|
|
178
|
+
return false;
|
|
265
179
|
}
|
|
180
|
+
|
|
181
|
+
// Generate pairing info
|
|
182
|
+
const responderRandom = Crypto.getRandom();
|
|
183
|
+
|
|
184
|
+
// TODO: Pass through a group id?
|
|
185
|
+
const fabric = await this.#fabrics.findFabricFromDestinationId(cx.destinationId, cx.peerRandom);
|
|
186
|
+
const { operationalCert: nodeOpCert, intermediateCACert, operationalIdentityProtectionKey } = fabric;
|
|
187
|
+
const { publicKey: responderEcdhPublicKey, sharedSecret } = await Crypto.ecdhGeneratePublicKeyAndSecret(
|
|
188
|
+
cx.peerEcdhPublicKey,
|
|
189
|
+
);
|
|
190
|
+
const sigma2Salt = Bytes.concat(
|
|
191
|
+
operationalIdentityProtectionKey,
|
|
192
|
+
responderRandom,
|
|
193
|
+
responderEcdhPublicKey,
|
|
194
|
+
await Crypto.hash(cx.bytes),
|
|
195
|
+
);
|
|
196
|
+
const sigma2Key = await Crypto.hkdf(sharedSecret, sigma2Salt, KDFSR2_INFO);
|
|
197
|
+
const signatureData = TlvSignedData.encode({
|
|
198
|
+
nodeOpCert,
|
|
199
|
+
intermediateCACert,
|
|
200
|
+
ecdhPublicKey: responderEcdhPublicKey,
|
|
201
|
+
peerEcdhPublicKey: cx.peerEcdhPublicKey,
|
|
202
|
+
});
|
|
203
|
+
const signature = await fabric.sign(signatureData);
|
|
204
|
+
const encryptedData = TlvEncryptedDataSigma2.encode({
|
|
205
|
+
nodeOpCert,
|
|
206
|
+
intermediateCACert,
|
|
207
|
+
signature,
|
|
208
|
+
resumptionId: cx.localResumptionId,
|
|
209
|
+
});
|
|
210
|
+
const encrypted = Crypto.encrypt(sigma2Key, encryptedData, TBE_DATA2_NONCE);
|
|
211
|
+
const responderSessionId = await this.#sessions.getNextAvailableSessionId();
|
|
212
|
+
const sigma2Bytes = await cx.messenger.sendSigma2({
|
|
213
|
+
responderRandom,
|
|
214
|
+
responderSessionId,
|
|
215
|
+
responderEcdhPublicKey,
|
|
216
|
+
encrypted,
|
|
217
|
+
responderSessionParams: this.#sessions.sessionParameters, // responder session parameters
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Read and process sigma 3
|
|
221
|
+
const {
|
|
222
|
+
sigma3Bytes,
|
|
223
|
+
sigma3: { encrypted: peerEncrypted },
|
|
224
|
+
} = await cx.messenger.readSigma3();
|
|
225
|
+
const sigma3Salt = Bytes.concat(operationalIdentityProtectionKey, await Crypto.hash([cx.bytes, sigma2Bytes]));
|
|
226
|
+
const sigma3Key = await Crypto.hkdf(sharedSecret, sigma3Salt, KDFSR3_INFO);
|
|
227
|
+
const peerDecryptedData = Crypto.decrypt(sigma3Key, peerEncrypted, TBE_DATA3_NONCE);
|
|
228
|
+
const {
|
|
229
|
+
nodeOpCert: peerNewOpCert,
|
|
230
|
+
intermediateCACert: peerIntermediateCACert,
|
|
231
|
+
signature: peerSignature,
|
|
232
|
+
} = TlvEncryptedDataSigma3.decode(peerDecryptedData);
|
|
233
|
+
|
|
234
|
+
await fabric.verifyCredentials(peerNewOpCert, peerIntermediateCACert);
|
|
235
|
+
|
|
236
|
+
const peerSignatureData = TlvSignedData.encode({
|
|
237
|
+
nodeOpCert: peerNewOpCert,
|
|
238
|
+
intermediateCACert: peerIntermediateCACert,
|
|
239
|
+
ecdhPublicKey: cx.peerEcdhPublicKey,
|
|
240
|
+
peerEcdhPublicKey: responderEcdhPublicKey,
|
|
241
|
+
});
|
|
242
|
+
const {
|
|
243
|
+
ellipticCurvePublicKey: peerPublicKey,
|
|
244
|
+
subject: { fabricId: peerFabricId, nodeId: peerNodeId, caseAuthenticatedTags },
|
|
245
|
+
} = TlvOperationalCertificate.decode(peerNewOpCert);
|
|
246
|
+
|
|
247
|
+
if (fabric.fabricId !== peerFabricId) {
|
|
248
|
+
throw new UnexpectedDataError(`Fabric ID mismatch: ${fabric.fabricId} !== ${peerFabricId}`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
await Crypto.verify(PublicKey(peerPublicKey), peerSignatureData, peerSignature);
|
|
252
|
+
|
|
253
|
+
// All good! Create secure session
|
|
254
|
+
const secureSessionSalt = Bytes.concat(
|
|
255
|
+
operationalIdentityProtectionKey,
|
|
256
|
+
await Crypto.hash([cx.bytes, sigma2Bytes, sigma3Bytes]),
|
|
257
|
+
);
|
|
258
|
+
const secureSession = await this.#sessions.createSecureSession({
|
|
259
|
+
sessionId: responderSessionId,
|
|
260
|
+
fabric,
|
|
261
|
+
peerNodeId,
|
|
262
|
+
peerSessionId: cx.peerSessionId,
|
|
263
|
+
sharedSecret,
|
|
264
|
+
salt: secureSessionSalt,
|
|
265
|
+
isInitiator: false,
|
|
266
|
+
isResumption: false,
|
|
267
|
+
peerSessionParameters: cx.peerSessionParams,
|
|
268
|
+
caseAuthenticatedTags,
|
|
269
|
+
});
|
|
270
|
+
logger.info(
|
|
271
|
+
`Session ${secureSession.id} created with ${cx.messenger.getChannelName()} for Fabric ${NodeId.toHexString(
|
|
272
|
+
fabric.nodeId,
|
|
273
|
+
)} (index ${fabric.fabricIndex}) and PeerNode ${NodeId.toHexString(peerNodeId)}`,
|
|
274
|
+
"with CATs",
|
|
275
|
+
caseAuthenticatedTags,
|
|
276
|
+
);
|
|
277
|
+
await cx.messenger.sendSuccess();
|
|
278
|
+
|
|
279
|
+
const resumptionRecord = {
|
|
280
|
+
peerNodeId,
|
|
281
|
+
fabric,
|
|
282
|
+
sharedSecret,
|
|
283
|
+
resumptionId: cx.localResumptionId,
|
|
284
|
+
sessionParameters: secureSession.parameters,
|
|
285
|
+
caseAuthenticatedTags,
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
await cx.messenger.close();
|
|
289
|
+
await this.#sessions.saveResumptionRecord(resumptionRecord);
|
|
290
|
+
|
|
291
|
+
return true;
|
|
266
292
|
}
|
|
267
293
|
|
|
268
294
|
async close() {
|
|
269
295
|
// Nothing to do
|
|
270
296
|
}
|
|
271
297
|
}
|
|
298
|
+
|
|
299
|
+
class Sigma1Context {
|
|
300
|
+
messenger: CaseServerMessenger;
|
|
301
|
+
bytes: Uint8Array;
|
|
302
|
+
peerSessionId: number;
|
|
303
|
+
peerResumptionId?: Uint8Array;
|
|
304
|
+
peerResumeMic?: Uint8Array;
|
|
305
|
+
destinationId: Uint8Array;
|
|
306
|
+
peerRandom: Uint8Array;
|
|
307
|
+
peerEcdhPublicKey: Uint8Array;
|
|
308
|
+
peerSessionParams?: TypeFromSchema<typeof TlvSessionParameters>;
|
|
309
|
+
resumptionRecord?: ResumptionRecord;
|
|
310
|
+
|
|
311
|
+
#localResumptionId?: Uint8Array;
|
|
312
|
+
|
|
313
|
+
constructor(
|
|
314
|
+
messenger: CaseServerMessenger,
|
|
315
|
+
bytes: Uint8Array,
|
|
316
|
+
sigma1: TypeFromSchema<typeof TlvCaseSigma1>,
|
|
317
|
+
resumptionRecord?: ResumptionRecord,
|
|
318
|
+
) {
|
|
319
|
+
this.messenger = messenger;
|
|
320
|
+
this.bytes = bytes;
|
|
321
|
+
this.peerSessionId = sigma1.initiatorSessionId;
|
|
322
|
+
this.peerResumptionId = sigma1.resumptionId;
|
|
323
|
+
this.peerResumeMic = sigma1.initiatorResumeMic;
|
|
324
|
+
this.destinationId = sigma1.destinationId;
|
|
325
|
+
this.peerRandom = sigma1.initiatorRandom;
|
|
326
|
+
this.peerEcdhPublicKey = sigma1.initiatorEcdhPublicKey;
|
|
327
|
+
this.peerSessionParams = sigma1.initiatorSessionParams;
|
|
328
|
+
this.resumptionRecord = resumptionRecord;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
get localResumptionId() {
|
|
332
|
+
return (this.#localResumptionId ??= Crypto.getRandomData(16));
|
|
333
|
+
}
|
|
334
|
+
}
|