• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
23 #include <fcntl.h>
24 #include <linux/fscrypt.h>
25 #include <openssl/sha.h>
26 #include <sys/ioctl.h>
27 
28 #include <android-base/file.h>
29 #include <android-base/logging.h>
30 #include <android-base/properties.h>
31 #include <keyutils.h>
32 
33 #include "KeyStorage.h"
34 #include "Utils.h"
35 
36 namespace android {
37 namespace vold {
38 
neverGen()39 const KeyGeneration neverGen() {
40     return KeyGeneration{0, false, false};
41 }
42 
randomKey(size_t size,KeyBuffer * key)43 static bool randomKey(size_t size, KeyBuffer* key) {
44     *key = KeyBuffer(size);
45     if (ReadRandomBytes(key->size(), key->data()) != 0) {
46         // TODO status_t plays badly with PLOG, fix it.
47         LOG(ERROR) << "Random read failed";
48         return false;
49     }
50     return true;
51 }
52 
generateStorageKey(const KeyGeneration & gen,KeyBuffer * key)53 bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key) {
54     if (!gen.allow_gen) return false;
55     if (gen.use_hw_wrapped_key) {
56         if (gen.keysize != FSCRYPT_MAX_KEY_SIZE) {
57             LOG(ERROR) << "Cannot generate a wrapped key " << gen.keysize << " bytes long";
58             return false;
59         }
60         LOG(DEBUG) << "Generating wrapped storage key";
61         return generateWrappedStorageKey(key);
62     } else {
63         LOG(DEBUG) << "Generating standard storage key";
64         return randomKey(gen.keysize, key);
65     }
66 }
67 
isFsKeyringSupportedImpl()68 static bool isFsKeyringSupportedImpl() {
69     android::base::unique_fd fd(open("/data", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
70 
71     // FS_IOC_ADD_ENCRYPTION_KEY with a NULL argument will fail with ENOTTY if
72     // the ioctl isn't supported.  Otherwise it will fail with another error
73     // code such as EFAULT.
74     //
75     // Note that there's no need to check for FS_IOC_REMOVE_ENCRYPTION_KEY,
76     // since it's guaranteed to be available if FS_IOC_ADD_ENCRYPTION_KEY is.
77     // There's also no need to check for support on external volumes separately
78     // from /data, since either the kernel supports the ioctls on all
79     // fscrypt-capable filesystems or it doesn't.
80     errno = 0;
81     (void)ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, NULL);
82     if (errno == ENOTTY) {
83         LOG(INFO) << "Kernel doesn't support FS_IOC_ADD_ENCRYPTION_KEY.  Falling back to "
84                      "session keyring";
85         return false;
86     }
87     if (errno != EFAULT) {
88         PLOG(WARNING) << "Unexpected error from FS_IOC_ADD_ENCRYPTION_KEY";
89     }
90     LOG(DEBUG) << "Detected support for FS_IOC_ADD_ENCRYPTION_KEY";
91     android::base::SetProperty("ro.crypto.uses_fs_ioc_add_encryption_key", "true");
92     return true;
93 }
94 
95 // Return true if the kernel supports the ioctls to add/remove fscrypt keys
96 // directly to/from the filesystem.
isFsKeyringSupported(void)97 bool isFsKeyringSupported(void) {
98     static bool supported = isFsKeyringSupportedImpl();
99     return supported;
100 }
101 
102 // Get raw keyref - used to make keyname and to pass to ioctl
generateKeyRef(const uint8_t * key,int length)103 static std::string generateKeyRef(const uint8_t* key, int length) {
104     SHA512_CTX c;
105 
106     SHA512_Init(&c);
107     SHA512_Update(&c, key, length);
108     unsigned char key_ref1[SHA512_DIGEST_LENGTH];
109     SHA512_Final(key_ref1, &c);
110 
111     SHA512_Init(&c);
112     SHA512_Update(&c, key_ref1, SHA512_DIGEST_LENGTH);
113     unsigned char key_ref2[SHA512_DIGEST_LENGTH];
114     SHA512_Final(key_ref2, &c);
115 
116     static_assert(FSCRYPT_KEY_DESCRIPTOR_SIZE <= SHA512_DIGEST_LENGTH,
117                   "Hash too short for descriptor");
118     return std::string((char*)key_ref2, FSCRYPT_KEY_DESCRIPTOR_SIZE);
119 }
120 
fillKey(const KeyBuffer & key,fscrypt_key * fs_key)121 static bool fillKey(const KeyBuffer& key, fscrypt_key* fs_key) {
122     if (key.size() != FSCRYPT_MAX_KEY_SIZE) {
123         LOG(ERROR) << "Wrong size key " << key.size();
124         return false;
125     }
126     static_assert(FSCRYPT_MAX_KEY_SIZE == sizeof(fs_key->raw), "Mismatch of max key sizes");
127     fs_key->mode = 0;  // unused by kernel
128     memcpy(fs_key->raw, key.data(), key.size());
129     fs_key->size = key.size();
130     return true;
131 }
132 
133 static char const* const NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt", nullptr};
134 
keyrefstring(const std::string & raw_ref)135 static std::string keyrefstring(const std::string& raw_ref) {
136     std::ostringstream o;
137     for (unsigned char i : raw_ref) {
138         o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
139     }
140     return o.str();
141 }
142 
buildLegacyKeyName(const std::string & prefix,const std::string & raw_ref)143 static std::string buildLegacyKeyName(const std::string& prefix, const std::string& raw_ref) {
144     return prefix + ":" + keyrefstring(raw_ref);
145 }
146 
147 // Get the ID of the keyring we store all fscrypt keys in when the kernel is too
148 // old to support FS_IOC_ADD_ENCRYPTION_KEY and FS_IOC_REMOVE_ENCRYPTION_KEY.
fscryptKeyring(key_serial_t * device_keyring)149 static bool fscryptKeyring(key_serial_t* device_keyring) {
150     *device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
151     if (*device_keyring == -1) {
152         PLOG(ERROR) << "Unable to find device keyring";
153         return false;
154     }
155     return true;
156 }
157 
158 // Add an encryption key of type "logon" to the global session keyring.
installKeyLegacy(const KeyBuffer & key,const std::string & raw_ref)159 static bool installKeyLegacy(const KeyBuffer& key, const std::string& raw_ref) {
160     // Place fscrypt_key into automatically zeroing buffer.
161     KeyBuffer fsKeyBuffer(sizeof(fscrypt_key));
162     fscrypt_key& fs_key = *reinterpret_cast<fscrypt_key*>(fsKeyBuffer.data());
163 
164     if (!fillKey(key, &fs_key)) return false;
165     key_serial_t device_keyring;
166     if (!fscryptKeyring(&device_keyring)) return false;
167     for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
168         auto ref = buildLegacyKeyName(*name_prefix, raw_ref);
169         key_serial_t key_id =
170             add_key("logon", ref.c_str(), (void*)&fs_key, sizeof(fs_key), device_keyring);
171         if (key_id == -1) {
172             PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
173             return false;
174         }
175         LOG(DEBUG) << "Added key " << key_id << " (" << ref << ") to keyring " << device_keyring
176                    << " in process " << getpid();
177     }
178     return true;
179 }
180 
181 // Installs fscrypt-provisioning key into session level kernel keyring.
182 // This allows for the given key to be installed back into filesystem keyring.
183 // For more context see reloadKeyFromSessionKeyring.
installProvisioningKey(const KeyBuffer & key,const std::string & ref,const fscrypt_key_specifier & key_spec)184 static bool installProvisioningKey(const KeyBuffer& key, const std::string& ref,
185                                    const fscrypt_key_specifier& key_spec) {
186     key_serial_t device_keyring;
187     if (!fscryptKeyring(&device_keyring)) return false;
188 
189     // Place fscrypt_provisioning_key_payload into automatically zeroing buffer.
190     KeyBuffer buf(sizeof(fscrypt_provisioning_key_payload) + key.size(), 0);
191     fscrypt_provisioning_key_payload& provisioning_key =
192             *reinterpret_cast<fscrypt_provisioning_key_payload*>(buf.data());
193     memcpy(provisioning_key.raw, key.data(), key.size());
194     provisioning_key.type = key_spec.type;
195 
196     key_serial_t key_id = add_key("fscrypt-provisioning", ref.c_str(), (void*)&provisioning_key,
197                                   buf.size(), device_keyring);
198     if (key_id == -1) {
199         PLOG(ERROR) << "Failed to insert fscrypt-provisioning key for " << ref
200                     << " into session keyring";
201         return false;
202     }
203     LOG(DEBUG) << "Added fscrypt-provisioning key for " << ref << " to session keyring";
204     return true;
205 }
206 
207 // Build a struct fscrypt_key_specifier for use in the key management ioctls.
buildKeySpecifier(fscrypt_key_specifier * spec,const EncryptionPolicy & policy)208 static bool buildKeySpecifier(fscrypt_key_specifier* spec, const EncryptionPolicy& policy) {
209     switch (policy.options.version) {
210         case 1:
211             if (policy.key_raw_ref.size() != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
212                 LOG(ERROR) << "Invalid key specifier size for v1 encryption policy: "
213                            << policy.key_raw_ref.size();
214                 return false;
215             }
216             spec->type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
217             memcpy(spec->u.descriptor, policy.key_raw_ref.c_str(), FSCRYPT_KEY_DESCRIPTOR_SIZE);
218             return true;
219         case 2:
220             if (policy.key_raw_ref.size() != FSCRYPT_KEY_IDENTIFIER_SIZE) {
221                 LOG(ERROR) << "Invalid key specifier size for v2 encryption policy: "
222                            << policy.key_raw_ref.size();
223                 return false;
224             }
225             spec->type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
226             memcpy(spec->u.identifier, policy.key_raw_ref.c_str(), FSCRYPT_KEY_IDENTIFIER_SIZE);
227             return true;
228         default:
229             LOG(ERROR) << "Invalid encryption policy version: " << policy.options.version;
230             return false;
231     }
232 }
233 
234 // Installs key into keyring of a filesystem mounted on |mountpoint|.
235 //
236 // It's callers responsibility to fill key specifier, and either arg->raw or arg->key_id.
237 //
238 // In case arg->key_spec.type equals to FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER
239 // arg->key_spec.u.identifier will be populated with raw key reference generated
240 // by kernel.
241 //
242 // For documentation on difference between arg->raw and arg->key_id see
243 // https://www.kernel.org/doc/html/latest/filesystems/fscrypt.html#fs-ioc-add-encryption-key
installFsKeyringKey(const std::string & mountpoint,const EncryptionOptions & options,fscrypt_add_key_arg * arg)244 static bool installFsKeyringKey(const std::string& mountpoint, const EncryptionOptions& options,
245                                 fscrypt_add_key_arg* arg) {
246     if (options.use_hw_wrapped_key) arg->__flags |= __FSCRYPT_ADD_KEY_FLAG_HW_WRAPPED;
247 
248     android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
249     if (fd == -1) {
250         PLOG(ERROR) << "Failed to open " << mountpoint << " to install key";
251         return false;
252     }
253 
254     if (ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, arg) != 0) {
255         PLOG(ERROR) << "Failed to install fscrypt key to " << mountpoint;
256         return false;
257     }
258 
259     return true;
260 }
261 
installKey(const std::string & mountpoint,const EncryptionOptions & options,const KeyBuffer & key,EncryptionPolicy * policy)262 bool installKey(const std::string& mountpoint, const EncryptionOptions& options,
263                 const KeyBuffer& key, EncryptionPolicy* policy) {
264     policy->options = options;
265     // Put the fscrypt_add_key_arg in an automatically-zeroing buffer, since we
266     // have to copy the raw key into it.
267     KeyBuffer arg_buf(sizeof(struct fscrypt_add_key_arg) + key.size(), 0);
268     struct fscrypt_add_key_arg* arg = (struct fscrypt_add_key_arg*)arg_buf.data();
269 
270     // Initialize the "key specifier", which is like a name for the key.
271     switch (options.version) {
272         case 1:
273             // A key for a v1 policy is specified by an arbitrary 8-byte
274             // "descriptor", which must be provided by userspace.  We use the
275             // first 8 bytes from the double SHA-512 of the key itself.
276             policy->key_raw_ref = generateKeyRef((const uint8_t*)key.data(), key.size());
277             if (!isFsKeyringSupported()) {
278                 return installKeyLegacy(key, policy->key_raw_ref);
279             }
280             if (!buildKeySpecifier(&arg->key_spec, *policy)) {
281                 return false;
282             }
283             break;
284         case 2:
285             // A key for a v2 policy is specified by an 16-byte "identifier",
286             // which is a cryptographic hash of the key itself which the kernel
287             // computes and returns.  Any user-provided value is ignored; we
288             // just need to set the specifier type to indicate that we're adding
289             // this type of key.
290             arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
291             break;
292         default:
293             LOG(ERROR) << "Invalid encryption policy version: " << options.version;
294             return false;
295     }
296 
297     arg->raw_size = key.size();
298     memcpy(arg->raw, key.data(), key.size());
299 
300     if (!installFsKeyringKey(mountpoint, options, arg)) return false;
301 
302     if (arg->key_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
303         // Retrieve the key identifier that the kernel computed.
304         policy->key_raw_ref =
305                 std::string((char*)arg->key_spec.u.identifier, FSCRYPT_KEY_IDENTIFIER_SIZE);
306     }
307     std::string ref = keyrefstring(policy->key_raw_ref);
308     LOG(DEBUG) << "Installed fscrypt key with ref " << ref << " to " << mountpoint;
309 
310     if (!installProvisioningKey(key, ref, arg->key_spec)) return false;
311     return true;
312 }
313 
314 // Remove an encryption key of type "logon" from the global session keyring.
evictKeyLegacy(const std::string & raw_ref)315 static bool evictKeyLegacy(const std::string& raw_ref) {
316     key_serial_t device_keyring;
317     if (!fscryptKeyring(&device_keyring)) return false;
318     bool success = true;
319     for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
320         auto ref = buildLegacyKeyName(*name_prefix, raw_ref);
321         auto key_serial = keyctl_search(device_keyring, "logon", ref.c_str(), 0);
322 
323         // Unlink the key from the keyring.  Prefer unlinking to revoking or
324         // invalidating, since unlinking is actually no less secure currently, and
325         // it avoids bugs in certain kernel versions where the keyring key is
326         // referenced from places it shouldn't be.
327         if (keyctl_unlink(key_serial, device_keyring) != 0) {
328             PLOG(ERROR) << "Failed to unlink key with serial " << key_serial << " ref " << ref;
329             success = false;
330         } else {
331             LOG(DEBUG) << "Unlinked key with serial " << key_serial << " ref " << ref;
332         }
333     }
334     return success;
335 }
336 
evictProvisioningKey(const std::string & ref)337 static bool evictProvisioningKey(const std::string& ref) {
338     key_serial_t device_keyring;
339     if (!fscryptKeyring(&device_keyring)) {
340         return false;
341     }
342 
343     auto key_serial = keyctl_search(device_keyring, "fscrypt-provisioning", ref.c_str(), 0);
344     if (key_serial == -1 && errno != ENOKEY) {
345         PLOG(ERROR) << "Error searching session keyring for fscrypt-provisioning key for " << ref;
346         return false;
347     }
348 
349     if (key_serial != -1 && keyctl_unlink(key_serial, device_keyring) != 0) {
350         PLOG(ERROR) << "Failed to unlink fscrypt-provisioning key for " << ref
351                     << " from session keyring";
352         return false;
353     }
354     return true;
355 }
356 
evictKey(const std::string & mountpoint,const EncryptionPolicy & policy)357 bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) {
358     if (policy.options.version == 1 && !isFsKeyringSupported()) {
359         return evictKeyLegacy(policy.key_raw_ref);
360     }
361 
362     android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
363     if (fd == -1) {
364         PLOG(ERROR) << "Failed to open " << mountpoint << " to evict key";
365         return false;
366     }
367 
368     struct fscrypt_remove_key_arg arg;
369     memset(&arg, 0, sizeof(arg));
370 
371     if (!buildKeySpecifier(&arg.key_spec, policy)) {
372         return false;
373     }
374 
375     std::string ref = keyrefstring(policy.key_raw_ref);
376 
377     if (ioctl(fd, FS_IOC_REMOVE_ENCRYPTION_KEY, &arg) != 0) {
378         PLOG(ERROR) << "Failed to evict fscrypt key with ref " << ref << " from " << mountpoint;
379         return false;
380     }
381 
382     LOG(DEBUG) << "Evicted fscrypt key with ref " << ref << " from " << mountpoint;
383     if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_OTHER_USERS) {
384         // Should never happen because keys are only added/removed as root.
385         LOG(ERROR) << "Unexpected case: key with ref " << ref << " is still added by other users!";
386     } else if (arg.removal_status_flags & FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY) {
387         LOG(ERROR) << "Files still open after removing key with ref " << ref
388                    << ".  These files were not locked!";
389     }
390 
391     if (!evictProvisioningKey(ref)) return false;
392     return true;
393 }
394 
retrieveOrGenerateKey(const std::string & key_path,const std::string & tmp_path,const KeyAuthentication & key_authentication,const KeyGeneration & gen,KeyBuffer * key)395 bool retrieveOrGenerateKey(const std::string& key_path, const std::string& tmp_path,
396                            const KeyAuthentication& key_authentication, const KeyGeneration& gen,
397                            KeyBuffer* key) {
398     if (pathExists(key_path)) {
399         LOG(DEBUG) << "Key exists, using: " << key_path;
400         if (!retrieveKey(key_path, key_authentication, key)) return false;
401     } else {
402         if (!gen.allow_gen) {
403             LOG(ERROR) << "No key found in " << key_path;
404             return false;
405         }
406         LOG(INFO) << "Creating new key in " << key_path;
407         if (!generateStorageKey(gen, key)) return false;
408         if (!storeKeyAtomically(key_path, tmp_path, key_authentication, *key)) return false;
409     }
410     return true;
411 }
412 
reloadKeyFromSessionKeyring(const std::string & mountpoint,const EncryptionPolicy & policy)413 bool reloadKeyFromSessionKeyring(const std::string& mountpoint, const EncryptionPolicy& policy) {
414     key_serial_t device_keyring;
415     if (!fscryptKeyring(&device_keyring)) {
416         return false;
417     }
418 
419     std::string ref = keyrefstring(policy.key_raw_ref);
420     auto key_serial = keyctl_search(device_keyring, "fscrypt-provisioning", ref.c_str(), 0);
421     if (key_serial == -1) {
422         PLOG(ERROR) << "Failed to find fscrypt-provisioning key for " << ref
423                     << " in session keyring";
424         return false;
425     }
426 
427     LOG(DEBUG) << "Installing fscrypt-provisioning key for " << ref << " back into " << mountpoint
428                << " fs-keyring";
429 
430     struct fscrypt_add_key_arg arg;
431     memset(&arg, 0, sizeof(arg));
432     if (!buildKeySpecifier(&arg.key_spec, policy)) return false;
433     arg.key_id = key_serial;
434     if (!installFsKeyringKey(mountpoint, policy.options, &arg)) return false;
435 
436     return true;
437 }
438 
439 }  // namespace vold
440 }  // namespace android
441