blob: ae4d70bffff2e6b4e7cc52d28663528774da39ad [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>
22
Eric Biggersf3dc4202019-09-30 13:05:58 -070023#include <fcntl.h>
Eric Biggers3e9c9962019-12-16 15:55:12 -080024#include <linux/fscrypt.h>
Paul Crowleyf71ace32016-06-02 11:01:19 -070025#include <openssl/sha.h>
Eric Biggersf3dc4202019-09-30 13:05:58 -070026#include <sys/ioctl.h>
Paul Crowleyf71ace32016-06-02 11:01:19 -070027
28#include <android-base/file.h>
29#include <android-base/logging.h>
Elliott Hughesc3bda182017-05-09 17:01:04 -070030#include <keyutils.h>
Paul Crowleyf71ace32016-06-02 11:01:19 -070031
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -080032#include <fscrypt_uapi.h>
Paul Crowleyf71ace32016-06-02 11:01:19 -070033#include "KeyStorage.h"
34#include "Utils.h"
35
36namespace android {
37namespace vold {
38
Pavel Grafove2e2d302017-08-01 17:15:53 +010039bool randomKey(KeyBuffer* key) {
Eric Biggers506342f2019-12-17 13:11:25 -080040 *key = KeyBuffer(FSCRYPT_MAX_KEY_SIZE);
Pavel Grafove2e2d302017-08-01 17:15:53 +010041 if (ReadRandomBytes(key->size(), key->data()) != 0) {
Paul Crowleyf71ace32016-06-02 11:01:19 -070042 // TODO status_t plays badly with PLOG, fix it.
43 LOG(ERROR) << "Random read failed";
44 return false;
45 }
46 return true;
47}
48
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -080049bool generateStorageKey(const EncryptionOptions& options, KeyBuffer* key) {
50 if (options.use_hw_wrapped_key) {
51 return generateWrappedStorageKey(key);
52 }
53 return randomKey(key);
54}
55
Eric Biggersf3dc4202019-09-30 13:05:58 -070056// Return true if the kernel supports the ioctls to add/remove fscrypt keys
57// directly to/from the filesystem.
58bool isFsKeyringSupported(void) {
59 static bool initialized = false;
60 static bool supported;
61
62 if (!initialized) {
63 android::base::unique_fd fd(open("/data", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
64
65 // FS_IOC_ADD_ENCRYPTION_KEY with a NULL argument will fail with ENOTTY
66 // if the ioctl isn't supported. Otherwise it will fail with another
67 // error code such as EFAULT.
68 errno = 0;
69 (void)ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, NULL);
70 if (errno == ENOTTY) {
71 LOG(INFO) << "Kernel doesn't support FS_IOC_ADD_ENCRYPTION_KEY. Falling back to "
72 "session keyring";
73 supported = false;
74 } else {
75 if (errno != EFAULT) {
76 PLOG(WARNING) << "Unexpected error from FS_IOC_ADD_ENCRYPTION_KEY";
77 }
78 LOG(DEBUG) << "Detected support for FS_IOC_ADD_ENCRYPTION_KEY";
79 supported = true;
80 }
81 // There's no need to check for FS_IOC_REMOVE_ENCRYPTION_KEY, since it's
82 // guaranteed to be available if FS_IOC_ADD_ENCRYPTION_KEY is. There's
83 // also no need to check for support on external volumes separately from
84 // /data, since either the kernel supports the ioctls on all
85 // fscrypt-capable filesystems or it doesn't.
86
87 initialized = true;
88 }
89 return supported;
90}
91
Paul Crowleyf71ace32016-06-02 11:01:19 -070092// Get raw keyref - used to make keyname and to pass to ioctl
Eric Biggersba997ee2018-10-23 13:07:43 -070093static std::string generateKeyRef(const uint8_t* key, int length) {
Paul Crowleyf71ace32016-06-02 11:01:19 -070094 SHA512_CTX c;
95
96 SHA512_Init(&c);
97 SHA512_Update(&c, key, length);
98 unsigned char key_ref1[SHA512_DIGEST_LENGTH];
99 SHA512_Final(key_ref1, &c);
100
101 SHA512_Init(&c);
102 SHA512_Update(&c, key_ref1, SHA512_DIGEST_LENGTH);
103 unsigned char key_ref2[SHA512_DIGEST_LENGTH];
104 SHA512_Final(key_ref2, &c);
105
Eric Biggers506342f2019-12-17 13:11:25 -0800106 static_assert(FSCRYPT_KEY_DESCRIPTOR_SIZE <= SHA512_DIGEST_LENGTH,
107 "Hash too short for descriptor");
108 return std::string((char*)key_ref2, FSCRYPT_KEY_DESCRIPTOR_SIZE);
Paul Crowleyf71ace32016-06-02 11:01:19 -0700109}
110
Eric Biggersa701c452018-10-23 13:06:55 -0700111static bool fillKey(const KeyBuffer& key, fscrypt_key* fs_key) {
Eric Biggers506342f2019-12-17 13:11:25 -0800112 if (key.size() != FSCRYPT_MAX_KEY_SIZE) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700113 LOG(ERROR) << "Wrong size key " << key.size();
114 return false;
115 }
Eric Biggers506342f2019-12-17 13:11:25 -0800116 static_assert(FSCRYPT_MAX_KEY_SIZE == sizeof(fs_key->raw), "Mismatch of max key sizes");
117 fs_key->mode = 0; // unused by kernel
Eric Biggersa701c452018-10-23 13:06:55 -0700118 memcpy(fs_key->raw, key.data(), key.size());
Eric Biggers506342f2019-12-17 13:11:25 -0800119 fs_key->size = key.size();
Paul Crowleyf71ace32016-06-02 11:01:19 -0700120 return true;
121}
122
Paul Crowley14c8c072018-09-18 13:30:21 -0700123static char const* const NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt", nullptr};
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700124
Eric Biggersf3dc4202019-09-30 13:05:58 -0700125static std::string keyrefstring(const std::string& raw_ref) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700126 std::ostringstream o;
Chen, Luhai5744dfe2017-08-18 14:49:45 +0800127 for (unsigned char i : raw_ref) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700128 o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
129 }
130 return o.str();
131}
132
Eric Biggersf3dc4202019-09-30 13:05:58 -0700133static std::string buildLegacyKeyName(const std::string& prefix, const std::string& raw_ref) {
134 return prefix + ":" + keyrefstring(raw_ref);
135}
136
137// Get the ID of the keyring we store all fscrypt keys in when the kernel is too
138// old to support FS_IOC_ADD_ENCRYPTION_KEY and FS_IOC_REMOVE_ENCRYPTION_KEY.
Eric Biggersa701c452018-10-23 13:06:55 -0700139static bool fscryptKeyring(key_serial_t* device_keyring) {
140 *device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
Paul Crowleyf71ace32016-06-02 11:01:19 -0700141 if (*device_keyring == -1) {
142 PLOG(ERROR) << "Unable to find device keyring";
143 return false;
144 }
145 return true;
146}
147
Eric Biggersf3dc4202019-09-30 13:05:58 -0700148// Add an encryption key to the legacy global session keyring.
149static bool installKeyLegacy(const KeyBuffer& key, const std::string& raw_ref) {
Eric Biggersa701c452018-10-23 13:06:55 -0700150 // Place fscrypt_key into automatically zeroing buffer.
151 KeyBuffer fsKeyBuffer(sizeof(fscrypt_key));
152 fscrypt_key& fs_key = *reinterpret_cast<fscrypt_key*>(fsKeyBuffer.data());
Pavel Grafove2e2d302017-08-01 17:15:53 +0100153
Eric Biggersa701c452018-10-23 13:06:55 -0700154 if (!fillKey(key, &fs_key)) return false;
Paul Crowleyf71ace32016-06-02 11:01:19 -0700155 key_serial_t device_keyring;
Eric Biggersa701c452018-10-23 13:06:55 -0700156 if (!fscryptKeyring(&device_keyring)) return false;
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700157 for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
Eric Biggersf3dc4202019-09-30 13:05:58 -0700158 auto ref = buildLegacyKeyName(*name_prefix, raw_ref);
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700159 key_serial_t key_id =
Eric Biggersa701c452018-10-23 13:06:55 -0700160 add_key("logon", ref.c_str(), (void*)&fs_key, sizeof(fs_key), device_keyring);
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700161 if (key_id == -1) {
162 PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
163 return false;
164 }
165 LOG(DEBUG) << "Added key " << key_id << " (" << ref << ") to keyring " << device_keyring
166 << " in process " << getpid();
Paul Crowleyf71ace32016-06-02 11:01:19 -0700167 }
Paul Crowleyf71ace32016-06-02 11:01:19 -0700168 return true;
169}
170
Eric Biggers83a73d72019-09-30 13:06:47 -0700171// Build a struct fscrypt_key_specifier for use in the key management ioctls.
Paul Crowley77df7f22020-01-23 15:29:30 -0800172static bool buildKeySpecifier(fscrypt_key_specifier* spec, const EncryptionPolicy& policy) {
173 switch (policy.options.version) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700174 case 1:
Paul Crowley77df7f22020-01-23 15:29:30 -0800175 if (policy.key_raw_ref.size() != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700176 LOG(ERROR) << "Invalid key specifier size for v1 encryption policy: "
Paul Crowley77df7f22020-01-23 15:29:30 -0800177 << policy.key_raw_ref.size();
Eric Biggers83a73d72019-09-30 13:06:47 -0700178 return false;
179 }
180 spec->type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
Paul Crowley77df7f22020-01-23 15:29:30 -0800181 memcpy(spec->u.descriptor, policy.key_raw_ref.c_str(), FSCRYPT_KEY_DESCRIPTOR_SIZE);
Eric Biggers83a73d72019-09-30 13:06:47 -0700182 return true;
183 case 2:
Paul Crowley77df7f22020-01-23 15:29:30 -0800184 if (policy.key_raw_ref.size() != FSCRYPT_KEY_IDENTIFIER_SIZE) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700185 LOG(ERROR) << "Invalid key specifier size for v2 encryption policy: "
Paul Crowley77df7f22020-01-23 15:29:30 -0800186 << policy.key_raw_ref.size();
Eric Biggers83a73d72019-09-30 13:06:47 -0700187 return false;
188 }
189 spec->type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
Paul Crowley77df7f22020-01-23 15:29:30 -0800190 memcpy(spec->u.identifier, policy.key_raw_ref.c_str(), FSCRYPT_KEY_IDENTIFIER_SIZE);
Eric Biggers83a73d72019-09-30 13:06:47 -0700191 return true;
192 default:
Paul Crowley77df7f22020-01-23 15:29:30 -0800193 LOG(ERROR) << "Invalid encryption policy version: " << policy.options.version;
Eric Biggers83a73d72019-09-30 13:06:47 -0700194 return false;
195 }
196}
197
Paul Crowley77df7f22020-01-23 15:29:30 -0800198bool installKey(const std::string& mountpoint, const EncryptionOptions& options,
199 const KeyBuffer& key, EncryptionPolicy* policy) {
200 policy->options = options;
Eric Biggersf3dc4202019-09-30 13:05:58 -0700201 // Put the fscrypt_add_key_arg in an automatically-zeroing buffer, since we
202 // have to copy the raw key into it.
203 KeyBuffer arg_buf(sizeof(struct fscrypt_add_key_arg) + key.size(), 0);
204 struct fscrypt_add_key_arg* arg = (struct fscrypt_add_key_arg*)arg_buf.data();
205
Eric Biggers83a73d72019-09-30 13:06:47 -0700206 // Initialize the "key specifier", which is like a name for the key.
Paul Crowley77df7f22020-01-23 15:29:30 -0800207 switch (options.version) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700208 case 1:
209 // A key for a v1 policy is specified by an arbitrary 8-byte
210 // "descriptor", which must be provided by userspace. We use the
211 // first 8 bytes from the double SHA-512 of the key itself.
Paul Crowley77df7f22020-01-23 15:29:30 -0800212 policy->key_raw_ref = generateKeyRef((const uint8_t*)key.data(), key.size());
Eric Biggers83a73d72019-09-30 13:06:47 -0700213 if (!isFsKeyringSupported()) {
Paul Crowley77df7f22020-01-23 15:29:30 -0800214 return installKeyLegacy(key, policy->key_raw_ref);
Eric Biggers83a73d72019-09-30 13:06:47 -0700215 }
Paul Crowley77df7f22020-01-23 15:29:30 -0800216 if (!buildKeySpecifier(&arg->key_spec, *policy)) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700217 return false;
218 }
219 break;
220 case 2:
221 // A key for a v2 policy is specified by an 16-byte "identifier",
222 // which is a cryptographic hash of the key itself which the kernel
223 // computes and returns. Any user-provided value is ignored; we
224 // just need to set the specifier type to indicate that we're adding
225 // this type of key.
226 arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
227 break;
228 default:
Paul Crowley77df7f22020-01-23 15:29:30 -0800229 LOG(ERROR) << "Invalid encryption policy version: " << options.version;
Eric Biggers83a73d72019-09-30 13:06:47 -0700230 return false;
231 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700232
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -0800233 if (options.use_hw_wrapped_key) arg->flags |= FSCRYPT_ADD_KEY_FLAG_WRAPPED;
Eric Biggers83a73d72019-09-30 13:06:47 -0700234 // Provide the raw key.
Eric Biggersf3dc4202019-09-30 13:05:58 -0700235 arg->raw_size = key.size();
236 memcpy(arg->raw, key.data(), key.size());
237
238 android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
239 if (fd == -1) {
240 PLOG(ERROR) << "Failed to open " << mountpoint << " to install key";
241 return false;
242 }
243
244 if (ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, arg) != 0) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700245 PLOG(ERROR) << "Failed to install fscrypt key to " << mountpoint;
Eric Biggersf3dc4202019-09-30 13:05:58 -0700246 return false;
247 }
248
Eric Biggers83a73d72019-09-30 13:06:47 -0700249 if (arg->key_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
250 // Retrieve the key identifier that the kernel computed.
Paul Crowley77df7f22020-01-23 15:29:30 -0800251 policy->key_raw_ref =
252 std::string((char*)arg->key_spec.u.identifier, FSCRYPT_KEY_IDENTIFIER_SIZE);
Eric Biggers83a73d72019-09-30 13:06:47 -0700253 }
Paul Crowley77df7f22020-01-23 15:29:30 -0800254 LOG(DEBUG) << "Installed fscrypt key with ref " << keyrefstring(policy->key_raw_ref) << " to "
Eric Biggersf3dc4202019-09-30 13:05:58 -0700255 << mountpoint;
256 return true;
257}
258
259// Remove an encryption key from the legacy global session keyring.
260static bool evictKeyLegacy(const std::string& raw_ref) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700261 key_serial_t device_keyring;
Eric Biggersa701c452018-10-23 13:06:55 -0700262 if (!fscryptKeyring(&device_keyring)) return false;
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700263 bool success = true;
264 for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
Eric Biggersf3dc4202019-09-30 13:05:58 -0700265 auto ref = buildLegacyKeyName(*name_prefix, raw_ref);
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700266 auto key_serial = keyctl_search(device_keyring, "logon", ref.c_str(), 0);
Paul Crowleyf71ace32016-06-02 11:01:19 -0700267
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700268 // Unlink the key from the keyring. Prefer unlinking to revoking or
269 // invalidating, since unlinking is actually no less secure currently, and
270 // it avoids bugs in certain kernel versions where the keyring key is
271 // referenced from places it shouldn't be.
272 if (keyctl_unlink(key_serial, device_keyring) != 0) {
273 PLOG(ERROR) << "Failed to unlink key with serial " << key_serial << " ref " << ref;
274 success = false;
275 } else {
276 LOG(DEBUG) << "Unlinked key with serial " << key_serial << " ref " << ref;
277 }
Paul Crowleyf71ace32016-06-02 11:01:19 -0700278 }
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700279 return success;
Paul Crowleyf71ace32016-06-02 11:01:19 -0700280}
281
Paul Crowley77df7f22020-01-23 15:29:30 -0800282bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) {
283 if (policy.options.version == 1 && !isFsKeyringSupported()) {
284 return evictKeyLegacy(policy.key_raw_ref);
Eric Biggersf3dc4202019-09-30 13:05:58 -0700285 }
286
287 android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
288 if (fd == -1) {
289 PLOG(ERROR) << "Failed to open " << mountpoint << " to evict key";
290 return false;
291 }
292
293 struct fscrypt_remove_key_arg arg;
294 memset(&arg, 0, sizeof(arg));
295
Paul Crowley77df7f22020-01-23 15:29:30 -0800296 if (!buildKeySpecifier(&arg.key_spec, policy)) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700297 return false;
298 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700299
Paul Crowley77df7f22020-01-23 15:29:30 -0800300 std::string ref = keyrefstring(policy.key_raw_ref);
Eric Biggersf3dc4202019-09-30 13:05:58 -0700301
302 if (ioctl(fd, FS_IOC_REMOVE_ENCRYPTION_KEY, &arg) != 0) {
303 PLOG(ERROR) << "Failed to evict fscrypt key with ref " << ref << " from " << mountpoint;
304 return false;
305 }
306
307 LOG(DEBUG) << "Evicted fscrypt key with ref " << ref << " from " << mountpoint;
308 if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS) {
309 // Should never happen because keys are only added/removed as root.
310 LOG(ERROR) << "Unexpected case: key with ref " << ref << " is still added by other users!";
311 } else if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY) {
312 LOG(ERROR) << "Files still open after removing key with ref " << ref
313 << ". These files were not locked!";
314 }
315 return true;
316}
317
Paul Crowley77df7f22020-01-23 15:29:30 -0800318bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authentication,
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -0800319 const std::string& key_path, const std::string& tmp_path,
320 const EncryptionOptions& options, KeyBuffer* key, bool keepOld) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700321 if (pathExists(key_path)) {
322 LOG(DEBUG) << "Key exists, using: " << key_path;
Paul Crowley77df7f22020-01-23 15:29:30 -0800323 if (!retrieveKey(key_path, key_authentication, key, keepOld)) return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700324 } else {
325 if (!create_if_absent) {
Paul Crowley14c8c072018-09-18 13:30:21 -0700326 LOG(ERROR) << "No key found in " << key_path;
327 return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700328 }
329 LOG(INFO) << "Creating new key in " << key_path;
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -0800330 if (!generateStorageKey(options, key)) return false;
Paul Crowley77df7f22020-01-23 15:29:30 -0800331 if (!storeKeyAtomically(key_path, tmp_path, key_authentication, *key)) return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700332 }
333 return true;
334}
335
Paul Crowleyf71ace32016-06-02 11:01:19 -0700336} // namespace vold
337} // namespace android