Index: head/lib/libsecureboot/h/libsecureboot.h =================================================================== --- head/lib/libsecureboot/h/libsecureboot.h (revision 347980) +++ head/lib/libsecureboot/h/libsecureboot.h (revision 347981) @@ -1,95 +1,97 @@ /*- * Copyright (c) 2017-2018, Juniper Networks, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * $FreeBSD$ */ #ifndef _LIBSECUREBOOT_H_ #define _LIBSECUREBOOT_H_ #include #ifdef _STANDALONE #include #else #include #include #include #include #include #include #endif #include #ifndef NEED_BRSSL_H unsigned char * read_file(const char *, size_t *); #endif extern int DebugVe; #define DEBUG_PRINTF(n, x) if (DebugVe >= n) printf x int ve_trust_init(void); int ve_trust_add(const char *); void ve_debug_set(int); void ve_utc_set(time_t utc); char *ve_error_get(void); int ve_error_set(const char *, ...) __printflike(1,2); int ve_self_tests(void); void fingerprint_info_add(const char *, const char *, const char *, const char *, struct stat *); int ve_check_hash(br_hash_compat_context *, const br_hash_class *, const char *, const char *, size_t); struct vectx; struct vectx* vectx_open(int, const char *, off_t, struct stat *, int *); ssize_t vectx_read(struct vectx *, void *, size_t); off_t vectx_lseek(struct vectx *, off_t, int); int vectx_close(struct vectx *); char * hexdigest(char *, size_t, unsigned char *, size_t); int verify_fd(int, const char *, off_t, struct stat *); int verify_open(const char *, int); unsigned char *verify_signed(const char *, int); unsigned char *verify_sig(const char *, int); unsigned char *verify_asc(const char *, int); /* OpenPGP */ void ve_pcr_init(void); void ve_pcr_update(unsigned char *, size_t); ssize_t ve_pcr_get(unsigned char *, size_t); +int ve_pcr_updating_get(void); +void ve_pcr_updating_set(int); /* flags for verify_{asc,sig,signed} */ #define VEF_VERBOSE 1 #define VE_FINGERPRINT_OK 1 #define VE_FINGERPRINT_IGNORE 2 /* errors from verify_fd */ #define VE_FINGERPRINT_NONE -2 #define VE_FINGERPRINT_WRONG -3 #define VE_FINGERPRINT_UNKNOWN -4 /* may not be an error */ #endif /* _LIBSECUREBOOT_H_ */ Index: head/lib/libsecureboot/tests/tvo.c =================================================================== --- head/lib/libsecureboot/tests/tvo.c (revision 347980) +++ head/lib/libsecureboot/tests/tvo.c (revision 347981) @@ -1,181 +1,188 @@ /* * Copyright (c) 2017-2018, Juniper Networks, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "../libsecureboot-priv.h" #include #include #include char *Skip; int main(int argc, char *argv[]) { int n; int fd; int c; int Vflag; char *cp; char *prefix; prefix = NULL; Skip = NULL; n = ve_trust_init(); printf("Trust %d\n", n); Vflag = 0; while ((c = getopt(argc, argv, "dp:s:T:V")) != -1) { switch (c) { case 'd': DebugVe++; break; case 'p': prefix = optarg; break; case 's': Skip = optarg; break; case 'T': n = ve_trust_add(optarg); printf("Local trust %s: %d\n", optarg, n); break; case 'V': Vflag = 1; break; default: errx(1, "unknown option: -%c", c); break; } } +#ifdef VE_PCR_SUPPORT + ve_pcr_updating_set(1); +#endif ve_self_tests(); for ( ; optind < argc; optind++) { if (Vflag) { /* * Simulate what loader does. * verify_file should "just work" */ fd = open(argv[optind], O_RDONLY); if (fd > 0) { /* * See if verify_file is happy */ int x; x = verify_file(fd, argv[optind], 0, VE_GUESS); printf("verify_file(%s) = %d\n", argv[optind], x); close(fd); } continue; } #ifdef VE_OPENPGP_SUPPORT if (strstr(argv[optind], "asc")) { cp = (char *)verify_asc(argv[optind], 1); if (cp) { printf("Verified: %s: %.28s...\n", argv[optind], cp); fingerprint_info_add(argv[optind], prefix, Skip, cp, NULL); } else { fprintf(stderr, "%s: %s\n", argv[optind], ve_error_get()); } } else #endif if (strstr(argv[optind], "sig")) { cp = (char *)verify_sig(argv[optind], 1); if (cp) { printf("Verified: %s: %.28s...\n", argv[optind], cp); fingerprint_info_add(argv[optind], prefix, Skip, cp, NULL); } else { fprintf(stderr, "%s: %s\n", argv[optind], ve_error_get()); } } else if (strstr(argv[optind], "manifest")) { cp = (char *)read_file(argv[optind], NULL); if (cp) { fingerprint_info_add(argv[optind], prefix, Skip, cp, NULL); } } else { fd = verify_open(argv[optind], O_RDONLY); printf("verify_open(%s) = %d %s\n", argv[optind], fd, (fd < 0) ? ve_error_get() : ""); if (fd > 0) { /* * Check that vectx_* can also verify the file. */ void *vp; char buf[BUFSIZ]; struct stat st; int error; size_t off, n; fstat(fd, &st); lseek(fd, 0, SEEK_SET); off = st.st_size % 512; vp = vectx_open(fd, argv[optind], off, &st, &error); if (!vp) { printf("vectx_open(%s) failed: %d %s\n", argv[optind], error, ve_error_get()); } else { off = vectx_lseek(vp, (st.st_size % 1024), SEEK_SET); if (off < st.st_size) { n = vectx_read(vp, buf, sizeof(buf)); if (n > 0) off += n; } off = vectx_lseek(vp, 0, SEEK_END); /* repeating that should be harmless */ off = vectx_lseek(vp, 0, SEEK_END); error = vectx_close(vp); if (error) { printf("vectx_close(%s) == %d %s\n", argv[optind], error, ve_error_get()); } else { printf("vectx_close: Verified: %s\n", argv[optind]); } } close(fd); } } } +#ifdef VE_PCR_SUPPORT + verify_pcr_export(); + printf("pcr=%s\n", getenv("loader.ve.pcr")); +#endif return (0); } Index: head/lib/libsecureboot/vepcr.c =================================================================== --- head/lib/libsecureboot/vepcr.c (revision 347980) +++ head/lib/libsecureboot/vepcr.c (revision 347981) @@ -1,84 +1,104 @@ /*- * Copyright (c) 2018, Juniper Networks, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "libsecureboot-priv.h" /* * To support measured boot without putting a ton * of extra code in the loader, we just maintain * a hash of all the hashes we (attempt to) verify. * The loader can export this for kernel or rc script * to feed to a TPM pcr register - hence the name ve_pcr. * * NOTE: in the current standard the TPM pcr register size is for SHA1, * the fact that we provide a SHA256 hash should not matter * as long as we are consistent - it can be truncated or hashed * before feeding to TPM. */ static const br_hash_class *pcr_md = NULL; static br_hash_compat_context pcr_ctx; static size_t pcr_hlen = 0; +static int pcr_updating; /** * @brief initialize pcr context * * Real TPM registers only hold a SHA1 hash * but we use SHA256 */ void ve_pcr_init(void) { + pcr_updating = 0; pcr_hlen = br_sha256_SIZE; pcr_md = &br_sha256_vtable; pcr_md->init(&pcr_ctx.vtable); } /** + * @brief get pcr_updating state + */ +int +ve_pcr_updating_get(void) +{ + return (pcr_updating); +} + +/** + * @brief set pcr_updating state + */ +void +ve_pcr_updating_set(int updating) +{ + pcr_updating = updating; +} + +/** * @brief update pcr context */ void ve_pcr_update(unsigned char *data, size_t dlen) { - if (pcr_md) + if (pcr_updating != 0 && pcr_md != NULL) pcr_md->update(&pcr_ctx.vtable, data, dlen); } /** * @brief get pcr result */ ssize_t ve_pcr_get(unsigned char *buf, size_t sz) { if (!pcr_md) return (-1); if (sz < pcr_hlen) return (-1); pcr_md->out(&pcr_ctx.vtable, buf); return (pcr_hlen); } Index: head/lib/libsecureboot/verify_file.c =================================================================== --- head/lib/libsecureboot/verify_file.c (revision 347980) +++ head/lib/libsecureboot/verify_file.c (revision 347981) @@ -1,423 +1,431 @@ /*- * Copyright (c) 2017-2018, Juniper Networks, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Routines to verify files loaded. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include "libsecureboot.h" #include #include #ifdef UNIT_TEST # include # define panic warn /* * define MANIFEST_SKIP to Skip - in tests/tvo.c so that * tvo can control the value we use in find_manifest() */ extern char *Skip; # undef MANIFEST_SKIP # define MANIFEST_SKIP Skip # undef VE_DEBUG_LEVEL #endif /* * We sometimes need to know if input is verified or not. * The extra slot is for tracking most recently opened. */ static int ve_status[SOPEN_MAX+1]; static int ve_status_state; struct verify_status; struct verify_status *verified_files = NULL; static int loaded_manifests = 0; /* have we loaded anything? */ #define VE_STATUS_NONE 1 #define VE_STATUS_VALID 2 /** * @brief set ve status for fd */ static void ve_status_set(int fd, int ves) { if (fd >= 0 && fd < SOPEN_MAX) { ve_status[fd] = ves; ve_status_state = VE_STATUS_VALID; } ve_status[SOPEN_MAX] = ves; } /** * @brief get ve status of fd * * What we return depends on ve_status_state. * * @return * @li ve_status[fd] if ve_status_state is valid * @li ve_status[SOPEN_MAX] if ve_status_state is none * @li VE_NOT_CHECKED if ve_status_state uninitialized */ int ve_status_get(int fd) { if (!ve_status_state) { return (VE_NOT_CHECKED); } if (ve_status_state == VE_STATUS_VALID && fd >= 0 && fd < SOPEN_MAX) return (ve_status[fd]); return (ve_status[SOPEN_MAX]); /* most recent */ } /** * @brief track verify status * * occasionally loader will make multiple calls * for the same file, we need only check it once. */ struct verify_status { dev_t vs_dev; ino_t vs_ino; int vs_status; struct verify_status *vs_next; }; int is_verified(struct stat *stp) { struct verify_status *vsp; 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); } return (VE_NOT_CHECKED); } /* most recent first, since most likely to see repeated calls. */ void add_verify_status(struct stat *stp, int status) { struct verify_status *vsp; vsp = malloc(sizeof(struct verify_status)); vsp->vs_next = verified_files; vsp->vs_dev = stp->st_dev; vsp->vs_ino = stp->st_ino; vsp->vs_status = status; verified_files = vsp; } /** * @brief * load specified manifest if verified */ int load_manifest(const char *name, const char *prefix, const char *skip, struct stat *stp) { struct stat st; size_t n; int rc; char *content; rc = VE_FINGERPRINT_NONE; n = strlen(name); if (n > 4) { if (!stp) { stp = &st; if (stat(name, &st) < 0 || !S_ISREG(st.st_mode)) return (rc); } rc = is_verified(stp); if (rc != VE_NOT_CHECKED) { return (rc); } /* loader has no sense of time */ ve_utc_set(stp->st_mtime); content = (char *)verify_signed(name, VEF_VERBOSE); if (content) { fingerprint_info_add(name, prefix, skip, content, stp); add_verify_status(stp, VE_VERIFIED); loaded_manifests = 1; /* we are verifying! */ DEBUG_PRINTF(3, ("loaded: %s %s %s\n", name, prefix, skip)); rc = 0; } else { rc = VE_FINGERPRINT_WRONG; add_verify_status(stp, rc); /* remember */ } } return (rc); } static int find_manifest(const char *name) { struct stat st; char buf[MAXPATHLEN]; char *prefix; char *skip; const char **tp; int rc; strncpy(buf, name, MAXPATHLEN - 1); if (!(prefix = strrchr(buf, '/'))) return (-1); *prefix = '\0'; prefix = strdup(buf); rc = VE_FINGERPRINT_NONE; for (tp = manifest_names; *tp; tp++) { snprintf(buf, sizeof(buf), "%s/%s", prefix, *tp); DEBUG_PRINTF(5, ("looking for %s\n", buf)); if (stat(buf, &st) == 0 && st.st_size > 0) { #ifdef MANIFEST_SKIP_ALWAYS /* very unlikely */ skip = MANIFEST_SKIP_ALWAYS; #else #ifdef MANIFEST_SKIP /* rare */ if (*tp[0] == '.') { skip = MANIFEST_SKIP; } else #endif skip = NULL; #endif rc = load_manifest(buf, skip ? prefix : NULL, skip, &st); break; } } free(prefix); return (rc); } #ifdef LOADER_VERIEXEC_TESTING # define ACCEPT_NO_FP_DEFAULT VE_MUST + 1 #else # define ACCEPT_NO_FP_DEFAULT VE_MUST #endif #ifndef VE_VERBOSE_DEFAULT # define VE_VERBOSE_DEFAULT 0 #endif static int severity_guess(const char *filename) { const char *cp; /* Some files like *.conf and *.hints may be unsigned */ if ((cp = strrchr(filename, '.'))) { if (strcmp(cp, ".conf") == 0 || strcmp(cp, ".cookie") == 0 || strcmp(cp, ".hints") == 0) return (VE_TRY); } return (VE_WANT); } static void verify_tweak(char *tweak, int *accept_no_fp, int *verbose, int *verifying) { if (strcmp(tweak, "off") == 0) { *verifying = 0; } else if (strcmp(tweak, "strict") == 0) { /* anything caller wants verified must be */ *accept_no_fp = VE_WANT; *verbose = 1; /* warn of anything unverified */ /* treat self test failure as fatal */ if (!ve_self_tests()) { panic("verify self tests failed"); } } else if (strcmp(tweak, "modules") == 0) { /* modules/kernel must be verified */ *accept_no_fp = VE_MUST; } else if (strcmp(tweak, "try") == 0) { /* best effort: always accept no fp */ *accept_no_fp = VE_MUST + 1; } else if (strcmp(tweak, "verbose") == 0) { *verbose = 1; } else if (strcmp(tweak, "quiet") == 0) { *verbose = 0; } } /** * @brief verify an open file * * @param[in] fd * open descriptor * * @param[in] filename * path we opened and will use to lookup fingerprint * * @param[in] off * current offset in fd, must be restored on return * * @param[in] severity * indicator of how to handle case of missing fingerprint * * We look for a signed manifest relative to the filename * just opened and verify/load it if needed. * * We then use verify_fd() in libve to actually verify that hash for * open file. If it returns < 0 we look at the severity arg to decide * what to do about it. * * If verify_fd() returns VE_FINGERPRINT_NONE we accept it if severity * is < accept_no_fp. * * @return >= 0 on success < 0 on failure */ int verify_file(int fd, const char *filename, off_t off, int severity) { static int verifying = -1; static int accept_no_fp = ACCEPT_NO_FP_DEFAULT; static int verbose = VE_VERBOSE_DEFAULT; struct stat st; char *cp; int rc; if (verifying < 0) { verifying = ve_trust_init(); #ifdef VE_DEBUG_LEVEL ve_debug_set(VE_DEBUG_LEVEL); #endif /* initialize ve_status with default result */ rc = verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING; ve_status_set(0, rc); ve_status_state = VE_STATUS_NONE; if (verifying) ve_self_tests(); } if (!verifying) return (0); if (fd < 0 || fstat(fd, &st) < 0 || !S_ISREG(st.st_mode)) return (0); DEBUG_PRINTF(3, ("fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n", fd, filename, (long long)off, (long long)st.st_dev, (long long)st.st_ino)); rc = is_verified(&st); if (rc != VE_NOT_CHECKED) { ve_status_set(fd, rc); return (rc); } rc = find_manifest(filename); if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) { if (severity <= VE_GUESS) severity = severity_guess(filename); +#ifdef VE_PCR_SUPPORT + /* + * Only update pcr with things that must verify + * these tend to be processed in a more deterministic + * order, which makes our pseudo pcr more useful. + */ + ve_pcr_updating_set((severity == VE_MUST)); +#endif if ((rc = verify_fd(fd, filename, off, &st)) >= 0) { if (verbose || severity > VE_WANT) { #if defined(VE_DEBUG_LEVEL) && VE_DEBUG_LEVEL > 0 printf("%serified %s %llu,%llu\n", (rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V", filename, (long long)st.st_dev, (long long)st.st_ino); #else printf("%serified %s\n", (rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V", filename); #endif } if (severity < VE_MUST) { /* not a kernel or module */ if ((cp = strrchr(filename, '/'))) { cp++; if (strncmp(cp, "loader.ve.", 10) == 0) { cp += 10; verify_tweak(cp, &accept_no_fp, &verbose, &verifying); } } } add_verify_status(&st, rc); ve_status_set(fd, rc); return (rc); } if (severity || verbose || rc == VE_FINGERPRINT_WRONG) printf("Unverified: %s\n", ve_error_get()); if (rc == VE_FINGERPRINT_UNKNOWN && severity < VE_MUST) rc = VE_UNVERIFIED_OK; else if (rc == VE_FINGERPRINT_NONE && severity < accept_no_fp) rc = VE_UNVERIFIED_OK; add_verify_status(&st, rc); } #ifdef LOADER_VERIEXEC_TESTING else if (rc != VE_FINGERPRINT_WRONG) { /* * We have not loaded any manifest and * not because of verication failure. * Most likely reason is we have none. * Allow boot to proceed if we are just testing. */ return (VE_UNVERIFIED_OK); } #endif if (rc == VE_FINGERPRINT_WRONG && severity > accept_no_fp) panic("cannot continue"); ve_status_set(fd, rc); return (rc); } /** * @brief get hex string for pcr value and export * * In case we are doing measured boot, provide * value of the "pcr" data we have accumulated. */ void verify_pcr_export(void) { #ifdef VE_PCR_SUPPORT char hexbuf[br_sha256_SIZE * 2 + 2]; unsigned char hbuf[br_sha256_SIZE]; char *hex; ssize_t hlen; hlen = ve_pcr_get(hbuf, sizeof(hbuf)); if (hlen > 0) { hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen); if (hex) { hex[hlen*2] = '\0'; /* clobber newline */ setenv("loader.ve.pcr", hex, 1); } } #endif }