OSDN Git Service

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