15fff9558SSimon J. Gerraty /*- 25fff9558SSimon J. Gerraty * Copyright (c) 2018, Juniper Networks, Inc. 35fff9558SSimon J. Gerraty * 45fff9558SSimon J. Gerraty * Redistribution and use in source and binary forms, with or without 55fff9558SSimon J. Gerraty * modification, are permitted provided that the following conditions 65fff9558SSimon J. Gerraty * are met: 75fff9558SSimon J. Gerraty * 1. Redistributions of source code must retain the above copyright 85fff9558SSimon J. Gerraty * notice, this list of conditions and the following disclaimer. 95fff9558SSimon J. Gerraty * 2. Redistributions in binary form must reproduce the above copyright 105fff9558SSimon J. Gerraty * notice, this list of conditions and the following disclaimer in the 115fff9558SSimon J. Gerraty * documentation and/or other materials provided with the distribution. 125fff9558SSimon J. Gerraty * 135fff9558SSimon J. Gerraty * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 145fff9558SSimon J. Gerraty * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 155fff9558SSimon J. Gerraty * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 165fff9558SSimon J. Gerraty * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 175fff9558SSimon J. Gerraty * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 185fff9558SSimon J. Gerraty * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 195fff9558SSimon J. Gerraty * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 205fff9558SSimon J. Gerraty * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 215fff9558SSimon J. Gerraty * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 225fff9558SSimon J. Gerraty * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 235fff9558SSimon J. Gerraty * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 245fff9558SSimon J. Gerraty */ 255fff9558SSimon J. Gerraty #include <sys/cdefs.h> 265fff9558SSimon J. Gerraty __FBSDID("$FreeBSD$"); 275fff9558SSimon J. Gerraty 28*53f151f9SSimon J. Gerraty #include <sys/queue.h> 295fff9558SSimon J. Gerraty #include "libsecureboot-priv.h" 305fff9558SSimon J. Gerraty 315fff9558SSimon J. Gerraty /* 325fff9558SSimon J. Gerraty * To support measured boot without putting a ton 335fff9558SSimon J. Gerraty * of extra code in the loader, we just maintain 345fff9558SSimon J. Gerraty * a hash of all the hashes we (attempt to) verify. 355fff9558SSimon J. Gerraty * The loader can export this for kernel or rc script 365fff9558SSimon J. Gerraty * to feed to a TPM pcr register - hence the name ve_pcr. 375fff9558SSimon J. Gerraty * 385fff9558SSimon J. Gerraty * NOTE: in the current standard the TPM pcr register size is for SHA1, 395fff9558SSimon J. Gerraty * the fact that we provide a SHA256 hash should not matter 405fff9558SSimon J. Gerraty * as long as we are consistent - it can be truncated or hashed 415fff9558SSimon J. Gerraty * before feeding to TPM. 425fff9558SSimon J. Gerraty */ 435fff9558SSimon J. Gerraty 445fff9558SSimon J. Gerraty static const br_hash_class *pcr_md = NULL; 455fff9558SSimon J. Gerraty static br_hash_compat_context pcr_ctx; 465fff9558SSimon J. Gerraty static size_t pcr_hlen = 0; 47*53f151f9SSimon J. Gerraty static int pcr_updating = -1; 48*53f151f9SSimon J. Gerraty 49*53f151f9SSimon J. Gerraty struct hashed_info { 50*53f151f9SSimon J. Gerraty const char *hi_path; 51*53f151f9SSimon J. Gerraty const char *hi_basename; 52*53f151f9SSimon J. Gerraty STAILQ_ENTRY(hashed_info) entries; 53*53f151f9SSimon J. Gerraty }; 54*53f151f9SSimon J. Gerraty 55*53f151f9SSimon J. Gerraty static STAILQ_HEAD(, hashed_info) hi_list; 56*53f151f9SSimon J. Gerraty 575fff9558SSimon J. Gerraty 585fff9558SSimon J. Gerraty /** 595fff9558SSimon J. Gerraty * @brief initialize pcr context 605fff9558SSimon J. Gerraty * 615fff9558SSimon J. Gerraty * Real TPM registers only hold a SHA1 hash 625fff9558SSimon J. Gerraty * but we use SHA256 635fff9558SSimon J. Gerraty */ 645fff9558SSimon J. Gerraty void 655fff9558SSimon J. Gerraty ve_pcr_init(void) 665fff9558SSimon J. Gerraty { 67*53f151f9SSimon J. Gerraty if (pcr_updating < 0) { 68980bde58SSimon J. Gerraty pcr_updating = 0; 695fff9558SSimon J. Gerraty pcr_hlen = br_sha256_SIZE; 705fff9558SSimon J. Gerraty pcr_md = &br_sha256_vtable; 715fff9558SSimon J. Gerraty pcr_md->init(&pcr_ctx.vtable); 72*53f151f9SSimon J. Gerraty STAILQ_INIT(&hi_list); 73*53f151f9SSimon J. Gerraty } 745fff9558SSimon J. Gerraty } 755fff9558SSimon J. Gerraty 765fff9558SSimon J. Gerraty /** 77980bde58SSimon J. Gerraty * @brief get pcr_updating state 78980bde58SSimon J. Gerraty */ 79980bde58SSimon J. Gerraty int 80980bde58SSimon J. Gerraty ve_pcr_updating_get(void) 81980bde58SSimon J. Gerraty { 82980bde58SSimon J. Gerraty return (pcr_updating); 83980bde58SSimon J. Gerraty } 84980bde58SSimon J. Gerraty 85980bde58SSimon J. Gerraty /** 86980bde58SSimon J. Gerraty * @brief set pcr_updating state 87980bde58SSimon J. Gerraty */ 88980bde58SSimon J. Gerraty void 89980bde58SSimon J. Gerraty ve_pcr_updating_set(int updating) 90980bde58SSimon J. Gerraty { 91980bde58SSimon J. Gerraty pcr_updating = updating; 92980bde58SSimon J. Gerraty } 93980bde58SSimon J. Gerraty 94980bde58SSimon J. Gerraty /** 955fff9558SSimon J. Gerraty * @brief update pcr context 965fff9558SSimon J. Gerraty */ 975fff9558SSimon J. Gerraty void 98*53f151f9SSimon J. Gerraty ve_pcr_update(const char *path, unsigned char *data, size_t dlen) 995fff9558SSimon J. Gerraty { 100*53f151f9SSimon J. Gerraty struct hashed_info *hip; 101*53f151f9SSimon J. Gerraty 102*53f151f9SSimon J. Gerraty if (pcr_updating > 0 && pcr_md != NULL) { 1035fff9558SSimon J. Gerraty pcr_md->update(&pcr_ctx.vtable, data, dlen); 104*53f151f9SSimon J. Gerraty /* if mallocs fail, measured boot will likely fail too */ 105*53f151f9SSimon J. Gerraty if ((hip = malloc(sizeof(struct hashed_info)))) { 106*53f151f9SSimon J. Gerraty hip->hi_path = strdup(path); 107*53f151f9SSimon J. Gerraty if (!hip->hi_path) { 108*53f151f9SSimon J. Gerraty free(hip); 109*53f151f9SSimon J. Gerraty return; 110*53f151f9SSimon J. Gerraty } 111*53f151f9SSimon J. Gerraty hip->hi_basename = strrchr(hip->hi_path, '/'); 112*53f151f9SSimon J. Gerraty if (hip->hi_basename) { 113*53f151f9SSimon J. Gerraty hip->hi_basename++; 114*53f151f9SSimon J. Gerraty } else { 115*53f151f9SSimon J. Gerraty hip->hi_basename = hip->hi_path; 116*53f151f9SSimon J. Gerraty } 117*53f151f9SSimon J. Gerraty STAILQ_INSERT_TAIL(&hi_list, hip, entries); 118*53f151f9SSimon J. Gerraty } 119*53f151f9SSimon J. Gerraty } 1205fff9558SSimon J. Gerraty } 1215fff9558SSimon J. Gerraty 1225fff9558SSimon J. Gerraty /** 1235fff9558SSimon J. Gerraty * @brief get pcr result 1245fff9558SSimon J. Gerraty */ 1255fff9558SSimon J. Gerraty ssize_t 1265fff9558SSimon J. Gerraty ve_pcr_get(unsigned char *buf, size_t sz) 1275fff9558SSimon J. Gerraty { 1285fff9558SSimon J. Gerraty if (!pcr_md) 1295fff9558SSimon J. Gerraty return (-1); 1305fff9558SSimon J. Gerraty if (sz < pcr_hlen) 1315fff9558SSimon J. Gerraty return (-1); 1325fff9558SSimon J. Gerraty pcr_md->out(&pcr_ctx.vtable, buf); 1335fff9558SSimon J. Gerraty return (pcr_hlen); 1345fff9558SSimon J. Gerraty } 1355fff9558SSimon J. Gerraty 136*53f151f9SSimon J. Gerraty /** 137*53f151f9SSimon J. Gerraty * @brief get list of paths in prc 138*53f151f9SSimon J. Gerraty */ 139*53f151f9SSimon J. Gerraty char * 140*53f151f9SSimon J. Gerraty ve_pcr_hashed_get(int flags) 141*53f151f9SSimon J. Gerraty { 142*53f151f9SSimon J. Gerraty const char *cp; 143*53f151f9SSimon J. Gerraty char *hinfo; 144*53f151f9SSimon J. Gerraty struct hashed_info *hip; 145*53f151f9SSimon J. Gerraty size_t nbytes; 146*53f151f9SSimon J. Gerraty size_t x; 147*53f151f9SSimon J. Gerraty int n; 148*53f151f9SSimon J. Gerraty 149*53f151f9SSimon J. Gerraty n = 0; 150*53f151f9SSimon J. Gerraty nbytes = x = 0; 151*53f151f9SSimon J. Gerraty hinfo = NULL; 152*53f151f9SSimon J. Gerraty STAILQ_FOREACH(hip, &hi_list, entries) { 153*53f151f9SSimon J. Gerraty nbytes += 1 + strlen(flags ? hip->hi_basename : hip->hi_path); 154*53f151f9SSimon J. Gerraty } 155*53f151f9SSimon J. Gerraty if (nbytes > 1) { 156*53f151f9SSimon J. Gerraty hinfo = malloc(nbytes + 2); 157*53f151f9SSimon J. Gerraty if (hinfo) { 158*53f151f9SSimon J. Gerraty STAILQ_FOREACH(hip, &hi_list, entries) { 159*53f151f9SSimon J. Gerraty cp = flags ? hip->hi_basename : hip->hi_path; 160*53f151f9SSimon J. Gerraty n = snprintf(&hinfo[x], nbytes - x, "%s,", cp); 161*53f151f9SSimon J. Gerraty x += n; 162*53f151f9SSimon J. Gerraty } 163*53f151f9SSimon J. Gerraty if (x > 0) { 164*53f151f9SSimon J. Gerraty hinfo[x-1] = '\0'; 165*53f151f9SSimon J. Gerraty } 166*53f151f9SSimon J. Gerraty } 167*53f151f9SSimon J. Gerraty } 168*53f151f9SSimon J. Gerraty return hinfo; 169*53f151f9SSimon J. Gerraty } 170