blob: 79a5102d38bdcdd22f7bd5db1dc7e1095f802d19 [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
32#include "KeyStorage.h"
33#include "Utils.h"
34
35namespace android {
36namespace vold {
37
Eric Biggersa701c452018-10-23 13:06:55 -070038constexpr int FS_AES_256_XTS_KEY_SIZE = 64;
Pavel Grafove2e2d302017-08-01 17:15:53 +010039
40bool randomKey(KeyBuffer* key) {
Eric Biggersa701c452018-10-23 13:06:55 -070041 *key = KeyBuffer(FS_AES_256_XTS_KEY_SIZE);
Pavel Grafove2e2d302017-08-01 17:15:53 +010042 if (ReadRandomBytes(key->size(), key->data()) != 0) {
Paul Crowleyf71ace32016-06-02 11:01:19 -070043 // TODO status_t plays badly with PLOG, fix it.
44 LOG(ERROR) << "Random read failed";
45 return false;
46 }
47 return true;
48}
49
Eric Biggersf3dc4202019-09-30 13:05:58 -070050// Return true if the kernel supports the ioctls to add/remove fscrypt keys
51// directly to/from the filesystem.
52bool isFsKeyringSupported(void) {
53 static bool initialized = false;
54 static bool supported;
55
56 if (!initialized) {
57 android::base::unique_fd fd(open("/data", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
58
59 // FS_IOC_ADD_ENCRYPTION_KEY with a NULL argument will fail with ENOTTY
60 // if the ioctl isn't supported. Otherwise it will fail with another
61 // error code such as EFAULT.
62 errno = 0;
63 (void)ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, NULL);
64 if (errno == ENOTTY) {
65 LOG(INFO) << "Kernel doesn't support FS_IOC_ADD_ENCRYPTION_KEY. Falling back to "
66 "session keyring";
67 supported = false;
68 } else {
69 if (errno != EFAULT) {
70 PLOG(WARNING) << "Unexpected error from FS_IOC_ADD_ENCRYPTION_KEY";
71 }
72 LOG(DEBUG) << "Detected support for FS_IOC_ADD_ENCRYPTION_KEY";
73 supported = true;
74 }
75 // There's no need to check for FS_IOC_REMOVE_ENCRYPTION_KEY, since it's
76 // guaranteed to be available if FS_IOC_ADD_ENCRYPTION_KEY is. There's
77 // also no need to check for support on external volumes separately from
78 // /data, since either the kernel supports the ioctls on all
79 // fscrypt-capable filesystems or it doesn't.
80
81 initialized = true;
82 }
83 return supported;
84}
85
Paul Crowleyf71ace32016-06-02 11:01:19 -070086// Get raw keyref - used to make keyname and to pass to ioctl
Eric Biggersba997ee2018-10-23 13:07:43 -070087static std::string generateKeyRef(const uint8_t* key, int length) {
Paul Crowleyf71ace32016-06-02 11:01:19 -070088 SHA512_CTX c;
89
90 SHA512_Init(&c);
91 SHA512_Update(&c, key, length);
92 unsigned char key_ref1[SHA512_DIGEST_LENGTH];
93 SHA512_Final(key_ref1, &c);
94
95 SHA512_Init(&c);
96 SHA512_Update(&c, key_ref1, SHA512_DIGEST_LENGTH);
97 unsigned char key_ref2[SHA512_DIGEST_LENGTH];
98 SHA512_Final(key_ref2, &c);
99
Eric Biggersa701c452018-10-23 13:06:55 -0700100 static_assert(FS_KEY_DESCRIPTOR_SIZE <= SHA512_DIGEST_LENGTH, "Hash too short for descriptor");
101 return std::string((char*)key_ref2, FS_KEY_DESCRIPTOR_SIZE);
Paul Crowleyf71ace32016-06-02 11:01:19 -0700102}
103
Eric Biggersa701c452018-10-23 13:06:55 -0700104static bool fillKey(const KeyBuffer& key, fscrypt_key* fs_key) {
105 if (key.size() != FS_AES_256_XTS_KEY_SIZE) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700106 LOG(ERROR) << "Wrong size key " << key.size();
107 return false;
108 }
Eric Biggersa701c452018-10-23 13:06:55 -0700109 static_assert(FS_AES_256_XTS_KEY_SIZE <= sizeof(fs_key->raw), "Key too long!");
110 fs_key->mode = FS_ENCRYPTION_MODE_AES_256_XTS;
111 fs_key->size = key.size();
112 memset(fs_key->raw, 0, sizeof(fs_key->raw));
113 memcpy(fs_key->raw, key.data(), key.size());
Paul Crowleyf71ace32016-06-02 11:01:19 -0700114 return true;
115}
116
Paul Crowley14c8c072018-09-18 13:30:21 -0700117static char const* const NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt", nullptr};
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700118
Eric Biggersf3dc4202019-09-30 13:05:58 -0700119static std::string keyrefstring(const std::string& raw_ref) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700120 std::ostringstream o;
Chen, Luhai5744dfe2017-08-18 14:49:45 +0800121 for (unsigned char i : raw_ref) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700122 o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
123 }
124 return o.str();
125}
126
Eric Biggersf3dc4202019-09-30 13:05:58 -0700127static std::string buildLegacyKeyName(const std::string& prefix, const std::string& raw_ref) {
128 return prefix + ":" + keyrefstring(raw_ref);
129}
130
131// Get the ID of the keyring we store all fscrypt keys in when the kernel is too
132// old to support FS_IOC_ADD_ENCRYPTION_KEY and FS_IOC_REMOVE_ENCRYPTION_KEY.
Eric Biggersa701c452018-10-23 13:06:55 -0700133static bool fscryptKeyring(key_serial_t* device_keyring) {
134 *device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
Paul Crowleyf71ace32016-06-02 11:01:19 -0700135 if (*device_keyring == -1) {
136 PLOG(ERROR) << "Unable to find device keyring";
137 return false;
138 }
139 return true;
140}
141
Eric Biggersf3dc4202019-09-30 13:05:58 -0700142// Add an encryption key to the legacy global session keyring.
143static bool installKeyLegacy(const KeyBuffer& key, const std::string& raw_ref) {
Eric Biggersa701c452018-10-23 13:06:55 -0700144 // Place fscrypt_key into automatically zeroing buffer.
145 KeyBuffer fsKeyBuffer(sizeof(fscrypt_key));
146 fscrypt_key& fs_key = *reinterpret_cast<fscrypt_key*>(fsKeyBuffer.data());
Pavel Grafove2e2d302017-08-01 17:15:53 +0100147
Eric Biggersa701c452018-10-23 13:06:55 -0700148 if (!fillKey(key, &fs_key)) return false;
Paul Crowleyf71ace32016-06-02 11:01:19 -0700149 key_serial_t device_keyring;
Eric Biggersa701c452018-10-23 13:06:55 -0700150 if (!fscryptKeyring(&device_keyring)) return false;
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700151 for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
Eric Biggersf3dc4202019-09-30 13:05:58 -0700152 auto ref = buildLegacyKeyName(*name_prefix, raw_ref);
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700153 key_serial_t key_id =
Eric Biggersa701c452018-10-23 13:06:55 -0700154 add_key("logon", ref.c_str(), (void*)&fs_key, sizeof(fs_key), device_keyring);
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700155 if (key_id == -1) {
156 PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
157 return false;
158 }
159 LOG(DEBUG) << "Added key " << key_id << " (" << ref << ") to keyring " << device_keyring
160 << " in process " << getpid();
Paul Crowleyf71ace32016-06-02 11:01:19 -0700161 }
Paul Crowleyf71ace32016-06-02 11:01:19 -0700162 return true;
163}
164
Eric Biggers83a73d72019-09-30 13:06:47 -0700165// Build a struct fscrypt_key_specifier for use in the key management ioctls.
166static bool buildKeySpecifier(fscrypt_key_specifier* spec, const std::string& raw_ref,
167 int policy_version) {
168 switch (policy_version) {
169 case 1:
170 if (raw_ref.size() != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
171 LOG(ERROR) << "Invalid key specifier size for v1 encryption policy: "
172 << raw_ref.size();
173 return false;
174 }
175 spec->type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
176 memcpy(spec->u.descriptor, raw_ref.c_str(), FSCRYPT_KEY_DESCRIPTOR_SIZE);
177 return true;
178 case 2:
179 if (raw_ref.size() != FSCRYPT_KEY_IDENTIFIER_SIZE) {
180 LOG(ERROR) << "Invalid key specifier size for v2 encryption policy: "
181 << raw_ref.size();
182 return false;
183 }
184 spec->type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
185 memcpy(spec->u.identifier, raw_ref.c_str(), FSCRYPT_KEY_IDENTIFIER_SIZE);
186 return true;
187 default:
188 LOG(ERROR) << "Invalid encryption policy version: " << policy_version;
189 return false;
190 }
191}
192
Eric Biggersf3dc4202019-09-30 13:05:58 -0700193// Install a file-based encryption key to the kernel, for use by encrypted files
Eric Biggers83a73d72019-09-30 13:06:47 -0700194// on the specified filesystem using the specified encryption policy version.
Eric Biggersf3dc4202019-09-30 13:05:58 -0700195//
Eric Biggers83a73d72019-09-30 13:06:47 -0700196// For v1 policies, we use FS_IOC_ADD_ENCRYPTION_KEY if the kernel supports it.
197// Otherwise we add the key to the legacy global session keyring.
198//
199// For v2 policies, we always use FS_IOC_ADD_ENCRYPTION_KEY; it's the only way
200// the kernel supports.
Eric Biggersf3dc4202019-09-30 13:05:58 -0700201//
202// Returns %true on success, %false on failure. On success also sets *raw_ref
203// to the raw key reference for use in the encryption policy.
Eric Biggers83a73d72019-09-30 13:06:47 -0700204bool installKey(const KeyBuffer& key, const std::string& mountpoint, int policy_version,
205 std::string* raw_ref) {
Eric Biggersf3dc4202019-09-30 13:05:58 -0700206 // Put the fscrypt_add_key_arg in an automatically-zeroing buffer, since we
207 // have to copy the raw key into it.
208 KeyBuffer arg_buf(sizeof(struct fscrypt_add_key_arg) + key.size(), 0);
209 struct fscrypt_add_key_arg* arg = (struct fscrypt_add_key_arg*)arg_buf.data();
210
Eric Biggers83a73d72019-09-30 13:06:47 -0700211 // Initialize the "key specifier", which is like a name for the key.
212 switch (policy_version) {
213 case 1:
214 // A key for a v1 policy is specified by an arbitrary 8-byte
215 // "descriptor", which must be provided by userspace. We use the
216 // first 8 bytes from the double SHA-512 of the key itself.
217 *raw_ref = generateKeyRef((const uint8_t*)key.data(), key.size());
218 if (!isFsKeyringSupported()) {
219 return installKeyLegacy(key, *raw_ref);
220 }
221 if (!buildKeySpecifier(&arg->key_spec, *raw_ref, policy_version)) {
222 return false;
223 }
224 break;
225 case 2:
226 // A key for a v2 policy is specified by an 16-byte "identifier",
227 // which is a cryptographic hash of the key itself which the kernel
228 // computes and returns. Any user-provided value is ignored; we
229 // just need to set the specifier type to indicate that we're adding
230 // this type of key.
231 arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
232 break;
233 default:
234 LOG(ERROR) << "Invalid encryption policy version: " << policy_version;
235 return false;
236 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700237
Eric Biggers83a73d72019-09-30 13:06:47 -0700238 // Provide the raw key.
Eric Biggersf3dc4202019-09-30 13:05:58 -0700239 arg->raw_size = key.size();
240 memcpy(arg->raw, key.data(), key.size());
241
242 android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
243 if (fd == -1) {
244 PLOG(ERROR) << "Failed to open " << mountpoint << " to install key";
245 return false;
246 }
247
248 if (ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, arg) != 0) {
Eric Biggers83a73d72019-09-30 13:06:47 -0700249 PLOG(ERROR) << "Failed to install fscrypt key to " << mountpoint;
Eric Biggersf3dc4202019-09-30 13:05:58 -0700250 return false;
251 }
252
Eric Biggers83a73d72019-09-30 13:06:47 -0700253 if (arg->key_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
254 // Retrieve the key identifier that the kernel computed.
255 *raw_ref = std::string((char*)arg->key_spec.u.identifier, FSCRYPT_KEY_IDENTIFIER_SIZE);
256 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700257 LOG(DEBUG) << "Installed fscrypt key with ref " << keyrefstring(*raw_ref) << " to "
258 << mountpoint;
259 return true;
260}
261
262// Remove an encryption key from the legacy global session keyring.
263static bool evictKeyLegacy(const std::string& raw_ref) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700264 key_serial_t device_keyring;
Eric Biggersa701c452018-10-23 13:06:55 -0700265 if (!fscryptKeyring(&device_keyring)) return false;
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700266 bool success = true;
267 for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
Eric Biggersf3dc4202019-09-30 13:05:58 -0700268 auto ref = buildLegacyKeyName(*name_prefix, raw_ref);
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700269 auto key_serial = keyctl_search(device_keyring, "logon", ref.c_str(), 0);
Paul Crowleyf71ace32016-06-02 11:01:19 -0700270
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700271 // Unlink the key from the keyring. Prefer unlinking to revoking or
272 // invalidating, since unlinking is actually no less secure currently, and
273 // it avoids bugs in certain kernel versions where the keyring key is
274 // referenced from places it shouldn't be.
275 if (keyctl_unlink(key_serial, device_keyring) != 0) {
276 PLOG(ERROR) << "Failed to unlink key with serial " << key_serial << " ref " << ref;
277 success = false;
278 } else {
279 LOG(DEBUG) << "Unlinked key with serial " << key_serial << " ref " << ref;
280 }
Paul Crowleyf71ace32016-06-02 11:01:19 -0700281 }
Paul Crowleycd8bfe32017-06-19 16:05:55 -0700282 return success;
Paul Crowleyf71ace32016-06-02 11:01:19 -0700283}
284
Eric Biggersf3dc4202019-09-30 13:05:58 -0700285// Evict a file-based encryption key from the kernel.
286//
287// We use FS_IOC_REMOVE_ENCRYPTION_KEY if the kernel supports it. Otherwise we
288// remove the key from the legacy global session keyring.
289//
290// In the latter case, the caller is responsible for dropping caches.
Eric Biggers83a73d72019-09-30 13:06:47 -0700291bool evictKey(const std::string& mountpoint, const std::string& raw_ref, int policy_version) {
292 if (policy_version == 1 && !isFsKeyringSupported()) {
Eric Biggersf3dc4202019-09-30 13:05:58 -0700293 return evictKeyLegacy(raw_ref);
294 }
295
296 android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
297 if (fd == -1) {
298 PLOG(ERROR) << "Failed to open " << mountpoint << " to evict key";
299 return false;
300 }
301
302 struct fscrypt_remove_key_arg arg;
303 memset(&arg, 0, sizeof(arg));
304
Eric Biggers83a73d72019-09-30 13:06:47 -0700305 if (!buildKeySpecifier(&arg.key_spec, raw_ref, policy_version)) {
306 return false;
307 }
Eric Biggersf3dc4202019-09-30 13:05:58 -0700308
309 std::string ref = keyrefstring(raw_ref);
310
311 if (ioctl(fd, FS_IOC_REMOVE_ENCRYPTION_KEY, &arg) != 0) {
312 PLOG(ERROR) << "Failed to evict fscrypt key with ref " << ref << " from " << mountpoint;
313 return false;
314 }
315
316 LOG(DEBUG) << "Evicted fscrypt key with ref " << ref << " from " << mountpoint;
317 if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS) {
318 // Should never happen because keys are only added/removed as root.
319 LOG(ERROR) << "Unexpected case: key with ref " << ref << " is still added by other users!";
320 } else if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY) {
321 LOG(ERROR) << "Files still open after removing key with ref " << ref
322 << ". These files were not locked!";
323 }
324 return true;
325}
326
Paul Crowley26a53882017-10-26 11:16:39 -0700327bool retrieveAndInstallKey(bool create_if_absent, const KeyAuthentication& key_authentication,
328 const std::string& key_path, const std::string& tmp_path,
Eric Biggers83a73d72019-09-30 13:06:47 -0700329 const std::string& volume_uuid, int policy_version,
330 std::string* key_ref) {
Pavel Grafove2e2d302017-08-01 17:15:53 +0100331 KeyBuffer key;
Paul Crowleyf71ace32016-06-02 11:01:19 -0700332 if (pathExists(key_path)) {
333 LOG(DEBUG) << "Key exists, using: " << key_path;
Paul Crowley26a53882017-10-26 11:16:39 -0700334 if (!retrieveKey(key_path, key_authentication, &key)) return false;
Paul Crowleyf71ace32016-06-02 11:01:19 -0700335 } else {
336 if (!create_if_absent) {
Paul Crowley14c8c072018-09-18 13:30:21 -0700337 LOG(ERROR) << "No key found in " << key_path;
338 return false;
Paul Crowleyf71ace32016-06-02 11:01:19 -0700339 }
340 LOG(INFO) << "Creating new key in " << key_path;
341 if (!randomKey(&key)) return false;
Paul Crowley26a53882017-10-26 11:16:39 -0700342 if (!storeKeyAtomically(key_path, tmp_path, key_authentication, key)) return false;
Paul Crowleyf71ace32016-06-02 11:01:19 -0700343 }
344
Eric Biggers83a73d72019-09-30 13:06:47 -0700345 if (!installKey(key, BuildDataPath(volume_uuid), policy_version, key_ref)) {
Paul Crowleyf71ace32016-06-02 11:01:19 -0700346 LOG(ERROR) << "Failed to install key in " << key_path;
347 return false;
348 }
349 return true;
350}
351
Paul Crowley14c8c072018-09-18 13:30:21 -0700352bool retrieveKey(bool create_if_absent, const std::string& key_path, const std::string& tmp_path,
Daniel Rosenberg690d6de2018-12-14 01:08:10 -0800353 KeyBuffer* key, bool keepOld) {
Paul Crowleyd5759812016-06-02 11:04:27 -0700354 if (pathExists(key_path)) {
355 LOG(DEBUG) << "Key exists, using: " << key_path;
Daniel Rosenberg690d6de2018-12-14 01:08:10 -0800356 if (!retrieveKey(key_path, kEmptyAuthentication, key, keepOld)) return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700357 } else {
358 if (!create_if_absent) {
Paul Crowley14c8c072018-09-18 13:30:21 -0700359 LOG(ERROR) << "No key found in " << key_path;
360 return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700361 }
362 LOG(INFO) << "Creating new key in " << key_path;
363 if (!randomKey(key)) return false;
Paul Crowley14c8c072018-09-18 13:30:21 -0700364 if (!storeKeyAtomically(key_path, tmp_path, kEmptyAuthentication, *key)) return false;
Paul Crowleyd5759812016-06-02 11:04:27 -0700365 }
366 return true;
367}
368
Paul Crowleyf71ace32016-06-02 11:01:19 -0700369} // namespace vold
370} // namespace android