mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-26 20:12:44 +00:00
libsecureboot do not report expected unverified files
By default only report unverified files at severity VE_WANT and above. This inlcudes *.conf but not *.hints, *.cookie or *.tgz which get VE_TRY as their severity. If Verbose is set to 0, then VerifyFlags should default to 0 too. Thus the combination of module_verbose=0 VE_VEBOSE=0 is sufficient to make the loader almost totally silent. When verify_prep has to find_manifest and it is verified ok return VE_NOT_CHECKED to verify_file so that it can skip repeating verify_fd Also add better debugging output for is_verified and add_verify_status. vectx handle compressed modules When verifying a compressed module (.ko.gz or .ko.bz2) stat() reports the size as -1 (unknown). vectx_lseek needs to spot this during closing - and just read until EOF is hit. Note: because of the way libsa's open() works, verify_prep will see the path to be verified as module.ko not module.ko.bz2 etc. This is actually ok, because we need a separate module.ko.bz2 entry so that the package can be verified, and the hash for module.ko is of the uncompressed file which is what vectx will see. Re-work local.trust.mk so site.trust.mk need only set VE_SIGN_URL_LIST (if using the mentioned signing server) interp.c: restrict interactive input Apply the same restrictions to interactive input as for unverified conf and hints files. Use version.veriexec when LOADER_VERIEXEC is yes Reviewed by: kevans Sponsored by: Juniper Networks, Inc. Differential Revision: https://reviews.freebsd.org/D43810
This commit is contained in:
parent
57e27ff07a
commit
f616d61ab6
@ -58,6 +58,10 @@ _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}
|
||||
|
||||
# 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 @@ 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
|
||||
|
||||
|
@ -46,9 +46,12 @@ manifests.h:
|
||||
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}\"
|
||||
|
@ -46,6 +46,7 @@ int verify_prep(int, const char *, off_t, struct stat *, const char *);
|
||||
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 *);
|
||||
|
@ -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
|
||||
|
||||
VE_SIGNATURE_EXT_LIST+= \
|
||||
sig
|
||||
.endif
|
||||
|
||||
# add OpenPGP support - possibly dormant
|
||||
VE_SIGNATURE_LIST+= OPENPGP
|
||||
VE_SIGNATURE_EXT_LIST+= asc
|
||||
|
||||
# allow site override of all the above
|
||||
# allow site control
|
||||
.-include "site.trust.mk"
|
||||
|
||||
SIGNER ?= ${SB_TOOLS_PATH:U/volume/buildtools/bin}/sign.py
|
||||
#VE_DEBUG_LEVEL?=3
|
||||
#VE_VERBOSE_DEFAULT?=2
|
||||
|
||||
VE_HASH_LIST?= \
|
||||
SHA256 \
|
||||
SHA384 \
|
||||
|
||||
VE_SELF_TESTS?= yes
|
||||
|
||||
# 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
|
||||
|
||||
# deal with quirk of our .esig format
|
||||
XCFLAGS.vets+= -DVE_ECDSA_HASH_AGAIN
|
||||
# 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 \
|
||||
|
||||
.if !empty(OPENPGP_SIGN_URL)
|
||||
.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
|
||||
|
||||
# cleanup duplicates
|
||||
VE_SIGNATURE_LIST:= ${VE_SIGNATURE_LIST:O:u}
|
||||
|
||||
.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 @@ ta_asc.h: vc_openpgp.asc
|
||||
.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 @@ ta_asc.h: ${TRUST_ANCHORS:M*.asc}
|
||||
# we take the mtime of this as our baseline time
|
||||
BUILD_UTC_FILE?= ${TRUST_ANCHORS:[1]}
|
||||
.endif
|
||||
|
||||
|
@ -306,19 +306,31 @@ vectx_lseek(struct vectx *ctx, off_t off, int whence)
|
||||
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);
|
||||
|
@ -82,7 +82,7 @@ static int Verbose = VE_VERBOSE_DEFAULT;
|
||||
/**
|
||||
* @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 @@ int
|
||||
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 @@ add_verify_status(struct stat *stp, int status)
|
||||
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 @@ severity_guess(const char *filename)
|
||||
/*
|
||||
* 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 @@ void
|
||||
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 @@ verify_prep(int fd, const char *filename, off_t off, struct stat *stp,
|
||||
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 @@ verify_file(int fd, const char *filename, off_t off, int severity,
|
||||
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 @@ verify_file(int fd, const char *filename, off_t off, int severity,
|
||||
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
|
||||
|
@ -35,6 +35,10 @@
|
||||
#include <string.h>
|
||||
#include "bootstrap.h"
|
||||
|
||||
#ifdef LOADER_VERIEXEC
|
||||
#include <verify_file.h>
|
||||
#endif
|
||||
|
||||
#define MAXARGS 20 /* maximum number of arguments allowed */
|
||||
|
||||
const char * volatile interp_identifier;
|
||||
@ -79,6 +83,10 @@ interact(void)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
7
stand/efi/loader/version.veriexec
Normal file
7
stand/efi/loader/version.veriexec
Normal file
@ -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.
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user