Accepting request 148684 from Base:System

the preboot loader for UEFI secureboot

OBS-URL: https://build.opensuse.org/request/show/148684
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/shim?expand=0&rev=1
This commit is contained in:
Stephan Kulow 2013-01-17 09:43:06 +00:00 committed by Git OBS Bridge
commit d7945289e5
13 changed files with 2232 additions and 0 deletions

23
.gitattributes vendored Normal file
View File

@ -0,0 +1,23 @@
## Default LFS
*.7z filter=lfs diff=lfs merge=lfs -text
*.bsp filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.gem filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.lz filter=lfs diff=lfs merge=lfs -text
*.lzma filter=lfs diff=lfs merge=lfs -text
*.obscpio filter=lfs diff=lfs merge=lfs -text
*.oxt filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.rpm filter=lfs diff=lfs merge=lfs -text
*.tbz filter=lfs diff=lfs merge=lfs -text
*.tbz2 filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.txz filter=lfs diff=lfs merge=lfs -text
*.whl filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.zst filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.osc

3
shim-0.2.tar.bz2 Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:866b1d73d022baa4874dede94bfd2525954b986db9497e6a8f6f2c7e5fea5852
size 940450

View File

@ -0,0 +1,30 @@
From daa6a7519caa23ef69b9a879bc70789a0669b3e3 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 26 Dec 2012 11:44:46 +0800
Subject: [PATCH] Make sure the menu shows when the callback fails
Since Pause() doesn't clear the key from the input queue, the next
ReadKeyStroke reads the queued key instead of the new one. If the
user presses "Enter", MokManager exits directly without showing
the menu again.
---
MokManager.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/MokManager.c b/MokManager.c
index bfcbfd6..97588cb 100644
--- a/MokManager.c
+++ b/MokManager.c
@@ -1241,6 +1241,9 @@ static void run_menu (CHAR16 *header, UINTN lines, struct menu_item *items,
if (ret < 0) {
Print(L"Press a key to continue\n");
Pause();
+ /* Clear the key in the queue */
+ uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2,
+ ST->ConIn, &key);
}
draw_menu (header, lines, items, count);
pos = 0;
--
1.7.10.4

View File

