Move CT viewer extension code to crypto/x509v3
[openssl.git] / apps / x509.c
index cea33f58a069fa8279abd6c15f40ff217c9e949c..1b612d17d41d01ebbfd921654b12dac664225563 100644 (file)
 #include <openssl/x509v3.h>
 #include <openssl/objects.h>
 #include <openssl/pem.h>
+#ifndef OPENSSL_NO_RSA
+#include <openssl/rsa.h>
+#endif
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif
 
 #undef PROG
 #define PROG x509_main
@@ -81,7 +87,7 @@
 #define        POSTFIX ".srl"
 #define DEF_DAYS       30
 
-static char *x509_usage[]={
+static const char *x509_usage[]={
 "usage: x509 args\n",
 " -inform arg     - input format - default PEM (one of DER, NET or PEM)\n",
 " -outform arg    - output format - default PEM (one of DER, NET or PEM)\n",
@@ -92,7 +98,15 @@ static char *x509_usage[]={
 " -out arg        - output file - default stdout\n",
 " -passin arg     - private key password source\n",
 " -serial         - print serial number value\n",
-" -hash           - print hash value\n",
+" -subject_hash   - print subject hash value\n",
+#ifndef OPENSSL_NO_MD5
+" -subject_hash_old   - print old-style (MD5) subject hash value\n",
+#endif
+" -issuer_hash    - print issuer hash value\n",
+#ifndef OPENSSL_NO_MD5
+" -issuer_hash_old    - print old-style (MD5) issuer hash value\n",
+#endif
+" -hash           - synonym for -subject_hash\n",
 " -subject        - print subject DN\n",
 " -issuer         - print issuer DN\n",
 " -email          - print email address(es)\n",
@@ -106,6 +120,7 @@ static char *x509_usage[]={
 " -alias          - output certificate alias\n",
 " -noout          - no certificate output\n",
 " -ocspid         - print OCSP hash values for the subject name and public key\n",
+" -ocsp_uri       - print OCSP Responder URL(s)\n",
 " -trustout       - output a \"trusted\" certificate\n",
 " -clrtrust       - clear all trusted purposes\n",
 " -clrreject      - clear all rejected purposes\n",
@@ -135,6 +150,9 @@ static char *x509_usage[]={
 " -engine e       - use engine e, possibly a hardware device.\n",
 #endif
 " -certopt arg    - various certificate text options\n",
+" -checkhost host - check certificate matches \"host\"\n",
+" -checkemail email - check certificate matches \"email\"\n",
+" -checkip ipaddr - check certificate matches \"ipaddr\"\n",
 NULL
 };
 
@@ -142,11 +160,15 @@ static int MS_CALLBACK callb(int ok, X509_STORE_CTX *ctx);
 static int sign (X509 *x, EVP_PKEY *pkey,int days,int clrext, const EVP_MD *digest,
                                                CONF *conf, char *section);
 static int x509_certify (X509_STORE *ctx,char *CAfile,const EVP_MD *digest,
-                        X509 *x,X509 *xca,EVP_PKEY *pkey,char *serial,
-                        int create,int days, int clrext, CONF *conf, char *section,
-                                               ASN1_INTEGER *sno);
+                        X509 *x,X509 *xca,EVP_PKEY *pkey,
+                        STACK_OF(OPENSSL_STRING) *sigopts,
+                        char *serial, int create ,int days, int clrext,
+                        CONF *conf, char *section, ASN1_INTEGER *sno);
 static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt);
 static int reqfile=0;
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+static int force_version=2;
+#endif
 
 int MAIN(int, char **);
 
@@ -157,34 +179,43 @@ int MAIN(int argc, char **argv)
        X509_REQ *req=NULL;
        X509 *x=NULL,*xca=NULL;
        ASN1_OBJECT *objtmp;
-       EVP_PKEY *Upkey=NULL,*CApkey=NULL;
+       STACK_OF(OPENSSL_STRING) *sigopts = NULL;
+       EVP_PKEY *Upkey=NULL,*CApkey=NULL, *fkey = NULL;
        ASN1_INTEGER *sno = NULL;
-       int i,num,badops=0;
+       int i,num,badops=0, badsig=0;
        BIO *out=NULL;
        BIO *STDout=NULL;
        STACK_OF(ASN1_OBJECT) *trust = NULL, *reject = NULL;
        int informat,outformat,keyformat,CAformat,CAkeyformat;
        char *infile=NULL,*outfile=NULL,*keyfile=NULL,*CAfile=NULL;
        char *CAkeyfile=NULL,*CAserial=NULL;
+       char *fkeyfile=NULL;
        char *alias=NULL;
-       int text=0,serial=0,hash=0,subject=0,issuer=0,startdate=0,enddate=0;
-       int ocspid=0;
+       int text=0,serial=0,subject=0,issuer=0,startdate=0,enddate=0;
+       int next_serial=0;
+       int subject_hash=0,issuer_hash=0,ocspid=0;
+#ifndef OPENSSL_NO_MD5
+       int subject_hash_old=0,issuer_hash_old=0;
+#endif
        int noout=0,sign_flag=0,CA_flag=0,CA_createserial=0,email=0;
+       int ocsp_uri=0;
        int trustout=0,clrtrust=0,clrreject=0,aliasout=0,clrext=0;
        int C=0;
        int x509req=0,days=DEF_DAYS,modulus=0,pubkey=0;
        int pprint = 0;
-       char **pp;
+       const char **pp;
        X509_STORE *ctx=NULL;
        X509_REQ *rq=NULL;
        int fingerprint=0;
        char buf[256];
-       const EVP_MD *md_alg,*digest=EVP_md5();
+       const EVP_MD *md_alg,*digest=NULL;
        CONF *extconf = NULL;
        char *extsect = NULL, *extfile = NULL, *passin = NULL, *passargin = NULL;
        int need_rand = 0;
        int checkend=0,checkoffset=0;
        unsigned long nmflag = 0, certflag = 0;
+       unsigned char *checkhost = NULL, *checkemail = NULL;
+       char *checkip = NULL;
 #ifndef OPENSSL_NO_ENGINE
        char *engine=NULL;
 #endif
@@ -214,7 +245,7 @@ int MAIN(int argc, char **argv)
 
        ctx=X509_STORE_new();
        if (ctx == NULL) goto end;
-       X509_STORE_set_verify_cb_func(ctx,callb);
+       X509_STORE_set_verify_cb(ctx,callb);
 
        argc--;
        argv++;
@@ -251,13 +282,29 @@ int MAIN(int argc, char **argv)
                        if (--argc < 1) goto bad;
                        CAkeyformat=str2fmt(*(++argv));
                        }
+               else if (strcmp(*argv,"-sigopt") == 0)
+                       {
+                       if (--argc < 1)
+                               goto bad;
+                       if (!sigopts)
+                               sigopts = sk_OPENSSL_STRING_new_null();
+                       if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, *(++argv)))
+                               goto bad;
+                       }
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+               else if (strcmp(*argv,"-force_version") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       force_version=atoi(*(++argv)) - 1;
+                       }
+#endif
                else if (strcmp(*argv,"-days") == 0)
                        {
                        if (--argc < 1) goto bad;
                        days=atoi(*(++argv));
                        if (days == 0)
                                {
-                               BIO_printf(STDout,"bad number of days\n");
+                               BIO_printf(bio_err,"bad number of days\n");
                                goto bad;
                                }
                        }
