summaryrefslogtreecommitdiff
path: root/identity/WritableCredential.cpp
diff options
context:
space:
mode:
authorDavid Zeuthen <zeuthen@google.com>2020-04-27 13:34:38 -0400
committerDavid Zeuthen <zeuthen@google.com>2020-04-29 09:52:51 -0400
commite2a78a48c0751400e8357b16c9355bef70ff7247 (patch)
tree408bc8bebb8ed2f68cb41e7002cdd9e682692a25 /identity/WritableCredential.cpp
parentda132924a0c0a1d0f4acaecc1c08c03e6659bbe9 (diff)
downloadsecurity-e2a78a48c0751400e8357b16c9355bef70ff7247.tar.gz
credstore: Pass additional information to Identity Credential HAL.
Without this extra information passed upfront it's not practical to implement a HAL which incrementally builds up cryptographically authenticated data. This information is conveyed by using two new methods on version 2 of the Identity Credential HAL. If these methods are not implemented (if a version 1 HAL is running) the invocation fails and we handle this gracefully by just ignoring the error. Bug: 154631410 Test: atest VtsHalIdentityTargetTest Test: atest android.security.identity.cts Change-Id: I17d516e41e800f58daa4c11dcca0305c80740d5b
Diffstat (limited to 'identity/WritableCredential.cpp')
-rw-r--r--identity/WritableCredential.cpp78
1 files changed, 74 insertions, 4 deletions
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<IWritableIdentityCredential> 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<uint8_t
return Status::ok();
}
+ssize_t WritableCredential::calcExpectedProofOfProvisioningSize(
+ const vector<AccessControlProfileParcel>& accessControlProfiles,
+ const vector<EntryNamespaceParcel>& 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<AccessControlProfileParcel>& accessControlProfiles,
const vector<EntryNamespaceParcel>& entryNamespaces,
@@ -113,7 +169,21 @@ WritableCredential::personalize(const vector<AccessControlProfileParcel>& 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);
}