1 /* Copyright (c) 2014, The Linux Foundation. All rights reserved. 2 * 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions are 5 * met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer in the documentation and/or other materials provided 11 * with the distribution. 12 * * Neither the name of The Linux Foundation nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <cryptfs_hw.h> 30 #include <stdlib.h> 31 #include <sys/limits.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <fcntl.h> 35 #include <dirent.h> 36 #include <dlfcn.h> 37 #define LOG_TAG "Cryptfs_HW" 38 #include "cutils/log.h" 39 #include "cutils/android_reboot.h" 40 41 42 // When device comes up or when user tries to change the password, user can 43 // try wrong password upto a certain number of times. If user enters wrong 44 // password further, HW would wipe all disk encryption related crypto data 45 // and would return an error ERR_MAX_PASSWORD_ATTEMPTS to VOLD. VOLD would 46 // wipe userdata partition once this error is received. 47 #define ERR_MAX_PASSWORD_ATTEMPTS -10 48 #define QSEECOM_DISK_ENCRYPTION 1 49 #define MAX_PASSWORD_LEN 32 50 51 /* Operations that be performed on HW based device encryption key */ 52 #define SET_HW_DISK_ENC_KEY 1 53 #define UPDATE_HW_DISK_ENC_KEY 2 54 55 static int loaded_library = 0; 56 static unsigned char current_passwd[MAX_PASSWORD_LEN]; 57 static int (*qseecom_create_key)(int, void*); 58 static int (*qseecom_update_key)(int, void*, void*); 59 static int (*qseecom_wipe_key)(int); 60 61 static unsigned char* get_tmp_passwd(const char* passwd) 62 { 63 int passwd_len = 0; 64 unsigned char * tmp_passwd = NULL; 65 if(passwd) { 66 tmp_passwd = (unsigned char*)malloc(MAX_PASSWORD_LEN); 67 if(tmp_passwd) { 68 memset(tmp_passwd, 0, MAX_PASSWORD_LEN); 69 passwd_len = (strlen(passwd) > MAX_PASSWORD_LEN) ? MAX_PASSWORD_LEN : strlen(passwd); 70 memcpy(tmp_passwd, passwd, passwd_len); 71 } else { 72 SLOGE("%s: Failed to allocate memory for tmp passwd \n", __func__); 73 } 74 } else { 75 SLOGE("%s: Passed argument is NULL \n", __func__); 76 } 77 return tmp_passwd; 78 } 79 80 static int load_qseecom_library() 81 { 82 const char *error = NULL; 83 if (loaded_library) 84 return loaded_library; 85 86 void * handle = dlopen("libQSEEComAPI.so", RTLD_NOW); 87 if(handle) { 88 dlerror(); /* Clear any existing error */ 89 *(void **) (&qseecom_create_key) = dlsym(handle,"QSEECom_create_key"); 90 91 if((error = dlerror()) == NULL) { 92 *(void **) (&qseecom_update_key) = dlsym(handle,"QSEECom_update_key_user_info"); 93 if((error = dlerror()) == NULL) { 94 *(void **) (&qseecom_wipe_key) = dlsym(handle,"QSEECom_wipe_key"); 95 if ((error = dlerror()) == NULL) 96 loaded_library = 1; 97 else 98 SLOGE("Error %s loading symbols for QSEECom APIs", error); 99 } 100 } 101 } else { 102 SLOGE("Could not load libQSEEComAPI.so"); 103 } 104 105 if(error) 106 dlclose(handle); 107 108 return loaded_library; 109 } 110 111 static unsigned int set_key(const char* passwd, const char* enc_mode, int operation) 112 { 113 int ret = 0; 114 int err = -1; 115 if (is_hw_disk_encryption(enc_mode) && load_qseecom_library()) { 116 unsigned char* tmp_passwd = get_tmp_passwd(passwd); 117 if(tmp_passwd) { 118 119 if (operation == UPDATE_HW_DISK_ENC_KEY) 120 err = qseecom_update_key(QSEECOM_DISK_ENCRYPTION, current_passwd, tmp_passwd); 121 else if (operation == SET_HW_DISK_ENC_KEY) 122 err = qseecom_create_key(QSEECOM_DISK_ENCRYPTION, tmp_passwd); 123 124 if(!err) { 125 memset(current_passwd, 0, MAX_PASSWORD_LEN); 126 memcpy(current_passwd, tmp_passwd, MAX_PASSWORD_LEN); 127 ret = 1; 128 } else { 129 if(ERR_MAX_PASSWORD_ATTEMPTS == err) 130 SLOGE("Maximum password attempts reached. Need factory data reset to recover."); 131 } 132 free(tmp_passwd); 133 } 134 } 135 return ret; 136 } 137 138 unsigned int set_hw_device_encryption_key(const char* passwd, const char* enc_mode) 139 { 140 SLOGI("Set key for HW disk encryption operation"); 141 return set_key(passwd, enc_mode, SET_HW_DISK_ENC_KEY); 142 } 143 144 unsigned int update_hw_device_encryption_key(const char* newpw, const char* enc_mode) 145 { 146 SLOGI("Update key for HW disk encryption operation"); 147 return set_key(newpw, enc_mode, UPDATE_HW_DISK_ENC_KEY); 148 } 149 150 unsigned int is_hw_disk_encryption(const char* encryption_mode) 151 { 152 int ret = 0; 153 if(encryption_mode) { 154 if (!strcmp(encryption_mode, "aes-xts")) { 155 ret = 1; 156 } 157 } 158 return ret; 159 } 160 161 unsigned int clear_hw_device_encryption_key() 162 { 163 int err = -1; 164 int rc = 0; 165 SLOGI("Clear HW disk encryption key"); 166 if (load_qseecom_library()) { 167 err = qseecom_wipe_key(1); 168 } 169 170 if (!err) rc = 1; 171 172 return rc; 173 } 174