diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | PROTOCOL.certkeys | 35 | ||||
-rw-r--r-- | auth-options.c | 282 | ||||
-rw-r--r-- | ssh-keygen.c | 94 |
4 files changed, 267 insertions, 152 deletions
@@ -33,6 +33,14 @@ [auth2-pubkey.c] fix logspam when key options (from="..." especially) deny non-matching keys; reported by henning@ also bz#1765; ok markus@ dtucker@ + - djm@cvs.openbsd.org 2010/05/20 23:46:02 + [PROTOCOL.certkeys auth-options.c ssh-keygen.c] + Move the permit-* options to the non-critical "extensions" field for v01 + certificates. The logic is that if another implementation fails to + implement them then the connection just loses features rather than fails + outright. + + ok markus@ 20100511 - (dtucker) [Makefile.in] Bug #1770: Link libopenbsd-compat twice to solve diff --git a/PROTOCOL.certkeys b/PROTOCOL.certkeys index 0fa5748f3..81b02a078 100644 --- a/PROTOCOL.certkeys +++ b/PROTOCOL.certkeys @@ -131,7 +131,7 @@ must refuse to authorise a key that has an unrecognised option. extensions is a set of zero or more optional extensions. These extensions are not critical, and an implementation that encounters one that it does -not recognise may safely ignore it. No extensions are defined at present. +not recognise may safely ignore it. The reserved field is currently unused and is ignored in this version of the protocol. @@ -172,6 +172,28 @@ force-command string Specifies a command that is executed ssh command-line) whenever this key is used for authentication. +source-address string Comma-separated list of source addresses + from which this certificate is accepted + for authentication. Addresses are + specified in CIDR format (nn.nn.nn.nn/nn + or hhhh::hhhh/nn). + If this option is not present then + certificates may be presented from any + source address. + +Extensions +---------- + +The extensions section of the certificate specifies zero or more +non-critical certificate extensions. The encoding of extensions in this +field is identical to that of the critical options. If an implementation +does not recognise an extension, then it should ignore it. + +The supported extensions and the contents and structure of their data +fields are: + +Name Format Description +----------------------------------------------------------------------------- permit-X11-forwarding empty Flag indicating that X11 forwarding should be permitted. X11 forwarding will be refused if this option is absent. @@ -196,13 +218,4 @@ permit-user-rc empty Flag indicating that execution of of this script will not be permitted if this option is not present. -source-address string Comma-separated list of source addresses - from which this certificate is accepted - for authentication. Addresses are - specified in CIDR format (nn.nn.nn.nn/nn - or hhhh::hhhh/nn). - If this option is not present then - certificates may be presented from any - source address. - -$OpenBSD: PROTOCOL.certkeys,v 1.5 2010/05/01 02:50:50 djm Exp $ +$OpenBSD: PROTOCOL.certkeys,v 1.6 2010/05/20 23:46:02 djm Exp $ diff --git a/auth-options.c b/auth-options.c index 57a67ec79..a7040247f 100644 --- a/auth-options.c +++ b/auth-options.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-options.c,v 1.51 2010/05/07 11:30:29 djm Exp $ */ +/* $OpenBSD: auth-options.c,v 1.52 2010/05/20 23:46:02 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -417,32 +417,31 @@ bad_option: return 0; } -/* - * Set options from critical certificate options. These supersede user key - * options so this must be called after auth_parse_options(). - */ -int -auth_cert_options(Key *k, struct passwd *pw) +#define OPTIONS_CRITICAL 1 +#define OPTIONS_EXTENSIONS 2 +static int +parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw, + u_int which, int crit, + int *cert_no_port_forwarding_flag, + int *cert_no_agent_forwarding_flag, + int *cert_no_x11_forwarding_flag, + int *cert_no_pty_flag, + int *cert_no_user_rc, + char **cert_forced_command, + int *cert_source_address_done) { + char *command, *allowed; + const char *remote_ip; u_char *name = NULL, *data_blob = NULL; u_int nlen, dlen, clen; Buffer c, data; - int ret = -1; - - int cert_no_port_forwarding_flag = 1; - int cert_no_agent_forwarding_flag = 1; - int cert_no_x11_forwarding_flag = 1; - int cert_no_pty_flag = 1; - int cert_no_user_rc = 1; - char *cert_forced_command = NULL; - int cert_source_address_done = 0; + int ret = -1, found; buffer_init(&data); /* Make copy to avoid altering original */ buffer_init(&c); - buffer_append(&c, - buffer_ptr(&k->cert->critical), buffer_len(&k->cert->critical)); + buffer_append(&c, optblob, optblob_len); while (buffer_len(&c) > 0) { if ((name = buffer_get_string_ret(&c, &nlen)) == NULL || @@ -451,90 +450,114 @@ auth_cert_options(Key *k, struct passwd *pw) goto out; } buffer_append(&data, data_blob, dlen); - debug3("found certificate constraint \"%.100s\" len %u", + debug3("found certificate option \"%.100s\" len %u", name, dlen); if (strlen(name) != nlen) { error("Certificate constraint name contains \\0"); goto out; } - if (strcmp(name, "permit-X11-forwarding") == 0) - cert_no_x11_forwarding_flag = 0; - else if (strcmp(name, "permit-agent-forwarding") == 0) - cert_no_agent_forwarding_flag = 0; - else if (strcmp(name, "permit-port-forwarding") == 0) - cert_no_port_forwarding_flag = 0; - else if (strcmp(name, "permit-pty") == 0) - cert_no_pty_flag = 0; - else if (strcmp(name, "permit-user-rc") == 0) - cert_no_user_rc = 0; - else if (strcmp(name, "force-command") == 0) { - char *command = buffer_get_string_ret(&data, &clen); - - if (command == NULL) { - error("Certificate constraint \"%s\" corrupt", - name); - goto out; - } - if (strlen(command) != clen) { - error("force-command constraint contains \\0"); - goto out; - } - if (cert_forced_command != NULL) { - error("Certificate has multiple " - "force-command options"); - xfree(command); - goto out; - } - cert_forced_command = command; - } else if (strcmp(name, "source-address") == 0) { - char *allowed = buffer_get_string_ret(&data, &clen); - const char *remote_ip = get_remote_ipaddr(); - - if (allowed == NULL) { - error("Certificate constraint \"%s\" corrupt", - name); - goto out; - } - if (strlen(allowed) != clen) { - error("source-address constraint contains \\0"); - goto out; + found = 0; + if ((which & OPTIONS_EXTENSIONS) != 0) { + if (strcmp(name, "permit-X11-forwarding") == 0) { + *cert_no_x11_forwarding_flag = 0; + found = 1; + } else if (strcmp(name, + "permit-agent-forwarding") == 0) { + *cert_no_agent_forwarding_flag = 0; + found = 1; + } else if (strcmp(name, + "permit-port-forwarding") == 0) { + *cert_no_port_forwarding_flag = 0; + found = 1; + } else if (strcmp(name, "permit-pty") == 0) { + *cert_no_pty_flag = 0; + found = 1; + } else if (strcmp(name, "permit-user-rc") == 0) { + *cert_no_user_rc = 0; + found = 1; } - if (cert_source_address_done++) { - error("Certificate has multiple " - "source-address options"); - xfree(allowed); - goto out; + } + if (!found && (which & OPTIONS_CRITICAL) != 0) { + if (strcmp(name, "force-command") == 0) { + if ((command = buffer_get_string_ret(&data, + &clen)) == NULL) { + error("Certificate constraint \"%s\" " + "corrupt", name); + goto out; + } + if (strlen(command) != clen) { + error("force-command constraint " + "contains \\0"); + goto out; + } + if (*cert_forced_command != NULL) { + error("Certificate has multiple " + "force-command options"); + xfree(command); + goto out; + } + *cert_forced_command = command; + found = 1; } - switch (addr_match_cidr_list(remote_ip, allowed)) { - case 1: - /* accepted */ - xfree(allowed); - 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); - auth_debug_add("Your address '%.200s' is not " - "permitted to use this certificate for " - "login.", remote_ip); - xfree(allowed); - goto out; - case -1: - error("Certificate source-address contents " - "invalid"); - xfree(allowed); - goto out; + if (strcmp(name, "source-address") == 0) { + if ((allowed = buffer_get_string_ret(&data, + &clen)) == NULL) { + error("Certificate constraint " + "\"%s\" corrupt", name); + goto out; + } + if (strlen(allowed) != clen) { + error("source-address constraint " + "contains \\0"); + goto out; + } + if ((*cert_source_address_done)++) { + error("Certificate has multiple " + "source-address options"); + xfree(allowed); + goto out; + } + remote_ip = get_remote_ipaddr(); + switch (addr_match_cidr_list(remote_ip, + allowed)) { + case 1: + /* accepted */ + xfree(allowed); + 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); + auth_debug_add("Your address '%.200s' " + "is not permitted to use this " + "certificate for login.", + remote_ip); + xfree(allowed); + goto out; + case -1: + error("Certificate source-address " + "contents invalid"); + xfree(allowed); + goto out; + } + found = 1; } - } else { - error("Certificate constraint \"%s\" is not supported", - name); - goto out; } - if (buffer_len(&data) != 0) { - error("Certificate constraint \"%s\" corrupt " + if (!found) { + if (crit) { + error("Certificate critical option \"%s\" " + "is not supported", name); + goto out; + } else { + logit("Certificate extension \"%s\" " + "is not supported", name); + } + } else if (buffer_len(&data) != 0) { + error("Certificate option \"%s\" corrupt " "(extra data)", name); goto out; } @@ -543,10 +566,73 @@ auth_cert_options(Key *k, struct passwd *pw) xfree(data_blob); name = data_blob = NULL; } - /* successfully parsed all options */ ret = 0; + out: + if (ret != 0 && + cert_forced_command != NULL && + *cert_forced_command != NULL) { + xfree(*cert_forced_command); + *cert_forced_command = NULL; + } + if (name != NULL) + xfree(name); + if (data_blob != NULL) + xfree(data_blob); + buffer_free(&data); + buffer_free(&c); + return ret; +} + +/* + * Set options from critical certificate options. These supersede user key + * options so this must be called after auth_parse_options(). + */ +int +auth_cert_options(Key *k, struct passwd *pw) +{ + int cert_no_port_forwarding_flag = 1; + int cert_no_agent_forwarding_flag = 1; + int cert_no_x11_forwarding_flag = 1; + int cert_no_pty_flag = 1; + int cert_no_user_rc = 1; + char *cert_forced_command = NULL; + int cert_source_address_done = 0; + + if (key_cert_is_legacy(k)) { + /* All options are in the one field for v00 certs */ + if (parse_option_list(buffer_ptr(&k->cert->critical), + buffer_len(&k->cert->critical), pw, + OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1, + &cert_no_port_forwarding_flag, + &cert_no_agent_forwarding_flag, + &cert_no_x11_forwarding_flag, + &cert_no_pty_flag, + &cert_no_user_rc, + &cert_forced_command, + &cert_source_address_done) == -1) + return -1; + } else { + /* Separate options and extensions for v01 certs */ + if (parse_option_list(buffer_ptr(&k->cert->critical), + buffer_len(&k->cert->critical), pw, + OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, + &cert_forced_command, + &cert_source_address_done) == -1) + return -1; + if (parse_option_list(buffer_ptr(&k->cert->extensions), + buffer_len(&k->cert->extensions), pw, + OPTIONS_EXTENSIONS, 1, + &cert_no_port_forwarding_flag, + &cert_no_agent_forwarding_flag, + &cert_no_x11_forwarding_flag, + &cert_no_pty_flag, + &cert_no_user_rc, + NULL, NULL) == -1) + return -1; + } + no_port_forwarding_flag |= cert_no_port_forwarding_flag; no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; @@ -558,14 +644,6 @@ auth_cert_options(Key *k, struct passwd *pw) xfree(forced_command); forced_command = cert_forced_command; } - - out: - if (name != NULL) - xfree(name); - if (data_blob != NULL) - xfree(data_blob); - buffer_free(&data); - buffer_free(&c); - return ret; + return 0; } diff --git a/ssh-keygen.c b/ssh-keygen.c index 1eb25bd94..14eee6f87 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.189 2010/04/23 22:48:31 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.190 2010/05/20 23:46:02 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -122,17 +122,16 @@ u_int64_t cert_valid_from = 0; u_int64_t cert_valid_to = ~0ULL; /* Certificate options */ -#define CRITOPT_X_FWD (1) -#define CRITOPT_AGENT_FWD (1<<1) -#define CRITOPT_PORT_FWD (1<<2) -#define CRITOPT_PTY (1<<3) -#define CRITOPT_USER_RC (1<<4) -#define CRITOPT_DEFAULT (CRITOPT_X_FWD|CRITOPT_AGENT_FWD| \ - CRITOPT_PORT_FWD|CRITOPT_PTY| \ - CRITOPT_USER_RC) -u_int32_t critical_flags = CRITOPT_DEFAULT; -char *critical_command = NULL; -char *critical_src_addr = NULL; +#define CERTOPT_X_FWD (1) +#define CERTOPT_AGENT_FWD (1<<1) +#define CERTOPT_PORT_FWD (1<<2) +#define CERTOPT_PTY (1<<3) +#define CERTOPT_USER_RC (1<<4) +#define CERTOPT_DEFAULT (CERTOPT_X_FWD|CERTOPT_AGENT_FWD| \ + CERTOPT_PORT_FWD|CERTOPT_PTY|CERTOPT_USER_RC) +u_int32_t certflags_flags = CERTOPT_DEFAULT; +char *certflags_command = NULL; +char *certflags_src_addr = NULL; /* Dump public key file in format used by real and the original SSH 2 */ int convert_to_ssh2 = 0; @@ -1133,24 +1132,33 @@ add_string_option(Buffer *c, const char *name, const char *value) buffer_free(&b); } +#define OPTIONS_CRITICAL 1 +#define OPTIONS_EXTENSIONS 2 static void -prepare_options_buf(Buffer *c) +prepare_options_buf(Buffer *c, int which) { buffer_clear(c); - if ((critical_flags & CRITOPT_X_FWD) != 0) + if ((which & OPTIONS_EXTENSIONS) != 0 && + (certflags_flags & CERTOPT_X_FWD) != 0) add_flag_option(c, "permit-X11-forwarding"); - if ((critical_flags & CRITOPT_AGENT_FWD) != 0) + if ((which & OPTIONS_EXTENSIONS) != 0 && + (certflags_flags & CERTOPT_AGENT_FWD) != 0) add_flag_option(c, "permit-agent-forwarding"); - if ((critical_flags & CRITOPT_PORT_FWD) != 0) + if ((which & OPTIONS_EXTENSIONS) != 0 && + (certflags_flags & CERTOPT_PORT_FWD) != 0) add_flag_option(c, "permit-port-forwarding"); - if ((critical_flags & CRITOPT_PTY) != 0) + if ((which & OPTIONS_EXTENSIONS) != 0 && + (certflags_flags & CERTOPT_PTY) != 0) add_flag_option(c, "permit-pty"); - if ((critical_flags & CRITOPT_USER_RC) != 0) + if ((which & OPTIONS_EXTENSIONS) != 0 && + (certflags_flags & CERTOPT_USER_RC) != 0) add_flag_option(c, "permit-user-rc"); - if (critical_command != NULL) - add_string_option(c, "force-command", critical_command); - if (critical_src_addr != NULL) - add_string_option(c, "source-address", critical_src_addr); + if ((which & OPTIONS_CRITICAL) != 0 && + certflags_command != NULL) + add_string_option(c, "force-command", certflags_command); + if ((which & OPTIONS_CRITICAL) != 0 && + certflags_src_addr != NULL) + add_string_option(c, "source-address", certflags_src_addr); } static void @@ -1218,7 +1226,15 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) public->cert->principals = plist; public->cert->valid_after = cert_valid_from; public->cert->valid_before = cert_valid_to; - prepare_options_buf(&public->cert->critical); + if (v00) { + prepare_options_buf(&public->cert->critical, + OPTIONS_CRITICAL|OPTIONS_EXTENSIONS); + } else { + prepare_options_buf(&public->cert->critical, + OPTIONS_CRITICAL); + prepare_options_buf(&public->cert->extensions, + OPTIONS_EXTENSIONS); + } public->cert->signature_key = key_from_private(ca); if (key_certify(public, ca) != 0) @@ -1354,43 +1370,43 @@ add_cert_option(char *opt) char *val; if (strcmp(opt, "clear") == 0) - critical_flags = 0; + certflags_flags = 0; else if (strcasecmp(opt, "no-x11-forwarding") == 0) - critical_flags &= ~CRITOPT_X_FWD; + certflags_flags &= ~CERTOPT_X_FWD; else if (strcasecmp(opt, "permit-x11-forwarding") == 0) - critical_flags |= CRITOPT_X_FWD; + certflags_flags |= CERTOPT_X_FWD; else if (strcasecmp(opt, "no-agent-forwarding") == 0) - critical_flags &= ~CRITOPT_AGENT_FWD; + certflags_flags &= ~CERTOPT_AGENT_FWD; else if (strcasecmp(opt, "permit-agent-forwarding") == 0) - critical_flags |= CRITOPT_AGENT_FWD; + certflags_flags |= CERTOPT_AGENT_FWD; else if (strcasecmp(opt, "no-port-forwarding") == 0) - critical_flags &= ~CRITOPT_PORT_FWD; + certflags_flags &= ~CERTOPT_PORT_FWD; else if (strcasecmp(opt, "permit-port-forwarding") == 0) - critical_flags |= CRITOPT_PORT_FWD; + certflags_flags |= CERTOPT_PORT_FWD; else if (strcasecmp(opt, "no-pty") == 0) - critical_flags &= ~CRITOPT_PTY; + certflags_flags &= ~CERTOPT_PTY; else if (strcasecmp(opt, "permit-pty") == 0) - critical_flags |= CRITOPT_PTY; + certflags_flags |= CERTOPT_PTY; else if (strcasecmp(opt, "no-user-rc") == 0) - critical_flags &= ~CRITOPT_USER_RC; + certflags_flags &= ~CERTOPT_USER_RC; else if (strcasecmp(opt, "permit-user-rc") == 0) - critical_flags |= CRITOPT_USER_RC; + certflags_flags |= CERTOPT_USER_RC; else if (strncasecmp(opt, "force-command=", 14) == 0) { val = opt + 14; if (*val == '\0') fatal("Empty force-command option"); - if (critical_command != NULL) + if (certflags_command != NULL) fatal("force-command already specified"); - critical_command = xstrdup(val); + certflags_command = xstrdup(val); } else if (strncasecmp(opt, "source-address=", 15) == 0) { val = opt + 15; if (*val == '\0') fatal("Empty source-address option"); - if (critical_src_addr != NULL) + if (certflags_src_addr != NULL) fatal("source-address already specified"); if (addr_match_cidr_list(NULL, val) != 0) fatal("Invalid source-address list"); - critical_src_addr = xstrdup(val); + certflags_src_addr = xstrdup(val); } else fatal("Unsupported certificate option \"%s\"", opt); } @@ -1667,7 +1683,7 @@ main(int argc, char **argv) break; case 'h': cert_key_type = SSH2_CERT_TYPE_HOST; - critical_flags = 0; + certflags_flags = 0; break; case 'i': case 'X': |