@ -0,0 +1,84 @@
commit f23f6b726bd12b28befd5a064c47a8a249d80a59
Author: Gary Ching-Pang Lin <glin@suse.com>
Date: Mon Jan 14 16:53:19 2013 +0800
Adopt the UEFI shell style LoadOptions
The previous commit, 14d4b8e, caused shim failed to parse the name
of the 2nd stage loader in UEFI shell. Amend parsing of the name the
2nd stage loader to be compatible with UEFI shell.
To create an boot entry for elilo.efi:
# efibootmgr -c -L "shim elilo" -l "efi\\shim.efi" -u "shim.efi elilo.efi"
diff --git a/shim.c b/shim.c
index dcf1c51..37a5898 100644
--- a/shim.c
+++ b/shim.c
@@ -1330,6 +1330,8 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
EFI_LOADED_IMAGE *li;
CHAR16 *start = NULL, *c;
int i, remaining_size = 0;
+ CHAR16 *loader_str = NULL;
+ int loader_len = 0;
second_stage = DEFAULT_LOADER;
load_options = NULL;
@@ -1351,6 +1353,11 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
return EFI_BAD_BUFFER_SIZE;
}
+ /*
+ * UEFI shell copies the whole line of the command into LoadOptions.
+ * We ignore the string before the first L' ', i.e. the name of this
+ * program.
+ */
for (i = 0; i < li->LoadOptionsSize; i += 2) {
c = (CHAR16 *)(li->LoadOptions + i);
if (*c == L' ') {
@@ -1360,9 +1367,30 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
break;
}
}
+ if (!start || remaining_size <= 0)
+ return EFI_SUCCESS;
- second_stage = (CHAR16 *)li->LoadOptions;
- if (start && remaining_size > 0) {
+ for (i = 0; start[i] != '\0'; i++) {
+ if (start[i] == L' ' || start[i] == L'\0')
+ break;
+ loader_len++;
+ }
+
+ /*
+ * Setup the name of the alternative loader and the LoadOptions for
+ * the loader
+ */
+ if (loader_len > 0) {
+ loader_str = AllocatePool((loader_len + 1) * sizeof(CHAR16));
+ if (!loader_str) {
+ Print(L"Failed to allocate loader string\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ for (i = 0; i < loader_len; i++)
+ loader_str[i] = start[i];
+ loader_str[loader_len] = L'\0';
+
+ second_stage = loader_str;
load_options = start;
load_options_size = remaining_size;
}
@@ -1439,5 +1467,11 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
uefi_call_wrapper(BS->UninstallProtocolInterface, 3, handle,
&shim_lock_guid, &shim_lock_interface);
+ /*
+ * Free the space allocated for the alternative 2nd stage loader
+ */
+ if (load_options_size > 0)
+ FreePool(second_stage);
+
return efi_status;
}

View File

@ -0,0 +1,123 @@
commit 940425a8bce6bf1b556dc48189884b4a82d8d420
Author: Gary Ching-Pang Lin <glin@suse.com>
Date: Thu Dec 6 17:47:26 2012 +0800
Get the second stage loader from the Load Options
This commit replaces the 2nd stage loader path with the first
argument in the Load Options and moves the rest arguments (if any)
to the Load Options for the 2nd stage loader.
For example, to make shim to load elilo.efi, just create a new
boot entry with efibootmgr:
# efibootmgr -c -L "shim elilo" -l "efi\\shim.efi" -u "elilo.efi"
diff --git a/shim.c b/shim.c
index c3aae9e..44301dd 100644
--- a/shim.c
+++ b/shim.c
@@ -42,12 +42,16 @@
#include "netboot.h"
#include "shim_cert.h"
-#define SECOND_STAGE L"\\grub.efi"
+#define DEFAULT_LOADER L"\\grub.efi"
#define MOK_MANAGER L"\\MokManager.efi"
static EFI_SYSTEM_TABLE *systab;
static EFI_STATUS (EFIAPI *entry_point) (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table);
+static CHAR16 *second_stage;
+static void *load_options;
+static UINT32 load_options_size;
+
/*
* The vendor certificate used for validating the second stage loader
*/
@@ -881,6 +885,10 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
li->ImageBase = buffer;
li->ImageSize = context.ImageSize;
+ /* Pass the load options to the second stage loader */
+ li->LoadOptions = load_options;
+ li->LoadOptionsSize = load_options_size;
+
if (!entry_point) {
Print(L"Invalid entry point\n");
FreePool(buffer);
@@ -1192,7 +1200,7 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
{
EFI_STATUS efi_status;
- efi_status = start_image(image_handle, SECOND_STAGE);
+ efi_status = start_image(image_handle, second_stage);
if (efi_status != EFI_SUCCESS)
efi_status = start_image(image_handle, MOK_MANAGER);
@@ -1312,6 +1320,55 @@ static EFI_STATUS check_mok_sb (void)
return status;
}
+/*
+ * Check the load options to specify the second stage loader
+ */
+EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
+{
+ EFI_STATUS status;
+ EFI_LOADED_IMAGE *li;
+ CHAR16 *start = NULL, *c;
+ int i, remaining_size = 0;
+
+ second_stage = DEFAULT_LOADER;
+ load_options = NULL;
+ load_options_size = 0;
+
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
+ &LoadedImageProtocol, (void **) &li);
+ if (status != EFI_SUCCESS) {
+ Print (L"Failed to get load options\n");
+ return status;
+ }
+
+ /* Expect a CHAR16 string with at least one CHAR16 */
+ if (li->LoadOptionsSize < 4 || li->LoadOptionsSize % 2 != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ c = (CHAR16 *)(li->LoadOptions + (li->LoadOptionsSize - 2));
+ if (*c != L'\0') {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ for (i = 0; i < li->LoadOptionsSize; i += 2) {
+ c = (CHAR16 *)(li->LoadOptions + i);
+ if (*c == L' ') {
+ *c = L'\0';
+ start = c + 1;
+ remaining_size = li->LoadOptionsSize - i - 2;
+ break;
+ }
+ }
+
+ second_stage = (CHAR16 *)li->LoadOptions;
+ if (start && remaining_size > 0) {
+ load_options = start;
+ load_options_size = remaining_size;
+ }
+
+ return EFI_SUCCESS;
+}
+
EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
@@ -1334,6 +1391,9 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
*/
InitializeLib(image_handle, systab);
+ /* Set the second stage loader */
+ set_second_stage (image_handle);
+
/*
* Check whether the user has configured the system to run in
* insecure mode

View File

@ -0,0 +1,722 @@
From 6d50f87a06ff70d2075863f4c145235c081263d6 Mon Sep 17 00:00:00 2001
From: Matthew Garrett <mjg59@srcf.ucam.org>
Date: Sat, 24 Nov 2012 00:07:11 -0500
Subject: [PATCH 1/2] Sign MokManager with a locally-generated key
shim needs to verify that MokManager hasn't been modified, but we want to
be able to support configurations where shim is shipped without a vendor
certificate. This patch adds support for generating a certificate at build
time, incorporating the public half into shim and signing MokManager with
the private half. It uses pesign and nss, but still requires openssl for
key generation. Anyone using sbsign will need to figure this out for
themselves.
---
Makefile | 28 ++-
make-certs | 554 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
shim.c | 24 ++-
3 files changed, 597 insertions(+), 9 deletions(-)
create mode 100755 make-certs
diff --git a/Makefile b/Makefile
index b266018..412eba5 100644
--- a/Makefile
+++ b/Makefile
@@ -28,15 +28,33 @@ LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(EFI_PATH
VERSION = 0.2
-TARGET = shim.efi MokManager.efi
+TARGET = shim.efi MokManager.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
all: $(TARGET)
-shim.o: $(SOURCES)
+shim.crt:
+ ./make-certs shim shim@xn--u4h.net all codesign 1.3.6.1.4.1.311.10.3.1 </dev/null
+
+shim.cer: shim.crt
+ openssl x509 -outform der -in $< -out $@
+
+shim_cert.h: shim.cer
+ echo "static UINT8 shim_cert[] = {" > $@
+ hexdump -v -e '1/1 "0x%02x, "' $< >> $@
+ echo "};" >> $@
+
+certdb/secmod.db: shim.crt
+ -mkdir certdb
+ certutil -A -n 'my CA' -d certdb/ -t CT,CT,CT -i ca.crt
+ pk12util -d certdb/ -i shim.p12 -W "" -K ""
+ certutil -d certdb/ -A -i shim.crt -n shim -t u
+
+shim.o: $(SOURCES) shim_cert.h
cert.o : cert.S
$(CC) $(CFLAGS) -c -o $@ $<
@@ -70,10 +88,14 @@ Cryptlib/OpenSSL/libopenssl.a:
-j .debug_line -j .debug_str -j .debug_ranges \
--target=efi-app-$(ARCH) $^ $@.debug
+%.efi.signed: %.efi certdb/secmod.db
+ pesign -n certdb -i $< -c "shim" -s -o $@ -f
+
clean:
$(MAKE) -C Cryptlib clean
$(MAKE) -C Cryptlib/OpenSSL clean
- rm -f $(TARGET) $(OBJS)
+ rm -rf $(TARGET) $(OBJS) $(MOK_OBJS) $(KEYS) certdb
+ rm -f *.debug *.so
GITTAG = $(VERSION)
diff --git a/make-certs b/make-certs
new file mode 100755
index 0000000..3e9293b
--- /dev/null
+++ b/make-certs
@@ -0,0 +1,554 @@
+#!/bin/bash -e
+#
+# Generate a root CA cert for signing, and then a subject cert.
+# Usage: make-certs.sh hostname [user[@domain]] [more ...]
+# For testing only, probably still has some bugs in it.
+#
+
+DOMAIN=xn--u4h.net
+DAYS=365
+KEYTYPE=RSA
+KEYSIZE=2048
+DIGEST=SHA256
+CRLHOURS=24
+CRLDAYS=
+
+# Cleanup temporary files at exit.
+touch openssl.cnf
+newcertdir=`mktemp -d`
+cleanup() {
+ test -f openssl.cnf && rm -f openssl.cnf
+ test -f ca.txt && rm -f ca.txt
+ test -f ocsp.txt && rm -f ocsp.txt
+ test -n "$newcertdir" && rm -fr "$newcertdir"
+}
+trap cleanup EXIT
+
+# The first argument is either a common name value or a flag indicating that
+# we're doing something other than issuing a cert.
+commonname="$1"
+refresh_crl=false
+revoke_cert=false
+ocsp_serve=false
+if test "x$commonname" = "x-refresh-crl" ; then
+ refresh_crl=true
+ commonname="$1"
+fi
+if test "x$commonname" = "x-refresh_crl" ; then
+ refresh_crl=true
+ commonname="$1"
+fi
+if test "x$commonname" = "x-revoke" ; then
+ revoke_cert=true
+ shift
+ commonname="$1"
+fi
+if test "x$commonname" = "x-ocsp" ; then
+ ocsp_serve=true
+ commonname="$1"
+fi
+if test "x$commonname" = x ; then
+ echo Usage: `basename $0` 'commonname' user'[@domain]' '[more [...]]'
+ echo Usage: `basename $0` -revoke 'commonname'
+ echo Usage: `basename $0` -ocsp
+ echo Usage: `basename $0` -refresh-crl
+ echo More:
+ echo -e \\tKey usage: "[sign|signing|encrypt|encryption|all]"
+ echo -e \\tAuthority Access Info OCSP responder: "ocsp:URI"
+ echo -e \\tCRL distribution point: "crl:URI"
+ echo -e \\tSubject Alternative Name:
+ echo -e \\t\\tHostname: "*"
+ echo -e \\t\\tIP address: w.x.y.z
+ echo -e \\t\\tEmail address: "*@*.com/edu/net/org/local"
+ echo -e \\t\\tKerberos principal name: "*@*.COM/EDU/NET/ORG/LOCAL"
+ echo -e \\tExtended key usage:
+ echo -e \\t\\t1....
+ echo -e \\t\\t2....
+ echo -e \\t\\tid-kp-server-auth \| tls-server
+ echo -e \\t\\tid-kp-client-auth \| tls-client
+ echo -e \\t\\tid-kp-email-protection \| email
+ echo -e \\t\\tid-ms-kp-sc-logon \| id-ms-sc-logon
+ echo -e \\t\\tid-pkinit-kp-client-auth \| id-pkinit-client
+ echo -e \\t\\tid-pkinit-kp-kdc \| id-pkinit-kdc
+ echo -e \\t\\tca \| CA
+ exit 1
+fi
+
+# Choose a user name part for email attributes.
+GIVENUSER=$2
+test x"$GIVENUSER" = x && GIVENUSER=$USER
+echo "$GIVENUSER" | grep -q @ || GIVENUSER="$GIVENUSER"@$DOMAIN
+DOMAIN=`echo "$GIVENUSER" | cut -f2- -d@`
+
+shift || true
+shift || true
+
+# Done already?
+done=:
+
+keygen() {
+ case "$KEYTYPE" in
+ DSA)
+ openssl dsaparam -out "$1".param $KEYSIZE
+ openssl gendsa "$1".param
+ ;;
+ RSA|*)
+ #openssl genrsa $KEYSIZE -passout pass:qweqwe
+ openssl genrsa $KEYSIZE
+ #openssl genrsa $KEYSIZE -nodes
+ ;;
+ esac
+}
+
+# Set some defaults.
+CA=FALSE
+if test -s ca.crldp.uri.txt ; then
+ crlval="`cat ca.crldp.uri.txt`"
+ crl="URI:$crlval"
+fi
+if test -s ca.ocsp.uri.txt ; then
+ aiaval="`cat ca.ocsp.uri.txt`"
+ aia="OCSP;URI:$aiaval"
+fi
+if test -s ca.domain.txt ; then
+ domval="`cat ca.domain.txt`"
+ if test -n "$domval" ; then
+ DOMAIN="$domval"
+ fi
+fi
+
+# Parse the arguments which indicate what sort of information we want.
+while test $# -gt 0 ; do
+ type=
+ value="$1"
+ case "$value" in
+ RSA|rsa)
+ KEYTYPE=RSA
+ ;;
+ DSA|dsa)
+ KEYTYPE=DSA
+ ;;
+ OCSP:*|ocsp:*)
+ aiaval=`echo "$value" | cut -f2- -d:`
+ aia="OCSP;URI:$aiaval"
+ ;;
+ CRL:*|crl:*)
+ crlval=`echo "$value" | cut -f2- -d:`
+ crl="URI:$crlval"
+ ;;
+ signing|sign)
+ keyusage="${keyusage:+${keyusage},}nonRepudiation,digitalSignature"
+ ;;
+ encryption|encrypt)
+ keyusage="${keyusage:+${keyusage},}keyEncipherment,dataEncipherment"
+ ;;
+ all)
+ keyusage="digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign,encipherOnly,decipherOnly"
+ ;;
+ ca|CA)
+ CA=TRUE
+ keyusage="${keyusage:+${keyusage},}nonRepudiation,digitalSignature,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign"
+ ;;
+ 1.*|2.*|id-*|tls-*|email|mail|codesign)
+ ekuval=`echo "$value" | tr '[A-Z]' '[a-z]' | sed 's,\-,,g'`
+ case "$ekuval" in
+ idkpserverauth|tlsserver) ekuval=1.3.6.1.5.5.7.3.1;;
+ idkpclientauth|tlsclient) ekuval=1.3.6.1.5.5.7.3.2;;
+ idkpemailprotection|email|mail) ekuval=1.3.6.1.5.5.7.3.4;;
+ idkpcodesign|codesign) ekuval=1.3.6.1.5.5.7.3.3;;
+ idmskpsclogon|idmssclogon) ekuval=1.3.6.1.4.1.311.20.2.2;;
+ idpkinitkpclientauth|idpkinitclient) ekuval=1.3.6.1.5.2.3.4;;
+ idpkinitkpkdc|idpkinitkdc) ekuval=1.3.6.1.5.2.3.5;;
+ esac
+ if test -z "$eku" ; then
+ eku="$ekuval"
+ else
+ eku="$eku,$ekuval"
+ fi
+ ;;
+ *@*.COM|*@*.EDU|*@*.NET|*@*.ORG|*@*.LOCAL)
+ luser=`echo "$value" | tr '[A-Z]' '[a-z]'`
+ if test "$luser" = "$value" ; then
+ luser=
+ fi
+ type="otherName:1.3.6.1.5.2.2;SEQUENCE:$value,${luser:+otherName:1.3.6.1.4.1.311.20.2.3;UTF8:${luser},}otherName:1.3.6.1.4.1.311.20.2.3;UTF8"
+ unset luser
+ principals="$principals $value"
+ ;;
+ *@*.com|*@*.edu|*@*.net|*@*.org|*@*.local) type=email;;
+ [0-9]*.[0-9]*.[0-9]*.[0-9]*) type=IP;;
+ *) type=DNS;;
+ esac
+ if test -n "$type" ; then
+ newvalue="${type}:$value"
+ if test -z "$altnames" ; then
+ altnames="${newvalue}"
+ else
+ altnames="${altnames},${newvalue}"
+ fi
+ fi
+ shift
+done
+
+# Build the configuration file, including bits on how to construct the CA
+# certificate, an OCSP responder certificate, and the issued certificate.
+cat > openssl.cnf <<- EOF
+[ca]
+default_ca = issuer
+
+[issuer]
+private_key = `pwd`/ca.key
+certificate = `pwd`/ca.crt
+database = `pwd`/ca.db
+serial = `pwd`/ca.srl
+default_md = $DIGEST
+new_certs_dir = $newcertdir
+policy = no_policy
+
+[no_policy]
+
+[req_oids]
+domainComponent = 0.9.2342.19200300.100.1.25
+
+[req_ca]
+prompt = no
+oid_section = req_oids
+distinguished_name = req_ca_name
+default_md = $DIGEST
+subjectKeyIdentifier=hash
+
+[req_ca_name]
+C=US
+#stateOrProvinceName=SomeState
+localityName=SomeCity
+O=SomeOrg
+EOF
+#echo $DOMAIN | awk 'BEGIN {FS="."}{for(i=NF;i>0;i--){print NF-i ".domainComponent="$i;}}' >> openssl.cnf
+cat >> openssl.cnf <<- EOF
+#commonName = Test Certifying CA
+
+[v3_ca]
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always
+#authorityKeyIdentifier=keyid:always,issuer:always
+keyUsage=nonRepudiation,digitalSignature,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
+basicConstraints=critical,CA:TRUE
+nsComment="Testing CA Certificate"
+EOF
+if test -n "$aia" ; then
+ echo "authorityInfoAccess = ${aia}" >> openssl.cnf
+ echo -n "$aiaval" > ca.ocsp.uri.txt
+fi
+if test -n "$crl" ; then
+ echo "crlDistributionPoints = ${crl}" >> openssl.cnf
+ echo -n "$crlval" > ca.crldp.uri.txt
+fi
+echo "$DOMAIN" > ca.domain.txt
+cat >> openssl.cnf <<- EOF
+
+[req_ocsp]
+prompt = no
+oid_section = req_oids
+distinguished_name = req_ocsp_name
+default_md = $DIGEST
+
+[req_ocsp_name]
+C=US
+#stateOrProvinceName=SomeState
+localityName=SomeOrg
+O=SomeOrg
+EOF
+#echo $DOMAIN | awk 'BEGIN {FS="."}{for(i=NF;i>0;i--){print NF-i ".domainComponent="$i;}}' >> openssl.cnf
+cat >> openssl.cnf <<- EOF
+#commonName = OCSP Signer for Test Certifying CA
+
+[v3_ocsp]
+subjectKeyIdentifier=hash
+#authorityKeyIdentifier=keyid:always,issuer:always
+authorityKeyIdentifier=keyid:always
+keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
+extendedKeyUsage=1.3.6.1.5.5.7.3.9
+#basicConstraints=CA:FALSE
+basicConstraints=CA:TRUE
+nsComment="Testing OCSP Certificate"
+1.3.6.1.5.5.7.48.1.5=ASN1:NULL
+EOF
+if test -n "$aia" ; then
+ echo "authorityInfoAccess = ${aia}" >> openssl.cnf
+fi
+if test -n "$crl" ; then
+ echo "crlDistributionPoints = ${crl}" >> openssl.cnf
+fi
+cat >> openssl.cnf <<- EOF
+
+[req_issued]
+prompt = no
+oid_section = req_oids
+distinguished_name = req_issued_name
+default_md = $DIGEST
+
+[req_issued_name]
+C=US
+#stateOrProvinceName=SomeState
+localityName=SomeCity
+O=SomeOrg
+EOF
+#echo $DOMAIN | awk 'BEGIN {FS="."}{for(i=NF;i>0;i--){print NF-i ".domainComponent="$i;}}' >> openssl.cnf
+#mail = $GIVENUSER
+cat >> openssl.cnf <<- EOF
+commonName = $commonname
+
+[v3_issued]
+#certificatePolicies=2.5.29.32.0${eku:+,${eku}}
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always
+#authorityKeyIdentifier=keyid:always,issuer:always
+EOF
+if test -n "$aia" ; then
+ echo "authorityInfoAccess = ${aia}" >> openssl.cnf
+fi
+if test -n "$crl" ; then
+ echo "crlDistributionPoints = ${crl}" >> openssl.cnf
+fi
+if test -n "$keyusage" ; then
+ echo "keyUsage = critical,${keyusage}" >> openssl.cnf
+fi
+if test -n "$altnames" ; then
+ echo "subjectAltName = ${altnames}" >> openssl.cnf
+fi
+if test -n "$eku" ; then
+ echo "extendedKeyUsage = ${eku}" >> openssl.cnf
+ :
+fi
+if test "x$CA" = xTRUE ; then
+ echo "basicConstraints=critical,CA:TRUE" >> openssl.cnf
+ echo 'nsComment="Testing CA Certificate for '"$commonname"'"' >> openssl.cnf
+else
+ echo "basicConstraints=CA:FALSE" >> openssl.cnf
+ echo 'nsComment="Testing Certificate for '"$commonname"'"' >> openssl.cnf
+fi
+for value in $principals; do
+ user=`echo "$value" | cut -f1 -d@`
+ realm=`echo "$value" | cut -f2- -d@`
+ echo "" >> openssl.cnf
+ echo "[$value]" >> openssl.cnf
+ echo "realm=EXPLICIT:0,GeneralString:$realm" >> openssl.cnf
+ echo "kerberosname=EXPLICIT:1,SEQUENCE:krb5$user" >> openssl.cnf
+
+ echo "" >> openssl.cnf
+ echo "[krb5$user]" >> openssl.cnf
+ echo "nametype=EXPLICIT:0,INTEGER:1" >> openssl.cnf
+ echo "namelist=EXPLICIT:1,SEQUENCE:krb5basic$user" >> openssl.cnf
+
+ echo "[krb5basic$user]" >> openssl.cnf
+ count=0
+ for part in `echo "$user" | sed 's,/, ,g'` ; do
+ echo "$count.part=GeneralString:$part" >> openssl.cnf
+ count=`expr "$count" + 1`
+ done
+done
+
+# Create the data files for a new CA.
+if ! test -s ca.srl ; then
+ (dd if=/dev/urandom bs=8 count=1 2> /dev/null) | od -t x1c | head -n 1 | awk '{$1="00";OFS="";print}' > ca.srl
+else
+ echo "You already have a ca.srl file; not replacing."
+fi
+if ! test -s ca.db ; then
+ touch ca.db
+else
+ echo "You already have a ca.db file; not replacing."
+fi
+if ! test -s ca.db.attr ; then
+ touch ca.db.attr
+else
+ echo "You already have a ca.db.attr file; not replacing."
+fi
+
+# If we need a CA key, generate one.
+if ! test -s ca.key ; then
+ umask=`umask -p`
+ umask 077
+ keygen ca > ca.key 2> /dev/null
+ $umask
+else
+ echo "You already have a ca.key file; not replacing."
+ done=echo
+fi
+
+# If we need a CA certificate, generate one.
+if ! test -s ca.crt ; then
+ sed -i -e 's,^\[req_ca\]$,\[req\],g' `pwd`/openssl.cnf
+ openssl req -config `pwd`/openssl.cnf -new -key ca.key > ca.csr 2> /dev/null -passin pass:shim
+ sed -i -e 's,^\[req\]$,\[req_ca\],g' `pwd`/openssl.cnf
+ openssl x509 -extfile `pwd`/openssl.cnf -CAserial ca.srl -signkey ca.key -extensions v3_ca -req -in ca.csr -days $DAYS -out ca.crt ; : 2> /dev/null
+ openssl x509 -noout -text -in ca.crt > ca.txt
+ cat ca.crt >> ca.txt
+ cat ca.txt > ca.crt
+ rm ca.txt
+ cat ca.crt > ca.chain.crt
+else
+ echo "You already have a ca.crt file; not replacing."
+ done=echo
+fi
+
+# If we need an OCSP key, generate one.
+if ! test -s ocsp.key ; then
+ umask=`umask -p`
+ umask 077
+ keygen ocsp > ocsp.key 2> /dev/null
+ $umask
+else
+ echo "You already have an ocsp.key file; not replacing."
+ done=echo
+fi
+
+# Generate the OCSP signing cert. Set the X.509v3 basic constraints and EKU.
+if ! test -s ocsp.crt ; then
+ sed -i -e 's,^\[req_ocsp\]$,\[req\],g' `pwd`/openssl.cnf
+ openssl req -config `pwd`/openssl.cnf -new -key ocsp.key > ocsp.csr 2> /dev/null
+ sed -i -e 's,^\[req\]$,\[req_ocsp\],g' `pwd`/openssl.cnf
+ openssl ca -batch -config `pwd`/openssl.cnf -extensions v3_ocsp -preserveDN -in ocsp.csr -days $DAYS -out ocsp.crt 2> /dev/null
+ openssl x509 -noout -text -in ocsp.crt > ocsp.txt
+ cat ocsp.crt >> ocsp.txt
+ cat ocsp.txt > ocsp.crt
+ rm ocsp.txt
+else
+ echo "You already have an ocsp.crt file; not replacing."
+ done=echo
+fi
+
+# If we were told to revoke the certificate with the specified common name,
+# do so.
+if $revoke_cert ; then
+ openssl ca -config `pwd`/openssl.cnf -revoke "$commonname".crt
+fi
+
+# Always refresh the CRL.
+openssl ca -config `pwd`/openssl.cnf -gencrl ${CRLHOURS:+-crlhours ${CRLHOURS}} ${CRLDAYS:+-crldays ${CRLDAYS}} -out ca.crl.pem
+openssl crl -in ca.crl.pem -outform der -out ca.crl
+openssl crl -in ca.crl -inform der -noout -text > ca.crl.pem
+openssl crl -in ca.crl -inform der >> ca.crl.pem
+
+# If we were told to start up the mini OCSP server, do so.
+if $ocsp_serve ; then
+ openssl ocsp -text -index `pwd`/ca.db -CA `pwd`/ca.crt -rsigner `pwd`/ocsp.crt -rkey `pwd`/ocsp.key -rother `pwd`/ocsp.crt -port "`cut -f3 -d/ ca.ocsp.uri.txt | sed -r 's,(^[^:]*),0.0.0.0,g'`"
+ exit 0
+fi
+
+# If we're just here to do a revocation or refresh the CRL, we're done.
+if $revoke_cert || $refresh_crl ; then
+ exit 0
+fi
+
+# Create a new serial number and whatnot if this is a new sub-CA.
+if test "x$CA" = xTRUE ; then
+ if ! test -d "$commonname" ; then
+ mkdir "$commonname"
+ fi
+ if ! test -s "$commonname/ca.srl" ; then
+ (dd if=/dev/urandom bs=8 count=1 2> /dev/null) | od -t x1c | head -n 1 | awk '{$1="00";OFS="";print}' > "$commonname/ca.srl"
+ else
+ echo "You already have a $commonname/ca.srl file; not replacing."
+ fi
+ if test -n "$aia" ; then
+ echo -n "$aiaval" > "$commonname/ca.ocsp.uri.txt"
+ fi
+ if test -n "$crl" ; then
+ echo -n "$crlval" > "$commonname/ca.crldp.uri.txt"
+ fi
+ echo "$DOMAIN" > "$commonname/ca.domain.txt"
+ touch "$commonname/ca.db" "$commonname/ca.db.attr"
+ cert="$commonname/ca.crt"
+ csr="$commonname/ca.csr"
+ key="$commonname/ca.key"
+ pem="$commonname/ca.pem"
+ pfx="$commonname/ca.p12"
+ ln -s ../`basename $0` "$commonname"/
+else
+ cert="$commonname.crt"
+ csr="$commonname.csr"
+ key="$commonname.key"
+ pem="$commonname.pem"
+ pfx="$commonname.p12"
+fi
+
+# Generate the subject's certificate. Set the X.509v3 basic constraints.
+if ! test -s "$cert" ; then
+ # Generate another key, unless we have a key or CSR.
+ if ! test -s "$key" && ! test -s "$csr" ; then
+ umask=`umask -p`
+ umask 077
+ keygen "$commonname" > "$key" 2> /dev/null
+ $umask
+ else
+ echo "You already have a $key or $csr file; not replacing."
+ done=echo
+ fi
+
+ if ! test -s "$csr" ; then
+ sed -i -e 's,^\[req_issued\]$,\[req\],g' `pwd`/openssl.cnf
+ openssl req -config `pwd`/openssl.cnf -new -key "$key" > "$csr" 2> /dev/null
+ sed -i -e 's,^\[req\]$,\[req_issued\],g' `pwd`/openssl.cnf
+ fi
+ openssl ca -batch -config `pwd`/openssl.cnf -extensions v3_issued -preserveDN -in "$csr" -days $DAYS -out "$cert" 2> /dev/null
+ openssl x509 -noout -text -in "$cert" > "$cert.txt"
+ cat "$cert" >> "$cert.txt"
+ cat "$cert.txt" > "$cert"
+ rm -f "$cert.txt"
+else
+ echo "You already have a $cert file; not replacing."
+ done=echo
+fi
+
+if test -s ca.chain.crt ; then
+ chain=ca.chain.crt
+else
+ chain=ca.crt
+fi
+if test "x$CA" = xTRUE ; then
+ cat "$chain" "$cert" > "$commonname/ca.chain.crt"
+fi
+
+# Create ca.pem and the subject's name.pem for the benefit of applications
+# which expect both the private key and the certificate in one file.
+umask=`umask -p`
+umask 077
+if ! test -s ca.pem ; then
+ cat ca.key ca.crt > ca.pem
+else
+ echo "You already have a ca.pem file; not replacing."
+ done=echo
+fi
+if ! test -s "$pem" ; then
+ cat "$key" "$cert" > "$pem"
+else
+ echo "You already have a $pem file; not replacing."
+ done=echo
+fi
+if ! test -s "$pfx" ; then
+ #openssl pkcs12 -export -inkey "$key" -in "$cert" -name "$commonname" -out "$pfx" -nodes -passout pass:qweqwe
+ openssl pkcs12 -export -inkey "$key" -in "$cert" -name "$commonname" -out "$pfx" -nodes -passout pass:
+else
+ echo "You already have a $pfx file; not replacing."
+ done=echo
+fi
+$umask
+$done
+
+echo CA certificate:
+openssl x509 -noout -issuer -in ca.crt | sed s,=\ ,\ ,g
+openssl x509 -noout -subject -in ca.crt | sed s,=\ ,\ ,g
+echo
+echo End entity certificate:
+openssl x509 -noout -issuer -in "$cert" | sed s,=\ ,\ ,g
+openssl x509 -noout -subject -in "$cert" | sed s,=\ ,\ ,g
+openssl x509 -noout -serial -in "$cert" | sed s,=,\ ,g
+echo
+echo PKCS12 bag:
+openssl pkcs12 -in "$pfx" -nodes -nokeys -nocerts -info -passin pass:
+#openssl pkcs12 -in "$pfx" -nodes -nokeys -nocerts -info -passin pass:qweqwe
+echo
+echo Verifying:
+echo + openssl verify -CAfile "$chain" "$cert"
+openssl verify -CAfile "$chain" "$cert"
diff --git a/shim.c b/shim.c
index 8130ed8..4d490b9 100644
--- a/shim.c
+++ b/shim.c
@@ -40,6 +40,7 @@
#include "shim.h"
#include "signature.h"
#include "netboot.h"
+#include "shim_cert.h"
#define SECOND_STAGE L"\\grub.efi"
#define MOK_MANAGER L"\\MokManager.efi"
@@ -415,6 +416,8 @@ static BOOLEAN secure_mode (void)
UINT8 sb, setupmode;
UINT32 attributes;
+ return TRUE;
+
if (insecure_mode)
return FALSE;
@@ -696,6 +699,19 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
}
/*
+ * Check against the shim build key
+ */
+ if (AuthenticodeVerify(cert->CertData,
+ context->SecDir->Size - sizeof(cert->Hdr),
+ shim_cert, sizeof(shim_cert), sha256hash,
+ SHA256_DIGEST_SIZE)) {
+ status = EFI_SUCCESS;
+ Print(L"Binary is verified by the vendor certificate\n");
+ return status;
+ }
+
+
+ /*
* And finally, check against shim's built-in key
*/
if (AuthenticodeVerify(cert->CertData,
@@ -1180,12 +1196,8 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
efi_status = start_image(image_handle, SECOND_STAGE);
- if (efi_status != EFI_SUCCESS) {
- if (efi_status == EFI_ACCESS_DENIED)
- efi_status = start_image(image_handle, MOK_MANAGER);
- else
- Print(L"Failed to start grub\n");
- }
+ if (efi_status != EFI_SUCCESS)
+ efi_status = start_image(image_handle, MOK_MANAGER);
done:
return efi_status;
--
1.7.10.4
From 9c0c64ebde4ec504fc4e4d92ea18b889b1ccd498 Mon Sep 17 00:00:00 2001
From: Matthew Garrett <mjg59@srcf.ucam.org>
Date: Tue, 27 Nov 2012 23:52:27 -0500
Subject: [PATCH 2/2] Remove debug code
secure_mode() was altered to always return true for debug purposes, and this
accidentally got committed to mainline. Fix that.
---
shim.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/shim.c b/shim.c
index 4d490b9..c3aae9e 100644
--- a/shim.c
+++ b/shim.c
@@ -416,8 +416,6 @@ static BOOLEAN secure_mode (void)
UINT8 sb, setupmode;
UINT32 attributes;
- return TRUE;
-
if (insecure_mode)
return FALSE;
--
1.7.10.4

View File

@ -0,0 +1,218 @@
From 6e816e3e0f8b2013c1bccd67ec27db10ccaabc67 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 15 Jan 2013 18:01:41 +0800
Subject: [PATCH 2/2] Support new password hash
Old password hash: sha256sum(key_list + password)
New password hash: salt + sha256sum(salt + password)
---
MokManager.c | 91 ++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 67 insertions(+), 24 deletions(-)
diff --git a/MokManager.c b/MokManager.c
index 97588cb..be2a764 100644
--- a/MokManager.c
+++ b/MokManager.c
@@ -19,6 +19,9 @@
#define CERT_STRING L"Select an X509 certificate to enroll:\n\n"
#define HASH_STRING L"Select a file to trust:\n\n"
+#define SALT_LEN 16
+#define AUTH_LEN (SALT_LEN + SHA256_DIGEST_SIZE)
+
struct menu_item {
CHAR16 *text;
INTN (* callback)(void *data, void *data2, void *data3);
@@ -648,23 +651,30 @@ static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
EFI_STATUS efi_status;
- UINT8 auth[SHA256_DIGEST_SIZE];
- UINTN auth_size;
+ UINT8 data[AUTH_LEN], *auth, *salt;
+ UINTN auth_size = AUTH_LEN;
UINT32 attributes;
if (authenticate) {
- auth_size = SHA256_DIGEST_SIZE;
efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
&shim_lock_guid,
- &attributes, &auth_size, auth);
+ &attributes, &auth_size, data);
- if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) {
+ if (efi_status != EFI_SUCCESS ||
+ (auth_size != SHA256_DIGEST_SIZE && auth_size != AUTH_LEN)) {
Print(L"Failed to get MokAuth %d\n", efi_status);
return efi_status;
}
- efi_status = match_password(MokNew, MokNewSize, auth, NULL);
+ if (auth_size == AUTH_LEN) {
+ salt = data;
+ auth = data + SALT_LEN;
+ efi_status = match_password(salt, SALT_LEN, auth, NULL);
+ } else {
+ auth = data;
+ efi_status = match_password(MokNew, MokNewSize, auth, NULL);
+ }
if (efi_status != EFI_SUCCESS)
return EFI_ACCESS_DENIED;
}
@@ -842,8 +852,8 @@ static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
EFI_STATUS efi_status;
- UINT8 auth[SHA256_DIGEST_SIZE];
- UINTN auth_size = SHA256_DIGEST_SIZE;
+ UINT8 data[AUTH_LEN], *auth, *salt;;
+ UINTN auth_size = AUTH_LEN;
UINT32 attributes;
void *MokListData = NULL;
UINTN MokListDataSize = 0;
@@ -853,14 +863,22 @@ static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize)
efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth",
&shim_lock_guid,
- &attributes, &auth_size, auth);
+ &attributes, &auth_size, data);
- if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) {
+ if (efi_status != EFI_SUCCESS ||
+ (auth_size != SHA256_DIGEST_SIZE && auth_size != AUTH_LEN)) {
Print(L"Failed to get MokDelAuth %d\n", efi_status);
return efi_status;
}
- efi_status = match_password(MokDel, MokDelSize, auth, NULL);
+ if (auth_size == AUTH_LEN) {
+ salt = data;
+ auth = data + SALT_LEN;
+ efi_status = match_password(salt, SALT_LEN, auth, NULL);
+ } else {
+ auth = data;
+ efi_status = match_password(MokDel, MokDelSize, auth, NULL);
+ }
if (efi_status != EFI_SUCCESS)
return EFI_ACCESS_DENIED;
@@ -1052,20 +1070,29 @@ static INTN mok_pw_prompt (void *MokPW, void *data2, void *data3) {
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
EFI_STATUS efi_status;
UINTN MokPWSize = (UINTN)data2;
- UINT8 hash[SHA256_DIGEST_SIZE];
+ UINT8 hash[AUTH_LEN], *auth, *salt;
+ UINT8 clear = 0;
UINT32 length;
CHAR16 line[1];
- if (MokPWSize != SHA256_DIGEST_SIZE) {
+ if (MokPWSize != SHA256_DIGEST_SIZE && MokPWSize != AUTH_LEN) {
Print(L"Invalid MokPW variable contents\n");
return -1;
}
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
- SetMem(hash, SHA256_DIGEST_SIZE, 0);
+ SetMem(hash, AUTH_LEN, 0);
+
+ if (MokPWSize == AUTH_LEN) {
+ if (CompareMem(MokPW, hash, AUTH_LEN) == 0)
+ clear = 1;
+ } else {
+ if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) == 0)
+ clear = 1;
+ }
- if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) == 0) {
+ if (clear) {
Print(L"Clear MOK password? (y/n): ");
do {
@@ -1080,7 +1107,14 @@ static INTN mok_pw_prompt (void *MokPW, void *data2, void *data3) {
return 0;
}
- efi_status = match_password(NULL, 0, MokPW, L"Confirm MOK passphrase: ");
+ if (MokPWSize == AUTH_LEN) {
+ salt = MokPW;
+ auth = MokPW + SALT_LEN;
+ efi_status = match_password(salt, SALT_LEN, auth, L"Confirm MOK passphrase: ");
+ } else {
+ efi_status = match_password(NULL, 0, MokPW, L"Confirm MOK passphrase: ");
+ }
+
if (efi_status != EFI_SUCCESS) {
Print(L"Password limit reached\n");
return -1;
@@ -1691,8 +1725,8 @@ static BOOLEAN verify_pw(void)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
EFI_STATUS efi_status;
- UINT8 pwhash[SHA256_DIGEST_SIZE];
- UINTN size = SHA256_DIGEST_SIZE;
+ UINT8 pwhash[AUTH_LEN], *auth, *salt;
+ UINTN size = AUTH_LEN;
UINT32 attributes;
efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokPWStore",
@@ -1704,7 +1738,8 @@ static BOOLEAN verify_pw(void)
* known value, so there's no safety advantage in failing to validate
* purely because of a failure to read the variable
*/
- if (efi_status != EFI_SUCCESS)
+ if (efi_status != EFI_SUCCESS ||
+ (size != SHA256_DIGEST_SIZE && size != AUTH_LEN))
return TRUE;
if (attributes & EFI_VARIABLE_RUNTIME_ACCESS)
@@ -1712,7 +1747,13 @@ static BOOLEAN verify_pw(void)
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
- efi_status = match_password(NULL, 0, pwhash, L"Enter MOK password: ");
+ if (size == AUTH_LEN) {
+ salt = pwhash;
+ auth = pwhash + SALT_LEN;
+ efi_status = match_password(salt, SALT_LEN, auth, L"Enter MOK password: ");
+ } else {
+ efi_status = match_password(NULL, 0, pwhash, L"Enter MOK password: ");
+ }
if (efi_status != EFI_SUCCESS) {
Print(L"Password limit reached\n");
return FALSE;
@@ -1733,8 +1774,8 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
UINTN menucount = 3, i = 0;
EFI_STATUS efi_status;
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- UINT8 auth[SHA256_DIGEST_SIZE];
- UINTN auth_size = SHA256_DIGEST_SIZE;
+ UINT8 auth[AUTH_LEN];
+ UINTN auth_size = AUTH_LEN;
UINT32 attributes;
if (verify_pw() == FALSE)
@@ -1744,14 +1785,16 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
&shim_lock_guid,
&attributes, &auth_size, auth);
- if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE))
+ if ((efi_status == EFI_SUCCESS) &&
+ (auth_size == SHA256_DIGEST_SIZE || auth_size == AUTH_LEN))
MokAuth = 1;
efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth",
&shim_lock_guid,
&attributes, &auth_size, auth);
- if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE))
+ if ((efi_status == EFI_SUCCESS) &&
+ (auth_size == SHA256_DIGEST_SIZE || auth_size == AUTH_LEN))
MokDelAuth = 1;
if (MokNew || MokAuth)
--
1.7.10.4

