Import upstream version 0.7

This commit is contained in:
Steve Langasek 2014-10-06 15:39:48 -07:00
parent bfab8d6791
commit 72bb39c023
68 changed files with 8304 additions and 3074 deletions

2
.gitignore vendored
View File

@ -22,3 +22,5 @@ shim_cert.h
*.so
*.srl
*.srl.old
*.tar.*
version.c

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -58,7 +58,7 @@ HmacMd5Init (
//
// Check input parameters.
//
if (HmacMd5Context == NULL) {
if (HmacMd5Context == NULL || KeySize > INT_MAX) {
return FALSE;
}

View File

@ -58,7 +58,7 @@ HmacSha1Init (
//
// Check input parameters.
//
if (HmacSha1Context == NULL) {
if (HmacSha1Context == NULL || KeySize > INT_MAX) {
return FALSE;
}

View File

@ -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

View File

@ -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
);

View File

@ -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 \

View File

@ -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 \

View 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;
}

View File

@ -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;
}

View File

@ -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.
//

View File

@ -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);
//

View File

@ -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;
}

View File

@ -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
View 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
View 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
);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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"

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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
View 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
View File

@ -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
View File

@ -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
View 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
View 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
View File

@ -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

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,2 @@
EFI_STATUS
argsplit(EFI_HANDLE image, int *argc, CHAR16*** ARGV);

21
include/simple_file.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -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
View 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
View 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
View File

@ -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
View File

@ -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);

View File

@ -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
View File

@ -0,0 +1,8 @@
#include "version.h"
CHAR8 shim_version[] =
"UEFI SHIM\n"
"$Version: @@VERSION@@ $\n"
"$BuildMachine: @@UNAME@@ $\n"
"$Commit: @@COMMIT@@ $\n";

8
version.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _SHIM_VERSION_H
#define _SHIM_VERSION_H 1
#include <efi.h>
extern CHAR8 shim_version[];
#endif /* SHIM_VERSION_H */