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