Re: [PATCH v4 08/16] efi_loader: image_loader: support image authentication

2020-01-26 Thread AKASHI Takahiro
On Thu, Jan 23, 2020 at 06:41:53PM +0100, Heinrich Schuchardt wrote:
> On 1/22/20 8:42 AM, AKASHI Takahiro wrote:
> >Heinrich,
> >
> >On Wed, Jan 22, 2020 at 10:13:48AM +0900, AKASHI Takahiro wrote:
> >>On Tue, Jan 21, 2020 at 08:15:06AM +0100, Heinrich Schuchardt wrote:
> >>>On 1/21/20 7:12 AM, AKASHI Takahiro wrote:
> On Fri, Jan 17, 2020 at 06:51:50AM +0100, Heinrich Schuchardt wrote:
> >On 1/17/20 6:11 AM, AKASHI Takahiro wrote:
> >>On Thu, Jan 09, 2020 at 12:55:17AM +0100, Heinrich Schuchardt wrote:
> >>>On 12/18/19 1:45 AM, AKASHI Takahiro wrote:
> With this commit, image validation can be enforced, as UEFI 
> specification
> section 32.5 describes, if CONFIG_EFI_SECURE_BOOT is enabled.
> 
> Currently we support
> * authentication based on db and dbx,
>    so dbx-validated image will always be rejected.
> * following signature types:
>  EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images)
>  EFI_CERT_X509_GUID (x509 certificate for signed images)
> Timestamp-based certificate revocation is not supported here.
> 
> Internally, authentication data is stored in one of certificates 
> tables
> of PE image (See efi_image_parse()) and will be verified by
> efi_image_authenticate() before loading a given image.
> 
> It seems that UEFI specification defines the verification process
> in a bit ambiguous way. I tried to implement it as closely to as
> EDK2 does.
> 
> Signed-off-by: AKASHI Takahiro 
> ---
>   include/efi_loader.h  |   7 +-
>   lib/efi_loader/efi_boottime.c |   2 +-
>   lib/efi_loader/efi_image_loader.c | 454 
>  +-
>   3 files changed, 449 insertions(+), 14 deletions(-)
> 
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 1f88caf86709..e12b49098fb0 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -11,6 +11,7 @@
>   #include 
>   #include 
>   #include 
> +#include 
> 
>   static inline int guidcmp(const void *g1, const void *g2)
>   {
> @@ -398,7 +399,8 @@ efi_status_t efi_set_watchdog(unsigned long 
> timeout);
>   /* Called from places to check whether a timer expired */
>   void efi_timer_check(void);
>   /* PE loader implementation */
> -efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void 
> *efi,
> +efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
> +  void *efi, size_t efi_size,
>    struct efi_loaded_image *loaded_image_info);
>   /* Called once to store the pristine gd pointer */
>   void efi_save_gd(void);
> @@ -726,6 +728,9 @@ void efi_sigstore_free(struct efi_signature_store 
> *sigstore);
>   struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);
> 
>   bool efi_secure_boot_enabled(void);
> +
> +bool efi_image_parse(void *efi, size_t len, struct efi_image_regions 
> **regp,
> +  WIN_CERTIFICATE **auth, size_t *auth_len);
>   #endif /* CONFIG_EFI_SECURE_BOOT */
> 
>   #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
> diff --git a/lib/efi_loader/efi_boottime.c 
> b/lib/efi_loader/efi_boottime.c
> index 493d906c641d..311681764034 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -1879,7 +1879,7 @@ efi_status_t EFIAPI efi_load_image(bool 
> boot_policy,
>   efi_dp_split_file_path(file_path, , );
>   ret = efi_setup_loaded_image(dp, fp, image_obj, );
>   if (ret == EFI_SUCCESS)
> - ret = efi_load_pe(*image_obj, dest_buffer, info);
> + ret = efi_load_pe(*image_obj, dest_buffer, source_size, 
> info);
>   if (!source_buffer)
>   /* Release buffer to which file was loaded */
>   efi_free_pages((uintptr_t)dest_buffer,
> diff --git a/lib/efi_loader/efi_image_loader.c 
> b/lib/efi_loader/efi_image_loader.c
> index 13541cfa7a28..939758e61e3c 100644
> --- a/lib/efi_loader/efi_image_loader.c
> +++ b/lib/efi_loader/efi_image_loader.c
> @@ -9,7 +9,9 @@
> 
>   #include 
>   #include 
> +#include 
>   #include 
> +#include "../lib/crypto/pkcs7_parser.h"
> 
>   const efi_guid_t efi_global_variable_guid = 
>  EFI_GLOBAL_VARIABLE_GUID;
>   const efi_guid_t efi_guid_device_path = 
>  EFI_DEVICE_PATH_PROTOCOL_GUID;
> @@ -205,6 

Re: [PATCH v4 08/16] efi_loader: image_loader: support image authentication

2020-01-23 Thread Heinrich Schuchardt

On 1/22/20 8:42 AM, AKASHI Takahiro wrote:

Heinrich,

On Wed, Jan 22, 2020 at 10:13:48AM +0900, AKASHI Takahiro wrote:

On Tue, Jan 21, 2020 at 08:15:06AM +0100, Heinrich Schuchardt wrote:

On 1/21/20 7:12 AM, AKASHI Takahiro wrote:

On Fri, Jan 17, 2020 at 06:51:50AM +0100, Heinrich Schuchardt wrote:

On 1/17/20 6:11 AM, AKASHI Takahiro wrote:

On Thu, Jan 09, 2020 at 12:55:17AM +0100, Heinrich Schuchardt wrote:

On 12/18/19 1:45 AM, AKASHI Takahiro wrote:

With this commit, image validation can be enforced, as UEFI specification
section 32.5 describes, if CONFIG_EFI_SECURE_BOOT is enabled.

Currently we support
* authentication based on db and dbx,
   so dbx-validated image will always be rejected.
* following signature types:
 EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images)
 EFI_CERT_X509_GUID (x509 certificate for signed images)
Timestamp-based certificate revocation is not supported here.

Internally, authentication data is stored in one of certificates tables
of PE image (See efi_image_parse()) and will be verified by
efi_image_authenticate() before loading a given image.

It seems that UEFI specification defines the verification process
in a bit ambiguous way. I tried to implement it as closely to as
EDK2 does.

Signed-off-by: AKASHI Takahiro 
---
  include/efi_loader.h  |   7 +-
  lib/efi_loader/efi_boottime.c |   2 +-
  lib/efi_loader/efi_image_loader.c | 454 +-
  3 files changed, 449 insertions(+), 14 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 1f88caf86709..e12b49098fb0 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -11,6 +11,7 @@
  #include 
  #include 
  #include 
+#include 

  static inline int guidcmp(const void *g1, const void *g2)
  {
@@ -398,7 +399,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout);
  /* Called from places to check whether a timer expired */
  void efi_timer_check(void);
  /* PE loader implementation */
-efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
+efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
+void *efi, size_t efi_size,
 struct efi_loaded_image *loaded_image_info);
  /* Called once to store the pristine gd pointer */
  void efi_save_gd(void);
