linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/25] Crypto keys and module signing
@ 2012-08-16  1:34 David Howells
  2012-08-16  1:34 ` [PATCH 01/25] KEYS: Add payload preparsing opportunity prior to key instantiate or update David Howells
                   ` (27 more replies)
  0 siblings, 28 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:34 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel


Hi Rusty,

I've posted new versions of my module signing patches to my GIT trees.

The patches with (approximately) your preferred way of attaching the signature
can be found here and I've followed this message with them:

	http://git.kernel.org/?p=linux/kernel/git/dhowells/linux-modsign.git;a=shortlog;h=refs/heads/modsign-rusty

And using an ELF note can be found here:

	http://git.kernel.org/?p=linux/kernel/git/dhowells/linux-modsign.git;a=shortlog;h=refs/heads/modsign

A slightly older version of the latter patches are being used in Fedora 18 and
Rawhide kernels.  I'm still doing some development on them to get X.509 and
PKCS#7 working with module signing for UEFI purposes.

If you look here, you can find most of an X.509 key parser:

	http://git.kernel.org/?p=linux/kernel/git/dhowells/linux-modsign.git;a=shortlog;h=refs/heads/devel-x509

I'm also working on a PKCS#7 signature parser and have a chunk of it working,
though it's not ready for release yet.  At the moment, I can add X.509
certificates as public keys like so:

	keyctl padd crypto "" @s </tmp/x509.cert

giving something like:

	102492b2 I--Q---     1 perm 39390000     0     0 crypto    bfbc0cd76d050ea4:/C=GB/L=Cambridge/O=Red Hat/CN=kernel key: X509.RSA 0c688c7b []

David
---

Changes made 16/08/2012:

 (*) Improvements for key handling:

     - Made it possible to pre-parse a payload blob without locks held.
     - Made it possible for a key to name itself if the adder doesn't give a
       description.
     - Preloaded keys are now named from their contents.

 (*) Fixes for the PGP/keys handling parts:
     
     - Put the signature parsers onto their own list, separate from the key
       parsers.  This makes PKCS#7 simpler.
     - Don't crash in RSA if given an unsupported digest type.
     - Various compile fixes [Thanks to Fengguang Wu].
     - Reverted a removal of a piece of MPILIB for a required check in the RSA
       algorithm as used from PGP.

 (*) Generalised asm/module.h.  Created Kconfig keys for the REL/RELA choice.

 (*) Fixes for testing in Fedora:

     - Adjusted the module signing policy to permit modules with unknown keys
       if we permit unsigned modules.

Changes made 22/05/2012:

 (*) Fixes for the PGP/keys handling parts:

     - Fix some checkpatch noise [Thanks to Tetsuo Handa].
     - Preclear array on stack [Thanks to Tetsuo Handa].
     - Check (sub)packet length [Thanks to Stephan Mueller].
     - Decrease (not increase) remnant length in signature parsing.
     - Handle new-format 5-octet length encoding.
     - Better report encounter of Partial Body Length spec.
     - Adjust the error handling.

 (*) Completely redo how signature is attached to the module file to comply
     with Rusty's specified method.  Also pre-strip modules.

 (*) Drop the MPILIB extra-exports patch as it's only required for the DSA
     algorithm.

Changes made 10/05/2012:

 (*) Overhauled the ELF checking code and module signing code.

     - Moved into one file.
     - Removed a lot of redundant ELF checks, relying a lot on the signature to
       catch stuff.
     - Rearranged the ELF checker function.
     - Commented thoroughly and documented things better in the commit messages.
     - Made it possible to exclude REL or RELA relocation handling.
     - Rearranged the modsign patch subset to be more logical.
     - Massively reduced the code size.

 (*) Applied a patch to handle short signatures.

 (*) Fixed a potential overflow in a check in the core module code.

Changes made 07/12/2011:

 (*) Dropped the DSA algorithm.

Changes made 02/12/2011:

 (*) Completely overhauled the architecture.

     - Introduced data parsers.
     - Reduced subtype to cryptographic data carrier.
     - Extracted out the common PGP bits of DSA and RSA algorithms.
     - Defined an asymmetric public-key subtype.
     - Reduced DSA and RSA algorithms to minimum.
     - Rolled verification initiation and key selection together into one.
     - Moved verification add_data/finish/cancel op pointers into verification
       context.

Changes made 29/11/2011:

 (*) Added RSA signature verification.

 (*) Stopped signature verification crashing on unsupported hash algorithm.

 (*) Fixed ENOMEM handling bug in MPI.

 (*) Worked around ccache problems with compilation of PGP public keyring into
     kernel (ccache hashes the preprocessor output, but the assembler includes
     the binary data, so ccache doesn't see that it changed).

 (*) Added a choice in kernel config for hash algorithm to use; forced the
     appropriate crypto module to be built directly into the kernel.

 (*) Cleaned out some debugging code.

 (*) Updated documentation.

---
David Howells (23):
      MODSIGN: Panic the kernel if FIPS is enabled upon module signing failure
      MODSIGN: Automatically generate module signing keys if missing
      MODSIGN: Module signature verification
      MODSIGN: Provide module signing public keys to the kernel
      MODSIGN: Sign modules during the build process
      MODSIGN: Provide Documentation and Kconfig options
      MODSIGN: Provide gitignore and make clean rules for extra files
      KEYS: Provide a function to load keys from a PGP keyring blob
      KEYS: Provide PGP key description autogeneration
      KEYS: PGP format signature parser
      KEYS: PGP-based public key signature verification
      KEYS: PGP data parser
      PGPLIB: Signature parser
      PGPLIB: Basic packet parser
      PGPLIB: PGP definitions (RFC 4880)
      KEYS: RSA: Fix signature verification for shorter signatures
      KEYS: RSA: Implement signature verification algorithm [PKCS#1 / RFC3447]
      MPILIB: Reinstate mpi_cmp[_ui]() and export for RSA signature verification
      KEYS: Asymmetric public-key algorithm crypto key subtype
      KEYS: Add signature verification facility
      KEYS: Create a key type that can be used for general cryptographic operations
      MPILIB: Provide count_leading/trailing_zeros() based on arch functions
      KEYS: Add payload preparsing opportunity prior to key instantiate or update

Josh Boyer (1):
      MODSIGN: Allow modules to be signed with an unknown key unless enforcing

Peter Jones (1):
      MODSIGN: Fix documentation of signed-nokey behavior when not enforcing.


 .gitignore                               |   13 +
 Documentation/module-signing.txt         |  183 ++++++++++
 Documentation/security/keys-crypto.txt   |  301 ++++++++++++++++
 Documentation/security/keys.txt          |   50 +++
 Makefile                                 |    1 
 fs/cifs/cifs_spnego.c                    |    6 
 fs/cifs/cifsacl.c                        |    8 
 include/asm-generic/bitops/count_zeros.h |   57 +++
 include/keys/crypto-subtype.h            |   89 +++++
 include/keys/crypto-type.h               |   37 ++
 include/keys/user-type.h                 |    6 
 include/linux/key-type.h                 |   35 ++
 include/linux/modsign.h                  |   27 +
 include/linux/module.h                   |    3 
 include/linux/pgp.h                      |  206 +++++++++++
 include/linux/pgplib.h                   |   72 ++++
 init/Kconfig                             |   62 +++
 kernel/Makefile                          |   42 ++
 kernel/modsign-pubkey.c                  |   74 ++++
 kernel/module-verify.c                   |  148 ++++++++
 kernel/module-verify.h                   |   20 +
 kernel/module.c                          |   26 +
 lib/mpi/Makefile                         |    1 
 lib/mpi/longlong.h                       |  138 --------
 lib/mpi/mpi-bit.c                        |    2 
 lib/mpi/mpi-cmp.c                        |   70 ++++
 lib/mpi/mpi-pow.c                        |    4 
 net/ceph/crypto.c                        |    9 
 net/dns_resolver/dns_key.c               |    6 
 net/rxrpc/ar-key.c                       |   40 +-
 scripts/Makefile.modpost                 |   99 +++++
 security/keys/Kconfig                    |    2 
 security/keys/Makefile                   |    1 
 security/keys/crypto/Kconfig             |   51 +++
 security/keys/crypto/Makefile            |   17 +
 security/keys/crypto/crypto_keys.h       |   27 +
 security/keys/crypto/crypto_rsa.c        |  275 +++++++++++++++
 security/keys/crypto/crypto_type.c       |  272 +++++++++++++++
 security/keys/crypto/crypto_verify.c     |  159 +++++++++
 security/keys/crypto/pgp_library.c       |  548 ++++++++++++++++++++++++++++++
 security/keys/crypto/pgp_parser.h        |   29 ++
 security/keys/crypto/pgp_preload.c       |  115 ++++++
 security/keys/crypto/pgp_public_key.c    |  386 +++++++++++++++++++++
 security/keys/crypto/pgp_sig_parser.c    |  136 +++++++
 security/keys/crypto/pgp_sig_verify.c    |  325 ++++++++++++++++++
 security/keys/crypto/public_key.c        |   82 ++++
 security/keys/crypto/public_key.h        |  125 +++++++
 security/keys/encrypted-keys/encrypted.c |   16 -
 security/keys/key.c                      |  108 ++++--
 security/keys/keyctl.c                   |   18 +
 security/keys/keyring.c                  |    6 
 security/keys/request_key_auth.c         |    8 
 security/keys/trusted.c                  |   16 -
 security/keys/user_defined.c             |   14 -
 54 files changed, 4325 insertions(+), 246 deletions(-)
 create mode 100644 Documentation/module-signing.txt
 create mode 100644 Documentation/security/keys-crypto.txt
 create mode 100644 include/asm-generic/bitops/count_zeros.h
 create mode 100644 include/keys/crypto-subtype.h
 create mode 100644 include/keys/crypto-type.h
 create mode 100644 include/linux/modsign.h
 create mode 100644 include/linux/pgp.h
 create mode 100644 include/linux/pgplib.h
 create mode 100644 kernel/modsign-pubkey.c
 create mode 100644 kernel/module-verify.c
 create mode 100644 kernel/module-verify.h
 create mode 100644 lib/mpi/mpi-cmp.c
 create mode 100644 security/keys/crypto/Kconfig
 create mode 100644 security/keys/crypto/Makefile
 create mode 100644 security/keys/crypto/crypto_keys.h
 create mode 100644 security/keys/crypto/crypto_rsa.c
 create mode 100644 security/keys/crypto/crypto_type.c
 create mode 100644 security/keys/crypto/crypto_verify.c
 create mode 100644 security/keys/crypto/pgp_library.c
 create mode 100644 security/keys/crypto/pgp_parser.h
 create mode 100644 security/keys/crypto/pgp_preload.c
 create mode 100644 security/keys/crypto/pgp_public_key.c
 create mode 100644 security/keys/crypto/pgp_sig_parser.c
 create mode 100644 security/keys/crypto/pgp_sig_verify.c
 create mode 100644 security/keys/crypto/public_key.c
 create mode 100644 security/keys/crypto/public_key.h


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH 01/25] KEYS: Add payload preparsing opportunity prior to key instantiate or update
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
@ 2012-08-16  1:34 ` David Howells
  2012-08-16  1:34 ` [PATCH 02/25] MPILIB: Provide count_leading/trailing_zeros() based on arch functions David Howells
                   ` (26 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:34 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Give the key type the opportunity to preparse the payload prior to the
instantiation and update routines being called.  This is done with the
provision of two new key type operations:

	int (*preparse)(struct key_preparsed_payload *prep);
	void (*free_preparse)(struct key_preparsed_payload *prep);

If the first operation is present, then it is called before key creation (in
the add/update case) or before the key semaphore is taken (in the update and
instantiate cases).  The second operation is called to clean up if the first
was called.

preparse() is given the opportunity to fill in the following structure:

	struct key_preparsed_payload {
		char		*description;
		void		*type_data[2];
		void		*payload;
		const void	*data;
		size_t		datalen;
		size_t		quotalen;
	};

Before the preparser is called, the first three fields will have been cleared,
the payload pointer and size will be stored in data and datalen and the default
quota size from the key_type struct will be stored into quotalen.

The preparser may parse the payload in any way it likes and may store data in
the type_data[] and payload fields for use by the instantiate() and update()
ops.

The preparser may also propose a description for the key by attaching it as a
string to the description field.  This can be used by passing a NULL or ""
description to the add_key() system call or the key_create_or_update()
function.  This cannot work with request_key() as that required the description
to tell the upcall about the key to be created.

This, for example permits keys that store PGP public keys to generate their own
name from the user ID and public key fingerprint in the key.

The instantiate() and update() operations are then modified to look like this:

	int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
	int (*update)(struct key *key, struct key_preparsed_payload *prep);

and the new payload data is passed in *prep, whether or not it was preparsed.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 Documentation/security/keys.txt          |   50 ++++++++++++++
 fs/cifs/cifs_spnego.c                    |    6 +-
 fs/cifs/cifsacl.c                        |    8 +-
 include/keys/user-type.h                 |    6 +-
 include/linux/key-type.h                 |   35 +++++++++-
 net/ceph/crypto.c                        |    9 +--
 net/dns_resolver/dns_key.c               |    6 +-
 net/rxrpc/ar-key.c                       |   40 ++++++-----
 security/keys/encrypted-keys/encrypted.c |   16 +++-
 security/keys/key.c                      |  108 +++++++++++++++++++++---------
 security/keys/keyctl.c                   |   18 ++++-
 security/keys/keyring.c                  |    6 +-
 security/keys/request_key_auth.c         |    8 +-
 security/keys/trusted.c                  |   16 +++-
 security/keys/user_defined.c             |   14 ++--
 15 files changed, 245 insertions(+), 101 deletions(-)


diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index aa0dbd7..7d9ca92 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -412,6 +412,10 @@ The main syscalls are:
      to the keyring. In this case, an error will be generated if the process
      does not have permission to write to the keyring.
 
+     If the key type supports it, if the description is NULL or an empty
+     string, the key type will try and generate a description from the content
+     of the payload.
+
      The payload is optional, and the pointer can be NULL if not required by
      the type. The payload is plen in size, and plen can be zero for an empty
      payload.
@@ -1114,12 +1118,53 @@ The structure has a number of fields, some of which are mandatory:
      it should return 0.
 
 
- (*) int (*instantiate)(struct key *key, const void *data, size_t datalen);
+ (*) int (*preparse)(struct key_preparsed_payload *prep);
+
+     This optional method permits the key type to attempt to parse payload
+     before a key is created (add key) or the key semaphore is taken (update or
+     instantiate key).  The structure pointed to by prep looks like:
+
+	struct key_preparsed_payload {
+		char		*description;
+		void		*type_data[2];
+		void		*payload;
+		const void	*data;
+		size_t		datalen;
+		size_t		quotalen;
+	};
+
+     Before calling the method, the caller will fill in data and datalen with
+     the payload blob parameters; quotalen will be filled in with the default
+     quota size from the key type and the rest will be cleared.
+
+     If a description can be proposed from the payload contents, that should be
+     attached as a string to the description field.  This will be used for the
+     key description if the caller of add_key() passes NULL or "".
+
+     The method can attach anything it likes to type_data[] and payload.  These
+     are merely passed along to the instantiate() or update() operations.
+
+     The method should return 0 if success ful or a negative error code
+     otherwise.
+
+     
+ (*) void (*free_preparse)(struct key_preparsed_payload *prep);
+
+     This method is only required if the preparse() method is provided,
+     otherwise it is unused.  It cleans up anything attached to the
+     description, type_data and payload fields of the key_preparsed_payload
+     struct as filled in by the preparse() method.
+
+
+ (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
 
      This method is called to attach a payload to a key during construction.
      The payload attached need not bear any relation to the data passed to this
      function.
 
+     The prep->data and prep->datalen fields will define the original payload
+     blob.  If preparse() was supplied then other fields may be filled in also.
+
      If the amount of data attached to the key differs from the size in
      keytype->def_datalen, then key_payload_reserve() should be called.
 
@@ -1135,6 +1180,9 @@ The structure has a number of fields, some of which are mandatory:
      If this type of key can be updated, then this method should be provided.
      It is called to update a key's payload from the blob of data provided.
 
+     The prep->data and prep->datalen fields will define the original payload
+     blob.  If preparse() was supplied then other fields may be filled in also.
+
      key_payload_reserve() should be called if the data length might change
      before any changes are actually made. Note that if this succeeds, the type
      is committed to changing the key because it's already been altered, so all
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
index e622863..086f381 100644
--- a/fs/cifs/cifs_spnego.c
+++ b/fs/cifs/cifs_spnego.c
@@ -31,18 +31,18 @@
 
 /* create a new cifs key */
 static int
-cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen)
+cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
 {
 	char *payload;
 	int ret;
 
 	ret = -ENOMEM;
-	payload = kmalloc(datalen, GFP_KERNEL);
+	payload = kmalloc(prep->datalen, GFP_KERNEL);
 	if (!payload)
 		goto error;
 
 	/* attach the data */
-	memcpy(payload, data, datalen);
+	memcpy(payload, prep->data, prep->datalen);
 	key->payload.data = payload;
 	ret = 0;
 
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 05f4dc2..f3c60e2 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -167,17 +167,17 @@ static struct shrinker cifs_shrinker = {
 };
 
 static int
-cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
+cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
 {
 	char *payload;
 
-	payload = kmalloc(datalen, GFP_KERNEL);
+	payload = kmalloc(prep->datalen, GFP_KERNEL);
 	if (!payload)
 		return -ENOMEM;
 
-	memcpy(payload, data, datalen);
+	memcpy(payload, prep->data, prep->datalen);
 	key->payload.data = payload;
-	key->datalen = datalen;
+	key->datalen = prep->datalen;
 	return 0;
 }
 
diff --git a/include/keys/user-type.h b/include/keys/user-type.h
index bc9ec1d..5e452c8 100644
--- a/include/keys/user-type.h
+++ b/include/keys/user-type.h
@@ -35,8 +35,10 @@ struct user_key_payload {
 extern struct key_type key_type_user;
 extern struct key_type key_type_logon;
 
-extern int user_instantiate(struct key *key, const void *data, size_t datalen);
-extern int user_update(struct key *key, const void *data, size_t datalen);
+struct key_preparsed_payload;
+
+extern int user_instantiate(struct key *key, struct key_preparsed_payload *prep);
+extern int user_update(struct key *key, struct key_preparsed_payload *prep);
 extern int user_match(const struct key *key, const void *criterion);
 extern void user_revoke(struct key *key);
 extern void user_destroy(struct key *key);
diff --git a/include/linux/key-type.h b/include/linux/key-type.h
index f0c651c..518a53a 100644
--- a/include/linux/key-type.h
+++ b/include/linux/key-type.h
@@ -26,6 +26,27 @@ struct key_construction {
 	struct key	*authkey;/* authorisation for key being constructed */
 };
 
+/*
+ * Pre-parsed payload, used by key add, update and instantiate.
+ *
+ * This struct will be cleared and data and datalen will be set with the data
+ * and length parameters from the caller and quotalen will be set from
+ * def_datalen from the key type.  Then if the preparse() op is provided by the
+ * key type, that will be called.  Then the struct will be passed to the
+ * instantiate() or the update() op.
+ *
+ * If the preparse() op is given, the free_preparse() op will be called to
+ * clear the contents.
+ */
+struct key_preparsed_payload {
+	char		*description;	/* Proposed key description (or NULL) */
+	void		*type_data[2];	/* Private key-type data */
+	void		*payload;	/* Proposed payload */
+	const void	*data;		/* Raw data */
+	size_t		datalen;	/* Raw datalen */
+	size_t		quotalen;	/* Quota length for proposed payload */
+};
+
 typedef int (*request_key_actor_t)(struct key_construction *key,
 				   const char *op, void *aux);
 
@@ -45,18 +66,28 @@ struct key_type {
 	/* vet a description */
 	int (*vet_description)(const char *description);
 
+	/* Preparse the data blob from userspace that is to be the payload,
+	 * generating a proposed description and payload that will be handed to
+	 * the instantiate() and update() ops.
+	 */
+	int (*preparse)(struct key_preparsed_payload *prep);
+
+	/* Free a preparse data structure.
+	 */
+	void (*free_preparse)(struct key_preparsed_payload *prep);
+
 	/* instantiate a key of this type
 	 * - this method should call key_payload_reserve() to determine if the
 	 *   user's quota will hold the payload
 	 */
-	int (*instantiate)(struct key *key, const void *data, size_t datalen);
+	int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
 
 	/* update a key of this type (optional)
 	 * - this method should call key_payload_reserve() to recalculate the
 	 *   quota consumption
 	 * - the key must be locked against read when modifying
 	 */
-	int (*update)(struct key *key, const void *data, size_t datalen);
+	int (*update)(struct key *key, struct key_preparsed_payload *prep);
 
 	/* match a key against a description */
 	int (*match)(const struct key *key, const void *desc);
diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c
index 9da7fdd..af14cb4 100644
--- a/net/ceph/crypto.c
+++ b/net/ceph/crypto.c
@@ -423,14 +423,15 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
 	}
 }
 
-int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
+int ceph_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
 {
 	struct ceph_crypto_key *ckey;
+	size_t datalen = prep->datalen;
 	int ret;
 	void *p;
 
 	ret = -EINVAL;
-	if (datalen <= 0 || datalen > 32767 || !data)
+	if (datalen <= 0 || datalen > 32767 || !prep->data)
 		goto err;
 
 	ret = key_payload_reserve(key, datalen);
@@ -443,8 +444,8 @@ int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
 		goto err;
 
 	/* TODO ceph_crypto_key_decode should really take const input */
-	p = (void *)data;
-	ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen);
+	p = (void *)prep->data;
+	ret = ceph_crypto_key_decode(ckey, &p, (char*)prep->data+datalen);
 	if (ret < 0)
 		goto err_ckey;
 
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
index d9507dd..859ab8b 100644
--- a/net/dns_resolver/dns_key.c
+++ b/net/dns_resolver/dns_key.c
@@ -59,13 +59,13 @@ const struct cred *dns_resolver_cache;
  *        "ip1,ip2,...#foo=bar"
  */
 static int
-dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
+dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
 {
 	struct user_key_payload *upayload;
 	unsigned long derrno;
 	int ret;
-	size_t result_len = 0;
-	const char *data = _data, *end, *opt;
+	size_t datalen = prep->datalen, result_len = 0;
+	const char *data = prep->data, *end, *opt;
 
 	kenter("%%%d,%s,'%*.*s',%zu",
 	       key->serial, key->description,
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
index 8b1f9f4..106c5a6 100644
--- a/net/rxrpc/ar-key.c
+++ b/net/rxrpc/ar-key.c
@@ -26,8 +26,8 @@
 #include "ar-internal.h"
 
 static int rxrpc_vet_description_s(const char *);
-static int rxrpc_instantiate(struct key *, const void *, size_t);
-static int rxrpc_instantiate_s(struct key *, const void *, size_t);
+static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *);
+static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *);
 static void rxrpc_destroy(struct key *);
 static void rxrpc_destroy_s(struct key *);
 static void rxrpc_describe(const struct key *, struct seq_file *);
@@ -678,7 +678,7 @@ error:
  *
  * if no data is provided, then a no-security key is made
  */
-static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
+static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep)
 {
 	const struct rxrpc_key_data_v1 *v1;
 	struct rxrpc_key_token *token, **pp;
@@ -686,26 +686,26 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
 	u32 kver;
 	int ret;
 
-	_enter("{%x},,%zu", key_serial(key), datalen);
+	_enter("{%x},,%zu", key_serial(key), prep->datalen);
 
 	/* handle a no-security key */
-	if (!data && datalen == 0)
+	if (!prep->data && prep->datalen == 0)
 		return 0;
 
 	/* determine if the XDR payload format is being used */
-	if (datalen > 7 * 4) {
-		ret = rxrpc_instantiate_xdr(key, data, datalen);
+	if (prep->datalen > 7 * 4) {
+		ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen);
 		if (ret != -EPROTO)
 			return ret;
 	}
 
 	/* get the key interface version number */
 	ret = -EINVAL;
-	if (datalen <= 4 || !data)
+	if (prep->datalen <= 4 || !prep->data)
 		goto error;
-	memcpy(&kver, data, sizeof(kver));
-	data += sizeof(kver);
-	datalen -= sizeof(kver);
+	memcpy(&kver, prep->data, sizeof(kver));
+	prep->data += sizeof(kver);
+	prep->datalen -= sizeof(kver);
 
 	_debug("KEY I/F VERSION: %u", kver);
 
@@ -715,11 +715,11 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
 
 	/* deal with a version 1 key */
 	ret = -EINVAL;
-	if (datalen < sizeof(*v1))
+	if (prep->datalen < sizeof(*v1))
 		goto error;
 
-	v1 = data;
-	if (datalen != sizeof(*v1) + v1->ticket_length)
+	v1 = prep->data;
+	if (prep->datalen != sizeof(*v1) + v1->ticket_length)
 		goto error;
 
 	_debug("SCIX: %u", v1->security_index);
@@ -784,17 +784,17 @@ error:
  * instantiate a server secret key
  * data should be a pointer to the 8-byte secret key
  */
-static int rxrpc_instantiate_s(struct key *key, const void *data,
-			       size_t datalen)
+static int rxrpc_instantiate_s(struct key *key,
+			       struct key_preparsed_payload *prep)
 {
 	struct crypto_blkcipher *ci;
 
-	_enter("{%x},,%zu", key_serial(key), datalen);
+	_enter("{%x},,%zu", key_serial(key), prep->datalen);
 
-	if (datalen != 8)
+	if (prep->datalen != 8)
 		return -EINVAL;
 
-	memcpy(&key->type_data, data, 8);
+	memcpy(&key->type_data, prep->data, 8);
 
 	ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(ci)) {
@@ -802,7 +802,7 @@ static int rxrpc_instantiate_s(struct key *key, const void *data,
 		return PTR_ERR(ci);
 	}
 
-	if (crypto_blkcipher_setkey(ci, data, 8) < 0)
+	if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
 		BUG();
 
 	key->payload.data = ci;
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 2d1bb8a..9e1e005 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -773,8 +773,8 @@ static int encrypted_init(struct encrypted_key_payload *epayload,
  *
  * On success, return 0. Otherwise return errno.
  */
-static int encrypted_instantiate(struct key *key, const void *data,
-				 size_t datalen)
+static int encrypted_instantiate(struct key *key,
+				 struct key_preparsed_payload *prep)
 {
 	struct encrypted_key_payload *epayload = NULL;
 	char *datablob = NULL;
@@ -782,16 +782,17 @@ static int encrypted_instantiate(struct key *key, const void *data,
 	char *master_desc = NULL;
 	char *decrypted_datalen = NULL;
 	char *hex_encoded_iv = NULL;
+	size_t datalen = prep->datalen;
 	int ret;
 
-	if (datalen <= 0 || datalen > 32767 || !data)
+	if (datalen <= 0 || datalen > 32767 || !prep->data)
 		return -EINVAL;
 
 	datablob = kmalloc(datalen + 1, GFP_KERNEL);
 	if (!datablob)
 		return -ENOMEM;
 	datablob[datalen] = 0;
-	memcpy(datablob, data, datalen);
+	memcpy(datablob, prep->data, datalen);
 	ret = datablob_parse(datablob, &format, &master_desc,
 			     &decrypted_datalen, &hex_encoded_iv);
 	if (ret < 0)
@@ -834,16 +835,17 @@ static void encrypted_rcu_free(struct rcu_head *rcu)
  *
  * On success, return 0. Otherwise return errno.
  */
-static int encrypted_update(struct key *key, const void *data, size_t datalen)
+static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
 {
 	struct encrypted_key_payload *epayload = key->payload.data;
 	struct encrypted_key_payload *new_epayload;
 	char *buf;
 	char *new_master_desc = NULL;
 	const char *format = NULL;
+	size_t datalen = prep->datalen;
 	int ret = 0;
 
-	if (datalen <= 0 || datalen > 32767 || !data)
+	if (datalen <= 0 || datalen > 32767 || !prep->data)
 		return -EINVAL;
 
 	buf = kmalloc(datalen + 1, GFP_KERNEL);
@@ -851,7 +853,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen)
 		return -ENOMEM;
 
 	buf[datalen] = 0;
-	memcpy(buf, data, datalen);
+	memcpy(buf, prep->data, datalen);
 	ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL);
 	if (ret < 0)
 		goto out;
diff --git a/security/keys/key.c b/security/keys/key.c
index 50d96d4..732a53e 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -412,8 +412,7 @@ EXPORT_SYMBOL(key_payload_reserve);
  * key_construction_mutex.
  */
 static int __key_instantiate_and_link(struct key *key,
-				      const void *data,
-				      size_t datalen,
+				      struct key_preparsed_payload *prep,
 				      struct key *keyring,
 				      struct key *authkey,
 				      unsigned long *_prealloc)
@@ -431,7 +430,7 @@ static int __key_instantiate_and_link(struct key *key,
 	/* can't instantiate twice */
 	if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
 		/* instantiate the key */
-		ret = key->type->instantiate(key, data, datalen);
+		ret = key->type->instantiate(key, prep);
 
 		if (ret == 0) {
 			/* mark the key as being instantiated */
@@ -482,22 +481,37 @@ int key_instantiate_and_link(struct key *key,
 			     struct key *keyring,
 			     struct key *authkey)
 {
+	struct key_preparsed_payload prep;
 	unsigned long prealloc;
 	int ret;
 
+	memset(&prep, 0, sizeof(prep));
+	prep.data = data;
+	prep.datalen = datalen;
+	prep.quotalen = key->type->def_datalen;
+	if (key->type->preparse) {
+		ret = key->type->preparse(&prep);
+		if (ret < 0)
+			goto error;
+	}
+
 	if (keyring) {
 		ret = __key_link_begin(keyring, key->type, key->description,
 				       &prealloc);
 		if (ret < 0)
-			return ret;
+			goto error_free_preparse;
 	}
 
-	ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey,
+	ret = __key_instantiate_and_link(key, &prep, keyring, authkey,
 					 &prealloc);
 
 	if (keyring)
 		__key_link_end(keyring, key->type, prealloc);
 
+error_free_preparse:
+	if (key->type->preparse)
+		key->type->free_preparse(&prep);
+error:
 	return ret;
 }
 
@@ -706,7 +720,7 @@ void key_type_put(struct key_type *ktype)
  * if we get an error.
  */
 static inline key_ref_t __key_update(key_ref_t key_ref,
-				     const void *payload, size_t plen)
+				     struct key_preparsed_payload *prep)
 {
 	struct key *key = key_ref_to_ptr(key_ref);
 	int ret;
@@ -722,7 +736,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
 
 	down_write(&key->sem);
 
-	ret = key->type->update(key, payload, plen);
+	ret = key->type->update(key, prep);
 	if (ret == 0)
 		/* updating a negative key instantiates it */
 		clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
@@ -774,6 +788,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 			       unsigned long flags)
 {
 	unsigned long prealloc;
+	struct key_preparsed_payload prep;
 	const struct cred *cred = current_cred();
 	struct key_type *ktype;
 	struct key *keyring, *key = NULL;
@@ -789,8 +804,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 	}
 
 	key_ref = ERR_PTR(-EINVAL);
-	if (!ktype->match || !ktype->instantiate)
-		goto error_2;
+	if (!ktype->match || !ktype->instantiate ||
+	    (!description && !ktype->preparse))
+		goto error_put_type;
 
 	keyring = key_ref_to_ptr(keyring_ref);
 
@@ -798,18 +814,33 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 
 	key_ref = ERR_PTR(-ENOTDIR);
 	if (keyring->type != &key_type_keyring)
-		goto error_2;
+		goto error_put_type;
+
+	memset(&prep, 0, sizeof(prep));
+	prep.data = payload;
+	prep.datalen = plen;
+	prep.quotalen = ktype->def_datalen;
+	if (ktype->preparse) {
+		ret = ktype->preparse(&prep);
+		if (ret < 0)
+			goto error_put_type;
+		if (!description)
+			description = prep.description;
+		ret = -EINVAL;
+		if (!description)
+			goto error_free_prep;
+	}
 
 	ret = __key_link_begin(keyring, ktype, description, &prealloc);
 	if (ret < 0)
-		goto error_2;
+		goto error_free_prep;
 
 	/* if we're going to allocate a new key, we're going to have
 	 * to modify the keyring */
 	ret = key_permission(keyring_ref, KEY_WRITE);
 	if (ret < 0) {
 		key_ref = ERR_PTR(ret);
-		goto error_3;
+		goto error_link_end;
 	}
 
 	/* if it's possible to update this type of key, search for an existing
@@ -840,25 +871,27 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 			perm, flags);
 	if (IS_ERR(key)) {
 		key_ref = ERR_CAST(key);
-		goto error_3;
+		goto error_link_end;
 	}
 
 	/* instantiate it and link it into the target keyring */
-	ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
-					 &prealloc);
+	ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &prealloc);
 	if (ret < 0) {
 		key_put(key);
 		key_ref = ERR_PTR(ret);
-		goto error_3;
+		goto error_link_end;
 	}
 
 	key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
 
- error_3:
+error_link_end:
 	__key_link_end(keyring, ktype, prealloc);
- error_2:
+error_free_prep:
+	if (ktype->preparse)
+		ktype->free_preparse(&prep);
+error_put_type:
 	key_type_put(ktype);
- error:
+error:
 	return key_ref;
 
  found_matching_key:
@@ -866,10 +899,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 	 * - we can drop the locks first as we have the key pinned
 	 */
 	__key_link_end(keyring, ktype, prealloc);
-	key_type_put(ktype);
 
-	key_ref = __key_update(key_ref, payload, plen);
-	goto error;
+	key_ref = __key_update(key_ref, &prep);
+	goto error_free_prep;
 }
 EXPORT_SYMBOL(key_create_or_update);
 
@@ -888,6 +920,7 @@ EXPORT_SYMBOL(key_create_or_update);
  */
 int key_update(key_ref_t key_ref, const void *payload, size_t plen)
 {
+	struct key_preparsed_payload prep;
 	struct key *key = key_ref_to_ptr(key_ref);
 	int ret;
 
@@ -900,18 +933,31 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
 
 	/* attempt to update it if supported */
 	ret = -EOPNOTSUPP;
-	if (key->type->update) {
-		down_write(&key->sem);
-
-		ret = key->type->update(key, payload, plen);
-		if (ret == 0)
-			/* updating a negative key instantiates it */
-			clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
+	if (!key->type->update)
+		goto error;
 
-		up_write(&key->sem);
+	memset(&prep, 0, sizeof(prep));
+	prep.data = payload;
+	prep.datalen = plen;
+	prep.quotalen = key->type->def_datalen;
+	if (key->type->preparse) {
+		ret = key->type->preparse(&prep);
+		if (ret < 0)
+			goto error;
 	}
 
- error:
+	down_write(&key->sem);
+
+	ret = key->type->update(key, &prep);
+	if (ret == 0)
+		/* updating a negative key instantiates it */
+		clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
+
+	up_write(&key->sem);
+
+	if (key->type->preparse)
+		key->type->free_preparse(&prep);
+error:
 	return ret;
 }
 EXPORT_SYMBOL(key_update);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 3364fbf..505d40b 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -46,6 +46,9 @@ static int key_get_type_from_user(char *type,
  * Extract the description of a new key from userspace and either add it as a
  * new key to the specified keyring or update a matching key in that keyring.
  *
+ * If the description is NULL or an empty string, the key type is asked to
+ * generate one from the payload.
+ *
  * The keyring must be writable so that we can attach the key to it.
  *
  * If successful, the new key's serial number is returned, otherwise an error
@@ -72,10 +75,17 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
 	if (ret < 0)
 		goto error;
 
-	description = strndup_user(_description, PAGE_SIZE);
-	if (IS_ERR(description)) {
-		ret = PTR_ERR(description);
-		goto error;
+	description = NULL;
+	if (_description) {
+		description = strndup_user(_description, PAGE_SIZE);
+		if (IS_ERR(description)) {
+			ret = PTR_ERR(description);
+			goto error;
+		}
+		if (!*description) {
+			kfree(description);
+			description = NULL;
+		}
 	}
 
 	/* pull the payload in if one was supplied */
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 81e7852..f04d8cf 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -66,7 +66,7 @@ static inline unsigned keyring_hash(const char *desc)
  * operations.
  */
 static int keyring_instantiate(struct key *keyring,
-			       const void *data, size_t datalen);
+			       struct key_preparsed_payload *prep);
 static int keyring_match(const struct key *keyring, const void *criterion);
 static void keyring_revoke(struct key *keyring);
 static void keyring_destroy(struct key *keyring);
@@ -121,12 +121,12 @@ static void keyring_publish_name(struct key *keyring)
  * Returns 0 on success, -EINVAL if given any data.
  */
 static int keyring_instantiate(struct key *keyring,
-			       const void *data, size_t datalen)
+			       struct key_preparsed_payload *prep)
 {
 	int ret;
 
 	ret = -EINVAL;
-	if (datalen == 0) {
+	if (prep->datalen == 0) {
 		/* make the keyring available by name if it has one */
 		keyring_publish_name(keyring);
 		ret = 0;
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 60d4e3f..85730d5 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -19,7 +19,8 @@
 #include <asm/uaccess.h>
 #include "internal.h"
 
-static int request_key_auth_instantiate(struct key *, const void *, size_t);
+static int request_key_auth_instantiate(struct key *,
+					struct key_preparsed_payload *);
 static void request_key_auth_describe(const struct key *, struct seq_file *);
 static void request_key_auth_revoke(struct key *);
 static void request_key_auth_destroy(struct key *);
@@ -42,10 +43,9 @@ struct key_type key_type_request_key_auth = {
  * Instantiate a request-key authorisation key.
  */
 static int request_key_auth_instantiate(struct key *key,
-					const void *data,
-					size_t datalen)
+					struct key_preparsed_payload *prep)
 {
-	key->payload.data = (struct request_key_auth *) data;
+	key->payload.data = (struct request_key_auth *)prep->data;
 	return 0;
 }
 
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 2d5d041..42036c7 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -927,22 +927,23 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
  *
  * On success, return 0. Otherwise return errno.
  */
-static int trusted_instantiate(struct key *key, const void *data,
-			       size_t datalen)
+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;
 
-	if (datalen <= 0 || datalen > 32767 || !data)
+	if (datalen <= 0 || datalen > 32767 || !prep->data)
 		return -EINVAL;
 
 	datablob = kmalloc(datalen + 1, GFP_KERNEL);
 	if (!datablob)
 		return -ENOMEM;
-	memcpy(datablob, data, datalen);
+	memcpy(datablob, prep->data, datalen);
 	datablob[datalen] = '\0';
 
 	options = trusted_options_alloc();
@@ -1011,17 +1012,18 @@ static void trusted_rcu_free(struct rcu_head *rcu)
 /*
  * trusted_update - reseal an existing key with new PCR values
  */
-static int trusted_update(struct key *key, const void *data, size_t datalen)
+static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
 {
 	struct trusted_key_payload *p = key->payload.data;
 	struct trusted_key_payload *new_p;
 	struct trusted_key_options *new_o;
+	size_t datalen = prep->datalen;
 	char *datablob;
 	int ret = 0;
 
 	if (!p->migratable)
 		return -EPERM;
-	if (datalen <= 0 || datalen > 32767 || !data)
+	if (datalen <= 0 || datalen > 32767 || !prep->data)
 		return -EINVAL;
 
 	datablob = kmalloc(datalen + 1, GFP_KERNEL);
@@ -1038,7 +1040,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
 		goto out;
 	}
 
-	memcpy(datablob, data, datalen);
+	memcpy(datablob, prep->data, datalen);
 	datablob[datalen] = '\0';
 	ret = datablob_parse(datablob, new_p, new_o);
 	if (ret != Opt_update) {
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index c7660a2..55dc889 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -58,13 +58,14 @@ EXPORT_SYMBOL_GPL(key_type_logon);
 /*
  * instantiate a user defined key
  */
-int user_instantiate(struct key *key, const void *data, size_t datalen)
+int user_instantiate(struct key *key, struct key_preparsed_payload *prep)
 {
 	struct user_key_payload *upayload;
+	size_t datalen = prep->datalen;
 	int ret;
 
 	ret = -EINVAL;
-	if (datalen <= 0 || datalen > 32767 || !data)
+	if (datalen <= 0 || datalen > 32767 || !prep->data)
 		goto error;
 
 	ret = key_payload_reserve(key, datalen);
@@ -78,7 +79,7 @@ int user_instantiate(struct key *key, const void *data, size_t datalen)
 
 	/* attach the data */
 	upayload->datalen = datalen;
-	memcpy(upayload->data, data, datalen);
+	memcpy(upayload->data, prep->data, datalen);
 	rcu_assign_keypointer(key, upayload);
 	ret = 0;
 
@@ -92,13 +93,14 @@ EXPORT_SYMBOL_GPL(user_instantiate);
  * update a user defined key
  * - the key's semaphore is write-locked
  */
-int user_update(struct key *key, const void *data, size_t datalen)
+int user_update(struct key *key, struct key_preparsed_payload *prep)
 {
 	struct user_key_payload *upayload, *zap;
+	size_t datalen = prep->datalen;
 	int ret;
 
 	ret = -EINVAL;
-	if (datalen <= 0 || datalen > 32767 || !data)
+	if (datalen <= 0 || datalen > 32767 || !prep->data)
 		goto error;
 
 	/* construct a replacement payload */
@@ -108,7 +110,7 @@ int user_update(struct key *key, const void *data, size_t datalen)
 		goto error;
 
 	upayload->datalen = datalen;
-	memcpy(upayload->data, data, datalen);
+	memcpy(upayload->data, prep->data, datalen);
 
 	/* check the quota and attach the new data */
 	zap = upayload;


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 02/25] MPILIB: Provide count_leading/trailing_zeros() based on arch functions
  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 ` David Howells
  2012-09-10  7:13   ` 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
                   ` (25 subsequent siblings)
  27 siblings, 1 reply; 48+ messages in thread
From: David Howells @ 2012-08-16  1:34 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Provide count_leading/trailing_zeros() macros based on extant arch bit scanning
functions rather than reimplementing from scratch in MPILIB.

Whilst we're at it, turn count_foo_zeros(n, x) into n = count_foo_zeros(x).

Also move the definition to asm-generic as other people may be interested in
using it.

Signed-off-by: David Howells <dhowells@redhat.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
Cc: Arnd Bergmann <arnd@arndb.com>
---

 include/asm-generic/bitops/count_zeros.h |   57 ++++++++++++
 lib/mpi/longlong.h                       |  138 ------------------------------
 lib/mpi/mpi-bit.c                        |    2 
 lib/mpi/mpi-pow.c                        |    4 -
 4 files changed, 62 insertions(+), 139 deletions(-)
 create mode 100644 include/asm-generic/bitops/count_zeros.h


diff --git a/include/asm-generic/bitops/count_zeros.h b/include/asm-generic/bitops/count_zeros.h
new file mode 100644
index 0000000..97520d2
--- /dev/null
+++ b/include/asm-generic/bitops/count_zeros.h
@@ -0,0 +1,57 @@
+/* Count leading and trailing zeros functions
+ *
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
+#define _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
+
+#include <asm/bitops.h>
+
+/**
+ * count_leading_zeros - Count the number of zeros from the MSB back
+ * @x: The value
+ *
+ * Count the number of leading zeros from the MSB going towards the LSB in @x.
+ *
+ * If the MSB of @x is set, the result is 0.
+ * If only the LSB of @x is set, then the result is BITS_PER_LONG-1.
+ * If @x is 0 then the result is COUNT_LEADING_ZEROS_0.
+ */
+static inline int count_leading_zeros(unsigned long x)
+{
+	if (sizeof(x) == 4)
+		return BITS_PER_LONG - fls(x);
+	else
+		return BITS_PER_LONG - fls64(x);
+}
+
+#define COUNT_LEADING_ZEROS_0 BITS_PER_LONG
+
+/**
+ * count_trailing_zeros - Count the number of zeros from the LSB forwards
+ * @x: The value
+ *
+ * Count the number of trailing zeros from the LSB going towards the MSB in @x.
+ *
+ * If the LSB of @x is set, the result is 0.
+ * If only the MSB of @x is set, then the result is BITS_PER_LONG-1.
+ * If @x is 0 then the result is COUNT_TRAILING_ZEROS_0.
+ */
+static inline int count_trailing_zeros(unsigned long x)
+{
+#define COUNT_TRAILING_ZEROS_0 (-1)
+
+	if (sizeof(x) == 4)
+		return ffs(x);
+	else
+		return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0;
+}
+
+#endif /* _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ */
diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h
index 29f9862..678ce4f 100644
--- a/lib/mpi/longlong.h
+++ b/lib/mpi/longlong.h
@@ -19,6 +19,8 @@
  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  * MA 02111-1307, USA. */
 
+#include <asm-generic/bitops/count_zeros.h>
+
 /* You have to define the following before including this file:
  *
  * UWtype -- An unsigned type, default type for operations (typically a "word")
@@ -146,12 +148,6 @@ do { \
 	: "1" ((USItype)(n1)), \
 		"r" ((USItype)(n0)), \
 		"r" ((USItype)(d)))
-
-#define count_leading_zeros(count, x) \
-	__asm__ ("clz %0,%1" \
-	: "=r" ((USItype)(count)) \
-	: "r" ((USItype)(x)))
-#define COUNT_LEADING_ZEROS_0 32
 #endif /* __a29k__ */
 
 #if defined(__alpha) && W_TYPE_SIZE == 64
@@ -298,11 +294,6 @@ extern UDItype __udiv_qrnnd();
 	: "1" ((USItype)(nh)), \
 		"0" ((USItype)(nl)), \
 		"g" ((USItype)(d)))
