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/param.h> 33 #include <sys/capsicum.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <assert.h> 37 #include <capsicum_helpers.h> 38 #include <err.h> 39 #include <errno.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include <openssl/evp.h> 46 #include <openssl/err.h> 47 #include <openssl/pem.h> 48 49 #include "uefisign.h" 50 51 static void 52 load(struct executable *x) 53 { 54 int error, fd; 55 struct stat sb; 56 char *buf; 57 size_t nread, len; 58 59 fd = fileno(x->x_fp); 60 61 error = fstat(fd, &sb); 62 if (error != 0) 63 err(1, "%s: fstat", x->x_path); 64 65 len = sb.st_size; 66 if (len <= 0) 67 errx(1, "%s: file is empty", x->x_path); 68 69 buf = malloc(len); 70 if (buf == NULL) 71 err(1, "%s: cannot malloc %zd bytes", x->x_path, len); 72 73 nread = fread(buf, len, 1, x->x_fp); 74 if (nread != 1) 75 err(1, "%s: fread", x->x_path); 76 77 x->x_buf = buf; 78 x->x_len = len; 79 } 80 81 static void 82 digest_range(struct executable *x, EVP_MD_CTX *mdctx, off_t off, size_t len) 83 { 84 int ok; 85 86 range_check(x, off, len, "chunk"); 87 88 ok = EVP_DigestUpdate(mdctx, x->x_buf + off, len); 89 if (ok == 0) { 90 ERR_print_errors_fp(stderr); 91 errx(1, "EVP_DigestUpdate(3) failed"); 92 } 93 } 94 95 static void 96 digest(struct executable *x) 97 { 98 EVP_MD_CTX *mdctx; 99 const EVP_MD *md; 100 size_t sum_of_bytes_hashed; 101 int i, ok; 102 103 /* 104 * Windows Authenticode Portable Executable Signature Format 105 * spec version 1.0 specifies MD5 and SHA1. However, pesign 106 * and sbsign both use SHA256, so do the same. 107 */ 108 md = EVP_get_digestbyname(DIGEST); 109 if (md == NULL) { 110 ERR_print_errors_fp(stderr); 111 errx(1, "EVP_get_digestbyname(\"%s\") failed", DIGEST); 112 } 113 114 mdctx = EVP_MD_CTX_create(); 115 if (mdctx == NULL) { 116 ERR_print_errors_fp(stderr); 117 errx(1, "EVP_MD_CTX_create(3) failed"); 118 } 119 120 ok = EVP_DigestInit_ex(mdctx, md, NULL); 121 if (ok == 0) { 122 ERR_print_errors_fp(stderr); 123 errx(1, "EVP_DigestInit_ex(3) failed"); 124 } 125 126 /* 127 * According to the Authenticode spec, we need to compute 128 * the digest in a rather... specific manner; see "Calculating 129 * the PE Image Hash" part of the spec for details. 130 * 131 * First, everything from 0 to before the PE checksum. 132 */ 133 digest_range(x, mdctx, 0, x->x_checksum_off); 134 135 /* 136 * Second, from after the PE checksum to before the Certificate 137 * entry in Data Directory. 138 */ 139 digest_range(x, mdctx, x->x_checksum_off + x->x_checksum_len, 140 x->x_certificate_entry_off - 141 (x->x_checksum_off + x->x_checksum_len)); 142 143 /* 144 * Then, from after the Certificate entry to the end of headers. 145 */ 146 digest_range(x, mdctx, 147 x->x_certificate_entry_off + x->x_certificate_entry_len, 148 x->x_headers_len - 149 (x->x_certificate_entry_off + x->x_certificate_entry_len)); 150 151 /* 152 * Then, each section in turn, as specified in the PE Section Table. 153 * 154 * XXX: Sorting. 155 */ 156 sum_of_bytes_hashed = x->x_headers_len; 157 for (i = 0; i < x->x_nsections; i++) { 158 digest_range(x, mdctx, 159 x->x_section_off[i], x->x_section_len[i]); 160 sum_of_bytes_hashed += x->x_section_len[i]; 161 } 162 163 /* 164 * I believe this can happen with overlapping sections. 165 */ 166 if (sum_of_bytes_hashed > x->x_len) 167 errx(1, "number of bytes hashed is larger than file size"); 168 169 /* 170 * I can't really explain this one; just do what the spec says. 171 */ 172 if (sum_of_bytes_hashed < x->x_len) { 173 digest_range(x, mdctx, sum_of_bytes_hashed, 174 x->x_len - (signature_size(x) + sum_of_bytes_hashed)); 175 } 176 177 ok = EVP_DigestFinal_ex(mdctx, x->x_digest, &x->x_digest_len); 178 if (ok == 0) { 179 ERR_print_errors_fp(stderr); 180 errx(1, "EVP_DigestFinal_ex(3) failed"); 181 } 182 183 EVP_MD_CTX_destroy(mdctx); 184 } 185 186 static void 187 show_digest(const struct executable *x) 188 { 189 int i; 190 191 printf("computed %s digest ", DIGEST); 192 for (i = 0; i < (int)x->x_digest_len; i++) 193 printf("%02x", (unsigned char)x->x_digest[i]); 194 printf("; digest len %u\n", x->x_digest_len); 195 } 196 197 static void 198 send_digest(const struct executable *x, int pipefd) 199 { 200 201 send_chunk(x->x_digest, x->x_digest_len, pipefd); 202 } 203 204 static void 205 receive_signature(struct executable *x, int pipefd) 206 { 207 208 receive_chunk(&x->x_signature, &x->x_signature_len, pipefd); 209 } 210 211 static void 212 save(struct executable *x, FILE *fp, const char *path) 213 { 214 size_t nwritten; 215 216 assert(fp != NULL); 217 assert(path != NULL); 218 219 nwritten = fwrite(x->x_buf, x->x_len, 1, fp); 220 if (nwritten != 1) 221 err(1, "%s: fwrite", path); 222 } 223 224 int 225 child(const char *inpath, const char *outpath, int pipefd, 226 bool Vflag, bool vflag) 227 { 228 FILE *outfp = NULL, *infp = NULL; 229 struct executable *x; 230 231 infp = checked_fopen(inpath, "r"); 232 if (outpath != NULL) 233 outfp = checked_fopen(outpath, "w"); 234 235 if (caph_enter() < 0) 236 err(1, "cap_enter"); 237 238 x = calloc(1, sizeof(*x)); 239 if (x == NULL) 240 err(1, "calloc"); 241 x->x_path = inpath; 242 x->x_fp = infp; 243 244 load(x); 245 parse(x); 246 if (Vflag) { 247 if (signature_size(x) == 0) 248 errx(1, "file not signed"); 249 250 printf("file contains signature\n"); 251 if (vflag) { 252 digest(x); 253 show_digest(x); 254 show_certificate(x); 255 } 256 } else { 257 if (signature_size(x) != 0) 258 errx(1, "file already signed"); 259 260 digest(x); 261 if (vflag) 262 show_digest(x); 263 send_digest(x, pipefd); 264 receive_signature(x, pipefd); 265 update(x); 266 save(x, outfp, outpath); 267 } 268 269 return (0); 270 } 271