@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.
- package/dist/cjs/certificate/AttestationCertificateManager.d.ts.map +1 -1
- package/dist/cjs/certificate/AttestationCertificateManager.js +26 -22
- package/dist/cjs/certificate/AttestationCertificateManager.js.map +1 -1
- package/dist/cjs/certificate/CertificateAuthority.d.ts +1 -2
- package/dist/cjs/certificate/CertificateAuthority.d.ts.map +1 -1
- package/dist/cjs/certificate/CertificateAuthority.js +22 -29
- package/dist/cjs/certificate/CertificateAuthority.js.map +1 -1
- package/dist/cjs/certificate/DeviceCertification.d.ts.map +1 -1
- package/dist/cjs/certificate/DeviceCertification.js +2 -6
- package/dist/cjs/certificate/DeviceCertification.js.map +1 -1
- package/dist/cjs/certificate/index.d.ts +7 -2
- package/dist/cjs/certificate/index.d.ts.map +1 -1
- package/dist/cjs/certificate/index.js +14 -2
- package/dist/cjs/certificate/index.js.map +1 -1
- package/dist/cjs/certificate/kinds/AttestationCertificates.d.ts +34 -0
- package/dist/cjs/certificate/kinds/AttestationCertificates.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/AttestationCertificates.js +64 -0
- package/dist/cjs/certificate/kinds/AttestationCertificates.js.map +6 -0
- package/dist/cjs/certificate/kinds/CertificationDeclaration.d.ts +23 -0
- package/dist/cjs/certificate/kinds/CertificationDeclaration.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/CertificationDeclaration.js +86 -0
- package/dist/cjs/certificate/kinds/CertificationDeclaration.js.map +6 -0
- package/dist/cjs/certificate/kinds/Icac.d.ts +29 -0
- package/dist/cjs/certificate/kinds/Icac.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/Icac.js +138 -0
- package/dist/cjs/certificate/kinds/Icac.js.map +6 -0
- package/dist/cjs/certificate/kinds/Noc.d.ts +27 -0
- package/dist/cjs/certificate/kinds/Noc.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/Noc.js +148 -0
- package/dist/cjs/certificate/kinds/Noc.js.map +6 -0
- package/dist/cjs/certificate/kinds/OperationalBase.d.ts +24 -0
- package/dist/cjs/certificate/kinds/OperationalBase.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/OperationalBase.js +68 -0
- package/dist/cjs/certificate/kinds/OperationalBase.js.map +6 -0
- package/dist/cjs/certificate/kinds/Rcac.d.ts +25 -0
- package/dist/cjs/certificate/kinds/Rcac.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/Rcac.js +119 -0
- package/dist/cjs/certificate/kinds/Rcac.js.map +6 -0
- package/dist/cjs/certificate/kinds/X509Base.d.ts +92 -0
- package/dist/cjs/certificate/kinds/X509Base.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/X509Base.js +344 -0
- package/dist/cjs/certificate/kinds/X509Base.js.map +6 -0
- package/dist/cjs/certificate/kinds/common.d.ts +18 -0
- package/dist/cjs/certificate/kinds/common.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/common.js +42 -0
- package/dist/cjs/certificate/kinds/common.js.map +6 -0
- package/dist/cjs/certificate/kinds/definitions/asn.d.ts +25 -0
- package/dist/cjs/certificate/kinds/definitions/asn.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/definitions/asn.js +83 -0
- package/dist/cjs/certificate/kinds/definitions/asn.js.map +6 -0
- package/dist/cjs/certificate/kinds/definitions/attestation.d.ts +44 -0
- package/dist/cjs/certificate/kinds/definitions/attestation.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/definitions/attestation.js +22 -0
- package/dist/cjs/certificate/kinds/definitions/attestation.js.map +6 -0
- package/dist/cjs/certificate/kinds/definitions/base.d.ts +52 -0
- package/dist/cjs/certificate/kinds/definitions/base.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/definitions/base.js +43 -0
- package/dist/cjs/certificate/kinds/definitions/base.js.map +6 -0
- package/dist/cjs/certificate/kinds/definitions/certification-declaration.d.ts +18 -0
- package/dist/cjs/certificate/kinds/definitions/certification-declaration.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/definitions/certification-declaration.js +50 -0
- package/dist/cjs/certificate/kinds/definitions/certification-declaration.js.map +6 -0
- package/dist/cjs/certificate/kinds/definitions/operational.d.ts +368 -0
- package/dist/cjs/certificate/kinds/definitions/operational.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/definitions/operational.js +149 -0
- package/dist/cjs/certificate/kinds/definitions/operational.js.map +6 -0
- package/dist/cjs/certificate/kinds/index.d.ts +12 -0
- package/dist/cjs/certificate/kinds/index.d.ts.map +1 -0
- package/dist/cjs/certificate/kinds/index.js +29 -0
- package/dist/cjs/certificate/kinds/index.js.map +6 -0
- package/dist/cjs/fabric/Fabric.d.ts +1 -2
- package/dist/cjs/fabric/Fabric.d.ts.map +1 -1
- package/dist/cjs/fabric/Fabric.js +28 -31
- package/dist/cjs/fabric/Fabric.js.map +1 -1
- package/dist/cjs/peer/ControllerCommissioningFlow.d.ts.map +1 -1
- package/dist/cjs/peer/ControllerCommissioningFlow.js +2 -1
- package/dist/cjs/peer/ControllerCommissioningFlow.js.map +1 -1
- package/dist/cjs/session/case/CaseClient.d.ts.map +1 -1
- package/dist/cjs/session/case/CaseClient.js +3 -3
- package/dist/cjs/session/case/CaseClient.js.map +1 -1
- package/dist/cjs/session/case/CaseServer.d.ts.map +1 -1
- package/dist/cjs/session/case/CaseServer.js +2 -2
- package/dist/cjs/session/case/CaseServer.js.map +1 -1
- package/dist/esm/certificate/AttestationCertificateManager.d.ts.map +1 -1
- package/dist/esm/certificate/AttestationCertificateManager.js +20 -16
- package/dist/esm/certificate/AttestationCertificateManager.js.map +1 -1
- package/dist/esm/certificate/CertificateAuthority.d.ts +1 -2
- package/dist/esm/certificate/CertificateAuthority.d.ts.map +1 -1
- package/dist/esm/certificate/CertificateAuthority.js +18 -30
- package/dist/esm/certificate/CertificateAuthority.js.map +1 -1
- package/dist/esm/certificate/DeviceCertification.d.ts.map +1 -1
- package/dist/esm/certificate/DeviceCertification.js +2 -6
- package/dist/esm/certificate/DeviceCertification.js.map +1 -1
- package/dist/esm/certificate/index.d.ts +7 -2
- package/dist/esm/certificate/index.d.ts.map +1 -1
- package/dist/esm/certificate/index.js +10 -2
- package/dist/esm/certificate/index.js.map +1 -1
- package/dist/esm/certificate/kinds/AttestationCertificates.d.ts +34 -0
- package/dist/esm/certificate/kinds/AttestationCertificates.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/AttestationCertificates.js +44 -0
- package/dist/esm/certificate/kinds/AttestationCertificates.js.map +6 -0
- package/dist/esm/certificate/kinds/CertificationDeclaration.d.ts +23 -0
- package/dist/esm/certificate/kinds/CertificationDeclaration.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/CertificationDeclaration.js +66 -0
- package/dist/esm/certificate/kinds/CertificationDeclaration.js.map +6 -0
- package/dist/esm/certificate/kinds/Icac.d.ts +29 -0
- package/dist/esm/certificate/kinds/Icac.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/Icac.js +118 -0
- package/dist/esm/certificate/kinds/Icac.js.map +6 -0
- package/dist/esm/certificate/kinds/Noc.d.ts +27 -0
- package/dist/esm/certificate/kinds/Noc.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/Noc.js +128 -0
- package/dist/esm/certificate/kinds/Noc.js.map +6 -0
- package/dist/esm/certificate/kinds/OperationalBase.d.ts +24 -0
- package/dist/esm/certificate/kinds/OperationalBase.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/OperationalBase.js +48 -0
- package/dist/esm/certificate/kinds/OperationalBase.js.map +6 -0
- package/dist/esm/certificate/kinds/Rcac.d.ts +25 -0
- package/dist/esm/certificate/kinds/Rcac.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/Rcac.js +99 -0
- package/dist/esm/certificate/kinds/Rcac.js.map +6 -0
- package/dist/esm/certificate/kinds/X509Base.d.ts +92 -0
- package/dist/esm/certificate/kinds/X509Base.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/X509Base.js +347 -0
- package/dist/esm/certificate/kinds/X509Base.js.map +6 -0
- package/dist/esm/certificate/kinds/common.d.ts +18 -0
- package/dist/esm/certificate/kinds/common.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/common.js +22 -0
- package/dist/esm/certificate/kinds/common.js.map +6 -0
- package/dist/esm/certificate/kinds/definitions/asn.d.ts +25 -0
- package/dist/esm/certificate/kinds/definitions/asn.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/definitions/asn.js +63 -0
- package/dist/esm/certificate/kinds/definitions/asn.js.map +6 -0
- package/dist/esm/certificate/kinds/definitions/attestation.d.ts +44 -0
- package/dist/esm/certificate/kinds/definitions/attestation.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/definitions/attestation.js +6 -0
- package/dist/esm/certificate/kinds/definitions/attestation.js.map +6 -0
- package/dist/esm/certificate/kinds/definitions/base.d.ts +52 -0
- package/dist/esm/certificate/kinds/definitions/base.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/definitions/base.js +23 -0
- package/dist/esm/certificate/kinds/definitions/base.js.map +6 -0
- package/dist/esm/certificate/kinds/definitions/certification-declaration.d.ts +18 -0
- package/dist/esm/certificate/kinds/definitions/certification-declaration.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/definitions/certification-declaration.js +41 -0
- package/dist/esm/certificate/kinds/definitions/certification-declaration.js.map +6 -0
- package/dist/esm/certificate/kinds/definitions/operational.d.ts +368 -0
- package/dist/esm/certificate/kinds/definitions/operational.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/definitions/operational.js +148 -0
- package/dist/esm/certificate/kinds/definitions/operational.js.map +6 -0
- package/dist/esm/certificate/kinds/index.d.ts +12 -0
- package/dist/esm/certificate/kinds/index.d.ts.map +1 -0
- package/dist/esm/certificate/kinds/index.js +12 -0
- package/dist/esm/certificate/kinds/index.js.map +6 -0
- package/dist/esm/fabric/Fabric.d.ts +1 -2
- package/dist/esm/fabric/Fabric.d.ts.map +1 -1
- package/dist/esm/fabric/Fabric.js +28 -36
- package/dist/esm/fabric/Fabric.js.map +1 -1
- package/dist/esm/peer/ControllerCommissioningFlow.d.ts.map +1 -1
- package/dist/esm/peer/ControllerCommissioningFlow.js +2 -1
- package/dist/esm/peer/ControllerCommissioningFlow.js.map +1 -1
- package/dist/esm/session/case/CaseClient.d.ts.map +1 -1
- package/dist/esm/session/case/CaseClient.js +3 -3
- package/dist/esm/session/case/CaseClient.js.map +1 -1
- package/dist/esm/session/case/CaseServer.d.ts.map +1 -1
- package/dist/esm/session/case/CaseServer.js +2 -2
- package/dist/esm/session/case/CaseServer.js.map +1 -1
- package/package.json +6 -6
- package/src/certificate/AttestationCertificateManager.ts +20 -16
- package/src/certificate/CertificateAuthority.ts +18 -35
- package/src/certificate/DeviceCertification.ts +2 -6
- package/src/certificate/index.ts +7 -2
- package/src/certificate/kinds/AttestationCertificates.ts +48 -0
- package/src/certificate/kinds/CertificationDeclaration.ts +91 -0
- package/src/certificate/kinds/Icac.ts +156 -0
- package/src/certificate/kinds/Noc.ts +164 -0
- package/src/certificate/kinds/OperationalBase.ts +72 -0
- package/src/certificate/kinds/Rcac.ts +126 -0
- package/src/certificate/kinds/X509Base.ts +380 -0
- package/src/certificate/kinds/common.ts +24 -0
- package/src/certificate/kinds/definitions/asn.ts +97 -0
- package/src/certificate/kinds/definitions/attestation.ts +46 -0
- package/src/certificate/kinds/definitions/base.ts +43 -0
- package/src/certificate/kinds/definitions/certification-declaration.ts +38 -0
- package/src/certificate/kinds/definitions/operational.ts +179 -0
- package/src/certificate/kinds/index.ts +12 -0
- package/src/fabric/Fabric.ts +28 -40
- package/src/peer/ControllerCommissioningFlow.ts +2 -1
- package/src/session/case/CaseClient.ts +3 -3
- package/src/session/case/CaseServer.ts +2 -2
- package/dist/cjs/certificate/CertificateManager.d.ts +0 -578
- package/dist/cjs/certificate/CertificateManager.d.ts.map +0 -1
- package/dist/cjs/certificate/CertificateManager.js +0 -843
- package/dist/cjs/certificate/CertificateManager.js.map +0 -6
- package/dist/cjs/certificate/CertificationDeclarationManager.d.ts +0 -11
- package/dist/cjs/certificate/CertificationDeclarationManager.d.ts.map +0 -1
- package/dist/cjs/certificate/CertificationDeclarationManager.js +0 -54
- package/dist/cjs/certificate/CertificationDeclarationManager.js.map +0 -6
- package/dist/esm/certificate/CertificateManager.d.ts +0 -578
- package/dist/esm/certificate/CertificateManager.d.ts.map +0 -1
- package/dist/esm/certificate/CertificateManager.js +0 -870
- package/dist/esm/certificate/CertificateManager.js.map +0 -6
- package/dist/esm/certificate/CertificationDeclarationManager.d.ts +0 -11
- package/dist/esm/certificate/CertificationDeclarationManager.d.ts.map +0 -1
- package/dist/esm/certificate/CertificationDeclarationManager.js +0 -34
- package/dist/esm/certificate/CertificationDeclarationManager.js.map +0 -6
- package/src/certificate/CertificateManager.ts +0 -1176
- package/src/certificate/CertificationDeclarationManager.ts +0 -52
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Bytes, Crypto, Diagnostic, PublicKey } from "#general";
|
|
8
|
+
import { CaseAuthenticatedTag, FabricId, NodeId } from "#types";
|
|
9
|
+
import { CertificateError } from "./common.js";
|
|
10
|
+
import { OperationalCertificate } from "./definitions/operational.js";
|
|
11
|
+
import { Icac } from "./Icac.js";
|
|
12
|
+
import { OperationalBase } from "./OperationalBase.js";
|
|
13
|
+
import { Rcac } from "./Rcac.js";
|
|
14
|
+
|
|
15
|
+
export class Noc extends OperationalBase<OperationalCertificate.Noc> {
|
|
16
|
+
/** Construct the class from a Tlv version of the certificate */
|
|
17
|
+
static fromTlv(tlv: Uint8Array) {
|
|
18
|
+
return new Noc(OperationalCertificate.TlvNoc.decode(tlv));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Validates all basic certificate fields on construction. */
|
|
22
|
+
protected validateFields() {
|
|
23
|
+
const {
|
|
24
|
+
issuer: { icacId, rcacId },
|
|
25
|
+
extensions: {
|
|
26
|
+
basicConstraints: { isCa },
|
|
27
|
+
},
|
|
28
|
+
} = this.cert;
|
|
29
|
+
if (icacId === undefined && rcacId === undefined) {
|
|
30
|
+
throw new CertificateError("Issuer RCAC or ICAC ID must be defined for an operational certificate.");
|
|
31
|
+
}
|
|
32
|
+
if (isCa) {
|
|
33
|
+
throw new CertificateError("Node operational certificate must not be a CA.");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Encodes the certificate with the signature as Matter Tlv.
|
|
39
|
+
* If the certificate is not signed, it throws a CertificateError.
|
|
40
|
+
*/
|
|
41
|
+
asSignedTlv() {
|
|
42
|
+
return OperationalCertificate.TlvNoc.encode({ ...this.cert, signature: this.signature });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Verify requirements a Matter Node Operational certificate must fulfill.
|
|
47
|
+
* Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
|
|
48
|
+
*/
|
|
49
|
+
async verify(crypto: Crypto, root: Rcac, ica?: Icac) {
|
|
50
|
+
this.generalVerify();
|
|
51
|
+
|
|
52
|
+
const {
|
|
53
|
+
subject,
|
|
54
|
+
extensions: { extendedKeyUsage, subjectKeyIdentifier, authorityKeyIdentifier },
|
|
55
|
+
} = this.cert;
|
|
56
|
+
const { nodeId, fabricId, caseAuthenticatedTags } = subject;
|
|
57
|
+
const {
|
|
58
|
+
subject: { fabricId: rootFabricId },
|
|
59
|
+
} = root.cert;
|
|
60
|
+
const {
|
|
61
|
+
subject: { fabricId: icaFabricId },
|
|
62
|
+
} = ica?.cert ?? { subject: {} };
|
|
63
|
+
|
|
64
|
+
// The subject DN SHALL encode exactly one matter-node-id attribute.
|
|
65
|
+
if (nodeId === undefined || Array.isArray(nodeId)) {
|
|
66
|
+
throw new CertificateError(`Invalid nodeId in NoC certificate: ${Diagnostic.json(nodeId)}`);
|
|
67
|
+
}
|
|
68
|
+
// The matter-node-id attribute’s value SHALL be in the Operational Node ID
|
|
69
|
+
if (!NodeId.isOperationalNodeId(nodeId)) {
|
|
70
|
+
throw new CertificateError(`Invalid nodeId in NoC certificate: ${Diagnostic.json(nodeId)}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// The subject DN SHALL encode exactly one matter-fabric-id attribute.
|
|
74
|
+
if (fabricId === undefined || Array.isArray(fabricId)) {
|
|
75
|
+
throw new CertificateError(`Invalid fabricId in NoC certificate: ${Diagnostic.json(fabricId)}`);
|
|
76
|
+
}
|
|
77
|
+
// The matter-fabric-id attribute’s value SHALL NOT be 0
|
|
78
|
+
if (fabricId === FabricId(0)) {
|
|
79
|
+
throw new CertificateError(`Invalid fabricId in NoC certificate: ${Diagnostic.json(fabricId)}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// The subject DN SHALL NOT encode any matter-icac-id attribute.
|
|
83
|
+
if ("icacId" in subject) {
|
|
84
|
+
throw new CertificateError(`Noc certificate must not contain an icacId.`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// The subject DN SHALL NOT encode any matter-rcac-id attribute.
|
|
88
|
+
if ("rcacId" in subject) {
|
|
89
|
+
throw new CertificateError(`Noc certificate must not contain an rcacId.`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// The subject DN MAY encode at most three matter-noc-cat attributes.
|
|
93
|
+
if (caseAuthenticatedTags !== undefined) {
|
|
94
|
+
CaseAuthenticatedTag.validateNocTagList(caseAuthenticatedTags); // throws ValidationError
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// When any matter-fabric-id attributes are present in either the Matter Root CA Certificate or the Matter ICA
|
|
98
|
+
// Certificate, the value SHALL match the one present in the Matter Node Operational Certificate (NOC) within
|
|
99
|
+
// the same certificate chain.
|
|
100
|
+
if (rootFabricId !== undefined && rootFabricId !== fabricId) {
|
|
101
|
+
throw new CertificateError(
|
|
102
|
+
`FabricId in NoC certificate does not match the fabricId in the parent certificate. ${Diagnostic.json(
|
|
103
|
+
rootFabricId,
|
|
104
|
+
)} !== ${Diagnostic.json(fabricId)}`,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
if (icaFabricId !== undefined && icaFabricId !== fabricId) {
|
|
108
|
+
throw new CertificateError(
|
|
109
|
+
`FabricId in NoC certificate does not match the fabricId in the parent certificate. ${Diagnostic.json(
|
|
110
|
+
icaFabricId,
|
|
111
|
+
)} !== ${Diagnostic.json(fabricId)}`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// The basic constraints extension SHALL be encoded with is-ca set to false.
|
|
116
|
+
if (this.cert.extensions.basicConstraints.isCa) {
|
|
117
|
+
throw new CertificateError(`Noc certificate must not have isCa set to true.`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// The key usage extension SHALL be encoded with exactly two flags: keyCertSign (0x0020) and CRLSign (0x0040).
|
|
121
|
+
// Formally the check should be the following line but Amazon uses a wrong Root cert which also has
|
|
122
|
+
// digitalCertificate set, so we just check that the two needed are set and ignore additionally set parameters.
|
|
123
|
+
//if (ExtensionKeyUsageSchema.encode(nocCert.extensions.keyUsage) !== 1) {
|
|
124
|
+
if (!this.cert.extensions.keyUsage.digitalSignature) {
|
|
125
|
+
throw new CertificateError(`Noc certificate must have keyUsage set to digitalSignature.`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// The extended key usage extension SHALL be encoded with exactly two key-purpose-id values: serverAuth and clientAuth.
|
|
129
|
+
if (extendedKeyUsage === undefined || (!extendedKeyUsage.includes(1) && !extendedKeyUsage.includes(2))) {
|
|
130
|
+
throw new CertificateError(
|
|
131
|
+
`Noc certificate must have extendedKeyUsage with serverAuth and clientAuth: ${Diagnostic.json(extendedKeyUsage)}`,
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// The subject key identifier extension SHALL be present and 160 bit long.
|
|
136
|
+
if (subjectKeyIdentifier === undefined) {
|
|
137
|
+
throw new CertificateError(`Noc certificate must have subjectKeyIdentifier set.`);
|
|
138
|
+
}
|
|
139
|
+
if (subjectKeyIdentifier.length !== 20) {
|
|
140
|
+
throw new CertificateError(`Noc certificate subjectKeyIdentifier must be 160 bit.`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// The authority key identifier extension SHALL be present and 160 bit long.
|
|
144
|
+
if (authorityKeyIdentifier === undefined) {
|
|
145
|
+
throw new CertificateError(`Noc certificate must have authorityKeyIdentifier set.`);
|
|
146
|
+
}
|
|
147
|
+
if (authorityKeyIdentifier.length !== 20) {
|
|
148
|
+
throw new CertificateError(`Noc certificate authorityKeyIdentifier must be 160 bit.`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Validate authority key identifier against subject key identifier
|
|
152
|
+
if (!Bytes.areEqual(authorityKeyIdentifier, (ica?.cert ?? root.cert).extensions.subjectKeyIdentifier)) {
|
|
153
|
+
throw new CertificateError(
|
|
154
|
+
`Noc certificate authorityKeyIdentifier must be equal to Root/Ica subjectKeyIdentifier.`,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
await crypto.verifyEcdsa(
|
|
159
|
+
PublicKey((ica?.cert ?? root.cert).ellipticCurvePublicKey),
|
|
160
|
+
this.asUnsignedAsn1(),
|
|
161
|
+
this.signature,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Logger, Time } from "#general";
|
|
8
|
+
import { X509Base } from "./X509Base.js";
|
|
9
|
+
import { CertificateError, Unsigned } from "./common.js";
|
|
10
|
+
import { X509Certificate } from "./definitions/base.js";
|
|
11
|
+
|
|
12
|
+
const logger = Logger.get("OperationalBaseCertificate");
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Base class for all operational certificates (RCAC, ICAC, NOC)
|
|
16
|
+
*/
|
|
17
|
+
export abstract class OperationalBase<CT extends X509Certificate> extends X509Base<CT> {
|
|
18
|
+
constructor(cert: CT | Unsigned<CT>) {
|
|
19
|
+
super(cert);
|
|
20
|
+
this.validateFields();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Validates all basic certificate fields on construction. */
|
|
24
|
+
protected abstract validateFields(): void;
|
|
25
|
+
|
|
26
|
+
/** Encodes the signed certificate into the Matter TLV format. */
|
|
27
|
+
abstract asSignedTlv(signature: Uint8Array<ArrayBufferLike>): Uint8Array;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Verifies general requirements a Matter certificate fields must fulfill.
|
|
31
|
+
* Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
|
|
32
|
+
*/
|
|
33
|
+
generalVerify() {
|
|
34
|
+
const cert = this.cert;
|
|
35
|
+
if (cert.serialNumber.length > 20)
|
|
36
|
+
throw new CertificateError(
|
|
37
|
+
`Serial number must not be longer then 20 octets. Current serial number has ${cert.serialNumber.length} octets.`,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (cert.signatureAlgorithm !== 1) {
|
|
41
|
+
// ecdsa-with-sha256
|
|
42
|
+
throw new CertificateError(`Unsupported signature algorithm: ${cert.signatureAlgorithm}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (cert.publicKeyAlgorithm !== 1) {
|
|
46
|
+
// ec-pub-key
|
|
47
|
+
throw new CertificateError(`Unsupported public key algorithm: ${cert.publicKeyAlgorithm}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (cert.ellipticCurveIdentifier !== 1) {
|
|
51
|
+
// prime256v1
|
|
52
|
+
throw new CertificateError(`Unsupported elliptic curve identifier: ${cert.ellipticCurveIdentifier}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// All implementations SHALL reject Matter certificates with more than 5 RDNs in a single DN.
|
|
56
|
+
if (Object.keys(cert.subject).length > 5) {
|
|
57
|
+
throw new CertificateError(`Certificate subject must not contain more than 5 RDNs.`);
|
|
58
|
+
}
|
|
59
|
+
if (Object.keys(cert.issuer).length > 5) {
|
|
60
|
+
throw new CertificateError(`Certificate issuer must not contain more than 5 RDNs.`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// notBefore date should be already reached, notAfter is not checked right now
|
|
64
|
+
// TODO: implement real checks when we add "Last known Good UTC time"
|
|
65
|
+
if (cert.notBefore * 1000 > Time.nowMs()) {
|
|
66
|
+
logger.warn(`Certificate notBefore date is in the future: ${cert.notBefore * 1000} vs ${Time.nowMs()}`);
|
|
67
|
+
/*throw new CertificateError(
|
|
68
|
+
`Certificate notBefore date is in the future: ${cert.notBefore * 1000} vs ${Time.nowMs()}`,
|
|
69
|
+
);*/
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Bytes, Crypto, Diagnostic, PublicKey } from "#general";
|
|
8
|
+
import { FabricId } from "#types";
|
|
9
|
+
import { CertificateError } from "./common.js";
|
|
10
|
+
import { ExtensionKeyUsageSchema } from "./definitions/base.js";
|
|
11
|
+
import { OperationalCertificate } from "./definitions/operational.js";
|
|
12
|
+
import { OperationalBase } from "./OperationalBase.js";
|
|
13
|
+
|
|
14
|
+
export class Rcac extends OperationalBase<OperationalCertificate.Rcac> {
|
|
15
|
+
/** Construct the class from a Tlv version of the certificate */
|
|
16
|
+
static fromTlv(tlv: Uint8Array): Rcac {
|
|
17
|
+
return new Rcac(OperationalCertificate.TlvRcac.decode(tlv));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Validates all basic certificate fields on construction. */
|
|
21
|
+
protected validateFields() {
|
|
22
|
+
const {
|
|
23
|
+
extensions: {
|
|
24
|
+
basicConstraints: { isCa },
|
|
25
|
+
},
|
|
26
|
+
} = this.cert;
|
|
27
|
+
if (!isCa) {
|
|
28
|
+
throw new CertificateError("Root certificate must be a CA.");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Encodes the certificate with the signature as Matter Tlv.
|
|
34
|
+
* If the certificate is not signed, it throws a CertificateError.
|
|
35
|
+
*/
|
|
36
|
+
asSignedTlv() {
|
|
37
|
+
return OperationalCertificate.TlvRcac.encode({ ...this.cert, signature: this.signature });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Verify requirements a Matter Root certificate must fulfill.
|
|
42
|
+
* Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
|
|
43
|
+
*/
|
|
44
|
+
async verify(crypto: Crypto) {
|
|
45
|
+
this.generalVerify();
|
|
46
|
+
|
|
47
|
+
const { subject, extensions } = this.cert;
|
|
48
|
+
const { fabricId, rcacId } = subject;
|
|
49
|
+
const { basicConstraints, subjectKeyIdentifier, authorityKeyIdentifier } = extensions;
|
|
50
|
+
|
|
51
|
+
// The subject DN SHALL NOT encode any matter-node-id attribute.
|
|
52
|
+
if ("nodeId" in subject) {
|
|
53
|
+
throw new CertificateError(`Root certificate must not contain a nodeId.`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// The subject DN MAY encode at most one matter-fabric-id attribute.
|
|
57
|
+
if (fabricId !== undefined) {
|
|
58
|
+
if (Array.isArray(fabricId)) {
|
|
59
|
+
throw new CertificateError(`Invalid fabricId in NoC certificate: ${Diagnostic.json(fabricId)}`);
|
|
60
|
+
}
|
|
61
|
+
// If present, the matter-fabric-id attribute’s value SHALL NOT be 0
|
|
62
|
+
if (fabricId === FabricId(0)) {
|
|
63
|
+
throw new CertificateError(`Invalid fabricId in NoC certificate: ${Diagnostic.json(fabricId)}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// The subject DN SHALL NOT encode any matter-icac-id attribute.
|
|
68
|
+
if ("icacId" in subject) {
|
|
69
|
+
throw new CertificateError(`Root certificate must not contain an icacId.`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// The subject DN SHALL encode exactly one matter-rcac-id attribute.
|
|
73
|
+
if (rcacId === undefined || Array.isArray(rcacId)) {
|
|
74
|
+
throw new CertificateError(`Invalid rcacId in Root certificate: ${Diagnostic.json(rcacId)}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The subject DN SHALL NOT encode any matter-noc-cat attribute.
|
|
78
|
+
if ("caseAuthenticatedTags" in subject) {
|
|
79
|
+
throw new CertificateError(`Root certificate must not contain a caseAuthenticatedTags.`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// The basic constraints extension SHALL be encoded with is-ca set to true.
|
|
83
|
+
if (basicConstraints.isCa !== true) {
|
|
84
|
+
throw new CertificateError(`Root certificate must have isCa set to true.`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// The key usage extension SHALL be encoded with at least two flags: keyCertSign (0x0020) and CRLSign (0x0040)
|
|
88
|
+
// and optionally with digitalSignature (0x0001).
|
|
89
|
+
const keyUsage = ExtensionKeyUsageSchema.encode(extensions.keyUsage);
|
|
90
|
+
if (keyUsage !== 0x0060 && keyUsage !== 0x0061) {
|
|
91
|
+
throw new CertificateError(
|
|
92
|
+
`Root certificate keyUsage must have keyCertSign and CRLSign and optionally digitalSignature set.`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// The extended key usage extension SHALL NOT be present.
|
|
97
|
+
if (extensions.extendedKeyUsage !== undefined) {
|
|
98
|
+
throw new CertificateError(`Root certificate must not have extendedKeyUsage set.`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// The subject key identifier extension SHALL be present and 160 bit long.
|
|
102
|
+
if (subjectKeyIdentifier === undefined) {
|
|
103
|
+
throw new CertificateError(`Root certificate must have subjectKeyIdentifier set.`);
|
|
104
|
+
}
|
|
105
|
+
if (subjectKeyIdentifier.length !== 20) {
|
|
106
|
+
throw new CertificateError(`Root certificate subjectKeyIdentifier must be 160 bit.`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// The authority key identifier extension SHALL be present and 160 bit long.
|
|
110
|
+
if (authorityKeyIdentifier === undefined) {
|
|
111
|
+
throw new CertificateError(`Root certificate must have authorityKeyIdentifier set.`);
|
|
112
|
+
}
|
|
113
|
+
if (authorityKeyIdentifier.length !== 20) {
|
|
114
|
+
throw new CertificateError(`Root certificate authorityKeyIdentifier must be 160 bit.`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// The authority key identifier extension SHALL be equal to the subject key identifier extension.
|
|
118
|
+
if (!Bytes.areEqual(authorityKeyIdentifier, subjectKeyIdentifier)) {
|
|
119
|
+
throw new CertificateError(
|
|
120
|
+
`Root certificate authorityKeyIdentifier must be equal to subjectKeyIdentifier.`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
await crypto.verifyEcdsa(PublicKey(this.cert.ellipticCurvePublicKey), this.asUnsignedAsn1(), this.signature);
|
|
125
|
+
}
|
|
126
|
+
}
|