@@ -316,6 +363,11 @@ int MAIN(int argc, char **argv)
                        if (!(sno = s2i_ASN1_INTEGER(NULL, *(++argv))))
                                goto bad;
                        }
+               else if (strcmp(*argv,"-force_pubkey") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       fkeyfile= *(++argv);
+                       }
                else if (strcmp(*argv,"-addtrust") == 0)
                        {
                        if (--argc < 1) goto bad;
@@ -358,12 +410,6 @@ int MAIN(int argc, char **argv)
                        if (--argc < 1) goto bad;
                        if (!set_name_ex(&nmflag, *(++argv))) goto bad;
                        }
-               else if (strcmp(*argv,"-setalias") == 0)
-                       {
-                       if (--argc < 1) goto bad;
-                       alias= *(++argv);
-                       trustout = 1;
-                       }
 #ifndef OPENSSL_NO_ENGINE
                else if (strcmp(*argv,"-engine") == 0)
                        {
@@ -375,8 +421,12 @@ int MAIN(int argc, char **argv)
                        C= ++num;
                else if (strcmp(*argv,"-email") == 0)
                        email= ++num;
+               else if (strcmp(*argv,"-ocsp_uri") == 0)
+                       ocsp_uri= ++num;
                else if (strcmp(*argv,"-serial") == 0)
                        serial= ++num;
+               else if (strcmp(*argv,"-next_serial") == 0)
+                       next_serial= ++num;
                else if (strcmp(*argv,"-modulus") == 0)
                        modulus= ++num;
                else if (strcmp(*argv,"-pubkey") == 0)
@@ -385,8 +435,19 @@ int MAIN(int argc, char **argv)
                        x509req= ++num;
                else if (strcmp(*argv,"-text") == 0)
                        text= ++num;
-               else if (strcmp(*argv,"-hash") == 0)
-                       hash= ++num;
+               else if (strcmp(*argv,"-hash") == 0
+                       || strcmp(*argv,"-subject_hash") == 0)
+                       subject_hash= ++num;
+#ifndef OPENSSL_NO_MD5
+               else if (strcmp(*argv,"-subject_hash_old") == 0)
+                       subject_hash_old= ++num;
+#endif
+               else if (strcmp(*argv,"-issuer_hash") == 0)
+                       issuer_hash= ++num;
+#ifndef OPENSSL_NO_MD5
+               else if (strcmp(*argv,"-issuer_hash_old") == 0)
+                       issuer_hash_old= ++num;
+#endif
                else if (strcmp(*argv,"-subject") == 0)
                        subject= ++num;
                else if (strcmp(*argv,"-issuer") == 0)
@@ -410,6 +471,21 @@ int MAIN(int argc, char **argv)
                        checkoffset=atoi(*(++argv));
                        checkend=1;
                        }
