Skip to contentSkip to conversation

Asymmetric keys and module signing

GIT PULL In review David Howells 12 participants 47 messages Sep 25, 2012 – Mar 19, 2013

Subsystems (5)
lore
Share & tools
lore

David Howells

author maintainer
#0 lore raw

Hi Herbert, Rusty,

Here are my latest module signing patches on top of the asymmetric key crypto patches, which I hope Herbert will consider taking, at least from the crypto-keys-post-KS branch:

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

The module signing patches go on top of those, and the set can be found here:

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

Do you want the patches posting to the lists? I've tried posting the series as one, but there seems to be a problem posting the merge commit in the middle because it has two parents:-/

Anyway...

The module signing patches provide:

- Some fixes to Rusty's patch. Also an additional patch to extend the policy handling for modules signed with an unknown key and to handle FIPS mode.

- Module signature generation and checking. The signature format is:

	<signer-id-string>
	<binary-key-id>
	<binary-signature>
	<sig-information-block>

The fixed-length sig-information-block indicates the crypto algorithm (RSA only for the moment), the hash type (SHA512 for example) and the identifier scope (X.509 in this case), plus the lengths of the other three parts.

The binary-key-id could be rendered as hex and pasted onto the end of the signer-id-string so that the kernel doesn't have to do the conversion.

A script is provided in one of the patches to generate the signer name and key ID parts from the X.509 cert for later inclusion in module signatures during the build.

- A transient X.509 cert will be automatically generated if one is not given and will be used to automatically sign the modules after they've been thoroughly stripped.

Note that this may prove not to be the best way for distributions to do things. We're currently looking at the best way being to do the stripping and signing manually from the RPM spec file after the make modules_install step and after the debuginfo has been extracted, so automatic signing may need to go away, or at least become optional.

To make this easier, a script is provided to sign a module and this can be called either from the Makefile or the spec file.

- An 'extra_certificates' file can be placed in the root of the kernel build containing a number of supplementary X.509 certs just cat'd together. These will get added to the internal keyring and can then be used to check module signatures also.

I have also fixed a number of things in the crypto patches:

- GeneralizedTime and GeneralString were transposed in the ASN.1 compiler directive table and enum token_type ('S' comes before 'i' to strcmp()), resulting in it not being possible to use either.

- I had made it a requirement that the X.509 certificate subjectKeyIdentifier and authorityKeyIdentifier extensions exist so that we can validate the X.509 signature if possible, but I hadn't put in any checks that they'd been found before using the values extracted, leading to a crash.

- I fixed header length computation in ASN.1 decoder resulting making it possible to discard one of the x509.asn1 callback actions (we can locate the start of the TBS container directly now by subtraction).

- I got rid of the fingerprint bit at the end of the public_key struct as it's superfluous (the asymmetric key type stores the fingerprint attached to key->type_data.p[1]).

- I made the X.509 parser render the key description in a more compact manner:

The description is split into two parts: "<signer>: <key-id>".

The <key-id> is a hex rendering of the key identifier - in the case of X.509 that would be the contents of the subjectKeyIdentifier extension field with the ASN.1 OctetString wrapper removed.

The <signer> is (in order) one of:

- The O and CN attributes as "<O-attr>: <CN-attr>" if the CN attribute isn't prefixed with the O attribute, and, if longer, doesn't share the same first seven chars (say a company name such as Red Hat Inc.). I admit this is entirely arbitrary and biased towards companies with 7 chars or more in there name, but it does remove duplication of the organisation's name if it's in both the O and the CN. Can anyone suggest a better heuristic?

- The CN attribute.

- The O attribute.

- The email address.

- Omitted (with ": " omitted too).

As an example:

	Magrathea: Glacier signing key: 5dd0839552bd6af498253f8af1e65da3472941c6

which is "<O-attr>: <CN-attr>: <key-id>" in form, or:

	Red Hat Test Certificate: 3580cf35d76b3b667a40df66691cbcf87353b23c

which is just "<CN-attr>: <key-id>" in form.

- I no longer extract the bits of the X.509 certificate I don't currently use (such as the version number).

