Home | History | Annotate | Download | only in cryptfs_hw
      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