View File

@ -0,0 +1,94 @@
From 10f0f58b03b3bcc56797744f25be15b226b51a50 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Mon, 10 Dec 2012 17:54:05 +0800
Subject: [PATCH 1/2] Clear the screen before erasing keys
---
MokManager.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/MokManager.c b/MokManager.c
index 5802d27..c6f84d8 100644
--- a/MokManager.c
+++ b/MokManager.c
@@ -675,6 +675,7 @@ static INTN mok_deletion_prompt (void *MokNew, void *data2, void *data3) {
UINT32 length;
EFI_STATUS efi_status;
+ uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
Print(L"Erase all stored keys? (y/N): ");
get_line (&length, line, 1, 1);
--
1.7.10.4
From 510dafda53cd56210d7ff634b1c630d3645150f0 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Mon, 10 Dec 2012 18:24:45 +0800
Subject: [PATCH 2/2] Reboot the system after enrolling/erasing keys
---
MokManager.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/MokManager.c b/MokManager.c
index c6f84d8..7d6650e 100644
--- a/MokManager.c
+++ b/MokManager.c
@@ -637,6 +637,7 @@ static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
}
static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth) {
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
CHAR16 line[1];
UINT32 length;
EFI_STATUS efi_status;
@@ -657,6 +658,19 @@ static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth) {
Print(L"Failed to enroll keys\n");
return -1;
}
+
+ if (auth) {
+ LibDeleteVariable(L"MokNew", &shim_lock_guid);
+ LibDeleteVariable(L"MokAuth", &shim_lock_guid);
+
+ Print(L"\nPress a key to reboot system\n");
+ Pause();
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
+ EFI_SUCCESS, 0, NULL);
+ Print(L"Failed to reboot\n");
+ return -1;
+ }
+
return 0;
}
} while (line[0] != 'N' && line[0] != 'n');
@@ -671,6 +685,7 @@ static INTN mok_enrollment_prompt_callback (void *MokNew, void *data2,
}
static INTN mok_deletion_prompt (void *MokNew, void *data2, void *data3) {
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
CHAR16 line[1];
UINT32 length;
EFI_STATUS efi_status;
@@ -687,6 +702,16 @@ static INTN mok_deletion_prompt (void *MokNew, void *data2, void *data3) {
Print(L"Failed to erase keys\n");
return -1;
}
+
+ LibDeleteVariable(L"MokNew", &shim_lock_guid);
+ LibDeleteVariable(L"MokAuth", &shim_lock_guid);
+
+ Print(L"\nPress a key to reboot system\n");
+ Pause();
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
+ EFI_SUCCESS, 0, NULL);
+ Print(L"Failed to reboot\n");
+ return -1;
}
return 0;
--
1.7.10.4