@@ -726,6 +728,9 @@ void efi_sigstore_free(struct efi_signature_store 
*sigstore);
  struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);

  bool efi_secure_boot_enabled(void);
+
+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
+WIN_CERTIFICATE **auth, size_t *auth_len);
  #endif /* CONFIG_EFI_SECURE_BOOT */

  #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 493d906c641d..311681764034 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1879,7 +1879,7 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy,
efi_dp_split_file_path(file_path, , );
ret = efi_setup_loaded_image(dp, fp, image_obj, );
if (ret == EFI_SUCCESS)
-   ret = efi_load_pe(*image_obj, dest_buffer, info);
+   ret = efi_load_pe(*image_obj, dest_buffer, source_size, info);
if (!source_buffer)
/* Release buffer to which file was loaded */
efi_free_pages((uintptr_t)dest_buffer,
diff --git a/lib/efi_loader/efi_image_loader.c 
b/lib/efi_loader/efi_image_loader.c
index 13541cfa7a28..939758e61e3c 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -9,7 +9,9 @@

  #include 
  #include 
+#include 
  #include 
+#include "../lib/crypto/pkcs7_parser.h"

  const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
  const efi_guid_t efi_guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
@@ -205,6 +207,367 @@ static void efi_set_code_and_data_type(
}
  }

+#ifdef CONFIG_EFI_SECURE_BOOT
+/**
+ * efi_image_parse - parse a PE image
+ * @efi:   Pointer to image
+ * @len:   Size of @efi
+ * @regs:  Pointer to a list of regions
+ * @auth:  Pointer to a pointer to authentication data in PE
+ * @auth_len:  Size of @auth
+ *
+ * Parse image binary in PE32(+) format, assuming that sanity of PE image
+ * has been checked by a caller.
+ * On success, an address of authentication data in @efi and its size will
+ * be returned in @auth and @auth_len, respectively.
+ *
+ * Return: true on success, false on error
+ */
+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
+WIN_CERTIFICATE **auth, size_t *auth_len)



This function is way too long (> 100 lines). Please, cut it into logical
units.




