mirror of
https://git.proxmox.com/git/efi-boot-shim
synced 2025-06-06 18:44:48 +00:00
Import upstream version 0.7
This commit is contained in:
parent
bfab8d6791
commit
72bb39c023
2
.gitignore
vendored
2
.gitignore
vendored
@ -22,3 +22,5 @@ shim_cert.h
|
||||
*.so
|
||||
*.srl
|
||||
*.srl.old
|
||||
*.tar.*
|
||||
version.c
|
||||
|
@ -38,7 +38,7 @@ AesGetContextSize (
|
||||
Initializes user-supplied memory as AES context for subsequent use.
|
||||
|
||||
This function initializes user-supplied memory pointed by AesContext as AES context.
|
||||
In addtion, it sets up all AES key materials for subsequent encryption and decryption
|
||||
In addition, it sets up all AES key materials for subsequent encryption and decryption
|
||||
operations.
|
||||
There are 3 options for key length, 128 bits, 192 bits, and 256 bits.
|
||||
|
||||
@ -241,7 +241,11 @@ AesCbcEncrypt (
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (AesContext == NULL || Input == NULL || (InputSize % AES_BLOCK_SIZE) != 0 || Ivec == NULL || Output == NULL) {
|
||||
if (AesContext == NULL || Input == NULL || (InputSize % AES_BLOCK_SIZE) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Ivec == NULL || Output == NULL || InputSize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -299,7 +303,11 @@ AesCbcDecrypt (
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (AesContext == NULL || Input == NULL || (InputSize % AES_BLOCK_SIZE) != 0 || Ivec == NULL || Output == NULL) {
|
||||
if (AesContext == NULL || Input == NULL || (InputSize % AES_BLOCK_SIZE) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Ivec == NULL || Output == NULL || InputSize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ Arc4GetContextSize (
|
||||
Initializes user-supplied memory as ARC4 context for subsequent use.
|
||||
|
||||
This function initializes user-supplied memory pointed by Arc4Context as ARC4 context.
|
||||
In addtion, it sets up all ARC4 key materials for subsequent encryption and decryption
|
||||
In addition, it sets up all ARC4 key materials for subsequent encryption and decryption
|
||||
operations.
|
||||
|
||||
If Arc4Context is NULL, then return FALSE.
|
||||
@ -115,7 +115,7 @@ Arc4Encrypt (
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (Arc4Context == NULL || Input == NULL || Output == NULL) {
|
||||
if (Arc4Context == NULL || Input == NULL || Output == NULL || InputSize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -161,7 +161,7 @@ Arc4Decrypt (
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (Arc4Context == NULL || Input == NULL || Output == NULL) {
|
||||
if (Arc4Context == NULL || Input == NULL || Output == NULL || InputSize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ TdesGetContextSize (
|
||||
Initializes user-supplied memory as TDES context for subsequent use.
|
||||
|
||||
This function initializes user-supplied memory pointed by TdesContext as TDES context.
|
||||
In addtion, it sets up all TDES key materials for subsequent encryption and decryption
|
||||
In addition, it sets up all TDES key materials for subsequent encryption and decryption
|
||||
operations.
|
||||
There are 3 key options as follows:
|
||||
KeyLength = 64, Keying option 1: K1 == K2 == K3 (Backward compatibility with DES)
|
||||
@ -76,9 +76,9 @@ TdesInit (
|
||||
KeySchedule = (DES_key_schedule *) TdesContext;
|
||||
|
||||
//
|
||||
// If input Key is a weak key, return error.
|
||||
//
|
||||
//
|
||||
if (DES_is_weak_key ((const_DES_cblock *) Key)) {
|
||||
if (DES_is_weak_key ((const_DES_cblock *) Key) == 1) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ TdesInit (
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (DES_is_weak_key ((const_DES_cblock *) Key + 8)) {
|
||||
if (DES_is_weak_key ((const_DES_cblock *) Key + 8) == 1) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ TdesInit (
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (DES_is_weak_key ((const_DES_cblock *) Key + 16)) {
|
||||
if (DES_is_weak_key ((const_DES_cblock *) Key + 16) == 1) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -275,7 +275,11 @@ TdesCbcEncrypt (
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (TdesContext == NULL || Input == NULL || (InputSize % TDES_BLOCK_SIZE) != 0 || Ivec == NULL || Output == NULL) {
|
||||
if (TdesContext == NULL || Input == NULL || (InputSize % TDES_BLOCK_SIZE) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Ivec == NULL || Output == NULL || InputSize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -339,7 +343,11 @@ TdesCbcDecrypt (
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (TdesContext == NULL || Input == NULL || (InputSize % TDES_BLOCK_SIZE) != 0 || Ivec == NULL || Output == NULL) {
|
||||
if (TdesContext == NULL || Input == NULL || (InputSize % TDES_BLOCK_SIZE) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Ivec == NULL || Output == NULL || InputSize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -34,3 +34,24 @@ index 805e6b4..bb7bcba 100644
|
||||
|
||||
//
|
||||
// Years Handling
|
||||
diff --git a/Cryptlib/SysCall/CrtWrapper.c b/Cryptlib/SysCall/CrtWrapper.c
|
||||
index fb446b6..5a8322d 100644
|
||||
--- a/Cryptlib/SysCall/CrtWrapper.c
|
||||
+++ b/Cryptlib/SysCall/CrtWrapper.c
|
||||
@@ -293,16 +293,6 @@ size_t fwrite (const void *buffer, size_t size, size_t count, FILE *stream)
|
||||
// -- Dummy OpenSSL Support Routines --
|
||||
//
|
||||
|
||||
-int BIO_printf (void *bio, const char *format, ...)
|
||||
-{
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-int BIO_snprintf(char *buf, size_t n, const char *format, ...)
|
||||
-{
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
void *UI_OpenSSL(void)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -58,7 +58,7 @@ HmacMd5Init (
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (HmacMd5Context == NULL) {
|
||||
if (HmacMd5Context == NULL || KeySize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ HmacSha1Init (
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (HmacSha1Context == NULL) {
|
||||
if (HmacSha1Context == NULL || KeySize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseCryptLib.h>
|
||||
|
||||
#include "OpenSslSupport.h"
|
||||
|
||||
//
|
||||
// Environment Setting for OpenSSL-based UEFI Crypto Library.
|
||||
//
|
||||
@ -28,25 +30,5 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#define OPENSSL_SYSNAME_UWIN
|
||||
#endif
|
||||
|
||||
/**
|
||||
Pop single certificate from STACK_OF(X509).
|
||||
|
||||
If X509Stack, Cert, or CertSize is NULL, then return FALSE.
|
||||
|
||||
@param[in] X509Stack Pointer to a X509 stack object.
|
||||
@param[out] Cert Pointer to a X509 certificate.
|
||||
@param[out] CertSize Length of output X509 certificate in bytes.
|
||||
|
||||
@retval TRUE The X509 stack pop succeeded.
|
||||
@retval FALSE The pop operation failed.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
X509PopCertificate (
|
||||
IN VOID *X509Stack,
|
||||
OUT UINT8 **Cert,
|
||||
OUT UINTN *CertSize
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1400,7 +1400,7 @@ RsaPkcs1Verify (
|
||||
IN VOID *RsaContext,
|
||||
IN CONST UINT8 *MessageHash,
|
||||
IN UINTN HashSize,
|
||||
IN UINT8 *Signature,
|
||||
IN CONST UINT8 *Signature,
|
||||
IN UINTN SigSize
|
||||
);
|
||||
|
||||
|
@ -27,7 +27,8 @@ OBJS = Hash/CryptMd4.o \
|
||||
Cipher/CryptTdes.o \
|
||||
Cipher/CryptArc4.o \
|
||||
Rand/CryptRand.o \
|
||||
Pk/CryptRsa.o \
|
||||
Pk/CryptRsaBasic.o \
|
||||
Pk/CryptRsaExt.o \
|
||||
Pk/CryptPkcs7.o \
|
||||
Pk/CryptDh.o \
|
||||
Pk/CryptX509.o \
|
||||
|
@ -10,7 +10,7 @@ LIB_GCC = $(shell $(CC) -print-libgcc-file-name)
|
||||
EFI_LIBS = -lefi -lgnuefi $(LIB_GCC)
|
||||
|
||||
CFLAGS = -ggdb -O0 -I. -I.. -I../Include/ -Icrypto -fno-stack-protector -fno-strict-aliasing -fpic -fshort-wchar -nostdinc -mno-mmx -mno-sse -mno-red-zone -maccumulate-outgoing-args \
|
||||
-Wall $(EFI_INCLUDES) -DOPENSSL_SYSNAME_UWIN -DOPENSSL_SYS_UEFI -DL_ENDIAN -DSIXTY_FOUR_BIT_LONG -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -DOPENSSL_NO_CAMELLIA -DOPENSSL_NO_SEED -DOPENSSL_NO_RC5 -DOPENSSL_NO_MDC2 -DOPENSSL_NO_SOCK -DOPENSSL_NO_CMS -DOPENSSL_NO_JPAKE -DOPENSSL_NO_CAPIENG -DOPENSSL_NO_ERR -DOPENSSL_NO_KRB5 -DOPENSSL_NO_DYNAMIC_ENGINE -DGETPID_IS_MEANINGLESS -DOPENSSL_NO_STDIO -DOPENSSL_NO_FP_API -DOPENSSL_NO_DGRAM -DOPENSSL_NO_SHA0 -DOPENSSL_NO_SHA512 -DOPENSSL_NO_LHASH -DOPENSSL_NO_HW -DOPENSSL_NO_OCSP -DOPENSSL_NO_LOCKING -DOPENSSL_NO_DEPRECATED -DOPENSSL_SMALL_FOOTPRINT -DPEDANTIC
|
||||
-Wall $(EFI_INCLUDES) -DOPENSSL_SYSNAME_UWIN -DOPENSSL_SYS_UEFI -DL_ENDIAN -DSIXTY_FOUR_BIT_LONG -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -DOPENSSL_NO_CAMELLIA -DOPENSSL_NO_SEED -DOPENSSL_NO_RC5 -DOPENSSL_NO_MDC2 -DOPENSSL_NO_SOCK -DOPENSSL_NO_CMS -DOPENSSL_NO_JPAKE -DOPENSSL_NO_CAPIENG -DOPENSSL_NO_ERR -DOPENSSL_NO_KRB5 -DOPENSSL_NO_DYNAMIC_ENGINE -DGETPID_IS_MEANINGLESS -DOPENSSL_NO_STDIO -DOPENSSL_NO_FP_API -DOPENSSL_NO_DGRAM -DOPENSSL_NO_SHA0 -DOPENSSL_NO_LHASH -DOPENSSL_NO_HW -DOPENSSL_NO_OCSP -DOPENSSL_NO_LOCKING -DOPENSSL_NO_DEPRECATED -DOPENSSL_SMALL_FOOTPRINT -DPEDANTIC
|
||||
ifeq ($(ARCH),x86_64)
|
||||
CFLAGS += -DEFI_FUNCTION_WRAPPER -DGNU_EFI_USE_MS_ABI
|
||||
endif
|
||||
@ -215,6 +215,7 @@ OBJS = crypto/cryptlib.o \
|
||||
crypto/bio/bf_null.o \
|
||||
crypto/bio/bf_buff.o \
|
||||
crypto/bio/b_dump.o \
|
||||
crypto/bio/b_print.o \
|
||||
crypto/bio/bf_nbio.o \
|
||||
crypto/bio/bss_log.o \
|
||||
crypto/bio/bss_bio.o \
|
||||
|
850
Cryptlib/OpenSSL/crypto/bio/b_print.c
Normal file
850
Cryptlib/OpenSSL/crypto/bio/b_print.c
Normal file
@ -0,0 +1,850 @@
|
||||
/* crypto/bio/b_print.c */
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.]
|
||||
*/
|
||||
|
||||
/* disable assert() unless BIO_DEBUG has been defined */
|
||||
#ifndef BIO_DEBUG
|
||||
# ifndef NDEBUG
|
||||
# define NDEBUG
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Stolen from tjh's ssl/ssl_trc.c stuff.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include "cryptlib.h"
|
||||
#ifndef NO_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <openssl/bn.h> /* To get BN_LLONG properly defined */
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#if defined(BN_LLONG) || defined(SIXTY_FOUR_BIT)
|
||||
# ifndef HAVE_LONG_LONG
|
||||
# define HAVE_LONG_LONG 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright Patrick Powell 1995
|
||||
* This code is based on code written by Patrick Powell <papowell@astart.com>
|
||||
* It may be used for any purpose as long as this notice remains intact
|
||||
* on all source code distributions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code contains numerious changes and enhancements which were
|
||||
* made by lots of contributors over the last years to Patrick Powell's
|
||||
* original code:
|
||||
*
|
||||
* o Patrick Powell <papowell@astart.com> (1995)
|
||||
* o Brandon Long <blong@fiction.net> (1996, for Mutt)
|
||||
* o Thomas Roessler <roessler@guug.de> (1998, for Mutt)
|
||||
* o Michael Elkins <me@cs.hmc.edu> (1998, for Mutt)
|
||||
* o Andrew Tridgell <tridge@samba.org> (1998, for Samba)
|
||||
* o Luke Mewburn <lukem@netbsd.org> (1999, for LukemFTP)
|
||||
* o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth)
|
||||
* o ... (for OpenSSL)
|
||||
*/
|
||||
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
#define LDOUBLE long double
|
||||
#else
|
||||
#define LDOUBLE double
|
||||
#endif
|
||||
|
||||
#if HAVE_LONG_LONG
|
||||
# if defined(OPENSSL_SYS_WIN32) && !defined(__GNUC__)
|
||||
# define LLONG __int64
|
||||
# else
|
||||
# define LLONG long long
|
||||
# endif
|
||||
#else
|
||||
#define LLONG long
|
||||
#endif
|
||||
|
||||
static void fmtstr (char **, char **, size_t *, size_t *,
|
||||
const char *, int, int, int);
|
||||
static void fmtint (char **, char **, size_t *, size_t *,
|
||||
LLONG, int, int, int, int);
|
||||
#ifndef OPENSSL_SYS_UEFI
|
||||
static void fmtfp (char **, char **, size_t *, size_t *,
|
||||
LDOUBLE, int, int, int);
|
||||
#endif
|
||||
static void doapr_outch (char **, char **, size_t *, size_t *, int);
|
||||
static void _dopr(char **sbuffer, char **buffer,
|
||||
size_t *maxlen, size_t *retlen, int *truncated,
|
||||
const char *format, va_list args);
|
||||
|
||||
/* format read states */
|
||||
#define DP_S_DEFAULT 0
|
||||
#define DP_S_FLAGS 1
|
||||
#define DP_S_MIN 2
|
||||
#define DP_S_DOT 3
|
||||
#define DP_S_MAX 4
|
||||
#define DP_S_MOD 5
|
||||
#define DP_S_CONV 6
|
||||
#define DP_S_DONE 7
|
||||
|
||||
/* format flags - Bits */
|
||||
#define DP_F_MINUS (1 << 0)
|
||||
#define DP_F_PLUS (1 << 1)
|
||||
#define DP_F_SPACE (1 << 2)
|
||||
#define DP_F_NUM (1 << 3)
|
||||
#define DP_F_ZERO (1 << 4)
|
||||
#define DP_F_UP (1 << 5)
|
||||
#define DP_F_UNSIGNED (1 << 6)
|
||||
|
||||
/* conversion flags */
|
||||
#define DP_C_SHORT 1
|
||||
#define DP_C_LONG 2
|
||||
#define DP_C_LDOUBLE 3
|
||||
#define DP_C_LLONG 4
|
||||
|
||||
/* some handy macros */
|
||||
#define char_to_int(p) (p - '0')
|
||||
#define OSSL_MAX(p,q) ((p >= q) ? p : q)
|
||||
|
||||
static void
|
||||
_dopr(
|
||||
char **sbuffer,
|
||||
char **buffer,
|
||||
size_t *maxlen,
|
||||
size_t *retlen,
|
||||
int *truncated,
|
||||
const char *format,
|
||||
va_list args)
|
||||
{
|
||||
char ch;
|
||||
LLONG value;
|
||||
#ifndef OPENSSL_SYS_UEFI
|
||||
LDOUBLE fvalue;
|
||||
#endif
|
||||
char *strvalue;
|
||||
int min;
|
||||
int max;
|
||||
int state;
|
||||
int flags;
|
||||
int cflags;
|
||||
size_t currlen;
|
||||
|
||||
state = DP_S_DEFAULT;
|
||||
flags = currlen = cflags = min = 0;
|
||||
max = -1;
|
||||
ch = *format++;
|
||||
|
||||
while (state != DP_S_DONE) {
|
||||
if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
|
||||
state = DP_S_DONE;
|
||||
|
||||
switch (state) {
|
||||
case DP_S_DEFAULT:
|
||||
if (ch == '%')
|
||||
state = DP_S_FLAGS;
|
||||
else
|
||||
doapr_outch(sbuffer,buffer, &currlen, maxlen, ch);
|
||||
ch = *format++;
|
||||
break;
|
||||
case DP_S_FLAGS:
|
||||
switch (ch) {
|
||||
case '-':
|
||||
flags |= DP_F_MINUS;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '+':
|
||||
flags |= DP_F_PLUS;
|
||||
ch = *format++;
|
||||
break;
|
||||
case ' ':
|
||||
flags |= DP_F_SPACE;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '#':
|
||||
flags |= DP_F_NUM;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '0':
|
||||
flags |= DP_F_ZERO;
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
state = DP_S_MIN;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DP_S_MIN:
|
||||
if (isdigit((unsigned char)ch)) {
|
||||
min = 10 * min + char_to_int(ch);
|
||||
ch = *format++;
|
||||
} else if (ch == '*') {
|
||||
min = va_arg(args, int);
|
||||
ch = *format++;
|
||||
state = DP_S_DOT;
|
||||
} else
|
||||
state = DP_S_DOT;
|
||||
break;
|
||||
case DP_S_DOT:
|
||||
if (ch == '.') {
|
||||
state = DP_S_MAX;
|
||||
ch = *format++;
|
||||
} else
|
||||
state = DP_S_MOD;
|
||||
break;
|
||||
case DP_S_MAX:
|
||||
if (isdigit((unsigned char)ch)) {
|
||||
if (max < 0)
|
||||
max = 0;
|
||||
max = 10 * max + char_to_int(ch);
|
||||
ch = *format++;
|
||||
} else if (ch == '*') {
|
||||
max = va_arg(args, int);
|
||||
ch = *format++;
|
||||
state = DP_S_MOD;
|
||||
} else
|
||||
state = DP_S_MOD;
|
||||
break;
|
||||
case DP_S_MOD:
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
cflags = DP_C_SHORT;
|
||||
ch = *format++;
|
||||
break;
|
||||
case 'l':
|
||||
if (*format == 'l') {
|
||||
cflags = DP_C_LLONG;
|
||||
format++;
|
||||
} else
|
||||
cflags = DP_C_LONG;
|
||||
ch = *format++;
|
||||
break;
|
||||
case 'q':
|
||||
cflags = DP_C_LLONG;
|
||||
ch = *format++;
|
||||
break;
|
||||
case 'L':
|
||||
cflags = DP_C_LDOUBLE;
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
state = DP_S_CONV;
|
||||
break;
|
||||
case DP_S_CONV:
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
switch (cflags) {
|
||||
case DP_C_SHORT:
|
||||
value = (short int)va_arg(args, int);
|
||||
break;
|
||||
case DP_C_LONG:
|
||||
value = va_arg(args, long int);
|
||||
break;
|
||||
case DP_C_LLONG:
|
||||
value = va_arg(args, LLONG);
|
||||
break;
|
||||
default:
|
||||
value = va_arg(args, int);
|
||||
break;
|
||||
}
|
||||
fmtint(sbuffer, buffer, &currlen, maxlen,
|
||||
value, 10, min, max, flags);
|
||||
break;
|
||||
case 'X':
|
||||
flags |= DP_F_UP;
|
||||
/* FALLTHROUGH */
|
||||
case 'x':
|
||||
case 'o':
|
||||
case 'u':
|
||||
flags |= DP_F_UNSIGNED;
|
||||
switch (cflags) {
|
||||
case DP_C_SHORT:
|
||||
value = (unsigned short int)va_arg(args, unsigned int);
|
||||
break;
|
||||
case DP_C_LONG:
|
||||
value = (LLONG) va_arg(args,
|
||||
unsigned long int);
|
||||
break;
|
||||
case DP_C_LLONG:
|
||||
value = va_arg(args, unsigned LLONG);
|
||||
break;
|
||||
default:
|
||||
value = (LLONG) va_arg(args,
|
||||
unsigned int);
|
||||
break;
|
||||
}
|
||||
fmtint(sbuffer, buffer, &currlen, maxlen, value,
|
||||
ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
|
||||
min, max, flags);
|
||||
break;
|
||||
#ifndef OPENSSL_SYS_UEFI
|
||||
case 'f':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg(args, LDOUBLE);
|
||||
else
|
||||
fvalue = va_arg(args, double);
|
||||
fmtfp(sbuffer, buffer, &currlen, maxlen,
|
||||
fvalue, min, max, flags);
|
||||
break;
|
||||
case 'E':
|
||||
flags |= DP_F_UP;
|
||||
case 'e':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg(args, LDOUBLE);
|
||||
else
|
||||
fvalue = va_arg(args, double);
|
||||
break;
|
||||
case 'G':
|
||||
flags |= DP_F_UP;
|
||||
case 'g':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg(args, LDOUBLE);
|
||||
else
|
||||
fvalue = va_arg(args, double);
|
||||
break;
|
||||
#endif
|
||||
case 'c':
|
||||
doapr_outch(sbuffer, buffer, &currlen, maxlen,
|
||||
va_arg(args, int));
|
||||
break;
|
||||
case 's':
|
||||
strvalue = va_arg(args, char *);
|
||||
if (max < 0) {
|
||||
if (buffer)
|
||||
max = INT_MAX;
|
||||
else
|
||||
max = *maxlen;
|
||||
}
|
||||
fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
|
||||
flags, min, max);
|
||||
break;
|
||||
case 'p':
|
||||
value = (long)va_arg(args, void *);
|
||||
fmtint(sbuffer, buffer, &currlen, maxlen,
|
||||
value, 16, min, max, flags|DP_F_NUM);
|
||||
break;
|
||||
case 'n': /* XXX */
|
||||
if (cflags == DP_C_SHORT) {
|
||||
short int *num;
|
||||
num = va_arg(args, short int *);
|
||||
*num = currlen;
|
||||
} else if (cflags == DP_C_LONG) { /* XXX */
|
||||
long int *num;
|
||||
num = va_arg(args, long int *);
|
||||
*num = (long int) currlen;
|
||||
} else if (cflags == DP_C_LLONG) { /* XXX */
|
||||
LLONG *num;
|
||||
num = va_arg(args, LLONG *);
|
||||
*num = (LLONG) currlen;
|
||||
} else {
|
||||
int *num;
|
||||
num = va_arg(args, int *);
|
||||
*num = currlen;
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
doapr_outch(sbuffer, buffer, &currlen, maxlen, ch);
|
||||
break;
|
||||
case 'w':
|
||||
/* not supported yet, treat as next char */
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
/* unknown, skip */
|
||||
break;
|
||||
}
|
||||
ch = *format++;
|
||||
state = DP_S_DEFAULT;
|
||||
flags = cflags = min = 0;
|
||||
max = -1;
|
||||
break;
|
||||
case DP_S_DONE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
*truncated = (currlen > *maxlen - 1);
|
||||
if (*truncated)
|
||||
currlen = *maxlen - 1;
|
||||
doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0');
|
||||
*retlen = currlen - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
fmtstr(
|
||||
char **sbuffer,
|
||||
char **buffer,
|
||||
size_t *currlen,
|
||||
size_t *maxlen,
|
||||
const char *value,
|
||||
int flags,
|
||||
int min,
|
||||
int max)
|
||||
{
|
||||
int padlen, strln;
|
||||
int cnt = 0;
|
||||
|
||||
if (value == 0)
|
||||
value = "<NULL>";
|
||||
for (strln = 0; value[strln]; ++strln)
|
||||
;
|
||||
padlen = min - strln;
|
||||
if (padlen < 0)
|
||||
padlen = 0;
|
||||
if (flags & DP_F_MINUS)
|
||||
padlen = -padlen;
|
||||
|
||||
while ((padlen > 0) && (cnt < max)) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
|
||||
--padlen;
|
||||
++cnt;
|
||||
}
|
||||
while (*value && (cnt < max)) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, *value++);
|
||||
++cnt;
|
||||
}
|
||||
while ((padlen < 0) && (cnt < max)) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
|
||||
++padlen;
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fmtint(
|
||||
char **sbuffer,
|
||||
char **buffer,
|
||||
size_t *currlen,
|
||||
size_t *maxlen,
|
||||
LLONG value,
|
||||
int base,
|
||||
int min,
|
||||
int max,
|
||||
int flags)
|
||||
{
|
||||
int signvalue = 0;
|
||||
const char *prefix = "";
|
||||
unsigned LLONG uvalue;
|
||||
char convert[DECIMAL_SIZE(value)+3];
|
||||
int place = 0;
|
||||
int spadlen = 0;
|
||||
int zpadlen = 0;
|
||||
int caps = 0;
|
||||
|
||||
if (max < 0)
|
||||
max = 0;
|
||||
uvalue = value;
|
||||
if (!(flags & DP_F_UNSIGNED)) {
|
||||
if (value < 0) {
|
||||
signvalue = '-';
|
||||
uvalue = -value;
|
||||
} else if (flags & DP_F_PLUS)
|
||||
signvalue = '+';
|
||||
else if (flags & DP_F_SPACE)
|
||||
signvalue = ' ';
|
||||
}
|
||||
if (flags & DP_F_NUM) {
|
||||
if (base == 8) prefix = "0";
|
||||
if (base == 16) prefix = "0x";
|
||||
}
|
||||
if (flags & DP_F_UP)
|
||||
caps = 1;
|
||||
do {
|
||||
convert[place++] =
|
||||
(caps ? "0123456789ABCDEF" : "0123456789abcdef")
|
||||
[uvalue % (unsigned) base];
|
||||
uvalue = (uvalue / (unsigned) base);
|
||||
} while (uvalue && (place < (int)sizeof(convert)));
|
||||
if (place == sizeof(convert))
|
||||
place--;
|
||||
convert[place] = 0;
|
||||
|
||||
zpadlen = max - place;
|
||||
spadlen = min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix);
|
||||
if (zpadlen < 0)
|
||||
zpadlen = 0;
|
||||
if (spadlen < 0)
|
||||
spadlen = 0;
|
||||
if (flags & DP_F_ZERO) {
|
||||
zpadlen = OSSL_MAX(zpadlen, spadlen);
|
||||
spadlen = 0;
|
||||
}
|
||||
if (flags & DP_F_MINUS)
|
||||
spadlen = -spadlen;
|
||||
|
||||
/* spaces */
|
||||
while (spadlen > 0) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
|
||||
--spadlen;
|
||||
}
|
||||
|
||||
/* sign */
|
||||
if (signvalue)
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
|
||||
|
||||
/* prefix */
|
||||
while (*prefix) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix);
|
||||
prefix++;
|
||||
}
|
||||
|
||||
/* zeros */
|
||||
if (zpadlen > 0) {
|
||||
while (zpadlen > 0) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
|
||||
--zpadlen;
|
||||
}
|
||||
}
|
||||
/* digits */
|
||||
while (place > 0)
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]);
|
||||
|
||||
/* left justified spaces */
|
||||
while (spadlen < 0) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
|
||||
++spadlen;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_SYS_UEFI
|
||||
static LDOUBLE
|
||||
abs_val(LDOUBLE value)
|
||||
{
|
||||
LDOUBLE result = value;
|
||||
if (value < 0)
|
||||
result = -value;
|
||||
return result;
|
||||
}
|
||||
|
||||
static LDOUBLE
|
||||
pow_10(int in_exp)
|
||||
{
|
||||
LDOUBLE result = 1;
|
||||
while (in_exp) {
|
||||
result *= 10;
|
||||
in_exp--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static long
|
||||
roundv(LDOUBLE value)
|
||||
{
|
||||
long intpart;
|
||||
intpart = (long) value;
|
||||
value = value - intpart;
|
||||
if (value >= 0.5)
|
||||
intpart++;
|
||||
return intpart;
|
||||
}
|
||||
|
||||
static void
|
||||
fmtfp(
|
||||
char **sbuffer,
|
||||
char **buffer,
|
||||
size_t *currlen,
|
||||
size_t *maxlen,
|
||||
LDOUBLE fvalue,
|
||||
int min,
|
||||
int max,
|
||||
int flags)
|
||||
{
|
||||
int signvalue = 0;
|
||||
LDOUBLE ufvalue;
|
||||
char iconvert[20];
|
||||
char fconvert[20];
|
||||
int iplace = 0;
|
||||
int fplace = 0;
|
||||
int padlen = 0;
|
||||
int zpadlen = 0;
|
||||
int caps = 0;
|
||||
long intpart;
|
||||
long fracpart;
|
||||
long max10;
|
||||
|
||||
if (max < 0)
|
||||
max = 6;
|
||||
ufvalue = abs_val(fvalue);
|
||||
if (fvalue < 0)
|
||||
signvalue = '-';
|
||||
else if (flags & DP_F_PLUS)
|
||||
signvalue = '+';
|
||||
else if (flags & DP_F_SPACE)
|
||||
signvalue = ' ';
|
||||
|
||||
intpart = (long)ufvalue;
|
||||
|
||||
/* sorry, we only support 9 digits past the decimal because of our
|
||||
conversion method */
|
||||
if (max > 9)
|
||||
max = 9;
|
||||
|
||||
/* we "cheat" by converting the fractional part to integer by
|
||||
multiplying by a factor of 10 */
|
||||
max10 = roundv(pow_10(max));
|
||||
fracpart = roundv(pow_10(max) * (ufvalue - intpart));
|
||||
|
||||
if (fracpart >= max10) {
|
||||
intpart++;
|
||||
fracpart -= max10;
|
||||
}
|
||||
|
||||
/* convert integer part */
|
||||
do {
|
||||
iconvert[iplace++] =
|
||||
(caps ? "0123456789ABCDEF"
|
||||
: "0123456789abcdef")[intpart % 10];
|
||||
intpart = (intpart / 10);
|
||||
} while (intpart && (iplace < (int)sizeof(iconvert)));
|
||||
if (iplace == sizeof iconvert)
|
||||
iplace--;
|
||||
iconvert[iplace] = 0;
|
||||
|
||||
/* convert fractional part */
|
||||
do {
|
||||
fconvert[fplace++] =
|
||||
(caps ? "0123456789ABCDEF"
|
||||
: "0123456789abcdef")[fracpart % 10];
|
||||
fracpart = (fracpart / 10);
|
||||
} while (fplace < max);
|
||||
if (fplace == sizeof fconvert)
|
||||
fplace--;
|
||||
fconvert[fplace] = 0;
|
||||
|
||||
/* -1 for decimal point, another -1 if we are printing a sign */
|
||||
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
|
||||
zpadlen = max - fplace;
|
||||
if (zpadlen < 0)
|
||||
zpadlen = 0;
|
||||
if (padlen < 0)
|
||||
padlen = 0;
|
||||
if (flags & DP_F_MINUS)
|
||||
padlen = -padlen;
|
||||
|
||||
if ((flags & DP_F_ZERO) && (padlen > 0)) {
|
||||
if (signvalue) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
|
||||
--padlen;
|
||||
signvalue = 0;
|
||||
}
|
||||
while (padlen > 0) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
|
||||
--padlen;
|
||||
}
|
||||
}
|
||||
while (padlen > 0) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
|
||||
--padlen;
|
||||
}
|
||||
if (signvalue)
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
|
||||
|
||||
while (iplace > 0)
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]);
|
||||
|
||||
/*
|
||||
* Decimal point. This should probably use locale to find the correct
|
||||
* char to print out.
|
||||
*/
|
||||
if (max > 0 || (flags & DP_F_NUM)) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, '.');
|
||||
|
||||
while (fplace > 0)
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, fconvert[--fplace]);
|
||||
}
|
||||
while (zpadlen > 0) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
|
||||
--zpadlen;
|
||||
}
|
||||
|
||||
while (padlen < 0) {
|
||||
doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
|
||||
++padlen;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
doapr_outch(
|
||||
char **sbuffer,
|
||||
char **buffer,
|
||||
size_t *currlen,
|
||||
size_t *maxlen,
|
||||
int c)
|
||||
{
|
||||
/* If we haven't at least one buffer, someone has doe a big booboo */
|
||||
assert(*sbuffer != NULL || buffer != NULL);
|
||||
|
||||
if (buffer) {
|
||||
while (*currlen >= *maxlen) {
|
||||
if (*buffer == NULL) {
|
||||
if (*maxlen == 0)
|
||||
*maxlen = 1024;
|
||||
*buffer = OPENSSL_malloc(*maxlen);
|
||||
if (*currlen > 0) {
|
||||
assert(*sbuffer != NULL);
|
||||
memcpy(*buffer, *sbuffer, *currlen);
|
||||
}
|
||||
*sbuffer = NULL;
|
||||
} else {
|
||||
*maxlen += 1024;
|
||||
*buffer = OPENSSL_realloc(*buffer, *maxlen);
|
||||
}
|
||||
}
|
||||
/* What to do if *buffer is NULL? */
|
||||
assert(*sbuffer != NULL || *buffer != NULL);
|
||||
}
|
||||
|
||||
if (*currlen < *maxlen) {
|
||||
if (*sbuffer)
|
||||
(*sbuffer)[(*currlen)++] = (char)c;
|
||||
else
|
||||
(*buffer)[(*currlen)++] = (char)c;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
int BIO_printf (BIO *bio, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
ret = BIO_vprintf(bio, format, args);
|
||||
|
||||
va_end(args);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int BIO_vprintf (BIO *bio, const char *format, va_list args)
|
||||
{
|
||||
int ret;
|
||||
size_t retlen;
|
||||
char hugebuf[1024*2]; /* Was previously 10k, which is unreasonable
|
||||
in small-stack environments, like threads
|
||||
or DOS programs. */
|
||||
char *hugebufp = hugebuf;
|
||||
size_t hugebufsize = sizeof(hugebuf);
|
||||
char *dynbuf = NULL;
|
||||
int ignored;
|
||||
|
||||
dynbuf = NULL;
|
||||
CRYPTO_push_info("doapr()");
|
||||
_dopr(&hugebufp, &dynbuf, &hugebufsize,
|
||||
&retlen, &ignored, format, args);
|
||||
if (dynbuf)
|
||||
{
|
||||
ret=BIO_write(bio, dynbuf, (int)retlen);
|
||||
OPENSSL_free(dynbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret=BIO_write(bio, hugebuf, (int)retlen);
|
||||
}
|
||||
CRYPTO_pop_info();
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/* As snprintf is not available everywhere, we provide our own implementation.
|
||||
* This function has nothing to do with BIOs, but it's closely related
|
||||
* to BIO_printf, and we need *some* name prefix ...
|
||||
* (XXX the function should be renamed, but to what?) */
|
||||
int BIO_snprintf(char *buf, size_t n, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
ret = BIO_vsnprintf(buf, n, format, args);
|
||||
|
||||
va_end(args);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
|
||||
{
|
||||
size_t retlen;
|
||||
int truncated;
|
||||
|
||||
_dopr(&buf, NULL, &n, &retlen, &truncated, format, args);
|
||||
|
||||
if (truncated)
|
||||
/* In case of truncation, return -1 like traditional snprintf.
|
||||
* (Current drafts for ISO/IEC 9899 say snprintf should return
|
||||
* the number of characters that would have been written,
|
||||
* had the buffer been large enough.) */
|
||||
return -1;
|
||||
else
|
||||
return (retlen <= INT_MAX) ? (int)retlen : -1;
|
||||
}
|
@ -176,7 +176,8 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
|
||||
STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
|
||||
PKCS7_SIGNER_INFO *si;
|
||||
X509_STORE_CTX cert_ctx;
|
||||
char buf[4096];
|
||||
char *buf = NULL;
|
||||
int bufsiz;
|
||||
int i, j=0, k, ret = 0;
|
||||
BIO *p7bio;
|
||||
BIO *tmpin, *tmpout;
|
||||
@ -287,10 +288,16 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
|
||||
BIO_set_mem_eof_return(tmpout, 0);
|
||||
} else tmpout = out;
|
||||
|
||||
bufsiz = 4096;
|
||||
buf = OPENSSL_malloc (bufsiz);
|
||||
if (buf == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* We now have to 'read' from p7bio to calculate digests etc. */
|
||||
for (;;)
|
||||
{
|
||||
i=BIO_read(p7bio,buf,sizeof(buf));
|
||||
i=BIO_read(p7bio,buf,bufsiz);
|
||||
if (i <= 0) break;
|
||||
if (tmpout) BIO_write(tmpout, buf, i);
|
||||
}
|
||||
@ -329,6 +336,10 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
|
||||
|
||||
sk_X509_free(signers);
|
||||
|
||||
if (buf != NULL) {
|
||||
OPENSSL_free (buf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/** @file
|
||||
PEM (Privacy Enhanced Mail) Format Handler Wrapper Implementation over OpenSSL.
|
||||
|
||||
Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
@ -86,27 +86,37 @@ RsaGetPrivateKeyFromPem (
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Status = FALSE;
|
||||
PemBio = NULL;
|
||||
|
||||
//
|
||||
// Add possible block-cipher descriptor for PEM data decryption.
|
||||
// NOTE: Only support most popular ciphers (3DES, AES) for the encrypted PEM.
|
||||
//
|
||||
EVP_add_cipher (EVP_des_ede3_cbc());
|
||||
EVP_add_cipher (EVP_aes_128_cbc());
|
||||
EVP_add_cipher (EVP_aes_192_cbc());
|
||||
EVP_add_cipher (EVP_aes_256_cbc());
|
||||
if (EVP_add_cipher (EVP_des_ede3_cbc ()) == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
if (EVP_add_cipher (EVP_aes_128_cbc ()) == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
if (EVP_add_cipher (EVP_aes_192_cbc ()) == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
if (EVP_add_cipher (EVP_aes_256_cbc ()) == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Status = FALSE;
|
||||
|
||||
//
|
||||
// Read encrypted PEM Data.
|
||||
//
|
||||
PemBio = BIO_new (BIO_s_mem ());
|
||||
BIO_write (PemBio, PemData, (int)PemSize);
|
||||
if (PemBio == NULL) {
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
if (BIO_write (PemBio, PemData, (int) PemSize) <= 0) {
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve RSA Private Key from encrypted PEM data.
|
||||
//
|
||||
|
@ -26,6 +26,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
|
||||
//
|
||||
// OID ASN.1 Value for SPC_INDIRECT_DATA_OBJID
|
||||
//
|
||||
UINT8 mSpcIndirectOidValue[] = {
|
||||
0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x04
|
||||
};
|
||||
|
||||
/**
|
||||
Verifies the validility of a PE/COFF Authenticode Signature as described in "Windows
|
||||
@ -70,6 +76,7 @@ AuthenticodeVerify (
|
||||
UINT8 *SpcIndirectDataContent;
|
||||
UINT8 Asn1Byte;
|
||||
UINTN ContentSize;
|
||||
UINT8 *SpcIndirectDataOid;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
@ -106,6 +113,19 @@ AuthenticodeVerify (
|
||||
// some authenticode-specific structure. Use opaque ASN.1 string to retrieve
|
||||
// PKCS#7 ContentInfo here.
|
||||
//
|
||||
SpcIndirectDataOid = (UINT8 *)(Pkcs7->d.sign->contents->type->data);
|
||||
if (CompareMem (
|
||||
SpcIndirectDataOid,
|
||||
mSpcIndirectOidValue,
|
||||
sizeof (mSpcIndirectOidValue)
|
||||
) != 0) {
|
||||
//
|
||||
// Un-matched SPC_INDIRECT_DATA_OBJID.
|
||||
//
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
|
||||
SpcIndirectDataContent = (UINT8 *)(Pkcs7->d.sign->contents->d.other->value.asn1_string->data);
|
||||
|
||||
//
|
||||
|
@ -91,7 +91,7 @@ DhGenerateParameter (
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (DhContext == NULL || Prime == NULL) {
|
||||
if (DhContext == NULL || Prime == NULL || PrimeLength > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -140,11 +140,12 @@ DhSetParameter (
|
||||
)
|
||||
{
|
||||
DH *Dh;
|
||||
BIGNUM *Bn;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (DhContext == NULL || Prime == NULL) {
|
||||
if (DhContext == NULL || Prime == NULL || PrimeLength > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -152,14 +153,46 @@ DhSetParameter (
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Dh = (DH *) DhContext;
|
||||
Dh->p = BN_new();
|
||||
Dh->g = BN_new();
|
||||
Bn = NULL;
|
||||
|
||||
BN_bin2bn (Prime, (UINT32) (PrimeLength / 8), Dh->p);
|
||||
BN_set_word (Dh->g, (UINT32) Generator);
|
||||
Dh = (DH *) DhContext;
|
||||
Dh->g = NULL;
|
||||
Dh->p = BN_new ();
|
||||
if (Dh->p == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
Dh->g = BN_new ();
|
||||
if (Dh->g == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
Bn = BN_bin2bn (Prime, (UINT32) (PrimeLength / 8), Dh->p);
|
||||
if (Bn == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
if (BN_set_word (Dh->g, (UINT32) Generator) == 0) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
Error:
|
||||
|
||||
if (Dh->p != NULL) {
|
||||
BN_free (Dh->p);
|
||||
}
|
||||
|
||||
if (Dh->g != NULL) {
|
||||
BN_free (Dh->g);
|
||||
}
|
||||
|
||||
if (Bn != NULL) {
|
||||
BN_free (Bn);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -194,6 +227,7 @@ DhGenerateKey (
|
||||
{
|
||||
BOOLEAN RetVal;
|
||||
DH *Dh;
|
||||
INTN Size;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
@ -207,12 +241,17 @@ DhGenerateKey (
|
||||
}
|
||||
|
||||
Dh = (DH *) DhContext;
|
||||
*PublicKeySize = 0;
|
||||
|
||||
RetVal = (BOOLEAN) DH_generate_key (DhContext);
|
||||
if (RetVal) {
|
||||
Size = BN_num_bytes (Dh->pub_key);
|
||||
if ((Size > 0) && (*PublicKeySize < (UINTN) Size)) {
|
||||
*PublicKeySize = Size;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BN_bn2bin (Dh->pub_key, PublicKey);
|
||||
*PublicKeySize = BN_num_bytes (Dh->pub_key);
|
||||
*PublicKeySize = Size;
|
||||
}
|
||||
|
||||
return RetVal;
|
||||
@ -227,7 +266,8 @@ DhGenerateKey (
|
||||
If DhContext is NULL, then return FALSE.
|
||||
If PeerPublicKey is NULL, then return FALSE.
|
||||
If KeySize is NULL, then return FALSE.
|
||||
If KeySize is large enough but Key is NULL, then return FALSE.
|
||||
If Key is NULL, then return FALSE.
|
||||
If KeySize is not large enough, then return FALSE.
|
||||
|
||||
@param[in, out] DhContext Pointer to the DH context.
|
||||
@param[in] PeerPublicKey Pointer to the peer's public key.
|
||||
@ -252,23 +292,37 @@ DhComputeKey (
|
||||
)
|
||||
{
|
||||
BIGNUM *Bn;
|
||||
INTN Size;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (DhContext == NULL || PeerPublicKey == NULL || KeySize == NULL) {
|
||||
if (DhContext == NULL || PeerPublicKey == NULL || KeySize == NULL || Key == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Key == NULL && *KeySize != 0) {
|
||||
if (PeerPublicKeySize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bn = BN_bin2bn (PeerPublicKey, (UINT32) PeerPublicKeySize, NULL);
|
||||
if (Bn == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*KeySize = (BOOLEAN) DH_compute_key (Key, Bn, DhContext);
|
||||
|
||||
Size = DH_compute_key (Key, Bn, DhContext);
|
||||
if (Size < 0) {
|
||||
BN_free (Bn);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (*KeySize < (UINTN) Size) {
|
||||
*KeySize = Size;
|
||||
BN_free (Bn);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*KeySize = Size;
|
||||
BN_free (Bn);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1,722 +0,0 @@
|
||||
/** @file
|
||||
RSA Asymmetric Cipher Wrapper Implementation over OpenSSL.
|
||||
|
||||
Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include "InternalCryptLib.h"
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
//
|
||||
// ASN.1 value for Hash Algorithm ID with the Distringuished Encoding Rules (DER)
|
||||
// Refer to Section 9.2 of PKCS#1 v2.1
|
||||
//
|
||||
CONST UINT8 Asn1IdMd5[] = {
|
||||
0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,
|
||||
0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10
|
||||
};
|
||||
|
||||
CONST UINT8 Asn1IdSha1[] = {
|
||||
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
|
||||
0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
|
||||
};
|
||||
|
||||
CONST UINT8 Asn1IdSha256[] = {
|
||||
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
|
||||
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
|
||||
0x00, 0x04, 0x20
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Allocates and initializes one RSA context for subsequent use.
|
||||
|
||||
@return Pointer to the RSA context that has been initialized.
|
||||
If the allocations fails, RsaNew() returns NULL.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
RsaNew (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Allocates & Initializes RSA Context by OpenSSL RSA_new()
|
||||
//
|
||||
return (VOID *)RSA_new ();
|
||||
}
|
||||
|
||||
/**
|
||||
Release the specified RSA context.
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
|
||||
@param[in] RsaContext Pointer to the RSA context to be released.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
RsaFree (
|
||||
IN VOID *RsaContext
|
||||
)
|
||||
{
|
||||
//
|
||||
// Free OpenSSL RSA Context
|
||||
//
|
||||
RSA_free ((RSA *)RsaContext);
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the tag-designated key component into the established RSA context.
|
||||
|
||||
This function sets the tag-designated RSA key component into the established
|
||||
RSA context from the user-specified non-negative integer (octet string format
|
||||
represented in RSA PKCS#1).
|
||||
If BigNumber is NULL, then the specified key componenet in RSA context is cleared.
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
|
||||
@param[in, out] RsaContext Pointer to RSA context being set.
|
||||
@param[in] KeyTag Tag of RSA key component being set.
|
||||
@param[in] BigNumber Pointer to octet integer buffer.
|
||||
If NULL, then the specified key componenet in RSA
|
||||
context is cleared.
|
||||
@param[in] BnSize Size of big number buffer in bytes.
|
||||
If BigNumber is NULL, then it is ignored.
|
||||
|
||||
@retval TRUE RSA key component was set successfully.
|
||||
@retval FALSE Invalid RSA key component tag.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaSetKey (
|
||||
IN OUT VOID *RsaContext,
|
||||
IN RSA_KEY_TAG KeyTag,
|
||||
IN CONST UINT8 *BigNumber,
|
||||
IN UINTN BnSize
|
||||
)
|
||||
{
|
||||
RSA *RsaKey;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RsaKey = (RSA *)RsaContext;
|
||||
//
|
||||
// Set RSA Key Components by converting octet string to OpenSSL BN representation.
|
||||
// NOTE: For RSA public key (used in signature verification), only public components
|
||||
// (N, e) are needed.
|
||||
//
|
||||
switch (KeyTag) {
|
||||
|
||||
//
|
||||
// RSA Public Modulus (N)
|
||||
//
|
||||
case RsaKeyN:
|
||||
if (RsaKey->n != NULL) {
|
||||
BN_free (RsaKey->n);
|
||||
}
|
||||
RsaKey->n = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->n = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->n);
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Public Exponent (e)
|
||||
//
|
||||
case RsaKeyE:
|
||||
if (RsaKey->e != NULL) {
|
||||
BN_free (RsaKey->e);
|
||||
}
|
||||
RsaKey->e = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->e = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->e);
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Private Exponent (d)
|
||||
//
|
||||
case RsaKeyD:
|
||||
if (RsaKey->d != NULL) {
|
||||
BN_free (RsaKey->d);
|
||||
}
|
||||
RsaKey->d = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->d = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->d);
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Secret Prime Factor of Modulus (p)
|
||||
//
|
||||
case RsaKeyP:
|
||||
if (RsaKey->p != NULL) {
|
||||
BN_free (RsaKey->p);
|
||||
}
|
||||
RsaKey->p = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->p = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->p);
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Secret Prime Factor of Modules (q)
|
||||
//
|
||||
case RsaKeyQ:
|
||||
if (RsaKey->q != NULL) {
|
||||
BN_free (RsaKey->q);
|
||||
}
|
||||
RsaKey->q = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->q = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->q);
|
||||
break;
|
||||
|
||||
//
|
||||
// p's CRT Exponent (== d mod (p - 1))
|
||||
//
|
||||
case RsaKeyDp:
|
||||
if (RsaKey->dmp1 != NULL) {
|
||||
BN_free (RsaKey->dmp1);
|
||||
}
|
||||
RsaKey->dmp1 = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->dmp1 = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->dmp1);
|
||||
break;
|
||||
|
||||
//
|
||||
// q's CRT Exponent (== d mod (q - 1))
|
||||
//
|
||||
case RsaKeyDq:
|
||||
if (RsaKey->dmq1 != NULL) {
|
||||
BN_free (RsaKey->dmq1);
|
||||
}
|
||||
RsaKey->dmq1 = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->dmq1 = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->dmq1);
|
||||
break;
|
||||
|
||||
//
|
||||
// The CRT Coefficient (== 1/q mod p)
|
||||
//
|
||||
case RsaKeyQInv:
|
||||
if (RsaKey->iqmp != NULL) {
|
||||
BN_free (RsaKey->iqmp);
|
||||
}
|
||||
RsaKey->iqmp = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->iqmp = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->iqmp);
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Gets the tag-designated RSA key component from the established RSA context.
|
||||
|
||||
This function retrieves the tag-designated RSA key component from the
|
||||
established RSA context as a non-negative integer (octet string format
|
||||
represented in RSA PKCS#1).
|
||||
If specified key component has not been set or has been cleared, then returned
|
||||
BnSize is set to 0.
|
||||
If the BigNumber buffer is too small to hold the contents of the key, FALSE
|
||||
is returned and BnSize is set to the required buffer size to obtain the key.
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
If BnSize is NULL, then return FALSE.
|
||||
If BnSize is large enough but BigNumber is NULL, then return FALSE.
|
||||
|
||||
@param[in, out] RsaContext Pointer to RSA context being set.
|
||||
@param[in] KeyTag Tag of RSA key component being set.
|
||||
@param[out] BigNumber Pointer to octet integer buffer.
|
||||
@param[in, out] BnSize On input, the size of big number buffer in bytes.
|
||||
On output, the size of data returned in big number buffer in bytes.
|
||||
|
||||
@retval TRUE RSA key component was retrieved successfully.
|
||||
@retval FALSE Invalid RSA key component tag.
|
||||
@retval FALSE BnSize is too small.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaGetKey (
|
||||
IN OUT VOID *RsaContext,
|
||||
IN RSA_KEY_TAG KeyTag,
|
||||
OUT UINT8 *BigNumber,
|
||||
IN OUT UINTN *BnSize
|
||||
)
|
||||
{
|
||||
RSA *RsaKey;
|
||||
BIGNUM *BnKey;
|
||||
UINTN Size;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL || BnSize == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RsaKey = (RSA *) RsaContext;
|
||||
Size = *BnSize;
|
||||
*BnSize = 0;
|
||||
|
||||
switch (KeyTag) {
|
||||
|
||||
//
|
||||
// RSA Public Modulus (N)
|
||||
//
|
||||
case RsaKeyN:
|
||||
if (RsaKey->n == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->n;
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Public Exponent (e)
|
||||
//
|
||||
case RsaKeyE:
|
||||
if (RsaKey->e == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->e;
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Private Exponent (d)
|
||||
//
|
||||
case RsaKeyD:
|
||||
if (RsaKey->d == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->d;
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Secret Prime Factor of Modulus (p)
|
||||
//
|
||||
case RsaKeyP:
|
||||
if (RsaKey->p == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->p;
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Secret Prime Factor of Modules (q)
|
||||
//
|
||||
case RsaKeyQ:
|
||||
if (RsaKey->q == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->q;
|
||||
break;
|
||||
|
||||
//
|
||||
// p's CRT Exponent (== d mod (p - 1))
|
||||
//
|
||||
case RsaKeyDp:
|
||||
if (RsaKey->dmp1 == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->dmp1;
|
||||
break;
|
||||
|
||||
//
|
||||
// q's CRT Exponent (== d mod (q - 1))
|
||||
//
|
||||
case RsaKeyDq:
|
||||
if (RsaKey->dmq1 == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->dmq1;
|
||||
break;
|
||||
|
||||
//
|
||||
// The CRT Coefficient (== 1/q mod p)
|
||||
//
|
||||
case RsaKeyQInv:
|
||||
if (RsaKey->iqmp == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->iqmp;
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*BnSize = Size;
|
||||
Size = BN_num_bytes (BnKey);
|
||||
|
||||
if (*BnSize < Size) {
|
||||
*BnSize = Size;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (BigNumber == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
*BnSize = BN_bn2bin (BnKey, BigNumber) ;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Generates RSA key components.
|
||||
|
||||
This function generates RSA key components. It takes RSA public exponent E and
|
||||
length in bits of RSA modulus N as input, and generates all key components.
|
||||
If PublicExponent is NULL, the default RSA public exponent (0x10001) will be used.
|
||||
|
||||
Before this function can be invoked, pseudorandom number generator must be correctly
|
||||
initialized by RandomSeed().
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
|
||||
@param[in, out] RsaContext Pointer to RSA context being set.
|
||||
@param[in] ModulusLength Length of RSA modulus N in bits.
|
||||
@param[in] PublicExponent Pointer to RSA public exponent.
|
||||
@param[in] PublicExponentSize Size of RSA public exponent buffer in bytes.
|
||||
|
||||
@retval TRUE RSA key component was generated successfully.
|
||||
@retval FALSE Invalid RSA key component tag.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaGenerateKey (
|
||||
IN OUT VOID *RsaContext,
|
||||
IN UINTN ModulusLength,
|
||||
IN CONST UINT8 *PublicExponent,
|
||||
IN UINTN PublicExponentSize
|
||||
)
|
||||
{
|
||||
BIGNUM *KeyE;
|
||||
BOOLEAN RetVal;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
KeyE = BN_new ();
|
||||
if (PublicExponent == NULL) {
|
||||
BN_set_word (KeyE, 0x10001);
|
||||
} else {
|
||||
BN_bin2bn (PublicExponent, (UINT32) PublicExponentSize, KeyE);
|
||||
}
|
||||
|
||||
RetVal = FALSE;
|
||||
if (RSA_generate_key_ex ((RSA *) RsaContext, (UINT32) ModulusLength, KeyE, NULL) == 1) {
|
||||
RetVal = TRUE;
|
||||
}
|
||||
|
||||
BN_free (KeyE);
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
/**
|
||||
Validates key components of RSA context.
|
||||
|
||||
This function validates key compoents of RSA context in following aspects:
|
||||
- Whether p is a prime
|
||||
- Whether q is a prime
|
||||
- Whether n = p * q
|
||||
- Whether d*e = 1 mod lcm(p-1,q-1)
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
|
||||
@param[in] RsaContext Pointer to RSA context to check.
|
||||
|
||||
@retval TRUE RSA key components are valid.
|
||||
@retval FALSE RSA key components are not valid.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaCheckKey (
|
||||
IN VOID *RsaContext
|
||||
)
|
||||
{
|
||||
UINTN Reason;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (RSA_check_key ((RSA *) RsaContext) != 1) {
|
||||
Reason = ERR_GET_REASON (ERR_peek_last_error ());
|
||||
if (Reason == RSA_R_P_NOT_PRIME ||
|
||||
Reason == RSA_R_Q_NOT_PRIME ||
|
||||
Reason == RSA_R_N_DOES_NOT_EQUAL_P_Q ||
|
||||
Reason == RSA_R_D_E_NOT_CONGRUENT_TO_1) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Performs the PKCS1-v1_5 encoding methods defined in RSA PKCS #1.
|
||||
|
||||
@param Message Message buffer to be encoded.
|
||||
@param MessageSize Size of message buffer in bytes.
|
||||
@param DigestInfo Pointer to buffer of digest info for output.
|
||||
|
||||
@return Size of DigestInfo in bytes.
|
||||
|
||||
**/
|
||||
UINTN
|
||||
DigestInfoEncoding (
|
||||
IN CONST UINT8 *Message,
|
||||
IN UINTN MessageSize,
|
||||
OUT UINT8 *DigestInfo
|
||||
)
|
||||
{
|
||||
CONST UINT8 *HashDer;
|
||||
UINTN DerSize;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (Message == NULL || DigestInfo == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// The original message length is used to determine the hash algorithm since
|
||||
// message is digest value hashed by the specified algorithm.
|
||||
//
|
||||
switch (MessageSize) {
|
||||
case MD5_DIGEST_SIZE:
|
||||
HashDer = Asn1IdMd5;
|
||||
DerSize = sizeof (Asn1IdMd5);
|
||||
break;
|
||||
|
||||
case SHA1_DIGEST_SIZE:
|
||||
HashDer = Asn1IdSha1;
|
||||
DerSize = sizeof (Asn1IdSha1);
|
||||
break;
|
||||
|
||||
case SHA256_DIGEST_SIZE:
|
||||
HashDer = Asn1IdSha256;
|
||||
DerSize = sizeof (Asn1IdSha256);
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CopyMem (DigestInfo, HashDer, DerSize);
|
||||
CopyMem (DigestInfo + DerSize, Message, MessageSize);
|
||||
|
||||
return (DerSize + MessageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
Carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme.
|
||||
|
||||
This function carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme defined in
|
||||
RSA PKCS#1.
|
||||
If the Signature buffer is too small to hold the contents of signature, FALSE
|
||||
is returned and SigSize is set to the required buffer size to obtain the signature.
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
If MessageHash is NULL, then return FALSE.
|
||||
If HashSize is not equal to the size of MD5, SHA-1 or SHA-256 digest, then return FALSE.
|
||||
If SigSize is large enough but Signature is NULL, then return FALSE.
|
||||
|
||||
@param[in] RsaContext Pointer to RSA context for signature generation.
|
||||
@param[in] MessageHash Pointer to octet message hash to be signed.
|
||||
@param[in] HashSize Size of the message hash in bytes.
|
||||
@param[out] Signature Pointer to buffer to receive RSA PKCS1-v1_5 signature.
|
||||
@param[in, out] SigSize On input, the size of Signature buffer in bytes.
|
||||
On output, the size of data returned in Signature buffer in bytes.
|
||||
|
||||
@retval TRUE Signature successfully generated in PKCS1-v1_5.
|
||||
@retval FALSE Signature generation failed.
|
||||
@retval FALSE SigSize is too small.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaPkcs1Sign (
|
||||
IN VOID *RsaContext,
|
||||
IN CONST UINT8 *MessageHash,
|
||||
IN UINTN HashSize,
|
||||
OUT UINT8 *Signature,
|
||||
IN OUT UINTN *SigSize
|
||||
)
|
||||
{
|
||||
RSA *Rsa;
|
||||
UINTN Size;
|
||||
INTN ReturnVal;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL || MessageHash == NULL ||
|
||||
(HashSize != MD5_DIGEST_SIZE && HashSize != SHA1_DIGEST_SIZE && HashSize != SHA256_DIGEST_SIZE)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Rsa = (RSA *) RsaContext;
|
||||
Size = BN_num_bytes (Rsa->n);
|
||||
|
||||
if (*SigSize < Size) {
|
||||
*SigSize = Size;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Signature == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Size = DigestInfoEncoding (MessageHash, HashSize, Signature);
|
||||
|
||||
ReturnVal = RSA_private_encrypt (
|
||||
(UINT32) Size,
|
||||
Signature,
|
||||
Signature,
|
||||
Rsa,
|
||||
RSA_PKCS1_PADDING
|
||||
);
|
||||
|
||||
if (ReturnVal < (INTN) Size) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*SigSize = (UINTN)ReturnVal;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Verifies the RSA-SSA signature with EMSA-PKCS1-v1_5 encoding scheme defined in
|
||||
RSA PKCS#1.
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
If MessageHash is NULL, then return FALSE.
|
||||
If Signature is NULL, then return FALSE.
|
||||
If HashSize is not equal to the size of MD5, SHA-1 or SHA-256 digest, then return FALSE.
|
||||
|
||||
@param[in] RsaContext Pointer to RSA context for signature verification.
|
||||
@param[in] MessageHash Pointer to octet message hash to be checked.
|
||||
@param[in] HashSize Size of the message hash in bytes.
|
||||
@param[in] Signature Pointer to RSA PKCS1-v1_5 signature to be verified.
|
||||
@param[in] SigSize Size of signature in bytes.
|
||||
|
||||
@retval TRUE Valid signature encoded in PKCS1-v1_5.
|
||||
@retval FALSE Invalid signature or invalid RSA context.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaPkcs1Verify (
|
||||
IN VOID *RsaContext,
|
||||
IN CONST UINT8 *MessageHash,
|
||||
IN UINTN HashSize,
|
||||
IN UINT8 *Signature,
|
||||
IN UINTN SigSize
|
||||
)
|
||||
{
|
||||
INTN Length;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL || MessageHash == NULL || Signature == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Check for unsupported hash size:
|
||||
// Only MD5, SHA-1 or SHA-256 digest size is supported
|
||||
//
|
||||
if (HashSize != MD5_DIGEST_SIZE && HashSize != SHA1_DIGEST_SIZE && HashSize != SHA256_DIGEST_SIZE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// RSA PKCS#1 Signature Decoding using OpenSSL RSA Decryption with Public Key
|
||||
//
|
||||
Length = RSA_public_decrypt (
|
||||
(UINT32) SigSize,
|
||||
Signature,
|
||||
Signature,
|
||||
RsaContext,
|
||||
RSA_PKCS1_PADDING
|
||||
);
|
||||
|
||||
//
|
||||
// Invalid RSA Key or PKCS#1 Padding Checking Failed (if Length < 0)
|
||||
// NOTE: Length should be the addition of HashSize and some DER value.
|
||||
// Ignore more strict length checking here.
|
||||
//
|
||||
if (Length < (INTN) HashSize) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Validate the MessageHash and Decoded Signature
|
||||
// NOTE: The decoded Signature should be the DER encoding of the DigestInfo value
|
||||
// DigestInfo ::= SEQUENCE {
|
||||
// digestAlgorithm AlgorithmIdentifier
|
||||
// digest OCTET STRING
|
||||
// }
|
||||
// Then Memory Comparing should skip the DER value of the underlying SEQUENCE
|
||||
// type and AlgorithmIdentifier.
|
||||
//
|
||||
if (CompareMem (MessageHash, Signature + Length - HashSize, HashSize) == 0) {
|
||||
//
|
||||
// Valid RSA PKCS#1 Signature
|
||||
//
|
||||
return TRUE;
|
||||
} else {
|
||||
//
|
||||
// Failed to verification
|
||||
//
|
||||
return FALSE;
|
||||
}
|
||||
}
|
335
Cryptlib/Pk/CryptRsaBasic.c
Normal file
335
Cryptlib/Pk/CryptRsaBasic.c
Normal file
@ -0,0 +1,335 @@
|
||||
/** @file
|
||||
RSA Asymmetric Cipher Wrapper Implementation over OpenSSL.
|
||||
|
||||
This file implements following APIs which provide basic capabilities for RSA:
|
||||
1) RsaNew
|
||||
2) RsaFree
|
||||
3) RsaSetKey
|
||||
4) RsaPkcs1Verify
|
||||
|
||||
Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include "InternalCryptLib.h"
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/objects.h>
|
||||
|
||||
/**
|
||||
Allocates and initializes one RSA context for subsequent use.
|
||||
|
||||
@return Pointer to the RSA context that has been initialized.
|
||||
If the allocations fails, RsaNew() returns NULL.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
RsaNew (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Allocates & Initializes RSA Context by OpenSSL RSA_new()
|
||||
//
|
||||
return (VOID *) RSA_new ();
|
||||
}
|
||||
|
||||
/**
|
||||
Release the specified RSA context.
|
||||
|
||||
@param[in] RsaContext Pointer to the RSA context to be released.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
RsaFree (
|
||||
IN VOID *RsaContext
|
||||
)
|
||||
{
|
||||
//
|
||||
// Free OpenSSL RSA Context
|
||||
//
|
||||
RSA_free ((RSA *) RsaContext);
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the tag-designated key component into the established RSA context.
|
||||
|
||||
This function sets the tag-designated RSA key component into the established
|
||||
RSA context from the user-specified non-negative integer (octet string format
|
||||
represented in RSA PKCS#1).
|
||||
If BigNumber is NULL, then the specified key componenet in RSA context is cleared.
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
|
||||
@param[in, out] RsaContext Pointer to RSA context being set.
|
||||
@param[in] KeyTag Tag of RSA key component being set.
|
||||
@param[in] BigNumber Pointer to octet integer buffer.
|
||||
If NULL, then the specified key componenet in RSA
|
||||
context is cleared.
|
||||
@param[in] BnSize Size of big number buffer in bytes.
|
||||
If BigNumber is NULL, then it is ignored.
|
||||
|
||||
@retval TRUE RSA key component was set successfully.
|
||||
@retval FALSE Invalid RSA key component tag.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaSetKey (
|
||||
IN OUT VOID *RsaContext,
|
||||
IN RSA_KEY_TAG KeyTag,
|
||||
IN CONST UINT8 *BigNumber,
|
||||
IN UINTN BnSize
|
||||
)
|
||||
{
|
||||
RSA *RsaKey;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL || BnSize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RsaKey = (RSA *) RsaContext;
|
||||
//
|
||||
// Set RSA Key Components by converting octet string to OpenSSL BN representation.
|
||||
// NOTE: For RSA public key (used in signature verification), only public components
|
||||
// (N, e) are needed.
|
||||
//
|
||||
switch (KeyTag) {
|
||||
|
||||
//
|
||||
// RSA Public Modulus (N)
|
||||
//
|
||||
case RsaKeyN:
|
||||
if (RsaKey->n != NULL) {
|
||||
BN_free (RsaKey->n);
|
||||
}
|
||||
RsaKey->n = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->n = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->n);
|
||||
if (RsaKey->n == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Public Exponent (e)
|
||||
//
|
||||
case RsaKeyE:
|
||||
if (RsaKey->e != NULL) {
|
||||
BN_free (RsaKey->e);
|
||||
}
|
||||
RsaKey->e = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->e = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->e);
|
||||
if (RsaKey->e == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Private Exponent (d)
|
||||
//
|
||||
case RsaKeyD:
|
||||
if (RsaKey->d != NULL) {
|
||||
BN_free (RsaKey->d);
|
||||
}
|
||||
RsaKey->d = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->d = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->d);
|
||||
if (RsaKey->d == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Secret Prime Factor of Modulus (p)
|
||||
//
|
||||
case RsaKeyP:
|
||||
if (RsaKey->p != NULL) {
|
||||
BN_free (RsaKey->p);
|
||||
}
|
||||
RsaKey->p = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->p = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->p);
|
||||
if (RsaKey->p == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Secret Prime Factor of Modules (q)
|
||||
//
|
||||
case RsaKeyQ:
|
||||
if (RsaKey->q != NULL) {
|
||||
BN_free (RsaKey->q);
|
||||
}
|
||||
RsaKey->q = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->q = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->q);
|
||||
if (RsaKey->q == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//
|
||||
// p's CRT Exponent (== d mod (p - 1))
|
||||
//
|
||||
case RsaKeyDp:
|
||||
if (RsaKey->dmp1 != NULL) {
|
||||
BN_free (RsaKey->dmp1);
|
||||
}
|
||||
RsaKey->dmp1 = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->dmp1 = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->dmp1);
|
||||
if (RsaKey->dmp1 == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//
|
||||
// q's CRT Exponent (== d mod (q - 1))
|
||||
//
|
||||
case RsaKeyDq:
|
||||
if (RsaKey->dmq1 != NULL) {
|
||||
BN_free (RsaKey->dmq1);
|
||||
}
|
||||
RsaKey->dmq1 = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->dmq1 = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->dmq1);
|
||||
if (RsaKey->dmq1 == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//
|
||||
// The CRT Coefficient (== 1/q mod p)
|
||||
//
|
||||
case RsaKeyQInv:
|
||||
if (RsaKey->iqmp != NULL) {
|
||||
BN_free (RsaKey->iqmp);
|
||||
}
|
||||
RsaKey->iqmp = NULL;
|
||||
if (BigNumber == NULL) {
|
||||
break;
|
||||
}
|
||||
RsaKey->iqmp = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->iqmp);
|
||||
if (RsaKey->iqmp == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Verifies the RSA-SSA signature with EMSA-PKCS1-v1_5 encoding scheme defined in
|
||||
RSA PKCS#1.
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
If MessageHash is NULL, then return FALSE.
|
||||
If Signature is NULL, then return FALSE.
|
||||
If HashSize is not equal to the size of MD5, SHA-1 or SHA-256 digest, then return FALSE.
|
||||
|
||||
@param[in] RsaContext Pointer to RSA context for signature verification.
|
||||
@param[in] MessageHash Pointer to octet message hash to be checked.
|
||||
@param[in] HashSize Size of the message hash in bytes.
|
||||
@param[in] Signature Pointer to RSA PKCS1-v1_5 signature to be verified.
|
||||
@param[in] SigSize Size of signature in bytes.
|
||||
|
||||
@retval TRUE Valid signature encoded in PKCS1-v1_5.
|
||||
@retval FALSE Invalid signature or invalid RSA context.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaPkcs1Verify (
|
||||
IN VOID *RsaContext,
|
||||
IN CONST UINT8 *MessageHash,
|
||||
IN UINTN HashSize,
|
||||
IN CONST UINT8 *Signature,
|
||||
IN UINTN SigSize
|
||||
)
|
||||
{
|
||||
INT32 DigestType;
|
||||
UINT8 *SigBuf;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL || MessageHash == NULL || Signature == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (SigSize > INT_MAX || SigSize == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Determine the message digest algorithm according to digest size.
|
||||
// Only MD5, SHA-1 or SHA-256 algorithm is supported.
|
||||
//
|
||||
switch (HashSize) {
|
||||
case MD5_DIGEST_SIZE:
|
||||
DigestType = NID_md5;
|
||||
break;
|
||||
|
||||
case SHA1_DIGEST_SIZE:
|
||||
DigestType = NID_sha1;
|
||||
break;
|
||||
|
||||
case SHA256_DIGEST_SIZE:
|
||||
DigestType = NID_sha256;
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SigBuf = (UINT8 *) Signature;
|
||||
return (BOOLEAN) RSA_verify (
|
||||
DigestType,
|
||||
MessageHash,
|
||||
(UINT32) HashSize,
|
||||
SigBuf,
|
||||
(UINT32) SigSize,
|
||||
(RSA *) RsaContext
|
||||
);
|
||||
}
|
377
Cryptlib/Pk/CryptRsaExt.c
Normal file
377
Cryptlib/Pk/CryptRsaExt.c
Normal file
@ -0,0 +1,377 @@
|
||||
/** @file
|
||||
RSA Asymmetric Cipher Wrapper Implementation over OpenSSL.
|
||||
|
||||
This file implements following APIs which provide more capabilities for RSA:
|
||||
1) RsaGetKey
|
||||
2) RsaGenerateKey
|
||||
3) RsaCheckKey
|
||||
4) RsaPkcs1Sign
|
||||
|
||||
Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include "InternalCryptLib.h"
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/objects.h>
|
||||
|
||||
/**
|
||||
Gets the tag-designated RSA key component from the established RSA context.
|
||||
|
||||
This function retrieves the tag-designated RSA key component from the
|
||||
established RSA context as a non-negative integer (octet string format
|
||||
represented in RSA PKCS#1).
|
||||
If specified key component has not been set or has been cleared, then returned
|
||||
BnSize is set to 0.
|
||||
If the BigNumber buffer is too small to hold the contents of the key, FALSE
|
||||
is returned and BnSize is set to the required buffer size to obtain the key.
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
If BnSize is NULL, then return FALSE.
|
||||
If BnSize is large enough but BigNumber is NULL, then return FALSE.
|
||||
|
||||
@param[in, out] RsaContext Pointer to RSA context being set.
|
||||
@param[in] KeyTag Tag of RSA key component being set.
|
||||
@param[out] BigNumber Pointer to octet integer buffer.
|
||||
@param[in, out] BnSize On input, the size of big number buffer in bytes.
|
||||
On output, the size of data returned in big number buffer in bytes.
|
||||
|
||||
@retval TRUE RSA key component was retrieved successfully.
|
||||
@retval FALSE Invalid RSA key component tag.
|
||||
@retval FALSE BnSize is too small.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaGetKey (
|
||||
IN OUT VOID *RsaContext,
|
||||
IN RSA_KEY_TAG KeyTag,
|
||||
OUT UINT8 *BigNumber,
|
||||
IN OUT UINTN *BnSize
|
||||
)
|
||||
{
|
||||
RSA *RsaKey;
|
||||
BIGNUM *BnKey;
|
||||
UINTN Size;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL || BnSize == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RsaKey = (RSA *) RsaContext;
|
||||
Size = *BnSize;
|
||||
*BnSize = 0;
|
||||
|
||||
switch (KeyTag) {
|
||||
|
||||
//
|
||||
// RSA Public Modulus (N)
|
||||
//
|
||||
case RsaKeyN:
|
||||
if (RsaKey->n == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->n;
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Public Exponent (e)
|
||||
//
|
||||
case RsaKeyE:
|
||||
if (RsaKey->e == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->e;
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Private Exponent (d)
|
||||
//
|
||||
case RsaKeyD:
|
||||
if (RsaKey->d == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->d;
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Secret Prime Factor of Modulus (p)
|
||||
//
|
||||
case RsaKeyP:
|
||||
if (RsaKey->p == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->p;
|
||||
break;
|
||||
|
||||
//
|
||||
// RSA Secret Prime Factor of Modules (q)
|
||||
//
|
||||
case RsaKeyQ:
|
||||
if (RsaKey->q == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->q;
|
||||
break;
|
||||
|
||||
//
|
||||
// p's CRT Exponent (== d mod (p - 1))
|
||||
//
|
||||
case RsaKeyDp:
|
||||
if (RsaKey->dmp1 == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->dmp1;
|
||||
break;
|
||||
|
||||
//
|
||||
// q's CRT Exponent (== d mod (q - 1))
|
||||
//
|
||||
case RsaKeyDq:
|
||||
if (RsaKey->dmq1 == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->dmq1;
|
||||
break;
|
||||
|
||||
//
|
||||
// The CRT Coefficient (== 1/q mod p)
|
||||
//
|
||||
case RsaKeyQInv:
|
||||
if (RsaKey->iqmp == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
BnKey = RsaKey->iqmp;
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*BnSize = Size;
|
||||
Size = BN_num_bytes (BnKey);
|
||||
|
||||
if (*BnSize < Size) {
|
||||
*BnSize = Size;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (BigNumber == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
*BnSize = BN_bn2bin (BnKey, BigNumber) ;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Generates RSA key components.
|
||||
|
||||
This function generates RSA key components. It takes RSA public exponent E and
|
||||
length in bits of RSA modulus N as input, and generates all key components.
|
||||
If PublicExponent is NULL, the default RSA public exponent (0x10001) will be used.
|
||||
|
||||
Before this function can be invoked, pseudorandom number generator must be correctly
|
||||
initialized by RandomSeed().
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
|
||||
@param[in, out] RsaContext Pointer to RSA context being set.
|
||||
@param[in] ModulusLength Length of RSA modulus N in bits.
|
||||
@param[in] PublicExponent Pointer to RSA public exponent.
|
||||
@param[in] PublicExponentSize Size of RSA public exponent buffer in bytes.
|
||||
|
||||
@retval TRUE RSA key component was generated successfully.
|
||||
@retval FALSE Invalid RSA key component tag.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaGenerateKey (
|
||||
IN OUT VOID *RsaContext,
|
||||
IN UINTN ModulusLength,
|
||||
IN CONST UINT8 *PublicExponent,
|
||||
IN UINTN PublicExponentSize
|
||||
)
|
||||
{
|
||||
BIGNUM *KeyE;
|
||||
BOOLEAN RetVal;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL || ModulusLength > INT_MAX || PublicExponentSize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
KeyE = BN_new ();
|
||||
if (KeyE == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RetVal = FALSE;
|
||||
|
||||
if (PublicExponent == NULL) {
|
||||
if (BN_set_word (KeyE, 0x10001) == 0) {
|
||||
goto _Exit;
|
||||
}
|
||||
} else {
|
||||
if (BN_bin2bn (PublicExponent, (UINT32) PublicExponentSize, KeyE) == NULL) {
|
||||
goto _Exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (RSA_generate_key_ex ((RSA *) RsaContext, (UINT32) ModulusLength, KeyE, NULL) == 1) {
|
||||
RetVal = TRUE;
|
||||
}
|
||||
|
||||
_Exit:
|
||||
BN_free (KeyE);
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
/**
|
||||
Validates key components of RSA context.
|
||||
|
||||
This function validates key compoents of RSA context in following aspects:
|
||||
- Whether p is a prime
|
||||
- Whether q is a prime
|
||||
- Whether n = p * q
|
||||
- Whether d*e = 1 mod lcm(p-1,q-1)
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
|
||||
@param[in] RsaContext Pointer to RSA context to check.
|
||||
|
||||
@retval TRUE RSA key components are valid.
|
||||
@retval FALSE RSA key components are not valid.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaCheckKey (
|
||||
IN VOID *RsaContext
|
||||
)
|
||||
{
|
||||
UINTN Reason;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (RSA_check_key ((RSA *) RsaContext) != 1) {
|
||||
Reason = ERR_GET_REASON (ERR_peek_last_error ());
|
||||
if (Reason == RSA_R_P_NOT_PRIME ||
|
||||
Reason == RSA_R_Q_NOT_PRIME ||
|
||||
Reason == RSA_R_N_DOES_NOT_EQUAL_P_Q ||
|
||||
Reason == RSA_R_D_E_NOT_CONGRUENT_TO_1) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme.
|
||||
|
||||
This function carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme defined in
|
||||
RSA PKCS#1.
|
||||
If the Signature buffer is too small to hold the contents of signature, FALSE
|
||||
is returned and SigSize is set to the required buffer size to obtain the signature.
|
||||
|
||||
If RsaContext is NULL, then return FALSE.
|
||||
If MessageHash is NULL, then return FALSE.
|
||||
If HashSize is not equal to the size of MD5, SHA-1 or SHA-256 digest, then return FALSE.
|
||||
If SigSize is large enough but Signature is NULL, then return FALSE.
|
||||
|
||||
@param[in] RsaContext Pointer to RSA context for signature generation.
|
||||
@param[in] MessageHash Pointer to octet message hash to be signed.
|
||||
@param[in] HashSize Size of the message hash in bytes.
|
||||
@param[out] Signature Pointer to buffer to receive RSA PKCS1-v1_5 signature.
|
||||
@param[in, out] SigSize On input, the size of Signature buffer in bytes.
|
||||
On output, the size of data returned in Signature buffer in bytes.
|
||||
|
||||
@retval TRUE Signature successfully generated in PKCS1-v1_5.
|
||||
@retval FALSE Signature generation failed.
|
||||
@retval FALSE SigSize is too small.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
RsaPkcs1Sign (
|
||||
IN VOID *RsaContext,
|
||||
IN CONST UINT8 *MessageHash,
|
||||
IN UINTN HashSize,
|
||||
OUT UINT8 *Signature,
|
||||
IN OUT UINTN *SigSize
|
||||
)
|
||||
{
|
||||
RSA *Rsa;
|
||||
UINTN Size;
|
||||
INT32 DigestType;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (RsaContext == NULL || MessageHash == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Rsa = (RSA *) RsaContext;
|
||||
Size = BN_num_bytes (Rsa->n);
|
||||
|
||||
if (*SigSize < Size) {
|
||||
*SigSize = Size;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Signature == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Determine the message digest algorithm according to digest size.
|
||||
// Only MD5, SHA-1 or SHA-256 algorithm is supported.
|
||||
//
|
||||
switch (HashSize) {
|
||||
case MD5_DIGEST_SIZE:
|
||||
DigestType = NID_md5;
|
||||
break;
|
||||
|
||||
case SHA1_DIGEST_SIZE:
|
||||
DigestType = NID_sha1;
|
||||
break;
|
||||
|
||||
case SHA256_DIGEST_SIZE:
|
||||
DigestType = NID_sha256;
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (BOOLEAN) RSA_sign (
|
||||
DigestType,
|
||||
MessageHash,
|
||||
(UINT32) HashSize,
|
||||
Signature,
|
||||
(UINT32 *) SigSize,
|
||||
(RSA *) RsaContext
|
||||
);
|
||||
}
|
@ -38,9 +38,7 @@ X509ConstructCertificate (
|
||||
OUT UINT8 **SingleX509Cert
|
||||
)
|
||||
{
|
||||
BIO *CertBio;
|
||||
X509 *X509Cert;
|
||||
BOOLEAN Status;
|
||||
|
||||
//
|
||||
// Check input parameters.
|
||||
@ -49,31 +47,17 @@ X509ConstructCertificate (
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Status = FALSE;
|
||||
|
||||
//
|
||||
// Read DER-encoded X509 Certificate and Construct X509 object.
|
||||
//
|
||||
CertBio = BIO_new (BIO_s_mem ());
|
||||
BIO_write (CertBio, Cert, (int) CertSize);
|
||||
if (CertBio == NULL) {
|
||||
goto _Exit;
|
||||
}
|
||||
X509Cert = d2i_X509_bio (CertBio, NULL);
|
||||
X509Cert = d2i_X509 (NULL, &Cert, (long) CertSize);
|
||||
if (X509Cert == NULL) {
|
||||
goto _Exit;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*SingleX509Cert = (UINT8 *) X509Cert;
|
||||
Status = TRUE;
|
||||
|
||||
_Exit:
|
||||
//
|
||||
// Release Resources.
|
||||
//
|
||||
BIO_free (CertBio);
|
||||
|
||||
return Status;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -224,91 +208,6 @@ X509StackFree (
|
||||
sk_X509_pop_free ((STACK_OF(X509) *) X509Stack, X509_free);
|
||||
}
|
||||
|
||||
/**
|
||||
Pop single certificate from STACK_OF(X509).
|
||||
|
||||
If X509Stack, Cert, or CertSize is NULL, then return FALSE.
|
||||
|
||||
@param[in] X509Stack Pointer to a X509 stack object.
|
||||
@param[out] Cert Pointer to a X509 certificate.
|
||||
@param[out] CertSize Length of output X509 certificate in bytes.
|
||||
|
||||
@retval TRUE The X509 stack pop succeeded.
|
||||
@retval FALSE The pop operation failed.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
X509PopCertificate (
|
||||
IN VOID *X509Stack,
|
||||
OUT UINT8 **Cert,
|
||||
OUT UINTN *CertSize
|
||||
)
|
||||
{
|
||||
BIO *CertBio;
|
||||
X509 *X509Cert;
|
||||
STACK_OF(X509) *CertStack;
|
||||
BOOLEAN Status;
|
||||
int Result;
|
||||
int Length;
|
||||
VOID *Buffer;
|
||||
|
||||
Status = FALSE;
|
||||
|
||||
if ((X509Stack == NULL) || (Cert == NULL) || (CertSize == NULL)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
CertStack = (STACK_OF(X509) *) X509Stack;
|
||||
|
||||
X509Cert = sk_X509_pop (CertStack);
|
||||
|
||||
if (X509Cert == NULL) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Buffer = NULL;
|
||||
|
||||
CertBio = BIO_new (BIO_s_mem ());
|
||||
if (CertBio == NULL) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Result = i2d_X509_bio (CertBio, X509Cert);
|
||||
if (Result == 0) {
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
Length = ((BUF_MEM *) CertBio->ptr)->length;
|
||||
if (Length <= 0) {
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
Buffer = malloc (Length);
|
||||
if (Buffer == NULL) {
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
Result = BIO_read (CertBio, Buffer, Length);
|
||||
if (Result != Length) {
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
*Cert = Buffer;
|
||||
*CertSize = Length;
|
||||
|
||||
Status = TRUE;
|
||||
|
||||
_Exit:
|
||||
|
||||
BIO_free (CertBio);
|
||||
|
||||
if (!Status && (Buffer != NULL)) {
|
||||
free (Buffer);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieve the subject bytes from one X.509 certificate.
|
||||
|
||||
@ -346,7 +245,6 @@ X509GetSubjectName (
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Status = FALSE;
|
||||
X509Cert = NULL;
|
||||
|
||||
//
|
||||
@ -354,13 +252,20 @@ X509GetSubjectName (
|
||||
//
|
||||
Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
|
||||
if ((X509Cert == NULL) || (!Status)) {
|
||||
Status = FALSE;
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
Status = FALSE;
|
||||
|
||||
//
|
||||
// Retrieve subject name from certificate object.
|
||||
//
|
||||
X509Name = X509_get_subject_name (X509Cert);
|
||||
if (X509Name == NULL) {
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
if (*SubjectSize < (UINTN) X509Name->bytes->length) {
|
||||
*SubjectSize = (UINTN) X509Name->bytes->length;
|
||||
goto _Exit;
|
||||
@ -375,7 +280,9 @@ _Exit:
|
||||
//
|
||||
// Release Resources.
|
||||
//
|
||||
if (X509Cert != NULL) {
|
||||
X509_free (X509Cert);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
@ -415,7 +322,6 @@ RsaGetPublicKeyFromX509 (
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Status = FALSE;
|
||||
Pkey = NULL;
|
||||
X509Cert = NULL;
|
||||
|
||||
@ -424,9 +330,12 @@ RsaGetPublicKeyFromX509 (
|
||||
//
|
||||
Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
|
||||
if ((X509Cert == NULL) || (!Status)) {
|
||||
Status = FALSE;
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
Status = FALSE;
|
||||
|
||||
//
|
||||
// Retrieve and check EVP_PKEY data from X509 Certificate.
|
||||
//
|
||||
@ -446,8 +355,13 @@ _Exit:
|
||||
//
|
||||
// Release Resources.
|
||||
//
|
||||
if (X509Cert != NULL) {
|
||||
X509_free (X509Cert);
|
||||
}
|
||||
|
||||
if (Pkey != NULL) {
|
||||
EVP_PKEY_free (Pkey);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
@ -498,15 +412,22 @@ X509VerifyCert (
|
||||
//
|
||||
// Register & Initialize necessary digest algorithms for certificate verification.
|
||||
//
|
||||
EVP_add_digest (EVP_md5());
|
||||
EVP_add_digest (EVP_sha1());
|
||||
EVP_add_digest (EVP_sha256());
|
||||
if (EVP_add_digest (EVP_md5 ()) == 0) {
|
||||
goto _Exit;
|
||||
}
|
||||
if (EVP_add_digest (EVP_sha1 ()) == 0) {
|
||||
goto _Exit;
|
||||
}
|
||||
if (EVP_add_digest (EVP_sha256 ()) == 0) {
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// Read DER-encoded certificate to be verified and Construct X509 object.
|
||||
//
|
||||
Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
|
||||
if ((X509Cert == NULL) || (!Status)) {
|
||||
Status = FALSE;
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
@ -515,9 +436,12 @@ X509VerifyCert (
|
||||
//
|
||||
Status = X509ConstructCertificate (CACert, CACertSize, (UINT8 **) &X509CACert);
|
||||
if ((X509CACert == NULL) || (!Status)) {
|
||||
Status = FALSE;
|
||||
goto _Exit;
|
||||
}
|
||||
|
||||
Status = FALSE;
|
||||
|
||||
//
|
||||
// Set up X509 Store for trusted certificate.
|
||||
//
|
||||
@ -546,9 +470,17 @@ _Exit:
|
||||
//
|
||||
// Release Resources.
|
||||
//
|
||||
if (X509Cert != NULL) {
|
||||
X509_free (X509Cert);
|
||||
}
|
||||
|
||||
if (X509CACert != NULL) {
|
||||
X509_free (X509CACert);
|
||||
}
|
||||
|
||||
if (CertStore != NULL) {
|
||||
X509_STORE_free (CertStore);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
@ -43,6 +43,10 @@ RandomSeed (
|
||||
IN UINTN SeedSize
|
||||
)
|
||||
{
|
||||
if (SeedSize > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Seed the pseudorandom number generator with user-supplied value.
|
||||
// NOTE: A cryptographic PRNG must be seeded with unpredictable data.
|
||||
@ -53,9 +57,13 @@ RandomSeed (
|
||||
RAND_seed (DefaultSeed, sizeof (DefaultSeed));
|
||||
}
|
||||
|
||||
if (RAND_status () == 1) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
Generates a pseudorandom byte stream of the specified size.
|
||||
|
||||
@ -78,7 +86,7 @@ RandomBytes (
|
||||
//
|
||||
// Check input parameters.
|
||||
//
|
||||
if (Output == NULL) {
|
||||
if (Output == NULL || Size > INT_MAX) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
Base Memory Allocation Routines Wrapper for Crypto library over OpenSSL
|
||||
during PEI & DXE phases.
|
||||
|
||||
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
|
@ -293,16 +293,6 @@ size_t fwrite (const void *buffer, size_t size, size_t count, FILE *stream)
|
||||
// -- Dummy OpenSSL Support Routines --
|
||||
//
|
||||
|
||||
int BIO_printf (void *bio, const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BIO_snprintf(char *buf, size_t n, const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *UI_OpenSSL(void)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -146,14 +146,14 @@ struct tm * gmtime (const time_t *timer)
|
||||
GmTime->tm_yday = (int) DayNo;
|
||||
|
||||
for (MonthNo = 12; MonthNo > 1; MonthNo--) {
|
||||
if (DayNo > CumulativeDays[IsLeap(Year)][MonthNo]) {
|
||||
if (DayNo >= CumulativeDays[IsLeap(Year)][MonthNo]) {
|
||||
DayNo = (UINT16) (DayNo - (UINT16) (CumulativeDays[IsLeap(Year)][MonthNo]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GmTime->tm_mon = (int) MonthNo;
|
||||
GmTime->tm_mday = (int) DayNo;
|
||||
GmTime->tm_mon = (int) MonthNo - 1;
|
||||
GmTime->tm_mday = (int) DayNo + 1;
|
||||
|
||||
GmTime->tm_isdst = 0;
|
||||
GmTime->tm_gmtoff = 0;
|
||||
|
60
Makefile
60
Makefile
@ -1,12 +1,12 @@
|
||||
ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)
|
||||
|
||||
SUBDIRS = Cryptlib
|
||||
SUBDIRS = Cryptlib lib
|
||||
|
||||
LIB_PATH = /usr/lib64
|
||||
|
||||
EFI_INCLUDE = /usr/include/efi
|
||||
EFI_INCLUDES = -nostdinc -ICryptlib -ICryptlib/Include -I$(EFI_INCLUDE) -I$(EFI_INCLUDE)/$(ARCH) -I$(EFI_INCLUDE)/protocol
|
||||
EFI_PATH = /usr/lib64/gnuefi
|
||||
EFI_INCLUDES = -nostdinc -ICryptlib -ICryptlib/Include -I$(EFI_INCLUDE) -I$(EFI_INCLUDE)/$(ARCH) -I$(EFI_INCLUDE)/protocol -Iinclude
|
||||
EFI_PATH := /usr/lib64/gnuefi
|
||||
|
||||
LIB_GCC = $(shell $(CC) -print-libgcc-file-name)
|
||||
EFI_LIBS = -lefi -lgnuefi --start-group Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a --end-group $(LIB_GCC)
|
||||
@ -14,10 +14,17 @@ EFI_LIBS = -lefi -lgnuefi --start-group Cryptlib/libcryptlib.a Cryptlib/OpenSSL/
|
||||
EFI_CRT_OBJS = $(EFI_PATH)/crt0-efi-$(ARCH).o
|
||||
EFI_LDS = elf_$(ARCH)_efi.lds
|
||||
|
||||
DEFAULT_LOADER := \\\\grub.efi
|
||||
CFLAGS = -ggdb -O0 -fno-stack-protector -fno-strict-aliasing -fpic \
|
||||
-fshort-wchar -Wall -mno-red-zone -maccumulate-outgoing-args \
|
||||
-mno-mmx -mno-sse \
|
||||
-fshort-wchar -Wall -Werror -mno-red-zone -maccumulate-outgoing-args \
|
||||
-mno-mmx -mno-sse -fno-builtin \
|
||||
"-DDEFAULT_LOADER=L\"$(DEFAULT_LOADER)\"" \
|
||||
"-DDEFAULT_LOADER_CHAR=\"$(DEFAULT_LOADER)\"" \
|
||||
$(EFI_INCLUDES)
|
||||
|
||||
ifneq ($(origin OVERRIDE_SECURITY_POLICY), undefined)
|
||||
CFLAGS += -DOVERRIDE_SECURITY_POLICY
|
||||
endif
|
||||
ifeq ($(ARCH),x86_64)
|
||||
CFLAGS += -DEFI_FUNCTION_WRAPPER -DGNU_EFI_USE_MS_ABI
|
||||
endif
|
||||
@ -30,14 +37,14 @@ endif
|
||||
|
||||
LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(EFI_PATH) -L$(LIB_PATH) -LCryptlib -LCryptlib/OpenSSL $(EFI_CRT_OBJS)
|
||||
|
||||
VERSION = 0.4
|
||||
VERSION = 0.7
|
||||
|
||||
TARGET = shim.efi MokManager.efi.signed fallback.efi.signed
|
||||
OBJS = shim.o netboot.o cert.o dbx.o
|
||||
KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key
|
||||
SOURCES = shim.c shim.h netboot.c signature.h PeImage.h
|
||||
MOK_OBJS = MokManager.o
|
||||
MOK_SOURCES = MokManager.c shim.h
|
||||
OBJS = shim.o netboot.o cert.o replacements.o version.o
|
||||
KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer
|
||||
SOURCES = shim.c shim.h netboot.c include/PeImage.h include/wincert.h include/console.h replacements.c replacements.h version.c version.h
|
||||
MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o
|
||||
MOK_SOURCES = MokManager.c shim.h include/console.h PasswordCrypt.c PasswordCrypt.h crypt_blowfish.c crypt_blowfish.h
|
||||
FALLBACK_OBJS = fallback.o
|
||||
FALLBACK_SRCS = fallback.c
|
||||
|
||||
@ -54,6 +61,12 @@ shim_cert.h: shim.cer
|
||||
hexdump -v -e '1/1 "0x%02x, "' $< >> $@
|
||||
echo "};" >> $@
|
||||
|
||||
version.c : version.c.in
|
||||
sed -e "s,@@VERSION@@,$(VERSION)," \
|
||||
-e "s,@@UNAME@@,$(shell uname -a)," \
|
||||
-e "s,@@COMMIT@@,$(shell if [ -d .git ] ; then git log -1 --pretty=format:%H ; elif [ -f commit ]; then cat commit ; else echo commit id not available; fi)," \
|
||||
< version.c.in > version.c
|
||||
|
||||
certdb/secmod.db: shim.crt
|
||||
-mkdir certdb
|
||||
certutil -A -n 'my CA' -d certdb/ -t CT,CT,CT -i ca.crt
|
||||
@ -65,10 +78,7 @@ shim.o: $(SOURCES) shim_cert.h
|
||||
cert.o : cert.S
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
dbx.o : dbx.S
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
shim.so: $(OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a
|
||||
shim.so: $(OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
|
||||
$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS)
|
||||
|
||||
fallback.o: $(FALLBACK_SRCS)
|
||||
@ -76,10 +86,10 @@ fallback.o: $(FALLBACK_SRCS)
|
||||
fallback.so: $(FALLBACK_OBJS)
|
||||
$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS)
|
||||
|
||||
MokManager.o: $(SOURCES)
|
||||
MokManager.o: $(MOK_SOURCES)
|
||||
|
||||
MokManager.so: $(MOK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a
|
||||
$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS)
|
||||
MokManager.so: $(MOK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
|
||||
$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS) lib/lib.a
|
||||
|
||||
Cryptlib/libcryptlib.a:
|
||||
$(MAKE) -C Cryptlib
|
||||
@ -87,6 +97,9 @@ Cryptlib/libcryptlib.a:
|
||||
Cryptlib/OpenSSL/libopenssl.a:
|
||||
$(MAKE) -C Cryptlib/OpenSSL
|
||||
|
||||
lib/lib.a:
|
||||
$(MAKE) -C lib EFI_PATH=$(EFI_PATH)
|
||||
|
||||
%.efi: %.so
|
||||
objcopy -j .text -j .sdata -j .data \
|
||||
-j .dynamic -j .dynsym -j .rel \
|
||||
@ -106,8 +119,9 @@ Cryptlib/OpenSSL/libopenssl.a:
|
||||
clean:
|
||||
$(MAKE) -C Cryptlib clean
|
||||
$(MAKE) -C Cryptlib/OpenSSL clean
|
||||
$(MAKE) -C lib clean
|
||||
rm -rf $(TARGET) $(OBJS) $(MOK_OBJS) $(FALLBACK_OBJS) $(KEYS) certdb
|
||||
rm -f *.debug *.so *.efi
|
||||
rm -f *.debug *.so *.efi *.tar.* version.c
|
||||
|
||||
GITTAG = $(VERSION)
|
||||
|
||||
@ -117,16 +131,20 @@ test-archive:
|
||||
@git archive --format=tar $(shell git branch | awk '/^*/ { print $$2 }') | ( cd /tmp/shim-$(VERSION)-tmp/ ; tar x )
|
||||
@git diff | ( cd /tmp/shim-$(VERSION)-tmp/ ; patch -s -p1 -b -z .gitdiff )
|
||||
@mv /tmp/shim-$(VERSION)-tmp/ /tmp/shim-$(VERSION)/
|
||||
@git log -1 --pretty=format:%H > /tmp/shim-$(VERSION)/commit
|
||||
@dir=$$PWD; cd /tmp; tar -c --bzip2 -f $$dir/shim-$(VERSION).tar.bz2 shim-$(VERSION)
|
||||
@rm -rf /tmp/shim-$(VERSION)
|
||||
@echo "The archive is in shim-$(VERSION).tar.bz2"
|
||||
|
||||
archive:
|
||||
git tag $(GITTAG) refs/heads/master
|
||||
tag:
|
||||
git tag --sign $(GITTAG) refs/heads/master
|
||||
|
||||
archive: tag
|
||||
@rm -rf /tmp/shim-$(VERSION) /tmp/shim-$(VERSION)-tmp
|
||||
@mkdir -p /tmp/shim-$(VERSION)-tmp
|
||||
@git archive --format=tar $(GITTAG) | ( cd /tmp/shim-$(VERSION)-tmp/ ; tar x )
|
||||
@mv /tmp/shim-$(VERSION)-tmp/ /tmp/shim-$(VERSION)/
|
||||
@git log -1 --pretty=format:%H > /tmp/shim-$(VERSION)/commit
|
||||
@dir=$$PWD; cd /tmp; tar -c --bzip2 -f $$dir/shim-$(VERSION).tar.bz2 shim-$(VERSION)
|
||||
@rm -rf /tmp/shim-$(VERSION)
|
||||
@echo "The archive is in shim-$(VERSION).tar.bz2"
|
||||
|
1957
MokManager.c
1957
MokManager.c
File diff suppressed because it is too large
Load Diff
23
MokVars.txt
23
MokVars.txt
@ -25,6 +25,23 @@ three randomly chosen characters from the password. If successful,
|
||||
they will then be prompted to change the signature validation
|
||||
according to MokSBState. BS,RT,NV
|
||||
|
||||
MokDB: Set by MokUtil when requesting a change in state of validation
|
||||
using db hashes and certs. A packed structure as follows:
|
||||
|
||||
typedef struct {
|
||||
UINT32 MokDBState;
|
||||
UINT32 PWLen;
|
||||
CHAR16 Password[PASSWORD_MAX];
|
||||
} __attribute__ ((packed)) MokDBvar;
|
||||
|
||||
If MokDBState is 0, the user will be prompted to disable usage of db for
|
||||
validation. Otherwise, the user will be prompted to allow it. PWLen
|
||||
is the length of the password, in characters. Password is a UCS-2
|
||||
representation of the password. The user will be prompted to enter
|
||||
three randomly chosen characters from the password. If successful,
|
||||
they will then be prompted to change the signature validation
|
||||
according to MokDBState. BS,RT,NV
|
||||
|
||||
MokNew: Set by MokUtil when requesting the addition or removal of keys
|
||||
from MokList. Is an EFI_SIGNATURE_LIST as described in the UEFI
|
||||
specification. BS,RT,NV
|
||||
@ -46,6 +63,12 @@ MokListRT: A copy of MokList made available to the kernel at runtime. RT
|
||||
MokSBState: An 8-bit unsigned integer. If 1, shim will switch to
|
||||
insecure mode. BS,NV
|
||||
|
||||
MokDBState: An 8-bit unsigned integer. If 1, shim will not use db for
|
||||
verification. BS,NV
|
||||
|
||||
MokIgnoreDB: An 8-bit unsigned integer. This allows the OS to query whether
|
||||
or not to import DB certs for its own verification purposes.
|
||||
|
||||
MokPWStore: A SHA-256 representation of the password set by the user
|
||||
via MokPW. The user will be prompted to enter this password in order
|
||||
to interact with MokManager.
|
||||
|
342
PasswordCrypt.c
Normal file
342
PasswordCrypt.c
Normal file
@ -0,0 +1,342 @@
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
#include <Library/BaseCryptLib.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/des.h>
|
||||
#include "PasswordCrypt.h"
|
||||
#include "crypt_blowfish.h"
|
||||
|
||||
#define TRAD_DES_HASH_SIZE 13 /* (64/6+1) + (12/6) */
|
||||
#define BSDI_DES_HASH_SIZE 20 /* (64/6+1) + (24/6) + 4 + 1 */
|
||||
#define BLOWFISH_HASH_SIZE 31 /* 184/6+1 */
|
||||
|
||||
UINT16 get_hash_size (const UINT16 method)
|
||||
{
|
||||
switch (method) {
|
||||
case TRADITIONAL_DES:
|
||||
return TRAD_DES_HASH_SIZE;
|
||||
case EXTEND_BSDI_DES:
|
||||
return BSDI_DES_HASH_SIZE;
|
||||
case MD5_BASED:
|
||||
return MD5_DIGEST_LENGTH;
|
||||
case SHA256_BASED:
|
||||
return SHA256_DIGEST_LENGTH;
|
||||
case SHA512_BASED:
|
||||
return SHA512_DIGEST_LENGTH;
|
||||
case BLOWFISH_BASED:
|
||||
return BLOWFISH_HASH_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static EFI_STATUS trad_des_crypt (const char *key, const char *salt, UINT8 *hash)
|
||||
{
|
||||
char result[TRAD_DES_HASH_SIZE + 1];
|
||||
char *ret;
|
||||
|
||||
ret = DES_fcrypt(key, salt, result);
|
||||
if (ret) {
|
||||
CopyMem(hash, result, TRAD_DES_HASH_SIZE);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static const char md5_salt_prefix[] = "$1$";
|
||||
|
||||
static EFI_STATUS md5_crypt (const char *key, UINT32 key_len,
|
||||
const char *salt, UINT32 salt_size,
|
||||
UINT8 *hash)
|
||||
{
|
||||
MD5_CTX ctx, alt_ctx;
|
||||
UINT8 alt_result[MD5_DIGEST_LENGTH];
|
||||
UINTN cnt;
|
||||
|
||||
MD5_Init(&ctx);
|
||||
MD5_Update(&ctx, key, key_len);
|
||||
MD5_Update(&ctx, md5_salt_prefix, sizeof(md5_salt_prefix) - 1);
|
||||
MD5_Update(&ctx, salt, salt_size);
|
||||
|
||||
MD5_Init(&alt_ctx);
|
||||
MD5_Update(&alt_ctx, key, key_len);
|
||||
MD5_Update(&alt_ctx, salt, salt_size);
|
||||
MD5_Update(&alt_ctx, key, key_len);
|
||||
MD5_Final(alt_result, &alt_ctx);
|
||||
|
||||
for (cnt = key_len; cnt > 16; cnt -= 16)
|
||||
MD5_Update(&ctx, alt_result, 16);
|
||||
MD5_Update(&ctx, alt_result, cnt);
|
||||
|
||||
*alt_result = '\0';
|
||||
|
||||
for (cnt = key_len; cnt > 0; cnt >>= 1) {
|
||||
if ((cnt & 1) != 0) {
|
||||
MD5_Update(&ctx, alt_result, 1);
|
||||
} else {
|
||||
MD5_Update(&ctx, key, 1);
|
||||
}
|
||||
}
|
||||
MD5_Final(alt_result, &ctx);
|
||||
|
||||
for (cnt = 0; cnt < 1000; ++cnt) {
|
||||
MD5_Init(&ctx);
|
||||
|
||||
if ((cnt & 1) != 0)
|
||||
MD5_Update(&ctx, key, key_len);
|
||||
else
|
||||
MD5_Update(&ctx, alt_result, 16);
|
||||
|
||||
if (cnt % 3 != 0)
|
||||
MD5_Update(&ctx, salt, salt_size);
|
||||
|
||||
if (cnt % 7 != 0)
|
||||
MD5_Update(&ctx, key, key_len);
|
||||
|
||||
if ((cnt & 1) != 0)
|
||||
MD5_Update(&ctx, alt_result, 16);
|
||||
else
|
||||
MD5_Update(&ctx, key, key_len);
|
||||
|
||||
MD5_Final(alt_result, &ctx);
|
||||
}
|
||||
|
||||
CopyMem(hash, alt_result, MD5_DIGEST_LENGTH);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static EFI_STATUS sha256_crypt (const char *key, UINT32 key_len,
|
||||
const char *salt, UINT32 salt_size,
|
||||
const UINT32 rounds, UINT8 *hash)
|
||||
{
|
||||
SHA256_CTX ctx, alt_ctx;
|
||||
UINT8 alt_result[SHA256_DIGEST_SIZE];
|
||||
UINT8 tmp_result[SHA256_DIGEST_SIZE];
|
||||
UINT8 *cp, *p_bytes, *s_bytes;
|
||||
UINTN cnt;
|
||||
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, key, key_len);
|
||||
SHA256_Update(&ctx, salt, salt_size);
|
||||
|
||||
SHA256_Init(&alt_ctx);
|
||||
SHA256_Update(&alt_ctx, key, key_len);
|
||||
SHA256_Update(&alt_ctx, salt, salt_size);
|
||||
SHA256_Update(&alt_ctx, key, key_len);
|
||||
SHA256_Final(alt_result, &alt_ctx);
|
||||
|
||||
for (cnt = key_len; cnt > 32; cnt -= 32)
|
||||
SHA256_Update(&ctx, alt_result, 32);
|
||||
SHA256_Update(&ctx, alt_result, cnt);
|
||||
|
||||
for (cnt = key_len; cnt > 0; cnt >>= 1) {
|
||||
if ((cnt & 1) != 0) {
|
||||
SHA256_Update(&ctx, alt_result, 32);
|
||||
} else {
|
||||
SHA256_Update(&ctx, key, key_len);
|
||||
}
|
||||
}
|
||||
SHA256_Final(alt_result, &ctx);
|
||||
|
||||
SHA256_Init(&alt_ctx);
|
||||
for (cnt = 0; cnt < key_len; ++cnt)
|
||||
SHA256_Update(&alt_ctx, key, key_len);
|
||||
SHA256_Final(tmp_result, &alt_ctx);
|
||||
|
||||
cp = p_bytes = AllocatePool(key_len);
|
||||
for (cnt = key_len; cnt >= 32; cnt -= 32) {
|
||||
CopyMem(cp, tmp_result, 32);
|
||||
cp += 32;
|
||||
}
|
||||
CopyMem(cp, tmp_result, cnt);
|
||||
|
||||
SHA256_Init(&alt_ctx);
|
||||
for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
|
||||
SHA256_Update(&alt_ctx, salt, salt_size);
|
||||
SHA256_Final(tmp_result, &alt_ctx);
|
||||
|
||||
cp = s_bytes = AllocatePool(salt_size);
|
||||
for (cnt = salt_size; cnt >= 32; cnt -= 32) {
|
||||
CopyMem(cp, tmp_result, 32);
|
||||
cp += 32;
|
||||
}
|
||||
CopyMem(cp, tmp_result, cnt);
|
||||
|
||||
for (cnt = 0; cnt < rounds; ++cnt) {
|
||||
SHA256_Init(&ctx);
|
||||
|
||||
if ((cnt & 1) != 0)
|
||||
SHA256_Update(&ctx, p_bytes, key_len);
|
||||
else
|
||||
SHA256_Update(&ctx, alt_result, 32);
|
||||
|
||||
if (cnt % 3 != 0)
|
||||
SHA256_Update(&ctx, s_bytes, salt_size);
|
||||
|
||||
if (cnt % 7 != 0)
|
||||
SHA256_Update(&ctx, p_bytes, key_len);
|
||||
|
||||
if ((cnt & 1) != 0)
|
||||
SHA256_Update(&ctx, alt_result, 32);
|
||||
else
|
||||
SHA256_Update(&ctx, p_bytes, key_len);
|
||||
|
||||
SHA256_Final(alt_result, &ctx);
|
||||
}
|
||||
|
||||
CopyMem(hash, alt_result, SHA256_DIGEST_SIZE);
|
||||
|
||||
FreePool(p_bytes);
|
||||
FreePool(s_bytes);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static EFI_STATUS sha512_crypt (const char *key, UINT32 key_len,
|
||||
const char *salt, UINT32 salt_size,
|
||||
const UINT32 rounds, UINT8 *hash)
|
||||
{
|
||||
SHA512_CTX ctx, alt_ctx;
|
||||
UINT8 alt_result[SHA512_DIGEST_LENGTH];
|
||||
UINT8 tmp_result[SHA512_DIGEST_LENGTH];
|
||||
UINT8 *cp, *p_bytes, *s_bytes;
|
||||
UINTN cnt;
|
||||
|
||||
SHA512_Init(&ctx);
|
||||
SHA512_Update(&ctx, key, key_len);
|
||||
SHA512_Update(&ctx, salt, salt_size);
|
||||
|
||||
SHA512_Init(&alt_ctx);
|
||||
SHA512_Update(&alt_ctx, key, key_len);
|
||||
SHA512_Update(&alt_ctx, salt, salt_size);
|
||||
SHA512_Update(&alt_ctx, key, key_len);
|
||||
|
||||
SHA512_Final(alt_result, &alt_ctx);
|
||||
|
||||
for (cnt = key_len; cnt > 64; cnt -= 64)
|
||||
SHA512_Update(&ctx, alt_result, 64);
|
||||
SHA512_Update(&ctx, alt_result, cnt);
|
||||
|
||||
for (cnt = key_len; cnt > 0; cnt >>= 1) {
|
||||
if ((cnt & 1) != 0) {
|
||||
SHA512_Update(&ctx, alt_result, 64);
|
||||
} else {
|
||||
SHA512_Update(&ctx, key, key_len);
|
||||
}
|
||||
}
|
||||
SHA512_Final(alt_result, &ctx);
|
||||
|
||||
SHA512_Init(&alt_ctx);
|
||||
for (cnt = 0; cnt < key_len; ++cnt)
|
||||
SHA512_Update(&alt_ctx, key, key_len);
|
||||
SHA512_Final(tmp_result, &alt_ctx);
|
||||
|
||||
cp = p_bytes = AllocatePool(key_len);
|
||||
for (cnt = key_len; cnt >= 64; cnt -= 64) {
|
||||
CopyMem(cp, tmp_result, 64);
|
||||
cp += 64;
|
||||
}
|
||||
CopyMem(cp, tmp_result, cnt);
|
||||
|
||||
SHA512_Init(&alt_ctx);
|
||||
for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
|
||||
SHA512_Update(&alt_ctx, salt, salt_size);
|
||||
SHA512_Final(tmp_result, &alt_ctx);
|
||||
|
||||
cp = s_bytes = AllocatePool(salt_size);
|
||||
for (cnt = salt_size; cnt >= 64; cnt -= 64) {
|
||||
CopyMem(cp, tmp_result, 64);
|
||||
cp += 64;
|
||||
}
|
||||
CopyMem(cp, tmp_result, cnt);
|
||||
|
||||
for (cnt = 0; cnt < rounds; ++cnt) {
|
||||
SHA512_Init(&ctx);
|
||||
|
||||
if ((cnt & 1) != 0)
|
||||
SHA512_Update(&ctx, p_bytes, key_len);
|
||||
else
|
||||
SHA512_Update(&ctx, alt_result, 64);
|
||||
|
||||
if (cnt % 3 != 0)
|
||||
SHA512_Update(&ctx, s_bytes, salt_size);
|
||||
|
||||
if (cnt % 7 != 0)
|
||||
SHA512_Update(&ctx, p_bytes, key_len);
|
||||
|
||||
if ((cnt & 1) != 0)
|
||||
SHA512_Update(&ctx, alt_result, 64);
|
||||
else
|
||||
SHA512_Update(&ctx, p_bytes, key_len);
|
||||
|
||||
SHA512_Final(alt_result, &ctx);
|
||||
}
|
||||
|
||||
CopyMem(hash, alt_result, SHA512_DIGEST_LENGTH);
|
||||
|
||||
FreePool(p_bytes);
|
||||
FreePool(s_bytes);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
#define BF_RESULT_SIZE (7 + 22 + 31 + 1)
|
||||
|
||||
static EFI_STATUS blowfish_crypt (const char *key, const char *salt, UINT8 *hash)
|
||||
{
|
||||
char *retval, result[BF_RESULT_SIZE];
|
||||
|
||||
retval = crypt_blowfish_rn (key, salt, result, BF_RESULT_SIZE);
|
||||
if (!retval)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
CopyMem(hash, result + 7 + 22, BF_RESULT_SIZE);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS password_crypt (const char *password, UINT32 pw_length,
|
||||
const PASSWORD_CRYPT *pw_crypt, UINT8 *hash)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
|
||||
if (!pw_crypt)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
switch (pw_crypt->method) {
|
||||
case TRADITIONAL_DES:
|
||||
status = trad_des_crypt (password, (char *)pw_crypt->salt, hash);
|
||||
break;
|
||||
case EXTEND_BSDI_DES:
|
||||
status = EFI_UNSUPPORTED;
|
||||
break;
|
||||
case MD5_BASED:
|
||||
status = md5_crypt (password, pw_length, (char *)pw_crypt->salt,
|
||||
pw_crypt->salt_size, hash);
|
||||
break;
|
||||
case SHA256_BASED:
|
||||
status = sha256_crypt(password, pw_length, (char *)pw_crypt->salt,
|
||||
pw_crypt->salt_size, pw_crypt->iter_count,
|
||||
hash);
|
||||
break;
|
||||
case SHA512_BASED:
|
||||
status = sha512_crypt(password, pw_length, (char *)pw_crypt->salt,
|
||||
pw_crypt->salt_size, pw_crypt->iter_count,
|
||||
hash);
|
||||
break;
|
||||
case BLOWFISH_BASED:
|
||||
if (pw_crypt->salt_size != (7 + 22 + 1)) {
|
||||
status = EFI_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
status = blowfish_crypt(password, (char *)pw_crypt->salt, hash);
|
||||
break;
|
||||
default:
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
27
PasswordCrypt.h
Normal file
27
PasswordCrypt.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef __PASSWORD_CRYPT_H__
|
||||
#define __PASSWORD_CRYPT_H__
|
||||
|
||||
enum HashMethod {
|
||||
TRADITIONAL_DES = 0,
|
||||
EXTEND_BSDI_DES,
|
||||
MD5_BASED,
|
||||
SHA256_BASED,
|
||||
SHA512_BASED,
|
||||
BLOWFISH_BASED
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
UINT16 method;
|
||||
UINT64 iter_count;
|
||||
UINT16 salt_size;
|
||||
UINT8 salt[32];
|
||||
UINT8 hash[128];
|
||||
} __attribute__ ((packed)) PASSWORD_CRYPT;
|
||||
|
||||
#define PASSWORD_CRYPT_SIZE sizeof(PASSWORD_CRYPT)
|
||||
|
||||
EFI_STATUS password_crypt (const char *password, UINT32 pw_length,
|
||||
const PASSWORD_CRYPT *pw_hash, UINT8 *hash);
|
||||
UINT16 get_hash_size (const UINT16 method);
|
||||
|
||||
#endif /* __PASSWORD_CRYPT_H__ */
|
24
TODO
24
TODO
@ -1 +1,23 @@
|
||||
Support for netbooting
|
||||
Versioned protocol:
|
||||
- Make shim and the bootloaders using it express how enlightened they
|
||||
are to one another, so we can stop earlier without tricks like
|
||||
the one above
|
||||
MokListRT signing:
|
||||
- For kexec and hybernate to work right, MokListRT probably needs to
|
||||
be an authenticated variable. It's probable this needs to be done
|
||||
in the kernel boot stub instead, just because it'll need an
|
||||
ephemeral key to be generated, and that means we need some entropy
|
||||
to build up.
|
||||
New security protocol:
|
||||
- TBD
|
||||
kexec MoK Management:
|
||||
Modsign enforcement mgmt MoK:
|
||||
- This is part of the plan for SecureBoot patches. Basically these
|
||||
features need to be disableable/enableable in MokManager.
|
||||
Variable for debug:
|
||||
- basically we need to be able to set a UEFI variable and get debug
|
||||
output. Right now some code uses SHIM_VERBOSE but that needs a fair
|
||||
amount of work to actually be useful.
|
||||
Hashing of option roms:
|
||||
- hash option roms and add them to MokListRT
|
||||
- probably belongs in MokManager
|
||||
|
85
cert.S
85
cert.S
@ -1,36 +1,67 @@
|
||||
.globl cert_table
|
||||
.data
|
||||
.align 16
|
||||
.type cert_table, @object
|
||||
.size cert_table, 4
|
||||
.section .vendor_cert, "a", @progbits
|
||||
cert_table:
|
||||
#if defined(VENDOR_CERT_FILE)
|
||||
.globl vendor_cert_size
|
||||
.data
|
||||
.align 1
|
||||
.type vendor_cert_size, @object
|
||||
.size vendor_cert_size, 4
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_cert_size:
|
||||
.long .L0 - vendor_cert
|
||||
.globl vendor_cert
|
||||
.data
|
||||
.align 1
|
||||
.type vendor_cert, @object
|
||||
.size vendor_cert, .L0-vendor_cert
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_cert:
|
||||
.incbin VENDOR_CERT_FILE
|
||||
.L0:
|
||||
.long vendor_cert_priv_end - vendor_cert_priv
|
||||
#else
|
||||
.globl vendor_cert
|
||||
.bss
|
||||
.type vendor_cert, @object
|
||||
.size vendor_cert, 1
|
||||
.long 0
|
||||
#endif
|
||||
#if defined(VENDOR_DBX_FILE)
|
||||
.long vendor_dbx_priv_end - vendor_dbx_priv
|
||||
#else
|
||||
.long 0
|
||||
#endif
|
||||
.long vendor_cert_priv - cert_table
|
||||
.long vendor_dbx_priv - cert_table
|
||||
#if defined(VENDOR_CERT_FILE)
|
||||
.data
|
||||
.align 1
|
||||
.type vendor_cert_priv, @object
|
||||
.size vendor_cert_priv, vendor_cert_priv_end-vendor_cert_priv
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_cert:
|
||||
vendor_cert_priv:
|
||||
.incbin VENDOR_CERT_FILE
|
||||
vendor_cert_priv_end:
|
||||
#else
|
||||
.bss
|
||||
.type vendor_cert_priv, @object
|
||||
.size vendor_cert_priv, 1
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_cert_priv:
|
||||
.zero 1
|
||||
|
||||
.globl vendor_cert_size
|
||||
.data
|
||||
.align 4
|
||||
.type vendor_cert_size, @object
|
||||
.size vendor_cert_size, 4
|
||||
.type vendor_cert_size_priv, @object
|
||||
.size vendor_cert_size_priv, 4
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_cert_size:
|
||||
.long 1
|
||||
vendor_cert_priv_end:
|
||||
#endif
|
||||
#if defined(VENDOR_DBX_FILE)
|
||||
.data
|
||||
.align 1
|
||||
.type vendor_dbx_priv, @object
|
||||
.size vendor_dbx_priv, vendor_dbx_priv_end-vendor_dbx_priv
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_dbx_priv:
|
||||
.incbin VENDOR_DBX_FILE
|
||||
vendor_dbx_priv_end:
|
||||
#else
|
||||
.bss
|
||||
.type vendor_dbx_priv, @object
|
||||
.size vendor_dbx_priv, 1
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_dbx_priv:
|
||||
.zero 1
|
||||
|
||||
.data
|
||||
.align 4
|
||||
.type vendor_dbx_size_priv, @object
|
||||
.size vendor_dbx_size_priv, 4
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_dbx_priv_end:
|
||||
#endif
|
||||
|
822
crypt_blowfish.c
Normal file
822
crypt_blowfish.c
Normal file
@ -0,0 +1,822 @@
|
||||
/*
|
||||
* The crypt_blowfish homepage is:
|
||||
*
|
||||
* http://www.openwall.com/crypt/
|
||||
*
|
||||
* This code comes from John the Ripper password cracker, with reentrant
|
||||
* and crypt(3) interfaces added, but optimizations specific to password
|
||||
* cracking removed.
|
||||
*
|
||||
* Written by Solar Designer <solar at openwall.com> in 1998-2011.
|
||||
* No copyright is claimed, and the software is hereby placed in the public
|
||||
* domain. In case this attempt to disclaim copyright and place the software
|
||||
* in the public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 1998-2011 Solar Designer and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* It is my intent that you should be able to use this on your system,
|
||||
* as part of a software package, or anywhere else to improve security,
|
||||
* ensure compatibility, or for any other purpose. I would appreciate
|
||||
* it if you give credit where it is due and keep your modifications in
|
||||
* the public domain as well, but I don't require that in order to let
|
||||
* you place this code and any modifications you make under a license
|
||||
* of your choice.
|
||||
*
|
||||
* This implementation is mostly compatible with OpenBSD's bcrypt.c (prefix
|
||||
* "$2a$") by Niels Provos <provos at citi.umich.edu>, and uses some of his
|
||||
* ideas. The password hashing algorithm was designed by David Mazieres
|
||||
* <dm at lcs.mit.edu>. For more information on the level of compatibility,
|
||||
* prefer refer to the comments in BF_set_key() below and to the included
|
||||
* crypt(3) man page.
|
||||
*
|
||||
* There's a paper on the algorithm that explains its design decisions:
|
||||
*
|
||||
* http://www.usenix.org/events/usenix99/provos.html
|
||||
*
|
||||
* Some of the tricks in BF_ROUND might be inspired by Eric Young's
|
||||
* Blowfish library (I can't be sure if I would think of something if I
|
||||
* hadn't seen his code).
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
/* Just to make sure the prototypes match the actual definitions */
|
||||
#include "crypt_blowfish.h"
|
||||
|
||||
typedef unsigned int BF_word;
|
||||
typedef signed int BF_word_signed;
|
||||
|
||||
/* Number of Blowfish rounds, this is also hardcoded into a few places */
|
||||
#define BF_N 16
|
||||
|
||||
typedef BF_word BF_key[BF_N + 2];
|
||||
|
||||
typedef struct {
|
||||
BF_word S[4][0x100];
|
||||
BF_key P;
|
||||
} BF_ctx;
|
||||
|
||||
/*
|
||||
* Magic IV for 64 Blowfish encryptions that we do at the end.
|
||||
* The string is "OrpheanBeholderScryDoubt" on big-endian.
|
||||
*/
|
||||
static BF_word BF_magic_w[6] = {
|
||||
0x4F727068, 0x65616E42, 0x65686F6C,
|
||||
0x64657253, 0x63727944, 0x6F756274
|
||||
};
|
||||
|
||||
/*
|
||||
* P-box and S-box tables initialized with digits of Pi.
|
||||
*/
|
||||
static BF_ctx BF_init_state = {
|
||||
{
|
||||
{
|
||||
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
|
||||
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
|
||||
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
||||
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
|
||||
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
|
||||
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||||
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
|
||||
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
|
||||
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
||||
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
|
||||
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
|
||||
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||||
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
|
||||
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
|
||||
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
||||
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
|
||||
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
|
||||
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||||
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
|
||||
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
|
||||
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
||||
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
|
||||
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
|
||||
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||||
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
|
||||
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
|
||||
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
||||
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
|
||||
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
|
||||
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||||
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
|
||||
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
|
||||
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
||||
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
|
||||
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
|
||||
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||||
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
|
||||
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
|
||||
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||||
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
|
||||
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
|
||||
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||||
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
|
||||
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
|
||||
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
||||
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
|
||||
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
|
||||
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||||
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
|
||||
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
|
||||
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
||||
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
|
||||
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
|
||||
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||||
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
|
||||
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
|
||||
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
||||
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
|
||||
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
|
||||
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||||
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
|
||||
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
|
||||
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
||||
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
|
||||
}, {
|
||||
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
|
||||
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
|
||||
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
||||
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
|
||||
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
|
||||
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||||
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
|
||||
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
|
||||
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
||||
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
|
||||
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
|
||||
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||||
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
|
||||
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
|
||||
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
||||
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
|
||||
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
|
||||
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||||
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
|
||||
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
|
||||
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
||||
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
|
||||
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
|
||||
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||||
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
|
||||
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
|
||||
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
||||
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
|
||||
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
|
||||
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||||
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
|
||||
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
|
||||
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
||||
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
|
||||
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
|
||||
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||||
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
|
||||
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
|
||||
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||||
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
|
||||
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
|
||||
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||||
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
|
||||
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
|
||||
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
||||
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
|
||||
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
|
||||
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||||
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
|
||||
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
|
||||
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
||||
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
|
||||
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
|
||||
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||||
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
|
||||
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
|
||||
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
||||
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
|
||||
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
|
||||
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||||
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
|
||||
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
|
||||
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
||||
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
|
||||
}, {
|
||||
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
|
||||
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
|
||||
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
||||
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
|
||||
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
|
||||
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||||
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
|
||||
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
|
||||
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
||||
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
|
||||
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
|
||||
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||||
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
|
||||
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
|
||||
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
||||
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
|
||||
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
|
||||
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||||
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
|
||||
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
|
||||
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
||||
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
|
||||
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
|
||||
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||||
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
|
||||
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
|
||||
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
||||
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
|
||||
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
|
||||
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||||
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
|
||||
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
|
||||
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
||||
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
|
||||
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
|
||||
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||||
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
|
||||
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
|
||||
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||||
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
|
||||
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
|
||||
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||||
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
|
||||
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
|
||||
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
||||
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
|
||||
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
|
||||
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||||
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
|
||||
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
|
||||
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
||||
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
|
||||
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
|
||||
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||||
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
|
||||
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
|
||||
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
||||
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
|
||||
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
|
||||
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||||
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
|
||||
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
|
||||
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
||||
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
|
||||
}, {
|
||||
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
|
||||
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
|
||||
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
||||
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
|
||||
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
|
||||
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||||
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
|
||||
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
|
||||
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
||||
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
|
||||
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
|
||||
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||||
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
|
||||
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
|
||||
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
||||
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
|
||||
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
|
||||
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||||
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
|
||||
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
|
||||
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
||||
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
|
||||
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
|
||||
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||||
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
|
||||
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
|
||||
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
||||
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
|
||||
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
|
||||
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||||
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
|
||||
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
|
||||
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
||||
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
|
||||
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
|
||||
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||||
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
|
||||
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
|
||||
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||||
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
|
||||
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
|
||||
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||||
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
|
||||
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
|
||||
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
||||
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
|
||||
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
|
||||
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||||
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
|
||||
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
|
||||
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
||||
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
|
||||
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
|
||||
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||||
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
|
||||
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
|
||||
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
||||
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
|
||||
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
|
||||
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||||
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
|
||||
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
|
||||
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
||||
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
|
||||
}
|
||||
}, {
|
||||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
|
||||
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
||||
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
||||
0x9216d5d9, 0x8979fb1b
|
||||
}
|
||||
};
|
||||
|
||||
static unsigned char BF_itoa64[64 + 1] =
|
||||
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
static unsigned char BF_atoi64[0x60] = {
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64,
|
||||
64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64,
|
||||
64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
|
||||
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64
|
||||
};
|
||||
|
||||
#define BF_safe_atoi64(dst, src) \
|
||||
{ \
|
||||
tmp = (unsigned char)(src); \
|
||||
if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \
|
||||
tmp = BF_atoi64[tmp]; \
|
||||
if (tmp > 63) return -1; \
|
||||
(dst) = tmp; \
|
||||
}
|
||||
|
||||
static int BF_decode(BF_word *dst, const char *src, int size)
|
||||
{
|
||||
unsigned char *dptr = (unsigned char *)dst;
|
||||
unsigned char *end = dptr + size;
|
||||
const unsigned char *sptr = (const unsigned char *)src;
|
||||
unsigned int tmp, c1, c2, c3, c4;
|
||||
|
||||
do {
|
||||
BF_safe_atoi64(c1, *sptr++);
|
||||
BF_safe_atoi64(c2, *sptr++);
|
||||
*dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
|
||||
if (dptr >= end) break;
|
||||
|
||||
BF_safe_atoi64(c3, *sptr++);
|
||||
*dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2);
|
||||
if (dptr >= end) break;
|
||||
|
||||
BF_safe_atoi64(c4, *sptr++);
|
||||
*dptr++ = ((c3 & 0x03) << 6) | c4;
|
||||
} while (dptr < end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void BF_encode(char *dst, const BF_word *src, int size)
|
||||
{
|
||||
const unsigned char *sptr = (const unsigned char *)src;
|
||||
const unsigned char *end = sptr + size;
|
||||
unsigned char *dptr = (unsigned char *)dst;
|
||||
unsigned int c1, c2;
|
||||
|
||||
do {
|
||||
c1 = *sptr++;
|
||||
*dptr++ = BF_itoa64[c1 >> 2];
|
||||
c1 = (c1 & 0x03) << 4;
|
||||
if (sptr >= end) {
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
break;
|
||||
}
|
||||
|
||||
c2 = *sptr++;
|
||||
c1 |= c2 >> 4;
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
c1 = (c2 & 0x0f) << 2;
|
||||
if (sptr >= end) {
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
break;
|
||||
}
|
||||
|
||||
c2 = *sptr++;
|
||||
c1 |= c2 >> 6;
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
*dptr++ = BF_itoa64[c2 & 0x3f];
|
||||
} while (sptr < end);
|
||||
}
|
||||
|
||||
static void BF_swap(BF_word *x, int count)
|
||||
{
|
||||
static int endianness_check = 1;
|
||||
char *is_little_endian = (char *)&endianness_check;
|
||||
BF_word tmp;
|
||||
|
||||
if (*is_little_endian)
|
||||
do {
|
||||
tmp = *x;
|
||||
tmp = (tmp << 16) | (tmp >> 16);
|
||||
*x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
|
||||
} while (--count);
|
||||
}
|
||||
|
||||
/* Architectures which can shift addresses left by 2 bits with no extra cost */
|
||||
#define BF_ROUND(L, R, N) \
|
||||
tmp1 = L & 0xFF; \
|
||||
tmp2 = L >> 8; \
|
||||
tmp2 &= 0xFF; \
|
||||
tmp3 = L >> 16; \
|
||||
tmp3 &= 0xFF; \
|
||||
tmp4 = L >> 24; \
|
||||
tmp1 = data.ctx.S[3][tmp1]; \
|
||||
tmp2 = data.ctx.S[2][tmp2]; \
|
||||
tmp3 = data.ctx.S[1][tmp3]; \
|
||||
tmp3 += data.ctx.S[0][tmp4]; \
|
||||
tmp3 ^= tmp2; \
|
||||
R ^= data.ctx.P[N + 1]; \
|
||||
tmp3 += tmp1; \
|
||||
R ^= tmp3;
|
||||
|
||||
/*
|
||||
* Encrypt one block, BF_N is hardcoded here.
|
||||
*/
|
||||
#define BF_ENCRYPT \
|
||||
L ^= data.ctx.P[0]; \
|
||||
BF_ROUND(L, R, 0); \
|
||||
BF_ROUND(R, L, 1); \
|
||||
BF_ROUND(L, R, 2); \
|
||||
BF_ROUND(R, L, 3); \
|
||||
BF_ROUND(L, R, 4); \
|
||||
BF_ROUND(R, L, 5); \
|
||||
BF_ROUND(L, R, 6); \
|
||||
BF_ROUND(R, L, 7); \
|
||||
BF_ROUND(L, R, 8); \
|
||||
BF_ROUND(R, L, 9); \
|
||||
BF_ROUND(L, R, 10); \
|
||||
BF_ROUND(R, L, 11); \
|
||||
BF_ROUND(L, R, 12); \
|
||||
BF_ROUND(R, L, 13); \
|
||||
BF_ROUND(L, R, 14); \
|
||||
BF_ROUND(R, L, 15); \
|
||||
tmp4 = R; \
|
||||
R = L; \
|
||||
L = tmp4 ^ data.ctx.P[BF_N + 1];
|
||||
|
||||
#define BF_body() \
|
||||
L = R = 0; \
|
||||
ptr = data.ctx.P; \
|
||||
do { \
|
||||
ptr += 2; \
|
||||
BF_ENCRYPT; \
|
||||
*(ptr - 2) = L; \
|
||||
*(ptr - 1) = R; \
|
||||
} while (ptr < &data.ctx.P[BF_N + 2]); \
|
||||
\
|
||||
ptr = data.ctx.S[0]; \
|
||||
do { \
|
||||
ptr += 2; \
|
||||
BF_ENCRYPT; \
|
||||
*(ptr - 2) = L; \
|
||||
*(ptr - 1) = R; \
|
||||
} while (ptr < &data.ctx.S[3][0xFF]);
|
||||
|
||||
static void BF_set_key(const char *key, BF_key expanded, BF_key initial,
|
||||
unsigned char flags)
|
||||
{
|
||||
const char *ptr = key;
|
||||
unsigned int bug, i, j;
|
||||
BF_word safety, sign, diff, tmp[2];
|
||||
|
||||
/*
|
||||
* There was a sign extension bug in older revisions of this function. While
|
||||
* we would have liked to simply fix the bug and move on, we have to provide
|
||||
* a backwards compatibility feature (essentially the bug) for some systems and
|
||||
* a safety measure for some others. The latter is needed because for certain
|
||||
* multiple inputs to the buggy algorithm there exist easily found inputs to
|
||||
* the correct algorithm that produce the same hash. Thus, we optionally
|
||||
* deviate from the correct algorithm just enough to avoid such collisions.
|
||||
* While the bug itself affected the majority of passwords containing
|
||||
* characters with the 8th bit set (although only a percentage of those in a
|
||||
* collision-producing way), the anti-collision safety measure affects
|
||||
* only a subset of passwords containing the '\xff' character (not even all of
|
||||
* those passwords, just some of them). This character is not found in valid
|
||||
* UTF-8 sequences and is rarely used in popular 8-bit character encodings.
|
||||
* Thus, the safety measure is unlikely to cause much annoyance, and is a
|
||||
* reasonable tradeoff to use when authenticating against existing hashes that
|
||||
* are not reliably known to have been computed with the correct algorithm.
|
||||
*
|
||||
* We use an approach that tries to minimize side-channel leaks of password
|
||||
* information - that is, we mostly use fixed-cost bitwise operations instead
|
||||
* of branches or table lookups. (One conditional branch based on password
|
||||
* length remains. It is not part of the bug aftermath, though, and is
|
||||
* difficult and possibly unreasonable to avoid given the use of C strings by
|
||||
* the caller, which results in similar timing leaks anyway.)
|
||||
*
|
||||
* For actual implementation, we set an array index in the variable "bug"
|
||||
* (0 means no bug, 1 means sign extension bug emulation) and a flag in the
|
||||
* variable "safety" (bit 16 is set when the safety measure is requested).
|
||||
* Valid combinations of settings are:
|
||||
*
|
||||
* Prefix "$2a$": bug = 0, safety = 0x10000
|
||||
* Prefix "$2x$": bug = 1, safety = 0
|
||||
* Prefix "$2y$": bug = 0, safety = 0
|
||||
*/
|
||||
bug = (unsigned int)flags & 1;
|
||||
safety = ((BF_word)flags & 2) << 15;
|
||||
|
||||
sign = diff = 0;
|
||||
|
||||
for (i = 0; i < BF_N + 2; i++) {
|
||||
tmp[0] = tmp[1] = 0;
|
||||
for (j = 0; j < 4; j++) {
|
||||
tmp[0] <<= 8;
|
||||
tmp[0] |= (unsigned char)*ptr; /* correct */
|
||||
tmp[1] <<= 8;
|
||||
tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */
|
||||
/*
|
||||
* Sign extension in the first char has no effect - nothing to overwrite yet,
|
||||
* and those extra 24 bits will be fully shifted out of the 32-bit word. For
|
||||
* chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign
|
||||
* extension in tmp[1] occurs. Once this flag is set, it remains set.
|
||||
*/
|
||||
if (j)
|
||||
sign |= tmp[1] & 0x80;
|
||||
if (!*ptr)
|
||||
ptr = key;
|
||||
else
|
||||
ptr++;
|
||||
}
|
||||
diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */
|
||||
|
||||
expanded[i] = tmp[bug];
|
||||
initial[i] = BF_init_state.P[i] ^ tmp[bug];
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, "diff" is zero iff the correct and buggy algorithms produced
|
||||
* exactly the same result. If so and if "sign" is non-zero, which indicates
|
||||
* that there was a non-benign sign extension, this means that we have a
|
||||
* collision between the correctly computed hash for this password and a set of
|
||||
* passwords that could be supplied to the buggy algorithm. Our safety measure
|
||||
* is meant to protect from such many-buggy to one-correct collisions, by
|
||||
* deviating from the correct algorithm in such cases. Let's check for this.
|
||||
*/
|
||||
diff |= diff >> 16; /* still zero iff exact match */
|
||||
diff &= 0xffff; /* ditto */
|
||||
diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */
|
||||
sign <<= 9; /* move the non-benign sign extension flag to bit 16 */
|
||||
sign &= ~diff & safety; /* action needed? */
|
||||
|
||||
/*
|
||||
* If we have determined that we need to deviate from the correct algorithm,
|
||||
* flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but
|
||||
* let's stick to it now. It came out of the approach we used above, and it's
|
||||
* not any worse than any other choice we could make.)
|
||||
*
|
||||
* It is crucial that we don't do the same to the expanded key used in the main
|
||||
* Eksblowfish loop. By doing it to only one of these two, we deviate from a
|
||||
* state that could be directly specified by a password to the buggy algorithm
|
||||
* (and to the fully correct one as well, but that's a side-effect).
|
||||
*/
|
||||
initial[0] ^= sign;
|
||||
}
|
||||
|
||||
static char *BF_crypt(const char *key, const char *setting,
|
||||
char *output, int size,
|
||||
BF_word min)
|
||||
{
|
||||
static const unsigned char flags_by_subtype[26] =
|
||||
{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0};
|
||||
struct {
|
||||
BF_ctx ctx;
|
||||
BF_key expanded_key;
|
||||
union {
|
||||
BF_word salt[4];
|
||||
BF_word output[6];
|
||||
} binary;
|
||||
} data;
|
||||
BF_word L, R;
|
||||
BF_word tmp1, tmp2, tmp3, tmp4;
|
||||
BF_word *ptr;
|
||||
BF_word count;
|
||||
int i;
|
||||
|
||||
if (size < 7 + 22 + 31 + 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (setting[0] != '$' ||
|
||||
setting[1] != '2' ||
|
||||
setting[2] < 'a' || setting[2] > 'z' ||
|
||||
!flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] ||
|
||||
setting[3] != '$' ||
|
||||
setting[4] < '0' || setting[4] > '3' ||
|
||||
setting[5] < '0' || setting[5] > '9' ||
|
||||
(setting[4] == '3' && setting[5] > '1') ||
|
||||
setting[6] != '$') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
|
||||
if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) {
|
||||
return NULL;
|
||||
}
|
||||
BF_swap(data.binary.salt, 4);
|
||||
|
||||
BF_set_key(key, data.expanded_key, data.ctx.P,
|
||||
flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']);
|
||||
|
||||
CopyMem(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S));
|
||||
|
||||
L = R = 0;
|
||||
for (i = 0; i < BF_N + 2; i += 2) {
|
||||
L ^= data.binary.salt[i & 2];
|
||||
R ^= data.binary.salt[(i & 2) + 1];
|
||||
BF_ENCRYPT;
|
||||
data.ctx.P[i] = L;
|
||||
data.ctx.P[i + 1] = R;
|
||||
}
|
||||
|
||||
ptr = data.ctx.S[0];
|
||||
do {
|
||||
ptr += 4;
|
||||
L ^= data.binary.salt[(BF_N + 2) & 3];
|
||||
R ^= data.binary.salt[(BF_N + 3) & 3];
|
||||
BF_ENCRYPT;
|
||||
*(ptr - 4) = L;
|
||||
*(ptr - 3) = R;
|
||||
|
||||
L ^= data.binary.salt[(BF_N + 4) & 3];
|
||||
R ^= data.binary.salt[(BF_N + 5) & 3];
|
||||
BF_ENCRYPT;
|
||||
*(ptr - 2) = L;
|
||||
*(ptr - 1) = R;
|
||||
} while (ptr < &data.ctx.S[3][0xFF]);
|
||||
|
||||
do {
|
||||
int done;
|
||||
|
||||
for (i = 0; i < BF_N + 2; i += 2) {
|
||||
data.ctx.P[i] ^= data.expanded_key[i];
|
||||
data.ctx.P[i + 1] ^= data.expanded_key[i + 1];
|
||||
}
|
||||
|
||||
done = 0;
|
||||
do {
|
||||
BF_body();
|
||||
if (done)
|
||||
break;
|
||||
done = 1;
|
||||
|
||||
tmp1 = data.binary.salt[0];
|
||||
tmp2 = data.binary.salt[1];
|
||||
tmp3 = data.binary.salt[2];
|
||||
tmp4 = data.binary.salt[3];
|
||||
for (i = 0; i < BF_N; i += 4) {
|
||||
data.ctx.P[i] ^= tmp1;
|
||||
data.ctx.P[i + 1] ^= tmp2;
|
||||
data.ctx.P[i + 2] ^= tmp3;
|
||||
data.ctx.P[i + 3] ^= tmp4;
|
||||
}
|
||||
data.ctx.P[16] ^= tmp1;
|
||||
data.ctx.P[17] ^= tmp2;
|
||||
} while (1);
|
||||
} while (--count);
|
||||
|
||||
for (i = 0; i < 6; i += 2) {
|
||||
L = BF_magic_w[i];
|
||||
R = BF_magic_w[i + 1];
|
||||
|
||||
count = 64;
|
||||
do {
|
||||
BF_ENCRYPT;
|
||||
} while (--count);
|
||||
|
||||
data.binary.output[i] = L;
|
||||
data.binary.output[i + 1] = R;
|
||||
}
|
||||
|
||||
CopyMem(output, (void *)setting, 7 + 22 - 1);
|
||||
output[7 + 22 - 1] = BF_itoa64[(int)
|
||||
BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30];
|
||||
|
||||
/* This has to be bug-compatible with the original implementation, so
|
||||
* only encode 23 of the 24 bytes. :-) */
|
||||
BF_swap(data.binary.output, 6);
|
||||
BF_encode(&output[7 + 22], data.binary.output, 23);
|
||||
output[7 + 22 + 31] = '\0';
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
int _crypt_output_magic(const char *setting, char *output, int size)
|
||||
{
|
||||
if (size < 3)
|
||||
return -1;
|
||||
|
||||
output[0] = '*';
|
||||
output[1] = '0';
|
||||
output[2] = '\0';
|
||||
|
||||
if (setting[0] == '*' && setting[1] == '0')
|
||||
output[1] = '1';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Please preserve the runtime self-test. It serves two purposes at once:
|
||||
*
|
||||
* 1. We really can't afford the risk of producing incompatible hashes e.g.
|
||||
* when there's something like gcc bug 26587 again, whereas an application or
|
||||
* library integrating this code might not also integrate our external tests or
|
||||
* it might not run them after every build. Even if it does, the miscompile
|
||||
* might only occur on the production build, but not on a testing build (such
|
||||
* as because of different optimization settings). It is painful to recover
|
||||
* from incorrectly-computed hashes - merely fixing whatever broke is not
|
||||
* enough. Thus, a proactive measure like this self-test is needed.
|
||||
*
|
||||
* 2. We don't want to leave sensitive data from our actual password hash
|
||||
* computation on the stack or in registers. Previous revisions of the code
|
||||
* would do explicit cleanups, but simply running the self-test after hash
|
||||
* computation is more reliable.
|
||||
*
|
||||
* The performance cost of this quick self-test is around 0.6% at the "$2a$08"
|
||||
* setting.
|
||||
*/
|
||||
char *crypt_blowfish_rn(const char *key, const char *setting,
|
||||
char *output, int size)
|
||||
{
|
||||
const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8";
|
||||
const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu";
|
||||
static const char * const test_hash[2] =
|
||||
{"VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55", /* $2x$ */
|
||||
"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55"}; /* $2a$, $2y$ */
|
||||
char *retval;
|
||||
const char *p;
|
||||
int ok;
|
||||
struct {
|
||||
char s[7 + 22 + 1];
|
||||
char o[7 + 22 + 31 + 1 + 1 + 1];
|
||||
} buf;
|
||||
|
||||
/* Hash the supplied password */
|
||||
_crypt_output_magic(setting, output, size);
|
||||
retval = BF_crypt(key, setting, output, size, 16);
|
||||
|
||||
/*
|
||||
* Do a quick self-test. It is important that we make both calls to BF_crypt()
|
||||
* from the same scope such that they likely use the same stack locations,
|
||||
* which makes the second call overwrite the first call's sensitive data on the
|
||||
* stack and makes it more likely that any alignment related issues would be
|
||||
* detected by the self-test.
|
||||
*/
|
||||
CopyMem(buf.s, (void *)test_setting, sizeof(buf.s));
|
||||
if (retval)
|
||||
buf.s[2] = setting[2];
|
||||
SetMem(buf.o, sizeof(buf.o), 0x55);
|
||||
buf.o[sizeof(buf.o) - 1] = 0;
|
||||
p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1);
|
||||
|
||||
ok = (p == buf.o &&
|
||||
!CompareMem((void *)p, (void *)buf.s, 7 + 22) &&
|
||||
!CompareMem((void *)(p + (7 + 22)),
|
||||
(void *)test_hash[(unsigned int)(unsigned char)buf.s[2] & 1],
|
||||
31 + 1 + 1 + 1));
|
||||
|
||||
{
|
||||
const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345";
|
||||
BF_key ae, ai, ye, yi;
|
||||
BF_set_key(k, ae, ai, 2); /* $2a$ */
|
||||
BF_set_key(k, ye, yi, 4); /* $2y$ */
|
||||
ai[0] ^= 0x10000; /* undo the safety (for comparison) */
|
||||
ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 &&
|
||||
!CompareMem(ae, ye, sizeof(ae)) &&
|
||||
!CompareMem(ai, yi, sizeof(ai));
|
||||
}
|
||||
|
||||
if (ok)
|
||||
return retval;
|
||||
|
||||
/* Should not happen */
|
||||
_crypt_output_magic(setting, output, size);
|
||||
return NULL;
|
||||
}
|
22
crypt_blowfish.h
Normal file
22
crypt_blowfish.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
|
||||
* No copyright is claimed, and the software is hereby placed in the public
|
||||
* domain. In case this attempt to disclaim copyright and place the software
|
||||
* in the public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* See crypt_blowfish.c for more information.
|
||||
*/
|
||||
|
||||
#ifndef _CRYPT_BLOWFISH_H
|
||||
#define _CRYPT_BLOWFISH_H
|
||||
|
||||
char *crypt_blowfish_rn(const char *key, const char *setting,
|
||||
char *output, int size);
|
||||
#endif
|
36
dbx.S
36
dbx.S
@ -1,36 +0,0 @@
|
||||
#if defined(VENDOR_DBX_FILE)
|
||||
.globl vendor_dbx_size
|
||||
.data
|
||||
.align 1
|
||||
.type vendor_dbx_size, @object
|
||||
.size vendor_dbx_size, 4
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_dbx_size:
|
||||
.long .L0 - vendor_dbx
|
||||
.globl vendor_dbx
|
||||
.data
|
||||
.align 1
|
||||
.type vendor_dbx, @object
|
||||
.size vendor_dbx, .L0-vendor_dbx
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_dbx:
|
||||
.incbin VENDOR_DBX_FILE
|
||||
.L0:
|
||||
#else
|
||||
.globl vendor_dbx
|
||||
.bss
|
||||
.type vendor_dbx, @object
|
||||
.size vendor_dbx, 1
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_dbx:
|
||||
.zero 1
|
||||
|
||||
.globl vendor_dbx_size
|
||||
.data
|
||||
.align 4
|
||||
.type vendor_dbx_size, @object
|
||||
.size vendor_dbx_size, 4
|
||||
.section .vendor_cert, "a", @progbits
|
||||
vendor_dbx_size:
|
||||
.long 0
|
||||
#endif
|
@ -22,6 +22,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#ifndef __PE_IMAGE_H__
|
||||
#define __PE_IMAGE_H__
|
||||
|
||||
#include <wincert.h>
|
||||
|
||||
#define SIGNATURE_16(A, B) ((A) | (B << 8))
|
||||
#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))
|
||||
#define SIGNATURE_64(A, B, C, D, E, F, G, H) \
|
||||
@ -760,13 +762,6 @@ typedef union {
|
||||
EFI_IMAGE_OPTIONAL_HEADER_UNION *Union;
|
||||
} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION;
|
||||
|
||||
typedef struct _WIN_CERTIFICATE {
|
||||
UINT32 dwLength;
|
||||
UINT16 wRevision;
|
||||
UINT16 wCertificateType;
|
||||
//UINT8 bCertificate[ANYSIZE_ARRAY];
|
||||
} WIN_CERTIFICATE;
|
||||
|
||||
typedef struct {
|
||||
WIN_CERTIFICATE Hdr;
|
||||
UINT8 CertData[1];
|
68
include/configtable.h
Normal file
68
include/configtable.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* definitions straight from TianoCore */
|
||||
|
||||
typedef UINT32 EFI_IMAGE_EXECUTION_ACTION;
|
||||
|
||||
#define EFI_IMAGE_EXECUTION_AUTHENTICATION 0x00000007
|
||||
#define EFI_IMAGE_EXECUTION_AUTH_UNTESTED 0x00000000
|
||||
#define EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED 0x00000001
|
||||
#define EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED 0x00000002
|
||||
#define EFI_IMAGE_EXECUTION_AUTH_SIG_NOT_FOUND 0x00000003
|
||||
#define EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND 0x00000004
|
||||
#define EFI_IMAGE_EXECUTION_POLICY_FAILED 0x00000005
|
||||
#define EFI_IMAGE_EXECUTION_INITIALIZED 0x00000008
|
||||
|
||||
typedef struct {
|
||||
///
|
||||
/// Describes the action taken by the firmware regarding this image.
|
||||
///
|
||||
EFI_IMAGE_EXECUTION_ACTION Action;
|
||||
///
|
||||
/// Size of all of the entire structure.
|
||||
///
|
||||
UINT32 InfoSize;
|
||||
///
|
||||
/// If this image was a UEFI device driver (for option ROM, for example) this is the
|
||||
/// null-terminated, user-friendly name for the device. If the image was for an application,
|
||||
/// then this is the name of the application. If this cannot be determined, then a simple
|
||||
/// NULL character should be put in this position.
|
||||
/// CHAR16 Name[];
|
||||
///
|
||||
|
||||
///
|
||||
/// For device drivers, this is the device path of the device for which this device driver
|
||||
/// was intended. In some cases, the driver itself may be stored as part of the system
|
||||
/// firmware, but this field should record the device's path, not the firmware path. For
|
||||
/// applications, this is the device path of the application. If this cannot be determined,
|
||||
/// a simple end-of-path device node should be put in this position.
|
||||
/// EFI_DEVICE_PATH_PROTOCOL DevicePath;
|
||||
///
|
||||
|
||||
///
|
||||
/// Zero or more image signatures. If the image contained no signatures,
|
||||
/// then this field is empty.
|
||||
///
|
||||
///EFI_SIGNATURE_LIST Signature;
|
||||
UINT8 Data[];
|
||||
} EFI_IMAGE_EXECUTION_INFO;
|
||||
|
||||
typedef struct {
|
||||
///
|
||||
/// Number of EFI_IMAGE_EXECUTION_INFO structures.
|
||||
///
|
||||
UINTN NumberOfImages;
|
||||
///
|
||||
/// Number of image instances of EFI_IMAGE_EXECUTION_INFO structures.
|
||||
///
|
||||
EFI_IMAGE_EXECUTION_INFO InformationInfo[];
|
||||
} EFI_IMAGE_EXECUTION_INFO_TABLE;
|
||||
|
||||
|
||||
void *
|
||||
configtable_get_table(EFI_GUID *guid);
|
||||
EFI_IMAGE_EXECUTION_INFO_TABLE *
|
||||
configtable_get_image_table(void);
|
||||
EFI_IMAGE_EXECUTION_INFO *
|
||||
configtable_find_image(const EFI_DEVICE_PATH *DevicePath);
|
||||
int
|
||||
configtable_image_is_forbidden(const EFI_DEVICE_PATH *DevicePath);
|
||||
|
88
include/console.h
Normal file
88
include/console.h
Normal file
@ -0,0 +1,88 @@
|
||||
#ifndef _SHIM_LIB_CONSOLE_H
|
||||
#define _SHIM_LIB_CONSOLE_H 1
|
||||
|
||||
EFI_INPUT_KEY
|
||||
console_get_keystroke(void);
|
||||
void
|
||||
console_print_box_at(CHAR16 *str_arr[], int highlight, int start_col, int start_row, int size_cols, int size_rows, int offset, int lines);
|
||||
void
|
||||
console_print_box(CHAR16 *str_arr[], int highlight);
|
||||
int
|
||||
console_yes_no(CHAR16 *str_arr[]);
|
||||
int
|
||||
console_select(CHAR16 *title[], CHAR16* selectors[], int start);
|
||||
void
|
||||
console_errorbox(CHAR16 *err);
|
||||
void
|
||||
console_error(CHAR16 *err, EFI_STATUS);
|
||||
void
|
||||
console_alertbox(CHAR16 **title);
|
||||
void
|
||||
console_notify(CHAR16 *string);
|
||||
void
|
||||
console_reset(void);
|
||||
#define NOSEL 0x7fffffff
|
||||
|
||||
#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \
|
||||
{ 0xf42f7782, 0x12e, 0x4c12, {0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21} }
|
||||
|
||||
typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL;
|
||||
|
||||
typedef enum {
|
||||
EfiConsoleControlScreenText,
|
||||
EfiConsoleControlScreenGraphics,
|
||||
EfiConsoleControlScreenMaxValue
|
||||
} EFI_CONSOLE_CONTROL_SCREEN_MODE;
|
||||
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) (
|
||||
IN EFI_CONSOLE_CONTROL_PROTOCOL *This,
|
||||
OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode,
|
||||
OUT BOOLEAN *GopUgaExists, OPTIONAL
|
||||
OUT BOOLEAN *StdInLocked OPTIONAL
|
||||
);
|
||||
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) (
|
||||
IN EFI_CONSOLE_CONTROL_PROTOCOL *This,
|
||||
IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
|
||||
);
|
||||
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) (
|
||||
IN EFI_CONSOLE_CONTROL_PROTOCOL *This,
|
||||
IN CHAR16 *Password
|
||||
);
|
||||
|
||||
struct _EFI_CONSOLE_CONTROL_PROTOCOL {
|
||||
EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode;
|
||||
EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode;
|
||||
EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn;
|
||||
};
|
||||
|
||||
extern VOID setup_console (int text);
|
||||
extern VOID setup_verbosity(VOID);
|
||||
extern UINT8 verbose;
|
||||
#define dprint(fmt, ...) ({ \
|
||||
UINTN __dprint_ret = 0; \
|
||||
if (verbose) \
|
||||
__dprint_ret = Print((fmt), ##__VA_ARGS__); \
|
||||
__dprint_ret; \
|
||||
})
|
||||
#define dprinta(fmt, ...) ({ \
|
||||
UINTN __dprinta_ret = 0; \
|
||||
if (verbose) { \
|
||||
UINTN __dprinta_i; \
|
||||
CHAR16 *__dprinta_str = AllocateZeroPool((strlena(fmt) + 1) * 2); \
|
||||
for (__dprinta_i = 0; fmt[__dprinta_i] != '\0'; __dprinta_i++) \
|
||||
__dprinta_str[__dprinta_i] = fmt[__dprinta_i]; \
|
||||
__dprinta_ret = Print((__dprinta_str), ##__VA_ARGS__); \
|
||||
FreePool(__dprinta_str); \
|
||||
} \
|
||||
__dprinta_ret; \
|
||||
})
|
||||
|
||||
#endif /* _SHIM_LIB_CONSOLE_H */
|
222
include/efiauthenticated.h
Normal file
222
include/efiauthenticated.h
Normal file
@ -0,0 +1,222 @@
|
||||
#ifndef _INC_EFIAUTHENTICATED_H
|
||||
#define _INC_EFIAUTHENTICATED_H
|
||||
#include <wincert.h>
|
||||
//***********************************************************************
|
||||
// Signature Database
|
||||
//***********************************************************************
|
||||
///
|
||||
/// The format of a signature database.
|
||||
///
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct {
|
||||
///
|
||||
/// An identifier which identifies the agent which added the signature to the list.
|
||||
///
|
||||
EFI_GUID SignatureOwner;
|
||||
///
|
||||
/// The format of the signature is defined by the SignatureType.
|
||||
///
|
||||
UINT8 SignatureData[1];
|
||||
} EFI_SIGNATURE_DATA;
|
||||
|
||||
typedef struct {
|
||||
///
|
||||
/// Type of the signature. GUID signature types are defined in below.
|
||||
///
|
||||
EFI_GUID SignatureType;
|
||||
///
|
||||
/// Total size of the signature list, including this header.
|
||||
///
|
||||
UINT32 SignatureListSize;
|
||||
///
|
||||
/// Size of the signature header which precedes the array of signatures.
|
||||
///
|
||||
UINT32 SignatureHeaderSize;
|
||||
///
|
||||
/// Size of each signature.
|
||||
///
|
||||
UINT32 SignatureSize;
|
||||
///
|
||||
/// Header before the array of signatures. The format of this header is specified
|
||||
/// by the SignatureType.
|
||||
/// UINT8 SignatureHeader[SignatureHeaderSize];
|
||||
///
|
||||
/// An array of signatures. Each signature is SignatureSize bytes in length.
|
||||
/// EFI_SIGNATURE_DATA Signatures[][SignatureSize];
|
||||
///
|
||||
} EFI_SIGNATURE_LIST;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
//
|
||||
// _WIN_CERTIFICATE.wCertificateType
|
||||
//
|
||||
#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
|
||||
#define WIN_CERT_TYPE_EFI_PKCS115 0x0EF0
|
||||
#define WIN_CERT_TYPE_EFI_GUID 0x0EF1
|
||||
|
||||
#define EFI_CERT_X509_GUID \
|
||||
(EFI_GUID){ \
|
||||
0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72} \
|
||||
}
|
||||
|
||||
#define EFI_CERT_RSA2048_GUID \
|
||||
(EFI_GUID){ \
|
||||
0x3c5766e8, 0x269c, 0x4e34, {0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6} \
|
||||
}
|
||||
|
||||
|
||||
#define EFI_CERT_TYPE_PKCS7_GUID \
|
||||
(EFI_GUID){ \
|
||||
0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} \
|
||||
}
|
||||
|
||||
///
|
||||
/// WIN_CERTIFICATE_UEFI_GUID.CertType
|
||||
///
|
||||
#define EFI_CERT_TYPE_RSA2048_SHA256_GUID \
|
||||
{0xa7717414, 0xc616, 0x4977, {0x94, 0x20, 0x84, 0x47, 0x12, 0xa7, 0x35, 0xbf } }
|
||||
|
||||
///
|
||||
/// WIN_CERTIFICATE_UEFI_GUID.CertData
|
||||
///
|
||||
typedef struct {
|
||||
EFI_GUID HashType;
|
||||
UINT8 PublicKey[256];
|
||||
UINT8 Signature[256];
|
||||
} EFI_CERT_BLOCK_RSA_2048_SHA256;
|
||||
|
||||
|
||||
///
|
||||
/// Certificate which encapsulates a GUID-specific digital signature
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// This is the standard WIN_CERTIFICATE header, where
|
||||
/// wCertificateType is set to WIN_CERT_TYPE_UEFI_GUID.
|
||||
///
|
||||
WIN_CERTIFICATE Hdr;
|
||||
///
|
||||
/// This is the unique id which determines the
|
||||
/// format of the CertData. .
|
||||
///
|
||||
EFI_GUID CertType;
|
||||
///
|
||||
/// The following is the certificate data. The format of
|
||||
/// the data is determined by the CertType.
|
||||
/// If CertType is EFI_CERT_TYPE_RSA2048_SHA256_GUID,
|
||||
/// the CertData will be EFI_CERT_BLOCK_RSA_2048_SHA256 structure.
|
||||
///
|
||||
UINT8 CertData[1];
|
||||
} WIN_CERTIFICATE_UEFI_GUID;
|
||||
|
||||
|
||||
///
|
||||
/// Certificate which encapsulates the RSASSA_PKCS1-v1_5 digital signature.
|
||||
///
|
||||
/// The WIN_CERTIFICATE_UEFI_PKCS1_15 structure is derived from
|
||||
/// WIN_CERTIFICATE and encapsulate the information needed to
|
||||
/// implement the RSASSA-PKCS1-v1_5 digital signature algorithm as
|
||||
/// specified in RFC2437.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// This is the standard WIN_CERTIFICATE header, where
|
||||
/// wCertificateType is set to WIN_CERT_TYPE_UEFI_PKCS1_15.
|
||||
///
|
||||
WIN_CERTIFICATE Hdr;
|
||||
///
|
||||
/// This is the hashing algorithm which was performed on the
|
||||
/// UEFI executable when creating the digital signature.
|
||||
///
|
||||
EFI_GUID HashAlgorithm;
|
||||
///
|
||||
/// The following is the actual digital signature. The
|
||||
/// size of the signature is the same size as the key
|
||||
/// (1024-bit key is 128 bytes) and can be determined by
|
||||
/// subtracting the length of the other parts of this header
|
||||
/// from the total length of the certificate as found in
|
||||
/// Hdr.dwLength.
|
||||
///
|
||||
/// UINT8 Signature[];
|
||||
///
|
||||
} WIN_CERTIFICATE_EFI_PKCS1_15;
|
||||
|
||||
#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field))
|
||||
|
||||
///
|
||||
/// Attributes of Authenticated Variable
|
||||
///
|
||||
#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
|
||||
#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020
|
||||
#define EFI_VARIABLE_APPEND_WRITE 0x00000040
|
||||
|
||||
///
|
||||
/// AuthInfo is a WIN_CERTIFICATE using the wCertificateType
|
||||
/// WIN_CERTIFICATE_UEFI_GUID and the CertType
|
||||
/// EFI_CERT_TYPE_RSA2048_SHA256_GUID. If the attribute specifies
|
||||
/// authenticated access, then the Data buffer should begin with an
|
||||
/// authentication descriptor prior to the data payload and DataSize
|
||||
/// should reflect the the data.and descriptor size. The caller
|
||||
/// shall digest the Monotonic Count value and the associated data
|
||||
/// for the variable update using the SHA-256 1-way hash algorithm.
|
||||
/// The ensuing the 32-byte digest will be signed using the private
|
||||
/// key associated w/ the public/private 2048-bit RSA key-pair. The
|
||||
/// WIN_CERTIFICATE shall be used to describe the signature of the
|
||||
/// Variable data *Data. In addition, the signature will also
|
||||
/// include the MonotonicCount value to guard against replay attacks.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// Included in the signature of
|
||||
/// AuthInfo.Used to ensure freshness/no
|
||||
/// replay. Incremented during each
|
||||
/// "Write" access.
|
||||
///
|
||||
UINT64 MonotonicCount;
|
||||
///
|
||||
/// Provides the authorization for the variable
|
||||
/// access. It is a signature across the
|
||||
/// variable data and the Monotonic Count
|
||||
/// value. Caller uses Private key that is
|
||||
/// associated with a public key that has been
|
||||
/// provisioned via the key exchange.
|
||||
///
|
||||
WIN_CERTIFICATE_UEFI_GUID AuthInfo;
|
||||
} EFI_VARIABLE_AUTHENTICATION;
|
||||
|
||||
///
|
||||
/// When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
|
||||
/// set, then the Data buffer shall begin with an instance of a complete (and serialized)
|
||||
/// EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
|
||||
/// variable value and DataSize shall reflect the combined size of the descriptor and the new
|
||||
/// variable value. The authentication descriptor is not part of the variable data and is not
|
||||
/// returned by subsequent calls to GetVariable().
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// For the TimeStamp value, components Pad1, Nanosecond, TimeZone, Daylight and
|
||||
/// Pad2 shall be set to 0. This means that the time shall always be expressed in GMT.
|
||||
///
|
||||
EFI_TIME TimeStamp;
|
||||
///
|
||||
/// Only a CertType of EFI_CERT_TYPE_PKCS7_GUID is accepted.
|
||||
///
|
||||
WIN_CERTIFICATE_UEFI_GUID AuthInfo;
|
||||
} EFI_VARIABLE_AUTHENTICATION_2;
|
||||
|
||||
///
|
||||
/// Size of AuthInfo prior to the data payload.
|
||||
///
|
||||
#define AUTHINFO_SIZE ((OFFSET_OF (EFI_VARIABLE_AUTHENTICATION, AuthInfo)) + \
|
||||
(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) + \
|
||||
sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256))
|
||||
|
||||
#define AUTHINFO2_SIZE(VarAuth2) ((OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) + \
|
||||
(UINTN) ((EFI_VARIABLE_AUTHENTICATION_2 *) (VarAuth2))->AuthInfo.Hdr.dwLength)
|
||||
|
||||
#define OFFSET_OF_AUTHINFO2_CERT_DATA ((OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) + \
|
||||
(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)))
|
||||
|
||||
#endif
|
9
include/errors.h
Normal file
9
include/errors.h
Normal file
@ -0,0 +1,9 @@
|
||||
#include <efierr.h>
|
||||
|
||||
#ifndef EFI_INCOMPATIBLE_VERSION
|
||||
#define EFI_INCOMPATIBLE_VERSION EFIERR(25)
|
||||
#endif
|
||||
#ifndef EFI_SECURITY_VIOLATION
|
||||
#define EFI_SECURITY_VIOLATION EFIERR(26)
|
||||
#endif
|
||||
|
5
include/execute.h
Normal file
5
include/execute.h
Normal file
@ -0,0 +1,5 @@
|
||||
EFI_STATUS
|
||||
generate_path(CHAR16* name, EFI_LOADED_IMAGE *li,
|
||||
EFI_DEVICE_PATH **path, CHAR16 **PathName);
|
||||
EFI_STATUS
|
||||
execute(EFI_HANDLE image, CHAR16 *name);
|
19
include/guid.h
Normal file
19
include/guid.h
Normal file
@ -0,0 +1,19 @@
|
||||
#include <efi.h>
|
||||
|
||||
#ifndef BUILD_EFI
|
||||
const char *guid_to_str(EFI_GUID *guid);
|
||||
void str_to_guid(const char *str, EFI_GUID *guid);
|
||||
#endif
|
||||
|
||||
extern EFI_GUID GV_GUID;
|
||||
extern EFI_GUID SIG_DB;
|
||||
extern EFI_GUID X509_GUID;
|
||||
extern EFI_GUID RSA2048_GUID;
|
||||
extern EFI_GUID PKCS7_GUID;
|
||||
extern EFI_GUID IMAGE_PROTOCOL;
|
||||
extern EFI_GUID SIMPLE_FS_PROTOCOL;
|
||||
extern EFI_GUID EFI_CERT_SHA1_GUID;
|
||||
extern EFI_GUID EFI_CERT_SHA256_GUID;
|
||||
extern EFI_GUID MOK_OWNER;
|
||||
extern EFI_GUID SECURITY_PROTOCOL_GUID;
|
||||
extern EFI_GUID SECURITY2_PROTOCOL_GUID;
|
15
include/security_policy.h
Normal file
15
include/security_policy.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef _SHIM_LIB_SECURITY_POLICY_H
|
||||
#define _SHIM_LIB_SECURITY_POLICY_H 1
|
||||
|
||||
#if defined(OVERRIDE_SECURITY_POLICY)
|
||||
typedef EFI_STATUS (*SecurityHook) (void *data, UINT32 len);
|
||||
|
||||
EFI_STATUS
|
||||
security_policy_install(SecurityHook authentication);
|
||||
EFI_STATUS
|
||||
security_policy_uninstall(void);
|
||||
void
|
||||
security_protocol_set_hashes(unsigned char *esl, int len);
|
||||
#endif /* OVERRIDE_SECURITY_POLICY */
|
||||
|
||||
#endif /* SHIM_LIB_SECURITY_POLICY_H */
|
2
include/shell.h
Normal file
2
include/shell.h
Normal file
@ -0,0 +1,2 @@
|
||||
EFI_STATUS
|
||||
argsplit(EFI_HANDLE image, int *argc, CHAR16*** ARGV);
|
21
include/simple_file.h
Normal file
21
include/simple_file.h
Normal file
@ -0,0 +1,21 @@
|
||||
EFI_STATUS
|
||||
simple_file_open (EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode);
|
||||
EFI_STATUS
|
||||
simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode);
|
||||
EFI_STATUS
|
||||
simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer);
|
||||
EFI_STATUS
|
||||
simple_file_write_all(EFI_FILE *file, UINTN size, void *buffer);
|
||||
void
|
||||
simple_file_close(EFI_FILE *file);
|
||||
EFI_STATUS
|
||||
simple_dir_read_all(EFI_HANDLE image, CHAR16 *name, EFI_FILE_INFO **Entries,
|
||||
int *count);
|
||||
EFI_STATUS
|
||||
simple_dir_filter(EFI_HANDLE image, CHAR16 *name, CHAR16 *filter,
|
||||
CHAR16 ***result, int *count, EFI_FILE_INFO **entries);
|
||||
void
|
||||
simple_file_selector(EFI_HANDLE *im, CHAR16 **title, CHAR16 *name,
|
||||
CHAR16 *filter, CHAR16 **result);
|
||||
EFI_STATUS
|
||||
simple_volume_selector(CHAR16 **title, CHAR16 **selected, EFI_HANDLE *h);
|
59
include/variables.h
Normal file
59
include/variables.h
Normal file
@ -0,0 +1,59 @@
|
||||
#include <efiauthenticated.h>
|
||||
|
||||
#include <PeImage.h> /* for SHA256_DIGEST_SIZE */
|
||||
|
||||
#define certlist_for_each_certentry(cl, cl_init, s, s_init) \
|
||||
for (cl = (EFI_SIGNATURE_LIST *)(cl_init), s = (s_init); \
|
||||
s > 0 && s >= cl->SignatureListSize; \
|
||||
s -= cl->SignatureListSize, \
|
||||
cl = (EFI_SIGNATURE_LIST *) ((UINT8 *)cl + cl->SignatureListSize))
|
||||
|
||||
/*
|
||||
* Warning: this assumes (cl)->SignatureHeaderSize is zero. It is for all
|
||||
* the signatures we process (X509, RSA2048, SHA256)
|
||||
*/
|
||||
#define certentry_for_each_cert(c, cl) \
|
||||
for (c = (EFI_SIGNATURE_DATA *)((UINT8 *) (cl) + sizeof(EFI_SIGNATURE_LIST) + (cl)->SignatureHeaderSize); \
|
||||
(UINT8 *)c < ((UINT8 *)(cl)) + (cl)->SignatureListSize; \
|
||||
c = (EFI_SIGNATURE_DATA *)((UINT8 *)c + (cl)->SignatureSize))
|
||||
|
||||
EFI_STATUS
|
||||
CreatePkX509SignatureList (
|
||||
IN UINT8 *X509Data,
|
||||
IN UINTN X509DataSize,
|
||||
IN EFI_GUID owner,
|
||||
OUT EFI_SIGNATURE_LIST **PkCert
|
||||
);
|
||||
EFI_STATUS
|
||||
CreateTimeBasedPayload (
|
||||
IN OUT UINTN *DataSize,
|
||||
IN OUT UINT8 **Data
|
||||
);
|
||||
EFI_STATUS
|
||||
SetSecureVariable(CHAR16 *var, UINT8 *Data, UINTN len, EFI_GUID owner, UINT32 options, int createtimebased);
|
||||
EFI_STATUS
|
||||
get_variable(CHAR16 *var, UINT8 **data, UINTN *len, EFI_GUID owner);
|
||||
EFI_STATUS
|
||||
get_variable_attr(CHAR16 *var, UINT8 **data, UINTN *len, EFI_GUID owner,
|
||||
UINT32 *attributes);
|
||||
EFI_STATUS
|
||||
find_in_esl(UINT8 *Data, UINTN DataSize, UINT8 *key, UINTN keylen);
|
||||
EFI_STATUS
|
||||
find_in_variable_esl(CHAR16* var, EFI_GUID owner, UINT8 *key, UINTN keylen);
|
||||
|
||||
#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
|
||||
|
||||
UINT64
|
||||
GetOSIndications(void);
|
||||
EFI_STATUS
|
||||
SETOSIndicationsAndReboot(UINT64 indications);
|
||||
int
|
||||
variable_is_secureboot(void);
|
||||
int
|
||||
variable_is_setupmode(void);
|
||||
EFI_STATUS
|
||||
variable_enroll_hash(CHAR16 *var, EFI_GUID owner,
|
||||
UINT8 hash[SHA256_DIGEST_SIZE]);
|
||||
EFI_STATUS
|
||||
variable_create_esl(void *cert, int cert_len, EFI_GUID *type, EFI_GUID *owner,
|
||||
void **out, int *outlen);
|
8
include/version.h
Normal file
8
include/version.h
Normal file
@ -0,0 +1,8 @@
|
||||
#define VERSION "1.3.4"
|
||||
|
||||
static void
|
||||
version(const char *progname)
|
||||
{
|
||||
printf("%s " VERSION "\n", progname);
|
||||
}
|
||||
|
33
include/wincert.h
Normal file
33
include/wincert.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef _INC_WINCERT_H
|
||||
#define _INC_WINCERT_H
|
||||
|
||||
///
|
||||
/// The WIN_CERTIFICATE structure is part of the PE/COFF specification.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// The length of the entire certificate,
|
||||
/// including the length of the header, in bytes.
|
||||
///
|
||||
UINT32 dwLength;
|
||||
///
|
||||
/// The revision level of the WIN_CERTIFICATE
|
||||
/// structure. The current revision level is 0x0200.
|
||||
///
|
||||
UINT16 wRevision;
|
||||
///
|
||||
/// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI
|
||||
/// certificate types. The UEFI specification reserves the range of
|
||||
/// certificate type values from 0x0EF0 to 0x0EFF.
|
||||
///
|
||||
UINT16 wCertificateType;
|
||||
///
|
||||
/// The following is the actual certificate. The format of
|
||||
/// the certificate depends on wCertificateType.
|
||||
///
|
||||
/// UINT8 bCertificate[ANYSIZE_ARRAY];
|
||||
///
|
||||
} WIN_CERTIFICATE;
|
||||
|
||||
|
||||
#endif
|
29
lib/Makefile
Normal file
29
lib/Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
TARGET = lib.a
|
||||
|
||||
LIBFILES = simple_file.o guid.o console.o execute.o configtable.o shell.o variables.o security_policy.o
|
||||
|
||||
ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)
|
||||
|
||||
EFI_INCLUDE = /usr/include/efi
|
||||
EFI_INCLUDES = -I$(EFI_INCLUDE) -I$(EFI_INCLUDE)/$(ARCH) -I$(EFI_INCLUDE)/protocol -I../include
|
||||
|
||||
EFI_CRT_OBJS = $(EFI_PATH)/crt0-efi-$(ARCH).o
|
||||
EFI_LDS = $(EFI_PATH)/elf_$(ARCH)_efi.lds
|
||||
|
||||
CFLAGS = -ggdb -O0 -fno-stack-protector -fno-strict-aliasing -fpic \
|
||||
-fshort-wchar -Wall -mno-red-zone -DBUILD_EFI -fno-builtin \
|
||||
-Werror \
|
||||
$(EFI_INCLUDES)
|
||||
ifeq ($(ARCH),x86_64)
|
||||
CFLAGS += -DEFI_FUNCTION_WRAPPER -DGNU_EFI_USE_MS_ABI
|
||||
endif
|
||||
|
||||
lib.a: $(LIBFILES)
|
||||
ar rcs lib.a $(LIBFILES)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
clean:
|
||||
rm -f lib.a
|
||||
rm -f $(LIBFILES)
|
||||
|
144
lib/configtable.c
Normal file
144
lib/configtable.c
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2013 <James.Bottomley@HansenPartnership.com>
|
||||
*
|
||||
* see COPYING file
|
||||
*
|
||||
* read some platform configuration tables
|
||||
*/
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include <guid.h>
|
||||
#include <configtable.h>
|
||||
|
||||
void *
|
||||
configtable_get_table(EFI_GUID *guid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ST->NumberOfTableEntries; i++) {
|
||||
EFI_CONFIGURATION_TABLE *CT = &ST->ConfigurationTable[i];
|
||||
|
||||
if (CompareGuid(guid, &CT->VendorGuid) == 0) {
|
||||
return CT->VendorTable;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EFI_IMAGE_EXECUTION_INFO_TABLE *
|
||||
configtable_get_image_table(void)
|
||||
{
|
||||
return configtable_get_table(&SIG_DB);
|
||||
}
|
||||
|
||||
EFI_IMAGE_EXECUTION_INFO *
|
||||
configtable_find_image(const EFI_DEVICE_PATH *DevicePath)
|
||||
{
|
||||
EFI_IMAGE_EXECUTION_INFO_TABLE *t = configtable_get_image_table();
|
||||
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
int entries = t->NumberOfImages;
|
||||
EFI_IMAGE_EXECUTION_INFO *e = t->InformationInfo;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < entries; i++) {
|
||||
#ifdef DEBUG_CONFIG
|
||||
Print(L"InfoSize = %d Action = %d\n", e->InfoSize, e->Action);
|
||||
|
||||
/* print what we have for debugging */
|
||||
UINT8 *d = (UINT8 *)e; // + sizeof(UINT32)*2;
|
||||
Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
d += 16;
|
||||
Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
d += 16;
|
||||
Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
d += 16;
|
||||
Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
d += 16;
|
||||
Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
d += 16;
|
||||
Print(L"Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
#endif
|
||||
CHAR16 *name = (CHAR16 *)(e->Data);
|
||||
int skip = 0;
|
||||
|
||||
/* There's a bug in a lot of EFI platforms and they forget to
|
||||
* put the name here. The only real way of detecting it is to
|
||||
* look for either a UC16 NULL or ASCII as UC16 */
|
||||
if (name[0] == '\0' || (e->Data[1] == 0 && e->Data[3] == 0)) {
|
||||
skip = StrSize(name);
|
||||
#ifdef DEBUG_CONFIG
|
||||
Print(L"FOUND NAME %s (%d)\n", name, skip);
|
||||
#endif
|
||||
}
|
||||
EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *)(e->Data + skip), *dpn = dp;
|
||||
if (dp->Type == 0 || dp->Type > 6 || dp->SubType == 0
|
||||
|| (((dp->Length[1] << 8) + dp->Length[0]) > e->InfoSize)) {
|
||||
/* Parse error, table corrupt, bail */
|
||||
Print(L"Image Execution Information table corrupt\n");
|
||||
break;
|
||||
}
|
||||
|
||||
UINTN Size;
|
||||
DevicePathInstance(&dpn, &Size);
|
||||
#ifdef DEBUG_CONFIG
|
||||
Print(L"Path: %s\n", DevicePathToStr(dp));
|
||||
Print(L"Device Path Size %d\n", Size);
|
||||
#endif
|
||||
if (Size > e->InfoSize) {
|
||||
/* parse error; the platform obviously has a
|
||||
* corrupted image table; bail */
|
||||
Print(L"Image Execution Information table corrupt\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (CompareMem(dp, (void *)DevicePath, Size) == 0) {
|
||||
#ifdef DEBUG_CONFIG
|
||||
Print(L"***FOUND\n");
|
||||
console_get_keystroke();
|
||||
#endif
|
||||
return e;
|
||||
}
|
||||
e = (EFI_IMAGE_EXECUTION_INFO *)((UINT8 *)e + e->InfoSize);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CONFIG
|
||||
Print(L"***NOT FOUND\n");
|
||||
console_get_keystroke();
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
configtable_image_is_forbidden(const EFI_DEVICE_PATH *DevicePath)
|
||||
{
|
||||
EFI_IMAGE_EXECUTION_INFO *e = configtable_find_image(DevicePath);
|
||||
|
||||
/* Image may not be in DB if it gets executed successfully If it is,
|
||||
* and EFI_IMAGE_EXECUTION_INITIALIZED is not set, then the image
|
||||
* isn't authenticated. If there's no signature, usually
|
||||
* EFI_IMAGE_EXECUTION_AUTH_UNTESTED is set, if the hash is in dbx,
|
||||
* EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND is returned, and if the key is
|
||||
* in dbx, EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED is returned*/
|
||||
|
||||
if (e && (e->Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND
|
||||
|| e->Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED)) {
|
||||
/* this means the images signing key is in dbx */
|
||||
#ifdef DEBUG_CONFIG
|
||||
Print(L"SIGNATURE IS IN DBX, FORBIDDING EXECUTION\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
452
lib/console.c
Normal file
452
lib/console.c
Normal file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
* Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
||||
* Copyright 2013 Red Hat Inc. <pjones@redhat.com>
|
||||
*
|
||||
* see COPYING file
|
||||
*/
|
||||
#include <efi/efi.h>
|
||||
#include <efi/efilib.h>
|
||||
|
||||
#include <console.h>
|
||||
#include <variables.h>
|
||||
#include <errors.h>
|
||||
|
||||
static EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
|
||||
|
||||
static int min(int a, int b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
static int
|
||||
count_lines(CHAR16 *str_arr[])
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (str_arr[i])
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
static void
|
||||
SetMem16(CHAR16 *dst, UINT32 n, CHAR16 c)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n/2; i++) {
|
||||
dst[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
EFI_INPUT_KEY
|
||||
console_get_keystroke(void)
|
||||
{
|
||||
EFI_INPUT_KEY key;
|
||||
UINTN EventIndex;
|
||||
|
||||
uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &EventIndex);
|
||||
uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
void
|
||||
console_print_box_at(CHAR16 *str_arr[], int highlight, int start_col, int start_row, int size_cols, int size_rows, int offset, int lines)
|
||||
{
|
||||
int i;
|
||||
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
|
||||
UINTN rows, cols;
|
||||
CHAR16 *Line;
|
||||
|
||||
if (lines == 0)
|
||||
return;
|
||||
|
||||
uefi_call_wrapper(co->QueryMode, 4, co, co->Mode->Mode, &cols, &rows);
|
||||
|
||||
/* last row on screen is unusable without scrolling, so ignore it */
|
||||
rows--;
|
||||
|
||||
if (size_rows < 0)
|
||||
size_rows = rows + size_rows + 1;
|
||||
if (size_cols < 0)
|
||||
size_cols = cols + size_cols + 1;
|
||||
|
||||
if (start_col < 0)
|
||||
start_col = (cols + start_col + 2)/2;
|
||||
if (start_row < 0)
|
||||
start_row = (rows + start_row + 2)/2;
|
||||
if (start_col < 0)
|
||||
start_col = 0;
|
||||
if (start_row < 0)
|
||||
start_row = 0;
|
||||
|
||||
if (start_col > cols || start_row > rows) {
|
||||
Print(L"Starting Position (%d,%d) is off screen\n",
|
||||
start_col, start_row);
|
||||
return;
|
||||
}
|
||||
if (size_cols + start_col > cols)
|
||||
size_cols = cols - start_col;
|
||||
if (size_rows + start_row > rows)
|
||||
size_rows = rows - start_row;
|
||||
|
||||
if (lines > size_rows - 2)
|
||||
lines = size_rows - 2;
|
||||
|
||||
Line = AllocatePool((size_cols+1)*sizeof(CHAR16));
|
||||
if (!Line) {
|
||||
Print(L"Failed Allocation\n");
|
||||
return;
|
||||
}
|
||||
|
||||
SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL);
|
||||
|
||||
Line[0] = BOXDRAW_DOWN_RIGHT;
|
||||
Line[size_cols - 1] = BOXDRAW_DOWN_LEFT;
|
||||
Line[size_cols] = L'\0';
|
||||
uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, start_row);
|
||||
uefi_call_wrapper(co->OutputString, 2, co, Line);
|
||||
|
||||
int start;
|
||||
if (offset == 0)
|
||||
/* middle */
|
||||
start = (size_rows - lines)/2 + start_row + offset;
|
||||
else if (offset < 0)
|
||||
/* from bottom */
|
||||
start = start_row + size_rows - lines + offset - 1;
|
||||
else
|
||||
/* from top */
|
||||
start = start_row + offset;
|
||||
|
||||
|
||||
for (i = start_row + 1; i < size_rows + start_row - 1; i++) {
|
||||
int line = i - start;
|
||||
|
||||
SetMem16 (Line, size_cols*2, L' ');
|
||||
Line[0] = BOXDRAW_VERTICAL;
|
||||
Line[size_cols - 1] = BOXDRAW_VERTICAL;
|
||||
Line[size_cols] = L'\0';
|
||||
if (line >= 0 && line < lines) {
|
||||
CHAR16 *s = str_arr[line];
|
||||
int len = StrLen(s);
|
||||
int col = (size_cols - 2 - len)/2;
|
||||
|
||||
if (col < 0)
|
||||
col = 0;
|
||||
|
||||
CopyMem(Line + col + 1, s, min(len, size_cols - 2)*2);
|
||||
}
|
||||
if (line >= 0 && line == highlight)
|
||||
uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
|
||||
uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, i);
|
||||
uefi_call_wrapper(co->OutputString, 2, co, Line);
|
||||
if (line >= 0 && line == highlight)
|
||||
uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
|
||||
|
||||
}
|
||||
SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL);
|
||||
Line[0] = BOXDRAW_UP_RIGHT;
|
||||
Line[size_cols - 1] = BOXDRAW_UP_LEFT;
|
||||
Line[size_cols] = L'\0';
|
||||
uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, i);
|
||||
uefi_call_wrapper(co->OutputString, 2, co, Line);
|
||||
|
||||
FreePool (Line);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
console_print_box(CHAR16 *str_arr[], int highlight)
|
||||
{
|
||||
SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
|
||||
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
|
||||
CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode));
|
||||
uefi_call_wrapper(co->EnableCursor, 2, co, FALSE);
|
||||
uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
|
||||
|
||||
console_print_box_at(str_arr, highlight, 0, 0, -1, -1, 0,
|
||||
count_lines(str_arr));
|
||||
|
||||
console_get_keystroke();
|
||||
|
||||
uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
|
||||
|
||||
uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
|
||||
uefi_call_wrapper(co->SetCursorPosition, 3, co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
|
||||
uefi_call_wrapper(co->SetAttribute, 2, co, SavedConsoleMode.Attribute);
|
||||
}
|
||||
|
||||
int
|
||||
console_select(CHAR16 *title[], CHAR16* selectors[], int start)
|
||||
{
|
||||
SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
|
||||
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
|
||||
EFI_INPUT_KEY k;
|
||||
int selector;
|
||||
int selector_lines = count_lines(selectors);
|
||||
int selector_max_cols = 0;
|
||||
int i, offs_col, offs_row, size_cols, size_rows, lines;
|
||||
int selector_offset;
|
||||
UINTN cols, rows;
|
||||
|
||||
uefi_call_wrapper(co->QueryMode, 4, co, co->Mode->Mode, &cols, &rows);
|
||||
|
||||
for (i = 0; i < selector_lines; i++) {
|
||||
int len = StrLen(selectors[i]);
|
||||
|
||||
if (len > selector_max_cols)
|
||||
selector_max_cols = len;
|
||||
}
|
||||
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (start >= selector_lines)
|
||||
start = selector_lines - 1;
|
||||
|
||||
offs_col = - selector_max_cols - 4;
|
||||
size_cols = selector_max_cols + 4;
|
||||
|
||||
if (selector_lines > rows - 10) {
|
||||
int title_lines = count_lines(title);
|
||||
offs_row = title_lines + 1;
|
||||
size_rows = rows - 3 - title_lines;
|
||||
lines = size_rows - 2;
|
||||
} else {
|
||||
offs_row = - selector_lines - 4;
|
||||
size_rows = selector_lines + 2;
|
||||
lines = selector_lines;
|
||||
}
|
||||
|
||||
if (start > lines) {
|
||||
selector = lines;
|
||||
selector_offset = start - lines;
|
||||
} else {
|
||||
selector = start;
|
||||
selector_offset = 0;
|
||||
}
|
||||
|
||||
CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode));
|
||||
uefi_call_wrapper(co->EnableCursor, 2, co, FALSE);
|
||||
uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
|
||||
|
||||
console_print_box_at(title, -1, 0, 0, -1, -1, 1, count_lines(title));
|
||||
|
||||
console_print_box_at(selectors, selector, offs_col, offs_row,
|
||||
size_cols, size_rows, 0, lines);
|
||||
|
||||
do {
|
||||
k = console_get_keystroke();
|
||||
|
||||
if (k.ScanCode == SCAN_ESC) {
|
||||
selector = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (k.ScanCode == SCAN_UP) {
|
||||
if (selector > 0)
|
||||
selector--;
|
||||
else if (selector_offset > 0)
|
||||
selector_offset--;
|
||||
} else if (k.ScanCode == SCAN_DOWN) {
|
||||
if (selector < lines - 1)
|
||||
selector++;
|
||||
else if (selector_offset < (selector_lines - lines))
|
||||
selector_offset++;
|
||||
}
|
||||
|
||||
console_print_box_at(&selectors[selector_offset], selector,
|
||||
offs_col, offs_row,
|
||||
size_cols, size_rows, 0, lines);
|
||||
} while (!(k.ScanCode == SCAN_NULL
|
||||
&& k.UnicodeChar == CHAR_CARRIAGE_RETURN));
|
||||
|
||||
uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
|
||||
|
||||
uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
|
||||
uefi_call_wrapper(co->SetCursorPosition, 3, co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
|
||||
uefi_call_wrapper(co->SetAttribute, 2, co, SavedConsoleMode.Attribute);
|
||||
|
||||
if (selector < 0)
|
||||
/* ESC pressed */
|
||||
return selector;
|
||||
return selector + selector_offset;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
console_yes_no(CHAR16 *str_arr[])
|
||||
{
|
||||
return console_select(str_arr, (CHAR16 *[]){ L"No", L"Yes", NULL }, 0);
|
||||
}
|
||||
|
||||
void
|
||||
console_alertbox(CHAR16 **title)
|
||||
{
|
||||
console_select(title, (CHAR16 *[]){ L"OK", 0 }, 0);
|
||||
}
|
||||
|
||||
void
|
||||
console_errorbox(CHAR16 *err)
|
||||
{
|
||||
CHAR16 **err_arr = (CHAR16 *[]){
|
||||
L"ERROR",
|
||||
L"",
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
err_arr[2] = err;
|
||||
|
||||
console_alertbox(err_arr);
|
||||
}
|
||||
|
||||
void
|
||||
console_notify(CHAR16 *string)
|
||||
{
|
||||
CHAR16 **str_arr = (CHAR16 *[]){
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
str_arr[0] = string;
|
||||
|
||||
console_alertbox(str_arr);
|
||||
}
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
|
||||
|
||||
/* Copy of gnu-efi-3.0 with the added secure boot strings */
|
||||
static struct {
|
||||
EFI_STATUS Code;
|
||||
WCHAR *Desc;
|
||||
} error_table[] = {
|
||||
{ EFI_SUCCESS, L"Success"},
|
||||
{ EFI_LOAD_ERROR, L"Load Error"},
|
||||
{ EFI_INVALID_PARAMETER, L"Invalid Parameter"},
|
||||
{ EFI_UNSUPPORTED, L"Unsupported"},
|
||||
{ EFI_BAD_BUFFER_SIZE, L"Bad Buffer Size"},
|
||||
{ EFI_BUFFER_TOO_SMALL, L"Buffer Too Small"},
|
||||
{ EFI_NOT_READY, L"Not Ready"},
|
||||
{ EFI_DEVICE_ERROR, L"Device Error"},
|
||||
{ EFI_WRITE_PROTECTED, L"Write Protected"},
|
||||
{ EFI_OUT_OF_RESOURCES, L"Out of Resources"},
|
||||
{ EFI_VOLUME_CORRUPTED, L"Volume Corrupt"},
|
||||
{ EFI_VOLUME_FULL, L"Volume Full"},
|
||||
{ EFI_NO_MEDIA, L"No Media"},
|
||||
{ EFI_MEDIA_CHANGED, L"Media changed"},
|
||||
{ EFI_NOT_FOUND, L"Not Found"},
|
||||
{ EFI_ACCESS_DENIED, L"Access Denied"},
|
||||
{ EFI_NO_RESPONSE, L"No Response"},
|
||||
{ EFI_NO_MAPPING, L"No mapping"},
|
||||
{ EFI_TIMEOUT, L"Time out"},
|
||||
{ EFI_NOT_STARTED, L"Not started"},
|
||||
{ EFI_ALREADY_STARTED, L"Already started"},
|
||||
{ EFI_ABORTED, L"Aborted"},
|
||||
{ EFI_ICMP_ERROR, L"ICMP Error"},
|
||||
{ EFI_TFTP_ERROR, L"TFTP Error"},
|
||||
{ EFI_PROTOCOL_ERROR, L"Protocol Error"},
|
||||
{ EFI_INCOMPATIBLE_VERSION, L"Incompatible Version"},
|
||||
{ EFI_SECURITY_VIOLATION, L"Security Violation"},
|
||||
|
||||
// warnings
|
||||
{ EFI_WARN_UNKOWN_GLYPH, L"Warning Unknown Glyph"},
|
||||
{ EFI_WARN_DELETE_FAILURE, L"Warning Delete Failure"},
|
||||
{ EFI_WARN_WRITE_FAILURE, L"Warning Write Failure"},
|
||||
{ EFI_WARN_BUFFER_TOO_SMALL, L"Warning Buffer Too Small"},
|
||||
{ 0, NULL}
|
||||
} ;
|
||||
|
||||
|
||||
static CHAR16 *
|
||||
err_string (
|
||||
IN EFI_STATUS Status
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
for (Index = 0; error_table[Index].Desc; Index +=1) {
|
||||
if (error_table[Index].Code == Status) {
|
||||
return error_table[Index].Desc;
|
||||
}
|
||||
}
|
||||
|
||||
return L"";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
console_error(CHAR16 *err, EFI_STATUS status)
|
||||
{
|
||||
CHAR16 **err_arr = (CHAR16 *[]){
|
||||
L"ERROR",
|
||||
L"",
|
||||
0,
|
||||
0,
|
||||
};
|
||||
CHAR16 str[512];
|
||||
|
||||
SPrint(str, sizeof(str), L"%s: (%d) %s", err, status, err_string(status));
|
||||
|
||||
err_arr[2] = str;
|
||||
|
||||
console_alertbox(err_arr);
|
||||
}
|
||||
|
||||
void
|
||||
console_reset(void)
|
||||
{
|
||||
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
|
||||
|
||||
uefi_call_wrapper(co->Reset, 2, co, TRUE);
|
||||
/* set mode 0 - required to be 80x25 */
|
||||
uefi_call_wrapper(co->SetMode, 2, co, 0);
|
||||
uefi_call_wrapper(co->ClearScreen, 1, co);
|
||||
}
|
||||
|
||||
UINT8 verbose;
|
||||
|
||||
VOID
|
||||
setup_verbosity(VOID)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
EFI_GUID guid = SHIM_LOCK_GUID;
|
||||
UINT8 verbose_check;
|
||||
UINTN verbose_check_size;
|
||||
|
||||
verbose_check_size = 1;
|
||||
status = get_variable(L"SHIM_VERBOSE", (void *)&verbose_check,
|
||||
&verbose_check_size, guid);
|
||||
verbose = 0;
|
||||
if (!EFI_ERROR(status))
|
||||
verbose = verbose_check;
|
||||
}
|
||||
|
||||
VOID setup_console (int text)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
EFI_GUID console_control_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
|
||||
EFI_CONSOLE_CONTROL_PROTOCOL *concon;
|
||||
static EFI_CONSOLE_CONTROL_SCREEN_MODE mode =
|
||||
EfiConsoleControlScreenGraphics;
|
||||
EFI_CONSOLE_CONTROL_SCREEN_MODE new_mode;
|
||||
|
||||
status = LibLocateProtocol(&console_control_guid, (VOID **)&concon);
|
||||
if (status != EFI_SUCCESS)
|
||||
return;
|
||||
|
||||
if (text) {
|
||||
new_mode = EfiConsoleControlScreenText;
|
||||
|
||||
status = uefi_call_wrapper(concon->GetMode, 4, concon, &mode,
|
||||
0, 0);
|
||||
/* If that didn't work, assume it's graphics */
|
||||
if (status != EFI_SUCCESS)
|
||||
mode = EfiConsoleControlScreenGraphics;
|
||||
} else {
|
||||
new_mode = mode;
|
||||
}
|
||||
|
||||
uefi_call_wrapper(concon->SetMode, 2, concon, new_mode);
|
||||
}
|
127
lib/execute.c
Normal file
127
lib/execute.c
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
||||
*
|
||||
* see COPYING file
|
||||
*
|
||||
* --
|
||||
*
|
||||
* generate_path is a cut and paste from
|
||||
*
|
||||
* git://github.com/mjg59/shim.git
|
||||
*
|
||||
* Code Copyright 2012 Red Hat, Inc <mjg@redhat.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include <guid.h>
|
||||
#include <execute.h>
|
||||
|
||||
EFI_STATUS
|
||||
generate_path(CHAR16* name, EFI_LOADED_IMAGE *li, EFI_DEVICE_PATH **path, CHAR16 **PathName)
|
||||
{
|
||||
unsigned int pathlen;
|
||||
EFI_STATUS efi_status = EFI_SUCCESS;
|
||||
CHAR16 *devpathstr = DevicePathToStr(li->FilePath),
|
||||
*found = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < StrLen(devpathstr); i++) {
|
||||
if (devpathstr[i] == '/')
|
||||
devpathstr[i] = '\\';
|
||||
if (devpathstr[i] == '\\')
|
||||
found = &devpathstr[i];
|
||||
}
|
||||
if (!found) {
|
||||
pathlen = 0;
|
||||
} else {
|
||||
while (*(found - 1) == '\\')
|
||||
--found;
|
||||
*found = '\0';
|
||||
pathlen = StrLen(devpathstr);
|
||||
}
|
||||
|
||||
if (name[0] != '\\')
|
||||
pathlen++;
|
||||
|
||||
*PathName = AllocatePool((pathlen + 1 + StrLen(name))*sizeof(CHAR16));
|
||||
|
||||
if (!*PathName) {
|
||||
Print(L"Failed to allocate path buffer\n");
|
||||
efi_status = EFI_OUT_OF_RESOURCES;
|
||||
goto error;
|
||||
}
|
||||
|
||||
StrCpy(*PathName, devpathstr);
|
||||
|
||||
if (name[0] != '\\')
|
||||
StrCat(*PathName, L"\\");
|
||||
StrCat(*PathName, name);
|
||||
|
||||
*path = FileDevicePath(li->DeviceHandle, *PathName);
|
||||
|
||||
error:
|
||||
FreePool(devpathstr);
|
||||
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
execute(EFI_HANDLE image, CHAR16 *name)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
EFI_HANDLE h;
|
||||
EFI_LOADED_IMAGE *li;
|
||||
EFI_DEVICE_PATH *devpath;
|
||||
CHAR16 *PathName;
|
||||
|
||||
status = uefi_call_wrapper(BS->HandleProtocol, 3, image,
|
||||
&IMAGE_PROTOCOL, (void **)&li);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
|
||||
status = generate_path(name, li, &devpath, &PathName);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = uefi_call_wrapper(BS->LoadImage, 6, FALSE, image,
|
||||
devpath, NULL, 0, &h);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
status = uefi_call_wrapper(BS->StartImage, 3, h, NULL, NULL);
|
||||
uefi_call_wrapper(BS->UnloadImage, 1, h);
|
||||
|
||||
out:
|
||||
FreePool(PathName);
|
||||
FreePool(devpath);
|
||||
return status;
|
||||
}
|
48
lib/guid.c
Normal file
48
lib/guid.c
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
||||
*
|
||||
* see COPYING file
|
||||
*/
|
||||
|
||||
#include <guid.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef BUILD_EFI
|
||||
/* EFI has %g for this, so it's only needed in platform c */
|
||||
const char *guid_to_str(EFI_GUID *guid)
|
||||
{
|
||||
static char str[256];
|
||||
|
||||
sprintf(str, "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
|
||||
guid->Data1, guid->Data2, guid->Data3,
|
||||
guid->Data4[0], guid->Data4[1], guid->Data4[2],
|
||||
guid->Data4[3], guid->Data4[4], guid->Data4[5],
|
||||
guid->Data4[6], guid->Data4[7]);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void str_to_guid(const char *str, EFI_GUID *guid)
|
||||
{
|
||||
sscanf(str, "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
|
||||
&guid->Data1, &guid->Data2, &guid->Data3,
|
||||
guid->Data4, guid->Data4 + 1, guid->Data4 + 2,
|
||||
guid->Data4 + 3, guid->Data4 + 4, guid->Data4 + 5,
|
||||
guid->Data4 + 6, guid->Data4 + 7);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* all the necessary guids */
|
||||
EFI_GUID GV_GUID = EFI_GLOBAL_VARIABLE;
|
||||
EFI_GUID SIG_DB = { 0xd719b2cb, 0x3d3a, 0x4596, {0xa3, 0xbc, 0xda, 0xd0, 0xe, 0x67, 0x65, 0x6f }};
|
||||
|
||||
EFI_GUID X509_GUID = { 0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72} };
|
||||
EFI_GUID RSA2048_GUID = { 0x3c5766e8, 0x269c, 0x4e34, {0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6} };
|
||||
EFI_GUID PKCS7_GUID = { 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} };
|
||||
EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL;
|
||||
EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL;
|
||||
EFI_GUID EFI_CERT_SHA1_GUID = { 0x826ca512, 0xcf10, 0x4ac9, {0xb1, 0x87, 0xbe, 0x1, 0x49, 0x66, 0x31, 0xbd }};
|
||||
EFI_GUID EFI_CERT_SHA256_GUID = { 0xc1c41626, 0x504c, 0x4092, { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 } };
|
||||
EFI_GUID MOK_OWNER = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
|
||||
EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } };
|
||||
EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } };
|
352
lib/security_policy.c
Normal file
352
lib/security_policy.c
Normal file
@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
||||
*
|
||||
* see COPYING file
|
||||
*
|
||||
* Install and remove a platform security2 override policy
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include <guid.h>
|
||||
#include <variables.h>
|
||||
#include <simple_file.h>
|
||||
#include <errors.h>
|
||||
|
||||
#if defined(OVERRIDE_SECURITY_POLICY)
|
||||
#include <security_policy.h>
|
||||
|
||||
/*
|
||||
* See the UEFI Platform Initialization manual (Vol2: DXE) for this
|
||||
*/
|
||||
struct _EFI_SECURITY2_PROTOCOL;
|
||||
struct _EFI_SECURITY_PROTOCOL;
|
||||
typedef struct _EFI_SECURITY2_PROTOCOL EFI_SECURITY2_PROTOCOL;
|
||||
typedef struct _EFI_SECURITY_PROTOCOL EFI_SECURITY_PROTOCOL;
|
||||
typedef EFI_DEVICE_PATH EFI_DEVICE_PATH_PROTOCOL;
|
||||
|
||||
typedef EFI_STATUS (EFIAPI *EFI_SECURITY_FILE_AUTHENTICATION_STATE) (
|
||||
const EFI_SECURITY_PROTOCOL *This,
|
||||
UINT32 AuthenticationStatus,
|
||||
const EFI_DEVICE_PATH_PROTOCOL *File
|
||||
);
|
||||
typedef EFI_STATUS (EFIAPI *EFI_SECURITY2_FILE_AUTHENTICATION) (
|
||||
const EFI_SECURITY2_PROTOCOL *This,
|
||||
const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
||||
VOID *FileBuffer,
|
||||
UINTN FileSize,
|
||||
BOOLEAN BootPolicy
|
||||
);
|
||||
|
||||
struct _EFI_SECURITY2_PROTOCOL {
|
||||
EFI_SECURITY2_FILE_AUTHENTICATION FileAuthentication;
|
||||
};
|
||||
|
||||
struct _EFI_SECURITY_PROTOCOL {
|
||||
EFI_SECURITY_FILE_AUTHENTICATION_STATE FileAuthenticationState;
|
||||
};
|
||||
|
||||
|
||||
static UINT8 *security_policy_esl = NULL;
|
||||
static UINTN security_policy_esl_len;
|
||||
static SecurityHook extra_check = NULL;
|
||||
|
||||
static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL;
|
||||
static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL;
|
||||
|
||||
static EFI_STATUS thunk_security_policy_authentication(
|
||||
const EFI_SECURITY_PROTOCOL *This,
|
||||
UINT32 AuthenticationStatus,
|
||||
const EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
||||
)
|
||||
__attribute__((unused));
|
||||
|
||||
static EFI_STATUS thunk_security2_policy_authentication(
|
||||
const EFI_SECURITY2_PROTOCOL *This,
|
||||
const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
||||
VOID *FileBuffer,
|
||||
UINTN FileSize,
|
||||
BOOLEAN BootPolicy
|
||||
)
|
||||
__attribute__((unused));
|
||||
|
||||
static __attribute__((used)) EFI_STATUS
|
||||
security2_policy_authentication (
|
||||
const EFI_SECURITY2_PROTOCOL *This,
|
||||
const EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
||||
VOID *FileBuffer,
|
||||
UINTN FileSize,
|
||||
BOOLEAN BootPolicy
|
||||
)
|
||||
{
|
||||
EFI_STATUS status, auth;
|
||||
|
||||
/* Chain original security policy */
|
||||
|
||||
status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer,
|
||||
FileSize, BootPolicy);
|
||||
|
||||
/* if OK, don't bother with MOK check */
|
||||
if (status == EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (extra_check)
|
||||
auth = extra_check(FileBuffer, FileSize);
|
||||
else
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
|
||||
if (auth == EFI_SECURITY_VIOLATION || auth == EFI_ACCESS_DENIED)
|
||||
/* return previous status, which is the correct one
|
||||
* for the platform: may be either EFI_ACCESS_DENIED
|
||||
* or EFI_SECURITY_VIOLATION */
|
||||
return status;
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
||||
static __attribute__((used)) EFI_STATUS
|
||||
security_policy_authentication (
|
||||
const EFI_SECURITY_PROTOCOL *This,
|
||||
UINT32 AuthenticationStatus,
|
||||
const EFI_DEVICE_PATH_PROTOCOL *DevicePathConst
|
||||
)
|
||||
{
|
||||
EFI_STATUS status, fail_status;
|
||||
EFI_DEVICE_PATH *DevPath
|
||||
= DuplicateDevicePath((EFI_DEVICE_PATH *)DevicePathConst),
|
||||
*OrigDevPath = DevPath;
|
||||
EFI_HANDLE h;
|
||||
EFI_FILE *f;
|
||||
VOID *FileBuffer;
|
||||
UINTN FileSize;
|
||||
CHAR16* DevPathStr;
|
||||
|
||||
/* Chain original security policy */
|
||||
status = uefi_call_wrapper(esfas, 3, This, AuthenticationStatus,
|
||||
DevicePathConst);
|
||||
|
||||
/* if OK avoid checking MOK: It's a bit expensive to
|
||||
* read the whole file in again (esfas already did this) */
|
||||
if (status == EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
/* capture failure status: may be either EFI_ACCESS_DENIED or
|
||||
* EFI_SECURITY_VIOLATION */
|
||||
fail_status = status;
|
||||
|
||||
status = uefi_call_wrapper(BS->LocateDevicePath, 3,
|
||||
&SIMPLE_FS_PROTOCOL, &DevPath, &h);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
DevPathStr = DevicePathToStr(DevPath);
|
||||
|
||||
status = simple_file_open_by_handle(h, DevPathStr, &f,
|
||||
EFI_FILE_MODE_READ);
|
||||
FreePool(DevPathStr);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
status = simple_file_read_all(f, &FileSize, &FileBuffer);
|
||||
simple_file_close(f);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
if (extra_check)
|
||||
status = extra_check(FileBuffer, FileSize);
|
||||
else
|
||||
status = EFI_SECURITY_VIOLATION;
|
||||
FreePool(FileBuffer);
|
||||
|
||||
if (status == EFI_ACCESS_DENIED || status == EFI_SECURITY_VIOLATION)
|
||||
/* return what the platform originally said */
|
||||
status = fail_status;
|
||||
out:
|
||||
FreePool(OrigDevPath);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Nasty: ELF and EFI have different calling conventions. Here is the map for
|
||||
* calling ELF -> EFI
|
||||
*
|
||||
* 1) rdi -> rcx (32 saved)
|
||||
* 2) rsi -> rdx (32 saved)
|
||||
* 3) rdx -> r8 ( 32 saved)
|
||||
* 4) rcx -> r9 (32 saved)
|
||||
* 5) r8 -> 32(%rsp) (48 saved)
|
||||
* 6) r9 -> 40(%rsp) (48 saved)
|
||||
* 7) pad+0(%rsp) -> 48(%rsp) (64 saved)
|
||||
* 8) pad+8(%rsp) -> 56(%rsp) (64 saved)
|
||||
* 9) pad+16(%rsp) -> 64(%rsp) (80 saved)
|
||||
* 10) pad+24(%rsp) -> 72(%rsp) (80 saved)
|
||||
* 11) pad+32(%rsp) -> 80(%rsp) (96 saved)
|
||||
|
||||
*
|
||||
* So for a five argument callback, the map is ignore the first two arguments
|
||||
* and then map (EFI -> ELF) assuming pad = 0.
|
||||
*
|
||||
* ARG4 -> ARG1
|
||||
* ARG3 -> ARG2
|
||||
* ARG5 -> ARG3
|
||||
* ARG6 -> ARG4
|
||||
* ARG11 -> ARG5
|
||||
*
|
||||
* Calling conventions also differ over volatile and preserved registers in
|
||||
* MS: RBX, RBP, RDI, RSI, R12, R13, R14, and R15 are considered nonvolatile .
|
||||
* In ELF: Registers %rbp, %rbx and %r12 through %r15 “belong” to the calling
|
||||
* function and the called function is required to preserve their values.
|
||||
*
|
||||
* This means when accepting a function callback from MS -> ELF, we have to do
|
||||
* separate preservation on %rdi, %rsi before swizzling the arguments and
|
||||
* handing off to the ELF function.
|
||||
*/
|
||||
|
||||
asm (
|
||||
".type security2_policy_authentication,@function\n"
|
||||
"thunk_security2_policy_authentication:\n\t"
|
||||
"mov 0x28(%rsp), %r10 # ARG5\n\t"
|
||||
"push %rdi\n\t"
|
||||
"push %rsi\n\t"
|
||||
"mov %r10, %rdi\n\t"
|
||||
"subq $8, %rsp # space for storing stack pad\n\t"
|
||||
"mov $0x08, %rax\n\t"
|
||||
"mov $0x10, %r10\n\t"
|
||||
"and %rsp, %rax\n\t"
|
||||
"cmovnz %rax, %r11\n\t"
|
||||
"cmovz %r10, %r11\n\t"
|
||||
"subq %r11, %rsp\n\t"
|
||||
"addq $8, %r11\n\t"
|
||||
"mov %r11, (%rsp)\n\t"
|
||||
"# five argument swizzle\n\t"
|
||||
"mov %rdi, %r10\n\t"
|
||||
"mov %rcx, %rdi\n\t"
|
||||
"mov %rdx, %rsi\n\t"
|
||||
"mov %r8, %rdx\n\t"
|
||||
"mov %r9, %rcx\n\t"
|
||||
"mov %r10, %r8\n\t"
|
||||
"callq security2_policy_authentication@PLT\n\t"
|
||||
"mov (%rsp), %r11\n\t"
|
||||
"addq %r11, %rsp\n\t"
|
||||
"pop %rsi\n\t"
|
||||
"pop %rdi\n\t"
|
||||
"ret\n"
|
||||
);
|
||||
|
||||
asm (
|
||||
".type security_policy_authentication,@function\n"
|
||||
"thunk_security_policy_authentication:\n\t"
|
||||
"push %rdi\n\t"
|
||||
"push %rsi\n\t"
|
||||
"subq $8, %rsp # space for storing stack pad\n\t"
|
||||
"mov $0x08, %rax\n\t"
|
||||
"mov $0x10, %r10\n\t"
|
||||
"and %rsp, %rax\n\t"
|
||||
"cmovnz %rax, %r11\n\t"
|
||||
"cmovz %r10, %r11\n\t"
|
||||
"subq %r11, %rsp\n\t"
|
||||
"addq $8, %r11\n\t"
|
||||
"mov %r11, (%rsp)\n\t"
|
||||
"# three argument swizzle\n\t"
|
||||
"mov %rcx, %rdi\n\t"
|
||||
"mov %rdx, %rsi\n\t"
|
||||
"mov %r8, %rdx\n\t"
|
||||
"callq security_policy_authentication@PLT\n\t"
|
||||
"mov (%rsp), %r11\n\t"
|
||||
"addq %r11, %rsp\n\t"
|
||||
"pop %rsi\n\t"
|
||||
"pop %rdi\n\t"
|
||||
"ret\n"
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
security_policy_install(SecurityHook hook)
|
||||
{
|
||||
EFI_SECURITY_PROTOCOL *security_protocol;
|
||||
EFI_SECURITY2_PROTOCOL *security2_protocol = NULL;
|
||||
EFI_STATUS status;
|
||||
|
||||
if (esfas)
|
||||
/* Already Installed */
|
||||
return EFI_ALREADY_STARTED;
|
||||
|
||||
/* Don't bother with status here. The call is allowed
|
||||
* to fail, since SECURITY2 was introduced in PI 1.2.1
|
||||
* If it fails, use security2_protocol == NULL as indicator */
|
||||
uefi_call_wrapper(BS->LocateProtocol, 3,
|
||||
&SECURITY2_PROTOCOL_GUID, NULL,
|
||||
&security2_protocol);
|
||||
|
||||
status = uefi_call_wrapper(BS->LocateProtocol, 3,
|
||||
&SECURITY_PROTOCOL_GUID, NULL,
|
||||
&security_protocol);
|
||||
if (status != EFI_SUCCESS)
|
||||
/* This one is mandatory, so there's a serious problem */
|
||||
return status;
|
||||
|
||||
if (security2_protocol) {
|
||||
es2fa = security2_protocol->FileAuthentication;
|
||||
security2_protocol->FileAuthentication =
|
||||
thunk_security2_policy_authentication;
|
||||
}
|
||||
|
||||
esfas = security_protocol->FileAuthenticationState;
|
||||
security_protocol->FileAuthenticationState =
|
||||
thunk_security_policy_authentication;
|
||||
|
||||
if (hook)
|
||||
extra_check = hook;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
security_policy_uninstall(void)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
|
||||
if (esfas) {
|
||||
EFI_SECURITY_PROTOCOL *security_protocol;
|
||||
|
||||
status = uefi_call_wrapper(BS->LocateProtocol, 3,
|
||||
&SECURITY_PROTOCOL_GUID, NULL,
|
||||
&security_protocol);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
security_protocol->FileAuthenticationState = esfas;
|
||||
esfas = NULL;
|
||||
} else {
|
||||
/* nothing installed */
|
||||
return EFI_NOT_STARTED;
|
||||
}
|
||||
|
||||
if (es2fa) {
|
||||
EFI_SECURITY2_PROTOCOL *security2_protocol;
|
||||
|
||||
status = uefi_call_wrapper(BS->LocateProtocol, 3,
|
||||
&SECURITY2_PROTOCOL_GUID, NULL,
|
||||
&security2_protocol);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
security2_protocol->FileAuthentication = es2fa;
|
||||
es2fa = NULL;
|
||||
}
|
||||
|
||||
if (extra_check)
|
||||
extra_check = NULL;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
security_protocol_set_hashes(unsigned char *esl, int len)
|
||||
{
|
||||
security_policy_esl = esl;
|
||||
security_policy_esl_len = len;
|
||||
}
|
||||
#endif /* OVERRIDE_SECURITY_POLICY */
|
57
lib/shell.c
Normal file
57
lib/shell.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
||||
*
|
||||
* see COPYING file
|
||||
*
|
||||
* misc shell helper functions
|
||||
*/
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include <shell.h>
|
||||
|
||||
EFI_STATUS
|
||||
argsplit(EFI_HANDLE image, int *argc, CHAR16*** ARGV)
|
||||
{
|
||||
int i, count = 1;
|
||||
EFI_STATUS status;
|
||||
EFI_LOADED_IMAGE *info;
|
||||
CHAR16 *start;
|
||||
|
||||
*argc = 0;
|
||||
|
||||
status = uefi_call_wrapper(BS->HandleProtocol, 3, image, &LoadedImageProtocol, (VOID **) &info);
|
||||
if (EFI_ERROR(status)) {
|
||||
Print(L"Failed to get arguments\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
for (i = 0; i < info->LoadOptionsSize; i += 2) {
|
||||
CHAR16 *c = (CHAR16 *)(info->LoadOptions + i);
|
||||
if (*c == L' ' && *(c+1) != '\0') {
|
||||
(*argc)++;
|
||||
}
|
||||
}
|
||||
|
||||
(*argc)++; /* we counted spaces, so add one for initial */
|
||||
|
||||
*ARGV = AllocatePool(*argc * sizeof(*ARGV));
|
||||
if (!*ARGV) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
(*ARGV)[0] = (CHAR16 *)info->LoadOptions;
|
||||
for (i = 0; i < info->LoadOptionsSize; i += 2) {
|
||||
CHAR16 *c = (CHAR16 *)(info->LoadOptions + i);
|
||||
if (*c == L' ') {
|
||||
*c = L'\0';
|
||||
if (*(c + 1) == '\0')
|
||||
/* strip trailing space */
|
||||
break;
|
||||
start = c + 1;
|
||||
(*ARGV)[count++] = start;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
528
lib/simple_file.c
Normal file
528
lib/simple_file.c
Normal file
@ -0,0 +1,528 @@
|
||||
/*
|
||||
* Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
||||
*
|
||||
* see COPYING file
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include <console.h>
|
||||
#include <simple_file.h>
|
||||
#include <efiauthenticated.h>
|
||||
#include <execute.h> /* for generate_path() */
|
||||
|
||||
static EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL;
|
||||
static EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL;
|
||||
static EFI_GUID FILE_INFO = EFI_FILE_INFO_ID;
|
||||
static EFI_GUID FS_INFO = EFI_FILE_SYSTEM_INFO_ID;
|
||||
|
||||
EFI_STATUS
|
||||
simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode)
|
||||
{
|
||||
EFI_STATUS efi_status;
|
||||
EFI_FILE_IO_INTERFACE *drive;
|
||||
EFI_FILE *root;
|
||||
|
||||
efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device,
|
||||
&SIMPLE_FS_PROTOCOL, (void **)&drive);
|
||||
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
Print(L"Unable to find simple file protocol (%d)\n", efi_status);
|
||||
goto error;
|
||||
}
|
||||
|
||||
efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
|
||||
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
Print(L"Failed to open drive volume (%d)\n", efi_status);
|
||||
goto error;
|
||||
}
|
||||
|
||||
efi_status = uefi_call_wrapper(root->Open, 5, root, file, name,
|
||||
mode, 0);
|
||||
|
||||
error:
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
simple_file_open(EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode)
|
||||
{
|
||||
EFI_STATUS efi_status;
|
||||
EFI_HANDLE device;
|
||||
EFI_LOADED_IMAGE *li;
|
||||
EFI_DEVICE_PATH *loadpath = NULL;
|
||||
CHAR16 *PathName = NULL;
|
||||
|
||||
efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image,
|
||||
&IMAGE_PROTOCOL, (void **)&li);
|
||||
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
return simple_file_open_by_handle(image, name, file, mode);
|
||||
|
||||
efi_status = generate_path(name, li, &loadpath, &PathName);
|
||||
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
Print(L"Unable to generate load path for %s\n", name);
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
device = li->DeviceHandle;
|
||||
|
||||
efi_status = simple_file_open_by_handle(device, PathName, file, mode);
|
||||
|
||||
FreePool(PathName);
|
||||
FreePool(loadpath);
|
||||
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
simple_dir_read_all_by_handle(EFI_HANDLE image, EFI_FILE *file, CHAR16* name, EFI_FILE_INFO **entries,
|
||||
int *count)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
char buf[4096];
|
||||
UINTN size = sizeof(buf);
|
||||
EFI_FILE_INFO *fi = (void *)buf;
|
||||
|
||||
status = uefi_call_wrapper(file->GetInfo, 4, file, &FILE_INFO,
|
||||
&size, fi);
|
||||
if (status != EFI_SUCCESS) {
|
||||
Print(L"Failed to get file info\n");
|
||||
goto out;
|
||||
}
|
||||
if ((fi->Attribute & EFI_FILE_DIRECTORY) == 0) {
|
||||
Print(L"Not a directory %s\n", name);
|
||||
status = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
size = 0;
|
||||
*count = 0;
|
||||
for (;;) {
|
||||
UINTN len = sizeof(buf);
|
||||
status = uefi_call_wrapper(file->Read, 3, file, &len, buf);
|
||||
if (status != EFI_SUCCESS || len == 0)
|
||||
break;
|
||||
(*count)++;
|
||||
size += len;
|
||||
}
|
||||
uefi_call_wrapper(file->SetPosition, 2, file, 0);
|
||||
|
||||
char *ptr = AllocatePool(size);
|
||||
*entries = (EFI_FILE_INFO *)ptr;
|
||||
if (!*entries)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
int i;
|
||||
for (i = 0; i < *count; i++) {
|
||||
UINTN len = size;
|
||||
uefi_call_wrapper(file->Read, 3, file, &len, ptr);
|
||||
ptr += len;
|
||||
size -= len;
|
||||
}
|
||||
status = EFI_SUCCESS;
|
||||
out:
|
||||
simple_file_close(file);
|
||||
if (status != EFI_SUCCESS && *entries) {
|
||||
FreePool(*entries);
|
||||
*entries = NULL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
simple_dir_read_all(EFI_HANDLE image, CHAR16 *name, EFI_FILE_INFO **entries,
|
||||
int *count)
|
||||
{
|
||||
EFI_FILE *file;
|
||||
EFI_STATUS status;
|
||||
|
||||
status = simple_file_open(image, name, &file, EFI_FILE_MODE_READ);
|
||||
if (status != EFI_SUCCESS) {
|
||||
Print(L"failed to open file %s: %d\n", name, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return simple_dir_read_all_by_handle(image, file, name, entries, count);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer)
|
||||
{
|
||||
EFI_STATUS efi_status;
|
||||
EFI_FILE_INFO *fi;
|
||||
char buf[1024];
|
||||
|
||||
*size = sizeof(buf);
|
||||
fi = (void *)buf;
|
||||
|
||||
|
||||
efi_status = uefi_call_wrapper(file->GetInfo, 4, file, &FILE_INFO,
|
||||
size, fi);
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
Print(L"Failed to get file info\n");
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
*size = fi->FileSize;
|
||||
|
||||
*buffer = AllocatePool(*size);
|
||||
if (!*buffer) {
|
||||
Print(L"Failed to allocate buffer of size %d\n", *size);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
efi_status = uefi_call_wrapper(file->Read, 3, file, size, *buffer);
|
||||
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
|
||||
EFI_STATUS
|
||||
simple_file_write_all(EFI_FILE *file, UINTN size, void *buffer)
|
||||
{
|
||||
EFI_STATUS efi_status;
|
||||
|
||||
efi_status = uefi_call_wrapper(file->Write, 3, file, &size, buffer);
|
||||
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
void
|
||||
simple_file_close(EFI_FILE *file)
|
||||
{
|
||||
uefi_call_wrapper(file->Close, 1, file);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
simple_volume_selector(CHAR16 **title, CHAR16 **selected, EFI_HANDLE *h)
|
||||
{
|
||||
UINTN count, i;
|
||||
EFI_HANDLE *vol_handles = NULL;
|
||||
EFI_STATUS status;
|
||||
CHAR16 **entries;
|
||||
int val;
|
||||
|
||||
uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol,
|
||||
&SIMPLE_FS_PROTOCOL, NULL, &count, &vol_handles);
|
||||
|
||||
if (!count || !vol_handles)
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
entries = AllocatePool(sizeof(CHAR16 *) * (count+1));
|
||||
if (!entries)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
char buf[4096];
|
||||
UINTN size = sizeof(buf);
|
||||
EFI_FILE_SYSTEM_INFO *fi = (void *)buf;
|
||||
EFI_FILE *root;
|
||||
CHAR16 *name;
|
||||
EFI_FILE_IO_INTERFACE *drive;
|
||||
|
||||
status = uefi_call_wrapper(BS->HandleProtocol, 3,
|
||||
vol_handles[i],
|
||||
&SIMPLE_FS_PROTOCOL,
|
||||
(void **)&drive);
|
||||
if (status != EFI_SUCCESS || !drive)
|
||||
continue;
|
||||
|
||||
status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root);
|
||||
if (status != EFI_SUCCESS)
|
||||
continue;
|
||||
|
||||
status = uefi_call_wrapper(root->GetInfo, 4, root, &FS_INFO,
|
||||
&size, fi);
|
||||
if (status != EFI_SUCCESS)
|
||||
continue;
|
||||
|
||||
name = fi->VolumeLabel;
|
||||
|
||||
if (!name || StrLen(name) == 0 || StrCmp(name, L" ") == 0)
|
||||
name = DevicePathToStr(DevicePathFromHandle(vol_handles[i]));
|
||||
|
||||
entries[i] = AllocatePool((StrLen(name) + 2) * sizeof(CHAR16));
|
||||
if (!entries[i])
|
||||
break;
|
||||
StrCpy(entries[i], name);
|
||||
}
|
||||
entries[i] = NULL;
|
||||
|
||||
val = console_select(title, entries, 0);
|
||||
|
||||
if (val >= 0) {
|
||||
*selected = AllocatePool((StrLen(entries[val]) + 1) * sizeof(CHAR16));
|
||||
if (*selected) {
|
||||
StrCpy(*selected , entries[val]);
|
||||
}
|
||||
*h = vol_handles[val];
|
||||
} else {
|
||||
*selected = NULL;
|
||||
*h = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (entries[i])
|
||||
FreePool(entries[i]);
|
||||
}
|
||||
FreePool(entries);
|
||||
FreePool(vol_handles);
|
||||
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
simple_dir_filter(EFI_HANDLE image, CHAR16 *name, CHAR16 *filter,
|
||||
CHAR16 ***result, int *count, EFI_FILE_INFO **entries)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
int tot, offs = StrLen(filter), i, c, filtercount = 1;
|
||||
EFI_FILE_INFO *next;
|
||||
void *ptr;
|
||||
CHAR16 *newfilter = AllocatePool((StrLen(filter) + 1) * sizeof(CHAR16)),
|
||||
**filterarr;
|
||||
|
||||
if (!newfilter)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
/* just in case efi ever stops writeable strings */
|
||||
StrCpy(newfilter, filter);
|
||||
|
||||
for (i = 0; i < offs; i++) {
|
||||
if (filter[i] == '|')
|
||||
filtercount++;
|
||||
}
|
||||
filterarr = AllocatePool(filtercount * sizeof(void *));
|
||||
if (!filterarr)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
c = 0;
|
||||
filterarr[c++] = newfilter;
|
||||
for (i = 0; i < offs; i++) {
|
||||
if (filter[i] == '|') {
|
||||
newfilter[i] = '\0';
|
||||
filterarr[c++] = &newfilter[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
*count = 0;
|
||||
|
||||
status = simple_dir_read_all(image, name, entries, &tot);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
goto out;
|
||||
ptr = next = *entries;
|
||||
|
||||
for (i = 0; i < tot; i++) {
|
||||
int len = StrLen(next->FileName);
|
||||
|
||||
for (c = 0; c < filtercount; c++) {
|
||||
offs = StrLen(filterarr[c]);
|
||||
|
||||
if (StrCmp(&next->FileName[len - offs], filterarr[c]) == 0
|
||||
|| (next->Attribute & EFI_FILE_DIRECTORY)) {
|
||||
(*count)++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ptr += OFFSET_OF(EFI_FILE_INFO, FileName) + (len + 1)*sizeof(CHAR16);
|
||||
next = ptr;
|
||||
}
|
||||
if (*count)
|
||||
*result = AllocatePool(((*count) + 1) * sizeof(void *));
|
||||
else
|
||||
*result = AllocatePool(2 * sizeof(void *));
|
||||
|
||||
*count = 0;
|
||||
ptr = next = *entries;
|
||||
|
||||
for (i = 0; i < tot; i++) {
|
||||
int len = StrLen(next->FileName);
|
||||
|
||||
if (StrCmp(next->FileName, L".") == 0)
|
||||
/* ignore . directory */
|
||||
goto next;
|
||||
|
||||
if (next->Attribute & EFI_FILE_DIRECTORY) {
|
||||
(*result)[(*count)] = PoolPrint(L"%s/", next->FileName);
|
||||
if (!(*result)[(*count)]) {
|
||||
Print(L"Failed to allocate buffer");
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
(*count)++;
|
||||
goto next;
|
||||
}
|
||||
|
||||
for (c = 0; c < filtercount; c++) {
|
||||
offs = StrLen(filterarr[c]);
|
||||
|
||||
if (StrCmp(&next->FileName[len - offs], filterarr[c]) == 0) {
|
||||
(*result)[(*count)] = StrDuplicate(next->FileName);
|
||||
if (!(*result)[(*count)]) {
|
||||
Print(L"Failed to allocate buffer");
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
(*count)++;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
next:
|
||||
if (StrCmp(next->FileName, L"..") == 0) {
|
||||
/* place .. directory first */
|
||||
CHAR16 *tmp = (*result)[(*count) - 1];
|
||||
|
||||
(*result)[(*count) - 1] = (*result)[0];
|
||||
(*result)[0] = tmp;
|
||||
}
|
||||
|
||||
ptr += OFFSET_OF(EFI_FILE_INFO, FileName) + (len + 1)*sizeof(CHAR16);
|
||||
next = ptr;
|
||||
}
|
||||
if (*count == 0) {
|
||||
/* no entries at all ... can happen because top level dir has no . or .. */
|
||||
(*result)[(*count)++] = L"./";
|
||||
}
|
||||
(*result)[*count] = NULL;
|
||||
status = EFI_SUCCESS;
|
||||
|
||||
out:
|
||||
if (status != EFI_SUCCESS) {
|
||||
if (*entries)
|
||||
FreePool(*entries);
|
||||
*entries = NULL;
|
||||
if (*result)
|
||||
FreePool(*result);
|
||||
*result = NULL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
free_entries(CHAR16 **entries, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i<count; i++)
|
||||
FreePool(entries[i]);
|
||||
}
|
||||
|
||||
void
|
||||
simple_file_selector(EFI_HANDLE *im, CHAR16 **title, CHAR16 *name,
|
||||
CHAR16 *filter, CHAR16 **result)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
CHAR16 **entries;
|
||||
EFI_FILE_INFO *dmp;
|
||||
int count, select, len;
|
||||
CHAR16 *newname, *selected;
|
||||
|
||||
*result = NULL;
|
||||
if (!name)
|
||||
name = L"\\";
|
||||
if (!filter)
|
||||
filter = L"";
|
||||
if (!*im) {
|
||||
EFI_HANDLE h;
|
||||
CHAR16 *volname;
|
||||
|
||||
simple_volume_selector(title, &volname, &h);
|
||||
if (!volname)
|
||||
return;
|
||||
FreePool(volname);
|
||||
*im = h;
|
||||
}
|
||||
|
||||
newname = AllocatePool((StrLen(name) + 1)*sizeof(CHAR16));
|
||||
if (!newname)
|
||||
return;
|
||||
|
||||
StrCpy(newname, name);
|
||||
name = newname;
|
||||
|
||||
redo:
|
||||
status = simple_dir_filter(*im, name, filter, &entries, &count, &dmp);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
goto out_free_name;
|
||||
|
||||
select = console_select(title, entries, 0);
|
||||
if (select < 0)
|
||||
/* ESC key */
|
||||
goto out_free;
|
||||
selected = entries[select];
|
||||
/* note that memory used by selected is valid until dmp is freed */
|
||||
len = StrLen(selected);
|
||||
if (selected[len - 1] == '/') {
|
||||
CHAR16 *newname;
|
||||
|
||||
/* stay where we are */
|
||||
if (StrCmp(selected, L"./") == 0) {
|
||||
free_entries(entries, count);
|
||||
FreePool(entries);
|
||||
entries = NULL;
|
||||
FreePool(dmp);
|
||||
goto redo;
|
||||
} else if (StrCmp(selected, L"../") == 0) {
|
||||
int i;
|
||||
|
||||
i = StrLen(name) - 1;
|
||||
|
||||
|
||||
for (i = StrLen(name); i > 0; --i) {
|
||||
if (name[i] == '\\')
|
||||
break;
|
||||
}
|
||||
if (i == 0)
|
||||
i = 1;
|
||||
|
||||
if (StrCmp(name, L"\\") != 0
|
||||
&& StrCmp(&name[i], L"..") != 0) {
|
||||
name[i] = '\0';
|
||||
free_entries(entries, count);
|
||||
FreePool(entries);
|
||||
entries = NULL;
|
||||
FreePool(dmp);
|
||||
goto redo;
|
||||
}
|
||||
}
|
||||
newname = AllocatePool((StrLen(name) + len + 2)*sizeof(CHAR16));
|
||||
if (!newname)
|
||||
goto out_free;
|
||||
StrCpy(newname, name);
|
||||
|
||||
if (name[StrLen(name) - 1] != '\\')
|
||||
StrCat(newname, L"\\");
|
||||
StrCat(newname, selected);
|
||||
/* remove trailing / */
|
||||
newname[StrLen(newname) - 1] = '\0';
|
||||
|
||||
free_entries(entries, count);
|
||||
FreePool(entries);
|
||||
entries = NULL;
|
||||
FreePool(dmp);
|
||||
FreePool(name);
|
||||
name = newname;
|
||||
|
||||
goto redo;
|
||||
}
|
||||
*result = AllocatePool((StrLen(name) + len + 2)*sizeof(CHAR16));
|
||||
if (*result) {
|
||||
StrCpy(*result, name);
|
||||
if (name[StrLen(name) - 1] != '\\')
|
||||
StrCat(*result, L"\\");
|
||||
StrCat(*result, selected);
|
||||
}
|
||||
|
||||
out_free:
|
||||
FreePool(dmp);
|
||||
if (entries) {
|
||||
free_entries(entries, count);
|
||||
FreePool(entries);
|
||||
}
|
||||
out_free_name:
|
||||
FreePool(name);
|
||||
}
|
339
lib/variables.c
Normal file
339
lib/variables.c
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Copyright 2012 <James.Bottomley@HansenPartnership.com>
|
||||
*
|
||||
* see COPYING file
|
||||
*
|
||||
* Portions of this file are a direct cut and paste from Tianocore
|
||||
* (http://tianocore.sf.net)
|
||||
*
|
||||
* SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
|
||||
*
|
||||
* Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
|
||||
* This program and the accompanying materials
|
||||
* are licensed and made available under the terms and conditions of the BSD License
|
||||
* which accompanies this distribution. The full text of the license may be found
|
||||
* at
|
||||
* http://opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
*
|
||||
*/
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include <efiauthenticated.h>
|
||||
|
||||
#include <variables.h>
|
||||
#include <guid.h>
|
||||
#include <console.h>
|
||||
#include <errors.h>
|
||||
|
||||
EFI_STATUS
|
||||
variable_create_esl(void *cert, int cert_len, EFI_GUID *type, EFI_GUID *owner,
|
||||
void **out, int *outlen)
|
||||
{
|
||||
*outlen = cert_len + sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID);
|
||||
|
||||
*out = AllocateZeroPool(*outlen);
|
||||
if (!*out)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
EFI_SIGNATURE_LIST *sl = *out;
|
||||
|
||||
sl->SignatureHeaderSize = 0;
|
||||
sl->SignatureType = *type;
|
||||
sl->SignatureSize = cert_len + sizeof(EFI_GUID);
|
||||
sl->SignatureListSize = *outlen;
|
||||
|
||||
EFI_SIGNATURE_DATA *sd = *out + sizeof(EFI_SIGNATURE_LIST);
|
||||
|
||||
if (owner)
|
||||
sd->SignatureOwner = *owner;
|
||||
|
||||
CopyMem(sd->SignatureData, cert, cert_len);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
EFI_STATUS
|
||||
CreateTimeBasedPayload (
|
||||
IN OUT UINTN *DataSize,
|
||||
IN OUT UINT8 **Data
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT8 *NewData;
|
||||
UINT8 *Payload;
|
||||
UINTN PayloadSize;
|
||||
EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;
|
||||
UINTN DescriptorSize;
|
||||
EFI_TIME Time;
|
||||
EFI_GUID efi_cert_type = EFI_CERT_TYPE_PKCS7_GUID;
|
||||
|
||||
if (Data == NULL || DataSize == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// In Setup mode or Custom mode, the variable does not need to be signed but the
|
||||
// parameters to the SetVariable() call still need to be prepared as authenticated
|
||||
// variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
|
||||
// data in it.
|
||||
//
|
||||
Payload = *Data;
|
||||
PayloadSize = *DataSize;
|
||||
|
||||
DescriptorSize = OFFSET_OF(EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);
|
||||
NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize);
|
||||
if (NewData == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
if ((Payload != NULL) && (PayloadSize != 0)) {
|
||||
CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
|
||||
}
|
||||
|
||||
DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
|
||||
|
||||
ZeroMem (&Time, sizeof (EFI_TIME));
|
||||
Status = uefi_call_wrapper(RT->GetTime,2, &Time, NULL);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool(NewData);
|
||||
return Status;
|
||||
}
|
||||
Time.Pad1 = 0;
|
||||
Time.Nanosecond = 0;
|
||||
Time.TimeZone = 0;
|
||||
Time.Daylight = 0;
|
||||
Time.Pad2 = 0;
|
||||
CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
|
||||
|
||||
DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
|
||||
DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
|
||||
DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
|
||||
DescriptorData->AuthInfo.CertType = efi_cert_type;
|
||||
|
||||
/* we're expecting an EFI signature list, so don't free the input since
|
||||
* it might not be in a pool */
|
||||
#if 0
|
||||
if (Payload != NULL) {
|
||||
FreePool(Payload);
|
||||
}
|
||||
#endif
|
||||
|
||||
*DataSize = DescriptorSize + PayloadSize;
|
||||
*Data = NewData;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
SetSecureVariable(CHAR16 *var, UINT8 *Data, UINTN len, EFI_GUID owner,
|
||||
UINT32 options, int createtimebased)
|
||||
{
|
||||
EFI_SIGNATURE_LIST *Cert;
|
||||
UINTN DataSize;
|
||||
EFI_STATUS efi_status;
|
||||
|
||||
/* Microsoft request: Bugs in some UEFI platforms mean that PK or any
|
||||
* other secure variable can be updated or deleted programmatically,
|
||||
* so prevent */
|
||||
if (!variable_is_setupmode())
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
|
||||
if (createtimebased) {
|
||||
int ds;
|
||||
efi_status = variable_create_esl(Data, len, &X509_GUID, NULL,
|
||||
(void **)&Cert, &ds);
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
Print(L"Failed to create %s certificate %d\n", var, efi_status);
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
DataSize = ds;
|
||||
} else {
|
||||
/* we expect an efi signature list rather than creating it */
|
||||
Cert = (EFI_SIGNATURE_LIST *)Data;
|
||||
DataSize = len;
|
||||
}
|
||||
efi_status = CreateTimeBasedPayload(&DataSize, (UINT8 **)&Cert);
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
Print(L"Failed to create time based payload %d\n", efi_status);
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
efi_status = uefi_call_wrapper(RT->SetVariable, 5, var, &owner,
|
||||
EFI_VARIABLE_NON_VOLATILE
|
||||
| EFI_VARIABLE_RUNTIME_ACCESS
|
||||
| EFI_VARIABLE_BOOTSERVICE_ACCESS
|
||||
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
|
||||
| options,
|
||||
DataSize, Cert);
|
||||
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
UINT64
|
||||
GetOSIndications(void)
|
||||
{
|
||||
UINT64 indications;
|
||||
UINTN DataSize = sizeof(indications);
|
||||
EFI_STATUS efi_status;
|
||||
|
||||
efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"OsIndicationsSupported", &GV_GUID, NULL, &DataSize, &indications);
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
return 0;
|
||||
|
||||
return indications;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
SETOSIndicationsAndReboot(UINT64 indications)
|
||||
{
|
||||
UINTN DataSize = sizeof(indications);
|
||||
EFI_STATUS efi_status;
|
||||
|
||||
efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"OsIndications",
|
||||
&GV_GUID,
|
||||
EFI_VARIABLE_NON_VOLATILE
|
||||
| EFI_VARIABLE_RUNTIME_ACCESS
|
||||
| EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
||||
DataSize, &indications);
|
||||
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
return efi_status;
|
||||
|
||||
uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0, NULL);
|
||||
/* does not return */
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
get_variable_attr(CHAR16 *var, UINT8 **data, UINTN *len, EFI_GUID owner,
|
||||
UINT32 *attributes)
|
||||
{
|
||||
EFI_STATUS efi_status;
|
||||
|
||||
*len = 0;
|
||||
|
||||
efi_status = uefi_call_wrapper(RT->GetVariable, 5, var, &owner,
|
||||
NULL, len, NULL);
|
||||
if (efi_status != EFI_BUFFER_TOO_SMALL)
|
||||
return efi_status;
|
||||
|
||||
*data = AllocateZeroPool(*len);
|
||||
if (!data)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
efi_status = uefi_call_wrapper(RT->GetVariable, 5, var, &owner,
|
||||
attributes, len, *data);
|
||||
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
FreePool(*data);
|
||||
*data = NULL;
|
||||
}
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
get_variable(CHAR16 *var, UINT8 **data, UINTN *len, EFI_GUID owner)
|
||||
{
|
||||
return get_variable_attr(var, data, len, owner, NULL);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
find_in_esl(UINT8 *Data, UINTN DataSize, UINT8 *key, UINTN keylen)
|
||||
{
|
||||
EFI_SIGNATURE_LIST *CertList;
|
||||
|
||||
certlist_for_each_certentry(CertList, Data, DataSize, DataSize) {
|
||||
if (CertList->SignatureSize != keylen + sizeof(EFI_GUID))
|
||||
continue;
|
||||
EFI_SIGNATURE_DATA *Cert;
|
||||
|
||||
certentry_for_each_cert(Cert, CertList)
|
||||
if (CompareMem (Cert->SignatureData, key, keylen) == 0)
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
find_in_variable_esl(CHAR16* var, EFI_GUID owner, UINT8 *key, UINTN keylen)
|
||||
{
|
||||
UINTN DataSize;
|
||||
UINT8 *Data;
|
||||
EFI_STATUS status;
|
||||
|
||||
status = get_variable(var, &Data, &DataSize, owner);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = find_in_esl(Data, DataSize, key, keylen);
|
||||
|
||||
FreePool(Data);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
variable_is_setupmode(void)
|
||||
{
|
||||
/* set to 1 because we return true if SetupMode doesn't exist */
|
||||
UINT8 SetupMode = 1;
|
||||
UINTN DataSize = sizeof(SetupMode);
|
||||
|
||||
uefi_call_wrapper(RT->GetVariable, 5, L"SetupMode", &GV_GUID, NULL,
|
||||
&DataSize, &SetupMode);
|
||||
|
||||
return SetupMode;
|
||||
}
|
||||
|
||||
int
|
||||
variable_is_secureboot(void)
|
||||
{
|
||||
/* return false if variable doesn't exist */
|
||||
UINT8 SecureBoot = 0;
|
||||
UINTN DataSize;
|
||||
|
||||
DataSize = sizeof(SecureBoot);
|
||||
uefi_call_wrapper(RT->GetVariable, 5, L"SecureBoot", &GV_GUID, NULL,
|
||||
&DataSize, &SecureBoot);
|
||||
|
||||
return SecureBoot;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
variable_enroll_hash(CHAR16 *var, EFI_GUID owner,
|
||||
UINT8 hash[SHA256_DIGEST_SIZE])
|
||||
{
|
||||
EFI_STATUS status;
|
||||
|
||||
if (find_in_variable_esl(var, owner, hash, SHA256_DIGEST_SIZE)
|
||||
== EFI_SUCCESS)
|
||||
/* hash already present */
|
||||
return EFI_ALREADY_STARTED;
|
||||
|
||||
UINT8 sig[sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + SHA256_DIGEST_SIZE];
|
||||
EFI_SIGNATURE_LIST *l = (void *)sig;
|
||||
EFI_SIGNATURE_DATA *d = (void *)sig + sizeof(EFI_SIGNATURE_LIST);
|
||||
SetMem(sig, 0, sizeof(sig));
|
||||
l->SignatureType = EFI_CERT_SHA256_GUID;
|
||||
l->SignatureListSize = sizeof(sig);
|
||||
l->SignatureSize = 16 +32; /* UEFI defined */
|
||||
CopyMem(&d->SignatureData, hash, SHA256_DIGEST_SIZE);
|
||||
d->SignatureOwner = MOK_OWNER;
|
||||
|
||||
if (CompareGuid(&owner, &SIG_DB) == 0)
|
||||
status = SetSecureVariable(var, sig, sizeof(sig), owner,
|
||||
EFI_VARIABLE_APPEND_WRITE, 0);
|
||||
else
|
||||
status = uefi_call_wrapper(RT->SetVariable, 5, var, &owner,
|
||||
EFI_VARIABLE_NON_VOLATILE
|
||||
| EFI_VARIABLE_BOOTSERVICE_ACCESS
|
||||
| EFI_VARIABLE_APPEND_WRITE,
|
||||
sizeof(sig), sig);
|
||||
return status;
|
||||
}
|
110
netboot.c
110
netboot.c
@ -39,7 +39,6 @@
|
||||
#include "shim.h"
|
||||
#include "netboot.h"
|
||||
|
||||
|
||||
static inline unsigned short int __swap16(unsigned short int x)
|
||||
{
|
||||
__asm__("xchgb %b0,%h0"
|
||||
@ -53,7 +52,7 @@ static inline unsigned short int __swap16(unsigned short int x)
|
||||
|
||||
static EFI_PXE_BASE_CODE *pxe;
|
||||
static EFI_IP_ADDRESS tftp_addr;
|
||||
static char *full_path;
|
||||
static CHAR8 *full_path;
|
||||
|
||||
|
||||
typedef struct {
|
||||
@ -62,6 +61,24 @@ typedef struct {
|
||||
UINT8 Data[1];
|
||||
} EFI_DHCP6_PACKET_OPTION;
|
||||
|
||||
static CHAR8 *
|
||||
translate_slashes(char *str)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
if (str == NULL)
|
||||
return (CHAR8 *)str;
|
||||
|
||||
for (i = 0, j = 0; str[i] != '\0'; i++, j++) {
|
||||
if (str[i] == '\\') {
|
||||
str[j] = '/';
|
||||
if (str[i+1] == '\\')
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return (CHAR8 *)str;
|
||||
}
|
||||
|
||||
/*
|
||||
* usingNetboot
|
||||
* Returns TRUE if we identify a protocol that is enabled and Providing us with
|
||||
@ -111,7 +128,7 @@ try_again:
|
||||
for (i=0; i < (bs / sizeof(EFI_HANDLE)); i++) {
|
||||
status = uefi_call_wrapper(BS->OpenProtocol, 6, hbuf[i],
|
||||
&pxe_base_code_protocol,
|
||||
&pxe, image_handle, NULL,
|
||||
(void **)&pxe, image_handle, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
@ -141,11 +158,11 @@ try_again:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static char *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
|
||||
static CHAR8 *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
|
||||
{
|
||||
void *optr;
|
||||
EFI_DHCP6_PACKET_OPTION *option;
|
||||
char *url;
|
||||
CHAR8 *url;
|
||||
UINT32 urllen;
|
||||
|
||||
optr = pkt->DhcpOptions;
|
||||
@ -159,10 +176,9 @@ static char *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
|
||||
if (ntohs(option->OpCode) == 59) {
|
||||
/* This is the bootfile url option */
|
||||
urllen = ntohs(option->Length);
|
||||
url = AllocatePool(urllen+2);
|
||||
url = AllocateZeroPool(urllen+1);
|
||||
if (!url)
|
||||
return NULL;
|
||||
memset(url, 0, urllen+2);
|
||||
memcpy(url, option->Data, urllen);
|
||||
return url;
|
||||
}
|
||||
@ -172,10 +188,10 @@ static char *get_v6_bootfile_url(EFI_PXE_BASE_CODE_DHCPV6_PACKET *pkt)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static UINT16 str2ns(UINT8 *str)
|
||||
static CHAR16 str2ns(CHAR8 *str)
|
||||
{
|
||||
UINT16 ret = 0;
|
||||
UINT8 v;
|
||||
CHAR16 ret = 0;
|
||||
CHAR8 v;
|
||||
for(;*str;str++) {
|
||||
if ('0' <= *str && *str <= '9')
|
||||
v = *str - '0';
|
||||
@ -190,18 +206,18 @@ static UINT16 str2ns(UINT8 *str)
|
||||
return htons(ret);
|
||||
}
|
||||
|
||||
static UINT8 *str2ip6(char *str)
|
||||
static CHAR8 *str2ip6(CHAR8 *str)
|
||||
{
|
||||
UINT8 i, j, p;
|
||||
size_t len;
|
||||
UINT8 *a, *b, t;
|
||||
CHAR8 *a, *b, t;
|
||||
static UINT16 ip[8];
|
||||
|
||||
for(i=0; i < 8; i++) {
|
||||
ip[i] = 0;
|
||||
}
|
||||
len = strlen((UINT8 *)str);
|
||||
a = b = (UINT8 *)str;
|
||||
len = strlen(str);
|
||||
a = b = str;
|
||||
for(i=p=0; i < len; i++, b++) {
|
||||
if (*b != ':')
|
||||
continue;
|
||||
@ -212,7 +228,7 @@ static UINT8 *str2ip6(char *str)
|
||||
if ( *(b+1) == ':' )
|
||||
break;
|
||||
}
|
||||
a = b = (UINT8 *)(str + len);
|
||||
a = b = (str + len);
|
||||
for(j=len, p=7; j > i; j--, a--) {
|
||||
if (*a != ':')
|
||||
continue;
|
||||
@ -222,14 +238,14 @@ static UINT8 *str2ip6(char *str)
|
||||
*b = t;
|
||||
b = a;
|
||||
}
|
||||
return (UINT8 *)ip;
|
||||
return (CHAR8 *)ip;
|
||||
}
|
||||
|
||||
static BOOLEAN extract_tftp_info(char *url)
|
||||
static BOOLEAN extract_tftp_info(CHAR8 *url)
|
||||
{
|
||||
char *start, *end;
|
||||
char ip6str[128];
|
||||
char *template = "/grubx64.efi";
|
||||
CHAR8 *start, *end;
|
||||
CHAR8 ip6str[40];
|
||||
CHAR8 *template = (CHAR8 *)translate_slashes(DEFAULT_LOADER_CHAR);
|
||||
|
||||
if (strncmp((UINT8 *)url, (UINT8 *)"tftp://", 7)) {
|
||||
Print(L"URLS MUST START WITH tftp://\n");
|
||||
@ -245,26 +261,28 @@ static BOOLEAN extract_tftp_info(char *url)
|
||||
end = start;
|
||||
while ((*end != '\0') && (*end != ']')) {
|
||||
end++;
|
||||
if (end - start > 39) {
|
||||
Print(L"TFTP URL includes malformed IPv6 address\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (end == '\0') {
|
||||
Print(L"TFTP SERVER MUST BE ENCLOSED IN [..]\n");
|
||||
return FALSE;
|
||||
}
|
||||
*end = '\0';
|
||||
memset(ip6str, 0, 128);
|
||||
memcpy(ip6str, start, strlen((UINT8 *)start));
|
||||
*end = ']';
|
||||
memset(ip6str, 0, 40);
|
||||
memcpy(ip6str, start, end - start);
|
||||
end++;
|
||||
memcpy(&tftp_addr.v6, str2ip6(ip6str), 16);
|
||||
full_path = AllocatePool(strlen((UINT8 *)end)+strlen((UINT8 *)template)+1);
|
||||
full_path = AllocateZeroPool(strlen(end)+strlen(template)+1);
|
||||
if (!full_path)
|
||||
return FALSE;
|
||||
memset(full_path, 0, strlen((UINT8 *)end)+strlen((UINT8 *)template));
|
||||
memcpy(full_path, end, strlen((UINT8 *)end));
|
||||
end = strrchr(full_path, '/');
|
||||
memcpy(full_path, end, strlen(end));
|
||||
end = (CHAR8 *)strrchr((char *)full_path, '/');
|
||||
if (!end)
|
||||
end = full_path;
|
||||
memcpy(end, template, strlen((UINT8 *)template));
|
||||
end = (CHAR8 *)full_path;
|
||||
memcpy(end, template, strlen(template));
|
||||
end[strlen(template)] = '\0';
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -272,32 +290,30 @@ static BOOLEAN extract_tftp_info(char *url)
|
||||
static EFI_STATUS parseDhcp6()
|
||||
{
|
||||
EFI_PXE_BASE_CODE_DHCPV6_PACKET *packet = (EFI_PXE_BASE_CODE_DHCPV6_PACKET *)&pxe->Mode->DhcpAck.Raw;
|
||||
char *bootfile_url;
|
||||
|
||||
CHAR8 *bootfile_url;
|
||||
|
||||
bootfile_url = get_v6_bootfile_url(packet);
|
||||
if (extract_tftp_info(bootfile_url) == FALSE)
|
||||
return EFI_NOT_FOUND;
|
||||
if (!bootfile_url)
|
||||
return EFI_NOT_FOUND;
|
||||
if (extract_tftp_info(bootfile_url) == FALSE) {
|
||||
FreePool(bootfile_url);
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
FreePool(bootfile_url);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static EFI_STATUS parseDhcp4()
|
||||
{
|
||||
char *template = "/grubx64.efi";
|
||||
char *tmp = AllocatePool(16);
|
||||
CHAR8 *template = (CHAR8 *)DEFAULT_LOADER_CHAR;
|
||||
full_path = AllocateZeroPool(strlen(template)+1);
|
||||
|
||||
|
||||
if (!tmp)
|
||||
if (!full_path)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
|
||||
memcpy(&tftp_addr.v4, pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr, 4);
|
||||
|
||||
memcpy(tmp, template, 12);
|
||||
tmp[13] = '\0';
|
||||
full_path = tmp;
|
||||
memcpy(full_path, template, strlen(template));
|
||||
|
||||
/* Note we don't capture the filename option here because we know its shim.efi
|
||||
* We instead assume the filename at the end of the path is going to be grubx64.efi
|
||||
@ -326,7 +342,7 @@ EFI_STATUS parseNetbootinfo(EFI_HANDLE image_handle)
|
||||
return rc;
|
||||
}
|
||||
|
||||
EFI_STATUS FetchNetbootimage(EFI_HANDLE image_handle, VOID **buffer, UINTN *bufsiz)
|
||||
EFI_STATUS FetchNetbootimage(EFI_HANDLE image_handle, VOID **buffer, UINT64 *bufsiz)
|
||||
{
|
||||
EFI_STATUS rc;
|
||||
EFI_PXE_BASE_CODE_TFTP_OPCODE read = EFI_PXE_BASE_CODE_TFTP_READ_FILE;
|
||||
@ -344,7 +360,7 @@ EFI_STATUS FetchNetbootimage(EFI_HANDLE image_handle, VOID **buffer, UINTN *bufs
|
||||
|
||||
try_again:
|
||||
rc = uefi_call_wrapper(pxe->Mtftp, 10, pxe, read, *buffer, overwrite,
|
||||
&bufsiz, &blksz, &tftp_addr, full_path, NULL, nobuffer);
|
||||
bufsiz, &blksz, &tftp_addr, full_path, NULL, nobuffer);
|
||||
|
||||
if (rc == EFI_BUFFER_TOO_SMALL) {
|
||||
/* try again, doubling buf size */
|
||||
@ -356,6 +372,8 @@ try_again:
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
if (rc != EFI_SUCCESS && *buffer) {
|
||||
FreePool(*buffer);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
147
replacements.c
Normal file
147
replacements.c
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* shim - trivial UEFI first-stage bootloader
|
||||
*
|
||||
* Copyright 2012 Red Hat, Inc <mjg@redhat.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Significant portions of this code are derived from Tianocore
|
||||
* (http://tianocore.sf.net) and are Copyright 2009-2012 Intel
|
||||
* Corporation.
|
||||
*/
|
||||
|
||||
/* Chemical agents lend themselves to covert use in sabotage against
|
||||
* which it is exceedingly difficult to visualize any really effective
|
||||
* defense... I will not dwell upon this use of CBW because, as one
|
||||
* pursues the possibilities of such covert uses, one discovers that the
|
||||
* scenarios resemble that in which the components of a nuclear weapon
|
||||
* are smuggled into New York City and assembled in the basement of the
|
||||
* Empire State Building.
|
||||
* In other words, once the possibility is recognized to exist, about
|
||||
* all that one can do is worry about it.
|
||||
* -- Dr. Ivan L Bennett, Jr., testifying before the Subcommittee on
|
||||
* National Security Policy and Scientific Developments, November 20,
|
||||
* 1969.
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efiapi.h>
|
||||
#include <efilib.h>
|
||||
#include "shim.h"
|
||||
#include "replacements.h"
|
||||
|
||||
/* oh for fuck's sakes.*/
|
||||
#ifndef EFI_SECURITY_VIOLATION
|
||||
#define EFI_SECURITY_VIOLATION 26
|
||||
#endif
|
||||
|
||||
static EFI_SYSTEM_TABLE *systab;
|
||||
|
||||
static typeof(systab->BootServices->StartImage) system_start_image;
|
||||
static typeof(systab->BootServices->Exit) system_exit;
|
||||
static typeof(systab->BootServices->ExitBootServices) system_exit_boot_services;
|
||||
|
||||
extern UINT8 insecure_mode;
|
||||
|
||||
void
|
||||
unhook_system_services(void)
|
||||
{
|
||||
if (insecure_mode)
|
||||
return;
|
||||
systab->BootServices->Exit = system_exit;
|
||||
systab->BootServices->StartImage = system_start_image;
|
||||
systab->BootServices->ExitBootServices = system_exit_boot_services;
|
||||
}
|
||||
|
||||
static EFI_STATUS EFIAPI
|
||||
start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 **exit_data)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
unhook_system_services();
|
||||
status = systab->BootServices->StartImage(image_handle, exit_data_size, exit_data);
|
||||
if (EFI_ERROR(status))
|
||||
hook_system_services(systab);
|
||||
return status;
|
||||
}
|
||||
|
||||
static EFI_STATUS EFIAPI
|
||||
exit_boot_services(EFI_HANDLE image_key, UINTN map_key)
|
||||
{
|
||||
if (loader_is_participating || verification_method == VERIFIED_BY_HASH) {
|
||||
unhook_system_services();
|
||||
EFI_STATUS status;
|
||||
status = systab->BootServices->ExitBootServices(image_key, map_key);
|
||||
if (status != EFI_SUCCESS)
|
||||
hook_system_services(systab);
|
||||
return status;
|
||||
}
|
||||
|
||||
Print(L"Bootloader has not verified loaded image.\n");
|
||||
Print(L"System is compromised. halting.\n");
|
||||
systab->BootServices->Stall(5000000);
|
||||
systab->RuntimeServices->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION, 0, NULL);
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
|
||||
static EFI_STATUS EFIAPI
|
||||
exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus,
|
||||
UINTN ExitDataSize, CHAR16 *ExitData)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
unhook_system_services();
|
||||
|
||||
status = systab->BootServices->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData);
|
||||
if (EFI_ERROR(status))
|
||||
hook_system_services(systab);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hook_system_services(EFI_SYSTEM_TABLE *local_systab)
|
||||
{
|
||||
if (insecure_mode)
|
||||
return;
|
||||
systab = local_systab;
|
||||
|
||||
/* We need to hook various calls to make this work... */
|
||||
|
||||
/* we need StartImage() so that we can allow chain booting to an
|
||||
* image trusted by the firmware */
|
||||
system_start_image = systab->BootServices->StartImage;
|
||||
systab->BootServices->StartImage = start_image;
|
||||
|
||||
/* we need to hook ExitBootServices() so a) we can enforce the policy
|
||||
* and b) we can unwrap when we're done. */
|
||||
system_exit_boot_services = systab->BootServices->ExitBootServices;
|
||||
systab->BootServices->ExitBootServices = exit_boot_services;
|
||||
|
||||
/* we need to hook Exit() so that we can allow users to quit the
|
||||
* bootloader and still e.g. start a new one or run an internal
|
||||
* shell. */
|
||||
system_exit = systab->BootServices->Exit;
|
||||
systab->BootServices->Exit = exit;
|
||||
}
|
44
replacements.h
Normal file
44
replacements.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc <pjones@redhat.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SHIM_REPLACEMENTS_H
|
||||
#define SHIM_REPLACEMENTS_H 1
|
||||
|
||||
typedef enum {
|
||||
VERIFIED_BY_NOTHING,
|
||||
VERIFIED_BY_CERT,
|
||||
VERIFIED_BY_HASH
|
||||
} verification_method_t;
|
||||
|
||||
extern verification_method_t verification_method;
|
||||
extern int loader_is_participating;
|
||||
|
||||
extern void hook_system_services(EFI_SYSTEM_TABLE *local_systab);
|
||||
extern void unhook_system_services(void);
|
||||
|
||||
#endif /* SHIM_REPLACEMENTS_H */
|
499
shim.c
499
shim.c
@ -38,12 +38,18 @@
|
||||
#include <Library/BaseCryptLib.h>
|
||||
#include "PeImage.h"
|
||||
#include "shim.h"
|
||||
#include "signature.h"
|
||||
#include "netboot.h"
|
||||
#include "shim_cert.h"
|
||||
#include "replacements.h"
|
||||
#include "ucs2.h"
|
||||
|
||||
#define DEFAULT_LOADER L"\\grub.efi"
|
||||
#include "guid.h"
|
||||
#include "variables.h"
|
||||
#include "efiauthenticated.h"
|
||||
#include "security_policy.h"
|
||||
#include "console.h"
|
||||
#include "version.h"
|
||||
|
||||
#define FALLBACK L"\\fallback.efi"
|
||||
#define MOK_MANAGER L"\\MokManager.efi"
|
||||
|
||||
@ -54,17 +60,33 @@ static CHAR16 *second_stage;
|
||||
static void *load_options;
|
||||
static UINT32 load_options_size;
|
||||
|
||||
EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
|
||||
|
||||
/*
|
||||
* The vendor certificate used for validating the second stage loader
|
||||
*/
|
||||
extern UINT8 vendor_cert[];
|
||||
extern UINT32 vendor_cert_size;
|
||||
extern EFI_SIGNATURE_LIST *vendor_dbx;
|
||||
extern UINT32 vendor_dbx_size;
|
||||
extern struct {
|
||||
UINT32 vendor_cert_size;
|
||||
UINT32 vendor_dbx_size;
|
||||
UINT32 vendor_cert_offset;
|
||||
UINT32 vendor_dbx_offset;
|
||||
} cert_table;
|
||||
|
||||
UINT32 vendor_cert_size;
|
||||
UINT32 vendor_dbx_size;
|
||||
UINT8 *vendor_cert;
|
||||
UINT8 *vendor_dbx;
|
||||
|
||||
/*
|
||||
* indicator of how an image has been verified
|
||||
*/
|
||||
verification_method_t verification_method;
|
||||
int loader_is_participating;
|
||||
|
||||
#define EFI_IMAGE_SECURITY_DATABASE_GUID { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }}
|
||||
|
||||
static UINT8 insecure_mode;
|
||||
UINT8 insecure_mode;
|
||||
UINT8 ignore_db;
|
||||
|
||||
typedef enum {
|
||||
DATA_FOUND,
|
||||
@ -77,32 +99,6 @@ typedef struct {
|
||||
UINT8 *Mok;
|
||||
} MokListNode;
|
||||
|
||||
static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes,
|
||||
UINTN *size, void **buffer)
|
||||
{
|
||||
EFI_STATUS efi_status;
|
||||
char allocate = !(*size);
|
||||
|
||||
efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid,
|
||||
attributes, size, buffer);
|
||||
|
||||
if (efi_status != EFI_BUFFER_TOO_SMALL || !allocate) {
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
*buffer = AllocatePool(*size);
|
||||
|
||||
if (!*buffer) {
|
||||
Print(L"Unable to allocate variable buffer\n");
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid,
|
||||
attributes, size, *buffer);
|
||||
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform basic bounds checking of the intra-image pointers
|
||||
*/
|
||||
@ -147,10 +143,18 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
|
||||
|
||||
Adjust = (UINT64)data - context->ImageAddress;
|
||||
|
||||
if (Adjust == 0)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
while (RelocBase < RelocBaseEnd) {
|
||||
Reloc = (UINT16 *) ((char *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
|
||||
RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock);
|
||||
|
||||
if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > context->RelocDir->Size)) {
|
||||
Print(L"Reloc block size is invalid\n");
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
RelocEnd = (UINT16 *) ((char *) RelocBase + RelocBase->SizeOfBlock);
|
||||
if ((void *)RelocEnd < data || (void *)RelocEnd > ImageEnd) {
|
||||
Print(L"Reloc entry overflows binary\n");
|
||||
return EFI_UNSUPPORTED;
|
||||
@ -226,11 +230,11 @@ static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
|
||||
EFI_SIGNATURE_DATA *Cert;
|
||||
UINTN CertCount, Index;
|
||||
BOOLEAN IsFound = FALSE;
|
||||
EFI_GUID CertType = EfiCertX509Guid;
|
||||
EFI_GUID CertType = X509_GUID;
|
||||
|
||||
while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
|
||||
if (CompareGuid (&CertList->SignatureType, &CertType) == 0) {
|
||||
CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize;
|
||||
CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
|
||||
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
|
||||
for (Index = 0; Index < CertCount; Index++) {
|
||||
IsFound = AuthenticodeVerify (data->CertData,
|
||||
@ -266,15 +270,14 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
|
||||
EFI_STATUS efi_status;
|
||||
EFI_SIGNATURE_LIST *CertList;
|
||||
UINTN dbsize = 0;
|
||||
UINT32 attributes;
|
||||
void *db;
|
||||
UINT8 *db;
|
||||
|
||||
efi_status = get_variable(dbname, guid, &attributes, &dbsize, &db);
|
||||
efi_status = get_variable(dbname, &db, &dbsize, guid);
|
||||
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
return VAR_NOT_FOUND;
|
||||
|
||||
CertList = db;
|
||||
CertList = (EFI_SIGNATURE_LIST *)db;
|
||||
|
||||
rc = check_db_cert_in_ram(CertList, dbsize, data, hash);
|
||||
|
||||
@ -295,7 +298,7 @@ static CHECK_STATUS check_db_hash_in_ram(EFI_SIGNATURE_LIST *CertList,
|
||||
BOOLEAN IsFound = FALSE;
|
||||
|
||||
while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
|
||||
CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize;
|
||||
CertCount = (CertList->SignatureListSize -sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
|
||||
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
|
||||
if (CompareGuid(&CertList->SignatureType, &CertType) == 0) {
|
||||
for (Index = 0; Index < CertCount; Index++) {
|
||||
@ -332,17 +335,16 @@ static CHECK_STATUS check_db_hash(CHAR16 *dbname, EFI_GUID guid, UINT8 *data,
|
||||
{
|
||||
EFI_STATUS efi_status;
|
||||
EFI_SIGNATURE_LIST *CertList;
|
||||
UINT32 attributes;
|
||||
UINTN dbsize = 0;
|
||||
void *db;
|
||||
UINT8 *db;
|
||||
|
||||
efi_status = get_variable(dbname, guid, &attributes, &dbsize, &db);
|
||||
efi_status = get_variable(dbname, &db, &dbsize, guid);
|
||||
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
return VAR_NOT_FOUND;
|
||||
}
|
||||
|
||||
CertList = db;
|
||||
CertList = (EFI_SIGNATURE_LIST *)db;
|
||||
|
||||
CHECK_STATUS rc = check_db_hash_in_ram(CertList, dbsize, data,
|
||||
SignatureSize, CertType);
|
||||
@ -359,31 +361,39 @@ static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert,
|
||||
UINT8 *sha256hash, UINT8 *sha1hash)
|
||||
{
|
||||
EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
|
||||
EFI_SIGNATURE_LIST *dbx = (EFI_SIGNATURE_LIST *)vendor_dbx;
|
||||
|
||||
if (check_db_hash_in_ram(vendor_dbx, vendor_dbx_size, sha256hash,
|
||||
SHA256_DIGEST_SIZE, EfiHashSha256Guid) ==
|
||||
if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha256hash,
|
||||
SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID) ==
|
||||
DATA_FOUND)
|
||||
return EFI_ACCESS_DENIED;
|
||||
if (check_db_hash_in_ram(vendor_dbx, vendor_dbx_size, sha1hash,
|
||||
SHA1_DIGEST_SIZE, EfiHashSha1Guid) ==
|
||||
if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha1hash,
|
||||
SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID) ==
|
||||
DATA_FOUND)
|
||||
return EFI_ACCESS_DENIED;
|
||||
if (check_db_cert_in_ram(vendor_dbx, vendor_dbx_size, cert,
|
||||
if (cert && check_db_cert_in_ram(dbx, vendor_dbx_size, cert,
|
||||
sha256hash) == DATA_FOUND)
|
||||
return EFI_ACCESS_DENIED;
|
||||
|
||||
if (check_db_hash(L"dbx", secure_var, sha256hash, SHA256_DIGEST_SIZE,
|
||||
EfiHashSha256Guid) == DATA_FOUND)
|
||||
EFI_CERT_SHA256_GUID) == DATA_FOUND)
|
||||
return EFI_ACCESS_DENIED;
|
||||
if (check_db_hash(L"dbx", secure_var, sha1hash, SHA1_DIGEST_SIZE,
|
||||
EfiHashSha1Guid) == DATA_FOUND)
|
||||
EFI_CERT_SHA1_GUID) == DATA_FOUND)
|
||||
return EFI_ACCESS_DENIED;
|
||||
if (check_db_cert(L"dbx", secure_var, cert, sha256hash) == DATA_FOUND)
|
||||
if (cert && check_db_cert(L"dbx", secure_var, cert, sha256hash) ==
|
||||
DATA_FOUND)
|
||||
return EFI_ACCESS_DENIED;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static void update_verification_method(verification_method_t method)
|
||||
{
|
||||
if (verification_method == VERIFIED_BY_NOTHING)
|
||||
verification_method = method;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the binary signature or hash are present in db or MokList
|
||||
*/
|
||||
@ -393,20 +403,40 @@ static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert,
|
||||
EFI_GUID secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
|
||||
EFI_GUID shim_var = SHIM_LOCK_GUID;
|
||||
|
||||
if (!ignore_db) {
|
||||
if (check_db_hash(L"db", secure_var, sha256hash, SHA256_DIGEST_SIZE,
|
||||
EfiHashSha256Guid) == DATA_FOUND)
|
||||
EFI_CERT_SHA256_GUID) == DATA_FOUND) {
|
||||
update_verification_method(VERIFIED_BY_HASH);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
if (check_db_hash(L"db", secure_var, sha1hash, SHA1_DIGEST_SIZE,
|
||||
EfiHashSha1Guid) == DATA_FOUND)
|
||||
EFI_CERT_SHA1_GUID) == DATA_FOUND) {
|
||||
verification_method = VERIFIED_BY_HASH;
|
||||
update_verification_method(VERIFIED_BY_HASH);
|
||||
return EFI_SUCCESS;
|
||||
if (check_db_hash(L"MokList", shim_var, sha256hash, SHA256_DIGEST_SIZE,
|
||||
EfiHashSha256Guid) == DATA_FOUND)
|
||||
return EFI_SUCCESS;
|
||||
if (check_db_cert(L"db", secure_var, cert, sha256hash) == DATA_FOUND)
|
||||
return EFI_SUCCESS;
|
||||
if (check_db_cert(L"MokList", shim_var, cert, sha256hash) == DATA_FOUND)
|
||||
}
|
||||
if (cert && check_db_cert(L"db", secure_var, cert, sha256hash)
|
||||
== DATA_FOUND) {
|
||||
verification_method = VERIFIED_BY_CERT;
|
||||
update_verification_method(VERIFIED_BY_CERT);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (check_db_hash(L"MokList", shim_var, sha256hash, SHA256_DIGEST_SIZE,
|
||||
EFI_CERT_SHA256_GUID) == DATA_FOUND) {
|
||||
verification_method = VERIFIED_BY_HASH;
|
||||
update_verification_method(VERIFIED_BY_HASH);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
if (cert && check_db_cert(L"MokList", shim_var, cert, sha256hash) ==
|
||||
DATA_FOUND) {
|
||||
verification_method = VERIFIED_BY_CERT;
|
||||
update_verification_method(VERIFIED_BY_CERT);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
update_verification_method(VERIFIED_BY_NOTHING);
|
||||
return EFI_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
@ -418,27 +448,38 @@ static BOOLEAN secure_mode (void)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
EFI_GUID global_var = EFI_GLOBAL_VARIABLE;
|
||||
UINTN charsize = sizeof(char);
|
||||
UINTN len;
|
||||
UINT8 *Data;
|
||||
UINT8 sb, setupmode;
|
||||
UINT32 attributes;
|
||||
|
||||
if (insecure_mode)
|
||||
return FALSE;
|
||||
|
||||
status = get_variable(L"SecureBoot", global_var, &attributes, &charsize,
|
||||
(void *)&sb);
|
||||
status = get_variable(L"SecureBoot", &Data, &len, global_var);
|
||||
if (status != EFI_SUCCESS) {
|
||||
if (verbose)
|
||||
console_notify(L"Secure boot not enabled\n");
|
||||
return FALSE;
|
||||
}
|
||||
sb = *Data;
|
||||
FreePool(Data);
|
||||
|
||||
/* FIXME - more paranoia here? */
|
||||
if (status != EFI_SUCCESS || sb != 1) {
|
||||
Print(L"Secure boot not enabled\n");
|
||||
if (sb != 1) {
|
||||
if (verbose)
|
||||
console_notify(L"Secure boot not enabled\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
status = get_variable(L"SetupMode", global_var, &attributes, &charsize,
|
||||
(void *)&setupmode);
|
||||
status = get_variable(L"SetupMode", &Data, &len, global_var);
|
||||
if (status != EFI_SUCCESS)
|
||||
return TRUE;
|
||||
|
||||
if (status == EFI_SUCCESS && setupmode == 1) {
|
||||
Print(L"Platform is in setup mode\n");
|
||||
setupmode = *Data;
|
||||
FreePool(Data);
|
||||
|
||||
if (setupmode == 1) {
|
||||
if (verbose)
|
||||
console_notify(L"Platform is in setup mode\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -622,12 +663,12 @@ done:
|
||||
static EFI_STATUS verify_mok (void) {
|
||||
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
|
||||
EFI_STATUS status = EFI_SUCCESS;
|
||||
void *MokListData = NULL;
|
||||
UINT8 *MokListData = NULL;
|
||||
UINTN MokListDataSize = 0;
|
||||
UINT32 attributes;
|
||||
|
||||
status = get_variable(L"MokList", shim_lock_guid, &attributes,
|
||||
&MokListDataSize, &MokListData);
|
||||
status = get_variable_attr(L"MokList", &MokListData, &MokListDataSize,
|
||||
shim_lock_guid, &attributes);
|
||||
|
||||
if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
|
||||
Print(L"MokList is compromised!\nErase all keys in MokList!\n");
|
||||
@ -638,6 +679,9 @@ static EFI_STATUS verify_mok (void) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (MokListData)
|
||||
FreePool(MokListData);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
@ -650,26 +694,25 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
|
||||
UINT8 sha256hash[SHA256_DIGEST_SIZE];
|
||||
UINT8 sha1hash[SHA1_DIGEST_SIZE];
|
||||
EFI_STATUS status = EFI_ACCESS_DENIED;
|
||||
WIN_CERTIFICATE_EFI_PKCS *cert;
|
||||
WIN_CERTIFICATE_EFI_PKCS *cert = NULL;
|
||||
unsigned int size = datasize;
|
||||
|
||||
if (context->SecDir->Size == 0) {
|
||||
Print(L"Empty security header\n");
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
cert = ImageAddress (data, size, context->SecDir->VirtualAddress);
|
||||
if (context->SecDir->Size != 0) {
|
||||
cert = ImageAddress (data, size,
|
||||
context->SecDir->VirtualAddress);
|
||||
|
||||
if (!cert) {
|
||||
Print(L"Certificate located outside the image\n");
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (cert->Hdr.wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
|
||||
if (cert->Hdr.wCertificateType !=
|
||||
WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
|
||||
Print(L"Unsupported certificate type %x\n",
|
||||
cert->Hdr.wCertificateType);
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
status = generate_hash(data, datasize, context, sha256hash, sha1hash);
|
||||
|
||||
@ -696,12 +739,10 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
|
||||
* databases
|
||||
*/
|
||||
status = check_whitelist(cert, sha256hash, sha1hash);
|
||||
|
||||
if (status == EFI_SUCCESS) {
|
||||
Print(L"Binary is whitelisted\n");
|
||||
if (status == EFI_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (cert) {
|
||||
/*
|
||||
* Check against the shim build key
|
||||
*/
|
||||
@ -710,7 +751,6 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
|
||||
shim_cert, sizeof(shim_cert), sha256hash,
|
||||
SHA256_DIGEST_SIZE)) {
|
||||
status = EFI_SUCCESS;
|
||||
Print(L"Binary is verified by the vendor certificate\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -723,11 +763,10 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
|
||||
vendor_cert, vendor_cert_size, sha256hash,
|
||||
SHA256_DIGEST_SIZE)) {
|
||||
status = EFI_SUCCESS;
|
||||
Print(L"Binary is verified by the vendor certificate\n");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
Print(L"Invalid signature\n");
|
||||
status = EFI_ACCESS_DENIED;
|
||||
|
||||
return status;
|
||||
@ -741,6 +780,7 @@ static EFI_STATUS read_header(void *data, unsigned int datasize,
|
||||
{
|
||||
EFI_IMAGE_DOS_HEADER *DosHdr = data;
|
||||
EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data;
|
||||
unsigned long HeaderWithoutDataDir, SectionHeaderOffset;
|
||||
|
||||
if (datasize < sizeof(EFI_IMAGE_DOS_HEADER)) {
|
||||
Print(L"Invalid image\n");
|
||||
@ -750,6 +790,37 @@ static EFI_STATUS read_header(void *data, unsigned int datasize,
|
||||
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
|
||||
PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)data + DosHdr->e_lfanew);
|
||||
|
||||
if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
|
||||
< PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes) {
|
||||
Print(L"Image header too small\n");
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER64)
|
||||
- sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
|
||||
if (((UINT32)PEHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
|
||||
PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes
|
||||
* sizeof (EFI_IMAGE_DATA_DIRECTORY)) {
|
||||
Print(L"Image header overflows data directory\n");
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
SectionHeaderOffset = DosHdr->e_lfanew
|
||||
+ sizeof (UINT32)
|
||||
+ sizeof (EFI_IMAGE_FILE_HEADER)
|
||||
+ PEHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader;
|
||||
if ((PEHdr->Pe32Plus.OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER
|
||||
<= PEHdr->Pe32Plus.FileHeader.NumberOfSections) {
|
||||
Print(L"Image sections overflow image size\n");
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if ((PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER
|
||||
< (UINT32)PEHdr->Pe32Plus.FileHeader.NumberOfSections) {
|
||||
Print(L"Image sections overflow section headers\n");
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if ((((UINT8 *)PEHdr - (UINT8 *)data) + sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION)) > datasize) {
|
||||
Print(L"Invalid image\n");
|
||||
return EFI_UNSUPPORTED;
|
||||
@ -826,9 +897,12 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
|
||||
if (secure_mode ()) {
|
||||
efi_status = verify_buffer(data, datasize, &context);
|
||||
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
Print(L"Verification failed\n");
|
||||
if (EFI_ERROR(efi_status)) {
|
||||
console_error(L"Verification failed", efi_status);
|
||||
return efi_status;
|
||||
} else {
|
||||
if (verbose)
|
||||
console_notify(L"Verification succeeded");
|
||||
}
|
||||
}
|
||||
|
||||
@ -859,6 +933,12 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (Section->VirtualAddress < context.SizeOfHeaders ||
|
||||
Section->PointerToRawData < context.SizeOfHeaders) {
|
||||
Print(L"Section is inside image headers\n");
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (Section->SizeOfRawData > 0)
|
||||
CopyMem(base, data + Section->PointerToRawData, size);
|
||||
|
||||
@ -950,7 +1030,12 @@ should_use_fallback(EFI_HANDLE image_handle)
|
||||
rc = uefi_call_wrapper(vh->Open, 5, vh, &fh, L"\\EFI\\BOOT" FALLBACK,
|
||||
EFI_FILE_MODE_READ, 0);
|
||||
if (EFI_ERROR(rc)) {
|
||||
Print(L"Could not open \"\\EFI\\BOOT%s\": %d\n", FALLBACK, rc);
|
||||
/* Do not print the error here - this is an acceptable case
|
||||
* for removable media, where we genuinely don't want
|
||||
* fallback.efi to exist.
|
||||
* Print(L"Could not open \"\\EFI\\BOOT%s\": %d\n", FALLBACK,
|
||||
* rc);
|
||||
*/
|
||||
uefi_call_wrapper(vh->Close, 1, vh);
|
||||
return 0;
|
||||
}
|
||||
@ -969,7 +1054,7 @@ static EFI_STATUS generate_path(EFI_LOADED_IMAGE *li, CHAR16 *ImagePath,
|
||||
{
|
||||
EFI_DEVICE_PATH *devpath;
|
||||
EFI_HANDLE device;
|
||||
int i;
|
||||
int i, j, last = -1;
|
||||
unsigned int pathlen = 0;
|
||||
EFI_STATUS efi_status = EFI_SUCCESS;
|
||||
CHAR16 *bootpath;
|
||||
@ -981,15 +1066,38 @@ static EFI_STATUS generate_path(EFI_LOADED_IMAGE *li, CHAR16 *ImagePath,
|
||||
|
||||
pathlen = StrLen(bootpath);
|
||||
|
||||
for (i=pathlen; i>0; i--) {
|
||||
if (bootpath[i] == '\\')
|
||||
break;
|
||||
/*
|
||||
* DevicePathToStr() concatenates two nodes with '/'.
|
||||
* Convert '/' to '\\'.
|
||||
*/
|
||||
for (i = 0; i < pathlen; i++) {
|
||||
if (bootpath[i] == '/')
|
||||
bootpath[i] = '\\';
|
||||
}
|
||||
|
||||
bootpath[i+1] = '\0';
|
||||
for (i=pathlen; i>0; i--) {
|
||||
if (bootpath[i] == '\\' && bootpath[i-1] == '\\')
|
||||
bootpath[i] = '/';
|
||||
else if (last == -1 && bootpath[i] == '\\')
|
||||
last = i;
|
||||
}
|
||||
|
||||
if (i == 0 || bootpath[i-i] == '\\')
|
||||
bootpath[i] = '\0';
|
||||
if (last == -1 && bootpath[0] == '\\')
|
||||
last = 0;
|
||||
bootpath[last+1] = '\0';
|
||||
|
||||
if (last > 0) {
|
||||
for (i = 0, j = 0; bootpath[i] != '\0'; i++) {
|
||||
if (bootpath[i] != '/') {
|
||||
bootpath[j] = bootpath[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
bootpath[j] = '\0';
|
||||
}
|
||||
|
||||
while (*ImagePath == '\\')
|
||||
ImagePath++;
|
||||
|
||||
*PathName = AllocatePool(StrSize(bootpath) + StrSize(ImagePath));
|
||||
|
||||
@ -1007,6 +1115,8 @@ static EFI_STATUS generate_path(EFI_LOADED_IMAGE *li, CHAR16 *ImagePath,
|
||||
*grubpath = FileDevicePath(device, *PathName);
|
||||
|
||||
error:
|
||||
FreePool(bootpath);
|
||||
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
@ -1143,6 +1253,8 @@ EFI_STATUS shim_verify (void *buffer, UINT32 size)
|
||||
EFI_STATUS status;
|
||||
PE_COFF_LOADER_IMAGE_CONTEXT context;
|
||||
|
||||
loader_is_participating = 1;
|
||||
|
||||
if (!secure_mode())
|
||||
return EFI_SUCCESS;
|
||||
|
||||
@ -1167,7 +1279,7 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
|
||||
EFI_DEVICE_PATH *path;
|
||||
CHAR16 *PathName = NULL;
|
||||
void *sourcebuffer = NULL;
|
||||
UINTN sourcesize = 0;
|
||||
UINT64 sourcesize = 0;
|
||||
void *data = NULL;
|
||||
int datasize;
|
||||
|
||||
@ -1236,6 +1348,8 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath)
|
||||
goto done;
|
||||
}
|
||||
|
||||
loader_is_participating = 0;
|
||||
|
||||
/*
|
||||
* The binary is trusted and relocated. Run it
|
||||
*/
|
||||
@ -1282,27 +1396,59 @@ EFI_STATUS mirror_mok_list()
|
||||
{
|
||||
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
|
||||
EFI_STATUS efi_status;
|
||||
UINT32 attributes;
|
||||
void *Data = NULL;
|
||||
UINT8 *Data = NULL;
|
||||
UINTN DataSize = 0;
|
||||
void *FullData = NULL;
|
||||
UINTN FullDataSize = 0;
|
||||
EFI_SIGNATURE_LIST *CertList = NULL;
|
||||
EFI_SIGNATURE_DATA *CertData = NULL;
|
||||
uint8_t *p = NULL;
|
||||
|
||||
efi_status = get_variable(L"MokList", shim_lock_guid, &attributes,
|
||||
&DataSize, &Data);
|
||||
efi_status = get_variable(L"MokList", &Data, &DataSize, shim_lock_guid);
|
||||
if (efi_status != EFI_SUCCESS)
|
||||
DataSize = 0;
|
||||
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
goto done;
|
||||
FullDataSize = DataSize
|
||||
+ sizeof (*CertList)
|
||||
+ sizeof (EFI_GUID)
|
||||
+ vendor_cert_size
|
||||
;
|
||||
FullData = AllocatePool(FullDataSize);
|
||||
if (!FullData) {
|
||||
Print(L"Failed to allocate space for MokListRT\n");
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
p = FullData;
|
||||
|
||||
if (efi_status == EFI_SUCCESS && DataSize > 0) {
|
||||
CopyMem(p, Data, DataSize);
|
||||
p += DataSize;
|
||||
}
|
||||
CertList = (EFI_SIGNATURE_LIST *)p;
|
||||
p += sizeof (*CertList);
|
||||
CertData = (EFI_SIGNATURE_DATA *)p;
|
||||
p += sizeof (EFI_GUID);
|
||||
|
||||
CertList->SignatureType = EFI_CERT_X509_GUID;
|
||||
CertList->SignatureListSize = vendor_cert_size
|
||||
+ sizeof (*CertList)
|
||||
+ sizeof (*CertData)
|
||||
-1;
|
||||
CertList->SignatureHeaderSize = 0;
|
||||
CertList->SignatureSize = vendor_cert_size + sizeof (EFI_GUID);
|
||||
|
||||
CertData->SignatureOwner = SHIM_LOCK_GUID;
|
||||
CopyMem(p, vendor_cert, vendor_cert_size);
|
||||
|
||||
efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokListRT",
|
||||
&shim_lock_guid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS
|
||||
| EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
DataSize, Data);
|
||||
FullDataSize, FullData);
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
Print(L"Failed to set MokListRT %d\n", efi_status);
|
||||
}
|
||||
|
||||
done:
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
@ -1337,7 +1483,7 @@ EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
|
||||
|
||||
if (check_var(L"MokNew") || check_var(L"MokSB") ||
|
||||
check_var(L"MokPW") || check_var(L"MokAuth") ||
|
||||
check_var(L"MokDel")) {
|
||||
check_var(L"MokDel") || check_var(L"MokDB")) {
|
||||
efi_status = start_image(image_handle, MOK_MANAGER);
|
||||
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
@ -1357,12 +1503,15 @@ static EFI_STATUS check_mok_sb (void)
|
||||
{
|
||||
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
|
||||
EFI_STATUS status = EFI_SUCCESS;
|
||||
void *MokSBState = NULL;
|
||||
UINT8 *MokSBState = NULL;
|
||||
UINTN MokSBStateSize = 0;
|
||||
UINT32 attributes;
|
||||
|
||||
status = get_variable(L"MokSBState", shim_lock_guid, &attributes,
|
||||
&MokSBStateSize, &MokSBState);
|
||||
insecure_mode = 0;
|
||||
ignore_db = 0;
|
||||
|
||||
status = get_variable_attr(L"MokSBState", &MokSBState, &MokSBStateSize,
|
||||
shim_lock_guid, &attributes);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
return EFI_ACCESS_DENIED;
|
||||
@ -1383,9 +1532,76 @@ static EFI_STATUS check_mok_sb (void)
|
||||
}
|
||||
}
|
||||
|
||||
FreePool(MokSBState);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that MokDBState is valid, and if appropriate set ignore db mode
|
||||
*/
|
||||
|
||||
static EFI_STATUS check_mok_db (void)
|
||||
{
|
||||
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
|
||||
EFI_STATUS status = EFI_SUCCESS;
|
||||
UINT8 *MokDBState = NULL;
|
||||
UINTN MokDBStateSize = 0;
|
||||
UINT32 attributes;
|
||||
|
||||
status = get_variable_attr(L"MokDBState", &MokDBState, &MokDBStateSize,
|
||||
shim_lock_guid, &attributes);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
return EFI_ACCESS_DENIED;
|
||||
|
||||
ignore_db = 0;
|
||||
|
||||
/*
|
||||
* Delete and ignore the variable if it's been set from or could be
|
||||
* modified by the OS
|
||||
*/
|
||||
if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
|
||||
Print(L"MokDBState is compromised! Clearing it\n");
|
||||
if (LibDeleteVariable(L"MokDBState", &shim_lock_guid) != EFI_SUCCESS) {
|
||||
Print(L"Failed to erase MokDBState\n");
|
||||
}
|
||||
status = EFI_ACCESS_DENIED;
|
||||
} else {
|
||||
if (*(UINT8 *)MokDBState == 1) {
|
||||
ignore_db = 1;
|
||||
}
|
||||
}
|
||||
|
||||
FreePool(MokDBState);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static EFI_STATUS mok_ignore_db()
|
||||
{
|
||||
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
|
||||
EFI_STATUS efi_status = EFI_SUCCESS;
|
||||
UINT8 Data = 1;
|
||||
UINTN DataSize = sizeof(UINT8);
|
||||
|
||||
check_mok_db();
|
||||
|
||||
if (ignore_db) {
|
||||
efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokIgnoreDB",
|
||||
&shim_lock_guid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS
|
||||
| EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
DataSize, (void *)&Data);
|
||||
if (efi_status != EFI_SUCCESS) {
|
||||
Print(L"Failed to set MokIgnoreDB %d\n", efi_status);
|
||||
}
|
||||
}
|
||||
|
||||
return efi_status;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the load options to specify the second stage loader
|
||||
*/
|
||||
@ -1471,6 +1687,13 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
|
||||
EFI_HANDLE handle = NULL;
|
||||
EFI_STATUS efi_status;
|
||||
|
||||
verification_method = VERIFIED_BY_NOTHING;
|
||||
|
||||
vendor_cert_size = cert_table.vendor_cert_size;
|
||||
vendor_dbx_size = cert_table.vendor_dbx_size;
|
||||
vendor_cert = (UINT8 *)&cert_table + cert_table.vendor_cert_offset;
|
||||
vendor_dbx = (UINT8 *)&cert_table + cert_table.vendor_dbx_offset;
|
||||
|
||||
/*
|
||||
* Set up the shim lock protocol so that grub and MokManager can
|
||||
* call back in and use shim functions
|
||||
@ -1486,6 +1709,11 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
|
||||
*/
|
||||
InitializeLib(image_handle, systab);
|
||||
|
||||
setup_console(1);
|
||||
setup_verbosity();
|
||||
|
||||
dprinta(shim_version);
|
||||
|
||||
/* Set the second stage loader */
|
||||
set_second_stage (image_handle);
|
||||
|
||||
@ -1498,17 +1726,35 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
|
||||
/*
|
||||
* Tell the user that we're in insecure mode if necessary
|
||||
*/
|
||||
if (insecure_mode) {
|
||||
if (!secure_mode()) {
|
||||
Print(L"Booting in insecure mode\n");
|
||||
uefi_call_wrapper(BS->Stall, 1, 2000000);
|
||||
} else {
|
||||
/*
|
||||
* Install our hooks for ExitBootServices() and StartImage()
|
||||
*/
|
||||
hook_system_services(systab);
|
||||
loader_is_participating = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Install the protocol
|
||||
*/
|
||||
uefi_call_wrapper(BS->InstallProtocolInterface, 4, &handle,
|
||||
&shim_lock_guid, EFI_NATIVE_INTERFACE,
|
||||
efi_status = uefi_call_wrapper(BS->InstallProtocolInterface, 4,
|
||||
&handle, &shim_lock_guid, EFI_NATIVE_INTERFACE,
|
||||
&shim_lock_interface);
|
||||
if (EFI_ERROR(efi_status)) {
|
||||
console_error(L"Could not install security protocol",
|
||||
efi_status);
|
||||
return efi_status;
|
||||
}
|
||||
|
||||
#if defined(OVERRIDE_SECURITY_POLICY)
|
||||
/*
|
||||
* Install the security protocol hook
|
||||
*/
|
||||
security_policy_install(shim_verify);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enter MokManager if necessary
|
||||
@ -1521,23 +1767,44 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
|
||||
*/
|
||||
efi_status = mirror_mok_list();
|
||||
|
||||
/*
|
||||
* Create the runtime MokIgnoreDB variable so the kernel can make
|
||||
* use of it
|
||||
*/
|
||||
efi_status = mok_ignore_db();
|
||||
|
||||
/*
|
||||
* Hand over control to the second stage bootloader
|
||||
*/
|
||||
|
||||
efi_status = init_grub(image_handle);
|
||||
|
||||
#if defined(OVERRIDE_SECURITY_POLICY)
|
||||
/*
|
||||
* Clean up the security protocol hook
|
||||
*/
|
||||
security_policy_uninstall();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If we're back here then clean everything up before exiting
|
||||
*/
|
||||
uefi_call_wrapper(BS->UninstallProtocolInterface, 3, handle,
|
||||
&shim_lock_guid, &shim_lock_interface);
|
||||
|
||||
|
||||
/*
|
||||
* Remove our hooks from system services.
|
||||
*/
|
||||
unhook_system_services();
|
||||
|
||||
/*
|
||||
* Free the space allocated for the alternative 2nd stage loader
|
||||
*/
|
||||
if (load_options_size > 0)
|
||||
FreePool(second_stage);
|
||||
|
||||
setup_console(0);
|
||||
|
||||
return efi_status;
|
||||
}
|
||||
|
3
shim.h
3
shim.h
@ -1,7 +1,6 @@
|
||||
#include "PeImage.h"
|
||||
|
||||
#define SHIM_LOCK_GUID \
|
||||
{ 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
|
||||
extern EFI_GUID SHIM_LOCK_GUID;
|
||||
|
||||
INTERFACE_DECL(_SHIM_LOCK);
|
||||
|
||||
|
43
signature.h
43
signature.h
@ -1,43 +0,0 @@
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
|
||||
EFI_GUID EfiHashSha1Guid = { 0x826ca512, 0xcf10, 0x4ac9, {0xb1, 0x87, 0xbe, 0x1, 0x49, 0x66, 0x31, 0xbd }};
|
||||
EFI_GUID EfiHashSha256Guid = { 0xc1c41626, 0x504c, 0x4092, {0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 }};
|
||||
EFI_GUID EfiCertX509Guid = { 0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 }};
|
||||
|
||||
typedef struct {
|
||||
///
|
||||
/// An identifier which identifies the agent which added the signature to the list.
|
||||
///
|
||||
EFI_GUID SignatureOwner;
|
||||
///
|
||||
/// The format of the signature is defined by the SignatureType.
|
||||
///
|
||||
UINT8 SignatureData[1];
|
||||
} __attribute__ ((packed)) EFI_SIGNATURE_DATA;
|
||||
|
||||
typedef struct {
|
||||
///
|
||||
/// Type of the signature. GUID signature types are defined in below.
|
||||
///
|
||||
EFI_GUID SignatureType;
|
||||
///
|
||||
/// Total size of the signature list, including this header.
|
||||
///
|
||||
UINT32 SignatureListSize;
|
||||
///
|
||||
/// Size of the signature header which precedes the array of signatures.
|
||||
///
|
||||
UINT32 SignatureHeaderSize;
|
||||
///
|
||||
/// Size of each signature.
|
||||
///
|
||||
UINT32 SignatureSize;
|
||||
///
|
||||
/// Header before the array of signatures. The format of this header is specified
|
||||
/// by the SignatureType.
|
||||
/// UINT8 SignatureHeader[SignatureHeaderSize];
|
||||
///
|
||||
/// An array of signatures. Each signature is SignatureSize bytes in length.
|
||||
/// EFI_SIGNATURE_DATA Signatures[][SignatureSize];
|
||||
///
|
||||
} __attribute__ ((packed)) EFI_SIGNATURE_LIST;
|
8
version.c.in
Normal file
8
version.c.in
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
#include "version.h"
|
||||
|
||||
CHAR8 shim_version[] =
|
||||
"UEFI SHIM\n"
|
||||
"$Version: @@VERSION@@ $\n"
|
||||
"$BuildMachine: @@UNAME@@ $\n"
|
||||
"$Commit: @@COMMIT@@ $\n";
|
Loading…
Reference in New Issue
Block a user