svn commit: r344565 - in head/lib/libsecureboot: . h openpgp tests

Simon J. Gerraty sjg at FreeBSD.org
Tue Feb 26 06:09:13 UTC 2019


Author: sjg
Date: Tue Feb 26 06:09:10 2019
New Revision: 344565
URL: https://svnweb.freebsd.org/changeset/base/344565

Log:
  Add libsecureboot
  
  Used by loader and veriexec
  Depends on libbearssl
  
  Reviewed by:	emaste
  Sponsored by:	Juniper Networks
  Differential Revision:	D16335

Added:
  head/lib/libsecureboot/
  head/lib/libsecureboot/Makefile   (contents, props changed)
  head/lib/libsecureboot/Makefile.depend   (contents, props changed)
  head/lib/libsecureboot/Makefile.depend.host   (contents, props changed)
  head/lib/libsecureboot/Makefile.inc   (contents, props changed)
  head/lib/libsecureboot/Makefile.libsa.inc   (contents, props changed)
  head/lib/libsecureboot/README.rst   (contents, props changed)
  head/lib/libsecureboot/brf.c   (contents, props changed)
  head/lib/libsecureboot/h/
  head/lib/libsecureboot/h/libsecureboot.h   (contents, props changed)
  head/lib/libsecureboot/h/verify_file.h   (contents, props changed)
  head/lib/libsecureboot/libsecureboot-priv.h   (contents, props changed)
  head/lib/libsecureboot/local.trust.mk   (contents, props changed)
  head/lib/libsecureboot/openpgp/
  head/lib/libsecureboot/openpgp/Makefile.inc   (contents, props changed)
  head/lib/libsecureboot/openpgp/dearmor.c   (contents, props changed)
  head/lib/libsecureboot/openpgp/decode.c   (contents, props changed)
  head/lib/libsecureboot/openpgp/decode.h   (contents, props changed)
  head/lib/libsecureboot/openpgp/opgp_key.c   (contents, props changed)
  head/lib/libsecureboot/openpgp/opgp_sig.c   (contents, props changed)
  head/lib/libsecureboot/openpgp/packet.h   (contents, props changed)
  head/lib/libsecureboot/readfile.c   (contents, props changed)
  head/lib/libsecureboot/tests/
  head/lib/libsecureboot/tests/Makefile   (contents, props changed)
  head/lib/libsecureboot/tests/Makefile.depend.host   (contents, props changed)
  head/lib/libsecureboot/tests/tvo.c   (contents, props changed)
  head/lib/libsecureboot/vectx.c   (contents, props changed)
  head/lib/libsecureboot/veopen.c   (contents, props changed)
  head/lib/libsecureboot/vepcr.c   (contents, props changed)
  head/lib/libsecureboot/verify_file.c   (contents, props changed)
  head/lib/libsecureboot/vesigned.c   (contents, props changed)
  head/lib/libsecureboot/veta.c   (contents, props changed)
  head/lib/libsecureboot/vets.c   (contents, props changed)

Added: head/lib/libsecureboot/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libsecureboot/Makefile	Tue Feb 26 06:09:10 2019	(r344565)
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+LIB= secureboot
+
+.include "Makefile.inc"
+
+INCS= h/libsecureboot.h
+
+.include <bsd.lib.mk>

Added: head/lib/libsecureboot/Makefile.depend
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libsecureboot/Makefile.depend	Tue Feb 26 06:09:10 2019	(r344565)
@@ -0,0 +1,17 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+	gnu/lib/csu \
+	include \
+	include/xlocale \
+	lib/${CSU_DIR} \
+	lib/libc \
+	lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif

Added: head/lib/libsecureboot/Makefile.depend.host
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libsecureboot/Makefile.depend.host	Tue Feb 26 06:09:10 2019	(r344565)
@@ -0,0 +1,12 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+	lib/libstand \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif

