Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 16c4db3b authored by James Morris's avatar James Morris
Browse files

Merge tag 'keys-fixes-20180222-2' of...

Merge tag 'keys-fixes-20180222-2' of https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs into fixes-v4.16-rc3

Keyrings fixes.
parents 645ae5c5 d9f4bb1a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
		pr_devel("sinfo %u: Direct signer is key %x\n",
			 sinfo->index, key_serial(key));
		x509 = NULL;
		sig = sinfo->sig;
		goto matched;
	}
	if (PTR_ERR(key) != -ENOKEY)
+7 −5
Original line number Diff line number Diff line
@@ -270,7 +270,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
				sinfo->index);
			return 0;
		}
		ret = public_key_verify_signature(p->pub, p->sig);
		ret = public_key_verify_signature(p->pub, x509->sig);
		if (ret < 0)
			return ret;
		x509->signer = p;
@@ -366,8 +366,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
 *
 *  (*) -EBADMSG if some part of the message was invalid, or:
 *
 *  (*) 0 if no signature chains were found to be blacklisted or to contain
 *	unsupported crypto, or:
 *  (*) 0 if a signature chain passed verification, or:
 *
 *  (*) -EKEYREJECTED if a blacklisted key was encountered, or:
 *
@@ -423,8 +422,11 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,

	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
		ret = pkcs7_verify_one(pkcs7, sinfo);
		if (sinfo->blacklisted && actual_ret == -ENOPKG)
		if (sinfo->blacklisted) {
			if (actual_ret == -ENOPKG)
				actual_ret = -EKEYREJECTED;
			continue;
		}
		if (ret < 0) {
			if (ret == -ENOPKG) {
				sinfo->unsupported_crypto = true;
+3 −1
Original line number Diff line number Diff line
@@ -79,9 +79,11 @@ int public_key_verify_signature(const struct public_key *pkey,

	BUG_ON(!pkey);
	BUG_ON(!sig);
	BUG_ON(!sig->digest);
	BUG_ON(!sig->s);

	if (!sig->digest)
		return -ENOPKG;

	alg_name = sig->pkey_algo;
	if (strcmp(sig->pkey_algo, "rsa") == 0) {
		/* The data wangled by the RSA algorithm is typically padded
+13 −8
Original line number Diff line number Diff line
@@ -67,8 +67,9 @@ __setup("ca_keys=", ca_keys_setup);
 *
 * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a
 * matching parent certificate in the trusted list, -EKEYREJECTED if the
 * signature check fails or the key is blacklisted and some other error if
 * there is a matching certificate but the signature check cannot be performed.
 * signature check fails or the key is blacklisted, -ENOPKG if the signature
 * uses unsupported crypto, or some other error if there is a matching
 * certificate but the signature check cannot be performed.
 */
int restrict_link_by_signature(struct key *dest_keyring,
			       const struct key_type *type,
@@ -88,6 +89,8 @@ int restrict_link_by_signature(struct key *dest_keyring,
		return -EOPNOTSUPP;

	sig = payload->data[asym_auth];
	if (!sig)
		return -ENOPKG;
	if (!sig->auth_ids[0] && !sig->auth_ids[1])
		return -ENOKEY;

@@ -139,6 +142,8 @@ static int key_or_keyring_common(struct key *dest_keyring,
		return -EOPNOTSUPP;

	sig = payload->data[asym_auth];
	if (!sig)
		return -ENOPKG;
	if (!sig->auth_ids[0] && !sig->auth_ids[1])
		return -ENOKEY;

@@ -222,9 +227,9 @@ static int key_or_keyring_common(struct key *dest_keyring,
 *
 * Returns 0 if the new certificate was accepted, -ENOKEY if we
 * couldn't find a matching parent certificate in the trusted list,
 * -EKEYREJECTED if the signature check fails, and some other error if
 * there is a matching certificate but the signature check cannot be
 * performed.
 * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses
 * unsupported crypto, or some other error if there is a matching certificate
 * but the signature check cannot be performed.
 */
int restrict_link_by_key_or_keyring(struct key *dest_keyring,
				    const struct key_type *type,
@@ -249,9 +254,9 @@ int restrict_link_by_key_or_keyring(struct key *dest_keyring,
 *
 * Returns 0 if the new certificate was accepted, -ENOKEY if we
 * couldn't find a matching parent certificate in the trusted list,
 * -EKEYREJECTED if the signature check fails, and some other error if
 * there is a matching certificate but the signature check cannot be
 * performed.
 * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses
 * unsupported crypto, or some other error if there is a matching certificate
 * but the signature check cannot be performed.
 */
int restrict_link_by_key_or_keyring_chain(struct key *dest_keyring,
					  const struct key_type *type,
+87 −23
Original line number Diff line number Diff line
@@ -22,6 +22,13 @@
#include <keys/big_key-type.h>
#include <crypto/aead.h>

struct big_key_buf {
	unsigned int		nr_pages;
	void			*virt;
	struct scatterlist	*sg;
	struct page		*pages[];
};

/*
 * Layout of key payload words.
 */
@@ -91,10 +98,9 @@ static DEFINE_MUTEX(big_key_aead_lock);
/*
 * Encrypt/decrypt big_key data
 */
static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
static int big_key_crypt(enum big_key_op op, struct big_key_buf *buf, size_t datalen, u8 *key)
{
	int ret;
	struct scatterlist sgio;
	struct aead_request *aead_req;
	/* We always use a zero nonce. The reason we can get away with this is
	 * because we're using a different randomly generated key for every
@@ -109,8 +115,7 @@ static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
		return -ENOMEM;

	memset(zero_nonce, 0, sizeof(zero_nonce));
	sg_init_one(&sgio, data, datalen + (op == BIG_KEY_ENC ? ENC_AUTHTAG_SIZE : 0));
	aead_request_set_crypt(aead_req, &sgio, &sgio, datalen, zero_nonce);
	aead_request_set_crypt(aead_req, buf->sg, buf->sg, datalen, zero_nonce);
	aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
	aead_request_set_ad(aead_req, 0);

@@ -129,22 +134,82 @@ static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
	return ret;
}

/*
 * Free up the buffer.
 */
static void big_key_free_buffer(struct big_key_buf *buf)
{
	unsigned int i;

	if (buf->virt) {
		memset(buf->virt, 0, buf->nr_pages * PAGE_SIZE);
		vunmap(buf->virt);
	}

	for (i = 0; i < buf->nr_pages; i++)
		if (buf->pages[i])
			__free_page(buf->pages[i]);

	kfree(buf);
}

/*
 * Allocate a buffer consisting of a set of pages with a virtual mapping
 * applied over them.
 */
static void *big_key_alloc_buffer(size_t len)
{
	struct big_key_buf *buf;
	unsigned int npg = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
	unsigned int i, l;

	buf = kzalloc(sizeof(struct big_key_buf) +
		      sizeof(struct page) * npg +
		      sizeof(struct scatterlist) * npg,
		      GFP_KERNEL);
	if (!buf)
		return NULL;

	buf->nr_pages = npg;
	buf->sg = (void *)(buf->pages + npg);
	sg_init_table(buf->sg, npg);

	for (i = 0; i < buf->nr_pages; i++) {
		buf->pages[i] = alloc_page(GFP_KERNEL);
		if (!buf->pages[i])
			goto nomem;

		l = min_t(size_t, len, PAGE_SIZE);
		sg_set_page(&buf->sg[i], buf->pages[i], l, 0);
		len -= l;
	}

	buf->virt = vmap(buf->pages, buf->nr_pages, VM_MAP, PAGE_KERNEL);
	if (!buf->virt)
		goto nomem;

	return buf;

nomem:
	big_key_free_buffer(buf);
	return NULL;
}

/*
 * Preparse a big key
 */
int big_key_preparse(struct key_preparsed_payload *prep)
{
	struct big_key_buf *buf;
	struct path *path = (struct path *)&prep->payload.data[big_key_path];
	struct file *file;
	u8 *enckey;
	u8 *data = NULL;
	ssize_t written;
	size_t datalen = prep->datalen;
	size_t datalen = prep->datalen, enclen = datalen + ENC_AUTHTAG_SIZE;
	int ret;

	ret = -EINVAL;
	if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data)
		goto error;
		return -EINVAL;

	/* Set an arbitrary quota */
	prep->quotalen = 16;
@@ -157,13 +222,12 @@ int big_key_preparse(struct key_preparsed_payload *prep)
		 *
		 * File content is stored encrypted with randomly generated key.
		 */
		size_t enclen = datalen + ENC_AUTHTAG_SIZE;
		loff_t pos = 0;

		data = kmalloc(enclen, GFP_KERNEL);
		if (!data)
		buf = big_key_alloc_buffer(enclen);
		if (!buf)
			return -ENOMEM;
		memcpy(data, prep->data, datalen);
		memcpy(buf->virt, prep->data, datalen);

		/* generate random key */
		enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL);
@@ -176,7 +240,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
			goto err_enckey;

		/* encrypt aligned data */
		ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey);
		ret = big_key_crypt(BIG_KEY_ENC, buf, datalen, enckey);
		if (ret)
			goto err_enckey;

@@ -187,7 +251,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
			goto err_enckey;
		}

		written = kernel_write(file, data, enclen, &pos);
		written = kernel_write(file, buf->virt, enclen, &pos);
		if (written != enclen) {
			ret = written;
			if (written >= 0)
@@ -202,7 +266,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
		*path = file->f_path;
		path_get(path);
		fput(file);
		kzfree(data);
		big_key_free_buffer(buf);
	} else {
		/* Just store the data in a buffer */
		void *data = kmalloc(datalen, GFP_KERNEL);
@@ -220,7 +284,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
err_enckey:
	kzfree(enckey);
error:
	kzfree(data);
	big_key_free_buffer(buf);
	return ret;
}

@@ -298,15 +362,15 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
		return datalen;

	if (datalen > BIG_KEY_FILE_THRESHOLD) {
		struct big_key_buf *buf;
		struct path *path = (struct path *)&key->payload.data[big_key_path];
		struct file *file;
		u8 *data;
		u8 *enckey = (u8 *)key->payload.data[big_key_data];
		size_t enclen = datalen + ENC_AUTHTAG_SIZE;
		loff_t pos = 0;

		data = kmalloc(enclen, GFP_KERNEL);
		if (!data)
		buf = big_key_alloc_buffer(enclen);
		if (!buf)
			return -ENOMEM;

		file = dentry_open(path, O_RDONLY, current_cred());
@@ -316,26 +380,26 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
		}

		/* read file to kernel and decrypt */
		ret = kernel_read(file, data, enclen, &pos);
		ret = kernel_read(file, buf->virt, enclen, &pos);
		if (ret >= 0 && ret != enclen) {
			ret = -EIO;
			goto err_fput;
		}

		ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey);
		ret = big_key_crypt(BIG_KEY_DEC, buf, enclen, enckey);
		if (ret)
			goto err_fput;

		ret = datalen;

		/* copy decrypted data to user */
		if (copy_to_user(buffer, data, datalen) != 0)
		if (copy_to_user(buffer, buf->virt, datalen) != 0)
			ret = -EFAULT;

err_fput:
		fput(file);
error:
		kzfree(data);
		big_key_free_buffer(buf);
	} else {
		ret = datalen;
		if (copy_to_user(buffer, key->payload.data[big_key_data],