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
This commit is contained in:
parent
da132924a0
commit
e2a78a48c0
4 changed files with 115 additions and 5 deletions
|
@ -261,7 +261,35 @@ Status Credential::getEntries(const vector<uint8_t>& requestMessage,
|
|||
signingKeyBlob = authKey->keyBlob;
|
||||
}
|
||||
|
||||
Status status =
|
||||
// Pass the HAL enough information to allow calculating the size of
|
||||
// DeviceNameSpaces ahead of time.
|
||||
vector<RequestNamespace> halRequestNamespaces;
|
||||
for (const RequestNamespaceParcel& rns : requestNamespaces) {
|
||||
RequestNamespace ns;
|
||||
ns.namespaceName = rns.namespaceName;
|
||||
for (const RequestEntryParcel& rep : rns.entries) {
|
||||
optional<EntryData> 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) {
|
||||
|
|
|
@ -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<CredentialData> data_;
|
||||
|
||||
sp<IIdentityCredential> halBinder_;
|
||||
|
||||
ssize_t
|
||||
calcExpectedDeviceNameSpacesSize(const vector<uint8_t>& requestMessage,
|
||||
const vector<RequestNamespaceParcel>& requestNamespaces,
|
||||
uint32_t authorizedAcps);
|
||||
};
|
||||
|
||||
} // namespace identity
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -50,10 +50,15 @@ class WritableCredential : public BnWritableCredential {
|
|||
private:
|
||||
string dataPath_;
|
||||
string credentialName_;
|
||||
string docType_;
|
||||
size_t dataChunkSize_;
|
||||
sp<IWritableIdentityCredential> halBinder_;
|
||||
vector<uint8_t> attestationCertificate_;
|
||||
|
||||
ssize_t calcExpectedProofOfProvisioningSize(
|
||||
const vector<AccessControlProfileParcel>& accessControlProfiles,
|
||||
const vector<EntryNamespaceParcel>& entryNamespaces);
|
||||
|
||||
Status ensureAttestationCertificateExists(const vector<uint8_t>& challenge);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue