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