15fff9558SSimon J. Gerraty /*-
20929924bSSimon J. Gerraty * Copyright (c) 2017-2020, 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 /*
265fff9558SSimon J. Gerraty * Routines to verify files loaded.
275fff9558SSimon J. Gerraty */
28a2f733abSWarner Losh
295fff9558SSimon J. Gerraty #include <sys/param.h>
305fff9558SSimon J. Gerraty #include <string.h>
315fff9558SSimon J. Gerraty #include <sys/queue.h>
323e6e3de0SSimon J. Gerraty #include <sys/kenv.h>
335fff9558SSimon J. Gerraty
345fff9558SSimon J. Gerraty #include "libsecureboot.h"
355fff9558SSimon J. Gerraty #include <verify_file.h>
365fff9558SSimon J. Gerraty #include <manifests.h>
375fff9558SSimon J. Gerraty
385fff9558SSimon J. Gerraty #ifdef UNIT_TEST
395fff9558SSimon J. Gerraty # include <err.h>
405fff9558SSimon J. Gerraty # define panic warn
415fff9558SSimon J. Gerraty /*
425fff9558SSimon J. Gerraty * define MANIFEST_SKIP to Skip - in tests/tvo.c so that
435fff9558SSimon J. Gerraty * tvo can control the value we use in find_manifest()
445fff9558SSimon J. Gerraty */
45afc571b1SSimon J. Gerraty extern char *Destdir;
46afc571b1SSimon J. Gerraty extern size_t DestdirLen;
475fff9558SSimon J. Gerraty extern char *Skip;
485fff9558SSimon J. Gerraty # undef MANIFEST_SKIP
495fff9558SSimon J. Gerraty # define MANIFEST_SKIP Skip
505fff9558SSimon J. Gerraty # undef VE_DEBUG_LEVEL
515fff9558SSimon J. Gerraty #endif
525fff9558SSimon J. Gerraty
535fff9558SSimon J. Gerraty /*
545fff9558SSimon J. Gerraty * We sometimes need to know if input is verified or not.
555fff9558SSimon J. Gerraty * The extra slot is for tracking most recently opened.
565fff9558SSimon J. Gerraty */
57ee6dc333SToomas Soome #ifndef SOPEN_MAX
58ee6dc333SToomas Soome #define SOPEN_MAX 64
59ee6dc333SToomas Soome #endif
605fff9558SSimon J. Gerraty static int ve_status[SOPEN_MAX+1];
615fff9558SSimon J. Gerraty static int ve_status_state;
625fff9558SSimon J. Gerraty struct verify_status;
6366655411SSimon J. Gerraty static struct verify_status *verified_files = NULL;
645fff9558SSimon J. Gerraty static int loaded_manifests = 0; /* have we loaded anything? */
655fff9558SSimon J. Gerraty
6666655411SSimon J. Gerraty enum {
6766655411SSimon J. Gerraty VE_VERBOSE_SILENT, /* only report errors */
6866655411SSimon J. Gerraty VE_VERBOSE_UNVERIFIED, /* all unverified files */
6966655411SSimon J. Gerraty VE_VERBOSE_MUST, /* report VE_MUST */
7066655411SSimon J. Gerraty VE_VERBOSE_ALL, /* report all */
7166655411SSimon J. Gerraty VE_VERBOSE_DEBUG, /* extra noise */
7266655411SSimon J. Gerraty };
7366655411SSimon J. Gerraty
7466655411SSimon J. Gerraty #ifndef VE_VERBOSE_DEFAULT
7566655411SSimon J. Gerraty # define VE_VERBOSE_DEFAULT VE_VERBOSE_MUST
7666655411SSimon J. Gerraty #endif
7766655411SSimon J. Gerraty static int Verbose = VE_VERBOSE_DEFAULT;
7866655411SSimon J. Gerraty
795fff9558SSimon J. Gerraty #define VE_STATUS_NONE 1
805fff9558SSimon J. Gerraty #define VE_STATUS_VALID 2
815fff9558SSimon J. Gerraty
825fff9558SSimon J. Gerraty /**
835fff9558SSimon J. Gerraty * @brief set ve status for fd
845fff9558SSimon J. Gerraty */
85*f616d61aSSimon J. Gerraty void
ve_status_set(int fd,int ves)865fff9558SSimon J. Gerraty ve_status_set(int fd, int ves)
875fff9558SSimon J. Gerraty {
885fff9558SSimon J. Gerraty if (fd >= 0 && fd < SOPEN_MAX) {
895fff9558SSimon J. Gerraty ve_status[fd] = ves;
905fff9558SSimon J. Gerraty ve_status_state = VE_STATUS_VALID;
915fff9558SSimon J. Gerraty }
925fff9558SSimon J. Gerraty ve_status[SOPEN_MAX] = ves;
935fff9558SSimon J. Gerraty }
945fff9558SSimon J. Gerraty
955fff9558SSimon J. Gerraty /**
965fff9558SSimon J. Gerraty * @brief get ve status of fd
975fff9558SSimon J. Gerraty *
985fff9558SSimon J. Gerraty * What we return depends on ve_status_state.
995fff9558SSimon J. Gerraty *
1005fff9558SSimon J. Gerraty * @return
1015fff9558SSimon J. Gerraty * @li ve_status[fd] if ve_status_state is valid
1025fff9558SSimon J. Gerraty * @li ve_status[SOPEN_MAX] if ve_status_state is none
1035fff9558SSimon J. Gerraty * @li VE_NOT_CHECKED if ve_status_state uninitialized
1045fff9558SSimon J. Gerraty */
1055fff9558SSimon J. Gerraty int
ve_status_get(int fd)1065fff9558SSimon J. Gerraty ve_status_get(int fd)
1075fff9558SSimon J. Gerraty {
1085fff9558SSimon J. Gerraty if (!ve_status_state) {
1095fff9558SSimon J. Gerraty return (VE_NOT_CHECKED);
1105fff9558SSimon J. Gerraty }
1115fff9558SSimon J. Gerraty if (ve_status_state == VE_STATUS_VALID &&
1125fff9558SSimon J. Gerraty fd >= 0 && fd < SOPEN_MAX)
1135fff9558SSimon J. Gerraty return (ve_status[fd]);
1145fff9558SSimon J. Gerraty return (ve_status[SOPEN_MAX]); /* most recent */
1155fff9558SSimon J. Gerraty }
1165fff9558SSimon J. Gerraty
1175fff9558SSimon J. Gerraty /**
1185fff9558SSimon J. Gerraty * @brief track verify status
1195fff9558SSimon J. Gerraty *
1205fff9558SSimon J. Gerraty * occasionally loader will make multiple calls
1215fff9558SSimon J. Gerraty * for the same file, we need only check it once.
1225fff9558SSimon J. Gerraty */
1235fff9558SSimon J. Gerraty struct verify_status {
1245fff9558SSimon J. Gerraty dev_t vs_dev;
1255fff9558SSimon J. Gerraty ino_t vs_ino;
1265fff9558SSimon J. Gerraty int vs_status;
1275fff9558SSimon J. Gerraty struct verify_status *vs_next;
1285fff9558SSimon J. Gerraty };
1295fff9558SSimon J. Gerraty
130b0fefb25SMarcin Wojtas int
is_verified(struct stat * stp)1315fff9558SSimon J. Gerraty is_verified(struct stat *stp)
1325fff9558SSimon J. Gerraty {
1335fff9558SSimon J. Gerraty struct verify_status *vsp;
134*f616d61aSSimon J. Gerraty int rc = VE_NOT_CHECKED;
1355fff9558SSimon J. Gerraty
13653f151f9SSimon J. Gerraty if (stp->st_ino > 0) {
1375fff9558SSimon J. Gerraty for (vsp = verified_files; vsp != NULL; vsp = vsp->vs_next) {
1385fff9558SSimon J. Gerraty if (stp->st_dev == vsp->vs_dev &&
139*f616d61aSSimon J. Gerraty stp->st_ino == vsp->vs_ino) {
140*f616d61aSSimon J. Gerraty rc = vsp->vs_status;
141*f616d61aSSimon J. Gerraty break;
1425fff9558SSimon J. Gerraty }
14353f151f9SSimon J. Gerraty }
144*f616d61aSSimon J. Gerraty }
145*f616d61aSSimon J. Gerraty DEBUG_PRINTF(4, ("%s: dev=%lld,ino=%llu,status=%d\n",
146*f616d61aSSimon J. Gerraty __func__, (long long)stp->st_dev,
147*f616d61aSSimon J. Gerraty (unsigned long long)stp->st_ino, rc));
148*f616d61aSSimon J. Gerraty return (rc);
1495fff9558SSimon J. Gerraty }
1505fff9558SSimon J. Gerraty
1515fff9558SSimon J. Gerraty /* most recent first, since most likely to see repeated calls. */
152b0fefb25SMarcin Wojtas void
add_verify_status(struct stat * stp,int status)1535fff9558SSimon J. Gerraty add_verify_status(struct stat *stp, int status)
1545fff9558SSimon J. Gerraty {
1555fff9558SSimon J. Gerraty struct verify_status *vsp;
1565fff9558SSimon J. Gerraty
1575fff9558SSimon J. Gerraty vsp = malloc(sizeof(struct verify_status));
15866655411SSimon J. Gerraty if (vsp) {
1595fff9558SSimon J. Gerraty vsp->vs_next = verified_files;
1605fff9558SSimon J. Gerraty vsp->vs_dev = stp->st_dev;
1615fff9558SSimon J. Gerraty vsp->vs_ino = stp->st_ino;
1625fff9558SSimon J. Gerraty vsp->vs_status = status;
1635fff9558SSimon J. Gerraty verified_files = vsp;
1645fff9558SSimon J. Gerraty }
165*f616d61aSSimon J. Gerraty DEBUG_PRINTF(4, ("%s: dev=%lld,ino=%llu,status=%d\n",
166*f616d61aSSimon J. Gerraty __func__, (long long)stp->st_dev,
167*f616d61aSSimon J. Gerraty (unsigned long long)stp->st_ino, status));
16866655411SSimon J. Gerraty }
1695fff9558SSimon J. Gerraty
1705fff9558SSimon J. Gerraty
1715fff9558SSimon J. Gerraty /**
1725fff9558SSimon J. Gerraty * @brief
1735fff9558SSimon J. Gerraty * load specified manifest if verified
1745fff9558SSimon J. Gerraty */
1755fff9558SSimon J. Gerraty int
load_manifest(const char * name,const char * prefix,const char * skip,struct stat * stp)1765fff9558SSimon J. Gerraty load_manifest(const char *name, const char *prefix,
1775fff9558SSimon J. Gerraty const char *skip, struct stat *stp)
1785fff9558SSimon J. Gerraty {
1795fff9558SSimon J. Gerraty struct stat st;
1805fff9558SSimon J. Gerraty size_t n;
1815fff9558SSimon J. Gerraty int rc;
1825fff9558SSimon J. Gerraty char *content;
1835fff9558SSimon J. Gerraty
1845fff9558SSimon J. Gerraty rc = VE_FINGERPRINT_NONE;
1855fff9558SSimon J. Gerraty n = strlen(name);
1865fff9558SSimon J. Gerraty if (n > 4) {
1875fff9558SSimon J. Gerraty if (!stp) {
1885fff9558SSimon J. Gerraty stp = &st;
1895fff9558SSimon J. Gerraty if (stat(name, &st) < 0 || !S_ISREG(st.st_mode))
1905fff9558SSimon J. Gerraty return (rc);
1915fff9558SSimon J. Gerraty }
1925fff9558SSimon J. Gerraty rc = is_verified(stp);
1935fff9558SSimon J. Gerraty if (rc != VE_NOT_CHECKED) {
1945fff9558SSimon J. Gerraty return (rc);
1955fff9558SSimon J. Gerraty }
1965fff9558SSimon J. Gerraty /* loader has no sense of time */
1975fff9558SSimon J. Gerraty ve_utc_set(stp->st_mtime);
19866655411SSimon J. Gerraty content = (char *)verify_signed(name, VerifyFlags);
1995fff9558SSimon J. Gerraty if (content) {
200afc571b1SSimon J. Gerraty #ifdef UNIT_TEST
201afc571b1SSimon J. Gerraty if (DestdirLen > 0 &&
202afc571b1SSimon J. Gerraty strncmp(name, Destdir, DestdirLen) == 0) {
203afc571b1SSimon J. Gerraty name += DestdirLen;
204afc571b1SSimon J. Gerraty if (prefix &&
205afc571b1SSimon J. Gerraty strncmp(prefix, Destdir, DestdirLen) == 0)
206afc571b1SSimon J. Gerraty prefix += DestdirLen;
207afc571b1SSimon J. Gerraty }
208afc571b1SSimon J. Gerraty #endif
2095fff9558SSimon J. Gerraty fingerprint_info_add(name, prefix, skip, content, stp);
2105fff9558SSimon J. Gerraty add_verify_status(stp, VE_VERIFIED);
2115fff9558SSimon J. Gerraty loaded_manifests = 1; /* we are verifying! */
2125fff9558SSimon J. Gerraty DEBUG_PRINTF(3, ("loaded: %s %s %s\n",
2135fff9558SSimon J. Gerraty name, prefix, skip));
214afc571b1SSimon J. Gerraty rc = VE_VERIFIED;
2155fff9558SSimon J. Gerraty } else {
2165fff9558SSimon J. Gerraty rc = VE_FINGERPRINT_WRONG;
2175fff9558SSimon J. Gerraty add_verify_status(stp, rc); /* remember */
2185fff9558SSimon J. Gerraty }
2195fff9558SSimon J. Gerraty }
2205fff9558SSimon J. Gerraty return (rc);
2215fff9558SSimon J. Gerraty }
2225fff9558SSimon J. Gerraty
2235fff9558SSimon J. Gerraty static int
find_manifest(const char * name)2245fff9558SSimon J. Gerraty find_manifest(const char *name)
2255fff9558SSimon J. Gerraty {
2265fff9558SSimon J. Gerraty struct stat st;
2275fff9558SSimon J. Gerraty char buf[MAXPATHLEN];
2285fff9558SSimon J. Gerraty char *prefix;
2295fff9558SSimon J. Gerraty char *skip;
2305fff9558SSimon J. Gerraty const char **tp;
2315fff9558SSimon J. Gerraty int rc;
2325fff9558SSimon J. Gerraty
2335fff9558SSimon J. Gerraty strncpy(buf, name, MAXPATHLEN - 1);
2345fff9558SSimon J. Gerraty if (!(prefix = strrchr(buf, '/')))
2355fff9558SSimon J. Gerraty return (-1);
2365fff9558SSimon J. Gerraty *prefix = '\0';
2375fff9558SSimon J. Gerraty prefix = strdup(buf);
2385fff9558SSimon J. Gerraty rc = VE_FINGERPRINT_NONE;
2395fff9558SSimon J. Gerraty for (tp = manifest_names; *tp; tp++) {
2405fff9558SSimon J. Gerraty snprintf(buf, sizeof(buf), "%s/%s", prefix, *tp);
24166655411SSimon J. Gerraty if (*tp[0] == '.') {
24266655411SSimon J. Gerraty /* skip /../ */
24366655411SSimon J. Gerraty if (prefix[0] == '\0' || prefix[1] == '\0')
24466655411SSimon J. Gerraty continue;
24566655411SSimon J. Gerraty }
2465fff9558SSimon J. Gerraty DEBUG_PRINTF(5, ("looking for %s\n", buf));
2475fff9558SSimon J. Gerraty if (stat(buf, &st) == 0 && st.st_size > 0) {
2485fff9558SSimon J. Gerraty #ifdef MANIFEST_SKIP_ALWAYS /* very unlikely */
2495fff9558SSimon J. Gerraty skip = MANIFEST_SKIP_ALWAYS;
2505fff9558SSimon J. Gerraty #else
2515fff9558SSimon J. Gerraty #ifdef MANIFEST_SKIP /* rare */
2525fff9558SSimon J. Gerraty if (*tp[0] == '.') {
2535fff9558SSimon J. Gerraty skip = MANIFEST_SKIP;
2545fff9558SSimon J. Gerraty } else
2555fff9558SSimon J. Gerraty #endif
2565fff9558SSimon J. Gerraty skip = NULL;
2575fff9558SSimon J. Gerraty #endif
2585fff9558SSimon J. Gerraty rc = load_manifest(buf, skip ? prefix : NULL,
2595fff9558SSimon J. Gerraty skip, &st);
2605fff9558SSimon J. Gerraty break;
2615fff9558SSimon J. Gerraty }
2625fff9558SSimon J. Gerraty }
2635fff9558SSimon J. Gerraty free(prefix);
2645fff9558SSimon J. Gerraty return (rc);
2655fff9558SSimon J. Gerraty }
2665fff9558SSimon J. Gerraty
2675fff9558SSimon J. Gerraty
2685fff9558SSimon J. Gerraty #ifdef LOADER_VERIEXEC_TESTING
2695fff9558SSimon J. Gerraty # define ACCEPT_NO_FP_DEFAULT VE_MUST + 1
2705fff9558SSimon J. Gerraty #else
2715fff9558SSimon J. Gerraty # define ACCEPT_NO_FP_DEFAULT VE_MUST
2725fff9558SSimon J. Gerraty #endif
2735fff9558SSimon J. Gerraty
2745fff9558SSimon J. Gerraty static int
severity_guess(const char * filename)2755fff9558SSimon J. Gerraty severity_guess(const char *filename)
2765fff9558SSimon J. Gerraty {
2775fff9558SSimon J. Gerraty const char *cp;
2785fff9558SSimon J. Gerraty
27966655411SSimon J. Gerraty /*
28066655411SSimon J. Gerraty * Some files like *.conf and *.hints may be unsigned,
28166655411SSimon J. Gerraty * a *.tgz is expected to have its own signed manifest.
282*f616d61aSSimon J. Gerraty * We allow *.conf to get VE_WANT, but files we expect
283*f616d61aSSimon J. Gerraty * to always be unverified get VE_TRY and we will not
284*f616d61aSSimon J. Gerraty * report them.
28566655411SSimon J. Gerraty */
2865fff9558SSimon J. Gerraty if ((cp = strrchr(filename, '.'))) {
287*f616d61aSSimon J. Gerraty if (strcmp(cp, ".cookie") == 0 ||
28866655411SSimon J. Gerraty strcmp(cp, ".hints") == 0 ||
289*f616d61aSSimon J. Gerraty strcmp(cp, ".order") == 0 ||
29066655411SSimon J. Gerraty strcmp(cp, ".tgz") == 0)
2915fff9558SSimon J. Gerraty return (VE_TRY);
2920929924bSSimon J. Gerraty if (strcmp(cp, ".4th") == 0 ||
2930929924bSSimon J. Gerraty strcmp(cp, ".lua") == 0 ||
2940929924bSSimon J. Gerraty strcmp(cp, ".rc") == 0)
2950929924bSSimon J. Gerraty return (VE_MUST);
2965fff9558SSimon J. Gerraty }
2975fff9558SSimon J. Gerraty return (VE_WANT);
2985fff9558SSimon J. Gerraty }
2995fff9558SSimon J. Gerraty
300afc571b1SSimon J. Gerraty static int Verifying = -1; /* 0 if not verifying */
301afc571b1SSimon J. Gerraty
3025fff9558SSimon J. Gerraty static void
verify_tweak(int fd,off_t off,struct stat * stp,char * tweak,int * accept_no_fp)303f9510887SSimon J. Gerraty verify_tweak(int fd, off_t off, struct stat *stp,
30466655411SSimon J. Gerraty char *tweak, int *accept_no_fp)
3055fff9558SSimon J. Gerraty {
3065fff9558SSimon J. Gerraty if (strcmp(tweak, "off") == 0) {
307afc571b1SSimon J. Gerraty Verifying = 0;
3085fff9558SSimon J. Gerraty } else if (strcmp(tweak, "strict") == 0) {
3095fff9558SSimon J. Gerraty /* anything caller wants verified must be */
3105fff9558SSimon J. Gerraty *accept_no_fp = VE_WANT;
31166655411SSimon J. Gerraty Verbose = VE_VERBOSE_ALL;
3125fff9558SSimon J. Gerraty /* treat self test failure as fatal */
3135fff9558SSimon J. Gerraty if (!ve_self_tests()) {
3145fff9558SSimon J. Gerraty panic("verify self tests failed");
3155fff9558SSimon J. Gerraty }
3165fff9558SSimon J. Gerraty } else if (strcmp(tweak, "modules") == 0) {
3175fff9558SSimon J. Gerraty /* modules/kernel must be verified */
3185fff9558SSimon J. Gerraty *accept_no_fp = VE_MUST;
3195fff9558SSimon J. Gerraty } else if (strcmp(tweak, "try") == 0) {
3205fff9558SSimon J. Gerraty /* best effort: always accept no fp */
3215fff9558SSimon J. Gerraty *accept_no_fp = VE_MUST + 1;
3225fff9558SSimon J. Gerraty } else if (strcmp(tweak, "verbose") == 0) {
32366655411SSimon J. Gerraty Verbose = VE_VERBOSE_ALL;
3245fff9558SSimon J. Gerraty } else if (strcmp(tweak, "quiet") == 0) {
32566655411SSimon J. Gerraty Verbose = VE_VERBOSE_UNVERIFIED;
32666655411SSimon J. Gerraty VerifyFlags = 0;
32766655411SSimon J. Gerraty } else if (strcmp(tweak, "silent") == 0) {
32866655411SSimon J. Gerraty Verbose = VE_VERBOSE_SILENT;
32966655411SSimon J. Gerraty VerifyFlags = 0;
330f9510887SSimon J. Gerraty } else if (strncmp(tweak, "trust", 5) == 0) {
331f9510887SSimon J. Gerraty /* content is trust anchor to add or revoke */
332f9510887SSimon J. Gerraty unsigned char *ucp;
333f9510887SSimon J. Gerraty size_t num;
334f9510887SSimon J. Gerraty
335f9510887SSimon J. Gerraty if (off > 0)
336f9510887SSimon J. Gerraty lseek(fd, 0, SEEK_SET);
337f9510887SSimon J. Gerraty ucp = read_fd(fd, stp->st_size);
338f9510887SSimon J. Gerraty if (ucp == NULL)
339f9510887SSimon J. Gerraty return;
340f9510887SSimon J. Gerraty if (strstr(tweak, "revoke")) {
341f9510887SSimon J. Gerraty num = ve_trust_anchors_revoke(ucp, stp->st_size);
342f9510887SSimon J. Gerraty DEBUG_PRINTF(3, ("revoked %d trust anchors\n",
343f9510887SSimon J. Gerraty (int) num));
344f9510887SSimon J. Gerraty } else {
345f9510887SSimon J. Gerraty num = ve_trust_anchors_add_buf(ucp, stp->st_size);
346f9510887SSimon J. Gerraty DEBUG_PRINTF(3, ("added %d trust anchors\n",
347f9510887SSimon J. Gerraty (int) num));
348f9510887SSimon J. Gerraty }
3495fff9558SSimon J. Gerraty }
3505fff9558SSimon J. Gerraty }
3515fff9558SSimon J. Gerraty
35218e2fbc0SSimon J. Gerraty #ifndef VE_DEBUG_LEVEL
35318e2fbc0SSimon J. Gerraty # define VE_DEBUG_LEVEL 0
35418e2fbc0SSimon J. Gerraty #endif
35518e2fbc0SSimon J. Gerraty
35618e2fbc0SSimon J. Gerraty static int
getenv_int(const char * var,int def)35718e2fbc0SSimon J. Gerraty getenv_int(const char *var, int def)
35818e2fbc0SSimon J. Gerraty {
35918e2fbc0SSimon J. Gerraty const char *cp;
36018e2fbc0SSimon J. Gerraty char *ep;
36118e2fbc0SSimon J. Gerraty long val;
36218e2fbc0SSimon J. Gerraty
36318e2fbc0SSimon J. Gerraty val = def;
36418e2fbc0SSimon J. Gerraty cp = getenv(var);
36518e2fbc0SSimon J. Gerraty if (cp && *cp) {
36618e2fbc0SSimon J. Gerraty val = strtol(cp, &ep, 0);
36718e2fbc0SSimon J. Gerraty if ((ep && *ep) || val != (int)val) {
36818e2fbc0SSimon J. Gerraty val = def;
36918e2fbc0SSimon J. Gerraty }
37018e2fbc0SSimon J. Gerraty }
37118e2fbc0SSimon J. Gerraty return (int)val;
37218e2fbc0SSimon J. Gerraty }
37318e2fbc0SSimon J. Gerraty
374afc571b1SSimon J. Gerraty
375afc571b1SSimon J. Gerraty /**
37666655411SSimon J. Gerraty * @brief report verification status
37766655411SSimon J. Gerraty *
37866655411SSimon J. Gerraty * @param[in] path
37966655411SSimon J. Gerraty * path we attempted to verify
38066655411SSimon J. Gerraty *
38166655411SSimon J. Gerraty * @param[in] severity
38266655411SSimon J. Gerraty * indicator of how to handle case of missing fingerprint
38366655411SSimon J. Gerraty *
38466655411SSimon J. Gerraty * @param[in] status
38566655411SSimon J. Gerraty * result of verification
38666655411SSimon J. Gerraty * 0 not a file to be verified, > 0 success, < 0 error
38766655411SSimon J. Gerraty *
38866655411SSimon J. Gerraty * @param[in] stp
38966655411SSimon J. Gerraty * pointer to struct stat, used in extra info to be output
39066655411SSimon J. Gerraty *
39166655411SSimon J. Gerraty * The output is dictated by combinations of the above and the setting
39266655411SSimon J. Gerraty * of Verbose:
39366655411SSimon J. Gerraty *
39466655411SSimon J. Gerraty * VE_VERBOSE_SILENT
39566655411SSimon J. Gerraty * report only failure to verify if severity is VE_WANT or higher.
39666655411SSimon J. Gerraty *
39766655411SSimon J. Gerraty * VE_VERBOSE_UNVERIFIED
39866655411SSimon J. Gerraty * report any unverified file.
39966655411SSimon J. Gerraty *
40066655411SSimon J. Gerraty * VE_VERBOSE_MUST
40166655411SSimon J. Gerraty * report verified only if severity is VE_MUST or higher.
40266655411SSimon J. Gerraty *
40366655411SSimon J. Gerraty * VE_VERBOSE_ALL
40466655411SSimon J. Gerraty * report all verified files.
40566655411SSimon J. Gerraty *
40666655411SSimon J. Gerraty * VE_VERBOSE_DEBUG
40766655411SSimon J. Gerraty * if stp is not NULL report dev,inode for path
40866655411SSimon J. Gerraty */
40966655411SSimon J. Gerraty void
verify_report(const char * path,int severity,int status,struct stat * stp)41066655411SSimon J. Gerraty verify_report(const char *path, int severity, int status, struct stat *stp)
41166655411SSimon J. Gerraty {
41266655411SSimon J. Gerraty if (status < 0 || status == VE_FINGERPRINT_IGNORE) {
413*f616d61aSSimon J. Gerraty if (Verbose < VE_VERBOSE_ALL && severity < VE_WANT)
414*f616d61aSSimon J. Gerraty return;
41566655411SSimon J. Gerraty if (Verbose >= VE_VERBOSE_UNVERIFIED || severity > VE_TRY ||
41666655411SSimon J. Gerraty status <= VE_FINGERPRINT_WRONG) {
41766655411SSimon J. Gerraty if (Verbose == VE_VERBOSE_DEBUG && stp != NULL)
41866655411SSimon J. Gerraty printf("Unverified %s %llu,%llu\n",
41966655411SSimon J. Gerraty ve_error_get(),
42066655411SSimon J. Gerraty (long long)stp->st_dev,
42166655411SSimon J. Gerraty (long long)stp->st_ino);
42266655411SSimon J. Gerraty else
42366655411SSimon J. Gerraty printf("Unverified %s\n", ve_error_get());
42466655411SSimon J. Gerraty }
42566655411SSimon J. Gerraty } else if (status > 0 && Verbose >= VE_VERBOSE_MUST) {
42666655411SSimon J. Gerraty if (severity >= VE_MUST || Verbose >= VE_VERBOSE_ALL) {
42766655411SSimon J. Gerraty if (Verbose == VE_VERBOSE_DEBUG && stp != NULL)
42866655411SSimon J. Gerraty printf("Unverified %s %llu,%llu\n",
42966655411SSimon J. Gerraty path,
43066655411SSimon J. Gerraty (long long)stp->st_dev,
43166655411SSimon J. Gerraty (long long)stp->st_ino);
43266655411SSimon J. Gerraty else
43366655411SSimon J. Gerraty printf("Verified %s\n", path);
43466655411SSimon J. Gerraty }
43566655411SSimon J. Gerraty }
43666655411SSimon J. Gerraty }
43766655411SSimon J. Gerraty
43866655411SSimon J. Gerraty
43966655411SSimon J. Gerraty /**
440afc571b1SSimon J. Gerraty * @brief prepare to verify an open file
441afc571b1SSimon J. Gerraty *
442afc571b1SSimon J. Gerraty * @param[in] fd
443afc571b1SSimon J. Gerraty * open descriptor
444afc571b1SSimon J. Gerraty *
445afc571b1SSimon J. Gerraty * @param[in] filename
446afc571b1SSimon J. Gerraty * path we opened and will use to lookup fingerprint
447afc571b1SSimon J. Gerraty *
448afc571b1SSimon J. Gerraty * @param[in] stp
449afc571b1SSimon J. Gerraty * stat pointer so we can check file type
450afc571b1SSimon J. Gerraty */
451afc571b1SSimon J. Gerraty int
verify_prep(int fd,const char * filename,off_t off,struct stat * stp,const char * caller)452afc571b1SSimon J. Gerraty verify_prep(int fd, const char *filename, off_t off, struct stat *stp,
453afc571b1SSimon J. Gerraty const char *caller)
454afc571b1SSimon J. Gerraty {
455afc571b1SSimon J. Gerraty int rc;
456afc571b1SSimon J. Gerraty
457afc571b1SSimon J. Gerraty if (Verifying < 0) {
458afc571b1SSimon J. Gerraty Verifying = ve_trust_init();
459afc571b1SSimon J. Gerraty /* initialize ve_status with default result */
460afc571b1SSimon J. Gerraty rc = Verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING;
461afc571b1SSimon J. Gerraty ve_status_set(0, rc);
462afc571b1SSimon J. Gerraty ve_status_state = VE_STATUS_NONE;
463afc571b1SSimon J. Gerraty if (Verifying) {
464afc571b1SSimon J. Gerraty ve_self_tests();
465afc571b1SSimon J. Gerraty ve_anchor_verbose_set(1);
466afc571b1SSimon J. Gerraty }
467afc571b1SSimon J. Gerraty }
468afc571b1SSimon J. Gerraty if (!Verifying || fd < 0)
469afc571b1SSimon J. Gerraty return (0);
470afc571b1SSimon J. Gerraty if (stp) {
471afc571b1SSimon J. Gerraty if (fstat(fd, stp) < 0 || !S_ISREG(stp->st_mode))
472afc571b1SSimon J. Gerraty return (0);
473afc571b1SSimon J. Gerraty }
474afc571b1SSimon J. Gerraty DEBUG_PRINTF(2,
47566655411SSimon J. Gerraty ("verify_prep: caller=%s,fd=%d,name='%s',off=%lld,dev=%lld,ino=%llu\n",
476afc571b1SSimon J. Gerraty caller, fd, filename, (long long)off, (long long)stp->st_dev,
47766655411SSimon J. Gerraty (unsigned long long)stp->st_ino));
478afc571b1SSimon J. Gerraty rc = is_verified(stp);
479afc571b1SSimon J. Gerraty if (rc == VE_NOT_CHECKED) {
480afc571b1SSimon J. Gerraty rc = find_manifest(filename);
481*f616d61aSSimon J. Gerraty if (rc == VE_VERIFIED)
482*f616d61aSSimon J. Gerraty rc = VE_NOT_CHECKED;
483afc571b1SSimon J. Gerraty } else {
484afc571b1SSimon J. Gerraty ve_status_set(fd, rc);
485afc571b1SSimon J. Gerraty }
486afc571b1SSimon J. Gerraty return (rc);
487afc571b1SSimon J. Gerraty }
488afc571b1SSimon J. Gerraty
4895fff9558SSimon J. Gerraty /**
4905fff9558SSimon J. Gerraty * @brief verify an open file
4915fff9558SSimon J. Gerraty *
4925fff9558SSimon J. Gerraty * @param[in] fd
4935fff9558SSimon J. Gerraty * open descriptor
4945fff9558SSimon J. Gerraty *
4955fff9558SSimon J. Gerraty * @param[in] filename
4965fff9558SSimon J. Gerraty * path we opened and will use to lookup fingerprint
4975fff9558SSimon J. Gerraty *
4985fff9558SSimon J. Gerraty * @param[in] off
4995fff9558SSimon J. Gerraty * current offset in fd, must be restored on return
5005fff9558SSimon J. Gerraty *
5015fff9558SSimon J. Gerraty * @param[in] severity
5025fff9558SSimon J. Gerraty * indicator of how to handle case of missing fingerprint
5035fff9558SSimon J. Gerraty *
5045fff9558SSimon J. Gerraty * We look for a signed manifest relative to the filename
5055fff9558SSimon J. Gerraty * just opened and verify/load it if needed.
5065fff9558SSimon J. Gerraty *
5075fff9558SSimon J. Gerraty * We then use verify_fd() in libve to actually verify that hash for
5085fff9558SSimon J. Gerraty * open file. If it returns < 0 we look at the severity arg to decide
5095fff9558SSimon J. Gerraty * what to do about it.
5105fff9558SSimon J. Gerraty *
5115fff9558SSimon J. Gerraty * If verify_fd() returns VE_FINGERPRINT_NONE we accept it if severity
5125fff9558SSimon J. Gerraty * is < accept_no_fp.
5135fff9558SSimon J. Gerraty *
5145fff9558SSimon J. Gerraty * @return >= 0 on success < 0 on failure
5155fff9558SSimon J. Gerraty */
5165fff9558SSimon J. Gerraty int
verify_file(int fd,const char * filename,off_t off,int severity,const char * caller)517afc571b1SSimon J. Gerraty verify_file(int fd, const char *filename, off_t off, int severity,
518afc571b1SSimon J. Gerraty const char *caller)
5195fff9558SSimon J. Gerraty {
52066655411SSimon J. Gerraty static int check_verbose = 1;
5215fff9558SSimon J. Gerraty static int accept_no_fp = ACCEPT_NO_FP_DEFAULT;
5225fff9558SSimon J. Gerraty struct stat st;
5235fff9558SSimon J. Gerraty char *cp;
5245fff9558SSimon J. Gerraty int rc;
5255fff9558SSimon J. Gerraty
52666655411SSimon J. Gerraty if (check_verbose) {
52766655411SSimon J. Gerraty check_verbose = 0;
52866655411SSimon J. Gerraty Verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT);
529*f616d61aSSimon J. Gerraty VerifyFlags = getenv_int("VE_VERIFY_FLAGS",
530*f616d61aSSimon J. Gerraty Verbose ? VEF_VERBOSE : 0);
53166655411SSimon J. Gerraty #ifndef UNIT_TEST
53266655411SSimon J. Gerraty ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL));
53366655411SSimon J. Gerraty #endif
53466655411SSimon J. Gerraty }
53566655411SSimon J. Gerraty
536afc571b1SSimon J. Gerraty rc = verify_prep(fd, filename, off, &st, caller);
537afc571b1SSimon J. Gerraty
538afc571b1SSimon J. Gerraty if (!rc)
539afc571b1SSimon J. Gerraty return (0);
540afc571b1SSimon J. Gerraty
5415fff9558SSimon J. Gerraty if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) {
542*f616d61aSSimon J. Gerraty if (rc != VE_NOT_CHECKED)
543*f616d61aSSimon J. Gerraty return (rc);
544*f616d61aSSimon J. Gerraty
5455fff9558SSimon J. Gerraty if (severity <= VE_GUESS)
5465fff9558SSimon J. Gerraty severity = severity_guess(filename);
547980bde58SSimon J. Gerraty #ifdef VE_PCR_SUPPORT
548980bde58SSimon J. Gerraty /*
549980bde58SSimon J. Gerraty * Only update pcr with things that must verify
550980bde58SSimon J. Gerraty * these tend to be processed in a more deterministic
551980bde58SSimon J. Gerraty * order, which makes our pseudo pcr more useful.
552980bde58SSimon J. Gerraty */
553980bde58SSimon J. Gerraty ve_pcr_updating_set((severity == VE_MUST));
554980bde58SSimon J. Gerraty #endif
555afc571b1SSimon J. Gerraty #ifdef UNIT_TEST
556afc571b1SSimon J. Gerraty if (DestdirLen > 0 &&
557afc571b1SSimon J. Gerraty strncmp(filename, Destdir, DestdirLen) == 0) {
558afc571b1SSimon J. Gerraty filename += DestdirLen;
559afc571b1SSimon J. Gerraty }
560afc571b1SSimon J. Gerraty #endif
56166655411SSimon J. Gerraty rc = verify_fd(fd, filename, off, &st);
56266655411SSimon J. Gerraty verify_report(filename, severity, rc, &st);
56366655411SSimon J. Gerraty if (rc >= 0) {
5645fff9558SSimon J. Gerraty if (severity < VE_MUST) { /* not a kernel or module */
5655fff9558SSimon J. Gerraty if ((cp = strrchr(filename, '/'))) {
5665fff9558SSimon J. Gerraty cp++;
5675fff9558SSimon J. Gerraty if (strncmp(cp, "loader.ve.", 10) == 0) {
5685fff9558SSimon J. Gerraty cp += 10;
569f9510887SSimon J. Gerraty verify_tweak(fd, off, &st, cp,
57066655411SSimon J. Gerraty &accept_no_fp);
5715fff9558SSimon J. Gerraty }
5725fff9558SSimon J. Gerraty }
5735fff9558SSimon J. Gerraty }
5745fff9558SSimon J. Gerraty add_verify_status(&st, rc);
5755fff9558SSimon J. Gerraty ve_status_set(fd, rc);
5765fff9558SSimon J. Gerraty return (rc);
5775fff9558SSimon J. Gerraty }
5785fff9558SSimon J. Gerraty if (rc == VE_FINGERPRINT_UNKNOWN && severity < VE_MUST)
5795fff9558SSimon J. Gerraty rc = VE_UNVERIFIED_OK;
5805fff9558SSimon J. Gerraty else if (rc == VE_FINGERPRINT_NONE && severity < accept_no_fp)
5815fff9558SSimon J. Gerraty rc = VE_UNVERIFIED_OK;
5825fff9558SSimon J. Gerraty
5835fff9558SSimon J. Gerraty add_verify_status(&st, rc);
58466655411SSimon J. Gerraty
58566655411SSimon J. Gerraty /* recheck debug/verbose level next time we are called */
58666655411SSimon J. Gerraty if (rc == VE_UNVERIFIED_OK) {
58766655411SSimon J. Gerraty check_verbose = 1;
58866655411SSimon J. Gerraty }
5895fff9558SSimon J. Gerraty }
5905fff9558SSimon J. Gerraty #ifdef LOADER_VERIEXEC_TESTING
5915fff9558SSimon J. Gerraty else if (rc != VE_FINGERPRINT_WRONG) {
5925fff9558SSimon J. Gerraty /*
5935fff9558SSimon J. Gerraty * We have not loaded any manifest and
5945fff9558SSimon J. Gerraty * not because of verication failure.
5955fff9558SSimon J. Gerraty * Most likely reason is we have none.
5965fff9558SSimon J. Gerraty * Allow boot to proceed if we are just testing.
5975fff9558SSimon J. Gerraty */
5985fff9558SSimon J. Gerraty return (VE_UNVERIFIED_OK);
5995fff9558SSimon J. Gerraty }
6005fff9558SSimon J. Gerraty #endif
6015fff9558SSimon J. Gerraty if (rc == VE_FINGERPRINT_WRONG && severity > accept_no_fp)
6025fff9558SSimon J. Gerraty panic("cannot continue");
6035fff9558SSimon J. Gerraty ve_status_set(fd, rc);
6045fff9558SSimon J. Gerraty return (rc);
6055fff9558SSimon J. Gerraty }
6065fff9558SSimon J. Gerraty
6075fff9558SSimon J. Gerraty /**
6085fff9558SSimon J. Gerraty * @brief get hex string for pcr value and export
6095fff9558SSimon J. Gerraty *
6105fff9558SSimon J. Gerraty * In case we are doing measured boot, provide
6115fff9558SSimon J. Gerraty * value of the "pcr" data we have accumulated.
6125fff9558SSimon J. Gerraty */
6135fff9558SSimon J. Gerraty void
verify_pcr_export(void)6145fff9558SSimon J. Gerraty verify_pcr_export(void)
6155fff9558SSimon J. Gerraty {
6165fff9558SSimon J. Gerraty #ifdef VE_PCR_SUPPORT
6175fff9558SSimon J. Gerraty char hexbuf[br_sha256_SIZE * 2 + 2];
6185fff9558SSimon J. Gerraty unsigned char hbuf[br_sha256_SIZE];
61953f151f9SSimon J. Gerraty char *hinfo;
6205fff9558SSimon J. Gerraty char *hex;
6215fff9558SSimon J. Gerraty ssize_t hlen;
6225fff9558SSimon J. Gerraty
6235fff9558SSimon J. Gerraty hlen = ve_pcr_get(hbuf, sizeof(hbuf));
6245fff9558SSimon J. Gerraty if (hlen > 0) {
6255fff9558SSimon J. Gerraty hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen);
6265fff9558SSimon J. Gerraty if (hex) {
6275fff9558SSimon J. Gerraty hex[hlen*2] = '\0'; /* clobber newline */
6285fff9558SSimon J. Gerraty setenv("loader.ve.pcr", hex, 1);
62953f151f9SSimon J. Gerraty DEBUG_PRINTF(1,
63053f151f9SSimon J. Gerraty ("%s: setenv(loader.ve.pcr, %s\n", __func__,
63153f151f9SSimon J. Gerraty hex));
63253f151f9SSimon J. Gerraty hinfo = ve_pcr_hashed_get(1);
63353f151f9SSimon J. Gerraty if (hinfo) {
63453f151f9SSimon J. Gerraty setenv("loader.ve.hashed", hinfo, 1);
63553f151f9SSimon J. Gerraty DEBUG_PRINTF(1,
63653f151f9SSimon J. Gerraty ("%s: setenv(loader.ve.hashed, %s\n",
63753f151f9SSimon J. Gerraty __func__, hinfo));
6383e6e3de0SSimon J. Gerraty if ((hlen = strlen(hinfo)) > KENV_MVALLEN) {
6393e6e3de0SSimon J. Gerraty /*
6403e6e3de0SSimon J. Gerraty * bump kenv_mvallen
6413e6e3de0SSimon J. Gerraty * roundup to multiple of KENV_MVALLEN
6423e6e3de0SSimon J. Gerraty */
6433e6e3de0SSimon J. Gerraty char mvallen[16];
6443e6e3de0SSimon J. Gerraty
6453e6e3de0SSimon J. Gerraty hlen += KENV_MVALLEN -
6463e6e3de0SSimon J. Gerraty (hlen % KENV_MVALLEN);
6473e6e3de0SSimon J. Gerraty if (snprintf(mvallen, sizeof(mvallen),
64866655411SSimon J. Gerraty "%d", (int) hlen) < (int)sizeof(mvallen))
6493e6e3de0SSimon J. Gerraty setenv("kenv_mvallen", mvallen, 1);
6503e6e3de0SSimon J. Gerraty }
65153f151f9SSimon J. Gerraty free(hinfo);
65253f151f9SSimon J. Gerraty }
6535fff9558SSimon J. Gerraty }
6545fff9558SSimon J. Gerraty }
6555fff9558SSimon J. Gerraty #endif
6565fff9558SSimon J. Gerraty }
65766655411SSimon J. Gerraty
65866655411SSimon J. Gerraty /*
65966655411SSimon J. Gerraty * For tftp and http we need to hash pathname
66066655411SSimon J. Gerraty * to be able to fake stat(2) data.
66166655411SSimon J. Gerraty */
66266655411SSimon J. Gerraty int
hash_string(char * s,size_t n,char * buf,size_t bufsz)66366655411SSimon J. Gerraty hash_string(char *s, size_t n, char *buf, size_t bufsz)
66466655411SSimon J. Gerraty {
66566655411SSimon J. Gerraty br_hash_compat_context mctx;
66666655411SSimon J. Gerraty const br_hash_class *md;
66766655411SSimon J. Gerraty
66866655411SSimon J. Gerraty switch (bufsz) {
66966655411SSimon J. Gerraty case br_sha1_SIZE:
67066655411SSimon J. Gerraty md = &br_sha1_vtable;
67166655411SSimon J. Gerraty break;
67266655411SSimon J. Gerraty case br_sha256_SIZE:
67366655411SSimon J. Gerraty md = &br_sha256_vtable;
67466655411SSimon J. Gerraty break;
67566655411SSimon J. Gerraty default:
67666655411SSimon J. Gerraty if (bufsz < br_sha1_SIZE)
67766655411SSimon J. Gerraty return -1;
67866655411SSimon J. Gerraty md = &br_sha1_vtable;
67966655411SSimon J. Gerraty bufsz = br_sha1_SIZE;
68066655411SSimon J. Gerraty break;
68166655411SSimon J. Gerraty }
68266655411SSimon J. Gerraty if (n == 0)
68366655411SSimon J. Gerraty n = strlen(s);
68466655411SSimon J. Gerraty md->init(&mctx.vtable);
68566655411SSimon J. Gerraty md->update(&mctx.vtable, s, n);
68666655411SSimon J. Gerraty md->out(&mctx.vtable, buf);
68766655411SSimon J. Gerraty return bufsz;
68866655411SSimon J. Gerraty }
68966655411SSimon J. Gerraty
69066655411SSimon J. Gerraty
691