Added: head/lib/libsecureboot/Makefile.inc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libsecureboot/Makefile.inc	Tue Feb 26 06:09:10 2019	(r344565)
@@ -0,0 +1,133 @@
+# $FreeBSD$
+
+.if empty(BEARSSL)
+.include "../libbearssl/Makefile.inc"
+.endif
+
+.if !target(_${__this}_)
+_${__this}_:
+
+libsecureboot_src:= ${.PARSEDIR}
+
+CFLAGS+= -I${libsecureboot_src}/h
+
+.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
+
+# 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 at -DVE_$H_SUPPORT@} \
+	${VE_SIGNATURE_LIST:@S at -DVE_$S_SUPPORT@}
+
+.if ${VE_SIGNATURE_LIST:MOPENPGP} != ""
+.include "openpgp/Makefile.inc"
+.endif
+
+.if ${VE_SELF_TESTS} != "no"
+# The input used for hash KATs
+VE_HASH_KAT_STR?= vc_PEM
+
+XCFLAGS.vets+= -DVE_HASH_KAT_STR=${VE_HASH_KAT_STR}
+.endif
+
+# 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 vc_PEM using each supported hash method
+# to use as a Known Answer Test (needed for FIPS 140-2)
+#
+vets.o vets.po vets.pico: ta.h
+ta.h: ${.ALLTARGETS:M[tv]*pem:O:u}
+	@( echo '/* Autogenerated - DO NOT EDIT!!! */'; echo; \
+	cat ${.ALLSRC:N*crl*:Mt*.pem} /dev/null | \
+	file2c -sx 'static const char ta_PEM[] = {' '};'; \
+	echo "${.newline}${VE_HASH_LIST:@H at static char vh_$H[] = \"`cat ${.ALLSRC:N*crl*:Mv*.pem} | ${$H:U${H:tl}}`\";${.newline}@}"; ) > ${.TARGET}
+.if ${VE_SELF_TESTS} != "no"
+	( cat ${.ALLSRC:N*crl*:Mv*.pem} /dev/null | \
+	file2c -sx 'static const char vc_PEM[] = {' '};'; echo ) >> ${.TARGET}
+.endif
+.if !empty(BUILD_UTC_FILE)
+	echo '#define BUILD_UTC ${${STAT:Ustat} -f %m ${BUILD_UTC_FILE}:L:sh}' >> ${.TARGET} ${.OODATE:MNOMETA_CMP}
+.endif
+
+# 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:@e@"$e",${.newline}@}'; \
+	echo 'NULL };' ) > ${.TARGET}
+
+
+.for s in ${BRSSL_SRCS} brf.c vets.c veta.c
+.ifdef BRSSL_SED
+$s: brssl.h
+.endif
+XCFLAGS.${s:R}+= ${BRSSL_CFLAGS}
+.endfor
+
+.endif

Added: head/lib/libsecureboot/Makefile.libsa.inc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libsecureboot/Makefile.libsa.inc	Tue Feb 26 06:09:10 2019	(r344565)
@@ -0,0 +1,40 @@
+# $FreeBSD$
+
+BRSSL_CFLAGS+= -DNO_STDIO
+
+.include "Makefile.inc"
+
+# for "measured boot"
+# loader puts the equivalent of TPM's PCR register into kenv
+# this is not as good but *way* simpler than talking to TPM
+CFLAGS+= -DVE_PCR_SUPPORT
+
+# sources that only apply to libsa
+SRCS+= \
+	vectx.c \
+	veopen.c \
+	vepcr.c \
+	verify_file.c \
+
+# this is the list of paths (relative to a file
+# that we need to verify) used to find a signed manifest.
+# the signature extensions in VE_SIGNATURE_EXT_LIST
+# will be applied to each.
+VE_MANIFEST_LIST?= manifest ../manifest
+
+verify_file.o: manifests.h
+manifests.h:
+	@( echo '/* Autogenerated - DO NOT EDIT!!! */'; echo; \
+	echo "static const char *manifest_names[] = {"; \
+	echo '${VE_MANIFEST_LIST:@m@"$m",${.newline}@}'; \
+	echo 'NULL };' ) > ${.TARGET}
+
+XCFLAGS.verify_file+= \
+	-DVE_DEBUG_LEVEL=${VE_DEBUG_LEVEL:U0} \
+	-DVE_VERBOSE_DEFAULT=${VE_VERBOSE_DEFAULT:U0} \
+
+.if !empty(MANIFEST_SKIP_ALWAYS)
+XCFLAGS.verify_file+= -DMANIFEST_SKIP_ALWAYS=\"${MANIFEST_SKIP_ALWAYS}\"
+.elif !empty(MANIFEST_SKIP)
+XCFLAGS.verify_file+= -DMANIFEST_SKIP=\"${MANIFEST_SKIP}\"
+.endif

