diff --git a/Keymaster.cpp b/Keymaster.cpp index 1bbeb61..4d055c2 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -203,71 +203,83 @@ int keymaster_compatibility_cryptfs_scrypt() { return dev.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; +static bool write_string_to_buf(const std::string& towrite, uint8_t* buffer, uint32_t buffer_size, + uint32_t* out_size) { + if (!buffer || !out_size) { + LOG(ERROR) << "Missing target pointers"; + return false; } - if (!key_buffer || !key_out_size) { - LOG(ERROR) << __FILE__ << ":" << __LINE__ << ":Invalid argument"; - return -1; + *out_size = towrite.size(); + if (buffer_size < towrite.size()) { + LOG(ERROR) << "Buffer too small " << buffer_size << " < " << towrite.size(); + return false; } + memset(buffer, '\0', buffer_size); + std::copy(towrite.begin(), towrite.end(), buffer); + 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); +} + +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) { 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)) { + Keymaster dev; + if (!dev) { + LOG(ERROR) << "Failed to initiate keymaster session"; return -1; } + std::string key; + if (!dev.generateKey(keyParams(rsa_key_size, rsa_exponent, ratelimit), &key)) return -1; + if (!write_string_to_buf(key, key_buffer, key_buffer_size, key_out_size)) return -1; + return 0; +} +int keymaster_upgrade_key_for_cryptfs_scrypt(uint32_t rsa_key_size, uint64_t rsa_exponent, + uint32_t ratelimit, const uint8_t* key_blob, + size_t key_blob_size, uint8_t* key_buffer, + uint32_t key_buffer_size, uint32_t* key_out_size) { if (key_out_size) { - *key_out_size = key.size(); + *key_out_size = 0; } - - if (key_buffer_size < key.size()) { + Keymaster dev; + if (!dev) { + LOG(ERROR) << "Failed to initiate keymaster session"; return -1; } - - std::copy(key.data(), key.data() + key.size(), key_buffer); + std::string old_key(reinterpret_cast(key_blob), key_blob_size); + std::string new_key; + if (!dev.upgradeKey(old_key, keyParams(rsa_key_size, rsa_exponent, ratelimit), &new_key)) + return -1; + if (!write_string_to_buf(new_key, key_buffer, key_buffer_size, key_out_size)) return -1; 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) -{ +KeymasterSignResult 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; + return KeymasterSignResult::error; } if (!key_blob || !object || !signature_buffer || !signature_buffer_size) { LOG(ERROR) << __FILE__ << ":" << __LINE__ << ":Invalid argument"; - return -1; + return KeymasterSignResult::error; } AuthorizationSet outParams; @@ -288,28 +300,33 @@ int keymaster_sign_object_for_cryptfs_scrypt(const uint8_t* key_blob, } else break; } + if (op.errorCode() == ErrorCode::KEY_REQUIRES_UPGRADE) { + LOG(ERROR) << "Keymaster key requires upgrade"; + return KeymasterSignResult::upgrade; + } + if (op.errorCode() != ErrorCode::OK) { LOG(ERROR) << "Error starting keymaster signature transaction: " << int32_t(op.errorCode()); - return -1; + return KeymasterSignResult::error; } if (!op.updateCompletely(input, &output)) { LOG(ERROR) << "Error sending data to keymaster signature transaction: " << uint32_t(op.errorCode()); - return -1; + return KeymasterSignResult::error; } if (!op.finish(&output)) { LOG(ERROR) << "Error finalizing keymaster signature transaction: " << int32_t(op.errorCode()); - return -1; + return KeymasterSignResult::error; } *signature_buffer = reinterpret_cast(malloc(output.size())); if (*signature_buffer == nullptr) { LOG(ERROR) << "Error allocation buffer for keymaster signature"; - return -1; + return KeymasterSignResult::error; } *signature_buffer_size = output.size(); std::copy(output.data(), output.data() + output.size(), *signature_buffer); - return 0; + return KeymasterSignResult::ok; } diff --git a/Keymaster.h b/Keymaster.h index f24a0c0..6eec6e9 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -136,6 +136,14 @@ class Keymaster { * key. */ +/* Return values for keymaster_sign_object_for_cryptfs_scrypt */ + +enum class KeymasterSignResult { + ok = 0, + error = -1, + upgrade = -2, +}; + int keymaster_compatibility_cryptfs_scrypt(); int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size, uint64_t rsa_exponent, @@ -144,13 +152,14 @@ int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size, 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); +int keymaster_upgrade_key_for_cryptfs_scrypt(uint32_t rsa_key_size, uint64_t rsa_exponent, + uint32_t ratelimit, const uint8_t* key_blob, + size_t key_blob_size, uint8_t* key_buffer, + uint32_t key_buffer_size, uint32_t* key_out_size); + +KeymasterSignResult 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); #endif diff --git a/cryptfs.cpp b/cryptfs.cpp index 1dc3d75..af7fda3 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -96,6 +96,8 @@ extern "C" { #define RETRY_MOUNT_ATTEMPTS 10 #define RETRY_MOUNT_DELAY_SECONDS 1 +static int put_crypt_ftr_and_key(struct crypt_mnt_ftr* crypt_ftr); + static unsigned char saved_master_key[KEY_LEN_BYTES]; static char *saved_mount_point; static int master_key_saved = 0; @@ -120,7 +122,7 @@ static int keymaster_create_key(struct crypt_mnt_ftr *ftr) &ftr->keymaster_blob_size); if (rc) { if (ftr->keymaster_blob_size > KEYMASTER_BLOB_SIZE) { - SLOGE("Keymaster key blob to large)"); + SLOGE("Keymaster key blob too large"); ftr->keymaster_blob_size = 0; } SLOGE("Failed to generate keypair"); @@ -169,8 +171,31 @@ static int keymaster_sign_object(struct crypt_mnt_ftr *ftr, SLOGE("Unknown KDF type %d", ftr->kdf_type); return -1; } - 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); + for (;;) { + auto result = 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); + switch (result) { + case KeymasterSignResult::ok: + return 0; + case KeymasterSignResult::upgrade: + break; + default: + return -1; + } + SLOGD("Upgrading key"); + if (keymaster_upgrade_key_for_cryptfs_scrypt( + RSA_KEY_SIZE, RSA_EXPONENT, KEYMASTER_CRYPTFS_RATE_LIMIT, ftr->keymaster_blob, + ftr->keymaster_blob_size, ftr->keymaster_blob, KEYMASTER_BLOB_SIZE, + &ftr->keymaster_blob_size) != 0) { + SLOGE("Failed to upgrade key"); + return -1; + } + if (put_crypt_ftr_and_key(ftr) != 0) { + SLOGE("Failed to write upgraded key to disk"); + } + SLOGD("Key upgraded successfully"); + } } /* Store password when userdata is successfully decrypted and mounted. diff --git a/tests/CryptfsScryptHidlizationEquivalence_test.cpp b/tests/CryptfsScryptHidlizationEquivalence_test.cpp index 3a6c029..2905af2 100644 --- a/tests/CryptfsScryptHidlizationEquivalence_test.cpp +++ b/tests/CryptfsScryptHidlizationEquivalence_test.cpp @@ -433,8 +433,11 @@ static int keymaster_sign_object_new(struct crypt_mnt_ftr *ftr, SLOGE("Unknown KDF type %d", ftr->kdf_type); return -1; } - 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); + if (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) != KeymasterSignResult::ok) + return -1; + return 0; } namespace android {