169990Sdes/*-
269990Sdes * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
369990Sdes *
469990Sdes * Copyright (c) 2014 The FreeBSD Foundation
569990Sdes * All rights reserved.
669990Sdes *
769990Sdes * This software was developed by Edward Tomasz Napierala under sponsorship
869990Sdes * from the FreeBSD Foundation.
969990Sdes *
1069990Sdes * Redistribution and use in source and binary forms, with or without
1169990Sdes * modification, are permitted provided that the following conditions
1269990Sdes * are met:
1369990Sdes * 1. Redistributions of source code must retain the above copyright
1469990Sdes *    notice, this list of conditions and the following disclaimer.
1569990Sdes * 2. Redistributions in binary form must reproduce the above copyright
1669990Sdes *    notice, this list of conditions and the following disclaimer in the
1769990Sdes *    documentation and/or other materials provided with the distribution.
1869990Sdes *
1969990Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2069990Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2169990Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2269990Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2369990Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2469990Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2569990Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2669990Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2769990Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2869990Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2969990Sdes * SUCH DAMAGE.
3069990Sdes *
3169990Sdes */
3274840Sken
3374840Sken#include <sys/cdefs.h>
3474840Sken__FBSDID("$FreeBSD: stable/11/usr.sbin/uefisign/child.c 332615 2018-04-16 17:13:54Z trasz $");
3569990Sdes
3669990Sdes#include <sys/param.h>
3769990Sdes#if __FreeBSD_version >= 1100000
3869990Sdes#include <sys/capsicum.h>
3974840Sken#else
4074840Sken#include <sys/capability.h>
4174840Sken#endif
4269990Sdes#include <sys/types.h>
4374840Sken#include <sys/stat.h>
4469990Sdes#include <assert.h>
4574840Sken#include <err.h>
4674840Sken#include <errno.h>
4774840Sken#include <stdio.h>
4874840Sken#include <stdlib.h>
4974840Sken#include <string.h>
5074840Sken#include <unistd.h>
5174840Sken
5274840Sken#include <openssl/evp.h>
5369990Sdes#include <openssl/err.h>
5471721Sdes#include <openssl/pem.h>
5571721Sdes
5671721Sdes#include "uefisign.h"
5771721Sdes
5871721Sdesstatic void
5971721Sdesload(struct executable *x)
6071721Sdes{
6171721Sdes	int error, fd;
6271721Sdes	struct stat sb;
6371721Sdes	char *buf;
6471721Sdes	size_t nread, len;
6571721Sdes
6671721Sdes	fd = fileno(x->x_fp);
6771721Sdes
6871721Sdes	error = fstat(fd, &sb);
6971721Sdes	if (error != 0)
7071721Sdes		err(1, "%s: fstat", x->x_path);
7174840Sken
7269990Sdes	len = sb.st_size;
7373891Sdes	if (len <= 0)
7469990Sdes		errx(1, "%s: file is empty", x->x_path);
7569990Sdes
7673891Sdes	buf = malloc(len);
7769990Sdes	if (buf == NULL)
7873891Sdes		err(1, "%s: cannot malloc %zd bytes", x->x_path, len);
7969990Sdes
8069990Sdes	nread = fread(buf, len, 1, x->x_fp);
8169990Sdes	if (nread != 1)
8269990Sdes		err(1, "%s: fread", x->x_path);
8369990Sdes
8473891Sdes	x->x_buf = buf;
8569990Sdes	x->x_len = len;
8669990Sdes}
8773891Sdes
8869990Sdesstatic void
8969990Sdesdigest_range(struct executable *x, EVP_MD_CTX *mdctx, off_t off, size_t len)
9073891Sdes{
9173891Sdes	int ok;
9274840Sken
9369990Sdes	range_check(x, off, len, "chunk");
9469990Sdes
9574840Sken	ok = EVP_DigestUpdate(mdctx, x->x_buf + off, len);
9669990Sdes	if (ok == 0) {
9769990Sdes		ERR_print_errors_fp(stderr);
9869990Sdes		errx(1, "EVP_DigestUpdate(3) failed");
9969990Sdes	}
10069990Sdes}
10169990Sdes
10269990Sdesstatic void
10371721Sdesdigest(struct executable *x)
10469990Sdes{
10571721Sdes	EVP_MD_CTX *mdctx;
10671721Sdes	const EVP_MD *md;
10769990Sdes	size_t sum_of_bytes_hashed;
10869990Sdes	int i, ok;
10969990Sdes
11069990Sdes	/*
11169990Sdes	 * Windows Authenticode Portable Executable Signature Format
11269990Sdes	 * spec version 1.0 specifies MD5 and SHA1.  However, pesign
11369990Sdes	 * and sbsign both use SHA256, so do the same.
11469990Sdes	 */
11569990Sdes	md = EVP_get_digestbyname(DIGEST);
11669990Sdes	if (md == NULL) {
11769990Sdes		ERR_print_errors_fp(stderr);
11874840Sken		errx(1, "EVP_get_digestbyname(\"%s\") failed", DIGEST);
11969990Sdes	}
12069990Sdes
12169990Sdes	mdctx = EVP_MD_CTX_create();
12269990Sdes	if (mdctx == NULL) {
12369990Sdes		ERR_print_errors_fp(stderr);
12469990Sdes		errx(1, "EVP_MD_CTX_create(3) failed");
12569990Sdes	}
12671721Sdes
12771721Sdes	ok = EVP_DigestInit_ex(mdctx, md, NULL);
12871721Sdes	if (ok == 0) {
12971721Sdes		ERR_print_errors_fp(stderr);
13071721Sdes		errx(1, "EVP_DigestInit_ex(3) failed");
13171721Sdes	}
13271724Sdes
13371721Sdes	/*
13471721Sdes	 * According to the Authenticode spec, we need to compute
13571721Sdes	 * the digest in a rather... specific manner; see "Calculating
13671721Sdes	 * the PE Image Hash" part of the spec for details.
13771721Sdes	 *
13871721Sdes	 * First, everything from 0 to before the PE checksum.
13971721Sdes	 */
14069990Sdes	digest_range(x, mdctx, 0, x->x_checksum_off);
14169990Sdes
14269990Sdes	/*
14371721Sdes	 * Second, from after the PE checksum to before the Certificate
14469990Sdes	 * entry in Data Directory.
14569990Sdes	 */
14669990Sdes	digest_range(x, mdctx, x->x_checksum_off + x->x_checksum_len,
14769990Sdes	    x->x_certificate_entry_off -
14869990Sdes	    (x->x_checksum_off + x->x_checksum_len));
14969990Sdes
15069990Sdes	/*
15169990Sdes	 * Then, from after the Certificate entry to the end of headers.
15269990Sdes	 */
15369990Sdes	digest_range(x, mdctx,
15469990Sdes	    x->x_certificate_entry_off + x->x_certificate_entry_len,
15569990Sdes	    x->x_headers_len -
15669990Sdes	    (x->x_certificate_entry_off + x->x_certificate_entry_len));
15769990Sdes
15869990Sdes	/*
15969990Sdes	 * Then, each section in turn, as specified in the PE Section Table.
16069990Sdes	 *
16169990Sdes	 * XXX: Sorting.
16269990Sdes	 */
16374840Sken	sum_of_bytes_hashed = x->x_headers_len;
16469990Sdes	for (i = 0; i < x->x_nsections; i++) {
16569990Sdes		digest_range(x, mdctx,
16669990Sdes		    x->x_section_off[i], x->x_section_len[i]);
16769990Sdes		sum_of_bytes_hashed += x->x_section_len[i];
16869990Sdes	}
16969990Sdes
17069990Sdes	/*
17169990Sdes	 * I believe this can happen with overlapping sections.
17269990Sdes	 */
17369990Sdes	if (sum_of_bytes_hashed > x->x_len)
17469990Sdes		errx(1, "number of bytes hashed is larger than file size");
17569990Sdes
17669990Sdes	/*
17769990Sdes	 * I can't really explain this one; just do what the spec says.
17869990Sdes	 */
17969990Sdes	if (sum_of_bytes_hashed < x->x_len) {
18069990Sdes		digest_range(x, mdctx, sum_of_bytes_hashed,
18169990Sdes		    x->x_len - (signature_size(x) + sum_of_bytes_hashed));
18269990Sdes	}
18369990Sdes
18474840Sken	ok = EVP_DigestFinal_ex(mdctx, x->x_digest, &x->x_digest_len);
18569990Sdes	if (ok == 0) {
18669990Sdes		ERR_print_errors_fp(stderr);
18769990Sdes		errx(1, "EVP_DigestFinal_ex(3) failed");
18869990Sdes	}
18971721Sdes
19069990Sdes	EVP_MD_CTX_destroy(mdctx);
19169990Sdes}
19269990Sdes
19369990Sdesstatic void
19469990Sdesshow_digest(const struct executable *x)
19569990Sdes{
19669990Sdes	int i;
19769990Sdes
19869990Sdes	printf("computed %s digest ", DIGEST);
19969990Sdes	for (i = 0; i < (int)x->x_digest_len; i++)
20071721Sdes		printf("%02x", (unsigned char)x->x_digest[i]);
20169990Sdes	printf("; digest len %u\n", x->x_digest_len);
20269990Sdes}
20369990Sdes
20469990Sdesstatic void
20569990Sdessend_digest(const struct executable *x, int pipefd)
20669990Sdes{
20769990Sdes
20869990Sdes	send_chunk(x->x_digest, x->x_digest_len, pipefd);
20969990Sdes}
21069990Sdes
21169990Sdesstatic void
21274840Skenreceive_signature(struct executable *x, int pipefd)
21369990Sdes{
21469990Sdes
21574840Sken	receive_chunk(&x->x_signature, &x->x_signature_len, pipefd);
21674840Sken}
21774840Sken
21874840Skenstatic void
21974840Skensave(struct executable *x, FILE *fp, const char *path)
22074840Sken{
22174840Sken	size_t nwritten;
22274840Sken
22374840Sken	assert(fp != NULL);
22474840Sken	assert(path != NULL);
22574840Sken
22674840Sken	nwritten = fwrite(x->x_buf, x->x_len, 1, fp);
22774840Sken	if (nwritten != 1)
22869990Sdes		err(1, "%s: fwrite", path);
22969990Sdes}
23069990Sdes
23169990Sdesint
23269990Sdeschild(const char *inpath, const char *outpath, int pipefd,
23369990Sdes    bool Vflag, bool vflag)
23469990Sdes{
23569990Sdes	int error;
23669990Sdes	FILE *outfp = NULL, *infp = NULL;
23769990Sdes	struct executable *x;
23869990Sdes
23969990Sdes	infp = checked_fopen(inpath, "r");
24069990Sdes	if (outpath != NULL)
24169990Sdes		outfp = checked_fopen(outpath, "w");
24269990Sdes
24369990Sdes	error = cap_enter();
24469990Sdes	if (error != 0 && errno != ENOSYS)
24569990Sdes		err(1, "cap_enter");
24669990Sdes
24769990Sdes	x = calloc(1, sizeof(*x));
24869990Sdes	if (x == NULL)
24969990Sdes		err(1, "calloc");
25069990Sdes	x->x_path = inpath;
25169990Sdes	x->x_fp = infp;
25273891Sdes
25373891Sdes	load(x);
25469990Sdes	parse(x);
25569990Sdes	if (Vflag) {
25669990Sdes		if (signature_size(x) == 0)
25769990Sdes			errx(1, "file not signed");
25871721Sdes
25971721Sdes		printf("file contains signature\n");
26071721Sdes		if (vflag) {
26171721Sdes			digest(x);
26271721Sdes			show_digest(x);
26371721Sdes			show_certificate(x);
26471721Sdes		}
26571721Sdes	} else {
26671721Sdes		if (signature_size(x) != 0)
26769990Sdes			errx(1, "file already signed");
26869990Sdes
26971721Sdes		digest(x);
27069990Sdes		if (vflag)
27169990Sdes			show_digest(x);
27269990Sdes		send_digest(x, pipefd);
27369990Sdes		receive_signature(x, pipefd);
27469990Sdes		update(x);
27573891Sdes		save(x, outfp, outpath);
27671721Sdes	}
27769990Sdes
27869990Sdes	return (0);
27969990Sdes}
28069990Sdes