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,
35 : kPaaNotFound = 101,
36 : kPaaExpired = 102,
37 : kPaaSignatureInvalid = 103,
38 : kPaaRevoked = 104,
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 :
51 : kDacExpired = 300,
52 : kDacSignatureInvalid = 301,
53 : kDacRevoked = 302,
54 : kDacFormatInvalid = 303,
55 : kDacArgumentInvalid = 304,
56 : kDacVendorIdMismatch = 305,
57 : kDacProductIdMismatch = 306,
58 : kDacAuthorityNotFound = 307,
59 :
60 : kFirmwareInformationMismatch = 400,
61 : kFirmwareInformationMissing = 401,
62 :
63 : kAttestationSignatureInvalid = 500,
64 : kAttestationElementsMalformed = 501,
65 : kAttestationNonceMismatch = 502,
66 : kAttestationSignatureInvalidFormat = 503,
67 :
68 : kCertificationDeclarationNoKeyId = 600,
69 : kCertificationDeclarationNoCertificateFound = 601,
70 : kCertificationDeclarationInvalidSignature = 602,
71 : kCertificationDeclarationInvalidFormat = 603,
72 : kCertificationDeclarationInvalidVendorId = 604,
73 : kCertificationDeclarationInvalidProductId = 605,
74 : kCertificationDeclarationInvalidPAA = 606,
75 :
76 : kNoMemory = 700,
77 :
78 : kInvalidArgument = 800,
79 :
80 : kInternalError = 900,
81 :
82 : kNotImplemented = 0xFFFFU,
83 :
84 : // TODO: Add more attestation verification errors
85 : };
86 :
87 : enum CertificateType : uint8_t
88 : {
89 : kUnknown = 0,
90 : kDAC = 1,
91 : kPAI = 2,
92 : };
93 :
94 : struct DeviceInfoForAttestation
95 : {
96 : // Vendor ID reported by device in Basic Information cluster
97 : uint16_t vendorId = VendorId::NotSpecified;
98 : // Product ID reported by device in Basic Information cluster
99 : uint16_t productId = 0;
100 : // Vendor ID from DAC
101 : uint16_t dacVendorId = VendorId::NotSpecified;
102 : // Product ID from DAC
103 : uint16_t dacProductId = 0;
104 : // Vendor ID from PAI cert
105 : uint16_t paiVendorId = VendorId::NotSpecified;
106 : // Product ID from PAI cert (0 if absent)
107 : uint16_t paiProductId = 0;
108 : // Vendor ID from PAA cert
109 : uint16_t paaVendorId = VendorId::NotSpecified;
110 : // Subject Key Identifier (SKID) from PAA cert
111 : uint8_t paaSKID[Crypto::kSubjectKeyIdentifierLength] = { 0 };
112 : };
113 :
114 : /**
115 : * @brief Helper utility to model a basic trust store usable for device attestation verifiers.
116 : *
117 : * API is synchronous. Real commissioner implementations may entirely
118 : * hide Product Attestation Authority cert lookup behind the DeviceAttestationVerifier and
119 : * never use this interface at all. It is provided as a utility to help build DeviceAttestationVerifier
120 : * implementations suitable for testing or examples.
121 : */
122 : class AttestationTrustStore
123 : {
124 : public:
125 3 : AttestationTrustStore() = default;
126 3 : virtual ~AttestationTrustStore() = default;
127 :
128 : // Not copyable
129 : AttestationTrustStore(const AttestationTrustStore &) = delete;
130 : AttestationTrustStore & operator=(const AttestationTrustStore &) = delete;
131 :
132 : /**
133 : * @brief Look-up a PAA cert by SKID
134 : *
135 : * The implementations of this interface must have access to a set of PAAs to trust.
136 : *
137 : * Interface is synchronous, and therefore this should not be used unless to expose a PAA
138 : * store that is both fully local and quick to access.
139 : *
140 : * @param[in] skid Buffer containing the subject key identifier (SKID) of the PAA to look-up
141 : * @param[in,out] outPaaDerBuffer Buffer to receive the contents of the PAA root cert, if found.
142 : * Size will be updated to match actual size.
143 : *
144 : * @returns CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if `skid` or `outPaaDerBuffer` arguments
145 : * are not usable, CHIP_BUFFER_TOO_SMALL if certificate doesn't fit in `outPaaDerBuffer`
146 : * span, CHIP_ERROR_CA_CERT_NOT_FOUND if no PAA found that matches `skid.
147 : *
148 : */
149 : virtual CHIP_ERROR GetProductAttestationAuthorityCert(const ByteSpan & skid, MutableByteSpan & outPaaDerBuffer) const = 0;
150 : };
151 :
152 : /**
153 : * @brief Helper utility to model obtaining verifying keys by Key ID
154 : *
155 : * API is synchronous. Real commissioner implementations may entirely
156 : * hide key lookup behind the DeviceAttestationVerifier and never use this interface at all.
157 : * It is provided as a utility to help build DeviceAttestationVerifier
158 : * implementations suitable for testing or examples.
159 : */
160 : class WellKnownKeysTrustStore
161 : {
162 : public:
163 2 : WellKnownKeysTrustStore() = default;
164 2 : virtual ~WellKnownKeysTrustStore() = default;
165 :
166 : // Not copyable
167 : WellKnownKeysTrustStore(const WellKnownKeysTrustStore &) = delete;
168 : WellKnownKeysTrustStore & operator=(const WellKnownKeysTrustStore &) = delete;
169 :
170 : /**
171 : * @brief Add a trusted key directly
172 : *
173 : * @param[in] kid - Key ID to use. Usually 20 bytes long, max 32 bytes.
174 : * @param[in] pubKey - Verifying public key to attach to the key ID.
175 : *
176 : * @return CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if `kid` or `pubKey` arguments
177 : * are not usable. CHIP_ERROR_NO_MEMORY if the trust store is full.
178 : */
179 : virtual CHIP_ERROR AddTrustedKey(const ByteSpan & kid, const Crypto::P256PublicKey & pubKey) = 0;
180 :
181 : /**
182 : * @brief Add a trusted key via a public certificate.
183 : *
184 : * The subject public key of the certificate will be used.
185 : * The subject key ID extensions of the certificate will be the `kid`.
186 : *
187 : * Verification of trust chaining is at the discretion of the implementation.
188 : *
189 : * @param[in] derCertBytes - Certificate containing the X.509 DER certificate with the key.
190 : *
191 : * @return CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if derCertBytes is improperly
192 : * formatted or not trusted. CHIP_ERROR_NO_MEMORY if the trust store is full.
193 : */
194 : virtual CHIP_ERROR AddTrustedKey(const ByteSpan & derCertBytes) = 0;
195 :
196 : /**
197 : * @brief Look-up a verifying key by Key ID
198 : *
199 : * Interface is synchronous.
200 : *
201 : * @param[in] kid Buffer containing the key identifier (KID) of the verifying key to look-up. Usually
202 : * a SHA-1-sized buffer (20 bytes).
203 : * @param[out] outPubKey Reference to where the verifying key found will be stored on CHIP_NO_ERROR
204 : *
205 : * @returns CHIP_NO_ERROR on success, CHIP_INVALID_ARGUMENT if `kid` or `pubKey` arguments
206 : * are not usable, CHIP_ERROR_KEY_NOT_FOUND if no key is found that matches `kid`.
207 : */
208 : virtual CHIP_ERROR LookupVerifyingKey(const ByteSpan & kid, Crypto::P256PublicKey & outPubKey) const = 0;
209 :
210 : /**
211 : * @brief Returns true if `kid` identifies a known test key.
212 : *
213 : * @param kid - Key ID to use. Usually 20 bytes long, max 32 bytes.
214 : * @return true if it's a test/development-only signing key identifier, false otherwise
215 : */
216 : virtual bool IsCdTestKey(const ByteSpan & kid) const = 0;
217 : };
218 :
219 : /**
220 : * @brief Basic AttestationTrustStore that holds all data within caller-owned memory.
221 : *
222 : * This is useful to wrap a fixed constant array of certificates into a trust store
223 : * implementation.
224 : */
225 :
226 : class ArrayAttestationTrustStore : public AttestationTrustStore
227 : {
228 : public:
229 3 : ArrayAttestationTrustStore(const ByteSpan * derCerts, size_t numCerts) : mDerCerts(derCerts), mNumCerts(numCerts) {}
230 :
231 97 : CHIP_ERROR GetProductAttestationAuthorityCert(const ByteSpan & skid, MutableByteSpan & outPaaDerBuffer) const override
232 : {
233 97 : VerifyOrReturnError(!skid.empty() && (skid.data() != nullptr), CHIP_ERROR_INVALID_ARGUMENT);
234 96 : VerifyOrReturnError(skid.size() == Crypto::kSubjectKeyIdentifierLength, CHIP_ERROR_INVALID_ARGUMENT);
235 :
236 : size_t paaIdx;
237 95 : ByteSpan candidate;
238 :
239 102 : for (paaIdx = 0; paaIdx < mNumCerts; ++paaIdx)
240 : {
241 100 : uint8_t skidBuf[Crypto::kSubjectKeyIdentifierLength] = { 0 };
242 100 : candidate = mDerCerts[paaIdx];
243 100 : MutableByteSpan candidateSkidSpan{ skidBuf };
244 193 : VerifyOrReturnError(CHIP_NO_ERROR == Crypto::ExtractSKIDFromX509Cert(candidate, candidateSkidSpan),
245 : CHIP_ERROR_INTERNAL);
246 :
247 100 : if (skid.data_equal(candidateSkidSpan))
248 : {
249 : // Found a match
250 93 : return CopySpanToMutableSpan(candidate, outPaaDerBuffer);
251 : }
252 : }
253 :
254 2 : return CHIP_ERROR_CA_CERT_NOT_FOUND;
255 : }
256 :
257 : protected:
258 : const ByteSpan * mDerCerts;
259 : const size_t mNumCerts;
260 : };
261 :
262 : class DeviceAttestationVerifier
263 : {
264 : public:
265 2 : DeviceAttestationVerifier() = default;
266 5 : virtual ~DeviceAttestationVerifier() = default;
267 :
268 : // Not copyable
269 : DeviceAttestationVerifier(const DeviceAttestationVerifier &) = delete;
270 : DeviceAttestationVerifier & operator=(const DeviceAttestationVerifier &) = delete;
271 :
272 : struct AttestationInfo
273 : {
274 0 : AttestationInfo(const ByteSpan & attestationElements, const ByteSpan & attestationChallenge,
275 : const ByteSpan & attestationSignature, const ByteSpan & paiDer, const ByteSpan & dacDer,
276 0 : const ByteSpan & attestationNonce, VendorId remoteVendorId, uint16_t remoteProductId) :
277 0 : attestationElementsBuffer(attestationElements),
278 0 : attestationChallengeBuffer(attestationChallenge), attestationSignatureBuffer(attestationSignature),
279 0 : paiDerBuffer(paiDer), dacDerBuffer(dacDer), attestationNonceBuffer(attestationNonce), vendorId(remoteVendorId),
280 0 : productId(remoteProductId)
281 0 : {}
282 : const ByteSpan
283 : attestationElementsBuffer; // Buffer containing attestation elements portion of Attestation Response (raw TLV)
284 : const ByteSpan attestationChallengeBuffer; // Buffer containing the attestation challenge from the secure session
285 : const ByteSpan attestationSignatureBuffer; // Buffer the signature portion of Attestation Response
286 : const ByteSpan paiDerBuffer; // Buffer containing the PAI certificate from device in DER format.
287 : const ByteSpan dacDerBuffer; // Buffer containing the DAC certificate from device in DER format.
288 : const ByteSpan attestationNonceBuffer; // Buffer containing attestation nonce.
289 : VendorId vendorId;
290 : uint16_t productId;
291 : };
292 :
293 : // Copies the bytes passed to it, and holds the PAI, DAC, and CD for additional verification step
294 : class AttestationDeviceInfo
295 : {
296 : public:
297 : AttestationDeviceInfo(const AttestationInfo & attestationInfo);
298 :
299 0 : ~AttestationDeviceInfo() = default;
300 :
301 : // Returns buffer containing the PAI certificate from device in DER format.
302 : const ByteSpan paiDerBuffer() const { return ByteSpan(mPaiDerBuffer.Get(), mPaiDerBuffer.AllocatedSize()); }
303 :
304 : // Returns buffer containing the DAC certificate from device in DER format.
305 : const ByteSpan dacDerBuffer() const { return ByteSpan(mDacDerBuffer.Get(), mDacDerBuffer.AllocatedSize()); }
306 :
307 : // Returns optional buffer containing the certificate declaration from device.
308 : const Optional<ByteSpan> cdBuffer() const
309 : {
310 : if (mCdBuffer.Get())
311 : {
312 : return MakeOptional(ByteSpan(mDacDerBuffer.Get(), mDacDerBuffer.AllocatedSize()));
313 : }
314 : else
315 : {
316 : return Optional<ByteSpan>();
317 : }
318 : }
319 :
320 : uint16_t BasicInformationVendorId() const { return mBasicInformationVendorId; }
321 :
322 : uint16_t BasicInformationProductId() const { return mBasicInformationProductId; }
323 :
324 : private:
325 : Platform::ScopedMemoryBufferWithSize<uint8_t> mPaiDerBuffer;
326 : Platform::ScopedMemoryBufferWithSize<uint8_t> mDacDerBuffer;
327 : Platform::ScopedMemoryBufferWithSize<uint8_t> mCdBuffer;
328 : uint16_t mBasicInformationVendorId;
329 : uint16_t mBasicInformationProductId;
330 : };
331 :
332 : typedef void (*OnAttestationInformationVerification)(void * context, const AttestationInfo & info,
333 : AttestationVerificationResult result);
334 :
335 : /**
336 : * @brief Verify an attestation information payload against a DAC/PAI chain.
337 : *
338 : * @param[in] info All of the information required to verify the attestation.
339 : * @param[in] onCompletion Callback handler to provide Attestation Information Verification result to the caller of
340 : * VerifyAttestationInformation()
341 : */
342 : virtual void VerifyAttestationInformation(const AttestationInfo & info,
343 : Callback::Callback<OnAttestationInformationVerification> * onCompletion) = 0;
344 :
345 : /**
346 : * @brief Verify a CMS Signed Data signature against the CSA certificate of Subject Key Identifier that matches
347 : * the subjectKeyIdentifier field of cmsEnvelopeBuffer.
348 : *
349 : * @param[in] cmsEnvelopeBuffer A ByteSpan with a CMS signed message.
350 : * @param[out] certDeclBuffer A ByteSpan to hold the CD content extracted from the CMS signed message.
351 : *
352 : * @returns AttestationVerificationResult::kSuccess on success or another specific
353 : * value from AttestationVerificationResult enum on failure.
354 : */
355 : virtual AttestationVerificationResult ValidateCertificationDeclarationSignature(const ByteSpan & cmsEnvelopeBuffer,
356 : ByteSpan & certDeclBuffer) = 0;
357 :
358 : /**
359 : * @brief Verify a CMS Signed Data Payload against the Basic Information Cluster and DAC/PAI's Vendor and Product IDs
360 : *
361 : * @param[in] certDeclBuffer A ByteSpan with the Certification Declaration content.
362 : * @param[in] firmwareInfo A ByteSpan with the Firmware Information content.
363 : * @param[in] deviceInfo The device information
364 : *
365 : * @returns AttestationVerificationResult::kSuccess on success or another specific
366 : * value from AttestationVerificationResult enum on failure.
367 : */
368 : virtual AttestationVerificationResult ValidateCertificateDeclarationPayload(const ByteSpan & certDeclBuffer,
369 : const ByteSpan & firmwareInfo,
370 : const DeviceInfoForAttestation & deviceInfo) = 0;
371 :
372 : // TODO: Validate Firmware Information
373 :
374 : /**
375 : * @brief Verify an operational certificate signing request payload against the DAC's public key.
376 : *
377 : * @param[in] nocsrElementsBuffer Buffer containing CSR elements as per specifications section 11.22.5.6. NOCSR Elements.
378 : * @param[in] attestationChallengeBuffer Buffer containing the attestation challenge from the secure session
379 : * @param[in] attestationSignatureBuffer Buffer containing the signature portion of CSR Response
380 : * @param[in] dacPublicKey Public Key from the DAC's certificate received from device.
381 : * @param[in] csrNonce Buffer containing CSR nonce.
382 : */
383 : virtual CHIP_ERROR VerifyNodeOperationalCSRInformation(const ByteSpan & nocsrElementsBuffer,
384 : const ByteSpan & attestationChallengeBuffer,
385 : const ByteSpan & attestationSignatureBuffer,
386 : const Crypto::P256PublicKey & dacPublicKey,
387 : const ByteSpan & csrNonce) = 0;
388 :
389 : /**
390 : * @brief Get the trust store used for the attestation verifier.
391 : *
392 : * Returns nullptr if not supported. Be careful not to hold-on to the trust store
393 : * for too long. It is only expected to have same lifetime as the DeviceAttestationVerifier.
394 : *
395 : * @return a pointer to the trust store or nullptr if none is directly accessible.
396 : */
397 0 : virtual WellKnownKeysTrustStore * GetCertificationDeclarationTrustStore() { return nullptr; }
398 :
399 : void EnableCdTestKeySupport(bool enabled) { mEnableCdTestKeySupport = enabled; }
400 82 : bool IsCdTestKeySupported() const { return mEnableCdTestKeySupport; }
401 :
402 : protected:
403 : CHIP_ERROR ValidateAttestationSignature(const Crypto::P256PublicKey & pubkey, const ByteSpan & attestationElements,
404 : const ByteSpan & attestationChallenge, const Crypto::P256ECDSASignature & signature);
405 :
406 : // Default to support the "development" test key for legacy purposes (since the DefaultDACVerifier)
407 : // always supported development keys.
408 : bool mEnableCdTestKeySupport = true;
409 : };
410 :
411 : /**
412 : * Instance getter for the global DeviceAttestationVerifier.
413 : *
414 : * Callers have to externally synchronize usage of this function.
415 : *
416 : * @return The global device attestation verifier. Assume never null.
417 : */
418 : DeviceAttestationVerifier * GetDeviceAttestationVerifier();
419 :
420 : /**
421 : * Instance setter for the global DeviceAttestationVerifier.
422 : *
423 : * Callers have to externally synchronize usage of this function.
424 : *
425 : * If the `verifier` is nullptr, no change is done.
426 : *
427 : * @param[in] verifier the DeviceAttestationVerifier to start returning with the getter
428 : */
429 : void SetDeviceAttestationVerifier(DeviceAttestationVerifier * verifier);
430 :
431 : } // namespace Credentials
432 : } // namespace chip
|