From: djm Date: Thu, 11 Aug 2022 01:56:51 +0000 (+0000) Subject: allow certificate validity intervals, sshsig verification times and X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=91000222d6df2abbf610bdca03f3c18d6298592f;p=openbsd allow certificate validity intervals, sshsig verification times and authorized_keys expiry-time options to accept dates in the UTC time zone in addition to the default of interpreting them in the system time zone. YYYYMMDD and YYMMDDHHMM[SS] dates/times will be interpreted as UTC if suffixed with a 'Z' character. Also allow certificate validity intervals to be specified in raw seconds-since-epoch as hex value, e.g. -V 0x1234:0x4567890. This is intended for use by regress tests and other tools that call ssh-keygen as part of a CA workflow. bz3468 ok dtucker --- diff --git a/usr.bin/ssh/misc.c b/usr.bin/ssh/misc.c index a864b87fa5b..f3534e48465 100644 --- a/usr.bin/ssh/misc.c +++ b/usr.bin/ssh/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.176 2022/06/03 04:30:47 djm Exp $ */ +/* $OpenBSD: misc.c,v 1.177 2022/08/11 01:56:51 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005-2020 Damien Miller. All rights reserved. @@ -2299,15 +2299,26 @@ parse_absolute_time(const char *s, uint64_t *tp) struct tm tm; time_t tt; char buf[32], *fmt; + const char *cp; + size_t l; + int is_utc = 0; *tp = 0; + l = strlen(s); + if (l > 1 && strcasecmp(s + l - 1, "Z") == 0) { + is_utc = 1; + l--; + } else if (l > 3 && strcasecmp(s + l - 3, "UTC") == 0) { + is_utc = 1; + l -= 3; + } /* * POSIX strptime says "The application shall ensure that there * is white-space or other non-alphanumeric characters between * any two conversion specifications" so arrange things this way. */ - switch (strlen(s)) { + switch (l) { case 8: /* YYYYMMDD */ fmt = "%Y-%m-%d"; snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6); @@ -2327,10 +2338,15 @@ parse_absolute_time(const char *s, uint64_t *tp) } memset(&tm, 0, sizeof(tm)); - if (strptime(buf, fmt, &tm) == NULL) - return SSH_ERR_INVALID_FORMAT; - if ((tt = mktime(&tm)) < 0) + if ((cp = strptime(buf, fmt, &tm)) == NULL || *cp != '\0') return SSH_ERR_INVALID_FORMAT; + if (is_utc) { + if ((tt = timegm(&tm)) < 0) + return SSH_ERR_INVALID_FORMAT; + } else { + if ((tt = mktime(&tm)) < 0) + return SSH_ERR_INVALID_FORMAT; + } /* success */ *tp = (uint64_t)tt; return 0; diff --git a/usr.bin/ssh/ssh-keygen.1 b/usr.bin/ssh/ssh-keygen.1 index 5f429813769..6aeab1cb0cd 100644 --- a/usr.bin/ssh/ssh-keygen.1 +++ b/usr.bin/ssh/ssh-keygen.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keygen.1,v 1.223 2022/06/03 03:17:42 dtucker Exp $ +.\" $OpenBSD: ssh-keygen.1,v 1.224 2022/08/11 01:56:51 djm Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -35,7 +35,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: June 3 2022 $ +.Dd $Mdocdate: August 11 2022 $ .Dt SSH-KEYGEN 1 .Os .Sh NAME @@ -511,8 +511,11 @@ Print the full public key to standard output after signature verification. .It Cm verify-time Ns = Ns Ar timestamp Specifies a time to use when validating signatures instead of the current time. -The time may be specified as a date in YYYYMMDD format or a time -in YYYYMMDDHHMM[SS] format. +The time may be specified as a date or time in the YYYYMMDD[Z] or +in YYYYMMDDHHMM[SS][Z] formats. +Dates and times will be interpreted in the current system time zone unless +suffixed with a Z character, which causes them to be interpreted in the +UTC time zone. .El .Pp The @@ -603,31 +606,67 @@ A validity interval may consist of a single time, indicating that the certificate is valid beginning now and expiring at that time, or may consist of two times separated by a colon to indicate an explicit time interval. .Pp -The start time may be specified as the string +The start time may be specified as: +.Bl -bullet -compact +.It +The string .Dq always -to indicate the certificate has no specified start time, -a date in YYYYMMDD format, a time in YYYYMMDDHHMM[SS] format, -a relative time (to the current time) consisting of a minus sign followed by -an interval in the format described in the +to indicate the certificate has no specified start time. +.It +A date or time in the system time zone formatted as YYYYMMDD or +YYYYMMDDHHMM[SS]. +.It +A date or time in the UTC time zone as YYYYMMDDZ or YYYYMMDDHHMM[SS]Z. +.It +A relative time before the current system time consisting of a minus sign +followed by an interval in the format described in the TIME FORMATS section of .Xr sshd_config 5 . +.It +A raw seconds since epoch (Jan 1 1970 00:00:00 UTC) as a hexadecimal +number beginning with +.Dq 0x . +.El .Pp -The end time may be specified as a YYYYMMDD date, a YYYYMMDDHHMM[SS] time, -a relative time starting with a plus character or the string +The end time may be specified similarly to the start time: +.Bl -bullet -compact +.It +The string .Dq forever -to indicate that the certificate has no expiry date. +to indicate the certificate has no specified end time. +.It +A date or time in the system time zone formatted as YYYYMMDD or +YYYYMMDDHHMM[SS]. +.It +A date or time in the UTC time zone as YYYYMMDDZ or YYYYMMDDHHMM[SS]Z. +.It +A relative time after the current system time consisting of a plus sign +followed by an interval in the format described in the +TIME FORMATS section of +.Xr sshd_config 5 . +.It +A raw seconds since epoch (Jan 1 1970 00:00:00 UTC) as a hexadecimal +number beginning with +.Dq 0x . +.El .Pp For example: -.Dq +52w1d -(valid from now to 52 weeks and one day from now), -.Dq -4w:+4w -(valid from four weeks ago to four weeks from now), -.Dq 20100101123000:20110101123000 -(valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011), -.Dq -1d:20110101 -(valid from yesterday to midnight, January 1st, 2011), -.Dq -1m:forever -(valid from one minute ago and never expiring). +.Bl -tag -width Ds +.It +52w1d +Valid from now to 52 weeks and one day from now. +.It -4w:+4w +Valid from four weeks ago to four weeks from now. +.It 20100101123000:20110101123000 +Valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011. +.It 20100101123000Z:20110101123000Z +Similar, but interpreted in the UTC time zone rather than the system time zone. +.It -1d:20110101 +Valid from yesterday to midnight, January 1st, 2011. +.It 0x1:0x2000000000 +Valid from roughly early 1970 to May 2033. +.It -1m:forever +Valid from one minute ago and never expiring. +.El .It Fl v Verbose mode. Causes @@ -1206,7 +1245,10 @@ signature object and presented on the verification command-line must match the specified list before the key will be considered acceptable. .It Cm valid-after Ns = Ns "timestamp" Indicates that the key is valid for use at or after the specified timestamp, -which may be a date in YYYYMMDD format or a time in YYYYMMDDHHMM[SS] format. +which may be a date or time in the YYYYMMDD[Z] or YYYYMMDDHHMM[SS][Z] formats. +Dates and times will be interpreted in the current system time zone unless +suffixed with a Z character, which causes them to be interpreted in the UTC +time zone. .It Cm valid-before Ns = Ns "timestamp" Indicates that the key is valid for use at or before the specified timestamp. .El diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c index 556679d0635..e3271585825 100644 --- a/usr.bin/ssh/ssh-keygen.c +++ b/usr.bin/ssh/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.458 2022/08/05 05:01:40 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.459 2022/08/11 01:56:51 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -1893,6 +1893,21 @@ parse_relative_time(const char *s, time_t now) return now + (u_int64_t)(secs * mul); } +static void +parse_hex_u64(const char *s, uint64_t *up) +{ + char *ep; + unsigned long long ull; + + errno = 0; + ull = strtoull(s, &ep, 16); + if (*s == '\0' || *ep != '\0') + fatal("Invalid certificate time: not a number"); + if (errno == ERANGE && ull == ULONG_MAX) + fatal_fr(SSH_ERR_SYSTEM_ERROR, "Invalid certificate time"); + *up = (uint64_t)ull; +} + static void parse_cert_times(char *timespec) { @@ -1915,8 +1930,8 @@ parse_cert_times(char *timespec) /* * from:to, where - * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | "always" - * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | "forever" + * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | 0x... | "always" + * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | 0x... | "forever" */ from = xstrdup(timespec); to = strchr(from, ':'); @@ -1928,6 +1943,8 @@ parse_cert_times(char *timespec) cert_valid_from = parse_relative_time(from, now); else if (strcmp(from, "always") == 0) cert_valid_from = 0; + else if (strncmp(from, "0x", 2) == 0) + parse_hex_u64(from, &cert_valid_from); else if (parse_absolute_time(from, &cert_valid_from) != 0) fatal("Invalid from time \"%s\"", from); @@ -1935,6 +1952,8 @@ parse_cert_times(char *timespec) cert_valid_to = parse_relative_time(to, now); else if (strcmp(to, "forever") == 0) cert_valid_to = ~(u_int64_t)0; + else if (strncmp(from, "0x", 2) == 0) + parse_hex_u64(to, &cert_valid_to); else if (parse_absolute_time(to, &cert_valid_to) != 0) fatal("Invalid to time \"%s\"", to); diff --git a/usr.bin/ssh/sshd.8 b/usr.bin/ssh/sshd.8 index b3684caab88..d356071bb01 100644 --- a/usr.bin/ssh/sshd.8 +++ b/usr.bin/ssh/sshd.8 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd.8,v 1.319 2022/05/02 05:40:37 jmc Exp $ -.Dd $Mdocdate: May 2 2022 $ +.\" $OpenBSD: sshd.8,v 1.320 2022/08/11 01:56:51 djm Exp $ +.Dd $Mdocdate: August 11 2022 $ .Dt SSHD 8 .Os .Sh NAME @@ -506,8 +506,9 @@ controlled via the option. .It Cm expiry-time="timespec" Specifies a time after which the key will not be accepted. -The time may be specified as a YYYYMMDD date or a YYYYMMDDHHMM[SS] time -in the system time-zone. +The time may be specified as a YYYYMMDD[Z] date or a YYYYMMDDHHMM[SS][Z] time. +Dates and times will be interpreted in the system time zone unless suffixed +by a Z character, in which case they will be interpreted in the UTC time zone. .It Cm from="pattern-list" Specifies that in addition to public key authentication, either the canonical name of the remote host or its IP address must be present in the