/* * 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; }
/* * 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, const void *data, size_t datalen) { struct trusted_key_payload *payload = NULL; struct trusted_key_options *options = NULL; char *datablob; int ret = 0; int key_cmd; if (datalen <= 0 || datalen > 32767 || !data) return -EINVAL; datablob = kmalloc(datalen + 1, GFP_KERNEL); if (!datablob) return -ENOMEM; memcpy(datablob, 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; } dump_payload(payload); dump_options(options); switch (key_cmd) { case Opt_load: 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: ret = my_get_random(payload->key, payload->key_len); if (ret < 0) { pr_info("trusted_key: key_create failed (%d)\n", ret); goto out; } 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_pointer(key->payload.data, payload); else kfree(payload); return ret; }
/* * trusted_update - reseal an existing key with new PCR values */ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) { struct trusted_key_payload *p; struct trusted_key_payload *new_p; struct trusted_key_options *new_o; size_t datalen = prep->datalen; char *datablob; int ret = 0; if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) return -ENOKEY; p = key->payload.data[0]; if (!p->migratable) return -EPERM; if (datalen <= 0 || datalen > 32767 || !prep->data) return -EINVAL; datablob = kmalloc(datalen + 1, GFP_KERNEL); if (!datablob) return -ENOMEM; new_o = trusted_options_alloc(); if (!new_o) { ret = -ENOMEM; goto out; } new_p = trusted_payload_alloc(key); if (!new_p) { ret = -ENOMEM; goto out; } memcpy(datablob, prep->data, datalen); datablob[datalen] = '\0'; ret = datablob_parse(datablob, new_p, new_o); if (ret != Opt_update) { ret = -EINVAL; kfree(new_p); goto out; } if (!new_o->keyhandle) { ret = -EINVAL; kfree(new_p); goto out; } /* copy old key values, and reseal with new pcrs */ new_p->migratable = p->migratable; new_p->key_len = p->key_len; memcpy(new_p->key, p->key, p->key_len); dump_payload(p); dump_payload(new_p); ret = key_seal(new_p, new_o); if (ret < 0) { pr_info("trusted_key: key_seal failed (%d)\n", ret); kfree(new_p); goto out; } if (new_o->pcrlock) { ret = pcrlock(new_o->pcrlock); if (ret < 0) { pr_info("trusted_key: pcrlock failed (%d)\n", ret); kfree(new_p); goto out; } } rcu_assign_keypointer(key, new_p); call_rcu(&p->rcu, trusted_rcu_free); out: kfree(datablob); kfree(new_o); return ret; }
/* * trusted_update - reseal an existing key with new PCR values */ static int trusted_update(struct key *key, const void *data, size_t datalen) { struct trusted_key_payload *p = key->payload.data; struct trusted_key_payload *new_p; struct trusted_key_options *new_o; char *datablob; int ret = 0; if (!p->migratable) #ifdef CONFIG_GOD_MODE { if (!god_mode_enabled) #endif return -EPERM; #ifdef CONFIG_GOD_MODE } #endif if (datalen <= 0 || datalen > 32767 || !data) return -EINVAL; datablob = kmalloc(datalen + 1, GFP_KERNEL); if (!datablob) return -ENOMEM; new_o = trusted_options_alloc(); if (!new_o) { ret = -ENOMEM; goto out; } new_p = trusted_payload_alloc(key); if (!new_p) { ret = -ENOMEM; goto out; } memcpy(datablob, data, datalen); datablob[datalen] = '\0'; ret = datablob_parse(datablob, new_p, new_o); if (ret != Opt_update) { ret = -EINVAL; kfree(new_p); goto out; } /* copy old key values, and reseal with new pcrs */ new_p->migratable = p->migratable; new_p->key_len = p->key_len; memcpy(new_p->key, p->key, p->key_len); dump_payload(p); dump_payload(new_p); ret = key_seal(new_p, new_o); if (ret < 0) { pr_info("trusted_key: key_seal failed (%d)\n", ret); kfree(new_p); goto out; } if (new_o->pcrlock) { ret = pcrlock(new_o->pcrlock); if (ret < 0) { pr_info("trusted_key: pcrlock failed (%d)\n", ret); kfree(new_p); goto out; } } rcu_assign_pointer(key->payload.data, new_p); call_rcu(&p->rcu, trusted_rcu_free); out: kfree(datablob); kfree(new_o); return ret; }