aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2014-07-22 17:18:18 +0100
committerDavid Howells <dhowells@redhat.com>2014-07-24 12:17:07 +0100
commit046cabedb6aeb3cd51cd052b95380b74377dbd5b (patch)
treed15f78660ab3d3dda568c55749c79dae500e123d
parent6c93b74dd0946f9aebff177bf3432225927b2096 (diff)
downloadlinux-modsign-pgp-parser.tar.gz
KEYS: Provide a function to load keys from a PGP keyring blobpgp-parser
Provide a function to load keys from a PGP keyring blob for use in initialising the module signing key keyring: int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, struct key *keyring); Descriptions are generated from user ID notes and key fingerprints. The keys will actually be identified by the ID calculated from the PGP data rather than by the description, so this shouldn't be a problem. The keys are attached to the keyring supplied. Looking as root in /proc/keys after the module signing keyring has been loaded: 383a00c1 I------ 1 perm 1f030000 0 0 asymmetri Red Hat, Inc. dbeca166: PGP.DSA dbeca166 [] Thanks to Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> for some pointing out some errors. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--crypto/asymmetric_keys/Kconfig10
-rw-r--r--crypto/asymmetric_keys/Makefile1
-rw-r--r--crypto/asymmetric_keys/pgp_preload.c118
-rw-r--r--include/linux/pgp_sig.h2
4 files changed, 131 insertions, 0 deletions
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index 5f58a54ed83136..dbb2145f1b1385 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -75,4 +75,14 @@ config PGP_TEST_KEY
This is intended for testing the PGP parser.
+config PGP_PRELOAD
+ bool "PGP public key preloading facility"
+ select PGP_LIBRARY
+ select CRYPTO_KEY_PGP_PARSER
+ select SYSTEM_TRUSTED_KEYRING
+ help
+ This option provides a facility for the kernel to preload PGP-wrapped
+ bundles of keys during boot. It is used by module signing to load
+ the module signing keys for example.
+
endif # ASYMMETRIC_KEY_TYPE
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index 857a0517fe11e9..1c72c5eb1a2c87 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -31,6 +31,7 @@ clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h
# PGP handling
#
obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o
+obj-$(CONFIG_PGP_PRELOAD) += pgp_preload.o
obj-$(CONFIG_PGP_KEY_PARSER) += pgp_key_parser.o
pgp_key_parser-y := \
diff --git a/crypto/asymmetric_keys/pgp_preload.c b/crypto/asymmetric_keys/pgp_preload.c
new file mode 100644
index 00000000000000..868b38ddc31f6a
--- /dev/null
+++ b/crypto/asymmetric_keys/pgp_preload.c
@@ -0,0 +1,118 @@
+/* Cryptographic key request handling
+ *
+ * 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.
+ *
+ * See Documentation/security/keys-crypto.txt
+ */
+
+#include <linux/module.h>
+#include <linux/key.h>
+#include <linux/pgp_sig.h>
+#include <linux/pgplib.h>
+#include <linux/err.h>
+#include <keys/asymmetric-type.h>
+
+struct preload_pgp_keys_context {
+ struct pgp_parse_context pgp;
+ key_ref_t keyring;
+ const u8 *key_start;
+ const u8 *key_end;
+ bool found_key;
+};
+
+/*
+ * Create a key.
+ */
+static int __init create_pgp_key(struct preload_pgp_keys_context *ctx)
+{
+ key_ref_t key;
+
+ key = key_create_or_update(ctx->keyring,
+ "asymmetric",
+ NULL,
+ ctx->key_start,
+ ctx->key_end - ctx->key_start,
+ ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW | KEY_USR_READ),
+ KEY_ALLOC_NOT_IN_QUOTA |
+ KEY_ALLOC_TRUSTED);
+ if (IS_ERR(key))
+ return PTR_ERR(key);
+
+ pr_notice("Loaded PGP key '%s'\n",
+ key_ref_to_ptr(key)->description);
+
+ key_ref_put(key);
+ return 0;
+}
+
+/*
+ * Extract a public key or subkey from the PGP stream.
+ */
+static int __init found_pgp_key(struct pgp_parse_context *context,
+ enum pgp_packet_tag type, u8 headerlen,
+ const u8 *data, size_t datalen)
+{
+ struct preload_pgp_keys_context *ctx =
+ container_of(context, struct preload_pgp_keys_context, pgp);
+ int ret;
+
+ if (ctx->found_key) {
+ ctx->key_end = data - headerlen;
+ ret = create_pgp_key(ctx);
+ if (ret < 0)
+ return ret;
+ }
+
+ ctx->key_start = data - headerlen;
+ ctx->found_key = true;
+ return 0;
+}
+
+/**
+ * preload_pgp_keys - Load keys from a PGP keyring blob
+ * @pgpdata: The PGP keyring blob containing the keys.
+ * @pgpdatalen: The size of the @pgpdata blob.
+ * @keyring: The keyring to add the new keys to.
+ *
+ * Preload a pack of keys from a PGP keyring blob.
+ *
+ * The keys have their descriptions generated from the user ID and fingerprint
+ * in the PGP stream. Since keys can be matched on their key IDs independently
+ * of the key description, the description is mostly irrelevant apart from the
+ * fact that keys of the same description displace one another from a keyring.
+ *
+ * The caller should override the current creds if they want the keys to be
+ * owned by someone other than the current process's owner. Keys will not be
+ * accounted towards the owner's quota.
+ *
+ * This function may only be called whilst the kernel is booting.
+ */
+int __init preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen,
+ struct key *keyring)
+{
+ struct preload_pgp_keys_context ctx;
+ int ret;
+
+ ctx.pgp.types_of_interest =
+ (1 << PGP_PKT_PUBLIC_KEY) | (1 << PGP_PKT_PUBLIC_SUBKEY);
+ ctx.pgp.process_packet = found_pgp_key;
+ ctx.keyring = make_key_ref(keyring, 1);
+ ctx.found_key = false;
+
+ ret = pgp_parse_packets(pgpdata, pgpdatalen, &ctx.pgp);
+ if (ret < 0)
+ return ret;
+
+ if (ctx.found_key) {
+ ctx.key_end = pgpdata + pgpdatalen;
+ return create_pgp_key(&ctx);
+ }
+ return 0;
+}
diff --git a/include/linux/pgp_sig.h b/include/linux/pgp_sig.h
index 0f6cb648b432bd..4d2c555b0ead2b 100644
--- a/include/linux/pgp_sig.h
+++ b/include/linux/pgp_sig.h
@@ -23,5 +23,7 @@ extern int pgp_verify_sig_end(struct pgp_sig_verify *ctx,
const u8 *sig, size_t siglen, bool *_trusted);
extern void pgp_verify_sig_cancel(struct pgp_sig_verify *ctx);
+extern __init int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen,
+ struct key *keyring);
#endif /* _LINUX_PGP_SIG_H */