From 758b795a86589994065099d0af02eb30626a3c21 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Sat, 20 Feb 2021 12:32:48 -0500 Subject: Cryptlib: make some Str*() args const. --- Cryptlib/Library/BaseLib.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Cryptlib/Library') diff --git a/Cryptlib/Library/BaseLib.h b/Cryptlib/Library/BaseLib.h index 5d326844..93d5c691 100644 --- a/Cryptlib/Library/BaseLib.h +++ b/Cryptlib/Library/BaseLib.h @@ -2,8 +2,8 @@ #include UINT32 WriteUnaligned32 (UINT32 *Buffer, UINT32 Value); -UINTN AsciiStrSize (CHAR8 *string); -char *AsciiStrnCpy(char *Destination, char *Source, UINTN count); -char *AsciiStrCat(char *Destination, char *Source); -CHAR8 *AsciiStrCpy(CHAR8 *Destination, CHAR8 *Source); -UINTN AsciiStrDecimalToUintn(const char *String); +UINTN AsciiStrSize (const CHAR8 *string); +CHAR8 *AsciiStrnCpy(CHAR8 *Destination, const CHAR8 *Source, UINTN count); +CHAR8 *AsciiStrCat(CHAR8 *Destination, const CHAR8 *Source); +CHAR8 *AsciiStrCpy(CHAR8 *Destination, const CHAR8 *Source); +UINTN AsciiStrDecimalToUintn(const CHAR8 *String); -- cgit v1.2.3 From 9beca885c29c77bb901547321a5ce6fd3c9c8ee3 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 9 Mar 2021 14:40:03 -0500 Subject: Fix stdarg to work the same everywhere. This gets us the same working definition for VA_* va_* etc everywhere, and it's the same definition edk2 is using. Signed-off-by: Peter Jones --- Cryptlib/Include/OpenSslSupport.h | 125 ++++++-------------------------------- Cryptlib/Library/BaseLib.h | 16 +++++ Cryptlib/Makefile | 3 +- Cryptlib/OpenSSL/Makefile | 3 +- Make.defaults | 4 +- errlog.c | 24 ++++---- include/console.h | 2 +- include/hexdump.h | 10 +-- include/system/efistdarg.h | 15 +++++ include/system/stdarg.h | 41 ++++++++----- lib/Makefile | 3 +- lib/console.c | 12 ++-- shim.h | 23 +++++-- 13 files changed, 120 insertions(+), 161 deletions(-) create mode 100644 include/system/efistdarg.h (limited to 'Cryptlib/Library') diff --git a/Cryptlib/Include/OpenSslSupport.h b/Cryptlib/Include/OpenSslSupport.h index 6bb7ba64..1f475a32 100644 --- a/Cryptlib/Include/OpenSslSupport.h +++ b/Cryptlib/Include/OpenSslSupport.h @@ -15,6 +15,22 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #ifndef __OPEN_SSL_SUPPORT_H__ #define __OPEN_SSL_SUPPORT_H__ +#if defined(__x86_64__) +/* shim.h will check if the compiler is new enough in some other CU */ + +#if !defined(GNU_EFI_USE_EXTERNAL_STDARG) +#define GNU_EFI_USE_EXTERNAL_STDARG +#endif + +#if !defined(GNU_EFI_USE_MS_ABI) +#define GNU_EFI_USE_MS_ABI +#endif + +#ifdef NO_BUILTIN_VA_FUNCS +#undef NO_BUILTIN_VA_FUNCS +#endif +#endif + /* * Include stddef.h to avoid redefining "offsetof" */ @@ -64,113 +80,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // typedef VOID *FILE; -// -// Map all va_xxxx elements to VA_xxx defined in MdePkg/Include/Base.h -// -#if !defined(__CC_ARM) || defined(_STDARG_H) // if va_list is not already defined -/* - * These are now unconditionally #defined by GNU_EFI's efistdarg.h, - * so we should #undef them here before providing a new definition. - */ -#undef va_arg -#undef va_start -#undef va_end - -#define va_list VA_LIST -#define va_arg VA_ARG -#define va_start VA_START -#define va_end VA_END - -# if !defined(NO_BUILTIN_VA_FUNCS) - -typedef __builtin_va_list VA_LIST; - -#define VA_START(Marker, Parameter) __builtin_va_start (Marker, Parameter) - -#define VA_ARG(Marker, TYPE) ((sizeof (TYPE) < sizeof (UINTN)) ? (TYPE)(__builtin_va_arg (Marker, UINTN)) : (TYPE)(__builtin_va_arg (Marker, TYPE))) - -#define VA_END(Marker) __builtin_va_end (Marker) - -#define VA_COPY(Dest, Start) __builtin_va_copy (Dest, Start) - -# else - -#define _INT_SIZE_OF(n) ((sizeof (n) + sizeof (UINTN) - 1) &~(sizeof (UINTN) - 1)) -/// -/// Variable used to traverse the list of arguments. This type can vary by -/// implementation and could be an array or structure. -/// -typedef CHAR8 *VA_LIST; - -/** - Retrieves a pointer to the beginning of a variable argument list, based on - the name of the parameter that immediately precedes the variable argument list. - - This function initializes Marker to point to the beginning of the variable - argument list that immediately follows Parameter. The method for computing the - pointer to the next argument in the argument list is CPU-specific following the - EFIAPI ABI. - - @param Marker The VA_LIST used to traverse the list of arguments. - @param Parameter The name of the parameter that immediately precedes - the variable argument list. - - @return A pointer to the beginning of a variable argument list. - -**/ -#define VA_START(Marker, Parameter) (Marker = (VA_LIST) ((UINTN) & (Parameter) + _INT_SIZE_OF (Parameter))) - -/** - Returns an argument of a specified type from a variable argument list and updates - the pointer to the variable argument list to point to the next argument. - - This function returns an argument of the type specified by TYPE from the beginning - of the variable argument list specified by Marker. Marker is then updated to point - to the next argument in the variable argument list. The method for computing the - pointer to the next argument in the argument list is CPU-specific following the EFIAPI ABI. - - @param Marker VA_LIST used to traverse the list of arguments. - @param TYPE The type of argument to retrieve from the beginning - of the variable argument list. - - @return An argument of the type specified by TYPE. - -**/ -#define VA_ARG(Marker, TYPE) (*(TYPE *) ((Marker += _INT_SIZE_OF (TYPE)) - _INT_SIZE_OF (TYPE))) - -/** - Terminates the use of a variable argument list. - - This function initializes Marker so it can no longer be used with VA_ARG(). - After this macro is used, the only way to access the variable argument list is - by using VA_START() again. - - @param Marker VA_LIST used to traverse the list of arguments. - -**/ -#define VA_END(Marker) (Marker = (VA_LIST) 0) - -/** - Initializes a VA_LIST as a copy of an existing VA_LIST. - - This macro initializes Dest as a copy of Start, as if the VA_START macro had been applied to Dest - followed by the same sequence of uses of the VA_ARG macro as had previously been used to reach - the present state of Start. - - @param Dest VA_LIST used to traverse the list of arguments. - @param Start VA_LIST used to traverse the list of arguments. - -**/ -#define VA_COPY(Dest, Start) ((void)((Dest) = (Start))) - -# endif - -#else // __CC_ARM -#define va_start(Marker, Parameter) __va_start(Marker, Parameter) -#define va_arg(Marker, TYPE) __va_arg(Marker, TYPE) -#define va_end(Marker) ((void)0) -#endif - // // #defines from EFI Application Toolkit required to buiild Open SSL // @@ -318,7 +227,7 @@ size_t fwrite (const void *, size_t, size_t, FILE *); char *fgets (char *, int, FILE *); int fputs (const char *, FILE *); int fprintf (FILE *, const char *, ...); -int vfprintf (FILE *, const char *, VA_LIST); +int vfprintf (FILE *, const char *, va_list); int fflush (FILE *); int fclose (FILE *); DIR *opendir (const char *); diff --git a/Cryptlib/Library/BaseLib.h b/Cryptlib/Library/BaseLib.h index 93d5c691..94b25c93 100644 --- a/Cryptlib/Library/BaseLib.h +++ b/Cryptlib/Library/BaseLib.h @@ -1,3 +1,19 @@ +#if defined(__x86_64__) +/* shim.h will check if the compiler is new enough in some other CU */ + +#if !defined(GNU_EFI_USE_EXTERNAL_STDARG) +#define GNU_EFI_USE_EXTERNAL_STDARG +#endif + +#if !defined(GNU_EFI_USE_MS_ABI) +#define GNU_EFI_USE_MS_ABI +#endif + +#ifdef NO_BUILTIN_VA_FUNCS +#undef NO_BUILTIN_VA_FUNCS +#endif +#endif + #include #include diff --git a/Cryptlib/Makefile b/Cryptlib/Makefile index 27614618..547fd106 100644 --- a/Cryptlib/Makefile +++ b/Cryptlib/Makefile @@ -22,8 +22,7 @@ CLANG_BUGS = $(if $(findstring gcc,$(CC)),-maccumulate-outgoing-args,) ifeq ($(ARCH),x86_64) FEATUREFLAGS += -m64 -mno-mmx -mno-sse -mno-red-zone $(CLANG_BUGS) -DEFINES += -DEFI_FUNCTION_WRAPPER -DGNU_EFI_USE_MS_ABI \ - -DNO_BUILTIN_VA_FUNCS -DMDE_CPU_X64 +DEFINES += -DMDE_CPU_X64 endif ifeq ($(ARCH),ia32) FEATUREFLAGS += -m32 -mno-mmx -mno-sse -mno-red-zone $(CLANG_BUGS) diff --git a/Cryptlib/OpenSSL/Makefile b/Cryptlib/OpenSSL/Makefile index 294e889a..1b8ca318 100644 --- a/Cryptlib/OpenSSL/Makefile +++ b/Cryptlib/OpenSSL/Makefile @@ -36,8 +36,7 @@ CLANG_BUGS = $(if $(findstring gcc,$(CC)),-maccumulate-outgoing-args,) ifeq ($(ARCH),x86_64) FEATUREFLAGS += -m64 -mno-mmx -mno-sse -mno-red-zone $(CLANG_BUGS) -DEFINES += -DEFI_FUNCTION_WRAPPER -DGNU_EFI_USE_MS_ABI \ - -UNO_BUILTIN_VA_FUNCS -DMDE_CPU_X64 +DEFINES += -DMDE_CPU_X64 endif ifeq ($(ARCH),ia32) FEATUREFLAGS += -m32 -mno-mmx -mno-sse -mno-red-zone -nostdinc $(CLANG_BUGS) diff --git a/Make.defaults b/Make.defaults index 50164ae8..f956c005 100644 --- a/Make.defaults +++ b/Make.defaults @@ -53,9 +53,7 @@ COMMIT_ID ?= $(shell if [ -e .git ] ; then git log -1 --pretty=format:%H ; elif ifeq ($(ARCH),x86_64) ARCH_CFLAGS ?= -mno-mmx -mno-sse -mno-red-zone -nostdinc \ $(CLANG_BUGS) -m64 \ - -DEFI_FUNCTION_WRAPPER -DGNU_EFI_USE_MS_ABI \ - -UNO_BUILTIN_VA_FUNCS -DMDE_CPU_X64 \ - -DPAGE_SIZE=4096 + -DMDE_CPU_X64 -DPAGE_SIZE=4096 ARCH_GNUEFI ?= x86_64 ARCH_SUFFIX ?= x64 ARCH_SUFFIX_UPPER ?= X64 diff --git a/errlog.c b/errlog.c index 16af23b0..ac657151 100644 --- a/errlog.c +++ b/errlog.c @@ -10,24 +10,26 @@ static CHAR16 **errs = NULL; static UINTN nerrs = 0; EFI_STATUS EFIAPI -vdprint_(const CHAR16 *fmt, const char *file, int line, const char *func, elf_va_list args) +vdprint_(const CHAR16 *fmt, const char *file, int line, const char *func, + va_list args) { - elf_va_list args2; + va_list args2; EFI_STATUS efi_status = EFI_SUCCESS; if (verbose) { - elf_va_copy(args2, args); + va_copy(args2, args); console_print(L"%a:%d:%a() ", file, line, func); efi_status = VPrint(fmt, args2); - elf_va_end(args2); + va_end(args2); } return efi_status; } EFI_STATUS EFIAPI -VLogError(const char *file, int line, const char *func, const CHAR16 *fmt, elf_va_list args) +VLogError(const char *file, int line, const char *func, const CHAR16 *fmt, + va_list args) { - elf_va_list args2; + va_list args2; CHAR16 **newerrs; newerrs = ReallocatePool(errs, (nerrs + 1) * sizeof(*errs), @@ -38,11 +40,11 @@ VLogError(const char *file, int line, const char *func, const CHAR16 *fmt, elf_v newerrs[nerrs] = PoolPrint(L"%a:%d %a() ", file, line, func); if (!newerrs[nerrs]) return EFI_OUT_OF_RESOURCES; - elf_va_copy(args2, args); + va_copy(args2, args); newerrs[nerrs+1] = VPoolPrint(fmt, args2); if (!newerrs[nerrs+1]) return EFI_OUT_OF_RESOURCES; - elf_va_end(args2); + va_end(args2); nerrs += 2; newerrs[nerrs] = NULL; @@ -54,12 +56,12 @@ VLogError(const char *file, int line, const char *func, const CHAR16 *fmt, elf_v EFI_STATUS EFIAPI LogError_(const char *file, int line, const char *func, const CHAR16 *fmt, ...) { - elf_va_list args; + va_list args; EFI_STATUS efi_status; - elf_va_start(args, fmt); + va_start(args, fmt); efi_status = VLogError(file, line, func, fmt, args); - elf_va_end(args); + va_end(args); return efi_status; } diff --git a/include/console.h b/include/console.h index d8af3cd3..00982744 100644 --- a/include/console.h +++ b/include/console.h @@ -102,7 +102,7 @@ extern UINT32 verbose; dprint_(L"%a:%d:%a() " fmt, __FILE__, __LINE__ - 1, __func__, \ ##__VA_ARGS__) extern EFI_STATUS EFIAPI vdprint_(const CHAR16 *fmt, const char *file, int line, - const char *func, elf_va_list args); + const char *func, va_list args); #define vdprint(fmt, ...) \ vdprint_(fmt, __FILE__, __LINE__ - 1, __func__, ##__VA_ARGS__) diff --git a/include/hexdump.h b/include/hexdump.h index a6aa2bfa..f778de9a 100644 --- a/include/hexdump.h +++ b/include/hexdump.h @@ -81,7 +81,7 @@ prepare_text(const void *data, size_t size, char *buf, unsigned int position) */ static inline void UNUSED EFIAPI vhexdumpf(const char *file, int line, const char *func, const CHAR16 *const fmt, - const void *data, unsigned long size, size_t at, elf_va_list ap) + const void *data, unsigned long size, size_t at, va_list ap) { unsigned long display_offset = at; unsigned long offset = 0; @@ -114,15 +114,15 @@ vhexdumpf(const char *file, int line, const char *func, const CHAR16 *const fmt, * hexdump formatted * think of it as: printf("%s%s", format(fmt, ...), hexdump(data,size)[lineN]); */ -static inline void UNUSED +static inline void UNUSED EFIAPI hexdumpf(const char *file, int line, const char *func, const CHAR16 *const fmt, const void *data, unsigned long size, size_t at, ...) { - elf_va_list ap; + va_list ap; - elf_va_start(ap, at); + va_start(ap, at); vhexdumpf(file, line, func, fmt, data, size, at, ap); - elf_va_end(ap); + va_end(ap); } static inline void UNUSED diff --git a/include/system/efistdarg.h b/include/system/efistdarg.h new file mode 100644 index 00000000..837c4f23 --- /dev/null +++ b/include/system/efistdarg.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * efistdarg.h - AAAARGGGG + * Copyright Peter Jones + */ + +#ifndef SHIM_UNIT_TEST +#ifndef _EFISTDARG_H_ +#define _EFISTDARG_H_ + +#include + +#endif /* !_EFISTDARG_H_ */ +#endif +// vim:fenc=utf-8:tw=75:noet diff --git a/include/system/stdarg.h b/include/system/stdarg.h index 346b760d..af1ac59b 100644 --- a/include/system/stdarg.h +++ b/include/system/stdarg.h @@ -8,24 +8,33 @@ #ifndef _STDARG_H #define _STDARG_H -#include - -#endif /* !_STDARG_H */ +#ifndef GNU_EFI_USE_EXTERNAL_STDARG +#define GNU_EFI_USE_EXTERNAL_STDARG #endif -#ifndef SHIM_STDARG_H_ -#define SHIM_STDARG_H_ -typedef __builtin_ms_va_list ms_va_list; -#define ms_va_copy(dest, start) __builtin_ms_va_copy(dest, start) -#define ms_va_start(marker, arg) __builtin_ms_va_start(marker, arg) -#define ms_va_arg(marker, type) __builtin_va_arg(marker, type) -#define ms_va_end(marker) __builtin_ms_va_end(marker) +#if defined(__aarch64__) || defined(__arm__) || defined(__i386__) || \ + defined(__i486__) || defined(__i686__) || defined(SHIM_UNIT_TEST) +typedef __builtin_va_list va_list; +#define va_copy(dest, start) __builtin_va_copy(dest, start) +#define va_start(marker, arg) __builtin_va_start(marker, arg) +#define va_arg(marker, type) __builtin_va_arg(marker, type) +#define va_end(marker) __builtin_va_end(marker) +#elif defined(__x86_64__) +typedef __builtin_ms_va_list va_list; +#define va_copy(dest, start) __builtin_ms_va_copy(dest, start) +#define va_start(marker, arg) __builtin_ms_va_start(marker, arg) +#define va_arg(marker, type) __builtin_va_arg(marker, type) +#define va_end(marker) __builtin_ms_va_end(marker) +#else +#error what arch is this +#endif -typedef __builtin_va_list elf_va_list; -#define elf_va_copy(dest, start) __builtin_va_copy(dest, start) -#define elf_va_start(marker, arg) __builtin_va_start(marker, arg) -#define elf_va_arg(marker, type) __builtin_va_arg(marker, type) -#define elf_va_end(marker) __builtin_va_end(marker) +typedef va_list VA_LIST; +#define VA_COPY(dest, start) va_copy(dest, start) +#define VA_START(marker, arg) va_start(marker, arg) +#define VA_END(marker) va_end(marker) +#define VA_ARG(marker, type) va_arg(marker, type) -#endif /* !SHIM_STDARG_H_ */ +#endif /* !_STDARG_H */ +#endif /* !SHIM_UNIT_TEST */ // vim:fenc=utf-8:tw=75:noet diff --git a/lib/Makefile b/lib/Makefile index 63893c3e..0d2d0a9d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -17,8 +17,7 @@ CLANG_BUGS = $(if $(findstring gcc,$(CC)),-maccumulate-outgoing-args,) ifeq ($(ARCH),x86_64) FEATUREFLAGS += -m64 -mno-mmx -mno-sse -mno-red-zone -nostdinc $(CLANG_BUGS) -DEFINES += -DEFI_FUNCTION_WRAPPER -DGNU_EFI_USE_MS_ABI \ - -UNO_BUILTIN_VA_FUNCS -DMDE_CPU_X64 +DEFINES += -DMDE_CPU_X64 endif ifeq ($(ARCH),ia32) FEATUREFLAGS += -m32 -mno-mmx -mno-sse -mno-red-zone -nostdinc $(CLANG_BUGS) diff --git a/lib/console.c b/lib/console.c index 32c6d55d..2da20b31 100644 --- a/lib/console.c +++ b/lib/console.c @@ -86,15 +86,15 @@ VOID console_fini(VOID) UINTN EFIAPI console_print(const CHAR16 *fmt, ...) { - elf_va_list args; + va_list args; UINTN ret; if (!console_text_mode) setup_console(1); - elf_va_start(args, fmt); + va_start(args, fmt); ret = VPrint(fmt, args); - elf_va_end(args); + va_end(args); return ret; } @@ -103,7 +103,7 @@ UINTN EFIAPI console_print_at(UINTN col, UINTN row, const CHAR16 *fmt, ...) { SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut; - elf_va_list args; + va_list args; UINTN ret; if (!console_text_mode) @@ -111,9 +111,9 @@ console_print_at(UINTN col, UINTN row, const CHAR16 *fmt, ...) co->SetCursorPosition(co, col, row); - elf_va_start(args, fmt); + va_start(args, fmt); ret = VPrint(fmt, args); - elf_va_end(args); + va_end(args); return ret; } diff --git a/shim.h b/shim.h index 3d2ac2d4..0ea182eb 100644 --- a/shim.h +++ b/shim.h @@ -17,20 +17,29 @@ #endif #if defined(__x86_64__) -#if !defined(GNU_EFI_USE_MS_ABI) -#error On x86_64 you must use ms_abi (GNU_EFI_USE_MS_ABI) in gnu-efi and shim. -#endif /* gcc 4.5.4 is the first documented release with -mabi=ms */ #if !GNUC_PREREQ(4, 7) && !CLANG_PREREQ(3, 4) #error On x86_64 you must have a compiler new enough to support __attribute__((__ms_abi__)) #endif + +#if !defined(GNU_EFI_USE_EXTERNAL_STDARG) +#define GNU_EFI_USE_EXTERNAL_STDARG +#endif + +#if !defined(GNU_EFI_USE_MS_ABI) +#define GNU_EFI_USE_MS_ABI +#endif + +#ifdef NO_BUILTIN_VA_FUNCS +#undef NO_BUILTIN_VA_FUNCS +#endif #endif #include #include #include #include -#include +#include #include #include @@ -40,6 +49,10 @@ #undef uefi_call_wrapper #include #include + +#if defined(__x86_64__) && !defined(HAVE_USE_MS_ABI) +#error something has gone wrong with the gnu-efi includes and defines +#endif #endif #ifdef SHIM_UNIT_TEST @@ -209,7 +222,7 @@ extern void shim_fini(void); extern EFI_STATUS EFIAPI LogError_(const char *file, int line, const char *func, const CHAR16 *fmt, ...); extern EFI_STATUS EFIAPI VLogError(const char *file, int line, const char *func, - const CHAR16 *fmt, elf_va_list args); + const CHAR16 *fmt, va_list args); extern VOID LogHexdump_(const char *file, int line, const char *func, const void *data, size_t sz); extern VOID PrintErrors(VOID); -- cgit v1.2.3 From 15c1a9a310645ceb958587fe000d5f60ed3bc4bd Mon Sep 17 00:00:00 2001 From: Gary Lin Date: Wed, 5 Jun 2024 15:31:04 +0800 Subject: Implement the CodeSign EKU check to fulfill the requirements of NIAP OS_PP. Also modify the ModSign EKU check to use VerifyEKUsInPkcs7Signature() to check the signer certificate instead of the certificate directly from the key database. This commit supersedes the PR#232 and PR#661 (Apply the EKU checks) so that author's original codes can be quite independent of other modification. To answer the question in PR#232, author also changed the conditional statement to EFI_Status != EFI_SUCCESS right after VerifyEKUsInPkcs7Signature() in Cryptlib/Pk/CryptPkcs7Verify.c Signed-off-by: Dennis Tseng Signed-off-by: Gary Lin --- Cryptlib/InternalCryptLib.h | 32 +++ Cryptlib/Library/BaseCryptLib.h | 40 +++ Cryptlib/Makefile | 1 + Cryptlib/Pk/CryptPkcs7Verify.c | 10 + Cryptlib/Pk/CryptPkcs7VerifyEku.c | 516 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 599 insertions(+) create mode 100644 Cryptlib/Pk/CryptPkcs7VerifyEku.c (limited to 'Cryptlib/Library') diff --git a/Cryptlib/InternalCryptLib.h b/Cryptlib/InternalCryptLib.h index dc1a95e6..b713ed1c 100644 --- a/Cryptlib/InternalCryptLib.h +++ b/Cryptlib/InternalCryptLib.h @@ -32,5 +32,37 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define OBJ_length(o) ((o)->length) #endif +/** + Check input P7Data is a wrapped ContentInfo structure or not. If not construct + a new structure to wrap P7Data. + + Caution: This function may receive untrusted input. + UEFI Authenticated Variable is external input, so this function will do basic + check for PKCS#7 data structure. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] WrapFlag If TRUE P7Data is a ContentInfo structure, otherwise + return FALSE. + @param[out] WrapData If return status of this function is TRUE: + 1) when WrapFlag is TRUE, pointer to P7Data. + 2) when WrapFlag is FALSE, pointer to a new ContentInfo + structure. It's caller's responsibility to free this + buffer. + @param[out] WrapDataSize Length of ContentInfo structure in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE The operation is failed due to lack of resources. + +**/ +BOOLEAN +WrapPkcs7Data ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT BOOLEAN *WrapFlag, + OUT UINT8 **WrapData, + OUT UINTN *WrapDataSize + ); + #endif diff --git a/Cryptlib/Library/BaseCryptLib.h b/Cryptlib/Library/BaseCryptLib.h index 2df8bd2f..ed482d3f 100644 --- a/Cryptlib/Library/BaseCryptLib.h +++ b/Cryptlib/Library/BaseCryptLib.h @@ -2403,6 +2403,46 @@ Pkcs7Verify ( IN UINTN DataLength ); +/** + This function receives a PKCS#7 formatted signature blob, + looks for the EKU SEQUENCE blob, and if found then looks + for all the required EKUs. This function was created so that + the Surface team can cut down on the number of Certificate + Authorities (CA's) by checking EKU's on leaf signers for + a specific product. This prevents one product's certificate + from signing another product's firmware or unlock blobs. + + Note that this function does not validate the certificate chain. + That needs to be done before using this function. + + @param[in] Pkcs7Signature The PKCS#7 signed information content block. An array + containing the content block with both the signature, + the signer's certificate, and any necessary intermediate + certificates. + @param[in] Pkcs7SignatureSize Number of bytes in Pkcs7Signature. + @param[in] RequiredEKUs Array of null-terminated strings listing OIDs of + required EKUs that must be present in the signature. + @param[in] RequiredEKUsSize Number of elements in the RequiredEKUs string array. + @param[in] RequireAllPresent If this is TRUE, then all of the specified EKU's + must be present in the leaf signer. If it is + FALSE, then we will succeed if we find any + of the specified EKU's. + + @retval EFI_SUCCESS The required EKUs were found in the signature. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND One or more EKU's were not found in the signature. + +**/ +EFI_STATUS +EFIAPI +VerifyEKUsInPkcs7Signature ( + IN CONST UINT8 *Pkcs7Signature, + IN CONST UINT32 SignatureSize, + IN CONST CHAR8 *RequiredEKUs[], + IN CONST UINT32 RequiredEKUsSize, + IN BOOLEAN RequireAllPresent + ); + /** Extracts the attached content from a PKCS#7 signed data if existed. The input signed data could be wrapped in a ContentInfo structure. diff --git a/Cryptlib/Makefile b/Cryptlib/Makefile index 51f4ca1d..023da637 100644 --- a/Cryptlib/Makefile +++ b/Cryptlib/Makefile @@ -60,6 +60,7 @@ OBJS = Hash/CryptMd4Null.o \ Pk/CryptRsaExtNull.o \ Pk/CryptPkcs7SignNull.o \ Pk/CryptPkcs7Verify.o \ + Pk/CryptPkcs7VerifyEku.o \ Pk/CryptDhNull.o \ Pk/CryptTs.o \ Pk/CryptX509.o \ diff --git a/Cryptlib/Pk/CryptPkcs7Verify.c b/Cryptlib/Pk/CryptPkcs7Verify.c index c1893848..fd523c59 100644 --- a/Cryptlib/Pk/CryptPkcs7Verify.c +++ b/Cryptlib/Pk/CryptPkcs7Verify.c @@ -29,6 +29,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include UINT8 mOidValue[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 }; +/* EKU CodeSign */ +CHAR8 mOidCodeSign[] = "1.3.6.1.5.5.7.3.3"; #if 1 #if OPENSSL_VERSION_NUMBER < 0x10100000L @@ -846,6 +848,8 @@ Pkcs7Verify ( CONST UINT8 *Temp; UINTN SignedDataSize; BOOLEAN Wrapped; + CONST CHAR8 *Ekus[1]; + EFI_STATUS EFI_Status; // // Check input parameters. @@ -859,6 +863,7 @@ Pkcs7Verify ( DataBio = NULL; Cert = NULL; CertStore = NULL; + Ekus[0] = mOidCodeSign; // // Register & Initialize necessary digest algorithms for PKCS#7 Handling @@ -958,6 +963,11 @@ Pkcs7Verify ( // X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY); + EFI_Status = VerifyEKUsInPkcs7Signature(P7Data, P7Length, Ekus, 1, TRUE); + if (EFI_Status != EFI_SUCCESS) { + goto _Exit; + } + // // Verifies the PKCS#7 signedData structure // diff --git a/Cryptlib/Pk/CryptPkcs7VerifyEku.c b/Cryptlib/Pk/CryptPkcs7VerifyEku.c new file mode 100644 index 00000000..f277f1dd --- /dev/null +++ b/Cryptlib/Pk/CryptPkcs7VerifyEku.c @@ -0,0 +1,516 @@ +/** @file + This module verifies that Enhanced Key Usages (EKU's) are present within + a PKCS7 signature blob using OpenSSL. + + Copyright (C) Microsoft Corporation. All Rights Reserved. + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include "InternalCryptLib.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + This function will return the leaf signer certificate in a chain. This is + required because certificate chains are not guaranteed to have the + certificates in the order that they were issued. + + A typical certificate chain looks like this: + + + ---------------------------- + | Root | + ---------------------------- + ^ + | + ---------------------------- + | Policy CA | <-- Typical Trust Anchor. + ---------------------------- + ^ + | + ---------------------------- + | Issuing CA | + ---------------------------- + ^ + | + ----------------------------- + / End-Entity (leaf) signer / <-- Bottom certificate. + ----------------------------- EKU: "1.3.6.1.4.1.311.76.9.21.1" + (Firmware Signing) + + + @param[in] CertChain Certificate chain. + + @param[out] SignerCert Last certificate in the chain. For PKCS7 signatures, + this will be the end-entity (leaf) signer cert. + + @retval EFI_SUCCESS The required EKUs were found in the signature. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND The number of signers found was not 1. + +**/ +EFI_STATUS +GetSignerCertificate ( + IN CONST PKCS7 *CertChain, + OUT X509 **SignerCert + ) +{ + EFI_STATUS Status; + STACK_OF(X509) *Signers; + INT32 NumberSigners; + + Status = EFI_SUCCESS; + Signers = NULL; + NumberSigners = 0; + + if (CertChain == NULL || SignerCert == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Get the signers from the chain. + // + Signers = PKCS7_get0_signers ((PKCS7*) CertChain, NULL, PKCS7_BINARY); + if (Signers == NULL) { + // + // Fail to get signers form PKCS7 + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // There should only be one signer in the PKCS7 stack. + // + NumberSigners = sk_X509_num (Signers); + if (NumberSigners != 1) { + // + // The number of singers should have been 1 + // + Status = EFI_NOT_FOUND; + goto Exit; + } + + *SignerCert = sk_X509_value (Signers, 0); + +Exit: + // + // Release Resources + // + if (Signers != NULL) { + sk_X509_free (Signers); + } + + return Status; +} + + +/** + Determines if the specified EKU represented in ASN1 form is present + in a given certificate. + + @param[in] Cert The certificate to check. + + @param[in] Asn1ToFind The EKU to look for. + + @retval EFI_SUCCESS We successfully identified the signing type. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND One or more EKU's were not found in the signature. + +**/ +EFI_STATUS +IsEkuInCertificate ( + IN CONST X509 *Cert, + IN ASN1_OBJECT *Asn1ToFind + ) +{ + EFI_STATUS Status; + X509 *ClonedCert; + X509_EXTENSION *Extension; + EXTENDED_KEY_USAGE *Eku; + INT32 ExtensionIndex; + INTN NumExtensions; + ASN1_OBJECT *Asn1InCert; + INTN Index; + + Status = EFI_NOT_FOUND; + ClonedCert = NULL; + Extension = NULL; + Eku = NULL; + ExtensionIndex = -1; + NumExtensions = 0; + Asn1InCert = NULL; + + if (Cert == NULL || Asn1ToFind == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Clone the certificate. This is required because the Extension API's + // only work once per instance of an X509 object. + // + ClonedCert = X509_dup ((X509*)Cert); + if (ClonedCert == NULL) { + // + // Fail to duplicate cert. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Look for the extended key usage. + // + ExtensionIndex = X509_get_ext_by_NID (ClonedCert, NID_ext_key_usage, -1); + + if (ExtensionIndex < 0) { + // + // Fail to find 'NID_ext_key_usage' in Cert. + // + goto Exit; + } + + Extension = X509_get_ext (ClonedCert, ExtensionIndex); + if (Extension == NULL) { + // + // Fail to get Extension form cert. + // + goto Exit; + } + + Eku = (EXTENDED_KEY_USAGE*)X509V3_EXT_d2i (Extension); + if (Eku == NULL) { + // + // Fail to get Eku from extension. + // + goto Exit; + } + + NumExtensions = sk_ASN1_OBJECT_num (Eku); + + // + // Now loop through the extensions, looking for the specified Eku. + // + for (Index = 0; Index < NumExtensions; Index++) { + Asn1InCert = sk_ASN1_OBJECT_value (Eku, (INT32)Index); + if (Asn1InCert == NULL) { + // + // Fail to get ASN object from Eku. + // + goto Exit; + } + + if (OBJ_cmp(Asn1InCert, Asn1ToFind) == 0) { + // + // Found Eku in certificate. + // + Status = EFI_SUCCESS; + goto Exit; + } + } + +Exit: + + // + // Release Resources + // + if (ClonedCert != NULL) { + X509_free (ClonedCert); + } + + if (Eku != NULL) { + sk_ASN1_OBJECT_pop_free (Eku, ASN1_OBJECT_free); + } + + return Status; +} + + +/** + Determines if the specified EKUs are present in a signing certificate. + + @param[in] SignerCert The certificate to check. + @param[in] RequiredEKUs The EKUs to look for. + @param[in] RequiredEKUsSize The number of EKUs + @param[in] RequireAllPresent If TRUE, then all the specified EKUs + must be present in the certificate. + + @retval EFI_SUCCESS We successfully identified the signing type. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND One or more EKU's were not found in the signature. +**/ +EFI_STATUS +CheckEKUs( + IN CONST X509 *SignerCert, + IN CONST CHAR8 *RequiredEKUs[], + IN CONST UINT32 RequiredEKUsSize, + IN BOOLEAN RequireAllPresent + ) +{ + EFI_STATUS Status; + ASN1_OBJECT *Asn1ToFind; + UINT32 NumEkusFound; + UINT32 Index; + + Status = EFI_NOT_FOUND; + Asn1ToFind = NULL; + NumEkusFound = 0; + + if (SignerCert == NULL || RequiredEKUs == NULL || RequiredEKUsSize == 0) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + for (Index = 0; Index < RequiredEKUsSize; Index++) { + // + // Finding required EKU in cert. + // + if (Asn1ToFind != NULL) { + ASN1_OBJECT_free(Asn1ToFind); + Asn1ToFind = NULL; + } + + Asn1ToFind = OBJ_txt2obj (RequiredEKUs[Index], 0); + if (Asn1ToFind == NULL) { + // + // Fail to convert required EKU to ASN1. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Status = IsEkuInCertificate (SignerCert, Asn1ToFind); + if (Status == EFI_SUCCESS) { + NumEkusFound++; + if (!RequireAllPresent) { + // + // Found at least one, so we are done. + // + goto Exit; + } + } else { + // + // Fail to find Eku in cert + break; + } + } + +Exit: + + if (Asn1ToFind != NULL) { + ASN1_OBJECT_free(Asn1ToFind); + } + + if (RequireAllPresent && + NumEkusFound == RequiredEKUsSize) { + // + // Found all required EKUs in certificate. + // + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + This function receives a PKCS#7 formatted signature blob, + looks for the EKU SEQUENCE blob, and if found then looks + for all the required EKUs. This function was created so that + the Surface team can cut down on the number of Certificate + Authorities (CA's) by checking EKU's on leaf signers for + a specific product. This prevents one product's certificate + from signing another product's firmware or unlock blobs. + + Note that this function does not validate the certificate chain. + That needs to be done before using this function. + + @param[in] Pkcs7Signature The PKCS#7 signed information content block. An array + containing the content block with both the signature, + the signer's certificate, and any necessary intermediate + certificates. + @param[in] Pkcs7SignatureSize Number of bytes in Pkcs7Signature. + @param[in] RequiredEKUs Array of null-terminated strings listing OIDs of + required EKUs that must be present in the signature. + @param[in] RequiredEKUsSize Number of elements in the RequiredEKUs string array. + @param[in] RequireAllPresent If this is TRUE, then all of the specified EKU's + must be present in the leaf signer. If it is + FALSE, then we will succeed if we find any + of the specified EKU's. + + @retval EFI_SUCCESS The required EKUs were found in the signature. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND One or more EKU's were not found in the signature. + +**/ +EFI_STATUS +EFIAPI +VerifyEKUsInPkcs7Signature ( + IN CONST UINT8 *Pkcs7Signature, + IN CONST UINT32 SignatureSize, + IN CONST CHAR8 *RequiredEKUs[], + IN CONST UINT32 RequiredEKUsSize, + IN BOOLEAN RequireAllPresent + ) +{ + EFI_STATUS Status; + PKCS7 *Pkcs7; + STACK_OF(X509) *CertChain; + INT32 SignatureType; + INT32 NumberCertsInSignature; + X509 *SignerCert; + UINT8 *SignedData; + UINT8 *Temp; + UINTN SignedDataSize; + BOOLEAN IsWrapped; + BOOLEAN Ok; + + Status = EFI_SUCCESS; + Pkcs7 = NULL; + CertChain = NULL; + SignatureType = 0; + NumberCertsInSignature = 0; + SignerCert = NULL; + SignedData = NULL; + SignedDataSize = 0; + IsWrapped = FALSE; + Ok = FALSE; + + // + //Validate the input parameters. + // + if (Pkcs7Signature == NULL || + SignatureSize == 0 || + RequiredEKUs == NULL || + RequiredEKUsSize == 0) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + if (RequiredEKUsSize == 1) { + RequireAllPresent = TRUE; + } + + // + // Wrap the PKCS7 data if needed. + // + Ok = WrapPkcs7Data (Pkcs7Signature, + SignatureSize, + &IsWrapped, + &SignedData, + &SignedDataSize); + if (!Ok) { + // + // Fail to Wrap the PKCS7 data. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Temp = SignedData; + + // + // Create the PKCS7 object. + // + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (INT32)SignedDataSize); + if (Pkcs7 == NULL) { + // + // Fail to read PKCS7 data. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Get the certificate chain. + // + SignatureType = OBJ_obj2nid (Pkcs7->type); + switch (SignatureType) { + case NID_pkcs7_signed: + if (Pkcs7->d.sign != NULL) { + CertChain = Pkcs7->d.sign->cert; + } + break; + case NID_pkcs7_signedAndEnveloped: + if (Pkcs7->d.signed_and_enveloped != NULL) { + CertChain = Pkcs7->d.signed_and_enveloped->cert; + } + break; + default: + break; + } + + // + // Ensure we have a certificate stack + // + if (CertChain == NULL) { + // + // Fail to get the certificate stack from signature. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Find out how many certificates were in the PKCS7 signature. + // + NumberCertsInSignature = sk_X509_num (CertChain); + + if (NumberCertsInSignature == 0) { + // + // Fail to find any certificates in signature. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Get the leaf signer. + // + Status = GetSignerCertificate (Pkcs7, &SignerCert); + if (Status != EFI_SUCCESS || SignerCert == NULL) { + // + // Fail to get the end-entity leaf signer certificate. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Status = CheckEKUs (SignerCert, RequiredEKUs, RequiredEKUsSize, RequireAllPresent); + if (Status != EFI_SUCCESS) { + goto Exit; + } + +Exit: + + // + // Release Resources + // + // If the signature was not wrapped, then the call to WrapData() will allocate + // the data and add a header to it + // + if (!IsWrapped && SignedData) { + free (SignedData); + } + + if (Pkcs7 != NULL) { + PKCS7_free (Pkcs7); + } + + return Status; +} + -- cgit v1.2.3 From eb02afc6f822576b73b7added3966ad7e72fd342 Mon Sep 17 00:00:00 2001 From: Dennis Tseng Date: Wed, 5 Jun 2024 22:33:06 +0800 Subject: Optionally enabling codesign EKU check in compiling time. This commit also supersedes PR#232 which was closed on Jul 1, 2021. So that original codesign EKU codes cannot be bothered. To enable the codesign check, ENABLE_CODESIGN_EKU can be set to 1. To disable the codesign check, ENABLE_CODESIGN_EKU can be set to 0 or just omit this flag. For example: make xxxx ENABLE_CODESIGN_EKU=1 xxxx shim.efi Signed-off-by: Dennis Tseng --- Cryptlib/InternalCryptLib.h | 3 ++- Cryptlib/Library/BaseCryptLib.h | 2 ++ Cryptlib/Makefile | 8 +++++++- Cryptlib/Pk/CryptPkcs7Verify.c | 8 ++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) (limited to 'Cryptlib/Library') diff --git a/Cryptlib/InternalCryptLib.h b/Cryptlib/InternalCryptLib.h index b713ed1c..0ad2ef70 100644 --- a/Cryptlib/InternalCryptLib.h +++ b/Cryptlib/InternalCryptLib.h @@ -32,6 +32,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define OBJ_length(o) ((o)->length) #endif +#if defined(ENABLE_CODESIGN_EKU) /** Check input P7Data is a wrapped ContentInfo structure or not. If not construct a new structure to wrap P7Data. @@ -65,4 +66,4 @@ WrapPkcs7Data ( ); #endif - +#endif diff --git a/Cryptlib/Library/BaseCryptLib.h b/Cryptlib/Library/BaseCryptLib.h index ed482d3f..439f0516 100644 --- a/Cryptlib/Library/BaseCryptLib.h +++ b/Cryptlib/Library/BaseCryptLib.h @@ -2403,6 +2403,7 @@ Pkcs7Verify ( IN UINTN DataLength ); +#if defined(ENABLE_CODESIGN_EKU) /** This function receives a PKCS#7 formatted signature blob, looks for the EKU SEQUENCE blob, and if found then looks @@ -2442,6 +2443,7 @@ VerifyEKUsInPkcs7Signature ( IN CONST UINT32 RequiredEKUsSize, IN BOOLEAN RequireAllPresent ); +#endif /** Extracts the attached content from a PKCS#7 signed data if existed. The input signed diff --git a/Cryptlib/Makefile b/Cryptlib/Makefile index 023da637..68a9395e 100644 --- a/Cryptlib/Makefile +++ b/Cryptlib/Makefile @@ -40,6 +40,9 @@ endif ifeq ($(ARCH),arm) DEFINES += -DMDE_CPU_ARM endif +ifeq ($(ENABLE_CODESIGN_EKU),1) +DEFINES += -DENABLE_CODESIGN_EKU +endif LDFLAGS = -nostdlib -znocombreloc @@ -60,7 +63,6 @@ OBJS = Hash/CryptMd4Null.o \ Pk/CryptRsaExtNull.o \ Pk/CryptPkcs7SignNull.o \ Pk/CryptPkcs7Verify.o \ - Pk/CryptPkcs7VerifyEku.o \ Pk/CryptDhNull.o \ Pk/CryptTs.o \ Pk/CryptX509.o \ @@ -71,6 +73,10 @@ OBJS = Hash/CryptMd4Null.o \ SysCall/BaseMemAllocation.o \ SysCall/BaseStrings.o +ifeq ($(ENABLE_CODESIGN_EKU),1) + OBJS += Pk/CryptPkcs7VerifyEku.o +endif + all: $(TARGET) libcryptlib.a: $(OBJS) diff --git a/Cryptlib/Pk/CryptPkcs7Verify.c b/Cryptlib/Pk/CryptPkcs7Verify.c index fd523c59..640b01d0 100644 --- a/Cryptlib/Pk/CryptPkcs7Verify.c +++ b/Cryptlib/Pk/CryptPkcs7Verify.c @@ -29,8 +29,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include UINT8 mOidValue[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 }; +#if defined(ENABLE_CODESIGN_EKU) /* EKU CodeSign */ CHAR8 mOidCodeSign[] = "1.3.6.1.5.5.7.3.3"; +#endif #if 1 #if OPENSSL_VERSION_NUMBER < 0x10100000L @@ -848,8 +850,10 @@ Pkcs7Verify ( CONST UINT8 *Temp; UINTN SignedDataSize; BOOLEAN Wrapped; +#if defined(ENABLE_CODESIGN_EKU) CONST CHAR8 *Ekus[1]; EFI_STATUS EFI_Status; +#endif // // Check input parameters. @@ -863,7 +867,9 @@ Pkcs7Verify ( DataBio = NULL; Cert = NULL; CertStore = NULL; +#if defined(ENABLE_CODESIGN_EKU) Ekus[0] = mOidCodeSign; +#endif // // Register & Initialize necessary digest algorithms for PKCS#7 Handling @@ -963,10 +969,12 @@ Pkcs7Verify ( // X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY); +#if defined(ENABLE_CODESIGN_EKU) EFI_Status = VerifyEKUsInPkcs7Signature(P7Data, P7Length, Ekus, 1, TRUE); if (EFI_Status != EFI_SUCCESS) { goto _Exit; } +#endif // // Verifies the PKCS#7 signedData structure -- cgit v1.2.3