Bugfix: previously the serial number file could turn negative
[openssl.git] / apps / x509.c
index 3bef1fc590a62342c72314ff65e824eb47e4b0c5..391bb3eef9504521a8a567ed4a2323bf9d797861 100644 (file)
@@ -60,7 +60,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#ifdef NO_STDIO
+#ifdef OPENSSL_NO_STDIO
 #define APPS_WIN16
 #endif
 #include "apps.h"
@@ -73,6 +73,7 @@
 #include <openssl/x509v3.h>
 #include <openssl/objects.h>
 #include <openssl/pem.h>
+#include <openssl/engine.h>
 
 #undef PROG
 #define PROG x509_main
@@ -105,6 +106,7 @@ static char *x509_usage[]={
 " -fingerprint    - print the certificate fingerprint\n",
 " -alias          - output certificate alias\n",
 " -noout          - no certificate output\n",
+" -ocspid         - print OCSP hash values for the subject name and public key\n",
 " -trustout       - output a \"trusted\" certificate\n",
 " -clrtrust       - clear all trusted purposes\n",
 " -clrreject      - clear all rejected purposes\n",
@@ -122,6 +124,7 @@ static char *x509_usage[]={
 "                   missing, it is assumed to be in the CA file.\n",
 " -CAcreateserial - create serial number file if it does not exist\n",
 " -CAserial       - serial file\n",
+" -set_serial     - serial number to use\n",
 " -text           - print the certificate in text form\n",
 " -C              - print out C code forms\n",
 " -md2/-md5/-sha1/-mdc2 - digest to use\n",
@@ -129,6 +132,7 @@ static char *x509_usage[]={
 " -extensions     - section from config file with X509V3 extensions to add\n",
 " -clrext         - delete extensions before signing and input certificate\n",
 " -nameopt arg    - various certificate name options\n",
+" -engine e       - use engine e, possibly a hardware device.\n",
 " -certopt arg    - various certificate text options\n",
 NULL
 };
@@ -138,7 +142,8 @@ static int sign (X509 *x, EVP_PKEY *pkey,int days,int clrext, const EVP_MD *dige
                                                LHASH *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, LHASH *conf, char *section);
+                        int create,int days, int clrext, LHASH *conf, char *section,
+                                               ASN1_INTEGER *sno);
 static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt);
 static int reqfile=0;
 
@@ -146,11 +151,13 @@ int MAIN(int, char **);
 
 int MAIN(int argc, char **argv)
        {
+       ENGINE *e = NULL;
        int ret=1;
        X509_REQ *req=NULL;
        X509 *x=NULL,*xca=NULL;
        ASN1_OBJECT *objtmp;
        EVP_PKEY *Upkey=NULL,*CApkey=NULL;
+       ASN1_INTEGER *sno = NULL;
        int i,num,badops=0;
        BIO *out=NULL;
        BIO *STDout=NULL;
@@ -160,6 +167,7 @@ int MAIN(int argc, char **argv)
        char *CAkeyfile=NULL,*CAserial=NULL;
        char *alias=NULL;
        int text=0,serial=0,hash=0,subject=0,issuer=0,startdate=0,enddate=0;
+       int ocspid=0;
        int noout=0,sign_flag=0,CA_flag=0,CA_createserial=0,email=0;
        int trustout=0,clrtrust=0,clrreject=0,aliasout=0,clrext=0;
        int C=0;
@@ -176,6 +184,7 @@ int MAIN(int argc, char **argv)
        int need_rand = 0;
        int checkend=0,checkoffset=0;
        unsigned long nmflag = 0, certflag = 0;
+       char *engine=NULL;
 
        reqfile=0;
 
@@ -184,7 +193,7 @@ int MAIN(int argc, char **argv)
        if (bio_err == NULL)
                bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
        STDout=BIO_new_fp(stdout,BIO_NOCLOSE);
-#ifdef VMS
+#ifdef OPENSSL_SYS_VMS
        {
        BIO *tmpbio = BIO_new(BIO_f_linebuffer());
        STDout = BIO_push(tmpbio, STDout);
@@ -295,6 +304,12 @@ int MAIN(int argc, char **argv)
                        if (--argc < 1) goto bad;
                        CAserial= *(++argv);
                        }
+               else if (strcmp(*argv,"-set_serial") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       if (!(sno = s2i_ASN1_INTEGER(NULL, *(++argv))))
+                               goto bad;
+                       }
                else if (strcmp(*argv,"-addtrust") == 0)
                        {
                        if (--argc < 1) goto bad;
@@ -343,6 +358,11 @@ int MAIN(int argc, char **argv)
                        alias= *(++argv);
                        trustout = 1;
                        }
+               else if (strcmp(*argv,"-engine") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       engine= *(++argv);
+                       }
                else if (strcmp(*argv,"-C") == 0)
                        C= ++num;
                else if (strcmp(*argv,"-email") == 0)
@@ -403,6 +423,8 @@ int MAIN(int argc, char **argv)
                        clrext = 1;
                        }
 #endif