Note, this implementation of the X.509 certificate parser uses a couple of patterns to drive a reusable ASN.1 decoder. I do, however, have a direct in-line decoder implementation also that can only decode X.509 certs. The stack space usage is greater, but the code size is simpler and slightly smaller and the code is less capable (it can't handle indefinite-length elements for example), and it can't be reused for anything else (such as CIFS, netfilter, PKCS#7, Kerberos tickets), whereas the pattern-based decoder can. I'll post this separately to see what people think.

As far as testing goes, I have posted a number of testing scripts that I have used to punish the crypto keys side of things. The "keyctl padd" command makes this straightforward.

Hopefully, later this week the patches will appear in the Fedora 18 kernel.

David
---
The following changes since commit eeea3ac912207dcf759b95b2b4c36f96bce583bf:

Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc (2012-09-06 10:23:58 -0700)

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-modsign.git modsign-post-KS

for you to fetch changes up to 8d4f62638e9aae069d1145dfeb7300c58077be49:

MODSIGN: Extend the policy on signature check failure (2012-09-24 20:51:59 +0100)

----------------------------------------------------------------
(from the branch description for modsign-post-KS local branch)

post Kernel-Summit module signing
----------------------------------------------------------------
David Howells (26):
KEYS: Add payload preparsing opportunity prior to key instantiate or update
MPILIB: Provide count_leading/trailing_zeros() based on arch functions
KEYS: Document asymmetric key type
KEYS: Implement asymmetric key type
KEYS: Asymmetric key pluggable data parsers
KEYS: Asymmetric public-key algorithm crypto key subtype
KEYS: Provide signature verification with an asymmetric key
MPILIB: Reinstate mpi_cmp[_ui]() and export for RSA signature verification
RSA: Implement signature verification algorithm [PKCS#1 / RFC3447]
RSA: Fix signature verification for shorter signatures
X.509: Implement simple static OID registry
X.509: Add utility functions to render OIDs as strings
X.509: Add simple ASN.1 grammar compiler
X.509: Add an ASN.1 decoder
MPILIB: Provide a function to read raw data into an MPI
X.509: Add a crypto key parser for binary (DER) X.509 certificates Merge Rusty's module signature checking hook into modsign-post-KS
MOD: Fix Rusty's module_sig_check()
MODSIGN: Provide gitignore and make clean rules for extra files
MODSIGN: Provide Kconfig options
MODSIGN: Automatically generate module signing keys if missing
MODSIGN: Provide module signing public keys to the kernel
MODSIGN: Implement module signature checking
MODSIGN: Provide a script for generating a key ID from an X.509 cert
MODSIGN: Sign modules during the build process
MODSIGN: Extend the policy on signature check failure

Rusty Russell (1):
module: signature checking hook

 .gitignore                                |   13 +
 Documentation/crypto/asymmetric-keys.txt  |  312 ++++++
 Documentation/kernel-parameters.txt       |    6 +
 Documentation/security/keys.txt           |   50 +-
 Makefile                                  |    1 +
 crypto/Kconfig                            |    1 +
 crypto/Makefile                           |    1 +
 crypto/asymmetric_keys/.gitignore         |    1 +
 crypto/asymmetric_keys/Kconfig            |   38 +
 crypto/asymmetric_keys/Makefile           |   27 +
 crypto/asymmetric_keys/asymmetric_keys.h  |   15 +
 crypto/asymmetric_keys/asymmetric_type.c  |  274 +++++
 crypto/asymmetric_keys/public_key.c       |  108 ++
 crypto/asymmetric_keys/public_key.h       |   30 +
 crypto/asymmetric_keys/rsa.c              |  277 ++++++
 crypto/asymmetric_keys/signature.c        |   49 +
 crypto/asymmetric_keys/x509.asn1          |   60 ++
 crypto/asymmetric_keys/x509_cert_parser.c |  497 ++++++++++
 crypto/asymmetric_keys/x509_parser.h      |   36 +
 crypto/asymmetric_keys/x509_public_key.c  |  207 ++++
 crypto/asymmetric_keys/x509_rsakey.asn1   |    4 +
 fs/cifs/cifs_spnego.c                     |    6 +-
 fs/cifs/cifsacl.c                         |    8 +-
 include/asm-generic/bitops/count_zeros.h  |   57 ++
 include/crypto/public_key.h               |  108 ++
 include/keys/asymmetric-parser.h          |   37 +
 include/keys/asymmetric-subtype.h         |   55 +
 include/keys/asymmetric-type.h            |   25 +
 include/keys/user-type.h                  |    6 +-
 include/linux/asn1.h                      |   67 ++
 include/linux/asn1_ber_bytecode.h         |   87 ++
 include/linux/asn1_decoder.h              |   24 +
 include/linux/key-type.h                  |   35 +-
 include/linux/module.h                    |    8 +
 include/linux/mpi.h                       |    1 +
 include/linux/oid_registry.h              |   92 ++
 init/Kconfig                              |   68 ++
 kernel/Makefile                           |   57 ++
 kernel/modsign_pubkey.c                   |  112 +++
 kernel/module-internal.h                  |   16 +
 kernel/module.c                           |  100 +-
 kernel/module_signing.c                   |  247 +++++
 lib/.gitignore                            |    2 +-
 lib/Kconfig                               |    5 +
 lib/Makefile                              |   18 +
 lib/asn1_decoder.c                        |  477 +++++++++
 lib/build_OID_registry                    |  209 ++++
 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 +-
 lib/mpi/mpicoder.c                        |   55 +
 lib/oid_registry.c                        |  170 ++++
 net/ceph/crypto.c                         |    9 +-
 net/dns_resolver/dns_key.c                |    6 +-
 net/rxrpc/ar-key.c                        |   40 +-
 scripts/.gitignore                        |    1 +
 scripts/Makefile                          |    2 +
 scripts/Makefile.build                    |   11 +
 scripts/Makefile.modpost                  |   75 +-
 scripts/asn1_compiler.c                   | 1545 +++++++++++++++++++++++++++++
 scripts/sign-file                         |  115 +++
 scripts/x509keyid                         |  268 +++++
 security/keys/encrypted-keys/encrypted.c  |   16 +-
 security/keys/key.c                       |  114 ++-
 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 +-
 71 files changed, 6394 insertions(+), 244 deletions(-)
 create mode 100644 Documentation/crypto/asymmetric-keys.txt
 create mode 100644 crypto/asymmetric_keys/.gitignore
 create mode 100644 crypto/asymmetric_keys/Kconfig
 create mode 100644 crypto/asymmetric_keys/Makefile
 create mode 100644 crypto/asymmetric_keys/asymmetric_keys.h
 create mode 100644 crypto/asymmetric_keys/asymmetric_type.c
 create mode 100644 crypto/asymmetric_keys/public_key.c
 create mode 100644 crypto/asymmetric_keys/public_key.h
 create mode 100644 crypto/asymmetric_keys/rsa.c
 create mode 100644 crypto/asymmetric_keys/signature.c
 create mode 100644 crypto/asymmetric_keys/x509.asn1
 create mode 100644 crypto/asymmetric_keys/x509_cert_parser.c
 create mode 100644 crypto/asymmetric_keys/x509_parser.h
 create mode 100644 crypto/asymmetric_keys/x509_public_key.c
 create mode 100644 crypto/asymmetric_keys/x509_rsakey.asn1
 create mode 100644 include/asm-generic/bitops/count_zeros.h
 create mode 100644 include/crypto/public_key.h
 create mode 100644 include/keys/asymmetric-parser.h
 create mode 100644 include/keys/asymmetric-subtype.h
 create mode 100644 include/keys/asymmetric-type.h
 create mode 100644 include/linux/asn1.h
 create mode 100644 include/linux/asn1_ber_bytecode.h
 create mode 100644 include/linux/asn1_decoder.h
 create mode 100644 include/linux/oid_registry.h
 create mode 100644 kernel/modsign_pubkey.c
 create mode 100644 kernel/module-internal.h
 create mode 100644 kernel/module_signing.c
 create mode 100644 lib/asn1_decoder.c
 create mode 100755 lib/build_OID_registry
 create mode 100644 lib/mpi/mpi-cmp.c
 create mode 100644 lib/oid_registry.c
 create mode 100644 scripts/asn1_compiler.c
 create mode 100644 scripts/sign-file
 create mode 100755 scripts/x509keyid
author maintainer
#1 lore raw
Quoted 8 lines · David Howells

Note, this implementation of the X.509 certificate parser uses a couple of patterns to drive a reusable ASN.1 decoder. I do, however, have a direct in-line decoder implementation also that can only decode X.509 certs. The stack space usage is greater, but the code size is simpler and slightly smaller and the code is less capable (it can't handle indefinite-length elements for example), and it can't be reused for anything else (such as CIFS, netfilter, PKCS#7, Kerberos tickets), whereas the pattern-based decoder can. I'll post this separately to see what people think.

Here's the direct inline X.509 ASN.1 decoder I mentioned.

David
---
/* X.509 certificate parser
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells ([email protected])
*
* 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) "X.509: "fmt
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/oid_registry.h>
#include "linux/asn1.h"
#include "public_key.h"
#include "x509_parser.h"

struct x509_cursor {
unsigned start; /* Start of this element's content */
unsigned len; /* Remaining length of element's content */
u8 hdrlen; /* Length of header */
u8 tag; /* Tag found */
bool present; /* Element present */
};

struct x509_parse_context {
	struct x509_certificate	*cert;		/* Certificate being constructed */
	const u8	*data;			/* Start of data */
	const void	*cert_start;		/* Start of cert content */
	const void	*key;			/* Key data */
	size_t		key_size;		/* Size of key data */
	enum OID	algo_oid;		/* Algorithm OID */
	unsigned char	nr_mpi;			/* Number of MPIs stored */
	int		error;
};

/*
* Free an X.509 certificate
*/
void x509_free_certificate(struct x509_certificate *cert)

{
	if (cert) {
		public_key_destroy(cert->pub);
		kfree(cert->issuer);
		kfree(cert->subject);
		kfree(cert->fingerprint);
		kfree(cert->authority);
		kfree(cert);
	}
}

/*
* Extract an ASN.1 element.
*/
static bool asn1_extract(struct x509_parse_context *ctx,
struct x509_cursor *cursor, int expected_tag, bool optional, struct x509_cursor *_extracted_cursor)

{
	unsigned start, len;
	u8 tag, l;

	pr_devel("==>%s(,{%u,%u},%02x,%u) [%02x%02x]\n",
		 __func__, cursor->start, cursor->len, expected_tag, optional,
		 ctx->data[cursor->start], ctx->data[cursor->start + 1]);

	if (ctx->error)
		return false;

	if (_extracted_cursor)
		_extracted_cursor->present = false;
	if (cursor->len == 0 && optional)
		return false;

	if (cursor->len < 2) {
		pr_debug("ASN.1 elem header underrun @%u+%u\n",
			 cursor->start, cursor->len);
		ctx->error = -EBADMSG;
		return false;
	}

	tag = ctx->data[cursor->start];
	len = ctx->data[cursor->start + 1];

	if (expected_tag != -1 && tag != expected_tag) {
		if (!optional) {
			pr_debug("ASN.1 unexpected tag %02x%02x not %02x @%u+%u\n",
				 tag, len, expected_tag,
				 cursor->start, cursor->len);
			ctx->error = -EBADMSG;
		}
		return false;
	}

	cursor->start += 2;
	cursor->len -= 2;

	if ((tag & 0x1f) == 0x1f) {
		pr_debug("ASN.1 long tag @%u\n", cursor->start);
		ctx->error = -EBADMSG;
		return false;
	}

	if (len == 0x80) {
		pr_debug("ASN.1 indefinite length @%u\n", cursor->start);
		ctx->error = -EBADMSG;
		return false;
	}

	l = 0;
	if (len > 0x80) {
		l = len - 0x80;
		if (cursor->len < l) {
			pr_debug("ASN.1 elem len underrun (%u) @%u+%u\n",
				 l, cursor->start, cursor->len);
			ctx->error = -EBADMSG;
			return false;
		}

		switch (l) {
		case 0x01:
			len = ctx->data[cursor->start];
			break;
		case 0x02:
			len  = ctx->data[cursor->start + 0] << 8;
			len += ctx->data[cursor->start + 1];
			break;
		case 0x03:
			len  = ctx->data[cursor->start + 0] << 16;
			len += ctx->data[cursor->start + 1] << 8;
			len += ctx->data[cursor->start + 2];
			break;
		case 0x04:
			len  = ctx->data[cursor->start + 0] << 24;
			len += ctx->data[cursor->start + 1] << 16;
			len += ctx->data[cursor->start + 2] << 8;
			len += ctx->data[cursor->start + 3];
			break;
		default:
			pr_debug("ASN.1 elem excessive len (%u) @%u\n",
				 l, cursor->start);
			ctx->error = -EBADMSG;
			return false;
		}

		cursor->start += l;
		cursor->len -= l;
	}

	pr_debug("TAG %02x len: %u+%u\n", tag, l + 2, len);

	if (cursor->len < len) {
		pr_debug("ASN.1 data underrun (%u) @%u+%u\n",
			 len, cursor->start, cursor->len);
		ctx->error = -EBADMSG;
		return false;
	}

	start = cursor->start;
	cursor->start += len;
	cursor->len -= len;
	if (_extracted_cursor) {
		_extracted_cursor->start = start;
		_extracted_cursor->len = len;
		_extracted_cursor->hdrlen = 2 + l;
		_extracted_cursor->tag = tag;
		_extracted_cursor->present = true;
	}
	return true;
}

static bool asn1_check_end(struct x509_parse_context *ctx,
struct x509_cursor *cursor)

{
	if (ctx->error)
		return false;
	if (cursor->len != 0) {
		pr_debug("ASN.1 excess data @%u+%u\n",
			 cursor->start, cursor->len);
		ctx->error = -EBADMSG;
		return false;
	}
	return true;
}

/*
* Parse the signature type.
*/
static void x509_parse_signature_type(struct x509_parse_context *ctx,
struct x509_cursor *data)

{
	struct x509_cursor type;
	enum OID oid;

	asn1_extract(ctx, data, ASN1_UNIV | ASN1_OID, false, &type);
	asn1_extract(ctx, data, -1, true, NULL);
	if (!asn1_check_end(ctx, data))
		return;

	oid = look_up_OID(ctx->data + type.start, type.len);

	switch (oid) {
	case OID_md2WithRSAEncryption:
	case OID_md3WithRSAEncryption:
	default:
		/* Unsupported combination */
		ctx->error = -ENOPKG;
		return;

	case OID_md4WithRSAEncryption:
		ctx->cert->sig_hash_algo = PKEY_HASH_MD5;
		ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
		break;

	case OID_sha1WithRSAEncryption:
		ctx->cert->sig_hash_algo = PKEY_HASH_SHA1;
		ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
		break;

	case OID_sha256WithRSAEncryption:
		ctx->cert->sig_hash_algo = PKEY_HASH_SHA256;
		ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
		break;

	case OID_sha384WithRSAEncryption:
		ctx->cert->sig_hash_algo = PKEY_HASH_SHA384;
		ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
		break;

	case OID_sha512WithRSAEncryption:
		ctx->cert->sig_hash_algo = PKEY_HASH_SHA512;
		ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
		break;

	case OID_sha224WithRSAEncryption:
		ctx->cert->sig_hash_algo = PKEY_HASH_SHA224;
		ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
		break;
	}

	ctx->algo_oid = oid;
}

/*
* Parse a name
*/
static void x509_parse_name(struct x509_parse_context *ctx,

			    struct x509_cursor *name, char **_name)
{
	const u8 *data = ctx->data;
	unsigned o_offset = 0, cn_offset = 0, email_offset = 0, offset;
	unsigned namesize;
	u8 o_size = 0, cn_size = 0, email_size = 0;
	char *buffer;

	BUG_ON(*_name);

	while (!ctx->error && name->len > 0) {
		struct x509_cursor rdn, attr, n_oid, n_val;
		enum OID oid;

		asn1_extract(ctx, name, ASN1_UNIV | ASN1_CONS | ASN1_SET,
			     false, &rdn);
		while (!ctx->error && rdn.len > 0) {
			asn1_extract(ctx, &rdn, ASN1_UNIV | ASN1_CONS | ASN1_SEQ,
				     false, &attr);
			asn1_extract(ctx, &attr, ASN1_UNIV | ASN1_OID, false, &n_oid);
			asn1_extract(ctx, &attr, -1, false, &n_val);
			if (!asn1_check_end(ctx, &attr))
				return;

			oid = look_up_OID(data + n_oid.start, n_oid.len);
			switch (oid) {
			case OID_organizationName:
				o_size = n_val.len;
				o_offset = n_val.start;
				break;
			case OID_commonName:
				cn_size = n_val.len;
				cn_offset = n_val.start;
				break;
			case OID_email_address:
				email_size = n_val.len;
				email_offset = n_val.start;
				break;
			default:
				continue;
			}
		}

		if (!asn1_check_end(ctx, &rdn))
			return;
	}

	if (!asn1_check_end(ctx, name))
		return;

	/* Empty name string if no material */
	if (!cn_size && !o_size && !email_size) {
		buffer = kmalloc(1, GFP_KERNEL);
		if (!buffer) {
			ctx->error = -ENOMEM;
			return;
		}
		buffer[0] = 0;
		goto done;
	}

	if (cn_size && o_size) {
		/* Consider combining O and CN, but use only the CN if it is
		 * prefixed by the O, or a significant portion thereof.
		 */
		namesize = cn_size;
		offset = cn_offset;
		if (cn_size >= o_size &&
		    memcmp(data + cn_offset, data + o_offset, o_size) == 0)
			goto single_component;
		if (cn_size >= 7 &&
		    o_size >= 7 &&
		    memcmp(data + cn_offset, data + o_offset, 7) == 0)
			goto single_component;

		buffer = kmalloc(o_size + 2 + cn_size + 1, GFP_KERNEL);
		if (!buffer) {
			ctx->error = -ENOMEM;
			return;
		}

		memcpy(buffer, data + o_offset, o_size);
		buffer[o_size + 0] = ':';
		buffer[o_size + 1] = ' ';
		memcpy(buffer + o_size + 2, data + cn_offset, cn_size);
		buffer[o_size + 2 + cn_size] = 0;
		goto done;

	} else if (cn_size) {
		namesize = cn_size;
		offset = cn_offset;
	} else if (o_size) {
		namesize = o_size;
		offset = o_offset;
	} else {
		namesize = email_size;
		offset = email_offset;
	}

single_component:

	buffer = kmalloc(namesize + 1, GFP_KERNEL);
	if (!buffer) {
		ctx->error = -ENOMEM;
		return;
	}
	memcpy(buffer, data + offset, namesize);
	buffer[namesize] = 0;

done:

	*_name = buffer;
}

/*
* Record a certificate time.
*/
static bool x509_note_time(struct x509_parse_context *ctx,
time_t *_time, u8 tag, const u8 *value, size_t vlen)

{
	unsigned YY, MM, DD, hh, mm, ss;
	const u8 *p = value;

#define dec2bin(X) ((X) - '0')
#define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; })

	if (tag == ASN1_UNITIM) {
		/* UTCTime: YYMMDDHHMMSSZ */
		if (vlen != 13)
			goto unsupported_time;
		YY = DD2bin(p);
		if (YY > 50)
			YY += 1900;
		else
			YY += 2000;
	} else if (tag == ASN1_GENTIM) {
		/* GenTime: YYYYMMDDHHMMSSZ */
		if (vlen != 15)
			goto unsupported_time;
		YY = DD2bin(p) * 100 + DD2bin(p);
	} else {
		goto unsupported_time;
	}

	MM = DD2bin(p);
	DD = DD2bin(p);
	hh = DD2bin(p);
	mm = DD2bin(p);
	ss = DD2bin(p);

	if (*p != 'Z')
		goto unsupported_time;

	*_time = mktime(YY, MM, DD, hh, mm, ss);
	return true;

unsupported_time:

	pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n",
		 tag, (int)vlen, (int)vlen, value);
	ctx->error = -EBADMSG;
	return false;
}

/*
* Parse the validity data.
*/
static void x509_parse_validity(struct x509_parse_context *ctx,
struct x509_cursor *data)

{
	struct x509_cursor not_before, not_after;

	asn1_extract(ctx, data, -1, false, &not_before);
	asn1_extract(ctx, data, -1, false, &not_after);
	if (!asn1_check_end(ctx, data))
		return;

	if (x509_note_time(ctx, &ctx->cert->valid_from, not_before.tag,
			   ctx->data + not_before.start, not_before.len) < 0) {
		ctx->error = -EBADMSG;
		return;
	}
	if (x509_note_time(ctx, &ctx->cert->valid_to, not_after.tag,
			   ctx->data + not_after.start, not_after.len) < 0) {
		ctx->error = -EBADMSG;
		return;
	}
}

/*
* Extract a RSA public key value
*/
static void x509_parse_rsa_key(struct x509_parse_context *ctx,
struct x509_cursor *data)

{
	struct x509_cursor list, integer;
	MPI mpi;

	asn1_extract(ctx, data, ASN1_UNIV | ASN1_CONS | ASN1_SEQ, false, &list);
	if (!asn1_check_end(ctx, data))
		return;

	while (list.len > 0) {
		if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) {
			pr_debug("Too many public key MPIs in certificate\n");
			ctx->error = -EBADMSG;
			return;
		}

		if (!asn1_extract(ctx, &list, ASN1_UNIV | ASN1_INT,
				  false, &integer))
			return;

		mpi = mpi_read_raw_data(ctx->data + integer.start, integer.len);
		if (!mpi) {
			ctx->error = -ENOMEM;
			return;
		}

		ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi;
	}

	asn1_check_end(ctx, &list);
}

/*
* Parse the key.
*/
static void x509_parse_key(struct x509_parse_context *ctx,
struct x509_cursor *data)

{
	struct x509_cursor algo, type, str;
	enum OID oid;

	asn1_extract(ctx, data, ASN1_UNIV | ASN1_CONS | ASN1_SEQ, false, &algo);
	asn1_extract(ctx, data, ASN1_UNIV | ASN1_BTS, false, &str);
	if (!asn1_check_end(ctx, data))
		return;

	asn1_extract(ctx, &algo, ASN1_UNIV | ASN1_OID, false, &type);
	asn1_extract(ctx, &algo, -1, true, NULL);
	if (!asn1_check_end(ctx, &algo))
		return;

	oid = look_up_OID(ctx->data + type.start, type.len);

	if (oid != OID_rsaEncryption) {
		ctx->error = -ENOPKG;
		return;
	}
	ctx->cert->pkey_algo = PKEY_ALGO_RSA;

	/* Remove the bit string's initial unused bit count */
	if (str.len < 1) {
		pr_debug("ASN.1 short BIT STRING @%u+%u\n", str.start, str.len);
		ctx->error = -EBADMSG;
		return;
	}
	str.start++;
	str.len--;
	x509_parse_rsa_key(ctx, &str);
}

/*
* Parse the extension list.
*/
static void x509_parse_extensions(struct x509_parse_context *ctx,
struct x509_cursor *data)

{
	struct x509_cursor extensions, ext;
	char *f;

	if (!data->present)
		return;

	asn1_extract(ctx, data, ASN1_UNIV | ASN1_CONS | ASN1_SEQ, false, &extensions);
	if (!asn1_check_end(ctx, data))
		return;

	while (extensions.len > 0 &&
	       asn1_extract(ctx, &extensions, ASN1_UNIV | ASN1_CONS | ASN1_SEQ,
			    false, &ext)
	       ) {
		struct x509_cursor type, val, wrapper, part;
		const u8 *v;
		enum OID oid;
		int i;

		asn1_extract(ctx, &ext, ASN1_UNIV | ASN1_OID, false, &type);
		asn1_extract(ctx, &ext, ASN1_UNIV | ASN1_BOOL, true, NULL);
		asn1_extract(ctx, &ext, ASN1_UNIV | ASN1_OTS, false, &val);
		if (!asn1_check_end(ctx, &ext))
			return;

		oid = look_up_OID(ctx->data + type.start, type.len);
		switch (oid) {
		case OID_subjectKeyIdentifier:
			/* Get hold of the key fingerprint */
			asn1_extract(ctx, &val, ASN1_UNIV | ASN1_OTS, false,
				     &part);
			if (!asn1_check_end(ctx, &val))
				return;
			if (part.len == 0) {
				pr_debug("Empty subjectKeyIdentifier\n");
				ctx->error = -EBADMSG;
				return;
			}

			f = kmalloc(part.len * 2 + 1, GFP_KERNEL);
			if (!f) {
				ctx->error = -ENOMEM;
				return;
			}
			v = ctx->data + part.start;
			for (i = 0; i < part.len; i++)
				sprintf(f + i * 2, "%02x", v[i]);
			pr_debug("fingerprint %s\n", f);
			ctx->cert->fingerprint = f;
			break;

		case OID_authorityKeyIdentifier:
			/* Get hold of the CA key fingerprint */
			asn1_extract(ctx, &val, ASN1_UNIV | ASN1_CONS | ASN1_SEQ,
				     false, &wrapper);
			if (!asn1_check_end(ctx, &val))
				return;
			asn1_extract(ctx, &wrapper, ASN1_CONT | 0, false, &part);
			if (!asn1_check_end(ctx, &wrapper))
				return;
			if (part.len == 0) {
				pr_debug("Empty authorityKeyIdentifier\n");
				ctx->error = -EBADMSG;
				return;
			}

			f = kmalloc(part.len * 2 + 1, GFP_KERNEL);
			if (!f) {
				ctx->error = -ENOMEM;
				return;
			}
			v = ctx->data + part.start;
			for (i = 0; i < part.len; i++)
				sprintf(f + i * 2, "%02x", v[i]);
			pr_debug("authority   %s\n", f);
			ctx->cert->authority = f;
			break;

		default:
			continue;
		}
	}

	asn1_check_end(ctx, &extensions);
}

/*
* Parse the signature algorithm.
*/
static void x509_parse_signature_algo(struct x509_parse_context *ctx,
struct x509_cursor *data)

{
	struct x509_cursor type;
	enum OID oid;

	asn1_extract(ctx, data, ASN1_UNIV | ASN1_OID, false, &type);
	asn1_extract(ctx, data, -1, true, NULL);
	if (!asn1_check_end(ctx, data))
		return;

	oid = look_up_OID(ctx->data + type.start, type.len);

	pr_debug("Signature type: %u\n", oid);

	if (oid != ctx->algo_oid) {
		pr_debug("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n",
			 ctx->algo_oid, oid);
		ctx->error = -EINVAL;
	}
}

/*
* Parse the basic structure of the certificate. */
static void x509_parse_basic(struct x509_parse_context *ctx,
size_t datalen)

{
	struct x509_cursor cert, tbs;
	struct x509_cursor tmp = {
		.start = 0,
		.len = datalen
	};

	if (!asn1_extract(ctx, &tmp, ASN1_UNIV | ASN1_CONS | ASN1_SEQ,
			  false, &cert) ||
	    !asn1_check_end(ctx, &tmp))
		return;

	if (!asn1_extract(ctx, &cert, ASN1_UNIV | ASN1_CONS | ASN1_SEQ,
			  false, &tbs))
		return;
	pr_debug("x509_note_tbs_certificate(,%02x,%u,%u)!\n",
		 tbs.tag, tbs.start, tbs.len);
	ctx->cert->tbs = ctx->data + (tbs.start - tbs.hdrlen);
	ctx->cert->tbs_size = tbs.hdrlen + tbs.len;

	{
		asn1_extract(ctx, &tbs, ASN1_CONT | ASN1_CONS | 0,
			     true, NULL); /* Version */
		asn1_extract(ctx, &tbs, ASN1_UNIV | ASN1_INT,
			     false, NULL); /* Serial */
		asn1_extract(ctx, &tbs, ASN1_UNIV | ASN1_CONS | ASN1_SEQ,
			     false, &tmp);
		x509_parse_signature_type(ctx, &tmp);
		asn1_extract(ctx, &tbs, ASN1_UNIV | ASN1_CONS | ASN1_SEQ,
			     false, &tmp);
		x509_parse_name(ctx, &tmp, &ctx->cert->issuer);
		asn1_extract(ctx, &tbs, ASN1_UNIV | ASN1_CONS | ASN1_SEQ,
			     false, &tmp);
		x509_parse_validity(ctx, &tmp);
		asn1_extract(ctx, &tbs, ASN1_UNIV | ASN1_CONS | ASN1_SEQ,
			     false, &tmp);
		x509_parse_name(ctx, &tmp, &ctx->cert->subject);
		asn1_extract(ctx, &tbs, ASN1_UNIV | ASN1_CONS | ASN1_SEQ,
			     false, &tmp);
		x509_parse_key(ctx, &tmp);
		asn1_extract(ctx, &tbs, ASN1_CONT | ASN1_CONS | 1,
			     true, NULL); /* Issuer uid */
		asn1_extract(ctx, &tbs, ASN1_CONT | ASN1_CONS | 2,
			     true, NULL); /* Subject uid */
		asn1_extract(ctx, &tbs, ASN1_CONT | ASN1_CONS | 3,
			     true, &tmp);
		x509_parse_extensions(ctx, &tmp);
	}
	if (!asn1_check_end(ctx, &tbs))
		return;

	asn1_extract(ctx, &cert, ASN1_UNIV | ASN1_CONS | ASN1_SEQ,
		     false, &tmp);
	x509_parse_signature_algo(ctx, &tmp);
	asn1_extract(ctx, &cert, ASN1_UNIV | ASN1_BTS, false, &tmp);
	if (!asn1_check_end(ctx, &cert))
		return;

	/* Remove the bit string's initial unused bit count */
	if (tmp.len < 1) {
		pr_debug("ASN.1 short BIT STRING @%u+%u\n", tmp.start, tmp.len);
		ctx->error = -EBADMSG;
		return;
	}
	tmp.start++;
	tmp.len--;

	pr_debug("Signature size %u\n", tmp.len);
	ctx->cert->sig = ctx->data + tmp.start;
	ctx->cert->sig_size = tmp.len;
}

/*
* Parse an X.509 certificate
*/
struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)

{
	struct x509_certificate *cert;
	struct x509_parse_context *ctx;
	long ret;

	ret = -ENOMEM;
	cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL);
	if (!cert)
		goto error_no_cert;
	cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
	if (!cert->pub)
		goto error_no_ctx;
	ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
	if (!ctx)
		goto error_no_ctx;

	ctx->cert = cert;
	ctx->data = data;

	/* Attempt to decode the certificate */
	x509_parse_basic(ctx, datalen);
	ret = ctx->error;
	if (ret < 0)
		goto error_decode;

	kfree(ctx);
	return cert;

error_decode:

	kfree(ctx);
error_no_ctx:
	x509_free_certificate(cert);
error_no_cert:
	return ERR_PTR(ret);
}
author maintainer
#2 lore raw

