@matter/protocol 0.14.1-alpha.0-20250606-a9bcd03f9 → 0.15.0-alpha.0-20250612-ddd428561

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.
Files changed (211) hide show
  1. package/dist/cjs/certificate/AttestationCertificateManager.js +2 -2
  2. package/dist/cjs/certificate/AttestationCertificateManager.js.map +1 -1
  3. package/dist/cjs/certificate/CertificateAuthority.d.ts +2 -2
  4. package/dist/cjs/certificate/CertificateAuthority.d.ts.map +1 -1
  5. package/dist/cjs/certificate/CertificateAuthority.js +5 -5
  6. package/dist/cjs/certificate/CertificateAuthority.js.map +1 -1
  7. package/dist/cjs/certificate/CertificateManager.d.ts +1 -1
  8. package/dist/cjs/certificate/CertificateManager.d.ts.map +1 -1
  9. package/dist/cjs/certificate/CertificateManager.js +21 -10
  10. package/dist/cjs/certificate/CertificateManager.js.map +1 -1
  11. package/dist/cjs/certificate/CertificationDeclarationManager.d.ts +1 -1
  12. package/dist/cjs/certificate/DeviceCertification.d.ts +1 -1
  13. package/dist/cjs/certificate/DeviceCertification.d.ts.map +1 -1
  14. package/dist/cjs/certificate/DeviceCertification.js +5 -3
  15. package/dist/cjs/certificate/DeviceCertification.js.map +1 -1
  16. package/dist/cjs/cluster/client/ClusterClient.d.ts.map +1 -1
  17. package/dist/cjs/cluster/client/ClusterClient.js +6 -0
  18. package/dist/cjs/cluster/client/ClusterClient.js.map +1 -1
  19. package/dist/cjs/cluster/client/ClusterClientTypes.d.ts +4 -1
  20. package/dist/cjs/cluster/client/ClusterClientTypes.d.ts.map +1 -1
  21. package/dist/cjs/codec/BtpCodec.d.ts +1 -1
  22. package/dist/cjs/codec/MessageCodec.d.ts +1 -1
  23. package/dist/cjs/fabric/Fabric.d.ts +8 -6
  24. package/dist/cjs/fabric/Fabric.d.ts.map +1 -1
  25. package/dist/cjs/fabric/Fabric.js +22 -15
  26. package/dist/cjs/fabric/Fabric.js.map +1 -1
  27. package/dist/cjs/fabric/FabricAuthority.d.ts +4 -0
  28. package/dist/cjs/fabric/FabricAuthority.d.ts.map +1 -1
  29. package/dist/cjs/fabric/FabricAuthority.js +6 -0
  30. package/dist/cjs/fabric/FabricAuthority.js.map +1 -1
  31. package/dist/cjs/fabric/FabricManager.d.ts.map +1 -1
  32. package/dist/cjs/fabric/FabricManager.js +9 -2
  33. package/dist/cjs/fabric/FabricManager.js.map +1 -1
  34. package/dist/cjs/fabric/TestFabric.d.ts +30 -0
  35. package/dist/cjs/fabric/TestFabric.d.ts.map +1 -0
  36. package/dist/cjs/fabric/TestFabric.js +70 -0
  37. package/dist/cjs/fabric/TestFabric.js.map +6 -0
  38. package/dist/cjs/fabric/index.d.ts +1 -0
  39. package/dist/cjs/fabric/index.d.ts.map +1 -1
  40. package/dist/cjs/fabric/index.js +1 -0
  41. package/dist/cjs/fabric/index.js.map +1 -1
  42. package/dist/cjs/groups/{FabricGroupsManager.d.ts → FabricGroups.d.ts} +2 -2
  43. package/dist/cjs/groups/FabricGroups.d.ts.map +1 -0
  44. package/dist/cjs/groups/{FabricGroupsManager.js → FabricGroups.js} +9 -9
  45. package/dist/cjs/groups/FabricGroups.js.map +6 -0
  46. package/dist/cjs/groups/KeySets.js +1 -1
  47. package/dist/cjs/groups/KeySets.js.map +1 -1
  48. package/dist/cjs/groups/index.d.ts +1 -1
  49. package/dist/cjs/groups/index.d.ts.map +1 -1
  50. package/dist/cjs/groups/index.js +1 -1
  51. package/dist/cjs/groups/index.js.map +1 -1
  52. package/dist/cjs/interaction/{AccessControlManager.d.ts → FabricAccessControl.d.ts} +12 -7
  53. package/dist/cjs/interaction/FabricAccessControl.d.ts.map +1 -0
  54. package/dist/cjs/interaction/{AccessControlManager.js → FabricAccessControl.js} +46 -21
  55. package/dist/cjs/interaction/FabricAccessControl.js.map +6 -0
  56. package/dist/cjs/interaction/index.d.ts +1 -1
  57. package/dist/cjs/interaction/index.d.ts.map +1 -1
  58. package/dist/cjs/interaction/index.js +1 -1
  59. package/dist/cjs/interaction/index.js.map +1 -1
  60. package/dist/cjs/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  61. package/dist/cjs/peer/ControllerCommissioningFlow.js +2 -4
  62. package/dist/cjs/peer/ControllerCommissioningFlow.js.map +1 -1
  63. package/dist/cjs/protocol/DeviceCommissioner.js +1 -1
  64. package/dist/cjs/protocol/DeviceCommissioner.js.map +1 -1
  65. package/dist/cjs/protocol/MessageExchange.d.ts +6 -0
  66. package/dist/cjs/protocol/MessageExchange.d.ts.map +1 -1
  67. package/dist/cjs/protocol/MessageExchange.js +13 -0
  68. package/dist/cjs/protocol/MessageExchange.js.map +1 -1
  69. package/dist/cjs/securechannel/SecureChannelStatusMessageSchema.d.ts +1 -1
  70. package/dist/cjs/session/NodeSession.js +1 -1
  71. package/dist/cjs/session/Session.d.ts +1 -1
  72. package/dist/cjs/session/SessionManager.d.ts.map +1 -1
  73. package/dist/cjs/session/SessionManager.js +1 -0
  74. package/dist/cjs/session/SessionManager.js.map +1 -1
  75. package/dist/cjs/session/case/CaseClient.d.ts.map +1 -1
  76. package/dist/cjs/session/case/CaseClient.js +34 -30
  77. package/dist/cjs/session/case/CaseClient.js.map +1 -1
  78. package/dist/cjs/session/case/CaseMessages.d.ts +8 -8
  79. package/dist/cjs/session/case/CaseMessages.js +8 -8
  80. package/dist/cjs/session/case/CaseMessages.js.map +1 -1
  81. package/dist/cjs/session/case/CaseServer.d.ts.map +1 -1
  82. package/dist/cjs/session/case/CaseServer.js +26 -23
  83. package/dist/cjs/session/case/CaseServer.js.map +1 -1
  84. package/dist/cjs/session/pase/PaseClient.d.ts.map +1 -1
  85. package/dist/cjs/session/pase/PaseClient.js +4 -1
  86. package/dist/cjs/session/pase/PaseClient.js.map +1 -1
  87. package/dist/cjs/session/pase/PaseServer.d.ts.map +1 -1
  88. package/dist/cjs/session/pase/PaseServer.js +4 -1
  89. package/dist/cjs/session/pase/PaseServer.js.map +1 -1
  90. package/dist/esm/certificate/AttestationCertificateManager.js +2 -2
  91. package/dist/esm/certificate/AttestationCertificateManager.js.map +1 -1
  92. package/dist/esm/certificate/CertificateAuthority.d.ts +2 -2
  93. package/dist/esm/certificate/CertificateAuthority.d.ts.map +1 -1
  94. package/dist/esm/certificate/CertificateAuthority.js +5 -5
  95. package/dist/esm/certificate/CertificateAuthority.js.map +1 -1
  96. package/dist/esm/certificate/CertificateManager.d.ts +1 -1
  97. package/dist/esm/certificate/CertificateManager.d.ts.map +1 -1
  98. package/dist/esm/certificate/CertificateManager.js +22 -11
  99. package/dist/esm/certificate/CertificateManager.js.map +1 -1
  100. package/dist/esm/certificate/CertificationDeclarationManager.d.ts +1 -1
  101. package/dist/esm/certificate/DeviceCertification.d.ts +1 -1
  102. package/dist/esm/certificate/DeviceCertification.d.ts.map +1 -1
  103. package/dist/esm/certificate/DeviceCertification.js +5 -3
  104. package/dist/esm/certificate/DeviceCertification.js.map +1 -1
  105. package/dist/esm/cluster/client/ClusterClient.d.ts.map +1 -1
  106. package/dist/esm/cluster/client/ClusterClient.js +6 -0
  107. package/dist/esm/cluster/client/ClusterClient.js.map +1 -1
  108. package/dist/esm/cluster/client/ClusterClientTypes.d.ts +4 -1
  109. package/dist/esm/cluster/client/ClusterClientTypes.d.ts.map +1 -1
  110. package/dist/esm/codec/BtpCodec.d.ts +1 -1
  111. package/dist/esm/codec/MessageCodec.d.ts +1 -1
  112. package/dist/esm/fabric/Fabric.d.ts +8 -6
  113. package/dist/esm/fabric/Fabric.d.ts.map +1 -1
  114. package/dist/esm/fabric/Fabric.js +22 -14
  115. package/dist/esm/fabric/Fabric.js.map +1 -1
  116. package/dist/esm/fabric/FabricAuthority.d.ts +4 -0
  117. package/dist/esm/fabric/FabricAuthority.d.ts.map +1 -1
  118. package/dist/esm/fabric/FabricAuthority.js +6 -0
  119. package/dist/esm/fabric/FabricAuthority.js.map +1 -1
  120. package/dist/esm/fabric/FabricManager.d.ts.map +1 -1
  121. package/dist/esm/fabric/FabricManager.js +9 -2
  122. package/dist/esm/fabric/FabricManager.js.map +1 -1
  123. package/dist/esm/fabric/TestFabric.d.ts +30 -0
  124. package/dist/esm/fabric/TestFabric.d.ts.map +1 -0
  125. package/dist/esm/fabric/TestFabric.js +50 -0
  126. package/dist/esm/fabric/TestFabric.js.map +6 -0
  127. package/dist/esm/fabric/index.d.ts +1 -0
  128. package/dist/esm/fabric/index.d.ts.map +1 -1
  129. package/dist/esm/fabric/index.js +1 -0
  130. package/dist/esm/fabric/index.js.map +1 -1
  131. package/dist/esm/groups/{FabricGroupsManager.d.ts → FabricGroups.d.ts} +2 -2
  132. package/dist/esm/groups/FabricGroups.d.ts.map +1 -0
  133. package/dist/esm/groups/{FabricGroupsManager.js → FabricGroups.js} +6 -6
  134. package/dist/esm/groups/FabricGroups.js.map +6 -0
  135. package/dist/esm/groups/KeySets.js +1 -1
  136. package/dist/esm/groups/KeySets.js.map +1 -1
  137. package/dist/esm/groups/index.d.ts +1 -1
  138. package/dist/esm/groups/index.d.ts.map +1 -1
  139. package/dist/esm/groups/index.js +1 -1
  140. package/dist/esm/interaction/{AccessControlManager.d.ts → FabricAccessControl.d.ts} +12 -7
  141. package/dist/esm/interaction/FabricAccessControl.d.ts.map +1 -0
  142. package/dist/esm/interaction/{AccessControlManager.js → FabricAccessControl.js} +44 -19
  143. package/dist/esm/interaction/FabricAccessControl.js.map +6 -0
  144. package/dist/esm/interaction/index.d.ts +1 -1
  145. package/dist/esm/interaction/index.d.ts.map +1 -1
  146. package/dist/esm/interaction/index.js +1 -1
  147. package/dist/esm/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  148. package/dist/esm/peer/ControllerCommissioningFlow.js +2 -4
  149. package/dist/esm/peer/ControllerCommissioningFlow.js.map +1 -1
  150. package/dist/esm/protocol/DeviceCommissioner.js +1 -1
  151. package/dist/esm/protocol/DeviceCommissioner.js.map +1 -1
  152. package/dist/esm/protocol/MessageExchange.d.ts +6 -0
  153. package/dist/esm/protocol/MessageExchange.d.ts.map +1 -1
  154. package/dist/esm/protocol/MessageExchange.js +13 -0
  155. package/dist/esm/protocol/MessageExchange.js.map +1 -1
  156. package/dist/esm/securechannel/SecureChannelStatusMessageSchema.d.ts +1 -1
  157. package/dist/esm/session/NodeSession.js +1 -1
  158. package/dist/esm/session/Session.d.ts +1 -1
  159. package/dist/esm/session/SessionManager.d.ts.map +1 -1
  160. package/dist/esm/session/SessionManager.js +1 -0
  161. package/dist/esm/session/SessionManager.js.map +1 -1
  162. package/dist/esm/session/case/CaseClient.d.ts.map +1 -1
  163. package/dist/esm/session/case/CaseClient.js +34 -30
  164. package/dist/esm/session/case/CaseClient.js.map +1 -1
  165. package/dist/esm/session/case/CaseMessages.d.ts +8 -8
  166. package/dist/esm/session/case/CaseMessages.js +8 -8
  167. package/dist/esm/session/case/CaseMessages.js.map +1 -1
  168. package/dist/esm/session/case/CaseServer.d.ts.map +1 -1
  169. package/dist/esm/session/case/CaseServer.js +26 -23
  170. package/dist/esm/session/case/CaseServer.js.map +1 -1
  171. package/dist/esm/session/pase/PaseClient.d.ts.map +1 -1
  172. package/dist/esm/session/pase/PaseClient.js +4 -1
  173. package/dist/esm/session/pase/PaseClient.js.map +1 -1
  174. package/dist/esm/session/pase/PaseServer.d.ts.map +1 -1
  175. package/dist/esm/session/pase/PaseServer.js +4 -1
  176. package/dist/esm/session/pase/PaseServer.js.map +1 -1
  177. package/package.json +6 -6
  178. package/src/certificate/AttestationCertificateManager.ts +2 -2
  179. package/src/certificate/CertificateAuthority.ts +7 -7
  180. package/src/certificate/CertificateManager.ts +22 -11
  181. package/src/certificate/DeviceCertification.ts +5 -3
  182. package/src/cluster/client/ClusterClient.ts +7 -0
  183. package/src/cluster/client/ClusterClientTypes.ts +7 -0
  184. package/src/fabric/Fabric.ts +24 -15
  185. package/src/fabric/FabricAuthority.ts +7 -0
  186. package/src/fabric/FabricManager.ts +9 -2
  187. package/src/fabric/TestFabric.ts +73 -0
  188. package/src/fabric/index.ts +1 -0
  189. package/src/groups/{FabricGroupsManager.ts → FabricGroups.ts} +4 -4
  190. package/src/groups/KeySets.ts +1 -1
  191. package/src/groups/index.ts +1 -1
  192. package/src/interaction/{AccessControlManager.ts → FabricAccessControl.ts} +61 -25
  193. package/src/interaction/index.ts +1 -1
  194. package/src/peer/ControllerCommissioningFlow.ts +2 -4
  195. package/src/protocol/DeviceCommissioner.ts +1 -1
  196. package/src/protocol/MessageExchange.ts +14 -0
  197. package/src/session/NodeSession.ts +1 -1
  198. package/src/session/SessionManager.ts +1 -0
  199. package/src/session/case/CaseClient.ts +34 -30
  200. package/src/session/case/CaseMessages.ts +8 -8
  201. package/src/session/case/CaseServer.ts +27 -23
  202. package/src/session/pase/PaseClient.ts +4 -1
  203. package/src/session/pase/PaseServer.ts +4 -1
  204. package/dist/cjs/groups/FabricGroupsManager.d.ts.map +0 -1
  205. package/dist/cjs/groups/FabricGroupsManager.js.map +0 -6
  206. package/dist/cjs/interaction/AccessControlManager.d.ts.map +0 -1
  207. package/dist/cjs/interaction/AccessControlManager.js.map +0 -6
  208. package/dist/esm/groups/FabricGroupsManager.d.ts.map +0 -1
  209. package/dist/esm/groups/FabricGroupsManager.js.map +0 -6
  210. package/dist/esm/interaction/AccessControlManager.d.ts.map +0 -1
  211. package/dist/esm/interaction/AccessControlManager.js.map +0 -6
