Showing with 373 additions and 19 deletions.
  1. +2 −0 Makefile.am
  2. +269 −0 lib/tpm2_errata.c
  3. +84 −0 lib/tpm2_errata.h
  4. +0 −15 test/system/test_helpers.sh
  5. +2 −2 test/system/test_tpm2_create.sh
  6. +1 −1 test/system/test_tpm2_encryptdecrypt.sh
  7. +1 −1 test/system/test_tpm2_quote.sh
  8. +4 −0 tools/tpm2_create.c
  9. +4 −0 tools/tpm2_import.c
  10. +6 −0 tools/tpm2_tool.c
2 changes: 2 additions & 0 deletions Makefile.am
Expand Up @@ -122,6 +122,8 @@ lib_libcommon_a_SOURCES = \
lib/rc-decode.h \
lib/tpm2_alg_util.c \
lib/tpm2_alg_util.h \
lib/tpm2_errata.c \
lib/tpm2_errata.h \
lib/tpm2_header.h \
lib/tpm2_nv_util.c \
lib/tpm2_nv_util.h \
Expand Down
269 changes: 269 additions & 0 deletions lib/tpm2_errata.c
@@ -0,0 +1,269 @@
//**********************************************************************;
// Copyright (c) 2017, Alibaba Group
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of Intel Corporation nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//**********************************************************************;
#include <stdarg.h>
#include <stdbool.h>

#include "log.h"
#include "tpm2_errata.h"
#include "tpm2_util.h"

struct tpm2_errata_desc {
UINT32 spec_level; /* spec level */
UINT32 spec_rev; /* spec revision */
UINT32 errata_ver; /* errata version */
void (*fixup)(va_list *ap); /* errata correction handler */
const char *name; /* full section name in errata doc */
};

/*
* Published spec and errata information.
*
* Note that TPM_PT_YEAR and TPM_PT_DAY_OF_YEAR retrieved
* from capability query only have the values of the
* release date of the specification if the TPM does not
* implement an errata. So the spec info are also given.
*/
static struct tpm2_errata_info {
UINT32 spec_level;
UINT32 spec_rev;
UINT32 errata_ver;
UINT32 year;
UINT32 day_of_year;
} known_errata_info[] = {
/* Specification Revision 1.16 October 30, 2014 */
{ 00, 116, 000, 2014, 303 },
/* Errata Version 1.2 February 16, 2015 */
{ 00, 116, 120, 2015, 4 },
/* Errata Version 1.3 June 16, 2015 */
{ 00, 116, 130, 2015, 167 },
/* Errata Version 1.4 January 15, 2016 */
{ 00, 116, 140, 2016, 15 },
/* Errata Version 1.5 September 21, 2016 */
{ 00, 116, 150, 2016, 265 },
/* Specification Revision 1.38 September 29, 2016 */
{ 00, 138, 000, 2016, 273 },
/* Errata Version 1.0 January 16, 2017 */
{ 00, 138, 100, 2017, 16 },
/* Errata Version 1.1 March 2, 2017 */
{ 00, 138, 110, 2017, 61 },
};

static struct tpm2_errata_info *this_errata_info;

static void fixup_sign_decrypt_attribute_encoding(va_list *ap);

/*
* Beware of that each record contains the first errata
* version with the corresponding correction. This rule
* allows errata_match() to function properly.
*/
static struct tpm2_errata_desc errata_desc_list[] = {
[SPEC_116_ERRATA_2_7] = {
.spec_level = 00,
.spec_rev = 116,
.errata_ver = 120,
.fixup = fixup_sign_decrypt_attribute_encoding,
.name = "Sign/decrypt attribute encoding",
},
/*
* Append the new errata descriptor here.
*/
};

static bool errata_match(struct tpm2_errata_desc *errata);
static struct tpm2_errata_desc *errata_query(tpm2_errata_index_t index);

/*
* Request an errata correction.
* @index: the errata to be queried.
*
* This function requests an errata correction to work
* around a known issue well documented in errata doc.
* If the request is valid and known, the queried errata
* will be applied by the corresponding pre-defined errata
* correction handler. The fixup process is transparent to
* the callers so there is no return values. Any tools can
* call this function to apply an errata if necessary.
*
* Return value:
* N/A
*/
void tpm2_errata_fixup(tpm2_errata_index_t index, ...) {

struct tpm2_errata_desc *errata;

errata = errata_query(index);
if (!errata) {
return;
}

bool res = errata_match(errata);
if (res == false) {
return;
}

va_list ap;

va_start(ap, index);
errata->fixup(&ap);
va_end(ap);

LOG_INFO("Errata %s applied\n", errata->name);
}

/*
* Query the full name of an errata.
* @index: the errata to be queried.
*
* Return value:
* the full name of an errata, or NULL if the query fails.
*/
const char *tpm2_errata_name(tpm2_errata_index_t index) {

struct tpm2_errata_desc *errata;

errata = errata_query(index);
if (!errata) {
return NULL;
}

return errata->name;
}