Wrong system clock vs X.509 date specifiers

In reply to David Howells

The X.509 certificate has a pair of times in it that delineate the valid period of the cert, and I'm checking that the system clock is within the bounds they define before permitting you to use the cert. I've been setting the expiry date to be 100 years in the future - by which time hopefully I won't have to worry about it - but occasionally clock skew means a freshly built kernel won't boot because the machine trying to boot doesn't think that the start time has been reached yet.

Do we actually want to do this, however? Or should we just ignore the times? Or just the start time?

Unfortunately, the ASN.1 says the field are mandatory, and openssl doesn't seem to give you a way to backdate the start time.

David

#3 lore raw

Re: Wrong system clock vs X.509 date specifiers

Quoted 11 lines · On Tue, 25 Sep 2012 16:09:54 +0100 David Howells <[email protected]> wrote:

The X.509 certificate has a pair of times in it that delineate the valid period of the cert, and I'm checking that the system clock is within the bounds they define before permitting you to use the cert. I've been setting the expiry date to be 100 years in the future - by which time hopefully I won't have to worry about it - but occasionally clock skew means a freshly built kernel won't boot because the machine trying to boot doesn't think that the start time has been reached yet.

Do we actually want to do this, however? Or should we just ignore the times? Or just the start time?

Generate a certificate that is valid from a few minutes before the wallclock time. It's a certificate policy question not a kernel hackery one.

Be careful moving your system clock on 100 years and testing - ext4 gets some timestamps wrong after 2038.

Alan

author maintainer
#4 lore raw

Re: Wrong system clock vs X.509 date specifiers

Quoted 3 lines · Alan Cox

Generate a certificate that is valid from a few minutes before the wallclock time. It's a certificate policy question not a kernel hackery one.

That doesn't seem to be possible with openssl req. What would you recommend?

David

#5 lore raw

Re: Wrong system clock vs X.509 date specifiers

Il 25/09/2012 17:35, David Howells ha scritto:

Quoted 6 lines
Quoted 3 lines · Alan Cox
Quoted 3 lines

Generate a certificate that is valid from a few minutes before the wallclock time. It's a certificate policy question not a kernel hackery one.

That doesn't seem to be possible with openssl req. What would you recommend?

Disgusting, but: add an LD_PRELOAD library that returns a time well in the past.

Paolo

#6 lore raw

Re: Wrong system clock vs X.509 date specifiers

In reply to David Howells
Quoted 7 lines · On Tue, 25 Sep 2012 16:35:20 +0100 David Howells <[email protected]> wrote:
Quoted 3 lines · Alan Cox

Generate a certificate that is valid from a few minutes before the wallclock time. It's a certificate policy question not a kernel hackery one.

That doesn't seem to be possible with openssl req. What would you recommend?

LD_PRELOAD ? or fixing it if GNUTLS certtool can't do the needed. We shouldn't botch security checks in kernel code to work around crappy userspace tools.

Alan

author maintainer
#7 lore raw

Re: Wrong system clock vs X.509 date specifiers

How about the attached? I knew perl had to be good for something...

David
---
#!/usr/bin/perl -w
#
# Generate an X.509 certificate from a public key. #
# Format:
#
# gen-x509-cert <private-key> \
# [C=<country>] [O=<org>] [CN=<cn>] [Email=<email>] \
# [--from=<secs-before-now>] [--to=<secs-after-now] >output
#
use strict;
use POSIX qw(strftime);

my $UNIV = 0 << 6;
my $APPL = 1 << 6;
my $CONT = 2 << 6;
my $PRIV = 3 << 6;

my $BOOLEAN = 0x01;
my $INTEGER = 0x02;
my $BIT_STRING = 0x03;
my $OCTET_STRING = 0x04;
my $NULL = 0x05;
my $OBJ_ID = 0x06;
my $UTF8String = 0x0c;
my $SEQUENCE = 0x10;
my $SET = 0x11;
my $GeneralizedTime = 0x18;

my %OIDs = (

    commonName			=> pack("CCC", 85, 4, 3),
    countryName			=> pack("CCC", 85, 4, 6),
    organizationName		=> pack("CCC", 85, 4, 10),
    organizationUnitName	=> pack("CCC", 85, 4, 11),
    rsaEncryption		=> pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1),
    sha1WithRSAEncryption	=> pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5),
    emailAddress		=> pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1),
    authorityKeyIdentifier	=> pack("CCC", 85, 29, 35),
    subjectKeyIdentifier	=> pack("CCC", 85, 29, 14),
    keyUsage			=> pack("CCC", 85, 29, 15),
    basicConstraints		=> pack("CCC", 85, 29, 19)

);