-#define count_leading_zeros(count, x) \
-	__asm__ ("bsch/1 %1,%0" \
-	: "=g" (count) \
-	: "g" ((USItype)(x)), \
-	     "0" ((USItype)0))
 #endif
 
 /***************************************
@@ -354,27 +345,6 @@ do { USItype __r; \
 } while (0)
 extern USItype __udiv_qrnnd();
 #endif /* LONGLONG_STANDALONE */
-#define count_leading_zeros(count, x) \
-do { \
-	USItype __tmp; \
-	__asm__ ( \
-	"ldi             1,%0\n" \
-	"extru,=	%1,15,16,%%r0  ; Bits 31..16 zero?\n" \
-	"extru,tr	%1,15,16,%1    ; No.  Shift down, skip add.\n" \
-	"ldo		16(%0),%0      ; Yes.	Perform add.\n" \
-	"extru,=	%1,23,8,%%r0   ; Bits 15..8 zero?\n" \
-	"extru,tr	%1,23,8,%1     ; No.  Shift down, skip add.\n" \
-	"ldo		8(%0),%0       ; Yes.	Perform add.\n" \
-	"extru,=	%1,27,4,%%r0   ; Bits 7..4 zero?\n" \
-	"extru,tr	%1,27,4,%1     ; No.  Shift down, skip add.\n" \
-	"ldo		4(%0),%0       ; Yes.	Perform add.\n" \
-	"extru,=	%1,29,2,%%r0   ; Bits 3..2 zero?\n" \
-	"extru,tr	%1,29,2,%1     ; No.  Shift down, skip add.\n" \
-	"ldo		2(%0),%0       ; Yes.	Perform add.\n" \
-	"extru		%1,30,1,%1     ; Extract bit 1.\n" \
-	"sub		%0,%1,%0       ; Subtract it.              " \
-	: "=r" (count), "=r" (__tmp) : "1" (x)); \
-} while (0)
 #endif /* hppa */
 
 /***************************************
@@ -457,15 +427,6 @@ do { \
 	: "0" ((USItype)(n0)), \
 	     "1" ((USItype)(n1)), \
 	     "rm" ((USItype)(d)))
-#define count_leading_zeros(count, x) \
-do { \
-	USItype __cbtmp; \
-	__asm__ ("bsrl %1,%0" \
-	: "=r" (__cbtmp) : "rm" ((USItype)(x))); \
-	(count) = __cbtmp ^ 31; \
-} while (0)
-#define count_trailing_zeros(count, x) \
-	__asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x)))
 #ifndef UMUL_TIME
 #define UMUL_TIME 40
 #endif
@@ -536,15 +497,6 @@ do { \
 	     "dI" ((USItype)(d))); \
 	(r) = __rq.__i.__l; (q) = __rq.__i.__h; \
 } while (0)
-#define count_leading_zeros(count, x) \
-do { \
-	USItype __cbtmp; \
-	__asm__ ("scanbit %1,%0" \
-	: "=r" (__cbtmp) \
-	: "r" ((USItype)(x))); \
-	(count) = __cbtmp ^ 31; \
-} while (0)
-#define COUNT_LEADING_ZEROS_0 (-32)	/* sic */
 #if defined(__i960mx)		/* what is the proper symbol to test??? */
 #define rshift_rhlc(r, h, l, c) \
 do { \
@@ -603,11 +555,6 @@ do { \
 	: "0" ((USItype)(n0)), \
 	     "1" ((USItype)(n1)), \
 	     "dmi" ((USItype)(d)))
-#define count_leading_zeros(count, x) \
-	__asm__ ("bfffo %1{%b2:%b2},%0" \
-	: "=d" ((USItype)(count)) \
-	: "od" ((USItype)(x)), "n" (0))
-#define COUNT_LEADING_ZEROS_0 32
 #else /* not mc68020 */
 #define umul_ppmm(xh, xl, a, b) \
 do { USItype __umul_tmp1, __umul_tmp2; \
@@ -664,15 +611,6 @@ do { USItype __umul_tmp1, __umul_tmp2; \
 	     "rJ" ((USItype)(bh)), \
 	     "rJ" ((USItype)(al)), \
 	     "rJ" ((USItype)(bl)))
-#define count_leading_zeros(count, x) \
-do { \
-	USItype __cbtmp; \
-	__asm__ ("ff1 %0,%1" \
-	: "=r" (__cbtmp) \
-	: "r" ((USItype)(x))); \
-	(count) = __cbtmp ^ 31; \
-} while (0)
-#define COUNT_LEADING_ZEROS_0 63	/* sic */
 #if defined(__m88110__)
 #define umul_ppmm(wh, wl, u, v) \
 do { \
@@ -779,12 +717,6 @@ do { \
 	: "0" (__xx.__ll), \
 	     "g" ((USItype)(d))); \
 	(r) = __xx.__i.__l; (q) = __xx.__i.__h; })
-#define count_trailing_zeros(count, x) \
-do { \
-	__asm__("ffsd      %2,%0" \
-	: "=r"((USItype) (count)) \
-	: "0"((USItype) 0), "r"((USItype) (x))); \
-	} while (0)
 #endif /* __ns32000__ */
 
 /***************************************
@@ -855,11 +787,6 @@ do { \
 		"rI" ((USItype)(al)), \
 		"r" ((USItype)(bl))); \
 } while (0)
-#define count_leading_zeros(count, x) \
-	__asm__ ("{cntlz|cntlzw} %0,%1" \
-	: "=r" ((USItype)(count)) \
-	: "r" ((USItype)(x)))
-#define COUNT_LEADING_ZEROS_0 32
 #if defined(_ARCH_PPC)
 #define umul_ppmm(ph, pl, m0, m1) \
 do { \
@@ -1001,19 +928,6 @@ do { \
 } while (0)
 #define UMUL_TIME 20
 #define UDIV_TIME 200
-#define count_leading_zeros(count, x) \
-do { \
-	if ((x) >= 0x10000) \
-		__asm__ ("clz     %0,%1" \
-		: "=r" ((USItype)(count)) \
-		: "r" ((USItype)(x) >> 16)); \
-	else { \
-		__asm__ ("clz   %0,%1" \
-		: "=r" ((USItype)(count)) \
-		: "r" ((USItype)(x))); \
-		(count) += 16; \
-	} \
-} while (0)
 #endif /* RT/ROMP */
 
 /***************************************
@@ -1142,13 +1056,6 @@ do { \
 	"rI" ((USItype)(d)) \
 	: "%g1" __AND_CLOBBER_CC)
 #define UDIV_TIME 37
-#define count_leading_zeros(count, x) \
-	__asm__ ("scan %1,0,%0" \
-	: "=r" ((USItype)(x)) \
-	: "r" ((USItype)(count)))
-/* Early sparclites return 63 for an argument of 0, but they warn that future
-	implementations might change this.  Therefore, leave COUNT_LEADING_ZEROS_0
-	undefined.  */
 #endif /* __sparclite__ */
 #endif /* __sparc_v8__ */
 	/* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd.  */
@@ -1454,47 +1361,6 @@ do { \
 #define udiv_qrnnd __udiv_qrnnd_c
 #endif
 
-#undef count_leading_zeros
-#if !defined(count_leading_zeros)
-	extern
-#ifdef __STDC__
-			const
-#endif
-			unsigned char __clz_tab[];
-#define count_leading_zeros(count, x) \
-do { \
-	UWtype __xr = (x); \
-	UWtype __a; \
-	\
-	if (W_TYPE_SIZE <= 32) { \
-		__a = __xr < ((UWtype) 1 << 2*__BITS4) \
-		? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \
-		: (__xr < ((UWtype) 1 << 3*__BITS4) ?  2*__BITS4 : 3*__BITS4); \
-	} \
-	else { \
-		for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \
-			if (((__xr >> __a) & 0xff) != 0) \
-				break; \
-	} \
-	\
-	(count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \
-} while (0)
-	/* This version gives a well-defined value for zero. */
-#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE
-#endif
-
-#if !defined(count_trailing_zeros)
-/* Define count_trailing_zeros using count_leading_zeros.  The latter might be
-	defined in asm, but if it is not, the C version above is good enough.  */
-#define count_trailing_zeros(count, x) \
-do { \
-	UWtype __ctz_x = (x); \
-	UWtype __ctz_c; \
-	count_leading_zeros(__ctz_c, __ctz_x & -__ctz_x); \
-	(count) = W_TYPE_SIZE - 1 - __ctz_c; \
-} while (0)
-#endif
-
 #ifndef UDIV_NEEDS_NORMALIZATION
 #define UDIV_NEEDS_NORMALIZATION 0
 #endif
diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c
index 5687248..503537e 100644
--- a/lib/mpi/mpi-bit.c
+++ b/lib/mpi/mpi-bit.c
@@ -45,7 +45,7 @@ unsigned mpi_get_nbits(MPI a)
 	if (a->nlimbs) {
 		mpi_limb_t alimb = a->d[a->nlimbs - 1];
 		if (alimb)
-			count_leading_zeros(n, alimb);
+			n = count_leading_zeros(alimb);
 		else
 			n = BITS_PER_MPI_LIMB;
 		n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB;
diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c
index 67f3e79..5464c87 100644
--- a/lib/mpi/mpi-pow.c
+++ b/lib/mpi/mpi-pow.c
@@ -77,7 +77,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod)
 	mp = mp_marker = mpi_alloc_limb_space(msize);
 	if (!mp)
 		goto enomem;
-	count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]);
+	mod_shift_cnt = count_leading_zeros(mod->d[msize - 1]);
 	if (mod_shift_cnt)
 		mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt);
 	else
@@ -169,7 +169,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod)
 
 		i = esize - 1;
 		e = ep[i];
-		count_leading_zeros(c, e);
+		c = count_leading_zeros(e);
 		e = (e << c) << 1;	/* shift the exp bits to the left, lose msb */
 		c = BITS_PER_MPI_LIMB - 1 - c;
 


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 03/25] KEYS: Create a key type that can be used for general cryptographic operations
  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-08-16  1:34 ` David Howells
  2012-08-16  1:34 ` [PATCH 04/25] KEYS: Add signature verification facility David Howells
                   ` (24 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:34 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Create a key type that can be used for general cryptographic operations, such
as encryption, decryption, signature generation and signature verification.

The key type is "crypto" and can provide access to a variety of cryptographic
algorithms.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 Documentation/security/keys-crypto.txt |  181 +++++++++++++++++++++
 include/keys/crypto-subtype.h          |   57 +++++++
 include/keys/crypto-type.h             |   25 +++
 security/keys/Kconfig                  |    2 
 security/keys/Makefile                 |    1 
 security/keys/crypto/Kconfig           |    7 +
 security/keys/crypto/Makefile          |    7 +
 security/keys/crypto/crypto_keys.h     |   28 +++
 security/keys/crypto/crypto_type.c     |  272 ++++++++++++++++++++++++++++++++
 9 files changed, 580 insertions(+)
 create mode 100644 Documentation/security/keys-crypto.txt
 create mode 100644 include/keys/crypto-subtype.h
 create mode 100644 include/keys/crypto-type.h
 create mode 100644 security/keys/crypto/Kconfig
 create mode 100644 security/keys/crypto/Makefile
 create mode 100644 security/keys/crypto/crypto_keys.h
 create mode 100644 security/keys/crypto/crypto_type.c


diff --git a/Documentation/security/keys-crypto.txt b/Documentation/security/keys-crypto.txt
new file mode 100644
index 0000000..97dee80
--- /dev/null
+++ b/Documentation/security/keys-crypto.txt
@@ -0,0 +1,181 @@
+			    ======================
+			    CRYPTOGRAPHIC KEY TYPE
+			    ======================
+
+Contents:
+
+  - Overview.
+  - Key identification.
+  - Accessing crypto keys.
+  - Implementing crypto parsers.
+  - Implementing crypto subtypes.
+
+
+========
+OVERVIEW
+========
+
+The "crypto" key type is designed to be a container for cryptographic keys,
+without imposing any particular restrictions on the form of the cryptography or
+the key.
+
+The crypto key is given a subtype that defines what sort of data is associated
+with the key and provides operations to describe and destroy it.  However, no
+requirement is made that the key data actually be loaded into the key.
+
+The crypto key also has a number of data parsers registered with it.  The data
+parsers are responsible for extracing information the blobs of data passed to
+the instantiator function.  The first data parser that recognises the blob gets
+to set the subtype of the key and define the operations that can be done on
+that key.
+
+Completely in-kernel key retention and operation subtypes and parsers can be
+defined, but it would also be possible to provide access to cryptographic
+hardware (such as a TPM) that might be used to both retain the relevant key and
+perform operations using that key.  In such a case, the crypto key would then
+merely be an interface to the TPM driver.
+
+
+==================
+KEY IDENTIFICATION
+==================
+
+Because the identity of a key is not necessarily known and may not be easily
+calculated when a crypto key is allocated, it may not be a simple matter to set
+a key description to something that's useful for determining whether this is
+the key you're looking for.  Furthermore, it may be necessary to perform a
+partial match upon the key identity.
+
+To help with this, when a key is loaded, the parser calculates the key
+fingerprint and stores a copy in the key structure.
+
+The crypto key type's key matching function then performs more checks than just
+the straightforward comparison of the description with the criterion string:
+
+ (1) If the criterion string is of the form "id:<hexdigits>" then the match
+     function will examine a key's fingerprint to see if the hex digits given
+     after the "id:" match the tail.  For instance:
+
+	keyctl search @s crypto id:5acc2142
+
+     will match a key with fingerprint:
+
+	1A00 2040 7601 7889 DE11  882C 3823 04AD 5ACC 2142
+
+ (2) If the criterion string is of the form "<subtype>:<hexdigits>" then the
+     match will match the ID as in (1), but with the added restriction that
+     only keys of the specified subtype (e.g. dsa or rsa) will be matched.  For
+     instance:
+
+	keyctl search @s crypto dsa:5acc2142
+
+Looking in /proc/keys, the last 8 hex digits of the key fingerprint are
+displayed, along with the subtype:
+
+	1a39e171 I-----     1 perm 3f010000     0     0 crypto    modsign.0: DSA 5acc2142 []
+
+
+=====================
+ACCESSING CRYPTO KEYS
+=====================
+
+To access crypto keys from within the kernel, the following inclusion is
+required:
+
+	#include <keys/crypto-type.h>
+
+This gives access to the key type:
+
+	struct key_type key_type_crypto;
+
+
+===========================
+IMPLEMENTING CRYPTO PARSERS
+===========================
+
+The crypto key type keeps a list of registered data parsers.  An example of
+such a parser is one that parses OpenPGP packet formatted data [RFC 4880].
+
+During key instantiation each parser in the list is tried until one doesn't
+return -EBADMSG.
+
+The parser definition structure looks like the following:
+
+	struct crypto_key_parser {
+		struct module		*owner;
+		const char		*name;
+
+		int (*instantiate)(struct key *key,
+				   const void *data, size_t datalen);
+	};
+
+The owner and name fields should be set to the owning module and the name of
+the parser.
+
+There are a number of operations defined by the parser.  They are all optional,
+but it is expected that at least one will be defined.
+
+ (1) instantiate().
+
+     The arguments are the same as for the instantiate function in the key
+     type.  'key' is the crypto key being instantiated; data and datalen are
+     the instantiation data, presumably containing cryptographic key data, and
+     the length of that data.
+
+     If the data format is not recognised, -EBADMSG should be returned.  If it
+     is recognised, but the key cannot for some reason be set up, some other
+     negative error code should be returned.
+
+     If the key can be successfully set up, then key->payload should be set to
+     point to the retained data, key->type_data.p[0] should be set to point to
+     the subtype chosen and key->type_data.p[1] should be set to point to a
+     copy of the key's identity string and 0 should be returned.
+
+     The key's identity string may be partially matched upon.  For a public-key
+     algorithm such as RSA and DSA this will likely be a printable hex version
+     of the key's fingerprint.
+
+Functions are provided to register and unregister parsers:
+
+	int register_crypto_key_parser(struct crypto_key_parser *parser);
+	void unregister_crypto_key_parser(struct crypto_key_parser *subtype);
+
+Parsers may not have the same name.  The names are only used for displaying in
+debugging messages.
+
+
+============================
+IMPLEMENTING CRYPTO SUBTYPES
+============================
+
+The parser selects the appropriate subtype directly and sets it on the key; the
+crypto key then retains a reference on the subtype module (which means the
+parser can be removed thereafter).
+
+The subtype definition structure looks like the following:
+
+	struct crypto_key_subtype {
+		struct module		*owner;
+		const char		*name;
+
+		void (*describe)(const struct key *key, struct seq_file *m);
+		void (*destroy)(void *payload);
+	};
+
+The owner and name fields should be set to the owning module and the name of
+the subtype.
+
+There are a number of operations defined by the subtype:
+
+ (1) describe().
+
+     Mandatory.  This allows the subtype to display something in /proc/keys
+     against the key.  For instance the name of the public key algorithm type
+     could be displayed.  The key type will display the tail of the key
+     identity string after this.
+
+ (2) destroy().
+
+     Mandatory.  This should free the memory associated with the key.  The
+     crypto key will look after freeing the fingerprint and releasing the
+     reference on the subtype module.
diff --git a/include/keys/crypto-subtype.h b/include/keys/crypto-subtype.h
new file mode 100644
index 0000000..1f546e6
--- /dev/null
+++ b/include/keys/crypto-subtype.h
@@ -0,0 +1,57 @@
+/* Cryptographic key subtype
+ *
+ * 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
+ */
+
+#ifndef _KEYS_CRYPTO_SUBTYPE_H
+#define _KEYS_CRYPTO_SUBTYPE_H
+
+#include <linux/seq_file.h>
+#include <keys/crypto-type.h>
+
+extern struct key_type key_type_crypto;
+
+/*
+ * Keys of this type declare a subtype that indicates the handlers and
+ * capabilities.
+ */
+struct crypto_key_subtype {
+	struct module		*owner;
+	const char		*name;
+	unsigned short		name_len;	/* length of name */
+
+	void (*describe)(const struct key *key, struct seq_file *m);
+
+	void (*destroy)(void *payload);
+};
+
+/*
+ * Data parser.  Called during instantiation and signature verification
+ * initiation.
+ */
+struct crypto_key_parser {
+	struct list_head	link;
+	struct module		*owner;
+	const char		*name;
+
+	/* Attempt to parse a key from the data blob passed to add_key() or
+	 * keyctl_instantiate().  Should also generate a proposed description
+	 * that the caller can optionally use for the key.
+	 *
+	 * Return EBADMSG if not recognised.
+	 */
+	int (*preparse)(struct key_preparsed_payload *prep);
+};
+
+extern int register_crypto_key_parser(struct crypto_key_parser *);
+extern void unregister_crypto_key_parser(struct crypto_key_parser *);
+
+#endif /* _KEYS_CRYPTO_SUBTYPE_H */
diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h
new file mode 100644
index 0000000..47c00c7
--- /dev/null
+++ b/include/keys/crypto-type.h
@@ -0,0 +1,25 @@
+/* Cryptographic key type interface
+ *
+ * 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
+ */
+
+#ifndef _KEYS_CRYPTO_TYPE_H
+#define _KEYS_CRYPTO_TYPE_H
+
+#include <linux/key-type.h>
+
+extern struct key_type key_type_crypto;
+
+/*
+ * The payload is at the discretion of the subtype.
+ */
+
+#endif /* _KEYS_CRYPTO_TYPE_H */
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index a90d6d3..992fe52 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -69,3 +69,5 @@ config KEYS_DEBUG_PROC_KEYS
 	  the resulting table.
 
 	  If you are unsure as to whether this is required, answer N.
+
+source security/keys/crypto/Kconfig
diff --git a/security/keys/Makefile b/security/keys/Makefile
index 504aaa0..67dae73 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_SYSCTL) += sysctl.o
 #
 obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
 obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/
+obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto/
diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig
new file mode 100644
index 0000000..3d15710
--- /dev/null
+++ b/security/keys/crypto/Kconfig
@@ -0,0 +1,7 @@
+config CRYPTO_KEY_TYPE
+	tristate "Cryptographic key type"
+	depends on KEYS
+	help
+	  This option provides support for a type of key that holds the keys
+	  required for cryptographic operations such as encryption, decryption,
+	  signature generation and signature verification.
diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile
new file mode 100644
index 0000000..36db1d5
--- /dev/null
+++ b/security/keys/crypto/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for cryptographic keys
+#
+
+obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o
+
+crypto_keys-y := crypto_type.o
diff --git a/security/keys/crypto/crypto_keys.h b/security/keys/crypto/crypto_keys.h
new file mode 100644
index 0000000..eb11788
--- /dev/null
+++ b/security/keys/crypto/crypto_keys.h
@@ -0,0 +1,28 @@
+/* Internal crypto type stuff
+ *
+ * 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.
+ */
+
+static inline
+struct crypto_key_subtype *crypto_key_subtype(const struct key *key)
+{
+	return key->type_data.p[0];
+}
+
+static inline const char *crypto_key_id(const struct key *key)
+{
+	return key->type_data.p[1];
+}
+
+
+/*
+ * 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
new file mode 100644
index 0000000..e8f83a6
--- /dev/null
+++ b/security/keys/crypto/crypto_type.c
@@ -0,0 +1,272 @@
+/* Cryptographic key type
+ *
+ * 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/seq_file.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "crypto_keys.h"
+
+MODULE_LICENSE("GPL");
+
+LIST_HEAD(crypto_key_parsers);
+DECLARE_RWSEM(crypto_key_parsers_sem);
+
+/*
+ * Match crypto_keys on (part of) their name
+ * We have some shorthand methods for matching keys.  We allow:
+ *
+ *	"<desc>"	- request a key by description
+ *	"id:<id>"	- request a key matching the ID
+ *	"<subtype>:<id>" - request a key of a subtype
+ */
+static int crypto_key_match(const struct key *key, const void *description)
+{
+	const struct crypto_key_subtype *subtype = crypto_key_subtype(key);
+	const char *spec = description;
+	const char *id, *kid;
+	ptrdiff_t speclen;
+	size_t idlen, kidlen;
+
+	if (!subtype || !spec || !*spec)
+		return 0;
+
+	/* See if the full key description matches as is */
+	if (key->description && strcmp(key->description, description) == 0)
+		return 1;
+
+	/* All tests from here on break the criterion description into a
+	 * specifier, a colon and then an identifier.
+	 */
+	id = strchr(spec, ':');
+	if (!id)
+		return 0;
+
+	speclen = id - spec;
+	id++;
+
+	/* Anything after here requires a partial match on the ID string */
+	kid = crypto_key_id(key);
+	if (!kid)
+		return 0;
+
+	idlen = strlen(id);
+	kidlen = strlen(kid);
+	if (idlen > kidlen)
+		return 0;
+
+	kid += kidlen - idlen;
+	if (strcasecmp(id, kid) != 0)
+		return 0;
+
+	if (speclen == 2 &&
+	    memcmp(spec, "id", 2) == 0)
+		return 1;
+
+	if (speclen == subtype->name_len &&
+	    memcmp(spec, subtype->name, speclen) == 0)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * Describe the crypto key
+ */
+static void crypto_key_describe(const struct key *key, struct seq_file *m)
+{
+	const struct crypto_key_subtype *subtype = crypto_key_subtype(key);
+	const char *kid = crypto_key_id(key);
+	size_t n;
+
+	seq_puts(m, key->description);
+
+	if (subtype) {
+		seq_puts(m, ": ");
+		subtype->describe(key, m);
+
+		if (kid) {
+			seq_putc(m, ' ');
+			n = strlen(kid);
+			if (n <= 8)
+				seq_puts(m, kid);
+			else
+				seq_puts(m, kid + n - 8);
+		}
+
+		seq_puts(m, " [");
+		/* put something here to indicate the key's capabilities */
+		seq_putc(m, ']');
+	}
+}
+
+/*
+ * Preparse a crypto payload to get format the contents appropriately for the
+ * internal payload to cut down on the number of scans of the data performed.
+ *
+ * We also generate a proposed description from the contents of the key that
+ * can be used to name the key if the user doesn't want to provide one.
+ */
+static int crypto_key_preparse(struct key_preparsed_payload *prep)
+{
+	struct crypto_key_parser *parser;
+	int ret;
+
+	pr_devel("==>%s()\n", __func__);
+
+	if (prep->datalen == 0)
+		return -EINVAL;
+
+	down_read(&crypto_key_parsers_sem);
+
+	ret = -EBADMSG;
+	list_for_each_entry(parser, &crypto_key_parsers, link) {
+		pr_debug("Trying parser '%s'\n", parser->name);
+
+		ret = parser->preparse(prep);
+		if (ret != -EBADMSG) {
+			pr_debug("Parser recognised the format (ret %d)\n",
+				 ret);
+			break;
+		}
+	}
+
+	up_read(&crypto_key_parsers_sem);
+	pr_devel("<==%s() = %d\n", __func__, ret);
+	return ret;
+}
+
+/*
+ * Clean up the preparse data
+ */
+static void crypto_key_free_preparse(struct key_preparsed_payload *prep)
+{
+	struct crypto_key_subtype *subtype = prep->type_data[0];
+
+	pr_devel("==>%s()\n", __func__);
+
+	if (subtype) {
+		subtype->destroy(prep->payload);
+		module_put(subtype->owner);
+	}
+	kfree(prep->type_data[1]);
+	kfree(prep->description);
+}
+
+/*
+ * Instantiate a crypto_key defined key
+ */
+static int crypto_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
+{
+	int ret;
+
+	pr_devel("==>%s()\n", __func__);
+
+	ret = key_payload_reserve(key, prep->quotalen);
+	if (ret == 0) {
+		key->type_data.p[0] = prep->type_data[0];
+		key->type_data.p[1] = prep->type_data[1];
+		key->payload.data = prep->payload;
+		prep->type_data[0] = NULL;
+		prep->type_data[1] = NULL;
+		prep->payload = NULL;
+	}
+	pr_devel("<==%s() = %d\n", __func__, ret);
+	return ret;
+}
+
+/*
+ * dispose of the data dangling from the corpse of a crypto key
+ */
+static void crypto_key_destroy(struct key *key)
+{
+	struct crypto_key_subtype *subtype = crypto_key_subtype(key);
+	if (subtype) {
+		subtype->destroy(key->payload.data);
+		module_put(subtype->owner);
+		key->type_data.p[0] = NULL;
+	}
+	kfree(key->type_data.p[1]);
+	key->type_data.p[1] = NULL;
+}
+
+struct key_type key_type_crypto = {
+	.name		= "crypto",
+	.preparse	= crypto_key_preparse,
+	.free_preparse	= crypto_key_free_preparse,
+	.instantiate	= crypto_key_instantiate,
+	.match		= crypto_key_match,
+	.destroy	= crypto_key_destroy,
+	.describe	= crypto_key_describe,
+};
+EXPORT_SYMBOL_GPL(key_type_crypto);
+
+/**
+ * register_crypto_key_parser - Register a crypto key blob parser
+ * @parser: The parser to register
+ */
+int register_crypto_key_parser(struct crypto_key_parser *parser)
+{
+	struct crypto_key_parser *cursor;
+	int ret;
+
+	down_write(&crypto_key_parsers_sem);
+
+	list_for_each_entry(cursor, &crypto_key_parsers, link) {
+		if (strcmp(cursor->name, parser->name) == 0) {
+			pr_err("Crypto key parser '%s' already registered\n",
+			       parser->name);
+			ret = -EEXIST;
+			goto out;
+		}
+	}
+
+	list_add_tail(&parser->link, &crypto_key_parsers);
+
+	pr_notice("Crypto key parser '%s' registered\n", parser->name);
+	ret = 0;
+
+out:
+	up_write(&crypto_key_parsers_sem);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(register_crypto_key_parser);
+
+/**
+ * unregister_crypto_key_parser - Unregister a crypto key blob parser
+ * @parser: The parser to unregister
+ */
+void unregister_crypto_key_parser(struct crypto_key_parser *parser)
+{
+	down_write(&crypto_key_parsers_sem);
+	list_del(&parser->link);
+	up_write(&crypto_key_parsers_sem);
+
+	pr_notice("Crypto key parser '%s' unregistered\n", parser->name);
+}
+EXPORT_SYMBOL_GPL(unregister_crypto_key_parser);
+
+/*
+ * Module stuff
+ */
+static int __init crypto_key_init(void)
+{
+	return register_key_type(&key_type_crypto);
+}
+
+static void __exit crypto_key_cleanup(void)
+{
+	unregister_key_type(&key_type_crypto);
+}
+
+module_init(crypto_key_init);
+module_exit(crypto_key_cleanup);


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 04/25] KEYS: Add signature verification facility
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (2 preceding siblings ...)
  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
  2012-08-16  1:35 ` [PATCH 05/25] KEYS: Asymmetric public-key algorithm crypto key subtype David Howells
                   ` (23 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:34 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

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);


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 05/25] KEYS: Asymmetric public-key algorithm crypto key subtype
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (3 preceding siblings ...)
  2012-08-16  1:34 ` [PATCH 04/25] KEYS: Add signature verification facility David Howells
