diff -Nru mokutil-0.3.0+1538710437.fb6250f/configure.ac mokutil-0.6.0/configure.ac --- mokutil-0.3.0+1538710437.fb6250f/configure.ac 2018-10-05 03:33:57.000000000 +0000 +++ mokutil-0.6.0/configure.ac 2022-05-07 07:02:34.000000000 +0000 @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.68]) -AC_INIT([mokutil], [0.3.0], [glin@suse.com]) +AC_INIT([mokutil], [0.6.0], [chingpang@gmail.com]) AM_INIT_AUTOMAKE([1.11 -Wno-portability tar-ustar dist-bzip2 no-dist-gzip]) AC_CONFIG_SRCDIR([src/mokutil.c]) AC_CONFIG_HEADERS([config.h]) @@ -85,6 +85,7 @@ PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9.8]) PKG_CHECK_MODULES(EFIVAR, [efivar >= 0.12]) +PKG_CHECK_MODULES(LIBKEYUTILS, [libkeyutils >= 1.5]) AC_ARG_WITH([bash-completion-dir], AS_HELP_STRING([--with-bash-completion-dir[=PATH]], diff -Nru mokutil-0.3.0+1538710437.fb6250f/data/mokutil mokutil-0.6.0/data/mokutil --- mokutil-0.3.0+1538710437.fb6250f/data/mokutil 2018-10-05 03:33:57.000000000 +0000 +++ mokutil-0.6.0/data/mokutil 2022-05-07 07:02:34.000000000 +0000 @@ -1,4 +1,4 @@ -#!/bin/bash +# mokutil(1) completion _mokutil() { @@ -24,6 +24,14 @@ COMPREPLY=( $( compgen -W "true false") ) return 0 ;; + --set-fallback-verbosity) + COMPREPLY=( $( compgen -W "true false") ) + return 0 + ;; + --set-fallback-noreboot) + COMPREPLY=( $( compgen -W "true false") ) + return 0 + ;; --generate-hash|-g) COMPREPLY=( $( compgen -o nospace -P= -W "") ) return 0 diff -Nru mokutil-0.3.0+1538710437.fb6250f/debian/changelog mokutil-0.6.0/debian/changelog --- mokutil-0.3.0+1538710437.fb6250f/debian/changelog 2018-10-11 18:55:12.000000000 +0000 +++ mokutil-0.6.0/debian/changelog 2023-06-07 18:14:30.000000000 +0000 @@ -1,3 +1,55 @@ +mokutil (0.6.0-2~18.04.1) bionic; urgency=medium + + * Backport 0.6.0-2 to bionic (LP: #2015664). + - debian/control,debian/compat: Drop debhelper version to 11 + to build on bionic. + - debian/patches/manually-define-LIBKEYUTILS-make-vars.patch: Workaround + missing libkeyutils.pc in bionic. + + -- Nick Rosbrook Wed, 07 Jun 2023 14:14:30 -0400 + +mokutil (0.6.0-2) unstable; urgency=medium + + * *Actually* switch to Arch: any to allow for more + architectures. :-( Closes: #987613. + + -- Steve McIntyre <93sam@debian.org> Wed, 15 Jun 2022 14:30:50 +0100 + +mokutil (0.6.0-1) unstable; urgency=medium + + * Move to new upstream version 0.6.0. + + Drop old patches, no longer needed. + * Switch to Arch: any to allow for more architectures. + Closes: #987613, #991933. + * Clean up old tweaks in debian/rules, no longer needed. + * Add build-dep on libkeyutils-dev, new dependency. + * Bump Standards-Version to 4.6.1, no changes needed. + + -- Steve McIntyre <93sam@debian.org> Sun, 12 Jun 2022 21:41:39 +0100 + +mokutil (0.4.0-1) unstable; urgency=medium + + * Take mokutil under the wing of efi-team. + Thanks to Simon for his work previously, added him as an uploader + * Import the upstream source + * Move to new upstream version 0.4.0. Closes: #925223 + + Includes manpage fixes. Closes: #930759 + * Fix compiler warnings about potential unaligned pointers + * Update packaging: + + Raise debhelper-compat to 13 + + Raise Standards-Version to 4.5.1 + + Remove now-redundant build-dep on dh-autoreconf + + -- Steve McIntyre <93sam@debian.org> Sun, 25 Apr 2021 21:47:18 +0100 + +mokutil (0.3.0+1538710437.fb6250f-1) unstable; urgency=medium + + * Upload to Debian (Closes: #925471). + * Adopt the package; thanks to Steve Langasek for your work! + * Update Vcs-* to reflect the move to Salsa. + + -- Simon Quigley Fri, 12 Apr 2019 17:45:52 -0500 + mokutil (0.3.0+1538710437.fb6250f-0ubuntu2~18.04.1) bionic; urgency=medium * Backport mokutil 0.3.0+1538710437.fb6250f-0ubuntu2 to 18.04. diff -Nru mokutil-0.3.0+1538710437.fb6250f/debian/compat mokutil-0.6.0/debian/compat --- mokutil-0.3.0+1538710437.fb6250f/debian/compat 2013-09-19 16:15:08.000000000 +0000 +++ mokutil-0.6.0/debian/compat 2023-06-07 18:14:30.000000000 +0000 @@ -1 +1 @@ -9 +11 diff -Nru mokutil-0.3.0+1538710437.fb6250f/debian/control mokutil-0.6.0/debian/control --- mokutil-0.3.0+1538710437.fb6250f/debian/control 2016-03-17 19:38:13.000000000 +0000 +++ mokutil-0.6.0/debian/control 2023-06-07 18:14:30.000000000 +0000 @@ -2,13 +2,15 @@ Section: admin Priority: optional Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Steve Langasek -Standards-Version: 3.9.4 -Build-Depends: debhelper (>= 9), libssl-dev, pkg-config, libefivar-dev, dh-autoreconf -Vcs-Bzr: lp:ubuntu/mokutil +XSBC-Original-Maintainer: Debian UEFI Maintainers +Uploaders: Steve McIntyre <93sam@debian.org>, Simon Quigley +Standards-Version: 4.6.1 +Build-Depends: debhelper (>= 11), libssl-dev, pkg-config, libefivar-dev, libkeyutils-dev +Vcs-Browser: https://salsa.debian.org/efi-team/mokutil +Vcs-Git: https://salsa.debian.org/efi-team/mokutil.git Package: mokutil -Architecture: any-amd64 any-arm any-arm64 any-i386 any-ia64 +Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: tools for manipulating machine owner keys This program provides the means to enroll and erase the machine owner diff -Nru mokutil-0.3.0+1538710437.fb6250f/debian/patches/int-signedness.patch mokutil-0.6.0/debian/patches/int-signedness.patch --- mokutil-0.3.0+1538710437.fb6250f/debian/patches/int-signedness.patch 2018-10-11 05:38:28.000000000 +0000 +++ mokutil-0.6.0/debian/patches/int-signedness.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -Description: Fix compile failure on platforms where int != unsigned int - The compiler may rightly warn about a comparison between an unsigned int - and an int on architectures where int is signed by default. Since the - existing code has been tested on architectures where int *is* unsigned, - we just make our other int explicitly unsigned, ignoring certain existing - corner cases for now wrt possible integer underflows. -Author: Steve Langasek -Last-Updated: 2018-10-10 - -Index: mokutil-0.3.0+1538710437.fb6250f/src/mokutil.c -=================================================================== ---- mokutil-0.3.0+1538710437.fb6250f.orig/src/mokutil.c -+++ mokutil-0.3.0+1538710437.fb6250f/src/mokutil.c -@@ -2005,7 +2005,7 @@ - char *password = NULL; - char *crypt_string; - const char *prefix; -- int settings_len = sizeof (settings) - 2; -+ unsigned int settings_len = sizeof (settings) - 2; - unsigned int pw_len, salt_size; - - if (input_pw) { diff -Nru mokutil-0.3.0+1538710437.fb6250f/debian/patches/manually-define-LIBKEYUTILS-make-vars.patch mokutil-0.6.0/debian/patches/manually-define-LIBKEYUTILS-make-vars.patch --- mokutil-0.3.0+1538710437.fb6250f/debian/patches/manually-define-LIBKEYUTILS-make-vars.patch 1970-01-01 00:00:00.000000000 +0000 +++ mokutil-0.6.0/debian/patches/manually-define-LIBKEYUTILS-make-vars.patch 2023-06-07 18:14:30.000000000 +0000 @@ -0,0 +1,21 @@ +Description: Manually define LIBKEYUTILS_{CFLAGS,LIBS} if missing libkeyutils.pc +Author: Nick Rosbrook +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/jammy/+source/mokutil/+bug/2015664 +Forwarded: no +Last-Update: 2023-06-07 +--- a/configure.ac ++++ b/configure.ac +@@ -85,7 +85,12 @@ + + PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9.8]) + PKG_CHECK_MODULES(EFIVAR, [efivar >= 0.12]) +-PKG_CHECK_MODULES(LIBKEYUTILS, [libkeyutils >= 1.5]) ++PKG_CHECK_MODULES(LIBKEYUTILS, [libkeyutils >= 1.5], [], [pkgconfig_found_keyutils="no"]) ++ ++if test "x$pkgconfig_found_keyutils" = "xno"; then ++ AC_SUBST([LIBKEYUTILS_CFLAGS],["-I${includedir}"]) ++ AC_SUBST([LIBKEYUTILS_LIBS],["-L${libdir} -lkeyutils"]) ++fi + + AC_ARG_WITH([bash-completion-dir], + AS_HELP_STRING([--with-bash-completion-dir[=PATH]], diff -Nru mokutil-0.3.0+1538710437.fb6250f/debian/patches/series mokutil-0.6.0/debian/patches/series --- mokutil-0.3.0+1538710437.fb6250f/debian/patches/series 2018-10-11 05:30:06.000000000 +0000 +++ mokutil-0.6.0/debian/patches/series 2023-06-07 18:14:30.000000000 +0000 @@ -1 +1 @@ -int-signedness.patch +manually-define-LIBKEYUTILS-make-vars.patch diff -Nru mokutil-0.3.0+1538710437.fb6250f/debian/rules mokutil-0.6.0/debian/rules --- mokutil-0.3.0+1538710437.fb6250f/debian/rules 2016-03-17 19:37:45.000000000 +0000 +++ mokutil-0.6.0/debian/rules 2023-06-07 18:14:30.000000000 +0000 @@ -1,8 +1,4 @@ #!/usr/bin/make -f %: - dh $@ --with autoreconf - -#override_dh_autoreconf: -# NOCONFIGURE=1 dh_autoreconf ./autogen.sh - + dh $@ diff -Nru mokutil-0.3.0+1538710437.fb6250f/man/mokutil.1 mokutil-0.6.0/man/mokutil.1 --- mokutil-0.3.0+1538710437.fb6250f/man/mokutil.1 2018-10-05 03:33:57.000000000 +0000 +++ mokutil-0.6.0/man/mokutil.1 2022-05-07 07:02:34.000000000 +0000 @@ -15,11 +15,11 @@ .br \fBmokutil\fR [--import \fIkeylist\fR| -i \fIkeylist\fR] ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] | - [--simple-hash | -s] | [--mokx | -X]) + [--mokx | -X] | [--ca-check] | [--ignore-keyring]) .br \fBmokutil\fR [--delete \fIkeylist\fR | -d \fIkeylist\fR] ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] | - [--simple-hash | -s] | [--mokx |- X]) + [--mokx |- X]) .br \fBmokutil\fR [--revoke-import] ([--mokx | -X]) @@ -30,11 +30,9 @@ \fBmokutil\fR [--export | -x] .br \fBmokutil\fR [--password | -p] - ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] | - [--simple-hash | -s]) + ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P]) .br \fBmokutil\fR [--clear-password | -c] - ([--simple-hash | -s]) .br \fBmokutil\fR [--disable-validation] .br @@ -43,11 +41,11 @@ \fBmokutil\fR [--sb-state] .br \fBmokutil\fR [--test-key \fIkeyfile\fR | -t \fIkeyfile\fR] - ([--mokx | -X]) + ([--mokx | -X] | [--ca-check] | [--ignore-keyring]) .br \fBmokutil\fR [--reset] ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] | - [--simple-hash | -s] | [--mok | -X]) + [--mok | -X]) .br \fBmokutil\fR [--generate-hash=\fIpassword\fR | -g\fIpassword\fR] .br @@ -57,14 +55,18 @@ .br \fBmokutil\fR [--import-hash \fIhash\fR] ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] | - [--simple-hash | -s] | [--mokx | -X]) + [--mokx | -X]) .br \fBmokutil\fR [--delete-hash \fIhash\fR] ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P] | - [--simple-hash | -s] | [--mokx | -X]) + [--mokx | -X]) .br \fBmokutil\fR [--set-verbosity (\fItrue\fR | \fIfalse\fR)] .br +\fBmokutil\fR [--set-fallback-verbosity (\fItrue\fR | \fIfalse\fR)] +.br +\fBmokutil\fR [--set-fallback-noreboot (\fItrue\fR | \fIfalse\fR)] +.br \fBmokutil\fR [--pk] .br \fBmokutil\fR [--kek] @@ -73,6 +75,12 @@ .br \fBmokutil\fR [--dbx] .br +\fBmokutil\fR [--list-sbat-revocations] +.br +\fBmokutil\fR [--set-sbat-policy (\fIlatest\fR | \fIprevious\fR | \fIdelete\fR)] +.br +\fBmokutil\fR [--timeout \fI-1,0..0x7fff\fR] +.br .SH DESCRIPTION \fBmokutil\fR is a tool to import or delete the machines owner keys @@ -90,11 +98,11 @@ List the keys to be deleted .TP \fB-i, --import\fR -Collect the followed files and form a enrolling request to shim. The files must +Collect the following files and form an enrolling request to shim. The files must be in DER format. .TP \fB-d, --delete\fR -Collect the followed files and form a deleting request to shim. The files must be +Collect the following files and form a deleting request to shim. The files must be in DER format. .TP \fB--revoke-import\fR @@ -115,7 +123,7 @@ \fB--disable-validation\fR Disable the validation process in shim .TP -\fB--enrolled-validation\fR +\fB--enable-validation\fR Enable the validation process in shim .TP \fB--sb-state\fR @@ -136,11 +144,6 @@ \fB-P, --root-pw\fR Use the root password hash from /etc/shadow .TP -\fB-s, --simple-hash\fR -Use the old SHA256 password hash method to hash the password -.br -Note: --root-pw invalidates --simple-hash -.TP \fB--ignore-db\fR Tell shim to not use the keys in db to verify EFI images .TP @@ -150,17 +153,23 @@ \fB-X, --mokx\fR Manipulate the MOK blacklist (MOKX) instead of the MOK list .TP -\fB-i, --import-hash\fR +\fB--import-hash\fR Create an enrolling request for the hash of a key in DER format. Note that this is not the password hash. .TP -\fB-d, --delete-hash\fR -Create an deleting request for the hash of a key in DER format. Note that +\fB--delete-hash\fR +Create a deleting request for the hash of a key in DER format. Note that this is not the password hash. .TP \fB--set-verbosity\fR Set the SHIM_VERBOSE to make shim more or less verbose .TP +\fB--set-fallback-verbosity\fR +Set the FALLBACK_VERBOSE to make fallback more or less verbose +.TP +\fB--set-fallback-noreboot\fR +Set the FB_NO_REBOOT to prevent fallback from automatically rebooting the system +.TP \fB--pk\fR List the keys in the public Platform Key (PK) .TP @@ -173,3 +182,24 @@ \fB--dbx\fR List the keys in the secure boot blacklist signature store (dbx) .TP +\fB--list-sbat-revocations\fR +List the entries in the Secure Boot Advanced Targeting store (SBAT) +.TP +\fB--set-sbat-policy (\fIlatest\fR | \fIprevious\fR | \fIdelete\fR)\fR +Set the SbatPolicy UEFI Variable to have shim apply either the latest +or the previous SBAT revocations. If UEFI Secure Boot is disabled, then +delete will reset the SBAT revocations to an empty revocation list. +While latest and previous are persistent configuration, delete will be +cleared by shim on the next boot whether or not it succeeds. The default +behavior is for shim to apply the previous revocations. +.TP +\fB--timeout\fR +Set the timeout for MOK prompt +.TP +\fB--ca-check\fR +Check if the CA of the given key is already enrolled or blocked in the key +databases. +.TP +\fB--ignore-keyring\fR +Ignore the kernel builtin trusted keys keyring check when enrolling a key into MokList +.TP diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/efi_hash.c mokutil-0.6.0/src/efi_hash.c --- mokutil-0.3.0+1538710437.fb6250f/src/efi_hash.c 1970-01-01 00:00:00.000000000 +0000 +++ mokutil-0.6.0/src/efi_hash.c 2022-05-07 07:02:34.000000000 +0000 @@ -0,0 +1,183 @@ +/** + * Copyright (C) 2020 Gary Lin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include +#include +#include + +#include "efi_hash.h" + +uint32_t +efi_hash_size (const efi_guid_t *hash_type) +{ + if (efi_guid_cmp (hash_type, &efi_guid_sha1) == 0) { + return SHA_DIGEST_LENGTH; + } else if (efi_guid_cmp (hash_type, &efi_guid_sha224) == 0) { + return SHA224_DIGEST_LENGTH; + } else if (efi_guid_cmp (hash_type, &efi_guid_sha256) == 0) { + return SHA256_DIGEST_LENGTH; + } else if (efi_guid_cmp (hash_type, &efi_guid_sha384) == 0) { + return SHA384_DIGEST_LENGTH; + } else if (efi_guid_cmp (hash_type, &efi_guid_sha512) == 0) { + return SHA512_DIGEST_LENGTH; + } + + return 0; +} + +uint32_t +signature_size (const efi_guid_t *hash_type) +{ + uint32_t hash_size; + + hash_size = efi_hash_size (hash_type); + if (hash_size) + return (hash_size + sizeof(efi_guid_t)); + + return 0; +} + +int +print_hash_array (const efi_guid_t *hash_type, const void *hash_array, + const uint32_t array_size) +{ + uint32_t hash_size, remain; + uint32_t sig_size; + uint8_t *hash; + char *name; + + if (!hash_array || array_size == 0) { + fprintf (stderr, "invalid hash array\n"); + return -1; + } + + int rc = efi_guid_to_name ((efi_guid_t *)hash_type, &name); + if (rc < 0 || isxdigit(name[0])) { + if (name) + free(name); + fprintf (stderr, "unknown hash type\n"); + return -1; + } + + hash_size = efi_hash_size (hash_type); + sig_size = hash_size + sizeof(efi_guid_t); + + printf (" [%s]\n", name); + free(name); + remain = array_size; + hash = (uint8_t *)hash_array; + + while (remain > 0) { + if (remain < sig_size) { + fprintf (stderr, "invalid array size\n"); + return -1; + } + + printf (" "); + hash += sizeof(efi_guid_t); + for (unsigned int i = 0; i '9' || hash_str[i] < '0') && + (hash_str[i] > 'f' || hash_str[i] < 'a') && + (hash_str[i] > 'F' || hash_str[i] < 'A')) + return -1; + } + + switch (len) { + case SHA224_DIGEST_LENGTH*2: + *type = efi_guid_sha224; + hash_size = SHA224_DIGEST_LENGTH; + break; + case SHA256_DIGEST_LENGTH*2: + *type = efi_guid_sha256; + hash_size = SHA256_DIGEST_LENGTH; + break; + case SHA384_DIGEST_LENGTH*2: + *type = efi_guid_sha384; + hash_size = SHA384_DIGEST_LENGTH; + break; + case SHA512_DIGEST_LENGTH*2: + *type = efi_guid_sha512; + hash_size = SHA512_DIGEST_LENGTH; + break; + default: + return -1; + } + + return hash_size; +} diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/efi_hash.h mokutil-0.6.0/src/efi_hash.h --- mokutil-0.3.0+1538710437.fb6250f/src/efi_hash.h 1970-01-01 00:00:00.000000000 +0000 +++ mokutil-0.6.0/src/efi_hash.h 2022-05-07 07:02:34.000000000 +0000 @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2020 Gary Lin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef __EFI_HASH_H__ +#define __EFI_HASH_H__ + +#include +#include + +#include "mokutil.h" + +uint32_t efi_hash_size (const efi_guid_t *hash_type); +uint32_t signature_size (const efi_guid_t *hash_type); +int print_hash_array (const efi_guid_t *hash_type, const void *hash_array, + const uint32_t array_size); +int match_hash_array (const efi_guid_t *hash_type, const void *hash, + const void *hash_array, const uint32_t array_size); +int identify_hash_type (const char *hash_str, efi_guid_t *type); + +#endif /* __EFI_HASH_H__ */ diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/efi_x509.c mokutil-0.6.0/src/efi_x509.c --- mokutil-0.3.0+1538710437.fb6250f/src/efi_x509.c 1970-01-01 00:00:00.000000000 +0000 +++ mokutil-0.6.0/src/efi_x509.c 2022-05-07 07:02:34.000000000 +0000 @@ -0,0 +1,242 @@ +/** + * Copyright (C) 2020 Gary Lin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include +#include +#include + +#include "efi_x509.h" + +int +print_x509 (const uint8_t *cert, const int cert_size) +{ + X509 *X509cert; + EVP_MD_CTX *ctx; + const EVP_MD *md; + unsigned int md_len; + const unsigned char *in = (const unsigned char *)cert; + unsigned char fingerprint[EVP_MAX_MD_SIZE]; + + X509cert = d2i_X509 (NULL, &in, cert_size); + if (X509cert == NULL) { + fprintf (stderr, "Invalid X509 certificate\n"); + return -1; + } + + md = EVP_get_digestbyname ("SHA1"); + if(md == NULL) { + fprintf (stderr, "Failed to get SHA1 digest\n"); + goto cleanup_cert; + } + + ctx = EVP_MD_CTX_create (); + if (ctx == NULL) { + fprintf (stderr, "Failed to create digest context\n"); + goto cleanup_cert; + } + + if (!EVP_DigestInit_ex (ctx, md, NULL)) { + fprintf (stderr, "Failed to initialize digest context\n"); + goto cleanup_ctx; + } + + if (!EVP_DigestUpdate (ctx, cert, cert_size)) { + fprintf (stderr, "Failed to hash into the digest context\n"); + goto cleanup_ctx; + } + + if (!EVP_DigestFinal_ex (ctx, fingerprint, &md_len)) { + fprintf (stderr, "Failed to get digest value\n"); + goto cleanup_ctx; + } + + printf ("SHA1 Fingerprint: "); + for (unsigned int i = 0; i < md_len; i++) { + printf ("%02x", fingerprint[i]); + if (i < md_len - 1) + printf (":"); + } + printf ("\n"); + X509_print_fp (stdout, X509cert); + +cleanup_ctx: + EVP_MD_CTX_destroy (ctx); +cleanup_cert: + X509_free (X509cert); + + return 0; +} + +int +is_valid_cert (const uint8_t *cert, const uint32_t cert_size) +{ + X509 *X509cert; + + if (cert == NULL) + return 0; + + X509cert = d2i_X509 (NULL, &cert, cert_size); + if (X509cert == NULL) + return 0; + + X509_free (X509cert); + + return 1; +} + +/** + * Check whether the given CA cert is the immediate CA of the given cert + **/ +int +is_immediate_ca (const uint8_t *cert, const uint32_t cert_size, + const uint8_t *ca_cert, const uint32_t ca_cert_size) +{ + X509 *X509cert = NULL; + X509 *X509ca = NULL; + X509_STORE *cert_store = NULL; + X509_STORE_CTX *cert_ctx = NULL; + int ret = 0; + + if (cert == NULL || ca_cert == NULL) + return 0; + + if (EVP_add_digest (EVP_md5 ()) == 0) + return 0; + if (EVP_add_digest (EVP_sha1 ()) == 0) + return 0; + if (EVP_add_digest (EVP_sha256 ()) == 0) + return 0; + + X509cert = d2i_X509 (NULL, &cert, cert_size); + if (X509cert == NULL) + return 0; + + X509ca = d2i_X509 (NULL, &ca_cert, ca_cert_size); + if (X509ca == NULL) + goto err; + + cert_store = X509_STORE_new (); + if (cert_store == NULL) + goto err; + + if (X509_STORE_add_cert (cert_store, X509ca) == 0) + goto err; + + /* Follow edk2 CryptoPkg to allow partial certificate chains and + * disable time checks */ + X509_STORE_set_flags (cert_store, + X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME); + + cert_ctx = X509_STORE_CTX_new (); + if (cert_ctx == NULL) + goto err; + + if (X509_STORE_CTX_init (cert_ctx, cert_store, X509cert, NULL) == 0) + goto err; + + /* Verify the cert */ + ret = X509_verify_cert (cert_ctx); + /* Treat the exceptional error as FALSE */ + if (ret < 0) + ret = 0; + X509_STORE_CTX_cleanup (cert_ctx); + +err: + if (X509cert) + X509_free (X509cert); + + if (X509ca) + X509_free (X509ca); + + if (cert_store) + X509_STORE_free (cert_store); + + if (cert_store) + X509_STORE_CTX_free (cert_ctx); + + return ret; +} + +/** + * Get the Subject Key Identifier of the given certificate + * + * This function allocates the SKID string and the caller is responsible to + * free the string. + * + * Return value: + * - 0 : Success + * - -1 : Error + */ +int +get_cert_skid(const uint8_t *cert, const uint32_t cert_size, char **skid) +{ + X509 *X509cert; + const ASN1_OCTET_STRING *asn1_id; + const uint8_t *data; + int data_len, i; + char *id_str, *ptr; + int ret = -1; + + X509cert = d2i_X509 (NULL, &cert, cert_size); + if (X509cert == NULL) { + fprintf (stderr, "invalid x509 certificate\n"); + goto out; + } + + asn1_id = X509_get0_subject_key_id (X509cert); + if (asn1_id == NULL) { + fprintf (stderr, "Failed to get Subject Key ID\n"); + goto out; + } + + data = ASN1_STRING_get0_data (asn1_id); + data_len = ASN1_STRING_length (asn1_id); + + id_str = malloc (data_len*2 + 1); + if (id_str == NULL) { + fprintf (stderr, "Failed to allocated id string\n"); + goto out; + } + + ptr = id_str; + for (i = 0; i < data_len; i++) { + snprintf (ptr, 3, "%02x", data[i]); + ptr += 2; + } + + *skid = id_str; + ret = 0; +out: + if (X509cert) + X509_free (X509cert); + + return ret; +} diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/efi_x509.h mokutil-0.6.0/src/efi_x509.h --- mokutil-0.3.0+1538710437.fb6250f/src/efi_x509.h 1970-01-01 00:00:00.000000000 +0000 +++ mokutil-0.6.0/src/efi_x509.h 2022-05-07 07:02:34.000000000 +0000 @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2020 Gary Lin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef __EFI_X509_H__ +#define __EFI_X509_H__ + +#include + +int print_x509 (const uint8_t *cert, const int cert_size); +int is_valid_cert (const uint8_t *cert, const uint32_t cert_size); +int is_immediate_ca (const uint8_t *cert, const uint32_t cert_size, + const uint8_t *ca_cert, const uint32_t ca_cert_size); +int get_cert_skid(const uint8_t *cert, const uint32_t cert_size, char **skid); + +#endif /* __EFI_X509_H__ */ diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/keyring.c mokutil-0.6.0/src/keyring.c --- mokutil-0.3.0+1538710437.fb6250f/src/keyring.c 1970-01-01 00:00:00.000000000 +0000 +++ mokutil-0.6.0/src/keyring.c 2022-05-07 07:02:34.000000000 +0000 @@ -0,0 +1,111 @@ +/** + * Copyright (C) 2020 Gary Lin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include +#include +#include +#include + +#include + +#include "keyring.h" + +/** + * Match the x509v3 Subject Key ID in the descriptions of the kernel built-in + * trusted keys keyring + * + * return value + * - 0 : not matched + * - 1 : matched + * - -1 : error + */ +int +match_skid_in_trusted_keyring (const char *skid) +{ + key_serial_t ring_id, key_id, *key_ptr; + void *keylist = NULL; + int count; + char buffer[1024]; + char *ptr; + long buf_size; + int ret = -1; + + if (skid == NULL) + return -1; + + /* Find the keyring ID of the kernel trusted keys */ + ring_id = find_key_by_type_and_desc("keyring", ".builtin_trusted_keys", 0); + if (ring_id < 0) { + fprintf(stderr, "Failed to accesss kernel trusted keyring: %m\n"); + goto out; + } + + count = keyctl_read_alloc(ring_id, &keylist); + if (count < 0) { + fprintf(stderr, "Failed to read kernel trusted keyring\n"); + goto out; + } + + count /= sizeof(key_serial_t); + if (count == 0) { + /* The keyring is empty */ + ret = 0; + goto out; + } + + /* Iterate the keylist and match SKID */ + key_ptr = keylist; + do { + key_id = *key_ptr++; + + buf_size = keyctl_describe(key_id, buffer, sizeof(buffer)); + if (buf_size < 0) { + fprintf(stderr, "key %X inaccessible %m\n", key_id); + goto out; + } + + /* Check if SKID is in the description */ + ptr = strstr(buffer, skid); + if (ptr && *(ptr + strlen(skid)) == '\0') { + /* Matched */ + ret = 1; + goto out; + } + } while (--count); + + ret = 0; +out: + if (keylist) + free(keylist); + + return ret; + +} diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/keyring.h mokutil-0.6.0/src/keyring.h --- mokutil-0.3.0+1538710437.fb6250f/src/keyring.h 1970-01-01 00:00:00.000000000 +0000 +++ mokutil-0.6.0/src/keyring.h 2022-05-07 07:02:34.000000000 +0000 @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2020 Gary Lin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef __KEYRING_H__ +#define __KEYRING_H__ + +int match_skid_in_trusted_keyring (const char *skid); + +#endif /* __KEYRING_H__ */ diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/Makefile.am mokutil-0.6.0/src/Makefile.am --- mokutil-0.3.0+1538710437.fb6250f/src/Makefile.am 2018-10-05 03:33:57.000000000 +0000 +++ mokutil-0.6.0/src/Makefile.am 2022-05-07 07:02:34.000000000 +0000 @@ -2,13 +2,25 @@ mokutil_CFLAGS = $(OPENSSL_CFLAGS) \ $(EFIVAR_CFLAGS) \ - $(WARNINGFLAGS_C) + $(LIBKEYUTILS_CFLAGS) \ + $(WARNINGFLAGS_C) \ + -DVERSION="\"$(VERSION)\"" mokutil_LDADD = $(OPENSSL_LIBS) \ $(EFIVAR_LIBS) \ + $(LIBKEYUTILS_LIBS) \ -lcrypt mokutil_SOURCES = signature.h \ + efi_hash.h \ + efi_hash.c \ + efi_x509.h \ + efi_x509.c \ + keyring.h \ + keyring.c \ password-crypt.h \ password-crypt.c \ + util.h \ + util.c \ + mokutil.h \ mokutil.c diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/mokutil.c mokutil-0.6.0/src/mokutil.c --- mokutil-0.3.0+1538710437.fb6250f/src/mokutil.c 2018-10-05 03:33:57.000000000 +0000 +++ mokutil-0.6.0/src/mokutil.c 2022-05-07 07:02:34.000000000 +0000 @@ -1,5 +1,5 @@ /** - * Copyright (C) 2012-2014 Gary Lin + * Copyright (C) 2012-2020 Gary Lin * Copyright (C) 2012 Matthew Garrett * * This program is free software: you can redistribute it and/or modify @@ -29,30 +29,29 @@ * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ -#include #include #include #include #include #include #include -#include -#include -#include #include -#include #include #include #include #include -#include #include #include +#include "mokutil.h" #include "signature.h" +#include "efi_hash.h" +#include "efi_x509.h" +#include "keyring.h" #include "password-crypt.h" +#include "util.h" #define PASSWORD_MAX 256 #define PASSWORD_MIN 1 @@ -76,65 +75,27 @@ #define TEST_KEY (1 << 14) #define RESET (1 << 15) #define GENERATE_PW_HASH (1 << 16) -#define SIMPLE_HASH (1 << 17) -#define IGNORE_DB (1 << 18) -#define USE_DB (1 << 19) -#define MOKX (1 << 20) -#define IMPORT_HASH (1 << 21) -#define DELETE_HASH (1 << 22) -#define VERBOSITY (1 << 23) -#define TIMEOUT (1 << 24) +#define IGNORE_DB (1 << 17) +#define USE_DB (1 << 18) +#define MOKX (1 << 19) +#define IMPORT_HASH (1 << 20) +#define DELETE_HASH (1 << 21) +#define VERBOSITY (1 << 22) +#define TIMEOUT (1 << 23) +#define LIST_SBAT (1 << 24) +#define FB_VERBOSITY (1 << 25) +#define FB_NOREBOOT (1 << 26) +#define TRUST_MOK (1 << 27) +#define UNTRUST_MOK (1 << 28) +#define SET_SBAT (1 << 29) #define DEFAULT_CRYPT_METHOD SHA512_BASED #define DEFAULT_SALT_SIZE SHA512_SALT_MAX #define SETTINGS_LEN (DEFAULT_SALT_SIZE*2) #define BUF_SIZE 300 -typedef unsigned long efi_status_t; -typedef uint8_t efi_bool_t; -typedef wchar_t efi_char16_t; /* UNICODE character */ - -static int use_simple_hash; - -typedef enum { - DELETE_MOK = 0, - ENROLL_MOK, - DELETE_BLACKLIST, - ENROLL_BLACKLIST, -} MokRequest; - -typedef enum { - MOK_LIST_RT = 0, - MOK_LIST_X_RT, - PK, - KEK, - DB, - DBX, -} DBName; - -const char *db_var_name[] = { - [MOK_LIST_RT] = "MokListRT", - [MOK_LIST_X_RT] = "MokListXRT", - [PK] = "PK", - [KEK] = "KEK", - [DB] = "db", - [DBX] = "dbx", -}; - -const char *db_friendly_name[] = { - [MOK_LIST_RT] = "MOK", - [MOK_LIST_X_RT] = "MOKX", - [PK] = "PK", - [KEK] = "KEK", - [DB] = "DB", - [DBX] = "DBX", -}; - -typedef struct { - EFI_SIGNATURE_LIST *header; - uint32_t mok_size; - void *mok; -} MokListNode; +static int force_ca_check; +static int check_keyring; typedef struct { uint32_t mok_toggle_state; @@ -171,266 +132,28 @@ printf (" --import-hash \t\t\tImport a hash into MOK or MOKX\n"); printf (" --delete-hash \t\t\tDelete a hash in MOK or MOKX\n"); printf (" --set-verbosity \t\tSet the verbosity bit for shim\n"); + printf (" --set-fallback-verbosity \t\tSet the verbosity bit for fallback\n"); + printf (" --set-fallback-noreboot \t\tPrevent fallback from automatically rebooting\n"); + printf (" --trust-mok\t\t\t\tTrust MOK keys within the kernel keyring\n"); + printf (" --untrust-mok\t\t\t\tDo not trust MOK keys\n"); + printf (" --set-sbat-policy \t\tApply Latest, Previous, or Blank SBAT revocations\n"); printf (" --pk\t\t\t\t\tList the keys in PK\n"); printf (" --kek\t\t\t\t\tList the keys in KEK\n"); printf (" --db\t\t\t\t\tList the keys in db\n"); printf (" --dbx\t\t\t\t\tList the keys in dbx\n"); printf (" --timeout <-1,0..0x7fff>\t\tSet the timeout for MOK prompt\n"); + printf (" --list-sbat-revocations\t\t\t\tList the entries in SBAT\n"); printf ("\n"); printf ("Supplimentary Options:\n"); printf (" --hash-file \t\tUse the specific password hash\n"); printf (" --root-pw\t\t\t\tUse the root password\n"); - printf (" --simple-hash\t\t\t\tUse the old password hash method\n"); printf (" --mokx\t\t\t\tManipulate the MOK blacklist\n"); + printf (" --ca-check\t\t\t\tCheck if CA of the key is enrolled/blocked\n"); + printf (" --ignore-keyring\t\t\tDon't check if the key is the kernel keyring\n"); } static int -test_and_delete_var (const char *var_name) -{ - size_t size; - int ret; - - ret = efi_get_variable_size (efi_guid_shim, var_name, &size); - if (ret < 0) { - if (errno == ENOENT) - return 0; - fprintf (stderr, "Failed to access variable \"%s\": %m\n", - var_name); - } - - /* Attempt to delete it no matter what, problem efi_get_variable_size() - * had, unless it just doesn't exist anyway. */ - if (!(ret < 0 && errno == ENOENT)) { - if (efi_del_variable (efi_guid_shim, var_name) < 0) - fprintf (stderr, "Failed to unset \"%s\": %m\n", var_name); - } - - return ret; -} - -static unsigned long -efichar_from_char (efi_char16_t *dest, const char *src, size_t dest_len) -{ - unsigned int i, src_len = strlen(src); - for (i=0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) { - dest[i] = src[i]; - } - dest[i] = 0; - return i * sizeof(*dest); -} - -static uint32_t -efi_hash_size (const efi_guid_t *hash_type) -{ - if (efi_guid_cmp (hash_type, &efi_guid_sha1) == 0) { - return SHA_DIGEST_LENGTH; - } else if (efi_guid_cmp (hash_type, &efi_guid_sha224) == 0) { - return SHA224_DIGEST_LENGTH; - } else if (efi_guid_cmp (hash_type, &efi_guid_sha256) == 0) { - return SHA256_DIGEST_LENGTH; - } else if (efi_guid_cmp (hash_type, &efi_guid_sha384) == 0) { - return SHA384_DIGEST_LENGTH; - } else if (efi_guid_cmp (hash_type, &efi_guid_sha512) == 0) { - return SHA512_DIGEST_LENGTH; - } - - return 0; -} - -static uint32_t -signature_size (const efi_guid_t *hash_type) -{ - uint32_t hash_size; - - hash_size = efi_hash_size (hash_type); - if (hash_size) - return (hash_size + sizeof(efi_guid_t)); - - return 0; -} - -static MokListNode* -build_mok_list (void *data, unsigned long data_size, uint32_t *mok_num) -{ - MokListNode *list = NULL; - MokListNode *list_new = NULL; - EFI_SIGNATURE_LIST *CertList = data; - EFI_SIGNATURE_DATA *Cert; - unsigned long dbsize = data_size; - unsigned long count = 0; - void *end = data + data_size; - - while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) { - if ((void *)(CertList + 1) > end || - CertList->SignatureListSize == 0 || - CertList->SignatureListSize <= CertList->SignatureSize) { - fprintf (stderr, "Corrupted signature list\n"); - if (list) - free (list); - return NULL; - } - - if ((efi_guid_cmp (&CertList->SignatureType, &efi_guid_x509_cert) != 0) && - (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha1) != 0) && - (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha224) != 0) && - (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha256) != 0) && - (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha384) != 0) && - (efi_guid_cmp (&CertList->SignatureType, &efi_guid_sha512) != 0)) { - dbsize -= CertList->SignatureListSize; - CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList + - CertList->SignatureListSize); - continue; - } - - if ((efi_guid_cmp (&CertList->SignatureType, &efi_guid_x509_cert) != 0) && - (CertList->SignatureSize != signature_size (&CertList->SignatureType))) { - dbsize -= CertList->SignatureListSize; - CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList + - CertList->SignatureListSize); - continue; - } - - Cert = (EFI_SIGNATURE_DATA *) (((uint8_t *) CertList) + - sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); - - if ((void *)(Cert + 1) > end || - CertList->SignatureSize <= sizeof(efi_guid_t)) { - if (list) - free (list); - fprintf (stderr, "Corrupted signature\n"); - return NULL; - } - - list_new = realloc(list, sizeof(MokListNode) * (count + 1)); - if (list_new) { - list = list_new; - } else { - if (list) - free (list); - fprintf(stderr, "Unable to allocate MOK list\n"); - return NULL; - } - - list[count].header = CertList; - if (efi_guid_cmp (&CertList->SignatureType, &efi_guid_x509_cert) == 0) { - /* X509 certificate */ - list[count].mok_size = CertList->SignatureSize - - sizeof(efi_guid_t); - list[count].mok = (void *)Cert->SignatureData; - } else { - /* hash array */ - list[count].mok_size = CertList->SignatureListSize - - sizeof(EFI_SIGNATURE_LIST) - - CertList->SignatureHeaderSize; - list[count].mok = (void *)Cert; - } - - if (list[count].mok_size > (unsigned long)end - - (unsigned long)list[count].mok) { - fprintf (stderr, "Corrupted data\n"); - free (list); - return NULL; - } - - count++; - dbsize -= CertList->SignatureListSize; - CertList = (EFI_SIGNATURE_LIST *) ((uint8_t *) CertList + - CertList->SignatureListSize); - } - - *mok_num = count; - - return list; -} - -static int -print_x509 (char *cert, int cert_size) -{ - X509 *X509cert; - BIO *cert_bio; - SHA_CTX ctx; - uint8_t fingerprint[SHA_DIGEST_LENGTH]; - - cert_bio = BIO_new (BIO_s_mem ()); - BIO_write (cert_bio, cert, cert_size); - if (cert_bio == NULL) { - fprintf (stderr, "Failed to write BIO\n"); - return -1; - } - - X509cert = d2i_X509_bio (cert_bio, NULL); - if (X509cert == NULL) { - fprintf (stderr, "Invalid X509 certificate\n"); - return -1; - } - - SHA1_Init (&ctx); - SHA1_Update (&ctx, cert, cert_size); - SHA1_Final (fingerprint, &ctx); - - printf ("SHA1 Fingerprint: "); - for (unsigned int i = 0; i < SHA_DIGEST_LENGTH; i++) { - printf ("%02x", fingerprint[i]); - if (i < SHA_DIGEST_LENGTH - 1) - printf (":"); - } - printf ("\n"); - X509_print_fp (stdout, X509cert); - - BIO_free (cert_bio); - - return 0; -} - -static int -print_hash_array (efi_guid_t *hash_type, void *hash_array, uint32_t array_size) -{ - uint32_t hash_size, remain; - uint32_t sig_size; - uint8_t *hash; - char *name; - - if (!hash_array || array_size == 0) { - fprintf (stderr, "invalid hash array\n"); - return -1; - } - - int rc = efi_guid_to_name(hash_type, &name); - if (rc < 0 || isxdigit(name[0])) { - if (name) - free(name); - fprintf (stderr, "unknown hash type\n"); - return -1; - } - - hash_size = efi_hash_size (hash_type); - sig_size = hash_size + sizeof(efi_guid_t); - - printf (" [%s]\n", name); - free(name); - remain = array_size; - hash = (uint8_t *)hash_array; - - while (remain > 0) { - if (remain < sig_size) { - fprintf (stderr, "invalid array size\n"); - return -1; - } - - printf (" "); - hash += sizeof(efi_guid_t); - for (unsigned int i = 0; iSignatureType, &efi_guid_x509_cert) == 0) { - print_x509 ((char *)list[i].mok, list[i].mok_size); + efi_guid_t sigtype = list[i].header->SignatureType; + if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) == 0) { + print_x509 (list[i].mok, list[i].mok_size); } else { - print_hash_array (&list[i].header->SignatureType, + print_hash_array (&sigtype, list[i].mok, list[i].mok_size); } if (i < mok_num - 1) @@ -457,222 +181,53 @@ return 0; } -/* match the hash in the hash array and return the index if matched */ -static int -match_hash_array (const efi_guid_t *hash_type, const void *hash, - const void *hash_array, const uint32_t array_size) -{ - uint32_t hash_size, hash_count; - uint32_t sig_size; - void *ptr; - - hash_size = efi_hash_size (hash_type); - if (!hash_size) - return -1; - - sig_size = hash_size + sizeof(efi_guid_t); - if ((array_size % sig_size) != 0) { - fprintf (stderr, "invalid hash array size\n"); - return -1; - } - - ptr = (void *)hash_array; - hash_count = array_size / sig_size; - for (unsigned int i = 0; i < hash_count; i++) { - ptr += sizeof(efi_guid_t); - if (memcmp (ptr, hash, hash_size) == 0) - return i; - ptr += hash_size; - } - - return -1; -} - -static int -delete_data_from_list (const efi_guid_t *var_guid, const char *var_name, - const efi_guid_t *type, void *data, uint32_t data_size) -{ - uint8_t *var_data = NULL; - size_t var_data_size = 0; - uint32_t attributes; - MokListNode *list; - uint32_t mok_num, total, remain; - void *end, *start = NULL; - int del_ind, ret = 0; - uint32_t sig_list_size, sig_size; - - if (!var_name || !data || data_size == 0) - return 0; - - ret = efi_get_variable (*var_guid, var_name, &var_data, &var_data_size, - &attributes); - if (ret < 0) { - if (errno == ENOENT) - return 0; - fprintf (stderr, "Failed to read variable \"%s\": %m\n", - var_name); - return -1; - } - - total = var_data_size; - - list = build_mok_list (var_data, var_data_size, &mok_num); - if (list == NULL) - goto done; - - remain = total; - for (unsigned int i = 0; i < mok_num; i++) { - remain -= list[i].header->SignatureListSize; - if (efi_guid_cmp (&list[i].header->SignatureType, type) != 0) - continue; - - sig_list_size = list[i].header->SignatureListSize; - - if (efi_guid_cmp (type, &efi_guid_x509_cert) == 0) { - if (list[i].mok_size != data_size) - continue; - - if (memcmp (list[i].mok, data, data_size) == 0) { - /* Remove this key */ - start = (void *)list[i].header; - end = start + sig_list_size; - total -= sig_list_size; - break; - } - } else { - del_ind = match_hash_array (type, data, list[i].mok, - list[i].mok_size); - if (del_ind < 0) - continue; - - start = (void *)list[i].header; - sig_size = signature_size (type); - if (sig_list_size == (sizeof(EFI_SIGNATURE_LIST) + sig_size)) { - /* Only one hash in the list */ - end = start + sig_list_size; - total -= sig_list_size; - } else { - /* More than one hash in the list */ - start += sizeof(EFI_SIGNATURE_LIST) + sig_size * del_ind; - end = start + sig_size; - total -= sig_size; - list[i].header->SignatureListSize -= sig_size; - remain += sig_list_size - sizeof(EFI_SIGNATURE_LIST) - - (del_ind + 1) * sig_size; - } - break; - } - } - - /* the key or hash is not in this list */ - if (start == NULL) - return 0; - - /* all keys are removed */ - if (total == 0) { - test_and_delete_var (var_name); - - /* delete the password */ - if (strcmp (var_name, "MokNew") == 0) - test_and_delete_var ("MokAuth"); - else if (strcmp (var_name, "MokXNew") == 0) - test_and_delete_var ("MokXAuth"); - else if (strcmp (var_name, "MokDel") == 0) - test_and_delete_var ("MokDelAuth"); - else if (strcmp (var_name, "MokXDel") == 0) - test_and_delete_var ("MokXDelAuth"); - - ret = 1; - goto done; - } - - /* remove the key or hash */ - if (remain > 0) - memmove (start, end, remain); - - attributes = EFI_VARIABLE_NON_VOLATILE - | EFI_VARIABLE_BOOTSERVICE_ACCESS - | EFI_VARIABLE_RUNTIME_ACCESS; - ret = efi_set_variable (*var_guid, var_name, - var_data, total, attributes, - S_IRUSR | S_IWUSR); - if (ret < 0) { - fprintf (stderr, "Failed to write variable \"%s\": %m\n", - var_name); - goto done; - } - efi_chmod_variable(*var_guid, var_name, S_IRUSR | S_IWUSR); - - ret = 1; -done: - if (list) - free (list); - free (var_data); - - return ret; -} - static int list_keys_in_var (const char *var_name, const efi_guid_t guid) { uint8_t *data = NULL; - size_t data_size; + char varname[] = "implausibly-long-mok-variable-name"; + size_t data_sz, i, varname_sz = sizeof(varname); uint32_t attributes; int ret; - ret = efi_get_variable (guid, var_name, &data, &data_size, &attributes); - if (ret < 0) { - if (errno == ENOENT) { - printf ("%s is empty\n", var_name); - return 0; - } - - fprintf (stderr, "Failed to read %s: %m\n", var_name); - return -1; + ret = mok_get_variable(var_name, &data, &data_sz); + if (ret >= 0) { + ret = list_keys (data, data_sz); + free(data); + return ret; } - ret = list_keys (data, data_size); - free (data); - - return ret; -} - -static int -read_hidden_line (char **line, size_t *n) -{ - struct termios old, new; - int nread; - int isTTY = isatty(fileno (stdin)); - - if (isTTY) { - /* Turn echoing off and fail if we can't. */ - if (tcgetattr (fileno (stdin), &old) != 0) - return -1; - - new = old; - new.c_lflag &= ~ECHO; - - if (tcsetattr (fileno (stdin), TCSAFLUSH, &new) != 0) - return -1; - } + for (i = 0; i < SIZE_MAX; i++) { + if (i == 0) { + snprintf(varname, varname_sz, "%s", var_name); + } else { + snprintf(varname, varname_sz, "%s%zu", var_name, i); + } - /* Read the password. */ - nread = getline (line, n, stdin); + ret = efi_get_variable (guid, varname, &data, &data_sz, + &attributes); + if (ret < 0) + return 0; - if (isTTY) { - /* Restore terminal. */ - (void) tcsetattr (fileno (stdin), TCSAFLUSH, &old); + ret = list_keys (data, data_sz); + free(data); + /* + * If ret is < 0, the next one will error as well. + * If ret is 0, we need to test the next variable. + * If it's 1, that's a real answer. + */ + if (ret < 0) + return 0; + if (ret > 0) + return ret; } - /* Remove the newline */ - (*line)[nread-1] = '\0'; - - return nread-1; + return 0; } static int get_password (char **password, unsigned int *len, - unsigned int min, unsigned int max) + const unsigned int min, const unsigned int max) { char *password_1, *password_2; unsigned int len_1, len_2; @@ -732,34 +287,8 @@ return ret; } -static int -generate_auth (void *new_list, int list_len, char *password, - unsigned int pw_len, uint8_t *auth) -{ - efi_char16_t efichar_pass[PASSWORD_MAX+1]; - unsigned long efichar_len; - SHA256_CTX ctx; - - if (!password || !auth) - return -1; - - efichar_len = efichar_from_char (efichar_pass, password, - pw_len * sizeof(efi_char16_t)); - - SHA256_Init (&ctx); - - if (new_list) - SHA256_Update (&ctx, new_list, list_len); - - SHA256_Update (&ctx, efichar_pass, efichar_len); - - SHA256_Final (auth, &ctx); - - return 0; -} - static void -generate_salt (char salt[], unsigned int salt_size) +generate_pw_salt (char salt[], const unsigned int salt_size) { struct timeval tv; char *rand_str; @@ -780,7 +309,8 @@ } static int -generate_hash (pw_crypt_t *pw_crypt, char *password, unsigned int pw_len) +generate_pw_crypt (pw_crypt_t *pw_crypt, const char *password, + const unsigned int pw_len) { pw_crypt_t new_crypt; char settings[SETTINGS_LEN]; @@ -796,8 +326,8 @@ if (!prefix) return -1; - pw_crypt->salt_size = get_salt_size (pw_crypt->method); - generate_salt ((char *)pw_crypt->salt, pw_crypt->salt_size); + pw_crypt->salt_size = get_pw_salt_size (pw_crypt->method); + generate_pw_salt ((char *)pw_crypt->salt, pw_crypt->salt_size); memset (settings, 0, sizeof (settings)); next = stpncpy (settings, prefix, settings_len); @@ -816,7 +346,7 @@ if (decode_pass (crypt_string, &new_crypt) < 0) return -1; - hash_len = get_hash_size (new_crypt.method); + hash_len = get_pw_hash_size (new_crypt.method); if (hash_len < 0) return -1; memcpy (pw_crypt->hash, new_crypt.hash, hash_len); @@ -831,7 +361,7 @@ } static int -get_hash_from_file (const char *file, pw_crypt_t *pw_crypt) +get_pw_hash_from_file (const char *file, pw_crypt_t *pw_crypt) { char string[BUF_SIZE]; ssize_t read_len = 0; @@ -890,14 +420,11 @@ } static int -update_request (void *new_list, int list_len, MokRequest req, - const char *hash_file, const int root_pw) +update_request (void *new_list, const int list_len, const MokRequest req, + const char *pw_hash_file, const int root_pw) { - uint8_t *data; - size_t data_size; const char *req_name, *auth_name; pw_crypt_t pw_crypt; - uint8_t auth[SHA256_DIGEST_LENGTH]; char *password = NULL; unsigned int pw_len; int auth_ret; @@ -930,8 +457,8 @@ return -1; } - if (hash_file) { - if (get_hash_from_file (hash_file, &pw_crypt) < 0) { + if (pw_hash_file) { + if (get_pw_hash_from_file (pw_hash_file, &pw_crypt) < 0) { fprintf (stderr, "Failed to read hash\n"); goto error; } @@ -946,12 +473,7 @@ goto error; } - if (!use_simple_hash) { - auth_ret = generate_hash (&pw_crypt, password, pw_len); - } else { - auth_ret = generate_auth (new_list, list_len, password, - pw_len, auth); - } + auth_ret = generate_pw_crypt (&pw_crypt, password, pw_len); if (auth_ret < 0) { fprintf (stderr, "Couldn't generate hash\n"); goto error; @@ -960,12 +482,10 @@ if (new_list) { /* Write MokNew, MokDel, MokXNew, or MokXDel*/ - data = new_list; - data_size = list_len; - - if (efi_set_variable (efi_guid_shim, req_name, - data, data_size, attributes, - S_IRUSR | S_IWUSR) < 0) { + ret = efi_set_variable (efi_guid_shim, req_name, + new_list, list_len, attributes, + S_IRUSR | S_IWUSR); + if (ret < 0) { switch (req) { case ENROLL_MOK: fprintf (stderr, "Failed to enroll new keys\n"); @@ -983,22 +503,16 @@ goto error; } } else { - test_and_delete_var (req_name); + test_and_delete_mok_var (req_name); } /* Write MokAuth, MokDelAuth, MokXAuth, or MokXDelAuth */ - if (!use_simple_hash) { - data = (void *)&pw_crypt; - data_size = PASSWORD_CRYPT_SIZE; - } else { - data = (void *)auth; - data_size = SHA256_DIGEST_LENGTH; - } - - if (efi_set_variable (efi_guid_shim, auth_name, data, data_size, - attributes, S_IRUSR | S_IWUSR) < 0) { + ret = efi_set_variable (efi_guid_shim, auth_name, (void *)&pw_crypt, + PASSWORD_CRYPT_SIZE, attributes, + S_IRUSR | S_IWUSR); + if (ret < 0) { fprintf (stderr, "Failed to write %s\n", auth_name); - test_and_delete_var (req_name); + test_and_delete_mok_var (req_name); goto error; } @@ -1010,45 +524,15 @@ } static int -is_valid_cert (void *cert, uint32_t cert_size) +is_one_duplicate (const efi_guid_t *type, + const void *data, const uint32_t data_size, + uint8_t *var_data, size_t var_data_size) { - X509 *X509cert; - BIO *cert_bio; - - cert_bio = BIO_new (BIO_s_mem ()); - BIO_write (cert_bio, cert, cert_size); - if (cert_bio == NULL) { - return 0; - } - - X509cert = d2i_X509_bio (cert_bio, NULL); - if (X509cert == NULL) { - BIO_free (cert_bio); - return 0; - } - - BIO_free (cert_bio); - - return 1; -} - -static int -is_duplicate (const efi_guid_t *type, const void *data, const uint32_t data_size, - const efi_guid_t *vendor, const char *db_name) -{ - uint8_t *var_data; - size_t var_data_size; - uint32_t attributes; uint32_t node_num; MokListNode *list; int ret = 0; - if (!data || data_size == 0 || !db_name) - return 0; - - ret = efi_get_variable (*vendor, db_name, &var_data, &var_data_size, - &attributes); - if (ret < 0) + if (!data || data_size == 0) return 0; list = build_mok_list (var_data, var_data_size, &node_num); @@ -1057,7 +541,8 @@ } for (unsigned int i = 0; i < node_num; i++) { - if (efi_guid_cmp (&list[i].header->SignatureType, type) != 0) + efi_guid_t sigtype = list[i].header->SignatureType; + if (efi_guid_cmp (&sigtype, type) != 0) continue; if (efi_guid_cmp (type, &efi_guid_x509_cert) == 0) { @@ -1080,24 +565,84 @@ done: if (list) free (list); - free (var_data); return ret; } static int -is_valid_request (const efi_guid_t *type, void *mok, uint32_t mok_size, - MokRequest req) +is_duplicate (const efi_guid_t *type, + const void *data, const uint32_t data_size, + const efi_guid_t *vendor, const char *db_name) +{ + uint32_t attributes; + char varname[] = "implausibly-long-mok-variable-name"; + size_t varname_sz = sizeof(varname); + int ret = 0; + size_t i; + + if (!strncmp(db_name, "Mok", 3)) { + uint8_t *var_data = NULL; + size_t var_data_size = 0; + ret = mok_get_variable(db_name, &var_data, &var_data_size); + if (ret >= 0) { + ret = is_one_duplicate(type, data, data_size, + var_data, var_data_size); + if (ret >= 0) { + free (var_data); + return ret; + } + var_data = NULL; + var_data_size = 0; + } + } + + for (i = 0; i < SIZE_MAX; i++) { + uint8_t *var_data = NULL; + size_t var_data_size = 0; + if (i == 0) { + snprintf(varname, varname_sz, "%s", db_name); + } else { + snprintf(varname, varname_sz, "%s%zu", db_name, i); + } + + ret = efi_get_variable (*vendor, varname, + &var_data, &var_data_size, + &attributes); + if (ret < 0) + return 0; + + ret = is_one_duplicate(type, data, data_size, + var_data, var_data_size); + free (var_data); + /* + * If ret is < 0, the next one will error as well. + * If ret is 0, we need to test the next variable. + * If it's 1, that's a real answer. + */ + if (ret < 0) + return 0; + if (ret > 0) + return ret; + } + + return 0; +} + +static int +is_valid_request (const efi_guid_t *type, const void *mok, + const uint32_t mok_size, const MokRequest req) { switch (req) { case ENROLL_MOK: - if (is_duplicate (type, mok, mok_size, &efi_guid_global, "PK") || - is_duplicate (type, mok, mok_size, &efi_guid_global, "KEK") || - is_duplicate (type, mok, mok_size, &efi_guid_security, "db") || + if (is_duplicate (type, mok, mok_size, &efi_guid_security, "db") || is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListRT") || is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokNew")) { return 0; } + /* Also check the blocklists */ + if (is_duplicate (type, mok, mok_size, &efi_guid_security, "dbx") || + is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListXRT")) + return 0; break; case DELETE_MOK: if (!is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListRT") || @@ -1111,111 +656,181 @@ return 0; } break; - case DELETE_BLACKLIST: - if (!is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListXRT") || - is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokXDel")) { - return 0; - } + case DELETE_BLACKLIST: + if (!is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokListXRT") || + is_duplicate (type, mok, mok_size, &efi_guid_shim, "MokXDel")) { + return 0; + } + break; + } + + return 1; +} + +static int +is_ca_in_db (const void *cert, const uint32_t cert_size, + const efi_guid_t *vendor, const char *db_name) +{ + uint8_t *var_data = NULL; + size_t var_data_size; + uint32_t attributes; + uint32_t node_num; + MokListNode *list; + int ret = 0; + + if (!cert || cert_size == 0 || !vendor || !db_name) + return 0; + + ret = efi_get_variable (*vendor, db_name, &var_data, &var_data_size, + &attributes); + if (ret < 0) + return 0; + + list = build_mok_list (var_data, var_data_size, &node_num); + if (list == NULL) { + goto done; + } + + for (unsigned int i = 0; i < node_num; i++) { + efi_guid_t sigtype = list[i].header->SignatureType; + if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0) + continue; + + if (is_immediate_ca (cert, cert_size, list[i].mok, + list[i].mok_size)) { + ret = 1; + break; + } + } + +done: + if (list) + free (list); + free (var_data); + + return ret; +} + +/* Check whether the CA cert is already enrolled */ +static int +is_ca_enrolled (const void *mok, const uint32_t mok_size, const MokRequest req) +{ + switch (req) { + case ENROLL_MOK: + if (is_ca_in_db (mok, mok_size, &efi_guid_shim, "MokListRT")) + return 1; + break; + case ENROLL_BLACKLIST: + if (is_ca_in_db (mok, mok_size, &efi_guid_shim, "MokListXRT")) + return 1; break; + default: + return 0; } - return 1; + return 0; } +/* Check whether the CA cert is blocked */ static int -in_pending_request (const efi_guid_t *type, void *data, uint32_t data_size, - MokRequest req) +is_ca_blocked (const void *mok, const uint32_t mok_size, const MokRequest req) { - uint8_t *authvar_data; - size_t authvar_data_size; - uint32_t attributes; - int ret; - - const char *authvar_names[] = { - [DELETE_MOK] = "MokDelAuth", - [ENROLL_MOK] = "MokAuth", - [DELETE_BLACKLIST] = "MokXDelAuth", - [ENROLL_BLACKLIST] = "MokXAuth" - }; - const char *var_names[] = { - [DELETE_MOK] = "MokDel", - [ENROLL_MOK] = "Mok", - [DELETE_BLACKLIST] = "MokXDel", - [ENROLL_BLACKLIST] = "MokX" - }; - - if (!data || data_size == 0) + switch (req) { + case ENROLL_MOK: + if (is_ca_in_db (mok, mok_size, &efi_guid_security, "dbx") || + is_ca_in_db (mok, mok_size, &efi_guid_shim, "MokListXRT")) + return 1; + break; + default: return 0; + } - if (efi_get_variable (efi_guid_shim, authvar_names[req], &authvar_data, - &authvar_data_size, &attributes) < 0) - return 0; + return 0; +} + +/* Check whether the key is already in the kernel trusted keyring */ +static int +is_in_trusted_keyring (const void *cert, const uint32_t cert_size) +{ + char *skid = NULL; + int ret; - free (authvar_data); - /* Check if the password hash is in the old format */ - if (authvar_data_size == SHA256_DIGEST_LENGTH) + if (get_cert_skid (cert, cert_size, &skid) < 0) return 0; - ret = delete_data_from_list (&efi_guid_shim, var_names[req], - type, data, data_size); + ret = match_skid_in_trusted_keyring (skid); if (ret < 0) - return -1; + ret = 0; + + free (skid); return ret; } +static int +in_reverse_pending_request (const efi_guid_t *type, const void *data, + uint32_t data_size, const MokRequest req) +{ + MokRequest reverse_req = get_reverse_req (req); + + if (!data || data_size == 0) + return 0; + + return delete_data_from_req_var (reverse_req, type, data, data_size); +} + static void -print_skip_message (const char *filename, void *mok, uint32_t mok_size, - MokRequest req) +print_skip_message (const char *filename, const void *mok, + const uint32_t mok_size, const MokRequest req) { switch (req) { case ENROLL_MOK: if (is_duplicate (&efi_guid_x509_cert, mok, mok_size, - &efi_guid_global, "PK")) - printf ("SKIP: %s is already in PK\n", filename); - else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size, - &efi_guid_global, "KEK")) - printf ("SKIP: %s is already in KEK\n", filename); - else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size, - &efi_guid_security, "db")) - printf ("SKIP: %s is already in db\n", filename); + &efi_guid_security, "db")) + printf ("%s is already in db\n", filename); else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size, &efi_guid_shim, "MokListRT")) - printf ("SKIP: %s is already enrolled\n", filename); + printf ("%s is already enrolled\n", filename); else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size, &efi_guid_shim, "MokNew")) - printf ("SKIP: %s is already in the enrollement request\n", filename); + printf ("%s is already in the enrollment request\n", filename); + else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size, + &efi_guid_security, "dbx")) + printf ("%s is blocked in dbx\n", filename); + else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size, + &efi_guid_shim, "MokListXRT")) + printf ("%s is blocked in MokListXRT\n", filename); break; case DELETE_MOK: if (!is_duplicate (&efi_guid_x509_cert, mok, mok_size, &efi_guid_shim, "MokListRT")) - printf ("SKIP: %s is not in MokList\n", filename); + printf ("%s is not in MokList\n", filename); else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size, &efi_guid_shim, "MokDel")) - printf ("SKIP: %s is already in the deletion request\n", filename); + printf ("%s is already in the deletion request\n", filename); break; case ENROLL_BLACKLIST: if (is_duplicate (&efi_guid_x509_cert, mok, mok_size, &efi_guid_shim, "MokListXRT")) - printf ("SKIP: %s is already in MokListX\n", filename); + printf ("%s is already in MokListX\n", filename); else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size, &efi_guid_shim, "MokXNew")) - printf ("SKIP: %s is already in the MokX enrollment request\n", filename); + printf ("%s is already in the MokX enrollment request\n", filename); break; case DELETE_BLACKLIST: if (!is_duplicate (&efi_guid_x509_cert, mok, mok_size, &efi_guid_shim, "MokListXRT")) - printf ("SKIP: %s is not in MokListX\n", filename); + printf ("%s is not in MokListX\n", filename); else if (is_duplicate (&efi_guid_x509_cert, mok, mok_size, &efi_guid_shim, "MokXDel")) - printf ("SKIP: %s is already in the MokX deletion request\n", filename); + printf ("%s is already in the MokX deletion request\n", filename); break; } } static int -issue_mok_request (char **files, uint32_t total, MokRequest req, - const char *hash_file, const int root_pw) +issue_mok_request (char **files, const uint32_t total, const MokRequest req, + const char *pw_hash_file, const int root_pw) { uint8_t *old_req_data = NULL; size_t old_req_data_size = 0; @@ -1231,18 +846,7 @@ int ret = -1; EFI_SIGNATURE_LIST *CertList; EFI_SIGNATURE_DATA *CertData; - const char *req_names[] = { - [DELETE_MOK] = "MokDel", - [ENROLL_MOK] = "MokNew", - [DELETE_BLACKLIST] = "MokXDel", - [ENROLL_BLACKLIST] = "MokXNew" - }; - const char *reverse_req_names[] = { - [DELETE_MOK] = "MokNew", - [ENROLL_MOK] = "MokDel", - [DELETE_BLACKLIST] = "MokXNew", - [ENROLL_BLACKLIST] = "MokXDel" - }; + const char *var_name = get_req_var_name (req); if (!files) return -1; @@ -1268,12 +872,12 @@ list_size += sizeof(EFI_SIGNATURE_LIST) * total; list_size += sizeof(efi_guid_t) * total; - ret = efi_get_variable (efi_guid_shim, req_names[req], &old_req_data, + ret = efi_get_variable (efi_guid_shim, var_name, &old_req_data, &old_req_data_size, &attributes); if (ret < 0) { if (errno != ENOENT) { fprintf (stderr, "Failed to read variable \"%s\": %m\n", - req_names[req]); + var_name); goto error; } } else { @@ -1284,7 +888,7 @@ new_list = malloc (list_size); if (!new_list) { fprintf (stderr, "Failed to allocate space for %s\n", - req_names[req]); + var_name); goto error; } ptr = new_list; @@ -1313,23 +917,53 @@ read_size = read (fd, ptr, sizes[i]); if (read_size < 0 || read_size != (int64_t)sizes[i]) { fprintf (stderr, "Failed to read %s\n", files[i]); + close (fd); goto error; } - if (!is_valid_cert (ptr, read_size)) { + + const void *mok = ptr; + const uint32_t mok_size = sizes[i]; + + if (!is_valid_cert (mok, mok_size)) { fprintf (stderr, "Abort!!! %s is not a valid x509 certificate in DER format\n", files[i]); + close (fd); goto error; } - if (is_valid_request (&efi_guid_x509_cert, ptr, sizes[i], req)) { - ptr += sizes[i]; - real_size += sizes[i] + sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t); - } else if (in_pending_request (&efi_guid_x509_cert, ptr, sizes[i], req)) { + /* Check whether the key is already in the trusted keyring */ + if (req == ENROLL_MOK && check_keyring && + is_in_trusted_keyring (mok, mok_size)) { + printf ("Already in kernel trusted keyring. Skip %s\n", + files[i]); + close (fd); + continue; + } + + /* Check whether CA is already enrolled */ + if (force_ca_check && is_ca_enrolled (mok, mok_size, req)) { + printf ("CA enrolled. Skip %s\n", files[i]); + close (fd); + continue; + } + + /* Check whether CA is blocked */ + if (force_ca_check && is_ca_blocked (mok, mok_size, req)) { + printf ("CA blocked. Skip %s\n", files[i]); + close (fd); + continue; + } + + if (is_valid_request (&efi_guid_x509_cert, mok, mok_size, req)) { + ptr += mok_size; + real_size += mok_size + sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t); + } else if (in_reverse_pending_request (&efi_guid_x509_cert, mok, mok_size, req)) { printf ("Removed %s from %s\n", files[i], - reverse_req_names[req]); + get_reverse_req_var_name (req)); ptr -= sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t); } else { - print_skip_message (files[i], ptr, sizes[i], req); + printf ("SKIP: "); + print_skip_message (files[i], mok, mok_size, req); ptr -= sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t); } @@ -1348,7 +982,7 @@ real_size += old_req_data_size; } - if (update_request (new_list, real_size, req, hash_file, root_pw) < 0) { + if (update_request (new_list, real_size, req, pw_hash_file, root_pw) < 0) { goto error; } @@ -1365,50 +999,7 @@ } static int -identify_hash_type (const char *hash_str, efi_guid_t *type) -{ - unsigned int len = strlen (hash_str); - int hash_size; - - for (unsigned int i = 0; i < len; i++) { - if ((hash_str[i] > '9' || hash_str[i] < '0') && - (hash_str[i] > 'f' || hash_str[i] < 'a') && - (hash_str[i] > 'F' || hash_str[i] < 'A')) - return -1; - } - - switch (len) { -#if 0 - case SHA_DIGEST_LENGTH*2: - *type = efi_guid_sha1; - hash_size = SHA_DIGEST_LENGTH; - break; -#endif - case SHA224_DIGEST_LENGTH*2: - *type = efi_guid_sha224; - hash_size = SHA224_DIGEST_LENGTH; - break; - case SHA256_DIGEST_LENGTH*2: - *type = efi_guid_sha256; - hash_size = SHA256_DIGEST_LENGTH; - break; - case SHA384_DIGEST_LENGTH*2: - *type = efi_guid_sha384; - hash_size = SHA384_DIGEST_LENGTH; - break; - case SHA512_DIGEST_LENGTH*2: - *type = efi_guid_sha512; - hash_size = SHA512_DIGEST_LENGTH; - break; - default: - return -1; - } - - return hash_size; -} - -static int -hex_str_to_binary (const char *hex_str, uint8_t *array, unsigned int len) +hex_str_to_binary (const char *hex_str, uint8_t *array, const unsigned int len) { char *pos; @@ -1425,14 +1016,12 @@ } static int -issue_hash_request (const char *hash_str, MokRequest req, - const char *hash_file, const int root_pw) +issue_hash_request (const char *hash_str, const MokRequest req, + const char *pw_hash_file, const int root_pw) { uint8_t *old_req_data = NULL; size_t old_req_data_size = 0; uint32_t attributes; - const char *req_name; - const char *reverse_req; void *new_list = NULL; void *ptr; unsigned long list_size = 0; @@ -1444,9 +1033,9 @@ uint8_t db_hash[SHA512_DIGEST_LENGTH]; int hash_size; int merge_ind = -1; - uint8_t valid = 0; MokListNode *mok_list = NULL; uint32_t mok_num; + const char *var_name = get_req_var_name (req); if (!hash_str) return -1; @@ -1458,48 +1047,24 @@ if (hex_str_to_binary (hash_str, db_hash, hash_size) < 0) return -1; - switch (req) { - case ENROLL_MOK: - req_name = "MokNew"; - reverse_req = "MokDel"; - break; - case DELETE_MOK: - req_name = "MokDel"; - reverse_req = "MokNew"; - break; - case ENROLL_BLACKLIST: - req_name = "MokXNew"; - reverse_req = "MokXDel"; - break; - case DELETE_BLACKLIST: - req_name = "MokXDel"; - reverse_req = "MokXNew"; - break; - default: - return -1; - } - - if (is_valid_request (&hash_type, db_hash, hash_size, req)) { - valid = 1; - } else if (in_pending_request (&hash_type, db_hash, hash_size, req)) { - printf ("Removed hash from %s\n", reverse_req); - } else { + if (is_valid_request (&hash_type, db_hash, hash_size, req) == 0) { printf ("Skip hash\n"); - } - - if (!valid) { + ret = 0; + goto error; + } else if (in_reverse_pending_request (&hash_type, db_hash, hash_size, req)) { + printf ("Removed hash from %s\n", get_reverse_req_var_name (req)); ret = 0; goto error; } list_size = sizeof(EFI_SIGNATURE_LIST) + sizeof(efi_guid_t) + hash_size; - ret = efi_get_variable (efi_guid_shim, req_name, &old_req_data, + ret = efi_get_variable (efi_guid_shim, var_name, &old_req_data, &old_req_data_size, &attributes); if (ret < 0) { if (errno != ENOENT) { fprintf (stderr, "Failed to read variable \"%s\": %m\n", - req_name); + var_name); goto error; } } else { @@ -1510,8 +1075,8 @@ goto error; /* Check if there is a signature list with the same type */ for (unsigned int i = 0; i < mok_num; i++) { - if (efi_guid_cmp (&mok_list[i].header->SignatureType, - &hash_type) == 0) { + efi_guid_t sigtype = mok_list[i].header->SignatureType; + if (efi_guid_cmp (&sigtype, &hash_type) == 0) { merge_ind = i; list_size -= sizeof(EFI_SIGNATURE_LIST); break; @@ -1523,7 +1088,7 @@ new_list = malloc (list_size); if (!new_list) { fprintf (stderr, "Failed to allocate space for %s: %m\n", - req_name); + var_name); goto error; } ptr = new_list; @@ -1577,7 +1142,7 @@ } } - if (update_request (new_list, list_size, req, hash_file, root_pw) < 0) { + if (update_request (new_list, list_size, req, pw_hash_file, root_pw) < 0) { goto error; } @@ -1594,34 +1159,12 @@ } static int -revoke_request (MokRequest req) +revoke_request (const MokRequest req) { - switch (req) { - case ENROLL_MOK: - if (test_and_delete_var ("MokNew") < 0) - return -1; - if (test_and_delete_var ("MokAuth") < 0) - return -1; - break; - case DELETE_MOK: - if (test_and_delete_var ("MokDel") < 0) - return -1; - if (test_and_delete_var ("MokDelAuth") < 0) - return -1; - break; - case ENROLL_BLACKLIST: - if (test_and_delete_var ("MokXNew") < 0) - return -1; - if (test_and_delete_var ("MokXAuth") < 0) - return -1; - break; - case DELETE_BLACKLIST: - if (test_and_delete_var ("MokXDel") < 0) - return -1; - if (test_and_delete_var ("MokXDelAuth") < 0) - return -1; - break; - } + if (test_and_delete_mok_var (get_req_var_name(req)) < 0) + return -1; + if (test_and_delete_mok_var (get_req_auth_var_name(req)) < 0) + return -1; return 0; } @@ -1629,6 +1172,7 @@ static int export_db_keys (const DBName db_name) { + const char *db_var_name; uint8_t *data = NULL; size_t data_size = 0; uint32_t attributes; @@ -1655,15 +1199,17 @@ break; }; - ret = efi_get_variable (guid, db_var_name[db_name], &data, &data_size, + db_var_name = get_db_var_name(db_name); + + ret = efi_get_variable (guid, db_var_name, &data, &data_size, &attributes); if (ret < 0) { if (errno == ENOENT) { - printf ("%s is empty\n", db_var_name[db_name]); + printf ("%s is empty\n", db_var_name); return 0; } - fprintf (stderr, "Failed to read %s: %m\n", db_var_name[db_name]); + fprintf (stderr, "Failed to read %s: %m\n", db_var_name); return -1; } ret = -1; @@ -1678,12 +1224,14 @@ for (unsigned i = 0; i < mok_num; i++) { off_t offset = 0; ssize_t write_size; + efi_guid_t sigtype = list[i].header->SignatureType; - if (efi_guid_cmp (&list[i].header->SignatureType, &efi_guid_x509_cert) != 0) + if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0) continue; /* Dump X509 certificate to files */ - snprintf (filename, PATH_MAX, "%s-%04d.der", db_friendly_name[db_name], i+1); + snprintf (filename, PATH_MAX, "%s-%04d.der", + get_db_friendly_name(db_name), i+1); fd = open (filename, O_CREAT | O_WRONLY, mode); if (fd < 0) { fprintf (stderr, "Failed to open %s: %m\n", filename); @@ -1714,22 +1262,18 @@ } static int -set_password (const char *hash_file, const int root_pw, const int clear) +set_password (const char *pw_hash_file, const int root_pw, const int clear) { - uint8_t *data; - size_t data_size; pw_crypt_t pw_crypt; - uint8_t auth[SHA256_DIGEST_LENGTH]; char *password = NULL; unsigned int pw_len; int auth_ret; int ret = -1; memset (&pw_crypt, 0, sizeof(pw_crypt_t)); - memset (auth, 0, SHA256_DIGEST_LENGTH); - if (hash_file) { - if (get_hash_from_file (hash_file, &pw_crypt) < 0) { + if (pw_hash_file) { + if (get_pw_hash_from_file (pw_hash_file, &pw_crypt) < 0) { fprintf (stderr, "Failed to read hash\n"); goto error; } @@ -1744,31 +1288,20 @@ goto error; } - if (!use_simple_hash) { - pw_crypt.method = DEFAULT_CRYPT_METHOD; - auth_ret = generate_hash (&pw_crypt, password, pw_len); - } else { - auth_ret = generate_auth (NULL, 0, password, pw_len, - auth); - } + pw_crypt.method = DEFAULT_CRYPT_METHOD; + auth_ret = generate_pw_crypt (&pw_crypt, password, pw_len); if (auth_ret < 0) { fprintf (stderr, "Couldn't generate hash\n"); goto error; } } - if (!use_simple_hash) { - data = (void *)&pw_crypt; - data_size = PASSWORD_CRYPT_SIZE; - } else { - data = (void *)auth; - data_size = SHA256_DIGEST_LENGTH; - } uint32_t attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; - ret = efi_set_variable (efi_guid_shim, "MokPW", data, data_size, - attributes, S_IRUSR | S_IWUSR); + ret = efi_set_variable (efi_guid_shim, "MokPW", (void *)&pw_crypt, + PASSWORD_CRYPT_SIZE, attributes, + S_IRUSR | S_IWUSR); if (ret < 0) { fprintf (stderr, "Failed to write MokPW: %m\n"); goto error; @@ -1782,7 +1315,7 @@ } static int -set_toggle (const char * VarName, uint32_t state) +set_toggle (const char * VarName, const uint32_t state) { uint32_t attributes; MokToggleVar tvar; @@ -1823,14 +1356,14 @@ return ret; } -static int -disable_validation() +static inline int +disable_validation(void) { return set_toggle("MokSB", 0); } -static int -enable_validation() +static inline int +enable_validation(void) { return set_toggle("MokSB", 1); } @@ -1838,7 +1371,7 @@ static int sb_state () { - uint8_t *data; + uint8_t *data = NULL; size_t data_size; uint32_t attributes; int32_t secureboot = -1; @@ -1856,17 +1389,16 @@ printf ("Strange data size %zd for \"SecureBoot\" variable\n", data_size); } - if (data_size == 4) { - secureboot = (int32_t)*(uint32_t *)data; - } else if (data_size == 2) { - secureboot = (int32_t)*(uint16_t *)data; - } else if (data_size == 1) { - secureboot = (int32_t)*(uint8_t *)data; + if (data_size == 4 || data_size == 2 || data_size == 1) { + secureboot = 0; + memcpy(&secureboot, data, data_size); } + free (data); + data = NULL; if (efi_get_variable (efi_guid_global, "SetupMode", &data, &data_size, &attributes) < 0) { - fprintf (stderr, "Failed to read \"SecureBoot\" " + fprintf (stderr, "Failed to read \"SetupMode\" " "variable: %m\n"); return -1; } @@ -1875,17 +1407,17 @@ printf ("Strange data size %zd for \"SetupMode\" variable\n", data_size); } - if (data_size == 4) { - setupmode = (int32_t)*(uint32_t *)data; - } else if (data_size == 2) { - setupmode = (int32_t)*(uint16_t *)data; - } else if (data_size == 1) { - setupmode = (int32_t)*(uint8_t *)data; + if (data_size == 4 || data_size == 2 || data_size == 1) { + setupmode = 0; + memcpy(&setupmode, data, data_size); } + free (data); + data = NULL; if (efi_get_variable (efi_guid_shim, "MokSBStateRT", &data, &data_size, &attributes) >= 0) { moksbstate = 1; + free (data); } if (secureboot == 1 && setupmode == 0) { @@ -1900,25 +1432,36 @@ printf ("Cannot determine secure boot state.\n"); } - free (data); - return 0; } -static int -disable_db() +static inline int +disable_db(void) { return set_toggle("MokDB", 0); } -static int -enable_db() +static inline int +enable_db(void) { return set_toggle("MokDB", 1); } +static int +trust_mok_keys() +{ + return set_toggle("MokListTrustedNew", 0); +} + +static int +untrust_mok_keys() +{ + return set_toggle("MokListTrustedNew", 1); +} + static inline int -read_file(int fd, void **bufp, size_t *lenptr) { +read_file(const int fd, void **bufp, size_t *lenptr) +{ int alloced = 0, size = 0, i = 0; void *buf = NULL; void *buf_new = NULL; @@ -1950,7 +1493,7 @@ } static int -test_key (MokRequest req, const char *key_file) +test_key (const MokRequest req, const char *key_file) { void *key = NULL; size_t read_size; @@ -1968,11 +1511,34 @@ goto error; } + if (!is_valid_cert (key, read_size)) { + fprintf (stderr, "Not a valid x509 certificate\n"); + goto error; + } + + if (check_keyring && is_in_trusted_keyring (key, read_size)) { + fprintf (stderr, "%s is already in the built-in trusted keyring\n", + key_file); + goto error; + } + + if (force_ca_check && is_ca_enrolled (key, read_size, req)) { + fprintf (stderr, "CA of %s is already enrolled\n", + key_file); + goto error; + } + + if (force_ca_check && is_ca_blocked (key, read_size, req)) { + fprintf (stderr, "CA of %s is blocked\n", + key_file); + goto error; + } + if (is_valid_request (&efi_guid_x509_cert, key, read_size, req)) { printf ("%s is not enrolled\n", key_file); ret = 0; } else { - printf ("%s is already enrolled\n", key_file); + print_skip_message (key_file, key, read_size, req); ret = 1; } @@ -1987,9 +1553,9 @@ } static int -reset_moks (MokRequest req, const char *hash_file, const int root_pw) +reset_moks (const MokRequest req, const char *pw_hash_file, const int root_pw) { - if (update_request (NULL, 0, req, hash_file, root_pw)) { + if (update_request (NULL, 0, req, pw_hash_file, root_pw)) { fprintf (stderr, "Failed to issue a reset request\n"); return -1; } @@ -2005,7 +1571,7 @@ char *password = NULL; char *crypt_string; const char *prefix; - int settings_len = sizeof (settings) - 2; + size_t settings_len = sizeof (settings) - 2; unsigned int pw_len, salt_size; if (input_pw) { @@ -2034,13 +1600,13 @@ memset (settings, 0, sizeof (settings)); next = stpncpy (settings, prefix, settings_len); - salt_size = get_salt_size (DEFAULT_CRYPT_METHOD); + salt_size = get_pw_salt_size (DEFAULT_CRYPT_METHOD); if (salt_size > settings_len - (next - settings)) { free(password); errno = EOVERFLOW; return -1; } - generate_salt (next, salt_size); + generate_pw_salt (next, salt_size); next += salt_size; *next = '\0'; @@ -2057,7 +1623,7 @@ } static int -set_timeout (char *t) +set_timeout (const char *t) { int timeout = strtol(t, NULL, 10); @@ -2077,14 +1643,39 @@ return -1; } } else { - return test_and_delete_var ("MokTimeout"); + return test_and_delete_mok_var ("MokTimeout"); } return 0; } static int -set_verbosity (uint8_t verbosity) +print_var_content (const char *var_name, const efi_guid_t guid) +{ + uint8_t *data = NULL; + size_t data_size; + uint32_t attributes; + int ret; + + ret = efi_get_variable (guid, var_name, &data, &data_size, &attributes); + if (ret < 0) { + if (errno == ENOENT) { + printf ("%s is empty\n", var_name); + return 0; + } + + fprintf (stderr, "Failed to read %s: %m\n", var_name); + return -1; + } + + printf ("%s", data); + free (data); + + return ret; +} + +static int +set_verbosity (const uint8_t verbosity) { if (verbosity) { uint32_t attributes = EFI_VARIABLE_NON_VOLATILE @@ -2097,14 +1688,54 @@ return -1; } } else { - return test_and_delete_var ("SHIM_VERBOSE"); + return test_and_delete_mok_var ("SHIM_VERBOSE"); + } + + return 0; +} + +static int +set_fallback_verbosity (const uint8_t verbosity) +{ + if (verbosity) { + uint32_t attributes = EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS; + if (efi_set_variable (efi_guid_shim, "FALLBACK_VERBOSE", + (uint8_t *)&verbosity, sizeof (verbosity), + attributes, S_IRUSR | S_IWUSR) < 0) { + fprintf (stderr, "Failed to set FALLBACK_VERBOSE\n"); + return -1; + } + } else { + return test_and_delete_mok_var ("FALLBACK_VERBOSE"); + } + + return 0; +} + +static int +set_fallback_noreboot (const uint8_t noreboot) +{ + if (noreboot) { + uint32_t attributes = EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS; + if (efi_set_variable (efi_guid_shim, "FB_NO_REBOOT", + (uint8_t *)&noreboot, sizeof (noreboot), + attributes, S_IRUSR | S_IWUSR) < 0) { + fprintf (stderr, "Failed to set FB_NO_REBOOT\n"); + return -1; + } + } else { + return test_and_delete_mok_var ("FB_NO_REBOOT"); } return 0; } static inline int -list_db (DBName db_name) +list_db (const DBName db_name) { switch (db_name) { case MOK_LIST_RT: @@ -2124,12 +1755,32 @@ return -1; } +static int +manage_sbat (const uint8_t sbat_policy) +{ + if (sbat_policy) { + uint32_t attributes = EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS; + if (efi_set_variable (efi_guid_shim, "SbatPolicy", + (uint8_t *)&sbat_policy, + sizeof (sbat_policy), + attributes, S_IRUSR | S_IWUSR) < 0) { + fprintf (stderr, "Failed to set SbatPolicy\n"); + return -1; + } + } else { + return test_and_delete_mok_var ("SbatPolicy"); + } + return 0; +} + int main (int argc, char *argv[]) { char **files = NULL; char *key_file = NULL; - char *hash_file = NULL; + char *pw_hash_file = NULL; char *input_pw = NULL; char *hash_str = NULL; char *timeout = NULL; @@ -2138,10 +1789,15 @@ unsigned int command = 0; int use_root_pw = 0; uint8_t verbosity = 0; + uint8_t fb_verbosity = 0; + uint8_t fb_noreboot = 0; + uint8_t sbat_policy = 0; DBName db_name = MOK_LIST_RT; int ret = -1; + int sb_check; - use_simple_hash = 0; + force_ca_check = 0; + check_keyring = 1; if (!efi_variables_supported ()) { fprintf (stderr, "EFI variables are not supported on this system\n"); @@ -2169,7 +1825,6 @@ {"hash-file", required_argument, 0, 'f'}, {"generate-hash", optional_argument, 0, 'g'}, {"root-pw", no_argument, 0, 'P'}, - {"simple-hash", no_argument, 0, 's'}, {"ignore-db", no_argument, 0, 0 }, {"use-db", no_argument, 0, 0 }, {"mok", no_argument, 0, 'm'}, @@ -2177,16 +1832,26 @@ {"import-hash", required_argument, 0, 0 }, {"delete-hash", required_argument, 0, 0 }, {"set-verbosity", required_argument, 0, 0 }, + {"set-fallback-verbosity", required_argument, 0, 0 }, + {"set-fallback-noreboot", required_argument, 0, 0 }, + {"trust-mok", no_argument, 0, 0 }, + {"untrust-mok", no_argument, 0, 0 }, + {"set-sbat-policy", required_argument, 0, 0 }, {"pk", no_argument, 0, 0 }, {"kek", no_argument, 0, 0 }, {"db", no_argument, 0, 0 }, {"dbx", no_argument, 0, 0 }, + {"list-sbat-revocations", no_argument, 0, 0 }, + {"sbat", no_argument, 0, 0 }, {"timeout", required_argument, 0, 0 }, + {"ca-check", no_argument, 0, 0 }, + {"ignore-keyring", no_argument, 0, 0 }, + {"version", no_argument, 0, 'v'}, {0, 0, 0, 0} }; int option_index = 0; - c = getopt_long (argc, argv, "cd:f:g::hi:lmpst:xDNPX", + c = getopt_long (argc, argv, "cd:f:g::hi:lmpst:xDNPXv", long_options, &option_index); if (c == -1) @@ -2211,6 +1876,10 @@ command |= IGNORE_DB; } else if (strcmp (option, "use-db") == 0) { command |= USE_DB; + } else if (strcmp (option, "trust-mok") == 0) { + command |= TRUST_MOK; + } else if (strcmp (option, "untrust-mok") == 0) { + command |= UNTRUST_MOK; } else if (strcmp (option, "import-hash") == 0) { command |= IMPORT_HASH; if (hash_str) { @@ -2241,6 +1910,32 @@ verbosity = 0; else command |= HELP; + } else if (strcmp (option, "set-fallback-verbosity") == 0) { + command |= FB_VERBOSITY; + if (strcmp (optarg, "true") == 0) + fb_verbosity = 1; + else if (strcmp (optarg, "false") == 0) + fb_verbosity = 0; + else + command |= HELP; + } else if (strcmp (option, "set-fallback-noreboot") == 0) { + command |= FB_NOREBOOT; + if (strcmp (optarg, "true") == 0) + fb_noreboot = 1; + else if (strcmp (optarg, "false") == 0) + fb_noreboot = 0; + else + command |= HELP; + } else if (strcmp (option, "set-sbat-policy") == 0) { + command |= SET_SBAT; + if (strcmp (optarg, "latest") == 0) + sbat_policy = 1; + else if (strcmp (optarg, "previous") == 0) + sbat_policy = 2; + else if (strcmp (optarg, "delete") == 0) + sbat_policy = 3; + else + command |= HELP; } else if (strcmp (option, "pk") == 0) { if (db_name != MOK_LIST_RT) { command |= HELP; @@ -2265,9 +1960,17 @@ } else { db_name = DBX; } + } else if (strcmp (option, "list-sbat-revocations") == 0) { + command |= LIST_SBAT; + } else if (strcmp (option, "sbat") == 0) { + command |= LIST_SBAT; } else if (strcmp (option, "timeout") == 0) { command |= TIMEOUT; timeout = strdup (optarg); + } else if (strcmp (option, "ca-check") == 0) { + force_ca_check = 1; + } else if (strcmp (option, "ignore-keyring") == 0) { + check_keyring = 0; } break; @@ -2317,12 +2020,12 @@ break; case 'f': - if (hash_file) { + if (pw_hash_file) { command |= HELP; break; } - hash_file = strdup (optarg); - if (hash_file == NULL) { + pw_hash_file = strdup (optarg); + if (pw_hash_file == NULL) { fprintf (stderr, "Could not allocate space: %m\n"); exit(1); } @@ -2368,10 +2071,6 @@ case 'x': command |= EXPORT; break; - case 's': - command |= SIMPLE_HASH; - use_simple_hash = 1; - break; case 'm': db_name = MOK_LIST_RT; break; @@ -2383,6 +2082,9 @@ db_name = MOK_LIST_X_RT; } break; + case 'v': + printf ("%s\n", VERSION); + goto out; case 'h': case '?': command |= HELP; @@ -2392,19 +2094,19 @@ } } - if (use_root_pw == 1 && use_simple_hash == 1) - use_simple_hash = 0; - - if (hash_file && use_root_pw) + if (pw_hash_file && use_root_pw) command |= HELP; if (db_name != MOK_LIST_RT && !(command & ~MOKX)) command |= LIST_ENROLLED; - if (!(command & HELP)) { + sb_check = !(command & HELP || command & TEST_KEY || + command & VERBOSITY || command & TIMEOUT || + command & FB_VERBOSITY || command & FB_NOREBOOT); + if (sb_check) { /* Check whether the machine supports Secure Boot or not */ int rc; - uint8_t *data; + uint8_t *data = NULL; size_t data_size; uint32_t attributes; @@ -2430,24 +2132,20 @@ ret = list_keys_in_var ("MokDel", efi_guid_shim); break; case IMPORT: - case IMPORT | SIMPLE_HASH: ret = issue_mok_request (files, total, ENROLL_MOK, - hash_file, use_root_pw); + pw_hash_file, use_root_pw); break; case DELETE: - case DELETE | SIMPLE_HASH: ret = issue_mok_request (files, total, DELETE_MOK, - hash_file, use_root_pw); + pw_hash_file, use_root_pw); break; case IMPORT_HASH: - case IMPORT_HASH | SIMPLE_HASH: ret = issue_hash_request (hash_str, ENROLL_MOK, - hash_file, use_root_pw); + pw_hash_file, use_root_pw); break; case DELETE_HASH: - case DELETE_HASH | SIMPLE_HASH: ret = issue_hash_request (hash_str, DELETE_MOK, - hash_file, use_root_pw); + pw_hash_file, use_root_pw); break; case REVOKE_IMPORT: ret = revoke_request (ENROLL_MOK); @@ -2460,11 +2158,9 @@ ret = export_db_keys (db_name); break; case PASSWORD: - case PASSWORD | SIMPLE_HASH: - ret = set_password (hash_file, use_root_pw, 0); + ret = set_password (pw_hash_file, use_root_pw, 0); break; case CLEAR_PASSWORD: - case CLEAR_PASSWORD | SIMPLE_HASH: ret = set_password (NULL, 0, 1); break; case DISABLE_VALIDATION: @@ -2480,8 +2176,7 @@ ret = test_key (ENROLL_MOK, key_file); break; case RESET: - case RESET | SIMPLE_HASH: - ret = reset_moks (ENROLL_MOK, hash_file, use_root_pw); + ret = reset_moks (ENROLL_MOK, pw_hash_file, use_root_pw); break; case GENERATE_PW_HASH: ret = generate_pw_hash (input_pw); @@ -2492,6 +2187,12 @@ case USE_DB: ret = enable_db (); break; + case TRUST_MOK: + ret = trust_mok_keys (); + break; + case UNTRUST_MOK: + ret = untrust_mok_keys (); + break; case LIST_NEW | MOKX: ret = list_keys_in_var ("MokXNew", efi_guid_shim); break; @@ -2499,24 +2200,20 @@ ret = list_keys_in_var ("MokXDel", efi_guid_shim); break; case IMPORT | MOKX: - case IMPORT | SIMPLE_HASH | MOKX: ret = issue_mok_request (files, total, ENROLL_BLACKLIST, - hash_file, use_root_pw); + pw_hash_file, use_root_pw); break; case DELETE | MOKX: - case DELETE | SIMPLE_HASH | MOKX: ret = issue_mok_request (files, total, DELETE_BLACKLIST, - hash_file, use_root_pw); + pw_hash_file, use_root_pw); break; case IMPORT_HASH | MOKX: - case IMPORT_HASH | SIMPLE_HASH | MOKX: ret = issue_hash_request (hash_str, ENROLL_BLACKLIST, - hash_file, use_root_pw); + pw_hash_file, use_root_pw); break; case DELETE_HASH | MOKX: - case DELETE_HASH | SIMPLE_HASH | MOKX: ret = issue_hash_request (hash_str, DELETE_BLACKLIST, - hash_file, use_root_pw); + pw_hash_file, use_root_pw); break; case REVOKE_IMPORT | MOKX: ret = revoke_request (ENROLL_BLACKLIST); @@ -2525,8 +2222,7 @@ ret = revoke_request (DELETE_BLACKLIST); break; case RESET | MOKX: - case RESET | SIMPLE_HASH | MOKX: - ret = reset_moks (ENROLL_BLACKLIST, hash_file, use_root_pw); + ret = reset_moks (ENROLL_BLACKLIST, pw_hash_file, use_root_pw); break; case TEST_KEY | MOKX: ret = test_key (ENROLL_BLACKLIST, key_file); @@ -2534,9 +2230,21 @@ case VERBOSITY: ret = set_verbosity (verbosity); break; + case FB_VERBOSITY: + ret = set_fallback_verbosity (fb_verbosity); + break; + case FB_NOREBOOT: + ret = set_fallback_noreboot (fb_noreboot); + break; case TIMEOUT: ret = set_timeout (timeout); break; + case LIST_SBAT: + ret = print_var_content ("SbatLevelRT", efi_guid_shim); + break; + case SET_SBAT: + ret = manage_sbat(sbat_policy); + break; default: print_help (); break; @@ -2555,8 +2263,8 @@ if (key_file) free (key_file); - if (hash_file) - free (hash_file); + if (pw_hash_file) + free (pw_hash_file); if (input_pw) free (input_pw); diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/mokutil.h mokutil-0.6.0/src/mokutil.h --- mokutil-0.3.0+1538710437.fb6250f/src/mokutil.h 1970-01-01 00:00:00.000000000 +0000 +++ mokutil-0.6.0/src/mokutil.h 2022-05-07 07:02:34.000000000 +0000 @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2020 Gary Lin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef __MOKUTIL_H__ +#define __MOKUTIL_H__ + +#include +#include + +#include "signature.h" + +typedef unsigned long efi_status_t; +typedef uint8_t efi_bool_t; +typedef wchar_t efi_char16_t; /* UNICODE character */ + +typedef enum { + DELETE_MOK = 0, + ENROLL_MOK, + DELETE_BLACKLIST, + ENROLL_BLACKLIST, +} MokRequest; + +typedef enum { + MOK_LIST_RT = 0, + MOK_LIST_X_RT, + PK, + KEK, + DB, + DBX, +} DBName; + +typedef struct { + EFI_SIGNATURE_LIST *header; + uint32_t mok_size; + void *mok; +} MokListNode; + +#endif /* __MOKUTIL_H__ */ diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/password-crypt.c mokutil-0.6.0/src/password-crypt.c --- mokutil-0.3.0+1538710437.fb6250f/src/password-crypt.c 2018-10-05 03:33:57.000000000 +0000 +++ mokutil-0.6.0/src/password-crypt.c 2022-05-07 07:02:34.000000000 +0000 @@ -79,7 +79,7 @@ } uint16_t -get_salt_size (int method) { +get_pw_salt_size (const HashMethod method) { switch (method) { case TRADITIONAL_DES: return T_DES_SALT_MAX; @@ -98,7 +98,7 @@ } int -get_hash_size (int method) +get_pw_hash_size (const HashMethod method) { switch (method) { case TRADITIONAL_DES: @@ -119,7 +119,7 @@ } const char * -get_crypt_prefix (int method) +get_crypt_prefix (const HashMethod method) { switch (method) { case TRADITIONAL_DES: @@ -405,7 +405,8 @@ return 0; } -int restore_md5_array (const char *string, uint8_t *hash) +static int +restore_md5_array (const char *string, uint8_t *hash) { uint32_t tmp = 0; int value1, value2; @@ -440,7 +441,7 @@ return 0; } -int +static int restore_sha256_array (const char *string, uint8_t *hash) { uint32_t tmp = 0; @@ -483,7 +484,7 @@ return 0; } -int +static int restore_sha512_array (const char *string, uint8_t *hash) { uint32_t tmp = 0; diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/password-crypt.h mokutil-0.6.0/src/password-crypt.h --- mokutil-0.3.0+1538710437.fb6250f/src/password-crypt.h 2018-10-05 03:33:57.000000000 +0000 +++ mokutil-0.6.0/src/password-crypt.h 2022-05-07 07:02:34.000000000 +0000 @@ -41,14 +41,14 @@ #define SHA512_SALT_MAX 16 #define BLOWFISH_SALT_MAX 22 -enum HashMethod { +typedef enum { TRADITIONAL_DES = 0, EXTEND_BSDI_DES, MD5_BASED, SHA256_BASED, SHA512_BASED, BLOWFISH_BASED -}; +} HashMethod; typedef struct { uint16_t method; @@ -64,9 +64,9 @@ #define SHA256_B64_LENGTH 43 #define SHA512_B64_LENGTH 86 -uint16_t get_salt_size (int method); -int get_hash_size (int method); -const char *get_crypt_prefix (int method); +uint16_t get_pw_salt_size (const HashMethod method); +int get_pw_hash_size (const HashMethod method); +const char *get_crypt_prefix (const HashMethod method); int decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt); char int_to_b64 (const int i); int b64_to_int (const char c); diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/util.c mokutil-0.6.0/src/util.c --- mokutil-0.3.0+1538710437.fb6250f/src/util.c 1970-01-01 00:00:00.000000000 +0000 +++ mokutil-0.6.0/src/util.c 2022-05-07 07:02:34.000000000 +0000 @@ -0,0 +1,456 @@ +/** + * Copyright (C) 2020 Gary Lin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#include +#include +#include + +#include "efi_hash.h" +#include "util.h" + +int +mok_get_variable(const char *name, uint8_t **datap, size_t *data_sizep) +{ + char filename[] = "/sys/firmware/efi/mok-variables/implausibly-long-mok-variable-name"; + size_t filename_sz = sizeof(filename); + int fd, rc; + struct stat sb = { 0, }; + uint8_t *buf; + size_t bufsz, pos = 0; + ssize_t ssz; + + *datap = 0; + *data_sizep = 0; + + snprintf(filename, filename_sz, "/sys/firmware/efi/mok-variables/%s", name); + + fd = open(filename, O_RDONLY); + if (fd < 0) + return fd; + + rc = fstat(fd, &sb); + if (rc < 0) { +err_close: + close(fd); + return rc; + } + + if (sb.st_size == 0) { + errno = ENOENT; + rc = -1; + goto err_close; + } + + bufsz = sb.st_size; + buf = calloc(1, bufsz); + if (!buf) + goto err_close; + + while (pos < bufsz) { + ssz = read(fd, &buf[pos], bufsz - pos); + if (ssz < 0) { + if (errno == EAGAIN || + errno == EWOULDBLOCK || + errno == EINTR) + continue; + free(buf); + goto err_close; + } + + pos += ssz; + } + *datap = buf; + *data_sizep = pos; + + return 0; +} + +MokListNode* +build_mok_list (const void *data, const uintptr_t data_size, + uint32_t *mok_num) +{ + MokListNode *list = NULL; + MokListNode *list_new = NULL; + EFI_SIGNATURE_LIST *CertList = (void *)data; + EFI_SIGNATURE_DATA *Cert; + unsigned long dbsize = data_size; + unsigned long count = 0; + const void *end = data + data_size; + + while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) { + if ((void *)(CertList + 1) > end || + CertList->SignatureListSize == 0 || + CertList->SignatureListSize <= CertList->SignatureSize) { + fprintf (stderr, "Corrupted signature list\n"); + if (list) + free (list); + return NULL; + } + + efi_guid_t sigtype = CertList->SignatureType; + + if ((efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0) && + (efi_guid_cmp (&sigtype, &efi_guid_sha1) != 0) && + (efi_guid_cmp (&sigtype, &efi_guid_sha224) != 0) && + (efi_guid_cmp (&sigtype, &efi_guid_sha256) != 0) && + (efi_guid_cmp (&sigtype, &efi_guid_sha384) != 0) && + (efi_guid_cmp (&sigtype, &efi_guid_sha512) != 0)) { + dbsize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList + + CertList->SignatureListSize); + continue; + } + + if ((efi_guid_cmp (&sigtype, &efi_guid_x509_cert) != 0) && + (CertList->SignatureSize != signature_size (&sigtype))) { + dbsize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *)((uint8_t *) CertList + + CertList->SignatureListSize); + continue; + } + + Cert = (EFI_SIGNATURE_DATA *) (((uint8_t *) CertList) + + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + + if ((void *)(Cert + 1) > end || + CertList->SignatureSize <= sizeof(efi_guid_t)) { + if (list) + free (list); + fprintf (stderr, "Corrupted signature\n"); + return NULL; + } + + list_new = realloc(list, sizeof(MokListNode) * (count + 1)); + if (list_new) { + list = list_new; + } else { + if (list) + free (list); + fprintf(stderr, "Unable to allocate MOK list\n"); + return NULL; + } + + list[count].header = CertList; + if (efi_guid_cmp (&sigtype, &efi_guid_x509_cert) == 0) { + /* X509 certificate */ + list[count].mok_size = CertList->SignatureSize - + sizeof(efi_guid_t); + list[count].mok = (void *)Cert->SignatureData; + } else { + /* hash array */ + list[count].mok_size = CertList->SignatureListSize - + sizeof(EFI_SIGNATURE_LIST) - + CertList->SignatureHeaderSize; + list[count].mok = (void *)Cert; + } + + if (list[count].mok_size > (unsigned long)end - + (unsigned long)list[count].mok) { + fprintf (stderr, "Corrupted data\n"); + free (list); + return NULL; + } + + count++; + dbsize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((uint8_t *) CertList + + CertList->SignatureListSize); + } + + *mok_num = count; + + return list; +} + +int +test_and_delete_mok_var (const char *var_name) +{ + size_t size; + int ret; + + ret = efi_get_variable_size (efi_guid_shim, var_name, &size); + if (ret < 0) { + if (errno == ENOENT) + return 0; + fprintf (stderr, "Failed to access variable \"%s\": %m\n", + var_name); + } + + /* Attempt to delete it no matter what, problem efi_get_variable_size() + * had, unless it just doesn't exist anyway. */ + if (!(ret < 0 && errno == ENOENT)) { + if (efi_del_variable (efi_guid_shim, var_name) < 0) + fprintf (stderr, "Failed to unset \"%s\": %m\n", var_name); + } + + return ret; +} + +int +delete_data_from_req_var (const MokRequest req, const efi_guid_t *type, + const void *data, const uint32_t data_size) +{ + const efi_guid_t *var_guid = &efi_guid_shim; + const char *var_name = get_req_var_name (req); + const char *authvar_name = get_req_auth_var_name (req); + uint8_t *var_data = NULL; + size_t var_data_size = 0; + uint32_t attributes; + MokListNode *list; + uint32_t mok_num, total, remain; + void *end, *start = NULL; + int del_ind, ret = 0; + uint32_t sig_list_size, sig_size; + + if (!var_name || !data || data_size == 0) + return 0; + + ret = efi_get_variable (*var_guid, var_name, &var_data, &var_data_size, + &attributes); + if (ret < 0) { + if (errno == ENOENT) + return 0; + fprintf (stderr, "Failed to read variable \"%s\": %m\n", + var_name); + return -1; + } + + total = var_data_size; + + list = build_mok_list (var_data, var_data_size, &mok_num); + if (list == NULL) + goto done; + + remain = total; + for (unsigned int i = 0; i < mok_num; i++) { + remain -= list[i].header->SignatureListSize; + efi_guid_t sigtype = list[i].header->SignatureType; + if (efi_guid_cmp (&sigtype, type) != 0) + continue; + + sig_list_size = list[i].header->SignatureListSize; + + if (efi_guid_cmp (type, &efi_guid_x509_cert) == 0) { + if (list[i].mok_size != data_size) + continue; + + if (memcmp (list[i].mok, data, data_size) == 0) { + /* Remove this key */ + start = (void *)list[i].header; + end = start + sig_list_size; + total -= sig_list_size; + break; + } + } else { + del_ind = match_hash_array (type, data, list[i].mok, + list[i].mok_size); + if (del_ind < 0) + continue; + + start = (void *)list[i].header; + sig_size = signature_size (type); + if (sig_list_size == (sizeof(EFI_SIGNATURE_LIST) + sig_size)) { + /* Only one hash in the list */ + end = start + sig_list_size; + total -= sig_list_size; + } else { + /* More than one hash in the list */ + start += sizeof(EFI_SIGNATURE_LIST) + sig_size * del_ind; + end = start + sig_size; + total -= sig_size; + list[i].header->SignatureListSize -= sig_size; + remain += sig_list_size - sizeof(EFI_SIGNATURE_LIST) - + (del_ind + 1) * sig_size; + } + break; + } + } + + /* the key or hash is not in this list */ + if (start == NULL) + return 0; + + /* all keys are removed */ + if (total == 0) { + if (test_and_delete_mok_var (var_name) != 0) + goto done; + if (test_and_delete_mok_var (authvar_name) != 0) + goto done; + ret = 1; + goto done; + } + + /* remove the key or hash */ + if (remain > 0) + memmove (start, end, remain); + + attributes = EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS; + ret = efi_set_variable (*var_guid, var_name, + var_data, total, attributes, + S_IRUSR | S_IWUSR); + if (ret < 0) { + fprintf (stderr, "Failed to write variable \"%s\": %m\n", + var_name); + goto done; + } + efi_chmod_variable(*var_guid, var_name, S_IRUSR | S_IWUSR); + + ret = 1; +done: + if (list) + free (list); + free (var_data); + + return ret; +} + +unsigned long +efichar_from_char (efi_char16_t *dest, const char *src, size_t dest_len) +{ + unsigned int i, src_len = strlen(src); + for (i=0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) { + dest[i] = src[i]; + } + dest[i] = 0; + return i * sizeof(*dest); +} + +int +read_hidden_line (char **line, size_t *n) +{ + struct termios old, new; + int nread; + int isTTY = isatty(fileno (stdin)); + + if (isTTY) { + /* Turn echoing off and fail if we can't. */ + if (tcgetattr (fileno (stdin), &old) != 0) + return -1; + + new = old; + new.c_lflag &= ~ECHO; + + if (tcsetattr (fileno (stdin), TCSAFLUSH, &new) != 0) + return -1; + } + + /* Read the password. */ + nread = getline (line, n, stdin); + + if (isTTY) { + /* Restore terminal. */ + (void) tcsetattr (fileno (stdin), TCSAFLUSH, &old); + } + + /* Remove the newline */ + (*line)[nread-1] = '\0'; + + return nread-1; +} + +const char * +get_db_var_name (const DBName db_name) +{ + const char *db_var_names[] = { + [MOK_LIST_RT] = "MokListRT", + [MOK_LIST_X_RT] = "MokListXRT", + [PK] = "PK", + [KEK] = "KEK", + [DB] = "db", + [DBX] = "dbx", + }; + + return db_var_names[db_name]; +} + +const char * +get_db_friendly_name (const DBName db_name) +{ + const char *db_friendly_names[] = { + [MOK_LIST_RT] = "MOK", + [MOK_LIST_X_RT] = "MOKX", + [PK] = "PK", + [KEK] = "KEK", + [DB] = "DB", + [DBX] = "DBX", + }; + + return db_friendly_names[db_name]; +} + +const char * +get_req_var_name (const MokRequest req) +{ + const char *var_names[] = { + [DELETE_MOK] = "MokDel", + [ENROLL_MOK] = "MokNew", + [DELETE_BLACKLIST] = "MokXDel", + [ENROLL_BLACKLIST] = "MokXNew" + }; + + return var_names[req]; +} + +const char * +get_req_auth_var_name (const MokRequest req) +{ + const char *auth_var_names[] = { + [DELETE_MOK] = "MokDelAuth", + [ENROLL_MOK] = "MokAuth", + [DELETE_BLACKLIST] = "MokXDelAuth", + [ENROLL_BLACKLIST] = "MokXAuth" + }; + + return auth_var_names[req]; +} + +MokRequest +get_reverse_req (const MokRequest req) +{ + const MokRequest reverse_reqs[] = { + [DELETE_MOK] = ENROLL_MOK, + [ENROLL_MOK] = DELETE_MOK, + [DELETE_BLACKLIST] = ENROLL_BLACKLIST, + [ENROLL_BLACKLIST] = DELETE_BLACKLIST, + }; + + return reverse_reqs[req]; +} + +const char * +get_reverse_req_var_name (const MokRequest req) +{ + const MokRequest reverse_req = get_reverse_req (req); + + return get_req_var_name (reverse_req); +} diff -Nru mokutil-0.3.0+1538710437.fb6250f/src/util.h mokutil-0.6.0/src/util.h --- mokutil-0.3.0+1538710437.fb6250f/src/util.h 1970-01-01 00:00:00.000000000 +0000 +++ mokutil-0.6.0/src/util.h 2022-05-07 07:02:34.000000000 +0000 @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2020 Gary Lin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ + +#ifndef __UTIL_H__ +#define __UTIL_H__ + +#include +#include "mokutil.h" + +#include +#include +#include + +int mok_get_variable(const char *name, uint8_t **datap, size_t *data_sizep); +MokListNode *build_mok_list (const void *data, const uintptr_t data_size, + uint32_t *mok_num); +int test_and_delete_mok_var (const char *var_name); +int delete_data_from_req_var (const MokRequest req, const efi_guid_t *type, + const void *data, const uint32_t data_size); +unsigned long efichar_from_char (efi_char16_t *dest, const char *src, + size_t dest_len); +int read_hidden_line (char **line, size_t *n); +const char *get_db_var_name (const DBName db); +const char *get_db_friendly_name (const DBName db); +const char *get_req_var_name (const MokRequest req); +const char *get_req_auth_var_name (const MokRequest req); +MokRequest get_reverse_req (const MokRequest req); +const char *get_reverse_req_var_name (const MokRequest req); + +#endif /* __UTIL_H__ */