1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2004 IBM Corporation
4*4882a593Smuzhiyun * Copyright (C) 2014 Intel Corporation
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/string.h>
8*4882a593Smuzhiyun #include <linux/err.h>
9*4882a593Smuzhiyun #include <linux/tpm.h>
10*4882a593Smuzhiyun #include <linux/tpm_command.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <keys/trusted-type.h>
13*4882a593Smuzhiyun #include <keys/trusted_tpm.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun static struct tpm2_hash tpm2_hash_map[] = {
16*4882a593Smuzhiyun {HASH_ALGO_SHA1, TPM_ALG_SHA1},
17*4882a593Smuzhiyun {HASH_ALGO_SHA256, TPM_ALG_SHA256},
18*4882a593Smuzhiyun {HASH_ALGO_SHA384, TPM_ALG_SHA384},
19*4882a593Smuzhiyun {HASH_ALGO_SHA512, TPM_ALG_SHA512},
20*4882a593Smuzhiyun {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
21*4882a593Smuzhiyun };
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun /**
24*4882a593Smuzhiyun * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer.
25*4882a593Smuzhiyun *
26*4882a593Smuzhiyun * @buf: an allocated tpm_buf instance
27*4882a593Smuzhiyun * @session_handle: session handle
28*4882a593Smuzhiyun * @nonce: the session nonce, may be NULL if not used
29*4882a593Smuzhiyun * @nonce_len: the session nonce length, may be 0 if not used
30*4882a593Smuzhiyun * @attributes: the session attributes
31*4882a593Smuzhiyun * @hmac: the session HMAC or password, may be NULL if not used
32*4882a593Smuzhiyun * @hmac_len: the session HMAC or password length, maybe 0 if not used
33*4882a593Smuzhiyun */
tpm2_buf_append_auth(struct tpm_buf * buf,u32 session_handle,const u8 * nonce,u16 nonce_len,u8 attributes,const u8 * hmac,u16 hmac_len)34*4882a593Smuzhiyun static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle,
35*4882a593Smuzhiyun const u8 *nonce, u16 nonce_len,
36*4882a593Smuzhiyun u8 attributes,
37*4882a593Smuzhiyun const u8 *hmac, u16 hmac_len)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun tpm_buf_append_u32(buf, 9 + nonce_len + hmac_len);
40*4882a593Smuzhiyun tpm_buf_append_u32(buf, session_handle);
41*4882a593Smuzhiyun tpm_buf_append_u16(buf, nonce_len);
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun if (nonce && nonce_len)
44*4882a593Smuzhiyun tpm_buf_append(buf, nonce, nonce_len);
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun tpm_buf_append_u8(buf, attributes);
47*4882a593Smuzhiyun tpm_buf_append_u16(buf, hmac_len);
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun if (hmac && hmac_len)
50*4882a593Smuzhiyun tpm_buf_append(buf, hmac, hmac_len);
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /**
54*4882a593Smuzhiyun * tpm2_seal_trusted() - seal the payload of a trusted key
55*4882a593Smuzhiyun *
56*4882a593Smuzhiyun * @chip: TPM chip to use
57*4882a593Smuzhiyun * @payload: the key data in clear and encrypted form
58*4882a593Smuzhiyun * @options: authentication values and other options
59*4882a593Smuzhiyun *
60*4882a593Smuzhiyun * Return: < 0 on error and 0 on success.
61*4882a593Smuzhiyun */
tpm2_seal_trusted(struct tpm_chip * chip,struct trusted_key_payload * payload,struct trusted_key_options * options)62*4882a593Smuzhiyun int tpm2_seal_trusted(struct tpm_chip *chip,
63*4882a593Smuzhiyun struct trusted_key_payload *payload,
64*4882a593Smuzhiyun struct trusted_key_options *options)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun unsigned int blob_len;
67*4882a593Smuzhiyun struct tpm_buf buf;
68*4882a593Smuzhiyun u32 hash;
69*4882a593Smuzhiyun int i;
70*4882a593Smuzhiyun int rc;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
73*4882a593Smuzhiyun if (options->hash == tpm2_hash_map[i].crypto_id) {
74*4882a593Smuzhiyun hash = tpm2_hash_map[i].tpm_id;
75*4882a593Smuzhiyun break;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun if (i == ARRAY_SIZE(tpm2_hash_map))
80*4882a593Smuzhiyun return -EINVAL;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun rc = tpm_try_get_ops(chip);
83*4882a593Smuzhiyun if (rc)
84*4882a593Smuzhiyun return rc;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
87*4882a593Smuzhiyun if (rc) {
88*4882a593Smuzhiyun tpm_put_ops(chip);
89*4882a593Smuzhiyun return rc;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun tpm_buf_append_u32(&buf, options->keyhandle);
93*4882a593Smuzhiyun tpm2_buf_append_auth(&buf, TPM2_RS_PW,
94*4882a593Smuzhiyun NULL /* nonce */, 0,
95*4882a593Smuzhiyun 0 /* session_attributes */,
96*4882a593Smuzhiyun options->keyauth /* hmac */,
97*4882a593Smuzhiyun TPM_DIGEST_SIZE);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* sensitive */
100*4882a593Smuzhiyun tpm_buf_append_u16(&buf, 4 + options->blobauth_len + payload->key_len + 1);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun tpm_buf_append_u16(&buf, options->blobauth_len);
103*4882a593Smuzhiyun if (options->blobauth_len)
104*4882a593Smuzhiyun tpm_buf_append(&buf, options->blobauth, options->blobauth_len);
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun tpm_buf_append_u16(&buf, payload->key_len + 1);
107*4882a593Smuzhiyun tpm_buf_append(&buf, payload->key, payload->key_len);
108*4882a593Smuzhiyun tpm_buf_append_u8(&buf, payload->migratable);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun /* public */
111*4882a593Smuzhiyun tpm_buf_append_u16(&buf, 14 + options->policydigest_len);
112*4882a593Smuzhiyun tpm_buf_append_u16(&buf, TPM_ALG_KEYEDHASH);
113*4882a593Smuzhiyun tpm_buf_append_u16(&buf, hash);
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /* policy */
116*4882a593Smuzhiyun if (options->policydigest_len) {
117*4882a593Smuzhiyun tpm_buf_append_u32(&buf, 0);
118*4882a593Smuzhiyun tpm_buf_append_u16(&buf, options->policydigest_len);
119*4882a593Smuzhiyun tpm_buf_append(&buf, options->policydigest,
120*4882a593Smuzhiyun options->policydigest_len);
121*4882a593Smuzhiyun } else {
122*4882a593Smuzhiyun tpm_buf_append_u32(&buf, TPM2_OA_USER_WITH_AUTH);
123*4882a593Smuzhiyun tpm_buf_append_u16(&buf, 0);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /* public parameters */
127*4882a593Smuzhiyun tpm_buf_append_u16(&buf, TPM_ALG_NULL);
128*4882a593Smuzhiyun tpm_buf_append_u16(&buf, 0);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* outside info */
131*4882a593Smuzhiyun tpm_buf_append_u16(&buf, 0);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /* creation PCR */
134*4882a593Smuzhiyun tpm_buf_append_u32(&buf, 0);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun if (buf.flags & TPM_BUF_OVERFLOW) {
137*4882a593Smuzhiyun rc = -E2BIG;
138*4882a593Smuzhiyun goto out;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
142*4882a593Smuzhiyun if (rc)
143*4882a593Smuzhiyun goto out;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun blob_len = be32_to_cpup((__be32 *) &buf.data[TPM_HEADER_SIZE]);
146*4882a593Smuzhiyun if (blob_len > MAX_BLOB_SIZE) {
147*4882a593Smuzhiyun rc = -E2BIG;
148*4882a593Smuzhiyun goto out;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 4 + blob_len) {
151*4882a593Smuzhiyun rc = -EFAULT;
152*4882a593Smuzhiyun goto out;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len);
156*4882a593Smuzhiyun payload->blob_len = blob_len;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun out:
159*4882a593Smuzhiyun tpm_buf_destroy(&buf);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun if (rc > 0) {
162*4882a593Smuzhiyun if (tpm2_rc_value(rc) == TPM2_RC_HASH)
163*4882a593Smuzhiyun rc = -EINVAL;
164*4882a593Smuzhiyun else
165*4882a593Smuzhiyun rc = -EPERM;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun tpm_put_ops(chip);
169*4882a593Smuzhiyun return rc;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /**
173*4882a593Smuzhiyun * tpm2_load_cmd() - execute a TPM2_Load command
174*4882a593Smuzhiyun *
175*4882a593Smuzhiyun * @chip: TPM chip to use
176*4882a593Smuzhiyun * @payload: the key data in clear and encrypted form
177*4882a593Smuzhiyun * @options: authentication values and other options
178*4882a593Smuzhiyun * @blob_handle: returned blob handle
179*4882a593Smuzhiyun *
180*4882a593Smuzhiyun * Return: 0 on success.
181*4882a593Smuzhiyun * -E2BIG on wrong payload size.
182*4882a593Smuzhiyun * -EPERM on tpm error status.
183*4882a593Smuzhiyun * < 0 error from tpm_send.
184*4882a593Smuzhiyun */
tpm2_load_cmd(struct tpm_chip * chip,struct trusted_key_payload * payload,struct trusted_key_options * options,u32 * blob_handle)185*4882a593Smuzhiyun static int tpm2_load_cmd(struct tpm_chip *chip,
186*4882a593Smuzhiyun struct trusted_key_payload *payload,
187*4882a593Smuzhiyun struct trusted_key_options *options,
188*4882a593Smuzhiyun u32 *blob_handle)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun struct tpm_buf buf;
191*4882a593Smuzhiyun unsigned int private_len;
192*4882a593Smuzhiyun unsigned int public_len;
193*4882a593Smuzhiyun unsigned int blob_len;
194*4882a593Smuzhiyun int rc;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun private_len = be16_to_cpup((__be16 *) &payload->blob[0]);
197*4882a593Smuzhiyun if (private_len > (payload->blob_len - 2))
198*4882a593Smuzhiyun return -E2BIG;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun public_len = be16_to_cpup((__be16 *) &payload->blob[2 + private_len]);
201*4882a593Smuzhiyun blob_len = private_len + public_len + 4;
202*4882a593Smuzhiyun if (blob_len > payload->blob_len)
203*4882a593Smuzhiyun return -E2BIG;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
206*4882a593Smuzhiyun if (rc)
207*4882a593Smuzhiyun return rc;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun tpm_buf_append_u32(&buf, options->keyhandle);
210*4882a593Smuzhiyun tpm2_buf_append_auth(&buf, TPM2_RS_PW,
211*4882a593Smuzhiyun NULL /* nonce */, 0,
212*4882a593Smuzhiyun 0 /* session_attributes */,
213*4882a593Smuzhiyun options->keyauth /* hmac */,
214*4882a593Smuzhiyun TPM_DIGEST_SIZE);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun tpm_buf_append(&buf, payload->blob, blob_len);
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun if (buf.flags & TPM_BUF_OVERFLOW) {
219*4882a593Smuzhiyun rc = -E2BIG;
220*4882a593Smuzhiyun goto out;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
224*4882a593Smuzhiyun if (!rc)
225*4882a593Smuzhiyun *blob_handle = be32_to_cpup(
226*4882a593Smuzhiyun (__be32 *) &buf.data[TPM_HEADER_SIZE]);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun out:
229*4882a593Smuzhiyun tpm_buf_destroy(&buf);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if (rc > 0)
232*4882a593Smuzhiyun rc = -EPERM;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun return rc;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun /**
238*4882a593Smuzhiyun * tpm2_unseal_cmd() - execute a TPM2_Unload command
239*4882a593Smuzhiyun *
240*4882a593Smuzhiyun * @chip: TPM chip to use
241*4882a593Smuzhiyun * @payload: the key data in clear and encrypted form
242*4882a593Smuzhiyun * @options: authentication values and other options
243*4882a593Smuzhiyun * @blob_handle: blob handle
244*4882a593Smuzhiyun *
245*4882a593Smuzhiyun * Return: 0 on success
246*4882a593Smuzhiyun * -EPERM on tpm error status
247*4882a593Smuzhiyun * < 0 error from tpm_send
248*4882a593Smuzhiyun */
tpm2_unseal_cmd(struct tpm_chip * chip,struct trusted_key_payload * payload,struct trusted_key_options * options,u32 blob_handle)249*4882a593Smuzhiyun static int tpm2_unseal_cmd(struct tpm_chip *chip,
250*4882a593Smuzhiyun struct trusted_key_payload *payload,
251*4882a593Smuzhiyun struct trusted_key_options *options,
252*4882a593Smuzhiyun u32 blob_handle)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun struct tpm_buf buf;
255*4882a593Smuzhiyun u16 data_len;
256*4882a593Smuzhiyun u8 *data;
257*4882a593Smuzhiyun int rc;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
260*4882a593Smuzhiyun if (rc)
261*4882a593Smuzhiyun return rc;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun tpm_buf_append_u32(&buf, blob_handle);
264*4882a593Smuzhiyun tpm2_buf_append_auth(&buf,
265*4882a593Smuzhiyun options->policyhandle ?
266*4882a593Smuzhiyun options->policyhandle : TPM2_RS_PW,
267*4882a593Smuzhiyun NULL /* nonce */, 0,
268*4882a593Smuzhiyun TPM2_SA_CONTINUE_SESSION,
269*4882a593Smuzhiyun options->blobauth /* hmac */,
270*4882a593Smuzhiyun options->blobauth_len);
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
273*4882a593Smuzhiyun if (rc > 0)
274*4882a593Smuzhiyun rc = -EPERM;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun if (!rc) {
277*4882a593Smuzhiyun data_len = be16_to_cpup(
278*4882a593Smuzhiyun (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
279*4882a593Smuzhiyun if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE + 1) {
280*4882a593Smuzhiyun rc = -EFAULT;
281*4882a593Smuzhiyun goto out;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) {
285*4882a593Smuzhiyun rc = -EFAULT;
286*4882a593Smuzhiyun goto out;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun data = &buf.data[TPM_HEADER_SIZE + 6];
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun memcpy(payload->key, data, data_len - 1);
291*4882a593Smuzhiyun payload->key_len = data_len - 1;
292*4882a593Smuzhiyun payload->migratable = data[data_len - 1];
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun out:
296*4882a593Smuzhiyun tpm_buf_destroy(&buf);
297*4882a593Smuzhiyun return rc;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun /**
301*4882a593Smuzhiyun * tpm2_unseal_trusted() - unseal the payload of a trusted key
302*4882a593Smuzhiyun *
303*4882a593Smuzhiyun * @chip: TPM chip to use
304*4882a593Smuzhiyun * @payload: the key data in clear and encrypted form
305*4882a593Smuzhiyun * @options: authentication values and other options
306*4882a593Smuzhiyun *
307*4882a593Smuzhiyun * Return: Same as with tpm_send.
308*4882a593Smuzhiyun */
tpm2_unseal_trusted(struct tpm_chip * chip,struct trusted_key_payload * payload,struct trusted_key_options * options)309*4882a593Smuzhiyun int tpm2_unseal_trusted(struct tpm_chip *chip,
310*4882a593Smuzhiyun struct trusted_key_payload *payload,
311*4882a593Smuzhiyun struct trusted_key_options *options)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun u32 blob_handle;
314*4882a593Smuzhiyun int rc;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun rc = tpm_try_get_ops(chip);
317*4882a593Smuzhiyun if (rc)
318*4882a593Smuzhiyun return rc;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun rc = tpm2_load_cmd(chip, payload, options, &blob_handle);
321*4882a593Smuzhiyun if (rc)
322*4882a593Smuzhiyun goto out;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun rc = tpm2_unseal_cmd(chip, payload, options, blob_handle);
325*4882a593Smuzhiyun tpm2_flush_context(chip, blob_handle);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun out:
328*4882a593Smuzhiyun tpm_put_ops(chip);
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun return rc;
331*4882a593Smuzhiyun }
332