diff options
-rw-r--r-- | drivers/char/tpm/tpm.c | 59 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 23 | ||||
-rw-r--r-- | include/linux/tpm.h | 4 | ||||
-rw-r--r-- | security/keys/trusted.c | 54 |
4 files changed, 92 insertions, 48 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 677c6e26593f..36e43e50dcef 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -32,12 +32,6 @@ | |||
32 | #include "tpm.h" | 32 | #include "tpm.h" |
33 | #include "tpm_eventlog.h" | 33 | #include "tpm_eventlog.h" |
34 | 34 | ||
35 | enum tpm_const { | ||
36 | TPM_MINOR = 224, /* officially assigned */ | ||
37 | TPM_BUFSIZE = 4096, | ||
38 | TPM_NUM_DEVICES = 256, | ||
39 | }; | ||
40 | |||
41 | enum tpm_duration { | 35 | enum tpm_duration { |
42 | TPM_SHORT = 0, | 36 | TPM_SHORT = 0, |
43 | TPM_MEDIUM = 1, | 37 | TPM_MEDIUM = 1, |
@@ -483,6 +477,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, | |||
483 | #define TPM_INTERNAL_RESULT_SIZE 200 | 477 | #define TPM_INTERNAL_RESULT_SIZE 200 |
484 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) | 478 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) |
485 | #define TPM_ORD_GET_CAP cpu_to_be32(101) | 479 | #define TPM_ORD_GET_CAP cpu_to_be32(101) |
480 | #define TPM_ORD_GET_RANDOM cpu_to_be32(70) | ||
486 | 481 | ||
487 | static const struct tpm_input_header tpm_getcap_header = { | 482 | static const struct tpm_input_header tpm_getcap_header = { |
488 | .tag = TPM_TAG_RQU_COMMAND, | 483 | .tag = TPM_TAG_RQU_COMMAND, |
@@ -1327,6 +1322,58 @@ int tpm_pm_resume(struct device *dev) | |||
1327 | } | 1322 | } |
1328 | EXPORT_SYMBOL_GPL(tpm_pm_resume); | 1323 | EXPORT_SYMBOL_GPL(tpm_pm_resume); |
1329 | 1324 | ||
1325 | #define TPM_GETRANDOM_RESULT_SIZE 18 | ||
1326 | static struct tpm_input_header tpm_getrandom_header = { | ||
1327 | .tag = TPM_TAG_RQU_COMMAND, | ||
1328 | .length = cpu_to_be32(14), | ||
1329 | .ordinal = TPM_ORD_GET_RANDOM | ||
1330 | }; | ||
1331 | |||
1332 | /** | ||
1333 | * tpm_get_random() - Get random bytes from the tpm's RNG | ||
1334 | * @chip_num: A specific chip number for the request or TPM_ANY_NUM | ||
1335 | * @out: destination buffer for the random bytes | ||
1336 | * @max: the max number of bytes to write to @out | ||
1337 | * | ||
1338 | * Returns < 0 on error and the number of bytes read on success | ||
1339 | */ | ||
1340 | int tpm_get_random(u32 chip_num, u8 *out, size_t max) | ||
1341 | { | ||
1342 | struct tpm_chip *chip; | ||
1343 | struct tpm_cmd_t tpm_cmd; | ||
1344 | u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA); | ||
1345 | int err, total = 0, retries = 5; | ||
1346 | u8 *dest = out; | ||
1347 | |||
1348 | chip = tpm_chip_find_get(chip_num); | ||
1349 | if (chip == NULL) | ||
1350 | return -ENODEV; | ||
1351 | |||
1352 | if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) | ||
1353 | return -EINVAL; | ||
1354 | |||
1355 | do { | ||
1356 | tpm_cmd.header.in = tpm_getrandom_header; | ||
1357 | tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); | ||
1358 | |||
1359 | err = transmit_cmd(chip, &tpm_cmd, | ||
1360 | TPM_GETRANDOM_RESULT_SIZE + num_bytes, | ||
1361 | "attempting get random"); | ||
1362 | if (err) | ||
1363 | break; | ||
1364 | |||
1365 | recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); | ||
1366 | memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd); | ||
1367 | |||
1368 | dest += recd; | ||
1369 | total += recd; | ||
1370 | num_bytes -= recd; | ||
1371 | } while (retries-- && total < max); | ||
1372 | |||
1373 | return total ? total : -EIO; | ||
1374 | } | ||
1375 | EXPORT_SYMBOL_GPL(tpm_get_random); | ||
1376 | |||
1330 | /* In case vendor provided release function, call it too.*/ | 1377 | /* In case vendor provided release function, call it too.*/ |
1331 | 1378 | ||
1332 | void tpm_dev_vendor_release(struct tpm_chip *chip) | 1379 | void tpm_dev_vendor_release(struct tpm_chip *chip) |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 917f727e6740..645136eea890 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -28,6 +28,12 @@ | |||
28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
29 | #include <linux/tpm.h> | 29 | #include <linux/tpm.h> |
30 | 30 | ||
31 | enum tpm_const { | ||
32 | TPM_MINOR = 224, /* officially assigned */ | ||
33 | TPM_BUFSIZE = 4096, | ||
34 | TPM_NUM_DEVICES = 256, | ||
35 | }; | ||
36 | |||
31 | enum tpm_timeout { | 37 | enum tpm_timeout { |
32 | TPM_TIMEOUT = 5, /* msecs */ | 38 | TPM_TIMEOUT = 5, /* msecs */ |
33 | }; | 39 | }; |
@@ -269,6 +275,21 @@ struct tpm_pcrextend_in { | |||
269 | u8 hash[TPM_DIGEST_SIZE]; | 275 | u8 hash[TPM_DIGEST_SIZE]; |
270 | }__attribute__((packed)); | 276 | }__attribute__((packed)); |
271 | 277 | ||
278 | /* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18 | ||
279 | * bytes, but 128 is still a relatively large number of random bytes and | ||
280 | * anything much bigger causes users of struct tpm_cmd_t to start getting | ||
281 | * compiler warnings about stack frame size. */ | ||
282 | #define TPM_MAX_RNG_DATA 128 | ||
283 | |||
284 | struct tpm_getrandom_out { | ||
285 | __be32 rng_data_len; | ||
286 | u8 rng_data[TPM_MAX_RNG_DATA]; | ||
287 | }__attribute__((packed)); | ||
288 | |||
289 | struct tpm_getrandom_in { | ||
290 | __be32 num_bytes; | ||
291 | }__attribute__((packed)); | ||
292 | |||
272 | typedef union { | 293 | typedef union { |
273 | struct tpm_getcap_params_out getcap_out; | 294 | struct tpm_getcap_params_out getcap_out; |
274 | struct tpm_readpubek_params_out readpubek_out; | 295 | struct tpm_readpubek_params_out readpubek_out; |
@@ -277,6 +298,8 @@ typedef union { | |||
277 | struct tpm_pcrread_in pcrread_in; | 298 | struct tpm_pcrread_in pcrread_in; |
278 | struct tpm_pcrread_out pcrread_out; | 299 | struct tpm_pcrread_out pcrread_out; |
279 | struct tpm_pcrextend_in pcrextend_in; | 300 | struct tpm_pcrextend_in pcrextend_in; |
301 | struct tpm_getrandom_in getrandom_in; | ||
302 | struct tpm_getrandom_out getrandom_out; | ||
280 | } tpm_cmd_params; | 303 | } tpm_cmd_params; |
281 | 304 | ||
282 | struct tpm_cmd_t { | 305 | struct tpm_cmd_t { |
diff --git a/include/linux/tpm.h b/include/linux/tpm.h index fdc718abf83b..fcb627ff8d3e 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h | |||
@@ -32,6 +32,7 @@ | |||
32 | extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); | 32 | extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); |
33 | extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); | 33 | extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); |
34 | extern int tpm_send(u32 chip_num, void *cmd, size_t buflen); | 34 | extern int tpm_send(u32 chip_num, void *cmd, size_t buflen); |
35 | extern int tpm_get_random(u32 chip_num, u8 *data, size_t max); | ||
35 | #else | 36 | #else |
36 | static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { | 37 | static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { |
37 | return -ENODEV; | 38 | return -ENODEV; |
@@ -42,5 +43,8 @@ static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) { | |||
42 | static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) { | 43 | static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) { |
43 | return -ENODEV; | 44 | return -ENODEV; |
44 | } | 45 | } |
46 | static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) { | ||
47 | return -ENODEV; | ||
48 | } | ||
45 | #endif | 49 | #endif |
46 | #endif | 50 | #endif |
diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 2d5d041f2049..3f163d0489ad 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c | |||
@@ -369,38 +369,6 @@ static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd, | |||
369 | } | 369 | } |
370 | 370 | ||
371 | /* | 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. | 372 | * Lock a trusted key, by extending a selected PCR. |
405 | * | 373 | * |
406 | * Prevents a trusted key that is sealed to PCRs from being accessed. | 374 | * Prevents a trusted key that is sealed to PCRs from being accessed. |
@@ -413,8 +381,8 @@ static int pcrlock(const int pcrnum) | |||
413 | 381 | ||
414 | if (!capable(CAP_SYS_ADMIN)) | 382 | if (!capable(CAP_SYS_ADMIN)) |
415 | return -EPERM; | 383 | return -EPERM; |
416 | ret = my_get_random(hash, SHA1_DIGEST_SIZE); | 384 | ret = tpm_get_random(TPM_ANY_NUM, hash, SHA1_DIGEST_SIZE); |
417 | if (ret < 0) | 385 | if (ret != SHA1_DIGEST_SIZE) |
418 | return ret; | 386 | return ret; |
419 | return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0; | 387 | return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0; |
420 | } | 388 | } |
@@ -429,8 +397,8 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, | |||
429 | unsigned char ononce[TPM_NONCE_SIZE]; | 397 | unsigned char ononce[TPM_NONCE_SIZE]; |
430 | int ret; | 398 | int ret; |
431 | 399 | ||
432 | ret = tpm_get_random(tb, ononce, TPM_NONCE_SIZE); | 400 | ret = tpm_get_random(TPM_ANY_NUM, ononce, TPM_NONCE_SIZE); |
433 | if (ret < 0) | 401 | if (ret != TPM_NONCE_SIZE) |
434 | return ret; | 402 | return ret; |
435 | 403 | ||
436 | INIT_BUF(tb); | 404 | INIT_BUF(tb); |
@@ -524,8 +492,8 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, | |||
524 | if (ret < 0) | 492 | if (ret < 0) |
525 | goto out; | 493 | goto out; |
526 | 494 | ||
527 | ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE); | 495 | ret = tpm_get_random(TPM_ANY_NUM, td->nonceodd, TPM_NONCE_SIZE); |
528 | if (ret < 0) | 496 | if (ret != TPM_NONCE_SIZE) |
529 | goto out; | 497 | goto out; |
530 | ordinal = htonl(TPM_ORD_SEAL); | 498 | ordinal = htonl(TPM_ORD_SEAL); |
531 | datsize = htonl(datalen); | 499 | datsize = htonl(datalen); |
@@ -634,8 +602,8 @@ static int tpm_unseal(struct tpm_buf *tb, | |||
634 | 602 | ||
635 | ordinal = htonl(TPM_ORD_UNSEAL); | 603 | ordinal = htonl(TPM_ORD_UNSEAL); |
636 | keyhndl = htonl(SRKHANDLE); | 604 | keyhndl = htonl(SRKHANDLE); |
637 | ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE); | 605 | ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE); |
638 | if (ret < 0) { | 606 | if (ret != TPM_NONCE_SIZE) { |
639 | pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); | 607 | pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); |
640 | return ret; | 608 | return ret; |
641 | } | 609 | } |
@@ -935,6 +903,7 @@ static int trusted_instantiate(struct key *key, const void *data, | |||
935 | char *datablob; | 903 | char *datablob; |
936 | int ret = 0; | 904 | int ret = 0; |
937 | int key_cmd; | 905 | int key_cmd; |
906 | size_t key_len; | ||
938 | 907 | ||
939 | if (datalen <= 0 || datalen > 32767 || !data) | 908 | if (datalen <= 0 || datalen > 32767 || !data) |
940 | return -EINVAL; | 909 | return -EINVAL; |
@@ -974,8 +943,9 @@ static int trusted_instantiate(struct key *key, const void *data, | |||
974 | pr_info("trusted_key: key_unseal failed (%d)\n", ret); | 943 | pr_info("trusted_key: key_unseal failed (%d)\n", ret); |
975 | break; | 944 | break; |
976 | case Opt_new: | 945 | case Opt_new: |
977 | ret = my_get_random(payload->key, payload->key_len); | 946 | key_len = payload->key_len; |
978 | if (ret < 0) { | 947 | ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len); |
948 | if (ret != key_len) { | ||
979 | pr_info("trusted_key: key_create failed (%d)\n", ret); | 949 | pr_info("trusted_key: key_create failed (%d)\n", ret); |
980 | goto out; | 950 | goto out; |
981 | } | 951 | } |