Added: head/lib/libsecureboot/README.rst
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libsecureboot/README.rst	Tue Feb 26 06:09:10 2019	(r344565)
@@ -0,0 +1,134 @@
+libsecureboot
+*************
+
+This library depends one way or another on verifying digital signatures.
+To do that, the necessary trust anchors need to be available.
+
+The simplest (and most attractive for an embedded system) is to
+capture them in this library.
+
+The makefile ``local.trust.mk`` is responsible for doing that.
+The file provided is just an example and depends on the environment
+here at Juniper.
+
+Within Juniper we use signing servers, which apart from signing things
+provide access to the necessary trust anchors.
+That signing server is freely available - see
+http://www.crufty.net/sjg/docs/signing-server.htm
+
+X.509 certificates chains offer a lot of flexibility over time and are
+a great solution for an embedded vendor like Juniper or even
+FreeBSD.org, but are probably overkill for personal or small site use.
+
+Setting up a CA for this is rather involved so I'll just provide a
+link below to suitable tutorial below.
+
+Using OpenPGP is much simpler.
+
+
+OpenPGP
+========
+
+This is very simple to setup and use.
+
+An RSA key pair can be generated with::
+
+	GNUPGHOME=$PWD/.gnupg gpg --openpgp \
+	--quick-generate-key --batch --passphrase '' "keyname" RSA
+
+The use of ``GNUPGHOME=$PWD/.gnupg`` just avoids messing with personal
+keyrings.
+We can list the resulting key::
+
+	GNUPGHOME=$PWD/.gnupg gpg --openpgp --list-keys
+
+	gpg: WARNING: unsafe permissions on homedir
+	'/h/sjg/openpgp/.gnupg'
+	gpg: Warning: using insecure memory!
+	/h/sjg/openpgp/.gnupg/pubring.kbx
+	---------------------------------
+	pub   rsa2048 2018-03-26 [SC] [expires: 2020-03-25]
+	      AB39B111E40DD019E0E7C171ACA72B4719FD2523
+	      uid           [ultimate] OpenPGPtest
+
+The ``keyID`` we want later will be the last 8 octets
+(``ACA72B4719FD2523``)
+This is what we will use for looking up the key.
+
+We can then export the private and public keys::
+
+	GNUPGHOME=$PWD/.gnupg gpg --openpgp \
+	--export --armor > ACA72B4719FD2523.pub.asc
+	GNUPGHOME=$PWD/.gnupg gpg --openpgp \
+	--export-secret-keys --armor > ACA72B4719FD2523.sec.asc
+
+The public key ``ACA72B4719FD2523.pub.asc`` is what we want to
+embed in this library.
+If you look at the ``ta_asc.h`` target in ``openpgp/Makefile.inc``
+we want the trust anchor in a file named ``t*.asc``
+eg. ``ta_openpgp.asc``.
+
+The ``ta_asc.h`` target will capture all such ``t*.asc`` into that
+header.
+
+Signatures
+----------
+
+We expect ascii armored (``.asc``) detached signatures.
+Eg. signature for ``manifest`` would be in ``manifest.asc``
+
+We only support version 4 signatures using RSA (the default for ``gpg``).
+
+
+OpenSSL
+========
+
+The basic idea here is to setup a private CA.
+
+There are lots of good tutorials on available on this topic;
+just google *setup openssl ca*.
+A good example is https://jamielinux.com/docs/openssl-certificate-authority/
+
+All we need for this library is a copy of the PEM encoded root CA
+certificate (trust anchor).  This is expected to be in a file named
+``t*.pem`` eg. ``ta_rsa.pem``.
+
+The ``ta.h`` target in ``Makefile.inc`` will combine all such
+``t*.pem`` files into that header.
+
+Signatures
+----------
+
+For Junos we currently use EC DSA signatures with file extension
+``.esig`` so the signature for ``manifest`` would be ``manifest.esig``
+
+This was the first signature method we used with the remote signing
+servers and it ends up being a signature of a hash.
+Ie. client sends a hash which during signing gets hashed again.
+So for Junos we define VE_ECDSA_HASH_AGAIN which causes ``verify_ec``
+to hash again.
+
+Otherwise our EC DSA and RSA signatures are the default used by
+OpenSSL - an original design goal was that a customer could verify our
+signatures using nothing but an ``openssl`` binary.
+
+
+Self tests
+==========
+
+If you want the ``loader`` to perform self-test of a given signature
+verification method on startup (a must for FIPS 140-2 certification)
+you need to provide a suitable file signed by each supported trust
+anchor.
+
+These should be stored in files with names that start with ``v`` and
+have the same extension as the corresponding trust anchor.
+Eg. for ``ta_openpgp.asc`` we use ``vc_openpgp.asc``
+and for ``ta_rsa.pem`` we use ``vc_rsa.pem``.
+
+Note for the X.509 case we simply extract the 2nd last certificate
+from the relevant chain - which is sure to be a valid certificate
+signed by the corresponding trust anchor.
+
+--------------------
+$FreeBSD$

