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

Commit b426beb6 authored by David Howells's avatar David Howells
Browse files

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: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Reviewed-by: default avatarJosh Boyer <jwboyer@redhat.com>
parent 57be4a78
Loading
Loading
Loading
Loading
+16 −14
Original line number Diff line number Diff line
@@ -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;
}

+11 −5
Original line number Diff line number Diff line
@@ -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);
+47 −36
Original line number Diff line number Diff line
@@ -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 = 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",