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-all
mailing list