1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2014 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * This software was developed by Edward Tomasz Napierala under sponsorship 8 * from the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/capsicum.h> 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <assert.h> 41 #include <capsicum_helpers.h> 42 #include <err.h> 43 #include <errno.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include <openssl/evp.h> 50 #include <openssl/err.h> 51 #include <openssl/pem.h> 52 53 #include "uefisign.h" 54 55 static void 56 load(struct executable *x) 57 { 58 int error, fd; 59 struct stat sb; 60 char *buf; 61 size_t nread, len; 62 63 fd = fileno(x->x_fp); 64 65 error = fstat(fd, &sb); 66 if (error != 0) 67 err(1, "%s: fstat", x->x_path); 68 69 len = sb.st_size; 70 if (len <= 0) 71 errx(1, "%s: file is empty", x->x_path); 72 73 buf = malloc(len); 74 if (buf == NULL) 75 err(1, "%s: cannot malloc %zd bytes", x->x_path, len); 76 77 nread = fread(buf, len, 1, x->x_fp); 78 if (nread != 1) 79 err(1, "%s: fread", x->x_path); 80 81 x->x_buf = buf; 82 x->x_len = len; 83 } 84 85 static void 86 digest_range(struct executable *x, EVP_MD_CTX *mdctx, off_t off, size_t len) 87 { 88 int ok; 89 90 range_check(x, off, len, "chunk"); 91 92 ok = EVP_DigestUpdate(mdctx, x->x_buf + off, len); 93 if (ok == 0) { 94 ERR_print_errors_fp(stderr); 95 errx(1, "EVP_DigestUpdate(3) failed"); 96 } 97 } 98 99 static void 100 digest(struct executable *x) 101 { 102 EVP_MD_CTX *mdctx; 103 const EVP_MD *md; 104 size_t sum_of_bytes_hashed; 105 int i, ok; 106 107 /* 108 * Windows Authenticode Portable Executable Signature Format 109 * spec version 1.0 specifies MD5 and SHA1. However, pesign 110 * and sbsign both use SHA256, so do the same. 111 */ 112 md = EVP_get_digestbyname(DIGEST); 113 if (md == NULL) { 114 ERR_print_errors_fp(stderr); 115 errx(1, "EVP_get_digestbyname(\"%s\") failed", DIGEST); 116 } 117 118 mdctx = EVP_MD_CTX_create(); 119 if (mdctx == NULL) { 120 ERR_print_errors_fp(stderr); 121 errx(1, "EVP_MD_CTX_create(3) failed"); 122 } 123 124 ok = EVP_DigestInit_ex(mdctx, md, NULL); 125 if (ok == 0) { 126 ERR_print_errors_fp(stderr); 127 errx(1, "EVP_DigestInit_ex(3) failed"); 128 } 129 130 /* 131 * According to the Authenticode spec, we need to compute 132 * the digest in a rather... specific manner; see "Calculating 133 * the PE Image Hash" part of the spec for details. 134 * 135 * First, everything from 0 to before the PE checksum. 136 */ 137 digest_range(x, mdctx, 0, x->x_checksum_off); 138 139 /* 140 * Second, from after the PE checksum to before the Certificate 141 * entry in Data Directory. 142 */ 143 digest_range(x, mdctx, x->x_checksum_off + x->x_checksum_len, 144 x->x_certificate_entry_off - 145 (x->x_checksum_off + x->x_checksum_len)); 146 147 /* 148 * Then, from after the Certificate entry to the end of headers. 149 */ 150 digest_range(x, mdctx, 151 x->x_certificate_entry_off + x->x_certificate_entry_len, 152 x->x_headers_len - 153 (x->x_certificate_entry_off + x->x_certificate_entry_len)); 154 155 /* 156 * Then, each section in turn, as specified in the PE Section Table. 157 * 158 * XXX: Sorting. 159 */ 160 sum_of_bytes_hashed = x->x_headers_len; 161 for (i = 0; i < x->x_nsections; i++) { 162 digest_range(x, mdctx, 163 x->x_section_off[i], x->x_section_len[i]); 164 sum_of_bytes_hashed += x->x_section_len[i]; 165 } 166 167 /* 168 * I believe this can happen with overlapping sections. 169 */ 170 if (sum_of_bytes_hashed > x->x_len) 171 errx(1, "number of bytes hashed is larger than file size"); 172 173 /* 174 * I can't really explain this one; just do what the spec says. 175 */ 176 if (sum_of_bytes_hashed < x->x_len) { 177 digest_range(x, mdctx, sum_of_bytes_hashed, 178 x->x_len - (signature_size(x) + sum_of_bytes_hashed)); 179 } 180 181 ok = EVP_DigestFinal_ex(mdctx, x->x_digest, &x->x_digest_len); 182 if (ok == 0) { 183 ERR_print_errors_fp(stderr); 184 errx(1, "EVP_DigestFinal_ex(3) failed"); 185 } 186 187 EVP_MD_CTX_destroy(mdctx); 188 } 189 190 static void 191 show_digest(const struct executable *x) 192 { 193 int i; 194 195 printf("computed %s digest ", DIGEST); 196 for (i = 0; i < (int)x->x_digest_len; i++) 197 printf("%02x", (unsigned char)x->x_digest[i]); 198 printf("; digest len %u\n", x->x_digest_len); 199 } 200 201 static void 202 send_digest(const struct executable *x, int pipefd) 203 { 204 205 send_chunk(x->x_digest, x->x_digest_len, pipefd); 206 } 207 208 static void 209 receive_signature(struct executable *x, int pipefd) 210 { 211 212 receive_chunk(&x->x_signature, &x->x_signature_len, pipefd); 213 } 214 215 static void 216 save(struct executable *x, FILE *fp, const char *path) 217 { 218 size_t nwritten; 219 220 assert(fp != NULL); 221 assert(path != NULL); 222 223 nwritten = fwrite(x->x_buf, x->x_len, 1, fp); 224 if (nwritten != 1) 225 err(1, "%s: fwrite", path); 226 } 227 228 int 229 child(const char *inpath, const char *outpath, int pipefd, 230 bool Vflag, bool vflag) 231 { 232 FILE *outfp = NULL, *infp = NULL; 233 struct executable *x; 234 235 infp = checked_fopen(inpath, "r"); 236 if (outpath != NULL) 237 outfp = checked_fopen(outpath, "w"); 238 239 if (caph_enter() < 0) 240 err(1, "cap_enter"); 241 242 x = calloc(1, sizeof(*x)); 243 if (x == NULL) 244 err(1, "calloc"); 245 x->x_path = inpath; 246 x->x_fp = infp; 247 248 load(x); 249 parse(x); 250 if (Vflag) { 251 if (signature_size(x) == 0) 252 errx(1, "file not signed"); 253 254 printf("file contains signature\n"); 255 if (vflag) { 256 digest(x); 257 show_digest(x); 258 show_certificate(x); 259 } 260 } else { 261 if (signature_size(x) != 0) 262 errx(1, "file already signed"); 263 264 digest(x); 265 if (vflag) 266 show_digest(x); 267 send_digest(x, pipefd); 268 receive_signature(x, pipefd); 269 update(x); 270 save(x, outfp, outpath); 271 } 272 273 return (0); 274 } 275