Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021-2022 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 "DacOnlyPartialAttestationVerifier.h"
18 :
19 : #include <controller/OperationalCredentialsDelegate.h>
20 : #include <credentials/CHIPCert.h>
21 : #include <credentials/CertificationDeclaration.h>
22 : #include <credentials/DeviceAttestationConstructor.h>
23 : #include <credentials/DeviceAttestationVendorReserved.h>
24 : #include <crypto/CHIPCryptoPAL.h>
25 :
26 : #include <lib/core/CHIPError.h>
27 : #include <lib/support/CodeUtils.h>
28 : #include <lib/support/ScopedMemoryBuffer.h>
29 : #include <lib/support/Span.h>
30 :
31 : using namespace chip::Crypto;
32 :
33 : namespace chip {
34 : namespace Credentials {
35 :
36 : // As per specifications section 11.22.5.1. Constant RESP_MAX
37 : constexpr size_t kMaxResponseLength = 900;
38 :
39 : /**
40 : * The implementation should track DefaultDACVerifier::VerifyAttestationInformation but with the checks
41 : * disabled that are outlined at the top of DacOnlyPartialAttestationVerifier.h.
42 : */
43 15 : void PartialDACVerifier::VerifyAttestationInformation(const DeviceAttestationVerifier::AttestationInfo & info,
44 : Callback::Callback<OnAttestationInformationVerification> * onCompletion)
45 : {
46 : // The exit handler below dereferences onCompletion unconditionally; reject null here.
47 15 : VerifyOrReturn(onCompletion != nullptr);
48 :
49 14 : AttestationVerificationResult attestationError = AttestationVerificationResult::kSuccess;
50 :
51 14 : AttestationCertVidPid dacVidPid;
52 14 : AttestationCertVidPid paiVidPid;
53 14 : AttestationCertVidPid paaVidPid;
54 :
55 14 : DeviceInfoForAttestation deviceInfo{
56 14 : .vendorId = info.vendorId,
57 14 : .productId = info.productId,
58 14 : };
59 :
60 14 : VerifyOrExit(!info.attestationElementsBuffer.empty() && !info.attestationChallengeBuffer.empty() &&
61 : !info.attestationSignatureBuffer.empty() && !info.paiDerBuffer.empty() && !info.dacDerBuffer.empty() &&
62 : !info.attestationNonceBuffer.empty(),
63 : attestationError = AttestationVerificationResult::kInvalidArgument);
64 :
65 13 : VerifyOrExit(info.attestationElementsBuffer.size() <= kMaxResponseLength,
66 : attestationError = AttestationVerificationResult::kInvalidArgument);
67 :
68 : // match DAC and PAI VIDs
69 : {
70 24 : VerifyOrExit(ExtractVIDPIDFromX509Cert(info.dacDerBuffer, dacVidPid) == CHIP_NO_ERROR,
71 : attestationError = AttestationVerificationResult::kDacFormatInvalid);
72 20 : VerifyOrExit(ExtractVIDPIDFromX509Cert(info.paiDerBuffer, paiVidPid) == CHIP_NO_ERROR,
73 : attestationError = AttestationVerificationResult::kPaiFormatInvalid);
74 9 : VerifyOrExit(paiVidPid.mVendorId.HasValue() && paiVidPid.mVendorId == dacVidPid.mVendorId,
75 : attestationError = AttestationVerificationResult::kDacVendorIdMismatch);
76 8 : VerifyOrExit(dacVidPid.mProductId.HasValue(), attestationError = AttestationVerificationResult::kDacProductIdMismatch);
77 8 : if (paiVidPid.mProductId.HasValue())
78 : {
79 8 : VerifyOrExit(paiVidPid.mProductId == dacVidPid.mProductId,
80 : attestationError = AttestationVerificationResult::kDacProductIdMismatch);
81 : }
82 : }
83 :
84 : {
85 7 : P256PublicKey remoteManufacturerPubkey;
86 7 : P256ECDSASignature deviceSignature;
87 :
88 14 : VerifyOrExit(ExtractPubkeyFromX509Cert(info.dacDerBuffer, remoteManufacturerPubkey) == CHIP_NO_ERROR,
89 : attestationError = AttestationVerificationResult::kDacFormatInvalid);
90 :
91 : // Validate overall attestation signature on attestation information
92 : // SetLength will fail if signature doesn't fit
93 14 : VerifyOrExit(deviceSignature.SetLength(info.attestationSignatureBuffer.size()) == CHIP_NO_ERROR,
94 : attestationError = AttestationVerificationResult::kAttestationSignatureInvalidFormat);
95 6 : memcpy(deviceSignature.Bytes(), info.attestationSignatureBuffer.data(), info.attestationSignatureBuffer.size());
96 12 : VerifyOrExit(ValidateAttestationSignature(remoteManufacturerPubkey, info.attestationElementsBuffer,
97 : info.attestationChallengeBuffer, deviceSignature) == CHIP_NO_ERROR,
98 : attestationError = AttestationVerificationResult::kAttestationSignatureInvalid);
99 9 : }
100 :
101 : {
102 5 : MutableByteSpan akid(deviceInfo.paaSKID);
103 :
104 10 : VerifyOrExit(ExtractAKIDFromX509Cert(info.paiDerBuffer, akid) == CHIP_NO_ERROR,
105 : attestationError = AttestationVerificationResult::kPaiFormatInvalid);
106 :
107 5 : ChipLogProgress(Support, "PartialDACVerifier::CheckPAA skipping vid-scoped PAA check - PAARootStore disabled");
108 : }
109 :
110 : #if !defined(CURRENT_TIME_NOT_IMPLEMENTED)
111 10 : VerifyOrExit(IsCertificateValidAtCurrentTime(info.dacDerBuffer) == CHIP_NO_ERROR,
112 : attestationError = AttestationVerificationResult::kDacExpired);
113 : #endif
114 :
115 3 : ChipLogProgress(Support, "PartialDACVerifier::CheckCertChain skipping cert chain check - PAARootStore disabled");
116 :
117 : {
118 3 : ByteSpan certificationDeclarationSpan;
119 3 : ByteSpan attestationNonceSpan;
120 : uint32_t timestampDeconstructed;
121 3 : ByteSpan firmwareInfoSpan;
122 3 : DeviceAttestationVendorReservedDeconstructor vendorReserved;
123 3 : ByteSpan certificationDeclarationPayload;
124 :
125 3 : deviceInfo.dacVendorId = dacVidPid.mVendorId.Value();
126 3 : deviceInfo.dacProductId = dacVidPid.mProductId.Value();
127 3 : deviceInfo.paiVendorId = paiVidPid.mVendorId.Value();
128 3 : deviceInfo.paiProductId = paiVidPid.mProductId.ValueOr(0);
129 3 : deviceInfo.paaVendorId = paaVidPid.mVendorId.ValueOr(VendorId::NotSpecified);
130 :
131 3 : ChipLogProgress(
132 : Support,
133 : "PartialDACVerifier::VerifyAttestationInformation skipping PAA subject key id extraction - PAARootStore disabled");
134 :
135 8 : VerifyOrExit(DeconstructAttestationElements(info.attestationElementsBuffer, certificationDeclarationSpan,
136 : attestationNonceSpan, timestampDeconstructed, firmwareInfoSpan,
137 : vendorReserved) == CHIP_NO_ERROR,
138 : attestationError = AttestationVerificationResult::kAttestationElementsMalformed);
139 :
140 : // Verify that Nonce matches with what we sent
141 2 : VerifyOrExit(attestationNonceSpan.data_equal(info.attestationNonceBuffer),
142 : attestationError = AttestationVerificationResult::kAttestationNonceMismatch);
143 :
144 1 : ChipLogProgress(Support,
145 : "PartialDACVerifier::VerifyAttestationInformation skipping CD signature check - LocalCSAStore disabled");
146 2 : VerifyOrExit(CMS_ExtractCDContent(certificationDeclarationSpan, certificationDeclarationPayload) == CHIP_NO_ERROR,
147 : attestationError = AttestationVerificationResult::kPaaFormatInvalid);
148 :
149 0 : attestationError = ValidateCertificateDeclarationPayload(certificationDeclarationPayload, firmwareInfoSpan, deviceInfo);
150 0 : VerifyOrExit(attestationError == AttestationVerificationResult::kSuccess, attestationError = attestationError);
151 : }
152 :
153 14 : exit:
154 14 : onCompletion->mCall(onCompletion->mContext, info, attestationError);
155 : }
156 :
157 : } // namespace Credentials
158 : } // namespace chip
|