@matter/protocol 0.15.0-alpha.0-20250616-4b3754906 → 0.15.0-alpha.0-20250619-df2264f15

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 (207) hide show
  1. package/dist/cjs/certificate/AttestationCertificateManager.d.ts.map +1 -1
  2. package/dist/cjs/certificate/AttestationCertificateManager.js +26 -22
  3. package/dist/cjs/certificate/AttestationCertificateManager.js.map +1 -1
  4. package/dist/cjs/certificate/CertificateAuthority.d.ts +1 -2
  5. package/dist/cjs/certificate/CertificateAuthority.d.ts.map +1 -1
  6. package/dist/cjs/certificate/CertificateAuthority.js +22 -29
  7. package/dist/cjs/certificate/CertificateAuthority.js.map +1 -1
  8. package/dist/cjs/certificate/DeviceCertification.d.ts.map +1 -1
  9. package/dist/cjs/certificate/DeviceCertification.js +2 -6
  10. package/dist/cjs/certificate/DeviceCertification.js.map +1 -1
  11. package/dist/cjs/certificate/index.d.ts +7 -2
  12. package/dist/cjs/certificate/index.d.ts.map +1 -1
  13. package/dist/cjs/certificate/index.js +14 -2
  14. package/dist/cjs/certificate/index.js.map +1 -1
  15. package/dist/cjs/certificate/kinds/AttestationCertificates.d.ts +34 -0
  16. package/dist/cjs/certificate/kinds/AttestationCertificates.d.ts.map +1 -0
  17. package/dist/cjs/certificate/kinds/AttestationCertificates.js +64 -0
  18. package/dist/cjs/certificate/kinds/AttestationCertificates.js.map +6 -0
  19. package/dist/cjs/certificate/kinds/CertificationDeclaration.d.ts +23 -0
  20. package/dist/cjs/certificate/kinds/CertificationDeclaration.d.ts.map +1 -0
  21. package/dist/cjs/certificate/kinds/CertificationDeclaration.js +86 -0
  22. package/dist/cjs/certificate/kinds/CertificationDeclaration.js.map +6 -0
  23. package/dist/cjs/certificate/kinds/Icac.d.ts +29 -0
  24. package/dist/cjs/certificate/kinds/Icac.d.ts.map +1 -0
  25. package/dist/cjs/certificate/kinds/Icac.js +138 -0
  26. package/dist/cjs/certificate/kinds/Icac.js.map +6 -0
  27. package/dist/cjs/certificate/kinds/Noc.d.ts +27 -0
  28. package/dist/cjs/certificate/kinds/Noc.d.ts.map +1 -0
  29. package/dist/cjs/certificate/kinds/Noc.js +148 -0
  30. package/dist/cjs/certificate/kinds/Noc.js.map +6 -0
  31. package/dist/cjs/certificate/kinds/OperationalBase.d.ts +24 -0
  32. package/dist/cjs/certificate/kinds/OperationalBase.d.ts.map +1 -0
  33. package/dist/cjs/certificate/kinds/OperationalBase.js +68 -0
  34. package/dist/cjs/certificate/kinds/OperationalBase.js.map +6 -0
  35. package/dist/cjs/certificate/kinds/Rcac.d.ts +25 -0
  36. package/dist/cjs/certificate/kinds/Rcac.d.ts.map +1 -0
  37. package/dist/cjs/certificate/kinds/Rcac.js +119 -0
  38. package/dist/cjs/certificate/kinds/Rcac.js.map +6 -0
  39. package/dist/cjs/certificate/kinds/X509Base.d.ts +92 -0
  40. package/dist/cjs/certificate/kinds/X509Base.d.ts.map +1 -0
  41. package/dist/cjs/certificate/kinds/X509Base.js +344 -0
  42. package/dist/cjs/certificate/kinds/X509Base.js.map +6 -0
  43. package/dist/cjs/certificate/kinds/common.d.ts +18 -0
  44. package/dist/cjs/certificate/kinds/common.d.ts.map +1 -0
  45. package/dist/cjs/certificate/kinds/common.js +42 -0
  46. package/dist/cjs/certificate/kinds/common.js.map +6 -0
  47. package/dist/cjs/certificate/kinds/definitions/asn.d.ts +25 -0
  48. package/dist/cjs/certificate/kinds/definitions/asn.d.ts.map +1 -0
  49. package/dist/cjs/certificate/kinds/definitions/asn.js +83 -0
  50. package/dist/cjs/certificate/kinds/definitions/asn.js.map +6 -0
  51. package/dist/cjs/certificate/kinds/definitions/attestation.d.ts +44 -0
  52. package/dist/cjs/certificate/kinds/definitions/attestation.d.ts.map +1 -0
  53. package/dist/cjs/certificate/kinds/definitions/attestation.js +22 -0
  54. package/dist/cjs/certificate/kinds/definitions/attestation.js.map +6 -0
  55. package/dist/cjs/certificate/kinds/definitions/base.d.ts +52 -0
  56. package/dist/cjs/certificate/kinds/definitions/base.d.ts.map +1 -0
  57. package/dist/cjs/certificate/kinds/definitions/base.js +43 -0
  58. package/dist/cjs/certificate/kinds/definitions/base.js.map +6 -0
  59. package/dist/cjs/certificate/kinds/definitions/certification-declaration.d.ts +18 -0
  60. package/dist/cjs/certificate/kinds/definitions/certification-declaration.d.ts.map +1 -0
  61. package/dist/cjs/certificate/kinds/definitions/certification-declaration.js +50 -0
  62. package/dist/cjs/certificate/kinds/definitions/certification-declaration.js.map +6 -0
  63. package/dist/cjs/certificate/kinds/definitions/operational.d.ts +368 -0
  64. package/dist/cjs/certificate/kinds/definitions/operational.d.ts.map +1 -0
  65. package/dist/cjs/certificate/kinds/definitions/operational.js +149 -0
  66. package/dist/cjs/certificate/kinds/definitions/operational.js.map +6 -0
  67. package/dist/cjs/certificate/kinds/index.d.ts +12 -0
  68. package/dist/cjs/certificate/kinds/index.d.ts.map +1 -0
  69. package/dist/cjs/certificate/kinds/index.js +29 -0
  70. package/dist/cjs/certificate/kinds/index.js.map +6 -0
  71. package/dist/cjs/fabric/Fabric.d.ts +1 -2
  72. package/dist/cjs/fabric/Fabric.d.ts.map +1 -1
  73. package/dist/cjs/fabric/Fabric.js +28 -31
  74. package/dist/cjs/fabric/Fabric.js.map +1 -1
  75. package/dist/cjs/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  76. package/dist/cjs/peer/ControllerCommissioningFlow.js +2 -1
  77. package/dist/cjs/peer/ControllerCommissioningFlow.js.map +1 -1
  78. package/dist/cjs/session/case/CaseClient.d.ts.map +1 -1
  79. package/dist/cjs/session/case/CaseClient.js +3 -3
  80. package/dist/cjs/session/case/CaseClient.js.map +1 -1
  81. package/dist/cjs/session/case/CaseServer.d.ts.map +1 -1
  82. package/dist/cjs/session/case/CaseServer.js +2 -2
  83. package/dist/cjs/session/case/CaseServer.js.map +1 -1
  84. package/dist/esm/certificate/AttestationCertificateManager.d.ts.map +1 -1
  85. package/dist/esm/certificate/AttestationCertificateManager.js +20 -16
  86. package/dist/esm/certificate/AttestationCertificateManager.js.map +1 -1
  87. package/dist/esm/certificate/CertificateAuthority.d.ts +1 -2
  88. package/dist/esm/certificate/CertificateAuthority.d.ts.map +1 -1
  89. package/dist/esm/certificate/CertificateAuthority.js +18 -30
  90. package/dist/esm/certificate/CertificateAuthority.js.map +1 -1
  91. package/dist/esm/certificate/DeviceCertification.d.ts.map +1 -1
  92. package/dist/esm/certificate/DeviceCertification.js +2 -6
  93. package/dist/esm/certificate/DeviceCertification.js.map +1 -1
  94. package/dist/esm/certificate/index.d.ts +7 -2
  95. package/dist/esm/certificate/index.d.ts.map +1 -1
  96. package/dist/esm/certificate/index.js +10 -2
  97. package/dist/esm/certificate/index.js.map +1 -1
  98. package/dist/esm/certificate/kinds/AttestationCertificates.d.ts +34 -0
  99. package/dist/esm/certificate/kinds/AttestationCertificates.d.ts.map +1 -0
  100. package/dist/esm/certificate/kinds/AttestationCertificates.js +44 -0
  101. package/dist/esm/certificate/kinds/AttestationCertificates.js.map +6 -0
  102. package/dist/esm/certificate/kinds/CertificationDeclaration.d.ts +23 -0
  103. package/dist/esm/certificate/kinds/CertificationDeclaration.d.ts.map +1 -0
  104. package/dist/esm/certificate/kinds/CertificationDeclaration.js +66 -0
  105. package/dist/esm/certificate/kinds/CertificationDeclaration.js.map +6 -0
  106. package/dist/esm/certificate/kinds/Icac.d.ts +29 -0
  107. package/dist/esm/certificate/kinds/Icac.d.ts.map +1 -0
  108. package/dist/esm/certificate/kinds/Icac.js +118 -0
  109. package/dist/esm/certificate/kinds/Icac.js.map +6 -0
  110. package/dist/esm/certificate/kinds/Noc.d.ts +27 -0
  111. package/dist/esm/certificate/kinds/Noc.d.ts.map +1 -0
  112. package/dist/esm/certificate/kinds/Noc.js +128 -0
  113. package/dist/esm/certificate/kinds/Noc.js.map +6 -0
  114. package/dist/esm/certificate/kinds/OperationalBase.d.ts +24 -0
  115. package/dist/esm/certificate/kinds/OperationalBase.d.ts.map +1 -0
  116. package/dist/esm/certificate/kinds/OperationalBase.js +48 -0
  117. package/dist/esm/certificate/kinds/OperationalBase.js.map +6 -0
  118. package/dist/esm/certificate/kinds/Rcac.d.ts +25 -0
  119. package/dist/esm/certificate/kinds/Rcac.d.ts.map +1 -0
  120. package/dist/esm/certificate/kinds/Rcac.js +99 -0
  121. package/dist/esm/certificate/kinds/Rcac.js.map +6 -0
  122. package/dist/esm/certificate/kinds/X509Base.d.ts +92 -0
  123. package/dist/esm/certificate/kinds/X509Base.d.ts.map +1 -0
  124. package/dist/esm/certificate/kinds/X509Base.js +347 -0
  125. package/dist/esm/certificate/kinds/X509Base.js.map +6 -0
  126. package/dist/esm/certificate/kinds/common.d.ts +18 -0
  127. package/dist/esm/certificate/kinds/common.d.ts.map +1 -0
  128. package/dist/esm/certificate/kinds/common.js +22 -0
  129. package/dist/esm/certificate/kinds/common.js.map +6 -0
  130. package/dist/esm/certificate/kinds/definitions/asn.d.ts +25 -0
  131. package/dist/esm/certificate/kinds/definitions/asn.d.ts.map +1 -0
  132. package/dist/esm/certificate/kinds/definitions/asn.js +63 -0
  133. package/dist/esm/certificate/kinds/definitions/asn.js.map +6 -0
  134. package/dist/esm/certificate/kinds/definitions/attestation.d.ts +44 -0
  135. package/dist/esm/certificate/kinds/definitions/attestation.d.ts.map +1 -0
  136. package/dist/esm/certificate/kinds/definitions/attestation.js +6 -0
  137. package/dist/esm/certificate/kinds/definitions/attestation.js.map +6 -0
  138. package/dist/esm/certificate/kinds/definitions/base.d.ts +52 -0
  139. package/dist/esm/certificate/kinds/definitions/base.d.ts.map +1 -0
  140. package/dist/esm/certificate/kinds/definitions/base.js +23 -0
  141. package/dist/esm/certificate/kinds/definitions/base.js.map +6 -0
  142. package/dist/esm/certificate/kinds/definitions/certification-declaration.d.ts +18 -0
  143. package/dist/esm/certificate/kinds/definitions/certification-declaration.d.ts.map +1 -0
  144. package/dist/esm/certificate/kinds/definitions/certification-declaration.js +41 -0
  145. package/dist/esm/certificate/kinds/definitions/certification-declaration.js.map +6 -0
  146. package/dist/esm/certificate/kinds/definitions/operational.d.ts +368 -0
  147. package/dist/esm/certificate/kinds/definitions/operational.d.ts.map +1 -0
  148. package/dist/esm/certificate/kinds/definitions/operational.js +148 -0
  149. package/dist/esm/certificate/kinds/definitions/operational.js.map +6 -0
  150. package/dist/esm/certificate/kinds/index.d.ts +12 -0
  151. package/dist/esm/certificate/kinds/index.d.ts.map +1 -0
  152. package/dist/esm/certificate/kinds/index.js +12 -0
  153. package/dist/esm/certificate/kinds/index.js.map +6 -0
  154. package/dist/esm/fabric/Fabric.d.ts +1 -2
  155. package/dist/esm/fabric/Fabric.d.ts.map +1 -1
  156. package/dist/esm/fabric/Fabric.js +28 -36
  157. package/dist/esm/fabric/Fabric.js.map +1 -1
  158. package/dist/esm/peer/ControllerCommissioningFlow.d.ts.map +1 -1
  159. package/dist/esm/peer/ControllerCommissioningFlow.js +2 -1
  160. package/dist/esm/peer/ControllerCommissioningFlow.js.map +1 -1
  161. package/dist/esm/session/case/CaseClient.d.ts.map +1 -1
  162. package/dist/esm/session/case/CaseClient.js +3 -3
  163. package/dist/esm/session/case/CaseClient.js.map +1 -1
  164. package/dist/esm/session/case/CaseServer.d.ts.map +1 -1
  165. package/dist/esm/session/case/CaseServer.js +2 -2
  166. package/dist/esm/session/case/CaseServer.js.map +1 -1
  167. package/package.json +6 -6
  168. package/src/certificate/AttestationCertificateManager.ts +20 -16
  169. package/src/certificate/CertificateAuthority.ts +18 -35
  170. package/src/certificate/DeviceCertification.ts +2 -6
  171. package/src/certificate/index.ts +7 -2
  172. package/src/certificate/kinds/AttestationCertificates.ts +48 -0
  173. package/src/certificate/kinds/CertificationDeclaration.ts +91 -0
  174. package/src/certificate/kinds/Icac.ts +156 -0
  175. package/src/certificate/kinds/Noc.ts +164 -0
  176. package/src/certificate/kinds/OperationalBase.ts +72 -0
  177. package/src/certificate/kinds/Rcac.ts +126 -0
  178. package/src/certificate/kinds/X509Base.ts +380 -0
  179. package/src/certificate/kinds/common.ts +24 -0
  180. package/src/certificate/kinds/definitions/asn.ts +97 -0
  181. package/src/certificate/kinds/definitions/attestation.ts +46 -0
  182. package/src/certificate/kinds/definitions/base.ts +43 -0
  183. package/src/certificate/kinds/definitions/certification-declaration.ts +38 -0
  184. package/src/certificate/kinds/definitions/operational.ts +179 -0
  185. package/src/certificate/kinds/index.ts +12 -0
  186. package/src/fabric/Fabric.ts +28 -40
  187. package/src/peer/ControllerCommissioningFlow.ts +2 -1
  188. package/src/session/case/CaseClient.ts +3 -3
  189. package/src/session/case/CaseServer.ts +2 -2
  190. package/dist/cjs/certificate/CertificateManager.d.ts +0 -578
  191. package/dist/cjs/certificate/CertificateManager.d.ts.map +0 -1
  192. package/dist/cjs/certificate/CertificateManager.js +0 -843
  193. package/dist/cjs/certificate/CertificateManager.js.map +0 -6
  194. package/dist/cjs/certificate/CertificationDeclarationManager.d.ts +0 -11
  195. package/dist/cjs/certificate/CertificationDeclarationManager.d.ts.map +0 -1
  196. package/dist/cjs/certificate/CertificationDeclarationManager.js +0 -54
  197. package/dist/cjs/certificate/CertificationDeclarationManager.js.map +0 -6
  198. package/dist/esm/certificate/CertificateManager.d.ts +0 -578
  199. package/dist/esm/certificate/CertificateManager.d.ts.map +0 -1
  200. package/dist/esm/certificate/CertificateManager.js +0 -870
  201. package/dist/esm/certificate/CertificateManager.js.map +0 -6
  202. package/dist/esm/certificate/CertificationDeclarationManager.d.ts +0 -11
  203. package/dist/esm/certificate/CertificationDeclarationManager.d.ts.map +0 -1
  204. package/dist/esm/certificate/CertificationDeclarationManager.js +0 -34
  205. package/dist/esm/certificate/CertificationDeclarationManager.js.map +0 -6
  206. package/src/certificate/CertificateManager.ts +0 -1176
  207. package/src/certificate/CertificationDeclarationManager.ts +0 -52
