keys, trusted: select hash algorithm for TPM2 chips
authorJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Thu, 5 Nov 2015 19:43:06 +0000 (21:43 +0200)
committerJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Sun, 20 Dec 2015 13:27:12 +0000 (15:27 +0200)
Added 'hash=' option for selecting the hash algorithm for add_key()
syscall and documentation for it.

Added entry for sm3-256 to the following tables in order to support
TPM_ALG_SM3_256:

* hash_algo_name
* hash_digest_size

Includes support for the following hash algorithms:

* sha1
* sha256
* sha384
* sha512
* sm3-256

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: Colin Ian King <colin.king@canonical.com>
Reviewed-by: James Morris <james.l.morris@oracle.com>
Reviewed-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Acked-by: Peter Huewe <peterhuewe@gmx.de>
Documentation/security/keys-trusted-encrypted.txt
crypto/hash_info.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm2-cmd.c
include/crypto/hash_info.h
include/keys/trusted-type.h
include/uapi/linux/hash_info.h
security/keys/Kconfig
security/keys/trusted.c

index e105ae97a4f5c0ff71387a5a895c7c4872e07afa..fd2565b301e87eaab6cc5ea4b08ddb4debbd8b94 100644 (file)
@@ -38,6 +38,9 @@ Usage:
        pcrlock=          pcr number to be extended to "lock" blob
        migratable= 0|1 indicating permission to reseal to new PCR values,
                    default 1 (resealing allowed)
+       hash=      hash algorithm name as a string. For TPM 1.x the only
+                  allowed value is sha1. For TPM 2.x the allowed values
+                 are sha1, sha256, sha384, sha512 and sm3-256.
 
 "keyctl print" returns an ascii hex copy of the sealed key, which is in standard
 TPM_STORED_DATA format.  The key length for new keys are always in bytes.
index 3e7ff46f26e8018d6a964c2722d2d451f8c3146c..7b1e0b188ce6a9caa32d4c903219c0b6fb0f9ee4 100644 (file)
@@ -31,6 +31,7 @@ const char *const hash_algo_name[HASH_ALGO__LAST] = {
        [HASH_ALGO_TGR_128]     = "tgr128",
        [HASH_ALGO_TGR_160]     = "tgr160",
        [HASH_ALGO_TGR_192]     = "tgr192",
+       [HASH_ALGO_SM3_256]     = "sm3-256",
 };
 EXPORT_SYMBOL_GPL(hash_algo_name);
 
@@ -52,5 +53,6 @@ const int hash_digest_size[HASH_ALGO__LAST] = {
        [HASH_ALGO_TGR_128]     = TGR128_DIGEST_SIZE,
        [HASH_ALGO_TGR_160]     = TGR160_DIGEST_SIZE,
        [HASH_ALGO_TGR_192]     = TGR192_DIGEST_SIZE,
+       [HASH_ALGO_SM3_256]     = SM3256_DIGEST_SIZE,
 };
 EXPORT_SYMBOL_GPL(hash_digest_size);
