Implement self-signing in 'openssl ca'. This makes it easier to have

the CA certificate part of the CA database, and combined with
'unique_subject=no', it should make operations like CA certificate
roll-over easier.
This commit is contained in:
Richard Levitte 2003-04-03 22:33:59 +00:00
parent e6526fbf4d
commit 16b1b03543
5 changed files with 88 additions and 44 deletions

View File

@ -4,6 +4,13 @@
Changes between 0.9.7a and 0.9.8 [xx XXX xxxx] Changes between 0.9.7a and 0.9.8 [xx XXX xxxx]
*) Make it possible to create self-signed certificates with 'openssl ca'
in such a way that the self-signed certificate becomes part of the
CA database and uses the same mechanisms for serial number generation
as all other certificate signing. The new flag '-selfsign' enables
this functionality. Adapt CA.sh and CA.pl.in.
[Richard Levitte]
*) Add functionality to check the public key of a certificate request *) Add functionality to check the public key of a certificate request
against a given private. This is useful to check that a certificate against a given private. This is useful to check that a certificate
request can be signed by that key (self-signing). request can be signed by that key (self-signing).

View File

@ -37,7 +37,8 @@
# demoCA ... where everything is stored # demoCA ... where everything is stored
$SSLEAY_CONFIG=$ENV{"SSLEAY_CONFIG"}; $SSLEAY_CONFIG=$ENV{"SSLEAY_CONFIG"};
$DAYS="-days 365"; $DAYS="-days 365"; # 1 year
$CADAYS="-days 1095"; # 3 years
$REQ="openssl req $SSLEAY_CONFIG"; $REQ="openssl req $SSLEAY_CONFIG";
$CA="openssl ca $SSLEAY_CONFIG"; $CA="openssl ca $SSLEAY_CONFIG";
$VERIFY="openssl verify"; $VERIFY="openssl verify";
@ -46,6 +47,7 @@ $PKCS12="openssl pkcs12";
$CATOP="./demoCA"; $CATOP="./demoCA";
$CAKEY="cakey.pem"; $CAKEY="cakey.pem";
$CAREQ="careq.pem";
$CACERT="cacert.pem"; $CACERT="cacert.pem";
$DIRMODE = 0777; $DIRMODE = 0777;
@ -101,8 +103,11 @@ foreach (@ARGV) {
$RET=$?; $RET=$?;
} else { } else {
print "Making CA certificate ...\n"; print "Making CA certificate ...\n";
system ("$REQ -new -x509 -keyout " . system ("$REQ -new -keyout " .
"${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT $DAYS"); "${CATOP}/private/$CAKEY -out ${CATOP}/$CAREQ");
system ("$CA -out ${CATOP}/$CACERT $CADAYS -batch " .
"-keyfile ${CATOP}/private/$CAKEY -selfsign " .
"-infiles ${CATOP}/$CAREQ ");
$RET=$?; $RET=$?;
} }
} }

View File

@ -30,7 +30,8 @@
# default openssl.cnf file has setup as per the following # default openssl.cnf file has setup as per the following
# demoCA ... where everything is stored # demoCA ... where everything is stored
DAYS="-days 365" DAYS="-days 365" # 1 year
CADAYS="-days 1095" # 3 years
REQ="openssl req $SSLEAY_CONFIG" REQ="openssl req $SSLEAY_CONFIG"
CA="openssl ca $SSLEAY_CONFIG" CA="openssl ca $SSLEAY_CONFIG"
VERIFY="openssl verify" VERIFY="openssl verify"
@ -38,6 +39,7 @@ X509="openssl x509"
CATOP=./demoCA CATOP=./demoCA
CAKEY=./cakey.pem CAKEY=./cakey.pem
CAREQ=./careq.pem
CACERT=./cacert.pem CACERT=./cacert.pem
for i for i
@ -70,7 +72,7 @@ case $i in
mkdir ${CATOP}/crl mkdir ${CATOP}/crl
mkdir ${CATOP}/newcerts mkdir ${CATOP}/newcerts
mkdir ${CATOP}/private mkdir ${CATOP}/private
echo "01" > ${CATOP}/serial echo "00" > ${CATOP}/serial
touch ${CATOP}/index.txt touch ${CATOP}/index.txt
fi fi
if [ ! -f ${CATOP}/private/$CAKEY ]; then if [ ! -f ${CATOP}/private/$CAKEY ]; then
@ -83,8 +85,11 @@ case $i in
RET=$? RET=$?
else else
echo "Making CA certificate ..." echo "Making CA certificate ..."
$REQ -new -x509 -keyout ${CATOP}/private/$CAKEY \ $REQ -new -keyout ${CATOP}/private/$CAKEY \
-out ${CATOP}/$CACERT $DAYS -out ${CATOP}/$CAREQ
$CA -out ${CATOP}/$CACERT $CADAYS -batch \
-keyfile ${CATOP}/private/$CAKEY -selfsign \
-infiles ${CATOP}/$CAREQ
RET=$? RET=$?
fi fi
fi fi

