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