xref: /freebsd/usr.sbin/uefisign/uefisign.c (revision 1aa6f9aea2118a567fc4bd9f275382a28a350cd5)
1e595e65bSEdward Tomasz Napierala /*-
2*1aa6f9aeSEdward Tomasz Napierala  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*1aa6f9aeSEdward Tomasz Napierala  *
4e595e65bSEdward Tomasz Napierala  * Copyright (c) 2014 The FreeBSD Foundation
5e595e65bSEdward Tomasz Napierala  * All rights reserved.
6e595e65bSEdward Tomasz Napierala  *
7e595e65bSEdward Tomasz Napierala  * This software was developed by Edward Tomasz Napierala under sponsorship
8e595e65bSEdward Tomasz Napierala  * from the FreeBSD Foundation.
9e595e65bSEdward Tomasz Napierala  *
10e595e65bSEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
11e595e65bSEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
12e595e65bSEdward Tomasz Napierala  * are met:
13e595e65bSEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
14e595e65bSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
15e595e65bSEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
16e595e65bSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
17e595e65bSEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
18e595e65bSEdward Tomasz Napierala  *
19e595e65bSEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20e595e65bSEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21e595e65bSEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22e595e65bSEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23e595e65bSEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24e595e65bSEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25e595e65bSEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26e595e65bSEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27e595e65bSEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28e595e65bSEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29e595e65bSEdward Tomasz Napierala  * SUCH DAMAGE.
30e595e65bSEdward Tomasz Napierala  *
31e595e65bSEdward Tomasz Napierala  */
32e595e65bSEdward Tomasz Napierala 
33e595e65bSEdward Tomasz Napierala #include <sys/cdefs.h>
34e595e65bSEdward Tomasz Napierala __FBSDID("$FreeBSD$");
35e595e65bSEdward Tomasz Napierala 
36e595e65bSEdward Tomasz Napierala #include <sys/wait.h>
37e595e65bSEdward Tomasz Napierala #include <assert.h>
38e595e65bSEdward Tomasz Napierala #include <err.h>
39e595e65bSEdward Tomasz Napierala #include <errno.h>
40e595e65bSEdward Tomasz Napierala #include <stdio.h>
41e595e65bSEdward Tomasz Napierala #include <string.h>
42e595e65bSEdward Tomasz Napierala #include <unistd.h>
43e595e65bSEdward Tomasz Napierala 
44e595e65bSEdward Tomasz Napierala #include <openssl/conf.h>
45e595e65bSEdward Tomasz Napierala #include <openssl/evp.h>
46e595e65bSEdward Tomasz Napierala #include <openssl/err.h>
47e595e65bSEdward Tomasz Napierala #include <openssl/pem.h>
48e595e65bSEdward Tomasz Napierala #include <openssl/pkcs7.h>
49e595e65bSEdward Tomasz Napierala 
50e595e65bSEdward Tomasz Napierala #include "uefisign.h"
51e595e65bSEdward Tomasz Napierala #include "magic.h"
52e595e65bSEdward Tomasz Napierala 
53e595e65bSEdward Tomasz Napierala static void
54e595e65bSEdward Tomasz Napierala usage(void)
55e595e65bSEdward Tomasz Napierala {
56e595e65bSEdward Tomasz Napierala 
57e595e65bSEdward Tomasz Napierala 	fprintf(stderr, "usage: uefisign -c cert -k key -o outfile [-v] file\n"
58e595e65bSEdward Tomasz Napierala 			"       uefisign -V [-c cert] [-v] file\n");
59e595e65bSEdward Tomasz Napierala 	exit(1);
60e595e65bSEdward Tomasz Napierala }
61e595e65bSEdward Tomasz Napierala 
62e595e65bSEdward Tomasz Napierala static char *
63e595e65bSEdward Tomasz Napierala checked_strdup(const char *s)
64e595e65bSEdward Tomasz Napierala {
65e595e65bSEdward Tomasz Napierala 	char *c;
66e595e65bSEdward Tomasz Napierala 
67e595e65bSEdward Tomasz Napierala 	c = strdup(s);
68e595e65bSEdward Tomasz Napierala 	if (c == NULL)
69e595e65bSEdward Tomasz Napierala 		err(1, "strdup");
70e595e65bSEdward Tomasz Napierala 	return (c);
71e595e65bSEdward Tomasz Napierala }
72e595e65bSEdward Tomasz Napierala 
73e595e65bSEdward Tomasz Napierala FILE *
74e595e65bSEdward Tomasz Napierala checked_fopen(const char *path, const char *mode)
75e595e65bSEdward Tomasz Napierala {
76e595e65bSEdward Tomasz Napierala 	FILE *fp;
77e595e65bSEdward Tomasz Napierala 
78e595e65bSEdward Tomasz Napierala 	assert(path != NULL);
79e595e65bSEdward Tomasz Napierala 
80e595e65bSEdward Tomasz Napierala 	fp = fopen(path, mode);
81e595e65bSEdward Tomasz Napierala 	if (fp == NULL)
82e595e65bSEdward Tomasz Napierala 		err(1, "%s", path);
83e595e65bSEdward Tomasz Napierala 	return (fp);
84e595e65bSEdward Tomasz Napierala }
85e595e65bSEdward Tomasz Napierala 
86e595e65bSEdward Tomasz Napierala void
87e595e65bSEdward Tomasz Napierala send_chunk(const void *buf, size_t len, int pipefd)
88e595e65bSEdward Tomasz Napierala {
89e595e65bSEdward Tomasz Napierala 	ssize_t ret;
90e595e65bSEdward Tomasz Napierala 
91e595e65bSEdward Tomasz Napierala 	ret = write(pipefd, &len, sizeof(len));
92e595e65bSEdward Tomasz Napierala 	if (ret != sizeof(len))
93e595e65bSEdward Tomasz Napierala 		err(1, "write");
94e595e65bSEdward Tomasz Napierala 	ret = write(pipefd, buf, len);
95e595e65bSEdward Tomasz Napierala 	if (ret != (ssize_t)len)
96e595e65bSEdward Tomasz Napierala 		err(1, "write");
97e595e65bSEdward Tomasz Napierala }
98e595e65bSEdward Tomasz Napierala 
99e595e65bSEdward Tomasz Napierala void
100e595e65bSEdward Tomasz Napierala receive_chunk(void **bufp, size_t *lenp, int pipefd)
101e595e65bSEdward Tomasz Napierala {
102e595e65bSEdward Tomasz Napierala 	ssize_t ret;
103e595e65bSEdward Tomasz Napierala 	size_t len;
104e595e65bSEdward Tomasz Napierala 	void *buf;
105e595e65bSEdward Tomasz Napierala 
106e595e65bSEdward Tomasz Napierala 	ret = read(pipefd, &len, sizeof(len));
107e595e65bSEdward Tomasz Napierala 	if (ret != sizeof(len))
108e595e65bSEdward Tomasz Napierala 		err(1, "read");
109e595e65bSEdward Tomasz Napierala 
110e595e65bSEdward Tomasz Napierala 	buf = calloc(1, len);
111e595e65bSEdward Tomasz Napierala 	if (buf == NULL)
112e595e65bSEdward Tomasz Napierala 		err(1, "calloc");
113e595e65bSEdward Tomasz Napierala 
114e595e65bSEdward Tomasz Napierala 	ret = read(pipefd, buf, len);
115e595e65bSEdward Tomasz Napierala 	if (ret != (ssize_t)len)
116e595e65bSEdward Tomasz Napierala 		err(1, "read");
117e595e65bSEdward Tomasz Napierala 
118e595e65bSEdward Tomasz Napierala 	*bufp = buf;
119e595e65bSEdward Tomasz Napierala 	*lenp = len;
120e595e65bSEdward Tomasz Napierala }
121e595e65bSEdward Tomasz Napierala 
122e595e65bSEdward Tomasz Napierala static char *
123e595e65bSEdward Tomasz Napierala bin2hex(const char *bin, size_t bin_len)
124e595e65bSEdward Tomasz Napierala {
125e595e65bSEdward Tomasz Napierala 	unsigned char *hex, *tmp, ch;
126e595e65bSEdward Tomasz Napierala 	size_t hex_len;
127e595e65bSEdward Tomasz Napierala 	size_t i;
128e595e65bSEdward Tomasz Napierala 
129e595e65bSEdward Tomasz Napierala 	hex_len = bin_len * 2 + 1; /* +1 for '\0'. */
130e595e65bSEdward Tomasz Napierala 	hex = malloc(hex_len);
131e595e65bSEdward Tomasz Napierala 	if (hex == NULL)
132e595e65bSEdward Tomasz Napierala 		err(1, "malloc");
133e595e65bSEdward Tomasz Napierala 
134e595e65bSEdward Tomasz Napierala 	tmp = hex;
135e595e65bSEdward Tomasz Napierala 	for (i = 0; i < bin_len; i++) {
136e595e65bSEdward Tomasz Napierala 		ch = bin[i];
137e595e65bSEdward Tomasz Napierala 		tmp += sprintf(tmp, "%02x", ch);
138e595e65bSEdward Tomasz Napierala 	}
139e595e65bSEdward Tomasz Napierala 
140e595e65bSEdward Tomasz Napierala 	return (hex);
141e595e65bSEdward Tomasz Napierala }
142e595e65bSEdward Tomasz Napierala 
143e595e65bSEdward Tomasz Napierala /*
144e595e65bSEdward Tomasz Napierala  * We need to replace a standard chunk of PKCS7 signature with one mandated
145e595e65bSEdward Tomasz Napierala  * by Authenticode.  Problem is, replacing it just like that and then calling
146e595e65bSEdward Tomasz Napierala  * PKCS7_final() would make OpenSSL segfault somewhere in PKCS7_dataFinal().
147e595e65bSEdward Tomasz Napierala  * So, instead, we call PKCS7_dataInit(), then put our Authenticode-specific
148e595e65bSEdward Tomasz Napierala  * data into BIO it returned, then call PKCS7_dataFinal() - which now somehow
149e595e65bSEdward Tomasz Napierala  * does not panic - and _then_ we replace it in the signature.  This technique
150e595e65bSEdward Tomasz Napierala  * was used in sbsigntool by Jeremy Kerr, and might have originated in
151e595e65bSEdward Tomasz Napierala  * osslsigncode.
152e595e65bSEdward Tomasz Napierala  */
153e595e65bSEdward Tomasz Napierala static void
154e595e65bSEdward Tomasz Napierala magic(PKCS7 *pkcs7, const char *digest, size_t digest_len)
155e595e65bSEdward Tomasz Napierala {
156e595e65bSEdward Tomasz Napierala 	BIO *bio, *t_bio;
157e595e65bSEdward Tomasz Napierala 	ASN1_TYPE *t;
158e595e65bSEdward Tomasz Napierala 	ASN1_STRING *s;
159e595e65bSEdward Tomasz Napierala 	CONF *cnf;
160e595e65bSEdward Tomasz Napierala 	unsigned char *buf, *tmp;
161e595e65bSEdward Tomasz Napierala 	char *digest_hex, *magic_conf, *str;
162e595e65bSEdward Tomasz Napierala 	int len, nid, ok;
163e595e65bSEdward Tomasz Napierala 
164e595e65bSEdward Tomasz Napierala 	digest_hex = bin2hex(digest, digest_len);
165e595e65bSEdward Tomasz Napierala 
166e595e65bSEdward Tomasz Napierala 	/*
167e595e65bSEdward Tomasz Napierala 	 * Construct the SpcIndirectDataContent chunk.
168e595e65bSEdward Tomasz Napierala 	 */
169e595e65bSEdward Tomasz Napierala 	nid = OBJ_create("1.3.6.1.4.1.311.2.1.4", NULL, NULL);
170e595e65bSEdward Tomasz Napierala 
171e595e65bSEdward Tomasz Napierala 	asprintf(&magic_conf, magic_fmt, digest_hex);
172e595e65bSEdward Tomasz Napierala 	if (magic_conf == NULL)
173e595e65bSEdward Tomasz Napierala 		err(1, "asprintf");
174e595e65bSEdward Tomasz Napierala 
175e595e65bSEdward Tomasz Napierala 	bio = BIO_new_mem_buf((void *)magic_conf, -1);
176e595e65bSEdward Tomasz Napierala 	if (bio == NULL) {
177e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
178e595e65bSEdward Tomasz Napierala 		errx(1, "BIO_new_mem_buf(3) failed");
179e595e65bSEdward Tomasz Napierala 	}
180e595e65bSEdward Tomasz Napierala 
181e595e65bSEdward Tomasz Napierala 	cnf = NCONF_new(NULL);
182e595e65bSEdward Tomasz Napierala 	if (cnf == NULL) {
183e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
184e595e65bSEdward Tomasz Napierala 		errx(1, "NCONF_new(3) failed");
185e595e65bSEdward Tomasz Napierala 	}
186e595e65bSEdward Tomasz Napierala 
187e595e65bSEdward Tomasz Napierala 	ok = NCONF_load_bio(cnf, bio, NULL);
188e595e65bSEdward Tomasz Napierala 	if (ok == 0) {
189e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
190e595e65bSEdward Tomasz Napierala 		errx(1, "NCONF_load_bio(3) failed");
191e595e65bSEdward Tomasz Napierala 	}
192e595e65bSEdward Tomasz Napierala 
193e595e65bSEdward Tomasz Napierala 	str = NCONF_get_string(cnf, "default", "asn1");
194e595e65bSEdward Tomasz Napierala 	if (str == NULL) {
195e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
196e595e65bSEdward Tomasz Napierala 		errx(1, "NCONF_get_string(3) failed");
197e595e65bSEdward Tomasz Napierala 	}
198e595e65bSEdward Tomasz Napierala 
199e595e65bSEdward Tomasz Napierala 	t = ASN1_generate_nconf(str, cnf);
200e595e65bSEdward Tomasz Napierala 	if (t == NULL) {
201e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
202e595e65bSEdward Tomasz Napierala 		errx(1, "ASN1_generate_nconf(3) failed");
203e595e65bSEdward Tomasz Napierala 	}
204e595e65bSEdward Tomasz Napierala 
205e595e65bSEdward Tomasz Napierala 	/*
206e595e65bSEdward Tomasz Napierala 	 * We now have our proprietary piece of ASN.1.  Let's do
207e595e65bSEdward Tomasz Napierala 	 * the actual signing.
208e595e65bSEdward Tomasz Napierala 	 */
209e595e65bSEdward Tomasz Napierala 	len = i2d_ASN1_TYPE(t, NULL);
210e595e65bSEdward Tomasz Napierala 	tmp = buf = calloc(1, len);
211e595e65bSEdward Tomasz Napierala 	if (tmp == NULL)
212e595e65bSEdward Tomasz Napierala 		err(1, "calloc");
213e595e65bSEdward Tomasz Napierala 	i2d_ASN1_TYPE(t, &tmp);
214e595e65bSEdward Tomasz Napierala 
215e595e65bSEdward Tomasz Napierala 	/*
216e595e65bSEdward Tomasz Napierala 	 * We now have contents of 't' stuffed into memory buffer 'buf'.
217e595e65bSEdward Tomasz Napierala 	 */
218e595e65bSEdward Tomasz Napierala 	tmp = NULL;
219e595e65bSEdward Tomasz Napierala 	t = NULL;
220e595e65bSEdward Tomasz Napierala 
221e595e65bSEdward Tomasz Napierala 	t_bio = PKCS7_dataInit(pkcs7, NULL);
222e595e65bSEdward Tomasz Napierala 	if (t_bio == NULL) {
223e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
224e595e65bSEdward Tomasz Napierala 		errx(1, "PKCS7_dataInit(3) failed");
225e595e65bSEdward Tomasz Napierala 	}
226e595e65bSEdward Tomasz Napierala 
227e595e65bSEdward Tomasz Napierala 	BIO_write(t_bio, buf + 2, len - 2);
228e595e65bSEdward Tomasz Napierala 
229e595e65bSEdward Tomasz Napierala 	ok = PKCS7_dataFinal(pkcs7, t_bio);
230e595e65bSEdward Tomasz Napierala 	if (ok == 0) {
231e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
232e595e65bSEdward Tomasz Napierala 		errx(1, "PKCS7_dataFinal(3) failed");
233e595e65bSEdward Tomasz Napierala 	}
234e595e65bSEdward Tomasz Napierala 
235e595e65bSEdward Tomasz Napierala 	t = ASN1_TYPE_new();
236e595e65bSEdward Tomasz Napierala 	s = ASN1_STRING_new();
237e595e65bSEdward Tomasz Napierala 	ASN1_STRING_set(s, buf, len);
238e595e65bSEdward Tomasz Napierala 	ASN1_TYPE_set(t, V_ASN1_SEQUENCE, s);
239e595e65bSEdward Tomasz Napierala 
240e595e65bSEdward Tomasz Napierala 	PKCS7_set0_type_other(pkcs7->d.sign->contents, nid, t);
241e595e65bSEdward Tomasz Napierala }
242e595e65bSEdward Tomasz Napierala 
243e595e65bSEdward Tomasz Napierala static void
244e595e65bSEdward Tomasz Napierala sign(X509 *cert, EVP_PKEY *key, int pipefd)
245e595e65bSEdward Tomasz Napierala {
246e595e65bSEdward Tomasz Napierala 	PKCS7 *pkcs7;
247e595e65bSEdward Tomasz Napierala 	BIO *bio, *out;
248e595e65bSEdward Tomasz Napierala 	const EVP_MD *md;
249e595e65bSEdward Tomasz Napierala 	PKCS7_SIGNER_INFO *info;
250e595e65bSEdward Tomasz Napierala 	void *digest, *signature;
251e595e65bSEdward Tomasz Napierala 	size_t digest_len, signature_len;
252e595e65bSEdward Tomasz Napierala 	int ok;
253e595e65bSEdward Tomasz Napierala 
254e595e65bSEdward Tomasz Napierala 	assert(cert != NULL);
255e595e65bSEdward Tomasz Napierala 	assert(key != NULL);
256e595e65bSEdward Tomasz Napierala 
257e595e65bSEdward Tomasz Napierala 	receive_chunk(&digest, &digest_len, pipefd);
258e595e65bSEdward Tomasz Napierala 
259e595e65bSEdward Tomasz Napierala 	bio = BIO_new_mem_buf(digest, digest_len);
260e595e65bSEdward Tomasz Napierala 	if (bio == NULL) {
261e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
262e595e65bSEdward Tomasz Napierala 		errx(1, "BIO_new_mem_buf(3) failed");
263e595e65bSEdward Tomasz Napierala 	}
264e595e65bSEdward Tomasz Napierala 
265e595e65bSEdward Tomasz Napierala 	pkcs7 = PKCS7_sign(NULL, NULL, NULL, bio, PKCS7_BINARY | PKCS7_PARTIAL);
266e595e65bSEdward Tomasz Napierala 	if (pkcs7 == NULL) {
267e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
268e595e65bSEdward Tomasz Napierala 		errx(1, "PKCS7_sign(3) failed");
269e595e65bSEdward Tomasz Napierala 	}
270e595e65bSEdward Tomasz Napierala 
271e595e65bSEdward Tomasz Napierala 	md = EVP_get_digestbyname(DIGEST);
272e595e65bSEdward Tomasz Napierala 	if (md == NULL) {
273e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
274e595e65bSEdward Tomasz Napierala 		errx(1, "EVP_get_digestbyname(\"%s\") failed", DIGEST);
275e595e65bSEdward Tomasz Napierala 	}
276e595e65bSEdward Tomasz Napierala 
277e595e65bSEdward Tomasz Napierala 	info = PKCS7_sign_add_signer(pkcs7, cert, key, md, 0);
278e595e65bSEdward Tomasz Napierala 	if (info == NULL) {
279e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
280e595e65bSEdward Tomasz Napierala 		errx(1, "PKCS7_sign_add_signer(3) failed");
281e595e65bSEdward Tomasz Napierala 	}
282e595e65bSEdward Tomasz Napierala 
283e595e65bSEdward Tomasz Napierala 	/*
284e595e65bSEdward Tomasz Napierala 	 * XXX: All the signed binaries seem to have this, but where is it
285e595e65bSEdward Tomasz Napierala 	 *      described in the spec?
286e595e65bSEdward Tomasz Napierala 	 */
287e595e65bSEdward Tomasz Napierala 	PKCS7_add_signed_attribute(info, NID_pkcs9_contentType,
288e595e65bSEdward Tomasz Napierala 	    V_ASN1_OBJECT, OBJ_txt2obj("1.3.6.1.4.1.311.2.1.4", 1));
289e595e65bSEdward Tomasz Napierala 
290e595e65bSEdward Tomasz Napierala 	magic(pkcs7, digest, digest_len);
291e595e65bSEdward Tomasz Napierala 
292e595e65bSEdward Tomasz Napierala #if 0
293e595e65bSEdward Tomasz Napierala 	out = BIO_new(BIO_s_file());
294e595e65bSEdward Tomasz Napierala 	BIO_set_fp(out, stdout, BIO_NOCLOSE);
295e595e65bSEdward Tomasz Napierala 	PKCS7_print_ctx(out, pkcs7, 0, NULL);
296e595e65bSEdward Tomasz Napierala 
297e595e65bSEdward Tomasz Napierala 	i2d_PKCS7_bio(out, pkcs7);
298e595e65bSEdward Tomasz Napierala #endif
299e595e65bSEdward Tomasz Napierala 
300e595e65bSEdward Tomasz Napierala 	out = BIO_new(BIO_s_mem());
301e595e65bSEdward Tomasz Napierala 	if (out == NULL) {
302e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
303e595e65bSEdward Tomasz Napierala 		errx(1, "BIO_new(3) failed");
304e595e65bSEdward Tomasz Napierala 	}
305e595e65bSEdward Tomasz Napierala 
306e595e65bSEdward Tomasz Napierala 	ok = i2d_PKCS7_bio(out, pkcs7);
307e595e65bSEdward Tomasz Napierala 	if (ok == 0) {
308e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
309e595e65bSEdward Tomasz Napierala 		errx(1, "i2d_PKCS7_bio(3) failed");
310e595e65bSEdward Tomasz Napierala 	}
311e595e65bSEdward Tomasz Napierala 
312e595e65bSEdward Tomasz Napierala 	signature_len = BIO_get_mem_data(out, &signature);
313e595e65bSEdward Tomasz Napierala 	if (signature_len <= 0) {
314e595e65bSEdward Tomasz Napierala 		ERR_print_errors_fp(stderr);
315e595e65bSEdward Tomasz Napierala 		errx(1, "BIO_get_mem_data(3) failed");
316e595e65bSEdward Tomasz Napierala 	}
317e595e65bSEdward Tomasz Napierala 
318e595e65bSEdward Tomasz Napierala 	(void)BIO_set_close(out, BIO_NOCLOSE);
319e595e65bSEdward Tomasz Napierala 	BIO_free(out);
320e595e65bSEdward Tomasz Napierala 
321e595e65bSEdward Tomasz Napierala 	send_chunk(signature, signature_len, pipefd);
322e595e65bSEdward Tomasz Napierala }
323e595e65bSEdward Tomasz Napierala 
324e595e65bSEdward Tomasz Napierala static int
325e595e65bSEdward Tomasz Napierala wait_for_child(pid_t pid)
326e595e65bSEdward Tomasz Napierala {
327e595e65bSEdward Tomasz Napierala 	int status;
328e595e65bSEdward Tomasz Napierala 
329e595e65bSEdward Tomasz Napierala 	pid = waitpid(pid, &status, 0);
330e595e65bSEdward Tomasz Napierala 	if (pid == -1)
331e595e65bSEdward Tomasz Napierala 		err(1, "waitpid");
332e595e65bSEdward Tomasz Napierala 
333e595e65bSEdward Tomasz Napierala 	return (WEXITSTATUS(status));
334e595e65bSEdward Tomasz Napierala }
335e595e65bSEdward Tomasz Napierala 
336e595e65bSEdward Tomasz Napierala int
337e595e65bSEdward Tomasz Napierala main(int argc, char **argv)
338e595e65bSEdward Tomasz Napierala {
339e595e65bSEdward Tomasz Napierala 	int ch, error;
340e595e65bSEdward Tomasz Napierala 	bool Vflag = false, vflag = false;
341e595e65bSEdward Tomasz Napierala 	const char *certpath = NULL, *keypath = NULL, *outpath = NULL, *inpath = NULL;
342e595e65bSEdward Tomasz Napierala 	FILE *certfp = NULL, *keyfp = NULL;
343e595e65bSEdward Tomasz Napierala 	X509 *cert = NULL;
344e595e65bSEdward Tomasz Napierala 	EVP_PKEY *key = NULL;
345e595e65bSEdward Tomasz Napierala 	pid_t pid;
346e595e65bSEdward Tomasz Napierala 	int pipefds[2];
347e595e65bSEdward Tomasz Napierala 
348e595e65bSEdward Tomasz Napierala 	while ((ch = getopt(argc, argv, "Vc:k:o:v")) != -1) {
349e595e65bSEdward Tomasz Napierala 		switch (ch) {
350e595e65bSEdward Tomasz Napierala 		case 'V':
351e595e65bSEdward Tomasz Napierala 			Vflag = true;
352e595e65bSEdward Tomasz Napierala 			break;
353e595e65bSEdward Tomasz Napierala 		case 'c':
354e595e65bSEdward Tomasz Napierala 			certpath = checked_strdup(optarg);
355e595e65bSEdward Tomasz Napierala 			break;
356e595e65bSEdward Tomasz Napierala 		case 'k':
357e595e65bSEdward Tomasz Napierala 			keypath = checked_strdup(optarg);
358e595e65bSEdward Tomasz Napierala 			break;
359e595e65bSEdward Tomasz Napierala 		case 'o':
360e595e65bSEdward Tomasz Napierala 			outpath = checked_strdup(optarg);
361e595e65bSEdward Tomasz Napierala 			break;
362e595e65bSEdward Tomasz Napierala 		case 'v':
363e595e65bSEdward Tomasz Napierala 			vflag = true;
364e595e65bSEdward Tomasz Napierala 			break;
365e595e65bSEdward Tomasz Napierala 		default:
366e595e65bSEdward Tomasz Napierala 			usage();
367e595e65bSEdward Tomasz Napierala 		}
368e595e65bSEdward Tomasz Napierala 	}
369e595e65bSEdward Tomasz Napierala 
370e595e65bSEdward Tomasz Napierala 	argc -= optind;
371e595e65bSEdward Tomasz Napierala 	argv += optind;
372e595e65bSEdward Tomasz Napierala 	if (argc != 1)
373e595e65bSEdward Tomasz Napierala 		usage();
374e595e65bSEdward Tomasz Napierala 
375e595e65bSEdward Tomasz Napierala 	if (Vflag) {
376e595e65bSEdward Tomasz Napierala 		if (certpath != NULL)
377e595e65bSEdward Tomasz Napierala 			errx(1, "-V and -c are mutually exclusive");
378e595e65bSEdward Tomasz Napierala 		if (keypath != NULL)
379e595e65bSEdward Tomasz Napierala 			errx(1, "-V and -k are mutually exclusive");
380e595e65bSEdward Tomasz Napierala 		if (outpath != NULL)
381e595e65bSEdward Tomasz Napierala 			errx(1, "-V and -o are mutually exclusive");
382e595e65bSEdward Tomasz Napierala 	} else {
383e595e65bSEdward Tomasz Napierala 		if (certpath == NULL)
384e595e65bSEdward Tomasz Napierala 			errx(1, "-c option is mandatory");
385e595e65bSEdward Tomasz Napierala 		if (keypath == NULL)
386e595e65bSEdward Tomasz Napierala 			errx(1, "-k option is mandatory");
387e595e65bSEdward Tomasz Napierala 		if (outpath == NULL)
388e595e65bSEdward Tomasz Napierala 			errx(1, "-o option is mandatory");
389e595e65bSEdward Tomasz Napierala 	}
390e595e65bSEdward Tomasz Napierala 
391e595e65bSEdward Tomasz Napierala 	inpath = argv[0];
392e595e65bSEdward Tomasz Napierala 
393e595e65bSEdward Tomasz Napierala 	OPENSSL_config(NULL);
394e595e65bSEdward Tomasz Napierala 	ERR_load_crypto_strings();
395e595e65bSEdward Tomasz Napierala 	OpenSSL_add_all_algorithms();
396e595e65bSEdward Tomasz Napierala 
397e595e65bSEdward Tomasz Napierala 	error = pipe(pipefds);
398e595e65bSEdward Tomasz Napierala 	if (error != 0)
399e595e65bSEdward Tomasz Napierala 		err(1, "pipe");
400e595e65bSEdward Tomasz Napierala 
401e595e65bSEdward Tomasz Napierala 	pid = fork();
402e595e65bSEdward Tomasz Napierala 	if (pid < 0)
403e595e65bSEdward Tomasz Napierala 		err(1, "fork");
404e595e65bSEdward Tomasz Napierala 
405e595e65bSEdward Tomasz Napierala 	if (pid == 0)
406e595e65bSEdward Tomasz Napierala 		return (child(inpath, outpath, pipefds[1], Vflag, vflag));
407e595e65bSEdward Tomasz Napierala 
408e595e65bSEdward Tomasz Napierala 	if (!Vflag) {
409e595e65bSEdward Tomasz Napierala 		certfp = checked_fopen(certpath, "r");
410e595e65bSEdward Tomasz Napierala 		cert = PEM_read_X509(certfp, NULL, NULL, NULL);
411e595e65bSEdward Tomasz Napierala 		if (cert == NULL) {
412e595e65bSEdward Tomasz Napierala 			ERR_print_errors_fp(stderr);
413e595e65bSEdward Tomasz Napierala 			errx(1, "failed to load certificate from %s", certpath);
414e595e65bSEdward Tomasz Napierala 		}
415e595e65bSEdward Tomasz Napierala 
416e595e65bSEdward Tomasz Napierala 		keyfp = checked_fopen(keypath, "r");
417e595e65bSEdward Tomasz Napierala 		key = PEM_read_PrivateKey(keyfp, NULL, NULL, NULL);
418e595e65bSEdward Tomasz Napierala 		if (key == NULL) {
419e595e65bSEdward Tomasz Napierala 			ERR_print_errors_fp(stderr);
420e595e65bSEdward Tomasz Napierala 			errx(1, "failed to load private key from %s", keypath);
421e595e65bSEdward Tomasz Napierala 		}
422e595e65bSEdward Tomasz Napierala 
423e595e65bSEdward Tomasz Napierala 		sign(cert, key, pipefds[0]);
424e595e65bSEdward Tomasz Napierala 	}
425e595e65bSEdward Tomasz Napierala 
426e595e65bSEdward Tomasz Napierala 	return (wait_for_child(pid));
427e595e65bSEdward Tomasz Napierala }
428