2 * Copyright (c) 2017-2018, Juniper Networks, Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 #include <sys/cdefs.h>
26 __FBSDID("$FreeBSD$");
27 #include <sys/queue.h>
29 #include "libsecureboot-priv.h"
32 struct fingerprint_info {
33 char *fi_prefix; /**< manifest entries relative to */
34 char *fi_skip; /**< manifest entries prefixed with */
35 const char *fi_data; /**< manifest data */
36 size_t fi_prefix_len; /**< length of prefix */
37 size_t fi_skip_len; /**< length of skip */
38 dev_t fi_dev; /**< device id */
39 LIST_ENTRY(fingerprint_info) entries;
42 static LIST_HEAD(, fingerprint_info) fi_list;
45 fingerprint_info_init(void)
57 * add manifest data to list
59 * list is kept sorted by longest prefix.
62 * path that all manifest entries are resolved via
65 * optional prefix within manifest entries which should be skipped
71 fingerprint_info_add(const char *filename, const char *prefix,
72 const char *skip, const char *data, struct stat *stp)
74 struct fingerprint_info *fip, *nfip, *lfip;
78 fingerprint_info_init();
79 nfip = malloc(sizeof(struct fingerprint_info));
82 printf("%s: out of memory! %lu\n", __func__,
83 (unsigned long)sizeof(struct fingerprint_info));
88 nfip->fi_prefix = strdup(prefix);
94 nfip->fi_prefix = strdup(filename);
95 cp = strrchr(nfip->fi_prefix, '/');
96 if (cp == nfip->fi_prefix) {
101 free(nfip->fi_prefix);
106 /* collapse any trailing ..[/] */
108 while ((cp = strrchr(nfip->fi_prefix, '/')) > nfip->fi_prefix) {
109 if (cp[1] == '\0') { /* trailing "/" */
113 if (strcmp(&cp[1], "..") == 0) {
125 nfip->fi_dev = stp->st_dev;
129 nfip->fi_data = data;
130 nfip->fi_prefix_len = strlen(nfip->fi_prefix);
132 nfip->fi_skip_len = strlen(skip);
133 if (nfip->fi_skip_len)
134 nfip->fi_skip = strdup(skip);
136 nfip->fi_skip = NULL;
138 nfip->fi_skip = NULL;
139 nfip->fi_skip_len = 0;
142 if (LIST_EMPTY(&fi_list)) {
143 LIST_INSERT_HEAD(&fi_list, nfip, entries);
144 DEBUG_PRINTF(4, ("inserted %zu %s at head\n",
145 nfip->fi_prefix_len, nfip->fi_prefix));
148 LIST_FOREACH(fip, &fi_list, entries) {
149 if (nfip->fi_prefix_len >= fip->fi_prefix_len) {
150 LIST_INSERT_BEFORE(fip, nfip, entries);
151 DEBUG_PRINTF(4, ("inserted %zu %s before %zu %s\n",
152 nfip->fi_prefix_len, nfip->fi_prefix,
153 fip->fi_prefix_len, fip->fi_prefix));
158 LIST_INSERT_AFTER(lfip, nfip, entries);
159 DEBUG_PRINTF(4, ("inserted %zu %s after %zu %s\n",
160 nfip->fi_prefix_len, nfip->fi_prefix,
161 lfip->fi_prefix_len, lfip->fi_prefix));
164 #ifdef MANIFEST_SKIP_MAYBE
166 * Deal with old incompatible boot/manifest
167 * if fp[-1] is '/' and start of entry matches
168 * MANIFEST_SKIP_MAYBE, we want it.
171 maybe_skip(char *fp, struct fingerprint_info *fip, size_t *nplenp)
175 tp = fp - sizeof(MANIFEST_SKIP_MAYBE);
177 if (tp >= fip->fi_data) {
178 DEBUG_PRINTF(3, ("maybe: %.48s\n", tp));
179 if ((tp == fip->fi_data || tp[-1] == '\n') &&
180 strncmp(tp, MANIFEST_SKIP_MAYBE,
181 sizeof(MANIFEST_SKIP_MAYBE) - 1) == 0) {
183 *nplenp += sizeof(MANIFEST_SKIP_MAYBE);
191 fingerprint_info_lookup(int fd, const char *path)
193 char pbuf[MAXPATHLEN+1];
194 char nbuf[MAXPATHLEN+1];
196 struct fingerprint_info *fip;
197 char *cp, *ep, *fp, *np;
199 size_t n, plen, nlen, nplen;
202 fingerprint_info_init();
204 n = strlcpy(pbuf, path, sizeof(pbuf));
205 if (n >= sizeof(pbuf))
207 if (fstat(fd, &st) == 0)
213 * get the first entry - it will have longest prefix
214 * so we can can work out how to initially split path
216 fip = LIST_FIRST(&fi_list);
221 cp = &pbuf[fip->fi_prefix_len];
229 nlen = plen = 0; /* keep gcc quiet */
231 for ( ; cp >= pbuf && *cp != '/'; cp--)
255 DEBUG_PRINTF(2, ("looking for %s %zu %s\n", prefix, plen, cp));
257 LIST_FOREACH(fip, &fi_list, entries) {
258 DEBUG_PRINTF(4, ("at %zu %s\n",
259 fip->fi_prefix_len, fip->fi_prefix));
261 if (fip->fi_prefix_len < plen) {
262 DEBUG_PRINTF(3, ("skipping prefix=%s %zu %zu\n",
263 fip->fi_prefix, fip->fi_prefix_len,
267 if (fip->fi_prefix_len == plen) {
268 if (fip->fi_dev != 0 && fip->fi_dev != dev) {
270 "skipping dev=%ld != %ld\n",
275 if (strcmp(prefix, fip->fi_prefix)) {
277 "skipping prefix=%s\n",
281 DEBUG_PRINTF(3, ("checking prefix=%s\n",
283 if (fip->fi_skip_len) {
285 nplen = snprintf(nbuf, sizeof(nbuf),
288 nplen = MIN(nplen, sizeof(nbuf) - 1);
293 DEBUG_PRINTF(3, ("lookup: '%s'\n", np));
294 if (!(fp = strstr(fip->fi_data, np)))
296 #ifdef MANIFEST_SKIP_MAYBE
297 if (fip->fi_skip_len == 0 &&
298 fp > fip->fi_data && fp[-1] == '/') {
299 fp = maybe_skip(fp, fip, &nplen);
303 * when we find a match:
304 * fp[nplen] will be space and
305 * fp will be fip->fi_data or
308 if (!((fp == fip->fi_data || fp[-1] == '\n') &&
314 #ifdef MANIFEST_SKIP_MAYBE
315 if (fip->fi_skip_len == 0 &&
318 fp = maybe_skip(fp, fip, &nplen);
322 ("fp[-1]=%#x fp[%zu]=%#x fp=%.78s\n",
327 } while (fp != NULL &&
333 DEBUG_PRINTF(2, ("found %.78s\n", fp));
334 /* we have a match! */
335 for (cp = &fp[nplen]; *cp == ' '; cp++)
340 ("Ignoring prefix=%s\n", fip->fi_prefix));
343 } while (cp > &pbuf[1]);
349 verify_fingerprint(int fd, const char *path, const char *cp, off_t off)
351 unsigned char buf[PAGE_SIZE];
352 const br_hash_class *md;
353 br_hash_compat_context mctx;
357 if (strncmp(cp, "no_hash", 7) == 0) {
358 return (VE_FINGERPRINT_IGNORE);
359 } else if (strncmp(cp, "sha256=", 7) == 0) {
360 md = &br_sha256_vtable;
361 hlen = br_sha256_SIZE;
363 #ifdef VE_SHA1_SUPPORT
364 } else if (strncmp(cp, "sha1=", 5) == 0) {
365 md = &br_sha1_vtable;
369 #ifdef VE_SHA384_SUPPORT
370 } else if (strncmp(cp, "sha384=", 7) == 0) {
371 md = &br_sha384_vtable;
372 hlen = br_sha384_SIZE;
375 #ifdef VE_SHA512_SUPPORT
376 } else if (strncmp(cp, "sha512=", 7) == 0) {
377 md = &br_sha512_vtable;
378 hlen = br_sha512_SIZE;
382 ve_error_set("%s: no supported fingerprint", path);
383 return (VE_FINGERPRINT_UNKNOWN);
386 md->init(&mctx.vtable);
388 lseek(fd, 0, SEEK_SET);
390 n = read(fd, buf, sizeof(buf));
394 md->update(&mctx.vtable, buf, n);
396 lseek(fd, off, SEEK_SET);
397 return (ve_check_hash(&mctx, md, path, cp, hlen));
403 * verify an open file
414 * @return 0, VE_FINGERPRINT_OK or VE_FINGERPRINT_NONE, VE_FINGERPRINT_WRONG
417 verify_fd(int fd, const char *path, off_t off, struct stat *stp)
424 if (fstat(fd, &st) == 0)
427 if (stp && !S_ISREG(stp->st_mode))
428 return (0); /* not relevant */
429 cp = fingerprint_info_lookup(fd, path);
431 ve_error_set("%s: no entry", path);
432 return (VE_FINGERPRINT_NONE);
434 rc = verify_fingerprint(fd, path, cp, off);
436 case VE_FINGERPRINT_OK:
437 case VE_FINGERPRINT_IGNORE:
438 case VE_FINGERPRINT_UNKNOWN:
441 return (VE_FINGERPRINT_WRONG);
447 * open a file if it can be verified
455 * @return fd or VE_FINGERPRINT_NONE, VE_FINGERPRINT_WRONG
458 verify_open(const char *path, int flags)
463 if ((fd = open(path, flags)) >= 0) {
464 if ((rc = verify_fd(fd, path, 0, NULL)) < 0) {