On Thu, Feb 10, 2022 at 09:13:34AM +0200, Ilias Apalodimas wrote:
> On Thu, Feb 10, 2022 at 02:13:48PM +0900, AKASHI Takahiro wrote:
> > Hi Ilias,
> > 
> > Thank you for reviewing the logic.
> > 
> > On Fri, Feb 04, 2022 at 09:32:01AM +0200, Ilias Apalodimas wrote:
> > > The EFI spec allows for images to carry multiple signatures. Currently
> > > we don't adhere to the verification process for such images.
> > 
> > In this patch, you're trying to do three things:
> > * remove efi_image_unsigned_authenticate()
> > * pull efi_signature_lookup_digest() out of a while loop
> > * change the logic of authentication
> > 
> > I'd prefer to see those changes in separate patches for better reviewing.
> 
> I tried both and the current one seemed easier to review.  Heinrich any
> preference?

Those three changes are basically independent from each other.
Such changes should be in speparate patchs.
I believe it is what Heinrich always requires me to do.

> > 
> > > The spec says:
> > > "Multiple signatures are allowed to exist in the binary's certificate
> > > table (as per PE/COFF Section "Attribute Certificate Table"). Only one
> > > hash or signature is required to be present in db in order to pass
> > > validation, so long as neither the SHA-256 hash of the binary nor any
> > > present signature is reflected in dbx."
> > 
> > I have some concern about what the last phrase, "neither the SHA-256 hash
> > of the binary nor any present signature is reflected in dbx" means.
> > See the comment below.
> > 
> > > With our current implementation signing the image with two certificates
> > > and inserting both of them in db and one of them dbx doesn't always reject
> > > the image.  The rejection depends on the order that the image was signed
> > > and the order the certificates are read (and checked) in db.
> > > 
> > > While at it move the sha256 hash verification outside the signature
> > > checking loop, since it only needs to run once per image and get simplify
> > > the logic for authenticating an unsigned imahe using sha256 hashes.
> > > 
> > > Signed-off-by: Ilias Apalodimas <ilias.apalodi...@linaro.org>
> > > ---
> > >  lib/efi_loader/efi_image_loader.c | 88 +++++++------------------------
> > >  1 file changed, 18 insertions(+), 70 deletions(-)
> > > 
> > > diff --git a/lib/efi_loader/efi_image_loader.c 
> > > b/lib/efi_loader/efi_image_loader.c
> > > index f41cfa4fccd5..5df35939f702 100644
> > > --- a/lib/efi_loader/efi_image_loader.c
> > > +++ b/lib/efi_loader/efi_image_loader.c
> > > @@ -516,53 +516,6 @@ err:
> > >  }
> > >  
> > >  #ifdef CONFIG_EFI_SECURE_BOOT
> > > -/**
> > > - * efi_image_unsigned_authenticate() - authenticate unsigned image with
> > > - * SHA256 hash
> > > - * @regs:        List of regions to be verified
> > > - *
> > > - * If an image is not signed, it doesn't have a signature. In this case,
> > > - * its message digest is calculated and it will be compared with one of
> > > - * hash values stored in signature databases.
> > > - *
> > > - * Return:       true if authenticated, false if not
> > > - */
> > > -static bool efi_image_unsigned_authenticate(struct efi_image_regions 
> > > *regs)
> > > -{
> > > - struct efi_signature_store *db = NULL, *dbx = NULL;
> > > - bool ret = false;
> > > -
> > > - dbx = efi_sigstore_parse_sigdb(u"dbx");
> > > - if (!dbx) {
> > > -         EFI_PRINT("Getting signature database(dbx) failed\n");
> > > -         goto out;
> > > - }
> > > -
> > > - db = efi_sigstore_parse_sigdb(u"db");
> > > - if (!db) {
> > > -         EFI_PRINT("Getting signature database(db) failed\n");
> > > -         goto out;
> > > - }
> > > -
> > > - /* try black-list first */
> > > - if (efi_signature_lookup_digest(regs, dbx, true)) {
> > > -         EFI_PRINT("Image is not signed and its digest found in 
> > > \"dbx\"\n");
> > > -         goto out;
> > > - }
> > > -
> > > - /* try white-list */
> > > - if (efi_signature_lookup_digest(regs, db, false))
> > > -         ret = true;
> > > - else
> > > -         EFI_PRINT("Image is not signed and its digest not found in 
> > > \"db\" or \"dbx\"\n");
> > > -
> > > -out:
> > > - efi_sigstore_free(db);
> > > - efi_sigstore_free(dbx);
> > > -
> > > - return ret;
> > > -}
> > > -
> > >  /**
> > >   * efi_image_authenticate() - verify a signature of signed image
> > >   * @efi: Pointer to image
> > > @@ -608,14 +561,7 @@ static bool efi_image_authenticate(void *efi, size_t 
> > > efi_size)
> > >   if (!efi_image_parse(new_efi, efi_size, &regs, &wincerts,
> > >                        &wincerts_len)) {
> > >           EFI_PRINT("Parsing PE executable image failed\n");
> > > -         goto err;
> > > - }
> > > -
> > > - if (!wincerts) {
> > > -         /* The image is not signed */
> > > -         ret = efi_image_unsigned_authenticate(regs);
> > > -
> > > -         goto err;
> > > +         goto out;
> > >   }
> > >  
> > >   /*
> > > @@ -624,18 +570,18 @@ static bool efi_image_authenticate(void *efi, 
> > > size_t efi_size)
> > >   db = efi_sigstore_parse_sigdb(u"db");
> > >   if (!db) {
> > >           EFI_PRINT("Getting signature database(db) failed\n");
> > > -         goto err;
> > > +         goto out;
> > >   }
> > >  
> > >   dbx = efi_sigstore_parse_sigdb(u"dbx");
> > >   if (!dbx) {
> > >           EFI_PRINT("Getting signature database(dbx) failed\n");
> > > -         goto err;
> > > +         goto out;
> > >   }
> > >  
> > >   if (efi_signature_lookup_digest(regs, dbx, true)) {
> > >           EFI_PRINT("Image's digest was found in \"dbx\"\n");
> > > -         goto err;
> > > +         goto out;
> > >   }
> > >  
> > >   /*
> > > @@ -678,7 +624,8 @@ static bool efi_image_authenticate(void *efi, size_t 
> > > efi_size)
> > >                   if (guidcmp(auth, &efi_guid_cert_type_pkcs7)) {
> > >                           EFI_PRINT("Certificate type not supported: 
> > > %pUs\n",
> > >                                     auth);
> > > -                         continue;
> > > +                         ret = false;
> > > +                         goto out;
> > 
> > Why should we break the loop here?
> 
> We were trying to reject signature verification that we don't support,
> since the equivalent cert might be in dbx.  But I am not 100% sure taht's
> what we want here.
> 
> > 
> > >                   }
> > >  
> > >                   auth += sizeof(efi_guid_t);
> > > @@ -686,7 +633,8 @@ static bool efi_image_authenticate(void *efi, size_t 
> > > efi_size)
> > >           } else if (wincert->wCertificateType
> > >                           != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
> > >                   EFI_PRINT("Certificate type not supported\n");
> > > -                 continue;
> > > +                 ret = false;
> > > +                 goto out;
> > >           }
> > >  
> > >           msg = pkcs7_parse_message(auth, auth_size);
> > > @@ -717,32 +665,32 @@ static bool efi_image_authenticate(void *efi, 
> > > size_t efi_size)
> > >            */
> > >           /* try black-list first */
> > >           if (efi_signature_verify_one(regs, msg, dbx)) {
> > > +                 ret = false;
> > >                   EFI_PRINT("Signature was rejected by \"dbx\"\n");
> > > -                 continue;
> > > +                 goto out;
> > 
> > If we go to "out" here, we have no chance to verify some cases:
> > 1) An image has two signatures, for instance, one signed by SHA1 cert
> >    and the other signed by SHA256 cert. A user wants to reject SHA1 cert
> >    and put the cert in dbx.
> 
> I am not sure I am following,  what does he gain be rejecting the SHA1
> portion only?  Avoid potential collisions?