@@ -1,1176 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2022-2025 Matter.js Authors
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- import {
8
- Bytes,
9
- ContextTagged,
10
- ContextTaggedBytes,
11
- Crypto,
12
- DatatypeOverride,
13
- DerBitString,
14
- DerCodec,
15
- DerKey,
16
- DerObject,
17
- DerType,
18
- Diagnostic,
19
- ImplementationError,
20
- Key,
21
- Logger,
22
- MatterError,
23
- Pkcs7,
24
- PublicKey,
25
- RawBytes,
26
- SHA256_CMS,
27
- Time,
28
- X509,
29
- X520,
30
- X962,
31
- } from "#general";
32
- import {
33
- BitFlag,
34
- BitmapSchema,
35
- CaseAuthenticatedTag,
36
- FabricId,
37
- NodeId,
38
- TlvArray,
39
- TlvBitmap,
40
- TlvBoolean,
41
- TlvByteString,
42
- TlvCaseAuthenticatedTag,
43
- TlvFabricId,
44
- TlvField,
45
- TlvNodeId,
46
- TlvObject,
47
- TlvObjectWithMaxSize,
48
- TlvOptionalField,
49
- TlvOptionalRepeatedField,
50
- TlvString,
51
- TlvTaggedList,
52
- TlvUInt16,
53
- TlvUInt32,
54
- TlvUInt64,
55
- TlvUInt8,
56
- TlvVendorId,
57
- TypeFromPartialBitSchema,
58
- TypeFromSchema,
59
- VendorId,
60
- } from "#types";
61
-
62
- const logger = Logger.get("CertificateManager");
63
-
64
- export class CertificateError extends MatterError {}
65
-
66
- const YEAR_S = 365 * 24 * 60 * 60;
67
- const EPOCH_OFFSET_S = 10957 * 24 * 60 * 60;
68
-
69
- /**
70
- * Matter specific Certificate Sizes
71
- * @see {@link MatterSpecification.v13.Core} 6.1.3.
72
- */
73
- const MAX_DER_CERTIFICATE_SIZE = 600;
74
- const MAX_TLV_CERTIFICATE_SIZE = 400;
75
-
76
- // TODO replace usage of Date by abstraction
77
-
78
- export function matterToJsDate(date: number) {
79
- return date === 0 ? X520.NON_WELL_DEFINED_DATE : new Date((date + EPOCH_OFFSET_S) * 1000);
80
- }
81
-
82
- export function jsToMatterDate(date: Date, addYears = 0) {
83
- return date.getTime() === X520.NON_WELL_DEFINED_DATE.getTime()
84
- ? 0
85
- : Math.floor(date.getTime() / 1000) - EPOCH_OFFSET_S + addYears * YEAR_S;
86
- }
87
-
88
- function intTo16Chars(value: bigint | number) {
89
- const byteArray = new Uint8Array(8);
90
- const dataView = Bytes.dataViewOf(byteArray);
91
- dataView.setBigUint64(0, typeof value === "bigint" ? value : BigInt(value));
92
- return Bytes.toHex(byteArray).toUpperCase();
93
- }
94
-
95
- function uInt16To8Chars(value: number) {
96
- const byteArray = new Uint8Array(4);
97
- const dataView = Bytes.dataViewOf(byteArray);
98
- dataView.setUint32(0, value);
99
- return Bytes.toHex(byteArray).toUpperCase();
100
- }
101
-
102
- function uInt16To4Chars(value: number) {
103
- const byteArray = new Uint8Array(2);
104
- const dataView = Bytes.dataViewOf(byteArray);
105
- dataView.setUint16(0, value);
106
- return Bytes.toHex(byteArray).toUpperCase();
107
- }
108
-
109
- /**
110
- * Matter specific ASN.1 OIDs
111
- * @see {@link MatterSpecification.v12.Core} Appendix E
112
- */
113
-
114
- /**
115
- * Generator function to create a specific ASN field for a Matter OpCert DN with the OID base 1.3.6.1.4.1.37244.1.*.
116
- * The returned function takes the value and returns the ASN.1 DER object.
117
- */
118
- const GenericMatterOpCertObject =
119
- <T>(id: number, valueConverter?: (value: T) => string) =>
120
- (value: T) => [
121
- DerObject(`2b0601040182a27c01${id.toString(16).padStart(2, "0")}`, {
122
- value: (valueConverter ?? intTo16Chars)(value as any),
123
- }),
124
- ];
125
-
126
- /**
127
- * Generator function to create a specific ASN field for a Matter AttCert DN with the OID base 1.3.6.1.4.1.37244.2.*.
128
- * The returned function takes the value and returns the ASN.1 DER object.
129
- */
130
- const GenericMatterAttCertObject =
131
- <T>(id: number, valueConverter?: (value: T) => string) =>
132
- (value: T) => [
133
- DerObject(`2b0601040182a27c02${id.toString(16).padStart(2, "0")}`, {
134
- value: (valueConverter ?? intTo16Chars)(value as any),
135
- }),
136
- ];
137
-
138
- /** matter-node-id = ASN.1 OID 1.3.6.1.4.1.37244.1.1 */
139
- export const NodeId_Matter = GenericMatterOpCertObject<NodeId>(1);
140
-
141
- /** matter-firmware-signing-id = ASN.1 OID 1.3.6.1.4.1.37244.1.2 */
142
- export const FirmwareSigningId_Matter = GenericMatterOpCertObject<number>(2);
143
-
144
- /** matter-icac-id = ASN.1 OID 1.3.6.1.4.1.37244.1.3 */
145
- export const IcacId_Matter = GenericMatterOpCertObject<bigint | number>(3);
146
-
147
- /** matter-rcac-id = ASN.1 OID 1.3.6.1.4.1.37244.1.4 */
148
- export const RcacId_Matter = GenericMatterOpCertObject<bigint | number>(4);
149
-
150
- /** matter-fabric-id = ASN.1 OID 1.3.6.1.4.1.37244.1.5 */
151
- export const FabricId_Matter = GenericMatterOpCertObject<FabricId>(5);
152
-
153
- /** matter-noc-cat = ASN.1 OID 1.3.6.1.4.1.37244.1.6 */
154
- export const NocCat_Matter = GenericMatterOpCertObject<number>(6, uInt16To8Chars);
155
-
156
- /** matter-oid-vid = ASN.1 OID 1.3.6.1.4.1.37244.2.1 */
157
- export const VendorId_Matter = GenericMatterAttCertObject<VendorId>(1, uInt16To4Chars);
158
-
159
- /** matter-oid-pid = ASN.1 OID 1.3.6.1.4.1.37244.2.2 */
160
- export const ProductId_Matter = GenericMatterAttCertObject<number>(2, uInt16To4Chars);
161
-
162
- /** All defined Matter fields for subject and issuer that we always allow optionally to be encoded */
163
- const AllowedSubjectAndIssuerMatterFields = {
164
- nodeId: TlvOptionalField(17, TlvNodeId),
165
- firmwareSigningId: TlvOptionalField(18, TlvUInt32),
166
- icacId: TlvOptionalField(19, TlvUInt64),
167
- rcacId: TlvOptionalField(20, TlvUInt64),
168
- fabricId: TlvOptionalField(21, TlvFabricId),
169
- caseAuthenticatedTags: TlvOptionalRepeatedField(22, TlvCaseAuthenticatedTag, { maxLength: 3 }),
170
- };
171
-
172
- /**
173
- * TLV schema for a generic subject or issuer field in a certificate. We handle all fields as optional here for the TLV
174
- * parsing and check required fields in the logic to make sure we return the correct errors.
175
- */
176
- const TlvGenericMatterSubjectOrIssuerTaggedList = <T>(matterFields: T) => {
177
- const fields = {
178
- // Standard DNs
179
- commonName: TlvOptionalField(1, TlvString),
180
- sureName: TlvOptionalField(2, TlvString),
181
- serialNum: TlvOptionalField(3, TlvString),
182
- countryName: TlvOptionalField(4, TlvString),
183
- localityName: TlvOptionalField(5, TlvString),
184
- stateOrProvinceName: TlvOptionalField(6, TlvString),
185
- orgName: TlvOptionalField(7, TlvString),
186
- orgUnitName: TlvOptionalField(8, TlvString),
187
- title: TlvOptionalField(9, TlvString),
188
- name: TlvOptionalField(10, TlvString),
189
- givenName: TlvOptionalField(11, TlvString),
190
- initials: TlvOptionalField(12, TlvString),
191
- genQualifier: TlvOptionalField(13, TlvString),
192
- dnQualifier: TlvOptionalField(14, TlvString),
193
- pseudonym: TlvOptionalField(15, TlvString),
194
- domainComponent: TlvOptionalField(16, TlvString),
195
-
196
- // Matter specific DNs
197
- ...matterFields,
198
-
199
- // Standard DNs when encoded as Printable String
200
- commonNamePs: TlvOptionalField(129, TlvString),
201
- sureNamePs: TlvOptionalField(130, TlvString),
202
- serialNumPs: TlvOptionalField(131, TlvString),
203
- countryNamePs: TlvOptionalField(132, TlvString),
204
- localityNamePs: TlvOptionalField(133, TlvString),
205
- stateOrProvinceNamePs: TlvOptionalField(134, TlvString),
206
- orgNamePs: TlvOptionalField(135, TlvString),
207
- orgUnitNamePs: TlvOptionalField(136, TlvString),
208
- titlePs: TlvOptionalField(137, TlvString),
209
- namePs: TlvOptionalField(138, TlvString),
210
- givenNamePs: TlvOptionalField(139, TlvString),
211
- initialsPs: TlvOptionalField(140, TlvString),
212
- genQualifierPs: TlvOptionalField(141, TlvString),
213
- dnQualifierPs: TlvOptionalField(142, TlvString),
214
- pseudonymPs: TlvOptionalField(143, TlvString),
215
- };
216
- return TlvTaggedList(fields);
217
- };
218
-
219
- const ExtensionKeyUsageBitmap = {
220
- digitalSignature: BitFlag(0),
221
- nonRepudiation: BitFlag(1),
222
- keyEncipherment: BitFlag(2),
223
- dataEncipherment: BitFlag(3),
224
- keyAgreement: BitFlag(4),
225
- keyCertSign: BitFlag(5),
226
- cRLSign: BitFlag(6),
227
- encipherOnly: BitFlag(7),
228
- decipherOnly: BitFlag(8),
229
- };
230
- const ExtensionKeyUsageSchema = BitmapSchema(ExtensionKeyUsageBitmap);
231
-
232
- /**
233
- * This generator enhances the generic Matter Certificate definition by allowing to override the subject and issuer
234
- * fields. The overriding serves two needs:
235
- * 1. to make some fields mandatory for the Tlv parsing and definition for the typescript types
236
- * 2. have typing guidance when generating certificates ourself in code
237
- *
238
- * On Tlv definition level also all not specified allowed Matter Fields are optionally allowed and are decoded,
239
- * re-encoded into Tlv and also encoded into ASN if the certificate is converted. Just the typing system do not know
240
- * about them.
241
- */
242
- const BaseMatterCertificate = <S, I>(matterFields?: { subject?: S; issuer?: I }) =>
243
- TlvObjectWithMaxSize(
244
- {
245
- serialNumber: TlvField(1, TlvByteString.bound({ maxLength: 20 })),
246
- signatureAlgorithm: TlvField(2, TlvUInt8),
247
- issuer: TlvField(
248
- 3,
249
- TlvGenericMatterSubjectOrIssuerTaggedList<I>({
250
- ...AllowedSubjectAndIssuerMatterFields,
251
- ...(matterFields?.issuer ?? {}),
252
- } as I),
253
- ),
254
- notBefore: TlvField(4, TlvUInt32),
255
- notAfter: TlvField(5, TlvUInt32),
256
- subject: TlvField(
257
- 6,
258
- TlvGenericMatterSubjectOrIssuerTaggedList<S>({
259
- ...AllowedSubjectAndIssuerMatterFields,
260
- ...(matterFields?.subject ?? {}),
261
- } as S),
262
- ),
263
- publicKeyAlgorithm: TlvField(7, TlvUInt8),
264
- ellipticCurveIdentifier: TlvField(8, TlvUInt8),
265
- ellipticCurvePublicKey: TlvField(9, TlvByteString),
266
- extensions: TlvField(
267
- 10,
268
- TlvTaggedList({
269
- basicConstraints: TlvField(
270
- 1,
271
- TlvObject({
272
- isCa: TlvField(1, TlvBoolean),
273
- pathLen: TlvOptionalField(2, TlvUInt8),
274
- }),
275
- ),
276
- keyUsage: TlvField(2, TlvBitmap(TlvUInt16, ExtensionKeyUsageBitmap)),
277
- extendedKeyUsage: TlvOptionalField(3, TlvArray(TlvUInt8)),
278
- subjectKeyIdentifier: TlvField(4, TlvByteString.bound({ length: 20 })),
279
- authorityKeyIdentifier: TlvField(5, TlvByteString.bound({ length: 20 })),
280
- futureExtension: TlvOptionalRepeatedField(6, TlvByteString),
281
- }),
282
- ),
283
- signature: TlvField(11, TlvByteString),
284
- },
285
- MAX_TLV_CERTIFICATE_SIZE,
286
- );
287
-
288
- export const TlvRootCertificate = BaseMatterCertificate({
289
- subject: {
290
- rcacId: TlvField(20, TlvUInt64),
291
- fabricId: TlvOptionalField(21, TlvFabricId),
292
- },
293
- issuer: AllowedSubjectAndIssuerMatterFields,
294
- });
295
-
296
- export const TlvOperationalCertificate = BaseMatterCertificate({
297
- subject: {
298
- nodeId: TlvField(17, TlvNodeId),
299
- fabricId: TlvField(21, TlvFabricId),
300
- caseAuthenticatedTags: TlvOptionalRepeatedField(22, TlvCaseAuthenticatedTag, { maxLength: 3 }),
301
- },
302
- issuer: AllowedSubjectAndIssuerMatterFields,
303
- });
304
-
305
- export const TlvIntermediateCertificate = BaseMatterCertificate({
306
- subject: {
307
- icacId: TlvField(19, TlvUInt64),
308
- fabricId: TlvOptionalField(21, TlvFabricId),
309
- },
310
- issuer: AllowedSubjectAndIssuerMatterFields,
311
- });
312
-
313
- const TlvBaseCertificate = BaseMatterCertificate();
314
-
315
- interface AttestationCertificateBase {
316
- serialNumber: Uint8Array;
317
- signatureAlgorithm: number;
318
- issuer: {};
319
- notBefore: number;
320
- notAfter: number;
321
- subject: {};
322
- publicKeyAlgorithm: number;
323
- ellipticCurveIdentifier: number;
324
- ellipticCurvePublicKey: Uint8Array;
325
- extensions: {
326
- basicConstraints: {
327
- isCa: boolean;
328
- pathLen?: number;
329
- };
330
- keyUsage: TypeFromPartialBitSchema<typeof ExtensionKeyUsageBitmap>;
331
- extendedKeyUsage?: number[];
332
- subjectKeyIdentifier: Uint8Array;
333
- authorityKeyIdentifier: Uint8Array;
334
- futureExtension?: Uint8Array[];
335
- };
336
- signature: Uint8Array;
337
- }
338
-
339
- export interface DeviceAttestationCertificate extends AttestationCertificateBase {
340
- issuer: {
341
- commonName: string;
342
- productId?: number;
343
- vendorId: VendorId;
344
- };
345
- subject: {
346
- commonName: string;
347
- productId: number;
348
- vendorId: VendorId;
349
- };
350
- }
351
-
352
- export interface ProductAttestationIntermediateCertificate extends AttestationCertificateBase {
353
- issuer: {
354
- commonName: string;
355
- vendorId?: VendorId;
356
- };
357
- subject: {
358
- commonName: string;
359
- productId?: number;
360
- vendorId: VendorId;
361
- };
362
- }
363
-
364
- export interface ProductAttestationAuthorityCertificate extends AttestationCertificateBase {
365
- issuer: {
366
- commonName: string;
367
- vendorId?: VendorId;
368
- };
369
- subject: {
370
- commonName: string;
371
- vendorId?: VendorId;
372
- };
373
- }
374
-
375
- export const TlvCertificationDeclaration = TlvObject({
376
- formatVersion: TlvField(0, TlvUInt16),
377
- vendorId: TlvField(1, TlvVendorId),
378
- produceIdArray: TlvField(2, TlvArray(TlvUInt16, { minLength: 1, maxLength: 100 })),
379
- deviceTypeId: TlvField(3, TlvUInt32),
380
- certificateId: TlvField(4, TlvString.bound({ length: 19 })),
381
- securityLevel: TlvField(5, TlvUInt8),
382
- securityInformation: TlvField(6, TlvUInt16),
383
- versionNumber: TlvField(7, TlvUInt16),
384
- certificationType: TlvField(8, TlvUInt8),
385
- dacOriginVendorId: TlvOptionalField(9, TlvVendorId),
386
- dacOriginProductId: TlvOptionalField(10, TlvUInt16),
387
- authorizedPaaList: TlvOptionalField(
388
- 11,
389
- TlvArray(TlvByteString.bound({ length: 20 }), { minLength: 1, maxLength: 10 }),
390
- ),
391
- });
392
-
393
- export type BaseCertificate = TypeFromSchema<typeof TlvBaseCertificate>;
394
- export type RootCertificate = TypeFromSchema<typeof TlvRootCertificate>;
395
- export type IntermediateCertificate = TypeFromSchema<typeof TlvIntermediateCertificate>;
396
- export type OperationalCertificate = TypeFromSchema<typeof TlvOperationalCertificate>;
397
- export type Unsigned<Type> = { [Property in keyof Type as Exclude<Property, "signature">]: Type[Property] };
398
-
399
- /**
400
- * Preserve order of keys from original subject and also copy potential custom elements
401
- * @param data
402
- */
403
- function subjectOrIssuerToAsn1(data: { [field: string]: any }) {
404
- const asn = {} as { [field: string]: any[] };
405
- Object.entries(data).forEach(([key, value]) => {
406
- if (value === undefined) {
407
- return;
408
- }
409
- switch (key) {
410
- case "commonName":
411
- asn.commonName = X520.CommonName(value as string);
412
- break;
413
- case "sureName":
414
- asn.sureName = X520.SurName(value as string);
415
- break;
416
- case "serialNum":
417
- asn.serialNum = X520.SerialNumber(value as string);
418
- break;
419
- case "countryName":
420
- asn.countryName = X520.CountryName(value as string);
421
- break;
422
- case "localityName":
423
- asn.localityName = X520.LocalityName(value as string);
424
- break;
425
- case "stateOrProvinceName":
426
- asn.stateOrProvinceName = X520.StateOrProvinceName(value as string);
427
- break;
428
- case "orgName":
429
- asn.orgName = X520.OrganisationName(value as string);
430
- break;
431
- case "orgUnitName":
432
- asn.orgUnitName = X520.OrganizationalUnitName(value as string);
433
- break;
434
- case "title":
435
- asn.title = X520.Title(value as string);
436
- break;
437
- case "name":
438
- asn.name = X520.Name(value as string);
439
- break;
440
- case "givenName":
441
- asn.givenName = X520.GivenName(value as string);
442
- break;
443
- case "initials":
444
- asn.initials = X520.Initials(value as string);
445
- break;
446
- case "genQualifier":
447
- asn.genQualifier = X520.GenerationQualifier(value as string);
448
- break;
449
- case "dnQualifier":
450
- asn.dnQualifier = X520.DnQualifier(value as string);
451
- break;
452
- case "pseudonym":
453
- asn.pseudonym = X520.Pseudonym(value as string);
454
- break;
455
- case "domainComponent":
456
- asn.domainComponent = X520.DomainComponent(value as string);
457
- break;
458
- case "nodeId":
459
- asn.nodeId = NodeId_Matter(value as NodeId);
460
- break;
461
- case "firmwareSigningId":
462
- asn.firmwareSigningId = FirmwareSigningId_Matter(value as number);
463
- break;
464
- case "icacId":
465
- asn.icacId = IcacId_Matter(value as number | bigint);
466
- break;
467
- case "rcacId":
468
- asn.rcacId = RcacId_Matter(value as number | bigint);
469
- break;
470
- case "fabricId":
471
- asn.fabricId = FabricId_Matter(value as FabricId);
472
- break;
473
- case "caseAuthenticatedTags":
474
- // In theory if someone mixes multiple caseAuthenticatedTag fields with other fields we currently would
475
- // code them in ASN.1 as fields at the first position from the original data which might fail
476
- // certificate validation. Changing this would require to change Tlv decoding, so lets try that way for now.
477
- const caseAuthenticatedTags = value as CaseAuthenticatedTag[];
478
- CaseAuthenticatedTag.validateNocTagList(caseAuthenticatedTags);
479
-
480
- const cat0 = caseAuthenticatedTags[0];
481
- const cat1 = caseAuthenticatedTags[1];
482
- const cat2 = caseAuthenticatedTags[2];
483
- if (cat0 !== undefined) {
484
- asn.caseAuthenticatedTag0 = NocCat_Matter(cat0);
485
- }
486
- if (cat1 !== undefined) {
487
- asn.caseAuthenticatedTag1 = NocCat_Matter(cat1);
488
- }
489
- if (cat2 !== undefined) {
490
- asn.caseAuthenticatedTag2 = NocCat_Matter(cat2);
491
- }
492
- break;
493
- case "vendorId": // Only relevant for ASN.1 encoding of DAC/PAA/PAI certificates
494
- asn.vendorId = VendorId_Matter(value as VendorId);
495
- break;
496
- case "productId": // Only relevant for ASN.1 encoding of DAC/PAA/PAI certificates
497
- asn.productId = ProductId_Matter(value as number);
498
- break;
499
- case "commonNamePs":
500
- asn.commonNamePs = X520.CommonName(value as string, true);
501
- break;
502
- case "sureNamePs":
503
- asn.sureNamePs = X520.SurName(value as string, true);
504
- break;
505
- case "serialNumPs":
506
- asn.serialNumPs = X520.SerialNumber(value as string, true);
507
- break;
508
- case "countryNamePs":
509
- asn.countryNamePs = X520.CountryName(value as string, true);
510
- break;
511
- case "localityNamePs":
512
- asn.localityNamePs = X520.LocalityName(value as string, true);
513
- break;
514
- case "stateOrProvinceNamePs":
515
- asn.stateOrProvinceNamePs = X520.StateOrProvinceName(value as string, true);
516
- break;
517
- case "orgNamePs":
518
- asn.orgNamePs = X520.OrganisationName(value as string, true);
519
- break;
520
- case "orgUnitNamePs":
521
- asn.orgUnitNamePs = X520.OrganizationalUnitName(value as string, true);
522
- break;
523
- case "titlePs":
524
- asn.titlePs = X520.Title(value as string, true);
525
- break;
526
- case "namePs":
527
- asn.namePs = X520.Name(value as string, true);
528
- break;
529
- case "givenNamePs":
530
- asn.givenNamePs = X520.GivenName(value as string, true);
531
- break;
532
- case "initialsPs":
533
- asn.initialsPs = X520.Initials(value as string, true);
534
- break;
535
- case "genQualifierPs":
536
- asn.genQualifierPs = X520.GenerationQualifier(value as string, true);
537
- break;
538
- case "dnQualifierPs":
539
- asn.dnQualifierPs = X520.DnQualifier(value as string, true);
540
- break;
541
- case "pseudonymPs":
542
- asn.pseudonymPs = X520.Pseudonym(value as string, true);
543
- break;
544
- }
545
- });
546
- return asn;
547
- }
548
-
549
- function extensionsToAsn1(extensions: BaseCertificate["extensions"]) {
550
- const asn = {} as { [field: string]: any[] | any };
551
- Object.entries(extensions).forEach(([key, value]) => {
552
- if (value === undefined) {
553
- return;
554
- }
555
- switch (key) {
556
- case "basicConstraints":
557
- asn.basicConstraints = X509.BasicConstraints(value);
558
- break;
559
- case "keyUsage":
560
- asn.keyUsage = X509.KeyUsage(
561
- ExtensionKeyUsageSchema.encode(value as TypeFromPartialBitSchema<typeof ExtensionKeyUsageBitmap>),
562
- );
563
- break;
564
- case "extendedKeyUsage":
565
- asn.extendedKeyUsage = X509.ExtendedKeyUsage(value as number[] | undefined);
566
- break;
567
- case "subjectKeyIdentifier":
568
- asn.subjectKeyIdentifier = X509.SubjectKeyIdentifier(value as Uint8Array);
569
- break;
570
- case "authorityKeyIdentifier":
571
- asn.authorityKeyIdentifier = X509.AuthorityKeyIdentifier(value as Uint8Array);
572
- break;
573
- case "futureExtension":
574
- asn.futureExtension = RawBytes(Bytes.concat(...((value as Uint8Array[] | undefined) ?? [])));
575
- break;
576
- }
577
- });
578
- return asn;
579
- }
580
-
581
- function genericBuildAsn1Structure({
582
- serialNumber,
583
- notBefore,
584
- notAfter,
585
- issuer,
586
- subject,
587
- ellipticCurvePublicKey,
588
- extensions,
589
- }: Unsigned<BaseCertificate>) {
590
- const {
591
- basicConstraints: { isCa, pathLen },
592
- } = extensions;
593
- if (!isCa && pathLen !== undefined) {
594
- throw new CertificateError("Path length must be undefined for non-CA certificates.");
595
- }
596
- return {
597
- version: ContextTagged(0, 2), // v3
598
- serialNumber: DatatypeOverride(DerType.Integer, serialNumber),
599
- signatureAlgorithm: X962.EcdsaWithSHA256,
600
- issuer: subjectOrIssuerToAsn1(issuer),
601
- validity: {
602
- notBefore: matterToJsDate(notBefore),
603
- notAfter: matterToJsDate(notAfter),
604
- },
605
- subject: subjectOrIssuerToAsn1(subject),
606
- publicKey: X962.PublicKeyEcPrime256v1(ellipticCurvePublicKey),
607
- extensions: ContextTagged(3, extensionsToAsn1(extensions)),
608
- };
609
- }
610
-
611
- function genericCertToAsn1(cert: Unsigned<BaseCertificate>) {
612
- const certBytes = DerCodec.encode(genericBuildAsn1Structure(cert));
613
- assertCertificateDerSize(certBytes);
614
- return certBytes;
615
- }
616
-
617
- function assertCertificateDerSize(certBytes: Uint8Array) {
618
- if (certBytes.length > MAX_DER_CERTIFICATE_SIZE) {
619
- throw new ImplementationError(
620
- `Certificate to generate is too big: ${certBytes.length} bytes instead of max ${MAX_DER_CERTIFICATE_SIZE} bytes`,
621
- );
622
- }
623
- }
624
-
625
- export class CertificateManager {
626
- #crypto: Crypto;
627
-
628
- constructor(crypto: Crypto) {
629
- this.#crypto = crypto;
630
- }
631
-
632
- get crypto() {
633
- return this.#crypto;
634
- }
635
-
636
- rootCertToAsn1(cert: Unsigned<RootCertificate>) {
637
- const {
638
- extensions: {
639
- basicConstraints: { isCa },
640
- },
641
- } = cert;
642
- if (!isCa) {
643
- throw new CertificateError("Root certificate must be a CA.");
644
- }
645
- return genericCertToAsn1(cert);
646
- }
647
-
648
- intermediateCaCertToAsn1(cert: Unsigned<IntermediateCertificate>) {
649
- const {
650
- extensions: {
651
- basicConstraints: { isCa },
652
- },
653
- } = cert;
654
- if (!isCa) {
655
- throw new CertificateError("Intermediate certificate must be a CA.");
656
- }
657
- return genericCertToAsn1(cert);
658
- }
659
-
660
- nodeOperationalCertToAsn1(cert: Unsigned<OperationalCertificate>) {
661
- const {
662
- issuer: { icacId, rcacId },
663
- extensions: {
664
- basicConstraints: { isCa },
665
- },
666
- } = cert;
667
- if (icacId === undefined && rcacId === undefined) {
668
- throw new CertificateError("Issuer RCAC or ICAC ID must be defined for an operational certificate.");
669
- }
670
- if (isCa) {
671
- throw new CertificateError("Node operational certificate must not be a CA.");
672
- }
673
-
674
- return genericCertToAsn1(cert);
675
- }
676
-
677
- async deviceAttestationCertToAsn1(cert: Unsigned<DeviceAttestationCertificate>, key: Key) {
678
- const certificate = genericBuildAsn1Structure(cert);
679
- const signature = await this.#crypto.signEcdsa(key, DerCodec.encode(certificate), "der");
680
- const certBytes = DerCodec.encode({
681
- certificate,
682
- signAlgorithm: X962.EcdsaWithSHA256,
683
- signature: DerBitString(signature),
684
- });
685
- assertCertificateDerSize(certBytes);
686
- return certBytes;
687
- }
688
-
689
- async productAttestationIntermediateCertToAsn1(
690
- cert: Unsigned<ProductAttestationIntermediateCertificate>,
691
- key: Key,
692
- ) {
693
- const certificate = genericBuildAsn1Structure(cert);
694
- const signature = await this.#crypto.signEcdsa(key, DerCodec.encode(certificate), "der");
695
- const certBytes = DerCodec.encode({
696
- certificate,
697
- signAlgorithm: X962.EcdsaWithSHA256,
698
- signature: DerBitString(signature),
699
- });
700
- assertCertificateDerSize(certBytes);
701
- return certBytes;
702
- }
703
-
704
- async productAttestationAuthorityCertToAsn1(cert: Unsigned<ProductAttestationAuthorityCertificate>, key: Key) {
705
- const certificate = genericBuildAsn1Structure(cert);
706
- const certBytes = DerCodec.encode({
707
- certificate,
708
- signAlgorithm: X962.EcdsaWithSHA256,
709
- signature: DerBitString(await this.#crypto.signEcdsa(key, DerCodec.encode(certificate), "der")),
710
- });
711
- assertCertificateDerSize(certBytes);
712
- return certBytes;
713
- }
714
-
715
- async certificationDeclarationToAsn1(
716
- eContent: Uint8Array,
717
- subjectKeyIdentifier: Uint8Array,
718
- privateKey: JsonWebKey,
719
- ) {
720
- const certificate = {
721
- version: 3,
722
- digestAlgorithm: [SHA256_CMS],
723
- encapContentInfo: Pkcs7.Data(eContent),
724
- signerInfo: [
725
- {
726
- version: 3,
727
- subjectKeyIdentifier: ContextTaggedBytes(0, subjectKeyIdentifier),
728
- digestAlgorithm: SHA256_CMS,
729
- signatureAlgorithm: X962.EcdsaWithSHA256,
730
- signature: await this.#crypto.signEcdsa(privateKey, eContent, "der"),
731
- },
732
- ],
733
- };
734
-
735
- const certBytes = DerCodec.encode(Pkcs7.SignedData(certificate));
736
- assertCertificateDerSize(certBytes);
737
- return certBytes;
738
- }
739
-
740
- /**
741
- * Validate general requirements a Matter certificate fields must fulfill.
742
- * Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
743
- */
744
- validateGeneralCertificateFields(cert: RootCertificate | OperationalCertificate | IntermediateCertificate) {
745
- if (cert.serialNumber.length > 20)
746
- throw new CertificateError(
747
- `Serial number must not be longer then 20 octets. Current serial number has ${cert.serialNumber.length} octets.`,
748
- );
749
-
750
- if (cert.signatureAlgorithm !== 1) {
751
- // ecdsa-with-sha256
752
- throw new CertificateError(`Unsupported signature algorithm: ${cert.signatureAlgorithm}`);
753
- }
754
-
755
- if (cert.publicKeyAlgorithm !== 1) {
756
- // ec-pub-key
757
- throw new CertificateError(`Unsupported public key algorithm: ${cert.publicKeyAlgorithm}`);
758
- }
759
-
760
- if (cert.ellipticCurveIdentifier !== 1) {
761
- // prime256v1
762
- throw new CertificateError(`Unsupported elliptic curve identifier: ${cert.ellipticCurveIdentifier}`);
763
- }
764
-
765
- // All implementations SHALL reject Matter certificates with more than 5 RDNs in a single DN.
766
- if (Object.keys(cert.subject).length > 5) {
767
- throw new CertificateError(`Certificate subject must not contain more than 5 RDNs.`);
768
- }
769
- if (Object.keys(cert.issuer).length > 5) {
770
- throw new CertificateError(`Certificate issuer must not contain more than 5 RDNs.`);
771
- }
772
-
773
- // notBefore date should be already reached, notAfter is not checked right now
774
- // TODO: implement real checks when we add "Last known Good UTC time"
775
- if (cert.notBefore * 1000 > Time.nowMs()) {
776
- logger.warn(`Certificate notBefore date is in the future: ${cert.notBefore * 1000} vs ${Time.nowMs()}`);
777
- /*throw new CertificateError(
778
- `Certificate notBefore date is in the future: ${cert.notBefore * 1000} vs ${Time.nowMs()}`,
779
- );*/
780
- }
781
- }
782
-
783
- /**
784
- * Verify requirements a Matter Root certificate must fulfill.
785
- * Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
786
- */
787
- async verifyRootCertificate(rootCert: RootCertificate) {
788
- this.validateGeneralCertificateFields(rootCert);
789
-
790
- // The subject DN SHALL NOT encode any matter-node-id attribute.
791
- if ("nodeId" in rootCert.subject) {
792
- throw new CertificateError(`Root certificate must not contain a nodeId.`);
793
- }
794
-
795
- // The subject DN MAY encode at most one matter-fabric-id attribute.
796
- if (rootCert.subject.fabricId !== undefined) {
797
- if (Array.isArray(rootCert.subject.fabricId)) {
798
- throw new CertificateError(
799
- `Invalid fabricId in NoC certificate: ${Diagnostic.json(rootCert.subject.fabricId)}`,
800
- );
801
- }
802
- // If present, the matter-fabric-id attribute’s value SHALL NOT be 0
803
- if (rootCert.subject.fabricId === FabricId(0)) {
804
- throw new CertificateError(
805
- `Invalid fabricId in NoC certificate: ${Diagnostic.json(rootCert.subject.fabricId)}`,
806
- );
807
- }
808
- }
809
-
810
- // The subject DN SHALL NOT encode any matter-icac-id attribute.
811
- if ("icacId" in rootCert.subject) {
812
- throw new CertificateError(`Root certificate must not contain an icacId.`);
813
- }
814
-
815
- // The subject DN SHALL encode exactly one matter-rcac-id attribute.
816
- if (rootCert.subject.rcacId === undefined || Array.isArray(rootCert.subject.rcacId)) {
817
- throw new CertificateError(
818
- `Invalid rcacId in Root certificate: ${Diagnostic.json(rootCert.subject.rcacId)}`,
819
- );
820
- }
821
-
822
- // The subject DN SHALL NOT encode any matter-noc-cat attribute.
823
- if ("caseAuthenticatedTags" in rootCert.subject) {
824
- throw new CertificateError(`Root certificate must not contain a caseAuthenticatedTags.`);
825
- }
826
-
827
- // The basic constraints extension SHALL be encoded with is-ca set to true.
828
- if (rootCert.extensions.basicConstraints.isCa !== true) {
829
- throw new CertificateError(`Root certificate must have isCa set to true.`);
830
- }
831
-
832
- // The key usage extension SHALL be encoded with at least two flags: keyCertSign (0x0020) and CRLSign (0x0040)
833
- // and optionally with digitalSignature (0x0001).
834
- if (
835
- ExtensionKeyUsageSchema.encode(rootCert.extensions.keyUsage) !== 0x0060 &&
836
- ExtensionKeyUsageSchema.encode(rootCert.extensions.keyUsage) !== 0x0061
837
- ) {
838
- throw new CertificateError(
839
- `Root certificate keyUsage must have keyCertSign and CRLSign and optionally digitalSignature set.`,
840
- );
841
- }
842
-
843
- // The extended key usage extension SHALL NOT be present.
844
- if (rootCert.extensions.extendedKeyUsage !== undefined) {
845
- throw new CertificateError(`Root certificate must not have extendedKeyUsage set.`);
846
- }
847
-
848
- // The subject key identifier extension SHALL be present and 160 bit long.
849
- if (rootCert.extensions.subjectKeyIdentifier === undefined) {
850
- throw new CertificateError(`Root certificate must have subjectKeyIdentifier set.`);
851
- }
852
- if (rootCert.extensions.subjectKeyIdentifier.length !== 20) {
853
- throw new CertificateError(`Root certificate subjectKeyIdentifier must be 160 bit.`);
854
- }
855
-
856
- // The authority key identifier extension SHALL be present and 160 bit long.
857
- if (rootCert.extensions.authorityKeyIdentifier === undefined) {
858
- throw new CertificateError(`Root certificate must have authorityKeyIdentifier set.`);
859
- }
860
- if (rootCert.extensions.authorityKeyIdentifier.length !== 20) {
861
- throw new CertificateError(`Root certificate authorityKeyIdentifier must be 160 bit.`);
862
- }
863
-
864
- // The authority key identifier extension SHALL be equal to the subject key identifier extension.
865
- if (!Bytes.areEqual(rootCert.extensions.authorityKeyIdentifier, rootCert.extensions.subjectKeyIdentifier)) {
866
- throw new CertificateError(
867
- `Root certificate authorityKeyIdentifier must be equal to subjectKeyIdentifier.`,
868
- );
869
- }
870
-
871
- await this.#crypto.verifyEcdsa(
872
- PublicKey(rootCert.ellipticCurvePublicKey),
873
- this.rootCertToAsn1(rootCert),
874
- rootCert.signature,
875
- );
876
- }
877
-
878
- /**
879
- * Verify requirements a Matter Node Operational certificate must fulfill.
880
- * Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
881
- */
882
- async verifyNodeOperationalCertificate(
883
- nocCert: OperationalCertificate,
884
- rootCert: RootCertificate,
885
- icaCert?: IntermediateCertificate,
886
- ) {
887
- this.validateGeneralCertificateFields(nocCert);
888
-
889
- // The subject DN SHALL encode exactly one matter-node-id attribute.
890
- if (nocCert.subject.nodeId === undefined || Array.isArray(nocCert.subject.nodeId)) {
891
- throw new CertificateError(`Invalid nodeId in NoC certificate: ${Diagnostic.json(nocCert.subject.nodeId)}`);
892
- }
893
- // The matter-node-id attribute’s value SHALL be in the Operational Node ID
894
- if (!NodeId.isOperationalNodeId(nocCert.subject.nodeId)) {
895
- throw new CertificateError(`Invalid nodeId in NoC certificate: ${Diagnostic.json(nocCert.subject.nodeId)}`);
896
- }
897
-
898
- // The subject DN SHALL encode exactly one matter-fabric-id attribute.
899
- if (nocCert.subject.fabricId === undefined || Array.isArray(nocCert.subject.fabricId)) {
900
- throw new CertificateError(
901
- `Invalid fabricId in NoC certificate: ${Diagnostic.json(nocCert.subject.fabricId)}`,
902
- );
903
- }
904
- // The matter-fabric-id attribute’s value SHALL NOT be 0
905
- if (nocCert.subject.fabricId === FabricId(0)) {
906
- throw new CertificateError(
907
- `Invalid fabricId in NoC certificate: ${Diagnostic.json(nocCert.subject.fabricId)}`,
908
- );
909
- }
910
-
911
- // The subject DN SHALL NOT encode any matter-icac-id attribute.
912
- if ("icacId" in nocCert.subject) {
913
- throw new CertificateError(`Noc certificate must not contain an icacId.`);
914
- }
915
-
916
- // The subject DN SHALL NOT encode any matter-rcac-id attribute.
917
- if ("rcacId" in nocCert.subject) {
918
- throw new CertificateError(`Noc certificate must not contain an rcacId.`);
919
- }
920
-
921
- // The subject DN MAY encode at most three matter-noc-cat attributes.
922
- if (nocCert.subject.caseAuthenticatedTags !== undefined) {
923
- CaseAuthenticatedTag.validateNocTagList(nocCert.subject.caseAuthenticatedTags); // throws ValidationError
924
- }
925
-
926
- // When any matter-fabric-id attributes are present in either the Matter Root CA Certificate or the Matter ICA
927
- // Certificate, the value SHALL match the one present in the Matter Node Operational Certificate (NOC) within
928
- // the same certificate chain.
929
- if (rootCert.subject.fabricId !== undefined && rootCert.subject.fabricId !== nocCert.subject.fabricId) {
930
- throw new CertificateError(
931
- `FabricId in NoC certificate does not match the fabricId in the parent certificate. ${Diagnostic.json(
932
- rootCert.subject.fabricId,
933
- )} !== ${Diagnostic.json(nocCert.subject.fabricId)}`,
934
- );
935
- }
936
- if (
937
- icaCert !== undefined &&
938
- icaCert.subject.fabricId !== undefined &&
939
- icaCert.subject.fabricId !== nocCert.subject.fabricId
940
- ) {
941
- throw new CertificateError(
942
- `FabricId in NoC certificate does not match the fabricId in the parent certificate. ${Diagnostic.json(
943
- icaCert.subject.fabricId,
944
- )} !== ${Diagnostic.json(nocCert.subject.fabricId)}`,
945
- );
946
- }
947
-
948
- // The basic constraints extension SHALL be encoded with is-ca set to false.
949
- if (nocCert.extensions.basicConstraints.isCa) {
950
- throw new CertificateError(`Noc certificate must not have isCa set to true.`);
951
- }
952
-
953
- // The key usage extension SHALL be encoded with exactly two flags: keyCertSign (0x0020) and CRLSign (0x0040).
954
- // Formally the check should be the following line but Amazon uses a wrong Root cert which also has
955
- // digitalCertificate set, so we just check the the two needed are set and ignore additionally set parameters.
956
- //if (ExtensionKeyUsageSchema.encode(nocCert.extensions.keyUsage) !== 1) {
957
- if (!nocCert.extensions.keyUsage.digitalSignature) {
958
- throw new CertificateError(`Noc certificate must have keyUsage set to digitalSignature.`);
959
- }
960
-
961
- // The extended key usage extension SHALL be encoded with exactly two key-purpose-id values: serverAuth and clientAuth.
962
- if (
963
- nocCert.extensions.extendedKeyUsage === undefined ||
964
- (!nocCert.extensions.extendedKeyUsage.includes(1) && !nocCert.extensions.extendedKeyUsage.includes(2))
965
- ) {
966
- throw new CertificateError(
967
- `Noc certificate must have extendedKeyUsage with serverAuth and clientAuth: ${Diagnostic.json(nocCert.extensions.extendedKeyUsage)}`,
968
- );
969
- }
970
-
971
- // The subject key identifier extension SHALL be present and 160 bit long.
972
- if (nocCert.extensions.subjectKeyIdentifier === undefined) {
973
- throw new CertificateError(`Noc certificate must have subjectKeyIdentifier set.`);
974
- }
975
- if (nocCert.extensions.subjectKeyIdentifier.length !== 20) {
976
- throw new CertificateError(`Noc certificate subjectKeyIdentifier must be 160 bit.`);
977
- }
978
-
979
- // The authority key identifier extension SHALL be present and 160 bit long.
980
- if (nocCert.extensions.authorityKeyIdentifier === undefined) {
981
- throw new CertificateError(`Noc certificate must have authorityKeyIdentifier set.`);
982
- }
983
- if (nocCert.extensions.authorityKeyIdentifier.length !== 20) {
984
- throw new CertificateError(`Noc certificate authorityKeyIdentifier must be 160 bit.`);
985
- }
986
-
987
- // Validate authority key identifier against subject key identifier
988
- if (
989
- !Bytes.areEqual(
990
- nocCert.extensions.authorityKeyIdentifier,
991
- (icaCert ?? rootCert).extensions.subjectKeyIdentifier,
992
- )
993
- ) {
994
- throw new CertificateError(
995
- `Noc certificate authorityKeyIdentifier must be equal to Root/Ica subjectKeyIdentifier.`,
996
- );
997
- }
998
-
999
- await this.#crypto.verifyEcdsa(
1000
- PublicKey((icaCert ?? rootCert).ellipticCurvePublicKey),
1001
- this.nodeOperationalCertToAsn1(nocCert),
1002
- nocCert.signature,
1003
- );
1004
- }
1005
-
1006
- /**
1007
- * Verify requirements a Matter Intermediate CA certificate must fulfill.
1008
- * Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
1009
- */
1010
- async verifyIntermediateCaCertificate(rootCert: RootCertificate, icaCert: IntermediateCertificate) {
1011
- this.validateGeneralCertificateFields(icaCert);
1012
-
1013
- // The subject DN SHALL NOT encode any matter-node-id attribute.
1014
- if ("nodeId" in icaCert.subject) {
1015
- throw new CertificateError(`Ica certificate must not contain a nodeId.`);
1016
- }
1017
-
1018
- // The subject DN MAY encode at most one matter-fabric-id attribute.
1019
- if (icaCert.subject.fabricId !== undefined) {
1020
- if (Array.isArray(icaCert.subject.fabricId)) {
1021
- throw new CertificateError(
1022
- `Invalid fabricId in NoC certificate: ${Diagnostic.json(icaCert.subject.fabricId)}`,
1023
- );
1024
- }
1025
- // If present, the matter-fabric-id attribute’s value SHALL NOT be 0
1026
- if (icaCert.subject.fabricId === FabricId(0)) {
1027
- throw new CertificateError(
1028
- `Invalid fabricId in NoC certificate: ${Diagnostic.json(icaCert.subject.fabricId)}`,
1029
- );
1030
- }
1031
- }
1032
-
1033
- // The subject DN SHALL encode exactly one matter-icac-id attribute.
1034
- if (icaCert.subject.icacId === undefined || Array.isArray(icaCert.subject.icacId)) {
1035
- throw new CertificateError(`Invalid icacId in Ica certificate: ${Diagnostic.json(icaCert.subject.icacId)}`);
1036
- }
1037
-
1038
- // The subject DN SHALL NOT encode any matter-rcac-id attribute.
1039
- if ("rcacId" in icaCert.subject) {
1040
- throw new CertificateError(`Ica certificate must not contain an rcacId.`);
1041
- }
1042
-
1043
- // The subject DN SHALL NOT encode any matter-noc-cat attribute.
1044
- if ("caseAuthenticatedTags" in icaCert.subject) {
1045
- throw new CertificateError(`Ica certificate must not contain a caseAuthenticatedTags.`);
1046
- }
1047
-
1048
- // When any matter-fabric-id attributes are present in either the Matter Root CA Certificate or the Matter ICA
1049
- // Certificate, the value SHALL match the one present in the Matter Node Operational Certificate (NOC) within
1050
- // the same certificate chain.
1051
- // Here means: When both are set, they must match
1052
- if (
1053
- rootCert.subject.fabricId !== undefined &&
1054
- icaCert.subject.fabricId !== undefined &&
1055
- rootCert.subject.fabricId !== icaCert.subject.fabricId
1056
- ) {
1057
- throw new CertificateError(
1058
- `FabricId in Ica certificate does not match the fabricId in the parent certificate. ${Diagnostic.json(
1059
- rootCert.subject.fabricId,
1060
- )} !== ${Diagnostic.json(icaCert.subject.fabricId)}`,
1061
- );
1062
- }
1063
-
1064
- // Verify the certificate chain by checking rcac ids in subject and issuer
1065
- if (rootCert.subject.rcacId !== icaCert.issuer.rcacId) {
1066
- throw new CertificateError(
1067
- `RcacId in Ica certificate does not match the rcacId in the parent certificate. ${Diagnostic.json(
1068
- rootCert.subject.rcacId,
1069
- )} !== ${Diagnostic.json(icaCert.issuer.rcacId)}`,
1070
- );
1071
- }
1072
-
1073
- // The basic constraints extension SHALL be encoded with is-ca set to true.
1074
- if (!icaCert.extensions.basicConstraints.isCa) {
1075
- throw new CertificateError(`Ica certificate must have isCa set to true.`);
1076
- }
1077
-
1078
- // The key usage extension SHALL be encoded with at least two flags: keyCertSign (0x0020) and CRLSign (0x0040)
1079
- // and optionally with digitalSignature (0x0001).
1080
- if (
1081
- ExtensionKeyUsageSchema.encode(rootCert.extensions.keyUsage) !== 0x0060 &&
1082
- ExtensionKeyUsageSchema.encode(rootCert.extensions.keyUsage) !== 0x0061
1083
- ) {
1084
- throw new CertificateError(
1085
- `Ica certificate keyUsage must have keyCertSign and CRLSign and optionally digitalSignature set.`,
1086
- );
1087
- }
1088
-
1089
- // The extended key usage extension SHALL NOT be present.
1090
- if (icaCert.extensions.extendedKeyUsage !== undefined) {
1091
- throw new CertificateError(`Ica certificate must not have extendedKeyUsage set.`);
1092
- }
1093
-
1094
- // The subject key identifier extension SHALL be present and 160 bit long.
1095
- if (icaCert.extensions.subjectKeyIdentifier === undefined) {
1096
- throw new CertificateError(`Ica certificate must have subjectKeyIdentifier set.`);
1097
- }
1098
- if (icaCert.extensions.subjectKeyIdentifier.length !== 20) {
1099
- throw new CertificateError(`Ica certificate subjectKeyIdentifier must be 160 bit.`);
1100
- }
1101
-
1102
- // The authority key identifier extension SHALL be present and 160 bit long.
1103
- if (icaCert.extensions.authorityKeyIdentifier === undefined) {
1104
- throw new CertificateError(`Ica certificate must have authorityKeyIdentifier set.`);
1105
- }
1106
- if (icaCert.extensions.authorityKeyIdentifier.length !== 20) {
1107
- throw new CertificateError(`Ica certificate authorityKeyIdentifier must be 160 bit.`);
1108
- }
1109
-
1110
- // Validate authority key identifier against subject key identifier
1111
- if (!Bytes.areEqual(icaCert.extensions.authorityKeyIdentifier, rootCert.extensions.subjectKeyIdentifier)) {
1112
- throw new CertificateError(
1113
- `Ica certificate authorityKeyIdentifier must be equal to root cert subjectKeyIdentifier.`,
1114
- );
1115
- }
1116
-
1117
- await this.#crypto.verifyEcdsa(
1118
- PublicKey(rootCert.ellipticCurvePublicKey),
1119
- this.intermediateCaCertToAsn1(icaCert),
1120
- icaCert.signature,
1121
- );
1122
- }
1123
-
1124
- async createCertificateSigningRequest(key: Key) {
1125
- const request = {
1126
- version: 0,
1127
- subject: { organization: X520.OrganisationName("CSR") },
1128
- publicKey: X962.PublicKeyEcPrime256v1(key.publicKey),
1129
- endSignedBytes: ContextTagged(0),
1130
- };
1131
-
1132
- return DerCodec.encode({
1133
- request,
1134
- signAlgorithm: X962.EcdsaWithSHA256,
1135
- signature: DerBitString(await this.#crypto.signEcdsa(key, DerCodec.encode(request), "der")),
1136
- });
1137
- }
1138
-
1139
- async getPublicKeyFromCsr(csr: Uint8Array) {
1140
- const { [DerKey.Elements]: rootElements } = DerCodec.decode(csr);
1141
- if (rootElements?.length !== 3) throw new CertificateError("Invalid CSR data");
1142
- const [requestNode, signAlgorithmNode, signatureNode] = rootElements;
1143
-
1144
- // Extract the public key
1145
- const { [DerKey.Elements]: requestElements } = requestNode;
1146
- if (requestElements?.length !== 4) throw new CertificateError("Invalid CSR data");
1147
- const [versionNode, _subjectNode, publicKeyNode] = requestElements;
1148
- const requestVersion = versionNode[DerKey.Bytes][0];
1149
- if (requestVersion !== 0) throw new CertificateError(`Unsupported request version${requestVersion}`);
1150
- // TODO: verify subject = { OrganisationName: "CSR" }
1151
-
1152
- const { [DerKey.Elements]: publicKeyElements } = publicKeyNode;
1153
- if (publicKeyElements?.length !== 2) throw new CertificateError("Invalid CSR data");
1154
- const [_publicKeyTypeNode, publicKeyBytesNode] = publicKeyElements;
1155
- // TODO: verify publicKey algorithm
1156
- const publicKey = publicKeyBytesNode[DerKey.Bytes];
1157
-
1158
- // Verify the CSR signature
1159
- if (
1160
- signAlgorithmNode[DerKey.Elements]?.[0]?.[DerKey.Bytes] === undefined ||
1161
- !Bytes.areEqual(
1162
- X962.EcdsaWithSHA256[DerKey.ObjectId][DerKey.Bytes],
1163
- signAlgorithmNode[DerKey.Elements]?.[0]?.[DerKey.Bytes],
1164
- )
1165
- )
1166
- throw new CertificateError("Unsupported signature type");
1167
- await this.#crypto.verifyEcdsa(
1168
- PublicKey(publicKey),
1169
- DerCodec.encode(requestNode),
1170
- signatureNode[DerKey.Bytes],
1171
- "der",
1172
- );
1173
-
1174
- return publicKey;
1175
- }
1176
- }