summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2014-07-01 16:40:19 +0100
committerDavid Howells <dhowells@redhat.com>2014-07-08 13:50:11 +0100
commit8c76d79393ccc9b89d9af402d79a49a9cd43c5aa (patch)
tree482d70a25d548d0a82d08ac0bb9e2749b388d633 /crypto
parenta4730357ee724f8c64f0292541ba3da8a95510fb (diff)
downloadlinux-8c76d79393ccc9b89d9af402d79a49a9cd43c5aa.tar.bz2
PKCS#7: Verify internal certificate chain
Verify certificate chain in the X.509 certificates contained within the PKCS#7 message as far as possible. If any signature that we should be able to verify fails, we reject the whole lot. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Vivek Goyal <vgoyal@redhat.com> Reviewed-by: Kees Cook <keescook@chromium.org>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/asymmetric_keys/pkcs7_verify.c88
1 files changed, 87 insertions, 1 deletions
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 745e5c86a35e..51ff36f3a913 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -170,6 +170,91 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
}
/*
+ * Verify the internal certificate chain as best we can.
+ */
+static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
+ struct pkcs7_signed_info *sinfo)
+{
+ struct x509_certificate *x509 = sinfo->signer, *p;
+ int ret;
+
+ kenter("");
+
+ for (p = pkcs7->certs; p; p = p->next)
+ p->seen = false;
+
+ for (;;) {
+ pr_debug("verify %s: %s\n", x509->subject, x509->fingerprint);
+ x509->seen = true;
+ ret = x509_get_sig_params(x509);
+ if (ret < 0)
+ return ret;
+
+ if (x509->issuer)
+ pr_debug("- issuer %s\n", x509->issuer);
+ if (x509->authority)
+ pr_debug("- authkeyid %s\n", x509->authority);
+
+ if (!x509->authority ||
+ (x509->subject &&
+ strcmp(x509->subject, x509->issuer) == 0)) {
+ /* 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)
+ return ret;
+ x509->signer = x509;
+ pr_debug("- self-signed\n");
+ return 0;
+ }
+
+ /* Look through the X.509 certificates in the PKCS#7 message's
+ * list to see if the next one is there.
+ */
+ pr_debug("- want %s\n", x509->authority);
+ for (p = pkcs7->certs; p; p = p->next) {
+ pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint);
+ if (p->raw_subject_size == x509->raw_issuer_size &&
+ strcmp(p->fingerprint, x509->authority) == 0 &&
+ memcmp(p->raw_subject, x509->raw_issuer,
+ x509->raw_issuer_size) == 0)
+ goto found_issuer;
+ }
+
+ /* We didn't find the root of this chain */
+ pr_debug("- top\n");
+ return 0;
+
+ found_issuer:
+ pr_debug("- issuer %s\n", p->subject);
+ if (p->seen) {
+ pr_warn("Sig %u: X.509 chain contains loop\n",
+ sinfo->index);
+ return 0;
+ }
+ ret = x509_check_signature(p->pub, x509);
+ if (ret < 0)
+ return ret;
+ x509->signer = p;
+ if (x509 == p) {
+ pr_debug("- self-signed\n");
+ return 0;
+ }
+ x509 = p;
+ might_sleep();
+ }
+}
+
+/*
* Verify one signed information block from a PKCS#7 message.
*/
static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
@@ -201,7 +286,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
pr_devel("Verified signature %u\n", sinfo->index);
- return 0;
+ /* Verify the internal certificate chain */
+ return pkcs7_verify_sig_chain(pkcs7, sinfo);
}
/**