+{
+   struct efi_image_regions *regs;
+   IMAGE_DOS_HEADER *dos;
+   IMAGE_NT_HEADERS32 *nt;
+   IMAGE_SECTION_HEADER *sections, **sorted;
+   int num_regions, num_sections, i, j;
+   int ctidx = 

Re: [PATCH v4 08/16] efi_loader: image_loader: support image authentication

2020-01-21 Thread AKASHI Takahiro
Heinrich,

On Wed, Jan 22, 2020 at 10:13:48AM +0900, AKASHI Takahiro wrote:
> On Tue, Jan 21, 2020 at 08:15:06AM +0100, Heinrich Schuchardt wrote:
> > On 1/21/20 7:12 AM, AKASHI Takahiro wrote:
> > >On Fri, Jan 17, 2020 at 06:51:50AM +0100, Heinrich Schuchardt wrote:
> > >>On 1/17/20 6:11 AM, AKASHI Takahiro wrote:
> > >>>On Thu, Jan 09, 2020 at 12:55:17AM +0100, Heinrich Schuchardt wrote:
> > On 12/18/19 1:45 AM, AKASHI Takahiro wrote:
> > >With this commit, image validation can be enforced, as UEFI 
> > >specification
> > >section 32.5 describes, if CONFIG_EFI_SECURE_BOOT is enabled.
> > >
> > >Currently we support
> > >* authentication based on db and dbx,
> > >   so dbx-validated image will always be rejected.
> > >* following signature types:
> > > EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images)
> > > EFI_CERT_X509_GUID (x509 certificate for signed images)
> > >Timestamp-based certificate revocation is not supported here.
> > >
> > >Internally, authentication data is stored in one of certificates tables
> > >of PE image (See efi_image_parse()) and will be verified by
> > >efi_image_authenticate() before loading a given image.
> > >
> > >It seems that UEFI specification defines the verification process
> > >in a bit ambiguous way. I tried to implement it as closely to as
> > >EDK2 does.
> > >
> > >Signed-off-by: AKASHI Takahiro 
> > >---
> > >  include/efi_loader.h  |   7 +-
> > >  lib/efi_loader/efi_boottime.c |   2 +-
> > >  lib/efi_loader/efi_image_loader.c | 454 
> > > +-
> > >  3 files changed, 449 insertions(+), 14 deletions(-)
> > >
> > >diff --git a/include/efi_loader.h b/include/efi_loader.h
> > >index 1f88caf86709..e12b49098fb0 100644
> > >--- a/include/efi_loader.h
> > >+++ b/include/efi_loader.h
> > >@@ -11,6 +11,7 @@
> > >  #include 
> > >  #include 
> > >  #include 
> > >+#include 
> > >
> > >  static inline int guidcmp(const void *g1, const void *g2)
> > >  {
> > >@@ -398,7 +399,8 @@ efi_status_t efi_set_watchdog(unsigned long 
> > >timeout);
> > >  /* Called from places to check whether a timer expired */
> > >  void efi_timer_check(void);
> > >  /* PE loader implementation */
> > >-efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void 
> > >*efi,
> > >+efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
> > >+   void *efi, size_t efi_size,
> > >struct efi_loaded_image *loaded_image_info);
> > >  /* Called once to store the pristine gd pointer */
> > >  void efi_save_gd(void);
> > >@@ -726,6 +728,9 @@ void efi_sigstore_free(struct efi_signature_store 
> > >*sigstore);
> > >  struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);
> > >
> > >  bool efi_secure_boot_enabled(void);
> > >+
> > >+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions 
> > >**regp,
> > >+   WIN_CERTIFICATE **auth, size_t *auth_len);
> > >  #endif /* CONFIG_EFI_SECURE_BOOT */
> > >
> > >  #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
> > >diff --git a/lib/efi_loader/efi_boottime.c 
> > >b/lib/efi_loader/efi_boottime.c
> > >index 493d906c641d..311681764034 100644
> > >--- a/lib/efi_loader/efi_boottime.c
> > >+++ b/lib/efi_loader/efi_boottime.c
> > >@@ -1879,7 +1879,7 @@ efi_status_t EFIAPI efi_load_image(bool 
> > >boot_policy,
> > >   efi_dp_split_file_path(file_path, , );
> > >   ret = efi_setup_loaded_image(dp, fp, image_obj, );
> > >   if (ret == EFI_SUCCESS)
> > >-  ret = efi_load_pe(*image_obj, dest_buffer, info);
> > >+  ret = efi_load_pe(*image_obj, dest_buffer, source_size, 
> > >info);
> > >   if (!source_buffer)
> > >   /* Release buffer to which file was loaded */
> > >   efi_free_pages((uintptr_t)dest_buffer,
> > >diff --git a/lib/efi_loader/efi_image_loader.c 
> > >b/lib/efi_loader/efi_image_loader.c
> > >index 13541cfa7a28..939758e61e3c 100644
> > >--- a/lib/efi_loader/efi_image_loader.c
> > >+++ b/lib/efi_loader/efi_image_loader.c
> > >@@ -9,7 +9,9 @@
> > >
> > >  #include 
> > >  #include 
> > >+#include 
> > >  #include 
> > >+#include "../lib/crypto/pkcs7_parser.h"
> > >
> > >  const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
> > >  const efi_guid_t efi_guid_device_path = 
> > > EFI_DEVICE_PATH_PROTOCOL_GUID;
> > >@@ -205,6 +207,367 @@ static void efi_set_code_and_data_type(
> > >   }
> > >  }
> > >
> > >+#ifdef CONFIG_EFI_SECURE_BOOT
> > >+/**
> > >+ * efi_image_parse - parse a PE image
> > >+ * @efi:  Pointer to image
> > 

Re: [PATCH v4 08/16] efi_loader: image_loader: support image authentication

2020-01-21 Thread AKASHI Takahiro
On Tue, Jan 21, 2020 at 08:15:06AM +0100, Heinrich Schuchardt wrote:
> On 1/21/20 7:12 AM, AKASHI Takahiro wrote:
> >On Fri, Jan 17, 2020 at 06:51:50AM +0100, Heinrich Schuchardt wrote:
> >>On 1/17/20 6:11 AM, AKASHI Takahiro wrote:
> >>>On Thu, Jan 09, 2020 at 12:55:17AM +0100, Heinrich Schuchardt wrote:
> On 12/18/19 1:45 AM, AKASHI Takahiro wrote:
> >With this commit, image validation can be enforced, as UEFI specification
> >section 32.5 describes, if CONFIG_EFI_SECURE_BOOT is enabled.
> >
> >Currently we support
> >* authentication based on db and dbx,
> >   so dbx-validated image will always be rejected.
> >* following signature types:
> > EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images)
> > EFI_CERT_X509_GUID (x509 certificate for signed images)
> >Timestamp-based certificate revocation is not supported here.
> >
> >Internally, authentication data is stored in one of certificates tables
> >of PE image (See efi_image_parse()) and will be verified by
> >efi_image_authenticate() before loading a given image.
> >
> >It seems that UEFI specification defines the verification process
> >in a bit ambiguous way. I tried to implement it as closely to as
> >EDK2 does.
> >
> >Signed-off-by: AKASHI Takahiro 
> >---
> >  include/efi_loader.h  |   7 +-
> >  lib/efi_loader/efi_boottime.c |   2 +-
> >  lib/efi_loader/efi_image_loader.c | 454 +-
> >  3 files changed, 449 insertions(+), 14 deletions(-)
> >
> >diff --git a/include/efi_loader.h b/include/efi_loader.h
> >index 1f88caf86709..e12b49098fb0 100644
> >--- a/include/efi_loader.h
> >+++ b/include/efi_loader.h
> >@@ -11,6 +11,7 @@
> >  #include 
> >  #include 
> >  #include 
> >+#include 
> >
> >  static inline int guidcmp(const void *g1, const void *g2)
> >  {
> >@@ -398,7 +399,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout);
> >  /* Called from places to check whether a timer expired */
> >  void efi_timer_check(void);
> >  /* PE loader implementation */
> >-efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
> >+efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
> >+ void *efi, size_t efi_size,
> >  struct efi_loaded_image *loaded_image_info);
> >  /* Called once to store the pristine gd pointer */
> >  void efi_save_gd(void);
> >@@ -726,6 +728,9 @@ void efi_sigstore_free(struct efi_signature_store 
> >*sigstore);
> >  struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);
> >
> >  bool efi_secure_boot_enabled(void);
> >+
> >+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions 
> >**regp,
> >+ WIN_CERTIFICATE **auth, size_t *auth_len);
> >  #endif /* CONFIG_EFI_SECURE_BOOT */
> >
> >  #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
> >diff --git a/lib/efi_loader/efi_boottime.c 
> >b/lib/efi_loader/efi_boottime.c
> >index 493d906c641d..311681764034 100644
> >--- a/lib/efi_loader/efi_boottime.c
> >+++ b/lib/efi_loader/efi_boottime.c
> >@@ -1879,7 +1879,7 @@ efi_status_t EFIAPI efi_load_image(bool 
> >boot_policy,
> > efi_dp_split_file_path(file_path, , );
> > ret = efi_setup_loaded_image(dp, fp, image_obj, );
> > if (ret == EFI_SUCCESS)
> >-ret = efi_load_pe(*image_obj, dest_buffer, info);
> >+ret = efi_load_pe(*image_obj, dest_buffer, source_size, 
> >info);
> > if (!source_buffer)
> > /* Release buffer to which file was loaded */
> > efi_free_pages((uintptr_t)dest_buffer,
> >diff --git a/lib/efi_loader/efi_image_loader.c 
> >b/lib/efi_loader/efi_image_loader.c
> >index 13541cfa7a28..939758e61e3c 100644
> >--- a/lib/efi_loader/efi_image_loader.c
> >+++ b/lib/efi_loader/efi_image_loader.c
> >@@ -9,7 +9,9 @@
> >
> >  #include 
> >  #include 
> >+#include 
> >  #include 
> >+#include "../lib/crypto/pkcs7_parser.h"
> >
> >  const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
> >  const efi_guid_t efi_guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
> >@@ -205,6 +207,367 @@ static void efi_set_code_and_data_type(
> > }
> >  }
> >
> >+#ifdef CONFIG_EFI_SECURE_BOOT
> >+/**
> >+ * efi_image_parse - parse a PE image
> >+ * @efi:Pointer to image
> >+ * @len:Size of @efi
> >+ * @regs:   Pointer to a list of regions
> >+ * @auth:   Pointer to a pointer to authentication data in PE
> >+ * @auth_len:   Size of @auth
> >+ *
> >+ * Parse image binary in PE32(+) format, assuming that sanity of PE 
> >image
> >+ * has 

Re: [PATCH v4 08/16] efi_loader: image_loader: support image authentication

2020-01-20 Thread Heinrich Schuchardt

On 1/21/20 7:12 AM, AKASHI Takahiro wrote:

On Fri, Jan 17, 2020 at 06:51:50AM +0100, Heinrich Schuchardt wrote:

On 1/17/20 6:11 AM, AKASHI Takahiro wrote:

On Thu, Jan 09, 2020 at 12:55:17AM +0100, Heinrich Schuchardt wrote:

On 12/18/19 1:45 AM, AKASHI Takahiro wrote:

With this commit, image validation can be enforced, as UEFI specification
section 32.5 describes, if CONFIG_EFI_SECURE_BOOT is enabled.

Currently we support
* authentication based on db and dbx,
   so dbx-validated image will always be rejected.
* following signature types:
 EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images)
 EFI_CERT_X509_GUID (x509 certificate for signed images)
Timestamp-based certificate revocation is not supported here.

Internally, authentication data is stored in one of certificates tables
of PE image (See efi_image_parse()) and will be verified by
efi_image_authenticate() before loading a given image.

It seems that UEFI specification defines the verification process
in a bit ambiguous way. I tried to implement it as closely to as
EDK2 does.

Signed-off-by: AKASHI Takahiro 
---
  include/efi_loader.h  |   7 +-
  lib/efi_loader/efi_boottime.c |   2 +-
  lib/efi_loader/efi_image_loader.c | 454 +-
  3 files changed, 449 insertions(+), 14 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 1f88caf86709..e12b49098fb0 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -11,6 +11,7 @@
  #include 
  #include 
  #include 
+#include 

  static inline int guidcmp(const void *g1, const void *g2)
  {
@@ -398,7 +399,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout);
  /* Called from places to check whether a timer expired */
  void efi_timer_check(void);
  /* PE loader implementation */
-efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
+efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
+void *efi, size_t efi_size,
 struct efi_loaded_image *loaded_image_info);
  /* Called once to store the pristine gd pointer */
  void efi_save_gd(void);
