/* * Copyright 2020, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "FakeSecureHardwareProxy" #include "FakeSecureHardwareProxy.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using ::std::optional; using ::std::string; using ::std::tuple; using ::std::vector; namespace android::hardware::identity { // ---------------------------------------------------------------------- // The singleton EicProvisioning object used everywhere. // EicProvisioning FakeSecureHardwareProvisioningProxy::ctx_; FakeSecureHardwareProvisioningProxy::~FakeSecureHardwareProvisioningProxy() { if (id_ != 0) { shutdown(); } } bool FakeSecureHardwareProvisioningProxy::initialize(bool testCredential) { if (id_ != 0) { LOG(WARNING) << "Proxy is already initialized"; return false; } bool initialized = eicProvisioningInit(&ctx_, testCredential); if (!initialized) { return false; } optional id = getId(); if (!id) { LOG(WARNING) << "Error getting id"; return false; } id_ = id.value(); return true; } bool FakeSecureHardwareProvisioningProxy::initializeForUpdate( bool testCredential, const string& docType, const vector& encryptedCredentialKeys) { if (id_ != 0) { LOG(WARNING) << "Proxy is already initialized"; return false; } bool initialized = eicProvisioningInitForUpdate(&ctx_, testCredential, docType.c_str(), docType.size(), encryptedCredentialKeys.data(), encryptedCredentialKeys.size()); if (!initialized) { return false; } optional id = getId(); if (!id) { LOG(WARNING) << "Error getting id"; return false; } id_ = id.value(); return true; } optional FakeSecureHardwareProvisioningProxy::getId() { uint32_t id; if (!eicProvisioningGetId(&ctx_, &id)) { return std::nullopt; } return id; } bool FakeSecureHardwareProvisioningProxy::validateId(const string& callerName) { if (id_ == 0) { LOG(WARNING) << "FakeSecureHardwareProvisioningProxy::" << callerName << ": While validating expected id is 0"; return false; } optional id = getId(); if (!id) { LOG(WARNING) << "FakeSecureHardwareProvisioningProxy::" << callerName << ": Error getting id for validating"; return false; } if (id.value() != id_) { LOG(WARNING) << "FakeSecureHardwareProvisioningProxy::" << callerName << ": While validating expected id " << id_ << " but got " << id.value(); return false; } return true; } bool FakeSecureHardwareProvisioningProxy::shutdown() { bool validated = validateId(__func__); id_ = 0; if (!validated) { return false; } if (!eicProvisioningShutdown(&ctx_)) { LOG(INFO) << "Error shutting down provisioning"; return false; } return true; } // Returns public key certificate. optional> FakeSecureHardwareProvisioningProxy::createCredentialKey( const vector& challenge, const vector& applicationId) { if (!validateId(__func__)) { return std::nullopt; } uint8_t publicKeyCert[4096]; size_t publicKeyCertSize = sizeof publicKeyCert; if (!eicProvisioningCreateCredentialKey(&ctx_, challenge.data(), challenge.size(), applicationId.data(), applicationId.size(), /*attestationKeyBlob=*/nullptr, /*attestationKeyBlobSize=*/0, /*attestationKeyCert=*/nullptr, /*attestationKeyCertSize=*/0, publicKeyCert, &publicKeyCertSize)) { return std::nullopt; } vector pubKeyCert(publicKeyCertSize); memcpy(pubKeyCert.data(), publicKeyCert, publicKeyCertSize); return pubKeyCert; } optional> FakeSecureHardwareProvisioningProxy::createCredentialKeyUsingRkp( const vector& challenge, const vector& applicationId, const vector& attestationKeyBlob, const vector& attstationKeyCert) { size_t publicKeyCertSize = 4096; vector publicKeyCert(publicKeyCertSize); if (!eicProvisioningCreateCredentialKey(&ctx_, challenge.data(), challenge.size(), applicationId.data(), applicationId.size(), attestationKeyBlob.data(), attestationKeyBlob.size(), attstationKeyCert.data(), attstationKeyCert.size(), publicKeyCert.data(), &publicKeyCertSize)) { LOG(ERROR) << "error creating credential key"; return std::nullopt; } publicKeyCert.resize(publicKeyCertSize); return publicKeyCert; } bool FakeSecureHardwareProvisioningProxy::startPersonalization( int accessControlProfileCount, const vector& entryCounts, const string& docType, size_t expectedProofOfProvisioningSize) { if (!validateId(__func__)) { return false; } if (!eicProvisioningStartPersonalization(&ctx_, accessControlProfileCount, entryCounts.data(), entryCounts.size(), docType.c_str(), docType.size(), expectedProofOfProvisioningSize)) { return false; } return true; } // Returns MAC (28 bytes). optional> FakeSecureHardwareProvisioningProxy::addAccessControlProfile( int id, const vector& readerCertificate, bool userAuthenticationRequired, uint64_t timeoutMillis, uint64_t secureUserId) { if (!validateId(__func__)) { return std::nullopt; } vector mac(28); uint8_t scratchSpace[512]; if (!eicProvisioningAddAccessControlProfile( &ctx_, id, readerCertificate.data(), readerCertificate.size(), userAuthenticationRequired, timeoutMillis, secureUserId, mac.data(), scratchSpace, sizeof(scratchSpace))) { return std::nullopt; } return mac; } bool FakeSecureHardwareProvisioningProxy::beginAddEntry(const vector& accessControlProfileIds, const string& nameSpace, const string& name, uint64_t entrySize) { if (!validateId(__func__)) { return false; } uint8_t scratchSpace[512]; vector uint8AccessControlProfileIds; for (size_t i = 0; i < accessControlProfileIds.size(); i++) { uint8AccessControlProfileIds.push_back(accessControlProfileIds[i] & 0xFF); } return eicProvisioningBeginAddEntry(&ctx_, uint8AccessControlProfileIds.data(), uint8AccessControlProfileIds.size(), nameSpace.c_str(), nameSpace.size(), name.c_str(), name.size(), entrySize, scratchSpace, sizeof(scratchSpace)); } // Returns encryptedContent. optional> FakeSecureHardwareProvisioningProxy::addEntryValue( const vector& accessControlProfileIds, const string& nameSpace, const string& name, const vector& content) { if (!validateId(__func__)) { return std::nullopt; } vector eicEncryptedContent; uint8_t scratchSpace[512]; vector uint8AccessControlProfileIds; for (size_t i = 0; i < accessControlProfileIds.size(); i++) { uint8AccessControlProfileIds.push_back(accessControlProfileIds[i] & 0xFF); } eicEncryptedContent.resize(content.size() + 28); if (!eicProvisioningAddEntryValue( &ctx_, uint8AccessControlProfileIds.data(), uint8AccessControlProfileIds.size(), nameSpace.c_str(), nameSpace.size(), name.c_str(), name.size(), content.data(), content.size(), eicEncryptedContent.data(), scratchSpace, sizeof(scratchSpace))) { return std::nullopt; } return eicEncryptedContent; } // Returns signatureOfToBeSigned (EIC_ECDSA_P256_SIGNATURE_SIZE bytes). optional> FakeSecureHardwareProvisioningProxy::finishAddingEntries() { if (!validateId(__func__)) { return std::nullopt; } vector signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE); if (!eicProvisioningFinishAddingEntries(&ctx_, signatureOfToBeSigned.data())) { return std::nullopt; } return signatureOfToBeSigned; } // Returns encryptedCredentialKeys. optional> FakeSecureHardwareProvisioningProxy::finishGetCredentialData( const string& docType) { if (!validateId(__func__)) { return std::nullopt; } vector encryptedCredentialKeys(116); size_t size = encryptedCredentialKeys.size(); if (!eicProvisioningFinishGetCredentialData(&ctx_, docType.c_str(), docType.size(), encryptedCredentialKeys.data(), &size)) { return std::nullopt; } encryptedCredentialKeys.resize(size); return encryptedCredentialKeys; } // ---------------------------------------------------------------------- // The singleton EicSession object used everywhere. // EicSession FakeSecureHardwareSessionProxy::ctx_; FakeSecureHardwareSessionProxy::~FakeSecureHardwareSessionProxy() { if (id_ != 0) { shutdown(); } } bool FakeSecureHardwareSessionProxy::initialize() { if (id_ != 0) { LOG(WARNING) << "Proxy is already initialized"; return false; } bool initialized = eicSessionInit(&ctx_); if (!initialized) { return false; } optional id = getId(); if (!id) { LOG(WARNING) << "Error getting id"; return false; } id_ = id.value(); return true; } optional FakeSecureHardwareSessionProxy::getId() { uint32_t id; if (!eicSessionGetId(&ctx_, &id)) { return std::nullopt; } return id; } bool FakeSecureHardwareSessionProxy::shutdown() { bool validated = validateId(__func__); id_ = 0; if (!validated) { return false; } if (!eicSessionShutdown(&ctx_)) { LOG(INFO) << "Error shutting down session"; return false; } return true; } bool FakeSecureHardwareSessionProxy::validateId(const string& callerName) { if (id_ == 0) { LOG(WARNING) << "FakeSecureHardwareSessionProxy::" << callerName << ": While validating expected id is 0"; return false; } optional id = getId(); if (!id) { LOG(WARNING) << "FakeSecureHardwareSessionProxy::" << callerName << ": Error getting id for validating"; return false; } if (id.value() != id_) { LOG(WARNING) << "FakeSecureHardwareSessionProxy::" << callerName << ": While validating expected id " << id_ << " but got " << id.value(); return false; } return true; } optional FakeSecureHardwareSessionProxy::getAuthChallenge() { if (!validateId(__func__)) { return std::nullopt; } uint64_t authChallenge; if (!eicSessionGetAuthChallenge(&ctx_, &authChallenge)) { return std::nullopt; } return authChallenge; } optional> FakeSecureHardwareSessionProxy::getEphemeralKeyPair() { if (!validateId(__func__)) { return std::nullopt; } vector priv(EIC_P256_PRIV_KEY_SIZE); if (!eicSessionGetEphemeralKeyPair(&ctx_, priv.data())) { return std::nullopt; } return priv; } bool FakeSecureHardwareSessionProxy::setReaderEphemeralPublicKey( const vector& readerEphemeralPublicKey) { if (!validateId(__func__)) { return false; } return eicSessionSetReaderEphemeralPublicKey(&ctx_, readerEphemeralPublicKey.data()); } bool FakeSecureHardwareSessionProxy::setSessionTranscript( const vector& sessionTranscript) { if (!validateId(__func__)) { return false; } return eicSessionSetSessionTranscript(&ctx_, sessionTranscript.data(), sessionTranscript.size()); } // ---------------------------------------------------------------------- // The singleton EicPresentation object used everywhere. // EicPresentation FakeSecureHardwarePresentationProxy::ctx_; FakeSecureHardwarePresentationProxy::~FakeSecureHardwarePresentationProxy() { if (id_ != 0) { shutdown(); } } bool FakeSecureHardwarePresentationProxy::initialize( uint32_t sessionId, bool testCredential, const string& docType, const vector& encryptedCredentialKeys) { if (id_ != 0) { LOG(WARNING) << "Proxy is already initialized"; return false; } bool initialized = eicPresentationInit(&ctx_, sessionId, testCredential, docType.c_str(), docType.size(), encryptedCredentialKeys.data(), encryptedCredentialKeys.size()); if (!initialized) { return false; } optional id = getId(); if (!id) { LOG(WARNING) << "Error getting id"; return false; } id_ = id.value(); return true; } optional FakeSecureHardwarePresentationProxy::getId() { uint32_t id; if (!eicPresentationGetId(&ctx_, &id)) { return std::nullopt; } return id; } bool FakeSecureHardwarePresentationProxy::validateId(const string& callerName) { if (id_ == 0) { LOG(WARNING) << "FakeSecureHardwarePresentationProxy::" << callerName << ": While validating expected id is 0"; return false; } optional id = getId(); if (!id) { LOG(WARNING) << "FakeSecureHardwarePresentationProxy::" << callerName << ": Error getting id for validating"; return false; } if (id.value() != id_) { LOG(WARNING) << "FakeSecureHardwarePresentationProxy::" << callerName << ": While validating expected id " << id_ << " but got " << id.value(); return false; } return true; } bool FakeSecureHardwarePresentationProxy::shutdown() { bool validated = validateId(__func__); id_ = 0; if (!validated) { return false; } if (!eicPresentationShutdown(&ctx_)) { LOG(INFO) << "Error shutting down presentation"; return false; } return true; } // Returns publicKeyCert (1st component) and signingKeyBlob (2nd component) optional, vector>> FakeSecureHardwarePresentationProxy::generateSigningKeyPair(const string& docType, time_t now) { if (!validateId(__func__)) { return std::nullopt; } uint8_t publicKeyCert[512]; size_t publicKeyCertSize = sizeof(publicKeyCert); vector signingKeyBlob(60); if (!eicPresentationGenerateSigningKeyPair(&ctx_, docType.c_str(), docType.size(), now, publicKeyCert, &publicKeyCertSize, signingKeyBlob.data())) { return std::nullopt; } vector cert; cert.resize(publicKeyCertSize); memcpy(cert.data(), publicKeyCert, publicKeyCertSize); return std::make_pair(cert, signingKeyBlob); } // Returns private key optional> FakeSecureHardwarePresentationProxy::createEphemeralKeyPair() { if (!validateId(__func__)) { return std::nullopt; } vector priv(EIC_P256_PRIV_KEY_SIZE); if (!eicPresentationCreateEphemeralKeyPair(&ctx_, priv.data())) { return std::nullopt; } return priv; } optional FakeSecureHardwarePresentationProxy::createAuthChallenge() { if (!validateId(__func__)) { return std::nullopt; } uint64_t challenge; if (!eicPresentationCreateAuthChallenge(&ctx_, &challenge)) { return std::nullopt; } return challenge; } bool FakeSecureHardwarePresentationProxy::pushReaderCert(const vector& certX509) { if (!validateId(__func__)) { return false; } return eicPresentationPushReaderCert(&ctx_, certX509.data(), certX509.size()); } bool FakeSecureHardwarePresentationProxy::validateRequestMessage( const vector& sessionTranscript, const vector& requestMessage, int coseSignAlg, const vector& readerSignatureOfToBeSigned) { if (!validateId(__func__)) { return false; } return eicPresentationValidateRequestMessage( &ctx_, sessionTranscript.data(), sessionTranscript.size(), requestMessage.data(), requestMessage.size(), coseSignAlg, readerSignatureOfToBeSigned.data(), readerSignatureOfToBeSigned.size()); } bool FakeSecureHardwarePresentationProxy::setAuthToken( uint64_t challenge, uint64_t secureUserId, uint64_t authenticatorId, int hardwareAuthenticatorType, uint64_t timeStamp, const vector& mac, uint64_t verificationTokenChallenge, uint64_t verificationTokenTimestamp, int verificationTokenSecurityLevel, const vector& verificationTokenMac) { if (!validateId(__func__)) { return false; } return eicPresentationSetAuthToken(&ctx_, challenge, secureUserId, authenticatorId, hardwareAuthenticatorType, timeStamp, mac.data(), mac.size(), verificationTokenChallenge, verificationTokenTimestamp, verificationTokenSecurityLevel, verificationTokenMac.data(), verificationTokenMac.size()); } optional FakeSecureHardwarePresentationProxy::validateAccessControlProfile( int id, const vector& readerCertificate, bool userAuthenticationRequired, int timeoutMillis, uint64_t secureUserId, const vector& mac) { if (!validateId(__func__)) { return std::nullopt; } bool accessGranted = false; uint8_t scratchSpace[512]; if (!eicPresentationValidateAccessControlProfile(&ctx_, id, readerCertificate.data(), readerCertificate.size(), userAuthenticationRequired, timeoutMillis, secureUserId, mac.data(), &accessGranted, scratchSpace, sizeof(scratchSpace))) { return std::nullopt; } return accessGranted; } bool FakeSecureHardwarePresentationProxy::startRetrieveEntries() { if (!validateId(__func__)) { return false; } return eicPresentationStartRetrieveEntries(&ctx_); } bool FakeSecureHardwarePresentationProxy::prepareDeviceAuthentication( const vector& sessionTranscript, const vector& readerEphemeralPublicKey, const vector& signingKeyBlob, const string& docType, unsigned int numNamespacesWithValues, size_t expectedDeviceNamespacesSize) { if (!validateId(__func__)) { return false; } if (signingKeyBlob.size() != 60) { eicDebug("Unexpected size %zd of signingKeyBlob, expected 60", signingKeyBlob.size()); return false; } return eicPresentationPrepareDeviceAuthentication( &ctx_, sessionTranscript.data(), sessionTranscript.size(), readerEphemeralPublicKey.data(), readerEphemeralPublicKey.size(), signingKeyBlob.data(), docType.c_str(), docType.size(), numNamespacesWithValues, expectedDeviceNamespacesSize); } AccessCheckResult FakeSecureHardwarePresentationProxy::startRetrieveEntryValue( const string& nameSpace, const string& name, unsigned int newNamespaceNumEntries, int32_t entrySize, const vector& accessControlProfileIds) { if (!validateId(__func__)) { return AccessCheckResult::kFailed; } uint8_t scratchSpace[512]; vector uint8AccessControlProfileIds; for (size_t i = 0; i < accessControlProfileIds.size(); i++) { uint8AccessControlProfileIds.push_back(accessControlProfileIds[i] & 0xFF); } EicAccessCheckResult result = eicPresentationStartRetrieveEntryValue( &ctx_, nameSpace.c_str(), nameSpace.size(), name.c_str(), name.size(), newNamespaceNumEntries, entrySize, uint8AccessControlProfileIds.data(), uint8AccessControlProfileIds.size(), scratchSpace, sizeof(scratchSpace)); switch (result) { case EIC_ACCESS_CHECK_RESULT_OK: return AccessCheckResult::kOk; case EIC_ACCESS_CHECK_RESULT_NO_ACCESS_CONTROL_PROFILES: return AccessCheckResult::kNoAccessControlProfiles; case EIC_ACCESS_CHECK_RESULT_FAILED: return AccessCheckResult::kFailed; case EIC_ACCESS_CHECK_RESULT_USER_AUTHENTICATION_FAILED: return AccessCheckResult::kUserAuthenticationFailed; case EIC_ACCESS_CHECK_RESULT_READER_AUTHENTICATION_FAILED: return AccessCheckResult::kReaderAuthenticationFailed; } eicDebug("Unknown result with code %d, returning kFailed", (int)result); return AccessCheckResult::kFailed; } optional> FakeSecureHardwarePresentationProxy::retrieveEntryValue( const vector& encryptedContent, const string& nameSpace, const string& name, const vector& accessControlProfileIds) { if (!validateId(__func__)) { return std::nullopt; } uint8_t scratchSpace[512]; vector uint8AccessControlProfileIds; for (size_t i = 0; i < accessControlProfileIds.size(); i++) { uint8AccessControlProfileIds.push_back(accessControlProfileIds[i] & 0xFF); } vector content; content.resize(encryptedContent.size() - 28); if (!eicPresentationRetrieveEntryValue( &ctx_, encryptedContent.data(), encryptedContent.size(), content.data(), nameSpace.c_str(), nameSpace.size(), name.c_str(), name.size(), uint8AccessControlProfileIds.data(), uint8AccessControlProfileIds.size(), scratchSpace, sizeof(scratchSpace))) { return std::nullopt; } return content; } optional, vector>> FakeSecureHardwarePresentationProxy::finishRetrievalWithSignature() { if (!validateId(__func__)) { return std::nullopt; } vector mac(32); size_t macSize = 32; vector ecdsaSignature(EIC_ECDSA_P256_SIGNATURE_SIZE); size_t ecdsaSignatureSize = EIC_ECDSA_P256_SIGNATURE_SIZE; if (!eicPresentationFinishRetrievalWithSignature(&ctx_, mac.data(), &macSize, ecdsaSignature.data(), &ecdsaSignatureSize)) { return std::nullopt; } mac.resize(macSize); ecdsaSignature.resize(ecdsaSignatureSize); return std::make_pair(mac, ecdsaSignature); } optional> FakeSecureHardwarePresentationProxy::finishRetrieval() { if (!validateId(__func__)) { return std::nullopt; } vector mac(32); size_t macSize = 32; if (!eicPresentationFinishRetrieval(&ctx_, mac.data(), &macSize)) { return std::nullopt; } mac.resize(macSize); return mac; } optional> FakeSecureHardwarePresentationProxy::deleteCredential( const string& docType, const vector& challenge, bool includeChallenge, size_t proofOfDeletionCborSize) { if (!validateId(__func__)) { return std::nullopt; } vector signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE); if (!eicPresentationDeleteCredential(&ctx_, docType.c_str(), docType.size(), challenge.data(), challenge.size(), includeChallenge, proofOfDeletionCborSize, signatureOfToBeSigned.data())) { return std::nullopt; } return signatureOfToBeSigned; } optional> FakeSecureHardwarePresentationProxy::proveOwnership( const string& docType, bool testCredential, const vector& challenge, size_t proofOfOwnershipCborSize) { if (!validateId(__func__)) { return std::nullopt; } vector signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE); if (!eicPresentationProveOwnership(&ctx_, docType.c_str(), docType.size(), testCredential, challenge.data(), challenge.size(), proofOfOwnershipCborSize, signatureOfToBeSigned.data())) { return std::nullopt; } return signatureOfToBeSigned; } } // namespace android::hardware::identity