Skip to content

Commit cd278d5

Browse files
committed
Improve secure session logic, teardown exchanges after each action (validated against a certified matter device)
1 parent 2c59174 commit cd278d5

File tree

11 files changed

+374
-57
lines changed

11 files changed

+374
-57
lines changed

Generator/ClusterGenerator.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ public static void Generate()
2525
IEnumerable<string> clusterxmls = Directory.EnumerateFiles("..\\..\\..\\Clusters");
2626
foreach (string clusterxml in clusterxmls)
2727
{
28-
Console.WriteLine("Generating " + clusterxml + "...");
29-
Cluster? cluster = deserializer.Deserialize(File.OpenRead(clusterxml)) as Cluster;
30-
if (cluster == null)
31-
throw new IOException("Failed to parse cluster " + clusterxml);
32-
WriteClass(cluster);
28+
if (clusterxml.EndsWith(".xml"))
29+
{
30+
Console.WriteLine("Generating " + clusterxml + "...");
31+
Cluster? cluster = deserializer.Deserialize(File.OpenRead(clusterxml)) as Cluster;
32+
if (cluster == null)
33+
throw new IOException("Failed to parse cluster " + clusterxml);
34+
WriteClass(cluster);
35+
}
3336
}
3437
}
3538

@@ -266,7 +269,7 @@ private static void WriteCommands(Cluster cluster, StreamWriter writer)
266269
writer.Write("<bool> ");
267270
else
268271
writer.Write("<" + GeneratorUtil.SanitizeName(response.name) + "?> ");
269-
writer.Write(GeneratorUtil.SanitizeName(cmd.name) + " (Exchange exchange");
272+
writer.Write(GeneratorUtil.SanitizeName(cmd.name) + " (SecureSession session");
270273
if (cmd.field != null)
271274
{
272275
foreach (var field in cmd.field)
@@ -283,14 +286,14 @@ private static void WriteCommands(Cluster cluster, StreamWriter writer)
283286
foreach (var field in cmd.field)
284287
writer.WriteLine($" {field.name} = {field.name},");
285288
writer.WriteLine(" };");
286-
writer.WriteLine(" InvokeResponseIB resp = await InteractionManager.ExecCommand(exchange, endPoint, CLUSTER_ID, " + cmd.id + ", requestFields);");
289+
writer.WriteLine(" InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, " + cmd.id + ", requestFields);");
287290
}
288291
else
289292
{
290293
if (cmd.response != "N")
291-
writer.WriteLine(" await InteractionManager.SendCommand(exchange, endPoint, CLUSTER_ID, " + cmd.id + ");");
294+
writer.WriteLine(" await InteractionManager.SendCommand(session, endPoint, CLUSTER_ID, " + cmd.id + ");");
292295
else
293-
writer.WriteLine(" InvokeResponseIB resp = await InteractionManager.ExecCommand(exchange, endPoint, CLUSTER_ID, " + cmd.id + ");");
296+
writer.WriteLine(" InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, " + cmd.id + ");");
294297
}
295298
if (response == null)
296299
{

MatterDotNet/Clusters/ClusterBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public ClusterBase(ushort endPoint)
3737
}
3838
protected object GetField(InvokeResponseIB resp, int fieldNumber)
3939
{
40-
object?[] fields = (object?[])resp.Command!.CommandFields!;
40+
object[] fields = (object[])resp.Command!.CommandFields!;
4141
if (fieldNumber >= fields.Length)
4242
throw new DataException("Field " + fieldNumber + " is missing");
4343
return fields[fieldNumber]!;
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// MatterDotNet Copyright (C) 2024
2+
//
3+
// This program is free software: you can redistribute it and/or modify
4+
// it under the terms of the GNU Affero General Public License as published by
5+
// the Free Software Foundation, either version 3 of the License, or any later version.
6+
// This program is distributed in the hope that it will be useful,
7+
// but WITHOUT ANY WARRANTY, without even the implied warranty of
8+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9+
// See the GNU Affero General Public License for more details.
10+
// You should have received a copy of the GNU Affero General Public License
11+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
12+
//
13+
// WARNING: This file was auto-generated. Do not edit.
14+
15+
16+
using MatterDotNet.Messages.InteractionModel;
17+
using MatterDotNet.Protocol;
18+
using MatterDotNet.Protocol.Parsers;
19+
using MatterDotNet.Protocol.Payloads;
20+
using MatterDotNet.Protocol.Sessions;
21+
22+
namespace MatterDotNet.Clusters
23+
{
24+
public class GeneralCommissioningCluster : ClusterBase
25+
{
26+
private const uint CLUSTER_ID = 0x0030;
27+
28+
public GeneralCommissioningCluster(ushort endPoint) : base(endPoint) { }
29+
30+
public enum CommissioningErrorEnum {
31+
/// <summary>
32+
/// No error
33+
/// </summary>
34+
OK = 0,
35+
/// <summary>
36+
/// <see cref="ValueOutsideRange"/> Attempting to set regulatory configuration to a region or indoor/outdoor mode for which the server does not have proper configuration.
37+
/// </summary>
38+
ValueOutsideRange = 1,
39+
/// <summary>
40+
/// <see cref="InvalidAuthentication"/> Executed CommissioningComplete outside CASE session.
41+
/// </summary>
42+
InvalidAuthentication = 2,
43+
/// <summary>
44+
/// <see cref="NoFailSafe"/> Executed CommissioningComplete when there was no active ArmFailSafe Command.
45+
/// </summary>
46+
NoFailSafe = 3,
47+
/// <summary>
48+
/// <see cref="BusyWithOtherAdmin"/> Attempting to arm fail-safe or execute CommissioningComplete from a fabric different than the one associated with the current fail-safe context.
49+
/// </summary>
50+
BusyWithOtherAdmin = 4,
51+
}
52+
53+
public enum RegulatoryLocationTypeEnum {
54+
/// <summary>
55+
/// Indoor only
56+
/// </summary>
57+
Indoor = 0,
58+
/// <summary>
59+
/// Outdoor only
60+
/// </summary>
61+
Outdoor = 1,
62+
/// <summary>
63+
/// Indoor/Outdoor
64+
/// </summary>
65+
IndoorOutdoor = 2,
66+
}
67+
68+
public record BasicCommissioningInfoStruct : TLVPayload {
69+
public required ushort FailSafeExpiryLengthSeconds { get; set; }
70+
public required ushort MaxCumulativeFailsafeSeconds { get; set; }
71+
public override void Serialize(TLVWriter writer, long structNumber = -1) {
72+
writer.StartStructure(structNumber);
73+
writer.WriteUShort(0, FailSafeExpiryLengthSeconds);
74+
writer.WriteUShort(1, MaxCumulativeFailsafeSeconds);
75+
writer.EndContainer();
76+
}
77+
}
78+
79+
private record ArmFailSafePayload : TLVPayload {
80+
public required ushort ExpiryLengthSeconds { get; set; } = 900;
81+
public required ulong Breadcrumb { get; set; }
82+
public override void Serialize(TLVWriter writer, long structNumber = -1) {
83+
writer.StartStructure(structNumber);
84+
writer.WriteUShort(0, ExpiryLengthSeconds);
85+
writer.WriteULong(1, Breadcrumb);
86+
writer.EndContainer();
87+
}
88+
}
89+
90+
public struct ArmFailSafeResponse {
91+
public CommissioningErrorEnum ErrorCode { get; set; }
92+
public string DebugText { get; set; }
93+
}
94+
95+
private record SetRegulatoryConfigPayload : TLVPayload {
96+
public required RegulatoryLocationTypeEnum NewRegulatoryConfig { get; set; }
97+
public required string CountryCode { get; set; }
98+
public required ulong Breadcrumb { get; set; }
99+
public override void Serialize(TLVWriter writer, long structNumber = -1) {
100+
writer.StartStructure(structNumber);
101+
writer.WriteUShort(0, (ushort)NewRegulatoryConfig);
102+
writer.WriteString(1, CountryCode);
103+
writer.WriteULong(2, Breadcrumb);
104+
writer.EndContainer();
105+
}
106+
}
107+
108+
public struct SetRegulatoryConfigResponse {
109+
public required CommissioningErrorEnum ErrorCode { get; set; }
110+
public required String DebugText { get; set; }
111+
}
112+
113+
public struct CommissioningCompleteResponse {
114+
public required CommissioningErrorEnum ErrorCode { get; set; }
115+
public required string DebugText { get; set; }
116+
}
117+
118+
// Commands
119+
public async Task<ArmFailSafeResponse?> ArmFailSafe (SecureSession session, ushort ExpiryLengthSeconds, ulong Breadcrumb) {
120+
ArmFailSafePayload requestFields = new ArmFailSafePayload() {
121+
ExpiryLengthSeconds = ExpiryLengthSeconds,
122+
Breadcrumb = Breadcrumb,
123+
};
124+
InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x00, requestFields);
125+
if (!validateResponse(resp))
126+
return null;
127+
return new ArmFailSafeResponse() {
128+
129+
ErrorCode = (CommissioningErrorEnum)(byte)GetField(resp, 0),
130+
DebugText = (string)GetField(resp, 1),
131+
};
132+
}
133+
134+
public async Task<SetRegulatoryConfigResponse?> SetRegulatoryConfig (SecureSession session, RegulatoryLocationTypeEnum NewRegulatoryConfig, string CountryCode, ulong Breadcrumb) {
135+
SetRegulatoryConfigPayload requestFields = new SetRegulatoryConfigPayload() {
136+
NewRegulatoryConfig = NewRegulatoryConfig,
137+
CountryCode = CountryCode,
138+
Breadcrumb = Breadcrumb,
139+
};
140+
InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x02, requestFields);
141+
if (!validateResponse(resp))
142+
return null;
143+
return new SetRegulatoryConfigResponse() {
144+
ErrorCode = (CommissioningErrorEnum)GetField(resp, 0),
145+
DebugText = (string)GetField(resp, 1),
146+
};
147+
}
148+
149+
public async Task<CommissioningCompleteResponse?> CommissioningComplete (SecureSession session) {
150+
InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x04);
151+
if (!validateResponse(resp))
152+
return null;
153+
return new CommissioningCompleteResponse() {
154+
ErrorCode = (CommissioningErrorEnum)GetField(resp, 0),
155+
DebugText = (string)GetField(resp, 1),
156+
};
157+
}
158+
159+
// Attributes
160+
public ulong Breadcrumb { get; set; } = 0;
161+
public BasicCommissioningInfoStruct BasicCommissioningInfo { get; }
162+
public RegulatoryLocationTypeEnum RegulatoryConfig { get; } = RegulatoryLocationTypeEnum.IndoorOutdoor;
163+
public RegulatoryLocationTypeEnum LocationCapability { get; } = RegulatoryLocationTypeEnum.IndoorOutdoor;
164+
public bool SupportsConcurrentConnection { get; } = true;
165+
}
166+
}

