Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for datetime format ISO 8601 #14384

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.md
Expand Up @@ -30,6 +30,11 @@ breaking changes, and mappings for the large list of deprecated functions.

### Changes between 1.1.1 and 3.0 [xx XXX xxxx]

* Add a configurable flag to output date formats as ISO 8601. Does not
change the default date format.

*William Edmisten*

* Version of MSVC earlier than 1300 could get link warnings, which could
be suppressed if the undocumented -DI_CAN_LIVE_WITH_LNK4049 was set.
Support for this flag has been removed.
Expand Down
40 changes: 23 additions & 17 deletions apps/ca.c
Expand Up @@ -99,7 +99,7 @@ static int certify(X509 **xret, const char *infile, int informat,
const char *enddate,
long days, int batch, const char *ext_sect, CONF *conf,
int verbose, unsigned long certopt, unsigned long nameopt,
int default_op, int ext_copy, int selfsign);
int default_op, int ext_copy, int selfsign, unsigned long dateopt);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not add to the "unsigned long" tech debt? See #15231 Or maybe the project doesn't care.

static int certify_cert(X509 **xret, const char *infile, int certformat,
const char *passin, EVP_PKEY *pkey, X509 *x509,
const char *dgst,
Expand All @@ -110,7 +110,7 @@ static int certify_cert(X509 **xret, const char *infile, int certformat,
int multirdn, int email_dn, const char *startdate,
const char *enddate, long days, int batch, const char *ext_sect,
CONF *conf, int verbose, unsigned long certopt,
unsigned long nameopt, int default_op, int ext_copy);
unsigned long nameopt, int default_op, int ext_copy, unsigned long dateopt);
static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey,
X509 *x509, const char *dgst,
STACK_OF(OPENSSL_STRING) *sigopts,
Expand All @@ -119,15 +119,15 @@ static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey,
int multirdn, int email_dn, const char *startdate,
const char *enddate, long days, const char *ext_sect, CONF *conf,
int verbose, unsigned long certopt,
unsigned long nameopt, int default_op, int ext_copy);
unsigned long nameopt, int default_op, int ext_copy, unsigned long dateopt);
static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509,
const char *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial,
const char *subj, unsigned long chtype, int multirdn,
int email_dn, const char *startdate, const char *enddate, long days,
int batch, int verbose, X509_REQ *req, const char *ext_sect,
CONF *conf, unsigned long certopt, unsigned long nameopt,
int default_op, int ext_copy, int selfsign);
int default_op, int ext_copy, int selfsign, unsigned long dateopt);
static int get_certificate_status(const char *ser_status, CA_DB *db);
static int do_updatedb(CA_DB *db);
static int check_time_format(const char *str);
Expand All @@ -148,7 +148,7 @@ typedef enum OPTION_choice {
OPT_CREATE_SERIAL, OPT_MULTIVALUE_RDN, OPT_STARTDATE, OPT_ENDDATE,
OPT_DAYS, OPT_MD, OPT_POLICY, OPT_KEYFILE, OPT_KEYFORM, OPT_PASSIN,
OPT_KEY, OPT_CERT, OPT_CERTFORM, OPT_SELFSIGN,
OPT_IN, OPT_INFORM, OPT_OUT, OPT_OUTDIR, OPT_VFYOPT,
OPT_IN, OPT_INFORM, OPT_OUT, OPT_DATEOPT, OPT_OUTDIR, OPT_VFYOPT,
OPT_SIGOPT, OPT_NOTEXT, OPT_BATCH, OPT_PRESERVEDN, OPT_NOEMAILDN,
OPT_GENCRL, OPT_MSIE_HACK, OPT_CRL_LASTUPDATE, OPT_CRL_NEXTUPDATE,
OPT_CRLDAYS, OPT_CRLHOURS, OPT_CRLSEC,
Expand All @@ -171,6 +171,7 @@ const OPTIONS ca_options[] = {
{"inform", OPT_INFORM, 'F', "CSR input format (DER or PEM); default PEM"},
{"infiles", OPT_INFILES, '-', "The last argument, requests to process"},
{"out", OPT_OUT, '>', "Where to put the output file(s)"},
{"dateopt", OPT_DATEOPT, 's', "Datetime format used for printing. (rfc_822/iso_8601). Default is rfc_822."},
{"notext", OPT_NOTEXT, '-', "Do not print the generated certificate"},
{"batch", OPT_BATCH, '-', "Don't ask questions"},
{"msie_hack", OPT_MSIE_HACK, '-',
Expand Down Expand Up @@ -275,6 +276,7 @@ int ca_main(int argc, char **argv)
char *dgst = NULL, *policy = NULL, *keyfile = NULL;
char *certfile = NULL, *crl_ext = NULL, *crlnumberfile = NULL;
int certformat = FORMAT_UNDEF, informat = FORMAT_UNDEF;
unsigned long dateopt = ASN1_DTFLGS_RFC822;
const char *infile = NULL, *spkac_file = NULL, *ss_cert_file = NULL;
const char *extensions = NULL, *extfile = NULL, *passinarg = NULL;
char *passin = NULL;
Expand Down Expand Up @@ -323,6 +325,10 @@ int ca_main(int argc, char **argv)
case OPT_OUT:
outfile = opt_arg();
break;
case OPT_DATEOPT:
if (!set_dateopt(&dateopt, opt_arg()))
goto opthelp;
break;
case OPT_VERBOSE:
verbose = 1;
break;
Expand Down Expand Up @@ -947,7 +953,7 @@ int ca_main(int argc, char **argv)
attribs, db, serial, subj, chtype, multirdn,
email_dn, startdate, enddate, days, extensions,
conf, verbose, certopt, get_nameopt(), default_op,
ext_copy);
ext_copy, dateopt);
if (j < 0)
goto end;
if (j > 0) {
Expand All @@ -968,7 +974,7 @@ int ca_main(int argc, char **argv)
db, serial, subj, chtype, multirdn, email_dn,
startdate, enddate, days, batch, extensions,
conf, verbose, certopt, get_nameopt(), default_op,
ext_copy);
ext_copy, dateopt);
if (j < 0)
goto end;
if (j > 0) {
Expand All @@ -988,7 +994,7 @@ int ca_main(int argc, char **argv)
sigopts, vfyopts, attribs, db,
serial, subj, chtype, multirdn, email_dn, startdate,
enddate, days, batch, extensions, conf, verbose,
certopt, get_nameopt(), default_op, ext_copy, selfsign);
certopt, get_nameopt(), default_op, ext_copy, selfsign, dateopt);
if (j < 0)
goto end;
if (j > 0) {
Expand All @@ -1009,7 +1015,7 @@ int ca_main(int argc, char **argv)
attribs, db,
serial, subj, chtype, multirdn, email_dn, startdate,
enddate, days, batch, extensions, conf, verbose,
certopt, get_nameopt(), default_op, ext_copy, selfsign);
certopt, get_nameopt(), default_op, ext_copy, selfsign, dateopt);
if (j < 0)
goto end;
if (j > 0) {
Expand Down Expand Up @@ -1357,7 +1363,7 @@ static int certify(X509 **xret, const char *infile, int informat,
const char *enddate,
long days, int batch, const char *ext_sect, CONF *lconf,
int verbose, unsigned long certopt, unsigned long nameopt,
int default_op, int ext_copy, int selfsign)
int default_op, int ext_copy, int selfsign, unsigned long dateopt)
{
X509_REQ *req = NULL;
EVP_PKEY *pktmp = NULL;
Expand Down Expand Up @@ -1396,7 +1402,7 @@ static int certify(X509 **xret, const char *infile, int informat,
ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, subj,
chtype, multirdn, email_dn, startdate, enddate, days, batch,
verbose, req, ext_sect, lconf, certopt, nameopt, default_op,
ext_copy, selfsign);
ext_copy, selfsign, dateopt);

