libsecureboot: allow OpenPGP support to be dormant

Since we can now add OpenPGP trust anchors at runtime,
ensure the latent support is available.

Ensure we do not add duplicate keys to trust store.

Also allow reporting names of trust anchors added/revoked

We only do this for loader and only after initializing trust store.
Thus only changes to initial trust store will be logged.

Reviewed by:	stevek
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D20700
This commit is contained in:
sjg 2019-06-26 23:33:32 +00:00
parent f18057177b
commit 10c90a3b2a
7 changed files with 240 additions and 31 deletions

View File

@ -42,6 +42,7 @@
#include <bearssl.h>
unsigned char * read_fd(int, size_t);
#ifndef NEED_BRSSL_H
unsigned char * read_file(const char *, size_t *);
#endif
@ -51,8 +52,12 @@ extern int DebugVe;
#define DEBUG_PRINTF(n, x) if (DebugVe >= n) printf x
int ve_trust_init(void);
size_t ve_trust_anchors_add_buf(unsigned char *, size_t);
size_t ve_trust_anchors_revoke(unsigned char *, size_t);
int ve_trust_add(const char *);
void ve_debug_set(int);
void ve_anchor_verbose_set(int);
int ve_anchor_verbose_get(void);
void ve_utc_set(time_t utc);
char *ve_error_get(void);
int ve_error_set(const char *, ...) __printflike(1,2);

View File

@ -56,6 +56,8 @@ int is_verified(struct stat *stp);
void add_verify_status(struct stat *stp, int status);
int openpgp_trust_init(void);
int openpgp_trust_add_buf(unsigned char *, size_t);
int openpgp_trust_revoke(const char *);
int openpgp_self_tests(void);
int efi_secure_boot_enabled(void);

View File

@ -33,6 +33,10 @@ VE_SIGNATURE_EXT_LIST+= \
sig
.endif
# add OpenPGP support - possibly dormant
VE_SIGNATURE_LIST+= OPENPGP
VE_SIGNATURE_EXT_LIST+= asc
SIGNER ?= ${SB_TOOLS_PATH:U/volume/buildtools/bin}/sign.py
.if exists(${SIGNER})
@ -42,7 +46,12 @@ 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
# deal with quirk of our .esig format
XCFLAGS.vets+= -DVE_ECDSA_HASH_AGAIN
.if !empty(OPENPGP_SIGN_URL)
XCFLAGS.opgp_key+= -DHAVE_TA_ASC_H
VE_SIGNATURE_LIST+= OPENPGP
VE_SIGNATURE_EXT_LIST+= asc

View File

@ -209,12 +209,53 @@ openpgp_trust_add(OpenPGP_key *key)
LIST_INIT(&trust_list);
}
if (key) {
DEBUG_PRINTF(2, ("openpgp_trust_add(%s)\n", key->id));
if (key && openpgp_trust_get(key->id) == NULL) {
if (ve_anchor_verbose_get())
printf("openpgp_trust_add(%s)\n", key->id);
LIST_INSERT_HEAD(&trust_list, key, entries);
}
}
/**
* @brief add trust anchor from buf
*/
int
openpgp_trust_add_buf(unsigned char *buf, size_t nbytes)
{
OpenPGP_key *key;
if ((key = load_key_buf(buf, nbytes))) {
openpgp_trust_add(key);
}
return (key != NULL);
}
/**
* @brief if keyID is in our list clobber it
*
* @return true if keyID removed
*/
int
openpgp_trust_revoke(const char *keyID)
{
OpenPGP_key *key, *tkey;
openpgp_trust_add(NULL); /* initialize if needed */
LIST_FOREACH(key, &trust_list, entries) {
if (strcmp(key->id, keyID) == 0) {
tkey = key;
LIST_REMOVE(tkey, entries);
printf("openpgp_trust_revoke(%s)\n", key->id);
memset(key, 0, sizeof(OpenPGP_key));
free(key);
return (1);
}
}
return (0);
}
/**
* @brief if keyID is in our list return the key
*
@ -251,7 +292,9 @@ load_key_file(const char *kfile)
return (key);
}
#ifdef HAVE_TA_ASC_H
#include <ta_asc.h>
#endif
#ifndef _STANDALONE
/* we can lookup keyID in filesystem */
@ -330,8 +373,8 @@ openpgp_trust_init(void)
}
}
}
}
#endif
}
return (once);
}

View File

