123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- /*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "KeyUtil.h"
- #include <linux/fs.h>
- #include <iomanip>
- #include <sstream>
- #include <string>
- #include <openssl/sha.h>
- #include <android-base/file.h>
- #include <android-base/logging.h>
- #include <keyutils.h>
- #include "KeyStorage.h"
- #include "Utils.h"
- namespace android {
- namespace vold {
- constexpr int FS_AES_256_XTS_KEY_SIZE = 64;
- bool randomKey(KeyBuffer* key) {
- *key = KeyBuffer(FS_AES_256_XTS_KEY_SIZE);
- if (ReadRandomBytes(key->size(), key->data()) != 0) {
- // TODO status_t plays badly with PLOG, fix it.
- LOG(ERROR) << "Random read failed";
- return false;
- }
- return true;
- }
- // Get raw keyref - used to make keyname and to pass to ioctl
- static std::string generateKeyRef(const uint8_t* key, int length) {
- SHA512_CTX c;
- SHA512_Init(&c);
- SHA512_Update(&c, key, length);
- unsigned char key_ref1[SHA512_DIGEST_LENGTH];
- SHA512_Final(key_ref1, &c);
- SHA512_Init(&c);
- SHA512_Update(&c, key_ref1, SHA512_DIGEST_LENGTH);
- unsigned char key_ref2[SHA512_DIGEST_LENGTH];
- SHA512_Final(key_ref2, &c);
- static_assert(FS_KEY_DESCRIPTOR_SIZE <= SHA512_DIGEST_LENGTH, "Hash too short for descriptor");
- return std::string((char*)key_ref2, FS_KEY_DESCRIPTOR_SIZE);
- }
- static bool fillKey(const KeyBuffer& key, fscrypt_key* fs_key) {
- if (key.size() != FS_AES_256_XTS_KEY_SIZE) {
- LOG(ERROR) << "Wrong size key " << key.size();
- return false;
- }
- static_assert(FS_AES_256_XTS_KEY_SIZE <= sizeof(fs_key->raw), "Key too long!");
- fs_key->mode = FS_ENCRYPTION_MODE_AES_256_XTS;
- fs_key->size = key.size();
- memset(fs_key->raw, 0, sizeof(fs_key->raw));
- memcpy(fs_key->raw, key.data(), key.size());
- return true;
- }
- static char const* const NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt", nullptr};
- static std::string keyname(const std::string& prefix, const std::string& raw_ref) {
- std::ostringstream o;
- o << prefix << ":";
- for (unsigned char i : raw_ref) {
- o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
- }
- return o.str();
- }
- // Get the keyring we store all keys in
- static bool fscryptKeyring(key_serial_t* device_keyring) {
- *device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
- if (*device_keyring == -1) {
- PLOG(ERROR) << "Unable to find device keyring";
- return false;
- }
- return true;
- }
- // Install password into global keyring
- // Return raw key reference for use in policy
- bool installKey(const KeyBuffer& key, std::string* raw_ref) {
- // Place fscrypt_key into automatically zeroing buffer.
- KeyBuffer fsKeyBuffer(sizeof(fscrypt_key));
- fscrypt_key& fs_key = *reinterpret_cast<fscrypt_key*>(fsKeyBuffer.data());
- if (!fillKey(key, &fs_key)) return false;
- *raw_ref = generateKeyRef(fs_key.raw, fs_key.size);
- key_serial_t device_keyring;
- if (!fscryptKeyring(&device_keyring)) return false;
- for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
- auto ref = keyname(*name_prefix, *raw_ref);
- key_serial_t key_id =
- add_key("logon", ref.c_str(), (void*)&fs_key, sizeof(fs_key), device_keyring);
- if (key_id == -1) {
- PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
- return false;
- }
- LOG(DEBUG) << "Added key " << key_id << " (" << ref << ") to keyring " << device_keyring
- << " in process " << getpid();
- }
- return true;
- }
- bool evictKey(const std::string& raw_ref) {
- key_serial_t device_keyring;
- if (!fscryptKeyring(&device_keyring)) return false;
- bool success = true;
- for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
- auto ref = keyname(*name_prefix, raw_ref);
- auto key_serial = keyctl_search(device_keyring, "logon", ref.c_str(), 0);
- // Unlink the key from the keyring. Prefer unlinking to revoking or
- // invalidating, since unlinking is actually no less secure currently, and
- // it avoids bugs in certain kernel versions where the keyring key is
- // referenced from places it shouldn't be.
- if (keyctl_unlink(key_serial, device_keyring) != 0) {
- PLOG(ERROR) << "Failed to unlink key with serial " << key_serial << " ref " << ref;
- success = false;
- } else {
- LOG(DEBUG) << "Unlinked key with serial " << key_serial << " ref " << ref;
- }
- }
- return success;
- }
- bool retrieveAndInstallKey(bool create_if_absent, const KeyAuthentication& key_authentication,
- const std::string& key_path, const std::string& tmp_path,
- std::string* key_ref) {
- KeyBuffer key;
- if (pathExists(key_path)) {
- LOG(DEBUG) << "Key exists, using: " << key_path;
- if (!retrieveKey(key_path, key_authentication, &key)) return false;
- } else {
- if (!create_if_absent) {
- LOG(ERROR) << "No key found in " << key_path;
- return false;
- }
- LOG(INFO) << "Creating new key in " << key_path;
- if (!randomKey(&key)) return false;
- if (!storeKeyAtomically(key_path, tmp_path, key_authentication, key)) return false;
- }
- if (!installKey(key, key_ref)) {
- LOG(ERROR) << "Failed to install key in " << key_path;
- return false;
- }
- return true;
- }
- bool retrieveKey(bool create_if_absent, const std::string& key_path, const std::string& tmp_path,
- KeyBuffer* key, bool keepOld) {
- if (pathExists(key_path)) {
- LOG(DEBUG) << "Key exists, using: " << key_path;
- if (!retrieveKey(key_path, kEmptyAuthentication, key, keepOld)) return false;
- } else {
- if (!create_if_absent) {
- LOG(ERROR) << "No key found in " << key_path;
- return false;
- }
- LOG(INFO) << "Creating new key in " << key_path;
- if (!randomKey(key)) return false;
- if (!storeKeyAtomically(key_path, tmp_path, kEmptyAuthentication, *key)) return false;
- }
- return true;
- }
- } // namespace vold
- } // namespace android
|