View File

@ -0,0 +1,763 @@
From 5abe73ab8177f0d831ff04ca67a8ed92ef09ca8b Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Thu, 20 Dec 2012 17:02:35 +0800
Subject: [PATCH 1/3] Add a general function for password matching
---
MokManager.c | 148 ++++++++++++++++++++++------------------------------------
1 file changed, 57 insertions(+), 91 deletions(-)
diff --git a/MokManager.c b/MokManager.c
index 7d6650e..ffe37ff 100644
--- a/MokManager.c
+++ b/MokManager.c
@@ -558,17 +558,61 @@ done:
return status;
}
+static EFI_STATUS match_password (void *Data, UINTN DataSize,
+ UINT8 auth[SHA256_DIGEST_SIZE],
+ CHAR16 *prompt)
+{
+ EFI_STATUS efi_status;
+ UINT8 hash[SHA256_DIGEST_SIZE];
+ CHAR16 password[PASSWORD_MAX];
+ UINT32 pw_length;
+ UINT8 fail_count = 0;
+
+ while (fail_count < 3) {
+ if (prompt) {
+ Print(L"%s", prompt);
+ } else {
+ Print(L"Password: ");
+ }
+ get_line(&pw_length, password, PASSWORD_MAX, 0);
+
+ if (pw_length < PASSWORD_MIN || pw_length > PASSWORD_MAX) {
+ Print(L"Invalid password length\n");
+ fail_count++;
+ continue;
+ }
+
+ efi_status = compute_pw_hash(Data, DataSize, password,
+ pw_length, hash);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Unable to generate password hash\n");
+ fail_count++;
+ continue;
+ }
+
+ if (CompareMem(auth, hash, SHA256_DIGEST_SIZE) != 0) {
+ Print(L"Password doesn't match\n");
+ fail_count++;
+ continue;
+ }
+
+ break;
+ }
+
+ if (fail_count >= 3)
+ return EFI_ACCESS_DENIED;
+
+ return EFI_SUCCESS;
+}
+
static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
EFI_STATUS efi_status;
- UINT8 hash[SHA256_DIGEST_SIZE];
UINT8 auth[SHA256_DIGEST_SIZE];
UINTN auth_size;
UINT32 attributes;
- CHAR16 password[PASSWORD_MAX];
- UINT32 pw_length;
- UINT8 fail_count = 0;
if (authenticate) {
auth_size = SHA256_DIGEST_SIZE;
@@ -582,32 +626,8 @@ static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
return efi_status;
}
- while (fail_count < 3) {
- Print(L"Password(%d-%d characters): ",
- PASSWORD_MIN, PASSWORD_MAX);
- get_line(&pw_length, password, PASSWORD_MAX, 0);
-
- if (pw_length < 8) {
- Print(L"At least %d characters for the password\n",
- PASSWORD_MIN);
- }
-
- efi_status = compute_pw_hash(MokNew, MokNewSize, password,
- pw_length, hash);
-
- if (efi_status != EFI_SUCCESS) {
- return efi_status;
- }
-
- if (CompareMem(auth, hash, SHA256_DIGEST_SIZE) != 0) {
- Print(L"Password doesn't match\n");
- fail_count++;
- } else {
- break;
- }
- }
-
- if (fail_count >= 3)
+ efi_status = match_password(MokNew, MokNewSize, auth, NULL);
+ if (efi_status != EFI_SUCCESS)
return EFI_ACCESS_DENIED;
}
@@ -819,9 +839,7 @@ static INTN mok_pw_prompt (void *MokPW, void *data2, void *data3) {
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
EFI_STATUS efi_status;
UINTN MokPWSize = (UINTN)data2;
- UINT8 fail_count = 0;
UINT8 hash[SHA256_DIGEST_SIZE];
- CHAR16 password[PASSWORD_MAX];
UINT32 length;
CHAR16 line[1];
@@ -849,34 +867,8 @@ static INTN mok_pw_prompt (void *MokPW, void *data2, void *data3) {
return 0;
}
- while (fail_count < 3) {
- Print(L"Confirm MOK passphrase: ");
- get_line(&length, password, PASSWORD_MAX, 0);
-
- if ((length < PASSWORD_MIN) || (length > PASSWORD_MAX)) {
- Print(L"Invalid password length\n");
- fail_count++;
- continue;
- }
-
- efi_status = compute_pw_hash(NULL, 0, password, length, hash);
-
- if (efi_status != EFI_SUCCESS) {
- Print(L"Unable to generate password hash\n");
- fail_count++;
- continue;
- }
-
- if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) != 0) {
- Print(L"Password doesn't match\n");
- fail_count++;
- continue;
- }
-
- break;
- }
-
- if (fail_count >= 3) {
+ efi_status = match_password(NULL, 0, MokPW, L"Confirm MOK passphrase: ");
+ if (efi_status != EFI_SUCCESS) {
Print(L"Password limit reached\n");
return -1;
}
@@ -1483,12 +1475,8 @@ static BOOLEAN verify_pw(void)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
EFI_STATUS efi_status;
- CHAR16 password[PASSWORD_MAX];
- UINT8 fail_count = 0;
- UINT8 hash[SHA256_DIGEST_SIZE];
UINT8 pwhash[SHA256_DIGEST_SIZE];
UINTN size = SHA256_DIGEST_SIZE;
- UINT32 length;
UINT32 attributes;
efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokPWStore",
@@ -1508,35 +1496,13 @@ static BOOLEAN verify_pw(void)
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
- while (fail_count < 3) {
- Print(L"Enter MOK password: ");
- get_line(&length, password, PASSWORD_MAX, 0);
-
- if (length < PASSWORD_MIN || length > PASSWORD_MAX) {
- Print(L"Invalid password length\n");
- fail_count++;
- continue;
- }
-
- efi_status = compute_pw_hash(NULL, 0, password, length, hash);
-
- if (efi_status != EFI_SUCCESS) {
- Print(L"Unable to generate password hash\n");
- fail_count++;
- continue;
- }
-
- if (CompareMem(pwhash, hash, SHA256_DIGEST_SIZE) != 0) {
- Print(L"Password doesn't match\n");
- fail_count++;
- continue;
- }
-
- return TRUE;
+ efi_status = match_password(NULL, 0, pwhash, L"Enter MOK password: ");
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Password limit reached\n");
+ return FALSE;
}
- Print(L"Password limit reached\n");
- return FALSE;
+ return TRUE;
}
static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
--
1.7.10.4
From 0c6a8a7501f2eb4e751c33090c6763044d131b96 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Fri, 21 Dec 2012 15:02:09 +0800
Subject: [PATCH 2/3] MOK doesn't include the signature owner
---
MokManager.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/MokManager.c b/MokManager.c
index ffe37ff..ddf12de 100644
--- a/MokManager.c
+++ b/MokManager.c
@@ -124,7 +124,7 @@ static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) +
sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
- list[count].MokSize = CertList->SignatureSize;
+ list[count].MokSize = CertList->SignatureSize - sizeof(EFI_GUID);
list[count].Mok = (void *)Cert->SignatureData;
count++;
@@ -317,7 +317,7 @@ static void show_mok_info (void *Mok, UINTN MokSize)
if (!Mok || MokSize == 0)
return;
- if (MokSize != 48) {
+ if (MokSize != SHA256_DIGEST_SIZE) {
if (X509ConstructCertificate(Mok, MokSize,
(UINT8 **) &X509Cert) && X509Cert != NULL) {
show_x509_info(X509Cert);
--
1.7.10.4
From 990dcdb6a6cea2a22ef237b68630aa30784184c4 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Fri, 21 Dec 2012 17:59:31 +0800
Subject: [PATCH 3/3] Add support for deleting specific keys
---
MokManager.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
shim.c | 3 +-
2 files changed, 293 insertions(+), 46 deletions(-)
diff --git a/MokManager.c b/MokManager.c
index ddf12de..bfcbfd6 100644
--- a/MokManager.c
+++ b/MokManager.c
@@ -31,6 +31,7 @@ struct menu_item {
typedef struct {
UINT32 MokSize;
UINT8 *Mok;
+ EFI_GUID Type;
} __attribute__ ((packed)) MokListNode;
typedef struct {
@@ -39,6 +40,32 @@ typedef struct {
CHAR16 Password[PASSWORD_MAX];
} __attribute__ ((packed)) MokSBvar;
+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;
+}
+
static EFI_INPUT_KEY get_keystroke (void)
{
EFI_INPUT_KEY key;
@@ -88,6 +115,42 @@ done:
return status;
}
+static UINT32 count_keys(void *Data, UINTN DataSize)
+{
+ EFI_SIGNATURE_LIST *CertList = Data;
+ EFI_GUID CertType = EfiCertX509Guid;
+ EFI_GUID HashType = EfiHashSha256Guid;
+ UINTN dbsize = DataSize;
+ UINT32 MokNum = 0;
+
+ while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
+ if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
+ (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
+ Print(L"Doesn't look like a key or hash\n");
+ dbsize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
+ CertList->SignatureListSize);
+ continue;
+ }
+
+ if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
+ (CertList->SignatureSize != 48)) {
+ Print(L"Doesn't look like a valid hash\n");
+ dbsize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
+ CertList->SignatureListSize);
+ continue;
+ }
+
+ MokNum++;
+ dbsize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
+ CertList->SignatureListSize);
+ }
+
+ return MokNum;
+}
+
static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
MokListNode *list;
EFI_SIGNATURE_LIST *CertList = Data;
@@ -126,6 +189,7 @@ static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
list[count].MokSize = CertList->SignatureSize - sizeof(EFI_GUID);
list[count].Mok = (void *)Cert->SignatureData;
+ list[count].Type = CertList->SignatureType;
count++;
dbsize -= CertList->SignatureListSize;
@@ -391,61 +455,35 @@ static INTN get_number ()
return (INTN)Atoi(input);
}
-static UINT8 list_keys (void *MokNew, UINTN MokNewSize)
+static UINT8 list_keys (void *KeyList, UINTN KeyListSize, CHAR16 *title)
{
UINT32 MokNum = 0;
MokListNode *keys = NULL;
INTN key_num = 0;
UINT8 initial = 1;
- EFI_SIGNATURE_LIST *CertList = MokNew;
- EFI_GUID CertType = EfiCertX509Guid;
- EFI_GUID HashType = EfiHashSha256Guid;
- UINTN dbsize = MokNewSize;
- if (MokNewSize < (sizeof(EFI_SIGNATURE_LIST) +
- sizeof(EFI_SIGNATURE_DATA))) {
+ if (KeyListSize < (sizeof(EFI_SIGNATURE_LIST) +
+ sizeof(EFI_SIGNATURE_DATA))) {
Print(L"No keys\n");
Pause();
return 0;
}
- while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
- if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
- (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
- Print(L"Doesn't look like a key or hash\n");
- dbsize -= CertList->SignatureListSize;
- CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
- CertList->SignatureListSize);
- continue;
- }
-
- if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
- (CertList->SignatureSize != 48)) {
- Print(L"Doesn't look like a valid hash\n");
- dbsize -= CertList->SignatureListSize;
- CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
- CertList->SignatureListSize);
- continue;
- }
-
- MokNum++;
- dbsize -= CertList->SignatureListSize;
- CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
- CertList->SignatureListSize);
- }
-
- keys = build_mok_list(MokNum, MokNew, MokNewSize);
+ MokNum = count_keys(KeyList, KeyListSize);
+ keys = build_mok_list(MokNum, KeyList, KeyListSize);
if (!keys) {
- Print(L"Failed to construct key list in MokNew\n");
+ Print(L"Failed to construct key list\n");
return 0;
}
do {
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
+ if (title)
+ Print(L"%s\n", title);
Print(L"Input the key number to show the details of the key or\n"
L"type \'0\' to continue\n\n");
- Print(L"%d key(s) in the new key list\n\n", MokNum);
+ Print(L"%d key(s) in the key list\n\n", MokNum);
if (key_num > MokNum) {
Print(L"[Key %d]\n", key_num);
@@ -663,7 +701,7 @@ static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth) {
EFI_STATUS efi_status;
do {
- if (!list_keys(MokNew, MokNewSize)) {
+ if (!list_keys(MokNew, MokNewSize, L"[Enroll MOK]")) {
return 0;
}
@@ -704,7 +742,8 @@ static INTN mok_enrollment_prompt_callback (void *MokNew, void *data2,
return mok_enrollment_prompt(MokNew, (UINTN)data2, TRUE);
}
-static INTN mok_deletion_prompt (void *MokNew, void *data2, void *data3) {
+static INTN mok_reset_prompt (void *MokNew, void *data2, void *data3)
+{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
CHAR16 line[1];
UINT32 length;
@@ -737,6 +776,180 @@ static INTN mok_deletion_prompt (void *MokNew, void *data2, void *data3) {
return 0;
}
+static EFI_STATUS write_back_mok_list (MokListNode *list, INTN key_num)
+{
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ EFI_STATUS efi_status;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *CertData;
+ void *Data = NULL, *ptr;
+ INTN DataSize = 0;
+ int i;
+
+ for (i = 0; i < key_num; i++) {
+ if (list[i].Mok == NULL)
+ continue;
+
+ DataSize += sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID);
+ DataSize += list[i].MokSize;
+ }
+
+ Data = AllocatePool(DataSize);
+ if (Data == NULL && DataSize != 0)
+ return EFI_OUT_OF_RESOURCES;
+
+ ptr = Data;
+
+ for (i = 0; i < key_num; i++) {
+ if (list[i].Mok == NULL)
+ continue;
+
+ CertList = (EFI_SIGNATURE_LIST *)ptr;
+ CertData = (EFI_SIGNATURE_DATA *)(((uint8_t *)ptr) +
+ sizeof(EFI_SIGNATURE_LIST));
+
+ CertList->SignatureType = list[i].Type;
+ CertList->SignatureListSize = list[i].MokSize +
+ sizeof(EFI_SIGNATURE_LIST) +
+ sizeof(EFI_SIGNATURE_DATA) - 1;
+ CertList->SignatureHeaderSize = 0;
+ CertList->SignatureSize = list[i].MokSize + sizeof(EFI_GUID);
+
+ CertData->SignatureOwner = shim_lock_guid;
+ CopyMem(CertData->SignatureData, list[i].Mok, list[i].MokSize);
+
+ ptr = (uint8_t *)ptr + sizeof(EFI_SIGNATURE_LIST) +
+ sizeof(EFI_GUID) + list[i].MokSize;
+ }
+
+ efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
+ &shim_lock_guid,
+ EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ DataSize, Data);
+ if (Data)
+ FreePool(Data);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to set variable %d\n", efi_status);
+ return efi_status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize)
+{
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ EFI_STATUS efi_status;
+ UINT8 auth[SHA256_DIGEST_SIZE];
+ UINTN auth_size = SHA256_DIGEST_SIZE;
+ UINT32 attributes;
+ void *MokListData = NULL;
+ UINTN MokListDataSize = 0;
+ MokListNode *mok, *del_key;
+ INTN mok_num, del_num;
+ int i, j;
+
+ efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth",
+ &shim_lock_guid,
+ &attributes, &auth_size, auth);
+
+ if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) {
+ Print(L"Failed to get MokDelAuth %d\n", efi_status);
+ return efi_status;
+ }
+
+ efi_status = match_password(MokDel, MokDelSize, auth, NULL);
+ if (efi_status != EFI_SUCCESS)
+ return EFI_ACCESS_DENIED;
+
+ efi_status = get_variable(L"MokList", shim_lock_guid, &attributes,
+ &MokListDataSize, &MokListData);
+
+ if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
+ Print(L"MokList is compromised!\nErase all keys in MokList!\n");
+ if (LibDeleteVariable(L"MokList", &shim_lock_guid) != EFI_SUCCESS) {
+ Print(L"Failed to erase MokList\n");
+ }
+ return EFI_ACCESS_DENIED;
+ }
+
+ /* Nothing to do */
+ if (!MokListData || MokListDataSize == 0)
+ return EFI_SUCCESS;
+
+ /* Construct lists */
+ mok_num = count_keys(MokListData, MokListDataSize);
+ mok = build_mok_list(mok_num, MokListData, MokListDataSize);
+ del_num = count_keys(MokDel, MokDelSize);
+ del_key = build_mok_list(del_num, MokDel, MokDelSize);
+
+ /* Search and destroy */
+ for (i = 0; i < del_num; i++) {
+ UINT32 key_size = del_key[i].MokSize;
+ void *key = del_key[i].Mok;
+ for (j = 0; j < mok_num; j++) {
+ if (mok[j].MokSize == key_size &&
+ CompareMem(key, mok[j].Mok, key_size) == 0) {
+ /* Remove the key */
+ mok[j].Mok = NULL;
+ mok[j].MokSize = 0;
+ }
+ }
+ }
+
+ efi_status = write_back_mok_list(mok, mok_num);
+
+ if (MokListData)
+ FreePool(MokListData);
+ if (mok)
+ FreePool(mok);
+ if (del_key)
+ FreePool(del_key);
+
+ return efi_status;
+}
+
+static INTN mok_deletion_prompt (void *MokDel, void *data2, void *data3)
+{
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ UINTN MokDelSize = (UINTN)data2;
+ CHAR16 line[1];
+ UINT32 length;
+ EFI_STATUS efi_status;
+
+ do {
+ if (!list_keys(MokDel, MokDelSize, L"[Delete MOK]")) {
+ return 0;
+ }
+
+ Print(L"Delete the key(s)? (y/n): ");
+
+ get_line (&length, line, 1, 1);
+
+ if (line[0] == 'Y' || line[0] == 'y') {
+ efi_status = delete_keys(MokDel, MokDelSize);
+
+ if (efi_status != EFI_SUCCESS) {
+ Print(L"Failed to delete keys\n");
+ return -1;
+ }
+
+ LibDeleteVariable(L"MokDel", &shim_lock_guid);
+ LibDeleteVariable(L"MokDelAuth", &shim_lock_guid);
+
+ Print(L"\nPress a key to reboot system\n");
+ Pause();
+ uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
+ EFI_SUCCESS, 0, NULL);
+ Print(L"Failed to reboot\n");
+ return -1;
+ }
+ } while (line[0] != 'N' && line[0] != 'n');
+ return -1;
+}
+
static INTN mok_sb_prompt (void *MokSB, void *data2, void *data3) {
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
EFI_STATUS efi_status;
@@ -1505,12 +1718,15 @@ static BOOLEAN verify_pw(void)
return TRUE;
}
-static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
- UINTN MokNewSize, void *MokSB,
- UINTN MokSBSize, void *MokPW, UINTN MokPWSize)
+static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
+ void *MokNew, UINTN MokNewSize,
+ void *MokDel, UINTN MokDelSize,
+ void *MokSB, UINTN MokSBSize,
+ void *MokPW, UINTN MokPWSize)
{
struct menu_item *menu_item;
UINT32 MokAuth = 0;
+ UINT32 MokDelAuth = 0;
UINTN menucount = 3, i = 0;
EFI_STATUS efi_status;
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
@@ -1528,9 +1744,19 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE))
MokAuth = 1;
+ efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth",
+ &shim_lock_guid,
+ &attributes, &auth_size, auth);
+
+ if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE))
+ MokDelAuth = 1;
+
if (MokNew || MokAuth)
menucount++;
+ if (MokDel || MokDelAuth)
+ menucount++;
+
if (MokSB)
menucount++;
@@ -1550,9 +1776,9 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
if (MokNew || MokAuth) {
if (!MokNew) {
- menu_item[i].text = StrDuplicate(L"Delete MOK");
+ menu_item[i].text = StrDuplicate(L"Reset MOK");
menu_item[i].colour = EFI_WHITE;
- menu_item[i].callback = mok_deletion_prompt;
+ menu_item[i].callback = mok_reset_prompt;
} else {
menu_item[i].text = StrDuplicate(L"Enroll MOK");
menu_item[i].colour = EFI_WHITE;
@@ -1563,6 +1789,15 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
i++;
}
+ if (MokDel || MokDelAuth) {
+ menu_item[i].text = StrDuplicate(L"Delete MOK");
+ menu_item[i].colour = EFI_WHITE;
+ menu_item[i].data = MokDel;
+ menu_item[i].data2 = (void *)MokDelSize;
+ menu_item[i].callback = mok_deletion_prompt;
+ i++;
+ }
+
if (MokSB) {
menu_item[i].text = StrDuplicate(L"Change Secure Boot state");
menu_item[i].colour = EFI_WHITE;
@@ -1605,19 +1840,22 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, void *MokNew,
static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- UINTN MokNewSize = 0, MokSBSize = 0, MokPWSize = 0;
+ UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0;
void *MokNew = NULL;
+ void *MokDel = NULL;
void *MokSB = NULL;
void *MokPW = NULL;
MokNew = LibGetVariableAndSize(L"MokNew", &shim_lock_guid, &MokNewSize);
+ MokDel = LibGetVariableAndSize(L"MokDel", &shim_lock_guid, &MokDelSize);
+
MokSB = LibGetVariableAndSize(L"MokSB", &shim_lock_guid, &MokSBSize);
MokPW = LibGetVariableAndSize(L"MokPW", &shim_lock_guid, &MokPWSize);
- enter_mok_menu(image_handle, MokNew, MokNewSize, MokSB, MokSBSize,
- MokPW, MokPWSize);
+ enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize,
+ MokSB, MokSBSize, MokPW, MokPWSize);
if (MokNew) {
if (LibDeleteVariable(L"MokNew", &shim_lock_guid) != EFI_SUCCESS) {
@@ -1626,6 +1864,13 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
FreePool (MokNew);
}
+ if (MokDel) {
+ if (LibDeleteVariable(L"MokDel", &shim_lock_guid) != EFI_SUCCESS) {
+ Print(L"Failed to delete MokDel\n");
+ }
+ FreePool (MokDel);
+ }
+
if (MokSB) {
if (LibDeleteVariable(L"MokSB", &shim_lock_guid) != EFI_SUCCESS) {
Print(L"Failed to delete MokSB\n");
@@ -1641,6 +1886,7 @@ static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
}
LibDeleteVariable(L"MokAuth", &shim_lock_guid);
+ LibDeleteVariable(L"MokDelAuth", &shim_lock_guid);
return EFI_SUCCESS;
}
diff --git a/shim.c b/shim.c
index 44301dd..dcf1c51 100644
--- a/shim.c
+++ b/shim.c
@@ -1271,7 +1271,8 @@ EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
EFI_STATUS efi_status;
if (check_var(L"MokNew") || check_var(L"MokSB") ||
- check_var(L"MokPW") || check_var(L"MokAuth")) {
+ check_var(L"MokPW") || check_var(L"MokAuth") ||
+ check_var(L"MokDel")) {
efi_status = start_image(image_handle, MOK_MANAGER);
if (efi_status != EFI_SUCCESS) {
--
1.7.10.4

13
shim-suse-build.patch Normal file
View File

@ -0,0 +1,13 @@
Index: shim-0.2/Makefile
===================================================================
--- shim-0.2.orig/Makefile
+++ shim-0.2/Makefile
@@ -6,7 +6,7 @@ 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_PATH = /usr/lib64
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)

66
shim.changes Normal file
View File

@ -0,0 +1,66 @@
-------------------------------------------------------------------
Wed Jan 16 08:01:55 UTC 2013 - glin@suse.com
- Merge patches for FATE#314506
+ Add shim-support-mok-delete.patch to add support for deleting
specific keys
+ Add shim-mokmanager-new-pw-hash.patch to support the new
password hash.
- Drop shim-correct-mok-size.patch which is included in
shim-support-mok-delete.patch
- Merge shim-remove-debug-code.patch and
shim-local-sign-mokmanager.patch into
shim-local-key-sign-mokmanager.patch
- Install COPYRIGHT
-------------------------------------------------------------------
Tue Jan 15 03:17:53 UTC 2013 - glin@suse.com
- Add shim-fix-loadoptions.patch to adopt the UEFI shell style
LoadOptions (bnc#798043)
- Drop shim-check-pk-kek.patch since upstream rejected the patch
due to violation of SPEC.
- Install EFI binaries to /usr/lib64/efi
-------------------------------------------------------------------
Wed Dec 26 07:05:02 UTC 2012 - glin@suse.com
- Update shim-reboot-after-changes.patch to avoid rebooting the
system after enrolling keys/hashes from the file system
- Add shim-correct-mok-size.patch to correct the size of MOK
- Add shim-clear-queued-key.patch to clear the queued key and show
the menu properly
-------------------------------------------------------------------
Wed Dec 12 15:16:18 UTC 2012 - fcrozat@suse.com
- Remove shim-rpmlintrc, it wasn't fixing the error, hide error
stdout to prevent post build check to get triggered by cast
warnings in openSSL code
- Add shim-remove-debug-code.patch: remove debug code
-------------------------------------------------------------------
Wed Dec 12 04:01:52 UTC 2012 - glin@suse.com
- Add shim-rpmlintrc to filter 64bit portability errors
-------------------------------------------------------------------
Tue Dec 11 07:36:32 UTC 2012 - glin@suse.com
- Add shim-local-sign-mokmanager.patch to create a local certicate
to sign MokManager
- Add shim-get-2nd-stage-loader.patch to get the second stage
loader path from the load options
- Add shim-check-pk-kek.patch to verify EFI images with PK and KEK
- Add shim-reboot-after-changes.patch to reboot the system after
enrolling or erasing keys
- Install the EFI images to /usr/lib64/shim instead of the EFI
partition
- Update the mail address of the author
-------------------------------------------------------------------
Fri Nov 2 08:19:37 UTC 2012 - glin@suse.com
- Add new package shim 0.2 (FATE#314484)
+ It's in fact git 2fd180a92 since there is no tag for 0.2

92
shim.spec Normal file
View File

@ -0,0 +1,92 @@
#
# spec file for package shim
#
# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
Name: shim
Version: 0.2
Release: 0
Summary: UEFI shim loader
License: BSD-2-Clause
Group: System/Boot
Url: https://github.com/mjg59/shim
Source: %{name}-%{version}.tar.bz2
# PATCH-FIX-SUSE shim-suse-build.patch glin@suse.com -- Adjust Makefile for the build service
Patch0: shim-suse-build.patch
# PATCH-FIX-UPSTREAM shim-local-key-sign-mokmanager.patch glin@suse.com -- Sign MokManager.efi with the local generated certificate
Patch1: shim-local-key-sign-mokmanager.patch
# PATCH-FEATURE-UPSTREAM shim-get-2nd-stage-loader.patch glin@suse.com -- Get the second stage loader path from the load options
Patch2: shim-get-2nd-stage-loader.patch
# PATCH-FIX-UPSTREAM shim-reboot-after-changes.patch glin@suse.com -- Reboot the system after enrolling or erasing keys
Patch3: shim-reboot-after-changes.patch
# PATCH-FIX-UPSTREAM shim-clear-queued-key.patch glin@suse.com -- Clear the queued key to show the menu properly
Patch5: shim-clear-queued-key.patch
# PATCH-FIX-UPSTREAM shim-fix-loadoptions.patch bnc#798043 glin@suse.com -- Adopt the UEFI shell style LoadOptions
Patch6: shim-fix-loadoptions.patch
# PATCH-FIX-UPSTREAM shim-support-mok-delete.patch glin@suse.com -- Support for deleting specific keys
Patch7: shim-support-mok-delete.patch
# PATCH-FIX-UPSTREAM shim-mokmanager-new-pw-hash.patch glin@suse.com -- Support the new password hash
Patch8: shim-mokmanager-new-pw-hash.patch
BuildRequires: gnu-efi >= 3.0q
BuildRequires: mozilla-nss-tools
BuildRequires: openssl >= 0.9.8
BuildRequires: pesign
BuildRoot: %{_tmppath}/%{name}-%{version}-build
ExclusiveArch: x86_64
%description
shim is a trivial EFI application that, when run, attempts to open and
execute another application.
Authors:
--------
Matthew Garrett <mjg59@srcf.ucam.org>
%prep
%setup -q
%patch0 -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%build
chmod +x "make-certs"
# make sure cast warnings don't trigger post build check
make 2>/dev/null
# make VENDOR_CERT_FILE=cert.der VENDOR_DBX_FILE=dbx
%install
install -d %{buildroot}/%{_libdir}/efi
install -m 444 shim.efi %{buildroot}/%{_libdir}/efi
install -m 444 MokManager.efi.signed %{buildroot}/%{_libdir}/efi/MokManager.efi
%clean
%{?buildroot:%__rm -rf "%{buildroot}"}
%files
%defattr(-,root,root)
%doc COPYRIGHT
%dir %{_libdir}/efi
%{_libdir}/efi/shim.efi
%{_libdir}/efi/MokManager.efi
%changelog