@@ -726,6 +728,9 @@ void efi_sigstore_free(struct efi_signature_store 
*sigstore);
  struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);

  bool efi_secure_boot_enabled(void);
+
+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
+WIN_CERTIFICATE **auth, size_t *auth_len);
  #endif /* CONFIG_EFI_SECURE_BOOT */

  #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 493d906c641d..311681764034 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1879,7 +1879,7 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy,
efi_dp_split_file_path(file_path, , );
ret = efi_setup_loaded_image(dp, fp, image_obj, );
if (ret == EFI_SUCCESS)
-   ret = efi_load_pe(*image_obj, dest_buffer, info);
+   ret = efi_load_pe(*image_obj, dest_buffer, source_size, info);
if (!source_buffer)
/* Release buffer to which file was loaded */
efi_free_pages((uintptr_t)dest_buffer,
diff --git a/lib/efi_loader/efi_image_loader.c 
b/lib/efi_loader/efi_image_loader.c
index 13541cfa7a28..939758e61e3c 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -9,7 +9,9 @@

  #include 
  #include 
+#include 
  #include 
+#include "../lib/crypto/pkcs7_parser.h"

  const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
  const efi_guid_t efi_guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
@@ -205,6 +207,367 @@ static void efi_set_code_and_data_type(
}
  }

+#ifdef CONFIG_EFI_SECURE_BOOT
+/**
+ * efi_image_parse - parse a PE image
+ * @efi:   Pointer to image
+ * @len:   Size of @efi
+ * @regs:  Pointer to a list of regions
+ * @auth:  Pointer to a pointer to authentication data in PE
+ * @auth_len:  Size of @auth
+ *
+ * Parse image binary in PE32(+) format, assuming that sanity of PE image
+ * has been checked by a caller.
+ * On success, an address of authentication data in @efi and its size will
+ * be returned in @auth and @auth_len, respectively.
+ *
+ * Return: true on success, false on error
+ */
+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
+WIN_CERTIFICATE **auth, size_t *auth_len)



This function is way too long (> 100 lines). Please, cut it into logical
units.




