Merge lp:~jibel/ubuntu/trusty/sbsigntool/lp1257305_add_corrected_efivars_magic into lp:ubuntu/trusty/sbsigntool

Proposed by Jean-Baptiste Lallement
Status: Merged
Merge reported by: Michael Terry
Merged at revision: not available
Proposed branch: lp:~jibel/ubuntu/trusty/sbsigntool/lp1257305_add_corrected_efivars_magic
Merge into: lp:ubuntu/trusty/sbsigntool
Diff against target: 1070 lines (+1014/-2)
6 files modified
.pc/add_corrected_efivars_magic.patch/src/sbkeysync.c (+979/-0)
.pc/applied-patches (+1/-0)
debian/changelog (+7/-0)
debian/patches/add_corrected_efivars_magic.patch (+23/-0)
debian/patches/series (+1/-0)
src/sbkeysync.c (+3/-2)
To merge this branch: bzr merge lp:~jibel/ubuntu/trusty/sbsigntool/lp1257305_add_corrected_efivars_magic
Reviewer Review Type Date Requested Status
Michael Terry Approve
Review via email: mp+197542@code.launchpad.net

Description of the change

* debian/patches/add_corrected_efivars_magic.patch: Cherry-picked upstream
  fix to add corrected efivars magic (LP: #1257305)

To post a comment you must log in.
Revision history for this message
Michael Terry (mterry) wrote :

Looks good! I uploaded to trusty.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc/add_corrected_efivars_magic.patch'
2=== added file '.pc/add_corrected_efivars_magic.patch/.timestamp'
3=== added directory '.pc/add_corrected_efivars_magic.patch/src'
4=== added file '.pc/add_corrected_efivars_magic.patch/src/sbkeysync.c'
5--- .pc/add_corrected_efivars_magic.patch/src/sbkeysync.c 1970-01-01 00:00:00 +0000
6+++ .pc/add_corrected_efivars_magic.patch/src/sbkeysync.c 2013-12-03 15:04:24 +0000
7@@ -0,0 +1,979 @@
8+/*
9+ * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
10+ *
11+ * This program is free software; you can redistribute it and/or
12+ * modify it under the terms of the GNU General Public License
13+ * as published by the Free Software Foundation; either version 3
14+ * of the License, or (at your option) any later version.
15+ *
16+ * This program is distributed in the hope that it will be useful,
17+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+ * GNU General Public License for more details.
20+ *
21+ * You should have received a copy of the GNU General Public License
22+ * along with this program; if not, write to the Free Software
23+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
24+ * USA.
25+ *
26+ * In addition, as a special exception, the copyright holders give
27+ * permission to link the code of portions of this program with the OpenSSL
28+ * library under certain conditions as described in each individual source file,
29+ * and distribute linked combinations including the two.
30+ *
31+ * You must obey the GNU General Public License in all respects for all
32+ * of the code used other than OpenSSL. If you modify file(s) with this
33+ * exception, you may extend this exception to your version of the
34+ * file(s), but you are not obligated to do so. If you do not wish to do
35+ * so, delete this exception statement from your version. If you delete
36+ * this exception statement from all source files in the program, then
37+ * also delete it here.
38+ */
39+#define _GNU_SOURCE
40+
41+#include <stdint.h>
42+#include <stdlib.h>
43+#include <string.h>
44+#include <dirent.h>
45+#include <fcntl.h>
46+#include <unistd.h>
47+#include <sys/stat.h>
48+#include <sys/statfs.h>
49+#include <sys/types.h>
50+
51+#include <getopt.h>
52+
53+#include <efi.h>
54+
55+#include <ccan/list/list.h>
56+#include <ccan/array_size/array_size.h>
57+#include <ccan/talloc/talloc.h>
58+
59+#include <openssl/x509.h>
60+#include <openssl/err.h>
61+
62+#include "fileio.h"
63+#include "efivars.h"
64+
65+#define EFIVARS_MOUNTPOINT "/sys/firmware/efi/efivars"
66+#define EFIVARS_FSTYPE 0x6165676C
67+
68+#define EFI_IMAGE_SECURITY_DATABASE_GUID \
69+ { 0xd719b2cb, 0x3d3a, 0x4596, \
70+ { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f } }
71+
72+static const char *toolname = "sbkeysync";
73+
74+static const uint32_t sigdb_attrs = EFI_VARIABLE_NON_VOLATILE |
75+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
76+ EFI_VARIABLE_RUNTIME_ACCESS |
77+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS |
78+ EFI_VARIABLE_APPEND_WRITE;
79+
80+struct key_database_type {
81+ const char *name;
82+ EFI_GUID guid;
83+};
84+
85+struct key_database_type keydb_types[] = {
86+ { "PK", EFI_GLOBAL_VARIABLE },
87+ { "KEK", EFI_GLOBAL_VARIABLE },
88+ { "db", EFI_IMAGE_SECURITY_DATABASE_GUID },
89+ { "dbx", EFI_IMAGE_SECURITY_DATABASE_GUID },
90+};
91+
92+enum keydb_type {
93+ KEYDB_PK = 0,
94+ KEYDB_KEK = 1,
95+ KEYDB_DB = 2,
96+ KEYDB_DBX = 3,
97+};
98+
99+static const char *default_keystore_dirs[] = {
100+ "/etc/secureboot/keys",
101+ "/usr/share/secureboot/keys",
102+};
103+
104+
105+struct key {
106+ EFI_GUID type;
107+ int id_len;
108+ uint8_t *id;
109+
110+ char *description;
111+
112+ struct list_node list;
113+
114+ /* set for keys loaded from a filesystem keystore */
115+ struct fs_keystore_entry *keystore_entry;
116+};
117+
118+typedef int (*key_parse_func)(struct key *, uint8_t *, size_t);
119+
120+struct cert_type {
121+ EFI_GUID guid;
122+ key_parse_func parse;
123+};
124+
125+struct key_database {
126+ const struct key_database_type *type;
127+ struct list_head keys;
128+};
129+
130+struct keyset {
131+ struct key_database pk;
132+ struct key_database kek;
133+ struct key_database db;
134+ struct key_database dbx;
135+};
136+
137+struct fs_keystore_entry {
138+ const struct key_database_type *type;
139+ const char *root;
140+ const char *name;
141+ uint8_t *data;
142+ size_t len;
143+ struct list_node keystore_list;
144+ struct list_node new_list;
145+};
146+
147+struct fs_keystore {
148+ struct list_head keys;
149+};
150+
151+struct sync_context {
152+ const char *efivars_dir;
153+ struct keyset *filesystem_keys;
154+ struct keyset *firmware_keys;
155+ struct fs_keystore *fs_keystore;
156+ const char **keystore_dirs;
157+ unsigned int n_keystore_dirs;
158+ struct list_head new_keys;
159+ bool verbose;
160+ bool dry_run;
161+ bool set_pk;
162+};
163+
164+
165+#define GUID_STRLEN (8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1)
166+static void guid_to_str(const EFI_GUID *guid, char *str)
167+{
168+ snprintf(str, GUID_STRLEN,
169+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
170+ guid->Data1, guid->Data2, guid->Data3,
171+ guid->Data4[0], guid->Data4[1],
172+ guid->Data4[2], guid->Data4[3],
173+ guid->Data4[4], guid->Data4[5],
174+ guid->Data4[6], guid->Data4[7]);
175+}
176+
177+static int sha256_key_parse(struct key *key, uint8_t *data, size_t len)
178+{
179+ const unsigned int sha256_id_size = 256 / 8;
180+ unsigned int i;
181+
182+ if (len != sha256_id_size)
183+ return -1;
184+
185+ key->id = talloc_memdup(key, data, sha256_id_size);
186+ key->id_len = sha256_id_size;
187+
188+ key->description = talloc_array(key, char, len * 2 + 1);
189+ for (i = 0; i < len; i++)
190+ snprintf(&key->description[i*2], 3, "%02x", data[i]);
191+ key->description[len*2] = '\0';
192+
193+ return 0;
194+}
195+
196+static int x509_key_parse(struct key *key, uint8_t *data, size_t len)
197+{
198+ const int description_len = 160;
199+ ASN1_INTEGER *serial;
200+ const uint8_t *tmp;
201+ X509 *x509;
202+ int rc;
203+
204+ rc = -1;
205+
206+ tmp = data;
207+
208+ x509 = d2i_X509(NULL, &tmp, len);
209+ if (!x509)
210+ return -1;
211+
212+ /* we use the X509 serial number as the key ID */
213+ if (!x509->cert_info || !x509->cert_info->serialNumber)
214+ goto out;
215+
216+ serial = x509->cert_info->serialNumber;
217+
218+ key->id_len = ASN1_STRING_length(serial);
219+ key->id = talloc_memdup(key, ASN1_STRING_data(serial), key->id_len);
220+
221+ key->description = talloc_array(key, char, description_len);
222+ X509_NAME_oneline(x509->cert_info->subject,
223+ key->description, description_len);
224+
225+ rc = 0;
226+
227+out:
228+ X509_free(x509);
229+ return rc;
230+}
231+
232+struct cert_type cert_types[] = {
233+ { EFI_CERT_SHA256_GUID, sha256_key_parse },
234+ { EFI_CERT_X509_GUID, x509_key_parse },
235+};
236+
237+static int guidcmp(const EFI_GUID *a, const EFI_GUID *b)
238+{
239+ return memcmp(a, b, sizeof(EFI_GUID));
240+}
241+
242+static int key_parse(struct key *key, const EFI_GUID *type,
243+ uint8_t *data, size_t len)
244+{
245+ char guid_str[GUID_STRLEN];
246+ unsigned int i;
247+
248+ for (i = 0; i < ARRAY_SIZE(cert_types); i++) {
249+ if (guidcmp(&cert_types[i].guid, type))
250+ continue;
251+
252+ return cert_types[i].parse(key, data, len);
253+ }
254+
255+ guid_to_str(type, guid_str);
256+ printf("warning: unknown signature type found:\n %s\n",
257+ guid_str);
258+ return -1;
259+
260+}
261+
262+typedef int (*sigdata_fn)(EFI_SIGNATURE_DATA *, int, const EFI_GUID *, void *);
263+
264+/**
265+ * Iterates an buffer of EFI_SIGNATURE_LISTs (at db_data, of length len),
266+ * and calls fn on each EFI_SIGNATURE_DATA item found.
267+ *
268+ * fn is passed the EFI_SIGNATURE_DATA pointer, and the length of the
269+ * signature data (including GUID header), the type of the signature list,
270+ * and a context pointer.
271+ */
272+static int sigdb_iterate(void *db_data, size_t len,
273+ sigdata_fn fn, void *arg)
274+{
275+ EFI_SIGNATURE_LIST *siglist;
276+ EFI_SIGNATURE_DATA *sigdata;
277+ unsigned int i, j;
278+ int rc = 0;
279+
280+ if (len == 0)
281+ return 0;
282+
283+ if (len < sizeof(*siglist))
284+ return -1;
285+
286+ for (i = 0, siglist = db_data + i;
287+ i + sizeof(*siglist) <= len &&
288+ i + siglist->SignatureListSize > i &&
289+ i + siglist->SignatureListSize <= len && !rc;
290+ i += siglist->SignatureListSize,
291+ siglist = db_data + i) {
292+
293+ /* ensure that the header & sig sizes are sensible */
294+ if (siglist->SignatureHeaderSize > siglist->SignatureListSize)
295+ continue;
296+
297+ if (siglist->SignatureSize > siglist->SignatureListSize)
298+ continue;
299+
300+ if (siglist->SignatureSize < sizeof(*sigdata))
301+ continue;
302+
303+ /* iterate through the (constant-sized) signature data blocks */
304+ for (j = sizeof(*siglist) + siglist->SignatureHeaderSize;
305+ j < siglist->SignatureListSize && !rc;
306+ j += siglist->SignatureSize)
307+ {
308+ sigdata = (void *)(siglist) + j;
309+
310+ rc = fn(sigdata, siglist->SignatureSize,
311+ &siglist->SignatureType, arg);
312+
313+ }
314+
315+ }
316+
317+ return rc;
318+}
319+
320+struct keydb_add_ctx {
321+ struct fs_keystore_entry *ke;
322+ struct key_database *kdb;
323+ struct keyset *keyset;
324+};
325+
326+static int keydb_add_key(EFI_SIGNATURE_DATA *sigdata, int len,
327+ const EFI_GUID *type, void *arg)
328+{
329+ struct keydb_add_ctx *add_ctx = arg;
330+ struct key *key;
331+ int rc;
332+
333+ key = talloc(add_ctx->keyset, struct key);
334+
335+ rc = key_parse(key, type, sigdata->SignatureData,
336+ len - sizeof(*sigdata));
337+
338+ if (rc) {
339+ talloc_free(key);
340+ return 0;
341+ }
342+ key->keystore_entry = add_ctx->ke;
343+ key->type = *type;
344+
345+ /* add a reference to the keystore entry: we don't want it to be
346+ * deallocated if the keystore is deallocated before the
347+ * struct key. */
348+ if (key->keystore_entry)
349+ talloc_reference(key, key->keystore_entry);
350+
351+ list_add(&add_ctx->kdb->keys, &key->list);
352+
353+ return 0;
354+}
355+
356+static int read_firmware_keydb(struct sync_context *ctx,
357+ struct key_database *kdb)
358+{
359+ struct keydb_add_ctx add_ctx;
360+ char guid_str[GUID_STRLEN];
361+ char *filename;
362+ uint8_t *buf;
363+ int rc = -1;
364+ size_t len;
365+
366+ add_ctx.keyset = ctx->firmware_keys;
367+ add_ctx.kdb = kdb;
368+ add_ctx.ke = NULL;
369+
370+ guid_to_str(&kdb->type->guid, guid_str);
371+
372+ filename = talloc_asprintf(ctx->firmware_keys, "%s/%s-%s",
373+ ctx->efivars_dir, kdb->type->name, guid_str);
374+
375+ buf = NULL;
376+ rc = fileio_read_file_noerror(ctx->firmware_keys, filename, &buf, &len);
377+ if (rc)
378+ goto out;
379+
380+ /* efivars files start with a 32-bit attribute block */
381+ if (len < sizeof(uint32_t))
382+ goto out;
383+
384+ buf += sizeof(uint32_t);
385+ len -= sizeof(uint32_t);
386+
387+ rc = 0;
388+ sigdb_iterate(buf, len, keydb_add_key, &add_ctx);
389+
390+out:
391+ if (rc)
392+ talloc_free(buf);
393+ talloc_free(filename);
394+
395+ return rc;
396+}
397+
398+static void __attribute__((format(printf, 2, 3))) print_keystore_key_error(
399+ struct fs_keystore_entry *ke, const char *fmt, ...)
400+{
401+ char *errstr;
402+ va_list ap;
403+
404+ va_start(ap, fmt);
405+ errstr = talloc_vasprintf(ke, fmt, ap);
406+
407+ fprintf(stderr, "Invalid key %s/%s\n - %s\n", ke->root, ke->name,
408+ errstr);
409+
410+ talloc_free(errstr);
411+ va_end(ap);
412+}
413+
414+static int read_filesystem_keydb(struct sync_context *ctx,
415+ struct key_database *kdb)
416+{
417+ EFI_GUID cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
418+ EFI_VARIABLE_AUTHENTICATION_2 *auth;
419+ struct keydb_add_ctx add_ctx;
420+ struct fs_keystore_entry *ke;
421+ int rc;
422+
423+ add_ctx.keyset = ctx->filesystem_keys;
424+ add_ctx.kdb = kdb;
425+
426+ list_for_each(&ctx->fs_keystore->keys, ke, keystore_list) {
427+ unsigned int len;
428+ void *buf;
429+
430+ if (ke->len == 0)
431+ continue;
432+
433+ if (ke->type != kdb->type)
434+ continue;
435+
436+ /* parse the three data structures:
437+ * EFI_VARIABLE_AUTHENTICATION_2 token
438+ * EFI_SIGNATURE_LIST
439+ * EFI_SIGNATURE_DATA
440+ * ensuring that we have enough data for each
441+ */
442+
443+ buf = ke->data;
444+ len = ke->len;
445+
446+ if (len < sizeof(*auth)) {
447+ print_keystore_key_error(ke, "does not contain an "
448+ "EFI_VARIABLE_AUTHENTICATION_2 descriptor");
449+ continue;
450+ }
451+
452+ auth = buf;
453+
454+ if (guidcmp(&auth->AuthInfo.CertType, &cert_type_pkcs7)) {
455+ print_keystore_key_error(ke, "unknown cert type");
456+ continue;
457+ }
458+
459+ if (auth->AuthInfo.Hdr.dwLength > len) {
460+ print_keystore_key_error(ke,
461+ "invalid WIN_CERTIFICATE length");
462+ continue;
463+ }
464+
465+ /* the dwLength field includes the size of the WIN_CERTIFICATE,
466+ * but not the other data in the EFI_VARIABLE_AUTHENTICATION_2
467+ * descriptor */
468+ buf += sizeof(*auth) - sizeof(auth->AuthInfo) +
469+ auth->AuthInfo.Hdr.dwLength;
470+ len -= sizeof(*auth) - sizeof(auth->AuthInfo) +
471+ auth->AuthInfo.Hdr.dwLength;
472+
473+ add_ctx.ke = ke;
474+ rc = sigdb_iterate(buf, len, keydb_add_key, &add_ctx);
475+ if (rc) {
476+ print_keystore_key_error(ke, "error parsing "
477+ "EFI_SIGNATURE_LIST");
478+ continue;
479+ }
480+
481+ }
482+
483+ return 0;
484+}
485+
486+static int read_keysets(struct sync_context *ctx)
487+{
488+ read_firmware_keydb(ctx, &ctx->firmware_keys->pk);
489+ read_firmware_keydb(ctx, &ctx->firmware_keys->kek);
490+ read_firmware_keydb(ctx, &ctx->firmware_keys->db);
491+ read_firmware_keydb(ctx, &ctx->firmware_keys->dbx);
492+
493+ read_filesystem_keydb(ctx, &ctx->filesystem_keys->pk);
494+ read_filesystem_keydb(ctx, &ctx->filesystem_keys->kek);
495+ read_filesystem_keydb(ctx, &ctx->filesystem_keys->db);
496+ read_filesystem_keydb(ctx, &ctx->filesystem_keys->dbx);
497+
498+ return 0;
499+}
500+
501+static int check_pk(struct sync_context *ctx)
502+{
503+ struct key *key;
504+ int i = 0;
505+
506+ list_for_each(&ctx->filesystem_keys->pk.keys, key, list)
507+ i++;
508+
509+ return (i <= 1) ? 0 : 1;
510+}
511+
512+static void print_keyset(struct keyset *keyset, const char *name)
513+{
514+ struct key_database *kdbs[] =
515+ { &keyset->pk, &keyset->kek, &keyset->db, &keyset->dbx };
516+ struct key *key;
517+ unsigned int i;
518+
519+ printf("%s keys:\n", name);
520+
521+ for (i = 0; i < ARRAY_SIZE(kdbs); i++) {
522+ printf(" %s:\n", kdbs[i]->type->name);
523+
524+ list_for_each(&kdbs[i]->keys, key, list) {
525+ printf(" %s\n", key->description);
526+ if (key->keystore_entry)
527+ printf(" from %s/%s\n",
528+ key->keystore_entry->root,
529+ key->keystore_entry->name);
530+ }
531+ }
532+}
533+
534+static int check_efivars_mount(const char *mountpoint)
535+{
536+ struct statfs statbuf;
537+ int rc;
538+
539+ rc = statfs(mountpoint, &statbuf);
540+ if (rc)
541+ return -1;
542+
543+ if (statbuf.f_type != EFIVARS_FSTYPE)
544+ return -1;
545+
546+ return 0;
547+}
548+
549+static int keystore_entry_read(struct fs_keystore_entry *ke)
550+{
551+ const char *path;
552+ int rc;
553+
554+ path = talloc_asprintf(ke, "%s/%s", ke->root, ke->name);
555+
556+ rc = fileio_read_file(ke, path, &ke->data, &ke->len);
557+
558+ talloc_free(path);
559+
560+ return rc;
561+}
562+
563+static bool keystore_contains_file(struct fs_keystore *keystore,
564+ const char *filename)
565+{
566+ struct fs_keystore_entry *ke;
567+
568+ list_for_each(&keystore->keys, ke, keystore_list) {
569+ if (!strcmp(ke->name, filename))
570+ return true;
571+ }
572+
573+ return false;
574+}
575+
576+static int update_keystore(struct fs_keystore *keystore, const char *root)
577+{
578+ struct fs_keystore_entry *ke;
579+ unsigned int i;
580+
581+ for (i = 0; i < ARRAY_SIZE(keydb_types); i++) {
582+ const char *filename, *dirname;
583+ struct dirent *dirent;
584+ DIR *dir;
585+
586+ dirname = talloc_asprintf(keystore, "%s/%s", root,
587+ keydb_types[i].name);
588+
589+ dir = opendir(dirname);
590+ if (!dir)
591+ continue;
592+
593+ for (dirent = readdir(dir); dirent; dirent = readdir(dir)) {
594+
595+ if (dirent->d_name[0] == '.')
596+ continue;
597+
598+ filename = talloc_asprintf(dirname, "%s/%s",
599+ keydb_types[i].name,
600+ dirent->d_name);
601+
602+ if (keystore_contains_file(keystore, filename))
603+ continue;
604+
605+ ke = talloc(keystore, struct fs_keystore_entry);
606+ ke->name = filename;
607+ ke->root = root;
608+ ke->type = &keydb_types[i];
609+ talloc_steal(ke, ke->name);
610+
611+ if (keystore_entry_read(ke))
612+ talloc_free(ke);
613+ else
614+ list_add(&keystore->keys, &ke->keystore_list);
615+ }
616+
617+ closedir(dir);
618+ talloc_free(dirname);
619+ }
620+
621+ return 0;
622+}
623+
624+static int read_keystore(struct sync_context *ctx)
625+{
626+ struct fs_keystore *keystore;
627+ unsigned int i;
628+
629+ keystore = talloc(ctx, struct fs_keystore);
630+ list_head_init(&keystore->keys);
631+
632+ for (i = 0; i < ctx->n_keystore_dirs; i++) {
633+ update_keystore(keystore, ctx->keystore_dirs[i]);
634+ }
635+
636+ ctx->fs_keystore = keystore;
637+
638+ return 0;
639+}
640+
641+static void print_keystore(struct fs_keystore *keystore)
642+{
643+ struct fs_keystore_entry *ke;
644+
645+ printf("Filesystem keystore:\n");
646+
647+ list_for_each(&keystore->keys, ke, keystore_list)
648+ printf(" %s/%s [%zd bytes]\n", ke->root, ke->name, ke->len);
649+}
650+
651+static int key_cmp(struct key *a, struct key *b)
652+{
653+ if (a->id_len != b->id_len)
654+ return a->id_len - b->id_len;
655+
656+ return memcmp(a->id, b->id, a->id_len);
657+}
658+
659+/**
660+ * Finds the set-difference of the filesystem and firmware keys, and
661+ * populates ctx->new_keys with the keystore_entries that should be
662+ * inserted into firmware
663+ */
664+static int find_new_keys(struct sync_context *ctx)
665+{
666+ struct {
667+ struct key_database *fs_kdb, *fw_kdb;
668+ } kdbs[] = {
669+ { &ctx->filesystem_keys->pk, &ctx->firmware_keys->pk },
670+ { &ctx->filesystem_keys->kek, &ctx->firmware_keys->kek },
671+ { &ctx->filesystem_keys->db, &ctx->firmware_keys->db },
672+ { &ctx->filesystem_keys->dbx, &ctx->firmware_keys->dbx },
673+ };
674+ unsigned int i;
675+ int n = 0;
676+
677+ for (i = 0; i < ARRAY_SIZE(kdbs); i++ ) {
678+ struct fs_keystore_entry *ke;
679+ struct key *fs_key, *fw_key;
680+ bool found;
681+
682+ list_for_each(&kdbs[i].fs_kdb->keys, fs_key, list) {
683+ found = false;
684+ list_for_each(&kdbs[i].fw_kdb->keys, fw_key, list) {
685+ if (!key_cmp(fs_key, fw_key)) {
686+ found = true;
687+ break;
688+ }
689+ }
690+ if (found)
691+ continue;
692+
693+ /* add the keystore entry if it's not already present */
694+ found = false;
695+ list_for_each(&ctx->new_keys, ke, new_list) {
696+ if (fs_key->keystore_entry == ke) {
697+ found = true;
698+ break;
699+ }
700+ }
701+
702+ if (found)
703+ continue;
704+
705+ list_add(&ctx->new_keys,
706+ &fs_key->keystore_entry->new_list);
707+ n++;
708+ }
709+ }
710+
711+ return n;
712+}
713+
714+static void print_new_keys(struct sync_context *ctx)
715+{
716+ struct fs_keystore_entry *ke;
717+
718+ printf("New keys in filesystem:\n");
719+
720+ list_for_each(&ctx->new_keys, ke, new_list)
721+ printf(" %s/%s\n", ke->root, ke->name);
722+}
723+
724+static int insert_key(struct sync_context *ctx, struct fs_keystore_entry *ke)
725+{
726+ char guid_str[GUID_STRLEN];
727+ char *efivars_filename;
728+ unsigned int buf_len;
729+ uint8_t *buf;
730+ int fd, rc;
731+
732+ fd = -1;
733+ rc = -1;
734+
735+ if (ctx->verbose)
736+ printf("Inserting key update %s/%s into %s\n",
737+ ke->root, ke->name, ke->type->name);
738+
739+ /* we create a contiguous buffer of attributes & key data, so that
740+ * we write to the efivars file in a single syscall */
741+ buf_len = sizeof(sigdb_attrs) + ke->len;
742+ buf = talloc_array(ke, uint8_t, buf_len);
743+ memcpy(buf, &sigdb_attrs, sizeof(sigdb_attrs));
744+ memcpy(buf + sizeof(sigdb_attrs), ke->data, ke->len);
745+
746+ guid_to_str(&ke->type->guid, guid_str);
747+
748+ efivars_filename = talloc_asprintf(ke, "%s/%s-%s", ctx->efivars_dir,
749+ ke->type->name, guid_str);
750+
751+ fd = open(efivars_filename, O_WRONLY | O_CREAT, 0600);
752+ if (fd < 0) {
753+ fprintf(stderr, "Can't create key file %s: %s\n",
754+ efivars_filename, strerror(errno));
755+ goto out;
756+ }
757+
758+ rc = write(fd, buf, buf_len);
759+ if (rc <= 0) {
760+ fprintf(stderr, "Error writing key update: %s\n",
761+ strerror(errno));
762+ goto out;
763+ }
764+
765+ if (rc != (int)buf_len) {
766+ fprintf(stderr, "Partial write during key update: "
767+ "wrote %d bytes, expecting %d\n",
768+ rc, buf_len);
769+ goto out;
770+ }
771+
772+ rc = 0;
773+
774+out:
775+ if (fd >= 0)
776+ close(fd);
777+ talloc_free(efivars_filename);
778+ talloc_free(buf);
779+ if (rc)
780+ fprintf(stderr, "Error syncing keystore file %s/%s\n",
781+ ke->root, ke->name);
782+ return rc;
783+}
784+
785+static int insert_new_keys(struct sync_context *ctx)
786+{
787+ struct fs_keystore_entry *ke, *ke_pk;
788+ int pks, rc;
789+
790+ rc = 0;
791+ pks = 0;
792+ ke_pk = NULL;
793+
794+ list_for_each(&ctx->new_keys, ke, new_list) {
795+
796+ /* we handle PK last */
797+ if (ke->type == &keydb_types[KEYDB_PK]) {
798+ ke_pk = ke;
799+ pks++;
800+ continue;
801+ }
802+
803+ if (insert_key(ctx, ke))
804+ rc = -1;
805+ }
806+
807+ if (rc)
808+ return rc;
809+
810+ if (pks == 0 || !ctx->set_pk)
811+ return 0;
812+
813+ if (pks > 1) {
814+ fprintf(stderr, "Skipping PK update due to mutiple PKs\n");
815+ return -1;
816+ }
817+
818+ rc = insert_key(ctx, ke_pk);
819+
820+ return rc;
821+}
822+
823+static struct keyset *init_keyset(struct sync_context *ctx)
824+{
825+ struct keyset *keyset;
826+
827+ keyset = talloc(ctx, struct keyset);
828+
829+ list_head_init(&keyset->pk.keys);
830+ keyset->pk.type = &keydb_types[KEYDB_PK];
831+
832+ list_head_init(&keyset->kek.keys);
833+ keyset->kek.type = &keydb_types[KEYDB_KEK];
834+
835+ list_head_init(&keyset->db.keys);
836+ keyset->db.type = &keydb_types[KEYDB_DB];
837+
838+ list_head_init(&keyset->dbx.keys);
839+ keyset->dbx.type = &keydb_types[KEYDB_DBX];
840+
841+ return keyset;
842+}
843+
844+static struct option options[] = {
845+ { "help", no_argument, NULL, 'h' },
846+ { "version", no_argument, NULL, 'V' },
847+ { "efivars-path", required_argument, NULL, 'e' },
848+ { "verbose", no_argument, NULL, 'v' },
849+ { "dry-run", no_argument, NULL, 'n' },
850+ { "pk", no_argument, NULL, 'p' },
851+ { "no-default-keystores", no_argument, NULL, 'd' },
852+ { "keystore", required_argument, NULL, 'k' },
853+ { NULL, 0, NULL, 0 },
854+};
855+
856+static void usage(void)
857+{
858+ printf("Usage: %s [options]\n"
859+ "Update EFI key databases from the filesystem\n"
860+ "\n"
861+ "Options:\n"
862+ "\t--efivars-path <dir> Path to efivars mountpoint\n"
863+ "\t (or regular directory for testing)\n"
864+ "\t--verbose Print verbose progress information\n"
865+ "\t--dry-run Don't update firmware key databases\n"
866+ "\t--pk Set PK\n"
867+ "\t--keystore <dir> Read keys from <dir>/{db,dbx,KEK}/*\n"
868+ "\t (can be specified multiple times,\n"
869+ "\t first dir takes precedence)\n"
870+ "\t--no-default-keystores\n"
871+ "\t Don't read keys from the default\n"
872+ "\t keystore dirs\n",
873+ toolname);
874+}
875+
876+static void version(void)
877+{
878+ printf("%s %s\n", toolname, VERSION);
879+}
880+
881+static void add_keystore_dir(struct sync_context *ctx, const char *dir)
882+{
883+ ctx->keystore_dirs = talloc_realloc(ctx, ctx->keystore_dirs,
884+ const char *, ++ctx->n_keystore_dirs);
885+
886+ ctx->keystore_dirs[ctx->n_keystore_dirs - 1] =
887+ talloc_strdup(ctx->keystore_dirs, dir);
888+}
889+
890+int main(int argc, char **argv)
891+{
892+ bool use_default_keystore_dirs;
893+ struct sync_context *ctx;
894+
895+ use_default_keystore_dirs = true;
896+ ctx = talloc_zero(NULL, struct sync_context);
897+ list_head_init(&ctx->new_keys);
898+
899+ for (;;) {
900+ int idx, c;
901+ c = getopt_long(argc, argv, "e:dpkvhV", options, &idx);
902+ if (c == -1)
903+ break;
904+
905+ switch (c) {
906+ case 'e':
907+ ctx->efivars_dir = optarg;
908+ break;
909+ case 'd':
910+ use_default_keystore_dirs = false;
911+ break;
912+ case 'k':
913+ add_keystore_dir(ctx, optarg);
914+ break;
915+ case 'p':
916+ ctx->set_pk = true;
917+ break;
918+ case 'v':
919+ ctx->verbose = true;
920+ break;
921+ case 'n':
922+ ctx->dry_run = true;
923+ break;
924+ case 'V':
925+ version();
926+ return EXIT_SUCCESS;
927+ case 'h':
928+ usage();
929+ return EXIT_SUCCESS;
930+ }
931+ }
932+
933+ if (argc != optind) {
934+ usage();
935+ return EXIT_FAILURE;
936+ }
937+
938+ ERR_load_crypto_strings();
939+ OpenSSL_add_all_digests();
940+ OpenSSL_add_all_ciphers();
941+
942+ ctx->filesystem_keys = init_keyset(ctx);
943+ ctx->firmware_keys = init_keyset(ctx);
944+
945+ if (!ctx->efivars_dir) {
946+ ctx->efivars_dir = EFIVARS_MOUNTPOINT;
947+ if (check_efivars_mount(ctx->efivars_dir)) {
948+ fprintf(stderr, "Can't access efivars filesystem "
949+ "at %s, aborting\n", ctx->efivars_dir);
950+ return EXIT_FAILURE;
951+ }
952+ }
953+
954+ if (use_default_keystore_dirs) {
955+ unsigned int i;
956+ for (i = 0; i < ARRAY_SIZE(default_keystore_dirs); i++)
957+ add_keystore_dir(ctx, default_keystore_dirs[i]);
958+ }
959+
960+
961+ read_keystore(ctx);
962+
963+ if (ctx->verbose)
964+ print_keystore(ctx->fs_keystore);
965+
966+ read_keysets(ctx);
967+ if (ctx->verbose) {
968+ print_keyset(ctx->firmware_keys, "firmware");
969+ print_keyset(ctx->filesystem_keys, "filesystem");
970+ }
971+
972+ if (check_pk(ctx))
973+ fprintf(stderr, "WARNING: multiple PKs found in filesystem\n");
974+
975+ find_new_keys(ctx);
976+
977+ if (ctx->verbose)
978+ print_new_keys(ctx);
979+
980+ if (!ctx->dry_run)
981+ insert_new_keys(ctx);
982+
983+ talloc_free(ctx);
984+
985+ return EXIT_SUCCESS;
986+}
987
988=== modified file '.pc/applied-patches'
989--- .pc/applied-patches 2013-10-04 01:43:03 +0000
990+++ .pc/applied-patches 2013-12-03 15:04:24 +0000
991@@ -3,3 +3,4 @@
992 update_checksums.patch
993 fix-signature-padding.patch
994 ignore-certificate-expiries.patch
995+add_corrected_efivars_magic.patch
996
997=== modified file 'debian/changelog'
998--- debian/changelog 2013-10-04 01:43:03 +0000
999+++ debian/changelog 2013-12-03 15:04:24 +0000
1000@@ -1,3 +1,10 @@
1001+sbsigntool (0.6-0ubuntu6) UNRELEASED; urgency=low
1002+
1003+ * debian/patches/add_corrected_efivars_magic.patch: Cherry-picked upstream
1004+ fix to add corrected efivars magic (LP: #1257305)
1005+
1006+ -- Jean-Baptiste Lallement <jean-baptiste.lallement@ubuntu.com> Tue, 03 Dec 2013 15:50:45 +0100
1007+
1008 sbsigntool (0.6-0ubuntu5) saucy; urgency=low
1009
1010 * debian/patches/ignore-certificate-expiries.patch: ignore certificate
1011
1012=== added file 'debian/patches/add_corrected_efivars_magic.patch'
1013--- debian/patches/add_corrected_efivars_magic.patch 1970-01-01 00:00:00 +0000
1014+++ debian/patches/add_corrected_efivars_magic.patch 2013-12-03 15:04:24 +0000
1015@@ -0,0 +1,23 @@
1016+Index: sbsigntool/src/sbkeysync.c
1017+===================================================================
1018+--- sbsigntool.orig/src/sbkeysync.c 2013-12-03 15:45:49.007312000 +0100
1019++++ sbsigntool/src/sbkeysync.c 2013-12-03 15:47:47.396135699 +0100
1020+@@ -56,7 +56,8 @@
1021+ #include "efivars.h"
1022+
1023+ #define EFIVARS_MOUNTPOINT "/sys/firmware/efi/efivars"
1024+-#define EFIVARS_FSTYPE 0x6165676C
1025++#define PSTORE_FSTYPE 0x6165676C
1026++#define EFIVARS_FSTYPE 0xde5e81e4
1027+
1028+ #define EFI_IMAGE_SECURITY_DATABASE_GUID \
1029+ { 0xd719b2cb, 0x3d3a, 0x4596, \
1030+@@ -533,7 +534,7 @@
1031+ if (rc)
1032+ return -1;
1033+
1034+- if (statbuf.f_type != EFIVARS_FSTYPE)
1035++ if (statbuf.f_type != EFIVARS_FSTYPE && statbuf.f_type != PSTORE_FSTYPE)
1036+ return -1;
1037+
1038+ return 0;
1039
1040=== modified file 'debian/patches/series'
1041--- debian/patches/series 2013-10-04 01:43:03 +0000
1042+++ debian/patches/series 2013-12-03 15:04:24 +0000
1043@@ -3,3 +3,4 @@
1044 update_checksums.patch
1045 fix-signature-padding.patch
1046 ignore-certificate-expiries.patch
1047+add_corrected_efivars_magic.patch
1048
1049=== modified file 'src/sbkeysync.c'
1050--- src/sbkeysync.c 2012-10-12 00:19:26 +0000
1051+++ src/sbkeysync.c 2013-12-03 15:04:24 +0000
1052@@ -56,7 +56,8 @@
1053 #include "efivars.h"
1054
1055 #define EFIVARS_MOUNTPOINT "/sys/firmware/efi/efivars"
1056-#define EFIVARS_FSTYPE 0x6165676C
1057+#define PSTORE_FSTYPE 0x6165676C
1058+#define EFIVARS_FSTYPE 0xde5e81e4
1059
1060 #define EFI_IMAGE_SECURITY_DATABASE_GUID \
1061 { 0xd719b2cb, 0x3d3a, 0x4596, \
1062@@ -533,7 +534,7 @@
1063 if (rc)
1064 return -1;
1065
1066- if (statbuf.f_type != EFIVARS_FSTYPE)
1067+ if (statbuf.f_type != EFIVARS_FSTYPE && statbuf.f_type != PSTORE_FSTYPE)
1068 return -1;
1069
1070 return 0;

Subscribers

People subscribed via source and target branches