Files
android_bootable_recovery/crypto/fscrypt/Keymaster.h
bigbiff bbbfe171f1 fscrypt: updates for wrapped key
- During OTA upgrades if security state or ROT changes then Keymaster
keys requires upgrade. So for such usescases, if the FBE ephemeral
key export fails, check whether KM key requires upgrade and try for
exporting ephemeral key again.

CRs-Fixed: 2632902
Change-Id: I3ee2fcd97a56b628dc4304867c8f2b8da875f883
Signed-off-by: Neeraj Soni <neersoni@codeaurora.org>

- Commit 77df7f2 / http://aosp/1217657 ("Refactor to use
EncryptionPolicy everywhere we used to use raw_ref") unintentionally
made fscrypt_initialize_systemwide_keys() start specifying keepOld=true
(via default parameter value) when retrieving the system DE key, and
likewise for read_or_create_volkey() and volume keys.

As a result, if the associated Keymaster key needs to be upgraded, the
upgraded key blob gets written to "keymaster_key_blob_upgraded", but it
doesn't replace the original "keymaster_key_blob", nor is the original
key deleted from Keymaster.  This happens at every boot, eventually
resulting in the RPMB partition in Keymaster becoming full.

Only the metadata encryption key ever needs keepOld=true, since it's the
only key that isn't stored in /data, and the purpose of keepOld=true is
to allow a key that isn't stored in /data to be committed or rolled back
when a userdata checkpoint is committed or rolled back.

So, fix this bug by removing the default value of keepOld, and
specifying false everywhere except the metadata encryption key.

Note that when an affected device gets this fix, it will finally upgrade
its system DE key correctly.  However, this fix doesn't free up space in
Keymaster that was consumed by this bug.

Test: On bramble:
  - Flashed rvc-d1-dev build, with wiping userdata
  - Flashed a newer build, without wiping userdata
  - Log expectedly shows key upgrades:
        $ adb logcat | grep 'Upgrading key'
        D vold    : Upgrading key:
/metadata/vold/metadata_encryption/key
        D vold    : Upgrading key: /data/unencrypted/key
        D vold    : Upgrading key: /data/misc/vold/user_keys/de/0
        D vold    : Upgrading key:
/data/misc/vold/user_keys/ce/0/current
  - Rebooted
  - Log unexpectedly shows the system DE key being upgraded again:
        $ adb logcat | grep 'Upgrading key'
        D vold    : Upgrading key: /data/unencrypted/key
  - "keymaster_key_blob_upgraded" unexpectedly still exists:
        $ adb shell find /data /metadata -name
