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: David Howells <dhowells@redhat.com> Reviewed-by: Kees Cook <keescook@chromium.org> Reviewed-by: Josh Boyer <jwboyer@redhat.com>
This commit is contained in:
@@ -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,
|
|||||||
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,
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
*/
|
*/
|
||||||
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 @@
|
|||||||
#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 = -ENOMEM;
|
ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
|
||||||
sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size);
|
|
||||||
if (!sig->rsa.s)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest);
|
|
||||||
if (ret < 0)
|
|
||||||
goto error_mpi;
|
|
||||||
|
|
||||||
ret = public_key_verify_signature(pub, sig);
|
|
||||||
|
|
||||||
pr_debug("Cert Verification: %d\n", ret);
|
|
||||||
|
|
||||||
error_mpi:
|
|
||||||
mpi_free(sig->rsa.s);
|
|
||||||
error:
|
error:
|
||||||
kfree(sig);
|
|
||||||
error_no_sig:
|
|
||||||
crypto_free_shash(tfm);
|
crypto_free_shash(tfm);
|
||||||
|
|
||||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(x509_get_sig_params);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
pr_devel("==>%s()\n", __func__);
|
||||||
|
|
||||||
|
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);
|
||||||
|
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)
|
|||||||
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",
|
||||||
|
Reference in New Issue
Block a user