+               else if (strcmp(*argv,"-checkhost") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       checkhost=(unsigned char *)*(++argv);
+                       }
+               else if (strcmp(*argv,"-checkemail") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       checkemail=(unsigned char *)*(++argv);
+                       }
+               else if (strcmp(*argv,"-checkip") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       checkip=*(++argv);
+                       }
                else if (strcmp(*argv,"-noout") == 0)
                        noout= ++num;
                else if (strcmp(*argv,"-trustout") == 0)
@@ -433,6 +509,8 @@ int MAIN(int argc, char **argv)
 #endif
                else if (strcmp(*argv,"-ocspid") == 0)
                        ocspid= ++num;
+               else if (strcmp(*argv,"-badsig") == 0)
+                       badsig = 1;
                else if ((md_alg=EVP_get_digestbyname(*argv + 1)))
                        {
                        /* ok */
@@ -477,6 +555,13 @@ bad:
                goto end;
                }
 
+       if (fkeyfile)
+               {
+               fkey = load_pubkey(bio_err, fkeyfile, keyformat, 0,
+                                               NULL, e, "Forced key");
+               if (fkey == NULL) goto end;
+               }
+
        if ((CAkeyfile == NULL) && (CA_flag) && (CAformat == FORMAT_PEM))
                { CAkeyfile=CAfile; }
        else if ((CA_flag) && (CAkeyfile == NULL))
@@ -527,7 +612,6 @@ bad:
        if (reqfile)
                {
                EVP_PKEY *pkey;
-               X509_CINF *ci;
                BIO *in;
 
                if (!sign_flag && !CA_flag)
@@ -595,23 +679,33 @@ bad:
                print_name(bio_err, "subject=", X509_REQ_get_subject_name(req), nmflag);
 
                if ((x=X509_new()) == NULL) goto end;
-               ci=x->cert_info;
 
-               if (sno)
+               if (sno == NULL)
                        {
-                       if (!X509_set_serialNumber(x, sno))
+                       sno = ASN1_INTEGER_new();
+                       if (!sno || !rand_serial(NULL, sno))
                                goto end;
+                       if (!X509_set_serialNumber(x, sno)) 
+                               goto end;
+                       ASN1_INTEGER_free(sno);
+                       sno = NULL;
                        }
-               else if (!ASN1_INTEGER_set(X509_get_serialNumber(x),0)) goto end;
+               else if (!X509_set_serialNumber(x, sno)) 
+                       goto end;
+
                if (!X509_set_issuer_name(x,req->req_info->subject)) goto end;
                if (!X509_set_subject_name(x,req->req_info->subject)) goto end;
 
                X509_gmtime_adj(X509_get_notBefore(x),0);
-               X509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*days);
-
-               pkey = X509_REQ_get_pubkey(req);
-               X509_set_pubkey(x,pkey);
-               EVP_PKEY_free(pkey);
+               X509_time_adj_ex(X509_get_notAfter(x),days, 0, NULL);
+               if (fkey)
+                       X509_set_pubkey(x, fkey);
+               else
+                       {
+                       pkey = X509_REQ_get_pubkey(req);
+                       X509_set_pubkey(x,pkey);
+                       EVP_PKEY_free(pkey);
+                       }
                }
        else
                x=load_cert(bio_err,infile,informat,NULL,e,"Certificate");
