diff --git a/lib/libsecureboot/Makefile.inc b/lib/libsecureboot/Makefile.inc --- a/lib/libsecureboot/Makefile.inc +++ b/lib/libsecureboot/Makefile.inc @@ -58,6 +58,10 @@ 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} +# 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" + # list of hashes we support VE_HASH_LIST?= SHA256 @@ -74,10 +78,6 @@ # 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 diff --git a/lib/libsecureboot/Makefile.libsa.inc b/lib/libsecureboot/Makefile.libsa.inc --- a/lib/libsecureboot/Makefile.libsa.inc +++ b/lib/libsecureboot/Makefile.libsa.inc @@ -46,9 +46,12 @@ echo '${VE_MANIFEST_LIST:@m@"$m",${.newline}@}'; \ echo 'NULL };' ) > ${.TARGET} +# only add these if set XCFLAGS.verify_file+= \ - -DVE_DEBUG_LEVEL=${VE_DEBUG_LEVEL:U0} \ - -DVE_VERBOSE_DEFAULT=${VE_VERBOSE_DEFAULT:U0} \ + ${VE_DEBUG_LEVEL \ + VE_VERBOSE_DEFAULT \ + VE_VERIFY_FLAGS \ + :L:@v@${$v:S,^,-D$v=,}@} .if !empty(MANIFEST_SKIP_ALWAYS) XCFLAGS.verify_file+= -DMANIFEST_SKIP_ALWAYS=\"${MANIFEST_SKIP_ALWAYS}\" diff --git a/lib/libsecureboot/h/verify_file.h b/lib/libsecureboot/h/verify_file.h --- a/lib/libsecureboot/h/verify_file.h +++ b/lib/libsecureboot/h/verify_file.h @@ -46,6 +46,7 @@ void ve_debug_set(int); char *ve_error_get(void); void ve_efi_init(void); +void ve_status_set(int, int); int ve_status_get(int); int load_manifest(const char *, const char *, const char *, struct stat *); int pass_manifest(const char *, const char *); diff --git a/lib/libsecureboot/local.trust.mk b/lib/libsecureboot/local.trust.mk --- a/lib/libsecureboot/local.trust.mk +++ b/lib/libsecureboot/local.trust.mk @@ -5,65 +5,69 @@ # 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 \ - SHA512 - -VE_SIGNATURE_LIST= \ - ECDSA \ - RSA - -VE_SIGNATURE_EXT_LIST= \ - esig \ - rsig - -VE_SELF_TESTS= yes - -.if ${MACHINE} == "host" && ${.CURDIR:T} == "tests" - -VE_SIGNATURE_LIST+= \ - DEPRECATED_RSA_SHA1 +# allow site control +.-include "site.trust.mk" -VE_SIGNATURE_EXT_LIST+= \ - sig -.endif +#VE_DEBUG_LEVEL?=3 +#VE_VERBOSE_DEFAULT?=2 -# add OpenPGP support - possibly dormant -VE_SIGNATURE_LIST+= OPENPGP -VE_SIGNATURE_EXT_LIST+= asc +VE_HASH_LIST?= \ + SHA256 \ + SHA384 \ -# allow site override of all the above -.-include "site.trust.mk" +VE_SELF_TESTS?= yes -SIGNER ?= ${SB_TOOLS_PATH:U/volume/buildtools/bin}/sign.py +# client for the signing server above +SIGNER?= /opt/sigs/sign.py .if exists(${SIGNER}) -SIGN_HOST ?= ${SB_SITE:Usvl}-junos-signer.juniper.net -ECDSA_PORT:= ${133%y:L:gmtime} -SIGN_ECDSA= ${PYTHON} ${SIGNER} -u ${SIGN_HOST}:${ECDSA_PORT} -h sha256 -RSA2_PORT:= ${163%y:L:gmtime} -SIGN_RSA2= ${PYTHON} ${SIGNER} -u ${SIGN_HOST}:${RSA2_PORT} -h sha256 +OPENPGP_SIGNER?= ${SIGNER:H}/openpgp-sign.py +OPENPGP_SIGN_FLAGS= -a +OPENPGP_SIGN_HOST?= localhost +SIGN_HOST ?= localhost + +# A list of name/ext/url tuples. +# name should be one of ECDSA, OPENPGP or RSA, they can be repeated +# Order of ext list implies runtime preference so do not sort! +VE_SIGN_URL_LIST?= \ + ECDSA/esig/${SIGN_HOST}:${133%y:L:localtime} \ + RSA/rsig/${SIGN_HOST}:${163%y:L:localtime} \ + OPENPGP/asc/${OPENPGP_SIGN_HOST}:1234 \ + +.for sig ext url in ${VE_SIGN_URL_LIST:@x@${x:H:H} ${x:H:T} ${x:T}@} +SIGN_${sig}:= ${PYTHON} ${${sig}_SIGNER:U${SIGNER}} -u ${url} ${${sig}_SIGN_FLAGS:U-h sha256} + +VE_SIGNATURE_LIST+= ${sig} +VE_SIGNATURE_EXT_LIST+= ${ext} + +_SIGN_${sig}_USE: .USE + ${SIGN_${sig}} ${.ALLSRC} + +_TA_${sig}_USE: .USE + ${SIGN_${sig}} -C ${.TARGET} + +.if ${sig} == "OPENPGP" +ta_${sig:tl}.${ext}: _TA_${sig}_USE +ta_${ext}.h: ta_${sig:tl}.${ext} +.else +${ext:S/sig/certs/}.pem: _TA_${sig}_USE +# the last cert in the chain is the one we want +ta_${ext}.pem: ${ext:S/sig/certs/}.pem _LAST_PEM_USE +ta.h: ta_${ext}.pem +.if ${VE_SELF_TESTS} != "no" +# we use the 2nd last cert to test verification +vc_${ext}.pem: ${ext:S/sig/certs/}.pem _2ndLAST_PEM_USE +ta.h: vc_${ext}.pem +.endif +.endif +.endfor -# deal with quirk of our .esig format -XCFLAGS.vets+= -DVE_ECDSA_HASH_AGAIN +# cleanup duplicates +VE_SIGNATURE_LIST:= ${VE_SIGNATURE_LIST:O:u} -.if !empty(OPENPGP_SIGN_URL) +.if target(ta_asc.h) XCFLAGS.opgp_key+= -DHAVE_TA_ASC_H -VE_SIGNATURE_LIST+= OPENPGP -VE_SIGNATURE_EXT_LIST+= asc - -SIGN_OPENPGP= ${PYTHON} ${SIGNER:H}/openpgp-sign.py -a -u ${OPENPGP_SIGN_URL} - -ta_openpgp.asc: - ${SIGN_OPENPGP} -C ${.TARGET} - -ta_asc.h: ta_openpgp.asc - .if ${VE_SELF_TESTS} != "no" # for self test vc_openpgp.asc: ta_openpgp.asc @@ -74,48 +78,26 @@ .endif .endif -rcerts.pem: - ${SIGN_RSA2} -C ${.TARGET} - -ecerts.pem: - ${SIGN_ECDSA} -C ${.TARGET} - -.if ${VE_SIGNATURE_LIST:tu:MECDSA} != "" -# the last cert in the chain is the one we want -ta_ec.pem: ecerts.pem _LAST_PEM_USE -ta.h: ta_ec.pem -.if ${VE_SELF_TESTS} != "no" -# these are for verification self test -vc_ec.pem: ecerts.pem _2ndLAST_PEM_USE -ta.h: vc_ec.pem -.endif -.endif - -.if ${VE_SIGNATURE_LIST:tu:MRSA} != "" -ta_rsa.pem: rcerts.pem _LAST_PEM_USE -ta.h: ta_rsa.pem -.if ${VE_SELF_TESTS} != "no" -vc_rsa.pem: rcerts.pem _2ndLAST_PEM_USE -ta.h: vc_rsa.pem -.endif -.endif - -# we take the mtime of this as our baseline time -#BUILD_UTC_FILE= ecerts.pem -#VE_DEBUG_LEVEL=3 -#VE_VERBOSE_DEFAULT=1 - .else +VE_SIGNATURE_LIST?= RSA + # you need to provide t*.pem or t*.asc files for each trust anchor +# below assumes they are named ta_${ext}.pem eg ta_esig.pem for ECDSA .if empty(TRUST_ANCHORS) TRUST_ANCHORS!= cd ${.CURDIR} && 'ls' -1 *.pem t*.asc 2> /dev/null .endif .if empty(TRUST_ANCHORS) && ${MK_LOADER_EFI_SECUREBOOT} != "yes" .error Need TRUST_ANCHORS see ${.PARSEDIR}/README.rst .endif + .if ${TRUST_ANCHORS:T:Mt*.pem} != "" ta.h: ${TRUST_ANCHORS:M*.pem} +VE_SIGNATURE_EXT_LIST?= ${TRUST_ANCHORS:T:Mt*.pem:R:S/ta_//} +.if ${VE_SIGNATURE_EXT_LIST:Mesig} != "" +VE_SIGNATURE_LIST+= ECDSA +.endif .endif + .if ${TRUST_ANCHORS:T:Mt*.asc} != "" VE_SIGNATURE_LIST+= OPENPGP VE_SIGNATURE_EXT_LIST+= asc @@ -124,4 +106,3 @@ # we take the mtime of this as our baseline time BUILD_UTC_FILE?= ${TRUST_ANCHORS:[1]} .endif - diff --git a/lib/libsecureboot/vectx.c b/lib/libsecureboot/vectx.c --- a/lib/libsecureboot/vectx.c +++ b/lib/libsecureboot/vectx.c @@ -306,19 +306,31 @@ DEBUG_PRINTF(3, ("%s(%s, %ld, %d)\n", __func__, ctx->vec_path, (long)off, whence)); if (whence == SEEK_END && off <= 0) { - if (ctx->vec_closing && ctx->vec_hashed < ctx->vec_size) { - DEBUG_PRINTF(3, ("%s: SEEK_END %ld\n", - __func__, - (long)(ctx->vec_size - ctx->vec_hashed))); + if (ctx->vec_size < 0) { + if (ctx->vec_closing) { + /* size unknown - read until EOF */ + do { + n = vectx_read(ctx, buf, PAGE_SIZE); + if (n < 0) + return (n); + } while (n > 0); + return (ctx->vec_off); + } + } else { + if (ctx->vec_closing && ctx->vec_hashed < ctx->vec_size) { + DEBUG_PRINTF(3, ("%s: SEEK_END %ld\n", + __func__, + (long)(ctx->vec_size - ctx->vec_hashed))); + } + whence = SEEK_SET; + off += ctx->vec_size; } - whence = SEEK_SET; - off += ctx->vec_size; } else if (whence == SEEK_CUR) { whence = SEEK_SET; off += ctx->vec_off; } if (whence != SEEK_SET || - off > ctx->vec_size) { + (off > ctx->vec_size && ctx->vec_size > 0)) { printf("ERROR: %s: unsupported operation: whence=%d off=%ld -> %ld\n", __func__, whence, (long)ctx->vec_off, (long)off); return (-1); diff --git a/lib/libsecureboot/verify_file.c b/lib/libsecureboot/verify_file.c --- a/lib/libsecureboot/verify_file.c +++ b/lib/libsecureboot/verify_file.c @@ -82,7 +82,7 @@ /** * @brief set ve status for fd */ -static void +void ve_status_set(int fd, int ves) { if (fd >= 0 && fd < SOPEN_MAX) { @@ -131,15 +131,21 @@ is_verified(struct stat *stp) { struct verify_status *vsp; + int rc = VE_NOT_CHECKED; if (stp->st_ino > 0) { for (vsp = verified_files; vsp != NULL; vsp = vsp->vs_next) { if (stp->st_dev == vsp->vs_dev && - stp->st_ino == vsp->vs_ino) - return (vsp->vs_status); + stp->st_ino == vsp->vs_ino) { + rc = vsp->vs_status; + break; + } } } - return (VE_NOT_CHECKED); + DEBUG_PRINTF(4, ("%s: dev=%lld,ino=%llu,status=%d\n", + __func__, (long long)stp->st_dev, + (unsigned long long)stp->st_ino, rc)); + return (rc); } /* most recent first, since most likely to see repeated calls. */ @@ -156,6 +162,9 @@ vsp->vs_status = status; verified_files = vsp; } + DEBUG_PRINTF(4, ("%s: dev=%lld,ino=%llu,status=%d\n", + __func__, (long long)stp->st_dev, + (unsigned long long)stp->st_ino, status)); } @@ -270,11 +279,14 @@ /* * Some files like *.conf and *.hints may be unsigned, * a *.tgz is expected to have its own signed manifest. + * We allow *.conf to get VE_WANT, but files we expect + * to always be unverified get VE_TRY and we will not + * report them. */ if ((cp = strrchr(filename, '.'))) { - if (strcmp(cp, ".conf") == 0 || - strcmp(cp, ".cookie") == 0 || + if (strcmp(cp, ".cookie") == 0 || strcmp(cp, ".hints") == 0 || + strcmp(cp, ".order") == 0 || strcmp(cp, ".tgz") == 0) return (VE_TRY); if (strcmp(cp, ".4th") == 0 || @@ -398,6 +410,8 @@ verify_report(const char *path, int severity, int status, struct stat *stp) { if (status < 0 || status == VE_FINGERPRINT_IGNORE) { + if (Verbose < VE_VERBOSE_ALL && severity < VE_WANT) + return; if (Verbose >= VE_VERBOSE_UNVERIFIED || severity > VE_TRY || status <= VE_FINGERPRINT_WRONG) { if (Verbose == VE_VERBOSE_DEBUG && stp != NULL) @@ -462,9 +476,10 @@ caller, fd, filename, (long long)off, (long long)stp->st_dev, (unsigned long long)stp->st_ino)); rc = is_verified(stp); - DEBUG_PRINTF(4,("verify_prep: is_verified()->%d\n", rc)); if (rc == VE_NOT_CHECKED) { rc = find_manifest(filename); + if (rc == VE_VERIFIED) + rc = VE_NOT_CHECKED; } else { ve_status_set(fd, rc); } @@ -511,7 +526,8 @@ if (check_verbose) { check_verbose = 0; Verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT); - VerifyFlags = getenv_int("VE_VERIFY_FLAGS", VEF_VERBOSE); + VerifyFlags = getenv_int("VE_VERIFY_FLAGS", + Verbose ? VEF_VERBOSE : 0); #ifndef UNIT_TEST ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL)); #endif @@ -523,6 +539,9 @@ return (0); if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) { + if (rc != VE_NOT_CHECKED) + return (rc); + if (severity <= VE_GUESS) severity = severity_guess(filename); #ifdef VE_PCR_SUPPORT diff --git a/stand/common/interp.c b/stand/common/interp.c --- a/stand/common/interp.c +++ b/stand/common/interp.c @@ -35,6 +35,10 @@ #include #include "bootstrap.h" +#ifdef LOADER_VERIEXEC +#include +#endif + #define MAXARGS 20 /* maximum number of arguments allowed */ const char * volatile interp_identifier; @@ -79,6 +83,10 @@ input[0] = '\0'; interp_emit_prompt(); ngets(input, sizeof(input)); +#ifdef LOADER_VERIEXEC + /* some settings should be restritcted */ + ve_status_set(-1, VE_UNVERIFIED_OK); +#endif interp_run(input); } } diff --git a/stand/efi/loader/version.veriexec b/stand/efi/loader/version.veriexec new file mode 100644 --- /dev/null +++ b/stand/efi/loader/version.veriexec @@ -0,0 +1,7 @@ +NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this +file is important. Make sure the current version number is on line 6. + +2.1: SMBIOS 3 support +2.0: Secure boot support +1.1: Keep in sync with i386 version. +0.1: Initial i386 version. Derived from ia64. diff --git a/stand/veriexec.mk b/stand/veriexec.mk --- a/stand/veriexec.mk +++ b/stand/veriexec.mk @@ -1,4 +1,7 @@ .if ${MK_LOADER_VERIEXEC} != "no" +.if exists(${VERSION_FILE}.veriexec) +VERSION_FILE:= ${VERSION_FILE}.veriexec +.endif CFLAGS+= -DLOADER_VERIEXEC -I${SRCTOP}/lib/libsecureboot/h .if ${MK_LOADER_VERIEXEC_VECTX} != "no" CFLAGS+= -DLOADER_VERIEXEC_VECTX