/* * Copyright 2021, 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 "RemoteSecureHardwareProxy" #include "RemoteSecureHardwareProxy.h" #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 { // ---------------------------------------------------------------------- RemoteSecureHardwareProvisioningProxy::RemoteSecureHardwareProvisioningProxy() { } RemoteSecureHardwareProvisioningProxy:: ~RemoteSecureHardwareProvisioningProxy() {} bool RemoteSecureHardwareProvisioningProxy::shutdown() { LOG(INFO) << "RemoteSecureHardwarePresentationProxy shutdown"; return true; } bool RemoteSecureHardwareProvisioningProxy::initialize(bool testCredential) { LOG(INFO) << "RemoteSecureHardwareProvisioningProxy created, " "sizeof(EicProvisioning): " << sizeof(EicProvisioning); return eicProvisioningInit(&ctx_, testCredential); } bool RemoteSecureHardwareProvisioningProxy::initializeForUpdate( bool testCredential, string docType, vector encryptedCredentialKeys) { return eicProvisioningInitForUpdate( &ctx_, testCredential, docType.c_str(), docType.size(), encryptedCredentialKeys.data(), encryptedCredentialKeys.size()); } // Returns public key certificate. optional> RemoteSecureHardwareProvisioningProxy::createCredentialKey( const vector& challenge, const vector& applicationId) { uint8_t publicKeyCert[4096]; size_t publicKeyCertSize = sizeof publicKeyCert; if (!eicProvisioningCreateCredentialKey( &ctx_, challenge.data(), challenge.size(), applicationId.data(), applicationId.size(), publicKeyCert, &publicKeyCertSize)) { return {}; } vector pubKeyCert(publicKeyCertSize); memcpy(pubKeyCert.data(), publicKeyCert, publicKeyCertSize); return pubKeyCert; } bool RemoteSecureHardwareProvisioningProxy::startPersonalization( int accessControlProfileCount, vector entryCounts, const string& docType, size_t expectedProofOfProvisioningSize) { if (!eicProvisioningStartPersonalization( &ctx_, accessControlProfileCount, entryCounts.data(), entryCounts.size(), docType.c_str(), docType.size(), expectedProofOfProvisioningSize)) { return false; } return true; } // Returns MAC (28 bytes). optional> RemoteSecureHardwareProvisioningProxy::addAccessControlProfile( int id, const vector& readerCertificate, bool userAuthenticationRequired, uint64_t timeoutMillis, uint64_t secureUserId) { vector mac(28); uint8_t scratchSpace[512]; if (!eicProvisioningAddAccessControlProfile( &ctx_, id, readerCertificate.data(), readerCertificate.size(), userAuthenticationRequired, timeoutMillis, secureUserId, mac.data(), scratchSpace, sizeof(scratchSpace))) { return {}; } return mac; } bool RemoteSecureHardwareProvisioningProxy::beginAddEntry( const vector& accessControlProfileIds, const string& nameSpace, const string& name, uint64_t entrySize) { 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> RemoteSecureHardwareProvisioningProxy::addEntryValue( const vector& accessControlProfileIds, const string& nameSpace, const string& name, const vector& content) { 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 {}; } return eicEncryptedContent; } // Returns signatureOfToBeSigned (EIC_ECDSA_P256_SIGNATURE_SIZE bytes). optional> RemoteSecureHardwareProvisioningProxy::finishAddingEntries() { vector signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE); if (!eicProvisioningFinishAddingEntries(&ctx_, signatureOfToBeSigned.data())) { return {}; } return signatureOfToBeSigned; } // Returns encryptedCredentialKeys. optional> RemoteSecureHardwareProvisioningProxy::finishGetCredentialData( const string& docType) { vector encryptedCredentialKeys(116); size_t size = encryptedCredentialKeys.size(); if (!eicProvisioningFinishGetCredentialData( &ctx_, docType.c_str(), docType.size(), encryptedCredentialKeys.data(), &size)) { return {}; } encryptedCredentialKeys.resize(size); return encryptedCredentialKeys; } // ---------------------------------------------------------------------- RemoteSecureHardwarePresentationProxy::RemoteSecureHardwarePresentationProxy() { } RemoteSecureHardwarePresentationProxy:: ~RemoteSecureHardwarePresentationProxy() {} bool RemoteSecureHardwarePresentationProxy::initialize( bool testCredential, string docType, vector encryptedCredentialKeys) { LOG(INFO) << "RemoteSecureHardwarePresentationProxy created, " "sizeof(EicPresentation): " << sizeof(EicPresentation); return eicPresentationInit(&ctx_, testCredential, docType.c_str(), docType.size(), encryptedCredentialKeys.data(), encryptedCredentialKeys.size()); } // Returns publicKeyCert (1st component) and signingKeyBlob (2nd component) optional, vector>> RemoteSecureHardwarePresentationProxy::generateSigningKeyPair(string docType, time_t now) { 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 {}; } vector cert; cert.resize(publicKeyCertSize); memcpy(cert.data(), publicKeyCert, publicKeyCertSize); return std::make_pair(cert, signingKeyBlob); } // Returns private key optional> RemoteSecureHardwarePresentationProxy::createEphemeralKeyPair() { vector priv(EIC_P256_PRIV_KEY_SIZE); if (!eicPresentationCreateEphemeralKeyPair(&ctx_, priv.data())) { return {}; } return priv; } optional RemoteSecureHardwarePresentationProxy::createAuthChallenge() { uint64_t challenge; if (!eicPresentationCreateAuthChallenge(&ctx_, &challenge)) { return {}; } return challenge; } bool RemoteSecureHardwarePresentationProxy::shutdown() { LOG(INFO) << "RemoteSecureHardwarePresentationProxy shutdown"; return true; } bool RemoteSecureHardwarePresentationProxy::pushReaderCert( const vector& certX509) { return eicPresentationPushReaderCert(&ctx_, certX509.data(), certX509.size()); } bool RemoteSecureHardwarePresentationProxy::validateRequestMessage( const vector& sessionTranscript, const vector& requestMessage, int coseSignAlg, const vector& readerSignatureOfToBeSigned) { return eicPresentationValidateRequestMessage( &ctx_, sessionTranscript.data(), sessionTranscript.size(), requestMessage.data(), requestMessage.size(), coseSignAlg, readerSignatureOfToBeSigned.data(), readerSignatureOfToBeSigned.size()); } bool RemoteSecureHardwarePresentationProxy::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) { return eicPresentationSetAuthToken( &ctx_, challenge, secureUserId, authenticatorId, hardwareAuthenticatorType, timeStamp, mac.data(), mac.size(), verificationTokenChallenge, verificationTokenTimestamp, verificationTokenSecurityLevel, verificationTokenMac.data(), verificationTokenMac.size()); } optional RemoteSecureHardwarePresentationProxy::validateAccessControlProfile( int id, const vector& readerCertificate, bool userAuthenticationRequired, int timeoutMillis, uint64_t secureUserId, const vector& mac) { 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 {}; } return accessGranted; } bool RemoteSecureHardwarePresentationProxy::startRetrieveEntries() { return eicPresentationStartRetrieveEntries(&ctx_); } bool RemoteSecureHardwarePresentationProxy::calcMacKey( const vector& sessionTranscript, const vector& readerEphemeralPublicKey, const vector& signingKeyBlob, const string& docType, unsigned int numNamespacesWithValues, size_t expectedProofOfProvisioningSize) { if (signingKeyBlob.size() != 60) { eicDebug("Unexpected size %zd of signingKeyBlob, expected 60", signingKeyBlob.size()); return false; } return eicPresentationCalcMacKey( &ctx_, sessionTranscript.data(), sessionTranscript.size(), readerEphemeralPublicKey.data(), signingKeyBlob.data(), docType.c_str(), docType.size(), numNamespacesWithValues, expectedProofOfProvisioningSize); } AccessCheckResult RemoteSecureHardwarePresentationProxy::startRetrieveEntryValue( const string& nameSpace, const string& name, unsigned int newNamespaceNumEntries, int32_t entrySize, const vector& accessControlProfileIds) { 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> RemoteSecureHardwarePresentationProxy::retrieveEntryValue( const vector& encryptedContent, const string& nameSpace, const string& name, const vector& accessControlProfileIds) { 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 {}; } return content; } optional> RemoteSecureHardwarePresentationProxy::finishRetrieval() { vector mac(32); size_t macSize = 32; if (!eicPresentationFinishRetrieval(&ctx_, mac.data(), &macSize)) { return {}; } mac.resize(macSize); return mac; } optional> RemoteSecureHardwarePresentationProxy::deleteCredential( const string& docType, const vector& challenge, bool includeChallenge, size_t proofOfDeletionCborSize) { vector signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE); if (!eicPresentationDeleteCredential( &ctx_, docType.c_str(), docType.size(), challenge.data(), challenge.size(), includeChallenge, proofOfDeletionCborSize, signatureOfToBeSigned.data())) { return {}; } return signatureOfToBeSigned; } optional> RemoteSecureHardwarePresentationProxy::proveOwnership( const string& docType, bool testCredential, const vector& challenge, size_t proofOfOwnershipCborSize) { vector signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE); if (!eicPresentationProveOwnership(&ctx_, docType.c_str(), docType.size(), testCredential, challenge.data(), challenge.size(), proofOfOwnershipCborSize, signatureOfToBeSigned.data())) { return {}; } return signatureOfToBeSigned; } } // namespace android::hardware::identity