static struct trusted_key_options *trusted_options_alloc(void) { struct trusted_key_options *options; int tpm2; tpm2 = tpm_is_tpm2(TPM_ANY_NUM); if (tpm2 < 0) return NULL; options = kzalloc(sizeof *options, GFP_KERNEL); if (options) { /* set any non-zero defaults */ options->keytype = SRK_keytype; if (!tpm2) options->keyhandle = SRKHANDLE; } return options; }
/* Given the blob, parse it and load it into the TPM */ struct tpm_key *tpm_key_create(const void *blob, uint32_t blob_len) { int r; struct tpm_key *tk; r = tpm_is_tpm2(NULL); if (r < 0) goto error; /* We don't support TPM2 yet */ if (r > 0) { r = -ENODEV; goto error; } r = -ENOMEM; tk = kzalloc(sizeof(struct tpm_key), GFP_KERNEL); if (!tk) goto error; tk->blob = kmemdup(blob, blob_len, GFP_KERNEL); if (!tk->blob) goto error_memdup; tk->blob_len = blob_len; r = extract_key_parameters(tk); if (r < 0) goto error_extract; return tk; error_extract: kfree(tk->blob); tk->blob_len = 0; error_memdup: kfree(tk); error: return ERR_PTR(r); }
/* * trusted_instantiate - create a new trusted key * * Unseal an existing trusted blob or, for a new key, get a * random key, then seal and create a trusted key-type key, * adding it to the specified keyring. * * On success, return 0. Otherwise return errno. */ static int trusted_instantiate(struct key *key, struct key_preparsed_payload *prep) { struct trusted_key_payload *payload = NULL; struct trusted_key_options *options = NULL; size_t datalen = prep->datalen; char *datablob; int ret = 0; int key_cmd; size_t key_len; int tpm2; tpm2 = tpm_is_tpm2(TPM_ANY_NUM); if (tpm2 < 0) return tpm2; if (datalen <= 0 || datalen > 32767 || !prep->data) return -EINVAL; datablob = kmalloc(datalen + 1, GFP_KERNEL); if (!datablob) return -ENOMEM; memcpy(datablob, prep->data, datalen); datablob[datalen] = '\0'; options = trusted_options_alloc(); if (!options) { ret = -ENOMEM; goto out; } payload = trusted_payload_alloc(key); if (!payload) { ret = -ENOMEM; goto out; } key_cmd = datablob_parse(datablob, payload, options); if (key_cmd < 0) { ret = key_cmd; goto out; } if (!options->keyhandle) { ret = -EINVAL; goto out; } dump_payload(payload); dump_options(options); switch (key_cmd) { case Opt_load: if (tpm2) ret = tpm_unseal_trusted(TPM_ANY_NUM, payload, options); else ret = key_unseal(payload, options); dump_payload(payload); dump_options(options); if (ret < 0) pr_info("trusted_key: key_unseal failed (%d)\n", ret); break; case Opt_new: key_len = payload->key_len; ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len); if (ret != key_len) { pr_info("trusted_key: key_create failed (%d)\n", ret); goto out; } if (tpm2) ret = tpm_seal_trusted(TPM_ANY_NUM, payload, options); else ret = key_seal(payload, options); if (ret < 0) pr_info("trusted_key: key_seal failed (%d)\n", ret); break; default: ret = -EINVAL; goto out; } if (!ret && options->pcrlock) ret = pcrlock(options->pcrlock); out: kfree(datablob); kfree(options); if (!ret) rcu_assign_keypointer(key, payload); else kfree(payload); return ret; }
/* can have zero or more token= options */ static int getoptions(char *c, struct trusted_key_payload *pay, struct trusted_key_options *opt) { substring_t args[MAX_OPT_ARGS]; char *p = c; int token; int res; 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; opt->digest_len = hash_digest_size[opt->hash]; while ((p = strsep(&c, " \t"))) { if (*p == '\0' || *p == ' ' || *p == '\t') continue; token = match_token(p, key_tokens, args); if (test_and_set_bit(token, &token_mask)) return -EINVAL; switch (token) { case Opt_pcrinfo: opt->pcrinfo_len = strlen(args[0].from) / 2; if (opt->pcrinfo_len > MAX_PCRINFO_SIZE) return -EINVAL; res = hex2bin(opt->pcrinfo, args[0].from, opt->pcrinfo_len); if (res < 0) return -EINVAL; break; case Opt_keyhandle: res = kstrtoul(args[0].from, 16, &handle); if (res < 0) return -EINVAL; opt->keytype = SEAL_keytype; opt->keyhandle = handle; break; case Opt_keyauth: if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE) return -EINVAL; res = hex2bin(opt->keyauth, args[0].from, SHA1_DIGEST_SIZE); if (res < 0) return -EINVAL; break; case Opt_blobauth: if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE) return -EINVAL; res = hex2bin(opt->blobauth, args[0].from, SHA1_DIGEST_SIZE); if (res < 0) return -EINVAL; break; case Opt_migratable: if (*args[0].from == '0') pay->migratable = 0; else return -EINVAL; break; case Opt_pcrlock: res = kstrtoul(args[0].from, 10, &lock); if (res < 0) return -EINVAL; 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; } } 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; 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; } } return 0; }