git: cc9e6590773d - main - Merge bearssl-20220418
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 18 Apr 2022 21:53:16 UTC
The branch main has been updated by sjg:
URL: https://cgit.FreeBSD.org/src/commit/?id=cc9e6590773dba57440750c124173ed531349a06
commit cc9e6590773dba57440750c124173ed531349a06
Merge: ecbe50447d04 f6acb9b9f81c
Author: Simon J. Gerraty <sjg@FreeBSD.org>
AuthorDate: 2022-04-18 21:47:09 +0000
Commit: Simon J. Gerraty <sjg@FreeBSD.org>
CommitDate: 2022-04-18 21:52:30 +0000
Merge bearssl-20220418
Main change is a callback for checking validity period of certificates.
Merge commit 'f6acb9b9f81c96ae7c9592bee1bb89c4357cc3e5'
Add -DHAVE_BR_X509_TIME_CHECK to libsecureboot/Makefile.inc
contrib/bearssl/.gitignore | 6 +
contrib/bearssl/T0Comp.exe | Bin 72704 -> 73216 bytes
contrib/bearssl/flist | 459 +++++++++++++++
contrib/bearssl/inc/bearssl_ec.h | 2 +-
contrib/bearssl/inc/bearssl_hash.h | 4 +-
contrib/bearssl/inc/bearssl_ssl.h | 8 +-
contrib/bearssl/inc/bearssl_x509.h | 83 ++-
contrib/bearssl/src/config.h | 22 +-
contrib/bearssl/src/ec/ec_c25519_m64.c | 4 -
contrib/bearssl/src/ec/ec_p256_m15.c | 22 +-
contrib/bearssl/src/ec/ec_p256_m31.c | 22 +-
contrib/bearssl/src/ec/ec_p256_m62.c | 2 +-
contrib/bearssl/src/ec/ec_p256_m64.c | 67 ++-
contrib/bearssl/src/ec/ec_prime_i15.c | 10 +-
contrib/bearssl/src/ec/ec_prime_i31.c | 13 +-
contrib/bearssl/src/inner.h | 26 +-
contrib/bearssl/src/rand/sysrng.c | 88 ++-
contrib/bearssl/src/rsa/rsa_i15_keygen.c | 6 +-
contrib/bearssl/src/rsa/rsa_i15_modulus.c | 2 +-
contrib/bearssl/src/rsa/rsa_i31_keygen_inner.c | 6 +-
contrib/bearssl/src/rsa/rsa_i31_modulus.c | 2 +-
contrib/bearssl/src/ssl/ssl_engine.c | 15 +
contrib/bearssl/src/ssl/ssl_rec_cbc.c | 2 +-
contrib/bearssl/src/x509/asn1.t0 | 2 +-
contrib/bearssl/src/x509/skey_decoder.c | 2 +-
contrib/bearssl/src/x509/skey_decoder.t0 | 2 +-
contrib/bearssl/src/x509/x509_minimal.c | 751 +++++++++++++------------
contrib/bearssl/src/x509/x509_minimal.t0 | 80 ++-
contrib/bearssl/test/test_crypto.c | 4 +-
contrib/bearssl/test/test_x509.c | 210 ++++---
contrib/bearssl/tools/sslio.c | 2 +-
lib/libsecureboot/Makefile.inc | 2 +
lib/libsecureboot/vets.c | 2 +-
33 files changed, 1358 insertions(+), 570 deletions(-)
diff --cc contrib/bearssl/.gitignore
index 000000000000,000000000000..7da362eddc00
new file mode 100644
--- /dev/null
+++ b/contrib/bearssl/.gitignore
@@@ -1,0 -1,0 +1,6 @@@
++/build/
++/libbearssl.a
++/brssl
++/testcrypto
++/testspeed
++/testx509
diff --cc contrib/bearssl/T0Comp.exe
index 67eba109800e,de2364d69e07..de2364d69e07
Binary files differ
diff --cc contrib/bearssl/flist
index 000000000000,9751ad231065..9751ad231065
mode 000000,100644..100644
--- a/contrib/bearssl/flist
+++ b/contrib/bearssl/flist
diff --cc lib/libsecureboot/Makefile.inc
index e0faf287a245,000000000000..921b5e7bc1d8
mode 100644,000000..100644
--- a/lib/libsecureboot/Makefile.inc
+++ b/lib/libsecureboot/Makefile.inc
@@@ -1,168 -1,0 +1,170 @@@
+# $FreeBSD$
+
+.if empty(BEARSSL)
+.include "../libbearssl/Makefile.inc"
+.endif
+
+.if !target(_${__this}_)
+_${__this}_:
+
+libsecureboot_src:= ${.PARSEDIR}
+
+CFLAGS+= -I${libsecureboot_src}/h
+
++CFLAGS+= -DHAVE_BR_X509_TIME_CHECK
++
+.PATH: ${.PARSEDIR}
+
+SRCS+= \
+ readfile.c \
+ brf.c \
+ vesigned.c \
+ vets.c
+
+.if ${.CURDIR:M*libsecureboot*} != ""
+SRCS+= veta.c
+.endif
+
+CFLAGS+= ${XCFLAGS.${.TARGET:T:R}:U}
+
+# we use a couple of files from ${BEARSSL}/tools
+BRSSL_CFLAGS+= -I${BEARSSL}/tools
+BRSSL_SRCS+= \
+ ${BEARSSL}/tools/xmem.c \
+ ${BEARSSL}/tools/vector.c
+
+BRSSL_DEPS= \
+ brf.c \
+ vets.c \
+ veta.c
+
+.if ${MK_LOADER_EFI_SECUREBOOT} != "no"
+BRSSL_DEPS+= \
+ efi_init.c \
+ efi_variables.c
+.endif
+
+# we do not need/want nested objdirs
+OBJS_SRCS_FILTER = T R
+
+SRCS+= ${BRSSL_SRCS}
+
+
+# extract the last cert from a chain (should be rootCA)
+_LAST_PEM_USE: .USE
+ sed "1,`grep -n .-END ${.ALLSRC:M*.pem} | tail -2 | head -1 | sed 's,:.*,,'`d" ${.ALLSRC:M*.pem} > ${.TARGET}
+
+# extract 2nd last cert from chain - we use this for self-test
+_2ndLAST_PEM_USE: .USE
+ sed -n "`grep -n .-BEGIN ${.ALLSRC:M*.pem} | tail -2 | \
+ sed 's,:.*,,' | xargs | (read a b; echo $$a,$$(($$b - 1)))`p" ${.ALLSRC:M*.pem} > ${.TARGET}
+
+# list of hashes we support
+VE_HASH_LIST?= SHA256
+
+# list of signatures we support
+# some people don't trust ECDSA
+VE_SIGNATURE_LIST?= RSA
+
+# this list controls our search for signatures so will not be sorted
+# note: for X509 signatures we assume we can replace the trailing
+# "sig" with "certs" to find the certificate chain
+# eg. for manifest.esig we use manifest.ecerts
+VE_SIGNATURE_EXT_LIST?= sig
+
+# needs to be yes for FIPS 140-2 compliance
+VE_SELF_TESTS?= no
+
+# rules to populate the [tv]*.pem files we use to generate ta.h
+# and can add/alter VE_*_LIST as desired.
+.-include "local.trust.mk"
+
+# this is what we use as our trust anchor
+CFLAGS+= -I. -DTRUST_ANCHOR_STR=ta_PEM
+
+.if ${VE_SELF_TESTS} != "no"
+XCFLAGS.vets+= -DVERIFY_CERTS_STR=vc_PEM
+.endif
+
+# clean these up
+VE_HASH_LIST:= ${VE_HASH_LIST:tu:O:u}
+VE_SIGNATURE_LIST:= ${VE_SIGNATURE_LIST:tu:O:u}
+
+# define what we are supporting
+CFLAGS+= ${VE_HASH_LIST:@H@-DVE_$H_SUPPORT@} \
+ ${VE_SIGNATURE_LIST:@S@-DVE_$S_SUPPORT@}
+
+.if ${VE_SIGNATURE_LIST:MOPENPGP} != ""
+.include "openpgp/Makefile.inc"
+.endif
+
+.if ${VE_SELF_TESTS} != "no"
+# The input used for hash KATs
+# we use a string by default so it is independent of any other test
+VE_HASH_KAT_STRLEN?= strlen
+.if ${VE_HASH_KAT_STRLEN} == "strlen"
+VE_HASH_KAT_STR?= self-tests-are-good
+VE_HASH_KAT_STR_INPUT= echo -n
+XCFLAGS.vets+= -DVE_HASH_KAT_STR=\"${VE_HASH_KAT_STR}\"
+.else
+VE_HASH_KAT_STR?= vc_PEM
+VE_HASH_KAT_STR_INPUT= cat
+VE_HASH_KAT_STRLEN= sizeof
+XCFLAGS.vets+= -DVE_HASH_KAT_STR=${VE_HASH_KAT_STR}
+.endif
+XCFLAGS.vets+= -DVE_HASH_KAT_STRLEN=${VE_HASH_KAT_STRLEN}
+.endif
+
+# this should be updated occassionally this is 2019-01-01Z
+SOURCE_DATE_EPOCH?= 1546329600
+.if ${MK_REPRODUCIBLE_BUILD} == "yes"
+BUILD_UTC?= ${SOURCE_DATE_EPOCH}
+.endif
+# BUILD_UTC provides a basis for the loader's notion of time
+# By default we use the mtime of BUILD_UTC_FILE
+.if empty(BUILD_UTC_FILE)
+BUILD_UTC_FILE:= ${.PARSEDIR:tA}/${.PARSEFILE}
+.endif
+# you can of course set BUILD_UTC to any value you like
+BUILD_UTC?= ${${STAT:Ustat} -f %m ${BUILD_UTC_FILE}:L:sh}
+
+# Generate ta.h containing one or more PEM encoded trust anchors in ta_PEM.
+#
+# If we are doing self-tests, we define another arrary vc_PEM
+# containing certificates that we can verify for each trust anchor.
+# This is typically a subordinate CA cert.
+# Finally we generate a hash of VE_HASH_KAT_STR
+# using each supported hash method
+# to use as a Known Answer Test (needed for FIPS 140-2)
+#
+TA_PEM_LIST ?= ${.ALLSRC:N*crl*:Mt*.pem}
+VC_PEM_LIST ?= ${.ALLSRC:N*crl*:Mv*.pem}
+vets.o vets.po vets.pico: ta.h
+ta.h:
+ @( echo '/* Autogenerated - DO NOT EDIT!!! */'; echo; \
+ cat ${TA_PEM_LIST:O:u} /dev/null | \
+ file2c -sx 'static const char ta_PEM[] = {' '};'; \
+ echo "${.newline}${VE_HASH_LIST:O:u:@H@static char vh_$H[] = \"`${VE_HASH_KAT_STR_INPUT} ${VE_HASH_KAT_STR} | ${$H:U${H:tl}}`\";${.newline}@}"; ) > ${.TARGET}
+.if ${VE_SELF_TESTS} != "no"
+ ( cat ${VC_PEM_LIST:O:u} /dev/null | \
+ file2c -sx 'static const char vc_PEM[] = {' '};'; echo ) >> ${.TARGET}
+.endif
+ echo '#define BUILD_UTC ${BUILD_UTC}' >> ${.TARGET} ${.OODATE:MNOMETA_CMP}
+
+# This header records our preference for signature extensions.
+vesigned.o vesigned.po vesigned.pico: vse.h
+vse.h:
+ @( echo '/* Autogenerated - DO NOT EDIT!!! */'; echo; \
+ echo "static const char *signature_exts[] = {"; \
+ echo '${VE_SIGNATURE_EXT_LIST:O:u:@e@"$e",${.newline}@}'; \
+ echo 'NULL };' ) > ${.TARGET}
+
+
+.for s in ${BRSSL_SRCS} ${BRSSL_DEPS}
+.ifdef BRSSL_SED
+$s: brssl.h
+.endif
+XCFLAGS.${s:R}+= ${BRSSL_CFLAGS}
+.endfor
+
+.endif
diff --cc lib/libsecureboot/vets.c
index dd347a0a8c13,000000000000..a3c1fb34a419
mode 100644,000000..100644
--- a/lib/libsecureboot/vets.c
+++ b/lib/libsecureboot/vets.c
@@@ -1,1128 -1,0 +1,1128 @@@
+/*-
+ * Copyright (c) 2017-2018, Juniper Networks, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/**
+ * @file vets.c - trust store
+ * @brief verify signatures
+ *
+ * We leverage code from BearSSL www.bearssl.org
+ */
+
+#include <sys/time.h>
+#include <stdarg.h>
+#define NEED_BRSSL_H
+#include "libsecureboot-priv.h"
+#include <brssl.h>
+#include <ta.h>
+
+#ifndef TRUST_ANCHOR_STR
+# define TRUST_ANCHOR_STR ta_PEM
+#endif
+
+#define EPOCH_YEAR 1970
+#define AVG_SECONDS_PER_YEAR 31556952L
+#define SECONDS_PER_DAY 86400
+#define SECONDS_PER_YEAR 365 * SECONDS_PER_DAY
+#ifndef VE_UTC_MAX_JUMP
+# define VE_UTC_MAX_JUMP 20 * SECONDS_PER_YEAR
+#endif
+#define X509_DAYS_TO_UTC0 719528
+
+int DebugVe = 0;
+
+#ifndef VE_VERIFY_FLAGS
+# define VE_VERIFY_FLAGS VEF_VERBOSE
+#endif
+int VerifyFlags = VE_VERIFY_FLAGS;
+
+typedef VECTOR(br_x509_certificate) cert_list;
+typedef VECTOR(hash_data) digest_list;
+
+static anchor_list trust_anchors = VEC_INIT;
+static anchor_list forbidden_anchors = VEC_INIT;
+static digest_list forbidden_digests = VEC_INIT;
+
+static int anchor_verbose = 0;
+
+void
+ve_anchor_verbose_set(int n)
+{
+ anchor_verbose = n;
+}
+
+int
+ve_anchor_verbose_get(void)
+{
+ return (anchor_verbose);
+}
+
+void
+ve_debug_set(int n)
+{
+ DebugVe = n;
+}
+
+static char ebuf[512];
+
+char *
+ve_error_get(void)
+{
+ return (ebuf);
+}
+
+int
+ve_error_set(const char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ebuf[0] = '\0';
+ rc = 0;
+ if (fmt) {
+#ifdef STAND_H
+ vsprintf(ebuf, fmt, ap); /* no vsnprintf in libstand */
+ ebuf[sizeof(ebuf) - 1] = '\0';
+ rc = strlen(ebuf);
+#else
+ rc = vsnprintf(ebuf, sizeof(ebuf), fmt, ap);
+#endif
+ }
+ va_end(ap);
+ return (rc);
+}
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+
+/*
+ * The *approximate* date.
+ *
+ * When certificate verification fails for being
+ * expired or not yet valid, it helps to indicate
+ * our current date.
+ * Since libsa lacks strftime and gmtime,
+ * this simple implementation suffices.
+ */
+static const char *
+gdate(char *buf, size_t bufsz, time_t clock)
+{
+ int days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ int year, y, m, d;
+
+ y = clock / AVG_SECONDS_PER_YEAR;
+ year = EPOCH_YEAR + y;
+ for (y = EPOCH_YEAR; y < year; y++) {
+ clock -= SECONDS_PER_YEAR;
+ if (isleap(y))
+ clock -= SECONDS_PER_DAY;
+ }
+ d = clock / SECONDS_PER_DAY;
+ for (m = 0; d > 1 && m < 12; m++) {
+ if (d > days[m]) {
+ d -= days[m];
+ if (m == 1 && d > 0 && isleap(year))
+ d--;
+ } else
+ break;
+ }
+ d++;
+ if (d > days[m]) {
+ d = 1;
+ m++;
+ if (m >= 12) {
+ year++;
+ m = 0;
+ }
+ }
+ (void)snprintf(buf, bufsz, "%04d-%02d-%02d", year, m+1, d);
+ return(buf);
+}
+
+/* this is the time we use for verifying certs */
+#ifdef UNIT_TEST
+extern time_t ve_utc;
+time_t ve_utc = 0;
+#else
+static time_t ve_utc = 0;
+#endif
+
+/**
+ * @brief
+ * set ve_utc used for certificate verification
+ *
+ * @param[in] utc
+ * time - ignored unless greater than current value
+ * and not a leap of 20 years or more.
+ */
+void
+ve_utc_set(time_t utc)
+{
+ if (utc > ve_utc &&
+ (ve_utc == 0 || (utc - ve_utc) < VE_UTC_MAX_JUMP)) {
+ DEBUG_PRINTF(2, ("Set ve_utc=%jd\n", (intmax_t)utc));
+ ve_utc = utc;
+ }
+}
+
+static void
+free_cert_contents(br_x509_certificate *xc)
+{
+ xfree(xc->data);
+}
+
+/*
+ * a bit of a dance to get commonName from a certificate
+ */
+static char *
+x509_cn_get(br_x509_certificate *xc, char *buf, size_t len)
+{
+ br_x509_minimal_context mc;
+ br_name_element cn;
+ unsigned char cn_oid[4];
+ int err;
+
+ if (buf == NULL)
+ return (buf);
+ /*
+ * We want the commonName field
+ * the OID we want is 2,5,4,3 - but DER encoded
+ */
+ cn_oid[0] = 3;
+ cn_oid[1] = 0x55;
+ cn_oid[2] = 4;
+ cn_oid[3] = 3;
+ cn.oid = cn_oid;
+ cn.buf = buf;
+ cn.len = len;
+ cn.buf[0] = '\0';
+
+ br_x509_minimal_init(&mc, &br_sha256_vtable, NULL, 0);
+ br_x509_minimal_set_name_elements(&mc, &cn, 1);
+ /* the below actually does the work - updates cn.status */
+ mc.vtable->start_chain(&mc.vtable, NULL);
+ mc.vtable->start_cert(&mc.vtable, xc->data_len);
+ mc.vtable->append(&mc.vtable, xc->data, xc->data_len);
+ mc.vtable->end_cert(&mc.vtable);
+ /* we don' actually care about cert status - just its name */
+ err = mc.vtable->end_chain(&mc.vtable);
+
+ if (!cn.status)
+ buf = NULL;
+ return (buf);
+}
+
+/* ASN parsing related defines */
+#define ASN1_PRIMITIVE_TAG 0x1F
+#define ASN1_INF_LENGTH 0x80
+#define ASN1_LENGTH_MASK 0x7F
+
+/*
+ * Get TBS part of certificate.
+ * Since BearSSL doesn't provide any API to do this,
+ * it has to be implemented here.
+ */
+static void*
+X509_to_tbs(unsigned char* cert, size_t* output_size)
+{
+ unsigned char *result;
+ size_t tbs_size;
+ int size, i;
+
+ if (cert == NULL)
+ return (NULL);
+
+ /* Strip two sequences to get to the TBS section */
+ for (i = 0; i < 2; i++) {
+ /*
+ * XXX: We don't need to support extended tags since
+ * they should not be present in certificates.
+ */
+ if ((*cert & ASN1_PRIMITIVE_TAG) == ASN1_PRIMITIVE_TAG)
+ return (NULL);
+
+ cert++;
+
+ if (*cert == ASN1_INF_LENGTH)
+ return (NULL);
+
+ size = *cert & ASN1_LENGTH_MASK;
+ tbs_size = 0;
+
+ /* Size can either be stored on a single or multiple bytes */
+ if (*cert & (ASN1_LENGTH_MASK + 1)) {
+ cert++;
+ while (*cert == 0 && size > 0) {
+ cert++;
+ size--;
+ }
+ while (size-- > 0) {
+ tbs_size <<= 8;
+ tbs_size |= *(cert++);
+ }
+ }
+ if (i == 0)
+ result = cert;
+ }
+ tbs_size += (cert - result);
+
+ if (output_size != NULL)
+ *output_size = tbs_size;
+
+ return (result);
+}
+
+void
+ve_forbidden_digest_add(hash_data *digest, size_t num)
+{
+ while (num--)
+ VEC_ADD(forbidden_digests, digest[num]);
+}
+
+static size_t
+ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors,
+ const char *anchors_name)
+{
+ br_x509_trust_anchor ta;
+ size_t u;
+
+ for (u = 0; u < num; u++) {
+ if (certificate_to_trust_anchor_inner(&ta, &xcs[u]) < 0) {
+ break;
+ }
+ VEC_ADD(*anchors, ta);
+ if (anchor_verbose && anchors_name) {
+ char buf[64];
+ char *cp;
+
+ cp = x509_cn_get(&xcs[u], buf, sizeof(buf));
+ if (cp) {
+ printf("x509_anchor(%s) %s\n", cp, anchors_name);
+ }
+ }
+ }
+ return (u);
+}
+
+/**
+ * @brief
+ * add certs to our trust store
+ */
+size_t
+ve_trust_anchors_add(br_x509_certificate *xcs, size_t num)
+{
+ return (ve_anchors_add(xcs, num, &trust_anchors, "trusted"));
+}
+
+size_t
+ve_forbidden_anchors_add(br_x509_certificate *xcs, size_t num)
+{
+ return (ve_anchors_add(xcs, num, &forbidden_anchors, "forbidden"));
+}
+
+
+/**
+ * @brief add trust anchors in buf
+ *
+ * Assume buf contains x509 certificates, but if not and
+ * we support OpenPGP try adding as that.
+ *
+ * @return number of anchors added
+ */
+size_t
+ve_trust_anchors_add_buf(unsigned char *buf, size_t len)
+{
+ br_x509_certificate *xcs;
+ size_t num;
+
+ num = 0;
+ xcs = parse_certificates(buf, len, &num);
+ if (xcs != NULL) {
+ num = ve_trust_anchors_add(xcs, num);
+#ifdef VE_OPENPGP_SUPPORT
+ } else {
+ num = openpgp_trust_add_buf(buf, len);
+#endif
+ }
+ return (num);
+}
+
+/**
+ * @brief revoke trust anchors in buf
+ *
+ * Assume buf contains x509 certificates, but if not and
+ * we support OpenPGP try revoking keyId
+ *
+ * @return number of anchors revoked
+ */
+size_t
+ve_trust_anchors_revoke(unsigned char *buf, size_t len)
+{
+ br_x509_certificate *xcs;
+ size_t num;
+
+ num = 0;
+ xcs = parse_certificates(buf, len, &num);
+ if (xcs != NULL) {
+ num = ve_forbidden_anchors_add(xcs, num);
+#ifdef VE_OPENPGP_SUPPORT
+ } else {
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+ num = openpgp_trust_revoke((char *)buf);
+#endif
+ }
+ return (num);
+}
+
+/**
+ * @brief
+ * initialize our trust_anchors from ta_PEM
+ */
+int
+ve_trust_init(void)
+{
+ static int once = -1;
+
+ if (once >= 0)
+ return (once);
+ once = 0; /* to be sure */
+#ifdef BUILD_UTC
+ ve_utc_set(BUILD_UTC); /* ensure sanity */
+#endif
+ ve_utc_set(time(NULL));
+ ve_error_set(NULL); /* make sure it is empty */
+#ifdef VE_PCR_SUPPORT
+ ve_pcr_init();
+#endif
+
+#ifdef TRUST_ANCHOR_STR
+ ve_trust_anchors_add_buf(__DECONST(unsigned char *, TRUST_ANCHOR_STR),
+ sizeof(TRUST_ANCHOR_STR));
+#endif
+ once = (int) VEC_LEN(trust_anchors);
+#ifdef VE_OPENPGP_SUPPORT
+ once += openpgp_trust_init();
+#endif
+ return (once);
+}
+
+#ifdef HAVE_BR_X509_TIME_CHECK
+static int
- verify_time_cb(void *tctx,
++verify_time_cb(void *tctx __unused,
+ uint32_t not_before_days, uint32_t not_before_seconds,
+ uint32_t not_after_days, uint32_t not_after_seconds)
+{
+ time_t not_before;
+ time_t not_after;
+ int rc;
+#ifdef UNIT_TEST
+ char date[12], nb_date[12], na_date[12];
+#endif
+
+ not_before = ((not_before_days - X509_DAYS_TO_UTC0) * SECONDS_PER_DAY) + not_before_seconds;
+ not_after = ((not_after_days - X509_DAYS_TO_UTC0) * SECONDS_PER_DAY) + not_after_seconds;
+ if (ve_utc < not_before)
+ rc = -1;
+ else if (ve_utc > not_after)
+ rc = 1;
+ else
+ rc = 0;
+#ifdef UNIT_TEST
+ printf("notBefore %s notAfter %s date %s rc %d\n",
+ gdate(nb_date, sizeof(nb_date), not_before),
+ gdate(na_date, sizeof(na_date), not_after),
+ gdate(date, sizeof(date), ve_utc), rc);
+#endif
+#if defined(_STANDALONE)
+ rc = 0; /* don't fail */
+#endif
+ return rc;
+}
+#endif
+
+/**
+ * if we can verify the certificate chain in "certs",
+ * return the public key and if "xcp" is !NULL the associated
+ * certificate
+ */
+static br_x509_pkey *
+verify_signer_xcs(br_x509_certificate *xcs,
+ size_t num,
+ br_name_element *elts, size_t num_elts,
+ anchor_list *anchors)
+{
+ br_x509_minimal_context mc;
+ br_x509_certificate *xc;
+ size_t u;
+ cert_list chain = VEC_INIT;
+ const br_x509_pkey *tpk;
+ br_x509_pkey *pk;
+ unsigned int usages;
+ int err;
+
+ DEBUG_PRINTF(5, ("verify_signer: %zu certs in chain\n", num));
+ VEC_ADDMANY(chain, xcs, num);
+ if (VEC_LEN(chain) == 0) {
+ ve_error_set("ERROR: no/invalid certificate chain\n");
+ return (NULL);
+ }
+
+ DEBUG_PRINTF(5, ("verify_signer: %zu trust anchors\n",
+ VEC_LEN(*anchors)));
+
+ br_x509_minimal_init(&mc, &br_sha256_vtable,
+ &VEC_ELT(*anchors, 0),
+ VEC_LEN(*anchors));
+#ifdef VE_ECDSA_SUPPORT
+ br_x509_minimal_set_ecdsa(&mc,
+ &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
+#endif
+#ifdef VE_RSA_SUPPORT
+ br_x509_minimal_set_rsa(&mc, &br_rsa_i31_pkcs1_vrfy);
+#endif
+#if defined(UNIT_TEST) && defined(VE_DEPRECATED_RSA_SHA1_SUPPORT)
+ /* This is deprecated! do not enable unless you absoultely have to */
+ br_x509_minimal_set_hash(&mc, br_sha1_ID, &br_sha1_vtable);
+#endif
+ br_x509_minimal_set_hash(&mc, br_sha256_ID, &br_sha256_vtable);
+#ifdef VE_SHA384_SUPPORT
+ br_x509_minimal_set_hash(&mc, br_sha384_ID, &br_sha384_vtable);
+#endif
+#ifdef VE_SHA512_SUPPORT
+ br_x509_minimal_set_hash(&mc, br_sha512_ID, &br_sha512_vtable);
+#endif
+ br_x509_minimal_set_name_elements(&mc, elts, num_elts);
+
+#ifdef HAVE_BR_X509_TIME_CHECK
+ br_x509_minimal_set_time_callback(&mc, NULL, verify_time_cb);
+#else
+#if defined(_STANDALONE) || defined(UNIT_TEST)
+ /*
+ * Clock is probably bogus so we use ve_utc.
+ */
+ mc.days = (ve_utc / SECONDS_PER_DAY) + X509_DAYS_TO_UTC0;
+ mc.seconds = (ve_utc % SECONDS_PER_DAY);
+#endif
+#endif
+ mc.vtable->start_chain(&mc.vtable, NULL);
+ for (u = 0; u < VEC_LEN(chain); u ++) {
+ xc = &VEC_ELT(chain, u);
+ mc.vtable->start_cert(&mc.vtable, xc->data_len);
+ mc.vtable->append(&mc.vtable, xc->data, xc->data_len);
+ mc.vtable->end_cert(&mc.vtable);
+ switch (mc.err) {
+ case 0:
+ case BR_ERR_X509_OK:
+ case BR_ERR_X509_EXPIRED:
+ break;
+ default:
+ printf("u=%zu mc.err=%d\n", u, mc.err);
+ break;
+ }
+ }
+ err = mc.vtable->end_chain(&mc.vtable);
+ pk = NULL;
+ if (err) {
+ char date[12];
+
+ switch (err) {
+ case 54:
+ ve_error_set("Validation failed, certificate not valid as of %s",
+ gdate(date, sizeof(date), ve_utc));
+ break;
+ default:
+ ve_error_set("Validation failed, err = %d", err);
+ break;
+ }
+ } else {
+ tpk = mc.vtable->get_pkey(&mc.vtable, &usages);
+ if (tpk != NULL) {
+ pk = xpkeydup(tpk);
+ }
+ }
+ VEC_CLEAR(chain);
+ return (pk);
+}
+
+/*
+ * Check if digest of one of the certificates from verified chain
+ * is present in the forbidden database.
+ * Since UEFI allows to store three types of digests
+ * all of them have to be checked separately.
+ */
+static int
+check_forbidden_digests(br_x509_certificate *xcs, size_t num)
+{
+ unsigned char sha256_digest[br_sha256_SIZE];
+ unsigned char sha384_digest[br_sha384_SIZE];
+ unsigned char sha512_digest[br_sha512_SIZE];
+ void *tbs;
+ hash_data *digest;
+ br_hash_compat_context ctx;
+ const br_hash_class *md;
+ size_t tbs_len, i;
+ int have_sha256, have_sha384, have_sha512;
+
+ if (VEC_LEN(forbidden_digests) == 0)
+ return (0);
+
+ /*
+ * Iterate through certificates, extract their To-Be-Signed section,
+ * and compare its digest against the ones in the forbidden database.
+ */
+ while (num--) {
+ tbs = X509_to_tbs(xcs[num].data, &tbs_len);
+ if (tbs == NULL) {
+ printf("Failed to obtain TBS part of certificate\n");
+ return (1);
+ }
+ have_sha256 = have_sha384 = have_sha512 = 0;
+
+ for (i = 0; i < VEC_LEN(forbidden_digests); i++) {
+ digest = &VEC_ELT(forbidden_digests, i);
+ switch (digest->hash_size) {
+ case br_sha256_SIZE:
+ if (!have_sha256) {
+ have_sha256 = 1;
+ md = &br_sha256_vtable;
+ md->init(&ctx.vtable);
+ md->update(&ctx.vtable, tbs, tbs_len);
+ md->out(&ctx.vtable, sha256_digest);
+ }
+ if (!memcmp(sha256_digest,
+ digest->data,
+ br_sha256_SIZE))
+ return (1);
+
+ break;
+ case br_sha384_SIZE:
+ if (!have_sha384) {
+ have_sha384 = 1;
+ md = &br_sha384_vtable;
+ md->init(&ctx.vtable);
+ md->update(&ctx.vtable, tbs, tbs_len);
+ md->out(&ctx.vtable, sha384_digest);
+ }
+ if (!memcmp(sha384_digest,
+ digest->data,
+ br_sha384_SIZE))
+ return (1);
+
+ break;
+ case br_sha512_SIZE:
+ if (!have_sha512) {
+ have_sha512 = 1;
+ md = &br_sha512_vtable;
+ md->init(&ctx.vtable);
+ md->update(&ctx.vtable, tbs, tbs_len);
+ md->out(&ctx.vtable, sha512_digest);
+ }
+ if (!memcmp(sha512_digest,
+ digest->data,
+ br_sha512_SIZE))
+ return (1);
+
+ break;
+ }
+ }
+ }
+
+ return (0);
+}
+
+static br_x509_pkey *
+verify_signer(const char *certs,
+ br_name_element *elts, size_t num_elts)
+{
+ br_x509_certificate *xcs;
+ br_x509_pkey *pk;
+ size_t num;
+
+ pk = NULL;
+
+ ve_trust_init();
+ xcs = read_certificates(certs, &num);
+ if (xcs == NULL) {
+ ve_error_set("cannot read certificates\n");
+ return (NULL);
+ }
+
+ /*
+ * Check if either
+ * 1. There is a direct match between cert from forbidden_anchors
+ * and a cert from chain.
+ * 2. CA that signed the chain is found in forbidden_anchors.
+ */
+ if (VEC_LEN(forbidden_anchors) > 0)
+ pk = verify_signer_xcs(xcs, num, elts, num_elts, &forbidden_anchors);
+ if (pk != NULL) {
+ ve_error_set("Certificate is on forbidden list\n");
+ xfreepkey(pk);
+ pk = NULL;
+ goto out;
+ }
+
+ pk = verify_signer_xcs(xcs, num, elts, num_elts, &trust_anchors);
+ if (pk == NULL)
+ goto out;
+
+ /*
+ * Check if hash of tbs part of any certificate in chain
+ * is on the forbidden list.
+ */
+ if (check_forbidden_digests(xcs, num)) {
+ ve_error_set("Certificate hash is on forbidden list\n");
+ xfreepkey(pk);
+ pk = NULL;
+ }
+out:
+ free_certificates(xcs, num);
+ return (pk);
+}
+
+/**
+ * we need a hex digest including trailing newline below
+ */
+char *
+hexdigest(char *buf, size_t bufsz, unsigned char *foo, size_t foo_len)
+{
+ char const hex2ascii[] = "0123456789abcdef";
+ size_t i;
+
+ /* every binary byte is 2 chars in hex + newline + null */
+ if (bufsz < (2 * foo_len) + 2)
+ return (NULL);
+
+ for (i = 0; i < foo_len; i++) {
+ buf[i * 2] = hex2ascii[foo[i] >> 4];
+ buf[i * 2 + 1] = hex2ascii[foo[i] & 0x0f];
+ }
+
+ buf[i * 2] = 0x0A; /* we also want a newline */
+ buf[i * 2 + 1] = '\0';
+
+ return (buf);
+}
+
*** 398 LINES SKIPPED ***