From e275ba54e585c6be6c89f3b40c2af84c255cf464 Mon Sep 17 00:00:00 2001 From: William Roberts Date: Thu, 28 May 2020 11:47:44 -0500 Subject: [PATCH] man/tpm2_verifysignature: clarify the scheme option The -f/scheme option was confusing. One only needs to specify the --scheme when the non *tss* format is used. The TSS format contains the metadata identifying the type of signature it is. It's only the *plain* formats that come from openssl or similair tools that require the scheme. Also, that clause said it only supports RSASSA, which is incorrect. Signed-off-by: William Roberts --- lib/files.c | 2 + lib/files.h | 21 +++++ lib/tpm2_convert.c | 116 ++++++++++++++++++++++----- lib/tpm2_convert.h | 4 + man/tpm2_verifysignature.1.md | 17 ++-- test/integration/tests/checkquote.sh | 14 +++- tools/misc/tpm2_checkquote.c | 15 +--- tools/tpm2_verifysignature.c | 8 +- 8 files changed, 156 insertions(+), 41 deletions(-) diff --git a/lib/files.c b/lib/files.c index d9386e669..44821ca9b 100644 --- a/lib/files.c +++ b/lib/files.c @@ -730,10 +730,12 @@ tool_rc files_save_ESYS_TR(ESYS_CONTEXT *ectx, ESYS_TR handle, const char *path) SAVE_TYPE(TPM2B_PUBLIC, public) LOAD_TYPE(TPM2B_PUBLIC, public) LOAD_TYPE_FILE(TPM2B_PUBLIC, public) +LOAD_TYPE_SILENT(TPM2B_PUBLIC, public) SAVE_TYPE(TPMT_PUBLIC, template) LOAD_TYPE(TPMT_PUBLIC, template) LOAD_TYPE_FILE(TPMT_PUBLIC, template) +LOAD_TYPE_SILENT(TPMT_PUBLIC, template) SAVE_TYPE(TPMT_SIGNATURE, signature) LOAD_TYPE(TPMT_SIGNATURE, signature) diff --git a/lib/files.h b/lib/files.h index efa7ddf10..15053d4d4 100644 --- a/lib/files.h +++ b/lib/files.h @@ -168,6 +168,17 @@ bool files_save_public(TPM2B_PUBLIC *public, const char *path); */ bool files_save_template(TPMT_PUBLIC *template, const char *path); +/** + * Like files_load_template(), but doesn't report errors. + * @param path + * The path containing the TPMT_PUBLIC to load from. + * @param public + * The destination for the TPMT_PUBLIC. + * @return + * true on success, false otherwise. + */ +bool files_load_template_silent(const char *path, TPMT_PUBLIC *public); + /** * Loads a TPM2B_PUBLIC from disk that was saved with files_save_pubkey() * @param path @@ -185,6 +196,16 @@ bool files_load_template(const char *path, TPMT_PUBLIC *public); bool files_load_template_file(FILE *f, const char *path, TPMT_PUBLIC *public); +/** + * Like files_load_public(), but doesn't report errors. + * @param path + * The path containing the TP2B_PUBLIC to load from. + * @param public + * The destination for the TP2B_PUBLIC. + * @return + * true on success, false otherwise. + */ +bool files_load_public_silent(const char *path, TPM2B_PUBLIC *public); /** * Serializes a TPMT_SIGNATURE to the file path provided. diff --git a/lib/tpm2_convert.c b/lib/tpm2_convert.c index 4ad4d0031..b9f7f26e5 100644 --- a/lib/tpm2_convert.c +++ b/lib/tpm2_convert.c @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include "files.h" @@ -69,7 +71,7 @@ bool tpm2_convert_pubkey_save(TPM2B_PUBLIC *public, } static bool convert_pubkey_RSA(TPMT_PUBLIC *public, - tpm2_convert_pubkey_fmt format, FILE *fp) { + tpm2_convert_pubkey_fmt format, BIO *bio) { bool ret = false; RSA *ssl_rsa_key = NULL; @@ -109,10 +111,10 @@ static bool convert_pubkey_RSA(TPMT_PUBLIC *public, switch (format) { case pubkey_format_pem: - ssl_res = PEM_write_RSA_PUBKEY(fp, ssl_rsa_key); + ssl_res = PEM_write_bio_RSA_PUBKEY(bio, ssl_rsa_key); break; case pubkey_format_der: - ssl_res = i2d_RSA_PUBKEY_fp(fp, ssl_rsa_key); + ssl_res = i2d_RSA_PUBKEY_bio(bio, ssl_rsa_key); break; default: LOG_ERR("Invalid OpenSSL target format %d encountered", format); @@ -140,7 +142,7 @@ static bool convert_pubkey_RSA(TPMT_PUBLIC *public, } static bool convert_pubkey_ECC(TPMT_PUBLIC *public, - tpm2_convert_pubkey_fmt format, FILE *fp) { + tpm2_convert_pubkey_fmt format, BIO *bio) { BIGNUM *x = NULL; BIGNUM *y = NULL; @@ -209,10 +211,10 @@ static bool convert_pubkey_ECC(TPMT_PUBLIC *public, switch (format) { case pubkey_format_pem: - ssl_res = PEM_write_EC_PUBKEY(fp, key); + ssl_res = PEM_write_bio_EC_PUBKEY(bio, key); break; case pubkey_format_der: - ssl_res = i2d_EC_PUBKEY_fp(fp, key); + ssl_res = i2d_EC_PUBKEY_bio(bio, key); break; default: LOG_ERR("Invalid OpenSSL target format %d encountered", format); @@ -243,37 +245,42 @@ static bool convert_pubkey_ECC(TPMT_PUBLIC *public, return result; } -static bool tpm2_convert_pubkey_ssl(TPMT_PUBLIC *public, - tpm2_convert_pubkey_fmt format, const char *path) { +static bool tpm2_convert_pubkey_bio(TPMT_PUBLIC *public, + tpm2_convert_pubkey_fmt format, BIO *bio) { bool result = false; - FILE *fp = fopen(path, "wb"); - if (!fp) { - LOG_ERR("Failed to open public key output file '%s': %s", path, - strerror(errno)); - goto out; - } - switch (public->type) { case TPM2_ALG_RSA: - result = convert_pubkey_RSA(public, format, fp); + result = convert_pubkey_RSA(public, format, bio); break; case TPM2_ALG_ECC: - result = convert_pubkey_ECC(public, format, fp); + result = convert_pubkey_ECC(public, format, bio); break; default: LOG_ERR( "Unsupported key type for requested output format. Only RSA is supported."); } - fclose(fp); - -out: ERR_free_strings(); return result; } +static bool tpm2_convert_pubkey_ssl(TPMT_PUBLIC *public, + tpm2_convert_pubkey_fmt format, const char *path) { + + BIO *bio = BIO_new_file(path, "wb"); + if (!bio) { + LOG_ERR("Failed to open public key output file '%s': %s", path, + ERR_error_string(ERR_get_error(), NULL)); + return false; + } + + bool result = tpm2_convert_pubkey_bio(public, format, bio); + BIO_free(bio); + return result; +} + bool tpm2_convert_sig_save(TPMT_SIGNATURE *signature, tpm2_convert_sig_fmt format, const char *path) { @@ -560,3 +567,72 @@ UINT8 *tpm2_convert_sig(UINT16 *size, TPMT_SIGNATURE *signature) { LOG_ERR("%s: couldn't allocate memory", __func__); return NULL; } + +bool tpm2_public_load_pkey(const char *path, EVP_PKEY **pkey) { + + bool result = false; + + BIO *bio = NULL; + EVP_PKEY *p = NULL; + + /* + * Order Matters. You must check for the smallest TSS size first, which + * it the TPMT_PUBLIC as it's embedded in the TPM2B_PUBLIC. It's possible + * to have valid TPMT's and have them parse as valid TPM2B_PUBLIC's (apparantly). + * + * If none of them convert, we try it as a plain signature. + */ + TPM2B_PUBLIC public = { 0 }; + bool ret = files_load_template_silent(path, &public.publicArea); + if (ret) { + goto convert_to_pem; + } + + ret = files_load_public_silent(path, &public); + if (ret) { + goto convert_to_pem; + } + + /* not a tss format, just treat it as a pem file */ + bio = BIO_new_file(path, "rb"); + if (!bio) { + LOG_ERR("Failed to open public key output file '%s': %s", path, + ERR_error_string(ERR_get_error(), NULL)); + return false; + } + + /* not a tpm data structure, must be pem */ + goto try_pem; + +convert_to_pem: + bio = BIO_new(BIO_s_mem()); + if (!bio) { + LOG_ERR("Failed to allocate memory bio: %s", + ERR_error_string(ERR_get_error(), NULL)); + return false; + } + + ret = tpm2_convert_pubkey_bio(&public.publicArea, pubkey_format_pem, bio); + if (!ret) { + goto out; + } + +try_pem: + p = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + if (!p) { + LOG_ERR("Failed to convert public key from file '%s': %s", path, + ERR_error_string(ERR_get_error(), NULL)); + goto out; + } + + *pkey = p; + + result = true; + +out: + if (bio) { + BIO_free(bio); + } + + return result; +} diff --git a/lib/tpm2_convert.h b/lib/tpm2_convert.h index b35279d4b..f8c821553 100644 --- a/lib/tpm2_convert.h +++ b/lib/tpm2_convert.h @@ -5,6 +5,8 @@ #include +#include + #include typedef enum tpm2_convert_pubkey_fmt tpm2_convert_pubkey_fmt; @@ -113,4 +115,6 @@ bool tpm2_convert_sig_load(const char *path, tpm2_convert_sig_fmt format, bool tpm2_convert_sig_load_plain(const char *path, TPM2B_MAX_BUFFER *signature, TPMI_ALG_HASH *halg); +bool tpm2_public_load_pkey(const char *path, EVP_PKEY **pkey); + #endif /* CONVERSION_H */ diff --git a/man/tpm2_verifysignature.1.md b/man/tpm2_verifysignature.1.md index b1115b0e9..61dbc3ffe 100644 --- a/man/tpm2_verifysignature.1.md +++ b/man/tpm2_verifysignature.1.md @@ -46,12 +46,19 @@ symmetric key, both the public and private portions need to be loaded. The input signature file of the signature to be validated. - * **-f**, **\--format**=_FORMAT_: + * **-f**, **\--scheme**=_SCHEME_: - Set the input signature file to a specified format. The default is the - tpm2.0 TPMT_SIGNATURE data format, however different schemes can be selected - if the data came from an external source like OpenSSL. The tool currently - only supports rsassa. + The signing scheme that was used to sign the message. This option should only + be specified if the signature comes in from a non *tss* standard, like openssl. + See "Signature format specifiers" for more details. The *tss* format contains + the signature metadata required to understand it's signature scheme. + + Signing schemes should follow the "formatting standards", see section + "Algorithm Specifiers". + + * **\--format**=_SCHEME_: + + Deprecated. Same as **\--scheme**. * **-t**, **\--ticket**=_FILE_: diff --git a/test/integration/tests/checkquote.sh b/test/integration/tests/checkquote.sh index 5134bb2f5..ea1c86e30 100755 --- a/test/integration/tests/checkquote.sh +++ b/test/integration/tests/checkquote.sh @@ -65,12 +65,22 @@ tpm2_createek -G ecc -c ecc.ek tpm2_createak -C ecc.ek -c ecc.ak -G ecc -g sha256 -s ecdsa -tpm2_readpublic -c ecc.ak -f pem -o ecc.ek.pem +tpm2_readpublic -c ecc.ak -f pem -o ecc.ak.pem tpm2_getrandom -o nonce.bin 20 tpm2_quote -c ecc.ak -l sha256:15,16,22 -q nonce.bin -m quote.bin -s quote.sig -o quote.pcr -g sha256 -tpm2_checkquote -u ecc.ek.pem -m quote.bin -s quote.sig -f quote.pcr -g sha256 -q nonce.bin +tpm2_checkquote -u ecc.ak.pem -m quote.bin -s quote.sig -f quote.pcr -g sha256 -q nonce.bin + +# Verify that tss format works +tpm2_readpublic -c ecc.ak -f tss -o ecc.ak.tss + +tpm2_checkquote -u ecc.ak.tss -m quote.bin -s quote.sig -f quote.pcr -g sha256 -q nonce.bin + +# Verify the tpmt format works +tpm2_readpublic -c ecc.ak -f tpmt -o ecc.ak.tpmt + +tpm2_checkquote -u ecc.ak.tpmt -m quote.bin -s quote.sig -f quote.pcr -g sha256 -q nonce.bin exit 0 diff --git a/tools/misc/tpm2_checkquote.c b/tools/misc/tpm2_checkquote.c index a658e1217..31600983f 100644 --- a/tools/misc/tpm2_checkquote.c +++ b/tools/misc/tpm2_checkquote.c @@ -52,17 +52,13 @@ static bool verify(void) { bool result = false; - // Read in the AKpub they provided as an RSA object - FILE *f = fopen(ctx.pubkey_file_path, "rb"); - if (!f) { - LOG_ERR("Could not open RSA pubkey input file \"%s\" error: \"%s\"", - ctx.pubkey_file_path, strerror(errno)); + /* read the public key */ + EVP_PKEY *pkey = NULL; + bool ret = tpm2_public_load_pkey(ctx.pubkey_file_path, &pkey); + if (!ret) { return false; } - /* read the public key */ - EVP_PKEY *pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL); - EVP_PKEY_CTX *pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL); if (!pkey_ctx) { LOG_ERR("EVP_PKEY_CTX_new failed: %s", ERR_error_string(ERR_get_error(), NULL)); @@ -125,9 +121,6 @@ static bool verify(void) { result = true; err: - if (f) { - fclose(f); - } EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(pkey_ctx); diff --git a/tools/tpm2_verifysignature.c b/tools/tpm2_verifysignature.c index 709e88f21..6d9dd843b 100644 --- a/tools/tpm2_verifysignature.c +++ b/tools/tpm2_verifysignature.c @@ -201,7 +201,9 @@ static bool on_option(char key, char *value) { ctx.flags.digest = 1; } break; - case 'f': { + case 0: + /* Falls-Thru */ + case 'f': ctx.format = tpm2_alg_util_from_optarg(value, tpm2_alg_util_flags_sig); if (ctx.format == TPM2_ALG_ERROR) { LOG_ERR("Unknown signing scheme, got: \"%s\"", value); @@ -209,7 +211,6 @@ static bool on_option(char key, char *value) { } ctx.flags.fmt = 1; - } break; case 's': ctx.sig_file_path = value; @@ -231,7 +232,8 @@ bool tpm2_tool_onstart(tpm2_options **opts) { { "digest", required_argument, NULL, 'd' }, { "hash-algorithm", required_argument, NULL, 'g' }, { "message", required_argument, NULL, 'm' }, - { "format", required_argument, NULL, 'f' }, + { "format", required_argument, NULL, '0' }, + { "scheme", required_argument, NULL, 'f' }, { "signature", required_argument, NULL, 's' }, { "ticket", required_argument, NULL, 't' }, { "key-context", required_argument, NULL, 'c' },