libimcv: migrate pts to tpm_tss
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include <library.h>
|
||||
|
||||
typedef enum tpm_version_t tpm_version_t;
|
||||
typedef enum tpm_quote_mode_t tpm_quote_mode_t;
|
||||
typedef struct tpm_tss_t tpm_tss_t;
|
||||
|
||||
/**
|
||||
@@ -35,6 +36,15 @@ enum tpm_version_t {
|
||||
TPM_VERSION_2_0,
|
||||
};
|
||||
|
||||
/**
|
||||
* TPM Quote Modes
|
||||
*/
|
||||
enum tpm_quote_mode_t {
|
||||
TPM_QUOTE,
|
||||
TPM_QUOTE2,
|
||||
TPM_QUOTE2_VERSION_INFO
|
||||
};
|
||||
|
||||
/**
|
||||
* TPM access via TSS public interface
|
||||
*/
|
||||
@@ -74,6 +84,45 @@ struct tpm_tss_t {
|
||||
*/
|
||||
chunk_t (*get_public)(tpm_tss_t *this, uint32_t handle);
|
||||
|
||||
/**
|
||||
* Retrieve the current value of a PCR register in a given PCR bank
|
||||
*
|
||||
* @param pcr_num PCR number
|
||||
* @param pcr_value PCR value returned
|
||||
* @param alg hash algorithm, selects PCR bank (TPM 2.0 only)
|
||||
* @return TRUE if PCR value retrieval succeeded
|
||||
*/
|
||||
bool (*read_pcr)(tpm_tss_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||
hash_algorithm_t alg);
|
||||
|
||||
/**
|
||||
* Extend a PCR register in a given PCR bank with a hash value
|
||||
*
|
||||
* @param pcr_num PCR number
|
||||
* @param pcr_value extended PCR value returned
|
||||
* @param hash data to be extended into the PCR
|
||||
* @param alg hash algorithm, selects PCR bank (TPM 2.0 only)
|
||||
* @return TRUE if PCR extension succeeded
|
||||
*/
|
||||
bool (*extend_pcr)(tpm_tss_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||
chunk_t data, hash_algorithm_t alg);
|
||||
|
||||
/**
|
||||
* Do a quote signature over a selection of PCR registers
|
||||
*
|
||||
* @param aik_handle object handle of AIK to be used for quote signature
|
||||
* @param pcr_sel selection of PCR registers
|
||||
* @param alg hash algorithm to be used for quote signature
|
||||
* @param data additional data to be hashed into the quote
|
||||
* @param mode define current and legacy TPM quote modes
|
||||
* @param pcr_comp returns hash of PCR composite
|
||||
* @param sig returns quote signature
|
||||
* @return TRUE if quote signature succeeded
|
||||
*/
|
||||
bool (*quote)(tpm_tss_t *this, uint32_t aik_handle, uint32_t pcr_sel,
|
||||
hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t mode,
|
||||
chunk_t *pcr_comp, chunk_t *quote_sig);
|
||||
|
||||
/**
|
||||
* Destroy a tpm_tss_t.
|
||||
*/
|
||||
|
||||
@@ -27,15 +27,24 @@
|
||||
|
||||
#ifdef TSS_TROUSERS
|
||||
|
||||
#ifdef _BASETSD_H_
|
||||
/* MinGW defines _BASETSD_H_, but TSS checks for _BASETSD_H */
|
||||
# define _BASETSD_H
|
||||
#endif
|
||||
|
||||
#include <trousers/tss.h>
|
||||
#include <trousers/trousers.h>
|
||||
|
||||
#define LABEL "TPM 1.2 -"
|
||||
|
||||
/* size in bytes of a TSS AIK public key blob */
|
||||
#define AIK_PUBKEY_BLOB_SIZE 284
|
||||
#define AIK_PUBKEY_BLOB_SIZE 284
|
||||
|
||||
/* maximum number of PCR registers */
|
||||
#define PCR_NUM_MAX 24
|
||||
|
||||
typedef struct private_tpm_tss_trousers_t private_tpm_tss_trousers_t;
|
||||
typedef struct aik_t aik_t;
|
||||
|
||||
/**
|
||||
* Private data of an tpm_tss_trousers_t object.
|
||||
@@ -45,20 +54,48 @@ struct private_tpm_tss_trousers_t {
|
||||
/**
|
||||
* Public tpm_tss_trousers_t interface.
|
||||
*/
|
||||
tpm_tss_t public;
|
||||
tpm_tss_trousers_t interface;
|
||||
|
||||
/**
|
||||
* TSS context
|
||||
*/
|
||||
TSS_HCONTEXT hContext;
|
||||
|
||||
/**
|
||||
* TPM handle
|
||||
*/
|
||||
TSS_HTPM hTPM;
|
||||
|
||||
/**
|
||||
* TPM version info
|
||||
*/
|
||||
chunk_t version_info;
|
||||
|
||||
/**
|
||||
* List of AIKs retrievable by an object handle
|
||||
*/
|
||||
linked_list_t *aik_list;
|
||||
|
||||
};
|
||||
|
||||
struct aik_t {
|
||||
/** AIK object handle */
|
||||
uint32_t handle;
|
||||
|
||||
/** AIK private key blob */
|
||||
chunk_t blob;
|
||||
|
||||
/** AIK public key */
|
||||
chunk_t pubkey;
|
||||
};
|
||||
|
||||
static void free_aik(aik_t *this)
|
||||
{
|
||||
free(this->blob.ptr);
|
||||
free(this->pubkey.ptr);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize TSS context
|
||||
*
|
||||
@@ -86,7 +123,6 @@ static bool initialize_context(private_tpm_tss_trousers_t *this)
|
||||
uint8_t *version_ptr;
|
||||
uint32_t version_len;
|
||||
|
||||
TSS_HTPM hTPM;
|
||||
TSS_RESULT result;
|
||||
TPM_CAP_VERSION_INFO *info;
|
||||
|
||||
@@ -106,7 +142,7 @@ static bool initialize_context(private_tpm_tss_trousers_t *this)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = Tspi_Context_GetTpmObject (this->hContext, &hTPM);
|
||||
result = Tspi_Context_GetTpmObject (this->hContext, &this->hTPM);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s could not get TPM object: 0x%x",
|
||||
@@ -114,8 +150,8 @@ static bool initialize_context(private_tpm_tss_trousers_t *this)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_VERSION_VAL, 0, NULL,
|
||||
&version_len, &version_ptr);
|
||||
result = Tspi_TPM_GetCapability(this->hTPM, TSS_TPMCAP_VERSION_VAL, 0,
|
||||
NULL, &version_len, &version_ptr);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_TPM_GetCapability failed: 0x%x",
|
||||
@@ -168,7 +204,6 @@ METHOD(tpm_tss_t, generate_aik, bool,
|
||||
chunk_t aik_exponent;
|
||||
|
||||
TSS_RESULT result;
|
||||
TSS_HTPM hTPM;
|
||||
TSS_HKEY hSRK;
|
||||
TSS_HKEY hPCAKey;
|
||||
TSS_HPOLICY hSrkPolicy;
|
||||
@@ -206,14 +241,14 @@ METHOD(tpm_tss_t, generate_aik, bool,
|
||||
}
|
||||
|
||||
/* get TPM plus TPM policy and set TPM secret */
|
||||
result = Tspi_Context_GetTpmObject (this->hContext, &hTPM);
|
||||
result = Tspi_Context_GetTpmObject (this->hContext, &this->hTPM);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_Context_GetTpmObject failed: 0x%x",
|
||||
LABEL, result);
|
||||
return FALSE;
|
||||
}
|
||||
result = Tspi_GetPolicyObject(hTPM, TSS_POLICY_USAGE, &hTPMPolicy);
|
||||
result = Tspi_GetPolicyObject(this->hTPM, TSS_POLICY_USAGE, &hTPMPolicy);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_GetPolicyObject for TPM failed: 0x%x",
|
||||
@@ -268,7 +303,7 @@ METHOD(tpm_tss_t, generate_aik, bool,
|
||||
|
||||
/* generate AIK */
|
||||
DBG1(DBG_LIB, "Generating identity key...");
|
||||
result = Tspi_TPM_CollateIdentityRequest(hTPM, hSRK, hPCAKey, 0, NULL,
|
||||
result = Tspi_TPM_CollateIdentityRequest(this->hTPM, hSRK, hPCAKey, 0, NULL,
|
||||
hIdentKey, TSS_ALG_AES, &IdentityReqLen, &IdentityReq);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
@@ -337,17 +372,240 @@ METHOD(tpm_tss_t, generate_aik, bool,
|
||||
METHOD(tpm_tss_t, get_public, chunk_t,
|
||||
private_tpm_tss_trousers_t *this, uint32_t handle)
|
||||
{
|
||||
return chunk_empty;
|
||||
enumerator_t *enumerator;
|
||||
chunk_t aik_pubkey = chunk_empty;
|
||||
aik_t *aik;
|
||||
|
||||
enumerator = this->aik_list->create_enumerator(this->aik_list);
|
||||
while (enumerator->enumerate(enumerator, &aik))
|
||||
{
|
||||
if (aik->handle == handle)
|
||||
{
|
||||
aik_pubkey = chunk_clone(aik->pubkey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return aik_pubkey;
|
||||
}
|
||||
|
||||
METHOD(tpm_tss_t, read_pcr, bool,
|
||||
private_tpm_tss_trousers_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||
hash_algorithm_t alg)
|
||||
{
|
||||
TSS_RESULT result;
|
||||
uint8_t *value;
|
||||
uint32_t len;
|
||||
|
||||
result = Tspi_TPM_PcrRead(this->hTPM, pcr_num, &len, &value);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_TPM_PcrRead failed: 0x%x", LABEL, result);
|
||||
return FALSE;
|
||||
}
|
||||
*pcr_value = chunk_clone(chunk_create(value, len));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(tpm_tss_t, extend_pcr, bool,
|
||||
private_tpm_tss_trousers_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||
chunk_t data, hash_algorithm_t alg)
|
||||
{
|
||||
TSS_RESULT result;
|
||||
uint32_t pcr_len;
|
||||
uint8_t *pcr_ptr;
|
||||
|
||||
result = Tspi_TPM_PcrExtend(this->hTPM, pcr_num, data.len, data.ptr,
|
||||
NULL, &pcr_len, &pcr_ptr);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_TPM_PcrExtend failed: 0x%x", LABEL, result);
|
||||
return FALSE;
|
||||
}
|
||||
*pcr_value = chunk_clone(chunk_create(pcr_ptr, pcr_len));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(tpm_tss_t, quote, bool,
|
||||
private_tpm_tss_trousers_t *this, uint32_t aik_handle, uint32_t pcr_sel,
|
||||
hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t mode, chunk_t *pcr_comp,
|
||||
chunk_t *quote_sig)
|
||||
{
|
||||
TSS_HKEY hAIK;
|
||||
TSS_HKEY hSRK;
|
||||
TSS_HPOLICY srkUsagePolicy;
|
||||
TSS_UUID SRK_UUID = TSS_UUID_SRK;
|
||||
TSS_HPCRS hPcrComposite;
|
||||
TSS_VALIDATION valData;
|
||||
TSS_RESULT result;
|
||||
uint8_t secret[] = TSS_WELL_KNOWN_SECRET;
|
||||
uint8_t *version_info, *comp_hash;
|
||||
uint32_t version_info_size, pcr;
|
||||
aik_t *aik;
|
||||
chunk_t aik_blob = chunk_empty;
|
||||
chunk_t quote_info;
|
||||
enumerator_t *enumerator;
|
||||
bool success = FALSE;
|
||||
|
||||
/* Retrieve SRK from TPM and set the authentication to well known secret*/
|
||||
result = Tspi_Context_LoadKeyByUUID(this->hContext, TSS_PS_TYPE_SYSTEM,
|
||||
SRK_UUID, &hSRK);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_Context_LoadKeyByUUID for SRK failed: 0x%x",
|
||||
LABEL, result);
|
||||
return FALSE;
|
||||
}
|
||||
result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_GetPolicyObject for SRK failed: 0x%x",
|
||||
LABEL, result);
|
||||
return FALSE;
|
||||
}
|
||||
result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_SHA1,
|
||||
20, secret);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_Policy_SetSecret for SRK failed: 0x%x",
|
||||
LABEL, result);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Retrieve AIK using its handle and load private key into TPM 1.2 */
|
||||
enumerator = this->aik_list->create_enumerator(this->aik_list);
|
||||
while (enumerator->enumerate(enumerator, &aik))
|
||||
{
|
||||
if (aik->handle == aik_handle)
|
||||
{
|
||||
aik_blob = aik->blob;
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (aik_blob.len == 0)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s AIK private key for handle 0x%80x not found", LABEL);
|
||||
return FALSE;
|
||||
}
|
||||
result = Tspi_Context_LoadKeyByBlob(this->hContext, hSRK, aik_blob.len,
|
||||
aik_blob.ptr, &hAIK);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_Context_LoadKeyByBlob for AIK failed: 0x%x",
|
||||
LABEL, result);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Create PCR composite object */
|
||||
result = Tspi_Context_CreateObject(this->hContext, TSS_OBJECT_TYPE_PCRS,
|
||||
(mode == TPM_QUOTE) ? TSS_PCRS_STRUCT_INFO :
|
||||
TSS_PCRS_STRUCT_INFO_SHORT,
|
||||
&hPcrComposite);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_Context_CreateObject for pcrComposite failed: "
|
||||
"0x%x", LABEL, result);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* Select PCRs */
|
||||
for (pcr = 0; pcr < PCR_NUM_MAX; pcr++)
|
||||
{
|
||||
if (pcr_sel & (1 << pcr))
|
||||
{
|
||||
result = (mode == TPM_QUOTE) ?
|
||||
Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr) :
|
||||
Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr,
|
||||
TSS_PCRS_DIRECTION_RELEASE);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_PcrComposite_SelectPcrIndex failed: "
|
||||
"0x%x", LABEL, result);
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the Validation Data */
|
||||
valData.ulExternalDataLength = data.len;
|
||||
valData.rgbExternalData = data.ptr;
|
||||
|
||||
/* TPM Quote */
|
||||
result = (mode == TPM_QUOTE) ?
|
||||
Tspi_TPM_Quote (this->hTPM, hAIK, hPcrComposite, &valData) :
|
||||
Tspi_TPM_Quote2(this->hTPM, hAIK, mode == TPM_QUOTE2_VERSION_INFO,
|
||||
hPcrComposite, &valData, &version_info_size,
|
||||
&version_info);
|
||||
if (result != TSS_SUCCESS)
|
||||
{
|
||||
DBG1(DBG_PTS, "%s Tspi_TPM_Quote%s failed: 0x%x", LABEL,
|
||||
(mode == TPM_QUOTE) ? "" : "2", result);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
/* Extract TPM_Composite_Hash */
|
||||
*pcr_comp = chunk_alloc(HASH_SIZE_SHA1);
|
||||
|
||||
if (mode == TPM_QUOTE)
|
||||
{
|
||||
/* TPM_Composite_Hash starts at byte 8 of TPM_Quote_Info structure */
|
||||
comp_hash = valData.rgbData + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TPM_Composite_Hash is last 20 bytes of TPM_Quote_Info2 structure */
|
||||
comp_hash = valData.rgbData + valData.ulDataLength - version_info_size -
|
||||
HASH_SIZE_SHA1;
|
||||
}
|
||||
memcpy(pcr_comp->ptr, comp_hash, HASH_SIZE_SHA1);
|
||||
DBG3(DBG_PTS, "Hash of PCR Composite: %#B", pcr_comp);
|
||||
|
||||
quote_info = chunk_create(valData.rgbData, valData.ulDataLength);
|
||||
DBG3(DBG_PTS, "TPM Quote Info: %B","e_info);
|
||||
|
||||
*quote_sig = chunk_clone(chunk_create(valData.rgbValidationData,
|
||||
valData.ulValidationDataLength));
|
||||
DBG3(DBG_PTS, "TPM Quote Signature: %B",quote_sig);
|
||||
|
||||
success = TRUE;
|
||||
|
||||
err2:
|
||||
Tspi_Context_CloseObject(this->hContext, hPcrComposite);
|
||||
err1:
|
||||
Tspi_Context_CloseObject(this->hContext, hAIK);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
METHOD(tpm_tss_t, destroy, void,
|
||||
private_tpm_tss_trousers_t *this)
|
||||
{
|
||||
finalize_context(this);
|
||||
this->aik_list->destroy_function(this->aik_list, (void*)free_aik);
|
||||
free(this->version_info.ptr);
|
||||
free(this);
|
||||
}
|
||||
|
||||
METHOD(tpm_tss_trousers_t, load_aik, void,
|
||||
private_tpm_tss_trousers_t *this, chunk_t blob, chunk_t pubkey,
|
||||
uint32_t handle)
|
||||
{
|
||||
aik_t *item;
|
||||
|
||||
INIT(item,
|
||||
.handle = handle,
|
||||
.blob = blob,
|
||||
.pubkey = pubkey,
|
||||
);
|
||||
|
||||
this->aik_list->insert_last(this->aik_list, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
@@ -357,13 +615,20 @@ tpm_tss_t *tpm_tss_trousers_create()
|
||||
bool available;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.get_version = _get_version,
|
||||
.get_version_info = _get_version_info,
|
||||
.generate_aik = _generate_aik,
|
||||
.get_public = _get_public,
|
||||
.destroy = _destroy,
|
||||
.interface = {
|
||||
.public = {
|
||||
.get_version = _get_version,
|
||||
.get_version_info = _get_version_info,
|
||||
.generate_aik = _generate_aik,
|
||||
.get_public = _get_public,
|
||||
.read_pcr = _read_pcr,
|
||||
.quote = _quote,
|
||||
.extend_pcr = _extend_pcr,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.load_aik = _load_aik,
|
||||
},
|
||||
.aik_list = linked_list_create(),
|
||||
);
|
||||
|
||||
available = initialize_context(this);
|
||||
@@ -374,7 +639,7 @@ tpm_tss_t *tpm_tss_trousers_create()
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
return &this->public;
|
||||
return &this->interface.public;
|
||||
}
|
||||
|
||||
#else /* TSS_TROUSERS */
|
||||
|
||||
@@ -23,6 +23,27 @@
|
||||
|
||||
#include "tpm_tss.h"
|
||||
|
||||
typedef struct tpm_tss_trousers_t tpm_tss_trousers_t;
|
||||
|
||||
/**
|
||||
* TPM 1.2 access via TrouSerS public interface
|
||||
*/
|
||||
struct tpm_tss_trousers_t {
|
||||
|
||||
tpm_tss_t public;
|
||||
|
||||
/**
|
||||
* Load AIK public and private key pair and save it under an object handle
|
||||
*
|
||||
* @param blob encrypted AIK private key
|
||||
* @param pubkey AIK public key
|
||||
* @param handle object handle under which the AIK key is stored
|
||||
*/
|
||||
void (*load_aik)(tpm_tss_trousers_t *this, chunk_t blob, chunk_t pubkey,
|
||||
uint32_t handle);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a tpm_tss_trousers instance.
|
||||
*/
|
||||
|
||||
@@ -335,6 +335,31 @@ METHOD(tpm_tss_t, get_public, chunk_t,
|
||||
return aik_pubkey;
|
||||
}
|
||||
|
||||
METHOD(tpm_tss_t, read_pcr, bool,
|
||||
private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||
hash_algorithm_t alg)
|
||||
{
|
||||
/* TODO */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(tpm_tss_t, extend_pcr, bool,
|
||||
private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||
chunk_t data, hash_algorithm_t alg)
|
||||
{
|
||||
/* TODO */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(tpm_tss_t, quote, bool,
|
||||
private_tpm_tss_tss2_t *this, uint32_t aik_handle, uint32_t pcr_sel,
|
||||
hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t mode, chunk_t *pcr_comp,
|
||||
chunk_t *quote_sig)
|
||||
{
|
||||
/* TODO */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(tpm_tss_t, destroy, void,
|
||||
private_tpm_tss_tss2_t *this)
|
||||
{
|
||||
@@ -356,6 +381,9 @@ tpm_tss_t *tpm_tss_tss2_create()
|
||||
.get_version_info = _get_version_info,
|
||||
.generate_aik = _generate_aik,
|
||||
.get_public = _get_public,
|
||||
.read_pcr = _read_pcr,
|
||||
.extend_pcr = _extend_pcr,
|
||||
.quote = _quote,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user