diff options
author | AnilKumar Chimata <anilc@codeaurora.org> | 2017-06-22 23:55:07 +0530 |
---|---|---|
committer | Michael Bestas <mkbestas@lineageos.org> | 2017-12-20 23:31:29 +0200 |
commit | 7c9d336fa81aaf2e481ee958402c71526059b861 (patch) | |
tree | 4d1fa2659292d08c032385952f2d56e8a2c18269 | |
parent | 5bbd79ba912159df838b27f8608f9b44ab040f17 (diff) | |
download | android_vendor_qcom_opensource_cryptfs_hw-7c9d336fa81aaf2e481ee958402c71526059b861.tar.gz android_vendor_qcom_opensource_cryptfs_hw-7c9d336fa81aaf2e481ee958402c71526059b861.tar.bz2 android_vendor_qcom_opensource_cryptfs_hw-7c9d336fa81aaf2e481ee958402c71526059b861.zip |
cryptfs_hw: Add new APIs for key management
Add new APIs for create, wipe and update keys, which is
required for HW based Full Disk Encryption.
Change-Id: I483ce1a734db7b7cbfb2a06fe74baf559cfb51fb
-rw-r--r-- | Android.mk | 3 | ||||
-rwxr-xr-x | cryptfs_hw.c | 289 |
2 files changed, 201 insertions, 91 deletions
@@ -13,7 +13,8 @@ commonSharedLibraries := \ liblog commonIncludes := \ - hardware/libhardware/include/hardware/ + hardware/libhardware/include/hardware/ \ + $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include \ LOCAL_C_INCLUDES := $(commonIncludes) LOCAL_SRC_FILES := $(sourceFiles) diff --git a/cryptfs_hw.c b/cryptfs_hw.c index 0006966..15c939d 100755 --- a/cryptfs_hw.c +++ b/cryptfs_hw.c @@ -26,7 +26,6 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <cryptfs_hw.h> #include <stdlib.h> #include <string.h> #include <sys/limits.h> @@ -35,64 +34,220 @@ #include <fcntl.h> #include <dirent.h> #include <dlfcn.h> +#include <linux/qseecom.h> #include "cutils/log.h" #include "cutils/properties.h" #include "cutils/android_reboot.h" #include "keymaster_common.h" #include "hardware.h" +#include "cryptfs_hw.h" -#if defined(__LP64__) -#define QSEECOM_LIBRARY_PATH "/vendor/lib64/libQSEEComAPI.so" -#else -#define QSEECOM_LIBRARY_PATH "/vendor/lib/libQSEEComAPI.so" -#endif - - -// When device comes up or when user tries to change the password, user can -// try wrong password upto a certain number of times. If user enters wrong -// password further, HW would wipe all disk encryption related crypto data -// and would return an error ERR_MAX_PASSWORD_ATTEMPTS to VOLD. VOLD would -// wipe userdata partition once this error is received. -#define ERR_MAX_PASSWORD_ATTEMPTS -10 -#define QSEECOM_DISK_ENCRYPTION 1 -#define QSEECOM_UFS_ICE_DISK_ENCRYPTION 3 -#define QSEECOM_SDCC_ICE_DISK_ENCRYPTION 4 -#define MAX_PASSWORD_LEN 32 -#define QCOM_ICE_STORAGE_UFS 1 -#define QCOM_ICE_STORAGE_SDCC 2 - -/* Operations that be performed on HW based device encryption key */ -#define SET_HW_DISK_ENC_KEY 1 -#define UPDATE_HW_DISK_ENC_KEY 2 -#define MAX_DEVICE_ID_LENGTH 4 /* 4 = 3 (MAX_SOC_ID_LENGTH) + 1 */ +/* + * When device comes up or when user tries to change the password, user can + * try wrong password upto a certain number of times. If user enters wrong + * password further, HW would wipe all disk encryption related crypto data + * and would return an error ERR_MAX_PASSWORD_ATTEMPTS to VOLD. VOLD would + * wipe userdata partition once this error is received. + */ +#define ERR_MAX_PASSWORD_ATTEMPTS -10 +#define MAX_PASSWORD_LEN 32 +#define QCOM_ICE_STORAGE_UFS 1 +#define QCOM_ICE_STORAGE_SDCC 2 +#define SET_HW_DISK_ENC_KEY 1 +#define UPDATE_HW_DISK_ENC_KEY 2 +#define MAX_DEVICE_ID_LENGTH 4 /* 4 = 3 (MAX_SOC_ID_LENGTH) + 1 */ static unsigned int cpu_id[] = { 239, /* MSM8939 SOC ID */ }; -#define QSEECOM_UP_CHECK_COUNT 10 +#define CRYPTFS_HW_KMS_CLEAR_KEY 0 +#define CRYPTFS_HW_KMS_WIPE_KEY 1 +#define CRYPTFS_HW_UP_CHECK_COUNT 10 +#define CRYPTFS_HW_CLEAR_KEY_FAILED -11 +#define CRYPTFS_HW_KMS_MAX_FAILURE -10 +#define CRYPTFS_HW_UPDATE_KEY_FAILED -9 +#define CRYPTFS_HW_WIPE_KEY_FAILED -8 +#define CRYPTFS_HW_CREATE_KEY_FAILED -7 + +enum cryptfs_hw_key_management_usage_type { + CRYPTFS_HW_KM_USAGE_DISK_ENCRYPTION = 0x01, + CRYPTFS_HW_KM_USAGE_FILE_ENCRYPTION = 0x02, + CRYPTFS_HW_KM_USAGE_UFS_ICE_DISK_ENCRYPTION = 0x03, + CRYPTFS_HW_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION = 0x04, + CRYPTFS_HW_KM_USAGE_MAX +}; -static int loaded_library = 0; -static int (*qseecom_create_key)(int, void*); -static int (*qseecom_update_key)(int, void*, void*); -static int (*qseecom_wipe_key)(int); +static inline void* secure_memset(void* v, int c , size_t n) +{ + volatile unsigned char* p = (volatile unsigned char* )v; + while (n--) *p++ = c; + return v; +} + +static size_t memscpy(void *dst, size_t dst_size, const void *src, size_t src_size) +{ + size_t min_size = (dst_size < src_size) ? dst_size : src_size; + memcpy(dst, src, min_size); + return min_size; +} + +static int cryptfs_hw_create_key(enum cryptfs_hw_key_management_usage_type usage, + unsigned char *hash32) +{ + struct qseecom_create_key_req req; + int qseecom_fd; + int32_t ret; + + if (usage < CRYPTFS_HW_KM_USAGE_DISK_ENCRYPTION || + usage >= CRYPTFS_HW_KM_USAGE_MAX) { + SLOGE("Error:: unsupported usage %d\n", usage); + return CRYPTFS_HW_CREATE_KEY_FAILED; + } + + qseecom_fd = open("/dev/qseecom", O_RDWR); + if (qseecom_fd < 0) { + SLOGE("Error::Failed to open /dev/qseecom device\n"); + return CRYPTFS_HW_CREATE_KEY_FAILED;; + } + + if (!hash32) { + secure_memset((void *)req.hash32, 0, QSEECOM_HASH_SIZE); + } else { + memscpy((void *)req.hash32, QSEECOM_HASH_SIZE, (void *)hash32, + QSEECOM_HASH_SIZE); + } + + req.usage = (enum qseecom_key_management_usage_type)usage; + ret = ioctl(qseecom_fd, QSEECOM_IOCTL_CREATE_KEY_REQ, &req); + if (ret) { + SLOGE("Error::ioctl call to create encryption key for usage %d failed with ret = %d, errno = %d\n", + usage, ret, errno); + if (errno == ERANGE) + ret = CRYPTFS_HW_KMS_MAX_FAILURE; + else + ret = CRYPTFS_HW_CREATE_KEY_FAILED; + } else { + SLOGE("SUCESS::ioctl call to create encryption key for usage %d success with ret = %d\n", + usage, ret); + } + close(qseecom_fd); + return ret; +} + +static int __cryptfs_hw_wipe_clear_key(enum cryptfs_hw_key_management_usage_type usage, int wipe_key_flag) +{ + struct qseecom_wipe_key_req req; + int32_t ret; + int qseecom_fd; + + if (usage < CRYPTFS_HW_KM_USAGE_DISK_ENCRYPTION || + usage >= CRYPTFS_HW_KM_USAGE_MAX) { + SLOGE("Error:: unsupported usage %d\n", usage); + return -1; + } + qseecom_fd = open("/dev/qseecom", O_RDWR); + if (qseecom_fd < 0) { + SLOGE("Error::Failed to open /dev/qseecom device\n"); + return -1; + } + + req.usage = (enum qseecom_key_management_usage_type)usage; + req.wipe_key_flag = wipe_key_flag; + ret = ioctl(qseecom_fd, QSEECOM_IOCTL_WIPE_KEY_REQ, &req); + close(qseecom_fd); + return ret; +} + +static int cryptfs_hw_wipe_key(enum cryptfs_hw_key_management_usage_type usage) +{ + int32_t ret; + + ret = __cryptfs_hw_wipe_clear_key(usage, CRYPTFS_HW_KMS_WIPE_KEY); + if (ret) { + SLOGE("Error::ioctl call to wipe the encryption key for usage %d failed with ret = %d, errno = %d\n", + usage, ret, errno); + ret = CRYPTFS_HW_WIPE_KEY_FAILED; + } else { + SLOGE("SUCCESS::ioctl call to wipe the encryption key for usage %d success with ret = %d\n", + usage, ret); + } + return ret; +} -inline void* secure_memset(void* v, int c , size_t n) { - volatile unsigned char* p = (volatile unsigned char* )v; - while (n--) *p++ = c; - return v; +static int cryptfs_hw_clear_key(enum cryptfs_hw_key_management_usage_type usage) +{ + int32_t ret; + + ret = __cryptfs_hw_wipe_clear_key(usage, CRYPTFS_HW_KMS_CLEAR_KEY); + if (ret) { + SLOGE("Error::ioctl call to wipe the encryption key for usage %d failed with ret = %d, errno = %d\n", + usage, ret, errno); + ret = CRYPTFS_HW_CLEAR_KEY_FAILED; + } else { + SLOGE("SUCCESS::ioctl call to wipe the encryption key for usage %d success with ret = %d\n", + usage, ret); + } + return ret; } +static int cryptfs_hw_update_key(enum cryptfs_hw_key_management_usage_type usage, + unsigned char *current_hash32, unsigned char *new_hash32) +{ + struct qseecom_update_key_userinfo_req req; + int qseecom_fd; + int32_t ret; + + if (usage < CRYPTFS_HW_KM_USAGE_DISK_ENCRYPTION || + usage >= CRYPTFS_HW_KM_USAGE_MAX) { + SLOGE("Error:: unsupported usage %d\n", usage); + return CRYPTFS_HW_UPDATE_KEY_FAILED; + } + qseecom_fd = open("/dev/qseecom", O_RDWR); + if (qseecom_fd < 0) { + SLOGE("Error::Failed to open /dev/qseecom device\n"); + return CRYPTFS_HW_UPDATE_KEY_FAILED; + } + + req.usage = (enum qseecom_key_management_usage_type)usage; + if (!current_hash32) { + secure_memset((void *)req.current_hash32, 0, QSEECOM_HASH_SIZE); + } else { + memscpy((void *)req.current_hash32, QSEECOM_HASH_SIZE, (void *)current_hash32, + QSEECOM_HASH_SIZE); + } + if (!new_hash32) { + secure_memset((void *)req.new_hash32, 0, QSEECOM_HASH_SIZE); + } else { + memscpy((void *)req.new_hash32, QSEECOM_HASH_SIZE, (void *)new_hash32, + QSEECOM_HASH_SIZE); + } + + ret = ioctl(qseecom_fd, QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ, &req); + if (ret) { + SLOGE("Error::ioctl call to update the encryption key for usage %d failed with ret = %d, errno = %d\n", + usage, ret, errno); + if (errno == ERANGE) + ret = CRYPTFS_HW_KMS_MAX_FAILURE; + else + ret = CRYPTFS_HW_UPDATE_KEY_FAILED; + } else { + SLOGE("SUCCESS::ioctl call to update the encryption key for usage %d success with ret = %d\n", + usage, ret); + } + close(qseecom_fd); + return ret; +} static int map_usage(int usage) { int storage_type = is_ice_enabled(); - if (usage == QSEECOM_DISK_ENCRYPTION) { + if (usage == CRYPTFS_HW_KM_USAGE_DISK_ENCRYPTION) { if (storage_type == QCOM_ICE_STORAGE_UFS) { - return QSEECOM_UFS_ICE_DISK_ENCRYPTION; + return CRYPTFS_HW_KM_USAGE_UFS_ICE_DISK_ENCRYPTION; } else if (storage_type == QCOM_ICE_STORAGE_SDCC) { - return QSEECOM_SDCC_ICE_DISK_ENCRYPTION ; + return CRYPTFS_HW_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION; } } return usage; @@ -105,7 +260,7 @@ static unsigned char* get_tmp_passwd(const char* passwd) if(passwd) { tmp_passwd = (unsigned char*)malloc(MAX_PASSWORD_LEN); if(tmp_passwd) { - memset(tmp_passwd, 0, MAX_PASSWORD_LEN); + secure_memset(tmp_passwd, 0, MAX_PASSWORD_LEN); passwd_len = strnlen(passwd, MAX_PASSWORD_LEN); memcpy(tmp_passwd, passwd, passwd_len); } else { @@ -122,7 +277,7 @@ static int is_qseecom_up() int i = 0; char value[PROPERTY_VALUE_MAX] = {0}; - for (; i<QSEECOM_UP_CHECK_COUNT; i++) { + for (; i<CRYPTFS_HW_UP_CHECK_COUNT; i++) { property_get("sys.keymaster.loaded", value, ""); if (!strncmp(value, "true", PROPERTY_VALUE_MAX)) return 1; @@ -131,49 +286,6 @@ static int is_qseecom_up() return 0; } - -static int load_qseecom_library() -{ - const char *error = NULL; - if (loaded_library) - return loaded_library; - - if (!is_qseecom_up()) { - SLOGE("Timed out waiting for QSEECom listeners..aborting FDE key operation"); - return 0; - } - - void * handle = dlopen(QSEECOM_LIBRARY_PATH, RTLD_NOW); - if(handle) { - dlerror(); /* Clear any existing error */ - *(void **) (&qseecom_create_key) = dlsym(handle,"QSEECom_create_key"); - - if((error = dlerror()) == NULL) { - SLOGD("Success loading QSEECom_create_key \n"); - *(void **) (&qseecom_update_key) = dlsym(handle,"QSEECom_update_key_user_info"); - if ((error = dlerror()) == NULL) { - SLOGD("Success loading QSEECom_update_key_user_info\n"); - *(void **) (&qseecom_wipe_key) = dlsym(handle,"QSEECom_wipe_key"); - if ((error = dlerror()) == NULL) { - loaded_library = 1; - SLOGD("Success loading QSEECom_wipe_key \n"); - } - else - SLOGE("Error %s loading symbols for QSEECom APIs \n", error); - } - else - SLOGE("Error %s loading symbols for QSEECom APIs \n", error); - } - } else { - SLOGE("Could not load libQSEEComAPI.so \n"); - } - - if(error) - dlclose(handle); - - return loaded_library; -} - /* * For NON-ICE targets, it would return 0 on success. On ICE based targets, * it would return key index in the ICE Key LUT @@ -181,17 +293,17 @@ static int load_qseecom_library() static int set_key(const char* currentpasswd, const char* passwd, const char* enc_mode, int operation) { int err = -1; - if (is_hw_disk_encryption(enc_mode) && load_qseecom_library()) { + if (is_hw_disk_encryption(enc_mode)) { unsigned char* tmp_passwd = get_tmp_passwd(passwd); unsigned char* tmp_currentpasswd = get_tmp_passwd(currentpasswd); - if(tmp_passwd) { + if (tmp_passwd) { if (operation == UPDATE_HW_DISK_ENC_KEY) { if (tmp_currentpasswd) { - err = qseecom_update_key(map_usage(QSEECOM_DISK_ENCRYPTION), tmp_currentpasswd, tmp_passwd); + err = cryptfs_hw_update_key(map_usage(CRYPTFS_HW_KM_USAGE_DISK_ENCRYPTION), tmp_currentpasswd, tmp_passwd); secure_memset(tmp_currentpasswd, 0, MAX_PASSWORD_LEN); } } else if (operation == SET_HW_DISK_ENC_KEY) { - err = qseecom_create_key(map_usage(QSEECOM_DISK_ENCRYPTION), tmp_passwd); + err = cryptfs_hw_create_key(map_usage(CRYPTFS_HW_KM_USAGE_DISK_ENCRYPTION), tmp_passwd); } if(err < 0) { if(ERR_MAX_PASSWORD_ATTEMPTS == err) @@ -301,10 +413,7 @@ int is_ice_enabled(void) int clear_hw_device_encryption_key() { - if (load_qseecom_library()) - return qseecom_wipe_key(map_usage(QSEECOM_DISK_ENCRYPTION)); - - return 0; + return cryptfs_hw_wipe_key(map_usage(CRYPTFS_HW_KM_USAGE_DISK_ENCRYPTION)); } static int get_keymaster_version() |