• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
randomKey(KeyBuffer * key)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
generateKeyRef(const char * key,int length)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 
fillKey(const KeyBuffer & key,ext4_encryption_key * ext4_key)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 
keyname(const std::string & prefix,const std::string & raw_ref)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
e4cryptKeyring(key_serial_t * device_keyring)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
installKey(const KeyBuffer & key,std::string * raw_ref)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 
evictKey(const std::string & raw_ref)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 
retrieveAndInstallKey(bool create_if_absent,const KeyAuthentication & key_authentication,const std::string & key_path,const std::string & tmp_path,std::string * key_ref)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 
retrieveKey(bool create_if_absent,const std::string & key_path,const std::string & tmp_path,KeyBuffer * key)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