summaryrefslogtreecommitdiff
path: root/identity/aidl/default/common/IdentityCredential.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'identity/aidl/default/common/IdentityCredential.cpp')
-rw-r--r--identity/aidl/default/common/IdentityCredential.cpp243
1 files changed, 184 insertions, 59 deletions
diff --git a/identity/aidl/default/common/IdentityCredential.cpp b/identity/aidl/default/common/IdentityCredential.cpp
index 95557b5c9d..ff80752ee7 100644
--- a/identity/aidl/default/common/IdentityCredential.cpp
+++ b/identity/aidl/default/common/IdentityCredential.cpp
@@ -72,14 +72,38 @@ int IdentityCredential::initialize() {
testCredential_ = testCredentialItem->value();
encryptedCredentialKeys_ = encryptedCredentialKeysItem->value();
- if (!hwProxy_->initialize(testCredential_, docType_, encryptedCredentialKeys_)) {
- LOG(ERROR) << "hwProxy->initialize failed";
- return false;
+
+ // If in a session, delay the initialization of the proxy.
+ //
+ if (!session_) {
+ ndk::ScopedAStatus status = ensureHwProxy();
+ if (!status.isOk()) {
+ LOG(ERROR) << "Error initializing hw proxy";
+ return IIdentityCredentialStore::STATUS_FAILED;
+ }
}
return IIdentityCredentialStore::STATUS_OK;
}
+ndk::ScopedAStatus IdentityCredential::ensureHwProxy() {
+ if (hwProxy_) {
+ return ndk::ScopedAStatus::ok();
+ }
+ hwProxy_ = hwProxyFactory_->createPresentationProxy();
+ if (!hwProxy_) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Error creating hw proxy"));
+ }
+ uint64_t sessionId = session_ ? session_->getSessionId() : EIC_PRESENTATION_ID_UNSET;
+ if (!hwProxy_->initialize(sessionId, testCredential_, docType_, encryptedCredentialKeys_)) {
+ hwProxy_.clear();
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Error initializing hw proxy"));
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus IdentityCredential::deleteCredential(
vector<uint8_t>* outProofOfDeletionSignature) {
return deleteCredentialCommon({}, false, outProofOfDeletionSignature);
@@ -93,6 +117,14 @@ ndk::ScopedAStatus IdentityCredential::deleteCredentialWithChallenge(
ndk::ScopedAStatus IdentityCredential::deleteCredentialCommon(
const vector<uint8_t>& challenge, bool includeChallenge,
vector<uint8_t>* outProofOfDeletionSignature) {
+ if (session_) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+ }
+ ndk::ScopedAStatus status = ensureHwProxy();
+ if (!status.isOk()) {
+ return status;
+ }
if (challenge.size() > 32) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_INVALID_DATA, "Challenge too big"));
@@ -128,6 +160,14 @@ ndk::ScopedAStatus IdentityCredential::deleteCredentialCommon(
ndk::ScopedAStatus IdentityCredential::proveOwnership(
const vector<uint8_t>& challenge, vector<uint8_t>* outProofOfOwnershipSignature) {
+ if (session_) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+ }
+ ndk::ScopedAStatus status = ensureHwProxy();
+ if (!status.isOk()) {
+ return status;
+ }
if (challenge.size() > 32) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_INVALID_DATA, "Challenge too big"));
@@ -159,6 +199,14 @@ ndk::ScopedAStatus IdentityCredential::proveOwnership(
}
ndk::ScopedAStatus IdentityCredential::createEphemeralKeyPair(vector<uint8_t>* outKeyPair) {
+ if (session_) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+ }
+ ndk::ScopedAStatus status = ensureHwProxy();
+ if (!status.isOk()) {
+ return status;
+ }
optional<vector<uint8_t>> ephemeralPriv = hwProxy_->createEphemeralKeyPair();
if (!ephemeralPriv) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -186,11 +234,23 @@ ndk::ScopedAStatus IdentityCredential::createEphemeralKeyPair(vector<uint8_t>* o
ndk::ScopedAStatus IdentityCredential::setReaderEphemeralPublicKey(
const vector<uint8_t>& publicKey) {
+ if (session_) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+ }
readerPublicKey_ = publicKey;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus IdentityCredential::createAuthChallenge(int64_t* outChallenge) {
+ if (session_) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+ }
+ ndk::ScopedAStatus status = ensureHwProxy();
+ if (!status.isOk()) {
+ return status;
+ }
optional<uint64_t> challenge = hwProxy_->createAuthChallenge();
if (!challenge) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -217,16 +277,22 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval(
const HardwareAuthToken& authToken, const vector<uint8_t>& itemsRequest,
const vector<uint8_t>& signingKeyBlob, const vector<uint8_t>& sessionTranscript,
const vector<uint8_t>& readerSignature, const vector<int32_t>& requestCounts) {
- std::unique_ptr<cppbor::Item> sessionTranscriptItem;
- if (sessionTranscript.size() > 0) {
- auto [item, _, message] = cppbor::parse(sessionTranscript);
- if (item == nullptr) {
+ ndk::ScopedAStatus status = ensureHwProxy();
+ if (!status.isOk()) {
+ return status;
+ }
+
+ // If in a session, ensure the passed-in session transcript matches the
+ // session transcript from the session.
+ if (session_) {
+ if (sessionTranscript != session_->getSessionTranscript()) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_INVALID_DATA,
- "SessionTranscript contains invalid CBOR"));
+ IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH,
+ "In a session and passed-in SessionTranscript doesn't match the one "
+ "from the session"));
}
- sessionTranscriptItem = std::move(item);
}
+
if (numStartRetrievalCalls_ > 0) {
if (sessionTranscript_ != sessionTranscript) {
LOG(ERROR) << "Session Transcript changed";
@@ -390,32 +456,36 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval(
}
}
- // TODO: move this check to the TA
-#if 1
- // To prevent replay-attacks, we check that the public part of the ephemeral
- // key we previously created, is present in the DeviceEngagement part of
- // SessionTranscript as a COSE_Key, in uncompressed form.
- //
- // We do this by just searching for the X and Y coordinates.
- if (sessionTranscript.size() > 0) {
- auto [getXYSuccess, ePubX, ePubY] = support::ecPublicKeyGetXandY(ephemeralPublicKey_);
- if (!getXYSuccess) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
- "Error extracting X and Y from ePub"));
- }
- if (sessionTranscript.size() > 0 &&
- !(memmem(sessionTranscript.data(), sessionTranscript.size(), ePubX.data(),
- ePubX.size()) != nullptr &&
- memmem(sessionTranscript.data(), sessionTranscript.size(), ePubY.data(),
- ePubY.size()) != nullptr)) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
- "Did not find ephemeral public key's X and Y coordinates in "
- "SessionTranscript (make sure leading zeroes are not used)"));
+ if (session_) {
+ // If presenting in a session, the TA has already done this check.
+
+ } else {
+ // To prevent replay-attacks, we check that the public part of the ephemeral
+ // key we previously created, is present in the DeviceEngagement part of
+ // SessionTranscript as a COSE_Key, in uncompressed form.
+ //
+ // We do this by just searching for the X and Y coordinates.
+ //
+ // Would be nice to move this check to the TA.
+ if (sessionTranscript.size() > 0) {
+ auto [getXYSuccess, ePubX, ePubY] = support::ecPublicKeyGetXandY(ephemeralPublicKey_);
+ if (!getXYSuccess) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
+ "Error extracting X and Y from ePub"));
+ }
+ if (sessionTranscript.size() > 0 &&
+ !(memmem(sessionTranscript.data(), sessionTranscript.size(), ePubX.data(),
+ ePubX.size()) != nullptr &&
+ memmem(sessionTranscript.data(), sessionTranscript.size(), ePubY.data(),
+ ePubY.size()) != nullptr)) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
+ "Did not find ephemeral public key's X and Y coordinates in "
+ "SessionTranscript (make sure leading zeroes are not used)"));
+ }
}
}
-#endif
// itemsRequest: If non-empty, contains request data that may be signed by the
// reader. The content can be defined in the way appropriate for the
@@ -537,21 +607,38 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval(
// Finally, pass info so the HMAC key can be derived and the TA can start
// creating the DeviceNameSpaces CBOR...
- if (sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0 && signingKeyBlob.size() > 0) {
- // We expect the reader ephemeral public key to be same size and curve
- // as the ephemeral key we generated (e.g. P-256 key), otherwise ECDH
- // won't work. So its length should be 65 bytes and it should be
- // starting with 0x04.
- if (readerPublicKey_.size() != 65 || readerPublicKey_[0] != 0x04) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_FAILED,
- "Reader public key is not in expected format"));
+ if (!session_) {
+ if (sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0 &&
+ signingKeyBlob.size() > 0) {
+ // We expect the reader ephemeral public key to be same size and curve
+ // as the ephemeral key we generated (e.g. P-256 key), otherwise ECDH
+ // won't work. So its length should be 65 bytes and it should be
+ // starting with 0x04.
+ if (readerPublicKey_.size() != 65 || readerPublicKey_[0] != 0x04) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED,
+ "Reader public key is not in expected format"));
+ }
+ vector<uint8_t> pubKeyP256(readerPublicKey_.begin() + 1, readerPublicKey_.end());
+ if (!hwProxy_->calcMacKey(sessionTranscript_, pubKeyP256, signingKeyBlob, docType_,
+ numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED,
+ "Error starting retrieving entries"));
+ }
}
- vector<uint8_t> pubKeyP256(readerPublicKey_.begin() + 1, readerPublicKey_.end());
- if (!hwProxy_->calcMacKey(sessionTranscript_, pubKeyP256, signingKeyBlob, docType_,
- numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_FAILED, "Error starting retrieving entries"));
+ } else {
+ if (session_->getSessionTranscript().size() > 0 &&
+ session_->getReaderEphemeralPublicKey().size() > 0 && signingKeyBlob.size() > 0) {
+ // Don't actually pass the reader ephemeral public key in, the TA will get
+ // it from the session object.
+ //
+ if (!hwProxy_->calcMacKey(sessionTranscript_, {}, signingKeyBlob, docType_,
+ numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED,
+ "Error starting retrieving entries"));
+ }
}
}
@@ -665,6 +752,11 @@ void IdentityCredential::calcDeviceNameSpacesSize(uint32_t accessControlProfileM
ndk::ScopedAStatus IdentityCredential::startRetrieveEntryValue(
const string& nameSpace, const string& name, int32_t entrySize,
const vector<int32_t>& accessControlProfileIds) {
+ ndk::ScopedAStatus status = ensureHwProxy();
+ if (!status.isOk()) {
+ return status;
+ }
+
if (name.empty()) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_INVALID_DATA, "Name cannot be empty"));
@@ -785,6 +877,11 @@ ndk::ScopedAStatus IdentityCredential::startRetrieveEntryValue(
ndk::ScopedAStatus IdentityCredential::retrieveEntryValue(const vector<uint8_t>& encryptedContent,
vector<uint8_t>* outContent) {
+ ndk::ScopedAStatus status = ensureHwProxy();
+ if (!status.isOk()) {
+ return status;
+ }
+
optional<vector<uint8_t>> content = hwProxy_->retrieveEntryValue(
encryptedContent, currentNameSpace_, currentName_, currentAccessControlProfileIds_);
if (!content) {
@@ -829,6 +926,11 @@ ndk::ScopedAStatus IdentityCredential::retrieveEntryValue(const vector<uint8_t>&
ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
vector<uint8_t>* outDeviceNameSpaces) {
+ ndk::ScopedAStatus status = ensureHwProxy();
+ if (!status.isOk()) {
+ return status;
+ }
+
if (currentNameSpaceDeviceNameSpacesMap_.size() > 0) {
deviceNameSpacesMap_.add(currentNameSpace_,
std::move(currentNameSpaceDeviceNameSpacesMap_));
@@ -846,18 +948,23 @@ ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
.c_str()));
}
- // If there's no signing key or no sessionTranscript or no reader ephemeral
- // public key, we return the empty MAC.
+ // If the TA calculated a MAC (it might not have), format it as a COSE_Mac0
+ //
optional<vector<uint8_t>> mac;
- if (signingKeyBlob_.size() > 0 && sessionTranscript_.size() > 0 &&
- readerPublicKey_.size() > 0) {
- optional<vector<uint8_t>> digestToBeMaced = hwProxy_->finishRetrieval();
- if (!digestToBeMaced || digestToBeMaced.value().size() != 32) {
+ optional<vector<uint8_t>> digestToBeMaced = hwProxy_->finishRetrieval();
+
+ // The MAC not being set means an error occurred.
+ if (!digestToBeMaced) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_INVALID_DATA, "Error generating digestToBeMaced"));
+ }
+ // Size 0 means that the MAC isn't set. If it's set, it has to be 32 bytes.
+ if (digestToBeMaced.value().size() != 0) {
+ if (digestToBeMaced.value().size() != 32) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_INVALID_DATA,
- "Error generating digestToBeMaced"));
+ "Unexpected size for digestToBeMaced"));
}
- // Now construct COSE_Mac0 from the returned MAC...
mac = support::coseMacWithDigest(digestToBeMaced.value(), {} /* data */);
}
@@ -868,6 +975,15 @@ ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair(
vector<uint8_t>* outSigningKeyBlob, Certificate* outSigningKeyCertificate) {
+ if (session_) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+ }
+ ndk::ScopedAStatus status = ensureHwProxy();
+ if (!status.isOk()) {
+ return status;
+ }
+
time_t now = time(NULL);
optional<pair<vector<uint8_t>, vector<uint8_t>>> pair =
hwProxy_->generateSigningKeyPair(docType_, now);
@@ -885,10 +1001,19 @@ ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair(
ndk::ScopedAStatus IdentityCredential::updateCredential(
shared_ptr<IWritableIdentityCredential>* outWritableCredential) {
- sp<SecureHardwareProvisioningProxy> hwProxy = hwProxyFactory_->createProvisioningProxy();
+ if (session_) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Cannot be called in a session"));
+ }
+ sp<SecureHardwareProvisioningProxy> provisioningHwProxy =
+ hwProxyFactory_->createProvisioningProxy();
+ if (!provisioningHwProxy) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Error creating provisioning proxy"));
+ }
shared_ptr<WritableIdentityCredential> wc =
- ndk::SharedRefBase::make<WritableIdentityCredential>(hwProxy, docType_,
- testCredential_);
+ ndk::SharedRefBase::make<WritableIdentityCredential>(
+ provisioningHwProxy, docType_, testCredential_, hardwareInformation_);
if (!wc->initializeForUpdate(encryptedCredentialKeys_)) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_FAILED,