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