[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1071693: sbsign should check certificate's expiration



Package: sbsigntool
Version: 0.9.4-3.1+b1
Severity: normal
X-Debbugs-Cc: debian.axhn@manchmal.in-ulm.de

Greetings,

it was a bit surprising to learn sbsign will happily sign EFI images
even if the certificate, provided via the --cert parameter, has expired.
While this possibly will not affect functionality, it might still cause
surprising and hard-to-debug issues later.

How to repeat:

Provide an EFI image (e.g. grubx64.efi) as "kernel", and run

---------------------------------------------------------------------
#!/bin/sh

image='kernel'

if [ ! -f "$image" ]; then
    echo "E: Copy some EFI image to '$image' first"
    exit 1
fi

# Generate signing key and certificate
# chronic (from moreutils), just to avoid noise
chronic \
faketime "2023/1/2" \
openssl req \
    -batch \
    -new \
    -subj "/CN=Root CA" \
    -newkey RSA:4096 \
    -nodes \
    -keyout root.key \
    -x509 \
    -days 180 \
    -sha256 \
    -extensions v3_ca \
    -out root.crt.pem

# Show the expiration date
openssl x509 -noout -enddate -in root.crt.pem

sbsign \
    --key root.key --cert root.crt.pem --output "$image.signed" "$image"
---------------------------------------------------------------------

Expected: sbsign should at least warn about an expired certificate, or
even refuse operation.

Observed: sbsign just signs the image.


How to fix (draft):

The patch attached is rather a proof of concept: It checks the
expiration date, warns if it's less than 365 days in the future, and
exits non-zero if it's less than 30 days, or even already expired.

Todo:

* Make the thresholds configurable via command line options.
* Documentation, including "Setting the thresholds to 0 (zero) disables
  the check".
* Check the certificate(s) provided via --addcert.

Regards,

    Christoph

-- System Information:
Debian Release: trixie/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)

Kernel: Linux 6.6.31 (SMP w/8 CPU threads)
Kernel taint flags: TAINT_WARN
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages sbsigntool depends on:
ii  libc6       2.38-11
ii  libssl3t64  3.2.1-3
ii  libuuid1    2.40.1-1

sbsigntool recommends no packages.

sbsigntool suggests no packages.

-- no debconf information

--- a/src/sbsign.c
+++ b/src/sbsign.c
@@ -39,6 +39,7 @@
 #include <sys/types.h>
 #include <fcntl.h>
 #include <string.h>
+#include <time.h>
 
 #include <getopt.h>
 
@@ -156,6 +157,8 @@
 	struct sign_context *ctx;
 	uint8_t *buf, *tmp;
 	int rc, c, sigsize;
+	int maxttl_warn = 365, maxttl_crit = 30;
+	time_t now = time(NULL);
 	EVP_PKEY *pkey;
 
 	ctx = talloc_zero(NULL, struct sign_context);
@@ -255,6 +258,29 @@
 	if (!cert)
 		return EXIT_FAILURE;
 
+	ASN1_TIME *notafter = X509_getm_notAfter(cert);
+	int expired = ASN1_TIME_cmp_time_t(notafter, now);
+	if (maxttl_crit > 0) {
+		if (expired == -1) {
+			fprintf(stderr, "critical, certificate %s has expired\n", certfilename);
+			return EXIT_FAILURE;
+		}
+		time_t time_crit = now + 86400*maxttl_crit;
+		if (ASN1_TIME_cmp_time_t(notafter, time_crit) == -1) {
+			fprintf(stderr, "critical, certificate %s will expire in less than %d days\n", certfilename, maxttl_crit);
+			return EXIT_FAILURE;
+		}
+	}
+	if (maxttl_warn > 0) {
+		if (expired == -1) {
+			fprintf(stderr, "warning, certificate %s has expired\n", certfilename);
+		} else {
+			time_t time_warn = now + 86400*maxttl_warn;
+			if (ASN1_TIME_cmp_time_t(notafter, time_warn) == -1)
+				fprintf(stderr, "warning, certificate %s will expire in less than %d days\n", certfilename, maxttl_warn);
+		}
+	}
+
 	const EVP_MD *md = EVP_get_digestbyname("SHA256");
 
 	/* set up the PKCS7 object */

Attachment: signature.asc
Description: PGP signature


Reply to: