Add support for ISO 8601 datetime format

Fixes #5430

Added the configuration file option "date_opt" to the openssl applications ca,
crl and x509.
Added ASN1_TIME_print_ex which supports the new datetime format using the
flag ASN1_DTFLGS_ISO8601

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14384)
This commit is contained in:
William Edmisten 2021-03-01 18:33:29 -05:00 committed by Tomas Mraz
parent 3eb4b5bfe6
commit 8c5bff2220
16 changed files with 191 additions and 42 deletions

View File

@ -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.

View File

@ -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);
static int certify_cert(X509 **xret, const char *infile, int certformat,
const char *passin, EVP_PKEY *pkey, X509 *x509,
const char *dgst,
@ -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,
@ -119,7 +119,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 *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,
@ -127,7 +127,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 *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);
@ -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,
@ -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, '-',
@ -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;
@ -323,6 +325,10 @@ opthelp:
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;
@ -947,7 +953,7 @@ end_of_options:
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) {
@ -968,7 +974,7 @@ end_of_options:
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) {
@ -988,7 +994,7 @@ end_of_options:
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) {
@ -1009,7 +1015,7 @@ end_of_options:
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) {
@ -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;
@ -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);
@ -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;
@ -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);
@ -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;
@ -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");
@ -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;
@ -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);

View File

@ -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;
@ -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
@ -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;
@ -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;
@ -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");

View File

@ -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);

View File

@ -1214,6 +1214,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)

View File

@ -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,
@ -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"},
@ -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;
@ -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,
@ -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;

View File

@ -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;
@ -508,15 +516,33 @@ int ossl_asn1_time_print_ex(BIO *bp, const ASN1_TIME *tm)
++f_len;
}
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;
}
}
}

View File

@ -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;

View File

@ -44,6 +44,7 @@ B<openssl> B<ca>
[B<-inform> B<DER>|<PEM>]
[B<-out> I<file>]
[B<-notext>]
[B<-dateopt>]
[B<-outdir> I<dir>]
[B<-infiles>]
[B<-spkac> I<file>]
@ -209,6 +210,11 @@ self-signed certificate.
Don't output the text form of a certificate to the output file.
=item B<-dateopt>
Specify the date output format. Values are: rfc_822 and iso_8601.
Defaults to rfc_822.
=item B<-startdate> I<date>
This allows the start date to be explicitly set. The format of the

View File

@ -13,6 +13,7 @@ B<openssl> B<crl>
[B<-outform> B<DER>|B<PEM>]
[B<-key> I<filename>]
[B<-keyform> B<DER>|B<PEM>|B<P12>]
[B<-dateopt>]
[B<-text>]
[B<-in> I<filename>]
[B<-out> I<filename>]
@ -81,6 +82,11 @@ Output a comparison of the main CRL and the one specified here.
Corrupt the signature before writing it; this can be useful
for testing.
=item B<-dateopt>
Specify the date output format. Values are: rfc_822 and iso_8601.
Defaults to rfc_822.
=item B<-text>
Print out the CRL in text form.

View File

@ -24,6 +24,7 @@ B<openssl> B<x509>
[B<-outform> B<DER>|B<PEM>]
[B<-nocert>]
[B<-noout>]
[B<-dateopt>]
[B<-text>]
[B<-certopt> I<option>]
[B<-fingerprint>]
@ -208,6 +209,11 @@ but are described in the L</Trust Settings> section.
=over 4
=item B<-dateopt>
Specify the date output format. Values are: rfc_822 and iso_8601.
Defaults to rfc_822.
=item B<-text>
Prints out the certificate in text form. Full details are printed including the

View File

