1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

tpm: Improve error handling and check returned lengths.

* tpm2d/command.c (cmd_pkdecrypt): Handle unknown algo.  Also slightly
rework error handling.
* tpm2d/tpm2.c (sexp_to_tpm2_public_ecc): Check length before checking
for 0x04.  Rework error handling.
(tpm2_ObjectPublic_GetName): Check the return value of
TSS_GetDigestSize before use.  Erro handling rework.
(tpm2_SensitiveToDuplicate): Ditto.
(tpm2_import_key): Ditto.
* tpm2d/intel-tss.h (TSS_Hash_Generate): Check passed length for
negative values.  Check return value of TSS_GetDigestSize.  Use
dedicated 16 bit length variable.
--

These are reworked and improved fixes as reported in
GnuPG-bug-id: 7129
This commit is contained in:
Werner Koch 2024-05-28 12:45:21 +02:00
parent 2e4b1f7850
commit d631c8198c
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 110 additions and 66 deletions

View File

@ -291,12 +291,12 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
{ {
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
int rc; int rc;
unsigned char *shadow_info; unsigned char *shadow_info = NULL;
size_t len; size_t len;
TSS_CONTEXT *tssc; TSS_CONTEXT *tssc;
TPM_HANDLE key; TPM_HANDLE key;
TPMI_ALG_PUBLIC type; TPMI_ALG_PUBLIC type;
unsigned char *crypto; unsigned char *crypto = NULL;
size_t cryptolen; size_t cryptolen;
char *buf; char *buf;
size_t buflen; size_t buflen;
@ -313,7 +313,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
rc = assuan_inquire (ctx, "EXTRA", &crypto, &cryptolen, MAXLEN_KEYDATA); rc = assuan_inquire (ctx, "EXTRA", &crypto, &cryptolen, MAXLEN_KEYDATA);
if (rc) if (rc)
goto out_freeshadow; goto out;
rc = tpm2_start (&tssc); rc = tpm2_start (&tssc);
if (rc) if (rc)
@ -329,6 +329,11 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
else if (type == TPM_ALG_ECC) else if (type == TPM_ALG_ECC)
rc = tpm2_ecc_decrypt (ctrl, tssc, key, pin_cb, crypto, rc = tpm2_ecc_decrypt (ctrl, tssc, key, pin_cb, crypto,
cryptolen, &buf, &buflen); cryptolen, &buf, &buflen);
else
{
rc = GPG_ERR_PUBKEY_ALGO;
goto end_out;
}
tpm2_flush_handle (tssc, key); tpm2_flush_handle (tssc, key);
@ -343,7 +348,6 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
out: out:
xfree (crypto); xfree (crypto);
out_freeshadow:
xfree (shadow_info); xfree (shadow_info);
return rc; return rc;

View File

@ -344,7 +344,7 @@ TSS_Hash_Generate(TPMT_HA *digest, ...)
int length; int length;
uint8_t *buffer; uint8_t *buffer;
int algo; int algo;
gcry_md_hd_t md; gcry_md_hd_t md = NULL;
va_list ap; va_list ap;
va_start(ap, digest); va_start(ap, digest);
@ -353,7 +353,7 @@ TSS_Hash_Generate(TPMT_HA *digest, ...)
if (rc) if (rc)
{ {
log_error ("TSS_Hash_Generate: Unknown hash %d\n", digest->hashAlg); log_error ("TSS_Hash_Generate: Unknown hash %d\n", digest->hashAlg);
goto out; goto leave;
} }
rc = gcry_md_open (&md, algo, 0); rc = gcry_md_open (&md, algo, 0);
@ -362,7 +362,7 @@ TSS_Hash_Generate(TPMT_HA *digest, ...)
log_error ("TSS_Hash_Generate: EVP_MD_CTX_create failed: %s\n", log_error ("TSS_Hash_Generate: EVP_MD_CTX_create failed: %s\n",
gpg_strerror (rc)); gpg_strerror (rc));
rc = TPM_RC_FAILURE; rc = TPM_RC_FAILURE;
goto out; goto leave;
} }
rc = TPM_RC_FAILURE; rc = TPM_RC_FAILURE;
@ -374,19 +374,24 @@ TSS_Hash_Generate(TPMT_HA *digest, ...)
break; break;
if (length < 0) if (length < 0)
{ {
log_error ("TSS_Hash_Generate: Length is negative\n"); log_error ("%s: Length is negative\n", "TSS_Hash_Generate");
goto out_free; goto leave;
} }
if (length != 0) if (length != 0)
gcry_md_write (md, buffer, length); gcry_md_write (md, buffer, length);
} }
memcpy (&digest->digest, gcry_md_read (md, algo), length = TSS_GetDigestSize(digest->hashAlg);
TSS_GetDigestSize(digest->hashAlg)); if (length < 0)
{
log_error ("%s: Length is negative\n", "TSS_GetDigestSize");
goto leave;
}
memcpy (&digest->digest, gcry_md_read (md, algo), length);
rc = TPM_RC_SUCCESS; rc = TPM_RC_SUCCESS;
out_free:
leave:
gcry_md_close (md); gcry_md_close (md);
out:
va_end(ap); va_end(ap);
return rc; return rc;
} }

