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 #include <thread>
23 
24 #include <fcntl.h>
25 #include <linux/fscrypt.h>
26 #include <openssl/sha.h>
27 #include <sys/ioctl.h>
28 
29 #include <android-base/file.h>
30 #include <android-base/logging.h>
31 
32 #include "KeyStorage.h"
33 #include "Utils.h"
34 
35 namespace android {
36 namespace vold {
37 
38 using android::fscrypt::EncryptionOptions;
39 using android::fscrypt::EncryptionPolicy;
40 
41 // This must be acquired before calling fscrypt ioctls that operate on keys.
42 // This prevents race conditions between evicting and reinstalling keys.
43 static std::mutex fscrypt_keyring_mutex;
44 
neverGen()45 const KeyGeneration neverGen() {
46     return KeyGeneration{0, false, false};
47 }
48 
randomKey(size_t size,KeyBuffer * key)49 static bool randomKey(size_t size, KeyBuffer* key) {
50     *key = KeyBuffer(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 
generateStorageKey(const KeyGeneration & gen,KeyBuffer * key)59 bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key) {
60     if (!gen.allow_gen) {
61         LOG(ERROR) << "Generating storage key not allowed";
62         return false;
63     }
64     if (gen.use_hw_wrapped_key) {
65         if (gen.keysize != FSCRYPT_MAX_KEY_SIZE) {
66             LOG(ERROR) << "Cannot generate a wrapped key " << gen.keysize << " bytes long";
67             return false;
68         }
69         LOG(DEBUG) << "Generating wrapped storage key";
70         return generateWrappedStorageKey(key);
71     } else {
72         LOG(DEBUG) << "Generating standard storage key";
73         return randomKey(gen.keysize, key);
74     }
75 }
76 
77 // Get raw keyref - used to make keyname and to pass to ioctl
generateKeyRef(const uint8_t * key,int length)78 static std::string generateKeyRef(const uint8_t* key, int length) {
79     SHA512_CTX c;
80 
81     SHA512_Init(&c);
82     SHA512_Update(&c, key, length);
83     unsigned char key_ref1[SHA512_DIGEST_LENGTH];
84     SHA512_Final(key_ref1, &c);
85 
86     SHA512_Init(&c);
87     SHA512_Update(&c, key_ref1, SHA512_DIGEST_LENGTH);
88     unsigned char key_ref2[SHA512_DIGEST_LENGTH];
89     SHA512_Final(key_ref2, &c);
90 
91     static_assert(FSCRYPT_KEY_DESCRIPTOR_SIZE <= SHA512_DIGEST_LENGTH,
92                   "Hash too short for descriptor");
93     return std::string((char*)key_ref2, FSCRYPT_KEY_DESCRIPTOR_SIZE);
94 }
95 
keyrefstring(const std::string & raw_ref)96 static std::string keyrefstring(const std::string& raw_ref) {
97     std::ostringstream o;
98     for (unsigned char i : raw_ref) {
99         o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
100     }
101     return o.str();
102 }
103 
104 // Build a struct fscrypt_key_specifier for use in the key management ioctls.
buildKeySpecifier(fscrypt_key_specifier * spec,const EncryptionPolicy & policy)105 static bool buildKeySpecifier(fscrypt_key_specifier* spec, const EncryptionPolicy& policy) {
106     switch (policy.options.version) {
107         case 1:
108             if (policy.key_raw_ref.size() != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
109                 LOG(ERROR) << "Invalid key specifier size for v1 encryption policy: "
110                            << policy.key_raw_ref.size();
111                 return false;
112             }
113             spec->type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
114             memcpy(spec->u.descriptor, policy.key_raw_ref.c_str(), FSCRYPT_KEY_DESCRIPTOR_SIZE);
115             return true;
116         case 2:
117             if (policy.key_raw_ref.size() != FSCRYPT_KEY_IDENTIFIER_SIZE) {
118                 LOG(ERROR) << "Invalid key specifier size for v2 encryption policy: "
119                            << policy.key_raw_ref.size();
120                 return false;
121             }
122             spec->type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
123             memcpy(spec->u.identifier, policy.key_raw_ref.c_str(), FSCRYPT_KEY_IDENTIFIER_SIZE);
124             return true;
125         default:
126             LOG(ERROR) << "Invalid encryption policy version: " << policy.options.version;
127             return false;
128     }
129 }
130 
installKey(const std::string & mountpoint,const EncryptionOptions & options,const KeyBuffer & key,EncryptionPolicy * policy)131 bool installKey(const std::string& mountpoint, const EncryptionOptions& options,
132                 const KeyBuffer& key, EncryptionPolicy* policy) {
133     const std::lock_guard<std::mutex> lock(fscrypt_keyring_mutex);
134     policy->options = options;
135     // Put the fscrypt_add_key_arg in an automatically-zeroing buffer, since we
136     // have to copy the raw key into it.
137     KeyBuffer arg_buf(sizeof(struct fscrypt_add_key_arg) + key.size(), 0);
138     struct fscrypt_add_key_arg* arg = (struct fscrypt_add_key_arg*)arg_buf.data();
139 
140     // Initialize the "key specifier", which is like a name for the key.
141     switch (options.version) {
142         case 1:
143             // A key for a v1 policy is specified by an arbitrary 8-byte
144             // "descriptor", which must be provided by userspace.  We use the
145             // first 8 bytes from the double SHA-512 of the key itself.
146             policy->key_raw_ref = generateKeyRef((const uint8_t*)key.data(), key.size());
147             if (!buildKeySpecifier(&arg->key_spec, *policy)) {
148                 return false;
149             }
150             break;
151         case 2:
152             // A key for a v2 policy is specified by an 16-byte "identifier",
153             // which is a cryptographic hash of the key itself which the kernel
154             // computes and returns.  Any user-provided value is ignored; we
155             // just need to set the specifier type to indicate that we're adding
156             // this type of key.
157             arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
158             break;
159         default:
160             LOG(ERROR) << "Invalid encryption policy version: " << options.version;
161             return false;
162     }
163 
164     if (options.use_hw_wrapped_key) arg->__flags |= __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED;
165     // Provide the raw key.
166     arg->raw_size = key.size();
167     memcpy(arg->raw, key.data(), key.size());
168 
169     android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
170     if (fd == -1) {
171         PLOG(ERROR) << "Failed to open " << mountpoint << " to install key";
172         return false;
173     }
174 
175     if (ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, arg) != 0) {
176         PLOG(ERROR) << "Failed to install fscrypt key to " << mountpoint;
177         return false;
178     }
179 
180     if (arg->key_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
181         // Retrieve the key identifier that the kernel computed.
182         policy->key_raw_ref =
183                 std::string((char*)arg->key_spec.u.identifier, FSCRYPT_KEY_IDENTIFIER_SIZE);
184     }
185     LOG(DEBUG) << "Installed fscrypt key with ref " << keyrefstring(policy->key_raw_ref) << " to "
186                << mountpoint;
187     return true;
188 }
189 
waitForBusyFiles(const struct fscrypt_key_specifier key_spec,const std::string ref,const std::string mountpoint)190 static void waitForBusyFiles(const struct fscrypt_key_specifier key_spec, const std::string ref,
191                              const std::string mountpoint) {
192     android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
193     if (fd == -1) {
194         PLOG(ERROR) << "Failed to open " << mountpoint << " to evict key";
195         return;
196     }
197 
198     std::chrono::milliseconds wait_time(3200);
199     std::chrono::milliseconds total_wait_time(0);
200     while (wait_time <= std::chrono::milliseconds(51200)) {
201         total_wait_time += wait_time;
202         std::this_thread::sleep_for(wait_time);
203 
204         const std::lock_guard<std::mutex> lock(fscrypt_keyring_mutex);
205 
206         struct fscrypt_get_key_status_arg get_arg;
207         memset(&get_arg, 0, sizeof(get_arg));
208         get_arg.key_spec = key_spec;
209 
210         if (ioctl(fd, FS_IOC_GET_ENCRYPTION_KEY_STATUS, &get_arg) != 0) {
211             PLOG(ERROR) << "Failed to get status for fscrypt key with ref " << ref << " from "
212                         << mountpoint;
213             return;
214         }
215         if (get_arg.status != FSCRYPT_KEY_STATUS_INCOMPLETELY_REMOVED) {
216             LOG(DEBUG) << "Key status changed, cancelling busy file cleanup for key with ref "
217                        << ref << ".";
218             return;
219         }
220 
221         struct fscrypt_remove_key_arg remove_arg;
222         memset(&remove_arg, 0, sizeof(remove_arg));
223         remove_arg.key_spec = key_spec;
224 
225         if (ioctl(fd, FS_IOC_REMOVE_ENCRYPTION_KEY, &remove_arg) != 0) {
226             PLOG(ERROR) << "Failed to clean up busy files for fscrypt key with ref " << ref
227                         << " from " << mountpoint;
228             return;
229         }
230         if (remove_arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS) {
231             // Should never happen because keys are only added/removed as root.
232             LOG(ERROR) << "Unexpected case: key with ref " << ref
233                        << " is still added by other users!";
234         } else if (!(remove_arg.removal_status_flags &
235                      FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY)) {
236             LOG(INFO) << "Successfully cleaned up busy files for key with ref " << ref
237                       << ".  After waiting " << total_wait_time.count() << "ms.";
238             return;
239         }
240         LOG(WARNING) << "Files still open after waiting " << total_wait_time.count()
241                      << "ms.  Key with ref " << ref << " still has unlocked files!";
242         wait_time *= 2;
243     }
244     LOG(ERROR) << "Waiting for files to close never completed.  Files using key with ref " << ref
245                << " were not locked!";
246 }
247 
evictKey(const std::string & mountpoint,const EncryptionPolicy & policy)248 bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) {
249     const std::lock_guard<std::mutex> lock(fscrypt_keyring_mutex);
250 
251     android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
252     if (fd == -1) {
253         PLOG(ERROR) << "Failed to open " << mountpoint << " to evict key";
254         return false;
255     }
256 
257     struct fscrypt_remove_key_arg arg;
258     memset(&arg, 0, sizeof(arg));
259 
260     if (!buildKeySpecifier(&arg.key_spec, policy)) {
261         return false;
262     }
263 
264     std::string ref = keyrefstring(policy.key_raw_ref);
265 
266     if (ioctl(fd, FS_IOC_REMOVE_ENCRYPTION_KEY, &arg) != 0) {
267         PLOG(ERROR) << "Failed to evict fscrypt key with ref " << ref << " from " << mountpoint;
268         return false;
269     }
270 
271     LOG(DEBUG) << "Evicted fscrypt key with ref " << ref << " from " << mountpoint;
272     if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS) {
273         // Should never happen because keys are only added/removed as root.
274         LOG(ERROR) << "Unexpected case: key with ref " << ref << " is still added by other users!";
275     } else if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY) {
276         LOG(WARNING)
277                 << "Files still open after removing key with ref " << ref
278                 << ".  These files were not locked!  Punting busy file clean up to worker thread.";
279         // Processes are killed asynchronously in ActivityManagerService due to performance issues
280         // with synchronous kills.  If there were busy files they will probably be killed soon. Wait
281         // for them asynchronously.
282         std::thread busyFilesThread(waitForBusyFiles, arg.key_spec, ref, mountpoint);
283         busyFilesThread.detach();
284     }
285     return true;
286 }
287 
retrieveOrGenerateKey(const std::string & key_path,const std::string & tmp_path,const KeyAuthentication & key_authentication,const KeyGeneration & gen,KeyBuffer * key)288 bool retrieveOrGenerateKey(const std::string& key_path, const std::string& tmp_path,
289                            const KeyAuthentication& key_authentication, const KeyGeneration& gen,
290                            KeyBuffer* key) {
291     if (pathExists(key_path)) {
292         LOG(DEBUG) << "Key exists, using: " << key_path;
293         if (!retrieveKey(key_path, key_authentication, key)) return false;
294     } else {
295         if (!gen.allow_gen) {
296             LOG(ERROR) << "No key found in " << key_path;
297             return false;
298         }
299         LOG(INFO) << "Creating new key in " << key_path;
300         if (!generateStorageKey(gen, key)) return false;
301         if (!storeKeyAtomically(key_path, tmp_path, key_authentication, *key)) return false;
302     }
303     return true;
304 }
305 
306 }  // namespace vold
307 }  // namespace android
308