xref: /aosp_15_r20/hardware/interfaces/identity/aidl/default/common/WritableIdentityCredential.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright 2019, The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker 
17*4d7e907cSAndroid Build Coastguard Worker #define LOG_TAG "WritableIdentityCredential"
18*4d7e907cSAndroid Build Coastguard Worker 
19*4d7e907cSAndroid Build Coastguard Worker #include "WritableIdentityCredential.h"
20*4d7e907cSAndroid Build Coastguard Worker 
21*4d7e907cSAndroid Build Coastguard Worker #include <android/hardware/identity/support/IdentityCredentialSupport.h>
22*4d7e907cSAndroid Build Coastguard Worker 
23*4d7e907cSAndroid Build Coastguard Worker #include <android-base/logging.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
25*4d7e907cSAndroid Build Coastguard Worker 
26*4d7e907cSAndroid Build Coastguard Worker #include <cppbor.h>
27*4d7e907cSAndroid Build Coastguard Worker #include <cppbor_parse.h>
28*4d7e907cSAndroid Build Coastguard Worker 
29*4d7e907cSAndroid Build Coastguard Worker #include <utility>
30*4d7e907cSAndroid Build Coastguard Worker 
31*4d7e907cSAndroid Build Coastguard Worker #include "IdentityCredentialStore.h"
32*4d7e907cSAndroid Build Coastguard Worker 
33*4d7e907cSAndroid Build Coastguard Worker #include "FakeSecureHardwareProxy.h"
34*4d7e907cSAndroid Build Coastguard Worker 
35*4d7e907cSAndroid Build Coastguard Worker namespace aidl::android::hardware::identity {
36*4d7e907cSAndroid Build Coastguard Worker 
37*4d7e907cSAndroid Build Coastguard Worker using ::android::base::StringPrintf;
38*4d7e907cSAndroid Build Coastguard Worker using ::std::optional;
39*4d7e907cSAndroid Build Coastguard Worker using namespace ::android::hardware::identity;
40*4d7e907cSAndroid Build Coastguard Worker 
initialize()41*4d7e907cSAndroid Build Coastguard Worker bool WritableIdentityCredential::initialize() {
42*4d7e907cSAndroid Build Coastguard Worker     if (!hwProxy_->initialize(testCredential_)) {
43*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "hwProxy->initialize() failed";
44*4d7e907cSAndroid Build Coastguard Worker         return false;
45*4d7e907cSAndroid Build Coastguard Worker     }
46*4d7e907cSAndroid Build Coastguard Worker     startPersonalizationCalled_ = false;
47*4d7e907cSAndroid Build Coastguard Worker     firstEntry_ = true;
48*4d7e907cSAndroid Build Coastguard Worker 
49*4d7e907cSAndroid Build Coastguard Worker     return true;
50*4d7e907cSAndroid Build Coastguard Worker }
51*4d7e907cSAndroid Build Coastguard Worker 
52*4d7e907cSAndroid Build Coastguard Worker // Used when updating a credential. Returns false on failure.
initializeForUpdate(const vector<uint8_t> & encryptedCredentialKeys)53*4d7e907cSAndroid Build Coastguard Worker bool WritableIdentityCredential::initializeForUpdate(
54*4d7e907cSAndroid Build Coastguard Worker         const vector<uint8_t>& encryptedCredentialKeys) {
55*4d7e907cSAndroid Build Coastguard Worker     if (!hwProxy_->initializeForUpdate(testCredential_, docType_, encryptedCredentialKeys)) {
56*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "hwProxy->initializeForUpdate() failed";
57*4d7e907cSAndroid Build Coastguard Worker         return false;
58*4d7e907cSAndroid Build Coastguard Worker     }
59*4d7e907cSAndroid Build Coastguard Worker     startPersonalizationCalled_ = false;
60*4d7e907cSAndroid Build Coastguard Worker     firstEntry_ = true;
61*4d7e907cSAndroid Build Coastguard Worker 
62*4d7e907cSAndroid Build Coastguard Worker     return true;
63*4d7e907cSAndroid Build Coastguard Worker }
64*4d7e907cSAndroid Build Coastguard Worker 
~WritableIdentityCredential()65*4d7e907cSAndroid Build Coastguard Worker WritableIdentityCredential::~WritableIdentityCredential() {}
66*4d7e907cSAndroid Build Coastguard Worker 
getAttestationCertificate(const vector<uint8_t> & attestationApplicationId,const vector<uint8_t> & attestationChallenge,vector<Certificate> * outCertificateChain)67*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate(
68*4d7e907cSAndroid Build Coastguard Worker         const vector<uint8_t>& attestationApplicationId,
69*4d7e907cSAndroid Build Coastguard Worker         const vector<uint8_t>& attestationChallenge, vector<Certificate>* outCertificateChain) {
70*4d7e907cSAndroid Build Coastguard Worker     if (getAttestationCertificateAlreadyCalled_) {
71*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
72*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED,
73*4d7e907cSAndroid Build Coastguard Worker                 "Error attestation certificate previously generated"));
74*4d7e907cSAndroid Build Coastguard Worker     }
75*4d7e907cSAndroid Build Coastguard Worker     getAttestationCertificateAlreadyCalled_ = true;
76*4d7e907cSAndroid Build Coastguard Worker 
77*4d7e907cSAndroid Build Coastguard Worker     if (attestationChallenge.empty()) {
78*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
79*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA, "Challenge can not be empty"));
80*4d7e907cSAndroid Build Coastguard Worker     }
81*4d7e907cSAndroid Build Coastguard Worker 
82*4d7e907cSAndroid Build Coastguard Worker     optional<vector<uint8_t>> certChain;
83*4d7e907cSAndroid Build Coastguard Worker     if (attestationKeyBlob_ && attestationCertificateChain_) {
84*4d7e907cSAndroid Build Coastguard Worker         certChain = hwProxy_->createCredentialKeyUsingRkp(
85*4d7e907cSAndroid Build Coastguard Worker                 attestationChallenge, attestationApplicationId, *attestationKeyBlob_,
86*4d7e907cSAndroid Build Coastguard Worker                 attestationCertificateChain_->at(0));
87*4d7e907cSAndroid Build Coastguard Worker     } else {
88*4d7e907cSAndroid Build Coastguard Worker         certChain = hwProxy_->createCredentialKey(attestationChallenge, attestationApplicationId);
89*4d7e907cSAndroid Build Coastguard Worker     }
90*4d7e907cSAndroid Build Coastguard Worker 
91*4d7e907cSAndroid Build Coastguard Worker     if (!certChain) {
92*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
93*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED,
94*4d7e907cSAndroid Build Coastguard Worker                 "Error generating attestation certificate chain"));
95*4d7e907cSAndroid Build Coastguard Worker     }
96*4d7e907cSAndroid Build Coastguard Worker 
97*4d7e907cSAndroid Build Coastguard Worker     optional<vector<vector<uint8_t>>> certs = support::certificateChainSplit(certChain.value());
98*4d7e907cSAndroid Build Coastguard Worker     if (!certs) {
99*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
100*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED,
101*4d7e907cSAndroid Build Coastguard Worker                 "Error splitting chain into separate certificates"));
102*4d7e907cSAndroid Build Coastguard Worker     }
103*4d7e907cSAndroid Build Coastguard Worker 
104*4d7e907cSAndroid Build Coastguard Worker     *outCertificateChain = vector<Certificate>();
105*4d7e907cSAndroid Build Coastguard Worker     for (vector<uint8_t>& cert : certs.value()) {
106*4d7e907cSAndroid Build Coastguard Worker         Certificate c;
107*4d7e907cSAndroid Build Coastguard Worker         c.encodedCertificate = std::move(cert);
108*4d7e907cSAndroid Build Coastguard Worker         outCertificateChain->push_back(std::move(c));
109*4d7e907cSAndroid Build Coastguard Worker     }
110*4d7e907cSAndroid Build Coastguard Worker 
111*4d7e907cSAndroid Build Coastguard Worker     for (const vector<uint8_t>& cert : *attestationCertificateChain_) {
112*4d7e907cSAndroid Build Coastguard Worker         Certificate c;
113*4d7e907cSAndroid Build Coastguard Worker         c.encodedCertificate = cert;
114*4d7e907cSAndroid Build Coastguard Worker         outCertificateChain->push_back(std::move(c));
115*4d7e907cSAndroid Build Coastguard Worker     }
116*4d7e907cSAndroid Build Coastguard Worker 
117*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
118*4d7e907cSAndroid Build Coastguard Worker }
119*4d7e907cSAndroid Build Coastguard Worker 
setExpectedProofOfProvisioningSize(int32_t expectedProofOfProvisioningSize)120*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus WritableIdentityCredential::setExpectedProofOfProvisioningSize(
121*4d7e907cSAndroid Build Coastguard Worker         int32_t expectedProofOfProvisioningSize) {
122*4d7e907cSAndroid Build Coastguard Worker     expectedProofOfProvisioningSize_ = expectedProofOfProvisioningSize;
123*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
124*4d7e907cSAndroid Build Coastguard Worker }
125*4d7e907cSAndroid Build Coastguard Worker 
startPersonalization(int32_t accessControlProfileCount,const vector<int32_t> & entryCounts)126*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus WritableIdentityCredential::startPersonalization(
127*4d7e907cSAndroid Build Coastguard Worker         int32_t accessControlProfileCount, const vector<int32_t>& entryCounts) {
128*4d7e907cSAndroid Build Coastguard Worker     if (startPersonalizationCalled_) {
129*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
130*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED, "startPersonalization called already"));
131*4d7e907cSAndroid Build Coastguard Worker     }
132*4d7e907cSAndroid Build Coastguard Worker     startPersonalizationCalled_ = true;
133*4d7e907cSAndroid Build Coastguard Worker 
134*4d7e907cSAndroid Build Coastguard Worker     numAccessControlProfileRemaining_ = accessControlProfileCount;
135*4d7e907cSAndroid Build Coastguard Worker     remainingEntryCounts_ = entryCounts;
136*4d7e907cSAndroid Build Coastguard Worker     entryNameSpace_ = "";
137*4d7e907cSAndroid Build Coastguard Worker 
138*4d7e907cSAndroid Build Coastguard Worker     signedDataAccessControlProfiles_ = cppbor::Array();
139*4d7e907cSAndroid Build Coastguard Worker     signedDataNamespaces_ = cppbor::Map();
140*4d7e907cSAndroid Build Coastguard Worker     signedDataCurrentNamespace_ = cppbor::Array();
141*4d7e907cSAndroid Build Coastguard Worker 
142*4d7e907cSAndroid Build Coastguard Worker     if (!hwProxy_->startPersonalization(accessControlProfileCount, entryCounts, docType_,
143*4d7e907cSAndroid Build Coastguard Worker                                         expectedProofOfProvisioningSize_)) {
144*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
145*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED, "eicStartPersonalization"));
146*4d7e907cSAndroid Build Coastguard Worker     }
147*4d7e907cSAndroid Build Coastguard Worker 
148*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
149*4d7e907cSAndroid Build Coastguard Worker }
150*4d7e907cSAndroid Build Coastguard Worker 
addAccessControlProfile(int32_t id,const Certificate & readerCertificate,bool userAuthenticationRequired,int64_t timeoutMillis,int64_t secureUserId,SecureAccessControlProfile * outSecureAccessControlProfile)151*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus WritableIdentityCredential::addAccessControlProfile(
152*4d7e907cSAndroid Build Coastguard Worker         int32_t id, const Certificate& readerCertificate, bool userAuthenticationRequired,
153*4d7e907cSAndroid Build Coastguard Worker         int64_t timeoutMillis, int64_t secureUserId,
154*4d7e907cSAndroid Build Coastguard Worker         SecureAccessControlProfile* outSecureAccessControlProfile) {
155*4d7e907cSAndroid Build Coastguard Worker     if (numAccessControlProfileRemaining_ == 0) {
156*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
157*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA,
158*4d7e907cSAndroid Build Coastguard Worker                 "numAccessControlProfileRemaining_ is 0 and expected non-zero"));
159*4d7e907cSAndroid Build Coastguard Worker     }
160*4d7e907cSAndroid Build Coastguard Worker 
161*4d7e907cSAndroid Build Coastguard Worker     if (accessControlProfileIds_.find(id) != accessControlProfileIds_.end()) {
162*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
163*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA,
164*4d7e907cSAndroid Build Coastguard Worker                 "Access Control Profile id must be unique"));
165*4d7e907cSAndroid Build Coastguard Worker     }
166*4d7e907cSAndroid Build Coastguard Worker     accessControlProfileIds_.insert(id);
167*4d7e907cSAndroid Build Coastguard Worker 
168*4d7e907cSAndroid Build Coastguard Worker     if (id < 0 || id >= 32) {
169*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
170*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA,
171*4d7e907cSAndroid Build Coastguard Worker                 "Access Control Profile id must be non-negative and less than 32"));
172*4d7e907cSAndroid Build Coastguard Worker     }
173*4d7e907cSAndroid Build Coastguard Worker 
174*4d7e907cSAndroid Build Coastguard Worker     // Spec requires if |userAuthenticationRequired| is false, then |timeoutMillis| must also
175*4d7e907cSAndroid Build Coastguard Worker     // be zero.
176*4d7e907cSAndroid Build Coastguard Worker     if (!userAuthenticationRequired && timeoutMillis != 0) {
177*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
178*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA,
179*4d7e907cSAndroid Build Coastguard Worker                 "userAuthenticationRequired is false but timeout is non-zero"));
180*4d7e907cSAndroid Build Coastguard Worker     }
181*4d7e907cSAndroid Build Coastguard Worker 
182*4d7e907cSAndroid Build Coastguard Worker     optional<vector<uint8_t>> mac = hwProxy_->addAccessControlProfile(
183*4d7e907cSAndroid Build Coastguard Worker             id, readerCertificate.encodedCertificate, userAuthenticationRequired, timeoutMillis,
184*4d7e907cSAndroid Build Coastguard Worker             secureUserId);
185*4d7e907cSAndroid Build Coastguard Worker     if (!mac) {
186*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
187*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED, "eicAddAccessControlProfile"));
188*4d7e907cSAndroid Build Coastguard Worker     }
189*4d7e907cSAndroid Build Coastguard Worker 
190*4d7e907cSAndroid Build Coastguard Worker     SecureAccessControlProfile profile;
191*4d7e907cSAndroid Build Coastguard Worker     profile.id = id;
192*4d7e907cSAndroid Build Coastguard Worker     profile.readerCertificate = readerCertificate;
193*4d7e907cSAndroid Build Coastguard Worker     profile.userAuthenticationRequired = userAuthenticationRequired;
194*4d7e907cSAndroid Build Coastguard Worker     profile.timeoutMillis = timeoutMillis;
195*4d7e907cSAndroid Build Coastguard Worker     profile.secureUserId = secureUserId;
196*4d7e907cSAndroid Build Coastguard Worker     profile.mac = mac.value();
197*4d7e907cSAndroid Build Coastguard Worker     cppbor::Map profileMap;
198*4d7e907cSAndroid Build Coastguard Worker     profileMap.add("id", profile.id);
199*4d7e907cSAndroid Build Coastguard Worker     if (profile.readerCertificate.encodedCertificate.size() > 0) {
200*4d7e907cSAndroid Build Coastguard Worker         profileMap.add("readerCertificate",
201*4d7e907cSAndroid Build Coastguard Worker                        cppbor::Bstr(profile.readerCertificate.encodedCertificate));
202*4d7e907cSAndroid Build Coastguard Worker     }
203*4d7e907cSAndroid Build Coastguard Worker     if (profile.userAuthenticationRequired) {
204*4d7e907cSAndroid Build Coastguard Worker         profileMap.add("userAuthenticationRequired", profile.userAuthenticationRequired);
205*4d7e907cSAndroid Build Coastguard Worker         profileMap.add("timeoutMillis", profile.timeoutMillis);
206*4d7e907cSAndroid Build Coastguard Worker     }
207*4d7e907cSAndroid Build Coastguard Worker     signedDataAccessControlProfiles_.add(std::move(profileMap));
208*4d7e907cSAndroid Build Coastguard Worker 
209*4d7e907cSAndroid Build Coastguard Worker     numAccessControlProfileRemaining_--;
210*4d7e907cSAndroid Build Coastguard Worker 
211*4d7e907cSAndroid Build Coastguard Worker     *outSecureAccessControlProfile = profile;
212*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
213*4d7e907cSAndroid Build Coastguard Worker }
214*4d7e907cSAndroid Build Coastguard Worker 
beginAddEntry(const vector<int32_t> & accessControlProfileIds,const string & nameSpace,const string & name,int32_t entrySize)215*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus WritableIdentityCredential::beginAddEntry(
216*4d7e907cSAndroid Build Coastguard Worker         const vector<int32_t>& accessControlProfileIds, const string& nameSpace, const string& name,
217*4d7e907cSAndroid Build Coastguard Worker         int32_t entrySize) {
218*4d7e907cSAndroid Build Coastguard Worker     if (numAccessControlProfileRemaining_ != 0) {
219*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "numAccessControlProfileRemaining_ is " << numAccessControlProfileRemaining_
220*4d7e907cSAndroid Build Coastguard Worker                    << " and expected zero";
221*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
222*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA,
223*4d7e907cSAndroid Build Coastguard Worker                 "numAccessControlProfileRemaining_ is not zero"));
224*4d7e907cSAndroid Build Coastguard Worker     }
225*4d7e907cSAndroid Build Coastguard Worker 
226*4d7e907cSAndroid Build Coastguard Worker     // Ensure passed-in profile ids reference valid access control profiles
227*4d7e907cSAndroid Build Coastguard Worker     for (const int32_t id : accessControlProfileIds) {
228*4d7e907cSAndroid Build Coastguard Worker         if (accessControlProfileIds_.find(id) == accessControlProfileIds_.end()) {
229*4d7e907cSAndroid Build Coastguard Worker             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
230*4d7e907cSAndroid Build Coastguard Worker                     IIdentityCredentialStore::STATUS_INVALID_DATA,
231*4d7e907cSAndroid Build Coastguard Worker                     "An id in accessControlProfileIds references non-existing ACP"));
232*4d7e907cSAndroid Build Coastguard Worker         }
233*4d7e907cSAndroid Build Coastguard Worker     }
234*4d7e907cSAndroid Build Coastguard Worker 
235*4d7e907cSAndroid Build Coastguard Worker     if (remainingEntryCounts_.size() == 0) {
236*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
237*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA, "No more namespaces to add to"));
238*4d7e907cSAndroid Build Coastguard Worker     }
239*4d7e907cSAndroid Build Coastguard Worker 
240*4d7e907cSAndroid Build Coastguard Worker     // Handle initial beginEntry() call.
241*4d7e907cSAndroid Build Coastguard Worker     if (firstEntry_) {
242*4d7e907cSAndroid Build Coastguard Worker         firstEntry_ = false;
243*4d7e907cSAndroid Build Coastguard Worker         entryNameSpace_ = nameSpace;
244*4d7e907cSAndroid Build Coastguard Worker         allNameSpaces_.insert(nameSpace);
245*4d7e907cSAndroid Build Coastguard Worker     }
246*4d7e907cSAndroid Build Coastguard Worker 
247*4d7e907cSAndroid Build Coastguard Worker     // If the namespace changed...
248*4d7e907cSAndroid Build Coastguard Worker     if (nameSpace != entryNameSpace_) {
249*4d7e907cSAndroid Build Coastguard Worker         if (allNameSpaces_.find(nameSpace) != allNameSpaces_.end()) {
250*4d7e907cSAndroid Build Coastguard Worker             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
251*4d7e907cSAndroid Build Coastguard Worker                     IIdentityCredentialStore::STATUS_INVALID_DATA,
252*4d7e907cSAndroid Build Coastguard Worker                     "Name space cannot be added in interleaving fashion"));
253*4d7e907cSAndroid Build Coastguard Worker         }
254*4d7e907cSAndroid Build Coastguard Worker 
255*4d7e907cSAndroid Build Coastguard Worker         // Then check that all entries in the previous namespace have been added..
256*4d7e907cSAndroid Build Coastguard Worker         if (remainingEntryCounts_[0] != 0) {
257*4d7e907cSAndroid Build Coastguard Worker             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
258*4d7e907cSAndroid Build Coastguard Worker                     IIdentityCredentialStore::STATUS_INVALID_DATA,
259*4d7e907cSAndroid Build Coastguard Worker                     "New namespace but a non-zero number of entries remain to be added"));
260*4d7e907cSAndroid Build Coastguard Worker         }
261*4d7e907cSAndroid Build Coastguard Worker         remainingEntryCounts_.erase(remainingEntryCounts_.begin());
262*4d7e907cSAndroid Build Coastguard Worker         remainingEntryCounts_[0] -= 1;
263*4d7e907cSAndroid Build Coastguard Worker         allNameSpaces_.insert(nameSpace);
264*4d7e907cSAndroid Build Coastguard Worker 
265*4d7e907cSAndroid Build Coastguard Worker         if (signedDataCurrentNamespace_.size() > 0) {
266*4d7e907cSAndroid Build Coastguard Worker             signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_));
267*4d7e907cSAndroid Build Coastguard Worker             signedDataCurrentNamespace_ = cppbor::Array();
268*4d7e907cSAndroid Build Coastguard Worker         }
269*4d7e907cSAndroid Build Coastguard Worker     } else {
270*4d7e907cSAndroid Build Coastguard Worker         // Same namespace...
271*4d7e907cSAndroid Build Coastguard Worker         if (remainingEntryCounts_[0] == 0) {
272*4d7e907cSAndroid Build Coastguard Worker             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
273*4d7e907cSAndroid Build Coastguard Worker                     IIdentityCredentialStore::STATUS_INVALID_DATA,
274*4d7e907cSAndroid Build Coastguard Worker                     "Same namespace but no entries remain to be added"));
275*4d7e907cSAndroid Build Coastguard Worker         }
276*4d7e907cSAndroid Build Coastguard Worker         remainingEntryCounts_[0] -= 1;
277*4d7e907cSAndroid Build Coastguard Worker     }
278*4d7e907cSAndroid Build Coastguard Worker 
279*4d7e907cSAndroid Build Coastguard Worker     entryRemainingBytes_ = entrySize;
280*4d7e907cSAndroid Build Coastguard Worker     entryNameSpace_ = nameSpace;
281*4d7e907cSAndroid Build Coastguard Worker     entryName_ = name;
282*4d7e907cSAndroid Build Coastguard Worker     entryAccessControlProfileIds_ = accessControlProfileIds;
283*4d7e907cSAndroid Build Coastguard Worker     entryBytes_.resize(0);
284*4d7e907cSAndroid Build Coastguard Worker     // LOG(INFO) << "name=" << name << " entrySize=" << entrySize;
285*4d7e907cSAndroid Build Coastguard Worker 
286*4d7e907cSAndroid Build Coastguard Worker     if (!hwProxy_->beginAddEntry(accessControlProfileIds, nameSpace, name, entrySize)) {
287*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
288*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED, "eicBeginAddEntry"));
289*4d7e907cSAndroid Build Coastguard Worker     }
290*4d7e907cSAndroid Build Coastguard Worker 
291*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
292*4d7e907cSAndroid Build Coastguard Worker }
293*4d7e907cSAndroid Build Coastguard Worker 
addEntryValue(const vector<uint8_t> & content,vector<uint8_t> * outEncryptedContent)294*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus WritableIdentityCredential::addEntryValue(const vector<uint8_t>& content,
295*4d7e907cSAndroid Build Coastguard Worker                                                              vector<uint8_t>* outEncryptedContent) {
296*4d7e907cSAndroid Build Coastguard Worker     size_t contentSize = content.size();
297*4d7e907cSAndroid Build Coastguard Worker 
298*4d7e907cSAndroid Build Coastguard Worker     if (contentSize > IdentityCredentialStore::kGcmChunkSize) {
299*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
300*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA,
301*4d7e907cSAndroid Build Coastguard Worker                 "Passed in chunk of is bigger than kGcmChunkSize"));
302*4d7e907cSAndroid Build Coastguard Worker     }
303*4d7e907cSAndroid Build Coastguard Worker     if (contentSize > entryRemainingBytes_) {
304*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
305*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA,
306*4d7e907cSAndroid Build Coastguard Worker                 "Passed in chunk is bigger than remaining space"));
307*4d7e907cSAndroid Build Coastguard Worker     }
308*4d7e907cSAndroid Build Coastguard Worker 
309*4d7e907cSAndroid Build Coastguard Worker     entryBytes_.insert(entryBytes_.end(), content.begin(), content.end());
310*4d7e907cSAndroid Build Coastguard Worker     entryRemainingBytes_ -= contentSize;
311*4d7e907cSAndroid Build Coastguard Worker     if (entryRemainingBytes_ > 0) {
312*4d7e907cSAndroid Build Coastguard Worker         if (contentSize != IdentityCredentialStore::kGcmChunkSize) {
313*4d7e907cSAndroid Build Coastguard Worker             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
314*4d7e907cSAndroid Build Coastguard Worker                     IIdentityCredentialStore::STATUS_INVALID_DATA,
315*4d7e907cSAndroid Build Coastguard Worker                     "Retrieved non-final chunk which isn't kGcmChunkSize"));
316*4d7e907cSAndroid Build Coastguard Worker         }
317*4d7e907cSAndroid Build Coastguard Worker     }
318*4d7e907cSAndroid Build Coastguard Worker 
319*4d7e907cSAndroid Build Coastguard Worker     optional<vector<uint8_t>> encryptedContent = hwProxy_->addEntryValue(
320*4d7e907cSAndroid Build Coastguard Worker             entryAccessControlProfileIds_, entryNameSpace_, entryName_, content);
321*4d7e907cSAndroid Build Coastguard Worker     if (!encryptedContent) {
322*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
323*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED, "eicAddEntryValue"));
324*4d7e907cSAndroid Build Coastguard Worker     }
325*4d7e907cSAndroid Build Coastguard Worker 
326*4d7e907cSAndroid Build Coastguard Worker     if (entryRemainingBytes_ == 0) {
327*4d7e907cSAndroid Build Coastguard Worker         // TODO: ideally do do this without parsing the data (but still validate data is valid
328*4d7e907cSAndroid Build Coastguard Worker         // CBOR).
329*4d7e907cSAndroid Build Coastguard Worker         auto [item, _, message] = cppbor::parse(entryBytes_);
330*4d7e907cSAndroid Build Coastguard Worker         if (item == nullptr) {
331*4d7e907cSAndroid Build Coastguard Worker             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
332*4d7e907cSAndroid Build Coastguard Worker                     IIdentityCredentialStore::STATUS_INVALID_DATA, "Data is not valid CBOR"));
333*4d7e907cSAndroid Build Coastguard Worker         }
334*4d7e907cSAndroid Build Coastguard Worker         cppbor::Map entryMap;
335*4d7e907cSAndroid Build Coastguard Worker         entryMap.add("name", entryName_);
336*4d7e907cSAndroid Build Coastguard Worker         entryMap.add("value", std::move(item));
337*4d7e907cSAndroid Build Coastguard Worker         cppbor::Array profileIdArray;
338*4d7e907cSAndroid Build Coastguard Worker         for (auto id : entryAccessControlProfileIds_) {
339*4d7e907cSAndroid Build Coastguard Worker             profileIdArray.add(id);
340*4d7e907cSAndroid Build Coastguard Worker         }
341*4d7e907cSAndroid Build Coastguard Worker         entryMap.add("accessControlProfiles", std::move(profileIdArray));
342*4d7e907cSAndroid Build Coastguard Worker         signedDataCurrentNamespace_.add(std::move(entryMap));
343*4d7e907cSAndroid Build Coastguard Worker     }
344*4d7e907cSAndroid Build Coastguard Worker 
345*4d7e907cSAndroid Build Coastguard Worker     *outEncryptedContent = encryptedContent.value();
346*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
347*4d7e907cSAndroid Build Coastguard Worker }
348*4d7e907cSAndroid Build Coastguard Worker 
finishAddingEntries(vector<uint8_t> * outCredentialData,vector<uint8_t> * outProofOfProvisioningSignature)349*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus WritableIdentityCredential::finishAddingEntries(
350*4d7e907cSAndroid Build Coastguard Worker         vector<uint8_t>* outCredentialData, vector<uint8_t>* outProofOfProvisioningSignature) {
351*4d7e907cSAndroid Build Coastguard Worker     if (numAccessControlProfileRemaining_ != 0) {
352*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
353*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA,
354*4d7e907cSAndroid Build Coastguard Worker                 "numAccessControlProfileRemaining_ is not 0 and expected zero"));
355*4d7e907cSAndroid Build Coastguard Worker     }
356*4d7e907cSAndroid Build Coastguard Worker 
357*4d7e907cSAndroid Build Coastguard Worker     if (remainingEntryCounts_.size() > 1 || remainingEntryCounts_[0] != 0) {
358*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
359*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA,
360*4d7e907cSAndroid Build Coastguard Worker                 "More entry spaces remain than startPersonalization configured"));
361*4d7e907cSAndroid Build Coastguard Worker     }
362*4d7e907cSAndroid Build Coastguard Worker 
363*4d7e907cSAndroid Build Coastguard Worker     if (signedDataCurrentNamespace_.size() > 0) {
364*4d7e907cSAndroid Build Coastguard Worker         signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_));
365*4d7e907cSAndroid Build Coastguard Worker     }
366*4d7e907cSAndroid Build Coastguard Worker     cppbor::Array popArray;
367*4d7e907cSAndroid Build Coastguard Worker     popArray.add("ProofOfProvisioning")
368*4d7e907cSAndroid Build Coastguard Worker             .add(docType_)
369*4d7e907cSAndroid Build Coastguard Worker             .add(std::move(signedDataAccessControlProfiles_))
370*4d7e907cSAndroid Build Coastguard Worker             .add(std::move(signedDataNamespaces_))
371*4d7e907cSAndroid Build Coastguard Worker             .add(testCredential_);
372*4d7e907cSAndroid Build Coastguard Worker     vector<uint8_t> encodedCbor = popArray.encode();
373*4d7e907cSAndroid Build Coastguard Worker 
374*4d7e907cSAndroid Build Coastguard Worker     if (encodedCbor.size() != expectedProofOfProvisioningSize_) {
375*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "CBOR for proofOfProvisioning is " << encodedCbor.size() << " bytes, "
376*4d7e907cSAndroid Build Coastguard Worker                    << "was expecting " << expectedProofOfProvisioningSize_;
377*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
378*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_INVALID_DATA,
379*4d7e907cSAndroid Build Coastguard Worker                 StringPrintf("Unexpected CBOR size %zd for proofOfProvisioning, was expecting %zd",
380*4d7e907cSAndroid Build Coastguard Worker                              encodedCbor.size(), expectedProofOfProvisioningSize_)
381*4d7e907cSAndroid Build Coastguard Worker                         .c_str()));
382*4d7e907cSAndroid Build Coastguard Worker     }
383*4d7e907cSAndroid Build Coastguard Worker 
384*4d7e907cSAndroid Build Coastguard Worker     optional<vector<uint8_t>> signatureOfToBeSigned = hwProxy_->finishAddingEntries();
385*4d7e907cSAndroid Build Coastguard Worker     if (!signatureOfToBeSigned) {
386*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
387*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED, "eicFinishAddingEntries"));
388*4d7e907cSAndroid Build Coastguard Worker     }
389*4d7e907cSAndroid Build Coastguard Worker 
390*4d7e907cSAndroid Build Coastguard Worker     optional<vector<uint8_t>> signature =
391*4d7e907cSAndroid Build Coastguard Worker             support::coseSignEcDsaWithSignature(signatureOfToBeSigned.value(),
392*4d7e907cSAndroid Build Coastguard Worker                                                 encodedCbor,  // data
393*4d7e907cSAndroid Build Coastguard Worker                                                 {});          // certificateChain
394*4d7e907cSAndroid Build Coastguard Worker     if (!signature) {
395*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
396*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED, "Error signing data"));
397*4d7e907cSAndroid Build Coastguard Worker     }
398*4d7e907cSAndroid Build Coastguard Worker 
399*4d7e907cSAndroid Build Coastguard Worker     optional<vector<uint8_t>> encryptedCredentialKeys = hwProxy_->finishGetCredentialData(docType_);
400*4d7e907cSAndroid Build Coastguard Worker     if (!encryptedCredentialKeys) {
401*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
402*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED,
403*4d7e907cSAndroid Build Coastguard Worker                 "Error generating encrypted CredentialKeys"));
404*4d7e907cSAndroid Build Coastguard Worker     }
405*4d7e907cSAndroid Build Coastguard Worker     cppbor::Array array;
406*4d7e907cSAndroid Build Coastguard Worker     array.add(docType_);
407*4d7e907cSAndroid Build Coastguard Worker     array.add(testCredential_);
408*4d7e907cSAndroid Build Coastguard Worker     array.add(encryptedCredentialKeys.value());
409*4d7e907cSAndroid Build Coastguard Worker     vector<uint8_t> credentialData = array.encode();
410*4d7e907cSAndroid Build Coastguard Worker 
411*4d7e907cSAndroid Build Coastguard Worker     *outCredentialData = credentialData;
412*4d7e907cSAndroid Build Coastguard Worker     *outProofOfProvisioningSignature = signature.value();
413*4d7e907cSAndroid Build Coastguard Worker     hwProxy_->shutdown();
414*4d7e907cSAndroid Build Coastguard Worker 
415*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
416*4d7e907cSAndroid Build Coastguard Worker }
417*4d7e907cSAndroid Build Coastguard Worker 
setRemotelyProvisionedAttestationKey(const vector<uint8_t> & attestationKeyBlob,const vector<uint8_t> & attestationCertificateChain)418*4d7e907cSAndroid Build Coastguard Worker ndk::ScopedAStatus WritableIdentityCredential::setRemotelyProvisionedAttestationKey(
419*4d7e907cSAndroid Build Coastguard Worker         const vector<uint8_t>& attestationKeyBlob,
420*4d7e907cSAndroid Build Coastguard Worker         const vector<uint8_t>& attestationCertificateChain) {
421*4d7e907cSAndroid Build Coastguard Worker     if (!hardwareInformation_.isRemoteKeyProvisioningSupported) {
422*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromExceptionCodeWithMessage(
423*4d7e907cSAndroid Build Coastguard Worker                 EX_UNSUPPORTED_OPERATION, "Remote key provisioning is not supported"));
424*4d7e907cSAndroid Build Coastguard Worker     }
425*4d7e907cSAndroid Build Coastguard Worker 
426*4d7e907cSAndroid Build Coastguard Worker     if (attestationKeyBlob.empty() || attestationCertificateChain.empty()) {
427*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
428*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED,
429*4d7e907cSAndroid Build Coastguard Worker                 "Empty data passed to setRemotlyProvisionedAttestationKey"));
430*4d7e907cSAndroid Build Coastguard Worker     }
431*4d7e907cSAndroid Build Coastguard Worker 
432*4d7e907cSAndroid Build Coastguard Worker     if (attestationKeyBlob_.has_value()) {
433*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
434*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED, "Attestation key already set"));
435*4d7e907cSAndroid Build Coastguard Worker     }
436*4d7e907cSAndroid Build Coastguard Worker 
437*4d7e907cSAndroid Build Coastguard Worker     optional<vector<vector<uint8_t>>> certs =
438*4d7e907cSAndroid Build Coastguard Worker             support::certificateChainSplit(attestationCertificateChain);
439*4d7e907cSAndroid Build Coastguard Worker     if (!certs) {
440*4d7e907cSAndroid Build Coastguard Worker         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
441*4d7e907cSAndroid Build Coastguard Worker                 IIdentityCredentialStore::STATUS_FAILED,
442*4d7e907cSAndroid Build Coastguard Worker                 "Error splitting chain into separate certificates"));
443*4d7e907cSAndroid Build Coastguard Worker     }
444*4d7e907cSAndroid Build Coastguard Worker 
445*4d7e907cSAndroid Build Coastguard Worker     attestationKeyBlob_ = attestationKeyBlob;
446*4d7e907cSAndroid Build Coastguard Worker     attestationCertificateChain_ = *certs;
447*4d7e907cSAndroid Build Coastguard Worker     return ndk::ScopedAStatus::ok();
448*4d7e907cSAndroid Build Coastguard Worker }
449*4d7e907cSAndroid Build Coastguard Worker 
450*4d7e907cSAndroid Build Coastguard Worker }  // namespace aidl::android::hardware::identity
451