MatterDotNet/Clusters/NodeOperationalCredentialsCluster.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,11 @@ public override void Serialize(TLVWriter writer, long structNumber = -1) {
225225
}
226226

227227
// Commands
228-
public async Task<AttestationResponse?> AttestationRequest (Exchange exchange, byte[] AttestationNonce) {
228+
public async Task<AttestationResponse?> AttestationRequest (SecureSession session, byte[] AttestationNonce) {
229229
AttestationRequestPayload requestFields = new AttestationRequestPayload() {
230230
AttestationNonce = AttestationNonce,
231231
};
232-
InvokeResponseIB resp = await InteractionManager.ExecCommand(exchange, endPoint, CLUSTER_ID, 0x00, requestFields);
232+
InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x00, requestFields);
233233
if (!validateResponse(resp))
234234
return null;
235235
return new AttestationResponse() {
@@ -238,24 +238,24 @@ public override void Serialize(TLVWriter writer, long structNumber = -1) {
238238
};
239239
}
240240

241-
public async Task<CertificateChainResponse?> CertificateChainRequest (Exchange exchange, CertificateChainTypeEnum CertificateType) {
241+
public async Task<CertificateChainResponse?> CertificateChainRequest (SecureSession session, CertificateChainTypeEnum CertificateType) {
242242
CertificateChainRequestPayload requestFields = new CertificateChainRequestPayload() {
243243
CertificateType = CertificateType,
244244
};
245-
InvokeResponseIB resp = await InteractionManager.ExecCommand(exchange, endPoint, CLUSTER_ID, 0x02, requestFields);
245+
InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x02, requestFields);
246246
if (!validateResponse(resp))
247247
return null;
248248
return new CertificateChainResponse() {
249249
Certificate = (byte[])GetField(resp, 0),
250250
};
251251
}
252252

253-
public async Task<CSRResponse?> CSRRequest (Exchange exchange, byte[] CSRNonce, bool IsForUpdateNOC) {
253+
public async Task<CSRResponse?> CSRRequest (SecureSession session, byte[] CSRNonce, bool IsForUpdateNOC) {
254254
CSRRequestPayload requestFields = new CSRRequestPayload() {
255255
CSRNonce = CSRNonce,
256256
IsForUpdateNOC = IsForUpdateNOC,
257257
};
258-
InvokeResponseIB resp = await InteractionManager.ExecCommand(exchange, endPoint, CLUSTER_ID, 0x04, requestFields);
258+
InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x04, requestFields);
259259
if (!validateResponse(resp))
260260
return null;
261261
return new CSRResponse() {
@@ -264,15 +264,15 @@ public override void Serialize(TLVWriter writer, long structNumber = -1) {
264264
};
265265
}
266266

267-
public async Task<NOCResponse?> AddNOC (Exchange exchange, byte[] NOCValue, byte[] ICACValue, byte[] IPKValue, ulong CaseAdminSubject, ushort AdminVendorId) {
267+
public async Task<NOCResponse?> AddNOC (SecureSession session, byte[] NOCValue, byte[] ICACValue, byte[] IPKValue, ulong CaseAdminSubject, ushort AdminVendorId) {
268268
AddNOCPayload requestFields = new AddNOCPayload() {
269269
NOCValue = NOCValue,
270270
ICACValue = ICACValue,
271271
IPKValue = IPKValue,
272272
CaseAdminSubject = CaseAdminSubject,
273273
AdminVendorId = AdminVendorId,
274274
};
275-
InvokeResponseIB resp = await InteractionManager.ExecCommand(exchange, endPoint, CLUSTER_ID, 0x06, requestFields);
275+
InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x06, requestFields);
276276
if (!validateResponse(resp))
277277
return null;
278278
return new NOCResponse() {
@@ -282,12 +282,12 @@ public override void Serialize(TLVWriter writer, long structNumber = -1) {
282282
};
283283
}
284284

285-
public async Task<NOCResponse?> UpdateNOC (Exchange exchange, byte[] NOCValue, byte[] ICACValue) {
285+
public async Task<NOCResponse?> UpdateNOC (SecureSession session, byte[] NOCValue, byte[] ICACValue) {
286286
UpdateNOCPayload requestFields = new UpdateNOCPayload() {
287287
NOCValue = NOCValue,
288288
ICACValue = ICACValue,
289289
};
290-
InvokeResponseIB resp = await InteractionManager.ExecCommand(exchange, endPoint, CLUSTER_ID, 0x07, requestFields);
290+
InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x07, requestFields);
291291
if (!validateResponse(resp))
292292
return null;
293293
return new NOCResponse() {
@@ -297,11 +297,11 @@ public override void Serialize(TLVWriter writer, long structNumber = -1) {
297297
};
298298
}
299299

300-
public async Task<NOCResponse?> UpdateFabricLabel (Exchange exchange, string Label) {
300+
public async Task<NOCResponse?> UpdateFabricLabel (SecureSession session, string Label) {
301301
UpdateFabricLabelPayload requestFields = new UpdateFabricLabelPayload() {
302302
Label = Label,
303303
};
304-
InvokeResponseIB resp = await InteractionManager.ExecCommand(exchange, endPoint, CLUSTER_ID, 0x09, requestFields);
304+
InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x09, requestFields);
305305
if (!validateResponse(resp))
306306
return null;
307307
return new NOCResponse() {
@@ -311,11 +311,11 @@ public override void Serialize(TLVWriter writer, long structNumber = -1) {
311311
};
312312
}
313313

314-
public async Task<NOCResponse?> RemoveFabric (Exchange exchange, byte FabricIndex) {
314+
public async Task<NOCResponse?> RemoveFabric (SecureSession session, byte FabricIndex) {
315315
RemoveFabricPayload requestFields = new RemoveFabricPayload() {
316316
FabricIndex = FabricIndex,
317317
};
318-
InvokeResponseIB resp = await InteractionManager.ExecCommand(exchange, endPoint, CLUSTER_ID, 0x0A, requestFields);
318+
InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x0A, requestFields);
319319
if (!validateResponse(resp))
320320
return null;
321321
return new NOCResponse() {
@@ -325,11 +325,11 @@ public override void Serialize(TLVWriter writer, long structNumber = -1) {
325325
};
326326
}
327327

328-
public async Task<bool> AddTrustedRootCertificate (Exchange exchange, byte[] RootCACertificate) {
328+
public async Task<bool> AddTrustedRootCertificate (SecureSession session, byte[] RootCACertificate) {
329329
AddTrustedRootCertificatePayload requestFields = new AddTrustedRootCertificatePayload() {
330330
RootCACertificate = RootCACertificate,
331331
};
332-
InvokeResponseIB resp = await InteractionManager.ExecCommand(exchange, endPoint, CLUSTER_ID, 0x0B, requestFields);
332+
InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x0B, requestFields);
333333
return validateResponse(resp);
334334
}
335335

0 commit comments

Comments
 (0)