Added: head/lib/libsecureboot/brf.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libsecureboot/brf.c	Tue Feb 26 06:09:10 2019	(r344565)
@@ -0,0 +1,403 @@
+// The functions here are derrived from BearSSL/tools/*.c
+// When that is refactored suitably we can use them directly.
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin at bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define NEED_BRSSL_H
+#include "libsecureboot-priv.h"
+#include <brssl.h>
+
+
+static int
+is_ign(int c)
+{
+	if (c == 0) {
+		return (0);
+	}
+	if (c <= 32 || c == '-' || c == '_' || c == '.'
+		|| c == '/' || c == '+' || c == ':')
+	{
+		return (1);
+	}
+	return (0);
+}
+
+/*
+ * Get next non-ignored character, normalised:
+ *    ASCII letters are converted to lowercase
+ *    control characters, space, '-', '_', '.', '/', '+' and ':' are ignored
+ * A terminating zero is returned as 0.
+ */
+static int
+next_char(const char **ps, const char *limit)
+{
+	for (;;) {
+		int c;
+
+		if (*ps == limit) {
+			return (0);
+		}
+		c = *(*ps) ++;
+		if (c == 0) {
+			return (0);
+		}
+		if (c >= 'A' && c <= 'Z') {
+			c += 'a' - 'A';
+		}
+		if (!is_ign(c)) {
+			return (c);
+		}
+	}
+}
+
+/*
+ * Partial string equality comparison, with normalisation.
+ */
+static int
+eqstr_chunk(const char *s1, size_t s1_len, const char *s2, size_t s2_len)
+{
+	const char *lim1, *lim2;
+
+	lim1 = s1 + s1_len;
+	lim2 = s2 + s2_len;
+	for (;;) {
+		int c1, c2;
+
+		c1 = next_char(&s1, lim1);
+		c2 = next_char(&s2, lim2);
+		if (c1 != c2) {
+			return (0);
+		}
+		if (c1 == 0) {
+			return (1);
+		}
+	}
+}
+
+/* see brssl.h */
+int
+eqstr(const char *s1, const char *s2)
+{
+	return (eqstr_chunk(s1, strlen(s1), s2, strlen(s2)));
+}
+
+int
+looks_like_DER(const unsigned char *buf, size_t len)
+{
+	int fb;
+	size_t dlen;
+
+	if (len < 2) {
+		return (0);
+	}
+	if (*buf ++ != 0x30) {
+		return (0);
+	}
+	fb = *buf ++;
+	len -= 2;
+	if (fb < 0x80) {
+		return ((size_t)fb == len);
+	} else if (fb == 0x80) {
+		return (0);
+	} else {
+		fb -= 0x80;
+		if (len < (size_t)fb + 2) {
+			return (0);
+		}
+		len -= (size_t)fb;
+		dlen = 0;
+		while (fb -- > 0) {
+			if (dlen > (len >> 8)) {
+				return (0);
+			}
+			dlen = (dlen << 8) + (size_t)*buf ++;
+		}
+		return (dlen == len);
+	}
+}
+
+static void
+vblob_append(void *cc, const void *data, size_t len)
+{
+	bvector *bv;
+
+	bv = cc;
+	VEC_ADDMANY(*bv, data, len);
+}
+
+void
+free_pem_object_contents(pem_object *po)
+{
+	if (po != NULL) {
+		xfree(po->name);
+		xfree(po->data);
+	}
+}
+
+pem_object *
+decode_pem(const void *src, size_t len, size_t *num)
+{
+	VECTOR(pem_object) pem_list = VEC_INIT;
+	br_pem_decoder_context pc;
+	pem_object po, *pos;
+	const unsigned char *buf;
+	bvector bv = VEC_INIT;
+	int inobj;
+	int extra_nl;
+
+	*num = 0;
+	br_pem_decoder_init(&pc);
+	buf = src;
+	inobj = 0;
+	po.name = NULL;
+	po.data = NULL;
+	po.data_len = 0;
+	extra_nl = 1;
+	while (len > 0) {
+		size_t tlen;
+
+		tlen = br_pem_decoder_push(&pc, buf, len);
+		buf += tlen;
+		len -= tlen;
+		switch (br_pem_decoder_event(&pc)) {
+
+		case BR_PEM_BEGIN_OBJ:
+			po.name = xstrdup(br_pem_decoder_name(&pc));
+			br_pem_decoder_setdest(&pc, vblob_append, &bv);
+			inobj = 1;
+			break;
+
+		case BR_PEM_END_OBJ:
+			if (inobj) {
+				po.data = VEC_TOARRAY(bv);
+				po.data_len = VEC_LEN(bv);
+				VEC_ADD(pem_list, po);
+				VEC_CLEAR(bv);
+				po.name = NULL;
+				po.data = NULL;
+				po.data_len = 0;
+				inobj = 0;
+			}
+			break;
+
+		case BR_PEM_ERROR:
+			xfree(po.name);
+			VEC_CLEAR(bv);
+			ve_error_set("ERROR: invalid PEM encoding");
+			VEC_CLEAREXT(pem_list, &free_pem_object_contents);
+			return (NULL);
+		}
+
+		/*
+		 * We add an extra newline at the end, in order to
+		 * support PEM files that lack the newline on their last
+		 * line (this is somwehat invalid, but PEM format is not
+		 * standardised and such files do exist in the wild, so
+		 * we'd better accept them).
+		 */
+		if (len == 0 && extra_nl) {
+			extra_nl = 0;
+			buf = (const unsigned char *)"\n";
+			len = 1;
+		}
+	}
+	if (inobj) {
+	    ve_error_set("ERROR: unfinished PEM object");
+		xfree(po.name);
+		VEC_CLEAR(bv);
+		VEC_CLEAREXT(pem_list, &free_pem_object_contents);
+		return (NULL);
+	}
+
+	*num = VEC_LEN(pem_list);
+	VEC_ADD(pem_list, po);
+	pos = VEC_TOARRAY(pem_list);
+	VEC_CLEAR(pem_list);
+	return (pos);
+}
+
+br_x509_certificate *
+parse_certificates(unsigned char *buf, size_t len, size_t *num)
+{
+	VECTOR(br_x509_certificate) cert_list = VEC_INIT;
+	pem_object *pos;
+	size_t u, num_pos;
+	br_x509_certificate *xcs;
+	br_x509_certificate dummy;
+
+	*num = 0;
+
+	/*
+	 * Check for a DER-encoded certificate.
+	 */
+	if (looks_like_DER(buf, len)) {
+		xcs = xmalloc(2 * sizeof *xcs);
+		xcs[0].data = buf;
+		xcs[0].data_len = len;
+		xcs[1].data = NULL;
+		xcs[1].data_len = 0;
+		*num = 1;
+		return (xcs);
+	}
+
+	pos = decode_pem(buf, len, &num_pos);
+	if (pos == NULL) {
+		return (NULL);
+	}
+	for (u = 0; u < num_pos; u ++) {
+		if (eqstr(pos[u].name, "CERTIFICATE")
+			|| eqstr(pos[u].name, "X509 CERTIFICATE"))
+		{
+			br_x509_certificate xc;
+
+			xc.data = pos[u].data;
+			xc.data_len = pos[u].data_len;
+			pos[u].data = NULL;
+			VEC_ADD(cert_list, xc);
+		}
+	}
+	for (u = 0; u < num_pos; u ++) {
+		free_pem_object_contents(&pos[u]);
+	}
+	xfree(pos);
+
+	if (VEC_LEN(cert_list) == 0) {
+		return (NULL);
+	}
+	*num = VEC_LEN(cert_list);
+	dummy.data = NULL;
+	dummy.data_len = 0;
+	VEC_ADD(cert_list, dummy);
+	xcs = VEC_TOARRAY(cert_list);
+	VEC_CLEAR(cert_list);
+	return (xcs);
+}
+
+br_x509_certificate *
+read_certificates(const char *fname, size_t *num)
+{
+	br_x509_certificate *xcs;
+	unsigned char *buf;
+	size_t len;
+
+	*num = 0;
+
+	/*
+	 * TODO: reading the whole file is crude; we could parse them
+	 * in a streamed fashion. But it does not matter much in practice.
+	 */
+	buf = read_file(fname, &len);
+	if (buf == NULL) {
+		return (NULL);
+	}
+	xcs = parse_certificates(buf, len, num);
+	if (xcs == NULL) {
+	    ve_error_set("ERROR: no certificate in file '%s'\n", fname);
+	}
+	xfree(buf);
+	return (xcs);
+}
+
+/* see brssl.h */
+void
+free_certificates(br_x509_certificate *certs, size_t num)
+{
+	size_t u;
+
+	for (u = 0; u < num; u ++) {
+		xfree(certs[u].data);
+	}
+	xfree(certs);
+}
+
+
+static void
+dn_append(void *ctx, const void *buf, size_t len)
+{
+	VEC_ADDMANY(*(bvector *)ctx, buf, len);
+}
+
+int
+certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
+	br_x509_certificate *xc)
+{
+	br_x509_decoder_context dc;
+	bvector vdn = VEC_INIT;
+	br_x509_pkey *pk;
+
+	br_x509_decoder_init(&dc, dn_append, &vdn);
+	br_x509_decoder_push(&dc, xc->data, xc->data_len);
+	pk = br_x509_decoder_get_pkey(&dc);
+	if (pk == NULL) {
+	    ve_error_set("ERROR: CA decoding failed with error %d\n",
+		      br_x509_decoder_last_error(&dc));
+	    VEC_CLEAR(vdn);
+	    return (-1);
+	}
+	ta->dn.data = VEC_TOARRAY(vdn);
+	ta->dn.len = VEC_LEN(vdn);
+	VEC_CLEAR(vdn);
+	ta->flags = 0;
+	if (br_x509_decoder_isCA(&dc)) {
+		ta->flags |= BR_X509_TA_CA;
+	}
+	switch (pk->key_type) {
+	case BR_KEYTYPE_RSA:
+		ta->pkey.key_type = BR_KEYTYPE_RSA;
+		ta->pkey.key.rsa.n = xblobdup(pk->key.rsa.n, pk->key.rsa.nlen);
+		ta->pkey.key.rsa.nlen = pk->key.rsa.nlen;
+		ta->pkey.key.rsa.e = xblobdup(pk->key.rsa.e, pk->key.rsa.elen);
+		ta->pkey.key.rsa.elen = pk->key.rsa.elen;
+		break;
+	case BR_KEYTYPE_EC:
+		ta->pkey.key_type = BR_KEYTYPE_EC;
+		ta->pkey.key.ec.curve = pk->key.ec.curve;
+		ta->pkey.key.ec.q = xblobdup(pk->key.ec.q, pk->key.ec.qlen);
+		ta->pkey.key.ec.qlen = pk->key.ec.qlen;
+		break;
+	default:
+	    ve_error_set("ERROR: unsupported public key type in CA\n");
+		xfree(ta->dn.data);
+		return (-1);
+	}
+	return (0);
+}
+
+/* see brssl.h */
+void
+free_ta_contents(br_x509_trust_anchor *ta)
+{
+	xfree(ta->dn.data);
+	switch (ta->pkey.key_type) {
+	case BR_KEYTYPE_RSA:
+		xfree(ta->pkey.key.rsa.n);
+		xfree(ta->pkey.key.rsa.e);
+		break;
+	case BR_KEYTYPE_EC:
+		xfree(ta->pkey.key.ec.q);
+		break;
+	}
+}

