From 015ec30b36713308db9f0051e8f97338419d7fbf Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Tue, 31 Jan 2017 11:31:08 +0000 Subject: [PATCH] Port cryptfs to HILD keymaster HAL Cryptfs uses keymaster for key derivation. Vold has a C++ abstraction for Keymaster. However, cryptfs, being a pure C implementation, uses its own abstraction of the keymaster HAL. This patch expresses cryptfs' keymaster abstraction in terms of vold's C++ Keymaster abstraction, consolidating the code base to a single point where the actual keymaster HAL is beeing used. Test: successfully upgrade bullhead/angler while using FDE and having a PIN set run vold_cryptfs_scrypt_hidlization_equivalence_test Bug: 35028230 Bug: 32020919 Change-Id: Ic3b765720be0cf7899dda5005fa89347ffb59b9f --- Keymaster.cpp | 132 +++++++++++++++++++++++- Keymaster.h | 45 ++++++++- cryptfs.c | 272 +++----------------------------------------------- 3 files changed, 187 insertions(+), 262 deletions(-) diff --git a/Keymaster.cpp b/Keymaster.cpp index bb99cde..7119dcc 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -31,7 +31,8 @@ KeymasterOperation::~KeymasterOperation() { } bool KeymasterOperation::updateCompletely(const std::string& input, std::string* output) { - output->clear(); + if (output) + output->clear(); auto it = input.begin(); uint32_t inputConsumed; @@ -55,7 +56,7 @@ bool KeymasterOperation::updateCompletely(const std::string& input, std::string* return false; } if (km_error != ErrorCode::OK) { - LOG(ERROR) << "update failed, code " << uint32_t(km_error); + LOG(ERROR) << "update failed, code " << int32_t(km_error); mDevice = nullptr; return false; } @@ -86,7 +87,7 @@ bool KeymasterOperation::finish(std::string* output) { return false; } if (km_error != ErrorCode::OK) { - LOG(ERROR) << "finish failed, code " << uint32_t(km_error); + LOG(ERROR) << "finish failed, code " << int32_t(km_error); return false; } return true; @@ -177,11 +178,134 @@ KeymasterOperation Keymaster::begin(KeyPurpose purpose, const std::string& key, return KeymasterOperation(ErrorCode::UNKNOWN_ERROR); } if (km_error != ErrorCode::OK) { - LOG(ERROR) << "begin failed, code " << uint32_t(km_error); + LOG(ERROR) << "begin failed, code " << int32_t(km_error); return KeymasterOperation(km_error); } return KeymasterOperation(mDevice, mOpHandle); } +bool Keymaster::isSecure() { + bool _isSecure = false; + auto rc = mDevice->getHardwareFeatures( + [&] (bool isSecure, bool, bool, bool) { _isSecure = isSecure; }); + return rc.isOk() && _isSecure; +} } // namespace vold } // namespace android + +using namespace ::android::vold; + +int keymaster_compatibility_cryptfs_scrypt() { + return Keymaster().isSecure(); +} + +int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size, + uint64_t rsa_exponent, + uint32_t ratelimit, + uint8_t* key_buffer, + uint32_t key_buffer_size, + uint32_t* key_out_size) +{ + Keymaster dev; + std::string key; + if (!dev) { + LOG(ERROR) << "Failed to initiate keymaster session"; + return -1; + } + if (!key_buffer || !key_out_size) { + LOG(ERROR) << __FILE__ << ":" << __LINE__ << ":Invalid argument"; + return -1; + } + if (key_out_size) { + *key_out_size = 0; + } + + auto paramBuilder = 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); + + if (!dev.generateKey(paramBuilder, &key)) { + return -1; + } + + if (key_out_size) { + *key_out_size = key.size(); + } + + if (key_buffer_size < key.size()) { + return -1; + } + + std::copy(key.data(), key.data() + key.size(), key_buffer); + return 0; +} + +int keymaster_sign_object_for_cryptfs_scrypt(const uint8_t* key_blob, + size_t key_blob_size, + uint32_t ratelimit, + const uint8_t* object, + const size_t object_size, + uint8_t** signature_buffer, + size_t* signature_buffer_size) +{ + Keymaster dev; + if (!dev) { + LOG(ERROR) << "Failed to initiate keymaster session"; + return -1; + } + if (!key_blob || !object || !signature_buffer || !signature_buffer_size) { + LOG(ERROR) << __FILE__ << ":" << __LINE__ << ":Invalid argument"; + return -1; + } + + 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); + + while (true) { + op = dev.begin(KeyPurpose::SIGN, key, paramBuilder, &outParams); + if (op.error() == ErrorCode::KEY_RATE_LIMIT_EXCEEDED) { + sleep(ratelimit); + continue; + } else break; + } + + if (op.error() != ErrorCode::OK) { + LOG(ERROR) << "Error starting keymaster signature transaction: " << int32_t(op.error()); + return -1; + } + + if (!op.updateCompletely(input, &output)) { + LOG(ERROR) << "Error sending data to keymaster signature transaction: " + << uint32_t(op.error()); + return -1; + } + + if (!op.finish(&output)) { + LOG(ERROR) << "Error finalizing keymaster signature transaction: " << int32_t(op.error()); + return -1; + } + + *signature_buffer = reinterpret_cast(malloc(output.size())); + if (*signature_buffer == nullptr) { + LOG(ERROR) << "Error allocation buffer for keymaster signature"; + return -1; + } + *signature_buffer_size = output.size(); + std::copy(output.data(), output.data() + output.size(), *signature_buffer); + return 0; +} diff --git a/Keymaster.h b/Keymaster.h index 893a6d1..7de8700 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -17,6 +17,8 @@ #ifndef ANDROID_VOLD_KEYMASTER_H #define ANDROID_VOLD_KEYMASTER_H +#ifdef __cplusplus + #include #include #include @@ -59,8 +61,17 @@ class KeymasterOperation { } // Construct an object in an error state for error returns KeymasterOperation() - : mDevice{nullptr}, mOpHandle{static_cast(0)}, + : mDevice{nullptr}, mOpHandle{0}, mError {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.mOpHandle = 0; + return *this; + } private: KeymasterOperation(const sp& d, uint64_t h) @@ -92,6 +103,7 @@ class Keymaster { // 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); + bool isSecure(); private: sp mDevice; @@ -101,4 +113,35 @@ class Keymaster { } // namespace vold } // namespace android +#endif // __cplusplus + + +/* + * The following functions provide C bindings to keymaster services + * needed by cryptfs scrypt. The compatibility check checks whether + * the keymaster implementation is considered secure, i.e., TEE backed. + * The create_key function generates an RSA key for signing. + * The sign_object function signes an object with the given keymaster + * key. + */ +__BEGIN_DECLS + +int keymaster_compatibility_cryptfs_scrypt(); +int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size, + uint64_t rsa_exponent, + uint32_t ratelimit, + uint8_t* key_buffer, + uint32_t key_buffer_size, + uint32_t* key_out_size); + +int keymaster_sign_object_for_cryptfs_scrypt(const uint8_t* key_blob, + size_t key_blob_size, + uint32_t ratelimit, + const uint8_t* object, + const size_t object_size, + uint8_t** signature_buffer, + size_t* signature_buffer_size); + +__END_DECLS + #endif diff --git a/cryptfs.c b/cryptfs.c index e2606ec..2797409 100644 --- a/cryptfs.c +++ b/cryptfs.c @@ -61,12 +61,9 @@ #include "f2fs_sparseblock.h" #include "CheckBattery.h" #include "Process.h" +#include "Keymaster.h" #include -#include -#include - -#define UNUSED __attribute__((unused)) #define UNUSED __attribute__((unused)) @@ -108,181 +105,32 @@ static char *saved_mount_point; static int master_key_saved = 0; static struct crypt_persist_data *persist_data = NULL; -static int keymaster_init(keymaster0_device_t **keymaster0_dev, - keymaster1_device_t **keymaster1_dev) -{ - int rc; - - const hw_module_t* mod; - rc = hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod); - if (rc) { - ALOGE("could not find any keystore module"); - goto err; - } - - SLOGI("keymaster module name is %s", mod->name); - SLOGI("keymaster version is %d", mod->module_api_version); - - *keymaster0_dev = NULL; - *keymaster1_dev = NULL; - if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_1_0) { - SLOGI("Found keymaster1 module, using keymaster1 API."); - rc = keymaster1_open(mod, keymaster1_dev); - } else { - SLOGI("Found keymaster0 module, using keymaster0 API."); - rc = keymaster0_open(mod, keymaster0_dev); - } - - if (rc) { - ALOGE("could not open keymaster device in %s (%s)", - KEYSTORE_HARDWARE_MODULE_ID, strerror(-rc)); - goto err; - } - - return 0; - -err: - *keymaster0_dev = NULL; - *keymaster1_dev = NULL; - return rc; -} - /* Should we use keymaster? */ static int keymaster_check_compatibility() { - keymaster0_device_t *keymaster0_dev = 0; - keymaster1_device_t *keymaster1_dev = 0; - int rc = 0; - - if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) { - SLOGE("Failed to init keymaster"); - rc = -1; - goto out; - } - - if (keymaster1_dev) { - rc = 1; - goto out; - } - - if (!keymaster0_dev || !keymaster0_dev->common.module) { - rc = -1; - goto out; - } - - // TODO(swillden): Check to see if there's any reason to require v0.3. I think v0.1 and v0.2 - // should work. - if (keymaster0_dev->common.module->module_api_version - < KEYMASTER_MODULE_API_VERSION_0_3) { - rc = 0; - goto out; - } - - if (!(keymaster0_dev->flags & KEYMASTER_SOFTWARE_ONLY) && - (keymaster0_dev->flags & KEYMASTER_BLOBS_ARE_STANDALONE)) { - rc = 1; - } - -out: - if (keymaster1_dev) { - keymaster1_close(keymaster1_dev); - } - if (keymaster0_dev) { - keymaster0_close(keymaster0_dev); - } - return rc; + return keymaster_compatibility_cryptfs_scrypt(); } /* Create a new keymaster key and store it in this footer */ static int keymaster_create_key(struct crypt_mnt_ftr *ftr) { - uint8_t* key = 0; - keymaster0_device_t *keymaster0_dev = 0; - keymaster1_device_t *keymaster1_dev = 0; - if (ftr->keymaster_blob_size) { SLOGI("Already have key"); return 0; } - if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) { - SLOGE("Failed to init keymaster"); + int rc = keymaster_create_key_for_cryptfs_scrypt(RSA_KEY_SIZE, RSA_EXPONENT, + KEYMASTER_CRYPTFS_RATE_LIMIT, ftr->keymaster_blob, KEYMASTER_BLOB_SIZE, + &ftr->keymaster_blob_size); + if (rc) { + if (ftr->keymaster_blob_size > KEYMASTER_BLOB_SIZE) { + SLOGE("Keymaster key blob to large)"); + ftr->keymaster_blob_size = 0; + } + SLOGE("Failed to generate keypair"); return -1; } - - int rc = 0; - size_t key_size = 0; - if (keymaster1_dev) { - keymaster_key_param_t params[] = { - /* Algorithm & size specifications. Stick with RSA for now. Switch to AES later. */ - keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_RSA), - keymaster_param_int(KM_TAG_KEY_SIZE, RSA_KEY_SIZE), - keymaster_param_long(KM_TAG_RSA_PUBLIC_EXPONENT, RSA_EXPONENT), - - /* The only allowed purpose for this key is signing. */ - keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN), - - /* Padding & digest specifications. */ - keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE), - keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE), - - /* Require that the key be usable in standalone mode. File system isn't available. */ - keymaster_param_enum(KM_TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE), - - /* No auth requirements, because cryptfs is not yet integrated with gatekeeper. */ - keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED), - - /* Rate-limit key usage attempts, to rate-limit brute force */ - keymaster_param_int(KM_TAG_MIN_SECONDS_BETWEEN_OPS, KEYMASTER_CRYPTFS_RATE_LIMIT), - }; - keymaster_key_param_set_t param_set = { params, sizeof(params)/sizeof(*params) }; - keymaster_key_blob_t key_blob; - keymaster_error_t error = keymaster1_dev->generate_key(keymaster1_dev, ¶m_set, - &key_blob, - NULL /* characteristics */); - if (error != KM_ERROR_OK) { - SLOGE("Failed to generate keymaster1 key, error %d", error); - rc = -1; - goto out; - } - - key = (uint8_t*)key_blob.key_material; - key_size = key_blob.key_material_size; - } - else if (keymaster0_dev) { - keymaster_rsa_keygen_params_t params; - memset(¶ms, '\0', sizeof(params)); - params.public_exponent = RSA_EXPONENT; - params.modulus_size = RSA_KEY_SIZE; - - if (keymaster0_dev->generate_keypair(keymaster0_dev, TYPE_RSA, ¶ms, - &key, &key_size)) { - SLOGE("Failed to generate keypair"); - rc = -1; - goto out; - } - } else { - SLOGE("Cryptfs bug: keymaster_init succeeded but didn't initialize a device"); - rc = -1; - goto out; - } - - if (key_size > KEYMASTER_BLOB_SIZE) { - SLOGE("Keymaster key too large for crypto footer"); - rc = -1; - goto out; - } - - memcpy(ftr->keymaster_blob, key, key_size); - ftr->keymaster_blob_size = key_size; - -out: - if (keymaster0_dev) - keymaster0_close(keymaster0_dev); - if (keymaster1_dev) - keymaster1_close(keymaster1_dev); - free(key); - return rc; + return 0; } /* This signs the given object using the keymaster key. */ @@ -292,15 +140,6 @@ static int keymaster_sign_object(struct crypt_mnt_ftr *ftr, unsigned char **signature, size_t *signature_size) { - int rc = 0; - keymaster0_device_t *keymaster0_dev = 0; - keymaster1_device_t *keymaster1_dev = 0; - if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) { - SLOGE("Failed to init keymaster"); - rc = -1; - goto out; - } - unsigned char to_sign[RSA_KEY_SIZE_BYTES]; size_t to_sign_size = sizeof(to_sign); memset(to_sign, 0, RSA_KEY_SIZE_BYTES); @@ -332,91 +171,10 @@ static int keymaster_sign_object(struct crypt_mnt_ftr *ftr, break; default: SLOGE("Unknown KDF type %d", ftr->kdf_type); - rc = -1; - goto out; + return -1; } - - if (keymaster0_dev) { - keymaster_rsa_sign_params_t params; - params.digest_type = DIGEST_NONE; - params.padding_type = PADDING_NONE; - - rc = keymaster0_dev->sign_data(keymaster0_dev, - ¶ms, - ftr->keymaster_blob, - ftr->keymaster_blob_size, - to_sign, - to_sign_size, - signature, - signature_size); - goto out; - } else if (keymaster1_dev) { - keymaster_key_blob_t key = { ftr->keymaster_blob, ftr->keymaster_blob_size }; - keymaster_key_param_t params[] = { - keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE), - keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE), - }; - keymaster_key_param_set_t param_set = { params, sizeof(params)/sizeof(*params) }; - keymaster_operation_handle_t op_handle; - keymaster_error_t error = keymaster1_dev->begin(keymaster1_dev, KM_PURPOSE_SIGN, &key, - ¶m_set, NULL /* out_params */, - &op_handle); - if (error == KM_ERROR_KEY_RATE_LIMIT_EXCEEDED) { - // Key usage has been rate-limited. Wait a bit and try again. - sleep(KEYMASTER_CRYPTFS_RATE_LIMIT); - error = keymaster1_dev->begin(keymaster1_dev, KM_PURPOSE_SIGN, &key, - ¶m_set, NULL /* out_params */, - &op_handle); - } - if (error != KM_ERROR_OK) { - SLOGE("Error starting keymaster signature transaction: %d", error); - rc = -1; - goto out; - } - - keymaster_blob_t input = { to_sign, to_sign_size }; - size_t input_consumed; - error = keymaster1_dev->update(keymaster1_dev, op_handle, NULL /* in_params */, - &input, &input_consumed, NULL /* out_params */, - NULL /* output */); - if (error != KM_ERROR_OK) { - SLOGE("Error sending data to keymaster signature transaction: %d", error); - rc = -1; - goto out; - } - if (input_consumed != to_sign_size) { - // This should never happen. If it does, it's a bug in the keymaster implementation. - SLOGE("Keymaster update() did not consume all data."); - keymaster1_dev->abort(keymaster1_dev, op_handle); - rc = -1; - goto out; - } - - keymaster_blob_t tmp_sig; - error = keymaster1_dev->finish(keymaster1_dev, op_handle, NULL /* in_params */, - NULL /* verify signature */, NULL /* out_params */, - &tmp_sig); - if (error != KM_ERROR_OK) { - SLOGE("Error finishing keymaster signature transaction: %d", error); - rc = -1; - goto out; - } - - *signature = (uint8_t*)tmp_sig.data; - *signature_size = tmp_sig.data_length; - } else { - SLOGE("Cryptfs bug: keymaster_init succeded but didn't initialize a device."); - rc = -1; - goto out; - } - - out: - if (keymaster1_dev) - keymaster1_close(keymaster1_dev); - if (keymaster0_dev) - keymaster0_close(keymaster0_dev); - - return rc; + return keymaster_sign_object_for_cryptfs_scrypt(ftr->keymaster_blob, ftr->keymaster_blob_size, + KEYMASTER_CRYPTFS_RATE_LIMIT, to_sign, to_sign_size, signature, signature_size); } /* Store password when userdata is successfully decrypted and mounted.