blob: a07212d9df59f81aa90adde00b16eeed6f08cd91 [file] [log] [blame]
Ethan Yonkerfefe5912017-09-30 22:22:13 -05001/*
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 "KeyStorage3.h"
18
19#include "Keymaster3.h"
20#include "ScryptParameters.h"
21#include "Utils.h"
22
23#include <vector>
24
25#include <errno.h>
26#include <stdio.h>
27#include <sys/stat.h>
28#include <sys/types.h>
29#include <sys/wait.h>
30#include <unistd.h>
31
32#include <openssl/err.h>
33#include <openssl/evp.h>
34#include <openssl/sha.h>
35
36#include <android-base/file.h>
37//#include <android-base/logging.h>
38
39#include <cutils/properties.h>
40
41#include <hardware/hw_auth_token.h>
42
43#include <keystore/authorization_set.h>
44#include <keystore/keystore_hidl_support.h>
45
46extern "C" {
47
48#include "crypto_scrypt.h"
49}
50
51#include <iostream>
52#define ERROR 1
53#define LOG(x) std::cout
54#define PLOG(x) std::cout
55
56namespace android {
57namespace vold {
58using namespace keystore;
59
60const KeyAuthentication kEmptyAuthentication{"", ""};
61
62static constexpr size_t AES_KEY_BYTES = 32;
63static constexpr size_t GCM_NONCE_BYTES = 12;
64static constexpr size_t GCM_MAC_BYTES = 16;
65static constexpr size_t SALT_BYTES = 1 << 4;
66static constexpr size_t SECDISCARDABLE_BYTES = 1 << 14;
67static constexpr size_t STRETCHED_BYTES = 1 << 6;
68
69static constexpr uint32_t AUTH_TIMEOUT = 30; // Seconds
70
71static const char* kCurrentVersion = "1";
72static const char* kRmPath = "/system/bin/rm";
73static const char* kSecdiscardPath = "/system/bin/secdiscard";
74static const char* kStretch_none = "none";
75static const char* kStretch_nopassword = "nopassword";
76static const std::string kStretchPrefix_scrypt = "scrypt ";
77static const char* kHashPrefix_secdiscardable = "Android secdiscardable SHA512";
78static const char* kHashPrefix_keygen = "Android key wrapping key generation SHA512";
79static const char* kFn_encrypted_key = "encrypted_key";
80static const char* kFn_keymaster_key_blob = "keymaster_key_blob";
81static const char* kFn_keymaster_key_blob_upgraded = "keymaster_key_blob_upgraded";
82static const char* kFn_salt = "salt";
83static const char* kFn_secdiscardable = "secdiscardable";
84static const char* kFn_stretching = "stretching";
85static const char* kFn_version = "version";
86
87static bool checkSize(const std::string& kind, size_t actual, size_t expected) {
88 if (actual != expected) {
89 LOG(ERROR) << "Wrong number of bytes in " << kind << ", expected " << expected << " got "
90 << actual;
91 return false;
92 }
93 return true;
94}
95
96static std::string hashWithPrefix(char const* prefix, const std::string& tohash) {
97 SHA512_CTX c;
98
99 SHA512_Init(&c);
100 // Personalise the hashing by introducing a fixed prefix.
101 // Hashing applications should use personalization except when there is a
102 // specific reason not to; see section 4.11 of https://www.schneier.com/skein1.3.pdf
103 std::string hashingPrefix = prefix;
104 hashingPrefix.resize(SHA512_CBLOCK);
105 SHA512_Update(&c, hashingPrefix.data(), hashingPrefix.size());
106 SHA512_Update(&c, tohash.data(), tohash.size());
107 std::string res(SHA512_DIGEST_LENGTH, '\0');
108 SHA512_Final(reinterpret_cast<uint8_t*>(&res[0]), &c);
109 return res;
110}
111
112/*static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& auth,
113 const std::string& appId, std::string* key) {
114 auto paramBuilder = AuthorizationSetBuilder()
115 .AesEncryptionKey(AES_KEY_BYTES * 8)
116 .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
117 .Authorization(TAG_MIN_MAC_LENGTH, GCM_MAC_BYTES * 8)
118 .Authorization(TAG_PADDING, PaddingMode::NONE)
119 .Authorization(TAG_APPLICATION_ID, blob2hidlVec(appId));
120 if (auth.token.empty()) {
121 LOG(DEBUG) << "Creating key that doesn't need auth token";
122 paramBuilder.Authorization(TAG_NO_AUTH_REQUIRED);
123 } else {
124 LOG(DEBUG) << "Auth token required for key";
125 if (auth.token.size() != sizeof(hw_auth_token_t)) {
126 LOG(ERROR) << "Auth token should be " << sizeof(hw_auth_token_t) << " bytes, was "
127 << auth.token.size() << " bytes";
128 return false;
129 }
130 const hw_auth_token_t* at = reinterpret_cast<const hw_auth_token_t*>(auth.token.data());
131 paramBuilder.Authorization(TAG_USER_SECURE_ID, at->user_id);
132 paramBuilder.Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD);
133 paramBuilder.Authorization(TAG_AUTH_TIMEOUT, AUTH_TIMEOUT);
134 }
135 return keymaster.generateKey(paramBuilder, key);
136}*/
137
138static AuthorizationSet beginParams(const KeyAuthentication& auth,
139 const std::string& appId) {
140 auto paramBuilder = AuthorizationSetBuilder()
141 .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
142 .Authorization(TAG_MAC_LENGTH, GCM_MAC_BYTES * 8)
143 .Authorization(TAG_PADDING, PaddingMode::NONE)
144 .Authorization(TAG_APPLICATION_ID, blob2hidlVec(appId));
145 if (!auth.token.empty()) {
146 LOG(DEBUG) << "Supplying auth token to Keymaster";
147 paramBuilder.Authorization(TAG_AUTH_TOKEN, blob2hidlVec(auth.token));
148 }
149 return paramBuilder;
150}
151
152static bool readFileToString(const std::string& filename, std::string* result) {
153 if (!android::base::ReadFileToString(filename, result)) {
154 PLOG(ERROR) << "Failed to read from " << filename;
155 return false;
156 }
157 return true;
158}
159
160static bool writeStringToFile(const std::string& payload, const std::string& filename) {
161 if (!android::base::WriteStringToFile(payload, filename)) {
162 PLOG(ERROR) << "Failed to write to " << filename;
163 return false;
164 }
165 return true;
166}
167
168static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir,
169 KeyPurpose purpose,
170 const AuthorizationSet &keyParams,
171 const AuthorizationSet &opParams,
172 AuthorizationSet* outParams) {
173 auto kmKeyPath = dir + "/" + kFn_keymaster_key_blob;
174 std::string kmKey;
175 if (!readFileToString(kmKeyPath, &kmKey)) return KeymasterOperation();
176 AuthorizationSet inParams(keyParams);
177 inParams.append(opParams.begin(), opParams.end());
178 for (;;) {
179 auto opHandle = keymaster.begin(purpose, kmKey, inParams, outParams);
180 if (opHandle) {
181 return opHandle;
182 }
183 if (opHandle.errorCode() != ErrorCode::KEY_REQUIRES_UPGRADE) return opHandle;
184 LOG(DEBUG) << "Upgrading key: " << dir;
185 std::string newKey;
186 if (!keymaster.upgradeKey(kmKey, keyParams, &newKey)) return KeymasterOperation();
187 // Upgrade the key in memory but do not replace the key in storage
188 /*auto newKeyPath = dir + "/" + kFn_keymaster_key_blob_upgraded;
189 if (!writeStringToFile(newKey, newKeyPath)) return KeymasterOperation();
190 if (rename(newKeyPath.c_str(), kmKeyPath.c_str()) != 0) {
191 PLOG(ERROR) << "Unable to move upgraded key to location: " << kmKeyPath;
192 return KeymasterOperation();
193 }
194 if (!keymaster.deleteKey(kmKey)) {
195 LOG(ERROR) << "Key deletion failed during upgrade, continuing anyway: " << dir;
196 }*/
197 kmKey = newKey;
198 LOG(INFO) << "Key upgraded: " << dir;
199 }
200}
201
202/*static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
203 const AuthorizationSet &keyParams,
204 const std::string& message, std::string* ciphertext) {
205 AuthorizationSet opParams;
206 AuthorizationSet outParams;
207 auto opHandle = begin(keymaster, dir, KeyPurpose::ENCRYPT, keyParams, opParams, &outParams);
208 if (!opHandle) return false;
209 auto nonceBlob = outParams.GetTagValue(TAG_NONCE);
210 if (!nonceBlob.isOk()) {
211 LOG(ERROR) << "GCM encryption but no nonce generated";
212 return false;
213 }
214 // nonceBlob here is just a pointer into existing data, must not be freed
215 std::string nonce(reinterpret_cast<const char*>(&nonceBlob.value()[0]), nonceBlob.value().size());
216 if (!checkSize("nonce", nonce.size(), GCM_NONCE_BYTES)) return false;
217 std::string body;
218 if (!opHandle.updateCompletely(message, &body)) return false;
219
220 std::string mac;
221 if (!opHandle.finish(&mac)) return false;
222 if (!checkSize("mac", mac.size(), GCM_MAC_BYTES)) return false;
223 *ciphertext = nonce + body + mac;
224 return true;
225}*/
226
227static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
228 const AuthorizationSet &keyParams,
229 const std::string& ciphertext, std::string* message) {
230 auto nonce = ciphertext.substr(0, GCM_NONCE_BYTES);
231 auto bodyAndMac = ciphertext.substr(GCM_NONCE_BYTES);
232 auto opParams = AuthorizationSetBuilder()
233 .Authorization(TAG_NONCE, blob2hidlVec(nonce));
234 auto opHandle = begin(keymaster, dir, KeyPurpose::DECRYPT, keyParams, opParams, nullptr);
235 if (!opHandle) return false;
236 if (!opHandle.updateCompletely(bodyAndMac, message)) return false;
237 if (!opHandle.finish(nullptr)) return false;
238 return true;
239}
240
241static std::string getStretching(const KeyAuthentication& auth) {
242 if (!auth.usesKeymaster()) {
243 return kStretch_none;
244 } else if (auth.secret.empty()) {
245 return kStretch_nopassword;
246 } else {
247 char paramstr[PROPERTY_VALUE_MAX];
248
249 property_get(SCRYPT_PROP, paramstr, SCRYPT_DEFAULTS);
250 return std::string() + kStretchPrefix_scrypt + paramstr;
251 }
252}
253
254static bool stretchingNeedsSalt(const std::string& stretching) {
255 return stretching != kStretch_nopassword && stretching != kStretch_none;
256}
257
258static bool stretchSecret(const std::string& stretching, const std::string& secret,
259 const std::string& salt, std::string* stretched) {
260 if (stretching == kStretch_nopassword) {
261 if (!secret.empty()) {
262 LOG(WARNING) << "Password present but stretching is nopassword";
263 // Continue anyway
264 }
265 stretched->clear();
266 } else if (stretching == kStretch_none) {
267 *stretched = secret;
268 } else if (std::equal(kStretchPrefix_scrypt.begin(), kStretchPrefix_scrypt.end(),
269 stretching.begin())) {
270 int Nf, rf, pf;
271 if (!parse_scrypt_parameters(stretching.substr(kStretchPrefix_scrypt.size()).c_str(), &Nf,
272 &rf, &pf)) {
273 LOG(ERROR) << "Unable to parse scrypt params in stretching: " << stretching;
274 return false;
275 }
276 stretched->assign(STRETCHED_BYTES, '\0');
277 if (crypto_scrypt(reinterpret_cast<const uint8_t*>(secret.data()), secret.size(),
278 reinterpret_cast<const uint8_t*>(salt.data()), salt.size(),
279 1 << Nf, 1 << rf, 1 << pf,
280 reinterpret_cast<uint8_t*>(&(*stretched)[0]), stretched->size()) != 0) {
281 LOG(ERROR) << "scrypt failed with params: " << stretching;
282 return false;
283 }
284 } else {
285 LOG(ERROR) << "Unknown stretching type: " << stretching;
286 return false;
287 }
288 return true;
289}
290
291static bool generateAppId(const KeyAuthentication& auth, const std::string& stretching,
292 const std::string& salt, const std::string& secdiscardable,
293 std::string* appId) {
294 std::string stretched;
295 if (!stretchSecret(stretching, auth.secret, salt, &stretched)) return false;
296 *appId = hashWithPrefix(kHashPrefix_secdiscardable, secdiscardable) + stretched;
297 return true;
298}
299
300static bool readRandomBytesOrLog(size_t count, std::string* out) {
301 auto status = ReadRandomBytes(count, *out);
302 if (status != OK) {
303 LOG(ERROR) << "Random read failed with status: " << status;
304 return false;
305 }
306 return true;
307}
308
309static void logOpensslError() {
310 LOG(ERROR) << "Openssl error: " << ERR_get_error();
311}
312
313static bool encryptWithoutKeymaster(const std::string& preKey,
314 const std::string& plaintext, std::string* ciphertext) {
315 auto key = hashWithPrefix(kHashPrefix_keygen, preKey);
316 key.resize(AES_KEY_BYTES);
317 if (!readRandomBytesOrLog(GCM_NONCE_BYTES, ciphertext)) return false;
318 auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>(
319 EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
320 if (!ctx) {
321 logOpensslError();
322 return false;
323 }
324 if (1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL,
325 reinterpret_cast<const uint8_t*>(key.data()),
326 reinterpret_cast<const uint8_t*>(ciphertext->data()))) {
327 logOpensslError();
328 return false;
329 }
330 ciphertext->resize(GCM_NONCE_BYTES + plaintext.size() + GCM_MAC_BYTES);
331 int outlen;
332 if (1 != EVP_EncryptUpdate(ctx.get(),
333 reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES), &outlen,
334 reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size())) {
335 logOpensslError();
336 return false;
337 }
338 if (outlen != static_cast<int>(plaintext.size())) {
339 LOG(ERROR) << "GCM ciphertext length should be " << plaintext.size() << " was " << outlen;
340 return false;
341 }
342 if (1 != EVP_EncryptFinal_ex(ctx.get(),
343 reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES + plaintext.size()), &outlen)) {
344 logOpensslError();
345 return false;
346 }
347 if (outlen != 0) {
348 LOG(ERROR) << "GCM EncryptFinal should be 0, was " << outlen;
349 return false;
350 }
351 if (1 != EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, GCM_MAC_BYTES,
352 reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES + plaintext.size()))) {
353 logOpensslError();
354 return false;
355 }
356 return true;
357}
358
359static bool decryptWithoutKeymaster(const std::string& preKey,
360 const std::string& ciphertext, std::string* plaintext) {
361 if (ciphertext.size() < GCM_NONCE_BYTES + GCM_MAC_BYTES) {
362 LOG(ERROR) << "GCM ciphertext too small: " << ciphertext.size();
363 return false;
364 }
365 auto key = hashWithPrefix(kHashPrefix_keygen, preKey);
366 key.resize(AES_KEY_BYTES);
367 auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>(
368 EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
369 if (!ctx) {
370 logOpensslError();
371 return false;
372 }
373 if (1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL,
374 reinterpret_cast<const uint8_t*>(key.data()),
375 reinterpret_cast<const uint8_t*>(ciphertext.data()))) {
376 logOpensslError();
377 return false;
378 }
379 plaintext->resize(ciphertext.size() - GCM_NONCE_BYTES - GCM_MAC_BYTES);
380 int outlen;
381 if (1 != EVP_DecryptUpdate(ctx.get(),
382 reinterpret_cast<uint8_t*>(&(*plaintext)[0]), &outlen,
383 reinterpret_cast<const uint8_t*>(ciphertext.data() + GCM_NONCE_BYTES), plaintext->size())) {
384 logOpensslError();
385 return false;
386 }
387 if (outlen != static_cast<int>(plaintext->size())) {
388 LOG(ERROR) << "GCM plaintext length should be " << plaintext->size() << " was " << outlen;
389 return false;
390 }
391 if (1 != EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, GCM_MAC_BYTES,
392 const_cast<void *>(
393 reinterpret_cast<const void*>(ciphertext.data() + GCM_NONCE_BYTES + plaintext->size())))) {
394 logOpensslError();
395 return false;
396 }
397 if (1 != EVP_DecryptFinal_ex(ctx.get(),
398 reinterpret_cast<uint8_t*>(&(*plaintext)[0] + plaintext->size()), &outlen)) {
399 logOpensslError();
400 return false;
401 }
402 if (outlen != 0) {
403 LOG(ERROR) << "GCM EncryptFinal should be 0, was " << outlen;
404 return false;
405 }
406 return true;
407}
408
409/*bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std::string& key) {
410 if (TEMP_FAILURE_RETRY(mkdir(dir.c_str(), 0700)) == -1) {
411 PLOG(ERROR) << "key mkdir " << dir;
412 return false;
413 }
414 if (!writeStringToFile(kCurrentVersion, dir + "/" + kFn_version)) return false;
415 std::string secdiscardable;
416 if (!readRandomBytesOrLog(SECDISCARDABLE_BYTES, &secdiscardable)) return false;
417 if (!writeStringToFile(secdiscardable, dir + "/" + kFn_secdiscardable)) return false;
418 std::string stretching = getStretching(auth);
419 if (!writeStringToFile(stretching, dir + "/" + kFn_stretching)) return false;
420 std::string salt;
421 if (stretchingNeedsSalt(stretching)) {
422 if (ReadRandomBytes(SALT_BYTES, salt) != OK) {
423 LOG(ERROR) << "Random read failed";
424 return false;
425 }
426 if (!writeStringToFile(salt, dir + "/" + kFn_salt)) return false;
427 }
428 std::string appId;
429 if (!generateAppId(auth, stretching, salt, secdiscardable, &appId)) return false;
430 std::string encryptedKey;
431 if (auth.usesKeymaster()) {
432 Keymaster keymaster;
433 if (!keymaster) return false;
434 std::string kmKey;
435 if (!generateKeymasterKey(keymaster, auth, appId, &kmKey)) return false;
436 if (!writeStringToFile(kmKey, dir + "/" + kFn_keymaster_key_blob)) return false;
437 auto keyParams = beginParams(auth, appId);
438 if (!encryptWithKeymasterKey(keymaster, dir, keyParams, key, &encryptedKey)) return false;
439 } else {
440 if (!encryptWithoutKeymaster(appId, key, &encryptedKey)) return false;
441 }
442 if (!writeStringToFile(encryptedKey, dir + "/" + kFn_encrypted_key)) return false;
443 return true;
444}*/
445
446bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, std::string* key) {
447 std::string version;
448 if (!readFileToString(dir + "/" + kFn_version, &version)) return false;
449 if (version != kCurrentVersion) {
450 LOG(ERROR) << "Version mismatch, expected " << kCurrentVersion << " got " << version;
451 return false;
452 }
453 std::string secdiscardable;
454 if (!readFileToString(dir + "/" + kFn_secdiscardable, &secdiscardable)) return false;
455 std::string stretching;
456 if (!readFileToString(dir + "/" + kFn_stretching, &stretching)) return false;
457 std::string salt;
458 if (stretchingNeedsSalt(stretching)) {
459 if (!readFileToString(dir + "/" + kFn_salt, &salt)) return false;
460 }
461 std::string appId;
462 if (!generateAppId(auth, stretching, salt, secdiscardable, &appId)) return false;
463 std::string encryptedMessage;
464 if (!readFileToString(dir + "/" + kFn_encrypted_key, &encryptedMessage)) return false;
465 if (auth.usesKeymaster()) {
466 Keymaster keymaster;
467 if (!keymaster) return false;
468 auto keyParams = beginParams(auth, appId);
469 if (!decryptWithKeymasterKey(keymaster, dir, keyParams, encryptedMessage, key)) return false;
470 } else {
471 if (!decryptWithoutKeymaster(appId, encryptedMessage, key)) return false;
472 }
473 return true;
474}
475
476static bool deleteKey(const std::string& dir) {
477 std::string kmKey;
478 if (!readFileToString(dir + "/" + kFn_keymaster_key_blob, &kmKey)) return false;
479 Keymaster keymaster;
480 if (!keymaster) return false;
481 if (!keymaster.deleteKey(kmKey)) return false;
482 return true;
483}
484
485static bool runSecdiscard(const std::string& dir) {
486 if (ForkExecvp(
487 std::vector<std::string>{kSecdiscardPath, "--",
488 dir + "/" + kFn_encrypted_key,
489 dir + "/" + kFn_keymaster_key_blob,
490 dir + "/" + kFn_secdiscardable,
491 }) != 0) {
492 LOG(ERROR) << "secdiscard failed";
493 return false;
494 }
495 return true;
496}
497
498bool runSecdiscardSingle(const std::string& file) {
499 if (ForkExecvp(
500 std::vector<std::string>{kSecdiscardPath, "--",
501 file}) != 0) {
502 LOG(ERROR) << "secdiscard failed";
503 return false;
504 }
505 return true;
506}
507
508static bool recursiveDeleteKey(const std::string& dir) {
509 if (ForkExecvp(std::vector<std::string>{kRmPath, "-rf", dir}) != 0) {
510 LOG(ERROR) << "recursive delete failed";
511 return false;
512 }
513 return true;
514}
515
516bool destroyKey(const std::string& dir) {
517 bool success = true;
518 // Try each thing, even if previous things failed.
519 success &= deleteKey(dir);
520 success &= runSecdiscard(dir);
521 success &= recursiveDeleteKey(dir);
522 return success;
523}
524
525} // namespace vold
526} // namespace android