Added: head/lib/libsecureboot/h/libsecureboot.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libsecureboot/h/libsecureboot.h	Tue Feb 26 06:09:10 2019	(r344565)
@@ -0,0 +1,94 @@
+/*-
+ * 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.
+ */
+/*
+ * $FreeBSD$
+ */
+#ifndef _LIBSECUREBOOT_H_
+#define _LIBSECUREBOOT_H_
+
+#include <sys/param.h>
+#ifdef _STANDALONE
+#include <stand.h>
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+
+#include <bearssl.h>
+
+#ifndef NEED_BRSSL_H
+unsigned char * read_file(const char *, size_t *);
+#endif
+
+extern int DebugVe;
+
+#define DEBUG_PRINTF(n, x) if (DebugVe >= n) printf x
+
+int ve_trust_init(void);
+int ve_trust_add(const char *);
+void ve_debug_set(int);
+void ve_utc_set(time_t utc);
+char *ve_error_get(void);
+int ve_error_set(const char *, ...) __printflike(1,2);
+int  ve_self_tests(void);
+
+void fingerprint_info_add(const char *, const char *, const char *,
+    const char *, struct stat *);
+
+int ve_check_hash(br_hash_compat_context *, const br_hash_class *,
+    const char *, const char *, size_t);
+
+struct vectx;
+struct vectx* vectx_open(int, const char *, off_t, struct stat *, int *);
+ssize_t vectx_read(struct vectx *, void *, size_t);
+off_t vectx_lseek(struct vectx *, off_t, int);
+int vectx_close(struct vectx *);
+
+char * hexdigest(char *, size_t, unsigned char *, size_t);
+int  verify_fd(int, const char *, off_t, struct stat *);
+int  verify_open(const char *, int);
+
+unsigned char *verify_signed(const char *, int);
+unsigned char *verify_sig(const char *, int);
+unsigned char *verify_asc(const char *, int); /* OpenPGP */
+
+void ve_pcr_init(void);
+void ve_pcr_update(unsigned char *, size_t);
+ssize_t ve_pcr_get(unsigned char *, size_t);
+
+/* flags for verify_{asc,sig,signed} */
+#define VEF_VERBOSE		1
+
+#define VE_FINGERPRINT_OK	1
+/* errors from verify_fd */
+#define VE_FINGERPRINT_NONE	-2
+#define VE_FINGERPRINT_WRONG	-3
+#define VE_FINGERPRINT_UNKNOWN	-4	/* may not be an error */
+
+#endif	/* _LIBSECUREBOOT_H_ */

