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:
parent
84322e3ee3
commit
f9510887ee
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user