• 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 <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 
33 namespace android {
34 namespace vold {
35 
36 constexpr int FS_AES_256_XTS_KEY_SIZE = 64;
37 
randomKey(KeyBuffer * key)38 bool 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
generateKeyRef(const uint8_t * key,int length)49 static 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 
fillKey(const KeyBuffer & key,fscrypt_key * fs_key)66 static 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 
79 static char const* const NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt", nullptr};
80 
keyname(const std::string & prefix,const std::string & raw_ref)81 static 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
fscryptKeyring(key_serial_t * device_keyring)91 static 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
installKey(const KeyBuffer & key,std::string * raw_ref)102 bool 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 
evictKey(const std::string & raw_ref)125 bool 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 
retrieveAndInstallKey(bool create_if_absent,const KeyAuthentication & key_authentication,const std::string & key_path,const std::string & tmp_path,std::string * key_ref)147 bool 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 
retrieveKey(bool create_if_absent,const std::string & key_path,const std::string & tmp_path,KeyBuffer * key,bool keepOld)171 bool retrieveKey(bool create_if_absent, const std::string& key_path, const std::string& tmp_path,
172                  KeyBuffer* key, bool keepOld) {
173     if (pathExists(key_path)) {
174         LOG(DEBUG) << "Key exists, using: " << key_path;
175         if (!retrieveKey(key_path, kEmptyAuthentication, key, keepOld)) return false;
176     } else {
177         if (!create_if_absent) {
178             LOG(ERROR) << "No key found in " << key_path;
179             return false;
180         }
181         LOG(INFO) << "Creating new key in " << key_path;
182         if (!randomKey(key)) return false;
183         if (!storeKeyAtomically(key_path, tmp_path, kEmptyAuthentication, *key)) return false;
184     }
185     return true;
186 }
187 
188 }  // namespace vold
189 }  // namespace android
190