2012-09-25 00:07:39

by David Howells

[permalink] [raw]
Subject: [GIT PULL] Asymmetric keys and module signing


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


2012-09-25 00:12:16

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

David Howells <[email protected]> wrote:

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

2012-09-25 15:10:05

by David Howells

[permalink] [raw]
Subject: Wrong system clock vs X.509 date specifiers


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

2012-09-25 15:30:37

by Alan Cox

[permalink] [raw]
Subject: Re: Wrong system clock vs X.509 date specifiers

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



2012-09-25 15:35:38

by David Howells

[permalink] [raw]
Subject: Re: Wrong system clock vs X.509 date specifiers

Alan Cox <[email protected]> wrote:

> 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

2012-09-25 15:43:50

by Paolo Bonzini

[permalink] [raw]
Subject: Re: Wrong system clock vs X.509 date specifiers

Il 25/09/2012 17:35, David Howells ha scritto:
> Alan Cox <[email protected]> wrote:
>
>> > 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

2012-09-25 15:44:38

by Kasatkin, Dmitry

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

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


On Tue, Sep 25, 2012 at 3:07 AM, David Howells <[email protected]> wrote:
>
> 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

2012-09-25 16:00:20

by Alan Cox

[permalink] [raw]
Subject: Re: Wrong system clock vs X.509 date specifiers

On Tue, 25 Sep 2012 16:35:20 +0100
David Howells <[email protected]> wrote:

> Alan Cox <[email protected]> wrote:
>
> > 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



2012-09-25 16:03:20

by Tomas Mraz

[permalink] [raw]
Subject: Re: Wrong system clock vs X.509 date specifiers

On Tue, 2012-09-25 at 16:35 +0100, David Howells wrote:
> Alan Cox <[email protected]> wrote:
>
> > 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).
--
Tomas Mraz
No matter how far down the wrong road you've gone, turn back.
Turkish proverb

2012-09-25 16:15:17

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

Kasatkin, Dmitry <[email protected]> wrote:

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

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

That's reasonable.

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

Correct.

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

[[email protected] ~]# keyctl padd asymmetric "" @s </tmp/uefi-x509
289786205
[[email protected] ~]# cat /proc/keys
1145c95d I--Q--- 1 perm 39390000 0 0 asymmetri Red Hat Test Certificate: 3580cf35d76b3b667a40df66691cbcf87353b23c: X509.RSA 7353b23c []
...
[[email protected] ~]# 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

2012-09-25 17:31:43

by David Howells

[permalink] [raw]
Subject: Re: Wrong system clock vs X.509 date specifiers

Tomas Mraz <[email protected]> wrote:

> 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

2012-09-25 18:39:29

by Tomas Mraz

[permalink] [raw]
Subject: Re: Wrong system clock vs X.509 date specifiers

On Tue, 2012-09-25 at 18:31 +0100, David Howells wrote:
> Tomas Mraz <[email protected]> wrote:
>
> > 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?

You can configure it to point to a different directories. But yes, you
have to create a CA cert and so on.
--
Tomas Mraz
No matter how far down the wrong road you've gone, turn back.
Turkish proverb

2012-09-25 21:57:06

by David Howells

[permalink] [raw]
Subject: 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([email protected])
{
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();

2012-09-26 03:47:57

by Rusty Russell

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

David Howells <[email protected]> writes:
> 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).

You previously wrote:
> 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]>)

Signed-off-by: Rusty Russell <[email protected]>

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -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
diff --git a/include/linux/module.h b/include/linux/module.h
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -21,6 +21,9 @@
#include <linux/percpu.h>
#include <asm/module.h>

+/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
+#define MODULE_SIG_STRING "~Module signature appended~\n"
+
/* Not Yet Implemented */
#define MODULE_SUPPORTED_DEVICE(name)

@@ -260,6 +263,11 @@ struct module
const unsigned long *unused_gpl_crcs;
#endif

+#ifdef CONFIG_MODULE_SIG
+ /* Signature was verified. */
+ bool sig_ok;
+#endif
+
/* symbols that will be GPL-only in the near future. */
const struct kernel_symbol *gpl_future_syms;
const unsigned long *gpl_future_crcs;
diff --git a/init/Kconfig b/init/Kconfig
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1585,6 +1585,20 @@ config MODULE_SRCVERSION_ALL
the version). With this option, such a "srcversion" field
will be created for all modules. If unsure, say N.

