sl@0: /* apps/ca.c */ sl@0: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) sl@0: * All rights reserved. sl@0: * sl@0: * This package is an SSL implementation written sl@0: * by Eric Young (eay@cryptsoft.com). sl@0: * The implementation was written so as to conform with Netscapes SSL. sl@0: * sl@0: * This library is free for commercial and non-commercial use as long as sl@0: * the following conditions are aheared to. The following conditions sl@0: * apply to all code found in this distribution, be it the RC4, RSA, sl@0: * lhash, DES, etc., code; not just the SSL code. The SSL documentation sl@0: * included with this distribution is covered by the same copyright terms sl@0: * except that the holder is Tim Hudson (tjh@cryptsoft.com). sl@0: * sl@0: * Copyright remains Eric Young's, and as such any Copyright notices in sl@0: * the code are not to be removed. sl@0: * If this package is used in a product, Eric Young should be given attribution sl@0: * as the author of the parts of the library used. sl@0: * This can be in the form of a textual message at program startup or sl@0: * in documentation (online or textual) provided with the package. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * 1. Redistributions of source code must retain the copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in the sl@0: * documentation and/or other materials provided with the distribution. sl@0: * 3. All advertising materials mentioning features or use of this software sl@0: * must display the following acknowledgement: sl@0: * "This product includes cryptographic software written by sl@0: * Eric Young (eay@cryptsoft.com)" sl@0: * The word 'cryptographic' can be left out if the rouines from the library sl@0: * being used are not cryptographic related :-). sl@0: * 4. If you include any Windows specific code (or a derivative thereof) from sl@0: * the apps directory (application code) you must include an acknowledgement: sl@0: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND sl@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE sl@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE sl@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL sl@0: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS sl@0: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT sl@0: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY sl@0: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF sl@0: * SUCH DAMAGE. sl@0: * sl@0: * The licence and distribution terms for any publically available version or sl@0: * derivative of this code cannot be changed. i.e. this code cannot simply be sl@0: * copied and put under another distribution licence sl@0: * [including the GNU Public Licence.] sl@0: */ sl@0: sl@0: /* The PPKI stuff has been donated by Jeff Barber */ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #ifndef W_OK sl@0: # ifdef OPENSSL_SYS_VMS sl@0: # if defined(__DECC) sl@0: # include sl@0: # else sl@0: # include sl@0: # endif sl@0: # elif !defined(OPENSSL_SYS_VXWORKS) && !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_NETWARE) sl@0: # include sl@0: # endif sl@0: #endif sl@0: sl@0: #include "apps.h" sl@0: sl@0: #ifndef W_OK sl@0: # define F_OK 0 sl@0: # define X_OK 1 sl@0: # define W_OK 2 sl@0: # define R_OK 4 sl@0: #endif sl@0: sl@0: #undef PROG sl@0: #define PROG ca_main sl@0: sl@0: #define BASE_SECTION "ca" sl@0: #define CONFIG_FILE "openssl.cnf" sl@0: sl@0: #define ENV_DEFAULT_CA "default_ca" sl@0: sl@0: #define STRING_MASK "string_mask" sl@0: #define UTF8_IN "utf8" sl@0: sl@0: #define ENV_DIR "dir" sl@0: #define ENV_CERTS "certs" sl@0: #define ENV_CRL_DIR "crl_dir" sl@0: #define ENV_CA_DB "CA_DB" sl@0: #define ENV_NEW_CERTS_DIR "new_certs_dir" sl@0: #define ENV_CERTIFICATE "certificate" sl@0: #define ENV_SERIAL "serial" sl@0: #define ENV_CRLNUMBER "crlnumber" sl@0: #define ENV_CRL "crl" sl@0: #define ENV_PRIVATE_KEY "private_key" sl@0: #define ENV_RANDFILE "RANDFILE" sl@0: #define ENV_DEFAULT_DAYS "default_days" sl@0: #define ENV_DEFAULT_STARTDATE "default_startdate" sl@0: #define ENV_DEFAULT_ENDDATE "default_enddate" sl@0: #define ENV_DEFAULT_CRL_DAYS "default_crl_days" sl@0: #define ENV_DEFAULT_CRL_HOURS "default_crl_hours" sl@0: #define ENV_DEFAULT_MD "default_md" sl@0: #define ENV_DEFAULT_EMAIL_DN "email_in_dn" sl@0: #define ENV_PRESERVE "preserve" sl@0: #define ENV_POLICY "policy" sl@0: #define ENV_EXTENSIONS "x509_extensions" sl@0: #define ENV_CRLEXT "crl_extensions" sl@0: #define ENV_MSIE_HACK "msie_hack" sl@0: #define ENV_NAMEOPT "name_opt" sl@0: #define ENV_CERTOPT "cert_opt" sl@0: #define ENV_EXTCOPY "copy_extensions" sl@0: #define ENV_UNIQUE_SUBJECT "unique_subject" sl@0: sl@0: #define ENV_DATABASE "database" sl@0: sl@0: /* Additional revocation information types */ sl@0: sl@0: #define REV_NONE 0 /* No addditional information */ sl@0: #define REV_CRL_REASON 1 /* Value is CRL reason code */ sl@0: #define REV_HOLD 2 /* Value is hold instruction */ sl@0: #define REV_KEY_COMPROMISE 3 /* Value is cert key compromise time */ sl@0: #define REV_CA_COMPROMISE 4 /* Value is CA key compromise time */ sl@0: sl@0: static const char *ca_usage[]={ sl@0: "usage: ca args\n", sl@0: "\n", sl@0: " -verbose - Talk alot while doing things\n", sl@0: " -config file - A config file\n", sl@0: " -name arg - The particular CA definition to use\n", sl@0: " -gencrl - Generate a new CRL\n", sl@0: " -crldays days - Days is when the next CRL is due\n", sl@0: " -crlhours hours - Hours is when the next CRL is due\n", sl@0: " -startdate YYMMDDHHMMSSZ - certificate validity notBefore\n", sl@0: " -enddate YYMMDDHHMMSSZ - certificate validity notAfter (overrides -days)\n", sl@0: " -days arg - number of days to certify the certificate for\n", sl@0: " -md arg - md to use, one of md2, md5, sha or sha1\n", sl@0: " -policy arg - The CA 'policy' to support\n", sl@0: " -keyfile arg - private key file\n", sl@0: " -keyform arg - private key file format (PEM or ENGINE)\n", sl@0: " -key arg - key to decode the private key if it is encrypted\n", sl@0: " -cert file - The CA certificate\n", sl@0: " -selfsign - sign a certificate with the key associated with it\n", sl@0: " -in file - The input PEM encoded certificate request(s)\n", sl@0: " -out file - Where to put the output file(s)\n", sl@0: " -outdir dir - Where to put output certificates\n", sl@0: " -infiles .... - The last argument, requests to process\n", sl@0: " -spkac file - File contains DN and signed public key and challenge\n", sl@0: " -ss_cert file - File contains a self signed cert to sign\n", sl@0: " -preserveDN - Don't re-order the DN\n", sl@0: " -noemailDN - Don't add the EMAIL field into certificate' subject\n", sl@0: " -batch - Don't ask questions\n", sl@0: " -msie_hack - msie modifications to handle all those universal strings\n", sl@0: " -revoke file - Revoke a certificate (given in file)\n", sl@0: " -subj arg - Use arg instead of request's subject\n", sl@0: " -utf8 - input characters are UTF8 (default ASCII)\n", sl@0: " -multivalue-rdn - enable support for multivalued RDNs\n", sl@0: " -extensions .. - Extension section (override value in config file)\n", sl@0: " -extfile file - Configuration file with X509v3 extentions to add\n", sl@0: " -crlexts .. - CRL extension section (override value in config file)\n", sl@0: #ifndef OPENSSL_NO_ENGINE sl@0: " -engine e - use engine e, possibly a hardware device.\n", sl@0: #endif sl@0: " -status serial - Shows certificate status given the serial number\n", sl@0: " -updatedb - Updates db for expired certificates\n", sl@0: NULL sl@0: }; sl@0: sl@0: #ifdef EFENCE sl@0: extern int EF_PROTECT_FREE; sl@0: extern int EF_PROTECT_BELOW; sl@0: extern int EF_ALIGNMENT; sl@0: #endif sl@0: sl@0: static void lookup_fail(const char *name, const char *tag); sl@0: static int certify(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509, sl@0: const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,CA_DB *db, sl@0: BIGNUM *serial, char *subj,unsigned long chtype, int multirdn, int email_dn, char *startdate, sl@0: char *enddate, long days, int batch, char *ext_sect, CONF *conf, sl@0: int verbose, unsigned long certopt, unsigned long nameopt, sl@0: int default_op, int ext_copy, int selfsign); sl@0: static int certify_cert(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509, sl@0: const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy, sl@0: CA_DB *db, BIGNUM *serial, char *subj,unsigned long chtype, int multirdn, int email_dn, sl@0: char *startdate, char *enddate, long days, int batch, sl@0: char *ext_sect, CONF *conf,int verbose, unsigned long certopt, sl@0: unsigned long nameopt, int default_op, int ext_copy, sl@0: ENGINE *e); sl@0: static int certify_spkac(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509, sl@0: const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy, sl@0: CA_DB *db, BIGNUM *serial,char *subj,unsigned long chtype, int multirdn, int email_dn, sl@0: char *startdate, char *enddate, long days, char *ext_sect, sl@0: CONF *conf, int verbose, unsigned long certopt, sl@0: unsigned long nameopt, int default_op, int ext_copy); sl@0: static int fix_data(int nid, int *type); sl@0: static void write_new_certificate(BIO *bp, X509 *x, int output_der, int notext); sl@0: static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, sl@0: STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial,char *subj,unsigned long chtype, int multirdn, sl@0: int email_dn, char *startdate, char *enddate, long days, int batch, sl@0: int verbose, X509_REQ *req, char *ext_sect, CONF *conf, sl@0: unsigned long certopt, unsigned long nameopt, int default_op, sl@0: int ext_copy, int selfsign); sl@0: static int do_revoke(X509 *x509, CA_DB *db, int ext, char *extval); sl@0: static int get_certificate_status(const char *ser_status, CA_DB *db); sl@0: static int do_updatedb(CA_DB *db); sl@0: static int check_time_format(char *str); sl@0: char *make_revocation_str(int rev_type, char *rev_arg); sl@0: int make_revoked(X509_REVOKED *rev, const char *str); sl@0: int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str); sl@0: static CONF *conf=NULL; sl@0: static CONF *extconf=NULL; sl@0: static char *section=NULL; sl@0: sl@0: static int preserve=0; sl@0: static int msie_hack=0; sl@0: sl@0: sl@0: sl@0: int MAIN(int, char **); sl@0: sl@0: int MAIN(int argc, char **argv) sl@0: { sl@0: ENGINE *e = NULL; sl@0: char *key=NULL,*passargin=NULL; sl@0: int create_ser = 0; sl@0: int free_key = 0; sl@0: int total=0; sl@0: int total_done=0; sl@0: int badops=0; sl@0: int ret=1; sl@0: int email_dn=1; sl@0: int req=0; sl@0: int verbose=0; sl@0: int gencrl=0; sl@0: int dorevoke=0; sl@0: int doupdatedb=0; sl@0: long crldays=0; sl@0: long crlhours=0; sl@0: long errorline= -1; sl@0: char *configfile=NULL; sl@0: char *md=NULL; sl@0: char *policy=NULL; sl@0: char *keyfile=NULL; sl@0: char *certfile=NULL; sl@0: int keyform=FORMAT_PEM; sl@0: char *infile=NULL; sl@0: char *spkac_file=NULL; sl@0: char *ss_cert_file=NULL; sl@0: char *ser_status=NULL; sl@0: EVP_PKEY *pkey=NULL; sl@0: int output_der = 0; sl@0: char *outfile=NULL; sl@0: char *outdir=NULL; sl@0: char *serialfile=NULL; sl@0: char *crlnumberfile=NULL; sl@0: char *extensions=NULL; sl@0: char *extfile=NULL; sl@0: char *subj=NULL; sl@0: unsigned long chtype = MBSTRING_ASC; sl@0: int multirdn = 0; sl@0: char *tmp_email_dn=NULL; sl@0: char *crl_ext=NULL; sl@0: int rev_type = REV_NONE; sl@0: char *rev_arg = NULL; sl@0: BIGNUM *serial=NULL; sl@0: BIGNUM *crlnumber=NULL; sl@0: char *startdate=NULL; sl@0: char *enddate=NULL; sl@0: long days=0; sl@0: int batch=0; sl@0: int notext=0; sl@0: unsigned long nameopt = 0, certopt = 0; sl@0: int default_op = 1; sl@0: int ext_copy = EXT_COPY_NONE; sl@0: int selfsign = 0; sl@0: X509 *x509=NULL, *x509p = NULL; sl@0: X509 *x=NULL; sl@0: BIO *in=NULL,*out=NULL,*Sout=NULL,*Cout=NULL; sl@0: char *dbfile=NULL; sl@0: CA_DB *db=NULL; sl@0: X509_CRL *crl=NULL; sl@0: X509_REVOKED *r=NULL; sl@0: ASN1_TIME *tmptm; sl@0: ASN1_INTEGER *tmpser; sl@0: char *f; sl@0: const char *p, **pp; sl@0: int i,j; sl@0: const EVP_MD *dgst=NULL; sl@0: STACK_OF(CONF_VALUE) *attribs=NULL; sl@0: STACK_OF(X509) *cert_sk=NULL; sl@0: #undef BSIZE sl@0: #define BSIZE 256 sl@0: MS_STATIC char buf[3][BSIZE]; sl@0: char *randfile=NULL; sl@0: #ifndef OPENSSL_NO_ENGINE sl@0: char *engine = NULL; sl@0: #endif sl@0: char *tofree=NULL; sl@0: DB_ATTR db_attr; sl@0: sl@0: #ifdef EFENCE sl@0: EF_PROTECT_FREE=1; sl@0: EF_PROTECT_BELOW=1; sl@0: EF_ALIGNMENT=0; sl@0: #endif sl@0: sl@0: apps_startup(); sl@0: sl@0: conf = NULL; sl@0: key = NULL; sl@0: section = NULL; sl@0: sl@0: preserve=0; sl@0: msie_hack=0; sl@0: if (bio_err == NULL) sl@0: if ((bio_err=BIO_new(BIO_s_file())) != NULL) sl@0: BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT); sl@0: sl@0: argc--; sl@0: argv++; sl@0: while (argc >= 1) sl@0: { sl@0: if (strcmp(*argv,"-verbose") == 0) sl@0: verbose=1; sl@0: else if (strcmp(*argv,"-config") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: configfile= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-name") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: section= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-subj") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: subj= *(++argv); sl@0: /* preserve=1; */ sl@0: } sl@0: else if (strcmp(*argv,"-utf8") == 0) sl@0: chtype = MBSTRING_UTF8; sl@0: else if (strcmp(*argv,"-create_serial") == 0) sl@0: create_ser = 1; sl@0: else if (strcmp(*argv,"-multivalue-rdn") == 0) sl@0: multirdn=1; sl@0: else if (strcmp(*argv,"-startdate") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: startdate= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-enddate") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: enddate= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-days") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: days=atoi(*(++argv)); sl@0: } sl@0: else if (strcmp(*argv,"-md") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: md= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-policy") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: policy= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-keyfile") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: keyfile= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-keyform") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: keyform=str2fmt(*(++argv)); sl@0: } sl@0: else if (strcmp(*argv,"-passin") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: passargin= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-key") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: key= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-cert") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: certfile= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-selfsign") == 0) sl@0: selfsign=1; sl@0: else if (strcmp(*argv,"-in") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: infile= *(++argv); sl@0: req=1; sl@0: } sl@0: else if (strcmp(*argv,"-out") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: outfile= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-outdir") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: outdir= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-notext") == 0) sl@0: notext=1; sl@0: else if (strcmp(*argv,"-batch") == 0) sl@0: batch=1; sl@0: else if (strcmp(*argv,"-preserveDN") == 0) sl@0: preserve=1; sl@0: else if (strcmp(*argv,"-noemailDN") == 0) sl@0: email_dn=0; sl@0: else if (strcmp(*argv,"-gencrl") == 0) sl@0: gencrl=1; sl@0: else if (strcmp(*argv,"-msie_hack") == 0) sl@0: msie_hack=1; sl@0: else if (strcmp(*argv,"-crldays") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: crldays= atol(*(++argv)); sl@0: } sl@0: else if (strcmp(*argv,"-crlhours") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: crlhours= atol(*(++argv)); sl@0: } sl@0: else if (strcmp(*argv,"-infiles") == 0) sl@0: { sl@0: argc--; sl@0: argv++; sl@0: req=1; sl@0: break; sl@0: } sl@0: else if (strcmp(*argv, "-ss_cert") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: ss_cert_file = *(++argv); sl@0: req=1; sl@0: } sl@0: else if (strcmp(*argv, "-spkac") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: spkac_file = *(++argv); sl@0: req=1; sl@0: } sl@0: else if (strcmp(*argv,"-revoke") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: infile= *(++argv); sl@0: dorevoke=1; sl@0: } sl@0: else if (strcmp(*argv,"-extensions") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: extensions= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-extfile") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: extfile= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-status") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: ser_status= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-updatedb") == 0) sl@0: { sl@0: doupdatedb=1; sl@0: } sl@0: else if (strcmp(*argv,"-crlexts") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: crl_ext= *(++argv); sl@0: } sl@0: else if (strcmp(*argv,"-crl_reason") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: rev_arg = *(++argv); sl@0: rev_type = REV_CRL_REASON; sl@0: } sl@0: else if (strcmp(*argv,"-crl_hold") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: rev_arg = *(++argv); sl@0: rev_type = REV_HOLD; sl@0: } sl@0: else if (strcmp(*argv,"-crl_compromise") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: rev_arg = *(++argv); sl@0: rev_type = REV_KEY_COMPROMISE; sl@0: } sl@0: else if (strcmp(*argv,"-crl_CA_compromise") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: rev_arg = *(++argv); sl@0: rev_type = REV_CA_COMPROMISE; sl@0: } sl@0: #ifndef OPENSSL_NO_ENGINE sl@0: else if (strcmp(*argv,"-engine") == 0) sl@0: { sl@0: if (--argc < 1) goto bad; sl@0: engine= *(++argv); sl@0: } sl@0: #endif sl@0: else sl@0: { sl@0: bad: sl@0: BIO_printf(bio_err,"unknown option %s\n",*argv); sl@0: badops=1; sl@0: break; sl@0: } sl@0: argc--; sl@0: argv++; sl@0: } sl@0: sl@0: if (badops) sl@0: { sl@0: for (pp=ca_usage; (*pp != NULL); pp++) sl@0: BIO_printf(bio_err,"%s",*pp); sl@0: goto err; sl@0: } sl@0: sl@0: ERR_load_crypto_strings(); sl@0: sl@0: /*****************************************************************/ sl@0: tofree=NULL; sl@0: if (configfile == NULL) configfile = getenv("OPENSSL_CONF"); sl@0: if (configfile == NULL) configfile = getenv("SSLEAY_CONF"); sl@0: if (configfile == NULL) sl@0: { sl@0: const char *s=X509_get_default_cert_area(); sl@0: size_t len; sl@0: sl@0: #ifdef OPENSSL_SYS_VMS sl@0: len = strlen(s)+sizeof(CONFIG_FILE); sl@0: tofree=OPENSSL_malloc(len); sl@0: strcpy(tofree,s); sl@0: #else sl@0: len = strlen(s)+sizeof(CONFIG_FILE)+1; sl@0: tofree=OPENSSL_malloc(len); sl@0: BUF_strlcpy(tofree,s,len); sl@0: BUF_strlcat(tofree,"/",len); sl@0: #endif sl@0: BUF_strlcat(tofree,CONFIG_FILE,len); sl@0: configfile=tofree; sl@0: } sl@0: sl@0: BIO_printf(bio_err,"Using configuration from %s\n",configfile); sl@0: conf = NCONF_new(NULL); sl@0: if (NCONF_load(conf,configfile,&errorline) <= 0) sl@0: { sl@0: if (errorline <= 0) sl@0: BIO_printf(bio_err,"error loading the config file '%s'\n", sl@0: configfile); sl@0: else sl@0: BIO_printf(bio_err,"error on line %ld of config file '%s'\n" sl@0: ,errorline,configfile); sl@0: goto err; sl@0: } sl@0: if(tofree) sl@0: { sl@0: OPENSSL_free(tofree); sl@0: tofree = NULL; sl@0: } sl@0: sl@0: if (!load_config(bio_err, conf)) sl@0: goto err; sl@0: sl@0: #ifndef OPENSSL_NO_ENGINE sl@0: e = setup_engine(bio_err, engine, 0); sl@0: #endif sl@0: sl@0: /* Lets get the config section we are using */ sl@0: if (section == NULL) sl@0: { sl@0: section=NCONF_get_string(conf,BASE_SECTION,ENV_DEFAULT_CA); sl@0: if (section == NULL) sl@0: { sl@0: lookup_fail(BASE_SECTION,ENV_DEFAULT_CA); sl@0: goto err; sl@0: } sl@0: } sl@0: sl@0: if (conf != NULL) sl@0: { sl@0: p=NCONF_get_string(conf,NULL,"oid_file"); sl@0: if (p == NULL) sl@0: ERR_clear_error(); sl@0: if (p != NULL) sl@0: { sl@0: BIO *oid_bio; sl@0: sl@0: oid_bio=BIO_new_file(p,"r"); sl@0: if (oid_bio == NULL) sl@0: { sl@0: /* sl@0: BIO_printf(bio_err,"problems opening %s for extra oid's\n",p); sl@0: ERR_print_errors(bio_err); sl@0: */ sl@0: ERR_clear_error(); sl@0: } sl@0: else sl@0: { sl@0: OBJ_create_objects(oid_bio); sl@0: BIO_free(oid_bio); sl@0: } sl@0: } sl@0: if (!add_oid_section(bio_err,conf)) sl@0: { sl@0: ERR_print_errors(bio_err); sl@0: goto err; sl@0: } sl@0: } sl@0: sl@0: randfile = NCONF_get_string(conf, BASE_SECTION, "RANDFILE"); sl@0: if (randfile == NULL) sl@0: ERR_clear_error(); sl@0: app_RAND_load_file(randfile, bio_err, 0); sl@0: sl@0: f = NCONF_get_string(conf, section, STRING_MASK); sl@0: if (!f) sl@0: ERR_clear_error(); sl@0: sl@0: if(f && !ASN1_STRING_set_default_mask_asc(f)) { sl@0: BIO_printf(bio_err, "Invalid global string mask setting %s\n", f); sl@0: goto err; sl@0: } sl@0: sl@0: if (chtype != MBSTRING_UTF8){ sl@0: f = NCONF_get_string(conf, section, UTF8_IN); sl@0: if (!f) sl@0: ERR_clear_error(); sl@0: else if (!strcmp(f, "yes")) sl@0: chtype = MBSTRING_UTF8; sl@0: } sl@0: sl@0: db_attr.unique_subject = 1; sl@0: p = NCONF_get_string(conf, section, ENV_UNIQUE_SUBJECT); sl@0: if (p) sl@0: { sl@0: #ifdef RL_DEBUG sl@0: BIO_printf(bio_err, "DEBUG: unique_subject = \"%s\"\n", p); sl@0: #endif sl@0: db_attr.unique_subject = parse_yesno(p,1); sl@0: } sl@0: else sl@0: ERR_clear_error(); sl@0: #ifdef RL_DEBUG sl@0: if (!p) sl@0: BIO_printf(bio_err, "DEBUG: unique_subject undefined\n", p); sl@0: #endif sl@0: #ifdef RL_DEBUG sl@0: BIO_printf(bio_err, "DEBUG: configured unique_subject is %d\n", sl@0: db_attr.unique_subject); sl@0: #endif sl@0: sl@0: in=BIO_new(BIO_s_file()); sl@0: out=BIO_new(BIO_s_file()); sl@0: Sout=BIO_new(BIO_s_file()); sl@0: Cout=BIO_new(BIO_s_file()); sl@0: if ((in == NULL) || (out == NULL) || (Sout == NULL) || (Cout == NULL)) sl@0: { sl@0: ERR_print_errors(bio_err); sl@0: goto err; sl@0: } sl@0: sl@0: /*****************************************************************/ sl@0: /* report status of cert with serial number given on command line */ sl@0: if (ser_status) sl@0: { sl@0: if ((dbfile=NCONF_get_string(conf,section,ENV_DATABASE)) == NULL) sl@0: { sl@0: lookup_fail(section,ENV_DATABASE); sl@0: goto err; sl@0: } sl@0: db = load_index(dbfile,&db_attr); sl@0: if (db == NULL) goto err; sl@0: sl@0: if (!index_index(db)) goto err; sl@0: sl@0: if (get_certificate_status(ser_status,db) != 1) sl@0: BIO_printf(bio_err,"Error verifying serial %s!\n", sl@0: ser_status); sl@0: goto err; sl@0: } sl@0: sl@0: /*****************************************************************/ sl@0: /* we definitely need a private key, so let's get it */ sl@0: sl@0: if ((keyfile == NULL) && ((keyfile=NCONF_get_string(conf, sl@0: section,ENV_PRIVATE_KEY)) == NULL)) sl@0: { sl@0: lookup_fail(section,ENV_PRIVATE_KEY); sl@0: goto err; sl@0: } sl@0: if (!key) sl@0: { sl@0: free_key = 1; sl@0: if (!app_passwd(bio_err, passargin, NULL, &key, NULL)) sl@0: { sl@0: BIO_printf(bio_err,"Error getting password\n"); sl@0: goto err; sl@0: } sl@0: } sl@0: pkey = load_key(bio_err, keyfile, keyform, 0, key, e, sl@0: "CA private key"); sl@0: if (key) OPENSSL_cleanse(key,strlen(key)); sl@0: if (pkey == NULL) sl@0: { sl@0: /* load_key() has already printed an appropriate message */ sl@0: goto err; sl@0: } sl@0: sl@0: /*****************************************************************/ sl@0: /* we need a certificate */ sl@0: if (!selfsign || spkac_file || ss_cert_file || gencrl) sl@0: { sl@0: if ((certfile == NULL) sl@0: && ((certfile=NCONF_get_string(conf, sl@0: section,ENV_CERTIFICATE)) == NULL)) sl@0: { sl@0: lookup_fail(section,ENV_CERTIFICATE); sl@0: goto err; sl@0: } sl@0: x509=load_cert(bio_err, certfile, FORMAT_PEM, NULL, e, sl@0: "CA certificate"); sl@0: if (x509 == NULL) sl@0: goto err; sl@0: sl@0: if (!X509_check_private_key(x509,pkey)) sl@0: { sl@0: BIO_printf(bio_err,"CA certificate and CA private key do not match\n"); sl@0: goto err; sl@0: } sl@0: } sl@0: if (!selfsign) x509p = x509; sl@0: sl@0: f=NCONF_get_string(conf,BASE_SECTION,ENV_PRESERVE); sl@0: if (f == NULL) sl@0: ERR_clear_error(); sl@0: if ((f != NULL) && ((*f == 'y') || (*f == 'Y'))) sl@0: preserve=1; sl@0: f=NCONF_get_string(conf,BASE_SECTION,ENV_MSIE_HACK); sl@0: if (f == NULL) sl@0: ERR_clear_error(); sl@0: if ((f != NULL) && ((*f == 'y') || (*f == 'Y'))) sl@0: msie_hack=1; sl@0: sl@0: f=NCONF_get_string(conf,section,ENV_NAMEOPT); sl@0: sl@0: if (f) sl@0: { sl@0: if (!set_name_ex(&nameopt, f)) sl@0: { sl@0: BIO_printf(bio_err, "Invalid name options: \"%s\"\n", f); sl@0: goto err; sl@0: } sl@0: default_op = 0; sl@0: } sl@0: else sl@0: ERR_clear_error(); sl@0: sl@0: f=NCONF_get_string(conf,section,ENV_CERTOPT); sl@0: sl@0: if (f) sl@0: { sl@0: if (!set_cert_ex(&certopt, f)) sl@0: { sl@0: BIO_printf(bio_err, "Invalid certificate options: \"%s\"\n", f); sl@0: goto err; sl@0: } sl@0: default_op = 0; sl@0: } sl@0: else sl@0: ERR_clear_error(); sl@0: sl@0: f=NCONF_get_string(conf,section,ENV_EXTCOPY); sl@0: sl@0: if (f) sl@0: { sl@0: if (!set_ext_copy(&ext_copy, f)) sl@0: { sl@0: BIO_printf(bio_err, "Invalid extension copy option: \"%s\"\n", f); sl@0: goto err; sl@0: } sl@0: } sl@0: else sl@0: ERR_clear_error(); sl@0: sl@0: /*****************************************************************/ sl@0: /* lookup where to write new certificates */ sl@0: if ((outdir == NULL) && (req)) sl@0: { sl@0: struct stat sb; sl@0: sl@0: if ((outdir=NCONF_get_string(conf,section,ENV_NEW_CERTS_DIR)) sl@0: == NULL) sl@0: { sl@0: BIO_printf(bio_err,"there needs to be defined a directory for new certificate to be placed in\n"); sl@0: goto err; sl@0: } sl@0: #ifndef OPENSSL_SYS_VMS sl@0: /* outdir is a directory spec, but access() for VMS demands a sl@0: filename. In any case, stat(), below, will catch the problem sl@0: if outdir is not a directory spec, and the fopen() or open() sl@0: will catch an error if there is no write access. sl@0: sl@0: Presumably, this problem could also be solved by using the DEC sl@0: C routines to convert the directory syntax to Unixly, and give sl@0: that to access(). However, time's too short to do that just sl@0: now. sl@0: */ sl@0: if (access(outdir,R_OK|W_OK|X_OK) != 0) sl@0: { sl@0: BIO_printf(bio_err,"I am unable to access the %s directory\n",outdir); sl@0: perror(outdir); sl@0: goto err; sl@0: } sl@0: sl@0: if (stat(outdir,&sb) != 0) sl@0: { sl@0: BIO_printf(bio_err,"unable to stat(%s)\n",outdir); sl@0: perror(outdir); sl@0: goto err; sl@0: } sl@0: #ifdef S_IFDIR sl@0: if (!(sb.st_mode & S_IFDIR)) sl@0: { sl@0: BIO_printf(bio_err,"%s need to be a directory\n",outdir); sl@0: perror(outdir); sl@0: goto err; sl@0: } sl@0: #endif sl@0: #endif sl@0: } sl@0: sl@0: /*****************************************************************/ sl@0: /* we need to load the database file */ sl@0: if ((dbfile=NCONF_get_string(conf,section,ENV_DATABASE)) == NULL) sl@0: { sl@0: lookup_fail(section,ENV_DATABASE); sl@0: goto err; sl@0: } sl@0: db = load_index(dbfile, &db_attr); sl@0: if (db == NULL) goto err; sl@0: sl@0: /* Lets check some fields */ sl@0: for (i=0; idb->data); i++) sl@0: { sl@0: pp=(const char **)sk_value(db->db->data,i); sl@0: if ((pp[DB_type][0] != DB_TYPE_REV) && sl@0: (pp[DB_rev_date][0] != '\0')) sl@0: { sl@0: BIO_printf(bio_err,"entry %d: not revoked yet, but has a revocation date\n",i+1); sl@0: goto err; sl@0: } sl@0: if ((pp[DB_type][0] == DB_TYPE_REV) && sl@0: !make_revoked(NULL, pp[DB_rev_date])) sl@0: { sl@0: BIO_printf(bio_err," in entry %d\n", i+1); sl@0: goto err; sl@0: } sl@0: if (!check_time_format((char *)pp[DB_exp_date])) sl@0: { sl@0: BIO_printf(bio_err,"entry %d: invalid expiry date\n",i+1); sl@0: goto err; sl@0: } sl@0: p=pp[DB_serial]; sl@0: j=strlen(p); sl@0: if (*p == '-') sl@0: { sl@0: p++; sl@0: j--; sl@0: } sl@0: if ((j&1) || (j < 2)) sl@0: { sl@0: BIO_printf(bio_err,"entry %d: bad serial number length (%d)\n",i+1,j); sl@0: goto err; sl@0: } sl@0: while (*p) sl@0: { sl@0: if (!( ((*p >= '0') && (*p <= '9')) || sl@0: ((*p >= 'A') && (*p <= 'F')) || sl@0: ((*p >= 'a') && (*p <= 'f'))) ) sl@0: { sl@0: BIO_printf(bio_err,"entry %d: bad serial number characters, char pos %ld, char is '%c'\n",i+1,(long)(p-pp[DB_serial]),*p); sl@0: goto err; sl@0: } sl@0: p++; sl@0: } sl@0: } sl@0: if (verbose) sl@0: { sl@0: BIO_set_fp(out,stdout,BIO_NOCLOSE|BIO_FP_TEXT); /* cannot fail */ sl@0: #ifdef OPENSSL_SYS_VMS sl@0: { sl@0: BIO *tmpbio = BIO_new(BIO_f_linebuffer()); sl@0: out = BIO_push(tmpbio, out); sl@0: } sl@0: #endif sl@0: TXT_DB_write(out,db->db); sl@0: BIO_printf(bio_err,"%d entries loaded from the database\n", sl@0: db->db->data->num); sl@0: BIO_printf(bio_err,"generating index\n"); sl@0: } sl@0: sl@0: if (!index_index(db)) goto err; sl@0: sl@0: /*****************************************************************/ sl@0: /* Update the db file for expired certificates */ sl@0: if (doupdatedb) sl@0: { sl@0: if (verbose) sl@0: BIO_printf(bio_err, "Updating %s ...\n", sl@0: dbfile); sl@0: sl@0: i = do_updatedb(db); sl@0: if (i == -1) sl@0: { sl@0: BIO_printf(bio_err,"Malloc failure\n"); sl@0: goto err; sl@0: } sl@0: else if (i == 0) sl@0: { sl@0: if (verbose) BIO_printf(bio_err, sl@0: "No entries found to mark expired\n"); sl@0: } sl@0: else sl@0: { sl@0: if (!save_index(dbfile,"new",db)) goto err; sl@0: sl@0: if (!rotate_index(dbfile,"new","old")) goto err; sl@0: sl@0: if (verbose) BIO_printf(bio_err, sl@0: "Done. %d entries marked as expired\n",i); sl@0: } sl@0: } sl@0: sl@0: /*****************************************************************/ sl@0: /* Read extentions config file */ sl@0: if (extfile) sl@0: { sl@0: extconf = NCONF_new(NULL); sl@0: if (NCONF_load(extconf,extfile,&errorline) <= 0) sl@0: { sl@0: if (errorline <= 0) sl@0: BIO_printf(bio_err, "ERROR: loading the config file '%s'\n", sl@0: extfile); sl@0: else sl@0: BIO_printf(bio_err, "ERROR: on line %ld of config file '%s'\n", sl@0: errorline,extfile); sl@0: ret = 1; sl@0: goto err; sl@0: } sl@0: sl@0: if (verbose) sl@0: BIO_printf(bio_err, "Successfully loaded extensions file %s\n", extfile); sl@0: sl@0: /* We can have sections in the ext file */ sl@0: if (!extensions && !(extensions = NCONF_get_string(extconf, "default", "extensions"))) sl@0: extensions = "default"; sl@0: } sl@0: sl@0: /*****************************************************************/ sl@0: if (req || gencrl) sl@0: { sl@0: if (outfile != NULL) sl@0: { sl@0: if (BIO_write_filename(Sout,outfile) <= 0) sl@0: { sl@0: perror(outfile); sl@0: goto err; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: BIO_set_fp(Sout,stdout,BIO_NOCLOSE|BIO_FP_TEXT); sl@0: #ifdef OPENSSL_SYS_VMS sl@0: { sl@0: BIO *tmpbio = BIO_new(BIO_f_linebuffer()); sl@0: Sout = BIO_push(tmpbio, Sout); sl@0: } sl@0: #endif sl@0: } sl@0: } sl@0: sl@0: if ((md == NULL) && ((md=NCONF_get_string(conf, sl@0: section,ENV_DEFAULT_MD)) == NULL)) sl@0: { sl@0: lookup_fail(section,ENV_DEFAULT_MD); sl@0: goto err; sl@0: } sl@0: sl@0: if ((dgst=EVP_get_digestbyname(md)) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"%s is an unsupported message digest type\n",md); sl@0: goto err; sl@0: } sl@0: sl@0: if (req) sl@0: { sl@0: if ((email_dn == 1) && ((tmp_email_dn=NCONF_get_string(conf, sl@0: section,ENV_DEFAULT_EMAIL_DN)) != NULL )) sl@0: { sl@0: if(strcmp(tmp_email_dn,"no") == 0) sl@0: email_dn=0; sl@0: } sl@0: if (verbose) sl@0: BIO_printf(bio_err,"message digest is %s\n", sl@0: OBJ_nid2ln(dgst->type)); sl@0: if ((policy == NULL) && ((policy=NCONF_get_string(conf, sl@0: section,ENV_POLICY)) == NULL)) sl@0: { sl@0: lookup_fail(section,ENV_POLICY); sl@0: goto err; sl@0: } sl@0: if (verbose) sl@0: BIO_printf(bio_err,"policy is %s\n",policy); sl@0: sl@0: if ((serialfile=NCONF_get_string(conf,section,ENV_SERIAL)) sl@0: == NULL) sl@0: { sl@0: lookup_fail(section,ENV_SERIAL); sl@0: goto err; sl@0: } sl@0: sl@0: if (!extconf) sl@0: { sl@0: /* no '-extfile' option, so we look for extensions sl@0: * in the main configuration file */ sl@0: if (!extensions) sl@0: { sl@0: extensions=NCONF_get_string(conf,section, sl@0: ENV_EXTENSIONS); sl@0: if (!extensions) sl@0: ERR_clear_error(); sl@0: } sl@0: if (extensions) sl@0: { sl@0: /* Check syntax of file */ sl@0: X509V3_CTX ctx; sl@0: X509V3_set_ctx_test(&ctx); sl@0: X509V3_set_nconf(&ctx, conf); sl@0: if (!X509V3_EXT_add_nconf(conf, &ctx, extensions, sl@0: NULL)) sl@0: { sl@0: BIO_printf(bio_err, sl@0: "Error Loading extension section %s\n", sl@0: extensions); sl@0: ret = 1; sl@0: goto err; sl@0: } sl@0: } sl@0: } sl@0: sl@0: if (startdate == NULL) sl@0: { sl@0: startdate=NCONF_get_string(conf,section, sl@0: ENV_DEFAULT_STARTDATE); sl@0: if (startdate == NULL) sl@0: ERR_clear_error(); sl@0: } sl@0: if (startdate && !ASN1_UTCTIME_set_string(NULL,startdate)) sl@0: { sl@0: BIO_printf(bio_err,"start date is invalid, it should be YYMMDDHHMMSSZ\n"); sl@0: goto err; sl@0: } sl@0: if (startdate == NULL) startdate="today"; sl@0: sl@0: if (enddate == NULL) sl@0: { sl@0: enddate=NCONF_get_string(conf,section, sl@0: ENV_DEFAULT_ENDDATE); sl@0: if (enddate == NULL) sl@0: ERR_clear_error(); sl@0: } sl@0: if (enddate && !ASN1_UTCTIME_set_string(NULL,enddate)) sl@0: { sl@0: BIO_printf(bio_err,"end date is invalid, it should be YYMMDDHHMMSSZ\n"); sl@0: goto err; sl@0: } sl@0: sl@0: if (days == 0) sl@0: { sl@0: if(!NCONF_get_number(conf,section, ENV_DEFAULT_DAYS, &days)) sl@0: days = 0; sl@0: } sl@0: if (!enddate && (days == 0)) sl@0: { sl@0: BIO_printf(bio_err,"cannot lookup how many days to certify for\n"); sl@0: goto err; sl@0: } sl@0: sl@0: if ((serial=load_serial(serialfile, create_ser, NULL)) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"error while loading serial number\n"); sl@0: goto err; sl@0: } sl@0: if (verbose) sl@0: { sl@0: if (BN_is_zero(serial)) sl@0: BIO_printf(bio_err,"next serial number is 00\n"); sl@0: else sl@0: { sl@0: if ((f=BN_bn2hex(serial)) == NULL) goto err; sl@0: BIO_printf(bio_err,"next serial number is %s\n",f); sl@0: OPENSSL_free(f); sl@0: } sl@0: } sl@0: sl@0: if ((attribs=NCONF_get_section(conf,policy)) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"unable to find 'section' for %s\n",policy); sl@0: goto err; sl@0: } sl@0: sl@0: if ((cert_sk=sk_X509_new_null()) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: if (spkac_file != NULL) sl@0: { sl@0: total++; sl@0: j=certify_spkac(&x,spkac_file,pkey,x509,dgst,attribs,db, sl@0: serial,subj,chtype,multirdn,email_dn,startdate,enddate,days,extensions, sl@0: conf,verbose,certopt,nameopt,default_op,ext_copy); sl@0: if (j < 0) goto err; sl@0: if (j > 0) sl@0: { sl@0: total_done++; sl@0: BIO_printf(bio_err,"\n"); sl@0: if (!BN_add_word(serial,1)) goto err; sl@0: if (!sk_X509_push(cert_sk,x)) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: if (outfile) sl@0: { sl@0: output_der = 1; sl@0: batch = 1; sl@0: } sl@0: } sl@0: } sl@0: if (ss_cert_file != NULL) sl@0: { sl@0: total++; sl@0: j=certify_cert(&x,ss_cert_file,pkey,x509,dgst,attribs, sl@0: db,serial,subj,chtype,multirdn,email_dn,startdate,enddate,days,batch, sl@0: extensions,conf,verbose, certopt, nameopt, sl@0: default_op, ext_copy, e); sl@0: if (j < 0) goto err; sl@0: if (j > 0) sl@0: { sl@0: total_done++; sl@0: BIO_printf(bio_err,"\n"); sl@0: if (!BN_add_word(serial,1)) goto err; sl@0: if (!sk_X509_push(cert_sk,x)) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: } sl@0: } sl@0: if (infile != NULL) sl@0: { sl@0: total++; sl@0: j=certify(&x,infile,pkey,x509p,dgst,attribs,db, sl@0: serial,subj,chtype,multirdn,email_dn,startdate,enddate,days,batch, sl@0: extensions,conf,verbose, certopt, nameopt, sl@0: default_op, ext_copy, selfsign); sl@0: if (j < 0) goto err; sl@0: if (j > 0) sl@0: { sl@0: total_done++; sl@0: BIO_printf(bio_err,"\n"); sl@0: if (!BN_add_word(serial,1)) goto err; sl@0: if (!sk_X509_push(cert_sk,x)) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: } sl@0: } sl@0: for (i=0; i 0) sl@0: { sl@0: total_done++; sl@0: BIO_printf(bio_err,"\n"); sl@0: if (!BN_add_word(serial,1)) goto err; sl@0: if (!sk_X509_push(cert_sk,x)) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: } sl@0: } sl@0: /* we have a stack of newly certified certificates sl@0: * and a data base and serial number that need sl@0: * updating */ sl@0: sl@0: if (sk_X509_num(cert_sk) > 0) sl@0: { sl@0: if (!batch) sl@0: { sl@0: BIO_printf(bio_err,"\n%d out of %d certificate requests certified, commit? [y/n]",total_done,total); sl@0: (void)BIO_flush(bio_err); sl@0: buf[0][0]='\0'; sl@0: fgets(buf[0],10,stdin); sl@0: if ((buf[0][0] != 'y') && (buf[0][0] != 'Y')) sl@0: { sl@0: BIO_printf(bio_err,"CERTIFICATION CANCELED\n"); sl@0: ret=0; sl@0: goto err; sl@0: } sl@0: } sl@0: sl@0: BIO_printf(bio_err,"Write out database with %d new entries\n",sk_X509_num(cert_sk)); sl@0: sl@0: if (!save_serial(serialfile,"new",serial,NULL)) goto err; sl@0: sl@0: if (!save_index(dbfile, "new", db)) goto err; sl@0: } sl@0: sl@0: if (verbose) sl@0: BIO_printf(bio_err,"writing new certificates\n"); sl@0: for (i=0; icert_info->serialNumber->length; sl@0: p=(const char *)x->cert_info->serialNumber->data; sl@0: sl@0: if(strlen(outdir) >= (size_t)(j ? BSIZE-j*2-6 : BSIZE-8)) sl@0: { sl@0: BIO_printf(bio_err,"certificate file name too long\n"); sl@0: goto err; sl@0: } sl@0: sl@0: strcpy(buf[2],outdir); sl@0: sl@0: #ifndef OPENSSL_SYS_VMS sl@0: BUF_strlcat(buf[2],"/",sizeof(buf[2])); sl@0: #endif sl@0: sl@0: n=(char *)&(buf[2][strlen(buf[2])]); sl@0: if (j > 0) sl@0: { sl@0: for (k=0; k= &(buf[2][sizeof(buf[2])])) sl@0: break; sl@0: BIO_snprintf(n, sl@0: &buf[2][0] + sizeof(buf[2]) - n, sl@0: "%02X",(unsigned char)*(p++)); sl@0: n+=2; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: *(n++)='0'; sl@0: *(n++)='0'; sl@0: } sl@0: *(n++)='.'; *(n++)='p'; *(n++)='e'; *(n++)='m'; sl@0: *n='\0'; sl@0: if (verbose) sl@0: BIO_printf(bio_err,"writing %s\n",buf[2]); sl@0: sl@0: if (BIO_write_filename(Cout,buf[2]) <= 0) sl@0: { sl@0: perror(buf[2]); sl@0: goto err; sl@0: } sl@0: write_new_certificate(Cout,x, 0, notext); sl@0: write_new_certificate(Sout,x, output_der, notext); sl@0: } sl@0: sl@0: if (sk_X509_num(cert_sk)) sl@0: { sl@0: /* Rename the database and the serial file */ sl@0: if (!rotate_serial(serialfile,"new","old")) goto err; sl@0: sl@0: if (!rotate_index(dbfile,"new","old")) goto err; sl@0: sl@0: BIO_printf(bio_err,"Data Base Updated\n"); sl@0: } sl@0: } sl@0: sl@0: /*****************************************************************/ sl@0: if (gencrl) sl@0: { sl@0: int crl_v2 = 0; sl@0: if (!crl_ext) sl@0: { sl@0: crl_ext=NCONF_get_string(conf,section,ENV_CRLEXT); sl@0: if (!crl_ext) sl@0: ERR_clear_error(); sl@0: } sl@0: if (crl_ext) sl@0: { sl@0: /* Check syntax of file */ sl@0: X509V3_CTX ctx; sl@0: X509V3_set_ctx_test(&ctx); sl@0: X509V3_set_nconf(&ctx, conf); sl@0: if (!X509V3_EXT_add_nconf(conf, &ctx, crl_ext, NULL)) sl@0: { sl@0: BIO_printf(bio_err, sl@0: "Error Loading CRL extension section %s\n", sl@0: crl_ext); sl@0: ret = 1; sl@0: goto err; sl@0: } sl@0: } sl@0: sl@0: if ((crlnumberfile=NCONF_get_string(conf,section,ENV_CRLNUMBER)) sl@0: != NULL) sl@0: if ((crlnumber=load_serial(crlnumberfile,0,NULL)) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"error while loading CRL number\n"); sl@0: goto err; sl@0: } sl@0: sl@0: if (!crldays && !crlhours) sl@0: { sl@0: if (!NCONF_get_number(conf,section, sl@0: ENV_DEFAULT_CRL_DAYS, &crldays)) sl@0: crldays = 0; sl@0: if (!NCONF_get_number(conf,section, sl@0: ENV_DEFAULT_CRL_HOURS, &crlhours)) sl@0: crlhours = 0; sl@0: } sl@0: if ((crldays == 0) && (crlhours == 0)) sl@0: { sl@0: BIO_printf(bio_err,"cannot lookup how long until the next CRL is issued\n"); sl@0: goto err; sl@0: } sl@0: sl@0: if (verbose) BIO_printf(bio_err,"making CRL\n"); sl@0: if ((crl=X509_CRL_new()) == NULL) goto err; sl@0: if (!X509_CRL_set_issuer_name(crl, X509_get_subject_name(x509))) goto err; sl@0: sl@0: tmptm = ASN1_TIME_new(); sl@0: if (!tmptm) goto err; sl@0: X509_gmtime_adj(tmptm,0); sl@0: X509_CRL_set_lastUpdate(crl, tmptm); sl@0: X509_gmtime_adj(tmptm,(crldays*24+crlhours)*60*60); sl@0: X509_CRL_set_nextUpdate(crl, tmptm); sl@0: sl@0: ASN1_TIME_free(tmptm); sl@0: sl@0: for (i=0; idb->data); i++) sl@0: { sl@0: pp=(const char **)sk_value(db->db->data,i); sl@0: if (pp[DB_type][0] == DB_TYPE_REV) sl@0: { sl@0: if ((r=X509_REVOKED_new()) == NULL) goto err; sl@0: j = make_revoked(r, pp[DB_rev_date]); sl@0: if (!j) goto err; sl@0: if (j == 2) crl_v2 = 1; sl@0: if (!BN_hex2bn(&serial, pp[DB_serial])) sl@0: goto err; sl@0: tmpser = BN_to_ASN1_INTEGER(serial, NULL); sl@0: BN_free(serial); sl@0: serial = NULL; sl@0: if (!tmpser) sl@0: goto err; sl@0: X509_REVOKED_set_serialNumber(r, tmpser); sl@0: ASN1_INTEGER_free(tmpser); sl@0: X509_CRL_add0_revoked(crl,r); sl@0: } sl@0: } sl@0: sl@0: /* sort the data so it will be written in serial sl@0: * number order */ sl@0: X509_CRL_sort(crl); sl@0: sl@0: /* we now have a CRL */ sl@0: if (verbose) BIO_printf(bio_err,"signing CRL\n"); sl@0: #ifndef OPENSSL_NO_DSA sl@0: if (pkey->type == EVP_PKEY_DSA) sl@0: dgst=EVP_dss1(); sl@0: else sl@0: #endif sl@0: #ifndef OPENSSL_NO_ECDSA sl@0: if (pkey->type == EVP_PKEY_EC) sl@0: dgst=EVP_ecdsa(); sl@0: #endif sl@0: sl@0: /* Add any extensions asked for */ sl@0: sl@0: if (crl_ext || crlnumberfile != NULL) sl@0: { sl@0: X509V3_CTX crlctx; sl@0: X509V3_set_ctx(&crlctx, x509, NULL, NULL, crl, 0); sl@0: X509V3_set_nconf(&crlctx, conf); sl@0: sl@0: if (crl_ext) sl@0: if (!X509V3_EXT_CRL_add_nconf(conf, &crlctx, sl@0: crl_ext, crl)) goto err; sl@0: if (crlnumberfile != NULL) sl@0: { sl@0: tmpser = BN_to_ASN1_INTEGER(crlnumber, NULL); sl@0: if (!tmpser) goto err; sl@0: X509_CRL_add1_ext_i2d(crl,NID_crl_number,tmpser,0,0); sl@0: ASN1_INTEGER_free(tmpser); sl@0: crl_v2 = 1; sl@0: if (!BN_add_word(crlnumber,1)) goto err; sl@0: } sl@0: } sl@0: if (crl_ext || crl_v2) sl@0: { sl@0: if (!X509_CRL_set_version(crl, 1)) sl@0: goto err; /* version 2 CRL */ sl@0: } sl@0: sl@0: sl@0: if (crlnumberfile != NULL) /* we have a CRL number that need updating */ sl@0: if (!save_serial(crlnumberfile,"new",crlnumber,NULL)) goto err; sl@0: sl@0: if (!X509_CRL_sign(crl,pkey,dgst)) goto err; sl@0: sl@0: PEM_write_bio_X509_CRL(Sout,crl); sl@0: sl@0: if (crlnumberfile != NULL) /* Rename the crlnumber file */ sl@0: if (!rotate_serial(crlnumberfile,"new","old")) goto err; sl@0: sl@0: } sl@0: /*****************************************************************/ sl@0: if (dorevoke) sl@0: { sl@0: if (infile == NULL) sl@0: { sl@0: BIO_printf(bio_err,"no input files\n"); sl@0: goto err; sl@0: } sl@0: else sl@0: { sl@0: X509 *revcert; sl@0: revcert=load_cert(bio_err, infile, FORMAT_PEM, sl@0: NULL, e, infile); sl@0: if (revcert == NULL) sl@0: goto err; sl@0: j=do_revoke(revcert,db, rev_type, rev_arg); sl@0: if (j <= 0) goto err; sl@0: X509_free(revcert); sl@0: sl@0: if (!save_index(dbfile, "new", db)) goto err; sl@0: sl@0: if (!rotate_index(dbfile, "new", "old")) goto err; sl@0: sl@0: BIO_printf(bio_err,"Data Base Updated\n"); sl@0: } sl@0: } sl@0: /*****************************************************************/ sl@0: ret=0; sl@0: err: sl@0: if(tofree) sl@0: OPENSSL_free(tofree); sl@0: BIO_free_all(Cout); sl@0: BIO_free_all(Sout); sl@0: BIO_free_all(out); sl@0: BIO_free_all(in); sl@0: sl@0: if (cert_sk) sl@0: sk_X509_pop_free(cert_sk,X509_free); sl@0: sl@0: if (ret) ERR_print_errors(bio_err); sl@0: app_RAND_write_file(randfile, bio_err); sl@0: if (free_key && key) sl@0: OPENSSL_free(key); sl@0: BN_free(serial); sl@0: free_index(db); sl@0: EVP_PKEY_free(pkey); sl@0: if (x509) X509_free(x509); sl@0: X509_CRL_free(crl); sl@0: NCONF_free(conf); sl@0: NCONF_free(extconf); sl@0: OBJ_cleanup(); sl@0: apps_shutdown(); sl@0: OPENSSL_EXIT(ret); sl@0: } sl@0: sl@0: static void lookup_fail(const char *name, const char *tag) sl@0: { sl@0: BIO_printf(bio_err,"variable lookup failed for %s::%s\n",name,tag); sl@0: } sl@0: sl@0: static int certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509, sl@0: const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, CA_DB *db, sl@0: BIGNUM *serial, char *subj,unsigned long chtype, int multirdn, int email_dn, char *startdate, char *enddate, sl@0: long days, int batch, char *ext_sect, CONF *lconf, int verbose, sl@0: unsigned long certopt, unsigned long nameopt, int default_op, sl@0: int ext_copy, int selfsign) sl@0: { sl@0: X509_REQ *req=NULL; sl@0: BIO *in=NULL; sl@0: EVP_PKEY *pktmp=NULL; sl@0: int ok= -1,i; sl@0: sl@0: in=BIO_new(BIO_s_file()); sl@0: sl@0: if (BIO_read_filename(in,infile) <= 0) sl@0: { sl@0: perror(infile); sl@0: goto err; sl@0: } sl@0: if ((req=PEM_read_bio_X509_REQ(in,NULL,NULL,NULL)) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"Error reading certificate request in %s\n", sl@0: infile); sl@0: goto err; sl@0: } sl@0: if (verbose) sl@0: X509_REQ_print(bio_err,req); sl@0: sl@0: BIO_printf(bio_err,"Check that the request matches the signature\n"); sl@0: sl@0: if (selfsign && !X509_REQ_check_private_key(req,pkey)) sl@0: { sl@0: BIO_printf(bio_err,"Certificate request and CA private key do not match\n"); sl@0: ok=0; sl@0: goto err; sl@0: } sl@0: if ((pktmp=X509_REQ_get_pubkey(req)) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"error unpacking public key\n"); sl@0: goto err; sl@0: } sl@0: i=X509_REQ_verify(req,pktmp); sl@0: EVP_PKEY_free(pktmp); sl@0: if (i < 0) sl@0: { sl@0: ok=0; sl@0: BIO_printf(bio_err,"Signature verification problems....\n"); sl@0: goto err; sl@0: } sl@0: if (i == 0) sl@0: { sl@0: ok=0; sl@0: BIO_printf(bio_err,"Signature did not match the certificate request\n"); sl@0: goto err; sl@0: } sl@0: else sl@0: BIO_printf(bio_err,"Signature ok\n"); sl@0: sl@0: ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,chtype,multirdn, email_dn, sl@0: startdate,enddate,days,batch,verbose,req,ext_sect,lconf, sl@0: certopt, nameopt, default_op, ext_copy, selfsign); sl@0: sl@0: err: sl@0: if (req != NULL) X509_REQ_free(req); sl@0: if (in != NULL) BIO_free(in); sl@0: return(ok); sl@0: } sl@0: sl@0: static int certify_cert(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509, sl@0: const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, CA_DB *db, sl@0: BIGNUM *serial, char *subj, unsigned long chtype, int multirdn, int email_dn, char *startdate, char *enddate, sl@0: long days, int batch, char *ext_sect, CONF *lconf, int verbose, sl@0: unsigned long certopt, unsigned long nameopt, int default_op, sl@0: int ext_copy, ENGINE *e) sl@0: { sl@0: X509 *req=NULL; sl@0: X509_REQ *rreq=NULL; sl@0: EVP_PKEY *pktmp=NULL; sl@0: int ok= -1,i; sl@0: sl@0: if ((req=load_cert(bio_err, infile, FORMAT_PEM, NULL, e, infile)) == NULL) sl@0: goto err; sl@0: if (verbose) sl@0: X509_print(bio_err,req); sl@0: sl@0: BIO_printf(bio_err,"Check that the request matches the signature\n"); sl@0: sl@0: if ((pktmp=X509_get_pubkey(req)) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"error unpacking public key\n"); sl@0: goto err; sl@0: } sl@0: i=X509_verify(req,pktmp); sl@0: EVP_PKEY_free(pktmp); sl@0: if (i < 0) sl@0: { sl@0: ok=0; sl@0: BIO_printf(bio_err,"Signature verification problems....\n"); sl@0: goto err; sl@0: } sl@0: if (i == 0) sl@0: { sl@0: ok=0; sl@0: BIO_printf(bio_err,"Signature did not match the certificate\n"); sl@0: goto err; sl@0: } sl@0: else sl@0: BIO_printf(bio_err,"Signature ok\n"); sl@0: sl@0: if ((rreq=X509_to_X509_REQ(req,NULL,EVP_md5())) == NULL) sl@0: goto err; sl@0: sl@0: ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,chtype,multirdn,email_dn,startdate,enddate, sl@0: days,batch,verbose,rreq,ext_sect,lconf, certopt, nameopt, default_op, sl@0: ext_copy, 0); sl@0: sl@0: err: sl@0: if (rreq != NULL) X509_REQ_free(rreq); sl@0: if (req != NULL) X509_free(req); sl@0: return(ok); sl@0: } sl@0: sl@0: static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, sl@0: STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj, sl@0: unsigned long chtype, int multirdn, sl@0: int email_dn, char *startdate, char *enddate, long days, int batch, sl@0: int verbose, X509_REQ *req, char *ext_sect, CONF *lconf, sl@0: unsigned long certopt, unsigned long nameopt, int default_op, sl@0: int ext_copy, int selfsign) sl@0: { sl@0: X509_NAME *name=NULL,*CAname=NULL,*subject=NULL, *dn_subject=NULL; sl@0: ASN1_UTCTIME *tm,*tmptm; sl@0: ASN1_STRING *str,*str2; sl@0: ASN1_OBJECT *obj; sl@0: X509 *ret=NULL; sl@0: X509_CINF *ci; sl@0: X509_NAME_ENTRY *ne; sl@0: X509_NAME_ENTRY *tne,*push; sl@0: EVP_PKEY *pktmp; sl@0: int ok= -1,i,j,last,nid; sl@0: const char *p; sl@0: CONF_VALUE *cv; sl@0: char *row[DB_NUMBER],**rrow=NULL,**irow=NULL; sl@0: char buf[25]; sl@0: sl@0: tmptm=ASN1_UTCTIME_new(); sl@0: if (tmptm == NULL) sl@0: { sl@0: BIO_printf(bio_err,"malloc error\n"); sl@0: return(0); sl@0: } sl@0: sl@0: for (i=0; ireq_info->enc.modified = 1; sl@0: X509_NAME_free(n); sl@0: } sl@0: sl@0: if (default_op) sl@0: BIO_printf(bio_err,"The Subject's Distinguished Name is as follows\n"); sl@0: sl@0: name=X509_REQ_get_subject_name(req); sl@0: for (i=0; iobject); sl@0: sl@0: if (str->type == V_ASN1_UNIVERSALSTRING) sl@0: ASN1_UNIVERSALSTRING_to_string(str); sl@0: sl@0: if ((str->type == V_ASN1_IA5STRING) && sl@0: (nid != NID_pkcs9_emailAddress)) sl@0: str->type=V_ASN1_T61STRING; sl@0: sl@0: if ((nid == NID_pkcs9_emailAddress) && sl@0: (str->type == V_ASN1_PRINTABLESTRING)) sl@0: str->type=V_ASN1_IA5STRING; sl@0: } sl@0: sl@0: /* If no EMAIL is wanted in the subject */ sl@0: if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) && (!email_dn)) sl@0: continue; sl@0: sl@0: /* check some things */ sl@0: if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) && sl@0: (str->type != V_ASN1_IA5STRING)) sl@0: { sl@0: BIO_printf(bio_err,"\nemailAddress type needs to be of type IA5STRING\n"); sl@0: goto err; sl@0: } sl@0: if ((str->type != V_ASN1_BMPSTRING) && (str->type != V_ASN1_UTF8STRING)) sl@0: { sl@0: j=ASN1_PRINTABLE_type(str->data,str->length); sl@0: if ( ((j == V_ASN1_T61STRING) && sl@0: (str->type != V_ASN1_T61STRING)) || sl@0: ((j == V_ASN1_IA5STRING) && sl@0: (str->type == V_ASN1_PRINTABLESTRING))) sl@0: { sl@0: BIO_printf(bio_err,"\nThe string contains characters that are illegal for the ASN.1 type\n"); sl@0: goto err; sl@0: } sl@0: } sl@0: sl@0: if (default_op) sl@0: old_entry_print(bio_err, obj, str); sl@0: } sl@0: sl@0: /* Ok, now we check the 'policy' stuff. */ sl@0: if ((subject=X509_NAME_new()) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: sl@0: /* take a copy of the issuer name before we mess with it. */ sl@0: if (selfsign) sl@0: CAname=X509_NAME_dup(name); sl@0: else sl@0: CAname=X509_NAME_dup(x509->cert_info->subject); sl@0: if (CAname == NULL) goto err; sl@0: str=str2=NULL; sl@0: sl@0: for (i=0; iname)) == NID_undef) sl@0: { sl@0: BIO_printf(bio_err,"%s:unknown object type in 'policy' configuration\n",cv->name); sl@0: goto err; sl@0: } sl@0: obj=OBJ_nid2obj(j); sl@0: sl@0: last= -1; sl@0: for (;;) sl@0: { sl@0: /* lookup the object in the supplied name list */ sl@0: j=X509_NAME_get_index_by_OBJ(name,obj,last); sl@0: if (j < 0) sl@0: { sl@0: if (last != -1) break; sl@0: tne=NULL; sl@0: } sl@0: else sl@0: { sl@0: tne=X509_NAME_get_entry(name,j); sl@0: } sl@0: last=j; sl@0: sl@0: /* depending on the 'policy', decide what to do. */ sl@0: push=NULL; sl@0: if (strcmp(cv->value,"optional") == 0) sl@0: { sl@0: if (tne != NULL) sl@0: push=tne; sl@0: } sl@0: else if (strcmp(cv->value,"supplied") == 0) sl@0: { sl@0: if (tne == NULL) sl@0: { sl@0: BIO_printf(bio_err,"The %s field needed to be supplied and was missing\n",cv->name); sl@0: goto err; sl@0: } sl@0: else sl@0: push=tne; sl@0: } sl@0: else if (strcmp(cv->value,"match") == 0) sl@0: { sl@0: int last2; sl@0: sl@0: if (tne == NULL) sl@0: { sl@0: BIO_printf(bio_err,"The mandatory %s field was missing\n",cv->name); sl@0: goto err; sl@0: } sl@0: sl@0: last2= -1; sl@0: sl@0: again2: sl@0: j=X509_NAME_get_index_by_OBJ(CAname,obj,last2); sl@0: if ((j < 0) && (last2 == -1)) sl@0: { sl@0: BIO_printf(bio_err,"The %s field does not exist in the CA certificate,\nthe 'policy' is misconfigured\n",cv->name); sl@0: goto err; sl@0: } sl@0: if (j >= 0) sl@0: { sl@0: push=X509_NAME_get_entry(CAname,j); sl@0: str=X509_NAME_ENTRY_get_data(tne); sl@0: str2=X509_NAME_ENTRY_get_data(push); sl@0: last2=j; sl@0: if (ASN1_STRING_cmp(str,str2) != 0) sl@0: goto again2; sl@0: } sl@0: if (j < 0) sl@0: { sl@0: BIO_printf(bio_err,"The %s field needed to be the same in the\nCA certificate (%s) and the request (%s)\n",cv->name,((str2 == NULL)?"NULL":(char *)str2->data),((str == NULL)?"NULL":(char *)str->data)); sl@0: goto err; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: BIO_printf(bio_err,"%s:invalid type in 'policy' configuration\n",cv->value); sl@0: goto err; sl@0: } sl@0: sl@0: if (push != NULL) sl@0: { sl@0: if (!X509_NAME_add_entry(subject,push, -1, 0)) sl@0: { sl@0: if (push != NULL) sl@0: X509_NAME_ENTRY_free(push); sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: } sl@0: if (j < 0) break; sl@0: } sl@0: } sl@0: sl@0: if (preserve) sl@0: { sl@0: X509_NAME_free(subject); sl@0: /* subject=X509_NAME_dup(X509_REQ_get_subject_name(req)); */ sl@0: subject=X509_NAME_dup(name); sl@0: if (subject == NULL) goto err; sl@0: } sl@0: sl@0: if (verbose) sl@0: BIO_printf(bio_err,"The subject name appears to be ok, checking data base for clashes\n"); sl@0: sl@0: /* Build the correct Subject if no e-mail is wanted in the subject */ sl@0: /* and add it later on because of the method extensions are added (altName) */ sl@0: sl@0: if (email_dn) sl@0: dn_subject = subject; sl@0: else sl@0: { sl@0: X509_NAME_ENTRY *tmpne; sl@0: /* Its best to dup the subject DN and then delete any email sl@0: * addresses because this retains its structure. sl@0: */ sl@0: if (!(dn_subject = X509_NAME_dup(subject))) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: while((i = X509_NAME_get_index_by_NID(dn_subject, sl@0: NID_pkcs9_emailAddress, -1)) >= 0) sl@0: { sl@0: tmpne = X509_NAME_get_entry(dn_subject, i); sl@0: X509_NAME_delete_entry(dn_subject, i); sl@0: X509_NAME_ENTRY_free(tmpne); sl@0: } sl@0: } sl@0: sl@0: if (BN_is_zero(serial)) sl@0: row[DB_serial]=BUF_strdup("00"); sl@0: else sl@0: row[DB_serial]=BN_bn2hex(serial); sl@0: if (row[DB_serial] == NULL) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: sl@0: if (db->attributes.unique_subject) sl@0: { sl@0: rrow=TXT_DB_get_by_index(db->db,DB_name,row); sl@0: if (rrow != NULL) sl@0: { sl@0: BIO_printf(bio_err, sl@0: "ERROR:There is already a certificate for %s\n", sl@0: row[DB_name]); sl@0: } sl@0: } sl@0: if (rrow == NULL) sl@0: { sl@0: rrow=TXT_DB_get_by_index(db->db,DB_serial,row); sl@0: if (rrow != NULL) sl@0: { sl@0: BIO_printf(bio_err,"ERROR:Serial number %s has already been issued,\n", sl@0: row[DB_serial]); sl@0: BIO_printf(bio_err," check the database/serial_file for corruption\n"); sl@0: } sl@0: } sl@0: sl@0: if (rrow != NULL) sl@0: { sl@0: BIO_printf(bio_err, sl@0: "The matching entry has the following details\n"); sl@0: if (rrow[DB_type][0] == 'E') sl@0: p="Expired"; sl@0: else if (rrow[DB_type][0] == 'R') sl@0: p="Revoked"; sl@0: else if (rrow[DB_type][0] == 'V') sl@0: p="Valid"; sl@0: else sl@0: p="\ninvalid type, Data base error\n"; sl@0: BIO_printf(bio_err,"Type :%s\n",p);; sl@0: if (rrow[DB_type][0] == 'R') sl@0: { sl@0: p=rrow[DB_exp_date]; if (p == NULL) p="undef"; sl@0: BIO_printf(bio_err,"Was revoked on:%s\n",p); sl@0: } sl@0: p=rrow[DB_exp_date]; if (p == NULL) p="undef"; sl@0: BIO_printf(bio_err,"Expires on :%s\n",p); sl@0: p=rrow[DB_serial]; if (p == NULL) p="undef"; sl@0: BIO_printf(bio_err,"Serial Number :%s\n",p); sl@0: p=rrow[DB_file]; if (p == NULL) p="undef"; sl@0: BIO_printf(bio_err,"File name :%s\n",p); sl@0: p=rrow[DB_name]; if (p == NULL) p="undef"; sl@0: BIO_printf(bio_err,"Subject Name :%s\n",p); sl@0: ok= -1; /* This is now a 'bad' error. */ sl@0: goto err; sl@0: } sl@0: sl@0: /* We are now totally happy, lets make and sign the certificate */ sl@0: if (verbose) sl@0: BIO_printf(bio_err,"Everything appears to be ok, creating and signing the certificate\n"); sl@0: sl@0: if ((ret=X509_new()) == NULL) goto err; sl@0: ci=ret->cert_info; sl@0: sl@0: #ifdef X509_V3 sl@0: /* Make it an X509 v3 certificate. */ sl@0: if (!X509_set_version(ret,2)) goto err; sl@0: #endif sl@0: sl@0: if (BN_to_ASN1_INTEGER(serial,ci->serialNumber) == NULL) sl@0: goto err; sl@0: if (selfsign) sl@0: { sl@0: if (!X509_set_issuer_name(ret,subject)) sl@0: goto err; sl@0: } sl@0: else sl@0: { sl@0: if (!X509_set_issuer_name(ret,X509_get_subject_name(x509))) sl@0: goto err; sl@0: } sl@0: sl@0: if (strcmp(startdate,"today") == 0) sl@0: X509_gmtime_adj(X509_get_notBefore(ret),0); sl@0: else ASN1_UTCTIME_set_string(X509_get_notBefore(ret),startdate); sl@0: sl@0: if (enddate == NULL) sl@0: X509_gmtime_adj(X509_get_notAfter(ret),(long)60*60*24*days); sl@0: else ASN1_UTCTIME_set_string(X509_get_notAfter(ret),enddate); sl@0: sl@0: if (!X509_set_subject_name(ret,subject)) goto err; sl@0: sl@0: pktmp=X509_REQ_get_pubkey(req); sl@0: i = X509_set_pubkey(ret,pktmp); sl@0: EVP_PKEY_free(pktmp); sl@0: if (!i) goto err; sl@0: sl@0: /* Lets add the extensions, if there are any */ sl@0: if (ext_sect) sl@0: { sl@0: X509V3_CTX ctx; sl@0: if (ci->version == NULL) sl@0: if ((ci->version=ASN1_INTEGER_new()) == NULL) sl@0: goto err; sl@0: ASN1_INTEGER_set(ci->version,2); /* version 3 certificate */ sl@0: sl@0: /* Free the current entries if any, there should not sl@0: * be any I believe */ sl@0: if (ci->extensions != NULL) sl@0: sk_X509_EXTENSION_pop_free(ci->extensions, sl@0: X509_EXTENSION_free); sl@0: sl@0: ci->extensions = NULL; sl@0: sl@0: /* Initialize the context structure */ sl@0: if (selfsign) sl@0: X509V3_set_ctx(&ctx, ret, ret, req, NULL, 0); sl@0: else sl@0: X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0); sl@0: sl@0: if (extconf) sl@0: { sl@0: if (verbose) sl@0: BIO_printf(bio_err, "Extra configuration file found\n"); sl@0: sl@0: /* Use the extconf configuration db LHASH */ sl@0: X509V3_set_nconf(&ctx, extconf); sl@0: sl@0: /* Test the structure (needed?) */ sl@0: /* X509V3_set_ctx_test(&ctx); */ sl@0: sl@0: /* Adds exts contained in the configuration file */ sl@0: if (!X509V3_EXT_add_nconf(extconf, &ctx, ext_sect,ret)) sl@0: { sl@0: BIO_printf(bio_err, sl@0: "ERROR: adding extensions in section %s\n", sl@0: ext_sect); sl@0: ERR_print_errors(bio_err); sl@0: goto err; sl@0: } sl@0: if (verbose) sl@0: BIO_printf(bio_err, "Successfully added extensions from file.\n"); sl@0: } sl@0: else if (ext_sect) sl@0: { sl@0: /* We found extensions to be set from config file */ sl@0: X509V3_set_nconf(&ctx, lconf); sl@0: sl@0: if(!X509V3_EXT_add_nconf(lconf, &ctx, ext_sect, ret)) sl@0: { sl@0: BIO_printf(bio_err, "ERROR: adding extensions in section %s\n", ext_sect); sl@0: ERR_print_errors(bio_err); sl@0: goto err; sl@0: } sl@0: sl@0: if (verbose) sl@0: BIO_printf(bio_err, "Successfully added extensions from config\n"); sl@0: } sl@0: } sl@0: sl@0: /* Copy extensions from request (if any) */ sl@0: sl@0: if (!copy_extensions(ret, req, ext_copy)) sl@0: { sl@0: BIO_printf(bio_err, "ERROR: adding extensions from request\n"); sl@0: ERR_print_errors(bio_err); sl@0: goto err; sl@0: } sl@0: sl@0: /* Set the right value for the noemailDN option */ sl@0: if( email_dn == 0 ) sl@0: { sl@0: if (!X509_set_subject_name(ret,dn_subject)) goto err; sl@0: } sl@0: sl@0: if (!default_op) sl@0: { sl@0: BIO_printf(bio_err, "Certificate Details:\n"); sl@0: /* Never print signature details because signature not present */ sl@0: certopt |= X509_FLAG_NO_SIGDUMP | X509_FLAG_NO_SIGNAME; sl@0: X509_print_ex(bio_err, ret, nameopt, certopt); sl@0: } sl@0: sl@0: BIO_printf(bio_err,"Certificate is to be certified until "); sl@0: ASN1_UTCTIME_print(bio_err,X509_get_notAfter(ret)); sl@0: if (days) BIO_printf(bio_err," (%ld days)",days); sl@0: BIO_printf(bio_err, "\n"); sl@0: sl@0: if (!batch) sl@0: { sl@0: sl@0: BIO_printf(bio_err,"Sign the certificate? [y/n]:"); sl@0: (void)BIO_flush(bio_err); sl@0: buf[0]='\0'; sl@0: fgets(buf,sizeof(buf)-1,stdin); sl@0: if (!((buf[0] == 'y') || (buf[0] == 'Y'))) sl@0: { sl@0: BIO_printf(bio_err,"CERTIFICATE WILL NOT BE CERTIFIED\n"); sl@0: ok=0; sl@0: goto err; sl@0: } sl@0: } sl@0: sl@0: sl@0: #ifndef OPENSSL_NO_DSA sl@0: if (pkey->type == EVP_PKEY_DSA) dgst=EVP_dss1(); sl@0: pktmp=X509_get_pubkey(ret); sl@0: if (EVP_PKEY_missing_parameters(pktmp) && sl@0: !EVP_PKEY_missing_parameters(pkey)) sl@0: EVP_PKEY_copy_parameters(pktmp,pkey); sl@0: EVP_PKEY_free(pktmp); sl@0: #endif sl@0: #ifndef OPENSSL_NO_ECDSA sl@0: if (pkey->type == EVP_PKEY_EC) sl@0: dgst = EVP_ecdsa(); sl@0: pktmp = X509_get_pubkey(ret); sl@0: if (EVP_PKEY_missing_parameters(pktmp) && sl@0: !EVP_PKEY_missing_parameters(pkey)) sl@0: EVP_PKEY_copy_parameters(pktmp, pkey); sl@0: EVP_PKEY_free(pktmp); sl@0: #endif sl@0: sl@0: sl@0: if (!X509_sign(ret,pkey,dgst)) sl@0: goto err; sl@0: sl@0: /* We now just add it to the database */ sl@0: row[DB_type]=(char *)OPENSSL_malloc(2); sl@0: sl@0: tm=X509_get_notAfter(ret); sl@0: row[DB_exp_date]=(char *)OPENSSL_malloc(tm->length+1); sl@0: memcpy(row[DB_exp_date],tm->data,tm->length); sl@0: row[DB_exp_date][tm->length]='\0'; sl@0: sl@0: row[DB_rev_date]=NULL; sl@0: sl@0: /* row[DB_serial] done already */ sl@0: row[DB_file]=(char *)OPENSSL_malloc(8); sl@0: row[DB_name]=X509_NAME_oneline(X509_get_subject_name(ret),NULL,0); sl@0: sl@0: if ((row[DB_type] == NULL) || (row[DB_exp_date] == NULL) || sl@0: (row[DB_file] == NULL) || (row[DB_name] == NULL)) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: BUF_strlcpy(row[DB_file],"unknown",8); sl@0: row[DB_type][0]='V'; sl@0: row[DB_type][1]='\0'; sl@0: sl@0: if ((irow=(char **)OPENSSL_malloc(sizeof(char *)*(DB_NUMBER+1))) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: sl@0: for (i=0; idb,irow)) sl@0: { sl@0: BIO_printf(bio_err,"failed to update database\n"); sl@0: BIO_printf(bio_err,"TXT_DB error number %ld\n",db->db->error); sl@0: goto err; sl@0: } sl@0: ok=1; sl@0: err: sl@0: for (i=0; icert_info->serialNumber); sl@0: BIO_puts(bp,"\n\n"); sl@0: #endif sl@0: if (!notext)X509_print(bp,x); sl@0: PEM_write_bio_X509(bp,x); sl@0: } sl@0: sl@0: static int certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509, sl@0: const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, CA_DB *db, sl@0: BIGNUM *serial, char *subj,unsigned long chtype, int multirdn, int email_dn, char *startdate, char *enddate, sl@0: long days, char *ext_sect, CONF *lconf, int verbose, unsigned long certopt, sl@0: unsigned long nameopt, int default_op, int ext_copy) sl@0: { sl@0: STACK_OF(CONF_VALUE) *sk=NULL; sl@0: LHASH *parms=NULL; sl@0: X509_REQ *req=NULL; sl@0: CONF_VALUE *cv=NULL; sl@0: NETSCAPE_SPKI *spki = NULL; sl@0: X509_REQ_INFO *ri; sl@0: char *type,*buf; sl@0: EVP_PKEY *pktmp=NULL; sl@0: X509_NAME *n=NULL; sl@0: X509_NAME_ENTRY *ne=NULL; sl@0: int ok= -1,i,j; sl@0: long errline; sl@0: int nid; sl@0: sl@0: /* sl@0: * Load input file into a hash table. (This is just an easy sl@0: * way to read and parse the file, then put it into a convenient sl@0: * STACK format). sl@0: */ sl@0: parms=CONF_load(NULL,infile,&errline); sl@0: if (parms == NULL) sl@0: { sl@0: BIO_printf(bio_err,"error on line %ld of %s\n",errline,infile); sl@0: ERR_print_errors(bio_err); sl@0: goto err; sl@0: } sl@0: sl@0: sk=CONF_get_section(parms, "default"); sl@0: if (sk_CONF_VALUE_num(sk) == 0) sl@0: { sl@0: BIO_printf(bio_err, "no name/value pairs found in %s\n", infile); sl@0: CONF_free(parms); sl@0: goto err; sl@0: } sl@0: sl@0: /* sl@0: * Now create a dummy X509 request structure. We don't actually sl@0: * have an X509 request, but we have many of the components sl@0: * (a public key, various DN components). The idea is that we sl@0: * put these components into the right X509 request structure sl@0: * and we can use the same code as if you had a real X509 request. sl@0: */ sl@0: req=X509_REQ_new(); sl@0: if (req == NULL) sl@0: { sl@0: ERR_print_errors(bio_err); sl@0: goto err; sl@0: } sl@0: sl@0: /* sl@0: * Build up the subject name set. sl@0: */ sl@0: ri=req->req_info; sl@0: n = ri->subject; sl@0: sl@0: for (i = 0; ; i++) sl@0: { sl@0: if (sk_CONF_VALUE_num(sk) <= i) break; sl@0: sl@0: cv=sk_CONF_VALUE_value(sk,i); sl@0: type=cv->name; sl@0: /* Skip past any leading X. X: X, etc to allow for sl@0: * multiple instances sl@0: */ sl@0: for (buf = cv->name; *buf ; buf++) sl@0: if ((*buf == ':') || (*buf == ',') || (*buf == '.')) sl@0: { sl@0: buf++; sl@0: if (*buf) type = buf; sl@0: break; sl@0: } sl@0: sl@0: buf=cv->value; sl@0: if ((nid=OBJ_txt2nid(type)) == NID_undef) sl@0: { sl@0: if (strcmp(type, "SPKAC") == 0) sl@0: { sl@0: spki = NETSCAPE_SPKI_b64_decode(cv->value, -1); sl@0: if (spki == NULL) sl@0: { sl@0: BIO_printf(bio_err,"unable to load Netscape SPKAC structure\n"); sl@0: ERR_print_errors(bio_err); sl@0: goto err; sl@0: } sl@0: } sl@0: continue; sl@0: } sl@0: sl@0: /* sl@0: if ((nid == NID_pkcs9_emailAddress) && (email_dn == 0)) sl@0: continue; sl@0: */ sl@0: sl@0: j=ASN1_PRINTABLE_type((unsigned char *)buf,-1); sl@0: if (fix_data(nid, &j) == 0) sl@0: { sl@0: BIO_printf(bio_err, sl@0: "invalid characters in string %s\n",buf); sl@0: goto err; sl@0: } sl@0: sl@0: if ((ne=X509_NAME_ENTRY_create_by_NID(&ne,nid,j, sl@0: (unsigned char *)buf, sl@0: strlen(buf))) == NULL) sl@0: goto err; sl@0: sl@0: if (!X509_NAME_add_entry(n,ne,-1, 0)) goto err; sl@0: } sl@0: if (spki == NULL) sl@0: { sl@0: BIO_printf(bio_err,"Netscape SPKAC structure not found in %s\n", sl@0: infile); sl@0: goto err; sl@0: } sl@0: sl@0: /* sl@0: * Now extract the key from the SPKI structure. sl@0: */ sl@0: sl@0: BIO_printf(bio_err,"Check that the SPKAC request matches the signature\n"); sl@0: sl@0: if ((pktmp=NETSCAPE_SPKI_get_pubkey(spki)) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"error unpacking SPKAC public key\n"); sl@0: goto err; sl@0: } sl@0: sl@0: j = NETSCAPE_SPKI_verify(spki, pktmp); sl@0: if (j <= 0) sl@0: { sl@0: BIO_printf(bio_err,"signature verification failed on SPKAC public key\n"); sl@0: goto err; sl@0: } sl@0: BIO_printf(bio_err,"Signature ok\n"); sl@0: sl@0: X509_REQ_set_pubkey(req,pktmp); sl@0: EVP_PKEY_free(pktmp); sl@0: ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,chtype,multirdn,email_dn,startdate,enddate, sl@0: days,1,verbose,req,ext_sect,lconf, certopt, nameopt, default_op, sl@0: ext_copy, 0); sl@0: err: sl@0: if (req != NULL) X509_REQ_free(req); sl@0: if (parms != NULL) CONF_free(parms); sl@0: if (spki != NULL) NETSCAPE_SPKI_free(spki); sl@0: if (ne != NULL) X509_NAME_ENTRY_free(ne); sl@0: sl@0: return(ok); sl@0: } sl@0: sl@0: static int fix_data(int nid, int *type) sl@0: { sl@0: if (nid == NID_pkcs9_emailAddress) sl@0: *type=V_ASN1_IA5STRING; sl@0: if ((nid == NID_commonName) && (*type == V_ASN1_IA5STRING)) sl@0: *type=V_ASN1_T61STRING; sl@0: if ((nid == NID_pkcs9_challengePassword) && (*type == V_ASN1_IA5STRING)) sl@0: *type=V_ASN1_T61STRING; sl@0: if ((nid == NID_pkcs9_unstructuredName) && (*type == V_ASN1_T61STRING)) sl@0: return(0); sl@0: if (nid == NID_pkcs9_unstructuredName) sl@0: *type=V_ASN1_IA5STRING; sl@0: return(1); sl@0: } sl@0: sl@0: static int check_time_format(char *str) sl@0: { sl@0: ASN1_UTCTIME tm; sl@0: sl@0: tm.data=(unsigned char *)str; sl@0: tm.length=strlen(str); sl@0: tm.type=V_ASN1_UTCTIME; sl@0: return(ASN1_UTCTIME_check(&tm)); sl@0: } sl@0: sl@0: static int do_revoke(X509 *x509, CA_DB *db, int type, char *value) sl@0: { sl@0: ASN1_UTCTIME *tm=NULL; sl@0: char *row[DB_NUMBER],**rrow,**irow; sl@0: char *rev_str = NULL; sl@0: BIGNUM *bn = NULL; sl@0: int ok=-1,i; sl@0: sl@0: for (i=0; idb,DB_serial,row); sl@0: if (rrow == NULL) sl@0: { sl@0: BIO_printf(bio_err,"Adding Entry with serial number %s to DB for %s\n", row[DB_serial], row[DB_name]); sl@0: sl@0: /* We now just add it to the database */ sl@0: row[DB_type]=(char *)OPENSSL_malloc(2); sl@0: sl@0: tm=X509_get_notAfter(x509); sl@0: row[DB_exp_date]=(char *)OPENSSL_malloc(tm->length+1); sl@0: memcpy(row[DB_exp_date],tm->data,tm->length); sl@0: row[DB_exp_date][tm->length]='\0'; sl@0: sl@0: row[DB_rev_date]=NULL; sl@0: sl@0: /* row[DB_serial] done already */ sl@0: row[DB_file]=(char *)OPENSSL_malloc(8); sl@0: sl@0: /* row[DB_name] done already */ sl@0: sl@0: if ((row[DB_type] == NULL) || (row[DB_exp_date] == NULL) || sl@0: (row[DB_file] == NULL)) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: BUF_strlcpy(row[DB_file],"unknown",8); sl@0: row[DB_type][0]='V'; sl@0: row[DB_type][1]='\0'; sl@0: sl@0: if ((irow=(char **)OPENSSL_malloc(sizeof(char *)*(DB_NUMBER+1))) == NULL) sl@0: { sl@0: BIO_printf(bio_err,"Memory allocation failure\n"); sl@0: goto err; sl@0: } sl@0: sl@0: for (i=0; idb,irow)) sl@0: { sl@0: BIO_printf(bio_err,"failed to update database\n"); sl@0: BIO_printf(bio_err,"TXT_DB error number %ld\n",db->db->error); sl@0: goto err; sl@0: } sl@0: sl@0: /* Revoke Certificate */ sl@0: ok = do_revoke(x509,db, type, value); sl@0: sl@0: goto err; sl@0: sl@0: } sl@0: else if (index_name_cmp((const char **)row,(const char **)rrow)) sl@0: { sl@0: BIO_printf(bio_err,"ERROR:name does not match %s\n", sl@0: row[DB_name]); sl@0: goto err; sl@0: } sl@0: else if (rrow[DB_type][0]=='R') sl@0: { sl@0: BIO_printf(bio_err,"ERROR:Already revoked, serial number %s\n", sl@0: row[DB_serial]); sl@0: goto err; sl@0: } sl@0: else sl@0: { sl@0: BIO_printf(bio_err,"Revoking Certificate %s.\n", rrow[DB_serial]); sl@0: rev_str = make_revocation_str(type, value); sl@0: if (!rev_str) sl@0: { sl@0: BIO_printf(bio_err, "Error in revocation arguments\n"); sl@0: goto err; sl@0: } sl@0: rrow[DB_type][0]='R'; sl@0: rrow[DB_type][1]='\0'; sl@0: rrow[DB_rev_date] = rev_str; sl@0: } sl@0: ok=1; sl@0: err: sl@0: for (i=0; idb,DB_serial,row); sl@0: if (rrow == NULL) sl@0: { sl@0: BIO_printf(bio_err,"Serial %s not present in db.\n", sl@0: row[DB_serial]); sl@0: ok=-1; sl@0: goto err; sl@0: } sl@0: else if (rrow[DB_type][0]=='V') sl@0: { sl@0: BIO_printf(bio_err,"%s=Valid (%c)\n", sl@0: row[DB_serial], rrow[DB_type][0]); sl@0: goto err; sl@0: } sl@0: else if (rrow[DB_type][0]=='R') sl@0: { sl@0: BIO_printf(bio_err,"%s=Revoked (%c)\n", sl@0: row[DB_serial], rrow[DB_type][0]); sl@0: goto err; sl@0: } sl@0: else if (rrow[DB_type][0]=='E') sl@0: { sl@0: BIO_printf(bio_err,"%s=Expired (%c)\n", sl@0: row[DB_serial], rrow[DB_type][0]); sl@0: goto err; sl@0: } sl@0: else if (rrow[DB_type][0]=='S') sl@0: { sl@0: BIO_printf(bio_err,"%s=Suspended (%c)\n", sl@0: row[DB_serial], rrow[DB_type][0]); sl@0: goto err; sl@0: } sl@0: else sl@0: { sl@0: BIO_printf(bio_err,"%s=Unknown (%c).\n", sl@0: row[DB_serial], rrow[DB_type][0]); sl@0: ok=-1; sl@0: } sl@0: err: sl@0: for (i=0; i= 2000 */ sl@0: char **rrow, *a_tm_s; sl@0: sl@0: a_tm = ASN1_UTCTIME_new(); sl@0: sl@0: /* get actual time and make a string */ sl@0: a_tm = X509_gmtime_adj(a_tm, 0); sl@0: a_tm_s = (char *) OPENSSL_malloc(a_tm->length+1); sl@0: if (a_tm_s == NULL) sl@0: { sl@0: cnt = -1; sl@0: goto err; sl@0: } sl@0: sl@0: memcpy(a_tm_s, a_tm->data, a_tm->length); sl@0: a_tm_s[a_tm->length] = '\0'; sl@0: sl@0: if (strncmp(a_tm_s, "49", 2) <= 0) sl@0: a_y2k = 1; sl@0: else sl@0: a_y2k = 0; sl@0: sl@0: for (i = 0; i < sk_num(db->db->data); i++) sl@0: { sl@0: rrow = (char **) sk_value(db->db->data, i); sl@0: sl@0: if (rrow[DB_type][0] == 'V') sl@0: { sl@0: /* ignore entries that are not valid */ sl@0: if (strncmp(rrow[DB_exp_date], "49", 2) <= 0) sl@0: db_y2k = 1; sl@0: else sl@0: db_y2k = 0; sl@0: sl@0: if (db_y2k == a_y2k) sl@0: { sl@0: /* all on the same y2k side */ sl@0: if (strcmp(rrow[DB_exp_date], a_tm_s) <= 0) sl@0: { sl@0: rrow[DB_type][0] = 'E'; sl@0: rrow[DB_type][1] = '\0'; sl@0: cnt++; sl@0: sl@0: BIO_printf(bio_err, "%s=Expired\n", sl@0: rrow[DB_serial]); sl@0: } sl@0: } sl@0: else if (db_y2k < a_y2k) sl@0: { sl@0: rrow[DB_type][0] = 'E'; sl@0: rrow[DB_type][1] = '\0'; sl@0: cnt++; sl@0: sl@0: BIO_printf(bio_err, "%s=Expired\n", sl@0: rrow[DB_serial]); sl@0: } sl@0: sl@0: } sl@0: } sl@0: sl@0: err: sl@0: sl@0: ASN1_UTCTIME_free(a_tm); sl@0: OPENSSL_free(a_tm_s); sl@0: sl@0: return (cnt); sl@0: } sl@0: sl@0: static const char *crl_reasons[] = { sl@0: /* CRL reason strings */ sl@0: "unspecified", sl@0: "keyCompromise", sl@0: "CACompromise", sl@0: "affiliationChanged", sl@0: "superseded", sl@0: "cessationOfOperation", sl@0: "certificateHold", sl@0: "removeFromCRL", sl@0: /* Additional pseudo reasons */ sl@0: "holdInstruction", sl@0: "keyTime", sl@0: "CAkeyTime" sl@0: }; sl@0: sl@0: #define NUM_REASONS (sizeof(crl_reasons) / sizeof(char *)) sl@0: sl@0: /* Given revocation information convert to a DB string. sl@0: * The format of the string is: sl@0: * revtime[,reason,extra]. Where 'revtime' is the sl@0: * revocation time (the current time). 'reason' is the sl@0: * optional CRL reason and 'extra' is any additional sl@0: * argument sl@0: */ sl@0: sl@0: char *make_revocation_str(int rev_type, char *rev_arg) sl@0: { sl@0: char *other = NULL, *str; sl@0: const char *reason = NULL; sl@0: ASN1_OBJECT *otmp; sl@0: ASN1_UTCTIME *revtm = NULL; sl@0: int i; sl@0: switch (rev_type) sl@0: { sl@0: case REV_NONE: sl@0: break; sl@0: sl@0: case REV_CRL_REASON: sl@0: for (i = 0; i < 8; i++) sl@0: { sl@0: if (!strcasecmp(rev_arg, crl_reasons[i])) sl@0: { sl@0: reason = crl_reasons[i]; sl@0: break; sl@0: } sl@0: } sl@0: if (reason == NULL) sl@0: { sl@0: BIO_printf(bio_err, "Unknown CRL reason %s\n", rev_arg); sl@0: return NULL; sl@0: } sl@0: break; sl@0: sl@0: case REV_HOLD: sl@0: /* Argument is an OID */ sl@0: sl@0: otmp = OBJ_txt2obj(rev_arg, 0); sl@0: ASN1_OBJECT_free(otmp); sl@0: sl@0: if (otmp == NULL) sl@0: { sl@0: BIO_printf(bio_err, "Invalid object identifier %s\n", rev_arg); sl@0: return NULL; sl@0: } sl@0: sl@0: reason = "holdInstruction"; sl@0: other = rev_arg; sl@0: break; sl@0: sl@0: case REV_KEY_COMPROMISE: sl@0: case REV_CA_COMPROMISE: sl@0: sl@0: /* Argument is the key compromise time */ sl@0: if (!ASN1_GENERALIZEDTIME_set_string(NULL, rev_arg)) sl@0: { sl@0: BIO_printf(bio_err, "Invalid time format %s. Need YYYYMMDDHHMMSSZ\n", rev_arg); sl@0: return NULL; sl@0: } sl@0: other = rev_arg; sl@0: if (rev_type == REV_KEY_COMPROMISE) sl@0: reason = "keyTime"; sl@0: else sl@0: reason = "CAkeyTime"; sl@0: sl@0: break; sl@0: sl@0: } sl@0: sl@0: revtm = X509_gmtime_adj(NULL, 0); sl@0: sl@0: i = revtm->length + 1; sl@0: sl@0: if (reason) i += strlen(reason) + 1; sl@0: if (other) i += strlen(other) + 1; sl@0: sl@0: str = OPENSSL_malloc(i); sl@0: sl@0: if (!str) return NULL; sl@0: sl@0: BUF_strlcpy(str, (char *)revtm->data, i); sl@0: if (reason) sl@0: { sl@0: BUF_strlcat(str, ",", i); sl@0: BUF_strlcat(str, reason, i); sl@0: } sl@0: if (other) sl@0: { sl@0: BUF_strlcat(str, ",", i); sl@0: BUF_strlcat(str, other, i); sl@0: } sl@0: ASN1_UTCTIME_free(revtm); sl@0: return str; sl@0: } sl@0: sl@0: /* Convert revocation field to X509_REVOKED entry sl@0: * return code: sl@0: * 0 error sl@0: * 1 OK sl@0: * 2 OK and some extensions added (i.e. V2 CRL) sl@0: */ sl@0: sl@0: sl@0: int make_revoked(X509_REVOKED *rev, const char *str) sl@0: { sl@0: char *tmp = NULL; sl@0: int reason_code = -1; sl@0: int i, ret = 0; sl@0: ASN1_OBJECT *hold = NULL; sl@0: ASN1_GENERALIZEDTIME *comp_time = NULL; sl@0: ASN1_ENUMERATED *rtmp = NULL; sl@0: sl@0: ASN1_TIME *revDate = NULL; sl@0: sl@0: i = unpack_revinfo(&revDate, &reason_code, &hold, &comp_time, str); sl@0: sl@0: if (i == 0) sl@0: goto err; sl@0: sl@0: if (rev && !X509_REVOKED_set_revocationDate(rev, revDate)) sl@0: goto err; sl@0: sl@0: if (rev && (reason_code != OCSP_REVOKED_STATUS_NOSTATUS)) sl@0: { sl@0: rtmp = ASN1_ENUMERATED_new(); sl@0: if (!rtmp || !ASN1_ENUMERATED_set(rtmp, reason_code)) sl@0: goto err; sl@0: if (!X509_REVOKED_add1_ext_i2d(rev, NID_crl_reason, rtmp, 0, 0)) sl@0: goto err; sl@0: } sl@0: sl@0: if (rev && comp_time) sl@0: { sl@0: if (!X509_REVOKED_add1_ext_i2d(rev, NID_invalidity_date, comp_time, 0, 0)) sl@0: goto err; sl@0: } sl@0: if (rev && hold) sl@0: { sl@0: if (!X509_REVOKED_add1_ext_i2d(rev, NID_hold_instruction_code, hold, 0, 0)) sl@0: goto err; sl@0: } sl@0: sl@0: if (reason_code != OCSP_REVOKED_STATUS_NOSTATUS) sl@0: ret = 2; sl@0: else ret = 1; sl@0: sl@0: err: sl@0: sl@0: if (tmp) OPENSSL_free(tmp); sl@0: ASN1_OBJECT_free(hold); sl@0: ASN1_GENERALIZEDTIME_free(comp_time); sl@0: ASN1_ENUMERATED_free(rtmp); sl@0: ASN1_TIME_free(revDate); sl@0: sl@0: return ret; sl@0: } sl@0: sl@0: int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str) sl@0: { sl@0: char buf[25],*pbuf, *p; sl@0: int j; sl@0: j=i2a_ASN1_OBJECT(bp,obj); sl@0: pbuf=buf; sl@0: for (j=22-j; j>0; j--) sl@0: *(pbuf++)=' '; sl@0: *(pbuf++)=':'; sl@0: *(pbuf++)='\0'; sl@0: BIO_puts(bp,buf); sl@0: sl@0: if (str->type == V_ASN1_PRINTABLESTRING) sl@0: BIO_printf(bp,"PRINTABLE:'"); sl@0: else if (str->type == V_ASN1_T61STRING) sl@0: BIO_printf(bp,"T61STRING:'"); sl@0: else if (str->type == V_ASN1_IA5STRING) sl@0: BIO_printf(bp,"IA5STRING:'"); sl@0: else if (str->type == V_ASN1_UNIVERSALSTRING) sl@0: BIO_printf(bp,"UNIVERSALSTRING:'"); sl@0: else sl@0: BIO_printf(bp,"ASN.1 %2d:'",str->type); sl@0: sl@0: p=(char *)str->data; sl@0: for (j=str->length; j>0; j--) sl@0: { sl@0: if ((*p >= ' ') && (*p <= '~')) sl@0: BIO_printf(bp,"%c",*p); sl@0: else if (*p & 0x80) sl@0: BIO_printf(bp,"\\0x%02X",*p); sl@0: else if ((unsigned char)*p == 0xf7) sl@0: BIO_printf(bp,"^?"); sl@0: else BIO_printf(bp,"^%c",*p+'@'); sl@0: p++; sl@0: } sl@0: BIO_printf(bp,"'\n"); sl@0: return 1; sl@0: } sl@0: sl@0: int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, ASN1_GENERALIZEDTIME **pinvtm, const char *str) sl@0: { sl@0: char *tmp = NULL; sl@0: char *rtime_str, *reason_str = NULL, *arg_str = NULL, *p; sl@0: int reason_code = -1; sl@0: int ret = 0; sl@0: unsigned int i; sl@0: ASN1_OBJECT *hold = NULL; sl@0: ASN1_GENERALIZEDTIME *comp_time = NULL; sl@0: tmp = BUF_strdup(str); sl@0: sl@0: p = strchr(tmp, ','); sl@0: sl@0: rtime_str = tmp; sl@0: sl@0: if (p) sl@0: { sl@0: *p = '\0'; sl@0: p++; sl@0: reason_str = p; sl@0: p = strchr(p, ','); sl@0: if (p) sl@0: { sl@0: *p = '\0'; sl@0: arg_str = p + 1; sl@0: } sl@0: } sl@0: sl@0: if (prevtm) sl@0: { sl@0: *prevtm = ASN1_UTCTIME_new(); sl@0: if (!ASN1_UTCTIME_set_string(*prevtm, rtime_str)) sl@0: { sl@0: BIO_printf(bio_err, "invalid revocation date %s\n", rtime_str); sl@0: goto err; sl@0: } sl@0: } sl@0: if (reason_str) sl@0: { sl@0: for (i = 0; i < NUM_REASONS; i++) sl@0: { sl@0: if(!strcasecmp(reason_str, crl_reasons[i])) sl@0: { sl@0: reason_code = i; sl@0: break; sl@0: } sl@0: } sl@0: if (reason_code == OCSP_REVOKED_STATUS_NOSTATUS) sl@0: { sl@0: BIO_printf(bio_err, "invalid reason code %s\n", reason_str); sl@0: goto err; sl@0: } sl@0: sl@0: if (reason_code == 7) sl@0: reason_code = OCSP_REVOKED_STATUS_REMOVEFROMCRL; sl@0: else if (reason_code == 8) /* Hold instruction */ sl@0: { sl@0: if (!arg_str) sl@0: { sl@0: BIO_printf(bio_err, "missing hold instruction\n"); sl@0: goto err; sl@0: } sl@0: reason_code = OCSP_REVOKED_STATUS_CERTIFICATEHOLD; sl@0: hold = OBJ_txt2obj(arg_str, 0); sl@0: sl@0: if (!hold) sl@0: { sl@0: BIO_printf(bio_err, "invalid object identifier %s\n", arg_str); sl@0: goto err; sl@0: } sl@0: if (phold) *phold = hold; sl@0: } sl@0: else if ((reason_code == 9) || (reason_code == 10)) sl@0: { sl@0: if (!arg_str) sl@0: { sl@0: BIO_printf(bio_err, "missing compromised time\n"); sl@0: goto err; sl@0: } sl@0: comp_time = ASN1_GENERALIZEDTIME_new(); sl@0: if (!ASN1_GENERALIZEDTIME_set_string(comp_time, arg_str)) sl@0: { sl@0: BIO_printf(bio_err, "invalid compromised time %s\n", arg_str); sl@0: goto err; sl@0: } sl@0: if (reason_code == 9) sl@0: reason_code = OCSP_REVOKED_STATUS_KEYCOMPROMISE; sl@0: else sl@0: reason_code = OCSP_REVOKED_STATUS_CACOMPROMISE; sl@0: } sl@0: } sl@0: sl@0: if (preason) *preason = reason_code; sl@0: if (pinvtm) *pinvtm = comp_time; sl@0: else ASN1_GENERALIZEDTIME_free(comp_time); sl@0: sl@0: ret = 1; sl@0: sl@0: err: sl@0: sl@0: if (tmp) OPENSSL_free(tmp); sl@0: if (!phold) ASN1_OBJECT_free(hold); sl@0: if (!pinvtm) ASN1_GENERALIZEDTIME_free(comp_time); sl@0: sl@0: return ret; sl@0: }