diff options
author | Denis Kenzior <denkenz@gmail.com> | 2018-10-09 12:49:20 -0400 |
---|---|---|
committer | James Morris <james.morris@microsoft.com> | 2018-10-26 04:30:47 -0400 |
commit | e08e6891231f5fae82a6ffb4affdfa2ced8c1a77 (patch) | |
tree | 35766b02094256b30237bfd93656ced38faf11a4 | |
parent | a335974ae0883e045151a2160093a22aa02c3626 (diff) |
KEYS: asym_tpm: Implement signature verification [ver #2]
This patch implements the verify_signature operation. The public key
portion extracted from the TPM key blob is used. The operation is
performed entirely in software using the crypto API.
Signed-off-by: Denis Kenzior <denkenz@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: James Morris <james.morris@microsoft.com>
-rw-r--r-- | crypto/asymmetric_keys/asym_tpm.c | 106 |
1 files changed, 100 insertions, 6 deletions
diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c index 6f5d5cf98910..a38ba375675e 100644 --- a/crypto/asymmetric_keys/asym_tpm.c +++ b/crypto/asymmetric_keys/asym_tpm.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <keys/asymmetric-subtype.h> | 15 | #include <keys/asymmetric-subtype.h> |
16 | #include <keys/trusted.h> | 16 | #include <keys/trusted.h> |
17 | #include <crypto/asym_tpm_subtype.h> | 17 | #include <crypto/asym_tpm_subtype.h> |
18 | #include <crypto/public_key.h> | ||
18 | 19 | ||
19 | #define TPM_ORD_FLUSHSPECIFIC 186 | 20 | #define TPM_ORD_FLUSHSPECIFIC 186 |
20 | #define TPM_ORD_LOADKEY2 65 | 21 | #define TPM_ORD_LOADKEY2 65 |
@@ -286,12 +287,16 @@ static uint32_t derive_pub_key(const void *pub_key, uint32_t len, uint8_t *buf) | |||
286 | static int determine_akcipher(const char *encoding, const char *hash_algo, | 287 | static int determine_akcipher(const char *encoding, const char *hash_algo, |
287 | char alg_name[CRYPTO_MAX_ALG_NAME]) | 288 | char alg_name[CRYPTO_MAX_ALG_NAME]) |
288 | { | 289 | { |
289 | /* TODO: We don't support hashing yet */ | ||
290 | if (hash_algo) | ||
291 | return -ENOPKG; | ||
292 | |||
293 | if (strcmp(encoding, "pkcs1") == 0) { | 290 | if (strcmp(encoding, "pkcs1") == 0) { |
294 | strcpy(alg_name, "pkcs1pad(rsa)"); | 291 | if (!hash_algo) { |
292 | strcpy(alg_name, "pkcs1pad(rsa)"); | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | if (snprintf(alg_name, CRYPTO_MAX_ALG_NAME, "pkcs1pad(rsa,%s)", | ||
297 | hash_algo) >= CRYPTO_MAX_ALG_NAME) | ||
298 | return -EINVAL; | ||
299 | |||
295 | return 0; | 300 | return 0; |
296 | } | 301 | } |
297 | 302 | ||
@@ -342,7 +347,8 @@ static int tpm_key_query(const struct kernel_pkey_params *params, | |||
342 | info->max_dec_size = tk->key_len / 8; | 347 | info->max_dec_size = tk->key_len / 8; |
343 | 348 | ||
344 | info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT | | 349 | info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT | |
345 | KEYCTL_SUPPORTS_DECRYPT; | 350 | KEYCTL_SUPPORTS_DECRYPT | |
351 | KEYCTL_SUPPORTS_VERIFY; | ||
346 | 352 | ||
347 | ret = 0; | 353 | ret = 0; |
348 | error_free_tfm: | 354 | error_free_tfm: |
@@ -488,6 +494,93 @@ static int tpm_key_eds_op(struct kernel_pkey_params *params, | |||
488 | } | 494 | } |
489 | 495 | ||
490 | /* | 496 | /* |
497 | * Verify a signature using a public key. | ||
498 | */ | ||
499 | static int tpm_key_verify_signature(const struct key *key, | ||
500 | const struct public_key_signature *sig) | ||
501 | { | ||
502 | const struct tpm_key *tk = key->payload.data[asym_crypto]; | ||
503 | struct crypto_wait cwait; | ||
504 | struct crypto_akcipher *tfm; | ||
505 | struct akcipher_request *req; | ||
506 | struct scatterlist sig_sg, digest_sg; | ||
507 | char alg_name[CRYPTO_MAX_ALG_NAME]; | ||
508 | uint8_t der_pub_key[PUB_KEY_BUF_SIZE]; | ||
509 | uint32_t der_pub_key_len; | ||
510 | void *output; | ||
511 | unsigned int outlen; | ||
512 | int ret; | ||
513 | |||
514 | pr_devel("==>%s()\n", __func__); | ||
515 | |||
516 | BUG_ON(!tk); | ||
517 | BUG_ON(!sig); | ||
518 | BUG_ON(!sig->s); | ||
519 | |||
520 | if (!sig->digest) | ||
521 | return -ENOPKG; | ||
522 | |||
523 | ret = determine_akcipher(sig->encoding, sig->hash_algo, alg_name); | ||
524 | if (ret < 0) | ||
525 | return ret; | ||
526 | |||
527 | tfm = crypto_alloc_akcipher(alg_name, 0, 0); | ||
528 | if (IS_ERR(tfm)) | ||
529 | return PTR_ERR(tfm); | ||
530 | |||
531 | der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len, | ||
532 | der_pub_key); | ||
533 | |||
534 | ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len); | ||
535 | if (ret < 0) | ||
536 | goto error_free_tfm; | ||
537 | |||
538 | ret = -ENOMEM; | ||
539 | req = akcipher_request_alloc(tfm, GFP_KERNEL); | ||
540 | if (!req) | ||
541 | goto error_free_tfm; | ||
542 | |||
543 | ret = -ENOMEM; | ||
544 | outlen = crypto_akcipher_maxsize(tfm); | ||
545 | output = kmalloc(outlen, GFP_KERNEL); | ||
546 | if (!output) | ||
547 | goto error_free_req; | ||
548 | |||
549 | sg_init_one(&sig_sg, sig->s, sig->s_size); | ||
550 | sg_init_one(&digest_sg, output, outlen); | ||
551 | akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size, | ||
552 | outlen); | ||
553 | crypto_init_wait(&cwait); | ||
554 | akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | | ||
555 | CRYPTO_TFM_REQ_MAY_SLEEP, | ||
556 | crypto_req_done, &cwait); | ||
557 | |||
558 | /* Perform the verification calculation. This doesn't actually do the | ||
559 | * verification, but rather calculates the hash expected by the | ||
560 | * signature and returns that to us. | ||
561 | */ | ||
562 | ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait); | ||
563 | if (ret) | ||
564 | goto out_free_output; | ||
565 | |||
566 | /* Do the actual verification step. */ | ||
567 | if (req->dst_len != sig->digest_size || | ||
568 | memcmp(sig->digest, output, sig->digest_size) != 0) | ||
569 | ret = -EKEYREJECTED; | ||
570 | |||
571 | out_free_output: | ||
572 | kfree(output); | ||
573 | error_free_req: | ||
574 | akcipher_request_free(req); | ||
575 | error_free_tfm: | ||
576 | crypto_free_akcipher(tfm); | ||
577 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
578 | if (WARN_ON_ONCE(ret > 0)) | ||
579 | ret = -EINVAL; | ||
580 | return ret; | ||
581 | } | ||
582 | |||
583 | /* | ||
491 | * Parse enough information out of TPM_KEY structure: | 584 | * Parse enough information out of TPM_KEY structure: |
492 | * TPM_STRUCT_VER -> 4 bytes | 585 | * TPM_STRUCT_VER -> 4 bytes |
493 | * TPM_KEY_USAGE -> 2 bytes | 586 | * TPM_KEY_USAGE -> 2 bytes |
@@ -645,6 +738,7 @@ struct asymmetric_key_subtype asym_tpm_subtype = { | |||
645 | .destroy = asym_tpm_destroy, | 738 | .destroy = asym_tpm_destroy, |
646 | .query = tpm_key_query, | 739 | .query = tpm_key_query, |
647 | .eds_op = tpm_key_eds_op, | 740 | .eds_op = tpm_key_eds_op, |
741 | .verify_signature = tpm_key_verify_signature, | ||
648 | }; | 742 | }; |
649 | EXPORT_SYMBOL_GPL(asym_tpm_subtype); | 743 | EXPORT_SYMBOL_GPL(asym_tpm_subtype); |
650 | 744 | ||