+config MODULE_SIG
+ bool "Module signature verification"
+ depends on MODULES
+ help
+ Check modules for valid signatures upon load: the signature
+ is simply appended to the module. For more information see
+ Documentation/module-signing.txt.
+
+config MODULE_SIG_FORCE
+ bool "Require modules to be validly signed"
+ depends on MODULE_SIG
+ help
+ Reject unsigned modules or signed modules for which we don't have a
+ key. Without this, such modules will simply taint the kernel.
endif # MODULES

config INIT_ALL_POSSIBLE
diff --git a/kernel/Makefile b/kernel/Makefile
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -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
diff --git a/kernel/module-internal.h b/kernel/module-internal.h
new file mode 100644
--- /dev/null
+++ b/kernel/module-internal.h
@@ -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);
diff --git a/kernel/module.c b/kernel/module.c
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -58,6 +58,7 @@
#include <linux/jump_label.h>
#include <linux/pfn.h>
#include <linux/bsearch.h>
+#include "module-internal.h"

#define CREATE_TRACE_POINTS
#include <trace/events/module.h>
@@ -102,6 +103,43 @@ static LIST_HEAD(modules);
struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
#endif /* CONFIG_KGDB_KDB */

+#ifdef CONFIG_MODULE_SIG
+#ifdef CONFIG_MODULE_SIG_FORCE
+static bool sig_enforce = true;
+#else
+static bool sig_enforce = false;
+
+static int param_set_bool_enable_only(const char *val,
+ const struct kernel_param *kp)
+{
+ int err;
+ bool test;
+ struct kernel_param dummy_kp = *kp;
+
+ dummy_kp.arg = &test;
+
+ err = param_set_bool(val, &dummy_kp);
+ if (err)
+ return err;
+
+ /* Don't let them unset it once it's set! */
+ if (!test && sig_enforce)
+ return -EROFS;
+
+ if (test)
+ sig_enforce = true;
+ return 0;
+}
+
+static const struct kernel_param_ops param_ops_bool_enable_only = {
+ .set = param_set_bool_enable_only,
+ .get = param_get_bool,
+};
+#define param_check_bool_enable_only param_check_bool
+
+module_param(sig_enforce, bool_enable_only, 0644);
+#endif /* !CONFIG_MODULE_SIG_FORCE */
+#endif /* CONFIG_MODULE_SIG */

/* Block module loading/unloading? */
int modules_disabled = 0;
@@ -136,6 +174,7 @@ struct load_info {
unsigned long symoffs, stroffs;
struct _ddebug *debug;
unsigned int num_debug;
+ bool sig_ok;
struct {
unsigned int sym, str, mod, vers, info, pcpu;
} index;
@@ -2379,7 +2418,49 @@ static inline void kmemleak_load_module(
}
#endif

-/* Sets info->hdr and info->len. */
+#ifdef CONFIG_MODULE_SIG
+static int module_sig_check(struct load_info *info,
+ const void *mod, unsigned long *len)
+{
+ int err = -ENOKEY;
+ const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
+ const void *p = mod, *end = mod + *len;
+
+ /* Poor man's memmem. */
+ while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) {
+ if (p + markerlen > end)
+ break;
+
+ if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) {
+ const void *sig = p + markerlen;
+ /* Truncate module up to signature. */
+ *len = p - mod;
+ err = mod_verify_sig(mod, *len, sig, end - sig);
+ break;
+ }
+ p++;
+ }
+
+ if (!err) {
+ info->sig_ok = true;
+ return 0;
+ }
+
+ /* Not having a signature is only an error if we're strict. */
+ if (err == -ENOKEY && !sig_enforce)
+ err = 0;
+
+ return err;
+}
+#else /* !CONFIG_MODULE_SIG */
+static int module_sig_check(struct load_info *info,
+ void *mod, unsigned long *len)
+{
+ return 0;
+}
+#endif /* !CONFIG_MODULE_SIG */
+
+/* Sets info->hdr, info->len and info->sig_ok. */
static int copy_and_check(struct load_info *info,
const void __user *umod, unsigned long len,
const char __user *uargs)
@@ -2399,6 +2480,10 @@ static int copy_and_check(struct load_in
goto free_hdr;
}

+ err = module_sig_check(info, hdr, &len);
+ if (err)
+ goto free_hdr;
+
/* Sanity checks against insmoding binaries or wrong arch,
weird elf version */
if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
@@ -2884,6 +2969,12 @@ static struct module *load_module(void _
goto free_copy;
}

