diff options
author | Denis Kenzior <denkenz@gmail.com> | 2018-10-09 12:48:17 -0400 |
---|---|---|
committer | James Morris <james.morris@microsoft.com> | 2018-10-26 04:30:46 -0400 |
commit | d5e72745ca121459f68c598dac7b374a76322b94 (patch) | |
tree | fbe5574be8ae84efcdf4a19f5c634b819b8e66ad /crypto | |
parent | f8c54e1ac4b82933dfcf88c37892da8ae35ccbe4 (diff) |
KEYS: Add parser for TPM-based keys [ver #2]
For TPM based keys, the only standard seems to be described here:
http://david.woodhou.se/draft-woodhouse-cert-best-practice.html#rfc.section.4.4
Quote from the relevant section:
"Rather, a common form of storage for "wrapped" keys is to encode the
binary TCPA_KEY structure in a single ASN.1 OCTET-STRING, and store the
result in PEM format with the tag "-----BEGIN TSS KEY BLOB-----". "
This patch implements the above behavior. It is assumed that the PEM
encoding is stripped out by userspace and only the raw DER/BER format is
provided. This is similar to how PKCS7, PKCS8 and X.509 keys are
handled.
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')
-rw-r--r-- | crypto/asymmetric_keys/Kconfig | 9 | ||||
-rw-r--r-- | crypto/asymmetric_keys/Makefile | 11 | ||||
-rw-r--r-- | crypto/asymmetric_keys/tpm.asn1 | 5 | ||||
-rw-r--r-- | crypto/asymmetric_keys/tpm_parser.c | 102 |
4 files changed, 127 insertions, 0 deletions
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index b75555c7d8ae..88353a9ebc9b 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig | |||
@@ -52,6 +52,15 @@ config PKCS8_PRIVATE_KEY_PARSER | |||
52 | private key data and provides the ability to instantiate a crypto key | 52 | private key data and provides the ability to instantiate a crypto key |
53 | from that data. | 53 | from that data. |
54 | 54 | ||
55 | config TPM_KEY_PARSER | ||
56 | tristate "TPM private key parser" | ||
57 | depends on ASYMMETRIC_TPM_KEY_SUBTYPE | ||
58 | select ASN1 | ||
59 | help | ||
60 | This option provides support for parsing TPM format blobs for | ||
61 | private key data and provides the ability to instantiate a crypto key | ||
62 | from that data. | ||
63 | |||
55 | config PKCS7_MESSAGE_PARSER | 64 | config PKCS7_MESSAGE_PARSER |
56 | tristate "PKCS#7 message parser" | 65 | tristate "PKCS#7 message parser" |
57 | depends on X509_CERTIFICATE_PARSER | 66 | depends on X509_CERTIFICATE_PARSER |
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index 73fbe650ff1d..28b91adba2ae 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile | |||
@@ -75,3 +75,14 @@ verify_signed_pefile-y := \ | |||
75 | 75 | ||
76 | $(obj)/mscode_parser.o: $(obj)/mscode.asn1.h $(obj)/mscode.asn1.h | 76 | $(obj)/mscode_parser.o: $(obj)/mscode.asn1.h $(obj)/mscode.asn1.h |
77 | $(obj)/mscode.asn1.o: $(obj)/mscode.asn1.c $(obj)/mscode.asn1.h | 77 | $(obj)/mscode.asn1.o: $(obj)/mscode.asn1.c $(obj)/mscode.asn1.h |
78 | |||
79 | # | ||
80 | # TPM private key parsing | ||
81 | # | ||
82 | obj-$(CONFIG_TPM_KEY_PARSER) += tpm_key_parser.o | ||
83 | tpm_key_parser-y := \ | ||
84 | tpm.asn1.o \ | ||
85 | tpm_parser.o | ||
86 | |||
87 | $(obj)/tpm_parser.o: $(obj)/tpm.asn1.h | ||
88 | $(obj)/tpm.asn1.o: $(obj)/tpm.asn1.c $(obj)/tpm.asn1.h | ||
diff --git a/crypto/asymmetric_keys/tpm.asn1 b/crypto/asymmetric_keys/tpm.asn1 new file mode 100644 index 000000000000..d7f194232f30 --- /dev/null +++ b/crypto/asymmetric_keys/tpm.asn1 | |||
@@ -0,0 +1,5 @@ | |||
1 | -- | ||
2 | -- Unencryted TPM Blob. For details of the format, see: | ||
3 | -- http://david.woodhou.se/draft-woodhouse-cert-best-practice.html#I-D.mavrogiannopoulos-tpmuri | ||
4 | -- | ||
5 | PrivateKeyInfo ::= OCTET STRING ({ tpm_note_key }) | ||
diff --git a/crypto/asymmetric_keys/tpm_parser.c b/crypto/asymmetric_keys/tpm_parser.c new file mode 100644 index 000000000000..96405d8dcd98 --- /dev/null +++ b/crypto/asymmetric_keys/tpm_parser.c | |||
@@ -0,0 +1,102 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #define pr_fmt(fmt) "TPM-PARSER: "fmt | ||
3 | #include <linux/module.h> | ||
4 | #include <linux/kernel.h> | ||
5 | #include <linux/export.h> | ||
6 | #include <linux/slab.h> | ||
7 | #include <linux/err.h> | ||
8 | #include <keys/asymmetric-subtype.h> | ||
9 | #include <keys/asymmetric-parser.h> | ||
10 | #include <crypto/asym_tpm_subtype.h> | ||
11 | #include "tpm.asn1.h" | ||
12 | |||
13 | struct tpm_parse_context { | ||
14 | const void *blob; | ||
15 | u32 blob_len; | ||
16 | }; | ||
17 | |||
18 | /* | ||
19 | * Note the key data of the ASN.1 blob. | ||
20 | */ | ||
21 | int tpm_note_key(void *context, size_t hdrlen, | ||
22 | unsigned char tag, | ||
23 | const void *value, size_t vlen) | ||
24 | { | ||
25 | struct tpm_parse_context *ctx = context; | ||
26 | |||
27 | ctx->blob = value; | ||
28 | ctx->blob_len = vlen; | ||
29 | |||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * Parse a TPM-encrypted private key blob. | ||
35 | */ | ||
36 | static struct tpm_key *tpm_parse(const void *data, size_t datalen) | ||
37 | { | ||
38 | struct tpm_parse_context ctx; | ||
39 | long ret; | ||
40 | |||
41 | memset(&ctx, 0, sizeof(ctx)); | ||
42 | |||
43 | /* Attempt to decode the private key */ | ||
44 | ret = asn1_ber_decoder(&tpm_decoder, &ctx, data, datalen); | ||
45 | if (ret < 0) | ||
46 | goto error; | ||
47 | |||
48 | return tpm_key_create(ctx.blob, ctx.blob_len); | ||
49 | |||
50 | error: | ||
51 | return ERR_PTR(ret); | ||
52 | } | ||
53 | /* | ||
54 | * Attempt to parse a data blob for a key as a TPM private key blob. | ||
55 | */ | ||
56 | static int tpm_key_preparse(struct key_preparsed_payload *prep) | ||
57 | { | ||
58 | struct tpm_key *tk; | ||
59 | |||
60 | /* | ||
61 | * TPM 1.2 keys are max 2048 bits long, so assume the blob is no | ||
62 | * more than 4x that | ||
63 | */ | ||
64 | if (prep->datalen > 256 * 4) | ||
65 | return -EMSGSIZE; | ||
66 | |||
67 | tk = tpm_parse(prep->data, prep->datalen); | ||
68 | |||
69 | if (IS_ERR(tk)) | ||
70 | return PTR_ERR(tk); | ||
71 | |||
72 | /* We're pinning the module by being linked against it */ | ||
73 | __module_get(asym_tpm_subtype.owner); | ||
74 | prep->payload.data[asym_subtype] = &asym_tpm_subtype; | ||
75 | prep->payload.data[asym_key_ids] = NULL; | ||
76 | prep->payload.data[asym_crypto] = tk; | ||
77 | prep->payload.data[asym_auth] = NULL; | ||
78 | prep->quotalen = 100; | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static struct asymmetric_key_parser tpm_key_parser = { | ||
83 | .owner = THIS_MODULE, | ||
84 | .name = "tpm_parser", | ||
85 | .parse = tpm_key_preparse, | ||
86 | }; | ||
87 | |||
88 | static int __init tpm_key_init(void) | ||
89 | { | ||
90 | return register_asymmetric_key_parser(&tpm_key_parser); | ||
91 | } | ||
92 | |||
93 | static void __exit tpm_key_exit(void) | ||
94 | { | ||
95 | unregister_asymmetric_key_parser(&tpm_key_parser); | ||
96 | } | ||
97 | |||
98 | module_init(tpm_key_init); | ||
99 | module_exit(tpm_key_exit); | ||
100 | |||
101 | MODULE_DESCRIPTION("TPM private key-blob parser"); | ||
102 | MODULE_LICENSE("GPL v2"); | ||