diff --git a/lib/libsecureboot/h/libsecureboot.h b/lib/libsecureboot/h/libsecureboot.h index 81984fde5f3e..d7d72e880744 100644 --- a/lib/libsecureboot/h/libsecureboot.h +++ b/lib/libsecureboot/h/libsecureboot.h @@ -42,6 +42,7 @@ #include +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); diff --git a/lib/libsecureboot/libsecureboot-priv.h b/lib/libsecureboot/libsecureboot-priv.h index c6a90d2c7404..bdf0c5c0c9bb 100644 --- a/lib/libsecureboot/libsecureboot-priv.h +++ b/lib/libsecureboot/libsecureboot-priv.h @@ -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); diff --git a/lib/libsecureboot/local.trust.mk b/lib/libsecureboot/local.trust.mk index 4ba4c862e929..b28e5ee2d1ef 100644 --- a/lib/libsecureboot/local.trust.mk +++ b/lib/libsecureboot/local.trust.mk @@ -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 diff --git a/lib/libsecureboot/openpgp/opgp_key.c b/lib/libsecureboot/openpgp/opgp_key.c index dc0d8fa2934d..c108cd2fa328 100644 --- a/lib/libsecureboot/openpgp/opgp_key.c +++ b/lib/libsecureboot/openpgp/opgp_key.c @@ -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 +#endif #ifndef _STANDALONE /* we can lookup keyID in filesystem */ @@ -330,8 +373,8 @@ openpgp_trust_init(void) } } } - } #endif + } return (once); } diff --git a/lib/libsecureboot/readfile.c b/lib/libsecureboot/readfile.c index f632922143ce..ff9f9f6f6d60 100644 --- a/lib/libsecureboot/readfile.c +++ b/lib/libsecureboot/readfile.c @@ -28,21 +28,13 @@ __FBSDID("$FreeBSD$"); #include 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); +} + diff --git a/lib/libsecureboot/verify_file.c b/lib/libsecureboot/verify_file.c index e8b00451133f..bb092dda2ed2 100644 --- a/lib/libsecureboot/verify_file.c +++ b/lib/libsecureboot/verify_file.c @@ -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); } diff --git a/lib/libsecureboot/vets.c b/lib/libsecureboot/vets.c index 73e3db7722d5..87fb190577eb 100644 --- a/lib/libsecureboot/vets.c +++ b/lib/libsecureboot/vets.c @@ -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,