@@ -623,7 +717,7 @@ bad:
                if (xca == NULL) goto end;
                }
 
-       if (!noout || text)
+       if (!noout || text || next_serial)
                {
                OBJ_create("2.99999.3",
                        "SET.ex3","SET x509v3 extension 3");
@@ -694,16 +788,39 @@ bad:
                        else if (serial == i)
                                {
                                BIO_printf(STDout,"serial=");
-                               i2a_ASN1_INTEGER(STDout,x->cert_info->serialNumber);
+                               i2a_ASN1_INTEGER(STDout,
+                                       X509_get_serialNumber(x));
                                BIO_printf(STDout,"\n");
                                }
-                       else if (email == i) 
+                       else if (next_serial == i)
+                               {
+                               BIGNUM *bnser;
+                               ASN1_INTEGER *ser;
+                               ser = X509_get_serialNumber(x);
+                               bnser = ASN1_INTEGER_to_BN(ser, NULL);
+                               if (!bnser)
+                                       goto end;
+                               if (!BN_add_word(bnser, 1))
+                                       goto end;
+                               ser = BN_to_ASN1_INTEGER(bnser, NULL);
+                               if (!ser)
+                                       goto end;
+                               BN_free(bnser);
+                               i2a_ASN1_INTEGER(out, ser);
+                               ASN1_INTEGER_free(ser);
+                               BIO_puts(out, "\n");
+                               }
+                       else if ((email == i) || (ocsp_uri == i))
                                {
                                int j;
-                               STACK *emlst;
-                               emlst = X509_get1_email(x);
-                               for (j = 0; j < sk_num(emlst); j++)
-                                       BIO_printf(STDout, "%s\n", sk_value(emlst, j));
+                               STACK_OF(OPENSSL_STRING) *emlst;
+                               if (email == i)
+                                       emlst = X509_get1_email(x);
+                               else
+                                       emlst = X509_get1_ocsp(x);
+                               for (j = 0; j < sk_OPENSSL_STRING_num(emlst); j++)
+                                       BIO_printf(STDout, "%s\n",
+                                                  sk_OPENSSL_STRING_value(emlst, j));
                                X509_email_free(emlst);
                                }
                        else if (aliasout == i)
@@ -713,10 +830,26 @@ bad:
                                if (alstr) BIO_printf(STDout,"%s\n", alstr);
                                else BIO_puts(STDout,"<No Alias>\n");
                                }
-                       else if (hash == i)
+                       else if (subject_hash == i)
                                {
                                BIO_printf(STDout,"%08lx\n",X509_subject_name_hash(x));
                                }
