From: David Howells <dhowells@redhat.com>
To: rusty@rustcorp.com.au
Cc: dhowells@redhat.com, dmitry.kasatkin@intel.com,
zohar@linux.vnet.ibm.com, jmorris@namei.org,
keyrings@linux-nfs.org, linux-security-module@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH 04/25] KEYS: Add signature verification facility
Date: Thu, 16 Aug 2012 02:34:57 +0100 [thread overview]
Message-ID: <20120816013456.872.6089.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <20120816013405.872.42381.stgit@warthog.procyon.org.uk>
Add a facility whereby a key subtype may be asked to verify a signature against
the data it is purported to have signed.
This adds four routines:
(1) struct crypto_key_verify_context *
verify_sig_begin(struct key *keyring, const void *sig, size_t siglen);
This sets up a verification context for the given signature using
information in that signature to select a key from the specified keyring
and to request a hash algorithm from the crypto layer.
(2) int verify_sig_add_data(struct crypto_key_verify_context *ctx,
const void *data, size_t datalen);
Incrementally supply data to be signed. May be called multiple times.
(3) int verify_sig_end(struct crypto_key_verify_context *ctx,
const void *sig, size_t siglen);
Complete the verification process and return the result. -EKEYREJECTED
will indicate that the verification failed and 0 will indicate success.
Other errors are also possible.
(4) void verify_sig_cancel(struct crypto_key_verify_context *ctx);
Cancel the verification process.
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/security/keys-crypto.txt | 100 ++++++++++++++++++++
include/keys/crypto-subtype.h | 36 +++++++
include/keys/crypto-type.h | 9 ++
security/keys/crypto/Makefile | 2
security/keys/crypto/crypto_keys.h | 1
security/keys/crypto/crypto_type.c | 2
security/keys/crypto/crypto_verify.c | 159 ++++++++++++++++++++++++++++++++
7 files changed, 304 insertions(+), 5 deletions(-)
create mode 100644 security/keys/crypto/crypto_verify.c
diff --git a/Documentation/security/keys-crypto.txt b/Documentation/security/keys-crypto.txt
index 97dee80..0a886ec 100644
--- a/Documentation/security/keys-crypto.txt
+++ b/Documentation/security/keys-crypto.txt
@@ -7,6 +7,7 @@ Contents:
- Overview.
- Key identification.
- Accessing crypto keys.
+ - Signature verification.
- Implementing crypto parsers.
- Implementing crypto subtypes.
@@ -89,6 +90,65 @@ This gives access to the key type:
struct key_type key_type_crypto;
+SIGNATURE VERIFICATION
+----------------------
+
+The four operations that can perform cryptographic signature verification,
+using one of a set of keys to provide the public key:
+
+ (1) Begin verification procedure.
+
+ struct crypto_key_verify_context *
+ verify_sig_begin(struct key *keyring, const void *sig, size_t siglen);
+
+ This function sets up a verification context from the information in the
+ signature and looks for a suitable key in the keyring. The signature blob
+ must be presented again at the end of the procedure. The keys will be
+ checked against parameters in the signature, and if the matching one is
+ not found then -ENOKEY will be returned.
+
+ The hashing algorithm, if such a thing applies, will be determined from
+ information in the signature and the appropriate crypto module will be
+ used. -ENOPKG will be returned if the hash algorithm is unavailable.
+
+ The return value is an opaque pointer to be passed to the other functions,
+ or a negative error code.
+
+ (2) Indicate data to be verified.
+
+ int verify_sig_add_data(struct crypto_key_verify_context *ctx,
+ const void *data, size_t datalen);
+
+ This function is used to shovel data to the verification procedure so that
+ it can load it into the hash, pass it to hardware or whatever is
+ appropriate for the algorithm being employed.
+
+ The data is not canonicalised for the document type specified in the
+ signature. The caller must do that.
+
+ It will return 0 if successful and a negative error code if not.
+
+ (3) Complete the verification process.
+
+ int verify_sig_end(struct crypto_key_verify_context *ctx,
+ const void *sig, size_t siglen);
+
+ This function performs the actual signature verification step and cleans
+ up the resources allocated at the beginning. The signature must be
+ presented again as some of the data therein may need to be added to the
+ internal hash.
+
+ It will return -EKEYREJECTED if the signature didn't match, 0 if
+ successful and may return other errors as appropriate.
+
+ (4) Cancel the verification process.
+
+ void verify_sig_cancel(struct crypto_key_verify_context *ctx);
+
+ This function cleans up the resources allocated at the beginning. This is
+ not necessary if verify_sig_end() was called.
+
+
===========================
IMPLEMENTING CRYPTO PARSERS
===========================
@@ -107,6 +167,8 @@ The parser definition structure looks like the following:
int (*instantiate)(struct key *key,
const void *data, size_t datalen);
+ struct crypto_key_verify_context *(*verify_sig_begin)(
+ struct key *keyring, const u8 *sig, size_t siglen);
};
The owner and name fields should be set to the owning module and the name of
@@ -135,6 +197,44 @@ but it is expected that at least one will be defined.
algorithm such as RSA and DSA this will likely be a printable hex version
of the key's fingerprint.
+ (2) verify_sig_begin().
+
+ This is similar in concept to the instantiate() function, except that it
+ is given a signature blob to parse rather than a key data blob.
+
+ If the data format is not recognised, -EBADMSG should be returned. If it
+ is recognised, but the signature verification process cannot for some
+ reason be set up, some other negative error code should be returned.
+ -ENOKEY should be used to indicate that no matching key is available and
+ -ENOPKG should be returned if the hash algorithm or the verification
+ algorithm are unavailable.
+
+ If successful, the parser should allocate a verification context and embed
+ the following struct in it:
+
+ struct crypto_key_verify_context {
+ struct key *key;
+ int (*add_data)(struct crypto_key_verify_context *ctx,
+ const void *data, size_t datalen);
+ int (*end)(struct crypto_key_verify_context *ctx,
+ const u8 *sig, size_t siglen);
+ void (*cancel)(struct crypto_key_verify_context *ctx);
+ };
+
+ and return a pointer to this to the caller, who will then pass it to the
+ verification operation wrappers described in the "Signature Verification"
+ section. The three operation pointers here correspond exactly to those
+ wrappers and are all mandatory. container_of() should be used to retrieve
+ the actual context.
+
+ Note that the crypto key type retains a reference on the parser module for
+ the lifetime of this context, though the operation pointers need not point
+ into this module.
+
+ The parser should also record a pointer to the key selected and take a
+ reference on that key with key_get().
+
+
Functions are provided to register and unregister parsers:
int register_crypto_key_parser(struct crypto_key_parser *parser);
diff --git a/include/keys/crypto-subtype.h b/include/keys/crypto-subtype.h
index 1f546e6..61a5338 100644
--- a/include/keys/crypto-subtype.h
+++ b/include/keys/crypto-subtype.h
@@ -34,8 +34,7 @@ struct crypto_key_subtype {
};
/*
- * Data parser. Called during instantiation and signature verification
- * initiation.
+ * Key data parser. Called during key instantiation.
*/
struct crypto_key_parser {
struct list_head link;
@@ -54,4 +53,37 @@ struct crypto_key_parser {
extern int register_crypto_key_parser(struct crypto_key_parser *);
extern void unregister_crypto_key_parser(struct crypto_key_parser *);
+/*
+ * Context base for signature verification methods. Allocated by the subtype
+ * and presumably embedded in something appropriate.
+ */
+struct crypto_sig_verify_context {
+ struct key *key;
+ struct crypto_sig_parser *parser;
+ int (*add_data)(struct crypto_sig_verify_context *ctx,
+ const void *data, size_t datalen);
+ int (*end)(struct crypto_sig_verify_context *ctx,
+ const u8 *sig, size_t siglen);
+ void (*cancel)(struct crypto_sig_verify_context *ctx);
+};
+
+/*
+ * Signature data parser. Called during signature verification initiation.
+ */
+struct crypto_sig_parser {
+ struct list_head link;
+ struct module *owner;
+ const char *name;
+
+ /* Attempt to recognise a signature blob and find a matching key.
+ *
+ * Return EBADMSG if not recognised.
+ */
+ struct crypto_sig_verify_context *(*verify_sig_begin)(
+ struct key *keyring, const u8 *sig, size_t siglen);
+};
+
+extern int register_crypto_sig_parser(struct crypto_sig_parser *);
+extern void unregister_crypto_sig_parser(struct crypto_sig_parser *);
+
#endif /* _KEYS_CRYPTO_SUBTYPE_H */
diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h
index 47c00c7..0fb362a 100644
--- a/include/keys/crypto-type.h
+++ b/include/keys/crypto-type.h
@@ -18,6 +18,15 @@
extern struct key_type key_type_crypto;
+struct crypto_sig_verify_context;
+extern struct crypto_sig_verify_context *verify_sig_begin(
+ struct key *key, const void *sig, size_t siglen);
+extern int verify_sig_add_data(struct crypto_sig_verify_context *ctx,
+ const void *data, size_t datalen);
+extern int verify_sig_end(struct crypto_sig_verify_context *ctx,
+ const void *sig, size_t siglen);
+extern void verify_sig_cancel(struct crypto_sig_verify_context *ctx);
+
/*
* The payload is at the discretion of the subtype.
*/
diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile
index 36db1d5..67001bc 100644
--- a/security/keys/crypto/Makefile
+++ b/security/keys/crypto/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o
-crypto_keys-y := crypto_type.o
+crypto_keys-y := crypto_type.o crypto_verify.o
diff --git a/security/keys/crypto/crypto_keys.h b/security/keys/crypto/crypto_keys.h
index eb11788..ab9b381 100644
--- a/security/keys/crypto/crypto_keys.h
+++ b/security/keys/crypto/crypto_keys.h
@@ -24,5 +24,4 @@ static inline const char *crypto_key_id(const struct key *key)
/*
* crypto_type.c
*/
-extern struct list_head crypto_key_parsers;
extern struct rw_semaphore crypto_key_parsers_sem;
diff --git a/security/keys/crypto/crypto_type.c b/security/keys/crypto/crypto_type.c
index e8f83a6..821db37 100644
--- a/security/keys/crypto/crypto_type.c
+++ b/security/keys/crypto/crypto_type.c
@@ -18,7 +18,7 @@
MODULE_LICENSE("GPL");
-LIST_HEAD(crypto_key_parsers);
+static LIST_HEAD(crypto_key_parsers);
DECLARE_RWSEM(crypto_key_parsers_sem);
/*
diff --git a/security/keys/crypto/crypto_verify.c b/security/keys/crypto/crypto_verify.c
new file mode 100644
index 0000000..d64f1c7
--- /dev/null
+++ b/security/keys/crypto/crypto_verify.c
@@ -0,0 +1,159 @@
+/* Signature verification with a crypto key
+ *
+ * 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 <keys/crypto-subtype.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include "crypto_keys.h"
+
+static LIST_HEAD(crypto_sig_parsers);
+
+/**
+ * verify_sig_begin - Initiate the use of a crypto key to verify a signature
+ * @keyring: The public keys to verify against
+ * @sig: The signature data
+ * @siglen: The signature length
+ *
+ * Returns a context or an error.
+ */
+struct crypto_sig_verify_context *verify_sig_begin(
+ struct key *keyring, const void *sig, size_t siglen)
+{
+ struct crypto_sig_verify_context *ret;
+ struct crypto_sig_parser *parser;
+
+ pr_devel("==>%s()\n", __func__);
+
+ if (siglen == 0 || !sig)
+ return ERR_PTR(-EINVAL);
+
+ down_read(&crypto_key_parsers_sem);
+
+ ret = ERR_PTR(-EBADMSG);
+ list_for_each_entry(parser, &crypto_sig_parsers, link) {
+ if (parser->verify_sig_begin) {
+ if (!try_module_get(parser->owner))
+ continue;
+
+ pr_debug("Trying parser '%s'\n", parser->name);
+
+ ret = parser->verify_sig_begin(keyring, sig, siglen);
+ if (IS_ERR(ret))
+ module_put(parser->owner);
+ else
+ ret->parser = parser;
+ if (ret != ERR_PTR(-EBADMSG)) {
+ pr_debug("Parser recognised the format"
+ " (ret %ld)\n",
+ PTR_ERR(ret));
+ break;
+ }
+ }
+ }
+
+ up_read(&crypto_key_parsers_sem);
+ pr_devel("<==%s() = %p\n", __func__, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(verify_sig_begin);
+
+/**
+ * verify_sig_add_data - Incrementally provide data to be verified
+ * @ctx: The context from verify_sig_begin()
+ * @data: Data
+ * @datalen: The amount of @data
+ *
+ * This may be called multiple times.
+ */
+int verify_sig_add_data(struct crypto_sig_verify_context *ctx,
+ const void *data, size_t datalen)
+{
+ return ctx->add_data(ctx, data, datalen);
+}
+EXPORT_SYMBOL_GPL(verify_sig_add_data);
+
+/**
+ * verify_sig_end - Finalise signature verification and return result
+ * @ctx: The context from verify_sig_begin()
+ * @sig: The signature data
+ * @siglen: The signature length
+ */
+int verify_sig_end(struct crypto_sig_verify_context *ctx,
+ const void *sig, size_t siglen)
+{
+ struct crypto_sig_parser *parser = ctx->parser;
+ int ret;
+
+ ret = ctx->end(ctx, sig, siglen);
+ module_put(parser->owner);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(verify_sig_end);
+
+/**
+ * verify_sig_end - Cancel signature verification
+ * @ctx: The context from verify_sig_begin()
+ */
+void verify_sig_cancel(struct crypto_sig_verify_context *ctx)
+{
+ struct crypto_sig_parser *parser = ctx->parser;
+
+ ctx->cancel(ctx);
+ module_put(parser->owner);
+}
+EXPORT_SYMBOL_GPL(verify_sig_cancel);
+
+/**
+ * register_crypto_sig_parser - Register a crypto sig blob parser
+ * @parser: The parser to register
+ */
+int register_crypto_sig_parser(struct crypto_sig_parser *parser)
+{
+ struct crypto_sig_parser *cursor;
+ int ret;
+
+ down_write(&crypto_key_parsers_sem);
+
+ list_for_each_entry(cursor, &crypto_sig_parsers, link) {
+ if (strcmp(cursor->name, parser->name) == 0) {
+ pr_err("Crypto signature parser '%s' already registered\n",
+ parser->name);
+ ret = -EEXIST;
+ goto out;
+ }
+ }
+
+ list_add_tail(&parser->link, &crypto_sig_parsers);
+
+ pr_notice("Crypto signature parser '%s' registered\n", parser->name);
+ ret = 0;
+
+out:
+ up_write(&crypto_key_parsers_sem);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_crypto_sig_parser);
+
+/**
+ * unregister_crypto_sig_parser - Unregister a crypto sig blob parser
+ * @parser: The parser to unregister
+ */
+void unregister_crypto_sig_parser(struct crypto_sig_parser *parser)
+{
+ down_write(&crypto_key_parsers_sem);
+ list_del(&parser->link);
+ up_write(&crypto_key_parsers_sem);
+
+ pr_notice("Crypto signature parser '%s' unregistered\n", parser->name);
+}
+EXPORT_SYMBOL_GPL(unregister_crypto_sig_parser);
next prev parent reply other threads:[~2012-08-16 1:35 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-08-16 1:34 [PATCH 00/25] Crypto keys and module signing David Howells
2012-08-16 1:34 ` [PATCH 01/25] KEYS: Add payload preparsing opportunity prior to key instantiate or update David Howells
2012-08-16 1:34 ` [PATCH 02/25] MPILIB: Provide count_leading/trailing_zeros() based on arch functions David Howells
2012-09-10 7:13 ` Kasatkin, Dmitry
2012-09-13 5:14 ` James Morris
2012-09-13 14:09 ` Kasatkin, Dmitry
2012-08-16 1:34 ` [PATCH 03/25] KEYS: Create a key type that can be used for general cryptographic operations David Howells
2012-08-16 1:34 ` David Howells [this message]
2012-08-16 1:35 ` [PATCH 05/25] KEYS: Asymmetric public-key algorithm crypto key subtype David Howells
2012-08-16 1:35 ` [PATCH 06/25] MPILIB: Reinstate mpi_cmp[_ui]() and export for RSA signature verification David Howells
2012-08-16 1:35 ` [PATCH 07/25] KEYS: RSA: Implement signature verification algorithm [PKCS#1 / RFC3447] David Howells
2012-08-16 1:35 ` [PATCH 08/25] KEYS: RSA: Fix signature verification for shorter signatures David Howells
2012-08-16 1:35 ` [PATCH 09/25] PGPLIB: PGP definitions (RFC 4880) David Howells
2012-08-16 1:36 ` [PATCH 10/25] PGPLIB: Basic packet parser David Howells
2012-08-16 1:36 ` [PATCH 11/25] PGPLIB: Signature parser David Howells
2012-08-16 1:36 ` [PATCH 12/25] KEYS: PGP data parser David Howells
2012-08-16 1:36 ` [PATCH 13/25] KEYS: PGP-based public key signature verification David Howells
2012-08-16 1:36 ` [PATCH 14/25] KEYS: PGP format signature parser David Howells
2012-08-16 1:36 ` [PATCH 15/25] KEYS: Provide PGP key description autogeneration David Howells
2012-08-16 1:37 ` [PATCH 16/25] KEYS: Provide a function to load keys from a PGP keyring blob David Howells
2012-08-16 1:37 ` [PATCH 17/25] MODSIGN: Provide gitignore and make clean rules for extra files David Howells
2012-08-16 1:37 ` [PATCH 18/25] MODSIGN: Provide Documentation and Kconfig options David Howells
2012-08-16 1:37 ` [PATCH 19/25] MODSIGN: Sign modules during the build process David Howells
2012-08-16 1:37 ` [PATCH 20/25] MODSIGN: Provide module signing public keys to the kernel David Howells
2012-08-31 14:33 ` Michal Marek
2012-08-16 1:38 ` [PATCH 21/25] MODSIGN: Module signature verification David Howells
2012-08-16 1:38 ` [PATCH 22/25] MODSIGN: Automatically generate module signing keys if missing David Howells
2012-08-16 1:38 ` [PATCH 23/25] MODSIGN: Panic the kernel if FIPS is enabled upon module signing failure David Howells
2012-08-16 1:38 ` [PATCH 24/25] MODSIGN: Allow modules to be signed with an unknown key unless enforcing David Howells
2012-08-16 1:38 ` [PATCH 25/25] MODSIGN: Fix documentation of signed-nokey behavior when not enforcing David Howells
2012-08-21 5:04 ` [PATCH 00/25] Crypto keys and module signing Rusty Russell
2012-08-22 10:50 ` David Howells
2012-08-22 11:52 ` Mimi Zohar
2012-08-22 16:07 ` Kasatkin, Dmitry
2012-09-04 5:55 ` [RFC] module: signature infrastructure Rusty Russell
2012-09-04 12:07 ` Kasatkin, Dmitry
2012-09-04 12:21 ` Kasatkin, Dmitry
2012-09-04 13:40 ` Mimi Zohar
2012-09-05 0:29 ` Rusty Russell
2012-09-05 13:34 ` Mimi Zohar
2012-09-06 2:05 ` Rusty Russell
2012-09-04 14:25 ` Lucas De Marchi
2012-09-04 15:04 ` Kasatkin, Dmitry
2012-09-05 0:19 ` Rusty Russell
2012-09-05 23:41 ` Lucas De Marchi
2012-09-06 7:55 ` Rusty Russell
2012-09-04 22:51 ` David Howells
2012-09-04 23:17 ` Kasatkin, Dmitry
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=20120816013456.872.6089.stgit@warthog.procyon.org.uk \
--to=dhowells@redhat.com \
--cc=dmitry.kasatkin@intel.com \
--cc=jmorris@namei.org \
--cc=keyrings@linux-nfs.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=rusty@rustcorp.com.au \
--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
Powered by JetHome