aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Kerr <jeremy.kerr@canonical.com>2012-08-10 15:35:07 +0800
committerJeremy Kerr <jeremy.kerr@canonical.com>2012-08-10 15:35:07 +0800
commit591847bb799d7b304eba5ac6a90f35d61eabae42 (patch)
tree1a6fe60cf7f21c847ed816422f60ad7f45164026
parent0ca483d5d019e587eec1fcb15d23cfdd6a9142fc (diff)
downloadsbsigntools-591847bb799d7b304eba5ac6a90f35d61eabae42.tar.gz
sbsiglist: Add utility for creating EFI_SIGNATURE_LISTs
KEK, db and dbx updates need to be written as EFI_SIGNATURE_LIST structures, so create a simple tool to create them. Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
-rw-r--r--Makefile.am6
-rw-r--r--efivars.h13
-rw-r--r--sbsiglist.c277
3 files changed, 295 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index 86baa7e..6a52cf7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
AM_CFLAGS = -Wall -Wextra --std=gnu99
-bin_PROGRAMS = sbsign sbverify sbattach sbvarsign
+bin_PROGRAMS = sbsign sbverify sbattach sbvarsign sbsiglist
coff_headers = coff/external.h coff/pe.h coff/i386.h coff/x86_64.h
@@ -26,6 +26,10 @@ sbvarsign_LDADD = $(common_LDADD) $(uuid_LIBS)
sbvarsign_CPPFLAGS = $(EFI_CPPFLAGS)
sbvarsign_CFLAGS = $(AM_CFLAGS) $(uuid_CFLAGS) $(common_CFLAGS)
+sbsiglist_SOURCES = sbsiglist.c $(common_SOURCES)
+sbsiglist_LDADD = $(common_LDADD) $(uuid_LIBS)
+sbsiglist_CPPFLAGS = $(EFI_CPPFLAGS)
+sbsiglist_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS)
man1_MANS = docs/sbsign.1 docs/sbverify.1 docs/sbattach.1
diff --git a/efivars.h b/efivars.h
index 742e0e0..8782714 100644
--- a/efivars.h
+++ b/efivars.h
@@ -56,5 +56,18 @@ typedef struct {
WIN_CERTIFICATE_UEFI_GUID AuthInfo;
} EFI_VARIABLE_AUTHENTICATION_2;
+
+typedef struct {
+ EFI_GUID SignatureOwner;
+ UINT8 SignatureData[];
+} EFI_SIGNATURE_DATA;
+
+typedef struct {
+ EFI_GUID SignatureType;
+ UINT32 SignatureListSize;
+ UINT32 SignatureHeaderSize;
+ UINT32 SignatureSize;
+} EFI_SIGNATURE_LIST;
+
#endif /* EFI_VARAUTH_H */
diff --git a/sbsiglist.c b/sbsiglist.c
new file mode 100644
index 0000000..ab52914
--- /dev/null
+++ b/sbsiglist.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the OpenSSL
+ * library under certain conditions as described in each individual source file,
+ * and distribute linked combinations including the two.
+ *
+ * You must obey the GNU General Public License in all respects for all
+ * of the code used other than OpenSSL. If you modify file(s) with this
+ * exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do
+ * so, delete this exception statement from your version. If you delete
+ * this exception statement from all source files in the program, then
+ * also delete it here.
+ */
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <getopt.h>
+
+#include <uuid/uuid.h>
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs7.h>
+
+#include <ccan/array_size/array_size.h>
+#include <ccan/read_write_all/read_write_all.h>
+#include <ccan/talloc/talloc.h>
+
+#include "efivars.h"
+#include "fileio.h"
+
+static const char *toolname = "sbsiglist";
+
+static struct option options[] = {
+ { "output", required_argument, NULL, 'o' },
+ { "type", required_argument, NULL, 't' },
+ { "owner", required_argument, NULL, 'w' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL, 0, NULL, 0 },
+};
+
+#define EFI_CERT_X509_GUID \
+ { 0xa5c059a1, 0x94e4, 0x4aa7, \
+ { 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 } }
+
+#define EFI_CERT_SHA256_GUID \
+ { 0xc1c41626, 0x504c, 0x4092, \
+ { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 } }
+
+struct cert_type {
+ const char *name;
+ const EFI_GUID guid;
+ unsigned int sigsize;
+};
+
+struct cert_type cert_types[] = {
+ { "x509", EFI_CERT_X509_GUID, 0 },
+ { "sha256", EFI_CERT_SHA256_GUID, sizeof(EFI_SIGNATURE_DATA) + 16 },
+};
+
+struct siglist_context {
+ int verbose;
+
+ const char *infilename;
+ const char *outfilename;
+ const struct cert_type *type;
+ EFI_GUID owner;
+
+ uint8_t *data;
+ size_t data_len;
+
+ EFI_SIGNATURE_LIST *siglist;
+};
+
+
+void usage(void)
+{
+ unsigned int i;
+
+ printf("Usage: %s [options] --owner <guid> --type <type> <sig-file>\n"
+ "Create an EFI_SIGNATURE_LIST from a signature file\n"
+ "Options:\n"
+ "\t--owner <guid> Signature owner GUID\n"
+ "\t--type <type> Signature type. One of:\n",
+ toolname);
+
+ for (i = 0; i < ARRAY_SIZE(cert_types); i++)
+ printf("\t %s\n", cert_types[i].name);
+
+ printf("\t--output <file> write signed data to <file>\n"
+ "\t (default <sig-file>.siglist)\n");
+}
+
+static void version(void)
+{
+ printf("%s %s\n", toolname, VERSION);
+}
+
+static int siglist_create(struct siglist_context *ctx)
+{
+ EFI_SIGNATURE_LIST *siglist;
+ EFI_SIGNATURE_DATA *sigdata;
+ uint32_t size;
+
+ if (ctx->type->sigsize && ctx->data_len + sizeof(*sigdata)
+ != ctx->type->sigsize) {
+ fprintf(stderr, "Error: signature lists of type '%s' expect "
+ "%d bytes of data, "
+ "%zd bytes provided.\n",
+ ctx->type->name,
+ ctx->type->sigsize,
+ ctx->data_len);
+ return -1;
+ }
+
+ size = sizeof(*siglist) + sizeof(*sigdata) + ctx->data_len;
+
+ siglist = talloc_size(ctx, size);
+ sigdata = (void *)(siglist + 1);
+
+ siglist->SignatureType = ctx->type->guid;
+ siglist->SignatureListSize = size;
+ siglist->SignatureHeaderSize = 0;
+ siglist->SignatureSize = ctx->data_len;
+
+ sigdata->SignatureOwner = ctx->owner;
+
+ memcpy(sigdata->SignatureData, ctx->data, ctx->data_len);
+
+ ctx->siglist = siglist;
+
+ return 0;
+}
+
+static int parse_guid(const char *str, EFI_GUID *guid)
+{
+ uuid_t uuid;
+
+ if (uuid_parse(str, uuid))
+ return -1;
+
+ /* convert to an EFI_GUID */
+ guid->Data1 = uuid[0] << 24 | uuid[1] << 16 | uuid[2] << 8 | uuid[3];
+ guid->Data2 = uuid[4] << 8 | uuid[5];
+ guid->Data3 = uuid[6] << 8 | uuid[7];
+ memcpy(guid->Data4, &uuid[8], sizeof(guid->Data4));
+
+ return 0;
+}
+
+static struct cert_type *parse_type(const char *str)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cert_types); i++)
+ if (!strcasecmp(cert_types[i].name, str))
+ return &cert_types[i];
+
+ return NULL;
+}
+
+static void set_default_outfilename(struct siglist_context *ctx)
+{
+ const char *extension = "siglist";
+
+ ctx->outfilename = talloc_asprintf(ctx, "%s.%s",
+ ctx->infilename, extension);
+}
+int main(int argc, char **argv)
+{
+ const char *type_str, *owner_guid_str;
+ struct siglist_context *ctx;
+ int c;
+
+ ctx = talloc_zero(NULL, struct siglist_context);
+
+ owner_guid_str = NULL;
+ type_str = NULL;
+
+ for (;;) {
+ int idx;
+ c = getopt_long(argc, argv, "o:t:w:ivVh", options, &idx);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'o':
+ ctx->outfilename = optarg;
+ break;
+ case 't':
+ type_str = optarg;
+ break;
+ case 'w':
+ owner_guid_str = optarg;
+ break;
+ case 'v':
+ ctx->verbose = 1;
+ break;
+ case 'V':
+ version();
+ return EXIT_SUCCESS;
+ case 'h':
+ usage();
+ return EXIT_SUCCESS;
+ }
+ }
+
+ if (argc != optind + 1) {
+ usage();
+ return EXIT_FAILURE;
+ }
+
+ ctx->infilename = argv[optind];
+
+ ctx->type = parse_type(type_str);
+ if (!ctx->type) {
+ fprintf(stderr, "Invalid type '%s'\n", type_str);
+ return EXIT_FAILURE;
+ }
+
+ if (parse_guid(owner_guid_str, &ctx->owner)) {
+ fprintf(stderr, "Invalid owner GUID '%s'\n", owner_guid_str);
+ return EXIT_FAILURE;
+ }
+
+ if (!ctx->outfilename)
+ set_default_outfilename(ctx);
+
+ if (fileio_read_file(ctx, ctx->infilename,
+ &ctx->data, &ctx->data_len)) {
+ fprintf(stderr, "Can't read input file %s\n", ctx->infilename);
+ return EXIT_FAILURE;
+ }
+
+ if (siglist_create(ctx))
+ return EXIT_FAILURE;
+
+ if (fileio_write_file(ctx->outfilename,
+ (void *)ctx->siglist,
+ ctx->siglist->SignatureListSize)) {
+ fprintf(stderr, "Can't write output file %s\n",
+ ctx->outfilename);
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}