#
# Set up the X.509 params
#
die "Format: <private-key> [options]"

    if ($#ARGV == -1);

my $privfilename = shift @ARGV;

my %subject_name;

if ($#ARGV == -1) {
    # Make something up if they don't want to admit to it
    $subject_name{"C"}		= 'h2g2',
    $subject_name{"O"}		= 'Magrathea',
    $subject_name{"CN"}		= 'Glacier signing key',
    $subject_name{"Email"}	= '[email protected]'
}

my $from = 7 * 24 * 60 * 60; my $to = 36500 * 24 * 60 * 60;

foreach my $_ (@ARGV) {
    if (/--from=(.*)/) {
	$from = $1;
    } elsif (/--to=(.*)/) {
	$to = $1;
    } elsif (/([A-Z][A-Za-z]*)=(.*)/) {
	$subject_name{$1} = $2;
    } else {
	last;
    }
}

my $now = time();
my $valid_from = strftime("%Y%m%d%H%M%SZ", gmtime($now - $from));
my $valid_to = strftime("%Y%m%d%H%M%SZ", gmtime($now + $to));

#

# openssl can be used to give us the public key in exactly the form we need -
# including ASN.1 wrappings - for inclusion in the certificate.
#
open PUBKEYFD, "openssl rsa -in $privfilename -pubout -outform DER 2>/dev/null |" ||
    die "Unable to process $privfilename through openssl rsa: $!\n";
binmode PUBKEYFD;

my $pubkey = "";
my $tmp;

while (read(PUBKEYFD, $tmp, 512)) {
    $pubkey .= $tmp;
}
close PUBKEYFD ||
    die "Unable to close channel to openssl rsa: $!\n";

#
# Generate a serial number #
my $serial = "";

for (my $i = int(rand(6)) + 6; $i > 0; $i--) {
    $serial .= pack("C", rand(256));
}
$serial = pack("x") . $serial
    if (unpack("C", substr($serial, 0, 1)) >= 0x80);

#
# Generate the SubjectKeyIdentifier. This is the ASN.1 sum of the contents of

# the bit string element from the public key.
#
die "Can't disassemble RSA public key wrapping\n"
    if (substr($pubkey,  0, 2) ne pack("n", 0x3082) ||
	substr($pubkey,  4, 4) ne pack("N", 0x300d0609) ||
	substr($pubkey,  8, 9) ne $OIDs{"rsaEncryption"} ||
	substr($pubkey, 17, 2) ne pack("n", 0x0500) ||
	substr($pubkey, 19, 2) ne pack("n", 0x0382) ||
	substr($pubkey, 23, 1) ne pack("C", 0x00));

my $key_data = substr($pubkey, 24);

sub sha1sum($)

{
    my ($data) = @_;

    my ($TO_RD, $TO_WR, $FROM_RD, $FROM_WR);
    pipe $TO_RD, $TO_WR;
    pipe $FROM_RD, $FROM_WR;

    my $sha1output;
    my $child = fork();
    if ($child == 0) {
	close $TO_WR;
	close $FROM_RD;
	open(STDIN, ">&", $TO_RD) or die "Can't direct $TO_RD to STDIN: $!";
	open(STDOUT, ">&", $FROM_WR) or die "Can't direct $FROM_WR to STDOUT: $!";
	close $TO_RD;
	close $FROM_WR;
	exec("sha1sum");
    } elsif (!$child) {
	die;
    } else {
	close $TO_RD;
	close $FROM_WR;
	binmode $TO_WR;
	syswrite $TO_WR, $data || die;
	close $TO_WR || die;
	$sha1output = <$FROM_RD> || die;
	close $FROM_RD;
	die "sha1sum failed\n"
	    if (waitpid($child, 0) != $child);
    }

    return pack("H*", substr($sha1output, 0, 40));
}

my $keyid = sha1sum($key_data);

###############################################################################
#
# Generate a header
#
###############################################################################
sub emit_asn1_hdr($$)

{
    my ($tag, $len) = @_;

    if ($len < 0x80) {
	return pack("CC",   $tag, $len);
    } elsif ($len <= 0xff) {
	return pack("CCC",   $tag, 0x81, $len);
    } elsif ($len <= 0xffff) {
	return pack("CCn",  $tag, 0x82, $len);
    } elsif ($len <= 0xffffff) {
	return pack("CCCn", $tag, 0x83, $len >> 16, $len & 0xffff);
    } else {
	return pack("CCN",  $tag, 0x84, $len);
    }
}

###############################################################################
#
# Generate a primitive containing some data #
###############################################################################
sub emit_asn1_prim(@)

{
    my ($class, $tag, $data) = @_;

    $data = ""
	if ($#_ == 1);

    $tag |= $class;
    return emit_asn1_hdr($tag, length($data)) . $data;
}

###############################################################################
#
# Generate an object identifier #
###############################################################################
sub emit_asn1_OID($$$)

{
    my ($class, $tag, $oid_name) = @_;
    my $oid;

    if (!exists($OIDs{$oid_name})) {
	print STDERR "Unknown OID: $oid_name\n";
	exit(2);
    }

    $oid = $OIDs{$oid_name};
    return emit_asn1_hdr($class | $tag, length($oid)) . $oid;
}

###############################################################################
#
# Generate a bit string. This has a leading byte indicating the number of

# trailing bits that should be ignored.
#
###############################################################################
sub emit_asn1_bts($$$)
{
    my ($class, $tag, $content) = @_;
    return emit_asn1_prim($class, $tag, pack("x") . $content);
}

###############################################################################
#
# Generate a construct
#
###############################################################################
sub emit_asn1_cons($$$)

{
    my ($class, $tag, $content) = @_;

    return emit_asn1_hdr($class | 0x20 | $tag, length($content)) . $content;
}

###############################################################################
#
# Generate a name
#
###############################################################################
sub emit_x509_AttributeValueAssertion($$$)

{
    my ($type, $name, $sym) = @_;
    my $output;
    my $data;

    return "" if (!exists($name->{$sym}));

    $data = $name->{$sym};
    $output  = emit_asn1_OID($UNIV, $OBJ_ID, $type);		# attributeType
    $output .= emit_asn1_prim($UNIV, $UTF8String, $data);	# attributeValue
    return emit_asn1_cons($UNIV, $SET,
			  emit_asn1_cons($UNIV, $SEQUENCE, $output));
}

sub emit_x509_RelativeDistinguishedName($)

{
    my ($name) = @_;
    my $output;

    # SET OF AttributeValueAssertion
    $output .= emit_x509_AttributeValueAssertion("countryName", $name, "C");
    $output .= emit_x509_AttributeValueAssertion("organizationName", $name, "O");
    $output .= emit_x509_AttributeValueAssertion("organizationUnitName", $name, "OU");
    $output .= emit_x509_AttributeValueAssertion("commonName", $name, "CN");
    $output .= emit_x509_AttributeValueAssertion("emailAddress", $name, "Email");
    return $output;
}

sub emit_x509_Name($)

{
    my ($name) = @_;
    my $output;

    # SEQUENCE OF RDN
    $output  = emit_x509_RelativeDistinguishedName($name);
    return emit_asn1_cons($UNIV, $SEQUENCE, $output);
}

###############################################################################
#
# Generate some X.509 extensions #
###############################################################################
sub emit_x509_SubjectKeyIdentifier()

{
    return emit_asn1_prim($UNIV, $OCTET_STRING, $keyid);
}

sub emit_x509_AuthorityKeyIdentifier()

{
    my $content = emit_asn1_prim($CONT, 0, $keyid);
    return emit_asn1_cons($UNIV, $SEQUENCE, $content);
}

sub emit_x509_BasicConstraints()

{
    return pack("CC", 0x30, 0x00);
}

sub emit_x509_KeyUsage()

{
    return emit_asn1_prim($UNIV, $BIT_STRING, pack("CC", 0x07, 0x80));
}

sub emit_x509_Extension($@)

{
    my ($ext, $crit) = @_;
    my $output;
    my $value = "";

    if ($ext eq "authorityKeyIdentifier") {
	$output = emit_asn1_OID($UNIV, $OBJ_ID, $ext);
	$value = emit_x509_AuthorityKeyIdentifier();
    } elsif ($ext eq "subjectKeyIdentifier") {
	$output = emit_asn1_OID($UNIV, $OBJ_ID, $ext);
	$value = emit_x509_SubjectKeyIdentifier();
    } elsif ($ext eq "basicConstraints") {
	$output = emit_asn1_OID($UNIV, $OBJ_ID, $ext);
	$value = emit_x509_BasicConstraints();
    } elsif ($ext eq "keyUsage") {
	$output = emit_asn1_OID($UNIV, $OBJ_ID, $ext);
	$value = emit_x509_KeyUsage();
    } else {
	die;
    }

    $output .= emit_asn1_prim($UNIV, $BOOLEAN, pack("C", 0x01))	# critical
	if ($crit);
    $output .= emit_asn1_hdr($UNIV | $OCTET_STRING, length($value)) . $value;

    return emit_asn1_cons($UNIV, $SEQUENCE, $output);
}

sub emit_x509_Extensions()

{
    my $output = "";

    # Probably do want a sequence of extensions here
    $output .= emit_x509_Extension("basicConstraints", 1);
    $output .= emit_x509_Extension("keyUsage");
    $output .= emit_x509_Extension("authorityKeyIdentifier");
    $output .= emit_x509_Extension("subjectKeyIdentifier");

    return emit_asn1_cons($CONT, 3, emit_asn1_cons($UNIV, $SEQUENCE, $output));
}

###############################################################################
#
# Sign a digest with an RSA key #
###############################################################################
sub rsa_sign($)

{
    my ($digest) = @_;

    my ($TO_RD, $TO_WR, $FROM_RD, $FROM_WR);
    pipe $TO_RD, $TO_WR;
    pipe $FROM_RD, $FROM_WR;

    my $output;
    my $child = fork();
    if ($child == 0) {
	close $TO_WR;
	close $FROM_RD;
	open(STDIN, ">&", $TO_RD) or die "Can't direct $TO_RD to STDIN: $!";
	open(STDOUT, ">&", $FROM_WR) or die "Can't direct $FROM_WR to STDOUT: $!";
	close $TO_RD;
	close $FROM_WR;
	exec("openssl rsautl -sign -inkey $privfilename");
    } elsif (!$child) {
	die;
    } else {
	close $TO_RD;
	close $FROM_WR;
	binmode $TO_WR;
	syswrite $TO_WR, $digest || die;
	close $TO_WR || die;

	my $tmp;
	while (read($FROM_RD, $tmp, 512)) {
	    $output .= $tmp;
	}
	close $FROM_RD;
	die "openssl rsautl failed\n"
	    if (waitpid($child, 0) != $child);
    }

    return $output;
}

###############################################################################
#
# Generate an X.509 certificate
#
###############################################################################
sub emit_x509_Validity()
{
my $output;
$output = emit_asn1_prim($UNIV, $GeneralizedTime, $valid_from); # notBefore
$output .= emit_asn1_prim($UNIV, $GeneralizedTime, $valid_to); # notAfter
return emit_asn1_cons($UNIV, $SEQUENCE, $output);
}

sub emit_x509_AlgorithmIdentifier($)

{
    my ($oid) = @_;
    my $output;

    $output  = emit_asn1_OID($UNIV, $OBJ_ID, $oid);	# algorithm
    $output .= emit_asn1_prim($UNIV, $NULL);		# parameters
    return emit_asn1_cons($UNIV, $SEQUENCE, $output);
}

sub emit_x509_Version()

{
    # Version 3
    my $output = emit_asn1_prim($UNIV, $INTEGER, pack("C", 3 - 1));
    return emit_asn1_cons($CONT, 0, $output);
}

sub emit_x509_SubjectPublicKeyInfo()
{
my $output;
$output = emit_x509_AlgorithmIdentifier("rsaEncryption"); # algorithm
$output .= emit_asn1_prim($UNIV, $BIT_STRING); # subjectPublicKey
return emit_asn1_cons($UNIV, $SEQUENCE, $output);
}

sub emit_x509_TBSCertificate()

{
    my $output;

    $output  = emit_x509_Version;			# version
    $output .= emit_asn1_prim($UNIV, $INTEGER, $serial); # serialNumber
    $output .= emit_x509_AlgorithmIdentifier("sha1WithRSAEncryption");	# signature
    $output .= emit_x509_Name(\%subject_name);		# issuer
    $output .= emit_x509_Validity();			# validity
    $output .= emit_x509_Name(\%subject_name);		# subject
    #$output .= emit_x509_SubjectPublicKeyInfo();	# subjectPublicKeyInfo
    $output .= $pubkey;
    $output .= emit_x509_Extensions();			# extensions

    return emit_asn1_cons($UNIV, $SEQUENCE, $output);
}

sub emit_x509_Certificate()

{
    my $output;

    $output  = emit_x509_TBSCertificate();		# tbsCertificate

    # We digest the TBS and sign it.
    my $tbs_digest =
	pack("C*", 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
	     0x2B, 0x0E, 0x03, 0x02, 0x1A,
	     0x05, 0x00, 0x04, 0x14) .
	     sha1sum($output);

    my $sig = rsa_sign($tbs_digest);

    $output .= emit_x509_AlgorithmIdentifier("sha1WithRSAEncryption");	# signatureAlgorithm
    $output .= emit_asn1_bts($UNIV, $BIT_STRING, $sig);	# signature

    return emit_asn1_cons($UNIV, $SEQUENCE, $output);
}

print emit_x509_Certificate();

#8 lore raw

Re: Wrong system clock vs X.509 date specifiers

In reply to David Howells
Quoted 7 lines · David Howells
Quoted 3 lines · Alan Cox

Generate a certificate that is valid from a few minutes before the wallclock time. It's a certificate policy question not a kernel hackery one.

That doesn't seem to be possible with openssl req. What would you recommend?

You can use openssl ca that allows to set arbitrary start date to generate selfsigned certs as well (-selfsign option).

Signature · 3 lines
Tomas Mraz
No matter how far down the wrong road you've gone, turn back.
                                              Turkish proverb
author maintainer
#9 lore raw

Re: Wrong system clock vs X.509 date specifiers

Quoted 2 lines · Tomas Mraz

You can use openssl ca that allows to set arbitrary start date to generate selfsigned certs as well (-selfsign option).

That seems to require some stuff I don't have installed:

warthog>openssl ca -in signing_key.priv -extensions v3_ca -out newcert.pem
Using configuration from /etc/pki/tls/openssl.cnf
Error opening CA private key /etc/pki/CA/private/cakey.pem
140244246955872:error:0200100D:system library:fopen:Permission denied:bss_file.c:398:fopen('/etc/pki/CA/private/cakey.pem','r') 140244246955872:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:400:
unable to load CA private key
unable to write 'random state'

(the /etc/pki/CA/private/ dir is inaccessible if not root and doesn't in any case contain cakey.pem).

Do I need to start with all the CA stuff in the right places to use it?

David

#10 lore raw

Re: Wrong system clock vs X.509 date specifiers

Quoted 15 lines · David Howells
Quoted 2 lines · Tomas Mraz

You can use openssl ca that allows to set arbitrary start date to generate selfsigned certs as well (-selfsign option).

That seems to require some stuff I don't have installed:

warthog>openssl ca -in signing_key.priv -extensions v3_ca -out newcert.pem
Using configuration from /etc/pki/tls/openssl.cnf
Error opening CA private key /etc/pki/CA/private/cakey.pem
140244246955872:error:0200100D:system library:fopen:Permission denied:bss_file.c:398:fopen('/etc/pki/CA/private/cakey.pem','r') 140244246955872:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:400:
unable to load CA private key
unable to write 'random state'

Quoted 4 lines

(the /etc/pki/CA/private/ dir is inaccessible if not root and doesn't in any case contain cakey.pem).

Do I need to start with all the CA stuff in the right places to use it?

You can configure it to point to a different directories. But yes, you have to create a CA cert and so on.

Signature · 3 lines
Tomas Mraz
No matter how far down the wrong road you've gone, turn back.
                                              Turkish proverb
#11 lore raw

Re: Wrong system clock vs X.509 date specifiers

In reply to Alan Cox
Quoted 12 lines · Alan Cox
Quoted 9 lines · On Tue, 25 Sep 2012 16:09:54 +0100 David Howells <[email protected]> wrote:

The X.509 certificate has a pair of times in it that delineate the valid period of the cert, and I'm checking that the system clock is within the bounds they define before permitting you to use the cert. I've been setting the expiry date to be 100 years in the future - by which time hopefully I won't have to worry about it - but occasionally clock skew means a freshly built kernel won't boot because the machine trying to boot doesn't think that the start time has been reached yet.

Quoted 6 lines
Quoted 2 lines

Do we actually want to do this, however? Or should we just ignore the times? Or just the start time?

Generate a certificate that is valid from a few minutes before the wallclock time. It's a certificate policy question not a kernel hackery one.

That's not good enough. I frequently encounter laptops with hardware clocks which are *way* slower than that. I see lots of machines booting up thinking it's 1970, 1900 iirc for some Macs, and more recently 2001.

This causes the kernel to refuse to load the certificate:

[    3.116185] Loading module verification certificates
[    3.117414] X.509: Cert e1a74f2317b1f38848278d07926ed16c2675393e is not yet valid
[    3.118639] MODSIGN: Problem loading in-kernel X.509 certificate (-129)

...and then spew error messages every time a module is loaded.

For the kernel, it makes *absolutely* no sense to be checking the start date of the certificate. We do not have a usage model where someone says "hey, here's this kernel module but I don't want you to be able to use it until tomorrow so I've post-dated its signature".

If we *ever* try to load a signed kernel module when the certificate is "not yet valid", it's because the clock is wrong. It's as simple as that.

And even if we *did* want to support that stupid "load this tomorrow" use case, it's broken. You couldn't boot today, then load the offending module tomorrow. You'd have to *reboot* tomorrow, because the kernel refused to load the damn cert into its store at all.

For the specific case of module signing, we should probably just disable the date checks completely.

Signature · 1 line
dwmw2
#12 lore raw

PATCH 1/1 Fix x509_key_preparse() not to reject keys outside their validity time range

The x509_key_preparse() function will refuse to even *parse* a certificate when the system clock happens to be set to a time before the ValidFrom or after the ValidTo date.

This is wrong. If date checks are to be done, they need to be done at the time the cert is *used*. It should be perfectly possible to load a cert which is post-dated, and can only be used for validation at some point in the future. The key in question should immediately start working at its ValidFrom date, and stop again at its ValidTo date. It should be allowed to *exist* in the kernel both before and after those times.

On systems where the hardware clock is inaccurate (a common occurrence and one which doesn't even get noticed when you use NTP or something else to fix it during the boot sequence), this was preventing the module signing cert from being loaded during boot. When the clock got fixed later on in he boot sequence, things *should* have started working. But they didn't...

---

Arguably, for the specific case of module signing we shouldn't bother checking for a current time before the ValidFrom date *at all*. It's *always* going to be a screwed up system clock, because we don't have a usage model of post-dating module signatures. We should simply document that the date is *not* checked for module signing, and have done with it. But that's a separate issue.

crypto/asymmetric_keys/x509_public_key.c +0 -4
index 06007f0..326dc80 100644
@@ -154,8 +154,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 		     (now.tm_sec < cert->valid_from.tm_sec
 		      ))))))))))) {
 		pr_warn("Cert %s is not yet valid\n", cert->fingerprint);
-		ret = -EKEYREJECTED;
-		goto error_free_cert;
 	}
 	if (now.tm_year > cert->valid_to.tm_year ||
 	    (now.tm_year == cert->valid_to.tm_year &&
@@ -170,8 +168,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 		     (now.tm_sec > cert->valid_to.tm_sec
 		      ))))))))))) {
 		pr_warn("Cert %s has expired\n", cert->fingerprint);
-		ret = -EKEYEXPIRED;
-		goto error_free_cert;
 	}
 
 	cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo];
