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
This commit is contained in:
parent
7fc4766ac7
commit
fd6dcef203
|
@ -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 <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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().
|
* options so this must be called after auth_parse_options().
|
||||||
*/
|
*/
|
||||||
int
|
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_port_forwarding_flag = 1;
|
||||||
int cert_no_agent_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;
|
char *cert_forced_command = NULL;
|
||||||
int cert_source_address_done = 0;
|
int cert_source_address_done = 0;
|
||||||
|
|
||||||
|
*reason = "invalid certificate options";
|
||||||
|
|
||||||
/* Separate options and extensions for v01 certs */
|
/* Separate options and extensions for v01 certs */
|
||||||
if (parse_option_list(k->cert->critical, pw,
|
if (parse_option_list(k->cert->critical, pw,
|
||||||
OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL,
|
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_x11_forwarding_flag |= cert_no_x11_forwarding_flag;
|
||||||
no_pty_flag |= cert_no_pty_flag;
|
no_pty_flag |= cert_no_pty_flag;
|
||||||
no_user_rc |= cert_no_user_rc;
|
no_user_rc |= cert_no_user_rc;
|
||||||
/* CA-specified forced command supersedes key option */
|
/*
|
||||||
if (cert_forced_command != NULL) {
|
* 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);
|
free(forced_command);
|
||||||
forced_command = cert_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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
|
@ -35,6 +35,6 @@ extern char *authorized_principals;
|
||||||
|
|
||||||
int auth_parse_options(struct passwd *, char *, char *, u_long);
|
int auth_parse_options(struct passwd *, char *, char *, u_long);
|
||||||
void auth_clear_options(void);
|
void auth_clear_options(void);
|
||||||
int auth_cert_options(struct sshkey *, struct passwd *);
|
int auth_cert_options(struct sshkey *, struct passwd *, const char **);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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.
|
* 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)
|
check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
|
||||||
{
|
{
|
||||||
char line[SSH_MAX_PUBKEY_BYTES];
|
char line[SSH_MAX_PUBKEY_BYTES];
|
||||||
const char *reason;
|
|
||||||
int found_key = 0;
|
int found_key = 0;
|
||||||
u_long linenum = 0;
|
u_long linenum = 0;
|
||||||
Key *found;
|
Key *found;
|
||||||
char *fp;
|
|
||||||
|
|
||||||
found_key = 0;
|
found_key = 0;
|
||||||
|
|
||||||
found = NULL;
|
found = NULL;
|
||||||
while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
|
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)
|
if (found != NULL)
|
||||||
key_free(found);
|
key_free(found);
|
||||||
found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
|
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,
|
authorized_principals == NULL ? pw->pw_name : NULL,
|
||||||
&reason) != 0)
|
&reason) != 0)
|
||||||
goto fail_reason;
|
goto fail_reason;
|
||||||
if (auth_cert_options(key, pw) != 0) {
|
if (auth_cert_options(key, pw, &reason) != 0)
|
||||||
free(fp);
|
goto fail_reason;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
verbose("Accepted certificate ID \"%s\" (serial %llu) "
|
verbose("Accepted certificate ID \"%s\" (serial %llu) "
|
||||||
"signed by %s CA %s via %s", key->cert->key_id,
|
"signed by %s CA %s via %s", key->cert->key_id,
|
||||||
(unsigned long long)key->cert->serial,
|
(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,
|
if (key_cert_check_authority(key, 0, 1,
|
||||||
use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
|
use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
|
||||||
goto fail_reason;
|
goto fail_reason;
|
||||||
if (auth_cert_options(key, pw) != 0)
|
if (auth_cert_options(key, pw, &reason) != 0)
|
||||||
goto out;
|
goto fail_reason;
|
||||||
|
|
||||||
verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
|
verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
|
||||||
"%s CA %s via %s", key->cert->key_id,
|
"%s CA %s via %s", key->cert->key_id,
|
||||||
|
|
18
sshd.8
18
sshd.8
|
@ -33,8 +33,8 @@
|
||||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" 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 $
|
.\" $OpenBSD: sshd.8,v 1.287 2016/11/30 02:57:40 djm Exp $
|
||||||
.Dd $Mdocdate: August 19 2016 $
|
.Dd $Mdocdate: November 30 2016 $
|
||||||
.Dt SSHD 8
|
.Dt SSHD 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -481,19 +481,27 @@ If an 8-bit clean channel is required,
|
||||||
one must not request a pty or should specify
|
one must not request a pty or should specify
|
||||||
.Cm no-pty .
|
.Cm no-pty .
|
||||||
A quote may be included in the command by quoting it with a backslash.
|
A quote may be included in the command by quoting it with a backslash.
|
||||||
|
.Pp
|
||||||
This option might be useful
|
This option might be useful
|
||||||
to restrict certain public keys to perform just a specific operation.
|
to restrict certain public keys to perform just a specific operation.
|
||||||
An example might be a key that permits remote backups but nothing else.
|
An example might be a key that permits remote backups but nothing else.
|
||||||
Note that the client may specify TCP and/or X11
|
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
|
The command originally supplied by the client is available in the
|
||||||
.Ev SSH_ORIGINAL_COMMAND
|
.Ev SSH_ORIGINAL_COMMAND
|
||||||
environment variable.
|
environment variable.
|
||||||
Note that this option applies to shell, command or subsystem execution.
|
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
|
.Xr sshd_config 5
|
||||||
.Cm ForceCommand
|
.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"
|
.It Cm environment="NAME=value"
|
||||||
Specifies that the string is to be added to the environment when
|
Specifies that the string is to be added to the environment when
|
||||||
logging in using this key.
|
logging in using this key.
|
||||||
|
|
Loading…
Reference in New Issue