diff options
| author | Mimi Zohar <zohar@linux.vnet.ibm.com> | 2010-11-23 17:50:34 -0500 |
|---|---|---|
| committer | James Morris <jmorris@namei.org> | 2010-11-28 16:55:25 -0500 |
| commit | d00a1c72f7f4661212299e6cb132dfa58030bcdb (patch) | |
| tree | 2c873e461f42bbf3aea03b7b2e59cea8f941d841 /security/keys | |
| parent | c749ba912e87ccebd674ae24b97462176c63732e (diff) | |
keys: add new trusted key-type
Define a new kernel key-type called 'trusted'. Trusted keys are random
number symmetric keys, generated and RSA-sealed by the TPM. The TPM
only unseals the keys, if the boot PCRs and other criteria match.
Userspace can only ever see encrypted blobs.
Based on suggestions by Jason Gunthorpe, several new options have been
added to support additional usages.
The new options are:
migratable= designates that the key may/may not ever be updated
(resealed under a new key, new pcrinfo or new auth.)
pcrlock=n extends the designated PCR 'n' with a random value,
so that a key sealed to that PCR may not be unsealed
again until after a reboot.
keyhandle= specifies the sealing/unsealing key handle.
keyauth= specifies the sealing/unsealing key auth.
blobauth= specifies the sealed data auth.
Implementation of a kernel reserved locality for trusted keys will be
investigated for a possible future extension.
Changelog:
- Updated and added examples to Documentation/keys-trusted-encrypted.txt
- Moved generic TPM constants to include/linux/tpm_command.h
(David Howell's suggestion.)
- trusted_defined.c: replaced kzalloc with kmalloc, added pcrlock failure
error handling, added const qualifiers where appropriate.
- moved to late_initcall
- updated from hash to shash (suggestion by David Howells)
- reduced worst stack usage (tpm_seal) from 530 to 312 bytes
- moved documentation to Documentation directory (suggestion by David Howells)
- all the other code cleanups suggested by David Howells
- Add pcrlock CAP_SYS_ADMIN dependency (based on comment by Jason Gunthorpe)
- New options: migratable, pcrlock, keyhandle, keyauth, blobauth (based on
discussions with Jason Gunthorpe)
- Free payload on failure to create key(reported/fixed by Roberto Sassu)
- Updated Kconfig and other descriptions (based on Serge Hallyn's suggestion)
- Replaced kzalloc() with kmalloc() (reported by Serge Hallyn)
Signed-off-by: David Safford <safford@watson.ibm.com>
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/keys')
| -rw-r--r-- | security/keys/Makefile | 1 | ||||
| -rw-r--r-- | security/keys/trusted_defined.c | 1151 | ||||
| -rw-r--r-- | security/keys/trusted_defined.h | 134 |
3 files changed, 1286 insertions, 0 deletions
diff --git a/security/keys/Makefile b/security/keys/Makefile index 74d5447d7df7..fcb107020b4a 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
| @@ -13,6 +13,7 @@ obj-y := \ | |||
| 13 | request_key_auth.o \ | 13 | request_key_auth.o \ |
| 14 | user_defined.o | 14 | user_defined.o |
| 15 | 15 | ||
| 16 | obj-$(CONFIG_TRUSTED_KEYS) += trusted_defined.o | ||
| 16 | obj-$(CONFIG_KEYS_COMPAT) += compat.o | 17 | obj-$(CONFIG_KEYS_COMPAT) += compat.o |
| 17 | obj-$(CONFIG_PROC_FS) += proc.o | 18 | obj-$(CONFIG_PROC_FS) += proc.o |
| 18 | obj-$(CONFIG_SYSCTL) += sysctl.o | 19 | obj-$(CONFIG_SYSCTL) += sysctl.o |
diff --git a/security/keys/trusted_defined.c b/security/keys/trusted_defined.c new file mode 100644 index 000000000000..1bec72e7596d --- /dev/null +++ b/security/keys/trusted_defined.c | |||
| @@ -0,0 +1,1151 @@ | |||
| 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 <keys/user-type.h> | ||
| 21 | #include <keys/trusted-type.h> | ||
| 22 | #include <linux/key-type.h> | ||
| 23 | #include <linux/rcupdate.h> | ||
| 24 | #include <linux/crypto.h> | ||
| 25 | #include <crypto/hash.h> | ||
| 26 | #include <crypto/sha.h> | ||
| 27 | #include <linux/capability.h> | ||
| 28 | #include <linux/tpm.h> | ||
| 29 | #include <linux/tpm_command.h> | ||
| 30 | |||
| 31 | #include "trusted_defined.h" | ||
| 32 | |||
| 33 | static const char hmac_alg[] = "hmac(sha1)"; | ||
| 34 | static const char hash_alg[] = "sha1"; | ||
| 35 | |||
| 36 | struct sdesc { | ||
| 37 | struct shash_desc shash; | ||
| 38 | char ctx[]; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static struct crypto_shash *hashalg; | ||
| 42 | static struct crypto_shash *hmacalg; | ||
| 43 | |||
| 44 | static struct sdesc *init_sdesc(struct crypto_shash *alg) | ||
| 45 | { | ||
| 46 | struct sdesc *sdesc; | ||
| 47 | int size; | ||
| 48 | |||
| 49 | size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); | ||
| 50 | sdesc = kmalloc(size, GFP_KERNEL); | ||
| 51 | if (!sdesc) | ||
| 52 | return ERR_PTR(-ENOMEM); | ||
| 53 | sdesc->shash.tfm = alg; | ||
| 54 | sdesc->shash.flags = 0x0; | ||
| 55 | return sdesc; | ||
| 56 | } | ||
| 57 | |||
| 58 | static int TSS_sha1(const unsigned char *data, const unsigned int datalen, | ||
| 59 | unsigned char *digest) | ||
| 60 | { | ||
| 61 | struct sdesc *sdesc; | ||
| 62 | int ret; | ||
| 63 | |||
| 64 | sdesc = init_sdesc(hashalg); | ||
| 65 | if (IS_ERR(sdesc)) { | ||
| 66 | pr_info("trusted_key: can't alloc %s\n", hash_alg); | ||
| 67 | return PTR_ERR(sdesc); | ||
| 68 | } | ||
| 69 | |||
| 70 | ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest); | ||
| 71 | kfree(sdesc); | ||
| 72 | return ret; | ||
| 73 | } | ||
| 74 | |||
| 75 | static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, | ||
| 76 | const unsigned int keylen, ...) | ||
| 77 | { | ||
| 78 | struct sdesc *sdesc; | ||
| 79 | va_list argp; | ||
| 80 | unsigned int dlen; | ||
| 81 | unsigned char *data; | ||
| 82 | int ret; | ||
| 83 | |||
| 84 | sdesc = init_sdesc(hmacalg); | ||
| 85 | if (IS_ERR(sdesc)) { | ||
| 86 | pr_info("trusted_key: can't alloc %s\n", hmac_alg); | ||
| 87 | return PTR_ERR(sdesc); | ||
| 88 | } | ||
| 89 | |||
| 90 | ret = crypto_shash_setkey(hmacalg, key, keylen); | ||
| 91 | if (ret < 0) | ||
| 92 | goto out; | ||
| 93 | ret = crypto_shash_init(&sdesc->shash); | ||
| 94 | if (ret < 0) | ||
| 95 | goto out; | ||
| 96 | |||
| 97 | va_start(argp, keylen); | ||
| 98 | for (;;) { | ||
| 99 | dlen = va_arg(argp, unsigned int); | ||
| 100 | if (dlen == 0) | ||
| 101 | break; | ||
| 102 | data = va_arg(argp, unsigned char *); | ||
| 103 | if (data == NULL) | ||
| 104 | return -EINVAL; | ||
| 105 | ret = crypto_shash_update(&sdesc->shash, data, dlen); | ||
| 106 | if (ret < 0) | ||
| 107 | goto out; | ||
| 108 | } | ||
| 109 | va_end(argp); | ||
| 110 | ret = crypto_shash_final(&sdesc->shash, digest); | ||
| 111 | out: | ||
| 112 | kfree(sdesc); | ||
| 113 | return ret; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* | ||
| 117 | * calculate authorization info fields to send to TPM | ||
| 118 | */ | ||
| 119 | static uint32_t TSS_authhmac(unsigned char *digest, const unsigned char *key, | ||
| 120 | const unsigned int keylen, unsigned char *h1, | ||
| 121 | unsigned char *h2, unsigned char h3, ...) | ||
| 122 | { | ||
| 123 | unsigned char paramdigest[SHA1_DIGEST_SIZE]; | ||
| 124 | struct sdesc *sdesc; | ||
| 125 | unsigned int dlen; | ||
| 126 | unsigned char *data; | ||
| 127 | unsigned char c; | ||
| 128 | int ret; | ||
| 129 | va_list argp; | ||
| 130 | |||
| 131 | sdesc = init_sdesc(hashalg); | ||
| 132 | if (IS_ERR(sdesc)) { | ||
| 133 | pr_info("trusted_key: can't alloc %s\n", hash_alg); | ||
| 134 | return PTR_ERR(sdesc); | ||
| 135 | } | ||
| 136 | |||
| 137 | c = h3; | ||
| 138 | ret = crypto_shash_init(&sdesc->shash); | ||
| 139 | if (ret < 0) | ||
| 140 | goto out; | ||
| 141 | va_start(argp, h3); | ||
| 142 | for (;;) { | ||
| 143 | dlen = va_arg(argp, unsigned int); | ||
| 144 | if (dlen == 0) | ||
| 145 | break; | ||
| 146 | data = va_arg(argp, unsigned char *); | ||
| 147 | ret = crypto_shash_update(&sdesc->shash, data, dlen); | ||
| 148 | if (ret < 0) | ||
| 149 | goto out; | ||
| 150 | } | ||
| 151 | va_end(argp); | ||
| 152 | ret = crypto_shash_final(&sdesc->shash, paramdigest); | ||
| 153 | if (!ret) | ||
| 154 | TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE, | ||
| 155 | paramdigest, TPM_NONCE_SIZE, h1, | ||
| 156 | TPM_NONCE_SIZE, h2, 1, &c, 0, 0); | ||
| 157 | out: | ||
| 158 | kfree(sdesc); | ||
| 159 | return ret; | ||
| 160 | } | ||
| 161 | |||
| 162 | /* | ||
| 163 | * verify the AUTH1_COMMAND (Seal) result from TPM | ||
| 164 | */ | ||
| 165 | static uint32_t TSS_checkhmac1(unsigned char *buffer, | ||
| 166 | const uint32_t command, | ||
| 167 | const unsigned char *ononce, | ||
| 168 | const unsigned char *key, | ||
| 169 | const unsigned int keylen, ...) | ||
| 170 | { | ||
| 171 | uint32_t bufsize; | ||
| 172 | uint16_t tag; | ||
| 173 | uin | ||
