1*85d11f29Stb /* $OpenBSD: crl2p7.c,v 1.12 2024/12/26 14:07:58 tb Exp $ */ 2dab3f910Sjsing /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3dab3f910Sjsing * All rights reserved. 4dab3f910Sjsing * 5dab3f910Sjsing * This package is an SSL implementation written 6dab3f910Sjsing * by Eric Young (eay@cryptsoft.com). 7dab3f910Sjsing * The implementation was written so as to conform with Netscapes SSL. 8dab3f910Sjsing * 9dab3f910Sjsing * This library is free for commercial and non-commercial use as long as 10dab3f910Sjsing * the following conditions are aheared to. The following conditions 11dab3f910Sjsing * apply to all code found in this distribution, be it the RC4, RSA, 12dab3f910Sjsing * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13dab3f910Sjsing * included with this distribution is covered by the same copyright terms 14dab3f910Sjsing * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15dab3f910Sjsing * 16dab3f910Sjsing * Copyright remains Eric Young's, and as such any Copyright notices in 17dab3f910Sjsing * the code are not to be removed. 18dab3f910Sjsing * If this package is used in a product, Eric Young should be given attribution 19dab3f910Sjsing * as the author of the parts of the library used. 20dab3f910Sjsing * This can be in the form of a textual message at program startup or 21dab3f910Sjsing * in documentation (online or textual) provided with the package. 22dab3f910Sjsing * 23dab3f910Sjsing * Redistribution and use in source and binary forms, with or without 24dab3f910Sjsing * modification, are permitted provided that the following conditions 25dab3f910Sjsing * are met: 26dab3f910Sjsing * 1. Redistributions of source code must retain the copyright 27dab3f910Sjsing * notice, this list of conditions and the following disclaimer. 28dab3f910Sjsing * 2. Redistributions in binary form must reproduce the above copyright 29dab3f910Sjsing * notice, this list of conditions and the following disclaimer in the 30dab3f910Sjsing * documentation and/or other materials provided with the distribution. 31dab3f910Sjsing * 3. All advertising materials mentioning features or use of this software 32dab3f910Sjsing * must display the following acknowledgement: 33dab3f910Sjsing * "This product includes cryptographic software written by 34dab3f910Sjsing * Eric Young (eay@cryptsoft.com)" 35dab3f910Sjsing * The word 'cryptographic' can be left out if the rouines from the library 36dab3f910Sjsing * being used are not cryptographic related :-). 37dab3f910Sjsing * 4. If you include any Windows specific code (or a derivative thereof) from 38dab3f910Sjsing * the apps directory (application code) you must include an acknowledgement: 39dab3f910Sjsing * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40dab3f910Sjsing * 41dab3f910Sjsing * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42dab3f910Sjsing * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43dab3f910Sjsing * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44dab3f910Sjsing * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45dab3f910Sjsing * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46dab3f910Sjsing * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47dab3f910Sjsing * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48dab3f910Sjsing * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49dab3f910Sjsing * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50dab3f910Sjsing * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51dab3f910Sjsing * SUCH DAMAGE. 52dab3f910Sjsing * 53dab3f910Sjsing * The licence and distribution terms for any publically available version or 54dab3f910Sjsing * derivative of this code cannot be changed. i.e. this code cannot simply be 55dab3f910Sjsing * copied and put under another distribution licence 56dab3f910Sjsing * [including the GNU Public Licence.] 57dab3f910Sjsing */ 58dab3f910Sjsing 59dab3f910Sjsing /* This was written by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu> 60dab3f910Sjsing * and donated 'to the cause' along with lots and lots of other fixes to 61dab3f910Sjsing * the library. */ 62dab3f910Sjsing 63dab3f910Sjsing #include <sys/types.h> 64dab3f910Sjsing 65dab3f910Sjsing #include <stdio.h> 66dab3f910Sjsing #include <string.h> 67dab3f910Sjsing 68dab3f910Sjsing #include "apps.h" 69dab3f910Sjsing 70dab3f910Sjsing #include <openssl/err.h> 71dab3f910Sjsing #include <openssl/evp.h> 72dab3f910Sjsing #include <openssl/objects.h> 73dab3f910Sjsing #include <openssl/pem.h> 74dab3f910Sjsing #include <openssl/pkcs7.h> 75dab3f910Sjsing #include <openssl/x509.h> 76dab3f910Sjsing 77dab3f910Sjsing static int add_certs_from_file(STACK_OF(X509) * stack, char *certfile); 78dab3f910Sjsing 79320be8b6Sdoug static struct { 80320be8b6Sdoug STACK_OF(OPENSSL_STRING) *certflst; 81320be8b6Sdoug char *infile; 82320be8b6Sdoug int informat; 83320be8b6Sdoug int nocrl; 84320be8b6Sdoug char *outfile; 85320be8b6Sdoug int outformat; 86e7718adaStb } cfg; 87320be8b6Sdoug 88320be8b6Sdoug static int 89320be8b6Sdoug crl2p7_opt_certfile(char *arg) 90320be8b6Sdoug { 91e7718adaStb if (cfg.certflst == NULL) 92e7718adaStb cfg.certflst = sk_OPENSSL_STRING_new_null(); 93e7718adaStb if (cfg.certflst == NULL) { 94320be8b6Sdoug fprintf(stderr, "out of memory\n"); 95320be8b6Sdoug return (1); 96320be8b6Sdoug } 97e7718adaStb if (!sk_OPENSSL_STRING_push(cfg.certflst, arg)) { 98320be8b6Sdoug fprintf(stderr, "out of memory\n"); 99320be8b6Sdoug return (1); 100320be8b6Sdoug } 101320be8b6Sdoug 102320be8b6Sdoug return (0); 103320be8b6Sdoug } 104320be8b6Sdoug 105ea149709Sguenther static const struct option crl2p7_options[] = { 106320be8b6Sdoug { 107320be8b6Sdoug .name = "certfile", 108320be8b6Sdoug .argname = "file", 109320be8b6Sdoug .desc = "Chain of PEM certificates to a trusted CA", 110320be8b6Sdoug .type = OPTION_ARG_FUNC, 111320be8b6Sdoug .opt.argfunc = crl2p7_opt_certfile, 112320be8b6Sdoug }, 113320be8b6Sdoug { 114320be8b6Sdoug .name = "in", 115320be8b6Sdoug .argname = "file", 116320be8b6Sdoug .desc = "Input file (default stdin)", 117320be8b6Sdoug .type = OPTION_ARG, 118e7718adaStb .opt.arg = &cfg.infile, 119320be8b6Sdoug }, 120320be8b6Sdoug { 121320be8b6Sdoug .name = "inform", 122320be8b6Sdoug .argname = "format", 123320be8b6Sdoug .desc = "Input format (DER or PEM (default))", 124320be8b6Sdoug .type = OPTION_ARG_FORMAT, 125e7718adaStb .opt.value = &cfg.informat, 126320be8b6Sdoug }, 127320be8b6Sdoug { 128320be8b6Sdoug .name = "nocrl", 129320be8b6Sdoug .desc = "Do not read CRL from input or include CRL in output", 130320be8b6Sdoug .type = OPTION_FLAG, 131e7718adaStb .opt.flag = &cfg.nocrl, 132320be8b6Sdoug }, 133320be8b6Sdoug { 134320be8b6Sdoug .name = "out", 135320be8b6Sdoug .argname = "file", 136320be8b6Sdoug .desc = "Output file (default stdout)", 137320be8b6Sdoug .type = OPTION_ARG, 138e7718adaStb .opt.arg = &cfg.outfile, 139320be8b6Sdoug }, 140320be8b6Sdoug { 141320be8b6Sdoug .name = "outform", 142320be8b6Sdoug .argname = "format", 143320be8b6Sdoug .desc = "Output format (DER or PEM (default))", 144320be8b6Sdoug .type = OPTION_ARG_FORMAT, 145e7718adaStb .opt.value = &cfg.outformat, 146320be8b6Sdoug }, 147320be8b6Sdoug { NULL }, 148320be8b6Sdoug }; 149320be8b6Sdoug 150320be8b6Sdoug static void 151320be8b6Sdoug crl2p7_usage(void) 152320be8b6Sdoug { 153320be8b6Sdoug fprintf(stderr, 154320be8b6Sdoug "usage: crl2p7 [-certfile file] [-in file] [-inform DER | PEM]\n" 155320be8b6Sdoug " [-nocrl] [-out file] [-outform DER | PEM]\n\n"); 156320be8b6Sdoug options_usage(crl2p7_options); 157320be8b6Sdoug } 158dab3f910Sjsing 159dab3f910Sjsing int 160dab3f910Sjsing crl2pkcs7_main(int argc, char **argv) 161dab3f910Sjsing { 162320be8b6Sdoug int i; 163dab3f910Sjsing BIO *in = NULL, *out = NULL; 164320be8b6Sdoug char *certfile; 165dab3f910Sjsing PKCS7 *p7 = NULL; 166dab3f910Sjsing PKCS7_SIGNED *p7s = NULL; 167dab3f910Sjsing X509_CRL *crl = NULL; 168dab3f910Sjsing STACK_OF(X509_CRL) *crl_stack = NULL; 169dab3f910Sjsing STACK_OF(X509) *cert_stack = NULL; 170320be8b6Sdoug int ret = 1; 171dab3f910Sjsing 17251811eadSderaadt if (pledge("stdio cpath wpath rpath", NULL) == -1) { 1739bc487adSdoug perror("pledge"); 174e370f0eeSdoug exit(1); 175e370f0eeSdoug } 1769bc487adSdoug 177e7718adaStb memset(&cfg, 0, sizeof(cfg)); 178dab3f910Sjsing 179e7718adaStb cfg.informat = FORMAT_PEM; 180e7718adaStb cfg.outformat = FORMAT_PEM; 181dab3f910Sjsing 182320be8b6Sdoug if (options_parse(argc, argv, crl2p7_options, NULL, NULL) != 0) { 183320be8b6Sdoug crl2p7_usage(); 184dab3f910Sjsing goto end; 185dab3f910Sjsing } 186dab3f910Sjsing 187dab3f910Sjsing in = BIO_new(BIO_s_file()); 188dab3f910Sjsing out = BIO_new(BIO_s_file()); 189320be8b6Sdoug if (in == NULL || out == NULL) { 190dab3f910Sjsing ERR_print_errors(bio_err); 191dab3f910Sjsing goto end; 192dab3f910Sjsing } 193e7718adaStb if (!cfg.nocrl) { 194e7718adaStb if (cfg.infile == NULL) 195dab3f910Sjsing BIO_set_fp(in, stdin, BIO_NOCLOSE); 196dab3f910Sjsing else { 197e7718adaStb if (BIO_read_filename(in, cfg.infile) <= 0) { 198e7718adaStb perror(cfg.infile); 199dab3f910Sjsing goto end; 200dab3f910Sjsing } 201dab3f910Sjsing } 202dab3f910Sjsing 203e7718adaStb if (cfg.informat == FORMAT_ASN1) 204dab3f910Sjsing crl = d2i_X509_CRL_bio(in, NULL); 205e7718adaStb else if (cfg.informat == FORMAT_PEM) 206dab3f910Sjsing crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); 207dab3f910Sjsing else { 208dab3f910Sjsing BIO_printf(bio_err, 209dab3f910Sjsing "bad input format specified for input crl\n"); 210dab3f910Sjsing goto end; 211dab3f910Sjsing } 212dab3f910Sjsing if (crl == NULL) { 213dab3f910Sjsing BIO_printf(bio_err, "unable to load CRL\n"); 214dab3f910Sjsing ERR_print_errors(bio_err); 215dab3f910Sjsing goto end; 216dab3f910Sjsing } 217dab3f910Sjsing } 218dab3f910Sjsing if ((p7 = PKCS7_new()) == NULL) 219dab3f910Sjsing goto end; 220dab3f910Sjsing if ((p7s = PKCS7_SIGNED_new()) == NULL) 221dab3f910Sjsing goto end; 222dab3f910Sjsing p7->type = OBJ_nid2obj(NID_pkcs7_signed); 223dab3f910Sjsing p7->d.sign = p7s; 224dab3f910Sjsing p7s->contents->type = OBJ_nid2obj(NID_pkcs7_data); 225dab3f910Sjsing 226dab3f910Sjsing if (!ASN1_INTEGER_set(p7s->version, 1)) 227dab3f910Sjsing goto end; 228dab3f910Sjsing if ((crl_stack = sk_X509_CRL_new_null()) == NULL) 229dab3f910Sjsing goto end; 230dab3f910Sjsing p7s->crl = crl_stack; 231dab3f910Sjsing if (crl != NULL) { 232*85d11f29Stb if (!sk_X509_CRL_push(crl_stack, crl)) 233*85d11f29Stb goto end; 234*85d11f29Stb crl = NULL; 235dab3f910Sjsing } 236dab3f910Sjsing if ((cert_stack = sk_X509_new_null()) == NULL) 237dab3f910Sjsing goto end; 238dab3f910Sjsing p7s->cert = cert_stack; 239dab3f910Sjsing 240e7718adaStb if (cfg.certflst) { 241e7718adaStb for (i = 0; i < sk_OPENSSL_STRING_num(cfg.certflst); i++) { 242e7718adaStb certfile = sk_OPENSSL_STRING_value(cfg.certflst, i); 243dab3f910Sjsing if (add_certs_from_file(cert_stack, certfile) < 0) { 244dab3f910Sjsing BIO_printf(bio_err, 245dab3f910Sjsing "error loading certificates\n"); 246dab3f910Sjsing ERR_print_errors(bio_err); 247dab3f910Sjsing goto end; 248dab3f910Sjsing } 249dab3f910Sjsing } 250320be8b6Sdoug } 251dab3f910Sjsing 252e7718adaStb if (cfg.outfile == NULL) { 253dab3f910Sjsing BIO_set_fp(out, stdout, BIO_NOCLOSE); 254dab3f910Sjsing } else { 255e7718adaStb if (BIO_write_filename(out, cfg.outfile) <= 0) { 256e7718adaStb perror(cfg.outfile); 257dab3f910Sjsing goto end; 258dab3f910Sjsing } 259dab3f910Sjsing } 260dab3f910Sjsing 261e7718adaStb if (cfg.outformat == FORMAT_ASN1) 262dab3f910Sjsing i = i2d_PKCS7_bio(out, p7); 263e7718adaStb else if (cfg.outformat == FORMAT_PEM) 264dab3f910Sjsing i = PEM_write_bio_PKCS7(out, p7); 265dab3f910Sjsing else { 266dab3f910Sjsing BIO_printf(bio_err, 267dab3f910Sjsing "bad output format specified for outfile\n"); 268dab3f910Sjsing goto end; 269dab3f910Sjsing } 270dab3f910Sjsing if (!i) { 271dab3f910Sjsing BIO_printf(bio_err, "unable to write pkcs7 object\n"); 272dab3f910Sjsing ERR_print_errors(bio_err); 273dab3f910Sjsing goto end; 274dab3f910Sjsing } 275*85d11f29Stb 276dab3f910Sjsing ret = 0; 277dab3f910Sjsing 278dab3f910Sjsing end: 279dab3f910Sjsing BIO_free(in); 280dab3f910Sjsing BIO_free_all(out); 281dab3f910Sjsing PKCS7_free(p7); 282dab3f910Sjsing X509_CRL_free(crl); 283*85d11f29Stb sk_OPENSSL_STRING_free(cfg.certflst); 284dab3f910Sjsing 285*85d11f29Stb return ret; 286dab3f910Sjsing } 287dab3f910Sjsing 288dab3f910Sjsing static int 289dab3f910Sjsing add_certs_from_file(STACK_OF(X509) *stack, char *certfile) 290dab3f910Sjsing { 291dab3f910Sjsing BIO *in = NULL; 292dab3f910Sjsing int count = 0; 293dab3f910Sjsing int ret = -1; 294dab3f910Sjsing STACK_OF(X509_INFO) *sk = NULL; 295*85d11f29Stb X509_INFO *xi = NULL; 296dab3f910Sjsing 297dab3f910Sjsing in = BIO_new(BIO_s_file()); 298320be8b6Sdoug if (in == NULL || BIO_read_filename(in, certfile) <= 0) { 299dab3f910Sjsing BIO_printf(bio_err, "error opening the file, %s\n", certfile); 300dab3f910Sjsing goto end; 301dab3f910Sjsing } 302dab3f910Sjsing /* This loads from a file, a stack of x509/crl/pkey sets */ 303dab3f910Sjsing sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL); 304dab3f910Sjsing if (sk == NULL) { 305dab3f910Sjsing BIO_printf(bio_err, "error reading the file, %s\n", certfile); 306dab3f910Sjsing goto end; 307dab3f910Sjsing } 308dab3f910Sjsing /* scan over it and pull out the CRL's */ 309*85d11f29Stb while (sk_X509_INFO_num(sk) > 0) { 310dab3f910Sjsing xi = sk_X509_INFO_shift(sk); 311dab3f910Sjsing if (xi->x509 != NULL) { 312*85d11f29Stb if (!sk_X509_push(stack, xi->x509)) 313*85d11f29Stb goto end; 314dab3f910Sjsing xi->x509 = NULL; 315dab3f910Sjsing count++; 316dab3f910Sjsing } 317dab3f910Sjsing X509_INFO_free(xi); 318*85d11f29Stb xi = NULL; 319dab3f910Sjsing } 320dab3f910Sjsing 321dab3f910Sjsing ret = count; 322dab3f910Sjsing 323dab3f910Sjsing end: 324dab3f910Sjsing BIO_free(in); 325*85d11f29Stb X509_INFO_free(xi); 326dab3f910Sjsing sk_X509_INFO_free(sk); 327*85d11f29Stb 328*85d11f29Stb return ret; 329dab3f910Sjsing } 330