View File

@ -446,46 +446,55 @@ static int
sexp_to_tpm2_public_ecc (TPMT_PUBLIC *p, gcry_sexp_t key) sexp_to_tpm2_public_ecc (TPMT_PUBLIC *p, gcry_sexp_t key)
{ {
const char *q; const char *q;
gcry_sexp_t l; gcry_sexp_t l = NULL;
int rc = GPG_ERR_BAD_PUBKEY; int rc;
size_t len; size_t len;
TPMI_ECC_CURVE curve; TPMI_ECC_CURVE curve;
char *curve_name; char *curve_name = NULL;
l = gcry_sexp_find_token (key, "curve", 0); l = gcry_sexp_find_token (key, "curve", 0);
if (!l) if (!l)
return rc; {
rc = GPG_ERR_NO_PUBKEY;
goto leave;
}
curve_name = gcry_sexp_nth_string (l, 1); curve_name = gcry_sexp_nth_string (l, 1);
if (!curve_name) if (!curve_name)
goto out; {
rc = GPG_ERR_INV_CURVE;
goto leave;
}
rc = tpm2_ecc_curve (curve_name, &curve); rc = tpm2_ecc_curve (curve_name, &curve);
gcry_free (curve_name);
if (rc) if (rc)
goto out; goto leave;
gcry_sexp_release (l);
gcry_sexp_release (l);
l = gcry_sexp_find_token (key, "q", 0); l = gcry_sexp_find_token (key, "q", 0);
if (!l) if (!l)
return rc; {
rc = GPG_ERR_NO_PUBKEY;
goto leave;
}
q = gcry_sexp_nth_data (l, 1, &len); q = gcry_sexp_nth_data (l, 1, &len);
/* This is a point representation, the first byte tells you what /* This is a point representation, the first byte tells you what
* type. The only format we understand is uncompressed (0x04) * type. The only format we understand is uncompressed (0x04)
* which has layout 0x04 | x | y */ * which has layout 0x04 | x | y */
if (q[0] != 0x04) if (!q || len < 2 || q[0] != 0x04)
{ {
log_error ("Point format for q is not uncompressed\n"); log_error ("tss: point format for q is not uncompressed\n");
goto out; rc = GPG_ERR_BAD_PUBKEY;
goto leave;
} }
q++; q++;
len--; len--;
/* now should have to equal sized big endian point numbers */ /* now should have to equal sized big endian point numbers */
if ((len & 0x01) == 1) if ((len & 0x01) == 1)
{ {
log_error ("Point format for q has incorrect length\n"); log_error ("tss: point format for q has incorrect length\n");
goto out; rc = GPG_ERR_BAD_PUBKEY;
goto leave;
} }
len >>= 1; /* Compute length of one coordinate. */
len >>= 1;
p->type = TPM_ALG_ECC; p->type = TPM_ALG_ECC;
p->nameAlg = TPM_ALG_SHA256; p->nameAlg = TPM_ALG_SHA256;
@ -502,7 +511,9 @@ sexp_to_tpm2_public_ecc (TPMT_PUBLIC *p, gcry_sexp_t key)
VAL_2B (p->unique.ecc.x, size) = len; VAL_2B (p->unique.ecc.x, size) = len;
memcpy (VAL_2B (p->unique.ecc.y, buffer), q + len, len); memcpy (VAL_2B (p->unique.ecc.y, buffer), q + len, len);
VAL_2B (p->unique.ecc.y, size) = len; VAL_2B (p->unique.ecc.y, size) = len;
out:
leave:
gcry_free (curve_name);
gcry_sexp_release (l); gcry_sexp_release (l);
return rc; return rc;
} }
@ -637,36 +648,42 @@ tpm2_ObjectPublic_GetName (NAME_2B *name,
uint16_t written = 0; uint16_t written = 0;
TPMT_HA digest; TPMT_HA digest;
uint32_t sizeInBytes; uint32_t sizeInBytes;
INT32 size = MAX_RESPONSE_SIZE;
uint8_t buffer[MAX_RESPONSE_SIZE]; uint8_t buffer[MAX_RESPONSE_SIZE];
uint8_t *buffer1 = buffer;
TPMI_ALG_HASH nameAlgNbo;
int length;
/* marshal the TPMT_PUBLIC */ /* marshal the TPMT_PUBLIC */
if (rc == 0) rc = TSS_TPMT_PUBLIC_Marshal (tpmtPublic, &written, &buffer1, &size);
{ if (rc)
INT32 size = MAX_RESPONSE_SIZE; goto leave;
uint8_t *buffer1 = buffer;
rc = TSS_TPMT_PUBLIC_Marshal (tpmtPublic, &written, &buffer1, &size);
}
/* hash the public area */
if (rc == 0)
{
sizeInBytes = TSS_GetDigestSize (tpmtPublic->nameAlg);
digest.hashAlg = tpmtPublic->nameAlg; /* Name digest algorithm */
/* generate the TPMT_HA */
rc = TSS_Hash_Generate (&digest, written, buffer, 0, NULL);
}
if (rc == 0)
{
TPMI_ALG_HASH nameAlgNbo;
/* copy the digest */ /* hash the public area */
memcpy (name->name + sizeof (TPMI_ALG_HASH), length = TSS_GetDigestSize (tpmtPublic->nameAlg);
(uint8_t *)&digest.digest, sizeInBytes); if (length < 0)
/* copy the hash algorithm */ {
nameAlgNbo = htons (tpmtPublic->nameAlg); rc = TPM_RC_VALUE;
memcpy (name->name, (uint8_t *)&nameAlgNbo, sizeof (TPMI_ALG_HASH)); goto leave;
/* set the size */
name->size = sizeInBytes + sizeof (TPMI_ALG_HASH);
} }
sizeInBytes = length;
digest.hashAlg = tpmtPublic->nameAlg; /* Name digest algorithm */
/* generate the TPMT_HA */
rc = TSS_Hash_Generate (&digest, written, buffer, 0, NULL);
if (rc)
goto leave;
/* copy the digest */
memcpy (name->name + sizeof (TPMI_ALG_HASH),
(uint8_t *)&digest.digest, sizeInBytes);
/* copy the hash algorithm */
nameAlgNbo = htons (tpmtPublic->nameAlg);
memcpy (name->name, (uint8_t *)&nameAlgNbo, sizeof (TPMI_ALG_HASH));
/* set the size */
name->size = sizeInBytes + sizeof (TPMI_ALG_HASH);
leave:
return rc; return rc;
} }
@ -694,7 +711,7 @@ TPM_RC tpm2_SensitiveToDuplicate (TPMT_SENSITIVE *s,
&& symdef->mode.aes == TPM_ALG_CFB) && symdef->mode.aes == TPM_ALG_CFB)
{ {
TPMT_HA hash; TPMT_HA hash;
const int hlen = TSS_GetDigestSize (nalg); int hlen;
BYTE *digest; BYTE *digest;
BYTE *s2b; BYTE *s2b;
int32_t size; int32_t size;
@ -706,6 +723,14 @@ TPM_RC tpm2_SensitiveToDuplicate (TPMT_SENSITIVE *s,
* the AES routines alter the passed in iv */ * the AES routines alter the passed in iv */
memset (null_iv, 0, sizeof (null_iv)); memset (null_iv, 0, sizeof (null_iv));
hlen = TSS_GetDigestSize (nalg);
if (hlen < 0)
{
log_error ("%s: unknown symmetric algo id %d\n",
"TSS_GetDigestSize", (int)nalg);
return TPM_RC_SYMMETRIC;
}
/* reserve space for hash before the encrypted sensitive */ /* reserve space for hash before the encrypted sensitive */
digest = buf; digest = buf;
bsize = sizeof (uint16_t /* TPM2B.size */) + hlen; bsize = sizeof (uint16_t /* TPM2B.size */) + hlen;
@ -765,7 +790,7 @@ TPM_RC tpm2_SensitiveToDuplicate (TPMT_SENSITIVE *s,
} }
else else
{ {
log_error ("Unknown symmetric algorithm\n"); log_error ("tss: Unknown symmetric algorithm\n");
return TPM_RC_SYMMETRIC; return TPM_RC_SYMMETRIC;
} }
@ -795,7 +820,9 @@ tpm2_import_key (ctrl_t ctrl, TSS_CONTEXT *tssc,
TPM_RC rc; TPM_RC rc;
uint32_t size; uint32_t size;
uint16_t len; uint16_t u16len;
size_t len;
int dlen;
BYTE *buffer; BYTE *buffer;
int ret; int ret;
char *passphrase; char *passphrase;
@ -817,14 +844,22 @@ tpm2_import_key (ctrl_t ctrl, TSS_CONTEXT *tssc,
/* add an authorization password to the key which the TPM will check */ /* add an authorization password to the key which the TPM will check */
ret = pin_cb (ctrl, _("Please enter the TPM Authorization passphrase for the key."), &passphrase); ret = pin_cb (ctrl,
_("Please enter the TPM Authorization passphrase for the key."),
&passphrase);
if (ret) if (ret)
return ret; return ret;
len = strlen(passphrase); len = strlen(passphrase);
if (len > TSS_GetDigestSize(objectPublic.publicArea.nameAlg)) dlen = TSS_GetDigestSize(objectPublic.publicArea.nameAlg);
if (dlen < 0)
{ {
len = TSS_GetDigestSize(objectPublic.publicArea.nameAlg); log_error ("%s: error getting digest size\n", "TSS_GetDigestSize");
log_error ("Truncating Passphrase to TPM allowed %d\n", len); return GPG_ERR_DIGEST_ALGO;
}
if (len > dlen)
{
len = dlen;
log_info ("tss: truncating Passphrase to TPM allowed size of %zu\n", len);
} }
VAL_2B (s.authValue, size) = len; VAL_2B (s.authValue, size) = len;
memcpy (VAL_2B (s.authValue, buffer), passphrase, len); memcpy (VAL_2B (s.authValue, buffer), passphrase, len);
@ -885,16 +920,16 @@ tpm2_import_key (ctrl_t ctrl, TSS_CONTEXT *tssc,
size = sizeof (pub); size = sizeof (pub);
buffer = pub; buffer = pub;
len = 0; u16len = 0;
TSS_TPM2B_PUBLIC_Marshal (&objectPublic, TSS_TPM2B_PUBLIC_Marshal (&objectPublic,
&len, &buffer, &size); &u16len, &buffer, &size);
pub_len = len; pub_len = len;
size = sizeof (priv); size = sizeof (priv);
buffer = priv; buffer = priv;
len = 0; u16len = 0;
TSS_TPM2B_PRIVATE_Marshal ((TPM2B_PRIVATE *)&outPrivate, TSS_TPM2B_PRIVATE_Marshal ((TPM2B_PRIVATE *)&outPrivate,
&len, &buffer, &size); &u16len, &buffer, &size);
priv_len = len; priv_len = len;
*shadow_info = make_tpm2_shadow_info (parent, pub, pub_len, *shadow_info = make_tpm2_shadow_info (parent, pub, pub_len,