summaryrefslogtreecommitdiffstats
path: root/crypto/asymmetric_keys
diff options
context:
space:
mode:
authorDenis Kenzior <denkenz@gmail.com>2018-10-09 12:49:35 -0400
committerJames Morris <james.morris@microsoft.com>2018-10-26 04:30:47 -0400
commit64ae16dfeefec670276607fa789ce096c7ebd7c4 (patch)
tree80e5dfbf69f7f6d631870fc484db0752921af1af /crypto/asymmetric_keys
parente73d170f6c77e7006b48c5e9c325fe520f6012ca (diff)
KEYS: asym_tpm: Add support for the sign operation [ver #2]
The sign operation can operate in a non-hashed mode by running the RSA sign operation directly on the input. This assumes that the input is less than key_size_in_bytes - 11. Since the TPM performs its own PKCS1 padding, it isn't possible to support 'raw' mode, only 'pkcs1'. Alternatively, a hashed version is also possible. In this variant the input is hashed (by userspace) via the selected hash function first. Then this implementation takes care of converting the hash to ASN.1 format and the sign operation is performed on the result. This is similar to the implementation inside crypto/rsa-pkcs1pad.c. ASN1 templates were copied from crypto/rsa-pkcs1pad.c. There seems to be no easy way to expose that functionality, but likely the templates should be shared somehow. The sign operation is implemented via TPM_Sign operation on the TPM. It is assumed that the TPM wrapped key provided uses TPM_SS_RSASSAPKCS1v15_DER signature scheme. This allows the TPM_Sign operation to work on data up to key_len_in_bytes - 11 bytes long. In theory, we could also use TPM_Unbind instead of TPM_Sign, but we would have to manually pkcs1 pad the digest first. 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>
Diffstat (limited to 'crypto/asymmetric_keys')
-rw-r--r--crypto/asymmetric_keys/asym_tpm.c156
1 files changed, 155 insertions, 1 deletions
diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c
index a5a5f913a74f..5d4c270463f6 100644
--- a/crypto/asymmetric_keys/asym_tpm.c
+++ b/crypto/asymmetric_keys/asym_tpm.c
@@ -435,7 +435,8 @@ static int tpm_key_query(const struct kernel_pkey_params *params,
435 435
436 info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT | 436 info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT |
437 KEYCTL_SUPPORTS_DECRYPT | 437 KEYCTL_SUPPORTS_DECRYPT |
438 KEYCTL_SUPPORTS_VERIFY; 438 KEYCTL_SUPPORTS_VERIFY |
439 KEYCTL_SUPPORTS_SIGN;
439 440
440 ret = 0; 441 ret = 0;
441error_free_tfm: 442error_free_tfm:
@@ -557,6 +558,156 @@ error:
557} 558}
558 559
559/* 560/*
561 * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
562 */
563static const u8 digest_info_md5[] = {
564 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,
565 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, /* OID */
566 0x05, 0x00, 0x04, 0x10
567};
568
569static const u8 digest_info_sha1[] = {
570 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
571 0x2b, 0x0e, 0x03, 0x02, 0x1a,
572 0x05, 0x00, 0x04, 0x14
573};
574
575static const u8 digest_info_rmd160[] = {
576 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
577 0x2b, 0x24, 0x03, 0x02, 0x01,
578 0x05, 0x00, 0x04, 0x14
579};
580
581static const u8 digest_info_sha224[] = {
582 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
583 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
584 0x05, 0x00, 0x04, 0x1c
585};
586
587static const u8 digest_info_sha256[] = {
588 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
589 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
590 0x05, 0x00, 0x04, 0x20
591};
592
593static const u8 digest_info_sha384[] = {
594 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
595 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
596 0x05, 0x00, 0x04, 0x30
597};
598
599static const u8 digest_info_sha512[] = {
600 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
601 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
602 0x05, 0x00, 0x04, 0x40
603};
604
605static const struct asn1_template {
606 const char *name;
607 const u8 *data;
608 size_t size;
609} asn1_templates[] = {
610#define _(X) { #X, digest_info_##X, sizeof(digest_info_##X) }
611 _(md5),
612 _(sha1),
613 _(rmd160),
614 _(sha256),
615 _(sha384),
616 _(sha512),
617 _(sha224),
618 { NULL }
619#undef _
620};
621
622static const struct asn1_template *lookup_asn1(const char *name)
623{
624 const struct asn1_template *p;
625
626 for (p = asn1_templates; p->name; p++)
627 if (strcmp(name, p->name) == 0)
628 return p;
629 return NULL;
630}
631
632/*
633 * Sign operation is performed with the private key in the TPM.
634 */
635static int tpm_key_sign(struct tpm_key *tk,
636 struct kernel_pkey_params *params,
637 const void *in, void *out)
638{
639 struct tpm_buf *tb;
640 uint32_t keyhandle;
641 uint8_t srkauth[SHA1_DIGEST_SIZE];
642 uint8_t keyauth[SHA1_DIGEST_SIZE];
643 void *asn1_wrapped = NULL;
644 uint32_t in_len = params->in_len;
645 int r;
646
647 pr_devel("==>%s()\n", __func__);
648
649 if (strcmp(params->encoding, "pkcs1"))
650 return -ENOPKG;
651
652 if (params->hash_algo) {
653 const struct asn1_template *asn1 =
654 lookup_asn1(params->hash_algo);
655
656 if (!asn1)
657 return -ENOPKG;
658
659 /* request enough space for the ASN.1 template + input hash */
660 asn1_wrapped = kzalloc(in_len + asn1->size, GFP_KERNEL);
661 if (!asn1_wrapped)
662 return -ENOMEM;
663
664 /* Copy ASN.1 template, then the input */
665 memcpy(asn1_wrapped, asn1->data, asn1->size);
666 memcpy(asn1_wrapped + asn1->size, in, in_len);
667
668 in = asn1_wrapped;
669 in_len += asn1->size;
670 }
671
672 if (in_len > tk->key_len / 8 - 11) {
673 r = -EOVERFLOW;
674 goto error_free_asn1_wrapped;
675 }
676
677 r = -ENOMEM;
678 tb = kzalloc(sizeof(*tb), GFP_KERNEL);
679 if (!tb)
680 goto error_free_asn1_wrapped;
681
682 /* TODO: Handle a non-all zero SRK authorization */
683 memset(srkauth, 0, sizeof(srkauth));
684
685 r = tpm_loadkey2(tb, SRKHANDLE, srkauth,
686 tk->blob, tk->blob_len, &keyhandle);
687 if (r < 0) {
688 pr_devel("loadkey2 failed (%d)\n", r);
689 goto error_free_tb;
690 }
691
692 /* TODO: Handle a non-all zero key authorization */
693 memset(keyauth, 0, sizeof(keyauth));
694
695 r = tpm_sign(tb, keyhandle, keyauth, in, in_len, out, params->out_len);
696 if (r < 0)
697 pr_devel("tpm_sign failed (%d)\n", r);
698
699 if (tpm_flushspecific(tb, keyhandle) < 0)
700 pr_devel("flushspecific failed (%d)\n", r);
701
702error_free_tb:
703 kzfree(tb);
704error_free_asn1_wrapped:
705 kfree(asn1_wrapped);
706 pr_devel("<==%s() = %d\n", __func__, r);
707 return r;
708}
709
710/*
560 * Do encryption, decryption and signing ops. 711 * Do encryption, decryption and signing ops.
561 */ 712 */
562static int tpm_key_eds_op(struct kernel_pkey_params *params, 713static int tpm_key_eds_op(struct kernel_pkey_params *params,
@@ -573,6 +724,9 @@ static int tpm_key_eds_op(struct kernel_pkey_params *params,
573 case kernel_pkey_decrypt: 724 case kernel_pkey_decrypt:
574 ret = tpm_key_decrypt(tk, params, in, out); 725 ret = tpm_key_decrypt(tk, params, in, out);
575 break; 726 break;
727 case kernel_pkey_sign:
728 ret = tpm_key_sign(tk, params, in, out);
729 break;
576 default: 730 default:
577 BUG(); 731 BUG();
578 } 732 }