Added: head/lib/libsecureboot/h/verify_file.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libsecureboot/h/verify_file.h	Tue Feb 26 06:09:10 2019	(r344565)
@@ -0,0 +1,47 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _VERIFY_FILE_H_
+#define _VERIFY_FILE_H_
+
+#define VE_GUESS        -1           /* let verify_file work it out */
+#define VE_TRY          0            /* we don't mind if unverified */
+#define VE_WANT         1            /* we want this verified */
+#define VE_MUST         2            /* this must be verified */
+
+#define VE_VERIFIED     1            /* all good */
+#define VE_UNVERIFIED_OK 0           /* not verified but that's ok */
+#define VE_NOT_VERIFYING 2	     /* we are not verifying */
+
+struct stat;
+
+void    ve_debug_set(int);
+int     ve_status_get(int);
+int     load_manifest(const char *, const char *, const char *, struct stat *);
+int     verify_file(int, const char *, off_t, int);
+void    verify_pcr_export(void);
+
+#endif	/* _VERIFY_FILE_H_ */

Added: head/lib/libsecureboot/libsecureboot-priv.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libsecureboot/libsecureboot-priv.h	Tue Feb 26 06:09:10 2019	(r344565)
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2017, 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.
+ */
+/*
+ * $FreeBSD$
+ */
+#ifndef _LIBSECUREBOOT_PRIV_H_
+#define _LIBSECUREBOOT_PRIV_H_
+
+/* public api */
+#include "libsecureboot.h"
+
+size_t ve_trust_anchors_add(br_x509_certificate *, size_t);
+char *fingerprint_info_lookup(int, const char *);
+
+br_x509_certificate * parse_certificates(unsigned char *, size_t, size_t *);
+int  certificate_to_trust_anchor_inner(br_x509_trust_anchor *,
+    br_x509_certificate *);
+
+int verify_rsa_digest(br_rsa_public_key *pkey,
+    const unsigned char *hash_oid,
+    unsigned char *mdata, size_t mlen,
+    unsigned char *sdata, size_t slen);
+
+int openpgp_self_tests(void);
+
+#endif	/* _LIBSECUREBOOT_PRIV_H_ */

Added: head/lib/libsecureboot/local.trust.mk
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libsecureboot/local.trust.mk	Tue Feb 26 06:09:10 2019	(r344565)
@@ -0,0 +1,114 @@
+# $FreeBSD$
+
+# Consider this file an example.
+#
+# For Junos this is how we obtain trust anchor .pems
+# the signing server (http://www.crufty.net/sjg/blog/signing-server.htm)
+# for each key will provide the appropriate certificate chain on request
+
+# force these for Junos
+MANIFEST_SKIP_ALWAYS= boot
+VE_HASH_LIST= \
+	SHA1 \
+	SHA256 \
+	SHA384
+
+VE_SIGNATURE_LIST= \
+	ECDSA
+
+VE_SIGNATURE_EXT_LIST= \
+	esig
+
+VE_SELF_TESTS= yes
+
+.if ${MACHINE} == "host" && ${.CURDIR:T} == "tests"
+# for testing
+VE_HASH_LIST+= \
+	SHA512
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list