+               else if (strcmp(*argv,"-ocspid") == 0)
+                       ocspid= ++num;
                else if ((md_alg=EVP_get_digestbyname(*argv + 1)))
                        {
                        /* ok */
@@ -422,10 +444,28 @@ int MAIN(int argc, char **argv)
                {
 bad:
                for (pp=x509_usage; (*pp != NULL); pp++)
-                       BIO_printf(bio_err,*pp);
+                       BIO_printf(bio_err,"%s",*pp);
                goto end;
                }
 
+       if (engine != NULL)
+               {
+               if((e = ENGINE_by_id(engine)) == NULL)
+                       {
+                       BIO_printf(bio_err,"invalid engine \"%s\"\n",
+                               engine);
+                       goto end;
+                       }
+               if(!ENGINE_set_default(e, ENGINE_METHOD_ALL))
+                       {
+                       BIO_printf(bio_err,"can't use that engine\n");
+                       goto end;
+                       }
+               BIO_printf(bio_err,"engine \"%s\" set.\n", engine);
+               /* Free our "structural" reference. */
+               ENGINE_free(e);
+               }
+
        if (need_rand)
                app_RAND_load_file(NULL, bio_err, 0);
 
@@ -467,8 +507,15 @@ bad:
                                                        ,errorline,extfile);
                        goto end;
                        }
-               if (!extsect && !(extsect = CONF_get_string(extconf, "default",
-                                        "extensions"))) extsect = "default";
+               if (!extsect)
+                       {
+                       extsect = CONF_get_string(extconf, "default", "extensions");
+                       if (!extsect)
+                               {
+                               ERR_clear_error();
+                               extsect = "default";
+                               }
+                       }
                X509V3_set_ctx_test(&ctx2);
                X509V3_set_conf_lhash(&ctx2, extconf);
                if (!X509V3_EXT_add_conf(extconf, &ctx2, extsect, NULL))
@@ -555,7 +602,12 @@ bad:
                if ((x=X509_new()) == NULL) goto end;
                ci=x->cert_info;
 
-               if (!ASN1_INTEGER_set(X509_get_serialNumber(x),0)) goto end;
+               if (sno)
+                       {
+                       if (!X509_set_serialNumber(x, sno))
+                               goto end;
+                       }
+               else if (!ASN1_INTEGER_set(X509_get_serialNumber(x),0)) 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;
 
@@ -590,7 +642,7 @@ bad:
                if (outfile == NULL)
                        {
                        BIO_set_fp(out,stdout,BIO_NOCLOSE);
-#ifdef VMS
+#ifdef OPENSSL_SYS_VMS
                        {
                        BIO *tmpbio = BIO_new(BIO_f_linebuffer());
                        out = BIO_push(tmpbio, out);
@@ -694,12 +746,12 @@ bad:
                                        goto end;
                                        }
                                BIO_printf(STDout,"Modulus=");
-#ifndef NO_RSA
+#ifndef OPENSSL_NO_RSA
                                if (pkey->type == EVP_PKEY_RSA)
                                        BN_print(STDout,pkey->pkey.rsa->n);
                                else
 #endif
-#ifndef NO_DSA
+#ifndef OPENSSL_NO_DSA
                                if (pkey->type == EVP_PKEY_DSA)
                                        BN_print(STDout,pkey->pkey.dsa->pub_key);
                                else
@@ -822,10 +874,10 @@ bad:
                                if (Upkey == NULL)
                                        {
                                        Upkey=load_key(bio_err,
-                                               keyfile,keyformat, passin);
+                                               keyfile,keyformat, passin, e);
                                        if (Upkey == NULL) goto end;
                                        }
-#ifndef NO_DSA
+#ifndef OPENSSL_NO_DSA
                                if (Upkey->type == EVP_PKEY_DSA)
                                        digest=EVP_dss1();
 #endif
@@ -840,10 +892,11 @@ bad:
                                if (CAkeyfile != NULL)
                                        {
                                        CApkey=load_key(bio_err,
-                                               CAkeyfile,CAkeyformat, passin);
+                                               CAkeyfile,CAkeyformat, passin,
+                                               e);
                                        if (CApkey == NULL) goto end;
                                        }
-#ifndef NO_DSA
+#ifndef OPENSSL_NO_DSA
                                if (CApkey->type == EVP_PKEY_DSA)
                                        digest=EVP_dss1();
 #endif