Signature · 2 lines
David Woodhouse                            Open Source Technology Centre
[email protected]                              Intel Corporation
#13 lore raw

Re: [PATCH] Fix x509_key_preparse() not to reject keys outside their validity time range

Am 14.03.2013 13:24, schrieb David Woodhouse:

Quoted 43 lines

The x509_key_preparse() function will refuse to even *parse* a certificate when the system clock happens to be set to a time before the ValidFrom or after the ValidTo date.

This is wrong. If date checks are to be done, they need to be done at the time the cert is *used*. It should be perfectly possible to load a cert which is post-dated, and can only be used for validation at some point in the future. The key in question should immediately start working at its ValidFrom date, and stop again at its ValidTo date. It should be allowed to *exist* in the kernel both before and after those times.

On systems where the hardware clock is inaccurate (a common occurrence and one which doesn't even get noticed when you use NTP or something else to fix it during the boot sequence), this was preventing the module signing cert from being loaded during boot. When the clock got fixed later on in he boot sequence, things *should* have started working. But they didn't...

---

Arguably, for the specific case of module signing we shouldn't bother checking for a current time before the ValidFrom date *at all*. It's *always* going to be a screwed up system clock, because we don't have a usage model of post-dating module signatures. We should simply document that the date is *not* checked for module signing, and have done with it. But that's a separate issue.

crypto/asymmetric_keys/x509_public_key.c +0 -2
index 06007f0..326dc80 100644
@@ -154,8 +154,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
  		     (now.tm_sec < cert->valid_from.tm_sec
  		      ))))))))))) {
  		pr_warn("Cert %s is not yet valid\n", cert->fingerprint);
-		ret = -EKEYREJECTED;
-		goto error_free_cert;
  	}
  	if (now.tm_year > cert->valid_to.tm_year ||
  	    (now.tm_year == cert->valid_to.tm_year &&

crypto/asymmetric_keys/x509_public_key.c static int x509_key_preparse(struct key_preparsed_payload *prep) · line 173

Quoted 8 lines
crypto/asymmetric_keys/x509_public_key.c +0 -2
@@ -170,8 +168,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
  		     (now.tm_sec > cert->valid_to.tm_sec
  		      ))))))))))) {
  		pr_warn("Cert %s has expired\n", cert->fingerprint);
-		ret = -EKEYEXPIRED;
-		goto error_free_cert;
  	}
 
  	cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo];

Why not remove the check and warning there too?

Regards,

Alexander

#14 lore raw
In reply to David Howells

Hello David,

As I can see API has changed towards our discussion on KS. Now digest can be supplied to the verify_signature in a public_key_signature argument.
It looks that in such away we can use this API for IMA/EVM as well.

Just one question about key description...
request_asymmetric_key uses format for key description: "<signer>: <key-id>". Preparsing code creates description from those values.
I see that key id is not 8 bytes anymore but full hash size of 20 bytes.

For practical reasons for IMA it might be nice to save some space in xattrs and use shorter key id/description.
As I understand from implementation, if key name is provided with "keyctl add", it will not be replaced with
preparsed value.

Right?
And we can actually use any keyid we want?

- Dmitry

Quoted 296 lines · David Howells

Hi Herbert, Rusty,

Here are my latest module signing patches on top of the asymmetric key crypto patches, which I hope Herbert will consider taking, at least from the crypto-keys-post-KS branch:

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

The module signing patches go on top of those, and the set can be found here:

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

Do you want the patches posting to the lists? I've tried posting the series as one, but there seems to be a problem posting the merge commit in the middle because it has two parents:-/

Anyway...

The module signing patches provide:

- Some fixes to Rusty's patch. Also an additional patch to extend the policy handling for modules signed with an unknown key and to handle FIPS mode.

- Module signature generation and checking. The signature format is:

        <signer-id-string>
        <binary-key-id>
        <binary-signature>
        <sig-information-block>

The fixed-length sig-information-block indicates the crypto algorithm (RSA only for the moment), the hash type (SHA512 for example) and the identifier scope (X.509 in this case), plus the lengths of the other three parts.

The binary-key-id could be rendered as hex and pasted onto the end of the signer-id-string so that the kernel doesn't have to do the conversion.

A script is provided in one of the patches to generate the signer name and key ID parts from the X.509 cert for later inclusion in module signatures during the build.

- A transient X.509 cert will be automatically generated if one is not given and will be used to automatically sign the modules after they've been thoroughly stripped.

Note that this may prove not to be the best way for distributions to do things. We're currently looking at the best way being to do the stripping and signing manually from the RPM spec file after the make modules_install step and after the debuginfo has been extracted, so automatic signing may need to go away, or at least become optional.

To make this easier, a script is provided to sign a module and this can be called either from the Makefile or the spec file.

- An 'extra_certificates' file can be placed in the root of the kernel build containing a number of supplementary X.509 certs just cat'd together. These will get added to the internal keyring and can then be used to check module signatures also.

I have also fixed a number of things in the crypto patches:

- GeneralizedTime and GeneralString were transposed in the ASN.1 compiler directive table and enum token_type ('S' comes before 'i' to strcmp()), resulting in it not being possible to use either.

- I had made it a requirement that the X.509 certificate subjectKeyIdentifier and authorityKeyIdentifier extensions exist so that we can validate the X.509 signature if possible, but I hadn't put in any checks that they'd been found before using the values extracted, leading to a crash.

- I fixed header length computation in ASN.1 decoder resulting making it possible to discard one of the x509.asn1 callback actions (we can locate the start of the TBS container directly now by subtraction).

- I got rid of the fingerprint bit at the end of the public_key struct as it's superfluous (the asymmetric key type stores the fingerprint attached to key->type_data.p[1]).

- I made the X.509 parser render the key description in a more compact manner:

The description is split into two parts: "<signer>: <key-id>".

The <key-id> is a hex rendering of the key identifier - in the case of X.509 that would be the contents of the subjectKeyIdentifier extension field with the ASN.1 OctetString wrapper removed.

The <signer> is (in order) one of:

- The O and CN attributes as "<O-attr>: <CN-attr>" if the CN attribute isn't prefixed with the O attribute, and, if longer, doesn't share the same first seven chars (say a company name such as Red Hat Inc.). I admit this is entirely arbitrary and biased towards companies with 7 chars or more in there name, but it does remove duplication of the organisation's name if it's in both the O and the CN. Can anyone suggest a better heuristic?

- The CN attribute.

- The O attribute.

- The email address.

- Omitted (with ": " omitted too).

As an example:

        Magrathea: Glacier signing key: 5dd0839552bd6af498253f8af1e65da3472941c6

which is "<O-attr>: <CN-attr>: <key-id>" in form, or:

        Red Hat Test Certificate: 3580cf35d76b3b667a40df66691cbcf87353b23c

which is just "<CN-attr>: <key-id>" in form.

- I no longer extract the bits of the X.509 certificate I don't currently use (such as the version number).

