blob: 1b9661c9ac38f6693d5b73fb56ce0564267e68d6 [file] [log] [blame]
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -08001/*
2 * Copyright (C) 2015 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
Paul Lawrence731a7a22015-04-28 22:14:15 +000017#include "Ext4Crypt.h"
18
Paul Crowley1ef25582016-01-21 20:26:12 +000019#include "KeyStorage.h"
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -080020#include "Utils.h"
21
Paul Lawrencefd7db732015-04-10 07:48:51 -070022#include <iomanip>
Paul Lawrence731a7a22015-04-28 22:14:15 +000023#include <map>
Paul Crowleyb1f3d242016-01-28 10:09:46 +000024#include <set>
Paul Lawrencefd7db732015-04-10 07:48:51 -070025#include <string>
26#include <sstream>
Paul Lawrence731a7a22015-04-28 22:14:15 +000027
Paul Crowleyb1f3d242016-01-28 10:09:46 +000028#include <stdio.h>
Paul Lawrence731a7a22015-04-28 22:14:15 +000029#include <errno.h>
Paul Crowley95376d62015-05-06 15:04:43 +010030#include <dirent.h>
Paul Lawrence731a7a22015-04-28 22:14:15 +000031#include <sys/mount.h>
Paul Crowley95376d62015-05-06 15:04:43 +010032#include <sys/types.h>
33#include <sys/stat.h>
34#include <fcntl.h>
Paul Lawrence731a7a22015-04-28 22:14:15 +000035#include <cutils/properties.h>
Paul Lawrencefd7db732015-04-10 07:48:51 -070036#include <openssl/sha.h>
Jeff Sharkey7a9dd952016-01-12 16:52:16 -070037#include <selinux/android.h>
Paul Lawrence731a7a22015-04-28 22:14:15 +000038
Paul Crowley480fcd22015-08-24 14:53:28 +010039#include <private/android_filesystem_config.h>
40
Paul Lawrence731a7a22015-04-28 22:14:15 +000041#include "unencrypted_properties.h"
42#include "key_control.h"
43#include "cryptfs.h"
Paul Crowley95376d62015-05-06 15:04:43 +010044#include "ext4_crypt_init_extensions.h"
Paul Lawrence731a7a22015-04-28 22:14:15 +000045
46#define LOG_TAG "Ext4Crypt"
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -080047
Jeff Sharkey7a9dd952016-01-12 16:52:16 -070048#define EMULATED_USES_SELINUX 0
49
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -080050#include <cutils/fs.h>
51#include <cutils/log.h>
Paul Lawrence731a7a22015-04-28 22:14:15 +000052#include <cutils/klog.h>
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -080053
Elliott Hughes7e128fb2015-12-04 15:50:53 -080054#include <android-base/file.h>
Elliott Hughes6bf05472015-12-04 17:55:33 -080055#include <android-base/logging.h>
Elliott Hughes7e128fb2015-12-04 15:50:53 -080056#include <android-base/stringprintf.h>
Paul Lawrence731a7a22015-04-28 22:14:15 +000057
Paul Lawrence7b6b5652016-02-02 11:14:59 -080058// TODO - remove when switch to using keymaster keys for device data
59static int e4crypt_check_passwd(const char* path, const char* password);
60
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -080061using android::base::StringPrintf;
62
Jeff Sharkeyfc505c32015-12-07 17:27:01 -070063static bool e4crypt_is_native() {
64 char value[PROPERTY_VALUE_MAX];
65 property_get("ro.crypto.type", value, "none");
66 return !strcmp(value, "file");
67}
68
69static bool e4crypt_is_emulated() {
70 return property_get_bool("persist.sys.emulate_fbe", false);
71}
Jeff Sharkeyc79fb892015-11-12 20:18:02 -080072
Paul Lawrence731a7a22015-04-28 22:14:15 +000073namespace {
74 // Key length in bits
75 const int key_length = 128;
Paul Lawrencefd7db732015-04-10 07:48:51 -070076 static_assert(key_length % 8 == 0,
77 "Key length must be multiple of 8 bits");
Paul Lawrence731a7a22015-04-28 22:14:15 +000078
Paul Crowley285956f2016-01-20 13:12:38 +000079 const std::string user_key_dir = std::string() + DATA_MNT_POINT + "/misc/vold/user_keys";
Paul Crowleyb1f3d242016-01-28 10:09:46 +000080 const std::string user_key_temp = user_key_dir + "/temp";
Paul Crowley285956f2016-01-20 13:12:38 +000081
Paul Lawrence7b6b5652016-02-02 11:14:59 -080082 bool s_enabled = false;
83
Paul Crowleyb1f3d242016-01-28 10:09:46 +000084 // Some users are ephemeral, don't try to wipe their keys from disk
85 std::set<userid_t> s_ephemeral_users;
86 // Map user ids to key references
Paul Crowleyb92f83c2016-02-01 14:10:43 +000087 std::map<userid_t, std::string> s_de_key_raw_refs;
Paul Crowleyb1f3d242016-01-28 10:09:46 +000088 std::map<userid_t, std::string> s_ce_key_raw_refs;
Paul Lawrence731a7a22015-04-28 22:14:15 +000089
Paul Crowley285956f2016-01-20 13:12:38 +000090 // ext4enc:TODO get this const from somewhere good
Paul Lawrencefd7db732015-04-10 07:48:51 -070091 const int EXT4_KEY_DESCRIPTOR_SIZE = 8;
92
Paul Lawrence731a7a22015-04-28 22:14:15 +000093 // ext4enc:TODO Include structure from somewhere sensible
94 // MUST be in sync with ext4_crypto.c in kernel
Paul Lawrencefd7db732015-04-10 07:48:51 -070095 const int EXT4_MAX_KEY_SIZE = 64;
96 const int EXT4_ENCRYPTION_MODE_AES_256_XTS = 1;
Paul Lawrence731a7a22015-04-28 22:14:15 +000097 struct ext4_encryption_key {
Paul Lawrencefd7db732015-04-10 07:48:51 -070098 uint32_t mode;
99 char raw[EXT4_MAX_KEY_SIZE];
100 uint32_t size;
Paul Lawrence731a7a22015-04-28 22:14:15 +0000101 };
102
103 namespace tag {
104 const char* magic = "magic";
105 const char* major_version = "major_version";
106 const char* minor_version = "minor_version";
107 const char* flags = "flags";
108 const char* crypt_type = "crypt_type";
109 const char* failed_decrypt_count = "failed_decrypt_count";
110 const char* crypto_type_name = "crypto_type_name";
111 const char* master_key = "master_key";
112 const char* salt = "salt";
113 const char* kdf_type = "kdf_type";
114 const char* N_factor = "N_factor";
115 const char* r_factor = "r_factor";
116 const char* p_factor = "p_factor";
117 const char* keymaster_blob = "keymaster_blob";
118 const char* scrypted_intermediate_key = "scrypted_intermediate_key";
119 }
120}
121
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000122static bool install_key(const std::string &key, std::string &raw_ref);
Paul Crowleyf25a35a2015-05-06 13:38:53 +0100123
Paul Lawrence731a7a22015-04-28 22:14:15 +0000124static int put_crypt_ftr_and_key(const crypt_mnt_ftr& crypt_ftr,
125 UnencryptedProperties& props)
126{
127 SLOGI("Putting crypt footer");
128
129 bool success = props.Set<int>(tag::magic, crypt_ftr.magic)
130 && props.Set<int>(tag::major_version, crypt_ftr.major_version)
131 && props.Set<int>(tag::minor_version, crypt_ftr.minor_version)
132 && props.Set<int>(tag::flags, crypt_ftr.flags)
133 && props.Set<int>(tag::crypt_type, crypt_ftr.crypt_type)
134 && props.Set<int>(tag::failed_decrypt_count,
135 crypt_ftr.failed_decrypt_count)
136 && props.Set<std::string>(tag::crypto_type_name,
137 std::string(reinterpret_cast<const char*>(crypt_ftr.crypto_type_name)))
138 && props.Set<std::string>(tag::master_key,
139 std::string((const char*) crypt_ftr.master_key,
140 crypt_ftr.keysize))
141 && props.Set<std::string>(tag::salt,
142 std::string((const char*) crypt_ftr.salt,
143 SALT_LEN))
144 && props.Set<int>(tag::kdf_type, crypt_ftr.kdf_type)
145 && props.Set<int>(tag::N_factor, crypt_ftr.N_factor)
146 && props.Set<int>(tag::r_factor, crypt_ftr.r_factor)
147 && props.Set<int>(tag::p_factor, crypt_ftr.p_factor)
148 && props.Set<std::string>(tag::keymaster_blob,
149 std::string((const char*) crypt_ftr.keymaster_blob,
150 crypt_ftr.keymaster_blob_size))
151 && props.Set<std::string>(tag::scrypted_intermediate_key,
152 std::string((const char*) crypt_ftr.scrypted_intermediate_key,
153 SCRYPT_LEN));
154 return success ? 0 : -1;
155}
156
157static int get_crypt_ftr_and_key(crypt_mnt_ftr& crypt_ftr,
158 const UnencryptedProperties& props)
159{
160 memset(&crypt_ftr, 0, sizeof(crypt_ftr));
161 crypt_ftr.magic = props.Get<int>(tag::magic);
162 crypt_ftr.major_version = props.Get<int>(tag::major_version);
163 crypt_ftr.minor_version = props.Get<int>(tag::minor_version);
Paul Lawrence0d9cd9e2015-05-05 15:58:27 -0700164 crypt_ftr.ftr_size = sizeof(crypt_ftr);
Paul Lawrence731a7a22015-04-28 22:14:15 +0000165 crypt_ftr.flags = props.Get<int>(tag::flags);
166 crypt_ftr.crypt_type = props.Get<int>(tag::crypt_type);
167 crypt_ftr.failed_decrypt_count = props.Get<int>(tag::failed_decrypt_count);
168 std::string crypto_type_name = props.Get<std::string>(tag::crypto_type_name);
169 strlcpy(reinterpret_cast<char*>(crypt_ftr.crypto_type_name),
170 crypto_type_name.c_str(),
171 sizeof(crypt_ftr.crypto_type_name));
172 std::string master_key = props.Get<std::string>(tag::master_key);
173 crypt_ftr.keysize = master_key.size();
174 if (crypt_ftr.keysize > sizeof(crypt_ftr.master_key)) {
175 SLOGE("Master key size too long");
176 return -1;
177 }
178 memcpy(crypt_ftr.master_key, &master_key[0], crypt_ftr.keysize);
179 std::string salt = props.Get<std::string>(tag::salt);
180 if (salt.size() != SALT_LEN) {
181 SLOGE("Salt wrong length");
182 return -1;
183 }
184 memcpy(crypt_ftr.salt, &salt[0], SALT_LEN);
185 crypt_ftr.kdf_type = props.Get<int>(tag::kdf_type);
186 crypt_ftr.N_factor = props.Get<int>(tag::N_factor);
187 crypt_ftr.r_factor = props.Get<int>(tag::r_factor);
188 crypt_ftr.p_factor = props.Get<int>(tag::p_factor);
189 std::string keymaster_blob = props.Get<std::string>(tag::keymaster_blob);
190 crypt_ftr.keymaster_blob_size = keymaster_blob.size();
191 if (crypt_ftr.keymaster_blob_size > sizeof(crypt_ftr.keymaster_blob)) {
192 SLOGE("Keymaster blob too long");
193 return -1;
194 }
195 memcpy(crypt_ftr.keymaster_blob, &keymaster_blob[0],
196 crypt_ftr.keymaster_blob_size);
197 std::string scrypted_intermediate_key = props.Get<std::string>(tag::scrypted_intermediate_key);
198 if (scrypted_intermediate_key.size() != SCRYPT_LEN) {
199 SLOGE("scrypted intermediate key wrong length");
200 return -1;
201 }
202 memcpy(crypt_ftr.scrypted_intermediate_key, &scrypted_intermediate_key[0],
203 SCRYPT_LEN);
204
205 return 0;
206}
207
208static UnencryptedProperties GetProps(const char* path)
209{
210 return UnencryptedProperties(path);
211}
212
Paul Lawrence731a7a22015-04-28 22:14:15 +0000213int e4crypt_enable(const char* path)
214{
215 // Already enabled?
Paul Lawrence7b6b5652016-02-02 11:14:59 -0800216 if (s_enabled) {
Paul Lawrence731a7a22015-04-28 22:14:15 +0000217 return 0;
218 }
219
220 // Not an encryptable device?
221 UnencryptedProperties key_props = GetProps(path).GetChild(properties::key);
222 if (!key_props.OK()) {
223 return 0;
224 }
225
226 if (key_props.Get<std::string>(tag::master_key).empty()) {
227 crypt_mnt_ftr ftr;
228 if (cryptfs_create_default_ftr(&ftr, key_length)) {
229 SLOGE("Failed to create crypto footer");
230 return -1;
231 }
232
Paul Lawrence0d9cd9e2015-05-05 15:58:27 -0700233 // Scrub fields not used by ext4enc
234 ftr.persist_data_offset[0] = 0;
235 ftr.persist_data_offset[1] = 0;
236 ftr.persist_data_size = 0;
237
Paul Lawrence731a7a22015-04-28 22:14:15 +0000238 if (put_crypt_ftr_and_key(ftr, key_props)) {
239 SLOGE("Failed to write crypto footer");
240 return -1;
241 }
242
243 crypt_mnt_ftr ftr2;
244 if (get_crypt_ftr_and_key(ftr2, key_props)) {
245 SLOGE("Failed to read crypto footer back");
246 return -1;
247 }
248
249 if (memcmp(&ftr, &ftr2, sizeof(ftr)) != 0) {
250 SLOGE("Crypto footer not correctly written");
Paul Lawrence0d9cd9e2015-05-05 15:58:27 -0700251 return -1;
Paul Lawrence731a7a22015-04-28 22:14:15 +0000252 }
253 }
254
255 if (!UnencryptedProperties(path).Remove(properties::ref)) {
256 SLOGE("Failed to remove key ref");
257 return -1;
258 }
259
260 return e4crypt_check_passwd(path, "");
261}
262
Paul Lawrence731a7a22015-04-28 22:14:15 +0000263int e4crypt_crypto_complete(const char* path)
264{
265 SLOGI("ext4 crypto complete called on %s", path);
Paul Lawrence7b6b5652016-02-02 11:14:59 -0800266 auto key_props = GetProps(path).GetChild(properties::key);
Paul Lawrence731a7a22015-04-28 22:14:15 +0000267 if (key_props.Get<std::string>(tag::master_key).empty()) {
268 SLOGI("No master key, so not ext4enc");
269 return -1;
270 }
271
272 return 0;
273}
274
Paul Crowley93363482015-07-07 15:17:22 +0100275// Get raw keyref - used to make keyname and to pass to ioctl
Paul Lawrencefd7db732015-04-10 07:48:51 -0700276static std::string generate_key_ref(const char* key, int length)
277{
278 SHA512_CTX c;
279
280 SHA512_Init(&c);
281 SHA512_Update(&c, key, length);
Paul Crowley285956f2016-01-20 13:12:38 +0000282 unsigned char key_ref1[SHA512_DIGEST_LENGTH];
Paul Lawrencefd7db732015-04-10 07:48:51 -0700283 SHA512_Final(key_ref1, &c);
284
285 SHA512_Init(&c);
Paul Crowley285956f2016-01-20 13:12:38 +0000286 SHA512_Update(&c, key_ref1, SHA512_DIGEST_LENGTH);
287 unsigned char key_ref2[SHA512_DIGEST_LENGTH];
Paul Lawrencefd7db732015-04-10 07:48:51 -0700288 SHA512_Final(key_ref2, &c);
289
290 return std::string((char*)key_ref2, EXT4_KEY_DESCRIPTOR_SIZE);
291}
292
Paul Lawrence7b6b5652016-02-02 11:14:59 -0800293static int e4crypt_check_passwd(const char* path, const char* password)
Paul Lawrence731a7a22015-04-28 22:14:15 +0000294{
295 SLOGI("e4crypt_check_password");
Paul Lawrence7b6b5652016-02-02 11:14:59 -0800296 auto props = GetProps(path);
Paul Lawrencea56d3132015-05-04 15:48:24 -0700297 auto key_props = props.GetChild(properties::key);
Paul Lawrence731a7a22015-04-28 22:14:15 +0000298
299 crypt_mnt_ftr ftr;
300 if (get_crypt_ftr_and_key(ftr, key_props)) {
301 SLOGE("Failed to read crypto footer back");
302 return -1;
303 }
304
Paul Crowley95376d62015-05-06 15:04:43 +0100305 unsigned char master_key_bytes[key_length / 8];
306 if (cryptfs_get_master_key (&ftr, password, master_key_bytes)){
Paul Lawrence731a7a22015-04-28 22:14:15 +0000307 SLOGI("Incorrect password");
Paul Lawrencec78c71b2015-04-14 15:26:29 -0700308 ftr.failed_decrypt_count++;
309 if (put_crypt_ftr_and_key(ftr, key_props)) {
310 SLOGW("Failed to update failed_decrypt_count");
311 }
312 return ftr.failed_decrypt_count;
313 }
314
315 if (ftr.failed_decrypt_count) {
316 ftr.failed_decrypt_count = 0;
317 if (put_crypt_ftr_and_key(ftr, key_props)) {
318 SLOGW("Failed to reset failed_decrypt_count");
319 }
Paul Lawrence731a7a22015-04-28 22:14:15 +0000320 }
Paul Crowley95376d62015-05-06 15:04:43 +0100321 std::string master_key(reinterpret_cast<char*>(master_key_bytes),
322 sizeof(master_key_bytes));
Paul Lawrence731a7a22015-04-28 22:14:15 +0000323
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000324 std::string raw_ref;
325 if (!install_key(master_key, raw_ref)) {
Paul Crowleyf25a35a2015-05-06 13:38:53 +0100326 return -1;
327 }
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000328 SLOGD("Installed master key");
Paul Lawrence731a7a22015-04-28 22:14:15 +0000329
Paul Crowleyf25a35a2015-05-06 13:38:53 +0100330 // Save reference to key so we can set policy later
331 if (!props.Set(properties::ref, raw_ref)) {
332 SLOGE("Cannot save key reference");
333 return -1;
334 }
335
Paul Lawrence7b6b5652016-02-02 11:14:59 -0800336 s_enabled = true;
Paul Crowleyf25a35a2015-05-06 13:38:53 +0100337 return 0;
338}
339
Paul Crowley93363482015-07-07 15:17:22 +0100340static ext4_encryption_key fill_key(const std::string &key)
Paul Crowleyf25a35a2015-05-06 13:38:53 +0100341{
Paul Lawrencefd7db732015-04-10 07:48:51 -0700342 // ext4enc:TODO Currently raw key is required to be of length
343 // sizeof(ext4_key.raw) == EXT4_MAX_KEY_SIZE, so zero pad to
344 // this length. Change when kernel bug is fixed.
345 ext4_encryption_key ext4_key = {EXT4_ENCRYPTION_MODE_AES_256_XTS,
346 {0},
347 sizeof(ext4_key.raw)};
348 memset(ext4_key.raw, 0, sizeof(ext4_key.raw));
349 static_assert(key_length / 8 <= sizeof(ext4_key.raw),
350 "Key too long!");
Paul Crowley95376d62015-05-06 15:04:43 +0100351 memcpy(ext4_key.raw, &key[0], key.size());
Paul Crowley93363482015-07-07 15:17:22 +0100352 return ext4_key;
353}
Paul Lawrence731a7a22015-04-28 22:14:15 +0000354
Paul Crowley93363482015-07-07 15:17:22 +0100355static std::string keyname(const std::string &raw_ref)
356{
Paul Lawrencefd7db732015-04-10 07:48:51 -0700357 std::ostringstream o;
Paul Crowley93363482015-07-07 15:17:22 +0100358 o << "ext4:";
Paul Lawrencefd7db732015-04-10 07:48:51 -0700359 for (auto i = raw_ref.begin(); i != raw_ref.end(); ++i) {
360 o << std::hex << std::setw(2) << std::setfill('0') << (int)*i;
361 }
Paul Crowley93363482015-07-07 15:17:22 +0100362 return o.str();
363}
Paul Lawrencefd7db732015-04-10 07:48:51 -0700364
Paul Crowley93363482015-07-07 15:17:22 +0100365// Get the keyring we store all keys in
366static key_serial_t e4crypt_keyring()
367{
368 return keyctl_search(KEY_SPEC_SESSION_KEYRING, "keyring", "e4crypt", 0);
369}
Paul Lawrence731a7a22015-04-28 22:14:15 +0000370
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000371// Install password into global keyring
372// Return raw key reference for use in policy
373static bool install_key(const std::string &key, std::string &raw_ref)
Paul Crowley93363482015-07-07 15:17:22 +0100374{
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000375 if (key.size() != key_length/8) {
376 LOG(ERROR) << "Wrong size key " << key.size();
377 return false;
378 }
379 auto ext4_key = fill_key(key);
380 raw_ref = generate_key_ref(ext4_key.raw, ext4_key.size);
381 auto ref = keyname(raw_ref);
Paul Crowley93363482015-07-07 15:17:22 +0100382 key_serial_t device_keyring = e4crypt_keyring();
Paul Lawrencefd7db732015-04-10 07:48:51 -0700383 key_serial_t key_id = add_key("logon", ref.c_str(),
Paul Lawrence731a7a22015-04-28 22:14:15 +0000384 (void*)&ext4_key, sizeof(ext4_key),
385 device_keyring);
Paul Lawrence731a7a22015-04-28 22:14:15 +0000386 if (key_id == -1) {
Paul Crowley285956f2016-01-20 13:12:38 +0000387 PLOG(ERROR) << "Failed to insert key into keyring " << device_keyring;
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000388 return false;
Paul Lawrence731a7a22015-04-28 22:14:15 +0000389 }
Paul Crowley285956f2016-01-20 13:12:38 +0000390 LOG(INFO) << "Added key " << key_id << " (" << ref << ") to keyring "
391 << device_keyring << " in process " << getpid();
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000392 return true;
Paul Lawrence731a7a22015-04-28 22:14:15 +0000393}
394
Paul Lawrence368d7942015-04-15 14:12:00 -0700395int e4crypt_get_field(const char* path, const char* fieldname,
396 char* value, size_t len)
397{
Paul Lawrence7b6b5652016-02-02 11:14:59 -0800398 auto v = GetProps(path).GetChild(properties::props)
Paul Lawrence368d7942015-04-15 14:12:00 -0700399 .Get<std::string>(fieldname);
400
401 if (v == "") {
402 return CRYPTO_GETFIELD_ERROR_NO_FIELD;
403 }
404
405 if (v.length() >= len) {
406 return CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL;
407 }
408
409 strlcpy(value, v.c_str(), len);
410 return 0;
411}
412
413int e4crypt_set_field(const char* path, const char* fieldname,
414 const char* value)
415{
Paul Lawrence7b6b5652016-02-02 11:14:59 -0800416 return GetProps(path).GetChild(properties::props)
Paul Lawrence368d7942015-04-15 14:12:00 -0700417 .Set(fieldname, std::string(value)) ? 0 : -1;
418}
Paul Crowley95376d62015-05-06 15:04:43 +0100419
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000420static std::string get_de_key_path(userid_t user_id) {
421 return StringPrintf("%s/de/%d", user_key_dir.c_str(), user_id);
422}
423
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000424static std::string get_ce_key_path(userid_t user_id) {
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000425 return StringPrintf("%s/ce/%d/current", user_key_dir.c_str(), user_id);
Paul Crowleyb33e8872015-05-19 12:34:09 +0100426}
427
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000428static bool read_and_install_key(const std::string &key_path, std::string &raw_ref)
429{
430 std::string key;
431 if (!android::vold::retrieveKey(key_path, key)) return false;
432 if (!install_key(key, raw_ref)) return false;
433 return true;
Lenka Trochtova395039f2015-11-25 10:13:03 +0100434}
435
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000436static bool read_and_install_user_ce_key(userid_t user_id)
Paul Crowleyb33e8872015-05-19 12:34:09 +0100437{
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000438 if (s_ce_key_raw_refs.count(user_id) != 0) return true;
439 const auto key_path = get_ce_key_path(user_id);
440 std::string raw_ref;
441 if (!read_and_install_key(key_path, raw_ref)) return false;
442 s_ce_key_raw_refs[user_id] = raw_ref;
443 LOG(DEBUG) << "Installed ce key for user " << user_id;
Paul Crowley1ef25582016-01-21 20:26:12 +0000444 return true;
Paul Crowley285956f2016-01-20 13:12:38 +0000445}
446
Paul Crowley13ffd8e2016-01-27 14:30:22 +0000447static bool prepare_dir(const std::string &dir, mode_t mode, uid_t uid, gid_t gid) {
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000448 LOG(DEBUG) << "Preparing: " << dir;
Paul Crowley13ffd8e2016-01-27 14:30:22 +0000449 if (fs_prepare_dir(dir.c_str(), mode, uid, gid) != 0) {
450 PLOG(ERROR) << "Failed to prepare " << dir;
Paul Crowley285956f2016-01-20 13:12:38 +0000451 return false;
452 }
Paul Crowley13ffd8e2016-01-27 14:30:22 +0000453 return true;
454}
455
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000456static bool random_key(std::string &key) {
Paul Crowley1ef25582016-01-21 20:26:12 +0000457 if (android::vold::ReadRandomBytes(key_length / 8, key) != 0) {
458 // TODO status_t plays badly with PLOG, fix it.
459 LOG(ERROR) << "Random read failed";
Paul Crowley285956f2016-01-20 13:12:38 +0000460 return false;
461 }
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000462 return true;
463}
464
465static bool path_exists(const std::string &path) {
466 return access(path.c_str(), F_OK) == 0;
467}
468
469// NB this assumes that there is only one thread listening for crypt commands, because
470// it creates keys in a fixed location.
471static bool store_key(const std::string &key_path, const std::string &key) {
472 if (path_exists(key_path)) {
473 LOG(ERROR) << "Already exists, cannot create key at: " << key_path;
474 return false;
475 }
476 if (path_exists(user_key_temp)) {
477 android::vold::destroyKey(user_key_temp);
478 }
479 if (!android::vold::storeKey(user_key_temp, key)) return false;
480 if (rename(user_key_temp.c_str(), key_path.c_str()) != 0) {
481 PLOG(ERROR) << "Unable to move new key to location: " << key_path;
482 return false;
Paul Crowley95376d62015-05-06 15:04:43 +0100483 }
Paul Crowley285956f2016-01-20 13:12:38 +0000484 LOG(DEBUG) << "Created key " << key_path;
Paul Crowley95376d62015-05-06 15:04:43 +0100485 return true;
486}
487
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000488static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) {
489 std::string de_key, ce_key;
490 if (!random_key(de_key)) return false;
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000491 if (!random_key(ce_key)) return false;
492 if (create_ephemeral) {
493 // If the key should be created as ephemeral, don't store it.
494 s_ephemeral_users.insert(user_id);
495 } else {
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000496 if (!store_key(get_de_key_path(user_id), de_key)) return false;
497 if (!prepare_dir(user_key_dir + "/ce/" + std::to_string(user_id),
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000498 0700, AID_ROOT, AID_ROOT)) return false;
499 if (!store_key(get_ce_key_path(user_id), ce_key)) return false;
Paul Crowley95376d62015-05-06 15:04:43 +0100500 }
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000501 std::string de_raw_ref;
502 if (!install_key(de_key, de_raw_ref)) return false;
503 s_de_key_raw_refs[user_id] = de_raw_ref;
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000504 std::string ce_raw_ref;
505 if (!install_key(ce_key, ce_raw_ref)) return false;
506 s_ce_key_raw_refs[user_id] = ce_raw_ref;
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000507 LOG(DEBUG) << "Created keys for user " << user_id;
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000508 return true;
509}
510
511static bool lookup_key_ref(const std::map<userid_t, std::string> &key_map,
512 userid_t user_id, std::string &raw_ref) {
513 auto refi = key_map.find(user_id);
514 if (refi == key_map.end()) {
515 LOG(ERROR) << "Cannot find key for " << user_id;
516 return false;
517 }
518 raw_ref = refi->second;
519 return true;
520}
521
522static bool set_policy(const std::string &raw_ref, const std::string& path) {
523 if (do_policy_set(path.c_str(), raw_ref.data(), raw_ref.size()) != 0) {
524 LOG(ERROR) << "Failed to set policy on: " << path;
525 return false;
526 }
527 return true;
Paul Crowley95376d62015-05-06 15:04:43 +0100528}
Paul Crowleyb33e8872015-05-19 12:34:09 +0100529
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000530static bool is_numeric(const char *name) {
531 for (const char *p = name; *p != '\0'; p++) {
532 if (!isdigit(*p))
533 return false;
534 }
535 return true;
536}
537
538static bool load_all_de_keys() {
539 auto de_dir = user_key_dir + "/de";
540 auto dirp = std::unique_ptr<DIR, int(*)(DIR*)>(opendir(de_dir.c_str()), closedir);
541 if (!dirp) {
542 PLOG(ERROR) << "Unable to read de key directory";
543 return false;
544 }
545 for (;;) {
546 errno = 0;
547 auto entry = readdir(dirp.get());
548 if (!entry) {
549 if (errno) {
550 PLOG(ERROR) << "Unable to read de key directory";
551 return false;
552 }
553 break;
554 }
555 if (entry->d_type != DT_DIR || !is_numeric(entry->d_name)) {
556 LOG(DEBUG) << "Skipping non-de-key " << entry->d_name;
557 continue;
558 }
559 userid_t user_id = atoi(entry->d_name);
560 if (s_de_key_raw_refs.count(user_id) == 0) {
561 std::string raw_ref;
562 if (!read_and_install_key(de_dir + "/" + entry->d_name, raw_ref)) return false;
563 s_de_key_raw_refs[user_id] = raw_ref;
564 LOG(DEBUG) << "Installed de key for user " << user_id;
565 }
566 }
567 // ext4enc:TODO: go through all DE directories, ensure that all user dirs have the
568 // correct policy set on them, and that no rogue ones exist.
569 return true;
570}
571
Paul Crowley8fb12fd2016-02-01 14:28:12 +0000572int e4crypt_init_user0() {
573 LOG(DEBUG) << "e4crypt_init_user0";
574 if (e4crypt_is_native()) {
575 if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return -1;
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000576 if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return -1;
577 if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return -1;
578 auto de_path = get_de_key_path(0);
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000579 auto ce_path = get_ce_key_path(0);
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000580 if (!path_exists(de_path) || !path_exists(ce_path)) {
581 if (path_exists(de_path)) {
582 android::vold::destroyKey(de_path); // Ignore failure
583 }
584 if (path_exists(ce_path)) {
585 android::vold::destroyKey(ce_path); // Ignore failure
586 }
587 if (!create_and_install_user_keys(0, false)) return -1;
Paul Crowley8fb12fd2016-02-01 14:28:12 +0000588 }
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000589 if (!load_all_de_keys()) return -1;
Paul Crowley8fb12fd2016-02-01 14:28:12 +0000590 }
591 // Ignore failures. FIXME this is horrid
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000592 // FIXME: we need an idempotent policy-setting call, which simply verifies the
593 // policy is already set on a second run, even if the directory is nonempty.
594 // Then we need to call it all the time.
Paul Crowley8fb12fd2016-02-01 14:28:12 +0000595 e4crypt_prepare_user_storage(nullptr, 0, 0, false);
596 return 0;
597}
598
Paul Crowley27cbce92015-12-10 14:51:30 +0000599int e4crypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral) {
Paul Crowley285956f2016-01-20 13:12:38 +0000600 LOG(DEBUG) << "e4crypt_vold_create_user_key for " << user_id << " serial " << serial;
Paul Crowleyea62e262016-01-28 12:23:53 +0000601 if (!e4crypt_is_native()) {
602 return 0;
603 }
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000604 // FIXME test for existence of key that is not loaded yet
605 if (s_ce_key_raw_refs.count(user_id) != 0) {
Paul Crowley285956f2016-01-20 13:12:38 +0000606 LOG(ERROR) << "Already exists, can't e4crypt_vold_create_user_key for "
607 << user_id << " serial " << serial;
608 // FIXME should we fail the command?
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800609 return 0;
610 }
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000611 if (!create_and_install_user_keys(user_id, ephemeral)) {
Paul Crowley285956f2016-01-20 13:12:38 +0000612 return -1;
613 }
614 // TODO: create second key for user_de data
615 return 0;
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800616}
617
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000618static bool evict_key(const std::string &raw_ref) {
619 auto ref = keyname(raw_ref);
Paul Crowley93363482015-07-07 15:17:22 +0100620 auto key_serial = keyctl_search(e4crypt_keyring(), "logon", ref.c_str(), 0);
Paul Crowley1ef25582016-01-21 20:26:12 +0000621 if (keyctl_revoke(key_serial) != 0) {
Paul Crowley285956f2016-01-20 13:12:38 +0000622 PLOG(ERROR) << "Failed to revoke key with serial " << key_serial << " ref " << ref;
Paul Crowley1ef25582016-01-21 20:26:12 +0000623 return false;
Paul Crowley93363482015-07-07 15:17:22 +0100624 }
Paul Crowley1ef25582016-01-21 20:26:12 +0000625 LOG(DEBUG) << "Revoked key with serial " << key_serial << " ref " << ref;
626 return true;
627}
628
629int e4crypt_destroy_user_key(userid_t user_id) {
630 LOG(DEBUG) << "e4crypt_destroy_user_key(" << user_id << ")";
Paul Crowleyea62e262016-01-28 12:23:53 +0000631 if (!e4crypt_is_native()) {
632 return 0;
633 }
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000634 bool success = true;
635 std::string raw_ref;
636 success &= lookup_key_ref(s_ce_key_raw_refs, user_id, raw_ref) && evict_key(raw_ref);
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000637 success &= lookup_key_ref(s_de_key_raw_refs, user_id, raw_ref) && evict_key(raw_ref);
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000638 auto it = s_ephemeral_users.find(user_id);
639 if (it != s_ephemeral_users.end()) {
640 s_ephemeral_users.erase(it);
Paul Crowley1ef25582016-01-21 20:26:12 +0000641 } else {
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000642 success &= android::vold::destroyKey(get_ce_key_path(user_id));
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000643 success &= android::vold::destroyKey(get_de_key_path(user_id));
Lenka Trochtova395039f2015-11-25 10:13:03 +0100644 }
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000645 return success ? 0 : -1;
Paul Crowleyb33e8872015-05-19 12:34:09 +0100646}
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800647
Jeff Sharkey7a9dd952016-01-12 16:52:16 -0700648static int emulated_lock(const std::string& path) {
649 if (chmod(path.c_str(), 0000) != 0) {
650 PLOG(ERROR) << "Failed to chmod " << path;
651 return -1;
652 }
653#if EMULATED_USES_SELINUX
654 if (setfilecon(path.c_str(), "u:object_r:storage_stub_file:s0") != 0) {
655 PLOG(WARNING) << "Failed to setfilecon " << path;
656 return -1;
657 }
658#endif
659 return 0;
660}
661
662static int emulated_unlock(const std::string& path, mode_t mode) {
663 if (chmod(path.c_str(), mode) != 0) {
664 PLOG(ERROR) << "Failed to chmod " << path;
Paul Crowleya042cb52016-01-21 17:24:49 +0000665 // FIXME temporary workaround for b/26713622
666 if (e4crypt_is_emulated()) return -1;
Jeff Sharkey7a9dd952016-01-12 16:52:16 -0700667 }
668#if EMULATED_USES_SELINUX
669 if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_FORCE) != 0) {
670 PLOG(WARNING) << "Failed to restorecon " << path;
Paul Crowleya042cb52016-01-21 17:24:49 +0000671 // FIXME temporary workaround for b/26713622
672 if (e4crypt_is_emulated()) return -1;
Jeff Sharkey7a9dd952016-01-12 16:52:16 -0700673 }
674#endif
675 return 0;
676}
677
Paul Crowley285956f2016-01-20 13:12:38 +0000678int e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token) {
679 LOG(DEBUG) << "e4crypt_unlock_user_key " << user_id << " " << (token != nullptr);
Jeff Sharkeyfc505c32015-12-07 17:27:01 -0700680 if (e4crypt_is_native()) {
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000681 if (!read_and_install_user_ce_key(user_id)) {
Paul Crowley8fb12fd2016-02-01 14:28:12 +0000682 LOG(ERROR) << "Couldn't read key for " << user_id;
683 return -1;
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800684 }
Jeff Sharkeyfc505c32015-12-07 17:27:01 -0700685 } else {
686 // When in emulation mode, we just use chmod. However, we also
687 // unlock directories when not in emulation mode, to bring devices
688 // back into a known-good state.
Jeff Sharkey7a9dd952016-01-12 16:52:16 -0700689 if (emulated_unlock(android::vold::BuildDataSystemCePath(user_id), 0771) ||
690 emulated_unlock(android::vold::BuildDataMediaPath(nullptr, user_id), 0770) ||
691 emulated_unlock(android::vold::BuildDataUserPath(nullptr, user_id), 0771)) {
692 LOG(ERROR) << "Failed to unlock user " << user_id;
Jeff Sharkeyfc505c32015-12-07 17:27:01 -0700693 return -1;
694 }
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800695 }
696 return 0;
697}
698
699int e4crypt_lock_user_key(userid_t user_id) {
Jeff Sharkeyfc505c32015-12-07 17:27:01 -0700700 if (e4crypt_is_native()) {
701 // TODO: remove from kernel keyring
702 } else if (e4crypt_is_emulated()) {
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800703 // When in emulation mode, we just use chmod
Jeff Sharkey7a9dd952016-01-12 16:52:16 -0700704 if (emulated_lock(android::vold::BuildDataSystemCePath(user_id)) ||
705 emulated_lock(android::vold::BuildDataMediaPath(nullptr, user_id)) ||
706 emulated_lock(android::vold::BuildDataUserPath(nullptr, user_id))) {
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800707 PLOG(ERROR) << "Failed to lock user " << user_id;
708 return -1;
709 }
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800710 }
Jeff Sharkeyfc505c32015-12-07 17:27:01 -0700711
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800712 return 0;
713}
714
Lenka Trochtova9ad43692015-12-11 13:27:26 +0100715int e4crypt_prepare_user_storage(const char* volume_uuid,
716 userid_t user_id,
717 int serial,
718 bool ephemeral) {
Paul Crowley285956f2016-01-20 13:12:38 +0000719 if (volume_uuid) {
720 LOG(DEBUG) << "e4crypt_prepare_user_storage " << volume_uuid << " " << user_id;
721 } else {
722 LOG(DEBUG) << "e4crypt_prepare_user_storage, null volume " << user_id;
723 }
Paul Crowley13ffd8e2016-01-27 14:30:22 +0000724 auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
725 auto media_ce_path = android::vold::BuildDataMediaPath(volume_uuid, user_id);
726 auto user_ce_path = android::vold::BuildDataUserPath(volume_uuid, user_id);
727 auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800728
Paul Crowley8fb12fd2016-02-01 14:28:12 +0000729 // FIXME: should this be 0770 or 0700?
730 if (!prepare_dir(system_ce_path, 0770, AID_SYSTEM, AID_SYSTEM)) return -1;
Paul Crowley13ffd8e2016-01-27 14:30:22 +0000731 if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return -1;
732 if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return -1;
733 if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return -1;
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800734
735 if (e4crypt_crypto_complete(DATA_MNT_POINT) == 0) {
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000736 std::string ce_raw_ref, de_raw_ref;
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000737 if (!lookup_key_ref(s_ce_key_raw_refs, user_id, ce_raw_ref)) return -1;
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000738 if (!lookup_key_ref(s_de_key_raw_refs, user_id, de_raw_ref)) return -1;
Paul Crowleyb1f3d242016-01-28 10:09:46 +0000739 if (!set_policy(ce_raw_ref, system_ce_path)) return -1;
740 if (!set_policy(ce_raw_ref, media_ce_path)) return -1;
741 if (!set_policy(ce_raw_ref, user_ce_path)) return -1;
Paul Crowleyb92f83c2016-02-01 14:10:43 +0000742 if (!set_policy(de_raw_ref, user_de_path)) return -1;
743 // FIXME I thought there were more DE directories than this
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800744 }
745
746 return 0;
747}