+#ifdef CONFIG_MODULE_SIG
+ mod->sig_ok = info.sig_ok;
+ if (!mod->sig_ok)
+ add_taint_module(mod, TAINT_FORCED_MODULE);
+#endif
+
/* Now module is in final location, initialize linked lists, etc. */
err = module_unload_init(mod);
if (err)
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
new file mode 100644
--- /dev/null
+++ b/kernel/module_signing.c
@@ -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;
+}

2012-09-26 09:09:48

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

Rusty Russell <[email protected]> wrote:

> 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

2012-09-27 02:05:39

by Rusty Russell

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

David Howells <[email protected]> writes:

> Rusty Russell <[email protected]> wrote:
>
>> 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.

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.

2012-09-27 02:09:43

by Mimi Zohar

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

On Wed, 2012-09-26 at 13:16 +0930, Rusty Russell wrote:
> David Howells <[email protected]> writes:
> > 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

2012-09-27 09:08:25

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing



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

2012-09-28 06:07:17

by Rusty Russell

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

David Howells <[email protected]> writes:

> 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

[email protected]:~/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.

2012-09-28 05:55:17

by Rusty Russell

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

David Howells <[email protected]> writes:

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

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.

2012-09-28 05:58:23

by Rusty Russell

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

Signed-off-by: Rusty Russell <[email protected]>

diff --git a/scripts/sign-file b/scripts/sign-file
index 1a472bb..e58e34e 100644
--- a/scripts/sign-file
+++ b/scripts/sign-file
@@ -10,7 +10,7 @@ scripts=`dirname $0`
CONFIG_MODULE_SIG_SHA512=y
if [ -r .config ]
then
- source ./.config
+ . ./.config
fi

key="$1"

2012-09-28 05:59:03

by Rusty Russell

[permalink] [raw]
Subject: [PATCH 2/2] modules: don't call eu-strip if it doesn't exist.

Signed-off-by: Rusty Russell <[email protected]>

diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 90b1bb1..2a4d1a1 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -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] [email protected]
cmd_sign_ko_stripped_ko_unsigned = \
cp $< [email protected] && \
strip -x -g [email protected] && \
- eu-strip [email protected]
+ $(EU_STRIP) [email protected]

ifeq ($(SIGN_MODULES),1)


2012-09-28 06:27:08

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

On Wed, Sep 26, 2012 at 5:46 AM, Rusty Russell <[email protected]> wrote:
> You previously wrote:
>> 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

2012-09-28 06:55:12

by Rusty Russell

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

Mimi Zohar <[email protected]> writes:

> On Wed, 2012-09-26 at 13:16 +0930, Rusty Russell wrote:
>> David Howells <[email protected]> writes:
>> > 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

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.

2012-09-28 08:00:41

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

Geert Uytterhoeven <[email protected]> wrote:

> 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

2012-09-28 08:10:04

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing


Rusty Russell <[email protected]> wrote:

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

> 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

2012-09-28 08:11:43

by David Howells

[permalink] [raw]
Subject: Re: [PATCH 2/2] modules: don't call eu-strip if it doesn't exist.

Rusty Russell <[email protected]> wrote:

> Signed-off-by: Rusty Russell <[email protected]>

Acked-by: David Howells <[email protected]>

2012-09-28 08:10:33

by David Howells

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

Rusty Russell <[email protected]> wrote:

> - source ./.config
> + . ./.config

Does that make a difference?

2012-09-28 08:13:09

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

Rusty Russell <[email protected]> wrote:

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

select is irritatingly broken in that regard.

David

2012-09-28 09:23:25

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing


Rusty Russell <[email protected]> wrote:

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

2012-09-28 10:32:04

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing


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

2012-09-29 06:53:31

by Rusty Russell

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

David Howells <[email protected]> writes:
> Rusty Russell <[email protected]> wrote:
>
>> 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);
>
>> 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.

2012-09-29 07:14:30

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

Rusty Russell <[email protected]> wrote:

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

2012-09-29 07:16:50

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

Rusty Russell <[email protected]> wrote:

> 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

2012-10-01 20:41:50

by Josh Boyer

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