/*
* Initialize errata subsystem.
* @sapi_ctx: SAPI context to be queried.
*
* Return value:
* return true if TPM_SPEC is known and valid, or false if opposite.
*/
bool tpm2_errata_init(TSS2_SYS_CONTEXT *sapi_ctx) {

TPMS_CAPABILITY_DATA capability_data;
TPMI_YES_NO more_data;
TSS2_RC rc;

rc = Tss2_Sys_GetCapability(sapi_ctx, NULL, TPM_CAP_TPM_PROPERTIES,
PT_FIXED, MAX_TPM_PROPERTIES, &more_data,
&capability_data, NULL);
if (rc != TSS2_RC_SUCCESS) {
LOG_ERR("Failed to GetCapability: capability: 0x%x, property: 0x%x, "
"TSS2_RC: 0x%x\n", TPM_CAP_TPM_PROPERTIES, PT_FIXED, rc);
return false;
} else if (more_data == YES) {
LOG_WARN("More data to be queried: capability: 0x%x, property: "
"0x%x\n", TPM_CAP_TPM_PROPERTIES, PT_FIXED);
}

/* Distinguish current spec level 0 */
UINT32 spec_level = -1;
UINT32 spec_rev = 0;
UINT32 day_of_year = 0;
UINT32 year = 0;
TPML_TAGGED_TPM_PROPERTY *properties = &capability_data.data.tpmProperties;
size_t i;
for (i = 0; i < properties->count; ++i) {
TPMS_TAGGED_PROPERTY *property = properties->tpmProperty + i;

if (property->property == TPM_PT_LEVEL) {
spec_level = property->value;
} else if (property->property == TPM_PT_REVISION) {
spec_rev = property->value;
} else if (property->property == TPM_PT_DAY_OF_YEAR) {
day_of_year = property->value;
} else if (property->property == TPM_PT_YEAR) {
year = property->value;
/* Short circuit because this is the last item we need */
break;
} else if (property->property > TPM_PT_YEAR) {
break;
}
}

if (!spec_rev || !day_of_year || !year) {
LOG_ERR("Invalid TPM_SPEC parameter\n");
return false;
}

/* Determine the TPM spec and errata */
for (i = 0; i < ARRAY_LEN(known_errata_info); ++i) {
if (known_errata_info[i].day_of_year == day_of_year &&
known_errata_info[i].year == year &&
known_errata_info[i].spec_rev == spec_rev &&
known_errata_info[i].spec_level == spec_level) {
this_errata_info = known_errata_info + i;
break;
}
}

if (!this_errata_info) {
LOG_ERR("Unknow TPM_SPEC. spec_level: %d, spec_rev: 0x%x, "
"year: %d, day_of_year: %d\n", spec_level, spec_rev,
year, day_of_year);
return false;
}

LOG_INFO("TPM_SPEC: spec level %d, spec rev %f, errata ver %f\n",
this_errata_info->spec_level,
(float)this_errata_info->spec_rev / 100,
(float)this_errata_info->errata_ver / 100);

return true;
}

static void fixup_sign_decrypt_attribute_encoding(va_list *ap) {

TPMA_OBJECT *attrs = va_arg(*ap, TPMA_OBJECT *);

attrs->sign = 0;
}

static bool errata_match(struct tpm2_errata_desc *errata) {

if (!this_errata_info) {
LOG_ERR("Unrecognized TPM_SPEC for errata check\n");
return false;
}

return errata->errata_ver > this_errata_info->errata_ver &&
errata->spec_rev >= this_errata_info->spec_rev &&
errata->spec_level == this_errata_info->spec_level;
}

static struct tpm2_errata_desc *errata_query(tpm2_errata_index_t index) {

if ((size_t)index >= ARRAY_LEN(errata_desc_list)) {
LOG_ERR("Invalid errata index queried: %u\n", (unsigned int)index);
return NULL;
}

return &errata_desc_list[index];
}
84 changes: 84 additions & 0 deletions lib/tpm2_errata.h
@@ -0,0 +1,84 @@
//**********************************************************************;
// Copyright (c) 2017, Alibaba Group
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of Intel Corporation nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//**********************************************************************;
#ifndef TPM2_ERRATA_H
#define TPM2_ERRATA_H

#include <sapi/tpm20.h>
#include <stdbool.h>

/*
* Errata index pattern:
* spec version + the section number in the errata doc
*
* Note that it is unnecessary to describe errata version
* because the section number should be kept consistent
* accoss all errata versions for a specific spec revision.
*/
typedef enum {
SPEC_116_ERRATA_2_7,
} tpm2_errata_index_t;

/*
* Initialize errata subsystem.
* @sapi_ctx: SAPI context to be queried.
*
* Return value:
* return true if TPM_SPEC is known and valid, or false if opposite.
*/
bool tpm2_errata_init(TSS2_SYS_CONTEXT *sapi_ctx);

/*
* Request an errata correction.
* @index: the errata to be queried.
*
* This function requests an errata correction to work
* around a known issue well documented in errata doc.
* If the request is valid and known, the queried errata
* will be applied by the corresponding pre-defined errata
* correction handler. The fixup process is transparent to
* the callers so there is no return values. Any tools can
* call this function to apply an errata if necessary.
*
* Return value:
* N/A
*/
void tpm2_errata_fixup(tpm2_errata_index_t index, ...);

/*
* Query the full name of an errata.
* @index: the errata to be queried.
*
* Return value:
* the full name of an errata, or NULL if the query fails.
*/
const char *tpm2_errata_name(tpm2_errata_index_t index);

#endif /* TPM2_ERRATA_H */
15 changes: 0 additions & 15 deletions test/system/test_helpers.sh
Expand Up @@ -99,18 +99,3 @@ hash_alg_supported() {
fi
done
}

# Certain TPM 2.0 chip, e.g, Nationz Z32H320TC, and tpm2simulator referring
# to TPM 2.0 spec rev 1.16 may have an errata, disallowing both decrypt and
# sign set for a symcipher object, and in response to RC_ATTRIBUTES. In
# order to work around it, we attempt to run tpm2_create again with sign bit
# clear.
create_object() {
local alg_create_obj=0x20072

if tpm2_create $@ 2>&1 | grep -q 'Create Object Failed ! ErrorCode: 0x2c2'; then
tpm2_create -Q -A $alg_create_obj $@
else
true
fi
}