+{
+   struct efi_image_regions *regs;
+   IMAGE_DOS_HEADER *dos;
+   IMAGE_NT_HEADERS32 *nt;
+   IMAGE_SECTION_HEADER *sections, **sorted;
+   int num_regions, num_sections, i, j;
+   int ctidx = IMAGE_DIRECTORY_ENTRY_SECURITY;
+   u32 align, size, authsz, authoff;
+   size_t bytes_hashed;
+
+   dos = (void *)efi;
+   nt = (void *)(efi + dos->e_lfanew);
+
+   /*
+  

Re: [PATCH v4 08/16] efi_loader: image_loader: support image authentication

2020-01-20 Thread AKASHI Takahiro
On Fri, Jan 17, 2020 at 06:51:50AM +0100, Heinrich Schuchardt wrote:
> On 1/17/20 6:11 AM, AKASHI Takahiro wrote:
> >On Thu, Jan 09, 2020 at 12:55:17AM +0100, Heinrich Schuchardt wrote:
> >>On 12/18/19 1:45 AM, AKASHI Takahiro wrote:
> >>>With this commit, image validation can be enforced, as UEFI specification
> >>>section 32.5 describes, if CONFIG_EFI_SECURE_BOOT is enabled.
> >>>
> >>>Currently we support
> >>>* authentication based on db and dbx,
> >>>   so dbx-validated image will always be rejected.
> >>>* following signature types:
> >>> EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images)
> >>> EFI_CERT_X509_GUID (x509 certificate for signed images)
> >>>Timestamp-based certificate revocation is not supported here.
> >>>
> >>>Internally, authentication data is stored in one of certificates tables
> >>>of PE image (See efi_image_parse()) and will be verified by
> >>>efi_image_authenticate() before loading a given image.
> >>>
> >>>It seems that UEFI specification defines the verification process
> >>>in a bit ambiguous way. I tried to implement it as closely to as
> >>>EDK2 does.
> >>>
> >>>Signed-off-by: AKASHI Takahiro 
> >>>---
> >>>  include/efi_loader.h  |   7 +-
> >>>  lib/efi_loader/efi_boottime.c |   2 +-
> >>>  lib/efi_loader/efi_image_loader.c | 454 +-
> >>>  3 files changed, 449 insertions(+), 14 deletions(-)
> >>>
> >>>diff --git a/include/efi_loader.h b/include/efi_loader.h
> >>>index 1f88caf86709..e12b49098fb0 100644
> >>>--- a/include/efi_loader.h
> >>>+++ b/include/efi_loader.h
> >>>@@ -11,6 +11,7 @@
> >>>  #include 
> >>>  #include 
> >>>  #include 
> >>>+#include 
> >>>
> >>>  static inline int guidcmp(const void *g1, const void *g2)
> >>>  {
> >>>@@ -398,7 +399,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout);
> >>>  /* Called from places to check whether a timer expired */
> >>>  void efi_timer_check(void);
> >>>  /* PE loader implementation */
> >>>-efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
> >>>+efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
> >>>+   void *efi, size_t efi_size,
> >>>struct efi_loaded_image *loaded_image_info);
> >>>  /* Called once to store the pristine gd pointer */
> >>>  void efi_save_gd(void);
> >>>@@ -726,6 +728,9 @@ void efi_sigstore_free(struct efi_signature_store 
> >>>*sigstore);
> >>>  struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);
> >>>
> >>>  bool efi_secure_boot_enabled(void);
> >>>+
> >>>+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions 
> >>>**regp,
> >>>+   WIN_CERTIFICATE **auth, size_t *auth_len);
> >>>  #endif /* CONFIG_EFI_SECURE_BOOT */
> >>>
> >>>  #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
> >>>diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> >>>index 493d906c641d..311681764034 100644
> >>>--- a/lib/efi_loader/efi_boottime.c
> >>>+++ b/lib/efi_loader/efi_boottime.c
> >>>@@ -1879,7 +1879,7 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy,
> >>>   efi_dp_split_file_path(file_path, , );
> >>>   ret = efi_setup_loaded_image(dp, fp, image_obj, );
> >>>   if (ret == EFI_SUCCESS)
> >>>-  ret = efi_load_pe(*image_obj, dest_buffer, info);
> >>>+  ret = efi_load_pe(*image_obj, dest_buffer, source_size, info);
> >>>   if (!source_buffer)
> >>>   /* Release buffer to which file was loaded */
> >>>   efi_free_pages((uintptr_t)dest_buffer,
> >>>diff --git a/lib/efi_loader/efi_image_loader.c 
> >>>b/lib/efi_loader/efi_image_loader.c
> >>>index 13541cfa7a28..939758e61e3c 100644
> >>>--- a/lib/efi_loader/efi_image_loader.c
> >>>+++ b/lib/efi_loader/efi_image_loader.c
> >>>@@ -9,7 +9,9 @@
> >>>
> >>>  #include 
> >>>  #include 
> >>>+#include 
> >>>  #include 
> >>>+#include "../lib/crypto/pkcs7_parser.h"
> >>>
> >>>  const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
> >>>  const efi_guid_t efi_guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
> >>>@@ -205,6 +207,367 @@ static void efi_set_code_and_data_type(
> >>>   }
> >>>  }
> >>>
> >>>+#ifdef CONFIG_EFI_SECURE_BOOT
> >>>+/**
> >>>+ * efi_image_parse - parse a PE image
> >>>+ * @efi:  Pointer to image
> >>>+ * @len:  Size of @efi
> >>>+ * @regs: Pointer to a list of regions
> >>>+ * @auth: Pointer to a pointer to authentication data in PE
> >>>+ * @auth_len: Size of @auth
> >>>+ *
> >>>+ * Parse image binary in PE32(+) format, assuming that sanity of PE image
> >>>+ * has been checked by a caller.
> >>>+ * On success, an address of authentication data in @efi and its size will
> >>>+ * be returned in @auth and @auth_len, respectively.
> >>>+ *
> >>>+ * Return:true on success, false on error
> >>>+ */
> >>>+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions 
> >>>**regp,
> >>>+   WIN_CERTIFICATE **auth, size_t *auth_len)
> >>
> >>
> >>This function is way too long (> 100 lines). 

Re: [PATCH v4 08/16] efi_loader: image_loader: support image authentication

2020-01-16 Thread Heinrich Schuchardt

On 1/17/20 6:11 AM, AKASHI Takahiro wrote:

On Thu, Jan 09, 2020 at 12:55:17AM +0100, Heinrich Schuchardt wrote:

On 12/18/19 1:45 AM, AKASHI Takahiro wrote:

