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: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/4185)
This commit is contained in:
Rich Salz 2017-08-16 15:49:25 -04:00
parent 932c0df29b
commit ffb46830e2
5 changed files with 59 additions and 29 deletions

View file

@ -1503,15 +1503,11 @@ int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
BIGNUM *btmp;
int ret = 0;
if (b)
btmp = b;
else
btmp = BN_new();
btmp = b == NULL ? BN_new() : b;
if (btmp == NULL)
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;
if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
goto error;

View file

@ -568,7 +568,12 @@ void store_setup_crl_download(X509_STORE *st);
# 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_access(const char *, int flag);

View file

@ -62,6 +62,7 @@
#define ENV_NEW_CERTS_DIR "new_certs_dir"
#define ENV_CERTIFICATE "certificate"
#define ENV_SERIAL "serial"
#define ENV_RAND_SERIAL "rand_serial"
#define ENV_CRLNUMBER "crlnumber"
#define ENV_PRIVATE_KEY "private_key"
#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_INFILES, OPT_SS_CERT, OPT_SPKAC, OPT_REVOKE, OPT_VALID,
OPT_EXTENSIONS, OPT_EXTFILE, OPT_STATUS, OPT_UPDATEDB, OPT_CRLEXTS,
OPT_RAND_SERIAL,
OPT_R_ENUM,
/* Do not change the order here; see related case statements below */
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)"},
{"create_serial", OPT_CREATE_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, '-',
"Enable support for multivalued RDNs"},
{"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 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 i, j, selfsign = 0;
int rand_ser = 0, i, j, selfsign = 0;
long crldays = 0, crlhours = 0, crlsec = 0, days = 0;
unsigned long chtype = MBSTRING_ASC, certopt = 0;
X509 *x509 = NULL, *x509p = NULL, *x = NULL;
@ -303,6 +307,9 @@ opthelp:
case OPT_UTF8:
chtype = MBSTRING_UTF8;
break;
case OPT_RAND_SERIAL:
rand_ser = 1;
break;
case OPT_CREATE_SERIAL:
create_ser = 1;
break;
@ -774,9 +781,13 @@ end_of_options:
if (verbose)
BIO_printf(bio_err, "policy is %s\n", policy);
serialfile = lookup_conf(conf, section, ENV_SERIAL);
if (serialfile == NULL)
goto end;
if (NCONF_get_string(conf, section, ENV_RAND_SERIAL) != NULL) {
rand_ser = 1;
} else {
serialfile = lookup_conf(conf, section, ENV_SERIAL);
if (serialfile == NULL)
goto end;
}
if (extconf == NULL) {
/*
@ -838,18 +849,25 @@ end_of_options:
goto end;
}
if ((serial = load_serial(serialfile, create_ser, NULL)) == NULL) {
BIO_printf(bio_err, "error while loading serial number\n");
goto end;
}
if (verbose) {
if (BN_is_zero(serial)) {
BIO_printf(bio_err, "next serial number is 00\n");
} else {
if ((f = BN_bn2hex(serial)) == NULL)
goto end;
BIO_printf(bio_err, "next serial number is %s\n", f);
OPENSSL_free(f);
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) {
BIO_printf(bio_err, "error while loading serial number\n");
goto end;
}
if (verbose) {
if (BN_is_zero(serial)) {
BIO_printf(bio_err, "next serial number is 00\n");
} else {
if ((f = BN_bn2hex(serial)) == NULL)
goto end;
BIO_printf(bio_err, "next serial number is %s\n", f);
OPENSSL_free(f);
}
}
}
@ -973,7 +991,8 @@ end_of_options:
BIO_printf(bio_err, "Write out database with %d new entries\n",
sk_X509_num(cert_sk));
if (!save_serial(serialfile, "new", serial, NULL))
if (!rand_ser
&& !save_serial(serialfile, "new", serial, NULL))
goto end;
if (!save_index(dbfile, "new", db))
@ -1171,7 +1190,8 @@ end_of_options:
/* we have a CRL number that need updating */
if (crlnumberfile != NULL)
if (!save_serial(crlnumberfile, "new", crlnumber, NULL))
if (!rand_ser
&& !save_serial(crlnumberfile, "new", crlnumber, NULL))
goto end;
BN_free(crlnumber);
@ -1213,16 +1233,16 @@ end_of_options:
BIO_printf(bio_err, "Data Base Updated\n");
}
}
/*****************************************************************/
ret = 0;
end:
if (ret)
ERR_print_errors(bio_err);
BIO_free_all(Sout);
BIO_free_all(out);
BIO_free_all(in);
sk_X509_pop_free(cert_sk, X509_free);
if (ret)
ERR_print_errors(bio_err);
if (free_key)
OPENSSL_free(key);
BN_free(serial);

View file

@ -51,6 +51,7 @@ B<openssl> B<ca>
[B<-subj arg>]
[B<-utf8>]
[B<-create_serial>]
[B<-rand_serial>]
[B<-multivalue-rdn>]
[B<-rand 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
fails, specifying this option creates a new random serial to be used as next
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>
@ -614,6 +622,7 @@ A sample configuration file with the relevant sections for B<ca>:
certificate = $dir/cacert.pem # The CA cert
serial = $dir/serial # serial no file
#rand_serial = yes # for random serial#'s
private_key = $dir/private/cakey.pem# CA private key
RANDFILE = $dir/private/.rand # random number file

View file

@ -35,7 +35,7 @@ plan tests => 5;
if !ok(run(perlapp(["CA.pl","-newreq"])),
'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
if !is(yes(cmdstr(perlapp(["CA.pl", "-sign"]))), 0,
'signing certificate request');