@ 2012-08-16  1:35 ` David Howells
  2012-08-16  1:35 ` [PATCH 06/25] MPILIB: Reinstate mpi_cmp[_ui]() and export for RSA signature verification David Howells
                   ` (22 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:35 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Add a subtype for supporting asymmetric public-key encryption algorithms such
as DSA (FIPS-186) and RSA (PKCS#1 / RFC1337).

Signed-off-by: David Howells <dhowells@redhat.com>
---

 security/keys/crypto/Kconfig      |   10 +++
 security/keys/crypto/Makefile     |    3 +
 security/keys/crypto/public_key.c |   82 +++++++++++++++++++++++++
 security/keys/crypto/public_key.h |  123 +++++++++++++++++++++++++++++++++++++
 4 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 security/keys/crypto/public_key.c
 create mode 100644 security/keys/crypto/public_key.h


diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig
index 3d15710..5f2b8ac 100644
--- a/security/keys/crypto/Kconfig
+++ b/security/keys/crypto/Kconfig
@@ -5,3 +5,13 @@ config CRYPTO_KEY_TYPE
 	  This option provides support for a type of key that holds the keys
 	  required for cryptographic operations such as encryption, decryption,
 	  signature generation and signature verification.
+
+config CRYPTO_KEY_PUBLIC_KEY_SUBTYPE
+	tristate "Asymmetric public-key crypto algorithm subtype"
+	depends on CRYPTO_KEY_TYPE
+	select MPILIB
+	help
+	  This option provides support for asymmetric public key type handling.
+	  If signature generation and/or verification are to be used,
+	  appropriate hash algorithms (such as SHA-1) must be available.
+	  ENOPKG will be reported if the requisite algorithm is unavailable.
diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile
index 67001bc..6384306 100644
--- a/security/keys/crypto/Makefile
+++ b/security/keys/crypto/Makefile
@@ -3,5 +3,6 @@
 #
 
 obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o
-
 crypto_keys-y := crypto_type.o crypto_verify.o
+
+obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o
diff --git a/security/keys/crypto/public_key.c b/security/keys/crypto/public_key.c
new file mode 100644
index 0000000..ebb31ec
--- /dev/null
+++ b/security/keys/crypto/public_key.c
@@ -0,0 +1,82 @@
+/* Asymmetric public key crypto subtype
+ *
+ * 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 pr_fmt(fmt) "PKEY: "fmt
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include "public_key.h"
+
+MODULE_LICENSE("GPL");
+
+const char *const pkey_algo[PKEY_ALGO__LAST] = {
+	[PKEY_ALGO_DSA]		= "DSA",
+	[PKEY_ALGO_RSA]		= "RSA",
+};
+EXPORT_SYMBOL_GPL(pkey_algo);
+
+const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
+	[PKEY_HASH_MD4]		= "md4",
+	[PKEY_HASH_MD5]		= "md5",
+	[PKEY_HASH_SHA1]	= "sha1",
+	[PKEY_HASH_RIPE_MD_160]	= "rmd160",
+	[PKEY_HASH_SHA256]	= "sha256",
+	[PKEY_HASH_SHA384]	= "sha384",
+	[PKEY_HASH_SHA512]	= "sha512",
+	[PKEY_HASH_SHA224]	= "sha224",
+};
+EXPORT_SYMBOL_GPL(pkey_hash_algo);
+
+const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = {
+	[PKEY_ID_PGP]		= "PGP",
+	[PKEY_ID_X509]		= "X509",
+};
+EXPORT_SYMBOL_GPL(pkey_id_type);
+
+/*
+ * Provide a part of a description of the key for /proc/keys.
+ */
+static void public_key_describe(const struct key *crypto_key,
+				struct seq_file *m)
+{
+	struct public_key *key = crypto_key->payload.data;
+
+	if (key)
+		seq_printf(m, "%s.%s",
+			   pkey_id_type[key->id_type], key->algo->name);
+}
+
+/*
+ * Destroy a public key algorithm key
+ */
+void public_key_destroy(void *payload)
+{
+	struct public_key *key = payload;
+	int i;
+
+	if (key) {
+		for (i = 0; i < ARRAY_SIZE(key->mpi); i++)
+			mpi_free(key->mpi[i]);
+		kfree(key);
+	}
+}
+EXPORT_SYMBOL_GPL(public_key_destroy);
+
+/*
+ * Public key algorithm crypto key subtype
+ */
+struct crypto_key_subtype public_key_crypto_key_subtype = {
+	.owner		= THIS_MODULE,
+	.name		= "public_key",
+	.describe	= public_key_describe,
+	.destroy	= public_key_destroy,
+};
+EXPORT_SYMBOL_GPL(public_key_crypto_key_subtype);
diff --git a/security/keys/crypto/public_key.h b/security/keys/crypto/public_key.h
new file mode 100644
index 0000000..228090d
--- /dev/null
+++ b/security/keys/crypto/public_key.h
@@ -0,0 +1,123 @@
+/* Asymmetric public-key algorithm 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.
+ */
+
+#ifndef _LINUX_PUBLIC_KEY_H
+#define _LINUX_PUBLIC_KEY_H
+
+#include <linux/mpi.h>
+#include <crypto/hash.h>
+#include <keys/crypto-subtype.h>
+
+struct public_key;
+struct public_key_signature;
+
+enum pkey_algo {
+	PKEY_ALGO_DSA,
+	PKEY_ALGO_RSA,
+	PKEY_ALGO__LAST
+};
+
+extern const char *const pkey_algo[PKEY_ALGO__LAST];
+
+enum pkey_hash_algo {
+	PKEY_HASH_MD4,
+	PKEY_HASH_MD5,
+	PKEY_HASH_SHA1,
+	PKEY_HASH_RIPE_MD_160,
+	PKEY_HASH_SHA256,
+	PKEY_HASH_SHA384,
+	PKEY_HASH_SHA512,
+	PKEY_HASH_SHA224,
+	PKEY_HASH__LAST
+};
+
+extern const char *const pkey_hash_algo[PKEY_HASH__LAST];
+
+enum pkey_id_type {
+	PKEY_ID_PGP,		/* OpenPGP generated key ID */
+	PKEY_ID_X509,		/* X.509 arbitrary subjectKeyIdentifier */
+	PKEY_ID_TYPE__LAST
+};
+
+extern const char *const pkey_id_type[PKEY_ID_TYPE__LAST];
+
+/*
+ * Public key type definition
+ */
+struct public_key_algorithm {
+	const char	*name;
+	u8		n_pub_mpi;	/* Number of MPIs in public key */
+	u8		n_sec_mpi;	/* Number of MPIs in secret key */
+	u8		n_sig_mpi;	/* Number of MPIs in a signature */
+	int (*verify)(const struct public_key *key,
+		      const struct public_key_signature *sig);
+};
+
+/*
+ * Asymmetric public key data
+ */
+struct public_key {
+	const struct public_key_algorithm *algo;
+	u8	capabilities;
+#define PKEY_CAN_ENCRYPT	0x01
+#define PKEY_CAN_DECRYPT	0x02
+#define PKEY_CAN_ENCDEC		(PKEY_CAN_ENCRYPT | PKEY_CAN_DECRYPT)
+#define PKEY_CAN_SIGN		0x04
+#define PKEY_CAN_VERIFY		0x08
+#define PKEY_CAN_SIGVER		(PKEY_CAN_SIGN | PKEY_CAN_VERIFY)
+	enum pkey_id_type id_type : 8;
+	union {
+		MPI	mpi[5];
+		struct {
+			MPI	p;	/* DSA prime */
+			MPI	q;	/* DSA group order */
+			MPI	g;	/* DSA group generator */
+			MPI	y;	/* DSA public-key value = g^x mod p */
+			MPI	x;	/* DSA secret exponent (if present) */
+		} dsa;
+		struct {
+			MPI	n;	/* RSA public modulus */
+			MPI	e;	/* RSA public encryption exponent */
+			MPI	d;	/* RSA secret encryption exponent (if present) */
+			MPI	p;	/* RSA secret prime (if present) */
+			MPI	q;	/* RSA secret prime (if present) */
+		} rsa;
+	};
+
+	u8	key_id[8];	/* ID of this key pair */
+	u8	key_id_size;	/* Number of bytes in key_id */
+};
+
+/*
+ * Asymmetric public key algorithm signature data
+ */
+struct public_key_signature {
+	struct crypto_sig_verify_context base;
+	u8 *digest;
+	enum pkey_hash_algo pkey_hash_algo : 8;
+	u8 signed_hash_msw[2];
+	u8 digest_size;	/* Number of bytes in digest */
+	union {
+		MPI mpi[2];
+		struct {
+			MPI s;			/* m^d mod n */
+		} rsa;
+		struct {
+			MPI r;
+			MPI s;
+		} dsa;
+	};
+	struct shash_desc hash;			/* This must go last! */
+};
+
+extern struct crypto_key_subtype public_key_crypto_key_subtype;
+
+#endif /* _LINUX_PUBLIC_KEY_H */


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 06/25] MPILIB: Reinstate mpi_cmp[_ui]() and export for RSA signature verification
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (4 preceding siblings ...)
  2012-08-16  1:35 ` [PATCH 05/25] KEYS: Asymmetric public-key algorithm crypto key subtype David Howells
@ 2012-08-16  1:35 ` David Howells
  2012-08-16  1:35 ` [PATCH 07/25] KEYS: RSA: Implement signature verification algorithm [PKCS#1 / RFC3447] David Howells
                   ` (21 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:35 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Reinstate and export mpi_cmp() and mpi_cmp_ui() from the MPI library for use by
RSA signature verification as per RFC3447 section 5.2.2 step 1.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 lib/mpi/Makefile  |    1 +
 lib/mpi/mpi-cmp.c |   70 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+)
 create mode 100644 lib/mpi/mpi-cmp.c


diff --git a/lib/mpi/Makefile b/lib/mpi/Makefile
index 45ca90a..019a68c 100644
--- a/lib/mpi/Makefile
+++ b/lib/mpi/Makefile
@@ -14,6 +14,7 @@ mpi-y = \
 	generic_mpih-add1.o		\
 	mpicoder.o			\
 	mpi-bit.o			\
+	mpi-cmp.o			\
 	mpih-cmp.o			\
 	mpih-div.o			\
 	mpih-mul.o			\
diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c
new file mode 100644
index 0000000..1871e7b
--- /dev/null
+++ b/lib/mpi/mpi-cmp.c
@@ -0,0 +1,70 @@
+/* mpi-cmp.c  -  MPI functions
+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * 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
+ */
+
+#include "mpi-internal.h"
+
+int mpi_cmp_ui(MPI u, unsigned long v)
+{
+	mpi_limb_t limb = v;
+
+	mpi_normalize(u);
+	if (!u->nlimbs && !limb)
+		return 0;
+	if (u->sign)
+		return -1;
+	if (u->nlimbs > 1)
+		return 1;
+
+	if (u->d[0] == limb)
+		return 0;
+	else if (u->d[0] > limb)
+		return 1;
+	else
+		return -1;
+}
+EXPORT_SYMBOL_GPL(mpi_cmp_ui);
+
+int mpi_cmp(MPI u, MPI v)
+{
+	mpi_size_t usize, vsize;
+	int cmp;
+
+	mpi_normalize(u);
+	mpi_normalize(v);
+	usize = u->nlimbs;
+	vsize = v->nlimbs;
+	if (!u->sign && v->sign)
+		return 1;
+	if (u->sign && !v->sign)
+		return -1;
+	if (usize != vsize && !u->sign && !v->sign)
+		return usize - vsize;
+	if (usize != vsize && u->sign && v->sign)
+		return vsize + usize;
+	if (!usize)
+		return 0;
+	cmp = mpihelp_cmp(u->d, v->d, usize);
+	if (!cmp)
+		return 0;
+	if ((cmp < 0 ? 1 : 0) == (u->sign ? 1 : 0))
+		return 1;
+	return -1;
+}
+EXPORT_SYMBOL_GPL(mpi_cmp);


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 07/25] KEYS: RSA: Implement signature verification algorithm [PKCS#1 / RFC3447]
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (5 preceding siblings ...)
  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 ` David Howells
  2012-08-16  1:35 ` [PATCH 08/25] KEYS: RSA: Fix signature verification for shorter signatures David Howells
                   ` (20 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:35 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Implement RSA public key cryptography [PKCS#1 / RFC3447].  At this time, only
the signature verification algorithm is supported.  This uses the asymmetric
public key subtype to hold its key data.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 security/keys/crypto/Kconfig      |    7 +
 security/keys/crypto/Makefile     |    1 
 security/keys/crypto/crypto_rsa.c |  267 +++++++++++++++++++++++++++++++++++++
 security/keys/crypto/public_key.h |    2 
 4 files changed, 277 insertions(+)
 create mode 100644 security/keys/crypto/crypto_rsa.c


diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig
index 5f2b8ac..4e3777e 100644
--- a/security/keys/crypto/Kconfig
+++ b/security/keys/crypto/Kconfig
@@ -15,3 +15,10 @@ config CRYPTO_KEY_PUBLIC_KEY_SUBTYPE
 	  If signature generation and/or verification are to be used,
 	  appropriate hash algorithms (such as SHA-1) must be available.
 	  ENOPKG will be reported if the requisite algorithm is unavailable.
+
+config CRYPTO_KEY_PKEY_ALGO_RSA
+	tristate "RSA public-key algorithm"
+	depends on CRYPTO_KEY_PUBLIC_KEY_SUBTYPE
+	select MPILIB_EXTRA
+	help
+	  This option enables support for the RSA algorithm (PKCS#1, RFC3447).
diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile
index 6384306..b6b1a5a 100644
--- a/security/keys/crypto/Makefile
+++ b/security/keys/crypto/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o
 crypto_keys-y := crypto_type.o crypto_verify.o
 
 obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o
+obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o
diff --git a/security/keys/crypto/crypto_rsa.c b/security/keys/crypto/crypto_rsa.c
new file mode 100644
index 0000000..6e95e60
--- /dev/null
+++ b/security/keys/crypto/crypto_rsa.c
@@ -0,0 +1,267 @@
+/* RSA asymmetric public-key algorithm [RFC3447]
+ *
+ * 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 pr_fmt(fmt) "RSA: "fmt
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include "public_key.h"
+
+MODULE_LICENSE("GPL");
+
+#define kenter(FMT, ...) \
+	pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
+#define kleave(FMT, ...) \
+	pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
+
+/*
+ * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
+ */
+static const u8 RSA_digest_info_MD5[] = {
+	0x30, 0x20, 0x30, 0x0C, 0x06, 0x08,
+	0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */
+	0x05, 0x00, 0x04, 0x10
+};
+
+static const u8 RSA_digest_info_SHA1[] = {
+	0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
+	0x2B, 0x0E, 0x03, 0x02, 0x1A,
+	0x05, 0x00, 0x04, 0x14
+};
+
+static const u8 RSA_digest_info_RIPE_MD_160[] = {
+	0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
+	0x2B, 0x24, 0x03, 0x02, 0x01,
+	0x05, 0x00, 0x04, 0x14
+};
+
+static const u8 RSA_digest_info_SHA224[] = {
+	0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
+	0x05, 0x00, 0x04, 0x1C
+};
+
+static const u8 RSA_digest_info_SHA256[] = {
+	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+	0x05, 0x00, 0x04, 0x20
+};
+
+static const u8 RSA_digest_info_SHA384[] = {
+	0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
+	0x05, 0x00, 0x04, 0x30
+};
+
+static const u8 RSA_digest_info_SHA512[] = {
+	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
+	0x05, 0x00, 0x04, 0x40
+};
+
+static const struct {
+	const u8 *data;
+	size_t size;
+} RSA_ASN1_templates[PKEY_HASH__LAST] = {
+#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) }
+	[PKEY_HASH_MD5]		= _(MD5),
+	[PKEY_HASH_SHA1]	= _(SHA1),
+	[PKEY_HASH_RIPE_MD_160]	= _(RIPE_MD_160),
+	[PKEY_HASH_SHA256]	= _(SHA256),
+	[PKEY_HASH_SHA384]	= _(SHA384),
+	[PKEY_HASH_SHA512]	= _(SHA512),
+	[PKEY_HASH_SHA224]	= _(SHA224),
+#undef _
+};
+
+/*
+ * RSAVP1() function [RFC3447 sec 5.2.2]
+ */
+static int RSAVP1(const struct public_key *key, MPI s, MPI *_m)
+{
+	MPI m;
+	int ret;
+
+	/* (1) Validate 0 <= s < n */
+	if (mpi_cmp_ui(s, 0) < 0) {
+		kleave(" = -EBADMSG [s < 0]");
+		return -EBADMSG;
+	}
+	if (mpi_cmp(s, key->rsa.n) >= 0) {
+		kleave(" = -EBADMSG [s >= n]");
+		return -EBADMSG;
+	}
+
+	m = mpi_alloc(0);
+	if (!m)
+		return -ENOMEM;
+
+	/* (2) m = s^e mod n */
+	ret = mpi_powm(m, s, key->rsa.e, key->rsa.n);
+	if (ret < 0) {
+		mpi_free(m);
+		return ret;
+	}
+
+	*_m = m;
+	return 0;
+}
+
+/*
+ * Integer to Octet String conversion [RFC3447 sec 4.1]
+ */
+static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
+{
+	unsigned X_size, x_size;
+	int X_sign;
+	u8 *X;
+
+	/* Make sure the string is the right length.  The number should begin
+	 * with { 0x00, 0x01, ... } so we have to account for 15 leading zero
+	 * bits not being reported by MPI.
+	 */
+	x_size = mpi_get_nbits(x);
+	pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8);
+	if (x_size != xLen * 8 - 15)
+		return -ERANGE;
+
+	X = mpi_get_buffer(x, &X_size, &X_sign);
+	if (!X)
+		return -ENOMEM;
+	if (X_sign < 0) {
+		kfree(X);
+		return -EBADMSG;
+	}
+	if (X_size != xLen - 1) {
+		kfree(X);
+		return -EBADMSG;
+	}
+
+	*_X = X;
+	return 0;
+}
+
+/*
+ * Perform the RSA signature verification.
+ * @H: Value of hash of data and metadata
+ * @EM: The computed signature value
+ * @k: The size of EM (EM[0] is an invalid location but should hold 0x00)
+ * @hash_size: The size of H
+ * @asn1_template: The DigestInfo ASN.1 template
+ * @asn1_size: Size of asm1_template[]
+ */
+static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size,
+		      const u8 *asn1_template, size_t asn1_size)
+{
+	unsigned PS_end, T_offset, i;
+
+	kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size);
+
+	if (k < 2 + 1 + asn1_size + hash_size)
+		return -EBADMSG;
+
+	/* Decode the EMSA-PKCS1-v1_5 */
+	if (EM[1] != 0x01) {
+		kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]);
+		return -EBADMSG;
+	}
+
+	T_offset = k - (asn1_size + hash_size);
+	PS_end = T_offset - 1;
+	if (EM[PS_end] != 0x00) {
+		kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]);
+		return -EBADMSG;
+	}
+
+	for (i = 2; i < PS_end; i++) {
+		if (EM[i] != 0xff) {
+			kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]);
+			return -EBADMSG;
+		}
+	}
+
+	if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) {
+		kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]");
+		return -EBADMSG;
+	}
+
+	if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) {
+		kleave(" = -EKEYREJECTED [EM[T] hash mismatch]");
+		return -EKEYREJECTED;
+	}
+
+	kleave(" = 0");
+	return 0;
+}
+
+/*
+ * Perform the verification step [RFC3447 sec 8.2.2].
+ */
+static int RSA_verify_signature(const struct public_key *key,
+				const struct public_key_signature *sig)
+{
+	size_t tsize;
+	int ret;
+
+	/* Variables as per RFC3447 sec 8.2.2 */
+	const u8 *H = sig->digest;
+	u8 *EM = NULL;
+	MPI m = NULL;
+	size_t k;
+
+	kenter("");
+
+	if (!RSA_ASN1_templates[sig->pkey_hash_algo].data)
+		return -ENOTSUPP;
+
+	/* (1) Check the signature size against the public key modulus size */
+	k = (mpi_get_nbits(key->rsa.n) + 7) / 8;
+
+	tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8;
+	pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize);
+	if (tsize != k) {
+		ret = -EBADMSG;
+		goto error;
+	}
+
+	/* (2b) Apply the RSAVP1 verification primitive to the public key */
+	ret = RSAVP1(key, sig->rsa.s, &m);
+	if (ret < 0)
+		goto error;
+
+	/* (2c) Convert the message representative (m) to an encoded message
+	 *      (EM) of length k octets.
+	 *
+	 *      NOTE!  The leading zero byte is suppressed by MPI, so we pass a
+	 *      pointer to the _preceding_ byte to RSA_verify()!
+	 */
+	ret = RSA_I2OSP(m, k, &EM);
+	if (ret < 0)
+		goto error;
+
+	ret = RSA_verify(H, EM - 1, k, sig->digest_size,
+			 RSA_ASN1_templates[sig->pkey_hash_algo].data,
+			 RSA_ASN1_templates[sig->pkey_hash_algo].size);
+
+error:
+	kfree(EM);
+	mpi_free(m);
+	kleave(" = %d", ret);
+	return ret;
+}
+
+const struct public_key_algorithm RSA_public_key_algorithm = {
+	.name		= "RSA",
+	.n_pub_mpi	= 2,
+	.n_sec_mpi	= 3,
+	.n_sig_mpi	= 1,
+	.verify		= RSA_verify_signature,
+};
+EXPORT_SYMBOL_GPL(RSA_public_key_algorithm);
diff --git a/security/keys/crypto/public_key.h b/security/keys/crypto/public_key.h
index 228090d..947817b 100644
--- a/security/keys/crypto/public_key.h
+++ b/security/keys/crypto/public_key.h
@@ -61,6 +61,8 @@ struct public_key_algorithm {
 		      const struct public_key_signature *sig);
 };
 
+extern const struct public_key_algorithm RSA_public_key_algorithm;
+
 /*
  * Asymmetric public key data
  */


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 08/25] KEYS: RSA: Fix signature verification for shorter signatures
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (6 preceding siblings ...)
  2012-08-16  1:35 ` [PATCH 07/25] KEYS: RSA: Implement signature verification algorithm [PKCS#1 / RFC3447] David Howells
@ 2012-08-16  1:35 ` David Howells
  2012-08-16  1:35 ` [PATCH 09/25] PGPLIB: PGP definitions (RFC 4880) David Howells
                   ` (19 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:35 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

gpg can produce a signature file where length of signature is less than the
modulus size because the amount of space an MPI takes up is kept as low as
possible by discarding leading zeros.  This regularly happens for several
modules during the build.

Fix it by relaxing check in RSA verification code.

Thanks to Tomas Mraz and Miloslav Trmac for help.

Signed-off-by: Milan Broz <mbroz@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 security/keys/crypto/crypto_rsa.c |   14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)


diff --git a/security/keys/crypto/crypto_rsa.c b/security/keys/crypto/crypto_rsa.c
index 6e95e60..796ed1d 100644
--- a/security/keys/crypto/crypto_rsa.c
+++ b/security/keys/crypto/crypto_rsa.c
@@ -222,15 +222,23 @@ static int RSA_verify_signature(const struct public_key *key,
 		return -ENOTSUPP;
 
 	/* (1) Check the signature size against the public key modulus size */
-	k = (mpi_get_nbits(key->rsa.n) + 7) / 8;
+	k = mpi_get_nbits(key->rsa.n);
+	tsize = mpi_get_nbits(sig->rsa.s);
 
-	tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8;
+	/* According to RFC 4880 sec 3.2, length of MPI is computed starting
+	 * from most significant bit.  So the RFC 3447 sec 8.2.2 size check
+	 * must be relaxed to conform with shorter signatures - so we fail here
+	 * only if signature length is longer than modulus size.
+	 */
 	pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize);
-	if (tsize != k) {
+	if (k < tsize) {
 		ret = -EBADMSG;
 		goto error;
 	}
 
+	/* Round up and convert to octets */
+	k = (k + 7) / 8;
+
 	/* (2b) Apply the RSAVP1 verification primitive to the public key */
 	ret = RSAVP1(key, sig->rsa.s, &m);
 	if (ret < 0)


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 09/25] PGPLIB: PGP definitions (RFC 4880)
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (7 preceding siblings ...)
  2012-08-16  1:35 ` [PATCH 08/25] KEYS: RSA: Fix signature verification for shorter signatures David Howells
@ 2012-08-16  1:35 ` David Howells
  2012-08-16  1:36 ` [PATCH 10/25] PGPLIB: Basic packet parser David Howells
                   ` (18 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:35 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Provide some useful PGP definitions from RFC 4880.  These describe details of
public key crypto as used by crypto keys for things like signature
verification.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 include/linux/pgp.h |  206 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 206 insertions(+)
 create mode 100644 include/linux/pgp.h


diff --git a/include/linux/pgp.h b/include/linux/pgp.h
new file mode 100644
index 0000000..1359f64
--- /dev/null
+++ b/include/linux/pgp.h
@@ -0,0 +1,206 @@
+/* PGP definitions (RFC 4880)
+ *
+ * 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.
+ */
+
+#ifndef _LINUX_PGP_H
+#define _LINUX_PGP_H
+
+#include <linux/types.h>
+
+struct pgp_key_ID {
+	u8 id[8];
+};
+
+struct pgp_time {
+	u8 time[4];
+};
+
+/*
+ * PGP public-key algorithm identifiers [RFC4880: 9.1]
+ */
+enum pgp_pubkey_algo {
+	PGP_PUBKEY_RSA_ENC_OR_SIG	= 1,
+	PGP_PUBKEY_RSA_ENC_ONLY		= 2,
+	PGP_PUBKEY_RSA_SIG_ONLY		= 3,
+	PGP_PUBKEY_ELGAMAL		= 16,
+	PGP_PUBKEY_DSA			= 17,
+	PGP_PUBKEY__LAST
+};
+
+/*
+ * PGP symmetric-key algorithm identifiers [RFC4880: 9.2]
+ */
+enum pgp_symkey_algo {
+	PGP_SYMKEY_PLAINTEXT		= 0,
+	PGP_SYMKEY_IDEA			= 1,
+	PGP_SYMKEY_3DES			= 2,
+	PGP_SYMKEY_CAST5		= 3,
+	PGP_SYMKEY_BLOWFISH		= 4,
+	PGP_SYMKEY_AES_128KEY		= 7,
+	PGP_SYMKEY_AES_192KEY		= 8,
+	PGP_SYMKEY_AES_256KEY		= 9,
+	PGP_SYMKEY_TWOFISH_256KEY	= 10,
+};
+
+/*
+ * PGP compression algorithm identifiers [RFC4880: 9.3]
+ */
+enum pgp_compr_algo {
+	PGP_COMPR_UNCOMPRESSED		= 0,
+	PGP_COMPR_ZIP			= 1,
+	PGP_COMPR_ZLIB			= 2,
+	PGP_COMPR_BZIP2			= 3,
+};
+
+/*
+ * PGP hash algorithm identifiers [RFC4880: 9.4]
+ */
+enum pgp_hash_algo {
+	PGP_HASH_MD5			= 1,
+	PGP_HASH_SHA1			= 2,
+	PGP_HASH_RIPE_MD_160		= 3,
+	PGP_HASH_SHA256			= 8,
+	PGP_HASH_SHA384			= 9,
+	PGP_HASH_SHA512			= 10,
+	PGP_HASH_SHA224			= 11,
+	PGP_HASH__LAST
+};
+
+extern const char *const pgp_hash_algorithms[PGP_HASH__LAST];
+
+/*
+ * PGP packet type tags [RFC4880: 4.3].
+ */
+enum pgp_packet_tag {
+	PGP_PKT_RESERVED		= 0,
+	PGP_PKT_PUBKEY_ENC_SESSION_KEY	= 1,
+	PGP_PKT_SIGNATURE		= 2,
+	PGP_PKT_SYMKEY_ENC_SESSION_KEY	= 3,
+	PGP_PKT_ONEPASS_SIGNATURE	= 4,
+	PGP_PKT_SECRET_KEY		= 5,
+	PGP_PKT_PUBLIC_KEY		= 6,
+	PGP_PKT_SECRET_SUBKEY		= 7,
+	PGP_PKT_COMPRESSED_DATA		= 8,
+	PGP_PKT_SYM_ENC_DATA		= 9,
+	PGP_PKT_MARKER			= 10,
+	PGP_PKT_LITERAL_DATA		= 11,
+	PGP_PKT_TRUST			= 12,
+	PGP_PKT_USER_ID			= 13,
+	PGP_PKT_PUBLIC_SUBKEY		= 14,
+	PGP_PKT_USER_ATTRIBUTE		= 17,
+	PGP_PKT_SYM_ENC_AND_INTEG_DATA	= 18,
+	PGP_PKT_MODIFY_DETECT_CODE	= 19,
+	PGP_PKT_PRIVATE_0		= 60,
+	PGP_PKT_PRIVATE_3		= 63,
+	PGP_PKT__HIGHEST		= 63
+};
+
+/*
+ * Signature (tag 2) packet [RFC4880: 5.2].
+ */
+enum pgp_signature_version {
+	PGP_SIG_VERSION_3			= 3,
+	PGP_SIG_VERSION_4			= 4,
+};
+
+enum pgp_signature_type {
+	PGP_SIG_BINARY_DOCUMENT_SIG		= 0x00,
+	PGP_SIG_CANONICAL_TEXT_DOCUMENT_SIG	= 0x01,
+	PGP_SIG_STANDALONE_SIG			= 0x02,
+	PGP_SIG_GENERAL_CERT_OF_UID_PUBKEY	= 0x10,
+	PGP_SIG_PERSONAL_CERT_OF_UID_PUBKEY	= 0x11,
+	PGP_SIG_CASUAL_CERT_OF_UID_PUBKEY	= 0x12,
+	PGP_SIG_POSTITIVE_CERT_OF_UID_PUBKEY	= 0x13,
+	PGP_SIG_SUBKEY_BINDING_SIG		= 0x18,
+	PGP_SIG_PRIMARY_KEY_BINDING_SIG		= 0x19,
+	PGP_SIG_DIRECTLY_ON_KEY			= 0x1F,
+	PGP_SIG_KEY_REVOCATION_SIG		= 0x20,
+	PGP_SIG_SUBKEY_REVOCATION_SIG		= 0x28,
+	PGP_SIG_CERT_REVOCATION_SIG		= 0x30,
+	PGP_SIG_TIMESTAMP_SIG			= 0x40,
+	PGP_SIG_THIRD_PARTY_CONFIRM_SIG		= 0x50,
+};
+
+struct pgp_signature_v3_packet {
+	enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_3 */
+	u8	length_of_hashed;	/* == 5 */
+	struct {
+		enum pgp_signature_type signature_type : 8;
+		struct pgp_time	creation_time;
+	} hashed;
+	struct pgp_key_ID issuer;
+	enum pgp_pubkey_algo pubkey_algo : 8;
+	enum pgp_hash_algo hash_algo : 8;
+} __packed;
+
+struct pgp_signature_v4_packet {
+	enum pgp_signature_version version : 8;	/* == PGP_SIG_VERSION_4 */
+	enum pgp_signature_type signature_type : 8;
+	enum pgp_pubkey_algo pubkey_algo : 8;
+	enum pgp_hash_algo hash_algo : 8;
+} __packed;
+
+/*
+ * V4 signature subpacket types [RFC4880: 5.2.3.1].
+ */
+enum pgp_sig_subpkt_type {
+	PGP_SIG_CREATION_TIME			= 2,
+	PGP_SIG_EXPIRATION_TIME			= 3,
+	PGP_SIG_EXPORTABLE_CERT			= 4,
+	PGP_SIG_TRUST_SIG			= 5,
+	PGP_SIG_REGEXP				= 6,
+	PGP_SIG_REVOCABLE			= 7,
+	PGP_SIG_KEY_EXPIRATION_TIME		= 9,
+	PGP_SIG_PREF_SYM_ALGO			= 11,
+	PGP_SIG_REVOCATION_KEY			= 12,
+	PGP_SIG_ISSUER				= 16,
+	PGP_SIG_NOTATION_DATA			= 20,
+	PGP_SIG_PREF_HASH_ALGO			= 21,
+	PGP_SIG_PREF_COMPR_ALGO			= 22,
+	PGP_SIG_KEY_SERVER_PREFS		= 23,
+	PGP_SIG_PREF_KEY_SERVER			= 24,
+	PGP_SIG_PRIMARY_USER_ID			= 25,
+	PGP_SIG_POLICY_URI			= 26,
+	PGP_SIG_KEY_FLAGS			= 27,
+	PGP_SIG_SIGNERS_USER_ID			= 28,
+	PGP_SIG_REASON_FOR_REVOCATION		= 29,
+	PGP_SIG_FEATURES			= 30,
+	PGP_SIG_TARGET				= 31,
+	PGP_SIG_EMBEDDED_SIG			= 32,
+	PGP_SIG__LAST
+};
+
+#define PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK	0x80
+
+/*
+ * Key (tag 5, 6, 7 and 14) packet
+ */
+enum pgp_key_version {
+	PGP_KEY_VERSION_2			= 2,
+	PGP_KEY_VERSION_3			= 3,
+	PGP_KEY_VERSION_4			= 4,
+};
+
+struct pgp_key_v3_packet {
+	enum pgp_key_version version : 8;
+	struct pgp_time	creation_time;
+	u8 expiry[2];				/* 0 or time in days till expiry */
+	enum pgp_pubkey_algo pubkey_algo : 8;
+	u8 key_material[0];
+} __packed;
+
+struct pgp_key_v4_packet {
+	enum pgp_key_version version : 8;
+	struct pgp_time	creation_time;
+	enum pgp_pubkey_algo pubkey_algo : 8;
+	u8 key_material[0];
+} __packed;
+
+#endif /* _LINUX_PGP_H */


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 10/25] PGPLIB: Basic packet parser
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (8 preceding siblings ...)
  2012-08-16  1:35 ` [PATCH 09/25] PGPLIB: PGP definitions (RFC 4880) David Howells
@ 2012-08-16  1:36 ` David Howells
  2012-08-16  1:36 ` [PATCH 11/25] PGPLIB: Signature parser David Howells
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:36 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Provide a simple parser that extracts the packets from a PGP packet blob and
passes the desirous ones to the given processor function:

	struct pgp_parse_context {
		u64 types_of_interest;
		int (*process_packet)(struct pgp_parse_context *context,
				      enum pgp_packet_tag type,
				      u8 headerlen,
				      const u8 *data,
				      size_t datalen);
	};

	int pgp_parse_packets(const u8 *data, size_t datalen,
			      struct pgp_parse_context *ctx);

This is configured on with CONFIG_PGP_LIBRARY.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 include/linux/pgplib.h             |   47 ++++++
 security/keys/crypto/Kconfig       |    6 +
 security/keys/crypto/Makefile      |    1 
 security/keys/crypto/pgp_library.c |  268 ++++++++++++++++++++++++++++++++++++
 4 files changed, 322 insertions(+)
 create mode 100644 include/linux/pgplib.h
 create mode 100644 security/keys/crypto/pgp_library.c


diff --git a/include/linux/pgplib.h b/include/linux/pgplib.h
new file mode 100644
index 0000000..a045b3a
--- /dev/null
+++ b/include/linux/pgplib.h
@@ -0,0 +1,47 @@
+/* PGP library definitions (RFC 4880)
+ *
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _LINUX_PGPLIB_H
+#define _LINUX_PGPLIB_H
+
+#if defined(CONFIG_PGP_LIBRARY) || defined(CONFIG_PGP_LIBRARY_MODULE)
+
+#include <linux/pgp.h>
+
+/*
+ * PGP library packet parser
+ */
+struct pgp_parse_context {
+	u64 types_of_interest;
+	int (*process_packet)(struct pgp_parse_context *context,
+			      enum pgp_packet_tag type,
+			      u8 headerlen,
+			      const u8 *data,
+			      size_t datalen);
+};
+
+extern int pgp_parse_packets(const u8 *data, size_t datalen,
+			     struct pgp_parse_context *ctx);
+
+struct pgp_parse_pubkey {
+	enum pgp_key_version version : 8;
+	enum pgp_pubkey_algo pubkey_algo : 8;
+	time_t		creation_time;
+	time_t		expires_at;
+};
+
+extern int pgp_parse_public_key(const u8 **_data, size_t *_datalen,
+				struct pgp_parse_pubkey *pk);
+
+
+#endif /* CONFIG_PGP_LIBRARY */
+
+#endif /* _LINUX_PGPLIB_H */
diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig
index 4e3777e..88ce0e2 100644
--- a/security/keys/crypto/Kconfig
+++ b/security/keys/crypto/Kconfig
@@ -22,3 +22,9 @@ config CRYPTO_KEY_PKEY_ALGO_RSA
 	select MPILIB_EXTRA
 	help
 	  This option enables support for the RSA algorithm (PKCS#1, RFC3447).
+
+config PGP_LIBRARY
+	tristate "PGP parsing library"
+	help
+	  This option enables a library that provides a number of simple
+	  utility functions for parsing PGP (RFC 4880) packet-based messages.
diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile
index b6b1a5a..5fbe54e 100644
--- a/security/keys/crypto/Makefile
+++ b/security/keys/crypto/Makefile
@@ -7,3 +7,4 @@ crypto_keys-y := crypto_type.o crypto_verify.o
 
 obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o
 obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o
+obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o
diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c
new file mode 100644
index 0000000..39d2878
--- /dev/null
+++ b/security/keys/crypto/pgp_library.c
@@ -0,0 +1,268 @@
+/* PGP packet parser (RFC 4880)
+ *
+ * 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 pr_fmt(fmt) "PGP: "fmt
+#include <linux/pgplib.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+MODULE_LICENSE("GPL");
+
+const char *const pgp_hash_algorithms[PGP_HASH__LAST] = {
+	[PGP_HASH_MD5]			= "md5",
+	[PGP_HASH_SHA1]			= "sha1",
+	[PGP_HASH_RIPE_MD_160]		= "rmd160",
+	[PGP_HASH_SHA256]		= "sha256",
+	[PGP_HASH_SHA384]		= "sha384",
+	[PGP_HASH_SHA512]		= "sha512",
+	[PGP_HASH_SHA224]		= "sha224",
+};
+EXPORT_SYMBOL_GPL(pgp_hash_algorithms);
+
+/**
+ * pgp_parse_packet_header - Parse a PGP packet header
+ * @_data: Start of the PGP packet (updated to PGP packet data)
+ * @_datalen: Amount of data remaining in buffer (decreased)
+ * @_type: Where the packet type will be returned
+ * @_headerlen: Where the header length will be returned
+ *
+ * Parse a set of PGP packet header [RFC 4880: 4.2].
+ *
+ * Returns packet data size on success; non-zero on error.  If successful,
+ * *_data and *_datalen will have been updated and *_headerlen will be set to
+ * hold the length of the packet header.
+ */
+static ssize_t pgp_parse_packet_header(const u8 **_data, size_t *_datalen,
+				       enum pgp_packet_tag *_type,
+				       u8 *_headerlen)
+{
+	enum pgp_packet_tag type;
+	const u8 *data = *_data;
+	size_t size, datalen = *_datalen;
+
+	pr_devel("-->pgp_parse_packet_header(,%zu,,)\n", datalen);
+
+	if (datalen < 2)
+		goto short_packet;
+
+	pr_devel("pkthdr %02x, %02x\n", data[0], data[1]);
+
+	type = *data++;
+	datalen--;
+	if (!(type & 0x80)) {
+		pr_debug("Packet type does not have MSB set\n");
+		return -EBADMSG;
+	}
+	type &= ~0x80;
+
+	if (type & 0x40) {
+		/* New packet length format */
+		type &= ~0x40;
+		pr_devel("new format: t=%u\n", type);
+		switch (data[0]) {
+		case 0x00 ... 0xbf:
+			/* One-byte length */
+			size = data[0];
+			data++;
+			datalen--;
+			*_headerlen = 2;
+			break;
+		case 0xc0 ... 0xdf:
+			/* Two-byte length */
+			if (datalen < 2)
+				goto short_packet;
+			size = (data[0] - 192) * 256;
+			size += data[1] + 192;
+			data += 2;
+			datalen -= 2;
+			*_headerlen = 3;
+			break;
+		case 0xff:
+			/* Five-byte length */
+			if (datalen < 5)
+				goto short_packet;
+			size =  data[1] << 24;
+			size |= data[2] << 16;
+			size |= data[3] << 8;
+			size |= data[4];
+			data += 5;
+			datalen -= 5;
+			*_headerlen = 6;
+			break;
+		default:
+			pr_debug("Partial body length packet not supported\n");
+			return -EBADMSG;
+		}
+	} else {
+		/* Old packet length format */
+		u8 length_type = type & 0x03;
+		type >>= 2;
+		pr_devel("old format: t=%u lt=%u\n", type, length_type);
+
+		switch (length_type) {
+		case 0:
+			/* One-byte length */
+			size = data[0];
+			data++;
+			datalen--;
+			*_headerlen = 2;
+			break;
+		case 1:
+			/* Two-byte length */
+			if (datalen < 2)
+				goto short_packet;
+			size  = data[0] << 8;
+			size |= data[1];
+			data += 2;
+			datalen -= 2;
+			*_headerlen = 3;
+			break;
+		case 2:
+			/* Four-byte length */
+			if (datalen < 4)
+				goto short_packet;
+			size  = data[0] << 24;
+			size |= data[1] << 16;
+			size |= data[2] << 8;
+			size |= data[3];
+			data += 4;
+			datalen -= 4;
+			*_headerlen = 5;
+			break;
+		default:
+			pr_debug("Indefinite length packet not supported\n");
+			return -EBADMSG;
+		}
+	}
+
+	pr_devel("datalen=%zu size=%zu", datalen, size);
+	if (datalen < size)
+		goto short_packet;
+	if ((int)size < 0)
+		goto too_big;
+
+	*_data = data;
+	*_datalen = datalen;
+	*_type = type;
+	pr_devel("Found packet type=%u size=%zd\n", type, size);
+	return size;
+
+short_packet:
+	pr_debug("Attempt to parse short packet\n");
+	return -EBADMSG;
+too_big:
+	pr_debug("Signature subpacket size >2G\n");
+	return -EMSGSIZE;
+}
+
+/**
+ * pgp_parse_packets - Parse a set of PGP packets
+ * @_data: Data to be parsed (updated)
+ * @_datalen: Amount of data (updated)
+ * @ctx: Parsing context
+ *
+ * Parse a set of PGP packets [RFC 4880: 4].
+ */
+int pgp_parse_packets(const u8 *data, size_t datalen,
+		      struct pgp_parse_context *ctx)
+{
+	enum pgp_packet_tag type;
+	ssize_t pktlen;
+	u8 headerlen;
+	int ret;
+
+	while (datalen > 2) {
+		pktlen = pgp_parse_packet_header(&data, &datalen, &type,
+						 &headerlen);
+		if (pktlen < 0)
+			return pktlen;
+
+		if ((ctx->types_of_interest >> type) & 1) {
+			ret = ctx->process_packet(ctx, type, headerlen,
+						  data, pktlen);
+			if (ret < 0)
+				return ret;
+		}
+		data += pktlen;
+		datalen -= pktlen;
+	}
+
+	if (datalen != 0) {
+		pr_debug("Excess octets in packet stream\n");
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pgp_parse_packets);
+
+/**
+ * pgp_parse_public_key - Parse the common part of a PGP pubkey packet
+ * @_data: Content of packet (updated)
+ * @_datalen: Length of packet remaining (updated)
+ * @pk: Public key data
+ *
+ * Parse the common data struct for a PGP pubkey packet [RFC 4880: 5.5.2].
+ */
+int pgp_parse_public_key(const u8 **_data, size_t *_datalen,
+			 struct pgp_parse_pubkey *pk)
+{
+	const u8 *data = *_data;
+	size_t datalen = *_datalen;
+	__be32 tmp;
+
+	if (datalen < 12) {
+		pr_debug("Public key packet too short\n");
+		return -EBADMSG;
+	}
+
+	pk->version = *data++;
+	switch (pk->version) {
+	case PGP_KEY_VERSION_2:
+	case PGP_KEY_VERSION_3:
+	case PGP_KEY_VERSION_4:
+		break;
+	default:
+		pr_debug("Public key packet with unhandled version %d\n",
+			   pk->version);
+		return -EBADMSG;
+	}
+
+	tmp  = *data++ << 24;
+	tmp |= *data++ << 16;
+	tmp |= *data++ << 8;
+	tmp |= *data++;
+	pk->creation_time = tmp;
+	if (pk->version == PGP_KEY_VERSION_4) {
+		pk->expires_at = 0; /* Have to get it from the selfsignature */
+	} else {
+		unsigned short ndays;
+		ndays  = *data++ << 8;
+		ndays |= *data++;
+		if (ndays)
+			pk->expires_at = pk->creation_time + ndays * 86400UL;
+		else
+			pk->expires_at = 0;
+		datalen -= 2;
+	}
+
+	pk->pubkey_algo = *data++;
+	datalen -= 6;
+
+	pr_devel("%x,%x,%lx,%lx",
+		 pk->version, pk->pubkey_algo, pk->creation_time,
+		 pk->expires_at);
+
+	*_data = data;
+	*_datalen = datalen;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pgp_parse_public_key);


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 11/25] PGPLIB: Signature parser
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (9 preceding siblings ...)
  2012-08-16  1:36 ` [PATCH 10/25] PGPLIB: Basic packet parser David Howells
