diff options
author | Stephan Wurm <atomisirsi@gsklan.de> | 2023-08-09 09:07:46 +0200 |
---|---|---|
committer | Tomas Mraz <tomas@openssl.org> | 2024-04-09 20:13:31 +0200 |
commit | 8120223773d4c707dd43d9cc42a7fcab19609813 (patch) | |
tree | d6ba640c8b11135d9c6f214a507bbcbad744804f /apps | |
parent | 4514e02cdfc96589d5e8ab0a08942fafa8e418ae (diff) |
apps: ca,req,x509: Add explicit start and end dates options
- Added options `-not_before` (start date) and `-not-after` (end date)
for explicit setting of the validity period of a certificate in the
apps `ca`, `req` and `x509`
- The new options accept time strings or "today"
- In app `ca`, use the new options as aliases of the already existing
options `-startdate` and `-enddate`
- When used in apps `req` and `x509`, the end date must be >= the start
date, in app `ca` end date < start date is also accepted
- In any case, `-not-after` overrides the `-days` option
- Added helper function `check_cert_time_string` to validate given
certificate time strings
- Use the new helper function in apps `ca`, `req` and `x509`
- Moved redundant code for time string checking into `set_cert_times`
helper function.
- Added tests for explicit start and end dates in apps `req` and `x509`
- test: Added auxiliary functions for parsing fields from `-text`
formatted output to `tconversion.pl`
- CHANGES: Added to new section 3.4
Signed-off-by: Stephan Wurm <atomisirsi@gsklan.de>
Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21716)
Diffstat (limited to 'apps')
-rw-r--r-- | apps/ca.c | 32 | ||||
-rw-r--r-- | apps/include/apps.h | 6 | ||||
-rw-r--r-- | apps/lib/apps.c | 41 | ||||
-rw-r--r-- | apps/req.c | 34 | ||||
-rw-r--r-- | apps/x509.c | 31 |
5 files changed, 105 insertions, 39 deletions
@@ -150,7 +150,7 @@ typedef enum OPTION_choice { 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, @@ -199,10 +199,13 @@ const OPTIONS ca_options[] = { "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, '<', @@ -359,9 +362,11 @@ opthelp: /* 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: @@ -874,22 +879,8 @@ end_of_options: 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; @@ -898,6 +889,9 @@ end_of_options: 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)) { @@ -1671,7 +1665,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, goto end; } - if (!set_cert_times(ret, startdate, enddate, days)) + if (!set_cert_times(ret, startdate, enddate, days, 0)) goto end; if (enddate != NULL) { diff --git a/apps/include/apps.h b/apps/include/apps.h index a1b2cbbdc3..f1d5fccc41 100644 --- a/apps/include/apps.h +++ b/apps/include/apps.h @@ -82,8 +82,12 @@ int has_stdin_waiting(void); # 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); diff --git a/apps/lib/apps.c b/apps/lib/apps.c index e04530ff44..c87f0f02f1 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -3275,23 +3275,54 @@ void corrupt_signature(const ASN1_STRING *signature) 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; } diff --git a/apps/req.c b/apps/req.c index b54a489722..dfa8319156 100644 --- a/apps/req.c +++ b/apps/req.c @@ -43,7 +43,7 @@ #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 @@ -87,7 +87,7 @@ typedef enum OPTION_choice { 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, @@ -127,7 +127,11 @@ const OPTIONS req_options[] = { "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"}, @@ -259,6 +263,7 @@ int req_main(int argc, char **argv) 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; @@ -423,9 +428,15 @@ int req_main(int argc, char **argv) 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; @@ -494,9 +505,13 @@ int req_main(int argc, char **argv) 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) @@ -802,10 +817,11 @@ int req_main(int argc, char **argv) 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; diff --git a/apps/x509.c b/apps/x509.c index d96e7819b2..cd5b7bf796 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -29,8 +29,8 @@ #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); @@ -54,6 +54,7 @@ typedef enum OPTION_choice { 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; @@ -135,6 +136,10 @@ const OPTIONS x509_options[] = { "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, '-', @@ -279,7 +284,7 @@ int x509_main(int argc, char **argv) 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; @@ -376,9 +381,15 @@ int x509_main(int argc, char **argv) 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; @@ -610,12 +621,22 @@ int x509_main(int argc, char **argv) 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"); @@ -837,7 +858,7 @@ int x509_main(int argc, char **argv) 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)) |