Note, this implementation of the X.509 certificate parser uses a couple of patterns to drive a reusable ASN.1 decoder. I do, however, have a direct in-line decoder implementation also that can only decode X.509 certs. The stack space usage is greater, but the code size is simpler and slightly smaller and the code is less capable (it can't handle indefinite-length elements for example), and it can't be reused for anything else (such as CIFS, netfilter, PKCS#7, Kerberos tickets), whereas the pattern-based decoder can. I'll post this separately to see what people think.

As far as testing goes, I have posted a number of testing scripts that I have used to punish the crypto keys side of things. The "keyctl padd" command makes this straightforward.

Hopefully, later this week the patches will appear in the Fedora 18 kernel.

David
---
The following changes since commit eeea3ac912207dcf759b95b2b4c36f96bce583bf:

Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc (2012-09-06 10:23:58 -0700)

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-modsign.git modsign-post-KS

for you to fetch changes up to 8d4f62638e9aae069d1145dfeb7300c58077be49:

MODSIGN: Extend the policy on signature check failure (2012-09-24 20:51:59 +0100)

----------------------------------------------------------------
(from the branch description for modsign-post-KS local branch)

post Kernel-Summit module signing
----------------------------------------------------------------
David Howells (26):
KEYS: Add payload preparsing opportunity prior to key instantiate or update
MPILIB: Provide count_leading/trailing_zeros() based on arch functions
KEYS: Document asymmetric key type
KEYS: Implement asymmetric key type
KEYS: Asymmetric key pluggable data parsers
KEYS: Asymmetric public-key algorithm crypto key subtype
KEYS: Provide signature verification with an asymmetric key
MPILIB: Reinstate mpi_cmp[_ui]() and export for RSA signature verification
RSA: Implement signature verification algorithm [PKCS#1 / RFC3447]
RSA: Fix signature verification for shorter signatures
X.509: Implement simple static OID registry
X.509: Add utility functions to render OIDs as strings
X.509: Add simple ASN.1 grammar compiler
X.509: Add an ASN.1 decoder
MPILIB: Provide a function to read raw data into an MPI
X.509: Add a crypto key parser for binary (DER) X.509 certificates Merge Rusty's module signature checking hook into modsign-post-KS
MOD: Fix Rusty's module_sig_check()
MODSIGN: Provide gitignore and make clean rules for extra files
MODSIGN: Provide Kconfig options
MODSIGN: Automatically generate module signing keys if missing
MODSIGN: Provide module signing public keys to the kernel
MODSIGN: Implement module signature checking
MODSIGN: Provide a script for generating a key ID from an X.509 cert
MODSIGN: Sign modules during the build process
MODSIGN: Extend the policy on signature check failure

Rusty Russell (1):
module: signature checking hook

 .gitignore                                |   13 +
 Documentation/crypto/asymmetric-keys.txt  |  312 ++++++
 Documentation/kernel-parameters.txt       |    6 +
 Documentation/security/keys.txt           |   50 +-
 Makefile                                  |    1 +
 crypto/Kconfig                            |    1 +
 crypto/Makefile                           |    1 +
 crypto/asymmetric_keys/.gitignore         |    1 +
 crypto/asymmetric_keys/Kconfig            |   38 +
 crypto/asymmetric_keys/Makefile           |   27 +
 crypto/asymmetric_keys/asymmetric_keys.h  |   15 +
 crypto/asymmetric_keys/asymmetric_type.c  |  274 +++++
 crypto/asymmetric_keys/public_key.c       |  108 ++
 crypto/asymmetric_keys/public_key.h       |   30 +
 crypto/asymmetric_keys/rsa.c              |  277 ++++++
 crypto/asymmetric_keys/signature.c        |   49 +
 crypto/asymmetric_keys/x509.asn1          |   60 ++
 crypto/asymmetric_keys/x509_cert_parser.c |  497 ++++++++++
 crypto/asymmetric_keys/x509_parser.h      |   36 +
 crypto/asymmetric_keys/x509_public_key.c  |  207 ++++
 crypto/asymmetric_keys/x509_rsakey.asn1   |    4 +
 fs/cifs/cifs_spnego.c                     |    6 +-
 fs/cifs/cifsacl.c                         |    8 +-
 include/asm-generic/bitops/count_zeros.h  |   57 ++
 include/crypto/public_key.h               |  108 ++
 include/keys/asymmetric-parser.h          |   37 +
 include/keys/asymmetric-subtype.h         |   55 +
 include/keys/asymmetric-type.h            |   25 +
 include/keys/user-type.h                  |    6 +-
 include/linux/asn1.h                      |   67 ++
 include/linux/asn1_ber_bytecode.h         |   87 ++
 include/linux/asn1_decoder.h              |   24 +
 include/linux/key-type.h                  |   35 +-
 include/linux/module.h                    |    8 +
 include/linux/mpi.h                       |    1 +
 include/linux/oid_registry.h              |   92 ++
 init/Kconfig                              |   68 ++
 kernel/Makefile                           |   57 ++
 kernel/modsign_pubkey.c                   |  112 +++
 kernel/module-internal.h                  |   16 +
 kernel/module.c                           |  100 +-
 kernel/module_signing.c                   |  247 +++++
 lib/.gitignore                            |    2 +-
 lib/Kconfig                               |    5 +
 lib/Makefile                              |   18 +
 lib/asn1_decoder.c                        |  477 +++++++++
 lib/build_OID_registry                    |  209 ++++
 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 +-
 lib/mpi/mpicoder.c                        |   55 +
 lib/oid_registry.c                        |  170 ++++
 net/ceph/crypto.c                         |    9 +-
 net/dns_resolver/dns_key.c                |    6 +-
 net/rxrpc/ar-key.c                        |   40 +-
 scripts/.gitignore                        |    1 +
 scripts/Makefile                          |    2 +
 scripts/Makefile.build                    |   11 +
 scripts/Makefile.modpost                  |   75 +-
 scripts/asn1_compiler.c                   | 1545 +++++++++++++++++++++++++++++
 scripts/sign-file                         |  115 +++
 scripts/x509keyid                         |  268 +++++
 security/keys/encrypted-keys/encrypted.c  |   16 +-
 security/keys/key.c                       |  114 ++-
 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 +-
 71 files changed, 6394 insertions(+), 244 deletions(-)
 create mode 100644 Documentation/crypto/asymmetric-keys.txt
 create mode 100644 crypto/asymmetric_keys/.gitignore
 create mode 100644 crypto/asymmetric_keys/Kconfig
 create mode 100644 crypto/asymmetric_keys/Makefile
 create mode 100644 crypto/asymmetric_keys/asymmetric_keys.h
 create mode 100644 crypto/asymmetric_keys/asymmetric_type.c
 create mode 100644 crypto/asymmetric_keys/public_key.c
 create mode 100644 crypto/asymmetric_keys/public_key.h
 create mode 100644 crypto/asymmetric_keys/rsa.c
 create mode 100644 crypto/asymmetric_keys/signature.c
 create mode 100644 crypto/asymmetric_keys/x509.asn1
 create mode 100644 crypto/asymmetric_keys/x509_cert_parser.c
 create mode 100644 crypto/asymmetric_keys/x509_parser.h
 create mode 100644 crypto/asymmetric_keys/x509_public_key.c
 create mode 100644 crypto/asymmetric_keys/x509_rsakey.asn1
 create mode 100644 include/asm-generic/bitops/count_zeros.h
 create mode 100644 include/crypto/public_key.h
 create mode 100644 include/keys/asymmetric-parser.h
 create mode 100644 include/keys/asymmetric-subtype.h
 create mode 100644 include/keys/asymmetric-type.h
 create mode 100644 include/linux/asn1.h
 create mode 100644 include/linux/asn1_ber_bytecode.h
 create mode 100644 include/linux/asn1_decoder.h
 create mode 100644 include/linux/oid_registry.h
 create mode 100644 kernel/modsign_pubkey.c
 create mode 100644 kernel/module-internal.h
 create mode 100644 kernel/module_signing.c
 create mode 100644 lib/asn1_decoder.c
 create mode 100755 lib/build_OID_registry
 create mode 100644 lib/mpi/mpi-cmp.c
 create mode 100644 lib/oid_registry.c
 create mode 100644 scripts/asn1_compiler.c
 create mode 100644 scripts/sign-file
 create mode 100755 scripts/x509keyid

--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#15 lore raw
Quoted 4 lines · Dmitry

Just one question about key description...
request_asymmetric_key uses format for key description: "<signer>: <key-id>". Preparsing code creates description from those values.
I see that key id is not 8 bytes anymore but full hash size of 20 bytes.

Remember: This is for viewing via /proc/keys and KEYCTL_DESCRIBE as much as for matching.

Quoted 2 lines

For practical reasons for IMA it might be nice to save some space in xattrs and use shorter key id/description.

That's reasonable.

Quoted 2 lines

As I understand from implementation, if key name is provided with "keyctl add", it will not be replaced with preparsed value.

Correct.

Quoted 1 line

And we can actually use any keyid we want?

Yes.

Note: The key type ->match() function is not required to limit itself to a direct strcmp(). It is at liberty to partially match the description or any other data attached to the key.

Look at asymmetric_key_match() in crypto/asymmetric/asymmetric_type.c. If you do a search for:

	"id:<hex-string>"

this will do a partial tail match on the key fingerprint:

[root@andromeda ~]# keyctl padd asymmetric "" @s </tmp/uefi-x509 289786205
[root@andromeda ~]# cat /proc/keys
1145c95d I--Q--- 1 perm 39390000 0 0 asymmetri Red Hat Test Certificate: 3580cf35d76b3b667a40df66691cbcf87353b23c: X509.RSA 7353b23c []
...
[root@andromeda ~]# keyctl search @s asymmetric "id:53b23c" 289786205

As an optimisation, it might be worth internally calling keyring_search_aux() with our own match function that takes a binary key ID and storing the fingerprint as binary rather than hex (attached to key->type_data.p[1]).

The type match function can only take text strings as it has to be invoked from userspace.

David

#16 lore raw
In reply to David Howells
Quoted 4 lines · David Howells

The module signing patches provide:

- Some fixes to Rusty's patch. Also an additional patch to extend the policy handling for modules signed with an unknown key and to handle FIPS mode.

Ok, I merged some of this (after our previous accidentally-off-list discussion).

Quoted 3 lines · You previously

You can't compare them that easily. One has a FIPS-mode panic and the other doesn't. Do we want to panic if we reject an unsigned module in enforcing mode when we're in FIPS mode?

It's a line ball, but I think consistency wins. Not a validly signed module => panic.

The code becomes pretty straightforward then:

        if (!err) {
                info->sig_ok = true;
                return 0;
        }
        if (fips_enabled)
               panic("Module verification failed with error %d in FIPS mode\n",
                     err);
        if (err == -ENOKEY && !sig_enforce)
                err = 0;
        
        return err;

In preparation, I've changed that below (and also, fixed up the -ENOKEY which I said I'd do, and didn't).

Thanks,
Rusty.
PS. Agree with Kconfig options move, but I'll do that in separate patch.

From: Rusty Russell <[email protected]>
Subject: module: signature checking hook

We do a very simple search for a particular string appended to the module (which is cache-hot and about to be SHA'd anyway). There's both a config option and a boot parameter which control whether we accept (and taint) or fail with unsigned modules.

(Useful feedback and tweaks by David Howells <[email protected]>)

Documentation/kernel-parameters.txt +6 -0
@@ -1582,6 +1582,12 @@ bytes respectively. Such letter suffixes
 			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
include/linux/module.h +8 -0
@@ -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;
init/Kconfig +14 -0
@@ -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
kernel/Makefile +1 -0
@@ -55,6 +55,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock
 obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_MODULE_SIG) += module_signing.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
kernel/module-internal.h new file +13 -0
new file mode 100644
@@ -0,0 +1,13 @@
+/* Module internals
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells ([email protected])
+ *
+ * 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.
+ */
+
+extern int mod_verify_sig(const void *mod, unsigned long modlen,
+			  const void *sig, unsigned long siglen);
kernel/module.c +92 -1

129 lines not on this page · raw message

kernel/module_signing.c new file +22 -0
new file mode 100644
@@ -0,0 +1,22 @@
+/* Module signature checker
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells ([email protected])
+ *
+ * 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 "module-internal.h"
+
+/*
+ * Verify the signature on a module.
+ */
+int mod_verify_sig(const void *mod, unsigned long modlen,
+		   const void *sig, unsigned long siglen)
+{
+	return -ENOKEY;
+}
author maintainer
#17 lore raw
Quoted 4 lines · Rusty Russell

We do a very simple search for a particular string appended to the module (which is cache-hot and about to be SHA'd anyway). There's both a config option and a boot parameter which control whether we accept (and taint) or fail with unsigned modules.

I've adjusted your patch description to this:

We do a very simple search for a particular string appended to the module (which is cache-hot and about to be SHA'd anyway). There's both a config option and a boot parameter which control whether we accept or fail with unsigned modules and modules that are signed with an unknown key.

If module signing is enabled, the kernel will be tainted if a module is accepted that is unsigned or has a signature for which we don't have the key.

I think it's worth mentioning the policy for unknown keys and worth making clear under what circumstances we mean the kernel to be tainted.

David

#18 lore raw
Quoted 14 lines · David Howells
Quoted 4 lines · Rusty Russell

We do a very simple search for a particular string appended to the module (which is cache-hot and about to be SHA'd anyway). There's both a config option and a boot parameter which control whether we accept (and taint) or fail with unsigned modules.

I've adjusted your patch description to this:

We do a very simple search for a particular string appended to the module (which is cache-hot and about to be SHA'd anyway). There's both a config option and a boot parameter which control whether we accept or fail with unsigned modules and modules that are signed with an unknown key.

Quoted 6 lines

If module signing is enabled, the kernel will be tainted if a module is accepted that is unsigned or has a signature for which we don't have the key.

I think it's worth mentioning the policy for unknown keys and worth making clear under what circumstances we mean the kernel to be tainted.

Great! I checked your Kconfig help, too, which is states it clearly:

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.

Which is really nice, since the kernel Kconfig help messages tend to suck.

Thanks,
Rusty.

author maintainer
#19 lore raw

Hi Rusty,

Could you pull my tree?

David
---

The following changes since commit eeea3ac912207dcf759b95b2b4c36f96bce583bf:

Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc (2012-09-06 10:23:58 -0700)

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-modsign.git modsign-post-KS

for you to fetch changes up to 15765081423824e1ccc329264ae13f5ea87f3a85:

MODSIGN: Sign modules during the build process (2012-09-26 10:11:06 +0100)

----------------------------------------------------------------
(from the branch description for modsign-post-KS local branch)

post Kernel-Summit module signing
----------------------------------------------------------------
David Howells (24):
KEYS: Add payload preparsing opportunity prior to key instantiate or update
MPILIB: Provide count_leading/trailing_zeros() based on arch functions
KEYS: Document asymmetric key type
KEYS: Implement asymmetric key type
KEYS: Asymmetric key pluggable data parsers
KEYS: Asymmetric public-key algorithm crypto key subtype
KEYS: Provide signature verification with an asymmetric key
MPILIB: Reinstate mpi_cmp[_ui]() and export for RSA signature verification
RSA: Implement signature verification algorithm [PKCS#1 / RFC3447]
RSA: Fix signature verification for shorter signatures
X.509: Implement simple static OID registry
X.509: Add utility functions to render OIDs as strings
X.509: Add simple ASN.1 grammar compiler
X.509: Add an ASN.1 decoder
MPILIB: Provide a function to read raw data into an MPI
X.509: Add a crypto key parser for binary (DER) X.509 certificates
MODSIGN: Add FIPS policy
MODSIGN: Provide gitignore and make clean rules for extra files
MODSIGN: Provide Kconfig options
MODSIGN: Automatically generate module signing keys if missing
MODSIGN: Provide module signing public keys to the kernel
MODSIGN: Implement module signature checking
MODSIGN: Provide a script for generating a key ID from an X.509 cert
MODSIGN: Sign modules during the build process

Rusty Russell (1):
module: signature checking hook

 .gitignore                                |   14 +
 Documentation/crypto/asymmetric-keys.txt  |  312 ++++++
 Documentation/kernel-parameters.txt       |    6 +
 Documentation/security/keys.txt           |   50 +-
 Makefile                                  |    1 +
 crypto/Kconfig                            |    1 +
 crypto/Makefile                           |    1 +
 crypto/asymmetric_keys/.gitignore         |    1 +
 crypto/asymmetric_keys/Kconfig            |   38 +
 crypto/asymmetric_keys/Makefile           |   27 +
 crypto/asymmetric_keys/asymmetric_keys.h  |   15 +
 crypto/asymmetric_keys/asymmetric_type.c  |  274 +++++
 crypto/asymmetric_keys/public_key.c       |  108 ++
 crypto/asymmetric_keys/public_key.h       |   30 +
 crypto/asymmetric_keys/rsa.c              |  277 ++++++
 crypto/asymmetric_keys/signature.c        |   49 +
 crypto/asymmetric_keys/x509.asn1          |   60 ++
 crypto/asymmetric_keys/x509_cert_parser.c |  497 ++++++++++
 crypto/asymmetric_keys/x509_parser.h      |   36 +
 crypto/asymmetric_keys/x509_public_key.c  |  207 ++++
 crypto/asymmetric_keys/x509_rsakey.asn1   |    4 +
 fs/cifs/cifs_spnego.c                     |    6 +-
 fs/cifs/cifsacl.c                         |    8 +-
 include/asm-generic/bitops/count_zeros.h  |   57 ++
 include/crypto/public_key.h               |  108 ++
 include/keys/asymmetric-parser.h          |   37 +
 include/keys/asymmetric-subtype.h         |   55 +
 include/keys/asymmetric-type.h            |   25 +
 include/keys/user-type.h                  |    6 +-
 include/linux/asn1.h                      |   67 ++
 include/linux/asn1_ber_bytecode.h         |   87 ++
 include/linux/asn1_decoder.h              |   24 +
 include/linux/key-type.h                  |   35 +-
 include/linux/module.h                    |    8 +
 include/linux/mpi.h                       |    1 +
 include/linux/oid_registry.h              |   92 ++
 init/Kconfig                              |   68 ++
 kernel/Makefile                           |   57 ++
 kernel/modsign_pubkey.c                   |  112 +++
 kernel/module-internal.h                  |   15 +
 kernel/module.c                           |   97 +-
 kernel/module_signing.c                   |  243 +++++
 lib/.gitignore                            |    2 +-
 lib/Kconfig                               |    5 +
 lib/Makefile                              |   18 +
 lib/asn1_decoder.c                        |  477 +++++++++
 lib/build_OID_registry                    |  209 ++++
 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 +-
 lib/mpi/mpicoder.c                        |   55 +
 lib/oid_registry.c                        |  170 ++++
 net/ceph/crypto.c                         |    9 +-
 net/dns_resolver/dns_key.c                |    6 +-
 net/rxrpc/ar-key.c                        |   40 +-
 scripts/.gitignore                        |    1 +
 scripts/Makefile                          |    2 +
 scripts/Makefile.build                    |   11 +
 scripts/Makefile.modpost                  |   75 +-
 scripts/asn1_compiler.c                   | 1545 +++++++++++++++++++++++++++++
 scripts/sign-file                         |  115 +++
 scripts/x509keyid                         |  268 +++++
 security/keys/encrypted-keys/encrypted.c  |   16 +-
 security/keys/key.c                       |  114 ++-
 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 +-
 71 files changed, 6387 insertions(+), 244 deletions(-)
 create mode 100644 Documentation/crypto/asymmetric-keys.txt
 create mode 100644 crypto/asymmetric_keys/.gitignore
 create mode 100644 crypto/asymmetric_keys/Kconfig
 create mode 100644 crypto/asymmetric_keys/Makefile
 create mode 100644 crypto/asymmetric_keys/asymmetric_keys.h
 create mode 100644 crypto/asymmetric_keys/asymmetric_type.c
 create mode 100644 crypto/asymmetric_keys/public_key.c
 create mode 100644 crypto/asymmetric_keys/public_key.h
 create mode 100644 crypto/asymmetric_keys/rsa.c
 create mode 100644 crypto/asymmetric_keys/signature.c
 create mode 100644 crypto/asymmetric_keys/x509.asn1
 create mode 100644 crypto/asymmetric_keys/x509_cert_parser.c
 create mode 100644 crypto/asymmetric_keys/x509_parser.h
 create mode 100644 crypto/asymmetric_keys/x509_public_key.c
 create mode 100644 crypto/asymmetric_keys/x509_rsakey.asn1
 create mode 100644 include/asm-generic/bitops/count_zeros.h
 create mode 100644 include/crypto/public_key.h
 create mode 100644 include/keys/asymmetric-parser.h
 create mode 100644 include/keys/asymmetric-subtype.h
 create mode 100644 include/keys/asymmetric-type.h
 create mode 100644 include/linux/asn1.h
 create mode 100644 include/linux/asn1_ber_bytecode.h
 create mode 100644 include/linux/asn1_decoder.h
 create mode 100644 include/linux/oid_registry.h
 create mode 100644 kernel/modsign_pubkey.c
 create mode 100644 kernel/module-internal.h
 create mode 100644 kernel/module_signing.c
 create mode 100644 lib/asn1_decoder.c
 create mode 100755 lib/build_OID_registry
 create mode 100644 lib/mpi/mpi-cmp.c
 create mode 100644 lib/oid_registry.c
 create mode 100644 scripts/asn1_compiler.c
 create mode 100644 scripts/sign-file
 create mode 100755 scripts/x509keyid
#20 lore raw
Quoted 11 lines · David Howells

Hi Rusty,

Could you pull my tree?

David
---

The following changes since commit eeea3ac912207dcf759b95b2b4c36f96bce583bf:

Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc (2012-09-06 10:23:58 -0700)

Quoted 8 lines

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-modsign.git modsign-post-KS

for you to fetch changes up to 15765081423824e1ccc329264ae13f5ea87f3a85:

MODSIGN: Sign modules during the build process (2012-09-26 10:11:06 +0100)

warning: (MODULE_SIG) selects ASYMMETRIC_KEY_TYPE which has unmet direct dependencies (CRYPTO && KEYS)

Ah, I see:

+ select CONFIG_KEYS
+ select CONFIG_CRYPTO

I fixed this commit, rather than go around again.

Thanks,
Rusty.

author maintainer
#21 lore raw
Quoted 8 lines · Rusty Russell

warning: (MODULE_SIG) selects ASYMMETRIC_KEY_TYPE which has unmet direct dependencies (CRYPTO && KEYS)

Ah, I see:

(quoted diff) +2 -0
+	select CONFIG_KEYS
+	select CONFIG_CRYPTO

I fixed this commit, rather than go around again.

Thanks.

select is irritatingly broken in that regard.

David

author maintainer
#23 lore raw

Re: [PATCH 1/2] modsign: don't use bashism in sh scripts.

scripts/sign-file scripts=`dirname $0` · line 13

Quoted 2 lines · Rusty Russell
scripts/sign-file +1 -1
-    source ./.config
+    . ./.config

Does that make a difference?

#24 lore raw

Re: [PATCH 1/2] modsign: don't use bashism in sh scripts.

Quoted 6 lines · David Howells

scripts/sign-file scripts=`dirname $0` · line 13

Quoted 2 lines · Rusty Russell
scripts/sign-file +1 -1
-    source ./.config
+    . ./.config

Does that make a difference?

It does on Ubuntu, where /bin/sh => dash. "source" is a bashism.

Cheers,
Rusty.

#25 lore raw

PATCH 2/2 modules: don't call eu-strip if it doesn't exist.

In reply to David Howells
scripts/Makefile.modpost +3 -1
index 90b1bb1..2a4d1a1 100644
@@ -165,11 +165,13 @@ 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.
+EU_STRIP = $(shell which eu-strip || echo true)
+
 quiet_cmd_sign_ko_stripped_ko_unsigned = STRIP [M] $@
       cmd_sign_ko_stripped_ko_unsigned = \
 		cp $< $@ && \
 		strip -x -g $@ && \
-		eu-strip $@
+		$(EU_STRIP) $@
 
 ifeq ($(SIGN_MODULES),1)
 
#27 lore raw
In reply to David Howells
Quoted 3 lines · David Howells

Hi Rusty,

Could you pull my tree?

And after those three fixes, I still get all fail:

[    3.361036] Request for unknown module key 'Magrathea: Glacier signing key: 6

e03943da0f3b015ba6ed7f5e0cac4fe48680994' err -11

rusty@rusty-x201:~/devel/kernel/linux (tmp-merge)$ grep '^CONFIG.*\(CRYPTO\|KEY\|MODULE\)' .config CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_SHA512=y
CONFIG_NET_KEY=m
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_ATKBD=y
CONFIG_HID_EZKEY=y
CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y
CONFIG_KEYS=y
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_BLKCIPHER=m
CONFIG_CRYPTO_BLKCIPHER2=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_RNG=m
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_PCOMP2=y
CONFIG_CRYPTO_MANAGER=m
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=m
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_CRC32C_INTEL=m
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_BLOWFISH_COMMON=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_TWOFISH_COMMON=m
CONFIG_CRYPTO_DEFLATE=m
CONFIG_CRYPTO_ANSI_CPRNG=m
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
CONFIG_PUBLIC_KEY_ALGO_RSA=y

Clues welcome...
Rusty.

author maintainer
#28 lore raw
Quoted 4 lines · Rusty Russell

And after those three fixes, I still get all fail:

[    3.361036] Request for unknown module key 'Magrathea: Glacier signing key: 6

e03943da0f3b015ba6ed7f5e0cac4fe48680994' err -11

Can you look back further in your kernel output, see if you can spot the bit where it's trying to load the keys. Look for things from modsign_pubkey.c:

	pr_notice("Loading module verification certificates\n");
	...
			pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n",
			       PTR_ERR(key));
		else
			pr_notice("MODSIGN: Loaded cert '%s'\n",
				  key_ref_to_ptr(key)->description);
Quoted 1 line

CONFIG_CRYPTO_SHA1=m

Hmmm... I suspect it's that. We need a hash to verify the key's own signature too - and if you're using the key my autogen patch created for you, I think that would be SHA1, so that must be built in too.

If you can see your kernel log (assuming a panic doesn't prevent you), I suspect you'll see something like:

MODSIGN: Problem loading in-kernel X.509 certificate (-65)

which is -ENOPKG.

The answer would be to either select SHA1 in Kconfig or, if possible, to tell openssl to use the same hash algorithm to sign the key as we're going to use in signing the modules.

David

#29 lore raw
Quoted 18 lines · David Howells
Quoted 4 lines · Rusty Russell

And after those three fixes, I still get all fail:

[    3.361036] Request for unknown module key 'Magrathea: Glacier signing key: 6

e03943da0f3b015ba6ed7f5e0cac4fe48680994' err -11

Can you look back further in your kernel output, see if you can spot the bit where it's trying to load the keys. Look for things from modsign_pubkey.c:

	pr_notice("Loading module verification certificates\n");
	...
			pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n",
			       PTR_ERR(key));
		else
			pr_notice("MODSIGN: Loaded cert '%s'\n",
				  key_ref_to_ptr(key)->description);
Quoted 5 lines
Quoted 1 line

CONFIG_CRYPTO_SHA1=m

Hmmm... I suspect it's that. We need a hash to verify the key's own signature too - and if you're using the key my autogen patch created for you, I think that would be SHA1, so that must be built in too.

Right, I chose SHA-512 because everyone knows it's 512 times more secure than SHA-1.

I cherry-picked those two patches, and now I see:

[    2.808075] Loading module verification certificates
[    2.809331] X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 has expired
[    2.810500] MODSIGN: Problem loading in-kernel X.509 certificate (-127)

I noticed the Cert number didn't change with rebuilds: "distclean" didn't remove some files:

$ git clean -f -f -x -d
Removing extra_certificates
Removing signing_key.priv
Removing signing_key.x509
Removing signing_key.x509.keyid
Removing signing_key.x509.signer
Removing x509.genkey

Removing them didn't fix it either, but at least I got a new certificate.

This is x86-32 BTW. I've put the complete, built tree (minus .git dir) up at http://ozlabs.org/~rusty/linux-for-dhowells.tar.xz

Here's how I run it:
kvm -nographic -m 256 -net user,restrict=off -net nic,model=virtio -drive file=$QEMUIMAGE,index=0,media=disk,if=virtio -drive file=$QEMUIMAGEB,index=1,media=disk,if=virtio -kernel arch/x86/boot/bzImage -append "ro root=/dev/vda1 console=ttyS0 $*"

Thanks,
Rusty.

author maintainer
#30 lore raw
Quoted 3 lines · Rusty Russell
[    2.808075] Loading module verification certificates
[    2.809331] X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 has expired
[    2.810500] MODSIGN: Problem loading in-kernel X.509 certificate (-127)

Hmmm... Other people have seen that.

Ahhhhh!

I wonder if the problem is that the certificate is valid for 100 years.... That might well cause an overflow on a 32-bit system.

Could you try changing the '36500' in kernel/Makefile to something shorter, like 365?

David

#31 lore raw
Quoted 6 lines · David Howells
Quoted 3 lines · Rusty Russell
[    2.808075] Loading module verification certificates
[    2.809331] X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 has expired
[    2.810500] MODSIGN: Problem loading in-kernel X.509 certificate (-127)
Quoted 6 lines

Hmmm... Other people have seen that.

Ahhhhh!

I wonder if the problem is that the certificate is valid for 100 years.... That might well cause an overflow on a 32-bit system.

That does seem quite plausible. The comparisons are done with time_t, which boils down to 'long' and 100 years in seconds would overflow LONG_MAX.

Quoted 2 lines

Could you try changing the '36500' in kernel/Makefile to something shorter, like 365?

I tried two values today. One close to LONG_MAX (24800 or ~68 years), and 10 years (3650). The former still seemed to overflow, but specifying a 10yr lifetime appears to have worked.

josh

#32 lore raw
Quoted 18 lines · Josh Boyer
Quoted 6 lines · David Howells
Quoted 3 lines · Rusty Russell
[    2.808075] Loading module verification certificates
[    2.809331] X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 has expired
[    2.810500] MODSIGN: Problem loading in-kernel X.509 certificate (-127)
Quoted 6 lines

Hmmm... Other people have seen that.

Ahhhhh!

I wonder if the problem is that the certificate is valid for 100 years.... That might well cause an overflow on a 32-bit system.

That does seem quite plausible. The comparisons are done with time_t, which boils down to 'long' and 100 years in seconds would overflow LONG_MAX.

Quoted 6 lines
Quoted 2 lines

Could you try changing the '36500' in kernel/Makefile to something shorter, like 365?

I tried two values today. One close to LONG_MAX (24800 or ~68 years), and 10 years (3650). The former still seemed to overflow, but specifying a 10yr lifetime appears to have worked.

That's because the timestamp is absolute, right? Indeed, that seems to be the limit here.

Here's my solution (tested, and it breaks if you change 2147300000 to 2147600000 as expected):

Quoted 1 line

From 2a4b91c2c29739191c6f7db9abee9296ae505c39 Mon Sep 17 00:00:00 2001

From: Rusty Russell <[email protected]>
Date: Tue, 2 Oct 2012 12:55:06 +0930
Subject: [PATCH] MODSIGN: fix expiry of auto-generated certificates on 32-bit
systems

100-year certificates make time_t wrap, resulting in:

[    2.835272] X.509: Cert a94f6776f3f5483b0764011d1fcc6c0298362e63 has expired
[    2.836346] MODSIGN: Problem loading in-kernel X.509 certificate (-127)
kernel/Makefile +9 -1
index e951adf..86336c9 100644
@@ -168,6 +168,13 @@ endif
 ifeq ($(sign_key_with_hash),)
 $(error Could not determine digest type to use from kernel config)
 endif
+ifeq ($(CONFIG_64BIT),y)
+# 100 years is beyond my best-before date, anyway.
+end_of_time_days=36500
+else
+# Until 32-bit time_t wraps, with some slack.
+end_of_time_days=$(shell expr \( 2147300000 - `date -u +%s` \) / 86400 )
+endif
 
 signing_key.priv signing_key.x509: x509.genkey
 	@echo "###"
@@ -180,7 +187,8 @@ signing_key.priv signing_key.x509: x509.genkey
 	@echo "###"
 	@echo "###     rngd -r /dev/hwrandom"
 	@echo "###"
-	openssl req -new -nodes -utf8 $(sign_key_with_hash) -days 36500 -batch \
+	openssl req -new -nodes -utf8 $(sign_key_with_hash) \
+		-days $(end_of_time_days) -batch \
 		-x509 -config x509.genkey \
 		-outform DER -out signing_key.x509 \
 		-keyout signing_key.priv
#33 lore raw
Quoted 23 lines · Rusty Russell
Quoted 21 lines · Josh Boyer
Quoted 6 lines · David Howells
Quoted 3 lines · Rusty Russell
[    2.808075] Loading module verification certificates
[    2.809331] X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 has expired
[    2.810500] MODSIGN: Problem loading in-kernel X.509 certificate (-127)
Quoted 6 lines

Hmmm... Other people have seen that.

Ahhhhh!

I wonder if the problem is that the certificate is valid for 100 years.... That might well cause an overflow on a 32-bit system.

That does seem quite plausible. The comparisons are done with time_t, which boils down to 'long' and 100 years in seconds would overflow LONG_MAX.

Quoted 2 lines

Could you try changing the '36500' in kernel/Makefile to something shorter, like 365?

Quoted 6 lines
Quoted 3 lines

I tried two values today. One close to LONG_MAX (24800 or ~68 years), and 10 years (3650). The former still seemed to overflow, but specifying a 10yr lifetime appears to have worked.

That's because the timestamp is absolute, right? Indeed, that seems to be the limit here.

Yep.

Quoted 35 lines

Here's my solution (tested, and it breaks if you change 2147300000 to 2147600000 as expected):

From 2a4b91c2c29739191c6f7db9abee9296ae505c39 Mon Sep 17 00:00:00 2001
From: Rusty Russell <[email protected]>
Date: Tue, 2 Oct 2012 12:55:06 +0930
Subject: [PATCH] MODSIGN: fix expiry of auto-generated certificates on 32-bit
systems

100-year certificates make time_t wrap, resulting in:

[    2.835272] X.509: Cert a94f6776f3f5483b0764011d1fcc6c0298362e63 has expired
[    2.836346] MODSIGN: Problem loading in-kernel X.509 certificate (-127)
kernel/Makefile +7 -0
index e951adf..86336c9 100644
@@ -168,6 +168,13 @@ endif
 ifeq ($(sign_key_with_hash),)
 $(error Could not determine digest type to use from kernel config)
 endif
+ifeq ($(CONFIG_64BIT),y)
+# 100 years is beyond my best-before date, anyway.
+end_of_time_days=36500
+else
+# Until 32-bit time_t wraps, with some slack.
+end_of_time_days=$(shell expr \( 2147300000 - `date -u +%s` \) / 86400 )
+endif
 
 signing_key.priv signing_key.x509: x509.genkey
 	@echo "###"

kernel/Makefile signing_key.priv signing_key.x509: x509.genkey · line 194

Quoted 9 lines
kernel/Makefile +2 -1
@@ -180,7 +187,8 @@ signing_key.priv signing_key.x509: x509.genkey
 	@echo "###"
 	@echo "###     rngd -r /dev/hwrandom"
 	@echo "###"
-	openssl req -new -nodes -utf8 $(sign_key_with_hash) -days 36500 -batch \
+	openssl req -new -nodes -utf8 $(sign_key_with_hash) \
+		-days $(end_of_time_days) -batch \
 		-x509 -config x509.genkey \
 		-outform DER -out signing_key.x509 \
 		-keyout signing_key.priv

That would likely work just fine. David actually has another patch that makes 100yrs still work on 32-bit as well that I've tested locally in a KVM instance. He was waiting on positive testing confirmation from me so hopefully he'll send it soon.

josh

author maintainer
#34 lore raw
In reply to Rusty Russell
Quoted 10 lines · Rusty Russell

I noticed the Cert number didn't change with rebuilds: "distclean" didn't remove some files:

$ git clean -f -f -x -d
Removing extra_certificates
Removing signing_key.priv
Removing signing_key.x509
Removing signing_key.x509.keyid
Removing signing_key.x509.signer
Removing x509.genkey

I'm not sure whether distclean should remove those, since they can be externally supplied, or whether x509.genkey should have a Makefile dependency on kernel/Makefile.

I lean towards 'yes' when I'm altering kernel/Makefile trying to get things right, and 'no' when I'm doing a make distclean to change my config or changing kernel/Makefile for some unrelated reason.

David

#35 lore raw
Quoted 13 lines · David Howells
Quoted 10 lines · Rusty Russell

I noticed the Cert number didn't change with rebuilds: "distclean" didn't remove some files:

$ git clean -f -f -x -d
Removing extra_certificates
Removing signing_key.priv
Removing signing_key.x509
Removing signing_key.x509.keyid
Removing signing_key.x509.signer
Removing x509.genkey
Quoted 7 lines

I'm not sure whether distclean should remove those, since they can be externally supplied, or whether x509.genkey should have a Makefile dependency on kernel/Makefile.

I lean towards 'yes' when I'm altering kernel/Makefile trying to get things right, and 'no' when I'm doing a make distclean to change my config or changing kernel/Makefile for some unrelated reason.

Right. I think we need to use different names for generated vs supplied files, then, because 'distclean' really must delete generated files.

But it turns out you do try to clean these files, it just doesn't work. See below. I've applied this, as well, to my tree:

git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux.git modules-next

BTW, you missed a Signed-off-by: on your "MODSIGN: Use the same digest for the autogen key sig as for the module sig" patch. Please update.

Cheers,
Rusty.

Quoted 1 line

From 8921e2ede91f93dcdbd08fa6613f8458de5f8afe Mon Sep 17 00:00:00 2001

From: Rusty Russell <[email protected]>
Date: Tue, 2 Oct 2012 14:35:24 +0930
Subject: [PATCH] MODSIGN: Make mrproper should remove generated files.

It doesn't, because the clean targets don't include kernel/Makefile, and because two files were missing from the list.

Makefile +4 -1
index 1c88ec3..e70ebfe 100644
@@ -995,7 +995,10 @@ MRPROPER_DIRS  += include/config usr/include include/generated          \
                   arch/*/include/generated
 MRPROPER_FILES += .config .config.old .version .old_version             \
                   include/linux/version.h                               \
-		  Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
+		  Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
+		  signing_key.priv signing_key.x509 x509.genkey		\
+		  extra_certificates signing_key.x509.keyid		\
+		  signing_key.x509.signer
 
 # clean - Delete most, but leave enough to build external modules
 #
kernel/Makefile +0 -1
index 86336c9..bb94783 100644
@@ -216,4 +216,3 @@ x509.genkey:
 	@echo >>x509.genkey "subjectKeyIdentifier=hash"
 	@echo >>x509.genkey "authorityKeyIdentifier=keyid"
 endif
-CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey extra_certificates
author maintainer
#36 lore raw
Quoted 2 lines · Rusty Russell

Right. I think we need to use different names for generated vs supplied files

The problem with supplied files is people who do allyesconfig, allmodconfig and randconfig just to test things finding that their builds break. The kernel build magic is not really set up to handle external files like this. I suppose make logic can be used to conditionally include stuff that might not exist.

Quoted 2 lines

BTW, you missed a Signed-off-by: on your "MODSIGN: Use the same digest for the autogen key sig as for the module sig" patch. Please update.

Done.

I've also added a patch to convert the system clock to a struct tm and to produce a struct tm within the ASN.1 decode and then compare those rather than time_t values as a way to deal with the validity time overflow problem. We may have to be able to handle certificates that we haven't generated that stretch beyond 2038 (I wonder if we might find such in the UEFI key database for example.

Another way of dealing with this could be to make mktime() within the kernel produce a u64 rather than an unsigned long, and then compare those.

David

#37 lore raw
Quoted 14 lines · David Howells
Quoted 2 lines · Rusty Russell

Right. I think we need to use different names for generated vs supplied files

The problem with supplied files is people who do allyesconfig, allmodconfig and randconfig just to test things finding that their builds break. The kernel build magic is not really set up to handle external files like this. I suppose make logic can be used to conditionally include stuff that might not exist.

Quoted 2 lines

BTW, you missed a Signed-off-by: on your "MODSIGN: Use the same digest for the autogen key sig as for the module sig" patch. Please update.

Quoted 8 lines

Done.

I've also added a patch to convert the system clock to a struct tm and to produce a struct tm within the ASN.1 decode and then compare those rather than time_t values as a way to deal with the validity time overflow problem. We may have to be able to handle certificates that we haven't generated that stretch beyond 2038 (I wonder if we might find such in the UEFI key database for example.

OK, cherry-picked to replace my hack.

It's in linux-next, and I will push in the next two days.

Thanks,
Rusty.

#38 lore raw
Quoted 25 lines · Rusty Russell
Quoted 14 lines · David Howells
Quoted 2 lines · Rusty Russell

Right. I think we need to use different names for generated vs supplied files

The problem with supplied files is people who do allyesconfig, allmodconfig and randconfig just to test things finding that their builds break. The kernel build magic is not really set up to handle external files like this. I suppose make logic can be used to conditionally include stuff that might not exist.

Quoted 2 lines

BTW, you missed a Signed-off-by: on your "MODSIGN: Use the same digest for the autogen key sig as for the module sig" patch. Please update.

Quoted 8 lines

Done.

I've also added a patch to convert the system clock to a struct tm and to produce a struct tm within the ASN.1 decode and then compare those rather than time_t values as a way to deal with the validity time overflow problem. We may have to be able to handle certificates that we haven't generated that stretch beyond 2038 (I wonder if we might find such in the UEFI key database for example.

Quoted 4 lines

OK, cherry-picked to replace my hack.

It's in linux-next, and I will push in the next two days.

http://git.kernel.org/?p=linux/kernel/git/rusty/linux.git;a=commit;h=a15e196c5543d1d2d7f0cd70e62351aeb1f8b871

It breaks bisect..

CC kernel/module_signing.o
kernel/module_signing.c: In function ‘mod_verify_sig’:
kernel/module_signing.c:21:10: error: ‘ENOKEY’ undeclared (first use in this function)
kernel/module_signing.c:21:10: note: each undeclared identifier is reported only once for each function it appears in kernel/module_signing.c:22:1: warning: control reaches end of non-void function [-Wreturn-type]
make[1]: *** [kernel/module_signing.o] Error 1
make: *** [kernel] Error 2
make: *** Waiting for unfinished jobs....

Quoted 6 lines

Thanks,
Rusty.
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#39 lore raw
Quoted 4 lines · Dmitry

http://git.kernel.org/?p=linux/kernel/git/rusty/linux.git;a=commit;h=a15e196c5543d1d2d7f0cd70e62351aeb1f8b871

It breaks bisect..

Quoted 11 lines

CC kernel/module_signing.o
kernel/module_signing.c: In function ‘mod_verify_sig’:
kernel/module_signing.c:21:10: error: ‘ENOKEY’ undeclared (first use in this function)
kernel/module_signing.c:21:10: note: each undeclared identifier is reported only once for each function it appears in kernel/module_signing.c:22:1: warning: control reaches end of non-void function [-Wreturn-type]
make[1]: *** [kernel/module_signing.o] Error 1
make: *** [kernel] Error 2
make: *** Waiting for unfinished jobs....

Ah, my mistake; missing #include. I've fixed this which unfortunately meant a rebase.

Thanks,
Rusty.

author maintainer
#40 lore raw
In reply to Rusty Russell
Quoted 2 lines · Rusty Russell
[    3.361036] Request for unknown module key 'Magrathea: Glacier signing key: 6

e03943da0f3b015ba6ed7f5e0cac4fe48680994' err -11

Okay, it turns out that my attempts to remove SHA1 by editing it out of the .config file were doomed to failure because a couple of IPv6 options I had turned on selected it back on.

Having turned those off and then turned off SHA1, I see in the kernel log:

MODSIGN: Problem loading in-kernel X.509 certificate (-65)
MODSIGN: Loaded cert 'Red Hat Test Certificate: 3580cf35d76b3b667a40df66691cbcf87353b23c'

My kernel has an extra certificate (in the extra_certificates file) given to me by Peter Jones in addition to the one it generates itself.

The first line is it failing to load the transient SHA1-hashed cert that was generated by the kernel build (the Magrathean glacier signing key).

The second line is it managing to load the certificate that Peter gave me for which it doesn't have the parent CA certificate available. I've made the assumption (which isn't necessarily warranted) that the signature in the cert, if the cert is not self-signed, is generated using the CA private key, not by the private key corresponding to this cert.

David

author maintainer
#41 lore raw
In reply to Rusty Russell

Hi Rusty,

I've pushed two additional patches. The first makes the X.509 cert signature use the same hash algorithm as the signatures on the modules - which should fix the problem you're seeing, I think. The second makes elements of the names use UTF8 strings, just in case someone wants to use accented characters.

David
---

The following changes since commit 15765081423824e1ccc329264ae13f5ea87f3a85:

MODSIGN: Sign modules during the build process (2012-09-26 10:11:06 +0100)

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-modsign.git modsign-post-KS

for you to fetch changes up to 9034de9a2c376229e2309eed7e2c871785b5890f:

MODSIGN: Use utf8 strings in signer's name in autogenerated X.509 certs (2012-09-28 11:16:57 +0100)

----------------------------------------------------------------
(from the branch description for modsign-post-KS local branch)

post Kernel-Summit module signing
----------------------------------------------------------------
David Howells (2):
MODSIGN: Use the same digest for the autogen key sig as for the module sig
MODSIGN: Use utf8 strings in signer's name in autogenerated X.509 certs

 kernel/Makefile | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)
#42 lore raw

PATCH 1/1 MODSIGN: Fix build error with strict typechecking

In reply to David Howells

"MODSIGN: Provide module signing public keys to the kernel" causes a build error when CONFIG_UIDGID_STRICT_TYPE_CHECKS is enabled:

kernel/modsign_pubkey.c: In function 'module_verify_init':
kernel/modsign_pubkey.c:47: error: incompatible type for argument 3 of 'key_alloc' include/linux/key.h:195: note: expected 'kuid_t' but argument is of type 'int' kernel/modsign_pubkey.c:47: error: incompatible type for argument 4 of 'key_alloc' include/linux/key.h:195: note: expected 'kgid_t' but argument is of type 'int'

Cast the parameters accordingly.

---
 kernel/modsign_pubkey.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
kernel/modsign_pubkey.c +2 -1
@@ -41,7 +41,8 @@ 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(),
+				    KUIDT_INIT(0), KGIDT_INIT(0),
+				    current_cred(),
 				    (KEY_POS_ALL & ~KEY_POS_SETATTR) |
 				    KEY_USR_VIEW | KEY_USR_READ,
 				    KEY_ALLOC_NOT_IN_QUOTA);
#43 lore raw
In reply to Rusty Russell
Quoted 8 lines · Rusty Russell
Quoted 4 lines · David Howells

The module signing patches provide:

- Some fixes to Rusty's patch. Also an additional patch to extend the policy handling for modules signed with an unknown key and to handle FIPS mode.

Ok, I merged some of this (after our previous accidentally-off-list discussion).

Rusty, have you pushed this branch out yet?

thanks,

Mimi

#44 lore raw
Quoted 7 lines · Mimi Zohar
Quoted 6 lines · Rusty Russell
Quoted 4 lines · David Howells

The module signing patches provide:

- Some fixes to Rusty's patch. Also an additional patch to extend the policy handling for modules signed with an unknown key and to handle FIPS mode.

Quoted 8 lines
Quoted 2 lines

Ok, I merged some of this (after our previous accidentally-off-list discussion).

Rusty, have you pushed this branch out yet?

thanks,

Mimi

git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux.git modules-next

(That's *not* where linux-next currently pulls from)

Cheers,
Rusty.

#45 lore raw
In reply to Rusty Russell
Quoted 7 lines · Rusty Russell
Quoted 3 lines · You previously

You can't compare them that easily. One has a FIPS-mode panic and the other doesn't. Do we want to panic if we reject an unsigned module in enforcing mode when we're in FIPS mode?

It's a line ball, but I think consistency wins. Not a validly signed module => panic.

Just wondering, what's the advantage of doing panic over just rejecting the module?
Panic is a DoS?

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

author maintainer
#46 lore raw
Quoted 3 lines · Geert Uytterhoeven

Just wondering, what's the advantage of doing panic over just rejecting the module?
Panic is a DoS?

FIPS mode is strange like that.

David