@ 2012-08-16  1:36 ` David Howells
  2012-08-16  1:36 ` [PATCH 12/25] KEYS: PGP data parser David Howells
                   ` (16 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:36 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Provide some PGP signature parsing helpers:

 (1) A function to parse V4 signature subpackets and pass the desired ones to
     a processor function:

	int pgp_parse_sig_subpkts(const u8 *data, size_t datalen,
				  struct pgp_parse_sig_context *ctx);

 (2) A function to parse out basic signature parameters from any PGP signature
     such that the algorithms and public key can be selected:

	int pgp_parse_sig_params(const u8 **_data, size_t *_datalen,
				 struct pgp_sig_parameters *p);

Signed-off-by: David Howells <dhowells@redhat.com>
---

 include/linux/pgplib.h             |   25 +++
 security/keys/crypto/pgp_library.c |  280 ++++++++++++++++++++++++++++++++++++
 2 files changed, 305 insertions(+)


diff --git a/include/linux/pgplib.h b/include/linux/pgplib.h
index a045b3a..34594a9 100644
--- a/include/linux/pgplib.h
+++ b/include/linux/pgplib.h
@@ -41,6 +41,31 @@ struct pgp_parse_pubkey {
 extern int pgp_parse_public_key(const u8 **_data, size_t *_datalen,
 				struct pgp_parse_pubkey *pk);
 
+struct pgp_parse_sig_context {
+	unsigned long types_of_interest[128 / BITS_PER_LONG];
+	int (*process_packet)(struct pgp_parse_sig_context *context,
+			      enum pgp_sig_subpkt_type type,
+			      const u8 *data,
+			      size_t datalen);
+};
+
+extern int pgp_parse_sig_packets(const u8 *data, size_t datalen,
+				 struct pgp_parse_sig_context *ctx);
+
+struct pgp_sig_parameters {
+	enum pgp_signature_version version : 8;
+	enum pgp_signature_type signature_type : 8;
+	enum pgp_pubkey_algo pubkey_algo : 8;
+	enum pgp_hash_algo hash_algo : 8;
+	union {
+		struct pgp_key_ID issuer;
+		__be32 issuer32[2];
+	};
+};
+
+extern int pgp_parse_sig_params(const u8 **_data, size_t *_datalen,
+				struct pgp_sig_parameters *p);
+
 
 #endif /* CONFIG_PGP_LIBRARY */
 
diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c
index 39d2878..50b7fa0 100644
--- a/security/keys/crypto/pgp_library.c
+++ b/security/keys/crypto/pgp_library.c
@@ -266,3 +266,283 @@ int pgp_parse_public_key(const u8 **_data, size_t *_datalen,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pgp_parse_public_key);
+
+/**
+ * pgp_parse_sig_subpkt_header - Parse a PGP V4 signature subpacket header
+ * @_data: Start of the subpacket (updated to subpacket data)
+ * @_datalen: Amount of data remaining in buffer (decreased)
+ * @_type: Where the subpacket type will be returned
+ *
+ * Parse a PGP V4 signature subpacket header [RFC 4880: 5.2.3.1].
+ *
+ * Returns packet data size on success; non-zero on error.  If successful,
+ * *_data and *_datalen will have been updated and *_headerlen will be set to
+ * hold the length of the packet header.
+ */
+static ssize_t pgp_parse_sig_subpkt_header(const u8 **_data, size_t *_datalen,
+					   enum pgp_sig_subpkt_type *_type)
+{
+	enum pgp_sig_subpkt_type type;
+	const u8 *data = *_data;
+	size_t size, datalen = *_datalen;
+
+	pr_devel("-->pgp_parse_sig_subpkt_header(,%zu,,)", datalen);
+
+	if (datalen < 2)
+		goto short_subpacket;
+
+	pr_devel("subpkt hdr %02x, %02x\n", data[0], data[1]);
+
+	switch (data[0]) {
+	case 0x00 ... 0xbf:
+		/* One-byte length */
+		size = data[0];
+		data++;
+		datalen--;
+		break;
+	case 0xc0 ... 0xfe:
+		/* Two-byte length */
+		if (datalen < 3)
+			goto short_subpacket;
+		size = (data[0] - 192) * 256;
+		size += data[1] + 192;
+		data += 2;
+		datalen -= 2;
+		break;
+	case 0xff:
+		if (datalen < 6)
+			goto short_subpacket;
+		size  = data[1] << 24;
+		size |= data[2] << 16;
+		size |= data[3] << 8;
+		size |= data[4];
+		data += 5;
+		datalen -= 5;
+		break;
+	}
+
+	/* The type octet is included in the size */
+	pr_devel("datalen=%zu size=%zu", datalen, size);
+	if (datalen < size)
+		goto short_subpacket;
+	if (size == 0)
+		goto very_short_subpacket;
+	if ((int)size < 0)
+		goto too_big;
+
+	type = *data++ & ~PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK;
+	datalen--;
+	size--;
+
+	*_data = data;
+	*_datalen = datalen;
+	*_type = type;
+	pr_devel("Found subpkt type=%u size=%zd\n", type, size);
+	return size;
+
+very_short_subpacket:
+	pr_debug("Signature subpacket size can't be zero\n");
+	return -EBADMSG;
+short_subpacket:
+	pr_debug("Attempt to parse short signature subpacket\n");
+	return -EBADMSG;
+too_big:
+	pr_debug("Signature subpacket size >2G\n");
+	return -EMSGSIZE;
+}
+
+/**
+ * pgp_parse_sig_subpkts - Parse a set of PGP V4 signatute subpackets
+ * @_data: Data to be parsed (updated)
+ * @_datalen: Amount of data (updated)
+ * @ctx: Parsing context
+ *
+ * Parse a set of PGP signature subpackets [RFC 4880: 5.2.3].
+ */
+static int pgp_parse_sig_subpkts(const u8 *data, size_t datalen,
+				 struct pgp_parse_sig_context *ctx)
+{
+	enum pgp_sig_subpkt_type type;
+	ssize_t pktlen;
+	int ret;
+
+	pr_devel("-->pgp_parse_sig_subpkts(,%zu,,)", datalen);
+
+	while (datalen > 2) {
+		pktlen = pgp_parse_sig_subpkt_header(&data, &datalen, &type);
+		if (pktlen < 0)
+			return pktlen;
+		if (test_bit(type, ctx->types_of_interest)) {
+			ret = ctx->process_packet(ctx, type, data, pktlen);
+			if (ret < 0)
+				return ret;
+		}
+		data += pktlen;
+		datalen -= pktlen;
+	}
+
+	if (datalen != 0) {
+		pr_debug("Excess octets in signature subpacket stream\n");
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+
+struct pgp_parse_sig_params_ctx {
+	struct pgp_parse_sig_context base;
+	struct pgp_sig_parameters *params;
+	bool got_the_issuer;
+};
+
+/*
+ * Process a V4 signature subpacket.
+ */
+static int pgp_process_sig_params_subpkt(struct pgp_parse_sig_context *context,
+					 enum pgp_sig_subpkt_type type,
+					 const u8 *data,
+					 size_t datalen)
+{
+	struct pgp_parse_sig_params_ctx *ctx =
+		container_of(context, struct pgp_parse_sig_params_ctx, base);
+
+	if (ctx->got_the_issuer) {
+		pr_debug("V4 signature packet has multiple issuers\n");
+		return -EBADMSG;
+	}
+
+	if (datalen != 8) {
+		pr_debug("V4 signature issuer subpkt not 8 long (%zu)\n",
+			   datalen);
+		return -EBADMSG;
+	}
+
+	memcpy(&ctx->params->issuer, data, 8);
+	ctx->got_the_issuer = true;
+	return 0;
+}
+
+/**
+ * pgp_parse_sig_params - Parse basic parameters from a PGP signature packet
+ * @_data: Content of packet (updated)
+ * @_datalen: Length of packet remaining (updated)
+ * @p: The basic parameters
+ *
+ * Parse the basic parameters from a PGP signature packet [RFC 4880: 5.2] that
+ * are needed to start off a signature verification operation.  The only ones
+ * actually necessary are the signature type (which affects how the data is
+ * transformed) and the hash algorithm.
+ *
+ * We also extract the public key algorithm and the issuer's key ID as we'll
+ * need those to determine if we actually have the public key available.  If
+ * not, then we can't verify the signature anyway.
+ *
+ * Returns 0 if successful or a negative error code.  *_data and *_datalen are
+ * updated to point to the 16-bit subset of the hash value and the set of MPIs.
+ */
+int pgp_parse_sig_params(const u8 **_data, size_t *_datalen,
+			 struct pgp_sig_parameters *p)
+{
+	const u8 *data = *_data;
+	size_t datalen = *_datalen;
+	int ret;
+
+	pr_devel("-->pgp_parse_sig_params(,%zu,,)", datalen);
+
+	if (datalen < 1)
+		return -EBADMSG;
+	p->version = *data;
+
+	if (p->version == PGP_SIG_VERSION_3) {
+		const struct pgp_signature_v3_packet *v3 = (const void *)data;
+
+		if (datalen < sizeof(*v3)) {
+			pr_debug("Short V3 signature packet\n");
+			return -EBADMSG;
+		}
+		datalen -= sizeof(*v3);
+		data += sizeof(*v3);
+
+		/* V3 has everything we need in the header */
+		p->signature_type = v3->hashed.signature_type;
+		p->issuer = v3->issuer;
+		p->pubkey_algo = v3->pubkey_algo;
+		p->hash_algo = v3->hash_algo;
+
+	} else if (p->version == PGP_SIG_VERSION_4) {
+		const struct pgp_signature_v4_packet *v4 = (const void *)data;
+		struct pgp_parse_sig_params_ctx ctx = {
+			.base.process_packet = pgp_process_sig_params_subpkt,
+			.params = p,
+			.got_the_issuer = false,
+		};
+		size_t subdatalen;
+
+		if (datalen < sizeof(*v4) + 2 + 2 + 2) {
+			pr_debug("Short V4 signature packet\n");
+			return -EBADMSG;
+		}
+		datalen -= sizeof(*v4);
+		data += sizeof(*v4);
+
+		/* V4 has most things in the header... */
+		p->signature_type = v4->signature_type;
+		p->pubkey_algo = v4->pubkey_algo;
+		p->hash_algo = v4->hash_algo;
+
+		/* ... but we have to get the key ID from the subpackets, of
+		 * which there are two sets. */
+		__set_bit(PGP_SIG_ISSUER, ctx.base.types_of_interest);
+
+		subdatalen  = *data++ << 8;
+		subdatalen |= *data++;
+		datalen -= 2;
+		if (subdatalen) {
+			/* Hashed subpackets */
+			pr_devel("hashed data: %zu (after %zu)\n",
+				 subdatalen, sizeof(*v4));
+			if (subdatalen > datalen + 2 + 2) {
+				pr_debug("Short V4 signature packet [hdata]\n");
+				return -EBADMSG;
+			}
+			ret = pgp_parse_sig_subpkts(data, subdatalen,
+						    &ctx.base);
+			if (ret < 0)
+				return ret;
+			data += subdatalen;
+			datalen -= subdatalen;
+		}
+
+		subdatalen  = *data++ << 8;
+		subdatalen |= *data++;
+		datalen -= 2;
+		if (subdatalen) {
+			/* Unhashed subpackets */
+			pr_devel("unhashed data: %zu\n", subdatalen);
+			if (subdatalen > datalen + 2) {
+				pr_debug("Short V4 signature packet [udata]\n");
+				return -EBADMSG;
+			}
+			ret = pgp_parse_sig_subpkts(data, subdatalen,
+						    &ctx.base);
+			if (ret < 0)
+				return ret;
+			data += subdatalen;
+			datalen -= subdatalen;
+		}
+
+		if (!ctx.got_the_issuer) {
+			pr_debug("V4 signature packet lacks issuer\n");
+			return -EBADMSG;
+		}
+	} else {
+		pr_debug("Signature packet with unhandled version %d\n",
+			 p->version);
+		return -EBADMSG;
+	}
+
+	*_data = data;
+	*_datalen = datalen;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pgp_parse_sig_params);


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 12/25] KEYS: PGP data parser
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (10 preceding siblings ...)
  2012-08-16  1:36 ` [PATCH 11/25] PGPLIB: Signature parser David Howells
@ 2012-08-16  1:36 ` David Howells
  2012-08-16  1:36 ` [PATCH 13/25] KEYS: PGP-based public key signature verification David Howells
                   ` (15 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:36 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Implement a PGP data parser for the crypto key type to use when instantiating a
key.

This parser attempts to parse the instantiation data as a PGP packet sequence
(RFC 4880) and if it parses okay, attempts to extract a public-key algorithm
key or subkey from it.

If it finds such a key, it will set up a public_key subtype payload with
appropriate handler routines (DSA or RSA) and attach it to the key.

Thanks to Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> for pointing out
some errors.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 security/keys/crypto/Kconfig          |   12 +
 security/keys/crypto/Makefile         |    4 
 security/keys/crypto/pgp_parser.h     |   23 ++
 security/keys/crypto/pgp_public_key.c |  344 +++++++++++++++++++++++++++++++++
 4 files changed, 383 insertions(+)
 create mode 100644 security/keys/crypto/pgp_parser.h
 create mode 100644 security/keys/crypto/pgp_public_key.c


diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig
index 88ce0e2..1c2ae55 100644
--- a/security/keys/crypto/Kconfig
+++ b/security/keys/crypto/Kconfig
@@ -28,3 +28,15 @@ config PGP_LIBRARY
 	help
 	  This option enables a library that provides a number of simple
 	  utility functions for parsing PGP (RFC 4880) packet-based messages.
+
+config CRYPTO_KEY_PGP_PARSER
+	tristate "PGP key blob parser"
+	depends on CRYPTO_KEY_TYPE
+	select CRYPTO_KEY_PUBLIC_KEY_SUBTYPE
+	select PGP_LIBRARY
+	select MD5 # V3 fingerprint generation
+	select SHA1 # V4 fingerprint generation
+	help
+	  This option provides support for parsing PGP (RFC 4880) format blobs
+	  for key data and provides the ability to instantiate a crypto key
+	  from a public key packet found inside the blob.
diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile
index 5fbe54e..35733fc 100644
--- a/security/keys/crypto/Makefile
+++ b/security/keys/crypto/Makefile
@@ -8,3 +8,7 @@ crypto_keys-y := crypto_type.o crypto_verify.o
 obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o
 obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o
 obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o
+
+obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_key_parser.o
+pgp_key_parser-y := \
+	pgp_public_key.o
diff --git a/security/keys/crypto/pgp_parser.h b/security/keys/crypto/pgp_parser.h
new file mode 100644
index 0000000..1cda231
--- /dev/null
+++ b/security/keys/crypto/pgp_parser.h
@@ -0,0 +1,23 @@
+/* PGP crypto data parser 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.
+ */
+
+#include <linux/pgp.h>
+
+#define kenter(FMT, ...) \
+	pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
+#define kleave(FMT, ...) \
+	pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
+
+/*
+ * pgp_key_parser.c
+ */
+extern const
+struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST];
diff --git a/security/keys/crypto/pgp_public_key.c b/security/keys/crypto/pgp_public_key.c
new file mode 100644
index 0000000..c260e02
--- /dev/null
+++ b/security/keys/crypto/pgp_public_key.c
@@ -0,0 +1,344 @@
+/* Instantiate a public key crypto key from PGP format data [RFC 4880]
+ *
+ * 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 pr_fmt(fmt) "PGP: "fmt
+#include <keys/crypto-subtype.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mpi.h>
+#include <linux/pgplib.h>
+#include <crypto/hash.h>
+#include "public_key.h"
+#include "pgp_parser.h"
+
+MODULE_LICENSE("GPL");
+
+const
+struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST] = {
+#if defined(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) || \
+	defined(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA_MODULE)
+	[PGP_PUBKEY_RSA_ENC_OR_SIG]	= &RSA_public_key_algorithm,
+	[PGP_PUBKEY_RSA_ENC_ONLY]	= &RSA_public_key_algorithm,
+	[PGP_PUBKEY_RSA_SIG_ONLY]	= &RSA_public_key_algorithm,
+#endif
+	[PGP_PUBKEY_ELGAMAL]		= NULL,
+	[PGP_PUBKEY_DSA]		= NULL,
+};
+
+static const u8 pgp_public_key_capabilities[PGP_PUBKEY__LAST] = {
+	[PGP_PUBKEY_RSA_ENC_OR_SIG]	= PKEY_CAN_ENCDEC | PKEY_CAN_SIGVER,
+	[PGP_PUBKEY_RSA_ENC_ONLY]	= PKEY_CAN_ENCDEC,
+	[PGP_PUBKEY_RSA_SIG_ONLY]	= PKEY_CAN_SIGVER,
+	[PGP_PUBKEY_ELGAMAL]		= 0,
+	[PGP_PUBKEY_DSA]		= 0,
+};
+
+static inline void digest_putc(struct shash_desc *digest, uint8_t ch)
+{
+	crypto_shash_update(digest, &ch, 1);
+}
+
+struct pgp_key_data_parse_context {
+	struct pgp_parse_context pgp;
+	struct crypto_key_subtype *subtype;
+	char *fingerprint;
+	void *payload;
+};
+
+/*
+ * Calculate the public key ID (RFC4880 12.2)
+ */
+static int pgp_calc_pkey_keyid(struct shash_desc *digest,
+			       struct pgp_parse_pubkey *pgp,
+			       struct public_key *key)
+{
+	unsigned nb[ARRAY_SIZE(key->mpi)];
+	unsigned nn[ARRAY_SIZE(key->mpi)];
+	unsigned n;
+	u8 *pp[ARRAY_SIZE(key->mpi)];
+	u32 a32;
+	int npkey = key->algo->n_pub_mpi;
+	int i, ret = -ENOMEM;
+
+	kenter("");
+
+	for (i = 0; i < ARRAY_SIZE(pp); i++)
+		pp[i] = NULL;
+
+	n = (pgp->version < PGP_KEY_VERSION_4) ? 8 : 6;
+	for (i = 0; i < npkey; i++) {
+		nb[i] = mpi_get_nbits(key->mpi[i]);
+		pp[i] = mpi_get_buffer(key->mpi[i], nn + i, NULL);
+		if (!pp[i])
+			goto error;
+		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, pgp->version);
+
+	a32 = pgp->creation_time;
+	digest_putc(digest, a32 >> 24);
+	digest_putc(digest, a32 >> 16);
+	digest_putc(digest, a32 >>  8);
+	digest_putc(digest, a32 >>  0);
+
+	if (pgp->version < PGP_KEY_VERSION_4) {
+		u16 a16;
+
+		if (pgp->expires_at)
+			a16 = (pgp->expires_at - pgp->creation_time) / 86400UL;
+		else
+			a16 = 0;
+		digest_putc(digest, a16 >> 8);
+		digest_putc(digest, a16 >> 0);
+	}
+
+	digest_putc(digest, 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]);
+	}
+	ret = 0;
+
+error:
+	for (i = 0; i < npkey; i++)
+		kfree(pp[i]);
+	kleave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * Calculate the public key ID fingerprint
+ */
+static int pgp_generate_fingerprint(struct pgp_key_data_parse_context *ctx,
+				    struct pgp_parse_pubkey *pgp,
+				    struct public_key *key)
+{
+	struct crypto_shash *tfm;
+	struct shash_desc *digest;
+	char *fingerprint;
+	u8 *raw_fingerprint;
+	int digest_size, offset;
+	int ret, i;
+
+	ret = -ENOMEM;
+	tfm = crypto_alloc_shash(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;
+
+	ret = pgp_calc_pkey_keyid(digest, pgp, key);
+	if (ret < 0)
+		goto cleanup_hash;
+
+	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;
+	pr_debug("offset %u/%u\n", offset, digest_size);
+
+	for (i = 0; i < digest_size; i++)
+		sprintf(fingerprint + i * 2, "%02x", raw_fingerprint[i]);
+	pr_debug("fingerprint %s\n", fingerprint);
+
+	memcpy(&key->key_id, raw_fingerprint + offset, 8);
+	key->key_id_size = 8;
+	key->id_type = PKEY_ID_PGP;
+
+	ctx->fingerprint = fingerprint;
+	ret = 0;
+cleanup_raw_fingerprint:
+	kfree(raw_fingerprint);
+cleanup_hash:
+	kfree(digest);
+cleanup_tfm:
+	crypto_free_shash(tfm);
+cleanup:
+	kleave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * Extract a public key or public subkey from the PGP stream.
+ */
+static int pgp_process_public_key(struct pgp_parse_context *context,
+				  enum pgp_packet_tag type,
+				  u8 headerlen,
+				  const u8 *data,
+				  size_t datalen)
+{
+	const struct public_key_algorithm *algo;
+	struct pgp_key_data_parse_context *ctx =
+		container_of(context, struct pgp_key_data_parse_context, pgp);
+	struct pgp_parse_pubkey pgp;
+	struct public_key *key;
+	int i, ret;
+
+	kenter(",%u,%u,,%zu", type, headerlen, datalen);
+
+	if (ctx->subtype) {
+		kleave(" = -ENOKEY [already]");
+		return -EBADMSG;
+	}
+
+	key = kzalloc(sizeof(struct public_key), GFP_KERNEL);
+	if (!key)
+		return -ENOMEM;
+
+	ret = pgp_parse_public_key(&data, &datalen, &pgp);
+	if (ret < 0)
+		goto cleanup;
+
+	if (pgp.pubkey_algo >= PGP_PUBKEY__LAST ||
+	    !pgp_public_key_algorithms[pgp.pubkey_algo]) {
+		pr_debug("Unsupported public key algorithm %u\n",
+			 pgp.pubkey_algo);
+		ret = -ENOPKG;
+		goto cleanup;
+	}
+
+	algo = key->algo = pgp_public_key_algorithms[pgp.pubkey_algo];
+
+	/* It's a public key, so that only gives us encrypt and verify
+	 * capabilities.
+	 */
+	key->capabilities = pgp_public_key_capabilities[pgp.pubkey_algo] &
+		(PKEY_CAN_ENCRYPT | PKEY_CAN_VERIFY);
+
+	for (i = 0; i < algo->n_pub_mpi; i++) {
+		unsigned int remaining = datalen;
+		if (remaining == 0) {
+			pr_debug("short %zu mpi %d\n", datalen, i);
+			goto cleanup_badmsg;
+		}
+		key->mpi[i] = mpi_read_from_buffer(data, &remaining);
+		if (!key->mpi[i])
+			goto cleanup_nomem;
+		data += remaining;
+		datalen -= remaining;
+	}
+
+	if (datalen != 0) {
+		pr_debug("excess %zu\n", datalen);
+		goto cleanup_badmsg;
+	}
+
+	ret = pgp_generate_fingerprint(ctx, &pgp, key);
+	if (ret < 0)
+		goto cleanup;
+
+	/* We're pinning the module by being linked against it */
+	__module_get(public_key_crypto_key_subtype.owner);
+	ctx->subtype = &public_key_crypto_key_subtype;
+	ctx->payload = key;
+	kleave(" = 0 [use]");
+	return 0;
+
+cleanup_nomem:
+	ret = -ENOMEM;
+	goto cleanup;
+cleanup_badmsg:
+	ret = -EBADMSG;
+cleanup:
+	pr_devel("cleanup");
+	if (key) {
+		for (i = 0; i < ARRAY_SIZE(key->mpi); i++)
+			mpi_free(key->mpi[i]);
+		kfree(key);
+	}
+	kleave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * Attempt to parse the instantiation data blob for a key as a PGP packet
+ * message holding a key.
+ */
+static int pgp_key_preparse(struct key_preparsed_payload *prep)
+{
+	struct pgp_key_data_parse_context ctx;
+	int ret;
+
+	kenter("");
+
+	ctx.pgp.types_of_interest =
+		(1 << PGP_PKT_PUBLIC_KEY) | (1 << PGP_PKT_PUBLIC_SUBKEY);
+	ctx.pgp.process_packet = pgp_process_public_key;
+	ctx.subtype = NULL;
+	ctx.fingerprint = NULL;
+	ctx.payload = NULL;
+
+	ret = pgp_parse_packets(prep->data, prep->datalen, &ctx.pgp);
+	if (ret < 0) {
+		if (ctx.payload)
+			ctx.subtype->destroy(ctx.payload);
+		if (ctx.subtype)
+			module_put(ctx.subtype->owner);
+		kfree(ctx.fingerprint);
+		return ret;
+	}
+
+	prep->type_data[0] = ctx.subtype;
+	prep->type_data[1] = ctx.fingerprint;
+	prep->payload = ctx.payload;
+	prep->quotalen = prep->datalen;
+	return 0;
+}
+
+static struct crypto_key_parser pgp_key_parser = {
+	.owner		= THIS_MODULE,
+	.name		= "pgp",
+	.preparse	= pgp_key_preparse,
+};
+
+/*
+ * Module stuff
+ */
+static int __init pgp_key_init(void)
+{
+	return register_crypto_key_parser(&pgp_key_parser);
+}
+
+static void __exit pgp_key_exit(void)
+{
+	unregister_crypto_key_parser(&pgp_key_parser);
+}
+
+module_init(pgp_key_init);
+module_exit(pgp_key_exit);


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 13/25] KEYS: PGP-based public key signature verification
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (11 preceding siblings ...)
  2012-08-16  1:36 ` [PATCH 12/25] KEYS: PGP data parser David Howells
@ 2012-08-16  1:36 ` David Howells
  2012-08-16  1:36 ` [PATCH 14/25] KEYS: PGP format signature parser David Howells
                   ` (14 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:36 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Provide handlers for PGP-based public-key algorithm signature verification.
This does most of the work involved in signature verification as most of it is
public-key algorithm agnostic.  The public-key verification algorithm itself
is just the last little bit and is supplied the complete hash data to process.

This requires glue logic putting on top to make use of it - something the next
patch provides.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 security/keys/crypto/Makefile         |    3 
 security/keys/crypto/pgp_parser.h     |    6 +
 security/keys/crypto/pgp_sig_verify.c |  325 +++++++++++++++++++++++++++++++++
 3 files changed, 333 insertions(+), 1 deletion(-)
 create mode 100644 security/keys/crypto/pgp_sig_verify.c


diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile
index 35733fc..0c8b8a1 100644
--- a/security/keys/crypto/Makefile
+++ b/security/keys/crypto/Makefile
@@ -11,4 +11,5 @@ obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o
 
 obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_key_parser.o
 pgp_key_parser-y := \
-	pgp_public_key.o
+	pgp_public_key.o \
+	pgp_sig_verify.o
diff --git a/security/keys/crypto/pgp_parser.h b/security/keys/crypto/pgp_parser.h
index 1cda231..6f5b3af 100644
--- a/security/keys/crypto/pgp_parser.h
+++ b/security/keys/crypto/pgp_parser.h
@@ -21,3 +21,9 @@
  */
 extern const
 struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST];
+
+/*
+ * pgp_pubkey_sig.c
+ */
+extern struct crypto_sig_verify_context *pgp_pkey_verify_sig_begin(
+	struct key *crypto_key, const u8 *sigdata, size_t siglen);
diff --git a/security/keys/crypto/pgp_sig_verify.c b/security/keys/crypto/pgp_sig_verify.c
new file mode 100644
index 0000000..f9bb949
--- /dev/null
+++ b/security/keys/crypto/pgp_sig_verify.c
@@ -0,0 +1,325 @@
+/* PGP public key signature verification [RFC 4880]
+ *
+ * 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 pr_fmt(fmt) "PGPSIG: "fmt
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pgplib.h>
+#include <linux/err.h>
+#include "public_key.h"
+#include "pgp_parser.h"
+
+static const struct {
+	enum pkey_hash_algo algo : 8;
+} pgp_pubkey_hash[PGP_HASH__LAST] = {
+	[PGP_HASH_MD5].algo		= PKEY_HASH_MD5,
+	[PGP_HASH_SHA1].algo		= PKEY_HASH_SHA1,
+	[PGP_HASH_RIPE_MD_160].algo	= PKEY_HASH_RIPE_MD_160,
+	[PGP_HASH_SHA256].algo		= PKEY_HASH_SHA256,
+	[PGP_HASH_SHA384].algo		= PKEY_HASH_SHA384,
+	[PGP_HASH_SHA512].algo		= PKEY_HASH_SHA512,
+	[PGP_HASH_SHA224].algo		= PKEY_HASH_SHA224,
+};
+
+static int pgp_pkey_verify_sig_add_data(struct crypto_sig_verify_context *ctx,
+					const void *data, size_t datalen);
+static int pgp_pkey_verify_sig_end(struct crypto_sig_verify_context *ctx,
+				   const u8 *sig, size_t siglen);
+static void pgp_pkey_verify_sig_cancel(struct crypto_sig_verify_context *ctx);
+
+struct pgp_pkey_sig_parse_context {
+	struct pgp_parse_context pgp;
+	struct pgp_sig_parameters params;
+};
+
+static int pgp_pkey_parse_signature(struct pgp_parse_context *context,
+				    enum pgp_packet_tag type,
+				    u8 headerlen,
+				    const u8 *data,
+				    size_t datalen)
+{
+	struct pgp_pkey_sig_parse_context *ctx =
+		container_of(context, struct pgp_pkey_sig_parse_context, pgp);
+
+	return pgp_parse_sig_params(&data, &datalen, &ctx->params);
+}
+
+/*
+ * Begin the process of verifying a DSA signature.
+ *
+ * This involves allocating the hash into which first the data and then the
+ * metadata will be put, and parsing the signature to check that it matches the
+ * key.
+ */
+struct crypto_sig_verify_context *pgp_pkey_verify_sig_begin(
+	struct key *crypto_key, const u8 *sigdata, size_t siglen)
+{
+	struct pgp_pkey_sig_parse_context p;
+	struct public_key_signature *sig;
+	struct crypto_shash *tfm;
+	const struct public_key *key = crypto_key->payload.data;
+	size_t digest_size, desc_size;
+	int ret;
+
+	kenter("{%d},,%zu", key_serial(crypto_key), siglen);
+
+	if (!key) {
+		kleave(" = -ENOKEY [no public key]");
+		return ERR_PTR(-ENOKEY);
+	}
+
+	p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE);
+	p.pgp.process_packet = pgp_pkey_parse_signature;
+	ret = pgp_parse_packets(sigdata, siglen, &p.pgp);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	if (p.params.pubkey_algo >= PGP_PUBKEY__LAST ||
+	    !pgp_public_key_algorithms[p.params.pubkey_algo]) {
+		pr_debug("Unsupported public key algorithm %u\n",
+			 p.params.pubkey_algo);
+		return ERR_PTR(-ENOPKG);
+	}
+
+	if (pgp_public_key_algorithms[p.params.pubkey_algo] != key->algo) {
+		kleave(" = -EKEYREJECTED [wrong pk algo]");
+		return ERR_PTR(-EKEYREJECTED);
+	}
+
+	if (!(key->capabilities & PKEY_CAN_VERIFY)) {
+		kleave(" = -EKEYREJECTED [key can't verify]");
+		return ERR_PTR(-EKEYREJECTED);
+	}
+
+	if (p.params.hash_algo >= PGP_HASH__LAST ||
+	    !pgp_hash_algorithms[p.params.hash_algo]) {
+		pr_debug("Unsupported hash algorithm %u\n",
+			 p.params.hash_algo);
+		return ERR_PTR(-ENOPKG);
+	}
+
+	pr_debug("Signature generated with %s hash\n",
+		 pgp_hash_algorithms[p.params.hash_algo]);
+
+	if (memcmp(&p.params.issuer, key->key_id, 8) != 0) {
+		kleave(" = -ENOKEY [wrong key ID]");
+		return ERR_PTR(-ENOKEY);
+	}
+
+	if (p.params.signature_type != PGP_SIG_BINARY_DOCUMENT_SIG &&
+	    p.params.signature_type != PGP_SIG_STANDALONE_SIG) {
+		/* We don't want to canonicalise */
+		kleave(" = -EOPNOTSUPP [canon]");
+		return ERR_PTR(-EOPNOTSUPP);
+	}
+
+	/* Allocate the hashing algorithm we're going to need and find out how
+	 * big the hash operational data will be.
+	 */
+	tfm = crypto_alloc_shash(pgp_hash_algorithms[p.params.hash_algo], 0, 0);
+	if (IS_ERR(tfm))
+		return PTR_ERR(tfm) == -ENOENT ?
+			ERR_PTR(-ENOPKG) : ERR_CAST(tfm);
+
+	desc_size = crypto_shash_descsize(tfm);
+	digest_size = crypto_shash_digestsize(tfm);
+
+	/* We allocate the hash operational data storage on the end of our
+	 * context data.
+	 */
+	sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL);
+	if (!sig) {
+		crypto_free_shash(tfm);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	sig->base.key		= crypto_key;
+	sig->base.add_data	= pgp_pkey_verify_sig_add_data;
+	sig->base.end		= pgp_pkey_verify_sig_end;
+	sig->base.cancel	= pgp_pkey_verify_sig_cancel;
+	sig->pkey_hash_algo	= pgp_pubkey_hash[p.params.hash_algo].algo;
+	sig->digest		= (u8 *)sig + sizeof(*sig) + desc_size;
+	sig->digest_size	= digest_size;
+	sig->hash.tfm		= tfm;
+	sig->hash.flags		= CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	ret = crypto_shash_init(&sig->hash);
+	if (ret < 0) {
+		crypto_free_shash(sig->hash.tfm);
+		kfree(sig);
+		return ERR_PTR(ret);
+	}
+
+	key_get(sig->base.key);
+	kleave(" = %p", sig);
+	return &sig->base;
+}
+
+/*
+ * Load data into the hash
+ */
+static int pgp_pkey_verify_sig_add_data(struct crypto_sig_verify_context *ctx,
+					const void *data, size_t datalen)
+{
+	struct public_key_signature *sig =
+		container_of(ctx, struct public_key_signature, base);
+
+	return crypto_shash_update(&sig->hash, data, datalen);
+}
+
+struct pgp_pkey_sig_digest_context {
+	struct pgp_parse_context pgp;
+	const struct public_key *key;
+	struct public_key_signature *sig;
+};
+
+/*
+ * Extract required metadata from the signature packet and add what we need to
+ * to the hash.
+ */
+static int pgp_pkey_digest_signature(struct pgp_parse_context *context,
+				     enum pgp_packet_tag type,
+				     u8 headerlen,
+				     const u8 *data,
+				     size_t datalen)
+{
+	struct pgp_pkey_sig_digest_context *ctx =
+		container_of(context, struct pgp_pkey_sig_digest_context, pgp);
+	enum pgp_signature_version version;
+	int i;
+
+	kenter(",%u,%u,,%zu", type, headerlen, datalen);
+
+	version = *data;
+	if (version == PGP_SIG_VERSION_3) {
+		/* We just include an excerpt of the metadata from a V3
+		 * signature.
+		 */
+		crypto_shash_update(&ctx->sig->hash, data + 1, 5);
+		data += sizeof(struct pgp_signature_v3_packet);
+		datalen -= sizeof(struct pgp_signature_v3_packet);
+	} else if (version == PGP_SIG_VERSION_4) {
+		/* We add the whole metadata header and some of the hashed data
+		 * for a V4 signature, plus a trailer.
+		 */
+		size_t hashedsz, unhashedsz;
+		u8 trailer[6];
+
+		hashedsz = 4 + 2 + (data[4] << 8) + data[5];
+		crypto_shash_update(&ctx->sig->hash, data, hashedsz);
+
+		trailer[0] = version;
+		trailer[1] = 0xffU;
+		trailer[2] = hashedsz >> 24;
+		trailer[3] = hashedsz >> 16;
+		trailer[4] = hashedsz >> 8;
+		trailer[5] = hashedsz;
+
+		crypto_shash_update(&ctx->sig->hash, trailer, 6);
+		data += hashedsz;
+		datalen -= hashedsz;
+
+		unhashedsz = 2 + (data[0] << 8) + data[1];
+		data += unhashedsz;
+		datalen -= unhashedsz;
+	}
+
+	if (datalen <= 2) {
+		kleave(" = -EBADMSG");
+		return -EBADMSG;
+	}
+
+	/* There's a quick check on the hash available. */
+	ctx->sig->signed_hash_msw[0] = *data++;
+	ctx->sig->signed_hash_msw[1] = *data++;
+	datalen -= 2;
+
+	/* And then the cryptographic data, which we'll need for the
+	 * algorithm.
+	 */
+	for (i = 0; i < ctx->key->algo->n_sig_mpi; i++) {
+		unsigned int remaining = datalen;
+		if (remaining == 0) {
+			pr_debug("short %zu mpi %d\n", datalen, i);
+			return -EBADMSG;
+		}
+		ctx->sig->mpi[i] = mpi_read_from_buffer(data, &remaining);
+		if (!ctx->sig->mpi[i])
+			return -ENOMEM;
+		data += remaining;
+		datalen -= remaining;
+	}
+
+	if (datalen != 0) {
+		kleave(" = -EBADMSG [trailer %zu]", datalen);
+		return -EBADMSG;
+	}
+
+	kleave(" = 0");
+	return 0;
+}
+
+/*
+ * The data is now all loaded into the hash; load the metadata, finalise the
+ * hash and perform the verification step.
+ */
+static int pgp_pkey_verify_sig_end(struct crypto_sig_verify_context *ctx,
+				   const u8 *sigdata, size_t siglen)
+{
+	struct public_key_signature *sig =
+		container_of(ctx, struct public_key_signature, base);
+	const struct public_key *key = sig->base.key->payload.data;
+	struct pgp_pkey_sig_digest_context p;
+	int ret;
+
+	kenter("");
+
+	/* Firstly we add metadata, starting with some of the data from the
+	 * signature packet */
+	p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE);
+	p.pgp.process_packet = pgp_pkey_digest_signature;
+	p.key = key;
+	p.sig = sig;
+	ret = pgp_parse_packets(sigdata, siglen, &p.pgp);
+	if (ret < 0)
+		goto error_free_ctx;
+
+	crypto_shash_final(&sig->hash, sig->digest);
+
+	ret = key->algo->verify(key, sig);
+
+error_free_ctx:
+	pgp_pkey_verify_sig_cancel(ctx);
+	kleave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * Cancel an in-progress data loading
+ */
+static void pgp_pkey_verify_sig_cancel(struct crypto_sig_verify_context *ctx)
+{
+	struct public_key_signature *sig =
+		container_of(ctx, struct public_key_signature, base);
+	int i;
+
+	kenter("");
+
+	/* !!! Do we need to tell the crypto layer to cancel too? */
+	crypto_free_shash(sig->hash.tfm);
+	key_put(sig->base.key);
+	for (i = 0; i < ARRAY_SIZE(sig->mpi); i++)
+		mpi_free(sig->mpi[i]);
+	kfree(sig);
+
+	kleave("");
+}


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 14/25] KEYS: PGP format signature parser
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (12 preceding siblings ...)
  2012-08-16  1:36 ` [PATCH 13/25] KEYS: PGP-based public key signature verification David Howells
