forked from luck/tmp_suning_uos_patched
PKCS#7: Make the signature a pointer rather than embedding it
Point to the public_key_signature struct from the pkcs7_signed_info struct rather than embedding it. This makes the code consistent with the X.509 signature handling and makes it possible to have a common cleanup function. We also save a copy of the digest in the signature without sharing the memory with the crypto layer metadata. Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
parent
77d0910d15
commit
566a117a8b
|
@ -44,9 +44,7 @@ struct pkcs7_parse_context {
|
||||||
static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
|
static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
|
||||||
{
|
{
|
||||||
if (sinfo) {
|
if (sinfo) {
|
||||||
kfree(sinfo->sig.s);
|
public_key_signature_free(sinfo->sig);
|
||||||
kfree(sinfo->sig.digest);
|
|
||||||
kfree(sinfo->signing_cert_id);
|
|
||||||
kfree(sinfo);
|
kfree(sinfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,6 +123,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
|
||||||
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
|
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
|
||||||
if (!ctx->sinfo)
|
if (!ctx->sinfo)
|
||||||
goto out_no_sinfo;
|
goto out_no_sinfo;
|
||||||
|
ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!ctx->sinfo->sig)
|
||||||
|
goto out_no_sig;
|
||||||
|
|
||||||
ctx->data = (unsigned long)data;
|
ctx->data = (unsigned long)data;
|
||||||
ctx->ppcerts = &ctx->certs;
|
ctx->ppcerts = &ctx->certs;
|
||||||
|
@ -150,6 +152,7 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
|
||||||
ctx->certs = cert->next;
|
ctx->certs = cert->next;
|
||||||
x509_free_certificate(cert);
|
x509_free_certificate(cert);
|
||||||
}
|
}
|
||||||
|
out_no_sig:
|
||||||
pkcs7_free_signed_info(ctx->sinfo);
|
pkcs7_free_signed_info(ctx->sinfo);
|
||||||
out_no_sinfo:
|
out_no_sinfo:
|
||||||
pkcs7_free_message(ctx->msg);
|
pkcs7_free_message(ctx->msg);
|
||||||
|
@ -218,25 +221,26 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
|
||||||
|
|
||||||
switch (ctx->last_oid) {
|
switch (ctx->last_oid) {
|
||||||
case OID_md4:
|
case OID_md4:
|
||||||
ctx->sinfo->sig.hash_algo = "md4";
|
ctx->sinfo->sig->hash_algo = "md4";
|
||||||
break;
|
break;
|
||||||
case OID_md5:
|
case OID_md5:
|
||||||
ctx->sinfo->sig.hash_algo = "md5";
|
ctx->sinfo->sig->hash_algo = "md5";
|
||||||
break;
|
break;
|
||||||
case OID_sha1:
|
case OID_sha1:
|
||||||
ctx->sinfo->sig.hash_algo = "sha1";
|
ctx->sinfo->sig->hash_algo = "sha1";
|
||||||
break;
|
break;
|
||||||
case OID_sha256:
|
case OID_sha256:
|
||||||
ctx->sinfo->sig.hash_algo = "sha256";
|
ctx->sinfo->sig->hash_algo = "sha256";
|
||||||
break;
|
break;
|
||||||
case OID_sha384:
|
case OID_sha384:
|
||||||
ctx->sinfo->sig.hash_algo = "sha384";
|
ctx->sinfo->sig->hash_algo = "sha384";
|
||||||
break;
|
break;
|
||||||
case OID_sha512:
|
case OID_sha512:
|
||||||
ctx->sinfo->sig.hash_algo = "sha512";
|
ctx->sinfo->sig->hash_algo = "sha512";
|
||||||
break;
|
break;
|
||||||
case OID_sha224:
|
case OID_sha224:
|
||||||
ctx->sinfo->sig.hash_algo = "sha224";
|
ctx->sinfo->sig->hash_algo = "sha224";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printk("Unsupported digest algo: %u\n", ctx->last_oid);
|
printk("Unsupported digest algo: %u\n", ctx->last_oid);
|
||||||
return -ENOPKG;
|
return -ENOPKG;
|
||||||
|
@ -255,7 +259,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
|
||||||
|
|
||||||
switch (ctx->last_oid) {
|
switch (ctx->last_oid) {
|
||||||
case OID_rsaEncryption:
|
case OID_rsaEncryption:
|
||||||
ctx->sinfo->sig.pkey_algo = "rsa";
|
ctx->sinfo->sig->pkey_algo = "rsa";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk("Unsupported pkey algo: %u\n", ctx->last_oid);
|
printk("Unsupported pkey algo: %u\n", ctx->last_oid);
|
||||||
|
@ -615,11 +619,11 @@ int pkcs7_sig_note_signature(void *context, size_t hdrlen,
|
||||||
{
|
{
|
||||||
struct pkcs7_parse_context *ctx = context;
|
struct pkcs7_parse_context *ctx = context;
|
||||||
|
|
||||||
ctx->sinfo->sig.s = kmemdup(value, vlen, GFP_KERNEL);
|
ctx->sinfo->sig->s = kmemdup(value, vlen, GFP_KERNEL);
|
||||||
if (!ctx->sinfo->sig.s)
|
if (!ctx->sinfo->sig->s)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ctx->sinfo->sig.s_size = vlen;
|
ctx->sinfo->sig->s_size = vlen;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,12 +659,16 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
|
||||||
|
|
||||||
pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
|
pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
|
||||||
|
|
||||||
sinfo->signing_cert_id = kid;
|
sinfo->sig->auth_ids[0] = kid;
|
||||||
sinfo->index = ++ctx->sinfo_index;
|
sinfo->index = ++ctx->sinfo_index;
|
||||||
*ctx->ppsinfo = sinfo;
|
*ctx->ppsinfo = sinfo;
|
||||||
ctx->ppsinfo = &sinfo->next;
|
ctx->ppsinfo = &sinfo->next;
|
||||||
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
|
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
|
||||||
if (!ctx->sinfo)
|
if (!ctx->sinfo)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!ctx->sinfo->sig)
|
||||||
|
return -ENOMEM;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,19 +41,17 @@ struct pkcs7_signed_info {
|
||||||
#define sinfo_has_ms_statement_type 5
|
#define sinfo_has_ms_statement_type 5
|
||||||
time64_t signing_time;
|
time64_t signing_time;
|
||||||
|
|
||||||
/* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1]
|
|
||||||
* or issuing cert's SKID [CMS ver 3].
|
|
||||||
*/
|
|
||||||
struct asymmetric_key_id *signing_cert_id;
|
|
||||||
|
|
||||||
/* Message signature.
|
/* Message signature.
|
||||||
*
|
*
|
||||||
* This contains the generated digest of _either_ the Content Data or
|
* This contains the generated digest of _either_ the Content Data or
|
||||||
* the Authenticated Attributes [RFC2315 9.3]. If the latter, one of
|
* the Authenticated Attributes [RFC2315 9.3]. If the latter, one of
|
||||||
* the attributes contains the digest of the the Content Data within
|
* the attributes contains the digest of the the Content Data within
|
||||||
* it.
|
* it.
|
||||||
|
*
|
||||||
|
* THis also contains the issuing cert serial number and issuer's name
|
||||||
|
* [PKCS#7 or CMS ver 1] or issuing cert's SKID [CMS ver 3].
|
||||||
*/
|
*/
|
||||||
struct public_key_signature sig;
|
struct public_key_signature *sig;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pkcs7_message {
|
struct pkcs7_message {
|
||||||
|
|
|
@ -27,7 +27,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
|
||||||
struct pkcs7_signed_info *sinfo,
|
struct pkcs7_signed_info *sinfo,
|
||||||
struct key *trust_keyring)
|
struct key *trust_keyring)
|
||||||
{
|
{
|
||||||
struct public_key_signature *sig = &sinfo->sig;
|
struct public_key_signature *sig = sinfo->sig;
|
||||||
struct x509_certificate *x509, *last = NULL, *p;
|
struct x509_certificate *x509, *last = NULL, *p;
|
||||||
struct key *key;
|
struct key *key;
|
||||||
bool trusted;
|
bool trusted;
|
||||||
|
@ -105,7 +105,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
|
||||||
* the signed info directly.
|
* the signed info directly.
|
||||||
*/
|
*/
|
||||||
key = x509_request_asymmetric_key(trust_keyring,
|
key = x509_request_asymmetric_key(trust_keyring,
|
||||||
sinfo->signing_cert_id,
|
sinfo->sig->auth_ids[0],
|
||||||
NULL,
|
NULL,
|
||||||
false);
|
false);
|
||||||
if (!IS_ERR(key)) {
|
if (!IS_ERR(key)) {
|
||||||
|
|
|
@ -25,34 +25,36 @@
|
||||||
static int pkcs7_digest(struct pkcs7_message *pkcs7,
|
static int pkcs7_digest(struct pkcs7_message *pkcs7,
|
||||||
struct pkcs7_signed_info *sinfo)
|
struct pkcs7_signed_info *sinfo)
|
||||||
{
|
{
|
||||||
|
struct public_key_signature *sig = sinfo->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 desc_size;
|
||||||
void *digest;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
kenter(",%u,%s", sinfo->index, sinfo->sig.hash_algo);
|
kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
|
||||||
|
|
||||||
if (!sinfo->sig.hash_algo)
|
if (!sinfo->sig->hash_algo)
|
||||||
return -ENOPKG;
|
return -ENOPKG;
|
||||||
|
|
||||||
/* 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(sinfo->sig.hash_algo, 0, 0);
|
tfm = crypto_alloc_shash(sinfo->sig->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);
|
||||||
sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm);
|
sig->digest_size = crypto_shash_digestsize(tfm);
|
||||||
|
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size,
|
sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
|
||||||
GFP_KERNEL);
|
if (!sig->digest)
|
||||||
if (!digest)
|
goto error_no_desc;
|
||||||
|
|
||||||
|
desc = kzalloc(desc_size, GFP_KERNEL);
|
||||||
|
if (!desc)
|
||||||
goto error_no_desc;
|
goto error_no_desc;
|
||||||
|
|
||||||
desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
|
|
||||||
desc->tfm = tfm;
|
desc->tfm = tfm;
|
||||||
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
||||||
|
|
||||||
|
@ -60,10 +62,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
|
||||||
ret = crypto_shash_init(desc);
|
ret = crypto_shash_init(desc);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest);
|
ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len,
|
||||||
|
sig->digest);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
pr_devel("MsgDigest = [%*ph]\n", 8, digest);
|
pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest);
|
||||||
|
|
||||||
/* However, if there are authenticated attributes, there must be a
|
/* However, if there are authenticated attributes, there must be a
|
||||||
* message digest attribute amongst them which corresponds to the
|
* message digest attribute amongst them which corresponds to the
|
||||||
|
@ -78,14 +81,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
|
if (sinfo->msgdigest_len != sig->digest_size) {
|
||||||
pr_debug("Sig %u: Invalid digest size (%u)\n",
|
pr_debug("Sig %u: Invalid digest size (%u)\n",
|
||||||
sinfo->index, sinfo->msgdigest_len);
|
sinfo->index, sinfo->msgdigest_len);
|
||||||
ret = -EBADMSG;
|
ret = -EBADMSG;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) {
|
if (memcmp(sig->digest, sinfo->msgdigest,
|
||||||
|
sinfo->msgdigest_len) != 0) {
|
||||||
pr_debug("Sig %u: Message digest doesn't match\n",
|
pr_debug("Sig %u: Message digest doesn't match\n",
|
||||||
sinfo->index);
|
sinfo->index);
|
||||||
ret = -EKEYREJECTED;
|
ret = -EKEYREJECTED;
|
||||||
|
@ -97,7 +101,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
|
||||||
* convert the attributes from a CONT.0 into a SET before we
|
* convert the attributes from a CONT.0 into a SET before we
|
||||||
* hash it.
|
* hash it.
|
||||||
*/
|
*/
|
||||||
memset(digest, 0, sinfo->sig.digest_size);
|
memset(sig->digest, 0, sig->digest_size);
|
||||||
|
|
||||||
ret = crypto_shash_init(desc);
|
ret = crypto_shash_init(desc);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -107,17 +111,14 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
ret = crypto_shash_finup(desc, sinfo->authattrs,
|
ret = crypto_shash_finup(desc, sinfo->authattrs,
|
||||||
sinfo->authattrs_len, digest);
|
sinfo->authattrs_len, sig->digest);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
pr_devel("AADigest = [%*ph]\n", 8, digest);
|
pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
sinfo->sig.digest = digest;
|
|
||||||
digest = NULL;
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
kfree(digest);
|
kfree(desc);
|
||||||
error_no_desc:
|
error_no_desc:
|
||||||
crypto_free_shash(tfm);
|
crypto_free_shash(tfm);
|
||||||
kleave(" = %d", ret);
|
kleave(" = %d", ret);
|
||||||
|
@ -144,12 +145,12 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
|
||||||
* PKCS#7 message - but I can't be 100% sure of that. It's
|
* PKCS#7 message - but I can't be 100% sure of that. It's
|
||||||
* possible this will need element-by-element comparison.
|
* possible this will need element-by-element comparison.
|
||||||
*/
|
*/
|
||||||
if (!asymmetric_key_id_same(x509->id, sinfo->signing_cert_id))
|
if (!asymmetric_key_id_same(x509->id, sinfo->sig->auth_ids[0]))
|
||||||
continue;
|
continue;
|
||||||
pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
|
pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
|
||||||
sinfo->index, certix);
|
sinfo->index, certix);
|
||||||
|
|
||||||
if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
|
if (x509->pub->pkey_algo != sinfo->sig->pkey_algo) {
|
||||||
pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
|
pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
|
||||||
sinfo->index);
|
sinfo->index);
|
||||||
continue;
|
continue;
|
||||||
|
@ -164,7 +165,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
|
||||||
*/
|
*/
|
||||||
pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n",
|
pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n",
|
||||||
sinfo->index,
|
sinfo->index,
|
||||||
sinfo->signing_cert_id->len, sinfo->signing_cert_id->data);
|
sinfo->sig->auth_ids[0]->len, sinfo->sig->auth_ids[0]->data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +335,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify the PKCS#7 binary against the key */
|
/* Verify the PKCS#7 binary against the key */
|
||||||
ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
|
ret = public_key_verify_signature(sinfo->signer->pub, sinfo->sig);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user