With this commit, image validation can be enforced, as UEFI specification
section 32.5 describes, if CONFIG_EFI_SECURE_BOOT is enabled.

Currently we support
* authentication based on db and dbx,
   so dbx-validated image will always be rejected.
* following signature types:
 EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images)
 EFI_CERT_X509_GUID (x509 certificate for signed images)
Timestamp-based certificate revocation is not supported here.

Internally, authentication data is stored in one of certificates tables
of PE image (See efi_image_parse()) and will be verified by
efi_image_authenticate() before loading a given image.

It seems that UEFI specification defines the verification process
in a bit ambiguous way. I tried to implement it as closely to as
EDK2 does.

Signed-off-by: AKASHI Takahiro 
---
  include/efi_loader.h  |   7 +-
  lib/efi_loader/efi_boottime.c |   2 +-
  lib/efi_loader/efi_image_loader.c | 454 +-
  3 files changed, 449 insertions(+), 14 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 1f88caf86709..e12b49098fb0 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -11,6 +11,7 @@
  #include 
  #include 
  #include 
+#include 

  static inline int guidcmp(const void *g1, const void *g2)
  {
@@ -398,7 +399,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout);
  /* Called from places to check whether a timer expired */
  void efi_timer_check(void);
  /* PE loader implementation */
-efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
+efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
+void *efi, size_t efi_size,
 struct efi_loaded_image *loaded_image_info);
  /* Called once to store the pristine gd pointer */
  void efi_save_gd(void);
@@ -726,6 +728,9 @@ void efi_sigstore_free(struct efi_signature_store 
*sigstore);
  struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);

  bool efi_secure_boot_enabled(void);
+
+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
+WIN_CERTIFICATE **auth, size_t *auth_len);
  #endif /* CONFIG_EFI_SECURE_BOOT */

  #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 493d906c641d..311681764034 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1879,7 +1879,7 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy,
efi_dp_split_file_path(file_path, , );
ret = efi_setup_loaded_image(dp, fp, image_obj, );
if (ret == EFI_SUCCESS)
-   ret = efi_load_pe(*image_obj, dest_buffer, info);
+   ret = efi_load_pe(*image_obj, dest_buffer, source_size, info);
if (!source_buffer)
/* Release buffer to which file was loaded */
efi_free_pages((uintptr_t)dest_buffer,
diff --git a/lib/efi_loader/efi_image_loader.c 
b/lib/efi_loader/efi_image_loader.c
index 13541cfa7a28..939758e61e3c 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -9,7 +9,9 @@

  #include 
  #include 
+#include 
  #include 
+#include "../lib/crypto/pkcs7_parser.h"

  const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
  const efi_guid_t efi_guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
@@ -205,6 +207,367 @@ static void efi_set_code_and_data_type(
}
  }

+#ifdef CONFIG_EFI_SECURE_BOOT
+/**
+ * efi_image_parse - parse a PE image
+ * @efi:   Pointer to image
+ * @len:   Size of @efi
+ * @regs:  Pointer to a list of regions
+ * @auth:  Pointer to a pointer to authentication data in PE
+ * @auth_len:  Size of @auth
+ *
+ * Parse image binary in PE32(+) format, assuming that sanity of PE image
+ * has been checked by a caller.
+ * On success, an address of authentication data in @efi and its size will
+ * be returned in @auth and @auth_len, respectively.
+ *
+ * Return: true on success, false on error
+ */
+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
+WIN_CERTIFICATE **auth, size_t *auth_len)



This function is way too long (> 100 lines). Please, cut it into logical
units.




