libsecureboot: make it easier to customize trust anchors

Avoid making hash self-tests depend on X.509 certs.
Include OpenPGP keys in trust store count.

Reviewed by:	stevek
MFC after:	1 week
Sponsored by:	Juniper Networks
Differential Revision:	https://reviews.freebsd.org/D20208
This commit is contained in:
sjg 2019-05-09 22:25:12 +00:00
parent 78ed458c48
commit 6e6b09f5c1
7 changed files with 111 additions and 73 deletions

View File

@ -98,10 +98,20 @@ CFLAGS+= ${VE_HASH_LIST:@H@-DVE_$H_SUPPORT@} \
.if ${VE_SELF_TESTS} != "no"
# The input used for hash KATs
# we use a string by default so it is independent of any other test
VE_HASH_KAT_STRLEN?= strlen
.if ${VE_HASH_KAT_STRLEN} == "strlen"
VE_HASH_KAT_STR?= self-tests-are-good
VE_HASH_KAT_STR_INPUT= echo -n
XCFLAGS.vets+= -DVE_HASH_KAT_STR=\"${VE_HASH_KAT_STR}\"
.else
VE_HASH_KAT_STR?= vc_PEM
VE_HASH_KAT_STR_INPUT= cat
VE_HASH_KAT_STRLEN= sizeof
XCFLAGS.vets+= -DVE_HASH_KAT_STR=${VE_HASH_KAT_STR}
.endif
XCFLAGS.vets+= -DVE_HASH_KAT_STRLEN=${VE_HASH_KAT_STRLEN}
.endif
# this should be updated occassionally this is 2019-01-01Z
SOURCE_DATE_EPOCH?= 1546329600
@ -121,17 +131,20 @@ BUILD_UTC?= ${${STAT:Ustat} -f %m ${BUILD_UTC_FILE}:L:sh}
# 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
# Finally we generate a hash of VE_HASH_KAT_STR
# using each supported hash method
# to use as a Known Answer Test (needed for FIPS 140-2)
#
TA_PEM_LIST ?= ${.ALLSRC:N*crl*:Mt*.pem}
VC_PEM_LIST ?= ${.ALLSRC:N*crl*:Mv*.pem}
vets.o vets.po vets.pico: ta.h
ta.h: ${.ALLTARGETS:M[tv]*pem:O:u}
ta.h:
@( echo '/* Autogenerated - DO NOT EDIT!!! */'; echo; \
cat ${.ALLSRC:N*crl*:Mt*.pem} /dev/null | \
cat ${TA_PEM_LIST:O:u} /dev/null | \
file2c -sx 'static const char ta_PEM[] = {' '};'; \
echo "${.newline}${VE_HASH_LIST:@H@static char vh_$H[] = \"`cat ${.ALLSRC:N*crl*:Mv*.pem} | ${$H:U${H:tl}}`\";${.newline}@}"; ) > ${.TARGET}
echo "${.newline}${VE_HASH_LIST:O:u:@H@static char vh_$H[] = \"`${VE_HASH_KAT_STR_INPUT} ${VE_HASH_KAT_STR} | ${$H:U${H:tl}}`\";${.newline}@}"; ) > ${.TARGET}
.if ${VE_SELF_TESTS} != "no"
( cat ${.ALLSRC:N*crl*:Mv*.pem} /dev/null | \
( cat ${VC_PEM_LIST:O:u} /dev/null | \
file2c -sx 'static const char vc_PEM[] = {' '};'; echo ) >> ${.TARGET}
.endif
echo '#define BUILD_UTC ${BUILD_UTC}' >> ${.TARGET} ${.OODATE:MNOMETA_CMP}
@ -141,7 +154,7 @@ 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 '${VE_SIGNATURE_EXT_LIST:O:u:@e@"$e",${.newline}@}'; \
echo 'NULL };' ) > ${.TARGET}

View File

