Merge ~enr0n/ubuntu/+source/mokutil:lp2015664-bionic into ubuntu/+source/mokutil:ubuntu/bionic-devel

Proposed by Nick Rosbrook
Status: Needs review
Proposed branch: ~enr0n/ubuntu/+source/mokutil:lp2015664-bionic
Merge into: ubuntu/+source/mokutil:ubuntu/bionic-devel
Diff against target: 4122 lines (+2032/-979)
23 files modified
configure.ac (+2/-1)
data/mokutil (+9/-1)
debian/changelog (+52/-0)
debian/compat (+1/-1)
debian/control (+7/-5)
debian/patches/manually-define-LIBKEYUTILS-make-vars.patch (+21/-0)
debian/patches/series (+1/-1)
debian/rules (+1/-5)
dev/null (+0/-22)
man/mokutil.1 (+50/-20)
src/Makefile.am (+13/-1)
src/efi_hash.c (+183/-0)
src/efi_hash.h (+48/-0)
src/efi_x509.c (+242/-0)
src/efi_x509.h (+43/-0)
src/keyring.c (+111/-0)
src/keyring.h (+37/-0)
src/mokutil.c (+619/-911)
src/mokutil.h (+66/-0)
src/password-crypt.c (+7/-6)
src/password-crypt.h (+5/-5)
src/util.c (+456/-0)
src/util.h (+58/-0)
Reviewer Review Type Date Requested Status
Steve Langasek (community) Approve
Review via email: mp+444298@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Steve Langasek (vorlon) :
review: Needs Fixing
Revision history for this message
Nick Rosbrook (enr0n) :
Revision history for this message
Steve Langasek (vorlon) :
review: Approve

Unmerged commits

62b8407... by Nick Rosbrook

changelog

7a6ca28... by Nick Rosbrook

update-maintainer

4b0011c... by Nick Rosbrook

d/p/manually-define-LIBKEYUTILS-make-vars.patch: workaround missing libkeyutils.pc in bionic

d1ac81c... by Nick Rosbrook

debian/control: drop debhelper version to 11 for bionic

319fc44... by Nick Rosbrook

debian/compat: drop to 11 for bionic

3a48661... by Steve McIntyre

0.6.0-2 (patches unapplied)

Imported using git-ubuntu import.

b7f0112... by Steve McIntyre

0.6.0-1 (patches unapplied)

Imported using git-ubuntu import.

a52b060... by Steve McIntyre

0.4.0-1 (patches unapplied)

Imported using git-ubuntu import.

ca9362e... by Simon Quigley

0.3.0+1538710437.fb6250f-1 (patches unapplied)

Imported using git-ubuntu import.

18df241... by Mathieu Trudel-Lapierre

0.3.0+1538710437.fb6250f-0ubuntu2~18.04.1 (patches unapplied)

