From: David Howells <dhowells@redhat.com>
To: keyrings@linux-nfs.org
Cc: linux-crypto@vger.kernel.org,
linux-security-module@vger.kernel.org,
linux-kernel@vger.kernel.org, dmitry.kasatkin@intel.com,
zohar@linux.vnet.ibm.com, arjan.van.de.ven@intel.com,
alan.cox@intel.com, David Howells <dhowells@redhat.com>
Subject: [PATCH 07/16] KEYS: Add a RSA crypto key subtype [ver #2]
Date: Tue, 29 Nov 2011 23:44:26 +0000 [thread overview]
Message-ID: <20111129234426.13625.10612.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <20111129234258.13625.21153.stgit@warthog.procyon.org.uk>
Add a key subtype for handling RSA crypto keys. For the moment it only
provides a signature verification facility.
Signed-off-by: David Howells <dhowells@redhat.com>
---
security/Kconfig | 9 +
security/keys/Makefile | 2
security/keys/crypto_rsa.h | 36 +++
security/keys/crypto_rsa_subtype.c | 371 ++++++++++++++++++++++++++++++++++++
4 files changed, 418 insertions(+), 0 deletions(-)
create mode 100644 security/keys/crypto_rsa.h
create mode 100644 security/keys/crypto_rsa_subtype.c
diff --git a/security/Kconfig b/security/Kconfig
index 48926af..4167b4f 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -72,6 +72,15 @@ config CRYPTO_KEY_DSA
This option makes DSA cryptographic keys available. They can be used
for signature verification.
+config CRYPTO_KEY_RSA
+ tristate "RSA key type"
+ depends on CRYPTO_KEY_TYPE
+ select CRYPTO
+ select MPILIB
+ help
+ This option makes RSA cryptographic keys available. They can be used
+ for signature verification.
+
config KEYS_DEBUG_PROC_KEYS
bool "Enable the /proc/keys file by which keys may be viewed"
depends on KEYS
diff --git a/security/keys/Makefile b/security/keys/Makefile
index 8c499b1..0cb7d08 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -17,9 +17,11 @@ obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/
obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o
obj-$(CONFIG_CRYPTO_KEY_DSA) += crypto_dsa.o
+obj-$(CONFIG_CRYPTO_KEY_RSA) += crypto_rsa.o
obj-$(CONFIG_KEYS_COMPAT) += compat.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSCTL) += sysctl.o
crypto_keys-y := crypto_type.o pgp_parse.o
crypto_dsa-y := crypto_dsa_subtype.o
+crypto_rsa-y := crypto_rsa_subtype.o
diff --git a/security/keys/crypto_rsa.h b/security/keys/crypto_rsa.h
new file mode 100644
index 0000000..2ec8edc
--- /dev/null
+++ b/security/keys/crypto_rsa.h
@@ -0,0 +1,36 @@
+/* RSA internal definitions
+ *
+ * Copyright (C) 2011 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 RSA_NPKEY 2 /* number of MPI's in an RSA public key */
+
+extern struct crypto_key_subtype RSA_crypto_key_subtype;
+extern struct crypto_key_subtype RSA_crypto_key_subtype_2;
+extern struct crypto_key_subtype RSA_crypto_key_subtype_3;
+
+/*
+ * public key record
+ */
+struct RSA_public_key {
+ struct pgp_parse_pubkey pgp;
+ union {
+ MPI pkey[RSA_NPKEY];
+ struct {
+ MPI n; /* RSA public modulus */
+ MPI e; /* RSA public encryption exponent */
+ };
+ };
+};
+
+struct RSA_payload {
+ u8 key_id[8]; /* ID of this key pair */
+ u8 key_id_size; /* Number of bytes in key_id */
+ struct RSA_public_key *public_key;
+};
diff --git a/security/keys/crypto_rsa_subtype.c b/security/keys/crypto_rsa_subtype.c
new file mode 100644
index 0000000..da0d4cf
--- /dev/null
+++ b/security/keys/crypto_rsa_subtype.c
@@ -0,0 +1,371 @@
+/* RSA crypto key subtype
+ *
+ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This file is derived from GnuPG.
+ * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#define DEBUG
+#define pr_fmt(fmt) "RSA: "fmt
+#include <keys/crypto-subtype.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mpi.h>
+#include <linux/pgp.h>
+#include <crypto/hash.h>
+#include "crypto_rsa.h"
+#define __KDEBUG
+#include "internal.h"
+
+MODULE_LICENSE("GPL");
+
+static inline void digest_putc(struct shash_desc *digest, uint8_t ch)
+{
+ crypto_shash_update(digest, &ch, 1);
+}
+
+/*
+ * Destroy the contents of a RSA payload
+ */
+static void RSA_destroy_payload(struct RSA_payload *rsa)
+{
+ int i;
+
+ if (rsa->public_key) {
+ for (i = 0; i < RSA_NPKEY; i++)
+ mpi_free(rsa->public_key->pkey[i]);
+ kfree(rsa->public_key);
+ }
+ kfree(rsa);
+}
+
+/*
+ * Calculate the public key ID (RFC4880 12.2)
+ */
+static void RSA_calc_pk_keyid(struct shash_desc *digest,
+ struct RSA_public_key *pk)
+{
+ unsigned n;
+ unsigned nb[RSA_NPKEY];
+ unsigned nn[RSA_NPKEY];
+ u8 *pp[RSA_NPKEY];
+ u32 a32;
+ int i;
+ int npkey = RSA_NPKEY;
+
+ kenter("");
+
+ n = (pk->pgp.version < PGP_KEY_VERSION_4) ? 8 : 6;
+ for (i = 0; i < npkey; i++) {
+ nb[i] = mpi_get_nbits(pk->pkey[i]);
+ pp[i] = mpi_get_buffer(pk->pkey[i], nn + i, NULL);
+ n += 2 + nn[i];
+ }
+
+ digest_putc(digest, 0x99); /* ctb */
+ digest_putc(digest, n >> 8); /* 16-bit header length */
+ digest_putc(digest, n);
+ digest_putc(digest, pk->pgp.version);
+
+ a32 = pk->pgp.creation_time;
+ digest_putc(digest, a32 >> 24);
+ digest_putc(digest, a32 >> 16);
+ digest_putc(digest, a32 >> 8);
+ digest_putc(digest, a32 >> 0);
+
+ if (pk->pgp.version < PGP_KEY_VERSION_4) {
+ u16 a16;
+
+ if( pk->pgp.expires_at)
+ a16 = (pk->pgp.expires_at - pk->pgp.creation_time) / 86400UL;
+ else
+ a16 = 0;
+ digest_putc(digest, a16 >> 8);
+ digest_putc(digest, a16 >> 0);
+ }
+
+ digest_putc(digest, pk->pgp.pubkey_algo);
+
+ for (i = 0; i < npkey; i++) {
+ digest_putc(digest, nb[i] >> 8);
+ digest_putc(digest, nb[i]);
+ crypto_shash_update(digest, pp[i], nn[i]);
+ kfree(pp[i]);
+ }
+
+ kleave("");
+}
+
+/*
+ * Calculate and check the public key ID fingerprint against the key ID
+ */
+static int RSA_get_fingerprint(struct RSA_payload *rsa,
+ struct RSA_public_key *pk,
+ char **_fingerprint)
+{
+ struct crypto_shash *tfm;
+ struct shash_desc *digest;
+ int digest_size, offset;
+ char *fingerprint;
+ u8 *raw_fingerprint;
+ int ret, i;
+
+ ret = -ENOMEM;
+ tfm = crypto_alloc_shash(pk->pgp.version < PGP_KEY_VERSION_4 ?
+ "md5" : "sha1", 0, 0);
+ if (!tfm)
+ goto cleanup;
+
+ digest = kmalloc(sizeof(*digest) + crypto_shash_descsize(tfm),
+ GFP_KERNEL);
+ if (!digest)
+ goto cleanup_tfm;
+
+ digest->tfm = tfm;
+ digest->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ ret = crypto_shash_init(digest);
+ if (ret < 0)
+ goto cleanup_hash;
+
+ RSA_calc_pk_keyid(digest, pk);
+
+ digest_size = crypto_shash_digestsize(tfm);
+
+ raw_fingerprint = kmalloc(digest_size, GFP_KERNEL);
+ if (!raw_fingerprint)
+ goto cleanup_hash;
+
+ ret = crypto_shash_final(digest, raw_fingerprint);
+ if (ret < 0)
+ goto cleanup_raw_fingerprint;
+
+ fingerprint = kmalloc(digest_size * 2 + 1, GFP_KERNEL);
+ if (!fingerprint)
+ goto cleanup_raw_fingerprint;
+
+ offset = digest_size - 8;
+ kdebug("offset %u/%u", offset, digest_size);
+
+ for (i = 0; i < digest_size; i++)
+ sprintf(fingerprint + i * 2, "%02x", raw_fingerprint[i]);
+ kdebug("fingerprint %s", fingerprint);
+
+ memcpy(&rsa->key_id, raw_fingerprint + offset, 8);
+ rsa->key_id_size = 8;
+
+ *_fingerprint = fingerprint;
+ fingerprint = NULL;
+ ret = 0;
+cleanup_raw_fingerprint:
+ kfree(raw_fingerprint);
+cleanup_hash:
+ kfree(digest);
+cleanup_tfm:
+ crypto_free_shash(tfm);
+cleanup:
+ kleave(" = %d", ret);
+ return ret;
+}
+
+struct RSA_pk_parse_context {
+ struct pgp_parse_context pgp;
+ struct RSA_payload *rsa;
+ struct RSA_public_key *pk;
+ char *fingerprint;
+};
+
+/*
+ * Extract a public key or subkey from the PGP stream.
+ */
+static int RSA_parse_public_key(struct pgp_parse_context *context,
+ enum pgp_packet_tag type,
+ u8 headerlen,
+ const u8 *data,
+ size_t datalen)
+{
+ struct RSA_pk_parse_context *ctx =
+ container_of(context, struct RSA_pk_parse_context, pgp);
+ struct RSA_payload *rsa = ctx->rsa;
+ struct RSA_public_key *pk;
+ int i, ret;
+
+ kenter(",%u,%u,,%zu", type, headerlen, datalen);
+
+ if (rsa->public_key) {
+ kleave(" = -ENOKEY [already]");
+ return -ENOKEY;
+ }
+
+ pk = kzalloc(sizeof(struct RSA_public_key), GFP_KERNEL);
+ if (!pk)
+ return -ENOMEM;
+
+ ret = pgp_parse_public_key(&data, &datalen, &pk->pgp);
+ if (pk->pgp.pubkey_algo != PGP_PUBKEY_RSA_ENC_OR_SIG &&
+ pk->pgp.pubkey_algo != PGP_PUBKEY_RSA_ENC_ONLY &&
+ pk->pgp.pubkey_algo != PGP_PUBKEY_RSA_SIG_ONLY) {
+ pr_debug("Ignoring non-RSA public key [%u]\n",
+ pk->pgp.pubkey_algo);
+ ret = -ENOKEY;
+ goto cleanup;
+ }
+
+ ret = -ENOMEM;
+ for (i = 0; i < RSA_NPKEY; i++) {
+ unsigned int remaining = datalen;
+ pk->pkey[i] = mpi_read_from_buffer(data, &remaining);
+ if (!pk->pkey[i])
+ goto cleanup;
+ data += remaining;
+ datalen -= remaining;
+ }
+
+ ret = RSA_get_fingerprint(rsa, pk, &ctx->fingerprint);
+ if (ret < 0)
+ goto cleanup;
+
+ rsa->public_key = pk;
+ kleave(" = 0 [use]");
+ return 0;
+
+cleanup:
+ kdebug("cleanup");
+ if (pk) {
+ for (i = 0; i < RSA_NPKEY; i++)
+ mpi_free(pk->pkey[i]);
+ kfree(pk);
+ }
+ kleave(" = %d", ret);
+ return ret;
+}
+
+/*
+ * Instantiate a RSA key
+ */
+static int RSA_instantiate(struct key *key,
+ const void *data, size_t datalen)
+{
+ struct RSA_pk_parse_context ctx;
+ struct RSA_payload *rsa;
+ int ret;
+
+ ret = key_payload_reserve(key, datalen);
+ if (ret < 0)
+ return ret;
+
+ rsa = kzalloc(sizeof(struct RSA_payload), GFP_KERNEL);
+ if (!rsa)
+ return -ENOMEM;
+
+ ctx.pgp.types_of_interest = 1 << PGP_PKT_PUBLIC_KEY;
+ ctx.pgp.process_packet = RSA_parse_public_key;
+ ctx.rsa = rsa;
+ ctx.pk = NULL;
+ ctx.fingerprint = NULL;
+
+ ret = pgp_parse_packets(data, datalen, &ctx.pgp);
+ if (ret < 0) {
+ RSA_destroy_payload(rsa);
+ kfree(ctx.fingerprint);
+ key_payload_reserve(key, 0);
+ return ret;
+ }
+
+ key->type_data.p[0] = &RSA_crypto_key_subtype;
+ key->type_data.p[1] = ctx.fingerprint;
+ key->payload.data = rsa;
+ return 0;
+}
+
+/*
+ * Destroy a RSA key
+ */
+static void RSA_destroy(struct key *key)
+{
+ if (key->payload.data)
+ RSA_destroy_payload(key->payload.data);
+}
+
+/*
+ * RSA crypto key subtype
+ */
+struct crypto_key_subtype RSA_crypto_key_subtype = {
+ .owner = THIS_MODULE,
+ .name = "rsa",
+ .pubkey_algo = PGP_PUBKEY_RSA_ENC_OR_SIG,
+ .info = CRYPTO_KEY_IS_PUBKEY_ALGO,
+ .instantiate = RSA_instantiate,
+ .destroy = RSA_destroy,
+};
+
+struct crypto_key_subtype RSA_crypto_key_subtype_2 = {
+ .owner = THIS_MODULE,
+ .name = "rsa",
+ .pubkey_algo = PGP_PUBKEY_RSA_ENC_ONLY,
+ .info = CRYPTO_KEY_IS_PUBKEY_ALGO,
+ .instantiate = RSA_instantiate,
+ .destroy = RSA_destroy,
+};
+
+struct crypto_key_subtype RSA_crypto_key_subtype_3 = {
+ .owner = THIS_MODULE,
+ .name = "rsa",
+ .pubkey_algo = PGP_PUBKEY_RSA_SIG_ONLY,
+ .info = CRYPTO_KEY_IS_PUBKEY_ALGO,
+ .instantiate = RSA_instantiate,
+ .destroy = RSA_destroy,
+};
+
+/*
+ * Module stuff
+ */
+static int __init RSA_init(void)
+{
+ int ret;
+
+ ret = register_crypto_key_subtype(&RSA_crypto_key_subtype);
+ if (ret < 0)
+ return ret;
+
+ ret = register_crypto_key_subtype(&RSA_crypto_key_subtype_2);
+ if (ret < 0)
+ goto error_1;
+
+ ret = register_crypto_key_subtype(&RSA_crypto_key_subtype_3);
+ if (ret < 0)
+ goto error_2;
+ return 0;
+
+error_2:
+ unregister_crypto_key_subtype(&RSA_crypto_key_subtype_2);
+error_1:
+ unregister_crypto_key_subtype(&RSA_crypto_key_subtype);
+ return ret;
+}
+
+static void __exit RSA_cleanup(void)
+{
+ unregister_crypto_key_subtype(&RSA_crypto_key_subtype);
+ unregister_crypto_key_subtype(&RSA_crypto_key_subtype_2);
+ unregister_crypto_key_subtype(&RSA_crypto_key_subtype_3);
+}
+
+module_init(RSA_init);
+module_exit(RSA_cleanup);
next prev parent reply other threads:[~2011-11-30 0:28 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-11-29 23:42 [RFC][PATCH 00/16] Crypto keys and module signing " David Howells
2011-11-29 23:43 ` [PATCH 01/16] MPILIB: Export some more symbols " David Howells
2011-11-29 23:43 ` [PATCH 02/16] MPILIB: Add a missing ENOMEM check " David Howells
2011-11-30 15:28 ` Serge Hallyn
2011-11-30 17:00 ` David Howells
2011-11-29 23:43 ` [PATCH 03/16] KEYS: Permit key_serial() to be called with a const key pointer " David Howells
2011-11-29 23:43 ` [PATCH 04/16] PGP: Add definitions (RFC 4880) and packet parser " David Howells
2011-12-04 16:03 ` Ben Hutchings
2011-12-05 11:21 ` David Howells
2011-11-29 23:44 ` [PATCH 05/16] KEYS: Create a key type that can be used for general cryptographic operations " David Howells
2011-11-29 23:44 ` [PATCH 06/16] KEYS: Add a DSA crypto key subtype " David Howells
2011-11-29 23:44 ` David Howells [this message]
2011-11-29 23:44 ` [PATCH 08/16] PGP: Add signature parser " David Howells
2011-11-29 23:44 ` [PATCH 09/16] KEYS: Add signature verification facility " David Howells
2011-11-29 23:45 ` [PATCH 10/16] KEYS: DSA key signature verification " David Howells
2011-11-29 23:45 ` [PATCH 11/16] KEYS: RSA " David Howells
2011-11-29 23:45 ` [PATCH 12/16] KEYS: Add a crypto key request function " David Howells
2011-11-29 23:45 ` [PATCH 13/16] KEYS: Provide a function to load keys from a PGP keyring blob " David Howells
2011-11-29 23:45 ` [PATCH 14/16] MODSIGN: Add indications of module ELF types " David Howells
2011-11-29 23:46 ` [PATCH 15/16] MODSIGN: Module ELF verifier " David Howells
2011-11-29 23:46 ` [PATCH 16/16] MODSIGN: Apply signature checking to modules on module load " David Howells
2011-11-30 11:01 ` [RFC][PATCH 00/16] Crypto keys and module signing " Greg KH
2011-12-05 11:32 ` H. Peter Anvin
2011-12-05 11:43 ` David Howells
2011-12-06 0:54 ` [Keyrings] " James Morris
2011-12-07 14:29 ` David Howells
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20111129234426.13625.10612.stgit@warthog.procyon.org.uk \
--to=dhowells@redhat.com \
--cc=alan.cox@intel.com \
--cc=arjan.van.de.ven@intel.com \
--cc=dmitry.kasatkin@intel.com \
--cc=keyrings@linux-nfs.org \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=zohar@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®