@ -9,7 +9,7 @@ ASN1_TIME_set_string, ASN1_UTCTIME_set_string, ASN1_GENERALIZEDTIME_set_string,
ASN1_TIME_set_string_X509,
ASN1_TIME_normalize,
ASN1_TIME_to_tm,
ASN1_TIME_print, ASN1_UTCTIME_print, ASN1_GENERALIZEDTIME_print,
ASN1_TIME_print, ASN1_TIME_print_ex, ASN1_UTCTIME_print, ASN1_GENERALIZEDTIME_print,
ASN1_TIME_diff,
ASN1_TIME_cmp_time_t, ASN1_UTCTIME_cmp_time_t,
ASN1_TIME_compare,
@ -44,6 +44,7 @@ ASN1_TIME_dup, ASN1_UTCTIME_dup, ASN1_GENERALIZEDTIME_dup - ASN.1 Time functions
int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *t);
int ASN1_TIME_print(BIO *b, const ASN1_TIME *s);
int ASN1_TIME_print_ex(BIO *bp, const ASN1_TIME *tm, unsigned long flags);
int ASN1_UTCTIME_print(BIO *b, const ASN1_UTCTIME *s);
int ASN1_GENERALIZEDTIME_print(BIO *b, const ASN1_GENERALIZEDTIME *s);
@ -107,6 +108,9 @@ If the time structure has invalid format it prints out "Bad time value" and
returns an error. The output for generalized time may include a fractional part
following the second.
ASN1_TIME_print_ex() provides I<flags> to specify the output format of the
datetime. This can be either B<ASN1_DTFLGS_RFC822> or B<ASN1_DTFLGS_ISO8601>.
ASN1_TIME_to_tm() converts the time I<s> to the standard I<tm> structure.
If I<s> is NULL, then the current time is converted. The output time is GMT.
The I<tm_sec>, I<tm_min>, I<tm_hour>, I<tm_mday>, I<tm_wday>, I<tm_yday>,
@ -177,12 +181,13 @@ either format.
=head1 BUGS
ASN1_TIME_print(), ASN1_UTCTIME_print() and ASN1_GENERALIZEDTIME_print()
do not print out the timezone: it either prints out "GMT" or nothing. But all
ASN1_TIME_print(), ASN1_UTCTIME_print() and ASN1_GENERALIZEDTIME_print() do
not print out the timezone: it either prints out "GMT" or nothing. But all
certificates complying with RFC5280 et al use GMT anyway.
ASN1_TIME_print(), ASN1_UTCTIME_print() and ASN1_GENERALIZEDTIME_print()
do not distinguish if they fail because of an I/O error or invalid time format.
ASN1_TIME_print(), ASN1_TIME_print_ex(), ASN1_UTCTIME_print() and
ASN1_GENERALIZEDTIME_print() do not distinguish if they fail because
of an I/O error or invalid time format.
Use the ASN1_TIME_normalize() function to normalize the time value before
printing to get GMT results.

View File

