xref: /freebsd/lib/libsecureboot/verify_file.c (revision f616d61ab6b071e5fbfdbae7033a9ef04c1444ad)
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