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