Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #pragma once
18 :
19 : #include <crypto/CHIPCryptoPAL.h>
20 : #include <lib/core/CHIPCallback.h>
21 : #include <lib/core/CHIPError.h>
22 : #include <lib/core/CHIPVendorIdentifiers.hpp>
23 : #include <lib/support/ScopedBuffer.h>
24 : #include <lib/support/Span.h>
25 : #include <stdlib.h>
26 :
27 : namespace chip {
28 : namespace Credentials {
29 :
30 : enum class AttestationVerificationResult : uint16_t
31 : {
32 : kSuccess = 0,
33 :
34 : kPaaUntrusted = 100, // NOTE: Was not used due to kPaaNotFound being the main case.
35 : kPaaNotFound = 101,
36 : kPaaExpired = 102,
37 : kPaaSignatureInvalid = 103,
38 : kPaaRevoked = 104, // NOTE: Likely not used in most cases due to kPaaNotFound being the main case.
39 : kPaaFormatInvalid = 105,
40 : kPaaArgumentInvalid = 106,
41 :
42 : kPaiExpired = 200,
43 : kPaiSignatureInvalid = 201,
44 : kPaiRevoked = 202,
45 : kPaiFormatInvalid = 203,
46 : kPaiArgumentInvalid = 204,
47 : kPaiVendorIdMismatch = 205,
48 : kPaiAuthorityNotFound = 206,
49 : kPaiMissing = 207,
50 : kPaiAndDacRevoked = 208,
51 :
52 : kDacExpired = 300,
53 : kDacSignatureInvalid = 301,
54 : kDacRevoked = 302,
55 : kDacFormatInvalid = 303,
56 : kDacArgumentInvalid = 304,
57 : kDacVendorIdMismatch = 305,
58 : kDacProductIdMismatch = 306,
59 : kDacAuthorityNotFound = 307,
60 :
61 : kFirmwareInformationMismatch = 400,
62 : kFirmwareInformationMissing = 401,
63 :
64 : kAttestationSignatureInvalid = 500,
65 : kAttestationElementsMalformed = 501,
66 : kAttestationNonceMismatch = 502,
67 : kAttestationSignatureInvalidFormat = 503,
68 :
69 : kCertificationDeclarationNoKeyId = 600,
70 : kCertificationDeclarationNoCertificateFound = 601,
71 : kCertificationDeclarationInvalidSignature = 602,
72 : kCertificationDeclarationInvalidFormat = 603,
73 : kCertificationDeclarationInvalidVendorId = 604,
74 : kCertificationDeclarationInvalidProductId = 605,
75 : kCertificationDeclarationInvalidPAA = 606,
76 :
77 : kNoMemory = 700,
78 : kInvalidArgument = 701,
79 : kInternalError = 702,
80 : kNotImplemented = 703,
81 :
82 : // TODO: Add more attestation verification errors
83 : };
84 :
85 : enum CertificateType : uint8_t
86 : {
87 : kUnknown = 0,
88 : kDAC = 1,
89 : kPAI = 2,
90 : };
91 :
92 : struct DeviceInfoForAttestation
93 : {
94 : // Vendor ID reported by device in Basic Information cluster
95 : uint16_t vendorId = VendorId::NotSpecified;
96 : // Product ID reported by device in Basic Information cluster
97 : uint16_t productId = 0;
98 : // Vendor ID from DAC
99 : uint16_t dacVendorId = VendorId::NotSpecified;
100 : // Product ID from DAC
101 : uint16_t dacProductId = 0;
102 : // Vendor ID from PAI cert
103 : uint16_t paiVendorId = VendorId::NotSpecified;
104 : // Product ID from PAI cert (0 if absent)
105 : uint16_t paiProductId = 0;
106 : // Vendor ID from PAA cert
107 : uint16_t paaVendorId = VendorId::NotSpecified;
108 : // Subject Key Identifier (SKID) from PAA cert
109 : uint8_t paaSKID[Crypto::kSubjectKeyIdentifierLength] = { 0 };
110 : };
111 :
112 : /**
113 : * @brief Helper utility to model a basic trust store usable for device attestation verifiers.
114 : *
115 : * API is synchronous. Real commissioner implementations may entirely
116 : * hide Product Attestation Authority cert lookup behind the DeviceAttestationVerifier and
117 : * never use this interface at all. It is provided as a utility to help build DeviceAttestationVerifier
118 : * implementations suitable for testing or examples.
119 : */
120 : class AttestationTrustStore
121 : {
122 : public:
123 3 : AttestationTrustStore() = default;
124 3 : virtual ~AttestationTrustStore() = default;
125 :
126 : // Not copyable
127 : AttestationTrustStore(const AttestationTrustStore &) = delete;
128 : AttestationTrustStore & operator=(const AttestationTrustStore &) = delete;
129 :
130 : /**
131 : * @brief Look-up a PAA cert by SKID
132 : *
133 : * The implementations of this interface must have access to a set of PAAs to trust.
134 : *
135 : * Interface is synchronous, and therefore this should not be used unless to expose a PAA
136 : * store that is both fully local and quick to access.
137 : *
138 : * @param[in] skid Buffer containing the subject key identifier (SKID) of the PAA to look-up
139 : * @param[in,out] outPaaDerBuffer Buffer to receive the contents of the PAA root cert, if found.
140 : * Size will be updated to match actual size.
141 : *
142 : * @returns CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if `skid` or `outPaaDerBuffer` arguments
143 : * are not usable, CHIP_BUFFER_TOO_SMALL if certificate doesn't fit in `outPaaDerBuffer`
144 : * span, CHIP_ERROR_CA_CERT_NOT_FOUND if no PAA found that matches `skid.
145 : *
146 : */
147 : virtual CHIP_ERROR GetProductAttestationAuthorityCert(const ByteSpan & skid, MutableByteSpan & outPaaDerBuffer) const = 0;
148 : };
149 :
150 : /**
151 : * @brief Helper utility to model obtaining verifying keys by Key ID
152 : *
153 : * API is synchronous. Real commissioner implementations may entirely
154 : * hide key lookup behind the DeviceAttestationVerifier and never use this interface at all.
155 : * It is provided as a utility to help build DeviceAttestationVerifier
156 : * implementations suitable for testing or examples.
157 : */
158 : class WellKnownKeysTrustStore
159 : {
160 : public:
161 2 : WellKnownKeysTrustStore() = default;
162 2 : virtual ~WellKnownKeysTrustStore() = default;
163 :
164 : // Not copyable
165 : WellKnownKeysTrustStore(const WellKnownKeysTrustStore &) = delete;
166 : WellKnownKeysTrustStore & operator=(const WellKnownKeysTrustStore &) = delete;
167 :
168 : /**
169 : * @brief Add a trusted key directly
170 : *
171 : * @param[in] kid - Key ID to use. Usually 20 bytes long, max 32 bytes.
172 : * @param[in] pubKey - Verifying public key to attach to the key ID.
173 : *
174 : * @return CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if `kid` or `pubKey` arguments
175 : * are not usable. CHIP_ERROR_NO_MEMORY if the trust store is full.
176 : */
177 : virtual CHIP_ERROR AddTrustedKey(const ByteSpan & kid, const Crypto::P256PublicKey & pubKey) = 0;
178 :
179 : /**
180 : * @brief Add a trusted key via a public certificate.
181 : *
182 : * The subject public key of the certificate will be used.
183 : * The subject key ID extensions of the certificate will be the `kid`.
184 : *
185 : * Verification of trust chaining is at the discretion of the implementation.
186 : *
187 : * @param[in] derCertBytes - Certificate containing the X.509 DER certificate with the key.
188 : *
189 : * @return CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if derCertBytes is improperly
190 : * formatted or not trusted. CHIP_ERROR_NO_MEMORY if the trust store is full.
191 : */
192 : virtual CHIP_ERROR AddTrustedKey(const ByteSpan & derCertBytes) = 0;
193 :
194 : /**
195 : * @brief Look-up a verifying key by Key ID
196 : *
197 : * Interface is synchronous.
198 : *
199 : * @param[in] kid Buffer containing the key identifier (KID) of the verifying key to look-up. Usually
200 : * a SHA-1-sized buffer (20 bytes).
201 : * @param[out] outPubKey Reference to where the verifying key found will be stored on CHIP_NO_ERROR
202 : *
203 : * @returns CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if `kid` or `pubKey` arguments
204 : * are not usable, CHIP_ERROR_KEY_NOT_FOUND if no key is found that matches `kid`.
205 : */
206 : virtual CHIP_ERROR LookupVerifyingKey(const ByteSpan & kid, Crypto::P256PublicKey & outPubKey) const = 0;
207 :
208 : /**
209 : * @brief Returns true if `kid` identifies a known test key.
210 : *
211 : * @param kid - Key ID to use. Usually 20 bytes long, max 32 bytes.
212 : * @return true if it's a test/development-only signing key identifier, false otherwise
213 : */
214 : virtual bool IsCdTestKey(const ByteSpan & kid) const = 0;
215 : };
216 :
217 : /**
218 : * @brief Basic AttestationTrustStore that holds all data within caller-owned memory.
219 : *
220 : * This is useful to wrap a fixed constant array of certificates into a trust store
221 : * implementation.
222 : */
223 :
224 : class ArrayAttestationTrustStore : public AttestationTrustStore
225 : {
226 : public:
227 3 : ArrayAttestationTrustStore(const ByteSpan * derCerts, size_t numCerts) : mDerCerts(derCerts), mNumCerts(numCerts) {}
228 :
229 99 : CHIP_ERROR GetProductAttestationAuthorityCert(const ByteSpan & skid, MutableByteSpan & outPaaDerBuffer) const override
230 : {
231 99 : VerifyOrReturnError(!skid.empty() && (skid.data() != nullptr), CHIP_ERROR_INVALID_ARGUMENT);
232 98 : VerifyOrReturnError(skid.size() == Crypto::kSubjectKeyIdentifierLength, CHIP_ERROR_INVALID_ARGUMENT);
233 :
234 : size_t paaIdx;
235 97 : ByteSpan candidate;
236 :
237 104 : for (paaIdx = 0; paaIdx < mNumCerts; ++paaIdx)
238 : {
239 102 : uint8_t skidBuf[Crypto::kSubjectKeyIdentifierLength] = { 0 };
240 102 : candidate = mDerCerts[paaIdx];
241 102 : MutableByteSpan candidateSkidSpan{ skidBuf };
242 197 : VerifyOrReturnError(CHIP_NO_ERROR == Crypto::ExtractSKIDFromX509Cert(candidate, candidateSkidSpan),
243 : CHIP_ERROR_INTERNAL);
244 :
245 102 : if (skid.data_equal(candidateSkidSpan))
246 : {
247 : // Found a match
248 95 : return CopySpanToMutableSpan(candidate, outPaaDerBuffer);
249 : }
250 : }
251 :
252 2 : return CHIP_ERROR_CA_CERT_NOT_FOUND;
253 : }
254 :
255 : protected:
256 : const ByteSpan * mDerCerts;
257 : const size_t mNumCerts;
258 : };
259 :
260 : // forward declaration
261 : class DeviceAttestationRevocationDelegate;
262 :
263 : class DeviceAttestationVerifier
264 : {
265 : public:
266 2 : DeviceAttestationVerifier() = default;
267 7 : virtual ~DeviceAttestationVerifier() = default;
268 :
269 : // Not copyable
270 : DeviceAttestationVerifier(const DeviceAttestationVerifier &) = delete;
271 : DeviceAttestationVerifier & operator=(const DeviceAttestationVerifier &) = delete;
272 :
273 : struct AttestationInfo
274 : {
275 0 : AttestationInfo(const ByteSpan & attestationElements, const ByteSpan & attestationChallenge,
276 : const ByteSpan & attestationSignature, const ByteSpan & paiDer, const ByteSpan & dacDer,
277 0 : const ByteSpan & attestationNonce, VendorId remoteVendorId, uint16_t remoteProductId) :
278 0 : attestationElementsBuffer(attestationElements),
279 0 : attestationChallengeBuffer(attestationChallenge), attestationSignatureBuffer(attestationSignature),
280 0 : paiDerBuffer(paiDer), dacDerBuffer(dacDer), attestationNonceBuffer(attestationNonce), vendorId(remoteVendorId),
281 0 : productId(remoteProductId)
282 0 : {}
283 : const ByteSpan
284 : attestationElementsBuffer; // Buffer containing attestation elements portion of Attestation Response (raw TLV)
285 : const ByteSpan attestationChallengeBuffer; // Buffer containing the attestation challenge from the secure session
286 : const ByteSpan attestationSignatureBuffer; // Buffer the signature portion of Attestation Response
287 : const ByteSpan paiDerBuffer; // Buffer containing the PAI certificate from device in DER format.
288 : const ByteSpan dacDerBuffer; // Buffer containing the DAC certificate from device in DER format.
289 : const ByteSpan attestationNonceBuffer; // Buffer containing attestation nonce.
290 : VendorId vendorId;
291 : uint16_t productId;
292 : };
293 :
294 : // Copies the bytes passed to it, and holds the PAI, DAC, and CD for additional verification step
295 : class AttestationDeviceInfo
296 : {
297 : public:
298 : AttestationDeviceInfo(const AttestationInfo & attestationInfo);
299 :
300 0 : ~AttestationDeviceInfo() = default;
301 :
302 : // Returns buffer containing the PAI certificate from device in DER format.
303 : const ByteSpan paiDerBuffer() const { return ByteSpan(mPaiDerBuffer.Get(), mPaiDerBuffer.AllocatedSize()); }
304 :
305 : // Returns buffer containing the DAC certificate from device in DER format.
306 : const ByteSpan dacDerBuffer() const { return ByteSpan(mDacDerBuffer.Get(), mDacDerBuffer.AllocatedSize()); }
307 :
308 : // Returns optional buffer containing the certificate declaration from device.
309 : const Optional<ByteSpan> cdBuffer() const
310 : {
311 : if (mCdBuffer.Get())
312 : {
313 : return MakeOptional(ByteSpan(mDacDerBuffer.Get(), mDacDerBuffer.AllocatedSize()));
314 : }
315 : else
316 : {
317 : return Optional<ByteSpan>();
318 : }
319 : }
320 :
321 : uint16_t BasicInformationVendorId() const { return mBasicInformationVendorId; }
322 :
323 : uint16_t BasicInformationProductId() const { return mBasicInformationProductId; }
324 :
325 : private:
326 : Platform::ScopedMemoryBufferWithSize<uint8_t> mPaiDerBuffer;
327 : Platform::ScopedMemoryBufferWithSize<uint8_t> mDacDerBuffer;
328 : Platform::ScopedMemoryBufferWithSize<uint8_t> mCdBuffer;
329 : uint16_t mBasicInformationVendorId;
330 : uint16_t mBasicInformationProductId;
331 : };
332 :
333 : typedef void (*OnAttestationInformationVerification)(void * context, const AttestationInfo & info,
334 : AttestationVerificationResult result);
335 :
336 : /**
337 : * @brief Verify an attestation information payload against a DAC/PAI chain.
338 : *
339 : * @param[in] info All of the information required to verify the attestation.
340 : * @param[in] onCompletion Callback handler to provide Attestation Information Verification result to the caller of
341 : * VerifyAttestationInformation()
342 : */
343 : virtual void VerifyAttestationInformation(const AttestationInfo & info,
344 : Callback::Callback<OnAttestationInformationVerification> * onCompletion) = 0;
345 :
346 : /**
347 : * @brief Verify a CMS Signed Data signature against the CSA certificate of Subject Key Identifier that matches
348 : * the subjectKeyIdentifier field of cmsEnvelopeBuffer.
349 : *
350 : * @param[in] cmsEnvelopeBuffer A ByteSpan with a CMS signed message.
351 : * @param[out] certDeclBuffer A ByteSpan to hold the CD content extracted from the CMS signed message.
352 : *
353 : * @returns AttestationVerificationResult::kSuccess on success or another specific
354 : * value from AttestationVerificationResult enum on failure.
355 : */
356 : virtual AttestationVerificationResult ValidateCertificationDeclarationSignature(const ByteSpan & cmsEnvelopeBuffer,
357 : ByteSpan & certDeclBuffer) = 0;
358 :
359 : /**
360 : * @brief Verify a CMS Signed Data Payload against the Basic Information Cluster and DAC/PAI's Vendor and Product IDs
361 : *
362 : * @param[in] certDeclBuffer A ByteSpan with the Certification Declaration content.
363 : * @param[in] firmwareInfo A ByteSpan with the Firmware Information content.
364 : * @param[in] deviceInfo The device information
365 : *
366 : * @returns AttestationVerificationResult::kSuccess on success or another specific
367 : * value from AttestationVerificationResult enum on failure.
368 : */
369 : virtual AttestationVerificationResult ValidateCertificateDeclarationPayload(const ByteSpan & certDeclBuffer,
370 : const ByteSpan & firmwareInfo,
371 : const DeviceInfoForAttestation & deviceInfo) = 0;
372 :
373 : // TODO: Validate Firmware Information
374 :
375 : /**
376 : * @brief Verify an operational certificate signing request payload against the DAC's public key.
377 : *
378 : * @param[in] nocsrElementsBuffer Buffer containing CSR elements as per specifications section 11.22.5.6. NOCSR Elements.
379 : * @param[in] attestationChallengeBuffer Buffer containing the attestation challenge from the secure session
380 : * @param[in] attestationSignatureBuffer Buffer containing the signature portion of CSR Response
381 : * @param[in] dacPublicKey Public Key from the DAC's certificate received from device.
382 : * @param[in] csrNonce Buffer containing CSR nonce.
383 : */
384 : virtual CHIP_ERROR VerifyNodeOperationalCSRInformation(const ByteSpan & nocsrElementsBuffer,
385 : const ByteSpan & attestationChallengeBuffer,
386 : const ByteSpan & attestationSignatureBuffer,
387 : const Crypto::P256PublicKey & dacPublicKey,
388 : const ByteSpan & csrNonce) = 0;
389 :
390 : /**
391 : * @brief Verify whether or not the given DAC chain is revoked.
392 : *
393 : * @param[in] info All of the information required to check for revoked DAC chain.
394 : * @param[in] onCompletion Callback handler to provide Attestation Information Verification result to the caller of
395 : * CheckForRevokedDACChain()
396 : */
397 : virtual void CheckForRevokedDACChain(const AttestationInfo & info,
398 : Callback::Callback<OnAttestationInformationVerification> * onCompletion) = 0;
399 :
400 : /**
401 : * @brief Get the trust store used for the attestation verifier.
402 : *
403 : * Returns nullptr if not supported. Be careful not to hold-on to the trust store
404 : * for too long. It is only expected to have same lifetime as the DeviceAttestationVerifier.
405 : *
406 : * @return a pointer to the trust store or nullptr if none is directly accessible.
407 : */
408 0 : virtual WellKnownKeysTrustStore * GetCertificationDeclarationTrustStore() { return nullptr; }
409 :
410 : /**
411 : * @brief Set whether the test CD keys from SDK are accepted (should be false in production)
412 : *
413 : * @param enabled - true to trust the SDK's test CD signing key, false otherwise.
414 : */
415 : void EnableCdTestKeySupport(bool enabled) { mEnableCdTestKeySupport = enabled; }
416 :
417 : /**
418 : * @brief Set whether extra verbose logging is enabled. The meaning depends on the verifier.
419 : *
420 : * @param enabled - if true, verbose logs will be enabled, otherwise they will be disabled.
421 : */
422 : void EnableVerboseLogs(bool enabled) { mEnableVerboseLogs = enabled; }
423 :
424 82 : bool IsCdTestKeySupported() const { return mEnableCdTestKeySupport; }
425 317 : bool AreVerboseLogsEnabled() const { return mEnableVerboseLogs; }
426 :
427 : /**
428 : * @brief Try to set the revocation delegate.
429 : *
430 : * @param[in] revocationDelegate The revocation delegate to set.
431 : *
432 : * @return CHIP_NO_ERROR on success, CHIP_ERROR_NOT_IMPLEMENTED if the revocation delegate is not supported.
433 : */
434 0 : virtual CHIP_ERROR SetRevocationDelegate(DeviceAttestationRevocationDelegate * revocationDelegate)
435 : {
436 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
437 : }
438 :
439 : protected:
440 : CHIP_ERROR ValidateAttestationSignature(const Crypto::P256PublicKey & pubkey, const ByteSpan & attestationElements,
441 : const ByteSpan & attestationChallenge, const Crypto::P256ECDSASignature & signature);
442 :
443 : // Default to support the "development" test key for legacy purposes (since the DefaultDACVerifier)
444 : // always supported development keys.
445 : bool mEnableCdTestKeySupport = true;
446 : bool mEnableVerboseLogs = false;
447 : };
448 :
449 : /**
450 : * @brief Interface for checking the device attestation revocation status
451 : *
452 : */
453 : class DeviceAttestationRevocationDelegate
454 : {
455 : public:
456 : DeviceAttestationRevocationDelegate() = default;
457 0 : virtual ~DeviceAttestationRevocationDelegate() = default;
458 :
459 : /**
460 : * @brief Verify whether or not the given DAC chain is revoked.
461 : *
462 : * @param[in] info All of the information required to check for revoked DAC chain.
463 : * @param[in] onCompletion Callback handler to provide Attestation Information Verification result to the caller of
464 : * CheckForRevokedDACChain().
465 : */
466 : virtual void
467 : CheckForRevokedDACChain(const DeviceAttestationVerifier::AttestationInfo & info,
468 : Callback::Callback<DeviceAttestationVerifier::OnAttestationInformationVerification> * onCompletion) = 0;
469 : };
470 :
471 : /**
472 : * @brief Get a brief description of an `AttestationVerificationResult` enum value.
473 : *
474 : * @param resultCode - The result code to describe
475 : * @return a pointer to a static null-terminated string describing the error.
476 : */
477 : const char * GetAttestationResultDescription(AttestationVerificationResult resultCode);
478 :
479 : /**
480 : * Instance getter for the global DeviceAttestationVerifier.
481 : *
482 : * Callers have to externally synchronize usage of this function.
483 : *
484 : * @return The global device attestation verifier. Assume never null.
485 : */
486 : DeviceAttestationVerifier * GetDeviceAttestationVerifier();
487 :
488 : /**
489 : * Instance setter for the global DeviceAttestationVerifier.
490 : *
491 : * Callers have to externally synchronize usage of this function.
492 : *
493 : * If the `verifier` is nullptr, no change is done.
494 : *
495 : * @param[in] verifier the DeviceAttestationVerifier to start returning with the getter
496 : */
497 : void SetDeviceAttestationVerifier(DeviceAttestationVerifier * verifier);
498 :
499 : } // namespace Credentials
500 : } // namespace chip
|