blob: fea289b9efad3e3e9e9f2073166870de958bf374 [file] [log] [blame]
David Zeuthenc75ac312019-10-28 13:16:45 -04001/*
2 * Copyright 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "WritableIdentityCredential"
18
Selene Huang459cb802020-01-08 22:59:02 -080019#include "WritableIdentityCredential.h"
20#include "IdentityCredentialStore.h"
21
David Zeuthenc75ac312019-10-28 13:16:45 -040022#include <android/hardware/identity/support/IdentityCredentialSupport.h>
23
24#include <android-base/logging.h>
David Zeuthen28edb102020-04-28 18:54:55 -040025#include <android-base/stringprintf.h>
David Zeuthenc75ac312019-10-28 13:16:45 -040026
27#include <cppbor/cppbor.h>
28#include <cppbor/cppbor_parse.h>
29
Selene Huang459cb802020-01-08 22:59:02 -080030#include <utility>
31
David Zeuthen81603152020-02-11 22:04:24 -050032#include "IdentityCredentialStore.h"
33#include "Util.h"
34#include "WritableIdentityCredential.h"
35
36namespace aidl::android::hardware::identity {
David Zeuthenc75ac312019-10-28 13:16:45 -040037
David Zeuthen28edb102020-04-28 18:54:55 -040038using ::android::base::StringPrintf;
David Zeuthenc75ac312019-10-28 13:16:45 -040039using ::std::optional;
David Zeuthen81603152020-02-11 22:04:24 -050040using namespace ::android::hardware::identity;
41
42bool WritableIdentityCredential::initialize() {
David Zeuthen81603152020-02-11 22:04:24 -050043 optional<vector<uint8_t>> random = support::getRandom(16);
44 if (!random) {
45 LOG(ERROR) << "Error creating storageKey";
46 return false;
47 }
48 storageKey_ = random.value();
Selene Huang92b61d62020-03-04 02:24:16 -080049 startPersonalizationCalled_ = false;
50 firstEntry_ = true;
David Zeuthen81603152020-02-11 22:04:24 -050051
52 return true;
53}
54
Selene Huang459cb802020-01-08 22:59:02 -080055// This function generates the attestation certificate using the passed in
56// |attestationApplicationId| and |attestationChallenge|. It will generate an
57// attestation certificate with current time and expires one year from now. The
58// certificate shall contain all values as specified in hal.
David Zeuthen81603152020-02-11 22:04:24 -050059ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate(
Jooyung Han17be89b2020-02-21 21:17:06 +090060 const vector<uint8_t>& attestationApplicationId, //
61 const vector<uint8_t>& attestationChallenge, //
Selene Huang459cb802020-01-08 22:59:02 -080062 vector<Certificate>* outCertificateChain) {
63 if (!credentialPrivKey_.empty() || !credentialPubKey_.empty() || !certificateChain_.empty()) {
David Zeuthen81603152020-02-11 22:04:24 -050064 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
65 IIdentityCredentialStore::STATUS_FAILED,
Selene Huang459cb802020-01-08 22:59:02 -080066 "Error attestation certificate previously generated"));
David Zeuthen81603152020-02-11 22:04:24 -050067 }
David Zeuthenef739512020-06-03 13:24:52 -040068 if (attestationChallenge.empty()) {
69 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
70 IIdentityCredentialStore::STATUS_INVALID_DATA, "Challenge can not be empty"));
71 }
David Zeuthen81603152020-02-11 22:04:24 -050072
Selene Huang459cb802020-01-08 22:59:02 -080073 vector<uint8_t> challenge(attestationChallenge.begin(), attestationChallenge.end());
74 vector<uint8_t> appId(attestationApplicationId.begin(), attestationApplicationId.end());
75
76 optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> keyAttestationPair =
77 support::createEcKeyPairAndAttestation(challenge, appId);
78 if (!keyAttestationPair) {
79 LOG(ERROR) << "Error creating credentialKey and attestation";
David Zeuthen81603152020-02-11 22:04:24 -050080 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
81 IIdentityCredentialStore::STATUS_FAILED,
Selene Huang459cb802020-01-08 22:59:02 -080082 "Error creating credentialKey and attestation"));
David Zeuthen81603152020-02-11 22:04:24 -050083 }
84
Selene Huang459cb802020-01-08 22:59:02 -080085 vector<uint8_t> keyPair = keyAttestationPair.value().first;
86 certificateChain_ = keyAttestationPair.value().second;
David Zeuthen81603152020-02-11 22:04:24 -050087
Selene Huang459cb802020-01-08 22:59:02 -080088 optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair);
89 if (!pubKey) {
David Zeuthen81603152020-02-11 22:04:24 -050090 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
91 IIdentityCredentialStore::STATUS_FAILED,
Selene Huang459cb802020-01-08 22:59:02 -080092 "Error getting public part of credentialKey"));
David Zeuthen81603152020-02-11 22:04:24 -050093 }
Selene Huang459cb802020-01-08 22:59:02 -080094 credentialPubKey_ = pubKey.value();
David Zeuthen81603152020-02-11 22:04:24 -050095
Selene Huang459cb802020-01-08 22:59:02 -080096 optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair);
97 if (!privKey) {
David Zeuthen81603152020-02-11 22:04:24 -050098 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
99 IIdentityCredentialStore::STATUS_FAILED,
Selene Huang459cb802020-01-08 22:59:02 -0800100 "Error getting private part of credentialKey"));
David Zeuthen81603152020-02-11 22:04:24 -0500101 }
Selene Huang459cb802020-01-08 22:59:02 -0800102 credentialPrivKey_ = privKey.value();
David Zeuthen81603152020-02-11 22:04:24 -0500103
Selene Huang459cb802020-01-08 22:59:02 -0800104 // convert from vector<vector<uint8_t>>> to vector<Certificate>*
David Zeuthen81603152020-02-11 22:04:24 -0500105 *outCertificateChain = vector<Certificate>();
Selene Huang459cb802020-01-08 22:59:02 -0800106 for (const vector<uint8_t>& cert : certificateChain_) {
David Zeuthen81603152020-02-11 22:04:24 -0500107 Certificate c = Certificate();
Jooyung Han17be89b2020-02-21 21:17:06 +0900108 c.encodedCertificate = cert;
David Zeuthen81603152020-02-11 22:04:24 -0500109 outCertificateChain->push_back(std::move(c));
110 }
111 return ndk::ScopedAStatus::ok();
112}
113
David Zeuthen28edb102020-04-28 18:54:55 -0400114ndk::ScopedAStatus WritableIdentityCredential::setExpectedProofOfProvisioningSize(
115 int32_t expectedProofOfProvisioningSize) {
116 expectedProofOfProvisioningSize_ = expectedProofOfProvisioningSize;
117 return ndk::ScopedAStatus::ok();
118}
119
David Zeuthen81603152020-02-11 22:04:24 -0500120ndk::ScopedAStatus WritableIdentityCredential::startPersonalization(
121 int32_t accessControlProfileCount, const vector<int32_t>& entryCounts) {
Selene Huang92b61d62020-03-04 02:24:16 -0800122 if (startPersonalizationCalled_) {
123 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
124 IIdentityCredentialStore::STATUS_FAILED, "startPersonalization called already"));
125 }
126
127 startPersonalizationCalled_ = true;
David Zeuthen81603152020-02-11 22:04:24 -0500128 numAccessControlProfileRemaining_ = accessControlProfileCount;
129 remainingEntryCounts_ = entryCounts;
130 entryNameSpace_ = "";
131
132 signedDataAccessControlProfiles_ = cppbor::Array();
133 signedDataNamespaces_ = cppbor::Map();
134 signedDataCurrentNamespace_ = cppbor::Array();
135
136 return ndk::ScopedAStatus::ok();
137}
138
139ndk::ScopedAStatus WritableIdentityCredential::addAccessControlProfile(
140 int32_t id, const Certificate& readerCertificate, bool userAuthenticationRequired,
141 int64_t timeoutMillis, int64_t secureUserId,
142 SecureAccessControlProfile* outSecureAccessControlProfile) {
143 SecureAccessControlProfile profile;
144
145 if (numAccessControlProfileRemaining_ == 0) {
146 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
147 IIdentityCredentialStore::STATUS_INVALID_DATA,
148 "numAccessControlProfileRemaining_ is 0 and expected non-zero"));
149 }
150
Selene Huang92b61d62020-03-04 02:24:16 -0800151 if (accessControlProfileIds_.find(id) != accessControlProfileIds_.end()) {
152 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
153 IIdentityCredentialStore::STATUS_INVALID_DATA,
154 "Access Control Profile id must be unique"));
155 }
156 accessControlProfileIds_.insert(id);
157
David Zeuthena0796e92020-04-27 15:24:55 -0400158 if (id < 0 || id >= 32) {
159 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
160 IIdentityCredentialStore::STATUS_INVALID_DATA,
161 "Access Control Profile id must be non-negative and less than 32"));
162 }
163
David Zeuthen81603152020-02-11 22:04:24 -0500164 // Spec requires if |userAuthenticationRequired| is false, then |timeoutMillis| must also
165 // be zero.
166 if (!userAuthenticationRequired && timeoutMillis != 0) {
167 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
168 IIdentityCredentialStore::STATUS_INVALID_DATA,
169 "userAuthenticationRequired is false but timeout is non-zero"));
170 }
171
David Zeuthenef739512020-06-03 13:24:52 -0400172 // If |userAuthenticationRequired| is true, then |secureUserId| must be non-zero.
173 if (userAuthenticationRequired && secureUserId == 0) {
174 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
175 IIdentityCredentialStore::STATUS_INVALID_DATA,
176 "userAuthenticationRequired is true but secureUserId is zero"));
177 }
178
David Zeuthen81603152020-02-11 22:04:24 -0500179 profile.id = id;
180 profile.readerCertificate = readerCertificate;
181 profile.userAuthenticationRequired = userAuthenticationRequired;
182 profile.timeoutMillis = timeoutMillis;
183 profile.secureUserId = secureUserId;
184 optional<vector<uint8_t>> mac = secureAccessControlProfileCalcMac(profile, storageKey_);
185 if (!mac) {
186 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
187 IIdentityCredentialStore::STATUS_FAILED, "Error calculating MAC for profile"));
188 }
Jooyung Han17be89b2020-02-21 21:17:06 +0900189 profile.mac = mac.value();
David Zeuthen81603152020-02-11 22:04:24 -0500190
191 cppbor::Map profileMap;
192 profileMap.add("id", profile.id);
193 if (profile.readerCertificate.encodedCertificate.size() > 0) {
Jooyung Han17be89b2020-02-21 21:17:06 +0900194 profileMap.add("readerCertificate",
195 cppbor::Bstr(profile.readerCertificate.encodedCertificate));
David Zeuthen81603152020-02-11 22:04:24 -0500196 }
197 if (profile.userAuthenticationRequired) {
198 profileMap.add("userAuthenticationRequired", profile.userAuthenticationRequired);
199 profileMap.add("timeoutMillis", profile.timeoutMillis);
200 }
201 signedDataAccessControlProfiles_.add(std::move(profileMap));
202
203 numAccessControlProfileRemaining_--;
204
205 *outSecureAccessControlProfile = profile;
206 return ndk::ScopedAStatus::ok();
207}
208
209ndk::ScopedAStatus WritableIdentityCredential::beginAddEntry(
210 const vector<int32_t>& accessControlProfileIds, const string& nameSpace, const string& name,
211 int32_t entrySize) {
212 if (numAccessControlProfileRemaining_ != 0) {
213 LOG(ERROR) << "numAccessControlProfileRemaining_ is " << numAccessControlProfileRemaining_
214 << " and expected zero";
215 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
216 IIdentityCredentialStore::STATUS_INVALID_DATA,
217 "numAccessControlProfileRemaining_ is not zero"));
218 }
219
220 if (remainingEntryCounts_.size() == 0) {
221 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
222 IIdentityCredentialStore::STATUS_INVALID_DATA, "No more namespaces to add to"));
223 }
224
225 // Handle initial beginEntry() call.
Selene Huang92b61d62020-03-04 02:24:16 -0800226 if (firstEntry_) {
227 firstEntry_ = false;
David Zeuthen81603152020-02-11 22:04:24 -0500228 entryNameSpace_ = nameSpace;
Selene Huang92b61d62020-03-04 02:24:16 -0800229 allNameSpaces_.insert(nameSpace);
David Zeuthen81603152020-02-11 22:04:24 -0500230 }
231
232 // If the namespace changed...
233 if (nameSpace != entryNameSpace_) {
Selene Huang92b61d62020-03-04 02:24:16 -0800234 if (allNameSpaces_.find(nameSpace) != allNameSpaces_.end()) {
235 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
236 IIdentityCredentialStore::STATUS_INVALID_DATA,
237 "Name space cannot be added in interleaving fashion"));
238 }
239
David Zeuthen81603152020-02-11 22:04:24 -0500240 // Then check that all entries in the previous namespace have been added..
241 if (remainingEntryCounts_[0] != 0) {
242 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
243 IIdentityCredentialStore::STATUS_INVALID_DATA,
244 "New namespace but a non-zero number of entries remain to be added"));
245 }
246 remainingEntryCounts_.erase(remainingEntryCounts_.begin());
Selene Huang92b61d62020-03-04 02:24:16 -0800247 remainingEntryCounts_[0] -= 1;
248 allNameSpaces_.insert(nameSpace);
David Zeuthen81603152020-02-11 22:04:24 -0500249
250 if (signedDataCurrentNamespace_.size() > 0) {
251 signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_));
252 signedDataCurrentNamespace_ = cppbor::Array();
253 }
254 } else {
255 // Same namespace...
256 if (remainingEntryCounts_[0] == 0) {
257 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
258 IIdentityCredentialStore::STATUS_INVALID_DATA,
259 "Same namespace but no entries remain to be added"));
260 }
261 remainingEntryCounts_[0] -= 1;
262 }
263
264 entryAdditionalData_ = entryCreateAdditionalData(nameSpace, name, accessControlProfileIds);
265
266 entryRemainingBytes_ = entrySize;
267 entryNameSpace_ = nameSpace;
268 entryName_ = name;
269 entryAccessControlProfileIds_ = accessControlProfileIds;
270 entryBytes_.resize(0);
271 // LOG(INFO) << "name=" << name << " entrySize=" << entrySize;
272 return ndk::ScopedAStatus::ok();
273}
274
Jooyung Han17be89b2020-02-21 21:17:06 +0900275ndk::ScopedAStatus WritableIdentityCredential::addEntryValue(const vector<uint8_t>& content,
276 vector<uint8_t>* outEncryptedContent) {
David Zeuthen81603152020-02-11 22:04:24 -0500277 size_t contentSize = content.size();
278
279 if (contentSize > IdentityCredentialStore::kGcmChunkSize) {
280 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
281 IIdentityCredentialStore::STATUS_INVALID_DATA,
282 "Passed in chunk of is bigger than kGcmChunkSize"));
283 }
284 if (contentSize > entryRemainingBytes_) {
285 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
286 IIdentityCredentialStore::STATUS_INVALID_DATA,
287 "Passed in chunk is bigger than remaining space"));
288 }
289
290 entryBytes_.insert(entryBytes_.end(), content.begin(), content.end());
291 entryRemainingBytes_ -= contentSize;
292 if (entryRemainingBytes_ > 0) {
293 if (contentSize != IdentityCredentialStore::kGcmChunkSize) {
294 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
295 IIdentityCredentialStore::STATUS_INVALID_DATA,
296 "Retrieved non-final chunk which isn't kGcmChunkSize"));
297 }
298 }
299
300 optional<vector<uint8_t>> nonce = support::getRandom(12);
301 if (!nonce) {
302 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
303 IIdentityCredentialStore::STATUS_FAILED, "Error getting nonce"));
304 }
305 optional<vector<uint8_t>> encryptedContent =
306 support::encryptAes128Gcm(storageKey_, nonce.value(), content, entryAdditionalData_);
307 if (!encryptedContent) {
308 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
309 IIdentityCredentialStore::STATUS_FAILED, "Error encrypting content"));
310 }
311
312 if (entryRemainingBytes_ == 0) {
313 // TODO: ideally do do this without parsing the data (but still validate data is valid
314 // CBOR).
315 auto [item, _, message] = cppbor::parse(entryBytes_);
316 if (item == nullptr) {
317 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
318 IIdentityCredentialStore::STATUS_INVALID_DATA, "Data is not valid CBOR"));
319 }
320 cppbor::Map entryMap;
321 entryMap.add("name", entryName_);
322 entryMap.add("value", std::move(item));
323 cppbor::Array profileIdArray;
324 for (auto id : entryAccessControlProfileIds_) {
325 profileIdArray.add(id);
326 }
327 entryMap.add("accessControlProfiles", std::move(profileIdArray));
328 signedDataCurrentNamespace_.add(std::move(entryMap));
329 }
330
Jooyung Han17be89b2020-02-21 21:17:06 +0900331 *outEncryptedContent = encryptedContent.value();
David Zeuthen81603152020-02-11 22:04:24 -0500332 return ndk::ScopedAStatus::ok();
333}
David Zeuthenc75ac312019-10-28 13:16:45 -0400334
335// Writes CBOR-encoded structure to |credentialKeys| containing |storageKey| and
336// |credentialPrivKey|.
337static bool generateCredentialKeys(const vector<uint8_t>& storageKey,
338 const vector<uint8_t>& credentialPrivKey,
339 vector<uint8_t>& credentialKeys) {
340 if (storageKey.size() != 16) {
341 LOG(ERROR) << "Size of storageKey is not 16";
342 return false;
343 }
344
345 cppbor::Array array;
346 array.add(cppbor::Bstr(storageKey));
347 array.add(cppbor::Bstr(credentialPrivKey));
348 credentialKeys = array.encode();
349 return true;
350}
351
352// Writes CBOR-encoded structure to |credentialData| containing |docType|,
353// |testCredential| and |credentialKeys|. The latter element will be stored in
354// encrypted form, using |hardwareBoundKey| as the encryption key.
355bool generateCredentialData(const vector<uint8_t>& hardwareBoundKey, const string& docType,
356 bool testCredential, const vector<uint8_t>& credentialKeys,
357 vector<uint8_t>& credentialData) {
358 optional<vector<uint8_t>> nonce = support::getRandom(12);
359 if (!nonce) {
360 LOG(ERROR) << "Error getting random";
361 return false;
362 }
363 vector<uint8_t> docTypeAsVec(docType.begin(), docType.end());
364 optional<vector<uint8_t>> credentialBlob = support::encryptAes128Gcm(
365 hardwareBoundKey, nonce.value(), credentialKeys, docTypeAsVec);
366 if (!credentialBlob) {
367 LOG(ERROR) << "Error encrypting CredentialKeys blob";
368 return false;
369 }
370
371 cppbor::Array array;
372 array.add(docType);
373 array.add(testCredential);
374 array.add(cppbor::Bstr(credentialBlob.value()));
375 credentialData = array.encode();
376 return true;
377}
378
David Zeuthen81603152020-02-11 22:04:24 -0500379ndk::ScopedAStatus WritableIdentityCredential::finishAddingEntries(
Jooyung Han17be89b2020-02-21 21:17:06 +0900380 vector<uint8_t>* outCredentialData, vector<uint8_t>* outProofOfProvisioningSignature) {
Selene Huang92b61d62020-03-04 02:24:16 -0800381 if (numAccessControlProfileRemaining_ != 0) {
382 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
383 IIdentityCredentialStore::STATUS_INVALID_DATA,
384 "numAccessControlProfileRemaining_ is not 0 and expected zero"));
385 }
386
387 if (remainingEntryCounts_.size() > 1 || remainingEntryCounts_[0] != 0) {
388 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
389 IIdentityCredentialStore::STATUS_INVALID_DATA,
390 "More entry spaces remain than startPersonalization configured"));
391 }
392
David Zeuthenc75ac312019-10-28 13:16:45 -0400393 if (signedDataCurrentNamespace_.size() > 0) {
394 signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_));
395 }
396 cppbor::Array popArray;
397 popArray.add("ProofOfProvisioning")
398 .add(docType_)
399 .add(std::move(signedDataAccessControlProfiles_))
400 .add(std::move(signedDataNamespaces_))
401 .add(testCredential_);
402 vector<uint8_t> encodedCbor = popArray.encode();
403
David Zeuthen28edb102020-04-28 18:54:55 -0400404 if (encodedCbor.size() != expectedProofOfProvisioningSize_) {
405 LOG(ERROR) << "CBOR for proofOfProvisioning is " << encodedCbor.size() << " bytes, "
406 << "was expecting " << expectedProofOfProvisioningSize_;
407 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
408 IIdentityCredentialStore::STATUS_INVALID_DATA,
409 StringPrintf("Unexpected CBOR size %zd for proofOfProvisioning, was expecting %zd",
410 encodedCbor.size(), expectedProofOfProvisioningSize_)
411 .c_str()));
412 }
413
David Zeuthenc75ac312019-10-28 13:16:45 -0400414 optional<vector<uint8_t>> signature = support::coseSignEcDsa(credentialPrivKey_,
415 encodedCbor, // payload
416 {}, // additionalData
417 {}); // certificateChain
418 if (!signature) {
David Zeuthen81603152020-02-11 22:04:24 -0500419 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
420 IIdentityCredentialStore::STATUS_FAILED, "Error signing data"));
David Zeuthenc75ac312019-10-28 13:16:45 -0400421 }
422
423 vector<uint8_t> credentialKeys;
424 if (!generateCredentialKeys(storageKey_, credentialPrivKey_, credentialKeys)) {
David Zeuthen81603152020-02-11 22:04:24 -0500425 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
426 IIdentityCredentialStore::STATUS_FAILED, "Error generating CredentialKeys"));
David Zeuthenc75ac312019-10-28 13:16:45 -0400427 }
428
429 vector<uint8_t> credentialData;
David Zeuthen81603152020-02-11 22:04:24 -0500430 if (!generateCredentialData(
431 testCredential_ ? support::getTestHardwareBoundKey() : getHardwareBoundKey(),
432 docType_, testCredential_, credentialKeys, credentialData)) {
433 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
434 IIdentityCredentialStore::STATUS_FAILED, "Error generating CredentialData"));
David Zeuthenc75ac312019-10-28 13:16:45 -0400435 }
436
Jooyung Han17be89b2020-02-21 21:17:06 +0900437 *outCredentialData = credentialData;
438 *outProofOfProvisioningSignature = signature.value();
David Zeuthen81603152020-02-11 22:04:24 -0500439 return ndk::ScopedAStatus::ok();
David Zeuthenc75ac312019-10-28 13:16:45 -0400440}
441
David Zeuthen81603152020-02-11 22:04:24 -0500442} // namespace aidl::android::hardware::identity