+{
+   struct efi_image_regions *regs;
+   IMAGE_DOS_HEADER *dos;
+   IMAGE_NT_HEADERS32 *nt;
+   IMAGE_SECTION_HEADER *sections, **sorted;
+   int num_regions, num_sections, i, j;
+   int ctidx = IMAGE_DIRECTORY_ENTRY_SECURITY;
+   u32 align, size, authsz, authoff;
+   size_t bytes_hashed;
+
+   dos = (void *)efi;
+   nt = (void *)(efi + dos->e_lfanew);
+
+   /*
+* Count maximum number of regions to be digested.
+* We don't have to have an exact number here.
+  

Re: [PATCH v4 08/16] efi_loader: image_loader: support image authentication

2020-01-16 Thread AKASHI Takahiro
On Thu, Jan 09, 2020 at 12:55:17AM +0100, Heinrich Schuchardt wrote:
> On 12/18/19 1:45 AM, AKASHI Takahiro wrote:
> >With this commit, image validation can be enforced, as UEFI specification
> >section 32.5 describes, if CONFIG_EFI_SECURE_BOOT is enabled.
> >
> >Currently we support
> >* authentication based on db and dbx,
> >   so dbx-validated image will always be rejected.
> >* following signature types:
> > EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images)
> > EFI_CERT_X509_GUID (x509 certificate for signed images)
> >Timestamp-based certificate revocation is not supported here.
> >
> >Internally, authentication data is stored in one of certificates tables
> >of PE image (See efi_image_parse()) and will be verified by
> >efi_image_authenticate() before loading a given image.
> >
> >It seems that UEFI specification defines the verification process
> >in a bit ambiguous way. I tried to implement it as closely to as
> >EDK2 does.
> >
> >Signed-off-by: AKASHI Takahiro 
> >---
> >  include/efi_loader.h  |   7 +-
> >  lib/efi_loader/efi_boottime.c |   2 +-
> >  lib/efi_loader/efi_image_loader.c | 454 +-
> >  3 files changed, 449 insertions(+), 14 deletions(-)
> >
> >diff --git a/include/efi_loader.h b/include/efi_loader.h
> >index 1f88caf86709..e12b49098fb0 100644
> >--- a/include/efi_loader.h
> >+++ b/include/efi_loader.h
> >@@ -11,6 +11,7 @@
> >  #include 
> >  #include 
> >  #include 
> >+#include 
> >
> >  static inline int guidcmp(const void *g1, const void *g2)
> >  {
> >@@ -398,7 +399,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout);
> >  /* Called from places to check whether a timer expired */
> >  void efi_timer_check(void);
> >  /* PE loader implementation */
> >-efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
> >+efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
> >+ void *efi, size_t efi_size,
> >  struct efi_loaded_image *loaded_image_info);
> >  /* Called once to store the pristine gd pointer */
> >  void efi_save_gd(void);
> >@@ -726,6 +728,9 @@ void efi_sigstore_free(struct efi_signature_store 
> >*sigstore);
> >  struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);
> >
> >  bool efi_secure_boot_enabled(void);
> >+
> >+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
> >+ WIN_CERTIFICATE **auth, size_t *auth_len);
> >  #endif /* CONFIG_EFI_SECURE_BOOT */
> >
> >  #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
> >diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> >index 493d906c641d..311681764034 100644
> >--- a/lib/efi_loader/efi_boottime.c
> >+++ b/lib/efi_loader/efi_boottime.c
> >@@ -1879,7 +1879,7 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy,
> > efi_dp_split_file_path(file_path, , );
> > ret = efi_setup_loaded_image(dp, fp, image_obj, );
> > if (ret == EFI_SUCCESS)
> >-ret = efi_load_pe(*image_obj, dest_buffer, info);
> >+ret = efi_load_pe(*image_obj, dest_buffer, source_size, info);
> > if (!source_buffer)
> > /* Release buffer to which file was loaded */
> > efi_free_pages((uintptr_t)dest_buffer,
> >diff --git a/lib/efi_loader/efi_image_loader.c 
> >b/lib/efi_loader/efi_image_loader.c
> >index 13541cfa7a28..939758e61e3c 100644
> >--- a/lib/efi_loader/efi_image_loader.c
> >+++ b/lib/efi_loader/efi_image_loader.c
> >@@ -9,7 +9,9 @@
> >
> >  #include 
> >  #include 
> >+#include 
> >  #include 
> >+#include "../lib/crypto/pkcs7_parser.h"
> >
> >  const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
> >  const efi_guid_t efi_guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
> >@@ -205,6 +207,367 @@ static void efi_set_code_and_data_type(
> > }
> >  }
> >
> >+#ifdef CONFIG_EFI_SECURE_BOOT
> >+/**
> >+ * efi_image_parse - parse a PE image
> >+ * @efi:Pointer to image
> >+ * @len:Size of @efi
> >+ * @regs:   Pointer to a list of regions
> >+ * @auth:   Pointer to a pointer to authentication data in PE
> >+ * @auth_len:   Size of @auth
> >+ *
> >+ * Parse image binary in PE32(+) format, assuming that sanity of PE image
> >+ * has been checked by a caller.
> >+ * On success, an address of authentication data in @efi and its size will
> >+ * be returned in @auth and @auth_len, respectively.
> >+ *
> >+ * Return:  true on success, false on error
> >+ */
> >+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
> >+ WIN_CERTIFICATE **auth, size_t *auth_len)
> 
> 
> This function is way too long (> 100 lines). Please, cut it into logical
> units.
> 
> 
> 
> >+{
> >+struct efi_image_regions *regs;
> >+IMAGE_DOS_HEADER *dos;
> >+IMAGE_NT_HEADERS32 *nt;
> >+IMAGE_SECTION_HEADER *sections, **sorted;
> >+int num_regions, num_sections, i, j;
> >+int ctidx = IMAGE_DIRECTORY_ENTRY_SECURITY;
> >+u32 align, size, 

Re: [PATCH v4 08/16] efi_loader: image_loader: support image authentication

2020-01-08 Thread Heinrich Schuchardt

On 12/18/19 1:45 AM, AKASHI Takahiro wrote:

With this commit, image validation can be enforced, as UEFI specification
section 32.5 describes, if CONFIG_EFI_SECURE_BOOT is enabled.

Currently we support
* authentication based on db and dbx,
   so dbx-validated image will always be rejected.
* following signature types:
 EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images)
 EFI_CERT_X509_GUID (x509 certificate for signed images)
Timestamp-based certificate revocation is not supported here.

Internally, authentication data is stored in one of certificates tables
of PE image (See efi_image_parse()) and will be verified by
efi_image_authenticate() before loading a given image.

It seems that UEFI specification defines the verification process
in a bit ambiguous way. I tried to implement it as closely to as
EDK2 does.

Signed-off-by: AKASHI Takahiro 
---
  include/efi_loader.h  |   7 +-
  lib/efi_loader/efi_boottime.c |   2 +-
  lib/efi_loader/efi_image_loader.c | 454 +-
  3 files changed, 449 insertions(+), 14 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 1f88caf86709..e12b49098fb0 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -11,6 +11,7 @@
  #include 
  #include 
  #include 
+#include 

  static inline int guidcmp(const void *g1, const void *g2)
  {
@@ -398,7 +399,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout);
  /* Called from places to check whether a timer expired */
  void efi_timer_check(void);
  /* PE loader implementation */
-efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
+efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
+void *efi, size_t efi_size,
 struct efi_loaded_image *loaded_image_info);
  /* Called once to store the pristine gd pointer */
  void efi_save_gd(void);
@@ -726,6 +728,9 @@ void efi_sigstore_free(struct efi_signature_store 
*sigstore);
  struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);

  bool efi_secure_boot_enabled(void);
+
+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
+WIN_CERTIFICATE **auth, size_t *auth_len);
  #endif /* CONFIG_EFI_SECURE_BOOT */

  #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 493d906c641d..311681764034 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1879,7 +1879,7 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy,
efi_dp_split_file_path(file_path, , );
ret = efi_setup_loaded_image(dp, fp, image_obj, );
if (ret == EFI_SUCCESS)
-   ret = efi_load_pe(*image_obj, dest_buffer, info);
+   ret = efi_load_pe(*image_obj, dest_buffer, source_size, info);
if (!source_buffer)
/* Release buffer to which file was loaded */
efi_free_pages((uintptr_t)dest_buffer,
diff --git a/lib/efi_loader/efi_image_loader.c 
b/lib/efi_loader/efi_image_loader.c
index 13541cfa7a28..939758e61e3c 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -9,7 +9,9 @@

  #include 
  #include 
+#include 
  #include 
+#include "../lib/crypto/pkcs7_parser.h"

  const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
  const efi_guid_t efi_guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
@@ -205,6 +207,367 @@ static void efi_set_code_and_data_type(
}
  }

