From patchwork Tue Aug 21 15:59:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10572003 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B8E491390 for ; Tue, 21 Aug 2018 15:59:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A5B362A989 for ; Tue, 21 Aug 2018 15:59:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 99C702A9B4; Tue, 21 Aug 2018 15:59:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CBE6F2A9AE for ; Tue, 21 Aug 2018 15:59:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728178AbeHUTUL (ORCPT ); Tue, 21 Aug 2018 15:20:11 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:59600 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727031AbeHUTUL (ORCPT ); Tue, 21 Aug 2018 15:20:11 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CF77340201CA; Tue, 21 Aug 2018 15:59:26 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id BF1DE2156701; Tue, 21 Aug 2018 15:59:25 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 23/23] TPM: Add an asymmetric key subtype for handling TPM-based keys From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:59:25 +0100 Message-ID: <153486716525.13066.18042327896429419884.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 21 Aug 2018 15:59:26 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 21 Aug 2018 15:59:26 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: linux-integrity-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add an asymmetric key subtype for handling keys that have to be loaded into the TPM to be used. A key can be created by something like: keyctl add asymmetric "a" "tpm_create parent=40000000,095c2a76085f6aa9327c62f72a3d1348f62b99db keyauth=095c2a76085f6aa9327c62f72a3d1348f62b99db" @s where "parent=," and "keyauth=". The above will ask the TPM to create a key and return the TPM_KEY struct as a blob with the private key encrypted by the parent key (in the above case, the SRK). Signed-off-by: David Howells --- crypto/asymmetric_keys/Kconfig | 7 + crypto/asymmetric_keys/Makefile | 1 crypto/asymmetric_keys/tpm_key.c | 73 +++++++++++ crypto/asymmetric_keys/tpm_key.h | 19 +++ crypto/asymmetric_keys/tpm_key_parser.c | 212 +++++++++++++++++++++++++++++++ 5 files changed, 312 insertions(+) create mode 100644 crypto/asymmetric_keys/tpm_key.c create mode 100644 crypto/asymmetric_keys/tpm_key.h create mode 100644 crypto/asymmetric_keys/tpm_key_parser.c diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 4870f28403f5..97d1bb714617 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -67,4 +67,11 @@ config SIGNED_PE_FILE_VERIFICATION This option provides support for verifying the signature(s) on a signed PE binary. +config ASYMMETRIC_TPM_KEY_SUBTYPE + tristate "Asymmetric TPM-based public-key crypto algorithm subtype" + depends on TCG_TPM + help + This option provides support for TPM hardware-based asymmetric public + key type handling. + endif # ASYMMETRIC_KEY_TYPE diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index e47fcd9ac5e8..690c16a517a9 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o asymmetric_keys-y := asymmetric_type.o signature.o obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o +obj-$(CONFIG_ASYMMETRIC_TPM_KEY_SUBTYPE) += tpm_key.o tpm_key_parser.o obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o # diff --git a/crypto/asymmetric_keys/tpm_key.c b/crypto/asymmetric_keys/tpm_key.c new file mode 100644 index 000000000000..bfddedc9db32 --- /dev/null +++ b/crypto/asymmetric_keys/tpm_key.c @@ -0,0 +1,73 @@ +/* In-TPM asymmetric public-key crypto subtype + * + * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#define pr_fmt(fmt) "TPK: "fmt +#include +#include +#include +#include +#include +#include +#include +#include "tpm_key.h" + +MODULE_LICENSE("GPL"); + +/* + * Provide a part of a description of the key for /proc/keys. + */ +static void tpm_key_describe(const struct key *asymmetric_key, + struct seq_file *m) +{ + struct tpm_asymmetric_key *key = asymmetric_key->payload.data; + struct tpm_wrapped_key *wrap; + + if (key && key->wrapped_key) { + wrap = key->wrapped_key; + seq_printf(m, "TPM.RSA %*phN", + wrap->pubkey_len, wrap->data + wrap->pubkey_offset); + } +} + +/* + * Destroy a TPM-based key. + */ +static void tpm_key_destroy(void *payload) +{ + struct tpm_asymmetric_key *key = payload; + + if (key) { + kfree(key->wrapped_key); + kfree(key); + tpm_library_unuse(); + } +} + +/* + * Verify a signature using a TPM-based key. + */ +static int tpm_key_verify_signature(const struct key *key, + const struct public_key_signature *sig) +{ + return -EOPNOTSUPP; +} + +/* + * Public key algorithm asymmetric key subtype + */ +struct asymmetric_key_subtype tpm_key_subtype = { + .owner = THIS_MODULE, + .name = "tpm_key", + .describe = tpm_key_describe, + .destroy = tpm_key_destroy, + .verify_signature = tpm_key_verify_signature, +}; +EXPORT_SYMBOL_GPL(tpm_key_subtype); diff --git a/crypto/asymmetric_keys/tpm_key.h b/crypto/asymmetric_keys/tpm_key.h new file mode 100644 index 000000000000..712221fee874 --- /dev/null +++ b/crypto/asymmetric_keys/tpm_key.h @@ -0,0 +1,19 @@ +/* TPM-based public key algorithm internals + * + * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +struct tpm_asymmetric_key { + struct tpm_wrapped_key *wrapped_key; + u32 parent_tpm_handle; + u8 parent_authdata[TPM_DIGEST_SIZE]; + u8 key_authdata[TPM_DIGEST_SIZE]; +}; + +extern struct asymmetric_key_subtype tpm_key_subtype; diff --git a/crypto/asymmetric_keys/tpm_key_parser.c b/crypto/asymmetric_keys/tpm_key_parser.c new file mode 100644 index 000000000000..efb53172b43d --- /dev/null +++ b/crypto/asymmetric_keys/tpm_key_parser.c @@ -0,0 +1,212 @@ +/* Instantiate a TPM key. + * + * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ +#define DEBUG +#define pr_fmt(fmt) "TPKP: "fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include "asymmetric_keys.h" +#include "tpm_key.h" + + +enum tpm_key_create_token { + opt_crt_err = -1, + opt_crt_parent, + opt_crt_keyauth, +}; + +static const match_table_t tpm_key_create_tokens = { + { opt_crt_parent, "parent=%x,%s"}, + { opt_crt_keyauth, "keyauth=%s"}, + { opt_crt_err, NULL} +}; + +/* + * Attempt to parse a key creation request. + */ +static int tpm_key_create(struct tpm_asymmetric_key *key, char *data) +{ + enum tpm_key_create_token token; + struct tpm_chip *chip; + unsigned long tmp, got = 0; + substring_t args[MAX_OPT_ARGS]; + uint32_t key_handle; + char *p; + int ret; + + pr_devel("==>%s(,%s)\n", __func__, data); + + while ((p = strsep(&data, " \t"))) { + if (*p == '\0' || *p == ' ' || *p == '\t') + continue; + token = match_token(p, tpm_key_create_tokens, args); + switch (token) { + case opt_crt_parent: + pr_devel("parent %ld %ld\n", + args[0].to - args[0].from, + args[1].to - args[1].from); + *args[0].to = 0; + ret = kstrtoul(args[0].from, 16, &tmp); + if (ret < 0) { + pr_devel("bad parent handle\n"); + return -EINVAL; + } + key->parent_tpm_handle = tmp; + if (args[1].to - args[1].from != TPM_DIGEST_SIZE * 2) { + pr_devel("parent auth wrong size\n"); + return -EINVAL; + } + if (hex2bin(key->parent_authdata, args[1].from, + TPM_DIGEST_SIZE) < 0) { + pr_devel("parent auth bad hex\n"); + return -EINVAL; + } + break; + + case opt_crt_keyauth: + pr_devel("keyauth\n"); + if (args[1].to - args[1].from != TPM_DIGEST_SIZE * 2) + return -EINVAL; + if (hex2bin(key->parent_authdata, args[1].from, + TPM_DIGEST_SIZE) < 0) + return -EINVAL; + break; + + case opt_crt_err: + pr_devel("Unknown token %s\n", p); + return -EINVAL; + } + got |= 1 << token; + } + + if ((got & 3) != 3) { + pr_devel("Missing mandatory args\n"); + return -EINVAL; + } + + chip = tpm_chip_find_get(TPM_ANY_NUM); + if (!chip) + return -ENODEV; + + /* Create a key and retrieve the partially encrypted blob. */ + ret = tpm_create_wrap_key(chip, TPM_ET_SRK, key->parent_tpm_handle, + key->parent_authdata, + key->key_authdata, + NULL, + &key->wrapped_key); + if (ret == -EBADMSG) + ret = -EIO; + + /* Attempt to load the key back as a check */ + ret = tpm_load_key2(chip, TPM_ET_SRK, key->parent_tpm_handle, + key->parent_authdata, key->wrapped_key, + &key_handle); + if (ret != 0) { + pr_devel("Couldn't load key back\n"); + goto out; + } + + ret = tpm_flush_specific(chip, key_handle, TPM_RT_KEY); + if (ret != 0) + pr_devel("Couldn't flush key handle\n"); + +out: + tpm_chip_put(chip); + pr_devel("<==%s() = %d\n", __func__, ret); + return ret; +} + +/* + * Attempt to parse a data blob for a key as a TPM key specification. + * + * We expect one of the following in the prep data: + * + * tpm_create parent=, keyauth= [options...] + * tpm_load parent=, data= [options...] + */ +static int tpm_key_preparse(struct key_preparsed_payload *prep) +{ + struct tpm_asymmetric_key *key; + char *data; + int ret; + + pr_devel("==>%s()\n", __func__); + + ret = tpm_library_use(); + if (ret < 0) + goto out; + + ret = -ENOMEM; + key = kzalloc(sizeof(*key), GFP_KERNEL); + if (!key) + goto out_free_tpmlib; + data = kmalloc(prep->datalen + 1, GFP_KERNEL); + if (!data) + goto out_free_key; + + memcpy(data, prep->data, prep->datalen); + data[prep->datalen] = 0; + if (memcmp(data, "tpm_create ", 11) == 0) { + ret = tpm_key_create(key, data + 11); + } else { + ret = -EBADMSG; + goto out_free_data; + } + + /* We're pinning the module by being linked against it */ + __module_get(tpm_key_subtype.owner); + prep->type_data[0] = &tpm_key_subtype; + //prep->type_data[1] = kids; + prep->payload[0] = key; + //prep->description = desc; + prep->quotalen = 100; + key = NULL; + tpm_library_use(); + +out_free_data: + kfree(data); +out_free_key: + kfree(key); +out_free_tpmlib: + tpm_library_unuse(); +out: + return ret; +} + +static struct asymmetric_key_parser tpm_key_parser = { + .owner = THIS_MODULE, + .name = "tpm", + .parse = tpm_key_preparse, +}; + +/* + * Module stuff + */ +static int __init tpm_key_init(void) +{ + return register_asymmetric_key_parser(&tpm_key_parser); +} + +static void __exit tpm_key_exit(void) +{ + unregister_asymmetric_key_parser(&tpm_key_parser); +} + +module_init(tpm_key_init); +module_exit(tpm_key_exit); + +MODULE_DESCRIPTION("TPM key parser"); +MODULE_LICENSE("GPL");