From e7907c1cb938b96dd33d27c2fea72c4e08c6b2f6 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 14 Sep 2016 05:42:25 +0000 Subject: upstream commit add %-escapes to AuthorizedPrincipalsCommand to match those supported for AuthorizedKeysCommand (key, key type, fingerprint, etc) and a few more to provide access to the certificate's CA key; 'looks ok' dtucker@ Upstream-ID: 6b00fd446dbebe67f4e4e146d2e492d650ae04eb --- auth2-pubkey.c | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) (limited to 'auth2-pubkey.c') diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 41b34aed2..5e1b88900 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.55 2016/01/27 00:53:12 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.56 2016/09/14 05:42:25 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -560,7 +560,7 @@ match_principals_option(const char *principal_list, struct sshkey_cert *cert) static int process_principals(FILE *f, char *file, struct passwd *pw, - struct sshkey_cert *cert) + const struct sshkey_cert *cert) { char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; u_long linenum = 0; @@ -629,14 +629,16 @@ match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) * returns 1 if the principal is allowed or 0 otherwise. */ static int -match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert) +match_principals_command(struct passwd *user_pw, const struct sshkey *key) { + const struct sshkey_cert *cert = key->cert; FILE *f = NULL; - int ok, found_principal = 0; + int r, ok, found_principal = 0; struct passwd *pw; int i, ac = 0, uid_swapped = 0; pid_t pid; char *tmp, *username = NULL, *command = NULL, **av = NULL; + char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL; void (*osigchld)(int); if (options.authorized_principals_command == NULL) @@ -674,10 +676,34 @@ match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert) command); goto out; } + if ((ca_fp = sshkey_fingerprint(cert->signature_key, + options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { + error("%s: sshkey_fingerprint failed", __func__); + goto out; + } + if ((key_fp = sshkey_fingerprint(cert->signature_key, + options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { + error("%s: sshkey_fingerprint failed", __func__); + goto out; + } + if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) { + error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); + goto out; + } + if ((r = sshkey_to_base64(key, &keytext)) != 0) { + error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); + goto out; + } for (i = 1; i < ac; i++) { tmp = percent_expand(av[i], "u", user_pw->pw_name, "h", user_pw->pw_dir, + "t", sshkey_ssh_name(key), + "T", sshkey_ssh_name(cert->signature_key), + "f", key_fp, + "F", ca_fp, + "k", keytext, + "K", catext, (char *)NULL); if (tmp == NULL) fatal("%s: percent_expand failed", __func__); @@ -712,6 +738,10 @@ match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert) restore_uid(); free(command); free(username); + free(ca_fp); + free(key_fp); + free(catext); + free(keytext); return found_principal; } /* @@ -863,7 +893,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) found_principal = 1; } /* Try querying command if specified */ - if (!found_principal && match_principals_command(pw, key->cert)) + if (!found_principal && match_principals_command(pw, key)) found_principal = 1; /* If principals file or command is specified, then require a match */ use_authorized_principals = principals_file != NULL || -- cgit v1.2.3 From 00df97ff68a49a756d4b977cd02283690f5dfa34 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 14 Sep 2016 20:11:26 +0000 Subject: upstream commit take fingerprint of correct key for AuthorizedPrincipalsCommand Upstream-ID: 553581a549cd6a3e73ce9f57559a325cc2cb1f38 --- auth2-pubkey.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'auth2-pubkey.c') diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 5e1b88900..a08354c7e 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.56 2016/09/14 05:42:25 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.57 2016/09/14 20:11:26 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -681,7 +681,7 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) error("%s: sshkey_fingerprint failed", __func__); goto out; } - if ((key_fp = sshkey_fingerprint(cert->signature_key, + if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { error("%s: sshkey_fingerprint failed", __func__); goto out; -- cgit v1.2.3 From bfa9d969ab6235d4938ce069d4db7e5825c56a19 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 21 Sep 2016 01:34:45 +0000 Subject: upstream commit add a way for principals command to get see key ID and serial too Upstream-ID: 0d30978bdcf7e8eaeee4eea1b030eb2eb1823fcb --- auth2-pubkey.c | 6 +++++- sshd_config.5 | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'auth2-pubkey.c') diff --git a/auth2-pubkey.c b/auth2-pubkey.c index a08354c7e..cc5466613 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.57 2016/09/14 20:11:26 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.58 2016/09/21 01:34:45 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -639,6 +639,7 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) pid_t pid; char *tmp, *username = NULL, *command = NULL, **av = NULL; char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL; + char serial_s[16]; void (*osigchld)(int); if (options.authorized_principals_command == NULL) @@ -694,6 +695,7 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); goto out; } + snprintf(serial_s, sizeof(serial_s), "%llu", cert->serial); for (i = 1; i < ac; i++) { tmp = percent_expand(av[i], "u", user_pw->pw_name, @@ -704,6 +706,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) "F", ca_fp, "k", keytext, "K", catext, + "i", cert->key_id, + "s", serial_s, (char *)NULL); if (tmp == NULL) fatal("%s: percent_expand failed", __func__); diff --git a/sshd_config.5 b/sshd_config.5 index 9e96acf39..dd94b4801 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -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_config.5,v 1.232 2016/09/14 05:42:25 djm Exp $ -.Dd $Mdocdate: September 14 2016 $ +.\" $OpenBSD: sshd_config.5,v 1.233 2016/09/21 01:34:45 djm Exp $ +.Dd $Mdocdate: September 21 2016 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -306,14 +306,16 @@ Arguments to may be provided using the following tokens, which will be expanded at runtime: %% is replaced by a literal '%', -%u is replaced by the username being authenticated, -%h is replaced by the home directory of the user being authenticated, -%t is replaced with type of the certificate being offered, -%T with the type of the CA key, -%f is replaced with certificate fingerprint, %F with the fingerprint of the CA key, -%k is replaced with the full base-64 encoded certificate and +%f is replaced with certificate fingerprint, %K is replaced with the base-64 encoded CA key. +%k is replaced with the full base-64 encoded certificate, +%h is replaced with the home directory of the user being authenticated, +%i is replaced with key ID in the certificate, +%s is replaced with the serial number of the certificate, +%T with the type of the CA key, +%t is replaced with type of the certificate being offered, and +%u is replaced by the username being authenticated, If no arguments are specified then the username of the target user will be supplied. .Pp -- cgit v1.2.3 From f83a0cfe16c7a73627b46a9a94e40087d60f32fb Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 21 Sep 2016 17:44:20 +0000 Subject: upstream commit cast uint64_t for printf Upstream-ID: 76d23e89419ccbd2320f92792a6d878211666ac1 --- auth2-pubkey.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'auth2-pubkey.c') diff --git a/auth2-pubkey.c b/auth2-pubkey.c index cc5466613..375d91cbd 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.58 2016/09/21 01:34:45 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.59 2016/09/21 17:44:20 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -695,7 +695,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); goto out; } - snprintf(serial_s, sizeof(serial_s), "%llu", cert->serial); + snprintf(serial_s, sizeof(serial_s), "%llu", + (unsigned long long)cert->serial); for (i = 1; i < ac; i++) { tmp = percent_expand(av[i], "u", user_pw->pw_name, -- cgit v1.2.3 From fd6dcef2030d23c43f986d26979f84619c10589d Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 30 Nov 2016 02:57:40 +0000 Subject: upstream commit When a forced-command appears in both a certificate and an authorized keys/principals command= restriction, refuse to accept the certificate unless they are identical. The previous (documented) behaviour of having the certificate forced- command override the other could be a bit confused and more error-prone. Pointed out by Jann Horn of Project Zero; ok dtucker@ Upstream-ID: 79d811b6eb6bbe1221bf146dde6928f92d2cd05f --- auth-options.c | 27 +++++++++++++++++++++------ auth-options.h | 4 ++-- auth2-pubkey.c | 18 ++++++++---------- sshd.8 | 18 +++++++++++++----- 4 files changed, 44 insertions(+), 23 deletions(-) (limited to 'auth2-pubkey.c') diff --git a/auth-options.c b/auth-options.c index b399b91e3..57b49f7fd 100644 --- a/auth-options.c +++ b/auth-options.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-options.c,v 1.71 2016/03/07 19:02:43 djm Exp $ */ +/* $OpenBSD: auth-options.c,v 1.72 2016/11/30 02:57:40 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -601,7 +601,7 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw, * options so this must be called after auth_parse_options(). */ int -auth_cert_options(struct sshkey *k, struct passwd *pw) +auth_cert_options(struct sshkey *k, struct passwd *pw, const char **reason) { int cert_no_port_forwarding_flag = 1; int cert_no_agent_forwarding_flag = 1; @@ -611,6 +611,8 @@ auth_cert_options(struct sshkey *k, struct passwd *pw) char *cert_forced_command = NULL; int cert_source_address_done = 0; + *reason = "invalid certificate options"; + /* Separate options and extensions for v01 certs */ if (parse_option_list(k->cert->critical, pw, OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, @@ -632,11 +634,24 @@ auth_cert_options(struct sshkey *k, struct passwd *pw) no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; no_pty_flag |= cert_no_pty_flag; no_user_rc |= cert_no_user_rc; - /* CA-specified forced command supersedes key option */ - if (cert_forced_command != NULL) { - free(forced_command); + /* + * Only permit both CA and key option forced-command if they match. + * Otherwise refuse the certificate. + */ + if (cert_forced_command != NULL && forced_command != NULL) { + if (strcmp(forced_command, cert_forced_command) == 0) { + free(forced_command); + forced_command = cert_forced_command; + } else { + *reason = "certificate and key options forced command " + "do not match"; + free(cert_forced_command); + return -1; + } + } else if (cert_forced_command != NULL) forced_command = cert_forced_command; - } + /* success */ + *reason = NULL; return 0; } diff --git a/auth-options.h b/auth-options.h index 34852e5c0..52cbb42aa 100644 --- a/auth-options.h +++ b/auth-options.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-options.h,v 1.21 2015/01/14 10:30:34 markus Exp $ */ +/* $OpenBSD: auth-options.h,v 1.22 2016/11/30 02:57:40 djm Exp $ */ /* * Author: Tatu Ylonen @@ -35,6 +35,6 @@ extern char *authorized_principals; int auth_parse_options(struct passwd *, char *, char *, u_long); void auth_clear_options(void); -int auth_cert_options(struct sshkey *, struct passwd *); +int auth_cert_options(struct sshkey *, struct passwd *, const char **); #endif diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 375d91cbd..20f3309e1 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.59 2016/09/21 17:44:20 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.60 2016/11/30 02:57:40 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -757,17 +757,17 @@ static int check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) { char line[SSH_MAX_PUBKEY_BYTES]; - const char *reason; int found_key = 0; u_long linenum = 0; Key *found; - char *fp; found_key = 0; found = NULL; while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { - char *cp, *key_options = NULL; + char *cp, *key_options = NULL, *fp = NULL; + const char *reason = NULL; + if (found != NULL) key_free(found); found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); @@ -832,10 +832,8 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) authorized_principals == NULL ? pw->pw_name : NULL, &reason) != 0) goto fail_reason; - if (auth_cert_options(key, pw) != 0) { - free(fp); - continue; - } + if (auth_cert_options(key, pw, &reason) != 0) + goto fail_reason; verbose("Accepted certificate ID \"%s\" (serial %llu) " "signed by %s CA %s via %s", key->cert->key_id, (unsigned long long)key->cert->serial, @@ -913,8 +911,8 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) if (key_cert_check_authority(key, 0, 1, use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) goto fail_reason; - if (auth_cert_options(key, pw) != 0) - goto out; + if (auth_cert_options(key, pw, &reason) != 0) + goto fail_reason; verbose("Accepted certificate ID \"%s\" (serial %llu) signed by " "%s CA %s via %s", key->cert->key_id, diff --git a/sshd.8 b/sshd.8 index 4cf8fee48..41fc5051a 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.286 2016/08/19 03:18:06 djm Exp $ -.Dd $Mdocdate: August 19 2016 $ +.\" $OpenBSD: sshd.8,v 1.287 2016/11/30 02:57:40 djm Exp $ +.Dd $Mdocdate: November 30 2016 $ .Dt SSHD 8 .Os .Sh NAME @@ -481,19 +481,27 @@ If an 8-bit clean channel is required, one must not request a pty or should specify .Cm no-pty . A quote may be included in the command by quoting it with a backslash. +.Pp This option might be useful to restrict certain public keys to perform just a specific operation. An example might be a key that permits remote backups but nothing else. Note that the client may specify TCP and/or X11 -forwarding unless they are explicitly prohibited. +forwarding unless they are explicitly prohibited, e.g. using the +.Cm restrict +key option. +.Pp The command originally supplied by the client is available in the .Ev SSH_ORIGINAL_COMMAND environment variable. Note that this option applies to shell, command or subsystem execution. -Also note that this command may be superseded by either a +Also note that this command may be superseded by a .Xr sshd_config 5 .Cm ForceCommand -directive or a command embedded in a certificate. +directive. +.Pp +If a command is specified and a forced-command is embedded in a certificate +used for authentication, then the certificate will be accepted only if the +two commands are identical. .It Cm environment="NAME=value" Specifies that the string is to be added to the environment when logging in using this key. -- cgit v1.2.3 From 69e0307a3bc73d5d360c19aeb61133c126cf63bf Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Sun, 9 Feb 2014 16:10:02 +0000 Subject: Quieten logs when multiple from= restrictions are used Bug-Debian: http://bugs.debian.org/630606 Forwarded: no Last-Update: 2013-09-14 Patch-Name: auth-log-verbosity.patch --- auth-options.c | 35 ++++++++++++++++++++++++++--------- auth-options.h | 1 + auth2-pubkey.c | 3 +++ 3 files changed, 30 insertions(+), 9 deletions(-) (limited to 'auth2-pubkey.c') diff --git a/auth-options.c b/auth-options.c index 57b49f7fd..7eb87b352 100644 --- a/auth-options.c +++ b/auth-options.c @@ -59,8 +59,19 @@ int forced_tun_device = -1; /* "principals=" option. */ char *authorized_principals = NULL; +/* Throttle log messages. */ +int logged_from_hostip = 0; +int logged_cert_hostip = 0; + extern ServerOptions options; +void +auth_start_parse_options(void) +{ + logged_from_hostip = 0; + logged_cert_hostip = 0; +} + void auth_clear_options(void) { @@ -316,10 +327,13 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) /* FALLTHROUGH */ case 0: free(patterns); - logit("Authentication tried for %.100s with " - "correct key but not from a permitted " - "host (host=%.200s, ip=%.200s).", - pw->pw_name, remote_host, remote_ip); + if (!logged_from_hostip) { + logit("Authentication tried for %.100s with " + "correct key but not from a permitted " + "host (host=%.200s, ip=%.200s).", + pw->pw_name, remote_host, remote_ip); + logged_from_hostip = 1; + } auth_debug_add("Your host '%.200s' is not " "permitted to use this key for login.", remote_host); @@ -543,11 +557,14 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw, break; case 0: /* no match */ - logit("Authentication tried for %.100s " - "with valid certificate but not " - "from a permitted host " - "(ip=%.200s).", pw->pw_name, - remote_ip); + if (!logged_cert_hostip) { + logit("Authentication tried for %.100s " + "with valid certificate but not " + "from a permitted host " + "(ip=%.200s).", pw->pw_name, + remote_ip); + logged_cert_hostip = 1; + } auth_debug_add("Your address '%.200s' " "is not permitted to use this " "certificate for login.", diff --git a/auth-options.h b/auth-options.h index 52cbb42aa..823552761 100644 --- a/auth-options.h +++ b/auth-options.h @@ -33,6 +33,7 @@ extern int forced_tun_device; extern int key_is_cert_authority; extern char *authorized_principals; +void auth_start_parse_options(void); int auth_parse_options(struct passwd *, char *, char *, u_long); void auth_clear_options(void); int auth_cert_options(struct sshkey *, struct passwd *, const char **); diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 20f3309e1..add77136e 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -566,6 +566,7 @@ process_principals(FILE *f, char *file, struct passwd *pw, u_long linenum = 0; u_int i; + auth_start_parse_options(); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { /* Skip leading whitespace. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) @@ -764,6 +765,7 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) found_key = 0; found = NULL; + auth_start_parse_options(); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp, *key_options = NULL, *fp = NULL; const char *reason = NULL; @@ -911,6 +913,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) if (key_cert_check_authority(key, 0, 1, use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) goto fail_reason; + auth_start_parse_options(); if (auth_cert_options(key, pw, &reason) != 0) goto fail_reason; -- cgit v1.2.3