Control: tags 823751 + patch Control: tags 823751 + pending Control: tags 900889 + patch Control: tags 900889 + pending Control: tags 912306 + patch Control: tags 912306 + pending
Dear maintainer, I've prepared an NMU for efitools (versioned as 1.8.1-1) and uploaded it to DELAYED/7. Please feel free to tell me if I should delay it longer. Regards. diff -Nru efitools-1.4.2/cert-to-efi-hash-list.c efitools-1.8.1/cert-to-efi-hash-list.c --- efitools-1.4.2/cert-to-efi-hash-list.c 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/cert-to-efi-hash-list.c 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,213 @@ +/* + * Copyright 2012 <[email protected]> + * + * see COPYING file + */ + + +#include <stdint.h> +#define _XOPEN_SOURCE +#include <efi.h> +#ifdef CONFIG_arm +/* FIXME: + * arm efi leaves a visibilit pragma pushed that won't work for + * non efi programs, so eliminate it */ +#pragma GCC visibility pop +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> +#include <unistd.h> +#include <wchar.h> + +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/sha.h> + +#include <guid.h> +#include <variables.h> +#include <version.h> + +static void +usage(const char *progname) +{ + printf("Usage: %s [-g <guid>][-t <timestamp>][-s <hash>] <crt file> <efi sig list file>\n", progname); +} + +static void +help(const char * progname) +{ + usage(progname); + printf("Take an input X509 certificate (in PEM format) and convert it to an EFI\n" + "signature hash list file containing only that single certificate\n\n" + "Options:\n" + "\t-g <guid> Use <guid> as the owner of the signature. If this is not\n" + "\t supplied, an all zero guid will be used\n" + "\t-s <hash> Use SHA<hash> hash algorithm (256, 384, 512)\n" + "\t-t <timestamp> Time of Revocation for hash signature\n" + " Set to 0 if not specified meaning revoke\n" + " for all time.\n" + ); + +} + +int +main(int argc, char *argv[]) +{ + char *certfile, *efifile; + const char *progname = argv[0]; + EFI_GUID owner = { 0 }; + int sha = 256; + EFI_TIME timestamp; + char *timestampstr = NULL; + + memset(×tamp, 0, sizeof(timestamp)); + + while (argc > 1) { + if (strcmp("--version", argv[1]) == 0) { + version(progname); + exit(0); + } else if (strcmp("--help", argv[1]) == 0) { + help(progname); + exit(0); + } else if (strcmp("-g", argv[1]) == 0) { + str_to_guid(argv[2], &owner); + argv += 2; + argc -= 2; + } else if (strcmp("-s", argv[1]) == 0) { + sha = atoi(argv[2]); + argv += 2; + argc -= 2; + } else if (strcmp("-t", argv[1]) == 0) { + timestampstr = argv[2]; + argv += 2; + argc -= 2; + } else { + break; + } + } + + + if (argc != 3) { + usage(progname); + exit(1); + } + + if (sha != 256 && sha != 384 && sha != 512) { + fprintf(stderr, "Supported algorithms are sha256, sha384 or sha512\n"); + exit(1); + } + + if (timestampstr) { + struct tm tms; + strptime(timestampstr, "%Y-%m-%d %H:%M:%S", &tms); + /* timestamp.Year is from 0 not 1900 as tm year is */ + tms.tm_year += 1900; + timestamp.Year = tms.tm_year; + timestamp.Month = tms.tm_mon + 1; + timestamp.Day = tms.tm_mday; + timestamp.Hour = tms.tm_hour; + timestamp.Minute = tms.tm_min; + timestamp.Second = tms.tm_sec; + } + certfile = argv[1]; + efifile = argv[2]; + + printf("TimeOfRevocation is %d-%d-%d %02d:%02d:%02d\n", timestamp.Year, + timestamp.Month, timestamp.Day, timestamp.Hour, timestamp.Minute, + timestamp.Second); + + ERR_load_crypto_strings(); + OpenSSL_add_all_digests(); + OpenSSL_add_all_ciphers(); + /* here we may get highly unlikely failures or we'll get a + * complaint about FIPS signatures (usually becuase the FIPS + * module isn't present). In either case ignore the errors + * (malloc will cause other failures out lower down */ + ERR_clear_error(); + + BIO *cert_bio = BIO_new_file(certfile, "r"); + X509 *cert = PEM_read_bio_X509(cert_bio, NULL, NULL, NULL); + unsigned char *cert_buf = NULL; + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + int cert_len = i2d_X509_CINF(cert->cert_info, &cert_buf); +#else + int cert_len = i2d_re_X509_tbs(cert, &cert_buf); +#endif + ERR_print_errors_fp(stdout); + + int len, digest_len, time_offset; + EFI_GUID guid; + const EVP_MD *md; + + if (sha == 256) { + len = sizeof(EFI_CERT_X509_SHA256); + digest_len = sizeof(EFI_SHA256_HASH); + guid = EFI_CERT_X509_SHA256_GUID; + md = EVP_get_digestbyname("SHA256"); + time_offset = OFFSET_OF(EFI_CERT_X509_SHA256, TimeOfRevocation); + } else if (sha == 384) { + len = sizeof(EFI_CERT_X509_SHA384); + digest_len = sizeof(EFI_SHA384_HASH); + guid = EFI_CERT_X509_SHA384_GUID; + md = EVP_get_digestbyname("SHA384"); + time_offset = OFFSET_OF(EFI_CERT_X509_SHA384, TimeOfRevocation); + } else if (sha == 512) { + len = sizeof(EFI_CERT_X509_SHA512); + digest_len = sizeof(EFI_SHA512_HASH); + guid = EFI_CERT_X509_SHA512_GUID; + md = EVP_get_digestbyname("SHA512"); + time_offset = OFFSET_OF(EFI_CERT_X509_SHA512, TimeOfRevocation); + } else { + fprintf(stderr, "assertion failure sha%d\n", sha); + exit(1); + } + len += sizeof(EFI_SIGNATURE_LIST) + OFFSET_OF(EFI_SIGNATURE_DATA, SignatureData); + unsigned char *buf = malloc(len); + EFI_SIGNATURE_LIST *SigList = (EFI_SIGNATURE_LIST *)buf; + SigList->SignatureListSize = len; + SigList->SignatureSize = (UINT32)(len - sizeof(EFI_SIGNATURE_LIST)); + SigList->SignatureHeaderSize = 0; + SigList->SignatureType = guid; + + EFI_SIGNATURE_DATA *SigData = (void *)buf + sizeof(EFI_SIGNATURE_LIST); + SigData->SignatureOwner = owner; + + /* point buf at hash buffer */ + unsigned char *digest = (void *)SigData + OFFSET_OF(EFI_SIGNATURE_DATA, SignatureData); + + EFI_TIME *TimeOfRevocation = (void *)digest + time_offset; + *TimeOfRevocation = timestamp; + + EVP_MD_CTX *ctx; + unsigned int md_len; + ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(ctx, md, NULL); + EVP_DigestUpdate(ctx, cert_buf, cert_len); + EVP_DigestFinal_ex(ctx, digest, &md_len); + EVP_MD_CTX_destroy(ctx); + if (digest_len != md_len) { + fprintf(stderr, "Digest assertion failure sha%d %d != %d\n", + sha, digest_len, md_len); + exit(1); + } + + FILE *f = fopen(efifile, "w"); + if (!f) { + fprintf(stderr, "failed to open efi file %s: ", efifile); + perror(""); + exit(1); + } + if (fwrite(buf, 1, len, f) != len) { + perror("Did not write enough bytes to efi file"); + exit(1); + } + + return 0; +} diff -Nru efitools-1.4.2/cert-to-efi-sig-list.c efitools-1.8.1/cert-to-efi-sig-list.c --- efitools-1.4.2/cert-to-efi-sig-list.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/cert-to-efi-sig-list.c 2018-02-21 03:53:05.000000000 +0000 @@ -8,6 +8,12 @@ #include <stdint.h> #define __STDC_VERSION__ 199901L #include <efi.h> +#ifdef CONFIG_arm +/* FIXME: + * arm efi leaves a visibilit pragma pushed that won't work for + * non efi programs, so eliminate it */ +#pragma GCC visibility pop +#endif #include <stdio.h> #include <stdlib.h> @@ -75,6 +81,11 @@ ERR_load_crypto_strings(); OpenSSL_add_all_digests(); OpenSSL_add_all_ciphers(); + /* here we may get highly unlikely failures or we'll get a + * complaint about FIPS signatures (usually becuase the FIPS + * module isn't present). In either case ignore the errors + * (malloc will cause other failures out lower down */ + ERR_clear_error(); BIO *cert_bio = BIO_new_file(certfile, "r"); X509 *cert = PEM_read_bio_X509(cert_bio, NULL, NULL, NULL); diff -Nru efitools-1.4.2/debian/changelog efitools-1.8.1/debian/changelog --- efitools-1.4.2/debian/changelog 2016-04-26 09:21:41.000000000 +0100 +++ efitools-1.8.1/debian/changelog 2018-06-01 10:10:50.000000000 +0100 @@ -1,3 +1,12 @@ +efitools (1.8.1-1) unstable; urgency=medium + + * Package salvaged (Closes: #912306) + * New upstream release (Closes: #823751, #900889) + * Remove makefiles-clean patch, applied upstream + * Update makefile-enable-harden-local-files patch + + -- Arnaud Rebillout <[email protected]> Fri, 01 Jun 2018 16:10:50 +0700 + efitools (1.4.2-2) unstable; urgency=medium * Add missing build-depends (Closes: #822262) diff -Nru efitools-1.4.2/debian/control efitools-1.8.1/debian/control --- efitools-1.4.2/debian/control 2016-04-26 09:20:56.000000000 +0100 +++ efitools-1.8.1/debian/control 2018-06-01 10:10:50.000000000 +0100 @@ -1,7 +1,8 @@ Source: efitools Section: admin Priority: optional -Maintainer: Pierre Chifflier <[email protected]> +Maintainer: Debian UEFI Maintainers <[email protected]> +Uploaders: Arnaud Rebillout <[email protected]> Build-Depends: debhelper (>= 9.0.0), libfile-slurp-perl, help2man, @@ -11,8 +12,8 @@ sbsigntool Standards-Version: 3.9.8 Homepage: http://blog.hansenpartnership.com/uefi-secure-boot/ -#Vcs-Git: git://git.debian.org/collab-maint/efitools.git -#Vcs-Browser: http://git.debian.org/?p=collab-maint/efitools.git;a=summary +Vcs-Git: https://salsa.debian.org/efi-team/efitools.git +Vcs-Browser: https://salsa.debian.org/efi-team/efitools Package: efitools Architecture: any diff -Nru efitools-1.4.2/debian/patches/makefile-enable-harden-local-files.patch efitools-1.8.1/debian/patches/makefile-enable-harden-local-files.patch --- efitools-1.4.2/debian/patches/makefile-enable-harden-local-files.patch 2016-04-19 08:43:50.000000000 +0100 +++ efitools-1.8.1/debian/patches/makefile-enable-harden-local-files.patch 2018-06-01 10:10:50.000000000 +0100 @@ -1,10 +1,8 @@ -Index: efitools/Makefile -=================================================================== ---- efitools.orig/Makefile -+++ efitools/Makefile -@@ -3,6 +3,9 @@ EFIFILES = HelloWorld.efi LockDown.efi L - BINARIES = cert-to-efi-sig-list sig-list-to-certs sign-efi-sig-list \ - hash-to-efi-sig-list efi-readvar efi-updatevar +--- a/Makefile ++++ b/Makefile +@@ -21,6 +21,9 @@ + KEYBLACKLISTAUTH = $(ALLKEYS:=-blacklist.auth) + KEYHASHBLACKLISTAUTH = $(ALLKEYS:=-hash-blacklist.auth) +OLD_CFLAGS:=$(CFLAGS) +OLD_LDFLAGS:=$(LDFLAGS) @@ -12,36 +10,44 @@ export TOPDIR := $(shell pwd)/ include Make.rules -@@ -76,25 +79,25 @@ PreLoader.so: lib/lib-efi.a - HelloWorld.so: lib/lib-efi.a +@@ -88,31 +91,31 @@ + ShimReplace.so: lib/lib-efi.a cert-to-efi-sig-list: cert-to-efi-sig-list.o lib/lib.a -- $(CC) -o $@ $< -lcrypto lib/lib.a -+ $(CC) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) -lcrypto lib/lib.a +- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a ++ $(CC) $(ARCH3264) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) -lcrypto lib/lib.a sig-list-to-certs: sig-list-to-certs.o lib/lib.a -- $(CC) -o $@ $< -lcrypto lib/lib.a -+ $(CC) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) -lcrypto lib/lib.a +- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a ++ $(CC) $(ARCH3264) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) -lcrypto lib/lib.a sign-efi-sig-list: sign-efi-sig-list.o lib/lib.a -- $(CC) -o $@ $< -lcrypto lib/lib.a -+ $(CC) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) -lcrypto lib/lib.a +- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a ++ $(CC) $(ARCH3264) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) -lcrypto lib/lib.a hash-to-efi-sig-list: hash-to-efi-sig-list.o lib/lib.a -- $(CC) -o $@ $< lib/lib.a -+ $(CC) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) lib/lib.a +- $(CC) $(ARCH3264) -o $@ $< lib/lib.a ++ $(CC) $(ARCH3264) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) lib/lib.a + + cert-to-efi-hash-list: cert-to-efi-hash-list.o lib/lib.a +- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a ++ $(CC) $(ARCH3264) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) -lcrypto lib/lib.a efi-keytool: efi-keytool.o lib/lib.a -- $(CC) -o $@ $< lib/lib.a -+ $(CC) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) lib/lib.a +- $(CC) $(ARCH3264) -o $@ $< lib/lib.a ++ $(CC) $(ARCH3264) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) lib/lib.a efi-readvar: efi-readvar.o lib/lib.a -- $(CC) -o $@ $< -lcrypto lib/lib.a -+ $(CC) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) -lcrypto lib/lib.a +- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a ++ $(CC) $(ARCH3264) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) -lcrypto lib/lib.a efi-updatevar: efi-updatevar.o lib/lib.a -- $(CC) -o $@ $< -lcrypto lib/lib.a -+ $(CC) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) -lcrypto lib/lib.a +- $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a ++ $(CC) $(ARCH3264) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) -lcrypto lib/lib.a + + flash-var: flash-var.o lib/lib.a +- $(CC) $(ARCH3264) -o $@ $< lib/lib.a ++ $(CC) $(ARCH3264) -o $@ $< $(OLD_CFLAGS) $(OLD_LDFLAGS) lib/lib.a clean: rm -f PK.* KEK.* DB.* $(EFIFILES) $(EFISIGNED) $(BINARIES) *.o *.so diff -Nru efitools-1.4.2/debian/patches/makefiles-fix-clean.patch efitools-1.8.1/debian/patches/makefiles-fix-clean.patch --- efitools-1.4.2/debian/patches/makefiles-fix-clean.patch 2016-04-19 07:29:58.000000000 +0100 +++ efitools-1.8.1/debian/patches/makefiles-fix-clean.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,41 +0,0 @@ -Index: efitools/lib/Makefile -=================================================================== ---- efitools.orig/lib/Makefile -+++ efitools/lib/Makefile -@@ -9,6 +9,9 @@ lib.a: $(LIBFILES) - lib-efi.a: $(EFILIBFILES) - - clean: -+ $(MAKE) -C asn1 clean - rm -f lib.a - rm -f $(LIBFILES) -+ rm -f lib-efi.a -+ rm -f $(EFILIBFILES) - -Index: efitools/lib/asn1/Makefile -=================================================================== ---- efitools.orig/lib/asn1/Makefile -+++ efitools/lib/asn1/Makefile -@@ -12,3 +12,9 @@ test.o: test.c ../../include/x509.h - - test: test.o libasn1.a - $(CC) -o $@ $< libasn1.a -+ -+clean: -+ rm -f libasn1.a -+ rm -f $(LIBFILES) -+ rm -f libasn1-efi.a -+ rm -f $(EFILIBFILES) -Index: efitools/Makefile -=================================================================== ---- efitools.orig/Makefile -+++ efitools/Makefile -@@ -100,6 +100,8 @@ clean: - rm -f PK.* KEK.* DB.* $(EFIFILES) $(EFISIGNED) $(BINARIES) *.o *.so - rm -f doc/*.1 - $(MAKE) -C lib clean -+ rm -f *.auth *.esl -+ rm -f HashTool.hash hashlist.h - - FORCE: - diff -Nru efitools-1.4.2/debian/patches/series efitools-1.8.1/debian/patches/series --- efitools-1.4.2/debian/patches/series 2016-04-19 08:40:48.000000000 +0100 +++ efitools-1.8.1/debian/patches/series 2018-06-01 10:10:50.000000000 +0100 @@ -1,2 +1 @@ -makefiles-fix-clean.patch makefile-enable-harden-local-files.patch diff -Nru efitools-1.4.2/doc/cert-to-efi-hash-list.1.in efitools-1.8.1/doc/cert-to-efi-hash-list.1.in --- efitools-1.4.2/doc/cert-to-efi-hash-list.1.in 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/doc/cert-to-efi-hash-list.1.in 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,30 @@ +[name] +cert-to-efi-hash-list - tool for converting openssl certificates to EFI signature hash revocation lists + +[examples] + +To take a standard X509 certificate in PEM format and +produce an output EFI signature list file, simply do + +cert-to-efi-hash-list PK.crt PK.esl + +Note that the format of EFI signature list files is such +that they can simply be concatenated to produce a file with +multiple signatures: + +cat PK1.esl PK2.esl > PK.esl + +If your platform has a setup mode key manipulation ability, +the keys will often only be displayed by GUID, so using the +-g option to give your keys recognisable GUIDs will be +useful if you plan to manage lots of keys. + +[see also] + +sign-efi-sig-list(1) for details on how to create an +authenticated update to EFI secure variables when the EFI +system is in user mode. + +[note] + +Signature revocation hashes are only implemented in UEFI 2.4 and up diff -Nru efitools-1.4.2/efi-updatevar.c efitools-1.8.1/efi-updatevar.c --- efitools-1.4.2/efi-updatevar.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/efi-updatevar.c 2018-02-21 03:53:05.000000000 +0000 @@ -328,7 +328,7 @@ /* FIXME: currently timestamp is one year into future because of * the way we set up the secure environment */ timestamp.Year = tm->tm_year + 1900 + 1; - timestamp.Month = tm->tm_mon; + timestamp.Month = tm->tm_mon + 1; timestamp.Day = tm->tm_mday; timestamp.Hour = tm->tm_hour; timestamp.Minute = tm->tm_min; diff -Nru efitools-1.4.2/elf_x86_64_efi.lds efitools-1.8.1/elf_x86_64_efi.lds --- efitools-1.4.2/elf_x86_64_efi.lds 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/elf_x86_64_efi.lds 1970-01-01 01:00:00.000000000 +0100 @@ -1,59 +0,0 @@ -OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") -OUTPUT_ARCH(i386:x86-64) -ENTRY(_start) -SECTIONS -{ - . = 0; - ImageBase = .; - .hash : { *(.hash) } /* this MUST come first! */ - . = ALIGN(4096); - .eh_frame : - { - *(.eh_frame) - } - . = ALIGN(4096); - .text : - { - *(.text) - } - . = ALIGN(4096); - .reloc : - { - *(.reloc) - } - . = ALIGN(4096); - .data : - { - *(.rodata*) - *(.got.plt) - *(.got) - *(.data*) - *(.sdata) - /* the EFI loader doesn't seem to like a .bss section, so we stick - it all into .data: */ - *(.sbss) - *(.scommon) - *(.dynbss) - *(.bss) - *(COMMON) - *(.rel.local) - } - . = ALIGN(4096); - .dynamic : { *(.dynamic) } - . = ALIGN(4096); - .rela : - { - *(.rela.data*) - *(.rela.got) - *(.rela.stab) - } - . = ALIGN(4096); - .dynsym : { *(.dynsym) } - . = ALIGN(4096); - .dynstr : { *(.dynstr) } - . = ALIGN(4096); - .ignored.reloc : - { - *(.rela.reloc) - } -} diff -Nru efitools-1.4.2/flash-var.c efitools-1.8.1/flash-var.c --- efitools-1.4.2/flash-var.c 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/flash-var.c 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,209 @@ +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <time.h> +#include <fcntl.h> +#include <unistd.h> + +#define __STDC_VERSION__ 199901L +#include <efi.h> + +#include <version.h> +#include <guid.h> +#include "efiauthenticated.h" +#include "variableformat.h" + +static void +usage(const char *progname) +{ + printf("Usage: %s: [-l] [-g <owner guid>] [-t <timestamp>] <flashfile> <var> <varcontentfile>\n", progname); +} + +static void +help(const char *progname) +{ + usage(progname); + printf("Poke a variable definition into a flash file\n\n" + "Options:\n" + "\t-g <owner guid> Variable owner GUID\n" + "\t-t <timestamp> Timestamp for the authenticated variable\n" + "\t-l List current flash variables\n" + ); +} + +int +main(int argc, char *argv[]) +{ + char *progname = argv[0], *buf, *vardata, *timestampstr = NULL; + uint32_t attributes = EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + int flashfile, varfile, i, offset, varlen, varfilesize, listvars = 0; + const int chunk = 8; + wchar_t var[128]; + struct stat st; + EFI_GUID *owner = NULL, guid; + EFI_TIME timestamp; + + while (argc > 1 && argv[1][0] == '-') { + if (strcmp("--version", argv[1]) == 0) { + version(progname); + exit(0); + } else if (strcmp("--help", argv[1]) == 0) { + help(progname); + exit(0); + } else if (strcmp(argv[1], "-g") == 0) { + if (str_to_guid(argv[2], &guid)) { + fprintf(stderr, "Invalid GUID %s\n", argv[2]); + exit(1); + } + owner = &guid; + argv += 2; + argc -= 2; + } else if (strcmp("-t", argv[1]) == 0) { + timestampstr = argv[2]; + argv += 2; + argc -= 2; + } else if (strcmp("-l", argv[1]) == 0) { + listvars = 1; + argv += 1; + argc -= 1; + } else { + /* unrecognised option */ + break; + } + } + + if ((argc != 4 && !listvars) || (argc != 2 && listvars)) { + usage(progname); + exit(1); + } + + /* copy to wchar16_t including trailing zero */ + for (i = 0; i < strlen(argv[2]) + 1; i++) + var[i] = argv[2][i]; + varlen = i*2; /* size of storage including zero */ + + if (!owner) + owner = get_owner_guid(argv[2]); + if (!owner) { + fprintf(stderr, "variable %s has no defined guid, one must be specified\n", argv[2]); + exit(1); + } + + + memset(×tamp, 0, sizeof(timestamp)); + time_t t; + struct tm *tm, tms; + + memset(&tms, 0, sizeof(tms)); + + + if (timestampstr) { + strptime(timestampstr, "%Y-%m-%d %H:%M:%S", &tms); + tm = &tms; + } else { + time(&t); + tm = localtime(&t); + } + + /* timestamp.Year is from 0 not 1900 as tm year is */ + timestamp.Year = tm->tm_year + 1900; + /* timestamp Month is 1-12 not 0-11 as tm_mon is */ + timestamp.Month = tm->tm_mon + 1; + timestamp.Day = tm->tm_mday; + timestamp.Hour = tm->tm_hour; + timestamp.Minute = tm->tm_min; + timestamp.Second = tm->tm_sec; + + printf("Timestamp is %d-%d-%d %02d:%02d:%02d\n", timestamp.Year, + timestamp.Month, timestamp.Day, timestamp.Hour, timestamp.Minute, + timestamp.Second); + + flashfile = open(argv[1], O_RDWR); + if (flashfile < 0) { + fprintf(stderr, "Failed to read file %s:", argv[1]); + perror(""); + } + + varfile = open(argv[3], O_RDONLY); + if (varfile < 0) { + fprintf(stderr, "Failed to read file %s:", argv[1]); + perror(""); + } + fstat(varfile, &st); + varfilesize = st.st_size; + + vardata = malloc(varfilesize); + if (read(varfile, vardata, varfilesize) != varfilesize) { + perror("Failed to read variable file"); + exit(1); + } + close(varfile); + + buf = malloc(sizeof(EFI_GUID)); + + for (i = 0; ; i += chunk) { + lseek(flashfile, i, SEEK_SET); + if (read(flashfile, buf, sizeof(EFI_GUID)) != sizeof(EFI_GUID)) + goto eof; + if (memcmp(buf, &SECURE_VARIABLE_GUID, sizeof(EFI_GUID)) == 0) + break; + } + offset = i; + printf("Variable header found at offset 0x%x\n", offset); + lseek(flashfile, offset, SEEK_SET); + free(buf); + buf = malloc(sizeof(VARIABLE_STORE_HEADER)); + read(flashfile, buf, sizeof(VARIABLE_STORE_HEADER)); + + VARIABLE_STORE_HEADER *vsh = (VARIABLE_STORE_HEADER *)buf; + if (vsh->Format != VARIABLE_STORE_FORMATTED && + vsh->State != VARIABLE_STORE_HEALTHY) { + fprintf(stderr, "Variable store header is corrupt\n"); + exit(1); + } + UINT32 size = vsh->Size; + free(buf); + buf = malloc(size); + lseek(flashfile, offset, SEEK_SET); + read(flashfile, buf, size); + vsh = (VARIABLE_STORE_HEADER *)buf; + printf("Variable Store Size = 0x%x\n", vsh->Size); + + VARIABLE_HEADER *vh = (void *)HEADER_ALIGN(vsh + 1); + printf("variables begin at 0x%x\n", (int)((char *)vh - (char *)vsh)); + for (i = 0; IsValidVariableHeader(vh); i++) { + vh = (void *)HEADER_ALIGN((char *)(vh + 1) + vh->NameSize + vh->DataSize); + } + printf("Found %d variables, now at offset %ld\n", i, (long)((char *)vh - (char *)vsh)); + memset(vh, 0, sizeof(*vh)); + vh->StartId = VARIABLE_DATA; + vh->State = VAR_ADDED; + vh->Attributes = attributes; + vh->NameSize = varlen; + vh->DataSize = varfilesize; + vh->TimeStamp = timestamp; + vh->VendorGuid = *owner; + + buf = (void *)(vh + 1); + memcpy (buf, var, varlen); + buf += varlen; + memcpy (buf, vardata, varfilesize); + lseek(flashfile, offset, SEEK_SET); + write(flashfile, vsh, vsh->Size); + close(flashfile); + + exit(0); + + eof: + printf("No variables found in file at offset 0x%x\n", i); + exit(2); +} + diff -Nru efitools-1.4.2/.gitignore efitools-1.8.1/.gitignore --- efitools-1.4.2/.gitignore 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/.gitignore 2018-02-21 03:53:05.000000000 +0000 @@ -23,8 +23,10 @@ *.cab hash-to-efi-sig-list cert-to-efi-sig-list +cert-to-efi-hash-list sig-list-to-certs sign-efi-sig-list efi-keytool efi-readvar efi-updatevar +flash-var diff -Nru efitools-1.4.2/hash-to-efi-sig-list.c efitools-1.8.1/hash-to-efi-sig-list.c --- efitools-1.4.2/hash-to-efi-sig-list.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/hash-to-efi-sig-list.c 2018-02-21 03:53:05.000000000 +0000 @@ -6,6 +6,12 @@ #include <stdint.h> #define __STDC_VERSION__ 199901L #include <efi.h> +#ifdef CONFIG_arm +/* FIXME: + * arm efi leaves a visibilit pragma pushed that won't work for + * non efi programs, so eliminate it */ +#pragma GCC visibility pop +#endif #include <stdio.h> #include <stdlib.h> @@ -17,6 +23,7 @@ #include <unistd.h> #include <wchar.h> +#include <PeImage.h> /* for ALIGN_VALUE */ #include <sha256.h> #include <efiauthenticated.h> #include <guid.h> @@ -80,7 +87,8 @@ exit(1); } fstat(fdefifile, &st); - efifile = malloc(st.st_size); + efifile = malloc(ALIGN_VALUE(st.st_size, 4096)); + memset(efifile, 0, ALIGN_VALUE(st.st_size, 4096)); read(fdefifile, efifile, st.st_size); close(fdefifile); status = sha256_get_pecoff_digest_mem(efifile, st.st_size, diff -Nru efitools-1.4.2/HashTool.c efitools-1.8.1/HashTool.c --- efitools-1.4.2/HashTool.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/HashTool.c 2018-02-21 03:53:05.000000000 +0000 @@ -252,9 +252,7 @@ NULL }); if (selection == 1) - uefi_call_wrapper(RT->ResetSystem, 4, - EfiResetWarm, - EFI_SUCCESS, 0, NULL); + RT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL); } else if (option == exit_moktool) { break; } diff -Nru efitools-1.4.2/include/buildefi.h efitools-1.8.1/include/buildefi.h --- efitools-1.4.2/include/buildefi.h 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/include/buildefi.h 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,15 @@ +#ifndef _BUILDEFI_H +#define _BUILDEFI_H + +#ifndef BUILD_EFI +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#define Print(...) printf("%ls", __VA_ARGS__) +#define AllocatePool(x) malloc(x) +#define CopyMem(d, s, l) memcpy(d, s, l) +#define ZeroMem(s, l) memset(s, 0, l) +#define FreePool(s) free(s) +#endif + +#endif /* _BUILDEFI_H */ diff -Nru efitools-1.4.2/include/efiauthenticated.h efitools-1.8.1/include/efiauthenticated.h --- efitools-1.4.2/include/efiauthenticated.h 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/include/efiauthenticated.h 2018-02-21 03:53:05.000000000 +0000 @@ -7,6 +7,11 @@ /// /// The format of a signature database. /// + +typedef UINT8 EFI_SHA256_HASH[32]; +typedef UINT8 EFI_SHA384_HASH[48]; +typedef UINT8 EFI_SHA512_HASH[64]; + #pragma pack(1) typedef struct { @@ -47,6 +52,39 @@ /// } EFI_SIGNATURE_LIST; +typedef struct { + /// + /// The SHA256 hash of an X.509 certificate's To-Be-Signed contents. + /// + EFI_SHA256_HASH ToBeSignedHash; + /// + /// The time that the certificate shall be considered to be revoked. + /// + EFI_TIME TimeOfRevocation; +} EFI_CERT_X509_SHA256; + +typedef struct { + /// + /// The SHA384 hash of an X.509 certificate's To-Be-Signed contents. + /// + EFI_SHA384_HASH ToBeSignedHash; + /// + /// The time that the certificate shall be considered to be revoked. + /// + EFI_TIME TimeOfRevocation; +} EFI_CERT_X509_SHA384; + +typedef struct { + /// + /// The SHA512 hash of an X.509 certificate's To-Be-Signed contents. + /// + EFI_SHA512_HASH ToBeSignedHash; + /// + /// The time that the certificate shall be considered to be revoked. + /// + EFI_TIME TimeOfRevocation; +} EFI_CERT_X509_SHA512; + #pragma pack() // @@ -72,6 +110,18 @@ 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} \ } +#define EFI_CERT_X509_SHA256_GUID \ + (EFI_GUID) { 0x3bd2a492, 0x96c0, 0x4079, \ + { 0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed } } + +#define EFI_CERT_X509_SHA384_GUID \ + (EFI_GUID) { 0x7076876e, 0x80c2, 0x4ee6, \ + { 0xaa, 0xd2, 0x28, 0xb3, 0x49, 0xa6, 0x86, 0x5b } } + +#define EFI_CERT_X509_SHA512_GUID \ + (EFI_GUID) { 0x446dbf63, 0x2502, 0x4cda, \ + { 0xbc, 0xfa, 0x24, 0x65, 0xd2, 0xb0, 0xfe, 0x9d } } + /// /// WIN_CERTIFICATE_UEFI_GUID.CertType /// diff -Nru efitools-1.4.2/include/guid.h efitools-1.8.1/include/guid.h --- efitools-1.4.2/include/guid.h 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/include/guid.h 2018-02-21 03:53:05.000000000 +0000 @@ -1,9 +1,16 @@ #include <efi.h> #ifndef BUILD_EFI +#ifdef CONFIG_arm +/* FIXME: + * arm efi leaves a visibilit pragma pushed that won't work for + * non efi programs, so eliminate it */ +#pragma GCC visibility pop +#endif const char *guid_to_str(EFI_GUID *guid); int str_to_guid(const char *str, EFI_GUID *guid); int compare_guid(EFI_GUID *g1, EFI_GUID *g2); +EFI_GUID *get_owner_guid(char *var); #endif extern EFI_GUID GV_GUID; @@ -17,3 +24,12 @@ extern EFI_GUID MOK_OWNER; extern EFI_GUID SECURITY_PROTOCOL_GUID; extern EFI_GUID SECURITY2_PROTOCOL_GUID; +extern EFI_GUID SECURE_VARIABLE_GUID; +extern EFI_GUID PKCS7_VERIFY_PROTOCOL_GUID; +extern EFI_GUID EFI_CERT_SHA1_GUID; +extern EFI_GUID EFI_CERT_SHA224_GUID; +extern EFI_GUID EFI_CERT_SHA384_GUID; +extern EFI_GUID EFI_CERT_SHA512_GUID; +extern EFI_GUID *allowed_hashes[]; +extern UINTN allowed_hashes_size; + diff -Nru efitools-1.4.2/include/pecoff.h efitools-1.8.1/include/pecoff.h --- efitools-1.4.2/include/pecoff.h 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/include/pecoff.h 2018-02-21 03:53:05.000000000 +0000 @@ -13,6 +13,11 @@ pecoff_execute_image(EFI_FILE *file, CHAR16 *name, EFI_HANDLE image, EFI_SYSTEM_TABLE *systab); +EFI_STATUS +pecoff_get_signature(PE_COFF_LOADER_IMAGE_CONTEXT *context, void *buffer, + WIN_CERTIFICATE **data, int signum); + + static inline void* pecoff_image_address(void *image, int size, unsigned int address) { diff -Nru efitools-1.4.2/include/PeImage.h efitools-1.8.1/include/PeImage.h --- efitools-1.4.2/include/PeImage.h 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/include/PeImage.h 2018-02-21 03:53:05.000000000 +0000 @@ -777,6 +777,7 @@ UINTN SizeOfHeaders; UINT16 ImageType; UINT16 NumberOfSections; + UINT32 FileAlignment; EFI_IMAGE_SECTION_HEADER *FirstSection; EFI_IMAGE_DATA_DIRECTORY *RelocDir; EFI_IMAGE_DATA_DIRECTORY *SecDir; diff -Nru efitools-1.4.2/include/pkcs7verify.h efitools-1.8.1/include/pkcs7verify.h --- efitools-1.4.2/include/pkcs7verify.h 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/include/pkcs7verify.h 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,220 @@ +/** @file + EFI_PKCS7_VERIFY_PROTOCOL as defined in UEFI 2.5. + The EFI_PKCS7_VERIFY_PROTOCOL is used to verify data signed using PKCS#7 + formatted authentication. The PKCS#7 data to be verified must be binary + DER encoded. + PKCS#7 is a general-purpose cryptographic standard (defined by RFC2315, + available at http://tools.ietf.org/html/rfc2315). + +Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_PKCS7_VERIFY_PROTOCOL_H__ +#define __EFI_PKCS7_VERIFY_PROTOCOL_H__ + +typedef struct _EFI_PKCS7_VERIFY_PROTOCOL EFI_PKCS7_VERIFY_PROTOCOL; + + +/** + Processes a buffer containing binary DER-encoded PKCS7 signature. + The signed data content may be embedded within the buffer or separated. Funtion + verifies the signature of the content is valid and signing certificate was not + revoked and is contained within a list of trusted signers. + + @param[in] This Pointer to EFI_PKCS7_VERIFY_PROTOCOL instance. + @param[in] SignedData Points to buffer containing ASN.1 DER-encoded PKCS7 + signature. + @param[in] SignedDataSize The size of SignedData buffer in bytes. + @param[in] InData In case of detached signature, InData points to + buffer containing the raw message data previously + signed and to be verified by function. In case of + SignedData containing embedded data, InData must be + NULL. + @param[in] InDataSize When InData is used, the size of InData buffer in + bytes. When InData is NULL. This parameter must be + 0. + @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST + structures. The list is terminated by a null + pointer. The EFI_SIGNATURE_LIST structures contain + lists of X.509 certificates of approved signers. + Function recognizes signer certificates of type + EFI_CERT_X509_GUID. Any hash certificate in AllowedDb + list is ignored by this function. Function returns + success if signer of the buffer is within this list + (and not within RevokedDb). This parameter is + required. + @param[in] RevokedDb Optional pointer to a list of pointers to + EFI_SIGNATURE_LIST structures. The list is terminated + by a null pointer. List of X.509 certificates of + revoked signers and revoked file hashes. Except as + noted in description of TimeStampDb signature + verification will always fail if the signer of the + file or the hash of the data component of the buffer + is in RevokedDb list. This list is optional and + caller may pass Null or pointer to NULL if not + required. + @param[in] TimeStampDb Optional pointer to a list of pointers to + EFI_SIGNATURE_LIST structures. The list is terminated + by a null pointer. This parameter can be used to pass + a list of X.509 certificates of trusted time stamp + signers. This list is optional and caller must pass + Null or pointer to NULL if not required. + @param[out] Content On input, points to an optional caller-allocated + buffer into which the function will copy the content + portion of the file after verification succeeds. + This parameter is optional and if NULL, no copy of + content from file is performed. + @param[in,out] ContentSize On input, points to the size in bytes of the optional + buffer Content previously allocated by caller. On + output, if the verification succeeds, the value + referenced by ContentSize will contain the actual + size of the content from signed file. If ContentSize + indicates the caller-allocated buffer is too small + to contain content, an error is returned, and + ContentSize will be updated with the required size. + This parameter must be 0 if Content is Null. + + @retval EFI_SUCCESS Content signature was verified against hash of + content, the signer's certificate was not found in + RevokedDb, and was found in AllowedDb or if in signer + is found in both AllowedDb and RevokedDb, the + signing was allowed by reference to TimeStampDb as + described above, and no hash matching content hash + was found in RevokedDb. + @retval EFI_SECURITY_VIOLATION The SignedData buffer was correctly formatted but + signer was in RevokedDb or not in AllowedDb. Also + returned if matching content hash found in RevokedDb. + @retval EFI_COMPROMISED_DATA Calculated hash differs from signed hash. + @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero. + AllowedDb is NULL. + @retval EFI_INVALID_PARAMETER Content is not NULL and ContentSize is NULL. + @retval EFI_ABORTED Unsupported or invalid format in TimeStampDb, + RevokedDb or AllowedDb list contents was detected. + @retval EFI_NOT_FOUND Content not found because InData is NULL and no + content embedded in SignedData. + @retval EFI_UNSUPPORTED The SignedData buffer was not correctly formatted + for processing by the function. + @retval EFI_UNSUPPORTED Signed data embedded in SignedData but InData is not + NULL. + @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too + small to hold the content. ContentSize updated to + required size. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PKCS7_VERIFY_BUFFER) ( + IN EFI_PKCS7_VERIFY_PROTOCOL *This, + IN VOID *SignedData, + IN UINTN SignedDataSize, + IN VOID *InData OPTIONAL, + IN UINTN InDataSize, + IN EFI_SIGNATURE_LIST **AllowedDb, + IN EFI_SIGNATURE_LIST **RevokedDb OPTIONAL, + IN EFI_SIGNATURE_LIST **TimeStampDb OPTIONAL, + OUT VOID *Content OPTIONAL, + IN OUT UINTN *ContentSize + ); + +/** + Processes a buffer containing binary DER-encoded detached PKCS7 signature. + The hash of the signed data content is calculated and passed by the caller. Function + verifies the signature of the content is valid and signing certificate was not revoked + and is contained within a list of trusted signers. + + @param[in] This Pointer to EFI_PKCS7_VERIFY_PROTOCOL instance. + @param[in] Signature Points to buffer containing ASN.1 DER-encoded PKCS + detached signature. + @param[in] SignatureSize The size of Signature buffer in bytes. + @param[in] InHash InHash points to buffer containing the caller + calculated hash of the data. The parameter may not + be NULL. + @param[in] InHashSize The size in bytes of InHash buffer. + @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST + structures. The list is terminated by a null + pointer. The EFI_SIGNATURE_LIST structures contain + lists of X.509 certificates of approved signers. + Function recognizes signer certificates of type + EFI_CERT_X509_GUID. Any hash certificate in AllowedDb + list is ignored by this function. Function returns + success if signer of the buffer is within this list + (and not within RevokedDb). This parameter is + required. + @param[in] RevokedDb Optional pointer to a list of pointers to + EFI_SIGNATURE_LIST structures. The list is terminated + by a null pointer. List of X.509 certificates of + revoked signers and revoked file hashes. Signature + verification will always fail if the signer of the + file or the hash of the data component of the buffer + is in RevokedDb list. This parameter is optional + and caller may pass Null if not required. + @param[in] TimeStampDb Optional pointer to a list of pointers to + EFI_SIGNATURE_LIST structures. The list is terminated + by a null pointer. This parameter can be used to pass + a list of X.509 certificates of trusted time stamp + counter-signers. + + @retval EFI_SUCCESS Signed hash was verified against caller-provided + hash of content, the signer's certificate was not + found in RevokedDb, and was found in AllowedDb or + if in signer is found in both AllowedDb and + RevokedDb, the signing was allowed by reference to + TimeStampDb as described above, and no hash matching + content hash was found in RevokedDb. + @retval EFI_SECURITY_VIOLATION The SignedData buffer was correctly formatted but + signer was in RevokedDb or not in AllowedDb. Also + returned if matching content hash found in RevokedDb. + @retval EFI_COMPROMISED_DATA Caller provided hash differs from signed hash. Or, + caller and encrypted hash are different sizes. + @retval EFI_INVALID_PARAMETER Signature is NULL or SignatureSize is zero. InHash + is NULL or InHashSize is zero. AllowedDb is NULL. + @retval EFI_ABORTED Unsupported or invalid format in TimeStampDb, + RevokedDb or AllowedDb list contents was detected. + @retval EFI_UNSUPPORTED The Signature buffer was not correctly formatted + for processing by the function. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PKCS7_VERIFY_SIGNATURE) ( + IN EFI_PKCS7_VERIFY_PROTOCOL *This, + IN VOID *Signature, + IN UINTN SignatureSize, + IN VOID *InHash, + IN UINTN InHashSize, + IN EFI_SIGNATURE_LIST **AllowedDb, + IN EFI_SIGNATURE_LIST **RevokedDb OPTIONAL, + IN EFI_SIGNATURE_LIST **TimeStampDb OPTIONAL + ); + +/// +/// The EFI_PKCS7_VERIFY_PROTOCOL is used to verify data signed using PKCS7 +/// structure. The PKCS7 data to be verified must be ASN.1 (DER) encoded. +/// SHA256 must be supported as digest algorithm with RSA digest encryption. +/// Support of other hash algorithms is optional. +/// +struct _EFI_PKCS7_VERIFY_PROTOCOL { + EFI_PKCS7_VERIFY_BUFFER VerifyBuffer; + EFI_PKCS7_VERIFY_SIGNATURE VerifySignature; +}; + +EFI_STATUS +pkcs7verify_get_protocol(EFI_HANDLE image, EFI_PKCS7_VERIFY_PROTOCOL **p7vp, CHAR16 **error); +BOOLEAN +pkcs7verify_deny(VOID *data, UINTN len); +EFI_SIGNATURE_LIST ** +pkcs7verify_to_cert_list(VOID *data, UINTN len); +BOOLEAN +pkcs7verify_allow(VOID *data, UINTN len); + + + +#endif diff -Nru efitools-1.4.2/include/security_policy.h efitools-1.8.1/include/security_policy.h --- efitools-1.4.2/include/security_policy.h 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/include/security_policy.h 2018-02-21 03:53:05.000000000 +0000 @@ -1,6 +1,13 @@ +typedef BOOLEAN (*POLICY_FUNCTION)(VOID *data, UINTN len); + EFI_STATUS -security_policy_install(void); +security_policy_install(BOOLEAN (*override)(void), POLICY_FUNCTION allow, POLICY_FUNCTION deny); EFI_STATUS security_policy_uninstall(void); void security_protocol_set_hashes(unsigned char *esl, int len); + +/* three policies for MoK based on hashes only */ +BOOLEAN security_policy_mok_override(void); +BOOLEAN security_policy_mok_deny(VOID *data, UINTN len); +BOOLEAN security_policy_mok_allow(VOID *data, UINTN len); diff -Nru efitools-1.4.2/include/shim_protocol.h efitools-1.8.1/include/shim_protocol.h --- efitools-1.4.2/include/shim_protocol.h 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/include/shim_protocol.h 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,42 @@ +#ifndef _SHIM_PROTOCOL_H +#define _SHIM_PROTOCOL_H + +#include <PeImage.h> +#include <pkcs7verify.h> + +typedef +EFI_STATUS +(*EFI_SHIM_LOCK_VERIFY) ( + IN VOID *buffer, + IN UINT32 size + ); + +typedef +EFI_STATUS +(*EFI_SHIM_LOCK_HASH) ( + IN char *data, + IN int datasize, + PE_COFF_LOADER_IMAGE_CONTEXT *context, + UINT8 *sha256hash, + UINT8 *sha1hash + ); + +typedef +EFI_STATUS +(*EFI_SHIM_LOCK_CONTEXT) ( + IN VOID *data, + IN unsigned int datasize, + PE_COFF_LOADER_IMAGE_CONTEXT *context + ); + +typedef struct _SHIM_LOCK { + EFI_SHIM_LOCK_VERIFY Verify; + EFI_SHIM_LOCK_HASH Hash; + EFI_SHIM_LOCK_CONTEXT Context; +} SHIM_LOCK; + + +EFI_STATUS shim_protocol_install(void); +void shim_protocol_uninstall(void); + +#endif /* _SHIM_PROTOCOL_H */ diff -Nru efitools-1.4.2/include/variableformat.h efitools-1.8.1/include/variableformat.h --- efitools-1.4.2/include/variableformat.h 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/include/variableformat.h 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,120 @@ +#ifndef _INC_VARIABLEFORMAT_H +#define _INC_VARIABLEFORMAT_H +/// +/// Alignment of Variable Data Header in Variable Store region. +/// +#define HEADER_ALIGNMENT 4 +#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1))) + +/// +/// Status of Variable Store Region. +/// +typedef enum { + EfiRaw, + EfiValid, + EfiInvalid, + EfiUnknown +} VARIABLE_STORE_STATUS; + +#pragma pack(1) + +#define VARIABLE_STORE_SIGNATURE EFI_AUTHENTICATED_VARIABLE_GUID + +/// +/// Variable Store Header Format and State. +/// +#define VARIABLE_STORE_FORMATTED 0x5a +#define VARIABLE_STORE_HEALTHY 0xfe + +/// +/// Variable Store region header. +/// +typedef struct { + /// + /// Variable store region signature. + /// + EFI_GUID Signature; + /// + /// Size of entire variable store, + /// including size of variable store header but not including the size of FvHeader. + /// + UINT32 Size; + /// + /// Variable region format state. + /// + UINT8 Format; + /// + /// Variable region healthy state. + /// + UINT8 State; + UINT16 Reserved; + UINT32 Reserved1; +} VARIABLE_STORE_HEADER; + +/// +/// Variable data start flag. +/// +#define VARIABLE_DATA 0x55AA + +/// +/// Variable State flags. +/// +#define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition. +#define VAR_DELETED 0xfd ///< Variable is obsolete. +#define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid. +#define VAR_ADDED 0x3f ///< Variable has been completely added. + +/// +/// Single Variable Data Header Structure. +/// +typedef struct { + /// + /// Variable Data Start Flag. + /// + UINT16 StartId; + /// + /// Variable State defined above. + /// + UINT8 State; + UINT8 Reserved; + /// + /// Attributes of variable defined in UEFI specification. + /// + UINT32 Attributes; + /// + /// Associated monotonic count value against replay attack. + /// + UINT64 MonotonicCount; + /// + /// Associated TimeStamp value against replay attack. + /// + EFI_TIME TimeStamp; + /// + /// Index of associated public key in database. + /// + UINT32 PubKeyIndex; + /// + /// Size of variable null-terminated Unicode string name. + /// + UINT32 NameSize; + /// + /// Size of the variable data without this header. + /// + UINT32 DataSize; + /// + /// A unique identifier for the vendor that produces and consumes this varaible. + /// + EFI_GUID VendorGuid; +} VARIABLE_HEADER; + +#pragma pack() + +inline BOOLEAN +IsValidVariableHeader (VARIABLE_HEADER *vh) { + if (vh == NULL || vh->StartId != VARIABLE_DATA) + return FALSE; + return TRUE; +} + + +#endif diff -Nru efitools-1.4.2/include/variables.h efitools-1.8.1/include/variables.h --- efitools-1.4.2/include/variables.h 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/include/variables.h 2018-02-21 03:53:05.000000000 +0000 @@ -27,7 +27,8 @@ EFI_STATUS find_in_variable_esl(CHAR16* var, EFI_GUID owner, UINT8 *key, UINTN keylen); -#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001 +#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001 +#define EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION 0x0000000000000002 UINT64 GetOSIndications(void); @@ -43,3 +44,7 @@ EFI_STATUS variable_create_esl(void *cert, int cert_len, EFI_GUID *type, EFI_GUID *owner, void **out, int *outlen); +int +hashes_in_esl(UINT8 *Data, UINTN DataSize, EFI_GUID *hashes[]); +int +hashes_in_variable(CHAR16* var, EFI_GUID owner, EFI_GUID *hashes[]); diff -Nru efitools-1.4.2/include/version.h efitools-1.8.1/include/version.h --- efitools-1.4.2/include/version.h 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/include/version.h 2018-02-21 03:53:05.000000000 +0000 @@ -1,4 +1,4 @@ -#define VERSION "1.4.1" +#define VERSION "1.8.1" static void version(const char *progname) diff -Nru efitools-1.4.2/KeyTool.c efitools-1.8.1/KeyTool.c --- efitools-1.4.2/KeyTool.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/KeyTool.c 2018-02-21 03:53:05.000000000 +0000 @@ -16,7 +16,7 @@ #include <efiauthenticated.h> static EFI_HANDLE im; -static UINT8 SetupMode, SecureBoot; +static UINT8 SetupMode, SecureBoot, display_dbt; #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) @@ -25,6 +25,7 @@ KEY_KEK, KEY_DB, KEY_DBX, + KEY_DBT, KEY_MOK, MAX_KEYS }; @@ -64,6 +65,13 @@ .authenticated = 1, .hash = 1, }, + [KEY_DBT] = { + .name = L"dbt", + .text = L"The Timestamp Signatures Database (dbt)", + .guid = &SIG_DB, + .authenticated = 1, + .hash = 0, + }, [KEY_MOK] = { .name = L"MokList", .text = L"The Machine Owner Key List (MokList)", @@ -87,6 +95,15 @@ { .guid = &EFI_CERT_SHA256_GUID, .name = L"SHA256 signature", }, + { .guid = &EFI_CERT_X509_SHA256_GUID, + .name = L"X509 SHA256 signature", + }, + { .guid = &EFI_CERT_X509_SHA384_GUID, + .name = L"X509 SHA384 signature", + }, + { .guid = &EFI_CERT_X509_SHA384_GUID, + .name = L"X509 SHA256 signature", + }, }; static const int signatures_size = ARRAY_SIZE(signatures); @@ -152,12 +169,11 @@ status = SetSecureVariable(keyinfo[key].name, esl, size, *keyinfo[key].guid, options, 0); } else { - status = uefi_call_wrapper(RT->SetVariable, 5, - keyinfo[key].name, keyinfo[key].guid, - EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_BOOTSERVICE_ACCESS - | options, - size, esl); + status = RT->SetVariable(keyinfo[key].name, keyinfo[key].guid, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | options, + size, esl); } if (status != EFI_SUCCESS) { console_error(L"Failed to update variable", status); @@ -176,7 +192,7 @@ return 1; } while (len > 0) { - int i, found; + int i, found = 0; for (i = 0; i < maxlen; i++) { if (str[i] == c) @@ -220,11 +236,10 @@ DataSize, *keyinfo[key].guid, 0, 0); else - status = uefi_call_wrapper(RT->SetVariable, 5, - keyinfo[key].name, keyinfo[key].guid, - EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_BOOTSERVICE_ACCESS, - DataSize, Data); + status = RT->SetVariable(keyinfo[key].name, keyinfo[key].guid, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS, + DataSize, Data); if (status != EFI_SUCCESS) console_error(L"Failed to delete key", status); @@ -290,6 +305,17 @@ title[++c] = L"Issuer:"; for (i = 0; i < sp; i++) title[++c] = tmpbuf1[i]; + } else if (CompareGuid(&CertList->SignatureType, &EFI_CERT_X509_SHA256_GUID) == 0) { + EFI_CERT_X509_SHA256 *tmp = (void *)Cert->SignatureData; + StrCpy(str2, L"Hash: "); + sha256_StrCat_hash(str2, Cert->SignatureData); + title[++c] = str2; + EFI_TIME timestamp = tmp->TimeOfRevocation; + SPrint(buf, sizeof(buf), + L"Revocation Timestamp: %d-%d-%d %02d:%02d:%02d\n", + timestamp.Year, timestamp.Month, timestamp.Day, + timestamp.Hour, timestamp.Minute, timestamp.Second); + title[++c] = buf; } title[++c] = NULL; @@ -444,28 +470,15 @@ static void save_key_internal(int key, EFI_HANDLE vol, CHAR16 *error) { - CHAR16 *variables[] = { - [KEY_PK] = L"PK", - [KEY_KEK] = L"KEK", - [KEY_DB] = L"db", - [KEY_DBX] = L"dbx", - [KEY_MOK] = L"MokList" - }; - EFI_GUID owners[] = { - [KEY_PK] = GV_GUID, - [KEY_KEK] = GV_GUID, - [KEY_DB] = SIG_DB, - [KEY_DBX] = SIG_DB, - [KEY_MOK] = MOK_OWNER - }; EFI_STATUS status; EFI_FILE *file; UINT8 *data; UINTN len; CHAR16 file_name[512]; - StrCpy(error, variables[key]); - status = get_variable(variables[key], &data, &len, owners[key]); + StrCpy(error, keyinfo[key].name); + status = get_variable(keyinfo[key].name, &data, &len, + *keyinfo[key].guid); if (status != EFI_SUCCESS) { if (status == EFI_NOT_FOUND) StrCat(error, L": Variable has no entries"); @@ -475,7 +488,7 @@ return; } StrCpy(file_name, L"\\"); - StrCat(file_name, variables[key]); + StrCat(file_name, keyinfo[key].name); StrCat(file_name, L".esl"); status = simple_file_open(vol, file_name, &file, EFI_FILE_MODE_READ @@ -541,7 +554,7 @@ UINT8 *Data; UINTN DataSize = 0, Size; - efi_status = uefi_call_wrapper(RT->GetVariable, 5, keyinfo[key].name, keyinfo[key].guid, NULL, &DataSize, NULL); + efi_status = RT->GetVariable(keyinfo[key].name, keyinfo[key].guid, NULL, &DataSize, NULL); if (efi_status != EFI_BUFFER_TOO_SMALL && efi_status != EFI_NOT_FOUND) { console_error(L"Failed to get DataSize", efi_status); return; @@ -555,7 +568,7 @@ return; } - efi_status = uefi_call_wrapper(RT->GetVariable, 5, keyinfo[key].name, keyinfo[key].guid, NULL, &DataSize, Data); + efi_status = RT->GetVariable(keyinfo[key].name, keyinfo[key].guid, NULL, &DataSize, Data); if (efi_status == EFI_NOT_FOUND) { int t = 2; title[t++] = L"Variable is Empty"; @@ -624,12 +637,17 @@ static void select_key(void) { - int i; + int i, j; + int keymap[keyinfo_size + 1]; CHAR16 *keys[keyinfo_size + 1]; - for (i = 0; i < keyinfo_size; i++) - keys[i] = keyinfo[i].text; - keys[i] = NULL; + for (i = 0, j = 0; i < keyinfo_size; i++) { + if (i == KEY_DBT && !display_dbt) + continue; + keys[j] = keyinfo[i].text; + keymap[j++] = i; + } + keys[j] = NULL; i = 0; @@ -637,7 +655,7 @@ i = console_select( (CHAR16 *[]){ L"Select Key to Manipulate", NULL }, keys, i); if (i == -1) break; - manipulate_key(i); + manipulate_key(keymap[i]); } } @@ -670,6 +688,8 @@ title[t_c++] = L""; for (i = 0; i < MAX_KEYS; i++) { + if (i == KEY_DBT && !display_dbt) + continue; save_key_internal(i, vol, &buf[b_c]); title[t_c++] = &buf[b_c]; b_c += StrLen(&buf[b_c]) + 1; @@ -678,6 +698,45 @@ console_alertbox(title); } +static void +execute_binary() +{ + CHAR16 *bin_name; + EFI_HANDLE h = NULL; + EFI_HANDLE ih; + EFI_DEVICE_PATH *devpath; + EFI_STATUS status; + + simple_file_selector(&h, (CHAR16 *[]) { + L"Select Binary to Execute", + L"", + NULL + }, L"\\", + NULL, &bin_name); + if (!bin_name) { + /* user pressed ESC */ + return; + } + + /* the execute() call is designed to construct handles from + * local resources on the image. We have a handle and a full + * path name, so we follow proper process here */ + + devpath = FileDevicePath(h, bin_name); + + status = BS->LoadImage(FALSE, im, devpath, NULL, 0, &ih); + if (status != EFI_SUCCESS) { + console_error(L"Image failed to load", status); + return; + } + + status = BS->StartImage(ih, NULL, NULL); + BS->UnloadImage(ih); + + if (status != EFI_SUCCESS) + console_error(L"Execution returned error", status); +} + EFI_STATUS efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) { @@ -689,7 +748,10 @@ InitializeLib(image, systab); - efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode); + if (GetOSIndications() & EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION) + display_dbt = 1; + + efi_status = RT->GetVariable(L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode); if (efi_status != EFI_SUCCESS) { Print(L"No SetupMode variable ... is platform secure boot enabled?\n"); return EFI_SUCCESS; @@ -710,7 +772,13 @@ StrCat(line3, SecureBoot ? L"on" : L"off"); title = (CHAR16 *[]){L"KeyTool main menu", L"", line2, line3, NULL }; - option = console_select(title, (CHAR16 *[]){ L"Save Keys", L"Edit Keys", L"Exit", NULL }, option); + option = console_select(title, (CHAR16 *[]){ + L"Save Keys", + L"Edit Keys", + L"Execute Binary", + L"Exit", + NULL }, + option); switch (option) { case 0: @@ -720,6 +788,9 @@ select_key(); break; case 2: + execute_binary(); + break; + case 3: /* exit from programme */ return EFI_SUCCESS; default: diff -Nru efitools-1.4.2/lib/asn1/Makefile efitools-1.8.1/lib/asn1/Makefile --- efitools-1.4.2/lib/asn1/Makefile 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/asn1/Makefile 2018-02-21 03:53:05.000000000 +0000 @@ -8,7 +8,14 @@ libasn1-efi.a: $(EFILIBFILES) test.o: test.c ../../include/x509.h - $(CC) -I../../include -c -o $@ $< + $(CC) $(ARCH3264) -I../../include -c -o $@ $< test: test.o libasn1.a - $(CC) -o $@ $< libasn1.a + $(CC) $(ARCH3264) -o $@ $< libasn1.a + +clean: + rm -f libasn1.a + rm -f libasn1-efi.a + rm -f test test.o + rm -f $(LIBFILES) + rm -f $(EFILIBFILES) diff -Nru efitools-1.4.2/lib/asn1/oid.h efitools-1.8.1/lib/asn1/oid.h --- efitools-1.4.2/lib/asn1/oid.h 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/asn1/oid.h 2018-02-21 03:53:05.000000000 +0000 @@ -5,6 +5,8 @@ * Do not edit manually! */ +#include <sys/types.h> + #ifndef OID_H_ #define OID_H_ diff -Nru efitools-1.4.2/lib/console.c efitools-1.8.1/lib/console.c --- efitools-1.4.2/lib/console.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/console.c 2018-02-21 03:53:05.000000000 +0000 @@ -42,8 +42,8 @@ EFI_INPUT_KEY key; UINTN EventIndex; - uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &EventIndex); - uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key); + BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &EventIndex); + ST->ConIn->ReadKeyStroke(ST->ConIn, &key); return key; } @@ -61,7 +61,7 @@ * it */ for(;;) { - status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &k); + status = ST->ConIn->ReadKeyStroke(ST->ConIn, &k); if (status != EFI_SUCCESS) break; @@ -83,7 +83,7 @@ if (lines == 0) return; - uefi_call_wrapper(co->QueryMode, 4, co, co->Mode->Mode, &cols, &rows); + co->QueryMode(co, co->Mode->Mode, &cols, &rows); /* last row on screen is unusable without scrolling, so ignore it */ rows--; @@ -126,8 +126,8 @@ Line[0] = BOXDRAW_DOWN_RIGHT; Line[size_cols - 1] = BOXDRAW_DOWN_LEFT; Line[size_cols] = L'\0'; - uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, start_row); - uefi_call_wrapper(co->OutputString, 2, co, Line); + co->SetCursorPosition(co, start_col, start_row); + co->OutputString(co, Line); int start; if (offset == 0) @@ -140,7 +140,6 @@ /* from top */ start = start_row + offset; - for (i = start_row + 1; i < size_rows + start_row - 1; i++) { int line = i - start; @@ -159,19 +158,19 @@ CopyMem(Line + col + 1, s, min(len, size_cols - 2)*2); } if (line >= 0 && line == highlight) - uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK); - uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, i); - uefi_call_wrapper(co->OutputString, 2, co, Line); + co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK); + co->SetCursorPosition(co, start_col, i); + co->OutputString(co, Line); if (line >= 0 && line == highlight) - uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE); + co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE); } SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL); Line[0] = BOXDRAW_UP_RIGHT; Line[size_cols - 1] = BOXDRAW_UP_LEFT; Line[size_cols] = L'\0'; - uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, i); - uefi_call_wrapper(co->OutputString, 2, co, Line); + co->SetCursorPosition(co, start_col, i); + co->OutputString(co, Line); FreePool (Line); @@ -183,19 +182,19 @@ SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode; SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut; CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode)); - uefi_call_wrapper(co->EnableCursor, 2, co, FALSE); - uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE); + co->EnableCursor(co, FALSE); + co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE); console_print_box_at(str_arr, highlight, 0, 0, -1, -1, 0, count_lines(str_arr)); console_get_keystroke(); - uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible); + co->EnableCursor(co, SavedConsoleMode.CursorVisible); - uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible); - uefi_call_wrapper(co->SetCursorPosition, 3, co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow); - uefi_call_wrapper(co->SetAttribute, 2, co, SavedConsoleMode.Attribute); + co->EnableCursor(co, SavedConsoleMode.CursorVisible); + co->SetCursorPosition(co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow); + co->SetAttribute(co, SavedConsoleMode.Attribute); } int @@ -209,9 +208,10 @@ int selector_max_cols = 0; int i, offs_col, offs_row, size_cols, size_rows, lines; int selector_offset; + int title_lines = count_lines(title); UINTN cols, rows; - uefi_call_wrapper(co->QueryMode, 4, co, co->Mode->Mode, &cols, &rows); + co->QueryMode(co, co->Mode->Mode, &cols, &rows); for (i = 0; i < selector_lines; i++) { int len = StrLen(selectors[i]); @@ -228,13 +228,12 @@ offs_col = - selector_max_cols - 4; size_cols = selector_max_cols + 4; - if (selector_lines > rows - 10) { - int title_lines = count_lines(title); - offs_row = title_lines + 1; - size_rows = rows - 3 - title_lines; + if (selector_lines > rows - 6 - title_lines) { + offs_row = title_lines + 2; + size_rows = rows - 4 - title_lines; lines = size_rows - 2; } else { - offs_row = - selector_lines - 4; + offs_row = (rows + title_lines - 1 - selector_lines)/2; size_rows = selector_lines + 2; lines = selector_lines; } @@ -248,8 +247,8 @@ } CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode)); - uefi_call_wrapper(co->EnableCursor, 2, co, FALSE); - uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE); + co->EnableCursor(co, FALSE); + co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE); console_print_box_at(title, -1, 0, 0, -1, -1, 1, count_lines(title)); @@ -282,11 +281,11 @@ } while (!(k.ScanCode == SCAN_NULL && k.UnicodeChar == CHAR_CARRIAGE_RETURN)); - uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible); + co->EnableCursor(co, SavedConsoleMode.CursorVisible); - uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible); - uefi_call_wrapper(co->SetCursorPosition, 3, co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow); - uefi_call_wrapper(co->SetAttribute, 2, co, SavedConsoleMode.Attribute); + co->EnableCursor(co, SavedConsoleMode.CursorVisible); + co->SetCursorPosition(co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow); + co->SetAttribute(co, SavedConsoleMode.Attribute); if (selector < 0) /* ESC pressed */ @@ -406,8 +405,8 @@ { SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut; - uefi_call_wrapper(co->Reset, 2, co, TRUE); + co->Reset(co, TRUE); /* set mode 0 - required to be 80x25 */ - uefi_call_wrapper(co->SetMode, 2, co, 0); - uefi_call_wrapper(co->ClearScreen, 1, co); + co->SetMode(co, 0); + co->ClearScreen(co); } diff -Nru efitools-1.4.2/lib/execute.c efitools-1.8.1/lib/execute.c --- efitools-1.4.2/lib/execute.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/execute.c 2018-02-21 03:53:05.000000000 +0000 @@ -102,8 +102,7 @@ EFI_DEVICE_PATH *devpath; CHAR16 *PathName; - status = uefi_call_wrapper(BS->HandleProtocol, 3, image, - &IMAGE_PROTOCOL, &li); + status = BS->HandleProtocol(image, &IMAGE_PROTOCOL, (VOID **)&li); if (status != EFI_SUCCESS) return status; @@ -112,13 +111,12 @@ if (status != EFI_SUCCESS) return status; - status = uefi_call_wrapper(BS->LoadImage, 6, FALSE, image, - devpath, NULL, 0, &h); + status = BS->LoadImage(FALSE, image, devpath, NULL, 0, &h); if (status != EFI_SUCCESS) goto out; - status = uefi_call_wrapper(BS->StartImage, 3, h, NULL, NULL); - uefi_call_wrapper(BS->UnloadImage, 1, h); + status = BS->StartImage(h, NULL, NULL); + BS->UnloadImage(h); out: FreePool(PathName); diff -Nru efitools-1.4.2/lib/guid.c efitools-1.8.1/lib/guid.c --- efitools-1.4.2/lib/guid.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/guid.c 2018-02-21 03:53:05.000000000 +0000 @@ -6,6 +6,9 @@ #include <guid.h> #include <stdio.h> +#include <buildefi.h> + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) #ifndef BUILD_EFI /* EFI has %g for this, so it's only needed in platform c */ @@ -40,8 +43,28 @@ { return memcmp(g1, g2, sizeof(*g1)); } + +EFI_GUID * +get_owner_guid(char *var) +{ + char *variables[] = { "PK", "KEK", "db", "dbx", "dbt", "MokList" }; + EFI_GUID *owners[] = { &GV_GUID, &GV_GUID, &SIG_DB, &SIG_DB, &SIG_DB, &MOK_OWNER }; + EFI_GUID *owner = NULL; + int i; + + for(i = 0; i < ARRAY_SIZE(variables); i++) { + if (strcmp(var, variables[i]) == 0) { + owner = owners[i]; + break; + } + } + + return owner; +} #endif + + /* all the necessary guids */ EFI_GUID GV_GUID = EFI_GLOBAL_VARIABLE; EFI_GUID SIG_DB = { 0xd719b2cb, 0x3d3a, 0x4596, {0xa3, 0xbc, 0xda, 0xd0, 0xe, 0x67, 0x65, 0x6f }}; @@ -55,3 +78,19 @@ EFI_GUID MOK_OWNER = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }; EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } }; EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } }; +EFI_GUID SECURE_VARIABLE_GUID = { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }; +EFI_GUID PKCS7_VERIFY_PROTOCOL_GUID = { 0x47889fb2, 0xd671, 0x4fab, {0xa0, 0xca, 0xdf, 0x0e, 0x44, 0xdf, 0x70, 0xd6 } }; +EFI_GUID EFI_CERT_SHA1_GUID = { 0x826ca512, 0xcf10, 0x4ac9, { 0xb1, 0x87, 0xbe, 0x01, 0x49, 0x66, 0x31, 0xbd } }; +EFI_GUID EFI_CERT_SHA224_GUID = { 0xb6e5233, 0xa65c, 0x44c9, {0x94, 0x07, 0xd9, 0xab, 0x83, 0xbf, 0xc8, 0xbd} }; +EFI_GUID EFI_CERT_SHA384_GUID = { 0xff3e5307, 0x9fd0, 0x48c9, {0x85, 0xf1, 0x8a, 0xd5, 0x6c, 0x70, 0x1e, 0x01}}; +EFI_GUID EFI_CERT_SHA512_GUID = { 0x93e0fae, 0xa6c4, 0x4f50, {0x9f, 0x1b, 0xd4, 0x1e, 0x2b, 0x89, 0xc1, 0x9a} }; + +EFI_GUID *allowed_hashes[] = { + &EFI_CERT_SHA1_GUID, + &EFI_CERT_SHA224_GUID, + &EFI_CERT_SHA256_GUID, + &EFI_CERT_SHA384_GUID, + &EFI_CERT_SHA512_GUID, +}; + +UINTN allowed_hashes_size = ARRAY_SIZE(allowed_hashes); diff -Nru efitools-1.4.2/lib/kernel_efivars.c efitools-1.8.1/lib/kernel_efivars.c --- efitools-1.4.2/lib/kernel_efivars.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/kernel_efivars.c 2018-02-21 03:53:05.000000000 +0000 @@ -66,10 +66,10 @@ while (ptr < buf + st.st_size) { int count; - sscanf(ptr, "%*s on %s type %s %*s\n%n", path, type, &count); + sscanf(ptr, "%*s on %s type %s %*[^\n]\n%n", path, type, &count); ptr += count; - if (strcmp(type, "efivarfs") != 0) - continue; + if (strcmp(type, "efivarfs") == 0) + break; } if (strcmp(type, "efivarfs") != 0) { fprintf(stderr, "No efivarfs filesystem is mounted\n"); @@ -205,7 +205,8 @@ /* FIXME: currently timestamp is one year into future because of * the way we set up the secure environment */ Time->Year = tm.tm_year + 1900 + 1; - Time->Month = tm.tm_mon; + /* EFI_TIME Month is 1-12; Unix tm_mon is 0-11 */ + Time->Month = tm.tm_mon + 1; Time->Day = tm.tm_mday; Time->Hour = tm.tm_hour; Time->Minute = tm.tm_min; diff -Nru efitools-1.4.2/lib/Makefile efitools-1.8.1/lib/Makefile --- efitools-1.4.2/lib/Makefile 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/Makefile 2018-02-21 03:53:05.000000000 +0000 @@ -1,5 +1,7 @@ FILES = simple_file.o pecoff.o guid.o sha256.o console.o \ - security_policy.o execute.o configtable.o shell.o + execute.o configtable.o shell.o security_policy.o \ + shim_protocol.o pkcs7verify.o + LIBFILES = $(FILES) kernel_efivars.o EFILIBFILES = $(patsubst %.o,%.efi.o,$(FILES)) variables.o @@ -10,5 +12,7 @@ clean: rm -f lib.a + rm -f lib-efi.a rm -f $(LIBFILES) + rm -f $(EFILIBFILES) diff -Nru efitools-1.4.2/lib/pecoff.c efitools-1.8.1/lib/pecoff.c --- efitools-1.4.2/lib/pecoff.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/pecoff.c 2018-02-21 03:53:05.000000000 +0000 @@ -50,6 +50,14 @@ #include <efi.h> #include <efilib.h> +#ifdef CONFIG_arm +#ifndef BUILD_EFI +/* FIXME: + * arm efi leaves a visibilit pragma pushed that won't work for + * non efi programs, so eliminate it */ +#pragma GCC visibility pop +#endif +#endif #include <pecoff.h> #include <guid.h> @@ -57,13 +65,8 @@ #include <variables.h> #include <sha256.h> #include <errors.h> - -#ifndef BUILD_EFI -#define Print(...) do { } while(0) -#define AllocatePool(x) malloc(x) -#define CopyMem(d, s, l) memcpy(d, s, l) -#define ZeroMem(s, l) memset(s, 0, l) -#endif +#include <execute.h> +#include <buildefi.h> EFI_STATUS pecoff_read_header(PE_COFF_LOADER_IMAGE_CONTEXT *context, void *data) @@ -84,21 +87,34 @@ return EFI_UNSUPPORTED; } - if (PEHdr->Pe32.OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - Print(L"Only 64-bit images supported\n"); + if (PEHdr->Pe32.OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC && + PEHdr->Pe32.OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Print(L"Only IA32 or X64 images supported\n"); return EFI_UNSUPPORTED; } context->PEHdr = PEHdr; - context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase; - context->ImageSize = (UINT64)PEHdr->Pe32Plus.OptionalHeader.SizeOfImage; - context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders; - context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint; - context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; - context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes; + if (PEHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + context->ImageAddress = PEHdr->Pe32Plus.OptionalHeader.ImageBase; + context->ImageSize = (UINT64)PEHdr->Pe32Plus.OptionalHeader.SizeOfImage; + context->SizeOfHeaders = PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders; + context->EntryPoint = PEHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint; + context->RelocDir = &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + context->NumberOfRvaAndSizes = PEHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes; + context->SecDir = (EFI_IMAGE_DATA_DIRECTORY *) &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + context->FileAlignment = PEHdr->Pe32Plus.OptionalHeader.FileAlignment; + + } else if (PEHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + context->ImageAddress = PEHdr->Pe32.OptionalHeader.ImageBase; + context->ImageSize = (UINT64)PEHdr->Pe32.OptionalHeader.SizeOfImage; + context->SizeOfHeaders = PEHdr->Pe32.OptionalHeader.SizeOfHeaders; + context->EntryPoint = PEHdr->Pe32.OptionalHeader.AddressOfEntryPoint; + context->RelocDir = &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + context->NumberOfRvaAndSizes = PEHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes; + context->SecDir = (EFI_IMAGE_DATA_DIRECTORY *) &PEHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + context->FileAlignment = PEHdr->Pe32.OptionalHeader.FileAlignment; } context->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections; context->FirstSection = (EFI_IMAGE_SECTION_HEADER *)((char *)PEHdr + PEHdr->Pe32.FileHeader.SizeOfOptionalHeader + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER)); - context->SecDir = (EFI_IMAGE_DATA_DIRECTORY *) &PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; if (context->SecDir->VirtualAddress >= context->ImageSize) { Print(L"Malformed security header\n"); @@ -120,10 +136,8 @@ for (i = 0; i < context->NumberOfSections; i++) { s = &context->FirstSection[i]; - size = s->Misc.VirtualSize; - - if (size > s->SizeOfRawData) - size = s->SizeOfRawData; + size = ALIGN_VALUE(s->SizeOfRawData, context->FileAlignment); + base = pecoff_image_address(buffer, context->ImageSize, s->VirtualAddress); end = pecoff_image_address(buffer, context->ImageSize, s->VirtualAddress + size - 1); @@ -165,7 +179,11 @@ return efi_status; } - context->PEHdr->Pe32Plus.OptionalHeader.ImageBase = (UINT64)*data; + if (context->PEHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + context->PEHdr->Pe32Plus.OptionalHeader.ImageBase = (UINT64)*data; + } else if (context->PEHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + context->PEHdr->Pe32.OptionalHeader.ImageBase = (UINT32)(long)*data; + } if (context->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { Print(L"Image has no relocation entry\n"); @@ -255,6 +273,32 @@ return EFI_SUCCESS; } +EFI_STATUS +pecoff_get_signature(PE_COFF_LOADER_IMAGE_CONTEXT *context, void *buffer, + WIN_CERTIFICATE **data, int signum) +{ + WIN_CERTIFICATE *cert; + UINT32 offset; + int i; + + if (!context->SecDir->Size) + return EFI_NOT_FOUND; + + offset = context->SecDir->VirtualAddress; + cert = (WIN_CERTIFICATE *)(buffer + offset); + for (i = 0; i < signum; i++) { + offset += ALIGN_VALUE(cert->dwLength, 8); + cert = (WIN_CERTIFICATE *)(buffer + offset); + if (offset >= context->SecDir->VirtualAddress + context->SecDir->Size) + break; + } + if (i != signum) + return EFI_NOT_FOUND; + + *data = cert; + return EFI_SUCCESS; +} + #ifdef BUILD_EFI EFI_STATUS pecoff_check_mok(EFI_HANDLE image, CHAR16 *name) @@ -319,21 +363,19 @@ EFI_HANDLE h; EFI_FILE *file; - status = uefi_call_wrapper(BS->HandleProtocol, 3, image, - &IMAGE_PROTOCOL, &li); + status = BS->HandleProtocol(image, &IMAGE_PROTOCOL, (VOID **)&li); if (status != EFI_SUCCESS) return status; status = generate_path(name, li, &loadpath, &PathName); if (status != EFI_SUCCESS) return status; - status = uefi_call_wrapper(BS->LoadImage, 6, FALSE, image, - loadpath, NULL, 0, &h); + status = BS->LoadImage(FALSE, image, loadpath, NULL, 0, &h); if (status == EFI_SECURITY_VIOLATION || status == EFI_ACCESS_DENIED) status = pecoff_check_mok(image, name); if (status != EFI_SUCCESS) /* this will fail if signature validation fails */ return status; - uefi_call_wrapper(BS->UnloadImage, 1, h); + BS->UnloadImage(h); status = simple_file_open(image, name, &file, EFI_FILE_MODE_READ); if (status != EFI_SUCCESS) @@ -381,7 +423,7 @@ goto out; } - efi_status = uefi_call_wrapper(entry_point, 2, image, systab); + efi_status = entry_point(image, systab); out: FreePool(buffer); diff -Nru efitools-1.4.2/lib/pkcs7verify.c efitools-1.8.1/lib/pkcs7verify.c --- efitools-1.4.2/lib/pkcs7verify.c 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/lib/pkcs7verify.c 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,250 @@ +#include <efi.h> +#include <efilib.h> + +#include <efiauthenticated.h> +#include <guid.h> +#include <pkcs7verify.h> +#include <variables.h> +#include <execute.h> +#include <pecoff.h> + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) + +static CHAR16 *p7bin = L"\\Pkcs7VerifyDxe.efi"; +static EFI_PKCS7_VERIFY_PROTOCOL *pkcs7verifyprotocol; + +EFI_STATUS +pkcs7verify_get_protocol(EFI_HANDLE image, EFI_PKCS7_VERIFY_PROTOCOL **p7vp, CHAR16 **error) +{ + EFI_LOADED_IMAGE *li; + EFI_DEVICE_PATH *loadpath = NULL; + CHAR16 *PathName = NULL; + EFI_HANDLE loader_handle; + EFI_STATUS status; + + status = BS->LocateProtocol(&PKCS7_VERIFY_PROTOCOL_GUID, + NULL, (VOID **)p7vp); + + if (status == EFI_SUCCESS) + return status; + + Print(L"Platform doesn't provide PKCS7_VERIFY protocol, trying to load\n"); + + status = BS->HandleProtocol(image, &IMAGE_PROTOCOL, (VOID **)&li); + if (status != EFI_SUCCESS) { + *error = L"Can't find loaded image protocol"; + return status; + } + + status = generate_path(p7bin, li, &loadpath, &PathName); + if (status != EFI_SUCCESS) { + *error = L"generate_path failed"; + return status; + } + + status = BS->LoadImage(FALSE, image, loadpath, NULL, 0, &loader_handle); + if (status != EFI_SUCCESS) { + *error = L"LoadImage failed for external module"; + return status; + } + + status = BS->StartImage(loader_handle, NULL, NULL); + if (status != EFI_SUCCESS) { + *error = L"StartImage failed for external module (loaded OK)"; + return status; + } + + status = BS->LocateProtocol(&PKCS7_VERIFY_PROTOCOL_GUID, + NULL, (VOID **)p7vp); + + if (status != EFI_SUCCESS) + *error = L"Loaded module but it didn't provide the pkcs7Verify protocol"; + else + pkcs7verifyprotocol = *p7vp; + + return status; +} + +/* + * Checks the variable for the binary hash. Returns 1 if found, 0 if + * not and -1 on error. + */ +static int +pkcs7verify_is_hash_present(CHAR16 *var, EFI_GUID owner, VOID *data, UINTN len) +{ + EFI_GUID **hashes; + UINT8 *hash; + int count, i; + int present = -1; + + hashes = AllocatePool(allowed_hashes_size * sizeof(EFI_GUID *)); + if (!hashes) + goto out; + + count = hashes_in_variable(var, owner, hashes); + if (count < 0) + goto out; + + for (i = 0; i < count; i++) { + if (CompareGuid(hashes[i], &EFI_CERT_SHA256_GUID) == 0) { + hash = AllocatePool(SHA256_DIGEST_SIZE); + if (!hash) + goto out; + if (sha256_get_pecoff_digest_mem(data, len, hash) != EFI_SUCCESS) { + FreePool(hash); + goto out; + } + if (find_in_variable_esl(var, owner, hash, SHA256_DIGEST_SIZE) == EFI_SUCCESS) { + present = 1; + FreePool(hash); + goto out; + } + FreePool(hash); + } else { + Print(L"FIXME: found an unrecognised hash algorithm %g\n", + hashes[i]); + goto out; + } + } + present = 0; + out: + if (hashes) + FreePool(hashes); + return present; +} + + +BOOLEAN +pkcs7verify_deny(VOID *data, UINTN len) +{ + int deny; + + deny = pkcs7verify_is_hash_present(L"dbx", SIG_DB, data, len); + if (deny == 1 || deny < 0) { + deny = 1; + goto out; + } + deny = pkcs7verify_is_hash_present(L"MokListX", MOK_OWNER, data, len); + if (deny == 1 || deny < 0) + deny = 1; + out: + return deny ? TRUE : FALSE; +} + +/* + * The Plcs7Verify protocol doesn't take raw signature lists and lengths, + * it takes a null terminated list of pointers to signature lists, so + * make the conversion + */ +EFI_SIGNATURE_LIST ** +pkcs7verify_to_cert_list(VOID *data, UINTN len) +{ + EFI_SIGNATURE_LIST *CertList, **retval; + + int size, count=0; + + if (!data) + return data; + + certlist_for_each_certentry(CertList, data, size, len) + count++; + + retval = AllocatePool((count + 1) * sizeof(void *)); + if (!retval) + return NULL; + count = 0; + certlist_for_each_certentry(CertList, data, size, len) + retval[count++] = CertList; + retval[count] = NULL; + + return retval; +} + +BOOLEAN +pkcs7verify_allow(VOID *data, UINTN len) +{ + PE_COFF_LOADER_IMAGE_CONTEXT context; + UINT8 hash[SHA256_DIGEST_SIZE]; + BOOLEAN allow = FALSE; + CHAR16 *check[] = { L"MokList", L"db" }; + CHAR16 *forbid[] = { L"MokListX", L"dbx" }; + EFI_GUID owners[] = { MOK_OWNER, SIG_DB }; + EFI_STATUS status; + int i; + + status = pecoff_read_header(&context, data); + if (status != EFI_SUCCESS) + goto out; + + /* FIXME: this is technically wrong, because the hash + * could be non-sha256, but it isn't a security breach + * because we'll refuse a binary we should have accepted */ + status = sha256_get_pecoff_digest_mem(data, len, hash); + if (status != EFI_SUCCESS) + goto out; + + /* first look up the hashes because the verify protocol can't + * do this anyway */ + + if (find_in_variable_esl(L"MokList", MOK_OWNER, hash, SHA256_DIGEST_SIZE) == EFI_SUCCESS || + find_in_variable_esl(L"db", SIG_DB, hash, SHA256_DIGEST_SIZE) == EFI_SUCCESS) { + allow = TRUE; + goto out; + } + + for (i = 0; i < ARRAY_SIZE(check); i++) { + VOID *db = NULL, *dbx = NULL; + EFI_SIGNATURE_LIST **dblist = NULL, **dbxlist = NULL; + UINTN db_len = 0, dbx_len = 0; + int j; + + status = get_variable(check[i], (UINT8 **)&db, &db_len, owners[i]); + if (status != EFI_SUCCESS) + goto next; + status = get_variable(forbid[i], (UINT8 **)&dbx, &dbx_len, owners[i]); + if (status != EFI_SUCCESS && status != EFI_NOT_FOUND) + goto next; + dblist = pkcs7verify_to_cert_list(db, db_len); + if (status != EFI_NOT_FOUND) + dbxlist = pkcs7verify_to_cert_list(dbx, dbx_len); + if ((db_len != 0 && dblist == NULL) || + (dbx_len != 0 && dbxlist == NULL)) + goto next; + for (j = 0; ; j++) { + WIN_CERTIFICATE *cert; + + status = pecoff_get_signature(&context, data, + &cert, j); + if (status != EFI_SUCCESS) + break; + + status = pkcs7verifyprotocol-> + VerifySignature(pkcs7verifyprotocol, + (VOID *)(cert + 1), + cert->dwLength - sizeof(*cert), + hash, sizeof(hash), + dblist, dbxlist, NULL); + + if (status == EFI_SUCCESS) { + allow = TRUE; + break; + } + } + next: + if (dblist) + FreePool(dblist); + if (dbxlist) + FreePool(dbxlist); + if (db) + FreePool(db); + if (dbx) + FreePool(dbx); + if (allow) + break; + } + + out: + return allow; + + +} diff -Nru efitools-1.4.2/lib/security_policy.c efitools-1.8.1/lib/security_policy.c --- efitools-1.4.2/lib/security_policy.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/security_policy.c 2018-02-21 03:53:05.000000000 +0000 @@ -51,16 +51,14 @@ static UINT8 *security_policy_esl = NULL; static UINTN security_policy_esl_len; -static EFI_STATUS -security_policy_check_mok(void *data, UINTN len) +BOOLEAN security_policy_mok_override(void) { - EFI_STATUS status; - UINT8 hash[SHA256_DIGEST_SIZE]; - UINT32 attr; UINT8 *VarData; UINTN VarLen; + UINT32 attr; + EFI_STATUS status; - /* first check is MokSBState. If we're in insecure mode, boot + /* Secure Boot Override: MokSBState. If we're in insecure mode, boot * anyway regardless of dbx contents */ status = get_variable_attr(L"MokSBState", &VarData, &VarLen, MOK_OWNER, &attr); @@ -70,17 +68,44 @@ FreePool(VarData); if ((attr & EFI_VARIABLE_RUNTIME_ACCESS) == 0 && MokSBState) - return EFI_SUCCESS; + return TRUE; } + return FALSE; +} + +BOOLEAN security_policy_mok_deny(VOID *data, UINTN len) +{ + EFI_STATUS status; + UINT8 hash[SHA256_DIGEST_SIZE]; status = sha256_get_pecoff_digest_mem(data, len, hash); if (status != EFI_SUCCESS) - return status; + return TRUE; if (find_in_variable_esl(L"dbx", SIG_DB, hash, SHA256_DIGEST_SIZE) == EFI_SUCCESS) /* MOK list cannot override dbx */ - return EFI_SECURITY_VIOLATION; + return FALSE; + + if (find_in_variable_esl(L"MokListX", SIG_DB, hash, SHA256_DIGEST_SIZE) + == EFI_SUCCESS) + return TRUE; + + return FALSE; +} + +BOOLEAN security_policy_mok_allow(VOID *data, UINTN len) +{ + EFI_STATUS status; + UINT8 hash[SHA256_DIGEST_SIZE]; + UINT32 attr; + UINT8 *VarData; + UINTN VarLen; + + + status = sha256_get_pecoff_digest_mem(data, len, hash); + if (status != EFI_SUCCESS) + return TRUE; status = get_variable_attr(L"MokList", &VarData, &VarLen, MOK_OWNER, &attr); @@ -93,37 +118,26 @@ goto check_tmplist; if (find_in_variable_esl(L"MokList", MOK_OWNER, hash, SHA256_DIGEST_SIZE) == EFI_SUCCESS) - return EFI_SUCCESS; + return TRUE; check_tmplist: if (security_policy_esl && find_in_esl(security_policy_esl, security_policy_esl_len, hash, SHA256_DIGEST_SIZE) == EFI_SUCCESS) - return EFI_SUCCESS; + return TRUE; - return EFI_SECURITY_VIOLATION; + return FALSE; } -static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL; -static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL; +static EFIAPI EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL; +static EFIAPI EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL; -static EFI_STATUS thunk_security_policy_authentication( - const EFI_SECURITY_PROTOCOL *This, - UINT32 AuthenticationStatus, - const EFI_DEVICE_PATH_PROTOCOL *DevicePath - ) -__attribute__((unused)); +static BOOLEAN(*sp_override)(void) = NULL; +static POLICY_FUNCTION sp_allow = NULL; +static POLICY_FUNCTION sp_deny = NULL; -static EFI_STATUS thunk_security2_policy_authentication( - const EFI_SECURITY2_PROTOCOL *This, - const EFI_DEVICE_PATH_PROTOCOL *DevicePath, - VOID *FileBuffer, - UINTN FileSize, - BOOLEAN BootPolicy - ) -__attribute__((unused)); - -static __attribute__((used)) EFI_STATUS +EFI_STATUS +EFIAPI security2_policy_authentication ( const EFI_SECURITY2_PROTOCOL *This, const EFI_DEVICE_PATH_PROTOCOL *DevicePath, @@ -132,29 +146,31 @@ BOOLEAN BootPolicy ) { - EFI_STATUS status, auth; + EFI_STATUS status; + + if (sp_override && sp_override()) + return EFI_SUCCESS; + + /* if policy would deny, fail now */ + if (sp_deny && sp_deny(FileBuffer, FileSize)) + return EFI_SECURITY_VIOLATION; /* Chain original security policy */ - status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer, - FileSize, BootPolicy); + status = es2fa(This, DevicePath, FileBuffer, FileSize, BootPolicy); - /* if OK, don't bother with MOK check */ + /* if OK, don't bother with allow check */ if (status == EFI_SUCCESS) return status; - auth = security_policy_check_mok(FileBuffer, FileSize); - - if (auth == EFI_SECURITY_VIOLATION || auth == EFI_ACCESS_DENIED) - /* return previous status, which is the correct one - * for the platform: may be either EFI_ACCESS_DENIED - * or EFI_SECURITY_VIOLATION */ - return status; + if (sp_allow && sp_allow(FileBuffer, FileSize)) + return EFI_SUCCESS; - return auth; + return status; } -static __attribute__((used)) EFI_STATUS +EFI_STATUS +EFIAPI security_policy_authentication ( const EFI_SECURITY_PROTOCOL *This, UINT32 AuthenticationStatus, @@ -171,21 +187,17 @@ UINTN FileSize; CHAR16* DevPathStr; - /* Chain original security policy */ - status = uefi_call_wrapper(esfas, 3, This, AuthenticationStatus, - DevicePathConst); + if (sp_override && sp_override()) + return EFI_SUCCESS; - /* if OK avoid checking MOK: It's a bit expensive to - * read the whole file in again (esfas already did this) */ - if (status == EFI_SUCCESS) - goto out; + /* Chain original security policy */ + status = esfas(This, AuthenticationStatus, DevicePathConst); /* capture failure status: may be either EFI_ACCESS_DENIED or * EFI_SECURITY_VIOLATION */ fail_status = status; - status = uefi_call_wrapper(BS->LocateDevicePath, 3, - &SIMPLE_FS_PROTOCOL, &DevPath, &h); + status = BS->LocateDevicePath(&SIMPLE_FS_PROTOCOL, &DevPath, &h); if (status != EFI_SUCCESS) goto out; @@ -202,117 +214,38 @@ if (status != EFI_SUCCESS) goto out; - status = security_policy_check_mok(FileBuffer, FileSize); - FreePool(FileBuffer); + status = EFI_SECURITY_VIOLATION; + if (sp_deny && sp_deny(FileBuffer, FileSize)) + goto out; + + status = fail_status; + if (status == EFI_SUCCESS) + goto out; + + /* fail status is platform security failure now */ + + if (sp_allow && sp_allow(FileBuffer, FileSize)) + status = EFI_SUCCESS; - if (status == EFI_ACCESS_DENIED || status == EFI_SECURITY_VIOLATION) - /* return what the platform originally said */ - status = fail_status; out: - FreePool(OrigDevPath); + if (FileBuffer) + FreePool(FileBuffer); + if (OrigDevPath) + FreePool(OrigDevPath); return status; } - -/* Nasty: ELF and EFI have different calling conventions. Here is the map for - * calling ELF -> EFI - * - * 1) rdi -> rcx (32 saved) - * 2) rsi -> rdx (32 saved) - * 3) rdx -> r8 ( 32 saved) - * 4) rcx -> r9 (32 saved) - * 5) r8 -> 32(%rsp) (48 saved) - * 6) r9 -> 40(%rsp) (48 saved) - * 7) pad+0(%rsp) -> 48(%rsp) (64 saved) - * 8) pad+8(%rsp) -> 56(%rsp) (64 saved) - * 9) pad+16(%rsp) -> 64(%rsp) (80 saved) - * 10) pad+24(%rsp) -> 72(%rsp) (80 saved) - * 11) pad+32(%rsp) -> 80(%rsp) (96 saved) - - * - * So for a five argument callback, the map is ignore the first two arguments - * and then map (EFI -> ELF) assuming pad = 0. - * - * ARG4 -> ARG1 - * ARG3 -> ARG2 - * ARG5 -> ARG3 - * ARG6 -> ARG4 - * ARG11 -> ARG5 - * - * Calling conventions also differ over volatile and preserved registers in - * MS: RBX, RBP, RDI, RSI, R12, R13, R14, and R15 are considered nonvolatile . - * In ELF: Registers %rbp, %rbx and %r12 through %r15 âbelongâ to the calling - * function and the called function is required to preserve their values. - * - * This means when accepting a function callback from MS -> ELF, we have to do - * separate preservation on %rdi, %rsi before swizzling the arguments and - * handing off to the ELF function. - */ - -asm ( -".type security2_policy_authentication,@function\n" -"thunk_security2_policy_authentication:\n\t" - "mov 0x28(%rsp), %r10 # ARG5\n\t" - "push %rdi\n\t" - "push %rsi\n\t" - "mov %r10, %rdi\n\t" - "subq $8, %rsp # space for storing stack pad\n\t" - "mov $0x08, %rax\n\t" - "mov $0x10, %r10\n\t" - "and %rsp, %rax\n\t" - "cmovnz %rax, %r11\n\t" - "cmovz %r10, %r11\n\t" - "subq %r11, %rsp\n\t" - "addq $8, %r11\n\t" - "mov %r11, (%rsp)\n\t" -"# five argument swizzle\n\t" - "mov %rdi, %r10\n\t" - "mov %rcx, %rdi\n\t" - "mov %rdx, %rsi\n\t" - "mov %r8, %rdx\n\t" - "mov %r9, %rcx\n\t" - "mov %r10, %r8\n\t" - "callq security2_policy_authentication@PLT\n\t" - "mov (%rsp), %r11\n\t" - "addq %r11, %rsp\n\t" - "pop %rsi\n\t" - "pop %rdi\n\t" - "ret\n" -); - -asm ( -".type security_policy_authentication,@function\n" -"thunk_security_policy_authentication:\n\t" - "push %rdi\n\t" - "push %rsi\n\t" - "subq $8, %rsp # space for storing stack pad\n\t" - "mov $0x08, %rax\n\t" - "mov $0x10, %r10\n\t" - "and %rsp, %rax\n\t" - "cmovnz %rax, %r11\n\t" - "cmovz %r10, %r11\n\t" - "subq %r11, %rsp\n\t" - "addq $8, %r11\n\t" - "mov %r11, (%rsp)\n\t" -"# three argument swizzle\n\t" - "mov %rcx, %rdi\n\t" - "mov %rdx, %rsi\n\t" - "mov %r8, %rdx\n\t" - "callq security_policy_authentication@PLT\n\t" - "mov (%rsp), %r11\n\t" - "addq %r11, %rsp\n\t" - "pop %rsi\n\t" - "pop %rdi\n\t" - "ret\n" -); - EFI_STATUS -security_policy_install(void) +security_policy_install(BOOLEAN (*override)(void), POLICY_FUNCTION allow, POLICY_FUNCTION deny) { EFI_SECURITY_PROTOCOL *security_protocol; EFI_SECURITY2_PROTOCOL *security2_protocol = NULL; EFI_STATUS status; + sp_override = override; + sp_allow = allow; + sp_deny = deny; + if (esfas) /* Already Installed */ return EFI_ALREADY_STARTED; @@ -320,13 +253,11 @@ /* Don't bother with status here. The call is allowed * to fail, since SECURITY2 was introduced in PI 1.2.1 * If it fails, use security2_protocol == NULL as indicator */ - uefi_call_wrapper(BS->LocateProtocol, 3, - &SECURITY2_PROTOCOL_GUID, NULL, - &security2_protocol); - - status = uefi_call_wrapper(BS->LocateProtocol, 3, - &SECURITY_PROTOCOL_GUID, NULL, - &security_protocol); + BS->LocateProtocol(&SECURITY2_PROTOCOL_GUID, NULL, + (VOID **)&security2_protocol); + + status = BS->LocateProtocol(&SECURITY_PROTOCOL_GUID, NULL, + (VOID **)&security_protocol); if (status != EFI_SUCCESS) /* This one is mandatory, so there's a serious problem */ return status; @@ -334,19 +265,19 @@ if (security2_protocol) { es2fa = security2_protocol->FileAuthentication; security2_protocol->FileAuthentication = - thunk_security2_policy_authentication; + security2_policy_authentication; /* check for security policy in write protected memory */ if (security2_protocol->FileAuthentication - != thunk_security2_policy_authentication) + != security2_policy_authentication) return EFI_ACCESS_DENIED; } esfas = security_protocol->FileAuthenticationState; security_protocol->FileAuthenticationState = - thunk_security_policy_authentication; + security_policy_authentication; /* check for security policy in write protected memory */ if (security_protocol->FileAuthenticationState - != thunk_security_policy_authentication) + != security_policy_authentication) return EFI_ACCESS_DENIED; return EFI_SUCCESS; @@ -360,9 +291,8 @@ if (esfas) { EFI_SECURITY_PROTOCOL *security_protocol; - status = uefi_call_wrapper(BS->LocateProtocol, 3, - &SECURITY_PROTOCOL_GUID, NULL, - &security_protocol); + status = BS->LocateProtocol(&SECURITY_PROTOCOL_GUID, NULL, + (VOID **)&security_protocol); if (status != EFI_SUCCESS) return status; @@ -377,9 +307,8 @@ if (es2fa) { EFI_SECURITY2_PROTOCOL *security2_protocol; - status = uefi_call_wrapper(BS->LocateProtocol, 3, - &SECURITY2_PROTOCOL_GUID, NULL, - &security2_protocol); + status = BS->LocateProtocol(&SECURITY2_PROTOCOL_GUID, NULL, + (VOID **)&security2_protocol); if (status != EFI_SUCCESS) return status; diff -Nru efitools-1.4.2/lib/sha256.c efitools-1.8.1/lib/sha256.c --- efitools-1.4.2/lib/sha256.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/sha256.c 2018-02-21 03:53:05.000000000 +0000 @@ -20,18 +20,19 @@ #include <efi/efi.h> #include <efi/efilib.h> +#ifdef CONFIG_arm +#ifndef BUILD_EFI +/* FIXME: + * arm efi leaves a visibilit pragma pushed that won't work for + * non efi programs, so eliminate it */ +#pragma GCC visibility pop +#endif +#endif #include <sha256.h> #include <pecoff.h> #include <simple_file.h> - -#ifndef BUILD_EFI -#define Print(...) do { } while(0) -#define AllocatePool(x) malloc(x) -#define CopyMem(d, s, l) memcpy(d, s, l) -#define ZeroMem(s, l) memset(s, 0, l) -#define FreePool(s) free(s) -#endif +#include <buildefi.h> #define GET_UINT32(n,b,i) \ { \ @@ -281,8 +282,13 @@ unsigned int hashsize; EFI_IMAGE_SECTION_HEADER *section; EFI_IMAGE_SECTION_HEADER **sections; - int i, sum_of_bytes; + int i, sum_of_bytes, checksum_size; EFI_STATUS efi_status; + void *checksum_ptr; + + /* add extra end alignment; rely on data buffer being zero + * filled to the end of the page */ + DataSize = ALIGN_VALUE(DataSize, 8); efi_status = pecoff_read_header(&context, buffer); if (efi_status != EFI_SUCCESS) { @@ -290,7 +296,15 @@ return efi_status; } - sections = AllocatePool(context.PEHdr->Pe32.FileHeader.NumberOfSections * sizeof(*sections)); + if (context.PEHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + checksum_ptr = &context.PEHdr->Pe32Plus.OptionalHeader.CheckSum; + checksum_size = sizeof(context.PEHdr->Pe32Plus.OptionalHeader.CheckSum); + } else { + checksum_ptr = &context.PEHdr->Pe32.OptionalHeader.CheckSum; + checksum_size = sizeof(context.PEHdr->Pe32.OptionalHeader.CheckSum); + } + + sections = AllocatePool(context.NumberOfSections * sizeof(*sections)); if (!sections) return EFI_OUT_OF_RESOURCES; @@ -298,27 +312,26 @@ /* hash start to checksum */ hashbase = buffer; - hashsize = (void *)&context.PEHdr->Pe32.OptionalHeader.CheckSum - buffer; + hashsize = checksum_ptr - buffer; sha256_update(&ctx, hashbase, hashsize); /* hash post-checksum to start of certificate table */ - hashbase = (void *)&context.PEHdr->Pe32.OptionalHeader.CheckSum + sizeof (int); + hashbase = checksum_ptr + checksum_size; hashsize = (void *)context.SecDir - hashbase; sha256_update(&ctx, hashbase, hashsize); /* Hash end of certificate table to end of image header */ - hashbase = &context.PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - hashsize = context.PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders - - (int) ((void *) (&context.PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - buffer); + hashbase = context.SecDir + 1; + hashsize = context.SizeOfHeaders - + (int) (hashbase - buffer); sha256_update(&ctx, hashbase, hashsize); - sum_of_bytes = context.PEHdr->Pe32Plus.OptionalHeader.SizeOfHeaders; + sum_of_bytes = context.SizeOfHeaders; section = (EFI_IMAGE_SECTION_HEADER *) ((char *)context.PEHdr + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + context.PEHdr->Pe32.FileHeader.SizeOfOptionalHeader); - /* Sort the section headers by their data pointers */ - for (i = 0; i < context.PEHdr->Pe32.FileHeader.NumberOfSections; i++) { + for (i = 0; i < context.NumberOfSections; i++) { int p = i; while (p > 0 && section->PointerToRawData < sections[p - 1]->PointerToRawData) { sections[p] = sections[p-1]; @@ -327,10 +340,11 @@ sections[p] = section++; } /* hash the sorted sections */ - for (i = 0; i < context.PEHdr->Pe32.FileHeader.NumberOfSections; i++) { + for (i = 0; i < context.NumberOfSections; i++) { section = sections[i]; hashbase = pecoff_image_address(buffer, DataSize, section->PointerToRawData); - hashsize = (unsigned int) section->SizeOfRawData; + hashsize = (unsigned int) ALIGN_VALUE(section->SizeOfRawData, + context.FileAlignment); if (hashsize == 0) continue; sha256_update(&ctx, hashbase, hashsize); @@ -340,7 +354,7 @@ if (DataSize > sum_of_bytes) { /* stuff at end to hash */ hashbase = buffer + sum_of_bytes; - hashsize = (unsigned int)(DataSize - context.PEHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - sum_of_bytes); + hashsize = (unsigned int)(DataSize - context.SecDir->Size - sum_of_bytes); sha256_update(&ctx, hashbase, hashsize); } sha256_finish(&ctx, hash); diff -Nru efitools-1.4.2/lib/shell.c efitools-1.8.1/lib/shell.c --- efitools-1.4.2/lib/shell.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/shell.c 2018-02-21 03:53:05.000000000 +0000 @@ -20,7 +20,7 @@ *argc = 0; - status = uefi_call_wrapper(BS->HandleProtocol, 3, image, &LoadedImageProtocol, (VOID **) &info); + status = BS->HandleProtocol(image, &LoadedImageProtocol, (VOID **) &info); if (EFI_ERROR(status)) { Print(L"Failed to get arguments\n"); return status; diff -Nru efitools-1.4.2/lib/shim_protocol.c efitools-1.8.1/lib/shim_protocol.c --- efitools-1.4.2/lib/shim_protocol.c 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/lib/shim_protocol.c 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,54 @@ +#include <efi.h> +#include <efilib.h> + +#include <guid.h> +#include <pecoff.h> +#include <sha256.h> +#include <efiauthenticated.h> +#include <pkcs7verify.h> +#include <variables.h> +#include <shim_protocol.h> +#include <console.h> + +static EFI_STATUS shimprotocol_context(void *data, unsigned int size, + PE_COFF_LOADER_IMAGE_CONTEXT *context) +{ + return pecoff_read_header(context, data); +} + +static EFI_STATUS shimprotocol_verify(void *buffer, UINT32 size) +{ + EFI_STATUS status; + + if (!variable_is_secureboot() || variable_is_setupmode()) + return EFI_SUCCESS; + + if (pkcs7verify_deny(buffer, size)) + return EFI_ACCESS_DENIED; + + if (pkcs7verify_allow(buffer, size)) + return EFI_SUCCESS; + + return EFI_ACCESS_DENIED; + + + return status; +} + +static SHIM_LOCK shim_protocol_interface = { + .Verify = shimprotocol_verify, + .Context = shimprotocol_context, +}; +static EFI_HANDLE shim_protocol_handle; + +EFI_STATUS +shim_protocol_install(void) +{ + return BS->InstallProtocolInterface(&shim_protocol_handle, &MOK_OWNER, EFI_NATIVE_INTERFACE, &shim_protocol_interface); +} + +void +shim_protocol_uninstall(void) +{ + BS->UninstallProtocolInterface(shim_protocol_handle, &MOK_OWNER, &shim_protocol_interface); +} diff -Nru efitools-1.4.2/lib/simple_file.c efitools-1.8.1/lib/simple_file.c --- efitools-1.4.2/lib/simple_file.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/simple_file.c 2018-02-21 03:53:05.000000000 +0000 @@ -7,6 +7,7 @@ #include <efi.h> #include <efilib.h> +#include <PeImage.h> /* for ALIGN_VALUE */ #include <console.h> #include <simple_file.h> #include <efiauthenticated.h> @@ -24,23 +25,21 @@ EFI_FILE_IO_INTERFACE *drive; EFI_FILE *root; - efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device, - &SIMPLE_FS_PROTOCOL, &drive); + efi_status = BS->HandleProtocol(device, &SIMPLE_FS_PROTOCOL, (VOID **)&drive); if (efi_status != EFI_SUCCESS) { Print(L"Unable to find simple file protocol (%d)\n", efi_status); goto error; } - efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root); + efi_status = drive->OpenVolume(drive, &root); if (efi_status != EFI_SUCCESS) { Print(L"Failed to open drive volume (%d)\n", efi_status); goto error; } - efi_status = uefi_call_wrapper(root->Open, 5, root, file, name, - mode, 0); + efi_status = root->Open(root, file, name, mode, 0); error: return efi_status; @@ -55,8 +54,7 @@ EFI_DEVICE_PATH *loadpath = NULL; CHAR16 *PathName = NULL; - efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image, - &IMAGE_PROTOCOL, &li); + efi_status = BS->HandleProtocol(image, &IMAGE_PROTOCOL, (VOID **)&li); if (efi_status != EFI_SUCCESS) return simple_file_open_by_handle(image, name, file, mode); @@ -87,8 +85,7 @@ UINTN size = sizeof(buf); EFI_FILE_INFO *fi = (void *)buf; - status = uefi_call_wrapper(file->GetInfo, 4, file, &FILE_INFO, - &size, fi); + status = file->GetInfo(file, &FILE_INFO, &size, fi); if (status != EFI_SUCCESS) { Print(L"Failed to get file info\n"); goto out; @@ -102,13 +99,13 @@ *count = 0; for (;;) { UINTN len = sizeof(buf); - status = uefi_call_wrapper(file->Read, 3, file, &len, buf); + status = file->Read(file, &len, buf); if (status != EFI_SUCCESS || len == 0) break; (*count)++; size += len; } - uefi_call_wrapper(file->SetPosition, 2, file, 0); + file->SetPosition(file, 0); char *ptr = AllocatePool(size); *entries = (EFI_FILE_INFO *)ptr; @@ -116,8 +113,8 @@ return EFI_OUT_OF_RESOURCES; int i; for (i = 0; i < *count; i++) { - int len = size; - uefi_call_wrapper(file->Read, 3, file, &len, ptr); + UINTN len = size; + file->Read(file, &len, ptr); ptr += len; size -= len; } @@ -158,8 +155,7 @@ fi = (void *)buf; - efi_status = uefi_call_wrapper(file->GetInfo, 4, file, &FILE_INFO, - size, fi); + efi_status = file->GetInfo(file, &FILE_INFO, size, fi); if (efi_status != EFI_SUCCESS) { Print(L"Failed to get file info\n"); return efi_status; @@ -167,12 +163,13 @@ *size = fi->FileSize; - *buffer = AllocatePool(*size); + /* might use memory mapped, so align up to nearest page */ + *buffer = AllocateZeroPool(ALIGN_VALUE(*size, 4096)); if (!*buffer) { Print(L"Failed to allocate buffer of size %d\n", *size); return EFI_OUT_OF_RESOURCES; } - efi_status = uefi_call_wrapper(file->Read, 3, file, size, *buffer); + efi_status = file->Read(file, size, *buffer); return efi_status; } @@ -183,7 +180,7 @@ { EFI_STATUS efi_status; - efi_status = uefi_call_wrapper(file->Write, 3, file, &size, buffer); + efi_status = file->Write(file, &size, buffer); return efi_status; } @@ -191,7 +188,7 @@ void simple_file_close(EFI_FILE *file) { - uefi_call_wrapper(file->Close, 1, file); + file->Close(file); } EFI_STATUS @@ -203,8 +200,8 @@ CHAR16 **entries; int val; - uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, - &SIMPLE_FS_PROTOCOL, NULL, &count, &vol_handles); + BS->LocateHandleBuffer(ByProtocol, &SIMPLE_FS_PROTOCOL, NULL, + &count, &vol_handles); if (!count || !vol_handles) return EFI_NOT_FOUND; @@ -221,18 +218,17 @@ CHAR16 *name; EFI_FILE_IO_INTERFACE *drive; - status = uefi_call_wrapper(BS->HandleProtocol, 3, - vol_handles[i], - &SIMPLE_FS_PROTOCOL, &drive); + status = BS->HandleProtocol(vol_handles[i], + &SIMPLE_FS_PROTOCOL, + (VOID **)&drive); if (status != EFI_SUCCESS || !drive) continue; - status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root); + status = drive->OpenVolume(drive, &root); if (status != EFI_SUCCESS) continue; - status = uefi_call_wrapper(root->GetInfo, 4, root, &FS_INFO, - &size, fi); + status = root->GetInfo(root, &FS_INFO, &size, fi); if (status != EFI_SUCCESS) continue; diff -Nru efitools-1.4.2/lib/variables.c efitools-1.8.1/lib/variables.c --- efitools-1.4.2/lib/variables.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/lib/variables.c 2018-02-21 03:53:05.000000000 +0000 @@ -30,6 +30,7 @@ #include <sha256.h> #include <errors.h> + EFI_STATUS variable_create_esl(void *cert, int cert_len, EFI_GUID *type, EFI_GUID *owner, void **out, int *outlen) @@ -99,7 +100,7 @@ DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData); ZeroMem (&Time, sizeof (EFI_TIME)); - Status = uefi_call_wrapper(RT->GetTime,2, &Time, NULL); + Status = RT->GetTime(&Time, NULL); if (EFI_ERROR (Status)) { FreePool(NewData); return Status; @@ -164,13 +165,13 @@ return efi_status; } - efi_status = uefi_call_wrapper(RT->SetVariable, 5, var, &owner, - EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_RUNTIME_ACCESS - | EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS - | options, - DataSize, Cert); + efi_status = RT->SetVariable(var, &owner, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS + | options, + DataSize, Cert); return efi_status; } @@ -182,7 +183,7 @@ UINTN DataSize = sizeof(indications); EFI_STATUS efi_status; - efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"OsIndicationsSupported", &GV_GUID, NULL, &DataSize, &indications); + efi_status = RT->GetVariable(L"OsIndicationsSupported", &GV_GUID, NULL, &DataSize, &indications); if (efi_status != EFI_SUCCESS) return 0; @@ -195,17 +196,17 @@ UINTN DataSize = sizeof(indications); EFI_STATUS efi_status; - efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"OsIndications", - &GV_GUID, - EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_RUNTIME_ACCESS - | EFI_VARIABLE_BOOTSERVICE_ACCESS, - DataSize, &indications); + efi_status = RT->SetVariable(L"OsIndications", + &GV_GUID, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS, + DataSize, &indications); if (efi_status != EFI_SUCCESS) return efi_status; - uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0, NULL); + RT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL); /* does not return */ return EFI_SUCCESS; @@ -219,8 +220,7 @@ *len = 0; - efi_status = uefi_call_wrapper(RT->GetVariable, 5, var, &owner, - NULL, len, NULL); + efi_status = RT->GetVariable(var, &owner, NULL, len, NULL); if (efi_status != EFI_BUFFER_TOO_SMALL) return efi_status; @@ -228,8 +228,7 @@ if (!data) return EFI_OUT_OF_RESOURCES; - efi_status = uefi_call_wrapper(RT->GetVariable, 5, var, &owner, - attributes, len, *data); + efi_status = RT->GetVariable(var, &owner, attributes, len, *data); if (efi_status != EFI_SUCCESS) { FreePool(*data); @@ -280,14 +279,61 @@ } int +hashes_in_esl(UINT8 *Data, UINTN DataSize, EFI_GUID *hashes[]) +{ + int count = 0; + EFI_SIGNATURE_LIST *CertList; + + certlist_for_each_certentry(CertList, Data, DataSize, DataSize) { + int i; + + for (i = 0; i < count; i++) { + if (CompareGuid(&CertList->SignatureType, hashes[i]) == 0) + goto found_skip; + } + + for (i = 0; i < allowed_hashes_size; i++) { + if (CompareGuid(&CertList->SignatureType, allowed_hashes[i]) == 0) + goto found; + } + found_skip: + continue; + + found: + hashes[count++] = allowed_hashes[i]; + } + return count; +} + +int +hashes_in_variable(CHAR16* var, EFI_GUID owner, EFI_GUID *hashes[]) +{ + UINTN DataSize; + UINT8 *Data; + EFI_STATUS status; + int count; + + status = get_variable(var, &Data, &DataSize, owner); + if (status == EFI_NOT_FOUND) + return 0; + if (status != EFI_SUCCESS) + return -1; + + count = hashes_in_esl(Data, DataSize, hashes); + + FreePool(Data); + + return count; +} + +int variable_is_setupmode(void) { /* set to 1 because we return true if SetupMode doesn't exist */ UINT8 SetupMode = 1; UINTN DataSize = sizeof(SetupMode); - uefi_call_wrapper(RT->GetVariable, 5, L"SetupMode", &GV_GUID, NULL, - &DataSize, &SetupMode); + RT->GetVariable(L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode); return SetupMode; } @@ -300,8 +346,7 @@ UINTN DataSize; DataSize = sizeof(SecureBoot); - uefi_call_wrapper(RT->GetVariable, 5, L"SecureBoot", &GV_GUID, NULL, - &DataSize, &SecureBoot); + RT->GetVariable(L"SecureBoot", &GV_GUID, NULL, &DataSize, &SecureBoot); return SecureBoot; } @@ -331,10 +376,10 @@ status = SetSecureVariable(var, sig, sizeof(sig), owner, EFI_VARIABLE_APPEND_WRITE, 0); else - status = uefi_call_wrapper(RT->SetVariable, 5, var, &owner, - EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_APPEND_WRITE, - sizeof(sig), sig); + status = RT->SetVariable(var, &owner, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_APPEND_WRITE, + sizeof(sig), sig); return status; } diff -Nru efitools-1.4.2/Loader.c efitools-1.8.1/Loader.c --- efitools-1.4.2/Loader.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/Loader.c 2018-02-21 03:53:05.000000000 +0000 @@ -16,6 +16,7 @@ #include <console.h> #include <efiauthenticated.h> #include <guid.h> +#include <execute.h> CHAR16 *loader = L"\\linux-loader.efi"; @@ -65,7 +66,7 @@ InitializeLib(image, systab); - efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"SecureBoot", &GV_GUID, NULL, &DataSize, &SecureBoot); + efi_status = RT->GetVariable(L"SecureBoot", &GV_GUID, NULL, &DataSize, &SecureBoot); if (efi_status != EFI_SUCCESS) { Print(L"Not a Secure Boot Platform %d\n", efi_status); @@ -74,10 +75,9 @@ DataSize = sizeof(SetupMode); } - uefi_call_wrapper(RT->GetVariable, 5, L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode); + RT->GetVariable(L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode); - efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image, - &IMAGE_PROTOCOL, &li); + efi_status = BS->HandleProtocol(image, &IMAGE_PROTOCOL, (VOID **)&li); if (efi_status != EFI_SUCCESS) { Print(L"Failed to init loaded image protocol: %d\n", efi_status); return efi_status; @@ -91,13 +91,13 @@ } if (!SetupMode) { - efi_status = uefi_call_wrapper(BS->LoadImage, 6, FALSE, image, - loadpath, NULL, 0, &loader_handle); + efi_status = BS->LoadImage(FALSE, image, loadpath, NULL, + 0, &loader_handle); if (efi_status == EFI_SUCCESS) { /* Image validates - start it */ Print(L"Starting file via StartImage\n"); - uefi_call_wrapper(BS->StartImage, 3, loader_handle, NULL, NULL); - uefi_call_wrapper(BS->UnloadImage, 1, loader_handle); + BS->StartImage(loader_handle, NULL, NULL); + BS->UnloadImage(loader_handle); return EFI_SUCCESS; } else { Print(L"Failed to load the image: %d\n", efi_status); diff -Nru efitools-1.4.2/LockDown.c efitools-1.8.1/LockDown.c --- efitools-1.4.2/LockDown.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/LockDown.c 2018-02-21 03:53:05.000000000 +0000 @@ -22,7 +22,7 @@ InitializeLib(image, systab); - efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode); + efi_status = RT->GetVariable(L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode); if (efi_status != EFI_SUCCESS) { Print(L"No SetupMode variable ... is platform secure boot enabled?\n"); @@ -36,23 +36,23 @@ Print(L"Platform is in Setup Mode\n"); - efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"KEK", &GV_GUID, - EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_RUNTIME_ACCESS - | EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, - KEK_auth_len, KEK_auth); + efi_status = RT->SetVariable(L"KEK", &GV_GUID, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, + KEK_auth_len, KEK_auth); if (efi_status != EFI_SUCCESS) { Print(L"Failed to enroll KEK: %d\n", efi_status); return efi_status; } Print(L"Created KEK Cert\n"); - efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"db", &SIG_DB, - EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_RUNTIME_ACCESS - | EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, - DB_auth_len, DB_auth); + efi_status = RT->SetVariable(L"db", &SIG_DB, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, + DB_auth_len, DB_auth); if (efi_status != EFI_SUCCESS) { Print(L"Failed to enroll db: %d\n", efi_status); return efi_status; @@ -68,12 +68,12 @@ } #endif /* PK must be updated with a signed copy of itself */ - efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"PK", &GV_GUID, - EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_RUNTIME_ACCESS - | EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, - PK_auth_len, PK_auth); + efi_status = RT->SetVariable(L"PK", &GV_GUID, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, + PK_auth_len, PK_auth); if (efi_status != EFI_SUCCESS) { @@ -82,7 +82,7 @@ } Print(L"Created PK Cert\n"); /* enrolling the PK should put us in SetupMode; check this */ - efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode); + efi_status = RT->GetVariable(L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode); if (efi_status != EFI_SUCCESS) { Print(L"Failed to get SetupMode variable: %d\n", efi_status); return efi_status; @@ -91,7 +91,7 @@ /* finally, check that SecureBoot is enabled */ - efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"SecureBoot", &GV_GUID, NULL, &DataSize, &SecureBoot); + efi_status = RT->GetVariable(L"SecureBoot", &GV_GUID, NULL, &DataSize, &SecureBoot); if (efi_status != EFI_SUCCESS) { Print(L"Failed to get SecureBoot variable: %d\n", efi_status); diff -Nru efitools-1.4.2/Makefile efitools-1.8.1/Makefile --- efitools-1.4.2/Makefile 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/Makefile 2018-02-21 03:53:05.000000000 +0000 @@ -1,7 +1,25 @@ EFIFILES = HelloWorld.efi LockDown.efi Loader.efi ReadVars.efi UpdateVars.efi \ - KeyTool.efi HashTool.efi PreLoader.efi SetNull.efi + KeyTool.efi HashTool.efi SetNull.efi ShimReplace.efi BINARIES = cert-to-efi-sig-list sig-list-to-certs sign-efi-sig-list \ - hash-to-efi-sig-list efi-readvar efi-updatevar + hash-to-efi-sig-list efi-readvar efi-updatevar cert-to-efi-hash-list \ + flash-var + +ifeq ($(ARCH),x86_64) +EFIFILES += PreLoader.efi +endif + +MSGUID = 77FA9ABD-0359-4D32-BD60-28F4E78F784B + +KEYS = PK KEK DB +EXTRAKEYS = DB1 DB2 +EXTERNALKEYS = ms-uefi ms-kek + +ALLKEYS = $(KEYS) $(EXTRAKEYS) $(EXTERNALKEYS) + +KEYAUTH = $(ALLKEYS:=.auth) +KEYUPDATEAUTH = $(ALLKEYS:=-update.auth) $(ALLKEYS:=-pkupdate.auth) +KEYBLACKLISTAUTH = $(ALLKEYS:=-blacklist.auth) +KEYHASHBLACKLISTAUTH = $(ALLKEYS:=-hash-blacklist.auth) export TOPDIR := $(shell pwd)/ @@ -9,7 +27,9 @@ EFISIGNED = $(patsubst %.efi,%-signed.efi,$(EFIFILES)) -all: $(EFISIGNED) $(BINARIES) $(MANPAGES) noPK.auth +all: $(EFISIGNED) $(BINARIES) $(MANPAGES) noPK.auth $(KEYAUTH) \ + $(KEYUPDATEAUTH) $(KEYBLACKLISTAUTH) $(KEYHASHBLACKLISTAUTH) + install: all $(INSTALL) -m 755 -d $(MANDIR) @@ -30,9 +50,6 @@ .SUFFIXES: .crt -PK.crt KEK.crt DB.crt: - openssl req -new -x509 -newkey rsa:2048 -subj "/CN=$*/" -keyout $*.key -out $@ -days 3650 -nodes -sha256 - .KEEP: PK.crt KEK.crt DB.crt PK.key KEK.key DB.key PK.esl DB.esl KEK.esl \ $(EFIFILES) @@ -49,16 +66,10 @@ > noPK.esl noPK.auth: noPK.esl PK.crt sign-efi-sig-list - ./sign-efi-sig-list -c PK.crt -k PK.key PK $< $@ - -PK.auth: PK.esl PK.crt sign-efi-sig-list - ./sign-efi-sig-list -c PK.crt -k PK.key PK $< $@ - -KEK.auth: KEK.esl PK.crt sign-efi-sig-list - ./sign-efi-sig-list -c PK.crt -k PK.key KEK $< $@ + ./sign-efi-sig-list -t "$(shell date --date='1 second' +'%Y-%m-%d %H:%M:%S')" -c PK.crt -k PK.key PK $< $@ -DB.auth: DB.esl KEK.crt sign-efi-sig-list - ./sign-efi-sig-list -c KEK.crt -k KEK.key db $< $@ +ms-%.esl: ms-%.crt cert-to-efi-sig-list + ./cert-to-efi-sig-list -g $(MSGUID) $< $@ hashlist.h: HashTool.hash cat $^ > /tmp/tmp.hash @@ -74,32 +85,41 @@ HashTool.so: lib/lib-efi.a PreLoader.so: lib/lib-efi.a HelloWorld.so: lib/lib-efi.a +ShimReplace.so: lib/lib-efi.a cert-to-efi-sig-list: cert-to-efi-sig-list.o lib/lib.a - $(CC) -o $@ $< -lcrypto lib/lib.a + $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a sig-list-to-certs: sig-list-to-certs.o lib/lib.a - $(CC) -o $@ $< -lcrypto lib/lib.a + $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a sign-efi-sig-list: sign-efi-sig-list.o lib/lib.a - $(CC) -o $@ $< -lcrypto lib/lib.a + $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a hash-to-efi-sig-list: hash-to-efi-sig-list.o lib/lib.a - $(CC) -o $@ $< lib/lib.a + $(CC) $(ARCH3264) -o $@ $< lib/lib.a + +cert-to-efi-hash-list: cert-to-efi-hash-list.o lib/lib.a + $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a efi-keytool: efi-keytool.o lib/lib.a - $(CC) -o $@ $< lib/lib.a + $(CC) $(ARCH3264) -o $@ $< lib/lib.a efi-readvar: efi-readvar.o lib/lib.a - $(CC) -o $@ $< -lcrypto lib/lib.a + $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a efi-updatevar: efi-updatevar.o lib/lib.a - $(CC) -o $@ $< -lcrypto lib/lib.a + $(CC) $(ARCH3264) -o $@ $< -lcrypto lib/lib.a + +flash-var: flash-var.o lib/lib.a + $(CC) $(ARCH3264) -o $@ $< lib/lib.a clean: rm -f PK.* KEK.* DB.* $(EFIFILES) $(EFISIGNED) $(BINARIES) *.o *.so + rm -f noPK.* rm -f doc/*.1 $(MAKE) -C lib clean + $(MAKE) -C lib/asn1 clean FORCE: diff -Nru efitools-1.4.2/Make.rules efitools-1.8.1/Make.rules --- efitools-1.4.2/Make.rules 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/Make.rules 2018-02-21 03:53:05.000000000 +0000 @@ -1,21 +1,32 @@ EFISIGNED = $(patsubst %.efi,%-signed.efi,$(EFIFILES)) MANPAGES = $(patsubst doc/%.1.in,doc/%.1,$(wildcard doc/*.1.in)) HELP2MAN = help2man -ARCH = $(shell uname -m) +ARCH = $(shell uname -m | sed 's/i.86/ia32/;s/arm.*/arm/') +ifeq ($(ARCH),ia32) +ARCH3264 = -m32 +else ifeq ($(ARCH),x86_64) +ARCH3264 = +else ifeq ($(ARCH),aarch64) +ARCH3264 = +else ifeq ($(ARCH),arm) +ARCH3264 = +else +$(error unknown architecture $(ARCH)) +endif INCDIR = -I$(TOPDIR)include/ -I/usr/include/efi -I/usr/include/efi/$(ARCH) -I/usr/include/efi/protocol CPPFLAGS = -DCONFIG_$(ARCH) -CFLAGS = -O2 -fpic -Wall -fshort-wchar -fno-strict-aliasing -fno-merge-constants -mno-red-zone -fno-stack-protector -g +CFLAGS = -O2 -g $(ARCH3264) -fpic -Wall -fshort-wchar -fno-strict-aliasing -fno-merge-constants -fno-stack-protector -ffreestanding -fno-stack-check LDFLAGS = -nostdlib CRTOBJ = crt0-efi-$(ARCH).o -CRTPATHS = /lib /lib64 /lib/efi /lib64/efi /usr/lib /usr/lib64 /usr/lib/efi /usr/lib64/efi +CRTPATHS = /lib /lib64 /lib/efi /lib64/efi /usr/lib /usr/lib64 /usr/lib/efi /usr/lib64/efi /usr/lib/gnuefi /usr/lib64/gnuefi CRTPATH = $(shell for f in $(CRTPATHS); do if [ -e $$f/$(CRTOBJ) ]; then echo $$f; break; fi; done) CRTOBJS = $(CRTPATH)/$(CRTOBJ) # there's a bug in the gnu tools ... the .reloc section has to be # aligned otherwise the file alignment gets screwed up -LDSCRIPT = $(TOPDIR)/elf_$(ARCH)_efi.lds -LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic $(CRTOBJS) -L $(CRTPATH) -LOADLIBES = -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name) -FORMAT = efi-app-$(ARCH) +LDSCRIPT = elf_$(ARCH)_efi.lds +LDFLAGS += -shared -Bsymbolic $(CRTOBJS) -L $(CRTPATH) -L /usr/lib -L /usr/lib64 -T $(LDSCRIPT) +LOADLIBES = -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name) +FORMAT = --target=efi-app-$(ARCH) OBJCOPY = objcopy MYGUID = 11111111-2222-3333-4444-123456789abc INSTALL = install @@ -24,14 +35,31 @@ EFIDIR = $(DESTDIR)/usr/share/efitools/efi DOCDIR = $(DESTDIR)/usr/share/efitools +# globally use EFI calling conventions (requires gcc >= 4.7) +CFLAGS += -DGNU_EFI_USE_MS_ABI + ifeq ($(ARCH),x86_64) - CFLAGS += -DEFI_FUNCTION_WRAPPER + CFLAGS += -DEFI_FUNCTION_WRAPPER -mno-red-zone endif -%.efi: %.so - $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ - -j .rela -j .reloc --target=$(FORMAT) $*.so $@ +ifeq ($(ARCH),ia32) + CFLAGS += -mno-red-zone +endif +ifeq ($(ARCH),arm) + LDFLAGS += --defsym=EFI_SUBSYSTEM=0x0a + FORMAT = -O binary +endif + +ifeq ($(ARCH),aarch64) + LDFLAGS += --defsym=EFI_SUBSYSTEM=0x0a + FORMAT = -O binary +endif + +%.efi: %.so + $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym \ + -j .rel -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ + -j .reloc $(FORMAT) $*.so $@ %.so: %.o $(LD) $(LDFLAGS) $^ -o $@ $(LOADLIBES) # check we have no undefined symbols @@ -43,9 +71,33 @@ %.hash: %.efi hash-to-efi-sig-list ./hash-to-efi-sig-list $< $@ +%-blacklist.esl: %.crt cert-to-efi-hash-list + ./cert-to-efi-sig-list $< $@ + +%-hash-blacklist.esl: %.crt cert-to-efi-hash-list + ./cert-to-efi-hash-list $< $@ + %.esl: %.crt cert-to-efi-sig-list ./cert-to-efi-sig-list -g $(MYGUID) $< $@ +getcert = $(shell if [ "$(1)" = "PK" -o "$(1)" = "KEK" ]; then echo "-c PK.crt -k PK.key"; else echo "-c KEK.crt -k KEK.key"; fi) +getvar = $(shell if [ "$(1)" = "PK" -o "$(1)" = "KEK" ]; then echo $(1); else echo db; fi) + +%.auth: %.esl PK.crt KEK.crt sign-efi-sig-list + ./sign-efi-sig-list $(call getcert,$*) $(call getvar,$*) $< $@ + +%-update.auth: %.esl PK.crt KEK.crt sign-efi-sig-list + ./sign-efi-sig-list -a $(call getcert,$*) $(call getvar,$*) $< $@ + +%-pkupdate.auth: %.esl PK.crt sign-efi-sig-list + ./sign-efi-sig-list -a -c PK.crt -k PK.key $(call getvar,$*) $< $@ + +%-blacklist.auth: %-blacklist.esl KEK.crt sign-efi-sig-list + ./sign-efi-sig-list -a -c KEK.crt -k KEK.key dbx $< $@ + +%-pkblacklist.auth: %-blacklist.esl PK.crt sign-efi-sig-list + ./sign-efi-sig-list -a -c PK.crt -k PK.key dbx $< $@ + %.o: %.c $(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ @@ -55,6 +107,8 @@ %.efi.s: %.c $(CC) -S $(INCDIR) $(CFLAGS) $(CPPFLAGS) -fno-toplevel-reorder -DBUILD_EFI -c $< -o $@ +%.crt: + openssl req -new -x509 -newkey rsa:2048 -subj "/CN=$*/" -keyout $*.key -out $@ -days 3650 -nodes -sha256 %.cer: %.crt openssl x509 -in $< -out $@ -outform DER diff -Nru efitools-1.4.2/ms-kek.crt efitools-1.8.1/ms-kek.crt --- efitools-1.4.2/ms-kek.crt 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/ms-kek.crt 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,121 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 61:0a:d1:88:00:00:00:00:00:03 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation Third Party Marketplace Root + Validity + Not Before: Jun 24 20:41:29 2011 GMT + Not After : Jun 24 20:51:29 2026 GMT + Subject: C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation KEK CA 2011 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c4:e8:b5:8a:bf:ad:57:26:b0:26:c3:ea:e7:fb: + 57:7a:44:02:5d:07:0d:da:4a:e5:74:2a:e6:b0:0f: + ec:6d:eb:ec:7f:b9:e3:5a:63:32:7c:11:17:4f:0e: + e3:0b:a7:38:15:93:8e:c6:f5:e0:84:b1:9a:9b:2c: + e7:f5:b7:91:d6:09:e1:e2:c0:04:a8:ac:30:1c:df: + 48:f3:06:50:9a:64:a7:51:7f:c8:85:4f:8f:20:86: + ce:fe:2f:e1:9f:ff:82:c0:ed:e9:cd:ce:f4:53:6a: + 62:3a:0b:43:b9:e2:25:fd:fe:05:f9:d4:c4:14:ab: + 11:e2:23:89:8d:70:b7:a4:1d:4d:ec:ae:e5:9c:fa: + 16:c2:d7:c1:cb:d4:e8:c4:2f:e5:99:ee:24:8b:03: + ec:8d:f2:8b:ea:c3:4a:fb:43:11:12:0b:7e:b5:47: + 92:6c:dc:e6:04:89:eb:f5:33:04:eb:10:01:2a:71: + e5:f9:83:13:3c:ff:25:09:2f:68:76:46:ff:ba:4f: + be:dc:ad:71:2a:58:aa:fb:0e:d2:79:3d:e4:9b:65: + 3b:cc:29:2a:9f:fc:72:59:a2:eb:ae:92:ef:f6:35: + 13:80:c6:02:ec:e4:5f:cc:9d:76:cd:ef:63:92:c1: + af:79:40:84:79:87:7f:e3:52:a8:e8:9d:7b:07:69: + 8f:15 + Exponent: 65537 (0x10001) + X509v3 extensions: + 1.3.6.1.4.1.311.21.1: + ... + X509v3 Subject Key Identifier: + 62:FC:43:CD:A0:3E:A4:CB:67:12:D2:5B:D9:55:AC:7B:CC:B6:8A:5F + 1.3.6.1.4.1.311.20.2: + . +.S.u.b.C.A + X509v3 Key Usage: + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:45:66:52:43:E1:7E:58:11:BF:D6:4E:9E:23:55:08:3B:3A:22:6A:A8 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl + + Authority Information Access: + CA Issuers - URI:http://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt + + Signature Algorithm: sha256WithRSAEncryption + d4:84:88:f5:14:94:18:02:ca:2a:3c:fb:2a:92:1c:0c:d7:a0: + d1:f1:e8:52:66:a8:ee:a2:b5:75:7a:90:00:aa:2d:a4:76:5a: + ea:79:b7:b9:37:6a:51:7b:10:64:f6:e1:64:f2:02:67:be:f7: + a8:1b:78:bd:ba:ce:88:58:64:0c:d6:57:c8:19:a3:5f:05:d6: + db:c6:d0:69:ce:48:4b:32:b7:eb:5d:d2:30:f5:c0:f5:b8:ba: + 78:07:a3:2b:fe:9b:db:34:56:84:ec:82:ca:ae:41:25:70:9c: + 6b:e9:fe:90:0f:d7:96:1f:e5:e7:94:1f:b2:2a:0c:8d:4b:ff: + 28:29:10:7b:f7:d7:7c:a5:d1:76:b9:05:c8:79:ed:0f:90:92: + 9c:c2:fe:df:6f:7e:6c:0f:7b:d4:c1:45:dd:34:51:96:39:0f: + e5:5e:56:d8:18:05:96:f4:07:a6:42:b3:a0:77:fd:08:19:f2: + 71:56:cc:9f:86:23:a4:87:cb:a6:fd:58:7e:d4:69:67:15:91: + 7e:81:f2:7f:13:e5:0d:8b:8a:3c:87:84:eb:e3:ce:bd:43:e5: + ad:2d:84:93:8e:6a:2b:5a:7c:44:fa:52:aa:81:c8:2d:1c:bb: + e0:52:df:00:11:f8:9a:3d:c1:60:b0:e1:33:b5:a3:88:d1:65: + 19:0a:1a:e7:ac:7c:a4:c1:82:87:4e:38:b1:2f:0d:c5:14:87: + 6f:fd:8d:2e:bc:39:b6:e7:e6:c3:e0:e4:cd:27:84:ef:94:42: + ef:29:8b:90:46:41:3b:81:1b:67:d8:f9:43:59:65:cb:0d:bc: + fd:00:92:4f:f4:75:3b:a7:a9:24:fc:50:41:40:79:e0:2d:4f: + 0a:6a:27:76:6e:52:ed:96:69:7b:af:0f:f7:87:05:d0:45:c2: + ad:53:14:81:1f:fb:30:04:aa:37:36:61:da:4a:69:1b:34:d8: + 68:ed:d6:02:cf:6c:94:0c:d3:cf:6c:22:79:ad:b1:f0:bc:03: + a2:46:60:a9:c4:07:c2:21:82:f1:fd:f2:e8:79:32:60:bf:d8: + ac:a5:22:14:4b:ca:c1:d8:4b:eb:7d:3f:57:35:b2:e6:4f:75: + b4:b0:60:03:22:53:ae:91:79:1d:d6:9b:41:1f:15:86:54:70: + b2:de:0d:35:0f:7c:b0:34:72:ba:97:60:3b:f0:79:eb:a2:b2: + 1c:5d:a2:16:b8:87:c5:e9:1b:f6:b5:97:25:6f:38:9f:e3:91: + fa:8a:79:98:c3:69:0e:b7:a3:1c:20:05:97:f8:ca:14:ae:00: + d7:c4:f3:c0:14:10:75:6b:34:a0:1b:b5:99:60:f3:5c:b0:c5: + 57:4e:36:d2:32:84:bf:9e +-----BEGIN CERTIFICATE----- +MIIF6DCCA9CgAwIBAgIKYQrRiAAAAAAAAzANBgkqhkiG9w0BAQsFADCBkTELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx +HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE7MDkGA1UEAxMyTWljcm9z +b2Z0IENvcnBvcmF0aW9uIFRoaXJkIFBhcnR5IE1hcmtldHBsYWNlIFJvb3QwHhcN +MTEwNjI0MjA0MTI5WhcNMjYwNjI0MjA1MTI5WjCBgDELMAkGA1UEBhMCVVMxEzAR +BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p +Y3Jvc29mdCBDb3Jwb3JhdGlvbjEqMCgGA1UEAxMhTWljcm9zb2Z0IENvcnBvcmF0 +aW9uIEtFSyBDQSAyMDExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +xOi1ir+tVyawJsPq5/tXekQCXQcN2krldCrmsA/sbevsf7njWmMyfBEXTw7jC6c4 +FZOOxvXghLGamyzn9beR1gnh4sAEqKwwHN9I8wZQmmSnUX/IhU+PIIbO/i/hn/+C +wO3pzc70U2piOgtDueIl/f4F+dTEFKsR4iOJjXC3pB1N7K7lnPoWwtfBy9ToxC/l +me4kiwPsjfKL6sNK+0MREgt+tUeSbNzmBInr9TME6xABKnHl+YMTPP8lCS9odkb/ +uk++3K1xKliq+w7SeT3km2U7zCkqn/xyWaLrrpLv9jUTgMYC7ORfzJ12ze9jksGv +eUCEeYd/41Ko6J17B2mPFQIDAQABo4IBTzCCAUswEAYJKwYBBAGCNxUBBAMCAQAw +HQYDVR0OBBYEFGL8Q82gPqTLZxLSW9lVrHvMtopfMBkGCSsGAQQBgjcUAgQMHgoA +UwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQY +MBaAFEVmUkPhflgRv9ZOniNVCDs6ImqoMFwGA1UdHwRVMFMwUaBPoE2GS2h0dHA6 +Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY0NvclRoaVBh +ck1hclJvb18yMDEwLTEwLTA1LmNybDBgBggrBgEFBQcBAQRUMFIwUAYIKwYBBQUH +MAKGRGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljQ29yVGhp +UGFyTWFyUm9vXzIwMTAtMTAtMDUuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQDUhIj1 +FJQYAsoqPPsqkhwM16DR8ehSZqjuorV1epAAqi2kdlrqebe5N2pRexBk9uFk8gJn +vveoG3i9us6IWGQM1lfIGaNfBdbbxtBpzkhLMrfrXdIw9cD1uLp4B6Mr/pvbNFaE +7ILKrkElcJxr6f6QD9eWH+XnlB+yKgyNS/8oKRB799d8pdF2uQXIee0PkJKcwv7f +b35sD3vUwUXdNFGWOQ/lXlbYGAWW9AemQrOgd/0IGfJxVsyfhiOkh8um/Vh+1Gln +FZF+gfJ/E+UNi4o8h4Tr4869Q+WtLYSTjmorWnxE+lKqgcgtHLvgUt8AEfiaPcFg +sOEztaOI0WUZChrnrHykwYKHTjixLw3FFIdv/Y0uvDm25+bD4OTNJ4TvlELvKYuQ +RkE7gRtn2PlDWWXLDbz9AJJP9HU7p6kk/FBBQHngLU8Kaid2blLtlml7rw/3hwXQ +RcKtUxSBH/swBKo3NmHaSmkbNNho7dYCz2yUDNPPbCJ5rbHwvAOiRmCpxAfCIYLx +/fLoeTJgv9ispSIUS8rB2EvrfT9XNbLmT3W0sGADIlOukXkd1ptBHxWGVHCy3g01 +D3ywNHK6l2A78HnrorIcXaIWuIfF6Rv2tZclbzif45H6inmYw2kOt6McIAWX+MoU +rgDXxPPAFBB1azSgG7WZYPNcsMVXTjbSMoS/ng== +-----END CERTIFICATE----- diff -Nru efitools-1.4.2/ms-uefi.crt efitools-1.8.1/ms-uefi.crt --- efitools-1.4.2/ms-uefi.crt 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/ms-uefi.crt 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIGEDCCA/igAwIBAgIKYQjTxAAAAAAABDANBgkqhkiG9w0BAQsFADCBkTELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx +HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE7MDkGA1UEAxMyTWljcm9z +b2Z0IENvcnBvcmF0aW9uIFRoaXJkIFBhcnR5IE1hcmtldHBsYWNlIFJvb3QwHhcN +MTEwNjI3MjEyMjQ1WhcNMjYwNjI3MjEzMjQ1WjCBgTELMAkGA1UEBhMCVVMxEzAR +BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p +Y3Jvc29mdCBDb3Jwb3JhdGlvbjErMCkGA1UEAxMiTWljcm9zb2Z0IENvcnBvcmF0 +aW9uIFVFRkkgQ0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKUIbEzHRQlqSwykwId/BnUMQwFUZOAWfwftkn0LsnO/DArGSkVhoMUWLZbT9Sug ++01Jm0GAkDy5VP3mvNGdxKQYin9BilxZg2gyu4xHye5xvCFPmop8/0Q/jY8ysiZI +rnW17slMHkoZfuSCmh14d00MsL32D9MW07z6K6VROF31+7rbeALb/+wKG5bVg7gZ +E+m2wHtAe+EfKCfJ+u9WXhzmfpR+wPBEsnk55dqyYotNvzhw4mgkFMkzpAg31Vhp +XtN87cEEUwjnTrAqh2MIYW9jFVnqsit51wxhZ4pb/V6th3+6hmdPcVgSIgQiIs6L +71RxAM5QNVh2lQjuarGiAdUCAwEAAaOCAXYwggFyMBIGCSsGAQQBgjcVAQQFAgMB +AAEwIwYJKwYBBAGCNxUCBBYEFPjBa7d/d1NK8yU3HU6hJnsPIHCAMB0GA1UdDgQW +BBQTrb9DCb2CcJyM1U8xbtUimIob1DAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMA +QTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRFZlJD +4X5YEb/WTp4jVQg7OiJqqDBcBgNVHR8EVTBTMFGgT6BNhktodHRwOi8vY3JsLm1p +Y3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNDb3JUaGlQYXJNYXJSb29f +MjAxMC0xMC0wNS5jcmwwYAYIKwYBBQUHAQEEVDBSMFAGCCsGAQUFBzAChkRodHRw +Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY0NvclRoaVBhck1hclJv +b18yMDEwLTEwLTA1LmNydDANBgkqhkiG9w0BAQsFAAOCAgEANQhC/zDMzvd2DK0Q +aFg1KUYydid87xJBJ0IbSqptgThIWRNV8+lYNKYWC4KqXa2C2oCDQQaPtB3yA7nz +Gl0b8VCQ+bNVhEIoHCC9sq5RFMXArJeVIRyQ2w/8d56Vc5GIyr29UrkFUA3fV56g +Ye0N5W0l2UAPF0DIzqNKwk2vmhIdCFSPvce8uSs9SSsfMvxqIWlPm8h+QjT8NgYX +i48gQMCzmiV1J83JA6P2XdHnNlR6uVC10xLRB7+7dN/cHo+A1e0Y9C8UFmsv3maM +sCPlx4TY7erBM4KtVksYLfFolQfNz/By8K673YaFmCwhTDMr8A9K8GiHtZJVMnWh +aoJqPKMlEaTtrdcErsvYQFmghNGVTGKRIhp0HYw9Rw5EpuSwmzQ1sfq2U6gsgeyk +BXHInbi66BtEZuRHVA6OVn+znxaYsobQaD6QI7UvXo9QhY3GjYJfQaH0Lg3gmdJs +deS2abUhhvoH0fbiTdHarSx3Ux4lMjfHbFJylYaw8TVhahn1sjuBUFamMi3+oon5 +QoYnGFWhgspam/gwmFQUpkeWJS/IJuRBlBpcAj/lluOFWzw+P7tHFnJV4iUisdl7 +5wMGKqP3HpBGwwAN1hmJ4w41J2IDcRWm79AnoKBZN2D4OJS44Hhw+LpMhoeU9uCu +AkXuZcK2o35pFnUHkpv1prxZg1g= +-----END CERTIFICATE----- diff -Nru efitools-1.4.2/PreLoader.c efitools-1.8.1/PreLoader.c --- efitools-1.4.2/PreLoader.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/PreLoader.c 2018-02-21 03:53:05.000000000 +0000 @@ -30,8 +30,8 @@ console_reset(); - status = uefi_call_wrapper(RT->GetVariable, 5, L"SecureBoot", - &GV_GUID, NULL, &DataSize, &SecureBoot); + status = RT->GetVariable(L"SecureBoot", + &GV_GUID, NULL, &DataSize, &SecureBoot); if (status != EFI_SUCCESS) { Print(L"Not a Secure Boot Platform %d\n", status); goto override; @@ -42,7 +42,9 @@ goto override; } - status = security_policy_install(); + status = security_policy_install(security_policy_mok_override, + security_policy_mok_allow, + security_policy_mok_deny); if (status != EFI_SUCCESS) { console_error(L"Failed to install override security policy", status); diff -Nru efitools-1.4.2/ReadVars.c efitools-1.8.1/ReadVars.c --- efitools-1.4.2/ReadVars.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/ReadVars.c 2018-02-21 03:53:05.000000000 +0000 @@ -16,8 +16,6 @@ #include <sha256.h> #include "efiauthenticated.h" -#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) - void parse_db(UINT8 *data, UINTN len, EFI_HANDLE image, CHAR16 *name, int save_file) { @@ -101,8 +99,8 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) { EFI_STATUS status; - CHAR16 *variables[] = { L"PK", L"KEK", L"db", L"dbx", L"MokList" }; - EFI_GUID owners[] = { GV_GUID, GV_GUID, SIG_DB, SIG_DB, MOK_OWNER }; + CHAR16 **variables; + EFI_GUID *owners; CHAR16 **ARGV, *progname; UINT8 *data; UINTN len; @@ -110,6 +108,14 @@ InitializeLib(image, systab); + if (GetOSIndications() & EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION) { + variables = (CHAR16 *[]){ L"PK", L"KEK", L"db", L"dbx", L"dbt", L"MokList" , NULL}; + owners = (EFI_GUID []){ GV_GUID, GV_GUID, SIG_DB, SIG_DB, SIG_DB, MOK_OWNER }; + } else { + variables = (CHAR16 *[]){ L"PK", L"KEK", L"db", L"dbx", L"MokList" , NULL}; + owners = (EFI_GUID []){ GV_GUID, GV_GUID, SIG_DB, SIG_DB, MOK_OWNER }; + } + status = argsplit(image, &argc, &ARGV); if (status != EFI_SUCCESS) { @@ -139,7 +145,7 @@ } if (argc == 1) { - for (i = 0; i < ARRAY_SIZE(owners); i++) { + for (i = 0; variables[i] != NULL; i++) { status = get_variable(variables[i], &data, &len, owners[i]); if (status == EFI_NOT_FOUND) { Print(L"Variable %s has no entries\n", variables[i]); @@ -154,14 +160,14 @@ } else { CHAR16 *var = ARGV[1]; - for(i = 0; i < ARRAY_SIZE(variables); i++) { + for(i = 0; variables[i] != NULL; i++) { if (StrCmp(var, variables[i]) == 0) { break; } } - if (i == ARRAY_SIZE(variables)) { + if (variables[i]== NULL) { Print(L"Invalid Variable %s\nVariable must be one of: ", var); - for (i = 0; i < ARRAY_SIZE(variables); i++) + for (i = 0; variables[i] != NULL; i++) Print(L"%s ", variables[i]); Print(L"\n"); return EFI_INVALID_PARAMETER; diff -Nru efitools-1.4.2/ShimReplace.c efitools-1.8.1/ShimReplace.c --- efitools-1.4.2/ShimReplace.c 1970-01-01 01:00:00.000000000 +0100 +++ efitools-1.8.1/ShimReplace.c 2018-02-21 03:53:05.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Copyright 2016 <[email protected]> + * + * see COPYING file + * + * Replacement for shim.efi which is signed by your own key + * and installs the shim protocol verifier for grub to use + * so the secure boot chain is unbroken + */ + +#include <efi.h> +#include <efilib.h> + +#include <console.h> +#include <guid.h> +#include <efiauthenticated.h> +#include <execute.h> +#include <shim_protocol.h> +#include <pkcs7verify.h> + +static const CHAR16 *loader = L"\\grub.efi"; +static const CHAR16 *fallback = L"\\fallback.efi"; + +EFI_STATUS +efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) +{ + EFI_STATUS efi_status; + EFI_PKCS7_VERIFY_PROTOCOL *p7vp; + CHAR16 *error; + void *ptr; + + InitializeLib(image, systab); + + efi_status = pkcs7verify_get_protocol(image, &p7vp, &error); + + if (efi_status != EFI_SUCCESS) { + console_error(error, efi_status); + return efi_status; + } + + efi_status = shim_protocol_install(); + if (efi_status != EFI_SUCCESS) + console_error(L"Failed to install shim protocol", efi_status); + + + efi_status = BS->LocateProtocol(&MOK_OWNER, + NULL, &ptr); + if (efi_status != EFI_SUCCESS) + console_error(L"Failed to locate shim protocol", efi_status); + + efi_status = execute(image, loader); + if (efi_status == EFI_SUCCESS) + return efi_status; + + console_error(L"Failed to start primary loader", efi_status); + + efi_status = execute(image, fallback); + + if (efi_status != EFI_SUCCESS) + console_error(L"Failed to start fallback loader", efi_status); + + return efi_status; +} diff -Nru efitools-1.4.2/sig-list-to-certs.c efitools-1.8.1/sig-list-to-certs.c --- efitools-1.4.2/sig-list-to-certs.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/sig-list-to-certs.c 2018-02-21 03:53:05.000000000 +0000 @@ -6,6 +6,12 @@ #include <stdint.h> #define __STDC_VERSION__ 199901L #include <efi.h> +#ifdef CONFIG_arm +/* FIXME: + * arm efi leaves a visibilit pragma pushed that won't work for + * non efi programs, so eliminate it */ +#pragma GCC visibility pop +#endif #include <sys/types.h> #include <sys/stat.h> @@ -25,17 +31,25 @@ int main(int argc, char *argv[]) { - char *certfile, *efifile, *name; + char *certfile, *efifile, *name, *esl_name; const char *progname = argv[0]; + int output_esl = 0; - if (argc != 3) { + if (argc != 3 && argc != 4) { printf("Usage: %s <efi sig list file> <cert file base name>\n", progname); exit(1); } + if (strcmp("-e", argv[1]) == 0) { + output_esl = 1; + argc--; + argv++; + } + efifile = argv[1]; certfile = argv[2]; name = malloc(strlen(certfile)+10); + esl_name = malloc(strlen(certfile)+10); int fd = open(efifile, O_RDONLY); if (fd < 0) { @@ -74,6 +88,8 @@ certentry_for_each_cert(sd, sl) { + FILE *g; + if (memcmp(&sl->SignatureType, &EFI_CERT_X509_GUID, sizeof(EFI_GUID)) == 0) { printf("X509 "); ext = "der"; @@ -95,10 +111,17 @@ EFI_GUID *guid = &sd->SignatureOwner; + sprintf(esl_name, "%s-%d.esl",certfile,count); sprintf(name, "%s-%d.%s",certfile,count++,ext); printf("file %s: Guid %s\n", name, guid_to_str(guid)); - FILE *g = fopen(name, "w"); + if (output_esl) { + g = fopen(esl_name, "w"); + fwrite(sl, 1, sl->SignatureListSize, g); + fclose(g); + } + + g = fopen(name, "w"); fwrite(sd->SignatureData, 1, sl->SignatureSize - OFFSET_OF(EFI_SIGNATURE_DATA, SignatureData), g); printf("Written %d bytes\n", sl->SignatureSize - (UINT32)OFFSET_OF(EFI_SIGNATURE_DATA, SignatureData)); fclose(g); diff -Nru efitools-1.4.2/sign-efi-sig-list.c efitools-1.8.1/sign-efi-sig-list.c --- efitools-1.4.2/sign-efi-sig-list.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/sign-efi-sig-list.c 2018-02-21 03:53:05.000000000 +0000 @@ -6,6 +6,12 @@ #include <stdint.h> #define __STDC_VERSION__ 199901L #include <efi.h> +#ifdef CONFIG_arm +/* FIXME: + * arm efi leaves a visibilit pragma pushed that won't work for + * non efi programs, so eliminate it */ +#pragma GCC visibility pop +#endif #include <stdio.h> #include <stdlib.h> @@ -151,23 +157,37 @@ time_t t; struct tm *tm, tms; + memset(&tms, 0, sizeof(tms)); + if (timestampstr) { - strptime(timestampstr, "%c", &tms); + strptime(timestampstr, "%Y-%m-%d %H:%M:%S", &tms); + tm = &tms; + /* timestamp.Year is from 0 not 1900 as tm year is */ + tm->tm_year += 1900; + tm->tm_mon += 1; /* tm_mon is 0-11 not 1-12 */ + } else if (attributes & EFI_VARIABLE_APPEND_WRITE) { + /* for append update timestamp should be zero */ + memset(&tms, 0, sizeof(tms)); tm = &tms; } else { time(&t); - tm = gmtime(&t); + tm = localtime(&t); + /* timestamp.Year is from 0 not 1900 as tm year is */ + tm->tm_year += 1900; + tm->tm_mon += 1; /* tm_mon is 0-11 not 1-12 */ } - /* FIXME: currently timestamp is one year into future because of - * the way we set up the secure environment */ - timestamp.Year = tm->tm_year + 1900 + 1; + timestamp.Year = tm->tm_year; timestamp.Month = tm->tm_mon; timestamp.Day = tm->tm_mday; timestamp.Hour = tm->tm_hour; timestamp.Minute = tm->tm_min; timestamp.Second = tm->tm_sec; + printf("Timestamp is %d-%d-%d %02d:%02d:%02d\n", timestamp.Year, + timestamp.Month, timestamp.Day, timestamp.Hour, timestamp.Minute, + timestamp.Second); + /* Warning: don't use any glibc wchar functions. We're building * with -fshort-wchar which breaks the glibc ABI */ i = 0; @@ -231,6 +251,11 @@ ERR_load_crypto_strings(); OpenSSL_add_all_digests(); OpenSSL_add_all_ciphers(); + /* here we may get highly unlikely failures or we'll get a + * complaint about FIPS signatures (usually becuase the FIPS + * module isn't present). In either case ignore the errors + * (malloc will cause other failures out lower down */ + ERR_clear_error(); BIO *cert_bio = BIO_new_file(certfile, "r"); X509 *cert = PEM_read_bio_X509(cert_bio, NULL, NULL, NULL); @@ -248,10 +273,10 @@ BIO *bio_data = BIO_new_mem_buf(signbuf, signbuflen); - p7 = PKCS7_sign(NULL, NULL, NULL, bio_data, PKCS7_BINARY|PKCS7_PARTIAL|PKCS7_DETACHED); + p7 = PKCS7_sign(NULL, NULL, NULL, bio_data, PKCS7_BINARY|PKCS7_PARTIAL|PKCS7_DETACHED|PKCS7_NOATTR); const EVP_MD *md = EVP_get_digestbyname("SHA256"); - PKCS7_sign_add_signer(p7, cert, pkey, md, PKCS7_BINARY|PKCS7_DETACHED); - PKCS7_final(p7, bio_data, PKCS7_BINARY|PKCS7_DETACHED); + PKCS7_sign_add_signer(p7, cert, pkey, md, PKCS7_BINARY|PKCS7_DETACHED|PKCS7_NOATTR); + PKCS7_final(p7, bio_data, PKCS7_BINARY|PKCS7_DETACHED|PKCS7_NOATTR); sigsize = i2d_PKCS7(p7, NULL); @@ -271,6 +296,7 @@ sigbuf = var_auth->AuthInfo.CertData; } else { sigbuf = var_auth->AuthInfo.CertData; + printf("Signature at: %ld\n", sigbuf - (unsigned char *)var_auth); i2d_PKCS7(p7, &sigbuf); ERR_print_errors_fp(stdout); } diff -Nru efitools-1.4.2/UpdateVars.c efitools-1.8.1/UpdateVars.c --- efitools-1.4.2/UpdateVars.c 2013-09-19 14:14:24.000000000 +0100 +++ efitools-1.8.1/UpdateVars.c 2018-02-21 03:53:05.000000000 +0000 @@ -16,8 +16,6 @@ #include <shell.h> #include "efiauthenticated.h" -#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) - EFI_STATUS efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) { @@ -28,12 +26,19 @@ void *buf; UINTN size, options = 0; EFI_GUID *owner; - CHAR16 *variables[] = { L"PK", L"KEK", L"db", L"dbx", L"MokList" }; - EFI_GUID *owners[] = { &GV_GUID, &GV_GUID, &SIG_DB, &SIG_DB, - &MOK_OWNER }; + CHAR16 **variables; + EFI_GUID **owners; InitializeLib(image, systab); + if (GetOSIndications() & EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION) { + variables = (CHAR16 *[]){ L"PK", L"KEK", L"db", L"dbx", L"dbt", L"MokList" , NULL}; + owners = (EFI_GUID *[]){ &GV_GUID, &GV_GUID, &SIG_DB, &SIG_DB, &SIG_DB, &MOK_OWNER }; + } else { + variables = (CHAR16 *[]){ L"PK", L"KEK", L"db", L"dbx", L"MokList" , NULL}; + owners = (EFI_GUID *[]){ &GV_GUID, &GV_GUID, &SIG_DB, &SIG_DB, &MOK_OWNER }; + } + status = argsplit(image, &argc, &ARGV); if (status != EFI_SUCCESS) { @@ -74,15 +79,15 @@ var = ARGV[1]; name = ARGV[2]; - for(i = 0; i < ARRAY_SIZE(variables); i++) { + for(i = 0; variables[i] != NULL; i++) { if (StrCmp(var, variables[i]) == 0) { owner = owners[i]; break; } } - if (i == ARRAY_SIZE(variables)) { + if (variables[i] == NULL) { Print(L"Invalid Variable %s\nVariable must be one of: ", var); - for (i = 0; i < ARRAY_SIZE(variables); i++) + for (i = 0; variables[i] != NULL; i++) Print(L"%s ", variables[i]); Print(L"\n"); return EFI_INVALID_PARAMETER; @@ -129,11 +134,11 @@ } else if (esl_mode) { status = SetSecureVariable(var, buf, size, *owner, options, 0); } else { - status = uefi_call_wrapper(RT->SetVariable, 5, var, owner, - EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_BOOTSERVICE_ACCESS - | options, - size, buf); + status = RT->SetVariable(var, owner, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | options, + size, buf); } if (status != EFI_SUCCESS) {

