| /* |
| * Copyright (C) 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. |
| */ |
| |
| #include "km_compat.h" |
| |
| #include "km_compat_type_conversion.h" |
| #include <AndroidKeyMintDevice.h> |
| #include <aidl/android/hardware/security/keymint/Algorithm.h> |
| #include <aidl/android/hardware/security/keymint/Digest.h> |
| #include <aidl/android/hardware/security/keymint/ErrorCode.h> |
| #include <aidl/android/hardware/security/keymint/KeyParameterValue.h> |
| #include <aidl/android/hardware/security/keymint/PaddingMode.h> |
| #include <aidl/android/system/keystore2/ResponseCode.h> |
| #include <android-base/logging.h> |
| #include <android/hidl/manager/1.2/IServiceManager.h> |
| #include <binder/IServiceManager.h> |
| #include <hardware/keymaster_defs.h> |
| #include <keymasterV4_1/Keymaster.h> |
| #include <keymasterV4_1/Keymaster3.h> |
| #include <keymasterV4_1/Keymaster4.h> |
| |
| #include <chrono> |
| |
| #include "certificate_utils.h" |
| |
| using ::aidl::android::hardware::security::keymint::Algorithm; |
| using ::aidl::android::hardware::security::keymint::CreateKeyMintDevice; |
| using ::aidl::android::hardware::security::keymint::Digest; |
| using ::aidl::android::hardware::security::keymint::KeyParameterValue; |
| using ::aidl::android::hardware::security::keymint::PaddingMode; |
| using ::aidl::android::hardware::security::keymint::Tag; |
| using ::aidl::android::system::keystore2::ResponseCode; |
| using ::android::hardware::hidl_vec; |
| using ::android::hardware::keymaster::V4_0::TagType; |
| using ::android::hidl::manager::V1_2::IServiceManager; |
| using V4_0_HardwareAuthToken = ::android::hardware::keymaster::V4_0::HardwareAuthToken; |
| using V4_0_HmacSharingParameters = ::android::hardware::keymaster::V4_0::HmacSharingParameters; |
| using V4_0_KeyCharacteristics = ::android::hardware::keymaster::V4_0::KeyCharacteristics; |
| using V4_0_KeyFormat = ::android::hardware::keymaster::V4_0::KeyFormat; |
| using V4_0_KeyParameter = ::android::hardware::keymaster::V4_0::KeyParameter; |
| using V4_0_VerificationToken = ::android::hardware::keymaster::V4_0::VerificationToken; |
| namespace V4_0 = ::android::hardware::keymaster::V4_0; |
| namespace V4_1 = ::android::hardware::keymaster::V4_1; |
| namespace KMV1 = ::aidl::android::hardware::security::keymint; |
| |
| using namespace std::chrono_literals; |
| using std::chrono::duration_cast; |
| |
| // Utility functions |
| |
| // Returns true if this parameter may be passed to attestKey. |
| bool isAttestationParameter(const KMV1::KeyParameter& param) { |
| switch (param.tag) { |
| case Tag::APPLICATION_ID: |
| case Tag::APPLICATION_DATA: |
| case Tag::ATTESTATION_CHALLENGE: |
| case Tag::ATTESTATION_APPLICATION_ID: |
| case Tag::ATTESTATION_ID_BRAND: |
| case Tag::ATTESTATION_ID_DEVICE: |
| case Tag::ATTESTATION_ID_PRODUCT: |
| case Tag::ATTESTATION_ID_SERIAL: |
| case Tag::ATTESTATION_ID_IMEI: |
| case Tag::ATTESTATION_ID_MEID: |
| case Tag::ATTESTATION_ID_MANUFACTURER: |
| case Tag::ATTESTATION_ID_MODEL: |
| case Tag::CERTIFICATE_SERIAL: |
| case Tag::CERTIFICATE_SUBJECT: |
| case Tag::CERTIFICATE_NOT_BEFORE: |
| case Tag::CERTIFICATE_NOT_AFTER: |
| case Tag::INCLUDE_UNIQUE_ID: |
| case Tag::DEVICE_UNIQUE_ATTESTATION: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| // Returns true if this parameter may be passed to generate/importKey. |
| bool isKeyCreationParameter(const KMV1::KeyParameter& param) { |
| switch (param.tag) { |
| case Tag::APPLICATION_ID: |
| case Tag::APPLICATION_DATA: |
| case Tag::CERTIFICATE_SERIAL: |
| case Tag::CERTIFICATE_SUBJECT: |
| case Tag::CERTIFICATE_NOT_BEFORE: |
| case Tag::CERTIFICATE_NOT_AFTER: |
| case Tag::PURPOSE: |
| case Tag::ALGORITHM: |
| case Tag::KEY_SIZE: |
| case Tag::BLOCK_MODE: |
| case Tag::DIGEST: |
| case Tag::PADDING: |
| case Tag::CALLER_NONCE: |
| case Tag::MIN_MAC_LENGTH: |
| case Tag::EC_CURVE: |
| case Tag::RSA_PUBLIC_EXPONENT: |
| case Tag::RSA_OAEP_MGF_DIGEST: |
| case Tag::BOOTLOADER_ONLY: |
| case Tag::ROLLBACK_RESISTANCE: |
| case Tag::EARLY_BOOT_ONLY: |
| case Tag::ACTIVE_DATETIME: |
| case Tag::ORIGINATION_EXPIRE_DATETIME: |
| case Tag::USAGE_EXPIRE_DATETIME: |
| case Tag::MIN_SECONDS_BETWEEN_OPS: |
| case Tag::MAX_USES_PER_BOOT: |
| case Tag::USAGE_COUNT_LIMIT: |
| case Tag::USER_ID: |
| case Tag::USER_SECURE_ID: |
| case Tag::NO_AUTH_REQUIRED: |
| case Tag::USER_AUTH_TYPE: |
| case Tag::AUTH_TIMEOUT: |
| case Tag::ALLOW_WHILE_ON_BODY: |
| case Tag::TRUSTED_USER_PRESENCE_REQUIRED: |
| case Tag::TRUSTED_CONFIRMATION_REQUIRED: |
| case Tag::UNLOCKED_DEVICE_REQUIRED: |
| case Tag::CREATION_DATETIME: |
| case Tag::UNIQUE_ID: |
| case Tag::IDENTITY_CREDENTIAL_KEY: |
| case Tag::STORAGE_KEY: |
| case Tag::MAC_LENGTH: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| // Size of prefix for blobs, see keyBlobPrefix(). |
| // |
| const size_t kKeyBlobPrefixSize = 8; |
| |
| // Magic used in blob prefix, see keyBlobPrefix(). |
| // |
| const uint8_t kKeyBlobMagic[7] = {'p', 'K', 'M', 'b', 'l', 'o', 'b'}; |
| |
| // Prefixes a keyblob returned by e.g. generateKey() with information on whether it |
| // originated from the real underlying KeyMaster HAL or from soft-KeyMint. |
| // |
| // When dealing with a keyblob, use prefixedKeyBlobRemovePrefix() to remove the |
| // prefix and prefixedKeyBlobIsSoftKeyMint() to determine its origin. |
| // |
| // Note how the prefix itself has a magic marker ("pKMblob") which can be used |
| // to identify if a blob has a prefix at all (it's assumed that any valid blob |
| // from KeyMint or KeyMaster HALs never starts with the magic). This is needed |
| // because blobs persisted to disk prior to using this code will not have the |
| // prefix and in that case we want prefixedKeyBlobRemovePrefix() to still work. |
| // |
| std::vector<uint8_t> keyBlobPrefix(const std::vector<uint8_t>& blob, bool isSoftKeyMint) { |
| std::vector<uint8_t> result; |
| result.reserve(blob.size() + kKeyBlobPrefixSize); |
| result.insert(result.begin(), kKeyBlobMagic, kKeyBlobMagic + sizeof kKeyBlobMagic); |
| result.push_back(isSoftKeyMint ? 1 : 0); |
| std::copy(blob.begin(), blob.end(), std::back_inserter(result)); |
| return result; |
| } |
| |
| // Helper for prefixedKeyBlobRemovePrefix() and prefixedKeyBlobIsSoftKeyMint(). |
| // |
| // First bool is whether there's a valid prefix. If there is, the second bool is |
| // the |isSoftKeyMint| value of the prefix |
| // |
| std::pair<bool, bool> prefixedKeyBlobParsePrefix(const std::vector<uint8_t>& prefixedBlob) { |
| // Having a unprefixed blob is not that uncommon, for example all devices |
| // upgrading to keystore2 (so e.g. upgrading to Android 12) will have |
| // unprefixed blobs. So don't spew warnings/errors in this case... |
| if (prefixedBlob.size() < kKeyBlobPrefixSize) { |
| return std::make_pair(false, false); |
| } |
| if (std::memcmp(prefixedBlob.data(), kKeyBlobMagic, sizeof kKeyBlobMagic) != 0) { |
| return std::make_pair(false, false); |
| } |
| if (prefixedBlob[kKeyBlobPrefixSize - 1] != 0 && prefixedBlob[kKeyBlobPrefixSize - 1] != 1) { |
| return std::make_pair(false, false); |
| } |
| bool isSoftKeyMint = (prefixedBlob[kKeyBlobPrefixSize - 1] == 1); |
| return std::make_pair(true, isSoftKeyMint); |
| } |
| |
| // Removes the prefix from a blob. If there's no prefix, returns the passed-in blob. |
| // |
| std::vector<uint8_t> prefixedKeyBlobRemovePrefix(const std::vector<uint8_t>& prefixedBlob) { |
| auto parsed = prefixedKeyBlobParsePrefix(prefixedBlob); |
| if (!parsed.first) { |
| // Not actually prefixed, blob was probably persisted to disk prior to the |
| // prefixing code being introduced. |
| return prefixedBlob; |
| } |
| return std::vector<uint8_t>(prefixedBlob.begin() + kKeyBlobPrefixSize, prefixedBlob.end()); |
| } |
| |
| // Returns true if the blob's origin is soft-KeyMint, false otherwise or if there |
| // is no prefix on the passed-in blob. |
| // |
| bool prefixedKeyBlobIsSoftKeyMint(const std::vector<uint8_t>& prefixedBlob) { |
| auto parsed = prefixedKeyBlobParsePrefix(prefixedBlob); |
| return parsed.second; |
| } |
| |
| // Inspects the given blob for prefixes. |
| // Returns the blob stripped of the prefix if present. The boolean argument is true if the blob was |
| // a software blob. |
| std::pair<std::vector<uint8_t>, bool> |
| dissectPrefixedKeyBlob(const std::vector<uint8_t>& prefixedBlob) { |
| auto [hasPrefix, isSoftware] = prefixedKeyBlobParsePrefix(prefixedBlob); |
| if (!hasPrefix) { |
| // Not actually prefixed, blob was probably persisted to disk prior to the |
| // prefixing code being introduced. |
| return {prefixedBlob, false}; |
| } |
| return {std::vector<uint8_t>(prefixedBlob.begin() + kKeyBlobPrefixSize, prefixedBlob.end()), |
| isSoftware}; |
| } |
| |
| /* |
| * Returns true if the parameter is not understood by KM 4.1 and older but can be enforced by |
| * Keystore. These parameters need to be included in the returned KeyCharacteristics, but will not |
| * be passed to the legacy backend. |
| */ |
| bool isNewAndKeystoreEnforceable(const KMV1::KeyParameter& param) { |
| switch (param.tag) { |
| case KMV1::Tag::MAX_BOOT_LEVEL: |
| return true; |
| case KMV1::Tag::USAGE_COUNT_LIMIT: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| std::vector<KMV1::KeyParameter> |
| extractGenerationParams(const std::vector<KMV1::KeyParameter>& params) { |
| std::vector<KMV1::KeyParameter> result; |
| std::copy_if(params.begin(), params.end(), std::back_inserter(result), isKeyCreationParameter); |
| return result; |
| } |
| |
| std::vector<KMV1::KeyParameter> |
| extractAttestationParams(const std::vector<KMV1::KeyParameter>& params) { |
| std::vector<KMV1::KeyParameter> result; |
| std::copy_if(params.begin(), params.end(), std::back_inserter(result), isAttestationParameter); |
| return result; |
| } |
| |
| std::vector<KMV1::KeyParameter> |
| extractNewAndKeystoreEnforceableParams(const std::vector<KMV1::KeyParameter>& params) { |
| std::vector<KMV1::KeyParameter> result; |
| std::copy_if(params.begin(), params.end(), std::back_inserter(result), |
| isNewAndKeystoreEnforceable); |
| return result; |
| } |
| |
| ScopedAStatus convertErrorCode(KMV1::ErrorCode result) { |
| if (result == KMV1::ErrorCode::OK) { |
| return ScopedAStatus::ok(); |
| } |
| return ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(result)); |
| } |
| |
| // Converts a V4 error code into a ScopedAStatus |
| ScopedAStatus convertErrorCode(V4_0_ErrorCode result) { |
| return convertErrorCode(convert(result)); |
| } |
| |
| static KMV1::ErrorCode toErrorCode(const ScopedAStatus& status) { |
| if (status.getExceptionCode() == EX_SERVICE_SPECIFIC) { |
| return static_cast<KMV1::ErrorCode>(status.getServiceSpecificError()); |
| } else { |
| return KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| } |
| |
| static std::vector<V4_0::KeyParameter> |
| convertKeyParametersToLegacy(const std::vector<KeyParameter>& kps) { |
| std::vector<V4_0::KeyParameter> legacyKps; |
| legacyKps.reserve(kps.size()); |
| for (const auto& kp : kps) { |
| auto p = convertKeyParameterToLegacy(kp); |
| if (p.tag != V4_0::Tag::INVALID) { |
| legacyKps.push_back(std::move(p)); |
| } |
| } |
| return legacyKps; |
| } |
| |
| static std::vector<KeyParameter> |
| convertKeyParametersFromLegacy(const std::vector<V4_0_KeyParameter>& legacyKps) { |
| std::vector<KeyParameter> kps(legacyKps.size()); |
| std::transform(legacyKps.begin(), legacyKps.end(), kps.begin(), convertKeyParameterFromLegacy); |
| return kps; |
| } |
| |
| static std::vector<KeyCharacteristics> |
| processLegacyCharacteristics(KeyMintSecurityLevel securityLevel, |
| const std::vector<KeyParameter>& genParams, |
| const V4_0_KeyCharacteristics& legacyKc, bool kmEnforcedOnly = false) { |
| |
| KeyCharacteristics kmEnforced{securityLevel, convertKeyParametersFromLegacy( |
| securityLevel == KeyMintSecurityLevel::SOFTWARE |
| ? legacyKc.softwareEnforced |
| : legacyKc.hardwareEnforced)}; |
| |
| if (securityLevel == KeyMintSecurityLevel::SOFTWARE && legacyKc.hardwareEnforced.size() > 0) { |
| LOG(WARNING) << "Unexpected hardware enforced parameters."; |
| } |
| |
| if (kmEnforcedOnly) { |
| return {kmEnforced}; |
| } |
| |
| KeyCharacteristics keystoreEnforced{KeyMintSecurityLevel::KEYSTORE, {}}; |
| |
| if (securityLevel != KeyMintSecurityLevel::SOFTWARE) { |
| // Don't include these tags on software backends, else they'd end up duplicated |
| // across both the keystore-enforced and software keymaster-enforced tags. |
| keystoreEnforced.authorizations = convertKeyParametersFromLegacy(legacyKc.softwareEnforced); |
| } |
| |
| // Add all parameters that we know can be enforced by keystore but not by the legacy backend. |
| auto unsupported_requested = extractNewAndKeystoreEnforceableParams(genParams); |
| keystoreEnforced.authorizations.insert(keystoreEnforced.authorizations.end(), |
| std::begin(unsupported_requested), |
| std::end(unsupported_requested)); |
| |
| return {kmEnforced, keystoreEnforced}; |
| } |
| |
| static V4_0_KeyFormat convertKeyFormatToLegacy(const KeyFormat& kf) { |
| return static_cast<V4_0_KeyFormat>(kf); |
| } |
| |
| static V4_0_HardwareAuthToken convertAuthTokenToLegacy(const std::optional<HardwareAuthToken>& at) { |
| if (!at) return {}; |
| |
| V4_0_HardwareAuthToken legacyAt; |
| legacyAt.challenge = at->challenge; |
| legacyAt.userId = at->userId; |
| legacyAt.authenticatorId = at->authenticatorId; |
| legacyAt.authenticatorType = |
| static_cast<::android::hardware::keymaster::V4_0::HardwareAuthenticatorType>( |
| at->authenticatorType); |
| legacyAt.timestamp = at->timestamp.milliSeconds; |
| legacyAt.mac = at->mac; |
| return legacyAt; |
| } |
| |
| static V4_0_VerificationToken |
| convertTimestampTokenToLegacy(const std::optional<TimeStampToken>& tst) { |
| if (!tst) return {}; |
| |
| V4_0_VerificationToken legacyVt; |
| legacyVt.challenge = tst->challenge; |
| legacyVt.timestamp = tst->timestamp.milliSeconds; |
| // Legacy verification tokens were always minted by TEE. |
| legacyVt.securityLevel = V4_0::SecurityLevel::TRUSTED_ENVIRONMENT; |
| legacyVt.mac = tst->mac; |
| return legacyVt; |
| } |
| |
| static V4_0_HmacSharingParameters |
| convertSharedSecretParameterToLegacy(const SharedSecretParameters& ssp) { |
| V4_0_HmacSharingParameters legacyHsp; |
| legacyHsp.seed = ssp.seed; |
| std::copy(ssp.nonce.begin(), ssp.nonce.end(), legacyHsp.nonce.data()); |
| return legacyHsp; |
| } |
| |
| static std::vector<V4_0_HmacSharingParameters> |
| convertSharedSecretParametersToLegacy(const std::vector<SharedSecretParameters>& legacySsps) { |
| std::vector<V4_0_HmacSharingParameters> ssps(legacySsps.size()); |
| std::transform(legacySsps.begin(), legacySsps.end(), ssps.begin(), |
| convertSharedSecretParameterToLegacy); |
| return ssps; |
| } |
| |
| void OperationSlots::setNumFreeSlots(uint8_t numFreeSlots) { |
| std::lock_guard<std::mutex> lock(mNumFreeSlotsMutex); |
| mNumFreeSlots = numFreeSlots; |
| } |
| |
| bool OperationSlots::claimSlot() { |
| std::lock_guard<std::mutex> lock(mNumFreeSlotsMutex); |
| if (mNumFreeSlots > 0) { |
| mNumFreeSlots--; |
| return true; |
| } |
| return false; |
| } |
| |
| void OperationSlots::freeSlot() { |
| std::lock_guard<std::mutex> lock(mNumFreeSlotsMutex); |
| mNumFreeSlots++; |
| } |
| |
| void OperationSlot::freeSlot() { |
| if (mIsActive) { |
| mOperationSlots->freeSlot(); |
| mIsActive = false; |
| } |
| } |
| |
| // KeyMintDevice implementation |
| |
| ScopedAStatus KeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* _aidl_return) { |
| auto result = mDevice->halVersion(); |
| _aidl_return->versionNumber = result.majorVersion * 10 + result.minorVersion; |
| securityLevel_ = convert(result.securityLevel); |
| _aidl_return->securityLevel = securityLevel_; |
| _aidl_return->keyMintName = result.keymasterName; |
| _aidl_return->keyMintAuthorName = result.authorName; |
| _aidl_return->timestampTokenRequired = securityLevel_ == KMV1::SecurityLevel::STRONGBOX; |
| return ScopedAStatus::ok(); |
| } |
| |
| ScopedAStatus KeyMintDevice::addRngEntropy(const std::vector<uint8_t>& in_data) { |
| auto result = mDevice->addRngEntropy(in_data); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } |
| return convertErrorCode(result); |
| } |
| |
| ScopedAStatus KeyMintDevice::generateKey(const std::vector<KeyParameter>& inKeyParams, |
| const std::optional<AttestationKey>& in_attestationKey, |
| KeyCreationResult* out_creationResult) { |
| |
| // Since KeyMaster doesn't support ECDH, route all key creation requests to |
| // soft-KeyMint if and only an ECDH key is requested. |
| // |
| // For this to work we'll need to also route begin() and deleteKey() calls to |
| // soft-KM. In order to do that, we'll prefix all keyblobs with whether it was |
| // created by the real underlying KeyMaster HAL or whether it was created by |
| // soft-KeyMint. |
| // |
| // See keyBlobPrefix() for more discussion. |
| // |
| for (const auto& keyParam : inKeyParams) { |
| if (keyParam.tag == Tag::PURPOSE && |
| keyParam.value.get<KeyParameterValue::Tag::keyPurpose>() == KeyPurpose::AGREE_KEY) { |
| auto ret = |
| softKeyMintDevice_->generateKey(inKeyParams, in_attestationKey, out_creationResult); |
| if (ret.isOk()) { |
| out_creationResult->keyBlob = keyBlobPrefix(out_creationResult->keyBlob, true); |
| } |
| return ret; |
| } |
| } |
| |
| auto legacyKeyGenParams = convertKeyParametersToLegacy(extractGenerationParams(inKeyParams)); |
| KMV1::ErrorCode errorCode; |
| auto result = mDevice->generateKey( |
| legacyKeyGenParams, [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyBlob, |
| const V4_0_KeyCharacteristics& keyCharacteristics) { |
| errorCode = convert(error); |
| out_creationResult->keyBlob = keyBlobPrefix(keyBlob, false); |
| out_creationResult->keyCharacteristics = |
| processLegacyCharacteristics(securityLevel_, inKeyParams, keyCharacteristics); |
| }); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } |
| if (errorCode == KMV1::ErrorCode::OK) { |
| auto cert = getCertificate(inKeyParams, out_creationResult->keyBlob); |
| if (std::holds_alternative<KMV1::ErrorCode>(cert)) { |
| auto code = std::get<KMV1::ErrorCode>(cert); |
| // We return OK in successful cases that do not generate a certificate. |
| if (code != KMV1::ErrorCode::OK) { |
| errorCode = code; |
| deleteKey(out_creationResult->keyBlob); |
| } |
| } else { |
| out_creationResult->certificateChain = std::get<std::vector<Certificate>>(cert); |
| } |
| } |
| return convertErrorCode(errorCode); |
| } |
| |
| ScopedAStatus KeyMintDevice::importKey(const std::vector<KeyParameter>& inKeyParams, |
| KeyFormat in_inKeyFormat, |
| const std::vector<uint8_t>& in_inKeyData, |
| const std::optional<AttestationKey>& /* in_attestationKey */, |
| KeyCreationResult* out_creationResult) { |
| auto legacyKeyGENParams = convertKeyParametersToLegacy(extractGenerationParams(inKeyParams)); |
| auto legacyKeyFormat = convertKeyFormatToLegacy(in_inKeyFormat); |
| KMV1::ErrorCode errorCode; |
| auto result = mDevice->importKey(legacyKeyGENParams, legacyKeyFormat, in_inKeyData, |
| [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyBlob, |
| const V4_0_KeyCharacteristics& keyCharacteristics) { |
| errorCode = convert(error); |
| out_creationResult->keyBlob = |
| keyBlobPrefix(keyBlob, false); |
| out_creationResult->keyCharacteristics = |
| processLegacyCharacteristics( |
| securityLevel_, inKeyParams, keyCharacteristics); |
| }); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } |
| if (errorCode == KMV1::ErrorCode::OK) { |
| auto cert = getCertificate(inKeyParams, out_creationResult->keyBlob); |
| if (std::holds_alternative<KMV1::ErrorCode>(cert)) { |
| auto code = std::get<KMV1::ErrorCode>(cert); |
| // We return OK in successful cases that do not generate a certificate. |
| if (code != KMV1::ErrorCode::OK) { |
| errorCode = code; |
| deleteKey(out_creationResult->keyBlob); |
| } |
| } else { |
| out_creationResult->certificateChain = std::get<std::vector<Certificate>>(cert); |
| } |
| } |
| return convertErrorCode(errorCode); |
| } |
| |
| ScopedAStatus |
| KeyMintDevice::importWrappedKey(const std::vector<uint8_t>& in_inWrappedKeyData, |
| const std::vector<uint8_t>& in_inPrefixedWrappingKeyBlob, |
| const std::vector<uint8_t>& in_inMaskingKey, |
| const std::vector<KeyParameter>& in_inUnwrappingParams, |
| int64_t in_inPasswordSid, int64_t in_inBiometricSid, |
| KeyCreationResult* out_creationResult) { |
| const std::vector<uint8_t>& wrappingKeyBlob = |
| prefixedKeyBlobRemovePrefix(in_inPrefixedWrappingKeyBlob); |
| if (prefixedKeyBlobIsSoftKeyMint(in_inPrefixedWrappingKeyBlob)) { |
| return softKeyMintDevice_->importWrappedKey( |
| in_inWrappedKeyData, wrappingKeyBlob, in_inMaskingKey, in_inUnwrappingParams, |
| in_inPasswordSid, in_inBiometricSid, out_creationResult); |
| } |
| |
| auto legacyUnwrappingParams = convertKeyParametersToLegacy(in_inUnwrappingParams); |
| KMV1::ErrorCode errorCode; |
| auto result = mDevice->importWrappedKey( |
| in_inWrappedKeyData, wrappingKeyBlob, in_inMaskingKey, legacyUnwrappingParams, |
| in_inPasswordSid, in_inBiometricSid, |
| [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyBlob, |
| const V4_0_KeyCharacteristics& keyCharacteristics) { |
| errorCode = convert(error); |
| out_creationResult->keyBlob = keyBlobPrefix(keyBlob, false); |
| out_creationResult->keyCharacteristics = |
| processLegacyCharacteristics(securityLevel_, {}, keyCharacteristics); |
| }); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } |
| return convertErrorCode(errorCode); |
| } |
| |
| ScopedAStatus KeyMintDevice::upgradeKey(const std::vector<uint8_t>& in_inKeyBlobToUpgrade, |
| const std::vector<KeyParameter>& in_inUpgradeParams, |
| std::vector<uint8_t>* _aidl_return) { |
| auto legacyUpgradeParams = convertKeyParametersToLegacy(in_inUpgradeParams); |
| V4_0_ErrorCode errorCode; |
| |
| auto result = |
| mDevice->upgradeKey(prefixedKeyBlobRemovePrefix(in_inKeyBlobToUpgrade), legacyUpgradeParams, |
| [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& upgradedKeyBlob) { |
| errorCode = error; |
| *_aidl_return = keyBlobPrefix(upgradedKeyBlob, false); |
| }); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } |
| return convertErrorCode(errorCode); |
| } |
| |
| ScopedAStatus KeyMintDevice::deleteKey(const std::vector<uint8_t>& prefixedKeyBlob) { |
| const std::vector<uint8_t>& keyBlob = prefixedKeyBlobRemovePrefix(prefixedKeyBlob); |
| if (prefixedKeyBlobIsSoftKeyMint(prefixedKeyBlob)) { |
| return softKeyMintDevice_->deleteKey(keyBlob); |
| } |
| |
| auto result = mDevice->deleteKey(keyBlob); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } |
| return convertErrorCode(result); |
| } |
| |
| ScopedAStatus KeyMintDevice::deleteAllKeys() { |
| auto result = mDevice->deleteAllKeys(); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } |
| return convertErrorCode(result); |
| } |
| |
| // We're not implementing this. |
| ScopedAStatus KeyMintDevice::destroyAttestationIds() { |
| return ScopedAStatus::fromServiceSpecificError( |
| static_cast<int32_t>(V4_0_ErrorCode::UNIMPLEMENTED)); |
| } |
| |
| ScopedAStatus KeyMintDevice::begin(KeyPurpose in_inPurpose, |
| const std::vector<uint8_t>& prefixedKeyBlob, |
| const std::vector<KeyParameter>& in_inParams, |
| const std::optional<HardwareAuthToken>& in_inAuthToken, |
| BeginResult* _aidl_return) { |
| if (!mOperationSlots.claimSlot()) { |
| return convertErrorCode(V4_0_ErrorCode::TOO_MANY_OPERATIONS); |
| } |
| |
| const std::vector<uint8_t>& in_inKeyBlob = prefixedKeyBlobRemovePrefix(prefixedKeyBlob); |
| if (prefixedKeyBlobIsSoftKeyMint(prefixedKeyBlob)) { |
| return softKeyMintDevice_->begin(in_inPurpose, in_inKeyBlob, in_inParams, in_inAuthToken, |
| _aidl_return); |
| } |
| |
| auto legacyPurpose = |
| static_cast<::android::hardware::keymaster::V4_0::KeyPurpose>(in_inPurpose); |
| auto legacyParams = convertKeyParametersToLegacy(in_inParams); |
| auto legacyAuthToken = convertAuthTokenToLegacy(in_inAuthToken); |
| KMV1::ErrorCode errorCode; |
| auto result = mDevice->begin( |
| legacyPurpose, in_inKeyBlob, legacyParams, legacyAuthToken, |
| [&](V4_0_ErrorCode error, const hidl_vec<V4_0_KeyParameter>& outParams, |
| uint64_t operationHandle) { |
| errorCode = convert(error); |
| _aidl_return->challenge = operationHandle; |
| _aidl_return->params = convertKeyParametersFromLegacy(outParams); |
| _aidl_return->operation = ndk::SharedRefBase::make<KeyMintOperation>( |
| mDevice, operationHandle, &mOperationSlots, error == V4_0_ErrorCode::OK); |
| }); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| errorCode = KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| if (errorCode != KMV1::ErrorCode::OK) { |
| mOperationSlots.freeSlot(); |
| } |
| return convertErrorCode(errorCode); |
| } |
| |
| ScopedAStatus KeyMintDevice::deviceLocked(bool passwordOnly, |
| const std::optional<TimeStampToken>& timestampToken) { |
| V4_0_VerificationToken token; |
| if (timestampToken.has_value()) { |
| token = convertTimestampTokenToLegacy(timestampToken.value()); |
| } |
| auto ret = mDevice->deviceLocked(passwordOnly, token); |
| if (!ret.isOk()) { |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } else { |
| return convertErrorCode(KMV1::ErrorCode::OK); |
| } |
| } |
| |
| ScopedAStatus KeyMintDevice::earlyBootEnded() { |
| auto ret = mDevice->earlyBootEnded(); |
| if (!ret.isOk()) { |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } else { |
| return convertErrorCode(KMV1::ErrorCode::OK); |
| } |
| } |
| |
| ScopedAStatus |
| KeyMintDevice::convertStorageKeyToEphemeral(const std::vector<uint8_t>& prefixedStorageKeyBlob, |
| std::vector<uint8_t>* ephemeralKeyBlob) { |
| KMV1::ErrorCode km_error; |
| |
| /* |
| * Wrapped storage keys cannot be emulated (and they don't need to, because if a platform |
| * supports wrapped storage keys, then the legacy backend will support it too. So error out |
| * if the wrapped storage key given is a soft keymint key. |
| */ |
| if (prefixedKeyBlobIsSoftKeyMint(prefixedStorageKeyBlob)) { |
| return convertErrorCode(KMV1::ErrorCode::UNIMPLEMENTED); |
| } |
| |
| const std::vector<uint8_t>& storageKeyBlob = |
| prefixedKeyBlobRemovePrefix(prefixedStorageKeyBlob); |
| |
| auto hidlCb = [&](V4_0_ErrorCode ret, const hidl_vec<uint8_t>& exportedKeyBlob) { |
| km_error = convert(ret); |
| if (km_error != KMV1::ErrorCode::OK) return; |
| /* |
| * This must return the blob without the prefix since it will be used directly |
| * as a storage encryption key. But this is alright, since this wrapped ephemeral |
| * key shouldn't/won't ever be used with keymint. |
| */ |
| *ephemeralKeyBlob = exportedKeyBlob; |
| }; |
| |
| auto ret = mDevice->exportKey(V4_0_KeyFormat::RAW, storageKeyBlob, {}, {}, hidlCb); |
| if (!ret.isOk()) { |
| LOG(ERROR) << __func__ << " export_key failed: " << ret.description(); |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } |
| if (km_error != KMV1::ErrorCode::OK) |
| LOG(ERROR) << __func__ << " export_key failed, code " << int32_t(km_error); |
| |
| return convertErrorCode(km_error); |
| } |
| |
| ScopedAStatus KeyMintDevice::getKeyCharacteristics( |
| const std::vector<uint8_t>& prefixedKeyBlob, const std::vector<uint8_t>& appId, |
| const std::vector<uint8_t>& appData, std::vector<KeyCharacteristics>* keyCharacteristics) { |
| auto [strippedKeyBlob, isSoftware] = dissectPrefixedKeyBlob(prefixedKeyBlob); |
| if (isSoftware) { |
| return softKeyMintDevice_->getKeyCharacteristics(strippedKeyBlob, appId, appData, |
| keyCharacteristics); |
| } else { |
| KMV1::ErrorCode km_error; |
| auto ret = mDevice->getKeyCharacteristics( |
| strippedKeyBlob, appId, appData, |
| [&](V4_0_ErrorCode errorCode, const V4_0_KeyCharacteristics& v40KeyCharacteristics) { |
| km_error = convert(errorCode); |
| *keyCharacteristics = |
| processLegacyCharacteristics(securityLevel_, {} /* getParams */, |
| v40KeyCharacteristics, true /* kmEnforcedOnly */); |
| }); |
| |
| if (!ret.isOk()) { |
| LOG(ERROR) << __func__ << " getKeyCharacteristics failed: " << ret.description(); |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } |
| if (km_error != KMV1::ErrorCode::OK) { |
| LOG(ERROR) << __func__ |
| << " getKeyCharacteristics failed with code: " << toString(km_error); |
| } |
| |
| return convertErrorCode(km_error); |
| } |
| } |
| |
| ScopedAStatus KeyMintOperation::updateAad(const std::vector<uint8_t>& input, |
| const std::optional<HardwareAuthToken>& optAuthToken, |
| const std::optional<TimeStampToken>& optTimeStampToken) { |
| V4_0_HardwareAuthToken authToken = convertAuthTokenToLegacy(optAuthToken); |
| V4_0_VerificationToken verificationToken = convertTimestampTokenToLegacy(optTimeStampToken); |
| |
| KMV1::ErrorCode errorCode; |
| auto result = mDevice->update( |
| mOperationHandle, {V4_0::makeKeyParameter(V4_0::TAG_ASSOCIATED_DATA, input)}, {}, authToken, |
| verificationToken, |
| [&](V4_0_ErrorCode error, auto, auto, auto) { errorCode = convert(error); }); |
| |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| errorCode = KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| if (errorCode != KMV1::ErrorCode::OK) mOperationSlot.freeSlot(); |
| |
| return convertErrorCode(errorCode); |
| } |
| |
| void KeyMintOperation::setUpdateBuffer(std::vector<uint8_t> data) { |
| mUpdateBuffer = std::move(data); |
| } |
| |
| const std::vector<uint8_t>& |
| KeyMintOperation::getExtendedUpdateBuffer(const std::vector<uint8_t>& suffix) { |
| if (mUpdateBuffer.empty()) { |
| return suffix; |
| } else { |
| mUpdateBuffer.insert(mUpdateBuffer.end(), suffix.begin(), suffix.end()); |
| return mUpdateBuffer; |
| } |
| } |
| |
| ScopedAStatus KeyMintOperation::update(const std::vector<uint8_t>& input_raw, |
| const std::optional<HardwareAuthToken>& optAuthToken, |
| const std::optional<TimeStampToken>& optTimeStampToken, |
| std::vector<uint8_t>* out_output) { |
| V4_0_HardwareAuthToken authToken = convertAuthTokenToLegacy(optAuthToken); |
| V4_0_VerificationToken verificationToken = convertTimestampTokenToLegacy(optTimeStampToken); |
| |
| size_t inputPos = 0; |
| *out_output = {}; |
| KMV1::ErrorCode errorCode = KMV1::ErrorCode::OK; |
| auto input = getExtendedUpdateBuffer(input_raw); |
| |
| while (inputPos < input.size() && errorCode == KMV1::ErrorCode::OK) { |
| uint32_t consumed = 0; |
| auto result = |
| mDevice->update(mOperationHandle, {} /* inParams */, |
| {input.begin() + inputPos, input.end()}, authToken, verificationToken, |
| [&](V4_0_ErrorCode error, uint32_t inputConsumed, auto /* outParams */, |
| const hidl_vec<uint8_t>& output) { |
| errorCode = convert(error); |
| out_output->insert(out_output->end(), output.begin(), output.end()); |
| consumed = inputConsumed; |
| }); |
| |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| errorCode = KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| |
| if (errorCode == KMV1::ErrorCode::OK && consumed == 0) { |
| // Some very old KM implementations do not buffer sub blocks in certain block modes, |
| // instead, the simply return consumed == 0. So we buffer the input here in the |
| // hope that we complete the bock in a future call to update. |
| setUpdateBuffer({input.begin() + inputPos, input.end()}); |
| return convertErrorCode(errorCode); |
| } |
| inputPos += consumed; |
| } |
| |
| if (errorCode != KMV1::ErrorCode::OK) mOperationSlot.freeSlot(); |
| |
| return convertErrorCode(errorCode); |
| } |
| |
| ScopedAStatus |
| KeyMintOperation::finish(const std::optional<std::vector<uint8_t>>& in_input, |
| const std::optional<std::vector<uint8_t>>& in_signature, |
| const std::optional<HardwareAuthToken>& in_authToken, |
| const std::optional<TimeStampToken>& in_timeStampToken, |
| const std::optional<std::vector<uint8_t>>& in_confirmationToken, |
| std::vector<uint8_t>* out_output) { |
| auto input_raw = in_input.value_or(std::vector<uint8_t>()); |
| auto input = getExtendedUpdateBuffer(input_raw); |
| auto signature = in_signature.value_or(std::vector<uint8_t>()); |
| V4_0_HardwareAuthToken authToken = convertAuthTokenToLegacy(in_authToken); |
| V4_0_VerificationToken verificationToken = convertTimestampTokenToLegacy(in_timeStampToken); |
| |
| std::vector<V4_0_KeyParameter> inParams; |
| if (in_confirmationToken) { |
| inParams.push_back(makeKeyParameter(V4_0::TAG_CONFIRMATION_TOKEN, *in_confirmationToken)); |
| } |
| |
| KMV1::ErrorCode errorCode; |
| auto result = mDevice->finish( |
| mOperationHandle, inParams, input, signature, authToken, verificationToken, |
| [&](V4_0_ErrorCode error, auto /* outParams */, const hidl_vec<uint8_t>& output) { |
| errorCode = convert(error); |
| *out_output = output; |
| }); |
| |
| mOperationSlot.freeSlot(); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| errorCode = KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| return convertErrorCode(errorCode); |
| } |
| |
| ScopedAStatus KeyMintOperation::abort() { |
| auto result = mDevice->abort(mOperationHandle); |
| mOperationSlot.freeSlot(); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR); |
| } |
| return convertErrorCode(result); |
| } |
| |
| KeyMintOperation::~KeyMintOperation() { |
| if (mOperationSlot.hasSlot()) { |
| auto error = abort(); |
| if (!error.isOk()) { |
| LOG(WARNING) << "Error calling abort in ~KeyMintOperation: " << error.getMessage(); |
| } |
| } |
| } |
| |
| // SecureClock implementation |
| |
| ScopedAStatus SecureClock::generateTimeStamp(int64_t in_challenge, TimeStampToken* _aidl_return) { |
| KMV1::ErrorCode errorCode; |
| auto result = mDevice->verifyAuthorization( |
| in_challenge, {}, V4_0_HardwareAuthToken(), |
| [&](V4_0_ErrorCode error, const V4_0_VerificationToken& token) { |
| errorCode = convert(error); |
| _aidl_return->challenge = token.challenge; |
| _aidl_return->timestamp.milliSeconds = token.timestamp; |
| _aidl_return->mac = token.mac; |
| }); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| errorCode = KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| return convertErrorCode(errorCode); |
| } |
| |
| // SharedSecret implementation |
| |
| ScopedAStatus SharedSecret::getSharedSecretParameters(SharedSecretParameters* _aidl_return) { |
| KMV1::ErrorCode errorCode; |
| auto result = mDevice->getHmacSharingParameters( |
| [&](V4_0_ErrorCode error, const V4_0_HmacSharingParameters& params) { |
| errorCode = convert(error); |
| _aidl_return->seed = params.seed; |
| std::copy(params.nonce.data(), params.nonce.data() + params.nonce.elementCount(), |
| std::back_inserter(_aidl_return->nonce)); |
| }); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| errorCode = KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| return convertErrorCode(errorCode); |
| } |
| |
| ScopedAStatus |
| SharedSecret::computeSharedSecret(const std::vector<SharedSecretParameters>& in_params, |
| std::vector<uint8_t>* _aidl_return) { |
| KMV1::ErrorCode errorCode; |
| auto legacyParams = convertSharedSecretParametersToLegacy(in_params); |
| auto result = mDevice->computeSharedHmac( |
| legacyParams, [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& sharingCheck) { |
| errorCode = convert(error); |
| *_aidl_return = sharingCheck; |
| }); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " transaction failed. " << result.description(); |
| errorCode = KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| return convertErrorCode(errorCode); |
| } |
| |
| // Certificate implementation |
| |
| template <KMV1::Tag tag, KMV1::TagType type> |
| static auto getParam(const std::vector<KeyParameter>& keyParams, KMV1::TypedTag<type, tag> ttag) |
| -> decltype(authorizationValue(ttag, KeyParameter())) { |
| for (const auto& p : keyParams) { |
| |
| if (auto v = authorizationValue(ttag, p)) { |
| return v; |
| } |
| } |
| return {}; |
| } |
| |
| template <typename T> |
| static bool containsParam(const std::vector<KeyParameter>& keyParams, T ttag) { |
| return static_cast<bool>(getParam(keyParams, ttag)); |
| } |
| |
| // Prefer the smallest. |
| // If no options are found, return the first. |
| template <typename T> |
| static typename KMV1::TypedTag2ValueType<T>::type |
| getMaximum(const std::vector<KeyParameter>& keyParams, T tag, |
| std::vector<typename KMV1::TypedTag2ValueType<T>::type> sortedOptions) { |
| auto bestSoFar = sortedOptions.end(); |
| for (const KeyParameter& kp : keyParams) { |
| if (auto value = authorizationValue(tag, kp)) { |
| auto candidate = std::find(sortedOptions.begin(), sortedOptions.end(), *value); |
| // sortedOptions is sorted from best to worst. `std::distance(first, last)` counts the |
| // hops from `first` to `last`. So a better `candidate` yields a positive distance to |
| // `bestSoFar`. |
| if (std::distance(candidate, bestSoFar) > 0) { |
| bestSoFar = candidate; |
| } |
| } |
| } |
| if (bestSoFar == sortedOptions.end()) { |
| return sortedOptions[0]; |
| } |
| return *bestSoFar; |
| } |
| |
| static std::variant<keystore::X509_Ptr, KMV1::ErrorCode> |
| makeCert(::android::sp<Keymaster> mDevice, const std::vector<KeyParameter>& keyParams, |
| const std::vector<uint8_t>& keyBlob) { |
| // Start generating the certificate. |
| // Get public key for makeCert. |
| KMV1::ErrorCode errorCode; |
| std::vector<uint8_t> key; |
| static std::vector<uint8_t> empty_vector; |
| auto unwrapBlob = [&](auto b) -> const std::vector<uint8_t>& { |
| if (b) |
| return *b; |
| else |
| return empty_vector; |
| }; |
| auto result = mDevice->exportKey( |
| V4_0_KeyFormat::X509, keyBlob, unwrapBlob(getParam(keyParams, KMV1::TAG_APPLICATION_ID)), |
| unwrapBlob(getParam(keyParams, KMV1::TAG_APPLICATION_DATA)), |
| [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyMaterial) { |
| errorCode = convert(error); |
| key = keyMaterial; |
| }); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << " exportKey transaction failed. " << result.description(); |
| return KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| if (errorCode != KMV1::ErrorCode::OK) { |
| return errorCode; |
| } |
| // Get pkey for makeCert. |
| CBS cbs; |
| CBS_init(&cbs, key.data(), key.size()); |
| auto pkey = EVP_parse_public_key(&cbs); |
| |
| // makeCert |
| std::optional<std::reference_wrapper<const std::vector<uint8_t>>> subject; |
| if (auto blob = getParam(keyParams, KMV1::TAG_CERTIFICATE_SUBJECT)) { |
| subject = *blob; |
| } |
| |
| std::optional<std::reference_wrapper<const std::vector<uint8_t>>> serial; |
| if (auto blob = getParam(keyParams, KMV1::TAG_CERTIFICATE_SERIAL)) { |
| serial = *blob; |
| } |
| |
| int64_t activation; |
| if (auto date = getParam(keyParams, KMV1::TAG_CERTIFICATE_NOT_BEFORE)) { |
| activation = static_cast<int64_t>(*date); |
| } else { |
| return KMV1::ErrorCode::MISSING_NOT_BEFORE; |
| } |
| |
| int64_t expiration; |
| if (auto date = getParam(keyParams, KMV1::TAG_CERTIFICATE_NOT_AFTER)) { |
| expiration = static_cast<int64_t>(*date); |
| } else { |
| return KMV1::ErrorCode::MISSING_NOT_AFTER; |
| } |
| |
| auto certOrError = keystore::makeCert( |
| pkey, serial, subject, activation, expiration, false /* intentionally left blank */, |
| std::nullopt /* intentionally left blank */, std::nullopt /* intentionally left blank */); |
| if (std::holds_alternative<keystore::CertUtilsError>(certOrError)) { |
| LOG(ERROR) << __func__ << ": Failed to make certificate"; |
| return KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| return std::move(std::get<keystore::X509_Ptr>(certOrError)); |
| } |
| |
| static std::variant<keystore::Algo, KMV1::ErrorCode> getKeystoreAlgorithm(Algorithm algorithm) { |
| switch (algorithm) { |
| case Algorithm::RSA: |
| return keystore::Algo::RSA; |
| case Algorithm::EC: |
| return keystore::Algo::ECDSA; |
| default: |
| LOG(ERROR) << __func__ << ": This should not be called with symmetric algorithm."; |
| return KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| } |
| |
| static std::variant<keystore::Padding, KMV1::ErrorCode> getKeystorePadding(PaddingMode padding) { |
| switch (padding) { |
| case PaddingMode::RSA_PKCS1_1_5_SIGN: |
| return keystore::Padding::PKCS1_5; |
| case PaddingMode::RSA_PSS: |
| return keystore::Padding::PSS; |
| default: |
| return keystore::Padding::Ignored; |
| } |
| } |
| |
| static std::variant<keystore::Digest, KMV1::ErrorCode> getKeystoreDigest(Digest digest) { |
| switch (digest) { |
| case Digest::SHA1: |
| return keystore::Digest::SHA1; |
| case Digest::SHA_2_224: |
| return keystore::Digest::SHA224; |
| case Digest::SHA_2_256: |
| case Digest::NONE: |
| return keystore::Digest::SHA256; |
| case Digest::SHA_2_384: |
| return keystore::Digest::SHA384; |
| case Digest::SHA_2_512: |
| return keystore::Digest::SHA512; |
| default: |
| LOG(ERROR) << __func__ << ": Unknown digest."; |
| return KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| } |
| |
| std::optional<KMV1::ErrorCode> |
| KeyMintDevice::signCertificate(const std::vector<KeyParameter>& keyParams, |
| const std::vector<uint8_t>& prefixedKeyBlob, X509* cert) { |
| |
| auto algorithm = getParam(keyParams, KMV1::TAG_ALGORITHM); |
| auto algoOrError = getKeystoreAlgorithm(*algorithm); |
| if (std::holds_alternative<KMV1::ErrorCode>(algoOrError)) { |
| return std::get<KMV1::ErrorCode>(algoOrError); |
| } |
| auto algo = std::get<keystore::Algo>(algoOrError); |
| auto origPadding = getMaximum(keyParams, KMV1::TAG_PADDING, |
| {PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN}); |
| auto paddingOrError = getKeystorePadding(origPadding); |
| if (std::holds_alternative<KMV1::ErrorCode>(paddingOrError)) { |
| return std::get<KMV1::ErrorCode>(paddingOrError); |
| } |
| auto padding = std::get<keystore::Padding>(paddingOrError); |
| auto origDigest = getMaximum(keyParams, KMV1::TAG_DIGEST, |
| {Digest::SHA_2_256, Digest::SHA_2_512, Digest::SHA_2_384, |
| Digest::SHA_2_224, Digest::SHA1, Digest::NONE}); |
| auto digestOrError = getKeystoreDigest(origDigest); |
| if (std::holds_alternative<KMV1::ErrorCode>(digestOrError)) { |
| return std::get<KMV1::ErrorCode>(digestOrError); |
| } |
| auto digest = std::get<keystore::Digest>(digestOrError); |
| |
| KMV1::ErrorCode errorCode = KMV1::ErrorCode::OK; |
| auto error = keystore::signCertWith( |
| &*cert, |
| [&](const uint8_t* data, size_t len) { |
| std::vector<uint8_t> dataVec(data, data + len); |
| std::vector<KeyParameter> kps = { |
| KMV1::makeKeyParameter(KMV1::TAG_DIGEST, origDigest), |
| }; |
| if (algorithm == KMV1::Algorithm::RSA) { |
| kps.push_back(KMV1::makeKeyParameter(KMV1::TAG_PADDING, origPadding)); |
| } |
| BeginResult beginResult; |
| auto error = |
| begin(KeyPurpose::SIGN, prefixedKeyBlob, kps, HardwareAuthToken(), &beginResult); |
| if (!error.isOk()) { |
| errorCode = toErrorCode(error); |
| return std::vector<uint8_t>(); |
| } |
| |
| std::vector<uint8_t> result; |
| error = beginResult.operation->finish(dataVec, // |
| {} /* signature */, // |
| {} /* authToken */, // |
| {} /* timestampToken */, // |
| {} /* confirmationToken */, // |
| &result); |
| if (!error.isOk()) { |
| errorCode = toErrorCode(error); |
| return std::vector<uint8_t>(); |
| } |
| return result; |
| }, |
| algo, padding, digest); |
| if (error) { |
| LOG(ERROR) << __func__ |
| << ": signCertWith failed. (Callback diagnosed: " << toString(errorCode) << ")"; |
| return KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| if (errorCode != KMV1::ErrorCode::OK) { |
| return errorCode; |
| } |
| return std::nullopt; |
| } |
| |
| std::variant<std::vector<Certificate>, KMV1::ErrorCode> |
| KeyMintDevice::getCertificate(const std::vector<KeyParameter>& keyParams, |
| const std::vector<uint8_t>& prefixedKeyBlob) { |
| const std::vector<uint8_t>& keyBlob = prefixedKeyBlobRemovePrefix(prefixedKeyBlob); |
| |
| // There are no certificates for symmetric keys. |
| auto algorithm = getParam(keyParams, KMV1::TAG_ALGORITHM); |
| if (!algorithm) { |
| LOG(ERROR) << __func__ << ": Unable to determine key algorithm."; |
| return KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| switch (*algorithm) { |
| case Algorithm::RSA: |
| case Algorithm::EC: |
| break; |
| default: |
| return KMV1::ErrorCode::OK; |
| } |
| |
| // If attestation was requested, call and use attestKey. |
| if (containsParam(keyParams, KMV1::TAG_ATTESTATION_CHALLENGE)) { |
| auto legacyParams = convertKeyParametersToLegacy(extractAttestationParams(keyParams)); |
| std::vector<Certificate> certs; |
| KMV1::ErrorCode errorCode = KMV1::ErrorCode::OK; |
| auto result = mDevice->attestKey( |
| keyBlob, legacyParams, |
| [&](V4_0::ErrorCode error, const hidl_vec<hidl_vec<uint8_t>>& certChain) { |
| errorCode = convert(error); |
| for (const auto& cert : certChain) { |
| Certificate certificate; |
| certificate.encodedCertificate = cert; |
| certs.push_back(certificate); |
| } |
| }); |
| if (!result.isOk()) { |
| LOG(ERROR) << __func__ << ": Call to attestKey failed."; |
| return KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| if (errorCode != KMV1::ErrorCode::OK) { |
| return errorCode; |
| } |
| return certs; |
| } |
| |
| // makeCert |
| auto certOrError = makeCert(mDevice, keyParams, keyBlob); |
| if (std::holds_alternative<KMV1::ErrorCode>(certOrError)) { |
| return std::get<KMV1::ErrorCode>(certOrError); |
| } |
| auto cert = std::move(std::get<keystore::X509_Ptr>(certOrError)); |
| |
| // setIssuer |
| auto error = keystore::setIssuer(&*cert, &*cert, false); |
| if (error) { |
| LOG(ERROR) << __func__ << ": Set issuer failed."; |
| return KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| |
| // Signing |
| auto canSelfSign = |
| std::find_if(keyParams.begin(), keyParams.end(), [&](const KeyParameter& kp) { |
| if (auto v = KMV1::authorizationValue(KMV1::TAG_PURPOSE, kp)) { |
| return *v == KeyPurpose::SIGN; |
| } |
| return false; |
| }) != keyParams.end(); |
| auto noAuthRequired = containsParam(keyParams, KMV1::TAG_NO_AUTH_REQUIRED); |
| // If we cannot sign because of purpose or authorization requirement, |
| if (!(canSelfSign && noAuthRequired) |
| // or if self signing fails for any other reason, |
| || signCertificate(keyParams, keyBlob, &*cert).has_value()) { |
| // we sign with ephemeral key. |
| keystore::EVP_PKEY_CTX_Ptr pkey_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)); |
| EVP_PKEY_keygen_init(pkey_ctx.get()); |
| EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx.get(), NID_X9_62_prime256v1); |
| EVP_PKEY* pkey_ptr = nullptr; |
| EVP_PKEY_keygen(pkey_ctx.get(), &pkey_ptr); |
| error = keystore::signCert(&*cert, pkey_ptr); |
| if (error) { |
| LOG(ERROR) << __func__ << ": signCert failed."; |
| return KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| } |
| |
| // encodeCert |
| auto encodedCertOrError = keystore::encodeCert(&*cert); |
| if (std::holds_alternative<keystore::CertUtilsError>(encodedCertOrError)) { |
| LOG(ERROR) << __func__ << ": encodeCert failed."; |
| return KMV1::ErrorCode::UNKNOWN_ERROR; |
| } |
| |
| Certificate certificate{.encodedCertificate = |
| std::get<std::vector<uint8_t>>(encodedCertOrError)}; |
| std::vector certificates = {certificate}; |
| return certificates; |
| } |
| |
| // Code to find the Keymaster devices (copied from existing code). |
| |
| // Copied from system/security/keystore/include/keystore/keymaster_types.h. |
| |
| // Changing this namespace alias will change the keymaster version. |
| namespace keymasterNs = ::android::hardware::keymaster::V4_1; |
| |
| using keymasterNs::SecurityLevel; |
| |
| // Copied from system/security/keystore/KeyStore.h. |
| |
| using ::android::sp; |
| using keymasterNs::support::Keymaster; |
| |
| template <typename T, size_t count> class Devices : public std::array<T, count> { |
| public: |
| T& operator[](SecurityLevel secLevel) { |
| static_assert(uint32_t(SecurityLevel::SOFTWARE) == 0 && |
| uint32_t(SecurityLevel::TRUSTED_ENVIRONMENT) == 1 && |
| uint32_t(SecurityLevel::STRONGBOX) == 2, |
| "Numeric values of security levels have changed"); |
| return std::array<T, count>::at(static_cast<uint32_t>(secLevel)); |
| } |
| T operator[](SecurityLevel secLevel) const { |
| if (static_cast<uint32_t>(secLevel) > static_cast<uint32_t>(SecurityLevel::STRONGBOX)) { |
| LOG(ERROR) << "Invalid security level requested"; |
| return {}; |
| } |
| return (*const_cast<Devices*>(this))[secLevel]; |
| } |
| }; |
| |
| using KeymasterDevices = Devices<sp<Keymaster>, 3>; |
| |
| // Copied from system/security/keystore/keystore_main.cpp. |
| |
| using ::android::hardware::hidl_string; |
| using keymasterNs::support::Keymaster3; |
| using keymasterNs::support::Keymaster4; |
| |
| template <typename Wrapper> |
| KeymasterDevices enumerateKeymasterDevices(IServiceManager* serviceManager) { |
| KeymasterDevices result; |
| serviceManager->listManifestByInterface( |
| Wrapper::WrappedIKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) { |
| auto try_get_device = [&](const auto& name, bool fail_silent) { |
| auto device = Wrapper::WrappedIKeymasterDevice::getService(name); |
| if (fail_silent && !device) return; |
| CHECK(device) << "Failed to get service for \"" |
| << Wrapper::WrappedIKeymasterDevice::descriptor |
| << "\" with interface name \"" << name << "\""; |
| |
| sp<Keymaster> kmDevice(new Wrapper(device, name)); |
| auto halVersion = kmDevice->halVersion(); |
| SecurityLevel securityLevel = halVersion.securityLevel; |
| LOG(INFO) << "found " << Wrapper::WrappedIKeymasterDevice::descriptor |
| << " with interface name " << name << " and seclevel " |
| << toString(securityLevel); |
| CHECK(static_cast<uint32_t>(securityLevel) < result.size()) |
| << "Security level of \"" << Wrapper::WrappedIKeymasterDevice::descriptor |
| << "\" with interface name \"" << name << "\" out of range"; |
| auto& deviceSlot = result[securityLevel]; |
| if (deviceSlot) { |
| if (!fail_silent) { |
| LOG(WARNING) << "Implementation of \"" |
| << Wrapper::WrappedIKeymasterDevice::descriptor |
| << "\" with interface name \"" << name |
| << "\" and security level: " << toString(securityLevel) |
| << " Masked by other implementation of Keymaster"; |
| } |
| } else { |
| deviceSlot = kmDevice; |
| } |
| }; |
| bool has_default = false; |
| for (auto& n : names) { |
| try_get_device(n, false); |
| if (n == "default") has_default = true; |
| } |
| // Make sure that we always check the default device. If we enumerate only what is |
| // known to hwservicemanager, we miss a possible passthrough HAL. |
| if (!has_default) { |
| try_get_device("default", true /* fail_silent */); |
| } |
| }); |
| return result; |
| } |
| |
| KeymasterDevices initializeKeymasters() { |
| auto serviceManager = IServiceManager::getService(); |
| CHECK(serviceManager.get()) << "Failed to get ServiceManager"; |
| auto result = enumerateKeymasterDevices<Keymaster4>(serviceManager.get()); |
| auto softKeymaster = result[SecurityLevel::SOFTWARE]; |
| if (!result[SecurityLevel::TRUSTED_ENVIRONMENT]) { |
| result = enumerateKeymasterDevices<Keymaster3>(serviceManager.get()); |
| } |
| if (softKeymaster) result[SecurityLevel::SOFTWARE] = softKeymaster; |
| if (result[SecurityLevel::SOFTWARE] && !result[SecurityLevel::TRUSTED_ENVIRONMENT]) { |
| LOG(WARNING) << "No secure Keymaster implementation found, but device offers insecure" |
| " Keymaster HAL. Using as default."; |
| result[SecurityLevel::TRUSTED_ENVIRONMENT] = result[SecurityLevel::SOFTWARE]; |
| result[SecurityLevel::SOFTWARE] = nullptr; |
| } |
| // The software bit was removed since we do not need it. |
| return result; |
| } |
| |
| void KeyMintDevice::setNumFreeSlots(uint8_t numFreeSlots) { |
| mOperationSlots.setNumFreeSlots(numFreeSlots); |
| } |
| |
| // Constructors and helpers. |
| |
| KeyMintDevice::KeyMintDevice(sp<Keymaster> device, KeyMintSecurityLevel securityLevel) |
| : mDevice(device), securityLevel_(securityLevel) { |
| if (securityLevel == KeyMintSecurityLevel::STRONGBOX) { |
| setNumFreeSlots(3); |
| } else { |
| setNumFreeSlots(15); |
| } |
| |
| softKeyMintDevice_.reset(CreateKeyMintDevice(KeyMintSecurityLevel::SOFTWARE)); |
| } |
| |
| sp<Keymaster> getDevice(KeyMintSecurityLevel securityLevel) { |
| static std::mutex mutex; |
| static sp<Keymaster> teeDevice; |
| static sp<Keymaster> sbDevice; |
| std::lock_guard<std::mutex> lock(mutex); |
| if (!teeDevice) { |
| auto devices = initializeKeymasters(); |
| teeDevice = devices[V4_0::SecurityLevel::TRUSTED_ENVIRONMENT]; |
| sbDevice = devices[V4_0::SecurityLevel::STRONGBOX]; |
| } |
| switch (securityLevel) { |
| case KeyMintSecurityLevel::TRUSTED_ENVIRONMENT: |
| return teeDevice; |
| case KeyMintSecurityLevel::STRONGBOX: |
| return sbDevice; |
| default: |
| return {}; |
| } |
| } |
| |
| std::shared_ptr<KeyMintDevice> |
| KeyMintDevice::createKeyMintDevice(KeyMintSecurityLevel securityLevel) { |
| if (auto dev = getDevice(securityLevel)) { |
| return ndk::SharedRefBase::make<KeyMintDevice>(std::move(dev), securityLevel); |
| } |
| return {}; |
| } |
| |
| std::shared_ptr<SharedSecret> SharedSecret::createSharedSecret(KeyMintSecurityLevel securityLevel) { |
| auto device = getDevice(securityLevel); |
| if (!device) { |
| return {}; |
| } |
| return ndk::SharedRefBase::make<SharedSecret>(std::move(device)); |
| } |
| |
| std::shared_ptr<SecureClock> SecureClock::createSecureClock(KeyMintSecurityLevel securityLevel) { |
| auto device = getDevice(securityLevel); |
| if (!device) { |
| return {}; |
| } |
| return ndk::SharedRefBase::make<SecureClock>(std::move(device)); |
| } |
| |
| ScopedAStatus |
| KeystoreCompatService::getKeyMintDevice(KeyMintSecurityLevel in_securityLevel, |
| std::shared_ptr<IKeyMintDevice>* _aidl_return) { |
| auto i = mDeviceCache.find(in_securityLevel); |
| if (i == mDeviceCache.end()) { |
| auto device = KeyMintDevice::createKeyMintDevice(in_securityLevel); |
| if (!device) { |
| return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND); |
| } |
| i = mDeviceCache.insert(i, {in_securityLevel, std::move(device)}); |
| } |
| *_aidl_return = i->second; |
| return ScopedAStatus::ok(); |
| } |
| |
| ScopedAStatus KeystoreCompatService::getSharedSecret(KeyMintSecurityLevel in_securityLevel, |
| std::shared_ptr<ISharedSecret>* _aidl_return) { |
| auto i = mSharedSecretCache.find(in_securityLevel); |
| if (i == mSharedSecretCache.end()) { |
| auto secret = SharedSecret::createSharedSecret(in_securityLevel); |
| if (!secret) { |
| return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND); |
| } |
| i = mSharedSecretCache.insert(i, {in_securityLevel, std::move(secret)}); |
| } |
| *_aidl_return = i->second; |
| return ScopedAStatus::ok(); |
| } |
| |
| ScopedAStatus KeystoreCompatService::getSecureClock(std::shared_ptr<ISecureClock>* _aidl_return) { |
| if (!mSecureClock) { |
| // The legacy verification service was always provided by the TEE variant. |
| auto clock = SecureClock::createSecureClock(KeyMintSecurityLevel::TRUSTED_ENVIRONMENT); |
| if (!clock) { |
| return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND); |
| } |
| mSecureClock = std::move(clock); |
| } |
| *_aidl_return = mSecureClock; |
| return ScopedAStatus::ok(); |
| } |