Home | History | Annotate | Download | only in vold
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "KeyUtil.h"
     18 
     19 #include <iomanip>
     20 #include <sstream>
     21 #include <string>
     22 
     23 #include <openssl/sha.h>
     24 
     25 #include <android-base/file.h>
     26 #include <android-base/logging.h>
     27 #include <keyutils.h>
     28 
     29 #include "KeyStorage.h"
     30 #include "Utils.h"
     31 
     32 namespace android {
     33 namespace vold {
     34 
     35 // ext4enc:TODO get this const from somewhere good
     36 const int EXT4_KEY_DESCRIPTOR_SIZE = 8;
     37 
     38 // ext4enc:TODO Include structure from somewhere sensible
     39 // MUST be in sync with ext4_crypto.c in kernel
     40 constexpr int EXT4_ENCRYPTION_MODE_AES_256_XTS = 1;
     41 constexpr int EXT4_AES_256_XTS_KEY_SIZE = 64;
     42 constexpr int EXT4_MAX_KEY_SIZE = 64;
     43 struct ext4_encryption_key {
     44     uint32_t mode;
     45     char raw[EXT4_MAX_KEY_SIZE];
     46     uint32_t size;
     47 };
     48 
     49 bool randomKey(KeyBuffer* key) {
     50     *key = KeyBuffer(EXT4_AES_256_XTS_KEY_SIZE);
     51     if (ReadRandomBytes(key->size(), key->data()) != 0) {
     52         // TODO status_t plays badly with PLOG, fix it.
     53         LOG(ERROR) << "Random read failed";
     54         return false;
     55     }
     56     return true;
     57 }
     58 
     59 // Get raw keyref - used to make keyname and to pass to ioctl
     60 static std::string generateKeyRef(const char* key, int length) {
     61     SHA512_CTX c;
     62 
     63     SHA512_Init(&c);
     64     SHA512_Update(&c, key, length);
     65     unsigned char key_ref1[SHA512_DIGEST_LENGTH];
     66     SHA512_Final(key_ref1, &c);
     67 
     68     SHA512_Init(&c);
     69     SHA512_Update(&c, key_ref1, SHA512_DIGEST_LENGTH);
     70     unsigned char key_ref2[SHA512_DIGEST_LENGTH];
     71     SHA512_Final(key_ref2, &c);
     72 
     73     static_assert(EXT4_KEY_DESCRIPTOR_SIZE <= SHA512_DIGEST_LENGTH,
     74                   "Hash too short for descriptor");
     75     return std::string((char*)key_ref2, EXT4_KEY_DESCRIPTOR_SIZE);
     76 }
     77 
     78 static bool fillKey(const KeyBuffer& key, ext4_encryption_key* ext4_key) {
     79     if (key.size() != EXT4_AES_256_XTS_KEY_SIZE) {
     80         LOG(ERROR) << "Wrong size key " << key.size();
     81         return false;
     82     }
     83     static_assert(EXT4_AES_256_XTS_KEY_SIZE <= sizeof(ext4_key->raw), "Key too long!");
     84     ext4_key->mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
     85     ext4_key->size = key.size();
     86     memset(ext4_key->raw, 0, sizeof(ext4_key->raw));
     87     memcpy(ext4_key->raw, key.data(), key.size());
     88     return true;
     89 }
     90 
     91 static char const* const NAME_PREFIXES[] = {
     92     "ext4",
     93     "f2fs",
     94     "fscrypt",
     95     nullptr
     96 };
     97 
     98 static std::string keyname(const std::string& prefix, const std::string& raw_ref) {
     99     std::ostringstream o;
    100     o << prefix << ":";
    101     for (unsigned char i : raw_ref) {
    102         o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
    103     }
    104     return o.str();
    105 }
    106 
    107 // Get the keyring we store all keys in
    108 static bool e4cryptKeyring(key_serial_t* device_keyring) {
    109     *device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "e4crypt", 0);
    110     if (*device_keyring == -1) {
    111         PLOG(ERROR) << "Unable to find device keyring";
    112         return false;
    113     }
    114     return true;
    115 }
    116 
    117 // Install password into global keyring
    118 // Return raw key reference for use in policy
    119 bool installKey(const KeyBuffer& key, std::string* raw_ref) {
    120     // Place ext4_encryption_key into automatically zeroing buffer.
    121     KeyBuffer ext4KeyBuffer(sizeof(ext4_encryption_key));
    122     ext4_encryption_key &ext4_key = *reinterpret_cast<ext4_encryption_key*>(ext4KeyBuffer.data());
    123 
    124     if (!fillKey(key, &ext4_key)) return false;
    125     *raw_ref = generateKeyRef(ext4_key.raw, ext4_key.size);
    126     key_serial_t device_keyring;
    127     if (!e4cryptKeyring(&device_keyring)) return false;
    128     for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
    129         auto ref = keyname(*name_prefix, *raw_ref);
    130         key_serial_t key_id =
    131             add_key("logon", ref.c_str(), (void*)&ext4_key, sizeof(ext4_key), device_keyring);
    132         if (key_id == -1) {
    133             PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
    134             return false;
    135         }
    136         LOG(DEBUG) << "Added key " << key_id << " (" << ref << ") to keyring " << device_keyring
    137                    << " in process " << getpid();
    138     }
    139     return true;
    140 }
    141 
    142 bool evictKey(const std::string& raw_ref) {
    143     key_serial_t device_keyring;
    144     if (!e4cryptKeyring(&device_keyring)) return false;
    145     bool success = true;
    146     for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
    147         auto ref = keyname(*name_prefix, raw_ref);
    148         auto key_serial = keyctl_search(device_keyring, "logon", ref.c_str(), 0);
    149 
    150         // Unlink the key from the keyring.  Prefer unlinking to revoking or
    151         // invalidating, since unlinking is actually no less secure currently, and
    152         // it avoids bugs in certain kernel versions where the keyring key is
    153         // referenced from places it shouldn't be.
    154         if (keyctl_unlink(key_serial, device_keyring) != 0) {
    155             PLOG(ERROR) << "Failed to unlink key with serial " << key_serial << " ref " << ref;
    156             success = false;
    157         } else {
    158             LOG(DEBUG) << "Unlinked key with serial " << key_serial << " ref " << ref;
    159         }
    160     }
    161     return success;
    162 }
    163 
    164 bool retrieveAndInstallKey(bool create_if_absent, const KeyAuthentication& key_authentication,
    165                            const std::string& key_path, const std::string& tmp_path,
    166                            std::string* key_ref) {
    167     KeyBuffer key;
    168     if (pathExists(key_path)) {
    169         LOG(DEBUG) << "Key exists, using: " << key_path;
    170         if (!retrieveKey(key_path, key_authentication, &key)) return false;
    171     } else {
    172         if (!create_if_absent) {
    173            LOG(ERROR) << "No key found in " << key_path;
    174            return false;
    175         }
    176         LOG(INFO) << "Creating new key in " << key_path;
    177         if (!randomKey(&key)) return false;
    178         if (!storeKeyAtomically(key_path, tmp_path, key_authentication, key)) return false;
    179     }
    180 
    181     if (!installKey(key, key_ref)) {
    182         LOG(ERROR) << "Failed to install key in " << key_path;
    183         return false;
    184     }
    185     return true;
    186 }
    187 
    188 bool retrieveKey(bool create_if_absent, const std::string& key_path,
    189                  const std::string& tmp_path, KeyBuffer* key) {
    190     if (pathExists(key_path)) {
    191         LOG(DEBUG) << "Key exists, using: " << key_path;
    192         if (!retrieveKey(key_path, kEmptyAuthentication, key)) return false;
    193     } else {
    194         if (!create_if_absent) {
    195            LOG(ERROR) << "No key found in " << key_path;
    196            return false;
    197         }
    198         LOG(INFO) << "Creating new key in " << key_path;
    199         if (!randomKey(key)) return false;
    200         if (!storeKeyAtomically(key_path, tmp_path,
    201                 kEmptyAuthentication, *key)) return false;
    202     }
    203     return true;
    204 }
    205 
    206 }  // namespace vold
    207 }  // namespace android
    208