1279315Strasz/*- 2332615Strasz * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3332615Strasz * 4279315Strasz * Copyright (c) 2014 The FreeBSD Foundation 5279315Strasz * All rights reserved. 6279315Strasz * 7279315Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 8279315Strasz * from the FreeBSD Foundation. 9279315Strasz * 10279315Strasz * Redistribution and use in source and binary forms, with or without 11279315Strasz * modification, are permitted provided that the following conditions 12279315Strasz * are met: 13279315Strasz * 1. Redistributions of source code must retain the above copyright 14279315Strasz * notice, this list of conditions and the following disclaimer. 15279315Strasz * 2. Redistributions in binary form must reproduce the above copyright 16279315Strasz * notice, this list of conditions and the following disclaimer in the 17279315Strasz * documentation and/or other materials provided with the distribution. 18279315Strasz * 19279315Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20279315Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21279315Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22279315Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23279315Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24279315Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25279315Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26279315Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27279315Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28279315Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29279315Strasz * SUCH DAMAGE. 30279315Strasz * 31279315Strasz */ 32279315Strasz 33279315Strasz#include <sys/cdefs.h> 34279315Strasz__FBSDID("$FreeBSD: stable/11/usr.sbin/uefisign/child.c 332615 2018-04-16 17:13:54Z trasz $"); 35279315Strasz 36279315Strasz#include <sys/param.h> 37279315Strasz#if __FreeBSD_version >= 1100000 38279315Strasz#include <sys/capsicum.h> 39279315Strasz#else 40279315Strasz#include <sys/capability.h> 41279315Strasz#endif 42279315Strasz#include <sys/types.h> 43279315Strasz#include <sys/stat.h> 44279315Strasz#include <assert.h> 45279315Strasz#include <err.h> 46279315Strasz#include <errno.h> 47279315Strasz#include <stdio.h> 48279315Strasz#include <stdlib.h> 49279315Strasz#include <string.h> 50279315Strasz#include <unistd.h> 51279315Strasz 52279315Strasz#include <openssl/evp.h> 53279315Strasz#include <openssl/err.h> 54279315Strasz#include <openssl/pem.h> 55279315Strasz 56279315Strasz#include "uefisign.h" 57279315Strasz 58279315Straszstatic void 59279315Straszload(struct executable *x) 60279315Strasz{ 61279315Strasz int error, fd; 62279315Strasz struct stat sb; 63279315Strasz char *buf; 64279315Strasz size_t nread, len; 65279315Strasz 66279315Strasz fd = fileno(x->x_fp); 67279315Strasz 68279315Strasz error = fstat(fd, &sb); 69279315Strasz if (error != 0) 70279315Strasz err(1, "%s: fstat", x->x_path); 71279315Strasz 72279315Strasz len = sb.st_size; 73279315Strasz if (len <= 0) 74279315Strasz errx(1, "%s: file is empty", x->x_path); 75279315Strasz 76279315Strasz buf = malloc(len); 77279315Strasz if (buf == NULL) 78279315Strasz err(1, "%s: cannot malloc %zd bytes", x->x_path, len); 79279315Strasz 80279315Strasz nread = fread(buf, len, 1, x->x_fp); 81279315Strasz if (nread != 1) 82279315Strasz err(1, "%s: fread", x->x_path); 83279315Strasz 84279315Strasz x->x_buf = buf; 85279315Strasz x->x_len = len; 86279315Strasz} 87279315Strasz 88279315Straszstatic void 89279315Straszdigest_range(struct executable *x, EVP_MD_CTX *mdctx, off_t off, size_t len) 90279315Strasz{ 91279315Strasz int ok; 92279315Strasz 93279315Strasz range_check(x, off, len, "chunk"); 94279315Strasz 95279315Strasz ok = EVP_DigestUpdate(mdctx, x->x_buf + off, len); 96279315Strasz if (ok == 0) { 97279315Strasz ERR_print_errors_fp(stderr); 98279315Strasz errx(1, "EVP_DigestUpdate(3) failed"); 99279315Strasz } 100279315Strasz} 101279315Strasz 102279315Straszstatic void 103279315Straszdigest(struct executable *x) 104279315Strasz{ 105279315Strasz EVP_MD_CTX *mdctx; 106279315Strasz const EVP_MD *md; 107279315Strasz size_t sum_of_bytes_hashed; 108279315Strasz int i, ok; 109279315Strasz 110279315Strasz /* 111279315Strasz * Windows Authenticode Portable Executable Signature Format 112279315Strasz * spec version 1.0 specifies MD5 and SHA1. However, pesign 113279315Strasz * and sbsign both use SHA256, so do the same. 114279315Strasz */ 115279315Strasz md = EVP_get_digestbyname(DIGEST); 116279315Strasz if (md == NULL) { 117279315Strasz ERR_print_errors_fp(stderr); 118279315Strasz errx(1, "EVP_get_digestbyname(\"%s\") failed", DIGEST); 119279315Strasz } 120279315Strasz 121279315Strasz mdctx = EVP_MD_CTX_create(); 122279315Strasz if (mdctx == NULL) { 123279315Strasz ERR_print_errors_fp(stderr); 124279315Strasz errx(1, "EVP_MD_CTX_create(3) failed"); 125279315Strasz } 126279315Strasz 127279315Strasz ok = EVP_DigestInit_ex(mdctx, md, NULL); 128279315Strasz if (ok == 0) { 129279315Strasz ERR_print_errors_fp(stderr); 130279315Strasz errx(1, "EVP_DigestInit_ex(3) failed"); 131279315Strasz } 132279315Strasz 133279315Strasz /* 134279315Strasz * According to the Authenticode spec, we need to compute 135279315Strasz * the digest in a rather... specific manner; see "Calculating 136279315Strasz * the PE Image Hash" part of the spec for details. 137279315Strasz * 138279315Strasz * First, everything from 0 to before the PE checksum. 139279315Strasz */ 140279315Strasz digest_range(x, mdctx, 0, x->x_checksum_off); 141279315Strasz 142279315Strasz /* 143279315Strasz * Second, from after the PE checksum to before the Certificate 144279315Strasz * entry in Data Directory. 145279315Strasz */ 146279315Strasz digest_range(x, mdctx, x->x_checksum_off + x->x_checksum_len, 147279315Strasz x->x_certificate_entry_off - 148279315Strasz (x->x_checksum_off + x->x_checksum_len)); 149279315Strasz 150279315Strasz /* 151279315Strasz * Then, from after the Certificate entry to the end of headers. 152279315Strasz */ 153279315Strasz digest_range(x, mdctx, 154279315Strasz x->x_certificate_entry_off + x->x_certificate_entry_len, 155279315Strasz x->x_headers_len - 156279315Strasz (x->x_certificate_entry_off + x->x_certificate_entry_len)); 157279315Strasz 158279315Strasz /* 159279315Strasz * Then, each section in turn, as specified in the PE Section Table. 160279315Strasz * 161279315Strasz * XXX: Sorting. 162279315Strasz */ 163279315Strasz sum_of_bytes_hashed = x->x_headers_len; 164279315Strasz for (i = 0; i < x->x_nsections; i++) { 165279315Strasz digest_range(x, mdctx, 166279315Strasz x->x_section_off[i], x->x_section_len[i]); 167279315Strasz sum_of_bytes_hashed += x->x_section_len[i]; 168279315Strasz } 169279315Strasz 170279315Strasz /* 171279315Strasz * I believe this can happen with overlapping sections. 172279315Strasz */ 173279315Strasz if (sum_of_bytes_hashed > x->x_len) 174279315Strasz errx(1, "number of bytes hashed is larger than file size"); 175279315Strasz 176279315Strasz /* 177279315Strasz * I can't really explain this one; just do what the spec says. 178279315Strasz */ 179279315Strasz if (sum_of_bytes_hashed < x->x_len) { 180279315Strasz digest_range(x, mdctx, sum_of_bytes_hashed, 181279315Strasz x->x_len - (signature_size(x) + sum_of_bytes_hashed)); 182279315Strasz } 183279315Strasz 184279315Strasz ok = EVP_DigestFinal_ex(mdctx, x->x_digest, &x->x_digest_len); 185279315Strasz if (ok == 0) { 186279315Strasz ERR_print_errors_fp(stderr); 187279315Strasz errx(1, "EVP_DigestFinal_ex(3) failed"); 188279315Strasz } 189279315Strasz 190279315Strasz EVP_MD_CTX_destroy(mdctx); 191279315Strasz} 192279315Strasz 193279315Straszstatic void 194279315Straszshow_digest(const struct executable *x) 195279315Strasz{ 196279315Strasz int i; 197279315Strasz 198279315Strasz printf("computed %s digest ", DIGEST); 199279315Strasz for (i = 0; i < (int)x->x_digest_len; i++) 200279315Strasz printf("%02x", (unsigned char)x->x_digest[i]); 201279315Strasz printf("; digest len %u\n", x->x_digest_len); 202279315Strasz} 203279315Strasz 204279315Straszstatic void 205279315Straszsend_digest(const struct executable *x, int pipefd) 206279315Strasz{ 207279315Strasz 208279315Strasz send_chunk(x->x_digest, x->x_digest_len, pipefd); 209279315Strasz} 210279315Strasz 211279315Straszstatic void 212279315Straszreceive_signature(struct executable *x, int pipefd) 213279315Strasz{ 214279315Strasz 215279315Strasz receive_chunk(&x->x_signature, &x->x_signature_len, pipefd); 216279315Strasz} 217279315Strasz 218279315Straszstatic void 219279315Straszsave(struct executable *x, FILE *fp, const char *path) 220279315Strasz{ 221279315Strasz size_t nwritten; 222279315Strasz 223279315Strasz assert(fp != NULL); 224279315Strasz assert(path != NULL); 225279315Strasz 226279315Strasz nwritten = fwrite(x->x_buf, x->x_len, 1, fp); 227279315Strasz if (nwritten != 1) 228279315Strasz err(1, "%s: fwrite", path); 229279315Strasz} 230279315Strasz 231279315Straszint 232279315Straszchild(const char *inpath, const char *outpath, int pipefd, 233279315Strasz bool Vflag, bool vflag) 234279315Strasz{ 235279315Strasz int error; 236279315Strasz FILE *outfp = NULL, *infp = NULL; 237279315Strasz struct executable *x; 238279315Strasz 239279315Strasz infp = checked_fopen(inpath, "r"); 240279315Strasz if (outpath != NULL) 241279315Strasz outfp = checked_fopen(outpath, "w"); 242279315Strasz 243279315Strasz error = cap_enter(); 244279315Strasz if (error != 0 && errno != ENOSYS) 245279315Strasz err(1, "cap_enter"); 246279315Strasz 247279315Strasz x = calloc(1, sizeof(*x)); 248279315Strasz if (x == NULL) 249279315Strasz err(1, "calloc"); 250279315Strasz x->x_path = inpath; 251279315Strasz x->x_fp = infp; 252279315Strasz 253279315Strasz load(x); 254279315Strasz parse(x); 255279315Strasz if (Vflag) { 256279315Strasz if (signature_size(x) == 0) 257279315Strasz errx(1, "file not signed"); 258279315Strasz 259279315Strasz printf("file contains signature\n"); 260279315Strasz if (vflag) { 261279315Strasz digest(x); 262279315Strasz show_digest(x); 263279315Strasz show_certificate(x); 264279315Strasz } 265279315Strasz } else { 266279315Strasz if (signature_size(x) != 0) 267279315Strasz errx(1, "file already signed"); 268279315Strasz 269279315Strasz digest(x); 270279315Strasz if (vflag) 271279315Strasz show_digest(x); 272279315Strasz send_digest(x, pipefd); 273279315Strasz receive_signature(x, pipefd); 274279315Strasz update(x); 275279315Strasz save(x, outfp, outpath); 276279315Strasz } 277279315Strasz 278279315Strasz return (0); 279279315Strasz} 280