end:
ERR_print_errors(bio_err);
Expand All @@ -1414,7 +1420,7 @@ static int certify_cert(X509 **xret, const char *infile, int certformat,
int multirdn, int email_dn, const char *startdate,
const char *enddate, long days, int batch, const char *ext_sect,
CONF *lconf, int verbose, unsigned long certopt,
unsigned long nameopt, int default_op, int ext_copy)
unsigned long nameopt, int default_op, int ext_copy, unsigned long dateopt)
{
X509 *template_cert = NULL;
X509_REQ *rreq = NULL;
Expand Down Expand Up @@ -1453,7 +1459,7 @@ static int certify_cert(X509 **xret, const char *infile, int certformat,
ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, subj,
chtype, multirdn, email_dn, startdate, enddate, days, batch,
verbose, rreq, ext_sect, lconf, certopt, nameopt, default_op,
ext_copy, 0);
ext_copy, 0, dateopt);

end:
X509_REQ_free(rreq);
Expand All @@ -1468,7 +1474,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509,
int email_dn, const char *startdate, const char *enddate, long days,
int batch, int verbose, X509_REQ *req, const char *ext_sect,
CONF *lconf, unsigned long certopt, unsigned long nameopt,
int default_op, int ext_copy, int selfsign)
int default_op, int ext_copy, int selfsign, unsigned long dateopt)
{
const X509_NAME *name = NULL;
X509_NAME *CAname = NULL, *subject = NULL;
Expand Down Expand Up @@ -1877,7 +1883,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509,
}

