[openssh-commits] [openssh] 01/07: upstream: add valid-before="[time]" authorized_keys option. A

git+noreply at mindrot.org git+noreply at mindrot.org
Wed Mar 14 18:56:04 AEDT 2018


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit bf0fbf2b11a44f06a64b620af7d01ff171c28e13
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Mon Mar 12 00:52:01 2018 +0000

    upstream: add valid-before="[time]" authorized_keys option. A
    
    simple way of giving a key an expiry date. ok markus@
    
    OpenBSD-Commit-ID: 1793b4dd5184fa87f42ed33c7b0f4f02bc877947
---
 auth-options.c | 32 +++++++++++++++++++++++++++++---
 auth-options.h |  5 ++++-
 auth.c         | 28 +++++++++++++++++++++++-----
 misc.c         | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 misc.h         |  4 +++-
 ssh-keygen.1   |  8 ++++----
 ssh-keygen.c   | 44 +++++---------------------------------------
 sshd.8         |  8 ++++++--
 8 files changed, 128 insertions(+), 56 deletions(-)

diff --git a/auth-options.c b/auth-options.c
index 484e44b7..38211fa2 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.c,v 1.76 2018/03/03 03:15:51 djm Exp $ */
+/* $OpenBSD: auth-options.c,v 1.77 2018/03/12 00:52:01 djm Exp $ */
 /*
  * Copyright (c) 2018 Damien Miller <djm at mindrot.org>
  *
@@ -311,6 +311,7 @@ sshauthopt_parse(const char *opts, const char **errstrp)
 	int r;
 	struct sshauthopt *ret = NULL;
 	const char *errstr = "unknown error";
+	uint64_t valid_before;
 
 	if (errstrp != NULL)
 		*errstrp = NULL;
@@ -366,6 +367,19 @@ sshauthopt_parse(const char *opts, const char **errstrp)
 			    &errstr);
 			if (ret->required_from_host_keys == NULL)
 				goto fail;
+		} else if (opt_match(&opts, "valid-before")) {
+			if ((opt = opt_dequote(&opts, &errstr)) == NULL)
+				goto fail;
+			if (parse_absolute_time(opt, &valid_before) != 0 ||
+			    valid_before == 0) {
+				free(opt);
+				errstr = "invalid expires time";
+				goto fail;
+			}
+			free(opt);
+			if (ret->valid_before == 0 ||
+			    valid_before < ret->valid_before)
+				ret->valid_before = valid_before;
 		} else if (opt_match(&opts, "environment")) {
 			if (ret->nenv > INT_MAX) {
 				errstr = "too many environment strings";
@@ -572,6 +586,13 @@ sshauthopt_merge(const struct sshauthopt *primary,
 	OPTFLAG(permit_user_rc);
 #undef OPTFLAG
 
+	/* Earliest expiry time should win */
+	if (primary->valid_before != 0)
+		ret->valid_before = primary->valid_before;
+	if (additional->valid_before != 0 &&
+	    additional->valid_before < ret->valid_before)
+		ret->valid_before = additional->valid_before;
+
 	/*
 	 * When both multiple forced-command are specified, only
 	 * proceed if they are identical, otherwise fail.
@@ -631,6 +652,7 @@ sshauthopt_copy(const struct sshauthopt *orig)
 	OPTSCALAR(restricted);
 	OPTSCALAR(cert_authority);
 	OPTSCALAR(force_tun_device);
+	OPTSCALAR(valid_before);
 #undef OPTSCALAR
 #define OPTSTRING(x) \
 	do { \
@@ -751,14 +773,15 @@ sshauthopt_serialise(const struct sshauthopt *opts, struct sshbuf *m,
 {
 	int r = SSH_ERR_INTERNAL_ERROR;
 
-	/* Flag options */
+	/* Flag and simple integer options */
 	if ((r = sshbuf_put_u8(m, opts->permit_port_forwarding_flag)) != 0 ||
 	    (r = sshbuf_put_u8(m, opts->permit_agent_forwarding_flag)) != 0 ||
 	    (r = sshbuf_put_u8(m, opts->permit_x11_forwarding_flag)) != 0 ||
 	    (r = sshbuf_put_u8(m, opts->permit_pty_flag)) != 0 ||
 	    (r = sshbuf_put_u8(m, opts->permit_user_rc)) != 0 ||
 	    (r = sshbuf_put_u8(m, opts->restricted)) != 0 ||
-	    (r = sshbuf_put_u8(m, opts->cert_authority)) != 0)
+	    (r = sshbuf_put_u8(m, opts->cert_authority)) != 0 ||
+	    (r = sshbuf_put_u64(m, opts->valid_before)) != 0)
 		return r;
 
 	/* tunnel number can be negative to indicate "unset" */
