blob: 6d96541841de353c573e11822ce53597f3b71aa3 [file] [log] [blame]
Paul Crowleyf71ace32016-06-02 11:01:19 -07001/*
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>
Nathan Huckleberrya21962b2023-02-22 02:28:28 +000022#include <thread>
Paul Crowleyf71ace32016-06-02 11:01:19 -070023
Eric Biggersf3dc4202019-09-30 13:05:58 -070024#include <fcntl.h>
Eric Biggers3e9c9962019-12-16 15:55:12 -080025#include <linux/fscrypt.h>
Paul Crowleyf71ace32016-06-02 11:01:19 -070026#include <openssl/sha.h>
Eric Biggersf3dc4202019-09-30 13:05:58 -070027#include <sys/ioctl.h>
Paul Crowleyf71ace32016-06-02 11:01:19 -070028
29#include <android-base/file.h>
30#include <android-base/logging.h>
31
32#include "KeyStorage.h"
33#include "Utils.h"
34
35namespace android {
36namespace vold {
37
Paul Crowleyf4430382020-04-05 19:34:31 -070038using android::fscrypt::EncryptionOptions;
39using android::fscrypt::EncryptionPolicy;
40
Nathan Huckleberrya21962b2023-02-22 02:28:28 +000041// This must be acquired before calling fscrypt ioctls that operate on keys.
42// This prevents race conditions between evicting and reinstalling keys.
43static std::mutex fscrypt_keyring_mutex;
44
Paul Crowley4eac2642020-02-12 11:04:05 -080045const KeyGeneration neverGen() {
46 return KeyGeneration{0, false, false};
47}
48
49static bool randomKey(size_t size, KeyBuffer* key) {
50 *key = KeyBuffer(size);
Pavel Grafove2e2d302017-08-01 17:15:53 +010051 if (ReadRandomBytes(key->size(), key->data()) != 0) {
Paul Crowleyf71ace32016-06-02 11:01:19 -070052 // TODO status_t plays badly with PLOG, fix it.
53 LOG(ERROR) << "Random read failed";
54 return false;
55 }
56 return true;
57}
58
Paul Crowley4eac2642020-02-12 11:04:05 -080059bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key) {
David Andersone1791572021-11-05 18:57:49 -070060 if (!gen.allow_gen) {
61 LOG(ERROR) << "Generating storage key not allowed";
62 return false;
63 }
Paul Crowley4eac2642020-02-12 11:04:05 -080064 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 }
Eric Biggersb2024e02021-03-15 12:44:36 -070069 LOG(DEBUG) << "Generating wrapped storage key";
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -080070 return generateWrappedStorageKey(key);
Paul Crowley4eac2642020-02-12 11:04:05 -080071 } else {
Eric Biggersb2024e02021-03-15 12:44:36 -070072 LOG(DEBUG) << "Generating standard storage key";
Paul Crowley4eac2642020-02-12 11:04:05 -080073 return randomKey(gen.keysize, key);
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -080074 }
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -080075}
76
Paul Crowleyf71ace32016-06-02 11:01:19 -070077// Get raw keyref - used to make keyname and to pass to ioctl
Eric Biggersba997ee2018-10-23 13:07:43 -070078static std::string generateKeyRef(const uint8_t* key, int length) {
Paul Crowleyf71ace32016-06-02 11:01:19 -070079 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
Eric Biggers506342f2019-12-17 13:11:25 -080091 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);
Paul Crowleyf71ace32016-06-02 11:01:19 -070094}
95
Eric Biggersf3dc4202019-09-30 13:05:58 -070096static std::string keyrefstring(const std::string& raw_ref) {
Paul Crowleyf71ace32016-06-02 11:01:19 -070097 std::ostringstream o;
Chen, Luhai5744dfe2017-08-18 14:49:45 +080098 for (unsigned char i : raw_ref) {
Paul Crowleyf71ace32016-06-02 11:01:19 -070099 o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
100 }
101 return o.str();
102}
103
Eric Biggers83a73d72019-09-30 13:06:47 -0700104// Build a struct fscrypt_key_specifier for use in the key management ioctls.
Paul Crowley77df7f22020-01-23 15:29:30 -0800105static bool buildKeySpecifier(fscrypt_key_specifier* spec, const EncryptionPolicy& policy) {
106 switch (policy.options.version) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700107 case 1:
Paul Crowley77df7f22020-01-23 15:29:30 -0800108 if (policy.key_raw_ref.size() != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700109 LOG(ERROR) << "Invalid key specifier size for v1 encryption policy: "
Paul Crowley77df7f22020-01-23 15:29:30 -0800110 << policy.key_raw_ref.size();
Eric Biggers83a73d72019-09-30 13:06:47 -0700111 return false;
112 }
113 spec->type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
Paul Crowley77df7f22020-01-23 15:29:30 -0800114 memcpy(spec->u.descriptor, policy.key_raw_ref.c_str(), FSCRYPT_KEY_DESCRIPTOR_SIZE);
Eric Biggers83a73d72019-09-30 13:06:47 -0700115 return true;
116 case 2:
Paul Crowley77df7f22020-01-23 15:29:30 -0800117 if (policy.key_raw_ref.size() != FSCRYPT_KEY_IDENTIFIER_SIZE) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700118 LOG(ERROR) << "Invalid key specifier size for v2 encryption policy: "
Paul Crowley77df7f22020-01-23 15:29:30 -0800119 << policy.key_raw_ref.size();
Eric Biggers83a73d72019-09-30 13:06:47 -0700120 return false;
121 }
122 spec->type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
Paul Crowley77df7f22020-01-23 15:29:30 -0800123 memcpy(spec->u.identifier, policy.key_raw_ref.c_str(), FSCRYPT_KEY_IDENTIFIER_SIZE);
Eric Biggers83a73d72019-09-30 13:06:47 -0700124 return true;
125 default:
Paul Crowley77df7f22020-01-23 15:29:30 -0800126 LOG(ERROR) << "Invalid encryption policy version: " << policy.options.version;
Eric Biggers83a73d72019-09-30 13:06:47 -0700127 return false;
128 }
129}
130
Paul Crowley77df7f22020-01-23 15:29:30 -0800131bool installKey(const std::string& mountpoint, const EncryptionOptions& options,
132 const KeyBuffer& key, EncryptionPolicy* policy) {
Nathan Huckleberrya21962b2023-02-22 02:28:28 +0000133 const std::lock_guard<std::mutex> lock(fscrypt_keyring_mutex);
Paul Crowley77df7f22020-01-23 15:29:30 -0800134 policy->options = options;
Eric Biggersf3dc4202019-09-30 13:05:58 -0700135 // 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
Eric Biggers83a73d72019-09-30 13:06:47 -0700140 // Initialize the "key specifier", which is like a name for the key.
Paul Crowley77df7f22020-01-23 15:29:30 -0800141 switch (options.version) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700142 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.
Pig654cdd12020-09-25 22:56:33 +0800146 if (options.use_hw_wrapped_key) {
147 /* When wrapped key is supported, only the first 32 bytes are
148 the same per boot. The second 32 bytes can change as the ephemeral
149 key is different. */
150 policy->key_raw_ref = generateKeyRef((const uint8_t*)key.data(), key.size()/2);
151 } else {
152 policy->key_raw_ref = generateKeyRef((const uint8_t*)key.data(), key.size());
153 }
Paul Crowley77df7f22020-01-23 15:29:30 -0800154 if (!buildKeySpecifier(&arg->key_spec, *policy)) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700155 return false;
156 }
157 break;
158 case 2:
159 // A key for a v2 policy is specified by an 16-byte "identifier",
160 // which is a cryptographic hash of the key itself which the kernel
161 // computes and returns. Any user-provided value is ignored; we
162 // just need to set the specifier type to indicate that we're adding
163 // this type of key.
164 arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
165 break;
166 default:
Paul Crowley77df7f22020-01-23 15:29:30 -0800167 LOG(ERROR) << "Invalid encryption policy version: " << options.version;
Eric Biggers83a73d72019-09-30 13:06:47 -0700168 return false;
169 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700170
Eric Biggers01604fb2023-08-07 19:35:01 +0000171 if (options.use_hw_wrapped_key) arg->__flags |= __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED;
172 // Provide the raw key.
Eric Biggersf3dc4202019-09-30 13:05:58 -0700173 arg->raw_size = key.size();
174 memcpy(arg->raw, key.data(), key.size());
175
Eric Biggers01604fb2023-08-07 19:35:01 +0000176 android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
177 if (fd == -1) {
178 PLOG(ERROR) << "Failed to open " << mountpoint << " to install key";
179 return false;
180 }
181
182 if (ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, arg) != 0) {
183 PLOG(ERROR) << "Failed to install fscrypt key to " << mountpoint;
184 return false;
185 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700186
Eric Biggers83a73d72019-09-30 13:06:47 -0700187 if (arg->key_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
188 // Retrieve the key identifier that the kernel computed.
Paul Crowley77df7f22020-01-23 15:29:30 -0800189 policy->key_raw_ref =
190 std::string((char*)arg->key_spec.u.identifier, FSCRYPT_KEY_IDENTIFIER_SIZE);
Eric Biggers83a73d72019-09-30 13:06:47 -0700191 }
Eric Biggers01604fb2023-08-07 19:35:01 +0000192 LOG(DEBUG) << "Installed fscrypt key with ref " << keyrefstring(policy->key_raw_ref) << " to "
193 << mountpoint;
Eric Biggersf3dc4202019-09-30 13:05:58 -0700194 return true;
195}
196
Nathan Huckleberrya21962b2023-02-22 02:28:28 +0000197static void waitForBusyFiles(const struct fscrypt_key_specifier key_spec, const std::string ref,
198 const std::string mountpoint) {
199 android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
200 if (fd == -1) {
201 PLOG(ERROR) << "Failed to open " << mountpoint << " to evict key";
202 return;
203 }
204
205 std::chrono::milliseconds wait_time(3200);
206 std::chrono::milliseconds total_wait_time(0);
207 while (wait_time <= std::chrono::milliseconds(51200)) {
208 total_wait_time += wait_time;
209 std::this_thread::sleep_for(wait_time);
210
211 const std::lock_guard<std::mutex> lock(fscrypt_keyring_mutex);
212
213 struct fscrypt_get_key_status_arg get_arg;
214 memset(&get_arg, 0, sizeof(get_arg));
215 get_arg.key_spec = key_spec;
216
217 if (ioctl(fd, FS_IOC_GET_ENCRYPTION_KEY_STATUS, &get_arg) != 0) {
218 PLOG(ERROR) << "Failed to get status for fscrypt key with ref " << ref << " from "
219 << mountpoint;
220 return;
221 }
222 if (get_arg.status != FSCRYPT_KEY_STATUS_INCOMPLETELY_REMOVED) {
223 LOG(DEBUG) << "Key status changed, cancelling busy file cleanup for key with ref "
224 << ref << ".";
225 return;
226 }
227
228 struct fscrypt_remove_key_arg remove_arg;
229 memset(&remove_arg, 0, sizeof(remove_arg));
230 remove_arg.key_spec = key_spec;
231
232 if (ioctl(fd, FS_IOC_REMOVE_ENCRYPTION_KEY, &remove_arg) != 0) {
233 PLOG(ERROR) << "Failed to clean up busy files for fscrypt key with ref " << ref
234 << " from " << mountpoint;
235 return;
236 }
237 if (remove_arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS) {
238 // Should never happen because keys are only added/removed as root.
239 LOG(ERROR) << "Unexpected case: key with ref " << ref
240 << " is still added by other users!";
241 } else if (!(remove_arg.removal_status_flags &
242 FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY)) {
243 LOG(INFO) << "Successfully cleaned up busy files for key with ref " << ref
244 << ". After waiting " << total_wait_time.count() << "ms.";
245 return;
246 }
247 LOG(WARNING) << "Files still open after waiting " << total_wait_time.count()
248 << "ms. Key with ref " << ref << " still has unlocked files!";
249 wait_time *= 2;
250 }
251 LOG(ERROR) << "Waiting for files to close never completed. Files using key with ref " << ref
252 << " were not locked!";
253}
254
Paul Crowley77df7f22020-01-23 15:29:30 -0800255bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) {
Nathan Huckleberrya21962b2023-02-22 02:28:28 +0000256 const std::lock_guard<std::mutex> lock(fscrypt_keyring_mutex);
Eric Biggersf3dc4202019-09-30 13:05:58 -0700257
258 android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
259 if (fd == -1) {
260 PLOG(ERROR) << "Failed to open " << mountpoint << " to evict key";
261 return false;
262 }
263
264 struct fscrypt_remove_key_arg arg;
265 memset(&arg, 0, sizeof(arg));
266
Paul Crowley77df7f22020-01-23 15:29:30 -0800267 if (!buildKeySpecifier(&arg.key_spec, policy)) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700268 return false;
269 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700270
Paul Crowley77df7f22020-01-23 15:29:30 -0800271 std::string ref = keyrefstring(policy.key_raw_ref);
Eric Biggersf3dc4202019-09-30 13:05:58 -0700272
273 if (ioctl(fd, FS_IOC_REMOVE_ENCRYPTION_KEY, &arg) != 0) {
274 PLOG(ERROR) << "Failed to evict fscrypt key with ref " << ref << " from " << mountpoint;
275 return false;
276 }
277
278 LOG(DEBUG) << "Evicted fscrypt key with ref " << ref << " from " << mountpoint;
279 if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS) {
280 // Should never happen because keys are only added/removed as root.
281 LOG(ERROR) << "Unexpected case: key with ref " << ref << " is still added by other users!";
282 } else if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY) {
Nathan Huckleberrya21962b2023-02-22 02:28:28 +0000283 LOG(WARNING)
284 << "Files still open after removing key with ref " << ref
285 << ". These files were not locked! Punting busy file clean up to worker thread.";
286 // Processes are killed asynchronously in ActivityManagerService due to performance issues
287 // with synchronous kills. If there were busy files they will probably be killed soon. Wait
288 // for them asynchronously.
289 std::thread busyFilesThread(waitForBusyFiles, arg.key_spec, ref, mountpoint);
290 busyFilesThread.detach();
Eric Biggersf3dc4202019-09-30 13:05:58 -0700291 }
292 return true;
293}
294
Paul Crowley4eac2642020-02-12 11:04:05 -0800295bool retrieveOrGenerateKey(const std::string& key_path, const std::string& tmp_path,
296 const KeyAuthentication& key_authentication, const KeyGeneration& gen,
Eric Biggersf74373b2020-11-05 19:58:26 -0800297 KeyBuffer* key) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700298 if (pathExists(key_path)) {
299 LOG(DEBUG) << "Key exists, using: " << key_path;
Eric Biggersf74373b2020-11-05 19:58:26 -0800300 if (!retrieveKey(key_path, key_authentication, key)) return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700301 } else {
Paul Crowley4eac2642020-02-12 11:04:05 -0800302 if (!gen.allow_gen) {
Paul Crowley14c8c072018-09-18 13:30:21 -0700303 LOG(ERROR) << "No key found in " << key_path;
304 return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700305 }
306 LOG(INFO) << "Creating new key in " << key_path;
Paul Crowley4eac2642020-02-12 11:04:05 -0800307 if (!generateStorageKey(gen, key)) return false;
Paul Crowley77df7f22020-01-23 15:29:30 -0800308 if (!storeKeyAtomically(key_path, tmp_path, key_authentication, *key)) return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700309 }
310 return true;
311}
312
Paul Crowleyf71ace32016-06-02 11:01:19 -0700313} // namespace vold
314} // namespace android