BIO_printf(bio_err, "Certificate is to be certified until ");
ASN1_TIME_print(bio_err, X509_get0_notAfter(ret));
ASN1_TIME_print_ex(bio_err, X509_get0_notAfter(ret), dateopt);
if (days)
BIO_printf(bio_err, " (%ld days)", days);
BIO_printf(bio_err, "\n");
Expand Down Expand Up @@ -1970,7 +1976,7 @@ static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey,
int multirdn, int email_dn, const char *startdate,
const char *enddate, long days, const char *ext_sect,
CONF *lconf, int verbose, unsigned long certopt,
unsigned long nameopt, int default_op, int ext_copy)
unsigned long nameopt, int default_op, int ext_copy, unsigned long dateopt)
{
STACK_OF(CONF_VALUE) *sk = NULL;
LHASH_OF(CONF_VALUE) *parms = NULL;
Expand Down Expand Up @@ -2083,7 +2089,7 @@ static int certify_spkac(X509 **xret, const char *infile, EVP_PKEY *pkey,
ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, subj,
chtype, multirdn, email_dn, startdate, enddate, days, 1,
verbose, req, ext_sect, lconf, certopt, nameopt, default_op,
ext_copy, 0);
ext_copy, 0, dateopt);
end:
X509_REQ_free(req);
CONF_free(parms);
Expand Down
12 changes: 9 additions & 3 deletions apps/crl.c
Expand Up @@ -23,7 +23,7 @@ typedef enum OPTION_choice {
OPT_INFORM, OPT_IN, OPT_OUTFORM, OPT_OUT, OPT_KEYFORM, OPT_KEY,
OPT_ISSUER, OPT_LASTUPDATE, OPT_NEXTUPDATE, OPT_FINGERPRINT,
OPT_CRLNUMBER, OPT_BADSIG, OPT_GENDELTA, OPT_CAPATH, OPT_CAFILE, OPT_CASTORE,
OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE, OPT_VERIFY, OPT_TEXT, OPT_HASH,
OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE, OPT_VERIFY, OPT_DATEOPT, OPT_TEXT, OPT_HASH,
OPT_HASH_OLD, OPT_NOOUT, OPT_NAMEOPT, OPT_MD, OPT_PROV_ENUM
} OPTION_CHOICE;

