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