keymaster_key_blob_upgraded
        /data/unencrypted/key/keymaster_key_blob_upgraded
  - Applied this fix and flashed, without wiping userdata
  - Log shows system DE key being upgraded (expected because due to the
    bug, the upgraded key didn't replace the original one before)
        $ adb logcat | grep 'Upgrading key'
        D vold    : Upgrading key: /data/unencrypted/key
  - "keymaster_key_blob_upgraded" expectedly no longer exists
        $ adb shell find /data /metadata -name
keymaster_key_blob_upgraded
  - Rebooted
  - Log expectedly doesn't show any more key upgrades
        $ adb logcat | grep 'Upgrading key'
Bug: 171944521
Bug: 172019387
(cherry picked from commit c493903732d0c17b33091cf722cbcc3262292801)
Merged-In: I42d3f5fbe32cb2ec229f4b614cfb271412a3ed29
Change-Id: I42d3f5fbe32cb2ec229f4b614cfb271412a3ed29

Change-Id: I0449b812e91c13020a8b653f2149c33e46027b97
2021-06-25 18:42:20 -04:00

172 lines
6.7 KiB
C++

/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_VOLD_KEYMASTER_H
#define ANDROID_VOLD_KEYMASTER_H
#include "KeyBuffer.h"
#include <memory>
#include <string>
#include <utility>
#include <android-base/macros.h>
#include <keymasterV4_1/Keymaster.h>
#include <keymasterV4_1/authorization_set.h>
namespace km {
using namespace ::android::hardware::keymaster::V4_1;
// Surprisingly -- to me, at least -- this is totally fine. You can re-define symbols that were
// brought in via a using directive (the "using namespace") above. In general this seems like a
// dangerous thing to rely on, but in this case its implications are simple and straightforward:
// km::ErrorCode refers to the 4.0 ErrorCode, though we pull everything else from 4.1.
using ErrorCode = ::android::hardware::keymaster::V4_0::ErrorCode;
using V4_1_ErrorCode = ::android::hardware::keymaster::V4_1::ErrorCode;
} // namespace km
using KmDevice = km::support::Keymaster;
// C++ wrappers to the Keymaster hidl interface.
// This is tailored to the needs of KeyStorage, but could be extended to be
// a more general interface.
// Wrapper for a Keymaster operation handle representing an
// ongoing Keymaster operation. Aborts the operation
// in the destructor if it is unfinished. Methods log failures
// to LOG(ERROR).
class KeymasterOperation {
public:
~KeymasterOperation();
// Is this instance valid? This is false if creation fails, and becomes
// false on finish or if an update fails.
explicit operator bool() const { return mError == km::ErrorCode::OK; }
km::ErrorCode errorCode() const { return mError; }
// Call "update" repeatedly until all of the input is consumed, and
// concatenate the output. Return true on success.
template <class TI, class TO>
bool updateCompletely(TI& input, TO* output) {
if (output) output->clear();
return updateCompletely(input.data(), input.size(), [&](const char* b, size_t n) {
if (output) std::copy(b, b + n, std::back_inserter(*output));
});
}
// Finish and write the output to this string, unless pointer is null.
bool finish(std::string* output);
// Move constructor
KeymasterOperation(KeymasterOperation&& rhs) { *this = std::move(rhs); }
// Construct an object in an error state for error returns
KeymasterOperation() : mDevice{nullptr}, mOpHandle{0}, mError{km::ErrorCode::UNKNOWN_ERROR} {}
// Move Assignment
KeymasterOperation& operator=(KeymasterOperation&& rhs) {
mDevice = rhs.mDevice;
rhs.mDevice = nullptr;
mOpHandle = rhs.mOpHandle;
rhs.mOpHandle = 0;
mError = rhs.mError;
rhs.mError = km::ErrorCode::UNKNOWN_ERROR;
return *this;
}
private:
KeymasterOperation(KmDevice* d, uint64_t h)
: mDevice{d}, mOpHandle{h}, mError{km::ErrorCode::OK} {}
KeymasterOperation(km::ErrorCode error) : mDevice{nullptr}, mOpHandle{0}, mError{error} {}
bool updateCompletely(const char* input, size_t inputLen,
const std::function<void(const char*, size_t)> consumer);
KmDevice* mDevice;
uint64_t mOpHandle;
km::ErrorCode mError;
DISALLOW_COPY_AND_ASSIGN(KeymasterOperation);
friend class Keymaster;
};
// Wrapper for a Keymaster device for methods that start a KeymasterOperation or are not
// part of one.
class Keymaster {
public:
Keymaster();
// false if we failed to open the keymaster device.
explicit operator bool() { return mDevice.get() != nullptr; }
// Generate a key in the keymaster from the given params.
bool generateKey(const km::AuthorizationSet& inParams, std::string* key);
// Exports a keymaster key with STORAGE_KEY tag wrapped with a per-boot ephemeral key
km::ErrorCode exportKey(const KeyBuffer& kmKey, std::string* key);
// If the keymaster supports it, permanently delete a key.
bool deleteKey(const std::string& key);
// Replace stored key blob in response to KM_ERROR_KEY_REQUIRES_UPGRADE.
bool upgradeKey(const std::string& oldKey, const km::AuthorizationSet& inParams,
std::string* newKey);
// Begin a new cryptographic operation, collecting output parameters if pointer is non-null
KeymasterOperation begin(km::KeyPurpose purpose, const std::string& key,
const km::AuthorizationSet& inParams,
const km::HardwareAuthToken& authToken,
km::AuthorizationSet* outParams);
bool isSecure();
// Tell all Keymaster instances that early boot has ended and early boot-only keys can no longer
// be created or used.
static void earlyBootEnded();
private:
android::sp<KmDevice> mDevice;
DISALLOW_COPY_AND_ASSIGN(Keymaster);
static bool hmacKeyGenerated;
};
// FIXME no longer needed now cryptfs is in C++.
/*
* The following functions provide C bindings to keymaster services
* needed by cryptfs scrypt. The compatibility check checks whether
* the keymaster implementation is considered secure, i.e., TEE backed.
* The create_key function generates an RSA key for signing.
* The sign_object function signes an object with the given keymaster
* key.
*/
/* Return values for keymaster_sign_object_for_cryptfs_scrypt */
enum class KeymasterSignResult {
ok = 0,
error = -1,
upgrade = -2,
};
int keymaster_compatibility_cryptfs_scrypt();
int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size, uint64_t rsa_exponent,
uint32_t ratelimit, uint8_t* key_buffer,
uint32_t key_buffer_size, uint32_t* key_out_size);
int keymaster_upgrade_key_for_cryptfs_scrypt(uint32_t rsa_key_size, uint64_t rsa_exponent,
uint32_t ratelimit, const uint8_t* key_blob,
size_t key_blob_size, uint8_t* key_buffer,
uint32_t key_buffer_size, uint32_t* key_out_size);
KeymasterSignResult keymaster_sign_object_for_cryptfs_scrypt(
const uint8_t* key_blob, size_t key_blob_size, uint32_t ratelimit, const uint8_t* object,
const size_t object_size, uint8_t** signature_buffer, size_t* signature_buffer_size);
#endif