mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
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:
parent
57be4a784b
commit
b426beb6ee
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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->tfm = tfm;
|
||||
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
||||
desc = digest + digest_size;
|
||||
desc->tfm = tfm;
|
||||
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
||||
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = -ENOMEM;
|
||||
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);
|
||||
might_sleep();
|
||||
ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
|
||||
error:
|
||||
kfree(sig);
|
||||
error_no_sig:
|
||||
crypto_free_shash(tfm);
|
||||
|
||||
pr_devel("<==%s() = %d\n", __func__, 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.
|
||||
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user