blob: 075e0f5ad9b67fa0230dc95eeb2eafd6b81eb84e [file] [log] [blame]
// Copyright 2020 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CRYPTOHOME_LE_CREDENTIAL_MANAGER_IMPL_H_
#define CRYPTOHOME_LE_CREDENTIAL_MANAGER_IMPL_H_
#include "cryptohome/le_credential_manager.h"
#include <map>
#include <memory>
#include <optional>
#include <vector>
#include <libhwsec/frontend/pinweaver/frontend.h>
#include "cryptohome/sign_in_hash_tree.h"
namespace cryptohome {
// Class containing all logic pertaining to management of Low Entropy(LE)
// credentials. The stated aim of this class should be the following:
// - Provide an interface to Set and Remove credentials in the underlying
// storage.
// - Provide an interface to verify a credential.
//
// This class contains a SignInHashTree object, which is used to store and
// maintain the credentials on disk.
//
// It also contains a pointer to a TPM object which will be able to invoke the
// necessary commands on the TPM side, for verification.
class LECredentialManagerImpl : public LECredentialManager {
public:
explicit LECredentialManagerImpl(const hwsec::PinWeaverFrontend* pinweaver,
const base::FilePath& le_basedir);
virtual ~LECredentialManagerImpl() {}
LECredStatus InsertCredential(
const std::vector<hwsec::OperationPolicySetting>& policies,
const brillo::SecureBlob& le_secret,
const brillo::SecureBlob& he_secret,
const brillo::SecureBlob& reset_secret,
const DelaySchedule& delay_sched,
std::optional<uint32_t> expiration_delay,
uint64_t* ret_label) override;
LECredStatus CheckCredential(uint64_t label,
const brillo::SecureBlob& le_secret,
brillo::SecureBlob* he_secret,
brillo::SecureBlob* reset_secret) override;
LECredStatus ResetCredential(uint64_t label,
const brillo::SecureBlob& reset_secret,
bool strong_reset) override;
LECredStatus RemoveCredential(uint64_t label) override;
// Returns the number of wrong authentication attempts done since the label
// was reset or created. Returns -1 if |label| is not present in the tree or
// the tree is corrupted.
int GetWrongAuthAttempts(uint64_t label) override;
LECredStatusOr<uint32_t> GetDelayInSeconds(uint64_t label) override;
LECredStatusOr<std::optional<uint32_t>> GetExpirationInSeconds(
uint64_t label) override;
LECredStatusOr<DelaySchedule> GetDelaySchedule(uint64_t label) override;
LECredStatus InsertRateLimiter(
uint8_t auth_channel,
const std::vector<hwsec::OperationPolicySetting>& policies,
const brillo::SecureBlob& reset_secret,
const DelaySchedule& delay_sched,
std::optional<uint32_t> expiration_delay,
uint64_t* ret_label) override;
LECredStatusOr<StartBiometricsAuthReply> StartBiometricsAuth(
uint8_t auth_channel,
uint64_t label,
const brillo::Blob& client_nonce) override;
private:
// Helper to turn a label into an original credential. Helper for a lot of the
// Get* functions which starts with a label and first need to turn it into a
// credential to call the actual Pinweaver function they need to call.
//
// The le_operation_type string specifies the type parameter that will be
// passed to ReportLEResult to report metrics on LE operation success and
// failure.
LECredStatusOr<brillo::Blob> GetCredentialMetadata(
uint64_t label, const char* le_operation_type);
// Since the InsertCredential() and InsertRateLimiter() functions are very
// similar, this function combines the common parts of both the calls
// into a generic "insert leaf" function. |auth_channel| is only valid in
// InsertRateLimiter(), while |le_secret| and |he_secret| is only valid in
// InsertCredential(). |is_rate_limiter| is used to signal whether the leaf
// being inserted is a rate-limiter (true) or a normal credential (false).
//
// On success, returns OkStatus and stores the
// newly provisioned label in |ret_label|.
//
// On failure, returns status with:
// - LE_CRED_ERROR_NO_FREE_LABEL if there is no free label.
// - LE_CRED_ERROR_HASH_TREE if there was an error in the hash tree.
//
// The returned label should be placed into the metadata associated with the
// authentication factor. so that it can be used to look up the credential
// later.
LECredStatus InsertLeaf(
uint8_t* auth_channel,
const std::vector<hwsec::OperationPolicySetting>& policies,
const brillo::SecureBlob* le_secret,
const brillo::SecureBlob* he_secret,
const brillo::SecureBlob& reset_secret,
const DelaySchedule& delay_sched,
std::optional<uint32_t> expiration_delay,
bool is_rate_limiter,
uint64_t* ret_label);
// Since the CheckCredential() and ResetCredential() functions are very
// similar, this function combines the common parts of both the calls
// into a generic "check credential" function. The label to be checked
// is stored in |label|, the secret to be verified is in |secret|, the
// high entropy credential and reset secret which gets released on successful
// verification are stored in |he_secret| and |reset_secret|. A flag
// |is_le_secret| is used to signal whether the secret being checked is the LE
// secret (true) or the reset secret (false).
//
// Returns OkStatus on success.
//
// On failure, returns a status with:
// - LE_CRED_ERROR_INVALID_LE_SECRET for incorrect LE authentication attempt.
// - LE_CRED_ERROR_INVALID_RESET_SECRET for incorrect reset secret.
// incorrect attempts).
// - LE_CRED_ERROR_HASH_TREE for error in hash tree.
// - LE_CRED_ERROR_INVALID_LABEL for invalid label.
// - LE_CRED_ERROR_INVALID_METADATA for invalid credential metadata.
// - LE_CRED_ERROR_PCR_NOT_MATCH if the PCR registers from TPM have unexpected
// values, in which case only reboot will allow this user to authenticate.
LECredStatus CheckSecret(uint64_t label,
const brillo::SecureBlob& secret,
brillo::SecureBlob* he_secret,
brillo::SecureBlob* reset_secret,
bool strong_reset,
bool is_le_secret);
// Helper function to perform RemoveCredential. The |during_sync| param is
// provided because RemoveCredential is one of the steps need to be performed
// during a sync. If it checks Sync() again, there might potentially be a
// infinite recursion.
LECredStatus RemoveCredentialInternal(uint64_t label, bool during_sync);
// Helper function to retrieve the credential metadata, MAC, and auxiliary
// hashes associated with a label |label| (stored in |cred_metadata|, |mac|
// and |h_aux| respectively). |metadata_lost| will denote whether the label
// contains valid metadata (false) or not (true).
//
// Returns OkStatus on success.
// On failure, returns a status with:
// - LE_CRED_ERROR_INVALID_LABEL if the label provided doesn't exist.
// - LE_CRED_ERROR_HASH_TREE if there was hash tree error (possibly out of
// sync).
LECredStatus RetrieveLabelInfo(const SignInHashTree::Label& label,
brillo::Blob* cred_metadata,
brillo::Blob* mac,
std::vector<brillo::Blob>* h_aux,
bool* metadata_lost);
// Given a label, gets the list of auxiliary hashes for that label.
// On failure, returns an empty vector.
std::vector<brillo::Blob> GetAuxHashes(const SignInHashTree::Label& label);
// Converts the error returned from LECredentialBackend to the equivalent
// LECredError.
LECredError BackendErrorToCredError(
hwsec::PinWeaverFrontend::CredentialTreeResult::ErrorCode err);
// Converts the error returned from LECredentialBackend to a LECredStatus.
LECredStatus ConvertTpmError(
hwsec::PinWeaverFrontend::CredentialTreeResult::ErrorCode err);
// Performs checks to ensure the SignInHashTree is in sync with the tree
// state in the LECredentialBackend. If there is an out-of-sync situation,
// this function also attempts to get the HashTree back in sync.
//
// Returns true on successful synchronization, and false on failure. On
// failure, |is_locked_| will be set to true, to prevent further
// operations during the class lifecycle.
bool Sync();
// Replays the InsertCredential operation using the information provided
// from the log entry from the LE credential backend.
// |label| denotes which label to perform the operation on,
// |log_root| is what the root hash should be after this operation is
// completed. It should directly be used from the log entry.
// |mac| is the MAC of the credential which has to be inserted.
//
// Returns true on success, false on failure.
//
// NOTE: A replayed insert is unusable and should be deleted after the replay
// is complete.
bool ReplayInsert(uint64_t label,
const brillo::Blob& log_root,
const brillo::Blob& mac);
// Replays the CheckCredential / ResetCredential operation using the
// information provided from the log entry from the LE credential
// backend.
// |label| denotes which credential label to perform the operation on.
// |log_root| is what the root hash should be after this operation is
// completed. It should directly be used from the log entry.
// |is_full_replay| is whether the log_replay is done with successfully
// locating the current root hash in the log entries, or done with replaying
// using all entries.
//
// Returns true on success, false on failure.
bool ReplayCheck(uint64_t label,
const brillo::Blob& log_root,
bool is_full_replay);
// Resets the HashTree.
bool ReplayResetTree();
// Replays the RemoveCredential for |label| which is provided from
// the LE Backend Replay logs.
//
// Returns true on success, false otherwise.
bool ReplayRemove(uint64_t label);
// Replays all the log operations provided in |log|, and makes the
// corresponding updates to the HashTree.
bool ReplayLogEntries(
const std::vector<hwsec::PinWeaverFrontend::GetLogResult::LogEntry>& log,
const brillo::Blob& disk_root_hash);
// Last resort flag which prevents any further Low Entropy operations from
// occurring, till the next time the class is instantiated.
// This is used in a situation where an operation succeeds on the TPM,
// but its on-disk counterpart fails. In this case, the mitigation strategy
// is as follows:
// - Prevent any further LE operations, to prevent disk and TPM from
// going further out of state, till next reboot.
// - Hope that on reboot, the problems causing disk failure don't recur,
// and the TPM replay log will enable the disk state to get in sync with
// the TPM again.
//
// We will collect UMA stats from the field and refine this strategy
// as required.
bool is_locked_;
// Pointer to an implementation of the pinweaver operations.
const hwsec::PinWeaverFrontend* pinweaver_;
// In-memory copy of LEBackend's root hash value.
brillo::Blob root_hash_;
// Directory where all LE Credential related data is stored.
base::FilePath basedir_;
std::unique_ptr<SignInHashTree> hash_tree_;
};
} // namespace cryptohome
#endif // CRYPTOHOME_LE_CREDENTIAL_MANAGER_IMPL_H_