OpenSSL Releases
----------------
+ - [OpenSSL 3.4](#openssl-34)
- [OpenSSL 3.3](#openssl-33)
- [OpenSSL 3.2](#openssl-32)
- [OpenSSL 3.1](#openssl-31)
### Changes between 3.3 and 3.4 [xx XXX xxxx]
- * None yet
+ * Added options `-not_before` and `-not_after` for explicit setting
+ start and end dates of certificates created with the `req` and `x509`
+ apps. Added the same options also to `ca` app as alias for
+ `-startdate` and `-enddate` options.
+
+ *Stephan Wurm*
OpenSSL 3.3
-----------
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,
+ OPT_CRLDAYS, OPT_CRLHOURS, OPT_CRLSEC, OPT_NOT_BEFORE, OPT_NOT_AFTER,
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_QUIET,
"Always create a random serial; do not store it"},
{"multivalue-rdn", OPT_MULTIVALUE_RDN, '-',
"Deprecated; multi-valued RDNs support is always on."},
- {"startdate", OPT_STARTDATE, 's', "Cert notBefore, YYMMDDHHMMSSZ"},
+ {"startdate", OPT_STARTDATE, 's',
+ "[CC]YYMMDDHHMMSSZ value for notBefore certificate field"},
+ {"not_before", OPT_NOT_BEFORE, 's', "An alias for -startdate"},
{"enddate", OPT_ENDDATE, 's',
- "YYMMDDHHMMSSZ cert notAfter (overrides -days)"},
- {"days", OPT_DAYS, 'p', "Number of days to certify the cert for"},
+ "[CC]YYMMDDHHMMSSZ value for notAfter certificate field, overrides -days"},
+ {"not_after", OPT_NOT_AFTER, 's', "An alias for -enddate"},
+ {"days", OPT_DAYS, 'p', "Number of days from today to certify the cert for"},
{"extensions", OPT_EXTENSIONS, 's',
"Extension section (override value in config file)"},
{"extfile", OPT_EXTFILE, '<',
/* obsolete */
break;
case OPT_STARTDATE:
+ case OPT_NOT_BEFORE:
startdate = opt_arg();
break;
case OPT_ENDDATE:
+ case OPT_NOT_AFTER:
enddate = opt_arg();
break;
case OPT_DAYS:
if (startdate == NULL)
startdate =
app_conf_try_string(conf, section, ENV_DEFAULT_STARTDATE);
- if (startdate != NULL && !ASN1_TIME_set_string_X509(NULL, startdate)) {
- BIO_printf(bio_err,
- "start date is invalid, it should be YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ\n");
- goto end;
- }
- if (startdate == NULL)
- startdate = "today";
-
if (enddate == NULL)
enddate = app_conf_try_string(conf, section, ENV_DEFAULT_ENDDATE);
- if (enddate != NULL && !ASN1_TIME_set_string_X509(NULL, enddate)) {
- BIO_printf(bio_err,
- "end date is invalid, it should be YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ\n");
- goto end;
- }
-
if (days == 0) {
if (!app_conf_try_number(conf, section, ENV_DEFAULT_DAYS, &days))
days = 0;
BIO_printf(bio_err, "cannot lookup how many days to certify for\n");
goto end;
}
+ if (days != 0 && enddate != NULL)
+ BIO_printf(bio_err,
+ "Warning: -enddate or -not_after option overriding -days option\n");
if (rand_ser) {
if ((serial = BN_new()) == NULL || !rand_serial(serial, NULL)) {
goto end;
}
- if (!set_cert_times(ret, startdate, enddate, days))
+ if (!set_cert_times(ret, startdate, enddate, days, 0))
goto end;
if (enddate != NULL) {
# endif
void corrupt_signature(const ASN1_STRING *signature);
+
+/* Helpers for setting X509v3 certificate fields notBefore and notAfter */
+int check_cert_time_string(const char *time, const char *desc);
int set_cert_times(X509 *x, const char *startdate, const char *enddate,
- int days);
+ int days, int strict_compare_times);
+
int set_crl_lastupdate(X509_CRL *crl, const char *lastupdate);
int set_crl_nextupdate(X509_CRL *crl, const char *nextupdate,
long days, long hours, long secs);
s[signature->length - 1] ^= 0x1;
}
+int check_cert_time_string(const char *time, const char *desc)
+{
+ if (time == NULL || strcmp(time, "today") == 0
+ || ASN1_TIME_set_string_X509(NULL, time))
+ return 1;
+ BIO_printf(bio_err,
+ "%s is invalid, it should be \"today\" or have format [CC]YYMMDDHHMMSSZ\n",
+ desc);
+ return 0;
+}
+
int set_cert_times(X509 *x, const char *startdate, const char *enddate,
- int days)
+ int days, int strict_compare_times)
{
+ if (!check_cert_time_string(startdate, "start date"))
+ return 0;
+ if (!check_cert_time_string(enddate, "end date"))
+ return 0;
if (startdate == NULL || strcmp(startdate, "today") == 0) {
- if (X509_gmtime_adj(X509_getm_notBefore(x), 0) == NULL)
+ if (X509_gmtime_adj(X509_getm_notBefore(x), 0) == NULL) {
+ BIO_printf(bio_err, "Error setting notBefore certificate field\n");
return 0;
+ }
} else {
- if (!ASN1_TIME_set_string_X509(X509_getm_notBefore(x), startdate))
+ if (!ASN1_TIME_set_string_X509(X509_getm_notBefore(x), startdate)) {
+ BIO_printf(bio_err, "Error setting notBefore certificate field\n");
return 0;
+ }
+ }
+ if (enddate != NULL && strcmp(enddate, "today") == 0) {
+ enddate = NULL;
+ days = 0;
}
if (enddate == NULL) {
- if (X509_time_adj_ex(X509_getm_notAfter(x), days, 0, NULL)
- == NULL)
+ if (X509_time_adj_ex(X509_getm_notAfter(x), days, 0, NULL) == NULL) {
+ BIO_printf(bio_err, "Error setting notAfter certificate field\n");
return 0;
+ }
} else if (!ASN1_TIME_set_string_X509(X509_getm_notAfter(x), enddate)) {
+ BIO_printf(bio_err, "Error setting notAfter certificate field\n");
return 0;
}
+ if (ASN1_TIME_compare(X509_get0_notAfter(x), X509_get0_notBefore(x)) < 0) {
+ BIO_printf(bio_err, "%s: end date before start date\n",
+ strict_compare_times ? "Error" : "Warning");
+ if (strict_compare_times)
+ return 0;
+ }
return 1;
}
#define DEFAULT_KEY_LENGTH 2048
#define MIN_KEY_LENGTH 512
-#define DEFAULT_DAYS 30 /* default cert validity period in days */
+#define DEFAULT_DAYS 30 /* default certificate validity period in days */
#define UNSET_DAYS -2 /* -1 may be used for testing expiration checks */
#define EXT_COPY_UNSET -1
OPT_VERIFY, OPT_NOENC, OPT_NODES, OPT_NOOUT, OPT_VERBOSE, OPT_UTF8,
OPT_NAMEOPT, OPT_REQOPT, OPT_SUBJ, OPT_SUBJECT, OPT_TEXT,
OPT_X509, OPT_X509V1, OPT_CA, OPT_CAKEY,
- OPT_MULTIVALUE_RDN, OPT_DAYS, OPT_SET_SERIAL,
+ OPT_MULTIVALUE_RDN, OPT_NOT_BEFORE, OPT_NOT_AFTER, OPT_DAYS, OPT_SET_SERIAL,
OPT_COPY_EXTENSIONS, OPT_EXTENSIONS, OPT_REQEXTS, OPT_ADDEXT,
OPT_PRECERT, OPT_MD,
OPT_SECTION, OPT_QUIET,
"Print the subject of the output request or cert"},
{"multivalue-rdn", OPT_MULTIVALUE_RDN, '-',
"Deprecated; multi-valued RDNs support is always on."},
- {"days", OPT_DAYS, 'p', "Number of days cert is valid for"},
+ {"not_before", OPT_NOT_BEFORE, 's',
+ "[CC]YYMMDDHHMMSSZ value for notBefore certificate field"},
+ {"not_after", OPT_NOT_AFTER, 's',
+ "[CC]YYMMDDHHMMSSZ value for notAfter certificate field, overrides -days"},
+ {"days", OPT_DAYS, 'p', "Number of days certificate is valid for"},
{"set_serial", OPT_SET_SERIAL, 's', "Serial number to use"},
{"copy_extensions", OPT_COPY_EXTENSIONS, 's',
"copy extensions from request when using -x509"},
char *template = default_config_file, *keyout = NULL;
const char *keyalg = NULL;
OPTION_CHOICE o;
+ char *not_before = NULL, *not_after = NULL;
int days = UNSET_DAYS;
int ret = 1, gen_x509 = 0, i = 0, newreq = 0, verbose = 0, progress = 1;
int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, keyform = FORMAT_UNDEF;
case OPT_CAKEY:
CAkeyfile = opt_arg();
break;
+ case OPT_NOT_BEFORE:
+ not_before = opt_arg();
+ break;
+ case OPT_NOT_AFTER:
+ not_after = opt_arg();
+ break;
case OPT_DAYS:
days = atoi(opt_arg());
- if (days < -1) {
+ if (days <= UNSET_DAYS) {
BIO_printf(bio_err, "%s: -days parameter arg must be >= -1\n",
prog);
goto end;
if (!gen_x509) {
if (days != UNSET_DAYS)
- BIO_printf(bio_err, "Ignoring -days without -x509; not generating a certificate\n");
+ BIO_printf(bio_err, "Warning: Ignoring -days without -x509; not generating a certificate\n");
+ if (not_before != NULL)
+ BIO_printf(bio_err, "Warning: Ignoring -not_before without -x509; not generating a certificate\n");
+ if (not_after != NULL)
+ BIO_printf(bio_err, "Warning: Ignoring -not_after without -x509; not generating a certificate\n");
if (ext_copy == EXT_COPY_NONE)
- BIO_printf(bio_err, "Ignoring -copy_extensions 'none' when -x509 is not given\n");
+ BIO_printf(bio_err, "Warning: Ignoring -copy_extensions 'none' when -x509 is not given\n");
}
if (infile == NULL) {
if (gen_x509)
if (!X509_set_issuer_name(new_x509, issuer))
goto end;
- if (days == UNSET_DAYS) {
+ if (days == UNSET_DAYS)
days = DEFAULT_DAYS;
- }
- if (!set_cert_times(new_x509, NULL, NULL, days))
+ else if (not_after != NULL)
+ BIO_printf(bio_err,"Warning: -not_after option overriding -days option\n");
+ if (!set_cert_times(new_x509, not_before, not_after, days, 1))
goto end;
if (!X509_set_subject_name(new_x509, n_subj))
goto end;
#undef POSTFIX
#define POSTFIX ".srl"
-#define DEFAULT_DAYS 30 /* default cert validity period in days */
-#define UNSET_DAYS -2 /* -1 is used for testing expiration checks */
+#define DEFAULT_DAYS 30 /* default certificate validity period in days */
+#define UNSET_DAYS -2 /* -1 may be used for testing expiration checks */
#define EXT_COPY_UNSET -1
static int callb(int ok, X509_STORE_CTX *ctx);
OPT_CLRREJECT, OPT_ALIAS, OPT_CACREATESERIAL, OPT_CLREXT, OPT_OCSPID,
OPT_SUBJECT_HASH_OLD, OPT_ISSUER_HASH_OLD, OPT_COPY_EXTENSIONS,
OPT_BADSIG, OPT_MD, OPT_ENGINE, OPT_NOCERT, OPT_PRESERVE_DATES,
+ OPT_NOT_BEFORE, OPT_NOT_AFTER,
OPT_R_ENUM, OPT_PROV_ENUM, OPT_EXT
} OPTION_CHOICE;
"Serial number to use, overrides -CAserial"},
{"next_serial", OPT_NEXT_SERIAL, '-',
"Increment current certificate serial number"},
+ {"not_before", OPT_NOT_BEFORE, 's',
+ "[CC]YYMMDDHHMMSSZ value for notBefore certificate field"},
+ {"not_after", OPT_NOT_AFTER, 's',
+ "[CC]YYMMDDHHMMSSZ value for notAfter certificate field, overrides -days"},
{"days", OPT_DAYS, 'n',
"Number of days until newly generated certificate expires - default 30"},
{"preserve_dates", OPT_PRESERVE_DATES, '-',
char *ext_names = NULL;
char *extsect = NULL, *extfile = NULL, *passin = NULL, *passinarg = NULL;
char *infile = NULL, *outfile = NULL, *privkeyfile = NULL, *CAfile = NULL;
- char *prog;
+ char *prog, *not_before = NULL, *not_after = NULL;
int days = UNSET_DAYS; /* not explicitly set */
int x509toreq = 0, modulus = 0, print_pubkey = 0, pprint = 0;
int CAformat = FORMAT_UNDEF, CAkeyformat = FORMAT_UNDEF;
if (!vfyopts || !sk_OPENSSL_STRING_push(vfyopts, opt_arg()))
goto opthelp;
break;
+ case OPT_NOT_BEFORE:
+ not_before = opt_arg();
+ break;
+ case OPT_NOT_AFTER:
+ not_after = opt_arg();
+ break;
case OPT_DAYS:
days = atoi(opt_arg());
- if (days < -1) {
+ if (days <= UNSET_DAYS) {
BIO_printf(bio_err, "%s: -days parameter arg must be >= -1\n",
prog);
goto err;
if (!opt_check_md(digest))
goto opthelp;
+ if (preserve_dates && not_before != NULL) {
+ BIO_printf(bio_err, "Cannot use -preserve_dates with -not_before option\n");
+ goto err;
+ }
+ if (preserve_dates && not_after != NULL) {
+ BIO_printf(bio_err, "Cannot use -preserve_dates with -not_after option\n");
+ goto err;
+ }
if (preserve_dates && days != UNSET_DAYS) {
BIO_printf(bio_err, "Cannot use -preserve_dates with -days option\n");
goto err;
}
if (days == UNSET_DAYS)
days = DEFAULT_DAYS;
+ else if (not_after != NULL)
+ BIO_printf(bio_err, "Warning: -not_after option overriding -days option\n");
if (!app_passwd(passinarg, NULL, &passin, NULL)) {
BIO_printf(bio_err, "Error getting password\n");
goto end;
if (reqfile || newcert || privkey != NULL || CAfile != NULL) {
- if (!preserve_dates && !set_cert_times(x, NULL, NULL, days))
+ if (!preserve_dates && !set_cert_times(x, not_before, not_after, days, 1))
goto end;
if (fissu != NULL) {
if (!X509_set_issuer_name(x, fissu))
[B<-crlsec> I<seconds>]
[B<-crlexts> I<section>]
[B<-startdate> I<date>]
+[B<-not_before> I<date>]
[B<-enddate> I<date>]
+[B<-not_after> I<date>]
[B<-days> I<arg>]
[B<-md> I<arg>]
[B<-policy> I<arg>]
Specify the date output format. Values are: rfc_822 and iso_8601.
Defaults to rfc_822.
-=item B<-startdate> I<date>
+=item B<-startdate> I<date>, B<-not_before> I<date>
This allows the start date to be explicitly set. The format of the
date is YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure), or
YYYYMMDDHHMMSSZ (the same as an ASN1 GeneralizedTime structure). In
both formats, seconds SS and timezone Z must be present.
+Alternatively, you can also use "today".
-=item B<-enddate> I<date>
+=item B<-enddate> I<date>, B<-not_after> I<date>
This allows the expiry date to be explicitly set. The format of the
date is YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure), or
YYYYMMDDHHMMSSZ (the same as an ASN1 GeneralizedTime structure). In
both formats, seconds SS and timezone Z must be present.
+Alternatively, you can also use "today".
+
+This overrides the B<-days> option.
=item B<-days> I<arg>
-The number of days to certify the certificate for.
+The number of days from today to certify the certificate for.
+
+Regardless of the option B<-not_before>, the days are always counted from
+today.
+When used together with the option B<-not_after>/B<-startdate>, the explicit
+expiry date takes precedence.
=item B<-md> I<alg>
=item B<default_days>
-The same as the B<-days> option. The number of days to certify
+The same as the B<-days> option. The number of days from today to certify
a certificate for.
=item B<default_startdate>
[B<-x509v1>]
[B<-CA> I<filename>|I<uri>]
[B<-CAkey> I<filename>|I<uri>]
+[B<-not_before> I<date>]
+[B<-not_after> I<date>]
[B<-days> I<n>]
[B<-set_serial> I<n>]
[B<-newhdr>]
The private key must match the public key of the certificate given with B<-CA>.
If this option is not provided then the key must be present in the B<-CA> input.
+=item B<-not_before> I<date>
+
+When B<-x509> is in use this allows the start date to be explicitly set,
+otherwise it is ignored. The format of I<date> is YYMMDDHHMMSSZ (the
+same as an ASN1 UTCTime structure), or YYYYMMDDHHMMSSZ (the same as an
+ASN1 GeneralizedTime structure). In both formats, seconds SS and
+timezone Z must be present.
+Alternatively, you can also use "today".
+
+=item B<-not_after> I<date>
+
+When B<-x509> is in use this allows the expiry date to be explicitly
+set, otherwise it is ignored. The format of I<date> is YYMMDDHHMMSSZ
+(the same as an ASN1 UTCTime structure), or YYYYMMDDHHMMSSZ (the same as
+an ASN1 GeneralizedTime structure). In both formats, seconds SS and
+timezone Z must be present.
+Alternatively, you can also use "today".
+
+This overrides the B<-days> option.
+
=item B<-days> I<n>
-When B<-x509> is in use this specifies the number of
-days to certify the certificate for, otherwise it is ignored. I<n> should
+When B<-x509> is in use this specifies the number of days from today to
+certify the certificate for, otherwise it is ignored. I<n> should
be a positive integer. The default is 30 days.
+Regardless of the option B<-not_before>, the days are always counted from
+today.
+When used together with the option B<-not_after>, the explicit expiry
+date takes precedence.
+
=item B<-set_serial> I<n>
Serial number to use when outputting a self-signed certificate.
[B<-checkip> I<ipaddr>]
[B<-set_serial> I<n>]
[B<-next_serial>]
+[B<-not_before> I<date>]
+[B<-not_after> I<date>]
[B<-days> I<arg>]
[B<-preserve_dates>]
[B<-set_issuer> I<arg>]
Unless the B<-preserve_dates> option is supplied,
it sets the validity start date to the current time
and the end date to a value determined by the B<-days> option.
+Start date and end date can also be explicitly supplied with options
+B<-not_before> and B<-not_after>.
=item B<-signkey> I<filename>|I<uri>
Set the serial to be one more than the number in the certificate.
+=item B<-not_before> I<date>
+
+This allows the start date to be explicitly set. The format of the
+date is YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure), or
+YYYYMMDDHHMMSSZ (the same as an ASN1 GeneralizedTime structure). In
+both formats, seconds SS and timezone Z must be present.
+Alternatively, you can also use "today".
+
+Cannot be used together with the B<-preserve_dates> option.
+
+=item B<-not_after> I<date>
+
+This allows the expiry date to be explicitly set. The format of the
+date is YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure), or
+YYYYMMDDHHMMSSZ (the same as an ASN1 GeneralizedTime structure). In
+both formats, seconds SS and timezone Z must be present.
+Alternatively, you can also use "today".
+
+Cannot be used together with the B<-preserve_dates> option.
+This overrides the option B<-days>.
+
=item B<-days> I<arg>
-Specifies the number of days until a newly generated certificate expires.
+Specifies the number of days from today until a newly generated certificate expires.
The default is 30.
-Cannot be used together with the B<-preserve_dates> option.
+
+Cannot be used together with the option B<-preserve_dates>.
+If option B<-not_after> is set, the explicit expiry date takes precedence.
=item B<-preserve_dates>
When signing a certificate, preserve "notBefore" and "notAfter" dates of any
input certificate instead of adjusting them to current time and duration.
-Cannot be used together with the B<-days> option.
+Cannot be used together with the options B<-days>, B<-not_before> and B<-not_after>.
=item B<-set_issuer> I<arg>
setup("test_req");
-plan tests => 108;
+plan tests => 109;
require_ok(srctop_file('test', 'recipes', 'tconversion.pl'));
# Verify cert
ok(run(app(["openssl", "x509", "-in", "testreq-cert.pem",
"-noout", "-text"])), "cert verification");
+
+# Generate cert with explicit start and end dates
+my $today = strftime("%Y-%m-%d", localtime);
+my $cert = "self-signed_explicit_date.pem";
+ok(run(app(["openssl", "req", "-x509", "-new", "-text",
+ "-config", srctop_file('test', 'test.cnf'),
+ "-key", srctop_file("test", "testrsa.pem"),
+ "-not_before", "today",
+ "-not_after", "today",
+ "-out", $cert]))
+&& get_not_before_date($cert) eq $today
+&& get_not_after_date($cert) eq $today, "explicit start and end dates");
setup("test_x509");
-plan tests => 46;
+plan tests => 51;
# Prevent MSys2 filename munging for arguments that look like file paths but
# aren't
"-in", srctop_file("test/certs", "ca-cert.pem")])),
"Run with invalid -dateopt format");
-# extracts issuer from a -text formatted-output
-sub get_issuer {
- my $f = shift(@_);
- my $issuer = "";
- open my $fh, $f or die;
- while (my $line = <$fh>) {
- if ($line =~ /Issuer:/) {
- $issuer = $line;
- }
- }
- close $fh;
- return $issuer;
-}
-
# Tests for signing certs (broken in 1.1.1o)
my $a_key = "a-key.pem";
my $a_cert = "a-cert.pem";
"-CAkey", $ca_key, "-set_serial", "1234567890",
"-preserve_dates", "-sha256", "-text", "-out", $a2_cert])));
# verify issuer is CA
-ok (get_issuer($a2_cert) =~ /CN=ca.example.com/);
+ok(get_issuer($a2_cert) =~ /CN=ca.example.com/);
my $in_csr = srctop_file('test', 'certs', 'x509-check.csr');
my $in_key = srctop_file('test', 'certs', 'x509-check-key.pem');
"-in", $b_csr])));
ok(-e $ca_serial_dot_in_dir);
+# Tests for explict start and end dates of certificates
+my $today;
+my $enddate;
+$today = strftime("%Y-%m-%d", localtime);
+ok(run(app(["openssl", "x509", "-req", "-text",
+ "-key", $b_key,
+ "-not_before", "20231031000000Z",
+ "-not_after", "today",
+ "-in", $b_csr, "-out", $b_cert]))
+&& get_not_before($b_cert) =~ /Oct 31 00:00:00 2023 GMT/
+&& get_not_after_date($b_cert) eq $today);
+# explicit start and end dates
+ok(run(app(["openssl", "x509", "-req", "-text",
+ "-key", $b_key,
+ "-not_before", "20231031000000Z",
+ "-not_after", "20231231000000Z",
+ "-days", "99",
+ "-in", $b_csr, "-out", $b_cert]))
+&& get_not_before($b_cert) =~ /Oct 31 00:00:00 2023 GMT/
+&& get_not_after($b_cert) =~ /Dec 31 00:00:00 2023 GMT/);
+# start date today and days
+$today = strftime("%Y-%m-%d", localtime);
+$enddate = strftime("%Y-%m-%d", localtime(time + 99 * 24 * 60 * 60));
+ok(run(app(["openssl", "x509", "-req", "-text",
+ "-key", $b_key,
+ "-not_before", "today",
+ "-days", "99",
+ "-in", $b_csr, "-out", $b_cert]))
+&& get_not_before_date($b_cert) eq $today
+&& get_not_after_date($b_cert) eq $enddate);
+# end date before start date
+ok(!run(app(["openssl", "x509", "-req", "-text",
+ "-key", $b_key,
+ "-not_before", "today",
+ "-not_after", "20231031000000Z",
+ "-in", $b_csr, "-out", $b_cert])));
+# default days option
+$today = strftime("%Y-%m-%d", localtime);
+$enddate = strftime("%Y-%m-%d", localtime(time + 30 * 24 * 60 * 60));
+ok(run(app(["openssl", "x509", "-req", "-text",
+ "-key", $b_key,
+ "-in", $b_csr, "-out", $b_cert]))
+&& get_not_before_date($b_cert) eq $today
+&& get_not_after_date($b_cert) eq $enddate);
+
SKIP: {
skip "EC is not supported by this OpenSSL build", 1
if disabled("ec");
use File::Compare qw/compare_text/;
use File::Copy;
use OpenSSL::Test qw/:DEFAULT/;
+use Time::Piece;
+use POSIX qw(strftime);
my %conversionforms = (
# Default conversion forms. Other series may be added with
# not unlinking $out
}
+# extracts string value of certificate field from a -text formatted-output
+sub get_field {
+ my ($f, $field) = @_;
+ my $string = "";
+ open my $fh, $f or die;
+ while (my $line = <$fh>) {
+ if ($line =~ /$field:\s+(.*)/) {
+ $string = $1;
+ }
+ }
+ close $fh;
+ return $string;
+}
+
+sub get_issuer {
+ return get_field(@_, "Issuer");
+}
+
+sub get_not_before {
+ return get_field(@_, "Not Before");
+}
+
+# Date as yyyy-mm-dd
+sub get_not_before_date {
+ return Time::Piece->strptime(
+ get_not_before(@_),
+ "%b %d %T %Y %Z")->date;
+}
+
+sub get_not_after {
+ return get_field(@_, "Not After ");
+}
+
+# Date as yyyy-mm-dd
+sub get_not_after_date {
+ return Time::Piece->strptime(
+ get_not_after(@_),
+ "%b %d %T %Y %Z")->date;
+}
+
1;