commit d7945289e54225f558e2c773f5b3bcaeb97fb884e6898b3eaf0fe3121b756e8b Author: Stephan Kulow Date: Thu Jan 17 09:43:06 2013 +0000 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 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9b03811 --- /dev/null +++ b/.gitattributes @@ -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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57affb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.osc diff --git a/shim-0.2.tar.bz2 b/shim-0.2.tar.bz2 new file mode 100644 index 0000000..47d444c --- /dev/null +++ b/shim-0.2.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:866b1d73d022baa4874dede94bfd2525954b986db9497e6a8f6f2c7e5fea5852 +size 940450 diff --git a/shim-clear-queued-key.patch b/shim-clear-queued-key.patch new file mode 100644 index 0000000..544b3f6 --- /dev/null +++ b/shim-clear-queued-key.patch @@ -0,0 +1,30 @@ +From daa6a7519caa23ef69b9a879bc70789a0669b3e3 Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +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 + diff --git a/shim-fix-loadoptions.patch b/shim-fix-loadoptions.patch new file mode 100644 index 0000000..74923e4 --- /dev/null +++ b/shim-fix-loadoptions.patch @@ -0,0 +1,84 @@ +commit f23f6b726bd12b28befd5a064c47a8a249d80a59 +Author: Gary Ching-Pang Lin +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; + } diff --git a/shim-get-2nd-stage-loader.patch b/shim-get-2nd-stage-loader.patch new file mode 100644 index 0000000..42e225b --- /dev/null +++ b/shim-get-2nd-stage-loader.patch @@ -0,0 +1,123 @@ +commit 940425a8bce6bf1b556dc48189884b4a82d8d420 +Author: Gary Ching-Pang Lin +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 diff --git a/shim-local-key-sign-mokmanager.patch b/shim-local-key-sign-mokmanager.patch new file mode 100644 index 0000000..feea2c8 --- /dev/null +++ b/shim-local-key-sign-mokmanager.patch @@ -0,0 +1,722 @@ +From 6d50f87a06ff70d2075863f4c145235c081263d6 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +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 $@ ++ 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 +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 + diff --git a/shim-mokmanager-new-pw-hash.patch b/shim-mokmanager-new-pw-hash.patch new file mode 100644 index 0000000..7c59f23 --- /dev/null +++ b/shim-mokmanager-new-pw-hash.patch @@ -0,0 +1,218 @@ +From 6e816e3e0f8b2013c1bccd67ec27db10ccaabc67 Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +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 + diff --git a/shim-reboot-after-changes.patch b/shim-reboot-after-changes.patch new file mode 100644 index 0000000..9256720 --- /dev/null +++ b/shim-reboot-after-changes.patch @@ -0,0 +1,94 @@ +From 10f0f58b03b3bcc56797744f25be15b226b51a50 Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +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 +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 + diff --git a/shim-support-mok-delete.patch b/shim-support-mok-delete.patch new file mode 100644 index 0000000..5b08f06 --- /dev/null +++ b/shim-support-mok-delete.patch @@ -0,0 +1,763 @@ +From 5abe73ab8177f0d831ff04ca67a8ed92ef09ca8b Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +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 +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 +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 + diff --git a/shim-suse-build.patch b/shim-suse-build.patch new file mode 100644 index 0000000..b29b70b --- /dev/null +++ b/shim-suse-build.patch @@ -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) diff --git a/shim.changes b/shim.changes new file mode 100644 index 0000000..51425a4 --- /dev/null +++ b/shim.changes @@ -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 + diff --git a/shim.spec b/shim.spec new file mode 100644 index 0000000..0a72e54 --- /dev/null +++ b/shim.spec @@ -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 + +%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