Expand All @@ -41,6 +41,7 @@ const OPTIONS crl_options[] = {
OPT_SECTION("Output"),
{"out", OPT_OUT, '>', "output file - default stdout"},
{"outform", OPT_OUTFORM, 'F', "Output format - default PEM"},
{"dateopt", OPT_DATEOPT, 's', "Datetime format used for printing. (rfc_822/iso_8601). Default is rfc_822."},
{"text", OPT_TEXT, '-', "Print out a text format version"},
{"hash", OPT_HASH, '-', "Print hash value"},
#ifndef OPENSSL_NO_MD5
Expand Down Expand Up @@ -91,6 +92,7 @@ int crl_main(int argc, char **argv)
int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, keyformat = FORMAT_UNDEF;
int ret = 1, num = 0, badsig = 0, fingerprint = 0, crlnumber = 0;
int text = 0, do_ver = 0, noCAfile = 0, noCApath = 0, noCAstore = 0;
unsigned long dateopt = ASN1_DTFLGS_RFC822;
int i;
#ifndef OPENSSL_NO_MD5
int hash_old = 0;
Expand Down Expand Up @@ -161,6 +163,10 @@ int crl_main(int argc, char **argv)
case OPT_VERIFY:
do_ver = 1;
break;
case OPT_DATEOPT:
if (!set_dateopt(&dateopt, opt_arg()))
goto opthelp;
break;
case OPT_TEXT:
text = 1;
break;
Expand Down Expand Up @@ -327,13 +333,13 @@ int crl_main(int argc, char **argv)
#endif
if (lastupdate == i) {
BIO_printf(bio_out, "lastUpdate=");
ASN1_TIME_print(bio_out, X509_CRL_get0_lastUpdate(x));
ASN1_TIME_print_ex(bio_out, X509_CRL_get0_lastUpdate(x), dateopt);
BIO_printf(bio_out, "\n");
}
if (nextupdate == i) {
BIO_printf(bio_out, "nextUpdate=");
if (X509_CRL_get0_nextUpdate(x))
ASN1_TIME_print(bio_out, X509_CRL_get0_nextUpdate(x));
ASN1_TIME_print_ex(bio_out, X509_CRL_get0_nextUpdate(x), dateopt);
else
BIO_printf(bio_out, "NONE");
BIO_printf(bio_out, "\n");
Expand Down
1 change: 1 addition & 0 deletions apps/include/apps.h
Expand Up @@ -100,6 +100,7 @@ void print_bignum_var(BIO *, const BIGNUM *, const char*,
void print_array(BIO *, const char *, int, const unsigned char *);
int set_nameopt(const char *arg);
unsigned long get_nameopt(void);
int set_dateopt(unsigned long *dateopt, const char *arg);
int set_cert_ex(unsigned long *flags, const char *arg);
int set_name_ex(unsigned long *flags, const char *arg);
int set_ext_copy(int *copy_type, const char *arg);
Expand Down
9 changes: 9 additions & 0 deletions apps/lib/apps.c
Expand Up @@ -1176,6 +1176,15 @@ int set_name_ex(unsigned long *flags, const char *arg)
return 1;
}

int set_dateopt(unsigned long *dateopt, const char *arg)
{
if (strcasecmp(arg, "rfc_822") == 0)
*dateopt = ASN1_DTFLGS_RFC822;
else if (strcasecmp(arg, "iso_8601") == 0)
*dateopt = ASN1_DTFLGS_ISO8601;
return 0;
}

int set_ext_copy(int *copy_type, const char *arg)
{
if (strcasecmp(arg, "none") == 0)
Expand Down
16 changes: 13 additions & 3 deletions apps/x509.c
Expand Up @@ -44,7 +44,7 @@ typedef enum OPTION_choice {
OPT_CAKEYFORM, OPT_VFYOPT, OPT_SIGOPT, OPT_DAYS, OPT_PASSIN, OPT_EXTFILE,
OPT_EXTENSIONS, OPT_IN, OPT_OUT, OPT_KEY, OPT_SIGNKEY, OPT_CA, OPT_CAKEY,
OPT_CASERIAL, OPT_SET_SERIAL, OPT_NEW, OPT_FORCE_PUBKEY, OPT_SUBJ,
OPT_ADDTRUST, OPT_ADDREJECT, OPT_SETALIAS, OPT_CERTOPT, OPT_NAMEOPT,
OPT_ADDTRUST, OPT_ADDREJECT, OPT_SETALIAS, OPT_CERTOPT, OPT_DATEOPT, OPT_NAMEOPT,
OPT_EMAIL, OPT_OCSP_URI, OPT_SERIAL, OPT_NEXT_SERIAL,
OPT_MODULUS, OPT_PUBKEY, OPT_X509TOREQ, OPT_TEXT, OPT_HASH,
OPT_ISSUER_HASH, OPT_SUBJECT, OPT_ISSUER, OPT_FINGERPRINT, OPT_DATES,
Expand Down Expand Up @@ -87,6 +87,7 @@ const OPTIONS x509_options[] = {

OPT_SECTION("Certificate printing"),
{"text", OPT_TEXT, '-', "Print the certificate in text form"},
{"dateopt", OPT_DATEOPT, 's', "Datetime format used for printing. (rfc_822/iso_8601). Default is rfc_822."},
{"certopt", OPT_CERTOPT, 's', "Various certificate text printing options"},
{"fingerprint", OPT_FINGERPRINT, '-', "Print the certificate fingerprint"},
{"alias", OPT_ALIAS, '-', "Print certificate alias"},
Expand Down Expand Up @@ -267,6 +268,7 @@ int x509_main(int argc, char **argv)
int days = UNSET_DAYS; /* not explicitly set */
int x509toreq = 0, modulus = 0, print_pubkey = 0, pprint = 0;
int CAformat = FORMAT_UNDEF, CAkeyformat = FORMAT_UNDEF;
unsigned long dateopt = ASN1_DTFLGS_RFC822;
int fingerprint = 0, reqfile = 0, checkend = 0;
int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, keyformat = FORMAT_UNDEF;
int next_serial = 0, subject_hash = 0, issuer_hash = 0, ocspid = 0;
Expand Down Expand Up @@ -330,6 +332,14 @@ int x509_main(int argc, char **argv)
case OPT_REQ:
reqfile = 1;
break;

case OPT_DATEOPT:
if (!set_dateopt(&dateopt, opt_arg())) {
BIO_printf(bio_err,
"Invalid date format: %s\n", opt_arg());
goto end;
}
break;
case OPT_COPY_EXTENSIONS:
if (!set_ext_copy(&ext_copy, opt_arg())) {
BIO_printf(bio_err,
Expand Down Expand Up @@ -956,11 +966,11 @@ int x509_main(int argc, char **argv)
X509_print_ex(out, x, get_nameopt(), certflag);
} else if (i == startdate) {
BIO_puts(out, "notBefore=");
ASN1_TIME_print(out, X509_get0_notBefore(x));
ASN1_TIME_print_ex(out, X509_get0_notBefore(x), dateopt);
BIO_puts(out, "\n");
} else if (i == enddate) {
BIO_puts(out, "notAfter=");
ASN1_TIME_print(out, X509_get0_notAfter(x));
ASN1_TIME_print_ex(out, X509_get0_notAfter(x), dateopt);
BIO_puts(out, "\n");
} else if (i == fingerprint) {
unsigned int n;
Expand Down
38 changes: 33 additions & 5 deletions crypto/asn1/a_time.c
Expand Up @@ -470,14 +470,22 @@ static const char _asn1_mon[12][4] = {
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

/* returns 1 on success, 0 on BIO write error or parse failure */
/* prints the time with the default date format (RFC 822) */
int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm)
{
return ossl_asn1_time_print_ex(bp, tm) > 0;
return ASN1_TIME_print_ex(bp, tm, ASN1_DTFLGS_RFC822);
}

/* returns 1 on success, 0 on BIO write error or parse failure */
int ASN1_TIME_print_ex(BIO *bp, const ASN1_TIME *tm, unsigned long flags)
{
return ossl_asn1_time_print_ex(bp, tm, flags) > 0;
}


/* prints the time with the date format of ISO 8601 */
/* returns 0 on BIO write error, else -1 in case of parse failure, else 1 */
int ossl_asn1_time_print_ex(BIO *bp, const ASN1_TIME *tm)
int ossl_asn1_time_print_ex(BIO *bp, const ASN1_TIME *tm, unsigned long flags)
{
char *v;
int gmt = 0, l;
Expand Down Expand Up @@ -508,15 +516,35 @@ int ossl_asn1_time_print_ex(BIO *bp, const ASN1_TIME *tm)
++f_len;
slontis marked this conversation as resolved.
Show resolved Hide resolved
}

return BIO_printf(bp, "%s %2d %02d:%02d:%02d%.*s %d%s",
if ((flags & ASN1_DTFLGS_TYPE_MASK) == ASN1_DTFLGS_ISO8601) {
return BIO_printf(bp, "%4d-%02d-%02d %02d:%02d:%02d%.*s%s",
stm.tm_year + 1900, stm.tm_mon + 1,
stm.tm_mday, stm.tm_hour,
stm.tm_min, stm.tm_sec, f_len, f,
(gmt ? "Z" : "")) > 0;
}
else {
return BIO_printf(bp, "%s %2d %02d:%02d:%02d%.*s %d%s",
_asn1_mon[stm.tm_mon], stm.tm_mday, stm.tm_hour,
stm.tm_min, stm.tm_sec, f_len, f, stm.tm_year + 1900,
(gmt ? " GMT" : "")) > 0;
}

} else {
return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s",
if ((flags & ASN1_DTFLGS_TYPE_MASK) == ASN1_DTFLGS_ISO8601) {
return BIO_printf(bp, "%4d-%02d-%02d %02d:%02d:%02d%s",
stm.tm_year + 1900, stm.tm_mon + 1,
stm.tm_mday, stm.tm_hour,
stm.tm_min, stm.tm_sec,
(gmt ? "Z" : "")) > 0;
}
else {
return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s",
_asn1_mon[stm.tm_mon], stm.tm_mday, stm.tm_hour,
stm.tm_min, stm.tm_sec, stm.tm_year + 1900,
(gmt ? " GMT" : "")) > 0;
}

}
}

Expand Down
4 changes: 2 additions & 2 deletions crypto/x509/t_x509.c
Expand Up @@ -140,11 +140,11 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
goto err;
if (BIO_write(bp, " Not Before: ", 24) <= 0)
goto err;
if (ossl_asn1_time_print_ex(bp, X509_get0_notBefore(x)) == 0)
if (ossl_asn1_time_print_ex(bp, X509_get0_notBefore(x), ASN1_DTFLGS_RFC822) == 0)
goto err;
if (BIO_write(bp, "\n Not After : ", 25) <= 0)
goto err;
if (ossl_asn1_time_print_ex(bp, X509_get0_notAfter(x)) == 0)
if (ossl_asn1_time_print_ex(bp, X509_get0_notAfter(x), ASN1_DTFLGS_RFC822) == 0)
goto err;
if (BIO_write(bp, "\n", 1) <= 0)
goto err;
Expand Down