Commit 4b174b6d281f5c87234fc65bafc02877f565c5cf
Committed by
James Morris
1 parent
1bae4ce27c
Exists in
master
and in
20 other branches
trusted-keys: rename trusted_defined files to trusted
Rename trusted_defined.c and trusted_defined.h files to trusted.c and trusted.h, respectively. Based on request from David Howells. Signed-off-by: Mimi Zohar <zohar@us.ibm.com> Acked-by: David Howells <dhowells@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
Showing 5 changed files with 1315 additions and 1315 deletions Side-by-side Diff
security/keys/Makefile
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | request_key_auth.o \ |
14 | 14 | user_defined.o |
15 | 15 | |
16 | -obj-$(CONFIG_TRUSTED_KEYS) += trusted_defined.o | |
16 | +obj-$(CONFIG_TRUSTED_KEYS) += trusted.o | |
17 | 17 | obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted_defined.o |
18 | 18 | obj-$(CONFIG_KEYS_COMPAT) += compat.o |
19 | 19 | obj-$(CONFIG_PROC_FS) += proc.o |
security/keys/trusted.c
Changes suppressed. Click to show
1 | +/* | |
2 | + * Copyright (C) 2010 IBM Corporation | |
3 | + * | |
4 | + * Author: | |
5 | + * David Safford <safford@us.ibm.com> | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or modify | |
8 | + * it under the terms of the GNU General Public License as published by | |
9 | + * the Free Software Foundation, version 2 of the License. | |
10 | + * | |
11 | + * See Documentation/keys-trusted-encrypted.txt | |
12 | + */ | |
13 | + | |
14 | +#include <linux/uaccess.h> | |
15 | +#include <linux/module.h> | |
16 | +#include <linux/init.h> | |
17 | +#include <linux/slab.h> | |
18 | +#include <linux/parser.h> | |
19 | +#include <linux/string.h> | |
20 | +#include <linux/err.h> | |
21 | +#include <keys/user-type.h> | |
22 | +#include <keys/trusted-type.h> | |
23 | +#include <linux/key-type.h> | |
24 | +#include <linux/rcupdate.h> | |
25 | +#include <linux/crypto.h> | |
26 | +#include <crypto/hash.h> | |
27 | +#include <crypto/sha.h> | |
28 | +#include <linux/capability.h> | |
29 | +#include <linux/tpm.h> | |
30 | +#include <linux/tpm_command.h> | |
31 | + | |
32 | +#include "trusted.h" | |
33 | + | |
34 | +static const char hmac_alg[] = "hmac(sha1)"; | |
35 | +static const char hash_alg[] = "sha1"; | |
36 | + | |
37 | +struct sdesc { | |
38 | + struct shash_desc shash; | |
39 | + char ctx[]; | |
40 | +}; | |
41 | + | |
42 | +static struct crypto_shash *hashalg; | |
43 | +static struct crypto_shash *hmacalg; | |
44 | + | |
45 | +static struct sdesc *init_sdesc(struct crypto_shash *alg) | |
46 | +{ | |
47 | + struct sdesc *sdesc; | |
48 | + int size; | |
49 | + | |
50 | + size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); | |
51 | + sdesc = kmalloc(size, GFP_KERNEL); | |
52 | + if (!sdesc) | |
53 | + return ERR_PTR(-ENOMEM); | |
54 | + sdesc->shash.tfm = alg; | |
55 | + sdesc->shash.flags = 0x0; | |
56 | + return sdesc; | |
57 | +} | |
58 | + | |
59 | +static int TSS_sha1(const unsigned char *data, unsigned int datalen, | |
60 | + unsigned char *digest) | |
61 | +{ | |
62 | + struct sdesc *sdesc; | |
63 | + int ret; | |
64 | + | |
65 | + sdesc = init_sdesc(hashalg); | |
66 | + if (IS_ERR(sdesc)) { | |
67 | + pr_info("trusted_key: can't alloc %s\n", hash_alg); | |
68 | + return PTR_ERR(sdesc); | |
69 | + } | |
70 | + | |
71 | + ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest); | |
72 | + kfree(sdesc); | |
73 | + return ret; | |
74 | +} | |
75 | + | |
76 | +static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, | |
77 | + unsigned int keylen, ...) | |
78 | +{ | |
79 | + struct sdesc *sdesc; | |
80 | + va_list argp; | |
81 | + unsigned int dlen; | |
82 | + unsigned char *data; | |
83 | + int ret; | |
84 | + | |
85 | + sdesc = init_sdesc(hmacalg); | |
86 | + if (IS_ERR(sdesc)) { | |
87 | + pr_info("trusted_key: can't alloc %s\n", hmac_alg); | |
88 | + return PTR_ERR(sdesc); | |
89 | + } | |
90 | + | |
91 | + ret = crypto_shash_setkey(hmacalg, key, keylen); | |
92 | + if (ret < 0) | |
93 | + goto out; | |
94 | + ret = crypto_shash_init(&sdesc->shash); | |
95 | + if (ret < 0) | |
96 | + goto out; | |
97 | + | |
98 | + va_start(argp, keylen); | |
99 | + for (;;) { | |
100 | + dlen = va_arg(argp, unsigned int); | |
101 | + if (dlen == 0) | |
102 | + break; | |
103 | + data = va_arg(argp, unsigned char *); | |
104 | + if (data == NULL) { | |
105 | + ret = -EINVAL; | |
106 | + break; | |
107 | + } | |
108 | + ret = crypto_shash_update(&sdesc->shash, data, dlen); | |
109 | + if (ret < 0) | |
110 | + break; | |
111 | + } | |
112 | + va_end(argp); | |
113 | + if (!ret) | |
114 | + ret = crypto_shash_final(&sdesc->shash, digest); | |
115 | +out: | |
116 | + kfree(sdesc); | |
117 | + return ret; | |
118 | +} | |
119 | + | |
120 | +/* | |
121 | + * calculate authorization info fields to send to TPM | |
122 | + */ | |
123 | +static int TSS_authhmac(unsigned char *digest, const unsigned char *key, | |
124 | + unsigned int keylen, unsigned char *h1, | |
125 | + unsigned char *h2, unsigned char h3, ...) | |
126 | +{ | |
127 | + unsigned char paramdigest[SHA1_DIGEST_SIZE]; | |
128 | + struct sdesc *sdesc; | |
129 | + unsigned int dlen; | |
130 | + unsigned char *data; | |
131 | + unsigned char c; | |
132 | + int ret; | |
133 | + va_list argp; | |
134 | + | |
135 | + sdesc = init_sdesc(hashalg); | |
136 | + if (IS_ERR(sdesc)) { | |
137 | + pr_info("trusted_key: can't alloc %s\n", hash_alg); | |
138 | + return PTR_ERR(sdesc); | |
139 | + } | |
140 | + | |
141 | + c = h3; | |
142 | + ret = crypto_shash_init(&sdesc->shash); | |
143 | + if (ret < 0) | |
144 | + goto out; | |
145 | + va_start(argp, h3); | |
146 | + for (;;) { | |
147 | + dlen = va_arg(argp, unsigned int); | |
148 | + if (dlen == 0) | |
149 | + break; | |
150 | + data = va_arg(argp, unsigned char *); | |
151 | + if (!data) { | |
152 | + ret = -EINVAL; | |
153 | + break; | |
154 | + } | |
155 | + ret = crypto_shash_update(&sdesc->shash, data, dlen); | |
156 | + if (ret < 0) | |
157 | + break; | |
158 | + } | |
159 | + va_end(argp); | |
160 | + if (!ret) | |
161 | + ret = crypto_shash_final(&sdesc->shash, paramdigest); | |
162 | + if (!ret) | |
163 | + ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE, | |
164 | + paramdigest, TPM_NONCE_SIZE, h1, | |
165 | + TPM_NONCE_SIZE, h2, 1, &c, 0, 0); | |
166 | +out: | |
167 | + kfree(sdesc); | |
168 | + return ret; | |
169 | +} | |
170 | + | |
171 | +/* | |
172 | + * verify the AUTH1_COMMAND (Seal) result from TPM | |
173 | + */ | |
174 | +static int TSS_checkhmac1(unsigned char *buffer, | |
175 | + const uint32_t command, | |
176 | + const unsigned char *ononce, | |
177 | + const unsigned char *key, | |
178 | + unsigned int keylen, ...) | |
179 | +{ | |
180 | + uint32_t bufsize; | |
181 | + uint16_t tag; | |
182 | + uint32_t ordinal; | |
183 | + uint32_t result; | |
184 | + unsigned char *enonce; | |
185 | + unsigned char *continueflag; | |
186 | + unsigned char *authdata; | |
187 | + unsigned char testhmac[SHA1_DIGEST_SIZE]; | |
188 | + unsigned char paramdigest[SHA1_DIGEST_SIZE]; | |
189 | + struct sdesc *sdesc; | |
190 | + unsigned int dlen; | |
191 | + unsigned int dpos; | |
192 | + va_list argp; | |
193 | + int ret; | |
194 | + | |
195 | + bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); | |
196 | + tag = LOAD16(buffer, 0); | |
197 | + ordinal = command; | |
198 | + result = LOAD32N(buffer, TPM_RETURN_OFFSET); | |
199 | + if (tag == TPM_TAG_RSP_COMMAND) | |
200 | + return 0; | |
201 | + if (tag != TPM_TAG_RSP_AUTH1_COMMAND) | |
202 | + return -EINVAL; | |
203 | + authdata = buffer + bufsize - SHA1_DIGEST_SIZE; | |
204 | + continueflag = authdata - 1; | |
205 | + enonce = continueflag - TPM_NONCE_SIZE; | |
206 | + | |
207 | + sdesc = init_sdesc(hashalg); | |
208 | + if (IS_ERR(sdesc)) { | |
209 | + pr_info("trusted_key: can't alloc %s\n", hash_alg); | |
210 | + return PTR_ERR(sdesc); | |
211 | + } | |
212 | + ret = crypto_shash_init(&sdesc->shash); | |
213 | + if (ret < 0) | |
214 | + goto out; | |
215 | + ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, | |
216 | + sizeof result); | |
217 | + if (ret < 0) | |
218 | + goto out; | |
219 | + ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, | |
220 | + sizeof ordinal); | |
221 | + if (ret < 0) | |
222 | + goto out; | |
223 | + va_start(argp, keylen); | |
224 | + for (;;) { | |
225 | + dlen = va_arg(argp, unsigned int); | |
226 | + if (dlen == 0) | |
227 | + break; | |
228 | + dpos = va_arg(argp, unsigned int); | |
229 | + ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); | |
230 | + if (ret < 0) | |
231 | + break; | |
232 | + } | |
233 | + va_end(argp); | |
234 | + if (!ret) | |
235 | + ret = crypto_shash_final(&sdesc->shash, paramdigest); | |
236 | + if (ret < 0) | |
237 | + goto out; | |
238 | + | |
239 | + ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest, | |
240 | + TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce, | |
241 | + 1, continueflag, 0, 0); | |
242 | + if (ret < 0) | |
243 | + goto out; | |
244 | + | |
245 | + if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE)) | |
246 | + ret = -EINVAL; | |
247 | +out: | |
248 | + kfree(sdesc); | |
249 | + return ret; | |
250 | +} | |
251 | + | |
252 | +/* | |
253 | + * verify the AUTH2_COMMAND (unseal) result from TPM | |
254 | + */ | |
255 | +static int TSS_checkhmac2(unsigned char *buffer, | |
256 | + const uint32_t command, | |
257 | + const unsigned char *ononce, | |
258 | + const unsigned char *key1, | |
259 | + unsigned int keylen1, | |
260 | + const unsigned char *key2, | |
261 | + unsigned int keylen2, ...) | |
262 | +{ | |
263 | + uint32_t bufsize; | |
264 | + uint16_t tag; | |
265 | + uint32_t ordinal; | |
266 | + uint32_t result; | |
267 | + unsigned char *enonce1; | |
268 | + unsigned char *continueflag1; | |
269 | + unsigned char *authdata1; | |
270 | + unsigned char *enonce2; | |
271 | + unsigned char *continueflag2; | |
272 | + unsigned char *authdata2; | |
273 | + unsigned char testhmac1[SHA1_DIGEST_SIZE]; | |
274 | + unsigned char testhmac2[SHA1_DIGEST_SIZE]; | |
275 | + unsigned char paramdigest[SHA1_DIGEST_SIZE]; | |
276 | + struct sdesc *sdesc; | |
277 | + unsigned int dlen; | |
278 | + unsigned int dpos; | |
279 | + va_list argp; | |
280 | + int ret; | |
281 | + | |
282 | + bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); | |
283 | + tag = LOAD16(buffer, 0); | |
284 | + ordinal = command; | |
285 | + result = LOAD32N(buffer, TPM_RETURN_OFFSET); | |
286 | + | |
287 | + if (tag == TPM_TAG_RSP_COMMAND) | |
288 | + return 0; | |
289 | + if (tag != TPM_TAG_RSP_AUTH2_COMMAND) | |
290 | + return -EINVAL; | |
291 | + authdata1 = buffer + bufsize - (SHA1_DIGEST_SIZE + 1 | |
292 | + + SHA1_DIGEST_SIZE + SHA1_DIGEST_SIZE); | |
293 | + authdata2 = buffer + bufsize - (SHA1_DIGEST_SIZE); | |
294 | + continueflag1 = authdata1 - 1; | |
295 | + continueflag2 = authdata2 - 1; | |
296 | + enonce1 = continueflag1 - TPM_NONCE_SIZE; | |
297 | + enonce2 = continueflag2 - TPM_NONCE_SIZE; | |
298 | + | |
299 | + sdesc = init_sdesc(hashalg); | |
300 | + if (IS_ERR(sdesc)) { | |
301 | + pr_info("trusted_key: can't alloc %s\n", hash_alg); | |
302 | + return PTR_ERR(sdesc); | |
303 | + } | |
304 | + ret = crypto_shash_init(&sdesc->shash); | |
305 | + if (ret < 0) | |
306 | + goto out; | |
307 | + ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, | |
308 | + sizeof result); | |
309 | + if (ret < 0) | |
310 | + goto out; | |
311 | + ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, | |
312 | + sizeof ordinal); | |
313 | + if (ret < 0) | |
314 | + goto out; | |
315 | + | |
316 | + va_start(argp, keylen2); | |
317 | + for (;;) { | |
318 | + dlen = va_arg(argp, unsigned int); | |
319 | + if (dlen == 0) | |
320 | + break; | |
321 | + dpos = va_arg(argp, unsigned int); | |
322 | + ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); | |
323 | + if (ret < 0) | |
324 | + break; | |
325 | + } | |
326 | + va_end(argp); | |
327 | + if (!ret) | |
328 | + ret = crypto_shash_final(&sdesc->shash, paramdigest); | |
329 | + if (ret < 0) | |
330 | + goto out; | |
331 | + | |
332 | + ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE, | |
333 | + paramdigest, TPM_NONCE_SIZE, enonce1, | |
334 | + TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0); | |
335 | + if (ret < 0) | |
336 | + goto out; | |
337 | + if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) { | |
338 | + ret = -EINVAL; | |
339 | + goto out; | |
340 | + } | |
341 | + ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE, | |
342 | + paramdigest, TPM_NONCE_SIZE, enonce2, | |
343 | + TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0); | |
344 | + if (ret < 0) | |
345 | + goto out; | |
346 | + if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE)) | |
347 | + ret = -EINVAL; | |
348 | +out: | |
349 | + kfree(sdesc); | |
350 | + return ret; | |
351 | +} | |
352 | + | |
353 | +/* | |
354 | + * For key specific tpm requests, we will generate and send our | |
355 | + * own TPM command packets using the drivers send function. | |
356 | + */ | |
357 | +static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd, | |
358 | + size_t buflen) | |
359 | +{ | |
360 | + int rc; | |
361 | + | |
362 | + dump_tpm_buf(cmd); | |
363 | + rc = tpm_send(chip_num, cmd, buflen); | |
364 | + dump_tpm_buf(cmd); | |
365 | + if (rc > 0) | |
366 | + /* Can't return positive return codes values to keyctl */ | |
367 | + rc = -EPERM; | |
368 | + return rc; | |
369 | +} | |
370 | + | |
371 | +/* | |
372 | + * get a random value from TPM | |
373 | + */ | |
374 | +static int tpm_get_random(struct tpm_buf *tb, unsigned char *buf, uint32_t len) | |
375 | +{ | |
376 | + int ret; | |
377 | + | |
378 | + INIT_BUF(tb); | |
379 | + store16(tb, TPM_TAG_RQU_COMMAND); | |
380 | + store32(tb, TPM_GETRANDOM_SIZE); | |
381 | + store32(tb, TPM_ORD_GETRANDOM); | |
382 | + store32(tb, len); | |
383 | + ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data); | |
384 | + if (!ret) | |
385 | + memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len); | |
386 | + return ret; | |
387 | +} | |
388 | + | |
389 | +static int my_get_random(unsigned char *buf, int len) | |
390 | +{ | |
391 | + struct tpm_buf *tb; | |
392 | + int ret; | |
393 | + | |
394 | + tb = kmalloc(sizeof *tb, GFP_KERNEL); | |
395 | + if (!tb) | |
396 | + return -ENOMEM; | |
397 | + ret = tpm_get_random(tb, buf, len); | |
398 | + | |
399 | + kfree(tb); | |
400 | + return ret; | |
401 | +} | |
402 | + | |
403 | +/* | |
404 | + * Lock a trusted key, by extending a selected PCR. | |
405 | + * | |
406 | + * Prevents a trusted key that is sealed to PCRs from being accessed. | |
407 | + * This uses the tpm driver's extend function. | |
408 | + */ | |
409 | +static int pcrlock(const int pcrnum) | |
410 | +{ | |
411 | + unsigned char hash[SHA1_DIGEST_SIZE]; | |
412 | + int ret; | |
413 | + | |
414 | + if (!capable(CAP_SYS_ADMIN)) | |
415 | + return -EPERM; | |
416 | + ret = my_get_random(hash, SHA1_DIGEST_SIZE); | |
417 | + if (ret < 0) | |
418 | + return ret; | |
419 | + return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0; | |
420 | +} | |
421 | + | |
422 | +/* | |
423 | + * Create an object specific authorisation protocol (OSAP) session | |
424 | + */ | |
425 | +static int osap(struct tpm_buf *tb, struct osapsess *s, | |
426 | + const unsigned char *key, uint16_t type, uint32_t handle) | |
427 | +{ | |
428 | + unsigned char enonce[TPM_NONCE_SIZE]; | |
429 | + unsigned char ononce[TPM_NONCE_SIZE]; | |
430 | + int ret; | |
431 | + | |
432 | + ret = tpm_get_random(tb, ononce, TPM_NONCE_SIZE); | |
433 | + if (ret < 0) | |
434 | + return ret; | |
435 | + | |
436 | + INIT_BUF(tb); | |
437 | + store16(tb, TPM_TAG_RQU_COMMAND); | |
438 | + store32(tb, TPM_OSAP_SIZE); | |
439 | + store32(tb, TPM_ORD_OSAP); | |
440 | + store16(tb, type); | |
441 | + store32(tb, handle); | |
442 | + storebytes(tb, ononce, TPM_NONCE_SIZE); | |
443 | + | |
444 | + ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); | |
445 | + if (ret < 0) | |
446 | + return ret; | |
447 | + | |
448 | + s->handle = LOAD32(tb->data, TPM_DATA_OFFSET); | |
449 | + memcpy(s->enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]), | |
450 | + TPM_NONCE_SIZE); | |
451 | + memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) + | |
452 | + TPM_NONCE_SIZE]), TPM_NONCE_SIZE); | |
453 | + return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE, | |
454 | + enonce, TPM_NONCE_SIZE, ononce, 0, 0); | |
455 | +} | |
456 | + | |
457 | +/* | |
458 | + * Create an object independent authorisation protocol (oiap) session | |
459 | + */ | |
460 | +static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) | |
461 | +{ | |
462 | + int ret; | |
463 | + | |
464 | + INIT_BUF(tb); | |
465 | + store16(tb, TPM_TAG_RQU_COMMAND); | |
466 | + store32(tb, TPM_OIAP_SIZE); | |
467 | + store32(tb, TPM_ORD_OIAP); | |
468 | + ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); | |
469 | + if (ret < 0) | |
470 | + return ret; | |
471 | + | |
472 | + *handle = LOAD32(tb->data, TPM_DATA_OFFSET); | |
473 | + memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)], | |
474 | + TPM_NONCE_SIZE); | |
475 | + return 0; | |
476 | +} | |
477 | + | |
478 | +struct tpm_digests { | |
479 | + unsigned char encauth[SHA1_DIGEST_SIZE]; | |
480 | + unsigned char pubauth[SHA1_DIGEST_SIZE]; | |
481 | + unsigned char xorwork[SHA1_DIGEST_SIZE * 2]; | |
482 | + unsigned char xorhash[SHA1_DIGEST_SIZE]; | |
483 | + unsigned char nonceodd[TPM_NONCE_SIZE]; | |
484 | +}; | |
485 | + | |
486 | +/* | |
487 | + * Have the TPM seal(encrypt) the trusted key, possibly based on | |
488 | + * Platform Configuration Registers (PCRs). AUTH1 for sealing key. | |
489 | + */ | |
490 | +static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, | |
491 | + uint32_t keyhandle, const unsigned char *keyauth, | |
492 | + const unsigned char *data, uint32_t datalen, | |
493 | + unsigned char *blob, uint32_t *bloblen, | |
494 | + const unsigned char *blobauth, | |
495 | + const unsigned char *pcrinfo, uint32_t pcrinfosize) | |
496 | +{ | |
497 | + struct osapsess sess; | |
498 | + struct tpm_digests *td; | |
499 | + unsigned char cont; | |
500 | + uint32_t ordinal; | |
501 | + uint32_t pcrsize; | |
502 | + uint32_t datsize; | |
503 | + int sealinfosize; | |
504 | + int encdatasize; | |
505 | + int storedsize; | |
506 | + int ret; | |
507 | + int i; | |
508 | + | |
509 | + /* alloc some work space for all the hashes */ | |
510 | + td = kmalloc(sizeof *td, GFP_KERNEL); | |
511 | + if (!td) | |
512 | + return -ENOMEM; | |
513 | + | |
514 | + /* get session for sealing key */ | |
515 | + ret = osap(tb, &sess, keyauth, keytype, keyhandle); | |
516 | + if (ret < 0) | |
517 | + goto out; | |
518 | + dump_sess(&sess); | |
519 | + | |
520 | + /* calculate encrypted authorization value */ | |
521 | + memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE); | |
522 | + memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE); | |
523 | + ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash); | |
524 | + if (ret < 0) | |
525 | + goto out; | |
526 | + | |
527 | + ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE); | |
528 | + if (ret < 0) | |
529 | + goto out; | |
530 | + ordinal = htonl(TPM_ORD_SEAL); | |
531 | + datsize = htonl(datalen); | |
532 | + pcrsize = htonl(pcrinfosize); | |
533 | + cont = 0; | |
534 | + | |
535 | + /* encrypt data authorization key */ | |
536 | + for (i = 0; i < SHA1_DIGEST_SIZE; ++i) | |
537 | + td->encauth[i] = td->xorhash[i] ^ blobauth[i]; | |
538 | + | |
539 | + /* calculate authorization HMAC value */ | |
540 | + if (pcrinfosize == 0) { | |
541 | + /* no pcr info specified */ | |
542 | + ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, | |
543 | + sess.enonce, td->nonceodd, cont, | |
544 | + sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE, | |
545 | + td->encauth, sizeof(uint32_t), &pcrsize, | |
546 | + sizeof(uint32_t), &datsize, datalen, data, 0, | |
547 | + 0); | |
548 | + } else { | |
549 | + /* pcr info specified */ | |
550 | + ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, | |
551 | + sess.enonce, td->nonceodd, cont, | |
552 | + sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE, | |
553 | + td->encauth, sizeof(uint32_t), &pcrsize, | |
554 | + pcrinfosize, pcrinfo, sizeof(uint32_t), | |
555 | + &datsize, datalen, data, 0, 0); | |
556 | + } | |
557 | + if (ret < 0) | |
558 | + goto out; | |
559 | + | |
560 | + /* build and send the TPM request packet */ | |
561 | + INIT_BUF(tb); | |
562 | + store16(tb, TPM_TAG_RQU_AUTH1_COMMAND); | |
563 | + store32(tb, TPM_SEAL_SIZE + pcrinfosize + datalen); | |
564 | + store32(tb, TPM_ORD_SEAL); | |
565 | + store32(tb, keyhandle); | |
566 | + storebytes(tb, td->encauth, SHA1_DIGEST_SIZE); | |
567 | + store32(tb, pcrinfosize); | |
568 | + storebytes(tb, pcrinfo, pcrinfosize); | |
569 | + store32(tb, datalen); | |
570 | + storebytes(tb, data, datalen); | |
571 | + store32(tb, sess.handle); | |
572 | + storebytes(tb, td->nonceodd, TPM_NONCE_SIZE); | |
573 | + store8(tb, cont); | |
574 | + storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); | |
575 | + | |
576 | + ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); | |
577 | + if (ret < 0) | |
578 | + goto out; | |
579 | + | |
580 | + /* calculate the size of the returned Blob */ | |
581 | + sealinfosize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t)); | |
582 | + encdatasize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t) + | |
583 | + sizeof(uint32_t) + sealinfosize); | |
584 | + storedsize = sizeof(uint32_t) + sizeof(uint32_t) + sealinfosize + | |
585 | + sizeof(uint32_t) + encdatasize; | |
586 | + | |
587 | + /* check the HMAC in the response */ | |
588 | + ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, sess.secret, | |
589 | + SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0, | |
590 | + 0); | |
591 | + | |
592 | + /* copy the returned blob to caller */ | |
593 | + if (!ret) { | |
594 | + memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize); | |
595 | + *bloblen = storedsize; | |
596 | + } | |
597 | +out: | |
598 | + kfree(td); | |
599 | + return ret; | |
600 | +} | |
601 | + | |
602 | +/* | |
603 | + * use the AUTH2_COMMAND form of unseal, to authorize both key and blob | |
604 | + */ | |
605 | +static int tpm_unseal(struct tpm_buf *tb, | |
606 | + uint32_t keyhandle, const unsigned char *keyauth, | |
607 | + const unsigned char *blob, int bloblen, | |
608 | + const unsigned char *blobauth, | |
609 | + unsigned char *data, unsigned int *datalen) | |
610 | +{ | |
611 | + unsigned char nonceodd[TPM_NONCE_SIZE]; | |
612 | + unsigned char enonce1[TPM_NONCE_SIZE]; | |
613 | + unsigned char enonce2[TPM_NONCE_SIZE]; | |
614 | + unsigned char authdata1[SHA1_DIGEST_SIZE]; | |
615 | + unsigned char authdata2[SHA1_DIGEST_SIZE]; | |
616 | + uint32_t authhandle1 = 0; | |
617 | + uint32_t authhandle2 = 0; | |
618 | + unsigned char cont = 0; | |
619 | + uint32_t ordinal; | |
620 | + uint32_t keyhndl; | |
621 | + int ret; | |
622 | + | |
623 | + /* sessions for unsealing key and data */ | |
624 | + ret = oiap(tb, &authhandle1, enonce1); | |
625 | + if (ret < 0) { | |
626 | + pr_info("trusted_key: oiap failed (%d)\n", ret); | |
627 | + return ret; | |
628 | + } | |
629 | + ret = oiap(tb, &authhandle2, enonce2); | |
630 | + if (ret < 0) { | |
631 | + pr_info("trusted_key: oiap failed (%d)\n", ret); | |
632 | + return ret; | |
633 | + } | |
634 | + | |
635 | + ordinal = htonl(TPM_ORD_UNSEAL); | |
636 | + keyhndl = htonl(SRKHANDLE); | |
637 | + ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE); | |
638 | + if (ret < 0) { | |
639 | + pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); | |
640 | + return ret; | |
641 | + } | |
642 | + ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, | |
643 | + enonce1, nonceodd, cont, sizeof(uint32_t), | |
644 | + &ordinal, bloblen, blob, 0, 0); | |
645 | + if (ret < 0) | |
646 | + return ret; | |
647 | + ret = TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE, | |
648 | + enonce2, nonceodd, cont, sizeof(uint32_t), | |
649 | + &ordinal, bloblen, blob, 0, 0); | |
650 | + if (ret < 0) | |
651 | + return ret; | |
652 | + | |
653 | + /* build and send TPM request packet */ | |
654 | + INIT_BUF(tb); | |
655 | + store16(tb, TPM_TAG_RQU_AUTH2_COMMAND); | |
656 | + store32(tb, TPM_UNSEAL_SIZE + bloblen); | |
657 | + store32(tb, TPM_ORD_UNSEAL); | |
658 | + store32(tb, keyhandle); | |
659 | + storebytes(tb, blob, bloblen); | |
660 | + store32(tb, authhandle1); | |
661 | + storebytes(tb, nonceodd, TPM_NONCE_SIZE); | |
662 | + store8(tb, cont); | |
663 | + storebytes(tb, authdata1, SHA1_DIGEST_SIZE); | |
664 | + store32(tb, authhandle2); | |
665 | + storebytes(tb, nonceodd, TPM_NONCE_SIZE); | |
666 | + store8(tb, cont); | |
667 | + storebytes(tb, authdata2, SHA1_DIGEST_SIZE); | |
668 | + | |
669 | + ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); | |
670 | + if (ret < 0) { | |
671 | + pr_info("trusted_key: authhmac failed (%d)\n", ret); | |
672 | + return ret; | |
673 | + } | |
674 | + | |
675 | + *datalen = LOAD32(tb->data, TPM_DATA_OFFSET); | |
676 | + ret = TSS_checkhmac2(tb->data, ordinal, nonceodd, | |
677 | + keyauth, SHA1_DIGEST_SIZE, | |
678 | + blobauth, SHA1_DIGEST_SIZE, | |
679 | + sizeof(uint32_t), TPM_DATA_OFFSET, | |
680 | + *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0, | |
681 | + 0); | |
682 | + if (ret < 0) { | |
683 | + pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret); | |
684 | + return ret; | |
685 | + } | |
686 | + memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen); | |
687 | + return 0; | |
688 | +} | |
689 | + | |
690 | +/* | |
691 | + * Have the TPM seal(encrypt) the symmetric key | |
692 | + */ | |
693 | +static int key_seal(struct trusted_key_payload *p, | |
694 | + struct trusted_key_options *o) | |
695 | +{ | |
696 | + struct tpm_buf *tb; | |
697 | + int ret; | |
698 | + | |
699 | + tb = kzalloc(sizeof *tb, GFP_KERNEL); | |
700 | + if (!tb) | |
701 | + return -ENOMEM; | |
702 | + | |
703 | + /* include migratable flag at end of sealed key */ | |
704 | + p->key[p->key_len] = p->migratable; | |
705 | + | |
706 | + ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth, | |
707 | + p->key, p->key_len + 1, p->blob, &p->blob_len, | |
708 | + o->blobauth, o->pcrinfo, o->pcrinfo_len); | |
709 | + if (ret < 0) | |
710 | + pr_info("trusted_key: srkseal failed (%d)\n", ret); | |
711 | + | |
712 | + kfree(tb); | |
713 | + return ret; | |
714 | +} | |
715 | + | |
716 | +/* | |
717 | + * Have the TPM unseal(decrypt) the symmetric key | |
718 | + */ | |
719 | +static int key_unseal(struct trusted_key_payload *p, | |
720 | + struct trusted_key_options *o) | |
721 | +{ | |
722 | + struct tpm_buf *tb; | |
723 | + int ret; | |
724 | + | |
725 | + tb = kzalloc(sizeof *tb, GFP_KERNEL); | |
726 | + if (!tb) | |
727 | + return -ENOMEM; | |
728 | + | |
729 | + ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len, | |
730 | + o->blobauth, p->key, &p->key_len); | |
731 | + if (ret < 0) | |
732 | + pr_info("trusted_key: srkunseal failed (%d)\n", ret); | |
733 | + else | |
734 | + /* pull migratable flag out of sealed key */ | |
735 | + p->migratable = p->key[--p->key_len]; | |
736 | + | |
737 | + kfree(tb); | |
738 | + return ret; | |
739 | +} | |
740 | + | |
741 | +enum { | |
742 | + Opt_err = -1, | |
743 | + Opt_new, Opt_load, Opt_update, | |
744 | + Opt_keyhandle, Opt_keyauth, Opt_blobauth, | |
745 | + Opt_pcrinfo, Opt_pcrlock, Opt_migratable | |
746 | +}; | |
747 | + | |
748 | +static const match_table_t key_tokens = { | |
749 | + {Opt_new, "new"}, | |
750 | + {Opt_load, "load"}, | |
751 | + {Opt_update, "update"}, | |
752 | + {Opt_keyhandle, "keyhandle=%s"}, | |
753 | + {Opt_keyauth, "keyauth=%s"}, | |
754 | + {Opt_blobauth, "blobauth=%s"}, | |
755 | + {Opt_pcrinfo, "pcrinfo=%s"}, | |
756 | + {Opt_pcrlock, "pcrlock=%s"}, | |
757 | + {Opt_migratable, "migratable=%s"}, | |
758 | + {Opt_err, NULL} | |
759 | +}; | |
760 | + | |
761 | +/* can have zero or more token= options */ | |
762 | +static int getoptions(char *c, struct trusted_key_payload *pay, | |
763 | + struct trusted_key_options *opt) | |
764 | +{ | |
765 | + substring_t args[MAX_OPT_ARGS]; | |
766 | + char *p = c; | |
767 | + int token; | |
768 | + int res; | |
769 | + unsigned long handle; | |
770 | + unsigned long lock; | |
771 | + | |
772 | + while ((p = strsep(&c, " \t"))) { | |
773 | + if (*p == '\0' || *p == ' ' || *p == '\t') | |
774 | + continue; | |
775 | + token = match_token(p, key_tokens, args); | |
776 | + | |
777 | + switch (token) { | |
778 | + case Opt_pcrinfo: | |
779 | + opt->pcrinfo_len = strlen(args[0].from) / 2; | |
780 | + if (opt->pcrinfo_len > MAX_PCRINFO_SIZE) | |
781 | + return -EINVAL; | |
782 | + hex2bin(opt->pcrinfo, args[0].from, opt->pcrinfo_len); | |
783 | + break; | |
784 | + case Opt_keyhandle: | |
785 | + res = strict_strtoul(args[0].from, 16, &handle); | |
786 | + if (res < 0) | |
787 | + return -EINVAL; | |
788 | + opt->keytype = SEAL_keytype; | |
789 | + opt->keyhandle = handle; | |
790 | + break; | |
791 | + case Opt_keyauth: | |
792 | + if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE) | |
793 | + return -EINVAL; | |
794 | + hex2bin(opt->keyauth, args[0].from, SHA1_DIGEST_SIZE); | |
795 | + break; | |
796 | + case Opt_blobauth: | |
797 | + if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE) | |
798 | + return -EINVAL; | |
799 | + hex2bin(opt->blobauth, args[0].from, SHA1_DIGEST_SIZE); | |
800 | + break; | |
801 | + case Opt_migratable: | |
802 | + if (*args[0].from == '0') | |
803 | + pay->migratable = 0; | |
804 | + else | |
805 | + return -EINVAL; | |
806 | + break; | |
807 | + case Opt_pcrlock: | |
808 | + res = strict_strtoul(args[0].from, 10, &lock); | |
809 | + if (res < 0) | |
810 | + return -EINVAL; | |
811 | + opt->pcrlock = lock; | |
812 | + break; | |
813 | + default: | |
814 | + return -EINVAL; | |
815 | + } | |
816 | + } | |
817 | + return 0; | |
818 | +} | |
819 | + | |
820 | +/* | |
821 | + * datablob_parse - parse the keyctl data and fill in the | |
822 | + * payload and options structures | |
823 | + * | |
824 | + * On success returns 0, otherwise -EINVAL. | |
825 | + */ | |
826 | +static int datablob_parse(char *datablob, struct trusted_key_payload *p, | |
827 | + struct trusted_key_options *o) | |
828 | +{ | |
829 | + substring_t args[MAX_OPT_ARGS]; | |
830 | + long keylen; | |
831 | + int ret = -EINVAL; | |
832 | + int key_cmd; | |
833 | + char *c; | |
834 | + | |
835 | + /* main command */ | |
836 | + c = strsep(&datablob, " \t"); | |
837 | + if (!c) | |
838 | + return -EINVAL; | |
839 | + key_cmd = match_token(c, key_tokens, args); | |
840 | + switch (key_cmd) { | |
841 | + case Opt_new: | |
842 | + /* first argument is key size */ | |
843 | + c = strsep(&datablob, " \t"); | |
844 | + if (!c) | |
845 | + return -EINVAL; | |
846 | + ret = strict_strtol(c, 10, &keylen); | |
847 | + if (ret < 0 || keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE) | |
848 | + return -EINVAL; | |
849 | + p->key_len = keylen; | |
850 | + ret = getoptions(datablob, p, o); | |
851 | + if (ret < 0) | |
852 | + return ret; | |
853 | + ret = Opt_new; | |
854 | + break; | |
855 | + case Opt_load: | |
856 | + /* first argument is sealed blob */ | |
857 | + c = strsep(&datablob, " \t"); | |
858 | + if (!c) | |
859 | + return -EINVAL; | |
860 | + p->blob_len = strlen(c) / 2; | |
861 | + if (p->blob_len > MAX_BLOB_SIZE) | |
862 | + return -EINVAL; | |
863 | + hex2bin(p->blob, c, p->blob_len); | |
864 | + ret = getoptions(datablob, p, o); | |
865 | + if (ret < 0) | |
866 | + return ret; | |
867 | + ret = Opt_load; | |
868 | + break; | |
869 | + case Opt_update: | |
870 | + /* all arguments are options */ | |
871 | + ret = getoptions(datablob, p, o); | |
872 | + if (ret < 0) | |
873 | + return ret; | |
874 | + ret = Opt_update; | |
875 | + break; | |
876 | + case Opt_err: | |
877 | + return -EINVAL; | |
878 | + break; | |
879 | + } | |
880 | + return ret; | |
881 | +} | |
882 | + | |
883 | +static struct trusted_key_options *trusted_options_alloc(void) | |
884 | +{ | |
885 | + struct trusted_key_options *options; | |
886 | + | |
887 | + options = kzalloc(sizeof *options, GFP_KERNEL); | |
888 | + if (options) { | |
889 | + /* set any non-zero defaults */ | |
890 | + options->keytype = SRK_keytype; | |
891 | + options->keyhandle = SRKHANDLE; | |
892 | + } | |
893 | + return options; | |
894 | +} | |
895 | + | |
896 | +static struct trusted_key_payload *trusted_payload_alloc(struct key *key) | |
897 | +{ | |
898 | + struct trusted_key_payload *p = NULL; | |
899 | + int ret; | |
900 | + | |
901 | + ret = key_payload_reserve(key, sizeof *p); | |
902 | + if (ret < 0) | |
903 | + return p; | |
904 | + p = kzalloc(sizeof *p, GFP_KERNEL); | |
905 | + if (p) | |
906 | + p->migratable = 1; /* migratable by default */ | |
907 | + return p; | |
908 | +} | |
909 | + | |
910 | +/* | |
911 | + * trusted_instantiate - create a new trusted key | |
912 | + * | |
913 | + * Unseal an existing trusted blob or, for a new key, get a | |
914 | + * random key, then seal and create a trusted key-type key, | |
915 | + * adding it to the specified keyring. | |
916 | + * | |
917 | + * On success, return 0. Otherwise return errno. | |
918 | + */ | |
919 | +static int trusted_instantiate(struct key *key, const void *data, | |
920 | + size_t datalen) | |
921 | +{ | |
922 | + struct trusted_key_payload *payload = NULL; | |
923 | + struct trusted_key_options *options = NULL; | |
924 | + char *datablob; | |
925 | + int ret = 0; | |
926 | + int key_cmd; | |
927 | + | |
928 | + if (datalen <= 0 || datalen > 32767 || !data) | |
929 | + return -EINVAL; | |
930 | + | |
931 | + datablob = kmalloc(datalen + 1, GFP_KERNEL); | |
932 | + if (!datablob) | |
933 | + return -ENOMEM; | |
934 | + memcpy(datablob, data, datalen); | |
935 | + datablob[datalen] = '\0'; | |
936 | + | |
937 | + options = trusted_options_alloc(); | |
938 | + if (!options) { | |
939 | + ret = -ENOMEM; | |
940 | + goto out; | |
941 | + } | |
942 | + payload = trusted_payload_alloc(key); | |
943 | + if (!payload) { | |
944 | + ret = -ENOMEM; | |
945 | + goto out; | |
946 | + } | |
947 | + | |
948 | + key_cmd = datablob_parse(datablob, payload, options); | |
949 | + if (key_cmd < 0) { | |
950 | + ret = key_cmd; | |
951 | + goto out; | |
952 | + } | |
953 | + | |
954 | + dump_payload(payload); | |
955 | + dump_options(options); | |
956 | + | |
957 | + switch (key_cmd) { | |
958 | + case Opt_load: | |
959 | + ret = key_unseal(payload, options); | |
960 | + dump_payload(payload); | |
961 | + dump_options(options); | |
962 | + if (ret < 0) | |
963 | + pr_info("trusted_key: key_unseal failed (%d)\n", ret); | |
964 | + break; | |
965 | + case Opt_new: | |
966 | + ret = my_get_random(payload->key, payload->key_len); | |
967 | + if (ret < 0) { | |
968 | + pr_info("trusted_key: key_create failed (%d)\n", ret); | |
969 | + goto out; | |
970 | + } | |
971 | + ret = key_seal(payload, options); | |
972 | + if (ret < 0) | |
973 | + pr_info("trusted_key: key_seal failed (%d)\n", ret); | |
974 | + break; | |
975 | + default: | |
976 | + ret = -EINVAL; | |
977 | + goto out; | |
978 | + } | |
979 | + if (!ret && options->pcrlock) | |
980 | + ret = pcrlock(options->pcrlock); | |
981 | +out: | |
982 | + kfree(datablob); | |
983 | + kfree(options); | |
984 | + if (!ret) | |
985 | + rcu_assign_pointer(key->payload.data, payload); | |
986 | + else | |
987 | + kfree(payload); | |
988 | + return ret; | |
989 | +} | |
990 | + | |
991 | +static void trusted_rcu_free(struct rcu_head *rcu) | |
992 | +{ | |
993 | + struct trusted_key_payload *p; | |
994 | + | |
995 | + p = container_of(rcu, struct trusted_key_payload, rcu); | |
996 | + memset(p->key, 0, p->key_len); | |
997 | + kfree(p); | |
998 | +} | |
999 | + | |
1000 | +/* | |
1001 | + * trusted_update - reseal an existing key with new PCR values | |
1002 | + */ | |
1003 | +static int trusted_update(struct key *key, const void *data, size_t datalen) | |
1004 | +{ | |
1005 | + struct trusted_key_payload *p = key->payload.data; | |
1006 | + struct trusted_key_payload *new_p; | |
1007 | + struct trusted_key_options *new_o; | |
1008 | + char *datablob; | |
1009 | + int ret = 0; | |
1010 | + | |
1011 | + if (!p->migratable) | |
1012 | + return -EPERM; | |
1013 | + if (datalen <= 0 || datalen > 32767 || !data) | |
1014 | + return -EINVAL; | |
1015 | + | |
1016 | + datablob = kmalloc(datalen + 1, GFP_KERNEL); | |
1017 | + if (!datablob) | |
1018 | + return -ENOMEM; | |
1019 | + new_o = trusted_options_alloc(); | |
1020 | + if (!new_o) { | |
1021 | + ret = -ENOMEM; | |
1022 | + goto out; | |
1023 | + } | |
1024 | + new_p = trusted_payload_alloc(key); | |
1025 | + if (!new_p) { | |
1026 | + ret = -ENOMEM; | |
1027 | + goto out; | |
1028 | + } | |
1029 | + | |
1030 | + memcpy(datablob, data, datalen); | |
1031 | + datablob[datalen] = '\0'; | |
1032 | + ret = datablob_parse(datablob, new_p, new_o); | |
1033 | + if (ret != Opt_update) { | |
1034 | + ret = -EINVAL; | |
1035 | + goto out; | |
1036 | + } | |
1037 | + /* copy old key values, and reseal with new pcrs */ | |
1038 | + new_p->migratable = p->migratable; | |
1039 | + new_p->key_len = p->key_len; | |
1040 | + memcpy(new_p->key, p->key, p->key_len); | |
1041 | + dump_payload(p); | |
1042 | + dump_payload(new_p); | |
1043 | + | |
1044 | + ret = key_seal(new_p, new_o); | |
1045 | + if (ret < 0) { | |
1046 | + pr_info("trusted_key: key_seal failed (%d)\n", ret); | |
1047 | + kfree(new_p); | |
1048 | + goto out; | |
1049 | + } | |
1050 | + if (new_o->pcrlock) { | |
1051 | + ret = pcrlock(new_o->pcrlock); | |
1052 | + if (ret < 0) { | |
1053 | + pr_info("trusted_key: pcrlock failed (%d)\n", ret); | |
1054 | + kfree(new_p); | |
1055 | + goto out; | |
1056 | + } | |
1057 | + } | |
1058 | + rcu_assign_pointer(key->payload.data, new_p); | |
1059 | + call_rcu(&p->rcu, trusted_rcu_free); | |
1060 | +out: | |
1061 | + kfree(datablob); | |
1062 | + kfree(new_o); | |
1063 | + return ret; | |
1064 | +} | |
1065 | + | |
1066 | +/* | |
1067 | + * trusted_read - copy the sealed blob data to userspace in hex. | |
1068 | + * On success, return to userspace the trusted key datablob size. | |
1069 | + */ | |
1070 | +static long trusted_read(const struct key *key, char __user *buffer, | |
1071 | + size_t buflen) | |
1072 | +{ | |
1073 | + struct trusted_key_payload *p; | |
1074 | + char *ascii_buf; | |
1075 | + char *bufp; | |
1076 | + int i; | |
1077 | + | |
1078 | + p = rcu_dereference_protected(key->payload.data, | |
1079 | + rwsem_is_locked(&((struct key *)key)->sem)); | |
1080 | + if (!p) | |
1081 | + return -EINVAL; | |
1082 | + if (!buffer || buflen <= 0) | |
1083 | + return 2 * p->blob_len; | |
1084 | + ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL); | |
1085 | + if (!ascii_buf) | |
1086 | + return -ENOMEM; | |
1087 | + | |
1088 | + bufp = ascii_buf; | |
1089 | + for (i = 0; i < p->blob_len; i++) | |
1090 | + bufp = pack_hex_byte(bufp, p->blob[i]); | |
1091 | + if ((copy_to_user(buffer, ascii_buf, 2 * p->blob_len)) != 0) { | |
1092 | + kfree(ascii_buf); | |
1093 | + return -EFAULT; | |
1094 | + } | |
1095 | + kfree(ascii_buf); | |
1096 | + return 2 * p->blob_len; | |
1097 | +} | |
1098 | + | |
1099 | +/* | |
1100 | + * trusted_destroy - before freeing the key, clear the decrypted data | |
1101 | + */ | |
1102 | +static void trusted_destroy(struct key *key) | |
1103 | +{ | |
1104 | + struct trusted_key_payload *p = key->payload.data; | |
1105 | + | |
1106 | + if (!p) | |
1107 | + return; | |
1108 | + memset(p->key, 0, p->key_len); | |
1109 | + kfree(key->payload.data); | |
1110 | +} | |
1111 | + | |
1112 | +struct key_type key_type_trusted = { | |
1113 | + .name = "trusted", | |
1114 | + .instantiate = trusted_instantiate, | |
1115 | + .update = trusted_update, | |
1116 | + .match = user_match, | |
1117 | + .destroy = trusted_destroy, | |
1118 | + .describe = user_describe, | |
1119 | + .read = trusted_read, | |
1120 | +}; | |
1121 | + | |
1122 | +EXPORT_SYMBOL_GPL(key_type_trusted); | |
1123 | + | |
1124 | +static void trusted_shash_release(void) | |
1125 | +{ | |
1126 | + if (hashalg) | |
1127 | + crypto_free_shash(hashalg); | |
1128 | + if (hmacalg) | |
1129 | + crypto_free_shash(hmacalg); | |
1130 | +} | |
1131 | + | |
1132 | +static int __init trusted_shash_alloc(void) | |
1133 | +{ | |
1134 | + int ret; | |
1135 | + | |
1136 | + hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC); | |
1137 | + if (IS_ERR(hmacalg)) { | |
1138 | + pr_info("trusted_key: could not allocate crypto %s\n", | |
1139 | + hmac_alg); | |
1140 | + return PTR_ERR(hmacalg); | |
1141 | + } | |
1142 | + | |
1143 | + hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); | |
1144 | + if (IS_ERR(hashalg)) { | |
1145 | + pr_info("trusted_key: could not allocate crypto %s\n", | |
1146 | + hash_alg); | |
1147 | + ret = PTR_ERR(hashalg); | |
1148 | + goto hashalg_fail; | |
1149 | + } | |
1150 | + | |
1151 | + return 0; | |
1152 | + | |
1153 | +hashalg_fail: | |
1154 | + crypto_free_shash(hmacalg); | |
1155 | + return ret; | |
1156 | +} | |
1157 | + | |
1158 | +static int __init init_trusted(void) | |
1159 | +{ | |
1160 | + int ret; | |
1161 | + | |
1162 | + ret = trusted_shash_alloc(); | |
1163 | + if (ret < 0) | |
1164 | + return ret; | |
1165 | + ret = register_key_type(&key_type_trusted); | |
1166 | + if (ret < 0) | |
1167 | + trusted_shash_release(); | |
1168 | + return ret; | |
1169 | +} | |
1170 | + | |
1171 | +static void __exit cleanup_trusted(void) | |
1172 | +{ | |
1173 | + trusted_shash_release(); | |
1174 | + unregister_key_type(&key_type_trusted); | |
1175 | +} | |
1176 | + | |
1177 | +late_initcall(init_trusted); | |
1178 | +module_exit(cleanup_trusted); | |
1179 | + | |
1180 | +MODULE_LICENSE("GPL"); |
security/keys/trusted.h
1 | +#ifndef __TRUSTED_KEY_H | |
2 | +#define __TRUSTED_KEY_H | |
3 | + | |
4 | +/* implementation specific TPM constants */ | |
5 | +#define MAX_PCRINFO_SIZE 64 | |
6 | +#define MAX_BUF_SIZE 512 | |
7 | +#define TPM_GETRANDOM_SIZE 14 | |
8 | +#define TPM_OSAP_SIZE 36 | |
9 | +#define TPM_OIAP_SIZE 10 | |
10 | +#define TPM_SEAL_SIZE 87 | |
11 | +#define TPM_UNSEAL_SIZE 104 | |
12 | +#define TPM_SIZE_OFFSET 2 | |
13 | +#define TPM_RETURN_OFFSET 6 | |
14 | +#define TPM_DATA_OFFSET 10 | |
15 | + | |
16 | +#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset])) | |
17 | +#define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) | |
18 | +#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) | |
19 | + | |
20 | +struct tpm_buf { | |
21 | + int len; | |
22 | + unsigned char data[MAX_BUF_SIZE]; | |
23 | +}; | |
24 | + | |
25 | +#define INIT_BUF(tb) (tb->len = 0) | |
26 | + | |
27 | +struct osapsess { | |
28 | + uint32_t handle; | |
29 | + unsigned char secret[SHA1_DIGEST_SIZE]; | |
30 | + unsigned char enonce[TPM_NONCE_SIZE]; | |
31 | +}; | |
32 | + | |
33 | +/* discrete values, but have to store in uint16_t for TPM use */ | |
34 | +enum { | |
35 | + SEAL_keytype = 1, | |
36 | + SRK_keytype = 4 | |
37 | +}; | |
38 | + | |
39 | +struct trusted_key_options { | |
40 | + uint16_t keytype; | |
41 | + uint32_t keyhandle; | |
42 | + unsigned char keyauth[SHA1_DIGEST_SIZE]; | |
43 | + unsigned char blobauth[SHA1_DIGEST_SIZE]; | |
44 | + uint32_t pcrinfo_len; | |
45 | + unsigned char pcrinfo[MAX_PCRINFO_SIZE]; | |
46 | + int pcrlock; | |
47 | +}; | |
48 | + | |
49 | +#define TPM_DEBUG 0 | |
50 | + | |
51 | +#if TPM_DEBUG | |
52 | +static inline void dump_options(struct trusted_key_options *o) | |
53 | +{ | |
54 | + pr_info("trusted_key: sealing key type %d\n", o->keytype); | |
55 | + pr_info("trusted_key: sealing key handle %0X\n", o->keyhandle); | |
56 | + pr_info("trusted_key: pcrlock %d\n", o->pcrlock); | |
57 | + pr_info("trusted_key: pcrinfo %d\n", o->pcrinfo_len); | |
58 | + print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE, | |
59 | + 16, 1, o->pcrinfo, o->pcrinfo_len, 0); | |
60 | +} | |
61 | + | |
62 | +static inline void dump_payload(struct trusted_key_payload *p) | |
63 | +{ | |
64 | + pr_info("trusted_key: key_len %d\n", p->key_len); | |
65 | + print_hex_dump(KERN_INFO, "key ", DUMP_PREFIX_NONE, | |
66 | + 16, 1, p->key, p->key_len, 0); | |
67 | + pr_info("trusted_key: bloblen %d\n", p->blob_len); | |
68 | + print_hex_dump(KERN_INFO, "blob ", DUMP_PREFIX_NONE, | |
69 | + 16, 1, p->blob, p->blob_len, 0); | |
70 | + pr_info("trusted_key: migratable %d\n", p->migratable); | |
71 | +} | |
72 | + | |
73 | +static inline void dump_sess(struct osapsess *s) | |
74 | +{ | |
75 | + print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE, | |
76 | + 16, 1, &s->handle, 4, 0); | |
77 | + pr_info("trusted-key: secret:\n"); | |
78 | + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, | |
79 | + 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0); | |
80 | + pr_info("trusted-key: enonce:\n"); | |
81 | + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, | |
82 | + 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0); | |
83 | +} | |
84 | + | |
85 | +static inline void dump_tpm_buf(unsigned char *buf) | |
86 | +{ | |
87 | + int len; | |
88 | + | |
89 | + pr_info("\ntrusted-key: tpm buffer\n"); | |
90 | + len = LOAD32(buf, TPM_SIZE_OFFSET); | |
91 | + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0); | |
92 | +} | |
93 | +#else | |
94 | +static inline void dump_options(struct trusted_key_options *o) | |
95 | +{ | |
96 | +} | |
97 | + | |
98 | +static inline void dump_payload(struct trusted_key_payload *p) | |
99 | +{ | |
100 | +} | |
101 | + | |
102 | +static inline void dump_sess(struct osapsess *s) | |
103 | +{ | |
104 | +} | |
105 | + | |
106 | +static inline void dump_tpm_buf(unsigned char *buf) | |
107 | +{ | |
108 | +} | |
109 | +#endif | |
110 | + | |
111 | +static inline void store8(struct tpm_buf *buf, const unsigned char value) | |
112 | +{ | |
113 | + buf->data[buf->len++] = value; | |
114 | +} | |
115 | + | |
116 | +static inline void store16(struct tpm_buf *buf, const uint16_t value) | |
117 | +{ | |
118 | + *(uint16_t *) & buf->data[buf->len] = htons(value); | |
119 | + buf->len += sizeof value; | |
120 | +} | |
121 | + | |
122 | +static inline void store32(struct tpm_buf *buf, const uint32_t value) | |
123 | +{ | |
124 | + *(uint32_t *) & buf->data[buf->len] = htonl(value); | |
125 | + buf->len += sizeof value; | |
126 | +} | |
127 | + | |
128 | +static inline void storebytes(struct tpm_buf *buf, const unsigned char *in, | |
129 | + const int len) | |
130 | +{ | |
131 | + memcpy(buf->data + buf->len, in, len); | |
132 | + buf->len += len; | |
133 | +} | |
134 | +#endif |
security/keys/trusted_defined.c
Changes suppressed. Click to show
1 | -/* | |
2 | - * Copyright (C) 2010 IBM Corporation | |
3 | - * | |
4 | - * Author: | |
5 | - * David Safford <safford@us.ibm.com> | |
6 | - * | |
7 | - * This program is free software; you can redistribute it and/or modify | |
8 | - * it under the terms of the GNU General Public License as published by | |
9 | - * the Free Software Foundation, version 2 of the License. | |
10 | - * | |
11 | - * See Documentation/keys-trusted-encrypted.txt | |
12 | - */ | |
13 | - | |
14 | -#include <linux/uaccess.h> | |
15 | -#include <linux/module.h> | |
16 | -#include <linux/init.h> | |
17 | -#include <linux/slab.h> | |
18 | -#include <linux/parser.h> | |
19 | -#include <linux/string.h> | |
20 | -#include <linux/err.h> | |
21 | -#include <keys/user-type.h> | |
22 | -#include <keys/trusted-type.h> | |
23 | -#include <linux/key-type.h> | |
24 | -#include <linux/rcupdate.h> | |
25 | -#include <linux/crypto.h> | |
26 | -#include <crypto/hash.h> | |
27 | -#include <crypto/sha.h> | |
28 | -#include <linux/capability.h> | |
29 | -#include <linux/tpm.h> | |
30 | -#include <linux/tpm_command.h> | |
31 | - | |
32 | -#include "trusted_defined.h" | |
33 | - | |
34 | -static const char hmac_alg[] = "hmac(sha1)"; | |
35 | -static const char hash_alg[] = "sha1"; | |
36 | - | |
37 | -struct sdesc { | |
38 | - struct shash_desc shash; | |
39 | - char ctx[]; | |
40 | -}; | |
41 | - | |
42 | -static struct crypto_shash *hashalg; | |
43 | -static struct crypto_shash *hmacalg; | |
44 | - | |
45 | -static struct sdesc *init_sdesc(struct crypto_shash *alg) | |
46 | -{ | |
47 | - struct sdesc *sdesc; | |
48 | - int size; | |
49 | - | |
50 | - size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); | |
51 | - sdesc = kmalloc(size, GFP_KERNEL); | |
52 | - if (!sdesc) | |
53 | - return ERR_PTR(-ENOMEM); | |
54 | - sdesc->shash.tfm = alg; | |
55 | - sdesc->shash.flags = 0x0; | |
56 | - return sdesc; | |
57 | -} | |
58 | - | |
59 | -static int TSS_sha1(const unsigned char *data, unsigned int datalen, | |
60 | - unsigned char *digest) | |
61 | -{ | |
62 | - struct sdesc *sdesc; | |
63 | - int ret; | |
64 | - | |
65 | - sdesc = init_sdesc(hashalg); | |
66 | - if (IS_ERR(sdesc)) { | |
67 | - pr_info("trusted_key: can't alloc %s\n", hash_alg); | |
68 | - return PTR_ERR(sdesc); | |
69 | - } | |
70 | - | |
71 | - ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest); | |
72 | - kfree(sdesc); | |
73 | - return ret; | |
74 | -} | |
75 | - | |
76 | -static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, | |
77 | - unsigned int keylen, ...) | |
78 | -{ | |
79 | - struct sdesc *sdesc; | |
80 | - va_list argp; | |
81 | - unsigned int dlen; | |
82 | - unsigned char *data; | |
83 | - int ret; | |
84 | - | |
85 | - sdesc = init_sdesc(hmacalg); | |
86 | - if (IS_ERR(sdesc)) { | |
87 | - pr_info("trusted_key: can't alloc %s\n", hmac_alg); | |
88 | - return PTR_ERR(sdesc); | |
89 | - } | |
90 | - | |
91 | - ret = crypto_shash_setkey(hmacalg, key, keylen); | |
92 | - if (ret < 0) | |
93 | - goto out; | |
94 | - ret = crypto_shash_init(&sdesc->shash); | |
95 | - if (ret < 0) | |
96 | - goto out; | |
97 | - | |
98 | - va_start(argp, keylen); | |
99 | - for (;;) { | |
100 | - dlen = va_arg(argp, unsigned int); | |
101 | - if (dlen == 0) | |
102 | - break; | |
103 | - data = va_arg(argp, unsigned char *); | |
104 | - if (data == NULL) { | |
105 | - ret = -EINVAL; | |
106 | - break; | |
107 | - } | |
108 | - ret = crypto_shash_update(&sdesc->shash, data, dlen); | |
109 | - if (ret < 0) | |
110 | - break; | |
111 | - } | |
112 | - va_end(argp); | |
113 | - if (!ret) | |
114 | - ret = crypto_shash_final(&sdesc->shash, digest); | |
115 | -out: | |
116 | - kfree(sdesc); | |
117 | - return ret; | |
118 | -} | |
119 | - | |
120 | -/* | |
121 | - * calculate authorization info fields to send to TPM | |
122 | - */ | |
123 | -static int TSS_authhmac(unsigned char *digest, const unsigned char *key, | |
124 | - unsigned int keylen, unsigned char *h1, | |
125 | - unsigned char *h2, unsigned char h3, ...) | |
126 | -{ | |
127 | - unsigned char paramdigest[SHA1_DIGEST_SIZE]; | |
128 | - struct sdesc *sdesc; | |
129 | - unsigned int dlen; | |
130 | - unsigned char *data; | |
131 | - unsigned char c; | |
132 | - int ret; | |
133 | - va_list argp; | |
134 | - | |
135 | - sdesc = init_sdesc(hashalg); | |
136 | - if (IS_ERR(sdesc)) { | |
137 | - pr_info("trusted_key: can't alloc %s\n", hash_alg); | |
138 | - return PTR_ERR(sdesc); | |
139 | - } | |
140 | - | |
141 | - c = h3; | |
142 | - ret = crypto_shash_init(&sdesc->shash); | |
143 | - if (ret < 0) | |
144 | - goto out; | |
145 | - va_start(argp, h3); | |
146 | - for (;;) { | |
147 | - dlen = va_arg(argp, unsigned int); | |
148 | - if (dlen == 0) | |
149 | - break; | |
150 | - data = va_arg(argp, unsigned char *); | |
151 | - if (!data) { | |
152 | - ret = -EINVAL; | |
153 | - break; | |
154 | - } | |
155 | - ret = crypto_shash_update(&sdesc->shash, data, dlen); | |
156 | - if (ret < 0) | |
157 | - break; | |
158 | - } | |
159 | - va_end(argp); | |
160 | - if (!ret) | |
161 | - ret = crypto_shash_final(&sdesc->shash, paramdigest); | |
162 | - if (!ret) | |
163 | - ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE, | |
164 | - paramdigest, TPM_NONCE_SIZE, h1, | |
165 | - TPM_NONCE_SIZE, h2, 1, &c, 0, 0); | |
166 | -out: | |
167 | - kfree(sdesc); | |
168 | - return ret; | |
169 | -} | |
170 | - | |
171 | -/* | |
172 | - * verify the AUTH1_COMMAND (Seal) result from TPM | |
173 | - */ | |
174 | -static int TSS_checkhmac1(unsigned char *buffer, | |
175 | - const uint32_t command, | |
176 | - const unsigned char *ononce, | |
177 | - const unsigned char *key, | |
178 | - unsigned int keylen, ...) | |
179 | -{ | |
180 | - uint32_t bufsize; | |
181 | - uint16_t tag; | |
182 | - uint32_t ordinal; | |
183 | - uint32_t result; | |
184 | - unsigned char *enonce; | |
185 | - unsigned char *continueflag; | |
186 | - unsigned char *authdata; | |
187 | - unsigned char testhmac[SHA1_DIGEST_SIZE]; | |
188 | - unsigned char paramdigest[SHA1_DIGEST_SIZE]; | |
189 | - struct sdesc *sdesc; | |
190 | - unsigned int dlen; | |
191 | - unsigned int dpos; | |
192 | - va_list argp; | |
193 | - int ret; | |
194 | - | |
195 | - bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); | |
196 | - tag = LOAD16(buffer, 0); | |
197 | - ordinal = command; | |
198 | - result = LOAD32N(buffer, TPM_RETURN_OFFSET); | |
199 | - if (tag == TPM_TAG_RSP_COMMAND) | |
200 | - return 0; | |
201 | - if (tag != TPM_TAG_RSP_AUTH1_COMMAND) | |
202 | - return -EINVAL; | |
203 | - authdata = buffer + bufsize - SHA1_DIGEST_SIZE; | |
204 | - continueflag = authdata - 1; | |
205 | - enonce = continueflag - TPM_NONCE_SIZE; | |
206 | - | |
207 | - sdesc = init_sdesc(hashalg); | |
208 | - if (IS_ERR(sdesc)) { | |
209 | - pr_info("trusted_key: can't alloc %s\n", hash_alg); | |
210 | - return PTR_ERR(sdesc); | |
211 | - } | |
212 | - ret = crypto_shash_init(&sdesc->shash); | |
213 | - if (ret < 0) | |
214 | - goto out; | |
215 | - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, | |
216 | - sizeof result); | |
217 | - if (ret < 0) | |
218 | - goto out; | |
219 | - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, | |
220 | - sizeof ordinal); | |
221 | - if (ret < 0) | |
222 | - goto out; | |
223 | - va_start(argp, keylen); | |
224 | - for (;;) { | |
225 | - dlen = va_arg(argp, unsigned int); | |
226 | - if (dlen == 0) | |
227 | - break; | |
228 | - dpos = va_arg(argp, unsigned int); | |
229 | - ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); | |
230 | - if (ret < 0) | |
231 | - break; | |
232 | - } | |
233 | - va_end(argp); | |
234 | - if (!ret) | |
235 | - ret = crypto_shash_final(&sdesc->shash, paramdigest); | |
236 | - if (ret < 0) | |
237 | - goto out; | |
238 | - | |
239 | - ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest, | |
240 | - TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce, | |
241 | - 1, continueflag, 0, 0); | |
242 | - if (ret < 0) | |
243 | - goto out; | |
244 | - | |
245 | - if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE)) | |
246 | - ret = -EINVAL; | |
247 | -out: | |
248 | - kfree(sdesc); | |
249 | - return ret; | |
250 | -} | |
251 | - | |
252 | -/* | |
253 | - * verify the AUTH2_COMMAND (unseal) result from TPM | |
254 | - */ | |
255 | -static int TSS_checkhmac2(unsigned char *buffer, | |
256 | - const uint32_t command, | |
257 | - const unsigned char *ononce, | |
258 | - const unsigned char *key1, | |
259 | - unsigned int keylen1, | |
260 | - const unsigned char *key2, | |
261 | - unsigned int keylen2, ...) | |
262 | -{ | |
263 | - uint32_t bufsize; | |
264 | - uint16_t tag; | |
265 | - uint32_t ordinal; | |
266 | - uint32_t result; | |
267 | - unsigned char *enonce1; | |
268 | - unsigned char *continueflag1; | |
269 | - unsigned char *authdata1; | |
270 | - unsigned char *enonce2; | |
271 | - unsigned char *continueflag2; | |
272 | - unsigned char *authdata2; | |
273 | - unsigned char testhmac1[SHA1_DIGEST_SIZE]; | |
274 | - unsigned char testhmac2[SHA1_DIGEST_SIZE]; | |
275 | - unsigned char paramdigest[SHA1_DIGEST_SIZE]; | |
276 | - struct sdesc *sdesc; | |
277 | - unsigned int dlen; | |
278 | - unsigned int dpos; | |
279 | - va_list argp; | |
280 | - int ret; | |
281 | - | |
282 | - bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); | |
283 | - tag = LOAD16(buffer, 0); | |
284 | - ordinal = command; | |
285 | - result = LOAD32N(buffer, TPM_RETURN_OFFSET); | |
286 | - | |
287 | - if (tag == TPM_TAG_RSP_COMMAND) | |
288 | - return 0; | |
289 | - if (tag != TPM_TAG_RSP_AUTH2_COMMAND) | |
290 | - return -EINVAL; | |
291 | - authdata1 = buffer + bufsize - (SHA1_DIGEST_SIZE + 1 | |
292 | - + SHA1_DIGEST_SIZE + SHA1_DIGEST_SIZE); | |
293 | - authdata2 = buffer + bufsize - (SHA1_DIGEST_SIZE); | |
294 | - continueflag1 = authdata1 - 1; | |
295 | - continueflag2 = authdata2 - 1; | |
296 | - enonce1 = continueflag1 - TPM_NONCE_SIZE; | |
297 | - enonce2 = continueflag2 - TPM_NONCE_SIZE; | |
298 | - | |
299 | - sdesc = init_sdesc(hashalg); | |
300 | - if (IS_ERR(sdesc)) { | |
301 | - pr_info("trusted_key: can't alloc %s\n", hash_alg); | |
302 | - return PTR_ERR(sdesc); | |
303 | - } | |
304 | - ret = crypto_shash_init(&sdesc->shash); | |
305 | - if (ret < 0) | |
306 | - goto out; | |
307 | - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, | |
308 | - sizeof result); | |
309 | - if (ret < 0) | |
310 | - goto out; | |
311 | - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, | |
312 | - sizeof ordinal); | |
313 | - if (ret < 0) | |
314 | - goto out; | |
315 | - | |
316 | - va_start(argp, keylen2); | |
317 | - for (;;) { | |
318 | - dlen = va_arg(argp, unsigned int); | |
319 | - if (dlen == 0) | |
320 | - break; | |
321 | - dpos = va_arg(argp, unsigned int); | |
322 | - ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); | |
323 | - if (ret < 0) | |
324 | - break; | |
325 | - } | |
326 | - va_end(argp); | |
327 | - if (!ret) | |
328 | - ret = crypto_shash_final(&sdesc->shash, paramdigest); | |
329 | - if (ret < 0) | |
330 | - goto out; | |
331 | - | |
332 | - ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE, | |
333 | - paramdigest, TPM_NONCE_SIZE, enonce1, | |
334 | - TPM_NONCE_SIZE, ononce, 1, continueflag1, 0, 0); | |
335 | - if (ret < 0) | |
336 | - goto out; | |
337 | - if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) { | |
338 | - ret = -EINVAL; | |
339 | - goto out; | |
340 | - } | |
341 | - ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE, | |
342 | - paramdigest, TPM_NONCE_SIZE, enonce2, | |
343 | - TPM_NONCE_SIZE, ononce, 1, continueflag2, 0, 0); | |
344 | - if (ret < 0) | |
345 | - goto out; | |
346 | - if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE)) | |
347 | - ret = -EINVAL; | |
348 | -out: | |
349 | - kfree(sdesc); | |
350 | - return ret; | |
351 | -} | |
352 | - | |
353 | -/* | |
354 | - * For key specific tpm requests, we will generate and send our | |
355 | - * own TPM command packets using the drivers send function. | |
356 | - */ | |
357 | -static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd, | |
358 | - size_t buflen) | |
359 | -{ | |
360 | - int rc; | |
361 | - | |
362 | - dump_tpm_buf(cmd); | |
363 | - rc = tpm_send(chip_num, cmd, buflen); | |
364 | - dump_tpm_buf(cmd); | |
365 | - if (rc > 0) | |
366 | - /* Can't return positive return codes values to keyctl */ | |
367 | - rc = -EPERM; | |
368 | - return rc; | |
369 | -} | |
370 | - | |
371 | -/* | |
372 | - * get a random value from TPM | |
373 | - */ | |
374 | -static int tpm_get_random(struct tpm_buf *tb, unsigned char *buf, uint32_t len) | |
375 | -{ | |
376 | - int ret; | |
377 | - | |
378 | - INIT_BUF(tb); | |
379 | - store16(tb, TPM_TAG_RQU_COMMAND); | |
380 | - store32(tb, TPM_GETRANDOM_SIZE); | |
381 | - store32(tb, TPM_ORD_GETRANDOM); | |
382 | - store32(tb, len); | |
383 | - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data); | |
384 | - if (!ret) | |
385 | - memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len); | |
386 | - return ret; | |
387 | -} | |
388 | - | |
389 | -static int my_get_random(unsigned char *buf, int len) | |
390 | -{ | |
391 | - struct tpm_buf *tb; | |
392 | - int ret; | |
393 | - | |
394 | - tb = kmalloc(sizeof *tb, GFP_KERNEL); | |
395 | - if (!tb) | |
396 | - return -ENOMEM; | |
397 | - ret = tpm_get_random(tb, buf, len); | |
398 | - | |
399 | - kfree(tb); | |
400 | - return ret; | |
401 | -} | |
402 | - | |
403 | -/* | |
404 | - * Lock a trusted key, by extending a selected PCR. | |
405 | - * | |
406 | - * Prevents a trusted key that is sealed to PCRs from being accessed. | |
407 | - * This uses the tpm driver's extend function. | |
408 | - */ | |
409 | -static int pcrlock(const int pcrnum) | |
410 | -{ | |
411 | - unsigned char hash[SHA1_DIGEST_SIZE]; | |
412 | - int ret; | |
413 | - | |
414 | - if (!capable(CAP_SYS_ADMIN)) | |
415 | - return -EPERM; | |
416 | - ret = my_get_random(hash, SHA1_DIGEST_SIZE); | |
417 | - if (ret < 0) | |
418 | - return ret; | |
419 | - return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0; | |
420 | -} | |
421 | - | |
422 | -/* | |
423 | - * Create an object specific authorisation protocol (OSAP) session | |
424 | - */ | |
425 | -static int osap(struct tpm_buf *tb, struct osapsess *s, | |
426 | - const unsigned char *key, uint16_t type, uint32_t handle) | |
427 | -{ | |
428 | - unsigned char enonce[TPM_NONCE_SIZE]; | |
429 | - unsigned char ononce[TPM_NONCE_SIZE]; | |
430 | - int ret; | |
431 | - | |
432 | - ret = tpm_get_random(tb, ononce, TPM_NONCE_SIZE); | |
433 | - if (ret < 0) | |
434 | - return ret; | |
435 | - | |
436 | - INIT_BUF(tb); | |
437 | - store16(tb, TPM_TAG_RQU_COMMAND); | |
438 | - store32(tb, TPM_OSAP_SIZE); | |
439 | - store32(tb, TPM_ORD_OSAP); | |
440 | - store16(tb, type); | |
441 | - store32(tb, handle); | |
442 | - storebytes(tb, ononce, TPM_NONCE_SIZE); | |
443 | - | |
444 | - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); | |
445 | - if (ret < 0) | |
446 | - return ret; | |
447 | - | |
448 | - s->handle = LOAD32(tb->data, TPM_DATA_OFFSET); | |
449 | - memcpy(s->enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]), | |
450 | - TPM_NONCE_SIZE); | |
451 | - memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) + | |
452 | - TPM_NONCE_SIZE]), TPM_NONCE_SIZE); | |
453 | - return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE, | |
454 | - enonce, TPM_NONCE_SIZE, ononce, 0, 0); | |
455 | -} | |
456 | - | |
457 | -/* | |
458 | - * Create an object independent authorisation protocol (oiap) session | |
459 | - */ | |
460 | -static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) | |
461 | -{ | |
462 | - int ret; | |
463 | - | |
464 | - INIT_BUF(tb); | |
465 | - store16(tb, TPM_TAG_RQU_COMMAND); | |
466 | - store32(tb, TPM_OIAP_SIZE); | |
467 | - store32(tb, TPM_ORD_OIAP); | |
468 | - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); | |
469 | - if (ret < 0) | |
470 | - return ret; | |
471 | - | |
472 | - *handle = LOAD32(tb->data, TPM_DATA_OFFSET); | |
473 | - memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)], | |
474 | - TPM_NONCE_SIZE); | |
475 | - return 0; | |
476 | -} | |
477 | - | |
478 | -struct tpm_digests { | |
479 | - unsigned char encauth[SHA1_DIGEST_SIZE]; | |
480 | - unsigned char pubauth[SHA1_DIGEST_SIZE]; | |
481 | - unsigned char xorwork[SHA1_DIGEST_SIZE * 2]; | |
482 | - unsigned char xorhash[SHA1_DIGEST_SIZE]; | |
483 | - unsigned char nonceodd[TPM_NONCE_SIZE]; | |
484 | -}; | |
485 | - | |
486 | -/* | |
487 | - * Have the TPM seal(encrypt) the trusted key, possibly based on | |
488 | - * Platform Configuration Registers (PCRs). AUTH1 for sealing key. | |
489 | - */ | |
490 | -static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, | |
491 | - uint32_t keyhandle, const unsigned char *keyauth, | |
492 | - const unsigned char *data, uint32_t datalen, | |
493 | - unsigned char *blob, uint32_t *bloblen, | |
494 | - const unsigned char *blobauth, | |
495 | - const unsigned char *pcrinfo, uint32_t pcrinfosize) | |
496 | -{ | |
497 | - struct osapsess sess; | |
498 | - struct tpm_digests *td; | |
499 | - unsigned char cont; | |
500 | - uint32_t ordinal; | |
501 | - uint32_t pcrsize; | |
502 | - uint32_t datsize; | |
503 | - int sealinfosize; | |
504 | - int encdatasize; | |
505 | - int storedsize; | |
506 | - int ret; | |
507 | - int i; | |
508 | - | |
509 | - /* alloc some work space for all the hashes */ | |
510 | - td = kmalloc(sizeof *td, GFP_KERNEL); | |
511 | - if (!td) | |
512 | - return -ENOMEM; | |
513 | - | |
514 | - /* get session for sealing key */ | |
515 | - ret = osap(tb, &sess, keyauth, keytype, keyhandle); | |
516 | - if (ret < 0) | |
517 | - goto out; | |
518 | - dump_sess(&sess); | |
519 | - | |
520 | - /* calculate encrypted authorization value */ | |
521 | - memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE); | |
522 | - memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE); | |
523 | - ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash); | |
524 | - if (ret < 0) | |
525 | - goto out; | |
526 | - | |
527 | - ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE); | |
528 | - if (ret < 0) | |
529 | - goto out; | |
530 | - ordinal = htonl(TPM_ORD_SEAL); | |
531 | - datsize = htonl(datalen); | |
532 | - pcrsize = htonl(pcrinfosize); | |
533 | - cont = 0; | |
534 | - | |
535 | - /* encrypt data authorization key */ | |
536 | - for (i = 0; i < SHA1_DIGEST_SIZE; ++i) | |
537 | - td->encauth[i] = td->xorhash[i] ^ blobauth[i]; | |
538 | - | |
539 | - /* calculate authorization HMAC value */ | |
540 | - if (pcrinfosize == 0) { | |
541 | - /* no pcr info specified */ | |
542 | - ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, | |
543 | - sess.enonce, td->nonceodd, cont, | |
544 | - sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE, | |
545 | - td->encauth, sizeof(uint32_t), &pcrsize, | |
546 | - sizeof(uint32_t), &datsize, datalen, data, 0, | |
547 | - 0); | |
548 | - } else { | |
549 | - /* pcr info specified */ | |
550 | - ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, | |
551 | - sess.enonce, td->nonceodd, cont, | |
552 | - sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE, | |
553 | - td->encauth, sizeof(uint32_t), &pcrsize, | |
554 | - pcrinfosize, pcrinfo, sizeof(uint32_t), | |
555 | - &datsize, datalen, data, 0, 0); | |
556 | - } | |
557 | - if (ret < 0) | |
558 | - goto out; | |
559 | - | |
560 | - /* build and send the TPM request packet */ | |
561 | - INIT_BUF(tb); | |
562 | - store16(tb, TPM_TAG_RQU_AUTH1_COMMAND); | |
563 | - store32(tb, TPM_SEAL_SIZE + pcrinfosize + datalen); | |
564 | - store32(tb, TPM_ORD_SEAL); | |
565 | - store32(tb, keyhandle); | |
566 | - storebytes(tb, td->encauth, SHA1_DIGEST_SIZE); | |
567 | - store32(tb, pcrinfosize); | |
568 | - storebytes(tb, pcrinfo, pcrinfosize); | |
569 | - store32(tb, datalen); | |
570 | - storebytes(tb, data, datalen); | |
571 | - store32(tb, sess.handle); | |
572 | - storebytes(tb, td->nonceodd, TPM_NONCE_SIZE); | |
573 | - store8(tb, cont); | |
574 | - storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); | |
575 | - | |
576 | - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); | |
577 | - if (ret < 0) | |
578 | - goto out; | |
579 | - | |
580 | - /* calculate the size of the returned Blob */ | |
581 | - sealinfosize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t)); | |
582 | - encdatasize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t) + | |
583 | - sizeof(uint32_t) + sealinfosize); | |
584 | - storedsize = sizeof(uint32_t) + sizeof(uint32_t) + sealinfosize + | |
585 | - sizeof(uint32_t) + encdatasize; | |
586 | - | |
587 | - /* check the HMAC in the response */ | |
588 | - ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, sess.secret, | |
589 | - SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0, | |
590 | - 0); | |
591 | - | |
592 | - /* copy the returned blob to caller */ | |
593 | - if (!ret) { | |
594 | - memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize); | |
595 | - *bloblen = storedsize; | |
596 | - } | |
597 | -out: | |
598 | - kfree(td); | |
599 | - return ret; | |
600 | -} | |
601 | - | |
602 | -/* | |
603 | - * use the AUTH2_COMMAND form of unseal, to authorize both key and blob | |
604 | - */ | |
605 | -static int tpm_unseal(struct tpm_buf *tb, | |
606 | - uint32_t keyhandle, const unsigned char *keyauth, | |
607 | - const unsigned char *blob, int bloblen, | |
608 | - const unsigned char *blobauth, | |
609 | - unsigned char *data, unsigned int *datalen) | |
610 | -{ | |
611 | - unsigned char nonceodd[TPM_NONCE_SIZE]; | |
612 | - unsigned char enonce1[TPM_NONCE_SIZE]; | |
613 | - unsigned char enonce2[TPM_NONCE_SIZE]; | |
614 | - unsigned char authdata1[SHA1_DIGEST_SIZE]; | |
615 | - unsigned char authdata2[SHA1_DIGEST_SIZE]; | |
616 | - uint32_t authhandle1 = 0; | |
617 | - uint32_t authhandle2 = 0; | |
618 | - unsigned char cont = 0; | |
619 | - uint32_t ordinal; | |
620 | - uint32_t keyhndl; | |
621 | - int ret; | |
622 | - | |
623 | - /* sessions for unsealing key and data */ | |
624 | - ret = oiap(tb, &authhandle1, enonce1); | |
625 | - if (ret < 0) { | |
626 | - pr_info("trusted_key: oiap failed (%d)\n", ret); | |
627 | - return ret; | |
628 | - } | |
629 | - ret = oiap(tb, &authhandle2, enonce2); | |
630 | - if (ret < 0) { | |
631 | - pr_info("trusted_key: oiap failed (%d)\n", ret); | |
632 | - return ret; | |
633 | - } | |
634 | - | |
635 | - ordinal = htonl(TPM_ORD_UNSEAL); | |
636 | - keyhndl = htonl(SRKHANDLE); | |
637 | - ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE); | |
638 | - if (ret < 0) { | |
639 | - pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); | |
640 | - return ret; | |
641 | - } | |
642 | - ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, | |
643 | - enonce1, nonceodd, cont, sizeof(uint32_t), | |
644 | - &ordinal, bloblen, blob, 0, 0); | |
645 | - if (ret < 0) | |
646 | - return ret; | |
647 | - ret = TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE, | |
648 | - enonce2, nonceodd, cont, sizeof(uint32_t), | |
649 | - &ordinal, bloblen, blob, 0, 0); | |
650 | - if (ret < 0) | |
651 | - return ret; | |
652 | - | |
653 | - /* build and send TPM request packet */ | |
654 | - INIT_BUF(tb); | |
655 | - store16(tb, TPM_TAG_RQU_AUTH2_COMMAND); | |
656 | - store32(tb, TPM_UNSEAL_SIZE + bloblen); | |
657 | - store32(tb, TPM_ORD_UNSEAL); | |
658 | - store32(tb, keyhandle); | |
659 | - storebytes(tb, blob, bloblen); | |
660 | - store32(tb, authhandle1); | |
661 | - storebytes(tb, nonceodd, TPM_NONCE_SIZE); | |
662 | - store8(tb, cont); | |
663 | - storebytes(tb, authdata1, SHA1_DIGEST_SIZE); | |
664 | - store32(tb, authhandle2); | |
665 | - storebytes(tb, nonceodd, TPM_NONCE_SIZE); | |
666 | - store8(tb, cont); | |
667 | - storebytes(tb, authdata2, SHA1_DIGEST_SIZE); | |
668 | - | |
669 | - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); | |
670 | - if (ret < 0) { | |
671 | - pr_info("trusted_key: authhmac failed (%d)\n", ret); | |
672 | - return ret; | |
673 | - } | |
674 | - | |
675 | - *datalen = LOAD32(tb->data, TPM_DATA_OFFSET); | |
676 | - ret = TSS_checkhmac2(tb->data, ordinal, nonceodd, | |
677 | - keyauth, SHA1_DIGEST_SIZE, | |
678 | - blobauth, SHA1_DIGEST_SIZE, | |
679 | - sizeof(uint32_t), TPM_DATA_OFFSET, | |
680 | - *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0, | |
681 | - 0); | |
682 | - if (ret < 0) { | |
683 | - pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret); | |
684 | - return ret; | |
685 | - } | |
686 | - memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen); | |
687 | - return 0; | |
688 | -} | |
689 | - | |
690 | -/* | |
691 | - * Have the TPM seal(encrypt) the symmetric key | |
692 | - */ | |
693 | -static int key_seal(struct trusted_key_payload *p, | |
694 | - struct trusted_key_options *o) | |
695 | -{ | |
696 | - struct tpm_buf *tb; | |
697 | - int ret; | |
698 | - | |
699 | - tb = kzalloc(sizeof *tb, GFP_KERNEL); | |
700 | - if (!tb) | |
701 | - return -ENOMEM; | |
702 | - | |
703 | - /* include migratable flag at end of sealed key */ | |
704 | - p->key[p->key_len] = p->migratable; | |
705 | - | |
706 | - ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth, | |
707 | - p->key, p->key_len + 1, p->blob, &p->blob_len, | |
708 | - o->blobauth, o->pcrinfo, o->pcrinfo_len); | |
709 | - if (ret < 0) | |
710 | - pr_info("trusted_key: srkseal failed (%d)\n", ret); | |
711 | - | |
712 | - kfree(tb); | |
713 | - return ret; | |
714 | -} | |
715 | - | |
716 | -/* | |
717 | - * Have the TPM unseal(decrypt) the symmetric key | |
718 | - */ | |
719 | -static int key_unseal(struct trusted_key_payload *p, | |
720 | - struct trusted_key_options *o) | |
721 | -{ | |
722 | - struct tpm_buf *tb; | |
723 | - int ret; | |
724 | - | |
725 | - tb = kzalloc(sizeof *tb, GFP_KERNEL); | |
726 | - if (!tb) | |
727 | - return -ENOMEM; | |
728 | - | |
729 | - ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len, | |
730 | - o->blobauth, p->key, &p->key_len); | |
731 | - if (ret < 0) | |
732 | - pr_info("trusted_key: srkunseal failed (%d)\n", ret); | |
733 | - else | |
734 | - /* pull migratable flag out of sealed key */ | |
735 | - p->migratable = p->key[--p->key_len]; | |
736 | - | |
737 | - kfree(tb); | |
738 | - return ret; | |
739 | -} | |
740 | - | |
741 | -enum { | |
742 | - Opt_err = -1, | |
743 | - Opt_new, Opt_load, Opt_update, | |
744 | - Opt_keyhandle, Opt_keyauth, Opt_blobauth, | |
745 | - Opt_pcrinfo, Opt_pcrlock, Opt_migratable | |
746 | -}; | |
747 | - | |
748 | -static const match_table_t key_tokens = { | |
749 | - {Opt_new, "new"}, | |
750 | - {Opt_load, "load"}, | |
751 | - {Opt_update, "update"}, | |
752 | - {Opt_keyhandle, "keyhandle=%s"}, | |
753 | - {Opt_keyauth, "keyauth=%s"}, | |
754 | - {Opt_blobauth, "blobauth=%s"}, | |
755 | - {Opt_pcrinfo, "pcrinfo=%s"}, | |
756 | - {Opt_pcrlock, "pcrlock=%s"}, | |
757 | - {Opt_migratable, "migratable=%s"}, | |
758 | - {Opt_err, NULL} | |
759 | -}; | |
760 | - | |
761 | -/* can have zero or more token= options */ | |
762 | -static int getoptions(char *c, struct trusted_key_payload *pay, | |
763 | - struct trusted_key_options *opt) | |
764 | -{ | |
765 | - substring_t args[MAX_OPT_ARGS]; | |
766 | - char *p = c; | |
767 | - int token; | |
768 | - int res; | |
769 | - unsigned long handle; | |
770 | - unsigned long lock; | |
771 | - | |
772 | - while ((p = strsep(&c, " \t"))) { | |
773 | - if (*p == '\0' || *p == ' ' || *p == '\t') | |
774 | - continue; | |
775 | - token = match_token(p, key_tokens, args); | |
776 | - | |
777 | - switch (token) { | |
778 | - case Opt_pcrinfo: | |
779 | - opt->pcrinfo_len = strlen(args[0].from) / 2; | |
780 | - if (opt->pcrinfo_len > MAX_PCRINFO_SIZE) | |
781 | - return -EINVAL; | |
782 | - hex2bin(opt->pcrinfo, args[0].from, opt->pcrinfo_len); | |
783 | - break; | |
784 | - case Opt_keyhandle: | |
785 | - res = strict_strtoul(args[0].from, 16, &handle); | |
786 | - if (res < 0) | |
787 | - return -EINVAL; | |
788 | - opt->keytype = SEAL_keytype; | |
789 | - opt->keyhandle = handle; | |
790 | - break; | |
791 | - case Opt_keyauth: | |
792 | - if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE) | |
793 | - return -EINVAL; | |
794 | - hex2bin(opt->keyauth, args[0].from, SHA1_DIGEST_SIZE); | |
795 | - break; | |
796 | - case Opt_blobauth: | |
797 | - if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE) | |
798 | - return -EINVAL; | |
799 | - hex2bin(opt->blobauth, args[0].from, SHA1_DIGEST_SIZE); | |
800 | - break; | |
801 | - case Opt_migratable: | |
802 | - if (*args[0].from == '0') | |
803 | - pay->migratable = 0; | |
804 | - else | |
805 | - return -EINVAL; | |
806 | - break; | |
807 | - case Opt_pcrlock: | |
808 | - res = strict_strtoul(args[0].from, 10, &lock); | |
809 | - if (res < 0) | |
810 | - return -EINVAL; | |
811 | - opt->pcrlock = lock; | |
812 | - break; | |
813 | - default: | |
814 | - return -EINVAL; | |
815 | - } | |
816 | - } | |
817 | - return 0; | |
818 | -} | |
819 | - | |
820 | -/* | |
821 | - * datablob_parse - parse the keyctl data and fill in the | |
822 | - * payload and options structures | |
823 | - * | |
824 | - * On success returns 0, otherwise -EINVAL. | |
825 | - */ | |
826 | -static int datablob_parse(char *datablob, struct trusted_key_payload *p, | |
827 | - struct trusted_key_options *o) | |
828 | -{ | |
829 | - substring_t args[MAX_OPT_ARGS]; | |
830 | - long keylen; | |
831 | - int ret = -EINVAL; | |
832 | - int key_cmd; | |
833 | - char *c; | |
834 | - | |
835 | - /* main command */ | |
836 | - c = strsep(&datablob, " \t"); | |
837 | - if (!c) | |
838 | - return -EINVAL; | |
839 | - key_cmd = match_token(c, key_tokens, args); | |
840 | - switch (key_cmd) { | |
841 | - case Opt_new: | |
842 | - /* first argument is key size */ | |
843 | - c = strsep(&datablob, " \t"); | |
844 | - if (!c) | |
845 | - return -EINVAL; | |
846 | - ret = strict_strtol(c, 10, &keylen); | |
847 | - if (ret < 0 || keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE) | |
848 | - return -EINVAL; | |
849 | - p->key_len = keylen; | |
850 | - ret = getoptions(datablob, p, o); | |
851 | - if (ret < 0) | |
852 | - return ret; | |
853 | - ret = Opt_new; | |
854 | - break; | |
855 | - case Opt_load: | |
856 | - /* first argument is sealed blob */ | |
857 | - c = strsep(&datablob, " \t"); | |
858 | - if (!c) | |
859 | - return -EINVAL; | |
860 | - p->blob_len = strlen(c) / 2; | |
861 | - if (p->blob_len > MAX_BLOB_SIZE) | |
862 | - return -EINVAL; | |
863 | - hex2bin(p->blob, c, p->blob_len); | |
864 | - ret = getoptions(datablob, p, o); | |
865 | - if (ret < 0) | |
866 | - return ret; | |
867 | - ret = Opt_load; | |
868 | - break; | |
869 | - case Opt_update: | |
870 | - /* all arguments are options */ | |
871 | - ret = getoptions(datablob, p, o); | |
872 | - if (ret < 0) | |
873 | - return ret; | |
874 | - ret = Opt_update; | |
875 | - break; | |
876 | - case Opt_err: | |
877 | - return -EINVAL; | |
878 | - break; | |
879 | - } | |
880 | - return ret; | |
881 | -} | |
882 | - | |
883 | -static struct trusted_key_options *trusted_options_alloc(void) | |
884 | -{ | |
885 | - struct trusted_key_options *options; | |
886 | - | |
887 | - options = kzalloc(sizeof *options, GFP_KERNEL); | |
888 | - if (options) { | |
889 | - /* set any non-zero defaults */ | |
890 | - options->keytype = SRK_keytype; | |
891 | - options->keyhandle = SRKHANDLE; | |
892 | - } | |
893 | - return options; | |
894 | -} | |
895 | - | |
896 | -static struct trusted_key_payload *trusted_payload_alloc(struct key *key) | |
897 | -{ | |
898 | - struct trusted_key_payload *p = NULL; | |
899 | - int ret; | |
900 | - | |
901 | - ret = key_payload_reserve(key, sizeof *p); | |
902 | - if (ret < 0) | |
903 | - return p; | |
904 | - p = kzalloc(sizeof *p, GFP_KERNEL); | |
905 | - if (p) | |
906 | - p->migratable = 1; /* migratable by default */ | |
907 | - return p; | |
908 | -} | |
909 | - | |
910 | -/* | |
911 | - * trusted_instantiate - create a new trusted key | |
912 | - * | |
913 | - * Unseal an existing trusted blob or, for a new key, get a | |
914 | - * random key, then seal and create a trusted key-type key, | |
915 | - * adding it to the specified keyring. | |
916 | - * | |
917 | - * On success, return 0. Otherwise return errno. | |
918 | - */ | |
919 | -static int trusted_instantiate(struct key *key, const void *data, | |
920 | - size_t datalen) | |
921 | -{ | |
922 | - struct trusted_key_payload *payload = NULL; | |
923 | - struct trusted_key_options *options = NULL; | |
924 | - char *datablob; | |
925 | - int ret = 0; | |
926 | - int key_cmd; | |
927 | - | |
928 | - if (datalen <= 0 || datalen > 32767 || !data) | |
929 | - return -EINVAL; | |
930 | - | |
931 | - datablob = kmalloc(datalen + 1, GFP_KERNEL); | |
932 | - if (!datablob) | |
933 | - return -ENOMEM; | |
934 | - memcpy(datablob, data, datalen); | |
935 | - datablob[datalen] = '\0'; | |
936 | - | |
937 | - options = trusted_options_alloc(); | |
938 | - if (!options) { | |
939 | - ret = -ENOMEM; | |
940 | - goto out; | |
941 | - } | |
942 | - payload = trusted_payload_alloc(key); | |
943 | - if (!payload) { | |
944 | - ret = -ENOMEM; | |
945 | - goto out; | |
946 | - } | |
947 | - | |
948 | - key_cmd = datablob_parse(datablob, payload, options); | |
949 | - if (key_cmd < 0) { | |
950 | - ret = key_cmd; | |
951 | - goto out; | |
952 | - } | |
953 | - | |
954 | - dump_payload(payload); | |
955 | - dump_options(options); | |
956 | - | |
957 | - switch (key_cmd) { | |
958 | - case Opt_load: | |
959 | - ret = key_unseal(payload, options); | |
960 | - dump_payload(payload); | |
961 | - dump_options(options); | |
962 | - if (ret < 0) | |
963 | - pr_info("trusted_key: key_unseal failed (%d)\n", ret); | |
964 | - break; | |
965 | - case Opt_new: | |
966 | - ret = my_get_random(payload->key, payload->key_len); | |
967 | - if (ret < 0) { | |
968 | - pr_info("trusted_key: key_create failed (%d)\n", ret); | |
969 | - goto out; | |
970 | - } | |
971 | - ret = key_seal(payload, options); | |
972 | - if (ret < 0) | |
973 | - pr_info("trusted_key: key_seal failed (%d)\n", ret); | |
974 | - break; | |
975 | - default: | |
976 | - ret = -EINVAL; | |
977 | - goto out; | |
978 | - } | |
979 | - if (!ret && options->pcrlock) | |
980 | - ret = pcrlock(options->pcrlock); | |
981 | -out: | |
982 | - kfree(datablob); | |
983 | - kfree(options); | |
984 | - if (!ret) | |
985 | - rcu_assign_pointer(key->payload.data, payload); | |
986 | - else | |
987 | - kfree(payload); | |
988 | - return ret; | |
989 | -} | |
990 | - | |
991 | -static void trusted_rcu_free(struct rcu_head *rcu) | |
992 | -{ | |
993 | - struct trusted_key_payload *p; | |
994 | - | |
995 | - p = container_of(rcu, struct trusted_key_payload, rcu); | |
996 | - memset(p->key, 0, p->key_len); | |
997 | - kfree(p); | |
998 | -} | |
999 | - | |
1000 | -/* | |
1001 | - * trusted_update - reseal an existing key with new PCR values | |
1002 | - */ | |
1003 | -static int trusted_update(struct key *key, const void *data, size_t datalen) | |
1004 | -{ | |
1005 | - struct trusted_key_payload *p = key->payload.data; | |
1006 | - struct trusted_key_payload *new_p; | |
1007 | - struct trusted_key_options *new_o; | |
1008 | - char *datablob; | |
1009 | - int ret = 0; | |
1010 | - | |
1011 | - if (!p->migratable) | |
1012 | - return -EPERM; | |
1013 | - if (datalen <= 0 || datalen > 32767 || !data) | |
1014 | - return -EINVAL; | |
1015 | - | |
1016 | - datablob = kmalloc(datalen + 1, GFP_KERNEL); | |
1017 | - if (!datablob) | |
1018 | - return -ENOMEM; | |
1019 | - new_o = trusted_options_alloc(); | |
1020 | - if (!new_o) { | |
1021 | - ret = -ENOMEM; | |
1022 | - goto out; | |
1023 | - } | |
1024 | - new_p = trusted_payload_alloc(key); | |
1025 | - if (!new_p) { | |
1026 | - ret = -ENOMEM; | |
1027 | - goto out; | |
1028 | - } | |
1029 | - | |
1030 | - memcpy(datablob, data, datalen); | |
1031 | - datablob[datalen] = '\0'; | |
1032 | - ret = datablob_parse(datablob, new_p, new_o); | |
1033 | - if (ret != Opt_update) { | |
1034 | - ret = -EINVAL; | |
1035 | - goto out; | |
1036 | - } | |
1037 | - /* copy old key values, and reseal with new pcrs */ | |
1038 | - new_p->migratable = p->migratable; | |
1039 | - new_p->key_len = p->key_len; | |
1040 | - memcpy(new_p->key, p->key, p->key_len); | |
1041 | - dump_payload(p); | |
1042 | - dump_payload(new_p); | |
1043 | - | |
1044 | - ret = key_seal(new_p, new_o); | |
1045 | - if (ret < 0) { | |
1046 | - pr_info("trusted_key: key_seal failed (%d)\n", ret); | |
1047 | - kfree(new_p); | |
1048 | - goto out; | |
1049 | - } | |
1050 | - if (new_o->pcrlock) { | |
1051 | - ret = pcrlock(new_o->pcrlock); | |
1052 | - if (ret < 0) { | |
1053 | - pr_info("trusted_key: pcrlock failed (%d)\n", ret); | |
1054 | - kfree(new_p); | |
1055 | - goto out; | |
1056 | - } | |
1057 | - } | |
1058 | - rcu_assign_pointer(key->payload.data, new_p); | |
1059 | - call_rcu(&p->rcu, trusted_rcu_free); | |
1060 | -out: | |
1061 | - kfree(datablob); | |
1062 | - kfree(new_o); | |
1063 | - return ret; | |
1064 | -} | |
1065 | - | |
1066 | -/* | |
1067 | - * trusted_read - copy the sealed blob data to userspace in hex. | |
1068 | - * On success, return to userspace the trusted key datablob size. | |
1069 | - */ | |
1070 | -static long trusted_read(const struct key *key, char __user *buffer, | |
1071 | - size_t buflen) | |
1072 | -{ | |
1073 | - struct trusted_key_payload *p; | |
1074 | - char *ascii_buf; | |
1075 | - char *bufp; | |
1076 | - int i; | |
1077 | - | |
1078 | - p = rcu_dereference_protected(key->payload.data, | |
1079 | - rwsem_is_locked(&((struct key *)key)->sem)); | |
1080 | - if (!p) | |
1081 | - return -EINVAL; | |
1082 | - if (!buffer || buflen <= 0) | |
1083 | - return 2 * p->blob_len; | |
1084 | - ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL); | |
1085 | - if (!ascii_buf) | |
1086 | - return -ENOMEM; | |
1087 | - | |
1088 | - bufp = ascii_buf; | |
1089 | - for (i = 0; i < p->blob_len; i++) | |
1090 | - bufp = pack_hex_byte(bufp, p->blob[i]); | |
1091 | - if ((copy_to_user(buffer, ascii_buf, 2 * p->blob_len)) != 0) { | |
1092 | - kfree(ascii_buf); | |
1093 | - return -EFAULT; | |
1094 | - } | |
1095 | - kfree(ascii_buf); | |
1096 | - return 2 * p->blob_len; | |
1097 | -} | |
1098 | - | |
1099 | -/* | |
1100 | - * trusted_destroy - before freeing the key, clear the decrypted data | |
1101 | - */ | |
1102 | -static void trusted_destroy(struct key *key) | |
1103 | -{ | |
1104 | - struct trusted_key_payload *p = key->payload.data; | |
1105 | - | |
1106 | - if (!p) | |
1107 | - return; | |
1108 | - memset(p->key, 0, p->key_len); | |
1109 | - kfree(key->payload.data); | |
1110 | -} | |
1111 | - | |
1112 | -struct key_type key_type_trusted = { | |
1113 | - .name = "trusted", | |
1114 | - .instantiate = trusted_instantiate, | |
1115 | - .update = trusted_update, | |
1116 | - .match = user_match, | |
1117 | - .destroy = trusted_destroy, | |
1118 | - .describe = user_describe, | |
1119 | - .read = trusted_read, | |
1120 | -}; | |
1121 | - | |
1122 | -EXPORT_SYMBOL_GPL(key_type_trusted); | |
1123 | - | |
1124 | -static void trusted_shash_release(void) | |
1125 | -{ | |
1126 | - if (hashalg) | |
1127 | - crypto_free_shash(hashalg); | |
1128 | - if (hmacalg) | |
1129 | - crypto_free_shash(hmacalg); | |
1130 | -} | |
1131 | - | |
1132 | -static int __init trusted_shash_alloc(void) | |
1133 | -{ | |
1134 | - int ret; | |
1135 | - | |
1136 | - hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC); | |
1137 | - if (IS_ERR(hmacalg)) { | |
1138 | - pr_info("trusted_key: could not allocate crypto %s\n", | |
1139 | - hmac_alg); | |
1140 | - return PTR_ERR(hmacalg); | |
1141 | - } | |
1142 | - | |
1143 | - hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); | |
1144 | - if (IS_ERR(hashalg)) { | |
1145 | - pr_info("trusted_key: could not allocate crypto %s\n", | |
1146 | - hash_alg); | |
1147 | - ret = PTR_ERR(hashalg); | |
1148 | - goto hashalg_fail; | |
1149 | - } | |
1150 | - | |
1151 | - return 0; | |
1152 | - | |
1153 | -hashalg_fail: | |
1154 | - crypto_free_shash(hmacalg); | |
1155 | - return ret; | |
1156 | -} | |
1157 | - | |
1158 | -static int __init init_trusted(void) | |
1159 | -{ | |
1160 | - int ret; | |
1161 | - | |
1162 | - ret = trusted_shash_alloc(); | |
1163 | - if (ret < 0) | |
1164 | - return ret; | |
1165 | - ret = register_key_type(&key_type_trusted); | |
1166 | - if (ret < 0) | |
1167 | - trusted_shash_release(); | |
1168 | - return ret; | |
1169 | -} | |
1170 | - | |
1171 | -static void __exit cleanup_trusted(void) | |
1172 | -{ | |
1173 | - trusted_shash_release(); | |
1174 | - unregister_key_type(&key_type_trusted); | |
1175 | -} | |
1176 | - | |
1177 | -late_initcall(init_trusted); | |
1178 | -module_exit(cleanup_trusted); | |
1179 | - | |
1180 | -MODULE_LICENSE("GPL"); |
security/keys/trusted_defined.h
1 | -#ifndef __TRUSTED_KEY_H | |
2 | -#define __TRUSTED_KEY_H | |
3 | - | |
4 | -/* implementation specific TPM constants */ | |
5 | -#define MAX_PCRINFO_SIZE 64 | |
6 | -#define MAX_BUF_SIZE 512 | |
7 | -#define TPM_GETRANDOM_SIZE 14 | |
8 | -#define TPM_OSAP_SIZE 36 | |
9 | -#define TPM_OIAP_SIZE 10 | |
10 | -#define TPM_SEAL_SIZE 87 | |
11 | -#define TPM_UNSEAL_SIZE 104 | |
12 | -#define TPM_SIZE_OFFSET 2 | |
13 | -#define TPM_RETURN_OFFSET 6 | |
14 | -#define TPM_DATA_OFFSET 10 | |
15 | - | |
16 | -#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset])) | |
17 | -#define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) | |
18 | -#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) | |
19 | - | |
20 | -struct tpm_buf { | |
21 | - int len; | |
22 | - unsigned char data[MAX_BUF_SIZE]; | |
23 | -}; | |
24 | - | |
25 | -#define INIT_BUF(tb) (tb->len = 0) | |
26 | - | |
27 | -struct osapsess { | |
28 | - uint32_t handle; | |
29 | - unsigned char secret[SHA1_DIGEST_SIZE]; | |
30 | - unsigned char enonce[TPM_NONCE_SIZE]; | |
31 | -}; | |
32 | - | |
33 | -/* discrete values, but have to store in uint16_t for TPM use */ | |
34 | -enum { | |
35 | - SEAL_keytype = 1, | |
36 | - SRK_keytype = 4 | |
37 | -}; | |
38 | - | |
39 | -struct trusted_key_options { | |
40 | - uint16_t keytype; | |
41 | - uint32_t keyhandle; | |
42 | - unsigned char keyauth[SHA1_DIGEST_SIZE]; | |
43 | - unsigned char blobauth[SHA1_DIGEST_SIZE]; | |
44 | - uint32_t pcrinfo_len; | |
45 | - unsigned char pcrinfo[MAX_PCRINFO_SIZE]; | |
46 | - int pcrlock; | |
47 | -}; | |
48 | - | |
49 | -#define TPM_DEBUG 0 | |
50 | - | |
51 | -#if TPM_DEBUG | |
52 | -static inline void dump_options(struct trusted_key_options *o) | |
53 | -{ | |
54 | - pr_info("trusted_key: sealing key type %d\n", o->keytype); | |
55 | - pr_info("trusted_key: sealing key handle %0X\n", o->keyhandle); | |
56 | - pr_info("trusted_key: pcrlock %d\n", o->pcrlock); | |
57 | - pr_info("trusted_key: pcrinfo %d\n", o->pcrinfo_len); | |
58 | - print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE, | |
59 | - 16, 1, o->pcrinfo, o->pcrinfo_len, 0); | |
60 | -} | |
61 | - | |
62 | -static inline void dump_payload(struct trusted_key_payload *p) | |
63 | -{ | |
64 | - pr_info("trusted_key: key_len %d\n", p->key_len); | |
65 | - print_hex_dump(KERN_INFO, "key ", DUMP_PREFIX_NONE, | |
66 | - 16, 1, p->key, p->key_len, 0); | |
67 | - pr_info("trusted_key: bloblen %d\n", p->blob_len); | |
68 | - print_hex_dump(KERN_INFO, "blob ", DUMP_PREFIX_NONE, | |
69 | - 16, 1, p->blob, p->blob_len, 0); | |
70 | - pr_info("trusted_key: migratable %d\n", p->migratable); | |
71 | -} | |
72 | - | |
73 | -static inline void dump_sess(struct osapsess *s) | |
74 | -{ | |
75 | - print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE, | |
76 | - 16, 1, &s->handle, 4, 0); | |
77 | - pr_info("trusted-key: secret:\n"); | |
78 | - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, | |
79 | - 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0); | |
80 | - pr_info("trusted-key: enonce:\n"); | |
81 | - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, | |
82 | - 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0); | |
83 | -} | |
84 | - | |
85 | -static inline void dump_tpm_buf(unsigned char *buf) | |
86 | -{ | |
87 | - int len; | |
88 | - | |
89 | - pr_info("\ntrusted-key: tpm buffer\n"); | |
90 | - len = LOAD32(buf, TPM_SIZE_OFFSET); | |
91 | - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0); | |
92 | -} | |
93 | -#else | |
94 | -static inline void dump_options(struct trusted_key_options *o) | |
95 | -{ | |
96 | -} | |
97 | - | |
98 | -static inline void dump_payload(struct trusted_key_payload *p) | |
99 | -{ | |
100 | -} | |
101 | - | |
102 | -static inline void dump_sess(struct osapsess *s) | |
103 | -{ | |
104 | -} | |
105 | - | |
106 | -static inline void dump_tpm_buf(unsigned char *buf) | |
107 | -{ | |
108 | -} | |
109 | -#endif | |
110 | - | |
111 | -static inline void store8(struct tpm_buf *buf, const unsigned char value) | |
112 | -{ | |
113 | - buf->data[buf->len++] = value; | |
114 | -} | |
115 | - | |
116 | -static inline void store16(struct tpm_buf *buf, const uint16_t value) | |
117 | -{ | |
118 | - *(uint16_t *) & buf->data[buf->len] = htons(value); | |
119 | - buf->len += sizeof value; | |
120 | -} | |
121 | - | |
122 | -static inline void store32(struct tpm_buf *buf, const uint32_t value) | |
123 | -{ | |
124 | - *(uint32_t *) & buf->data[buf->len] = htonl(value); | |
125 | - buf->len += sizeof value; | |
126 | -} | |
127 | - | |
128 | -static inline void storebytes(struct tpm_buf *buf, const unsigned char *in, | |
129 | - const int len) | |
130 | -{ | |
131 | - memcpy(buf->data + buf->len, in, len); | |
132 | - buf->len += len; | |
133 | -} | |
134 | -#endif |