@@ -815,6 +838,9 @@ sshauthopt_deserialise(struct sshbuf *m, struct sshauthopt **optsp)
 	OPT_FLAG(cert_authority);
 #undef OPT_FLAG
 
+	if ((r = sshbuf_get_u64(m, &opts->valid_before)) != 0)
+		goto out;
+
 	/* tunnel number can be negative to indicate "unset" */
 	if ((r = sshbuf_get_u8(m, &f)) != 0 ||
 	    (r = sshbuf_get_u32(m, &tmp)) != 0)
diff --git a/auth-options.h b/auth-options.h
index 16871d75..bf59b30b 100644
--- a/auth-options.h
+++ b/auth-options.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.h,v 1.25 2018/03/03 03:15:51 djm Exp $ */
+/* $OpenBSD: auth-options.h,v 1.26 2018/03/12 00:52:01 djm Exp $ */
 
 /*
  * Copyright (c) 2018 Damien Miller <djm at mindrot.org>
@@ -37,6 +37,9 @@ struct sshauthopt {
 	/* "restrict" keyword was invoked */
 	int restricted;
 
+	/* key/principal expiry date */
+	uint64_t valid_before;
+
 	/* Certificate-related options */
 	int cert_authority;
 	char *cert_principals;
diff --git a/auth.c b/auth.c
index 041a09e3..63366768 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.126 2018/03/03 03:15:51 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.127 2018/03/12 00:52:01 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -1004,20 +1004,21 @@ auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
 	int do_permitopen = opts->npermitopen > 0 &&
 	    (options.allow_tcp_forwarding & FORWARD_LOCAL) != 0;
 	size_t i;
-	char msg[1024], tbuf[32];
+	char msg[1024], buf[64];
 
-	snprintf(tbuf, sizeof(tbuf), "%d", opts->force_tun_device);
+	snprintf(buf, sizeof(buf), "%d", opts->force_tun_device);
 	/* Try to keep this alphabetically sorted */
-	snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s",
+	snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s",
 	    opts->permit_agent_forwarding_flag ? " agent-forwarding" : "",
 	    opts->force_command == NULL ? "" : " command",
 	    do_env ?  " environment" : "",
+	    opts->valid_before == 0 ? "" : "expires",
 	    do_permitopen ?  " permitopen" : "",
 	    opts->permit_port_forwarding_flag ? " port-forwarding" : "",
 	    opts->cert_principals == NULL ? "" : " principals",
 	    opts->permit_pty_flag ? " pty" : "",
 	    opts->force_tun_device == -1 ? "" : " tun=",
-	    opts->force_tun_device == -1 ? "" : tbuf,
+	    opts->force_tun_device == -1 ? "" : buf,
 	    opts->permit_user_rc ? " user-rc" : "",
 	    opts->permit_x11_forwarding_flag ? " x11-forwarding" : "");
 
@@ -1036,6 +1037,10 @@ auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
 	}
 
 	/* Go into a little more details for the local logs. */
