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