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
diff --git a/configure.ac b/configure.ac
index 7b52a06..bfa0dfe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
2# Process this file with autoconf to produce a configure script.2# Process this file with autoconf to produce a configure script.
33
4AC_PREREQ([2.68])4AC_PREREQ([2.68])
5AC_INIT([mokutil], [0.3.0], [glin@suse.com])5AC_INIT([mokutil], [0.6.0], [chingpang@gmail.com])
6AM_INIT_AUTOMAKE([1.11 -Wno-portability tar-ustar dist-bzip2 no-dist-gzip])6AM_INIT_AUTOMAKE([1.11 -Wno-portability tar-ustar dist-bzip2 no-dist-gzip])
7AC_CONFIG_SRCDIR([src/mokutil.c])7AC_CONFIG_SRCDIR([src/mokutil.c])
8AC_CONFIG_HEADERS([config.h])8AC_CONFIG_HEADERS([config.h])
@@ -85,6 +85,7 @@ AC_CHECK_FUNCS([memset])
8585
86PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9.8])86PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9.8])
87PKG_CHECK_MODULES(EFIVAR, [efivar >= 0.12])87PKG_CHECK_MODULES(EFIVAR, [efivar >= 0.12])
88PKG_CHECK_MODULES(LIBKEYUTILS, [libkeyutils >= 1.5])
8889
89AC_ARG_WITH([bash-completion-dir],90AC_ARG_WITH([bash-completion-dir],
90 AS_HELP_STRING([--with-bash-completion-dir[=PATH]],91 AS_HELP_STRING([--with-bash-completion-dir[=PATH]],
diff --git a/data/mokutil b/data/mokutil
index 800b039..b6ee859 100755
--- a/data/mokutil
+++ b/data/mokutil
@@ -1,4 +1,4 @@
1#!/bin/bash1# mokutil(1) completion
22
3_mokutil()3_mokutil()
4{4{
@@ -24,6 +24,14 @@ _mokutil()
24 COMPREPLY=( $( compgen -W "true false") )24 COMPREPLY=( $( compgen -W "true false") )
25 return 025 return 0
26 ;;26 ;;
27 --set-fallback-verbosity)
28 COMPREPLY=( $( compgen -W "true false") )
29 return 0
30 ;;
31 --set-fallback-noreboot)
32 COMPREPLY=( $( compgen -W "true false") )
33 return 0
34 ;;
27 --generate-hash|-g)35 --generate-hash|-g)
28 COMPREPLY=( $( compgen -o nospace -P= -W "") )36 COMPREPLY=( $( compgen -o nospace -P= -W "") )
29 return 037 return 0
diff --git a/debian/changelog b/debian/changelog
index a753ef6..733aee3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,55 @@
1mokutil (0.6.0-2~18.04.1) bionic; urgency=medium
2
3 * Backport 0.6.0-2 to bionic (LP: #2015664).
4 - debian/control,debian/compat: Drop debhelper version to 11
5 to build on bionic.
6 - debian/patches/manually-define-LIBKEYUTILS-make-vars.patch: Workaround
7 missing libkeyutils.pc in bionic.
8
9 -- Nick Rosbrook <nick.rosbrook@canonical.com> Wed, 07 Jun 2023 14:14:30 -0400
10
11mokutil (0.6.0-2) unstable; urgency=medium
12
13 * *Actually* switch to Arch: any to allow for more
14 architectures. :-( Closes: #987613.
15
16 -- Steve McIntyre <93sam@debian.org> Wed, 15 Jun 2022 14:30:50 +0100
17
18mokutil (0.6.0-1) unstable; urgency=medium
19
20 * Move to new upstream version 0.6.0.
21 + Drop old patches, no longer needed.
22 * Switch to Arch: any to allow for more architectures.
23 Closes: #987613, #991933.
24 * Clean up old tweaks in debian/rules, no longer needed.
25 * Add build-dep on libkeyutils-dev, new dependency.
26 * Bump Standards-Version to 4.6.1, no changes needed.
27
28 -- Steve McIntyre <93sam@debian.org> Sun, 12 Jun 2022 21:41:39 +0100
29
30mokutil (0.4.0-1) unstable; urgency=medium
31
32 * Take mokutil under the wing of efi-team.
33 Thanks to Simon for his work previously, added him as an uploader
34 * Import the upstream source
35 * Move to new upstream version 0.4.0. Closes: #925223
36 + Includes manpage fixes. Closes: #930759
37 * Fix compiler warnings about potential unaligned pointers
38 * Update packaging:
39 + Raise debhelper-compat to 13
40 + Raise Standards-Version to 4.5.1
41 + Remove now-redundant build-dep on dh-autoreconf
42
43 -- Steve McIntyre <93sam@debian.org> Sun, 25 Apr 2021 21:47:18 +0100
44
45mokutil (0.3.0+1538710437.fb6250f-1) unstable; urgency=medium
46
47 * Upload to Debian (Closes: #925471).
48 * Adopt the package; thanks to Steve Langasek for your work!
49 * Update Vcs-* to reflect the move to Salsa.
50
51 -- Simon Quigley <tsimonq2@debian.org> Fri, 12 Apr 2019 17:45:52 -0500
52
1mokutil (0.3.0+1538710437.fb6250f-0ubuntu2~18.04.1) bionic; urgency=medium53mokutil (0.3.0+1538710437.fb6250f-0ubuntu2~18.04.1) bionic; urgency=medium
254
3 * Backport mokutil 0.3.0+1538710437.fb6250f-0ubuntu2 to 18.04.55 * Backport mokutil 0.3.0+1538710437.fb6250f-0ubuntu2 to 18.04.
diff --git a/debian/compat b/debian/compat
index ec63514..b4de394 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
19111
diff --git a/debian/control b/debian/control
index 8f8b6c7..fd9e619 100644
--- a/debian/control
+++ b/debian/control
@@ -2,13 +2,15 @@ Source: mokutil
2Section: admin2Section: admin
3Priority: optional3Priority: optional
4Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>4Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
5XSBC-Original-Maintainer: Steve Langasek <vorlon@debian.org>5XSBC-Original-Maintainer: Debian UEFI Maintainers <debian-efi@lists.debian.org>
6Standards-Version: 3.9.46Uploaders: Steve McIntyre <93sam@debian.org>, Simon Quigley <tsimonq2@debian.org>
7Build-Depends: debhelper (>= 9), libssl-dev, pkg-config, libefivar-dev, dh-autoreconf7Standards-Version: 4.6.1
8Vcs-Bzr: lp:ubuntu/mokutil8Build-Depends: debhelper (>= 11), libssl-dev, pkg-config, libefivar-dev, libkeyutils-dev
9Vcs-Browser: https://salsa.debian.org/efi-team/mokutil
10Vcs-Git: https://salsa.debian.org/efi-team/mokutil.git
911
10Package: mokutil12Package: mokutil
11Architecture: any-amd64 any-arm any-arm64 any-i386 any-ia6413Architecture: any
12Depends: ${shlibs:Depends}, ${misc:Depends}14Depends: ${shlibs:Depends}, ${misc:Depends}
13Description: tools for manipulating machine owner keys15Description: tools for manipulating machine owner keys
14 This program provides the means to enroll and erase the machine owner16 This program provides the means to enroll and erase the machine owner
diff --git a/debian/patches/int-signedness.patch b/debian/patches/int-signedness.patch
15deleted file mode 10064417deleted file mode 100644
index 34b7dfa..0000000
--- a/debian/patches/int-signedness.patch
+++ /dev/null
@@ -1,22 +0,0 @@
1Description: Fix compile failure on platforms where int != unsigned int
2 The compiler may rightly warn about a comparison between an unsigned int
3 and an int on architectures where int is signed by default. Since the
4 existing code has been tested on architectures where int *is* unsigned,
5 we just make our other int explicitly unsigned, ignoring certain existing
6 corner cases for now wrt possible integer underflows.
7Author: Steve Langasek <steve.langasek@canonical.com>
8Last-Updated: 2018-10-10
9
10Index: mokutil-0.3.0+1538710437.fb6250f/src/mokutil.c
11===================================================================
12--- mokutil-0.3.0+1538710437.fb6250f.orig/src/mokutil.c
13+++ mokutil-0.3.0+1538710437.fb6250f/src/mokutil.c
14@@ -2005,7 +2005,7 @@
15 char *password = NULL;
16 char *crypt_string;
17 const char *prefix;
18- int settings_len = sizeof (settings) - 2;
19+ unsigned int settings_len = sizeof (settings) - 2;
20 unsigned int pw_len, salt_size;
21
22 if (input_pw) {
diff --git a/debian/patches/manually-define-LIBKEYUTILS-make-vars.patch b/debian/patches/manually-define-LIBKEYUTILS-make-vars.patch
23new file mode 1006440new file mode 100644
index 0000000..46df49c
--- /dev/null
+++ b/debian/patches/manually-define-LIBKEYUTILS-make-vars.patch
@@ -0,0 +1,21 @@
1Description: Manually define LIBKEYUTILS_{CFLAGS,LIBS} if missing libkeyutils.pc
2Author: Nick Rosbrook <nick.rosbrook@canonical.com>
3Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/jammy/+source/mokutil/+bug/2015664
4Forwarded: no
5Last-Update: 2023-06-07
6--- a/configure.ac
7+++ b/configure.ac
8@@ -85,7 +85,12 @@
9
10 PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9.8])
11 PKG_CHECK_MODULES(EFIVAR, [efivar >= 0.12])
12-PKG_CHECK_MODULES(LIBKEYUTILS, [libkeyutils >= 1.5])
13+PKG_CHECK_MODULES(LIBKEYUTILS, [libkeyutils >= 1.5], [], [pkgconfig_found_keyutils="no"])
14+
15+if test "x$pkgconfig_found_keyutils" = "xno"; then
16+ AC_SUBST([LIBKEYUTILS_CFLAGS],["-I${includedir}"])
17+ AC_SUBST([LIBKEYUTILS_LIBS],["-L${libdir} -lkeyutils"])
18+fi
19
20 AC_ARG_WITH([bash-completion-dir],
21 AS_HELP_STRING([--with-bash-completion-dir[=PATH]],
diff --git a/debian/patches/series b/debian/patches/series
index e7d00e3..4c264fa 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1 @@
1int-signedness.patch1manually-define-LIBKEYUTILS-make-vars.patch
diff --git a/debian/rules b/debian/rules
index e31f87c..2d33f6a 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,8 +1,4 @@
1#!/usr/bin/make -f1#!/usr/bin/make -f
22
3%:3%:
4 dh $@ --with autoreconf4 dh $@
5
6#override_dh_autoreconf:
7# NOCONFIGURE=1 dh_autoreconf ./autogen.sh
8
diff --git a/man/mokutil.1 b/man/mokutil.1
index 25fe8b4..4260a7e 100644
--- a/man/mokutil.1
+++ b/man/mokutil.1
@@ -15,11 +15,11 @@ mokutil \- utility to manipulate machine owner keys
15.br15.br
16\fBmokutil\fR [--import \fIkeylist\fR| -i \fIkeylist\fR]16\fBmokutil\fR [--import \fIkeylist\fR| -i \fIkeylist\fR]
17 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |17 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
18 [--simple-hash | -s] | [--mokx | -X])18 [--mokx | -X] | [--ca-check] | [--ignore-keyring])
19.br19.br
20\fBmokutil\fR [--delete \fIkeylist\fR | -d \fIkeylist\fR]20\fBmokutil\fR [--delete \fIkeylist\fR | -d \fIkeylist\fR]
21 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |21 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
22 [--simple-hash | -s] | [--mokx |- X])22 [--mokx |- X])
23.br23.br
24\fBmokutil\fR [--revoke-import]24\fBmokutil\fR [--revoke-import]
25 ([--mokx | -X])25 ([--mokx | -X])
@@ -30,11 +30,9 @@ mokutil \- utility to manipulate machine owner keys
30\fBmokutil\fR [--export | -x]30\fBmokutil\fR [--export | -x]
31.br31.br
32\fBmokutil\fR [--password | -p]32\fBmokutil\fR [--password | -p]
33 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |33 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P])
34 [--simple-hash | -s])
35.br34.br
36\fBmokutil\fR [--clear-password | -c]35\fBmokutil\fR [--clear-password | -c]
37 ([--simple-hash | -s])
38.br36.br
39\fBmokutil\fR [--disable-validation]37\fBmokutil\fR [--disable-validation]
40.br38.br
@@ -43,11 +41,11 @@ mokutil \- utility to manipulate machine owner keys
43\fBmokutil\fR [--sb-state]41\fBmokutil\fR [--sb-state]
44.br42.br
45\fBmokutil\fR [--test-key \fIkeyfile\fR | -t \fIkeyfile\fR]43\fBmokutil\fR [--test-key \fIkeyfile\fR | -t \fIkeyfile\fR]
46 ([--mokx | -X])44 ([--mokx | -X] | [--ca-check] | [--ignore-keyring])
47.br45.br
48\fBmokutil\fR [--reset]46\fBmokutil\fR [--reset]
49 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |47 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
50 [--simple-hash | -s] | [--mok | -X])48 [--mok | -X])
51.br49.br
52\fBmokutil\fR [--generate-hash=\fIpassword\fR | -g\fIpassword\fR]50\fBmokutil\fR [--generate-hash=\fIpassword\fR | -g\fIpassword\fR]
53.br51.br
@@ -57,14 +55,18 @@ mokutil \- utility to manipulate machine owner keys
57.br55.br
58\fBmokutil\fR [--import-hash \fIhash\fR]56\fBmokutil\fR [--import-hash \fIhash\fR]
59 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |57 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
60 [--simple-hash | -s] | [--mokx | -X])58 [--mokx | -X])
61.br59.br
62\fBmokutil\fR [--delete-hash \fIhash\fR]60\fBmokutil\fR [--delete-hash \fIhash\fR]
63 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |61 ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] |
64 [--simple-hash | -s] | [--mokx | -X])62 [--mokx | -X])
65.br63.br
66\fBmokutil\fR [--set-verbosity (\fItrue\fR | \fIfalse\fR)]64\fBmokutil\fR [--set-verbosity (\fItrue\fR | \fIfalse\fR)]
67.br65.br
66\fBmokutil\fR [--set-fallback-verbosity (\fItrue\fR | \fIfalse\fR)]
67.br
68\fBmokutil\fR [--set-fallback-noreboot (\fItrue\fR | \fIfalse\fR)]
69.br
68\fBmokutil\fR [--pk]70\fBmokutil\fR [--pk]
69.br71.br
70\fBmokutil\fR [--kek]72\fBmokutil\fR [--kek]
@@ -73,6 +75,12 @@ mokutil \- utility to manipulate machine owner keys
73.br75.br
74\fBmokutil\fR [--dbx]76\fBmokutil\fR [--dbx]
75.br77.br
78\fBmokutil\fR [--list-sbat-revocations]
79.br
80\fBmokutil\fR [--set-sbat-policy (\fIlatest\fR | \fIprevious\fR | \fIdelete\fR)]
81.br
82\fBmokutil\fR [--timeout \fI-1,0..0x7fff\fR]
83.br
7684
77.SH DESCRIPTION85.SH DESCRIPTION
78\fBmokutil\fR is a tool to import or delete the machines owner keys86\fBmokutil\fR is a tool to import or delete the machines owner keys
@@ -90,11 +98,11 @@ List the keys to be enrolled
90List the keys to be deleted98List the keys to be deleted
91.TP99.TP
92\fB-i, --import\fR100\fB-i, --import\fR
93Collect the followed files and form a enrolling request to shim. The files must101Collect the following files and form an enrolling request to shim. The files must
94be in DER format.102be in DER format.
95.TP103.TP
96\fB-d, --delete\fR104\fB-d, --delete\fR
97Collect the followed files and form a deleting request to shim. The files must be105Collect the following files and form a deleting request to shim. The files must be
98in DER format.106in DER format.
99.TP107.TP
100\fB--revoke-import\fR108\fB--revoke-import\fR
@@ -115,7 +123,7 @@ Clear the password for MokManager (MokPW)
115\fB--disable-validation\fR123\fB--disable-validation\fR
116Disable the validation process in shim124Disable the validation process in shim
117.TP125.TP
118\fB--enrolled-validation\fR126\fB--enable-validation\fR
119Enable the validation process in shim127Enable the validation process in shim
120.TP128.TP
121\fB--sb-state\fR129\fB--sb-state\fR
@@ -136,11 +144,6 @@ Use the password hash from a specific file
136\fB-P, --root-pw\fR144\fB-P, --root-pw\fR
137Use the root password hash from /etc/shadow145Use the root password hash from /etc/shadow
138.TP146.TP
139\fB-s, --simple-hash\fR
140Use the old SHA256 password hash method to hash the password
141.br
142Note: --root-pw invalidates --simple-hash
143.TP
144\fB--ignore-db\fR147\fB--ignore-db\fR
145Tell shim to not use the keys in db to verify EFI images148Tell shim to not use the keys in db to verify EFI images
146.TP149.TP
@@ -150,17 +153,23 @@ Tell shim to use the keys in db to verify EFI images (default)
150\fB-X, --mokx\fR153\fB-X, --mokx\fR
151Manipulate the MOK blacklist (MOKX) instead of the MOK list154Manipulate the MOK blacklist (MOKX) instead of the MOK list
152.TP155.TP
153\fB-i, --import-hash\fR156\fB--import-hash\fR
154Create an enrolling request for the hash of a key in DER format. Note that157Create an enrolling request for the hash of a key in DER format. Note that
155this is not the password hash.158this is not the password hash.
156.TP159.TP
157\fB-d, --delete-hash\fR160\fB--delete-hash\fR
158Create an deleting request for the hash of a key in DER format. Note that161Create a deleting request for the hash of a key in DER format. Note that
159this is not the password hash.162this is not the password hash.
160.TP163.TP
161\fB--set-verbosity\fR164\fB--set-verbosity\fR
162Set the SHIM_VERBOSE to make shim more or less verbose165Set the SHIM_VERBOSE to make shim more or less verbose
163.TP166.TP
167\fB--set-fallback-verbosity\fR
168Set the FALLBACK_VERBOSE to make fallback more or less verbose
169.TP
170\fB--set-fallback-noreboot\fR
171Set the FB_NO_REBOOT to prevent fallback from automatically rebooting the system
172.TP
164\fB--pk\fR173\fB--pk\fR
165List the keys in the public Platform Key (PK)174List the keys in the public Platform Key (PK)
166.TP175.TP
@@ -173,3 +182,24 @@ List the keys in the secure boot signature store (db)
173\fB--dbx\fR182\fB--dbx\fR
174List the keys in the secure boot blacklist signature store (dbx)183List the keys in the secure boot blacklist signature store (dbx)
175.TP184.TP
185\fB--list-sbat-revocations\fR
186List the entries in the Secure Boot Advanced Targeting store (SBAT)
187.TP
188\fB--set-sbat-policy (\fIlatest\fR | \fIprevious\fR | \fIdelete\fR)\fR
189Set the SbatPolicy UEFI Variable to have shim apply either the latest
190or the previous SBAT revocations. If UEFI Secure Boot is disabled, then
191delete will reset the SBAT revocations to an empty revocation list.
192While latest and previous are persistent configuration, delete will be
193cleared by shim on the next boot whether or not it succeeds. The default
194behavior is for shim to apply the previous revocations.
195.TP
196\fB--timeout\fR
197Set the timeout for MOK prompt
198.TP
199\fB--ca-check\fR
200Check if the CA of the given key is already enrolled or blocked in the key
201databases.
202.TP
203\fB--ignore-keyring\fR
204Ignore the kernel builtin trusted keys keyring check when enrolling a key into MokList
205.TP
diff --git a/src/Makefile.am b/src/Makefile.am
index 87b1515..1ac380d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,13 +2,25 @@ bin_PROGRAMS = mokutil
22
3mokutil_CFLAGS = $(OPENSSL_CFLAGS) \3mokutil_CFLAGS = $(OPENSSL_CFLAGS) \
4 $(EFIVAR_CFLAGS) \4 $(EFIVAR_CFLAGS) \
5 $(WARNINGFLAGS_C)5 $(LIBKEYUTILS_CFLAGS) \
6 $(WARNINGFLAGS_C) \
7 -DVERSION="\"$(VERSION)\""
68
7mokutil_LDADD = $(OPENSSL_LIBS) \9mokutil_LDADD = $(OPENSSL_LIBS) \
8 $(EFIVAR_LIBS) \10 $(EFIVAR_LIBS) \
11 $(LIBKEYUTILS_LIBS) \
9 -lcrypt12 -lcrypt
1013
11mokutil_SOURCES = signature.h \14mokutil_SOURCES = signature.h \
15 efi_hash.h \
16 efi_hash.c \
17 efi_x509.h \
18 efi_x509.c \
19 keyring.h \
20 keyring.c \
12 password-crypt.h \21 password-crypt.h \
13 password-crypt.c \22 password-crypt.c \
23 util.h \
24 util.c \
25 mokutil.h \
14 mokutil.c26 mokutil.c
diff --git a/src/efi_hash.c b/src/efi_hash.c
15new file mode 10064427new file mode 100644
index 0000000..1ffe347
--- /dev/null
+++ b/src/efi_hash.c
@@ -0,0 +1,183 @@
1/**
2 * Copyright (C) 2020 Gary Lin <glin@suse.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * In addition, as a special exception, the copyright holders give
18 * permission to link the code of portions of this program with the
19 * OpenSSL library under certain conditions as described in each
20 * individual source file, and distribute linked combinations
21 * including the two.
22 *
23 * You must obey the GNU General Public License in all respects
24 * for all of the code used other than OpenSSL. If you modify
25 * file(s) with this exception, you may extend this exception to your
26 * version of the file(s), but you are not obligated to do so. If you
27 * do not wish to do so, delete this exception statement from your
28 * version. If you delete this exception statement from all source
29 * files in the program, then also delete it here.
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <openssl/sha.h>
35
36#include "efi_hash.h"
37
38uint32_t
39efi_hash_size (const efi_guid_t *hash_type)
40{
41 if (efi_guid_cmp (hash_type, &efi_guid_sha1) == 0) {
42 return SHA_DIGEST_LENGTH;
43 } else if (efi_guid_cmp (hash_type, &efi_guid_sha224) == 0) {
44 return SHA224_DIGEST_LENGTH;
45 } else if (efi_guid_cmp (hash_type, &efi_guid_sha256) == 0) {
46 return SHA256_DIGEST_LENGTH;
47 } else if (efi_guid_cmp (hash_type, &efi_guid_sha384) == 0) {
48 return SHA384_DIGEST_LENGTH;
49 } else if (efi_guid_cmp (hash_type, &efi_guid_sha512) == 0) {
50 return SHA512_DIGEST_LENGTH;
51 }
52
53 return 0;
54}
55
56uint32_t
57signature_size (const efi_guid_t *hash_type)
58{
59 uint32_t hash_size;
60
61 hash_size = efi_hash_size (hash_type);
62 if (hash_size)
63 return (hash_size + sizeof(efi_guid_t));
64
65 return 0;
66}
67
68int
69print_hash_array (const efi_guid_t *hash_type, const void *hash_array,
70 const uint32_t array_size)
71{
72 uint32_t hash_size, remain;
73 uint32_t sig_size;
74 uint8_t *hash;
75 char *name;
76
77 if (!hash_array || array_size == 0) {
78 fprintf (stderr, "invalid hash array\n");
79 return -1;
80 }
81
82 int rc = efi_guid_to_name ((efi_guid_t *)hash_type, &name);
83 if (rc < 0 || isxdigit(name[0])) {
84 if (name)
85 free(name);
86 fprintf (stderr, "unknown hash type\n");
87 return -1;
88 }
89
90 hash_size = efi_hash_size (hash_type);
91 sig_size = hash_size + sizeof(efi_guid_t);
92
93 printf (" [%s]\n", name);
94 free(name);
95 remain = array_size;
96 hash = (uint8_t *)hash_array;
97
98 while (remain > 0) {
99 if (remain < sig_size) {
100 fprintf (stderr, "invalid array size\n");
101 return -1;
102 }
103
104 printf (" ");
105 hash += sizeof(efi_guid_t);
106 for (unsigned int i = 0; i<hash_size; i++)
107 printf ("%02x", *(hash + i));
108 printf ("\n");
109 hash += hash_size;
110 remain -= sig_size;
111 }
112
113 return 0;
114}
115
116/* match the hash in the hash array and return the index if matched */
117int
118match_hash_array (const efi_guid_t *hash_type, const void *hash,
119 const void *hash_array, const uint32_t array_size)
120{
121 uint32_t hash_size, hash_count;
122 uint32_t sig_size;
123 void *ptr;
124
125 hash_size = efi_hash_size (hash_type);
126 if (!hash_size)
127 return -1;
128
129 sig_size = hash_size + sizeof(efi_guid_t);
130 if ((array_size % sig_size) != 0) {
131 fprintf (stderr, "invalid hash array size\n");
132 return -1;
133 }
134
135 ptr = (void *)hash_array;
136 hash_count = array_size / sig_size;
137 for (unsigned int i = 0; i < hash_count; i++) {
138 ptr += sizeof(efi_guid_t);
139 if (memcmp (ptr, hash, hash_size) == 0)
140 return i;
141 ptr += hash_size;
142 }
143
144 return -1;
145}
146
147/* Return the hash type and size of a given hash string */
148int
149identify_hash_type (const char *hash_str, efi_guid_t *type)
150{
151 unsigned int len = strlen (hash_str);
152 int hash_size;
153
154 for (unsigned int i = 0; i < len; i++) {
155 if ((hash_str[i] > '9' || hash_str[i] < '0') &&
156 (hash_str[i] > 'f' || hash_str[i] < 'a') &&
157 (hash_str[i] > 'F' || hash_str[i] < 'A'))
158 return -1;
159 }
160
161 switch (len) {
162 case SHA224_DIGEST_LENGTH*2:
163 *type = efi_guid_sha224;
164 hash_size = SHA224_DIGEST_LENGTH;
165 break;
166 case SHA256_DIGEST_LENGTH*2:
167 *type = efi_guid_sha256;
168 hash_size = SHA256_DIGEST_LENGTH;
169 break;
170 case SHA384_DIGEST_LENGTH*2:
171 *type = efi_guid_sha384;
172 hash_size = SHA384_DIGEST_LENGTH;
173 break;
174 case SHA512_DIGEST_LENGTH*2:
175 *type = efi_guid_sha512;
176 hash_size = SHA512_DIGEST_LENGTH;
177 break;
178 default:
179 return -1;
180 }
181
182 return hash_size;
183}
diff --git a/src/efi_hash.h b/src/efi_hash.h
0new file mode 100644184new file mode 100644
index 0000000..d09f793
--- /dev/null
+++ b/src/efi_hash.h
@@ -0,0 +1,48 @@
1/**
2 * Copyright (C) 2020 Gary Lin <glin@suse.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * In addition, as a special exception, the copyright holders give
18 * permission to link the code of portions of this program with the
19 * OpenSSL library under certain conditions as described in each
20 * individual source file, and distribute linked combinations
21 * including the two.
22 *
23 * You must obey the GNU General Public License in all respects
24 * for all of the code used other than OpenSSL. If you modify
25 * file(s) with this exception, you may extend this exception to your
26 * version of the file(s), but you are not obligated to do so. If you
27 * do not wish to do so, delete this exception statement from your
28 * version. If you delete this exception statement from all source
29 * files in the program, then also delete it here.
30 */
31
32#ifndef __EFI_HASH_H__
33#define __EFI_HASH_H__
34
35#include <ctype.h>
36#include <efivar.h>
37
38#include "mokutil.h"
39
40uint32_t efi_hash_size (const efi_guid_t *hash_type);
41uint32_t signature_size (const efi_guid_t *hash_type);
42int print_hash_array (const efi_guid_t *hash_type, const void *hash_array,
43 const uint32_t array_size);
44int match_hash_array (const efi_guid_t *hash_type, const void *hash,
45 const void *hash_array, const uint32_t array_size);
46int identify_hash_type (const char *hash_str, efi_guid_t *type);
47
48#endif /* __EFI_HASH_H__ */
diff --git a/src/efi_x509.c b/src/efi_x509.c
0new file mode 10064449new file mode 100644
index 0000000..4788740
--- /dev/null
+++ b/src/efi_x509.c
@@ -0,0 +1,242 @@
1/**
2 * Copyright (C) 2020 Gary Lin <glin@suse.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * In addition, as a special exception, the copyright holders give
18 * permission to link the code of portions of this program with the
19 * OpenSSL library under certain conditions as described in each
20 * individual source file, and distribute linked combinations
21 * including the two.
22 *
23 * You must obey the GNU General Public License in all respects
24 * for all of the code used other than OpenSSL. If you modify
25 * file(s) with this exception, you may extend this exception to your
26 * version of the file(s), but you are not obligated to do so. If you
27 * do not wish to do so, delete this exception statement from your
28 * version. If you delete this exception statement from all source
29 * files in the program, then also delete it here.
30 */
31
32#include <stdio.h>
33#include <openssl/x509.h>
34#include <openssl/x509v3.h>
35
36#include "efi_x509.h"
37
38int
39print_x509 (const uint8_t *cert, const int cert_size)
40{
41 X509 *X509cert;
42 EVP_MD_CTX *ctx;
43 const EVP_MD *md;
44 unsigned int md_len;
45 const unsigned char *in = (const unsigned char *)cert;
46 unsigned char fingerprint[EVP_MAX_MD_SIZE];
47
48 X509cert = d2i_X509 (NULL, &in, cert_size);
49 if (X509cert == NULL) {
50 fprintf (stderr, "Invalid X509 certificate\n");
51 return -1;
52 }
53
54 md = EVP_get_digestbyname ("SHA1");
55 if(md == NULL) {
56 fprintf (stderr, "Failed to get SHA1 digest\n");
57 goto cleanup_cert;
58 }
59
60 ctx = EVP_MD_CTX_create ();
61 if (ctx == NULL) {
62 fprintf (stderr, "Failed to create digest context\n");
63 goto cleanup_cert;
64 }
65
66 if (!EVP_DigestInit_ex (ctx, md, NULL)) {
67 fprintf (stderr, "Failed to initialize digest context\n");
68 goto cleanup_ctx;
69 }
70
71 if (!EVP_DigestUpdate (ctx, cert, cert_size)) {
72 fprintf (stderr, "Failed to hash into the digest context\n");
73 goto cleanup_ctx;
74 }
75
76 if (!EVP_DigestFinal_ex (ctx, fingerprint, &md_len)) {
77 fprintf (stderr, "Failed to get digest value\n");
78 goto cleanup_ctx;
79 }
80
81 printf ("SHA1 Fingerprint: ");
82 for (unsigned int i = 0; i < md_len; i++) {
83 printf ("%02x", fingerprint[i]);
84 if (i < md_len - 1)
85 printf (":");
86 }
87 printf ("\n");
88 X509_print_fp (stdout, X509cert);
89
90cleanup_ctx:
91 EVP_MD_CTX_destroy (ctx);
92cleanup_cert:
93 X509_free (X509cert);
94
95 return 0;
96}
97
98int
99is_valid_cert (const uint8_t *cert, const uint32_t cert_size)
100{
101 X509 *X509cert;
102
103 if (cert == NULL)
104 return 0;
105
106 X509cert = d2i_X509 (NULL, &cert, cert_size);
107 if (X509cert == NULL)
108 return 0;
109
110 X509_free (X509cert);
111
112 return 1;
113}
114
115/**
116 * Check whether the given CA cert is the immediate CA of the given cert
117 **/
118int
119is_immediate_ca (const uint8_t *cert, const uint32_t cert_size,
120 const uint8_t *ca_cert, const uint32_t ca_cert_size)
121{
122 X509 *X509cert = NULL;
123 X509 *X509ca = NULL;
124 X509_STORE *cert_store = NULL;
125 X509_STORE_CTX *cert_ctx = NULL;
126 int ret = 0;
127
128 if (cert == NULL || ca_cert == NULL)
129 return 0;
130
131 if (EVP_add_digest (EVP_md5 ()) == 0)
132 return 0;
133 if (EVP_add_digest (EVP_sha1 ()) == 0)
134 return 0;
135 if (EVP_add_digest (EVP_sha256 ()) == 0)
136 return 0;
137
138 X509cert = d2i_X509 (NULL, &cert, cert_size);
139 if (X509cert == NULL)
140 return 0;
141
142 X509ca = d2i_X509 (NULL, &ca_cert, ca_cert_size);
143 if (X509ca == NULL)
144 goto err;
145
146 cert_store = X509_STORE_new ();
147 if (cert_store == NULL)
148 goto err;
149
150 if (X509_STORE_add_cert (cert_store, X509ca) == 0)
151 goto err;
152
153 /* Follow edk2 CryptoPkg to allow partial certificate chains and
154 * disable time checks */
155 X509_STORE_set_flags (cert_store,
156 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
157
158 cert_ctx = X509_STORE_CTX_new ();
159 if (cert_ctx == NULL)
160 goto err;
161
162 if (X509_STORE_CTX_init (cert_ctx, cert_store, X509cert, NULL) == 0)
163 goto err;
164
165 /* Verify the cert */
166 ret = X509_verify_cert (cert_ctx);
167 /* Treat the exceptional error as FALSE */
168 if (ret < 0)
169 ret = 0;
170 X509_STORE_CTX_cleanup (cert_ctx);
171
172err:
173 if (X509cert)
174 X509_free (X509cert);
175
176 if (X509ca)
177 X509_free (X509ca);
178
179 if (cert_store)
180 X509_STORE_free (cert_store);
181
182 if (cert_store)
183 X509_STORE_CTX_free (cert_ctx);
184
185 return ret;
186}
187
188/**
189 * Get the Subject Key Identifier of the given certificate
190 *
191 * This function allocates the SKID string and the caller is responsible to
192 * free the string.
193 *
194 * Return value:
195 * - 0 : Success
196 * - -1 : Error
197 */
198int
199get_cert_skid(const uint8_t *cert, const uint32_t cert_size, char **skid)
200{
201 X509 *X509cert;
202 const ASN1_OCTET_STRING *asn1_id;
203 const uint8_t *data;
204 int data_len, i;
205 char *id_str, *ptr;
206 int ret = -1;
207
208 X509cert = d2i_X509 (NULL, &cert, cert_size);
209 if (X509cert == NULL) {
210 fprintf (stderr, "invalid x509 certificate\n");
211 goto out;
212 }
213
214 asn1_id = X509_get0_subject_key_id (X509cert);
215 if (asn1_id == NULL) {
216 fprintf (stderr, "Failed to get Subject Key ID\n");
217 goto out;
218 }
219
220 data = ASN1_STRING_get0_data (asn1_id);
221 data_len = ASN1_STRING_length (asn1_id);
222
223 id_str = malloc (data_len*2 + 1);
224 if (id_str == NULL) {
225 fprintf (stderr, "Failed to allocated id string\n");
226 goto out;
227 }
228
229 ptr = id_str;
230 for (i = 0; i < data_len; i++) {
231 snprintf (ptr, 3, "%02x", data[i]);
232 ptr += 2;
233 }
234
235 *skid = id_str;
236 ret = 0;
237out:
238 if (X509cert)
239 X509_free (X509cert);
240
241 return ret;
242}
diff --git a/src/efi_x509.h b/src/efi_x509.h
0new file mode 100644243new file mode 100644
index 0000000..99e5d09
--- /dev/null
+++ b/src/efi_x509.h
@@ -0,0 +1,43 @@
1/**
2 * Copyright (C) 2020 Gary Lin <glin@suse.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * In addition, as a special exception, the copyright holders give
18 * permission to link the code of portions of this program with the
19 * OpenSSL library under certain conditions as described in each
20 * individual source file, and distribute linked combinations
21 * including the two.
22 *
23 * You must obey the GNU General Public License in all respects
24 * for all of the code used other than OpenSSL. If you modify
25 * file(s) with this exception, you may extend this exception to your
26 * version of the file(s), but you are not obligated to do so. If you
27 * do not wish to do so, delete this exception statement from your
28 * version. If you delete this exception statement from all source
29 * files in the program, then also delete it here.
30 */
31
32#ifndef __EFI_X509_H__
33#define __EFI_X509_H__
34
35#include <stdint.h>
36
37int print_x509 (const uint8_t *cert, const int cert_size);
38int is_valid_cert (const uint8_t *cert, const uint32_t cert_size);
39int is_immediate_ca (const uint8_t *cert, const uint32_t cert_size,
40 const uint8_t *ca_cert, const uint32_t ca_cert_size);
41int get_cert_skid(const uint8_t *cert, const uint32_t cert_size, char **skid);
42
43#endif /* __EFI_X509_H__ */
diff --git a/src/keyring.c b/src/keyring.c
0new file mode 10064444new file mode 100644
index 0000000..9709efd
--- /dev/null
+++ b/src/keyring.c
@@ -0,0 +1,111 @@
1/**
2 * Copyright (C) 2020 Gary Lin <glin@suse.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * In addition, as a special exception, the copyright holders give
18 * permission to link the code of portions of this program with the
19 * OpenSSL library under certain conditions as described in each
20 * individual source file, and distribute linked combinations
21 * including the two.
22 *
23 * You must obey the GNU General Public License in all respects
24 * for all of the code used other than OpenSSL. If you modify
25 * file(s) with this exception, you may extend this exception to your
26 * version of the file(s), but you are not obligated to do so. If you
27 * do not wish to do so, delete this exception statement from your
28 * version. If you delete this exception statement from all source
29 * files in the program, then also delete it here.
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <errno.h>
35#include <string.h>
36
37#include <keyutils.h>
38
39#include "keyring.h"
40
41/**
42 * Match the x509v3 Subject Key ID in the descriptions of the kernel built-in
43 * trusted keys keyring
44 *
45 * return value
46 * - 0 : not matched
47 * - 1 : matched
48 * - -1 : error
49 */
50int
51match_skid_in_trusted_keyring (const char *skid)
52{
53 key_serial_t ring_id, key_id, *key_ptr;
54 void *keylist = NULL;
55 int count;
56 char buffer[1024];
57 char *ptr;
58 long buf_size;
59 int ret = -1;
60
61 if (skid == NULL)
62 return -1;
63
64 /* Find the keyring ID of the kernel trusted keys */
65 ring_id = find_key_by_type_and_desc("keyring", ".builtin_trusted_keys", 0);
66 if (ring_id < 0) {
67 fprintf(stderr, "Failed to accesss kernel trusted keyring: %m\n");
68 goto out;
69 }
70
71 count = keyctl_read_alloc(ring_id, &keylist);
72 if (count < 0) {
73 fprintf(stderr, "Failed to read kernel trusted keyring\n");
74 goto out;
75 }
76
77 count /= sizeof(key_serial_t);
78 if (count == 0) {
79 /* The keyring is empty */
80 ret = 0;
81 goto out;
82 }
83
84 /* Iterate the keylist and match SKID */
85 key_ptr = keylist;
86 do {
87 key_id = *key_ptr++;
88
89 buf_size = keyctl_describe(key_id, buffer, sizeof(buffer));
90 if (buf_size < 0) {
91 fprintf(stderr, "key %X inaccessible %m\n", key_id);
92 goto out;
93 }
94
95 /* Check if SKID is in the description */
96 ptr = strstr(buffer, skid);
97 if (ptr && *(ptr + strlen(skid)) == '\0') {
98 /* Matched */
99 ret = 1;
100 goto out;
101 }
102 } while (--count);
103
104 ret = 0;
105out:
106 if (keylist)
107 free(keylist);
108
109 return ret;
110
111}
diff --git a/src/keyring.h b/src/keyring.h
0new file mode 100644112new file mode 100644
index 0000000..44127cf
--- /dev/null
+++ b/src/keyring.h
@@ -0,0 +1,37 @@
1/**
2 * Copyright (C) 2020 Gary Lin <glin@suse.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * In addition, as a special exception, the copyright holders give
18 * permission to link the code of portions of this program with the
19 * OpenSSL library under certain conditions as described in each
20 * individual source file, and distribute linked combinations
21 * including the two.
22 *
23 * You must obey the GNU General Public License in all respects
24 * for all of the code used other than OpenSSL. If you modify
25 * file(s) with this exception, you may extend this exception to your
26 * version of the file(s), but you are not obligated to do so. If you
27 * do not wish to do so, delete this exception statement from your
28 * version. If you delete this exception statement from all source
29 * files in the program, then also delete it here.
30 */
31
32#ifndef __KEYRING_H__
33#define __KEYRING_H__
34
35int match_skid_in_trusted_keyring (const char *skid);
36
37#endif /* __KEYRING_H__ */
diff --git a/src/mokutil.c b/src/mokutil.c
index e2d567d..5d725c9 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -1,5 +1,5 @@
1/**1/**
2 * Copyright (C) 2012-2014 Gary Lin <glin@suse.com>2 * Copyright (C) 2012-2020 Gary Lin <glin@suse.com>
3 * Copyright (C) 2012 Matthew Garrett <mjg@redhat.com>3 * Copyright (C) 2012 Matthew Garrett <mjg@redhat.com>
4 *4 *
5 * This program is free software: you can redistribute it and/or modify5 * This program is free software: you can redistribute it and/or modify
@@ -29,30 +29,29 @@
29 * version. If you delete this exception statement from all source29 * version. If you delete this exception statement from all source
30 * files in the program, then also delete it here.30 * files in the program, then also delete it here.
31 */31 */
32#include <ctype.h>
33#include <dirent.h>32#include <dirent.h>
34#include <errno.h>33#include <errno.h>
35#include <stdio.h>34#include <stdio.h>
36#include <stdlib.h>35#include <stdlib.h>
37#include <string.h>36#include <string.h>
38#include <strings.h>37#include <strings.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <fcntl.h>
42#include <unistd.h>38#include <unistd.h>
43#include <termios.h>
44#include <getopt.h>39#include <getopt.h>
45#include <shadow.h>40#include <shadow.h>
46#include <sys/time.h>41#include <sys/time.h>
4742
48#include <openssl/sha.h>43#include <openssl/sha.h>
49#include <openssl/x509.h>
5044
51#include <crypt.h>45#include <crypt.h>
52#include <efivar.h>46#include <efivar.h>
5347
48#include "mokutil.h"
54#include "signature.h"49#include "signature.h"
50#include "efi_hash.h"
51#include "efi_x509.h"
52#include "keyring.h"
55#include "password-crypt.h"53#include "password-crypt.h"
54#include "util.h"
5655
57#define PASSWORD_MAX 25656#define PASSWORD_MAX 256
58#define PASSWORD_MIN 157#define PASSWORD_MIN 1
@@ -76,65 +75,27 @@
76#define TEST_KEY (1 << 14)75#define TEST_KEY (1 << 14)
77#define RESET (1 << 15)76#define RESET (1 << 15)
78#define GENERATE_PW_HASH (1 << 16)77#define GENERATE_PW_HASH (1 << 16)
79#define SIMPLE_HASH (1 << 17)78#define IGNORE_DB (1 << 17)
80#define IGNORE_DB (1 << 18)79#define USE_DB (1 << 18)
81#define USE_DB (1 << 19)80#define MOKX (1 << 19)
82#define MOKX (1 << 20)81#define IMPORT_HASH (1 << 20)
83#define IMPORT_HASH (1 << 21)82#define DELETE_HASH (1 << 21)
84#define DELETE_HASH (1 << 22)83#define VERBOSITY (1 << 22)
85#define VERBOSITY (1 << 23)84#define TIMEOUT (1 << 23)
86#define TIMEOUT (1 << 24)85#define LIST_SBAT (1 << 24)
86#define FB_VERBOSITY (1 << 25)
87#define FB_NOREBOOT (1 << 26)
88#define TRUST_MOK (1 << 27)
89#define UNTRUST_MOK (1 << 28)
90#define SET_SBAT (1 << 29)
8791
88#define DEFAULT_CRYPT_METHOD SHA512_BASED92#define DEFAULT_CRYPT_METHOD SHA512_BASED
89#define DEFAULT_SALT_SIZE SHA512_SALT_MAX93#define DEFAULT_SALT_SIZE SHA512_SALT_MAX
90#define SETTINGS_LEN (DEFAULT_SALT_SIZE*2)94#define SETTINGS_LEN (DEFAULT_SALT_SIZE*2)
91#define BUF_SIZE 30095#define BUF_SIZE 300
9296
93typedef unsigned long efi_status_t;97static int force_ca_check;
94typedef uint8_t efi_bool_t;98static int check_keyring;
95typedef wchar_t efi_char16_t; /* UNICODE character */
96
97static int use_simple_hash;
98
99typedef enum {
100 DELETE_MOK = 0,
101 ENROLL_MOK,
102 DELETE_BLACKLIST,
103 ENROLL_BLACKLIST,
104} MokRequest;
105
106typedef enum {
107 MOK_LIST_RT = 0,
108 MOK_LIST_X_RT,
109 PK,
110 KEK,
111 DB,
112 DBX,
113} DBName;
114
115const char *db_var_name[] = {
116 [MOK_LIST_RT] = "MokListRT",
117 [MOK_LIST_X_RT] = "MokListXRT",
118 [PK] = "PK",
119 [KEK] = "KEK",
120 [DB] = "db",
121 [DBX] = "dbx",
122};
123
124const char *db_friendly_name[] = {
125 [MOK_LIST_RT] = "MOK",
126 [MOK_LIST_X_RT] = "MOKX",
127 [PK] = "PK",
128 [KEK] = "KEK",
129 [DB] = "DB",
130 [DBX] = "DBX",
131};
132
133typedef struct {
134 EFI_SIGNATURE_LIST *header;
135 uint32_t mok_size;
136 void *mok;
137} MokListNode;
13899
139typedef struct {100typedef struct {
140 uint32_t mok_toggle_state;101 uint32_t mok_toggle_state;
@@ -171,266 +132,28 @@ print_help ()
171 printf (" --import-hash <hash>\t\t\tImport a hash into MOK or MOKX\n");132 printf (" --import-hash <hash>\t\t\tImport a hash into MOK or MOKX\n");
172 printf (" --delete-hash <hash>\t\t\tDelete a hash in MOK or MOKX\n");133 printf (" --delete-hash <hash>\t\t\tDelete a hash in MOK or MOKX\n");
173 printf (" --set-verbosity <true/false>\t\tSet the verbosity bit for shim\n");134 printf (" --set-verbosity <true/false>\t\tSet the verbosity bit for shim\n");
135 printf (" --set-fallback-verbosity <true/false>\t\tSet the verbosity bit for fallback\n");
136 printf (" --set-fallback-noreboot <true/false>\t\tPrevent fallback from automatically rebooting\n");
137 printf (" --trust-mok\t\t\t\tTrust MOK keys within the kernel keyring\n");
138 printf (" --untrust-mok\t\t\t\tDo not trust MOK keys\n");
139 printf (" --set-sbat-policy <latest/previous/delete>\t\tApply Latest, Previous, or Blank SBAT revocations\n");
174 printf (" --pk\t\t\t\t\tList the keys in PK\n");140 printf (" --pk\t\t\t\t\tList the keys in PK\n");
175 printf (" --kek\t\t\t\t\tList the keys in KEK\n");141 printf (" --kek\t\t\t\t\tList the keys in KEK\n");
176 printf (" --db\t\t\t\t\tList the keys in db\n");142 printf (" --db\t\t\t\t\tList the keys in db\n");
177 printf (" --dbx\t\t\t\t\tList the keys in dbx\n");143 printf (" --dbx\t\t\t\t\tList the keys in dbx\n");
178 printf (" --timeout <-1,0..0x7fff>\t\tSet the timeout for MOK prompt\n");144 printf (" --timeout <-1,0..0x7fff>\t\tSet the timeout for MOK prompt\n");
145 printf (" --list-sbat-revocations\t\t\t\tList the entries in SBAT\n");
179 printf ("\n");146 printf ("\n");
180 printf ("Supplimentary Options:\n");147 printf ("Supplimentary Options:\n");
181 printf (" --hash-file <hash file>\t\tUse the specific password hash\n");148 printf (" --hash-file <hash file>\t\tUse the specific password hash\n");
182 printf (" --root-pw\t\t\t\tUse the root password\n");149 printf (" --root-pw\t\t\t\tUse the root password\n");
183 printf (" --simple-hash\t\t\t\tUse the old password hash method\n");
184 printf (" --mokx\t\t\t\tManipulate the MOK blacklist\n");150 printf (" --mokx\t\t\t\tManipulate the MOK blacklist\n");
151 printf (" --ca-check\t\t\t\tCheck if CA of the key is enrolled/blocked\n");
152 printf (" --ignore-keyring\t\t\tDon't check if the key is the kernel keyring\n");
185}153}
186154
187static int155static int
188test_and_delete_var (const char *var_name)156list_keys (const uint8_t *data, const size_t data_size)
189{
190 size_t size;
191 int ret;
192
193 ret = efi_get_variable_size (efi_guid_shim, var_name, &size);
194 if (ret < 0) {
195 if (errno == ENOENT)
196 return 0;
197 fprintf (stderr, "Failed to access variable \"%s\": %m\n",
198 var_name);
199 }
200
201 /* Attempt to delete it no matter what, problem efi_get_variable_size()
202 * had, unless it just doesn't exist anyway. */
203 if (!(ret < 0 && errno == ENOENT)) {
204 if (efi_del_variable (efi_guid_shim, var_name) < 0)
205 fprintf (stderr, "Failed to unset \"%s\": %m\n", var_name);
206 }
207
208 return ret;
209}
210
211static unsigned long
212efichar_from_char (efi_char16_t *dest, const char *src, size_t dest_len)
213{
214 unsigned int i, src_len = strlen(src);
215 for (i=0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) {
216 dest[i] = src[i];
217 }
218 dest[i] = 0;
219 return i * sizeof(*dest);
220}
221
222static uint32_t
223efi_hash_size (const efi_guid_t *hash_type)
224{
225 if (efi_guid_cmp (hash_type, &efi_guid_sha1) == 0) {
226 return SHA_DIGEST_LENGTH;
227 } else if (efi_guid_cmp (hash_type, &efi_guid_sha224) == 0) {
228 return SHA224_DIGEST_LENGTH;
229 } else if (efi_guid_cmp (hash_type, &efi_guid_sha256) == 0) {
230 return SHA256_DIGEST_LENGTH;
231 } else if (efi_guid_cmp (hash_type, &efi_guid_sha384) == 0) {
232 return SHA384_DIGEST_LENGTH;
233 } else if (efi_guid_cmp (hash_type, &efi_guid_sha512) == 0) {
234 return SHA512_DIGEST_LENGTH;
235 }
236
237 return 0;
238}
239
240static uint32_t
241signature_size (const efi_guid_t *hash_type)
242{
243 uint32_t hash_size;
244
245 hash_size = efi_hash_size (hash_type);
246 if (hash_size)
247 return (hash_size + sizeof(efi_guid_t));
248
249 return 0;
250}
251
252static MokListNode*
253build_mok_list (void *data, unsigned long data_size, uint32_t *mok_num)
254{
255 MokListNode *list = NULL;
256 MokListNode *list_new = NULL;
257 EFI_SIGNATURE_LIST *CertList = data;
258 EFI_SIGNATURE_DATA *Cert;
259 unsigned long dbsize = data_size;
260 unsigned long count = 0;
261 void *end = data + data_size;
262
263 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
264 if ((void *)(CertList + 1) > end ||
265 CertList->SignatureListSize == 0 ||
266 CertList->SignatureListSize <= CertList->SignatureSize) {
267 fprintf (stderr, "Corrupted signature list\n");
268 if (list)
269 free (list);
270 return NULL;
271 }
272
273 if ((efi_guid_cmp (&CertList->SignatureType, &efi_guid_x509_cert) != 0) &&
274 (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha1) != 0) &&
275 (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha224) != 0) &&
276 (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha256) != 0) &&
277 (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha384) != 0) &&
278 (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha512) != 0)) {
279 dbsize -= CertList->SignatureListSize;
280 CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList +
281 CertList->SignatureListSize);
282 continue;
283 }
284
285 if ((efi_guid_cmp (&CertList->SignatureType, &efi_guid_x509_cert) != 0) &&
286 (CertList->SignatureSize != signature_size (&CertList->SignatureType))) {
287 dbsize -= CertList->SignatureListSize;
288 CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList +
289 CertList->SignatureListSize);
290 continue;
291 }
292
293 Cert = (EFI_SIGNATURE_DATA *) (((uint8_t *) CertList) +
294 sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
295
296 if ((void *)(Cert + 1) > end ||
297 CertList->SignatureSize <= sizeof(efi_guid_t)) {
298 if (list)
299 free (list);
300 fprintf (stderr, "Corrupted signature\n");
301 return NULL;
302 }
303
304 list_new = realloc(list, sizeof(MokListNode) * (count + 1));
305 if (list_new) {
306 list = list_new;
307 } else {
308 if (list)
309 free (list);
310 fprintf(stderr, "Unable to allocate MOK list\n");
311 return NULL;
312 }
313
314 list[count].header = CertList;
315 if (efi_guid_cmp (&CertList->SignatureType, &efi_guid_x509_cert) == 0) {
316 /* X509 certificate */
317 list[count].mok_size = CertList->SignatureSize -
318 sizeof(efi_guid_t);
319 list[count].mok = (void *)Cert->SignatureData;
320 } else {
321 /* hash array */
322 list[count].mok_size = CertList->SignatureListSize -
323 sizeof(EFI_SIGNATURE_LIST) -
324 CertList->SignatureHeaderSize;
325 list[count].mok = (void *)Cert;
326 }
327
328 if (list[count].mok_size > (unsigned long)end -
329 (unsigned long)list[count].mok) {
330 fprintf (stderr, "Corrupted data\n");
331 free (list);
332 return NULL;
333 }
334
335 count++;
336 dbsize -= CertList->SignatureListSize;
337 CertList = (EFI_SIGNATURE_LIST *) ((uint8_t *) CertList +
338 CertList->SignatureListSize);
339 }
340
341 *mok_num = count;
342
343 return list;
344}
345
346static int
347print_x509 (char *cert, int cert_size)
348{
349 X509 *X509cert;
350 BIO *cert_bio;
351 SHA_CTX ctx;
352 uint8_t fingerprint[SHA_DIGEST_LENGTH];
353
354 cert_bio = BIO_new (BIO_s_mem ());
355 BIO_write (cert_bio, cert, cert_size);
356 if (cert_bio == NULL) {
357 fprintf (stderr, "Failed to write BIO\n");
358 return -1;
359 }
360
361 X509cert = d2i_X509_bio (cert_bio, NULL);
362 if (X509cert == NULL) {
363 fprintf (stderr, "Invalid X509 certificate\n");
364 return -1;
365 }
366
367 SHA1_Init (&ctx);
368 SHA1_Update (&ctx, cert, cert_size);
369 SHA1_Final (fingerprint, &ctx);
370
371 printf ("SHA1 Fingerprint: ");
372 for (unsigned int i = 0; i < SHA_DIGEST_LENGTH; i++) {
373 printf ("%02x", fingerprint[i]);
374 if (i < SHA_DIGEST_LENGTH - 1)
375 printf (":");
376 }
377 printf ("\n");
378 X509_print_fp (stdout, X509cert);
379
380 BIO_free (cert_bio);
381
382 return 0;
383}
384
385static int
386print_hash_array (efi_guid_t *hash_type, void *hash_array, uint32_t array_size)
387{
388 uint32_t hash_size, remain;
389 uint32_t sig_size;
390 uint8_t *hash;
391 char *name;
392
393 if (!hash_array || array_size == 0) {
394 fprintf (stderr, "invalid hash array\n");
395 return -1;
396 }
397
398 int rc = efi_guid_to_name(hash_type, &name);
399 if (rc < 0 || isxdigit(name[0])) {
400 if (name)
401 free(name);
402 fprintf (stderr, "unknown hash type\n");
403 return -1;
404 }
405
406 hash_size = efi_hash_size (hash_type);
407 sig_size = hash_size + sizeof(efi_guid_t);
408
409 printf (" [%s]\n", name);
410 free(name);
411 remain = array_size;
412 hash = (uint8_t *)hash_array;
413
414 while (remain > 0) {
415 if (remain < sig_size) {
416 fprintf (stderr, "invalid array size\n");
417 return -1;
418 }
419
420 printf (" ");
421 hash += sizeof(efi_guid_t);
422 for (unsigned int i = 0; i<hash_size; i++)
423 printf ("%02x", *(hash + i));
424 printf ("\n");
425 hash += hash_size;
426 remain -= sig_size;
427 }
428
429 return 0;
430}
431
432static int
433list_keys (uint8_t *data, size_t data_size)
434{157{
435 uint32_t mok_num;158 uint32_t mok_num;
436 MokListNode *list;159 MokListNode *list;
@@ -442,10 +165,11 @@ list_keys (uint8_t *data, size_t data_size)
442165
443 for (unsigned int i = 0; i < mok_num; i++) {166 for (unsigned int i = 0; i < mok_num; i++) {
444 printf ("[key %d]\n", i+1);167 printf ("[key %d]\n", i+1);
445 if (efi_guid_cmp (&list[i].header->SignatureType, &efi_guid_x509_cert) == 0) {168 efi_guid_t sigtype = list[i].header->SignatureType;
446 print_x509 ((char *)list[i].mok, list[i].mok_size);169 if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) == 0) {
170 print_x509 (list[i].mok, list[i].mok_size);
447 } else {171 } else {
448 print_hash_array (&list[i].header->SignatureType,172 print_hash_array (&sigtype,
449 list[i].mok, list[i].mok_size);173 list[i].mok, list[i].mok_size);
450 }174 }
451 if (i < mok_num - 1)175 if (i < mok_num - 1)
@@ -457,222 +181,53 @@ list_keys (uint8_t *data, size_t data_size)
457 return 0;181 return 0;
458}182}
459183
460/* match the hash in the hash array and return the index if matched */
461static int
462match_hash_array (const efi_guid_t *hash_type, const void *hash,
463 const void *hash_array, const uint32_t array_size)
464{
465 uint32_t hash_size, hash_count;
466 uint32_t sig_size;
467 void *ptr;
468
469 hash_size = efi_hash_size (hash_type);
470 if (!hash_size)
471 return -1;
472
473 sig_size = hash_size + sizeof(efi_guid_t);
474 if ((array_size % sig_size) != 0) {
475 fprintf (stderr, "invalid hash array size\n");
476 return -1;
477 }
478
479 ptr = (void *)hash_array;
480 hash_count = array_size / sig_size;
481 for (unsigned int i = 0; i < hash_count; i++) {
482 ptr += sizeof(efi_guid_t);
483 if (memcmp (ptr, hash, hash_size) == 0)
484 return i;
485 ptr += hash_size;
486 }
487
488 return -1;
489}
490
491static int
492delete_data_from_list (const efi_guid_t *var_guid, const char *var_name,
493 const efi_guid_t *type, void *data, uint32_t data_size)
494{
495 uint8_t *var_data = NULL;
496 size_t var_data_size = 0;
497 uint32_t attributes;
498 MokListNode *list;
499 uint32_t mok_num, total, remain;
500 void *end, *start = NULL;
501 int del_ind, ret = 0;
502 uint32_t sig_list_size, sig_size;
503
504 if (!var_name || !data || data_size == 0)
505 return 0;
506
507 ret = efi_get_variable (*var_guid, var_name, &var_data, &var_data_size,
508 &attributes);
509 if (ret < 0) {
510 if (errno == ENOENT)
511 return 0;
512 fprintf (stderr, "Failed to read variable \"%s\": %m\n",
513 var_name);
514 return -1;
515 }
516
517 total = var_data_size;
518
519 list = build_mok_list (var_data, var_data_size, &mok_num);
520 if (list == NULL)
521 goto done;
522
523 remain = total;
524 for (unsigned int i = 0; i < mok_num; i++) {
525 remain -= list[i].header->SignatureListSize;
526 if (efi_guid_cmp (&list[i].header->SignatureType, type) != 0)
527 continue;
528
529 sig_list_size = list[i].header->SignatureListSize;
530
531 if (efi_guid_cmp (type, &efi_guid_x509_cert) == 0) {
532 if (list[i].mok_size != data_size)
533 continue;
534
535 if (memcmp (list[i].mok, data, data_size) == 0) {
536 /* Remove this key */
537 start = (void *)list[i].header;
538 end = start + sig_list_size;
539 total -= sig_list_size;
540 break;
541 }
542 } else {
543 del_ind = match_hash_array (type, data, list[i].mok,
544 list[i].mok_size);
545 if (del_ind < 0)
546 continue;
547
548 start = (void *)list[i].header;
549 sig_size = signature_size (type);
550 if (sig_list_size == (sizeof(EFI_SIGNATURE_LIST) + sig_size)) {
551 /* Only one hash in the list */
552 end = start + sig_list_size;
553 total -= sig_list_size;
554 } else {
555 /* More than one hash in the list */
556 start += sizeof(EFI_SIGNATURE_LIST) + sig_size * del_ind;
557 end = start + sig_size;
558 total -= sig_size;
559 list[i].header->SignatureListSize -= sig_size;
560 remain += sig_list_size - sizeof(EFI_SIGNATURE_LIST) -
561 (del_ind + 1) * sig_size;
562 }
563 break;
564 }
565 }
566
567 /* the key or hash is not in this list */
568 if (start == NULL)
569 return 0;
570
571 /* all keys are removed */
572 if (total == 0) {
573 test_and_delete_var (var_name);
574
575 /* delete the password */
576 if (strcmp (var_name, "MokNew") == 0)
577 test_and_delete_var ("MokAuth");
578 else if (strcmp (var_name, "MokXNew") == 0)
579 test_and_delete_var ("MokXAuth");
580 else if (strcmp (var_name, "MokDel") == 0)
581 test_and_delete_var ("MokDelAuth");
582 else if (strcmp (var_name, "MokXDel") == 0)
583 test_and_delete_var ("MokXDelAuth");
584
585 ret = 1;
586 goto done;
587 }
588
589 /* remove the key or hash */
590 if (remain > 0)
591 memmove (start, end, remain);
592
593 attributes = EFI_VARIABLE_NON_VOLATILE
594 | EFI_VARIABLE_BOOTSERVICE_ACCESS
595 | EFI_VARIABLE_RUNTIME_ACCESS;
596 ret = efi_set_variable (*var_guid, var_name,
597 var_data, total, attributes,
598 S_IRUSR | S_IWUSR);
599 if (ret < 0) {
600 fprintf (stderr, "Failed to write variable \"%s\": %m\n",
601 var_name);
602 goto done;
603 }
604 efi_chmod_variable(*var_guid, var_name, S_IRUSR | S_IWUSR);
605
606 ret = 1;
607done:
608 if (list)
609 free (list);
610 free (var_data);
611
612 return ret;
613}
614
615static int184static int
616list_keys_in_var (const char *var_name, const efi_guid_t guid)185list_keys_in_var (const char *var_name, const efi_guid_t guid)
617{186{
618 uint8_t *data = NULL;187 uint8_t *data = NULL;
619 size_t data_size;188 char varname[] = "implausibly-long-mok-variable-name";
189 size_t data_sz, i, varname_sz = sizeof(varname);
620 uint32_t attributes;190 uint32_t attributes;
621 int ret;191 int ret;
622192
623 ret = efi_get_variable (guid, var_name, &data, &data_size, &attributes);193 ret = mok_get_variable(var_name, &data, &data_sz);
624 if (ret < 0) {194 if (ret >= 0) {
625 if (errno == ENOENT) {195 ret = list_keys (data, data_sz);
626 printf ("%s is empty\n", var_name);196 free(data);
627 return 0;197 return ret;
628 }
629
630 fprintf (stderr, "Failed to read %s: %m\n", var_name);
631 return -1;
632 }198 }
633199
634 ret = list_keys (data, data_size);200 for (i = 0; i < SIZE_MAX; i++) {
635 free (data);201 if (i == 0) {
636202 snprintf(varname, varname_sz, "%s", var_name);
637 return ret;203 } else {
638}204 snprintf(varname, varname_sz, "%s%zu", var_name, i);
639205 }
640static int
641read_hidden_line (char **line, size_t *n)
642{
643 struct termios old, new;
644 int nread;
645 int isTTY = isatty(fileno (stdin));
646
647 if (isTTY) {
648 /* Turn echoing off and fail if we can't. */
649 if (tcgetattr (fileno (stdin), &old) != 0)
650 return -1;
651
652 new = old;
653 new.c_lflag &= ~ECHO;
654
655 if (tcsetattr (fileno (stdin), TCSAFLUSH, &new) != 0)
656 return -1;
657 }
658206
659 /* Read the password. */207 ret = efi_get_variable (guid, varname, &data, &data_sz,
660 nread = getline (line, n, stdin);208 &attributes);
209 if (ret < 0)
210 return 0;
661211
662 if (isTTY) {212 ret = list_keys (data, data_sz);
663 /* Restore terminal. */213 free(data);
664 (void) tcsetattr (fileno (stdin), TCSAFLUSH, &old);214 /*
215 * If ret is < 0, the next one will error as well.
216 * If ret is 0, we need to test the next variable.
217 * If it's 1, that's a real answer.
218 */
219 if (ret < 0)
220 return 0;
221 if (ret > 0)
222 return ret;
665 }223 }
666224
667 /* Remove the newline */225 return 0;
668 (*line)[nread-1] = '\0';
669
670 return nread-1;
671}226}
672227
673static int228static int
674get_password (char **password, unsigned int *len,229get_password (char **password, unsigned int *len,
675 unsigned int min, unsigned int max)230 const unsigned int min, const unsigned int max)
676{231{
677 char *password_1, *password_2;232 char *password_1, *password_2;
678 unsigned int len_1, len_2;233 unsigned int len_1, len_2;
@@ -732,34 +287,8 @@ error:
732 return ret;287 return ret;
733}288}
734289
735static int
736generate_auth (void *new_list, int list_len, char *password,
737 unsigned int pw_len, uint8_t *auth)
738{
739 efi_char16_t efichar_pass[PASSWORD_MAX+1];
740 unsigned long efichar_len;
741 SHA256_CTX ctx;
742
743 if (!password || !auth)
744 return -1;
745
746 efichar_len = efichar_from_char (efichar_pass, password,
747 pw_len * sizeof(efi_char16_t));
748
749 SHA256_Init (&ctx);
750
751 if (new_list)
752 SHA256_Update (&ctx, new_list, list_len);
753
754 SHA256_Update (&ctx, efichar_pass, efichar_len);
755
756 SHA256_Final (auth, &ctx);
757
758 return 0;
759}
760
761static void290static void
762generate_salt (char salt[], unsigned int salt_size)291generate_pw_salt (char salt[], const unsigned int salt_size)
763{292{
764 struct timeval tv;293 struct timeval tv;
765 char *rand_str;294 char *rand_str;
@@ -780,7 +309,8 @@ generate_salt (char salt[], unsigned int salt_size)
780}309}
781310
782static int311static int
783generate_hash (pw_crypt_t *pw_crypt, char *password, unsigned int pw_len)312generate_pw_crypt (pw_crypt_t *pw_crypt, const char *password,
313 const unsigned int pw_len)
784{314{
785 pw_crypt_t new_crypt;315 pw_crypt_t new_crypt;
786 char settings[SETTINGS_LEN];316 char settings[SETTINGS_LEN];
@@ -796,8 +326,8 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, unsigned int pw_len)
796 if (!prefix)326 if (!prefix)
797 return -1;327 return -1;
798328
799 pw_crypt->salt_size = get_salt_size (pw_crypt->method);329 pw_crypt->salt_size = get_pw_salt_size (pw_crypt->method);
800 generate_salt ((char *)pw_crypt->salt, pw_crypt->salt_size);330 generate_pw_salt ((char *)pw_crypt->salt, pw_crypt->salt_size);
801331
802 memset (settings, 0, sizeof (settings));332 memset (settings, 0, sizeof (settings));
803 next = stpncpy (settings, prefix, settings_len);333 next = stpncpy (settings, prefix, settings_len);
@@ -816,7 +346,7 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, unsigned int pw_len)
816 if (decode_pass (crypt_string, &new_crypt) < 0)346 if (decode_pass (crypt_string, &new_crypt) < 0)
817 return -1;347 return -1;
818348
819 hash_len = get_hash_size (new_crypt.method);349 hash_len = get_pw_hash_size (new_crypt.method);
820 if (hash_len < 0)350 if (hash_len < 0)
821 return -1;351 return -1;
822 memcpy (pw_crypt->hash, new_crypt.hash, hash_len);352 memcpy (pw_crypt->hash, new_crypt.hash, hash_len);
@@ -831,7 +361,7 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, unsigned int pw_len)
831}361}
832362
833static int363static int
834get_hash_from_file (const char *file, pw_crypt_t *pw_crypt)364get_pw_hash_from_file (const char *file, pw_crypt_t *pw_crypt)
835{365{
836 char string[BUF_SIZE];366 char string[BUF_SIZE];
837 ssize_t read_len = 0;367 ssize_t read_len = 0;
@@ -890,14 +420,11 @@ get_password_from_shadow (pw_crypt_t *pw_crypt)
890}420}
891421
892static int422static int
893update_request (void *new_list, int list_len, MokRequest req,423update_request (void *new_list, const int list_len, const MokRequest req,
894 const char *hash_file, const int root_pw)424 const char *pw_hash_file, const int root_pw)
895{425{
896 uint8_t *data;
897 size_t data_size;
898 const char *req_name, *auth_name;426 const char *req_name, *auth_name;
899 pw_crypt_t pw_crypt;427 pw_crypt_t pw_crypt;
900 uint8_t auth[SHA256_DIGEST_LENGTH];
901 char *password = NULL;428 char *password = NULL;
902 unsigned int pw_len;429 unsigned int pw_len;
903 int auth_ret;430 int auth_ret;
@@ -930,8 +457,8 @@ update_request (void *new_list, int list_len, MokRequest req,
930 return -1;457 return -1;
931 }458 }
932459
933 if (hash_file) {460 if (pw_hash_file) {
934 if (get_hash_from_file (hash_file, &pw_crypt) < 0) {461 if (get_pw_hash_from_file (pw_hash_file, &pw_crypt) < 0) {
935 fprintf (stderr, "Failed to read hash\n");462 fprintf (stderr, "Failed to read hash\n");
936 goto error;463 goto error;
937 }464 }
@@ -946,12 +473,7 @@ update_request (void *new_list, int list_len, MokRequest req,
946 goto error;473 goto error;
947 }474 }
948475
949 if (!use_simple_hash) {476 auth_ret = generate_pw_crypt (&pw_crypt, password, pw_len);
950 auth_ret = generate_hash (&pw_crypt, password, pw_len);
951 } else {
952 auth_ret = generate_auth (new_list, list_len, password,
953 pw_len, auth);
954 }
955 if (auth_ret < 0) {477 if (auth_ret < 0) {
956 fprintf (stderr, "Couldn't generate hash\n");478 fprintf (stderr, "Couldn't generate hash\n");
957 goto error;479 goto error;
@@ -960,12 +482,10 @@ update_request (void *new_list, int list_len, MokRequest req,
960482
961 if (new_list) {483 if (new_list) {
962 /* Write MokNew, MokDel, MokXNew, or MokXDel*/484 /* Write MokNew, MokDel, MokXNew, or MokXDel*/
963 data = new_list;485 ret = efi_set_variable (efi_guid_shim, req_name,
964 data_size = list_len;486 new_list, list_len, attributes,
965487 S_IRUSR | S_IWUSR);
966 if (efi_set_variable (efi_guid_shim, req_name,488 if (ret < 0) {
967 data, data_size, attributes,
968 S_IRUSR | S_IWUSR) < 0) {
969 switch (req) {489 switch (req) {
970 case ENROLL_MOK:490 case ENROLL_MOK:
971 fprintf (stderr, "Failed to enroll new keys\n");491 fprintf (stderr, "Failed to enroll new keys\n");
@@ -983,22 +503,16 @@ update_request (void *new_list, int list_len, MokRequest req,
983 goto error;503 goto error;
984 }504 }
985 } else {505 } else {
986 test_and_delete_var (req_name);506 test_and_delete_mok_var (req_name);
987 }507 }
988508
989 /* Write MokAuth, MokDelAuth, MokXAuth, or MokXDelAuth */509 /* Write MokAuth, MokDelAuth, MokXAuth, or MokXDelAuth */
990 if (!use_simple_hash) {510 ret = efi_set_variable (efi_guid_shim, auth_name, (void *)&pw_crypt,
991 data = (void *)&pw_crypt;511 PASSWORD_CRYPT_SIZE, attributes,
992 data_size = PASSWORD_CRYPT_SIZE;512 S_IRUSR | S_IWUSR);
993 } else {513 if (ret < 0) {
994 data = (void *)auth;
995 data_size = SHA256_DIGEST_LENGTH;
996 }
997
998 if (efi_set_variable (efi_guid_shim, auth_name, data, data_size,
999 attributes, S_IRUSR | S_IWUSR) < 0) {
1000 fprintf (stderr, "Failed to write %s\n", auth_name);514 fprintf (stderr, "Failed to write %s\n", auth_name);
1001 test_and_delete_var (req_name);515 test_and_delete_mok_var (req_name);
1002 goto error;516 goto error;
1003 }517 }
1004518
@@ -1010,45 +524,15 @@ error:
1010}524}
1011525
1012static int526static int
1013is_valid_cert (void *cert, uint32_t cert_size)527is_one_duplicate (const efi_guid_t *type,
1014{528 const void *data, const uint32_t data_size,
1015 X509 *X509cert;529 uint8_t *var_data, size_t var_data_size)
1016 BIO *cert_bio;
1017
1018 cert_bio = BIO_new (BIO_s_mem ());
1019 BIO_write (cert_bio, cert, cert_size);
1020 if (cert_bio == NULL) {
1021 return 0;
1022 }
1023
1024 X509cert = d2i_X509_bio (cert_bio, NULL);
1025 if (X509cert == NULL) {
1026 BIO_free (cert_bio);
1027 return 0;
1028 }
1029
1030 BIO_free (cert_bio);
1031
1032 return 1;
1033}
1034
1035static int
1036is_duplicate (const efi_guid_t *type, const void *data, const uint32_t data_size,
1037 const efi_guid_t *vendor, const char *db_name)
1038{530{
1039 uint8_t *var_data;
1040 size_t var_data_size;
1041 uint32_t attributes;
1042 uint32_t node_num;531 uint32_t node_num;
1043 MokListNode *list;532 MokListNode *list;
1044 int ret = 0;533 int ret = 0;
1045534
1046 if (!data || data_size == 0 || !db_name)535 if (!data || data_size == 0)
1047 return 0;
1048
1049 ret = efi_get_variable (*vendor, db_name, &var_data, &var_data_size,
1050 &attributes);
1051 if (ret < 0)
1052 return 0;536 return 0;
1053537
1054 list = build_mok_list (var_data, var_data_size, &node_num);538 list = build_mok_list (var_data, var_data_size, &node_num);
@@ -1057,7 +541,8 @@ is_duplicate (const efi_guid_t *type, const void *data, const uint32_t data_size
1057 }541 }
1058542
1059 for (unsigned int i = 0; i < node_num; i++) {543 for (unsigned int i = 0; i < node_num; i++) {
1060 if (efi_guid_cmp (&list[i].header->SignatureType, type) != 0)544 efi_guid_t sigtype = list[i].header->SignatureType;
545 if (efi_guid_cmp (&sigtype, type) != 0)
1061 continue;546 continue;
1062547
1063 if (efi_guid_cmp (type, &efi_guid_x509_cert) == 0) {548 if (efi_guid_cmp (type, &efi_guid_x509_cert) == 0) {
@@ -1080,24 +565,84 @@ is_duplicate (const efi_guid_t *type, const void *data, const uint32_t data_size
1080done:565done:
1081 if (list)566 if (list)
1082 free (list);567 free (list);
1083 free (var_data);
1084568
1085 return ret;569 return ret;
1086}570}
1087571
1088static int572static int
1089is_valid_request (const efi_guid_t *type, void *mok, uint32_t mok_size,573is_duplicate (const efi_guid_t *type,
1090 MokRequest req)574 const void *data, const uint32_t data_size,
575 const efi_guid_t *vendor, const char *db_name)
576{
577 uint32_t attributes;
578 char varname[] = "implausibly-long-mok-variable-name";
579 size_t varname_sz = sizeof(varname);
580 int ret = 0;
581 size_t i;
582
583 if (!strncmp(db_name, "Mok", 3)) {
584 uint8_t *var_data = NULL;
585 size_t var_data_size = 0;
586 ret = mok_get_variable(db_name, &var_data, &var_data_size);
587 if (ret >= 0) {
588 ret = is_one_duplicate(type, data, data_size,
589 var_data, var_data_size);
590 if (ret >= 0) {
591 free (var_data);
592 return ret;
593 }
594 var_data = NULL;
595 var_data_size = 0;
596 }
597 }
598
599 for (i = 0; i < SIZE_MAX; i++) {
600 uint8_t *var_data = NULL;
601 size_t var_data_size = 0;
602 if (i == 0) {
603 snprintf(varname, varname_sz, "%s", db_name);
604 } else {
605 snprintf(varname, varname_sz, "%s%zu", db_name, i);
606 }
607
608 ret = efi_get_variable (*vendor, varname,
609 &var_data, &var_data_size,
610 &attributes);
611 if (ret < 0)
612 return 0;
613
614 ret = is_one_duplicate(type, data, data_size,
615 var_data, var_data_size);
616 free (var_data);
617 /*
618 * If ret is < 0, the next one will error as well.
619 * If ret is 0, we need to test the next variable.
620 * If it's 1, that's a real answer.
621 */
622 if (ret < 0)
623 return 0;
624 if (ret > 0)
625 return ret;
626 }
627
628 return 0;
629}
630
631static int
632is_valid_request (const efi_guid_t *type, const void *mok,
633 const uint32_t mok_size, const MokRequest req)
1091{634{
1092 switch (req) {635 switch (req) {
1093 case ENROLL_MOK:636 case ENROLL_MOK:
1094 if (is_duplicate (type, mok, mok_size, &efi_guid_global, "PK") ||637 if (is_duplicate (type, mok, mok_size, &efi_guid_security, "db") ||
1095 is_duplicate (type, mok, mok_size, &efi_guid_global, "KEK") ||
1096 is_duplicate (type, mok, mok_size, &efi_guid_security, "db") ||
1097 is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListRT") ||638 is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListRT") ||
1098 is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokNew")) {639 is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokNew")) {
1099 return 0;640 return 0;
1100 }641 }
642 /* Also check the blocklists */
643 if (is_duplicate (type, mok, mok_size, &efi_guid_security, "dbx") ||
644 is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListXRT"))
645 return 0;
1101 break;646 break;
1102 case DELETE_MOK:647 case DELETE_MOK:
1103 if (!is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListRT") ||648 if (!is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListRT") ||
@@ -1111,111 +656,181 @@ is_valid_request (const efi_guid_t *type, void *mok, uint32_t mok_size,
1111 return 0;656 return 0;
1112 }657 }
1113 break;658 break;
1114 case DELETE_BLACKLIST:659 case DELETE_BLACKLIST:
1115 if (!is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListXRT") ||660 if (!is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListXRT") ||
1116 is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokXDel")) {661 is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokXDel")) {
1117 return 0;662 return 0;
1118 }663 }
664 break;
665 }
666
667 return 1;
668}
669
670static int
671is_ca_in_db (const void *cert, const uint32_t cert_size,
672 const efi_guid_t *vendor, const char *db_name)
673{
674 uint8_t *var_data = NULL;
675 size_t var_data_size;
676 uint32_t attributes;
677 uint32_t node_num;
678 MokListNode *list;
679 int ret = 0;
680
681 if (!cert || cert_size == 0 || !vendor || !db_name)
682 return 0;
683
684 ret = efi_get_variable (*vendor, db_name, &var_data, &var_data_size,
685 &attributes);
686 if (ret < 0)
687 return 0;
688
689 list = build_mok_list (var_data, var_data_size, &node_num);
690 if (list == NULL) {
691 goto done;
692 }
693
694 for (unsigned int i = 0; i < node_num; i++) {
695 efi_guid_t sigtype = list[i].header->SignatureType;
696 if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0)
697 continue;
698
699 if (is_immediate_ca (cert, cert_size, list[i].mok,
700 list[i].mok_size)) {
701 ret = 1;
702 break;
703 }
704 }
705
706done:
707 if (list)
708 free (list);
709 free (var_data);
710
711 return ret;
712}
713
714/* Check whether the CA cert is already enrolled */
715static int
716is_ca_enrolled (const void *mok, const uint32_t mok_size, const MokRequest req)
717{
718 switch (req) {
719 case ENROLL_MOK:
720 if (is_ca_in_db (mok, mok_size, &efi_guid_shim, "MokListRT"))
721 return 1;
722 break;
723 case ENROLL_BLACKLIST:
724 if (is_ca_in_db (mok, mok_size, &efi_guid_shim, "MokListXRT"))
725 return 1;
1119 break;726 break;
727 default:
728 return 0;
1120 }729 }
1121730
1122 return 1;731 return 0;
1123}732}
1124733
734/* Check whether the CA cert is blocked */
1125static int735static int
1126in_pending_request (const efi_guid_t *type, void *data, uint32_t data_size,736is_ca_blocked (const void *mok, const uint32_t mok_size, const MokRequest req)
1127 MokRequest req)
1128{737{
1129 uint8_t *authvar_data;738 switch (req) {
1130 size_t authvar_data_size;739 case ENROLL_MOK:
1131 uint32_t attributes;740 if (is_ca_in_db (mok, mok_size, &efi_guid_security, "dbx") ||
1132 int ret;741 is_ca_in_db (mok, mok_size, &efi_guid_shim, "MokListXRT"))
1133742 return 1;
1134 const char *authvar_names[] = {743 break;
1135 [DELETE_MOK] = "MokDelAuth",744 default:
1136 [ENROLL_MOK] = "MokAuth",
1137 [DELETE_BLACKLIST] = "MokXDelAuth",
1138 [ENROLL_BLACKLIST] = "MokXAuth"
1139 };
1140 const char *var_names[] = {
1141 [DELETE_MOK] = "MokDel",
1142 [ENROLL_MOK] = "Mok",
1143 [DELETE_BLACKLIST] = "MokXDel",
1144 [ENROLL_BLACKLIST] = "MokX"
1145 };
1146
1147 if (!data || data_size == 0)
1148 return 0;745 return 0;
746 }
1149747
1150 if (efi_get_variable (efi_guid_shim, authvar_names[req], &authvar_data,748 return 0;
1151 &authvar_data_size, &attributes) < 0)749}
1152 return 0;750
751/* Check whether the key is already in the kernel trusted keyring */
752static int
753is_in_trusted_keyring (const void *cert, const uint32_t cert_size)
754{
755 char *skid = NULL;
756 int ret;
1153757
1154 free (authvar_data);758 if (get_cert_skid (cert, cert_size, &skid) < 0)
1155 /* Check if the password hash is in the old format */
1156 if (authvar_data_size == SHA256_DIGEST_LENGTH)
1157 return 0;759 return 0;
1158760
1159 ret = delete_data_from_list (&efi_guid_shim, var_names[req],761 ret = match_skid_in_trusted_keyring (skid);
1160 type, data, data_size);
1161 if (ret < 0)762 if (ret < 0)
1162 return -1;763 ret = 0;
764
765 free (skid);
1163766
1164 return ret;767 return ret;
1165}768}
1166769
770static int
771in_reverse_pending_request (const efi_guid_t *type, const void *data,
772 uint32_t data_size, const MokRequest req)
773{
774 MokRequest reverse_req = get_reverse_req (req);
775
776 if (!data || data_size == 0)
777 return 0;
778
779 return delete_data_from_req_var (reverse_req, type, data, data_size);
780}
781
1167static void782static void
1168print_skip_message (const char *filename, void *mok, uint32_t mok_size,783print_skip_message (const char *filename, const void *mok,
1169 MokRequest req)784 const uint32_t mok_size, const MokRequest req)
1170{785{
1171 switch (req) {786 switch (req) {
1172 case ENROLL_MOK:787 case ENROLL_MOK:
1173 if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,788 if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
1174 &efi_guid_global, "PK"))789 &efi_guid_security, "db"))
1175 printf ("SKIP: %s is already in PK\n", filename);790 printf ("%s is already in db\n", filename);
1176 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
1177 &efi_guid_global, "KEK"))
1178 printf ("SKIP: %s is already in KEK\n", filename);
1179 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
1180 &efi_guid_security, "db"))
1181 printf ("SKIP: %s is already in db\n", filename);
1182 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,791 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
1183 &efi_guid_shim, "MokListRT"))792 &efi_guid_shim, "MokListRT"))
1184 printf ("SKIP: %s is already enrolled\n", filename);793 printf ("%s is already enrolled\n", filename);
1185 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,794 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
1186 &efi_guid_shim, "MokNew"))795 &efi_guid_shim, "MokNew"))
1187 printf ("SKIP: %s is already in the enrollement request\n", filename);796 printf ("%s is already in the enrollment request\n", filename);
797 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
798 &efi_guid_security, "dbx"))
799 printf ("%s is blocked in dbx\n", filename);
800 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
801 &efi_guid_shim, "MokListXRT"))
802 printf ("%s is blocked in MokListXRT\n", filename);
1188 break;803 break;
1189 case DELETE_MOK:804 case DELETE_MOK:
1190 if (!is_duplicate (&efi_guid_x509_cert, mok, mok_size,805 if (!is_duplicate (&efi_guid_x509_cert, mok, mok_size,
1191 &efi_guid_shim, "MokListRT"))806 &efi_guid_shim, "MokListRT"))
1192 printf ("SKIP: %s is not in MokList\n", filename);807 printf ("%s is not in MokList\n", filename);
1193 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,808 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
1194 &efi_guid_shim, "MokDel"))809 &efi_guid_shim, "MokDel"))
1195 printf ("SKIP: %s is already in the deletion request\n", filename);810 printf ("%s is already in the deletion request\n", filename);
1196 break;811 break;
1197 case ENROLL_BLACKLIST:812 case ENROLL_BLACKLIST:
1198 if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,813 if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
1199 &efi_guid_shim, "MokListXRT"))814 &efi_guid_shim, "MokListXRT"))
1200 printf ("SKIP: %s is already in MokListX\n", filename);815 printf ("%s is already in MokListX\n", filename);
1201 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,816 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
1202 &efi_guid_shim, "MokXNew"))817 &efi_guid_shim, "MokXNew"))
1203 printf ("SKIP: %s is already in the MokX enrollment request\n", filename);818 printf ("%s is already in the MokX enrollment request\n", filename);
1204 break;819 break;
1205 case DELETE_BLACKLIST:820 case DELETE_BLACKLIST:
1206 if (!is_duplicate (&efi_guid_x509_cert, mok, mok_size,821 if (!is_duplicate (&efi_guid_x509_cert, mok, mok_size,
1207 &efi_guid_shim, "MokListXRT"))822 &efi_guid_shim, "MokListXRT"))
1208 printf ("SKIP: %s is not in MokListX\n", filename);823 printf ("%s is not in MokListX\n", filename);
1209 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,824 else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size,
1210 &efi_guid_shim, "MokXDel"))825 &efi_guid_shim, "MokXDel"))
1211 printf ("SKIP: %s is already in the MokX deletion request\n", filename);826 printf ("%s is already in the MokX deletion request\n", filename);
1212 break;827 break;
1213 }828 }
1214}829}
1215830
1216static int831static int
1217issue_mok_request (char **files, uint32_t total, MokRequest req,832issue_mok_request (char **files, const uint32_t total, const MokRequest req,
1218 const char *hash_file, const int root_pw)833 const char *pw_hash_file, const int root_pw)
1219{834{
1220 uint8_t *old_req_data = NULL;835 uint8_t *old_req_data = NULL;
1221 size_t old_req_data_size = 0;836 size_t old_req_data_size = 0;
@@ -1231,18 +846,7 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
1231 int ret = -1;846 int ret = -1;
1232 EFI_SIGNATURE_LIST *CertList;847 EFI_SIGNATURE_LIST *CertList;
1233 EFI_SIGNATURE_DATA *CertData;848 EFI_SIGNATURE_DATA *CertData;
1234 const char *req_names[] = {849 const char *var_name = get_req_var_name (req);
1235 [DELETE_MOK] = "MokDel",
1236 [ENROLL_MOK] = "MokNew",
1237 [DELETE_BLACKLIST] = "MokXDel",
1238 [ENROLL_BLACKLIST] = "MokXNew"
1239 };
1240 const char *reverse_req_names[] = {
1241 [DELETE_MOK] = "MokNew",
1242 [ENROLL_MOK] = "MokDel",
1243 [DELETE_BLACKLIST] = "MokXNew",
1244 [ENROLL_BLACKLIST] = "MokXDel"
1245 };
1246850
1247 if (!files)851 if (!files)
1248 return -1;852 return -1;
@@ -1268,12 +872,12 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
1268 list_size += sizeof(EFI_SIGNATURE_LIST) * total;872 list_size += sizeof(EFI_SIGNATURE_LIST) * total;
1269 list_size += sizeof(efi_guid_t) * total;873 list_size += sizeof(efi_guid_t) * total;
1270874
1271 ret = efi_get_variable (efi_guid_shim, req_names[req], &old_req_data,875 ret = efi_get_variable (efi_guid_shim, var_name, &old_req_data,
1272 &old_req_data_size, &attributes);876 &old_req_data_size, &attributes);
1273 if (ret < 0) {877 if (ret < 0) {
1274 if (errno != ENOENT) {878 if (errno != ENOENT) {
1275 fprintf (stderr, "Failed to read variable \"%s\": %m\n",879 fprintf (stderr, "Failed to read variable \"%s\": %m\n",
1276 req_names[req]);880 var_name);
1277 goto error;881 goto error;
1278 }882 }
1279 } else {883 } else {
@@ -1284,7 +888,7 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
1284 new_list = malloc (list_size);888 new_list = malloc (list_size);
1285 if (!new_list) {889 if (!new_list) {
1286 fprintf (stderr, "Failed to allocate space for %s\n",890 fprintf (stderr, "Failed to allocate space for %s\n",
1287 req_names[req]);891 var_name);
1288 goto error;892 goto error;
1289 }893 }
1290 ptr = new_list;894 ptr = new_list;
@@ -1313,23 +917,53 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
1313 read_size = read (fd, ptr, sizes[i]);917 read_size = read (fd, ptr, sizes[i]);
1314 if (read_size < 0 || read_size != (int64_t)sizes[i]) {918 if (read_size < 0 || read_size != (int64_t)sizes[i]) {
1315 fprintf (stderr, "Failed to read %s\n", files[i]);919 fprintf (stderr, "Failed to read %s\n", files[i]);
920 close (fd);
1316 goto error;921 goto error;
1317 }922 }
1318 if (!is_valid_cert (ptr, read_size)) {923
924 const void *mok = ptr;
925 const uint32_t mok_size = sizes[i];
926
927 if (!is_valid_cert (mok, mok_size)) {
1319 fprintf (stderr, "Abort!!! %s is not a valid x509 certificate in DER format\n",928 fprintf (stderr, "Abort!!! %s is not a valid x509 certificate in DER format\n",
1320 files[i]);929 files[i]);
930 close (fd);
1321 goto error;931 goto error;
1322 }932 }
1323933
1324 if (is_valid_request (&efi_guid_x509_cert, ptr, sizes[i], req)) {934 /* Check whether the key is already in the trusted keyring */
1325 ptr += sizes[i];935 if (req == ENROLL_MOK && check_keyring &&
1326 real_size += sizes[i] + sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);936 is_in_trusted_keyring (mok, mok_size)) {
1327 } else if (in_pending_request (&efi_guid_x509_cert, ptr, sizes[i], req)) {937 printf ("Already in kernel trusted keyring. Skip %s\n",
938 files[i]);
939 close (fd);
940 continue;
941 }
942
943 /* Check whether CA is already enrolled */
944 if (force_ca_check && is_ca_enrolled (mok, mok_size, req)) {
945 printf ("CA enrolled. Skip %s\n", files[i]);
946 close (fd);
947 continue;
948 }
949
950 /* Check whether CA is blocked */
951 if (force_ca_check && is_ca_blocked (mok, mok_size, req)) {
952 printf ("CA blocked. Skip %s\n", files[i]);
953 close (fd);
954 continue;
955 }
956
957 if (is_valid_request (&efi_guid_x509_cert, mok, mok_size, req)) {
958 ptr += mok_size;
959 real_size += mok_size + sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
960 } else if (in_reverse_pending_request (&efi_guid_x509_cert, mok, mok_size, req)) {
1328 printf ("Removed %s from %s\n", files[i],961 printf ("Removed %s from %s\n", files[i],
1329 reverse_req_names[req]);962 get_reverse_req_var_name (req));
1330 ptr -= sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);963 ptr -= sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
1331 } else {964 } else {
1332 print_skip_message (files[i], ptr, sizes[i], req);965 printf ("SKIP: ");
966 print_skip_message (files[i], mok, mok_size, req);
1333 ptr -= sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);967 ptr -= sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t);
1334 }968 }
1335969
@@ -1348,7 +982,7 @@ issue_mok_request (char **files, uint32_t total, MokRequest req,
1348 real_size += old_req_data_size;982 real_size += old_req_data_size;
1349 }983 }
1350984
1351 if (update_request (new_list, real_size, req, hash_file, root_pw) < 0) {985 if (update_request (new_list, real_size, req, pw_hash_file, root_pw) < 0) {
1352 goto error;986 goto error;
1353 }987 }
1354988
@@ -1365,50 +999,7 @@ error:
1365}999}
13661000
1367static int1001static int
1368identify_hash_type (const char *hash_str, efi_guid_t *type)1002hex_str_to_binary (const char *hex_str, uint8_t *array, const unsigned int len)
1369{
1370 unsigned int len = strlen (hash_str);
1371 int hash_size;
1372
1373 for (unsigned int i = 0; i < len; i++) {
1374 if ((hash_str[i] > '9' || hash_str[i] < '0') &&
1375 (hash_str[i] > 'f' || hash_str[i] < 'a') &&
1376 (hash_str[i] > 'F' || hash_str[i] < 'A'))
1377 return -1;
1378 }
1379
1380 switch (len) {
1381#if 0
1382 case SHA_DIGEST_LENGTH*2:
1383 *type = efi_guid_sha1;
1384 hash_size = SHA_DIGEST_LENGTH;
1385 break;
1386#endif
1387 case SHA224_DIGEST_LENGTH*2:
1388 *type = efi_guid_sha224;
1389 hash_size = SHA224_DIGEST_LENGTH;
1390 break;
1391 case SHA256_DIGEST_LENGTH*2:
1392 *type = efi_guid_sha256;
1393 hash_size = SHA256_DIGEST_LENGTH;
1394 break;
1395 case SHA384_DIGEST_LENGTH*2:
1396 *type = efi_guid_sha384;
1397 hash_size = SHA384_DIGEST_LENGTH;
1398 break;
1399 case SHA512_DIGEST_LENGTH*2:
1400 *type = efi_guid_sha512;
1401 hash_size = SHA512_DIGEST_LENGTH;
1402 break;
1403 default:
1404 return -1;
1405 }
1406
1407 return hash_size;
1408}
1409
1410static int
1411hex_str_to_binary (const char *hex_str, uint8_t *array, unsigned int len)
1412{1003{
1413 char *pos;1004 char *pos;
14141005
@@ -1425,14 +1016,12 @@ hex_str_to_binary (const char *hex_str, uint8_t *array, unsigned int len)
1425}1016}
14261017
1427static int1018static int
1428issue_hash_request (const char *hash_str, MokRequest req,1019issue_hash_request (const char *hash_str, const MokRequest req,
1429 const char *hash_file, const int root_pw)1020 const char *pw_hash_file, const int root_pw)
1430{1021{
1431 uint8_t *old_req_data = NULL;1022 uint8_t *old_req_data = NULL;
1432 size_t old_req_data_size = 0;1023 size_t old_req_data_size = 0;
1433 uint32_t attributes;1024 uint32_t attributes;
1434 const char *req_name;
1435 const char *reverse_req;
1436 void *new_list = NULL;1025 void *new_list = NULL;
1437 void *ptr;1026 void *ptr;
1438 unsigned long list_size = 0;1027 unsigned long list_size = 0;
@@ -1444,9 +1033,9 @@ issue_hash_request (const char *hash_str, MokRequest req,
1444 uint8_t db_hash[SHA512_DIGEST_LENGTH];1033 uint8_t db_hash[SHA512_DIGEST_LENGTH];
1445 int hash_size;1034 int hash_size;
1446 int merge_ind = -1;1035 int merge_ind = -1;
1447 uint8_t valid = 0;
1448 MokListNode *mok_list = NULL;1036 MokListNode *mok_list = NULL;
1449 uint32_t mok_num;1037 uint32_t mok_num;
1038 const char *var_name = get_req_var_name (req);
14501039
1451 if (!hash_str)1040 if (!hash_str)
1452 return -1;1041 return -1;
@@ -1458,48 +1047,24 @@ issue_hash_request (const char *hash_str, MokRequest req,
1458 if (hex_str_to_binary (hash_str, db_hash, hash_size) < 0)1047 if (hex_str_to_binary (hash_str, db_hash, hash_size) < 0)
1459 return -1;1048 return -1;
14601049
1461 switch (req) {1050 if (is_valid_request (&hash_type, db_hash, hash_size, req) == 0) {
1462 case ENROLL_MOK:
1463 req_name = "MokNew";
1464 reverse_req = "MokDel";
1465 break;
1466 case DELETE_MOK:
1467 req_name = "MokDel";
1468 reverse_req = "MokNew";
1469 break;
1470 case ENROLL_BLACKLIST:
1471 req_name = "MokXNew";
1472 reverse_req = "MokXDel";
1473 break;
1474 case DELETE_BLACKLIST:
1475 req_name = "MokXDel";
1476 reverse_req = "MokXNew";
1477 break;
1478 default:
1479 return -1;
1480 }
1481
1482 if (is_valid_request (&hash_type, db_hash, hash_size, req)) {
1483 valid = 1;
1484 } else if (in_pending_request (&hash_type, db_hash, hash_size, req)) {
1485 printf ("Removed hash from %s\n", reverse_req);
1486 } else {
1487 printf ("Skip hash\n");1051 printf ("Skip hash\n");
1488 }1052 ret = 0;
14891053 goto error;
1490 if (!valid) {1054 } else if (in_reverse_pending_request (&hash_type, db_hash, hash_size, req)) {
1055 printf ("Removed hash from %s\n", get_reverse_req_var_name (req));
1491 ret = 0;1056 ret = 0;
1492 goto error;1057 goto error;
1493 }1058 }
14941059
1495 list_size = sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t) + hash_size;1060 list_size = sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t) + hash_size;
14961061
1497 ret = efi_get_variable (efi_guid_shim, req_name, &old_req_data,1062 ret = efi_get_variable (efi_guid_shim, var_name, &old_req_data,
1498 &old_req_data_size, &attributes);1063 &old_req_data_size, &attributes);
1499 if (ret < 0) {1064 if (ret < 0) {
1500 if (errno != ENOENT) {1065 if (errno != ENOENT) {
1501 fprintf (stderr, "Failed to read variable \"%s\": %m\n",1066 fprintf (stderr, "Failed to read variable \"%s\": %m\n",
1502 req_name);1067 var_name);
1503 goto error;1068 goto error;
1504 }1069 }
1505 } else {1070 } else {
@@ -1510,8 +1075,8 @@ issue_hash_request (const char *hash_str, MokRequest req,
1510 goto error;1075 goto error;
1511 /* Check if there is a signature list with the same type */1076 /* Check if there is a signature list with the same type */
1512 for (unsigned int i = 0; i < mok_num; i++) {1077 for (unsigned int i = 0; i < mok_num; i++) {
1513 if (efi_guid_cmp (&mok_list[i].header->SignatureType,1078 efi_guid_t sigtype = mok_list[i].header->SignatureType;
1514 &hash_type) == 0) {1079 if (efi_guid_cmp (&sigtype, &hash_type) == 0) {
1515 merge_ind = i;1080 merge_ind = i;
1516 list_size -= sizeof(EFI_SIGNATURE_LIST);1081 list_size -= sizeof(EFI_SIGNATURE_LIST);
1517 break;1082 break;
@@ -1523,7 +1088,7 @@ issue_hash_request (const char *hash_str, MokRequest req,
1523 new_list = malloc (list_size);1088 new_list = malloc (list_size);
1524 if (!new_list) {1089 if (!new_list) {
1525 fprintf (stderr, "Failed to allocate space for %s: %m\n",1090 fprintf (stderr, "Failed to allocate space for %s: %m\n",
1526 req_name);1091 var_name);
1527 goto error;1092 goto error;
1528 }1093 }
1529 ptr = new_list;1094 ptr = new_list;
@@ -1577,7 +1142,7 @@ issue_hash_request (const char *hash_str, MokRequest req,
1577 }1142 }
1578 }1143 }
15791144
1580 if (update_request (new_list, list_size, req, hash_file, root_pw) < 0) {1145 if (update_request (new_list, list_size, req, pw_hash_file, root_pw) < 0) {
1581 goto error;1146 goto error;
1582 }1147 }
15831148
@@ -1594,34 +1159,12 @@ error:
1594}1159}
15951160
1596static int1161static int
1597revoke_request (MokRequest req)1162revoke_request (const MokRequest req)
1598{1163{
1599 switch (req) {1164 if (test_and_delete_mok_var (get_req_var_name(req)) < 0)
1600 case ENROLL_MOK:1165 return -1;
1601 if (test_and_delete_var ("MokNew") < 0)1166 if (test_and_delete_mok_var (get_req_auth_var_name(req)) < 0)
1602 return -1;1167 return -1;
1603 if (test_and_delete_var ("MokAuth") < 0)
1604 return -1;
1605 break;
1606 case DELETE_MOK:
1607 if (test_and_delete_var ("MokDel") < 0)
1608 return -1;
1609 if (test_and_delete_var ("MokDelAuth") < 0)
1610 return -1;
1611 break;
1612 case ENROLL_BLACKLIST:
1613 if (test_and_delete_var ("MokXNew") < 0)
1614 return -1;
1615 if (test_and_delete_var ("MokXAuth") < 0)
1616 return -1;
1617 break;
1618 case DELETE_BLACKLIST:
1619 if (test_and_delete_var ("MokXDel") < 0)
1620 return -1;
1621 if (test_and_delete_var ("MokXDelAuth") < 0)
1622 return -1;
1623 break;
1624 }
16251168
1626 return 0;1169 return 0;
1627}1170}
@@ -1629,6 +1172,7 @@ revoke_request (MokRequest req)
1629static int1172static int
1630export_db_keys (const DBName db_name)1173export_db_keys (const DBName db_name)
1631{1174{
1175 const char *db_var_name;
1632 uint8_t *data = NULL;1176 uint8_t *data = NULL;
1633 size_t data_size = 0;1177 size_t data_size = 0;
1634 uint32_t attributes;1178 uint32_t attributes;
@@ -1655,15 +1199,17 @@ export_db_keys (const DBName db_name)
1655 break;1199 break;
1656 };1200 };
16571201
1658 ret = efi_get_variable (guid, db_var_name[db_name], &data, &data_size,1202 db_var_name = get_db_var_name(db_name);
1203
1204 ret = efi_get_variable (guid, db_var_name, &data, &data_size,
1659 &attributes);1205 &attributes);
1660 if (ret < 0) {1206 if (ret < 0) {
1661 if (errno == ENOENT) {1207 if (errno == ENOENT) {
1662 printf ("%s is empty\n", db_var_name[db_name]);1208 printf ("%s is empty\n", db_var_name);
1663 return 0;1209 return 0;
1664 }1210 }
16651211
1666 fprintf (stderr, "Failed to read %s: %m\n", db_var_name[db_name]);1212 fprintf (stderr, "Failed to read %s: %m\n", db_var_name);
1667 return -1;1213 return -1;
1668 }1214 }
1669 ret = -1;1215 ret = -1;
@@ -1678,12 +1224,14 @@ export_db_keys (const DBName db_name)
1678 for (unsigned i = 0; i < mok_num; i++) {1224 for (unsigned i = 0; i < mok_num; i++) {
1679 off_t offset = 0;1225 off_t offset = 0;
1680 ssize_t write_size;1226 ssize_t write_size;
1227 efi_guid_t sigtype = list[i].header->SignatureType;
16811228
1682 if (efi_guid_cmp (&list[i].header->SignatureType, &efi_guid_x509_cert) != 0)1229 if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0)
1683 continue;1230 continue;
16841231
1685 /* Dump X509 certificate to files */1232 /* Dump X509 certificate to files */
1686 snprintf (filename, PATH_MAX, "%s-%04d.der", db_friendly_name[db_name], i+1);1233 snprintf (filename, PATH_MAX, "%s-%04d.der",
1234 get_db_friendly_name(db_name), i+1);
1687 fd = open (filename, O_CREAT | O_WRONLY, mode);1235 fd = open (filename, O_CREAT | O_WRONLY, mode);
1688 if (fd < 0) {1236 if (fd < 0) {
1689 fprintf (stderr, "Failed to open %s: %m\n", filename);1237 fprintf (stderr, "Failed to open %s: %m\n", filename);
@@ -1714,22 +1262,18 @@ error:
1714}1262}
17151263
1716static int1264static int
1717set_password (const char *hash_file, const int root_pw, const int clear)1265set_password (const char *pw_hash_file, const int root_pw, const int clear)
1718{1266{
1719 uint8_t *data;
1720 size_t data_size;
1721 pw_crypt_t pw_crypt;1267 pw_crypt_t pw_crypt;
1722 uint8_t auth[SHA256_DIGEST_LENGTH];
1723 char *password = NULL;1268 char *password = NULL;
1724 unsigned int pw_len;1269 unsigned int pw_len;
1725 int auth_ret;1270 int auth_ret;
1726 int ret = -1;1271 int ret = -1;
17271272
1728 memset (&pw_crypt, 0, sizeof(pw_crypt_t));1273 memset (&pw_crypt, 0, sizeof(pw_crypt_t));
1729 memset (auth, 0, SHA256_DIGEST_LENGTH);
17301274
1731 if (hash_file) {1275 if (pw_hash_file) {
1732 if (get_hash_from_file (hash_file, &pw_crypt) < 0) {1276 if (get_pw_hash_from_file (pw_hash_file, &pw_crypt) < 0) {
1733 fprintf (stderr, "Failed to read hash\n");1277 fprintf (stderr, "Failed to read hash\n");
1734 goto error;1278 goto error;
1735 }1279 }
@@ -1744,31 +1288,20 @@ set_password (const char *hash_file, const int root_pw, const int clear)
1744 goto error;1288 goto error;
1745 }1289 }
17461290
1747 if (!use_simple_hash) {1291 pw_crypt.method = DEFAULT_CRYPT_METHOD;
1748 pw_crypt.method = DEFAULT_CRYPT_METHOD;1292 auth_ret = generate_pw_crypt (&pw_crypt, password, pw_len);
1749 auth_ret = generate_hash (&pw_crypt, password, pw_len);
1750 } else {
1751 auth_ret = generate_auth (NULL, 0, password, pw_len,
1752 auth);
1753 }
1754 if (auth_ret < 0) {1293 if (auth_ret < 0) {
1755 fprintf (stderr, "Couldn't generate hash\n");1294 fprintf (stderr, "Couldn't generate hash\n");
1756 goto error;1295 goto error;
1757 }1296 }
1758 }1297 }
17591298
1760 if (!use_simple_hash) {
1761 data = (void *)&pw_crypt;
1762 data_size = PASSWORD_CRYPT_SIZE;
1763 } else {
1764 data = (void *)auth;
1765 data_size = SHA256_DIGEST_LENGTH;
1766 }
1767 uint32_t attributes = EFI_VARIABLE_NON_VOLATILE1299 uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
1768 | EFI_VARIABLE_BOOTSERVICE_ACCESS1300 | EFI_VARIABLE_BOOTSERVICE_ACCESS
1769 | EFI_VARIABLE_RUNTIME_ACCESS;1301 | EFI_VARIABLE_RUNTIME_ACCESS;
1770 ret = efi_set_variable (efi_guid_shim, "MokPW", data, data_size,1302 ret = efi_set_variable (efi_guid_shim, "MokPW", (void *)&pw_crypt,
1771 attributes, S_IRUSR | S_IWUSR);1303 PASSWORD_CRYPT_SIZE, attributes,
1304 S_IRUSR | S_IWUSR);
1772 if (ret < 0) {1305 if (ret < 0) {
1773 fprintf (stderr, "Failed to write MokPW: %m\n");1306 fprintf (stderr, "Failed to write MokPW: %m\n");
1774 goto error;1307 goto error;
@@ -1782,7 +1315,7 @@ error:
1782}1315}
17831316
1784static int1317static int
1785set_toggle (const char * VarName, uint32_t state)1318set_toggle (const char * VarName, const uint32_t state)
1786{1319{
1787 uint32_t attributes;1320 uint32_t attributes;
1788 MokToggleVar tvar;1321 MokToggleVar tvar;
@@ -1823,14 +1356,14 @@ error:
1823 return ret;1356 return ret;
1824}1357}
18251358
1826static int1359static inline int
1827disable_validation()1360disable_validation(void)
1828{1361{
1829 return set_toggle("MokSB", 0);1362 return set_toggle("MokSB", 0);
1830}1363}
18311364
1832static int1365static inline int
1833enable_validation()1366enable_validation(void)
1834{1367{
1835 return set_toggle("MokSB", 1);1368 return set_toggle("MokSB", 1);
1836}1369}
@@ -1838,7 +1371,7 @@ enable_validation()
1838static int1371static int
1839sb_state ()1372sb_state ()
1840{1373{
1841 uint8_t *data;1374 uint8_t *data = NULL;
1842 size_t data_size;1375 size_t data_size;
1843 uint32_t attributes;1376 uint32_t attributes;
1844 int32_t secureboot = -1;1377 int32_t secureboot = -1;
@@ -1856,17 +1389,16 @@ sb_state ()
1856 printf ("Strange data size %zd for \"SecureBoot\" variable\n",1389 printf ("Strange data size %zd for \"SecureBoot\" variable\n",
1857 data_size);1390 data_size);
1858 }1391 }
1859 if (data_size == 4) {1392 if (data_size == 4 || data_size == 2 || data_size == 1) {
1860 secureboot = (int32_t)*(uint32_t *)data;1393 secureboot = 0;
1861 } else if (data_size == 2) {1394 memcpy(&secureboot, data, data_size);
1862 secureboot = (int32_t)*(uint16_t *)data;
1863 } else if (data_size == 1) {
1864 secureboot = (int32_t)*(uint8_t *)data;
1865 }1395 }
1396 free (data);
18661397
1398 data = NULL;
1867 if (efi_get_variable (efi_guid_global, "SetupMode", &data, &data_size,1399 if (efi_get_variable (efi_guid_global, "SetupMode", &data, &data_size,
1868 &attributes) < 0) {1400 &attributes) < 0) {
1869 fprintf (stderr, "Failed to read \"SecureBoot\" "1401 fprintf (stderr, "Failed to read \"SetupMode\" "
1870 "variable: %m\n");1402 "variable: %m\n");
1871 return -1;1403 return -1;
1872 }1404 }
@@ -1875,17 +1407,17 @@ sb_state ()
1875 printf ("Strange data size %zd for \"SetupMode\" variable\n",1407 printf ("Strange data size %zd for \"SetupMode\" variable\n",
1876 data_size);1408 data_size);
1877 }1409 }
1878 if (data_size == 4) {1410 if (data_size == 4 || data_size == 2 || data_size == 1) {
1879 setupmode = (int32_t)*(uint32_t *)data;1411 setupmode = 0;
1880 } else if (data_size == 2) {1412 memcpy(&setupmode, data, data_size);
1881 setupmode = (int32_t)*(uint16_t *)data;
1882 } else if (data_size == 1) {
1883 setupmode = (int32_t)*(uint8_t *)data;
1884 }1413 }
1414 free (data);
18851415
1416 data = NULL;
1886 if (efi_get_variable (efi_guid_shim, "MokSBStateRT", &data, &data_size,1417 if (efi_get_variable (efi_guid_shim, "MokSBStateRT", &data, &data_size,
1887 &attributes) >= 0) {1418 &attributes) >= 0) {
1888 moksbstate = 1;1419 moksbstate = 1;
1420 free (data);
1889 }1421 }
18901422
1891 if (secureboot == 1 && setupmode == 0) {1423 if (secureboot == 1 && setupmode == 0) {
@@ -1900,25 +1432,36 @@ sb_state ()
1900 printf ("Cannot determine secure boot state.\n");1432 printf ("Cannot determine secure boot state.\n");
1901 }1433 }
19021434
1903 free (data);
1904
1905 return 0;1435 return 0;
1906}1436}
19071437
1908static int1438static inline int
1909disable_db()1439disable_db(void)
1910{1440{
1911 return set_toggle("MokDB", 0);1441 return set_toggle("MokDB", 0);
1912}1442}
19131443
1914static int1444static inline int
1915enable_db()1445enable_db(void)
1916{1446{
1917 return set_toggle("MokDB", 1);1447 return set_toggle("MokDB", 1);
1918}1448}
19191449
1450static int
1451trust_mok_keys()
1452{
1453 return set_toggle("MokListTrustedNew", 0);
1454}
1455
1456static int
1457untrust_mok_keys()
1458{
1459 return set_toggle("MokListTrustedNew", 1);
1460}
1461
1920static inline int1462static inline int
1921read_file(int fd, void **bufp, size_t *lenptr) {1463read_file(const int fd, void **bufp, size_t *lenptr)
1464{
1922 int alloced = 0, size = 0, i = 0;1465 int alloced = 0, size = 0, i = 0;
1923 void *buf = NULL;1466 void *buf = NULL;
1924 void *buf_new = NULL;1467 void *buf_new = NULL;
@@ -1950,7 +1493,7 @@ read_file(int fd, void **bufp, size_t *lenptr) {
1950}1493}
19511494
1952static int1495static int
1953test_key (MokRequest req, const char *key_file)1496test_key (const MokRequest req, const char *key_file)
1954{1497{
1955 void *key = NULL;1498 void *key = NULL;
1956 size_t read_size;1499 size_t read_size;
@@ -1968,11 +1511,34 @@ test_key (MokRequest req, const char *key_file)
1968 goto error;1511 goto error;
1969 }1512 }
19701513
1514 if (!is_valid_cert (key, read_size)) {
1515 fprintf (stderr, "Not a valid x509 certificate\n");
1516 goto error;
1517 }
1518
1519 if (check_keyring && is_in_trusted_keyring (key, read_size)) {
1520 fprintf (stderr, "%s is already in the built-in trusted keyring\n",
1521 key_file);
1522 goto error;
1523 }
1524
1525 if (force_ca_check && is_ca_enrolled (key, read_size, req)) {
1526 fprintf (stderr, "CA of %s is already enrolled\n",
1527 key_file);
1528 goto error;
1529 }
1530
1531 if (force_ca_check && is_ca_blocked (key, read_size, req)) {
1532 fprintf (stderr, "CA of %s is blocked\n",
1533 key_file);
1534 goto error;
1535 }
1536
1971 if (is_valid_request (&efi_guid_x509_cert, key, read_size, req)) {1537 if (is_valid_request (&efi_guid_x509_cert, key, read_size, req)) {
1972 printf ("%s is not enrolled\n", key_file);1538 printf ("%s is not enrolled\n", key_file);
1973 ret = 0;1539 ret = 0;
1974 } else {1540 } else {
1975 printf ("%s is already enrolled\n", key_file);1541 print_skip_message (key_file, key, read_size, req);
1976 ret = 1;1542 ret = 1;
1977 }1543 }
19781544
@@ -1987,9 +1553,9 @@ error:
1987}1553}
19881554
1989static int1555static int
1990reset_moks (MokRequest req, const char *hash_file, const int root_pw)1556reset_moks (const MokRequest req, const char *pw_hash_file, const int root_pw)
1991{1557{
1992 if (update_request (NULL, 0, req, hash_file, root_pw)) {1558 if (update_request (NULL, 0, req, pw_hash_file, root_pw)) {
1993 fprintf (stderr, "Failed to issue a reset request\n");1559 fprintf (stderr, "Failed to issue a reset request\n");
1994 return -1;1560 return -1;
1995 }1561 }
@@ -2005,7 +1571,7 @@ generate_pw_hash (const char *input_pw)
2005 char *password = NULL;1571 char *password = NULL;
2006 char *crypt_string;1572 char *crypt_string;
2007 const char *prefix;1573 const char *prefix;
2008 int settings_len = sizeof (settings) - 2;1574 size_t settings_len = sizeof (settings) - 2;
2009 unsigned int pw_len, salt_size;1575 unsigned int pw_len, salt_size;
20101576
2011 if (input_pw) {1577 if (input_pw) {
@@ -2034,13 +1600,13 @@ generate_pw_hash (const char *input_pw)
20341600
2035 memset (settings, 0, sizeof (settings));1601 memset (settings, 0, sizeof (settings));
2036 next = stpncpy (settings, prefix, settings_len);1602 next = stpncpy (settings, prefix, settings_len);
2037 salt_size = get_salt_size (DEFAULT_CRYPT_METHOD);1603 salt_size = get_pw_salt_size (DEFAULT_CRYPT_METHOD);
2038 if (salt_size > settings_len - (next - settings)) {1604 if (salt_size > settings_len - (next - settings)) {
2039 free(password);1605 free(password);
2040 errno = EOVERFLOW;1606 errno = EOVERFLOW;
2041 return -1;1607 return -1;
2042 }1608 }
2043 generate_salt (next, salt_size);1609 generate_pw_salt (next, salt_size);
2044 next += salt_size;1610 next += salt_size;
2045 *next = '\0';1611 *next = '\0';
20461612
@@ -2057,7 +1623,7 @@ generate_pw_hash (const char *input_pw)
2057}1623}
20581624
2059static int1625static int
2060set_timeout (char *t)1626set_timeout (const char *t)
2061{1627{
2062 int timeout = strtol(t, NULL, 10);1628 int timeout = strtol(t, NULL, 10);
20631629
@@ -2077,14 +1643,39 @@ set_timeout (char *t)
2077 return -1;1643 return -1;
2078 }1644 }
2079 } else {1645 } else {
2080 return test_and_delete_var ("MokTimeout");1646 return test_and_delete_mok_var ("MokTimeout");
2081 }1647 }
20821648
2083 return 0;1649 return 0;
2084}1650}
20851651
2086static int1652static int
2087set_verbosity (uint8_t verbosity)1653print_var_content (const char *var_name, const efi_guid_t guid)
1654{
1655 uint8_t *data = NULL;
1656 size_t data_size;
1657 uint32_t attributes;
1658 int ret;
1659
1660 ret = efi_get_variable (guid, var_name, &data, &data_size, &attributes);
1661 if (ret < 0) {
1662 if (errno == ENOENT) {
1663 printf ("%s is empty\n", var_name);
1664 return 0;
1665 }
1666
1667 fprintf (stderr, "Failed to read %s: %m\n", var_name);
1668 return -1;
1669 }
1670
1671 printf ("%s", data);
1672 free (data);
1673
1674 return ret;
1675}
1676
1677static int
1678set_verbosity (const uint8_t verbosity)
2088{1679{
2089 if (verbosity) {1680 if (verbosity) {
2090 uint32_t attributes = EFI_VARIABLE_NON_VOLATILE1681 uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
@@ -2097,14 +1688,54 @@ set_verbosity (uint8_t verbosity)
2097 return -1;1688 return -1;
2098 }1689 }
2099 } else {1690 } else {
2100 return test_and_delete_var ("SHIM_VERBOSE");1691 return test_and_delete_mok_var ("SHIM_VERBOSE");
1692 }
1693
1694 return 0;
1695}
1696
1697static int
1698set_fallback_verbosity (const uint8_t verbosity)
1699{
1700 if (verbosity) {
1701 uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
1702 | EFI_VARIABLE_BOOTSERVICE_ACCESS
1703 | EFI_VARIABLE_RUNTIME_ACCESS;
1704 if (efi_set_variable (efi_guid_shim, "FALLBACK_VERBOSE",
1705 (uint8_t *)&verbosity, sizeof (verbosity),
1706 attributes, S_IRUSR | S_IWUSR) < 0) {
1707 fprintf (stderr, "Failed to set FALLBACK_VERBOSE\n");
1708 return -1;
1709 }
1710 } else {
1711 return test_and_delete_mok_var ("FALLBACK_VERBOSE");
1712 }
1713
1714 return 0;
1715}
1716
1717static int
1718set_fallback_noreboot (const uint8_t noreboot)
1719{
1720 if (noreboot) {
1721 uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
1722 | EFI_VARIABLE_BOOTSERVICE_ACCESS
1723 | EFI_VARIABLE_RUNTIME_ACCESS;
1724 if (efi_set_variable (efi_guid_shim, "FB_NO_REBOOT",
1725 (uint8_t *)&noreboot, sizeof (noreboot),
1726 attributes, S_IRUSR | S_IWUSR) < 0) {
1727 fprintf (stderr, "Failed to set FB_NO_REBOOT\n");
1728 return -1;
1729 }
1730 } else {
1731 return test_and_delete_mok_var ("FB_NO_REBOOT");
2101 }1732 }
21021733
2103 return 0;1734 return 0;
2104}1735}
21051736
2106static inline int1737static inline int
2107list_db (DBName db_name)1738list_db (const DBName db_name)
2108{1739{
2109 switch (db_name) {1740 switch (db_name) {
2110 case MOK_LIST_RT:1741 case MOK_LIST_RT:
@@ -2124,12 +1755,32 @@ list_db (DBName db_name)
2124 return -1;1755 return -1;
2125}1756}
21261757
1758static int
1759manage_sbat (const uint8_t sbat_policy)
1760{
1761 if (sbat_policy) {
1762 uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
1763 | EFI_VARIABLE_BOOTSERVICE_ACCESS
1764 | EFI_VARIABLE_RUNTIME_ACCESS;
1765 if (efi_set_variable (efi_guid_shim, "SbatPolicy",
1766 (uint8_t *)&sbat_policy,
1767 sizeof (sbat_policy),
1768 attributes, S_IRUSR | S_IWUSR) < 0) {
1769 fprintf (stderr, "Failed to set SbatPolicy\n");
1770 return -1;
1771 }
1772 } else {
1773 return test_and_delete_mok_var ("SbatPolicy");
1774 }
1775 return 0;
1776}
1777
2127int1778int
2128main (int argc, char *argv[])1779main (int argc, char *argv[])
2129{1780{
2130 char **files = NULL;1781 char **files = NULL;
2131 char *key_file = NULL;1782 char *key_file = NULL;
2132 char *hash_file = NULL;1783 char *pw_hash_file = NULL;
2133 char *input_pw = NULL;1784 char *input_pw = NULL;
2134 char *hash_str = NULL;1785 char *hash_str = NULL;
2135 char *timeout = NULL;1786 char *timeout = NULL;
@@ -2138,10 +1789,15 @@ main (int argc, char *argv[])
2138 unsigned int command = 0;1789 unsigned int command = 0;
2139 int use_root_pw = 0;1790 int use_root_pw = 0;
2140 uint8_t verbosity = 0;1791 uint8_t verbosity = 0;
1792 uint8_t fb_verbosity = 0;
1793 uint8_t fb_noreboot = 0;
1794 uint8_t sbat_policy = 0;
2141 DBName db_name = MOK_LIST_RT;1795 DBName db_name = MOK_LIST_RT;
2142 int ret = -1;1796 int ret = -1;
1797 int sb_check;
21431798
2144 use_simple_hash = 0;1799 force_ca_check = 0;
1800 check_keyring = 1;
21451801
2146 if (!efi_variables_supported ()) {1802 if (!efi_variables_supported ()) {
2147 fprintf (stderr, "EFI variables are not supported on this system\n");1803 fprintf (stderr, "EFI variables are not supported on this system\n");
@@ -2169,7 +1825,6 @@ main (int argc, char *argv[])
2169 {"hash-file", required_argument, 0, 'f'},1825 {"hash-file", required_argument, 0, 'f'},
2170 {"generate-hash", optional_argument, 0, 'g'},1826 {"generate-hash", optional_argument, 0, 'g'},
2171 {"root-pw", no_argument, 0, 'P'},1827 {"root-pw", no_argument, 0, 'P'},
2172 {"simple-hash", no_argument, 0, 's'},
2173 {"ignore-db", no_argument, 0, 0 },1828 {"ignore-db", no_argument, 0, 0 },
2174 {"use-db", no_argument, 0, 0 },1829 {"use-db", no_argument, 0, 0 },
2175 {"mok", no_argument, 0, 'm'},1830 {"mok", no_argument, 0, 'm'},
@@ -2177,16 +1832,26 @@ main (int argc, char *argv[])
2177 {"import-hash", required_argument, 0, 0 },1832 {"import-hash", required_argument, 0, 0 },
2178 {"delete-hash", required_argument, 0, 0 },1833 {"delete-hash", required_argument, 0, 0 },
2179 {"set-verbosity", required_argument, 0, 0 },1834 {"set-verbosity", required_argument, 0, 0 },
1835 {"set-fallback-verbosity", required_argument, 0, 0 },
1836 {"set-fallback-noreboot", required_argument, 0, 0 },
1837 {"trust-mok", no_argument, 0, 0 },
1838 {"untrust-mok", no_argument, 0, 0 },
1839 {"set-sbat-policy", required_argument, 0, 0 },
2180 {"pk", no_argument, 0, 0 },1840 {"pk", no_argument, 0, 0 },
2181 {"kek", no_argument, 0, 0 },1841 {"kek", no_argument, 0, 0 },
2182 {"db", no_argument, 0, 0 },1842 {"db", no_argument, 0, 0 },
2183 {"dbx", no_argument, 0, 0 },1843 {"dbx", no_argument, 0, 0 },
1844 {"list-sbat-revocations", no_argument, 0, 0 },
1845 {"sbat", no_argument, 0, 0 },
2184 {"timeout", required_argument, 0, 0 },1846 {"timeout", required_argument, 0, 0 },
1847 {"ca-check", no_argument, 0, 0 },
1848 {"ignore-keyring", no_argument, 0, 0 },
1849 {"version", no_argument, 0, 'v'},
2185 {0, 0, 0, 0}1850 {0, 0, 0, 0}
2186 };1851 };
21871852
2188 int option_index = 0;1853 int option_index = 0;
2189 c = getopt_long (argc, argv, "cd:f:g::hi:lmpst:xDNPX",1854 c = getopt_long (argc, argv, "cd:f:g::hi:lmpst:xDNPXv",
2190 long_options, &option_index);1855 long_options, &option_index);
21911856
2192 if (c == -1)1857 if (c == -1)
@@ -2211,6 +1876,10 @@ main (int argc, char *argv[])
2211 command |= IGNORE_DB;1876 command |= IGNORE_DB;
2212 } else if (strcmp (option, "use-db") == 0) {1877 } else if (strcmp (option, "use-db") == 0) {
2213 command |= USE_DB;1878 command |= USE_DB;
1879 } else if (strcmp (option, "trust-mok") == 0) {
1880 command |= TRUST_MOK;
1881 } else if (strcmp (option, "untrust-mok") == 0) {
1882 command |= UNTRUST_MOK;
2214 } else if (strcmp (option, "import-hash") == 0) {1883 } else if (strcmp (option, "import-hash") == 0) {
2215 command |= IMPORT_HASH;1884 command |= IMPORT_HASH;
2216 if (hash_str) {1885 if (hash_str) {
@@ -2241,6 +1910,32 @@ main (int argc, char *argv[])
2241 verbosity = 0;1910 verbosity = 0;
2242 else1911 else
2243 command |= HELP;1912 command |= HELP;
1913 } else if (strcmp (option, "set-fallback-verbosity") == 0) {
1914 command |= FB_VERBOSITY;
1915 if (strcmp (optarg, "true") == 0)
1916 fb_verbosity = 1;
1917 else if (strcmp (optarg, "false") == 0)
1918 fb_verbosity = 0;
1919 else
1920 command |= HELP;
1921 } else if (strcmp (option, "set-fallback-noreboot") == 0) {
1922 command |= FB_NOREBOOT;
1923 if (strcmp (optarg, "true") == 0)
1924 fb_noreboot = 1;
1925 else if (strcmp (optarg, "false") == 0)
1926 fb_noreboot = 0;
1927 else
1928 command |= HELP;
1929 } else if (strcmp (option, "set-sbat-policy") == 0) {
1930 command |= SET_SBAT;
1931 if (strcmp (optarg, "latest") == 0)
1932 sbat_policy = 1;
1933 else if (strcmp (optarg, "previous") == 0)
1934 sbat_policy = 2;
1935 else if (strcmp (optarg, "delete") == 0)
1936 sbat_policy = 3;
1937 else
1938 command |= HELP;
2244 } else if (strcmp (option, "pk") == 0) {1939 } else if (strcmp (option, "pk") == 0) {
2245 if (db_name != MOK_LIST_RT) {1940 if (db_name != MOK_LIST_RT) {
2246 command |= HELP;1941 command |= HELP;
@@ -2265,9 +1960,17 @@ main (int argc, char *argv[])
2265 } else {1960 } else {
2266 db_name = DBX;1961 db_name = DBX;
2267 }1962 }
1963 } else if (strcmp (option, "list-sbat-revocations") == 0) {
1964 command |= LIST_SBAT;
1965 } else if (strcmp (option, "sbat") == 0) {
1966 command |= LIST_SBAT;
2268 } else if (strcmp (option, "timeout") == 0) {1967 } else if (strcmp (option, "timeout") == 0) {
2269 command |= TIMEOUT;1968 command |= TIMEOUT;
2270 timeout = strdup (optarg);1969 timeout = strdup (optarg);
1970 } else if (strcmp (option, "ca-check") == 0) {
1971 force_ca_check = 1;
1972 } else if (strcmp (option, "ignore-keyring") == 0) {
1973 check_keyring = 0;
2271 }1974 }
22721975
2273 break;1976 break;
@@ -2317,12 +2020,12 @@ main (int argc, char *argv[])
23172020
2318 break;2021 break;
2319 case 'f':2022 case 'f':
2320 if (hash_file) {2023 if (pw_hash_file) {
2321 command |= HELP;2024 command |= HELP;
2322 break;2025 break;
2323 }2026 }
2324 hash_file = strdup (optarg);2027 pw_hash_file = strdup (optarg);
2325 if (hash_file == NULL) {2028 if (pw_hash_file == NULL) {
2326 fprintf (stderr, "Could not allocate space: %m\n");2029 fprintf (stderr, "Could not allocate space: %m\n");
2327 exit(1);2030 exit(1);
2328 }2031 }
@@ -2368,10 +2071,6 @@ main (int argc, char *argv[])
2368 case 'x':2071 case 'x':
2369 command |= EXPORT;2072 command |= EXPORT;
2370 break;2073 break;
2371 case 's':
2372 command |= SIMPLE_HASH;
2373 use_simple_hash = 1;
2374 break;
2375 case 'm':2074 case 'm':
2376 db_name = MOK_LIST_RT;2075 db_name = MOK_LIST_RT;
2377 break;2076 break;
@@ -2383,6 +2082,9 @@ main (int argc, char *argv[])
2383 db_name = MOK_LIST_X_RT;2082 db_name = MOK_LIST_X_RT;
2384 }2083 }
2385 break;2084 break;
2085 case 'v':
2086 printf ("%s\n", VERSION);
2087 goto out;
2386 case 'h':2088 case 'h':
2387 case '?':2089 case '?':
2388 command |= HELP;2090 command |= HELP;
@@ -2392,19 +2094,19 @@ main (int argc, char *argv[])
2392 }2094 }
2393 }2095 }
23942096
2395 if (use_root_pw == 1 && use_simple_hash == 1)2097 if (pw_hash_file && use_root_pw)
2396 use_simple_hash = 0;
2397
2398 if (hash_file && use_root_pw)
2399 command |= HELP;2098 command |= HELP;
24002099
2401 if (db_name != MOK_LIST_RT && !(command & ~MOKX))2100 if (db_name != MOK_LIST_RT && !(command & ~MOKX))
2402 command |= LIST_ENROLLED;2101 command |= LIST_ENROLLED;
24032102
2404 if (!(command & HELP)) {2103 sb_check = !(command & HELP || command & TEST_KEY ||
2104 command & VERBOSITY || command & TIMEOUT ||
2105 command & FB_VERBOSITY || command & FB_NOREBOOT);
2106 if (sb_check) {
2405 /* Check whether the machine supports Secure Boot or not */2107 /* Check whether the machine supports Secure Boot or not */
2406 int rc;2108 int rc;
2407 uint8_t *data;2109 uint8_t *data = NULL;
2408 size_t data_size;2110 size_t data_size;
2409 uint32_t attributes;2111 uint32_t attributes;
24102112
@@ -2430,24 +2132,20 @@ main (int argc, char *argv[])
2430 ret = list_keys_in_var ("MokDel", efi_guid_shim);2132 ret = list_keys_in_var ("MokDel", efi_guid_shim);
2431 break;2133 break;
2432 case IMPORT:2134 case IMPORT:
2433 case IMPORT | SIMPLE_HASH:
2434 ret = issue_mok_request (files, total, ENROLL_MOK,2135 ret = issue_mok_request (files, total, ENROLL_MOK,
2435 hash_file, use_root_pw);2136 pw_hash_file, use_root_pw);
2436 break;2137 break;
2437 case DELETE:2138 case DELETE:
2438 case DELETE | SIMPLE_HASH:
2439 ret = issue_mok_request (files, total, DELETE_MOK,2139 ret = issue_mok_request (files, total, DELETE_MOK,
2440 hash_file, use_root_pw);2140 pw_hash_file, use_root_pw);
2441 break;2141 break;
2442 case IMPORT_HASH:2142 case IMPORT_HASH:
2443 case IMPORT_HASH | SIMPLE_HASH:
2444 ret = issue_hash_request (hash_str, ENROLL_MOK,2143 ret = issue_hash_request (hash_str, ENROLL_MOK,
2445 hash_file, use_root_pw);2144 pw_hash_file, use_root_pw);
2446 break;2145 break;
2447 case DELETE_HASH:2146 case DELETE_HASH:
2448 case DELETE_HASH | SIMPLE_HASH:
2449 ret = issue_hash_request (hash_str, DELETE_MOK,2147 ret = issue_hash_request (hash_str, DELETE_MOK,
2450 hash_file, use_root_pw);2148 pw_hash_file, use_root_pw);
2451 break;2149 break;
2452 case REVOKE_IMPORT:2150 case REVOKE_IMPORT:
2453 ret = revoke_request (ENROLL_MOK);2151 ret = revoke_request (ENROLL_MOK);
@@ -2460,11 +2158,9 @@ main (int argc, char *argv[])
2460 ret = export_db_keys (db_name);2158 ret = export_db_keys (db_name);
2461 break;2159 break;
2462 case PASSWORD:2160 case PASSWORD:
2463 case PASSWORD | SIMPLE_HASH:2161 ret = set_password (pw_hash_file, use_root_pw, 0);
2464 ret = set_password (hash_file, use_root_pw, 0);
2465 break;2162 break;
2466 case CLEAR_PASSWORD:2163 case CLEAR_PASSWORD:
2467 case CLEAR_PASSWORD | SIMPLE_HASH:
2468 ret = set_password (NULL, 0, 1);2164 ret = set_password (NULL, 0, 1);
2469 break;2165 break;
2470 case DISABLE_VALIDATION:2166 case DISABLE_VALIDATION:
@@ -2480,8 +2176,7 @@ main (int argc, char *argv[])
2480 ret = test_key (ENROLL_MOK, key_file);2176 ret = test_key (ENROLL_MOK, key_file);
2481 break;2177 break;
2482 case RESET:2178 case RESET:
2483 case RESET | SIMPLE_HASH:2179 ret = reset_moks (ENROLL_MOK, pw_hash_file, use_root_pw);
2484 ret = reset_moks (ENROLL_MOK, hash_file, use_root_pw);
2485 break;2180 break;
2486 case GENERATE_PW_HASH:2181 case GENERATE_PW_HASH:
2487 ret = generate_pw_hash (input_pw);2182 ret = generate_pw_hash (input_pw);
@@ -2492,6 +2187,12 @@ main (int argc, char *argv[])
2492 case USE_DB:2187 case USE_DB:
2493 ret = enable_db ();2188 ret = enable_db ();
2494 break;2189 break;
2190 case TRUST_MOK:
2191 ret = trust_mok_keys ();
2192 break;
2193 case UNTRUST_MOK:
2194 ret = untrust_mok_keys ();
2195 break;
2495 case LIST_NEW | MOKX:2196 case LIST_NEW | MOKX:
2496 ret = list_keys_in_var ("MokXNew", efi_guid_shim);2197 ret = list_keys_in_var ("MokXNew", efi_guid_shim);
2497 break;2198 break;
@@ -2499,24 +2200,20 @@ main (int argc, char *argv[])
2499 ret = list_keys_in_var ("MokXDel", efi_guid_shim);2200 ret = list_keys_in_var ("MokXDel", efi_guid_shim);
2500 break;2201 break;
2501 case IMPORT | MOKX:2202 case IMPORT | MOKX:
2502 case IMPORT | SIMPLE_HASH | MOKX:
2503 ret = issue_mok_request (files, total, ENROLL_BLACKLIST,2203 ret = issue_mok_request (files, total, ENROLL_BLACKLIST,
2504 hash_file, use_root_pw);2204 pw_hash_file, use_root_pw);
2505 break;2205 break;
2506 case DELETE | MOKX:2206 case DELETE | MOKX:
2507 case DELETE | SIMPLE_HASH | MOKX:
2508 ret = issue_mok_request (files, total, DELETE_BLACKLIST,2207 ret = issue_mok_request (files, total, DELETE_BLACKLIST,
2509 hash_file, use_root_pw);2208 pw_hash_file, use_root_pw);
2510 break;2209 break;
2511 case IMPORT_HASH | MOKX:2210 case IMPORT_HASH | MOKX:
2512 case IMPORT_HASH | SIMPLE_HASH | MOKX:
2513 ret = issue_hash_request (hash_str, ENROLL_BLACKLIST,2211 ret = issue_hash_request (hash_str, ENROLL_BLACKLIST,
2514 hash_file, use_root_pw);2212 pw_hash_file, use_root_pw);
2515 break;2213 break;
2516 case DELETE_HASH | MOKX:2214 case DELETE_HASH | MOKX:
2517 case DELETE_HASH | SIMPLE_HASH | MOKX:
2518 ret = issue_hash_request (hash_str, DELETE_BLACKLIST,2215 ret = issue_hash_request (hash_str, DELETE_BLACKLIST,
2519 hash_file, use_root_pw);2216 pw_hash_file, use_root_pw);
2520 break;2217 break;
2521 case REVOKE_IMPORT | MOKX:2218 case REVOKE_IMPORT | MOKX:
2522 ret = revoke_request (ENROLL_BLACKLIST);2219 ret = revoke_request (ENROLL_BLACKLIST);
@@ -2525,8 +2222,7 @@ main (int argc, char *argv[])
2525 ret = revoke_request (DELETE_BLACKLIST);2222 ret = revoke_request (DELETE_BLACKLIST);
2526 break;2223 break;
2527 case RESET | MOKX:2224 case RESET | MOKX:
2528 case RESET | SIMPLE_HASH | MOKX:2225 ret = reset_moks (ENROLL_BLACKLIST, pw_hash_file, use_root_pw);
2529 ret = reset_moks (ENROLL_BLACKLIST, hash_file, use_root_pw);
2530 break;2226 break;
2531 case TEST_KEY | MOKX:2227 case TEST_KEY | MOKX:
2532 ret = test_key (ENROLL_BLACKLIST, key_file);2228 ret = test_key (ENROLL_BLACKLIST, key_file);
@@ -2534,9 +2230,21 @@ main (int argc, char *argv[])
2534 case VERBOSITY:2230 case VERBOSITY:
2535 ret = set_verbosity (verbosity);2231 ret = set_verbosity (verbosity);
2536 break;2232 break;
2233 case FB_VERBOSITY:
2234 ret = set_fallback_verbosity (fb_verbosity);
2235 break;
2236 case FB_NOREBOOT:
2237 ret = set_fallback_noreboot (fb_noreboot);
2238 break;
2537 case TIMEOUT:2239 case TIMEOUT:
2538 ret = set_timeout (timeout);2240 ret = set_timeout (timeout);
2539 break;2241 break;
2242 case LIST_SBAT:
2243 ret = print_var_content ("SbatLevelRT", efi_guid_shim);
2244 break;
2245 case SET_SBAT:
2246 ret = manage_sbat(sbat_policy);
2247 break;
2540 default:2248 default:
2541 print_help ();2249 print_help ();
2542 break;2250 break;
@@ -2555,8 +2263,8 @@ out:
2555 if (key_file)2263 if (key_file)
2556 free (key_file);2264 free (key_file);
25572265
2558 if (hash_file)2266 if (pw_hash_file)
2559 free (hash_file);2267 free (pw_hash_file);
25602268
2561 if (input_pw)2269 if (input_pw)
2562 free (input_pw);2270 free (input_pw);
diff --git a/src/mokutil.h b/src/mokutil.h
2563new file mode 1006442271new file mode 100644
index 0000000..75922fa
--- /dev/null
+++ b/src/mokutil.h
@@ -0,0 +1,66 @@
1/**
2 * Copyright (C) 2020 Gary Lin <glin@suse.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * In addition, as a special exception, the copyright holders give
18 * permission to link the code of portions of this program with the
19 * OpenSSL library under certain conditions as described in each
20 * individual source file, and distribute linked combinations
21 * including the two.
22 *
23 * You must obey the GNU General Public License in all respects
24 * for all of the code used other than OpenSSL. If you modify
25 * file(s) with this exception, you may extend this exception to your
26 * version of the file(s), but you are not obligated to do so. If you
27 * do not wish to do so, delete this exception statement from your
28 * version. If you delete this exception statement from all source
29 * files in the program, then also delete it here.
30 */
31
32#ifndef __MOKUTIL_H__
33#define __MOKUTIL_H__
34
35#include <ctype.h>
36#include <wchar.h>
37
38#include "signature.h"
39
40typedef unsigned long efi_status_t;
41typedef uint8_t efi_bool_t;
42typedef wchar_t efi_char16_t; /* UNICODE character */
43
44typedef enum {
45 DELETE_MOK = 0,
46 ENROLL_MOK,
47 DELETE_BLACKLIST,
48 ENROLL_BLACKLIST,
49} MokRequest;
50
51typedef enum {
52 MOK_LIST_RT = 0,
53 MOK_LIST_X_RT,
54 PK,
55 KEK,
56 DB,
57 DBX,
58} DBName;
59
60typedef struct {
61 EFI_SIGNATURE_LIST *header;
62 uint32_t mok_size;
63 void *mok;
64} MokListNode;
65
66#endif /* __MOKUTIL_H__ */
diff --git a/src/password-crypt.c b/src/password-crypt.c
index 0b31d64..db69b88 100644
--- a/src/password-crypt.c
+++ b/src/password-crypt.c
@@ -79,7 +79,7 @@ gen_salt_size (uint16_t min, uint16_t max)
79}79}
8080
81uint16_t81uint16_t
82get_salt_size (int method) {82get_pw_salt_size (const HashMethod method) {
83 switch (method) {83 switch (method) {
84 case TRADITIONAL_DES:84 case TRADITIONAL_DES:
85 return T_DES_SALT_MAX;85 return T_DES_SALT_MAX;
@@ -98,7 +98,7 @@ get_salt_size (int method) {
98}98}
9999
100int100int
101get_hash_size (int method)101get_pw_hash_size (const HashMethod method)
102{102{
103 switch (method) {103 switch (method) {
104 case TRADITIONAL_DES:104 case TRADITIONAL_DES:
@@ -119,7 +119,7 @@ get_hash_size (int method)
119}119}
120120
121const char *121const char *
122get_crypt_prefix (int method)122get_crypt_prefix (const HashMethod method)
123{123{
124 switch (method) {124 switch (method) {
125 case TRADITIONAL_DES:125 case TRADITIONAL_DES:
@@ -405,7 +405,8 @@ split_24bit (const char *string, uint8_t *hash, int start, int n,
405 return 0;405 return 0;
406}406}
407407
408int restore_md5_array (const char *string, uint8_t *hash)408static int
409restore_md5_array (const char *string, uint8_t *hash)
409{410{
410 uint32_t tmp = 0;411 uint32_t tmp = 0;
411 int value1, value2;412 int value1, value2;
@@ -440,7 +441,7 @@ int restore_md5_array (const char *string, uint8_t *hash)
440 return 0;441 return 0;
441}442}
442443
443int444static int
444restore_sha256_array (const char *string, uint8_t *hash)445restore_sha256_array (const char *string, uint8_t *hash)
445{446{
446 uint32_t tmp = 0;447 uint32_t tmp = 0;
@@ -483,7 +484,7 @@ restore_sha256_array (const char *string, uint8_t *hash)
483 return 0;484 return 0;
484}485}
485486
486int487static int
487restore_sha512_array (const char *string, uint8_t *hash)488restore_sha512_array (const char *string, uint8_t *hash)
488{489{
489 uint32_t tmp = 0;490 uint32_t tmp = 0;
diff --git a/src/password-crypt.h b/src/password-crypt.h
index 5487363..214a65b 100644
--- a/src/password-crypt.h
+++ b/src/password-crypt.h
@@ -41,14 +41,14 @@
41#define SHA512_SALT_MAX 1641#define SHA512_SALT_MAX 16
42#define BLOWFISH_SALT_MAX 2242#define BLOWFISH_SALT_MAX 22
4343
44enum HashMethod {44typedef enum {
45 TRADITIONAL_DES = 0,45 TRADITIONAL_DES = 0,
46 EXTEND_BSDI_DES,46 EXTEND_BSDI_DES,
47 MD5_BASED,47 MD5_BASED,
48 SHA256_BASED,48 SHA256_BASED,
49 SHA512_BASED,49 SHA512_BASED,
50 BLOWFISH_BASED50 BLOWFISH_BASED
51};51} HashMethod;
5252
53typedef struct {53typedef struct {
54 uint16_t method;54 uint16_t method;
@@ -64,9 +64,9 @@ typedef struct {
64#define SHA256_B64_LENGTH 4364#define SHA256_B64_LENGTH 43
65#define SHA512_B64_LENGTH 8665#define SHA512_B64_LENGTH 86
6666
67uint16_t get_salt_size (int method);67uint16_t get_pw_salt_size (const HashMethod method);
68int get_hash_size (int method);68int get_pw_hash_size (const HashMethod method);
69const char *get_crypt_prefix (int method);69const char *get_crypt_prefix (const HashMethod method);
70int decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt);70int decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt);
71char int_to_b64 (const int i);71char int_to_b64 (const int i);
72int b64_to_int (const char c);72int b64_to_int (const char c);
diff --git a/src/util.c b/src/util.c
73new file mode 10064473new file mode 100644
index 0000000..621869f
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,456 @@
1/**
2 * Copyright (C) 2020 Gary Lin <glin@suse.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * In addition, as a special exception, the copyright holders give
18 * permission to link the code of portions of this program with the
19 * OpenSSL library under certain conditions as described in each
20 * individual source file, and distribute linked combinations
21 * including the two.
22 *
23 * You must obey the GNU General Public License in all respects
24 * for all of the code used other than OpenSSL. If you modify
25 * file(s) with this exception, you may extend this exception to your
26 * version of the file(s), but you are not obligated to do so. If you
27 * do not wish to do so, delete this exception statement from your
28 * version. If you delete this exception statement from all source
29 * files in the program, then also delete it here.
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <termios.h>
35
36#include "efi_hash.h"
37#include "util.h"
38
39int
40mok_get_variable(const char *name, uint8_t **datap, size_t *data_sizep)
41{
42 char filename[] = "/sys/firmware/efi/mok-variables/implausibly-long-mok-variable-name";
43 size_t filename_sz = sizeof(filename);
44 int fd, rc;
45 struct stat sb = { 0, };
46 uint8_t *buf;
47 size_t bufsz, pos = 0;
48 ssize_t ssz;
49
50 *datap = 0;
51 *data_sizep = 0;
52
53 snprintf(filename, filename_sz, "/sys/firmware/efi/mok-variables/%s", name);
54
55 fd = open(filename, O_RDONLY);
56 if (fd < 0)
57 return fd;
58
59 rc = fstat(fd, &sb);
60 if (rc < 0) {
61err_close:
62 close(fd);
63 return rc;
64 }
65
66 if (sb.st_size == 0) {
67 errno = ENOENT;
68 rc = -1;
69 goto err_close;
70 }
71
72 bufsz = sb.st_size;
73 buf = calloc(1, bufsz);
74 if (!buf)
75 goto err_close;
76
77 while (pos < bufsz) {
78 ssz = read(fd, &buf[pos], bufsz - pos);
79 if (ssz < 0) {
80 if (errno == EAGAIN ||
81 errno == EWOULDBLOCK ||
82 errno == EINTR)
83 continue;
84 free(buf);
85 goto err_close;
86 }
87
88 pos += ssz;
89 }
90 *datap = buf;
91 *data_sizep = pos;
92
93 return 0;
94}
95
96MokListNode*
97build_mok_list (const void *data, const uintptr_t data_size,
98 uint32_t *mok_num)
99{
100 MokListNode *list = NULL;
101 MokListNode *list_new = NULL;
102 EFI_SIGNATURE_LIST *CertList = (void *)data;
103 EFI_SIGNATURE_DATA *Cert;
104 unsigned long dbsize = data_size;
105 unsigned long count = 0;
106 const void *end = data + data_size;
107
108 while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
109 if ((void *)(CertList + 1) > end ||
110 CertList->SignatureListSize == 0 ||
111 CertList->SignatureListSize <= CertList->SignatureSize) {
112 fprintf (stderr, "Corrupted signature list\n");
113 if (list)
114 free (list);
115 return NULL;
116 }
117
118 efi_guid_t sigtype = CertList->SignatureType;
119
120 if ((efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0) &&
121 (efi_guid_cmp (&sigtype, &efi_guid_sha1) != 0) &&
122 (efi_guid_cmp (&sigtype, &efi_guid_sha224) != 0) &&
123 (efi_guid_cmp (&sigtype, &efi_guid_sha256) != 0) &&
124 (efi_guid_cmp (&sigtype, &efi_guid_sha384) != 0) &&
125 (efi_guid_cmp (&sigtype, &efi_guid_sha512) != 0)) {
126 dbsize -= CertList->SignatureListSize;
127 CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList +
128 CertList->SignatureListSize);
129 continue;
130 }
131
132 if ((efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0) &&
133 (CertList->SignatureSize != signature_size (&sigtype))) {
134 dbsize -= CertList->SignatureListSize;
135 CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList +
136 CertList->SignatureListSize);
137 continue;
138 }
139
140 Cert = (EFI_SIGNATURE_DATA *) (((uint8_t *) CertList) +
141 sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
142
143 if ((void *)(Cert + 1) > end ||
144 CertList->SignatureSize <= sizeof(efi_guid_t)) {
145 if (list)
146 free (list);
147 fprintf (stderr, "Corrupted signature\n");
148 return NULL;
149 }
150
151 list_new = realloc(list, sizeof(MokListNode) * (count + 1));
152 if (list_new) {
153 list = list_new;
154 } else {
155 if (list)
156 free (list);
157 fprintf(stderr, "Unable to allocate MOK list\n");
158 return NULL;
159 }
160
161 list[count].header = CertList;
162 if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) == 0) {
163 /* X509 certificate */
164 list[count].mok_size = CertList->SignatureSize -
165 sizeof(efi_guid_t);
166 list[count].mok = (void *)Cert->SignatureData;
167 } else {
168 /* hash array */
169 list[count].mok_size = CertList->SignatureListSize -
170 sizeof(EFI_SIGNATURE_LIST) -
171 CertList->SignatureHeaderSize;
172 list[count].mok = (void *)Cert;
173 }
174
175 if (list[count].mok_size > (unsigned long)end -
176 (unsigned long)list[count].mok) {
177 fprintf (stderr, "Corrupted data\n");
178 free (list);
179 return NULL;
180 }
181
182 count++;
183 dbsize -= CertList->SignatureListSize;
184 CertList = (EFI_SIGNATURE_LIST *) ((uint8_t *) CertList +
185 CertList->SignatureListSize);
186 }
187
188 *mok_num = count;
189
190 return list;
191}
192
193int
194test_and_delete_mok_var (const char *var_name)
195{
196 size_t size;
197 int ret;
198
199 ret = efi_get_variable_size (efi_guid_shim, var_name, &size);
200 if (ret < 0) {
201 if (errno == ENOENT)
202 return 0;
203 fprintf (stderr, "Failed to access variable \"%s\": %m\n",
204 var_name);
205 }
206
207 /* Attempt to delete it no matter what, problem efi_get_variable_size()
208 * had, unless it just doesn't exist anyway. */
209 if (!(ret < 0 && errno == ENOENT)) {
210 if (efi_del_variable (efi_guid_shim, var_name) < 0)
211 fprintf (stderr, "Failed to unset \"%s\": %m\n", var_name);
212 }
213
214 return ret;
215}
216
217int
218delete_data_from_req_var (const MokRequest req, const efi_guid_t *type,
219 const void *data, const uint32_t data_size)
220{
221 const efi_guid_t *var_guid = &efi_guid_shim;
222 const char *var_name = get_req_var_name (req);
223 const char *authvar_name = get_req_auth_var_name (req);
224 uint8_t *var_data = NULL;
225 size_t var_data_size = 0;
226 uint32_t attributes;
227 MokListNode *list;
228 uint32_t mok_num, total, remain;
229 void *end, *start = NULL;
230 int del_ind, ret = 0;
231 uint32_t sig_list_size, sig_size;
232
233 if (!var_name || !data || data_size == 0)
234 return 0;
235
236 ret = efi_get_variable (*var_guid, var_name, &var_data, &var_data_size,
237 &attributes);
238 if (ret < 0) {
239 if (errno == ENOENT)
240 return 0;
241 fprintf (stderr, "Failed to read variable \"%s\": %m\n",
242 var_name);
243 return -1;
244 }
245
246 total = var_data_size;
247
248 list = build_mok_list (var_data, var_data_size, &mok_num);
249 if (list == NULL)
250 goto done;
251
252 remain = total;
253 for (unsigned int i = 0; i < mok_num; i++) {
254 remain -= list[i].header->SignatureListSize;
255 efi_guid_t sigtype = list[i].header->SignatureType;
256 if (efi_guid_cmp (&sigtype, type) != 0)
257 continue;
258
259 sig_list_size = list[i].header->SignatureListSize;
260
261 if (efi_guid_cmp (type, &efi_guid_x509_cert) == 0) {
262 if (list[i].mok_size != data_size)
263 continue;
264
265 if (memcmp (list[i].mok, data, data_size) == 0) {
266 /* Remove this key */
267 start = (void *)list[i].header;
268 end = start + sig_list_size;
269 total -= sig_list_size;
270 break;
271 }
272 } else {
273 del_ind = match_hash_array (type, data, list[i].mok,
274 list[i].mok_size);
275 if (del_ind < 0)
276 continue;
277
278 start = (void *)list[i].header;
279 sig_size = signature_size (type);
280 if (sig_list_size == (sizeof(EFI_SIGNATURE_LIST) + sig_size)) {
281 /* Only one hash in the list */
282 end = start + sig_list_size;
283 total -= sig_list_size;
284 } else {
285 /* More than one hash in the list */
286 start += sizeof(EFI_SIGNATURE_LIST) + sig_size * del_ind;
287 end = start + sig_size;
288 total -= sig_size;
289 list[i].header->SignatureListSize -= sig_size;
290 remain += sig_list_size - sizeof(EFI_SIGNATURE_LIST) -
291 (del_ind + 1) * sig_size;
292 }
293 break;
294 }
295 }
296
297 /* the key or hash is not in this list */
298 if (start == NULL)
299 return 0;
300
301 /* all keys are removed */
302 if (total == 0) {
303 if (test_and_delete_mok_var (var_name) != 0)
304 goto done;
305 if (test_and_delete_mok_var (authvar_name) != 0)
306 goto done;
307 ret = 1;
308 goto done;
309 }
310
311 /* remove the key or hash */
312 if (remain > 0)
313 memmove (start, end, remain);
314
315 attributes = EFI_VARIABLE_NON_VOLATILE
316 | EFI_VARIABLE_BOOTSERVICE_ACCESS
317 | EFI_VARIABLE_RUNTIME_ACCESS;
318 ret = efi_set_variable (*var_guid, var_name,
319 var_data, total, attributes,
320 S_IRUSR | S_IWUSR);
321 if (ret < 0) {
322 fprintf (stderr, "Failed to write variable \"%s\": %m\n",
323 var_name);
324 goto done;
325 }
326 efi_chmod_variable(*var_guid, var_name, S_IRUSR | S_IWUSR);
327
328 ret = 1;
329done:
330 if (list)
331 free (list);
332 free (var_data);
333
334 return ret;
335}
336
337unsigned long
338efichar_from_char (efi_char16_t *dest, const char *src, size_t dest_len)
339{
340 unsigned int i, src_len = strlen(src);
341 for (i=0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) {
342 dest[i] = src[i];
343 }
344 dest[i] = 0;
345 return i * sizeof(*dest);
346}
347
348int
349read_hidden_line (char **line, size_t *n)
350{
351 struct termios old, new;
352 int nread;
353 int isTTY = isatty(fileno (stdin));
354
355 if (isTTY) {
356 /* Turn echoing off and fail if we can't. */
357 if (tcgetattr (fileno (stdin), &old) != 0)
358 return -1;
359
360 new = old;
361 new.c_lflag &= ~ECHO;
362
363 if (tcsetattr (fileno (stdin), TCSAFLUSH, &new) != 0)
364 return -1;
365 }
366
367 /* Read the password. */
368 nread = getline (line, n, stdin);
369
370 if (isTTY) {
371 /* Restore terminal. */
372 (void) tcsetattr (fileno (stdin), TCSAFLUSH, &old);
373 }
374
375 /* Remove the newline */
376 (*line)[nread-1] = '\0';
377
378 return nread-1;
379}
380
381const char *
382get_db_var_name (const DBName db_name)
383{
384 const char *db_var_names[] = {
385 [MOK_LIST_RT] = "MokListRT",
386 [MOK_LIST_X_RT] = "MokListXRT",
387 [PK] = "PK",
388 [KEK] = "KEK",
389 [DB] = "db",
390 [DBX] = "dbx",
391 };
392
393 return db_var_names[db_name];
394}
395
396const char *
397get_db_friendly_name (const DBName db_name)
398{
399 const char *db_friendly_names[] = {
400 [MOK_LIST_RT] = "MOK",
401 [MOK_LIST_X_RT] = "MOKX",
402 [PK] = "PK",
403 [KEK] = "KEK",
404 [DB] = "DB",
405 [DBX] = "DBX",
406 };
407
408 return db_friendly_names[db_name];
409}
410
411const char *
412get_req_var_name (const MokRequest req)
413{
414 const char *var_names[] = {
415 [DELETE_MOK] = "MokDel",
416 [ENROLL_MOK] = "MokNew",
417 [DELETE_BLACKLIST] = "MokXDel",
418 [ENROLL_BLACKLIST] = "MokXNew"
419 };
420
421 return var_names[req];
422}
423
424const char *
425get_req_auth_var_name (const MokRequest req)
426{
427 const char *auth_var_names[] = {
428 [DELETE_MOK] = "MokDelAuth",
429 [ENROLL_MOK] = "MokAuth",
430 [DELETE_BLACKLIST] = "MokXDelAuth",
431 [ENROLL_BLACKLIST] = "MokXAuth"
432 };
433
434 return auth_var_names[req];
435}
436
437MokRequest
438get_reverse_req (const MokRequest req)
439{
440 const MokRequest reverse_reqs[] = {
441 [DELETE_MOK] = ENROLL_MOK,
442 [ENROLL_MOK] = DELETE_MOK,
443 [DELETE_BLACKLIST] = ENROLL_BLACKLIST,
444 [ENROLL_BLACKLIST] = DELETE_BLACKLIST,
445 };
446
447 return reverse_reqs[req];
448}
449
450const char *
451get_reverse_req_var_name (const MokRequest req)
452{
453 const MokRequest reverse_req = get_reverse_req (req);
454
455 return get_req_var_name (reverse_req);
456}
diff --git a/src/util.h b/src/util.h
0new file mode 100644457new file mode 100644
index 0000000..70deb31
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,58 @@
1/**
2 * Copyright (C) 2020 Gary Lin <glin@suse.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * In addition, as a special exception, the copyright holders give
18 * permission to link the code of portions of this program with the
19 * OpenSSL library under certain conditions as described in each
20 * individual source file, and distribute linked combinations
21 * including the two.
22 *
23 * You must obey the GNU General Public License in all respects
24 * for all of the code used other than OpenSSL. If you modify
25 * file(s) with this exception, you may extend this exception to your
26 * version of the file(s), but you are not obligated to do so. If you
27 * do not wish to do so, delete this exception statement from your
28 * version. If you delete this exception statement from all source
29 * files in the program, then also delete it here.
30 */
31
32#ifndef __UTIL_H__
33#define __UTIL_H__
34
35#include <efivar.h>
36#include "mokutil.h"
37
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <fcntl.h>
41
42int mok_get_variable(const char *name, uint8_t **datap, size_t *data_sizep);
43MokListNode *build_mok_list (const void *data, const uintptr_t data_size,
44 uint32_t *mok_num);
45int test_and_delete_mok_var (const char *var_name);
46int delete_data_from_req_var (const MokRequest req, const efi_guid_t *type,
47 const void *data, const uint32_t data_size);
48unsigned long efichar_from_char (efi_char16_t *dest, const char *src,
49 size_t dest_len);
50int read_hidden_line (char **line, size_t *n);
51const char *get_db_var_name (const DBName db);
52const char *get_db_friendly_name (const DBName db);
53const char *get_req_var_name (const MokRequest req);
54const char *get_req_auth_var_name (const MokRequest req);
55MokRequest get_reverse_req (const MokRequest req);
56const char *get_reverse_req_var_name (const MokRequest req);
57
58#endif /* __UTIL_H__ */

Subscribers

People subscribed via source and target branches