@ 2012-08-16  1:36 ` David Howells
  2012-08-16  1:36 ` [PATCH 15/25] KEYS: Provide PGP key description autogeneration David Howells
                   ` (13 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:36 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Implement a signature parser that will attempt to parse a signature blob as a
PGP packet format message.  If it can, it will find an appropriate crypto key
and set the public-key algorithm according to the data in the signature.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 security/keys/crypto/Makefile         |    1 
 security/keys/crypto/pgp_sig_parser.c |  136 +++++++++++++++++++++++++++++++++
 2 files changed, 137 insertions(+)
 create mode 100644 security/keys/crypto/pgp_sig_parser.c


diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile
index 0c8b8a1..a9a34c6 100644
--- a/security/keys/crypto/Makefile
+++ b/security/keys/crypto/Makefile
@@ -12,4 +12,5 @@ obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o
 obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_key_parser.o
 pgp_key_parser-y := \
 	pgp_public_key.o \
+	pgp_sig_parser.o \
 	pgp_sig_verify.o
diff --git a/security/keys/crypto/pgp_sig_parser.c b/security/keys/crypto/pgp_sig_parser.c
new file mode 100644
index 0000000..683eb53
--- /dev/null
+++ b/security/keys/crypto/pgp_sig_parser.c
@@ -0,0 +1,136 @@
+/* Handling for PGP public key signature data [RFC 4880]
+ *
+ * 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 pr_fmt(fmt) "PGPSIG: "fmt
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pgplib.h>
+#include <linux/err.h>
+#include "public_key.h"
+#include "pgp_parser.h"
+
+struct PGP_sig_parse_context {
+	struct pgp_parse_context pgp;
+	struct pgp_sig_parameters params;
+	bool found_sig;
+};
+
+/*
+ * Look inside signature sections for a key ID
+ */
+static int pgp_process_signature(struct pgp_parse_context *context,
+				 enum pgp_packet_tag type,
+				 u8 headerlen,
+				 const u8 *data,
+				 size_t datalen)
+{
+	struct PGP_sig_parse_context *ctx =
+		container_of(context, struct PGP_sig_parse_context, pgp);
+
+	ctx->found_sig = true;
+	return pgp_parse_sig_params(&data, &datalen, &ctx->params);
+}
+
+/*
+ * Attempt to find a key to use for PGP signature verification, starting off by
+ * looking in the supplied keyring.
+ *
+ * The function may also look for other key sources such as a TPM.  If an
+ * alternative key is found it can be added to the keyring for future
+ * reference.
+ */
+static struct key *find_key_for_pgp_sig(struct key *keyring,
+					const u8 *sig, size_t siglen)
+{
+	struct PGP_sig_parse_context p;
+	key_ref_t key;
+	char criterion[3 + 8 * 2 + 1];
+	int ret;
+
+	if (!keyring)
+		return ERR_PTR(-ENOKEY);
+
+	/* Need to find the key ID */
+	p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE);
+	p.pgp.process_packet = pgp_process_signature;
+	p.found_sig = false;
+	ret = pgp_parse_packets(sig, siglen, &p.pgp);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	if (!p.found_sig)
+		return ERR_PTR(-ENOMSG);
+
+	sprintf(criterion, "id:%08x%08x",
+		be32_to_cpu(p.params.issuer32[0]),
+		be32_to_cpu(p.params.issuer32[1]));
+
+	pr_debug("Look up: %s\n", criterion);
+
+	key = keyring_search(make_key_ref(keyring, 1),
+			     &key_type_crypto, criterion);
+	if (IS_ERR(key)) {
+		switch (PTR_ERR(key)) {
+			/* Hide some search errors */
+		case -EACCES:
+		case -ENOTDIR:
+		case -EAGAIN:
+			return ERR_PTR(-ENOKEY);
+		default:
+			return ERR_CAST(key);
+		}
+	}
+
+	pr_debug("Found key %x\n", key_serial(key_ref_to_ptr(key)));
+	return key_ref_to_ptr(key);
+}
+
+/*
+ * Attempt to parse a signature as a PGP packet format blob and find a
+ * matching key.
+ */
+static struct crypto_sig_verify_context *pgp_verify_sig_begin(
+	struct key *keyring, const u8 *sig, size_t siglen)
+{
+	struct crypto_sig_verify_context *ctx;
+	struct key *key;
+
+	key = find_key_for_pgp_sig(keyring, sig, siglen);
+	if (IS_ERR(key))
+		return ERR_CAST(key);
+
+	/* We only handle in-kernel public key signatures for the moment */
+	ctx = pgp_pkey_verify_sig_begin(key, sig, siglen);
+	key_put(key);
+	return ctx;
+}
+
+static struct crypto_sig_parser pgp_sig_parser = {
+	.owner		= THIS_MODULE,
+	.name		= "pgp",
+	.verify_sig_begin = pgp_verify_sig_begin,
+};
+
+/*
+ * Module stuff
+ */
+static int __init pgp_sig_init(void)
+{
+	return register_crypto_sig_parser(&pgp_sig_parser);
+}
+
+static void __exit pgp_sig_exit(void)
+{
+	unregister_crypto_sig_parser(&pgp_sig_parser);
+}
+
+module_init(pgp_sig_init);
+module_exit(pgp_sig_exit);


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 15/25] KEYS: Provide PGP key description autogeneration
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (13 preceding siblings ...)
  2012-08-16  1:36 ` [PATCH 14/25] KEYS: PGP format signature parser David Howells
@ 2012-08-16  1:36 ` David Howells
  2012-08-16  1:37 ` [PATCH 16/25] KEYS: Provide a function to load keys from a PGP keyring blob David Howells
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:36 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Provide a facility to autogenerate the name of PGP keys from the contents of
the payload.  If add_key() is given a blank description, a description is
constructed from the last user ID packet in the payload data plus the last 8
hex digits of the key ID.  For instance:

	keyctl padd crypto "" @s </tmp/key.pub

might create a key with a constructed description that can be seen in
/proc/keys:

2f674b96 I--Q---     1 perm 39390000     0     0 crypto    Sample kernel key 31f0ae93: PGP.RSA 31f0ae93 []

Signed-off-by: David Howells <dhowells@redhat.com>
---

 security/keys/crypto/pgp_public_key.c |   64 +++++++++++++++++++++++++++------
 1 file changed, 53 insertions(+), 11 deletions(-)


diff --git a/security/keys/crypto/pgp_public_key.c b/security/keys/crypto/pgp_public_key.c
index c260e02..2347ecd 100644
--- a/security/keys/crypto/pgp_public_key.c
+++ b/security/keys/crypto/pgp_public_key.c
@@ -52,6 +52,9 @@ struct pgp_key_data_parse_context {
 	struct crypto_key_subtype *subtype;
 	char *fingerprint;
 	void *payload;
+	const char *user_id;
+	size_t user_id_len;
+	size_t fingerprint_len;
 };
 
 /*
@@ -166,6 +169,7 @@ static int pgp_generate_fingerprint(struct pgp_key_data_parse_context *ctx,
 	if (ret < 0)
 		goto cleanup_raw_fingerprint;
 
+	ctx->fingerprint_len = digest_size * 2;
 	fingerprint = kmalloc(digest_size * 2 + 1, GFP_KERNEL);
 	if (!fingerprint)
 		goto cleanup_raw_fingerprint;
@@ -212,6 +216,13 @@ static int pgp_process_public_key(struct pgp_parse_context *context,
 
 	kenter(",%u,%u,,%zu", type, headerlen, datalen);
 
+	if (type == PGP_PKT_USER_ID) {
+		ctx->user_id = data;
+		ctx->user_id_len = datalen;
+		kleave(" = 0 [user ID]");
+		return 0;
+	}
+
 	if (ctx->subtype) {
 		kleave(" = -ENOKEY [already]");
 		return -EBADMSG;
@@ -297,21 +308,44 @@ static int pgp_key_preparse(struct key_preparsed_payload *prep)
 
 	kenter("");
 
+	memset(&ctx, 0, sizeof(ctx));
 	ctx.pgp.types_of_interest =
-		(1 << PGP_PKT_PUBLIC_KEY) | (1 << PGP_PKT_PUBLIC_SUBKEY);
+		(1 << PGP_PKT_PUBLIC_KEY) | (1 << PGP_PKT_PUBLIC_SUBKEY) |
+		(1 << PGP_PKT_USER_ID);
 	ctx.pgp.process_packet = pgp_process_public_key;
-	ctx.subtype = NULL;
-	ctx.fingerprint = NULL;
-	ctx.payload = NULL;
 
 	ret = pgp_parse_packets(prep->data, prep->datalen, &ctx.pgp);
-	if (ret < 0) {
-		if (ctx.payload)
-			ctx.subtype->destroy(ctx.payload);
-		if (ctx.subtype)
-			module_put(ctx.subtype->owner);
-		kfree(ctx.fingerprint);
-		return ret;
+	if (ret < 0)
+		goto error;
+
+	if (ctx.user_id && ctx.user_id_len > 0) {
+		/* Propose a description for the key (user ID without the comment) */
+		size_t ulen = ctx.user_id_len, flen = ctx.fingerprint_len;
+		const char *p;
+
+		p = memchr(ctx.user_id, '(', ulen);
+		if (p) {
+			/* Remove the comment */
+			do {
+				p--;
+			} while (*p == ' ' && p > ctx.user_id);
+			if (*p != ' ')
+				p++;
+			ulen = p - ctx.user_id;
+		}
+
+		if (ulen > 255 - 9)
+			ulen = 255 - 9;
+		prep->description = kmalloc(ulen + 1 + 8 + 1, GFP_KERNEL);
+		ret = -ENOMEM;
+		if (!prep->description)
+			goto error;
+		memcpy(prep->description, ctx.user_id, ulen);
+		prep->description[ulen] = ' ';
+		memcpy(prep->description + ulen + 1,
+		       ctx.fingerprint + flen - 8, 8);
+		prep->description[ulen + 9] = 0;
+		pr_debug("desc '%s'\n", prep->description);
 	}
 
 	prep->type_data[0] = ctx.subtype;
@@ -319,6 +353,14 @@ static int pgp_key_preparse(struct key_preparsed_payload *prep)
 	prep->payload = ctx.payload;
 	prep->quotalen = prep->datalen;
 	return 0;
+
+error:
+	if (ctx.payload)
+		ctx.subtype->destroy(ctx.payload);
+	if (ctx.subtype)
+		module_put(ctx.subtype->owner);
+	kfree(ctx.fingerprint);
+	return ret;
 }
 
 static struct crypto_key_parser pgp_key_parser = {


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 16/25] KEYS: Provide a function to load keys from a PGP keyring blob
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (14 preceding siblings ...)
  2012-08-16  1:36 ` [PATCH 15/25] KEYS: Provide PGP key description autogeneration David Howells
@ 2012-08-16  1:37 ` David Howells
  2012-08-16  1:37 ` [PATCH 17/25] MODSIGN: Provide gitignore and make clean rules for extra files David Howells
                   ` (11 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:37 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Provide a function to load keys from a PGP keyring blob for use in initialising
the module signing key keyring:

	int load_PGP_keys(const u8 *pgpdata, size_t pgpdatalen,
			  struct key *keyring, const char *descprefix);

The keys are labelled with descprefix plus a number to uniquify them.  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:

24460d1c I-----     1 perm 3f010000     0     0 crypto    modsign.0: dsa 5acc2142 []
3ca85723 I-----     1 perm 1f010000     0     0 keyring   .module_sign: 1/4

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>
---

 Documentation/security/keys-crypto.txt |   20 ++++++
 include/keys/crypto-type.h             |    3 +
 security/keys/crypto/Kconfig           |    9 +++
 security/keys/crypto/Makefile          |    1 
 security/keys/crypto/pgp_preload.c     |  115 ++++++++++++++++++++++++++++++++
 5 files changed, 148 insertions(+)
 create mode 100644 security/keys/crypto/pgp_preload.c


diff --git a/Documentation/security/keys-crypto.txt b/Documentation/security/keys-crypto.txt
index 0a886ec..be5067e 100644
--- a/Documentation/security/keys-crypto.txt
+++ b/Documentation/security/keys-crypto.txt
@@ -10,6 +10,7 @@ Contents:
     - Signature verification.
   - Implementing crypto parsers.
   - Implementing crypto subtypes.
+  - Initial PGP key preloading.
 
 
 ========
@@ -279,3 +280,22 @@ There are a number of operations defined by the subtype:
      Mandatory.  This should free the memory associated with the key.  The
      crypto key will look after freeing the fingerprint and releasing the
      reference on the subtype module.
+
+
+=======================
+INITIAL PGP KEY LOADING
+=======================
+
+A function is provided to perform an initial load of a set of public keys bound
+into a PGP packet format blob:
+
+	int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen,
+			     struct key *keyring);
+
+This takes the blob of data defined by pgpdata and pgpdatalen, extracts keys
+from them and adds them to the specified keyring.  The keys are labelled with a
+description generated from the fingerprint and last user ID of each key.  The
+description is required to prevent all but the last key being discarded when
+the keys are linked into the keyring.
+
+This function is only available during initial kernel set up.
diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h
index 0fb362a..ed9b203 100644
--- a/include/keys/crypto-type.h
+++ b/include/keys/crypto-type.h
@@ -31,4 +31,7 @@ extern void verify_sig_cancel(struct crypto_sig_verify_context *ctx);
  * The payload is at the discretion of the subtype.
  */
 
+extern __init int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen,
+				   struct key *keyring);
+
 #endif /* _KEYS_CRYPTO_TYPE_H */
diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig
index 1c2ae55..8af0155 100644
--- a/security/keys/crypto/Kconfig
+++ b/security/keys/crypto/Kconfig
@@ -40,3 +40,12 @@ config CRYPTO_KEY_PGP_PARSER
 	  This option provides support for parsing PGP (RFC 4880) format blobs
 	  for key data and provides the ability to instantiate a crypto key
 	  from a public key packet found inside the blob.
+
+config PGP_PRELOAD
+	bool "PGP public key preloading facility"
+	select PGP_LIBRARY
+	select CRYPTO_KEY_PGP_PARSER
+	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.
diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile
index a9a34c6..c873674 100644
--- a/security/keys/crypto/Makefile
+++ b/security/keys/crypto/Makefile
@@ -8,6 +8,7 @@ crypto_keys-y := crypto_type.o crypto_verify.o
 obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o
 obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o
 obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o
+obj-$(CONFIG_PGP_PRELOAD) += pgp_preload.o
 
 obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_key_parser.o
 pgp_key_parser-y := \
diff --git a/security/keys/crypto/pgp_preload.c b/security/keys/crypto/pgp_preload.c
new file mode 100644
index 0000000..ca4cfe6
--- /dev/null
+++ b/security/keys/crypto/pgp_preload.c
@@ -0,0 +1,115 @@
+/* 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/pgplib.h>
+#include <linux/err.h>
+#include <keys/crypto-type.h>
+#include "crypto_keys.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, "crypto", NULL,
+				   ctx->key_start,
+				   ctx->key_end - ctx->key_start,
+				   KEY_POS_ALL | KEY_USR_VIEW,
+				   KEY_ALLOC_NOT_IN_QUOTA);
+	if (IS_ERR(key))
+		return PTR_ERR(key);
+
+	pr_notice("Loaded %s key: %s\n",
+		  key_ref_to_ptr(key)->description,
+		  crypto_key_id(key_ref_to_ptr(key)));
+
+	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;
+}


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 17/25] MODSIGN: Provide gitignore and make clean rules for extra files
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (15 preceding siblings ...)
  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 ` David Howells
  2012-08-16  1:37 ` [PATCH 18/25] MODSIGN: Provide Documentation and Kconfig options David Howells
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:37 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Provide gitignore and make clean rules for extra files to hide and clean up the
extra files produced by module signing stuff once it is added.  Also add a
clean up rule for the module content extractor program used to extract the data
to be signed.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 .gitignore |   13 +++++++++++++
 Makefile   |    1 +
 2 files changed, 14 insertions(+)


diff --git a/.gitignore b/.gitignore
index 57af07c..4d63081 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,10 @@
 *.o.*
 *.a
 *.s
+*.ko.unsigned
+*.ko.stripped
+*.ko.stripped.sig
+*.ko.trailer
 *.ko
 *.so
 *.so.dbg
@@ -84,3 +88,12 @@ GTAGS
 *.orig
 *~
 \#*#
+
+#
+# GPG leavings from module signing
+#
+genkey
+modsign.pub
+modsign.sec
+random_seed
+trustdb.gpg
diff --git a/Makefile b/Makefile
index ddf5be9..70a6b5b 100644
--- a/Makefile
+++ b/Makefile
@@ -1239,6 +1239,7 @@ clean: $(clean-dirs)
 	$(call cmd,rmfiles)
 	@find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
 		\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
+		-o -name '*.ko.*' \
 		-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
 		-o -name '*.symtypes' -o -name 'modules.order' \
 		-o -name modules.builtin -o -name '.tmp_*.o.*' \


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 18/25] MODSIGN: Provide Documentation and Kconfig options
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (16 preceding siblings ...)
  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 ` David Howells
  2012-08-16  1:37 ` [PATCH 19/25] MODSIGN: Sign modules during the build process David Howells
                   ` (9 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:37 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Provide documentation and kernel configuration options for module signing.

The documentation can be found in:

	Documentation/module-signing.txt

The following configuration options are added:

 (1) CONFIG_MODULE_SIG

     Enable module signing.  This will both cause the build process to sign
     modules and the kernel to check modules when they're loaded.

 (2) CONFIG_MODULE_SIG_SHA1
     CONFIG_MODULE_SIG_SHA224
     CONFIG_MODULE_SIG_SHA256
     CONFIG_MODULE_SIG_SHA384
     CONFIG_MODULE_SIG_SHA512

     Select the cryptographic hash used to digest the data prior to signing.
     Additionally, the crypto module selected will be built into the kernel as
     it won't be possible to load it as a module without incurring a circular
     dependency when the kernel tries to check its signature.

 (3) CONFIG_MODULE_SIG_FORCE

     Require that any module loaded must be signed with a key compiled into
     the kernel.  All other modules are rejected with EKEYREJECTED.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 Documentation/module-signing.txt |  183 ++++++++++++++++++++++++++++++++++++++
 include/linux/modsign.h          |   27 ++++++
 init/Kconfig                     |   62 +++++++++++++
 3 files changed, 272 insertions(+)
 create mode 100644 Documentation/module-signing.txt
 create mode 100644 include/linux/modsign.h


diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt
new file mode 100644
index 0000000..b355aa2
--- /dev/null
+++ b/Documentation/module-signing.txt
@@ -0,0 +1,183 @@
+			==============================
+			KERNEL MODULE SIGNING FACILITY
+			==============================
+
+The module signing facility applies cryptographic signature checking to modules
+on module load, checking the signature against a ring of public keys compiled
+into the kernel.  GPG is used to do the cryptographic work and determines the
+format of the signature and key data.  The facility uses GPG's MPI library to
+handle the huge numbers involved.
+
+The signature checker in the kernel is capable of handling multiple keys of
+either DSA or RSA type, and can support any of MD5, RIPE-MD-160, SHA-1,
+SHA-224, SHA-256, SHA-384 and SHA-512 hashes - PROVIDED(!) the requisite
+algorithms are compiled into the kernel.
+
+(!) NOTE: Modules may only be verified initially with algorithms compiled into
+the kernel.  Further algorithm modules may be loaded and used - but these must
+first pass a verification step using already loaded/compiled-in algorithms.
+
+
+=====================
+SUPPLYING PUBLIC KEYS
+=====================
+
+A set of public keys must be supplied at kernel image build time.  This is done
+by taking a GPG public key file and placing it in the base of the kernel
+directory in a file called modsign.pub.
+
+For example, a throwaway key could be generated automatically by something like
+the following:
+
+	cat >genkey <<EOF
+	%pubring modsign.pub
+	%secring modsign.sec
+	Key-Type: RSA
+	Key-Length: 4096
+	Name-Real: A. N. Other
+	Name-Comment: Kernel Module GPG key
+	%commit
+	EOF
+	gpg --homedir . --batch --gen-key genkey
+
+The above generates fresh keys using /dev/random.  If there's insufficient data
+in /dev/random, more can be provided using the rngd program if there's a
+hardware random number generator available.
+
+Note that no GPG password is used in the above scriptlet.
+
+The modsign.pub file is compiled into the kernel directly by the assembler by
+means of an ".incbin" directive in kernel/modsign-pubkey.c.
+
+Once the kernel is running, the keys are visible to root as kernel crypto keys
+in /proc/keys in a keyring called .module_sign:
+
+335ab517 I-----     1 perm 1f030000     0     0 keyring   .module_sign: 2/4
+38d7d169 I-----     1 perm 3f010000     0     0 crypto    modsign.0: rsa 57532ca5 []
+195fa736 I-----     1 perm 3f010000     0     0 crypto    modsign.1: dsa 5acc2142 []
+
+This keyring can be listed with the keyctl program.  See:
+
+	Documentation/security/keys-crypto.txt
+
+for more information of crypto keys.
+
+
+============================
+SELECTING THE HASH ALGORITHM
+============================
+
+The hash algorithm to be used is selected by a multiple choice configuration
+item that enables one of the following variables:
+
+	CONFIG_SIG_SHA1
+	CONFIG_SIG_SHA224
+	CONFIG_SIG_SHA256
+	CONFIG_SIG_SHA384
+	CONFIG_SIG_SHA512
+
+These cause an appropriate "--digest-algo=" parameter to be passed to gpg when
+signing a module and force the appropriate hash algorithm to be compiled
+directly into the kernel rather than being built as a module.
+
+
+==============
+MODULE SIGNING
+==============
+
+Modules will then be signed automatically.  The kernel make command line can
+include the following options:
+
+ (*) MODSECKEY=<secret-key-ring-path>
+
+     This indicates the whereabouts of the GPG keyring that is the source of
+     the secret key to be used.  The default is "./modsign.sec".
+
+ (*) MODPUBKEY=<public-key-ring-path>
+
+     This indicates the whereabouts of the GPG keyring that is the source of
+     the public key to be used.  The default is "./modsign.pub".
+
+ (*) MODKEYNAME=<key-name>
+
+     The name of the key pair to be used from the aforementioned keyrings.
+     This defaults to being unset, thus leaving the choice of default key to
+     gpg.
+
+ (*) KEYFLAGS="gpg-options"
+
+     Override the complete gpg command line, including the preceding three
+     options.  The default options supplied to gpg are:
+
+	--no-default-keyring
+	--secret-keyring $(MODSECKEY)
+	--keyring $(MODPUBKEY)
+	--no-default-keyring
+	--homedir .
+	--no-options
+	--no-auto-check-trustdb
+	--no-permission-warning
+	--digest-algo=<hash-algorithm>
+
+      with:
+
+	--default-key $(MODKEYNAME)
+
+      being added if requested.
+
+The resulting module.ko file will be the signed module.
+
+
+============================
+SIGNED MODULES AND STRIPPING
+============================
+
+The module signature is just appended to the module binary with a magic number
+at the end of file, a couple of fixed-size lengths prior to that and the
+signature prior to that.
+
+WARNING! Signed modules are BRITTLE as the signature is outside of the defined
+ELF container.  Thus they MAY NOT be stripped once the signature is computed
+and attached, lest the signature be discarded or the payload be modified.  Note
+that the entire module is the signed payload, including all the debug
+information present at the time of signing so it must still be present when the
+signature is checked.
+
+As the module may need to be included in a ramdisk image of limited capacity,
+modules are maximally stripped prior to signing by the build process.
+
+Note that if FIPS mode is engaged, a module for which the signature does not
+match the payload will panic the box.
+
+
+======================
+LOADING SIGNED MODULES
+======================
+
+Modules are loaded with insmod, exactly as for unsigned modules.  The signature
+checker will check at the end of the file for the signature marker and apply
+signature checking if found.
+
+
+=========================================
+NON-VALID SIGNATURES AND UNSIGNED MODULES
+=========================================
+
+If CONFIG_MODULE_SIG_FORCE is enabled or "enforcemodulesig=1" is supplied on
+the kernel command line, the kernel will _only_ load validly signed modules
+for which it has a public key.  Otherwise, it will also load modules that are
+unsigned.  Any module for which the kernel has a key, but which proves to have
+a signature mismatch will not be permitted to load (returning EKEYREJECTED).
+
+This table indicates the behaviours of the various situations:
+
+	MODULE STATE				PERMISSIVE MODE	ENFORCING MODE
+	=======================================	===============	===============
+	Unsigned				Ok		EKEYREJECTED
+	Signed, no public key			ENOKEY		ENOKEY
+	Validly signed, public key		Ok		Ok
+	Invalidly signed, public key		EKEYREJECTED	EKEYREJECTED
+	Validly signed, expired key		EKEYEXPIRED	EKEYEXPIRED
+	Signed, hash algorithm unavailable	ENOPKG		ENOPKG
+	Corrupt signature			EBADMSG		EBADMSG
+
diff --git a/include/linux/modsign.h b/include/linux/modsign.h
new file mode 100644
index 0000000..c5ac87a
--- /dev/null
+++ b/include/linux/modsign.h
@@ -0,0 +1,27 @@
+/* Module signing definitions
+ *
+ * Copyright (C) 2009 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.
+ */
+
+#ifndef _LINUX_MODSIGN_H
+#define _LINUX_MODSIGN_H
+
+#ifdef CONFIG_MODULE_SIG
+
+#include <linux/elfnote.h>
+
+/*
+ * The parameters of the ELF note used to carry the signature
+ */
+#define MODSIGN_NOTE_NAME	module.sig
+#define MODSIGN_NOTE_TYPE	100
+
+#endif
+
+#endif /* _LINUX_MODSIGN_H */
diff --git a/init/Kconfig b/init/Kconfig
index af6c7f8..c7a1cea 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1585,6 +1585,68 @@ config MODULE_SRCVERSION_ALL
 	  the version).  With this option, such a "srcversion" field
 	  will be created for all modules.  If unsure, say N.
 
+config MODULE_SIG
+	bool "Module signature verification"
+	depends on MODULES
+	select CRYPTO_KEY_TYPE
+	select CRYPTO_KEY_PKEY_ALGO_RSA
+	select PGP_PARSER
+	select PGP_PRELOAD
+	help
+	  Check modules for valid signatures upon load.  For more information
+	  see:
+
+	  Documentation/module-signing.txt
+
+	  !!!WARNING!!!  If you enable this option, you MUST make sure that the
+	  module DOES NOT get stripped after being signed.  This includes the
+	  debuginfo strip done by some packagers (such as rpmbuild) and
+	  inclusion into an initramfs that wants the module size reduced.
+
+	  The signed module is brittle, and any change is likely to result in
+	  the module load being rejected due to the signature being discarded
+	  or the signed payload being altered.  If FIPS mode is engaged, the
+	  kernel will panic if the signature is detected, but does not match.
+
+choice
+	prompt "Which hash algorithm should modules be signed with?"
+	depends on MODULE_SIG
+	help
+	  This determines which sort of hashing algorithm will be used during
+	  signature generation.  This algorithm _must_ be built into the kernel
+	  directly so that signature verification can take place.  It is not
+	  possible to load a signed module containing the algorithm to check
+	  the signature on that module.
+
+config MODULE_SIG_SHA1
+	bool "Sign modules with SHA-1"
+	select CRYPTO_SHA1
+
+config MODULE_SIG_SHA224
+	bool "Sign modules with SHA-224"
+	select CRYPTO_SHA224
+
+config MODULE_SIG_SHA256
+	bool "Sign modules with SHA-256"
+	select CRYPTO_SHA256
+
+config MODULE_SIG_SHA384
+	bool "Sign modules with SHA-384"
+	select CRYPTO_SHA384
+
+config MODULE_SIG_SHA512
+	bool "Sign modules with SHA-512"
+	select CRYPTO_SHA512
+
+endchoice
+
+config MODULE_SIG_FORCE
+	bool "Required modules to be validly signed (EXPERIMENTAL)"
+	depends on MODULE_SIG
+	help
+	  Reject unsigned modules or signed modules for which we don't have a
+	  key.
+
 endif # MODULES
 
 config INIT_ALL_POSSIBLE


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 19/25] MODSIGN: Sign modules during the build process
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (17 preceding siblings ...)
  2012-08-16  1:37 ` [PATCH 18/25] MODSIGN: Provide Documentation and Kconfig options David Howells
@ 2012-08-16  1:37 ` David Howells
  2012-08-16  1:37 ` [PATCH 20/25] MODSIGN: Provide module signing public keys to the kernel David Howells
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:37 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

If CONFIG_MODULE_SIG is set, then this patch will cause the module to get a
signature installed.  The following steps will occur:

 (1) The module will be linked to foo.ko.unsigned instead of foo.ko

 (2) The module will be stripped using both "strip -x -g" and "eu-strip" to
     ensure minimal size for inclusion in an initramfs.

 (3) The signature will be generated on the stripped module.

 (4) The signature will be appended to the module, along with the payload
     size, the signature size and a magic string.

Step (3) requires private and public keys to be available.  By default these
are expected to be found in PGP keyring files called modsign.sec (the secret
key) and modsign.pub (the public key) in the build root.

If the secret key is not found then signing will be skipped and the unsigned
module from (1) will just be copied to foo.ko.

If signing occurs, lines like the following will be seen:

	LD [M]  fs/foo/foo.ko.unsigned
	STRIP [M] fs/foo/foo.ko.stripped
	SIGN [M] fs/foo/foo.ko

will appear in the build log.  If the signature step will be skipped and the
following will be seen:

	LD [M]  fs/foo/foo.ko.unsigned
	STRIP [M] fs/foo/foo.ko.stripped
	NO SIGN [M] fs/foo/foo.ko

NOTE!  After the signature step, the signed module must not be passed through
strip.  The unstripped, unsigned module is still available at the name on the
LD [M] line.  This restriction may affect packaging tools (such as rpmbuild)
and initramfs composition tools.

Note that I do not agree with this method of attaching signatures to modules.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 scripts/Makefile.modpost |   99 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+), 1 deletion(-)


diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 08dce14..cd4d028 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -14,7 +14,8 @@
 # 3)  create one <module>.mod.c file pr. module
 # 4)  create one Module.symvers file with CRC for all exported symbols
 # 5) compile all <module>.mod.c files
-# 6) final link of the module to a <module.ko> file
+# 6) final link of the module to a <module.ko> (or <module.unsigned>) file
+# 7) signs the modules to a <module.ko> file
 
 # Step 3 is used to place certain information in the module's ELF
 # section, including information such as:
@@ -32,6 +33,8 @@
 # Step 4 is solely used to allow module versioning in external modules,
 # where the CRC of each module is retrieved from the Module.symvers file.
 
+# Step 7 is dependent on CONFIG_MODULE_SIG being enabled.
+
 # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined
 # symbols in the final module linking stage
 # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
@@ -116,6 +119,7 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE
 targets += $(modules:.ko=.mod.o)
 
 # Step 6), final link of the modules
+ifneq ($(CONFIG_MODULE_SIG),y)
 quiet_cmd_ld_ko_o = LD [M]  $@
       cmd_ld_ko_o = $(LD) -r $(LDFLAGS)                                 \
                              $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
@@ -125,7 +129,100 @@ $(modules): %.ko :%.o %.mod.o FORCE
 	$(call if_changed,ld_ko_o)
 
 targets += $(modules)
+else
+quiet_cmd_ld_ko_unsigned_o = LD [M]  $@
+      cmd_ld_ko_unsigned_o =						\
+		$(LD) -r $(LDFLAGS)					\
+			 $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE)	\
+			 -o $@ $(filter-out FORCE,$^)			\
+		$(if $(AFTER_LINK),; $(AFTER_LINK))
+
+$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE
+	$(call if_changed,ld_ko_unsigned_o)
+
+targets += $(modules:.ko=.ko.unsigned)
+
+# Step 7), sign the modules
+MODSECKEY = ./modsign.sec
+MODPUBKEY = ./modsign.pub
+KEYFLAGS = --no-default-keyring --secret-keyring $(MODSECKEY) --keyring $(MODPUBKEY) --no-default-keyring --homedir . --no-options --no-auto-check-trustdb --no-permission-warning
+
+ifdef CONFIG_MODULE_SIG_SHA1
+KEYFLAGS += --digest-algo=SHA1
+else
+ifdef CONFIG_MODULE_SIG_SHA224
+KEYFLAGS += --digest-algo=SHA224
+else
+ifdef CONFIG_MODULE_SIG_SHA256
+KEYFLAGS += --digest-algo=SHA256
+else
+ifdef CONFIG_MODULE_SIG_SHA384
+KEYFLAGS += --digest-algo=SHA384
+else
+ifdef CONFIG_MODULE_SIG_SHA512
+KEYFLAGS += --digest-algo=SHA512
+else
+endif
+endif
+endif
+endif
+endif
+
+ifdef MODKEYNAME
+KEYFLAGS += --default-key $(MODKEYNAME)
+endif
+
+ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY))
+ifeq ($(KBUILD_SRC),)
+	# no O= is being used
+	SCRIPTS_DIR := scripts
+else
+	SCRIPTS_DIR := $(KBUILD_SRC)/scripts
+endif
+SIGN_MODULES := 1
+else
+SIGN_MODULES := 0
+endif
+
+# only sign if it's an in-tree module
+ifneq ($(KBUILD_EXTMOD),)
+SIGN_MODULES := 0
+endif
+
+# We strip the module as best we can - note that using both strip and eu-strip
+# results in a smaller module than using either alone.
+quiet_cmd_sign_ko_stripped_ko_unsigned = STRIP [M] $@
+      cmd_sign_ko_stripped_ko_unsigned = \
+		cp $< $@ && \
+		strip -x -g $@ && \
+		eu-strip $@
+
+ifeq ($(SIGN_MODULES),1)
+KEYRING_DEP := modsign.sec modsign.pub
+quiet_cmd_sign_ko_ko_stripped = SIGN [M] $@
+      cmd_sign_ko_ko_stripped = \
+		rm -f $<.sig && \
+		gpg --batch --no-greeting $(KEYFLAGS) -b $< && \
+		( \
+			cat $< $<.sig && \
+			stat --printf %-5s $<.sig && \
+			echo -n "This Is A Crypto Signed Module" \
+		) >$@
+else
+KEYRING_DEP :=
+quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@
+      cmd_sign_ko_ko_unsigned = \
+		cp $< $@
+endif
+
+$(modules): %.ko :%.ko.stripped $(KEYRING_DEP) FORCE
+	$(call if_changed,sign_ko_ko_stripped)
+
+$(patsubst %.ko,%.ko.stripped,$(modules)): %.ko.stripped :%.ko.unsigned FORCE
+	$(call if_changed,sign_ko_stripped_ko_unsigned)
 
+targets += $(modules)
+endif
 
 # Add FORCE to the prequisites of a target to force it to be always rebuilt.
 # ---------------------------------------------------------------------------


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 20/25] MODSIGN: Provide module signing public keys to the kernel
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (18 preceding siblings ...)
  2012-08-16  1:37 ` [PATCH 19/25] MODSIGN: Sign modules during the build process David Howells
