Commit 64724cfc authored by David Howells's avatar David Howells

Merge remote-tracking branch 'integrity/next-with-keys' into keys-next

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parents 6204e002 7d2ce232
...@@ -566,6 +566,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -566,6 +566,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
possible to determine what the correct size should be. possible to determine what the correct size should be.
This option provides an override for these situations. This option provides an override for these situations.
ca_keys= [KEYS] This parameter identifies a specific key(s) on
the system trusted keyring to be used for certificate
trust validation.
format: { id:<keyid> | builtin }
ccw_timeout_log [S390] ccw_timeout_log [S390]
See Documentation/s390/CommonIO for details. See Documentation/s390/CommonIO for details.
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
* 2 of the Licence, or (at your option) any later version. * 2 of the Licence, or (at your option) any later version.
*/ */
int asymmetric_keyid_match(const char *kid, const char *id);
static inline const char *asymmetric_key_id(const struct key *key) static inline const char *asymmetric_key_id(const struct key *key)
{ {
return key->type_data.p[1]; return key->type_data.p[1];
......
...@@ -22,6 +22,35 @@ MODULE_LICENSE("GPL"); ...@@ -22,6 +22,35 @@ MODULE_LICENSE("GPL");
static LIST_HEAD(asymmetric_key_parsers); static LIST_HEAD(asymmetric_key_parsers);
static DECLARE_RWSEM(asymmetric_key_parsers_sem); static DECLARE_RWSEM(asymmetric_key_parsers_sem);
/*
* Match asymmetric key id with partial match
* @id: key id to match in a form "id:<id>"
*/
int asymmetric_keyid_match(const char *kid, const char *id)
{
size_t idlen, kidlen;
if (!kid || !id)
return 0;
/* make it possible to use id as in the request: "id:<id>" */
if (strncmp(id, "id:", 3) == 0)
id += 3;
/* Anything after here requires a partial match on the ID string */
idlen = strlen(id);
kidlen = strlen(kid);
if (idlen > kidlen)
return 0;
kid += kidlen - idlen;
if (strcasecmp(id, kid) != 0)
return 0;
return 1;
}
EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
/* /*
* Match asymmetric keys on (part of) their name * Match asymmetric keys on (part of) their name
* We have some shorthand methods for matching keys. We allow: * We have some shorthand methods for matching keys. We allow:
...@@ -34,9 +63,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) ...@@ -34,9 +63,8 @@ static int asymmetric_key_match(const struct key *key, const void *description)
{ {
const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
const char *spec = description; const char *spec = description;
const char *id, *kid; const char *id;
ptrdiff_t speclen; ptrdiff_t speclen;
size_t idlen, kidlen;
if (!subtype || !spec || !*spec) if (!subtype || !spec || !*spec)
return 0; return 0;
...@@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) ...@@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description)
speclen = id - spec; speclen = id - spec;
id++; id++;
/* Anything after here requires a partial match on the ID string */ if (speclen == 2 && memcmp(spec, "id", 2) == 0)
kid = asymmetric_key_id(key); return asymmetric_keyid_match(asymmetric_key_id(key), id);
if (!kid)
return 0;
idlen = strlen(id);
kidlen = strlen(kid);
if (idlen > kidlen)
return 0;
kid += kidlen - idlen;
if (strcasecmp(id, kid) != 0)
return 0;
if (speclen == 2 &&
memcmp(spec, "id", 2) == 0)
return 1;
if (speclen == subtype->name_len && if (speclen == subtype->name_len &&
memcmp(spec, subtype->name, speclen) == 0) memcmp(spec, subtype->name, speclen) == 0)
......
...@@ -18,11 +18,80 @@ ...@@ -18,11 +18,80 @@
#include <linux/asn1_decoder.h> #include <linux/asn1_decoder.h>
#include <keys/asymmetric-subtype.h> #include <keys/asymmetric-subtype.h>
#include <keys/asymmetric-parser.h> #include <keys/asymmetric-parser.h>
#include <keys/system_keyring.h>
#include <crypto/hash.h> #include <crypto/hash.h>
#include "asymmetric_keys.h" #include "asymmetric_keys.h"
#include "public_key.h" #include "public_key.h"
#include "x509_parser.h" #include "x509_parser.h"
static bool use_builtin_keys;
static char *ca_keyid;
#ifndef MODULE
static int __init ca_keys_setup(char *str)
{
if (!str) /* default system keyring */
return 1;
if (strncmp(str, "id:", 3) == 0)
ca_keyid = str; /* owner key 'id:xxxxxx' */
else if (strcmp(str, "builtin") == 0)
use_builtin_keys = true;
return 1;
}
__setup("ca_keys=", ca_keys_setup);
#endif
/*
* 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 * Set up the signature parameters in an X.509 certificate. This involves
* digesting the signed data and extracting the signature. * digesting the signed data and extracting the signature.
...@@ -102,6 +171,40 @@ int x509_check_signature(const struct public_key *pub, ...@@ -102,6 +171,40 @@ int x509_check_signature(const struct public_key *pub,
} }
EXPORT_SYMBOL_GPL(x509_check_signature); 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)
{
struct key *key;
int ret = 1;
if (!trust_keyring)
return -EOPNOTSUPP;
if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid))
return -EPERM;
key = x509_request_asymmetric_key(trust_keyring,
cert->issuer, strlen(cert->issuer),
cert->authority,
strlen(cert->authority));
if (!IS_ERR(key)) {
if (!use_builtin_keys
|| test_bit(KEY_FLAG_BUILTIN, &key->flags))
ret = x509_check_signature(key->payload.data, cert);
key_put(key);
}
return ret;
}
/* /*
* Attempt to parse a data blob for a key as an X509 certificate. * Attempt to parse a data blob for a key as an X509 certificate.
*/ */
...@@ -155,9 +258,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) ...@@ -155,9 +258,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
/* Check the signature on the key if it appears to be self-signed */ /* Check the signature on the key if it appears to be self-signed */
if (!cert->authority || if (!cert->authority ||
strcmp(cert->fingerprint, cert->authority) == 0) { 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) if (ret < 0)
goto error_free_cert; goto error_free_cert;
} else if (!prep->trusted) {
ret = x509_validate_trust(cert, get_system_trusted_keyring());
if (!ret)
prep->trusted = 1;
} }
/* Propose a description */ /* Propose a description */
......
...@@ -17,7 +17,15 @@ ...@@ -17,7 +17,15 @@
#include <linux/key.h> #include <linux/key.h>
extern struct key *system_trusted_keyring; extern struct key *system_trusted_keyring;
static inline struct key *get_system_trusted_keyring(void)
{
return system_trusted_keyring;
}
#else
static inline struct key *get_system_trusted_keyring(void)
{
return NULL;
}
#endif #endif
#endif /* _KEYS_SYSTEM_KEYRING_H */ #endif /* _KEYS_SYSTEM_KEYRING_H */
...@@ -170,6 +170,7 @@ struct key { ...@@ -170,6 +170,7 @@ struct key {
#define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ #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 8 /* set if key is trusted */
#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ #define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */
#define KEY_FLAG_BUILTIN 10 /* set if key is builtin */
/* the key type and key description string /* the key type and key description string
* - the desc is used to match a key against search criteria * - the desc is used to match a key against search criteria
......
...@@ -89,6 +89,7 @@ static __init int load_system_certificate_list(void) ...@@ -89,6 +89,7 @@ static __init int load_system_certificate_list(void)
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key)); PTR_ERR(key));
} else { } else {
set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
pr_notice("Loaded X.509 cert '%s'\n", pr_notice("Loaded X.509 cert '%s'\n",
key_ref_to_ptr(key)->description); key_ref_to_ptr(key)->description);
key_ref_put(key); key_ref_put(key);
......
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h> #include <linux/err.h>
#include <linux/sched.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/cred.h>
#include <linux/key-type.h> #include <linux/key-type.h>
#include <linux/digsig.h> #include <linux/digsig.h>
...@@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX]; ...@@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX];
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
"_evm", "_evm",
"_module", "_module",
#ifndef CONFIG_IMA_TRUSTED_KEYRING
"_ima", "_ima",
#else
".ima",
#endif
}; };
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
...@@ -56,3 +62,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, ...@@ -56,3 +62,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
int integrity_init_keyring(const unsigned int id)
{
const struct cred *cred = current_cred();
int err = 0;
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
KGIDT_INIT(0), cred,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH),
KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (!IS_ERR(keyring[id]))
set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
else {
err = PTR_ERR(keyring[id]);
pr_info("Can't allocate %s keyring (%d)\n",
keyring_name[id], err);
keyring[id] = NULL;
}
return err;
}
...@@ -123,3 +123,13 @@ config IMA_APPRAISE ...@@ -123,3 +123,13 @@ config IMA_APPRAISE
For more information on integrity appraisal refer to: For more information on integrity appraisal refer to:
<http://linux-ima.sourceforge.net> <http://linux-ima.sourceforge.net>
If unsure, say N. If unsure, say N.
config IMA_TRUSTED_KEYRING
bool "Require all keys on the .ima keyring be signed"
depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
depends on INTEGRITY_ASYMMETRIC_KEYS
select KEYS_DEBUG_PROC_KEYS
default y
help
This option requires that all keys added to the .ima
keyring be signed by a key on the system trusted keyring.
...@@ -249,4 +249,16 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op, ...@@ -249,4 +249,16 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
return -EINVAL; return -EINVAL;
} }
#endif /* CONFIG_IMA_LSM_RULES */ #endif /* CONFIG_IMA_LSM_RULES */
#ifdef CONFIG_IMA_TRUSTED_KEYRING
static inline int ima_init_keyring(const unsigned int id)
{
return integrity_init_keyring(id);
}
#else
static inline int ima_init_keyring(const unsigned int id)
{
return 0;
}
#endif /* CONFIG_IMA_TRUSTED_KEYRING */
#endif #endif
...@@ -325,8 +325,14 @@ static int __init init_ima(void) ...@@ -325,8 +325,14 @@ static int __init init_ima(void)
hash_setup(CONFIG_IMA_DEFAULT_HASH); hash_setup(CONFIG_IMA_DEFAULT_HASH);
error = ima_init(); error = ima_init();
if (!error) if (error)
goto out;
error = ima_init_keyring(INTEGRITY_KEYRING_IMA);
if (error)
goto out;
ima_initialized = 1; ima_initialized = 1;
out:
return error; return error;
} }
......
...@@ -124,6 +124,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); ...@@ -124,6 +124,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen); const char *digest, int digestlen);
int integrity_init_keyring(const unsigned int id);
#else #else
static inline int integrity_digsig_verify(const unsigned int id, static inline int integrity_digsig_verify(const unsigned int id,
...@@ -133,6 +134,10 @@ static inline int integrity_digsig_verify(const unsigned int id, ...@@ -133,6 +134,10 @@ static inline int integrity_digsig_verify(const unsigned int id,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline int integrity_init_keyring(const unsigned int id)
{
return 0;
}
#endif /* CONFIG_INTEGRITY_SIGNATURE */ #endif /* CONFIG_INTEGRITY_SIGNATURE */
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
......
...@@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type, ...@@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type,
return ret; return ret;
if (ret == 0 || ret >= len) if (ret == 0 || ret >= len)
return -EINVAL; return -EINVAL;
if (type[0] == '.')
return -EPERM;
type[len - 1] = '\0'; type[len - 1] = '\0';
return 0; return 0;
} }
...@@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, ...@@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
if (!*description) { if (!*description) {
kfree(description); kfree(description);
description = NULL; description = NULL;
} else if ((description[0] == '.') &&
(strncmp(type, "keyring", 7) == 0)) {
ret = -EPERM;
goto error2;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment