Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021-2022 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #include <algorithm>
20 : #include <controller/ExampleOperationalCredentialsIssuer.h>
21 : #include <credentials/CHIPCert.h>
22 : #include <lib/core/TLV.h>
23 : #include <lib/support/CHIPMem.h>
24 : #include <lib/support/CodeUtils.h>
25 : #include <lib/support/PersistentStorageMacros.h>
26 : #include <lib/support/SafeInt.h>
27 : #include <lib/support/ScopedBuffer.h>
28 : #include <lib/support/TestGroupData.h>
29 :
30 : namespace chip {
31 : namespace Controller {
32 :
33 : constexpr char kOperationalCredentialsIssuerKeypairStorage[] = "ExampleOpCredsCAKey";
34 : constexpr char kOperationalCredentialsIntermediateIssuerKeypairStorage[] = "ExampleOpCredsICAKey";
35 : constexpr char kOperationalCredentialsRootCertificateStorage[] = "ExampleCARootCert";
36 : constexpr char kOperationalCredentialsIntermediateCertificateStorage[] = "ExampleCAIntermediateCert";
37 :
38 : using namespace Credentials;
39 : using namespace Crypto;
40 : using namespace TLV;
41 :
42 : namespace {
43 :
44 : enum CertType : uint8_t
45 : {
46 : kRcac = 0,
47 : kIcac = 1,
48 : kNoc = 2
49 : };
50 :
51 0 : CHIP_ERROR IssueX509Cert(uint32_t now, uint32_t validity, ChipDN issuerDn, ChipDN desiredDn, CertType certType, bool maximizeSize,
52 : const Crypto::P256PublicKey & subjectPublicKey, Crypto::P256Keypair & issuerKeypair,
53 : MutableByteSpan & outX509Cert)
54 : {
55 0 : constexpr size_t kDERCertFutureExtEncodingOverhead = 12;
56 0 : constexpr size_t kTLVCertFutureExtEncodingOverhead = kDERCertFutureExtEncodingOverhead + 5;
57 0 : constexpr size_t kMaxCertPaddingLength = 200;
58 0 : constexpr size_t kTLVDesiredSize = kMaxCHIPCertLength;
59 0 : constexpr uint8_t sOID_Extension_SubjectAltName[] = { 0x55, 0x1d, 0x11 };
60 :
61 0 : Platform::ScopedMemoryBuffer<uint8_t> derBuf;
62 0 : ReturnErrorCodeIf(!derBuf.Alloc(kMaxDERCertLength), CHIP_ERROR_NO_MEMORY);
63 0 : MutableByteSpan derSpan{ derBuf.Get(), kMaxDERCertLength };
64 :
65 0 : int64_t serialNumber = 1;
66 :
67 0 : switch (certType)
68 : {
69 0 : case CertType::kRcac: {
70 0 : X509CertRequestParams rcacRequest = { serialNumber, now, now + validity, desiredDn, desiredDn };
71 0 : ReturnErrorOnFailure(NewRootX509Cert(rcacRequest, issuerKeypair, derSpan));
72 0 : break;
73 0 : }
74 0 : case CertType::kIcac: {
75 0 : X509CertRequestParams icacRequest = { serialNumber, now, now + validity, desiredDn, issuerDn };
76 0 : ReturnErrorOnFailure(NewICAX509Cert(icacRequest, subjectPublicKey, issuerKeypair, derSpan));
77 0 : break;
78 0 : }
79 0 : case CertType::kNoc: {
80 0 : X509CertRequestParams nocRequest = { serialNumber, now, now + validity, desiredDn, issuerDn };
81 0 : ReturnErrorOnFailure(NewNodeOperationalX509Cert(nocRequest, subjectPublicKey, issuerKeypair, derSpan));
82 0 : break;
83 0 : }
84 0 : default:
85 0 : return CHIP_ERROR_INVALID_ARGUMENT;
86 : }
87 :
88 0 : if (maximizeSize)
89 : {
90 0 : Platform::ScopedMemoryBuffer<uint8_t> paddedTlvBuf;
91 0 : ReturnErrorCodeIf(!paddedTlvBuf.Alloc(kMaxCHIPCertLength + kMaxCertPaddingLength), CHIP_ERROR_NO_MEMORY);
92 0 : MutableByteSpan paddedTlvSpan{ paddedTlvBuf.Get(), kMaxCHIPCertLength + kMaxCertPaddingLength };
93 0 : ReturnErrorOnFailure(ConvertX509CertToChipCert(derSpan, paddedTlvSpan));
94 :
95 0 : Platform::ScopedMemoryBuffer<uint8_t> paddedDerBuf;
96 0 : ReturnErrorCodeIf(!paddedDerBuf.Alloc(kMaxDERCertLength + kMaxCertPaddingLength), CHIP_ERROR_NO_MEMORY);
97 0 : MutableByteSpan paddedDerSpan{ paddedDerBuf.Get(), kMaxDERCertLength + kMaxCertPaddingLength };
98 :
99 0 : Platform::ScopedMemoryBuffer<char> fillerBuf;
100 0 : ReturnErrorCodeIf(!fillerBuf.Alloc(kMaxCertPaddingLength), CHIP_ERROR_NO_MEMORY);
101 0 : memset(fillerBuf.Get(), 'A', kMaxCertPaddingLength);
102 :
103 0 : int derPaddingLen = static_cast<int>(kMaxDERCertLength - kDERCertFutureExtEncodingOverhead - derSpan.size());
104 0 : int tlvPaddingLen = static_cast<int>(kTLVDesiredSize - kTLVCertFutureExtEncodingOverhead - paddedTlvSpan.size());
105 0 : size_t paddingLen = 0;
106 0 : if (derPaddingLen >= 1 && tlvPaddingLen >= 1)
107 : {
108 0 : paddingLen = std::min(static_cast<size_t>(std::min(derPaddingLen, tlvPaddingLen)), kMaxCertPaddingLength);
109 : }
110 :
111 0 : for (; paddingLen > 0; paddingLen--)
112 : {
113 0 : paddedDerSpan = MutableByteSpan{ paddedDerBuf.Get(), kMaxDERCertLength + kMaxCertPaddingLength };
114 0 : paddedTlvSpan = MutableByteSpan{ paddedTlvBuf.Get(), kMaxCHIPCertLength + kMaxCertPaddingLength };
115 :
116 0 : Optional<FutureExtension> futureExt;
117 : FutureExtension ext = { ByteSpan(sOID_Extension_SubjectAltName),
118 0 : ByteSpan(reinterpret_cast<uint8_t *>(fillerBuf.Get()), paddingLen) };
119 0 : futureExt.SetValue(ext);
120 :
121 0 : switch (certType)
122 : {
123 0 : case CertType::kRcac: {
124 0 : X509CertRequestParams rcacRequest = { serialNumber, now, now + validity, desiredDn, desiredDn, futureExt };
125 0 : ReturnErrorOnFailure(NewRootX509Cert(rcacRequest, issuerKeypair, paddedDerSpan));
126 0 : break;
127 0 : }
128 0 : case CertType::kIcac: {
129 0 : X509CertRequestParams icacRequest = { serialNumber, now, now + validity, desiredDn, issuerDn, futureExt };
130 0 : ReturnErrorOnFailure(NewICAX509Cert(icacRequest, subjectPublicKey, issuerKeypair, paddedDerSpan));
131 0 : break;
132 0 : }
133 0 : case CertType::kNoc: {
134 0 : X509CertRequestParams nocRequest = { serialNumber, now, now + validity, desiredDn, issuerDn, futureExt };
135 0 : ReturnErrorOnFailure(NewNodeOperationalX509Cert(nocRequest, subjectPublicKey, issuerKeypair, paddedDerSpan));
136 0 : break;
137 0 : }
138 0 : default:
139 0 : return CHIP_ERROR_INVALID_ARGUMENT;
140 : }
141 :
142 0 : ReturnErrorOnFailure(ConvertX509CertToChipCert(paddedDerSpan, paddedTlvSpan));
143 :
144 0 : if (paddedDerSpan.size() <= kMaxDERCertLength && paddedTlvSpan.size() <= kMaxCHIPCertLength)
145 : {
146 0 : ChipLogProgress(Controller, "Generated maximized certificate with %u DER bytes, %u TLV bytes",
147 : static_cast<unsigned>(paddedDerSpan.size()), static_cast<unsigned>(paddedTlvSpan.size()));
148 0 : return CopySpanToMutableSpan(paddedDerSpan, outX509Cert);
149 : }
150 0 : }
151 0 : }
152 :
153 0 : return CopySpanToMutableSpan(derSpan, outX509Cert);
154 0 : }
155 :
156 : } // namespace
157 :
158 0 : CHIP_ERROR ExampleOperationalCredentialsIssuer::Initialize(PersistentStorageDelegate & storage)
159 : {
160 : using namespace ASN1;
161 : ASN1UniversalTime effectiveTime;
162 : CHIP_ERROR err;
163 :
164 : // Initializing the default start validity to start of 2021. The default validity duration is 10 years.
165 0 : CHIP_ZERO_AT(effectiveTime);
166 0 : effectiveTime.Year = 2021;
167 0 : effectiveTime.Month = 1;
168 0 : effectiveTime.Day = 1;
169 0 : ReturnErrorOnFailure(ASN1ToChipEpochTime(effectiveTime, mNow));
170 :
171 0 : Crypto::P256SerializedKeypair serializedKey;
172 : {
173 : // Scope for keySize, because we use it as an in/out param.
174 0 : uint16_t keySize = static_cast<uint16_t>(serializedKey.Capacity());
175 :
176 0 : PERSISTENT_KEY_OP(mIndex, kOperationalCredentialsIssuerKeypairStorage, key,
177 : err = storage.SyncGetKeyValue(key, serializedKey.Bytes(), keySize));
178 0 : serializedKey.SetLength(keySize);
179 : }
180 :
181 0 : if (err != CHIP_NO_ERROR)
182 : {
183 0 : ChipLogProgress(Controller, "Couldn't get %s from storage: %s", kOperationalCredentialsIssuerKeypairStorage, ErrorStr(err));
184 : // Storage doesn't have an existing keypair. Let's create one and add it to the storage.
185 0 : ReturnErrorOnFailure(mIssuer.Initialize(Crypto::ECPKeyTarget::ECDSA));
186 0 : ReturnErrorOnFailure(mIssuer.Serialize(serializedKey));
187 :
188 0 : PERSISTENT_KEY_OP(mIndex, kOperationalCredentialsIssuerKeypairStorage, key,
189 : ReturnErrorOnFailure(
190 : storage.SyncSetKeyValue(key, serializedKey.Bytes(), static_cast<uint16_t>(serializedKey.Length()))));
191 : }
192 : else
193 : {
194 : // Use the keypair from the storage
195 0 : ReturnErrorOnFailure(mIssuer.Deserialize(serializedKey));
196 : }
197 :
198 : {
199 : // Scope for keySize, because we use it as an in/out param.
200 0 : uint16_t keySize = static_cast<uint16_t>(serializedKey.Capacity());
201 :
202 0 : PERSISTENT_KEY_OP(mIndex, kOperationalCredentialsIntermediateIssuerKeypairStorage, key,
203 : err = storage.SyncGetKeyValue(key, serializedKey.Bytes(), keySize));
204 0 : serializedKey.SetLength(keySize);
205 : }
206 :
207 0 : if (err != CHIP_NO_ERROR)
208 : {
209 0 : ChipLogProgress(Controller, "Couldn't get %s from storage: %s", kOperationalCredentialsIntermediateIssuerKeypairStorage,
210 : ErrorStr(err));
211 : // Storage doesn't have an existing keypair. Let's create one and add it to the storage.
212 0 : ReturnErrorOnFailure(mIntermediateIssuer.Initialize(Crypto::ECPKeyTarget::ECDSA));
213 0 : ReturnErrorOnFailure(mIntermediateIssuer.Serialize(serializedKey));
214 :
215 0 : PERSISTENT_KEY_OP(mIndex, kOperationalCredentialsIntermediateIssuerKeypairStorage, key,
216 : ReturnErrorOnFailure(
217 : storage.SyncSetKeyValue(key, serializedKey.Bytes(), static_cast<uint16_t>(serializedKey.Length()))));
218 : }
219 : else
220 : {
221 : // Use the keypair from the storage
222 0 : ReturnErrorOnFailure(mIntermediateIssuer.Deserialize(serializedKey));
223 : }
224 :
225 0 : mStorage = &storage;
226 0 : mInitialized = true;
227 0 : return CHIP_NO_ERROR;
228 0 : }
229 :
230 0 : CHIP_ERROR ExampleOperationalCredentialsIssuer::GenerateNOCChainAfterValidation(NodeId nodeId, FabricId fabricId,
231 : const CATValues & cats,
232 : const Crypto::P256PublicKey & pubkey,
233 : MutableByteSpan & rcac, MutableByteSpan & icac,
234 : MutableByteSpan & noc)
235 : {
236 0 : ChipDN rcac_dn;
237 0 : CHIP_ERROR err = CHIP_NO_ERROR;
238 0 : uint16_t rcacBufLen = static_cast<uint16_t>(std::min(rcac.size(), static_cast<size_t>(UINT16_MAX)));
239 0 : PERSISTENT_KEY_OP(mIndex, kOperationalCredentialsRootCertificateStorage, key,
240 : err = mStorage->SyncGetKeyValue(key, rcac.data(), rcacBufLen));
241 : // Always regenerate RCAC on maximally sized certs. The keys remain the same, so everything is fine.
242 0 : if (mUseMaximallySizedCerts)
243 : {
244 0 : err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
245 : }
246 :
247 0 : if (err == CHIP_NO_ERROR)
248 : {
249 : uint64_t rcacId;
250 : // Found root certificate in the storage.
251 0 : rcac.reduce_size(rcacBufLen);
252 0 : ReturnErrorOnFailure(ExtractSubjectDNFromX509Cert(rcac, rcac_dn));
253 0 : ReturnErrorOnFailure(rcac_dn.GetCertChipId(rcacId));
254 0 : VerifyOrReturnError(rcacId == mIssuerId, CHIP_ERROR_INTERNAL);
255 : }
256 : // If root certificate not found in the storage, generate new root certificate.
257 : else
258 : {
259 0 : ReturnErrorOnFailure(rcac_dn.AddAttribute_MatterRCACId(mIssuerId));
260 :
261 0 : ChipLogProgress(Controller, "Generating RCAC");
262 0 : ReturnErrorOnFailure(IssueX509Cert(mNow, mValidity, rcac_dn, rcac_dn, CertType::kRcac, mUseMaximallySizedCerts,
263 : mIssuer.Pubkey(), mIssuer, rcac));
264 0 : VerifyOrReturnError(CanCastTo<uint16_t>(rcac.size()), CHIP_ERROR_INTERNAL);
265 :
266 : // Re-extract DN based on final generated cert
267 0 : rcac_dn = ChipDN{};
268 0 : ReturnErrorOnFailure(ExtractSubjectDNFromX509Cert(rcac, rcac_dn));
269 :
270 0 : PERSISTENT_KEY_OP(mIndex, kOperationalCredentialsRootCertificateStorage, key,
271 : ReturnErrorOnFailure(mStorage->SyncSetKeyValue(key, rcac.data(), static_cast<uint16_t>(rcac.size()))));
272 : }
273 :
274 0 : ChipDN icac_dn;
275 0 : uint16_t icacBufLen = static_cast<uint16_t>(std::min(icac.size(), static_cast<size_t>(UINT16_MAX)));
276 0 : PERSISTENT_KEY_OP(mIndex, kOperationalCredentialsIntermediateCertificateStorage, key,
277 : err = mStorage->SyncGetKeyValue(key, icac.data(), icacBufLen));
278 : // Always regenerate ICAC on maximally sized certs. The keys remain the same, so everything is fine.
279 0 : if (mUseMaximallySizedCerts)
280 : {
281 0 : err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
282 : }
283 0 : if (err == CHIP_NO_ERROR)
284 : {
285 : uint64_t icacId;
286 : // Found intermediate certificate in the storage.
287 0 : icac.reduce_size(icacBufLen);
288 0 : ReturnErrorOnFailure(ExtractSubjectDNFromX509Cert(icac, icac_dn));
289 0 : ReturnErrorOnFailure(icac_dn.GetCertChipId(icacId));
290 0 : VerifyOrReturnError(icacId == mIntermediateIssuerId, CHIP_ERROR_INTERNAL);
291 : }
292 : // If intermediate certificate not found in the storage, generate new intermediate certificate.
293 : else
294 : {
295 0 : ReturnErrorOnFailure(icac_dn.AddAttribute_MatterICACId(mIntermediateIssuerId));
296 :
297 0 : ChipLogProgress(Controller, "Generating ICAC");
298 0 : ReturnErrorOnFailure(IssueX509Cert(mNow, mValidity, rcac_dn, icac_dn, CertType::kIcac, mUseMaximallySizedCerts,
299 : mIntermediateIssuer.Pubkey(), mIssuer, icac));
300 0 : VerifyOrReturnError(CanCastTo<uint16_t>(icac.size()), CHIP_ERROR_INTERNAL);
301 :
302 : // Re-extract DN based on final generated cert
303 0 : icac_dn = ChipDN{};
304 0 : ReturnErrorOnFailure(ExtractSubjectDNFromX509Cert(icac, icac_dn));
305 :
306 0 : PERSISTENT_KEY_OP(mIndex, kOperationalCredentialsIntermediateCertificateStorage, key,
307 : ReturnErrorOnFailure(mStorage->SyncSetKeyValue(key, icac.data(), static_cast<uint16_t>(icac.size()))));
308 : }
309 :
310 0 : ChipDN noc_dn;
311 0 : ReturnErrorOnFailure(noc_dn.AddAttribute_MatterFabricId(fabricId));
312 0 : ReturnErrorOnFailure(noc_dn.AddAttribute_MatterNodeId(nodeId));
313 0 : ReturnErrorOnFailure(noc_dn.AddCATs(cats));
314 :
315 0 : ChipLogProgress(Controller, "Generating NOC");
316 0 : return IssueX509Cert(mNow, mValidity, icac_dn, noc_dn, CertType::kNoc, mUseMaximallySizedCerts, pubkey, mIntermediateIssuer,
317 0 : noc);
318 0 : }
319 :
320 0 : CHIP_ERROR ExampleOperationalCredentialsIssuer::GenerateNOCChain(const ByteSpan & csrElements, const ByteSpan & csrNonce,
321 : const ByteSpan & attestationSignature,
322 : const ByteSpan & attestationChallenge, const ByteSpan & DAC,
323 : const ByteSpan & PAI,
324 : Callback::Callback<OnNOCChainGeneration> * onCompletion)
325 : {
326 0 : VerifyOrReturnError(mInitialized, CHIP_ERROR_UNINITIALIZED);
327 : // At this point, Credential issuer may wish to validate the CSR information
328 : (void) attestationChallenge;
329 : (void) csrNonce;
330 :
331 : NodeId assignedId;
332 0 : if (mNodeIdRequested)
333 : {
334 0 : assignedId = mNextRequestedNodeId;
335 0 : mNodeIdRequested = false;
336 : }
337 : else
338 : {
339 0 : assignedId = mNextAvailableNodeId++;
340 : }
341 :
342 0 : ChipLogProgress(Controller, "Verifying Certificate Signing Request");
343 : TLVReader reader;
344 0 : reader.Init(csrElements);
345 :
346 0 : if (reader.GetType() == kTLVType_NotSpecified)
347 : {
348 0 : ReturnErrorOnFailure(reader.Next());
349 : }
350 :
351 0 : ReturnErrorOnFailure(reader.Expect(kTLVType_Structure, AnonymousTag()));
352 :
353 : TLVType containerType;
354 0 : ReturnErrorOnFailure(reader.EnterContainer(containerType));
355 0 : ReturnErrorOnFailure(reader.Next(kTLVType_ByteString, TLV::ContextTag(1)));
356 :
357 0 : ByteSpan csr(reader.GetReadPoint(), reader.GetLength());
358 0 : reader.ExitContainer(containerType);
359 :
360 0 : P256PublicKey pubkey;
361 0 : ReturnErrorOnFailure(VerifyCertificateSigningRequest(csr.data(), csr.size(), pubkey));
362 :
363 0 : chip::Platform::ScopedMemoryBuffer<uint8_t> noc;
364 0 : ReturnErrorCodeIf(!noc.Alloc(kMaxDERCertLength), CHIP_ERROR_NO_MEMORY);
365 0 : MutableByteSpan nocSpan(noc.Get(), kMaxDERCertLength);
366 :
367 0 : chip::Platform::ScopedMemoryBuffer<uint8_t> icac;
368 0 : ReturnErrorCodeIf(!icac.Alloc(kMaxDERCertLength), CHIP_ERROR_NO_MEMORY);
369 0 : MutableByteSpan icacSpan(icac.Get(), kMaxDERCertLength);
370 :
371 0 : chip::Platform::ScopedMemoryBuffer<uint8_t> rcac;
372 0 : ReturnErrorCodeIf(!rcac.Alloc(kMaxDERCertLength), CHIP_ERROR_NO_MEMORY);
373 0 : MutableByteSpan rcacSpan(rcac.Get(), kMaxDERCertLength);
374 :
375 0 : ReturnErrorOnFailure(
376 : GenerateNOCChainAfterValidation(assignedId, mNextFabricId, mNextCATs, pubkey, rcacSpan, icacSpan, nocSpan));
377 :
378 : // TODO(#13825): Should always generate some IPK. Using a temporary fixed value until APIs are plumbed in to set it end-to-end
379 : // TODO: Force callers to set IPK if used before GenerateNOCChain will succeed.
380 0 : ByteSpan defaultIpkSpan = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk();
381 :
382 : // The below static assert validates a key assumption in types used (needed for public API conformance)
383 : static_assert(CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES == kAES_CCM128_Key_Length, "IPK span sizing must match");
384 :
385 : // Prepare IPK to be sent back. A more fully-fledged operational credentials delegate
386 : // would obtain a suitable key per fabric.
387 : uint8_t ipkValue[CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES];
388 0 : Crypto::IdentityProtectionKeySpan ipkSpan(ipkValue);
389 :
390 0 : ReturnErrorCodeIf(defaultIpkSpan.size() != sizeof(ipkValue), CHIP_ERROR_INTERNAL);
391 0 : memcpy(&ipkValue[0], defaultIpkSpan.data(), defaultIpkSpan.size());
392 :
393 : // Callback onto commissioner.
394 0 : ChipLogProgress(Controller, "Providing certificate chain to the commissioner");
395 0 : onCompletion->mCall(onCompletion->mContext, CHIP_NO_ERROR, nocSpan, icacSpan, rcacSpan, MakeOptional(ipkSpan),
396 0 : Optional<NodeId>());
397 0 : return CHIP_NO_ERROR;
398 0 : }
399 :
400 0 : CHIP_ERROR ExampleOperationalCredentialsIssuer::GetRandomOperationalNodeId(NodeId * aNodeId)
401 : {
402 0 : for (int i = 0; i < 10; ++i)
403 : {
404 0 : CHIP_ERROR err = DRBG_get_bytes(reinterpret_cast<uint8_t *>(aNodeId), sizeof(*aNodeId));
405 0 : if (err != CHIP_NO_ERROR)
406 : {
407 0 : return err;
408 : }
409 :
410 0 : if (IsOperationalNodeId(*aNodeId))
411 : {
412 0 : return CHIP_NO_ERROR;
413 : }
414 : }
415 :
416 : // Terrible, universe-ending luck (chances are 1 in 2^280 or so here, if our
417 : // DRBG is good).
418 0 : return CHIP_ERROR_INTERNAL;
419 : }
420 :
421 : } // namespace Controller
422 : } // namespace chip
|