]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
efi_loader: image_loader: add digest-based verification for signed image
authorAKASHI Takahiro <takahiro.akashi@linaro.org>
Wed, 8 Jul 2020 05:01:57 +0000 (14:01 +0900)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Sat, 11 Jul 2020 21:14:15 +0000 (23:14 +0200)
In case that a type of certificate in "db" or "dbx" is
EFI_CERT_X509_SHA256_GUID, it is actually not a certificate which contains
a public key for RSA decryption, but a digest of image to be loaded.
If the value matches to a value calculated from a given binary image, it is
granted for loading.

With this patch, common digest check code, which used to be used for
unsigned image verification, will be extracted from
efi_signature_verify_with_sigdb() into efi_signature_lookup_digest(), and
extra step for digest check will be added to efi_image_authenticate().

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
include/efi_loader.h
lib/efi_loader/efi_image_loader.c
lib/efi_loader/efi_signature.c

index 2f9fb112b34ac67bd4a83406596aeffe3ecfc839..ceabbaadd0f26851968eb901e5c9aa6a7e23aff9 100644 (file)
@@ -765,6 +765,8 @@ struct efi_signature_store {
 struct x509_certificate;
 struct pkcs7_message;
 
+bool efi_signature_lookup_digest(struct efi_image_regions *regs,
+                                struct efi_signature_store *db);
 bool efi_signature_verify_one(struct efi_image_regions *regs,
                              struct pkcs7_message *msg,
                              struct efi_signature_store *db);
index 058359fc25857e31cc4e0d0f82e43396c147be98..b7cf26046e07be0f619d91f7b5271187f9ce9e49 100644 (file)
@@ -448,16 +448,16 @@ static bool efi_image_unsigned_authenticate(struct efi_image_regions *regs)
        }
 
        /* try black-list first */
-       if (efi_signature_verify_one(regs, NULL, dbx)) {
-               EFI_PRINT("Image is not signed and rejected by \"dbx\"\n");
+       if (efi_signature_lookup_digest(regs, dbx)) {
+               EFI_PRINT("Image is not signed and its digest found in \"dbx\"\n");
                goto out;
        }
 
        /* try white-list */
-       if (efi_signature_verify_one(regs, NULL, db))
+       if (efi_signature_lookup_digest(regs, db))
                ret = true;
        else
-               EFI_PRINT("Image is not signed and not found in \"db\" or \"dbx\"\n");
+               EFI_PRINT("Image is not signed and its digest not found in \"db\" or \"dbx\"\n");
 
 out:
        efi_sigstore_free(db);
@@ -605,6 +605,25 @@ static bool efi_image_authenticate(void *efi, size_t efi_size)
                        continue;
                }
 
+               /*
+                * NOTE:
+                * UEFI specification defines two signature types possible
+                * in signature database:
+                * a. x509 certificate, where a signature in image is
+                *    a message digest encrypted by RSA public key
+                *    (EFI_CERT_X509_GUID)
+                * b. bare hash value of message digest
+                *    (EFI_CERT_SHAxxx_GUID)
+                *
+                * efi_signature_verify() handles case (a), while
+                * efi_signature_lookup_digest() handles case (b).
+                *
+                * There is a third type:
+                * c. message digest of a certificate
+                *    (EFI_CERT_X509_SHAAxxx_GUID)
+                * This type of signature is used only in revocation list
+                * (dbx) and handled as part of efi_signatgure_verify().
+                */
                /* try black-list first */
                if (efi_signature_verify_one(regs, msg, dbx)) {
                        EFI_PRINT("Signature was rejected by \"dbx\"\n");
@@ -616,11 +635,22 @@ static bool efi_image_authenticate(void *efi, size_t efi_size)
                        goto err;
                }
 
-               /* try white-list */
-               if (!efi_signature_verify_with_sigdb(regs, msg, db, dbx)) {
-                       EFI_PRINT("Signature was not verified by \"db\"\n");
+               if (efi_signature_lookup_digest(regs, dbx)) {
+                       EFI_PRINT("Image's digest was found in \"dbx\"\n");
                        goto err;
                }
+
+               /* try white-list */
+               if (efi_signature_verify_with_sigdb(regs, msg, db, dbx))
+                       continue;
+
+               debug("Signature was not verified by \"db\"\n");
+
+               if (efi_signature_lookup_digest(regs, db))
+                       continue;
+
+               debug("Image's digest was not found in \"db\" or \"dbx\"\n");
+               goto err;
        }
        ret = true;
 
index 52392d139a0ce65e3f1b161d85a242cce707afe7..fc0314e6d48c03f7cd98c501c951caac78a6396a 100644 (file)
@@ -198,55 +198,43 @@ out:
 }
 
 /**
- * efi_signature_verify_with_list - verify a signature with signature list
- * @regs:              List of regions to be authenticated
- * @msg:               Signature
- * @signed_info:       Pointer to PKCS7's signed_info
- * @siglist:           Signature list for certificates
- * @valid_cert:                x509 certificate that verifies this signature
+ * efi_signature_lookup_digest - search for an image's digest in sigdb
+ * @regs:      List of regions to be authenticated
+ * @db:                Signature database for trusted certificates
  *
- * Signature pointed to by @signed_info against image pointed to by @regs
- * is verified by signature list pointed to by @siglist.
- * Signature database is a simple concatenation of one or more
- * signature list(s).
+ * A message digest of image pointed to by @regs is calculated and
+ * its hash value is compared to entries in signature database pointed
+ * to by @db.
  *
- * Return:     true if signature is verified, false if not
+ * Return:     true if found, false if not
  */