View File

@ -204,7 +204,7 @@ static int certify(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509,
BIGNUM *serial, char *subj, int email_dn, char *startdate, BIGNUM *serial, char *subj, int email_dn, char *startdate,
char *enddate, long days, int batch, char *ext_sect, CONF *conf, char *enddate, long days, int batch, char *ext_sect, CONF *conf,
int verbose, unsigned long certopt, unsigned long nameopt, int verbose, unsigned long certopt, unsigned long nameopt,
int default_op, int ext_copy); int default_op, int ext_copy, int selfsign);
static int certify_cert(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509, static int certify_cert(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509,
const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy, const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,
CA_DB *db, BIGNUM *serial, char *subj, int email_dn, CA_DB *db, BIGNUM *serial, char *subj, int email_dn,
@ -225,7 +225,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
int email_dn, char *startdate, char *enddate, long days, int batch, int email_dn, char *startdate, char *enddate, long days, int batch,
int verbose, X509_REQ *req, char *ext_sect, CONF *conf, int verbose, X509_REQ *req, char *ext_sect, CONF *conf,
unsigned long certopt, unsigned long nameopt, int default_op, unsigned long certopt, unsigned long nameopt, int default_op,
int ext_copy); int ext_copy, int selfsign);
static int do_revoke(X509 *x509, CA_DB *db, int ext, char *extval); static int do_revoke(X509 *x509, CA_DB *db, int ext, char *extval);
static int get_certificate_status(const char *ser_status, CA_DB *db); static int get_certificate_status(const char *ser_status, CA_DB *db);
static int do_updatedb(CA_DB *db); static int do_updatedb(CA_DB *db);
@ -292,7 +292,8 @@ int MAIN(int argc, char **argv)
unsigned long nameopt = 0, certopt = 0; unsigned long nameopt = 0, certopt = 0;
int default_op = 1; int default_op = 1;
int ext_copy = EXT_COPY_NONE; int ext_copy = EXT_COPY_NONE;
X509 *x509=NULL; int selfsign = 0;
X509 *x509=NULL, *x509p = NULL;
X509 *x=NULL; X509 *x=NULL;
BIO *in=NULL,*out=NULL,*Sout=NULL,*Cout=NULL; BIO *in=NULL,*out=NULL,*Sout=NULL,*Cout=NULL;
char *dbfile=NULL; char *dbfile=NULL;
@ -406,6 +407,8 @@ EF_ALIGNMENT=0;
if (--argc < 1) goto bad; if (--argc < 1) goto bad;
certfile= *(++argv); certfile= *(++argv);
} }
else if (strcmp(*argv,"-selfsign") == 0)
selfsign=1;
else if (strcmp(*argv,"-in") == 0) else if (strcmp(*argv,"-in") == 0)
{ {
if (--argc < 1) goto bad; if (--argc < 1) goto bad;
@ -700,7 +703,7 @@ bad:
} }
/*****************************************************************/ /*****************************************************************/
/* we definitely need a public key, so let's get it */ /* we definitely need a private key, so let's get it */
if ((keyfile == NULL) && ((keyfile=NCONF_get_string(conf, if ((keyfile == NULL) && ((keyfile=NCONF_get_string(conf,
section,ENV_PRIVATE_KEY)) == NULL)) section,ENV_PRIVATE_KEY)) == NULL))
@ -728,22 +731,27 @@ bad:
/*****************************************************************/ /*****************************************************************/
/* we need a certificate */ /* we need a certificate */
if ((certfile == NULL) && ((certfile=NCONF_get_string(conf, if (!selfsign || spkac_file || ss_cert_file || gencrl)
section,ENV_CERTIFICATE)) == NULL))
{ {
lookup_fail(section,ENV_CERTIFICATE); if ((certfile == NULL)
goto err; && ((certfile=NCONF_get_string(conf,
} section,ENV_CERTIFICATE)) == NULL))
x509=load_cert(bio_err, certfile, FORMAT_PEM, NULL, e, {
"CA certificate"); lookup_fail(section,ENV_CERTIFICATE);
if (x509 == NULL) goto err;
goto err; }
x509=load_cert(bio_err, certfile, FORMAT_PEM, NULL, e,
"CA certificate");
if (x509 == NULL)
goto err;
if (!X509_check_private_key(x509,pkey)) if (!X509_check_private_key(x509,pkey))
{ {
BIO_printf(bio_err,"CA certificate and CA private key do not match\n"); BIO_printf(bio_err,"CA certificate and CA private key do not match\n");
goto err; goto err;
}
} }
if (!selfsign) x509p = x509;
f=NCONF_get_string(conf,BASE_SECTION,ENV_PRESERVE); f=NCONF_get_string(conf,BASE_SECTION,ENV_PRESERVE);
if (f == NULL) if (f == NULL)
@ -1175,10 +1183,10 @@ bad:
if (infile != NULL) if (infile != NULL)
{ {
total++; total++;
j=certify(&x,infile,pkey,x509,dgst,attribs,db, j=certify(&x,infile,pkey,x509p,dgst,attribs,db,
serial,subj,email_dn,startdate,enddate,days,batch, serial,subj,email_dn,startdate,enddate,days,batch,
extensions,conf,verbose, certopt, nameopt, extensions,conf,verbose, certopt, nameopt,
default_op, ext_copy); default_op, ext_copy, selfsign);
if (j < 0) goto err; if (j < 0) goto err;
if (j > 0) if (j > 0)
{ {
@ -1195,10 +1203,10 @@ bad:
for (i=0; i<argc; i++) for (i=0; i<argc; i++)
{ {
total++; total++;
j=certify(&x,argv[i],pkey,x509,dgst,attribs,db, j=certify(&x,argv[i],pkey,x509p,dgst,attribs,db,
serial,subj,email_dn,startdate,enddate,days,batch, serial,subj,email_dn,startdate,enddate,days,batch,
extensions,conf,verbose, certopt, nameopt, extensions,conf,verbose, certopt, nameopt,
default_op, ext_copy); default_op, ext_copy, selfsign);
if (j < 0) goto err; if (j < 0) goto err;
if (j > 0) if (j > 0)
{ {
@ -1515,7 +1523,7 @@ err:
BN_free(serial); BN_free(serial);
free_index(db); free_index(db);
EVP_PKEY_free(pkey); EVP_PKEY_free(pkey);
X509_free(x509); if (x509) X509_free(x509);
X509_CRL_free(crl); X509_CRL_free(crl);
NCONF_free(conf); NCONF_free(conf);
OBJ_cleanup(); OBJ_cleanup();
@ -1533,7 +1541,7 @@ static int certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
BIGNUM *serial, char *subj, int email_dn, char *startdate, char *enddate, BIGNUM *serial, char *subj, int email_dn, char *startdate, char *enddate,
long days, int batch, char *ext_sect, CONF *lconf, int verbose, long days, int batch, char *ext_sect, CONF *lconf, int verbose,
unsigned long certopt, unsigned long nameopt, int default_op, unsigned long certopt, unsigned long nameopt, int default_op,
int ext_copy) int ext_copy, int selfsign)
{ {
X509_REQ *req=NULL; X509_REQ *req=NULL;
BIO *in=NULL; BIO *in=NULL;
@ -1558,6 +1566,12 @@ static int certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
BIO_printf(bio_err,"Check that the request matches the signature\n"); BIO_printf(bio_err,"Check that the request matches the signature\n");
if (selfsign && !X509_REQ_check_private_key(req,pkey))
{
BIO_printf(bio_err,"Certificate request and CA private key do not match\n");
ok=0;
goto err;
}
if ((pktmp=X509_REQ_get_pubkey(req)) == NULL) if ((pktmp=X509_REQ_get_pubkey(req)) == NULL)
{ {
BIO_printf(bio_err,"error unpacking public key\n"); BIO_printf(bio_err,"error unpacking public key\n");
@ -1582,7 +1596,7 @@ static int certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj, email_dn, ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj, email_dn,
startdate,enddate,days,batch,verbose,req,ext_sect,lconf, startdate,enddate,days,batch,verbose,req,ext_sect,lconf,
certopt, nameopt, default_op, ext_copy); certopt, nameopt, default_op, ext_copy, selfsign);
err: err:
if (req != NULL) X509_REQ_free(req); if (req != NULL) X509_REQ_free(req);
@ -1636,7 +1650,7 @@ static int certify_cert(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,email_dn,startdate,enddate, ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,email_dn,startdate,enddate,
days,batch,verbose,rreq,ext_sect,lconf, certopt, nameopt, default_op, days,batch,verbose,rreq,ext_sect,lconf, certopt, nameopt, default_op,
ext_copy); ext_copy, 0);
err: err:
if (rreq != NULL) X509_REQ_free(rreq); if (rreq != NULL) X509_REQ_free(rreq);
@ -1649,7 +1663,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
int email_dn, char *startdate, char *enddate, long days, int batch, int email_dn, char *startdate, char *enddate, long days, int batch,
int verbose, X509_REQ *req, char *ext_sect, CONF *lconf, int verbose, X509_REQ *req, char *ext_sect, CONF *lconf,
unsigned long certopt, unsigned long nameopt, int default_op, unsigned long certopt, unsigned long nameopt, int default_op,
int ext_copy) int ext_copy, int selfsign)
{ {
X509_NAME *name=NULL,*CAname=NULL,*subject=NULL, *dn_subject=NULL; X509_NAME *name=NULL,*CAname=NULL,*subject=NULL, *dn_subject=NULL;
ASN1_UTCTIME *tm,*tmptm; ASN1_UTCTIME *tm,*tmptm;
@ -1753,7 +1767,10 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
} }
/* take a copy of the issuer name before we mess with it. */ /* take a copy of the issuer name before we mess with it. */
CAname=X509_NAME_dup(x509->cert_info->subject); if (selfsign)
CAname=X509_NAME_dup(name);
else
CAname=X509_NAME_dup(x509->cert_info->subject);
if (CAname == NULL) goto err; if (CAname == NULL) goto err;
str=str2=NULL; str=str2=NULL;
@ -1965,8 +1982,16 @@ again2:
if (BN_to_ASN1_INTEGER(serial,ci->serialNumber) == NULL) if (BN_to_ASN1_INTEGER(serial,ci->serialNumber) == NULL)
goto err; goto err;
if (!X509_set_issuer_name(ret,X509_get_subject_name(x509))) if (selfsign)
goto err; {
if (!X509_set_issuer_name(ret,subject))
goto err;
}
else
{
if (!X509_set_issuer_name(ret,X509_get_subject_name(x509)))
goto err;
}
if (strcmp(startdate,"today") == 0) if (strcmp(startdate,"today") == 0)
X509_gmtime_adj(X509_get_notBefore(ret),0); X509_gmtime_adj(X509_get_notBefore(ret),0);
@ -2001,7 +2026,10 @@ again2:
ci->extensions = NULL; ci->extensions = NULL;
/* Initialize the context structure */ /* Initialize the context structure */
X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0); if (selfsign)
X509V3_set_ctx(&ctx, ret, ret, req, NULL, 0);
else
X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0);
if (extconf) if (extconf)
{ {
@ -2344,7 +2372,7 @@ static int certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
EVP_PKEY_free(pktmp); EVP_PKEY_free(pktmp);
ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,email_dn,startdate,enddate, ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,email_dn,startdate,enddate,
days,1,verbose,req,ext_sect,lconf, certopt, nameopt, default_op, days,1,verbose,req,ext_sect,lconf, certopt, nameopt, default_op,
ext_copy); ext_copy, 0);
err: err:
if (req != NULL) X509_REQ_free(req); if (req != NULL) X509_REQ_free(req);
if (parms != NULL) CONF_free(parms); if (parms != NULL) CONF_free(parms);

View File

@ -66,14 +66,13 @@ Section 5 will tell you more on how to handle the certificate you
received. received.
4. Creating a self-signed certificate 4. Creating a self-signed test certificate
If you don't want to deal with another certificate authority, or just If you don't want to deal with another certificate authority, or just
want to create a test certificate for yourself, or are setting up a want to create a test certificate for yourself. This is similar to
certificate authority of your own, you may want to make the requested creating a certificate request, but creates a certificate instead of
certificate a self-signed one. This is similar to creating a a certificate request. This is NOT the recommended way to create a
certificate request, but creates a certificate instead of a CA certificate, see ca.txt.
certificate request (1095 is 3 years):
openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095 openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095