@ 2012-08-16  1:37 ` David Howells
  2012-08-31 14:33   ` Michal Marek
  2012-08-16  1:38 ` [PATCH 21/25] MODSIGN: Module signature verification David Howells
                   ` (7 subsequent siblings)
  27 siblings, 1 reply; 48+ messages in thread
From: David Howells @ 2012-08-16  1:37 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Include a PGP keyring containing the public keys required to perform module
verification in the kernel image during build and create a special keyring
during boot which is then populated with keys of crypto type holding the public
keys found in the PGP keyring.

These can be seen by root:

[root@andromeda ~]# cat /proc/keys
07ad4ee0 I-----     1 perm 3f010000     0     0 crypto    modsign.0: RSA 87b9b3bd []
15c7f8c3 I-----     1 perm 1f030000     0     0 keyring   .module_sign: 1/4
...

It is probably worth permitting root to invalidate these keys, resulting in
their removal and preventing further modules from being loaded with that key.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 kernel/Makefile         |    3 ++
 kernel/modsign-pubkey.c |   74 +++++++++++++++++++++++++++++++++++++++++++++++
 kernel/module-verify.h  |   14 +++++++++
 3 files changed, 91 insertions(+)
 create mode 100644 kernel/modsign-pubkey.c
 create mode 100644 kernel/module-verify.h


diff --git a/kernel/Makefile b/kernel/Makefile
index c0cc67a..84f6c04 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
 obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_MODULE_SIG) += modsign-pubkey.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
@@ -131,3 +132,5 @@ quiet_cmd_timeconst  = TIMEC   $@
 targets += timeconst.h
 $(obj)/timeconst.h: $(src)/timeconst.pl FORCE
 	$(call if_changed,timeconst)
+
+kernel/modsign-pubkey.o: modsign.pub
diff --git a/kernel/modsign-pubkey.c b/kernel/modsign-pubkey.c
new file mode 100644
index 0000000..ce14c9a
--- /dev/null
+++ b/kernel/modsign-pubkey.c
@@ -0,0 +1,74 @@
+/* Public keys for module signature verification
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+#include <keys/crypto-type.h>
+#include "module-verify.h"
+
+struct key *modsign_keyring;
+
+extern __initdata const u8 modsign_public_keys[];
+extern __initdata const u8 modsign_public_keys_end[];
+asm(".section .init.data,\"aw\"\n"
+    "modsign_public_keys:\n"
+    ".incbin \"modsign.pub\"\n"
+    "modsign_public_keys_end:"
+    );
+
+/*
+ * We need to make sure ccache doesn't cache the .o file as it doesn't notice
+ * if modsign.pub changes.
+ */
+static __initdata const char annoy_ccache[] = __TIME__ "foo";
+
+/*
+ * Load the compiled-in keys
+ */
+static __init int module_verify_init(void)
+{
+	pr_notice("Initialise module verification\n");
+
+	modsign_keyring = key_alloc(&key_type_keyring, ".module_sign",
+				    0, 0, current_cred(),
+				    (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+				    KEY_USR_VIEW | KEY_USR_READ,
+				    KEY_ALLOC_NOT_IN_QUOTA);
+	if (IS_ERR(modsign_keyring))
+		panic("Can't allocate module signing keyring\n");
+
+	if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0)
+		panic("Can't instantiate module signing keyring\n");
+
+	return 0;
+}
+
+/*
+ * Must be initialised before we try and load the keys into the keyring.
+ */
+device_initcall(module_verify_init);
+
+/*
+ * Load the compiled-in keys
+ */
+static __init int modsign_pubkey_init(void)
+{
+	pr_notice("Load module verification keys\n");
+
+	if (preload_pgp_keys(modsign_public_keys,
+			     modsign_public_keys_end - modsign_public_keys,
+			     modsign_keyring) < 0)
+		panic("Can't load module signing keys\n");
+
+	return 0;
+}
+late_initcall(modsign_pubkey_init);
diff --git a/kernel/module-verify.h b/kernel/module-verify.h
new file mode 100644
index 0000000..2f6cc16
--- /dev/null
+++ b/kernel/module-verify.h
@@ -0,0 +1,14 @@
+/* Module verification definitions
+ *
+ * Copyright (C) 2004, 2012 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.
+ */
+
+#ifdef CONFIG_MODULE_SIG
+extern struct key *modsign_keyring;
+#endif


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 21/25] MODSIGN: Module signature verification
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (19 preceding siblings ...)
  2012-08-16  1:37 ` [PATCH 20/25] MODSIGN: Provide module signing public keys to the kernel David Howells
@ 2012-08-16  1:38 ` David Howells
  2012-08-16  1:38 ` [PATCH 22/25] MODSIGN: Automatically generate module signing keys if missing David Howells
                   ` (6 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:38 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Apply signature checking to modules on module load, checking the signature
against the ring of public keys compiled into the kernel (if enabled by
CONFIG_MODULE_SIG).

There are several reasons why these patches are useful, amongst which are:

 (1) to prevent accidentally corrupted modules from causing damage;

 (2) to prevent maliciously modified modules from causing damage;

 (3) to allow a sysadmin (or more likely an IT department) to enforce a policy
     that only known and approved modules shall be loaded onto machines which
     they're expected to support;

 (4) to allow other support providers to do likewise, or at least to _detect_
     the fact that unsupported modules are loaded;

 (5) to allow the detection of modules replaced by a second-order distro or a
     preloaded Linux purveyor.

These patches have two main appeals: (a) preventing malicious modules from
being loaded, and (b) reducing support workload by pointing out modules on a
crashing box that aren't what they're expected to be.

Note that this is not a complete solution by any means: the core kernel is not
protected, and nor are /dev/mem or /dev/kmem, but it denies (or at least
controls) one relatively simple attack vector.  To protect the kernel image
would be the responsibility of the boot loader or the system BIOS.

This facility is optional: the builder of a kernel is by no means under any
requirement to actually enable it, let alone force the set of loadable modules
to be restricted to just those that the builder provides (there are degrees of
restriction available).

If CONFIG_MODULE_SIG_FORCE is enabled or "enforcemodulesig=1" is supplied on
the kernel command line, the kernel will _only_ load validly signed modules
for which it has a public key.  Otherwise, it will also load modules that are
unsigned.  Any module for which the kernel has a key, but which proves to have
a signature mismatch will not be permitted to load.

This table indicates the behaviours in the various situations:

	MODULE STATE				PERMISSIVE MODE	ENFORCING MODE
	=======================================	===============	===============
	Unsigned				Ok		EKEYREJECTED
	Signed, no public key			ENOKEY		ENOKEY
	Validly signed, public key		Ok		Ok
	Invalidly signed, public key		EKEYREJECTED	EKEYREJECTED
	Validly signed, expired key		EKEYEXPIRED	EKEYEXPIRED
	Signed, hash algorithm unavailable	ENOPKG		ENOPKG
	Signed, pubkey algorithm unavailable	ENOPKG		ENOPKG
	Signature without sig packet		ENOMSG		ENOMSG
	Corrupt signature			EBADMSG		EBADMSG
	Corrupt file				ELIBBAD		ELIBBAD


=======================
!!!IMPORTANT WARNING!!!
=======================

Signed modules generated by this kernel very likely CANNOT be used with
existing packaging and installation infrastructure.  For example, in Fedora's
environment, the module is potentially stripped at least twice:

 (1) by rpmbuild when the debuginfo is detached from the module, and

 (2) by the initrd image composer to reduce the module size.

Both of these will potentially result in the module signature being discarded
or rendered unverifiable, resulting in the module load just going ahead if the
signature magic is not found and enforcemodulesig=1 not being supplied or
-EKEYREJECTED being given or a panic being forced if FIPS mode is engaged.

To aid with (2), the module is completely stripped prior to signing as it
cannot be stripped after signing.  Both "strip -x -g" and "eu-strip" are
applied as the use of both of these results in a smaller binary.

That, however, means there is no debug information directly available for the
module.

The original unstripped binary for the foo.ko module can be found as
foo.ko.unsigned in the build tree.  It may be possible to use this as the debug
info source.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 include/linux/module.h |    3 +
 kernel/Makefile        |    2 -
 kernel/module-verify.c |  136 ++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/module-verify.h |    6 ++
 kernel/module.c        |   26 +++++++--
 5 files changed, 167 insertions(+), 6 deletions(-)
 create mode 100644 kernel/module-verify.c


diff --git a/include/linux/module.h b/include/linux/module.h
index fbcafe2..7391833 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -227,6 +227,9 @@ struct module
 	/* Unique handle for this module */
 	char name[MODULE_NAME_LEN];
 
+	/* Is this module GPG signed */
+	bool gpgsig_ok;
+
 	/* Sysfs stuff. */
 	struct module_kobject mkobj;
 	struct module_attribute *modinfo_attrs;
diff --git a/kernel/Makefile b/kernel/Makefile
index 84f6c04..895bef0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -55,7 +55,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
 obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
-obj-$(CONFIG_MODULE_SIG) += modsign-pubkey.o
+obj-$(CONFIG_MODULE_SIG) += module-verify.o modsign-pubkey.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
diff --git a/kernel/module-verify.c b/kernel/module-verify.c
new file mode 100644
index 0000000..6684e24
--- /dev/null
+++ b/kernel/module-verify.c
@@ -0,0 +1,136 @@
+/* Module signature verification
+ *
+ * The code in this file examines a signed kernel module and attempts to
+ * determine if the PGP signature attached to the end of the module matches the
+ * entire content of the module without the signature attached.
+ *
+ * Copyright (C) 2004, 2011, 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ * - Method specified by Rusty Russell.
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/modsign.h>
+#include <linux/moduleparam.h>
+#include <keys/crypto-type.h>
+#include "module-verify.h"
+
+#ifdef CONFIG_MODULE_SIG_FORCE
+#define modsign_signedonly true
+#else
+static bool modsign_signedonly;
+#endif
+
+static const char modsign_magic[] = "This Is A Crypto Signed Module";
+
+/*
+ * Verify a module's signature, if it has one
+ *
+ * Returns 0 if module is validly signed, 1 if there's no signature and a
+ * negative error code otherwise.
+ */
+static int module_verify_signature(const void *data, size_t size)
+{
+	struct crypto_sig_verify_context *mod_sig;
+	const char *cp, *sig;
+	char *end;
+	size_t magic_size, sig_size, mod_size;
+	int ret;
+
+	magic_size = sizeof(modsign_magic) - 1;
+	if (size <= 5 + magic_size)
+		return 1;
+
+	if (memcmp(data + size - magic_size, modsign_magic, magic_size) != 0)
+		return 1;
+	size -= 5 + magic_size;
+
+	cp = data + size;
+	sig_size = simple_strtoul(cp, &end, 10);
+	if (sig_size >= size || (*end != ' ' && *end != 'T'))
+		return -ELIBBAD;
+
+	mod_size = size - sig_size;
+	sig = data + mod_size;
+
+	/* Find the crypto key for the module signature
+	 * - !!! if this tries to load the required hash algorithm module,
+	 *       we will deadlock!!!
+	 */
+	mod_sig = verify_sig_begin(modsign_keyring, sig, sig_size);
+	if (IS_ERR(mod_sig)) {
+		pr_err("Couldn't initiate module signature verification: %ld\n",
+		       PTR_ERR(mod_sig));
+		return PTR_ERR(mod_sig);
+	}
+
+	/* Load the module contents into the digest */
+	ret = verify_sig_add_data(mod_sig, data, mod_size);
+	if (ret < 0) {
+		verify_sig_cancel(mod_sig);
+		return ret;
+	}
+
+	/* Do the actual signature verification */
+	ret = verify_sig_end(mod_sig, sig, sig_size);
+	pr_devel("verify-sig : %d\n", ret);
+	return ret;
+}
+
+/*
+ * Verify a module's integrity
+ */
+int module_verify(const void *data, size_t size, bool *_gpgsig_ok)
+{
+	int ret;
+
+	pr_devel("-->module_verify(,%zu,)\n", size);
+
+	ret = module_verify_signature(data, size);
+
+	pr_devel("module_verify_signature() = %d\n", ret);
+
+	switch (ret) {
+	case 0:			/* Good signature */
+		*_gpgsig_ok = true;
+		break;
+	case 1:			/* Unsigned module */
+		if (modsign_signedonly) {
+			pr_err("An attempt to load unsigned module was rejected\n");
+			return -EKEYREJECTED;
+		}
+		ret = 0;
+		break;
+	case -ELIBBAD:
+		pr_err("Module format error encountered\n");
+		break;
+	case -EBADMSG:
+		pr_err("Module signature error encountered\n");
+		break;
+	case -EKEYREJECTED:	/* Signature mismatch or number format error */
+		pr_err("Module signature verification failed\n");
+		break;
+	case -ENOKEY:		/* Signed, but we don't have the public key */
+		pr_err("Module signed with unknown public key\n");
+		break;
+	default:		/* Other error (probably ENOMEM) */
+		break;
+	}
+	return ret;
+}
+
+static int __init sign_setup(char *str)
+{
+#ifndef CONFIG_MODULE_SIG_FORCE
+	modsign_signedonly = true;
+#endif
+	return 0;
+}
+__setup("enforcemodulesig", sign_setup);
diff --git a/kernel/module-verify.h b/kernel/module-verify.h
index 2f6cc16..d59e7c9 100644
--- a/kernel/module-verify.h
+++ b/kernel/module-verify.h
@@ -11,4 +11,10 @@
 
 #ifdef CONFIG_MODULE_SIG
 extern struct key *modsign_keyring;
+extern int module_verify(const void *data, size_t size, bool *_gpgsig_ok);
+#else
+static inline int module_verify(const void *data, size_t size, bool *_gpgsig_ok)
+{
+	return 0;
+}
 #endif
diff --git a/kernel/module.c b/kernel/module.c
index 4edbd9c..30f0c0f 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -58,6 +58,7 @@
 #include <linux/jump_label.h>
 #include <linux/pfn.h>
 #include <linux/bsearch.h>
+#include "module-verify.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/module.h>
@@ -2402,7 +2403,8 @@ static inline void kmemleak_load_module(const struct module *mod,
 /* Sets info->hdr and info->len. */
 static int copy_and_check(struct load_info *info,
 			  const void __user *umod, unsigned long len,
-			  const char __user *uargs)
+			  const char __user *uargs,
+			  bool *_gpgsig_ok)
 {
 	int err;
 	Elf_Ehdr *hdr;
@@ -2435,6 +2437,12 @@ static int copy_and_check(struct load_info *info,
 		goto free_hdr;
 	}
 
+	/* Verify the module's contents */
+	*_gpgsig_ok = false;
+	err = module_verify(hdr, len, _gpgsig_ok);
+	if (err < 0)
+		goto free_hdr;
+
 	info->hdr = hdr;
 	info->len = len;
 	return 0;
@@ -2777,7 +2785,8 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
 	return 0;
 }
 
-static struct module *layout_and_allocate(struct load_info *info)
+static struct module *layout_and_allocate(struct load_info *info,
+					  bool gpgsig_ok)
 {
 	/* Module within temporary copy. */
 	struct module *mod;
@@ -2787,6 +2796,7 @@ static struct module *layout_and_allocate(struct load_info *info)
 	mod = setup_load_info(info);
 	if (IS_ERR(mod))
 		return mod;
+	mod->gpgsig_ok = gpgsig_ok;
 
 	err = check_modinfo(mod, info);
 	if (err)
@@ -2870,17 +2880,18 @@ static struct module *load_module(void __user *umod,
 	struct load_info info = { NULL, };
 	struct module *mod;
 	long err;
+	bool gpgsig_ok;
 
 	pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n",
 	       umod, len, uargs);
 
 	/* Copy in the blobs from userspace, check they are vaguely sane. */
-	err = copy_and_check(&info, umod, len, uargs);
+	err = copy_and_check(&info, umod, len, uargs, &gpgsig_ok);
 	if (err)
 		return ERR_PTR(err);
 
 	/* Figure out module layout, and allocate all the memory. */
-	mod = layout_and_allocate(&info);
+	mod = layout_and_allocate(&info, gpgsig_ok);
 	if (IS_ERR(mod)) {
 		err = PTR_ERR(mod);
 		goto free_copy;
@@ -3517,8 +3528,13 @@ void print_modules(void)
 	printk(KERN_DEFAULT "Modules linked in:");
 	/* Most callers should already have preempt disabled, but make sure */
 	preempt_disable();
-	list_for_each_entry_rcu(mod, &modules, list)
+	list_for_each_entry_rcu(mod, &modules, list) {
 		printk(" %s%s", mod->name, module_flags(mod, buf));
+#ifdef CONFIG_MODULE_SIG
+		if (!mod->gpgsig_ok)
+			printk("(U)");
+#endif
+	}
 	preempt_enable();
 	if (last_unloaded_module[0])
 		printk(" [last unloaded: %s]", last_unloaded_module);


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 22/25] MODSIGN: Automatically generate module signing keys if missing
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (20 preceding siblings ...)
  2012-08-16  1:38 ` [PATCH 21/25] MODSIGN: Module signature verification David Howells
@ 2012-08-16  1:38 ` David Howells
  2012-08-16  1:38 ` [PATCH 23/25] MODSIGN: Panic the kernel if FIPS is enabled upon module signing failure David Howells
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:38 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Automatically generate keys for module signing if they're absent so that
allyesconfig doesn't break.  The builder should consider generating their own
keyrings, however, so that the keys are appropriately named and any extra keys
required get imported.

Also change the names of the keyring files to modsign.pub and modsign.sec so
that they are then a more obvious what they're about and add a dependency for
the signing rules on the keyring files so that the signatures get regenerated
if the keyrings change.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 kernel/Makefile |   39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)


diff --git a/kernel/Makefile b/kernel/Makefile
index 895bef0..f612ed0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -133,4 +133,43 @@ targets += timeconst.h
 $(obj)/timeconst.h: $(src)/timeconst.pl FORCE
 	$(call if_changed,timeconst)
 
+###############################################################################
+#
+# If module signing is requested, say by allyesconfig, but a key has not been
+# supplied, then one will need to be generated to make sure the build does not
+# fail and that the kernel may be used afterwards.
+#
+###############################################################################
+ifeq ($(CONFIG_MODULE_SIG),y)
 kernel/modsign-pubkey.o: modsign.pub
+
+modsign.pub modsign.sec: genkey
+	@echo "###"
+	@echo "### Now generating a PGP key pair to be used for signing modules."
+	@echo "###"
+	@echo "### If this takes a long time, you might wish to run rngd in the"
+	@echo "### background to keep the supply of entropy topped up.  It"
+	@echo "### needs to be run as root, and should use a hardware random"
+	@echo "### number generator if one is available, eg:"
+	@echo "###"
+	@echo "###     rngd -r /dev/hwrandom"
+	@echo "###"
+	gpg --homedir . --batch --gen-key genkey
+	@echo "###"
+	@echo "### Key pair generated."
+	@echo "###"
+	rm -f pubring.gpg secring.gpg trustdb.gpg
+
+genkey:
+	echo "%pubring modsign.pub" >genkey
+	echo "%secring modsign.sec" >>genkey
+	echo "%no-protection: yes" >> genkey
+	echo "%transient-key: yes" >>genkey
+	echo "Key-Type: RSA" >>genkey
+	echo "Key-Length: 4096" >>genkey
+	echo "Name-Real: Sample kernel key" >>genkey
+	echo "Name-Comment: Sample kernel module signing key" >>genkey
+	echo "%commit" >>genkey
+
+endif
+CLEAN_FILES += modsign.pub modsign.sec genkey random_seed


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 23/25] MODSIGN: Panic the kernel if FIPS is enabled upon module signing failure
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (21 preceding siblings ...)
  2012-08-16  1:38 ` [PATCH 22/25] MODSIGN: Automatically generate module signing keys if missing David Howells
@ 2012-08-16  1:38 ` David Howells
  2012-08-16  1:38 ` [PATCH 24/25] MODSIGN: Allow modules to be signed with an unknown key unless enforcing David Howells
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:38 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

If module signing fails when the kernel is running with FIPS enabled then the
kernel should panic lest the crypto layer be compromised.  Possibly a panic
shouldn't happen on cases like ENOMEM.

Reported-by: Stephan Mueller <stephan.mueller@atsec.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 kernel/module-verify.c |    5 +++++
 1 file changed, 5 insertions(+)


diff --git a/kernel/module-verify.c b/kernel/module-verify.c
index 6684e24..070d730 100644
--- a/kernel/module-verify.c
+++ b/kernel/module-verify.c
@@ -19,6 +19,7 @@
 #include <linux/sched.h>
 #include <linux/modsign.h>
 #include <linux/moduleparam.h>
+#include <linux/fips.h>
 #include <keys/crypto-type.h>
 #include "module-verify.h"
 
@@ -97,6 +98,10 @@ int module_verify(const void *data, size_t size, bool *_gpgsig_ok)
 
 	pr_devel("module_verify_signature() = %d\n", ret);
 
+        if (ret < 0 && fips_enabled)
+                panic("Module verification failed with error %d in FIPS mode\n",
+                      ret);
+
 	switch (ret) {
 	case 0:			/* Good signature */
 		*_gpgsig_ok = true;


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 24/25] MODSIGN: Allow modules to be signed with an unknown key unless enforcing
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (22 preceding siblings ...)
  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 ` David Howells
  2012-08-16  1:38 ` [PATCH 25/25] MODSIGN: Fix documentation of signed-nokey behavior when not enforcing David Howells
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:38 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Currently we fail the loading of modules that are signed with a public key
that is not in the modsign keyring even if we are not in enforcing mode.
This is somewhat at odds with the fact that we allow a completely unsigned
module to load in such a case.

We should allow modules signed with an unknown key to load in cases
where we are not enforcing and not in FIPS mode.

Signed-off-by: Josh Boyer <jwboyer@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 kernel/module-verify.c |    7 +++++++
 1 file changed, 7 insertions(+)


diff --git a/kernel/module-verify.c b/kernel/module-verify.c
index 070d730..c02d2e5 100644
--- a/kernel/module-verify.c
+++ b/kernel/module-verify.c
@@ -124,6 +124,13 @@ int module_verify(const void *data, size_t size, bool *_gpgsig_ok)
 		break;
 	case -ENOKEY:		/* Signed, but we don't have the public key */
 		pr_err("Module signed with unknown public key\n");
+		if (!modsign_signedonly) {
+			/* Allow a module to be signed with an unknown public
+			 * key unless we're enforcing.
+			 */
+			pr_info("Allowing\n");
+			ret = 0;
+		}
 		break;
 	default:		/* Other error (probably ENOMEM) */
 		break;


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 25/25] MODSIGN: Fix documentation of signed-nokey behavior when not enforcing.
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (23 preceding siblings ...)
  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 ` David Howells
  2012-08-21  5:04 ` [PATCH 00/25] Crypto keys and module signing Rusty Russell
                   ` (2 subsequent siblings)
  27 siblings, 0 replies; 48+ messages in thread
From: David Howells @ 2012-08-16  1:38 UTC (permalink / raw)
  To: rusty
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

jwboyer's previous commit changes the behavior of module signing when
there's a valid signature but we don't know the public key and are in
permissive mode.  This updates the documentation to match.

Signed-off-by: Peter Jones <pjones@redhat.com>
Acked-by: Josh Boyer <jwboyer@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 Documentation/module-signing.txt |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)


diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt
index b355aa2..2549536 100644
--- a/Documentation/module-signing.txt
+++ b/Documentation/module-signing.txt
@@ -174,7 +174,7 @@ This table indicates the behaviours of the various situations:
 	MODULE STATE				PERMISSIVE MODE	ENFORCING MODE
 	=======================================	===============	===============
 	Unsigned				Ok		EKEYREJECTED
-	Signed, no public key			ENOKEY		ENOKEY
+	Signed, no public key			Ok		ENOKEY
 	Validly signed, public key		Ok		Ok
 	Invalidly signed, public key		EKEYREJECTED	EKEYREJECTED
 	Validly signed, expired key		EKEYEXPIRED	EKEYEXPIRED


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH 00/25] Crypto keys and module signing
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (24 preceding siblings ...)
  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 ` Rusty Russell
  2012-08-22 10:50 ` David Howells
  2012-09-04  5:55 ` [RFC] module: signature infrastructure Rusty Russell
  27 siblings, 0 replies; 48+ messages in thread
From: Rusty Russell @ 2012-08-21  5:04 UTC (permalink / raw)
  To: David Howells
  Cc: dhowells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

On Thu, 16 Aug 2012 02:34:05 +0100, David Howells <dhowells@redhat.com> wrote:
> 
> Hi Rusty,
> 
> I've posted new versions of my module signing patches to my GIT trees.

Now I get to punt this discussion to KS.

I knew it was good for something!

Cheers,
Rusty.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 00/25] Crypto keys and module signing
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (25 preceding siblings ...)
  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
  27 siblings, 2 replies; 48+ messages in thread
From: David Howells @ 2012-08-22 10:50 UTC (permalink / raw)
  To: Rusty Russell, dmitry.kasatkin, zohar
  Cc: dhowells, jmorris, keyrings, linux-security-module, linux-kernel

Rusty Russell <rusty@rustcorp.com.au> wrote:

> > I've posted new versions of my module signing patches to my GIT trees.
> 
> Now I get to punt this discussion to KS.

:-)

See you there!

Dmitry, Mimi: We should discuss if there's any way to integrate our two
approaches.  Are you going to the security summit?

David

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 00/25] Crypto keys and module signing
  2012-08-22 10:50 ` David Howells
@ 2012-08-22 11:52   ` Mimi Zohar
  2012-08-22 16:07   ` Kasatkin, Dmitry
  1 sibling, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2012-08-22 11:52 UTC (permalink / raw)
  To: David Howells
  Cc: Rusty Russell, dmitry.kasatkin, jmorris, keyrings,
	linux-security-module, linux-kernel

On Wed, 2012-08-22 at 11:50 +0100, David Howells wrote:
> Rusty Russell <rusty@rustcorp.com.au> wrote:
> 
> > > I've posted new versions of my module signing patches to my GIT trees.
> > 
> > Now I get to punt this discussion to KS.
> 
> :-)
> 
> See you there!
> 
> Dmitry, Mimi: We should discuss if there's any way to integrate our two
> approaches.  Are you going to the security summit?

Sounds good!  Both of us will be there.  I haven't seen the KS schedule
for Wed, but Rusty has requested a slot.  I'm arriving Tues, if you want
to schedule something else/in addition.

thanks,

Mimi



^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 00/25] Crypto keys and module signing
  2012-08-22 10:50 ` David Howells
  2012-08-22 11:52   ` Mimi Zohar
@ 2012-08-22 16:07   ` Kasatkin, Dmitry
  1 sibling, 0 replies; 48+ messages in thread
From: Kasatkin, Dmitry @ 2012-08-22 16:07 UTC (permalink / raw)
  To: David Howells
  Cc: Rusty Russell, zohar, jmorris, keyrings, linux-security-module,
	linux-kernel

Hi David,

Yes, I will be also attending LSS and would like to visit KS discussion as well.
Hope Rusty will send a schedule soon...

Regards,
Dmitry


On Wed, Aug 22, 2012 at 1:50 PM, David Howells <dhowells@redhat.com> wrote:
> Rusty Russell <rusty@rustcorp.com.au> wrote:
>
>> > I've posted new versions of my module signing patches to my GIT trees.
>>
>> Now I get to punt this discussion to KS.
>
> :-)
>
> See you there!
>
> Dmitry, Mimi: We should discuss if there's any way to integrate our two
> approaches.  Are you going to the security summit?
>
> David

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 20/25] MODSIGN: Provide module signing public keys to the kernel
  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
  0 siblings, 0 replies; 48+ messages in thread
From: Michal Marek @ 2012-08-31 14:33 UTC (permalink / raw)
  To: David Howells
  Cc: rusty, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

On 16.8.2012 03:37, David Howells wrote:
> +asm(".section .init.data,\"aw\"\n"
> +    "modsign_public_keys:\n"
> +    ".incbin \"modsign.pub\"\n"
> +    "modsign_public_keys_end:"
> +    );
> +
> +/*
> + * We need to make sure ccache doesn't cache the .o file as it doesn't notice
> + * if modsign.pub changes.
> + */
> +static __initdata const char annoy_ccache[] = __TIME__ "foo";

