From 593e17d673abe8e903412e6d55b2eb54b159b096 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 14 Apr 2020 11:51:39 +0900 Subject: efi_loader: add signature verification functions In this commit, implemented are a couple of helper functions which will be used to materialize variable authentication as well as image authentication in later patches. Signed-off-by: AKASHI Takahiro --- include/efi_api.h | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/efi_loader.h | 72 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 1c40ffc4f56..77d6bf2660b 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -18,6 +18,7 @@ #include #include +#include #ifdef CONFIG_EFI_LOADER #include @@ -329,6 +330,10 @@ struct efi_runtime_services { EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, \ 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) +#define EFI_IMAGE_SECURITY_DATABASE_GUID \ + EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, \ + 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f) + #define EFI_FDT_GUID \ EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, \ 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) @@ -1682,4 +1687,86 @@ struct efi_load_file_protocol { #define LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL_VENDOR_RANGE_MIN 0x00001000 #define LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL_VENDOR_RANGE_MAX 0x00004000 +/* Certificate types in signature database */ +#define EFI_CERT_SHA256_GUID \ + EFI_GUID(0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, \ + 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28) +#define EFI_CERT_RSA2048_GUID \ + EFI_GUID(0x3c5766e8, 0x269c, 0x4e34, 0xaa, 0x14, \ + 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6) +#define EFI_CERT_X509_GUID \ + EFI_GUID(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, \ + 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72) +#define EFI_CERT_X509_SHA256_GUID \ + EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, \ + 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed) +#define EFI_CERT_TYPE_PKCS7_GUID \ + EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \ + 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7) + +/** + * win_certificate_uefi_guid - A certificate that encapsulates + * a GUID-specific signature + * + * @hdr: Windows certificate header + * @cert_type: Certificate type + * @cert_data: Certificate data + */ +struct win_certificate_uefi_guid { + WIN_CERTIFICATE hdr; + efi_guid_t cert_type; + u8 cert_data[]; +} __attribute__((__packed__)); + +/** + * efi_variable_authentication_2 - A time-based authentication method + * descriptor + * + * This structure describes an authentication information for + * a variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS + * and should be included as part of a variable's value. + * Only EFI_CERT_TYPE_PKCS7_GUID is accepted. + * + * @time_stamp: Descriptor's time stamp + * @auth_info: Authentication info + */ +struct efi_variable_authentication_2 { + struct efi_time time_stamp; + struct win_certificate_uefi_guid auth_info; +} __attribute__((__packed__)); + +/** + * efi_signature_data - A format of signature + * + * This structure describes a single signature in signature database. + * + * @signature_owner: Signature owner + * @signature_data: Signature data + */ +struct efi_signature_data { + efi_guid_t signature_owner; + u8 signature_data[]; +} __attribute__((__packed__)); + +/** + * efi_signature_list - A format of signature database + * + * This structure describes a list of signatures with the same type. + * An authenticated variable's value is a concatenation of one or more + * efi_signature_list's. + * + * @signature_type: Signature type + * @signature_list_size: Size of signature list + * @signature_header_size: Size of signature header + * @signature_size: Size of signature + */ +struct efi_signature_list { + efi_guid_t signature_type; + u32 signature_list_size; + u32 signature_header_size; + u32 signature_size; +/* u8 signature_header[signature_header_size]; */ +/* struct efi_signature_data signatures[...][signature_size]; */ +} __attribute__((__packed__)); + #endif diff --git a/include/efi_loader.h b/include/efi_loader.h index 3f2792892f3..8cf85d2fb7e 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -26,6 +26,7 @@ static inline void *guidcpy(void *dst, const void *src) #if CONFIG_IS_ENABLED(EFI_LOADER) #include +#include /* Maximum number of configuration tables */ #define EFI_MAX_CONFIGURATION_TABLES 16 @@ -178,6 +179,11 @@ extern const efi_guid_t efi_guid_hii_config_routing_protocol; extern const efi_guid_t efi_guid_hii_config_access_protocol; extern const efi_guid_t efi_guid_hii_database_protocol; extern const efi_guid_t efi_guid_hii_string_protocol; +/* GUIDs for authentication */ +extern const efi_guid_t efi_guid_image_security_database; +extern const efi_guid_t efi_guid_sha256; +extern const efi_guid_t efi_guid_cert_x509; +extern const efi_guid_t efi_guid_cert_x509_sha256; /* GUID of RNG protocol */ extern const efi_guid_t efi_guid_rng_protocol; @@ -680,6 +686,72 @@ void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data); unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data); efi_status_t efi_bootmgr_load(efi_handle_t *handle); +#ifdef CONFIG_EFI_SECURE_BOOT +#include + +/** + * efi_image_regions - A list of memory regions + * + * @max: Maximum number of regions + * @num: Number of regions + * @reg: array of regions + */ +struct efi_image_regions { + int max; + int num; + struct image_region reg[]; +}; + +/** + * efi_sig_data - A decoded data of struct efi_signature_data + * + * This structure represents an internal form of signature in + * signature database. A listed list may represent a signature list. + * + * @next: Pointer to next entry + * @onwer: Signature owner + * @data: Pointer to signature data + * @size: Size of signature data + */ +struct efi_sig_data { + struct efi_sig_data *next; + efi_guid_t owner; + void *data; + size_t size; +}; + +/** + * efi_signature_store - A decoded data of signature database + * + * This structure represents an internal form of signature database. + * + * @next: Pointer to next entry + * @sig_type: Signature type + * @sig_data_list: Pointer to signature list + */ +struct efi_signature_store { + struct efi_signature_store *next; + efi_guid_t sig_type; + struct efi_sig_data *sig_data_list; +}; + +struct x509_certificate; +struct pkcs7_message; + +bool efi_signature_verify_cert(struct x509_certificate *cert, + struct efi_signature_store *dbx); +bool efi_signature_verify_signers(struct pkcs7_message *msg, + struct efi_signature_store *dbx); +bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct efi_signature_store *db, + struct x509_certificate **cert); + +efi_status_t efi_image_region_add(struct efi_image_regions *regs, + const void *start, const void *end, + int nocheck); +#endif /* CONFIG_EFI_SECURE_BOOT */ + #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */ -- cgit v1.2.3 From be6296d05b072f312a20587cf2de8e4456bcb8ff Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 14 Apr 2020 11:51:40 +0900 Subject: efi_loader: add signature database parser efi_signature_parse_sigdb() is a helper function will be used to parse signature database variable and instantiate a signature store structure in later patches. Signed-off-by: AKASHI Takahiro --- include/efi_loader.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 8cf85d2fb7e..fea2ead02e9 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -750,6 +750,9 @@ bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs, efi_status_t efi_image_region_add(struct efi_image_regions *regs, const void *start, const void *end, int nocheck); + +void efi_sigstore_free(struct efi_signature_store *sigstore); +struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name); #endif /* CONFIG_EFI_SECURE_BOOT */ #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ -- cgit v1.2.3 From 767f6eeb01d331a7570a1a5e89010b09e5499bfb Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 14 Apr 2020 11:51:41 +0900 Subject: efi_loader: variable: support variable authentication With this commit, EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is supported for authenticated variables and the system secure state will transfer between setup mode and user mode as UEFI specification section 32.3 describes. Internally, authentication data is stored as part of authenticated variable's value. It is nothing but a pkcs7 message (but we need some wrapper, see efi_variable_parse_signature()) and will be validated by efi_variable_authenticate(), hence efi_signature_verify_with_db(). Associated time value will be encoded in "{...,time=...}" along with other UEFI variable's attributes. Signed-off-by: AKASHI Takahiro --- include/efi_loader.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index fea2ead02e9..ef8d184a6ee 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -184,6 +184,7 @@ extern const efi_guid_t efi_guid_image_security_database; extern const efi_guid_t efi_guid_sha256; extern const efi_guid_t efi_guid_cert_x509; extern const efi_guid_t efi_guid_cert_x509_sha256; +extern const efi_guid_t efi_guid_cert_type_pkcs7; /* GUID of RNG protocol */ extern const efi_guid_t efi_guid_rng_protocol; @@ -753,6 +754,8 @@ efi_status_t efi_image_region_add(struct efi_image_regions *regs, 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); #endif /* CONFIG_EFI_SECURE_BOOT */ #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ -- cgit v1.2.3 From 4540dabdcacaea50bf874115f28adc103966d25a Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 14 Apr 2020 11:51:44 +0900 Subject: efi_loader: image_loader: support image authentication 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 | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index ef8d184a6ee..0ba9a1f702a 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) { @@ -263,6 +264,11 @@ struct efi_object { enum efi_object_type type; }; +enum efi_image_auth_status { + EFI_IMAGE_AUTH_FAILED = 0, + EFI_IMAGE_AUTH_PASSED, +}; + /** * struct efi_loaded_image_obj - handle of a loaded image * @@ -282,6 +288,7 @@ struct efi_loaded_image_obj { EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, struct efi_system_table *st); u16 image_type; + enum efi_image_auth_status auth_status; }; /** @@ -415,7 +422,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); @@ -756,6 +764,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) */ -- cgit v1.2.3