PKCS#7: Find the right key in the PKCS#7 key list and verify the signature
authorDavid Howells <dhowells@redhat.com>
Tue, 1 Jul 2014 15:40:19 +0000 (16:40 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 8 Jul 2014 12:50:08 +0000 (13:50 +0100)
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>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
crypto/asymmetric_keys/pkcs7_verify.c
include/crypto/pkcs7.h

index 0bb408a5b64f9cf2b5840d0bac9c343f7b2e6d4f..745e5c86a35e309a92f44073302f22420a6ce660 100644 (file)
@@ -120,6 +120,55 @@ error_no_desc:
 }
 
 /*
+ * 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 pkcs7_signed_info *sinfo)
+{
+       struct x509_certificate *x509;
+       unsigned certix = 1;
+
+       kenter("%u,%u,%u",
+              sinfo->index, sinfo->raw_serial_size, sinfo->raw_issuer_size);
+
+       for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) {
+               /* 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 != sinfo->raw_serial_size ||
+                   memcmp(x509->raw_serial, sinfo->raw_serial,
+                          sinfo->raw_serial_size) != 0)
+                       continue;
+               pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
+                        sinfo->index, certix);
+
+               if (x509->raw_issuer_size != sinfo->raw_issuer_size ||
+                   memcmp(x509->raw_issuer, sinfo->raw_issuer,
+                          sinfo->raw_issuer_size) != 0) {
+                       pr_warn("Sig %u: X.509 subject and PKCS#7 issuer don't match\n",
+                               sinfo->index);
+                       continue;
+               }
+
+               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;
+               }
+
+               sinfo->signer = x509;
+               return 0;
+       }
+       pr_warn("Sig %u: Issuing X.509 cert not found (#%*ph)\n",
+               sinfo->index, sinfo->raw_serial_size, sinfo->raw_serial);
+       return -ENOKEY;
+}
+
 /*
  * Verify one signed information block from a PKCS#7 message.
  */
@@ -137,6 +186,21 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
        if (ret < 0)
                return ret;
 
+       /* Find the key for the signature */
+       ret = pkcs7_find_key(pkcs7, sinfo);
+       if (ret < 0)
+               return ret;
+
+       pr_devel("Using X.509[%u] for sig %u\n",
+                sinfo->signer->index, sinfo->index);
+
+       /* Verify the PKCS#7 binary against the key */
+       ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
+       if (ret < 0)
+               return ret;
+
+       pr_devel("Verified signature %u\n", sinfo->index);
+
        return 0;
 }
 
index 8f2628fbdfce7576d1f750d1d559aad384878fe1..8ba0f3810d6718656e07374e5564d9658173ffdc 100644 (file)
@@ -21,3 +21,8 @@ extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
 extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
                                  const void **_data, size_t *_datalen,
                                  bool want_wrapper);
+
+/*
+ * pkcs7_verify.c
+ */
+extern int pkcs7_verify(struct pkcs7_message *pkcs7);