index 347fc615bcc9738ab08a0d7e14c7aded3b2c42fd..542a80cbfd9cf054278dff185166161ec429db96 100644 (file)
@@ -83,16 +83,20 @@ enum tpm2_structures {
 };
 
 enum tpm2_return_codes {
-       TPM2_RC_INITIALIZE      = 0x0100,
-       TPM2_RC_TESTING         = 0x090A,
+       TPM2_RC_HASH            = 0x0083, /* RC_FMT1 */
+       TPM2_RC_INITIALIZE      = 0x0100, /* RC_VER1 */
        TPM2_RC_DISABLED        = 0x0120,
+       TPM2_RC_TESTING         = 0x090A, /* RC_WARN */
 };
 
 enum tpm2_algorithms {
        TPM2_ALG_SHA1           = 0x0004,
        TPM2_ALG_KEYEDHASH      = 0x0008,
        TPM2_ALG_SHA256         = 0x000B,
-       TPM2_ALG_NULL           = 0x0010
+       TPM2_ALG_SHA384         = 0x000C,
+       TPM2_ALG_SHA512         = 0x000D,
+       TPM2_ALG_NULL           = 0x0010,
+       TPM2_ALG_SM3_256        = 0x0012,
 };
 
 enum tpm2_command_codes {
index c12130485fc18e966c9e41736e57bd7fd0586082..d9d082206f6e4fb417cff29f2473d63dcf12ea67 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "tpm.h"
+#include <crypto/hash_info.h>
 #include <keys/trusted-type.h>
 
 enum tpm2_object_attributes {
@@ -104,6 +105,19 @@ struct tpm2_cmd {
        union tpm2_cmd_params   params;
 } __packed;
 
+struct tpm2_hash {
+       unsigned int crypto_id;
+       unsigned int tpm_id;
+};
+
+static struct tpm2_hash tpm2_hash_map[] = {
+       {HASH_ALGO_SHA1, TPM2_ALG_SHA1},
+       {HASH_ALGO_SHA256, TPM2_ALG_SHA256},
+       {HASH_ALGO_SHA384, TPM2_ALG_SHA384},
+       {HASH_ALGO_SHA512, TPM2_ALG_SHA512},
+       {HASH_ALGO_SM3_256, TPM2_ALG_SM3_256},
+};
+
 /*
  * Array with one entry per ordinal defining the maximum amount
  * of time the chip could take to return the result. The values
@@ -429,8 +443,20 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
 {
        unsigned int blob_len;
        struct tpm_buf buf;
+       u32 hash;
+       int i;
        int rc;
 
+       for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
+               if (options->hash == tpm2_hash_map[i].crypto_id) {
+                       hash = tpm2_hash_map[i].tpm_id;
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(tpm2_hash_map))
+               return -EINVAL;
+
        rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
        if (rc)
                return rc;
@@ -455,7 +481,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
        tpm_buf_append_u16(&buf, 14);
 
        tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
-       tpm_buf_append_u16(&buf, TPM2_ALG_SHA256);
+       tpm_buf_append_u16(&buf, hash);
        tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH);
        tpm_buf_append_u16(&buf, 0); /* policy digest size */
        tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
@@ -488,8 +514,12 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
 out:
        tpm_buf_destroy(&buf);
 
-       if (rc > 0)
-               rc = -EPERM;
+       if (rc > 0) {
+               if ((rc & TPM2_RC_HASH) == TPM2_RC_HASH)
+                       rc = -EINVAL;
+               else
+                       rc = -EPERM;
+       }
 
        return rc;
 }
index e1e5a3e5dd1bdab70852120be204f0fb4db73e4f..56f217d41f12e376028ac67e4617633acd76dd21 100644 (file)
@@ -34,6 +34,9 @@
 #define TGR160_DIGEST_SIZE 20
 #define TGR192_DIGEST_SIZE 24
 
+/* not defined in include/crypto/ */
+#define SM3256_DIGEST_SIZE 32
+
 extern const char *const hash_algo_name[HASH_ALGO__LAST];
 extern const int hash_digest_size[HASH_ALGO__LAST];
 
index f91ecd9d1bb19c2c241af39137521432492bff48..a6a100833ae9cde5a70bce1a66c92adc6f4d895f 100644 (file)
@@ -36,6 +36,7 @@ struct trusted_key_options {
        uint32_t pcrinfo_len;
        unsigned char pcrinfo[MAX_PCRINFO_SIZE];
        int pcrlock;
+       uint32_t hash;
 };
 
 extern struct key_type key_type_trusted;
index ca18c45f8304bd4b62c9d53fcaddc59ce23de296..ebf8fd885dd59cdd6b7d5a72a3bdcaa8353fc1b5 100644 (file)
@@ -31,6 +31,7 @@ enum hash_algo {
        HASH_ALGO_TGR_128,
        HASH_ALGO_TGR_160,
        HASH_ALGO_TGR_192,
+       HASH_ALGO_SM3_256,
        HASH_ALGO__LAST
 };
 
index 72483b8f1be5b058d7ca6001fb8e9877c4cf9a94..fe4d74e126a768f4c502cf3e55e5ab55f37e90d9 100644 (file)
@@ -54,6 +54,7 @@ config TRUSTED_KEYS
        select CRYPTO
        select CRYPTO_HMAC
        select CRYPTO_SHA1
+       select CRYPTO_HASH_INFO
        help
          This option provides support for creating, sealing, and unsealing
          keys in the kernel. Trusted keys are random number symmetric keys,
index 7c183c767a3a0084c30e9f5598045cf89e976df7..8f1300cab38ed6bcf5d4b2a8a77e0ae94b46bf91 100644 (file)
@@ -11,6 +11,7 @@
  * See Documentation/security/keys-trusted-encrypted.txt
  */
 
+#include <crypto/hash_info.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -710,7 +711,8 @@ enum {
        Opt_err = -1,
        Opt_new, Opt_load, Opt_update,
        Opt_keyhandle, Opt_keyauth, Opt_blobauth,
-       Opt_pcrinfo, Opt_pcrlock, Opt_migratable
+       Opt_pcrinfo, Opt_pcrlock, Opt_migratable,
+       Opt_hash,
 };
 
 static const match_table_t key_tokens = {
@@ -723,6 +725,7 @@ static const match_table_t key_tokens = {
        {Opt_pcrinfo, "pcrinfo=%s"},
        {Opt_pcrlock, "pcrlock=%s"},
        {Opt_migratable, "migratable=%s"},
+       {Opt_hash, "hash=%s"},
        {Opt_err, NULL}
 };
 
@@ -737,6 +740,14 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
        unsigned long handle;
        unsigned long lock;
        unsigned long token_mask = 0;
+       int i;
+       int tpm2;
+
+       tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
+       if (tpm2 < 0)
+               return tpm2;
+
+       opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
 
        while ((p = strsep(&c, " \t"))) {
                if (*p == '\0' || *p == ' ' || *p == '\t')
@@ -790,6 +801,20 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
                                return -EINVAL;
                        opt->pcrlock = lock;
                        break;
+               case Opt_hash:
+                       for (i = 0; i < HASH_ALGO__LAST; i++) {
+                               if (!strcmp(args[0].from, hash_algo_name[i])) {
+                                       opt->hash = i;
+                                       break;
+                               }
+                       }
+                       if (i == HASH_ALGO__LAST)
+                               return -EINVAL;
+                       if  (!tpm2 && i != HASH_ALGO_SHA1) {
+                               pr_info("trusted_key: TPM 1.x only supports SHA-1.\n");
+                               return -EINVAL;
+                       }
+                       break;
                default:
                        return -EINVAL;
                }