@@ -851,7 +904,7 @@ bad:
                                assert(need_rand);
                                if (!x509_certify(ctx,CAfile,digest,x,xca,
                                        CApkey, CAserial,CA_createserial,days, clrext,
-                                       extconf, extsect))
+                                       extconf, extsect, sno))
                                        goto end;
                                }
                        else if (x509req == i)
@@ -867,7 +920,7 @@ bad:
                                else
                                        {
                                        pk=load_key(bio_err,
-                                               keyfile,FORMAT_PEM, passin);
+                                               keyfile,FORMAT_PEM, passin, e);
                                        if (pk == NULL) goto end;
                                        }
 
@@ -890,6 +943,10 @@ bad:
                                        }
                                noout=1;
                                }
+                       else if (ocspid == i)
+                               {
+                               X509_ocspid_print(out, x);
+                               }
                        }
                }
 
@@ -962,32 +1019,22 @@ end:
        EVP_PKEY_free(Upkey);
        EVP_PKEY_free(CApkey);
        X509_REQ_free(rq);
+       ASN1_INTEGER_free(sno);
        sk_ASN1_OBJECT_pop_free(trust, ASN1_OBJECT_free);
        sk_ASN1_OBJECT_pop_free(reject, ASN1_OBJECT_free);
        if (passin) OPENSSL_free(passin);
        EXIT(ret);
        }
 
-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, LHASH *conf, char *section)
+static ASN1_INTEGER *load_serial(char *CAfile, char *serialfile, int create)
        {
-       int ret=0;
-       BIO *io=NULL;
+       char *buf = NULL, *p;
        MS_STATIC char buf2[1024];
-       char *buf=NULL,*p;
-       BIGNUM *serial=NULL;
-       ASN1_INTEGER *bs=NULL,bs2;
-       X509_STORE_CTX xsc;
-       EVP_PKEY *upkey;
+       ASN1_INTEGER *bs = NULL, *bs2 = NULL;
+       BIO *io = NULL;
+       BIGNUM *serial = NULL;
 
-       upkey = X509_get_pubkey(xca);
-       EVP_PKEY_copy_parameters(upkey,pkey);
-       EVP_PKEY_free(upkey);
-
-       X509_STORE_CTX_init(&xsc,ctx,x,NULL);
-       buf=OPENSSL_malloc(EVP_PKEY_size(pkey)*2+
-               ((serialfile == NULL)
+       buf=OPENSSL_malloc( ((serialfile == NULL)
                        ?(strlen(CAfile)+strlen(POSTFIX)+1)
                        :(strlen(serialfile)))+1);
        if (buf == NULL) { BIO_printf(bio_err,"out of mem\n"); goto end; }
@@ -1053,20 +1100,51 @@ static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest,
 
        if (!BN_add_word(serial,1))
                { BIO_printf(bio_err,"add_word failure\n"); goto end; }
-       bs2.data=(unsigned char *)buf2;
-       bs2.length=BN_bn2bin(serial,bs2.data);
-
+       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);
+       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;
+
+       end:
+       if (buf) OPENSSL_free(buf);
+       BIO_free(io);
+       ASN1_INTEGER_free(bs);
+       BN_free(serial);
+       return NULL;
+
+       }
+
+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, LHASH *conf, char *section, ASN1_INTEGER *sno)
+       {
+       int ret=0;
+       ASN1_INTEGER *bs=NULL;
+       X509_STORE_CTX xsc;
+       EVP_PKEY *upkey;
+
+       upkey = X509_get_pubkey(xca);
+       EVP_PKEY_copy_parameters(upkey,pkey);
+       EVP_PKEY_free(upkey);
+
+       X509_STORE_CTX_init(&xsc,ctx,x,NULL);
+       if (sno) bs = sno;
+       else if (!(bs = load_serial(CAfile, serialfile, create)))
+               goto end;
+
        if (!X509_STORE_add_cert(ctx,x)) goto end;
 
        /* NOTE: this certificate can/should be self signed, unless it was
@@ -1111,10 +1189,7 @@ end:
        X509_STORE_CTX_cleanup(&xsc);
        if (!ret)
                ERR_print_errors(bio_err);
-       if (buf != NULL) OPENSSL_free(buf);
-       if (bs != NULL) ASN1_INTEGER_free(bs);
-       if (io != NULL) BIO_free(io);
-       if (serial != NULL) BN_free(serial);
+       if (!sno) ASN1_INTEGER_free(bs);
        return ret;
        }
 
@@ -1207,6 +1282,3 @@ static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt)
                }
        return 1;
 }
-
-
-