+#ifndef OPENSSL_NO_MD5
+                       else if (subject_hash_old == i)
+                               {
+                               BIO_printf(STDout,"%08lx\n",X509_subject_name_hash_old(x));
+                               }
+#endif
+                       else if (issuer_hash == i)
+                               {
+                               BIO_printf(STDout,"%08lx\n",X509_issuer_name_hash(x));
+                               }
+#ifndef OPENSSL_NO_MD5
+                       else if (issuer_hash_old == i)
+                               {
+                               BIO_printf(STDout,"%08lx\n",X509_issuer_name_hash_old(x));
+                               }
+#endif
                        else if (pprint == i)
                                {
                                X509_PURPOSE *ptmp;
@@ -828,7 +961,7 @@ bad:
                                }
                        else if (text == i)
                                {
-                               X509_print_ex(out,x,nmflag, certflag);
+                               X509_print_ex(STDout,x,nmflag, certflag);
                                }
                        else if (startdate == i)
                                {
@@ -847,14 +980,18 @@ bad:
                                int j;
                                unsigned int n;
                                unsigned char md[EVP_MAX_MD_SIZE];
+                               const EVP_MD *fdig = digest;
+
+                               if (!fdig)
+                                       fdig = EVP_sha1();
 
-                               if (!X509_digest(x,digest,md,&n))
+                               if (!X509_digest(x,fdig,md,&n))
                                        {
                                        BIO_printf(bio_err,"out of memory\n");
                                        goto end;
                                        }
                                BIO_printf(STDout,"%s Fingerprint=",
-                                               OBJ_nid2sn(EVP_MD_type(digest)));
+                                               OBJ_nid2sn(EVP_MD_type(fdig)));
                                for (j=0; j<(int)n; j++)
                                        {
                                        BIO_printf(STDout,"%02X%c",md[j],
@@ -874,14 +1011,6 @@ bad:
                                                passin, e, "Private key");
                                        if (Upkey == NULL) goto end;
                                        }
-#ifndef OPENSSL_NO_DSA
-                               if (Upkey->type == EVP_PKEY_DSA)
-                                       digest=EVP_dss1();
-#endif
-#ifndef OPENSSL_NO_ECDSA
-                               if (Upkey->type == EVP_PKEY_EC)
-                                       digest=EVP_ecdsa();
-#endif
 
                                assert(need_rand);
                                if (!sign(x,Upkey,days,clrext,digest,
@@ -898,18 +1027,11 @@ bad:
                                                "CA Private Key");
                                        if (CApkey == NULL) goto end;
                                        }
-#ifndef OPENSSL_NO_DSA
-                               if (CApkey->type == EVP_PKEY_DSA)
-                                       digest=EVP_dss1();
-#endif
-#ifndef OPENSSL_NO_ECDSA
-                               if (CApkey->type == EVP_PKEY_EC)
-                                       digest = EVP_ecdsa();
-#endif
                                
                                assert(need_rand);
                                if (!x509_certify(ctx,CAfile,digest,x,xca,
-                                       CApkey, CAserial,CA_createserial,days, clrext,
+                                       CApkey, sigopts,
+                                       CAserial,CA_createserial,days, clrext,
                                        extconf, extsect, sno))
                                        goto end;
                                }
@@ -926,22 +1048,13 @@ bad:
                                else
                                        {
                                        pk=load_key(bio_err,
-                                               keyfile, FORMAT_PEM, 0,
+                                               keyfile, keyformat, 0,
                                                passin, e, "request key");
                                        if (pk == NULL) goto end;
                                        }
 
                                BIO_printf(bio_err,"Generating certificate request\n");
 
-#ifndef OPENSSL_NO_DSA
-                               if (pk->type == EVP_PKEY_DSA)
-                                       digest=EVP_dss1();
-#endif
-#ifndef OPENSSL_NO_ECDSA
-                               if (pk->type == EVP_PKEY_EC)
-                                       digest=EVP_ecdsa();
-#endif
-
                                rq=X509_to_X509_REQ(x,pk,digest);
                                EVP_PKEY_free(pk);
                                if (rq == NULL)
@@ -965,9 +1078,9 @@ bad:
 
        if (checkend)
                {
-               time_t tnow=time(NULL);
+               time_t tcheck=time(NULL) + checkoffset;
 
-               if (ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(x), tnow+checkoffset) == -1)
+               if (X509_cmp_time(X509_get_notAfter(x), &tcheck) < 0)
                        {
                        BIO_printf(out,"Certificate will expire\n");
                        ret=1;
@@ -980,12 +1093,17 @@ bad:
                goto end;
                }
 
+       print_cert_checks(STDout, x, checkhost, checkemail, checkip);
+
        if (noout)
                {
                ret=0;
                goto end;
                }
 
+       if (badsig)
+               x->signature->data[x->signature->length - 1] ^= 0x1;
+
        if      (outformat == FORMAT_ASN1)
                i=i2d_X509_bio(out,x);
        else if (outformat == FORMAT_PEM)
