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