@ -28,21 +28,13 @@ __FBSDID("$FreeBSD$");
#include <libsecureboot.h>
unsigned char *
read_file(const char *path, size_t *len)
read_fd(int fd, size_t len)
{
int fd, m, n, x;
struct stat st;
int m, n, x;
unsigned char *buf;
if (len)
*len = 0;
if ((fd = open(path, O_RDONLY)) < 0)
return (NULL);
fstat(fd, &st);
if (len)
*len = st.st_size;
buf = malloc(st.st_size + 1);
for (x = 0, m = st.st_size; m > 0; ) {
buf = malloc(len + 1);
for (x = 0, m = len; m > 0; ) {
n = read(fd, &buf[x], m);
if (n < 0)
break;
@ -51,11 +43,30 @@ read_file(const char *path, size_t *len)
x += n;
}
}
close(fd);
if (m == 0) {
buf[st.st_size] = '\0';
buf[len] = '\0';
return (buf);
}
free(buf);
return (NULL);
}
unsigned char *
read_file(const char *path, size_t *len)
{
struct stat st;
unsigned char *ucp;
int fd;
if (len)
*len = 0;
if ((fd = open(path, O_RDONLY)) < 0)
return (NULL);
fstat(fd, &st);
ucp = read_fd(fd, st.st_size);
close(fd);
if (len != NULL && ucp != NULL)
*len = st.st_size;
return (ucp);
}

View File

