strongswan/src/libtpmtss/tpm_tss_quote_info.c

331 lines
7.4 KiB
C

/*
* Copyright (C) 2016 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <tpm_tss_quote_info.h>
#include <bio/bio_writer.h>
#ifndef TPM_TAG_QUOTE_INFO2
#define TPM_TAG_QUOTE_INFO2 0x0036
#endif
#ifndef TPM_LOC_ZERO
#define TPM_LOC_ZERO 0x01
#endif
typedef struct private_tpm_tss_quote_info_t private_tpm_tss_quote_info_t;
/**
* Private data of an tpm_tss_quote_info_t object.
*/
struct private_tpm_tss_quote_info_t {
/**
* Public tpm_tss_quote_info_t interface.
*/
tpm_tss_quote_info_t public;
/**
* TPM Quote Mode
*/
tpm_quote_mode_t quote_mode;
/**
* TPM Qualified Signer
*/
chunk_t qualified_signer;
/**
* TPM Clock Info
*/
chunk_t clock_info;
/**
* TPM Version Info
*/
chunk_t version_info;
/**
* TPM PCR Selection
*/
chunk_t pcr_select;
/**
* TPM PCR Composite Hash
*/
chunk_t pcr_digest;
/**
* TPM PCR Composite Hash algorithm
*/
hash_algorithm_t pcr_digest_alg;
/**
* Reference count
*/
refcount_t ref;
};
METHOD(tpm_tss_quote_info_t, get_quote_mode, tpm_quote_mode_t,
private_tpm_tss_quote_info_t *this)
{
return this->quote_mode;
}
METHOD(tpm_tss_quote_info_t, get_pcr_digest_alg, hash_algorithm_t,
private_tpm_tss_quote_info_t *this)
{
return this->pcr_digest_alg;
}
METHOD(tpm_tss_quote_info_t, get_pcr_digest, chunk_t,
private_tpm_tss_quote_info_t *this)
{
return this->pcr_digest;
}
METHOD(tpm_tss_quote_info_t, get_quote, bool,
private_tpm_tss_quote_info_t *this, chunk_t nonce,
tpm_tss_pcr_composite_t *composite, chunk_t *quoted)
{
chunk_t pcr_composite, pcr_digest;
bio_writer_t *writer;
hasher_t *hasher;
bool equal_digests;
/* Construct PCR Composite */
writer = bio_writer_create(32);
switch (this->quote_mode)
{
case TPM_QUOTE:
case TPM_QUOTE2:
case TPM_QUOTE2_VERSION_INFO:
writer->write_data16(writer, composite->pcr_select);
writer->write_data32(writer, composite->pcr_composite);
break;
case TPM_QUOTE_TPM2:
writer->write_data(writer, composite->pcr_composite);
break;
case TPM_QUOTE_NONE:
break;
}
pcr_composite = writer->extract_buf(writer);
writer->destroy(writer);
DBG2(DBG_PTS, "constructed PCR Composite: %B", &pcr_composite);
/* Compute PCR Composite Hash */
hasher = lib->crypto->create_hasher(lib->crypto, this->pcr_digest_alg);
if (!hasher || !hasher->allocate_hash(hasher, pcr_composite, &pcr_digest))
{
DESTROY_IF(hasher);
chunk_free(&pcr_composite);
return FALSE;
}
hasher->destroy(hasher);
chunk_free(&pcr_composite);
DBG2(DBG_PTS, "constructed PCR Composite digest: %B", &pcr_digest);
equal_digests = chunk_equals(pcr_digest, this->pcr_digest);
/* Construct Quote Info */
writer = bio_writer_create(32);
switch (this->quote_mode)
{
case TPM_QUOTE:
/* Version number */
writer->write_data(writer, chunk_from_chars(1, 1, 0, 0));
/* Magic QUOT value */
writer->write_data(writer, chunk_from_str("QUOT"));
/* PCR Composite Hash */
writer->write_data(writer, pcr_digest);
/* Secret assessment value 20 bytes (nonce) */
writer->write_data(writer, nonce);
break;
case TPM_QUOTE2:
case TPM_QUOTE2_VERSION_INFO:
/* TPM Structure Tag */
writer->write_uint16(writer, TPM_TAG_QUOTE_INFO2);
/* Magic QUT2 value */
writer->write_data(writer, chunk_from_str("QUT2"));
/* Secret assessment value 20 bytes (nonce) */
writer->write_data(writer, nonce);
/* PCR selection */
writer->write_data16(writer, composite->pcr_select);
/* TPM Locality Selection */
writer->write_uint8(writer, TPM_LOC_ZERO);
/* PCR Composite Hash */
writer->write_data(writer, pcr_digest);
if (this->quote_mode == TPM_QUOTE2_VERSION_INFO)
{
/* TPM version Info */
writer->write_data(writer, this->version_info);
}
break;
case TPM_QUOTE_TPM2:
/* Magic */
writer->write_data(writer, chunk_from_chars(0xff,0x54,0x43,0x47));
/* Type */
writer->write_uint16(writer, 0x8018);
/* Qualified Signer */
writer->write_data16(writer, this->qualified_signer);
/* Extra Data */
writer->write_data16(writer, nonce);
/* Clock Info */
writer->write_data(writer, this->clock_info);
/* Firmware Version */
writer->write_data(writer, this->version_info);
/* PCR Selection */
writer->write_data(writer, this->pcr_select);
/* PCR Composite Hash */
writer->write_data16(writer, pcr_digest);
break;
case TPM_QUOTE_NONE:
break;
}
chunk_free(&pcr_digest);
*quoted = writer->extract_buf(writer);
writer->destroy(writer);
DBG2(DBG_PTS, "constructed TPM Quote Info: %B", quoted);
if (!equal_digests)
{
DBG1(DBG_IMV, "received PCR Composite digest does not match "
"constructed one");
chunk_free(quoted);
}
return equal_digests;
}
METHOD(tpm_tss_quote_info_t, set_version_info, void,
private_tpm_tss_quote_info_t *this, chunk_t version_info)
{
chunk_free(&this->version_info);
this->version_info = chunk_clone(version_info);
}
METHOD(tpm_tss_quote_info_t, get_version_info, chunk_t,
private_tpm_tss_quote_info_t *this)
{
return this->version_info;
}
METHOD(tpm_tss_quote_info_t, set_tpm2_info, void,
private_tpm_tss_quote_info_t *this, chunk_t qualified_signer,
chunk_t clock_info, chunk_t pcr_select)
{
chunk_free(&this->qualified_signer);
this->qualified_signer = chunk_clone(qualified_signer);
chunk_free(&this->clock_info);
this->clock_info = chunk_clone(clock_info);
chunk_free(&this->pcr_select);
this->pcr_select = chunk_clone(pcr_select);
}
METHOD(tpm_tss_quote_info_t, get_tpm2_info, void,
private_tpm_tss_quote_info_t *this, chunk_t *qualified_signer,
chunk_t *clock_info, chunk_t *pcr_select)
{
if (qualified_signer)
{
*qualified_signer = this->qualified_signer;
}
if (clock_info)
{
*clock_info = this->clock_info;
}
if (pcr_select)
{
*pcr_select = this->pcr_select;
}
}
METHOD(tpm_tss_quote_info_t, get_ref, tpm_tss_quote_info_t*,
private_tpm_tss_quote_info_t *this)
{
ref_get(&this->ref);
return &this->public;
}
METHOD(tpm_tss_quote_info_t, destroy, void,
private_tpm_tss_quote_info_t *this)
{
if (ref_put(&this->ref))
{
chunk_free(&this->qualified_signer);
chunk_free(&this->clock_info);
chunk_free(&this->version_info);
chunk_free(&this->pcr_select);
chunk_free(&this->pcr_digest);
free(this);
}
}
/**
* See header
*/
tpm_tss_quote_info_t *tpm_tss_quote_info_create(tpm_quote_mode_t quote_mode,
hash_algorithm_t pcr_digest_alg, chunk_t pcr_digest)
{
private_tpm_tss_quote_info_t *this;
INIT(this,
.public = {
.get_quote_mode = _get_quote_mode,
.get_pcr_digest_alg = _get_pcr_digest_alg,
.get_pcr_digest = _get_pcr_digest,
.get_quote = _get_quote,
.set_version_info = _set_version_info,
.get_version_info = _get_version_info,
.set_tpm2_info = _set_tpm2_info,
.get_tpm2_info = _get_tpm2_info,
.get_ref = _get_ref,
.destroy = _destroy,
},
.quote_mode = quote_mode,
.pcr_digest_alg = pcr_digest_alg,
.pcr_digest = chunk_clone(pcr_digest),
.ref = 1,
);
return &this->public;
}