summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2016-11-30 02:57:40 +0000
committerDamien Miller <djm@mindrot.org>2016-11-30 19:44:01 +1100
commitfd6dcef2030d23c43f986d26979f84619c10589d (patch)
treea9b9d64866a656d5e187f7d63b61e1c1bede5e8f
parent7fc4766ac78abae81ee75b22b7550720bfa28a33 (diff)
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
-rw-r--r--auth-options.c27
-rw-r--r--auth-options.h4
-rw-r--r--auth2-pubkey.c18
-rw-r--r--sshd.818
4 files changed, 44 insertions, 23 deletions
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 @@
1/* $OpenBSD: auth-options.c,v 1.71 2016/03/07 19:02:43 djm Exp $ */ 1/* $OpenBSD: auth-options.c,v 1.72 2016/11/30 02:57:40 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -601,7 +601,7 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw,
601 * options so this must be called after auth_parse_options(). 601 * options so this must be called after auth_parse_options().
602 */ 602 */
603int 603int
604auth_cert_options(struct sshkey *k, struct passwd *pw) 604auth_cert_options(struct sshkey *k, struct passwd *pw, const char **reason)
605{ 605{
606 int cert_no_port_forwarding_flag = 1; 606 int cert_no_port_forwarding_flag = 1;
607 int cert_no_agent_forwarding_flag = 1; 607 int cert_no_agent_forwarding_flag = 1;
@@ -611,6 +611,8 @@ auth_cert_options(struct sshkey *k, struct passwd *pw)
611 char *cert_forced_command = NULL; 611 char *cert_forced_command = NULL;
612 int cert_source_address_done = 0; 612 int cert_source_address_done = 0;
613 613
614 *reason = "invalid certificate options";
615
614 /* Separate options and extensions for v01 certs */ 616 /* Separate options and extensions for v01 certs */
615 if (parse_option_list(k->cert->critical, pw, 617 if (parse_option_list(k->cert->critical, pw,
616 OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, 618 OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL,
@@ -632,11 +634,24 @@ auth_cert_options(struct sshkey *k, struct passwd *pw)
632 no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; 634 no_x11_forwarding_flag |= cert_no_x11_forwarding_flag;
633 no_pty_flag |= cert_no_pty_flag; 635 no_pty_flag |= cert_no_pty_flag;
634 no_user_rc |= cert_no_user_rc; 636 no_user_rc |= cert_no_user_rc;
635 /* CA-specified forced command supersedes key option */ 637 /*
636 if (cert_forced_command != NULL) { 638 * Only permit both CA and key option forced-command if they match.
637 free(forced_command); 639 * Otherwise refuse the certificate.
640 */
641 if (cert_forced_command != NULL && forced_command != NULL) {
642 if (strcmp(forced_command, cert_forced_command) == 0) {
643 free(forced_command);
644 forced_command = cert_forced_command;
645 } else {
646 *reason = "certificate and key options forced command "
647 "do not match";
648 free(cert_forced_command);
649 return -1;
650 }
651 } else if (cert_forced_command != NULL)
638 forced_command = cert_forced_command; 652 forced_command = cert_forced_command;
639 } 653 /* success */
654 *reason = NULL;
640 return 0; 655 return 0;
641} 656}
642 657
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 @@
1/* $OpenBSD: auth-options.h,v 1.21 2015/01/14 10:30:34 markus Exp $ */ 1/* $OpenBSD: auth-options.h,v 1.22 2016/11/30 02:57:40 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -35,6 +35,6 @@ extern char *authorized_principals;
35 35
36int auth_parse_options(struct passwd *, char *, char *, u_long); 36int auth_parse_options(struct passwd *, char *, char *, u_long);
37void auth_clear_options(void); 37void auth_clear_options(void);
38int auth_cert_options(struct sshkey *, struct passwd *); 38int auth_cert_options(struct sshkey *, struct passwd *, const char **);
39 39
40#endif 40#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 @@
1/* $OpenBSD: auth2-pubkey.c,v 1.59 2016/09/21 17:44:20 djm Exp $ */ 1/* $OpenBSD: auth2-pubkey.c,v 1.60 2016/11/30 02:57:40 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -757,17 +757,17 @@ static int
757check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) 757check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
758{ 758{
759 char line[SSH_MAX_PUBKEY_BYTES]; 759 char line[SSH_MAX_PUBKEY_BYTES];
760 const char *reason;
761 int found_key = 0; 760 int found_key = 0;
762 u_long linenum = 0; 761 u_long linenum = 0;
763 Key *found; 762 Key *found;
764 char *fp;
765 763
766 found_key = 0; 764 found_key = 0;
767 765
768 found = NULL; 766 found = NULL;
769 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 767 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
770 char *cp, *key_options = NULL; 768 char *cp, *key_options = NULL, *fp = NULL;
769 const char *reason = NULL;
770
771 if (found != NULL) 771 if (found != NULL)
772 key_free(found); 772 key_free(found);
773 found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); 773 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)
832 authorized_principals == NULL ? pw->pw_name : NULL, 832 authorized_principals == NULL ? pw->pw_name : NULL,
833 &reason) != 0) 833 &reason) != 0)
834 goto fail_reason; 834 goto fail_reason;
835 if (auth_cert_options(key, pw) != 0) { 835 if (auth_cert_options(key, pw, &reason) != 0)
836 free(fp); 836 goto fail_reason;
837 continue;
838 }
839 verbose("Accepted certificate ID \"%s\" (serial %llu) " 837 verbose("Accepted certificate ID \"%s\" (serial %llu) "
840 "signed by %s CA %s via %s", key->cert->key_id, 838 "signed by %s CA %s via %s", key->cert->key_id,
841 (unsigned long long)key->cert->serial, 839 (unsigned long long)key->cert->serial,
@@ -913,8 +911,8 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
913 if (key_cert_check_authority(key, 0, 1, 911 if (key_cert_check_authority(key, 0, 1,
914 use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) 912 use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
915 goto fail_reason; 913 goto fail_reason;
916 if (auth_cert_options(key, pw) != 0) 914 if (auth_cert_options(key, pw, &reason) != 0)
917 goto out; 915 goto fail_reason;
918 916
919 verbose("Accepted certificate ID \"%s\" (serial %llu) signed by " 917 verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
920 "%s CA %s via %s", key->cert->key_id, 918 "%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 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: sshd.8,v 1.286 2016/08/19 03:18:06 djm Exp $ 36.\" $OpenBSD: sshd.8,v 1.287 2016/11/30 02:57:40 djm Exp $
37.Dd $Mdocdate: August 19 2016 $ 37.Dd $Mdocdate: November 30 2016 $
38.Dt SSHD 8 38.Dt SSHD 8
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -481,19 +481,27 @@ If an 8-bit clean channel is required,
481one must not request a pty or should specify 481one must not request a pty or should specify
482.Cm no-pty . 482.Cm no-pty .
483A quote may be included in the command by quoting it with a backslash. 483A quote may be included in the command by quoting it with a backslash.
484.Pp
484This option might be useful 485This option might be useful
485to restrict certain public keys to perform just a specific operation. 486to restrict certain public keys to perform just a specific operation.
486An example might be a key that permits remote backups but nothing else. 487An example might be a key that permits remote backups but nothing else.
487Note that the client may specify TCP and/or X11 488Note that the client may specify TCP and/or X11
488forwarding unless they are explicitly prohibited. 489forwarding unless they are explicitly prohibited, e.g. using the
490.Cm restrict
491key option.
492.Pp
489The command originally supplied by the client is available in the 493The command originally supplied by the client is available in the
490.Ev SSH_ORIGINAL_COMMAND 494.Ev SSH_ORIGINAL_COMMAND
491environment variable. 495environment variable.
492Note that this option applies to shell, command or subsystem execution. 496Note that this option applies to shell, command or subsystem execution.
493Also note that this command may be superseded by either a 497Also note that this command may be superseded by a
494.Xr sshd_config 5 498.Xr sshd_config 5
495.Cm ForceCommand 499.Cm ForceCommand
496directive or a command embedded in a certificate. 500directive.
501.Pp
502If a command is specified and a forced-command is embedded in a certificate
503used for authentication, then the certificate will be accepted only if the
504two commands are identical.
497.It Cm environment="NAME=value" 505.It Cm environment="NAME=value"
498Specifies that the string is to be added to the environment when 506Specifies that the string is to be added to the environment when
499logging in using this key. 507logging in using this key.