Skip to content

Commit 41ab999

Browse files
author
Kent Yoder
committed
tpm: Move tpm_get_random api into the TPM device driver
Move the tpm_get_random api from the trusted keys code into the TPM device driver itself so that other callers can make use of it. Also, change the api slightly so that the number of bytes read is returned in the call, since the TPM command can potentially return fewer bytes than requested. Acked-by: David Safford <safford@linux.vnet.ibm.com> Reviewed-by: H. Peter Anvin <hpa@linux.intel.com> Signed-off-by: Kent Yoder <key@linux.vnet.ibm.com>
1 parent e5dcd87 commit 41ab999

File tree

4 files changed

+92
-48
lines changed

4 files changed

+92
-48
lines changed

drivers/char/tpm/tpm.c

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,6 @@
3232
#include "tpm.h"
3333
#include "tpm_eventlog.h"
3434

35-
enum tpm_const {
36-
TPM_MINOR = 224, /* officially assigned */
37-
TPM_BUFSIZE = 4096,
38-
TPM_NUM_DEVICES = 256,
39-
};
40-
4135
enum tpm_duration {
4236
TPM_SHORT = 0,
4337
TPM_MEDIUM = 1,
@@ -483,6 +477,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
483477
#define TPM_INTERNAL_RESULT_SIZE 200
484478
#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
485479
#define TPM_ORD_GET_CAP cpu_to_be32(101)
480+
#define TPM_ORD_GET_RANDOM cpu_to_be32(70)
486481

487482
static const struct tpm_input_header tpm_getcap_header = {
488483
.tag = TPM_TAG_RQU_COMMAND,
@@ -1327,6 +1322,58 @@ int tpm_pm_resume(struct device *dev)
13271322
}
13281323
EXPORT_SYMBOL_GPL(tpm_pm_resume);
13291324

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+
13301377
/* In case vendor provided release function, call it too.*/
13311378

13321379
void tpm_dev_vendor_release(struct tpm_chip *chip)

drivers/char/tpm/tpm.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@
2828
#include <linux/io.h>
2929
#include <linux/tpm.h>
3030

31+
enum tpm_const {
32+
TPM_MINOR = 224, /* officially assigned */
33+
TPM_BUFSIZE = 4096,
34+
TPM_NUM_DEVICES = 256,
35+
};
36+
3137
enum tpm_timeout {
3238
TPM_TIMEOUT = 5, /* msecs */
3339
};
@@ -269,6 +275,21 @@ struct tpm_pcrextend_in {
269275
u8 hash[TPM_DIGEST_SIZE];
270276
}__attribute__((packed));
271277

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+
272293
typedef union {
273294
struct tpm_getcap_params_out getcap_out;
274295
struct tpm_readpubek_params_out readpubek_out;
@@ -277,6 +298,8 @@ typedef union {
277298
struct tpm_pcrread_in pcrread_in;
278299
struct tpm_pcrread_out pcrread_out;
279300
struct tpm_pcrextend_in pcrextend_in;
301+
struct tpm_getrandom_in getrandom_in;
302+
struct tpm_getrandom_out getrandom_out;
280303
} tpm_cmd_params;
281304

282305
struct tpm_cmd_t {

include/linux/tpm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
3333
extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
3434
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);
3536
#else
3637
static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
3738
return -ENODEV;
@@ -42,5 +43,8 @@ static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) {
4243
static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) {
4344
return -ENODEV;
4445
}
46+
static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) {
47+
return -ENODEV;
48+
}
4549
#endif
4650
#endif

security/keys/trusted.c

Lines changed: 12 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -368,38 +368,6 @@ static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd,
368368
return rc;
369369
}
370370

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-
403371
/*
404372
* Lock a trusted key, by extending a selected PCR.
405373
*
@@ -413,8 +381,8 @@ static int pcrlock(const int pcrnum)
413381

414382
if (!capable(CAP_SYS_ADMIN))
415383
return -EPERM;
416-
ret = my_get_random(hash, SHA1_DIGEST_SIZE);
417-
if (ret < 0)
384+
ret = tpm_get_random(TPM_ANY_NUM, hash, SHA1_DIGEST_SIZE);
385+
if (ret != SHA1_DIGEST_SIZE)
418386
return ret;
419387
return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0;
420388
}
@@ -429,8 +397,8 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
429397
unsigned char ononce[TPM_NONCE_SIZE];
430398
int ret;
431399

432-
ret = tpm_get_random(tb, ononce, TPM_NONCE_SIZE);
433-
if (ret < 0)
400+
ret = tpm_get_random(TPM_ANY_NUM, ononce, TPM_NONCE_SIZE);
401+
if (ret != TPM_NONCE_SIZE)
434402
return ret;
435403

436404
INIT_BUF(tb);
@@ -524,8 +492,8 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
524492
if (ret < 0)
525493
goto out;
526494

527-
ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE);
528-
if (ret < 0)
495+
ret = tpm_get_random(TPM_ANY_NUM, td->nonceodd, TPM_NONCE_SIZE);
496+
if (ret != TPM_NONCE_SIZE)
529497
goto out;
530498
ordinal = htonl(TPM_ORD_SEAL);
531499
datsize = htonl(datalen);
@@ -634,8 +602,8 @@ static int tpm_unseal(struct tpm_buf *tb,
634602

635603
ordinal = htonl(TPM_ORD_UNSEAL);
636604
keyhndl = htonl(SRKHANDLE);
637-
ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE);
638-
if (ret < 0) {
605+
ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE);
606+
if (ret != TPM_NONCE_SIZE) {
639607
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
640608
return ret;
641609
}
@@ -935,6 +903,7 @@ static int trusted_instantiate(struct key *key, const void *data,
935903
char *datablob;
936904
int ret = 0;
937905
int key_cmd;
906+
size_t key_len;
938907

939908
if (datalen <= 0 || datalen > 32767 || !data)
940909
return -EINVAL;
@@ -974,8 +943,9 @@ static int trusted_instantiate(struct key *key, const void *data,
974943
pr_info("trusted_key: key_unseal failed (%d)\n", ret);
975944
break;
976945
case Opt_new:
977-
ret = my_get_random(payload->key, payload->key_len);
978-
if (ret < 0) {
946+
key_len = payload->key_len;
947+
ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len);
948+
if (ret != key_len) {
979949
pr_info("trusted_key: key_create failed (%d)\n", ret);
980950
goto out;
981951
}

0 commit comments

Comments
 (0)