This results in a different object file after each build, even if
modsign.pub is the same :(. How about generating a modsign-hash.c with
the following content

static __initdata const char annoy_ccache[] = "<some checksum of
modsign.pub, or the key fingerprint>";

and including it in modsign-pubkey.c with the preprocessor? When
changing the public key, modsign.hash.c would change as well and ccache
would notice it. But when doing a rebuild from the same source with the
same public key, the resulting object file would not change.

Thanks,
Michal

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [RFC] module: signature infrastructure
  2012-08-16  1:34 [PATCH 00/25] Crypto keys and module signing David Howells
                   ` (26 preceding siblings ...)
  2012-08-22 10:50 ` David Howells
@ 2012-09-04  5:55 ` Rusty Russell
  2012-09-04 12:07   ` Kasatkin, Dmitry
                     ` (2 more replies)
  27 siblings, 3 replies; 48+ messages in thread
From: Rusty Russell @ 2012-09-04  5:55 UTC (permalink / raw)
  To: David Howells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

OK, I took a look at the module.c parts of David and Dmitry's patchsets,
and didn't really like either, but I stole parts of David's to make
this.

So, here's the module.c part of module signing.  I hope you two got time
to discuss the signature format details?  Mimi suggested a scheme where
the private key would never be saved on disk (even temporarily), but I
didn't see patches.  Frankly it's something we can do later; let's aim
at getting the format right for the next merge window.

Cheers,
Rusty.

---
This patch doesn't compile: we need to implement:

	int mod_verify_sig(const void *mod, unsigned long modlen,
			   const void *sig, unsigned long siglen,
			   bool *sig_ok);

Also, we need to actually append the signatures during build.

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index ad7e2e5..9b2b8d3 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1582,6 +1582,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			log everything. Information is printed at KERN_DEBUG
 			so loglevel=8 may also need to be specified.
 
+	module.sig_enforce
+			[KNL] When CONFIG_MODULE_SIG is set, this means that
+			modules without (valid) signatures will fail to load.
+			Note that if CONFIG_MODULE_SIG_ENFORCE is set, that
+			is always true, so this option does nothing.
+
 	mousedev.tap_time=
 			[MOUSE] Maximum time between finger touching and
 			leaving touchpad surface for touch to be considered
diff --git a/include/linux/module.h b/include/linux/module.h
index fbcafe2..7760c6d 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -21,6 +21,9 @@
 #include <linux/percpu.h>
 #include <asm/module.h>
 
+/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
+#define MODULE_SIG_STRING "~Module signature appended~\n"
+
 /* Not Yet Implemented */
 #define MODULE_SUPPORTED_DEVICE(name)
 
@@ -260,6 +263,11 @@ struct module
 	const unsigned long *unused_gpl_crcs;
 #endif
 
+#ifdef CONFIG_MODULE_SIG
+	/* Signature was verified. */
+	bool sig_ok;
+#endif
+
 	/* symbols that will be GPL-only in the near future. */
 	const struct kernel_symbol *gpl_future_syms;
 	const unsigned long *gpl_future_crcs;
diff --git a/init/Kconfig b/init/Kconfig
index af6c7f8..7452e19 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1585,6 +1585,20 @@ config MODULE_SRCVERSION_ALL
 	  the version).  With this option, such a "srcversion" field
 	  will be created for all modules.  If unsure, say N.
 
+config MODULE_SIG
+	bool "Module signature verification"
+	depends on MODULES
+	help
+	  Check modules for valid signatures upon load: the signature
+	  is simply appended to the module. For more information see
+	  Documentation/module-signing.txt.
+
+config MODULE_SIG_FORCE
+	bool "Require modules to be validly signed"
+	depends on MODULE_SIG
+	help
+	  Reject unsigned modules or signed modules for which we don't have a
+	  key.  Without this, such modules will simply taint the kernel.
 endif # MODULES
 
 config INIT_ALL_POSSIBLE
diff --git a/kernel/module.c b/kernel/module.c
index 4edbd9c..3cbd1a4 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -102,6 +102,43 @@ static LIST_HEAD(modules);
 struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
 #endif /* CONFIG_KGDB_KDB */
 
+#ifdef CONFIG_MODULE_SIG
+#ifdef CONFIG_MODULE_SIG_ENFORCE
+static bool sig_enforce = true;
+#else
+static bool sig_enforce = false;
+
+static int param_set_bool_enable_only(const char *val,
+				      const struct kernel_param *kp)
+{
+	int err;
+	bool test;
+	struct kernel_param dummy_kp = *kp;
+
+	dummy_kp.arg = &test;
+
+	err = param_set_bool(val, &dummy_kp);
+	if (err)
+		return err;
+
+	/* Don't let them unset it once it's set! */
+	if (!test && sig_enforce)
+		return -EROFS;
+
+	if (test)
+		sig_enforce = true;
+	return 0;
+}
+
+static const struct kernel_param_ops param_ops_bool_enable_only = {
+	.set = param_set_bool_enable_only,
+	.get = param_get_bool,
+};
+#define param_check_bool_enable_only param_check_bool
+
+module_param(sig_enforce, bool_enable_only, 0644);
+#endif /* !CONFIG_MODULE_SIG_ENFORCE */
+#endif /* CONFIG_MODULE_SIG */
 
 /* Block module loading/unloading? */
 int modules_disabled = 0;
@@ -136,6 +173,7 @@ struct load_info {
 	unsigned long symoffs, stroffs;
 	struct _ddebug *debug;
 	unsigned int num_debug;
+	bool sig_ok;
 	struct {
 		unsigned int sym, str, mod, vers, info, pcpu;
 	} index;
@@ -2399,7 +2437,50 @@ static inline void kmemleak_load_module(const struct module *mod,
 }
 #endif
 
-/* Sets info->hdr and info->len. */
+#ifdef CONFIG_MODULE_SIG
+static int module_sig_check(struct load_info *info,
+			    void *mod, unsigned long *len)
+{
+	int err;
+	unsigned long i, siglen;
+	char *sig = NULL;
+
+	/* This is not a valid module: ELF header is larger anyway. */
+	if (*len < sizeof(MODULE_SIG_STRING))
+		return -ENOEXEC;
+
+	for (i = 0; i < *len - (sizeof(MODULE_SIG_STRING)-1); i++) {
+		/* Our memcmp is dumb, speed it up a little. */
+		if (((char *)mod)[i] != MODULE_SIG_STRING[0])
+			continue;
+		if (memcmp(mod, MODULE_SIG_STRING, strlen(MODULE_SIG_STRING)))
+			continue;
+
+		sig = mod + i + strlen(MODULE_SIG_STRING);
+		siglen = *len - i - strlen(MODULE_SIG_STRING);
+		*len = i;
+		break;
+	}
+
+	if (!sig)
+		err = 0;
+	else
+		err = mod_verify_sig(mod, len, sig, siglen, &info->sig_ok);
+
+	/* Not having a signature is only an error if we're strict. */
+	if (!err && !info->sig_ok && sig_enforce)
+		err = -EKEYREJECTED;
+	return err;
+}
+#else /* !CONFIG_MODULE_SIG */
+static int module_sig_check(struct load_info *info,
+			    void *mod, unsigned long *len)
+{
+	return 0;
+}
+#endif /* !CONFIG_MODULE_SIG */
+
+/* Sets info->hdr, info->len and info->sig_ok. */
 static int copy_and_check(struct load_info *info,
 			  const void __user *umod, unsigned long len,
 			  const char __user *uargs)
@@ -2419,6 +2500,10 @@ static int copy_and_check(struct load_info *info,
 		goto free_hdr;
 	}
 
+	err = module_sig_check(info, hdr, &len);
+	if (err)
+		goto free_hdr;
+
 	/* Sanity checks against insmoding binaries or wrong arch,
 	   weird elf version */
 	if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
@@ -2886,6 +2971,12 @@ static struct module *load_module(void __user *umod,
 		goto free_copy;
 	}
 
+#ifdef CONFIG_MODULE_SIG
+	mod->sig_ok = info.sig_ok;
+	if (!mod->sig_ok)
+		add_taint_module(mod, TAINT_FORCED_MODULE);
+#endif
+
 	/* Now module is in final location, initialize linked lists, etc. */
 	err = module_unload_init(mod);
 	if (err)

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  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-05  0:29     ` Rusty Russell
  2012-09-04 14:25   ` Lucas De Marchi
  2012-09-04 22:51   ` David Howells
  2 siblings, 2 replies; 48+ messages in thread
From: Kasatkin, Dmitry @ 2012-09-04 12:07 UTC (permalink / raw)
  To: Rusty Russell
  Cc: David Howells, zohar, jmorris, keyrings, linux-security-module,
	linux-kernel

Hi,

Please read bellow...

On Tue, Sep 4, 2012 at 8:55 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> OK, I took a look at the module.c parts of David and Dmitry's patchsets,
> and didn't really like either, but I stole parts of David's to make
> this.
>
> So, here's the module.c part of module signing.  I hope you two got time
> to discuss the signature format details?  Mimi suggested a scheme where
> the private key would never be saved on disk (even temporarily), but I
> didn't see patches.  Frankly it's something we can do later; let's aim
> at getting the format right for the next merge window.

In our patches key is stored on the disc in encrypted format...

More bellow..

>
> Cheers,
> Rusty.
>
> ---
> This patch doesn't compile: we need to implement:
>
>         int mod_verify_sig(const void *mod, unsigned long modlen,
>                            const void *sig, unsigned long siglen,
>                            bool *sig_ok);
>
> Also, we need to actually append the signatures during build.
>
> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> index ad7e2e5..9b2b8d3 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -1582,6 +1582,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
>                         log everything. Information is printed at KERN_DEBUG
>                         so loglevel=8 may also need to be specified.
>
> +       module.sig_enforce
> +                       [KNL] When CONFIG_MODULE_SIG is set, this means that
> +                       modules without (valid) signatures will fail to load.
> +                       Note that if CONFIG_MODULE_SIG_ENFORCE is set, that
> +                       is always true, so this option does nothing.
> +
>         mousedev.tap_time=
>                         [MOUSE] Maximum time between finger touching and
>                         leaving touchpad surface for touch to be considered
> diff --git a/include/linux/module.h b/include/linux/module.h
> index fbcafe2..7760c6d 100644
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -21,6 +21,9 @@
>  #include <linux/percpu.h>
>  #include <asm/module.h>
>
> +/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
> +#define MODULE_SIG_STRING "~Module signature appended~\n"
> +
>  /* Not Yet Implemented */
>  #define MODULE_SUPPORTED_DEVICE(name)
>
> @@ -260,6 +263,11 @@ struct module
>         const unsigned long *unused_gpl_crcs;
>  #endif
>
> +#ifdef CONFIG_MODULE_SIG
> +       /* Signature was verified. */
> +       bool sig_ok;
> +#endif
> +
>         /* symbols that will be GPL-only in the near future. */
>         const struct kernel_symbol *gpl_future_syms;
>         const unsigned long *gpl_future_crcs;
> diff --git a/init/Kconfig b/init/Kconfig
> index af6c7f8..7452e19 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -1585,6 +1585,20 @@ config MODULE_SRCVERSION_ALL
>           the version).  With this option, such a "srcversion" field
>           will be created for all modules.  If unsure, say N.
>
> +config MODULE_SIG
> +       bool "Module signature verification"
> +       depends on MODULES
> +       help
> +         Check modules for valid signatures upon load: the signature
> +         is simply appended to the module. For more information see
> +         Documentation/module-signing.txt.
> +
> +config MODULE_SIG_FORCE
> +       bool "Require modules to be validly signed"
> +       depends on MODULE_SIG
> +       help
> +         Reject unsigned modules or signed modules for which we don't have a
> +         key.  Without this, such modules will simply taint the kernel.
>  endif # MODULES
>
>  config INIT_ALL_POSSIBLE
> diff --git a/kernel/module.c b/kernel/module.c
> index 4edbd9c..3cbd1a4 100644
> --- a/kernel/module.c
> +++ b/kernel/module.c
> @@ -102,6 +102,43 @@ static LIST_HEAD(modules);
>  struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
>  #endif /* CONFIG_KGDB_KDB */
>
> +#ifdef CONFIG_MODULE_SIG
> +#ifdef CONFIG_MODULE_SIG_ENFORCE
> +static bool sig_enforce = true;
> +#else
> +static bool sig_enforce = false;
> +
> +static int param_set_bool_enable_only(const char *val,
> +                                     const struct kernel_param *kp)
> +{
> +       int err;
> +       bool test;
> +       struct kernel_param dummy_kp = *kp;
> +
> +       dummy_kp.arg = &test;
> +
> +       err = param_set_bool(val, &dummy_kp);
> +       if (err)
> +               return err;
> +
> +       /* Don't let them unset it once it's set! */
> +       if (!test && sig_enforce)
> +               return -EROFS;
> +
> +       if (test)
> +               sig_enforce = true;
> +       return 0;
> +}
> +
> +static const struct kernel_param_ops param_ops_bool_enable_only = {
> +       .set = param_set_bool_enable_only,
> +       .get = param_get_bool,
> +};
> +#define param_check_bool_enable_only param_check_bool
> +
> +module_param(sig_enforce, bool_enable_only, 0644);
> +#endif /* !CONFIG_MODULE_SIG_ENFORCE */
> +#endif /* CONFIG_MODULE_SIG */
>
>  /* Block module loading/unloading? */
>  int modules_disabled = 0;
> @@ -136,6 +173,7 @@ struct load_info {
>         unsigned long symoffs, stroffs;
>         struct _ddebug *debug;
>         unsigned int num_debug;
> +       bool sig_ok;
>         struct {
>                 unsigned int sym, str, mod, vers, info, pcpu;
>         } index;
> @@ -2399,7 +2437,50 @@ static inline void kmemleak_load_module(const struct module *mod,
>  }
>  #endif
>
> -/* Sets info->hdr and info->len. */
> +#ifdef CONFIG_MODULE_SIG
> +static int module_sig_check(struct load_info *info,
> +                           void *mod, unsigned long *len)
> +{
> +       int err;
> +       unsigned long i, siglen;
> +       char *sig = NULL;
> +
> +       /* This is not a valid module: ELF header is larger anyway. */
> +       if (*len < sizeof(MODULE_SIG_STRING))
> +               return -ENOEXEC;
> +
> +       for (i = 0; i < *len - (sizeof(MODULE_SIG_STRING)-1); i++) {
> +               /* Our memcmp is dumb, speed it up a little. */
> +               if (((char *)mod)[i] != MODULE_SIG_STRING[0])
> +                       continue;
> +               if (memcmp(mod, MODULE_SIG_STRING, strlen(MODULE_SIG_STRING)))

should be (mod+i)?

> +                       continue;
> +
> +               sig = mod + i + strlen(MODULE_SIG_STRING);
> +               siglen = *len - i - strlen(MODULE_SIG_STRING);
> +               *len = i;
> +               break;
> +       }

In general please clarify why do you need such parsing at all?
Why not to have MODULE_SIG_STRING as a last octets of the module and
have signature length field before?
Then it is easy to get the signature and rest of the module?
That will be super fast...

Please clarify.

> +
> +       if (!sig)
> +               err = 0;
> +       else
> +               err = mod_verify_sig(mod, len, sig, siglen, &info->sig_ok);
> +
> +       /* Not having a signature is only an error if we're strict. */
> +       if (!err && !info->sig_ok && sig_enforce)
> +               err = -EKEYREJECTED;
> +       return err;
> +}
> +#else /* !CONFIG_MODULE_SIG */
> +static int module_sig_check(struct load_info *info,
> +                           void *mod, unsigned long *len)
> +{
> +       return 0;
> +}
> +#endif /* !CONFIG_MODULE_SIG */
> +
> +/* Sets info->hdr, info->len and info->sig_ok. */
>  static int copy_and_check(struct load_info *info,
>                           const void __user *umod, unsigned long len,
>                           const char __user *uargs)
> @@ -2419,6 +2500,10 @@ static int copy_and_check(struct load_info *info,
>                 goto free_hdr;
>         }
>
> +       err = module_sig_check(info, hdr, &len);
> +       if (err)
> +               goto free_hdr;
> +
>         /* Sanity checks against insmoding binaries or wrong arch,
>            weird elf version */
>         if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
> @@ -2886,6 +2971,12 @@ static struct module *load_module(void __user *umod,
>                 goto free_copy;
>         }
>
> +#ifdef CONFIG_MODULE_SIG
> +       mod->sig_ok = info.sig_ok;
> +       if (!mod->sig_ok)
> +               add_taint_module(mod, TAINT_FORCED_MODULE);
> +#endif
> +
>         /* Now module is in final location, initialize linked lists, etc. */
>         err = module_unload_init(mod);
>         if (err)

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  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
  1 sibling, 1 reply; 48+ messages in thread
From: Kasatkin, Dmitry @ 2012-09-04 12:21 UTC (permalink / raw)
  To: Rusty Russell
  Cc: David Howells, zohar, jmorris, keyrings, linux-security-module,
	linux-kernel

On Tue, Sep 4, 2012 at 3:07 PM, Kasatkin, Dmitry
<dmitry.kasatkin@intel.com> wrote:
> Hi,
>
> Please read bellow...
>
> On Tue, Sep 4, 2012 at 8:55 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
>> OK, I took a look at the module.c parts of David and Dmitry's patchsets,
>> and didn't really like either, but I stole parts of David's to make
>> this.
>>
>> So, here's the module.c part of module signing.  I hope you two got time
>> to discuss the signature format details?  Mimi suggested a scheme where
>> the private key would never be saved on disk (even temporarily), but I
>> didn't see patches.  Frankly it's something we can do later; let's aim
>> at getting the format right for the next merge window.
>
> In our patches key is stored on the disc in encrypted format...
>
> More bellow..
>
>>
>> Cheers,
>> Rusty.
>>
>> ---
>> This patch doesn't compile: we need to implement:
>>
>>         int mod_verify_sig(const void *mod, unsigned long modlen,
>>                            const void *sig, unsigned long siglen,
>>                            bool *sig_ok);
>>
>> Also, we need to actually append the signatures during build.
>>
>> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
>> index ad7e2e5..9b2b8d3 100644
>> --- a/Documentation/kernel-parameters.txt
>> +++ b/Documentation/kernel-parameters.txt
>> @@ -1582,6 +1582,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
>>                         log everything. Information is printed at KERN_DEBUG
>>                         so loglevel=8 may also need to be specified.
>>
>> +       module.sig_enforce
>> +                       [KNL] When CONFIG_MODULE_SIG is set, this means that
>> +                       modules without (valid) signatures will fail to load.
>> +                       Note that if CONFIG_MODULE_SIG_ENFORCE is set, that
>> +                       is always true, so this option does nothing.
>> +
>>         mousedev.tap_time=
>>                         [MOUSE] Maximum time between finger touching and
>>                         leaving touchpad surface for touch to be considered
>> diff --git a/include/linux/module.h b/include/linux/module.h
>> index fbcafe2..7760c6d 100644
>> --- a/include/linux/module.h
>> +++ b/include/linux/module.h
>> @@ -21,6 +21,9 @@
>>  #include <linux/percpu.h>
>>  #include <asm/module.h>
>>
>> +/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
>> +#define MODULE_SIG_STRING "~Module signature appended~\n"
>> +
>>  /* Not Yet Implemented */
>>  #define MODULE_SUPPORTED_DEVICE(name)
>>
>> @@ -260,6 +263,11 @@ struct module
>>         const unsigned long *unused_gpl_crcs;
>>  #endif
>>
>> +#ifdef CONFIG_MODULE_SIG
>> +       /* Signature was verified. */
>> +       bool sig_ok;
>> +#endif
>> +
>>         /* symbols that will be GPL-only in the near future. */
>>         const struct kernel_symbol *gpl_future_syms;
>>         const unsigned long *gpl_future_crcs;
>> diff --git a/init/Kconfig b/init/Kconfig
>> index af6c7f8..7452e19 100644
>> --- a/init/Kconfig
>> +++ b/init/Kconfig
>> @@ -1585,6 +1585,20 @@ config MODULE_SRCVERSION_ALL
>>           the version).  With this option, such a "srcversion" field
>>           will be created for all modules.  If unsure, say N.
>>
>> +config MODULE_SIG
>> +       bool "Module signature verification"
>> +       depends on MODULES
>> +       help
>> +         Check modules for valid signatures upon load: the signature
>> +         is simply appended to the module. For more information see
>> +         Documentation/module-signing.txt.
>> +
>> +config MODULE_SIG_FORCE
>> +       bool "Require modules to be validly signed"
>> +       depends on MODULE_SIG
>> +       help
>> +         Reject unsigned modules or signed modules for which we don't have a
>> +         key.  Without this, such modules will simply taint the kernel.
>>  endif # MODULES
>>
>>  config INIT_ALL_POSSIBLE
>> diff --git a/kernel/module.c b/kernel/module.c
>> index 4edbd9c..3cbd1a4 100644
>> --- a/kernel/module.c
>> +++ b/kernel/module.c
>> @@ -102,6 +102,43 @@ static LIST_HEAD(modules);
>>  struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
>>  #endif /* CONFIG_KGDB_KDB */
>>
>> +#ifdef CONFIG_MODULE_SIG
>> +#ifdef CONFIG_MODULE_SIG_ENFORCE
>> +static bool sig_enforce = true;
>> +#else
>> +static bool sig_enforce = false;
>> +
>> +static int param_set_bool_enable_only(const char *val,
>> +                                     const struct kernel_param *kp)
>> +{
>> +       int err;
>> +       bool test;
>> +       struct kernel_param dummy_kp = *kp;
>> +
>> +       dummy_kp.arg = &test;
>> +
>> +       err = param_set_bool(val, &dummy_kp);
>> +       if (err)
>> +               return err;
>> +
>> +       /* Don't let them unset it once it's set! */
>> +       if (!test && sig_enforce)
>> +               return -EROFS;
>> +
>> +       if (test)
>> +               sig_enforce = true;
>> +       return 0;
>> +}
>> +
>> +static const struct kernel_param_ops param_ops_bool_enable_only = {
>> +       .set = param_set_bool_enable_only,
>> +       .get = param_get_bool,
>> +};
>> +#define param_check_bool_enable_only param_check_bool
>> +
>> +module_param(sig_enforce, bool_enable_only, 0644);
>> +#endif /* !CONFIG_MODULE_SIG_ENFORCE */
>> +#endif /* CONFIG_MODULE_SIG */
>>
>>  /* Block module loading/unloading? */
>>  int modules_disabled = 0;
>> @@ -136,6 +173,7 @@ struct load_info {
>>         unsigned long symoffs, stroffs;
>>         struct _ddebug *debug;
>>         unsigned int num_debug;
>> +       bool sig_ok;
>>         struct {
>>                 unsigned int sym, str, mod, vers, info, pcpu;
>>         } index;
>> @@ -2399,7 +2437,50 @@ static inline void kmemleak_load_module(const struct module *mod,
>>  }
>>  #endif
>>
>> -/* Sets info->hdr and info->len. */
>> +#ifdef CONFIG_MODULE_SIG
>> +static int module_sig_check(struct load_info *info,
>> +                           void *mod, unsigned long *len)
>> +{
>> +       int err;
>> +       unsigned long i, siglen;
>> +       char *sig = NULL;
>> +
>> +       /* This is not a valid module: ELF header is larger anyway. */
>> +       if (*len < sizeof(MODULE_SIG_STRING))
>> +               return -ENOEXEC;
>> +
>> +       for (i = 0; i < *len - (sizeof(MODULE_SIG_STRING)-1); i++) {
>> +               /* Our memcmp is dumb, speed it up a little. */
>> +               if (((char *)mod)[i] != MODULE_SIG_STRING[0])
>> +                       continue;
>> +               if (memcmp(mod, MODULE_SIG_STRING, strlen(MODULE_SIG_STRING)))
>
> should be (mod+i)?
>
>> +                       continue;
>> +
>> +               sig = mod + i + strlen(MODULE_SIG_STRING);
>> +               siglen = *len - i - strlen(MODULE_SIG_STRING);
>> +               *len = i;
>> +               break;
>> +       }
>
> In general please clarify why do you need such parsing at all?
> Why not to have MODULE_SIG_STRING as a last octets of the module and
> have signature length field before?
> Then it is easy to get the signature and rest of the module?
> That will be super fast...
>

This is how it looks

http://git.kernel.org/?p=linux/kernel/git/kasatkin/linux-digsig.git;a=blob;f=security/integrity/module.c;h=b111bb400a248ab9b03a64ea373c88396f311649;hb=19eef6e4e529ccf2b3a6ab5c19dd40f2eaf8fcaf

> Please clarify.
>
>> +
>> +       if (!sig)
>> +               err = 0;
>> +       else
>> +               err = mod_verify_sig(mod, len, sig, siglen, &info->sig_ok);
>> +
>> +       /* Not having a signature is only an error if we're strict. */
>> +       if (!err && !info->sig_ok && sig_enforce)
>> +               err = -EKEYREJECTED;
>> +       return err;
>> +}
>> +#else /* !CONFIG_MODULE_SIG */
>> +static int module_sig_check(struct load_info *info,
>> +                           void *mod, unsigned long *len)
>> +{
>> +       return 0;
>> +}
>> +#endif /* !CONFIG_MODULE_SIG */
>> +
>> +/* Sets info->hdr, info->len and info->sig_ok. */
>>  static int copy_and_check(struct load_info *info,
>>                           const void __user *umod, unsigned long len,
>>                           const char __user *uargs)
>> @@ -2419,6 +2500,10 @@ static int copy_and_check(struct load_info *info,
>>                 goto free_hdr;
>>         }
>>
>> +       err = module_sig_check(info, hdr, &len);
>> +       if (err)
>> +               goto free_hdr;
>> +
>>         /* Sanity checks against insmoding binaries or wrong arch,
>>            weird elf version */
>>         if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
>> @@ -2886,6 +2971,12 @@ static struct module *load_module(void __user *umod,
>>                 goto free_copy;
>>         }
>>
>> +#ifdef CONFIG_MODULE_SIG
>> +       mod->sig_ok = info.sig_ok;
>> +       if (!mod->sig_ok)
>> +               add_taint_module(mod, TAINT_FORCED_MODULE);
>> +#endif
>> +
>>         /* Now module is in final location, initialize linked lists, etc. */
>>         err = module_unload_init(mod);
>>         if (err)

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  2012-09-04 12:21     ` Kasatkin, Dmitry
@ 2012-09-04 13:40       ` Mimi Zohar
  0 siblings, 0 replies; 48+ messages in thread
From: Mimi Zohar @ 2012-09-04 13:40 UTC (permalink / raw)
  To: Kasatkin, Dmitry
  Cc: Rusty Russell, David Howells, jmorris, keyrings,
	linux-security-module, linux-kernel

On Tue, 2012-09-04 at 15:21 +0300, Kasatkin, Dmitry wrote:
> On Tue, Sep 4, 2012 at 3:07 PM, Kasatkin, Dmitry
> <dmitry.kasatkin@intel.com> wrote:
> > Hi,
> >
> > Please read bellow...
> >
> > On Tue, Sep 4, 2012 at 8:55 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> >> OK, I took a look at the module.c parts of David and Dmitry's patchsets,
> >> and didn't really like either, but I stole parts of David's to make
> >> this.
> >>
> >> So, here's the module.c part of module signing.  I hope you two got time
> >> to discuss the signature format details?  

The integrity subsystem currently defines 3 extended attribute formats
in security/integrity.h.

enum evm_ima_xattr_type {
        IMA_XATTR_DIGEST = 0x01,
        EVM_XATTR_HMAC,
        EVM_IMA_XATTR_DIGSIG,
};

integrity_digsig_verify() is called to appraise EVM signatures stored as
EVM_IMA_XATTR_DIGSIG.  In Dmitry's patches, this same call is used to
appraise modules.  If you decide to define a new format, it should be
included here as well.

> Mimi suggested a scheme where
> >> the private key would never be saved on disk (even temporarily), but I
> >> didn't see patches.  Frankly it's something we can do later; let's aim
> >> at getting the format right for the next merge window.

Right, the key is a build issue, which doesn't affect the format.

> > In our patches key is stored on the disc in encrypted format...

An updated version of Dmitry's patches are in the 'modsig' branch of
git://git.kernel.org/pub/scm/linux/kernel/git/kasatkin/linux-digsig. For
now, although commit 59f1d53 "modsig: build rules and scripts to
generate keys and sign modules" writes the ephemeral key to disk, it is
encrypted.

thanks,

Mimi


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  2012-09-04  5:55 ` [RFC] module: signature infrastructure Rusty Russell
  2012-09-04 12:07   ` Kasatkin, Dmitry
@ 2012-09-04 14:25   ` Lucas De Marchi
  2012-09-04 15:04     ` Kasatkin, Dmitry
  2012-09-05  0:19     ` Rusty Russell
  2012-09-04 22:51   ` David Howells
  2 siblings, 2 replies; 48+ messages in thread
From: Lucas De Marchi @ 2012-09-04 14:25 UTC (permalink / raw)
  To: Rusty Russell
  Cc: David Howells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Hi Rusty,

On Tue, Sep 4, 2012 at 2:55 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> OK, I took a look at the module.c parts of David and Dmitry's patchsets,
> and didn't really like either, but I stole parts of David's to make
> this.
>
> So, here's the module.c part of module signing.  I hope you two got time
> to discuss the signature format details?  Mimi suggested a scheme where
> the private key would never be saved on disk (even temporarily), but I
> didn't see patches.  Frankly it's something we can do later; let's aim
> at getting the format right for the next merge window.
>
> Cheers,
> Rusty.
>
> ---
> This patch doesn't compile: we need to implement:
>
>         int mod_verify_sig(const void *mod, unsigned long modlen,
>                            const void *sig, unsigned long siglen,
>                            bool *sig_ok);
>
> Also, we need to actually append the signatures during build.
>
> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> index ad7e2e5..9b2b8d3 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -1582,6 +1582,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
>                         log everything. Information is printed at KERN_DEBUG
>                         so loglevel=8 may also need to be specified.
>
> +       module.sig_enforce
> +                       [KNL] When CONFIG_MODULE_SIG is set, this means that
> +                       modules without (valid) signatures will fail to load.
> +                       Note that if CONFIG_MODULE_SIG_ENFORCE is set, that
> +                       is always true, so this option does nothing.
> +
>         mousedev.tap_time=
>                         [MOUSE] Maximum time between finger touching and
>                         leaving touchpad surface for touch to be considered
> diff --git a/include/linux/module.h b/include/linux/module.h
> index fbcafe2..7760c6d 100644
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -21,6 +21,9 @@
>  #include <linux/percpu.h>
>  #include <asm/module.h>
>
> +/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
> +#define MODULE_SIG_STRING "~Module signature appended~\n"
> +
>  /* Not Yet Implemented */
>  #define MODULE_SUPPORTED_DEVICE(name)
>
> @@ -260,6 +263,11 @@ struct module
>         const unsigned long *unused_gpl_crcs;
>  #endif
>
> +#ifdef CONFIG_MODULE_SIG
> +       /* Signature was verified. */
> +       bool sig_ok;
> +#endif
> +
>         /* symbols that will be GPL-only in the near future. */
>         const struct kernel_symbol *gpl_future_syms;
>         const unsigned long *gpl_future_crcs;
> diff --git a/init/Kconfig b/init/Kconfig
> index af6c7f8..7452e19 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -1585,6 +1585,20 @@ config MODULE_SRCVERSION_ALL
>           the version).  With this option, such a "srcversion" field
>           will be created for all modules.  If unsure, say N.
>
> +config MODULE_SIG
> +       bool "Module signature verification"
> +       depends on MODULES
> +       help
> +         Check modules for valid signatures upon load: the signature
> +         is simply appended to the module. For more information see
> +         Documentation/module-signing.txt.
> +
> +config MODULE_SIG_FORCE
> +       bool "Require modules to be validly signed"
> +       depends on MODULE_SIG
> +       help
> +         Reject unsigned modules or signed modules for which we don't have a
> +         key.  Without this, such modules will simply taint the kernel.
>  endif # MODULES
>
>  config INIT_ALL_POSSIBLE
> diff --git a/kernel/module.c b/kernel/module.c
> index 4edbd9c..3cbd1a4 100644
> --- a/kernel/module.c
> +++ b/kernel/module.c
> @@ -102,6 +102,43 @@ static LIST_HEAD(modules);
>  struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
>  #endif /* CONFIG_KGDB_KDB */
>
> +#ifdef CONFIG_MODULE_SIG
> +#ifdef CONFIG_MODULE_SIG_ENFORCE
> +static bool sig_enforce = true;
> +#else
> +static bool sig_enforce = false;
> +
> +static int param_set_bool_enable_only(const char *val,
> +                                     const struct kernel_param *kp)
> +{
> +       int err;
> +       bool test;
> +       struct kernel_param dummy_kp = *kp;
> +
> +       dummy_kp.arg = &test;
> +
> +       err = param_set_bool(val, &dummy_kp);
> +       if (err)
> +               return err;
> +
> +       /* Don't let them unset it once it's set! */
> +       if (!test && sig_enforce)
> +               return -EROFS;
> +
> +       if (test)
> +               sig_enforce = true;
> +       return 0;
> +}
> +
> +static const struct kernel_param_ops param_ops_bool_enable_only = {
> +       .set = param_set_bool_enable_only,
> +       .get = param_get_bool,
> +};
> +#define param_check_bool_enable_only param_check_bool
> +
> +module_param(sig_enforce, bool_enable_only, 0644);
> +#endif /* !CONFIG_MODULE_SIG_ENFORCE */
> +#endif /* CONFIG_MODULE_SIG */
>
>  /* Block module loading/unloading? */
>  int modules_disabled = 0;
> @@ -136,6 +173,7 @@ struct load_info {
>         unsigned long symoffs, stroffs;
>         struct _ddebug *debug;
>         unsigned int num_debug;
> +       bool sig_ok;
>         struct {
>                 unsigned int sym, str, mod, vers, info, pcpu;
>         } index;
> @@ -2399,7 +2437,50 @@ static inline void kmemleak_load_module(const struct module *mod,
>  }
>  #endif
>
> -/* Sets info->hdr and info->len. */
> +#ifdef CONFIG_MODULE_SIG
> +static int module_sig_check(struct load_info *info,
> +                           void *mod, unsigned long *len)
> +{
> +       int err;
> +       unsigned long i, siglen;
> +       char *sig = NULL;
> +
> +       /* This is not a valid module: ELF header is larger anyway. */
> +       if (*len < sizeof(MODULE_SIG_STRING))
> +               return -ENOEXEC;
> +
> +       for (i = 0; i < *len - (sizeof(MODULE_SIG_STRING)-1); i++) {
> +               /* Our memcmp is dumb, speed it up a little. */
> +               if (((char *)mod)[i] != MODULE_SIG_STRING[0])
> +                       continue;

Since the signature is appended to the module, why don't you go
backwards, starting from *len - strlen(sizeof(MODULE_SIG_STRING)) and
making this first comparison?

Or let the magic string as the last thing in the module and store the
signature length, too. In this case no scanning is needed


Lucas De Marchi


> +               if (memcmp(mod, MODULE_SIG_STRING, strlen(MODULE_SIG_STRING)))
> +                       continue;
> +
> +               sig = mod + i + strlen(MODULE_SIG_STRING);
> +               siglen = *len - i - strlen(MODULE_SIG_STRING);
> +               *len = i;
> +               break;
> +       }
> +
> +       if (!sig)
> +               err = 0;
> +       else
> +               err = mod_verify_sig(mod, len, sig, siglen, &info->sig_ok);
> +
> +       /* Not having a signature is only an error if we're strict. */
> +       if (!err && !info->sig_ok && sig_enforce)
> +               err = -EKEYREJECTED;
> +       return err;
> +}
> +#else /* !CONFIG_MODULE_SIG */
> +static int module_sig_check(struct load_info *info,
> +                           void *mod, unsigned long *len)
> +{
> +       return 0;
> +}
> +#endif /* !CONFIG_MODULE_SIG */
> +
> +/* Sets info->hdr, info->len and info->sig_ok. */
>  static int copy_and_check(struct load_info *info,
>                           const void __user *umod, unsigned long len,
>                           const char __user *uargs)
> @@ -2419,6 +2500,10 @@ static int copy_and_check(struct load_info *info,
>                 goto free_hdr;
>         }
>
> +       err = module_sig_check(info, hdr, &len);
> +       if (err)
> +               goto free_hdr;
> +
>         /* Sanity checks against insmoding binaries or wrong arch,
>            weird elf version */
>         if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
> @@ -2886,6 +2971,12 @@ static struct module *load_module(void __user *umod,
>                 goto free_copy;
>         }
>
> +#ifdef CONFIG_MODULE_SIG
> +       mod->sig_ok = info.sig_ok;
> +       if (!mod->sig_ok)
> +               add_taint_module(mod, TAINT_FORCED_MODULE);
> +#endif
> +
>         /* Now module is in final location, initialize linked lists, etc. */
>         err = module_unload_init(mod);
>         if (err)
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/



-- 

Lucas De Marchi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  2012-09-04 14:25   ` Lucas De Marchi
@ 2012-09-04 15:04     ` Kasatkin, Dmitry
  2012-09-05  0:19     ` Rusty Russell
  1 sibling, 0 replies; 48+ messages in thread
From: Kasatkin, Dmitry @ 2012-09-04 15:04 UTC (permalink / raw)
  To: Lucas De Marchi
  Cc: Rusty Russell, David Howells, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

On Tue, Sep 4, 2012 at 5:25 PM, Lucas De Marchi
<lucas.de.marchi@gmail.com> wrote:
> Hi Rusty,
>
> On Tue, Sep 4, 2012 at 2:55 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
>> OK, I took a look at the module.c parts of David and Dmitry's patchsets,
>> and didn't really like either, but I stole parts of David's to make
>> this.
>>
>> So, here's the module.c part of module signing.  I hope you two got time
>> to discuss the signature format details?  Mimi suggested a scheme where
>> the private key would never be saved on disk (even temporarily), but I
>> didn't see patches.  Frankly it's something we can do later; let's aim
>> at getting the format right for the next merge window.
>>
>> Cheers,
>> Rusty.
>>
>> ---
>> This patch doesn't compile: we need to implement:
>>
>>         int mod_verify_sig(const void *mod, unsigned long modlen,
>>                            const void *sig, unsigned long siglen,
>>                            bool *sig_ok);
>>
>> Also, we need to actually append the signatures during build.
>>
>> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
>> index ad7e2e5..9b2b8d3 100644
>> --- a/Documentation/kernel-parameters.txt
>> +++ b/Documentation/kernel-parameters.txt
>> @@ -1582,6 +1582,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
>>                         log everything. Information is printed at KERN_DEBUG
>>                         so loglevel=8 may also need to be specified.
>>
>> +       module.sig_enforce
>> +                       [KNL] When CONFIG_MODULE_SIG is set, this means that
>> +                       modules without (valid) signatures will fail to load.
>> +                       Note that if CONFIG_MODULE_SIG_ENFORCE is set, that
>> +                       is always true, so this option does nothing.
>> +
>>         mousedev.tap_time=
>>                         [MOUSE] Maximum time between finger touching and
>>                         leaving touchpad surface for touch to be considered
>> diff --git a/include/linux/module.h b/include/linux/module.h
>> index fbcafe2..7760c6d 100644
>> --- a/include/linux/module.h
>> +++ b/include/linux/module.h
>> @@ -21,6 +21,9 @@
>>  #include <linux/percpu.h>
>>  #include <asm/module.h>
>>
>> +/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
>> +#define MODULE_SIG_STRING "~Module signature appended~\n"
>> +
>>  /* Not Yet Implemented */
>>  #define MODULE_SUPPORTED_DEVICE(name)
>>
>> @@ -260,6 +263,11 @@ struct module
>>         const unsigned long *unused_gpl_crcs;
>>  #endif
>>
>> +#ifdef CONFIG_MODULE_SIG
>> +       /* Signature was verified. */
>> +       bool sig_ok;
>> +#endif
>> +
>>         /* symbols that will be GPL-only in the near future. */
>>         const struct kernel_symbol *gpl_future_syms;
>>         const unsigned long *gpl_future_crcs;
>> diff --git a/init/Kconfig b/init/Kconfig
>> index af6c7f8..7452e19 100644
>> --- a/init/Kconfig
>> +++ b/init/Kconfig
>> @@ -1585,6 +1585,20 @@ config MODULE_SRCVERSION_ALL
>>           the version).  With this option, such a "srcversion" field
>>           will be created for all modules.  If unsure, say N.
>>
>> +config MODULE_SIG
>> +       bool "Module signature verification"
>> +       depends on MODULES
>> +       help
>> +         Check modules for valid signatures upon load: the signature
>> +         is simply appended to the module. For more information see
>> +         Documentation/module-signing.txt.
>> +
>> +config MODULE_SIG_FORCE
>> +       bool "Require modules to be validly signed"
>> +       depends on MODULE_SIG
>> +       help
>> +         Reject unsigned modules or signed modules for which we don't have a
>> +         key.  Without this, such modules will simply taint the kernel.
>>  endif # MODULES
>>
>>  config INIT_ALL_POSSIBLE
>> diff --git a/kernel/module.c b/kernel/module.c
>> index 4edbd9c..3cbd1a4 100644
>> --- a/kernel/module.c
>> +++ b/kernel/module.c
>> @@ -102,6 +102,43 @@ static LIST_HEAD(modules);
>>  struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
>>  #endif /* CONFIG_KGDB_KDB */
>>
>> +#ifdef CONFIG_MODULE_SIG
>> +#ifdef CONFIG_MODULE_SIG_ENFORCE
>> +static bool sig_enforce = true;
>> +#else
>> +static bool sig_enforce = false;
>> +
>> +static int param_set_bool_enable_only(const char *val,
>> +                                     const struct kernel_param *kp)
>> +{
>> +       int err;
>> +       bool test;
>> +       struct kernel_param dummy_kp = *kp;
>> +
>> +       dummy_kp.arg = &test;
>> +
>> +       err = param_set_bool(val, &dummy_kp);
>> +       if (err)
>> +               return err;
>> +
>> +       /* Don't let them unset it once it's set! */
>> +       if (!test && sig_enforce)
>> +               return -EROFS;
>> +
>> +       if (test)
>> +               sig_enforce = true;
>> +       return 0;
>> +}
>> +
>> +static const struct kernel_param_ops param_ops_bool_enable_only = {
>> +       .set = param_set_bool_enable_only,
>> +       .get = param_get_bool,
>> +};
>> +#define param_check_bool_enable_only param_check_bool
>> +
>> +module_param(sig_enforce, bool_enable_only, 0644);
>> +#endif /* !CONFIG_MODULE_SIG_ENFORCE */
>> +#endif /* CONFIG_MODULE_SIG */
>>
>>  /* Block module loading/unloading? */
>>  int modules_disabled = 0;
>> @@ -136,6 +173,7 @@ struct load_info {
>>         unsigned long symoffs, stroffs;
>>         struct _ddebug *debug;
>>         unsigned int num_debug;
>> +       bool sig_ok;
>>         struct {
>>                 unsigned int sym, str, mod, vers, info, pcpu;
>>         } index;
>> @@ -2399,7 +2437,50 @@ static inline void kmemleak_load_module(const struct module *mod,
>>  }
>>  #endif
>>
>> -/* Sets info->hdr and info->len. */
>> +#ifdef CONFIG_MODULE_SIG
>> +static int module_sig_check(struct load_info *info,
>> +                           void *mod, unsigned long *len)
>> +{
>> +       int err;
>> +       unsigned long i, siglen;
>> +       char *sig = NULL;
>> +
>> +       /* This is not a valid module: ELF header is larger anyway. */
>> +       if (*len < sizeof(MODULE_SIG_STRING))
>> +               return -ENOEXEC;
>> +
>> +       for (i = 0; i < *len - (sizeof(MODULE_SIG_STRING)-1); i++) {
>> +               /* Our memcmp is dumb, speed it up a little. */
>> +               if (((char *)mod)[i] != MODULE_SIG_STRING[0])
>> +                       continue;
>
> Since the signature is appended to the module, why don't you go
> backwards, starting from *len - strlen(sizeof(MODULE_SIG_STRING)) and
> making this first comparison?
>
> Or let the magic string as the last thing in the module and store the
> signature length, too. In this case no scanning is needed
>
>
> Lucas De Marchi
>

This is exactly like that here...

http://git.kernel.org/?p=linux/kernel/git/kasatkin/linux-digsig.git;a=blob;f=security/integrity/module.c;h=b111bb400a248ab9b03a64ea373c88396f311649;hb=19eef6e4e529ccf2b3a6ab5c19dd40f2eaf8fcaf

- Dmitry

>
>> +               if (memcmp(mod, MODULE_SIG_STRING, strlen(MODULE_SIG_STRING)))
>> +                       continue;
>> +
>> +               sig = mod + i + strlen(MODULE_SIG_STRING);
>> +               siglen = *len - i - strlen(MODULE_SIG_STRING);
>> +               *len = i;
>> +               break;
>> +       }
>> +
>> +       if (!sig)
>> +               err = 0;
>> +       else
>> +               err = mod_verify_sig(mod, len, sig, siglen, &info->sig_ok);
>> +
>> +       /* Not having a signature is only an error if we're strict. */
>> +       if (!err && !info->sig_ok && sig_enforce)
>> +               err = -EKEYREJECTED;
>> +       return err;
>> +}
>> +#else /* !CONFIG_MODULE_SIG */
>> +static int module_sig_check(struct load_info *info,
>> +                           void *mod, unsigned long *len)
>> +{
>> +       return 0;
>> +}
>> +#endif /* !CONFIG_MODULE_SIG */
>> +
>> +/* Sets info->hdr, info->len and info->sig_ok. */
>>  static int copy_and_check(struct load_info *info,
>>                           const void __user *umod, unsigned long len,
>>                           const char __user *uargs)
>> @@ -2419,6 +2500,10 @@ static int copy_and_check(struct load_info *info,
>>                 goto free_hdr;
>>         }
>>
>> +       err = module_sig_check(info, hdr, &len);
>> +       if (err)
>> +               goto free_hdr;
>> +
>>         /* Sanity checks against insmoding binaries or wrong arch,
>>            weird elf version */
>>         if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
>> @@ -2886,6 +2971,12 @@ static struct module *load_module(void __user *umod,
>>                 goto free_copy;
>>         }
>>
>> +#ifdef CONFIG_MODULE_SIG
>> +       mod->sig_ok = info.sig_ok;
>> +       if (!mod->sig_ok)
>> +               add_taint_module(mod, TAINT_FORCED_MODULE);
>> +#endif
>> +
>>         /* Now module is in final location, initialize linked lists, etc. */
>>         err = module_unload_init(mod);
>>         if (err)
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/
>
>
>
> --
>
> Lucas De Marchi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  2012-09-04  5:55 ` [RFC] module: signature infrastructure Rusty Russell
  2012-09-04 12:07   ` Kasatkin, Dmitry
  2012-09-04 14:25   ` Lucas De Marchi
@ 2012-09-04 22:51   ` David Howells
  2012-09-04 23:17     ` Kasatkin, Dmitry
  2 siblings, 1 reply; 48+ messages in thread
From: David Howells @ 2012-09-04 22:51 UTC (permalink / raw)
  To: Lucas De Marchi
  Cc: dhowells, Rusty Russell, dmitry.kasatkin, zohar, jmorris,
	keyrings, linux-security-module, linux-kernel

Lucas De Marchi <lucas.de.marchi@gmail.com> wrote:

> Or let the magic string as the last thing in the module and store the
> signature length, too. In this case no scanning is needed

Indeed.  This is the better way.

The main problem is rendering the length from a shell script.  It's trivial to
do as ASCII (there's a printf program), but a pain to render to binary.  I'm
sure it can be done with perl or python without the need to compile anything.

David

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  2012-09-04 22:51   ` David Howells
@ 2012-09-04 23:17     ` Kasatkin, Dmitry
  0 siblings, 0 replies; 48+ messages in thread
From: Kasatkin, Dmitry @ 2012-09-04 23:17 UTC (permalink / raw)
  To: David Howells
  Cc: Lucas De Marchi, Rusty Russell, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

On Wed, Sep 5, 2012 at 1:51 AM, David Howells <dhowells@redhat.com> wrote:
> Lucas De Marchi <lucas.de.marchi@gmail.com> wrote:
>
>> Or let the magic string as the last thing in the module and store the
>> signature length, too. In this case no scanning is needed
>
> Indeed.  This is the better way.
>
> The main problem is rendering the length from a shell script.  It's trivial to
> do as ASCII (there's a printf program), but a pain to render to binary.  I'm
> sure it can be done with perl or python without the need to compile anything.
>
> David

That is very easy to do from script as well.
See script in my tree.

http://git.kernel.org/?p=linux/kernel/git/kasatkin/linux-digsig.git;a=blob;f=scripts/modsig.sh;h=4e997c3996d71d8e1afeb3a7afe23b3f303b9f63;hb=59f1d5352969166f2f32f84e07e20dd1b30a890f

110 # add signature length - big endian
111 dec2hex $(stat --printf %s $sigfile) 4 | hex2bin $sigfile
112 echo -n "This Is A Crypto Signed Module" >>$sigfile

well. I have couple of small functions in the script. dec2hex and hex2bin

- Dmitry

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  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
  1 sibling, 1 reply; 48+ messages in thread
From: Rusty Russell @ 2012-09-05  0:19 UTC (permalink / raw)
  To: Lucas De Marchi
  Cc: David Howells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Lucas De Marchi <lucas.de.marchi@gmail.com> writes:
> Hi Rusty,
>
> On Tue, Sep 4, 2012 at 2:55 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
>> @@ -2399,7 +2437,50 @@ static inline void kmemleak_load_module(const struct module *mod,
>>  }
>>  #endif
>>
>> -/* Sets info->hdr and info->len. */
>> +#ifdef CONFIG_MODULE_SIG
>> +static int module_sig_check(struct load_info *info,
>> +                           void *mod, unsigned long *len)
>> +{
>> +       int err;
>> +       unsigned long i, siglen;
>> +       char *sig = NULL;
>> +
>> +       /* This is not a valid module: ELF header is larger anyway. */
>> +       if (*len < sizeof(MODULE_SIG_STRING))
>> +               return -ENOEXEC;
>> +
>> +       for (i = 0; i < *len - (sizeof(MODULE_SIG_STRING)-1); i++) {
>> +               /* Our memcmp is dumb, speed it up a little. */
>> +               if (((char *)mod)[i] != MODULE_SIG_STRING[0])
>> +                       continue;
>
> Since the signature is appended to the module, why don't you go
> backwards, starting from *len - strlen(sizeof(MODULE_SIG_STRING)) and
> making this first comparison?

We've had this discussion multiple times.  Simple wins.  It's so
marginal, I don't really care, but I've changed it to:

	int err;
	unsigned long i, siglen, markerlen;
	char *sig = NULL;

	markerlen = strlen(MODULE_SIG_STRING);
	/* This is not a valid module: ELF header is larger anyway. */
	if (*len < markerlen)
		return -ENOEXEC;

	for (i = *len - markerlen; i > 0; i--) {
		/* Our memcmp is dumb, speed it up a little. */
		if (((char *)mod)[i] != MODULE_SIG_STRING[0])
			continue;
		if (memcmp(mod+i, MODULE_SIG_STRING, markerlen))
			continue;

		sig = mod + i + markerlen;
		siglen = *len - i - markerlen;
		*len = i;
		break;
	}

We could also implement memrchr(), or memrmem().  Hell, if we had
memmem() in the kernel I'd gladly use it.

> Or let the magic string as the last thing in the module and store the
> signature length, too. In this case no scanning is needed

Yes, they did that too, but append is simpler.  I don't even have to
think about endianness (Dmitry chose be32) or parsing (David chose
5-digit ascii numeric encoding).

Scanning the module is the least of our issues since we've just copied
it and we're about to SHA it.

Cheers,
Rusty.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  2012-09-04 12:07   ` Kasatkin, Dmitry
  2012-09-04 12:21     ` Kasatkin, Dmitry
@ 2012-09-05  0:29     ` Rusty Russell
  2012-09-05 13:34       ` Mimi Zohar
  1 sibling, 1 reply; 48+ messages in thread
From: Rusty Russell @ 2012-09-05  0:29 UTC (permalink / raw)
  To: Kasatkin, Dmitry
  Cc: David Howells, zohar, jmorris, keyrings, linux-security-module,
	linux-kernel

"Kasatkin, Dmitry" <dmitry.kasatkin@intel.com> writes:
> Hi,
>
> Please read bellow...
>
> On Tue, Sep 4, 2012 at 8:55 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
>> OK, I took a look at the module.c parts of David and Dmitry's patchsets,
>> and didn't really like either, but I stole parts of David's to make
>> this.
>>
>> So, here's the module.c part of module signing.  I hope you two got time
>> to discuss the signature format details?  Mimi suggested a scheme where
>> the private key would never be saved on disk (even temporarily), but I
>> didn't see patches.  Frankly it's something we can do later; let's aim
>> at getting the format right for the next merge window.
>
> In our patches key is stored on the disc in encrypted format...

Oh, I missed that twist.  Thanks for the explanation.

On consideration, I prefer signing to be the final part of the "modules"
target rather than modules_install.  I run the latter as root, and that
is wrong for doing any code generation.

>> +       for (i = 0; i < *len - (sizeof(MODULE_SIG_STRING)-1); i++) {
>> +               /* Our memcmp is dumb, speed it up a little. */
>> +               if (((char *)mod)[i] != MODULE_SIG_STRING[0])
>> +                       continue;
>> +               if (memcmp(mod, MODULE_SIG_STRING, strlen(MODULE_SIG_STRING)))
>
> should be (mod+i)?

Yes, indeed.  Thanks, fixed.

>> +                       continue;
>> +
>> +               sig = mod + i + strlen(MODULE_SIG_STRING);
>> +               siglen = *len - i - strlen(MODULE_SIG_STRING);
>> +               *len = i;
>> +               break;
>> +       }
>
> In general please clarify why do you need such parsing at all?
> Why not to have MODULE_SIG_STRING as a last octets of the module and
> have signature length field before?
> Then it is easy to get the signature and rest of the module?
> That will be super fast...
>
> Please clarify.

Ignore performance, it's just not an issue here.  So the simplest code
wins.

And it's also simpler to sign a module this way.

        (echo '~Module signature appended~'; gpg --sign ....) >> mod.ko

Cheers,
Rusty.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  2012-09-05  0:29     ` Rusty Russell
@ 2012-09-05 13:34       ` Mimi Zohar
  2012-09-06  2:05         ` Rusty Russell
  0 siblings, 1 reply; 48+ messages in thread
From: Mimi Zohar @ 2012-09-05 13:34 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Kasatkin, Dmitry, David Howells, jmorris, keyrings,
	linux-security-module, linux-kernel

On Wed, 2012-09-05 at 09:59 +0930, Rusty Russell wrote:
> "Kasatkin, Dmitry" <dmitry.kasatkin@intel.com> writes:
> > Hi,
> >
> > Please read bellow...
> >
> > On Tue, Sep 4, 2012 at 8:55 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> >> OK, I took a look at the module.c parts of David and Dmitry's patchsets,
> >> and didn't really like either, but I stole parts of David's to make
> >> this.
> >>
> >> So, here's the module.c part of module signing.  I hope you two got time
> >> to discuss the signature format details?  Mimi suggested a scheme where
> >> the private key would never be saved on disk (even temporarily), but I
> >> didn't see patches.  Frankly it's something we can do later; let's aim
> >> at getting the format right for the next merge window.
> >
> > In our patches key is stored on the disc in encrypted format...
> 
> Oh, I missed that twist.  Thanks for the explanation.
> 
> On consideration, I prefer signing to be the final part of the "modules"
> target rather than modules_install.  I run the latter as root, and that
> is wrong for doing any code generation.

Agreed, but keep in mind that 'modules_install' could subsequently strip
the module.

Mimi

> >> +       for (i = 0; i < *len - (sizeof(MODULE_SIG_STRING)-1); i++) {
> >> +               /* Our memcmp is dumb, speed it up a little. */
> >> +               if (((char *)mod)[i] != MODULE_SIG_STRING[0])
> >> +                       continue;
> >> +               if (memcmp(mod, MODULE_SIG_STRING, strlen(MODULE_SIG_STRING)))
> >
> > should be (mod+i)?
> 
> Yes, indeed.  Thanks, fixed.
> 
> >> +                       continue;
> >> +
> >> +               sig = mod + i + strlen(MODULE_SIG_STRING);
> >> +               siglen = *len - i - strlen(MODULE_SIG_STRING);
> >> +               *len = i;
> >> +               break;
> >> +       }
> >
> > In general please clarify why do you need such parsing at all?
> > Why not to have MODULE_SIG_STRING as a last octets of the module and
> > have signature length field before?
> > Then it is easy to get the signature and rest of the module?
> > That will be super fast...
> >
> > Please clarify.
> 
> Ignore performance, it's just not an issue here.  So the simplest code
> wins.
> 
> And it's also simpler to sign a module this way.
> 
>         (echo '~Module signature appended~'; gpg --sign ....) >> mod.ko
> 
> Cheers,
> Rusty.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 



^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  2012-09-05  0:19     ` Rusty Russell
@ 2012-09-05 23:41       ` Lucas De Marchi
  2012-09-06  7:55         ` Rusty Russell
  0 siblings, 1 reply; 48+ messages in thread
From: Lucas De Marchi @ 2012-09-05 23:41 UTC (permalink / raw)
  To: Rusty Russell
  Cc: David Howells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

On Tue, Sep 4, 2012 at 9:19 PM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> Lucas De Marchi <lucas.de.marchi@gmail.com> writes:
>> Hi Rusty,
>>
>> On Tue, Sep 4, 2012 at 2:55 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
>>> @@ -2399,7 +2437,50 @@ static inline void kmemleak_load_module(const struct module *mod,
>>>  }
>>>  #endif
>>>
>>> -/* Sets info->hdr and info->len. */
>>> +#ifdef CONFIG_MODULE_SIG
>>> +static int module_sig_check(struct load_info *info,
>>> +                           void *mod, unsigned long *len)
>>> +{
>>> +       int err;
>>> +       unsigned long i, siglen;
>>> +       char *sig = NULL;
>>> +
>>> +       /* This is not a valid module: ELF header is larger anyway. */
>>> +       if (*len < sizeof(MODULE_SIG_STRING))
>>> +               return -ENOEXEC;
>>> +
>>> +       for (i = 0; i < *len - (sizeof(MODULE_SIG_STRING)-1); i++) {
>>> +               /* Our memcmp is dumb, speed it up a little. */
>>> +               if (((char *)mod)[i] != MODULE_SIG_STRING[0])
>>> +                       continue;
>>
>> Since the signature is appended to the module, why don't you go
>> backwards, starting from *len - strlen(sizeof(MODULE_SIG_STRING)) and
>> making this first comparison?
>
> We've had this discussion multiple times.  Simple wins.  It's so
> marginal, I don't really care, but I've changed it to:

Sorry to come up with this suggestion only now (and after you have
already talked to me at LPC). Only after seeing this implementation I
thought about the implications of having the module signed in this
format.

I'm worried about performance here. Module loading can take a fair
amount of boot time. It may not be critical for servers or desktops
that we rarely boot, but it is for embedded uses.

>         int err;
>         unsigned long i, siglen, markerlen;
>         char *sig = NULL;
>
>         markerlen = strlen(MODULE_SIG_STRING);
>         /* This is not a valid module: ELF header is larger anyway. */
>         if (*len < markerlen)
>                 return -ENOEXEC;
>
>         for (i = *len - markerlen; i > 0; i--) {
>                 /* Our memcmp is dumb, speed it up a little. */
>                 if (((char *)mod)[i] != MODULE_SIG_STRING[0])
>                         continue;
>                 if (memcmp(mod+i, MODULE_SIG_STRING, markerlen))
>                         continue;
>
>                 sig = mod + i + markerlen;
>                 siglen = *len - i - markerlen;
>                 *len = i;
>                 break;
>         }
>
> We could also implement memrchr(), or memrmem().  Hell, if we had
> memmem() in the kernel I'd gladly use it.
>
>> Or let the magic string as the last thing in the module and store the
>> signature length, too. In this case no scanning is needed
>
> Yes, they did that too, but append is simpler.  I don't even have to
> think about endianness (Dmitry chose be32) or parsing (David chose
> 5-digit ascii numeric encoding).

Letting it in be32 is the simplest solution IMO. it's way simpler then
the loop above. You have to check exactly 1 byte to have a first
decision if module is not signed (as opposed to scanning the entire
module). Then you compare the memory area with MODULE_SIG_STRING and
have a final decision. To get the signature length it is just a matter
of converting it to host endiannes.  And we do have functions for
doing that. If it's for simplicity in kernel side, this one could be
implemented in half of the code above.

>
> Scanning the module is the least of our issues since we've just copied
> it and we're about to SHA it.

Yeah, but I don't think we need to scan it one more time. On every
boot. For every module


Lucas De Marchi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  2012-09-05 13:34       ` Mimi Zohar
@ 2012-09-06  2:05         ` Rusty Russell
  0 siblings, 0 replies; 48+ messages in thread
From: Rusty Russell @ 2012-09-06  2:05 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Kasatkin, Dmitry, David Howells, jmorris, keyrings,
	linux-security-module, linux-kernel

Mimi Zohar <zohar@linux.vnet.ibm.com> writes:

> On Wed, 2012-09-05 at 09:59 +0930, Rusty Russell wrote:
>> "Kasatkin, Dmitry" <dmitry.kasatkin@intel.com> writes:
>> > Hi,
>> >
>> > Please read bellow...
>> >
>> > On Tue, Sep 4, 2012 at 8:55 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
>> >> OK, I took a look at the module.c parts of David and Dmitry's patchsets,
>> >> and didn't really like either, but I stole parts of David's to make
>> >> this.
>> >>
>> >> So, here's the module.c part of module signing.  I hope you two got time
>> >> to discuss the signature format details?  Mimi suggested a scheme where
>> >> the private key would never be saved on disk (even temporarily), but I
>> >> didn't see patches.  Frankly it's something we can do later; let's aim
>> >> at getting the format right for the next merge window.
>> >
>> > In our patches key is stored on the disc in encrypted format...
>> 
>> Oh, I missed that twist.  Thanks for the explanation.
>> 
>> On consideration, I prefer signing to be the final part of the "modules"
>> target rather than modules_install.  I run the latter as root, and that
>> is wrong for doing any code generation.
>
> Agreed, but keep in mind that 'modules_install' could subsequently strip
> the module.

That had better be part of your signing step then!

Cheers,
Rusty.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [RFC] module: signature infrastructure
  2012-09-05 23:41       ` Lucas De Marchi
@ 2012-09-06  7:55         ` Rusty Russell
  0 siblings, 0 replies; 48+ messages in thread
From: Rusty Russell @ 2012-09-06  7:55 UTC (permalink / raw)
  To: Lucas De Marchi
  Cc: David Howells, dmitry.kasatkin, zohar, jmorris, keyrings,
	linux-security-module, linux-kernel

Lucas De Marchi <lucas.de.marchi@gmail.com> writes:
> Sorry to come up with this suggestion only now (and after you have
> already talked to me at LPC). Only after seeing this implementation I
> thought about the implications of having the module signed in this
> format.
...
> I'm worried about performance here. Module loading can take a fair
> amount of boot time. It may not be critical for servers or desktops
> that we rarely boot, but it is for embedded uses.
...
> Letting it in be32 is the simplest solution IMO. it's way simpler then
> the loop above.
...
>> Scanning the module is the least of our issues since we've just copied
>> it and we're about to SHA it.
>
> Yeah, but I don't think we need to scan it one more time. On every
> boot. For every module

Regretfully, I don't have Linus' talent for flamage.

There's no measurable performance impact.  Scanning 1k takes about
5usec; we've wasted about enough time on this subject to load a billion
kernel modules.

I know this.  Not because I'm brilliant, but because I *measured* it.  I
even pulled out my original module signature signing check code, and
that was both faster and simpler.  See below.

Your assertion that the length-prepended version is "way simpler" is
wrong.  Again, I know this because I *read the code*:

        https://git.kernel.org/?p=linux/kernel/git/kasatkin/linux-digsig.git;a=commitdiff;h=19eef6e4e529ccf2b3a6ab5c19dd40f2eaf8fcaf

Don't send any more lazy, unthoughtful mails to the list.  It's
disrespectful and makes me grumpy.

Rusty.
PS.  Pushed updated version to my kernel.org linux.git/module-signing branch.

#ifdef CONFIG_MODULE_SIG
static int module_sig_check(struct load_info *info,
			    const void *mod, unsigned long *len)
{
	int err = 0;
	const unsigned long markerlen = strlen(MODULE_SIG_STRING);
	const void *p = mod, *end = mod + *len;

	/* Poor man's memmem. */
	while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) {
		if (p + markerlen > end)
			break;

		if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) {
			const void *sig = p + markerlen;
			/* Truncate module up to signature. */
			*len = p - mod;
			err = mod_verify_sig(mod, *len,
					     sig, end - sig,
					     &info->sig_ok);
			break;
		}
		p++;
	}

	/* Not having a signature is only an error if we're strict. */
	if (!err && !info->sig_ok && sig_enforce)
		err = -EKEYREJECTED;
	return err;
}

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 02/25] MPILIB: Provide count_leading/trailing_zeros() based on arch functions
  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
  0 siblings, 1 reply; 48+ messages in thread
From: Kasatkin, Dmitry @ 2012-09-10  7:13 UTC (permalink / raw)
  To: David Howells, James Morris
  Cc: rusty, zohar, keyrings, linux-security-module, linux-kernel

On Thu, Aug 16, 2012 at 4:34 AM, David Howells <dhowells@redhat.com> wrote:
> Provide count_leading/trailing_zeros() macros based on extant arch bit scanning
> functions rather than reimplementing from scratch in MPILIB.
>
> Whilst we're at it, turn count_foo_zeros(n, x) into n = count_foo_zeros(x).
>
> Also move the definition to asm-generic as other people may be interested in
> using it.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> Cc: David S. Miller <davem@davemloft.net>
> Cc: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
> Cc: Arnd Bergmann <arnd@arndb.com>

Hi James,

Can you please apply this?


Acked-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>


> ---
>
>  include/asm-generic/bitops/count_zeros.h |   57 ++++++++++++
>  lib/mpi/longlong.h                       |  138 ------------------------------
>  lib/mpi/mpi-bit.c                        |    2
>  lib/mpi/mpi-pow.c                        |    4 -
>  4 files changed, 62 insertions(+), 139 deletions(-)
>  create mode 100644 include/asm-generic/bitops/count_zeros.h
>
>
> diff --git a/include/asm-generic/bitops/count_zeros.h b/include/asm-generic/bitops/count_zeros.h
> new file mode 100644
> index 0000000..97520d2
> --- /dev/null
> +++ b/include/asm-generic/bitops/count_zeros.h
> @@ -0,0 +1,57 @@
> +/* Count leading and trailing zeros functions
> + *
> + * Copyright (C) 2012 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.
> + */
> +
> +#ifndef _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
> +#define _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
> +
> +#include <asm/bitops.h>
> +
> +/**
> + * count_leading_zeros - Count the number of zeros from the MSB back
> + * @x: The value
> + *
> + * Count the number of leading zeros from the MSB going towards the LSB in @x.
> + *
> + * If the MSB of @x is set, the result is 0.
> + * If only the LSB of @x is set, then the result is BITS_PER_LONG-1.
> + * If @x is 0 then the result is COUNT_LEADING_ZEROS_0.
> + */
> +static inline int count_leading_zeros(unsigned long x)
> +{
> +       if (sizeof(x) == 4)
> +               return BITS_PER_LONG - fls(x);
> +       else
> +               return BITS_PER_LONG - fls64(x);
> +}
> +
> +#define COUNT_LEADING_ZEROS_0 BITS_PER_LONG
> +
> +/**
> + * count_trailing_zeros - Count the number of zeros from the LSB forwards
> + * @x: The value
> + *
> + * Count the number of trailing zeros from the LSB going towards the MSB in @x.
> + *
> + * If the LSB of @x is set, the result is 0.
> + * If only the MSB of @x is set, then the result is BITS_PER_LONG-1.
> + * If @x is 0 then the result is COUNT_TRAILING_ZEROS_0.
> + */
> +static inline int count_trailing_zeros(unsigned long x)
> +{
> +#define COUNT_TRAILING_ZEROS_0 (-1)
> +
> +       if (sizeof(x) == 4)
> +               return ffs(x);
> +       else
> +               return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0;
> +}
> +
> +#endif /* _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ */
> diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h
> index 29f9862..678ce4f 100644
> --- a/lib/mpi/longlong.h
> +++ b/lib/mpi/longlong.h
> @@ -19,6 +19,8 @@
>   * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
>   * MA 02111-1307, USA. */
>
> +#include <asm-generic/bitops/count_zeros.h>
> +
>  /* You have to define the following before including this file:
>   *
>   * UWtype -- An unsigned type, default type for operations (typically a "word")
> @@ -146,12 +148,6 @@ do { \
>         : "1" ((USItype)(n1)), \
>                 "r" ((USItype)(n0)), \
>                 "r" ((USItype)(d)))
> -
> -#define count_leading_zeros(count, x) \
> -       __asm__ ("clz %0,%1" \
> -       : "=r" ((USItype)(count)) \
> -       : "r" ((USItype)(x)))
> -#define COUNT_LEADING_ZEROS_0 32
>  #endif /* __a29k__ */
>
>  #if defined(__alpha) && W_TYPE_SIZE == 64
> @@ -298,11 +294,6 @@ extern UDItype __udiv_qrnnd();
>         : "1" ((USItype)(nh)), \
>                 "0" ((USItype)(nl)), \
>                 "g" ((USItype)(d)))
> -#define count_leading_zeros(count, x) \
> -       __asm__ ("bsch/1 %1,%0" \
> -       : "=g" (count) \
> -       : "g" ((USItype)(x)), \
> -            "0" ((USItype)0))
>  #endif
>
>  /***************************************
> @@ -354,27 +345,6 @@ do { USItype __r; \
>  } while (0)
>  extern USItype __udiv_qrnnd();
>  #endif /* LONGLONG_STANDALONE */
> -#define count_leading_zeros(count, x) \
> -do { \
> -       USItype __tmp; \
> -       __asm__ ( \
> -       "ldi             1,%0\n" \
> -       "extru,=        %1,15,16,%%r0  ; Bits 31..16 zero?\n" \
> -       "extru,tr       %1,15,16,%1    ; No.  Shift down, skip add.\n" \
> -       "ldo            16(%0),%0      ; Yes.   Perform add.\n" \
> -       "extru,=        %1,23,8,%%r0   ; Bits 15..8 zero?\n" \
> -       "extru,tr       %1,23,8,%1     ; No.  Shift down, skip add.\n" \
> -       "ldo            8(%0),%0       ; Yes.   Perform add.\n" \
> -       "extru,=        %1,27,4,%%r0   ; Bits 7..4 zero?\n" \
> -       "extru,tr       %1,27,4,%1     ; No.  Shift down, skip add.\n" \
> -       "ldo            4(%0),%0       ; Yes.   Perform add.\n" \
> -       "extru,=        %1,29,2,%%r0   ; Bits 3..2 zero?\n" \
> -       "extru,tr       %1,29,2,%1     ; No.  Shift down, skip add.\n" \
> -       "ldo            2(%0),%0       ; Yes.   Perform add.\n" \
> -       "extru          %1,30,1,%1     ; Extract bit 1.\n" \
> -       "sub            %0,%1,%0       ; Subtract it.              " \
> -       : "=r" (count), "=r" (__tmp) : "1" (x)); \
> -} while (0)
>  #endif /* hppa */
>
>  /***************************************
> @@ -457,15 +427,6 @@ do { \
>         : "0" ((USItype)(n0)), \
>              "1" ((USItype)(n1)), \
>              "rm" ((USItype)(d)))
> -#define count_leading_zeros(count, x) \
> -do { \
> -       USItype __cbtmp; \
> -       __asm__ ("bsrl %1,%0" \
> -       : "=r" (__cbtmp) : "rm" ((USItype)(x))); \
> -       (count) = __cbtmp ^ 31; \
> -} while (0)
> -#define count_trailing_zeros(count, x) \
> -       __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x)))
>  #ifndef UMUL_TIME
>  #define UMUL_TIME 40
>  #endif
> @@ -536,15 +497,6 @@ do { \
>              "dI" ((USItype)(d))); \
>         (r) = __rq.__i.__l; (q) = __rq.__i.__h; \
>  } while (0)
> -#define count_leading_zeros(count, x) \
> -do { \
> -       USItype __cbtmp; \
> -       __asm__ ("scanbit %1,%0" \
> -       : "=r" (__cbtmp) \
> -       : "r" ((USItype)(x))); \
> -       (count) = __cbtmp ^ 31; \
> -} while (0)
> -#define COUNT_LEADING_ZEROS_0 (-32)    /* sic */
>  #if defined(__i960mx)          /* what is the proper symbol to test??? */
>  #define rshift_rhlc(r, h, l, c) \
>  do { \
> @@ -603,11 +555,6 @@ do { \
>         : "0" ((USItype)(n0)), \
>              "1" ((USItype)(n1)), \
>              "dmi" ((USItype)(d)))
> -#define count_leading_zeros(count, x) \
> -       __asm__ ("bfffo %1{%b2:%b2},%0" \
> -       : "=d" ((USItype)(count)) \
> -       : "od" ((USItype)(x)), "n" (0))
> -#define COUNT_LEADING_ZEROS_0 32
>  #else /* not mc68020 */
>  #define umul_ppmm(xh, xl, a, b) \
>  do { USItype __umul_tmp1, __umul_tmp2; \
> @@ -664,15 +611,6 @@ do { USItype __umul_tmp1, __umul_tmp2; \
>              "rJ" ((USItype)(bh)), \
>              "rJ" ((USItype)(al)), \
>              "rJ" ((USItype)(bl)))
> -#define count_leading_zeros(count, x) \
> -do { \
> -       USItype __cbtmp; \
> -       __asm__ ("ff1 %0,%1" \
> -       : "=r" (__cbtmp) \
> -       : "r" ((USItype)(x))); \
> -       (count) = __cbtmp ^ 31; \
> -} while (0)
> -#define COUNT_LEADING_ZEROS_0 63       /* sic */
>  #if defined(__m88110__)
>  #define umul_ppmm(wh, wl, u, v) \
>  do { \
> @@ -779,12 +717,6 @@ do { \
>         : "0" (__xx.__ll), \
>              "g" ((USItype)(d))); \
>         (r) = __xx.__i.__l; (q) = __xx.__i.__h; })
> -#define count_trailing_zeros(count, x) \
> -do { \
> -       __asm__("ffsd      %2,%0" \
> -       : "=r"((USItype) (count)) \
> -       : "0"((USItype) 0), "r"((USItype) (x))); \
> -       } while (0)
>  #endif /* __ns32000__ */
>
>  /***************************************
> @@ -855,11 +787,6 @@ do { \
>                 "rI" ((USItype)(al)), \
>                 "r" ((USItype)(bl))); \
>  } while (0)
> -#define count_leading_zeros(count, x) \
> -       __asm__ ("{cntlz|cntlzw} %0,%1" \
> -       : "=r" ((USItype)(count)) \
> -       : "r" ((USItype)(x)))
> -#define COUNT_LEADING_ZEROS_0 32
>  #if defined(_ARCH_PPC)
>  #define umul_ppmm(ph, pl, m0, m1) \
>  do { \
> @@ -1001,19 +928,6 @@ do { \
>  } while (0)
>  #define UMUL_TIME 20
>  #define UDIV_TIME 200
> -#define count_leading_zeros(count, x) \
> -do { \
> -       if ((x) >= 0x10000) \
> -               __asm__ ("clz     %0,%1" \
> -               : "=r" ((USItype)(count)) \
> -               : "r" ((USItype)(x) >> 16)); \
> -       else { \
> -               __asm__ ("clz   %0,%1" \
> -               : "=r" ((USItype)(count)) \
> -               : "r" ((USItype)(x))); \
> -               (count) += 16; \
> -       } \
> -} while (0)
>  #endif /* RT/ROMP */
>
>  /***************************************
> @@ -1142,13 +1056,6 @@ do { \
>         "rI" ((USItype)(d)) \
>         : "%g1" __AND_CLOBBER_CC)
>  #define UDIV_TIME 37
> -#define count_leading_zeros(count, x) \
> -       __asm__ ("scan %1,0,%0" \
> -       : "=r" ((USItype)(x)) \
> -       : "r" ((USItype)(count)))
> -/* Early sparclites return 63 for an argument of 0, but they warn that future
> -       implementations might change this.  Therefore, leave COUNT_LEADING_ZEROS_0
> -       undefined.  */
>  #endif /* __sparclite__ */
>  #endif /* __sparc_v8__ */
>         /* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd.  */
> @@ -1454,47 +1361,6 @@ do { \
>  #define udiv_qrnnd __udiv_qrnnd_c
>  #endif
>
> -#undef count_leading_zeros
> -#if !defined(count_leading_zeros)
> -       extern
> -#ifdef __STDC__
> -                       const
> -#endif
> -                       unsigned char __clz_tab[];
> -#define count_leading_zeros(count, x) \
> -do { \
> -       UWtype __xr = (x); \
> -       UWtype __a; \
> -       \
> -       if (W_TYPE_SIZE <= 32) { \
> -               __a = __xr < ((UWtype) 1 << 2*__BITS4) \
> -               ? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \
> -               : (__xr < ((UWtype) 1 << 3*__BITS4) ?  2*__BITS4 : 3*__BITS4); \
> -       } \
> -       else { \
> -               for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \
> -                       if (((__xr >> __a) & 0xff) != 0) \
> -                               break; \
> -       } \
> -       \
> -       (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \
> -} while (0)
> -       /* This version gives a well-defined value for zero. */
> -#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE
> -#endif
> -
> -#if !defined(count_trailing_zeros)
> -/* Define count_trailing_zeros using count_leading_zeros.  The latter might be
> -       defined in asm, but if it is not, the C version above is good enough.  */
> -#define count_trailing_zeros(count, x) \
> -do { \
> -       UWtype __ctz_x = (x); \
> -       UWtype __ctz_c; \
> -       count_leading_zeros(__ctz_c, __ctz_x & -__ctz_x); \
> -       (count) = W_TYPE_SIZE - 1 - __ctz_c; \
> -} while (0)
> -#endif
> -
>  #ifndef UDIV_NEEDS_NORMALIZATION
>  #define UDIV_NEEDS_NORMALIZATION 0
>  #endif
> diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c
> index 5687248..503537e 100644
> --- a/lib/mpi/mpi-bit.c
> +++ b/lib/mpi/mpi-bit.c
> @@ -45,7 +45,7 @@ unsigned mpi_get_nbits(MPI a)
>         if (a->nlimbs) {
>                 mpi_limb_t alimb = a->d[a->nlimbs - 1];
>                 if (alimb)
> -                       count_leading_zeros(n, alimb);
> +                       n = count_leading_zeros(alimb);
>                 else
>                         n = BITS_PER_MPI_LIMB;
>                 n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB;
> diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c
> index 67f3e79..5464c87 100644
> --- a/lib/mpi/mpi-pow.c
> +++ b/lib/mpi/mpi-pow.c
> @@ -77,7 +77,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod)
>         mp = mp_marker = mpi_alloc_limb_space(msize);
>         if (!mp)
>                 goto enomem;
> -       count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]);
> +       mod_shift_cnt = count_leading_zeros(mod->d[msize - 1]);
>         if (mod_shift_cnt)
>                 mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt);
>         else
> @@ -169,7 +169,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod)
>
>                 i = esize - 1;
>                 e = ep[i];
> -               count_leading_zeros(c, e);
> +               c = count_leading_zeros(e);
>                 e = (e << c) << 1;      /* shift the exp bits to the left, lose msb */
>                 c = BITS_PER_MPI_LIMB - 1 - c;
>
>

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 02/25] MPILIB: Provide count_leading/trailing_zeros() based on arch functions
  2012-09-10  7:13   ` Kasatkin, Dmitry
@ 2012-09-13  5:14     ` James Morris
  2012-09-13 14:09       ` Kasatkin, Dmitry
  0 siblings, 1 reply; 48+ messages in thread
From: James Morris @ 2012-09-13  5:14 UTC (permalink / raw)
  To: Kasatkin, Dmitry
  Cc: David Howells, rusty, zohar, keyrings, linux-security-module,
	linux-kernel

On Mon, 10 Sep 2012, Kasatkin, Dmitry wrote:

> > Signed-off-by: David Howells <dhowells@redhat.com>
> > Cc: David S. Miller <davem@davemloft.net>
> > Cc: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
> > Cc: Arnd Bergmann <arnd@arndb.com>
> 
> Hi James,
> 
> Can you please apply this?

Could you send me this and any other outstanding changes as patches 
against my -next branch, tested and signed-off ?

Or, perhaps Mimi could do that as maintainer of the integrity subsystem.


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 02/25] MPILIB: Provide count_leading/trailing_zeros() based on arch functions
  2012-09-13  5:14     ` James Morris
@ 2012-09-13 14:09       ` Kasatkin, Dmitry
  0 siblings, 0 replies; 48+ messages in thread
From: Kasatkin, Dmitry @ 2012-09-13 14:09 UTC (permalink / raw)
  To: James Morris
  Cc: David Howells, rusty, zohar, keyrings, linux-security-module,
	linux-kernel

O

On Thu, Sep 13, 2012 at 8:14 AM, James Morris <jmorris@namei.org> wrote:
> On Mon, 10 Sep 2012, Kasatkin, Dmitry wrote:
>
>> > Signed-off-by: David Howells <dhowells@redhat.com>
>> > Cc: David S. Miller <davem@davemloft.net>
>> > Cc: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
>> > Cc: Arnd Bergmann <arnd@arndb.com>
>>
>> Hi James,
>>
>> Can you please apply this?
>
> Could you send me this and any other outstanding changes as patches
> against my -next branch, tested and signed-off ?
>
> Or, perhaps Mimi could do that as maintainer of the integrity subsystem.
>
>

Ok. let's do it with other collection of patches...

> - James
> --
> James Morris
> <jmorris@namei.org>

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2012-09-13 14:09 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH 04/25] KEYS: Add signature verification facility David Howells
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).