@ -246,7 +246,9 @@ severity_guess(const char *filename)
}
static void
verify_tweak(char *tweak, int *accept_no_fp, int *verbose, int *verifying)
verify_tweak(int fd, off_t off, struct stat *stp,
char *tweak, int *accept_no_fp,
int *verbose, int *verifying)
{
if (strcmp(tweak, "off") == 0) {
*verifying = 0;
@ -268,6 +270,25 @@ verify_tweak(char *tweak, int *accept_no_fp, int *verbose, int *verifying)
*verbose = 1;
} else if (strcmp(tweak, "quiet") == 0) {
*verbose = 0;
} else if (strncmp(tweak, "trust", 5) == 0) {
/* content is trust anchor to add or revoke */
unsigned char *ucp;
size_t num;
if (off > 0)
lseek(fd, 0, SEEK_SET);
ucp = read_fd(fd, stp->st_size);
if (ucp == NULL)
return;
if (strstr(tweak, "revoke")) {
num = ve_trust_anchors_revoke(ucp, stp->st_size);
DEBUG_PRINTF(3, ("revoked %d trust anchors\n",
(int) num));
} else {
num = ve_trust_anchors_add_buf(ucp, stp->st_size);
DEBUG_PRINTF(3, ("added %d trust anchors\n",
(int) num));
}
}
}
@ -317,8 +338,10 @@ verify_file(int fd, const char *filename, off_t off, int severity)
rc = verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING;
ve_status_set(0, rc);
ve_status_state = VE_STATUS_NONE;
if (verifying)
if (verifying) {
ve_self_tests();
ve_anchor_verbose_set(1);
}
}
if (!verifying)
return (0);
@ -367,7 +390,7 @@ verify_file(int fd, const char *filename, off_t off, int severity)
cp++;
if (strncmp(cp, "loader.ve.", 10) == 0) {
cp += 10;
verify_tweak(cp,
verify_tweak(fd, off, &st, cp,
&accept_no_fp, &verbose,
&verifying);
}

View File

@ -55,6 +55,20 @@ static anchor_list trust_anchors = VEC_INIT;
static anchor_list forbidden_anchors = VEC_INIT;
static digest_list forbidden_digests = VEC_INIT;
static int anchor_verbose = 0;
void
ve_anchor_verbose_set(int n)
{
anchor_verbose = n;
}
int
ve_anchor_verbose_get(void)
{
return (anchor_verbose);
}
void
ve_debug_set(int n)
{
@ -116,6 +130,47 @@ free_cert_contents(br_x509_certificate *xc)
xfree(xc->data);
}
/*
* a bit of a dance to get commonName from a certificate
*/
static char *
x509_cn_get(br_x509_certificate *xc, char *buf, size_t len)
{
br_x509_minimal_context mc;
br_name_element cn;
unsigned char cn_oid[4];
int err;
if (buf == NULL)
return (buf);
/*
* 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 = buf;
cn.len = len;
cn.buf[0] = '\0';
br_x509_minimal_init(&mc, &br_sha256_vtable, NULL, 0);
br_x509_minimal_set_name_elements(&mc, &cn, 1);
/* the below actually does the work - updates cn.status */
mc.vtable->start_chain(&mc.vtable, NULL);
mc.vtable->start_cert(&mc.vtable, xc->data_len);
mc.vtable->append(&mc.vtable, xc->data, xc->data_len);
mc.vtable->end_cert(&mc.vtable);
/* we don' actually care about cert status - just its name */
err = mc.vtable->end_chain(&mc.vtable);
if (!cn.status)
buf = NULL;
return (buf);
}
/* ASN parsing related defines */
#define ASN1_PRIMITIVE_TAG 0x1F
#define ASN1_INF_LENGTH 0x80
@ -184,7 +239,8 @@ ve_forbidden_digest_add(hash_data *digest, size_t num)
}
static size_t
ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors)
ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors,
char *anchors_name)
{
br_x509_trust_anchor ta;
size_t u;
@ -194,6 +250,15 @@ ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors)
break;
}
VEC_ADD(*anchors, ta);
if (anchor_verbose && anchors_name) {
char buf[64];
char *cp;
cp = x509_cn_get(&xcs[u], buf, sizeof(buf));
if (cp) {
printf("x509_anchor(%s) %s\n", cp, anchors_name);
}
}
}
return (u);
}
@ -205,13 +270,68 @@ ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors)
size_t
ve_trust_anchors_add(br_x509_certificate *xcs, size_t num)
{
return (ve_anchors_add(xcs, num, &trust_anchors));
return (ve_anchors_add(xcs, num, &trust_anchors, "trusted"));
}
size_t
ve_forbidden_anchors_add(br_x509_certificate *xcs, size_t num)
{
return (ve_anchors_add(xcs, num, &forbidden_anchors));
return (ve_anchors_add(xcs, num, &forbidden_anchors, "forbidden"));
}
/**
* @brief add trust anchors in buf
*
* Assume buf contains x509 certificates, but if not and
* we support OpenPGP try adding as that.
*
* @return number of anchors added
*/
size_t
ve_trust_anchors_add_buf(unsigned char *buf, size_t len)
{
br_x509_certificate *xcs;
size_t num;
num = 0;
xcs = parse_certificates(buf, len, &num);
if (xcs != NULL) {
num = ve_trust_anchors_add(xcs, num);
#ifdef VE_OPENPGP_SUPPORT
} else {
num = openpgp_trust_add_buf(buf, len);
#endif
}
return (num);
}
/**
* @brief revoke trust anchors in buf
*
* Assume buf contains x509 certificates, but if not and
* we support OpenPGP try revoking keyId
*
* @return number of anchors revoked
*/
size_t
ve_trust_anchors_revoke(unsigned char *buf, size_t len)
{
br_x509_certificate *xcs;
size_t num;
num = 0;
xcs = parse_certificates(buf, len, &num);
if (xcs != NULL) {
num = ve_forbidden_anchors_add(xcs, num);
#ifdef VE_OPENPGP_SUPPORT
} else {
if (buf[len - 1] == '\n')
buf[len - 1] = '\0';
num = openpgp_trust_revoke((char *)buf);
#endif
}
return (num);
}
/**
@ -221,11 +341,7 @@ ve_forbidden_anchors_add(br_x509_certificate *xcs, size_t num)
int
ve_trust_init(void)
{
#ifdef TRUST_ANCHOR_STR
br_x509_certificate *xcs;
#endif
static int once = -1;
size_t num;
if (once >= 0)
return (once);
@ -240,10 +356,8 @@ ve_trust_init(void)
#endif
#ifdef TRUST_ANCHOR_STR
xcs = parse_certificates(__DECONST(unsigned char *, TRUST_ANCHOR_STR),
sizeof(TRUST_ANCHOR_STR), &num);
if (xcs != NULL)
num = ve_trust_anchors_add(xcs, num);
ve_trust_anchors_add_buf(__DECONST(unsigned char *, TRUST_ANCHOR_STR),
sizeof(TRUST_ANCHOR_STR));
#endif
once = (int) VEC_LEN(trust_anchors);
#ifdef VE_OPENPGP_SUPPORT
@ -552,6 +666,7 @@ verify_ec(br_x509_pkey *pk, const char *file, const char *sigfile)
br_sha256_init(&ctx);
br_sha256_update(&ctx, fcp, flen);
br_sha256_out(&ctx, rhbuf);
#ifdef VE_ECDSA_HASH_AGAIN
hex = hexdigest(hexbuf, sizeof(hexbuf), rhbuf, br_sha256_SIZE);
/* now hash that */
if (hex) {
@ -559,6 +674,7 @@ verify_ec(br_x509_pkey *pk, const char *file, const char *sigfile)
br_sha256_update(&ctx, hex, strlen(hex));
br_sha256_out(&ctx, rhbuf);
}
#endif
ec = br_ec_get_default();
vrfy = br_ecdsa_vrfy_asn1_get_default();
if (!vrfy(ec, rhbuf, br_sha256_SIZE, &pk->key.ec, po->data,