Message ID | 20240524130459.21510-5-James.Bottomley@HansenPartnership.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add policy to sealed keys | expand |
On Fri May 24, 2024 at 4:04 PM EEST, James Bottomley wrote: > This patch adds a policy= argument to key creation. The policy is the > standard tss policymaker format and each separate policy line must > have a newline after it. > > Thus to construct a policy requiring authorized value and pcr 16 > locking using a sha256 hash, the policy (policy.txt) file would be two > lines: > > 0000017F00000001000B03000001303095B49BE85E381E5B20E557E46363EF55B0F43B132C2D8E3DE9AC436656F2 > 0000016b > > This can be inserted into the key with > > keyctl add trusted kmk "new 32 policy=`cat policy.txt` keyhandle=0x81000001 hash=sha256" @u > > Note that although a few policies work like this, most require special > handling which must be added to the kernel policy construction > routine. > > Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> > --- > .../security/keys/trusted-encrypted.rst | 17 +++++- > security/keys/trusted-keys/tpm2-policy.c | 53 +++++++++++++++++++ > security/keys/trusted-keys/tpm2-policy.h | 5 ++ > security/keys/trusted-keys/trusted_tpm1.c | 15 ++++++ > 4 files changed, 89 insertions(+), 1 deletion(-) > > diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst > index c37c08956ec1..fbb41cf16f30 100644 > --- a/Documentation/security/keys/trusted-encrypted.rst > +++ b/Documentation/security/keys/trusted-encrypted.rst > @@ -233,6 +233,9 @@ Usage:: > 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. > + policy= specify an arbitrary set of policies. These must > + be in policymaker format with each separate > + policy line newline terminated. > > "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. > @@ -377,6 +380,19 @@ the sha1 pcr16 bank you'd say:: > > because the trailing hash is the sha256sum of 20 zero bytes. > > +You can also specify arbitrary policy in policymaker format, so a two > +value policy (the pcr example above and authvalue) would look like > +this in policymaker format:: > + > + 0000017F000000010004030000016768033e216468247bd031a0a2d9876d79818f8f > + 0000016b > + > +This can be placed in a file (say policy.txt) and then added to the key as:: > + > + $ keyctl add trusted kmk "new 32 keyhandle=0x81000001 hash=sha1 policy=`cat policy.txt`" @u > + > +The newlines in the file policy.txt will be automatically processed. > + > Reseal (TPM specific) a trusted key under new PCR values:: > > $ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`" > @@ -447,7 +463,6 @@ Another new format 'enc32' has been defined in order to support encrypted keys > with payload size of 32 bytes. This will initially be used for nvdimm security > but may expand to other usages that require 32 bytes payload. > > - > TPM 2.0 ASN.1 Key Format > ------------------------ > > diff --git a/security/keys/trusted-keys/tpm2-policy.c b/security/keys/trusted-keys/tpm2-policy.c > index 8c3a09762c10..a731c10d9bba 100644 > --- a/security/keys/trusted-keys/tpm2-policy.c > +++ b/security/keys/trusted-keys/tpm2-policy.c Ditto. > @@ -323,3 +323,56 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols) > > return 0; > } > + > +int tpm2_parse_policies(struct tpm2_policies **ppols, char *str) > +{ > + struct tpm2_policies *pols; > + char *p; > + u8 *ptr; > + int i = 0, left = PAGE_SIZE, res; > + > + pols = kmalloc(left, GFP_KERNEL); > + if (!pols) > + return -ENOMEM; > + > + ptr = (u8 *)(pols + 1); > + left -= ptr - (u8 *)pols; > + > + while ((p = strsep(&str, "\n"))) { > + if (*p == '\0' || *p == '\n') > + continue; > + > + pols->len[i] = strlen(p)/2; > + if (pols->len[i] > left) { > + res = -E2BIG; > + goto err; > + } > + > + res = hex2bin(ptr, p, pols->len[i]); > + if (res) > + goto err; > + > + /* get command code and skip past */ > + pols->code[i] = get_unaligned_be32(ptr); > + pols->policies[i] = ptr + 4; > + ptr += pols->len[i]; > + left -= pols->len[i]; > + pols->len[i] -= 4; > + > + /* > + * FIXME: this does leave the code embedded in dead > + * regions of the memory, but it's easier than > + * hexdumping to a temporary or copying over > + */ > + i++; > + } > + > + pols->count = i; > + *ppols = pols; > + > + return 0; > + > + err: > + kfree(pols); > + return res; > +} > diff --git a/security/keys/trusted-keys/tpm2-policy.h b/security/keys/trusted-keys/tpm2-policy.h > index b20e9c3e2f06..8ddf235b3fec 100644 > --- a/security/keys/trusted-keys/tpm2-policy.h > +++ b/security/keys/trusted-keys/tpm2-policy.h > @@ -28,6 +28,7 @@ int tpm2_generate_policy_digest(struct tpm2_policies *pols, u32 hash, > u8 *policydigest, u32 *plen); > int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len); > int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols); > +int tpm2_parse_policies(struct tpm2_policies **ppols, char *str); > #else > static inline int tpm2_key_policy_process(struct tpm2_key_context *ctx, > struct trusted_key_payload *payload) > @@ -50,4 +51,8 @@ static inline int tpm2_get_policy_session(struct tpm_chip *chip, > { > return -EINVAL; > } > +static inline int tpm2_parse_policies(struct tpm2_policies **ppols, char *str) > +{ > + return -EINVAL; > +} > #endif > diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c > index 89c9798d1800..4dcc1373dd05 100644 > --- a/security/keys/trusted-keys/trusted_tpm1.c > +++ b/security/keys/trusted-keys/trusted_tpm1.c > @@ -22,6 +22,8 @@ > > #include <keys/trusted_tpm.h> > > +#include "tpm2-policy.h" > + > static const char hmac_alg[] = "hmac(sha1)"; > static const char hash_alg[] = "sha1"; > static struct tpm_chip *chip; > @@ -724,6 +726,7 @@ enum { > Opt_hash, > Opt_policydigest, > Opt_policyhandle, > + Opt_policy, > }; > > static const match_table_t key_tokens = { > @@ -736,6 +739,7 @@ static const match_table_t key_tokens = { > {Opt_hash, "hash=%s"}, > {Opt_policydigest, "policydigest=%s"}, > {Opt_policyhandle, "policyhandle=%s"}, > + {Opt_policy, "policy=%s"}, > {Opt_err, NULL} > }; > > @@ -869,6 +873,17 @@ static int getoptions(char *c, struct trusted_key_payload *pay, > return -EINVAL; > opt->policyhandle = handle; > break; > + > + case Opt_policy: > + if (pay->policies) > + return -EINVAL; > + if (!tpm2) > + return -EINVAL; > + res = tpm2_parse_policies(&pay->policies, args[0].from); > + if (res) > + return res; > + break; > + > default: > return -EINVAL; > } BR, Jarkko
diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst index c37c08956ec1..fbb41cf16f30 100644 --- a/Documentation/security/keys/trusted-encrypted.rst +++ b/Documentation/security/keys/trusted-encrypted.rst @@ -233,6 +233,9 @@ Usage:: 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. + policy= specify an arbitrary set of policies. These must + be in policymaker format with each separate + policy line newline terminated. "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. @@ -377,6 +380,19 @@ the sha1 pcr16 bank you'd say:: because the trailing hash is the sha256sum of 20 zero bytes. +You can also specify arbitrary policy in policymaker format, so a two +value policy (the pcr example above and authvalue) would look like +this in policymaker format:: + + 0000017F000000010004030000016768033e216468247bd031a0a2d9876d79818f8f + 0000016b + +This can be placed in a file (say policy.txt) and then added to the key as:: + + $ keyctl add trusted kmk "new 32 keyhandle=0x81000001 hash=sha1 policy=`cat policy.txt`" @u + +The newlines in the file policy.txt will be automatically processed. + Reseal (TPM specific) a trusted key under new PCR values:: $ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`" @@ -447,7 +463,6 @@ Another new format 'enc32' has been defined in order to support encrypted keys with payload size of 32 bytes. This will initially be used for nvdimm security but may expand to other usages that require 32 bytes payload. - TPM 2.0 ASN.1 Key Format ------------------------ diff --git a/security/keys/trusted-keys/tpm2-policy.c b/security/keys/trusted-keys/tpm2-policy.c index 8c3a09762c10..a731c10d9bba 100644 --- a/security/keys/trusted-keys/tpm2-policy.c +++ b/security/keys/trusted-keys/tpm2-policy.c @@ -323,3 +323,56 @@ int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols) return 0; } + +int tpm2_parse_policies(struct tpm2_policies **ppols, char *str) +{ + struct tpm2_policies *pols; + char *p; + u8 *ptr; + int i = 0, left = PAGE_SIZE, res; + + pols = kmalloc(left, GFP_KERNEL); + if (!pols) + return -ENOMEM; + + ptr = (u8 *)(pols + 1); + left -= ptr - (u8 *)pols; + + while ((p = strsep(&str, "\n"))) { + if (*p == '\0' || *p == '\n') + continue; + + pols->len[i] = strlen(p)/2; + if (pols->len[i] > left) { + res = -E2BIG; + goto err; + } + + res = hex2bin(ptr, p, pols->len[i]); + if (res) + goto err; + + /* get command code and skip past */ + pols->code[i] = get_unaligned_be32(ptr); + pols->policies[i] = ptr + 4; + ptr += pols->len[i]; + left -= pols->len[i]; + pols->len[i] -= 4; + + /* + * FIXME: this does leave the code embedded in dead + * regions of the memory, but it's easier than + * hexdumping to a temporary or copying over + */ + i++; + } + + pols->count = i; + *ppols = pols; + + return 0; + + err: + kfree(pols); + return res; +} diff --git a/security/keys/trusted-keys/tpm2-policy.h b/security/keys/trusted-keys/tpm2-policy.h index b20e9c3e2f06..8ddf235b3fec 100644 --- a/security/keys/trusted-keys/tpm2-policy.h +++ b/security/keys/trusted-keys/tpm2-policy.h @@ -28,6 +28,7 @@ int tpm2_generate_policy_digest(struct tpm2_policies *pols, u32 hash, u8 *policydigest, u32 *plen); int tpm2_encode_policy(struct tpm2_policies *pols, u8 **data, u32 *len); int tpm2_get_policy_session(struct tpm_chip *chip, struct tpm2_policies *pols); +int tpm2_parse_policies(struct tpm2_policies **ppols, char *str); #else static inline int tpm2_key_policy_process(struct tpm2_key_context *ctx, struct trusted_key_payload *payload) @@ -50,4 +51,8 @@ static inline int tpm2_get_policy_session(struct tpm_chip *chip, { return -EINVAL; } +static inline int tpm2_parse_policies(struct tpm2_policies **ppols, char *str) +{ + return -EINVAL; +} #endif diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c index 89c9798d1800..4dcc1373dd05 100644 --- a/security/keys/trusted-keys/trusted_tpm1.c +++ b/security/keys/trusted-keys/trusted_tpm1.c @@ -22,6 +22,8 @@ #include <keys/trusted_tpm.h> +#include "tpm2-policy.h" + static const char hmac_alg[] = "hmac(sha1)"; static const char hash_alg[] = "sha1"; static struct tpm_chip *chip; @@ -724,6 +726,7 @@ enum { Opt_hash, Opt_policydigest, Opt_policyhandle, + Opt_policy, }; static const match_table_t key_tokens = { @@ -736,6 +739,7 @@ static const match_table_t key_tokens = { {Opt_hash, "hash=%s"}, {Opt_policydigest, "policydigest=%s"}, {Opt_policyhandle, "policyhandle=%s"}, + {Opt_policy, "policy=%s"}, {Opt_err, NULL} }; @@ -869,6 +873,17 @@ static int getoptions(char *c, struct trusted_key_payload *pay, return -EINVAL; opt->policyhandle = handle; break; + + case Opt_policy: + if (pay->policies) + return -EINVAL; + if (!tpm2) + return -EINVAL; + res = tpm2_parse_policies(&pay->policies, args[0].from); + if (res) + return res; + break; + default: return -EINVAL; }
This patch adds a policy= argument to key creation. The policy is the standard tss policymaker format and each separate policy line must have a newline after it. Thus to construct a policy requiring authorized value and pcr 16 locking using a sha256 hash, the policy (policy.txt) file would be two lines: 0000017F00000001000B03000001303095B49BE85E381E5B20E557E46363EF55B0F43B132C2D8E3DE9AC436656F2 0000016b This can be inserted into the key with keyctl add trusted kmk "new 32 policy=`cat policy.txt` keyhandle=0x81000001 hash=sha256" @u Note that although a few policies work like this, most require special handling which must be added to the kernel policy construction routine. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> --- .../security/keys/trusted-encrypted.rst | 17 +++++- security/keys/trusted-keys/tpm2-policy.c | 53 +++++++++++++++++++ security/keys/trusted-keys/tpm2-policy.h | 5 ++ security/keys/trusted-keys/trusted_tpm1.c | 15 ++++++ 4 files changed, 89 insertions(+), 1 deletion(-)