+#ifdef CONFIG_EFI_SECURE_BOOT
+/**
+ * efi_image_parse - parse a PE image
+ * @efi:   Pointer to image
+ * @len:   Size of @efi
+ * @regs:  Pointer to a list of regions
+ * @auth:  Pointer to a pointer to authentication data in PE
+ * @auth_len:  Size of @auth
+ *
+ * Parse image binary in PE32(+) format, assuming that sanity of PE image
+ * has been checked by a caller.
+ * On success, an address of authentication data in @efi and its size will
+ * be returned in @auth and @auth_len, respectively.
+ *
+ * Return: true on success, false on error
+ */
+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
+WIN_CERTIFICATE **auth, size_t *auth_len)



This function is way too long (> 100 lines). Please, cut it into logical
units.




+{
+   struct efi_image_regions *regs;
+   IMAGE_DOS_HEADER *dos;
+   IMAGE_NT_HEADERS32 *nt;
+   IMAGE_SECTION_HEADER *sections, **sorted;
+   int num_regions, num_sections, i, j;
+   int ctidx = IMAGE_DIRECTORY_ENTRY_SECURITY;
+   u32 align, size, authsz, authoff;
+   size_t bytes_hashed;
+
+   dos = (void *)efi;
+   nt = (void *)(efi + dos->e_lfanew);
+
+   /*
+* Count maximum number of regions to be digested.
+* We don't have to have an exact number here.
+* See efi_image_region_add()'s in parsing below.
+*/
+   num_regions = 3; /* for header */
+   

[PATCH v4 08/16] efi_loader: image_loader: support image authentication

2019-12-17 Thread AKASHI Takahiro
With this commit, image validation can be enforced, as UEFI specification
section 32.5 describes, if CONFIG_EFI_SECURE_BOOT is enabled.

Currently we support
* authentication based on db and dbx,
  so dbx-validated image will always be rejected.
* following signature types:
EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images)
EFI_CERT_X509_GUID (x509 certificate for signed images)
Timestamp-based certificate revocation is not supported here.

Internally, authentication data is stored in one of certificates tables
of PE image (See efi_image_parse()) and will be verified by
efi_image_authenticate() before loading a given image.

It seems that UEFI specification defines the verification process
in a bit ambiguous way. I tried to implement it as closely to as
EDK2 does.

Signed-off-by: AKASHI Takahiro 
---
 include/efi_loader.h  |   7 +-
 lib/efi_loader/efi_boottime.c |   2 +-
 lib/efi_loader/efi_image_loader.c | 454 +-
 3 files changed, 449 insertions(+), 14 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 1f88caf86709..e12b49098fb0 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -11,6 +11,7 @@
 #include 
 #include 
 #include 
+#include 
 
 static inline int guidcmp(const void *g1, const void *g2)
 {
@@ -398,7 +399,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout);
 /* Called from places to check whether a timer expired */
 void efi_timer_check(void);
 /* PE loader implementation */
-efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
+efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
+void *efi, size_t efi_size,
 struct efi_loaded_image *loaded_image_info);
 /* Called once to store the pristine gd pointer */
 void efi_save_gd(void);
@@ -726,6 +728,9 @@ void efi_sigstore_free(struct efi_signature_store 
*sigstore);
 struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);
 
 bool efi_secure_boot_enabled(void);
+
+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
+WIN_CERTIFICATE **auth, size_t *auth_len);
 #endif /* CONFIG_EFI_SECURE_BOOT */
 
 #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 493d906c641d..311681764034 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1879,7 +1879,7 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy,
efi_dp_split_file_path(file_path, , );
ret = efi_setup_loaded_image(dp, fp, image_obj, );
if (ret == EFI_SUCCESS)
-   ret = efi_load_pe(*image_obj, dest_buffer, info);
+   ret = efi_load_pe(*image_obj, dest_buffer, source_size, info);
if (!source_buffer)
/* Release buffer to which file was loaded */
efi_free_pages((uintptr_t)dest_buffer,
diff --git a/lib/efi_loader/efi_image_loader.c 
b/lib/efi_loader/efi_image_loader.c
index 13541cfa7a28..939758e61e3c 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -9,7 +9,9 @@
 
 #include 
 #include 
+#include 
 #include 
+#include "../lib/crypto/pkcs7_parser.h"
 
 const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
 const efi_guid_t efi_guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
@@ -205,6 +207,367 @@ static void efi_set_code_and_data_type(
}
 }
 
+#ifdef CONFIG_EFI_SECURE_BOOT
+/**
+ * efi_image_parse - parse a PE image
+ * @efi:   Pointer to image
+ * @len:   Size of @efi
+ * @regs:  Pointer to a list of regions
+ * @auth:  Pointer to a pointer to authentication data in PE
+ * @auth_len:  Size of @auth
+ *
+ * Parse image binary in PE32(+) format, assuming that sanity of PE image
+ * has been checked by a caller.
+ * On success, an address of authentication data in @efi and its size will
+ * be returned in @auth and @auth_len, respectively.
+ *
+ * Return: true on success, false on error
+ */
+bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp,
+WIN_CERTIFICATE **auth, size_t *auth_len)
+{
+   struct efi_image_regions *regs;
+   IMAGE_DOS_HEADER *dos;
+   IMAGE_NT_HEADERS32 *nt;
+   IMAGE_SECTION_HEADER *sections, **sorted;
+   int num_regions, num_sections, i, j;
+   int ctidx = IMAGE_DIRECTORY_ENTRY_SECURITY;
+   u32 align, size, authsz, authoff;
+   size_t bytes_hashed;
+
+   dos = (void *)efi;
+   nt = (void *)(efi + dos->e_lfanew);
+
+   /*
+* Count maximum number of regions to be digested.
+* We don't have to have an exact number here.
+* See efi_image_region_add()'s in parsing below.
+*/
+   num_regions = 3; /* for header */
+   num_regions += nt->FileHeader.NumberOfSections;
+   num_regions++; /* for extra */
+
+   regs = calloc(sizeof(*regs) + sizeof(struct image_region)