+	if (opts->valid_before != 0) {
+		format_absolute_time(opts->valid_before, buf, sizeof(buf));
+		debug("%s: expires at %s", loc, buf);
+	}
 	if (opts->cert_principals != NULL) {
 		debug("%s: authorized principals: \"%s\"",
 		    loc, opts->cert_principals);
@@ -1089,7 +1094,20 @@ auth_authorise_keyopts(struct ssh *ssh, struct passwd *pw,
 	const char *remote_ip = ssh_remote_ipaddr(ssh);
 	const char *remote_host = auth_get_canonical_hostname(ssh,
 	    options.use_dns);
+	time_t now = time(NULL);
+	char buf[64];
 
+	/*
+	 * Check keys/principals file expiry time.
+	 * NB. validity interval in certificate is handled elsewhere.
+	 */
+	if (opts->valid_before && now > 0 &&
+	    opts->valid_before < (uint64_t)now) {
+		format_absolute_time(opts->valid_before, buf, sizeof(buf));
+		debug("%s: entry expired at %s", loc, buf);
+		auth_debug_add("%s: entry expired at %s", loc, buf);
+		return -1;
+	}
 	/* Consistency checks */
 	if (opts->cert_principals != NULL && !opts->cert_authority) {
 		debug("%s: principals on non-CA key", loc);
diff --git a/misc.c b/misc.c
index fbc36310..874dcc8a 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.126 2018/03/07 23:53:08 djm Exp $ */
+/* $OpenBSD: misc.c,v 1.127 2018/03/12 00:52:01 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2005,2006 Damien Miller.  All rights reserved.
@@ -1976,3 +1976,56 @@ atoi_err(const char *nptr, int *val)
 		*val = (int)num;
 	return errstr;
 }
+
+int
+parse_absolute_time(const char *s, uint64_t *tp)
+{
+	struct tm tm;
+	time_t tt;
+	char buf[32], *fmt;
+
+	*tp = 0;
+
+	/*
+	 * 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)) {
+	case 8: /* YYYYMMDD */
+		fmt = "%Y-%m-%d";
+		snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6);
+		break;
+	case 12: /* YYYYMMDDHHMM */
+		fmt = "%Y-%m-%dT%H:%M";
+		snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s",
+		    s, s + 4, s + 6, s + 8, s + 10);
+		break;
+	case 14: /* YYYYMMDDHHMMSS */
+		fmt = "%Y-%m-%dT%H:%M:%S";
+		snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s",
+		    s, s + 4, s + 6, s + 8, s + 10, s + 12);
+		break;
+	default:
+		return SSH_ERR_INVALID_FORMAT;
+	}
+
+	memset(&tm, 0, sizeof(tm));
+	if (strptime(buf, fmt, &tm) == NULL)
+		return SSH_ERR_INVALID_FORMAT;
+	if ((tt = mktime(&tm)) < 0)
+		return SSH_ERR_INVALID_FORMAT;
+	/* success */
+	*tp = (uint64_t)tt;
+	return 0;
+}
+
+void
+format_absolute_time(uint64_t t, char *buf, size_t len)
+{
+	time_t tt = t > INT_MAX ? INT_MAX : t; /* XXX revisit in 2038 :P */
+	struct tm tm;
+
+	localtime_r(&tt, &tm);
+	strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
+}
diff --git a/misc.h b/misc.h
index 8f778067..cdafea73 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.70 2018/01/08 15:21:49 markus Exp $ */
+/* $OpenBSD: misc.h,v 1.71 2018/03/12 00:52:01 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -75,6 +75,8 @@ void	 lowercase(char *s);
 int	 unix_listener(const char *, int, int);
 int	 valid_domain(char *, int, const char **);
 const char *atoi_err(const char *, int *);
+int	 parse_absolute_time(const char *, uint64_t *);
+void	 format_absolute_time(uint64_t, char *, size_t);
 
 void	 sock_set_v6only(int);
 
diff --git a/ssh-keygen.1 b/ssh-keygen.1
index f925eb2d..3525d7d1 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -1,4 +1,4 @@
-.\"	$OpenBSD: ssh-keygen.1,v 1.146 2018/01/25 03:34:43 djm Exp $
+.\"	$OpenBSD: ssh-keygen.1,v 1.147 2018/03/12 00:52:01 djm Exp $
 .\"
 .\" Author: Tatu Ylonen <ylo at cs.hut.fi>
 .\" Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, 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: January 25 2018 $
+.Dd $Mdocdate: March 12 2018 $
 .Dt SSH-KEYGEN 1
 .Os
 .Sh NAME
@@ -588,13 +588,13 @@ of two times separated by a colon to indicate an explicit time interval.
 The start time may be specified as the string
 .Dq always
 to indicate the certificate has no specified start time,
-a date in YYYYMMDD format, a time in YYYYMMDDHHMMSS format,
+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
 TIME FORMATS section of
 .Xr sshd_config 5 .
 .Pp
-The end time may be specified as a YYYYMMDD date, a YYYYMMDDHHMMSS time,
+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
 .Dq forever
 to indicate that the certificate has no expirty date.
diff --git a/ssh-keygen.c b/ssh-keygen.c
index d80930ee..9aac64fc 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keygen.c,v 1.313 2018/02/23 15:58:38 markus Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.314 2018/03/12 00:52:01 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1994 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -1798,40 +1798,6 @@ parse_relative_time(const char *s, time_t now)
 	return now + (u_int64_t)(secs * mul);
 }
 
-static u_int64_t
-parse_absolute_time(const char *s)
-{
-	struct tm tm;
-	time_t tt;
-	char buf[32], *fmt;
-
-	/*
-	 * 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)) {
-	case 8:
-		fmt = "%Y-%m-%d";
-		snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6);
-		break;
-	case 14:
-		fmt = "%Y-%m-%dT%H:%M:%S";
-		snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s",
-		    s, s + 4, s + 6, s + 8, s + 10, s + 12);
-		break;
-	default:
-		fatal("Invalid certificate time format \"%s\"", s);
-	}
-
-	memset(&tm, 0, sizeof(tm));
-	if (strptime(buf, fmt, &tm) == NULL)
-		fatal("Invalid certificate time %s", s);
-	if ((tt = mktime(&tm)) < 0)
-		fatal("Certificate time %s cannot be represented", s);
-	return (u_int64_t)tt;
-}
-
 static void
 parse_cert_times(char *timespec)
 {
@@ -1867,15 +1833,15 @@ parse_cert_times(char *timespec)
 		cert_valid_from = parse_relative_time(from, now);
 	else if (strcmp(from, "always") == 0)
 		cert_valid_from = 0;
-	else
-		cert_valid_from = parse_absolute_time(from);
+	else if (parse_absolute_time(from, &cert_valid_from) != 0)
+		fatal("Invalid from time \"%s\"", from);
 
 	if (*to == '-' || *to == '+')
 		cert_valid_to = parse_relative_time(to, now);
 	else if (strcmp(to, "forever") == 0)
 		cert_valid_to = ~(u_int64_t)0;
-	else
-		cert_valid_to = parse_absolute_time(to);
+	else if (parse_absolute_time(to, &cert_valid_to) != 0)
+		fatal("Invalid to time \"%s\"", to);
 
 	if (cert_valid_to <= cert_valid_from)
 		fatal("Empty certificate validity interval");
diff --git a/sshd.8 b/sshd.8
index 0d52cc50..f973cc38 100644
--- a/sshd.8
+++ b/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.296 2018/03/03 06:37:53 dtucker Exp $
-.Dd $Mdocdate: March 3 2018 $
+.\" $OpenBSD: sshd.8,v 1.297 2018/03/12 00:52:01 djm Exp $
+.Dd $Mdocdate: March 12 2018 $
 .Dt SSHD 8
 .Os
 .Sh NAME
@@ -602,6 +602,10 @@ Enables execution of
 previously disabled by the
 .Cm restrict
 option.
+.It Cm valid-before="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.
 .It Cm X11-forwarding
 Permits X11 forwarding previously disabled by the
 .Cm restrict

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list