On Sat, Sep 29, 2012 at 08:13:25AM +0100, David Howells wrote:
> Rusty Russell <[email protected]> wrote:
>
> > [ 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.

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.

> 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

2012-10-02 06:30:32

by Rusty Russell

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

David Howells <[email protected]> writes:

> Rusty Russell <[email protected]> wrote:
>
>> 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.

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.

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

Signed-off-by: Rusty Russell <[email protected]>

diff --git a/Makefile b/Makefile
index 1c88ec3..e70ebfe 100644
--- a/Makefile
+++ b/Makefile
@@ -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
#
diff --git a/kernel/Makefile b/kernel/Makefile
index 86336c9..bb94783 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -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

2012-10-02 02:24:51

by Rusty Russell

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

David Howells <[email protected]> writes:

> Rusty Russell <[email protected]> wrote:
>
>> - source ./.config
>> + . ./.config
>
> Does that make a difference?

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

Cheers,
Rusty.

2012-10-02 03:28:03

by Rusty Russell

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

Josh Boyer <[email protected]> writes:

> On Sat, Sep 29, 2012 at 08:13:25AM +0100, David Howells wrote:
>> Rusty Russell <[email protected]> wrote:
>>
>> > [ 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.
>
> 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.
>
>> 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):

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

Signed-off-by: Rusty Russell <[email protected]>

diff --git a/kernel/Makefile b/kernel/Makefile
index e951adf..86336c9 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -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

2012-10-02 12:17:15

by Josh Boyer

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

On Tue, Oct 02, 2012 at 12:58:03PM +0930, Rusty Russell wrote:
> Josh Boyer <[email protected]> writes:
>
> > On Sat, Sep 29, 2012 at 08:13:25AM +0100, David Howells wrote:
> >> Rusty Russell <[email protected]> wrote:
> >>
> >> > [ 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.
> >
> > 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.
> >
> >> 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.

Yep.

> 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)
>
> Signed-off-by: Rusty Russell <[email protected]>
>
> diff --git a/kernel/Makefile b/kernel/Makefile
> index e951adf..86336c9 100644
> --- a/kernel/Makefile
> +++ b/kernel/Makefile
> @@ -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

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

2012-10-02 14:07:45

by David Howells

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

Rusty Russell <[email protected]> wrote:

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

> 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

2012-10-03 17:50:33

by David Rientjes

[permalink] [raw]
Subject: [patch] MODSIGN: Fix build error with strict typechecking

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

Signed-off-by: David Rientjes <[email protected]>
---
kernel/modsign_pubkey.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c
--- a/kernel/modsign_pubkey.c
+++ b/kernel/modsign_pubkey.c
@@ -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);

2012-10-04 01:24:04

by Rusty Russell

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

David Howells <[email protected]> writes:

> Rusty Russell <[email protected]> wrote:
>
>> 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.
>
>> 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.

OK, cherry-picked to replace my hack.

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

Thanks,
Rusty.

2012-10-09 10:55:30

by Kasatkin, Dmitry

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

On Thu, Oct 4, 2012 at 2:22 AM, Rusty Russell <[email protected]> wrote:
> David Howells <[email protected]> writes:
>
>> Rusty Russell <[email protected]> wrote:
>>
>>> 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.
>>
>>> 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.
>
> 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....

> 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

2012-10-10 09:37:11

by Rusty Russell

[permalink] [raw]
Subject: Re: [GIT PULL] Asymmetric keys and module signing

"Kasatkin, Dmitry" <[email protected]> writes:
> 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....

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

Thanks,
Rusty.

2013-03-14 10:48:28

by David Woodhouse

[permalink] [raw]
Subject: Re: Wrong system clock vs X.509 date specifiers

On Tue, 2012-09-25 at 16:30 +0100, Alan Cox wrote:
> 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.

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.

--
dwmw2


Attachments:
smime.p7s (6.03 kB)

2013-03-14 12:24:02

by David Woodhouse

[permalink] [raw]
Subject: [PATCH] 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...

Signed-off-by: David Woodhouse <[email protected]>
---

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.

diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 06007f0..326dc80 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -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];




--
David Woodhouse Open Source Technology Centre
[email protected] Intel Corporation


Attachments:
smime.p7s (6.03 kB)

2013-03-19 21:07:05

by Alexander Holler

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

Am 14.03.2013 13:24, schrieb David Woodhouse:
> 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...
>
> Signed-off-by: David Woodhouse <[email protected]>
> ---
>
> 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.
>
> diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
> index 06007f0..326dc80 100644
> --- a/crypto/asymmetric_keys/x509_public_key.c
> +++ b/crypto/asymmetric_keys/x509_public_key.c
> @@ -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];

Why not remove the check and warning there too?

Regards,

Alexander