diff --git a/Android.bp b/Android.bp index 3760285..12d8b2d 100644 --- a/Android.bp +++ b/Android.bp @@ -38,6 +38,7 @@ cc_defaults { ], shared_libs: [ "android.hardware.keymaster@3.0", + "android.hardware.keymaster@4.0", "libbase", "libbinder", "libcrypto", @@ -50,6 +51,7 @@ cc_defaults { "libhardware_legacy", "libhidlbase", "libhwbinder", + "libkeymaster4support", "libkeyutils", "liblog", "liblogwrap", @@ -113,7 +115,6 @@ cc_library_static { "VoldNativeService.cpp", "VoldUtil.cpp", "VolumeManager.cpp", - "authorization_set.cpp", "cryptfs.cpp", "fs/Exfat.cpp", "fs/Ext4.cpp", diff --git a/KeyStorage.cpp b/KeyStorage.cpp index b564feb..0518930 100644 --- a/KeyStorage.cpp +++ b/KeyStorage.cpp @@ -40,18 +40,16 @@ #include #include +#include +#include extern "C" { #include "crypto_scrypt.h" } -#include "authorization_set.h" -#include "keystore_hidl_support.h" - namespace android { namespace vold { -using namespace keystore; const KeyAuthentication kEmptyAuthentication{"", ""}; @@ -106,15 +104,13 @@ static void hashWithPrefix(char const* prefix, const std::string& tohash, std::s static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& auth, const std::string& appId, std::string* key) { - auto paramBuilder = AuthorizationSetBuilder() + auto paramBuilder = km::AuthorizationSetBuilder() .AesEncryptionKey(AES_KEY_BYTES * 8) - .Authorization(TAG_BLOCK_MODE, BlockMode::GCM) - .Authorization(TAG_MIN_MAC_LENGTH, GCM_MAC_BYTES * 8) - .Authorization(TAG_PADDING, PaddingMode::NONE) - .Authorization(TAG_APPLICATION_ID, blob2hidlVec(appId)); + .GcmModeMinMacLen(GCM_MAC_BYTES * 8) + .Authorization(km::TAG_APPLICATION_ID, km::support::blob2hidlVec(appId)); if (auth.token.empty()) { LOG(DEBUG) << "Creating key that doesn't need auth token"; - paramBuilder.Authorization(TAG_NO_AUTH_REQUIRED); + paramBuilder.Authorization(km::TAG_NO_AUTH_REQUIRED); } else { LOG(DEBUG) << "Auth token required for key"; if (auth.token.size() != sizeof(hw_auth_token_t)) { @@ -123,24 +119,24 @@ static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& return false; } const hw_auth_token_t* at = reinterpret_cast(auth.token.data()); - paramBuilder.Authorization(TAG_USER_SECURE_ID, at->user_id); - paramBuilder.Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD); - paramBuilder.Authorization(TAG_AUTH_TIMEOUT, AUTH_TIMEOUT); + paramBuilder.Authorization(km::TAG_USER_SECURE_ID, at->user_id); + paramBuilder.Authorization(km::TAG_USER_AUTH_TYPE, km::HardwareAuthenticatorType::PASSWORD); + paramBuilder.Authorization(km::TAG_AUTH_TIMEOUT, AUTH_TIMEOUT); } return keymaster.generateKey(paramBuilder, key); } -static AuthorizationSet beginParams(const KeyAuthentication& auth, const std::string& appId) { - auto paramBuilder = AuthorizationSetBuilder() - .Authorization(TAG_BLOCK_MODE, BlockMode::GCM) - .Authorization(TAG_MAC_LENGTH, GCM_MAC_BYTES * 8) - .Authorization(TAG_PADDING, PaddingMode::NONE) - .Authorization(TAG_APPLICATION_ID, blob2hidlVec(appId)); +static std::pair beginParams( + const KeyAuthentication& auth, const std::string& appId) { + auto paramBuilder = km::AuthorizationSetBuilder() + .GcmModeMacLen(GCM_MAC_BYTES * 8) + .Authorization(km::TAG_APPLICATION_ID, km::support::blob2hidlVec(appId)); + km::HardwareAuthToken authToken; if (!auth.token.empty()) { LOG(DEBUG) << "Supplying auth token to Keymaster"; - paramBuilder.Authorization(TAG_AUTH_TOKEN, blob2hidlVec(auth.token)); + authToken = km::support::hidlVec2AuthToken(km::support::blob2hidlVec(auth.token)); } - return paramBuilder; + return {paramBuilder, authToken}; } static bool readFileToString(const std::string& filename, std::string* result) { @@ -202,20 +198,22 @@ bool readSecdiscardable(const std::string& filename, std::string* hash) { return true; } -static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, KeyPurpose purpose, - const AuthorizationSet& keyParams, const AuthorizationSet& opParams, - AuthorizationSet* outParams) { +static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, + km::KeyPurpose purpose, const km::AuthorizationSet& keyParams, + const km::AuthorizationSet& opParams, + const km::HardwareAuthToken& authToken, + km::AuthorizationSet* outParams) { auto kmKeyPath = dir + "/" + kFn_keymaster_key_blob; std::string kmKey; if (!readFileToString(kmKeyPath, &kmKey)) return KeymasterOperation(); - AuthorizationSet inParams(keyParams); + km::AuthorizationSet inParams(keyParams); inParams.append(opParams.begin(), opParams.end()); for (;;) { - auto opHandle = keymaster.begin(purpose, kmKey, inParams, outParams); + auto opHandle = keymaster.begin(purpose, kmKey, inParams, authToken, outParams); if (opHandle) { return opHandle; } - if (opHandle.errorCode() != ErrorCode::KEY_REQUIRES_UPGRADE) return opHandle; + if (opHandle.errorCode() != km::ErrorCode::KEY_REQUIRES_UPGRADE) return opHandle; LOG(DEBUG) << "Upgrading key: " << dir; std::string newKey; if (!keymaster.upgradeKey(kmKey, keyParams, &newKey)) return KeymasterOperation(); @@ -234,13 +232,15 @@ static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, Ke } static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir, - const AuthorizationSet& keyParams, const KeyBuffer& message, - std::string* ciphertext) { - AuthorizationSet opParams; - AuthorizationSet outParams; - auto opHandle = begin(keymaster, dir, KeyPurpose::ENCRYPT, keyParams, opParams, &outParams); + const km::AuthorizationSet& keyParams, + const km::HardwareAuthToken& authToken, + const KeyBuffer& message, std::string* ciphertext) { + km::AuthorizationSet opParams; + km::AuthorizationSet outParams; + auto opHandle = + begin(keymaster, dir, km::KeyPurpose::ENCRYPT, keyParams, opParams, authToken, &outParams); if (!opHandle) return false; - auto nonceBlob = outParams.GetTagValue(TAG_NONCE); + auto nonceBlob = outParams.GetTagValue(km::TAG_NONCE); if (!nonceBlob.isOk()) { LOG(ERROR) << "GCM encryption but no nonce generated"; return false; @@ -260,12 +260,15 @@ static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir } static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir, - const AuthorizationSet& keyParams, + const km::AuthorizationSet& keyParams, + const km::HardwareAuthToken& authToken, const std::string& ciphertext, KeyBuffer* message) { auto nonce = ciphertext.substr(0, GCM_NONCE_BYTES); auto bodyAndMac = ciphertext.substr(GCM_NONCE_BYTES); - auto opParams = AuthorizationSetBuilder().Authorization(TAG_NONCE, blob2hidlVec(nonce)); - auto opHandle = begin(keymaster, dir, KeyPurpose::DECRYPT, keyParams, opParams, nullptr); + auto opParams = km::AuthorizationSetBuilder().Authorization(km::TAG_NONCE, + km::support::blob2hidlVec(nonce)); + auto opHandle = + begin(keymaster, dir, km::KeyPurpose::DECRYPT, keyParams, opParams, authToken, nullptr); if (!opHandle) return false; if (!opHandle.updateCompletely(bodyAndMac, message)) return false; if (!opHandle.finish(nullptr)) return false; @@ -468,8 +471,11 @@ bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBu std::string kmKey; if (!generateKeymasterKey(keymaster, auth, appId, &kmKey)) return false; if (!writeStringToFile(kmKey, dir + "/" + kFn_keymaster_key_blob)) return false; - auto keyParams = beginParams(auth, appId); - if (!encryptWithKeymasterKey(keymaster, dir, keyParams, key, &encryptedKey)) return false; + km::AuthorizationSet keyParams; + km::HardwareAuthToken authToken; + std::tie(keyParams, authToken) = beginParams(auth, appId); + if (!encryptWithKeymasterKey(keymaster, dir, keyParams, authToken, key, &encryptedKey)) + return false; } else { if (!encryptWithoutKeymaster(appId, key, &encryptedKey)) return false; } @@ -518,8 +524,10 @@ bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffe if (auth.usesKeymaster()) { Keymaster keymaster; if (!keymaster) return false; - auto keyParams = beginParams(auth, appId); - if (!decryptWithKeymasterKey(keymaster, dir, keyParams, encryptedMessage, key)) + km::AuthorizationSet keyParams; + km::HardwareAuthToken authToken; + std::tie(keyParams, authToken) = beginParams(auth, appId); + if (!decryptWithKeymasterKey(keymaster, dir, keyParams, authToken, encryptedMessage, key)) return false; } else { if (!decryptWithoutKeymaster(appId, encryptedMessage, key)) return false; diff --git a/Keymaster.cpp b/Keymaster.cpp index c39280e..7d061bb 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -17,45 +17,48 @@ #include "Keymaster.h" #include - -#include "authorization_set.h" -#include "keymaster_tags.h" -#include "keystore_hidl_support.h" - -using namespace ::keystore; -using android::hardware::hidl_string; +#include +#include namespace android { namespace vold { +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; + KeymasterOperation::~KeymasterOperation() { - if (mDevice.get()) mDevice->abort(mOpHandle); + if (mDevice) mDevice->abort(mOpHandle); } bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen, const std::function consumer) { uint32_t inputConsumed = 0; - ErrorCode km_error; - auto hidlCB = [&](ErrorCode ret, uint32_t inputConsumedDelta, - const hidl_vec& /*ignored*/, const hidl_vec& _output) { + km::ErrorCode km_error; + auto hidlCB = [&](km::ErrorCode ret, uint32_t inputConsumedDelta, + const hidl_vec& /*ignored*/, + const hidl_vec& _output) { km_error = ret; - if (km_error != ErrorCode::OK) return; + if (km_error != km::ErrorCode::OK) return; inputConsumed += inputConsumedDelta; consumer(reinterpret_cast(&_output[0]), _output.size()); }; while (inputConsumed != inputLen) { size_t toRead = static_cast(inputLen - inputConsumed); - auto inputBlob = - blob2hidlVec(reinterpret_cast(&input[inputConsumed]), toRead); - auto error = mDevice->update(mOpHandle, hidl_vec(), inputBlob, hidlCB); + auto inputBlob = km::support::blob2hidlVec( + reinterpret_cast(&input[inputConsumed]), toRead); + // TODO(swillden): Need to handle getting a VerificationToken from the TEE if mDevice is + // StrongBox, so we can provide it here. The VerificationToken will need to be + // requested/retrieved during Keymaster::begin(). + auto error = mDevice->update(mOpHandle, hidl_vec(), inputBlob, + km::HardwareAuthToken(), km::VerificationToken(), hidlCB); if (!error.isOk()) { LOG(ERROR) << "update failed: " << error.description(); mDevice = nullptr; return false; } - if (km_error != ErrorCode::OK) { + if (km_error != km::ErrorCode::OK) { LOG(ERROR) << "update failed, code " << int32_t(km_error); mDevice = nullptr; return false; @@ -70,21 +73,22 @@ bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen, } bool KeymasterOperation::finish(std::string* output) { - ErrorCode km_error; - auto hidlCb = [&](ErrorCode ret, const hidl_vec& /*ignored*/, + km::ErrorCode km_error; + auto hidlCb = [&](km::ErrorCode ret, const hidl_vec& /*ignored*/, const hidl_vec& _output) { km_error = ret; - if (km_error != ErrorCode::OK) return; + if (km_error != km::ErrorCode::OK) return; if (output) output->assign(reinterpret_cast(&_output[0]), _output.size()); }; - auto error = mDevice->finish(mOpHandle, hidl_vec(), hidl_vec(), - hidl_vec(), hidlCb); + auto error = mDevice->finish(mOpHandle, hidl_vec(), hidl_vec(), + hidl_vec(), km::HardwareAuthToken(), + km::VerificationToken(), hidlCb); mDevice = nullptr; if (!error.isOk()) { LOG(ERROR) << "finish failed: " << error.description(); return false; } - if (km_error != ErrorCode::OK) { + if (km_error != km::ErrorCode::OK) { LOG(ERROR) << "finish failed, code " << int32_t(km_error); return false; } @@ -92,15 +96,21 @@ bool KeymasterOperation::finish(std::string* output) { } Keymaster::Keymaster() { - mDevice = ::android::hardware::keymaster::V3_0::IKeymasterDevice::getService(); + auto devices = KmDevice::enumerateAvailableDevices(); + if (devices.empty()) return; + mDevice = std::move(devices[0]); + auto& version = mDevice->halVersion(); + LOG(INFO) << "Using " << version.keymasterName << " from " << version.authorName + << " for encryption. Security level: " << toString(version.securityLevel) + << ", HAL: " << mDevice->descriptor() << "/" << mDevice->instanceName(); } -bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key) { - ErrorCode km_error; - auto hidlCb = [&](ErrorCode ret, const hidl_vec& keyBlob, - const KeyCharacteristics& /*ignored*/) { +bool Keymaster::generateKey(const km::AuthorizationSet& inParams, std::string* key) { + km::ErrorCode km_error; + auto hidlCb = [&](km::ErrorCode ret, const hidl_vec& keyBlob, + const km::KeyCharacteristics& /*ignored*/) { km_error = ret; - if (km_error != ErrorCode::OK) return; + if (km_error != km::ErrorCode::OK) return; if (key) key->assign(reinterpret_cast(&keyBlob[0]), keyBlob.size()); }; @@ -109,7 +119,7 @@ bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key) LOG(ERROR) << "generate_key failed: " << error.description(); return false; } - if (km_error != ErrorCode::OK) { + if (km_error != km::ErrorCode::OK) { LOG(ERROR) << "generate_key failed, code " << int32_t(km_error); return false; } @@ -117,26 +127,26 @@ bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key) } bool Keymaster::deleteKey(const std::string& key) { - auto keyBlob = blob2hidlVec(key); + auto keyBlob = km::support::blob2hidlVec(key); auto error = mDevice->deleteKey(keyBlob); if (!error.isOk()) { LOG(ERROR) << "delete_key failed: " << error.description(); return false; } - if (ErrorCode(error) != ErrorCode::OK) { - LOG(ERROR) << "delete_key failed, code " << uint32_t(ErrorCode(error)); + if (error != km::ErrorCode::OK) { + LOG(ERROR) << "delete_key failed, code " << int32_t(km::ErrorCode(error)); return false; } return true; } -bool Keymaster::upgradeKey(const std::string& oldKey, const AuthorizationSet& inParams, +bool Keymaster::upgradeKey(const std::string& oldKey, const km::AuthorizationSet& inParams, std::string* newKey) { - auto oldKeyBlob = blob2hidlVec(oldKey); - ErrorCode km_error; - auto hidlCb = [&](ErrorCode ret, const hidl_vec& upgradedKeyBlob) { + auto oldKeyBlob = km::support::blob2hidlVec(oldKey); + km::ErrorCode km_error; + auto hidlCb = [&](km::ErrorCode ret, const hidl_vec& upgradedKeyBlob) { km_error = ret; - if (km_error != ErrorCode::OK) return; + if (km_error != km::ErrorCode::OK) return; if (newKey) newKey->assign(reinterpret_cast(&upgradedKeyBlob[0]), upgradedKeyBlob.size()); @@ -146,44 +156,43 @@ bool Keymaster::upgradeKey(const std::string& oldKey, const AuthorizationSet& in LOG(ERROR) << "upgrade_key failed: " << error.description(); return false; } - if (km_error != ErrorCode::OK) { + if (km_error != km::ErrorCode::OK) { LOG(ERROR) << "upgrade_key failed, code " << int32_t(km_error); return false; } return true; } -KeymasterOperation Keymaster::begin(KeyPurpose purpose, const std::string& key, - const AuthorizationSet& inParams, AuthorizationSet* outParams) { - auto keyBlob = blob2hidlVec(key); +KeymasterOperation Keymaster::begin(km::KeyPurpose purpose, const std::string& key, + const km::AuthorizationSet& inParams, + const km::HardwareAuthToken& authToken, + km::AuthorizationSet* outParams) { + auto keyBlob = km::support::blob2hidlVec(key); uint64_t mOpHandle; - ErrorCode km_error; + km::ErrorCode km_error; - auto hidlCb = [&](ErrorCode ret, const hidl_vec& _outParams, + auto hidlCb = [&](km::ErrorCode ret, const hidl_vec& _outParams, uint64_t operationHandle) { km_error = ret; - if (km_error != ErrorCode::OK) return; + if (km_error != km::ErrorCode::OK) return; if (outParams) *outParams = _outParams; mOpHandle = operationHandle; }; - auto error = mDevice->begin(purpose, keyBlob, inParams.hidl_data(), hidlCb); + auto error = mDevice->begin(purpose, keyBlob, inParams.hidl_data(), authToken, hidlCb); if (!error.isOk()) { LOG(ERROR) << "begin failed: " << error.description(); - return KeymasterOperation(ErrorCode::UNKNOWN_ERROR); + return KeymasterOperation(km::ErrorCode::UNKNOWN_ERROR); } - if (km_error != ErrorCode::OK) { + if (km_error != km::ErrorCode::OK) { LOG(ERROR) << "begin failed, code " << int32_t(km_error); return KeymasterOperation(km_error); } - return KeymasterOperation(mDevice, mOpHandle); + return KeymasterOperation(mDevice.get(), mOpHandle); } + bool Keymaster::isSecure() { - bool _isSecure = false; - auto rc = - mDevice->getHardwareFeatures([&](bool isSecure, bool, bool, bool, bool, const hidl_string&, - const hidl_string&) { _isSecure = isSecure; }); - return rc.isOk() && _isSecure; + return mDevice->halVersion().securityLevel != km::SecurityLevel::SOFTWARE; } } // namespace vold @@ -216,17 +225,14 @@ static bool write_string_to_buf(const std::string& towrite, uint8_t* buffer, uin return true; } -static AuthorizationSet keyParams(uint32_t rsa_key_size, uint64_t rsa_exponent, uint32_t ratelimit) { - return AuthorizationSetBuilder() - .Authorization(TAG_ALGORITHM, Algorithm::RSA) - .Authorization(TAG_KEY_SIZE, rsa_key_size) - .Authorization(TAG_RSA_PUBLIC_EXPONENT, rsa_exponent) - .Authorization(TAG_PURPOSE, KeyPurpose::SIGN) - .Authorization(TAG_PADDING, PaddingMode::NONE) - .Authorization(TAG_DIGEST, Digest::NONE) - .Authorization(TAG_BLOB_USAGE_REQUIREMENTS, KeyBlobUsageRequirements::STANDALONE) - .Authorization(TAG_NO_AUTH_REQUIRED) - .Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, ratelimit); +static km::AuthorizationSet keyParams(uint32_t rsa_key_size, uint64_t rsa_exponent, + uint32_t ratelimit) { + return km::AuthorizationSetBuilder() + .RsaSigningKey(rsa_key_size, rsa_exponent) + .NoDigestOrPadding() + .Authorization(km::TAG_BLOB_USAGE_REQUIREMENTS, km::KeyBlobUsageRequirements::STANDALONE) + .Authorization(km::TAG_NO_AUTH_REQUIRED) + .Authorization(km::TAG_MIN_SECONDS_BETWEEN_OPS, ratelimit); } int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size, uint64_t rsa_exponent, @@ -279,31 +285,28 @@ KeymasterSignResult keymaster_sign_object_for_cryptfs_scrypt( return KeymasterSignResult::error; } - AuthorizationSet outParams; + km::AuthorizationSet outParams; std::string key(reinterpret_cast(key_blob), key_blob_size); std::string input(reinterpret_cast(object), object_size); std::string output; KeymasterOperation op; - auto paramBuilder = AuthorizationSetBuilder() - .Authorization(TAG_PADDING, PaddingMode::NONE) - .Authorization(TAG_DIGEST, Digest::NONE); - + auto paramBuilder = km::AuthorizationSetBuilder().NoDigestOrPadding(); while (true) { - op = dev.begin(KeyPurpose::SIGN, key, paramBuilder, &outParams); - if (op.errorCode() == ErrorCode::KEY_RATE_LIMIT_EXCEEDED) { + op = dev.begin(km::KeyPurpose::SIGN, key, paramBuilder, km::HardwareAuthToken(), &outParams); + if (op.errorCode() == km::ErrorCode::KEY_RATE_LIMIT_EXCEEDED) { sleep(ratelimit); continue; } else break; } - if (op.errorCode() == ErrorCode::KEY_REQUIRES_UPGRADE) { + if (op.errorCode() == km::ErrorCode::KEY_REQUIRES_UPGRADE) { LOG(ERROR) << "Keymaster key requires upgrade"; return KeymasterSignResult::upgrade; } - if (op.errorCode() != ErrorCode::OK) { + if (op.errorCode() != km::ErrorCode::OK) { LOG(ERROR) << "Error starting keymaster signature transaction: " << int32_t(op.errorCode()); return KeymasterSignResult::error; } diff --git a/Keymaster.h b/Keymaster.h index aef1602..0bda8cd 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -24,16 +24,14 @@ #include #include -#include - -#include "authorization_set.h" +#include +#include namespace android { namespace vold { -using ::android::hardware::keymaster::V3_0::IKeymasterDevice; -using ::keystore::ErrorCode; -using ::keystore::KeyPurpose; -using ::keystore::AuthorizationSet; + +namespace km = ::android::hardware::keymaster::V4_0; +using KmDevice = km::support::Keymaster; // C++ wrappers to the Keymaster hidl interface. // This is tailored to the needs of KeyStorage, but could be extended to be @@ -48,8 +46,8 @@ class KeymasterOperation { ~KeymasterOperation(); // Is this instance valid? This is false if creation fails, and becomes // false on finish or if an update fails. - explicit operator bool() { return mError == ErrorCode::OK; } - ErrorCode errorCode() { return mError; } + explicit operator bool() { return mError == km::ErrorCode::OK; } + km::ErrorCode errorCode() { return mError; } // Call "update" repeatedly until all of the input is consumed, and // concatenate the output. Return true on success. template @@ -63,34 +61,30 @@ class KeymasterOperation { // Finish and write the output to this string, unless pointer is null. bool finish(std::string* output); // Move constructor - KeymasterOperation(KeymasterOperation&& rhs) { - mDevice = std::move(rhs.mDevice); - mOpHandle = std::move(rhs.mOpHandle); - mError = std::move(rhs.mError); - } + KeymasterOperation(KeymasterOperation&& rhs) { *this = std::move(rhs); } // Construct an object in an error state for error returns - KeymasterOperation() : mDevice{nullptr}, mOpHandle{0}, mError{ErrorCode::UNKNOWN_ERROR} {} + KeymasterOperation() : mDevice{nullptr}, mOpHandle{0}, mError{km::ErrorCode::UNKNOWN_ERROR} {} // Move Assignment KeymasterOperation& operator=(KeymasterOperation&& rhs) { mDevice = std::move(rhs.mDevice); mOpHandle = std::move(rhs.mOpHandle); mError = std::move(rhs.mError); - rhs.mError = ErrorCode::UNKNOWN_ERROR; + rhs.mError = km::ErrorCode::UNKNOWN_ERROR; rhs.mOpHandle = 0; return *this; } private: - KeymasterOperation(const sp& d, uint64_t h) - : mDevice{d}, mOpHandle{h}, mError{ErrorCode::OK} {} - KeymasterOperation(ErrorCode error) : mDevice{nullptr}, mOpHandle{0}, mError{error} {} + KeymasterOperation(KmDevice* d, uint64_t h) + : mDevice{d}, mOpHandle{h}, mError{km::ErrorCode::OK} {} + KeymasterOperation(km::ErrorCode error) : mDevice{nullptr}, mOpHandle{0}, mError{error} {} bool updateCompletely(const char* input, size_t inputLen, const std::function consumer); - sp mDevice; + KmDevice* mDevice; uint64_t mOpHandle; - ErrorCode mError; + km::ErrorCode mError; DISALLOW_COPY_AND_ASSIGN(KeymasterOperation); friend class Keymaster; }; @@ -103,19 +97,21 @@ class Keymaster { // false if we failed to open the keymaster device. explicit operator bool() { return mDevice.get() != nullptr; } // Generate a key in the keymaster from the given params. - bool generateKey(const AuthorizationSet& inParams, std::string* key); + bool generateKey(const km::AuthorizationSet& inParams, std::string* key); // If the keymaster supports it, permanently delete a key. bool deleteKey(const std::string& key); // Replace stored key blob in response to KM_ERROR_KEY_REQUIRES_UPGRADE. - bool upgradeKey(const std::string& oldKey, const AuthorizationSet& inParams, + bool upgradeKey(const std::string& oldKey, const km::AuthorizationSet& inParams, std::string* newKey); // Begin a new cryptographic operation, collecting output parameters if pointer is non-null - KeymasterOperation begin(KeyPurpose purpose, const std::string& key, - const AuthorizationSet& inParams, AuthorizationSet* outParams); + KeymasterOperation begin(km::KeyPurpose purpose, const std::string& key, + const km::AuthorizationSet& inParams, + const km::HardwareAuthToken& authToken, + km::AuthorizationSet* outParams); bool isSecure(); private: - sp mDevice; + std::unique_ptr mDevice; DISALLOW_COPY_AND_ASSIGN(Keymaster); }; diff --git a/authorization_set.cpp b/authorization_set.cpp deleted file mode 100644 index e7a3401..0000000 --- a/authorization_set.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2014 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 "authorization_set.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace keystore { - -inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) { - if (a.tag != b.tag) return a.tag < b.tag; - int retval; - switch (typeFromTag(a.tag)) { - case TagType::INVALID: - case TagType::BOOL: - return false; - case TagType::ENUM: - case TagType::ENUM_REP: - case TagType::UINT: - case TagType::UINT_REP: - return a.f.integer < b.f.integer; - case TagType::ULONG: - case TagType::ULONG_REP: - return a.f.longInteger < b.f.longInteger; - case TagType::DATE: - return a.f.dateTime < b.f.dateTime; - case TagType::BIGNUM: - case TagType::BYTES: - // Handle the empty cases. - if (a.blob.size() == 0) return b.blob.size() != 0; - if (b.blob.size() == 0) return false; - - retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size())); - // if one is the prefix of the other the longer wins - if (retval == 0) return a.blob.size() < b.blob.size(); - // Otherwise a is less if a is less. - else - return retval < 0; - } - return false; -} - -inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) { - if (a.tag != b.tag) return false; - - switch (typeFromTag(a.tag)) { - case TagType::INVALID: - case TagType::BOOL: - return true; - case TagType::ENUM: - case TagType::ENUM_REP: - case TagType::UINT: - case TagType::UINT_REP: - return a.f.integer == b.f.integer; - case TagType::ULONG: - case TagType::ULONG_REP: - return a.f.longInteger == b.f.longInteger; - case TagType::DATE: - return a.f.dateTime == b.f.dateTime; - case TagType::BIGNUM: - case TagType::BYTES: - if (a.blob.size() != b.blob.size()) return false; - return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0; - } - return false; -} - -void AuthorizationSet::Sort() { - std::sort(data_.begin(), data_.end(), keyParamLess); -} - -void AuthorizationSet::Deduplicate() { - if (data_.empty()) return; - - Sort(); - std::vector result; - - auto curr = data_.begin(); - auto prev = curr++; - for (; curr != data_.end(); ++prev, ++curr) { - if (prev->tag == Tag::INVALID) continue; - - if (!keyParamEqual(*prev, *curr)) { - result.emplace_back(std::move(*prev)); - } - } - result.emplace_back(std::move(*prev)); - - std::swap(data_, result); -} - -void AuthorizationSet::Union(const AuthorizationSet& other) { - data_.insert(data_.end(), other.data_.begin(), other.data_.end()); - Deduplicate(); -} - -void AuthorizationSet::Subtract(const AuthorizationSet& other) { - Deduplicate(); - - auto i = other.begin(); - while (i != other.end()) { - int pos = -1; - do { - pos = find(i->tag, pos); - if (pos != -1 && keyParamEqual(*i, data_[pos])) { - data_.erase(data_.begin() + pos); - break; - } - } while (pos != -1); - ++i; - } -} - -int AuthorizationSet::find(Tag tag, int begin) const { - auto iter = data_.begin() + (1 + begin); - - while (iter != data_.end() && iter->tag != tag) ++iter; - - if (iter != data_.end()) return iter - data_.begin(); - return -1; -} - -bool AuthorizationSet::erase(int index) { - auto pos = data_.begin() + index; - if (pos != data_.end()) { - data_.erase(pos); - return true; - } - return false; -} - -KeyParameter& AuthorizationSet::operator[](int at) { - return data_[at]; -} - -const KeyParameter& AuthorizationSet::operator[](int at) const { - return data_[at]; -} - -void AuthorizationSet::Clear() { - data_.clear(); -} - -size_t AuthorizationSet::GetTagCount(Tag tag) const { - size_t count = 0; - for (int pos = -1; (pos = find(tag, pos)) != -1;) ++count; - return count; -} - -NullOr AuthorizationSet::GetEntry(Tag tag) const { - int pos = find(tag); - if (pos == -1) return {}; - return data_[pos]; -} - -/** - * Persistent format is: - * | 32 bit indirect_size | - * -------------------------------- - * | indirect_size bytes of data | this is where the blob data is stored - * -------------------------------- - * | 32 bit element_count | number of entries - * | 32 bit elements_size | total bytes used by entries (entries have variable length) - * -------------------------------- - * | elementes_size bytes of data | where the elements are stored - */ - -/** - * Persistent format of blobs and bignums: - * | 32 bit tag | - * | 32 bit blob_length | - * | 32 bit indirect_offset | - */ - -struct OutStreams { - std::ostream& indirect; - std::ostream& elements; -}; - -OutStreams& serializeParamValue(OutStreams& out, const hidl_vec& blob) { - uint32_t buffer; - - // write blob_length - auto blob_length = blob.size(); - if (blob_length > std::numeric_limits::max()) { - out.elements.setstate(std::ios_base::badbit); - return out; - } - buffer = blob_length; - out.elements.write(reinterpret_cast(&buffer), sizeof(uint32_t)); - - // write indirect_offset - auto offset = out.indirect.tellp(); - if (offset < 0 || offset > std::numeric_limits::max() || - uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) { // overflow check - out.elements.setstate(std::ios_base::badbit); - return out; - } - buffer = offset; - out.elements.write(reinterpret_cast(&buffer), sizeof(uint32_t)); - - // write blob to indirect stream - if (blob_length) out.indirect.write(reinterpret_cast(&blob[0]), blob_length); - - return out; -} - -template -OutStreams& serializeParamValue(OutStreams& out, const T& value) { - out.elements.write(reinterpret_cast(&value), sizeof(T)); - return out; -} - -OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) { - // skip invalid entries. - return out; -} -template -OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) { - out.elements.write(reinterpret_cast(¶m.tag), sizeof(int32_t)); - return serializeParamValue(out, accessTagValue(ttag, param)); -} - -template -struct choose_serializer; -template -struct choose_serializer> { - static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { - return choose_serializer::serialize(out, param); - } -}; -template <> -struct choose_serializer<> { - static OutStreams& serialize(OutStreams& out, const KeyParameter&) { return out; } -}; -template -struct choose_serializer, Tail...> { - static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { - if (param.tag == tag) { - return keystore::serialize(TypedTag(), out, param); - } else { - return choose_serializer::serialize(out, param); - } - } -}; - -OutStreams& serialize(OutStreams& out, const KeyParameter& param) { - return choose_serializer::serialize(out, param); -} - -std::ostream& serialize(std::ostream& out, const std::vector& params) { - std::stringstream indirect; - std::stringstream elements; - OutStreams streams = {indirect, elements}; - for (const auto& param : params) { - serialize(streams, param); - } - if (indirect.bad() || elements.bad()) { - out.setstate(std::ios_base::badbit); - return out; - } - auto pos = indirect.tellp(); - if (pos < 0 || pos > std::numeric_limits::max()) { - out.setstate(std::ios_base::badbit); - return out; - } - uint32_t indirect_size = pos; - pos = elements.tellp(); - if (pos < 0 || pos > std::numeric_limits::max()) { - out.setstate(std::ios_base::badbit); - return out; - } - uint32_t elements_size = pos; - uint32_t element_count = params.size(); - - out.write(reinterpret_cast(&indirect_size), sizeof(uint32_t)); - - pos = out.tellp(); - if (indirect_size) out << indirect.rdbuf(); - assert(out.tellp() - pos == indirect_size); - - out.write(reinterpret_cast(&element_count), sizeof(uint32_t)); - out.write(reinterpret_cast(&elements_size), sizeof(uint32_t)); - - pos = out.tellp(); - if (elements_size) out << elements.rdbuf(); - assert(out.tellp() - pos == elements_size); - - return out; -} - -struct InStreams { - std::istream& indirect; - std::istream& elements; -}; - -InStreams& deserializeParamValue(InStreams& in, hidl_vec* blob) { - uint32_t blob_length = 0; - uint32_t offset = 0; - in.elements.read(reinterpret_cast(&blob_length), sizeof(uint32_t)); - blob->resize(blob_length); - in.elements.read(reinterpret_cast(&offset), sizeof(uint32_t)); - in.indirect.seekg(offset); - in.indirect.read(reinterpret_cast(&(*blob)[0]), blob->size()); - return in; -} - -template -InStreams& deserializeParamValue(InStreams& in, T* value) { - in.elements.read(reinterpret_cast(value), sizeof(T)); - return in; -} - -InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) { - // there should be no invalid KeyParamaters but if handle them as zero sized. - return in; -} - -template -InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) { - return deserializeParamValue(in, &accessTagValue(ttag, *param)); -} - -template -struct choose_deserializer; -template -struct choose_deserializer> { - static InStreams& deserialize(InStreams& in, KeyParameter* param) { - return choose_deserializer::deserialize(in, param); - } -}; -template <> -struct choose_deserializer<> { - static InStreams& deserialize(InStreams& in, KeyParameter*) { - // encountered an unknown tag -> fail parsing - in.elements.setstate(std::ios_base::badbit); - return in; - } -}; -template -struct choose_deserializer, Tail...> { - static InStreams& deserialize(InStreams& in, KeyParameter* param) { - if (param->tag == tag) { - return keystore::deserialize(TypedTag(), in, param); - } else { - return choose_deserializer::deserialize(in, param); - } - } -}; - -InStreams& deserialize(InStreams& in, KeyParameter* param) { - in.elements.read(reinterpret_cast(¶m->tag), sizeof(Tag)); - return choose_deserializer::deserialize(in, param); -} - -std::istream& deserialize(std::istream& in, std::vector* params) { - uint32_t indirect_size = 0; - in.read(reinterpret_cast(&indirect_size), sizeof(uint32_t)); - std::string indirect_buffer(indirect_size, '\0'); - if (indirect_buffer.size() != indirect_size) { - in.setstate(std::ios_base::badbit); - return in; - } - in.read(&indirect_buffer[0], indirect_buffer.size()); - - uint32_t element_count = 0; - in.read(reinterpret_cast(&element_count), sizeof(uint32_t)); - uint32_t elements_size = 0; - in.read(reinterpret_cast(&elements_size), sizeof(uint32_t)); - - std::string elements_buffer(elements_size, '\0'); - if (elements_buffer.size() != elements_size) { - in.setstate(std::ios_base::badbit); - return in; - } - in.read(&elements_buffer[0], elements_buffer.size()); - - if (in.bad()) return in; - - // TODO write one-shot stream buffer to avoid copying here - std::stringstream indirect(indirect_buffer); - std::stringstream elements(elements_buffer); - InStreams streams = {indirect, elements}; - - params->resize(element_count); - - for (uint32_t i = 0; i < element_count; ++i) { - deserialize(streams, &(*params)[i]); - } - return in; -} -void AuthorizationSet::Serialize(std::ostream* out) const { - serialize(*out, data_); -} -void AuthorizationSet::Deserialize(std::istream* in) { - deserialize(*in, &data_); -} - -} // namespace keystore diff --git a/authorization_set.h b/authorization_set.h deleted file mode 100644 index 8f68bb0..0000000 --- a/authorization_set.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright 2014 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. - */ - -#ifndef SYSTEM_VOLD_AUTHORIZATION_SET_H_ -#define SYSTEM_VOLD_AUTHORIZATION_SET_H_ - -#include - -#include "keymaster_tags.h" - -namespace keystore { - -class AuthorizationSetBuilder; - -/** - * An ordered collection of KeyParameters. It provides memory ownership and some convenient - * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters. - * For serialization, wrap the backing store of this structure in a hidl_vec. - */ -class AuthorizationSet { - public: - /** - * Construct an empty, dynamically-allocated, growable AuthorizationSet. - */ - AuthorizationSet(){}; - - // Copy constructor. - AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {} - - // Move constructor. - AuthorizationSet(AuthorizationSet&& other) : data_(std::move(other.data_)) {} - - // Constructor from hidl_vec - AuthorizationSet(const hidl_vec& other) { *this = other; } - - // Copy assignment. - AuthorizationSet& operator=(const AuthorizationSet& other) { - data_ = other.data_; - return *this; - } - - // Move assignment. - AuthorizationSet& operator=(AuthorizationSet&& other) { - data_ = std::move(other.data_); - return *this; - } - - AuthorizationSet& operator=(const hidl_vec& other) { - if (other.size() > 0) { - data_.resize(other.size()); - for (size_t i = 0; i < data_.size(); ++i) { - /* This makes a deep copy even of embedded blobs. - * See assignment operator/copy constructor of hidl_vec.*/ - data_[i] = other[i]; - } - } - return *this; - } - - /** - * Clear existing authorization set data - */ - void Clear(); - - ~AuthorizationSet() = default; - - /** - * Returns the size of the set. - */ - size_t size() const { return data_.size(); } - - /** - * Returns true if the set is empty. - */ - bool empty() const { return size() == 0; } - - /** - * Returns the data in the set, directly. Be careful with this. - */ - const KeyParameter* data() const { return data_.data(); } - - /** - * Sorts the set - */ - void Sort(); - - /** - * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the - * AuthorizationSetBuilder). - */ - void Deduplicate(); - - /** - * Adds all elements from \p set that are not already present in this AuthorizationSet. As a - * side-effect, if \p set is not null this AuthorizationSet will end up sorted. - */ - void Union(const AuthorizationSet& set); - - /** - * Removes all elements in \p set from this AuthorizationSet. - */ - void Subtract(const AuthorizationSet& set); - - /** - * Returns the offset of the next entry that matches \p tag, starting from the element after \p - * begin. If not found, returns -1. - */ - int find(Tag tag, int begin = -1) const; - - /** - * Removes the entry at the specified index. Returns true if successful, false if the index was - * out of bounds. - */ - bool erase(int index); - - /** - * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration - */ - std::vector::const_iterator begin() const { return data_.begin(); } - - /** - * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration - */ - std::vector::const_iterator end() const { return data_.end(); } - - /** - * Returns the nth element of the set. - * Like for std::vector::operator[] there is no range check performed. Use of out of range - * indices is undefined. - */ - KeyParameter& operator[](int n); - - /** - * Returns the nth element of the set. - * Like for std::vector::operator[] there is no range check performed. Use of out of range - * indices is undefined. - */ - const KeyParameter& operator[](int n) const; - - /** - * Returns true if the set contains at least one instance of \p tag - */ - bool Contains(Tag tag) const { return find(tag) != -1; } - - template - bool Contains(TypedTag ttag, const ValueT& value) const { - for (const auto& param : data_) { - auto entry = authorizationValue(ttag, param); - if (entry.isOk() && entry.value() == value) return true; - } - return false; - } - /** - * Returns the number of \p tag entries. - */ - size_t GetTagCount(Tag tag) const; - - template - inline NullOr::type&> GetTagValue(T tag) const { - auto entry = GetEntry(tag); - if (entry.isOk()) return authorizationValue(tag, entry.value()); - return {}; - } - - void push_back(const KeyParameter& param) { data_.push_back(param); } - void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); } - - /** - * Append the tag and enumerated value to the set. - * "val" may be exactly one parameter unless a boolean parameter is added. - * In this case "val" is omitted. This condition is checked at compile time by Authorization() - */ - template - void push_back(TypedTagT tag, Value&&... val) { - push_back(Authorization(tag, std::forward(val)...)); - } - - template - void append(Iterator begin, Iterator end) { - while (begin != end) { - push_back(*begin); - ++begin; - } - } - - hidl_vec hidl_data() const { - hidl_vec result; - result.setToExternal(const_cast(data()), size()); - return result; - } - - void Serialize(std::ostream* out) const; - void Deserialize(std::istream* in); - - private: - NullOr GetEntry(Tag tag) const; - - std::vector data_; -}; - -class AuthorizationSetBuilder : public AuthorizationSet { - public: - template - AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) { - push_back(ttag, std::forward(value)...); - return *this; - } - - template - AuthorizationSetBuilder& Authorization(TypedTag ttag, const uint8_t* data, - size_t data_length) { - hidl_vec new_blob; - new_blob.setToExternal(const_cast(data), data_length); - push_back(ttag, std::move(new_blob)); - return *this; - } - - template - AuthorizationSetBuilder& Authorization(TypedTag ttag, const char* data, - size_t data_length) { - return Authorization(ttag, reinterpret_cast(data), data_length); - } - - AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent); - AuthorizationSetBuilder& EcdsaKey(uint32_t key_size); - AuthorizationSetBuilder& AesKey(uint32_t key_size); - AuthorizationSetBuilder& HmacKey(uint32_t key_size); - - AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent); - AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent); - AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size); - AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size); - - AuthorizationSetBuilder& SigningKey(); - AuthorizationSetBuilder& EncryptionKey(); - AuthorizationSetBuilder& NoDigestOrPadding(); - AuthorizationSetBuilder& EcbMode(); - - AuthorizationSetBuilder& Digest(Digest digest) { return Authorization(TAG_DIGEST, digest); } - - AuthorizationSetBuilder& Padding(PaddingMode padding) { - return Authorization(TAG_PADDING, padding); - } -}; - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size, - uint64_t public_exponent) { - Authorization(TAG_ALGORITHM, Algorithm::RSA); - Authorization(TAG_KEY_SIZE, key_size); - Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent); - return *this; -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) { - Authorization(TAG_ALGORITHM, Algorithm::EC); - Authorization(TAG_KEY_SIZE, key_size); - return *this; -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) { - Authorization(TAG_ALGORITHM, Algorithm::AES); - return Authorization(TAG_KEY_SIZE, key_size); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) { - Authorization(TAG_ALGORITHM, Algorithm::HMAC); - Authorization(TAG_KEY_SIZE, key_size); - return SigningKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size, - uint64_t public_exponent) { - RsaKey(key_size, public_exponent); - return SigningKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size, - uint64_t public_exponent) { - RsaKey(key_size, public_exponent); - return EncryptionKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) { - EcdsaKey(key_size); - return SigningKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) { - AesKey(key_size); - return EncryptionKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() { - Authorization(TAG_PURPOSE, KeyPurpose::SIGN); - return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() { - Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT); - return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() { - Authorization(TAG_DIGEST, Digest::NONE); - return Authorization(TAG_PADDING, PaddingMode::NONE); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() { - return Authorization(TAG_BLOCK_MODE, BlockMode::ECB); -} - -} // namespace keystore - -#endif // SYSTEM_VOLD_AUTHORIZATION_SET_H_ diff --git a/keymaster_tags.h b/keymaster_tags.h deleted file mode 100644 index c89354d..0000000 --- a/keymaster_tags.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright 2014 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. - */ - -#ifndef SYSTEM_VOLD_KEYMASTER_TAGS_H_ -#define SYSTEM_VOLD_KEYMASTER_TAGS_H_ - -/** - * This header contains various definitions that make working with keymaster tags safer and easier. - * - * It makes use of a fair amount of template metaprogramming. The metaprogramming serves the purpose - * of making it impossible to make certain classes of mistakes when operating on keymaster - * authorizations. For example, it's an error to create a KeyParameter with tag == Tag::PURPOSE - * and then to assign Algorithm::RSA to algorithm element of its union. But because the user - * must choose the union field, there could be a mismatch which the compiler has now way to - * diagnose. - * - * The machinery in this header solves these problems by describing which union field corresponds - * to which Tag. Central to this mechanism is the template TypedTag. It has zero size and binds a - * numeric Tag to a type that the compiler understands. By means of the macro DECLARE_TYPED_TAG, - * we declare types for each of the tags defined in hardware/interfaces/keymaster/2.0/types.hal. - * - * The macro DECLARE_TYPED_TAG(name) generates a typename TAG_name_t and a zero sized instance - * TAG_name. Once these typed tags have been declared we define metafunctions mapping the each tag - * to its value c++ type and the correct union element of KeyParameter. This is done by means of - * the macros MAKE_TAG_*VALUE_ACCESSOR, which generates TypedTag2ValueType, a metafunction mapping - * a typed tag to the corresponding c++ type, and access function, accessTagValue returning a - * reference to the correct element of KeyParameter. - * E.g.: - * given "KeyParameter param;" then "accessTagValue(TAG_PURPOSE, param)" - * yields a reference to param.f.purpose - * If used in an assignment the compiler can now check the compatibility of the assigned value. - * - * For convenience we also provide the constructor like function Authorization(). - * Authorization takes a typed tag and a value and checks at compile time whether the value given - * is suitable for the given tag. At runtime it creates a new KeyParameter initialized with the - * given tag and value and returns it by value. - * - * The second convenience function, authorizationValue, allows access to the KeyParameter value in - * a safe way. It takes a typed tag and a KeyParameter and returns a reference to the value wrapped - * by NullOr. NullOr has out-of-band information about whether it is save to access the wrapped - * reference. - * E.g.: - * auto param = Authorization(TAG_ALGORITM, Algorithm::RSA); - * auto value1 = authorizationValue(TAG_PURPOSE, param); - * auto value2 = authorizationValue(TAG_ALGORITM, param); - * value1.isOk() yields false, but value2.isOk() yields true, thus value2.value() is save to access. - */ - -#include -#include -#include - -namespace keystore { - -using ::android::hardware::keymaster::V3_0::Algorithm; -using ::android::hardware::keymaster::V3_0::BlockMode; -using ::android::hardware::keymaster::V3_0::Digest; -using ::android::hardware::keymaster::V3_0::EcCurve; -using ::android::hardware::keymaster::V3_0::ErrorCode; -using ::android::hardware::keymaster::V3_0::HardwareAuthToken; -using ::android::hardware::keymaster::V3_0::HardwareAuthenticatorType; -using ::android::hardware::keymaster::V3_0::IKeymasterDevice; -using ::android::hardware::keymaster::V3_0::KeyBlobUsageRequirements; -using ::android::hardware::keymaster::V3_0::KeyCharacteristics; -using ::android::hardware::keymaster::V3_0::KeyDerivationFunction; -using ::android::hardware::keymaster::V3_0::KeyFormat; -using ::android::hardware::keymaster::V3_0::KeyOrigin; -using ::android::hardware::keymaster::V3_0::KeyParameter; -using ::android::hardware::keymaster::V3_0::KeyPurpose; -using ::android::hardware::keymaster::V3_0::PaddingMode; -using ::android::hardware::keymaster::V3_0::Tag; -using ::android::hardware::keymaster::V3_0::TagType; - -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; - -// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We -// need these old values to be able to support old keys that use them. -static const int32_t KM_TAG_DIGEST_OLD = static_cast(TagType::ENUM) | 5; -static const int32_t KM_TAG_PADDING_OLD = static_cast(TagType::ENUM) | 7; - -constexpr TagType typeFromTag(Tag tag) { - return static_cast(static_cast(tag) & static_cast(0xf0000000)); -} - -/** - * TypedTag is a templatized version of Tag, which provides compile-time checking of - * keymaster tag types. Instances are convertible to Tag, so they can be used wherever - * Tag is expected, and because they encode the tag type it's possible to create - * function overloads that only operate on tags with a particular type. - */ -template -struct TypedTag { - inline TypedTag() { - // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type - // 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile - // error (no match for template specialization StaticAssert), with no run-time cost. - static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type"); - } - operator Tag() const { return tag; } -}; - -template -struct Tag2TypedTag { - typedef TypedTag type; -}; - -template -struct Tag2String; - -#define _TAGS_STRINGIFY(x) #x -#define TAGS_STRINGIFY(x) _TAGS_STRINGIFY(x) - -#define DECLARE_TYPED_TAG(name) \ - typedef typename Tag2TypedTag::type TAG_##name##_t; \ - extern TAG_##name##_t TAG_##name; \ - template <> \ - struct Tag2String { \ - static const char* value() { return "Tag::" TAGS_STRINGIFY(name); } \ - } - -DECLARE_TYPED_TAG(INVALID); -DECLARE_TYPED_TAG(KEY_SIZE); -DECLARE_TYPED_TAG(MAC_LENGTH); -DECLARE_TYPED_TAG(CALLER_NONCE); -DECLARE_TYPED_TAG(MIN_MAC_LENGTH); -DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT); -DECLARE_TYPED_TAG(ECIES_SINGLE_HASH_MODE); -DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID); -DECLARE_TYPED_TAG(ACTIVE_DATETIME); -DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME); -DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME); -DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS); -DECLARE_TYPED_TAG(MAX_USES_PER_BOOT); -DECLARE_TYPED_TAG(ALL_USERS); -DECLARE_TYPED_TAG(USER_ID); -DECLARE_TYPED_TAG(USER_SECURE_ID); -DECLARE_TYPED_TAG(NO_AUTH_REQUIRED); -DECLARE_TYPED_TAG(AUTH_TIMEOUT); -DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY); -DECLARE_TYPED_TAG(ALL_APPLICATIONS); -DECLARE_TYPED_TAG(APPLICATION_ID); -DECLARE_TYPED_TAG(APPLICATION_DATA); -DECLARE_TYPED_TAG(CREATION_DATETIME); -DECLARE_TYPED_TAG(ROLLBACK_RESISTANT); -DECLARE_TYPED_TAG(ROOT_OF_TRUST); -DECLARE_TYPED_TAG(ASSOCIATED_DATA); -DECLARE_TYPED_TAG(NONCE); -DECLARE_TYPED_TAG(AUTH_TOKEN); -DECLARE_TYPED_TAG(BOOTLOADER_ONLY); -DECLARE_TYPED_TAG(OS_VERSION); -DECLARE_TYPED_TAG(OS_PATCHLEVEL); -DECLARE_TYPED_TAG(UNIQUE_ID); -DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE); -DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID); -DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION); - -DECLARE_TYPED_TAG(PURPOSE); -DECLARE_TYPED_TAG(ALGORITHM); -DECLARE_TYPED_TAG(BLOCK_MODE); -DECLARE_TYPED_TAG(DIGEST); -DECLARE_TYPED_TAG(PADDING); -DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS); -DECLARE_TYPED_TAG(ORIGIN); -DECLARE_TYPED_TAG(USER_AUTH_TYPE); -DECLARE_TYPED_TAG(KDF); -DECLARE_TYPED_TAG(EC_CURVE); - -template -struct MetaList {}; - -using all_tags_t = MetaList< - TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t, - TAG_RSA_PUBLIC_EXPONENT_t, TAG_ECIES_SINGLE_HASH_MODE_t, TAG_INCLUDE_UNIQUE_ID_t, - TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, - TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_ALL_USERS_t, TAG_USER_ID_t, - TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t, - TAG_ALL_APPLICATIONS_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t, - TAG_ROLLBACK_RESISTANT_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, - TAG_AUTH_TOKEN_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, - TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t, - TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t, - TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_KDF_t, TAG_EC_CURVE_t>; - -/* implementation in keystore_utils.cpp */ -extern const char* stringifyTag(Tag tag); - -template -struct TypedTag2ValueType; - -#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \ - template \ - struct TypedTag2ValueType> { \ - typedef decltype(static_cast(nullptr)->field_name) type; \ - }; \ - template \ - inline auto accessTagValue(TypedTag, const KeyParameter& param) \ - ->const decltype(param.field_name)& { \ - return param.field_name; \ - } \ - template \ - inline auto accessTagValue(TypedTag, KeyParameter& param) \ - ->decltype(param.field_name)& { \ - return param.field_name; \ - } - -MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, f.longInteger) -MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, f.longInteger) -MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, f.dateTime) -MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, f.integer) -MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, f.integer) -MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, f.boolValue) -MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob) -MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob) - -#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name) \ - template <> \ - struct TypedTag2ValueType { \ - typedef decltype(static_cast(nullptr)->field_name) type; \ - }; \ - inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param) \ - ->const decltype(param.field_name)& { \ - return param.field_name; \ - } \ - inline auto accessTagValue(decltype(typed_tag), KeyParameter& param) \ - ->decltype(param.field_name)& { \ - return param.field_name; \ - } - -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, f.algorithm) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOB_USAGE_REQUIREMENTS, f.keyBlobUsageRequirements) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, f.blockMode) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, f.digest) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, f.ecCurve) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_KDF, f.keyDerivationFunction) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, f.origin) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType) - -template -inline KeyParameter makeKeyParameter(TypedTag ttag, ValueT&& value) { - KeyParameter param; - param.tag = tag; - param.f.longInteger = 0; - accessTagValue(ttag, param) = std::forward(value); - return param; -} - -// the boolean case -template -inline KeyParameter makeKeyParameter(TypedTag) { - KeyParameter param; - param.tag = tag; - param.f.boolValue = true; - return param; -} - -template -struct FirstOrNoneHelper; -template -struct FirstOrNoneHelper { - typedef First type; -}; -template <> -struct FirstOrNoneHelper<> { - struct type {}; -}; - -template -using FirstOrNone = typename FirstOrNoneHelper::type; - -template -inline KeyParameter Authorization(TypedTag ttag, Args&&... args) { - static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0), - "TagType::BOOL Authorizations do not take parameters. Presence is truth."); - static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1), - "Authorization other then TagType::BOOL take exactly one parameter."); - static_assert( - tag_type == TagType::BOOL || - std::is_convertible>>, - typename TypedTag2ValueType>::type>::value, - "Invalid argument type for given tag."); - - return makeKeyParameter(ttag, std::forward(args)...); -} - -/** - * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out - * of band. Note that if the wrapped value is a reference it is unsafe to access the value if - * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the - * wrapped value. In this case the pointer will be NULL though, and the value will be default - * constructed. - */ -template -class NullOr { - template - struct reference_initializer { - static T&& init() { return *static_cast*>(nullptr); } - }; - template - struct pointer_initializer { - static T init() { return nullptr; } - }; - template - struct value_initializer { - static T init() { return T(); } - }; - template - using initializer_t = std::conditional_t< - std::is_lvalue_reference::value, reference_initializer, - std::conditional_t::value, pointer_initializer, value_initializer>>; - - public: - NullOr() : value_(initializer_t::init()), null_(true) {} - NullOr(ValueT&& value) : value_(std::forward(value)), null_(false) {} - - bool isOk() const { return !null_; } - - const ValueT& value() const & { return value_; } - ValueT& value() & { return value_; } - ValueT&& value() && { return std::move(value_); } - - private: - ValueT value_; - bool null_; -}; - -template -std::remove_reference_t NullOrOr(T&& v) { - if (v.isOk()) return v; - return {}; -} - -template -std::remove_reference_t NullOrOr(Head&& head, Tail&&... tail) { - if (head.isOk()) return head; - return NullOrOr(std::forward(tail)...); -} - -template -std::remove_reference_t defaultOr(NullOr&& optional, Default&& def) { - static_assert( - std::is_convertible, std::remove_reference_t>::value, - "Type of default value must match the type wrapped by NullOr"); - if (optional.isOk()) return optional.value(); - return def; -} - -template -inline NullOr>::type&> authorizationValue( - TypedTag ttag, const KeyParameter& param) { - if (tag != param.tag) return {}; - return accessTagValue(ttag, param); -} - -} // namespace keystore - -#endif // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_ diff --git a/keystore_hidl_support.h b/keystore_hidl_support.h deleted file mode 100644 index d21e02a..0000000 --- a/keystore_hidl_support.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - ** - ** Copyright 2016, 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. - */ - -#ifndef SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_ -#define SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_ - -#include -#include -#include - -#include - -#include "keymaster_tags.h" - -namespace keystore { - -inline static std::ostream& formatArgs(std::ostream& out) { - return out; -} - -template -inline static std::ostream& formatArgs(std::ostream& out, First&& first, Args&&... args) { - out << first; - return formatArgs(out, args...); -} - -template -inline static std::string argsToString(Args&&... args) { - std::stringstream s; - formatArgs(s, args...); - return s.str(); -} - -template -inline static ErrorCode ksHandleHidlError(const Return& error, Msgs&&... msgs) { - if (!error.isOk()) { - ALOGE("HIDL call failed with %s @ %s", error.description().c_str(), - argsToString(msgs...).c_str()); - return ErrorCode::UNKNOWN_ERROR; - } - return ErrorCode(error); -} -template -inline static ErrorCode ksHandleHidlError(const Return& error, Msgs&&... msgs) { - if (!error.isOk()) { - ALOGE("HIDL call failed with %s @ %s", error.description().c_str(), - argsToString(msgs...).c_str()); - return ErrorCode::UNKNOWN_ERROR; - } - return ErrorCode::OK; -} - -#define KS_HANDLE_HIDL_ERROR(rc) \ - ::keystore::ksHandleHidlError(rc, __FILE__, ":", __LINE__, ":", __PRETTY_FUNCTION__) - -inline static hidl_vec blob2hidlVec(const uint8_t* data, const size_t length, - bool inPlace = true) { - hidl_vec result; - if (inPlace) - result.setToExternal(const_cast(data), length); - else { - result.resize(length); - memcpy(&result[0], data, length); - } - return result; -} - -inline static hidl_vec blob2hidlVec(const std::string& value) { - hidl_vec result; - result.setToExternal( - reinterpret_cast(const_cast(value.data())), - static_cast(value.size())); - return result; -} - -inline static hidl_vec blob2hidlVec(const std::vector& blob) { - hidl_vec result; - result.setToExternal(const_cast(blob.data()), static_cast(blob.size())); - return result; -} - -template -inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) { - const uint8_t* value_ptr = reinterpret_cast(&value); - return std::copy(value_ptr, value_ptr + sizeof(value), dest); -} - -inline std::string hidlVec2String(const hidl_vec& value) { - return std::string(reinterpret_cast(&value[0]), value.size()); -} - -} // namespace keystore - -#endif // SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_