//
// Copyright (C) 2014 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 TRUNKS_TPM_UTILITY_H_
#define TRUNKS_TPM_UTILITY_H_
#include <string>
#include <vector>
#include <base/macros.h>
#include "trunks/hmac_session.h"
#include "trunks/tpm_generated.h"
#include "trunks/trunks_export.h"
namespace trunks {
// These handles will be used by TpmUtility to create storage root keys.
const TPMI_DH_PERSISTENT kRSAStorageRootKey = PERSISTENT_FIRST;
const TPMI_DH_PERSISTENT kECCStorageRootKey = PERSISTENT_FIRST + 1;
const TPMI_DH_PERSISTENT kSaltingKey = PERSISTENT_FIRST + 2;
// This value to used to specify that no pcr are needed in the creation data
// for a key.
const int kNoCreationPCR = -1;
// An interface which provides convenient methods for common TPM operations.
class TRUNKS_EXPORT TpmUtility {
public:
enum AsymmetricKeyUsage { kDecryptKey, kSignKey, kDecryptAndSignKey };
TpmUtility() {}
virtual ~TpmUtility() {}
// Synchronously performs a TPM startup sequence and self tests. Typically
// this is done by the platform firmware. Returns the result of the startup
// and self-tests or, if already started, just the result of the self-tests.
virtual TPM_RC Startup() = 0;
// This method removes all TPM context associated with a specific Owner.
// As part of this process, it resets the SPS to a new random value, and
// clears ownerAuth, endorsementAuth and lockoutAuth.
// NOTE: This method needs to be called before InitializeTPM.
virtual TPM_RC Clear() = 0;
// Synchronously performs a TPM shutdown operation. It should always be
// successful.
virtual void Shutdown() = 0;
// Synchronously prepares a TPM for use by Chromium OS. Typically this is done
// by the platform firmware and, in that case, this method has no effect.
virtual TPM_RC InitializeTpm() = 0;
// Synchronously allocates the PCRs in the TPM. Currently we allocate
// the first 16 PCRs to use the SHA-256 hash algorithm.
// NOTE: PCR allocation only takes place at the next TPM_Startup call.
// NOTE: This command needs platform authorization and PP assertion.
virtual TPM_RC AllocatePCR(const std::string& platform_password) = 0;
// Synchronously takes ownership of the TPM with the given passwords as
// authorization values.
virtual TPM_RC TakeOwnership(const std::string& owner_password,
const std::string& endorsement_password,
const std::string& lockout_password) = 0;
// Stir the tpm random generation module with some random entropy data.
// |delegate| specifies an optional authorization delegate to be used.
virtual TPM_RC StirRandom(const std::string& entropy_data,
AuthorizationDelegate* delegate) = 0;
// This method returns |num_bytes| of random data generated by the tpm.
// |delegate| specifies an optional authorization delegate to be used.
virtual TPM_RC GenerateRandom(size_t num_bytes,
AuthorizationDelegate* delegate,
std::string* random_data) = 0;
// This method extends the pcr specified by |pcr_index| with the SHA256
// hash of |extend_data|. The exact action performed is
// TPM2_PCR_Extend(Sha256(extend_data));
// |delegate| specifies an optional authorization delegate to be used.
virtual TPM_RC ExtendPCR(int pcr_index,
const std::string& extend_data,
AuthorizationDelegate* delegate) = 0;
// This method reads the pcr specified by |pcr_index| and returns its value
// in |pcr_value|. NOTE: it assumes we are using SHA256 as our hash alg.
virtual TPM_RC ReadPCR(int pcr_index, std::string* pcr_value) = 0;
// This method performs an encryption operation using a LOADED RSA key
// referrenced by its handle |key_handle|. The |plaintext| is then encrypted
// to give us the |ciphertext|. |scheme| refers to the encryption scheme
// to be used. By default keys use OAEP, but can also use TPM_ALG_RSAES.
// |delegate| specifies an optional authorization delegate to be used.
virtual TPM_RC AsymmetricEncrypt(TPM_HANDLE key_handle,
TPM_ALG_ID scheme,
TPM_ALG_ID hash_alg,
const std::string& plaintext,
AuthorizationDelegate* delegate,
std::string* ciphertext) = 0;
// This method performs a decryption operating using a loaded RSA key
// referenced by its handle |key_handle|. The |ciphertext| is then decrypted
// to give us the |plaintext|. |scheme| refers to the decryption scheme
// used. By default it is OAEP, but TPM_ALG_RSAES can be specified.
// |delegate| is an AuthorizationDelegate used to authorize this command.
virtual TPM_RC AsymmetricDecrypt(TPM_HANDLE key_handle,
TPM_ALG_ID scheme,
TPM_ALG_ID hash_alg,
const std::string& ciphertext,
AuthorizationDelegate* delegate,
std::string* plaintext) = 0;
// This method takes an unrestricted signing key referenced by |key_handle|
// and uses it to sign the hash of |plaintext|. The signature produced is
// returned using the |signature| argument. |scheme| is used to specify the
// signature scheme used. By default it is TPM_ALG_RSASSA, but TPM_ALG_RSAPPS
// can be specified. |hash_alg| is the algorithm used in the signing
// operation. It is by default TPM_ALG_SHA256.
// |delegate| is an AuthorizationDelegate used to authorize this command.
virtual TPM_RC Sign(TPM_HANDLE key_handle,
TPM_ALG_ID scheme,
TPM_ALG_ID hash_alg,
const std::string& plaintext,
AuthorizationDelegate* delegate,
std::string* signature) = 0;
// This method verifies that the signature produced on the plaintext was
// performed by |key_handle|. |scheme| and |hash| refer to the signature
// scheme used to sign the hash of |plaintext| and produce the signature.
// This value is by default TPM_ALG_RSASSA with TPM_ALG_SHA256 but can take
// the value of TPM_ALG_RSAPPS with other hash algorithms supported by the
// tpm. Returns TPM_RC_SUCCESS when the signature is correct.
// |delegate| specifies an optional authorization delegate to be used.
virtual TPM_RC Verify(TPM_HANDLE key_handle,
TPM_ALG_ID scheme,
TPM_ALG_ID hash_alg,
const std::string& plaintext,
const std::string& signature,
AuthorizationDelegate* delegate) = 0;
// This method is used to check if a key was created in the TPM. |key_handle|
// refers to a loaded Tpm2.0 object, and |creation_blob| is the blob
// generated when the object was created. Returns TPM_RC_SUCCESS iff the
// object was created in the TPM.
virtual TPM_RC CertifyCreation(TPM_HANDLE key_handle,
const std::string& creation_blob) = 0;
// This method is used to change the authorization value associated with a
// |key_handle| to |new_password|. |delegate| is an AuthorizationDelegate
// that is loaded with the old authorization value of |key_handle|.
// When |key_blob| is not null, it is populated with the new encrypted key
// blob. Note: the key must be unloaded and reloaded to use the
// new authorization value.
virtual TPM_RC ChangeKeyAuthorizationData(TPM_HANDLE key_handle,
const std::string& new_password,
AuthorizationDelegate* delegate,
std::string* key_blob) = 0;
// This method imports an external RSA key of |key_type| into the TPM.
// |modulus| and |prime_factor| are interpreted as raw bytes in big-endian
// order. If the out argument |key_blob| is not null, it is populated with
// the imported key, which can then be loaded into the TPM.
virtual TPM_RC ImportRSAKey(AsymmetricKeyUsage key_type,
const std::string& modulus,
uint32_t public_exponent,
const std::string& prime_factor,
const std::string& password,
AuthorizationDelegate* delegate,
std::string* key_blob) = 0;
// This method uses the TPM to generates an RSA key of type |key_type|.
// |modulus_bits| is used to specify the size of the modulus, and
// |public_exponent| specifies the exponent of the key. After this function
// terminates, |key_blob| contains a key blob that can be loaded into the TPM.
// |policy_digest| specifies an optional policy to use to authorize this key.
// |use_only_policy_authorization| specifies if we can use HmacSession in
// addition to PolicySession to authorize use of this key.
// |creation_pcr_index| allows the caller to specify a pcr value to include
// in the creation data. If no pcr are needed in the creation data, this
// argument can take the value of kNoCreationPCR.
// If the |creation_blob| out param is defined, it will contain the
// serialized creation structures generated by the TPM.
// This can be used to verify the state of the TPM during key creation.
// NOTE: if |use_only_policy_authorization| is set to true,
// parameter_encryption must be disabled when the key is used.
virtual TPM_RC CreateRSAKeyPair(AsymmetricKeyUsage key_type,
int modulus_bits,
uint32_t public_exponent,
const std::string& password,
const std::string& policy_digest,
bool use_only_policy_authorization,
int creation_pcr_index,
AuthorizationDelegate* delegate,
std::string* key_blob,
std::string* creation_blob) = 0;
// This method loads a pregenerated TPM key into the TPM. |key_blob| contains
// the blob returned by a key creation function. The loaded key's handle is
// returned using |key_handle|.
virtual TPM_RC LoadKey(const std::string& key_blob,
AuthorizationDelegate* delegate,
TPM_HANDLE* key_handle) = 0;
// This function sets |name| to the name of the object referenced by
// |handle|. This function only works on Transient and Permanent objects.
virtual TPM_RC GetKeyName(TPM_HANDLE handle, std::string* name) = 0;
// This function returns the public area of a handle in the tpm.
virtual TPM_RC GetKeyPublicArea(TPM_HANDLE handle,
TPMT_PUBLIC* public_data) = 0;
// This method seals |data_to_seal| to the TPM. The |sealed_data| can be
// retreived by fulfilling the policy represented by |policy_digest|.
virtual TPM_RC SealData(const std::string& data_to_seal,
const std::string& policy_digest,
AuthorizationDelegate* delegate,
std::string* sealed_data) = 0;
// This method is used to retrieve data that was sealed to the TPM.
// |sealed_data| refers to sealed data returned from SealData.
virtual TPM_RC UnsealData(const std::string& sealed_data,
AuthorizationDelegate* delegate,
std::string* unsealed_data) = 0;
// This method sets up a given HmacSession with parameter encryption set to
// true. Returns an TPM_RC_SUCCESS on success.
virtual TPM_RC StartSession(HmacSession* session) = 0;
// This method uses a trial session to compute the |policy_digest| when
// the policy is bound to a given |pcr_value| at |pcr_index|. If |pcr_value|
// is the empty string, this method uses the currect value of the pcr.
virtual TPM_RC GetPolicyDigestForPcrValue(int pcr_index,
const std::string& pcr_value,
std::string* policy_digest) = 0;
// This method defines a non-volatile storage area in the TPM, referenced
// by |index| of size |num_bytes|. This command needs owner authorization.
// The |attributes| of the space must be specified as a combination of
// TPMA_NV_* values. Optionally, an |authorization_value| and / or
// |policy_digest| can be specified which will be associated with the space.
// These values must either be a valid SHA256 digest (or empty).
virtual TPM_RC DefineNVSpace(uint32_t index,
size_t num_bytes,
TPMA_NV attributes,
const std::string& authorization_value,
const std::string& policy_digest,
AuthorizationDelegate* delegate) = 0;
// This method destroys the non-volatile space referred to by |index|.
// This command needs owner authorization.
virtual TPM_RC DestroyNVSpace(uint32_t index,
AuthorizationDelegate* delegate) = 0;
// This method locks the non-volatile space referred to by |index|. The caller
// needs indicate whether they want to |lock_read| and / or |lock_write|. They
// also need to indicate if they are |using_owner_authorization|.
virtual TPM_RC LockNVSpace(uint32_t index,
bool lock_read,
bool lock_write,
bool using_owner_authorization,
AuthorizationDelegate* delegate) = 0;
// This method writes |nvram_data| to the non-volatile space referenced by
// |index|, at |offset| bytes from the start of the non-volatile space. The
// caller needs to indicate if they are |using_owner_authorization|. If
// |extend| is set, the value will be extended and offset ignored.
virtual TPM_RC WriteNVSpace(uint32_t index,
uint32_t offset,
const std::string& nvram_data,
bool using_owner_authorization,
bool extend,
AuthorizationDelegate* delegate) = 0;
// This method reads |num_bytes| of data from the |offset| located at the
// non-volatile space defined by |index|. This method returns an error if
// |length| + |offset| is larger than the size of the defined non-volatile
// space. The caller needs to indicate if they are |using_owner_authorization|
virtual TPM_RC ReadNVSpace(uint32_t index,
uint32_t offset,
size_t num_bytes,
bool using_owner_authorization,
std::string* nvram_data,
AuthorizationDelegate* delegate) = 0;
// This function sets |name| to the name of the non-volatile space referenced
// by |index|.
virtual TPM_RC GetNVSpaceName(uint32_t index, std::string* name) = 0;
// This function returns the public area of an non-volatile space defined in
// the TPM.
virtual TPM_RC GetNVSpacePublicArea(uint32_t index,
TPMS_NV_PUBLIC* public_data) = 0;
// Lists all defined NV indexes.
virtual TPM_RC ListNVSpaces(std::vector<uint32_t>* index_list) = 0;
// Sets dictionary attack parameters. Requires lockout authorization.
// Parameters map directly to TPM2_DictionaryAttackParameters in the TPM 2.0
// specification.
virtual TPM_RC SetDictionaryAttackParameters(
uint32_t max_tries,
uint32_t recovery_time,
uint32_t lockout_recovery,
AuthorizationDelegate* delegate) = 0;
// Reset dictionary attack lockout. Requires lockout authorization.
virtual TPM_RC ResetDictionaryAttackLock(AuthorizationDelegate* delegate) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(TpmUtility);
};
} // namespace trunks
#endif // TRUNKS_TPM_UTILITY_H_