@ -140,7 +140,7 @@ int ossl_x509_algor_new_from_md(X509_ALGOR **palg, const EVP_MD *md);
const EVP_MD *ossl_x509_algor_get_md(X509_ALGOR *alg);
X509_ALGOR *ossl_x509_algor_mgf1_decode(X509_ALGOR *alg);
int ossl_x509_algor_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md);
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);
EVP_PKEY * ossl_d2i_PrivateKey_legacy(int keytype, EVP_PKEY **a,
const unsigned char **pp, long length,

View File

@ -391,6 +391,11 @@ typedef const ASN1_ITEM *ASN1_ITEM_EXP (void);
# define ASN1_STRFLGS_ESC_CTRL 2
# define ASN1_STRFLGS_ESC_MSB 4
/* Lower 8 bits are reserved as an output type specifier */
# define ASN1_DTFLGS_TYPE_MASK 0x0FUL
# define ASN1_DTFLGS_RFC822 0x00UL
# define ASN1_DTFLGS_ISO8601 0x01UL
/*
* This flag determines how we do escaping: normally RC2253 backslash only,
* set this to use backslash and quote.
@ -800,7 +805,8 @@ int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, const void *x);
BIO *ASN1_item_i2d_mem_bio(const ASN1_ITEM *it, const ASN1_VALUE *val);
int ASN1_UTCTIME_print(BIO *fp, const ASN1_UTCTIME *a);
int ASN1_GENERALIZEDTIME_print(BIO *fp, const ASN1_GENERALIZEDTIME *a);
int ASN1_TIME_print(BIO *fp, const ASN1_TIME *a);
int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm);
int ASN1_TIME_print_ex(BIO *bp, const ASN1_TIME *tm, unsigned long flags);
int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v);
int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str, unsigned long flags);
int ASN1_buf_print(BIO *bp, const unsigned char *buf, size_t buflen, int off);

View File

@ -482,7 +482,7 @@ static int test_days(int n)
static const struct {
ASN1_TIME asn1;
const char *readable;
} x509_print_tests [] = {
} x509_print_tests_rfc_822 [] = {
/* Generalized Time */
construct_asn1_time("20170731222050Z", V_ASN1_GENERALIZEDTIME,
"Jul 31 22:20:50 2017 GMT"),
@ -506,7 +506,34 @@ static const struct {
"Jul 31 22:20:00 2017 GMT"),
};
static int test_x509_time_print(int idx)
static const struct {
ASN1_TIME asn1;
const char *readable;
} x509_print_tests_iso_8601 [] = {
/* Generalized Time */
construct_asn1_time("20170731222050Z", V_ASN1_GENERALIZEDTIME,
"2017-07-31 22:20:50Z"),
/* Generalized Time, no seconds */
construct_asn1_time("201707312220Z", V_ASN1_GENERALIZEDTIME,
"2017-07-31 22:20:00Z"),
/* Generalized Time, fractional seconds (3 digits) */
construct_asn1_time("20170731222050.123Z", V_ASN1_GENERALIZEDTIME,
"2017-07-31 22:20:50.123Z"),
/* Generalized Time, fractional seconds (1 digit) */
construct_asn1_time("20170731222050.1Z", V_ASN1_GENERALIZEDTIME,
"2017-07-31 22:20:50.1Z"),
/* Generalized Time, fractional seconds (0 digit) */
construct_asn1_time("20170731222050.Z", V_ASN1_GENERALIZEDTIME,
"Bad time value"),
/* UTC Time */
construct_asn1_time("170731222050Z", V_ASN1_UTCTIME,
"2017-07-31 22:20:50Z"),
/* UTC Time, no seconds */
construct_asn1_time("1707312220Z", V_ASN1_UTCTIME,
"2017-07-31 22:20:00Z"),
};
static int test_x509_time_print_rfc_822(int idx)
{
BIO *m;
int ret = 0, rv;
@ -516,8 +543,36 @@ static int test_x509_time_print(int idx)
if (!TEST_ptr(m = BIO_new(BIO_s_mem())))
goto err;
rv = ASN1_TIME_print(m, &x509_print_tests[idx].asn1);
readable = x509_print_tests[idx].readable;
rv = ASN1_TIME_print_ex(m, &x509_print_tests_rfc_822[idx].asn1, ASN1_DTFLGS_RFC822);
readable = x509_print_tests_rfc_822[idx].readable;
if (rv == 0 && !TEST_str_eq(readable, "Bad time value")) {
/* only if the test case intends to fail... */
goto err;
}
if (!TEST_int_ne(rv = BIO_get_mem_data(m, &pp), 0)
|| !TEST_int_eq(rv, (int)strlen(readable))
|| !TEST_strn_eq(pp, readable, rv))
goto err;
ret = 1;
err:
BIO_free(m);
return ret;
}
static int test_x509_time_print_iso_8601(int idx)
{
BIO *m;
int ret = 0, rv;
char *pp;
const char *readable;
if (!TEST_ptr(m = BIO_new(BIO_s_mem())))
goto err;
rv = ASN1_TIME_print_ex(m, &x509_print_tests_iso_8601[idx].asn1, ASN1_DTFLGS_ISO8601);
readable = x509_print_tests_iso_8601[idx].readable;
if (rv == 0 && !TEST_str_eq(readable, "Bad time value")) {
/* only if the test case intends to fail... */
@ -541,6 +596,7 @@ int setup_tests(void)
ADD_ALL_TESTS(test_x509_cmp_time, OSSL_NELEM(x509_cmp_tests));
ADD_ALL_TESTS(test_x509_time, OSSL_NELEM(x509_format_tests));
ADD_ALL_TESTS(test_days, OSSL_NELEM(day_of_week_tests));
ADD_ALL_TESTS(test_x509_time_print, OSSL_NELEM(x509_print_tests));
ADD_ALL_TESTS(test_x509_time_print_rfc_822, OSSL_NELEM(x509_print_tests_rfc_822));
ADD_ALL_TESTS(test_x509_time_print_iso_8601, OSSL_NELEM(x509_print_tests_iso_8601));
return 1;
}

View File

@ -5411,3 +5411,4 @@ ASN1_item_new_ex ? 3_0_0 EXIST::FUNCTION:
ASN1_item_d2i_fp_ex ? 3_0_0 EXIST::FUNCTION:STDIO
ASN1_item_d2i_bio_ex ? 3_0_0 EXIST::FUNCTION:
ASN1_item_d2i_ex ? 3_0_0 EXIST::FUNCTION:
ASN1_TIME_print_ex ? 3_0_0 EXIST::FUNCTION: