diff options
author | Denis Kenzior <denkenz@gmail.com> | 2018-10-09 12:48:58 -0400 |
---|---|---|
committer | James Morris <james.morris@microsoft.com> | 2018-10-26 04:30:47 -0400 |
commit | 0c36264aa1d5b77eb21f646f83223134e4528cfe (patch) | |
tree | a6415d4abbaffbd4aa103f51616db71560cf9d3f | |
parent | 22447981fc050b5f1bdd0e7cbee89b4152a2b2d8 (diff) |
KEYS: asym_tpm: Add loadkey2 and flushspecific [ver #2]
This commit adds TPM_LoadKey2 and TPM_FlushSpecific operations.
Signed-off-by: Denis Kenzior <denkenz@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: James Morris <james.morris@microsoft.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 | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c index 8edca3c4c193..6a2d33014ecc 100644 --- a/crypto/asymmetric_keys/asym_tpm.c +++ b/crypto/asymmetric_keys/asym_tpm.c | |||
@@ -7,11 +7,105 @@ | |||
7 | #include <linux/seq_file.h> | 7 | #include <linux/seq_file.h> |
8 | #include <linux/scatterlist.h> | 8 | #include <linux/scatterlist.h> |
9 | #include <linux/tpm.h> | 9 | #include <linux/tpm.h> |
10 | #include <linux/tpm_command.h> | ||
10 | #include <crypto/akcipher.h> | 11 | #include <crypto/akcipher.h> |
12 | #include <crypto/hash.h> | ||
13 | #include <crypto/sha.h> | ||
11 | #include <asm/unaligned.h> | 14 | #include <asm/unaligned.h> |
12 | #include <keys/asymmetric-subtype.h> | 15 | #include <keys/asymmetric-subtype.h> |
16 | #include <keys/trusted.h> | ||
13 | #include <crypto/asym_tpm_subtype.h> | 17 | #include <crypto/asym_tpm_subtype.h> |
14 | 18 | ||
19 | #define TPM_ORD_FLUSHSPECIFIC 186 | ||
20 | #define TPM_ORD_LOADKEY2 65 | ||
21 | #define TPM_LOADKEY2_SIZE 59 | ||
22 | #define TPM_FLUSHSPECIFIC_SIZE 18 | ||
23 | |||
24 | #define TPM_RT_KEY 0x00000001 | ||
25 | |||
26 | /* | ||
27 | * Load a TPM key from the blob provided by userspace | ||
28 | */ | ||
29 | static int tpm_loadkey2(struct tpm_buf *tb, | ||
30 | uint32_t keyhandle, unsigned char *keyauth, | ||
31 | const unsigned char *keyblob, int keybloblen, | ||
32 | uint32_t *newhandle) | ||
33 | { | ||
34 | unsigned char nonceodd[TPM_NONCE_SIZE]; | ||
35 | unsigned char enonce[TPM_NONCE_SIZE]; | ||
36 | unsigned char authdata[SHA1_DIGEST_SIZE]; | ||
37 | uint32_t authhandle = 0; | ||
38 | unsigned char cont = 0; | ||
39 | uint32_t ordinal; | ||
40 | int ret; | ||
41 | |||
42 | ordinal = htonl(TPM_ORD_LOADKEY2); | ||
43 | |||
44 | /* session for loading the key */ | ||
45 | ret = oiap(tb, &authhandle, enonce); | ||
46 | if (ret < 0) { | ||
47 | pr_info("oiap failed (%d)\n", ret); | ||
48 | return ret; | ||
49 | } | ||
50 | |||
51 | /* generate odd nonce */ | ||
52 | ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE); | ||
53 | if (ret < 0) { | ||
54 | pr_info("tpm_get_random failed (%d)\n", ret); | ||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | /* calculate authorization HMAC value */ | ||
59 | ret = TSS_authhmac(authdata, keyauth, SHA1_DIGEST_SIZE, enonce, | ||
60 | nonceodd, cont, sizeof(uint32_t), &ordinal, | ||
61 | keybloblen, keyblob, 0, 0); | ||
62 | if (ret < 0) | ||
63 | return ret; | ||
64 | |||
65 | /* build the request buffer */ | ||
66 | INIT_BUF(tb); | ||
67 | store16(tb, TPM_TAG_RQU_AUTH1_COMMAND); | ||
68 | store32(tb, TPM_LOADKEY2_SIZE + keybloblen); | ||
69 | store32(tb, TPM_ORD_LOADKEY2); | ||
70 | store32(tb, keyhandle); | ||
71 | storebytes(tb, keyblob, keybloblen); | ||
72 | store32(tb, authhandle); | ||
73 | storebytes(tb, nonceodd, TPM_NONCE_SIZE); | ||
74 | store8(tb, cont); | ||
75 | storebytes(tb, authdata, SHA1_DIGEST_SIZE); | ||
76 | |||
77 | ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); | ||
78 | if (ret < 0) { | ||
79 | pr_info("authhmac failed (%d)\n", ret); | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | ret = TSS_checkhmac1(tb->data, ordinal, nonceodd, keyauth, | ||
84 | SHA1_DIGEST_SIZE, 0, 0); | ||
85 | if (ret < 0) { | ||
86 | pr_info("TSS_checkhmac1 failed (%d)\n", ret); | ||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | *newhandle = LOAD32(tb->data, TPM_DATA_OFFSET); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Execute the FlushSpecific TPM command | ||
96 | */ | ||
97 | static int tpm_flushspecific(struct tpm_buf *tb, uint32_t handle) | ||
98 | { | ||
99 | INIT_BUF(tb); | ||
100 | store16(tb, TPM_TAG_RQU_COMMAND); | ||
101 | store32(tb, TPM_FLUSHSPECIFIC_SIZE); | ||
102 | store32(tb, TPM_ORD_FLUSHSPECIFIC); | ||
103 | store32(tb, handle); | ||
104 | store32(tb, TPM_RT_KEY); | ||
105 | |||
106 | return trusted_tpm_send(tb->data, MAX_BUF_SIZE); | ||
107 | } | ||
108 | |||
15 | /* | 109 | /* |
16 | * Maximum buffer size for the BER/DER encoded public key. The public key | 110 | * Maximum buffer size for the BER/DER encoded public key. The public key |
17 | * is of the form SEQUENCE { INTEGER n, INTEGER e } where n is a maximum 2048 | 111 | * is of the form SEQUENCE { INTEGER n, INTEGER e } where n is a maximum 2048 |