Imported using git-ubuntu import.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/configure.ac b/configure.ac
2index 7b52a06..bfa0dfe 100644
3--- a/configure.ac
4+++ b/configure.ac
5@@ -2,7 +2,7 @@
6 # Process this file with autoconf to produce a configure script.
7
8 AC_PREREQ([2.68])
9-AC_INIT([mokutil], [0.3.0], [glin@suse.com])
10+AC_INIT([mokutil], [0.6.0], [chingpang@gmail.com])
11 AM_INIT_AUTOMAKE([1.11 -Wno-portability tar-ustar dist-bzip2 no-dist-gzip])
12 AC_CONFIG_SRCDIR([src/mokutil.c])
13 AC_CONFIG_HEADERS([config.h])
14@@ -85,6 +85,7 @@ AC_CHECK_FUNCS([memset])
15
16 PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9.8])
17 PKG_CHECK_MODULES(EFIVAR, [efivar >= 0.12])
18+PKG_CHECK_MODULES(LIBKEYUTILS, [libkeyutils >= 1.5])
19
20 AC_ARG_WITH([bash-completion-dir],
21 AS_HELP_STRING([--with-bash-completion-dir[=PATH]],
22diff --git a/data/mokutil b/data/mokutil
23index 800b039..b6ee859 100755
24--- a/data/mokutil
25+++ b/data/mokutil
26@@ -1,4 +1,4 @@
27-#!/bin/bash
28+# mokutil(1) completion
29
30 _mokutil()
31 {
32@@ -24,6 +24,14 @@ _mokutil()
33 COMPREPLY=( $( compgen -W "true false") )
34 return 0
35 ;;
36+ --set-fallback-verbosity)
37+ COMPREPLY=( $( compgen -W "true false") )
38+ return 0
39+ ;;
40+ --set-fallback-noreboot)
41+ COMPREPLY=( $( compgen -W "true false") )
42+ return 0
43+ ;;
44 --generate-hash|-g)
45 COMPREPLY=( $( compgen -o nospace -P= -W "") )
46 return 0
47diff --git a/debian/changelog b/debian/changelog
48index a753ef6..733aee3 100644
49--- a/debian/changelog
50+++ b/debian/changelog
51@@ -1,3 +1,55 @@
52+mokutil (0.6.0-2~18.04.1) bionic; urgency=medium
53+
54+ * Backport 0.6.0-2 to bionic (LP: #2015664).
55+ - debian/control,debian/compat: Drop debhelper version to 11
56+ to build on bionic.
57+ - debian/patches/manually-define-LIBKEYUTILS-make-vars.patch: Workaround
58+ missing libkeyutils.pc in bionic.
59+
60+ -- Nick Rosbrook <nick.rosbrook@canonical.com> Wed, 07 Jun 2023 14:14:30 -0400
61+
62+mokutil (0.6.0-2) unstable; urgency=medium
63+
64+ * *Actually* switch to Arch: any to allow for more
65+ architectures. :-( Closes: #987613.
66+
67+ -- Steve McIntyre <93sam@debian.org> Wed, 15 Jun 2022 14:30:50 +0100
68+
69+mokutil (0.6.0-1) unstable; urgency=medium
70+
71+ * Move to new upstream version 0.6.0.
72+ + Drop old patches, no longer needed.
73+ * Switch to Arch: any to allow for more architectures.
74+ Closes: #987613, #991933.
75+ * Clean up old tweaks in debian/rules, no longer needed.
76+ * Add build-dep on libkeyutils-dev, new dependency.
77+ * Bump Standards-Version to 4.6.1, no changes needed.
78+
79+ -- Steve McIntyre <93sam@debian.org> Sun, 12 Jun 2022 21:41:39 +0100
80+
81+mokutil (0.4.0-1) unstable; urgency=medium
82+
83+ * Take mokutil under the wing of efi-team.
84+ Thanks to Simon for his work previously, added him as an uploader
85+ * Import the upstream source
86+ * Move to new upstream version 0.4.0. Closes: #925223
87+ + Includes manpage fixes. Closes: #930759
88+ * Fix compiler warnings about potential unaligned pointers
89+ * Update packaging:
90+ + Raise debhelper-compat to 13
91+ + Raise Standards-Version to 4.5.1
92+ + Remove now-redundant build-dep on dh-autoreconf
93+
94+ -- Steve McIntyre <93sam@debian.org> Sun, 25 Apr 2021 21:47:18 +0100
95+
96+mokutil (0.3.0+1538710437.fb6250f-1) unstable; urgency=medium
97+
98+ * Upload to Debian (Closes: #925471).
99+ * Adopt the package; thanks to Steve Langasek for your work!
100+ * Update Vcs-* to reflect the move to Salsa.
101+
102+ -- Simon Quigley <tsimonq2@debian.org> Fri, 12 Apr 2019 17:45:52 -0500
103+
104 mokutil (0.3.0+1538710437.fb6250f-0ubuntu2~18.04.1) bionic; urgency=medium
105
106 * Backport mokutil 0.3.0+1538710437.fb6250f-0ubuntu2 to 18.04.
107diff --git a/debian/compat b/debian/compat
108index ec63514..b4de394 100644
109--- a/debian/compat
110+++ b/debian/compat
111@@ -1 +1 @@
112-9
113+11
114diff --git a/debian/control b/debian/control
115index 8f8b6c7..fd9e619 100644
116--- a/debian/control
117+++ b/debian/control
118@@ -2,13 +2,15 @@ Source: mokutil
119 Section: admin
120 Priority: optional
121 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
122-XSBC-Original-Maintainer: Steve Langasek <vorlon@debian.org>
123-Standards-Version: 3.9.4
124-Build-Depends: debhelper (>= 9), libssl-dev, pkg-config, libefivar-dev, dh-autoreconf
125-Vcs-Bzr: lp:ubuntu/mokutil
126+XSBC-Original-Maintainer: Debian UEFI Maintainers <debian-efi@lists.debian.org>
127+Uploaders: Steve McIntyre <93sam@debian.org>, Simon Quigley <tsimonq2@debian.org>
128+Standards-Version: 4.6.1
129+Build-Depends: debhelper (>= 11), libssl-dev, pkg-config, libefivar-dev, libkeyutils-dev
130+Vcs-Browser: https://salsa.debian.org/efi-team/mokutil
131+Vcs-Git: https://salsa.debian.org/efi-team/mokutil.git
132
133 Package: mokutil
134-Architecture: any-amd64 any-arm any-arm64 any-i386 any-ia64
135+Architecture: any
136 Depends: ${shlibs:Depends}, ${misc:Depends}
137 Description: tools for manipulating machine owner keys
138 This program provides the means to enroll and erase the machine owner
139diff --git a/debian/patches/int-signedness.patch b/debian/patches/int-signedness.patch
140deleted file mode 100644
141index 34b7dfa..0000000
142--- a/debian/patches/int-signedness.patch
143+++ /dev/null
144@@ -1,22 +0,0 @@
145-Description: Fix compile failure on platforms where int != unsigned int
146- The compiler may rightly warn about a comparison between an unsigned int
147- and an int on architectures where int is signed by default. Since the
148- existing code has been tested on architectures where int *is* unsigned,
149- we just make our other int explicitly unsigned, ignoring certain existing
150- corner cases for now wrt possible integer underflows.
151-Author: Steve Langasek <steve.langasek@canonical.com>
152-Last-Updated: 2018-10-10
153-
154-Index: mokutil-0.3.0+1538710437.fb6250f/src/mokutil.c
155-===================================================================
156---- mokutil-0.3.0+1538710437.fb6250f.orig/src/mokutil.c
157-+++ mokutil-0.3.0+1538710437.fb6250f/src/mokutil.c
158-@@ -2005,7 +2005,7 @@
159- char *password = NULL;
160- char *crypt_string;
161- const char *prefix;
162-- int settings_len = sizeof (settings) - 2;
163-+ unsigned int settings_len = sizeof (settings) - 2;
164- unsigned int pw_len, salt_size;
165-
166- if (input_pw) {
167diff --git a/debian/patches/manually-define-LIBKEYUTILS-make-vars.patch b/debian/patches/manually-define-LIBKEYUTILS-make-vars.patch
168new file mode 100644
169index 0000000..46df49c
170--- /dev/null
171+++ b/debian/patches/manually-define-LIBKEYUTILS-make-vars.patch
172@@ -0,0 +1,21 @@
173+Description: Manually define LIBKEYUTILS_{CFLAGS,LIBS} if missing libkeyutils.pc
174+Author: Nick Rosbrook <nick.rosbrook@canonical.com>
175+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/jammy/+source/mokutil/+bug/2015664
176+Forwarded: no
177+Last-Update: 2023-06-07
178+--- a/configure.ac
179++++ b/configure.ac
180+@@ -85,7 +85,12 @@
181+
182+ PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9.8])
183+ PKG_CHECK_MODULES(EFIVAR, [efivar >= 0.12])
184+-PKG_CHECK_MODULES(LIBKEYUTILS, [libkeyutils >= 1.5])
185++PKG_CHECK_MODULES(LIBKEYUTILS, [libkeyutils >= 1.5], [], [pkgconfig_found_keyutils="no"])
186++
187++if test "x$pkgconfig_found_keyutils" = "xno"; then
188++ AC_SUBST([LIBKEYUTILS_CFLAGS],["-I${includedir}"])
189++ AC_SUBST([LIBKEYUTILS_LIBS],["-L${libdir} -lkeyutils"])
190++fi
191+
192+ AC_ARG_WITH([bash-completion-dir],
193+ AS_HELP_STRING([--with-bash-completion-dir[=PATH]],
194diff --git a/debian/patches/series b/debian/patches/series
195index e7d00e3..4c264fa 100644
196--- a/debian/patches/series
197+++ b/debian/patches/series
198@@ -1 +1 @@
199-int-signedness.patch
200+manually-define-LIBKEYUTILS-make-vars.patch
201diff --git a/debian/rules b/debian/rules
202index e31f87c..2d33f6a 100755
203--- a/debian/rules
204+++ b/debian/rules
205@@ -1,8 +1,4 @@
206 #!/usr/bin/make -f
207
208 %:
209- dh $@ --with autoreconf
210-
211-#override_dh_autoreconf:
212-# NOCONFIGURE=1 dh_autoreconf ./autogen.sh
213-
214+ dh $@
215diff --git a/man/mokutil.1 b/man/mokutil.1
216index 25fe8b4..4260a7e 100644
217--- a/man/mokutil.1
218+++ b/man/mokutil.1
219@@ -15,11 +15,11 @@ mokutil \- utility to manipulate machine owner keys
220 .br
221 \fBmokutil\fR [--import \fIkeylist\fR| -i \fIkeylist\fR]
222 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
223- [--simple-hash | -s] | [--mokx | -X])
224+ [--mokx | -X] | [--ca-check] | [--ignore-keyring])
225 .br
226 \fBmokutil\fR [--delete \fIkeylist\fR | -d \fIkeylist\fR]
227 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
228- [--simple-hash | -s] | [--mokx |- X])
229+ [--mokx |- X])
230 .br
231 \fBmokutil\fR [--revoke-import]
232 ([--mokx | -X])
233@@ -30,11 +30,9 @@ mokutil \- utility to manipulate machine owner keys
234 \fBmokutil\fR [--export | -x]
235 .br
236 \fBmokutil\fR [--password | -p]
237- ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
238- [--simple-hash | -s])
239+ ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P])
240 .br
241 \fBmokutil\fR [--clear-password | -c]
242- ([--simple-hash | -s])
243 .br
244 \fBmokutil\fR [--disable-validation]
245 .br
246@@ -43,11 +41,11 @@ mokutil \- utility to manipulate machine owner keys
247 \fBmokutil\fR [--sb-state]
248 .br
249 \fBmokutil\fR [--test-key \fIkeyfile\fR | -t \fIkeyfile\fR]
250- ([--mokx | -X])
251+ ([--mokx | -X] | [--ca-check] | [--ignore-keyring])
252 .br
253 \fBmokutil\fR [--reset]
254 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
255- [--simple-hash | -s] | [--mok | -X])
256+ [--mok | -X])
257 .br
258 \fBmokutil\fR [--generate-hash=\fIpassword\fR | -g\fIpassword\fR]
259 .br
260@@ -57,14 +55,18 @@ mokutil \- utility to manipulate machine owner keys
261 .br
262 \fBmokutil\fR [--import-hash \fIhash\fR]
263 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
264- [--simple-hash | -s] | [--mokx | -X])
265+ [--mokx | -X])
266 .br
267 \fBmokutil\fR [--delete-hash \fIhash\fR]
268 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
269- [--simple-hash | -s] | [--mokx | -X])
270+ [--mokx | -X])
271 .br
272 \fBmokutil\fR [--set-verbosity (\fItrue\fR | \fIfalse\fR)]
273 .br
274+\fBmokutil\fR [--set-fallback-verbosity (\fItrue\fR | \fIfalse\fR)]
275+.br
276+\fBmokutil\fR [--set-fallback-noreboot (\fItrue\fR | \fIfalse\fR)]
277+.br
278 \fBmokutil\fR [--pk]
279 .br
280 \fBmokutil\fR [--kek]
281@@ -73,6 +75,12 @@ mokutil \- utility to manipulate machine owner keys
282 .br
283 \fBmokutil\fR [--dbx]
284 .br
285+\fBmokutil\fR [--list-sbat-revocations]
286+.br
287+\fBmokutil\fR [--set-sbat-policy (\fIlatest\fR | \fIprevious\fR | \fIdelete\fR)]
288+.br
289+\fBmokutil\fR [--timeout \fI-1,0..0x7fff\fR]
290+.br
291
292 .SH DESCRIPTION
293 \fBmokutil\fR is a tool to import or delete the machines owner keys
294@@ -90,11 +98,11 @@ List the keys to be enrolled
295 List the keys to be deleted
296 .TP
297 \fB-i, --import\fR
298-Collect the followed files and form a enrolling request to shim. The files must
299+Collect the following files and form an enrolling request to shim. The files must
300 be in DER format.
301 .TP
302 \fB-d, --delete\fR
303-Collect the followed files and form a deleting request to shim. The files must be
304+Collect the following files and form a deleting request to shim. The files must be
305 in DER format.
306 .TP
307 \fB--revoke-import\fR
308@@ -115,7 +123,7 @@ Clear the password for MokManager (MokPW)
309 \fB--disable-validation\fR
310 Disable the validation process in shim
311 .TP
312-\fB--enrolled-validation\fR
313+\fB--enable-validation\fR
314 Enable the validation process in shim
315 .TP
316 \fB--sb-state\fR
317@@ -136,11 +144,6 @@ Use the password hash from a specific file
318 \fB-P, --root-pw\fR
319 Use the root password hash from /etc/shadow
320 .TP
321-\fB-s, --simple-hash\fR
322-Use the old SHA256 password hash method to hash the password
323-.br
324-Note: --root-pw invalidates --simple-hash
325-.TP
326 \fB--ignore-db\fR
327 Tell shim to not use the keys in db to verify EFI images
328 .TP
329@@ -150,17 +153,23 @@ Tell shim to use the keys in db to verify EFI images (default)
330 \fB-X, --mokx\fR
331 Manipulate the MOK blacklist (MOKX) instead of the MOK list
332 .TP
333-\fB-i, --import-hash\fR
334+\fB--import-hash\fR
335 Create an enrolling request for the hash of a key in DER format. Note that
336 this is not the password hash.
337 .TP
338-\fB-d, --delete-hash\fR
339-Create an deleting request for the hash of a key in DER format. Note that
340+\fB--delete-hash\fR
341+Create a deleting request for the hash of a key in DER format. Note that
342 this is not the password hash.
343 .TP
344 \fB--set-verbosity\fR
345 Set the SHIM_VERBOSE to make shim more or less verbose
346 .TP
347+\fB--set-fallback-verbosity\fR
348+Set the FALLBACK_VERBOSE to make fallback more or less verbose
349+.TP
350+\fB--set-fallback-noreboot\fR
351+Set the FB_NO_REBOOT to prevent fallback from automatically rebooting the system
352+.TP
353 \fB--pk\fR
354 List the keys in the public Platform Key (PK)
355 .TP
356@@ -173,3 +182,24 @@ List the keys in the secure boot signature store (db)
357 \fB--dbx\fR
358 List the keys in the secure boot blacklist signature store (dbx)
359 .TP
360+\fB--list-sbat-revocations\fR
361+List the entries in the Secure Boot Advanced Targeting store (SBAT)
362+.TP
363+\fB--set-sbat-policy (\fIlatest\fR | \fIprevious\fR | \fIdelete\fR)\fR
364+Set the SbatPolicy UEFI Variable to have shim apply either the latest
365+or the previous SBAT revocations. If UEFI Secure Boot is disabled, then
366+delete will reset the SBAT revocations to an empty revocation list.
367+While latest and previous are persistent configuration, delete will be
368+cleared by shim on the next boot whether or not it succeeds. The default
369+behavior is for shim to apply the previous revocations.
370+.TP
371+\fB--timeout\fR
372+Set the timeout for MOK prompt
373+.TP
374+\fB--ca-check\fR
375+Check if the CA of the given key is already enrolled or blocked in the key
376+databases.
377+.TP
378+\fB--ignore-keyring\fR
379+Ignore the kernel builtin trusted keys keyring check when enrolling a key into MokList
380+.TP
381diff --git a/src/Makefile.am b/src/Makefile.am
382index 87b1515..1ac380d 100644
383--- a/src/Makefile.am
384+++ b/src/Makefile.am
385@@ -2,13 +2,25 @@ bin_PROGRAMS = mokutil
386
387 mokutil_CFLAGS = $(OPENSSL_CFLAGS) \
388 $(EFIVAR_CFLAGS) \
389- $(WARNINGFLAGS_C)
390+ $(LIBKEYUTILS_CFLAGS) \
391+ $(WARNINGFLAGS_C) \
392+ -DVERSION="\"$(VERSION)\""
393
394 mokutil_LDADD = $(OPENSSL_LIBS) \
395 $(EFIVAR_LIBS) \
396+ $(LIBKEYUTILS_LIBS) \
397 -lcrypt
398
399 mokutil_SOURCES = signature.h \
400+ efi_hash.h \
401+ efi_hash.c \
402+ efi_x509.h \
403+ efi_x509.c \
404+ keyring.h \
405+ keyring.c \
406 password-crypt.h \
407 password-crypt.c \
408+ util.h \
409+ util.c \
410+ mokutil.h \
411 mokutil.c
412diff --git a/src/efi_hash.c b/src/efi_hash.c
413new file mode 100644
414index 0000000..1ffe347
415--- /dev/null
416+++ b/src/efi_hash.c
417@@ -0,0 +1,183 @@
418+/**
419+ * Copyright (C) 2020 Gary Lin <glin@suse.com>
420+ *
421+ * This program is free software: you can redistribute it and/or modify
422+ * it under the terms of the GNU General Public License as published by
423+ * the Free Software Foundation, either version 3 of the License, or
424+ * (at your option) any later version.
425+ *
426+ * This program is distributed in the hope that it will be useful,
427+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
428+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
429+ * GNU General Public License for more details.
430+ *
431+ * You should have received a copy of the GNU General Public License
432+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
433+ *
434+ * In addition, as a special exception, the copyright holders give
435+ * permission to link the code of portions of this program with the
436+ * OpenSSL library under certain conditions as described in each
437+ * individual source file, and distribute linked combinations
438+ * including the two.
439+ *
440+ * You must obey the GNU General Public License in all respects
441+ * for all of the code used other than OpenSSL. If you modify
442+ * file(s) with this exception, you may extend this exception to your
443+ * version of the file(s), but you are not obligated to do so. If you
444+ * do not wish to do so, delete this exception statement from your
445+ * version. If you delete this exception statement from all source
446+ * files in the program, then also delete it here.
447+ */
448+
449+#include <stdio.h>
450+#include <stdlib.h>
451+#include <openssl/sha.h>
452+
453+#include "efi_hash.h"
454+
455+uint32_t
456+efi_hash_size (const efi_guid_t *hash_type)
457+{
458+ if (efi_guid_cmp (hash_type, &efi_guid_sha1) == 0) {
459+ return SHA_DIGEST_LENGTH;
460+ } else if (efi_guid_cmp (hash_type, &efi_guid_sha224) == 0) {
461+ return SHA224_DIGEST_LENGTH;
462+ } else if (efi_guid_cmp (hash_type, &efi_guid_sha256) == 0) {
463+ return SHA256_DIGEST_LENGTH;
464+ } else if (efi_guid_cmp (hash_type, &efi_guid_sha384) == 0) {
465+ return SHA384_DIGEST_LENGTH;
466+ } else if (efi_guid_cmp (hash_type, &efi_guid_sha512) == 0) {
467+ return SHA512_DIGEST_LENGTH;
468+ }
469+
470+ return 0;
471+}
472+
473+uint32_t
474+signature_size (const efi_guid_t *hash_type)
475+{
476+ uint32_t hash_size;
477+
478+ hash_size = efi_hash_size (hash_type);
479+ if (hash_size)
480+ return (hash_size + sizeof(efi_guid_t));
481+
482+ return 0;
483+}
484+
485+int
486+print_hash_array (const efi_guid_t *hash_type, const void *hash_array,
487+ const uint32_t array_size)
488+{
489+ uint32_t hash_size, remain;
490+ uint32_t sig_size;
491+ uint8_t *hash;
492+ char *name;
493+
494+ if (!hash_array || array_size == 0) {
495+ fprintf (stderr, "invalid hash array\n");
496+ return -1;
497+ }
498+
499+ int rc = efi_guid_to_name ((efi_guid_t *)hash_type, &name);
500+ if (rc < 0 || isxdigit(name[0])) {
501+ if (name)
502+ free(name);
503+ fprintf (stderr, "unknown hash type\n");
504+ return -1;
505+ }
506+
507+ hash_size = efi_hash_size (hash_type);
508+ sig_size = hash_size + sizeof(efi_guid_t);
509+
510+ printf (" [%s]\n", name);
511+ free(name);
512+ remain = array_size;
513+ hash = (uint8_t *)hash_array;
514+
515+ while (remain > 0) {
516+ if (remain < sig_size) {
517+ fprintf (stderr, "invalid array size\n");
518+ return -1;
519+ }
520+
521+ printf (" ");
522+ hash += sizeof(efi_guid_t);
523+ for (unsigned int i = 0; i<hash_size; i++)
524+ printf ("%02x", *(hash + i));
525+ printf ("\n");
526+ hash += hash_size;
527+ remain -= sig_size;
528+ }
529+
530+ return 0;
531+}
532+
533+/* match the hash in the hash array and return the index if matched */
534+int
535+match_hash_array (const efi_guid_t *hash_type, const void *hash,
536+ const void *hash_array, const uint32_t array_size)
537+{
538+ uint32_t hash_size, hash_count;
539+ uint32_t sig_size;
540+ void *ptr;
541+
542+ hash_size = efi_hash_size (hash_type);
543+ if (!hash_size)
544+ return -1;
545+
546+ sig_size = hash_size + sizeof(efi_guid_t);
547+ if ((array_size % sig_size) != 0) {
548+ fprintf (stderr, "invalid hash array size\n");
549+ return -1;
550+ }
551+
552+ ptr = (void *)hash_array;
553+ hash_count = array_size / sig_size;
554+ for (unsigned int i = 0; i < hash_count; i++) {
555+ ptr += sizeof(efi_guid_t);
556+ if (memcmp (ptr, hash, hash_size) == 0)
557+ return i;
558+ ptr += hash_size;
559+ }
560+
561+ return -1;
562+}
563+
564+/* Return the hash type and size of a given hash string */
565+int
566+identify_hash_type (const char *hash_str, efi_guid_t *type)
567+{
568+ unsigned int len = strlen (hash_str);
569+ int hash_size;
570+
571+ for (unsigned int i = 0; i < len; i++) {
572+ if ((hash_str[i] > '9' || hash_str[i] < '0') &&
573+ (hash_str[i] > 'f' || hash_str[i] < 'a') &&
574+ (hash_str[i] > 'F' || hash_str[i] < 'A'))
575+ return -1;
576+ }
577+
578+ switch (len) {
579+ case SHA224_DIGEST_LENGTH*2:
580+ *type = efi_guid_sha224;
581+ hash_size = SHA224_DIGEST_LENGTH;
582+ break;
583+ case SHA256_DIGEST_LENGTH*2:
584+ *type = efi_guid_sha256;
585+ hash_size = SHA256_DIGEST_LENGTH;
586+ break;
587+ case SHA384_DIGEST_LENGTH*2:
588+ *type = efi_guid_sha384;
589+ hash_size = SHA384_DIGEST_LENGTH;
590+ break;
591+ case SHA512_DIGEST_LENGTH*2:
592+ *type = efi_guid_sha512;
593+ hash_size = SHA512_DIGEST_LENGTH;
594+ break;
595+ default:
596+ return -1;
597+ }
598+
599+ return hash_size;
600+}
601diff --git a/src/efi_hash.h b/src/efi_hash.h
602new file mode 100644
603index 0000000..d09f793
604--- /dev/null
605+++ b/src/efi_hash.h
606@@ -0,0 +1,48 @@
607+/**
608+ * Copyright (C) 2020 Gary Lin <glin@suse.com>
609+ *
610+ * This program is free software: you can redistribute it and/or modify
611+ * it under the terms of the GNU General Public License as published by
612+ * the Free Software Foundation, either version 3 of the License, or
613+ * (at your option) any later version.
614+ *
615+ * This program is distributed in the hope that it will be useful,
616+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
617+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
618+ * GNU General Public License for more details.
619+ *
620+ * You should have received a copy of the GNU General Public License
621+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
622+ *
623+ * In addition, as a special exception, the copyright holders give
624+ * permission to link the code of portions of this program with the
625+ * OpenSSL library under certain conditions as described in each
626+ * individual source file, and distribute linked combinations
627+ * including the two.
628+ *
629+ * You must obey the GNU General Public License in all respects
630+ * for all of the code used other than OpenSSL. If you modify
631+ * file(s) with this exception, you may extend this exception to your
632+ * version of the file(s), but you are not obligated to do so. If you
633+ * do not wish to do so, delete this exception statement from your
634+ * version. If you delete this exception statement from all source
635+ * files in the program, then also delete it here.
636+ */
637+
638+#ifndef __EFI_HASH_H__
639+#define __EFI_HASH_H__
640+
641+#include <ctype.h>
642+#include <efivar.h>
643+
644+#include "mokutil.h"
645+
646+uint32_t efi_hash_size (const efi_guid_t *hash_type);
647+uint32_t signature_size (const efi_guid_t *hash_type);
648+int print_hash_array (const efi_guid_t *hash_type, const void *hash_array,
649+ const uint32_t array_size);
650+int match_hash_array (const efi_guid_t *hash_type, const void *hash,
651+ const void *hash_array, const uint32_t array_size);
652+int identify_hash_type (const char *hash_str, efi_guid_t *type);
653+
654+#endif /* __EFI_HASH_H__ */
655diff --git a/src/efi_x509.c b/src/efi_x509.c
656new file mode 100644
657index 0000000..4788740
658--- /dev/null
659+++ b/src/efi_x509.c
660@@ -0,0 +1,242 @@
661+/**
662+ * Copyright (C) 2020 Gary Lin <glin@suse.com>
663+ *
664+ * This program is free software: you can redistribute it and/or modify
665+ * it under the terms of the GNU General Public License as published by
666+ * the Free Software Foundation, either version 3 of the License, or
667+ * (at your option) any later version.
668+ *
669+ * This program is distributed in the hope that it will be useful,
670+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
671+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
672+ * GNU General Public License for more details.
673+ *
674+ * You should have received a copy of the GNU General Public License
675+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
676+ *
677+ * In addition, as a special exception, the copyright holders give
678+ * permission to link the code of portions of this program with the
679+ * OpenSSL library under certain conditions as described in each
680+ * individual source file, and distribute linked combinations
681+ * including the two.
682+ *
683+ * You must obey the GNU General Public License in all respects
684+ * for all of the code used other than OpenSSL. If you modify
685+ * file(s) with this exception, you may extend this exception to your
686+ * version of the file(s), but you are not obligated to do so. If you
687+ * do not wish to do so, delete this exception statement from your
688+ * version. If you delete this exception statement from all source
689+ * files in the program, then also delete it here.
690+ */
691+
692+#include <stdio.h>
693+#include <openssl/x509.h>
694+#include <openssl/x509v3.h>
695+
696+#include "efi_x509.h"
697+
698+int
699+print_x509 (const uint8_t *cert, const int cert_size)
700+{
701+ X509 *X509cert;
702+ EVP_MD_CTX *ctx;
703+ const EVP_MD *md;
704+ unsigned int md_len;
705+ const unsigned char *in = (const unsigned char *)cert;
706+ unsigned char fingerprint[EVP_MAX_MD_SIZE];
707+
708+ X509cert = d2i_X509 (NULL, &in, cert_size);
709+ if (X509cert == NULL) {
710+ fprintf (stderr, "Invalid X509 certificate\n");
711+ return -1;
712+ }
713+
714+ md = EVP_get_digestbyname ("SHA1");
715+ if(md == NULL) {
716+ fprintf (stderr, "Failed to get SHA1 digest\n");
717+ goto cleanup_cert;
718+ }
719+
720+ ctx = EVP_MD_CTX_create ();
721+ if (ctx == NULL) {
722+ fprintf (stderr, "Failed to create digest context\n");
723+ goto cleanup_cert;
724+ }
725+
726+ if (!EVP_DigestInit_ex (ctx, md, NULL)) {
727+ fprintf (stderr, "Failed to initialize digest context\n");
728+ goto cleanup_ctx;
729+ }
730+
731+ if (!EVP_DigestUpdate (ctx, cert, cert_size)) {
732+ fprintf (stderr, "Failed to hash into the digest context\n");
733+ goto cleanup_ctx;
734+ }
735+
736+ if (!EVP_DigestFinal_ex (ctx, fingerprint, &md_len)) {
737+ fprintf (stderr, "Failed to get digest value\n");
738+ goto cleanup_ctx;
739+ }
740+
741+ printf ("SHA1 Fingerprint: ");
742+ for (unsigned int i = 0; i < md_len; i++) {
743+ printf ("%02x", fingerprint[i]);
744+ if (i < md_len - 1)
745+ printf (":");
746+ }
747+ printf ("\n");
748+ X509_print_fp (stdout, X509cert);
749+
750+cleanup_ctx:
751+ EVP_MD_CTX_destroy (ctx);
752+cleanup_cert:
753+ X509_free (X509cert);
754+
755+ return 0;
756+}
757+
758+int
759+is_valid_cert (const uint8_t *cert, const uint32_t cert_size)
760+{
761+ X509 *X509cert;
762+
763+ if (cert == NULL)
764+ return 0;
765+
766+ X509cert = d2i_X509 (NULL, &cert, cert_size);
767+ if (X509cert == NULL)
768+ return 0;
769+
770+ X509_free (X509cert);
771+
772+ return 1;
773+}
774+
775+/**
776+ * Check whether the given CA cert is the immediate CA of the given cert
777+ **/
778+int
779+is_immediate_ca (const uint8_t *cert, const uint32_t cert_size,
780+ const uint8_t *ca_cert, const uint32_t ca_cert_size)
781+{
782+ X509 *X509cert = NULL;
783+ X509 *X509ca = NULL;
784+ X509_STORE *cert_store = NULL;
785+ X509_STORE_CTX *cert_ctx = NULL;
786+ int ret = 0;
787+
788+ if (cert == NULL || ca_cert == NULL)
789+ return 0;
790+
791+ if (EVP_add_digest (EVP_md5 ()) == 0)
792+ return 0;
793+ if (EVP_add_digest (EVP_sha1 ()) == 0)
794+ return 0;
795+ if (EVP_add_digest (EVP_sha256 ()) == 0)
796+ return 0;
797+
798+ X509cert = d2i_X509 (NULL, &cert, cert_size);
799+ if (X509cert == NULL)
800+ return 0;
801+
802+ X509ca = d2i_X509 (NULL, &ca_cert, ca_cert_size);
803+ if (X509ca == NULL)
804+ goto err;
805+
806+ cert_store = X509_STORE_new ();
807+ if (cert_store == NULL)
808+ goto err;
809+
810+ if (X509_STORE_add_cert (cert_store, X509ca) == 0)
811+ goto err;
812+
813+ /* Follow edk2 CryptoPkg to allow partial certificate chains and
814+ * disable time checks */
815+ X509_STORE_set_flags (cert_store,
816+ X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
817+
818+ cert_ctx = X509_STORE_CTX_new ();
819+ if (cert_ctx == NULL)
820+ goto err;
821+
822+ if (X509_STORE_CTX_init (cert_ctx, cert_store, X509cert, NULL) == 0)
823+ goto err;
824+
825+ /* Verify the cert */
826+ ret = X509_verify_cert (cert_ctx);
827+ /* Treat the exceptional error as FALSE */
828+ if (ret < 0)
829+ ret = 0;
830+ X509_STORE_CTX_cleanup (cert_ctx);
831+
832+err:
833+ if (X509cert)
834+ X509_free (X509cert);
835+
836+ if (X509ca)
837+ X509_free (X509ca);
838+
839+ if (cert_store)
840+ X509_STORE_free (cert_store);
841+
842+ if (cert_store)
843+ X509_STORE_CTX_free (cert_ctx);
844+
845+ return ret;
846+}
847+
848+/**
849+ * Get the Subject Key Identifier of the given certificate
850+ *
851+ * This function allocates the SKID string and the caller is responsible to
852+ * free the string.
853+ *
854+ * Return value:
855+ * - 0 : Success
856+ * - -1 : Error
857+ */
858+int
859+get_cert_skid(const uint8_t *cert, const uint32_t cert_size, char **skid)
860+{
861+ X509 *X509cert;
862+ const ASN1_OCTET_STRING *asn1_id;
863+ const uint8_t *data;
864+ int data_len, i;
865+ char *id_str, *ptr;
866+ int ret = -1;
867+
868+ X509cert = d2i_X509 (NULL, &cert, cert_size);
869+ if (X509cert == NULL) {
870+ fprintf (stderr, "invalid x509 certificate\n");
871+ goto out;
872+ }
873+
874+ asn1_id = X509_get0_subject_key_id (X509cert);
875+ if (asn1_id == NULL) {
876+ fprintf (stderr, "Failed to get Subject Key ID\n");
877+ goto out;
878+ }
879+
880+ data = ASN1_STRING_get0_data (asn1_id);
881+ data_len = ASN1_STRING_length (asn1_id);
882+
883+ id_str = malloc (data_len*2 + 1);
884+ if (id_str == NULL) {
885+ fprintf (stderr, "Failed to allocated id string\n");
886+ goto out;
887+ }
888+
889+ ptr = id_str;
890+ for (i = 0; i < data_len; i++) {
891+ snprintf (ptr, 3, "%02x", data[i]);
892+ ptr += 2;
893+ }
894+
895+ *skid = id_str;
896+ ret = 0;
897+out:
898+ if (X509cert)
899+ X509_free (X509cert);
900+
901+ return ret;
902+}
903diff --git a/src/efi_x509.h b/src/efi_x509.h
904new file mode 100644
905index 0000000..99e5d09
906--- /dev/null
907+++ b/src/efi_x509.h
908@@ -0,0 +1,43 @@
909+/**
910+ * Copyright (C) 2020 Gary Lin <glin@suse.com>
911+ *
912+ * This program is free software: you can redistribute it and/or modify
913+ * it under the terms of the GNU General Public License as published by
914+ * the Free Software Foundation, either version 3 of the License, or
915+ * (at your option) any later version.
916+ *
917+ * This program is distributed in the hope that it will be useful,
918+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
919+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
920+ * GNU General Public License for more details.
921+ *
922+ * You should have received a copy of the GNU General Public License
923+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
924+ *
925+ * In addition, as a special exception, the copyright holders give
926+ * permission to link the code of portions of this program with the
927+ * OpenSSL library under certain conditions as described in each
928+ * individual source file, and distribute linked combinations
929+ * including the two.
930+ *
931+ * You must obey the GNU General Public License in all respects
932+ * for all of the code used other than OpenSSL. If you modify
933+ * file(s) with this exception, you may extend this exception to your
934+ * version of the file(s), but you are not obligated to do so. If you
935+ * do not wish to do so, delete this exception statement from your
936+ * version. If you delete this exception statement from all source
937+ * files in the program, then also delete it here.
938+ */
939+
940+#ifndef __EFI_X509_H__
941+#define __EFI_X509_H__
942+
943+#include <stdint.h>
944+
945+int print_x509 (const uint8_t *cert, const int cert_size);
946+int is_valid_cert (const uint8_t *cert, const uint32_t cert_size);
947+int is_immediate_ca (const uint8_t *cert, const uint32_t cert_size,
948+ const uint8_t *ca_cert, const uint32_t ca_cert_size);
949+int get_cert_skid(const uint8_t *cert, const uint32_t cert_size, char **skid);
950+
951+#endif /* __EFI_X509_H__ */
952diff --git a/src/keyring.c b/src/keyring.c
953new file mode 100644
954index 0000000..9709efd
955--- /dev/null
956+++ b/src/keyring.c
957@@ -0,0 +1,111 @@
958+/**
959+ * Copyright (C) 2020 Gary Lin <glin@suse.com>
960+ *
961+ * This program is free software: you can redistribute it and/or modify
962+ * it under the terms of the GNU General Public License as published by
963+ * the Free Software Foundation, either version 3 of the License, or
964+ * (at your option) any later version.
965+ *
966+ * This program is distributed in the hope that it will be useful,
967+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
968+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
969+ * GNU General Public License for more details.
970+ *
971+ * You should have received a copy of the GNU General Public License
972+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
973+ *
974+ * In addition, as a special exception, the copyright holders give
975+ * permission to link the code of portions of this program with the
976+ * OpenSSL library under certain conditions as described in each
977+ * individual source file, and distribute linked combinations
978+ * including the two.
979+ *
980+ * You must obey the GNU General Public License in all respects
981+ * for all of the code used other than OpenSSL. If you modify
982+ * file(s) with this exception, you may extend this exception to your
983+ * version of the file(s), but you are not obligated to do so. If you
984+ * do not wish to do so, delete this exception statement from your
985+ * version. If you delete this exception statement from all source
986+ * files in the program, then also delete it here.
987+ */
988+
989+#include <stdio.h>
990+#include <stdlib.h>
991+#include <errno.h>
992+#include <string.h>
993+
994+#include <keyutils.h>
995+
996+#include "keyring.h"
997+
998+/**
999+ * Match the x509v3 Subject Key ID in the descriptions of the kernel built-in
1000+ * trusted keys keyring
1001+ *
1002+ * return value
1003+ * - 0 : not matched
1004+ * - 1 : matched
1005+ * - -1 : error
1006+ */
1007+int
1008+match_skid_in_trusted_keyring (const char *skid)
1009+{
1010+ key_serial_t ring_id, key_id, *key_ptr;
1011+ void *keylist = NULL;
1012+ int count;
1013+ char buffer[1024];
1014+ char *ptr;
1015+ long buf_size;
1016+ int ret = -1;
1017+
1018+ if (skid == NULL)
1019+ return -1;
1020+
1021+ /* Find the keyring ID of the kernel trusted keys */
1022+ ring_id = find_key_by_type_and_desc("keyring", ".builtin_trusted_keys", 0);
1023+ if (ring_id < 0) {
1024+ fprintf(stderr, "Failed to accesss kernel trusted keyring: %m\n");
1025+ goto out;
1026+ }
1027+
1028+ count = keyctl_read_alloc(ring_id, &keylist);
1029+ if (count < 0) {
1030+ fprintf(stderr, "Failed to read kernel trusted keyring\n");
1031+ goto out;
1032+ }
1033+
1034+ count /= sizeof(key_serial_t);
1035+ if (count == 0) {
1036+ /* The keyring is empty */
1037+ ret = 0;
1038+ goto out;
1039+ }
1040+
1041+ /* Iterate the keylist and match SKID */
1042+ key_ptr = keylist;
1043+ do {
1044+ key_id = *key_ptr++;
1045+
1046+ buf_size = keyctl_describe(key_id, buffer, sizeof(buffer));
1047+ if (buf_size < 0) {
1048+ fprintf(stderr, "key %X inaccessible %m\n", key_id);
1049+ goto out;
1050+ }
1051+
1052+ /* Check if SKID is in the description */
1053+ ptr = strstr(buffer, skid);
1054+ if (ptr && *(ptr + strlen(skid)) == '\0') {
1055+ /* Matched */
1056+ ret = 1;
1057+ goto out;
1058+ }
1059+ } while (--count);
1060+
1061+ ret = 0;
1062+out:
1063+ if (keylist)
1064+ free(keylist);
1065+
1066+ return ret;
1067+
1068+}
1069diff --git a/src/keyring.h b/src/keyring.h
1070new file mode 100644
1071index 0000000..44127cf
1072--- /dev/null
1073+++ b/src/keyring.h
1074@@ -0,0 +1,37 @@
1075+/**
1076+ * Copyright (C) 2020 Gary Lin <glin@suse.com>
1077+ *
1078+ * This program is free software: you can redistribute it and/or modify
1079+ * it under the terms of the GNU General Public License as published by
1080+ * the Free Software Foundation, either version 3 of the License, or
1081+ * (at your option) any later version.
1082+ *
1083+ * This program is distributed in the hope that it will be useful,
1084+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1085+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1086+ * GNU General Public License for more details.
1087+ *
1088+ * You should have received a copy of the GNU General Public License
1089+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1090+ *
1091+ * In addition, as a special exception, the copyright holders give
1092+ * permission to link the code of portions of this program with the
1093+ * OpenSSL library under certain conditions as described in each
1094+ * individual source file, and distribute linked combinations
1095+ * including the two.
1096+ *
1097+ * You must obey the GNU General Public License in all respects
1098+ * for all of the code used other than OpenSSL. If you modify
1099+ * file(s) with this exception, you may extend this exception to your
1100+ * version of the file(s), but you are not obligated to do so. If you
1101+ * do not wish to do so, delete this exception statement from your
1102+ * version. If you delete this exception statement from all source
1103+ * files in the program, then also delete it here.
1104+ */
1105+
1106+#ifndef __KEYRING_H__
1107+#define __KEYRING_H__
1108+
1109+int match_skid_in_trusted_keyring (const char *skid);
1110+
1111+#endif /* __KEYRING_H__ */
1112diff --git a/src/mokutil.c b/src/mokutil.c
1113index e2d567d..5d725c9 100644
1114--- a/src/mokutil.c
1115+++ b/src/mokutil.c
1116@@ -1,5 +1,5 @@
1117 /**
1118- * Copyright (C) 2012-2014 Gary Lin <glin@suse.com>
1119+ * Copyright (C) 2012-2020 Gary Lin <glin@suse.com>
1120 * Copyright (C) 2012 Matthew Garrett <mjg@redhat.com>
1121 *
1122 * This program is free software: you can redistribute it and/or modify
1123@@ -29,30 +29,29 @@
1124 * version. If you delete this exception statement from all source
1125 * files in the program, then also delete it here.
1126 */
1127-#include <ctype.h>
1128 #include <dirent.h>
1129 #include <errno.h>
1130 #include <stdio.h>
1131 #include <stdlib.h>
1132 #include <string.h>
1133 #include <strings.h>
1134-#include <sys/types.h>
1135-#include <sys/stat.h>
1136-#include <fcntl.h>
1137 #include <unistd.h>
1138-#include <termios.h>
1139 #include <getopt.h>
1140 #include <shadow.h>
1141 #include <sys/time.h>
1142
1143 #include <openssl/sha.h>
1144-#include <openssl/x509.h>
1145
1146 #include <crypt.h>
1147 #include <efivar.h>
1148
1149+#include "mokutil.h"
1150 #include "signature.h"
1151+#include "efi_hash.h"
1152+#include "efi_x509.h"
1153+#include "keyring.h"
1154 #include "password-crypt.h"
1155+#include "util.h"
1156
1157 #define PASSWORD_MAX 256
1158 #define PASSWORD_MIN 1
1159@@ -76,65 +75,27 @@
1160 #define TEST_KEY (1 << 14)
1161 #define RESET (1 << 15)
1162 #define GENERATE_PW_HASH (1 << 16)
1163-#define SIMPLE_HASH (1 << 17)
1164-#define IGNORE_DB (1 << 18)
1165-#define USE_DB (1 << 19)
1166-#define MOKX (1 << 20)
1167-#define IMPORT_HASH (1 << 21)
1168-#define DELETE_HASH (1 << 22)
1169-#define VERBOSITY (1 << 23)
1170-#define TIMEOUT (1 << 24)
1171+#define IGNORE_DB (1 << 17)
1172+#define USE_DB (1 << 18)
1173+#define MOKX (1 << 19)
1174+#define IMPORT_HASH (1 << 20)
1175+#define DELETE_HASH (1 << 21)
1176+#define VERBOSITY (1 << 22)
1177+#define TIMEOUT (1 << 23)
1178+#define LIST_SBAT (1 << 24)
1179+#define FB_VERBOSITY (1 << 25)
1180+#define FB_NOREBOOT (1 << 26)
1181+#define TRUST_MOK (1 << 27)
1182+#define UNTRUST_MOK (1 << 28)
1183+#define SET_SBAT (1 << 29)
1184
1185 #define DEFAULT_CRYPT_METHOD SHA512_BASED
1186 #define DEFAULT_SALT_SIZE SHA512_SALT_MAX
1187 #define SETTINGS_LEN (DEFAULT_SALT_SIZE*2)
1188 #define BUF_SIZE 300
1189
1190-typedef unsigned long efi_status_t;
1191-typedef uint8_t efi_bool_t;
1192-typedef wchar_t efi_char16_t; /* UNICODE character */
1193-
1194-static int use_simple_hash;
1195-
1196-typedef enum {
1197- DELETE_MOK = 0,
1198- ENROLL_MOK,
1199- DELETE_BLACKLIST,
1200- ENROLL_BLACKLIST,
1201-} MokRequest;
1202-
1203-typedef enum {
1204- MOK_LIST_RT = 0,
1205- MOK_LIST_X_RT,
1206- PK,
1207- KEK,
1208- DB,
1209- DBX,
1210-} DBName;
1211-
1212-const char *db_var_name[] = {
1213- [MOK_LIST_RT] = "MokListRT",
1214- [MOK_LIST_X_RT] = "MokListXRT",
1215- [PK] = "PK",
1216- [KEK] = "KEK",
1217- [DB] = "db",
1218- [DBX] = "dbx",
1219-};
1220-
1221-const char *db_friendly_name[] = {
1222- [MOK_LIST_RT] = "MOK",
1223- [MOK_LIST_X_RT] = "MOKX",
1224- [PK] = "PK",
1225- [KEK] = "KEK",
1226- [DB] = "DB",
1227- [DBX] = "DBX",
1228-};
1229-
1230-typedef struct {
1231- EFI_SIGNATURE_LIST *header;
1232- uint32_t mok_size;
1233- void *mok;
1234-} MokListNode;
1235+static int force_ca_check;
1236+static int check_keyring;
1237
1238 typedef struct {
1239 uint32_t mok_toggle_state;
1240@@ -171,266 +132,28 @@ print_help ()
1241 printf (" --import-hash <hash>\t\t\tImport a hash into MOK or MOKX\n");
1242 printf (" --delete-hash <hash>\t\t\tDelete a hash in MOK or MOKX\n");
1243 printf (" --set-verbosity <true/false>\t\tSet the verbosity bit for shim\n");
1244+ printf (" --set-fallback-verbosity <true/false>\t\tSet the verbosity bit for fallback\n");
1245+ printf (" --set-fallback-noreboot <true/false>\t\tPrevent fallback from automatically rebooting\n");
1246+ printf (" --trust-mok\t\t\t\tTrust MOK keys within the kernel keyring\n");
1247+ printf (" --untrust-mok\t\t\t\tDo not trust MOK keys\n");
1248+ printf (" --set-sbat-policy <latest/previous/delete>\t\tApply Latest, Previous, or Blank SBAT revocations\n");
1249 printf (" --pk\t\t\t\t\tList the keys in PK\n");
1250 printf (" --kek\t\t\t\t\tList the keys in KEK\n");
1251 printf (" --db\t\t\t\t\tList the keys in db\n");
1252 printf (" --dbx\t\t\t\t\tList the keys in dbx\n");
1253 printf (" --timeout <-1,0..0x7fff>\t\tSet the timeout for MOK prompt\n");
1254+ printf (" --list-sbat-revocations\t\t\t\tList the entries in SBAT\n");
1255 printf ("\n");
1256 printf ("Supplimentary Options:\n");
1257 printf (" --hash-file <hash file>\t\tUse the specific password hash\n");
1258 printf (" --root-pw\t\t\t\tUse the root password\n");
1259- printf (" --simple-hash\t\t\t\tUse the old password hash method\n");
1260 printf (" --mokx\t\t\t\tManipulate the MOK blacklist\n");
1261+ printf (" --ca-check\t\t\t\tCheck if CA of the key is enrolled/blocked\n");
1262+ printf (" --ignore-keyring\t\t\tDon't check if the key is the kernel keyring\n");
1263 }
1264
1265 static int
1266-test_and_delete_var (const char *var_name)
1267-{
1268- size_t size;
1269- int ret;
1270-
1271- ret = efi_get_variable_size (efi_guid_shim, var_name, &size);
1272- if (ret < 0) {
1273- if (errno == ENOENT)
1274- return 0;
1275- fprintf (stderr, "Failed to access variable \"%s\": %m\n",
1276- var_name);
1277- }
1278-
1279- /* Attempt to delete it no matter what, problem efi_get_variable_size()
1280- * had, unless it just doesn't exist anyway. */
1281- if (!(ret < 0 && errno == ENOENT)) {
1282- if (efi_del_variable (efi_guid_shim, var_name) < 0)
1283- fprintf (stderr, "Failed to unset \"%s\": %m\n", var_name);
1284- }
1285-
1286- return ret;
1287-}
1288-
1289-static unsigned long
1290-efichar_from_char (efi_char16_t *dest, const char *src, size_t dest_len)
1291-{
1292- unsigned int i, src_len = strlen(src);
1293- for (i=0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) {
1294- dest[i] = src[i];
1295- }
1296- dest[i] = 0;
1297- return i * sizeof(*dest);
1298-}
1299-
1300-static uint32_t
1301-efi_hash_size (const efi_guid_t *hash_type)
1302-{
1303- if (efi_guid_cmp (hash_type, &efi_guid_sha1) == 0) {
1304- return SHA_DIGEST_LENGTH;
1305- } else if (efi_guid_cmp (hash_type, &efi_guid_sha224) == 0) {
1306- return SHA224_DIGEST_LENGTH;
1307- } else if (efi_guid_cmp (hash_type, &efi_guid_sha256) == 0) {
1308- return SHA256_DIGEST_LENGTH;
1309- } else if (efi_guid_cmp (hash_type, &efi_guid_sha384) == 0) {
1310- return SHA384_DIGEST_LENGTH;
1311- } else if (efi_guid_cmp (hash_type, &efi_guid_sha512) == 0) {
1312- return SHA512_DIGEST_LENGTH;
1313- }
1314-
1315- return 0;
1316-}
1317-
1318-static uint32_t
1319-signature_size (const efi_guid_t *hash_type)
1320-{
1321- uint32_t hash_size;
1322-
1323- hash_size = efi_hash_size (hash_type);
1324- if (hash_size)
1325- return (hash_size + sizeof(efi_guid_t));
1326-
1327- return 0;
1328-}
1329-
1330-static MokListNode*
1331-build_mok_list (void *data, unsigned long data_size, uint32_t *mok_num)
1332-{
1333- MokListNode *list = NULL;
1334- MokListNode *list_new = NULL;
1335- EFI_SIGNATURE_LIST *CertList = data;
1336- EFI_SIGNATURE_DATA *Cert;
1337- unsigned long dbsize = data_size;
1338- unsigned long count = 0;
1339- void *end = data + data_size;
1340-
1341- while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
1342- if ((void *)(CertList + 1) > end ||
1343- CertList->SignatureListSize == 0 ||
1344- CertList->SignatureListSize <= CertList->SignatureSize) {
1345- fprintf (stderr, "Corrupted signature list\n");
1346- if (list)
1347- free (list);
1348- return NULL;
1349- }
1350-
1351- if ((efi_guid_cmp (&CertList->SignatureType, &efi_guid_x509_cert) != 0) &&
1352- (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha1) != 0) &&
1353- (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha224) != 0) &&
1354- (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha256) != 0) &&
1355- (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha384) != 0) &&
1356- (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha512) != 0)) {
1357- dbsize -= CertList->SignatureListSize;
1358- CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList +
1359- CertList->SignatureListSize);
1360- continue;
1361- }
1362-
1363- if ((efi_guid_cmp (&CertList->SignatureType, &efi_guid_x509_cert) != 0) &&
1364- (CertList->SignatureSize != signature_size (&CertList->SignatureType))) {
1365- dbsize -= CertList->SignatureListSize;
1366- CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList +
1367- CertList->SignatureListSize);
1368- continue;
1369- }
1370-
1371- Cert = (EFI_SIGNATURE_DATA *) (((uint8_t *) CertList) +
1372- sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1373-
1374- if ((void *)(Cert + 1) > end ||
1375- CertList->SignatureSize <= sizeof(efi_guid_t)) {
1376- if (list)
1377- free (list);
1378- fprintf (stderr, "Corrupted signature\n");
1379- return NULL;
1380- }
1381-
1382- list_new = realloc(list, sizeof(MokListNode) * (count + 1));
1383- if (list_new) {
1384- list = list_new;
1385- } else {
1386- if (list)
1387- free (list);
1388- fprintf(stderr, "Unable to allocate MOK list\n");
1389- return NULL;
1390- }
1391-
1392- list[count].header = CertList;
1393- if (efi_guid_cmp (&CertList->SignatureType, &efi_guid_x509_cert) == 0) {
1394- /* X509 certificate */
1395- list[count].mok_size = CertList->SignatureSize -
1396- sizeof(efi_guid_t);
1397- list[count].mok = (void *)Cert->SignatureData;
1398- } else {
1399- /* hash array */
1400- list[count].mok_size = CertList->SignatureListSize -
1401- sizeof(EFI_SIGNATURE_LIST) -
1402- CertList->SignatureHeaderSize;
1403- list[count].mok = (void *)Cert;
1404- }
1405-
1406- if (list[count].mok_size > (unsigned long)end -
1407- (unsigned long)list[count].mok) {
1408- fprintf (stderr, "Corrupted data\n");
1409- free (list);
1410- return NULL;
1411- }
1412-
1413- count++;
1414- dbsize -= CertList->SignatureListSize;
1415- CertList = (EFI_SIGNATURE_LIST *) ((uint8_t *) CertList +
1416- CertList->SignatureListSize);
1417- }
1418-
1419- *mok_num = count;
1420-
1421- return list;
1422-}
1423-
1424-static int
1425-print_x509 (char *cert, int cert_size)
1426-{
1427- X509 *X509cert;
1428- BIO *cert_bio;
1429- SHA_CTX ctx;
1430- uint8_t fingerprint[SHA_DIGEST_LENGTH];
1431-
1432- cert_bio = BIO_new (BIO_s_mem ());
1433- BIO_write (cert_bio, cert, cert_size);
1434- if (cert_bio == NULL) {
1435- fprintf (stderr, "Failed to write BIO\n");
1436- return -1;
1437- }
1438-
1439- X509cert = d2i_X509_bio (cert_bio, NULL);
1440- if (X509cert == NULL) {
1441- fprintf (stderr, "Invalid X509 certificate\n");
1442- return -1;
1443- }
1444-
1445- SHA1_Init (&ctx);
1446- SHA1_Update (&ctx, cert, cert_size);
1447- SHA1_Final (fingerprint, &ctx);
1448-
1449- printf ("SHA1 Fingerprint: ");
1450- for (unsigned int i = 0; i < SHA_DIGEST_LENGTH; i++) {
1451- printf ("%02x", fingerprint[i]);
1452- if (i < SHA_DIGEST_LENGTH - 1)
1453- printf (":");
1454- }
1455- printf ("\n");
1456- X509_print_fp (stdout, X509cert);
1457-
1458- BIO_free (cert_bio);
1459-
1460- return 0;
1461-}
1462-
1463-static int
1464-print_hash_array (efi_guid_t *hash_type, void *hash_array, uint32_t array_size)
1465-{
1466- uint32_t hash_size, remain;
1467- uint32_t sig_size;
1468- uint8_t *hash;
1469- char *name;
1470-
1471- if (!hash_array || array_size == 0) {
1472- fprintf (stderr, "invalid hash array\n");
1473- return -1;
1474- }
1475-
1476- int rc = efi_guid_to_name(hash_type, &name);
1477- if (rc < 0 || isxdigit(name[0])) {
1478- if (name)
1479- free(name);
1480- fprintf (stderr, "unknown hash type\n");
1481- return -1;
1482- }
1483-
1484- hash_size = efi_hash_size (hash_type);
1485- sig_size = hash_size + sizeof(efi_guid_t);
1486-
1487- printf (" [%s]\n", name);
1488- free(name);
1489- remain = array_size;
1490- hash = (uint8_t *)hash_array;
1491-
1492- while (remain > 0) {
1493- if (remain < sig_size) {
1494- fprintf (stderr, "invalid array size\n");
1495- return -1;
1496- }
1497-
1498- printf (" ");
1499- hash += sizeof(efi_guid_t);
1500- for (unsigned int i = 0; i<hash_size; i++)
1501- printf ("%02x", *(hash + i));
1502- printf ("\n");
1503- hash += hash_size;
1504- remain -= sig_size;
1505- }
1506-
1507- return 0;
1508-}
1509-
1510-static int
1511-list_keys (uint8_t *data, size_t data_size)
1512+list_keys (const uint8_t *data, const size_t data_size)
1513 {
1514 uint32_t mok_num;
1515 MokListNode *list;
1516@@ -442,10 +165,11 @@ list_keys (uint8_t *data, size_t data_size)
1517
1518 for (unsigned int i = 0; i < mok_num; i++) {
1519 printf ("[key %d]\n", i+1);
1520- if (efi_guid_cmp (&list[i].header->SignatureType, &efi_guid_x509_cert) == 0) {
1521- print_x509 ((char *)list[i].mok, list[i].mok_size);
1522+ efi_guid_t sigtype = list[i].header->SignatureType;
1523+ if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) == 0) {
1524+ print_x509 (list[i].mok, list[i].mok_size);
1525 } else {
1526- print_hash_array (&list[i].header->SignatureType,
1527+ print_hash_array (&sigtype,
1528 list[i].mok, list[i].mok_size);
1529 }
1530 if (i < mok_num - 1)
1531@@ -457,222 +181,53 @@ list_keys (uint8_t *data, size_t data_size)
1532 return 0;
1533 }
1534
1535-/* match the hash in the hash array and return the index if matched */
1536-static int
1537-match_hash_array (const efi_guid_t *hash_type, const void *hash,
1538- const void *hash_array, const uint32_t array_size)
1539-{
1540- uint32_t hash_size, hash_count;
1541- uint32_t sig_size;
1542- void *ptr;
1543-
1544- hash_size = efi_hash_size (hash_type);
1545- if (!hash_size)
1546- return -1;
1547-
1548- sig_size = hash_size + sizeof(efi_guid_t);
1549- if ((array_size % sig_size) != 0) {
1550- fprintf (stderr, "invalid hash array size\n");
1551- return -1;
1552- }
1553-
1554- ptr = (void *)hash_array;
1555- hash_count = array_size / sig_size;
1556- for (unsigned int i = 0; i < hash_count; i++) {
1557- ptr += sizeof(efi_guid_t);
1558- if (memcmp (ptr, hash, hash_size) == 0)
1559- return i;
1560- ptr += hash_size;
1561- }
1562-
1563- return -1;
1564-}
1565-
1566-static int
1567-delete_data_from_list (const efi_guid_t *var_guid, const char *var_name,
1568- const efi_guid_t *type, void *data, uint32_t data_size)
1569-{
1570- uint8_t *var_data = NULL;
1571- size_t var_data_size = 0;
1572- uint32_t attributes;
1573- MokListNode *list;
1574- uint32_t mok_num, total, remain;
1575- void *end, *start = NULL;
1576- int del_ind, ret = 0;
1577- uint32_t sig_list_size, sig_size;
1578-
1579- if (!var_name || !data || data_size == 0)
1580- return 0;
1581-
1582- ret = efi_get_variable (*var_guid, var_name, &var_data, &var_data_size,
1583- &attributes);
1584- if (ret < 0) {
1585- if (errno == ENOENT)
1586- return 0;
1587- fprintf (stderr, "Failed to read variable \"%s\": %m\n",
1588- var_name);
1589- return -1;
1590- }
1591-
1592- total = var_data_size;
1593-
1594- list = build_mok_list (var_data, var_data_size, &mok_num);
1595- if (list == NULL)
1596- goto done;
1597-
1598- remain = total;
1599- for (unsigned int i = 0; i < mok_num; i++) {
1600- remain -= list[i].header->SignatureListSize;
1601- if (efi_guid_cmp (&list[i].header->SignatureType, type) != 0)
1602- continue;
1603-
1604- sig_list_size = list[i].header->SignatureListSize;
1605-
1606- if (efi_guid_cmp (type, &efi_guid_x509_cert) == 0) {
1607- if (list[i].mok_size != data_size)
1608- continue;
1609-
1610- if (memcmp (list[i].mok, data, data_size) == 0) {
1611- /* Remove this key */
1612- start = (void *)list[i].header;
1613- end = start + sig_list_size;
1614- total -= sig_list_size;
1615- break;
1616- }
1617- } else {
1618- del_ind = match_hash_array (type, data, list[i].mok,
1619- list[i].mok_size);
1620- if (del_ind < 0)
1621- continue;
1622-
1623- start = (void *)list[i].header;
1624- sig_size = signature_size (type);
1625- if (sig_list_size == (sizeof(EFI_SIGNATURE_LIST) + sig_size)) {
1626- /* Only one hash in the list */
1627- end = start + sig_list_size;
1628- total -= sig_list_size;
1629- } else {
1630- /* More than one hash in the list */
1631- start += sizeof(EFI_SIGNATURE_LIST) + sig_size * del_ind;
1632- end = start + sig_size;
1633- total -= sig_size;
1634- list[i].header->SignatureListSize -= sig_size;
1635- remain += sig_list_size - sizeof(EFI_SIGNATURE_LIST) -
1636- (del_ind + 1) * sig_size;
1637- }
1638- break;
1639- }
1640- }
1641-
1642- /* the key or hash is not in this list */
1643- if (start == NULL)
1644- return 0;
1645-
1646- /* all keys are removed */
1647- if (total == 0) {
1648- test_and_delete_var (var_name);
1649-
1650- /* delete the password */
1651- if (strcmp (var_name, "MokNew") == 0)
1652- test_and_delete_var ("MokAuth");
1653- else if (strcmp (var_name, "MokXNew") == 0)
1654- test_and_delete_var ("MokXAuth");
1655- else if (strcmp (var_name, "MokDel") == 0)
1656- test_and_delete_var ("MokDelAuth");
1657- else if (strcmp (var_name, "MokXDel") == 0)
1658- test_and_delete_var ("MokXDelAuth");
1659-
1660- ret = 1;
1661- goto done;
1662- }
1663-
1664- /* remove the key or hash */
1665- if (remain > 0)
1666- memmove (start, end, remain);
1667-
1668- attributes = EFI_VARIABLE_NON_VOLATILE
1669- | EFI_VARIABLE_BOOTSERVICE_ACCESS
1670- | EFI_VARIABLE_RUNTIME_ACCESS;
1671- ret = efi_set_variable (*var_guid, var_name,
1672- var_data, total, attributes,
1673- S_IRUSR | S_IWUSR);
1674- if (ret < 0) {
1675- fprintf (stderr, "Failed to write variable \"%s\": %m\n",
1676- var_name);
1677- goto done;
1678- }
1679- efi_chmod_variable(*var_guid, var_name, S_IRUSR | S_IWUSR);
1680-
1681- ret = 1;
1682-done:
1683- if (list)
1684- free (list);
1685- free (var_data);
1686-
1687- return ret;
1688-}
1689-
1690 static int
1691 list_keys_in_var (const char *var_name, const efi_guid_t guid)
1692 {
1693 uint8_t *data = NULL;
1694- size_t data_size;
1695+ char varname[] = "implausibly-long-mok-variable-name";
1696+ size_t data_sz, i, varname_sz = sizeof(varname);
1697 uint32_t attributes;
1698 int ret;
1699
1700- ret = efi_get_variable (guid, var_name, &data, &data_size, &attributes);
1701- if (ret < 0) {
1702- if (errno == ENOENT) {
1703- printf ("%s is empty\n", var_name);
1704- return 0;
1705- }
1706-
1707- fprintf (stderr, "Failed to read %s: %m\n", var_name);
1708- return -1;
1709+ ret = mok_get_variable(var_name, &data, &data_sz);
1710+ if (ret >= 0) {
1711+ ret = list_keys (data, data_sz);
1712+ free(data);
1713+ return ret;
1714 }
1715
1716- ret = list_keys (data, data_size);
1717- free (data);
1718-
1719- return ret;
1720-}
1721-
1722-static int
1723-read_hidden_line (char **line, size_t *n)
1724-{
1725- struct termios old, new;
1726- int nread;
1727- int isTTY = isatty(fileno (stdin));
1728-
1729- if (isTTY) {
1730- /* Turn echoing off and fail if we can't. */
1731- if (tcgetattr (fileno (stdin), &old) != 0)
1732- return -1;
1733-
1734- new = old;
1735- new.c_lflag &= ~ECHO;
1736-
1737- if (tcsetattr (fileno (stdin), TCSAFLUSH, &new) != 0)
1738- return -1;
1739- }
1740+ for (i = 0; i < SIZE_MAX; i++) {
1741+ if (i == 0) {
1742+ snprintf(varname, varname_sz, "%s", var_name);
1743+ } else {
1744+ snprintf(varname, varname_sz, "%s%zu", var_name, i);
1745+ }
1746
1747- /* Read the password. */
1748- nread = getline (line, n, stdin);
1749+ ret = efi_get_variable (guid, varname, &data, &data_sz,
1750+ &attributes);
1751+ if (ret < 0)
1752+ return 0;
1753
1754- if (isTTY) {
1755- /* Restore terminal. */
1756- (void) tcsetattr (fileno (stdin), TCSAFLUSH, &old);
1757+ ret = list_keys (data, data_sz);
1758+ free(data);
1759+ /*
1760+ * If ret is < 0, the next one will error as well.
1761+ * If ret is 0, we need to test the next variable.
1762+ * If it's 1, that's a real answer.
1763+ */
1764+ if (ret < 0)
1765+ return 0;
1766+ if (ret > 0)
1767+ return ret;
1768 }
1769
1770- /* Remove the newline */
1771- (*line)[nread-1] = '\0';
1772-
1773- return nread-1;
1774+ return 0;
1775 }
1776
1777 static int
1778 get_password (char **password, unsigned int *len,
1779- unsigned int min, unsigned int max)
1780+ const unsigned int min, const unsigned int max)
1781 {
1782 char *password_1, *password_2;
1783 unsigned int len_1, len_2;
1784@@ -732,34 +287,8 @@ error:
1785 return ret;
1786 }
1787
1788-static int
1789-generate_auth (void *new_list, int list_len, char *password,
1790- unsigned int pw_len, uint8_t *auth)
1791-{
1792- efi_char16_t efichar_pass[PASSWORD_MAX+1];
1793- unsigned long efichar_len;
1794- SHA256_CTX ctx;
1795-
1796- if (!password || !auth)
1797- return -1;
1798-
1799- efichar_len = efichar_from_char (efichar_pass, password,
1800- pw_len * sizeof(efi_char16_t));
1801-
1802- SHA256_Init (&ctx);
1803-
1804- if (new_list)
1805- SHA256_Update (&ctx, new_list, list_len);
1806-
1807- SHA256_Update (&ctx, efichar_pass, efichar_len);
1808-
1809- SHA256_Final (auth, &ctx);
1810-
1811- return 0;
1812-}
1813-
1814 static void
1815-generate_salt (char salt[], unsigned int salt_size)
1816+generate_pw_salt (char salt[], const unsigned int salt_size)
1817 {
1818 struct timeval tv;
1819 char *rand_str;
1820@@ -780,7 +309,8 @@ generate_salt (char salt[], unsigned int salt_size)
1821 }
1822
1823 static int
1824-generate_hash (pw_crypt_t *pw_crypt, char *password, unsigned int pw_len)
1825+generate_pw_crypt (pw_crypt_t *pw_crypt, const char *password,
1826+ const unsigned int pw_len)
1827 {
1828 pw_crypt_t new_crypt;
1829 char settings[SETTINGS_LEN];
1830@@ -796,8 +326,8 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, unsigned int pw_len)
1831 if (!prefix)
1832 return -1;
1833
1834- pw_crypt->salt_size = get_salt_size (pw_crypt->method);
1835- generate_salt ((char *)pw_crypt->salt, pw_crypt->salt_size);
1836+ pw_crypt->salt_size = get_pw_salt_size (pw_crypt->method);
1837+ generate_pw_salt ((char *)pw_crypt->salt, pw_crypt->salt_size);
1838
1839 memset (settings, 0, sizeof (settings));
1840 next = stpncpy (settings, prefix, settings_len);
1841@@ -816,7 +346,7 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, unsigned int pw_len)
1842 if (decode_pass (crypt_string, &new_crypt) < 0)
1843 return -1;
1844
1845- hash_len = get_hash_size (new_crypt.method);
1846+ hash_len = get_pw_hash_size (new_crypt.method);
1847 if (hash_len < 0)
1848 return -1;
1849 memcpy (pw_crypt->hash, new_crypt.hash, hash_len);
1850@@ -831,7 +361,7 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, unsigned int pw_len)
1851 }
1852
1853 static int
1854-get_hash_from_file (const char *file, pw_crypt_t *pw_crypt)
1855+get_pw_hash_from_file (const char *file, pw_crypt_t *pw_crypt)
1856 {
1857 char string[BUF_SIZE];
1858 ssize_t read_len = 0;
1859@@ -890,14 +420,11 @@ get_password_from_shadow (pw_crypt_t *pw_crypt)
1860 }
1861
1862 static int
1863-update_request (void *new_list, int list_len, MokRequest req,
1864- const char *hash_file, const int root_pw)
1865+update_request (void *new_list, const int list_len, const MokRequest req,
1866+ const char *pw_hash_file, const int root_pw)
1867 {
1868- uint8_t *data;
1869- size_t data_size;
1870 const char *req_name, *auth_name;
1871 pw_crypt_t pw_crypt;
1872- uint8_t auth[SHA256_DIGEST_LENGTH];
1873 char *password = NULL;
1874 unsigned int pw_len;
1875 int auth_ret;
1876@@ -930,8 +457,8 @@ update_request (void *new_list, int list_len, MokRequest req,
1877 return -1;
1878 }
1879
1880- if (hash_file) {
1881- if (get_hash_from_file (hash_file, &pw_crypt) < 0) {
1882+ if (pw_hash_file) {
1883+ if (get_pw_hash_from_file (pw_hash_file, &pw_crypt) < 0) {
1884 fprintf (stderr, "Failed to read hash\n");
1885 goto error;
1886 }
1887@@ -946,12 +473,7 @@ update_request (void *new_list, int list_len, MokRequest req,
1888 goto error;
1889 }
1890
1891- if (!use_simple_hash) {
1892- auth_ret = generate_hash (&pw_crypt, password, pw_len);
1893- } else {
1894- auth_ret = generate_auth (new_list, list_len, password,
1895- pw_len, auth);
1896- }
1897+ auth_ret = generate_pw_crypt (&pw_crypt, password, pw_len);
1898 if (auth_ret < 0) {
1899 fprintf (stderr, "Couldn't generate hash\n");
1900 goto error;
1901@@ -960,12 +482,10 @@ update_request (void *new_list, int list_len, MokRequest req,
1902
1903 if (new_list) {
1904 /* Write MokNew, MokDel, MokXNew, or MokXDel*/
1905- data = new_list;
1906- data_size = list_len;
1907-
1908- if (efi_set_variable (efi_guid_shim, req_name,
1909- data, data_size, attributes,
1910- S_IRUSR | S_IWUSR) < 0) {
1911+ ret = efi_set_variable (efi_guid_shim, req_name,
1912+ new_list, list_len, attributes,
1913+ S_IRUSR | S_IWUSR);
1914+ if (ret < 0) {
1915 switch (req) {
1916 case ENROLL_MOK:
1917 fprintf (stderr, "Failed to enroll new keys\n");
1918@@ -983,22 +503,16 @@ update_request (void *new_list, int list_len, MokRequest req,
1919 goto error;
1920 }
1921 } else {
1922- test_and_delete_var (req_name);
1923+ test_and_delete_mok_var (req_name);
1924 }
1925
1926 /* Write MokAuth, MokDelAuth, MokXAuth, or MokXDelAuth */
1927- if (!use_simple_hash) {
1928- data = (void *)&pw_crypt;
1929- data_size = PASSWORD_CRYPT_SIZE;
1930- } else {
1931- data = (void *)auth;
1932- data_size = SHA256_DIGEST_LENGTH;
1933- }
1934-
1935- if (efi_set_variable (efi_guid_shim, auth_name, data, data_size,
1936- attributes, S_IRUSR | S_IWUSR) < 0) {
1937+ ret = efi_set_variable (efi_guid_shim, auth_name, (void *)&pw_crypt,
1938+ PASSWORD_CRYPT_SIZE, attributes,
1939+ S_IRUSR | S_IWUSR);
1940+ if (ret < 0) {
1941 fprintf (stderr, "Failed to write %s\n", auth_name);
1942- test_and_delete_var (req_name);
1943+ test_and_delete_mok_var (req_name);
1944 goto error;
1945 }
1946
1947@@ -1010,45 +524,15 @@ error:
1948 }
1949
1950 static int
1951-is_valid_cert (void *cert, uint32_t cert_size)
1952-{
1953- X509 *X509cert;
1954- BIO *cert_bio;
1955-
1956- cert_bio = BIO_new (BIO_s_mem ());
1957- BIO_write (cert_bio, cert, cert_size);
1958- if (cert_bio == NULL) {
1959- return 0;
1960- }
1961-
1962- X509cert = d2i_X509_bio (cert_bio, NULL);
1963- if (X509cert == NULL) {
1964- BIO_free (cert_bio);
1965- return 0;
1966- }
1967-
1968- BIO_free (cert_bio);
1969-
1970- return 1;
1971-}
1972-
1973-static int
1974-is_duplicate (const efi_guid_t *type, const void *data, const uint32_t data_size,
1975- const efi_guid_t *vendor, const char *db_name)
1976+is_one_duplicate (const efi_guid_t *type,
1977+ const void *data, const uint32_t data_size,
1978+ uint8_t *var_data, size_t var_data_size)
1979 {
1980- uint8_t *var_data;
1981- size_t var_data_size;
1982- uint32_t attributes;
1983 uint32_t node_num;
1984 MokListNode *list;
1985 int ret = 0;
1986
1987- if (!data || data_size == 0 || !db_name)
1988- return 0;
1989-
1990- ret = efi_get_variable (*vendor, db_name, &var_data, &var_data_size,
1991- &attributes);
1992- if (ret < 0)
1993+ if (!data || data_size == 0)
1994 return 0;
1995
1996 list = build_mok_list (var_data, var_data_size, &node_num);
1997@@ -1057,7 +541,8 @@ is_duplicate (const efi_guid_t *type, const void *data, const uint32_t data_size
1998 }
1999
2000 for (unsigned int i = 0; i < node_num; i++) {
2001- if (efi_guid_cmp (&list[i].header->SignatureType, type) != 0)
2002+ efi_guid_t sigtype = list[i].header->SignatureType;
2003+ if (efi_guid_cmp (&sigtype, type) != 0)
2004 continue;
2005
2006 if (efi_guid_cmp (type, &efi_guid_x509_cert) == 0) {
2007@@ -1080,24 +565,84 @@ is_duplicate (const efi_guid_t *type, const void *data, const uint32_t data_size
2008 done:
2009 if (list)
2010 free (list);
2011- free (var_data);
2012
2013 return ret;
2014 }
2015
2016 static int
2017-is_valid_request (const efi_guid_t *type, void *mok, uint32_t mok_size,
2018- MokRequest req)
2019+is_duplicate (const efi_guid_t *type,
2020+ const void *data, const uint32_t data_size,
2021+ const efi_guid_t *vendor, const char *db_name)
2022+{
2023+ uint32_t attributes;
2024+ char varname[] = "implausibly-long-mok-variable-name";
2025+ size_t varname_sz = sizeof(varname);
2026+ int ret = 0;
2027+ size_t i;
2028+
2029+ if (!strncmp(db_name, "Mok", 3)) {
2030+ uint8_t *var_data = NULL;
2031+ size_t var_data_size = 0;
2032+ ret = mok_get_variable(db_name, &var_data, &var_data_size);
2033+ if (ret >= 0) {
2034+ ret = is_one_duplicate(type, data, data_size,
2035+ var_data, var_data_size);
2036+ if (ret >= 0) {
2037+ free (var_data);
2038+ return ret;
2039+ }
2040+ var_data = NULL;
2041+ var_data_size = 0;
2042+ }
2043+ }
2044+
2045+ for (i = 0; i < SIZE_MAX; i++) {
2046+ uint8_t *var_data = NULL;
2047+ size_t var_data_size = 0;
2048+ if (i == 0) {
2049+ snprintf(varname, varname_sz, "%s", db_name);
2050+ } else {
2051+ snprintf(varname, varname_sz, "%s%zu", db_name, i);
2052+ }
2053+
2054+ ret = efi_get_variable (*vendor, varname,
2055+ &var_data, &var_data_size,
2056+ &attributes);
2057+ if (ret < 0)
2058+ return 0;
2059+
2060+ ret = is_one_duplicate(type, data, data_size,
2061+ var_data, var_data_size);
2062+ free (var_data);
2063+ /*
2064+ * If ret is < 0, the next one will error as well.
2065+ * If ret is 0, we need to test the next variable.
2066+ * If it's 1, that's a real answer.
2067+ */
2068+ if (ret < 0)
2069+ return 0;
2070+ if (ret > 0)
2071+ return ret;
2072+ }
2073+
2074+ return 0;
2075+}
2076+
2077+static int
2078+is_valid_request (const efi_guid_t *type, const void *mok,
2079+ const uint32_t mok_size, const MokRequest req)
2080 {
2081 switch (req) {
2082 case ENROLL_MOK:
2083- if (is_duplicate (type, mok, mok_size, &efi_guid_global, "PK") ||
2084- is_duplicate (type, mok, mok_size, &efi_guid_global, "KEK") ||
2085- is_duplicate (type, mok, mok_size, &efi_guid_security, "db") ||
2086+ if (is_duplicate (type, mok, mok_size, &efi_guid_security, "db") ||
2087 is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListRT") ||
2088 is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokNew")) {
2089 return 0;
2090 }
2091+ /* Also check the blocklists */
2092+ if (is_duplicate (type, mok, mok_size, &efi_guid_security, "dbx") ||
2093+ is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListXRT"))
2094+ return 0;
2095 break;
2096 case DELETE_MOK:
2097 if (!is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListRT") ||
2098@@ -1111,111 +656,181 @@ is_valid_request (const efi_guid_t *type, void *mok, uint32_t mok_size,
2099 return 0;
2100 }
2101 break;
2102- case DELETE_BLACKLIST:
2103- if (!is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListXRT") ||
2104- is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokXDel")) {
2105- return 0;
2106- }
2107+ case DELETE_BLACKLIST:
2108+ if (!is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListXRT") ||
2109+ is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokXDel")) {
2110+ return 0;
2111+ }
2112+ break;
2113+ }
2114+
2115+ return 1;
2116+}
2117+
2118+static int
2119+is_ca_in_db (const void *cert, const uint32_t cert_size,
2120+ const efi_guid_t *vendor, const char *db_name)
2121+{
2122+ uint8_t *var_data = NULL;
2123+ size_t var_data_size;
2124+ uint32_t attributes;
2125+ uint32_t node_num;
2126+ MokListNode *list;
2127+ int ret = 0;
2128+
2129+ if (!cert || cert_size == 0 || !vendor || !db_name)
2130+ return 0;
2131+
2132+ ret = efi_get_variable (*vendor, db_name, &var_data, &var_data_size,
2133+ &attributes);
2134+ if (ret < 0)
2135+ return 0;
2136+
2137+ list = build_mok_list (var_data, var_data_size, &node_num);
2138+ if (list == NULL) {
2139+ goto done;
2140+ }
2141+
2142+ for (unsigned int i = 0; i < node_num; i++) {
2143+ efi_guid_t sigtype = list[i].header->SignatureType;
2144+ if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0)
2145+ continue;
2146+
2147+ if (is_immediate_ca (cert, cert_size, list[i].mok,
2148+ list[i].mok_size)) {
2149+ ret = 1;
2150+ break;
2151+ }
2152+ }
2153+
2154+done:
2155+ if (list)
2156+ free (list);
2157+ free (var_data);
2158+
2159+ return ret;
2160+}
2161+
2162+/* Check whether the CA cert is already enrolled */
2163+static int
2164+is_ca_enrolled (const void *mok, const uint32_t mok_size, const MokRequest req)
2165+{
2166+ switch (req) {
2167+ case ENROLL_MOK:
2168+ if (is_ca_in_db (mok, mok_size, &efi_guid_shim, "MokListRT"))
2169+ return 1;
2170+ break;
2171+ case ENROLL_BLACKLIST:
2172+ if (is_ca_in_db (mok, mok_size, &efi_guid_shim, "MokListXRT"))
2173+ return 1;
2174 break;
2175+ default:
2176+ return 0;
2177 }
2178
2179- return 1;
2180+ return 0;
2181 }
2182
2183+/* Check whether the CA cert is blocked */
2184 static int
2185-in_pending_request (const efi_guid_t *type, void *data, uint32_t data_size,
2186- MokRequest req)
2187+is_ca_blocked (const void *mok, const uint32_t mok_size, const MokRequest req)
2188 {
2189- uint8_t *authvar_data;
2190- size_t authvar_data_size;
2191- uint32_t attributes;
2192- int ret;
2193-
2194- const char *authvar_names[] = {
2195- [DELETE_MOK] = "MokDelAuth",
2196- [ENROLL_MOK] = "MokAuth",
2197- [DELETE_BLACKLIST] = "MokXDelAuth",
2198- [ENROLL_BLACKLIST] = "MokXAuth"
2199- };
2200- const char *var_names[] = {
2201- [DELETE_MOK] = "MokDel",
2202- [ENROLL_MOK] = "Mok",
2203- [DELETE_BLACKLIST] = "MokXDel",
2204- [ENROLL_BLACKLIST] = "MokX"
2205- };
2206-
2207- if (!data || data_size == 0)
2208+ switch (req) {
2209+ case ENROLL_MOK:
2210+ if (is_ca_in_db (mok, mok_size, &efi_guid_security, "dbx") ||
2211+ is_ca_in_db (mok, mok_size, &efi_guid_shim, "MokListXRT"))
2212+ return 1;
2213+ break;
2214+ default:
2215 return 0;
2216+ }
2217
2218- if (efi_get_variable (efi_guid_shim, authvar_names[req], &authvar_data,
2219- &authvar_data_size, &attributes) < 0)
2220- return 0;
2221+ return 0;
2222+}
2223+
2224+/* Check whether the key is already in the kernel trusted keyring */
2225+static int
2226+is_in_trusted_keyring (const void *cert, const uint32_t cert_size)
2227+{
2228+ char *skid = NULL;
2229+ int ret;
2230
2231- free (authvar_data);
2232- /* Check if the password hash is in the old format */
2233- if (authvar_data_size == SHA256_DIGEST_LENGTH)
2234+ if (get_cert_skid (cert, cert_size, &skid) < 0)
2235 return 0;
2236
2237- ret = delete_data_from_list (&efi_guid_shim, var_names[req],
2238- type, data, data_size);
2239+ ret = match_skid_in_trusted_keyring (skid);
2240 if (ret < 0)
2241- return -1;
2242+ ret = 0;
2243+
2244+ free (skid);
2245
2246 return ret;
2247 }
2248
2249+static int
2250+in_reverse_pending_request (const efi_guid_t *type, const void *data,
2251+ uint32_t data_size, const MokRequest req)
2252+{
2253+ MokRequest reverse_req = get_reverse_req (req);
2254+
2255+ if (!data || data_size == 0)
2256+ return 0;
2257+
2258+ return delete_data_from_req_var (reverse_req, type, data, data_size);
2259+}
2260+
2261 static void
2262-print_skip_message (const char *filename, void *mok, uint32_t mok_size,
2263- MokRequest req)
2264+print_skip_message (const char *filename, const void *mok,
2265+ const uint32_t mok_size, const MokRequest req)
2266 {
2267 switch (req) {
2268 case ENROLL_MOK:
2269 if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2270- &efi_guid_global, "PK"))
2271- printf ("SKIP: %s is already in PK\n", filename);
2272- else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2273- &efi_guid_global, "KEK"))
2274- printf ("SKIP: %s is already in KEK\n", filename);
2275- else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2276- &efi_guid_security, "db"))
2277- printf ("SKIP: %s is already in db\n", filename);
2278+ &efi_guid_security, "db"))
2279+ printf ("%s is already in db\n", filename);
2280 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2281 &efi_guid_shim, "MokListRT"))
2282- printf ("SKIP: %s is already enrolled\n", filename);
2283+ printf ("%s is already enrolled\n", filename);
2284 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2285 &efi_guid_shim, "MokNew"))
2286- printf ("SKIP: %s is already in the enrollement request\n", filename);
2287+ printf ("%s is already in the enrollment request\n", filename);
2288+ else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2289+ &efi_guid_security, "dbx"))
2290+ printf ("%s is blocked in dbx\n", filename);
2291+ else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2292+ &efi_guid_shim, "MokListXRT"))
2293+ printf ("%s is blocked in MokListXRT\n", filename);
2294 break;
2295 case DELETE_MOK:
2296 if (!is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2297 &efi_guid_shim, "MokListRT"))
2298- printf ("SKIP: %s is not in MokList\n", filename);
2299+ printf ("%s is not in MokList\n", filename);
2300 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2301 &efi_guid_shim, "MokDel"))
2302- printf ("SKIP: %s is already in the deletion request\n", filename);
2303+ printf ("%s is already in the deletion request\n", filename);
2304 break;
2305 case ENROLL_BLACKLIST:
2306 if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2307 &efi_guid_shim, "MokListXRT"))
2308- printf ("SKIP: %s is already in MokListX\n", filename);
2309+ printf ("%s is already in MokListX\n", filename);
2310 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2311 &efi_guid_shim, "MokXNew"))
2312- printf ("SKIP: %s is already in the MokX enrollment request\n", filename);
2313+ printf ("%s is already in the MokX enrollment request\n", filename);
2314 break;
2315 case DELETE_BLACKLIST:
2316 if (!is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2317 &efi_guid_shim, "MokListXRT"))
2318- printf ("SKIP: %s is not in MokListX\n", filename);
2319+ printf ("%s is not in MokListX\n", filename);
2320 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
2321 &efi_guid_shim, "MokXDel"))
2322- printf ("SKIP: %s is already in the MokX deletion request\n", filename);
2323+ printf ("%s is already in the MokX deletion request\n", filename);
2324 break;
2325 }
2326 }
2327
2328 static int
2329-issue_mok_request (char **files, uint32_t total, MokRequest req,
2330- const char *hash_file, const int root_pw)
2331+issue_mok_request (char **files, const uint32_t total, const MokRequest req,
2332+ const char *pw_hash_file, const int root_pw)
2333 {
2334 uint8_t *old_req_data = NULL;
2335 size_t old_req_data_size = 0;
2336@@ -1231,18 +846,7 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
2337 int ret = -1;
2338 EFI_SIGNATURE_LIST *CertList;
2339 EFI_SIGNATURE_DATA *CertData;
2340- const char *req_names[] = {
2341- [DELETE_MOK] = "MokDel",
2342- [ENROLL_MOK] = "MokNew",
2343- [DELETE_BLACKLIST] = "MokXDel",
2344- [ENROLL_BLACKLIST] = "MokXNew"
2345- };
2346- const char *reverse_req_names[] = {
2347- [DELETE_MOK] = "MokNew",
2348- [ENROLL_MOK] = "MokDel",
2349- [DELETE_BLACKLIST] = "MokXNew",
2350- [ENROLL_BLACKLIST] = "MokXDel"
2351- };
2352+ const char *var_name = get_req_var_name (req);
2353
2354 if (!files)
2355 return -1;
2356@@ -1268,12 +872,12 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
2357 list_size += sizeof(EFI_SIGNATURE_LIST) * total;
2358 list_size += sizeof(efi_guid_t) * total;
2359
2360- ret = efi_get_variable (efi_guid_shim, req_names[req], &old_req_data,
2361+ ret = efi_get_variable (efi_guid_shim, var_name, &old_req_data,
2362 &old_req_data_size, &attributes);
2363 if (ret < 0) {
2364 if (errno != ENOENT) {
2365 fprintf (stderr, "Failed to read variable \"%s\": %m\n",
2366- req_names[req]);
2367+ var_name);
2368 goto error;
2369 }
2370 } else {
2371@@ -1284,7 +888,7 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
2372 new_list = malloc (list_size);
2373 if (!new_list) {
2374 fprintf (stderr, "Failed to allocate space for %s\n",
2375- req_names[req]);
2376+ var_name);
2377 goto error;
2378 }
2379 ptr = new_list;
2380@@ -1313,23 +917,53 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
2381 read_size = read (fd, ptr, sizes[i]);
2382 if (read_size < 0 || read_size != (int64_t)sizes[i]) {
2383 fprintf (stderr, "Failed to read %s\n", files[i]);
2384+ close (fd);
2385 goto error;
2386 }
2387- if (!is_valid_cert (ptr, read_size)) {
2388+
2389+ const void *mok = ptr;
2390+ const uint32_t mok_size = sizes[i];
2391+
2392+ if (!is_valid_cert (mok, mok_size)) {
2393 fprintf (stderr, "Abort!!! %s is not a valid x509 certificate in DER format\n",
2394 files[i]);
2395+ close (fd);
2396 goto error;
2397 }
2398
2399- if (is_valid_request (&efi_guid_x509_cert, ptr, sizes[i], req)) {
2400- ptr += sizes[i];
2401- real_size += sizes[i] + sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
2402- } else if (in_pending_request (&efi_guid_x509_cert, ptr, sizes[i], req)) {
2403+ /* Check whether the key is already in the trusted keyring */
2404+ if (req == ENROLL_MOK && check_keyring &&
2405+ is_in_trusted_keyring (mok, mok_size)) {
2406+ printf ("Already in kernel trusted keyring. Skip %s\n",
2407+ files[i]);
2408+ close (fd);
2409+ continue;
2410+ }
2411+
2412+ /* Check whether CA is already enrolled */
2413+ if (force_ca_check && is_ca_enrolled (mok, mok_size, req)) {
2414+ printf ("CA enrolled. Skip %s\n", files[i]);
2415+ close (fd);
2416+ continue;
2417+ }
2418+
2419+ /* Check whether CA is blocked */
2420+ if (force_ca_check && is_ca_blocked (mok, mok_size, req)) {
2421+ printf ("CA blocked. Skip %s\n", files[i]);
2422+ close (fd);
2423+ continue;
2424+ }
2425+
2426+ if (is_valid_request (&efi_guid_x509_cert, mok, mok_size, req)) {
2427+ ptr += mok_size;
2428+ real_size += mok_size + sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
2429+ } else if (in_reverse_pending_request (&efi_guid_x509_cert, mok, mok_size, req)) {
2430 printf ("Removed %s from %s\n", files[i],
2431- reverse_req_names[req]);
2432+ get_reverse_req_var_name (req));
2433 ptr -= sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
2434 } else {
2435- print_skip_message (files[i], ptr, sizes[i], req);
2436+ printf ("SKIP: ");
2437+ print_skip_message (files[i], mok, mok_size, req);
2438 ptr -= sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
2439 }
2440
2441@@ -1348,7 +982,7 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
2442 real_size += old_req_data_size;
2443 }
2444
2445- if (update_request (new_list, real_size, req, hash_file, root_pw) < 0) {
2446+ if (update_request (new_list, real_size, req, pw_hash_file, root_pw) < 0) {
2447 goto error;
2448 }
2449
2450@@ -1365,50 +999,7 @@ error:
2451 }
2452
2453 static int
2454-identify_hash_type (const char *hash_str, efi_guid_t *type)
2455-{
2456- unsigned int len = strlen (hash_str);
2457- int hash_size;
2458-
2459- for (unsigned int i = 0; i < len; i++) {
2460- if ((hash_str[i] > '9' || hash_str[i] < '0') &&
2461- (hash_str[i] > 'f' || hash_str[i] < 'a') &&
2462- (hash_str[i] > 'F' || hash_str[i] < 'A'))
2463- return -1;
2464- }
2465-
2466- switch (len) {
2467-#if 0
2468- case SHA_DIGEST_LENGTH*2:
2469- *type = efi_guid_sha1;
2470- hash_size = SHA_DIGEST_LENGTH;
2471- break;
2472-#endif
2473- case SHA224_DIGEST_LENGTH*2:
2474- *type = efi_guid_sha224;
2475- hash_size = SHA224_DIGEST_LENGTH;
2476- break;
2477- case SHA256_DIGEST_LENGTH*2:
2478- *type = efi_guid_sha256;
2479- hash_size = SHA256_DIGEST_LENGTH;
2480- break;
2481- case SHA384_DIGEST_LENGTH*2:
2482- *type = efi_guid_sha384;
2483- hash_size = SHA384_DIGEST_LENGTH;
2484- break;
2485- case SHA512_DIGEST_LENGTH*2:
2486- *type = efi_guid_sha512;
2487- hash_size = SHA512_DIGEST_LENGTH;
2488- break;
2489- default:
2490- return -1;
2491- }
2492-
2493- return hash_size;
2494-}
2495-
2496-static int
2497-hex_str_to_binary (const char *hex_str, uint8_t *array, unsigned int len)
2498+hex_str_to_binary (const char *hex_str, uint8_t *array, const unsigned int len)
2499 {
2500 char *pos;
2501
2502@@ -1425,14 +1016,12 @@ hex_str_to_binary (const char *hex_str, uint8_t *array, unsigned int len)
2503 }
2504
2505 static int
2506-issue_hash_request (const char *hash_str, MokRequest req,
2507- const char *hash_file, const int root_pw)
2508+issue_hash_request (const char *hash_str, const MokRequest req,
2509+ const char *pw_hash_file, const int root_pw)
2510 {
2511 uint8_t *old_req_data = NULL;
2512 size_t old_req_data_size = 0;
2513 uint32_t attributes;
2514- const char *req_name;
2515- const char *reverse_req;
2516 void *new_list = NULL;
2517 void *ptr;
2518 unsigned long list_size = 0;
2519@@ -1444,9 +1033,9 @@ issue_hash_request (const char *hash_str, MokRequest req,
2520 uint8_t db_hash[SHA512_DIGEST_LENGTH];
2521 int hash_size;
2522 int merge_ind = -1;
2523- uint8_t valid = 0;
2524 MokListNode *mok_list = NULL;
2525 uint32_t mok_num;
2526+ const char *var_name = get_req_var_name (req);
2527
2528 if (!hash_str)
2529 return -1;
2530@@ -1458,48 +1047,24 @@ issue_hash_request (const char *hash_str, MokRequest req,
2531 if (hex_str_to_binary (hash_str, db_hash, hash_size) < 0)
2532 return -1;
2533
2534- switch (req) {
2535- case ENROLL_MOK:
2536- req_name = "MokNew";
2537- reverse_req = "MokDel";
2538- break;
2539- case DELETE_MOK:
2540- req_name = "MokDel";
2541- reverse_req = "MokNew";
2542- break;
2543- case ENROLL_BLACKLIST:
2544- req_name = "MokXNew";
2545- reverse_req = "MokXDel";
2546- break;
2547- case DELETE_BLACKLIST:
2548- req_name = "MokXDel";
2549- reverse_req = "MokXNew";
2550- break;
2551- default:
2552- return -1;
2553- }
2554-
2555- if (is_valid_request (&hash_type, db_hash, hash_size, req)) {
2556- valid = 1;
2557- } else if (in_pending_request (&hash_type, db_hash, hash_size, req)) {
2558- printf ("Removed hash from %s\n", reverse_req);
2559- } else {
2560+ if (is_valid_request (&hash_type, db_hash, hash_size, req) == 0) {
2561 printf ("Skip hash\n");
2562- }
2563-
2564- if (!valid) {
2565+ ret = 0;
2566+ goto error;
2567+ } else if (in_reverse_pending_request (&hash_type, db_hash, hash_size, req)) {
2568+ printf ("Removed hash from %s\n", get_reverse_req_var_name (req));
2569 ret = 0;
2570 goto error;
2571 }
2572
2573 list_size = sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t) + hash_size;
2574
2575- ret = efi_get_variable (efi_guid_shim, req_name, &old_req_data,
2576+ ret = efi_get_variable (efi_guid_shim, var_name, &old_req_data,
2577 &old_req_data_size, &attributes);
2578 if (ret < 0) {
2579 if (errno != ENOENT) {
2580 fprintf (stderr, "Failed to read variable \"%s\": %m\n",
2581- req_name);
2582+ var_name);
2583 goto error;
2584 }
2585 } else {
2586@@ -1510,8 +1075,8 @@ issue_hash_request (const char *hash_str, MokRequest req,
2587 goto error;
2588 /* Check if there is a signature list with the same type */
2589 for (unsigned int i = 0; i < mok_num; i++) {
2590- if (efi_guid_cmp (&mok_list[i].header->SignatureType,
2591- &hash_type) == 0) {
2592+ efi_guid_t sigtype = mok_list[i].header->SignatureType;
2593+ if (efi_guid_cmp (&sigtype, &hash_type) == 0) {
2594 merge_ind = i;
2595 list_size -= sizeof(EFI_SIGNATURE_LIST);
2596 break;
2597@@ -1523,7 +1088,7 @@ issue_hash_request (const char *hash_str, MokRequest req,
2598 new_list = malloc (list_size);
2599 if (!new_list) {
2600 fprintf (stderr, "Failed to allocate space for %s: %m\n",
2601- req_name);
2602+ var_name);
2603 goto error;
2604 }
2605 ptr = new_list;
2606@@ -1577,7 +1142,7 @@ issue_hash_request (const char *hash_str, MokRequest req,
2607 }
2608 }
2609
2610- if (update_request (new_list, list_size, req, hash_file, root_pw) < 0) {
2611+ if (update_request (new_list, list_size, req, pw_hash_file, root_pw) < 0) {
2612 goto error;
2613 }
2614
2615@@ -1594,34 +1159,12 @@ error:
2616 }
2617
2618 static int
2619-revoke_request (MokRequest req)
2620+revoke_request (const MokRequest req)
2621 {
2622- switch (req) {
2623- case ENROLL_MOK:
2624- if (test_and_delete_var ("MokNew") < 0)
2625- return -1;
2626- if (test_and_delete_var ("MokAuth") < 0)
2627- return -1;
2628- break;
2629- case DELETE_MOK:
2630- if (test_and_delete_var ("MokDel") < 0)
2631- return -1;
2632- if (test_and_delete_var ("MokDelAuth") < 0)
2633- return -1;
2634- break;
2635- case ENROLL_BLACKLIST:
2636- if (test_and_delete_var ("MokXNew") < 0)
2637- return -1;
2638- if (test_and_delete_var ("MokXAuth") < 0)
2639- return -1;
2640- break;
2641- case DELETE_BLACKLIST:
2642- if (test_and_delete_var ("MokXDel") < 0)
2643- return -1;
2644- if (test_and_delete_var ("MokXDelAuth") < 0)
2645- return -1;
2646- break;
2647- }
2648+ if (test_and_delete_mok_var (get_req_var_name(req)) < 0)
2649+ return -1;
2650+ if (test_and_delete_mok_var (get_req_auth_var_name(req)) < 0)
2651+ return -1;
2652
2653 return 0;
2654 }
2655@@ -1629,6 +1172,7 @@ revoke_request (MokRequest req)
2656 static int
2657 export_db_keys (const DBName db_name)
2658 {
2659+ const char *db_var_name;
2660 uint8_t *data = NULL;
2661 size_t data_size = 0;
2662 uint32_t attributes;
2663@@ -1655,15 +1199,17 @@ export_db_keys (const DBName db_name)
2664 break;
2665 };
2666
2667- ret = efi_get_variable (guid, db_var_name[db_name], &data, &data_size,
2668+ db_var_name = get_db_var_name(db_name);
2669+
2670+ ret = efi_get_variable (guid, db_var_name, &data, &data_size,
2671 &attributes);
2672 if (ret < 0) {
2673 if (errno == ENOENT) {
2674- printf ("%s is empty\n", db_var_name[db_name]);
2675+ printf ("%s is empty\n", db_var_name);
2676 return 0;
2677 }
2678
2679- fprintf (stderr, "Failed to read %s: %m\n", db_var_name[db_name]);
2680+ fprintf (stderr, "Failed to read %s: %m\n", db_var_name);
2681 return -1;
2682 }
2683 ret = -1;
2684@@ -1678,12 +1224,14 @@ export_db_keys (const DBName db_name)
2685 for (unsigned i = 0; i < mok_num; i++) {
2686 off_t offset = 0;
2687 ssize_t write_size;
2688+ efi_guid_t sigtype = list[i].header->SignatureType;
2689
2690- if (efi_guid_cmp (&list[i].header->SignatureType, &efi_guid_x509_cert) != 0)
2691+ if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0)
2692 continue;
2693
2694 /* Dump X509 certificate to files */
2695- snprintf (filename, PATH_MAX, "%s-%04d.der", db_friendly_name[db_name], i+1);
2696+ snprintf (filename, PATH_MAX, "%s-%04d.der",
2697+ get_db_friendly_name(db_name), i+1);
2698 fd = open (filename, O_CREAT | O_WRONLY, mode);
2699 if (fd < 0) {
2700 fprintf (stderr, "Failed to open %s: %m\n", filename);
2701@@ -1714,22 +1262,18 @@ error:
2702 }
2703
2704 static int
2705-set_password (const char *hash_file, const int root_pw, const int clear)
2706+set_password (const char *pw_hash_file, const int root_pw, const int clear)
2707 {
2708- uint8_t *data;
2709- size_t data_size;
2710 pw_crypt_t pw_crypt;
2711- uint8_t auth[SHA256_DIGEST_LENGTH];
2712 char *password = NULL;
2713 unsigned int pw_len;
2714 int auth_ret;
2715 int ret = -1;
2716
2717 memset (&pw_crypt, 0, sizeof(pw_crypt_t));
2718- memset (auth, 0, SHA256_DIGEST_LENGTH);
2719
2720- if (hash_file) {
2721- if (get_hash_from_file (hash_file, &pw_crypt) < 0) {
2722+ if (pw_hash_file) {
2723+ if (get_pw_hash_from_file (pw_hash_file, &pw_crypt) < 0) {
2724 fprintf (stderr, "Failed to read hash\n");
2725 goto error;
2726 }
2727@@ -1744,31 +1288,20 @@ set_password (const char *hash_file, const int root_pw, const int clear)
2728 goto error;
2729 }
2730
2731- if (!use_simple_hash) {
2732- pw_crypt.method = DEFAULT_CRYPT_METHOD;
2733- auth_ret = generate_hash (&pw_crypt, password, pw_len);
2734- } else {
2735- auth_ret = generate_auth (NULL, 0, password, pw_len,
2736- auth);
2737- }
2738+ pw_crypt.method = DEFAULT_CRYPT_METHOD;
2739+ auth_ret = generate_pw_crypt (&pw_crypt, password, pw_len);
2740 if (auth_ret < 0) {
2741 fprintf (stderr, "Couldn't generate hash\n");
2742 goto error;
2743 }
2744 }
2745
2746- if (!use_simple_hash) {
2747- data = (void *)&pw_crypt;
2748- data_size = PASSWORD_CRYPT_SIZE;
2749- } else {
2750- data = (void *)auth;
2751- data_size = SHA256_DIGEST_LENGTH;
2752- }
2753 uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
2754 | EFI_VARIABLE_BOOTSERVICE_ACCESS
2755 | EFI_VARIABLE_RUNTIME_ACCESS;
2756- ret = efi_set_variable (efi_guid_shim, "MokPW", data, data_size,
2757- attributes, S_IRUSR | S_IWUSR);
2758+ ret = efi_set_variable (efi_guid_shim, "MokPW", (void *)&pw_crypt,
2759+ PASSWORD_CRYPT_SIZE, attributes,
2760+ S_IRUSR | S_IWUSR);
2761 if (ret < 0) {
2762 fprintf (stderr, "Failed to write MokPW: %m\n");
2763 goto error;
2764@@ -1782,7 +1315,7 @@ error:
2765 }
2766
2767 static int
2768-set_toggle (const char * VarName, uint32_t state)
2769+set_toggle (const char * VarName, const uint32_t state)
2770 {
2771 uint32_t attributes;
2772 MokToggleVar tvar;
2773@@ -1823,14 +1356,14 @@ error:
2774 return ret;
2775 }
2776
2777-static int
2778-disable_validation()
2779+static inline int
2780+disable_validation(void)
2781 {
2782 return set_toggle("MokSB", 0);
2783 }
2784
2785-static int
2786-enable_validation()
2787+static inline int
2788+enable_validation(void)
2789 {
2790 return set_toggle("MokSB", 1);
2791 }
2792@@ -1838,7 +1371,7 @@ enable_validation()
2793 static int
2794 sb_state ()
2795 {
2796- uint8_t *data;
2797+ uint8_t *data = NULL;
2798 size_t data_size;
2799 uint32_t attributes;
2800 int32_t secureboot = -1;
2801@@ -1856,17 +1389,16 @@ sb_state ()
2802 printf ("Strange data size %zd for \"SecureBoot\" variable\n",
2803 data_size);
2804 }
2805- if (data_size == 4) {
2806- secureboot = (int32_t)*(uint32_t *)data;
2807- } else if (data_size == 2) {
2808- secureboot = (int32_t)*(uint16_t *)data;
2809- } else if (data_size == 1) {
2810- secureboot = (int32_t)*(uint8_t *)data;
2811+ if (data_size == 4 || data_size == 2 || data_size == 1) {
2812+ secureboot = 0;
2813+ memcpy(&secureboot, data, data_size);
2814 }
2815+ free (data);
2816
2817+ data = NULL;
2818 if (efi_get_variable (efi_guid_global, "SetupMode", &data, &data_size,
2819 &attributes) < 0) {
2820- fprintf (stderr, "Failed to read \"SecureBoot\" "
2821+ fprintf (stderr, "Failed to read \"SetupMode\" "
2822 "variable: %m\n");
2823 return -1;
2824 }
2825@@ -1875,17 +1407,17 @@ sb_state ()
2826 printf ("Strange data size %zd for \"SetupMode\" variable\n",
2827 data_size);
2828 }
2829- if (data_size == 4) {
2830- setupmode = (int32_t)*(uint32_t *)data;
2831- } else if (data_size == 2) {
2832- setupmode = (int32_t)*(uint16_t *)data;
2833- } else if (data_size == 1) {
2834- setupmode = (int32_t)*(uint8_t *)data;
2835+ if (data_size == 4 || data_size == 2 || data_size == 1) {
2836+ setupmode = 0;
2837+ memcpy(&setupmode, data, data_size);
2838 }
2839+ free (data);
2840
2841+ data = NULL;
2842 if (efi_get_variable (efi_guid_shim, "MokSBStateRT", &data, &data_size,
2843 &attributes) >= 0) {
2844 moksbstate = 1;
2845+ free (data);
2846 }
2847
2848 if (secureboot == 1 && setupmode == 0) {
2849@@ -1900,25 +1432,36 @@ sb_state ()
2850 printf ("Cannot determine secure boot state.\n");
2851 }
2852
2853- free (data);
2854-
2855 return 0;
2856 }
2857
2858-static int
2859-disable_db()
2860+static inline int
2861+disable_db(void)
2862 {
2863 return set_toggle("MokDB", 0);
2864 }
2865
2866-static int
2867-enable_db()
2868+static inline int
2869+enable_db(void)
2870 {
2871 return set_toggle("MokDB", 1);
2872 }
2873
2874+static int
2875+trust_mok_keys()
2876+{
2877+ return set_toggle("MokListTrustedNew", 0);
2878+}
2879+
2880+static int
2881+untrust_mok_keys()
2882+{
2883+ return set_toggle("MokListTrustedNew", 1);
2884+}
2885+
2886 static inline int
2887-read_file(int fd, void **bufp, size_t *lenptr) {
2888+read_file(const int fd, void **bufp, size_t *lenptr)
2889+{
2890 int alloced = 0, size = 0, i = 0;
2891 void *buf = NULL;
2892 void *buf_new = NULL;
2893@@ -1950,7 +1493,7 @@ read_file(int fd, void **bufp, size_t *lenptr) {
2894 }
2895
2896 static int
2897-test_key (MokRequest req, const char *key_file)
2898+test_key (const MokRequest req, const char *key_file)
2899 {
2900 void *key = NULL;
2901 size_t read_size;
2902@@ -1968,11 +1511,34 @@ test_key (MokRequest req, const char *key_file)
2903 goto error;
2904 }
2905
2906+ if (!is_valid_cert (key, read_size)) {
2907+ fprintf (stderr, "Not a valid x509 certificate\n");
2908+ goto error;
2909+ }
2910+
2911+ if (check_keyring && is_in_trusted_keyring (key, read_size)) {
2912+ fprintf (stderr, "%s is already in the built-in trusted keyring\n",
2913+ key_file);
2914+ goto error;
2915+ }
2916+
2917+ if (force_ca_check && is_ca_enrolled (key, read_size, req)) {
2918+ fprintf (stderr, "CA of %s is already enrolled\n",
2919+ key_file);
2920+ goto error;
2921+ }
2922+
2923+ if (force_ca_check && is_ca_blocked (key, read_size, req)) {
2924+ fprintf (stderr, "CA of %s is blocked\n",
2925+ key_file);
2926+ goto error;
2927+ }
2928+
2929 if (is_valid_request (&efi_guid_x509_cert, key, read_size, req)) {
2930 printf ("%s is not enrolled\n", key_file);
2931 ret = 0;
2932 } else {
2933- printf ("%s is already enrolled\n", key_file);
2934+ print_skip_message (key_file, key, read_size, req);
2935 ret = 1;
2936 }
2937
2938@@ -1987,9 +1553,9 @@ error:
2939 }
2940
2941 static int
2942-reset_moks (MokRequest req, const char *hash_file, const int root_pw)
2943+reset_moks (const MokRequest req, const char *pw_hash_file, const int root_pw)
2944 {
2945- if (update_request (NULL, 0, req, hash_file, root_pw)) {
2946+ if (update_request (NULL, 0, req, pw_hash_file, root_pw)) {
2947 fprintf (stderr, "Failed to issue a reset request\n");
2948 return -1;
2949 }
2950@@ -2005,7 +1571,7 @@ generate_pw_hash (const char *input_pw)
2951 char *password = NULL;
2952 char *crypt_string;
2953 const char *prefix;
2954- int settings_len = sizeof (settings) - 2;
2955+ size_t settings_len = sizeof (settings) - 2;
2956 unsigned int pw_len, salt_size;
2957
2958 if (input_pw) {
2959@@ -2034,13 +1600,13 @@ generate_pw_hash (const char *input_pw)
2960
2961 memset (settings, 0, sizeof (settings));
2962 next = stpncpy (settings, prefix, settings_len);
2963- salt_size = get_salt_size (DEFAULT_CRYPT_METHOD);
2964+ salt_size = get_pw_salt_size (DEFAULT_CRYPT_METHOD);
2965 if (salt_size > settings_len - (next - settings)) {
2966 free(password);
2967 errno = EOVERFLOW;
2968 return -1;
2969 }
2970- generate_salt (next, salt_size);
2971+ generate_pw_salt (next, salt_size);
2972 next += salt_size;
2973 *next = '\0';
2974
2975@@ -2057,7 +1623,7 @@ generate_pw_hash (const char *input_pw)
2976 }
2977
2978 static int
2979-set_timeout (char *t)
2980+set_timeout (const char *t)
2981 {
2982 int timeout = strtol(t, NULL, 10);
2983
2984@@ -2077,14 +1643,39 @@ set_timeout (char *t)
2985 return -1;
2986 }
2987 } else {
2988- return test_and_delete_var ("MokTimeout");
2989+ return test_and_delete_mok_var ("MokTimeout");
2990 }
2991
2992 return 0;
2993 }
2994
2995 static int
2996-set_verbosity (uint8_t verbosity)
2997+print_var_content (const char *var_name, const efi_guid_t guid)
2998+{
2999+ uint8_t *data = NULL;
3000+ size_t data_size;
3001+ uint32_t attributes;
3002+ int ret;
3003+
3004+ ret = efi_get_variable (guid, var_name, &data, &data_size, &attributes);
3005+ if (ret < 0) {
3006+ if (errno == ENOENT) {
3007+ printf ("%s is empty\n", var_name);
3008+ return 0;
3009+ }
3010+
3011+ fprintf (stderr, "Failed to read %s: %m\n", var_name);
3012+ return -1;
3013+ }
3014+
3015+ printf ("%s", data);
3016+ free (data);
3017+
3018+ return ret;
3019+}
3020+
3021+static int
3022+set_verbosity (const uint8_t verbosity)
3023 {
3024 if (verbosity) {
3025 uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
3026@@ -2097,14 +1688,54 @@ set_verbosity (uint8_t verbosity)
3027 return -1;
3028 }
3029 } else {
3030- return test_and_delete_var ("SHIM_VERBOSE");
3031+ return test_and_delete_mok_var ("SHIM_VERBOSE");
3032+ }
3033+
3034+ return 0;
3035+}
3036+
3037+static int
3038+set_fallback_verbosity (const uint8_t verbosity)
3039+{
3040+ if (verbosity) {
3041+ uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
3042+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
3043+ | EFI_VARIABLE_RUNTIME_ACCESS;
3044+ if (efi_set_variable (efi_guid_shim, "FALLBACK_VERBOSE",
3045+ (uint8_t *)&verbosity, sizeof (verbosity),
3046+ attributes, S_IRUSR | S_IWUSR) < 0) {
3047+ fprintf (stderr, "Failed to set FALLBACK_VERBOSE\n");
3048+ return -1;
3049+ }
3050+ } else {
3051+ return test_and_delete_mok_var ("FALLBACK_VERBOSE");
3052+ }
3053+
3054+ return 0;
3055+}
3056+
3057+static int
3058+set_fallback_noreboot (const uint8_t noreboot)
3059+{
3060+ if (noreboot) {
3061+ uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
3062+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
3063+ | EFI_VARIABLE_RUNTIME_ACCESS;
3064+ if (efi_set_variable (efi_guid_shim, "FB_NO_REBOOT",
3065+ (uint8_t *)&noreboot, sizeof (noreboot),
3066+ attributes, S_IRUSR | S_IWUSR) < 0) {
3067+ fprintf (stderr, "Failed to set FB_NO_REBOOT\n");
3068+ return -1;
3069+ }
3070+ } else {
3071+ return test_and_delete_mok_var ("FB_NO_REBOOT");
3072 }
3073
3074 return 0;
3075 }
3076
3077 static inline int
3078-list_db (DBName db_name)
3079+list_db (const DBName db_name)
3080 {
3081 switch (db_name) {
3082 case MOK_LIST_RT:
3083@@ -2124,12 +1755,32 @@ list_db (DBName db_name)
3084 return -1;
3085 }
3086
3087+static int
3088+manage_sbat (const uint8_t sbat_policy)
3089+{
3090+ if (sbat_policy) {
3091+ uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
3092+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
3093+ | EFI_VARIABLE_RUNTIME_ACCESS;
3094+ if (efi_set_variable (efi_guid_shim, "SbatPolicy",
3095+ (uint8_t *)&sbat_policy,
3096+ sizeof (sbat_policy),
3097+ attributes, S_IRUSR | S_IWUSR) < 0) {
3098+ fprintf (stderr, "Failed to set SbatPolicy\n");
3099+ return -1;
3100+ }
3101+ } else {
3102+ return test_and_delete_mok_var ("SbatPolicy");
3103+ }
3104+ return 0;
3105+}
3106+
3107 int
3108 main (int argc, char *argv[])
3109 {
3110 char **files = NULL;
3111 char *key_file = NULL;
3112- char *hash_file = NULL;
3113+ char *pw_hash_file = NULL;
3114 char *input_pw = NULL;
3115 char *hash_str = NULL;
3116 char *timeout = NULL;
3117@@ -2138,10 +1789,15 @@ main (int argc, char *argv[])
3118 unsigned int command = 0;
3119 int use_root_pw = 0;
3120 uint8_t verbosity = 0;
3121+ uint8_t fb_verbosity = 0;
3122+ uint8_t fb_noreboot = 0;
3123+ uint8_t sbat_policy = 0;
3124 DBName db_name = MOK_LIST_RT;
3125 int ret = -1;
3126+ int sb_check;
3127
3128- use_simple_hash = 0;
3129+ force_ca_check = 0;
3130+ check_keyring = 1;
3131
3132 if (!efi_variables_supported ()) {
3133 fprintf (stderr, "EFI variables are not supported on this system\n");
3134@@ -2169,7 +1825,6 @@ main (int argc, char *argv[])
3135 {"hash-file", required_argument, 0, 'f'},
3136 {"generate-hash", optional_argument, 0, 'g'},
3137 {"root-pw", no_argument, 0, 'P'},
3138- {"simple-hash", no_argument, 0, 's'},
3139 {"ignore-db", no_argument, 0, 0 },
3140 {"use-db", no_argument, 0, 0 },
3141 {"mok", no_argument, 0, 'm'},
3142@@ -2177,16 +1832,26 @@ main (int argc, char *argv[])
3143 {"import-hash", required_argument, 0, 0 },
3144 {"delete-hash", required_argument, 0, 0 },
3145 {"set-verbosity", required_argument, 0, 0 },
3146+ {"set-fallback-verbosity", required_argument, 0, 0 },
3147+ {"set-fallback-noreboot", required_argument, 0, 0 },
3148+ {"trust-mok", no_argument, 0, 0 },
3149+ {"untrust-mok", no_argument, 0, 0 },
3150+ {"set-sbat-policy", required_argument, 0, 0 },
3151 {"pk", no_argument, 0, 0 },
3152 {"kek", no_argument, 0, 0 },
3153 {"db", no_argument, 0, 0 },
3154 {"dbx", no_argument, 0, 0 },
3155+ {"list-sbat-revocations", no_argument, 0, 0 },
3156+ {"sbat", no_argument, 0, 0 },
3157 {"timeout", required_argument, 0, 0 },
3158+ {"ca-check", no_argument, 0, 0 },
3159+ {"ignore-keyring", no_argument, 0, 0 },
3160+ {"version", no_argument, 0, 'v'},
3161 {0, 0, 0, 0}
3162 };
3163
3164 int option_index = 0;
3165- c = getopt_long (argc, argv, "cd:f:g::hi:lmpst:xDNPX",
3166+ c = getopt_long (argc, argv, "cd:f:g::hi:lmpst:xDNPXv",
3167 long_options, &option_index);
3168
3169 if (c == -1)
3170@@ -2211,6 +1876,10 @@ main (int argc, char *argv[])
3171 command |= IGNORE_DB;
3172 } else if (strcmp (option, "use-db") == 0) {
3173 command |= USE_DB;
3174+ } else if (strcmp (option, "trust-mok") == 0) {
3175+ command |= TRUST_MOK;
3176+ } else if (strcmp (option, "untrust-mok") == 0) {
3177+ command |= UNTRUST_MOK;
3178 } else if (strcmp (option, "import-hash") == 0) {
3179 command |= IMPORT_HASH;
3180 if (hash_str) {
3181@@ -2241,6 +1910,32 @@ main (int argc, char *argv[])
3182 verbosity = 0;
3183 else
3184 command |= HELP;
3185+ } else if (strcmp (option, "set-fallback-verbosity") == 0) {
3186+ command |= FB_VERBOSITY;
3187+ if (strcmp (optarg, "true") == 0)
3188+ fb_verbosity = 1;
3189+ else if (strcmp (optarg, "false") == 0)
3190+ fb_verbosity = 0;
3191+ else
3192+ command |= HELP;
3193+ } else if (strcmp (option, "set-fallback-noreboot") == 0) {
3194+ command |= FB_NOREBOOT;
3195+ if (strcmp (optarg, "true") == 0)
3196+ fb_noreboot = 1;
3197+ else if (strcmp (optarg, "false") == 0)
3198+ fb_noreboot = 0;
3199+ else
3200+ command |= HELP;
3201+ } else if (strcmp (option, "set-sbat-policy") == 0) {
3202+ command |= SET_SBAT;
3203+ if (strcmp (optarg, "latest") == 0)
3204+ sbat_policy = 1;
3205+ else if (strcmp (optarg, "previous") == 0)
3206+ sbat_policy = 2;
3207+ else if (strcmp (optarg, "delete") == 0)
3208+ sbat_policy = 3;
3209+ else
3210+ command |= HELP;
3211 } else if (strcmp (option, "pk") == 0) {
3212 if (db_name != MOK_LIST_RT) {
3213 command |= HELP;
3214@@ -2265,9 +1960,17 @@ main (int argc, char *argv[])
3215 } else {
3216 db_name = DBX;
3217 }
3218+ } else if (strcmp (option, "list-sbat-revocations") == 0) {
3219+ command |= LIST_SBAT;
3220+ } else if (strcmp (option, "sbat") == 0) {
3221+ command |= LIST_SBAT;
3222 } else if (strcmp (option, "timeout") == 0) {
3223 command |= TIMEOUT;
3224 timeout = strdup (optarg);
3225+ } else if (strcmp (option, "ca-check") == 0) {
3226+ force_ca_check = 1;
3227+ } else if (strcmp (option, "ignore-keyring") == 0) {
3228+ check_keyring = 0;
3229 }
3230
3231 break;
3232@@ -2317,12 +2020,12 @@ main (int argc, char *argv[])
3233
3234 break;
3235 case 'f':
3236- if (hash_file) {
3237+ if (pw_hash_file) {
3238 command |= HELP;
3239 break;
3240 }
3241- hash_file = strdup (optarg);
3242- if (hash_file == NULL) {
3243+ pw_hash_file = strdup (optarg);
3244+ if (pw_hash_file == NULL) {
3245 fprintf (stderr, "Could not allocate space: %m\n");
3246 exit(1);
3247 }
3248@@ -2368,10 +2071,6 @@ main (int argc, char *argv[])
3249 case 'x':
3250 command |= EXPORT;
3251 break;
3252- case 's':
3253- command |= SIMPLE_HASH;
3254- use_simple_hash = 1;
3255- break;
3256 case 'm':
3257 db_name = MOK_LIST_RT;
3258 break;
3259@@ -2383,6 +2082,9 @@ main (int argc, char *argv[])
3260 db_name = MOK_LIST_X_RT;
3261 }
3262 break;
3263+ case 'v':
3264+ printf ("%s\n", VERSION);
3265+ goto out;
3266 case 'h':
3267 case '?':
3268 command |= HELP;
3269@@ -2392,19 +2094,19 @@ main (int argc, char *argv[])
3270 }
3271 }
3272
3273- if (use_root_pw == 1 && use_simple_hash == 1)
3274- use_simple_hash = 0;
3275-
3276- if (hash_file && use_root_pw)
3277+ if (pw_hash_file && use_root_pw)
3278 command |= HELP;
3279
3280 if (db_name != MOK_LIST_RT && !(command & ~MOKX))
3281 command |= LIST_ENROLLED;
3282
3283- if (!(command & HELP)) {
3284+ sb_check = !(command & HELP || command & TEST_KEY ||
3285+ command & VERBOSITY || command & TIMEOUT ||
3286+ command & FB_VERBOSITY || command & FB_NOREBOOT);
3287+ if (sb_check) {
3288 /* Check whether the machine supports Secure Boot or not */
3289 int rc;
3290- uint8_t *data;
3291+ uint8_t *data = NULL;
3292 size_t data_size;
3293 uint32_t attributes;
3294
3295@@ -2430,24 +2132,20 @@ main (int argc, char *argv[])
3296 ret = list_keys_in_var ("MokDel", efi_guid_shim);
3297 break;
3298 case IMPORT:
3299- case IMPORT | SIMPLE_HASH:
3300 ret = issue_mok_request (files, total, ENROLL_MOK,
3301- hash_file, use_root_pw);
3302+ pw_hash_file, use_root_pw);
3303 break;
3304 case DELETE:
3305- case DELETE | SIMPLE_HASH:
3306 ret = issue_mok_request (files, total, DELETE_MOK,
3307- hash_file, use_root_pw);
3308+ pw_hash_file, use_root_pw);
3309 break;
3310 case IMPORT_HASH:
3311- case IMPORT_HASH | SIMPLE_HASH:
3312 ret = issue_hash_request (hash_str, ENROLL_MOK,
3313- hash_file, use_root_pw);
3314+ pw_hash_file, use_root_pw);
3315 break;
3316 case DELETE_HASH:
3317- case DELETE_HASH | SIMPLE_HASH:
3318 ret = issue_hash_request (hash_str, DELETE_MOK,
3319- hash_file, use_root_pw);
3320+ pw_hash_file, use_root_pw);
3321 break;
3322 case REVOKE_IMPORT:
3323 ret = revoke_request (ENROLL_MOK);
3324@@ -2460,11 +2158,9 @@ main (int argc, char *argv[])
3325 ret = export_db_keys (db_name);
3326 break;
3327 case PASSWORD:
3328- case PASSWORD | SIMPLE_HASH:
3329- ret = set_password (hash_file, use_root_pw, 0);
3330+ ret = set_password (pw_hash_file, use_root_pw, 0);
3331 break;
3332 case CLEAR_PASSWORD:
3333- case CLEAR_PASSWORD | SIMPLE_HASH:
3334 ret = set_password (NULL, 0, 1);
3335 break;
3336 case DISABLE_VALIDATION:
3337@@ -2480,8 +2176,7 @@ main (int argc, char *argv[])
3338 ret = test_key (ENROLL_MOK, key_file);
3339 break;
3340 case RESET:
3341- case RESET | SIMPLE_HASH:
3342- ret = reset_moks (ENROLL_MOK, hash_file, use_root_pw);
3343+ ret = reset_moks (ENROLL_MOK, pw_hash_file, use_root_pw);
3344 break;
3345 case GENERATE_PW_HASH:
3346 ret = generate_pw_hash (input_pw);
3347@@ -2492,6 +2187,12 @@ main (int argc, char *argv[])
3348 case USE_DB:
3349 ret = enable_db ();
3350 break;
3351+ case TRUST_MOK:
3352+ ret = trust_mok_keys ();
3353+ break;
3354+ case UNTRUST_MOK:
3355+ ret = untrust_mok_keys ();
3356+ break;
3357 case LIST_NEW | MOKX:
3358 ret = list_keys_in_var ("MokXNew", efi_guid_shim);
3359 break;
3360@@ -2499,24 +2200,20 @@ main (int argc, char *argv[])
3361 ret = list_keys_in_var ("MokXDel", efi_guid_shim);
3362 break;
3363 case IMPORT | MOKX:
3364- case IMPORT | SIMPLE_HASH | MOKX:
3365 ret = issue_mok_request (files, total, ENROLL_BLACKLIST,
3366- hash_file, use_root_pw);
3367+ pw_hash_file, use_root_pw);
3368 break;
3369 case DELETE | MOKX:
3370- case DELETE | SIMPLE_HASH | MOKX:
3371 ret = issue_mok_request (files, total, DELETE_BLACKLIST,
3372- hash_file, use_root_pw);
3373+ pw_hash_file, use_root_pw);
3374 break;
3375 case IMPORT_HASH | MOKX:
3376- case IMPORT_HASH | SIMPLE_HASH | MOKX:
3377 ret = issue_hash_request (hash_str, ENROLL_BLACKLIST,
3378- hash_file, use_root_pw);
3379+ pw_hash_file, use_root_pw);
3380 break;
3381 case DELETE_HASH | MOKX:
3382- case DELETE_HASH | SIMPLE_HASH | MOKX:
3383 ret = issue_hash_request (hash_str, DELETE_BLACKLIST,
3384- hash_file, use_root_pw);
3385+ pw_hash_file, use_root_pw);
3386 break;
3387 case REVOKE_IMPORT | MOKX:
3388 ret = revoke_request (ENROLL_BLACKLIST);
3389@@ -2525,8 +2222,7 @@ main (int argc, char *argv[])
3390 ret = revoke_request (DELETE_BLACKLIST);
3391 break;
3392 case RESET | MOKX:
3393- case RESET | SIMPLE_HASH | MOKX:
3394- ret = reset_moks (ENROLL_BLACKLIST, hash_file, use_root_pw);
3395+ ret = reset_moks (ENROLL_BLACKLIST, pw_hash_file, use_root_pw);
3396 break;
3397 case TEST_KEY | MOKX:
3398 ret = test_key (ENROLL_BLACKLIST, key_file);
3399@@ -2534,9 +2230,21 @@ main (int argc, char *argv[])
3400 case VERBOSITY:
3401 ret = set_verbosity (verbosity);
3402 break;
3403+ case FB_VERBOSITY:
3404+ ret = set_fallback_verbosity (fb_verbosity);
3405+ break;
3406+ case FB_NOREBOOT:
3407+ ret = set_fallback_noreboot (fb_noreboot);
3408+ break;
3409 case TIMEOUT:
3410 ret = set_timeout (timeout);
3411 break;
3412+ case LIST_SBAT:
3413+ ret = print_var_content ("SbatLevelRT", efi_guid_shim);
3414+ break;
3415+ case SET_SBAT:
3416+ ret = manage_sbat(sbat_policy);
3417+ break;
3418 default:
3419 print_help ();
3420 break;
3421@@ -2555,8 +2263,8 @@ out:
3422 if (key_file)
3423 free (key_file);
3424
3425- if (hash_file)
3426- free (hash_file);
3427+ if (pw_hash_file)
3428+ free (pw_hash_file);
3429
3430 if (input_pw)
3431 free (input_pw);
3432diff --git a/src/mokutil.h b/src/mokutil.h
3433new file mode 100644
3434index 0000000..75922fa
3435--- /dev/null
3436+++ b/src/mokutil.h
3437@@ -0,0 +1,66 @@
3438+/**
3439+ * Copyright (C) 2020 Gary Lin <glin@suse.com>
3440+ *
3441+ * This program is free software: you can redistribute it and/or modify
3442+ * it under the terms of the GNU General Public License as published by
3443+ * the Free Software Foundation, either version 3 of the License, or
3444+ * (at your option) any later version.
3445+ *
3446+ * This program is distributed in the hope that it will be useful,
3447+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3448+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3449+ * GNU General Public License for more details.
3450+ *
3451+ * You should have received a copy of the GNU General Public License
3452+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3453+ *
3454+ * In addition, as a special exception, the copyright holders give
3455+ * permission to link the code of portions of this program with the
3456+ * OpenSSL library under certain conditions as described in each
3457+ * individual source file, and distribute linked combinations
3458+ * including the two.
3459+ *
3460+ * You must obey the GNU General Public License in all respects
3461+ * for all of the code used other than OpenSSL. If you modify
3462+ * file(s) with this exception, you may extend this exception to your
3463+ * version of the file(s), but you are not obligated to do so. If you
3464+ * do not wish to do so, delete this exception statement from your
3465+ * version. If you delete this exception statement from all source
3466+ * files in the program, then also delete it here.
3467+ */
3468+
3469+#ifndef __MOKUTIL_H__
3470+#define __MOKUTIL_H__
3471+
3472+#include <ctype.h>
3473+#include <wchar.h>
3474+
3475+#include "signature.h"
3476+
3477+typedef unsigned long efi_status_t;
3478+typedef uint8_t efi_bool_t;
3479+typedef wchar_t efi_char16_t; /* UNICODE character */
3480+
3481+typedef enum {
3482+ DELETE_MOK = 0,
3483+ ENROLL_MOK,
3484+ DELETE_BLACKLIST,
3485+ ENROLL_BLACKLIST,
3486+} MokRequest;
3487+
3488+typedef enum {
3489+ MOK_LIST_RT = 0,
3490+ MOK_LIST_X_RT,
3491+ PK,
3492+ KEK,
3493+ DB,
3494+ DBX,
3495+} DBName;
3496+
3497+typedef struct {
3498+ EFI_SIGNATURE_LIST *header;
3499+ uint32_t mok_size;
3500+ void *mok;
3501+} MokListNode;
3502+
3503+#endif /* __MOKUTIL_H__ */
3504diff --git a/src/password-crypt.c b/src/password-crypt.c
3505index 0b31d64..db69b88 100644
3506--- a/src/password-crypt.c
3507+++ b/src/password-crypt.c
3508@@ -79,7 +79,7 @@ gen_salt_size (uint16_t min, uint16_t max)
3509 }
3510
3511 uint16_t
3512-get_salt_size (int method) {
3513+get_pw_salt_size (const HashMethod method) {
3514 switch (method) {
3515 case TRADITIONAL_DES:
3516 return T_DES_SALT_MAX;
3517@@ -98,7 +98,7 @@ get_salt_size (int method) {
3518 }
3519
3520 int
3521-get_hash_size (int method)
3522+get_pw_hash_size (const HashMethod method)
3523 {
3524 switch (method) {
3525 case TRADITIONAL_DES:
3526@@ -119,7 +119,7 @@ get_hash_size (int method)
3527 }
3528
3529 const char *
3530-get_crypt_prefix (int method)
3531+get_crypt_prefix (const HashMethod method)
3532 {
3533 switch (method) {
3534 case TRADITIONAL_DES:
3535@@ -405,7 +405,8 @@ split_24bit (const char *string, uint8_t *hash, int start, int n,
3536 return 0;
3537 }
3538
3539-int restore_md5_array (const char *string, uint8_t *hash)
3540+static int
3541+restore_md5_array (const char *string, uint8_t *hash)
3542 {
3543 uint32_t tmp = 0;
3544 int value1, value2;
3545@@ -440,7 +441,7 @@ int restore_md5_array (const char *string, uint8_t *hash)
3546 return 0;
3547 }
3548
3549-int
3550+static int
3551 restore_sha256_array (const char *string, uint8_t *hash)
3552 {
3553 uint32_t tmp = 0;
3554@@ -483,7 +484,7 @@ restore_sha256_array (const char *string, uint8_t *hash)
3555 return 0;
3556 }
3557
3558-int
3559+static int
3560 restore_sha512_array (const char *string, uint8_t *hash)
3561 {
3562 uint32_t tmp = 0;
3563diff --git a/src/password-crypt.h b/src/password-crypt.h
3564index 5487363..214a65b 100644
3565--- a/src/password-crypt.h
3566+++ b/src/password-crypt.h
3567@@ -41,14 +41,14 @@
3568 #define SHA512_SALT_MAX 16
3569 #define BLOWFISH_SALT_MAX 22
3570
3571-enum HashMethod {
3572+typedef enum {
3573 TRADITIONAL_DES = 0,
3574 EXTEND_BSDI_DES,
3575 MD5_BASED,
3576 SHA256_BASED,
3577 SHA512_BASED,
3578 BLOWFISH_BASED
3579-};
3580+} HashMethod;
3581
3582 typedef struct {
3583 uint16_t method;
3584@@ -64,9 +64,9 @@ typedef struct {
3585 #define SHA256_B64_LENGTH 43
3586 #define SHA512_B64_LENGTH 86
3587
3588-uint16_t get_salt_size (int method);
3589-int get_hash_size (int method);
3590-const char *get_crypt_prefix (int method);
3591+uint16_t get_pw_salt_size (const HashMethod method);
3592+int get_pw_hash_size (const HashMethod method);
3593+const char *get_crypt_prefix (const HashMethod method);
3594 int decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt);
3595 char int_to_b64 (const int i);
3596 int b64_to_int (const char c);
3597diff --git a/src/util.c b/src/util.c
3598new file mode 100644
3599index 0000000..621869f
3600--- /dev/null
3601+++ b/src/util.c
3602@@ -0,0 +1,456 @@
3603+/**
3604+ * Copyright (C) 2020 Gary Lin <glin@suse.com>
3605+ *
3606+ * This program is free software: you can redistribute it and/or modify
3607+ * it under the terms of the GNU General Public License as published by
3608+ * the Free Software Foundation, either version 3 of the License, or
3609+ * (at your option) any later version.
3610+ *
3611+ * This program is distributed in the hope that it will be useful,
3612+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3613+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3614+ * GNU General Public License for more details.
3615+ *
3616+ * You should have received a copy of the GNU General Public License
3617+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3618+ *
3619+ * In addition, as a special exception, the copyright holders give
3620+ * permission to link the code of portions of this program with the
3621+ * OpenSSL library under certain conditions as described in each
3622+ * individual source file, and distribute linked combinations
3623+ * including the two.
3624+ *
3625+ * You must obey the GNU General Public License in all respects
3626+ * for all of the code used other than OpenSSL. If you modify
3627+ * file(s) with this exception, you may extend this exception to your
3628+ * version of the file(s), but you are not obligated to do so. If you
3629+ * do not wish to do so, delete this exception statement from your
3630+ * version. If you delete this exception statement from all source
3631+ * files in the program, then also delete it here.
3632+ */
3633+
3634+#include <stdio.h>
3635+#include <stdlib.h>
3636+#include <termios.h>
3637+
3638+#include "efi_hash.h"
3639+#include "util.h"
3640+
3641+int
3642+mok_get_variable(const char *name, uint8_t **datap, size_t *data_sizep)
3643+{
3644+ char filename[] = "/sys/firmware/efi/mok-variables/implausibly-long-mok-variable-name";
3645+ size_t filename_sz = sizeof(filename);
3646+ int fd, rc;
3647+ struct stat sb = { 0, };
3648+ uint8_t *buf;
3649+ size_t bufsz, pos = 0;
3650+ ssize_t ssz;
3651+
3652+ *datap = 0;
3653+ *data_sizep = 0;
3654+
3655+ snprintf(filename, filename_sz, "/sys/firmware/efi/mok-variables/%s", name);
3656+
3657+ fd = open(filename, O_RDONLY);
3658+ if (fd < 0)
3659+ return fd;
3660+
3661+ rc = fstat(fd, &sb);
3662+ if (rc < 0) {
3663+err_close:
3664+ close(fd);
3665+ return rc;
3666+ }
3667+
3668+ if (sb.st_size == 0) {
3669+ errno = ENOENT;
3670+ rc = -1;
3671+ goto err_close;
3672+ }
3673+
3674+ bufsz = sb.st_size;
3675+ buf = calloc(1, bufsz);
3676+ if (!buf)
3677+ goto err_close;
3678+
3679+ while (pos < bufsz) {
3680+ ssz = read(fd, &buf[pos], bufsz - pos);
3681+ if (ssz < 0) {
3682+ if (errno == EAGAIN ||
3683+ errno == EWOULDBLOCK ||
3684+ errno == EINTR)
3685+ continue;
3686+ free(buf);
3687+ goto err_close;
3688+ }
3689+
3690+ pos += ssz;
3691+ }
3692+ *datap = buf;
3693+ *data_sizep = pos;
3694+
3695+ return 0;
3696+}
3697+
3698+MokListNode*
3699+build_mok_list (const void *data, const uintptr_t data_size,
3700+ uint32_t *mok_num)
3701+{
3702+ MokListNode *list = NULL;
3703+ MokListNode *list_new = NULL;
3704+ EFI_SIGNATURE_LIST *CertList = (void *)data;
3705+ EFI_SIGNATURE_DATA *Cert;
3706+ unsigned long dbsize = data_size;
3707+ unsigned long count = 0;
3708+ const void *end = data + data_size;
3709+
3710+ while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
3711+ if ((void *)(CertList + 1) > end ||
3712+ CertList->SignatureListSize == 0 ||
3713+ CertList->SignatureListSize <= CertList->SignatureSize) {
3714+ fprintf (stderr, "Corrupted signature list\n");
3715+ if (list)
3716+ free (list);
3717+ return NULL;
3718+ }
3719+
3720+ efi_guid_t sigtype = CertList->SignatureType;
3721+
3722+ if ((efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0) &&
3723+ (efi_guid_cmp (&sigtype, &efi_guid_sha1) != 0) &&
3724+ (efi_guid_cmp (&sigtype, &efi_guid_sha224) != 0) &&
3725+ (efi_guid_cmp (&sigtype, &efi_guid_sha256) != 0) &&
3726+ (efi_guid_cmp (&sigtype, &efi_guid_sha384) != 0) &&
3727+ (efi_guid_cmp (&sigtype, &efi_guid_sha512) != 0)) {
3728+ dbsize -= CertList->SignatureListSize;
3729+ CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList +
3730+ CertList->SignatureListSize);
3731+ continue;
3732+ }
3733+
3734+ if ((efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0) &&
3735+ (CertList->SignatureSize != signature_size (&sigtype))) {
3736+ dbsize -= CertList->SignatureListSize;
3737+ CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList +
3738+ CertList->SignatureListSize);
3739+ continue;
3740+ }
3741+
3742+ Cert = (EFI_SIGNATURE_DATA *) (((uint8_t *) CertList) +
3743+ sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
3744+
3745+ if ((void *)(Cert + 1) > end ||
3746+ CertList->SignatureSize <= sizeof(efi_guid_t)) {
3747+ if (list)
3748+ free (list);
3749+ fprintf (stderr, "Corrupted signature\n");
3750+ return NULL;
3751+ }
3752+
3753+ list_new = realloc(list, sizeof(MokListNode) * (count + 1));
3754+ if (list_new) {
3755+ list = list_new;
3756+ } else {
3757+ if (list)
3758+ free (list);
3759+ fprintf(stderr, "Unable to allocate MOK list\n");
3760+ return NULL;
3761+ }
3762+
3763+ list[count].header = CertList;
3764+ if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) == 0) {
3765+ /* X509 certificate */
3766+ list[count].mok_size = CertList->SignatureSize -
3767+ sizeof(efi_guid_t);
3768+ list[count].mok = (void *)Cert->SignatureData;
3769+ } else {
3770+ /* hash array */
3771+ list[count].mok_size = CertList->SignatureListSize -
3772+ sizeof(EFI_SIGNATURE_LIST) -
3773+ CertList->SignatureHeaderSize;
3774+ list[count].mok = (void *)Cert;
3775+ }
3776+
3777+ if (list[count].mok_size > (unsigned long)end -
3778+ (unsigned long)list[count].mok) {
3779+ fprintf (stderr, "Corrupted data\n");
3780+ free (list);
3781+ return NULL;
3782+ }
3783+
3784+ count++;
3785+ dbsize -= CertList->SignatureListSize;
3786+ CertList = (EFI_SIGNATURE_LIST *) ((uint8_t *) CertList +
3787+ CertList->SignatureListSize);
3788+ }
3789+
3790+ *mok_num = count;
3791+
3792+ return list;
3793+}
3794+
3795+int
3796+test_and_delete_mok_var (const char *var_name)
3797+{
3798+ size_t size;
3799+ int ret;
3800+
3801+ ret = efi_get_variable_size (efi_guid_shim, var_name, &size);
3802+ if (ret < 0) {
3803+ if (errno == ENOENT)
3804+ return 0;
3805+ fprintf (stderr, "Failed to access variable \"%s\": %m\n",
3806+ var_name);
3807+ }
3808+
3809+ /* Attempt to delete it no matter what, problem efi_get_variable_size()
3810+ * had, unless it just doesn't exist anyway. */
3811+ if (!(ret < 0 && errno == ENOENT)) {
3812+ if (efi_del_variable (efi_guid_shim, var_name) < 0)
3813+ fprintf (stderr, "Failed to unset \"%s\": %m\n", var_name);
3814+ }
3815+
3816+ return ret;
3817+}
3818+
3819+int
3820+delete_data_from_req_var (const MokRequest req, const efi_guid_t *type,
3821+ const void *data, const uint32_t data_size)
3822+{
3823+ const efi_guid_t *var_guid = &efi_guid_shim;
3824+ const char *var_name = get_req_var_name (req);
3825+ const char *authvar_name = get_req_auth_var_name (req);
3826+ uint8_t *var_data = NULL;
3827+ size_t var_data_size = 0;
3828+ uint32_t attributes;
3829+ MokListNode *list;
3830+ uint32_t mok_num, total, remain;
3831+ void *end, *start = NULL;
3832+ int del_ind, ret = 0;
3833+ uint32_t sig_list_size, sig_size;
3834+
3835+ if (!var_name || !data || data_size == 0)
3836+ return 0;
3837+
3838+ ret = efi_get_variable (*var_guid, var_name, &var_data, &var_data_size,
3839+ &attributes);
3840+ if (ret < 0) {
3841+ if (errno == ENOENT)
3842+ return 0;
3843+ fprintf (stderr, "Failed to read variable \"%s\": %m\n",
3844+ var_name);
3845+ return -1;
3846+ }
3847+
3848+ total = var_data_size;
3849+
3850+ list = build_mok_list (var_data, var_data_size, &mok_num);
3851+ if (list == NULL)
3852+ goto done;
3853+
3854+ remain = total;
3855+ for (unsigned int i = 0; i < mok_num; i++) {
3856+ remain -= list[i].header->SignatureListSize;
3857+ efi_guid_t sigtype = list[i].header->SignatureType;
3858+ if (efi_guid_cmp (&sigtype, type) != 0)
3859+ continue;
3860+
3861+ sig_list_size = list[i].header->SignatureListSize;
3862+
3863+ if (efi_guid_cmp (type, &efi_guid_x509_cert) == 0) {
3864+ if (list[i].mok_size != data_size)
3865+ continue;
3866+
3867+ if (memcmp (list[i].mok, data, data_size) == 0) {
3868+ /* Remove this key */
3869+ start = (void *)list[i].header;
3870+ end = start + sig_list_size;
3871+ total -= sig_list_size;
3872+ break;
3873+ }
3874+ } else {
3875+ del_ind = match_hash_array (type, data, list[i].mok,
3876+ list[i].mok_size);
3877+ if (del_ind < 0)
3878+ continue;
3879+
3880+ start = (void *)list[i].header;
3881+ sig_size = signature_size (type);
3882+ if (sig_list_size == (sizeof(EFI_SIGNATURE_LIST) + sig_size)) {
3883+ /* Only one hash in the list */
3884+ end = start + sig_list_size;
3885+ total -= sig_list_size;
3886+ } else {
3887+ /* More than one hash in the list */
3888+ start += sizeof(EFI_SIGNATURE_LIST) + sig_size * del_ind;
3889+ end = start + sig_size;
3890+ total -= sig_size;
3891+ list[i].header->SignatureListSize -= sig_size;
3892+ remain += sig_list_size - sizeof(EFI_SIGNATURE_LIST) -
3893+ (del_ind + 1) * sig_size;
3894+ }
3895+ break;
3896+ }
3897+ }
3898+
3899+ /* the key or hash is not in this list */
3900+ if (start == NULL)
3901+ return 0;
3902+
3903+ /* all keys are removed */
3904+ if (total == 0) {
3905+ if (test_and_delete_mok_var (var_name) != 0)
3906+ goto done;
3907+ if (test_and_delete_mok_var (authvar_name) != 0)
3908+ goto done;
3909+ ret = 1;
3910+ goto done;
3911+ }
3912+
3913+ /* remove the key or hash */
3914+ if (remain > 0)
3915+ memmove (start, end, remain);
3916+
3917+ attributes = EFI_VARIABLE_NON_VOLATILE
3918+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
3919+ | EFI_VARIABLE_RUNTIME_ACCESS;
3920+ ret = efi_set_variable (*var_guid, var_name,
3921+ var_data, total, attributes,
3922+ S_IRUSR | S_IWUSR);
3923+ if (ret < 0) {
3924+ fprintf (stderr, "Failed to write variable \"%s\": %m\n",
3925+ var_name);
3926+ goto done;
3927+ }
3928+ efi_chmod_variable(*var_guid, var_name, S_IRUSR | S_IWUSR);
3929+
3930+ ret = 1;
3931+done:
3932+ if (list)
3933+ free (list);
3934+ free (var_data);
3935+
3936+ return ret;
3937+}
3938+
3939+unsigned long
3940+efichar_from_char (efi_char16_t *dest, const char *src, size_t dest_len)
3941+{
3942+ unsigned int i, src_len = strlen(src);
3943+ for (i=0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) {
3944+ dest[i] = src[i];
3945+ }
3946+ dest[i] = 0;
3947+ return i * sizeof(*dest);
3948+}
3949+
3950+int
3951+read_hidden_line (char **line, size_t *n)
3952+{
3953+ struct termios old, new;
3954+ int nread;
3955+ int isTTY = isatty(fileno (stdin));
3956+
3957+ if (isTTY) {
3958+ /* Turn echoing off and fail if we can't. */
3959+ if (tcgetattr (fileno (stdin), &old) != 0)
3960+ return -1;
3961+
3962+ new = old;
3963+ new.c_lflag &= ~ECHO;
3964+
3965+ if (tcsetattr (fileno (stdin), TCSAFLUSH, &new) != 0)
3966+ return -1;
3967+ }
3968+
3969+ /* Read the password. */
3970+ nread = getline (line, n, stdin);
3971+
3972+ if (isTTY) {
3973+ /* Restore terminal. */
3974+ (void) tcsetattr (fileno (stdin), TCSAFLUSH, &old);
3975+ }
3976+
3977+ /* Remove the newline */
3978+ (*line)[nread-1] = '\0';
3979+
3980+ return nread-1;
3981+}
3982+
3983+const char *
3984+get_db_var_name (const DBName db_name)
3985+{
3986+ const char *db_var_names[] = {
3987+ [MOK_LIST_RT] = "MokListRT",
3988+ [MOK_LIST_X_RT] = "MokListXRT",
3989+ [PK] = "PK",
3990+ [KEK] = "KEK",
3991+ [DB] = "db",
3992+ [DBX] = "dbx",
3993+ };
3994+
3995+ return db_var_names[db_name];
3996+}
3997+
3998+const char *
3999+get_db_friendly_name (const DBName db_name)
4000+{
4001+ const char *db_friendly_names[] = {
4002+ [MOK_LIST_RT] = "MOK",
4003+ [MOK_LIST_X_RT] = "MOKX",
4004+ [PK] = "PK",
4005+ [KEK] = "KEK",
4006+ [DB] = "DB",
4007+ [DBX] = "DBX",
4008+ };
4009+
4010+ return db_friendly_names[db_name];
4011+}
4012+
4013+const char *
4014+get_req_var_name (const MokRequest req)
4015+{
4016+ const char *var_names[] = {
4017+ [DELETE_MOK] = "MokDel",
4018+ [ENROLL_MOK] = "MokNew",
4019+ [DELETE_BLACKLIST] = "MokXDel",
4020+ [ENROLL_BLACKLIST] = "MokXNew"
4021+ };
4022+
4023+ return var_names[req];
4024+}
4025+
4026+const char *
4027+get_req_auth_var_name (const MokRequest req)
4028+{
4029+ const char *auth_var_names[] = {
4030+ [DELETE_MOK] = "MokDelAuth",
4031+ [ENROLL_MOK] = "MokAuth",
4032+ [DELETE_BLACKLIST] = "MokXDelAuth",
4033+ [ENROLL_BLACKLIST] = "MokXAuth"
4034+ };
4035+
4036+ return auth_var_names[req];
4037+}
4038+
4039+MokRequest
4040+get_reverse_req (const MokRequest req)
4041+{
4042+ const MokRequest reverse_reqs[] = {
4043+ [DELETE_MOK] = ENROLL_MOK,
4044+ [ENROLL_MOK] = DELETE_MOK,
4045+ [DELETE_BLACKLIST] = ENROLL_BLACKLIST,
4046+ [ENROLL_BLACKLIST] = DELETE_BLACKLIST,
4047+ };
4048+
4049+ return reverse_reqs[req];
4050+}
4051+
4052+const char *
4053+get_reverse_req_var_name (const MokRequest req)
4054+{
4055+ const MokRequest reverse_req = get_reverse_req (req);
4056+
4057+ return get_req_var_name (reverse_req);
4058+}
4059diff --git a/src/util.h b/src/util.h
4060new file mode 100644
4061index 0000000..70deb31
4062--- /dev/null
4063+++ b/src/util.h
4064@@ -0,0 +1,58 @@
4065+/**
4066+ * Copyright (C) 2020 Gary Lin <glin@suse.com>
4067+ *
4068+ * This program is free software: you can redistribute it and/or modify
4069+ * it under the terms of the GNU General Public License as published by
4070+ * the Free Software Foundation, either version 3 of the License, or
4071+ * (at your option) any later version.
4072+ *
4073+ * This program is distributed in the hope that it will be useful,
4074+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4075+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4076+ * GNU General Public License for more details.
4077+ *
4078+ * You should have received a copy of the GNU General Public License
4079+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4080+ *
4081+ * In addition, as a special exception, the copyright holders give
4082+ * permission to link the code of portions of this program with the
4083+ * OpenSSL library under certain conditions as described in each
4084+ * individual source file, and distribute linked combinations
4085+ * including the two.
4086+ *
4087+ * You must obey the GNU General Public License in all respects
4088+ * for all of the code used other than OpenSSL. If you modify
4089+ * file(s) with this exception, you may extend this exception to your
4090+ * version of the file(s), but you are not obligated to do so. If you
4091+ * do not wish to do so, delete this exception statement from your
4092+ * version. If you delete this exception statement from all source
4093+ * files in the program, then also delete it here.
4094+ */
4095+
4096+#ifndef __UTIL_H__
4097+#define __UTIL_H__
4098+
4099+#include <efivar.h>
4100+#include "mokutil.h"
4101+
4102+#include <sys/types.h>
4103+#include <sys/stat.h>
4104+#include <fcntl.h>
4105+
4106+int mok_get_variable(const char *name, uint8_t **datap, size_t *data_sizep);
4107+MokListNode *build_mok_list (const void *data, const uintptr_t data_size,
4108+ uint32_t *mok_num);
4109+int test_and_delete_mok_var (const char *var_name);
4110+int delete_data_from_req_var (const MokRequest req, const efi_guid_t *type,
4111+ const void *data, const uint32_t data_size);
4112+unsigned long efichar_from_char (efi_char16_t *dest, const char *src,
4113+ size_t dest_len);
4114+int read_hidden_line (char **line, size_t *n);
4115+const char *get_db_var_name (const DBName db);
4116+const char *get_db_friendly_name (const DBName db);
4117+const char *get_req_var_name (const MokRequest req);
4118+const char *get_req_auth_var_name (const MokRequest req);
4119+MokRequest get_reverse_req (const MokRequest req);
4120+const char *get_reverse_req_var_name (const MokRequest req);
4121+
4122+#endif /* __UTIL_H__ */

Subscribers

People subscribed via source and target branches