blob: bd2ccddd3a1c531bf2a99b2ba67b997604cc06ed [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.
Paul Crowley77df7f22020-01-23 15:29:30 -0800146 policy->key_raw_ref = generateKeyRef((const uint8_t*)key.data(), key.size());
Paul Crowley77df7f22020-01-23 15:29:30 -0800147 if (!buildKeySpecifier(&arg->key_spec, *policy)) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700148 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:
Paul Crowley77df7f22020-01-23 15:29:30 -0800160 LOG(ERROR) << "Invalid encryption policy version: " << options.version;
Eric Biggers83a73d72019-09-30 13:06:47 -0700161 return false;
162 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700163
Eric Biggers01604fb2023-08-07 19:35:01 +0000164 if (options.use_hw_wrapped_key) arg->__flags |= __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED;
165 // Provide the raw key.
Eric Biggersf3dc4202019-09-30 13:05:58 -0700166 arg->raw_size = key.size();
167 memcpy(arg->raw, key.data(), key.size());
168
Eric Biggers01604fb2023-08-07 19:35:01 +0000169 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 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700179
Eric Biggers83a73d72019-09-30 13:06:47 -0700180 if (arg->key_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
181 // Retrieve the key identifier that the kernel computed.
Paul Crowley77df7f22020-01-23 15:29:30 -0800182 policy->key_raw_ref =
183 std::string((char*)arg->key_spec.u.identifier, FSCRYPT_KEY_IDENTIFIER_SIZE);
Eric Biggers83a73d72019-09-30 13:06:47 -0700184 }
Eric Biggers01604fb2023-08-07 19:35:01 +0000185 LOG(DEBUG) << "Installed fscrypt key with ref " << keyrefstring(policy->key_raw_ref) << " to "
186 << mountpoint;
Eric Biggersf3dc4202019-09-30 13:05:58 -0700187 return true;
188}
189
Nathan Huckleberrya21962b2023-02-22 02:28:28 +0000190static 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
Paul Crowley77df7f22020-01-23 15:29:30 -0800248bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) {
Nathan Huckleberrya21962b2023-02-22 02:28:28 +0000249 const std::lock_guard<std::mutex> lock(fscrypt_keyring_mutex);
Eric Biggersf3dc4202019-09-30 13:05:58 -0700250
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
Paul Crowley77df7f22020-01-23 15:29:30 -0800260 if (!buildKeySpecifier(&arg.key_spec, policy)) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700261 return false;
262 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700263
Paul Crowley77df7f22020-01-23 15:29:30 -0800264 std::string ref = keyrefstring(policy.key_raw_ref);
Eric Biggersf3dc4202019-09-30 13:05:58 -0700265
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) {
Nathan Huckleberrya21962b2023-02-22 02:28:28 +0000276 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();
Eric Biggersf3dc4202019-09-30 13:05:58 -0700284 }
285 return true;
286}
287
Paul Crowley4eac2642020-02-12 11:04:05 -0800288bool retrieveOrGenerateKey(const std::string& key_path, const std::string& tmp_path,
289 const KeyAuthentication& key_authentication, const KeyGeneration& gen,
Eric Biggersf74373b2020-11-05 19:58:26 -0800290 KeyBuffer* key) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700291 if (pathExists(key_path)) {
292 LOG(DEBUG) << "Key exists, using: " << key_path;
Eric Biggersf74373b2020-11-05 19:58:26 -0800293 if (!retrieveKey(key_path, key_authentication, key)) return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700294 } else {
Paul Crowley4eac2642020-02-12 11:04:05 -0800295 if (!gen.allow_gen) {
Paul Crowley14c8c072018-09-18 13:30:21 -0700296 LOG(ERROR) << "No key found in " << key_path;
297 return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700298 }
299 LOG(INFO) << "Creating new key in " << key_path;
Paul Crowley4eac2642020-02-12 11:04:05 -0800300 if (!generateStorageKey(gen, key)) return false;
Paul Crowley77df7f22020-01-23 15:29:30 -0800301 if (!storeKeyAtomically(key_path, tmp_path, key_authentication, *key)) return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700302 }
303 return true;
304}
305
Paul Crowleyf71ace32016-06-02 11:01:19 -0700306} // namespace vold
307} // namespace android