Commit b426beb6 authored by David Howells's avatar David Howells

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
...@@ -47,6 +47,8 @@ void x509_free_certificate(struct x509_certificate *cert) ...@@ -47,6 +47,8 @@ void x509_free_certificate(struct x509_certificate *cert)
kfree(cert->subject); kfree(cert->subject);
kfree(cert->fingerprint); kfree(cert->fingerprint);
kfree(cert->authority); kfree(cert->authority);
kfree(cert->sig.digest);
mpi_free(cert->sig.rsa.s);
kfree(cert); kfree(cert);
} }
} }
...@@ -152,33 +154,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, ...@@ -152,33 +154,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
return -ENOPKG; /* Unsupported combination */ return -ENOPKG; /* Unsupported combination */
case OID_md4WithRSAEncryption: case OID_md4WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_MD5; ctx->cert->sig.pkey_hash_algo = PKEY_HASH_MD5;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
case OID_sha1WithRSAEncryption: case OID_sha1WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_SHA1; ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA1;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
case OID_sha256WithRSAEncryption: case OID_sha256WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_SHA256; ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA256;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
case OID_sha384WithRSAEncryption: case OID_sha384WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_SHA384; ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA384;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
case OID_sha512WithRSAEncryption: case OID_sha512WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_SHA512; ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA512;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
case OID_sha224WithRSAEncryption: case OID_sha224WithRSAEncryption:
ctx->cert->sig_hash_algo = PKEY_HASH_SHA224; ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA224;
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
break; break;
} }
...@@ -203,8 +205,8 @@ int x509_note_signature(void *context, size_t hdrlen, ...@@ -203,8 +205,8 @@ int x509_note_signature(void *context, size_t hdrlen,
return -EINVAL; return -EINVAL;
} }
ctx->cert->sig = value; ctx->cert->raw_sig = value;
ctx->cert->sig_size = vlen; ctx->cert->raw_sig_size = vlen;
return 0; return 0;
} }
......
...@@ -21,12 +21,11 @@ struct x509_certificate { ...@@ -21,12 +21,11 @@ struct x509_certificate {
char *authority; /* Authority key fingerprint as hex */ char *authority; /* Authority key fingerprint as hex */
struct tm valid_from; struct tm valid_from;
struct tm valid_to; 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 */ const void *tbs; /* Signed data */
size_t tbs_size; /* Size of signed data */ unsigned tbs_size; /* Size of signed data */
const void *sig; /* Signature data */ unsigned raw_sig_size; /* Size of sigature */
size_t 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 { ...@@ -34,3 +33,10 @@ struct x509_certificate {
*/ */
extern void x509_free_certificate(struct x509_certificate *cert); extern void x509_free_certificate(struct x509_certificate *cert);
extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); 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);
...@@ -24,72 +24,83 @@ ...@@ -24,72 +24,83 @@
#include "x509_parser.h" #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, int x509_get_sig_params(struct x509_certificate *cert)
const struct x509_certificate *cert)
{ {
struct public_key_signature *sig;
struct crypto_shash *tfm; struct crypto_shash *tfm;
struct shash_desc *desc; struct shash_desc *desc;
size_t digest_size, desc_size; size_t digest_size, desc_size;
void *digest;
int ret; int ret;
pr_devel("==>%s()\n", __func__); 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 /* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be. * 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)) if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
digest_size = crypto_shash_digestsize(tfm); digest_size = crypto_shash_digestsize(tfm);
/* We allocate the hash operational data storage on the end of our /* We allocate the hash operational data storage on the end of the
* context data. * digest storage space.
*/ */
ret = -ENOMEM; ret = -ENOMEM;
sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL); digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
if (!sig) if (!digest)
goto error_no_sig; goto error;
sig->pkey_hash_algo = cert->sig_hash_algo; cert->sig.digest = digest;
sig->digest = (u8 *)sig + sizeof(*sig) + desc_size; cert->sig.digest_size = digest_size;
sig->digest_size = digest_size;
desc = (void *)sig + sizeof(*sig); desc = digest + digest_size;
desc->tfm = tfm; desc->tfm = tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
ret = crypto_shash_init(desc); ret = crypto_shash_init(desc);
if (ret < 0) if (ret < 0)
goto error; 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); * Check the signature on a certificate using the provided public key
if (!sig->rsa.s) */
goto error; 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); pr_devel("==>%s()\n", __func__);
if (ret < 0)
goto error_mpi;
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); 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; return ret;
} }
EXPORT_SYMBOL_GPL(x509_check_signature);
/* /*
* 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.
...@@ -118,8 +129,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) ...@@ -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_mday, cert->valid_to.tm_hour,
cert->valid_to.tm_min, cert->valid_to.tm_sec); cert->valid_to.tm_min, cert->valid_to.tm_sec);
pr_devel("Cert Signature: %s + %s\n", pr_devel("Cert Signature: %s + %s\n",
pkey_algo_name[cert->sig_pkey_algo], pkey_algo_name[cert->sig.pkey_algo],
pkey_hash_algo_name[cert->sig_hash_algo]); pkey_hash_algo_name[cert->sig.pkey_hash_algo]);
if (!cert->fingerprint || !cert->authority) { if (!cert->fingerprint || !cert->authority) {
pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n", pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
......
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