@@ -995,17 +1113,15 @@ bad:
                }
        else if (outformat == FORMAT_NETSCAPE)
                {
-               ASN1_HEADER ah;
-               ASN1_OCTET_STRING os;
+               NETSCAPE_X509 nx;
+               ASN1_OCTET_STRING hdr;
 
-               os.data=(unsigned char *)NETSCAPE_CERT_HDR;
-               os.length=strlen(NETSCAPE_CERT_HDR);
-               ah.header= &os;
-               ah.data=(char *)x;
-               ah.meth=X509_asn1_meth();
+               hdr.data=(unsigned char *)NETSCAPE_CERT_HDR;
+               hdr.length=strlen(NETSCAPE_CERT_HDR);
+               nx.header= &hdr;
+               nx.cert=x;
 
-               /* no macro for this one yet */
-               i=ASN1_i2d_bio(i2d_ASN1_HEADER,out,(unsigned char *)&ah);
+               i=ASN1_item_i2d_bio(ASN1_ITEM_rptr(NETSCAPE_X509),out,&nx);
                }
        else    {
                BIO_printf(bio_err,"bad output format specified for outfile\n");
@@ -1031,6 +1147,9 @@ end:
        X509_free(xca);
        EVP_PKEY_free(Upkey);
        EVP_PKEY_free(CApkey);
+       EVP_PKEY_free(fkey);
+       if (sigopts)
+               sk_OPENSSL_STRING_free(sigopts);
        X509_REQ_free(rq);
        ASN1_INTEGER_free(sno);
        sk_ASN1_OBJECT_pop_free(trust, ASN1_OBJECT_free);
@@ -1040,110 +1159,52 @@ end:
        OPENSSL_EXIT(ret);
        }
 
-static ASN1_INTEGER *load_serial(char *CAfile, char *serialfile, int create)
+static ASN1_INTEGER *x509_load_serial(char *CAfile, char *serialfile, int create)
        {
        char *buf = NULL, *p;
-       MS_STATIC char buf2[1024];
-       ASN1_INTEGER *bs = NULL, *bs2 = NULL;
-       BIO *io = NULL;
+       ASN1_INTEGER *bs = NULL;
        BIGNUM *serial = NULL;
+       size_t len;
 
-       buf=OPENSSL_malloc( ((serialfile == NULL)
-                       ?(strlen(CAfile)+strlen(POSTFIX)+1)
-                       :(strlen(serialfile)))+1);
+       len = ((serialfile == NULL)
+               ?(strlen(CAfile)+strlen(POSTFIX)+1)
+               :(strlen(serialfile)))+1;
+       buf=OPENSSL_malloc(len);
        if (buf == NULL) { BIO_printf(bio_err,"out of mem\n"); goto end; }
        if (serialfile == NULL)
                {
-               strcpy(buf,CAfile);
+               BUF_strlcpy(buf,CAfile,len);
                for (p=buf; *p; p++)
                        if (*p == '.')
                                {
                                *p='\0';
                                break;
                                }
-               strcat(buf,POSTFIX);
+               BUF_strlcat(buf,POSTFIX,len);
                }
        else
-               strcpy(buf,serialfile);
-       serial=BN_new();
-       bs=ASN1_INTEGER_new();
-       if ((serial == NULL) || (bs == NULL))
-               {
-               ERR_print_errors(bio_err);
-               goto end;
-               }
+               BUF_strlcpy(buf,serialfile,len);
 
-       io=BIO_new(BIO_s_file());
-       if (io == NULL)
-               {
-               ERR_print_errors(bio_err);
-               goto end;
-               }
-       
-       if (BIO_read_filename(io,buf) <= 0)
-               {
-               if (!create)
-                       {
-                       perror(buf);
-                       goto end;
-                       }
-               else
-                       {
-                       ASN1_INTEGER_set(bs,1);
-                       BN_one(serial);
-                       }
-               }
-       else 
-               {
-               if (!a2i_ASN1_INTEGER(io,bs,buf2,sizeof buf2))
-                       {
-                       BIO_printf(bio_err,"unable to load serial number from %s\n",buf);
-                       ERR_print_errors(bio_err);
-                       goto end;
-                       }
-               else
-                       {
-                       serial=BN_bin2bn(bs->data,bs->length,serial);
-                       if (serial == NULL)
-                               {
-                               BIO_printf(bio_err,"error converting bin 2 bn");
-                               goto end;
-                               }
-                       }
-               }
+       serial = load_serial(buf, create, NULL);
+       if (serial == NULL) goto end;
 
        if (!BN_add_word(serial,1))
                { BIO_printf(bio_err,"add_word failure\n"); goto end; }
-       if (!(bs2 = BN_to_ASN1_INTEGER(serial, NULL)))
-               { BIO_printf(bio_err,"error converting bn 2 asn1_integer\n"); goto end; }
-       if (BIO_write_filename(io,buf) <= 0)
-               {
-               BIO_printf(bio_err,"error attempting to write serial number file\n");
-               perror(buf);
-               goto end;
-               }
-       i2a_ASN1_INTEGER(io,bs2);
-       BIO_puts(io,"\n");
 
-       BIO_free(io);
-       if (buf) OPENSSL_free(buf);
-       ASN1_INTEGER_free(bs2);
-       BN_free(serial);
-       io=NULL;
-       return bs;
+       if (!save_serial(buf, NULL, serial, &bs)) goto end;
 
      end:
+ end:
        if (buf) OPENSSL_free(buf);
-       BIO_free(io);
-       ASN1_INTEGER_free(bs);
        BN_free(serial);
-       return NULL;
-
+       return bs;
        }
 
 static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest,