-static
-bool efi_signature_verify_with_list(struct efi_image_regions *regs,
-                                   struct pkcs7_message *msg,
-                                   struct pkcs7_signed_info *signed_info,
-                                   struct efi_signature_store *siglist,
-                                   struct x509_certificate **valid_cert)
+bool efi_signature_lookup_digest(struct efi_image_regions *regs,
+                                struct efi_signature_store *db)
 {
-       struct x509_certificate *cert;
+       struct efi_signature_store *siglist;
        struct efi_sig_data *sig_data;
-       bool verified = false;
+       void *hash = NULL;
+       size_t size = 0;
+       bool found = false;
 
-       EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__,
-                 regs, signed_info, siglist, valid_cert);
+       EFI_PRINT("%s: Enter, %p, %p\n", __func__, regs, db);
 
-       if (!signed_info) {
-               void *hash = NULL;
-               size_t size;
+       if (!regs || !db || !db->sig_data_list)
+               goto out;
 
-               EFI_PRINT("%s: unsigned image\n", __func__);
-               /*
-                * verify based on calculated hash value
-                * TODO: support other hash algorithms
-                */
+       for (siglist = db; siglist; siglist = siglist->next) {
+               /* TODO: support other hash algorithms */
                if (guidcmp(&siglist->sig_type, &efi_guid_sha256)) {
                        EFI_PRINT("Digest algorithm is not supported: %pUl\n",
                                  &siglist->sig_type);
-                       goto out;
+                       break;
                }
 
                if (!efi_hash_regions(regs->reg, regs->num, &hash, &size)) {
-                       EFI_PRINT("Digesting unsigned image failed\n");
-                       goto out;
+                       EFI_PRINT("Digesting an image failed\n");
+                       break;
                }
 
-               /* go through the list */
                for (sig_data = siglist->sig_data_list; sig_data;
                     sig_data = sig_data->next) {
 #ifdef DEBUG
@@ -254,18 +242,52 @@ bool efi_signature_verify_with_list(struct efi_image_regions *regs,
                        print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
                                       sig_data->data, sig_data->size, false);
 #endif
-                       if ((sig_data->size == size) &&
+                       if (sig_data->size == size &&
                            !memcmp(sig_data->data, hash, size)) {
-                               verified = true;
+                               found = true;
                                free(hash);
                                goto out;
                        }
                }
+
                free(hash);
-               goto out;
+               hash = NULL;
        }
 
-       EFI_PRINT("%s: signed image\n", __func__);
+out:
+       EFI_PRINT("%s: Exit, found: %d\n", __func__, found);
+       return found;
+}
+
+/**
+ * efi_signature_verify_with_list - verify a signature with signature list
+ * @regs:              List of regions to be authenticated
+ * @msg:               Signature
+ * @signed_info:       Pointer to PKCS7's signed_info
+ * @siglist:           Signature list for certificates
+ * @valid_cert:                x509 certificate that verifies this signature
+ *
+ * Signature pointed to by @signed_info against image pointed to by @regs
+ * is verified by signature list pointed to by @siglist.
+ * Signature database is a simple concatenation of one or more
+ * signature list(s).
+ *
+ * Return:     true if signature is verified, false if not
+ */
+static
+bool efi_signature_verify_with_list(struct efi_image_regions *regs,
+                                   struct pkcs7_message *msg,
+                                   struct pkcs7_signed_info *signed_info,
+                                   struct efi_signature_store *siglist,
+                                   struct x509_certificate **valid_cert)
+{
+       struct x509_certificate *cert;
+       struct efi_sig_data *sig_data;
+       bool verified = false;
+
+       EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__,
+                 regs, signed_info, siglist, valid_cert);
+
        if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509)) {
                EFI_PRINT("Signature type is not supported: %pUl\n",
                          &siglist->sig_type);
@@ -412,19 +434,6 @@ bool efi_signature_verify_one(struct efi_image_regions *regs,
        if (!db->sig_data_list)
                goto out;
 
-       /* for unsigned image */
-       if (!msg) {
-               EFI_PRINT("%s: Verify unsigned image with db\n", __func__);
-               for (siglist = db; siglist; siglist = siglist->next)
-                       if (efi_signature_verify_with_list(regs, NULL, NULL,
-                                                          siglist, &cert)) {
-                               verified = true;
-                               break;
-                       }
-               goto out;
-       }
-
-       /* for signed image or variable */
        EFI_PRINT("%s: Verify signed image with db\n", __func__);
        for (sinfo = msg->signed_infos; sinfo; sinfo = sinfo->next) {
                EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n",
@@ -468,26 +477,9 @@ bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs,
 
        EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__, regs, msg, db, dbx);
 
-       if (!db)
-               goto out;
-
-       if (!db->sig_data_list)
+       if (!regs || !msg || !db || !db->sig_data_list)
                goto out;
 
-       /* for unsigned image */
-       if (!msg) {
-               EFI_PRINT("%s: Verify unsigned image with db\n", __func__);
-               for (siglist = db; siglist; siglist = siglist->next)
-                       if (efi_signature_verify_with_list(regs, NULL, NULL,
-                                                          siglist, &cert)) {
-                               verified = true;
-                               break;
-                       }
-               goto out;
-       }
-
-       /* for signed image or variable */
-       EFI_PRINT("%s: Verify signed image with db\n", __func__);
        for (info = msg->signed_infos; info; info = info->next) {
                EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n",
                          info->sig->hash_algo, info->sig->pkey_algo);