2000-01-10 06:22:05 +00:00
/* apps/ca.c */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved .
*
* This package is an SSL implementation written
* by Eric Young ( eay @ cryptsoft . com ) .
* The implementation was written so as to conform with Netscapes SSL .
*
* This library is free for commercial and non - commercial use as long as
* the following conditions are aheared to . The following conditions
* apply to all code found in this distribution , be it the RC4 , RSA ,
* lhash , DES , etc . , code ; not just the SSL code . The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson ( tjh @ cryptsoft . com ) .
*
* Copyright remains Eric Young ' s , and as such any Copyright notices in
* the code are not to be removed .
* If this package is used in a product , Eric Young should be given attribution
* as the author of the parts of the library used .
* This can be in the form of a textual message at program startup or
* in documentation ( online or textual ) provided with the package .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement :
* " This product includes cryptographic software written by
* Eric Young ( eay @ cryptsoft . com ) "
* The word ' cryptographic ' can be left out if the rouines from the library
* being used are not cryptographic related : - ) .
* 4. If you include any Windows specific code ( or a derivative thereof ) from
* the apps directory ( application code ) you must include an acknowledgement :
* " This product includes software written by Tim Hudson (tjh@cryptsoft.com) "
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed . i . e . this code cannot simply be
* copied and put under another distribution licence
* [ including the GNU Public Licence . ]
*/
/* The PPKI stuff has been donated by Jeff Barber <jeffb@issl.atl.hp.com> */
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/types.h>
# include <sys/stat.h>
# include "apps.h"
# include <openssl/conf.h>
# include <openssl/bio.h>
# include <openssl/err.h>
# include <openssl/bn.h>
# include <openssl/txt_db.h>
# include <openssl/evp.h>
# include <openssl/x509.h>
# include <openssl/x509v3.h>
# include <openssl/objects.h>
# include <openssl/pem.h>
# ifndef W_OK
# ifdef VMS
# if defined(__DECC)
# include <unistd.h>
# else
# include <unixlib.h>
# endif
# else
# include <sys / file.h>
# endif
# endif
# ifndef W_OK
# define F_OK 0
# define X_OK 1
# define W_OK 2
# define R_OK 4
# endif
# undef PROG
# define PROG ca_main
# define BASE_SECTION "ca"
# define CONFIG_FILE "openssl.cnf"
# define ENV_DEFAULT_CA "default_ca"
# define ENV_DIR "dir"
# define ENV_CERTS "certs"
# define ENV_CRL_DIR "crl_dir"
# define ENV_CA_DB "CA_DB"
# define ENV_NEW_CERTS_DIR "new_certs_dir"
# define ENV_CERTIFICATE "certificate"
# define ENV_SERIAL "serial"
# define ENV_CRL "crl"
# define ENV_PRIVATE_KEY "private_key"
# define ENV_RANDFILE "RANDFILE"
# define ENV_DEFAULT_DAYS "default_days"
# define ENV_DEFAULT_STARTDATE "default_startdate"
# define ENV_DEFAULT_ENDDATE "default_enddate"
# define ENV_DEFAULT_CRL_DAYS "default_crl_days"
# define ENV_DEFAULT_CRL_HOURS "default_crl_hours"
# define ENV_DEFAULT_MD "default_md"
# define ENV_PRESERVE "preserve"
# define ENV_POLICY "policy"
# define ENV_EXTENSIONS "x509_extensions"
# define ENV_CRLEXT "crl_extensions"
# define ENV_MSIE_HACK "msie_hack"
# define ENV_DATABASE "database"
# define DB_type 0
# define DB_exp_date 1
# define DB_rev_date 2
# define DB_serial 3 /* index - unique */
# define DB_file 4
# define DB_name 5 /* index - unique for active */
# define DB_NUMBER 6
# define DB_TYPE_REV 'R'
# define DB_TYPE_EXP 'E'
# define DB_TYPE_VAL 'V'
static char * ca_usage [ ] = {
" usage: ca args \n " ,
" \n " ,
" -verbose - Talk alot while doing things \n " ,
" -config file - A config file \n " ,
" -name arg - The particular CA definition to use \n " ,
" -gencrl - Generate a new CRL \n " ,
" -crldays days - Days is when the next CRL is due \n " ,
" -crlhours hours - Hours is when the next CRL is due \n " ,
2000-04-13 06:33:22 +00:00
" -startdate YYMMDDHHMMSSZ - certificate validity notBefore \n " ,
" -enddate YYMMDDHHMMSSZ - certificate validity notAfter (overrides -days) \n " ,
2000-01-10 06:22:05 +00:00
" -days arg - number of days to certify the certificate for \n " ,
" -md arg - md to use, one of md2, md5, sha or sha1 \n " ,
" -policy arg - The CA 'policy' to support \n " ,
" -keyfile arg - PEM private key file \n " ,
" -key arg - key to decode the private key if it is encrypted \n " ,
" -cert file - The CA certificate \n " ,
" -in file - The input PEM encoded certificate request(s) \n " ,
" -out file - Where to put the output file(s) \n " ,
" -outdir dir - Where to put output certificates \n " ,
" -infiles .... - The last argument, requests to process \n " ,
" -spkac file - File contains DN and signed public key and challenge \n " ,
" -ss_cert file - File contains a self signed cert to sign \n " ,
" -preserveDN - Don't re-order the DN \n " ,
" -batch - Don't ask questions \n " ,
" -msie_hack - msie modifications to handle all those universal strings \n " ,
" -revoke file - Revoke a certificate (given in file) \n " ,
2000-04-13 06:33:22 +00:00
" -extensions .. - Extension section (override value in config file) \n " ,
" -crlexts .. - CRL extension section (override value in config file) \n " ,
2000-01-10 06:22:05 +00:00
NULL
} ;
# ifdef EFENCE
extern int EF_PROTECT_FREE ;
extern int EF_PROTECT_BELOW ;
extern int EF_ALIGNMENT ;
# endif
static void lookup_fail ( char * name , char * tag ) ;
static unsigned long index_serial_hash ( char * * a ) ;
static int index_serial_cmp ( char * * a , char * * b ) ;
static unsigned long index_name_hash ( char * * a ) ;
static int index_name_qual ( char * * a ) ;
static int index_name_cmp ( char * * a , char * * b ) ;
static BIGNUM * load_serial ( char * serialfile ) ;
static int save_serial ( char * serialfile , BIGNUM * serial ) ;
static int certify ( X509 * * xret , char * infile , EVP_PKEY * pkey , X509 * x509 ,
const EVP_MD * dgst , STACK_OF ( CONF_VALUE ) * policy , TXT_DB * db ,
BIGNUM * serial , char * startdate , char * enddate , int days ,
int batch , char * ext_sect , LHASH * conf , int verbose ) ;
static int certify_cert ( X509 * * xret , char * infile , EVP_PKEY * pkey , X509 * x509 ,
const EVP_MD * dgst , STACK_OF ( CONF_VALUE ) * policy ,
TXT_DB * db , BIGNUM * serial , char * startdate ,
char * enddate , int days , int batch , char * ext_sect ,
LHASH * conf , int verbose ) ;
static int certify_spkac ( X509 * * xret , char * infile , EVP_PKEY * pkey , X509 * x509 ,
const EVP_MD * dgst , STACK_OF ( CONF_VALUE ) * policy ,
TXT_DB * db , BIGNUM * serial , char * startdate ,
char * enddate , int days , char * ext_sect , LHASH * conf ,
int verbose ) ;
static int fix_data ( int nid , int * type ) ;
2000-04-13 06:33:22 +00:00
static void write_new_certificate ( BIO * bp , X509 * x , int output_der , int notext ) ;
2000-01-10 06:22:05 +00:00
static int do_body ( X509 * * xret , EVP_PKEY * pkey , X509 * x509 , const EVP_MD * dgst ,
STACK_OF ( CONF_VALUE ) * policy , TXT_DB * db , BIGNUM * serial ,
char * startdate , char * enddate , int days , int batch , int verbose ,
X509_REQ * req , char * ext_sect , LHASH * conf ) ;
static int do_revoke ( X509 * x509 , TXT_DB * db ) ;
static int check_time_format ( char * str ) ;
2000-04-13 06:33:22 +00:00
static LHASH * conf = NULL ;
2000-01-10 06:22:05 +00:00
static char * section = NULL ;
static int preserve = 0 ;
static int msie_hack = 0 ;
2000-04-13 06:33:22 +00:00
int MAIN ( int , char * * ) ;
2000-01-10 06:22:05 +00:00
int MAIN ( int argc , char * * argv )
{
2000-11-13 01:03:58 +00:00
char * key = NULL , * passargin = NULL ;
2000-01-10 06:22:05 +00:00
int total = 0 ;
int total_done = 0 ;
int badops = 0 ;
int ret = 1 ;
int req = 0 ;
int verbose = 0 ;
int gencrl = 0 ;
int dorevoke = 0 ;
long crldays = 0 ;
long crlhours = 0 ;
long errorline = - 1 ;
char * configfile = NULL ;
char * md = NULL ;
char * policy = NULL ;
char * keyfile = NULL ;
char * certfile = NULL ;
char * infile = NULL ;
char * spkac_file = NULL ;
char * ss_cert_file = NULL ;
EVP_PKEY * pkey = NULL ;
int output_der = 0 ;
char * outfile = NULL ;
char * outdir = NULL ;
char * serialfile = NULL ;
char * extensions = NULL ;
char * crl_ext = NULL ;
BIGNUM * serial = NULL ;
char * startdate = NULL ;
char * enddate = NULL ;
int days = 0 ;
int batch = 0 ;
2000-04-13 06:33:22 +00:00
int notext = 0 ;
2000-01-10 06:22:05 +00:00
X509 * x509 = NULL ;
X509 * x = NULL ;
BIO * in = NULL , * out = NULL , * Sout = NULL , * Cout = NULL ;
char * dbfile = NULL ;
TXT_DB * db = NULL ;
X509_CRL * crl = NULL ;
X509_CRL_INFO * ci = NULL ;
X509_REVOKED * r = NULL ;
char * * pp , * p , * f ;
int i , j ;
long l ;
const EVP_MD * dgst = NULL ;
STACK_OF ( CONF_VALUE ) * attribs = NULL ;
2000-11-13 01:03:58 +00:00
STACK_OF ( X509 ) * cert_sk = NULL ;
2000-01-10 06:22:05 +00:00
BIO * hex = NULL ;
# undef BSIZE
# define BSIZE 256
MS_STATIC char buf [ 3 ] [ BSIZE ] ;
2000-04-13 06:33:22 +00:00
char * randfile = NULL ;
2000-01-10 06:22:05 +00:00
# ifdef EFENCE
EF_PROTECT_FREE = 1 ;
EF_PROTECT_BELOW = 1 ;
EF_ALIGNMENT = 0 ;
# endif
apps_startup ( ) ;
2000-04-13 06:33:22 +00:00
conf = NULL ;
key = NULL ;
section = NULL ;
2000-01-10 06:22:05 +00:00
preserve = 0 ;
2000-04-13 06:33:22 +00:00
msie_hack = 0 ;
2000-01-10 06:22:05 +00:00
if ( bio_err = = NULL )
if ( ( bio_err = BIO_new ( BIO_s_file ( ) ) ) ! = NULL )
BIO_set_fp ( bio_err , stderr , BIO_NOCLOSE | BIO_FP_TEXT ) ;
argc - - ;
argv + + ;
while ( argc > = 1 )
{
if ( strcmp ( * argv , " -verbose " ) = = 0 )
verbose = 1 ;
else if ( strcmp ( * argv , " -config " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
configfile = * ( + + argv ) ;
}
else if ( strcmp ( * argv , " -name " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
section = * ( + + argv ) ;
}
else if ( strcmp ( * argv , " -startdate " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
startdate = * ( + + argv ) ;
}
else if ( strcmp ( * argv , " -enddate " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
enddate = * ( + + argv ) ;
}
else if ( strcmp ( * argv , " -days " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
days = atoi ( * ( + + argv ) ) ;
}
else if ( strcmp ( * argv , " -md " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
md = * ( + + argv ) ;
}
else if ( strcmp ( * argv , " -policy " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
policy = * ( + + argv ) ;
}
else if ( strcmp ( * argv , " -keyfile " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
keyfile = * ( + + argv ) ;
}
2000-11-13 01:03:58 +00:00
else if ( strcmp ( * argv , " -passin " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
passargin = * ( + + argv ) ;
}
2000-01-10 06:22:05 +00:00
else if ( strcmp ( * argv , " -key " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
key = * ( + + argv ) ;
}
else if ( strcmp ( * argv , " -cert " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
certfile = * ( + + argv ) ;
}
else if ( strcmp ( * argv , " -in " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
infile = * ( + + argv ) ;
req = 1 ;
}
else if ( strcmp ( * argv , " -out " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
outfile = * ( + + argv ) ;
}
else if ( strcmp ( * argv , " -outdir " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
outdir = * ( + + argv ) ;
}
2000-04-13 06:33:22 +00:00
else if ( strcmp ( * argv , " -notext " ) = = 0 )
notext = 1 ;
2000-01-10 06:22:05 +00:00
else if ( strcmp ( * argv , " -batch " ) = = 0 )
batch = 1 ;
else if ( strcmp ( * argv , " -preserveDN " ) = = 0 )
preserve = 1 ;
else if ( strcmp ( * argv , " -gencrl " ) = = 0 )
gencrl = 1 ;
else if ( strcmp ( * argv , " -msie_hack " ) = = 0 )
msie_hack = 1 ;
else if ( strcmp ( * argv , " -crldays " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
crldays = atol ( * ( + + argv ) ) ;
}
else if ( strcmp ( * argv , " -crlhours " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
crlhours = atol ( * ( + + argv ) ) ;
}
else if ( strcmp ( * argv , " -infiles " ) = = 0 )
{
argc - - ;
argv + + ;
req = 1 ;
break ;
}
else if ( strcmp ( * argv , " -ss_cert " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
ss_cert_file = * ( + + argv ) ;
req = 1 ;
}
else if ( strcmp ( * argv , " -spkac " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
spkac_file = * ( + + argv ) ;
req = 1 ;
}
else if ( strcmp ( * argv , " -revoke " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
infile = * ( + + argv ) ;
dorevoke = 1 ;
}
2000-04-13 06:33:22 +00:00
else if ( strcmp ( * argv , " -extensions " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
extensions = * ( + + argv ) ;
}
else if ( strcmp ( * argv , " -crlexts " ) = = 0 )
{
if ( - - argc < 1 ) goto bad ;
crl_ext = * ( + + argv ) ;
}
2000-01-10 06:22:05 +00:00
else
{
bad :
BIO_printf ( bio_err , " unknown option %s \n " , * argv ) ;
badops = 1 ;
break ;
}
argc - - ;
argv + + ;
}
if ( badops )
{
for ( pp = ca_usage ; ( * pp ! = NULL ) ; pp + + )
BIO_printf ( bio_err , * pp ) ;
goto err ;
}
ERR_load_crypto_strings ( ) ;
/*****************************************************************/
if ( configfile = = NULL ) configfile = getenv ( " OPENSSL_CONF " ) ;
if ( configfile = = NULL ) configfile = getenv ( " SSLEAY_CONF " ) ;
if ( configfile = = NULL )
{
/* We will just use 'buf[0]' as a temporary buffer. */
# ifdef VMS
strncpy ( buf [ 0 ] , X509_get_default_cert_area ( ) ,
sizeof ( buf [ 0 ] ) - 1 - sizeof ( CONFIG_FILE ) ) ;
# else
strncpy ( buf [ 0 ] , X509_get_default_cert_area ( ) ,
sizeof ( buf [ 0 ] ) - 2 - sizeof ( CONFIG_FILE ) ) ;
strcat ( buf [ 0 ] , " / " ) ;
# endif
strcat ( buf [ 0 ] , CONFIG_FILE ) ;
configfile = buf [ 0 ] ;
}
BIO_printf ( bio_err , " Using configuration from %s \n " , configfile ) ;
if ( ( conf = CONF_load ( NULL , configfile , & errorline ) ) = = NULL )
{
if ( errorline < = 0 )
BIO_printf ( bio_err , " error loading the config file '%s' \n " ,
configfile ) ;
else
BIO_printf ( bio_err , " error on line %ld of config file '%s' \n "
, errorline , configfile ) ;
goto err ;
}
/* Lets get the config section we are using */
if ( section = = NULL )
{
section = CONF_get_string ( conf , BASE_SECTION , ENV_DEFAULT_CA ) ;
if ( section = = NULL )
{
lookup_fail ( BASE_SECTION , ENV_DEFAULT_CA ) ;
goto err ;
}
}
if ( conf ! = NULL )
{
p = CONF_get_string ( conf , NULL , " oid_file " ) ;
if ( p ! = NULL )
{
BIO * oid_bio ;
oid_bio = BIO_new_file ( p , " r " ) ;
if ( oid_bio = = NULL )
{
/*
BIO_printf ( bio_err , " problems opening %s for extra oid's \n " , p ) ;
ERR_print_errors ( bio_err ) ;
*/
ERR_clear_error ( ) ;
}
else
{
OBJ_create_objects ( oid_bio ) ;
BIO_free ( oid_bio ) ;
}
}
2000-11-13 01:03:58 +00:00
if ( ! add_oid_section ( bio_err , conf ) )
2000-04-13 06:33:22 +00:00
{
2000-01-10 06:22:05 +00:00
ERR_print_errors ( bio_err ) ;
goto err ;
2000-04-13 06:33:22 +00:00
}
2000-01-10 06:22:05 +00:00
}
2000-04-13 06:33:22 +00:00
randfile = CONF_get_string ( conf , BASE_SECTION , " RANDFILE " ) ;
app_RAND_load_file ( randfile , bio_err , 0 ) ;
2000-01-10 06:22:05 +00:00
in = BIO_new ( BIO_s_file ( ) ) ;
out = BIO_new ( BIO_s_file ( ) ) ;
Sout = BIO_new ( BIO_s_file ( ) ) ;
Cout = BIO_new ( BIO_s_file ( ) ) ;
if ( ( in = = NULL ) | | ( out = = NULL ) | | ( Sout = = NULL ) | | ( Cout = = NULL ) )
{
ERR_print_errors ( bio_err ) ;
goto err ;
}
/*****************************************************************/
2000-04-13 06:33:22 +00:00
/* we definitely need an public key, so lets get it */
2000-01-10 06:22:05 +00:00
if ( ( keyfile = = NULL ) & & ( ( keyfile = CONF_get_string ( conf ,
section , ENV_PRIVATE_KEY ) ) = = NULL ) )
{
lookup_fail ( section , ENV_PRIVATE_KEY ) ;
goto err ;
}
2000-11-13 01:03:58 +00:00
if ( ! key & & ! app_passwd ( bio_err , passargin , NULL , & key , NULL ) )
{
BIO_printf ( bio_err , " Error getting password \n " ) ;
goto err ;
}
2000-01-10 06:22:05 +00:00
if ( BIO_read_filename ( in , keyfile ) < = 0 )
{
perror ( keyfile ) ;
BIO_printf ( bio_err , " trying to load CA private key \n " ) ;
goto err ;
}
2000-04-13 06:33:22 +00:00
pkey = PEM_read_bio_PrivateKey ( in , NULL , NULL , key ) ;
if ( key ) memset ( key , 0 , strlen ( key ) ) ;
2000-01-10 06:22:05 +00:00
if ( pkey = = NULL )
{
BIO_printf ( bio_err , " unable to load CA private key \n " ) ;
goto err ;
}
/*****************************************************************/
/* we need a certificate */
if ( ( certfile = = NULL ) & & ( ( certfile = CONF_get_string ( conf ,
section , ENV_CERTIFICATE ) ) = = NULL ) )
{
lookup_fail ( section , ENV_CERTIFICATE ) ;
goto err ;
}
if ( BIO_read_filename ( in , certfile ) < = 0 )
{
perror ( certfile ) ;
BIO_printf ( bio_err , " trying to load CA certificate \n " ) ;
goto err ;
}
x509 = PEM_read_bio_X509 ( in , NULL , NULL , NULL ) ;
if ( x509 = = NULL )
{
BIO_printf ( bio_err , " unable to load CA certificate \n " ) ;
goto err ;
}
if ( ! X509_check_private_key ( x509 , pkey ) )
{
BIO_printf ( bio_err , " CA certificate and CA private key do not match \n " ) ;
goto err ;
}
f = CONF_get_string ( conf , BASE_SECTION , ENV_PRESERVE ) ;
if ( ( f ! = NULL ) & & ( ( * f = = ' y ' ) | | ( * f = = ' Y ' ) ) )
preserve = 1 ;
f = CONF_get_string ( conf , BASE_SECTION , ENV_MSIE_HACK ) ;
if ( ( f ! = NULL ) & & ( ( * f = = ' y ' ) | | ( * f = = ' Y ' ) ) )
msie_hack = 1 ;
/*****************************************************************/
/* lookup where to write new certificates */
if ( ( outdir = = NULL ) & & ( req ) )
{
struct stat sb ;
if ( ( outdir = CONF_get_string ( conf , section , ENV_NEW_CERTS_DIR ) )
= = NULL )
{
BIO_printf ( bio_err , " there needs to be defined a directory for new certificate to be placed in \n " ) ;
goto err ;
}
2000-04-13 06:33:22 +00:00
# ifndef VMS / * outdir is a directory spec, but access() for VMS demands a
filename . In any case , stat ( ) , below , will catch the problem
if outdir is not a directory spec , and the fopen ( ) or open ( )
will catch an error if there is no write access .
Presumably , this problem could also be solved by using the DEC
C routines to convert the directory syntax to Unixly , and give
that to access ( ) . However , time ' s too short to do that just
now .
*/
2000-01-10 06:22:05 +00:00
if ( access ( outdir , R_OK | W_OK | X_OK ) ! = 0 )
{
2000-04-13 06:33:22 +00:00
BIO_printf ( bio_err , " I am unable to access the %s directory \n " , outdir ) ;
2000-01-10 06:22:05 +00:00
perror ( outdir ) ;
goto err ;
}
if ( stat ( outdir , & sb ) ! = 0 )
{
BIO_printf ( bio_err , " unable to stat(%s) \n " , outdir ) ;
perror ( outdir ) ;
goto err ;
}
2000-04-13 06:33:22 +00:00
# ifdef S_IFDIR
2000-01-10 06:22:05 +00:00
if ( ! ( sb . st_mode & S_IFDIR ) )
{
BIO_printf ( bio_err , " %s need to be a directory \n " , outdir ) ;
perror ( outdir ) ;
goto err ;
}
2000-04-13 06:33:22 +00:00
# endif
# endif
2000-01-10 06:22:05 +00:00
}
/*****************************************************************/
/* we need to load the database file */
if ( ( dbfile = CONF_get_string ( conf , section , ENV_DATABASE ) ) = = NULL )
{
lookup_fail ( section , ENV_DATABASE ) ;
goto err ;
}
if ( BIO_read_filename ( in , dbfile ) < = 0 )
{
perror ( dbfile ) ;
BIO_printf ( bio_err , " unable to open '%s' \n " , dbfile ) ;
goto err ;
}
db = TXT_DB_read ( in , DB_NUMBER ) ;
if ( db = = NULL ) goto err ;
/* Lets check some fields */
for ( i = 0 ; i < sk_num ( db - > data ) ; i + + )
{
pp = ( char * * ) sk_value ( db - > data , i ) ;
if ( ( pp [ DB_type ] [ 0 ] ! = DB_TYPE_REV ) & &
( pp [ DB_rev_date ] [ 0 ] ! = ' \0 ' ) )
{
BIO_printf ( bio_err , " entry %d: not revoked yet, but has a revocation date \n " , i + 1 ) ;
goto err ;
}
if ( ( pp [ DB_type ] [ 0 ] = = DB_TYPE_REV ) & &
! check_time_format ( pp [ DB_rev_date ] ) )
{
BIO_printf ( bio_err , " entry %d: invalid revocation date \n " ,
i + 1 ) ;
goto err ;
}
if ( ! check_time_format ( pp [ DB_exp_date ] ) )
{
BIO_printf ( bio_err , " entry %d: invalid expiry date \n " , i + 1 ) ;
goto err ;
}
p = pp [ DB_serial ] ;
j = strlen ( p ) ;
if ( ( j & 1 ) | | ( j < 2 ) )
{
BIO_printf ( bio_err , " entry %d: bad serial number length (%d) \n " , i + 1 , j ) ;
goto err ;
}
while ( * p )
{
if ( ! ( ( ( * p > = ' 0 ' ) & & ( * p < = ' 9 ' ) ) | |
( ( * p > = ' A ' ) & & ( * p < = ' F ' ) ) | |
( ( * p > = ' a ' ) & & ( * p < = ' f ' ) ) ) )
{
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 ) ;
goto err ;
}
p + + ;
}
}
if ( verbose )
{
BIO_set_fp ( out , stdout , BIO_NOCLOSE | BIO_FP_TEXT ) ; /* cannot fail */
2000-11-13 01:03:58 +00:00
# ifdef VMS
{
BIO * tmpbio = BIO_new ( BIO_f_linebuffer ( ) ) ;
out = BIO_push ( tmpbio , out ) ;
}
# endif
2000-01-10 06:22:05 +00:00
TXT_DB_write ( out , db ) ;
BIO_printf ( bio_err , " %d entries loaded from the database \n " ,
db - > data - > num ) ;
2000-04-13 06:33:22 +00:00
BIO_printf ( bio_err , " generating index \n " ) ;
2000-01-10 06:22:05 +00:00
}
if ( ! TXT_DB_create_index ( db , DB_serial , NULL , index_serial_hash ,
index_serial_cmp ) )
{
BIO_printf ( bio_err , " error creating serial number index:(%ld,%ld,%ld) \n " , db - > error , db - > arg1 , db - > arg2 ) ;
goto err ;
}
if ( ! TXT_DB_create_index ( db , DB_name , index_name_qual , index_name_hash ,
index_name_cmp ) )
{
BIO_printf ( bio_err , " error creating name index:(%ld,%ld,%ld) \n " ,
db - > error , db - > arg1 , db - > arg2 ) ;
goto err ;
}
/*****************************************************************/
if ( req | | gencrl )
{
if ( outfile ! = NULL )
{
if ( BIO_write_filename ( Sout , outfile ) < = 0 )
{
perror ( outfile ) ;
goto err ;
}
}
else
2000-11-13 01:03:58 +00:00
{
2000-01-10 06:22:05 +00:00
BIO_set_fp ( Sout , stdout , BIO_NOCLOSE | BIO_FP_TEXT ) ;
2000-11-13 01:03:58 +00:00
# ifdef VMS
{
BIO * tmpbio = BIO_new ( BIO_f_linebuffer ( ) ) ;
Sout = BIO_push ( tmpbio , Sout ) ;
}
# endif
}
2000-01-10 06:22:05 +00:00
}
if ( req )
{
if ( ( md = = NULL ) & & ( ( md = CONF_get_string ( conf ,
section , ENV_DEFAULT_MD ) ) = = NULL ) )
{
lookup_fail ( section , ENV_DEFAULT_MD ) ;
goto err ;
}
if ( ( dgst = EVP_get_digestbyname ( md ) ) = = NULL )
{
BIO_printf ( bio_err , " %s is an unsupported message digest type \n " , md ) ;
goto err ;
}
if ( verbose )
BIO_printf ( bio_err , " message digest is %s \n " ,
OBJ_nid2ln ( dgst - > type ) ) ;
if ( ( policy = = NULL ) & & ( ( policy = CONF_get_string ( conf ,
section , ENV_POLICY ) ) = = NULL ) )
{
lookup_fail ( section , ENV_POLICY ) ;
goto err ;
}
if ( verbose )
BIO_printf ( bio_err , " policy is %s \n " , policy ) ;
if ( ( serialfile = CONF_get_string ( conf , section , ENV_SERIAL ) )
= = NULL )
{
lookup_fail ( section , ENV_SERIAL ) ;
goto err ;
}
2000-04-13 06:33:22 +00:00
if ( ! extensions )
extensions = CONF_get_string ( conf , section , ENV_EXTENSIONS ) ;
2000-01-10 06:22:05 +00:00
if ( extensions ) {
/* Check syntax of file */
X509V3_CTX ctx ;
X509V3_set_ctx_test ( & ctx ) ;
X509V3_set_conf_lhash ( & ctx , conf ) ;
if ( ! X509V3_EXT_add_conf ( conf , & ctx , extensions , NULL ) ) {
BIO_printf ( bio_err ,
" Error Loading extension section %s \n " ,
extensions ) ;
ret = 1 ;
goto err ;
}
}
if ( startdate = = NULL )
{
startdate = CONF_get_string ( conf , section ,
ENV_DEFAULT_STARTDATE ) ;
}
if ( startdate & & ! ASN1_UTCTIME_set_string ( NULL , startdate ) )
{
BIO_printf ( bio_err , " start date is invalid, it should be YYMMDDHHMMSSZ \n " ) ;
goto err ;
}
if ( startdate = = NULL ) startdate = " today " ;
if ( enddate = = NULL )
{
enddate = CONF_get_string ( conf , section ,
ENV_DEFAULT_ENDDATE ) ;
}
if ( enddate & & ! ASN1_UTCTIME_set_string ( NULL , enddate ) )
{
BIO_printf ( bio_err , " end date is invalid, it should be YYMMDDHHMMSSZ \n " ) ;
goto err ;
}
if ( days = = 0 )
{
days = ( int ) CONF_get_number ( conf , section ,
ENV_DEFAULT_DAYS ) ;
}
if ( ! enddate & & ( days = = 0 ) )
{
BIO_printf ( bio_err , " cannot lookup how many days to certify for \n " ) ;
goto err ;
}
if ( ( serial = load_serial ( serialfile ) ) = = NULL )
{
BIO_printf ( bio_err , " error while loading serial number \n " ) ;
goto err ;
}
if ( verbose )
{
if ( ( f = BN_bn2hex ( serial ) ) = = NULL ) goto err ;
BIO_printf ( bio_err , " next serial number is %s \n " , f ) ;
2000-11-13 01:03:58 +00:00
OPENSSL_free ( f ) ;
2000-01-10 06:22:05 +00:00
}
if ( ( attribs = CONF_get_section ( conf , policy ) ) = = NULL )
{
BIO_printf ( bio_err , " unable to find 'section' for %s \n " , policy ) ;
goto err ;
}
2000-11-13 01:03:58 +00:00
if ( ( cert_sk = sk_X509_new_null ( ) ) = = NULL )
2000-01-10 06:22:05 +00:00
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
if ( spkac_file ! = NULL )
{
total + + ;
j = certify_spkac ( & x , spkac_file , pkey , x509 , dgst , attribs , db ,
serial , startdate , enddate , days , extensions , conf ,
verbose ) ;
if ( j < 0 ) goto err ;
if ( j > 0 )
{
total_done + + ;
BIO_printf ( bio_err , " \n " ) ;
if ( ! BN_add_word ( serial , 1 ) ) goto err ;
2000-11-13 01:03:58 +00:00
if ( ! sk_X509_push ( cert_sk , x ) )
2000-01-10 06:22:05 +00:00
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
if ( outfile )
{
output_der = 1 ;
batch = 1 ;
}
}
}
if ( ss_cert_file ! = NULL )
{
total + + ;
j = certify_cert ( & x , ss_cert_file , pkey , x509 , dgst , attribs ,
db , serial , startdate , enddate , days , batch ,
extensions , conf , verbose ) ;
if ( j < 0 ) goto err ;
if ( j > 0 )
{
total_done + + ;
BIO_printf ( bio_err , " \n " ) ;
if ( ! BN_add_word ( serial , 1 ) ) goto err ;
2000-11-13 01:03:58 +00:00
if ( ! sk_X509_push ( cert_sk , x ) )
2000-01-10 06:22:05 +00:00
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
}
}
if ( infile ! = NULL )
{
total + + ;
j = certify ( & x , infile , pkey , x509 , dgst , attribs , db ,
serial , startdate , enddate , days , batch ,
extensions , conf , verbose ) ;
if ( j < 0 ) goto err ;
if ( j > 0 )
{
total_done + + ;
BIO_printf ( bio_err , " \n " ) ;
if ( ! BN_add_word ( serial , 1 ) ) goto err ;
2000-11-13 01:03:58 +00:00
if ( ! sk_X509_push ( cert_sk , x ) )
2000-01-10 06:22:05 +00:00
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
}
}
for ( i = 0 ; i < argc ; i + + )
{
total + + ;
j = certify ( & x , argv [ i ] , pkey , x509 , dgst , attribs , db ,
serial , startdate , enddate , days , batch ,
extensions , conf , verbose ) ;
if ( j < 0 ) goto err ;
if ( j > 0 )
{
total_done + + ;
BIO_printf ( bio_err , " \n " ) ;
if ( ! BN_add_word ( serial , 1 ) ) goto err ;
2000-11-13 01:03:58 +00:00
if ( ! sk_X509_push ( cert_sk , x ) )
2000-01-10 06:22:05 +00:00
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
}
}
/* we have a stack of newly certified certificates
* and a data base and serial number that need
* updating */
2000-11-13 01:03:58 +00:00
if ( sk_X509_num ( cert_sk ) > 0 )
2000-01-10 06:22:05 +00:00
{
if ( ! batch )
{
BIO_printf ( bio_err , " \n %d out of %d certificate requests certified, commit? [y/n] " , total_done , total ) ;
( void ) BIO_flush ( bio_err ) ;
buf [ 0 ] [ 0 ] = ' \0 ' ;
fgets ( buf [ 0 ] , 10 , stdin ) ;
if ( ( buf [ 0 ] [ 0 ] ! = ' y ' ) & & ( buf [ 0 ] [ 0 ] ! = ' Y ' ) )
{
BIO_printf ( bio_err , " CERTIFICATION CANCELED \n " ) ;
ret = 0 ;
goto err ;
}
}
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Write out database with %d new entries \n " , sk_X509_num ( cert_sk ) ) ;
2000-01-10 06:22:05 +00:00
strncpy ( buf [ 0 ] , serialfile , BSIZE - 4 ) ;
# ifdef VMS
strcat ( buf [ 0 ] , " -new " ) ;
# else
strcat ( buf [ 0 ] , " .new " ) ;
# endif
if ( ! save_serial ( buf [ 0 ] , serial ) ) goto err ;
strncpy ( buf [ 1 ] , dbfile , BSIZE - 4 ) ;
# ifdef VMS
strcat ( buf [ 1 ] , " -new " ) ;
# else
strcat ( buf [ 1 ] , " .new " ) ;
# endif
if ( BIO_write_filename ( out , buf [ 1 ] ) < = 0 )
{
perror ( dbfile ) ;
BIO_printf ( bio_err , " unable to open '%s' \n " , dbfile ) ;
goto err ;
}
l = TXT_DB_write ( out , db ) ;
if ( l < = 0 ) goto err ;
}
if ( verbose )
BIO_printf ( bio_err , " writing new certificates \n " ) ;
2000-11-13 01:03:58 +00:00
for ( i = 0 ; i < sk_X509_num ( cert_sk ) ; i + + )
2000-01-10 06:22:05 +00:00
{
int k ;
unsigned char * n ;
2000-11-13 01:03:58 +00:00
x = sk_X509_value ( cert_sk , i ) ;
2000-01-10 06:22:05 +00:00
j = x - > cert_info - > serialNumber - > length ;
p = ( char * ) x - > cert_info - > serialNumber - > data ;
strncpy ( buf [ 2 ] , outdir , BSIZE - ( j * 2 ) - 6 ) ;
# ifndef VMS
strcat ( buf [ 2 ] , " / " ) ;
# endif
n = ( unsigned char * ) & ( buf [ 2 ] [ strlen ( buf [ 2 ] ) ] ) ;
if ( j > 0 )
{
for ( k = 0 ; k < j ; k + + )
{
sprintf ( ( char * ) n , " %02X " , ( unsigned char ) * ( p + + ) ) ;
n + = 2 ;
}
}
else
{
* ( n + + ) = ' 0 ' ;
* ( n + + ) = ' 0 ' ;
}
* ( n + + ) = ' . ' ; * ( n + + ) = ' p ' ; * ( n + + ) = ' e ' ; * ( n + + ) = ' m ' ;
* n = ' \0 ' ;
if ( verbose )
BIO_printf ( bio_err , " writing %s \n " , buf [ 2 ] ) ;
if ( BIO_write_filename ( Cout , buf [ 2 ] ) < = 0 )
{
perror ( buf [ 2 ] ) ;
goto err ;
}
2000-04-13 06:33:22 +00:00
write_new_certificate ( Cout , x , 0 , notext ) ;
write_new_certificate ( Sout , x , output_der , notext ) ;
2000-01-10 06:22:05 +00:00
}
2000-11-13 01:03:58 +00:00
if ( sk_X509_num ( cert_sk ) )
2000-01-10 06:22:05 +00:00
{
/* Rename the database and the serial file */
strncpy ( buf [ 2 ] , serialfile , BSIZE - 4 ) ;
# ifdef VMS
strcat ( buf [ 2 ] , " -old " ) ;
# else
strcat ( buf [ 2 ] , " .old " ) ;
# endif
BIO_free ( in ) ;
2000-11-13 01:03:58 +00:00
BIO_free_all ( out ) ;
2000-01-10 06:22:05 +00:00
in = NULL ;
out = NULL ;
if ( rename ( serialfile , buf [ 2 ] ) < 0 )
{
2000-04-13 06:33:22 +00:00
BIO_printf ( bio_err , " unable to rename %s to %s \n " ,
2000-01-10 06:22:05 +00:00
serialfile , buf [ 2 ] ) ;
perror ( " reason " ) ;
goto err ;
}
if ( rename ( buf [ 0 ] , serialfile ) < 0 )
{
2000-04-13 06:33:22 +00:00
BIO_printf ( bio_err , " unable to rename %s to %s \n " ,
2000-01-10 06:22:05 +00:00
buf [ 0 ] , serialfile ) ;
perror ( " reason " ) ;
rename ( buf [ 2 ] , serialfile ) ;
goto err ;
}
strncpy ( buf [ 2 ] , dbfile , BSIZE - 4 ) ;
# ifdef VMS
strcat ( buf [ 2 ] , " -old " ) ;
# else
strcat ( buf [ 2 ] , " .old " ) ;
# endif
if ( rename ( dbfile , buf [ 2 ] ) < 0 )
{
2000-04-13 06:33:22 +00:00
BIO_printf ( bio_err , " unable to rename %s to %s \n " ,
2000-01-10 06:22:05 +00:00
dbfile , buf [ 2 ] ) ;
perror ( " reason " ) ;
goto err ;
}
if ( rename ( buf [ 1 ] , dbfile ) < 0 )
{
2000-04-13 06:33:22 +00:00
BIO_printf ( bio_err , " unable to rename %s to %s \n " ,
2000-01-10 06:22:05 +00:00
buf [ 1 ] , dbfile ) ;
perror ( " reason " ) ;
rename ( buf [ 2 ] , dbfile ) ;
goto err ;
}
BIO_printf ( bio_err , " Data Base Updated \n " ) ;
}
}
/*****************************************************************/
if ( gencrl )
{
2000-04-13 06:33:22 +00:00
if ( ! crl_ext ) crl_ext = CONF_get_string ( conf , section , ENV_CRLEXT ) ;
2000-01-10 06:22:05 +00:00
if ( crl_ext ) {
/* Check syntax of file */
X509V3_CTX ctx ;
X509V3_set_ctx_test ( & ctx ) ;
X509V3_set_conf_lhash ( & ctx , conf ) ;
if ( ! X509V3_EXT_add_conf ( conf , & ctx , crl_ext , NULL ) ) {
BIO_printf ( bio_err ,
" Error Loading CRL extension section %s \n " ,
crl_ext ) ;
ret = 1 ;
goto err ;
}
}
if ( ( hex = BIO_new ( BIO_s_mem ( ) ) ) = = NULL ) goto err ;
if ( ! crldays & & ! crlhours )
{
crldays = CONF_get_number ( conf , section ,
ENV_DEFAULT_CRL_DAYS ) ;
crlhours = CONF_get_number ( conf , section ,
ENV_DEFAULT_CRL_HOURS ) ;
}
if ( ( crldays = = 0 ) & & ( crlhours = = 0 ) )
{
BIO_printf ( bio_err , " cannot lookup how long until the next CRL is issuer \n " ) ;
goto err ;
}
if ( verbose ) BIO_printf ( bio_err , " making CRL \n " ) ;
if ( ( crl = X509_CRL_new ( ) ) = = NULL ) goto err ;
ci = crl - > crl ;
X509_NAME_free ( ci - > issuer ) ;
ci - > issuer = X509_NAME_dup ( x509 - > cert_info - > subject ) ;
if ( ci - > issuer = = NULL ) goto err ;
X509_gmtime_adj ( ci - > lastUpdate , 0 ) ;
if ( ci - > nextUpdate = = NULL )
ci - > nextUpdate = ASN1_UTCTIME_new ( ) ;
X509_gmtime_adj ( ci - > nextUpdate , ( crldays * 24 + crlhours ) * 60 * 60 ) ;
for ( i = 0 ; i < sk_num ( db - > data ) ; i + + )
{
pp = ( char * * ) sk_value ( db - > data , i ) ;
if ( pp [ DB_type ] [ 0 ] = = DB_TYPE_REV )
{
if ( ( r = X509_REVOKED_new ( ) ) = = NULL ) goto err ;
ASN1_STRING_set ( ( ASN1_STRING * )
r - > revocationDate ,
( unsigned char * ) pp [ DB_rev_date ] ,
strlen ( pp [ DB_rev_date ] ) ) ;
/* strcpy(r->revocationDate,pp[DB_rev_date]);*/
( void ) BIO_reset ( hex ) ;
if ( ! BIO_puts ( hex , pp [ DB_serial ] ) )
goto err ;
if ( ! a2i_ASN1_INTEGER ( hex , r - > serialNumber ,
buf [ 0 ] , BSIZE ) ) goto err ;
sk_X509_REVOKED_push ( ci - > revoked , r ) ;
}
}
/* sort the data so it will be written in serial
* number order */
sk_X509_REVOKED_sort ( ci - > revoked ) ;
for ( i = 0 ; i < sk_X509_REVOKED_num ( ci - > revoked ) ; i + + )
{
r = sk_X509_REVOKED_value ( ci - > revoked , i ) ;
r - > sequence = i ;
}
/* we now have a CRL */
if ( verbose ) BIO_printf ( bio_err , " signing CRL \n " ) ;
if ( md ! = NULL )
{
if ( ( dgst = EVP_get_digestbyname ( md ) ) = = NULL )
{
BIO_printf ( bio_err , " %s is an unsupported message digest type \n " , md ) ;
goto err ;
}
}
else
{
# ifndef NO_DSA
if ( pkey - > type = = EVP_PKEY_DSA )
dgst = EVP_dss1 ( ) ;
else
# endif
dgst = EVP_md5 ( ) ;
}
/* Add any extensions asked for */
if ( crl_ext ) {
X509V3_CTX crlctx ;
if ( ci - > version = = NULL )
if ( ( ci - > version = ASN1_INTEGER_new ( ) ) = = NULL ) goto err ;
ASN1_INTEGER_set ( ci - > version , 1 ) ; /* version 2 CRL */
X509V3_set_ctx ( & crlctx , x509 , NULL , NULL , crl , 0 ) ;
X509V3_set_conf_lhash ( & crlctx , conf ) ;
if ( ! X509V3_EXT_CRL_add_conf ( conf , & crlctx ,
crl_ext , crl ) ) goto err ;
}
if ( ! X509_CRL_sign ( crl , pkey , dgst ) ) goto err ;
PEM_write_bio_X509_CRL ( Sout , crl ) ;
}
/*****************************************************************/
if ( dorevoke )
{
if ( infile = = NULL )
{
BIO_printf ( bio_err , " no input files \n " ) ;
goto err ;
}
else
{
2000-04-13 06:33:22 +00:00
X509 * revcert ;
2000-01-10 06:22:05 +00:00
if ( BIO_read_filename ( in , infile ) < = 0 )
{
perror ( infile ) ;
BIO_printf ( bio_err , " error trying to load '%s' certificate \n " , infile ) ;
goto err ;
}
2000-04-13 06:33:22 +00:00
revcert = PEM_read_bio_X509 ( in , NULL , NULL , NULL ) ;
if ( revcert = = NULL )
2000-01-10 06:22:05 +00:00
{
BIO_printf ( bio_err , " unable to load '%s' certificate \n " , infile ) ;
goto err ;
}
2000-04-13 06:33:22 +00:00
j = do_revoke ( revcert , db ) ;
if ( j < = 0 ) goto err ;
X509_free ( revcert ) ;
2000-01-10 06:22:05 +00:00
strncpy ( buf [ 0 ] , dbfile , BSIZE - 4 ) ;
strcat ( buf [ 0 ] , " .new " ) ;
if ( BIO_write_filename ( out , buf [ 0 ] ) < = 0 )
{
perror ( dbfile ) ;
BIO_printf ( bio_err , " unable to open '%s' \n " , dbfile ) ;
goto err ;
}
j = TXT_DB_write ( out , db ) ;
if ( j < = 0 ) goto err ;
strncpy ( buf [ 1 ] , dbfile , BSIZE - 4 ) ;
strcat ( buf [ 1 ] , " .old " ) ;
if ( rename ( dbfile , buf [ 1 ] ) < 0 )
{
BIO_printf ( bio_err , " unable to rename %s to %s \n " , dbfile , buf [ 1 ] ) ;
perror ( " reason " ) ;
goto err ;
}
if ( rename ( buf [ 0 ] , dbfile ) < 0 )
{
BIO_printf ( bio_err , " unable to rename %s to %s \n " , buf [ 0 ] , dbfile ) ;
perror ( " reason " ) ;
rename ( buf [ 1 ] , dbfile ) ;
goto err ;
}
BIO_printf ( bio_err , " Data Base Updated \n " ) ;
}
}
/*****************************************************************/
ret = 0 ;
err :
BIO_free ( hex ) ;
2000-11-13 01:03:58 +00:00
BIO_free_all ( Cout ) ;
BIO_free_all ( Sout ) ;
BIO_free_all ( out ) ;
2000-01-10 06:22:05 +00:00
BIO_free ( in ) ;
2000-11-13 01:03:58 +00:00
sk_X509_pop_free ( cert_sk , X509_free ) ;
2000-01-10 06:22:05 +00:00
if ( ret ) ERR_print_errors ( bio_err ) ;
2000-04-13 06:33:22 +00:00
app_RAND_write_file ( randfile , bio_err ) ;
2000-01-10 06:22:05 +00:00
BN_free ( serial ) ;
TXT_DB_free ( db ) ;
EVP_PKEY_free ( pkey ) ;
X509_free ( x509 ) ;
X509_CRL_free ( crl ) ;
CONF_free ( conf ) ;
OBJ_cleanup ( ) ;
EXIT ( ret ) ;
}
static void lookup_fail ( char * name , char * tag )
{
BIO_printf ( bio_err , " variable lookup failed for %s::%s \n " , name , tag ) ;
}
static unsigned long index_serial_hash ( char * * a )
{
char * n ;
n = a [ DB_serial ] ;
while ( * n = = ' 0 ' ) n + + ;
return ( lh_strhash ( n ) ) ;
}
static int index_serial_cmp ( char * * a , char * * b )
{
char * aa , * bb ;
for ( aa = a [ DB_serial ] ; * aa = = ' 0 ' ; aa + + ) ;
for ( bb = b [ DB_serial ] ; * bb = = ' 0 ' ; bb + + ) ;
return ( strcmp ( aa , bb ) ) ;
}
static unsigned long index_name_hash ( char * * a )
{ return ( lh_strhash ( a [ DB_name ] ) ) ; }
static int index_name_qual ( char * * a )
{ return ( a [ 0 ] [ 0 ] = = ' V ' ) ; }
static int index_name_cmp ( char * * a , char * * b )
{ return ( strcmp ( a [ DB_name ] ,
b [ DB_name ] ) ) ; }
static BIGNUM * load_serial ( char * serialfile )
{
BIO * in = NULL ;
BIGNUM * ret = NULL ;
MS_STATIC char buf [ 1024 ] ;
ASN1_INTEGER * ai = NULL ;
if ( ( in = BIO_new ( BIO_s_file ( ) ) ) = = NULL )
{
ERR_print_errors ( bio_err ) ;
goto err ;
}
if ( BIO_read_filename ( in , serialfile ) < = 0 )
{
perror ( serialfile ) ;
goto err ;
}
ai = ASN1_INTEGER_new ( ) ;
if ( ai = = NULL ) goto err ;
if ( ! a2i_ASN1_INTEGER ( in , ai , buf , 1024 ) )
{
BIO_printf ( bio_err , " unable to load number from %s \n " ,
serialfile ) ;
goto err ;
}
ret = ASN1_INTEGER_to_BN ( ai , NULL ) ;
if ( ret = = NULL )
{
BIO_printf ( bio_err , " error converting number from bin to BIGNUM " ) ;
goto err ;
}
err :
if ( in ! = NULL ) BIO_free ( in ) ;
if ( ai ! = NULL ) ASN1_INTEGER_free ( ai ) ;
return ( ret ) ;
}
static int save_serial ( char * serialfile , BIGNUM * serial )
{
BIO * out ;
int ret = 0 ;
ASN1_INTEGER * ai = NULL ;
out = BIO_new ( BIO_s_file ( ) ) ;
if ( out = = NULL )
{
ERR_print_errors ( bio_err ) ;
goto err ;
}
if ( BIO_write_filename ( out , serialfile ) < = 0 )
{
perror ( serialfile ) ;
goto err ;
}
if ( ( ai = BN_to_ASN1_INTEGER ( serial , NULL ) ) = = NULL )
{
BIO_printf ( bio_err , " error converting serial to ASN.1 format \n " ) ;
goto err ;
}
i2a_ASN1_INTEGER ( out , ai ) ;
BIO_puts ( out , " \n " ) ;
ret = 1 ;
err :
2000-11-13 01:03:58 +00:00
if ( out ! = NULL ) BIO_free_all ( out ) ;
2000-01-10 06:22:05 +00:00
if ( ai ! = NULL ) ASN1_INTEGER_free ( ai ) ;
return ( ret ) ;
}
static int certify ( X509 * * xret , char * infile , EVP_PKEY * pkey , X509 * x509 ,
const EVP_MD * dgst , STACK_OF ( CONF_VALUE ) * policy , TXT_DB * db ,
BIGNUM * serial , char * startdate , char * enddate , int days ,
int batch , char * ext_sect , LHASH * lconf , int verbose )
{
X509_REQ * req = NULL ;
BIO * in = NULL ;
EVP_PKEY * pktmp = NULL ;
int ok = - 1 , i ;
in = BIO_new ( BIO_s_file ( ) ) ;
if ( BIO_read_filename ( in , infile ) < = 0 )
{
perror ( infile ) ;
goto err ;
}
if ( ( req = PEM_read_bio_X509_REQ ( in , NULL , NULL , NULL ) ) = = NULL )
{
BIO_printf ( bio_err , " Error reading certificate request in %s \n " ,
infile ) ;
goto err ;
}
if ( verbose )
X509_REQ_print ( bio_err , req ) ;
BIO_printf ( bio_err , " Check that the request matches the signature \n " ) ;
if ( ( pktmp = X509_REQ_get_pubkey ( req ) ) = = NULL )
{
BIO_printf ( bio_err , " error unpacking public key \n " ) ;
goto err ;
}
i = X509_REQ_verify ( req , pktmp ) ;
EVP_PKEY_free ( pktmp ) ;
if ( i < 0 )
{
ok = 0 ;
BIO_printf ( bio_err , " Signature verification problems.... \n " ) ;
goto err ;
}
if ( i = = 0 )
{
ok = 0 ;
BIO_printf ( bio_err , " Signature did not match the certificate request \n " ) ;
goto err ;
}
else
BIO_printf ( bio_err , " Signature ok \n " ) ;
ok = do_body ( xret , pkey , x509 , dgst , policy , db , serial , startdate , enddate ,
days , batch , verbose , req , ext_sect , lconf ) ;
err :
if ( req ! = NULL ) X509_REQ_free ( req ) ;
if ( in ! = NULL ) BIO_free ( in ) ;
return ( ok ) ;
}
static int certify_cert ( X509 * * xret , char * infile , EVP_PKEY * pkey , X509 * x509 ,
const EVP_MD * dgst , STACK_OF ( CONF_VALUE ) * policy , TXT_DB * db ,
BIGNUM * serial , char * startdate , char * enddate , int days ,
int batch , char * ext_sect , LHASH * lconf , int verbose )
{
X509 * req = NULL ;
X509_REQ * rreq = NULL ;
BIO * in = NULL ;
EVP_PKEY * pktmp = NULL ;
int ok = - 1 , i ;
in = BIO_new ( BIO_s_file ( ) ) ;
if ( BIO_read_filename ( in , infile ) < = 0 )
{
perror ( infile ) ;
goto err ;
}
if ( ( req = PEM_read_bio_X509 ( in , NULL , NULL , NULL ) ) = = NULL )
{
BIO_printf ( bio_err , " Error reading self signed certificate in %s \n " , infile ) ;
goto err ;
}
if ( verbose )
X509_print ( bio_err , req ) ;
BIO_printf ( bio_err , " Check that the request matches the signature \n " ) ;
if ( ( pktmp = X509_get_pubkey ( req ) ) = = NULL )
{
BIO_printf ( bio_err , " error unpacking public key \n " ) ;
goto err ;
}
i = X509_verify ( req , pktmp ) ;
EVP_PKEY_free ( pktmp ) ;
if ( i < 0 )
{
ok = 0 ;
BIO_printf ( bio_err , " Signature verification problems.... \n " ) ;
goto err ;
}
if ( i = = 0 )
{
ok = 0 ;
BIO_printf ( bio_err , " Signature did not match the certificate \n " ) ;
goto err ;
}
else
BIO_printf ( bio_err , " Signature ok \n " ) ;
if ( ( rreq = X509_to_X509_REQ ( req , NULL , EVP_md5 ( ) ) ) = = NULL )
goto err ;
ok = do_body ( xret , pkey , x509 , dgst , policy , db , serial , startdate , enddate , days ,
batch , verbose , rreq , ext_sect , lconf ) ;
err :
if ( rreq ! = NULL ) X509_REQ_free ( rreq ) ;
if ( req ! = NULL ) X509_free ( req ) ;
if ( in ! = NULL ) BIO_free ( in ) ;
return ( ok ) ;
}
static int do_body ( X509 * * xret , EVP_PKEY * pkey , X509 * x509 , const EVP_MD * dgst ,
STACK_OF ( CONF_VALUE ) * policy , TXT_DB * db , BIGNUM * serial ,
char * startdate , char * enddate , int days , int batch , int verbose ,
X509_REQ * req , char * ext_sect , LHASH * lconf )
{
X509_NAME * name = NULL , * CAname = NULL , * subject = NULL ;
ASN1_UTCTIME * tm , * tmptm ;
ASN1_STRING * str , * str2 ;
ASN1_OBJECT * obj ;
X509 * ret = NULL ;
X509_CINF * ci ;
X509_NAME_ENTRY * ne ;
X509_NAME_ENTRY * tne , * push ;
EVP_PKEY * pktmp ;
int ok = - 1 , i , j , last , nid ;
char * p ;
CONF_VALUE * cv ;
char * row [ DB_NUMBER ] , * * rrow , * * irow = NULL ;
char buf [ 25 ] , * pbuf ;
tmptm = ASN1_UTCTIME_new ( ) ;
if ( tmptm = = NULL )
{
BIO_printf ( bio_err , " malloc error \n " ) ;
return ( 0 ) ;
}
for ( i = 0 ; i < DB_NUMBER ; i + + )
row [ i ] = NULL ;
BIO_printf ( bio_err , " The Subjects Distinguished Name is as follows \n " ) ;
name = X509_REQ_get_subject_name ( req ) ;
for ( i = 0 ; i < X509_NAME_entry_count ( name ) ; i + + )
{
ne = ( X509_NAME_ENTRY * ) X509_NAME_get_entry ( name , i ) ;
obj = X509_NAME_ENTRY_get_object ( ne ) ;
j = i2a_ASN1_OBJECT ( bio_err , obj ) ;
str = X509_NAME_ENTRY_get_data ( ne ) ;
pbuf = buf ;
for ( j = 22 - j ; j > 0 ; j - - )
* ( pbuf + + ) = ' ' ;
* ( pbuf + + ) = ' : ' ;
* ( pbuf + + ) = ' \0 ' ;
BIO_puts ( bio_err , buf ) ;
if ( msie_hack )
{
/* assume all type should be strings */
nid = OBJ_obj2nid ( ne - > object ) ;
if ( str - > type = = V_ASN1_UNIVERSALSTRING )
ASN1_UNIVERSALSTRING_to_string ( str ) ;
if ( ( str - > type = = V_ASN1_IA5STRING ) & &
( nid ! = NID_pkcs9_emailAddress ) )
str - > type = V_ASN1_T61STRING ;
if ( ( nid = = NID_pkcs9_emailAddress ) & &
( str - > type = = V_ASN1_PRINTABLESTRING ) )
str - > type = V_ASN1_IA5STRING ;
}
if ( str - > type = = V_ASN1_PRINTABLESTRING )
BIO_printf ( bio_err , " PRINTABLE:' " ) ;
else if ( str - > type = = V_ASN1_T61STRING )
BIO_printf ( bio_err , " T61STRING:' " ) ;
else if ( str - > type = = V_ASN1_IA5STRING )
BIO_printf ( bio_err , " IA5STRING:' " ) ;
else if ( str - > type = = V_ASN1_UNIVERSALSTRING )
BIO_printf ( bio_err , " UNIVERSALSTRING:' " ) ;
else
BIO_printf ( bio_err , " ASN.1 %2d:' " , str - > type ) ;
/* check some things */
if ( ( OBJ_obj2nid ( obj ) = = NID_pkcs9_emailAddress ) & &
( str - > type ! = V_ASN1_IA5STRING ) )
{
BIO_printf ( bio_err , " \n emailAddress type needs to be of type IA5STRING \n " ) ;
goto err ;
}
j = ASN1_PRINTABLE_type ( str - > data , str - > length ) ;
if ( ( ( j = = V_ASN1_T61STRING ) & &
( str - > type ! = V_ASN1_T61STRING ) ) | |
( ( j = = V_ASN1_IA5STRING ) & &
( str - > type = = V_ASN1_PRINTABLESTRING ) ) )
{
BIO_printf ( bio_err , " \n The string contains characters that are illegal for the ASN.1 type \n " ) ;
goto err ;
}
p = ( char * ) str - > data ;
for ( j = str - > length ; j > 0 ; j - - )
{
if ( ( * p > = ' ' ) & & ( * p < = ' ~ ' ) )
BIO_printf ( bio_err , " %c " , * p ) ;
else if ( * p & 0x80 )
BIO_printf ( bio_err , " \\ 0x%02X " , * p ) ;
else if ( ( unsigned char ) * p = = 0xf7 )
BIO_printf ( bio_err , " ^? " ) ;
else BIO_printf ( bio_err , " ^%c " , * p + ' @ ' ) ;
p + + ;
}
BIO_printf ( bio_err , " ' \n " ) ;
}
/* Ok, now we check the 'policy' stuff. */
if ( ( subject = X509_NAME_new ( ) ) = = NULL )
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
/* take a copy of the issuer name before we mess with it. */
CAname = X509_NAME_dup ( x509 - > cert_info - > subject ) ;
if ( CAname = = NULL ) goto err ;
str = str2 = NULL ;
for ( i = 0 ; i < sk_CONF_VALUE_num ( policy ) ; i + + )
{
cv = sk_CONF_VALUE_value ( policy , i ) ; /* get the object id */
if ( ( j = OBJ_txt2nid ( cv - > name ) ) = = NID_undef )
{
BIO_printf ( bio_err , " %s:unknown object type in 'policy' configuration \n " , cv - > name ) ;
goto err ;
}
obj = OBJ_nid2obj ( j ) ;
last = - 1 ;
for ( ; ; )
{
/* lookup the object in the supplied name list */
j = X509_NAME_get_index_by_OBJ ( name , obj , last ) ;
if ( j < 0 )
{
if ( last ! = - 1 ) break ;
tne = NULL ;
}
else
{
tne = X509_NAME_get_entry ( name , j ) ;
}
last = j ;
/* depending on the 'policy', decide what to do. */
push = NULL ;
if ( strcmp ( cv - > value , " optional " ) = = 0 )
{
if ( tne ! = NULL )
push = tne ;
}
else if ( strcmp ( cv - > value , " supplied " ) = = 0 )
{
if ( tne = = NULL )
{
BIO_printf ( bio_err , " The %s field needed to be supplied and was missing \n " , cv - > name ) ;
goto err ;
}
else
push = tne ;
}
else if ( strcmp ( cv - > value , " match " ) = = 0 )
{
int last2 ;
if ( tne = = NULL )
{
BIO_printf ( bio_err , " The mandatory %s field was missing \n " , cv - > name ) ;
goto err ;
}
last2 = - 1 ;
again2 :
j = X509_NAME_get_index_by_OBJ ( CAname , obj , last2 ) ;
if ( ( j < 0 ) & & ( last2 = = - 1 ) )
{
BIO_printf ( bio_err , " The %s field does not exist in the CA certificate, \n the 'policy' is misconfigured \n " , cv - > name ) ;
goto err ;
}
if ( j > = 0 )
{
push = X509_NAME_get_entry ( CAname , j ) ;
str = X509_NAME_ENTRY_get_data ( tne ) ;
str2 = X509_NAME_ENTRY_get_data ( push ) ;
last2 = j ;
if ( ASN1_STRING_cmp ( str , str2 ) ! = 0 )
goto again2 ;
}
if ( j < 0 )
{
2000-04-13 06:33:22 +00:00
BIO_printf ( bio_err , " The %s field needed to be the same in the \n CA certificate (%s) and the request (%s) \n " , cv - > name , ( ( str2 = = NULL ) ? " NULL " : ( char * ) str2 - > data ) , ( ( str = = NULL ) ? " NULL " : ( char * ) str - > data ) ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
}
else
{
BIO_printf ( bio_err , " %s:invalid type in 'policy' configuration \n " , cv - > value ) ;
goto err ;
}
if ( push ! = NULL )
{
2000-04-13 06:33:22 +00:00
if ( ! X509_NAME_add_entry ( subject , push , - 1 , 0 ) )
2000-01-10 06:22:05 +00:00
{
if ( push ! = NULL )
X509_NAME_ENTRY_free ( push ) ;
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
}
if ( j < 0 ) break ;
}
}
if ( preserve )
{
X509_NAME_free ( subject ) ;
subject = X509_NAME_dup ( X509_REQ_get_subject_name ( req ) ) ;
if ( subject = = NULL ) goto err ;
}
if ( verbose )
2000-04-13 06:33:22 +00:00
BIO_printf ( bio_err , " The subject name appears to be ok, checking data base for clashes \n " ) ;
2000-01-10 06:22:05 +00:00
row [ DB_name ] = X509_NAME_oneline ( subject , NULL , 0 ) ;
row [ DB_serial ] = BN_bn2hex ( serial ) ;
if ( ( row [ DB_name ] = = NULL ) | | ( row [ DB_serial ] = = NULL ) )
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
rrow = TXT_DB_get_by_index ( db , DB_name , row ) ;
if ( rrow ! = NULL )
{
BIO_printf ( bio_err , " ERROR:There is already a certificate for %s \n " ,
row [ DB_name ] ) ;
}
else
{
rrow = TXT_DB_get_by_index ( db , DB_serial , row ) ;
if ( rrow ! = NULL )
{
BIO_printf ( bio_err , " ERROR:Serial number %s has already been issued, \n " ,
row [ DB_serial ] ) ;
BIO_printf ( bio_err , " check the database/serial_file for corruption \n " ) ;
}
}
if ( rrow ! = NULL )
{
BIO_printf ( bio_err ,
" The matching entry has the following details \n " ) ;
if ( rrow [ DB_type ] [ 0 ] = = ' E ' )
p = " Expired " ;
else if ( rrow [ DB_type ] [ 0 ] = = ' R ' )
p = " Revoked " ;
else if ( rrow [ DB_type ] [ 0 ] = = ' V ' )
p = " Valid " ;
else
p = " \n invalid type, Data base error \n " ;
BIO_printf ( bio_err , " Type :%s \n " , p ) ; ;
if ( rrow [ DB_type ] [ 0 ] = = ' R ' )
{
p = rrow [ DB_exp_date ] ; if ( p = = NULL ) p = " undef " ;
BIO_printf ( bio_err , " Was revoked on:%s \n " , p ) ;
}
p = rrow [ DB_exp_date ] ; if ( p = = NULL ) p = " undef " ;
BIO_printf ( bio_err , " Expires on :%s \n " , p ) ;
p = rrow [ DB_serial ] ; if ( p = = NULL ) p = " undef " ;
BIO_printf ( bio_err , " Serial Number :%s \n " , p ) ;
p = rrow [ DB_file ] ; if ( p = = NULL ) p = " undef " ;
BIO_printf ( bio_err , " File name :%s \n " , p ) ;
p = rrow [ DB_name ] ; if ( p = = NULL ) p = " undef " ;
BIO_printf ( bio_err , " Subject Name :%s \n " , p ) ;
ok = - 1 ; /* This is now a 'bad' error. */
goto err ;
}
2000-04-13 06:33:22 +00:00
/* We are now totally happy, lets make and sign the certificate */
2000-01-10 06:22:05 +00:00
if ( verbose )
BIO_printf ( bio_err , " Everything appears to be ok, creating and signing the certificate \n " ) ;
if ( ( ret = X509_new ( ) ) = = NULL ) goto err ;
ci = ret - > cert_info ;
# ifdef X509_V3
/* Make it an X509 v3 certificate. */
if ( ! X509_set_version ( x509 , 2 ) ) goto err ;
# endif
if ( BN_to_ASN1_INTEGER ( serial , ci - > serialNumber ) = = NULL )
goto err ;
if ( ! X509_set_issuer_name ( ret , X509_get_subject_name ( x509 ) ) )
goto err ;
BIO_printf ( bio_err , " Certificate is to be certified until " ) ;
if ( strcmp ( startdate , " today " ) = = 0 )
X509_gmtime_adj ( X509_get_notBefore ( ret ) , 0 ) ;
else ASN1_UTCTIME_set_string ( X509_get_notBefore ( ret ) , startdate ) ;
if ( enddate = = NULL )
X509_gmtime_adj ( X509_get_notAfter ( ret ) , ( long ) 60 * 60 * 24 * days ) ;
else ASN1_UTCTIME_set_string ( X509_get_notAfter ( ret ) , enddate ) ;
ASN1_UTCTIME_print ( bio_err , X509_get_notAfter ( ret ) ) ;
if ( days ) BIO_printf ( bio_err , " (%d days) " , days ) ;
BIO_printf ( bio_err , " \n " ) ;
if ( ! X509_set_subject_name ( ret , subject ) ) goto err ;
pktmp = X509_REQ_get_pubkey ( req ) ;
i = X509_set_pubkey ( ret , pktmp ) ;
EVP_PKEY_free ( pktmp ) ;
if ( ! i ) goto err ;
/* Lets add the extensions, if there are any */
if ( ext_sect )
{
X509V3_CTX ctx ;
if ( ci - > version = = NULL )
if ( ( ci - > version = ASN1_INTEGER_new ( ) ) = = NULL )
goto err ;
ASN1_INTEGER_set ( ci - > version , 2 ) ; /* version 3 certificate */
/* Free the current entries if any, there should not
2000-04-13 06:33:22 +00:00
* be any I believe */
2000-01-10 06:22:05 +00:00
if ( ci - > extensions ! = NULL )
sk_X509_EXTENSION_pop_free ( ci - > extensions ,
X509_EXTENSION_free ) ;
ci - > extensions = NULL ;
X509V3_set_ctx ( & ctx , x509 , ret , req , NULL , 0 ) ;
X509V3_set_conf_lhash ( & ctx , lconf ) ;
if ( ! X509V3_EXT_add_conf ( lconf , & ctx , ext_sect , ret ) ) goto err ;
}
if ( ! batch )
{
BIO_printf ( bio_err , " Sign the certificate? [y/n]: " ) ;
( void ) BIO_flush ( bio_err ) ;
buf [ 0 ] = ' \0 ' ;
fgets ( buf , sizeof ( buf ) - 1 , stdin ) ;
if ( ! ( ( buf [ 0 ] = = ' y ' ) | | ( buf [ 0 ] = = ' Y ' ) ) )
{
BIO_printf ( bio_err , " CERTIFICATE WILL NOT BE CERTIFIED \n " ) ;
ok = 0 ;
goto err ;
}
}
# ifndef NO_DSA
if ( pkey - > type = = EVP_PKEY_DSA ) dgst = EVP_dss1 ( ) ;
pktmp = X509_get_pubkey ( ret ) ;
if ( EVP_PKEY_missing_parameters ( pktmp ) & &
! EVP_PKEY_missing_parameters ( pkey ) )
EVP_PKEY_copy_parameters ( pktmp , pkey ) ;
EVP_PKEY_free ( pktmp ) ;
# endif
if ( ! X509_sign ( ret , pkey , dgst ) )
goto err ;
/* We now just add it to the database */
2000-11-13 01:03:58 +00:00
row [ DB_type ] = ( char * ) OPENSSL_malloc ( 2 ) ;
2000-01-10 06:22:05 +00:00
tm = X509_get_notAfter ( ret ) ;
2000-11-13 01:03:58 +00:00
row [ DB_exp_date ] = ( char * ) OPENSSL_malloc ( tm - > length + 1 ) ;
2000-01-10 06:22:05 +00:00
memcpy ( row [ DB_exp_date ] , tm - > data , tm - > length ) ;
row [ DB_exp_date ] [ tm - > length ] = ' \0 ' ;
row [ DB_rev_date ] = NULL ;
/* row[DB_serial] done already */
2000-11-13 01:03:58 +00:00
row [ DB_file ] = ( char * ) OPENSSL_malloc ( 8 ) ;
2000-01-10 06:22:05 +00:00
/* row[DB_name] done already */
if ( ( row [ DB_type ] = = NULL ) | | ( row [ DB_exp_date ] = = NULL ) | |
( row [ DB_file ] = = NULL ) )
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
strcpy ( row [ DB_file ] , " unknown " ) ;
row [ DB_type ] [ 0 ] = ' V ' ;
row [ DB_type ] [ 1 ] = ' \0 ' ;
2000-11-13 01:03:58 +00:00
if ( ( irow = ( char * * ) OPENSSL_malloc ( sizeof ( char * ) * ( DB_NUMBER + 1 ) ) ) = = NULL )
2000-01-10 06:22:05 +00:00
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
for ( i = 0 ; i < DB_NUMBER ; i + + )
{
irow [ i ] = row [ i ] ;
row [ i ] = NULL ;
}
irow [ DB_NUMBER ] = NULL ;
if ( ! TXT_DB_insert ( db , irow ) )
{
BIO_printf ( bio_err , " failed to update database \n " ) ;
BIO_printf ( bio_err , " TXT_DB error number %ld \n " , db - > error ) ;
goto err ;
}
ok = 1 ;
err :
for ( i = 0 ; i < DB_NUMBER ; i + + )
2000-11-13 01:03:58 +00:00
if ( row [ i ] ! = NULL ) OPENSSL_free ( row [ i ] ) ;
2000-01-10 06:22:05 +00:00
if ( CAname ! = NULL )
X509_NAME_free ( CAname ) ;
if ( subject ! = NULL )
X509_NAME_free ( subject ) ;
2000-04-13 06:33:22 +00:00
if ( tmptm ! = NULL )
ASN1_UTCTIME_free ( tmptm ) ;
2000-01-10 06:22:05 +00:00
if ( ok < = 0 )
{
if ( ret ! = NULL ) X509_free ( ret ) ;
ret = NULL ;
}
else
* xret = ret ;
return ( ok ) ;
}
2000-04-13 06:33:22 +00:00
static void write_new_certificate ( BIO * bp , X509 * x , int output_der , int notext )
2000-01-10 06:22:05 +00:00
{
if ( output_der )
{
( void ) i2d_X509_bio ( bp , x ) ;
return ;
}
2000-04-13 06:33:22 +00:00
#if 0
/* ??? Not needed since X509_print prints all this stuff anyway */
2000-01-10 06:22:05 +00:00
f = X509_NAME_oneline ( X509_get_issuer_name ( x ) , buf , 256 ) ;
BIO_printf ( bp , " issuer :%s \n " , f ) ;
f = X509_NAME_oneline ( X509_get_subject_name ( x ) , buf , 256 ) ;
BIO_printf ( bp , " subject:%s \n " , f ) ;
BIO_puts ( bp , " serial : " ) ;
i2a_ASN1_INTEGER ( bp , x - > cert_info - > serialNumber ) ;
BIO_puts ( bp , " \n \n " ) ;
2000-04-13 06:33:22 +00:00
# endif
if ( ! notext ) X509_print ( bp , x ) ;
2000-01-10 06:22:05 +00:00
PEM_write_bio_X509 ( bp , x ) ;
}
static int certify_spkac ( X509 * * xret , char * infile , EVP_PKEY * pkey , X509 * x509 ,
const EVP_MD * dgst , STACK_OF ( CONF_VALUE ) * policy , TXT_DB * db ,
BIGNUM * serial , char * startdate , char * enddate , int days ,
char * ext_sect , LHASH * lconf , int verbose )
{
STACK_OF ( CONF_VALUE ) * sk = NULL ;
LHASH * parms = NULL ;
X509_REQ * req = NULL ;
CONF_VALUE * cv = NULL ;
NETSCAPE_SPKI * spki = NULL ;
X509_REQ_INFO * ri ;
char * type , * buf ;
EVP_PKEY * pktmp = NULL ;
X509_NAME * n = NULL ;
X509_NAME_ENTRY * ne = NULL ;
int ok = - 1 , i , j ;
long errline ;
int nid ;
/*
* Load input file into a hash table . ( This is just an easy
* way to read and parse the file , then put it into a convenient
* STACK format ) .
*/
parms = CONF_load ( NULL , infile , & errline ) ;
if ( parms = = NULL )
{
BIO_printf ( bio_err , " error on line %ld of %s \n " , errline , infile ) ;
ERR_print_errors ( bio_err ) ;
goto err ;
}
sk = CONF_get_section ( parms , " default " ) ;
if ( sk_CONF_VALUE_num ( sk ) = = 0 )
{
BIO_printf ( bio_err , " no name/value pairs found in %s \n " , infile ) ;
CONF_free ( parms ) ;
goto err ;
}
/*
* Now create a dummy X509 request structure . We don ' t actually
* have an X509 request , but we have many of the components
* ( a public key , various DN components ) . The idea is that we
* put these components into the right X509 request structure
* and we can use the same code as if you had a real X509 request .
*/
req = X509_REQ_new ( ) ;
if ( req = = NULL )
{
ERR_print_errors ( bio_err ) ;
goto err ;
}
/*
* Build up the subject name set .
*/
ri = req - > req_info ;
n = ri - > subject ;
for ( i = 0 ; ; i + + )
{
if ( sk_CONF_VALUE_num ( sk ) < = i ) break ;
cv = sk_CONF_VALUE_value ( sk , i ) ;
type = cv - > name ;
2000-04-13 06:33:22 +00:00
/* Skip past any leading X. X: X, etc to allow for
* multiple instances
*/
for ( buf = cv - > name ; * buf ; buf + + )
if ( ( * buf = = ' : ' ) | | ( * buf = = ' , ' ) | | ( * buf = = ' . ' ) ) {
buf + + ;
if ( * buf ) type = buf ;
break ;
}
2000-01-10 06:22:05 +00:00
2000-04-13 06:33:22 +00:00
buf = cv - > value ;
2000-01-10 06:22:05 +00:00
if ( ( nid = OBJ_txt2nid ( type ) ) = = NID_undef )
{
if ( strcmp ( type , " SPKAC " ) = = 0 )
{
2000-04-13 06:33:22 +00:00
spki = NETSCAPE_SPKI_b64_decode ( cv - > value , - 1 ) ;
2000-01-10 06:22:05 +00:00
if ( spki = = NULL )
{
BIO_printf ( bio_err , " unable to load Netscape SPKAC structure \n " ) ;
ERR_print_errors ( bio_err ) ;
goto err ;
}
}
continue ;
}
j = ASN1_PRINTABLE_type ( ( unsigned char * ) buf , - 1 ) ;
if ( fix_data ( nid , & j ) = = 0 )
{
BIO_printf ( bio_err ,
" invalid characters in string %s \n " , buf ) ;
goto err ;
}
if ( ( ne = X509_NAME_ENTRY_create_by_NID ( & ne , nid , j ,
( unsigned char * ) buf ,
strlen ( buf ) ) ) = = NULL )
goto err ;
2000-04-13 06:33:22 +00:00
if ( ! X509_NAME_add_entry ( n , ne , - 1 , 0 ) ) goto err ;
2000-01-10 06:22:05 +00:00
}
if ( spki = = NULL )
{
BIO_printf ( bio_err , " Netscape SPKAC structure not found in %s \n " ,
infile ) ;
goto err ;
}
/*
* Now extract the key from the SPKI structure .
*/
BIO_printf ( bio_err , " Check that the SPKAC request matches the signature \n " ) ;
2000-04-13 06:33:22 +00:00
if ( ( pktmp = NETSCAPE_SPKI_get_pubkey ( spki ) ) = = NULL )
2000-01-10 06:22:05 +00:00
{
BIO_printf ( bio_err , " error unpacking SPKAC public key \n " ) ;
goto err ;
}
j = NETSCAPE_SPKI_verify ( spki , pktmp ) ;
if ( j < = 0 )
{
BIO_printf ( bio_err , " signature verification failed on SPKAC public key \n " ) ;
goto err ;
}
BIO_printf ( bio_err , " Signature ok \n " ) ;
X509_REQ_set_pubkey ( req , pktmp ) ;
EVP_PKEY_free ( pktmp ) ;
ok = do_body ( xret , pkey , x509 , dgst , policy , db , serial , startdate , enddate ,
days , 1 , verbose , req , ext_sect , lconf ) ;
err :
if ( req ! = NULL ) X509_REQ_free ( req ) ;
if ( parms ! = NULL ) CONF_free ( parms ) ;
if ( spki ! = NULL ) NETSCAPE_SPKI_free ( spki ) ;
if ( ne ! = NULL ) X509_NAME_ENTRY_free ( ne ) ;
return ( ok ) ;
}
static int fix_data ( int nid , int * type )
{
if ( nid = = NID_pkcs9_emailAddress )
* type = V_ASN1_IA5STRING ;
if ( ( nid = = NID_commonName ) & & ( * type = = V_ASN1_IA5STRING ) )
* type = V_ASN1_T61STRING ;
if ( ( nid = = NID_pkcs9_challengePassword ) & & ( * type = = V_ASN1_IA5STRING ) )
* type = V_ASN1_T61STRING ;
if ( ( nid = = NID_pkcs9_unstructuredName ) & & ( * type = = V_ASN1_T61STRING ) )
return ( 0 ) ;
if ( nid = = NID_pkcs9_unstructuredName )
* type = V_ASN1_IA5STRING ;
return ( 1 ) ;
}
static int check_time_format ( char * str )
{
ASN1_UTCTIME tm ;
tm . data = ( unsigned char * ) str ;
tm . length = strlen ( str ) ;
tm . type = V_ASN1_UTCTIME ;
return ( ASN1_UTCTIME_check ( & tm ) ) ;
}
static int do_revoke ( X509 * x509 , TXT_DB * db )
{
2000-04-13 06:33:22 +00:00
ASN1_UTCTIME * tm = NULL , * revtm = NULL ;
2000-01-10 06:22:05 +00:00
char * row [ DB_NUMBER ] , * * rrow , * * irow ;
2000-04-13 06:33:22 +00:00
BIGNUM * bn = NULL ;
2000-01-10 06:22:05 +00:00
int ok = - 1 , i ;
for ( i = 0 ; i < DB_NUMBER ; i + + )
row [ i ] = NULL ;
2000-04-13 06:33:22 +00:00
row [ DB_name ] = X509_NAME_oneline ( X509_get_subject_name ( x509 ) , NULL , 0 ) ;
bn = ASN1_INTEGER_to_BN ( X509_get_serialNumber ( x509 ) , NULL ) ;
row [ DB_serial ] = BN_bn2hex ( bn ) ;
BN_free ( bn ) ;
2000-01-10 06:22:05 +00:00
if ( ( row [ DB_name ] = = NULL ) | | ( row [ DB_serial ] = = NULL ) )
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
2000-04-13 06:33:22 +00:00
/* We have to lookup by serial number because name lookup
* skips revoked certs
*/
rrow = TXT_DB_get_by_index ( db , DB_serial , row ) ;
2000-01-10 06:22:05 +00:00
if ( rrow = = NULL )
{
BIO_printf ( bio_err , " Adding Entry to DB for %s \n " , row [ DB_name ] ) ;
/* We now just add it to the database */
2000-11-13 01:03:58 +00:00
row [ DB_type ] = ( char * ) OPENSSL_malloc ( 2 ) ;
2000-01-10 06:22:05 +00:00
tm = X509_get_notAfter ( x509 ) ;
2000-11-13 01:03:58 +00:00
row [ DB_exp_date ] = ( char * ) OPENSSL_malloc ( tm - > length + 1 ) ;
2000-01-10 06:22:05 +00:00
memcpy ( row [ DB_exp_date ] , tm - > data , tm - > length ) ;
row [ DB_exp_date ] [ tm - > length ] = ' \0 ' ;
row [ DB_rev_date ] = NULL ;
/* row[DB_serial] done already */
2000-11-13 01:03:58 +00:00
row [ DB_file ] = ( char * ) OPENSSL_malloc ( 8 ) ;
2000-01-10 06:22:05 +00:00
/* row[DB_name] done already */
if ( ( row [ DB_type ] = = NULL ) | | ( row [ DB_exp_date ] = = NULL ) | |
( row [ DB_file ] = = NULL ) )
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
strcpy ( row [ DB_file ] , " unknown " ) ;
row [ DB_type ] [ 0 ] = ' V ' ;
row [ DB_type ] [ 1 ] = ' \0 ' ;
2000-11-13 01:03:58 +00:00
if ( ( irow = ( char * * ) OPENSSL_malloc ( sizeof ( char * ) * ( DB_NUMBER + 1 ) ) ) = = NULL )
2000-01-10 06:22:05 +00:00
{
2000-11-13 01:03:58 +00:00
BIO_printf ( bio_err , " Memory allocation failure \n " ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
for ( i = 0 ; i < DB_NUMBER ; i + + )
{
irow [ i ] = row [ i ] ;
row [ i ] = NULL ;
}
irow [ DB_NUMBER ] = NULL ;
if ( ! TXT_DB_insert ( db , irow ) )
{
BIO_printf ( bio_err , " failed to update database \n " ) ;
BIO_printf ( bio_err , " TXT_DB error number %ld \n " , db - > error ) ;
goto err ;
}
/* Revoke Certificate */
2000-04-13 06:33:22 +00:00
ok = do_revoke ( x509 , db ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
2000-04-13 06:33:22 +00:00
else if ( index_name_cmp ( row , rrow ) )
2000-01-10 06:22:05 +00:00
{
2000-04-13 06:33:22 +00:00
BIO_printf ( bio_err , " ERROR:name does not match %s \n " ,
row [ DB_name ] ) ;
2000-01-10 06:22:05 +00:00
goto err ;
}
else if ( rrow [ DB_type ] [ 0 ] = = ' R ' )
{
BIO_printf ( bio_err , " ERROR:Already revoked, serial number %s \n " ,
row [ DB_serial ] ) ;
goto err ;
}
else
{
BIO_printf ( bio_err , " Revoking Certificate %s. \n " , rrow [ DB_serial ] ) ;
2000-04-13 06:33:22 +00:00
revtm = ASN1_UTCTIME_new ( ) ;
revtm = X509_gmtime_adj ( revtm , 0 ) ;
2000-01-10 06:22:05 +00:00
rrow [ DB_type ] [ 0 ] = ' R ' ;
rrow [ DB_type ] [ 1 ] = ' \0 ' ;
2000-11-13 01:03:58 +00:00
rrow [ DB_rev_date ] = ( char * ) OPENSSL_malloc ( revtm - > length + 1 ) ;
2000-04-13 06:33:22 +00:00
memcpy ( rrow [ DB_rev_date ] , revtm - > data , revtm - > length ) ;
rrow [ DB_rev_date ] [ revtm - > length ] = ' \0 ' ;
ASN1_UTCTIME_free ( revtm ) ;
2000-01-10 06:22:05 +00:00
}
ok = 1 ;
err :
for ( i = 0 ; i < DB_NUMBER ; i + + )
{
if ( row [ i ] ! = NULL )
2000-11-13 01:03:58 +00:00
OPENSSL_free ( row [ i ] ) ;
2000-01-10 06:22:05 +00:00
}
return ( ok ) ;
}