1890 lines
63 KiB
Diff
1890 lines
63 KiB
Diff
From 775d395f8bd8ef08971c77f54c38ec7b9355ba4f Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:15:10 +0100
|
|
Subject: [PATCH 01/18] KEYS: Rename public key parameter name arrays
|
|
|
|
Rename the arrays of public key parameters (public key algorithm names, hash
|
|
algorithm names and ID type names) so that the array name ends in "_name".
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Reviewed-by: Josh Boyer <jwboyer@redhat.com>
|
|
---
|
|
crypto/asymmetric_keys/public_key.c | 14 +++++++-------
|
|
crypto/asymmetric_keys/x509_public_key.c | 8 ++++----
|
|
include/crypto/public_key.h | 6 +++---
|
|
kernel/module_signing.c | 4 ++--
|
|
4 files changed, 16 insertions(+), 16 deletions(-)
|
|
|
|
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
|
|
index cb2e291..b313df1 100644
|
|
--- a/crypto/asymmetric_keys/public_key.c
|
|
+++ b/crypto/asymmetric_keys/public_key.c
|
|
@@ -22,13 +22,13 @@
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
-const char *const pkey_algo[PKEY_ALGO__LAST] = {
|
|
+const char *const pkey_algo_name[PKEY_ALGO__LAST] = {
|
|
[PKEY_ALGO_DSA] = "DSA",
|
|
[PKEY_ALGO_RSA] = "RSA",
|
|
};
|
|
-EXPORT_SYMBOL_GPL(pkey_algo);
|
|
+EXPORT_SYMBOL_GPL(pkey_algo_name);
|
|
|
|
-const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
|
|
+const char *const pkey_hash_algo_name[PKEY_HASH__LAST] = {
|
|
[PKEY_HASH_MD4] = "md4",
|
|
[PKEY_HASH_MD5] = "md5",
|
|
[PKEY_HASH_SHA1] = "sha1",
|
|
@@ -38,13 +38,13 @@ const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
|
|
[PKEY_HASH_SHA512] = "sha512",
|
|
[PKEY_HASH_SHA224] = "sha224",
|
|
};
|
|
-EXPORT_SYMBOL_GPL(pkey_hash_algo);
|
|
+EXPORT_SYMBOL_GPL(pkey_hash_algo_name);
|
|
|
|
-const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = {
|
|
+const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = {
|
|
[PKEY_ID_PGP] = "PGP",
|
|
[PKEY_ID_X509] = "X509",
|
|
};
|
|
-EXPORT_SYMBOL_GPL(pkey_id_type);
|
|
+EXPORT_SYMBOL_GPL(pkey_id_type_name);
|
|
|
|
/*
|
|
* Provide a part of a description of the key for /proc/keys.
|
|
@@ -56,7 +56,7 @@ static void public_key_describe(const struct key *asymmetric_key,
|
|
|
|
if (key)
|
|
seq_printf(m, "%s.%s",
|
|
- pkey_id_type[key->id_type], key->algo->name);
|
|
+ pkey_id_type_name[key->id_type], key->algo->name);
|
|
}
|
|
|
|
/*
|
|
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
|
|
index 06007f0..afbbc36 100644
|
|
--- a/crypto/asymmetric_keys/x509_public_key.c
|
|
+++ b/crypto/asymmetric_keys/x509_public_key.c
|
|
@@ -49,7 +49,7 @@ static int x509_check_signature(const struct public_key *pub,
|
|
/* Allocate the hashing algorithm we're going to need and find out how
|
|
* big the hash operational data will be.
|
|
*/
|
|
- tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_hash_algo], 0, 0);
|
|
+ tfm = crypto_alloc_shash(pkey_hash_algo_name[cert->sig_hash_algo], 0, 0);
|
|
if (IS_ERR(tfm))
|
|
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
|
|
|
|
@@ -117,7 +117,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
|
|
pr_devel("Cert Issuer: %s\n", cert->issuer);
|
|
pr_devel("Cert Subject: %s\n", cert->subject);
|
|
- pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]);
|
|
+ pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pkey_algo]);
|
|
pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
|
|
cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
|
|
cert->valid_from.tm_mday, cert->valid_from.tm_hour,
|
|
@@ -127,8 +127,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
cert->valid_to.tm_mday, cert->valid_to.tm_hour,
|
|
cert->valid_to.tm_min, cert->valid_to.tm_sec);
|
|
pr_devel("Cert Signature: %s + %s\n",
|
|
- pkey_algo[cert->sig_pkey_algo],
|
|
- pkey_hash_algo[cert->sig_hash_algo]);
|
|
+ pkey_algo_name[cert->sig_pkey_algo],
|
|
+ pkey_hash_algo_name[cert->sig_hash_algo]);
|
|
|
|
if (!cert->fingerprint || !cert->authority) {
|
|
pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
|
|
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
|
|
index f5b0224..619d570 100644
|
|
--- a/include/crypto/public_key.h
|
|
+++ b/include/crypto/public_key.h
|
|
@@ -22,7 +22,7 @@ enum pkey_algo {
|
|
PKEY_ALGO__LAST
|
|
};
|
|
|
|
-extern const char *const pkey_algo[PKEY_ALGO__LAST];
|
|
+extern const char *const pkey_algo_name[PKEY_ALGO__LAST];
|
|
|
|
enum pkey_hash_algo {
|
|
PKEY_HASH_MD4,
|
|
@@ -36,7 +36,7 @@ enum pkey_hash_algo {
|
|
PKEY_HASH__LAST
|
|
};
|
|
|
|
-extern const char *const pkey_hash_algo[PKEY_HASH__LAST];
|
|
+extern const char *const pkey_hash_algo_name[PKEY_HASH__LAST];
|
|
|
|
enum pkey_id_type {
|
|
PKEY_ID_PGP, /* OpenPGP generated key ID */
|
|
@@ -44,7 +44,7 @@ enum pkey_id_type {
|
|
PKEY_ID_TYPE__LAST
|
|
};
|
|
|
|
-extern const char *const pkey_id_type[PKEY_ID_TYPE__LAST];
|
|
+extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST];
|
|
|
|
/*
|
|
* Cryptographic data for the public-key subtype of the asymmetric key type.
|
|
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
|
|
index f2970bd..ee47640 100644
|
|
--- a/kernel/module_signing.c
|
|
+++ b/kernel/module_signing.c
|
|
@@ -54,7 +54,7 @@ static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash,
|
|
/* Allocate the hashing algorithm we're going to need and find out how
|
|
* big the hash operational data will be.
|
|
*/
|
|
- tfm = crypto_alloc_shash(pkey_hash_algo[hash], 0, 0);
|
|
+ tfm = crypto_alloc_shash(pkey_hash_algo_name[hash], 0, 0);
|
|
if (IS_ERR(tfm))
|
|
return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm);
|
|
|
|
@@ -217,7 +217,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
|
|
return -ENOPKG;
|
|
|
|
if (ms.hash >= PKEY_HASH__LAST ||
|
|
- !pkey_hash_algo[ms.hash])
|
|
+ !pkey_hash_algo_name[ms.hash])
|
|
return -ENOPKG;
|
|
|
|
key = request_asymmetric_key(sig, ms.signer_len,
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From d12f06db05dacb455714f00f070cce844fb3e44c Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:15:18 +0100
|
|
Subject: [PATCH 02/18] KEYS: Move the algorithm pointer array from x509 to
|
|
public_key.c
|
|
|
|
Move the public-key algorithm pointer array from x509_public_key.c to
|
|
public_key.c as it isn't X.509 specific.
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Reviewed-by: Josh Boyer <jwboyer@redhat.com>
|
|
---
|
|
crypto/asymmetric_keys/public_key.c | 8 ++++++++
|
|
crypto/asymmetric_keys/x509_public_key.c | 11 +----------
|
|
include/crypto/public_key.h | 1 +
|
|
3 files changed, 10 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
|
|
index b313df1..796ce08 100644
|
|
--- a/crypto/asymmetric_keys/public_key.c
|
|
+++ b/crypto/asymmetric_keys/public_key.c
|
|
@@ -28,6 +28,14 @@ const char *const pkey_algo_name[PKEY_ALGO__LAST] = {
|
|
};
|
|
EXPORT_SYMBOL_GPL(pkey_algo_name);
|
|
|
|
+const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST] = {
|
|
+#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
|
|
+ defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
|
|
+ [PKEY_ALGO_RSA] = &RSA_public_key_algorithm,
|
|
+#endif
|
|
+};
|
|
+EXPORT_SYMBOL_GPL(pkey_algo);
|
|
+
|
|
const char *const pkey_hash_algo_name[PKEY_HASH__LAST] = {
|
|
[PKEY_HASH_MD4] = "md4",
|
|
[PKEY_HASH_MD5] = "md5",
|
|
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
|
|
index afbbc36..fe38628 100644
|
|
--- a/crypto/asymmetric_keys/x509_public_key.c
|
|
+++ b/crypto/asymmetric_keys/x509_public_key.c
|
|
@@ -23,15 +23,6 @@
|
|
#include "public_key.h"
|
|
#include "x509_parser.h"
|
|
|
|
-static const
|
|
-struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = {
|
|
- [PKEY_ALGO_DSA] = NULL,
|
|
-#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
|
|
- defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
|
|
- [PKEY_ALGO_RSA] = &RSA_public_key_algorithm,
|
|
-#endif
|
|
-};
|
|
-
|
|
/*
|
|
* Check the signature on a certificate using the provided public key
|
|
*/
|
|
@@ -174,7 +165,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
goto error_free_cert;
|
|
}
|
|
|
|
- cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo];
|
|
+ cert->pub->algo = pkey_algo[cert->pkey_algo];
|
|
cert->pub->id_type = PKEY_ID_X509;
|
|
|
|
/* Check the signature on the key */
|
|
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
|
|
index 619d570..46bde25 100644
|
|
--- a/include/crypto/public_key.h
|
|
+++ b/include/crypto/public_key.h
|
|
@@ -23,6 +23,7 @@ enum pkey_algo {
|
|
};
|
|
|
|
extern const char *const pkey_algo_name[PKEY_ALGO__LAST];
|
|
+extern const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST];
|
|
|
|
enum pkey_hash_algo {
|
|
PKEY_HASH_MD4,
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 8d2905bce58b356e9b5313a4aaebb5085bb4c151 Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:15:24 +0100
|
|
Subject: [PATCH 03/18] KEYS: Store public key algo ID in public_key struct
|
|
|
|
Store public key algo ID in public_key struct for reference purposes. This
|
|
allows it to be removed from the x509_certificate struct and used to find a
|
|
default in public_key_verify_signature().
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Reviewed-by: Josh Boyer <jwboyer@redhat.com>
|
|
---
|
|
crypto/asymmetric_keys/x509_cert_parser.c | 5 +++--
|
|
crypto/asymmetric_keys/x509_parser.h | 1 -
|
|
crypto/asymmetric_keys/x509_public_key.c | 4 ++--
|
|
include/crypto/public_key.h | 1 +
|
|
4 files changed, 6 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
|
|
index facbf26..8cc253d 100644
|
|
--- a/crypto/asymmetric_keys/x509_cert_parser.c
|
|
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
|
|
@@ -343,8 +343,9 @@ int x509_extract_key_data(void *context, size_t hdrlen,
|
|
if (ctx->last_oid != OID_rsaEncryption)
|
|
return -ENOPKG;
|
|
|
|
- /* There seems to be an extraneous 0 byte on the front of the data */
|
|
- ctx->cert->pkey_algo = PKEY_ALGO_RSA;
|
|
+ ctx->cert->pub->pkey_algo = PKEY_ALGO_RSA;
|
|
+
|
|
+ /* Discard the BIT STRING metadata */
|
|
ctx->key = value + 1;
|
|
ctx->key_size = vlen - 1;
|
|
return 0;
|
|
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
|
|
index f86dc5f..e583ad0 100644
|
|
--- a/crypto/asymmetric_keys/x509_parser.h
|
|
+++ b/crypto/asymmetric_keys/x509_parser.h
|
|
@@ -20,7 +20,6 @@ struct x509_certificate {
|
|
char *authority; /* Authority key fingerprint as hex */
|
|
struct tm valid_from;
|
|
struct tm valid_to;
|
|
- enum pkey_algo pkey_algo : 8; /* Public key algorithm */
|
|
enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */
|
|
enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */
|
|
const void *tbs; /* Signed data */
|
|
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
|
|
index fe38628..fac574c 100644
|
|
--- a/crypto/asymmetric_keys/x509_public_key.c
|
|
+++ b/crypto/asymmetric_keys/x509_public_key.c
|
|
@@ -108,7 +108,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
|
|
pr_devel("Cert Issuer: %s\n", cert->issuer);
|
|
pr_devel("Cert Subject: %s\n", cert->subject);
|
|
- pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pkey_algo]);
|
|
+ pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
|
|
pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
|
|
cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
|
|
cert->valid_from.tm_mday, cert->valid_from.tm_hour,
|
|
@@ -165,7 +165,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
goto error_free_cert;
|
|
}
|
|
|
|
- cert->pub->algo = pkey_algo[cert->pkey_algo];
|
|
+ cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
|
|
cert->pub->id_type = PKEY_ID_X509;
|
|
|
|
/* Check the signature on the key */
|
|
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
|
|
index 46bde25..05778df 100644
|
|
--- a/include/crypto/public_key.h
|
|
+++ b/include/crypto/public_key.h
|
|
@@ -60,6 +60,7 @@ struct public_key {
|
|
#define PKEY_CAN_DECRYPT 0x02
|
|
#define PKEY_CAN_SIGN 0x04
|
|
#define PKEY_CAN_VERIFY 0x08
|
|
+ enum pkey_algo pkey_algo : 8;
|
|
enum pkey_id_type id_type : 8;
|
|
union {
|
|
MPI mpi[5];
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From df1662a5b9f37a88c1e112d4052eca79efc8e6fc Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:15:30 +0100
|
|
Subject: [PATCH 04/18] KEYS: Split public_key_verify_signature() and make
|
|
available
|
|
|
|
Modify public_key_verify_signature() so that it now takes a public_key struct
|
|
rather than a key struct and supply a wrapper that takes a key struct. The
|
|
wrapper is then used by the asymmetric key subtype and the modified function is
|
|
used by X.509 self-signature checking and can be used by other things also.
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Reviewed-by: Josh Boyer <jwboyer@redhat.com>
|
|
---
|
|
crypto/asymmetric_keys/public_key.c | 40 +++++++++++++++++++++++++-------
|
|
crypto/asymmetric_keys/public_key.h | 6 +++++
|
|
crypto/asymmetric_keys/x509_public_key.c | 2 +-
|
|
3 files changed, 39 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
|
|
index 796ce08..49ac8d8 100644
|
|
--- a/crypto/asymmetric_keys/public_key.c
|
|
+++ b/crypto/asymmetric_keys/public_key.c
|
|
@@ -86,21 +86,45 @@ EXPORT_SYMBOL_GPL(public_key_destroy);
|
|
/*
|
|
* Verify a signature using a public key.
|
|
*/
|
|
-static int public_key_verify_signature(const struct key *key,
|
|
- const struct public_key_signature *sig)
|
|
+int public_key_verify_signature(const struct public_key *pk,
|
|
+ const struct public_key_signature *sig)
|
|
{
|
|
- const struct public_key *pk = key->payload.data;
|
|
+ const struct public_key_algorithm *algo;
|
|
+
|
|
+ BUG_ON(!pk);
|
|
+ BUG_ON(!pk->mpi[0]);
|
|
+ BUG_ON(!pk->mpi[1]);
|
|
+ BUG_ON(!sig);
|
|
+ BUG_ON(!sig->digest);
|
|
+ BUG_ON(!sig->mpi[0]);
|
|
+
|
|
+ algo = pk->algo;
|
|
+ if (!algo) {
|
|
+ if (pk->pkey_algo >= PKEY_ALGO__LAST)
|
|
+ return -ENOPKG;
|
|
+ algo = pkey_algo[pk->pkey_algo];
|
|
+ if (!algo)
|
|
+ return -ENOPKG;
|
|
+ }
|
|
|
|
- if (!pk->algo->verify_signature)
|
|
+ if (!algo->verify_signature)
|
|
return -ENOTSUPP;
|
|
|
|
- if (sig->nr_mpi != pk->algo->n_sig_mpi) {
|
|
+ if (sig->nr_mpi != algo->n_sig_mpi) {
|
|
pr_debug("Signature has %u MPI not %u\n",
|
|
- sig->nr_mpi, pk->algo->n_sig_mpi);
|
|
+ sig->nr_mpi, algo->n_sig_mpi);
|
|
return -EINVAL;
|
|
}
|
|
|
|
- return pk->algo->verify_signature(pk, sig);
|
|
+ return algo->verify_signature(pk, sig);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(public_key_verify_signature);
|
|
+
|
|
+static int public_key_verify_signature_2(const struct key *key,
|
|
+ const struct public_key_signature *sig)
|
|
+{
|
|
+ const struct public_key *pk = key->payload.data;
|
|
+ return public_key_verify_signature(pk, sig);
|
|
}
|
|
|
|
/*
|
|
@@ -111,6 +135,6 @@ struct asymmetric_key_subtype public_key_subtype = {
|
|
.name = "public_key",
|
|
.describe = public_key_describe,
|
|
.destroy = public_key_destroy,
|
|
- .verify_signature = public_key_verify_signature,
|
|
+ .verify_signature = public_key_verify_signature_2,
|
|
};
|
|
EXPORT_SYMBOL_GPL(public_key_subtype);
|
|
diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h
|
|
index 5e5e356..5c37a22 100644
|
|
--- a/crypto/asymmetric_keys/public_key.h
|
|
+++ b/crypto/asymmetric_keys/public_key.h
|
|
@@ -28,3 +28,9 @@ struct public_key_algorithm {
|
|
};
|
|
|
|
extern const struct public_key_algorithm RSA_public_key_algorithm;
|
|
+
|
|
+/*
|
|
+ * public_key.c
|
|
+ */
|
|
+extern int public_key_verify_signature(const struct public_key *pk,
|
|
+ const struct public_key_signature *sig);
|
|
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
|
|
index fac574c..8cb2f70 100644
|
|
--- a/crypto/asymmetric_keys/x509_public_key.c
|
|
+++ b/crypto/asymmetric_keys/x509_public_key.c
|
|
@@ -76,7 +76,7 @@ static int x509_check_signature(const struct public_key *pub,
|
|
if (ret < 0)
|
|
goto error_mpi;
|
|
|
|
- ret = pub->algo->verify_signature(pub, sig);
|
|
+ ret = public_key_verify_signature(pub, sig);
|
|
|
|
pr_debug("Cert Verification: %d\n", ret);
|
|
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 322d3b7e2debb3c7983dce2b80a5aefa4e7b1bda Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:15:37 +0100
|
|
Subject: [PATCH 05/18] KEYS: Store public key algo ID in public_key_signature
|
|
struct
|
|
|
|
Store public key algorithm ID in public_key_signature struct for reference
|
|
purposes. This allows a public_key_signature struct to be embedded in
|
|
struct x509_certificate and other places more easily.
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Reviewed-by: Josh Boyer <jwboyer@redhat.com>
|
|
---
|
|
include/crypto/public_key.h | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
|
|
index 05778df..b34fda4 100644
|
|
--- a/include/crypto/public_key.h
|
|
+++ b/include/crypto/public_key.h
|
|
@@ -90,6 +90,7 @@ struct public_key_signature {
|
|
u8 *digest;
|
|
u8 digest_size; /* Number of bytes in digest */
|
|
u8 nr_mpi; /* Occupancy of mpi[] */
|
|
+ enum pkey_algo pkey_algo : 8;
|
|
enum pkey_hash_algo pkey_hash_algo : 8;
|
|
union {
|
|
MPI mpi[2];
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 743143dd12661df376dcfc916b626b01d8ec84a4 Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:16:34 +0100
|
|
Subject: [PATCH 06/18] X.509: struct x509_certificate needs struct tm
|
|
declaring
|
|
|
|
struct x509_certificate needs struct tm declaring by #inclusion of linux/time.h
|
|
prior to its definition.
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Reviewed-by: Josh Boyer <jwboyer@redhat.com>
|
|
---
|
|
crypto/asymmetric_keys/x509_parser.h | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
|
|
index e583ad0..2d01182 100644
|
|
--- a/crypto/asymmetric_keys/x509_parser.h
|
|
+++ b/crypto/asymmetric_keys/x509_parser.h
|
|
@@ -9,6 +9,7 @@
|
|
* 2 of the Licence, or (at your option) any later version.
|
|
*/
|
|
|
|
+#include <linux/time.h>
|
|
#include <crypto/public_key.h>
|
|
|
|
struct x509_certificate {
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From a326ca89468c73dacb00fa247e92873d09e1387b Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:18:02 +0100
|
|
Subject: [PATCH 07/18] X.509: Embed public_key_signature struct and create
|
|
filler function
|
|
|
|
Embed a public_key_signature struct in struct x509_certificate, eliminating
|
|
now unnecessary fields, and split x509_check_signature() to create a filler
|
|
function for it that attaches a digest of the signed data and an MPI that
|
|
represents the signature data. x509_free_certificate() is then modified to
|
|
deal with these.
|
|
|
|
Whilst we're at it, export both x509_check_signature() and the new
|
|
x509_get_sig_params().
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Reviewed-by: Josh Boyer <jwboyer@redhat.com>
|
|
---
|
|
crypto/asymmetric_keys/x509_cert_parser.c | 30 +++++------
|
|
crypto/asymmetric_keys/x509_parser.h | 16 ++++--
|
|
crypto/asymmetric_keys/x509_public_key.c | 83 +++++++++++++++++--------------
|
|
3 files changed, 74 insertions(+), 55 deletions(-)
|
|
|
|
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
|
|
index 8cc253d..144201c 100644
|
|
--- a/crypto/asymmetric_keys/x509_cert_parser.c
|
|
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
|
|
@@ -47,6 +47,8 @@ void x509_free_certificate(struct x509_certificate *cert)
|
|
kfree(cert->subject);
|
|
kfree(cert->fingerprint);
|
|
kfree(cert->authority);
|
|
+ kfree(cert->sig.digest);
|
|
+ mpi_free(cert->sig.rsa.s);
|
|
kfree(cert);
|
|
}
|
|
}
|
|
@@ -152,33 +154,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
|
|
return -ENOPKG; /* Unsupported combination */
|
|
|
|
case OID_md4WithRSAEncryption:
|
|
- ctx->cert->sig_hash_algo = PKEY_HASH_MD5;
|
|
- ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
|
|
+ ctx->cert->sig.pkey_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;
|
|
+ ctx->cert->sig.pkey_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;
|
|
+ ctx->cert->sig.pkey_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;
|
|
+ ctx->cert->sig.pkey_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;
|
|
+ ctx->cert->sig.pkey_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;
|
|
+ ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA224;
|
|
+ ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
|
|
break;
|
|
}
|
|
|
|
@@ -203,8 +205,8 @@ int x509_note_signature(void *context, size_t hdrlen,
|
|
return -EINVAL;
|
|
}
|
|
|
|
- ctx->cert->sig = value;
|
|
- ctx->cert->sig_size = vlen;
|
|
+ ctx->cert->raw_sig = value;
|
|
+ ctx->cert->raw_sig_size = vlen;
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
|
|
index 2d01182..87d9cc2 100644
|
|
--- a/crypto/asymmetric_keys/x509_parser.h
|
|
+++ b/crypto/asymmetric_keys/x509_parser.h
|
|
@@ -21,12 +21,11 @@ struct x509_certificate {
|
|
char *authority; /* Authority key fingerprint as hex */
|
|
struct tm valid_from;
|
|
struct tm valid_to;
|
|
- enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */
|
|
- enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */
|
|
const void *tbs; /* Signed data */
|
|
- size_t tbs_size; /* Size of signed data */
|
|
- const void *sig; /* Signature data */
|
|
- size_t sig_size; /* Size of sigature */
|
|
+ unsigned tbs_size; /* Size of signed data */
|
|
+ unsigned raw_sig_size; /* Size of sigature */
|
|
+ const void *raw_sig; /* Signature data */
|
|
+ struct public_key_signature sig; /* Signature parameters */
|
|
};
|
|
|
|
/*
|
|
@@ -34,3 +33,10 @@ struct x509_certificate {
|
|
*/
|
|
extern void x509_free_certificate(struct x509_certificate *cert);
|
|
extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen);
|
|
+
|
|
+/*
|
|
+ * x509_public_key.c
|
|
+ */
|
|
+extern int x509_get_sig_params(struct x509_certificate *cert);
|
|
+extern int x509_check_signature(const struct public_key *pub,
|
|
+ struct x509_certificate *cert);
|
|
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
|
|
index 8cb2f70..b7c81d8 100644
|
|
--- a/crypto/asymmetric_keys/x509_public_key.c
|
|
+++ b/crypto/asymmetric_keys/x509_public_key.c
|
|
@@ -24,72 +24,83 @@
|
|
#include "x509_parser.h"
|
|
|
|
/*
|
|
- * Check the signature on a certificate using the provided public key
|
|
+ * Set up the signature parameters in an X.509 certificate. This involves
|
|
+ * digesting the signed data and extracting the signature.
|
|
*/
|
|
-static int x509_check_signature(const struct public_key *pub,
|
|
- const struct x509_certificate *cert)
|
|
+int x509_get_sig_params(struct x509_certificate *cert)
|
|
{
|
|
- struct public_key_signature *sig;
|
|
struct crypto_shash *tfm;
|
|
struct shash_desc *desc;
|
|
size_t digest_size, desc_size;
|
|
+ void *digest;
|
|
int ret;
|
|
|
|
pr_devel("==>%s()\n", __func__);
|
|
-
|
|
+
|
|
+ if (cert->sig.rsa.s)
|
|
+ return 0;
|
|
+
|
|
+ cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
|
|
+ if (!cert->sig.rsa.s)
|
|
+ return -ENOMEM;
|
|
+ cert->sig.nr_mpi = 1;
|
|
+
|
|
/* Allocate the hashing algorithm we're going to need and find out how
|
|
* big the hash operational data will be.
|
|
*/
|
|
- tfm = crypto_alloc_shash(pkey_hash_algo_name[cert->sig_hash_algo], 0, 0);
|
|
+ tfm = crypto_alloc_shash(pkey_hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
|
|
if (IS_ERR(tfm))
|
|
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
|
|
|
|
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
|
|
digest_size = crypto_shash_digestsize(tfm);
|
|
|
|
- /* We allocate the hash operational data storage on the end of our
|
|
- * context data.
|
|
+ /* We allocate the hash operational data storage on the end of the
|
|
+ * digest storage space.
|
|
*/
|
|
ret = -ENOMEM;
|
|
- sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL);
|
|
- if (!sig)
|
|
- goto error_no_sig;
|
|
+ digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
|
|
+ if (!digest)
|
|
+ goto error;
|
|
|
|
- sig->pkey_hash_algo = cert->sig_hash_algo;
|
|
- sig->digest = (u8 *)sig + sizeof(*sig) + desc_size;
|
|
- sig->digest_size = digest_size;
|
|
+ cert->sig.digest = digest;
|
|
+ cert->sig.digest_size = digest_size;
|
|
|
|
- desc = (void *)sig + sizeof(*sig);
|
|
- desc->tfm = tfm;
|
|
- desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
|
+ desc = digest + digest_size;
|
|
+ desc->tfm = tfm;
|
|
+ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
|
|
|
ret = crypto_shash_init(desc);
|
|
if (ret < 0)
|
|
goto error;
|
|
+ might_sleep();
|
|
+ ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
|
|
+error:
|
|
+ crypto_free_shash(tfm);
|
|
+ pr_devel("<==%s() = %d\n", __func__, ret);
|
|
+ return ret;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(x509_get_sig_params);
|
|
|
|
- ret = -ENOMEM;
|
|
- sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size);
|
|
- if (!sig->rsa.s)
|
|
- goto error;
|
|
+/*
|
|
+ * Check the signature on a certificate using the provided public key
|
|
+ */
|
|
+int x509_check_signature(const struct public_key *pub,
|
|
+ struct x509_certificate *cert)
|
|
+{
|
|
+ int ret;
|
|
|
|
- ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest);
|
|
- if (ret < 0)
|
|
- goto error_mpi;
|
|
+ pr_devel("==>%s()\n", __func__);
|
|
|
|
- ret = public_key_verify_signature(pub, sig);
|
|
+ ret = x509_get_sig_params(cert);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
|
|
+ ret = public_key_verify_signature(pub, &cert->sig);
|
|
pr_debug("Cert Verification: %d\n", ret);
|
|
-
|
|
-error_mpi:
|
|
- mpi_free(sig->rsa.s);
|
|
-error:
|
|
- kfree(sig);
|
|
-error_no_sig:
|
|
- crypto_free_shash(tfm);
|
|
-
|
|
- pr_devel("<==%s() = %d\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(x509_check_signature);
|
|
|
|
/*
|
|
* Attempt to parse a data blob for a key as an X509 certificate.
|
|
@@ -118,8 +129,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
cert->valid_to.tm_mday, cert->valid_to.tm_hour,
|
|
cert->valid_to.tm_min, cert->valid_to.tm_sec);
|
|
pr_devel("Cert Signature: %s + %s\n",
|
|
- pkey_algo_name[cert->sig_pkey_algo],
|
|
- pkey_hash_algo_name[cert->sig_hash_algo]);
|
|
+ pkey_algo_name[cert->sig.pkey_algo],
|
|
+ pkey_hash_algo_name[cert->sig.pkey_hash_algo]);
|
|
|
|
if (!cert->fingerprint || !cert->authority) {
|
|
pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 2857db9154b0fcfb8ba490c12f98cd47cc3f46fc Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:18:15 +0100
|
|
Subject: [PATCH 08/18] X.509: Check the algorithm IDs obtained from parsing an
|
|
X.509 certificate
|
|
|
|
Check that the algorithm IDs obtained from the ASN.1 parse by OID lookup
|
|
corresponds to algorithms that are available to us.
|
|
|
|
Reported-by: Kees Cook <keescook@chromium.org>
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
---
|
|
crypto/asymmetric_keys/x509_public_key.c | 11 +++++++++++
|
|
1 file changed, 11 insertions(+)
|
|
|
|
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
|
|
index b7c81d8..eb368d4 100644
|
|
--- a/crypto/asymmetric_keys/x509_public_key.c
|
|
+++ b/crypto/asymmetric_keys/x509_public_key.c
|
|
@@ -119,6 +119,17 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
|
|
pr_devel("Cert Issuer: %s\n", cert->issuer);
|
|
pr_devel("Cert Subject: %s\n", cert->subject);
|
|
+
|
|
+ if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
|
|
+ cert->sig.pkey_algo >= PKEY_ALGO__LAST ||
|
|
+ cert->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
|
|
+ !pkey_algo[cert->pub->pkey_algo] ||
|
|
+ !pkey_algo[cert->sig.pkey_algo] ||
|
|
+ !pkey_hash_algo_name[cert->sig.pkey_hash_algo]) {
|
|
+ ret = -ENOPKG;
|
|
+ goto error_free_cert;
|
|
+ }
|
|
+
|
|
pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
|
|
pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
|
|
cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From f78f0e8694517a3b1e5393d6ea0d46084bdc816a Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:18:31 +0100
|
|
Subject: [PATCH 09/18] X.509: Handle certificates that lack an
|
|
authorityKeyIdentifier field
|
|
|
|
Handle certificates that lack an authorityKeyIdentifier field by assuming
|
|
they're self-signed and checking their signatures against themselves.
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
Reviewed-by: Josh Boyer <jwboyer@redhat.com>
|
|
---
|
|
crypto/asymmetric_keys/x509_public_key.c | 9 +++++----
|
|
1 file changed, 5 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
|
|
index eb368d4..0f55e3b 100644
|
|
--- a/crypto/asymmetric_keys/x509_public_key.c
|
|
+++ b/crypto/asymmetric_keys/x509_public_key.c
|
|
@@ -143,8 +143,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
pkey_algo_name[cert->sig.pkey_algo],
|
|
pkey_hash_algo_name[cert->sig.pkey_hash_algo]);
|
|
|
|
- if (!cert->fingerprint || !cert->authority) {
|
|
- pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
|
|
+ if (!cert->fingerprint) {
|
|
+ pr_warn("Cert for '%s' must have a SubjKeyId extension\n",
|
|
cert->subject);
|
|
ret = -EKEYREJECTED;
|
|
goto error_free_cert;
|
|
@@ -190,8 +190,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
|
|
cert->pub->id_type = PKEY_ID_X509;
|
|
|
|
- /* Check the signature on the key */
|
|
- if (strcmp(cert->fingerprint, cert->authority) == 0) {
|
|
+ /* Check the signature on the key if it appears to be self-signed */
|
|
+ if (!cert->authority ||
|
|
+ strcmp(cert->fingerprint, cert->authority) == 0) {
|
|
ret = x509_check_signature(cert->pub, cert);
|
|
if (ret < 0)
|
|
goto error_free_cert;
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 4d729ace6be1c3b2b5d9b0d0301a4ffd342ec74a Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Tue, 18 Jun 2013 17:40:44 +0100
|
|
Subject: [PATCH 10/18] X.509: Remove certificate date checks
|
|
|
|
Remove the certificate date checks that are performed when a certificate is
|
|
parsed. There are two checks: a valid from and a valid to. The first check is
|
|
causing a lot of problems with system clocks that don't keep good time and the
|
|
second places an implicit expiry date upon the kernel when used for module
|
|
signing, so do we really need them?
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
cc: David Woodhouse <dwmw2@infradead.org>
|
|
cc: Rusty Russell <rusty@rustcorp.com.au>
|
|
cc: Josh Boyer <jwboyer@redhat.com>
|
|
cc: Alexander Holler <holler@ahsoftware.de>
|
|
cc: stable@vger.kernel.org
|
|
---
|
|
crypto/asymmetric_keys/x509_public_key.c | 38 --------------------------------
|
|
1 file changed, 38 deletions(-)
|
|
|
|
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
|
|
index 0f55e3b..c1540e8 100644
|
|
--- a/crypto/asymmetric_keys/x509_public_key.c
|
|
+++ b/crypto/asymmetric_keys/x509_public_key.c
|
|
@@ -108,7 +108,6 @@ EXPORT_SYMBOL_GPL(x509_check_signature);
|
|
static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
{
|
|
struct x509_certificate *cert;
|
|
- struct tm now;
|
|
size_t srlen, sulen;
|
|
char *desc = NULL;
|
|
int ret;
|
|
@@ -150,43 +149,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
goto error_free_cert;
|
|
}
|
|
|
|
- time_to_tm(CURRENT_TIME.tv_sec, 0, &now);
|
|
- pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n",
|
|
- now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
|
|
- now.tm_hour, now.tm_min, now.tm_sec);
|
|
- if (now.tm_year < cert->valid_from.tm_year ||
|
|
- (now.tm_year == cert->valid_from.tm_year &&
|
|
- (now.tm_mon < cert->valid_from.tm_mon ||
|
|
- (now.tm_mon == cert->valid_from.tm_mon &&
|
|
- (now.tm_mday < cert->valid_from.tm_mday ||
|
|
- (now.tm_mday == cert->valid_from.tm_mday &&
|
|
- (now.tm_hour < cert->valid_from.tm_hour ||
|
|
- (now.tm_hour == cert->valid_from.tm_hour &&
|
|
- (now.tm_min < cert->valid_from.tm_min ||
|
|
- (now.tm_min == cert->valid_from.tm_min &&
|
|
- (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 &&
|
|
- (now.tm_mon > cert->valid_to.tm_mon ||
|
|
- (now.tm_mon == cert->valid_to.tm_mon &&
|
|
- (now.tm_mday > cert->valid_to.tm_mday ||
|
|
- (now.tm_mday == cert->valid_to.tm_mday &&
|
|
- (now.tm_hour > cert->valid_to.tm_hour ||
|
|
- (now.tm_hour == cert->valid_to.tm_hour &&
|
|
- (now.tm_min > cert->valid_to.tm_min ||
|
|
- (now.tm_min == cert->valid_to.tm_min &&
|
|
- (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 = pkey_algo[cert->pub->pkey_algo];
|
|
cert->pub->id_type = PKEY_ID_X509;
|
|
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 33f859fea67ab5307da4049e947fbc23cdd13a27 Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:07:13 +0100
|
|
Subject: [PATCH 11/18] KEYS: Load *.x509 files into kernel keyring
|
|
|
|
Load all the files matching the pattern "*.x509" that are to be found in kernel
|
|
base source dir and base build dir into the module signing keyring.
|
|
|
|
The "extra_certificates" file is then redundant.
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
---
|
|
kernel/Makefile | 35 +++++++++++++++++++++++++++++------
|
|
kernel/modsign_certificate.S | 3 +--
|
|
2 files changed, 30 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/kernel/Makefile b/kernel/Makefile
|
|
index 1ce4755..c34e5f9 100644
|
|
--- a/kernel/Makefile
|
|
+++ b/kernel/Makefile
|
|
@@ -142,17 +142,40 @@ $(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE
|
|
$(call if_changed,bc)
|
|
|
|
ifeq ($(CONFIG_MODULE_SIG),y)
|
|
+###############################################################################
|
|
#
|
|
-# Pull the signing certificate and any extra certificates into the kernel
|
|
+# Roll all the X.509 certificates that we can find together and pull
|
|
+# them into the kernel.
|
|
#
|
|
+###############################################################################
|
|
+X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509)
|
|
+X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += signing_key.x509
|
|
+X509_CERTIFICATES := $(sort $(X509_CERTIFICATES-y))
|
|
+
|
|
+ifeq ($(X509_CERTIFICATES),)
|
|
+$(warning *** No X.509 certificates found ***)
|
|
+endif
|
|
+
|
|
+ifneq ($(wildcard $(obj)/.x509.list),)
|
|
+ifneq ($(shell cat $(obj)/.x509.list),$(X509_CERTIFICATES))
|
|
+$(info X.509 certificate list changed)
|
|
+$(shell rm $(obj)/.x509.list)
|
|
+endif
|
|
+endif
|
|
+
|
|
+kernel/modsign_certificate.o: $(obj)/x509_certificate_list
|
|
|
|
-quiet_cmd_touch = TOUCH $@
|
|
- cmd_touch = touch $@
|
|
+quiet_cmd_x509certs = CERTS $@
|
|
+ cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@
|
|
+targets += $(obj)/x509_certificate_list
|
|
+$(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list
|
|
+ $(call if_changed,x509certs)
|
|
|
|
-extra_certificates:
|
|
- $(call cmd,touch)
|
|
+targets += $(obj)/.x509.list
|
|
+$(obj)/.x509.list:
|
|
+ @echo $(X509_CERTIFICATES) >$@
|
|
|
|
-kernel/modsign_certificate.o: signing_key.x509 extra_certificates
|
|
+clean-files := x509_certificate_list .x509.list
|
|
|
|
###############################################################################
|
|
#
|
|
diff --git a/kernel/modsign_certificate.S b/kernel/modsign_certificate.S
|
|
index 4a9a86d..6fe03c7 100644
|
|
--- a/kernel/modsign_certificate.S
|
|
+++ b/kernel/modsign_certificate.S
|
|
@@ -7,6 +7,5 @@
|
|
.section ".init.data","aw"
|
|
|
|
GLOBAL(modsign_certificate_list)
|
|
- .incbin "signing_key.x509"
|
|
- .incbin "extra_certificates"
|
|
+ .incbin "kernel/x509_certificate_list"
|
|
GLOBAL(modsign_certificate_list_end)
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 068606ba7df3206e5a09b544b4b89ed09cd30f44 Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 17:13:15 +0100
|
|
Subject: [PATCH 12/18] KEYS: Have make canonicalise the paths of the X.509
|
|
certs better to deduplicate
|
|
|
|
Have make canonicalise the paths of the X.509 certificates before we sort them
|
|
as this allows $(sort) to better remove duplicates.
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
---
|
|
kernel/Makefile | 12 +++++++++---
|
|
1 file changed, 9 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/kernel/Makefile b/kernel/Makefile
|
|
index c34e5f9..2c24195 100644
|
|
--- a/kernel/Makefile
|
|
+++ b/kernel/Makefile
|
|
@@ -144,13 +144,19 @@ $(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE
|
|
ifeq ($(CONFIG_MODULE_SIG),y)
|
|
###############################################################################
|
|
#
|
|
-# Roll all the X.509 certificates that we can find together and pull
|
|
-# them into the kernel.
|
|
+# Roll all the X.509 certificates that we can find together and pull them into
|
|
+# the kernel.
|
|
+#
|
|
+# We look in the source root and the build root for all files whose name ends
|
|
+# in ".x509". Unfortunately, this will generate duplicate filenames, so we
|
|
+# have make canonicalise the pathnames and then sort them to discard the
|
|
+# duplicates.
|
|
#
|
|
###############################################################################
|
|
X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509)
|
|
X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += signing_key.x509
|
|
-X509_CERTIFICATES := $(sort $(X509_CERTIFICATES-y))
|
|
+X509_CERTIFICATES := $(sort $(foreach CERT,$(X509_CERTIFICATES-y), \
|
|
+ $(or $(realpath $(CERT)),$(CERT))))
|
|
|
|
ifeq ($(X509_CERTIFICATES),)
|
|
$(warning *** No X.509 certificates found ***)
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 9006cfbd669e9ba52d1a91db2ffd9482ad8a6090 Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:07:30 +0100
|
|
Subject: [PATCH 13/18] KEYS: Separate the kernel signature checking keyring
|
|
from module signing
|
|
|
|
Separate the kernel signature checking keyring from module signing so that it
|
|
can be used by code other than the module-signing code.
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
---
|
|
include/keys/system_keyring.h | 23 ++++++++++
|
|
init/Kconfig | 13 ++++++
|
|
kernel/Makefile | 15 ++++--
|
|
kernel/modsign_certificate.S | 11 -----
|
|
kernel/modsign_pubkey.c | 104 ------------------------------------------
|
|
kernel/module-internal.h | 2 -
|
|
kernel/module_signing.c | 3 +-
|
|
kernel/system_certificates.S | 11 +++++
|
|
kernel/system_keyring.c | 103 +++++++++++++++++++++++++++++++++++++++++
|
|
9 files changed, 162 insertions(+), 123 deletions(-)
|
|
create mode 100644 include/keys/system_keyring.h
|
|
delete mode 100644 kernel/modsign_certificate.S
|
|
delete mode 100644 kernel/modsign_pubkey.c
|
|
create mode 100644 kernel/system_certificates.S
|
|
create mode 100644 kernel/system_keyring.c
|
|
|
|
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
|
|
new file mode 100644
|
|
index 0000000..8dabc39
|
|
--- /dev/null
|
|
+++ b/include/keys/system_keyring.h
|
|
@@ -0,0 +1,23 @@
|
|
+/* System keyring containing trusted public keys.
|
|
+ *
|
|
+ * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
|
|
+ * Written by David Howells (dhowells@redhat.com)
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU General Public Licence
|
|
+ * as published by the Free Software Foundation; either version
|
|
+ * 2 of the Licence, or (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#ifndef _KEYS_SYSTEM_KEYRING_H
|
|
+#define _KEYS_SYSTEM_KEYRING_H
|
|
+
|
|
+#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
|
|
+
|
|
+#include <linux/key.h>
|
|
+
|
|
+extern struct key *system_trusted_keyring;
|
|
+
|
|
+#endif
|
|
+
|
|
+#endif /* _KEYS_SYSTEM_KEYRING_H */
|
|
diff --git a/init/Kconfig b/init/Kconfig
|
|
index 18bd9e3..cf14d07 100644
|
|
--- a/init/Kconfig
|
|
+++ b/init/Kconfig
|
|
@@ -1668,6 +1668,18 @@ config BASE_SMALL
|
|
default 0 if BASE_FULL
|
|
default 1 if !BASE_FULL
|
|
|
|
+config SYSTEM_TRUSTED_KEYRING
|
|
+ bool "Provide system-wide ring of trusted keys"
|
|
+ depends on KEYS
|
|
+ help
|
|
+ Provide a system keyring to which trusted keys can be added. Keys in
|
|
+ the keyring are considered to be trusted. Keys may be added at will
|
|
+ by the kernel from compiled-in data and from hardware key stores, but
|
|
+ userspace may only add extra keys if those keys can be verified by
|
|
+ keys already in the keyring.
|
|
+
|
|
+ Keys in this keyring are used by module signature checking.
|
|
+
|
|
menuconfig MODULES
|
|
bool "Enable loadable module support"
|
|
option modules
|
|
@@ -1741,6 +1753,7 @@ config MODULE_SRCVERSION_ALL
|
|
config MODULE_SIG
|
|
bool "Module signature verification"
|
|
depends on MODULES
|
|
+ select SYSTEM_TRUSTED_KEYRING
|
|
select KEYS
|
|
select CRYPTO
|
|
select ASYMMETRIC_KEY_TYPE
|
|
diff --git a/kernel/Makefile b/kernel/Makefile
|
|
index 2c24195..6313698 100644
|
|
--- a/kernel/Makefile
|
|
+++ b/kernel/Makefile
|
|
@@ -54,8 +54,9 @@ obj-$(CONFIG_SMP) += spinlock.o
|
|
obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
|
|
obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
|
|
obj-$(CONFIG_UID16) += uid16.o
|
|
+obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
|
|
obj-$(CONFIG_MODULES) += module.o
|
|
-obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o modsign_certificate.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
|
|
@@ -141,11 +142,11 @@ targets += timeconst.h
|
|
$(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE
|
|
$(call if_changed,bc)
|
|
|
|
-ifeq ($(CONFIG_MODULE_SIG),y)
|
|
###############################################################################
|
|
#
|
|
# Roll all the X.509 certificates that we can find together and pull them into
|
|
-# the kernel.
|
|
+# the kernel so that they get loaded into the system trusted keyring during
|
|
+# boot.
|
|
#
|
|
# We look in the source root and the build root for all files whose name ends
|
|
# in ".x509". Unfortunately, this will generate duplicate filenames, so we
|
|
@@ -153,6 +154,7 @@ ifeq ($(CONFIG_MODULE_SIG),y)
|
|
# duplicates.
|
|
#
|
|
###############################################################################
|
|
+ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y)
|
|
X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509)
|
|
X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += signing_key.x509
|
|
X509_CERTIFICATES := $(sort $(foreach CERT,$(X509_CERTIFICATES-y), \
|
|
@@ -169,10 +171,11 @@ $(shell rm $(obj)/.x509.list)
|
|
endif
|
|
endif
|
|
|
|
-kernel/modsign_certificate.o: $(obj)/x509_certificate_list
|
|
+kernel/system_certificates.o: $(obj)/x509_certificate_list
|
|
|
|
quiet_cmd_x509certs = CERTS $@
|
|
- cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@
|
|
+ cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; echo " - Including cert $(X509)")
|
|
+
|
|
targets += $(obj)/x509_certificate_list
|
|
$(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list
|
|
$(call if_changed,x509certs)
|
|
@@ -182,7 +185,9 @@ $(obj)/.x509.list:
|
|
@echo $(X509_CERTIFICATES) >$@
|
|
|
|
clean-files := x509_certificate_list .x509.list
|
|
+endif
|
|
|
|
+ifeq ($(CONFIG_MODULE_SIG),y)
|
|
###############################################################################
|
|
#
|
|
# If module signing is requested, say by allyesconfig, but a key has not been
|
|
diff --git a/kernel/modsign_certificate.S b/kernel/modsign_certificate.S
|
|
deleted file mode 100644
|
|
index 6fe03c7..0000000
|
|
--- a/kernel/modsign_certificate.S
|
|
+++ /dev/null
|
|
@@ -1,11 +0,0 @@
|
|
-#include <linux/export.h>
|
|
-
|
|
-#define GLOBAL(name) \
|
|
- .globl VMLINUX_SYMBOL(name); \
|
|
- VMLINUX_SYMBOL(name):
|
|
-
|
|
- .section ".init.data","aw"
|
|
-
|
|
-GLOBAL(modsign_certificate_list)
|
|
- .incbin "kernel/x509_certificate_list"
|
|
-GLOBAL(modsign_certificate_list_end)
|
|
diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c
|
|
deleted file mode 100644
|
|
index 7cbd450..0000000
|
|
--- a/kernel/modsign_pubkey.c
|
|
+++ /dev/null
|
|
@@ -1,104 +0,0 @@
|
|
-/* Public keys for module signature verification
|
|
- *
|
|
- * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
|
- * Written by David Howells (dhowells@redhat.com)
|
|
- *
|
|
- * This program is free software; you can redistribute it and/or
|
|
- * modify it under the terms of the GNU General Public Licence
|
|
- * as published by the Free Software Foundation; either version
|
|
- * 2 of the Licence, or (at your option) any later version.
|
|
- */
|
|
-
|
|
-#include <linux/kernel.h>
|
|
-#include <linux/sched.h>
|
|
-#include <linux/cred.h>
|
|
-#include <linux/err.h>
|
|
-#include <keys/asymmetric-type.h>
|
|
-#include "module-internal.h"
|
|
-
|
|
-struct key *modsign_keyring;
|
|
-
|
|
-extern __initconst const u8 modsign_certificate_list[];
|
|
-extern __initconst const u8 modsign_certificate_list_end[];
|
|
-
|
|
-/*
|
|
- * We need to make sure ccache doesn't cache the .o file as it doesn't notice
|
|
- * if modsign.pub changes.
|
|
- */
|
|
-static __initconst const char annoy_ccache[] = __TIME__ "foo";
|
|
-
|
|
-/*
|
|
- * Load the compiled-in keys
|
|
- */
|
|
-static __init int module_verify_init(void)
|
|
-{
|
|
- pr_notice("Initialise module verification\n");
|
|
-
|
|
- modsign_keyring = keyring_alloc(".module_sign",
|
|
- 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, NULL);
|
|
- if (IS_ERR(modsign_keyring))
|
|
- panic("Can't allocate module signing keyring\n");
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * Must be initialised before we try and load the keys into the keyring.
|
|
- */
|
|
-device_initcall(module_verify_init);
|
|
-
|
|
-/*
|
|
- * Load the compiled-in keys
|
|
- */
|
|
-static __init int load_module_signing_keys(void)
|
|
-{
|
|
- key_ref_t key;
|
|
- const u8 *p, *end;
|
|
- size_t plen;
|
|
-
|
|
- pr_notice("Loading module verification certificates\n");
|
|
-
|
|
- end = modsign_certificate_list_end;
|
|
- p = modsign_certificate_list;
|
|
- while (p < end) {
|
|
- /* Each cert begins with an ASN.1 SEQUENCE tag and must be more
|
|
- * than 256 bytes in size.
|
|
- */
|
|
- if (end - p < 4)
|
|
- goto dodgy_cert;
|
|
- if (p[0] != 0x30 &&
|
|
- p[1] != 0x82)
|
|
- goto dodgy_cert;
|
|
- plen = (p[2] << 8) | p[3];
|
|
- plen += 4;
|
|
- if (plen > end - p)
|
|
- goto dodgy_cert;
|
|
-
|
|
- key = key_create_or_update(make_key_ref(modsign_keyring, 1),
|
|
- "asymmetric",
|
|
- NULL,
|
|
- p,
|
|
- plen,
|
|
- (KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
|
- KEY_USR_VIEW,
|
|
- KEY_ALLOC_NOT_IN_QUOTA);
|
|
- if (IS_ERR(key))
|
|
- 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);
|
|
- p += plen;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-
|
|
-dodgy_cert:
|
|
- pr_err("MODSIGN: Problem parsing in-kernel X.509 certificate list\n");
|
|
- return 0;
|
|
-}
|
|
-late_initcall(load_module_signing_keys);
|
|
diff --git a/kernel/module-internal.h b/kernel/module-internal.h
|
|
index 24f9247..915e123 100644
|
|
--- a/kernel/module-internal.h
|
|
+++ b/kernel/module-internal.h
|
|
@@ -9,6 +9,4 @@
|
|
* 2 of the Licence, or (at your option) any later version.
|
|
*/
|
|
|
|
-extern struct key *modsign_keyring;
|
|
-
|
|
extern int mod_verify_sig(const void *mod, unsigned long *_modlen);
|
|
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
|
|
index ee47640..0b6b870 100644
|
|
--- a/kernel/module_signing.c
|
|
+++ b/kernel/module_signing.c
|
|
@@ -14,6 +14,7 @@
|
|
#include <crypto/public_key.h>
|
|
#include <crypto/hash.h>
|
|
#include <keys/asymmetric-type.h>
|
|
+#include <keys/system_keyring.h>
|
|
#include "module-internal.h"
|
|
|
|
/*
|
|
@@ -157,7 +158,7 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
|
|
|
|
pr_debug("Look up: \"%s\"\n", id);
|
|
|
|
- key = keyring_search(make_key_ref(modsign_keyring, 1),
|
|
+ key = keyring_search(make_key_ref(system_trusted_keyring, 1),
|
|
&key_type_asymmetric, id);
|
|
if (IS_ERR(key))
|
|
pr_warn("Request for unknown module key '%s' err %ld\n",
|
|
diff --git a/kernel/system_certificates.S b/kernel/system_certificates.S
|
|
new file mode 100644
|
|
index 0000000..5cffe86
|
|
--- /dev/null
|
|
+++ b/kernel/system_certificates.S
|
|
@@ -0,0 +1,11 @@
|
|
+#include <linux/export.h>
|
|
+
|
|
+#define GLOBAL(name) \
|
|
+ .globl VMLINUX_SYMBOL(name); \
|
|
+ VMLINUX_SYMBOL(name):
|
|
+
|
|
+ .section ".init.data","aw"
|
|
+
|
|
+GLOBAL(system_certificate_list)
|
|
+ .incbin "kernel/x509_certificate_list"
|
|
+GLOBAL(system_certificate_list_end)
|
|
diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c
|
|
new file mode 100644
|
|
index 0000000..51c3514
|
|
--- /dev/null
|
|
+++ b/kernel/system_keyring.c
|
|
@@ -0,0 +1,103 @@
|
|
+/* System trusted keyring for trusted public keys
|
|
+ *
|
|
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
|
+ * Written by David Howells (dhowells@redhat.com)
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU General Public Licence
|
|
+ * as published by the Free Software Foundation; either version
|
|
+ * 2 of the Licence, or (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#include <linux/export.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/cred.h>
|
|
+#include <linux/err.h>
|
|
+#include <keys/asymmetric-type.h>
|
|
+#include <keys/system_keyring.h>
|
|
+#include "module-internal.h"
|
|
+
|
|
+struct key *system_trusted_keyring;
|
|
+EXPORT_SYMBOL_GPL(system_trusted_keyring);
|
|
+
|
|
+extern __initconst const u8 system_certificate_list[];
|
|
+extern __initconst const u8 system_certificate_list_end[];
|
|
+
|
|
+/*
|
|
+ * Load the compiled-in keys
|
|
+ */
|
|
+static __init int system_trusted_keyring_init(void)
|
|
+{
|
|
+ pr_notice("Initialise system trusted keyring\n");
|
|
+
|
|
+ system_trusted_keyring =
|
|
+ keyring_alloc(".system_keyring",
|
|
+ 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, NULL);
|
|
+ if (IS_ERR(system_trusted_keyring))
|
|
+ panic("Can't allocate system trusted keyring\n");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Must be initialised before we try and load the keys into the keyring.
|
|
+ */
|
|
+device_initcall(system_trusted_keyring_init);
|
|
+
|
|
+/*
|
|
+ * Load the compiled-in list of X.509 certificates.
|
|
+ */
|
|
+static __init int load_system_certificate_list(void)
|
|
+{
|
|
+ key_ref_t key;
|
|
+ const u8 *p, *end;
|
|
+ size_t plen;
|
|
+
|
|
+ pr_notice("Loading compiled-in X.509 certificates\n");
|
|
+
|
|
+ end = system_certificate_list_end;
|
|
+ p = system_certificate_list;
|
|
+ while (p < end) {
|
|
+ /* Each cert begins with an ASN.1 SEQUENCE tag and must be more
|
|
+ * than 256 bytes in size.
|
|
+ */
|
|
+ if (end - p < 4)
|
|
+ goto dodgy_cert;
|
|
+ if (p[0] != 0x30 &&
|
|
+ p[1] != 0x82)
|
|
+ goto dodgy_cert;
|
|
+ plen = (p[2] << 8) | p[3];
|
|
+ plen += 4;
|
|
+ if (plen > end - p)
|
|
+ goto dodgy_cert;
|
|
+
|
|
+ key = key_create_or_update(make_key_ref(system_trusted_keyring, 1),
|
|
+ "asymmetric",
|
|
+ NULL,
|
|
+ p,
|
|
+ plen,
|
|
+ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
|
+ KEY_USR_VIEW,
|
|
+ KEY_ALLOC_NOT_IN_QUOTA);
|
|
+ if (IS_ERR(key)) {
|
|
+ pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
|
|
+ PTR_ERR(key));
|
|
+ } else {
|
|
+ pr_notice("Loaded X.509 cert '%s'\n",
|
|
+ key_ref_to_ptr(key)->description);
|
|
+ key_ref_put(key);
|
|
+ }
|
|
+ p += plen;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+dodgy_cert:
|
|
+ pr_err("Problem parsing in-kernel X.509 certificate list\n");
|
|
+ return 0;
|
|
+}
|
|
+late_initcall(load_system_certificate_list);
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From c0522b3236c27359bd61fee0f0b74be9f8e2ad60 Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Fri, 30 Aug 2013 16:07:37 +0100
|
|
Subject: [PATCH 14/18] KEYS: Add a 'trusted' flag and a 'trusted only' flag
|
|
|
|
Add KEY_FLAG_TRUSTED to indicate that a key either comes from a trusted source
|
|
or had a cryptographic signature chain that led back to a trusted key the
|
|
kernel already possessed.
|
|
|
|
Add KEY_FLAGS_TRUSTED_ONLY to indicate that a keyring will only accept links to
|
|
keys marked with KEY_FLAGS_TRUSTED.
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
Reviewed-by: Kees Cook <keescook@chromium.org>
|
|
---
|
|
include/linux/key-type.h | 1 +
|
|
include/linux/key.h | 3 +++
|
|
kernel/system_keyring.c | 4 +++-
|
|
security/keys/key.c | 8 ++++++++
|
|
security/keys/keyring.c | 4 ++++
|
|
5 files changed, 19 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/include/linux/key-type.h b/include/linux/key-type.h
|
|
index f58737b..a74c3a8 100644
|
|
--- a/include/linux/key-type.h
|
|
+++ b/include/linux/key-type.h
|
|
@@ -45,6 +45,7 @@ struct key_preparsed_payload {
|
|
const void *data; /* Raw data */
|
|
size_t datalen; /* Raw datalen */
|
|
size_t quotalen; /* Quota length for proposed payload */
|
|
+ bool trusted; /* True if key is trusted */
|
|
};
|
|
|
|
typedef int (*request_key_actor_t)(struct key_construction *key,
|
|
diff --git a/include/linux/key.h b/include/linux/key.h
|
|
index 010dbb6..80d6774 100644
|
|
--- a/include/linux/key.h
|
|
+++ b/include/linux/key.h
|
|
@@ -168,6 +168,8 @@ struct key {
|
|
#define KEY_FLAG_NEGATIVE 5 /* set if key is negative */
|
|
#define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */
|
|
#define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */
|
|
+#define KEY_FLAG_TRUSTED 8 /* set if key is trusted */
|
|
+#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */
|
|
|
|
/* the key type and key description string
|
|
* - the desc is used to match a key against search criteria
|
|
@@ -218,6 +220,7 @@ extern struct key *key_alloc(struct key_type *type,
|
|
#define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */
|
|
#define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */
|
|
#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */
|
|
+#define KEY_ALLOC_TRUSTED 0x0004 /* Key should be flagged as trusted */
|
|
|
|
extern void key_revoke(struct key *key);
|
|
extern void key_invalidate(struct key *key);
|
|
diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c
|
|
index 51c3514..5296721 100644
|
|
--- a/kernel/system_keyring.c
|
|
+++ b/kernel/system_keyring.c
|
|
@@ -40,6 +40,7 @@ static __init int system_trusted_keyring_init(void)
|
|
if (IS_ERR(system_trusted_keyring))
|
|
panic("Can't allocate system trusted keyring\n");
|
|
|
|
+ set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
|
|
return 0;
|
|
}
|
|
|
|
@@ -82,7 +83,8 @@ static __init int load_system_certificate_list(void)
|
|
plen,
|
|
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
|
KEY_USR_VIEW,
|
|
- KEY_ALLOC_NOT_IN_QUOTA);
|
|
+ KEY_ALLOC_NOT_IN_QUOTA |
|
|
+ KEY_ALLOC_TRUSTED);
|
|
if (IS_ERR(key)) {
|
|
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
|
|
PTR_ERR(key));
|
|
diff --git a/security/keys/key.c b/security/keys/key.c
|
|
index a819b5c..d331ea9 100644
|
|
--- a/security/keys/key.c
|
|
+++ b/security/keys/key.c
|
|
@@ -300,6 +300,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
|
|
|
|
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
|
|
key->flags |= 1 << KEY_FLAG_IN_QUOTA;
|
|
+ if (flags & KEY_ALLOC_TRUSTED)
|
|
+ key->flags |= 1 << KEY_FLAG_TRUSTED;
|
|
|
|
memset(&key->type_data, 0, sizeof(key->type_data));
|
|
|
|
@@ -813,6 +815,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
|
prep.data = payload;
|
|
prep.datalen = plen;
|
|
prep.quotalen = index_key.type->def_datalen;
|
|
+ prep.trusted = flags & KEY_ALLOC_TRUSTED;
|
|
if (index_key.type->preparse) {
|
|
ret = index_key.type->preparse(&prep);
|
|
if (ret < 0) {
|
|
@@ -827,6 +830,11 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
|
}
|
|
index_key.desc_len = strlen(index_key.description);
|
|
|
|
+ key_ref = ERR_PTR(-EPERM);
|
|
+ if (!prep.trusted && test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags))
|
|
+ goto error_free_prep;
|
|
+ flags |= prep.trusted ? KEY_ALLOC_TRUSTED : 0;
|
|
+
|
|
ret = __key_link_begin(keyring, &index_key, &edit);
|
|
if (ret < 0) {
|
|
key_ref = ERR_PTR(ret);
|
|
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
|
|
index f7cdea2..9b6f6e0 100644
|
|
--- a/security/keys/keyring.c
|
|
+++ b/security/keys/keyring.c
|
|
@@ -1183,6 +1183,10 @@ int key_link(struct key *keyring, struct key *key)
|
|
key_check(keyring);
|
|
key_check(key);
|
|
|
|
+ if (test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags) &&
|
|
+ !test_bit(KEY_FLAG_TRUSTED, &key->flags))
|
|
+ return -EPERM;
|
|
+
|
|
ret = __key_link_begin(keyring, &key->index_key, &edit);
|
|
if (ret == 0) {
|
|
kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage));
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From e8e9a6af1d2de6aca01751ccaf0475ed46f9bdb2 Mon Sep 17 00:00:00 2001
|
|
From: David Howells <dhowells@redhat.com>
|
|
Date: Wed, 4 Sep 2013 19:28:03 +0100
|
|
Subject: [PATCH 15/18] KEYS: Set the asymmetric-key type default search method
|
|
|
|
The keyring expansion patches introduces a new search method by which
|
|
key_search() attempts to walk directly to the key that has exactly the same
|
|
description as the requested one.
|
|
|
|
However, this causes inexact matching of asymmetric keys to fail. The
|
|
solution to this is to select iterative rather than direct search as the
|
|
default search type for asymmetric keys.
|
|
|
|
As an example, the kernel might have a key like this:
|
|
|
|
Magrathea: Glacier signing key: 6a2a0f82bad7e396665f465e4e3e1f9bd24b1226
|
|
|
|
and:
|
|
|
|
keyctl search <keyring-ID> asymmetric id:d24b1226
|
|
|
|
should find the key, despite that not being its exact description.
|
|
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
---
|
|
crypto/asymmetric_keys/asymmetric_type.c | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
|
|
index cf80765..b77eb53 100644
|
|
--- a/crypto/asymmetric_keys/asymmetric_type.c
|
|
+++ b/crypto/asymmetric_keys/asymmetric_type.c
|
|
@@ -209,6 +209,7 @@ struct key_type key_type_asymmetric = {
|
|
.match = asymmetric_key_match,
|
|
.destroy = asymmetric_key_destroy,
|
|
.describe = asymmetric_key_describe,
|
|
+ .def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE,
|
|
};
|
|
EXPORT_SYMBOL_GPL(key_type_asymmetric);
|
|
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From dfb7781ebba28004f95f7af4e039d8b44697c87c Mon Sep 17 00:00:00 2001
|
|
From: Mimi Zohar <zohar@linux.vnet.ibm.com>
|
|
Date: Tue, 20 Aug 2013 14:36:26 -0400
|
|
Subject: [PATCH 16/18] KEYS: Make the system 'trusted' keyring viewable by
|
|
userspace
|
|
|
|
Give the root user the ability to read the system keyring and put read
|
|
permission on the trusted keys added during boot. The latter is actually more
|
|
theoretical than real for the moment as asymmetric keys do not currently
|
|
provide a read operation.
|
|
|
|
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
---
|
|
kernel/system_keyring.c | 6 +++---
|
|
1 file changed, 3 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c
|
|
index 5296721..564dd93 100644
|
|
--- a/kernel/system_keyring.c
|
|
+++ b/kernel/system_keyring.c
|
|
@@ -35,7 +35,7 @@ static __init int system_trusted_keyring_init(void)
|
|
keyring_alloc(".system_keyring",
|
|
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
|
|
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
|
- KEY_USR_VIEW | KEY_USR_READ),
|
|
+ KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
|
|
KEY_ALLOC_NOT_IN_QUOTA, NULL);
|
|
if (IS_ERR(system_trusted_keyring))
|
|
panic("Can't allocate system trusted keyring\n");
|
|
@@ -81,8 +81,8 @@ static __init int load_system_certificate_list(void)
|
|
NULL,
|
|
p,
|
|
plen,
|
|
- (KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
|
- KEY_USR_VIEW,
|
|
+ ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
|
+ KEY_USR_VIEW | KEY_USR_READ),
|
|
KEY_ALLOC_NOT_IN_QUOTA |
|
|
KEY_ALLOC_TRUSTED);
|
|
if (IS_ERR(key)) {
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 052744b12209e66ede2a04ec31b9bb7ff40bbc9a Mon Sep 17 00:00:00 2001
|
|
From: Mimi Zohar <zohar@linux.vnet.ibm.com>
|
|
Date: Tue, 20 Aug 2013 14:36:27 -0400
|
|
Subject: [PATCH 17/18] KEYS: verify a certificate is signed by a 'trusted' key
|
|
|
|
Only public keys, with certificates signed by an existing
|
|
'trusted' key on the system trusted keyring, should be added
|
|
to a trusted keyring. This patch adds support for verifying
|
|
a certificate's signature.
|
|
|
|
This is derived from David Howells pkcs7_request_asymmetric_key() patch.
|
|
|
|
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
---
|
|
crypto/asymmetric_keys/x509_public_key.c | 81 +++++++++++++++++++++++++++++++-
|
|
1 file changed, 80 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
|
|
index c1540e8..8761264 100644
|
|
--- a/crypto/asymmetric_keys/x509_public_key.c
|
|
+++ b/crypto/asymmetric_keys/x509_public_key.c
|
|
@@ -18,12 +18,60 @@
|
|
#include <linux/asn1_decoder.h>
|
|
#include <keys/asymmetric-subtype.h>
|
|
#include <keys/asymmetric-parser.h>
|
|
+#include <keys/system_keyring.h>
|
|
#include <crypto/hash.h>
|
|
#include "asymmetric_keys.h"
|
|
#include "public_key.h"
|
|
#include "x509_parser.h"
|
|
|
|
/*
|
|
+ * Find a key in the given keyring by issuer and authority.
|
|
+ */
|
|
+static struct key *x509_request_asymmetric_key(
|
|
+ struct key *keyring,
|
|
+ const char *signer, size_t signer_len,
|
|
+ const char *authority, size_t auth_len)
|
|
+{
|
|
+ key_ref_t key;
|
|
+ char *id;
|
|
+
|
|
+ /* Construct an identifier. */
|
|
+ id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL);
|
|
+ if (!id)
|
|
+ return ERR_PTR(-ENOMEM);
|
|
+
|
|
+ memcpy(id, signer, signer_len);
|
|
+ id[signer_len + 0] = ':';
|
|
+ id[signer_len + 1] = ' ';
|
|
+ memcpy(id + signer_len + 2, authority, auth_len);
|
|
+ id[signer_len + 2 + auth_len] = 0;
|
|
+
|
|
+ pr_debug("Look up: \"%s\"\n", id);
|
|
+
|
|
+ key = keyring_search(make_key_ref(keyring, 1),
|
|
+ &key_type_asymmetric, id);
|
|
+ if (IS_ERR(key))
|
|
+ pr_debug("Request for module key '%s' err %ld\n",
|
|
+ id, PTR_ERR(key));
|
|
+ kfree(id);
|
|
+
|
|
+ if (IS_ERR(key)) {
|
|
+ switch (PTR_ERR(key)) {
|
|
+ /* Hide some search errors */
|
|
+ case -EACCES:
|
|
+ case -ENOTDIR:
|
|
+ case -EAGAIN:
|
|
+ return ERR_PTR(-ENOKEY);
|
|
+ default:
|
|
+ return ERR_CAST(key);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key)));
|
|
+ return key_ref_to_ptr(key);
|
|
+}
|
|
+
|
|
+/*
|
|
* Set up the signature parameters in an X.509 certificate. This involves
|
|
* digesting the signed data and extracting the signature.
|
|
*/
|
|
@@ -103,6 +151,33 @@ int x509_check_signature(const struct public_key *pub,
|
|
EXPORT_SYMBOL_GPL(x509_check_signature);
|
|
|
|
/*
|
|
+ * Check the new certificate against the ones in the trust keyring. If one of
|
|
+ * those is the signing key and validates the new certificate, then mark the
|
|
+ * new certificate as being trusted.
|
|
+ *
|
|
+ * Return 0 if the new certificate was successfully validated, 1 if we couldn't
|
|
+ * find a matching parent certificate in the trusted list and an error if there
|
|
+ * is a matching certificate but the signature check fails.
|
|
+ */
|
|
+static int x509_validate_trust(struct x509_certificate *cert,
|
|
+ struct key *trust_keyring)
|
|
+{
|
|
+ const struct public_key *pk;
|
|
+ struct key *key;
|
|
+ int ret = 1;
|
|
+
|
|
+ key = x509_request_asymmetric_key(trust_keyring,
|
|
+ cert->issuer, strlen(cert->issuer),
|
|
+ cert->authority,
|
|
+ strlen(cert->authority));
|
|
+ if (!IS_ERR(key)) {
|
|
+ pk = key->payload.data;
|
|
+ ret = x509_check_signature(pk, cert);
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/*
|
|
* Attempt to parse a data blob for a key as an X509 certificate.
|
|
*/
|
|
static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
@@ -155,9 +230,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
|
|
/* Check the signature on the key if it appears to be self-signed */
|
|
if (!cert->authority ||
|
|
strcmp(cert->fingerprint, cert->authority) == 0) {
|
|
- ret = x509_check_signature(cert->pub, cert);
|
|
+ ret = x509_check_signature(cert->pub, cert); /* self-signed */
|
|
if (ret < 0)
|
|
goto error_free_cert;
|
|
+ } else {
|
|
+ ret = x509_validate_trust(cert, system_trusted_keyring);
|
|
+ if (!ret)
|
|
+ prep->trusted = 1;
|
|
}
|
|
|
|
/* Propose a description */
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 8b39d9a6d9f805f6a2e837bf8b9595f701ea4a1c Mon Sep 17 00:00:00 2001
|
|
From: Mimi Zohar <zohar@linux.vnet.ibm.com>
|
|
Date: Wed, 4 Sep 2013 13:26:22 +0100
|
|
Subject: [PATCH 18/18] KEYS: initialize root uid and session keyrings early
|
|
|
|
In order to create the integrity keyrings (eg. _evm, _ima), root's
|
|
uid and session keyrings need to be initialized early.
|
|
|
|
Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
|
|
Signed-off-by: David Howells <dhowells@redhat.com>
|
|
---
|
|
security/keys/process_keys.c | 10 ++++++++++
|
|
1 file changed, 10 insertions(+)
|
|
|
|
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
|
|
index 68548ea..0cf8a13 100644
|
|
--- a/security/keys/process_keys.c
|
|
+++ b/security/keys/process_keys.c
|
|
@@ -857,3 +857,13 @@ void key_change_session_keyring(struct callback_head *twork)
|
|
|
|
commit_creds(new);
|
|
}
|
|
+
|
|
+/*
|
|
+ * Make sure that root's user and user-session keyrings exist.
|
|
+ */
|
|
+static int __init init_root_keyring(void)
|
|
+{
|
|
+ return install_user_keyrings();
|
|
+}
|
|
+
|
|
+late_initcall(init_root_keyring);
|
|
--
|
|
1.8.3.1
|
|
|