blob: 737c64d71a1290556c13b9788d2af49e582c5cf1 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Interface used by "mount-encrypted" to interface with the TPM.
#ifndef CRYPTOHOME_MOUNT_ENCRYPTED_TPM_H_
#define CRYPTOHOME_MOUNT_ENCRYPTED_TPM_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <vector>
#include <base/files/file_path.h>
#include <base/macros.h>
#include <brillo/secure_blob.h>
#include <vboot/tlcl.h>
#include "cryptohome/mount_encrypted/mount_encrypted.h"
namespace mount_encrypted {
const uint32_t kLockboxSizeV1 = 0x2c;
const uint32_t kLockboxSizeV2 = 0x45;
#if USE_TPM2
const uint32_t kLockboxIndex = 0x800004;
const uint32_t kEncStatefulIndex = 0x800005;
const uint32_t kEncStatefulSize = 40;
#else
const uint32_t kLockboxIndex = 0x20000004;
const uint32_t kEncStatefulIndex = 0x20000005;
const uint32_t kEncStatefulSize = 72;
#endif
const uint32_t kPCRBootMode = 0;
// Secret used for owner authorization. This is used for taking ownership and in
// TPM commands that require owner authorization. Currently, only the TPM 1.2
// implementation uses owner authorization for some of its operations. The
// constants are nullptr and zero, respectively, for TPM 2.0.
extern const uint8_t* kOwnerSecret;
extern const size_t kOwnerSecretSize;
// Path constants. Note that these don't carry the / root prefix because the
// actual path gets constructed relative to a rootdir (which is a temporary
// directory in tests, the actual root directory for production).
namespace paths {
const char kFirmwareUpdateRequest[] =
"mnt/stateful_partition/unencrypted/preserve/tpm_firmware_update_request";
const char kFirmwareDir[] = "lib/firmware/tpm";
const char kFirmwareUpdateLocator[] = "usr/sbin/tpm-firmware-locate-update";
namespace cryptohome {
const char kTpmOwned[] = "mnt/stateful_partition/.tpm_owned";
const char kTpmStatus[] = "mnt/stateful_partition/.tpm_status";
const char kShallInitialize[] = "home/.shadow/.can_attempt_ownership";
const char kAttestationDatabase[] =
"mnt/stateful_partition/unencrypted/preserve/attestation.epb";
} // namespace cryptohome
} // namespace paths
class Tpm;
class NvramSpace {
public:
NvramSpace(Tpm* tpm, uint32_t index);
enum class Status {
kUnknown, // Not accessed yet.
kAbsent, // Not defined.
kValid, // Present and read was successful.
kTpmError, // Error accessing the space.
};
Status status() const { return status_; }
bool is_valid() const { return status() == Status::kValid; }
const brillo::SecureBlob& contents() const { return contents_; }
// Resets the space so that it appears invalid. Doesn't update the TPM.
void Reset();
// Retrieves the space attributes.
result_code GetAttributes(uint32_t* attributes);
// Attempts to read the NVRAM space.
result_code Read(uint32_t size);
// Writes to the NVRAM space.
result_code Write(const brillo::SecureBlob& contents);
// Sets the read lock on the space.
result_code ReadLock();
// Sets write lock on the space.
result_code WriteLock();
// Attempt to define the space with the given attributes and size.
result_code Define(uint32_t attributes,
uint32_t size,
uint32_t pcr_selection);
// Check whether the space is bound to the specified PCR selection.
result_code CheckPCRBinding(uint32_t pcr_selection, bool* match);
private:
// Reads space definition parameters from the TPM.
result_code GetSpaceInfo();
// Get the binding policy for the current PCR values of the given PCR
// selection.
result_code GetPCRBindingPolicy(uint32_t pcr_selection,
std::vector<uint8_t>* policy);
Tpm* tpm_;
uint32_t index_;
// Cached copy of NVRAM space attributes.
uint32_t attributes_;
// Cached copy of the auth policy.
std::vector<uint8_t> auth_policy_;
// Cached copy of the data as read from the space.
brillo::SecureBlob contents_;
// Cached indicator reflecting the status of the space in the TPM.
Status status_ = Status::kUnknown;
};
// Encapsulates high-level TPM state and the motions needed to open and close
// the TPM library.
class Tpm {
public:
Tpm();
Tpm(const Tpm&) = delete;
Tpm& operator=(const Tpm&) = delete;
~Tpm();
bool available() const { return available_; }
bool is_tpm2() const { return is_tpm2_; }
result_code IsOwned(bool* owned);
result_code GetRandomBytes(uint8_t* buffer, int wanted);
// Returns the PCR value for PCR |index|, possibly from the cache.
result_code ReadPCR(uint32_t index, std::vector<uint8_t>* value);
// Returns TPM version info.
bool GetVersionInfo(uint32_t* vendor,
uint64_t* firmware_version,
std::vector<uint8_t>* vendor_specific);
// Returns Infineon-specific field upgrade status.
bool GetIFXFieldUpgradeInfo(TPM_IFX_FIELDUPGRADEINFO* field_upgrade_info);
// Returns the initialized lockbox NVRAM space.
NvramSpace* GetLockboxSpace();
// Get the initialized encrypted stateful space.
NvramSpace* GetEncStatefulSpace();
// Take TPM ownership using an all-zeros password.
result_code TakeOwnership();
// Set a flag in the TPM to indicate that the system key has been
// re-initialized after the last TPM clear. The TPM automatically clears the
// flag as a side effect of the TPM clear operation.
result_code SetSystemKeyInitializedFlag();
// Check the system key initialized flag.
result_code HasSystemKeyInitializedFlag(bool* flag_value);
private:
bool available_ = false;
bool is_tpm2_ = false;
bool ownership_checked_ = false;
bool owned_ = false;
#if !USE_TPM2
bool initialized_flag_checked_ = false;
bool initialized_flag_ = false;
#endif // !USE_TPM2
std::map<uint32_t, std::vector<uint8_t>> pcr_values_;
std::unique_ptr<NvramSpace> lockbox_space_;
std::unique_ptr<NvramSpace> encstateful_space_;
};
// The interface used by the key handling logic to access the system key. The
// system key is used to wrap the actual data encryption key.
//
// System keys must have these properties:
// 1. The system key can only be accessed in the current boot mode, i.e.
// switching to developer mode blocks access or destroys the system key.
// 2. A fresh system key must be generated after clearing the TPM. This can be
// achieved either by arranging a TPM clear to drop the key or by detecting
// a TPM clear an generating a fresh key.
// 3. The key should ideally not be accessible for reading after early boot.
// 4. Because mounting the encrypted stateful file system is on the critical
// boot path, loading the system key must be reasonably fast.
// 5. Fresh keys can be generated with reasonable cost. Costly operations such
// as taking TPM ownership after each TPM clear to set up fresh NVRAM spaces
// do not fly performance-wise. The file system encryption key logic has a
// fallback path to dump its key without protection by a system key until
// the latter becomes available, but that's a risk that should ideally be
// avoided.
class SystemKeyLoader {
public:
virtual ~SystemKeyLoader() = default;
// Create a system key loader suitable for the system.
static std::unique_ptr<SystemKeyLoader> Create(Tpm* tpm,
const base::FilePath& rootdir);
// Load the encryption key from TPM NVRAM. Returns true if successful and
// fills in key, false if the key is not available or there is an error.
virtual result_code Load(brillo::SecureBlob* key) = 0;
// Initializes system key NV space contents using |key_material|.
// The size of |key_material| must equal DIGEST_LENGTH. If
// |derived_system_key| is not null, stores the derived system key into it.
//
// This function does not store the contents in NVRAM yet.
//
// Returns RESULT_SUCCESS if successful or RESULT_FAIL_FATAL otherwise.
virtual result_code Initialize(const brillo::SecureBlob& key_material,
brillo::SecureBlob* derived_system_key) = 0;
// Persist a previously generated system key in NVRAM. This may not be
// possible in case the TPM is not in a state where the NVRAM spaces can be
// manipulated.
virtual result_code Persist() = 0;
// Lock the system key to prevent further manipulation.
virtual void Lock() = 0;
// Set up the TPM to allow generation of a system key. This is an expensive
// operation that can take dozens of seconds depending on hardware so this
// can't be used routinely.
virtual result_code SetupTpm() = 0;
// Checks whether the system is eligible for encryption key preservation. If
// so, sets up a new system key to wrap the existing encryption key. On
// success, |previous_key| and |fresh_key| will be filled in. Returns false if
// the system is not eligible or there is an error.
virtual result_code GenerateForPreservation(
brillo::SecureBlob* previous_key, brillo::SecureBlob* fresh_key) = 0;
// Checks whether the lockbox space contents are considered valid.
virtual result_code CheckLockbox(bool* valid) = 0;
// Whether the lockbox salt is used as the system key.
virtual bool UsingLockboxKey() = 0;
};
// A SystemKeyLoader implementation backed by a fixed system key supplied at
// construction time.
class FixedSystemKeyLoader : public SystemKeyLoader {
public:
explicit FixedSystemKeyLoader(const brillo::SecureBlob& key) : key_(key) {}
virtual ~FixedSystemKeyLoader() = default;
result_code Load(brillo::SecureBlob* key) override {
*key = key_;
return RESULT_SUCCESS;
}
result_code Initialize(const brillo::SecureBlob& key_material,
brillo::SecureBlob* derived_system_key) override {
return RESULT_FAIL_FATAL;
}
result_code Persist() override { return RESULT_FAIL_FATAL; }
void Lock() override {}
result_code SetupTpm() override { return RESULT_FAIL_FATAL; }
result_code GenerateForPreservation(brillo::SecureBlob* previous_key,
brillo::SecureBlob* fresh_key) override {
return RESULT_FAIL_FATAL;
}
result_code CheckLockbox(bool* valid) override { return RESULT_FAIL_FATAL; }
bool UsingLockboxKey() override { return false; }
private:
brillo::SecureBlob key_;
};
} // namespace mount_encrypted
#endif // CRYPTOHOME_MOUNT_ENCRYPTED_TPM_H_