]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
PKCS#7: Find the right key in the PKCS#7 key list and verify the signature
authorDavid Howells <dhowells@redhat.com>
Tue, 15 Jan 2013 15:33:39 +0000 (15:33 +0000)
committerDavid Howells <dhowells@redhat.com>
Sat, 19 Jan 2013 01:05:19 +0000 (01:05 +0000)
Find the appropriate key in the PKCS#7 key list and verify the signature with
it.  There may be several keys in there forming a chain.  Any link in that
chain or the root of that chain may be in our keyrings.

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
crypto/asymmetric_keys/pkcs7_verify.c

index 2f9f26c55f8be5a1378fe2eb904695b1d60b5db1..3f6f0e2b5ed5b79b4ed77adff4387c139cad3129 100644 (file)
@@ -117,6 +117,53 @@ error_no_desc:
        return ret;
 }
 
+/*
+ * Find the key (X.509 certificate) to use to verify a PKCS#7 message.  PKCS#7
+ * uses the issuer's name and the issuing certificate serial number for
+ * matching purposes.  These must match the certificate issuer's name (not
+ * subject's name) and the certificate serial number [RFC 2315 6.7].
+ */
+static int pkcs7_find_key(struct pkcs7_message *pkcs7)
+{
+       struct x509_certificate *x509;
+
+       kenter("%u,%u", pkcs7->raw_serial_size, pkcs7->raw_issuer_size);
+
+       for (x509 = pkcs7->certs; x509; x509 = x509->next) {
+               pr_devel("- x509 %u,%u\n",
+                        x509->raw_serial_size, x509->raw_issuer_size);
+
+               /* I'm _assuming_ that the generator of the PKCS#7 message will
+                * encode the fields from the X.509 cert in the same way in the
+                * PKCS#7 message - but I can't be 100% sure of that.  It's
+                * possible this will need element-by-element comparison.
+                */
+               if (x509->raw_serial_size != pkcs7->raw_serial_size ||
+                   memcmp(x509->raw_serial, pkcs7->raw_serial,
+                          pkcs7->raw_serial_size) != 0)
+                       continue;
+               pr_devel("Found cert serial match\n");
+
+               if (x509->raw_issuer_size != pkcs7->raw_issuer_size ||
+                   memcmp(x509->raw_issuer, pkcs7->raw_issuer,
+                          pkcs7->raw_issuer_size) != 0) {
+                       pr_warn("X.509 subject and PKCS#7 issuer don't match\n");
+                       continue;
+               }
+
+               if (x509->pub->pkey_algo != pkcs7->sig.pkey_algo) {
+                       pr_warn("X.509 algo and PKCS#7 sig algo don't match\n");
+                       continue;
+               }
+
+               pkcs7->signer = x509;
+               return 0;
+       }
+       pr_warn("Issuing X.509 cert not found (#%*ph)\n",
+               pkcs7->raw_serial_size, pkcs7->raw_serial);
+       return -ENOKEY;
+}
+
 /*
  * Verify a PKCS#7 message
  */
@@ -129,6 +176,20 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
        if (ret < 0)
                return ret;
 
+       /* Find the key for the message signature */
+       ret = pkcs7_find_key(pkcs7);
+       if (ret < 0)
+               return ret;
+
+       pr_devel("Found X.509 cert\n");
+
+       /* Verify the PKCS#7 binary against the key */
+       ret = public_key_verify_signature(pkcs7->signer->pub, &pkcs7->sig);
+       if (ret < 0)
+               return ret;
+
+       pr_devel("Verified signature\n");
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(pkcs7_verify);