Merge tag 'iwlwifi-for-kalle-2015-10-05' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / crypto / asymmetric_keys / pkcs7_verify.c
index 42bfc9de0d796ee7c8262bfef2a79b02b5132017..d20c0b4b880ed1e6dde6552cfce4c6d85a05b053 100644 (file)
@@ -70,9 +70,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
         * message digest attribute amongst them which corresponds to the
         * digest we just calculated.
         */
-       if (sinfo->msgdigest) {
+       if (sinfo->authattrs) {
                u8 tag;
 
+               if (!sinfo->msgdigest) {
+                       pr_warn("Sig %u: No messageDigest\n", sinfo->index);
+                       ret = -EKEYREJECTED;
+                       goto error;
+               }
+
                if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
                        pr_debug("Sig %u: Invalid digest size (%u)\n",
                                 sinfo->index, sinfo->msgdigest_len);
@@ -314,6 +320,18 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
        pr_devel("Using X.509[%u] for sig %u\n",
                 sinfo->signer->index, sinfo->index);
 
+       /* Check that the PKCS#7 signing time is valid according to the X.509
+        * certificate.  We can't, however, check against the system clock
+        * since that may not have been set yet and may be wrong.
+        */
+       if (test_bit(sinfo_has_signing_time, &sinfo->aa_set)) {
+               if (sinfo->signing_time < sinfo->signer->valid_from ||
+                   sinfo->signing_time > sinfo->signer->valid_to) {
+                       pr_warn("Message signed outside of X.509 validity window\n");
+                       return -EKEYREJECTED;
+               }
+       }
+
        /* Verify the PKCS#7 binary against the key */
        ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
        if (ret < 0)
@@ -328,6 +346,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
 /**
  * pkcs7_verify - Verify a PKCS#7 message
  * @pkcs7: The PKCS#7 message to be verified
+ * @usage: The use to which the key is being put
  *
  * Verify a PKCS#7 message is internally consistent - that is, the data digest
  * matches the digest in the AuthAttrs and any signature in the message or one
@@ -339,6 +358,9 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
  *
  * Returns, in order of descending priority:
  *
+ *  (*) -EKEYREJECTED if a key was selected that had a usage restriction at
+ *      odds with the specified usage, or:
+ *
  *  (*) -EKEYREJECTED if a signature failed to match for which we found an
  *     appropriate X.509 certificate, or:
  *
@@ -350,7 +372,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
  *  (*) 0 if all the signature chains that don't incur -ENOPKG can be verified
  *     (note that a signature chain may be of zero length), or:
  */
-int pkcs7_verify(struct pkcs7_message *pkcs7)
+int pkcs7_verify(struct pkcs7_message *pkcs7,
+                enum key_being_used_for usage)
 {
        struct pkcs7_signed_info *sinfo;
        struct x509_certificate *x509;
@@ -359,6 +382,44 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
 
        kenter("");
 
+       switch (usage) {
+       case VERIFYING_MODULE_SIGNATURE:
+               if (pkcs7->data_type != OID_data) {
+                       pr_warn("Invalid module sig (not pkcs7-data)\n");
+                       return -EKEYREJECTED;
+               }
+               if (pkcs7->have_authattrs) {
+                       pr_warn("Invalid module sig (has authattrs)\n");
+                       return -EKEYREJECTED;
+               }
+               break;
+       case VERIFYING_FIRMWARE_SIGNATURE:
+               if (pkcs7->data_type != OID_data) {
+                       pr_warn("Invalid firmware sig (not pkcs7-data)\n");
+                       return -EKEYREJECTED;
+               }
+               if (!pkcs7->have_authattrs) {
+                       pr_warn("Invalid firmware sig (missing authattrs)\n");
+                       return -EKEYREJECTED;
+               }
+               break;
+       case VERIFYING_KEXEC_PE_SIGNATURE:
+               if (pkcs7->data_type != OID_msIndirectData) {
+                       pr_warn("Invalid kexec sig (not Authenticode)\n");
+                       return -EKEYREJECTED;
+               }
+               /* Authattr presence checked in parser */
+               break;
+       case VERIFYING_UNSPECIFIED_SIGNATURE:
+               if (pkcs7->data_type != OID_data) {
+                       pr_warn("Invalid unspecified sig (not pkcs7-data)\n");
+                       return -EKEYREJECTED;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
        for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
                ret = x509_get_sig_params(x509);
                if (ret < 0)
@@ -382,3 +443,28 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
        return enopkg;
 }
 EXPORT_SYMBOL_GPL(pkcs7_verify);
+
+/**
+ * pkcs7_supply_detached_data - Supply the data needed to verify a PKCS#7 message
+ * @pkcs7: The PKCS#7 message
+ * @data: The data to be verified
+ * @datalen: The amount of data
+ *
+ * Supply the detached data needed to verify a PKCS#7 message.  Note that no
+ * attempt to retain/pin the data is made.  That is left to the caller.  The
+ * data will not be modified by pkcs7_verify() and will not be freed when the
+ * PKCS#7 message is freed.
+ *
+ * Returns -EINVAL if data is already supplied in the message, 0 otherwise.
+ */
+int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7,
+                              const void *data, size_t datalen)
+{
+       if (pkcs7->data) {
+               pr_debug("Data already supplied\n");
+               return -EINVAL;
+       }
+       pkcs7->data = data;
+       pkcs7->data_len = datalen;
+       return 0;
+}