|
@@ -25,34 +25,36 @@
|
|
|
static int pkcs7_digest(struct pkcs7_message *pkcs7,
|
|
|
struct pkcs7_signed_info *sinfo)
|
|
|
{
|
|
|
+ struct public_key_signature *sig = sinfo->sig;
|
|
|
struct crypto_shash *tfm;
|
|
|
struct shash_desc *desc;
|
|
|
- size_t digest_size, desc_size;
|
|
|
- void *digest;
|
|
|
+ size_t desc_size;
|
|
|
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;
|
|
|
|
|
|
/* Allocate the hashing algorithm we're going to need and find out how
|
|
|
* 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))
|
|
|
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
|
|
|
|
|
|
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;
|
|
|
- digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size,
|
|
|
- GFP_KERNEL);
|
|
|
- if (!digest)
|
|
|
+ sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
|
|
|
+ if (!sig->digest)
|
|
|
+ goto error_no_desc;
|
|
|
+
|
|
|
+ desc = kzalloc(desc_size, GFP_KERNEL);
|
|
|
+ if (!desc)
|
|
|
goto error_no_desc;
|
|
|
|
|
|
- desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
|
|
|
desc->tfm = tfm;
|
|
|
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
|
|
|
|
@@ -60,10 +62,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
|
|
|
ret = crypto_shash_init(desc);
|
|
|
if (ret < 0)
|
|
|
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)
|
|
|
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
|
|
|
* message digest attribute amongst them which corresponds to the
|
|
@@ -78,14 +81,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
|
|
|
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",
|
|
|
sinfo->index, sinfo->msgdigest_len);
|
|
|
ret = -EBADMSG;
|
|
|
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",
|
|
|
sinfo->index);
|
|
|
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
|
|
|
* hash it.
|
|
|
*/
|
|
|
- memset(digest, 0, sinfo->sig.digest_size);
|
|
|
+ memset(sig->digest, 0, sig->digest_size);
|
|
|
|
|
|
ret = crypto_shash_init(desc);
|
|
|
if (ret < 0)
|
|
@@ -107,17 +111,14 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
|
|
|
if (ret < 0)
|
|
|
goto error;
|
|
|
ret = crypto_shash_finup(desc, sinfo->authattrs,
|
|
|
- sinfo->authattrs_len, digest);
|
|
|
+ sinfo->authattrs_len, sig->digest);
|
|
|
if (ret < 0)
|
|
|
goto error;
|
|
|
- pr_devel("AADigest = [%*ph]\n", 8, digest);
|
|
|
+ pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
|
|
|
}
|
|
|
|
|
|
- sinfo->sig.digest = digest;
|
|
|
- digest = NULL;
|
|
|
-
|
|
|
error:
|
|
|
- kfree(digest);
|
|
|
+ kfree(desc);
|
|
|
error_no_desc:
|
|
|
crypto_free_shash(tfm);
|
|
|
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
|
|
|
* 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;
|
|
|
pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
|
|
|
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",
|
|
|
sinfo->index);
|
|
|
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",
|
|
|
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;
|
|
|
}
|
|
|
|
|
@@ -174,6 +175,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
|
|
|
static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
|
|
|
struct pkcs7_signed_info *sinfo)
|
|
|
{
|
|
|
+ struct public_key_signature *sig;
|
|
|
struct x509_certificate *x509 = sinfo->signer, *p;
|
|
|
struct asymmetric_key_id *auth;
|
|
|
int ret;
|
|
@@ -188,34 +190,26 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
|
|
|
x509->subject,
|
|
|
x509->raw_serial_size, x509->raw_serial);
|
|
|
x509->seen = true;
|
|
|
- ret = x509_get_sig_params(x509);
|
|
|
- if (ret < 0)
|
|
|
- goto maybe_missing_crypto_in_x509;
|
|
|
+ if (x509->unsupported_key)
|
|
|
+ goto unsupported_crypto_in_x509;
|
|
|
|
|
|
pr_debug("- issuer %s\n", x509->issuer);
|
|
|
- if (x509->akid_id)
|
|
|
+ sig = x509->sig;
|
|
|
+ if (sig->auth_ids[0])
|
|
|
pr_debug("- authkeyid.id %*phN\n",
|
|
|
- x509->akid_id->len, x509->akid_id->data);
|
|
|
- if (x509->akid_skid)
|
|
|
+ sig->auth_ids[0]->len, sig->auth_ids[0]->data);
|
|
|
+ if (sig->auth_ids[1])
|
|
|
pr_debug("- authkeyid.skid %*phN\n",
|
|
|
- x509->akid_skid->len, x509->akid_skid->data);
|
|
|
+ sig->auth_ids[1]->len, sig->auth_ids[1]->data);
|
|
|
|
|
|
- if ((!x509->akid_id && !x509->akid_skid) ||
|
|
|
- strcmp(x509->subject, x509->issuer) == 0) {
|
|
|
+ if (x509->self_signed) {
|
|
|
/* If there's no authority certificate specified, then
|
|
|
* the certificate must be self-signed and is the root
|
|
|
* of the chain. Likewise if the cert is its own
|
|
|
* authority.
|
|
|
*/
|
|
|
- pr_debug("- no auth?\n");
|
|
|
- if (x509->raw_subject_size != x509->raw_issuer_size ||
|
|
|
- memcmp(x509->raw_subject, x509->raw_issuer,
|
|
|
- x509->raw_issuer_size) != 0)
|
|
|
- return 0;
|
|
|
-
|
|
|
- ret = x509_check_signature(x509->pub, x509);
|
|
|
- if (ret < 0)
|
|
|
- goto maybe_missing_crypto_in_x509;
|
|
|
+ if (x509->unsupported_sig)
|
|
|
+ goto unsupported_crypto_in_x509;
|
|
|
x509->signer = x509;
|
|
|
pr_debug("- self-signed\n");
|
|
|
return 0;
|
|
@@ -224,7 +218,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
|
|
|
/* Look through the X.509 certificates in the PKCS#7 message's
|
|
|
* list to see if the next one is there.
|
|
|
*/
|
|
|
- auth = x509->akid_id;
|
|
|
+ auth = sig->auth_ids[0];
|
|
|
if (auth) {
|
|
|
pr_debug("- want %*phN\n", auth->len, auth->data);
|
|
|
for (p = pkcs7->certs; p; p = p->next) {
|
|
@@ -234,7 +228,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
|
|
|
goto found_issuer_check_skid;
|
|
|
}
|
|
|
} else {
|
|
|
- auth = x509->akid_skid;
|
|
|
+ auth = sig->auth_ids[1];
|
|
|
pr_debug("- want %*phN\n", auth->len, auth->data);
|
|
|
for (p = pkcs7->certs; p; p = p->next) {
|
|
|
if (!p->skid)
|
|
@@ -254,8 +248,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
|
|
|
/* We matched issuer + serialNumber, but if there's an
|
|
|
* authKeyId.keyId, that must match the CA subjKeyId also.
|
|
|
*/
|
|
|
- if (x509->akid_skid &&
|
|
|
- !asymmetric_key_id_same(p->skid, x509->akid_skid)) {
|
|
|
+ if (sig->auth_ids[1] &&
|
|
|
+ !asymmetric_key_id_same(p->skid, sig->auth_ids[1])) {
|
|
|
pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n",
|
|
|
sinfo->index, x509->index, p->index);
|
|
|
return -EKEYREJECTED;
|
|
@@ -267,7 +261,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
|
|
|
sinfo->index);
|
|
|
return 0;
|
|
|
}
|
|
|
- ret = x509_check_signature(p->pub, x509);
|
|
|
+ ret = public_key_verify_signature(p->pub, p->sig);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
x509->signer = p;
|
|
@@ -279,16 +273,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
|
|
|
might_sleep();
|
|
|
}
|
|
|
|
|
|
-maybe_missing_crypto_in_x509:
|
|
|
+unsupported_crypto_in_x509:
|
|
|
/* Just prune the certificate chain at this point if we lack some
|
|
|
* crypto module to go further. Note, however, we don't want to set
|
|
|
- * sinfo->missing_crypto as the signed info block may still be
|
|
|
+ * sinfo->unsupported_crypto as the signed info block may still be
|
|
|
* validatable against an X.509 cert lower in the chain that we have a
|
|
|
* trusted copy of.
|
|
|
*/
|
|
|
- if (ret == -ENOPKG)
|
|
|
- return 0;
|
|
|
- return ret;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -332,7 +324,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
|
|
|
}
|
|
|
|
|
|
/* 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)
|
|
|
return ret;
|
|
|
|
|
@@ -375,9 +367,8 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
|
|
|
enum key_being_used_for usage)
|
|
|
{
|
|
|
struct pkcs7_signed_info *sinfo;
|
|
|
- struct x509_certificate *x509;
|
|
|
int enopkg = -ENOPKG;
|
|
|
- int ret, n;
|
|
|
+ int ret;
|
|
|
|
|
|
kenter("");
|
|
|
|
|
@@ -419,12 +410,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
|
|
|
- ret = x509_get_sig_params(x509);
|
|
|
- if (ret < 0)
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
|
|
|
ret = pkcs7_verify_one(pkcs7, sinfo);
|
|
|
if (ret < 0) {
|