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