mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
Merge remote-tracking branch 'integrity/next-with-keys' into keys-next
Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
commit
64724cfc6e
@ -566,6 +566,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
possible to determine what the correct size should be.
|
||||
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]
|
||||
See Documentation/s390/CommonIO for details.
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
* 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)
|
||||
{
|
||||
return key->type_data.p[1];
|
||||
|
@ -22,6 +22,35 @@ MODULE_LICENSE("GPL");
|
||||
static LIST_HEAD(asymmetric_key_parsers);
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
|
||||
const char *spec = description;
|
||||
const char *id, *kid;
|
||||
const char *id;
|
||||
ptrdiff_t speclen;
|
||||
size_t idlen, kidlen;
|
||||
|
||||
if (!subtype || !spec || !*spec)
|
||||
return 0;
|
||||
@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description)
|
||||
speclen = id - spec;
|
||||
id++;
|
||||
|
||||
/* Anything after here requires a partial match on the ID string */
|
||||
kid = asymmetric_key_id(key);
|
||||
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 == 2 && memcmp(spec, "id", 2) == 0)
|
||||
return asymmetric_keyid_match(asymmetric_key_id(key), id);
|
||||
|
||||
if (speclen == subtype->name_len &&
|
||||
memcmp(spec, subtype->name, speclen) == 0)
|
||||
|
@ -18,11 +18,80 @@
|
||||
#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"
|
||||
|
||||
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
|
||||
* digesting the signed data and extracting the signature.
|
||||
@ -102,6 +171,40 @@ 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)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
@ -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 */
|
||||
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 if (!prep->trusted) {
|
||||
ret = x509_validate_trust(cert, get_system_trusted_keyring());
|
||||
if (!ret)
|
||||
prep->trusted = 1;
|
||||
}
|
||||
|
||||
/* Propose a description */
|
||||
|
@ -17,7 +17,15 @@
|
||||
#include <linux/key.h>
|
||||
|
||||
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 /* _KEYS_SYSTEM_KEYRING_H */
|
||||
|
@ -170,6 +170,7 @@ struct key {
|
||||
#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 */
|
||||
#define KEY_FLAG_BUILTIN 10 /* set if key is builtin */
|
||||
|
||||
/* the key type and key description string
|
||||
* - the desc is used to match a key against search criteria
|
||||
|
@ -89,6 +89,7 @@ static __init int load_system_certificate_list(void)
|
||||
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
|
||||
PTR_ERR(key));
|
||||
} else {
|
||||
set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
|
||||
pr_notice("Loaded X.509 cert '%s'\n",
|
||||
key_ref_to_ptr(key)->description);
|
||||
key_ref_put(key);
|
||||
|
@ -13,7 +13,9 @@
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/key-type.h>
|
||||
#include <linux/digsig.h>
|
||||
|
||||
@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX];
|
||||
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
|
||||
"_evm",
|
||||
"_module",
|
||||
#ifndef CONFIG_IMA_TRUSTED_KEYRING
|
||||
"_ima",
|
||||
#else
|
||||
".ima",
|
||||
#endif
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
For more information on integrity appraisal refer to:
|
||||
<http://linux-ima.sourceforge.net>
|
||||
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,
|
||||
return -EINVAL;
|
||||
}
|
||||
#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
|
||||
|
@ -325,8 +325,14 @@ static int __init init_ima(void)
|
||||
|
||||
hash_setup(CONFIG_IMA_DEFAULT_HASH);
|
||||
error = ima_init();
|
||||
if (!error)
|
||||
ima_initialized = 1;
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = ima_init_keyring(INTEGRITY_KEYRING_IMA);
|
||||
if (error)
|
||||
goto out;
|
||||
ima_initialized = 1;
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
const char *digest, int digestlen);
|
||||
|
||||
int integrity_init_keyring(const unsigned int id);
|
||||
#else
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static inline int integrity_init_keyring(const unsigned int id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_INTEGRITY_SIGNATURE */
|
||||
|
||||
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
|
||||
|
@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type,
|
||||
return ret;
|
||||
if (ret == 0 || ret >= len)
|
||||
return -EINVAL;
|
||||
if (type[0] == '.')
|
||||
return -EPERM;
|
||||
type[len - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
|
||||
if (!*description) {
|
||||
kfree(description);
|
||||
description = NULL;
|
||||
} else if ((description[0] == '.') &&
|
||||
(strncmp(type, "keyring", 7) == 0)) {
|
||||
ret = -EPERM;
|
||||
goto error2;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user