diff --git a/identity/Credential.cpp b/identity/Credential.cpp index 05c31d3d..49b412ff 100644 --- a/identity/Credential.cpp +++ b/identity/Credential.cpp @@ -261,7 +261,35 @@ Status Credential::getEntries(const vector& requestMessage, signingKeyBlob = authKey->keyBlob; } - Status status = + // Pass the HAL enough information to allow calculating the size of + // DeviceNameSpaces ahead of time. + vector halRequestNamespaces; + for (const RequestNamespaceParcel& rns : requestNamespaces) { + RequestNamespace ns; + ns.namespaceName = rns.namespaceName; + for (const RequestEntryParcel& rep : rns.entries) { + optional entryData = data_->getEntryData(rns.namespaceName, rep.name); + if (entryData) { + RequestDataItem di; + di.name = rep.name; + di.size = entryData.value().size; + di.accessControlProfileIds = entryData.value().accessControlProfileIds; + ns.items.push_back(di); + } + } + if (ns.items.size() > 0) { + halRequestNamespaces.push_back(ns); + } + } + // This is not catastrophic, we might be dealing with a version 1 implementation which + // doesn't have this method. + Status status = halBinder_->setRequestedNamespaces(halRequestNamespaces); + if (!status.isOk()) { + LOG(INFO) << "Failed setting expected requested namespaces assuming V1 HAL " + << "and continuing"; + } + + status = halBinder_->startRetrieval(selectedProfiles, aidlAuthToken, requestMessage, signingKeyBlob, sessionTranscript, readerSignature, requestCounts); if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) { diff --git a/identity/Credential.h b/identity/Credential.h index a0d90634..e2880d98 100644 --- a/identity/Credential.h +++ b/identity/Credential.h @@ -38,6 +38,8 @@ using ::std::vector; using ::android::hardware::identity::CipherSuite; using ::android::hardware::identity::IIdentityCredential; using ::android::hardware::identity::IIdentityCredentialStore; +using ::android::hardware::identity::RequestDataItem; +using ::android::hardware::identity::RequestNamespace; class Credential : public BnCredential { public: @@ -80,6 +82,11 @@ class Credential : public BnCredential { sp data_; sp halBinder_; + + ssize_t + calcExpectedDeviceNameSpacesSize(const vector& requestMessage, + const vector& requestNamespaces, + uint32_t authorizedAcps); }; } // namespace identity diff --git a/identity/WritableCredential.cpp b/identity/WritableCredential.cpp index dec95a6a..cb2d6ffd 100644 --- a/identity/WritableCredential.cpp +++ b/identity/WritableCredential.cpp @@ -39,10 +39,10 @@ using ::android::hardware::identity::SecureAccessControlProfile; using ::android::hardware::identity::support::chunkVector; WritableCredential::WritableCredential(const string& dataPath, const string& credentialName, - const string& /*docType*/, size_t dataChunkSize, + const string& docType, size_t dataChunkSize, sp halBinder) - : dataPath_(dataPath), credentialName_(credentialName), dataChunkSize_(dataChunkSize), - halBinder_(halBinder) {} + : dataPath_(dataPath), credentialName_(credentialName), docType_(docType), + dataChunkSize_(dataChunkSize), halBinder_(halBinder) {} WritableCredential::~WritableCredential() {} @@ -89,6 +89,62 @@ Status WritableCredential::getCredentialKeyCertificateChain(const vector& accessControlProfiles, + const vector& entryNamespaces) { + + // Right now, we calculate the size by simply just calculating the + // CBOR. There's a little bit of overhead associated with this (as compared + // to just adding up sizes) but it's a lot simpler and robust. In the future + // if this turns out to be a problem, we can optimize it. + // + + cppbor::Array acpArray; + for (const AccessControlProfileParcel& profile : accessControlProfiles) { + cppbor::Map map; + map.add("id", profile.id); + if (profile.readerCertificate.size() > 0) { + map.add("readerCertificate", cppbor::Bstr(profile.readerCertificate)); + } + if (profile.userAuthenticationRequired) { + map.add("userAuthenticationRequired", profile.userAuthenticationRequired); + map.add("timeoutMillis", profile.userAuthenticationTimeoutMillis); + } + acpArray.add(std::move(map)); + } + + cppbor::Map dataMap; + for (const EntryNamespaceParcel& ensParcel : entryNamespaces) { + cppbor::Array entriesArray; + for (const EntryParcel& eParcel : ensParcel.entries) { + // TODO: ideally do do this without parsing the data (but still validate data is valid + // CBOR). + auto [itemForValue, _, _2] = cppbor::parse(eParcel.value); + if (itemForValue == nullptr) { + return -1; + } + cppbor::Map entryMap; + entryMap.add("name", eParcel.name); + entryMap.add("value", std::move(itemForValue)); + cppbor::Array acpIdsArray; + for (int32_t id : eParcel.accessControlProfileIds) { + acpIdsArray.add(id); + } + entryMap.add("accessControlProfiles", std::move(acpIdsArray)); + entriesArray.add(std::move(entryMap)); + } + dataMap.add(ensParcel.namespaceName, std::move(entriesArray)); + } + + cppbor::Array array; + array.add("ProofOfProvisioning"); + array.add(docType_); + array.add(std::move(acpArray)); + array.add(std::move(dataMap)); + array.add(false); // testCredential + return array.encode().size(); +} + Status WritableCredential::personalize(const vector& accessControlProfiles, const vector& entryNamespaces, @@ -113,7 +169,21 @@ WritableCredential::personalize(const vector& access entryCounts.push_back(ensParcel.entries.size()); } - Status status = halBinder_->startPersonalization(accessControlProfiles.size(), entryCounts); + ssize_t expectedPoPSize = + calcExpectedProofOfProvisioningSize(accessControlProfiles, entryNamespaces); + if (expectedPoPSize < 0) { + return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC, + "Data is not valid CBOR"); + } + // This is not catastrophic, we might be dealing with a version 1 implementation which + // doesn't have this method. + Status status = halBinder_->setExpectedProofOfProvisioningSize(expectedPoPSize); + if (!status.isOk()) { + LOG(INFO) << "Failed setting expected ProofOfProvisioning size, assuming V1 HAL " + << "and continuing"; + } + + status = halBinder_->startPersonalization(accessControlProfiles.size(), entryCounts); if (!status.isOk()) { return halStatusToGenericError(status); } diff --git a/identity/WritableCredential.h b/identity/WritableCredential.h index 8b5e19e2..eb63aca2 100644 --- a/identity/WritableCredential.h +++ b/identity/WritableCredential.h @@ -50,10 +50,15 @@ class WritableCredential : public BnWritableCredential { private: string dataPath_; string credentialName_; + string docType_; size_t dataChunkSize_; sp halBinder_; vector attestationCertificate_; + ssize_t calcExpectedProofOfProvisioningSize( + const vector& accessControlProfiles, + const vector& entryNamespaces); + Status ensureAttestationCertificateExists(const vector& challenge); };