1*252eed92Stb /* $OpenBSD: x509.c,v 1.42 2025/01/19 13:14:22 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 #include <assert.h> 60662ea354Sinoguchi #include <limits.h> 61dab3f910Sjsing #include <stdio.h> 62dab3f910Sjsing #include <stdlib.h> 63dab3f910Sjsing #include <string.h> 64dab3f910Sjsing 65dab3f910Sjsing #include "apps.h" 66dab3f910Sjsing 67dab3f910Sjsing #include <openssl/asn1.h> 68dab3f910Sjsing #include <openssl/bio.h> 69dab3f910Sjsing #include <openssl/bn.h> 70662ea354Sinoguchi #include <openssl/dsa.h> 71dab3f910Sjsing #include <openssl/err.h> 72dab3f910Sjsing #include <openssl/evp.h> 73dab3f910Sjsing #include <openssl/objects.h> 74dab3f910Sjsing #include <openssl/pem.h> 75662ea354Sinoguchi #include <openssl/rsa.h> 76dab3f910Sjsing #include <openssl/x509.h> 77dab3f910Sjsing #include <openssl/x509v3.h> 78dab3f910Sjsing 79dab3f910Sjsing #define POSTFIX ".srl" 80dab3f910Sjsing #define DEF_DAYS 30 81dab3f910Sjsing 82dab3f910Sjsing static int callb(int ok, X509_STORE_CTX *ctx); 83dab3f910Sjsing static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, 84d4c9bc7eSjob const EVP_MD *digest, CONF *conf, char *section, X509_NAME *issuer, 85d4c9bc7eSjob char *force_pubkey); 86dab3f910Sjsing static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, 87dab3f910Sjsing X509 *x, X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts, 88dab3f910Sjsing char *serial, int create, int days, int clrext, CONF *conf, char *section, 890293fcf8Sjob ASN1_INTEGER *sno, X509_NAME *issuer); 905bbf7eacStb static int purpose_print(BIO *bio, X509 *cert, const X509_PURPOSE *pt); 9134d3f182Sinoguchi 9234d3f182Sinoguchi static struct { 9334d3f182Sinoguchi char *alias; 9434d3f182Sinoguchi int aliasout; 9534d3f182Sinoguchi int badops; 9634d3f182Sinoguchi int CA_createserial; 9734d3f182Sinoguchi int CA_flag; 9834d3f182Sinoguchi char *CAfile; 9934d3f182Sinoguchi int CAformat; 10034d3f182Sinoguchi char *CAkeyfile; 10134d3f182Sinoguchi int CAkeyformat; 10234d3f182Sinoguchi char *CAserial; 10334d3f182Sinoguchi unsigned long certflag; 10434d3f182Sinoguchi int checkend; 10534d3f182Sinoguchi int checkoffset; 1060293fcf8Sjob unsigned long chtype; 10734d3f182Sinoguchi int clrext; 10834d3f182Sinoguchi int clrreject; 10934d3f182Sinoguchi int clrtrust; 11034d3f182Sinoguchi int days; 11134d3f182Sinoguchi const EVP_MD *digest; 11234d3f182Sinoguchi int email; 11334d3f182Sinoguchi int enddate; 11434d3f182Sinoguchi char *extfile; 11534d3f182Sinoguchi char *extsect; 11634d3f182Sinoguchi int fingerprint; 1170293fcf8Sjob char *force_pubkey; 11834d3f182Sinoguchi char *infile; 11934d3f182Sinoguchi int informat; 12034d3f182Sinoguchi int issuer; 12134d3f182Sinoguchi int issuer_hash; 12234d3f182Sinoguchi #ifndef OPENSSL_NO_MD5 12334d3f182Sinoguchi int issuer_hash_old; 12434d3f182Sinoguchi #endif 12534d3f182Sinoguchi char *keyfile; 12634d3f182Sinoguchi int keyformat; 12734d3f182Sinoguchi const EVP_MD *md_alg; 12834d3f182Sinoguchi int modulus; 1290293fcf8Sjob int multirdn; 130d4c9bc7eSjob int new; 13134d3f182Sinoguchi int next_serial; 13234d3f182Sinoguchi unsigned long nmflag; 13334d3f182Sinoguchi int noout; 13434d3f182Sinoguchi int num; 13534d3f182Sinoguchi int ocspid; 13634d3f182Sinoguchi ASN1_OBJECT *objtmp; 13734d3f182Sinoguchi int ocsp_uri; 13834d3f182Sinoguchi char *outfile; 13934d3f182Sinoguchi int outformat; 14034d3f182Sinoguchi char *passargin; 14134d3f182Sinoguchi int pprint; 14234d3f182Sinoguchi int pubkey; 14334d3f182Sinoguchi STACK_OF(ASN1_OBJECT) *reject; 14434d3f182Sinoguchi int reqfile; 14534d3f182Sinoguchi int serial; 1460293fcf8Sjob char *set_issuer; 1470293fcf8Sjob char *set_subject; 14834d3f182Sinoguchi int sign_flag; 14934d3f182Sinoguchi STACK_OF(OPENSSL_STRING) *sigopts; 15034d3f182Sinoguchi ASN1_INTEGER *sno; 15134d3f182Sinoguchi int startdate; 15234d3f182Sinoguchi int subject; 15334d3f182Sinoguchi int subject_hash; 15434d3f182Sinoguchi #ifndef OPENSSL_NO_MD5 15534d3f182Sinoguchi int subject_hash_old; 15634d3f182Sinoguchi #endif 15734d3f182Sinoguchi int text; 15834d3f182Sinoguchi STACK_OF(ASN1_OBJECT) *trust; 15934d3f182Sinoguchi int trustout; 16034d3f182Sinoguchi int x509req; 161e7718adaStb } cfg; 16234d3f182Sinoguchi 16334d3f182Sinoguchi static int 16434d3f182Sinoguchi x509_opt_addreject(char *arg) 16534d3f182Sinoguchi { 166e7718adaStb if ((cfg.objtmp = OBJ_txt2obj(arg, 0)) == NULL) { 16734d3f182Sinoguchi BIO_printf(bio_err, "Invalid reject object value %s\n", arg); 16834d3f182Sinoguchi return (1); 16934d3f182Sinoguchi } 17034d3f182Sinoguchi 171e7718adaStb if (cfg.reject == NULL && 172e7718adaStb (cfg.reject = sk_ASN1_OBJECT_new_null()) == NULL) 17334d3f182Sinoguchi return (1); 17434d3f182Sinoguchi 175e7718adaStb if (!sk_ASN1_OBJECT_push(cfg.reject, cfg.objtmp)) 17634d3f182Sinoguchi return (1); 17734d3f182Sinoguchi 178e7718adaStb cfg.trustout = 1; 17934d3f182Sinoguchi return (0); 18034d3f182Sinoguchi } 18134d3f182Sinoguchi 18234d3f182Sinoguchi static int 18334d3f182Sinoguchi x509_opt_addtrust(char *arg) 18434d3f182Sinoguchi { 185e7718adaStb if ((cfg.objtmp = OBJ_txt2obj(arg, 0)) == NULL) { 18634d3f182Sinoguchi BIO_printf(bio_err, "Invalid trust object value %s\n", arg); 18734d3f182Sinoguchi return (1); 18834d3f182Sinoguchi } 18934d3f182Sinoguchi 190e7718adaStb if (cfg.trust == NULL && 191e7718adaStb (cfg.trust = sk_ASN1_OBJECT_new_null()) == NULL) 19234d3f182Sinoguchi return (1); 19334d3f182Sinoguchi 194e7718adaStb if (!sk_ASN1_OBJECT_push(cfg.trust, cfg.objtmp)) 19534d3f182Sinoguchi return (1); 19634d3f182Sinoguchi 197e7718adaStb cfg.trustout = 1; 19834d3f182Sinoguchi return (0); 19934d3f182Sinoguchi } 20034d3f182Sinoguchi 20134d3f182Sinoguchi static int 20234d3f182Sinoguchi x509_opt_ca(char *arg) 20334d3f182Sinoguchi { 204e7718adaStb cfg.CAfile = arg; 205e7718adaStb cfg.CA_flag = ++cfg.num; 20634d3f182Sinoguchi return (0); 20734d3f182Sinoguchi } 20834d3f182Sinoguchi 20934d3f182Sinoguchi static int 21034d3f182Sinoguchi x509_opt_certopt(char *arg) 21134d3f182Sinoguchi { 212e7718adaStb if (!set_cert_ex(&cfg.certflag, arg)) 21334d3f182Sinoguchi return (1); 21434d3f182Sinoguchi 21534d3f182Sinoguchi return (0); 21634d3f182Sinoguchi } 21734d3f182Sinoguchi 21834d3f182Sinoguchi static int 21934d3f182Sinoguchi x509_opt_checkend(char *arg) 22034d3f182Sinoguchi { 22134d3f182Sinoguchi const char *errstr; 22234d3f182Sinoguchi 223e7718adaStb cfg.checkoffset = strtonum(arg, 0, INT_MAX, &errstr); 22434d3f182Sinoguchi if (errstr != NULL) { 22534d3f182Sinoguchi BIO_printf(bio_err, "checkend unusable: %s\n", errstr); 22634d3f182Sinoguchi return (1); 22734d3f182Sinoguchi } 228e7718adaStb cfg.checkend = 1; 22934d3f182Sinoguchi return (0); 23034d3f182Sinoguchi } 23134d3f182Sinoguchi 23234d3f182Sinoguchi static int 23334d3f182Sinoguchi x509_opt_dates(void) 23434d3f182Sinoguchi { 235e7718adaStb cfg.startdate = ++cfg.num; 236e7718adaStb cfg.enddate = ++cfg.num; 23734d3f182Sinoguchi return (0); 23834d3f182Sinoguchi } 23934d3f182Sinoguchi 24034d3f182Sinoguchi static int 24134d3f182Sinoguchi x509_opt_days(char *arg) 24234d3f182Sinoguchi { 24334d3f182Sinoguchi const char *errstr; 24434d3f182Sinoguchi 245e7718adaStb cfg.days = strtonum(arg, 1, INT_MAX, &errstr); 24634d3f182Sinoguchi if (errstr != NULL) { 24734d3f182Sinoguchi BIO_printf(bio_err, "bad number of days: %s\n", errstr); 24834d3f182Sinoguchi return (1); 24934d3f182Sinoguchi } 25034d3f182Sinoguchi return (0); 25134d3f182Sinoguchi } 25234d3f182Sinoguchi 25334d3f182Sinoguchi static int 25434d3f182Sinoguchi x509_opt_digest(int argc, char **argv, int *argsused) 25534d3f182Sinoguchi { 25634d3f182Sinoguchi char *name = argv[0]; 25734d3f182Sinoguchi 25834d3f182Sinoguchi if (*name++ != '-') 25934d3f182Sinoguchi return (1); 26034d3f182Sinoguchi 261e7718adaStb if ((cfg.md_alg = EVP_get_digestbyname(name)) != NULL) { 262e7718adaStb cfg.digest = cfg.md_alg; 26334d3f182Sinoguchi } else { 26434d3f182Sinoguchi BIO_printf(bio_err, "unknown option %s\n", *argv); 265e7718adaStb cfg.badops = 1; 26634d3f182Sinoguchi return (1); 26734d3f182Sinoguchi } 26834d3f182Sinoguchi 26934d3f182Sinoguchi *argsused = 1; 27034d3f182Sinoguchi return (0); 27134d3f182Sinoguchi } 27234d3f182Sinoguchi 27334d3f182Sinoguchi static int 27434d3f182Sinoguchi x509_opt_nameopt(char *arg) 27534d3f182Sinoguchi { 276e7718adaStb if (!set_name_ex(&cfg.nmflag, arg)) 27734d3f182Sinoguchi return (1); 27834d3f182Sinoguchi 27934d3f182Sinoguchi return (0); 28034d3f182Sinoguchi } 28134d3f182Sinoguchi 28234d3f182Sinoguchi static int 28334d3f182Sinoguchi x509_opt_set_serial(char *arg) 28434d3f182Sinoguchi { 285e7718adaStb ASN1_INTEGER_free(cfg.sno); 286e7718adaStb if ((cfg.sno = s2i_ASN1_INTEGER(NULL, arg)) == NULL) 28734d3f182Sinoguchi return (1); 28834d3f182Sinoguchi 28934d3f182Sinoguchi return (0); 29034d3f182Sinoguchi } 29134d3f182Sinoguchi 29234d3f182Sinoguchi static int 29334d3f182Sinoguchi x509_opt_setalias(char *arg) 29434d3f182Sinoguchi { 295e7718adaStb cfg.alias = arg; 296e7718adaStb cfg.trustout = 1; 29734d3f182Sinoguchi return (0); 29834d3f182Sinoguchi } 29934d3f182Sinoguchi 30034d3f182Sinoguchi static int 30134d3f182Sinoguchi x509_opt_signkey(char *arg) 30234d3f182Sinoguchi { 303e7718adaStb cfg.keyfile = arg; 304e7718adaStb cfg.sign_flag = ++cfg.num; 30534d3f182Sinoguchi return (0); 30634d3f182Sinoguchi } 30734d3f182Sinoguchi 30834d3f182Sinoguchi static int 30934d3f182Sinoguchi x509_opt_sigopt(char *arg) 31034d3f182Sinoguchi { 311e7718adaStb if (cfg.sigopts == NULL && 312e7718adaStb (cfg.sigopts = sk_OPENSSL_STRING_new_null()) == NULL) 31334d3f182Sinoguchi return (1); 31434d3f182Sinoguchi 315e7718adaStb if (!sk_OPENSSL_STRING_push(cfg.sigopts, arg)) 31634d3f182Sinoguchi return (1); 31734d3f182Sinoguchi 31834d3f182Sinoguchi return (0); 31934d3f182Sinoguchi } 32034d3f182Sinoguchi 3210293fcf8Sjob static int 3220293fcf8Sjob x509_opt_utf8(void) 3230293fcf8Sjob { 3240293fcf8Sjob cfg.chtype = MBSTRING_UTF8; 3250293fcf8Sjob return (0); 3260293fcf8Sjob } 3270293fcf8Sjob 32834d3f182Sinoguchi static const struct option x509_options[] = { 32934d3f182Sinoguchi { 33034d3f182Sinoguchi .name = "addreject", 33134d3f182Sinoguchi .argname = "arg", 33234d3f182Sinoguchi .desc = "Reject certificate for a given purpose", 33334d3f182Sinoguchi .type = OPTION_ARG_FUNC, 33434d3f182Sinoguchi .opt.argfunc = x509_opt_addreject, 33534d3f182Sinoguchi }, 33634d3f182Sinoguchi { 33734d3f182Sinoguchi .name = "addtrust", 33834d3f182Sinoguchi .argname = "arg", 33934d3f182Sinoguchi .desc = "Trust certificate for a given purpose", 34034d3f182Sinoguchi .type = OPTION_ARG_FUNC, 34134d3f182Sinoguchi .opt.argfunc = x509_opt_addtrust, 34234d3f182Sinoguchi }, 34334d3f182Sinoguchi { 34434d3f182Sinoguchi .name = "alias", 34534d3f182Sinoguchi .desc = "Output certificate alias", 34634d3f182Sinoguchi .type = OPTION_ORDER, 347e7718adaStb .opt.order = &cfg.aliasout, 348e7718adaStb .order = &cfg.num, 34934d3f182Sinoguchi }, 35034d3f182Sinoguchi { 35134d3f182Sinoguchi .name = "CA", 35234d3f182Sinoguchi .argname = "file", 35334d3f182Sinoguchi .desc = "CA certificate in PEM format unless -CAform is specified", 35434d3f182Sinoguchi .type = OPTION_ARG_FUNC, 35534d3f182Sinoguchi .opt.argfunc = x509_opt_ca, 35634d3f182Sinoguchi }, 35734d3f182Sinoguchi { 35834d3f182Sinoguchi .name = "CAcreateserial", 35934d3f182Sinoguchi .desc = "Create serial number file if it does not exist", 36034d3f182Sinoguchi .type = OPTION_ORDER, 361e7718adaStb .opt.order = &cfg.CA_createserial, 362e7718adaStb .order = &cfg.num, 36334d3f182Sinoguchi }, 36434d3f182Sinoguchi { 36534d3f182Sinoguchi .name = "CAform", 36634d3f182Sinoguchi .argname = "fmt", 36734d3f182Sinoguchi .desc = "CA format - default PEM", 36834d3f182Sinoguchi .type = OPTION_ARG_FORMAT, 369e7718adaStb .opt.value = &cfg.CAformat, 37034d3f182Sinoguchi }, 37134d3f182Sinoguchi { 37234d3f182Sinoguchi .name = "CAkey", 37334d3f182Sinoguchi .argname = "file", 37434d3f182Sinoguchi .desc = "CA key in PEM format unless -CAkeyform is specified\n" 37534d3f182Sinoguchi "if omitted, the key is assumed to be in the CA file", 37634d3f182Sinoguchi .type = OPTION_ARG, 377e7718adaStb .opt.arg = &cfg.CAkeyfile, 37834d3f182Sinoguchi }, 37934d3f182Sinoguchi { 38034d3f182Sinoguchi .name = "CAkeyform", 38134d3f182Sinoguchi .argname = "fmt", 38234d3f182Sinoguchi .desc = "CA key format - default PEM", 38334d3f182Sinoguchi .type = OPTION_ARG_FORMAT, 384e7718adaStb .opt.value = &cfg.CAkeyformat, 38534d3f182Sinoguchi }, 38634d3f182Sinoguchi { 38734d3f182Sinoguchi .name = "CAserial", 38834d3f182Sinoguchi .argname = "file", 38934d3f182Sinoguchi .desc = "Serial file", 39034d3f182Sinoguchi .type = OPTION_ARG, 391e7718adaStb .opt.arg = &cfg.CAserial, 39234d3f182Sinoguchi }, 39334d3f182Sinoguchi { 39434d3f182Sinoguchi .name = "certopt", 39534d3f182Sinoguchi .argname = "option", 39634d3f182Sinoguchi .desc = "Various certificate text options", 39734d3f182Sinoguchi .type = OPTION_ARG_FUNC, 39834d3f182Sinoguchi .opt.argfunc = x509_opt_certopt, 39934d3f182Sinoguchi }, 40034d3f182Sinoguchi { 40134d3f182Sinoguchi .name = "checkend", 40234d3f182Sinoguchi .argname = "arg", 40334d3f182Sinoguchi .desc = "Check whether the cert expires in the next arg seconds\n" 40434d3f182Sinoguchi "exit 1 if so, 0 if not", 40534d3f182Sinoguchi .type = OPTION_ARG_FUNC, 40634d3f182Sinoguchi .opt.argfunc = x509_opt_checkend, 40734d3f182Sinoguchi }, 40834d3f182Sinoguchi { 40934d3f182Sinoguchi .name = "clrext", 41034d3f182Sinoguchi .desc = "Clear all extensions", 41134d3f182Sinoguchi .type = OPTION_FLAG, 412e7718adaStb .opt.flag = &cfg.clrext, 41334d3f182Sinoguchi }, 41434d3f182Sinoguchi { 41534d3f182Sinoguchi .name = "clrreject", 41634d3f182Sinoguchi .desc = "Clear all rejected purposes", 41734d3f182Sinoguchi .type = OPTION_ORDER, 418e7718adaStb .opt.order = &cfg.clrreject, 419e7718adaStb .order = &cfg.num, 42034d3f182Sinoguchi }, 42134d3f182Sinoguchi { 42234d3f182Sinoguchi .name = "clrtrust", 42334d3f182Sinoguchi .desc = "Clear all trusted purposes", 42434d3f182Sinoguchi .type = OPTION_ORDER, 425e7718adaStb .opt.order = &cfg.clrtrust, 426e7718adaStb .order = &cfg.num, 42734d3f182Sinoguchi }, 42834d3f182Sinoguchi { 42934d3f182Sinoguchi .name = "dates", 43034d3f182Sinoguchi .desc = "Both Before and After dates", 43134d3f182Sinoguchi .type = OPTION_FUNC, 43234d3f182Sinoguchi .opt.func = x509_opt_dates, 43334d3f182Sinoguchi }, 43434d3f182Sinoguchi { 43534d3f182Sinoguchi .name = "days", 43634d3f182Sinoguchi .argname = "arg", 43734d3f182Sinoguchi .desc = "How long till expiry of a signed certificate - def 30 days", 43834d3f182Sinoguchi .type = OPTION_ARG_FUNC, 43934d3f182Sinoguchi .opt.argfunc = x509_opt_days, 44034d3f182Sinoguchi }, 44134d3f182Sinoguchi { 44234d3f182Sinoguchi .name = "email", 44334d3f182Sinoguchi .desc = "Print email address(es)", 44434d3f182Sinoguchi .type = OPTION_ORDER, 445e7718adaStb .opt.order = &cfg.email, 446e7718adaStb .order = &cfg.num, 44734d3f182Sinoguchi }, 44834d3f182Sinoguchi { 44934d3f182Sinoguchi .name = "enddate", 45034d3f182Sinoguchi .desc = "Print notAfter field", 45134d3f182Sinoguchi .type = OPTION_ORDER, 452e7718adaStb .opt.order = &cfg.enddate, 453e7718adaStb .order = &cfg.num, 45434d3f182Sinoguchi }, 45534d3f182Sinoguchi { 45634d3f182Sinoguchi .name = "extensions", 45734d3f182Sinoguchi .argname = "section", 45834d3f182Sinoguchi .desc = "Section from config file with X509V3 extensions to add", 45934d3f182Sinoguchi .type = OPTION_ARG, 460e7718adaStb .opt.arg = &cfg.extsect, 46134d3f182Sinoguchi }, 46234d3f182Sinoguchi { 46334d3f182Sinoguchi .name = "extfile", 46434d3f182Sinoguchi .argname = "file", 46534d3f182Sinoguchi .desc = "Configuration file with X509V3 extensions to add", 46634d3f182Sinoguchi .type = OPTION_ARG, 467e7718adaStb .opt.arg = &cfg.extfile, 46834d3f182Sinoguchi }, 46934d3f182Sinoguchi { 47034d3f182Sinoguchi .name = "fingerprint", 47134d3f182Sinoguchi .desc = "Print the certificate fingerprint", 47234d3f182Sinoguchi .type = OPTION_ORDER, 473e7718adaStb .opt.order = &cfg.fingerprint, 474e7718adaStb .order = &cfg.num, 47534d3f182Sinoguchi }, 47634d3f182Sinoguchi { 4770293fcf8Sjob .name = "force_pubkey", 4780293fcf8Sjob .argname = "key", 4790293fcf8Sjob .desc = "Force the public key to be put in the certificate", 4800293fcf8Sjob .type = OPTION_ARG, 4810293fcf8Sjob .opt.arg = &cfg.force_pubkey, 4820293fcf8Sjob }, 4830293fcf8Sjob { 48434d3f182Sinoguchi .name = "hash", 48534d3f182Sinoguchi .desc = "Synonym for -subject_hash", 48634d3f182Sinoguchi .type = OPTION_ORDER, 487e7718adaStb .opt.order = &cfg.subject_hash, 488e7718adaStb .order = &cfg.num, 48934d3f182Sinoguchi }, 49034d3f182Sinoguchi { 49134d3f182Sinoguchi .name = "in", 49234d3f182Sinoguchi .argname = "file", 49334d3f182Sinoguchi .desc = "Input file - default stdin", 49434d3f182Sinoguchi .type = OPTION_ARG, 495e7718adaStb .opt.arg = &cfg.infile, 49634d3f182Sinoguchi }, 49734d3f182Sinoguchi { 49834d3f182Sinoguchi .name = "inform", 49934d3f182Sinoguchi .argname = "fmt", 50034d3f182Sinoguchi .desc = "Input format - default PEM (one of DER, NET or PEM)", 50134d3f182Sinoguchi .type = OPTION_ARG_FORMAT, 502e7718adaStb .opt.value = &cfg.informat, 50334d3f182Sinoguchi }, 50434d3f182Sinoguchi { 50534d3f182Sinoguchi .name = "issuer", 50634d3f182Sinoguchi .desc = "Print issuer name", 50734d3f182Sinoguchi .type = OPTION_ORDER, 508e7718adaStb .opt.order = &cfg.issuer, 509e7718adaStb .order = &cfg.num, 51034d3f182Sinoguchi }, 51134d3f182Sinoguchi { 51234d3f182Sinoguchi .name = "issuer_hash", 51334d3f182Sinoguchi .desc = "Print issuer hash value", 51434d3f182Sinoguchi .type = OPTION_ORDER, 515e7718adaStb .opt.order = &cfg.issuer_hash, 516e7718adaStb .order = &cfg.num, 51734d3f182Sinoguchi }, 51834d3f182Sinoguchi #ifndef OPENSSL_NO_MD5 51934d3f182Sinoguchi { 52034d3f182Sinoguchi .name = "issuer_hash_old", 52134d3f182Sinoguchi .desc = "Print old-style (MD5) issuer hash value", 52234d3f182Sinoguchi .type = OPTION_ORDER, 523e7718adaStb .opt.order = &cfg.issuer_hash_old, 524e7718adaStb .order = &cfg.num, 52534d3f182Sinoguchi }, 52634d3f182Sinoguchi #endif 52734d3f182Sinoguchi { 528d4c9bc7eSjob .name = "key", 529d4c9bc7eSjob .argname = "file", 530d4c9bc7eSjob .type = OPTION_ARG_FUNC, 531d4c9bc7eSjob .opt.argfunc = x509_opt_signkey, 532d4c9bc7eSjob }, 533d4c9bc7eSjob { 53434d3f182Sinoguchi .name = "keyform", 53534d3f182Sinoguchi .argname = "fmt", 53634d3f182Sinoguchi .desc = "Private key format - default PEM", 53734d3f182Sinoguchi .type = OPTION_ARG_FORMAT, 538e7718adaStb .opt.value = &cfg.keyformat, 53934d3f182Sinoguchi }, 54034d3f182Sinoguchi { 54134d3f182Sinoguchi .name = "modulus", 54234d3f182Sinoguchi .desc = "Print the RSA key modulus", 54334d3f182Sinoguchi .type = OPTION_ORDER, 544e7718adaStb .opt.order = &cfg.modulus, 545e7718adaStb .order = &cfg.num, 54634d3f182Sinoguchi }, 54734d3f182Sinoguchi { 5480293fcf8Sjob .name = "multivalue-rdn", 5490293fcf8Sjob .desc = "Enable support for multivalued RDNs", 5500293fcf8Sjob .type = OPTION_FLAG, 5510293fcf8Sjob .opt.flag = &cfg.multirdn, 5520293fcf8Sjob }, 5530293fcf8Sjob { 55434d3f182Sinoguchi .name = "nameopt", 55534d3f182Sinoguchi .argname = "option", 55634d3f182Sinoguchi .desc = "Various certificate name options", 55734d3f182Sinoguchi .type = OPTION_ARG_FUNC, 55834d3f182Sinoguchi .opt.argfunc = x509_opt_nameopt, 55934d3f182Sinoguchi }, 56034d3f182Sinoguchi { 561d4c9bc7eSjob .name = "new", 562d4c9bc7eSjob .desc = "Generate a new certificate", 563d4c9bc7eSjob .type = OPTION_FLAG, 564d4c9bc7eSjob .opt.flag = &cfg.new, 565d4c9bc7eSjob }, 566d4c9bc7eSjob { 56734d3f182Sinoguchi .name = "next_serial", 56834d3f182Sinoguchi .desc = "Print the next serial number", 56934d3f182Sinoguchi .type = OPTION_ORDER, 570e7718adaStb .opt.order = &cfg.next_serial, 571e7718adaStb .order = &cfg.num, 57234d3f182Sinoguchi }, 57334d3f182Sinoguchi { 57434d3f182Sinoguchi .name = "noout", 57534d3f182Sinoguchi .desc = "No certificate output", 57634d3f182Sinoguchi .type = OPTION_ORDER, 577e7718adaStb .opt.order = &cfg.noout, 578e7718adaStb .order = &cfg.num, 57934d3f182Sinoguchi }, 58034d3f182Sinoguchi { 58134d3f182Sinoguchi .name = "ocsp_uri", 58234d3f182Sinoguchi .desc = "Print OCSP Responder URL(s)", 58334d3f182Sinoguchi .type = OPTION_ORDER, 584e7718adaStb .opt.order = &cfg.ocsp_uri, 585e7718adaStb .order = &cfg.num, 58634d3f182Sinoguchi }, 58734d3f182Sinoguchi { 58834d3f182Sinoguchi .name = "ocspid", 58934d3f182Sinoguchi .desc = "Print OCSP hash values for the subject name and public key", 59034d3f182Sinoguchi .type = OPTION_ORDER, 591e7718adaStb .opt.order = &cfg.ocspid, 592e7718adaStb .order = &cfg.num, 59334d3f182Sinoguchi }, 59434d3f182Sinoguchi { 59534d3f182Sinoguchi .name = "out", 59634d3f182Sinoguchi .argname = "file", 59734d3f182Sinoguchi .desc = "Output file - default stdout", 59834d3f182Sinoguchi .type = OPTION_ARG, 599e7718adaStb .opt.arg = &cfg.outfile, 60034d3f182Sinoguchi }, 60134d3f182Sinoguchi { 60234d3f182Sinoguchi .name = "outform", 60334d3f182Sinoguchi .argname = "fmt", 60434d3f182Sinoguchi .desc = "Output format - default PEM (one of DER, NET or PEM)", 60534d3f182Sinoguchi .type = OPTION_ARG_FORMAT, 606e7718adaStb .opt.value = &cfg.outformat, 60734d3f182Sinoguchi }, 60834d3f182Sinoguchi { 60934d3f182Sinoguchi .name = "passin", 61034d3f182Sinoguchi .argname = "src", 61134d3f182Sinoguchi .desc = "Private key password source", 61234d3f182Sinoguchi .type = OPTION_ARG, 613e7718adaStb .opt.arg = &cfg.passargin, 61434d3f182Sinoguchi }, 61534d3f182Sinoguchi { 61634d3f182Sinoguchi .name = "pubkey", 61734d3f182Sinoguchi .desc = "Output the public key", 61834d3f182Sinoguchi .type = OPTION_ORDER, 619e7718adaStb .opt.order = &cfg.pubkey, 620e7718adaStb .order = &cfg.num, 62134d3f182Sinoguchi }, 62234d3f182Sinoguchi { 62334d3f182Sinoguchi .name = "purpose", 62434d3f182Sinoguchi .desc = "Print out certificate purposes", 62534d3f182Sinoguchi .type = OPTION_ORDER, 626e7718adaStb .opt.order = &cfg.pprint, 627e7718adaStb .order = &cfg.num, 62834d3f182Sinoguchi }, 62934d3f182Sinoguchi { 63034d3f182Sinoguchi .name = "req", 63134d3f182Sinoguchi .desc = "Input is a certificate request, sign and output", 63234d3f182Sinoguchi .type = OPTION_FLAG, 633e7718adaStb .opt.flag = &cfg.reqfile, 63434d3f182Sinoguchi }, 63534d3f182Sinoguchi { 63634d3f182Sinoguchi .name = "serial", 63734d3f182Sinoguchi .desc = "Print serial number value", 63834d3f182Sinoguchi .type = OPTION_ORDER, 639e7718adaStb .opt.order = &cfg.serial, 640e7718adaStb .order = &cfg.num, 64134d3f182Sinoguchi }, 64234d3f182Sinoguchi { 6430293fcf8Sjob .name = "set_issuer", 6440293fcf8Sjob .argname = "name", 6450293fcf8Sjob .desc = "Set the issuer name", 6460293fcf8Sjob .type = OPTION_ARG, 6470293fcf8Sjob .opt.arg = &cfg.set_issuer, 6480293fcf8Sjob }, 6490293fcf8Sjob { 65034d3f182Sinoguchi .name = "set_serial", 65134d3f182Sinoguchi .argname = "n", 65234d3f182Sinoguchi .desc = "Serial number to use", 65334d3f182Sinoguchi .type = OPTION_ARG_FUNC, 65434d3f182Sinoguchi .opt.argfunc = x509_opt_set_serial, 65534d3f182Sinoguchi }, 65634d3f182Sinoguchi { 6570293fcf8Sjob .name = "set_subject", 6580293fcf8Sjob .argname = "name", 6590293fcf8Sjob .desc = "Set the subject name", 6600293fcf8Sjob .type = OPTION_ARG, 6610293fcf8Sjob .opt.arg = &cfg.set_subject, 6620293fcf8Sjob }, 6630293fcf8Sjob { 66434d3f182Sinoguchi .name = "setalias", 66534d3f182Sinoguchi .argname = "arg", 66634d3f182Sinoguchi .desc = "Set certificate alias", 66734d3f182Sinoguchi .type = OPTION_ARG_FUNC, 66834d3f182Sinoguchi .opt.argfunc = x509_opt_setalias, 66934d3f182Sinoguchi }, 67034d3f182Sinoguchi { 67134d3f182Sinoguchi .name = "signkey", 67234d3f182Sinoguchi .argname = "file", 67334d3f182Sinoguchi .desc = "Self sign cert with arg", 67434d3f182Sinoguchi .type = OPTION_ARG_FUNC, 67534d3f182Sinoguchi .opt.argfunc = x509_opt_signkey, 67634d3f182Sinoguchi }, 67734d3f182Sinoguchi { 67834d3f182Sinoguchi .name = "sigopt", 67934d3f182Sinoguchi .argname = "nm:v", 68034d3f182Sinoguchi .desc = "Various signature algorithm options", 68134d3f182Sinoguchi .type = OPTION_ARG_FUNC, 68234d3f182Sinoguchi .opt.argfunc = x509_opt_sigopt, 68334d3f182Sinoguchi }, 68434d3f182Sinoguchi { 68534d3f182Sinoguchi .name = "startdate", 68634d3f182Sinoguchi .desc = "Print notBefore field", 68734d3f182Sinoguchi .type = OPTION_ORDER, 688e7718adaStb .opt.order = &cfg.startdate, 689e7718adaStb .order = &cfg.num, 69034d3f182Sinoguchi }, 69134d3f182Sinoguchi { 6920293fcf8Sjob .name = "subj", 6930293fcf8Sjob .type = OPTION_ARG, 6940293fcf8Sjob .opt.arg = &cfg.set_subject, 6950293fcf8Sjob }, 6960293fcf8Sjob { 69734d3f182Sinoguchi .name = "subject", 69834d3f182Sinoguchi .desc = "Print subject name", 69934d3f182Sinoguchi .type = OPTION_ORDER, 700e7718adaStb .opt.order = &cfg.subject, 701e7718adaStb .order = &cfg.num, 70234d3f182Sinoguchi }, 70334d3f182Sinoguchi { 70434d3f182Sinoguchi .name = "subject_hash", 70534d3f182Sinoguchi .desc = "Print subject hash value", 70634d3f182Sinoguchi .type = OPTION_ORDER, 707e7718adaStb .opt.order = &cfg.subject_hash, 708e7718adaStb .order = &cfg.num, 70934d3f182Sinoguchi }, 71034d3f182Sinoguchi #ifndef OPENSSL_NO_MD5 71134d3f182Sinoguchi { 71234d3f182Sinoguchi .name = "subject_hash_old", 71334d3f182Sinoguchi .desc = "Print old-style (MD5) subject hash value", 71434d3f182Sinoguchi .type = OPTION_ORDER, 715e7718adaStb .opt.order = &cfg.subject_hash_old, 716e7718adaStb .order = &cfg.num, 71734d3f182Sinoguchi }, 71834d3f182Sinoguchi #endif 71934d3f182Sinoguchi { 72034d3f182Sinoguchi .name = "text", 72134d3f182Sinoguchi .desc = "Print the certificate in text form", 72234d3f182Sinoguchi .type = OPTION_ORDER, 723e7718adaStb .opt.order = &cfg.text, 724e7718adaStb .order = &cfg.num, 72534d3f182Sinoguchi }, 72634d3f182Sinoguchi { 72734d3f182Sinoguchi .name = "trustout", 72834d3f182Sinoguchi .desc = "Output a trusted certificate", 72934d3f182Sinoguchi .type = OPTION_FLAG, 730e7718adaStb .opt.flag = &cfg.trustout, 73134d3f182Sinoguchi }, 73234d3f182Sinoguchi { 7330293fcf8Sjob .name = "utf8", 7340293fcf8Sjob .desc = "Input characters are in UTF-8 (default ASCII)", 7350293fcf8Sjob .type = OPTION_FUNC, 7360293fcf8Sjob .opt.func = x509_opt_utf8, 7370293fcf8Sjob }, 7380293fcf8Sjob { 73934d3f182Sinoguchi .name = "x509toreq", 74034d3f182Sinoguchi .desc = "Output a certification request object", 74134d3f182Sinoguchi .type = OPTION_ORDER, 742e7718adaStb .opt.order = &cfg.x509req, 743e7718adaStb .order = &cfg.num, 74434d3f182Sinoguchi }, 74534d3f182Sinoguchi { 74634d3f182Sinoguchi .name = NULL, 74734d3f182Sinoguchi .desc = "", 74834d3f182Sinoguchi .type = OPTION_ARGV_FUNC, 74934d3f182Sinoguchi .opt.argvfunc = x509_opt_digest, 75034d3f182Sinoguchi }, 75134d3f182Sinoguchi { NULL }, 75234d3f182Sinoguchi }; 75334d3f182Sinoguchi 75434d3f182Sinoguchi static void 75534d3f182Sinoguchi x509_usage(void) 75634d3f182Sinoguchi { 75734d3f182Sinoguchi fprintf(stderr, "usage: x509 " 758a9d90585Stb "[-addreject arg] [-addtrust arg] [-alias] [-CA file]\n" 75934d3f182Sinoguchi " [-CAcreateserial] [-CAform der | pem] [-CAkey file]\n" 76034d3f182Sinoguchi " [-CAkeyform der | pem] [-CAserial file] [-certopt option]\n" 76134d3f182Sinoguchi " [-checkend arg] [-clrext] [-clrreject] [-clrtrust] [-dates]\n" 76234d3f182Sinoguchi " [-days arg] [-email] [-enddate] [-extensions section]\n" 7630293fcf8Sjob " [-extfile file] [-fingerprint] [-force_pubkey key] [-hash]\n" 7640293fcf8Sjob " [-in file] [-inform der | net | pem] [-issuer]\n" 7650293fcf8Sjob " [-issuer_hash] [-issuer_hash_old] [-keyform der | pem]\n" 7660293fcf8Sjob " [-md5 | -sha1] [-modulus] [-multivalue-rdn]\n" 767d4c9bc7eSjob " [-nameopt option] [-new] [-next_serial] [-noout] [-ocsp_uri]\n" 7680293fcf8Sjob " [-ocspid] [-out file] [-outform der | net | pem]\n" 7690293fcf8Sjob " [-passin arg] [-pubkey] [-purpose] [-req] [-serial]\n" 7700293fcf8Sjob " [-set_issuer name] [-set_serial n] [-set_subject name]\n" 7710293fcf8Sjob " [-setalias arg] [-signkey file] [-sigopt nm:v] [-startdate]\n" 7720293fcf8Sjob " [-subject] [-subject_hash] [-subject_hash_old] [-text]\n" 7730293fcf8Sjob " [-trustout] [-utf8] [-x509toreq]\n"); 77434d3f182Sinoguchi fprintf(stderr, "\n"); 77534d3f182Sinoguchi options_usage(x509_options); 77634d3f182Sinoguchi fprintf(stderr, "\n"); 77734d3f182Sinoguchi } 778dab3f910Sjsing 779dab3f910Sjsing int 780dab3f910Sjsing x509_main(int argc, char **argv) 781dab3f910Sjsing { 782dab3f910Sjsing int ret = 1; 783dab3f910Sjsing X509_REQ *req = NULL; 784dab3f910Sjsing X509 *x = NULL, *xca = NULL; 7850293fcf8Sjob X509_NAME *iname = NULL, *sname = NULL; 7860293fcf8Sjob EVP_PKEY *Fpkey = NULL, *Upkey = NULL, *CApkey = NULL; 787d4c9bc7eSjob EVP_PKEY *pkey; 78834d3f182Sinoguchi int i; 789dab3f910Sjsing BIO *out = NULL; 790dab3f910Sjsing BIO *STDout = NULL; 791dab3f910Sjsing X509_STORE *ctx = NULL; 792dab3f910Sjsing X509_REQ *rq = NULL; 793dab3f910Sjsing CONF *extconf = NULL; 79434d3f182Sinoguchi char *passin = NULL; 795dab3f910Sjsing 79651811eadSderaadt if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 7979bc487adSdoug perror("pledge"); 798e370f0eeSdoug exit(1); 799e370f0eeSdoug } 8009bc487adSdoug 801e7718adaStb memset(&cfg, 0, sizeof(cfg)); 8020293fcf8Sjob cfg.chtype = MBSTRING_ASC; 803e7718adaStb cfg.days = DEF_DAYS; 804e7718adaStb cfg.informat = FORMAT_PEM; 805e7718adaStb cfg.outformat = FORMAT_PEM; 806e7718adaStb cfg.keyformat = FORMAT_PEM; 807e7718adaStb cfg.CAformat = FORMAT_PEM; 808e7718adaStb cfg.CAkeyformat = FORMAT_PEM; 809dab3f910Sjsing 810dab3f910Sjsing STDout = BIO_new_fp(stdout, BIO_NOCLOSE); 811dab3f910Sjsing 812dab3f910Sjsing ctx = X509_STORE_new(); 813dab3f910Sjsing if (ctx == NULL) 814dab3f910Sjsing goto end; 815dab3f910Sjsing X509_STORE_set_verify_cb(ctx, callb); 816dab3f910Sjsing 81734d3f182Sinoguchi if (options_parse(argc, argv, x509_options, NULL, NULL) != 0) 818dab3f910Sjsing goto bad; 819dab3f910Sjsing 820e7718adaStb if (cfg.badops) { 821dab3f910Sjsing bad: 82234d3f182Sinoguchi x509_usage(); 823dab3f910Sjsing goto end; 824dab3f910Sjsing } 825dab3f910Sjsing 826e7718adaStb if (!app_passwd(bio_err, cfg.passargin, NULL, &passin, NULL)) { 827dab3f910Sjsing BIO_printf(bio_err, "Error getting password\n"); 828dab3f910Sjsing goto end; 829dab3f910Sjsing } 830dab3f910Sjsing if (!X509_STORE_set_default_paths(ctx)) { 831dab3f910Sjsing ERR_print_errors(bio_err); 832dab3f910Sjsing goto end; 833dab3f910Sjsing } 8345c31e3d8Stb if (cfg.CAkeyfile == NULL && cfg.CA_flag && cfg.CAformat == FORMAT_PEM) { 835e7718adaStb cfg.CAkeyfile = cfg.CAfile; 8365c31e3d8Stb } else if (cfg.CA_flag && cfg.CAkeyfile == NULL) { 837dab3f910Sjsing BIO_printf(bio_err, 838dab3f910Sjsing "need to specify a CAkey if using the CA command\n"); 839dab3f910Sjsing goto end; 840dab3f910Sjsing } 841e7718adaStb if (cfg.extfile != NULL) { 842dab3f910Sjsing long errorline = -1; 843dab3f910Sjsing X509V3_CTX ctx2; 844dab3f910Sjsing extconf = NCONF_new(NULL); 845e7718adaStb if (!NCONF_load(extconf, cfg.extfile, &errorline)) { 846dab3f910Sjsing if (errorline <= 0) 847dab3f910Sjsing BIO_printf(bio_err, 848dab3f910Sjsing "error loading the config file '%s'\n", 849e7718adaStb cfg.extfile); 850dab3f910Sjsing else 851dab3f910Sjsing BIO_printf(bio_err, 852dab3f910Sjsing "error on line %ld of config file '%s'\n", 853e7718adaStb errorline, cfg.extfile); 854dab3f910Sjsing goto end; 855dab3f910Sjsing } 856e7718adaStb if (cfg.extsect == NULL) { 8575c31e3d8Stb cfg.extsect = NCONF_get_string(extconf, "default", 8585c31e3d8Stb "extensions"); 859e7718adaStb if (cfg.extsect == NULL) { 860dab3f910Sjsing ERR_clear_error(); 861e7718adaStb cfg.extsect = "default"; 862dab3f910Sjsing } 863dab3f910Sjsing } 864dab3f910Sjsing X509V3_set_ctx_test(&ctx2); 865dab3f910Sjsing X509V3_set_nconf(&ctx2, extconf); 8665c31e3d8Stb if (!X509V3_EXT_add_nconf(extconf, &ctx2, cfg.extsect, NULL)) { 867dab3f910Sjsing BIO_printf(bio_err, 8685c31e3d8Stb "Error Loading extension section %s\n", cfg.extsect); 869dab3f910Sjsing ERR_print_errors(bio_err); 870dab3f910Sjsing goto end; 871dab3f910Sjsing } 872dab3f910Sjsing } 8730293fcf8Sjob if (cfg.force_pubkey != NULL) { 8740293fcf8Sjob if ((Fpkey = load_pubkey(bio_err, cfg.force_pubkey, 8750293fcf8Sjob cfg.keyformat, 0, NULL, "Forced key")) == NULL) 8760293fcf8Sjob goto end; 8770293fcf8Sjob } 878d4c9bc7eSjob if (cfg.new) { 879d4c9bc7eSjob if (cfg.infile != NULL) { 880d4c9bc7eSjob BIO_printf(bio_err, "Can't combine -new and -in\n"); 881d4c9bc7eSjob goto end; 882d4c9bc7eSjob } 883e7718adaStb if (cfg.reqfile) { 884d4c9bc7eSjob BIO_printf(bio_err, "Can't combine -new and -req\n"); 885d4c9bc7eSjob goto end; 886d4c9bc7eSjob } 887d4c9bc7eSjob if (cfg.set_subject == NULL) { 888d4c9bc7eSjob BIO_printf(bio_err, "Must use -set_subject with -new\n"); 889d4c9bc7eSjob goto end; 890d4c9bc7eSjob } 891d4c9bc7eSjob if (cfg.keyfile == NULL) { 892d4c9bc7eSjob BIO_printf(bio_err, "Must use -signkey with -new\n"); 893d4c9bc7eSjob goto end; 894d4c9bc7eSjob } 895d4c9bc7eSjob if ((Upkey = load_key(bio_err, cfg.keyfile, cfg.keyformat, 0, 896d4c9bc7eSjob passin, "Private key")) == NULL) 897d4c9bc7eSjob goto end; 898d4c9bc7eSjob } 899d4c9bc7eSjob if (cfg.reqfile) { 900dab3f910Sjsing BIO *in; 901dab3f910Sjsing 902e7718adaStb if (!cfg.sign_flag && !cfg.CA_flag) { 903662ea354Sinoguchi BIO_printf(bio_err, 904662ea354Sinoguchi "We need a private key to sign with\n"); 905dab3f910Sjsing goto end; 906dab3f910Sjsing } 907dab3f910Sjsing in = BIO_new(BIO_s_file()); 908dab3f910Sjsing if (in == NULL) { 909dab3f910Sjsing ERR_print_errors(bio_err); 910dab3f910Sjsing goto end; 911dab3f910Sjsing } 912e7718adaStb if (cfg.infile == NULL) 913dab3f910Sjsing BIO_set_fp(in, stdin, BIO_NOCLOSE | BIO_FP_TEXT); 914dab3f910Sjsing else { 915e7718adaStb if (BIO_read_filename(in, cfg.infile) <= 0) { 916e7718adaStb perror(cfg.infile); 917dab3f910Sjsing BIO_free(in); 918dab3f910Sjsing goto end; 919dab3f910Sjsing } 920dab3f910Sjsing } 921dab3f910Sjsing req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL); 922dab3f910Sjsing BIO_free(in); 923dab3f910Sjsing 924dab3f910Sjsing if (req == NULL) { 925dab3f910Sjsing ERR_print_errors(bio_err); 926dab3f910Sjsing goto end; 927dab3f910Sjsing } 92819ac38f1Stb if ((pkey = X509_REQ_get0_pubkey(req)) == NULL) { 929dab3f910Sjsing BIO_printf(bio_err, "error unpacking public key\n"); 930dab3f910Sjsing goto end; 931dab3f910Sjsing } 932dab3f910Sjsing i = X509_REQ_verify(req, pkey); 933dab3f910Sjsing if (i < 0) { 934dab3f910Sjsing BIO_printf(bio_err, "Signature verification error\n"); 935dab3f910Sjsing ERR_print_errors(bio_err); 936dab3f910Sjsing goto end; 937dab3f910Sjsing } 938dab3f910Sjsing if (i == 0) { 939662ea354Sinoguchi BIO_printf(bio_err, 940662ea354Sinoguchi "Signature did not match the certificate request\n"); 941dab3f910Sjsing goto end; 942dab3f910Sjsing } else 943dab3f910Sjsing BIO_printf(bio_err, "Signature ok\n"); 944dab3f910Sjsing 945662ea354Sinoguchi print_name(bio_err, "subject=", X509_REQ_get_subject_name(req), 946e7718adaStb cfg.nmflag); 947dab3f910Sjsing 948d4c9bc7eSjob } 949d4c9bc7eSjob if (cfg.reqfile || cfg.new) { 950dab3f910Sjsing if ((x = X509_new()) == NULL) 951dab3f910Sjsing goto end; 952dab3f910Sjsing 953e7718adaStb if (cfg.sno == NULL) { 954e7718adaStb cfg.sno = ASN1_INTEGER_new(); 9555c31e3d8Stb if (cfg.sno == NULL || !rand_serial(NULL, cfg.sno)) 956dab3f910Sjsing goto end; 957e7718adaStb if (!X509_set_serialNumber(x, cfg.sno)) 958dab3f910Sjsing goto end; 959e7718adaStb ASN1_INTEGER_free(cfg.sno); 960e7718adaStb cfg.sno = NULL; 961e7718adaStb } else if (!X509_set_serialNumber(x, cfg.sno)) 962dab3f910Sjsing goto end; 963dab3f910Sjsing 9640293fcf8Sjob if (cfg.set_issuer != NULL) { 9650293fcf8Sjob iname = parse_name(cfg.set_issuer, cfg.chtype, 9660293fcf8Sjob cfg.multirdn); 9670293fcf8Sjob if (iname == NULL) 968dab3f910Sjsing goto end; 9690293fcf8Sjob } 9700293fcf8Sjob 9710293fcf8Sjob if (cfg.set_subject != NULL) 9720293fcf8Sjob sname = parse_name(cfg.set_subject, cfg.chtype, 9730293fcf8Sjob cfg.multirdn); 9740293fcf8Sjob else 9750293fcf8Sjob sname = X509_NAME_dup(X509_REQ_get_subject_name(req)); 9760293fcf8Sjob if (sname == NULL) 9770293fcf8Sjob goto end; 9780293fcf8Sjob if (!X509_set_subject_name(x, sname)) 979dab3f910Sjsing goto end; 980dab3f910Sjsing 9819d967dc8Sinoguchi if (X509_gmtime_adj(X509_get_notBefore(x), 0) == NULL) 9829d967dc8Sinoguchi goto end; 983e7718adaStb if (X509_time_adj_ex(X509_get_notAfter(x), cfg.days, 0, 9849d967dc8Sinoguchi NULL) == NULL) 9859d967dc8Sinoguchi goto end; 986dab3f910Sjsing 9870293fcf8Sjob if ((pkey = Fpkey) == NULL) 9880293fcf8Sjob pkey = X509_REQ_get0_pubkey(req); 9890293fcf8Sjob if (pkey == NULL) 990d4c9bc7eSjob pkey = Upkey; 991d4c9bc7eSjob if (pkey == NULL) 9929d967dc8Sinoguchi goto end; 9939e77a05dStb if (!X509_set_pubkey(x, pkey)) 9949d967dc8Sinoguchi goto end; 9959d967dc8Sinoguchi } else { 9965c31e3d8Stb x = load_cert(bio_err, cfg.infile, cfg.informat, NULL, 9975c31e3d8Stb "Certificate"); 9989d967dc8Sinoguchi } 999dab3f910Sjsing if (x == NULL) 1000dab3f910Sjsing goto end; 10019d967dc8Sinoguchi 1002e7718adaStb if (cfg.CA_flag) { 10035c31e3d8Stb xca = load_cert(bio_err, cfg.CAfile, cfg.CAformat, NULL, 10045c31e3d8Stb "CA Certificate"); 1005dab3f910Sjsing if (xca == NULL) 1006dab3f910Sjsing goto end; 1007dab3f910Sjsing } 1008e7718adaStb if (!cfg.noout || cfg.text || cfg.next_serial) { 1009662ea354Sinoguchi OBJ_create("2.99999.3", "SET.ex3", "SET x509v3 extension 3"); 1010dab3f910Sjsing 1011dab3f910Sjsing out = BIO_new(BIO_s_file()); 1012dab3f910Sjsing if (out == NULL) { 1013dab3f910Sjsing ERR_print_errors(bio_err); 1014dab3f910Sjsing goto end; 1015dab3f910Sjsing } 1016e7718adaStb if (cfg.outfile == NULL) { 1017dab3f910Sjsing BIO_set_fp(out, stdout, BIO_NOCLOSE); 1018dab3f910Sjsing } else { 1019e7718adaStb if (BIO_write_filename(out, cfg.outfile) <= 0) { 1020e7718adaStb perror(cfg.outfile); 1021dab3f910Sjsing goto end; 1022dab3f910Sjsing } 1023dab3f910Sjsing } 1024dab3f910Sjsing } 1025e7718adaStb if (cfg.alias != NULL) { 1026e7718adaStb if (!X509_alias_set1(x, (unsigned char *)cfg.alias, -1)) 10279d967dc8Sinoguchi goto end; 10289d967dc8Sinoguchi } 1029dab3f910Sjsing 1030e7718adaStb if (cfg.clrtrust) 1031dab3f910Sjsing X509_trust_clear(x); 1032e7718adaStb if (cfg.clrreject) 1033dab3f910Sjsing X509_reject_clear(x); 1034dab3f910Sjsing 1035e7718adaStb if (cfg.trust != NULL) { 1036e7718adaStb for (i = 0; i < sk_ASN1_OBJECT_num(cfg.trust); i++) { 10375c31e3d8Stb cfg.objtmp = sk_ASN1_OBJECT_value(cfg.trust, i); 1038e7718adaStb if (!X509_add1_trust_object(x, cfg.objtmp)) 10399d967dc8Sinoguchi goto end; 1040dab3f910Sjsing } 1041dab3f910Sjsing } 1042e7718adaStb if (cfg.reject != NULL) { 1043e7718adaStb for (i = 0; i < sk_ASN1_OBJECT_num(cfg.reject); i++) { 10445c31e3d8Stb cfg.objtmp = sk_ASN1_OBJECT_value(cfg.reject, i); 1045e7718adaStb if (!X509_add1_reject_object(x, cfg.objtmp)) 10469d967dc8Sinoguchi goto end; 1047dab3f910Sjsing } 1048dab3f910Sjsing } 1049e7718adaStb if (cfg.num) { 1050e7718adaStb for (i = 1; i <= cfg.num; i++) { 1051e7718adaStb if (cfg.issuer == i) { 1052dab3f910Sjsing print_name(STDout, "issuer= ", 10535c31e3d8Stb X509_get_issuer_name(x), cfg.nmflag); 1054e7718adaStb } else if (cfg.subject == i) { 1055dab3f910Sjsing print_name(STDout, "subject= ", 10565c31e3d8Stb X509_get_subject_name(x), cfg.nmflag); 1057e7718adaStb } else if (cfg.serial == i) { 1058dab3f910Sjsing BIO_printf(STDout, "serial="); 1059dab3f910Sjsing i2a_ASN1_INTEGER(STDout, 1060dab3f910Sjsing X509_get_serialNumber(x)); 1061dab3f910Sjsing BIO_printf(STDout, "\n"); 1062e7718adaStb } else if (cfg.next_serial == i) { 1063dab3f910Sjsing BIGNUM *bnser; 1064dab3f910Sjsing ASN1_INTEGER *ser; 10655c31e3d8Stb 1066dab3f910Sjsing ser = X509_get_serialNumber(x); 10679d967dc8Sinoguchi if (ser == NULL) 10689d967dc8Sinoguchi goto end; 1069dab3f910Sjsing bnser = ASN1_INTEGER_to_BN(ser, NULL); 10701274c900Sinoguchi if (bnser == NULL) 1071dab3f910Sjsing goto end; 1072f4c45f04Sinoguchi if (!BN_add_word(bnser, 1)) { 1073f4c45f04Sinoguchi BN_free(bnser); 1074dab3f910Sjsing goto end; 1075f4c45f04Sinoguchi } 1076dab3f910Sjsing ser = BN_to_ASN1_INTEGER(bnser, NULL); 1077f4c45f04Sinoguchi if (ser == NULL) { 1078f4c45f04Sinoguchi BN_free(bnser); 1079dab3f910Sjsing goto end; 1080f4c45f04Sinoguchi } 1081dab3f910Sjsing BN_free(bnser); 1082dab3f910Sjsing i2a_ASN1_INTEGER(out, ser); 1083dab3f910Sjsing ASN1_INTEGER_free(ser); 1084dab3f910Sjsing BIO_puts(out, "\n"); 10855c31e3d8Stb } else if (cfg.email == i || cfg.ocsp_uri == i) { 1086dab3f910Sjsing STACK_OF(OPENSSL_STRING) *emlst; 10875c31e3d8Stb int j; 10885c31e3d8Stb 1089e7718adaStb if (cfg.email == i) 1090dab3f910Sjsing emlst = X509_get1_email(x); 1091dab3f910Sjsing else 1092dab3f910Sjsing emlst = X509_get1_ocsp(x); 1093dab3f910Sjsing for (j = 0; j < sk_OPENSSL_STRING_num(emlst); j++) 1094dab3f910Sjsing BIO_printf(STDout, "%s\n", 1095dab3f910Sjsing sk_OPENSSL_STRING_value(emlst, j)); 1096dab3f910Sjsing X509_email_free(emlst); 1097e7718adaStb } else if (cfg.aliasout == i) { 109862085575Sschwarze unsigned char *albuf; 109962085575Sschwarze int buflen; 110062085575Sschwarze albuf = X509_alias_get0(x, &buflen); 110162085575Sschwarze if (albuf != NULL) 110262085575Sschwarze BIO_printf(STDout, "%.*s\n", 110362085575Sschwarze buflen, albuf); 1104dab3f910Sjsing else 1105dab3f910Sjsing BIO_puts(STDout, "<No Alias>\n"); 1106e7718adaStb } else if (cfg.subject_hash == i) { 1107662ea354Sinoguchi BIO_printf(STDout, "%08lx\n", 1108662ea354Sinoguchi X509_subject_name_hash(x)); 1109dab3f910Sjsing } 1110dab3f910Sjsing #ifndef OPENSSL_NO_MD5 1111e7718adaStb else if (cfg.subject_hash_old == i) { 1112662ea354Sinoguchi BIO_printf(STDout, "%08lx\n", 1113662ea354Sinoguchi X509_subject_name_hash_old(x)); 1114dab3f910Sjsing } 1115dab3f910Sjsing #endif 1116e7718adaStb else if (cfg.issuer_hash == i) { 1117662ea354Sinoguchi BIO_printf(STDout, "%08lx\n", 1118662ea354Sinoguchi X509_issuer_name_hash(x)); 1119dab3f910Sjsing } 1120dab3f910Sjsing #ifndef OPENSSL_NO_MD5 1121e7718adaStb else if (cfg.issuer_hash_old == i) { 1122662ea354Sinoguchi BIO_printf(STDout, "%08lx\n", 1123662ea354Sinoguchi X509_issuer_name_hash_old(x)); 1124dab3f910Sjsing } 1125dab3f910Sjsing #endif 1126e7718adaStb else if (cfg.pprint == i) { 11275bbf7eacStb const X509_PURPOSE *ptmp; 1128dab3f910Sjsing int j; 11295c31e3d8Stb 1130dab3f910Sjsing BIO_printf(STDout, "Certificate purposes:\n"); 1131dab3f910Sjsing for (j = 0; j < X509_PURPOSE_get_count(); j++) { 1132dab3f910Sjsing ptmp = X509_PURPOSE_get0(j); 1133dab3f910Sjsing purpose_print(STDout, x, ptmp); 1134dab3f910Sjsing } 1135e7718adaStb } else if (cfg.modulus == i) { 1136de555dcbStb EVP_PKEY *pubkey; 1137dab3f910Sjsing 1138de555dcbStb if ((pubkey = X509_get0_pubkey(x)) == NULL) { 1139662ea354Sinoguchi BIO_printf(bio_err, 1140662ea354Sinoguchi "Modulus=unavailable\n"); 1141dab3f910Sjsing ERR_print_errors(bio_err); 1142dab3f910Sjsing goto end; 1143dab3f910Sjsing } 1144dab3f910Sjsing BIO_printf(STDout, "Modulus="); 1145de555dcbStb if (EVP_PKEY_id(pubkey) == EVP_PKEY_RSA) { 1146de555dcbStb RSA *rsa = EVP_PKEY_get0_RSA(pubkey); 11476bd9a17aStb const BIGNUM *n = NULL; 11486bd9a17aStb 11496bd9a17aStb RSA_get0_key(rsa, &n, NULL, NULL); 11506bd9a17aStb BN_print(STDout, n); 1151de555dcbStb } else if (EVP_PKEY_id(pubkey) == EVP_PKEY_DSA) { 1152de555dcbStb DSA *dsa = EVP_PKEY_get0_DSA(pubkey); 11534692ea2bStb const BIGNUM *dsa_pub_key = NULL; 11546bd9a17aStb 11554692ea2bStb DSA_get0_key(dsa, &dsa_pub_key, NULL); 11566bd9a17aStb 11574692ea2bStb BN_print(STDout, dsa_pub_key); 11586bd9a17aStb } else 1159662ea354Sinoguchi BIO_printf(STDout, 1160662ea354Sinoguchi "Wrong Algorithm type"); 1161dab3f910Sjsing BIO_printf(STDout, "\n"); 1162e7718adaStb } else if (cfg.pubkey == i) { 1163de555dcbStb EVP_PKEY *pubkey; 1164dab3f910Sjsing 1165de555dcbStb if ((pubkey = X509_get0_pubkey(x)) == NULL) { 1166662ea354Sinoguchi BIO_printf(bio_err, 1167662ea354Sinoguchi "Error getting public key\n"); 1168dab3f910Sjsing ERR_print_errors(bio_err); 1169dab3f910Sjsing goto end; 1170dab3f910Sjsing } 1171de555dcbStb PEM_write_bio_PUBKEY(STDout, pubkey); 1172e7718adaStb } else if (cfg.text == i) { 1173e7718adaStb if(!X509_print_ex(STDout, x, cfg.nmflag, 1174e7718adaStb cfg.certflag)) 11759d967dc8Sinoguchi goto end; 1176e7718adaStb } else if (cfg.startdate == i) { 1177bbdaa95aSbeck ASN1_TIME *nB = X509_get_notBefore(x); 11785c31e3d8Stb 1179dab3f910Sjsing BIO_puts(STDout, "notBefore="); 118010666173Stb if (!ASN1_TIME_to_tm(nB, NULL)) 1181662ea354Sinoguchi BIO_puts(STDout, 1182662ea354Sinoguchi "INVALID RFC5280 TIME"); 1183bbdaa95aSbeck else 1184bbdaa95aSbeck ASN1_TIME_print(STDout, nB); 1185dab3f910Sjsing BIO_puts(STDout, "\n"); 1186e7718adaStb } else if (cfg.enddate == i) { 1187bbdaa95aSbeck ASN1_TIME *nA = X509_get_notAfter(x); 11885c31e3d8Stb 1189dab3f910Sjsing BIO_puts(STDout, "notAfter="); 119010666173Stb if (!ASN1_TIME_to_tm(nA, NULL)) 1191662ea354Sinoguchi BIO_puts(STDout, 1192662ea354Sinoguchi "INVALID RFC5280 TIME"); 1193bbdaa95aSbeck else 1194bbdaa95aSbeck ASN1_TIME_print(STDout, nA); 1195dab3f910Sjsing BIO_puts(STDout, "\n"); 1196e7718adaStb } else if (cfg.fingerprint == i) { 1197dab3f910Sjsing int j; 1198dab3f910Sjsing unsigned int n; 1199dab3f910Sjsing unsigned char md[EVP_MAX_MD_SIZE]; 1200e7718adaStb const EVP_MD *fdig = cfg.digest; 1201dab3f910Sjsing 12021274c900Sinoguchi if (fdig == NULL) 1203020b59f8Sjsg fdig = EVP_sha256(); 1204dab3f910Sjsing 1205dab3f910Sjsing if (!X509_digest(x, fdig, md, &n)) { 1206dab3f910Sjsing BIO_printf(bio_err, "out of memory\n"); 1207dab3f910Sjsing goto end; 1208dab3f910Sjsing } 1209dab3f910Sjsing BIO_printf(STDout, "%s Fingerprint=", 1210dab3f910Sjsing OBJ_nid2sn(EVP_MD_type(fdig))); 1211dab3f910Sjsing for (j = 0; j < (int) n; j++) { 1212dab3f910Sjsing BIO_printf(STDout, "%02X%c", md[j], 1213dab3f910Sjsing (j + 1 == (int)n) ? '\n' : ':'); 1214dab3f910Sjsing } 12155c31e3d8Stb } else if (cfg.sign_flag == i && cfg.x509req == 0) { 1216dab3f910Sjsing if (Upkey == NULL) { 12175c31e3d8Stb Upkey = load_key(bio_err, cfg.keyfile, 1218e7718adaStb cfg.keyformat, 0, passin, 1219662ea354Sinoguchi "Private key"); 1220dab3f910Sjsing if (Upkey == NULL) 1221dab3f910Sjsing goto end; 1222dab3f910Sjsing } 1223e7718adaStb if (!sign(x, Upkey, cfg.days, 1224e7718adaStb cfg.clrext, cfg.digest, 1225d4c9bc7eSjob extconf, cfg.extsect, iname, 1226d4c9bc7eSjob cfg.force_pubkey)) 1227dab3f910Sjsing goto end; 1228e7718adaStb } else if (cfg.CA_flag == i) { 1229e7718adaStb if (cfg.CAkeyfile != NULL) { 12305c31e3d8Stb CApkey = load_key(bio_err, cfg.CAkeyfile, 1231e7718adaStb cfg.CAkeyformat, 0, passin, 1232662ea354Sinoguchi "CA Private Key"); 1233dab3f910Sjsing if (CApkey == NULL) 1234dab3f910Sjsing goto end; 1235dab3f910Sjsing } 12365c31e3d8Stb if (!x509_certify(ctx, cfg.CAfile, cfg.digest, 12375c31e3d8Stb x, xca, CApkey, cfg.sigopts, cfg.CAserial, 12385c31e3d8Stb cfg.CA_createserial, cfg.days, cfg.clrext, 12390293fcf8Sjob extconf, cfg.extsect, cfg.sno, iname)) 1240dab3f910Sjsing goto end; 1241e7718adaStb } else if (cfg.x509req == i) { 1242dab3f910Sjsing EVP_PKEY *pk; 1243dab3f910Sjsing 1244662ea354Sinoguchi BIO_printf(bio_err, 1245662ea354Sinoguchi "Getting request Private Key\n"); 1246e7718adaStb if (cfg.keyfile == NULL) { 1247662ea354Sinoguchi BIO_printf(bio_err, 1248662ea354Sinoguchi "no request key file specified\n"); 1249dab3f910Sjsing goto end; 1250dab3f910Sjsing } else { 12515c31e3d8Stb pk = load_key(bio_err, cfg.keyfile, 1252e7718adaStb cfg.keyformat, 0, passin, 1253662ea354Sinoguchi "request key"); 1254dab3f910Sjsing if (pk == NULL) 1255dab3f910Sjsing goto end; 1256dab3f910Sjsing } 1257dab3f910Sjsing 1258662ea354Sinoguchi BIO_printf(bio_err, 1259662ea354Sinoguchi "Generating certificate request\n"); 1260dab3f910Sjsing 1261e7718adaStb rq = X509_to_X509_REQ(x, pk, cfg.digest); 1262dab3f910Sjsing EVP_PKEY_free(pk); 1263dab3f910Sjsing if (rq == NULL) { 1264dab3f910Sjsing ERR_print_errors(bio_err); 1265dab3f910Sjsing goto end; 1266dab3f910Sjsing } 1267e7718adaStb if (!cfg.noout) { 12689d967dc8Sinoguchi if (!X509_REQ_print(out, rq)) 12699d967dc8Sinoguchi goto end; 12709d967dc8Sinoguchi if (!PEM_write_bio_X509_REQ(out, rq)) 12719d967dc8Sinoguchi goto end; 1272dab3f910Sjsing } 1273e7718adaStb cfg.noout = 1; 1274e7718adaStb } else if (cfg.ocspid == i) { 12759d967dc8Sinoguchi if (!X509_ocspid_print(out, x)) 12769d967dc8Sinoguchi goto end; 1277dab3f910Sjsing } 1278dab3f910Sjsing } 1279dab3f910Sjsing } 1280e7718adaStb if (cfg.checkend) { 1281e7718adaStb time_t tcheck = time(NULL) + cfg.checkoffset; 1282bbdaa95aSbeck int timecheck = X509_cmp_time(X509_get_notAfter(x), &tcheck); 1283bbdaa95aSbeck if (timecheck == 0) { 1284bbdaa95aSbeck BIO_printf(out, "Certificate expiry time is invalid\n"); 1285bbdaa95aSbeck ret = 1; 1286bbdaa95aSbeck } else if (timecheck < 0) { 1287dab3f910Sjsing BIO_printf(out, "Certificate will expire\n"); 1288dab3f910Sjsing ret = 1; 1289dab3f910Sjsing } else { 1290dab3f910Sjsing BIO_printf(out, "Certificate will not expire\n"); 1291dab3f910Sjsing ret = 0; 1292dab3f910Sjsing } 1293dab3f910Sjsing goto end; 1294dab3f910Sjsing } 1295e7718adaStb if (cfg.noout) { 1296dab3f910Sjsing ret = 0; 1297dab3f910Sjsing goto end; 1298dab3f910Sjsing } 1299e7718adaStb if (cfg.outformat == FORMAT_ASN1) 1300dab3f910Sjsing i = i2d_X509_bio(out, x); 1301e7718adaStb else if (cfg.outformat == FORMAT_PEM) { 1302e7718adaStb if (cfg.trustout) 1303dab3f910Sjsing i = PEM_write_bio_X509_AUX(out, x); 1304dab3f910Sjsing else 1305dab3f910Sjsing i = PEM_write_bio_X509(out, x); 1306dab3f910Sjsing } else { 1307662ea354Sinoguchi BIO_printf(bio_err, 1308662ea354Sinoguchi "bad output format specified for outfile\n"); 1309dab3f910Sjsing goto end; 1310dab3f910Sjsing } 1311dab3f910Sjsing if (!i) { 1312dab3f910Sjsing BIO_printf(bio_err, "unable to write certificate\n"); 1313dab3f910Sjsing ERR_print_errors(bio_err); 1314dab3f910Sjsing goto end; 1315dab3f910Sjsing } 1316dab3f910Sjsing ret = 0; 1317dab3f910Sjsing 1318dab3f910Sjsing end: 1319dab3f910Sjsing OBJ_cleanup(); 1320dab3f910Sjsing NCONF_free(extconf); 1321dab3f910Sjsing BIO_free_all(out); 1322dab3f910Sjsing BIO_free_all(STDout); 13230293fcf8Sjob X509_NAME_free(iname); 13240293fcf8Sjob X509_NAME_free(sname); 1325dab3f910Sjsing X509_STORE_free(ctx); 1326dab3f910Sjsing X509_REQ_free(req); 1327dab3f910Sjsing X509_free(x); 1328dab3f910Sjsing X509_free(xca); 13290293fcf8Sjob EVP_PKEY_free(Fpkey); 1330dab3f910Sjsing EVP_PKEY_free(Upkey); 1331dab3f910Sjsing EVP_PKEY_free(CApkey); 1332e7718adaStb sk_OPENSSL_STRING_free(cfg.sigopts); 1333dab3f910Sjsing X509_REQ_free(rq); 1334e7718adaStb ASN1_INTEGER_free(cfg.sno); 1335e7718adaStb sk_ASN1_OBJECT_pop_free(cfg.trust, ASN1_OBJECT_free); 1336e7718adaStb sk_ASN1_OBJECT_pop_free(cfg.reject, ASN1_OBJECT_free); 1337dab3f910Sjsing free(passin); 1338dab3f910Sjsing 1339dab3f910Sjsing return (ret); 1340dab3f910Sjsing } 1341dab3f910Sjsing 1342dab3f910Sjsing static ASN1_INTEGER * 1343dab3f910Sjsing x509_load_serial(char *CAfile, char *serialfile, int create) 1344dab3f910Sjsing { 1345dab3f910Sjsing char *buf = NULL, *p; 1346dab3f910Sjsing ASN1_INTEGER *bs = NULL; 1347dab3f910Sjsing BIGNUM *serial = NULL; 1348dab3f910Sjsing size_t len; 1349dab3f910Sjsing 1350dab3f910Sjsing len = ((serialfile == NULL) ? (strlen(CAfile) + strlen(POSTFIX) + 1) : 1351dab3f910Sjsing (strlen(serialfile))) + 1; 1352dab3f910Sjsing buf = malloc(len); 1353dab3f910Sjsing if (buf == NULL) { 1354dab3f910Sjsing BIO_printf(bio_err, "out of mem\n"); 1355dab3f910Sjsing goto end; 1356dab3f910Sjsing } 1357dab3f910Sjsing if (serialfile == NULL) { 1358dab3f910Sjsing strlcpy(buf, CAfile, len); 1359dab3f910Sjsing for (p = buf; *p; p++) 1360dab3f910Sjsing if (*p == '.') { 1361dab3f910Sjsing *p = '\0'; 1362dab3f910Sjsing break; 1363dab3f910Sjsing } 1364dab3f910Sjsing strlcat(buf, POSTFIX, len); 1365dab3f910Sjsing } else 1366dab3f910Sjsing strlcpy(buf, serialfile, len); 1367dab3f910Sjsing 1368dab3f910Sjsing serial = load_serial(buf, create, NULL); 1369dab3f910Sjsing if (serial == NULL) 1370dab3f910Sjsing goto end; 1371dab3f910Sjsing 1372dab3f910Sjsing if (!BN_add_word(serial, 1)) { 1373dab3f910Sjsing BIO_printf(bio_err, "add_word failure\n"); 1374dab3f910Sjsing goto end; 1375dab3f910Sjsing } 1376dab3f910Sjsing if (!save_serial(buf, NULL, serial, &bs)) 1377dab3f910Sjsing goto end; 1378dab3f910Sjsing 1379dab3f910Sjsing end: 1380dab3f910Sjsing free(buf); 1381dab3f910Sjsing BN_free(serial); 1382dab3f910Sjsing 1383dab3f910Sjsing return bs; 1384dab3f910Sjsing } 1385dab3f910Sjsing 1386dab3f910Sjsing static int 1387dab3f910Sjsing x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, X509 *x, 1388dab3f910Sjsing X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts, 1389dab3f910Sjsing char *serialfile, int create, int days, int clrext, CONF *conf, 13900293fcf8Sjob char *section, ASN1_INTEGER *sno, X509_NAME *issuer) 1391dab3f910Sjsing { 1392dab3f910Sjsing int ret = 0; 1393dab3f910Sjsing ASN1_INTEGER *bs = NULL; 139424e9ed32Stb X509_STORE_CTX *xsc = NULL; 1395dab3f910Sjsing EVP_PKEY *upkey; 1396dab3f910Sjsing 139719ac38f1Stb upkey = X509_get0_pubkey(xca); 13989d967dc8Sinoguchi if (upkey == NULL) 13999d967dc8Sinoguchi goto end; 1400dab3f910Sjsing EVP_PKEY_copy_parameters(upkey, pkey); 1401dab3f910Sjsing 140224e9ed32Stb if ((xsc = X509_STORE_CTX_new()) == NULL) 140324e9ed32Stb goto end; 140424e9ed32Stb if (!X509_STORE_CTX_init(xsc, ctx, x, NULL)) { 1405dab3f910Sjsing BIO_printf(bio_err, "Error initialising X509 store\n"); 1406dab3f910Sjsing goto end; 1407dab3f910Sjsing } 14081274c900Sinoguchi if (sno != NULL) 1409dab3f910Sjsing bs = sno; 14101274c900Sinoguchi else if ((bs = x509_load_serial(CAfile, serialfile, create)) == NULL) 1411dab3f910Sjsing goto end; 1412dab3f910Sjsing 1413dab3f910Sjsing /* if (!X509_STORE_add_cert(ctx,x)) goto end;*/ 1414dab3f910Sjsing 1415dab3f910Sjsing /* 1416dab3f910Sjsing * NOTE: this certificate can/should be self signed, unless it was a 1417dab3f910Sjsing * certificate request in which case it is not. 1418dab3f910Sjsing */ 141924e9ed32Stb X509_STORE_CTX_set_cert(xsc, x); 142024e9ed32Stb X509_STORE_CTX_set_flags(xsc, X509_V_FLAG_CHECK_SS_SIGNATURE); 1421e7718adaStb if (!cfg.reqfile && X509_verify_cert(xsc) <= 0) 1422dab3f910Sjsing goto end; 1423dab3f910Sjsing 1424dab3f910Sjsing if (!X509_check_private_key(xca, pkey)) { 1425662ea354Sinoguchi BIO_printf(bio_err, 1426662ea354Sinoguchi "CA certificate and CA private key do not match\n"); 1427dab3f910Sjsing goto end; 1428dab3f910Sjsing } 14290293fcf8Sjob 14300293fcf8Sjob if (issuer == NULL) 14310293fcf8Sjob issuer = X509_get_subject_name(xca); 14320293fcf8Sjob if (issuer == NULL) 1433dab3f910Sjsing goto end; 14340293fcf8Sjob if (!X509_set_issuer_name(x, issuer)) 14350293fcf8Sjob goto end; 14360293fcf8Sjob 1437dab3f910Sjsing if (!X509_set_serialNumber(x, bs)) 1438dab3f910Sjsing goto end; 1439dab3f910Sjsing 1440dab3f910Sjsing if (X509_gmtime_adj(X509_get_notBefore(x), 0L) == NULL) 1441dab3f910Sjsing goto end; 1442dab3f910Sjsing 1443dab3f910Sjsing /* hardwired expired */ 1444dab3f910Sjsing if (X509_time_adj_ex(X509_get_notAfter(x), days, 0, NULL) == NULL) 1445dab3f910Sjsing goto end; 1446dab3f910Sjsing 1447dab3f910Sjsing if (clrext) { 14489d967dc8Sinoguchi while (X509_get_ext_count(x) > 0) { 14499d967dc8Sinoguchi if (X509_delete_ext(x, 0) == NULL) 14509d967dc8Sinoguchi goto end; 14519d967dc8Sinoguchi } 1452dab3f910Sjsing } 14531274c900Sinoguchi if (conf != NULL) { 1454dab3f910Sjsing X509V3_CTX ctx2; 14559d967dc8Sinoguchi if (!X509_set_version(x, 2)) /* version 3 certificate */ 14569d967dc8Sinoguchi goto end; 1457dab3f910Sjsing X509V3_set_ctx(&ctx2, xca, x, NULL, NULL, 0); 1458dab3f910Sjsing X509V3_set_nconf(&ctx2, conf); 1459dab3f910Sjsing if (!X509V3_EXT_add_nconf(conf, &ctx2, section, x)) 1460dab3f910Sjsing goto end; 1461dab3f910Sjsing } 1462dab3f910Sjsing if (!do_X509_sign(bio_err, x, pkey, digest, sigopts)) 1463dab3f910Sjsing goto end; 14649d967dc8Sinoguchi 1465dab3f910Sjsing ret = 1; 1466dab3f910Sjsing end: 146724e9ed32Stb X509_STORE_CTX_free(xsc); 1468dab3f910Sjsing if (!ret) 1469dab3f910Sjsing ERR_print_errors(bio_err); 14701274c900Sinoguchi if (sno == NULL) 1471dab3f910Sjsing ASN1_INTEGER_free(bs); 1472dab3f910Sjsing return ret; 1473dab3f910Sjsing } 1474dab3f910Sjsing 1475dab3f910Sjsing static int 1476dab3f910Sjsing callb(int ok, X509_STORE_CTX *ctx) 1477dab3f910Sjsing { 1478dab3f910Sjsing int err; 1479dab3f910Sjsing X509 *err_cert; 1480dab3f910Sjsing 1481dab3f910Sjsing /* 1482dab3f910Sjsing * it is ok to use a self signed certificate This case will catch 1483dab3f910Sjsing * both the initial ok == 0 and the final ok == 1 calls to this 1484dab3f910Sjsing * function 1485dab3f910Sjsing */ 1486dab3f910Sjsing err = X509_STORE_CTX_get_error(ctx); 1487dab3f910Sjsing if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) 1488dab3f910Sjsing return 1; 1489dab3f910Sjsing 1490dab3f910Sjsing /* 1491dab3f910Sjsing * BAD we should have gotten an error. Normally if everything worked 1492dab3f910Sjsing * X509_STORE_CTX_get_error(ctx) will still be set to 1493dab3f910Sjsing * DEPTH_ZERO_SELF_.... 1494dab3f910Sjsing */ 1495dab3f910Sjsing if (ok) { 1496662ea354Sinoguchi BIO_printf(bio_err, 1497662ea354Sinoguchi "error with certificate to be certified - should be self signed\n"); 1498dab3f910Sjsing return 0; 1499dab3f910Sjsing } else { 1500dab3f910Sjsing err_cert = X509_STORE_CTX_get_current_cert(ctx); 1501dab3f910Sjsing print_name(bio_err, NULL, X509_get_subject_name(err_cert), 0); 1502662ea354Sinoguchi BIO_printf(bio_err, 1503662ea354Sinoguchi "error with certificate - error %d at depth %d\n%s\n", 1504dab3f910Sjsing err, X509_STORE_CTX_get_error_depth(ctx), 1505dab3f910Sjsing X509_verify_cert_error_string(err)); 1506dab3f910Sjsing return 1; 1507dab3f910Sjsing } 1508dab3f910Sjsing } 1509dab3f910Sjsing 1510e8e63f68Stb static int 1511e8e63f68Stb key_identifier_hash(EVP_PKEY *pkey, unsigned char *md, unsigned int *md_len) 1512e8e63f68Stb { 1513e8e63f68Stb X509_PUBKEY *x509_pubkey = NULL; 1514e8e63f68Stb const unsigned char *der; 1515e8e63f68Stb int der_len; 1516e8e63f68Stb int ret = 0; 1517e8e63f68Stb 1518e8e63f68Stb if (*md_len < SHA_DIGEST_LENGTH) 1519e8e63f68Stb goto err; 1520e8e63f68Stb 1521e8e63f68Stb if (!X509_PUBKEY_set(&x509_pubkey, pkey)) 1522e8e63f68Stb goto err; 1523e8e63f68Stb if (!X509_PUBKEY_get0_param(NULL, &der, &der_len, NULL, x509_pubkey)) 1524e8e63f68Stb goto err; 1525e8e63f68Stb if (!EVP_Digest(der, der_len, md, md_len, EVP_sha1(), NULL)) 1526e8e63f68Stb goto err; 1527e8e63f68Stb 1528e8e63f68Stb ret = 1; 1529e8e63f68Stb 1530e8e63f68Stb err: 1531e8e63f68Stb X509_PUBKEY_free(x509_pubkey); 1532e8e63f68Stb 1533e8e63f68Stb return ret; 1534e8e63f68Stb } 1535e8e63f68Stb 1536e8e63f68Stb static ASN1_OCTET_STRING * 1537e8e63f68Stb compute_key_identifier(EVP_PKEY *pkey) 1538e8e63f68Stb { 1539e8e63f68Stb ASN1_OCTET_STRING *ki = NULL; 1540e8e63f68Stb unsigned char md[EVP_MAX_MD_SIZE]; 1541e8e63f68Stb unsigned int md_len = EVP_MAX_MD_SIZE; 1542e8e63f68Stb 1543e8e63f68Stb if (!key_identifier_hash(pkey, md, &md_len)) 1544e8e63f68Stb goto err; 1545e8e63f68Stb 1546e8e63f68Stb if ((ki = ASN1_OCTET_STRING_new()) == NULL) 1547e8e63f68Stb goto err; 1548e8e63f68Stb if (!ASN1_STRING_set(ki, md, md_len)) 1549e8e63f68Stb goto err; 1550e8e63f68Stb 1551e8e63f68Stb return ki; 1552e8e63f68Stb 1553e8e63f68Stb err: 1554e8e63f68Stb ASN1_OCTET_STRING_free(ki); 1555e8e63f68Stb 1556e8e63f68Stb return NULL; 1557e8e63f68Stb } 1558e8e63f68Stb 1559e8e63f68Stb static ASN1_OCTET_STRING * 1560e8e63f68Stb compute_subject_key_identifier(EVP_PKEY *subject_key) 1561e8e63f68Stb { 1562e8e63f68Stb return compute_key_identifier(subject_key); 1563e8e63f68Stb } 1564e8e63f68Stb 1565e8e63f68Stb static AUTHORITY_KEYID * 1566e8e63f68Stb compute_authority_key_identifier(EVP_PKEY *issuer_key) 1567e8e63f68Stb { 1568e8e63f68Stb AUTHORITY_KEYID *aki = NULL; 1569e8e63f68Stb 1570e8e63f68Stb if ((aki = AUTHORITY_KEYID_new()) == NULL) 1571e8e63f68Stb goto err; 1572e8e63f68Stb if ((aki->keyid = compute_key_identifier(issuer_key)) == NULL) 1573e8e63f68Stb goto err; 1574e8e63f68Stb 1575e8e63f68Stb return aki; 1576e8e63f68Stb 1577e8e63f68Stb err: 1578e8e63f68Stb AUTHORITY_KEYID_free(aki); 1579e8e63f68Stb 1580e8e63f68Stb return NULL; 1581e8e63f68Stb } 1582e8e63f68Stb 1583e8e63f68Stb static int 1584e8e63f68Stb set_key_identifiers(X509 *cert, EVP_PKEY *issuer_key) 1585e8e63f68Stb { 1586e8e63f68Stb EVP_PKEY *subject_key; 1587e8e63f68Stb ASN1_OCTET_STRING *ski = NULL; 1588e8e63f68Stb AUTHORITY_KEYID *aki = NULL; 1589e8e63f68Stb int ret = 0; 1590e8e63f68Stb 1591e8e63f68Stb if ((subject_key = X509_get0_pubkey(cert)) == NULL) 1592e8e63f68Stb goto err; 1593e8e63f68Stb 1594e8e63f68Stb if ((ski = compute_subject_key_identifier(subject_key)) == NULL) 1595e8e63f68Stb goto err; 1596e8e63f68Stb if (!X509_add1_ext_i2d(cert, NID_subject_key_identifier, ski, 0, 1597e8e63f68Stb X509V3_ADD_REPLACE)) 1598e8e63f68Stb goto err; 1599e8e63f68Stb 1600e8e63f68Stb /* 1601e8e63f68Stb * Historical OpenSSL behavior: don't set AKI if we're self-signing. 1602e8e63f68Stb * RFC 5280 says we MAY omit it, so this is ok. 1603e8e63f68Stb */ 1604e8e63f68Stb if (EVP_PKEY_cmp(subject_key, issuer_key) == 1) 1605e8e63f68Stb goto done; 1606e8e63f68Stb 1607e8e63f68Stb if ((aki = compute_authority_key_identifier(issuer_key)) == NULL) 1608e8e63f68Stb goto err; 1609e8e63f68Stb if (!X509_add1_ext_i2d(cert, NID_authority_key_identifier, aki, 0, 1610e8e63f68Stb X509V3_ADD_REPLACE)) 1611e8e63f68Stb goto err; 1612e8e63f68Stb 1613e8e63f68Stb done: 1614e8e63f68Stb ret = 1; 1615e8e63f68Stb 1616e8e63f68Stb err: 1617e8e63f68Stb ASN1_OCTET_STRING_free(ski); 1618e8e63f68Stb AUTHORITY_KEYID_free(aki); 1619e8e63f68Stb 1620e8e63f68Stb return ret; 1621e8e63f68Stb } 1622e8e63f68Stb 1623dab3f910Sjsing static int 1624dab3f910Sjsing sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, const EVP_MD *digest, 1625d4c9bc7eSjob CONF *conf, char *section, X509_NAME *issuer, char *force_pubkey) 1626dab3f910Sjsing { 1627dab3f910Sjsing EVP_PKEY *pktmp; 1628dab3f910Sjsing 162919ac38f1Stb pktmp = X509_get0_pubkey(x); 16309d967dc8Sinoguchi if (pktmp == NULL) 16319d967dc8Sinoguchi goto err; 1632dab3f910Sjsing EVP_PKEY_copy_parameters(pktmp, pkey); 1633dab3f910Sjsing EVP_PKEY_save_parameters(pktmp, 1); 1634dab3f910Sjsing 16350293fcf8Sjob if (issuer == NULL) 16360293fcf8Sjob issuer = X509_get_subject_name(x); 16370293fcf8Sjob if (issuer == NULL) 16380293fcf8Sjob goto err; 16390293fcf8Sjob if (!X509_set_issuer_name(x, issuer)) 1640dab3f910Sjsing goto err; 1641dab3f910Sjsing if (X509_gmtime_adj(X509_get_notBefore(x), 0) == NULL) 1642dab3f910Sjsing goto err; 1643dab3f910Sjsing 1644e8e63f68Stb if (X509_gmtime_adj(X509_get_notAfter(x), 60L * 60 * 24 * days) == NULL) 1645dab3f910Sjsing goto err; 1646dab3f910Sjsing 1647d4c9bc7eSjob if (force_pubkey == NULL) { 1648dab3f910Sjsing if (!X509_set_pubkey(x, pkey)) 1649dab3f910Sjsing goto err; 1650d4c9bc7eSjob } 1651dab3f910Sjsing if (clrext) { 16529d967dc8Sinoguchi while (X509_get_ext_count(x) > 0) { 16539d967dc8Sinoguchi if (X509_delete_ext(x, 0) == NULL) 16549d967dc8Sinoguchi goto err; 16559d967dc8Sinoguchi } 1656dab3f910Sjsing } 16571274c900Sinoguchi if (conf != NULL) { 1658dab3f910Sjsing X509V3_CTX ctx; 1659e8e63f68Stb 16609d967dc8Sinoguchi if (!X509_set_version(x, 2)) /* version 3 certificate */ 16619d967dc8Sinoguchi goto err; 1662dab3f910Sjsing X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0); 1663dab3f910Sjsing X509V3_set_nconf(&ctx, conf); 1664dab3f910Sjsing if (!X509V3_EXT_add_nconf(conf, &ctx, section, x)) 1665dab3f910Sjsing goto err; 1666e8e63f68Stb if (force_pubkey != NULL) { 1667e8e63f68Stb /* 1668e8e63f68Stb * Set or fix up SKI and AKI. 1669e8e63f68Stb * 1670e8e63f68Stb * XXX - Doing this in a fully OpenSSL 3 compatible way 1671e8e63f68Stb * is extremely nasty: they hang an issuer_pubkey off 1672e8e63f68Stb * the X509V3_CTX and adjusted v2i_AUTHORITY_KEYID(). 1673e8e63f68Stb * Punt on this and make things work in the specific 1674e8e63f68Stb * situation we're interested in. Like OpenSSL, we only 1675e8e63f68Stb * support the keyid form of the AKI, which is what 1676e8e63f68Stb * RFC 5280 recommends, but unlike OpenSSL we replace 1677e8e63f68Stb * existing SKI and AKI rather than honoring the most 1678e8e63f68Stb * likely outdated ones already present in the cert. 1679e8e63f68Stb */ 1680e8e63f68Stb if (!set_key_identifiers(x, pkey)) 1681e8e63f68Stb goto err; 1682e8e63f68Stb } 1683dab3f910Sjsing } 1684dab3f910Sjsing if (!X509_sign(x, pkey, digest)) 1685dab3f910Sjsing goto err; 1686662ea354Sinoguchi 1687dab3f910Sjsing return 1; 1688dab3f910Sjsing 1689dab3f910Sjsing err: 1690dab3f910Sjsing ERR_print_errors(bio_err); 1691dab3f910Sjsing return 0; 1692dab3f910Sjsing } 1693dab3f910Sjsing 1694dab3f910Sjsing static int 16955bbf7eacStb purpose_print(BIO *bio, X509 *cert, const X509_PURPOSE *pt) 1696dab3f910Sjsing { 1697dab3f910Sjsing int id, i, idret; 16985bbf7eacStb const char *pname; 1699dab3f910Sjsing 1700dab3f910Sjsing id = X509_PURPOSE_get_id(pt); 1701dab3f910Sjsing pname = X509_PURPOSE_get0_name(pt); 1702dab3f910Sjsing for (i = 0; i < 2; i++) { 1703dab3f910Sjsing idret = X509_check_purpose(cert, id, i); 1704dab3f910Sjsing BIO_printf(bio, "%s%s : ", pname, i ? " CA" : ""); 1705dab3f910Sjsing if (idret == 1) 1706dab3f910Sjsing BIO_printf(bio, "Yes\n"); 1707dab3f910Sjsing else if (idret == 0) 1708dab3f910Sjsing BIO_printf(bio, "No\n"); 1709dab3f910Sjsing else 1710dab3f910Sjsing BIO_printf(bio, "Yes (WARNING code=%d)\n", idret); 1711dab3f910Sjsing } 1712dab3f910Sjsing return 1; 1713dab3f910Sjsing } 1714