keys, trusted: seal with a TPM2 authorization policy
authorJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Sat, 31 Oct 2015 15:53:44 +0000 (17:53 +0200)
committerJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Sun, 20 Dec 2015 13:27:13 +0000 (15:27 +0200)
TPM2 supports authorization policies, which are essentially
combinational logic statements repsenting the conditions where the data
can be unsealed based on the TPM state. This patch enables to use
authorization policies to seal trusted keys.

Two following new options have been added for trusted keys:

* 'policydigest=': provide an auth policy digest for sealing.
* 'policyhandle=': provide a policy session handle for unsealing.

If 'hash=' option is supplied after 'policydigest=' option, this
will result an error because the state of the option would become
mixed.

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

index fd2565b301e87eaab6cc5ea4b08ddb4debbd8b94..324ddf5223b34007b0cee28d7d6587ec93b77641 100644 (file)
@@ -27,20 +27,26 @@ Usage:
     keyctl print keyid
 
     options:
-       keyhandle= ascii hex value of sealing key default 0x40000000 (SRK)
-       keyauth=          ascii hex auth for sealing key default 0x00...i
-                 (40 ascii zeros)
-       blobauth=  ascii hex auth for sealed data default 0x00...
-                 (40 ascii zeros)
-       blobauth=  ascii hex auth for sealed data default 0x00...
-                 (40 ascii zeros)
-       pcrinfo=          ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
-       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.
+       keyhandle=    ascii hex value of sealing key default 0x40000000 (SRK)
+       keyauth=             ascii hex auth for sealing key default 0x00...i
+                     (40 ascii zeros)
+       blobauth=     ascii hex auth for sealed data default 0x00...
+                     (40 ascii zeros)
+       blobauth=     ascii hex auth for sealed data default 0x00...
+                     (40 ascii zeros)
+       pcrinfo=             ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
+       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.
+       policydigest= digest for the authorization policy. must be calculated
+                     with the same hash algorithm as specified by the 'hash='
+                     option.
+       policyhandle= handle to an authorization policy session that defines the
+                     same policy and with the same hash algorithm as was used to
+                     seal the key.
 
 "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 d9d082206f6e4fb417cff29f2473d63dcf12ea67..45a634016f9556f1770928c0cf42972017fc494b 100644 (file)
@@ -478,12 +478,26 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
        tpm_buf_append_u8(&buf, payload->migratable);
 
        /* public */
-       tpm_buf_append_u16(&buf, 14);
+       if (options->policydigest)
+               tpm_buf_append_u16(&buf, 14 + options->digest_len);
+       else
+               tpm_buf_append_u16(&buf, 14);
 
        tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
        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 */
+
+       /* policy */
+       if (options->policydigest) {
+               tpm_buf_append_u32(&buf, 0);
+               tpm_buf_append_u16(&buf, options->digest_len);
+               tpm_buf_append(&buf, options->policydigest,
+                              options->digest_len);
+       } else {
+               tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH);
+               tpm_buf_append_u16(&buf, 0);
+       }
+
+       /* public parameters */
        tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
        tpm_buf_append_u16(&buf, 0);
 
@@ -613,7 +627,9 @@ static int tpm2_unseal(struct tpm_chip *chip,
                return rc;
 
        tpm_buf_append_u32(&buf, blob_handle);
-       tpm2_buf_append_auth(&buf, TPM2_RS_PW,
+       tpm2_buf_append_auth(&buf,
+                            options->policyhandle ?
+                            options->policyhandle : TPM2_RS_PW,
                             NULL /* nonce */, 0,
                             0 /* session_attributes */,
                             options->blobauth /* hmac */,
index a6a100833ae9cde5a70bce1a66c92adc6f4d895f..42cf2d991bf4b496a4b13fdbfc0a6da753621820 100644 (file)
@@ -18,6 +18,7 @@
 #define MAX_KEY_SIZE                   128
 #define MAX_BLOB_SIZE                  512
 #define MAX_PCRINFO_SIZE               64
+#define MAX_DIGEST_SIZE                        64
 
 struct trusted_key_payload {
        struct rcu_head rcu;
@@ -37,6 +38,9 @@ struct trusted_key_options {
        unsigned char pcrinfo[MAX_PCRINFO_SIZE];
        int pcrlock;
        uint32_t hash;
+       uint32_t digest_len;
+       unsigned char policydigest[MAX_DIGEST_SIZE];
+       uint32_t policyhandle;
 };
 
 extern struct key_type key_type_trusted;
index 8f1300cab38ed6bcf5d4b2a8a77e0ae94b46bf91..e15baf722ae3be044e39755bb218eff0ddf83863 100644 (file)
@@ -713,6 +713,8 @@ enum {
        Opt_keyhandle, Opt_keyauth, Opt_blobauth,
        Opt_pcrinfo, Opt_pcrlock, Opt_migratable,
        Opt_hash,
+       Opt_policydigest,
+       Opt_policyhandle,
 };
 
 static const match_table_t key_tokens = {
@@ -726,6 +728,8 @@ static const match_table_t key_tokens = {
        {Opt_pcrlock, "pcrlock=%s"},
        {Opt_migratable, "migratable=%s"},
        {Opt_hash, "hash=%s"},
+       {Opt_policydigest, "policydigest=%s"},
+       {Opt_policyhandle, "policyhandle=%s"},
        {Opt_err, NULL}
 };
 
@@ -748,6 +752,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
                return tpm2;
 
        opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
+       opt->digest_len = hash_digest_size[opt->hash];
 
        while ((p = strsep(&c, " \t"))) {
                if (*p == '\0' || *p == ' ' || *p == '\t')
@@ -802,9 +807,13 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
                        opt->pcrlock = lock;
                        break;
                case Opt_hash:
+                       if (test_bit(Opt_policydigest, &token_mask))
+                               return -EINVAL;
                        for (i = 0; i < HASH_ALGO__LAST; i++) {
                                if (!strcmp(args[0].from, hash_algo_name[i])) {
                                        opt->hash = i;
+                                       opt->digest_len =
+                                               hash_digest_size[opt->hash];
                                        break;
                                }
                        }
@@ -815,6 +824,23 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
                                return -EINVAL;
                        }
                        break;
+               case Opt_policydigest:
+                       if (!tpm2 ||
+                           strlen(args[0].from) != (2 * opt->digest_len))
+                               return -EINVAL;
+                       res = hex2bin(opt->policydigest, args[0].from,
+                                     opt->digest_len);
+                       if (res < 0)
+                               return -EINVAL;
+                       break;
+               case Opt_policyhandle:
+                       if (!tpm2)
+                               return -EINVAL;
+                       res = kstrtoul(args[0].from, 16, &handle);
+                       if (res < 0)
+                               return -EINVAL;
+                       opt->policyhandle = handle;
+                       break;
                default:
                        return -EINVAL;
                }