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 : #include "DeviceAttestationVerifier.h"
18 :
19 : #include <credentials/DeviceAttestationConstructor.h>
20 : #include <crypto/CHIPCryptoPAL.h>
21 : #include <lib/support/CHIPMem.h>
22 :
23 : using namespace chip::Crypto;
24 :
25 : namespace chip {
26 : namespace Credentials {
27 :
28 : namespace {
29 :
30 : // Version to have a default placeholder so the getter never
31 : // returns `nullptr` by default.
32 : class UnimplementedDACVerifier : public DeviceAttestationVerifier
33 : {
34 : public:
35 0 : void VerifyAttestationInformation(const AttestationInfo & info,
36 : Callback::Callback<OnAttestationInformationVerification> * onCompletion) override
37 : {
38 : (void) info;
39 : (void) onCompletion;
40 0 : }
41 :
42 1 : AttestationVerificationResult ValidateCertificationDeclarationSignature(const ByteSpan & cmsEnvelopeBuffer,
43 : ByteSpan & certDeclBuffer) override
44 : {
45 : (void) cmsEnvelopeBuffer;
46 : (void) certDeclBuffer;
47 1 : return AttestationVerificationResult::kNotImplemented;
48 : }
49 :
50 0 : AttestationVerificationResult ValidateCertificateDeclarationPayload(const ByteSpan & certDeclBuffer,
51 : const ByteSpan & firmwareInfo,
52 : const DeviceInfoForAttestation & deviceInfo) override
53 : {
54 : (void) certDeclBuffer;
55 : (void) firmwareInfo;
56 : (void) deviceInfo;
57 0 : return AttestationVerificationResult::kNotImplemented;
58 : }
59 :
60 0 : CHIP_ERROR VerifyNodeOperationalCSRInformation(const ByteSpan & nocsrElementsBuffer,
61 : const ByteSpan & attestationChallengeBuffer,
62 : const ByteSpan & attestationSignatureBuffer,
63 : const Crypto::P256PublicKey & dacPublicKey, const ByteSpan & csrNonce) override
64 : {
65 : (void) nocsrElementsBuffer;
66 : (void) attestationChallengeBuffer;
67 : (void) attestationSignatureBuffer;
68 : (void) dacPublicKey;
69 : (void) csrNonce;
70 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
71 : }
72 :
73 0 : void CheckForRevokedDACChain(const AttestationInfo & info,
74 : Callback::Callback<OnAttestationInformationVerification> * onCompletion) override
75 : {
76 : (void) info;
77 : (void) onCompletion;
78 0 : VerifyOrDie(false);
79 : }
80 : };
81 :
82 : // Default to avoid nullptr on getter and cleanly handle new products/clients before
83 : // they provide their own.
84 : UnimplementedDACVerifier gDefaultDACVerifier;
85 :
86 : DeviceAttestationVerifier * gDacVerifier = &gDefaultDACVerifier;
87 :
88 : } // namespace
89 :
90 3 : const char * GetAttestationResultDescription(AttestationVerificationResult resultCode)
91 : {
92 3 : switch (resultCode)
93 : {
94 1 : case AttestationVerificationResult::kSuccess:
95 1 : return "Success";
96 0 : case AttestationVerificationResult::kPaaUntrusted:
97 0 : return "PAA is untrusted (OBSOLETE: consider using a different error)";
98 0 : case AttestationVerificationResult::kPaaNotFound:
99 0 : return "PAA not found in DCL and/or local PAA trust store";
100 0 : case AttestationVerificationResult::kPaaExpired:
101 0 : return "PAA is expired";
102 0 : case AttestationVerificationResult::kPaaSignatureInvalid:
103 0 : return "PAA signature is invalid";
104 0 : case AttestationVerificationResult::kPaaRevoked:
105 0 : return "PAA is revoked (consider removing from DCL or PAA trust store!)";
106 0 : case AttestationVerificationResult::kPaaFormatInvalid:
107 0 : return "PAA format is invalid";
108 0 : case AttestationVerificationResult::kPaaArgumentInvalid:
109 0 : return "PAA argument is invalid in some way according to X.509 backend";
110 0 : case AttestationVerificationResult::kPaiExpired:
111 0 : return "PAI is expired";
112 0 : case AttestationVerificationResult::kPaiSignatureInvalid:
113 0 : return "PAI signature is invalid";
114 0 : case AttestationVerificationResult::kPaiRevoked:
115 0 : return "PAI is revoked";
116 0 : case AttestationVerificationResult::kPaiFormatInvalid:
117 0 : return "PAI format is invalid";
118 0 : case AttestationVerificationResult::kPaiArgumentInvalid:
119 0 : return "PAI argument is invalid in some way according to X.509 backend";
120 0 : case AttestationVerificationResult::kPaiVendorIdMismatch:
121 0 : return "PAI vendor ID mismatch (did not match VID present in PAA)";
122 0 : case AttestationVerificationResult::kPaiAuthorityNotFound:
123 0 : return "PAI authority not found (OBSOLETE: consider using a different error)";
124 0 : case AttestationVerificationResult::kPaiMissing:
125 0 : return "PAI is missing/empty from attestation information data";
126 1 : case AttestationVerificationResult::kPaiAndDacRevoked:
127 1 : return "Both PAI and DAC are revoked";
128 0 : case AttestationVerificationResult::kDacExpired:
129 0 : return "DAC is expired";
130 0 : case AttestationVerificationResult::kDacSignatureInvalid:
131 0 : return "DAC signature is invalid";
132 0 : case AttestationVerificationResult::kDacRevoked:
133 0 : return "DAC is revoked";
134 0 : case AttestationVerificationResult::kDacFormatInvalid:
135 0 : return "DAC format is invalid";
136 0 : case AttestationVerificationResult::kDacArgumentInvalid:
137 0 : return "DAC is invalid in some way according to X.509 backend";
138 0 : case AttestationVerificationResult::kDacVendorIdMismatch:
139 0 : return "DAC vendor ID mismatch (either between DAC and PAI, or between DAC and Basic Information cluster)";
140 0 : case AttestationVerificationResult::kDacProductIdMismatch:
141 0 : return "DAC product ID mismatch (either between DAC and PAI, or between DAC and Basic Information cluster)";
142 0 : case AttestationVerificationResult::kDacAuthorityNotFound:
143 0 : return "DAC authority not found (OBSOLETE: consider using a different error)";
144 0 : case AttestationVerificationResult::kFirmwareInformationMismatch:
145 0 : return "Firmware information mismatch";
146 0 : case AttestationVerificationResult::kFirmwareInformationMissing:
147 0 : return "Firmware information missing";
148 0 : case AttestationVerificationResult::kAttestationSignatureInvalid:
149 0 : return "Attestation signature failed to validate against DAC subject public key";
150 0 : case AttestationVerificationResult::kAttestationElementsMalformed:
151 0 : return "Attestation elements payload is malformed";
152 0 : case AttestationVerificationResult::kAttestationNonceMismatch:
153 0 : return "Attestation nonce does not match the one from Attestation Request";
154 0 : case AttestationVerificationResult::kAttestationSignatureInvalidFormat:
155 0 : return "Attestation signature format is invalid (likely wrong signature algorithm in certificate)";
156 0 : case AttestationVerificationResult::kCertificationDeclarationNoKeyId:
157 0 : return "Certification declaration missing the required key ID in CMS envelope";
158 0 : case AttestationVerificationResult::kCertificationDeclarationNoCertificateFound:
159 0 : return "Could not find matching trusted verification certificate for the certification declaration's key ID";
160 0 : case AttestationVerificationResult::kCertificationDeclarationInvalidSignature:
161 0 : return "Certification declaration signature failed to validate against the verification certificate";
162 0 : case AttestationVerificationResult::kCertificationDeclarationInvalidFormat:
163 0 : return "Certification declaration format is invalid";
164 0 : case AttestationVerificationResult::kCertificationDeclarationInvalidVendorId:
165 0 : return "Certification declaration vendor ID failed to cross-reference with DAC and/or PAI and/or Basic Information cluster";
166 0 : case AttestationVerificationResult::kCertificationDeclarationInvalidProductId:
167 : return "Certification declaration product ID failed to cross-reference with DAC and/or PAI and/or Basic Information "
168 0 : "cluster";
169 0 : case AttestationVerificationResult::kCertificationDeclarationInvalidPAA:
170 0 : return "Certification declaration required a fixed allowed PAA which does not match the final PAA found";
171 0 : case AttestationVerificationResult::kNoMemory:
172 0 : return "Failed to allocate memory to process attestation verification";
173 0 : case AttestationVerificationResult::kInvalidArgument:
174 : return "Some unexpected invalid argument was provided internally to the device attestation procedure (likely malformed "
175 0 : "input data from candidate device)";
176 0 : case AttestationVerificationResult::kInternalError:
177 : return "An internal error arose in the device attestation procedure (likely malformed input data from candidate "
178 0 : "device)";
179 0 : case AttestationVerificationResult::kNotImplemented:
180 0 : return "Reached a critical-but-unimplemented part of the device attestation procedure!";
181 : }
182 :
183 1 : return "<AttestationVerificationResult does not have a description!>";
184 : }
185 :
186 95 : CHIP_ERROR DeviceAttestationVerifier::ValidateAttestationSignature(const P256PublicKey & pubkey,
187 : const ByteSpan & attestationElements,
188 : const ByteSpan & attestationChallenge,
189 : const P256ECDSASignature & signature)
190 : {
191 95 : Hash_SHA256_stream hashStream;
192 : uint8_t md[kSHA256_Hash_Length];
193 95 : MutableByteSpan messageDigestSpan(md);
194 :
195 95 : ReturnErrorOnFailure(hashStream.Begin());
196 95 : ReturnErrorOnFailure(hashStream.AddData(attestationElements));
197 95 : ReturnErrorOnFailure(hashStream.AddData(attestationChallenge));
198 95 : ReturnErrorOnFailure(hashStream.Finish(messageDigestSpan));
199 :
200 95 : ReturnErrorOnFailure(pubkey.ECDSA_validate_hash_signature(messageDigestSpan.data(), messageDigestSpan.size(), signature));
201 :
202 94 : return CHIP_NO_ERROR;
203 95 : }
204 :
205 3 : DeviceAttestationVerifier * GetDeviceAttestationVerifier()
206 : {
207 3 : return gDacVerifier;
208 : }
209 :
210 2 : void SetDeviceAttestationVerifier(DeviceAttestationVerifier * verifier)
211 : {
212 2 : if (verifier == nullptr)
213 : {
214 0 : return;
215 : }
216 :
217 2 : gDacVerifier = verifier;
218 : }
219 :
220 0 : static inline Platform::ScopedMemoryBufferWithSize<uint8_t> CopyByteSpanHelper(const ByteSpan & span_to_copy)
221 : {
222 0 : Platform::ScopedMemoryBufferWithSize<uint8_t> bufferCopy;
223 0 : if (bufferCopy.Alloc(span_to_copy.size()))
224 : {
225 0 : memcpy(bufferCopy.Get(), span_to_copy.data(), span_to_copy.size());
226 : }
227 0 : return bufferCopy;
228 : }
229 :
230 0 : DeviceAttestationVerifier::AttestationDeviceInfo::AttestationDeviceInfo(const AttestationInfo & attestationInfo) :
231 0 : mPaiDerBuffer(CopyByteSpanHelper(attestationInfo.paiDerBuffer)),
232 0 : mDacDerBuffer(CopyByteSpanHelper(attestationInfo.dacDerBuffer)), mBasicInformationVendorId(attestationInfo.vendorId),
233 0 : mBasicInformationProductId(attestationInfo.productId)
234 : {
235 0 : ByteSpan certificationDeclarationSpan;
236 0 : ByteSpan attestationNonceSpan;
237 : uint32_t timestampDeconstructed;
238 0 : ByteSpan firmwareInfoSpan;
239 0 : DeviceAttestationVendorReservedDeconstructor vendorReserved;
240 :
241 0 : if (DeconstructAttestationElements(attestationInfo.attestationElementsBuffer, certificationDeclarationSpan,
242 : attestationNonceSpan, timestampDeconstructed, firmwareInfoSpan,
243 0 : vendorReserved) == CHIP_NO_ERROR)
244 : {
245 0 : mCdBuffer = CopyByteSpanHelper(certificationDeclarationSpan);
246 : }
247 0 : }
248 :
249 : } // namespace Credentials
250 : } // namespace chip
|