@ -55,6 +55,7 @@ int verify_rsa_digest(br_rsa_public_key *pkey,
int is_verified(struct stat *stp);
void add_verify_status(struct stat *stp, int status);
int openpgp_trust_init(void);
int openpgp_self_tests(void);
int efi_secure_boot_enabled(void);

View File

@ -51,7 +51,7 @@ SIGN_OPENPGP= ${PYTHON} ${SIGNER:H}/openpgp-sign.py -a -u ${OPENPGP_SIGN_URL}
ta_openpgp.asc:
${SIGN_OPENPGP} -C ${.TARGET}
ta.h: ta_openpgp.asc
ta_asc.h: ta_openpgp.asc
.if ${VE_SELF_TESTS} != "no"
# for self test
@ -59,7 +59,7 @@ vc_openpgp.asc: ta_openpgp.asc
${SIGN_OPENPGP} ${.ALLSRC:M*.asc}
mv ta_openpgp.asc.asc ${.TARGET}
ta.h: vc_openpgp.asc
ta_asc.h: vc_openpgp.asc
.endif
.endif
@ -72,17 +72,20 @@ ecerts.pem:
.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

View File

@ -24,25 +24,28 @@ opgp_key.o opgp_key.po opgp_key.pico: ta_asc.h
# the appropriate t*.asc so that the relative order of vc_ASC
# entries matches ta_ASC.
#
ta_asc.h: ${.ALLTARGETS:M[tv]*.asc:O:u}
TA_ASC_LIST ?= ${.ALLSRC:Mt*.asc}
VC_ASC_LIST ?= ${.ALLSRC:Mv*.asc}
ta_asc.h:
.if ${VE_SIGNATURE_LIST:MOPENPGP} != ""
@( echo '/* Autogenerated - DO NOT EDIT!!! */'; echo; \
echo "#define HAVE_TA_ASC 1"; \
set -- ${.ALLSRC:Mt*.asc:@f@$f ${f:T:R}@}; \
set -- ${TA_ASC_LIST:@f@$f ${f:T:R}@}; \
while test $$# -ge 2; do \
file2c -sx "static const char $$2[] = {" ', 0x00 };' < $$1; \
shift 2; \
done; \
echo 'static const char *ta_ASC[] = { ${.ALLSRC:Mt*.asc:T:R:ts,}, NULL };'; \
echo 'static const char *ta_ASC[] = { ${TA_ASC_LIST:T:R:ts,}, NULL };'; \
echo; ) > ${.TARGET}
.if ${VE_SELF_TESTS} != "no"
@( echo "#define HAVE_VC_ASC 1"; \
set -- ${.ALLSRC:Mv*.asc:@f@$f ${f:T:R}@}; \
set -- ${VC_ASC_LIST:@f@$f ${f:T:R}@}; \
while test $$# -ge 2; do \
file2c -sx "static const char $$2[] = {" ', 0x00 };' < $$1; \
shift 2; \
done; \
echo 'static const char *vc_ASC[] = { ${.ALLSRC:Mv*.asc:T:R:ts,}, NULL };'; \
echo 'static const char *vc_ASC[] = { ${VC_ASC_LIST:T:R:ts,}, NULL };'; \
echo; ) >> ${.TARGET}
.endif
.endif

View File

@ -289,26 +289,8 @@ load_trusted_key_id(const char *keyID)
OpenPGP_key *
load_key_id(const char *keyID)
{
static int once = 0;
OpenPGP_key *key;
if (!once) {
#ifdef HAVE_TA_ASC
const char **tp;
char *cp;
size_t n;
for (tp = ta_ASC; *tp; tp++) {
if ((cp = strdup(*tp))) {
n = strlen(cp);
key = load_key_buf((unsigned char *)cp, n);
free(cp);
openpgp_trust_add(key);
}
}
#endif
once = 1;
}
key = openpgp_trust_get(keyID);
#ifndef _STANDALONE
if (!key)
@ -317,6 +299,39 @@ load_key_id(const char *keyID)
return (key);
}
/**
* @brief initialize our internal trust store if any
*/
int
openpgp_trust_init(void)
{
static int once = -1;
#ifdef HAVE_TA_ASC
OpenPGP_key *key;
const char **tp;
char *cp;
size_t n;
#endif
if (once < 0) {
once = 0;
#ifdef HAVE_TA_ASC
for (tp = ta_ASC; *tp; tp++) {
if ((cp = strdup(*tp))) {
n = strlen(cp);
key = load_key_buf((unsigned char *)cp, n);
free(cp);
if (key) {
openpgp_trust_add(key);
once++;
}
}
}
}
#endif
return (once);
}
/**
* @brief test that we can verify a signature
*
@ -333,19 +348,21 @@ openpgp_self_tests(void)
char *fdata, *sdata = NULL;
size_t fbytes, sbytes;
for (tp = ta_ASC, vp = vc_ASC; *tp && *vp && rc; tp++, vp++) {
if ((fdata = strdup(*tp)) &&
(sdata = strdup(*vp))) {
fbytes = strlen(fdata);
sbytes = strlen(sdata);
rc = openpgp_verify("ta_ASC",
(unsigned char *)fdata, fbytes,
(unsigned char *)sdata, sbytes, 0);
printf("Testing verify OpenPGP signature:\t\t%s\n",
rc ? "Failed" : "Passed");
if (openpgp_trust_init() > 0) {
for (tp = ta_ASC, vp = vc_ASC; *tp && *vp && rc; tp++, vp++) {
if ((fdata = strdup(*tp)) &&
(sdata = strdup(*vp))) {
fbytes = strlen(fdata);
sbytes = strlen(sdata);
rc = openpgp_verify("ta_ASC",
(unsigned char *)fdata, fbytes,
(unsigned char *)sdata, sbytes, 0);
printf("Testing verify OpenPGP signature:\t\t%s\n",
rc ? "Failed" : "Passed");
}
free(fdata);
free(sdata);
}
free(fdata);
free(sdata);
}
#endif
return (rc);

View File

@ -13,6 +13,7 @@ NO_SHARED=
# we want to test verify_file api too
# which requires a kludge or two
MK_LOADER_EFI_SECUREBOOT= no
.include "../Makefile.libsa.inc"
BRSSL_CFLAGS := ${BRSSL_CFLAGS:N-DNO_STDIO}
XCFLAGS.verify_file += -DSOPEN_MAX=64

View File

@ -246,7 +246,9 @@ ve_trust_init(void)
num = ve_trust_anchors_add(xcs, num);
#endif
once = (int) VEC_LEN(trust_anchors);
#ifdef VE_OPENPGP_SUPPORT
once += openpgp_trust_init();
#endif
return (once);
}
@ -814,7 +816,7 @@ test_hash(const br_hash_class *md, size_t hlen,
#define ve_test_hash(n, N) \
printf("Testing hash: " #n "\t\t\t\t%s\n", \
test_hash(&br_ ## n ## _vtable, br_ ## n ## _SIZE, #n, \
VE_HASH_KAT_STR, sizeof(VE_HASH_KAT_STR), \
VE_HASH_KAT_STR, VE_HASH_KAT_STRLEN(VE_HASH_KAT_STR), \
vh_ ## N) ? "Failed" : "Passed")
/**
@ -863,34 +865,32 @@ ve_self_tests(void)
#ifdef VERIFY_CERTS_STR
xcs = parse_certificates(__DECONST(unsigned char *, VERIFY_CERTS_STR),
sizeof(VERIFY_CERTS_STR), &num);
if (xcs == NULL)
return (0);
/*
* We want the commonName field
* the OID we want is 2,5,4,3 - but DER encoded
*/
cn_oid[0] = 3;
cn_oid[1] = 0x55;
cn_oid[2] = 4;
cn_oid[3] = 3;
cn.oid = cn_oid;
cn.buf = cn_buf;
if (xcs != NULL) {
/*
* We want the commonName field
* the OID we want is 2,5,4,3 - but DER encoded
*/
cn_oid[0] = 3;
cn_oid[1] = 0x55;
cn_oid[2] = 4;
cn_oid[3] = 3;
cn.oid = cn_oid;
cn.buf = cn_buf;
for (u = 0; u < num; u ++) {
cn.len = sizeof(cn_buf);
if ((pk = verify_signer_xcs(&xcs[u], 1, &cn, 1, &trust_anchors)) != NULL) {
free_cert_contents(&xcs[u]);
once++;
printf("Testing verify certificate: %s\tPassed\n",
cn.status ? cn_buf : "");
xfreepkey(pk);
for (u = 0; u < num; u ++) {
cn.len = sizeof(cn_buf);
if ((pk = verify_signer_xcs(&xcs[u], 1, &cn, 1, &trust_anchors)) != NULL) {
free_cert_contents(&xcs[u]);
once++;
printf("Testing verify certificate: %s\tPassed\n",
cn.status ? cn_buf : "");
xfreepkey(pk);
}
}
if (!once)
printf("Testing verify certificate:\t\t\tFailed\n");
xfree(xcs);
}
if (!once)
printf("Testing verify certificate:\t\t\tFailed\n");
xfree(xcs);
#else
printf("No X.509 self tests\n");
#endif /* VERIFY_CERTS_STR */
#ifdef VE_OPENPGP_SUPPORT
if (!openpgp_self_tests())