@@ -5,12 +5,12 @@
5
5
  */
6
6
 
7
7
  import {
8
- BitByteArray,
9
8
  Bytes,
10
9
  ContextTagged,
11
10
  ContextTaggedBytes,
12
11
  Crypto,
13
12
  DatatypeOverride,
13
+ DerBitString,
14
14
  DerCodec,
15
15
  DerKey,
16
16
  DerObject,
@@ -666,10 +666,11 @@ export namespace CertificateManager {
666
666
 
667
667
  export async function deviceAttestationCertToAsn1(cert: Unsigned<DeviceAttestationCertificate>, key: Key) {
668
668
  const certificate = genericBuildAsn1Structure(cert);
669
+ const signature = await Crypto.signEcdsa(key, DerCodec.encode(certificate), "der");
669
670
  const certBytes = DerCodec.encode({
670
671
  certificate,
671
672
  signAlgorithm: X962.EcdsaWithSHA256,
672
- signature: BitByteArray(await Crypto.sign(key, DerCodec.encode(certificate), "der")),
673
+ signature: DerBitString(signature),
673
674
  });
674
675
  assertCertificateDerSize(certBytes);
675
676
  return certBytes;
@@ -680,10 +681,11 @@ export namespace CertificateManager {
680
681
  key: Key,
681
682
  ) {
682
683
  const certificate = genericBuildAsn1Structure(cert);
684
+ const signature = await Crypto.signEcdsa(key, DerCodec.encode(certificate), "der");
683
685
  const certBytes = DerCodec.encode({
684
686
  certificate,
685
687
  signAlgorithm: X962.EcdsaWithSHA256,
686
- signature: BitByteArray(await Crypto.sign(key, DerCodec.encode(certificate), "der")),
688
+ signature: DerBitString(signature),
687
689
  });
688
690
  assertCertificateDerSize(certBytes);
689
691
  return certBytes;
@@ -697,13 +699,13 @@ export namespace CertificateManager {
697
699
  const certBytes = DerCodec.encode({
698
700
  certificate,
699
701
  signAlgorithm: X962.EcdsaWithSHA256,
700
- signature: BitByteArray(await Crypto.sign(key, DerCodec.encode(certificate), "der")),
702
+ signature: DerBitString(await Crypto.signEcdsa(key, DerCodec.encode(certificate), "der")),
701
703
  });
702
704
  assertCertificateDerSize(certBytes);
703
705
  return certBytes;
704
706
  }
705
707
 
706
- export function certificationDeclarationToAsn1(
708
+ export async function certificationDeclarationToAsn1(
707
709
  eContent: Uint8Array,
708
710
  subjectKeyIdentifier: Uint8Array,
709
711
  privateKey: JsonWebKey,
@@ -718,7 +720,7 @@ export namespace CertificateManager {
718
720
  subjectKeyIdentifier: ContextTaggedBytes(0, subjectKeyIdentifier),
719
721
  digestAlgorithm: SHA256_CMS,
720
722
  signatureAlgorithm: X962.EcdsaWithSHA256,
721
- signature: Crypto.sign(privateKey, eContent, "der"),
723
+ signature: await Crypto.signEcdsa(privateKey, eContent, "der"),
722
724
  },
723
725
  ],
724
726
  };
@@ -861,7 +863,11 @@ export namespace CertificateManager {
861
863
  );
862
864
  }
863
865
 
864
- await Crypto.verify(PublicKey(rootCert.ellipticCurvePublicKey), rootCertToAsn1(rootCert), rootCert.signature);
866
+ await Crypto.verifyEcdsa(
867
+ PublicKey(rootCert.ellipticCurvePublicKey),
868
+ rootCertToAsn1(rootCert),
869
+ rootCert.signature,
870
+ );
865
871
  }
866
872
 
867
873
  /**
@@ -985,7 +991,7 @@ export namespace CertificateManager {
985
991
  );
986
992
  }
987
993
 
988
- await Crypto.verify(
994
+ await Crypto.verifyEcdsa(
989
995
  PublicKey((icaCert ?? rootCert).ellipticCurvePublicKey),
990
996
  nodeOperationalCertToAsn1(nocCert),
991
997
  nocCert.signature,
@@ -1103,7 +1109,7 @@ export namespace CertificateManager {
1103
1109
  );
1104
1110
  }
1105
1111
 
1106
- await Crypto.verify(
1112
+ await Crypto.verifyEcdsa(
1107
1113
  PublicKey(rootCert.ellipticCurvePublicKey),
1108
1114
  intermediateCaCertToAsn1(icaCert),
1109
1115
  icaCert.signature,
@@ -1121,7 +1127,7 @@ export namespace CertificateManager {
1121
1127
  return DerCodec.encode({
1122
1128
  request,
1123
1129
  signAlgorithm: X962.EcdsaWithSHA256,
1124
- signature: BitByteArray(await Crypto.sign(key, DerCodec.encode(request), "der")),
1130
+ signature: DerBitString(await Crypto.signEcdsa(key, DerCodec.encode(request), "der")),
1125
1131
  });
1126
1132
  }
1127
1133
 
@@ -1153,7 +1159,12 @@ export namespace CertificateManager {
1153
1159
  )
1154
1160
  )
1155
1161
  throw new CertificateError("Unsupported signature type");
1156
- await Crypto.verify(PublicKey(publicKey), DerCodec.encode(requestNode), signatureNode[DerKey.Bytes], "der");
1162
+ await Crypto.verifyEcdsa(
1163
+ PublicKey(publicKey),
1164
+ DerCodec.encode(requestNode),
1165
+ signatureNode[DerKey.Bytes],
1166
+ "der",
1167
+ );
1157
1168
 
1158
1169
  return publicKey;
1159
1170
  }
@@ -55,7 +55,7 @@ export class DeviceCertification {
55
55
  privateKey: PrivateKey(dacKeyPair.privateKey),
56
56
  certificate: dac,
57
57
  intermediateCertificate: await paa.getPAICert(),
58
- declaration: CertificationDeclarationManager.generate(product.vendorId, product.productId),
58
+ declaration: await CertificationDeclarationManager.generate(product.vendorId, product.productId),
59
59
  };
60
60
  };
61
61
  }
@@ -71,8 +71,10 @@ export class DeviceCertification {
71
71
  });
72
72
  }
73
73
 
74
- sign(session: NodeSession, data: Uint8Array) {
75
- return Crypto.sign(this.#assertInitialized().privateKey, [data, session.attestationChallengeKey]);
74
+ async sign(session: NodeSession, data: Uint8Array) {
75
+ const { privateKey } = this.#assertInitialized();
76
+ const signature = await Crypto.signEcdsa(privateKey, [data, session.attestationChallengeKey]);
77
+ return signature;
76
78
  }
77
79
 
78
80
  /**
@@ -91,6 +91,13 @@ export function ClusterClient<const T extends ClusterType>(
91
91
  throw e;
92
92
  }
93
93
  };
94
+ result[`get${capitalizedAttributeName}AttributeFromCache`] = () => {
95
+ if (isGroupAddress) {
96
+ throw new ImplementationError("Group cluster clients do not support reading attributes");
97
+ }
98
+
99
+ return (attributes as any)[attributeName].getLocal();
100
+ };
94
101
  result[`set${capitalizedAttributeName}Attribute`] = async <T>(value: T, dataVersion?: number) =>
95
102
  (attributes as any)[attributeName].set(value, dataVersion);
96
103
  result[`subscribe${capitalizedAttributeName}Attribute`] = async <T>(
@@ -100,6 +100,12 @@ type ClientAttributeGetters<A extends Attributes> = Omit<
100
100
  },
101
101
  keyof GlobalAttributes<any>
102
102
  >;
103
+ type ClientLocalAttributeGetters<A extends Attributes> = Omit<
104
+ {
105
+ [P in keyof A as `get${Capitalize<string & P>}AttributeFromCache`]: () => GetterTypeFromSpec<A[P]> | undefined;
106
+ },
107
+ keyof GlobalAttributes<any>
108
+ >;
103
109
  type ClientGlobalAttributeGetters<F extends BitSchema> = {
104
110
  [P in GlobalAttributeNames<F> as `get${Capitalize<string & P>}Attribute`]: () => Promise<
105
111
  GetterTypeFromSpec<GlobalAttributes<F>[P]>
@@ -265,6 +271,7 @@ export type ClusterClientObj<T extends ClusterType = ClusterType> = BaseClusterC
265
271
  /** Returns if a given Command with provided name is present and supported at the connected cluster server. */
266
272
  isCommandSupportedByName: (commandName: string) => boolean;
267
273
  } & ClientAttributeGetters<T["attributes"]> &
274
+ ClientLocalAttributeGetters<T["attributes"]> &
268
275
  ClientGlobalAttributeGetters<T["features"]> &
269
276
  ClientAttributeSubscribers<T["attributes"]> &
270
277
  ClientAttributeListeners<T["attributes"]> &
@@ -15,6 +15,7 @@ import {
15
15
  Bytes,
16
16
  Crypto,
17
17
  DataWriter,
18
+ Diagnostic,
18
19
  Endian,
19
20
  ImplementationError,
20
21
  InternalError,
@@ -26,7 +27,8 @@ import {
26
27
  PrivateKey,
27
28
  StorageContext,
28
29
  } from "#general";
29
- import { FabricGroupsManager, GROUP_SECURITY_INFO } from "#groups/FabricGroupsManager.js";
30
+ import { FabricGroups, GROUP_SECURITY_INFO } from "#groups/FabricGroups.js";
31
+ import { FabricAccessControl } from "#interaction/FabricAccessControl.js";
30
32
  import { PeerAddress } from "#peer/PeerAddress.js";
31
33
  import { Session } from "#session/Session.js";
32
34
  import { CaseAuthenticatedTag, FabricId, FabricIndex, GroupId, NodeId, VendorId } from "#types";
@@ -61,7 +63,8 @@ export class Fabric {
61
63
  readonly operationalCert: Uint8Array;
62
64
  readonly #keyPair: Key;
63
65
  readonly #sessions = new Set<Session>();
64
- readonly #groupManager: FabricGroupsManager;
66
+ readonly #groupManager: FabricGroups;
67
+ readonly #aclManager: FabricAccessControl;
65
68
  #label: string;
66
69
  #removeCallbacks = new Array<() => MaybePromise<void>>();
67
70
  #persistCallback: ((isUpdate?: boolean) => MaybePromise<void>) | undefined;
@@ -82,7 +85,8 @@ export class Fabric {
82
85
  this.operationalCert = config.operationalCert;
83
86
  this.#label = config.label;
84
87
  this.#keyPair = PrivateKey(config.keyPair);
85
- this.#groupManager = new FabricGroupsManager(this);
88
+ this.#aclManager = new FabricAccessControl(this);
89
+ this.#groupManager = new FabricGroups(this);
86
90
  }
87
91
 
88
92
  get config(): Fabric.Config {
@@ -132,12 +136,16 @@ export class Fabric {
132
136
  return this.#groupManager;
133
137
  }
134
138
 
139
+ get acl() {
140
+ return this.#aclManager;
141
+ }
142
+
135
143
  get publicKey() {
136
144
  return this.#keyPair.publicKey;
137
145
  }
138
146
 
139
147
  sign(data: Uint8Array) {
140
- return Crypto.sign(this.#keyPair, data);
148
+ return Crypto.signEcdsa(this.#keyPair, data);
141
149
  }
142
150
 
143
151
  async verifyCredentials(operationalCert: Uint8Array, intermediateCACert?: Uint8Array) {
@@ -174,21 +182,21 @@ export class Fabric {
174
182
  }
175
183
 
176
184
  /**
177
- * Returns the destination IDs for a given nodeId, random value and optional groupId.
178
- * When groupId is provided, it returns the time-wise valid operational keys for that groupId.
185
+ * Returns the destination IDs for a given nodeId, random value and optional groupId. When groupId is provided, it
186
+ * returns the time-wise valid operational keys for that groupId.
179
187
  */
180
188
  async currentDestinationIdFor(nodeId: NodeId, random: Uint8Array) {
181
- return await Crypto.hmac(this.groups.keySets.currentKeyForId(0).key, this.#generateSalt(nodeId, random));
189
+ return await Crypto.signHmac(this.groups.keySets.currentKeyForId(0).key, this.#generateSalt(nodeId, random));
182
190
  }
183
191
 
184
192
  /**
185
- * Returns the destination IDs for a given nodeId, random value and optional groupId.
186
- * When groupId is provided, it returns all operational keys for that groupId.
193
+ * Returns the destination IDs for a given nodeId, random value and optional groupId. When groupId is provided, it
194
+ * returns all operational keys for that groupId.
187
195
  */
188
196
  async destinationIdsFor(nodeId: NodeId, random: Uint8Array) {
189
197
  const salt = this.#generateSalt(nodeId, random);
190
198
  // Check all keys of keyset 0 - typically it is only the IPK
191
- const destinationIds = this.groups.keySets.allKeysForId(0).map(({ key }) => Crypto.hmac(key, salt));
199
+ const destinationIds = this.groups.keySets.allKeysForId(0).map(({ key }) => Crypto.signHmac(key, salt));
192
200
  return await Promise.all(destinationIds);
193
201
  }
194
202
 
@@ -306,18 +314,19 @@ export class FabricBuilder {
306
314
  ellipticCurvePublicKey,
307
315
  } = TlvOperationalCertificate.decode(operationalCert);
308
316
  logger.debug(
309
- `FabricBuilder setOperationalCert: nodeId=${nodeId}, fabricId=${fabricId}, caseAuthenticatedTags=${caseAuthenticatedTags}`,
317
+ "Installing operational certificate",
318
+ Diagnostic.dict({ nodeId, fabricId, caseAuthenticatedTags }),
310
319
  );
311
320
  if (caseAuthenticatedTags !== undefined) {
312
321
  CaseAuthenticatedTag.validateNocTagList(caseAuthenticatedTags);
313
322
  }
314
323
 
315
324
  if (!Bytes.areEqual(ellipticCurvePublicKey, this.#keyPair.publicKey)) {
316
- throw new PublicKeyError("Operational Certificate does not match public key.");
325
+ throw new PublicKeyError("Operational certificate does not match public key");
317
326
  }
318
327
 
319
328
  if (this.#rootCert === undefined) {
320
- throw new MatterFlowError("Root Certificate needs to be set first.");
329
+ throw new MatterFlowError("Root certificate needs to be set first");
321
330
  }
322
331
 
323
332
  const rootCert = TlvRootCertificate.decode(this.#rootCert);
@@ -401,7 +410,7 @@ export class FabricBuilder {
401
410
  this.#fabricIndex = fabricIndex;
402
411
  const saltWriter = new DataWriter();
403
412
  saltWriter.writeUInt64(this.#fabricId);
404
- const operationalId = await Crypto.hkdf(
413
+ const operationalId = await Crypto.createHkdfKey(
405
414
  this.#rootPublicKey.slice(1),
406
415
  saltWriter.toByteArray(),
407
416
  COMPRESSED_FABRIC_ID_INFO,
@@ -419,7 +428,7 @@ export class FabricBuilder {
419
428
  rootVendorId: this.#rootVendorId,
420
429
  rootCert: this.#rootCert,
421
430
  identityProtectionKey: this.#identityProtectionKey, // Epoch Key
422
- operationalIdentityProtectionKey: await Crypto.hkdf(
431
+ operationalIdentityProtectionKey: await Crypto.createHkdfKey(
423
432
  this.#identityProtectionKey,
424
433
  operationalId,
425
434
  GROUP_SECURITY_INFO,
@@ -66,6 +66,13 @@ export class FabricAuthority {
66
66
  this.#config = context.config;
67
67
  }
68
68
 
69
+ /**
70
+ * Access the certificate authority.
71
+ */
72
+ get ca() {
73
+ return this.#ca;
74
+ }
75
+
69
76
  /**
70
77
  * Obtain the default fabric for this authority.
71
78
  */
@@ -160,6 +160,9 @@ export class FabricManager {
160
160
  this.#fabrics.set(fabricIndex, fabric);
161
161
  fabric.addRemoveCallback(async () => this.removeFabric(fabricIndex));
162
162
  fabric.persistCallback = (isUpdate = true) => {
163
+ if (!this.#storage) {
164
+ return;
165
+ }
163
166
  const persistResult = this.persistFabrics();
164
167
  return MaybePromise.then(persistResult, () => {
165
168
  if (isUpdate) {
@@ -184,7 +187,9 @@ export class FabricManager {
184
187
  `Fabric with index ${fabricIndex} cannot be removed because it does not exist.`,
185
188
  );
186
189
  this.#fabrics.delete(fabricIndex);
187
- await this.persistFabrics();
190
+ if (this.#storage) {
191
+ await this.persistFabrics();
192
+ }
188
193
  await fabric.storage?.clearAll();
189
194
  this.#events.deleted.emit(fabric);
190
195
  }
@@ -253,7 +258,9 @@ export class FabricManager {
253
258
  );
254
259
  }
255
260
  this.#fabrics.set(fabricIndex, fabric);
256
- await this.persistFabrics();
261
+ if (this.#storage) {
262
+ await this.persistFabrics();
263
+ }
257
264
  this.#events.updated.emit(fabric);
258
265
  }
259
266
 
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Project CHIP Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { CertificateAuthority } from "#certificate/CertificateAuthority.js";
8
+ import { ImplementationError, nonentropic } from "#general";
9
+ import { FabricIndex, VendorId } from "#types";
10
+ import { FabricAuthority } from "./FabricAuthority.js";
11
+ import { FabricManager } from "./FabricManager.js";
12
+
13
+ /**
14
+ * WARNING: ONLY FOR USE IN PROTECTED TESTING ENVIRONMENTS WHERE SECURITY IS NOT A CONCERN
15
+ *
16
+ * Generate a fabric useful for testing purposes.
17
+ *
18
+ * The properties of the fabric, including crypto matter, are stable with regards to {@link index}.
19
+ */
20
+ export async function TestFabric(options: TestFabric.Options = {}) {
21
+ const authority = await TestFabric.Authority(options);
22
+
23
+ return authority.createFabric();
24
+ }
25
+
26
+ export namespace TestFabric {
27
+ /**
28
+ * WARNING: ONLY FOR USE IN PROTECTED TESTING ENVIRONMENTS WHERE SECURITY IS NOT A CONCERN
29
+ *
30
+ * Obtain a test authority.
31
+ *
32
+ * Crypto matter is stable with respect to {@link index}.
33
+ */
34
+ export async function Authority({ index, fabrics }: Options = {}) {
35
+ if (index === undefined) {
36
+ if (fabrics) {
37
+ index = fabrics.allocateFabricIndex();
38
+ } else {
39
+ index = 1;
40
+ }
41
+ }
42
+
43
+ return forFabric(index, async () => {
44
+ const authority = new FabricAuthority({
45
+ ca: await CertificateAuthority.create(),
46
+ config: {
47
+ adminFabricLabel: `mock-fabric-${index}`,
48
+ adminVendorId: VendorId(0xfff1),
49
+ fabricIndex: FabricIndex(index),
50
+ },
51
+ fabrics: fabrics ?? new FabricManager(),
52
+ });
53
+
54
+ const createFabric = authority.createFabric.bind(authority);
55
+ authority.createFabric = () => forFabric(index ?? 1, createFabric);
56
+
57
+ return authority;
58
+ });
59
+ }
60
+
61
+ export interface Options {
62
+ index?: number;
63
+ fabrics?: FabricManager;
64
+ }
65
+ }
66
+
67
+ async function forFabric<T>(index: number, actor: () => Promise<T>): Promise<T> {
68
+ if (index < 1 || index > 254) {
69
+ throw new ImplementationError("Test fabric indexes must be in the range 1-254");
70
+ }
71
+
72
+ return nonentropic(index, actor);
73
+ }
@@ -7,3 +7,4 @@
7
7
  export * from "./Fabric.js";
8
8
  export * from "./FabricAuthority.js";
9
9
  export * from "./FabricManager.js";
10
+ export * from "./TestFabric.js";
@@ -15,7 +15,7 @@ export const GROUP_SECURITY_INFO = Bytes.fromString("GroupKey v1.0");
15
15
  /**
16
16
  * Class that contains an operational view on the Group Keys for a fabric
17
17
  */
18
- export class FabricGroupsManager {
18
+ export class FabricGroups {
19
19
  #fabric: Fabric;
20
20
  #groups: Groups;
21
21
  #messagingState: MessagingState;
@@ -122,11 +122,11 @@ export class FabricGroupsManager {
122
122
 
123
123
  // Lets pre-calculate the operational keys
124
124
  const operationalId = this.#fabric.operationalId;
125
- const operationalEpochKey0 = await Crypto.hkdf(epochKey0, operationalId, GROUP_SECURITY_INFO);
125
+ const operationalEpochKey0 = await Crypto.createHkdfKey(epochKey0, operationalId, GROUP_SECURITY_INFO);
126
126
  const operationalEpochKey1 =
127
- epochKey1 !== null ? await Crypto.hkdf(epochKey1, operationalId, GROUP_SECURITY_INFO) : null;
127
+ epochKey1 !== null ? await Crypto.createHkdfKey(epochKey1, operationalId, GROUP_SECURITY_INFO) : null;
128
128
  const operationalEpochKey2 =
129
- epochKey2 !== null ? await Crypto.hkdf(epochKey2, operationalId, GROUP_SECURITY_INFO) : null;
129
+ epochKey2 !== null ? await Crypto.createHkdfKey(epochKey2, operationalId, GROUP_SECURITY_INFO) : null;
130
130
  this.#keySets.add({
131
131
  ...groupKeySet,
132
132
  operationalEpochKey0,
@@ -143,7 +143,7 @@ export class KeySets<T extends OperationalKeySet> extends BasicSet<T> {
143
143
  /** Calculates a group session id based on the operational group key. */
144
144
  async sessionIdFromKey(operationalGroupKey: Uint8Array) {
145
145
  // GroupKeyHash is an array of 2 bytes (16 bits) per Crypto_KDF
146
- const groupKeyHash = await Crypto.hkdf(operationalGroupKey, new Uint8Array(), GROUP_KEY_INFO, 2);
146
+ const groupKeyHash = await Crypto.createHkdfKey(operationalGroupKey, new Uint8Array(), GROUP_KEY_INFO, 2);
147
147
 
148
148
  // GroupSessionId is computed by considering the GroupKeyHash as a Big-Endian value. GroupSessionId is a scalar.
149
149
  // Its use in fields within messages may cause a re-serialization into a different byte order than the one used
@@ -4,5 +4,5 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- export * from "./FabricGroupsManager.js";
7
+ export * from "./FabricGroups.js";
8
8
  export * from "./KeySets.js";
@@ -5,7 +5,8 @@
5
5
  */
6
6
  import { Subject } from "#action/server/Subject.js";
7
7
  import { AccessControl } from "#clusters/access-control";
8
- import { MatterFlowError } from "#general";
8
+ import { Fabric } from "#fabric/Fabric.js";
9
+ import { InternalError, Logger, MatterFlowError } from "#general";
9
10
  import { AccessLevel } from "#model";
10
11
  import {
11
12
  CaseAuthenticatedTag,
@@ -20,6 +21,8 @@ import {
20
21
  } from "#types";
21
22
  import { AccessControl as AccessControlContext } from "../action/server/AccessControl.js";
22
23
 
24
+ const logger = Logger.get("FabricAccessControlManager");
25
+
23
26
  export type AclEntry = Omit<AccessControl.AccessControlEntry, "privilege"> & {
24
27
  privilege: AccessLevel;
25
28
  };
@@ -59,10 +62,11 @@ export class AccessDeniedError extends StatusResponseError {
59
62
  }
60
63
 
61
64
  /**
62
- * Implements Access Control Logic as per Matter Specification @see {@link MatterSpecification.v12.Core} § 6.6.5.2.
65
+ * Implements Access Control Logic For one fabric as per Matter Specification @see {@link MatterSpecification.v12.Core} § 6.6.5.2.
63
66
  */
64
- export class AccessControlManager {
65
- #aclList: AclList;
67
+ export class FabricAccessControl {
68
+ #fabricIndex: FabricIndex;
69
+ #aclList: AclList = [];
66
70
  #extensionEntryAccessCheck: (
67
71
  aclList: AclList,
68
72
  aclEntry: AclEntry,
@@ -71,9 +75,36 @@ export class AccessControlManager {
71
75
  clusterId: ClusterId,
72
76
  ) => boolean = () => true;
73
77
 
74
- constructor(
75
- aclList: AccessControl.AccessControlEntry[] = [],
76
- extensionEntryAccessCheck?: (
78
+ constructor(fabric?: Fabric) {
79
+ if (fabric === undefined) {
80
+ this.#fabricIndex = FabricIndex.NO_FABRIC;
81
+ // Add the implicit default PASE ACL entry for the fabric
82
+ this.#aclList.push(ImplicitDefaultPaseAclEntry);
83
+ } else {
84
+ this.#fabricIndex = fabric.fabricIndex;
85
+ }
86
+ }
87
+
88
+ set fabricIndex(fabricIndex: FabricIndex) {
89
+ if (this.#fabricIndex === undefined || this.#fabricIndex === FabricIndex.NO_FABRIC) {
90
+ this.#fabricIndex = fabricIndex;
91
+ }
92
+ throw new InternalError("Can not overwrite FabricIndex");
93
+ }
94
+
95
+ /**
96
+ * Public method used to update the Access Control List on changes.
97
+ */
98
+ set aclList(aclList: AccessControl.AccessControlEntry[]) {
99
+ if (aclList.some(({ fabricIndex }) => fabricIndex !== this.#fabricIndex)) {
100
+ throw new InternalError("ACL entries must match the fabric index of the manager");
101
+ }
102
+ this.#aclList = [...aclList] as unknown as AclList; // It is the same structure we just use an internal type for privilege
103
+ logger.info("ACL List updated for FabricIndex ", this.#fabricIndex, this.#aclList);
104
+ }
105
+
106
+ set extensionEntryAccessCheck(
107
+ func: (
77
108
  aclList: AclList,
78
109
  aclEntry: AclEntry,
79
110
  subjectDesc: IncomingSubjectDescriptor,
@@ -81,24 +112,31 @@ export class AccessControlManager {
81
112
  clusterId: ClusterId,
82
113
  ) => boolean,
83
114
  ) {
84
- this.#aclList = aclList as unknown as AclList; // It is the same structure we just use an internal type for privilege
85
- if (extensionEntryAccessCheck !== undefined) {
86
- this.#extensionEntryAccessCheck = extensionEntryAccessCheck;
87
- }
115
+ this.#extensionEntryAccessCheck = func;
88
116
  }
89
117
 
90
118
  /**
91
- * Public method used to update the Access Control List on changes.
119
+ * Implements the access control check for the given context, location and endpoint and is called by the
120
+ * InteractionServer. The method returns the list of granted Access privileges for the given context, location and
121
+ * endpoint.
92
122
  */
93
- updateAccessControlList(aclList: AccessControl.AccessControlEntry[] = []): void {
94
- this.#aclList = [...aclList] as unknown as AclList; // It is the same structure we just use an internal type for privilege
95
- }
123
+ accessLevelsFor(
124
+ context: AccessControlContext.Session,
125
+ location: AccessControlContext.Location,
126
+ endpoint?: AclEndpointContext,
127
+ ): AccessLevel[] {
128
+ if (location.cluster === undefined) {
129
+ // Without a cluster, internal behaviors are only accessible internally, so this is an irrelevant placeholder
130
+ logger.warn("Access control check without cluster, returning View access level");
131
+ return [AccessLevel.View];
132
+ }
133
+ if (endpoint === undefined) {
134
+ // Without an endpoint, we can't determine access levels, ???
135
+ logger.warn("Access control check without endpoint, returning View access level");
136
+ return [AccessLevel.View];
137
+ }
96
138
 
97
- /**
98
- * Get the Access Control List for a given fabric.
99
- */
100
- #getAccessControlEntriesForFabric(fabricIndex: FabricIndex): AclList {
101
- return this.#aclList.filter(entry => entry.fabricIndex === fabricIndex);
139
+ return this.#getGrantedPrivileges(context, endpoint, location.cluster);
102
140
  }
103
141
 
104
142
  /**
@@ -152,15 +190,13 @@ export class AccessControlManager {
152
190
  /**
153
191
  * Determines the granted privileges for the given session, endpoint, and cluster ID and returns them.
154
192
  */
155
- getGrantedPrivileges(
193
+ #getGrantedPrivileges(
156
194
  context: AccessControlContext.Session,
157
195
  endpoint: AclEndpointContext,
158
196
  clusterId: ClusterId,
159
197
  ): AccessLevel[] {
160
198
  const endpointId = endpoint.id;
161
- const fabric = context.fabric;
162
199
  const subjectDesc = this.#getIsdFromMessage(context);
163
- const acl = fabric ? this.#getAccessControlEntriesForFabric(fabric) : [ImplicitDefaultPaseAclEntry];
164
200
 
165
201
  // Granted privileges set is initially empty
166
202
  const grantedPrivileges = new Set<AccessLevel>();
@@ -170,7 +206,7 @@ export class AccessControlManager {
170
206
  this.#addGrantedPrivilege(grantedPrivileges, AccessLevel.Administer);
171
207
  }
172
208
 
173
- for (const aclEntry of acl) {
209
+ for (const aclEntry of this.#aclList) {
174
210
  if (grantedPrivileges.has(AccessLevel.Administer)) {
175
211
  // End checking if highest privilege is granted
176
212
  break;
@@ -254,7 +290,7 @@ export class AccessControlManager {
254
290
  }
255
291
 
256
292
  // Extensions processing must not fail
257
- if (!this.#extensionEntryAccessCheck(acl, aclEntry, subjectDesc, endpoint, clusterId)) {
293
+ if (!this.#extensionEntryAccessCheck(this.#aclList, aclEntry, subjectDesc, endpoint, clusterId)) {
258
294
  continue;
259
295
  }
260
296
 
@@ -4,10 +4,10 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- export * from "./AccessControlManager.js";
8
7
  export * from "./AttributeDataDecoder.js";
9
8
  export * from "./AttributeDataEncoder.js";
10
9
  export * from "./EventDataDecoder.js";
10
+ export * from "./FabricAccessControl.js";
11
11
  export * from "./InteractionClient.js";
12
12
  export * from "./InteractionMessenger.js";
13
13
  export * from "./Subscription.js";
@@ -1274,10 +1274,8 @@ export class ControllerCommissioningFlow {
1274
1274
  // Assume concurrent connections are supported if not know (which should not be the case when we came here)
1275
1275
  isConcurrentFlow,
1276
1276
  );
1277
- } catch (error) {
1278
- const commError = new OperativeConnectionFailedError("Operative reconnection with device failed");
1279
- commError.cause = error;
1280
- throw commError;
1277
+ } catch (cause) {
1278
+ throw new OperativeConnectionFailedError("Operative reconnection with device failed", { cause });
1281
1279
  }
1282
1280
 
1283
1281
  reArmFailsafeInterval.stop();
@@ -153,7 +153,7 @@ export class DeviceCommissioner {
153
153
  this.#context.secureChannelProtocol.setPaseCommissioner(
154
154
  await PaseServer.fromPin(this.#context.sessions, this.#context.commissioningConfig.values.passcode, {
155
155
  iterations: 1000,
156
- salt: Crypto.get().getRandomData(32),
156
+ salt: Crypto.getRandomData(32),
157
157
  }),
158
158
  );
159
159