I will reply to Heinrich's comment later.

-Takahiro Akashi

> >    But this image can and should yet be verified by SHA256 cert.
> 
> Why should it be verified?  My understanding of the EFI spec is that any match
> in dbx of any certificate in the signing chain of the signature being 
> verified means 
> reject the image. 
> 
> > 2) A user knows that a given image is safe for some reason even though
> >    he or she doesn't trust the certficate which is used for signing
> >    the image.
> > 
> > -Takahiro Akashi
> > 
> > >           }
> > >  
> > >           if (!efi_signature_check_signers(msg, dbx)) {
> > > +                 ret = false;
> > >                   EFI_PRINT("Signer(s) in \"dbx\"\n");
> > > -                 continue;
> > > +                 goto out;
> > >           }
> > >  
> > >           /* try white-list */
> > >           if (efi_signature_verify(regs, msg, db, dbx)) {
> > >                   ret = true;
> > > -                 break;
> > > +                 continue;
> > >           }
> > >  
> > >           EFI_PRINT("Signature was not verified by \"db\"\n");
> > > + }
> > >  
> > > -         if (efi_signature_lookup_digest(regs, db, false)) {
> > > -                 ret = true;
> > > -                 break;
> > > -         }
> > >  
> > > -         EFI_PRINT("Image's digest was not found in \"db\" or 
> > > \"dbx\"\n");
> > > - }
> > > + /* last resort try the image sha256 hash in db */
> > > + if (!ret && efi_signature_lookup_digest(regs, db, false))
> > > +         ret = true;
> > >  
> > > -err:
> > > +out:
> > >   efi_sigstore_free(db);
> > >   efi_sigstore_free(dbx);
> > >   pkcs7_free_message(msg);
> > > -- 
> > > 2.32.0
> > > 
> 
> Thanks
> /Ilias

Reply via email to