-            X509 *x, X509 *xca, EVP_PKEY *pkey, char *serialfile, int create,
-            int days, int clrext, CONF *conf, char *section, ASN1_INTEGER *sno)
+                       X509 *x, X509 *xca, EVP_PKEY *pkey,
+                       STACK_OF(OPENSSL_STRING) *sigopts,
+                       char *serialfile, int create,
+                       int days, int clrext, CONF *conf, char *section,
+                       ASN1_INTEGER *sno)
        {
        int ret=0;
        ASN1_INTEGER *bs=NULL;
@@ -1160,15 +1221,16 @@ static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest,
                goto end;
                }
        if (sno) bs = sno;
-       else if (!(bs = load_serial(CAfile, serialfile, create)))
+       else if (!(bs = x509_load_serial(CAfile, serialfile, create)))
                goto end;
 
-       if (!X509_STORE_add_cert(ctx,x)) goto end;
+/*     if (!X509_STORE_add_cert(ctx,x)) goto end;*/
 
        /* NOTE: this certificate can/should be self signed, unless it was
         * a certificate request in which case it is not. */
        X509_STORE_CTX_set_cert(&xsc,x);
-       if (!reqfile && !X509_verify_cert(&xsc))
+       X509_STORE_CTX_set_flags(&xsc, X509_V_FLAG_CHECK_SS_SIGNATURE);
+       if (!reqfile && X509_verify_cert(&xsc) <= 0)
                goto end;
 
        if (!X509_check_private_key(xca,pkey))
@@ -1184,7 +1246,7 @@ static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest,
                goto end;
 
        /* hardwired expired */
-       if (X509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*days) == NULL)
+       if (X509_time_adj_ex(X509_get_notAfter(x),days, 0, NULL) == NULL)
                goto end;
 
        if (clrext)
@@ -1195,13 +1257,18 @@ static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest,
        if (conf)
                {
                X509V3_CTX ctx2;
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+               X509_set_version(x, force_version);
+#else
                X509_set_version(x,2); /* version 3 certificate */
+#endif
                 X509V3_set_ctx(&ctx2, xca, x, NULL, NULL, 0);
                 X509V3_set_nconf(&ctx2, conf);
                 if (!X509V3_EXT_add_nconf(conf, &ctx2, section, x)) goto end;
                }
 
-       if (!X509_sign(x,pkey,digest)) goto end;
+       if (!do_X509_sign(bio_err, x, pkey, digest, sigopts))
+               goto end;
        ret=1;
 end:
        X509_STORE_CTX_cleanup(&xsc);
@@ -1272,7 +1339,11 @@ static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, const EVP_MD *dig
        if (conf)
                {
                X509V3_CTX ctx;
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+               X509_set_version(x, force_version);
+#else
                X509_set_version(x,2); /* version 3 certificate */
+#endif
                 X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0);
                 X509V3_set_nconf(&ctx, conf);
                 if (!X509V3_EXT_add_nconf(conf, &ctx, section, x)) goto err;