git: cc9e6590773d - main - Merge bearssl-20220418

From: Simon J. Gerraty <sjg_at_FreeBSD.org>
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 ***