Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

security: keys: trusted: use ASN.1 TPM2 key format for the blobs

Modify the TPM2 key format blob output to export and import in the
ASN.1 form for TPM2 sealed object keys. For compatibility with prior
trusted keys, the importer will also accept two TPM2B quantities
representing the public and private parts of the key. However, the
export via keyctl pipe will only output the ASN.1 format.

The benefit of the ASN.1 format is that it's a standard and thus the
exported key can be used by userspace tools (openssl_tpm2_engine,
openconnect and tpm2-tss-engine). The format includes policy
specifications, thus it gets us out of having to construct policy
handles in userspace and the format includes the parent meaning you
don't have to keep passing it in each time.

This patch only implements basic handling for the ASN.1 format, so
keys with passwords but no policy.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Tested-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>

authored by

James Bottomley and committed by
Jarkko Sakkinen
f2219745 de66514d

+280 -8
+58
Documentation/security/keys/trusted-encrypted.rst
··· 207 207 Another new format 'enc32' has been defined in order to support encrypted keys 208 208 with payload size of 32 bytes. This will initially be used for nvdimm security 209 209 but may expand to other usages that require 32 bytes payload. 210 + 211 + 212 + TPM 2.0 ASN.1 Key Format 213 + ------------------------ 214 + 215 + The TPM 2.0 ASN.1 key format is designed to be easily recognisable, 216 + even in binary form (fixing a problem we had with the TPM 1.2 ASN.1 217 + format) and to be extensible for additions like importable keys and 218 + policy:: 219 + 220 + TPMKey ::= SEQUENCE { 221 + type OBJECT IDENTIFIER 222 + emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL 223 + parent INTEGER 224 + pubkey OCTET STRING 225 + privkey OCTET STRING 226 + } 227 + 228 + type is what distinguishes the key even in binary form since the OID 229 + is provided by the TCG to be unique and thus forms a recognizable 230 + binary pattern at offset 3 in the key. The OIDs currently made 231 + available are:: 232 + 233 + 2.23.133.10.1.3 TPM Loadable key. This is an asymmetric key (Usually 234 + RSA2048 or Elliptic Curve) which can be imported by a 235 + TPM2_Load() operation. 236 + 237 + 2.23.133.10.1.4 TPM Importable Key. This is an asymmetric key (Usually 238 + RSA2048 or Elliptic Curve) which can be imported by a 239 + TPM2_Import() operation. 240 + 241 + 2.23.133.10.1.5 TPM Sealed Data. This is a set of data (up to 128 242 + bytes) which is sealed by the TPM. It usually 243 + represents a symmetric key and must be unsealed before 244 + use. 245 + 246 + The trusted key code only uses the TPM Sealed Data OID. 247 + 248 + emptyAuth is true if the key has well known authorization "". If it 249 + is false or not present, the key requires an explicit authorization 250 + phrase. This is used by most user space consumers to decide whether 251 + to prompt for a password. 252 + 253 + parent represents the parent key handle, either in the 0x81 MSO space, 254 + like 0x81000001 for the RSA primary storage key. Userspace programmes 255 + also support specifying the primary handle in the 0x40 MSO space. If 256 + this happens the Elliptic Curve variant of the primary key using the 257 + TCG defined template will be generated on the fly into a volatile 258 + object and used as the parent. The current kernel code only supports 259 + the 0x81 MSO form. 260 + 261 + pubkey is the binary representation of TPM2B_PRIVATE excluding the 262 + initial TPM2B header, which can be reconstructed from the ASN.1 octet 263 + string length. 264 + 265 + privkey is the binary representation of TPM2B_PUBLIC excluding the 266 + initial TPM2B header which can be reconstructed from the ASN.1 octed 267 + string length.
+1
include/keys/trusted-type.h
··· 22 22 unsigned int key_len; 23 23 unsigned int blob_len; 24 24 unsigned char migratable; 25 + unsigned char old_format; 25 26 unsigned char key[MAX_KEY_SIZE + 1]; 26 27 unsigned char blob[MAX_BLOB_SIZE]; 27 28 };
+3
security/keys/Kconfig
··· 75 75 select CRYPTO_HMAC 76 76 select CRYPTO_SHA1 77 77 select CRYPTO_HASH_INFO 78 + select ASN1_ENCODER 79 + select OID_REGISTRY 80 + select ASN1 78 81 help 79 82 This option provides support for creating, sealing, and unsealing 80 83 keys in the kernel. Trusted keys are random number symmetric keys,
+3
security/keys/trusted-keys/Makefile
··· 5 5 6 6 obj-$(CONFIG_TRUSTED_KEYS) += trusted.o 7 7 trusted-y += trusted_tpm1.o 8 + 9 + $(obj)/trusted_tpm2.o: $(obj)/tpm2key.asn1.h 8 10 trusted-y += trusted_tpm2.o 11 + trusted-y += tpm2key.asn1.o
+11
security/keys/trusted-keys/tpm2key.asn1
··· 1 + --- 2 + --- ASN.1 for TPM 2.0 keys 3 + --- 4 + 5 + TPMKey ::= SEQUENCE { 6 + type OBJECT IDENTIFIER ({tpm2_key_type}), 7 + emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL, 8 + parent INTEGER ({tpm2_key_parent}), 9 + pubkey OCTET STRING ({tpm2_key_pub}), 10 + privkey OCTET STRING ({tpm2_key_priv}) 11 + }
+1 -1
security/keys/trusted-keys/trusted_tpm1.c
··· 1021 1021 goto out; 1022 1022 } 1023 1023 1024 - if (!options->keyhandle) { 1024 + if (!options->keyhandle && !tpm2) { 1025 1025 ret = -EINVAL; 1026 1026 goto out; 1027 1027 }
+203 -7
security/keys/trusted-keys/trusted_tpm2.c
··· 4 4 * Copyright (C) 2014 Intel Corporation 5 5 */ 6 6 7 + #include <linux/asn1_encoder.h> 8 + #include <linux/oid_registry.h> 7 9 #include <linux/string.h> 8 10 #include <linux/err.h> 9 11 #include <linux/tpm.h> ··· 14 12 #include <keys/trusted-type.h> 15 13 #include <keys/trusted_tpm.h> 16 14 15 + #include <asm/unaligned.h> 16 + 17 + #include "tpm2key.asn1.h" 18 + 17 19 static struct tpm2_hash tpm2_hash_map[] = { 18 20 {HASH_ALGO_SHA1, TPM_ALG_SHA1}, 19 21 {HASH_ALGO_SHA256, TPM_ALG_SHA256}, ··· 25 19 {HASH_ALGO_SHA512, TPM_ALG_SHA512}, 26 20 {HASH_ALGO_SM3_256, TPM_ALG_SM3_256}, 27 21 }; 22 + 23 + static u32 tpm2key_oid[] = { 2, 23, 133, 10, 1, 5 }; 24 + 25 + static int tpm2_key_encode(struct trusted_key_payload *payload, 26 + struct trusted_key_options *options, 27 + u8 *src, u32 len) 28 + { 29 + const int SCRATCH_SIZE = PAGE_SIZE; 30 + u8 *scratch = kmalloc(SCRATCH_SIZE, GFP_KERNEL); 31 + u8 *work = scratch, *work1; 32 + u8 *end_work = scratch + SCRATCH_SIZE; 33 + u8 *priv, *pub; 34 + u16 priv_len, pub_len; 35 + 36 + priv_len = get_unaligned_be16(src) + 2; 37 + priv = src; 38 + 39 + src += priv_len; 40 + 41 + pub_len = get_unaligned_be16(src) + 2; 42 + pub = src; 43 + 44 + if (!scratch) 45 + return -ENOMEM; 46 + 47 + work = asn1_encode_oid(work, end_work, tpm2key_oid, 48 + asn1_oid_len(tpm2key_oid)); 49 + 50 + if (options->blobauth_len == 0) { 51 + unsigned char bool[3], *w = bool; 52 + /* tag 0 is emptyAuth */ 53 + w = asn1_encode_boolean(w, w + sizeof(bool), true); 54 + if (WARN(IS_ERR(w), "BUG: Boolean failed to encode")) 55 + return PTR_ERR(w); 56 + work = asn1_encode_tag(work, end_work, 0, bool, w - bool); 57 + } 58 + 59 + /* 60 + * Assume both octet strings will encode to a 2 byte definite length 61 + * 62 + * Note: For a well behaved TPM, this warning should never 63 + * trigger, so if it does there's something nefarious going on 64 + */ 65 + if (WARN(work - scratch + pub_len + priv_len + 14 > SCRATCH_SIZE, 66 + "BUG: scratch buffer is too small")) 67 + return -EINVAL; 68 + 69 + work = asn1_encode_integer(work, end_work, options->keyhandle); 70 + work = asn1_encode_octet_string(work, end_work, pub, pub_len); 71 + work = asn1_encode_octet_string(work, end_work, priv, priv_len); 72 + 73 + work1 = payload->blob; 74 + work1 = asn1_encode_sequence(work1, work1 + sizeof(payload->blob), 75 + scratch, work - scratch); 76 + if (WARN(IS_ERR(work1), "BUG: ASN.1 encoder failed")) 77 + return PTR_ERR(work1); 78 + 79 + return work1 - payload->blob; 80 + } 81 + 82 + struct tpm2_key_context { 83 + u32 parent; 84 + const u8 *pub; 85 + u32 pub_len; 86 + const u8 *priv; 87 + u32 priv_len; 88 + }; 89 + 90 + static int tpm2_key_decode(struct trusted_key_payload *payload, 91 + struct trusted_key_options *options, 92 + u8 **buf) 93 + { 94 + int ret; 95 + struct tpm2_key_context ctx; 96 + u8 *blob; 97 + 98 + memset(&ctx, 0, sizeof(ctx)); 99 + 100 + ret = asn1_ber_decoder(&tpm2key_decoder, &ctx, payload->blob, 101 + payload->blob_len); 102 + if (ret < 0) 103 + return ret; 104 + 105 + if (ctx.priv_len + ctx.pub_len > MAX_BLOB_SIZE) 106 + return -EINVAL; 107 + 108 + blob = kmalloc(ctx.priv_len + ctx.pub_len + 4, GFP_KERNEL); 109 + if (!blob) 110 + return -ENOMEM; 111 + 112 + *buf = blob; 113 + options->keyhandle = ctx.parent; 114 + 115 + memcpy(blob, ctx.priv, ctx.priv_len); 116 + blob += ctx.priv_len; 117 + 118 + memcpy(blob, ctx.pub, ctx.pub_len); 119 + 120 + return 0; 121 + } 122 + 123 + int tpm2_key_parent(void *context, size_t hdrlen, 124 + unsigned char tag, 125 + const void *value, size_t vlen) 126 + { 127 + struct tpm2_key_context *ctx = context; 128 + const u8 *v = value; 129 + int i; 130 + 131 + ctx->parent = 0; 132 + for (i = 0; i < vlen; i++) { 133 + ctx->parent <<= 8; 134 + ctx->parent |= v[i]; 135 + } 136 + 137 + return 0; 138 + } 139 + 140 + int tpm2_key_type(void *context, size_t hdrlen, 141 + unsigned char tag, 142 + const void *value, size_t vlen) 143 + { 144 + enum OID oid = look_up_OID(value, vlen); 145 + 146 + if (oid != OID_TPMSealedData) { 147 + char buffer[50]; 148 + 149 + sprint_oid(value, vlen, buffer, sizeof(buffer)); 150 + pr_debug("OID is \"%s\" which is not TPMSealedData\n", 151 + buffer); 152 + return -EINVAL; 153 + } 154 + 155 + return 0; 156 + } 157 + 158 + int tpm2_key_pub(void *context, size_t hdrlen, 159 + unsigned char tag, 160 + const void *value, size_t vlen) 161 + { 162 + struct tpm2_key_context *ctx = context; 163 + 164 + ctx->pub = value; 165 + ctx->pub_len = vlen; 166 + 167 + return 0; 168 + } 169 + 170 + int tpm2_key_priv(void *context, size_t hdrlen, 171 + unsigned char tag, 172 + const void *value, size_t vlen) 173 + { 174 + struct tpm2_key_context *ctx = context; 175 + 176 + ctx->priv = value; 177 + ctx->priv_len = vlen; 178 + 179 + return 0; 180 + } 28 181 29 182 /** 30 183 * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer. ··· 228 63 struct trusted_key_payload *payload, 229 64 struct trusted_key_options *options) 230 65 { 231 - unsigned int blob_len; 66 + int blob_len = 0; 232 67 struct tpm_buf buf; 233 68 u32 hash; 234 69 int i; ··· 242 77 } 243 78 244 79 if (i == ARRAY_SIZE(tpm2_hash_map)) 80 + return -EINVAL; 81 + 82 + if (!options->keyhandle) 245 83 return -EINVAL; 246 84 247 85 rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE); ··· 320 152 goto out; 321 153 } 322 154 323 - memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len); 324 - payload->blob_len = blob_len; 155 + blob_len = tpm2_key_encode(payload, options, 156 + &buf.data[TPM_HEADER_SIZE + 4], 157 + blob_len); 325 158 326 159 out: 327 160 tpm_buf_destroy(&buf); ··· 333 164 else 334 165 rc = -EPERM; 335 166 } 167 + if (blob_len < 0) 168 + return blob_len; 169 + 170 + payload->blob_len = blob_len; 336 171 337 172 tpm_put_ops(chip); 338 173 return rc; ··· 364 191 unsigned int private_len; 365 192 unsigned int public_len; 366 193 unsigned int blob_len; 194 + u8 *blob; 367 195 int rc; 368 196 369 - private_len = be16_to_cpup((__be16 *) &payload->blob[0]); 370 - if (private_len > (payload->blob_len - 2)) 197 + rc = tpm2_key_decode(payload, options, &blob); 198 + if (rc) { 199 + /* old form */ 200 + blob = payload->blob; 201 + payload->old_format = 1; 202 + } 203 + 204 + /* new format carries keyhandle but old format doesn't */ 205 + if (!options->keyhandle) 206 + return -EINVAL; 207 + 208 + /* must be big enough for at least the two be16 size counts */ 209 + if (payload->blob_len < 4) 210 + return -EINVAL; 211 + 212 + private_len = get_unaligned_be16(blob); 213 + 214 + /* must be big enough for following public_len */ 215 + if (private_len + 2 + 2 > (payload->blob_len)) 371 216 return -E2BIG; 372 217 373 - public_len = be16_to_cpup((__be16 *) &payload->blob[2 + private_len]); 218 + public_len = get_unaligned_be16(blob + 2 + private_len); 219 + if (private_len + 2 + public_len + 2 > payload->blob_len) 220 + return -E2BIG; 221 + 374 222 blob_len = private_len + public_len + 4; 375 223 if (blob_len > payload->blob_len) 376 224 return -E2BIG; ··· 407 213 options->keyauth /* hmac */, 408 214 TPM_DIGEST_SIZE); 409 215 410 - tpm_buf_append(&buf, payload->blob, blob_len); 216 + tpm_buf_append(&buf, blob, blob_len); 411 217 412 218 if (buf.flags & TPM_BUF_OVERFLOW) { 413 219 rc = -E2BIG; ··· 420 226 (__be32 *) &buf.data[TPM_HEADER_SIZE]); 421 227 422 228 out: 229 + if (blob != payload->blob) 230 + kfree(blob); 423 231 tpm_buf_destroy(&buf); 424 232 425 233 if (rc > 0)