Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KEYS: trusted: Add session encryption protection to the seal/unseal path

If some entity is snooping the TPM bus, the can see the data going in
to be sealed and the data coming out as it is unsealed. Add parameter
and response encryption to these cases to ensure that no secrets are
leaked even if the bus is snooped.

As part of doing this conversion it was discovered that policy
sessions can't work with HMAC protected authority because of missing
pieces (the tpm Nonce). I've added code to work the same way as
before, which will result in potential authority exposure (while still
adding security for the command and the returned blob), and a fixme to
redo the API to get rid of this security hole.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Tested-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>

authored by

James Bottomley and committed by
Jarkko Sakkinen
52ce7d97 1b6d7f9e

+61 -27
+61 -27
security/keys/trusted-keys/trusted_tpm2.c
··· 253 253 if (rc) 254 254 return rc; 255 255 256 + rc = tpm2_start_auth_session(chip); 257 + if (rc) 258 + goto out_put; 259 + 256 260 rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE); 257 261 if (rc) { 258 - tpm_put_ops(chip); 259 - return rc; 262 + tpm2_end_auth_session(chip); 263 + goto out_put; 260 264 } 261 265 262 266 rc = tpm_buf_init_sized(&sized); 263 267 if (rc) { 264 268 tpm_buf_destroy(&buf); 265 - tpm_put_ops(chip); 266 - return rc; 269 + tpm2_end_auth_session(chip); 270 + goto out_put; 267 271 } 268 272 269 - tpm_buf_reset(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE); 270 - tpm_buf_append_u32(&buf, options->keyhandle); 271 - tpm2_buf_append_auth(&buf, TPM2_RS_PW, 272 - NULL /* nonce */, 0, 273 - 0 /* session_attributes */, 274 - options->keyauth /* hmac */, 275 - TPM_DIGEST_SIZE); 273 + tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); 274 + tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT, 275 + options->keyauth, TPM_DIGEST_SIZE); 276 276 277 277 /* sensitive */ 278 278 tpm_buf_append_u16(&sized, options->blobauth_len); ··· 314 314 315 315 if (buf.flags & TPM_BUF_OVERFLOW) { 316 316 rc = -E2BIG; 317 + tpm2_end_auth_session(chip); 317 318 goto out; 318 319 } 319 320 321 + tpm_buf_fill_hmac_session(chip, &buf); 320 322 rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data"); 323 + rc = tpm_buf_check_hmac_response(chip, &buf, rc); 321 324 if (rc) 322 325 goto out; 323 326 ··· 351 348 else 352 349 payload->blob_len = blob_len; 353 350 351 + out_put: 354 352 tpm_put_ops(chip); 355 353 return rc; 356 354 } ··· 421 417 if (blob_len > payload->blob_len) 422 418 return -E2BIG; 423 419 424 - rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD); 420 + rc = tpm2_start_auth_session(chip); 425 421 if (rc) 426 422 return rc; 427 423 428 - tpm_buf_append_u32(&buf, options->keyhandle); 429 - tpm2_buf_append_auth(&buf, TPM2_RS_PW, 430 - NULL /* nonce */, 0, 431 - 0 /* session_attributes */, 432 - options->keyauth /* hmac */, 433 - TPM_DIGEST_SIZE); 424 + rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD); 425 + if (rc) { 426 + tpm2_end_auth_session(chip); 427 + return rc; 428 + } 429 + 430 + tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); 431 + tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth, 432 + TPM_DIGEST_SIZE); 434 433 435 434 tpm_buf_append(&buf, blob, blob_len); 436 435 437 436 if (buf.flags & TPM_BUF_OVERFLOW) { 438 437 rc = -E2BIG; 438 + tpm2_end_auth_session(chip); 439 439 goto out; 440 440 } 441 441 442 + tpm_buf_fill_hmac_session(chip, &buf); 442 443 rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob"); 444 + rc = tpm_buf_check_hmac_response(chip, &buf, rc); 443 445 if (!rc) 444 446 *blob_handle = be32_to_cpup( 445 447 (__be32 *) &buf.data[TPM_HEADER_SIZE]); ··· 483 473 u8 *data; 484 474 int rc; 485 475 486 - rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL); 476 + rc = tpm2_start_auth_session(chip); 487 477 if (rc) 488 478 return rc; 489 479 490 - tpm_buf_append_u32(&buf, blob_handle); 491 - tpm2_buf_append_auth(&buf, 492 - options->policyhandle ? 493 - options->policyhandle : TPM2_RS_PW, 494 - NULL /* nonce */, 0, 495 - TPM2_SA_CONTINUE_SESSION, 496 - options->blobauth /* hmac */, 497 - options->blobauth_len); 480 + rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL); 481 + if (rc) { 482 + tpm2_end_auth_session(chip); 483 + return rc; 484 + } 498 485 486 + tpm_buf_append_name(chip, &buf, blob_handle, NULL); 487 + 488 + if (!options->policyhandle) { 489 + tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT, 490 + options->blobauth, 491 + options->blobauth_len); 492 + } else { 493 + /* 494 + * FIXME: The policy session was generated outside the 495 + * kernel so we don't known the nonce and thus can't 496 + * calculate a HMAC on it. Therefore, the user can 497 + * only really use TPM2_PolicyPassword and we must 498 + * send down the plain text password, which could be 499 + * intercepted. We can still encrypt the returned 500 + * key, but that's small comfort since the interposer 501 + * could repeat our actions with the exfiltrated 502 + * password. 503 + */ 504 + tpm2_buf_append_auth(&buf, options->policyhandle, 505 + NULL /* nonce */, 0, 0, 506 + options->blobauth, options->blobauth_len); 507 + tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT, 508 + NULL, 0); 509 + } 510 + 511 + tpm_buf_fill_hmac_session(chip, &buf); 499 512 rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing"); 513 + rc = tpm_buf_check_hmac_response(chip, &buf, rc); 500 514 if (rc > 0) 501 515 rc = -EPERM; 502 516