blob: 91d6b37d66e232446974534865d2e035bf801ec8 [file] [log] [blame]
bigbiff7ba75002020-04-11 20:47:09 -04001/*
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 <linux/fs.h>
20#include <iomanip>
21#include <sstream>
22#include <string>
23
24#include <openssl/sha.h>
25
26#include <android-base/file.h>
27#include <android-base/logging.h>
28#include <keyutils.h>
29
30#include "KeyStorage.h"
31#include "Utils.h"
32
33namespace android {
34namespace vold {
35
36constexpr int FS_AES_256_XTS_KEY_SIZE = 64;
37
38bool randomKey(KeyBuffer* key) {
39 *key = KeyBuffer(FS_AES_256_XTS_KEY_SIZE);
40 if (ReadRandomBytes(key->size(), key->data()) != 0) {
41 // TODO status_t plays badly with PLOG, fix it.
42 LOG(ERROR) << "Random read failed";
43 return false;
44 }
45 return true;
46}
47
48// Get raw keyref - used to make keyname and to pass to ioctl
49static std::string generateKeyRef(const uint8_t* key, int length) {
50 SHA512_CTX c;
51
52 SHA512_Init(&c);
53 SHA512_Update(&c, key, length);
54 unsigned char key_ref1[SHA512_DIGEST_LENGTH];
55 SHA512_Final(key_ref1, &c);
56
57 SHA512_Init(&c);
58 SHA512_Update(&c, key_ref1, SHA512_DIGEST_LENGTH);
59 unsigned char key_ref2[SHA512_DIGEST_LENGTH];
60 SHA512_Final(key_ref2, &c);
61
62 static_assert(FS_KEY_DESCRIPTOR_SIZE <= SHA512_DIGEST_LENGTH, "Hash too short for descriptor");
63 return std::string((char*)key_ref2, FS_KEY_DESCRIPTOR_SIZE);
64}
65
66static bool fillKey(const KeyBuffer& key, fscrypt_key* fs_key) {
67 if (key.size() != FS_AES_256_XTS_KEY_SIZE) {
68 LOG(ERROR) << "Wrong size key " << key.size();
69 return false;
70 }
71 static_assert(FS_AES_256_XTS_KEY_SIZE <= sizeof(fs_key->raw), "Key too long!");
72 fs_key->mode = FS_ENCRYPTION_MODE_AES_256_XTS;
73 fs_key->size = key.size();
74 memset(fs_key->raw, 0, sizeof(fs_key->raw));
75 memcpy(fs_key->raw, key.data(), key.size());
76 return true;
77}
78
79static char const* const NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt", nullptr};
80
81static std::string keyname(const std::string& prefix, const std::string& raw_ref) {
82 std::ostringstream o;
83 o << prefix << ":";
84 for (unsigned char i : raw_ref) {
85 o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
86 }
87 return o.str();
88}
89
90// Get the keyring we store all keys in
91static bool fscryptKeyring(key_serial_t* device_keyring) {
92 *device_keyring = keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
93 if (*device_keyring == -1) {
94 PLOG(ERROR) << "Unable to find device keyring";
95 return false;
96 }
97 return true;
98}
99
100// Install password into global keyring
101// Return raw key reference for use in policy
102bool installKey(const KeyBuffer& key, std::string* raw_ref) {
103 // Place fscrypt_key into automatically zeroing buffer.
104 KeyBuffer fsKeyBuffer(sizeof(fscrypt_key));
105 fscrypt_key& fs_key = *reinterpret_cast<fscrypt_key*>(fsKeyBuffer.data());
106
107 if (!fillKey(key, &fs_key)) return false;
108 *raw_ref = generateKeyRef(fs_key.raw, fs_key.size);
109 key_serial_t device_keyring;
110 if (!fscryptKeyring(&device_keyring)) return false;
111 for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
112 auto ref = keyname(*name_prefix, *raw_ref);
113 key_serial_t key_id =
114 add_key("logon", ref.c_str(), (void*)&fs_key, sizeof(fs_key), device_keyring);
115 if (key_id == -1) {
116 PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
117 return false;
118 }
119 LOG(DEBUG) << "Added key " << key_id << " (" << ref << ") to keyring " << device_keyring
120 << " in process " << getpid();
121 }
122 return true;
123}
124
125bool evictKey(const std::string& raw_ref) {
126 key_serial_t device_keyring;
127 if (!fscryptKeyring(&device_keyring)) return false;
128 bool success = true;
129 for (char const* const* name_prefix = NAME_PREFIXES; *name_prefix != nullptr; name_prefix++) {
130 auto ref = keyname(*name_prefix, raw_ref);
131 auto key_serial = keyctl_search(device_keyring, "logon", ref.c_str(), 0);
132
133 // Unlink the key from the keyring. Prefer unlinking to revoking or
134 // invalidating, since unlinking is actually no less secure currently, and
135 // it avoids bugs in certain kernel versions where the keyring key is
136 // referenced from places it shouldn't be.
137 if (keyctl_unlink(key_serial, device_keyring) != 0) {
138 PLOG(ERROR) << "Failed to unlink key with serial " << key_serial << " ref " << ref;
139 success = false;
140 } else {
141 LOG(DEBUG) << "Unlinked key with serial " << key_serial << " ref " << ref;
142 }
143 }
144 return success;
145}
146
147bool retrieveAndInstallKey(bool create_if_absent, const KeyAuthentication& key_authentication,
148 const std::string& key_path, const std::string& tmp_path,
149 std::string* key_ref) {
150 KeyBuffer key;
151 if (pathExists(key_path)) {
152 LOG(DEBUG) << "Key exists, using: " << key_path;
153 if (!retrieveKey(key_path, key_authentication, &key)) return false;
154 } else {
155 if (!create_if_absent) {
156 LOG(ERROR) << "No key found in " << key_path;
157 return false;
158 }
159 LOG(INFO) << "Creating new key in " << key_path;
160 if (!randomKey(&key)) return false;
161 if (!storeKeyAtomically(key_path, tmp_path, key_authentication, key)) return false;
162 }
163
164 if (!installKey(key, key_ref)) {
165 LOG(ERROR) << "Failed to install key in " << key_path;
166 return false;
167 }
168 return true;
169}
170
171bool retrieveKey(bool create_if_absent, const std::string& key_path, const std::string& tmp_path,
172 KeyBuffer* key, bool keepOld) {
173 LOG(ERROR) << "retreiveKey1";
174 if (pathExists(key_path)) {
175 LOG(ERROR) << "Key exists, using: " << key_path;
176 if (!retrieveKey(key_path, kEmptyAuthentication, key, keepOld)) return false;
177 } else {
178 if (!create_if_absent) {
179 LOG(ERROR) << "No key found in " << key_path;
180 return false;
181 }
182 LOG(ERROR) << "Creating new key in " << key_path;
183 if (!randomKey(key)) return false;
184 LOG(ERROR) << "retrieveKey1";
185 if (!storeKeyAtomically(key_path, tmp_path, kEmptyAuthentication, *key)) return false;
186 }
187 return true;
188}
189
190} // namespace vold
191} // namespace android