blob: 2e810ffdab5c7611b152bb5b161e352854272672 [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
Paul Crowley4eac2642020-02-12 11:04:05 -080039const KeyGeneration makeGen(const EncryptionOptions& options) {
40 return KeyGeneration{FSCRYPT_MAX_KEY_SIZE, true, options.use_hw_wrapped_key};
41}
42
43const KeyGeneration makeGen(const CryptoType& crypto) {
44 return KeyGeneration{crypto.get_keysize(), true, false};
45}
46
47const KeyGeneration neverGen() {
48 return KeyGeneration{0, false, false};
49}
50
51static bool randomKey(size_t size, KeyBuffer* key) {
52 *key = KeyBuffer(size);
Pavel Grafove2e2d302017-08-01 17:15:53 +010053 if (ReadRandomBytes(key->size(), key->data()) != 0) {
Paul Crowleyf71ace32016-06-02 11:01:19 -070054 // TODO status_t plays badly with PLOG, fix it.
55 LOG(ERROR) << "Random read failed";
56 return false;
57 }
58 return true;
59}
60
Paul Crowley4eac2642020-02-12 11:04:05 -080061bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key) {
62 if (!gen.allow_gen) return false;
63 if (gen.use_hw_wrapped_key) {
64 if (gen.keysize != FSCRYPT_MAX_KEY_SIZE) {
65 LOG(ERROR) << "Cannot generate a wrapped key " << gen.keysize << " bytes long";
66 return false;
67 }
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -080068 return generateWrappedStorageKey(key);
Paul Crowley4eac2642020-02-12 11:04:05 -080069 } else {
70 return randomKey(gen.keysize, key);
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -080071 }
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -080072}
73
Eric Biggersf3dc4202019-09-30 13:05:58 -070074// Return true if the kernel supports the ioctls to add/remove fscrypt keys
75// directly to/from the filesystem.
76bool isFsKeyringSupported(void) {
77 static bool initialized = false;
78 static bool supported;
79
80 if (!initialized) {
81 android::base::unique_fd fd(open("/data", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
82
83 // FS_IOC_ADD_ENCRYPTION_KEY with a NULL argument will fail with ENOTTY
84 // if the ioctl isn't supported. Otherwise it will fail with another
85 // error code such as EFAULT.
86 errno = 0;
87 (void)ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, NULL);
88 if (errno == ENOTTY) {
89 LOG(INFO) << "Kernel doesn't support FS_IOC_ADD_ENCRYPTION_KEY. Falling back to "
90 "session keyring";
91 supported = false;
92 } else {
93 if (errno != EFAULT) {
94 PLOG(WARNING) << "Unexpected error from FS_IOC_ADD_ENCRYPTION_KEY";
95 }
96 LOG(DEBUG) << "Detected support for FS_IOC_ADD_ENCRYPTION_KEY";
97 supported = true;
98 }
99 // There's no need to check for FS_IOC_REMOVE_ENCRYPTION_KEY, since it's
100 // guaranteed to be available if FS_IOC_ADD_ENCRYPTION_KEY is. There's
101 // also no need to check for support on external volumes separately from
102 // /data, since either the kernel supports the ioctls on all
103 // fscrypt-capable filesystems or it doesn't.
104
105 initialized = true;
106 }
107 return supported;
108}
109
Paul Crowleyf71ace32016-06-02 11:01:19 -0700110// Get raw keyref - used to make keyname and to pass to ioctl
Eric Biggersba997ee2018-10-23 13:07:43 -0700111static std::string generateKeyRef(const uint8_t* key, int length) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700112 SHA512_CTX c;
113
114 SHA512_Init(&c);
115 SHA512_Update(&c, key, length);
116 unsigned char key_ref1[SHA512_DIGEST_LENGTH];
117 SHA512_Final(key_ref1, &c);
118
119 SHA512_Init(&c);
120 SHA512_Update(&c, key_ref1, SHA512_DIGEST_LENGTH);
121 unsigned char key_ref2[SHA512_DIGEST_LENGTH];
122 SHA512_Final(key_ref2, &c);
123
Eric Biggers506342f2019-12-17 13:11:25 -0800124 static_assert(FSCRYPT_KEY_DESCRIPTOR_SIZE <= SHA512_DIGEST_LENGTH,
125 "Hash too short for descriptor");
126 return std::string((char*)key_ref2, FSCRYPT_KEY_DESCRIPTOR_SIZE);
Paul Crowleyf71ace32016-06-02 11:01:19 -0700127}
128
Eric Biggersa701c452018-10-23 13:06:55 -0700129static bool fillKey(const KeyBuffer& key, fscrypt_key* fs_key) {
Eric Biggers506342f2019-12-17 13:11:25 -0800130 if (key.size() != FSCRYPT_MAX_KEY_SIZE) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700131 LOG(ERROR) << "Wrong size key " << key.size();
132 return false;
133 }
Eric Biggers506342f2019-12-17 13:11:25 -0800134 static_assert(FSCRYPT_MAX_KEY_SIZE == sizeof(fs_key->raw), "Mismatch of max key sizes");
135 fs_key->mode = 0; // unused by kernel
Eric Biggersa701c452018-10-23 13:06:55 -0700136 memcpy(fs_key->raw, key.data(), key.size());
Eric Biggers506342f2019-12-17 13:11:25 -0800137 fs_key->size = key.size();
Paul Crowleyf71ace32016-06-02 11:01:19 -0700138 return true;
139}
140
Paul Crowley14c8c072018-09-18 13:30:21 -0700141static char const* const NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt", nullptr};
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700142
Eric Biggersf3dc4202019-09-30 13:05:58 -0700143static std::string keyrefstring(const std::string& raw_ref) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700144 std::ostringstream o;
Chen, Luhai5744dfe2017-08-18 14:49:45 +0800145 for (unsigned char i : raw_ref) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700146 o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
147 }
148 return o.str();
149}
150
Eric Biggersf3dc4202019-09-30 13:05:58 -0700151static std::string buildLegacyKeyName(const std::string& prefix, const std::string& raw_ref) {
152 return prefix + ":" + keyrefstring(raw_ref);
153}
154
155// Get the ID of the keyring we store all fscrypt keys in when the kernel is too
156// old to support FS_IOC_ADD_ENCRYPTION_KEY and FS_IOC_REMOVE_ENCRYPTION_KEY.
Eric Biggersa701c452018-10-23 13:06:55 -0700157static bool fscryptKeyring(key_serial_t* device_keyring) {
158 *device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
Paul Crowleyf71ace32016-06-02 11:01:19 -0700159 if (*device_keyring == -1) {
160 PLOG(ERROR) << "Unable to find device keyring";
161 return false;
162 }
163 return true;
164}
165
Eric Biggersf3dc4202019-09-30 13:05:58 -0700166// Add an encryption key to the legacy global session keyring.
167static bool installKeyLegacy(const KeyBuffer& key, const std::string& raw_ref) {
Eric Biggersa701c452018-10-23 13:06:55 -0700168 // Place fscrypt_key into automatically zeroing buffer.
169 KeyBuffer fsKeyBuffer(sizeof(fscrypt_key));
170 fscrypt_key& fs_key = *reinterpret_cast<fscrypt_key*>(fsKeyBuffer.data());
Pavel Grafove2e2d302017-08-01 17:15:53 +0100171
Eric Biggersa701c452018-10-23 13:06:55 -0700172 if (!fillKey(key, &fs_key)) return false;
Paul Crowleyf71ace32016-06-02 11:01:19 -0700173 key_serial_t device_keyring;
Eric Biggersa701c452018-10-23 13:06:55 -0700174 if (!fscryptKeyring(&device_keyring)) return false;
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700175 for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
Eric Biggersf3dc4202019-09-30 13:05:58 -0700176 auto ref = buildLegacyKeyName(*name_prefix, raw_ref);
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700177 key_serial_t key_id =
Eric Biggersa701c452018-10-23 13:06:55 -0700178 add_key("logon", ref.c_str(), (void*)&fs_key, sizeof(fs_key), device_keyring);
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700179 if (key_id == -1) {
180 PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
181 return false;
182 }
183 LOG(DEBUG) << "Added key " << key_id << " (" << ref << ") to keyring " << device_keyring
184 << " in process " << getpid();
Paul Crowleyf71ace32016-06-02 11:01:19 -0700185 }
Paul Crowleyf71ace32016-06-02 11:01:19 -0700186 return true;
187}
188
Eric Biggers83a73d72019-09-30 13:06:47 -0700189// Build a struct fscrypt_key_specifier for use in the key management ioctls.
Paul Crowley77df7f22020-01-23 15:29:30 -0800190static bool buildKeySpecifier(fscrypt_key_specifier* spec, const EncryptionPolicy& policy) {
191 switch (policy.options.version) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700192 case 1:
Paul Crowley77df7f22020-01-23 15:29:30 -0800193 if (policy.key_raw_ref.size() != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700194 LOG(ERROR) << "Invalid key specifier size for v1 encryption policy: "
Paul Crowley77df7f22020-01-23 15:29:30 -0800195 << policy.key_raw_ref.size();
Eric Biggers83a73d72019-09-30 13:06:47 -0700196 return false;
197 }
198 spec->type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
Paul Crowley77df7f22020-01-23 15:29:30 -0800199 memcpy(spec->u.descriptor, policy.key_raw_ref.c_str(), FSCRYPT_KEY_DESCRIPTOR_SIZE);
Eric Biggers83a73d72019-09-30 13:06:47 -0700200 return true;
201 case 2:
Paul Crowley77df7f22020-01-23 15:29:30 -0800202 if (policy.key_raw_ref.size() != FSCRYPT_KEY_IDENTIFIER_SIZE) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700203 LOG(ERROR) << "Invalid key specifier size for v2 encryption policy: "
Paul Crowley77df7f22020-01-23 15:29:30 -0800204 << policy.key_raw_ref.size();
Eric Biggers83a73d72019-09-30 13:06:47 -0700205 return false;
206 }
207 spec->type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
Paul Crowley77df7f22020-01-23 15:29:30 -0800208 memcpy(spec->u.identifier, policy.key_raw_ref.c_str(), FSCRYPT_KEY_IDENTIFIER_SIZE);
Eric Biggers83a73d72019-09-30 13:06:47 -0700209 return true;
210 default:
Paul Crowley77df7f22020-01-23 15:29:30 -0800211 LOG(ERROR) << "Invalid encryption policy version: " << policy.options.version;
Eric Biggers83a73d72019-09-30 13:06:47 -0700212 return false;
213 }
214}
215
Paul Crowley77df7f22020-01-23 15:29:30 -0800216bool installKey(const std::string& mountpoint, const EncryptionOptions& options,
217 const KeyBuffer& key, EncryptionPolicy* policy) {
218 policy->options = options;
Eric Biggersf3dc4202019-09-30 13:05:58 -0700219 // Put the fscrypt_add_key_arg in an automatically-zeroing buffer, since we
220 // have to copy the raw key into it.
221 KeyBuffer arg_buf(sizeof(struct fscrypt_add_key_arg) + key.size(), 0);
222 struct fscrypt_add_key_arg* arg = (struct fscrypt_add_key_arg*)arg_buf.data();
223
Eric Biggers83a73d72019-09-30 13:06:47 -0700224 // Initialize the "key specifier", which is like a name for the key.
Paul Crowley77df7f22020-01-23 15:29:30 -0800225 switch (options.version) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700226 case 1:
227 // A key for a v1 policy is specified by an arbitrary 8-byte
228 // "descriptor", which must be provided by userspace. We use the
229 // first 8 bytes from the double SHA-512 of the key itself.
Paul Crowley77df7f22020-01-23 15:29:30 -0800230 policy->key_raw_ref = generateKeyRef((const uint8_t*)key.data(), key.size());
Eric Biggers83a73d72019-09-30 13:06:47 -0700231 if (!isFsKeyringSupported()) {
Paul Crowley77df7f22020-01-23 15:29:30 -0800232 return installKeyLegacy(key, policy->key_raw_ref);
Eric Biggers83a73d72019-09-30 13:06:47 -0700233 }
Paul Crowley77df7f22020-01-23 15:29:30 -0800234 if (!buildKeySpecifier(&arg->key_spec, *policy)) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700235 return false;
236 }
237 break;
238 case 2:
239 // A key for a v2 policy is specified by an 16-byte "identifier",
240 // which is a cryptographic hash of the key itself which the kernel
241 // computes and returns. Any user-provided value is ignored; we
242 // just need to set the specifier type to indicate that we're adding
243 // this type of key.
244 arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
245 break;
246 default:
Paul Crowley77df7f22020-01-23 15:29:30 -0800247 LOG(ERROR) << "Invalid encryption policy version: " << options.version;
Eric Biggers83a73d72019-09-30 13:06:47 -0700248 return false;
249 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700250
Barani Muthukumaran3dfb0942020-02-03 13:06:45 -0800251 if (options.use_hw_wrapped_key) arg->flags |= FSCRYPT_ADD_KEY_FLAG_WRAPPED;
Eric Biggers83a73d72019-09-30 13:06:47 -0700252 // Provide the raw key.
Eric Biggersf3dc4202019-09-30 13:05:58 -0700253 arg->raw_size = key.size();
254 memcpy(arg->raw, key.data(), key.size());
255
256 android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
257 if (fd == -1) {
258 PLOG(ERROR) << "Failed to open " << mountpoint << " to install key";
259 return false;
260 }
261
262 if (ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, arg) != 0) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700263 PLOG(ERROR) << "Failed to install fscrypt key to " << mountpoint;
Eric Biggersf3dc4202019-09-30 13:05:58 -0700264 return false;
265 }
266
Eric Biggers83a73d72019-09-30 13:06:47 -0700267 if (arg->key_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
268 // Retrieve the key identifier that the kernel computed.
Paul Crowley77df7f22020-01-23 15:29:30 -0800269 policy->key_raw_ref =
270 std::string((char*)arg->key_spec.u.identifier, FSCRYPT_KEY_IDENTIFIER_SIZE);
Eric Biggers83a73d72019-09-30 13:06:47 -0700271 }
Paul Crowley77df7f22020-01-23 15:29:30 -0800272 LOG(DEBUG) << "Installed fscrypt key with ref " << keyrefstring(policy->key_raw_ref) << " to "
Eric Biggersf3dc4202019-09-30 13:05:58 -0700273 << mountpoint;
274 return true;
275}
276
277// Remove an encryption key from the legacy global session keyring.
278static bool evictKeyLegacy(const std::string& raw_ref) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700279 key_serial_t device_keyring;
Eric Biggersa701c452018-10-23 13:06:55 -0700280 if (!fscryptKeyring(&device_keyring)) return false;
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700281 bool success = true;
282 for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
Eric Biggersf3dc4202019-09-30 13:05:58 -0700283 auto ref = buildLegacyKeyName(*name_prefix, raw_ref);
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700284 auto key_serial = keyctl_search(device_keyring, "logon", ref.c_str(), 0);
Paul Crowleyf71ace32016-06-02 11:01:19 -0700285
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700286 // Unlink the key from the keyring. Prefer unlinking to revoking or
287 // invalidating, since unlinking is actually no less secure currently, and
288 // it avoids bugs in certain kernel versions where the keyring key is
289 // referenced from places it shouldn't be.
290 if (keyctl_unlink(key_serial, device_keyring) != 0) {
291 PLOG(ERROR) << "Failed to unlink key with serial " << key_serial << " ref " << ref;
292 success = false;
293 } else {
294 LOG(DEBUG) << "Unlinked key with serial " << key_serial << " ref " << ref;
295 }
Paul Crowleyf71ace32016-06-02 11:01:19 -0700296 }
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700297 return success;
Paul Crowleyf71ace32016-06-02 11:01:19 -0700298}
299
Paul Crowley77df7f22020-01-23 15:29:30 -0800300bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) {
301 if (policy.options.version == 1 && !isFsKeyringSupported()) {
302 return evictKeyLegacy(policy.key_raw_ref);
Eric Biggersf3dc4202019-09-30 13:05:58 -0700303 }
304
305 android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
306 if (fd == -1) {
307 PLOG(ERROR) << "Failed to open " << mountpoint << " to evict key";
308 return false;
309 }
310
311 struct fscrypt_remove_key_arg arg;
312 memset(&arg, 0, sizeof(arg));
313
Paul Crowley77df7f22020-01-23 15:29:30 -0800314 if (!buildKeySpecifier(&arg.key_spec, policy)) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700315 return false;
316 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700317
Paul Crowley77df7f22020-01-23 15:29:30 -0800318 std::string ref = keyrefstring(policy.key_raw_ref);
Eric Biggersf3dc4202019-09-30 13:05:58 -0700319
320 if (ioctl(fd, FS_IOC_REMOVE_ENCRYPTION_KEY, &arg) != 0) {
321 PLOG(ERROR) << "Failed to evict fscrypt key with ref " << ref << " from " << mountpoint;
322 return false;
323 }
324
325 LOG(DEBUG) << "Evicted fscrypt key with ref " << ref << " from " << mountpoint;
326 if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS) {
327 // Should never happen because keys are only added/removed as root.
328 LOG(ERROR) << "Unexpected case: key with ref " << ref << " is still added by other users!";
329 } else if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY) {
330 LOG(ERROR) << "Files still open after removing key with ref " << ref
331 << ". These files were not locked!";
332 }
333 return true;
334}
335
Paul Crowley4eac2642020-02-12 11:04:05 -0800336bool retrieveOrGenerateKey(const std::string& key_path, const std::string& tmp_path,
337 const KeyAuthentication& key_authentication, const KeyGeneration& gen,
338 KeyBuffer* key, bool keepOld) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700339 if (pathExists(key_path)) {
340 LOG(DEBUG) << "Key exists, using: " << key_path;
Paul Crowley77df7f22020-01-23 15:29:30 -0800341 if (!retrieveKey(key_path, key_authentication, key, keepOld)) return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700342 } else {
Paul Crowley4eac2642020-02-12 11:04:05 -0800343 if (!gen.allow_gen) {
Paul Crowley14c8c072018-09-18 13:30:21 -0700344 LOG(ERROR) << "No key found in " << key_path;
345 return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700346 }
347 LOG(INFO) << "Creating new key in " << key_path;
Paul Crowley4eac2642020-02-12 11:04:05 -0800348 if (!generateStorageKey(gen, key)) return false;
Paul Crowley77df7f22020-01-23 15:29:30 -0800349 if (!storeKeyAtomically(key_path, tmp_path, key_authentication, *key)) return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700350 }
351 return true;
352}
353
Paul Crowleyf71ace32016-06-02 11:01:19 -0700354} // namespace vold
355} // namespace android