1*5fff9558SSimon J. Gerraty /*- 2*5fff9558SSimon J. Gerraty * Copyright (c) 2018, Juniper Networks, Inc. 3*5fff9558SSimon J. Gerraty * 4*5fff9558SSimon J. Gerraty * Redistribution and use in source and binary forms, with or without 5*5fff9558SSimon J. Gerraty * modification, are permitted provided that the following conditions 6*5fff9558SSimon J. Gerraty * are met: 7*5fff9558SSimon J. Gerraty * 1. Redistributions of source code must retain the above copyright 8*5fff9558SSimon J. Gerraty * notice, this list of conditions and the following disclaimer. 9*5fff9558SSimon J. Gerraty * 2. Redistributions in binary form must reproduce the above copyright 10*5fff9558SSimon J. Gerraty * notice, this list of conditions and the following disclaimer in the 11*5fff9558SSimon J. Gerraty * documentation and/or other materials provided with the distribution. 12*5fff9558SSimon J. Gerraty * 13*5fff9558SSimon J. Gerraty * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 14*5fff9558SSimon J. Gerraty * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 15*5fff9558SSimon J. Gerraty * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 16*5fff9558SSimon J. Gerraty * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 17*5fff9558SSimon J. Gerraty * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18*5fff9558SSimon J. Gerraty * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 19*5fff9558SSimon J. Gerraty * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20*5fff9558SSimon J. Gerraty * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21*5fff9558SSimon J. Gerraty * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22*5fff9558SSimon J. Gerraty * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23*5fff9558SSimon J. Gerraty * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24*5fff9558SSimon J. Gerraty */ 25*5fff9558SSimon J. Gerraty #include <sys/cdefs.h> 26*5fff9558SSimon J. Gerraty __FBSDID("$FreeBSD$"); 27*5fff9558SSimon J. Gerraty 28*5fff9558SSimon J. Gerraty #ifndef _STANDALONE 29*5fff9558SSimon J. Gerraty /* Avoid unwanted userlandish components */ 30*5fff9558SSimon J. Gerraty #define _KERNEL 31*5fff9558SSimon J. Gerraty #include <sys/errno.h> 32*5fff9558SSimon J. Gerraty #undef _KERNEL 33*5fff9558SSimon J. Gerraty #endif 34*5fff9558SSimon J. Gerraty 35*5fff9558SSimon J. Gerraty #include "libsecureboot-priv.h" 36*5fff9558SSimon J. Gerraty 37*5fff9558SSimon J. Gerraty /** 38*5fff9558SSimon J. Gerraty * @file vectx.c 39*5fff9558SSimon J. Gerraty * @brief api to verify file while reading 40*5fff9558SSimon J. Gerraty * 41*5fff9558SSimon J. Gerraty * This API allows the hash of a file to be computed as it is read. 42*5fff9558SSimon J. Gerraty * Key to this is seeking by reading. 43*5fff9558SSimon J. Gerraty * 44*5fff9558SSimon J. Gerraty * On close an indication of the verification result is returned. 45*5fff9558SSimon J. Gerraty */ 46*5fff9558SSimon J. Gerraty 47*5fff9558SSimon J. Gerraty struct vectx { 48*5fff9558SSimon J. Gerraty br_hash_compat_context vec_ctx; /* hash ctx */ 49*5fff9558SSimon J. Gerraty const br_hash_class *vec_md; /* hash method */ 50*5fff9558SSimon J. Gerraty const char *vec_path; /* path we are verifying */ 51*5fff9558SSimon J. Gerraty const char *vec_want; /* hash value we want */ 52*5fff9558SSimon J. Gerraty off_t vec_off; /* current offset */ 53*5fff9558SSimon J. Gerraty size_t vec_size; /* size of path */ 54*5fff9558SSimon J. Gerraty size_t vec_hashsz; /* size of hash */ 55*5fff9558SSimon J. Gerraty int vec_fd; /* file descriptor */ 56*5fff9558SSimon J. Gerraty int vec_status; /* verification status */ 57*5fff9558SSimon J. Gerraty }; 58*5fff9558SSimon J. Gerraty 59*5fff9558SSimon J. Gerraty /** 60*5fff9558SSimon J. Gerraty * @brief 61*5fff9558SSimon J. Gerraty * verify an open file as we read it 62*5fff9558SSimon J. Gerraty * 63*5fff9558SSimon J. Gerraty * If the file has no fingerprint to match, we will still return a 64*5fff9558SSimon J. Gerraty * verification context containing little more than the file 65*5fff9558SSimon J. Gerraty * descriptor, and an error code in @c error. 66*5fff9558SSimon J. Gerraty * 67*5fff9558SSimon J. Gerraty * @param[in] fd 68*5fff9558SSimon J. Gerraty * open descriptor 69*5fff9558SSimon J. Gerraty * 70*5fff9558SSimon J. Gerraty * @param[in] path 71*5fff9558SSimon J. Gerraty * pathname to open 72*5fff9558SSimon J. Gerraty * 73*5fff9558SSimon J. Gerraty * @param[in] off 74*5fff9558SSimon J. Gerraty * current offset 75*5fff9558SSimon J. Gerraty * 76*5fff9558SSimon J. Gerraty * @param[in] stp 77*5fff9558SSimon J. Gerraty * pointer to struct stat 78*5fff9558SSimon J. Gerraty * 79*5fff9558SSimon J. Gerraty * @param[out] error 80*5fff9558SSimon J. Gerraty * @li 0 all is good 81*5fff9558SSimon J. Gerraty * @li ENOMEM out of memory 82*5fff9558SSimon J. Gerraty * @li VE_FINGERPRINT_NONE no entry found 83*5fff9558SSimon J. Gerraty * @li VE_FINGERPRINT_UNKNOWN no fingerprint in entry 84*5fff9558SSimon J. Gerraty * 85*5fff9558SSimon J. Gerraty * @return ctx or NULL on error. 86*5fff9558SSimon J. Gerraty * NULL is only returned for non-files or out-of-memory. 87*5fff9558SSimon J. Gerraty */ 88*5fff9558SSimon J. Gerraty struct vectx * 89*5fff9558SSimon J. Gerraty vectx_open(int fd, const char *path, off_t off, struct stat *stp, int *error) 90*5fff9558SSimon J. Gerraty { 91*5fff9558SSimon J. Gerraty struct vectx *ctx; 92*5fff9558SSimon J. Gerraty struct stat st; 93*5fff9558SSimon J. Gerraty size_t hashsz; 94*5fff9558SSimon J. Gerraty char *cp; 95*5fff9558SSimon J. Gerraty 96*5fff9558SSimon J. Gerraty if (!stp) { 97*5fff9558SSimon J. Gerraty if (fstat(fd, &st) == 0) 98*5fff9558SSimon J. Gerraty stp = &st; 99*5fff9558SSimon J. Gerraty } 100*5fff9558SSimon J. Gerraty 101*5fff9558SSimon J. Gerraty /* we *should* only get called for files */ 102*5fff9558SSimon J. Gerraty if (stp && !S_ISREG(stp->st_mode)) { 103*5fff9558SSimon J. Gerraty *error = 0; 104*5fff9558SSimon J. Gerraty return (NULL); 105*5fff9558SSimon J. Gerraty } 106*5fff9558SSimon J. Gerraty 107*5fff9558SSimon J. Gerraty ctx = malloc(sizeof(struct vectx)); 108*5fff9558SSimon J. Gerraty if (!ctx) 109*5fff9558SSimon J. Gerraty goto enomem; 110*5fff9558SSimon J. Gerraty ctx->vec_fd = fd; 111*5fff9558SSimon J. Gerraty ctx->vec_path = path; 112*5fff9558SSimon J. Gerraty ctx->vec_size = stp->st_size; 113*5fff9558SSimon J. Gerraty ctx->vec_off = 0; 114*5fff9558SSimon J. Gerraty ctx->vec_want = NULL; 115*5fff9558SSimon J. Gerraty ctx->vec_status = 0; 116*5fff9558SSimon J. Gerraty hashsz = 0; 117*5fff9558SSimon J. Gerraty 118*5fff9558SSimon J. Gerraty cp = fingerprint_info_lookup(fd, path); 119*5fff9558SSimon J. Gerraty if (!cp) { 120*5fff9558SSimon J. Gerraty ctx->vec_status = VE_FINGERPRINT_NONE; 121*5fff9558SSimon J. Gerraty ve_error_set("%s: no entry", path); 122*5fff9558SSimon J. Gerraty } else { 123*5fff9558SSimon J. Gerraty if (strncmp(cp, "sha256=", 7) == 0) { 124*5fff9558SSimon J. Gerraty ctx->vec_md = &br_sha256_vtable; 125*5fff9558SSimon J. Gerraty hashsz = br_sha256_SIZE; 126*5fff9558SSimon J. Gerraty cp += 7; 127*5fff9558SSimon J. Gerraty #ifdef VE_SHA1_SUPPORT 128*5fff9558SSimon J. Gerraty } else if (strncmp(cp, "sha1=", 5) == 0) { 129*5fff9558SSimon J. Gerraty ctx->vec_md = &br_sha1_vtable; 130*5fff9558SSimon J. Gerraty hashsz = br_sha1_SIZE; 131*5fff9558SSimon J. Gerraty cp += 5; 132*5fff9558SSimon J. Gerraty #endif 133*5fff9558SSimon J. Gerraty #ifdef VE_SHA384_SUPPORT 134*5fff9558SSimon J. Gerraty } else if (strncmp(cp, "sha384=", 7) == 0) { 135*5fff9558SSimon J. Gerraty ctx->vec_md = &br_sha384_vtable; 136*5fff9558SSimon J. Gerraty hashsz = br_sha384_SIZE; 137*5fff9558SSimon J. Gerraty cp += 7; 138*5fff9558SSimon J. Gerraty #endif 139*5fff9558SSimon J. Gerraty #ifdef VE_SHA512_SUPPORT 140*5fff9558SSimon J. Gerraty } else if (strncmp(cp, "sha512=", 7) == 0) { 141*5fff9558SSimon J. Gerraty ctx->vec_md = &br_sha512_vtable; 142*5fff9558SSimon J. Gerraty hashsz = br_sha512_SIZE; 143*5fff9558SSimon J. Gerraty cp += 7; 144*5fff9558SSimon J. Gerraty #endif 145*5fff9558SSimon J. Gerraty } else { 146*5fff9558SSimon J. Gerraty ctx->vec_status = VE_FINGERPRINT_UNKNOWN; 147*5fff9558SSimon J. Gerraty ve_error_set("%s: no supported fingerprint", path); 148*5fff9558SSimon J. Gerraty } 149*5fff9558SSimon J. Gerraty } 150*5fff9558SSimon J. Gerraty *error = ctx->vec_status; 151*5fff9558SSimon J. Gerraty ctx->vec_hashsz = hashsz; 152*5fff9558SSimon J. Gerraty ctx->vec_want = cp; 153*5fff9558SSimon J. Gerraty ctx->vec_md->init(&ctx->vec_ctx.vtable); 154*5fff9558SSimon J. Gerraty 155*5fff9558SSimon J. Gerraty if (hashsz > 0 && off > 0) { 156*5fff9558SSimon J. Gerraty lseek(fd, 0, SEEK_SET); 157*5fff9558SSimon J. Gerraty vectx_lseek(ctx, off, SEEK_SET); 158*5fff9558SSimon J. Gerraty } 159*5fff9558SSimon J. Gerraty return (ctx); 160*5fff9558SSimon J. Gerraty 161*5fff9558SSimon J. Gerraty enomem: /* unlikely */ 162*5fff9558SSimon J. Gerraty *error = ENOMEM; 163*5fff9558SSimon J. Gerraty free(ctx); 164*5fff9558SSimon J. Gerraty return (NULL); 165*5fff9558SSimon J. Gerraty } 166*5fff9558SSimon J. Gerraty 167*5fff9558SSimon J. Gerraty /** 168*5fff9558SSimon J. Gerraty * @brief 169*5fff9558SSimon J. Gerraty * read bytes from file and update hash 170*5fff9558SSimon J. Gerraty * 171*5fff9558SSimon J. Gerraty * It is critical that all file I/O comes through here. 172*5fff9558SSimon J. Gerraty * We keep track of current offset. 173*5fff9558SSimon J. Gerraty * 174*5fff9558SSimon J. Gerraty * @param[in] pctx 175*5fff9558SSimon J. Gerraty * pointer to ctx 176*5fff9558SSimon J. Gerraty * 177*5fff9558SSimon J. Gerraty * @param[in] buf 178*5fff9558SSimon J. Gerraty * 179*5fff9558SSimon J. Gerraty * @param[in] nbytes 180*5fff9558SSimon J. Gerraty * 181*5fff9558SSimon J. Gerraty * @return bytes read or error. 182*5fff9558SSimon J. Gerraty */ 183*5fff9558SSimon J. Gerraty ssize_t 184*5fff9558SSimon J. Gerraty vectx_read(struct vectx *ctx, void *buf, size_t nbytes) 185*5fff9558SSimon J. Gerraty { 186*5fff9558SSimon J. Gerraty unsigned char *bp = buf; 187*5fff9558SSimon J. Gerraty int n; 188*5fff9558SSimon J. Gerraty size_t off; 189*5fff9558SSimon J. Gerraty 190*5fff9558SSimon J. Gerraty if (ctx->vec_hashsz == 0) /* nothing to do */ 191*5fff9558SSimon J. Gerraty return (read(ctx->vec_fd, buf, nbytes)); 192*5fff9558SSimon J. Gerraty 193*5fff9558SSimon J. Gerraty off = 0; 194*5fff9558SSimon J. Gerraty do { 195*5fff9558SSimon J. Gerraty n = read(ctx->vec_fd, &bp[off], nbytes - off); 196*5fff9558SSimon J. Gerraty if (n < 0) 197*5fff9558SSimon J. Gerraty return (n); 198*5fff9558SSimon J. Gerraty if (n > 0) { 199*5fff9558SSimon J. Gerraty ctx->vec_md->update(&ctx->vec_ctx.vtable, &bp[off], n); 200*5fff9558SSimon J. Gerraty off += n; 201*5fff9558SSimon J. Gerraty ctx->vec_off += n; 202*5fff9558SSimon J. Gerraty } 203*5fff9558SSimon J. Gerraty } while (n > 0 && off < nbytes); 204*5fff9558SSimon J. Gerraty return (off); 205*5fff9558SSimon J. Gerraty } 206*5fff9558SSimon J. Gerraty 207*5fff9558SSimon J. Gerraty /** 208*5fff9558SSimon J. Gerraty * @brief 209*5fff9558SSimon J. Gerraty * vectx equivalent of lseek 210*5fff9558SSimon J. Gerraty * 211*5fff9558SSimon J. Gerraty * We do not actually, seek, but call vectx_read 212*5fff9558SSimon J. Gerraty * to reach the desired offset. 213*5fff9558SSimon J. Gerraty * 214*5fff9558SSimon J. Gerraty * We do not support seeking backwards. 215*5fff9558SSimon J. Gerraty * 216*5fff9558SSimon J. Gerraty * @param[in] pctx 217*5fff9558SSimon J. Gerraty * pointer to ctx 218*5fff9558SSimon J. Gerraty * 219*5fff9558SSimon J. Gerraty * @param[in] off 220*5fff9558SSimon J. Gerraty * desired offset 221*5fff9558SSimon J. Gerraty * 222*5fff9558SSimon J. Gerraty * @param[in] whence 223*5fff9558SSimon J. Gerraty * 224*5fff9558SSimon J. Gerraty * @return offset or error. 225*5fff9558SSimon J. Gerraty */ 226*5fff9558SSimon J. Gerraty off_t 227*5fff9558SSimon J. Gerraty vectx_lseek(struct vectx *ctx, off_t off, int whence) 228*5fff9558SSimon J. Gerraty { 229*5fff9558SSimon J. Gerraty unsigned char buf[PAGE_SIZE]; 230*5fff9558SSimon J. Gerraty size_t delta; 231*5fff9558SSimon J. Gerraty ssize_t n; 232*5fff9558SSimon J. Gerraty 233*5fff9558SSimon J. Gerraty if (ctx->vec_hashsz == 0) /* nothing to do */ 234*5fff9558SSimon J. Gerraty return (lseek(ctx->vec_fd, off, whence)); 235*5fff9558SSimon J. Gerraty 236*5fff9558SSimon J. Gerraty /* 237*5fff9558SSimon J. Gerraty * Try to convert whence to SEEK_SET 238*5fff9558SSimon J. Gerraty * but we cannot support seeking backwards! 239*5fff9558SSimon J. Gerraty * Nor beyond end of file. 240*5fff9558SSimon J. Gerraty */ 241*5fff9558SSimon J. Gerraty if (whence == SEEK_END && off <= 0) { 242*5fff9558SSimon J. Gerraty whence = SEEK_SET; 243*5fff9558SSimon J. Gerraty off += ctx->vec_size; 244*5fff9558SSimon J. Gerraty } else if (whence == SEEK_CUR && off >= 0) { 245*5fff9558SSimon J. Gerraty whence = SEEK_SET; 246*5fff9558SSimon J. Gerraty off += ctx->vec_off; 247*5fff9558SSimon J. Gerraty } 248*5fff9558SSimon J. Gerraty if (whence != SEEK_SET || off < ctx->vec_off || 249*5fff9558SSimon J. Gerraty (size_t)off > ctx->vec_size) { 250*5fff9558SSimon J. Gerraty printf("ERROR: %s: unsupported operation\n", __func__); 251*5fff9558SSimon J. Gerraty return (-1); 252*5fff9558SSimon J. Gerraty } 253*5fff9558SSimon J. Gerraty n = 0; 254*5fff9558SSimon J. Gerraty do { 255*5fff9558SSimon J. Gerraty delta = off - ctx->vec_off; 256*5fff9558SSimon J. Gerraty if (delta > 0) { 257*5fff9558SSimon J. Gerraty delta = MIN(PAGE_SIZE, delta); 258*5fff9558SSimon J. Gerraty n = vectx_read(ctx, buf, delta); 259*5fff9558SSimon J. Gerraty if (n < 0) 260*5fff9558SSimon J. Gerraty return (n); 261*5fff9558SSimon J. Gerraty } 262*5fff9558SSimon J. Gerraty } while (ctx->vec_off < off && n > 0); 263*5fff9558SSimon J. Gerraty return (ctx->vec_off); 264*5fff9558SSimon J. Gerraty } 265*5fff9558SSimon J. Gerraty 266*5fff9558SSimon J. Gerraty /** 267*5fff9558SSimon J. Gerraty * @brief 268*5fff9558SSimon J. Gerraty * check that hashes match and cleanup 269*5fff9558SSimon J. Gerraty * 270*5fff9558SSimon J. Gerraty * We have finished reading file, compare the hash with what 271*5fff9558SSimon J. Gerraty * we wanted. 272*5fff9558SSimon J. Gerraty * 273*5fff9558SSimon J. Gerraty * @param[in] pctx 274*5fff9558SSimon J. Gerraty * pointer to ctx 275*5fff9558SSimon J. Gerraty * 276*5fff9558SSimon J. Gerraty * @return 0 or an error. 277*5fff9558SSimon J. Gerraty */ 278*5fff9558SSimon J. Gerraty int 279*5fff9558SSimon J. Gerraty vectx_close(struct vectx *ctx) 280*5fff9558SSimon J. Gerraty { 281*5fff9558SSimon J. Gerraty int rc; 282*5fff9558SSimon J. Gerraty 283*5fff9558SSimon J. Gerraty if (ctx->vec_hashsz == 0) { 284*5fff9558SSimon J. Gerraty rc = ctx->vec_status; 285*5fff9558SSimon J. Gerraty } else { 286*5fff9558SSimon J. Gerraty rc = ve_check_hash(&ctx->vec_ctx, ctx->vec_md, 287*5fff9558SSimon J. Gerraty ctx->vec_path, ctx->vec_want, ctx->vec_hashsz); 288*5fff9558SSimon J. Gerraty } 289*5fff9558SSimon J. Gerraty free(ctx); 290*5fff9558SSimon J. Gerraty return ((rc < 0) ? rc : 0); 291*5fff9558SSimon J. Gerraty } 292