Commit ffb46830 authored by Rich Salz's avatar Rich Salz
Browse files

Add random serial# support.



Add -rand_serial to CA command and "serial_rand" config option.

Up RAND_BITS to 159, and comment why: now confirms to CABForum
guidelines (Ballot 164) as well as IETF RFC 5280 (PKIX).

Reviewed-by: default avatarRichard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/4185)
parent 932c0df2
Loading
Loading
Loading
Loading
+2 −6
Original line number Original line Diff line number Diff line
@@ -1503,15 +1503,11 @@ int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
    BIGNUM *btmp;
    BIGNUM *btmp;
    int ret = 0;
    int ret = 0;


    if (b)
    btmp = b == NULL ? BN_new() : b;
        btmp = b;
    else
        btmp = BN_new();

    if (btmp == NULL)
    if (btmp == NULL)
        return 0;
        return 0;


    if (!BN_rand(btmp, SERIAL_RAND_BITS, 0, 0))
    if (!BN_rand(btmp, SERIAL_RAND_BITS, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
        goto error;
        goto error;
    if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
    if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
        goto error;
        goto error;
+6 −1
Original line number Original line Diff line number Diff line
@@ -568,7 +568,12 @@ void store_setup_crl_download(X509_STORE *st);


# define APP_PASS_LEN    1024
# define APP_PASS_LEN    1024


# define SERIAL_RAND_BITS        64
/*
 * IETF RFC 5280 says serial number must be <= 20 bytes. Use 159 bits
 * so that the first bit will never be one, so that the DER encoding
 * rules won't force a leading octet.
 */
# define SERIAL_RAND_BITS        159


int app_isdir(const char *);
int app_isdir(const char *);
int app_access(const char *, int flag);
int app_access(const char *, int flag);
+41 −21
Original line number Original line Diff line number Diff line
@@ -62,6 +62,7 @@
#define ENV_NEW_CERTS_DIR       "new_certs_dir"
#define ENV_NEW_CERTS_DIR       "new_certs_dir"
#define ENV_CERTIFICATE         "certificate"
#define ENV_CERTIFICATE         "certificate"
#define ENV_SERIAL              "serial"
#define ENV_SERIAL              "serial"
#define ENV_RAND_SERIAL         "rand_serial"
#define ENV_CRLNUMBER           "crlnumber"
#define ENV_CRLNUMBER           "crlnumber"
#define ENV_PRIVATE_KEY         "private_key"
#define ENV_PRIVATE_KEY         "private_key"
#define ENV_DEFAULT_DAYS        "default_days"
#define ENV_DEFAULT_DAYS        "default_days"
@@ -153,6 +154,7 @@ typedef enum OPTION_choice {
    OPT_GENCRL, OPT_MSIE_HACK, OPT_CRLDAYS, OPT_CRLHOURS, OPT_CRLSEC,
    OPT_GENCRL, OPT_MSIE_HACK, OPT_CRLDAYS, OPT_CRLHOURS, OPT_CRLSEC,
    OPT_INFILES, OPT_SS_CERT, OPT_SPKAC, OPT_REVOKE, OPT_VALID,
    OPT_INFILES, OPT_SS_CERT, OPT_SPKAC, OPT_REVOKE, OPT_VALID,
    OPT_EXTENSIONS, OPT_EXTFILE, OPT_STATUS, OPT_UPDATEDB, OPT_CRLEXTS,
    OPT_EXTENSIONS, OPT_EXTFILE, OPT_STATUS, OPT_UPDATEDB, OPT_CRLEXTS,
    OPT_RAND_SERIAL,
    OPT_R_ENUM,
    OPT_R_ENUM,
    /* Do not change the order here; see related case statements below */
    /* Do not change the order here; see related case statements below */
    OPT_CRL_REASON, OPT_CRL_HOLD, OPT_CRL_COMPROMISE, OPT_CRL_CA_COMPROMISE
    OPT_CRL_REASON, OPT_CRL_HOLD, OPT_CRL_COMPROMISE, OPT_CRL_CA_COMPROMISE
@@ -167,6 +169,8 @@ const OPTIONS ca_options[] = {
    {"utf8", OPT_UTF8, '-', "Input characters are UTF8 (default ASCII)"},
    {"utf8", OPT_UTF8, '-', "Input characters are UTF8 (default ASCII)"},
    {"create_serial", OPT_CREATE_SERIAL, '-',
    {"create_serial", OPT_CREATE_SERIAL, '-',
     "If reading serial fails, create a new random serial"},
     "If reading serial fails, create a new random serial"},
    {"rand_serial", OPT_RAND_SERIAL, '-',
     "Always create a random serial; do not store it"},
    {"multivalue-rdn", OPT_MULTIVALUE_RDN, '-',
    {"multivalue-rdn", OPT_MULTIVALUE_RDN, '-',
     "Enable support for multivalued RDNs"},
     "Enable support for multivalued RDNs"},
    {"startdate", OPT_STARTDATE, 's', "Cert notBefore, YYMMDDHHMMSSZ"},
    {"startdate", OPT_STARTDATE, 's', "Cert notBefore, YYMMDDHHMMSSZ"},
@@ -258,7 +262,7 @@ int ca_main(int argc, char **argv)
    int batch = 0, default_op = 1, doupdatedb = 0, ext_copy = EXT_COPY_NONE;
    int batch = 0, default_op = 1, doupdatedb = 0, ext_copy = EXT_COPY_NONE;
    int keyformat = FORMAT_PEM, multirdn = 0, notext = 0, output_der = 0;
    int keyformat = FORMAT_PEM, multirdn = 0, notext = 0, output_der = 0;
    int ret = 1, email_dn = 1, req = 0, verbose = 0, gencrl = 0, dorevoke = 0;
    int ret = 1, email_dn = 1, req = 0, verbose = 0, gencrl = 0, dorevoke = 0;
    int i, j, selfsign = 0;
    int rand_ser = 0, i, j, selfsign = 0;
    long crldays = 0, crlhours = 0, crlsec = 0, days = 0;
    long crldays = 0, crlhours = 0, crlsec = 0, days = 0;
    unsigned long chtype = MBSTRING_ASC, certopt = 0;
    unsigned long chtype = MBSTRING_ASC, certopt = 0;
    X509 *x509 = NULL, *x509p = NULL, *x = NULL;
    X509 *x509 = NULL, *x509p = NULL, *x = NULL;
@@ -303,6 +307,9 @@ opthelp:
        case OPT_UTF8:
        case OPT_UTF8:
            chtype = MBSTRING_UTF8;
            chtype = MBSTRING_UTF8;
            break;
            break;
        case OPT_RAND_SERIAL:
            rand_ser = 1;
            break;
        case OPT_CREATE_SERIAL:
        case OPT_CREATE_SERIAL:
            create_ser = 1;
            create_ser = 1;
            break;
            break;
@@ -774,9 +781,13 @@ end_of_options:
        if (verbose)
        if (verbose)
            BIO_printf(bio_err, "policy is %s\n", policy);
            BIO_printf(bio_err, "policy is %s\n", policy);


        if (NCONF_get_string(conf, section, ENV_RAND_SERIAL) != NULL) {
            rand_ser = 1;
        } else {
            serialfile = lookup_conf(conf, section, ENV_SERIAL);
            serialfile = lookup_conf(conf, section, ENV_SERIAL);
            if (serialfile == NULL)
            if (serialfile == NULL)
                goto end;
                goto end;
        }


        if (extconf == NULL) {
        if (extconf == NULL) {
            /*
            /*
@@ -838,6 +849,12 @@ end_of_options:
            goto end;
            goto end;
        }
        }


        if (rand_ser) {
            if ((serial = BN_new()) == NULL || !rand_serial(serial, NULL)) {
                BIO_printf(bio_err, "error generating serial number\n");
                goto end;
            }
        } else {
            if ((serial = load_serial(serialfile, create_ser, NULL)) == NULL) {
            if ((serial = load_serial(serialfile, create_ser, NULL)) == NULL) {
                BIO_printf(bio_err, "error while loading serial number\n");
                BIO_printf(bio_err, "error while loading serial number\n");
                goto end;
                goto end;
@@ -852,6 +869,7 @@ end_of_options:
                    OPENSSL_free(f);
                    OPENSSL_free(f);
                }
                }
            }
            }
        }


        if ((attribs = NCONF_get_section(conf, policy)) == NULL) {
        if ((attribs = NCONF_get_section(conf, policy)) == NULL) {
            BIO_printf(bio_err, "unable to find 'section' for %s\n", policy);
            BIO_printf(bio_err, "unable to find 'section' for %s\n", policy);
@@ -973,7 +991,8 @@ end_of_options:
            BIO_printf(bio_err, "Write out database with %d new entries\n",
            BIO_printf(bio_err, "Write out database with %d new entries\n",
                       sk_X509_num(cert_sk));
                       sk_X509_num(cert_sk));


            if (!save_serial(serialfile, "new", serial, NULL))
            if (!rand_ser
                    && !save_serial(serialfile, "new", serial, NULL))
                goto end;
                goto end;


            if (!save_index(dbfile, "new", db))
            if (!save_index(dbfile, "new", db))
@@ -1171,7 +1190,8 @@ end_of_options:


        /* we have a CRL number that need updating */
        /* we have a CRL number that need updating */
        if (crlnumberfile != NULL)
        if (crlnumberfile != NULL)
            if (!save_serial(crlnumberfile, "new", crlnumber, NULL))
            if (!rand_ser
                    && !save_serial(crlnumberfile, "new", crlnumber, NULL))
                goto end;
                goto end;


        BN_free(crlnumber);
        BN_free(crlnumber);
@@ -1213,16 +1233,16 @@ end_of_options:
            BIO_printf(bio_err, "Data Base Updated\n");
            BIO_printf(bio_err, "Data Base Updated\n");
        }
        }
    }
    }
    /*****************************************************************/
    ret = 0;
    ret = 0;

 end:
 end:
    if (ret)
        ERR_print_errors(bio_err);
    BIO_free_all(Sout);
    BIO_free_all(Sout);
    BIO_free_all(out);
    BIO_free_all(out);
    BIO_free_all(in);
    BIO_free_all(in);
    sk_X509_pop_free(cert_sk, X509_free);
    sk_X509_pop_free(cert_sk, X509_free);


    if (ret)
        ERR_print_errors(bio_err);
    if (free_key)
    if (free_key)
        OPENSSL_free(key);
        OPENSSL_free(key);
    BN_free(serial);
    BN_free(serial);
+9 −0
Original line number Original line Diff line number Diff line
@@ -51,6 +51,7 @@ B<openssl> B<ca>
[B<-subj arg>]
[B<-subj arg>]
[B<-utf8>]
[B<-utf8>]
[B<-create_serial>]
[B<-create_serial>]
[B<-rand_serial>]
[B<-multivalue-rdn>]
[B<-multivalue-rdn>]
[B<-rand file...>]
[B<-rand file...>]
[B<-writerand file>]
[B<-writerand file>]
@@ -262,6 +263,13 @@ configuration file, must be valid UTF8 strings.
If reading serial from the text file as specified in the configuration
If reading serial from the text file as specified in the configuration
fails, specifying this option creates a new random serial to be used as next
fails, specifying this option creates a new random serial to be used as next
serial number.
serial number.
To get random serial numbers, use the B<-rand_serial> flag instead; this
should only be used for simple error-recovery.

=item B<-rand_serial>

Generate a large random number to use as the serial number.
This overrides any option or configuration to use a serial number file.


=item B<-multivalue-rdn>
=item B<-multivalue-rdn>


@@ -614,6 +622,7 @@ A sample configuration file with the relevant sections for B<ca>:


 certificate    = $dir/cacert.pem       # The CA cert
 certificate    = $dir/cacert.pem       # The CA cert
 serial         = $dir/serial           # serial no file
 serial         = $dir/serial           # serial no file
 #rand_serial    = yes                  # for random serial#'s
 private_key    = $dir/private/cakey.pem# CA private key
 private_key    = $dir/private/cakey.pem# CA private key
 RANDFILE       = $dir/private/.rand    # random number file
 RANDFILE       = $dir/private/.rand    # random number file


+1 −1
Original line number Original line Diff line number Diff line
@@ -35,7 +35,7 @@ plan tests => 5;
	 if !ok(run(perlapp(["CA.pl","-newreq"])),
	 if !ok(run(perlapp(["CA.pl","-newreq"])),
		'creating certificate request');
		'creating certificate request');


     $ENV{OPENSSL_CONFIG} = '-config "'.$std_openssl_cnf.'"';
     $ENV{OPENSSL_CONFIG} = '-rand_serial -config "'.$std_openssl_cnf.'"';
     skip "failed to sign certificate request", 2
     skip "failed to sign certificate request", 2
	 if !is(yes(cmdstr(perlapp(["CA.pl", "-sign"]))), 0,
	 if !is(yes(cmdstr(perlapp(["CA.pl", "-sign"]))), 0,
		'signing certificate request');
		'signing certificate request');