@matter/protocol 0.13.1-alpha.0-20250506-f9ad9c3d8 → 0.13.1-alpha.0-20250508-047aa0277
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 +7 -13
- package/dist/cjs/certificate/AttestationCertificateManager.d.ts.map +1 -1
- package/dist/cjs/certificate/AttestationCertificateManager.js +37 -29
- package/dist/cjs/certificate/AttestationCertificateManager.js.map +1 -1
- package/dist/cjs/certificate/CertificateAuthority.d.ts +1 -6
- package/dist/cjs/certificate/CertificateAuthority.d.ts.map +1 -1
- package/dist/cjs/certificate/CertificateAuthority.js +56 -38
- package/dist/cjs/certificate/CertificateAuthority.js.map +1 -1
- package/dist/cjs/certificate/CertificateManager.d.ts +8 -8
- package/dist/cjs/certificate/CertificateManager.d.ts.map +1 -1
- package/dist/cjs/certificate/CertificateManager.js +20 -16
- package/dist/cjs/certificate/CertificateManager.js.map +1 -1
- package/dist/cjs/certificate/DeviceCertification.d.ts +1 -1
- package/dist/cjs/certificate/DeviceCertification.d.ts.map +1 -1
- package/dist/cjs/certificate/DeviceCertification.js +24 -26
- package/dist/cjs/certificate/DeviceCertification.js.map +2 -2
- package/dist/cjs/common/FailsafeContext.d.ts +2 -2
- package/dist/cjs/common/FailsafeContext.d.ts.map +1 -1
- package/dist/cjs/common/FailsafeContext.js +20 -13
- package/dist/cjs/common/FailsafeContext.js.map +1 -1
- package/dist/cjs/fabric/Fabric.d.ts +8 -6
- package/dist/cjs/fabric/Fabric.d.ts.map +1 -1
- package/dist/cjs/fabric/Fabric.js +15 -9
- package/dist/cjs/fabric/Fabric.js.map +1 -1
- package/dist/cjs/fabric/FabricAuthority.d.ts.map +1 -1
- package/dist/cjs/fabric/FabricAuthority.js +5 -3
- package/dist/cjs/fabric/FabricAuthority.js.map +1 -1
- package/dist/cjs/fabric/FabricManager.d.ts +1 -1
- package/dist/cjs/fabric/FabricManager.d.ts.map +1 -1
- package/dist/cjs/fabric/FabricManager.js +2 -2
- package/dist/cjs/fabric/FabricManager.js.map +1 -1
- package/dist/cjs/peer/ControllerCommissioningFlow.js +2 -2
- package/dist/cjs/peer/ControllerCommissioningFlow.js.map +1 -1
- package/dist/cjs/session/SessionManager.d.ts +4 -0
- package/dist/cjs/session/SessionManager.d.ts.map +1 -1
- package/dist/cjs/session/SessionManager.js +11 -2
- package/dist/cjs/session/SessionManager.js.map +1 -1
- package/dist/cjs/session/case/CaseClient.d.ts.map +1 -1
- package/dist/cjs/session/case/CaseClient.js +13 -10
- 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 +11 -8
- package/dist/cjs/session/case/CaseServer.js.map +1 -1
- package/dist/cjs/session/pase/PaseClient.js +1 -1
- package/dist/cjs/session/pase/PaseClient.js.map +1 -1
- package/dist/cjs/session/pase/PaseServer.js +1 -1
- package/dist/cjs/session/pase/PaseServer.js.map +1 -1
- package/dist/esm/certificate/AttestationCertificateManager.d.ts +7 -13
- package/dist/esm/certificate/AttestationCertificateManager.d.ts.map +1 -1
- package/dist/esm/certificate/AttestationCertificateManager.js +37 -29
- package/dist/esm/certificate/AttestationCertificateManager.js.map +1 -1
- package/dist/esm/certificate/CertificateAuthority.d.ts +1 -6
- package/dist/esm/certificate/CertificateAuthority.d.ts.map +1 -1
- package/dist/esm/certificate/CertificateAuthority.js +57 -38
- package/dist/esm/certificate/CertificateAuthority.js.map +1 -1
- package/dist/esm/certificate/CertificateManager.d.ts +8 -8
- package/dist/esm/certificate/CertificateManager.d.ts.map +1 -1
- package/dist/esm/certificate/CertificateManager.js +20 -16
- package/dist/esm/certificate/CertificateManager.js.map +1 -1
- package/dist/esm/certificate/DeviceCertification.d.ts +1 -1
- package/dist/esm/certificate/DeviceCertification.d.ts.map +1 -1
- package/dist/esm/certificate/DeviceCertification.js +24 -26
- package/dist/esm/certificate/DeviceCertification.js.map +2 -2
- package/dist/esm/common/FailsafeContext.d.ts +2 -2
- package/dist/esm/common/FailsafeContext.d.ts.map +1 -1
- package/dist/esm/common/FailsafeContext.js +28 -14
- package/dist/esm/common/FailsafeContext.js.map +1 -1
- package/dist/esm/fabric/Fabric.d.ts +8 -6
- package/dist/esm/fabric/Fabric.d.ts.map +1 -1
- package/dist/esm/fabric/Fabric.js +15 -9
- package/dist/esm/fabric/Fabric.js.map +1 -1
- package/dist/esm/fabric/FabricAuthority.d.ts.map +1 -1
- package/dist/esm/fabric/FabricAuthority.js +5 -3
- package/dist/esm/fabric/FabricAuthority.js.map +1 -1
- package/dist/esm/fabric/FabricManager.d.ts +1 -1
- package/dist/esm/fabric/FabricManager.d.ts.map +1 -1
- package/dist/esm/fabric/FabricManager.js +2 -2
- package/dist/esm/fabric/FabricManager.js.map +1 -1
- package/dist/esm/peer/ControllerCommissioningFlow.js +2 -2
- package/dist/esm/peer/ControllerCommissioningFlow.js.map +1 -1
- package/dist/esm/session/SessionManager.d.ts +4 -0
- package/dist/esm/session/SessionManager.d.ts.map +1 -1
- package/dist/esm/session/SessionManager.js +11 -2
- package/dist/esm/session/SessionManager.js.map +1 -1
- package/dist/esm/session/case/CaseClient.d.ts.map +1 -1
- package/dist/esm/session/case/CaseClient.js +13 -10
- 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 +11 -8
- package/dist/esm/session/case/CaseServer.js.map +1 -1
- package/dist/esm/session/pase/PaseClient.js +1 -1
- package/dist/esm/session/pase/PaseClient.js.map +1 -1
- package/dist/esm/session/pase/PaseServer.js +1 -1
- package/dist/esm/session/pase/PaseServer.js.map +1 -1
- package/package.json +6 -6
- package/src/certificate/AttestationCertificateManager.ts +37 -27
- package/src/certificate/CertificateAuthority.ts +60 -38
- package/src/certificate/CertificateManager.ts +20 -16
- package/src/certificate/DeviceCertification.ts +28 -32
- package/src/common/FailsafeContext.ts +29 -14
- package/src/fabric/Fabric.ts +17 -9
- package/src/fabric/FabricAuthority.ts +5 -4
- package/src/fabric/FabricManager.ts +2 -2
- package/src/peer/ControllerCommissioningFlow.ts +2 -2
- package/src/session/SessionManager.ts +13 -2
- package/src/session/case/CaseClient.ts +13 -10
- package/src/session/case/CaseServer.ts +11 -8
- package/src/session/pase/PaseClient.ts +1 -1
- package/src/session/pase/PaseServer.ts +1 -1
|
@@ -33,29 +33,39 @@ export class AttestationCertificateManager {
|
|
|
33
33
|
|
|
34
34
|
// We use the official PAA cert for now because else pairing with Chip tool do not work because
|
|
35
35
|
// only this one is the Certificate store
|
|
36
|
-
|
|
36
|
+
readonly #paaKeyPair = PrivateKey(TestCert_PAA_NoVID_PrivateKey, {
|
|
37
37
|
publicKey: TestCert_PAA_NoVID_PublicKey,
|
|
38
38
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
readonly #vendorId: VendorId;
|
|
40
|
+
readonly #paiKeyPair: PrivateKey;
|
|
41
|
+
readonly #paiKeyIdentifier: Uint8Array;
|
|
42
|
+
readonly #paaKeyIdentifier = TestCert_PAA_NoVID_SKID;
|
|
43
|
+
readonly #paiCertId = BigInt(1);
|
|
44
|
+
readonly #paiCertBytes;
|
|
45
|
+
#nextCertificateId = 2;
|
|
45
46
|
|
|
46
|
-
constructor(
|
|
47
|
-
this
|
|
47
|
+
constructor(vendorId: VendorId, paiKeyPair: PrivateKey, paiKeyIdentifier: Uint8Array) {
|
|
48
|
+
this.#vendorId = vendorId;
|
|
49
|
+
this.#paiKeyPair = paiKeyPair;
|
|
50
|
+
this.#paiKeyIdentifier = paiKeyIdentifier;
|
|
51
|
+
this.#paiCertBytes = this.generatePAICert(vendorId);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static async create(vendorId: VendorId) {
|
|
55
|
+
const key = await Crypto.createKeyPair();
|
|
56
|
+
const identifier = await Crypto.hash(key.publicKey);
|
|
57
|
+
return new AttestationCertificateManager(vendorId, key, identifier.slice(0, 20));
|
|
48
58
|
}
|
|
49
59
|
|
|
50
60
|
getPAICert() {
|
|
51
|
-
return this
|
|
61
|
+
return this.#paiCertBytes;
|
|
52
62
|
}
|
|
53
63
|
|
|
54
|
-
getDACert(productId: number) {
|
|
55
|
-
const dacKeyPair = Crypto.createKeyPair();
|
|
64
|
+
async getDACert(productId: number) {
|
|
65
|
+
const dacKeyPair = await Crypto.createKeyPair();
|
|
56
66
|
return {
|
|
57
67
|
keyPair: dacKeyPair,
|
|
58
|
-
dac: this.generateDaCert(dacKeyPair.publicKey, this
|
|
68
|
+
dac: await this.generateDaCert(dacKeyPair.publicKey, this.#vendorId, productId),
|
|
59
69
|
};
|
|
60
70
|
}
|
|
61
71
|
|
|
@@ -79,7 +89,7 @@ export class AttestationCertificateManager {
|
|
|
79
89
|
commonName: getPaaCommonName(),
|
|
80
90
|
vendorId: vendorId,
|
|
81
91
|
},
|
|
82
|
-
ellipticCurvePublicKey: this
|
|
92
|
+
ellipticCurvePublicKey: this.#paaKeyPair.publicKey,
|
|
83
93
|
extensions: {
|
|
84
94
|
basicConstraints: {
|
|
85
95
|
isCa: true,
|
|
@@ -89,17 +99,17 @@ export class AttestationCertificateManager {
|
|
|
89
99
|
keyCertSign: true,
|
|
90
100
|
cRLSign: true,
|
|
91
101
|
},
|
|
92
|
-
subjectKeyIdentifier: this
|
|
93
|
-
authorityKeyIdentifier: this
|
|
102
|
+
subjectKeyIdentifier: this.#paaKeyIdentifier,
|
|
103
|
+
authorityKeyIdentifier: this.#paaKeyIdentifier,
|
|
94
104
|
},
|
|
95
105
|
};
|
|
96
|
-
return CertificateManager.productAttestationAuthorityCertToAsn1(unsignedCertificate, this
|
|
106
|
+
return CertificateManager.productAttestationAuthorityCertToAsn1(unsignedCertificate, this.#paaKeyPair);
|
|
97
107
|
}
|
|
98
108
|
|
|
99
109
|
private generatePAICert(vendorId: VendorId, productId?: number) {
|
|
100
110
|
const now = Time.get().now();
|
|
101
111
|
const unsignedCertificate = {
|
|
102
|
-
serialNumber: Bytes.fromHex(toHex(this
|
|
112
|
+
serialNumber: Bytes.fromHex(toHex(this.#paiCertId)),
|
|
103
113
|
signatureAlgorithm: 1 /* EcdsaWithSHA256 */,
|
|
104
114
|
publicKeyAlgorithm: 1 /* EC */,
|
|
105
115
|
ellipticCurveIdentifier: 1 /* P256v1 */,
|
|
@@ -113,7 +123,7 @@ export class AttestationCertificateManager {
|
|
|
113
123
|
vendorId: vendorId,
|
|
114
124
|
productId: productId,
|
|
115
125
|
},
|
|
116
|
-
ellipticCurvePublicKey: this
|
|
126
|
+
ellipticCurvePublicKey: this.#paiKeyPair.publicKey,
|
|
117
127
|
extensions: {
|
|
118
128
|
basicConstraints: {
|
|
119
129
|
isCa: true,
|
|
@@ -123,16 +133,16 @@ export class AttestationCertificateManager {
|
|
|
123
133
|
keyCertSign: true,
|
|
124
134
|
cRLSign: true,
|
|
125
135
|
},
|
|
126
|
-
subjectKeyIdentifier: this
|
|
127
|
-
authorityKeyIdentifier: this
|
|
136
|
+
subjectKeyIdentifier: this.#paiKeyIdentifier,
|
|
137
|
+
authorityKeyIdentifier: this.#paaKeyIdentifier,
|
|
128
138
|
},
|
|
129
139
|
};
|
|
130
|
-
return CertificateManager.productAttestationIntermediateCertToAsn1(unsignedCertificate, this
|
|
140
|
+
return CertificateManager.productAttestationIntermediateCertToAsn1(unsignedCertificate, this.#paaKeyPair);
|
|
131
141
|
}
|
|
132
142
|
|
|
133
|
-
generateDaCert(publicKey: Uint8Array, vendorId: VendorId, productId: number) {
|
|
143
|
+
async generateDaCert(publicKey: Uint8Array, vendorId: VendorId, productId: number) {
|
|
134
144
|
const now = Time.get().now();
|
|
135
|
-
const certId = this
|
|
145
|
+
const certId = this.#nextCertificateId++;
|
|
136
146
|
const unsignedCertificate = {
|
|
137
147
|
serialNumber: Bytes.fromHex(toHex(certId)),
|
|
138
148
|
signatureAlgorithm: 1 /* EcdsaWithSHA256 */,
|
|
@@ -157,10 +167,10 @@ export class AttestationCertificateManager {
|
|
|
157
167
|
keyUsage: {
|
|
158
168
|
digitalSignature: true,
|
|
159
169
|
},
|
|
160
|
-
subjectKeyIdentifier: Crypto.hash(publicKey).slice(0, 20),
|
|
161
|
-
authorityKeyIdentifier: this
|
|
170
|
+
subjectKeyIdentifier: (await Crypto.hash(publicKey)).slice(0, 20),
|
|
171
|
+
authorityKeyIdentifier: this.#paiKeyIdentifier,
|
|
162
172
|
},
|
|
163
173
|
};
|
|
164
|
-
return CertificateManager.deviceAttestationCertToAsn1(unsignedCertificate, this
|
|
174
|
+
return CertificateManager.deviceAttestationCertToAsn1(unsignedCertificate, this.#paiKeyPair);
|
|
165
175
|
}
|
|
166
176
|
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
Crypto,
|
|
12
12
|
Environment,
|
|
13
13
|
Environmental,
|
|
14
|
+
InternalError,
|
|
14
15
|
Logger,
|
|
15
16
|
PrivateKey,
|
|
16
17
|
StorageContext,
|
|
@@ -37,11 +38,11 @@ const logger = Logger.get("CertificateAuthority");
|
|
|
37
38
|
* TODO: Add support for (optional) ICACs
|
|
38
39
|
*/
|
|
39
40
|
export class CertificateAuthority {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
#rootCertId = BigInt(0);
|
|
42
|
+
#rootKeyPair?: PrivateKey;
|
|
43
|
+
#rootKeyIdentifier?: Uint8Array<ArrayBufferLike>;
|
|
44
|
+
#rootCertBytes?: Uint8Array<ArrayBufferLike>;
|
|
45
|
+
#nextCertificateId = BigInt(1);
|
|
45
46
|
#construction: Construction<CertificateAuthority>;
|
|
46
47
|
|
|
47
48
|
get construction() {
|
|
@@ -57,6 +58,10 @@ export class CertificateAuthority {
|
|
|
57
58
|
// Use provided CA config or read from storage, otherwise initialize and store
|
|
58
59
|
const certValues = options instanceof StorageContext ? await options.values() : options;
|
|
59
60
|
|
|
61
|
+
this.#rootKeyPair = await Crypto.createKeyPair();
|
|
62
|
+
this.#rootKeyIdentifier = (await Crypto.hash(this.#rootKeyPair.publicKey)).slice(0, 20);
|
|
63
|
+
this.#rootCertBytes = await this.#generateRootCert();
|
|
64
|
+
|
|
60
65
|
if (
|
|
61
66
|
(typeof certValues.rootCertId === "number" || typeof certValues.rootCertId === "bigint") &&
|
|
62
67
|
(ArrayBuffer.isView(certValues.rootKeyPair) || typeof certValues.rootKeyPair === "object") &&
|
|
@@ -64,24 +69,24 @@ export class CertificateAuthority {
|
|
|
64
69
|
ArrayBuffer.isView(certValues.rootCertBytes) &&
|
|
65
70
|
(typeof certValues.nextCertificateId === "number" || typeof certValues.nextCertificateId === "bigint")
|
|
66
71
|
) {
|
|
67
|
-
this
|
|
68
|
-
this
|
|
69
|
-
this
|
|
70
|
-
this
|
|
71
|
-
this
|
|
72
|
-
logger.info(`Loaded stored credentials with ID ${this
|
|
72
|
+
this.#rootCertId = BigInt(certValues.rootCertId);
|
|
73
|
+
this.#rootKeyPair = PrivateKey(certValues.rootKeyPair as BinaryKeyPair);
|
|
74
|
+
this.#rootKeyIdentifier = certValues.rootKeyIdentifier;
|
|
75
|
+
this.#rootCertBytes = certValues.rootCertBytes;
|
|
76
|
+
this.#nextCertificateId = BigInt(certValues.nextCertificateId);
|
|
77
|
+
logger.info(`Loaded stored credentials with ID ${this.#rootCertId}`);
|
|
73
78
|
return;
|
|
74
79
|
}
|
|
75
80
|
|
|
76
|
-
logger.info(`Created new credentials with ID ${this
|
|
81
|
+
logger.info(`Created new credentials with ID ${this.#rootCertId}`);
|
|
77
82
|
|
|
78
83
|
if (options instanceof StorageContext) {
|
|
79
84
|
await options.set({
|
|
80
|
-
rootCertId: this
|
|
81
|
-
rootKeyPair: this
|
|
82
|
-
rootKeyIdentifier: this
|
|
83
|
-
rootCertBytes: this
|
|
84
|
-
nextCertificateId: this
|
|
85
|
+
rootCertId: this.#rootCertId,
|
|
86
|
+
rootKeyPair: this.#rootKeyPair.keyPair,
|
|
87
|
+
rootKeyIdentifier: this.#rootKeyIdentifier,
|
|
88
|
+
rootCertBytes: this.#rootCertBytes,
|
|
89
|
+
nextCertificateId: this.#nextCertificateId,
|
|
85
90
|
});
|
|
86
91
|
}
|
|
87
92
|
});
|
|
@@ -95,59 +100,62 @@ export class CertificateAuthority {
|
|
|
95
100
|
}
|
|
96
101
|
|
|
97
102
|
get rootCert() {
|
|
98
|
-
return this.rootCertBytes;
|
|
103
|
+
return this.#construction.assert("root cert", this.#rootCertBytes);
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
get config(): CertificateAuthority.Configuration {
|
|
102
107
|
return {
|
|
103
|
-
rootCertId: this
|
|
104
|
-
rootKeyPair: this.rootKeyPair.keyPair,
|
|
105
|
-
rootKeyIdentifier: this.rootKeyIdentifier,
|
|
106
|
-
rootCertBytes: this.rootCertBytes,
|
|
107
|
-
nextCertificateId: this
|
|
108
|
+
rootCertId: this.#rootCertId,
|
|
109
|
+
rootKeyPair: this.construction.assert("root key pair", this.#rootKeyPair).keyPair,
|
|
110
|
+
rootKeyIdentifier: this.construction.assert("root key identifier", this.#rootKeyIdentifier),
|
|
111
|
+
rootCertBytes: this.construction.assert("root cert bytes", this.#rootCertBytes),
|
|
112
|
+
nextCertificateId: this.#nextCertificateId,
|
|
108
113
|
};
|
|
109
114
|
}
|
|
110
115
|
|
|
111
|
-
#generateRootCert() {
|
|
116
|
+
async #generateRootCert() {
|
|
112
117
|
const now = Time.get().now();
|
|
113
118
|
const unsignedCertificate: Unsigned<RootCertificate> = {
|
|
114
|
-
serialNumber: Bytes.fromHex(toHex(this
|
|
119
|
+
serialNumber: Bytes.fromHex(toHex(this.#rootCertId)),
|
|
115
120
|
signatureAlgorithm: 1 /* EcdsaWithSHA256 */,
|
|
116
121
|
publicKeyAlgorithm: 1 /* EC */,
|
|
117
122
|
ellipticCurveIdentifier: 1 /* P256v1 */,
|
|
118
|
-
issuer: { rcacId: this
|
|
123
|
+
issuer: { rcacId: this.#rootCertId },
|
|
119
124
|
notBefore: jsToMatterDate(now, -1),
|
|
120
125
|
notAfter: jsToMatterDate(now, 10),
|
|
121
|
-
subject: { rcacId: this
|
|
122
|
-
ellipticCurvePublicKey: this.
|
|
126
|
+
subject: { rcacId: this.#rootCertId },
|
|
127
|
+
ellipticCurvePublicKey: this.#initializedRootKeyPair.publicKey,
|
|
123
128
|
extensions: {
|
|
124
129
|
basicConstraints: { isCa: true },
|
|
125
130
|
keyUsage: {
|
|
126
131
|
keyCertSign: true,
|
|
127
132
|
cRLSign: true,
|
|
128
133
|
},
|
|
129
|
-
subjectKeyIdentifier: this
|
|
130
|
-
authorityKeyIdentifier: this
|
|
134
|
+
subjectKeyIdentifier: this.#initializedRootKeyIdentifier,
|
|
135
|
+
authorityKeyIdentifier: this.#initializedRootKeyIdentifier,
|
|
131
136
|
},
|
|
132
137
|
};
|
|
133
|
-
const signature = Crypto.sign(
|
|
138
|
+
const signature = await Crypto.sign(
|
|
139
|
+
this.#initializedRootKeyPair,
|
|
140
|
+
CertificateManager.rootCertToAsn1(unsignedCertificate),
|
|
141
|
+
);
|
|
134
142
|
return TlvRootCertificate.encode({ ...unsignedCertificate, signature });
|
|
135
143
|
}
|
|
136
144
|
|
|
137
|
-
generateNoc(
|
|
145
|
+
async generateNoc(
|
|
138
146
|
publicKey: Uint8Array,
|
|
139
147
|
fabricId: FabricId,
|
|
140
148
|
nodeId: NodeId,
|
|
141
149
|
caseAuthenticatedTags?: CaseAuthenticatedTag[],
|
|
142
150
|
) {
|
|
143
151
|
const now = Time.get().now();
|
|
144
|
-
const certId = this
|
|
152
|
+
const certId = this.#nextCertificateId++;
|
|
145
153
|
const unsignedCertificate: Unsigned<OperationalCertificate> = {
|
|
146
154
|
serialNumber: Bytes.fromHex(toHex(certId)),
|
|
147
155
|
signatureAlgorithm: 1 /* EcdsaWithSHA256 */,
|
|
148
156
|
publicKeyAlgorithm: 1 /* EC */,
|
|
149
157
|
ellipticCurveIdentifier: 1 /* P256v1 */,
|
|
150
|
-
issuer: { rcacId: this
|
|
158
|
+
issuer: { rcacId: this.#rootCertId },
|
|
151
159
|
notBefore: jsToMatterDate(now, -1),
|
|
152
160
|
notAfter: jsToMatterDate(now, 10),
|
|
153
161
|
subject: { fabricId, nodeId, caseAuthenticatedTags },
|
|
@@ -158,18 +166,32 @@ export class CertificateAuthority {
|
|
|
158
166
|
digitalSignature: true,
|
|
159
167
|
},
|
|
160
168
|
extendedKeyUsage: [2, 1],
|
|
161
|
-
subjectKeyIdentifier: Crypto.hash(publicKey).slice(0, 20),
|
|
162
|
-
authorityKeyIdentifier: this
|
|
169
|
+
subjectKeyIdentifier: (await Crypto.hash(publicKey)).slice(0, 20),
|
|
170
|
+
authorityKeyIdentifier: this.#initializedRootKeyIdentifier,
|
|
163
171
|
},
|
|
164
172
|
};
|
|
165
173
|
|
|
166
|
-
const signature = Crypto.sign(
|
|
167
|
-
this
|
|
174
|
+
const signature = await Crypto.sign(
|
|
175
|
+
this.#initializedRootKeyPair,
|
|
168
176
|
CertificateManager.nodeOperationalCertToAsn1(unsignedCertificate),
|
|
169
177
|
);
|
|
170
178
|
|
|
171
179
|
return TlvOperationalCertificate.encode({ ...unsignedCertificate, signature });
|
|
172
180
|
}
|
|
181
|
+
|
|
182
|
+
get #initializedRootKeyPair() {
|
|
183
|
+
if (this.#rootKeyPair === undefined) {
|
|
184
|
+
throw new InternalError("CA private key is not installed");
|
|
185
|
+
}
|
|
186
|
+
return this.#rootKeyPair;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
get #initializedRootKeyIdentifier() {
|
|
190
|
+
if (this.#rootKeyIdentifier === undefined) {
|
|
191
|
+
throw new InternalError("CA key identifier is not installed");
|
|
192
|
+
}
|
|
193
|
+
return this.#rootKeyIdentifier;
|
|
194
|
+
}
|
|
173
195
|
}
|
|
174
196
|
|
|
175
197
|
export namespace CertificateAuthority {
|
|
@@ -664,18 +664,18 @@ export namespace CertificateManager {
|
|
|
664
664
|
return genericCertToAsn1(cert);
|
|
665
665
|
}
|
|
666
666
|
|
|
667
|
-
export function deviceAttestationCertToAsn1(cert: Unsigned<DeviceAttestationCertificate>, key: Key) {
|
|
667
|
+
export async function deviceAttestationCertToAsn1(cert: Unsigned<DeviceAttestationCertificate>, key: Key) {
|
|
668
668
|
const certificate = genericBuildAsn1Structure(cert);
|
|
669
669
|
const certBytes = DerCodec.encode({
|
|
670
670
|
certificate,
|
|
671
671
|
signAlgorithm: X962.EcdsaWithSHA256,
|
|
672
|
-
signature: BitByteArray(Crypto.sign(key, DerCodec.encode(certificate), "der")),
|
|
672
|
+
signature: BitByteArray(await Crypto.sign(key, DerCodec.encode(certificate), "der")),
|
|
673
673
|
});
|
|
674
674
|
assertCertificateDerSize(certBytes);
|
|
675
675
|
return certBytes;
|
|
676
676
|
}
|
|
677
677
|
|
|
678
|
-
export function productAttestationIntermediateCertToAsn1(
|
|
678
|
+
export async function productAttestationIntermediateCertToAsn1(
|
|
679
679
|
cert: Unsigned<ProductAttestationIntermediateCertificate>,
|
|
680
680
|
key: Key,
|
|
681
681
|
) {
|
|
@@ -683,13 +683,13 @@ export namespace CertificateManager {
|
|
|
683
683
|
const certBytes = DerCodec.encode({
|
|
684
684
|
certificate,
|
|
685
685
|
signAlgorithm: X962.EcdsaWithSHA256,
|
|
686
|
-
signature: BitByteArray(Crypto.sign(key, DerCodec.encode(certificate), "der")),
|
|
686
|
+
signature: BitByteArray(await Crypto.sign(key, DerCodec.encode(certificate), "der")),
|
|
687
687
|
});
|
|
688
688
|
assertCertificateDerSize(certBytes);
|
|
689
689
|
return certBytes;
|
|
690
690
|
}
|
|
691
691
|
|
|
692
|
-
export function productAttestationAuthorityCertToAsn1(
|
|
692
|
+
export async function productAttestationAuthorityCertToAsn1(
|
|
693
693
|
cert: Unsigned<ProductAttestationAuthorityCertificate>,
|
|
694
694
|
key: Key,
|
|
695
695
|
) {
|
|
@@ -697,7 +697,7 @@ export namespace CertificateManager {
|
|
|
697
697
|
const certBytes = DerCodec.encode({
|
|
698
698
|
certificate,
|
|
699
699
|
signAlgorithm: X962.EcdsaWithSHA256,
|
|
700
|
-
signature: BitByteArray(Crypto.sign(key, DerCodec.encode(certificate), "der")),
|
|
700
|
+
signature: BitByteArray(await Crypto.sign(key, DerCodec.encode(certificate), "der")),
|
|
701
701
|
});
|
|
702
702
|
assertCertificateDerSize(certBytes);
|
|
703
703
|
return certBytes;
|
|
@@ -777,7 +777,7 @@ export namespace CertificateManager {
|
|
|
777
777
|
* Verify requirements a Matter Root certificate must fulfill.
|
|
778
778
|
* Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
|
|
779
779
|
*/
|
|
780
|
-
export function verifyRootCertificate(rootCert: RootCertificate) {
|
|
780
|
+
export async function verifyRootCertificate(rootCert: RootCertificate) {
|
|
781
781
|
CertificateManager.validateGeneralCertificateFields(rootCert);
|
|
782
782
|
|
|
783
783
|
// The subject DN SHALL NOT encode any matter-node-id attribute.
|
|
@@ -861,14 +861,14 @@ export namespace CertificateManager {
|
|
|
861
861
|
);
|
|
862
862
|
}
|
|
863
863
|
|
|
864
|
-
Crypto.verify(PublicKey(rootCert.ellipticCurvePublicKey), rootCertToAsn1(rootCert), rootCert.signature);
|
|
864
|
+
await Crypto.verify(PublicKey(rootCert.ellipticCurvePublicKey), rootCertToAsn1(rootCert), rootCert.signature);
|
|
865
865
|
}
|
|
866
866
|
|
|
867
867
|
/**
|
|
868
868
|
* Verify requirements a Matter Node Operational certificate must fulfill.
|
|
869
869
|
* Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
|
|
870
870
|
*/
|
|
871
|
-
export function verifyNodeOperationalCertificate(
|
|
871
|
+
export async function verifyNodeOperationalCertificate(
|
|
872
872
|
nocCert: OperationalCertificate,
|
|
873
873
|
rootCert: RootCertificate,
|
|
874
874
|
icaCert?: IntermediateCertificate,
|
|
@@ -985,7 +985,7 @@ export namespace CertificateManager {
|
|
|
985
985
|
);
|
|
986
986
|
}
|
|
987
987
|
|
|
988
|
-
Crypto.verify(
|
|
988
|
+
await Crypto.verify(
|
|
989
989
|
PublicKey((icaCert ?? rootCert).ellipticCurvePublicKey),
|
|
990
990
|
nodeOperationalCertToAsn1(nocCert),
|
|
991
991
|
nocCert.signature,
|
|
@@ -996,7 +996,7 @@ export namespace CertificateManager {
|
|
|
996
996
|
* Verify requirements a Matter Intermediate CA certificate must fulfill.
|
|
997
997
|
* Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
|
|
998
998
|
*/
|
|
999
|
-
export function verifyIntermediateCaCertificate(rootCert: RootCertificate, icaCert: IntermediateCertificate) {
|
|
999
|
+
export async function verifyIntermediateCaCertificate(rootCert: RootCertificate, icaCert: IntermediateCertificate) {
|
|
1000
1000
|
CertificateManager.validateGeneralCertificateFields(icaCert);
|
|
1001
1001
|
|
|
1002
1002
|
// The subject DN SHALL NOT encode any matter-node-id attribute.
|
|
@@ -1103,10 +1103,14 @@ export namespace CertificateManager {
|
|
|
1103
1103
|
);
|
|
1104
1104
|
}
|
|
1105
1105
|
|
|
1106
|
-
Crypto.verify(
|
|
1106
|
+
await Crypto.verify(
|
|
1107
|
+
PublicKey(rootCert.ellipticCurvePublicKey),
|
|
1108
|
+
intermediateCaCertToAsn1(icaCert),
|
|
1109
|
+
icaCert.signature,
|
|
1110
|
+
);
|
|
1107
1111
|
}
|
|
1108
1112
|
|
|
1109
|
-
export function createCertificateSigningRequest(key: Key) {
|
|
1113
|
+
export async function createCertificateSigningRequest(key: Key) {
|
|
1110
1114
|
const request = {
|
|
1111
1115
|
version: 0,
|
|
1112
1116
|
subject: { organization: X520.OrganisationName("CSR") },
|
|
@@ -1117,11 +1121,11 @@ export namespace CertificateManager {
|
|
|
1117
1121
|
return DerCodec.encode({
|
|
1118
1122
|
request,
|
|
1119
1123
|
signAlgorithm: X962.EcdsaWithSHA256,
|
|
1120
|
-
signature: BitByteArray(Crypto.sign(key, DerCodec.encode(request), "der")),
|
|
1124
|
+
signature: BitByteArray(await Crypto.sign(key, DerCodec.encode(request), "der")),
|
|
1121
1125
|
});
|
|
1122
1126
|
}
|
|
1123
1127
|
|
|
1124
|
-
export function getPublicKeyFromCsr(csr: Uint8Array) {
|
|
1128
|
+
export async function getPublicKeyFromCsr(csr: Uint8Array) {
|
|
1125
1129
|
const { [DerKey.Elements]: rootElements } = DerCodec.decode(csr);
|
|
1126
1130
|
if (rootElements?.length !== 3) throw new CertificateError("Invalid CSR data");
|
|
1127
1131
|
const [requestNode, signAlgorithmNode, signatureNode] = rootElements;
|
|
@@ -1149,7 +1153,7 @@ export namespace CertificateManager {
|
|
|
1149
1153
|
)
|
|
1150
1154
|
)
|
|
1151
1155
|
throw new CertificateError("Unsupported signature type");
|
|
1152
|
-
Crypto.verify(PublicKey(publicKey), DerCodec.encode(requestNode), signatureNode[DerKey.Bytes], "der");
|
|
1156
|
+
await Crypto.verify(PublicKey(publicKey), DerCodec.encode(requestNode), signatureNode[DerKey.Bytes], "der");
|
|
1153
1157
|
|
|
1154
1158
|
return publicKey;
|
|
1155
1159
|
}
|
|
@@ -37,42 +37,38 @@ export class DeviceCertification {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
constructor(config?: DeviceCertification.Definition, product?: ProductDescription) {
|
|
40
|
-
|
|
40
|
+
let configProvider;
|
|
41
41
|
if (typeof config === "function") {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
config = {
|
|
62
|
-
privateKey: PrivateKey(dacKeyPair.privateKey),
|
|
63
|
-
certificate: dac,
|
|
64
|
-
intermediateCertificate: paa.getPAICert(),
|
|
65
|
-
declaration: CertificationDeclarationManager.generate(product.vendorId, product.productId),
|
|
42
|
+
configProvider = config;
|
|
43
|
+
} else if (config) {
|
|
44
|
+
configProvider = () => config;
|
|
45
|
+
} else {
|
|
46
|
+
configProvider = async () => {
|
|
47
|
+
if (product === undefined) {
|
|
48
|
+
throw new ImplementationError(`Cannot generate device certification without product information`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const paa = await AttestationCertificateManager.create(product.vendorId);
|
|
52
|
+
const { keyPair: dacKeyPair, dac } = await paa.getDACert(product.productId);
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
privateKey: PrivateKey(dacKeyPair.privateKey),
|
|
56
|
+
certificate: dac,
|
|
57
|
+
intermediateCertificate: await paa.getPAICert(),
|
|
58
|
+
declaration: CertificationDeclarationManager.generate(product.vendorId, product.productId),
|
|
59
|
+
};
|
|
66
60
|
};
|
|
67
61
|
}
|
|
68
|
-
this.#initializeFromConfig(config);
|
|
69
|
-
}
|
|
70
62
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
63
|
+
this.#construction = Construction(this, async () => {
|
|
64
|
+
const config = await configProvider();
|
|
65
|
+
|
|
66
|
+
this.#privateKey =
|
|
67
|
+
config.privateKey instanceof Uint8Array ? PrivateKey(config.privateKey) : config.privateKey;
|
|
68
|
+
this.#certificate = config.certificate;
|
|
69
|
+
this.#intermediateCertificate = config.intermediateCertificate;
|
|
70
|
+
this.#declaration = config.declaration;
|
|
71
|
+
});
|
|
76
72
|
}
|
|
77
73
|
|
|
78
74
|
sign(session: SecureSession, data: Uint8Array) {
|
|
@@ -4,7 +4,14 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
AsyncObservable,
|
|
9
|
+
Construction,
|
|
10
|
+
Logger,
|
|
11
|
+
MatterFlowError,
|
|
12
|
+
UnexpectedDataError,
|
|
13
|
+
UninitializedDependencyError,
|
|
14
|
+
} from "#general";
|
|
8
15
|
import { CaseAuthenticatedTag, NodeId, ValidationError, VendorId } from "#types";
|
|
9
16
|
import { Fabric, FabricBuilder } from "../fabric/Fabric.js";
|
|
10
17
|
import { FabricManager } from "../fabric/FabricManager.js";
|
|
@@ -32,7 +39,7 @@ export abstract class FailsafeContext {
|
|
|
32
39
|
#associatedFabric?: Fabric;
|
|
33
40
|
#csrSessionId?: number;
|
|
34
41
|
#forUpdateNoc?: boolean;
|
|
35
|
-
#fabricBuilder
|
|
42
|
+
#fabricBuilder?: FabricBuilder;
|
|
36
43
|
#rootCertSet = false;
|
|
37
44
|
|
|
38
45
|
#commissioned = AsyncObservable<[], void>();
|
|
@@ -45,6 +52,7 @@ export abstract class FailsafeContext {
|
|
|
45
52
|
this.#associatedFabric = options.associatedFabric;
|
|
46
53
|
|
|
47
54
|
this.#construction = Construction(this, async () => {
|
|
55
|
+
this.#fabricBuilder = await FabricBuilder.create();
|
|
48
56
|
// Ensure derived class construction is complete
|
|
49
57
|
await Promise.resolve();
|
|
50
58
|
|
|
@@ -71,7 +79,7 @@ export abstract class FailsafeContext {
|
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
get fabricIndex() {
|
|
74
|
-
return this.#
|
|
82
|
+
return this.#builder.fabricIndex;
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
get construction() {
|
|
@@ -99,11 +107,11 @@ export abstract class FailsafeContext {
|
|
|
99
107
|
}
|
|
100
108
|
|
|
101
109
|
get hasRootCert() {
|
|
102
|
-
return this.#
|
|
110
|
+
return this.#builder.rootCert !== undefined;
|
|
103
111
|
}
|
|
104
112
|
|
|
105
113
|
get rootCert() {
|
|
106
|
-
return this.#
|
|
114
|
+
return this.#builder.rootCert;
|
|
107
115
|
}
|
|
108
116
|
|
|
109
117
|
async completeCommission() {
|
|
@@ -157,11 +165,11 @@ export abstract class FailsafeContext {
|
|
|
157
165
|
* validity checks.
|
|
158
166
|
*/
|
|
159
167
|
createCertificateSigningRequest(isForUpdateNoc: boolean, sessionId: number) {
|
|
160
|
-
if (this.#fabrics.findByKeypair(this.#
|
|
168
|
+
if (this.#fabrics.findByKeypair(this.#builder.keyPair)) {
|
|
161
169
|
throw new MatterFlowError("Key pair already exists."); // becomes Failure as StatusResponse
|
|
162
170
|
}
|
|
163
171
|
|
|
164
|
-
const result = this.#
|
|
172
|
+
const result = this.#builder.createCertificateSigningRequest();
|
|
165
173
|
this.#csrSessionId = sessionId;
|
|
166
174
|
this.#forUpdateNoc = isForUpdateNoc;
|
|
167
175
|
return result;
|
|
@@ -186,8 +194,8 @@ export abstract class FailsafeContext {
|
|
|
186
194
|
}
|
|
187
195
|
|
|
188
196
|
/** Handles adding a trusted root certificate from Operational Credentials cluster. */
|
|
189
|
-
setRootCert(rootCert: Uint8Array) {
|
|
190
|
-
this.#
|
|
197
|
+
async setRootCert(rootCert: Uint8Array) {
|
|
198
|
+
await this.#builder.setRootCert(rootCert);
|
|
191
199
|
this.#rootCertSet = true;
|
|
192
200
|
}
|
|
193
201
|
|
|
@@ -199,9 +207,9 @@ export abstract class FailsafeContext {
|
|
|
199
207
|
if (this.associatedFabric === undefined) {
|
|
200
208
|
throw new MatterFlowError("No fabric associated with failsafe context, but we prepare an Fabric update.");
|
|
201
209
|
}
|
|
202
|
-
this.#
|
|
203
|
-
this.#
|
|
204
|
-
return await this.#
|
|
210
|
+
this.#builder.initializeFromFabricForUpdate(this.associatedFabric);
|
|
211
|
+
await this.#builder.setOperationalCert(nocValue, icacValue);
|
|
212
|
+
return await this.#builder.build(this.associatedFabric.fabricIndex);
|
|
205
213
|
}
|
|
206
214
|
|
|
207
215
|
/** Build a new Fabric object for a new fabric for the "AddNoc" case of the Operational Credentials cluster. */
|
|
@@ -212,7 +220,7 @@ export abstract class FailsafeContext {
|
|
|
212
220
|
ipkValue: Uint8Array;
|
|
213
221
|
caseAdminSubject: NodeId;
|
|
214
222
|
}) {
|
|
215
|
-
const builder = this.#
|
|
223
|
+
const builder = this.#builder;
|
|
216
224
|
|
|
217
225
|
const { nocValue, icacValue, adminVendorId, ipkValue, caseAdminSubject } = nocData;
|
|
218
226
|
|
|
@@ -232,7 +240,7 @@ export abstract class FailsafeContext {
|
|
|
232
240
|
}
|
|
233
241
|
}
|
|
234
242
|
|
|
235
|
-
builder.setOperationalCert(nocValue, icacValue);
|
|
243
|
+
await builder.setOperationalCert(nocValue, icacValue);
|
|
236
244
|
const fabricAlreadyExisting = this.#fabrics.find(fabric => builder.matchesToFabric(fabric));
|
|
237
245
|
|
|
238
246
|
if (fabricAlreadyExisting) {
|
|
@@ -320,6 +328,13 @@ export abstract class FailsafeContext {
|
|
|
320
328
|
abstract revokeFabric(fabric: Fabric): Promise<void>;
|
|
321
329
|
|
|
322
330
|
abstract restoreBreadcrumb(): Promise<void>;
|
|
331
|
+
|
|
332
|
+
get #builder() {
|
|
333
|
+
if (this.#fabricBuilder === undefined) {
|
|
334
|
+
throw new UninitializedDependencyError("FailsafeContext", "Fabric builder has not been initialized");
|
|
335
|
+
}
|
|
336
|
+
return this.#fabricBuilder;
|
|
337
|
+
}
|
|
323
338
|
}
|
|
324
339
|
|
|
325
340
|
export namespace FailsafeContext {
|