From d77b81f856e078714ec6b0f86f61c20249b7ead4 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Thu, 17 Oct 2013 11:39:00 +1100 Subject: - jmc@cvs.openbsd.org 2013/10/15 14:10:25 [ssh.1 ssh_config.5] tweak previous; --- ssh.1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'ssh.1') diff --git a/ssh.1 b/ssh.1 index 227654016..8091aecfd 100644 --- a/ssh.1 +++ b/ssh.1 @@ -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: ssh.1,v 1.336 2013/08/20 06:56:07 jmc Exp $ -.Dd $Mdocdate: August 20 2013 $ +.\" $OpenBSD: ssh.1,v 1.337 2013/10/15 14:10:25 jmc Exp $ +.Dd $Mdocdate: October 15 2013 $ .Dt SSH 1 .Os .Sh NAME @@ -456,6 +456,7 @@ For full details of the options listed below, and their possible values, see .It LocalForward .It LogLevel .It MACs +.It Match .It NoHostAuthenticationForLocalhost .It NumberOfPasswordPrompts .It PasswordAuthentication -- cgit v1.2.3 From 0faf747e2f77f0f7083bcd59cbed30c4b5448444 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Thu, 17 Oct 2013 11:47:23 +1100 Subject: - djm@cvs.openbsd.org 2013/10/16 02:31:47 [readconf.c readconf.h roaming_client.c ssh.1 ssh.c ssh_config.5] [sshconnect.c sshconnect.h] Implement client-side hostname canonicalisation to allow an explicit search path of domain suffixes to use to convert unqualified host names to fully-qualified ones for host key matching. This is particularly useful for host certificates, which would otherwise need to list unqualified names alongside fully-qualified ones (and this causes a number of problems). "looks fine" markus@ --- ChangeLog | 10 +++ readconf.c | 113 +++++++++++++++++++++++++++++++++- readconf.h | 22 ++++++- roaming_client.c | 8 +-- ssh.1 | 9 ++- ssh.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++----- ssh_config.5 | 75 ++++++++++++++++++++++- sshconnect.c | 74 +++++++++------------- sshconnect.h | 8 +-- 9 files changed, 426 insertions(+), 76 deletions(-) (limited to 'ssh.1') diff --git a/ChangeLog b/ChangeLog index 255a3e021..c765bceab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,16 @@ - jmc@cvs.openbsd.org 2013/10/15 14:10:25 [ssh.1 ssh_config.5] tweak previous; + - djm@cvs.openbsd.org 2013/10/16 02:31:47 + [readconf.c readconf.h roaming_client.c ssh.1 ssh.c ssh_config.5] + [sshconnect.c sshconnect.h] + Implement client-side hostname canonicalisation to allow an explicit + search path of domain suffixes to use to convert unqualified host names + to fully-qualified ones for host key matching. + This is particularly useful for host certificates, which would otherwise + need to list unqualified names alongside fully-qualified ones (and this + causes a number of problems). + "looks fine" markus@ 20131015 - (djm) OpenBSD CVS Sync diff --git a/readconf.c b/readconf.c index 9340effd0..de8eb7cd3 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.207 2013/10/14 23:28:23 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.208 2013/10/16 02:31:45 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -144,6 +144,8 @@ typedef enum { oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, + oCanonicalDomains, oCanonicaliseHostname, oCanonicaliseMaxDots, + oCanonicaliseFallbackLocal, oCanonicalisePermittedCNAMEs, oIgnoredUnknownOption, oDeprecated, oUnsupported } OpCodes; @@ -257,6 +259,11 @@ static struct { { "ipqos", oIPQoS }, { "requesttty", oRequestTTY }, { "proxyusefdpass", oProxyUseFdpass }, + { "canonicaldomains", oCanonicalDomains }, + { "canonicalisefallbacklocal", oCanonicaliseFallbackLocal }, + { "canonicalisehostname", oCanonicaliseHostname }, + { "canonicalisemaxdots", oCanonicaliseMaxDots }, + { "canonicalisepermittedcnames", oCanonicalisePermittedCNAMEs }, { "ignoreunknown", oIgnoreUnknown }, { NULL, oBadOption } @@ -535,6 +542,34 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw, return result; } +/* Check and prepare a domain name: removes trailing '.' and lowercases */ +static void +valid_domain(char *name, const char *filename, int linenum) +{ + size_t i, l = strlen(name); + u_char c, last = '\0'; + + if (l == 0) + fatal("%s line %d: empty hostname suffix", filename, linenum); + if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0])) + fatal("%s line %d: hostname suffix \"%.100s\" " + "starts with invalid character", filename, linenum, name); + for (i = 0; i < l; i++) { + c = tolower((u_char)name[i]); + name[i] = (char)c; + if (last == '.' && c == '.') + fatal("%s line %d: hostname suffix \"%.100s\" contains " + "consecutive separators", filename, linenum, name); + if (c != '.' && c != '-' && !isalnum(c) && + c != '_') /* technically invalid, but common */ + fatal("%s line %d: hostname suffix \"%.100s\" contains " + "invalid characters", filename, linenum, name); + last = c; + } + if (name[l - 1] == '.') + name[l - 1] = '\0'; +} + /* * Returns the number of the token pointed to by cp or oBadOption. */ @@ -609,6 +644,14 @@ static const struct multistate multistate_requesttty[] = { { "auto", REQUEST_TTY_AUTO }, { NULL, -1 } }; +static const struct multistate multistate_canonicalisehostname[] = { + { "true", SSH_CANONICALISE_YES }, + { "false", SSH_CANONICALISE_NO }, + { "yes", SSH_CANONICALISE_YES }, + { "no", SSH_CANONICALISE_NO }, + { "always", SSH_CANONICALISE_ALWAYS }, + { NULL, -1 } +}; /* * Processes a single option line as used in the configuration files. This @@ -628,6 +671,7 @@ process_config_line(Options *options, struct passwd *pw, const char *host, size_t len; Forward fwd; const struct multistate *multistate_ptr; + struct allowed_cname *cname; if (activep == NULL) { /* We are processing a command line directive */ cmdline = 1; @@ -1263,6 +1307,62 @@ parse_int: intptr = &options->proxy_use_fdpass; goto parse_flag; + case oCanonicalDomains: + value = options->num_canonical_domains != 0; + while ((arg = strdelim(&s)) != NULL && *arg != '\0') { + valid_domain(arg, filename, linenum); + if (!*activep || value) + continue; + if (options->num_canonical_domains >= MAX_CANON_DOMAINS) + fatal("%s line %d: too many hostname suffixes.", + filename, linenum); + options->canonical_domains[ + options->num_canonical_domains++] = xstrdup(arg); + } + break; + + case oCanonicalisePermittedCNAMEs: + value = options->num_permitted_cnames != 0; + while ((arg = strdelim(&s)) != NULL && *arg != '\0') { + /* Either '*' for everything or 'list:list' */ + if (strcmp(arg, "*") == 0) + arg2 = arg; + else { + lowercase(arg); + if ((arg2 = strchr(arg, ':')) == NULL || + arg2[1] == '\0') { + fatal("%s line %d: " + "Invalid permitted CNAME \"%s\"", + filename, linenum, arg); + } + *arg2 = '\0'; + arg2++; + } + if (!*activep || value) + continue; + if (options->num_permitted_cnames >= MAX_CANON_DOMAINS) + fatal("%s line %d: too many permitted CNAMEs.", + filename, linenum); + cname = options->permitted_cnames + + options->num_permitted_cnames++; + cname->source_list = xstrdup(arg); + cname->target_list = xstrdup(arg2); + } + break; + + case oCanonicaliseHostname: + intptr = &options->canonicalise_hostname; + multistate_ptr = multistate_canonicalisehostname; + goto parse_multistate; + + case oCanonicaliseMaxDots: + intptr = &options->canonicalise_max_dots; + goto parse_int; + + case oCanonicaliseFallbackLocal: + intptr = &options->canonicalise_fallback_local; + goto parse_flag; + case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); @@ -1426,6 +1526,11 @@ initialize_options(Options * options) options->request_tty = -1; options->proxy_use_fdpass = -1; options->ignored_unknown = NULL; + options->num_canonical_domains = 0; + options->num_permitted_cnames = 0; + options->canonicalise_max_dots = -1; + options->canonicalise_fallback_local = -1; + options->canonicalise_hostname = -1; } /* @@ -1579,6 +1684,12 @@ fill_default_options(Options * options) options->request_tty = REQUEST_TTY_AUTO; if (options->proxy_use_fdpass == -1) options->proxy_use_fdpass = 0; + if (options->canonicalise_max_dots == -1) + options->canonicalise_max_dots = 1; + if (options->canonicalise_fallback_local == -1) + options->canonicalise_fallback_local = 1; + if (options->canonicalise_hostname == -1) + options->canonicalise_hostname = SSH_CANONICALISE_NO; #define CLEAR_ON_NONE(v) \ do { \ if (v != NULL && strcasecmp(v, "none") == 0) { \ diff --git a/readconf.h b/readconf.h index cde8b5242..4a210897e 100644 --- a/readconf.h +++ b/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.97 2013/10/14 22:22:03 djm Exp $ */ +/* $OpenBSD: readconf.h,v 1.98 2013/10/16 02:31:46 djm Exp $ */ /* * Author: Tatu Ylonen @@ -29,7 +29,13 @@ typedef struct { /* Data structure for representing option data. */ #define MAX_SEND_ENV 256 -#define SSH_MAX_HOSTS_FILES 256 +#define SSH_MAX_HOSTS_FILES 32 +#define MAX_CANON_DOMAINS 32 + +struct allowed_cname { + char *source_list; + char *target_list; +}; typedef struct { int forward_agent; /* Forward authentication agent. */ @@ -140,9 +146,21 @@ typedef struct { int proxy_use_fdpass; + int num_canonical_domains; + char *canonical_domains[MAX_CANON_DOMAINS]; + int canonicalise_hostname; + int canonicalise_max_dots; + int canonicalise_fallback_local; + int num_permitted_cnames; + struct allowed_cname permitted_cnames[MAX_CANON_DOMAINS]; + char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ } Options; +#define SSH_CANONICALISE_NO 0 +#define SSH_CANONICALISE_YES 1 +#define SSH_CANONICALISE_ALWAYS 2 + #define SSHCTL_MASTER_NO 0 #define SSHCTL_MASTER_YES 1 #define SSHCTL_MASTER_AUTO 2 diff --git a/roaming_client.c b/roaming_client.c index 81c496827..2fb623121 100644 --- a/roaming_client.c +++ b/roaming_client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: roaming_client.c,v 1.5 2013/05/17 00:13:14 djm Exp $ */ +/* $OpenBSD: roaming_client.c,v 1.6 2013/10/16 02:31:46 djm Exp $ */ /* * Copyright (c) 2004-2009 AppGate Network Security AB * @@ -259,10 +259,10 @@ wait_for_roaming_reconnect(void) if (c != '\n' && c != '\r') continue; - if (ssh_connect(host, &hostaddr, options.port, + if (ssh_connect(host, NULL, &hostaddr, options.port, options.address_family, 1, &timeout_ms, - options.tcp_keep_alive, options.use_privileged_port, - options.proxy_command) == 0 && roaming_resume() == 0) { + options.tcp_keep_alive, options.use_privileged_port) == 0 && + roaming_resume() == 0) { packet_restore_state(); reenter_guard = 0; fprintf(stderr, "[connection resumed]\n"); diff --git a/ssh.1 b/ssh.1 index 8091aecfd..d9e2cb658 100644 --- a/ssh.1 +++ b/ssh.1 @@ -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: ssh.1,v 1.337 2013/10/15 14:10:25 jmc Exp $ -.Dd $Mdocdate: October 15 2013 $ +.\" $OpenBSD: ssh.1,v 1.338 2013/10/16 02:31:46 djm Exp $ +.Dd $Mdocdate: October 16 2013 $ .Dt SSH 1 .Os .Sh NAME @@ -417,6 +417,11 @@ For full details of the options listed below, and their possible values, see .It AddressFamily .It BatchMode .It BindAddress +.It CanonicalDomains +.It CanonicaliseFallbackLocal +.It CanonicaliseHostname +.It CanonicaliseMaxDots +.It CanonicalisePermittedCNAMEs .It ChallengeResponseAuthentication .It CheckHostIP .It Cipher diff --git a/ssh.c b/ssh.c index ad6ae0f4f..230591b3a 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.384 2013/10/14 23:31:01 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.385 2013/10/16 02:31:46 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -231,6 +231,134 @@ tilde_expand_paths(char **paths, u_int num_paths) } } +static struct addrinfo * +resolve_host(const char *name, u_int port, int logerr, char *cname, size_t clen) +{ + char strport[NI_MAXSERV]; + struct addrinfo hints, *res; + int gaierr, loglevel = SYSLOG_LEVEL_DEBUG1; + + snprintf(strport, sizeof strport, "%u", port); + bzero(&hints, sizeof(hints)); + hints.ai_family = options.address_family; + hints.ai_socktype = SOCK_STREAM; + if (cname != NULL) + hints.ai_flags = AI_CANONNAME; + if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) { + if (logerr || (gaierr != EAI_NONAME && gaierr != EAI_NODATA)) + loglevel = SYSLOG_LEVEL_ERROR; + do_log2(loglevel, "%s: Could not resolve hostname %.100s: %s", + __progname, name, ssh_gai_strerror(gaierr)); + return NULL; + } + if (cname != NULL && res->ai_canonname != NULL) { + if (strlcpy(cname, res->ai_canonname, clen) >= clen) { + error("%s: host \"%s\" cname \"%s\" too long (max %lu)", + __func__, name, res->ai_canonname, (u_long)clen); + if (clen > 0) + *cname = '\0'; + } + } + return res; +} + +/* + * Check whether the cname is a permitted replacement for the hostname + * and perform the replacement if it is. + */ +static int +check_follow_cname(char **namep, const char *cname) +{ + int i; + struct allowed_cname *rule; + + if (*cname == '\0' || options.num_permitted_cnames == 0 || + strcmp(*namep, cname) == 0) + return 0; + if (options.canonicalise_hostname == SSH_CANONICALISE_NO) + return 0; + /* + * Don't attempt to canonicalise names that will be interpreted by + * a proxy unless the user specifically requests so. + */ + if (options.proxy_command != NULL && + options.canonicalise_hostname != SSH_CANONICALISE_ALWAYS) + return 0; + debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname); + for (i = 0; i < options.num_permitted_cnames; i++) { + rule = options.permitted_cnames + i; + if (match_pattern_list(*namep, rule->source_list, + strlen(rule->source_list), 1) != 1 || + match_pattern_list(cname, rule->target_list, + strlen(rule->target_list), 1) != 1) + continue; + verbose("Canonicalised DNS aliased hostname " + "\"%s\" => \"%s\"", *namep, cname); + free(*namep); + *namep = xstrdup(cname); + return 1; + } + return 0; +} + +/* + * Attempt to resolve the supplied hostname after applying the user's + * canonicalisation rules. Returns the address list for the host or NULL + * if no name was found after canonicalisation. + */ +static struct addrinfo * +resolve_canonicalise(char **hostp, u_int port) +{ + int i, ndots; + char *cp, *fullhost, cname_target[NI_MAXHOST]; + struct addrinfo *addrs; + + if (options.canonicalise_hostname == SSH_CANONICALISE_NO) + return NULL; + /* + * Don't attempt to canonicalise names that will be interpreted by + * a proxy unless the user specifically requests so. + */ + if (options.proxy_command != NULL && + options.canonicalise_hostname != SSH_CANONICALISE_ALWAYS) + return NULL; + /* Don't apply canonicalisation to sufficiently-qualified hostnames */ + ndots = 0; + for (cp = *hostp; *cp != '\0'; cp++) { + if (*cp == '.') + ndots++; + } + if (ndots > options.canonicalise_max_dots) { + debug3("%s: not canonicalising hostname \"%s\" (max dots %d)", + __func__, *hostp, options.canonicalise_max_dots); + return NULL; + } + /* Attempt each supplied suffix */ + for (i = 0; i < options.num_canonical_domains; i++) { + *cname_target = '\0'; + xasprintf(&fullhost, "%s.%s.", *hostp, + options.canonical_domains[i]); + if ((addrs = resolve_host(fullhost, options.port, 0, + cname_target, sizeof(cname_target))) == NULL) { + free(fullhost); + continue; + } + /* Remove trailing '.' */ + fullhost[strlen(fullhost) - 1] = '\0'; + /* Follow CNAME if requested */ + if (!check_follow_cname(&fullhost, cname_target)) { + debug("Canonicalised hostname \"%s\" => \"%s\"", + *hostp, fullhost); + } + free(*hostp); + *hostp = fullhost; + return addrs; + } + if (!options.canonicalise_fallback_local) + fatal("%s: Could not resolve host \"%s\"", __progname, host); + return NULL; +} + /* * Main program for the ssh client. */ @@ -240,12 +368,14 @@ main(int ac, char **av) int i, r, opt, exit_status, use_syslog; char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile; char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; + char cname[NI_MAXHOST]; struct stat st; struct passwd *pw; int timeout_ms; extern int optind, optreset; extern char *optarg; Forward fwd; + struct addrinfo *addrs = NULL; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); @@ -630,9 +760,9 @@ main(int ac, char **av) usage(); options.user = p; *cp = '\0'; - host = ++cp; + host = xstrdup(++cp); } else - host = *av; + host = xstrdup(*av); if (ac > 1) { optind = optreset = 1; goto again; @@ -644,6 +774,9 @@ main(int ac, char **av) if (!host) usage(); + lowercase(host); + host_arg = xstrdup(host); + OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); @@ -728,6 +861,10 @@ main(int ac, char **av) strcmp(options.proxy_command, "-") == 0 && options.proxy_use_fdpass) fatal("ProxyCommand=- and ProxyUseFDPass are incompatible"); +#ifndef HAVE_CYGWIN + if (original_effective_uid != 0) + options.use_privileged_port = 0; +#endif /* reinit */ log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); @@ -762,10 +899,26 @@ main(int ac, char **av) options.port = default_ssh_port(); /* preserve host name given on command line for %n expansion */ - host_arg = host; if (options.hostname != NULL) { - host = percent_expand(options.hostname, + cp = percent_expand(options.hostname, "h", host, (char *)NULL); + free(host); + host = cp; + } + + /* If canonicalisation requested then try to apply it */ + if (options.canonicalise_hostname != SSH_CANONICALISE_NO) + addrs = resolve_canonicalise(&host, options.port); + /* + * If canonicalisation not requested, or if it failed then try to + * resolve the bare hostname name using the system resolver's usual + * search rules. + */ + if (addrs == NULL) { + if ((addrs = resolve_host(host, options.port, 1, + cname, sizeof(cname))) == NULL) + cleanup_exit(255); /* resolve_host logs the error */ + check_follow_cname(&host, cname); } if (gethostname(thishost, sizeof(thishost)) == -1) @@ -803,16 +956,15 @@ main(int ac, char **av) timeout_ms = options.connection_timeout * 1000; /* Open a connection to the remote host. */ - if (ssh_connect(host, &hostaddr, options.port, - options.address_family, options.connection_attempts, &timeout_ms, - options.tcp_keep_alive, -#ifdef HAVE_CYGWIN - options.use_privileged_port, -#else - original_effective_uid == 0 && options.use_privileged_port, -#endif - options.proxy_command) != 0) - exit(255); + if (ssh_connect(host, addrs, &hostaddr, options.port, + options.address_family, options.connection_attempts, + &timeout_ms, options.tcp_keep_alive, + options.use_privileged_port) != 0) + exit(255); + + freeaddrinfo(addrs); + packet_set_timeout(options.server_alive_interval, + options.server_alive_count_max); if (timeout_ms > 0) debug3("timeout: %d ms remain after connect", timeout_ms); @@ -1621,4 +1773,3 @@ main_sigchld_handler(int sig) signal(sig, main_sigchld_handler); errno = save_errno; } - diff --git a/ssh_config.5 b/ssh_config.5 index 3eaaa536a..3c1f87bef 100644 --- a/ssh_config.5 +++ b/ssh_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: ssh_config.5,v 1.170 2013/10/15 14:10:25 jmc Exp $ -.Dd $Mdocdate: October 15 2013 $ +.\" $OpenBSD: ssh_config.5,v 1.171 2013/10/16 02:31:46 djm Exp $ +.Dd $Mdocdate: October 16 2013 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -200,6 +200,77 @@ Note that this option does not work if .Cm UsePrivilegedPort is set to .Dq yes . +.It Cm CanonicalDomains +when +.Cm CanonicaliseHostname +is enabled, this option specifies the list of domain suffixes in which to +search for the specified destination host. +.It Cm CanonicaliseFallbackLocal +specified whether to fail with an error when hostname canonicalisation fails. +The default of +.Dq no +will attempt to lookup the unqualified hostname using the system resolver's +search rules. +A value of +.Dq yes +will cause +.Xr ssh 1 +to fail instantly if +.Cm CanonicaliseHostname +is enabled and the target hostname cannot be found in any of the domains +specified by +.Cm CanonicalDomains . +.It Cm CanonicaliseHostname +controls whether explicit hostname canonicalisation is performed. +The default +.Dq no +is not to perform any name rewriting and let the system resolver handle all +hostname lookups. +If set to +.Dq yes +then, for connections that do not use a +.Cm ProxyCommand , +.Xr ssh 1 +will attempt to canonicalise the hostname specified on the command line +using the +.Cm CanonicalDomains +suffixes and +.Cm CanonicalisePermittedCNAMEs +rules. +If +.Cm CanonicaliseHostname +is set to +.Dq always , +then canonicalisation is applied to proxied connections to. +.It Cm CanonicaliseMaxDots +specifies the maximum number of dot characters in a hostname name before +canonicalisation is disabled. +The default of +.Dq 1 +allows a single dot (i.e. hostname.subdomain) +.It Cm CanonicalisePermittedCNAMEs +specifies rules to determine whether CNAMEs should be followed when +canonicalising hostnames. +The rules consist of one or more arguments of +.Sm off +.Ar source_domain_list : Ar target_domain_list +.Sm on +where +.Ar source_domain_list +is a pattern-list of domains that are may follow CNAMEs in canonicalisation +and +.Ar target_domain_list +is a pattern-list of domains that they may resove to. +.Pp +For example, +.Dq *.a.example.com:*.b.example.com,*.c.example.com +will allow hostnames matching +.Dq *.a.example.com +to be canonicalised to names in the +.Dq *.b.example.com +or +.Dq *.c.example.com +domains. .It Cm ChallengeResponseAuthentication Specifies whether to use challenge-response authentication. The argument to this keyword must be diff --git a/sshconnect.c b/sshconnect.c index aee38198b..3cdc46149 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.240 2013/09/19 01:26:29 djm Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.241 2013/10/16 02:31:46 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -86,7 +86,7 @@ expand_proxy_command(const char *proxy_command, const char *user, { char *tmp, *ret, strport[NI_MAXSERV]; - snprintf(strport, sizeof strport, "%hu", port); + snprintf(strport, sizeof strport, "%d", port); xasprintf(&tmp, "exec %s", proxy_command); ret = percent_expand(tmp, "h", host, "p", strport, "r", options.user, (char *)NULL); @@ -170,8 +170,6 @@ ssh_proxy_fdpass_connect(const char *host, u_short port, /* Set the connection file descriptors. */ packet_set_connection(sock, sock); - packet_set_timeout(options.server_alive_interval, - options.server_alive_count_max); return 0; } @@ -187,16 +185,6 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) pid_t pid; char *shell; - if (!strcmp(proxy_command, "-")) { - packet_set_connection(STDIN_FILENO, STDOUT_FILENO); - packet_set_timeout(options.server_alive_interval, - options.server_alive_count_max); - return 0; - } - - if (options.proxy_use_fdpass) - return ssh_proxy_fdpass_connect(host, port, proxy_command); - if ((shell = getenv("SHELL")) == NULL || *shell == '\0') shell = _PATH_BSHELL; @@ -258,8 +246,6 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) /* Set the connection file descriptors. */ packet_set_connection(pout[0], pin[1]); - packet_set_timeout(options.server_alive_interval, - options.server_alive_count_max); /* Indicate OK return */ return 0; @@ -429,33 +415,18 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr, * and %p substituted for host and port, respectively) to use to contact * the daemon. */ -int -ssh_connect(const char *host, struct sockaddr_storage * hostaddr, - u_short port, int family, int connection_attempts, int *timeout_ms, - int want_keepalive, int needpriv, const char *proxy_command) +static int +ssh_connect_direct(const char *host, struct addrinfo *aitop, + struct sockaddr_storage *hostaddr, u_short port, int family, + int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) { - int gaierr; int on = 1; int sock = -1, attempt; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; - struct addrinfo hints, *ai, *aitop; + struct addrinfo *ai; debug2("ssh_connect: needpriv %d", needpriv); - /* If a proxy command is given, connect using it. */ - if (proxy_command != NULL) - return ssh_proxy_connect(host, port, proxy_command); - - /* No proxy command. */ - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = family; - hints.ai_socktype = SOCK_STREAM; - snprintf(strport, sizeof strport, "%u", port); - if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) - fatal("%s: Could not resolve hostname %.100s: %s", __progname, - host, ssh_gai_strerror(gaierr)); - for (attempt = 0; attempt < connection_attempts; attempt++) { if (attempt > 0) { /* Sleep a moment before retrying. */ @@ -467,7 +438,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, * sequence until the connection succeeds. */ for (ai = aitop; ai; ai = ai->ai_next) { - if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + if (ai->ai_family != AF_INET && + ai->ai_family != AF_INET6) continue; if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), strport, sizeof(strport), @@ -500,8 +472,6 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, break; /* Successful connection. */ } - freeaddrinfo(aitop); - /* Return failure if we didn't get a successful connection. */ if (sock == -1) { error("ssh: connect to host %s port %s: %s", @@ -519,12 +489,28 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, /* Set the connection. */ packet_set_connection(sock, sock); - packet_set_timeout(options.server_alive_interval, - options.server_alive_count_max); return 0; } +int +ssh_connect(const char *host, struct addrinfo *addrs, + struct sockaddr_storage *hostaddr, u_short port, int family, + int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) +{ + if (options.proxy_command == NULL) { + return ssh_connect_direct(host, addrs, hostaddr, port, family, + connection_attempts, timeout_ms, want_keepalive, needpriv); + } else if (strcmp(options.proxy_command, "-") == 0) { + packet_set_connection(STDIN_FILENO, STDOUT_FILENO); + return 0; /* Always succeeds */ + } else if (options.proxy_use_fdpass) { + return ssh_proxy_fdpass_connect(host, port, + options.proxy_command); + } + return ssh_proxy_connect(host, port, options.proxy_command); +} + static void send_client_banner(int connection_out, int minor1) { @@ -1265,7 +1251,7 @@ void ssh_login(Sensitive *sensitive, const char *orighost, struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms) { - char *host, *cp; + char *host; char *server_user, *local_user; local_user = xstrdup(pw->pw_name); @@ -1273,9 +1259,7 @@ ssh_login(Sensitive *sensitive, const char *orighost, /* Convert the user-supplied hostname into all lowercase. */ host = xstrdup(orighost); - for (cp = host; *cp; cp++) - if (isupper(*cp)) - *cp = (char)tolower(*cp); + lowercase(host); /* Exchange protocol version identification strings with the server. */ ssh_exchange_identification(timeout_ms); diff --git a/sshconnect.h b/sshconnect.h index fd7f7f7c6..0ea6e99f6 100644 --- a/sshconnect.h +++ b/sshconnect.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.h,v 1.27 2010/11/29 23:45:51 djm Exp $ */ +/* $OpenBSD: sshconnect.h,v 1.28 2013/10/16 02:31:47 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -31,9 +31,9 @@ struct Sensitive { int external_keysign; }; -int -ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int, - int *, int, int, const char *); +struct addrinfo; +int ssh_connect(const char *, struct addrinfo *, struct sockaddr_storage *, + u_short, int, int, int *, int, int); void ssh_kill_proxy_command(void); void ssh_login(Sensitive *, const char *, struct sockaddr *, u_short, -- cgit v1.2.3 From 3850559be93f1a442ae9ed370e8c389889dd5f72 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Thu, 17 Oct 2013 11:48:13 +1100 Subject: - djm@cvs.openbsd.org 2013/10/16 22:49:39 [readconf.c readconf.h ssh.1 ssh.c ssh_config.5] s/canonicalise/canonicalize/ for consistency with existing spelling, e.g. authorized_keys; pointed out by naddy@ --- ChangeLog | 4 ++++ readconf.c | 50 +++++++++++++++++++++++++------------------------- readconf.h | 8 ++++---- ssh.1 | 10 +++++----- ssh.c | 32 ++++++++++++++++---------------- ssh_config.5 | 24 ++++++++++++------------ 6 files changed, 66 insertions(+), 62 deletions(-) (limited to 'ssh.1') diff --git a/ChangeLog b/ChangeLog index 38082e9c4..6935b5cad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,10 @@ - jmc@cvs.openbsd.org 2013/10/16 06:42:25 [ssh_config.5] tweak previous; + - djm@cvs.openbsd.org 2013/10/16 22:49:39 + [readconf.c readconf.h ssh.1 ssh.c ssh_config.5] + s/canonicalise/canonicalize/ for consistency with existing spelling, + e.g. authorized_keys; pointed out by naddy@ 20131015 - (djm) OpenBSD CVS Sync diff --git a/readconf.c b/readconf.c index de8eb7cd3..fb77fa9dc 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.208 2013/10/16 02:31:45 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.209 2013/10/16 22:49:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -144,8 +144,8 @@ typedef enum { oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, - oCanonicalDomains, oCanonicaliseHostname, oCanonicaliseMaxDots, - oCanonicaliseFallbackLocal, oCanonicalisePermittedCNAMEs, + oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, + oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, oIgnoredUnknownOption, oDeprecated, oUnsupported } OpCodes; @@ -260,10 +260,10 @@ static struct { { "requesttty", oRequestTTY }, { "proxyusefdpass", oProxyUseFdpass }, { "canonicaldomains", oCanonicalDomains }, - { "canonicalisefallbacklocal", oCanonicaliseFallbackLocal }, - { "canonicalisehostname", oCanonicaliseHostname }, - { "canonicalisemaxdots", oCanonicaliseMaxDots }, - { "canonicalisepermittedcnames", oCanonicalisePermittedCNAMEs }, + { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, + { "canonicalizehostname", oCanonicalizeHostname }, + { "canonicalizemaxdots", oCanonicalizeMaxDots }, + { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, { "ignoreunknown", oIgnoreUnknown }, { NULL, oBadOption } @@ -644,7 +644,7 @@ static const struct multistate multistate_requesttty[] = { { "auto", REQUEST_TTY_AUTO }, { NULL, -1 } }; -static const struct multistate multistate_canonicalisehostname[] = { +static const struct multistate multistate_canonicalizehostname[] = { { "true", SSH_CANONICALISE_YES }, { "false", SSH_CANONICALISE_NO }, { "yes", SSH_CANONICALISE_YES }, @@ -1321,7 +1321,7 @@ parse_int: } break; - case oCanonicalisePermittedCNAMEs: + case oCanonicalizePermittedCNAMEs: value = options->num_permitted_cnames != 0; while ((arg = strdelim(&s)) != NULL && *arg != '\0') { /* Either '*' for everything or 'list:list' */ @@ -1350,17 +1350,17 @@ parse_int: } break; - case oCanonicaliseHostname: - intptr = &options->canonicalise_hostname; - multistate_ptr = multistate_canonicalisehostname; + case oCanonicalizeHostname: + intptr = &options->canonicalize_hostname; + multistate_ptr = multistate_canonicalizehostname; goto parse_multistate; - case oCanonicaliseMaxDots: - intptr = &options->canonicalise_max_dots; + case oCanonicalizeMaxDots: + intptr = &options->canonicalize_max_dots; goto parse_int; - case oCanonicaliseFallbackLocal: - intptr = &options->canonicalise_fallback_local; + case oCanonicalizeFallbackLocal: + intptr = &options->canonicalize_fallback_local; goto parse_flag; case oDeprecated: @@ -1528,9 +1528,9 @@ initialize_options(Options * options) options->ignored_unknown = NULL; options->num_canonical_domains = 0; options->num_permitted_cnames = 0; - options->canonicalise_max_dots = -1; - options->canonicalise_fallback_local = -1; - options->canonicalise_hostname = -1; + options->canonicalize_max_dots = -1; + options->canonicalize_fallback_local = -1; + options->canonicalize_hostname = -1; } /* @@ -1684,12 +1684,12 @@ fill_default_options(Options * options) options->request_tty = REQUEST_TTY_AUTO; if (options->proxy_use_fdpass == -1) options->proxy_use_fdpass = 0; - if (options->canonicalise_max_dots == -1) - options->canonicalise_max_dots = 1; - if (options->canonicalise_fallback_local == -1) - options->canonicalise_fallback_local = 1; - if (options->canonicalise_hostname == -1) - options->canonicalise_hostname = SSH_CANONICALISE_NO; + if (options->canonicalize_max_dots == -1) + options->canonicalize_max_dots = 1; + if (options->canonicalize_fallback_local == -1) + options->canonicalize_fallback_local = 1; + if (options->canonicalize_hostname == -1) + options->canonicalize_hostname = SSH_CANONICALISE_NO; #define CLEAR_ON_NONE(v) \ do { \ if (v != NULL && strcasecmp(v, "none") == 0) { \ diff --git a/readconf.h b/readconf.h index 4a210897e..2d7ea9fc4 100644 --- a/readconf.h +++ b/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.98 2013/10/16 02:31:46 djm Exp $ */ +/* $OpenBSD: readconf.h,v 1.99 2013/10/16 22:49:38 djm Exp $ */ /* * Author: Tatu Ylonen @@ -148,9 +148,9 @@ typedef struct { int num_canonical_domains; char *canonical_domains[MAX_CANON_DOMAINS]; - int canonicalise_hostname; - int canonicalise_max_dots; - int canonicalise_fallback_local; + int canonicalize_hostname; + int canonicalize_max_dots; + int canonicalize_fallback_local; int num_permitted_cnames; struct allowed_cname permitted_cnames[MAX_CANON_DOMAINS]; diff --git a/ssh.1 b/ssh.1 index d9e2cb658..6369fc28b 100644 --- a/ssh.1 +++ b/ssh.1 @@ -33,7 +33,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. .\" -.\" $OpenBSD: ssh.1,v 1.338 2013/10/16 02:31:46 djm Exp $ +.\" $OpenBSD: ssh.1,v 1.339 2013/10/16 22:49:38 djm Exp $ .Dd $Mdocdate: October 16 2013 $ .Dt SSH 1 .Os @@ -418,10 +418,10 @@ For full details of the options listed below, and their possible values, see .It BatchMode .It BindAddress .It CanonicalDomains -.It CanonicaliseFallbackLocal -.It CanonicaliseHostname -.It CanonicaliseMaxDots -.It CanonicalisePermittedCNAMEs +.It CanonicalizeFallbackLocal +.It CanonicalizeHostname +.It CanonicalizeMaxDots +.It CanonicalizePermittedCNAMEs .It ChallengeResponseAuthentication .It CheckHostIP .It Cipher diff --git a/ssh.c b/ssh.c index 230591b3a..6581e57bf 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.385 2013/10/16 02:31:46 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.386 2013/10/16 22:49:39 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -275,14 +275,14 @@ check_follow_cname(char **namep, const char *cname) if (*cname == '\0' || options.num_permitted_cnames == 0 || strcmp(*namep, cname) == 0) return 0; - if (options.canonicalise_hostname == SSH_CANONICALISE_NO) + if (options.canonicalize_hostname == SSH_CANONICALISE_NO) return 0; /* - * Don't attempt to canonicalise names that will be interpreted by + * Don't attempt to canonicalize names that will be interpreted by * a proxy unless the user specifically requests so. */ if (options.proxy_command != NULL && - options.canonicalise_hostname != SSH_CANONICALISE_ALWAYS) + options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) return 0; debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname); for (i = 0; i < options.num_permitted_cnames; i++) { @@ -292,7 +292,7 @@ check_follow_cname(char **namep, const char *cname) match_pattern_list(cname, rule->target_list, strlen(rule->target_list), 1) != 1) continue; - verbose("Canonicalised DNS aliased hostname " + verbose("Canonicalized DNS aliased hostname " "\"%s\" => \"%s\"", *namep, cname); free(*namep); *namep = xstrdup(cname); @@ -307,20 +307,20 @@ check_follow_cname(char **namep, const char *cname) * if no name was found after canonicalisation. */ static struct addrinfo * -resolve_canonicalise(char **hostp, u_int port) +resolve_canonicalize(char **hostp, u_int port) { int i, ndots; char *cp, *fullhost, cname_target[NI_MAXHOST]; struct addrinfo *addrs; - if (options.canonicalise_hostname == SSH_CANONICALISE_NO) + if (options.canonicalize_hostname == SSH_CANONICALISE_NO) return NULL; /* - * Don't attempt to canonicalise names that will be interpreted by + * Don't attempt to canonicalize names that will be interpreted by * a proxy unless the user specifically requests so. */ if (options.proxy_command != NULL && - options.canonicalise_hostname != SSH_CANONICALISE_ALWAYS) + options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) return NULL; /* Don't apply canonicalisation to sufficiently-qualified hostnames */ ndots = 0; @@ -328,9 +328,9 @@ resolve_canonicalise(char **hostp, u_int port) if (*cp == '.') ndots++; } - if (ndots > options.canonicalise_max_dots) { - debug3("%s: not canonicalising hostname \"%s\" (max dots %d)", - __func__, *hostp, options.canonicalise_max_dots); + if (ndots > options.canonicalize_max_dots) { + debug3("%s: not canonicalizing hostname \"%s\" (max dots %d)", + __func__, *hostp, options.canonicalize_max_dots); return NULL; } /* Attempt each supplied suffix */ @@ -347,14 +347,14 @@ resolve_canonicalise(char **hostp, u_int port) fullhost[strlen(fullhost) - 1] = '\0'; /* Follow CNAME if requested */ if (!check_follow_cname(&fullhost, cname_target)) { - debug("Canonicalised hostname \"%s\" => \"%s\"", + debug("Canonicalized hostname \"%s\" => \"%s\"", *hostp, fullhost); } free(*hostp); *hostp = fullhost; return addrs; } - if (!options.canonicalise_fallback_local) + if (!options.canonicalize_fallback_local) fatal("%s: Could not resolve host \"%s\"", __progname, host); return NULL; } @@ -907,8 +907,8 @@ main(int ac, char **av) } /* If canonicalisation requested then try to apply it */ - if (options.canonicalise_hostname != SSH_CANONICALISE_NO) - addrs = resolve_canonicalise(&host, options.port); + if (options.canonicalize_hostname != SSH_CANONICALISE_NO) + addrs = resolve_canonicalize(&host, options.port); /* * If canonicalisation not requested, or if it failed then try to * resolve the bare hostname name using the system resolver's usual diff --git a/ssh_config.5 b/ssh_config.5 index 2c0e66556..586db6b9f 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,7 +33,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. .\" -.\" $OpenBSD: ssh_config.5,v 1.172 2013/10/16 06:42:25 jmc Exp $ +.\" $OpenBSD: ssh_config.5,v 1.173 2013/10/16 22:49:39 djm Exp $ .Dd $Mdocdate: October 16 2013 $ .Dt SSH_CONFIG 5 .Os @@ -202,10 +202,10 @@ is set to .Dq yes . .It Cm CanonicalDomains When -.Cm CanonicaliseHostname +.Cm CanonicalizeHostname is enabled, this option specifies the list of domain suffixes in which to search for the specified destination host. -.It Cm CanonicaliseFallbackLocal +.It Cm CanonicalizeFallbackLocal Specifies whether to fail with an error when hostname canonicalisation fails. The default, .Dq no , @@ -216,11 +216,11 @@ A value of will cause .Xr ssh 1 to fail instantly if -.Cm CanonicaliseHostname +.Cm CanonicalizeHostname is enabled and the target hostname cannot be found in any of the domains specified by .Cm CanonicalDomains . -.It Cm CanonicaliseHostname +.It Cm CanonicalizeHostname Controls whether explicit hostname canonicalisation is performed. The default, .Dq no , @@ -231,26 +231,26 @@ If set to then, for connections that do not use a .Cm ProxyCommand , .Xr ssh 1 -will attempt to canonicalise the hostname specified on the command line +will attempt to canonicalize the hostname specified on the command line using the .Cm CanonicalDomains suffixes and -.Cm CanonicalisePermittedCNAMEs +.Cm CanonicalizePermittedCNAMEs rules. If -.Cm CanonicaliseHostname +.Cm CanonicalizeHostname is set to .Dq always , then canonicalisation is applied to proxied connections too. -.It Cm CanonicaliseMaxDots +.It Cm CanonicalizeMaxDots Specifies the maximum number of dot characters in a hostname before canonicalisation is disabled. The default, .Dq 1 , allows a single dot (i.e. hostname.subdomain). -.It Cm CanonicalisePermittedCNAMEs +.It Cm CanonicalizePermittedCNAMEs Specifies rules to determine whether CNAMEs should be followed when -canonicalising hostnames. +canonicalizing hostnames. The rules consist of one or more arguments of .Ar source_domain_list : Ns Ar target_domain_list , where @@ -264,7 +264,7 @@ For example, .Dq *.a.example.com:*.b.example.com,*.c.example.com will allow hostnames matching .Dq *.a.example.com -to be canonicalised to names in the +to be canonicalized to names in the .Dq *.b.example.com or .Dq *.c.example.com -- cgit v1.2.3 From 0fde8acdad78a4d20cadae974376cc0165f645ee Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Thu, 21 Nov 2013 14:12:23 +1100 Subject: - djm@cvs.openbsd.org 2013/11/21 00:45:44 [Makefile.in PROTOCOL PROTOCOL.chacha20poly1305 authfile.c chacha.c] [chacha.h cipher-chachapoly.c cipher-chachapoly.h cipher.c cipher.h] [dh.c myproposal.h packet.c poly1305.c poly1305.h servconf.c ssh.1] [ssh.c ssh_config.5 sshd_config.5] Add a new protocol 2 transport cipher "chacha20-poly1305@openssh.com" that combines Daniel Bernstein's ChaCha20 stream cipher and Poly1305 MAC to build an authenticated encryption mode. Inspired by and similar to Adam Langley's proposal for TLS: http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 but differs in layout used for the MAC calculation and the use of a second ChaCha20 instance to separately encrypt packet lengths. Details are in the PROTOCOL.chacha20poly1305 file. Feedback markus@, naddy@; manpage bits Loganden Velvindron @ AfriNIC ok markus@ naddy@ --- ChangeLog | 17 ++++ Makefile.in | 4 +- PROTOCOL | 7 +- PROTOCOL.chacha20poly1305 | 105 ++++++++++++++++++++++ authfile.c | 6 +- chacha.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++ chacha.h | 35 ++++++++ cipher-chachapoly.c | 114 ++++++++++++++++++++++++ cipher-chachapoly.h | 41 +++++++++ cipher.c | 65 ++++++++++++-- cipher.h | 11 ++- dh.c | 38 +++----- myproposal.h | 3 +- packet.c | 24 ++--- poly1305.c | 158 +++++++++++++++++++++++++++++++++ poly1305.h | 22 +++++ servconf.c | 4 +- ssh.1 | 6 +- ssh.c | 6 +- ssh_config.5 | 18 +++- sshd_config.5 | 18 +++- 21 files changed, 853 insertions(+), 68 deletions(-) create mode 100644 PROTOCOL.chacha20poly1305 create mode 100644 chacha.c create mode 100644 chacha.h create mode 100644 cipher-chachapoly.c create mode 100644 cipher-chachapoly.h create mode 100644 poly1305.c create mode 100644 poly1305.h (limited to 'ssh.1') diff --git a/ChangeLog b/ChangeLog index cb4dae30e..28186e89f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,6 +19,23 @@ [canohost.c clientloop.c match.c readconf.c sftp.c] unsigned casts for ctype macros where neccessary ok guenther millert markus + - djm@cvs.openbsd.org 2013/11/21 00:45:44 + [Makefile.in PROTOCOL PROTOCOL.chacha20poly1305 authfile.c chacha.c] + [chacha.h cipher-chachapoly.c cipher-chachapoly.h cipher.c cipher.h] + [dh.c myproposal.h packet.c poly1305.c poly1305.h servconf.c ssh.1] + [ssh.c ssh_config.5 sshd_config.5] Add a new protocol 2 transport + cipher "chacha20-poly1305@openssh.com" that combines Daniel + Bernstein's ChaCha20 stream cipher and Poly1305 MAC to build an + authenticated encryption mode. + + Inspired by and similar to Adam Langley's proposal for TLS: + http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 + but differs in layout used for the MAC calculation and the use of a + second ChaCha20 instance to separately encrypt packet lengths. + Details are in the PROTOCOL.chacha20poly1305 file. + + Feedback markus@, naddy@; manpage bits Loganden Velvindron @ AfriNIC + ok markus@ naddy@ 20131110 - (dtucker) [regress/keytype.sh] Populate ECDSA key types to be tested by diff --git a/Makefile.in b/Makefile.in index e1c68c00b..91f39d4f3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in,v 1.344 2013/11/08 13:17:41 dtucker Exp $ +# $Id: Makefile.in,v 1.345 2013/11/21 03:12:23 djm Exp $ # uncomment if you run a non bourne compatable shell. Ie. csh #SHELL = @SH@ @@ -74,7 +74,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ jpake.o schnorr.o ssh-pkcs11.o krl.o smult_curve25519_ref.o \ - kexc25519.o kexc25519c.o + kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ sshconnect.o sshconnect1.o sshconnect2.o mux.o \ diff --git a/PROTOCOL b/PROTOCOL index 0363314c0..cace97f88 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -91,6 +91,11 @@ an MAC algorithm. Additionally, if AES-GCM is selected as the cipher the exchanged MAC algorithms are ignored and there doesn't have to be a matching MAC. +1.7 transport: chacha20-poly1305@openssh.com authenticated encryption + +OpenSSH supports authenticated encryption using ChaCha20 and Poly1305 +as described in PROTOCOL.chacha20poly1305. + 2. Connection protocol changes 2.1. connection: Channel write close extension "eow@openssh.com" @@ -345,4 +350,4 @@ respond with a SSH_FXP_STATUS message. This extension is advertised in the SSH_FXP_VERSION hello with version "1". -$OpenBSD: PROTOCOL,v 1.21 2013/10/17 00:30:13 djm Exp $ +$OpenBSD: PROTOCOL,v 1.22 2013/11/21 00:45:43 djm Exp $ diff --git a/PROTOCOL.chacha20poly1305 b/PROTOCOL.chacha20poly1305 new file mode 100644 index 000000000..c4b723aff --- /dev/null +++ b/PROTOCOL.chacha20poly1305 @@ -0,0 +1,105 @@ +This document describes the chacha20-poly1305@openssh.com authenticated +encryption cipher supported by OpenSSH. + +Background +---------- + +ChaCha20 is a stream cipher designed by Daniel Bernstein and described +in [1]. It operates by permuting 128 fixed bits, 128 or 256 bits of key, +a 64 bit nonce and a 64 bit counter into 64 bytes of output. This output +is used as a keystream, with any unused bytes simply discarded. + +Poly1305[2], also by Daniel Bernstein, is a one-time Carter-Wegman MAC +that computes a 128 bit integrity tag given a message and a single-use +256 bit secret key. + +The chacha20-poly1305@openssh.com combines these two primitives into an +authenticated encryption mode. The construction used is based on that +proposed for TLS by Adam Langley in [3], but differs in the layout of +data passed to the MAC and in the addition of encyption of the packet +lengths. + +Negotiation +----------- + +The chacha20-poly1305@openssh.com offers both encryption and +authentication. As such, no separate MAC is required. If the +chacha20-poly1305@openssh.com cipher is selected in key exchange, +the offered MAC algorithms are ignored and no MAC is required to be +negotiated. + +Detailed Construction +--------------------- + +The chacha20-poly1305@openssh.com cipher requires 512 bits of key +material as output from the SSH key exchange. This forms two 256 bit +keys (K_1 and K_2), used by two separate instances of chacha20. + +The instance keyed by K_1 is a stream cipher that is used only +to encrypt the 4 byte packet length field. The second instance, +keyed by K_2, is used in conjunction with poly1305 to build an AEAD +(Authenticated Encryption with Associated Data) that is used to encrypt +and authenticate the entire packet. + +Two separate cipher instances are used here so as to keep the packet +lengths confidential but not create an oracle for the packet payload +cipher by decrypting and using the packet length prior to checking +the MAC. By using an independently-keyed cipher instance to encrypt the +length, an active attacker seeking to exploit the packet input handling +as a decryption oracle can learn nothing about the payload contents or +its MAC (assuming key derivation, ChaCha20 and Poly1306 are secure). + +The AEAD is constructed as follows: for each packet, generate a Poly1305 +key by taking the first 256 bits of ChaCha20 stream output generated +using K_2, an IV consisting of the packet sequence number encoded as an +uint64 under the SSH wire encoding rules and a ChaCha20 block counter of +zero. The K_2 ChaCha20 block counter is then set to the little-endian +encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance is used +for encryption of the packet payload. + +Packet Handling +--------------- + +When receiving a packet, the length must be decrypted first. When 4 +bytes of ciphertext length have been received, they may be decrypted +using the K_1 key, a nonce consisting of the packet sequence number +encoded as a uint64 under the usual SSH wire encoding and a zero block +counter to obtain the plaintext length. + +Once the entire packet has been received, the MAC MUST be checked +before decryption. A per-packet Poly1305 key is generated as described +above and the MAC tag calculated using Poly1305 with this key over the +ciphertext of the packet length and the payload together. The calculated +MAC is then compared in constant time with the one appended to the +packet and the packet decrypted using ChaCha20 as described above (with +K_2, the packet sequence number as nonce and a starting block counter of +1). + +To send a packet, first encode the 4 byte length and encrypt it using +K_1. Encrypt the packet payload (using K_2) and append it to the +encrypted length. Finally, calculate a MAC tag and append it. + +Rekeying +-------- + +ChaCha20 must never reuse a {key, nonce} for encryption nor may it be +used to encrypt more than 2^70 bytes under the same {key, nonce}. The +SSH Transport protocol (RFC4253) recommends a far more conservative +rekeying every 1GB of data sent or received. If this recommendation +is followed, then chacha20-poly1305@openssh.com requires no special +handling in this area. + +References +---------- + +[1] "ChaCha, a variant of Salsa20", Daniel Bernstein + http://cr.yp.to/chacha/chacha-20080128.pdf + +[2] "The Poly1305-AES message-authentication code", Daniel Bernstein + http://cr.yp.to/mac/poly1305-20050329.pdf + +[3] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley + http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 + +$OpenBSD: PROTOCOL.chacha20poly1305,v 1.1 2013/11/21 00:45:43 djm Exp $ + diff --git a/authfile.c b/authfile.c index 63ae16bbd..d0c1089eb 100644 --- a/authfile.c +++ b/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.97 2013/05/17 00:13:13 djm Exp $ */ +/* $OpenBSD: authfile.c,v 1.98 2013/11/21 00:45:43 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -149,7 +149,7 @@ key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_ENCRYPT); - cipher_crypt(&ciphercontext, cp, + cipher_crypt(&ciphercontext, 0, cp, buffer_ptr(&buffer), buffer_len(&buffer), 0, 0); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); @@ -473,7 +473,7 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_DECRYPT); - cipher_crypt(&ciphercontext, cp, + cipher_crypt(&ciphercontext, 0, cp, buffer_ptr(©), buffer_len(©), 0, 0); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); diff --git a/chacha.c b/chacha.c new file mode 100644 index 000000000..a84c25ea8 --- /dev/null +++ b/chacha.c @@ -0,0 +1,219 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#include "includes.h" + +#include "chacha.h" + +/* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */ + +typedef unsigned char u8; +typedef unsigned int u32; + +typedef struct chacha_ctx chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +void +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +void +chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) +{ + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +void +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + u8 *ctarget = NULL; + u8 tmp[64]; + u_int i; + + if (!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} diff --git a/chacha.h b/chacha.h new file mode 100644 index 000000000..4ef42cc70 --- /dev/null +++ b/chacha.h @@ -0,0 +1,35 @@ +/* $OpenBSD: chacha.h,v 1.1 2013/11/21 00:45:44 djm Exp $ */ + +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#ifndef CHACHA_H +#define CHACHA_H + +#include + +struct chacha_ctx { + u_int input[16]; +}; + +#define CHACHA_MINKEYLEN 16 +#define CHACHA_NONCELEN 8 +#define CHACHA_CTRLEN 8 +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) +#define CHACHA_BLOCKLEN 64 + +void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); +void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); +void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m, + u_char *c, u_int bytes) + __attribute__((__bounded__(__buffer__, 2, 4))) + __attribute__((__bounded__(__buffer__, 3, 4))); + +#endif /* CHACHA_H */ + diff --git a/cipher-chachapoly.c b/cipher-chachapoly.c new file mode 100644 index 000000000..20628ab5d --- /dev/null +++ b/cipher-chachapoly.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2013 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* $OpenBSD: cipher-chachapoly.c,v 1.2 2013/11/21 02:50:00 djm Exp $ */ + +#include "includes.h" + +#include +#include /* needed for log.h */ +#include +#include /* needed for misc.h */ + +#include "log.h" +#include "misc.h" +#include "cipher-chachapoly.h" + +void chachapoly_init(struct chachapoly_ctx *ctx, + const u_char *key, u_int keylen) +{ + if (keylen != (32 + 32)) /* 2 x 256 bit keys */ + fatal("%s: invalid keylen %u", __func__, keylen); + chacha_keysetup(&ctx->main_ctx, key, 256); + chacha_keysetup(&ctx->header_ctx, key + 32, 256); +} + +/* + * chachapoly_crypt() operates as following: + * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. + * Theses bytes are treated as additional authenticated data. + * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. + * Use POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the + * authentication tag. + * This tag is written on encryption and verified on decryption. + * Both 'aadlen' and 'authlen' can be set to 0. + */ +int +chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest, + const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) +{ + u_char seqbuf[8]; + u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB. little-endian */ + u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; + int r = -1; + + /* + * Run ChaCha20 once to generate the Poly1305 key. The IV is the + * packet sequence number. + */ + bzero(poly_key, sizeof(poly_key)); + put_u64(seqbuf, seqnr); + chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->main_ctx, + poly_key, poly_key, sizeof(poly_key)); + /* Set Chacha's block counter to 1 */ + chacha_ivsetup(&ctx->main_ctx, seqbuf, one); + + /* If decrypting, check tag before anything else */ + if (!do_encrypt) { + const u_char *tag = src + aadlen + len; + + poly1305_auth(expected_tag, src, aadlen + len, poly_key); + if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) + goto out; + } + /* Crypt additional data */ + if (aadlen) { + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); + } + chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, + dest + aadlen, len); + + /* If encrypting, calculate and append tag */ + if (do_encrypt) { + poly1305_auth(dest + aadlen + len, dest, aadlen + len, + poly_key); + } + r = 0; + + out: + bzero(expected_tag, sizeof(expected_tag)); + bzero(seqbuf, sizeof(seqbuf)); + bzero(poly_key, sizeof(poly_key)); + return r; +} + +int +chachapoly_get_length(struct chachapoly_ctx *ctx, + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) +{ + u_char buf[4], seqbuf[8]; + + if (len < 4) + return -1; /* Insufficient length */ + put_u64(seqbuf, seqnr); + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); + *plenp = get_u32(buf); + return 0; +} + diff --git a/cipher-chachapoly.h b/cipher-chachapoly.h new file mode 100644 index 000000000..1628693b2 --- /dev/null +++ b/cipher-chachapoly.h @@ -0,0 +1,41 @@ +/* $OpenBSD: cipher-chachapoly.h,v 1.1 2013/11/21 00:45:44 djm Exp $ */ + +/* + * Copyright (c) Damien Miller 2013 + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef CHACHA_POLY_AEAD_H +#define CHACHA_POLY_AEAD_H + +#include +#include "chacha.h" +#include "poly1305.h" + +#define CHACHA_KEYLEN 32 /* Only 256 bit keys used here */ + +struct chachapoly_ctx { + struct chacha_ctx main_ctx, header_ctx; +}; + +void chachapoly_init(struct chachapoly_ctx *cpctx, + const u_char *key, u_int keylen) + __attribute__((__bounded__(__buffer__, 2, 3))); +int chachapoly_crypt(struct chachapoly_ctx *cpctx, u_int seqnr, + u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen, + int do_encrypt); +int chachapoly_get_length(struct chachapoly_ctx *cpctx, + u_int *plenp, u_int seqnr, const u_char *cp, u_int len) + __attribute__((__bounded__(__buffer__, 4, 5))); + +#endif /* CHACHA_POLY_AEAD_H */ diff --git a/cipher.c b/cipher.c index 54315f488..c4aec3923 100644 --- a/cipher.c +++ b/cipher.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cipher.c,v 1.90 2013/11/07 11:58:27 dtucker Exp $ */ +/* $OpenBSD: cipher.c,v 1.91 2013/11/21 00:45:44 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -43,9 +43,11 @@ #include #include +#include #include "xmalloc.h" #include "log.h" +#include "misc.h" #include "cipher.h" /* compatibility with old or broken OpenSSL versions */ @@ -63,7 +65,9 @@ struct Cipher { u_int iv_len; /* defaults to block_size */ u_int auth_len; u_int discard_len; - u_int cbc_mode; + u_int flags; +#define CFLAG_CBC (1<<0) +#define CFLAG_CHACHAPOLY (1<<1) const EVP_CIPHER *(*evptype)(void); }; @@ -95,6 +99,8 @@ static const struct Cipher ciphers[] = { { "aes256-gcm@openssh.com", SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, #endif + { "chacha20-poly1305@openssh.com", + SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL }, { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } }; @@ -102,7 +108,7 @@ static const struct Cipher ciphers[] = { /* Returns a list of supported ciphers separated by the specified char. */ char * -cipher_alg_list(char sep) +cipher_alg_list(char sep, int auth_only) { char *ret = NULL; size_t nlen, rlen = 0; @@ -111,6 +117,8 @@ cipher_alg_list(char sep) for (c = ciphers; c->name != NULL; c++) { if (c->number != SSH_CIPHER_SSH2) continue; + if (auth_only && c->auth_len == 0) + continue; if (ret != NULL) ret[rlen++] = sep; nlen = strlen(c->name); @@ -142,7 +150,12 @@ cipher_authlen(const Cipher *c) u_int cipher_ivlen(const Cipher *c) { - return (c->iv_len ? c->iv_len : c->block_size); + /* + * Default is cipher block size, except for chacha20+poly1305 that + * needs no IV. XXX make iv_len == -1 default? + */ + return (c->iv_len != 0 || (c->flags & CFLAG_CHACHAPOLY) != 0) ? + c->iv_len : c->block_size; } u_int @@ -154,7 +167,7 @@ cipher_get_number(const Cipher *c) u_int cipher_is_cbc(const Cipher *c) { - return (c->cbc_mode); + return (c->flags & CFLAG_CBC) != 0; } u_int @@ -274,8 +287,11 @@ cipher_init(CipherContext *cc, const Cipher *cipher, ivlen, cipher->name); cc->cipher = cipher; + if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { + chachapoly_init(&cc->cp_ctx, key, keylen); + return; + } type = (*cipher->evptype)(); - EVP_CIPHER_CTX_init(&cc->evp); #ifdef SSH_OLD_EVP if (type->key_len > 0 && type->key_len != keylen) { @@ -330,9 +346,15 @@ cipher_init(CipherContext *cc, const Cipher *cipher, * Both 'aadlen' and 'authlen' can be set to 0. */ void -cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, +cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen) { + if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { + if (chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, + authlen, cc->encrypt) != 0) + fatal("Decryption integrity check failed"); + return; + } if (authlen) { u_char lastiv[1]; @@ -374,10 +396,26 @@ cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, } } +/* Extract the packet length, including any decryption necessary beforehand */ +int +cipher_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, + const u_char *cp, u_int len) +{ + if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) + return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr, + cp, len); + if (len < 4) + return -1; + *plenp = get_u32(cp); + return 0; +} + void cipher_cleanup(CipherContext *cc) { - if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) + if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) + bzero(&cc->cp_ctx, sizeof(&cc->cp_ctx)); + else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); } @@ -417,6 +455,8 @@ cipher_get_keyiv_len(const CipherContext *cc) if (c->number == SSH_CIPHER_3DES) ivlen = 24; + else if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) + ivlen = 0; else ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); return (ivlen); @@ -428,6 +468,12 @@ cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) const Cipher *c = cc->cipher; int evplen; + if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { + if (len != 0) + fatal("%s: wrong iv length %d != %d", __func__, len, 0); + return; + } + switch (c->number) { case SSH_CIPHER_SSH2: case SSH_CIPHER_DES: @@ -464,6 +510,9 @@ cipher_set_keyiv(CipherContext *cc, u_char *iv) const Cipher *c = cc->cipher; int evplen = 0; + if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) + return; + switch (c->number) { case SSH_CIPHER_SSH2: case SSH_CIPHER_DES: diff --git a/cipher.h b/cipher.h index 46502348b..4e837a754 100644 --- a/cipher.h +++ b/cipher.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cipher.h,v 1.41 2013/11/07 11:58:27 dtucker Exp $ */ +/* $OpenBSD: cipher.h,v 1.42 2013/11/21 00:45:44 djm Exp $ */ /* * Author: Tatu Ylonen @@ -38,6 +38,8 @@ #define CIPHER_H #include +#include "cipher-chachapoly.h" + /* * Cipher types for SSH-1. New types can be added, but old types should not * be removed for compatibility. The maximum allowed value is 31. @@ -66,6 +68,7 @@ struct CipherContext { int plaintext; int encrypt; EVP_CIPHER_CTX evp; + struct chachapoly_ctx cp_ctx; /* XXX union with evp? */ const Cipher *cipher; }; @@ -75,11 +78,13 @@ const Cipher *cipher_by_number(int); int cipher_number(const char *); char *cipher_name(int); int ciphers_valid(const char *); -char *cipher_alg_list(char); +char *cipher_alg_list(char, int); void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, const u_char *, u_int, int); -void cipher_crypt(CipherContext *, u_char *, const u_char *, +void cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, u_int, u_int, u_int); +int cipher_get_length(CipherContext *, u_int *, u_int, + const u_char *, u_int); void cipher_cleanup(CipherContext *); void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); u_int cipher_blocksize(const Cipher *); diff --git a/dh.c b/dh.c index d33af1fa7..3331cda6c 100644 --- a/dh.c +++ b/dh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dh.c,v 1.52 2013/10/08 11:42:13 dtucker Exp $ */ +/* $OpenBSD: dh.c,v 1.53 2013/11/21 00:45:44 djm Exp $ */ /* * Copyright (c) 2000 Niels Provos. All rights reserved. * @@ -254,33 +254,19 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) void dh_gen_key(DH *dh, int need) { - int i, bits_set, tries = 0; + int pbits; - if (need < 0) - fatal("dh_gen_key: need < 0"); + if (need <= 0) + fatal("%s: need <= 0", __func__); if (dh->p == NULL) - fatal("dh_gen_key: dh->p == NULL"); - if (need > INT_MAX / 2 || 2 * need >= BN_num_bits(dh->p)) - fatal("dh_gen_key: group too small: %d (2*need %d)", - BN_num_bits(dh->p), 2*need); - do { - if (dh->priv_key != NULL) - BN_clear_free(dh->priv_key); - if ((dh->priv_key = BN_new()) == NULL) - fatal("dh_gen_key: BN_new failed"); - /* generate a 2*need bits random private exponent */ - if (!BN_rand(dh->priv_key, 2*need, 0, 0)) - fatal("dh_gen_key: BN_rand failed"); - if (DH_generate_key(dh) == 0) - fatal("DH_generate_key"); - for (i = 0, bits_set = 0; i <= BN_num_bits(dh->priv_key); i++) - if (BN_is_bit_set(dh->priv_key, i)) - bits_set++; - debug2("dh_gen_key: priv key bits set: %d/%d", - bits_set, BN_num_bits(dh->priv_key)); - if (tries++ > 10) - fatal("dh_gen_key: too many bad keys: giving up"); - } while (!dh_pub_is_valid(dh, dh->pub_key)); + fatal("%s: dh->p == NULL", __func__); + if ((pbits = BN_num_bits(dh->p)) <= 0) + fatal("%s: bits(p) <= 0", __func__); + dh->length = MIN(need * 2, pbits - 1); + if (DH_generate_key(dh) == 0) + fatal("%s: key generation failed", __func__); + if (!dh_pub_is_valid(dh, dh->pub_key)) + fatal("%s: generated invalid key", __func__); } DH * diff --git a/myproposal.h b/myproposal.h index 8da2ac91f..71dbc997e 100644 --- a/myproposal.h +++ b/myproposal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: myproposal.h,v 1.33 2013/11/02 21:59:15 markus Exp $ */ +/* $OpenBSD: myproposal.h,v 1.34 2013/11/21 00:45:44 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -104,6 +104,7 @@ "aes128-ctr,aes192-ctr,aes256-ctr," \ "arcfour256,arcfour128," \ AESGCM_CIPHER_MODES \ + "chacha20-poly1305@openssh.com," \ "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se" diff --git a/packet.c b/packet.c index 90db33bdd..029bb4c98 100644 --- a/packet.c +++ b/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.189 2013/11/08 00:39:15 djm Exp $ */ +/* $OpenBSD: packet.c,v 1.190 2013/11/21 00:45:44 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -713,7 +713,7 @@ packet_send1(void) buffer_append(&active_state->output, buf, 4); cp = buffer_append_space(&active_state->output, buffer_len(&active_state->outgoing_packet)); - cipher_crypt(&active_state->send_context, cp, + cipher_crypt(&active_state->send_context, 0, cp, buffer_ptr(&active_state->outgoing_packet), buffer_len(&active_state->outgoing_packet), 0, 0); @@ -946,8 +946,8 @@ packet_send2_wrapped(void) } /* encrypt packet and append to output buffer. */ cp = buffer_append_space(&active_state->output, len + authlen); - cipher_crypt(&active_state->send_context, cp, - buffer_ptr(&active_state->outgoing_packet), + cipher_crypt(&active_state->send_context, active_state->p_send.seqnr, + cp, buffer_ptr(&active_state->outgoing_packet), len - aadlen, aadlen, authlen); /* append unencrypted MAC */ if (mac && mac->enabled) { @@ -1208,7 +1208,7 @@ packet_read_poll1(void) /* Decrypt data to incoming_packet. */ buffer_clear(&active_state->incoming_packet); cp = buffer_append_space(&active_state->incoming_packet, padded_len); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, 0, cp, buffer_ptr(&active_state->input), padded_len, 0, 0); buffer_consume(&active_state->input, padded_len); @@ -1279,10 +1279,12 @@ packet_read_poll2(u_int32_t *seqnr_p) aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; if (aadlen && active_state->packlen == 0) { - if (buffer_len(&active_state->input) < 4) + if (cipher_get_length(&active_state->receive_context, + &active_state->packlen, + active_state->p_read.seqnr, + buffer_ptr(&active_state->input), + buffer_len(&active_state->input)) != 0) return SSH_MSG_NONE; - cp = buffer_ptr(&active_state->input); - active_state->packlen = get_u32(cp); if (active_state->packlen < 1 + 4 || active_state->packlen > PACKET_MAX_SIZE) { #ifdef PACKET_DEBUG @@ -1302,7 +1304,8 @@ packet_read_poll2(u_int32_t *seqnr_p) buffer_clear(&active_state->incoming_packet); cp = buffer_append_space(&active_state->incoming_packet, block_size); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, + active_state->p_read.seqnr, cp, buffer_ptr(&active_state->input), block_size, 0, 0); cp = buffer_ptr(&active_state->incoming_packet); active_state->packlen = get_u32(cp); @@ -1357,7 +1360,8 @@ packet_read_poll2(u_int32_t *seqnr_p) macbuf = mac_compute(mac, active_state->p_read.seqnr, buffer_ptr(&active_state->input), aadlen + need); cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); - cipher_crypt(&active_state->receive_context, cp, + cipher_crypt(&active_state->receive_context, + active_state->p_read.seqnr, cp, buffer_ptr(&active_state->input), need, aadlen, authlen); buffer_consume(&active_state->input, aadlen + need + authlen); /* diff --git a/poly1305.c b/poly1305.c new file mode 100644 index 000000000..059cc60f7 --- /dev/null +++ b/poly1305.c @@ -0,0 +1,158 @@ +/* + * Public Domain poly1305 from Andrew M. + * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna + */ + +/* $OpenBSD: poly1305.c,v 1.2 2013/11/21 02:50:00 djm Exp $ */ + +#include "includes.h" + +#include +#include + +#include "poly1305.h" + +#define mul32x32_64(a,b) ((uint64_t)(a) * (b)) + +#define U8TO32_LE(p) \ + (((uint32_t)((p)[0])) | \ + ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | \ + ((uint32_t)((p)[3]) << 24)) + +#define U32TO8_LE(p, v) \ + do { \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); \ + } while (0) + +void +poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { + uint32_t t0,t1,t2,t3; + uint32_t h0,h1,h2,h3,h4; + uint32_t r0,r1,r2,r3,r4; + uint32_t s1,s2,s3,s4; + uint32_t b, nb; + size_t j; + uint64_t t[5]; + uint64_t f0,f1,f2,f3; + uint32_t g0,g1,g2,g3,g4; + uint64_t c; + unsigned char mp[16]; + + /* clamp key */ + t0 = U8TO32_LE(key+0); + t1 = U8TO32_LE(key+4); + t2 = U8TO32_LE(key+8); + t3 = U8TO32_LE(key+12); + + /* precompute multipliers */ + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; + r3 = t2 & 0x3f03fff; t3 >>= 8; + r4 = t3 & 0x00fffff; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + /* init state */ + h0 = 0; + h1 = 0; + h2 = 0; + h3 = 0; + h4 = 0; + + /* full blocks */ + if (inlen < 16) goto poly1305_donna_atmost15bytes; +poly1305_donna_16bytes: + m += 16; + inlen -= 16; + + t0 = U8TO32_LE(m-16); + t1 = U8TO32_LE(m-12); + t2 = U8TO32_LE(m-8); + t3 = U8TO32_LE(m-4); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8) | (1 << 24); + + +poly1305_donna_mul: + t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); + t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); + t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); + t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); + t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); + + h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26); + t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26); + t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26); + t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26); + t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26); + h0 += b * 5; + + if (inlen >= 16) goto poly1305_donna_16bytes; + + /* final bytes */ +poly1305_donna_atmost15bytes: + if (!inlen) goto poly1305_donna_finish; + + for (j = 0; j < inlen; j++) mp[j] = m[j]; + mp[j++] = 1; + for (; j < 16; j++) mp[j] = 0; + inlen = 0; + + t0 = U8TO32_LE(mp+0); + t1 = U8TO32_LE(mp+4); + t2 = U8TO32_LE(mp+8); + t3 = U8TO32_LE(mp+12); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8); + + goto poly1305_donna_mul; + +poly1305_donna_finish: + b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; + h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; + + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; + g4 = h4 + b - (1 << 26); + + b = (g4 >> 31) - 1; + nb = ~b; + h0 = (h0 & nb) | (g0 & b); + h1 = (h1 & nb) | (g1 & b); + h2 = (h2 & nb) | (g2 & b); + h3 = (h3 & nb) | (g3 & b); + h4 = (h4 & nb) | (g4 & b); + + f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); + + U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); + U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); + U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); + U32TO8_LE(&out[12], f3); +} diff --git a/poly1305.h b/poly1305.h new file mode 100644 index 000000000..a31fb7425 --- /dev/null +++ b/poly1305.h @@ -0,0 +1,22 @@ +/* $OpenBSD: poly1305.h,v 1.1 2013/11/21 00:45:44 djm Exp $ */ + +/* + * Public Domain poly1305 from Andrew M. + * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna + */ + +#ifndef POLY1305_H +#define POLY1305_H + +#include + +#define POLY1305_KEYLEN 32 +#define POLY1305_TAGLEN 16 + +void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen, + const u_char key[POLY1305_KEYLEN]) + __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) + __attribute__((__bounded__(__buffer__, 2, 3))) + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); + +#endif /* POLY1305_H */ diff --git a/servconf.c b/servconf.c index 3593223f7..cb21bd229 100644 --- a/servconf.c +++ b/servconf.c @@ -1,5 +1,5 @@ -/* $OpenBSD: servconf.c,v 1.245 2013/11/07 11:58:27 dtucker Exp $ */ +/* $OpenBSD: servconf.c,v 1.246 2013/11/21 00:45:44 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -2038,7 +2038,7 @@ dump_config(ServerOptions *o) dump_cfg_string(sPidFile, o->pid_file); dump_cfg_string(sXAuthLocation, o->xauth_location); dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : - cipher_alg_list(',')); + cipher_alg_list(',', 0)); dump_cfg_string(sMacs, o->macs ? o->macs : mac_alg_list(',')); dump_cfg_string(sBanner, o->banner); dump_cfg_string(sForceCommand, o->adm_forced_command); diff --git a/ssh.1 b/ssh.1 index 6369fc28b..73e208693 100644 --- a/ssh.1 +++ b/ssh.1 @@ -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: ssh.1,v 1.339 2013/10/16 22:49:38 djm Exp $ -.Dd $Mdocdate: October 16 2013 $ +.\" $OpenBSD: ssh.1,v 1.340 2013/11/21 00:45:44 djm Exp $ +.Dd $Mdocdate: November 21 2013 $ .Dt SSH 1 .Os .Sh NAME @@ -504,6 +504,8 @@ for the algorithms supported for the specified version 2 The queriable features are: .Dq cipher (supported symmetric ciphers), +.Dq cipher-auth +(supported symmetric ciphers that support authenticated encryption), .Dq MAC (supported message integrity codes), .Dq KEX diff --git a/ssh.c b/ssh.c index e2c43634a..58becd708 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.392 2013/11/07 11:58:27 dtucker Exp $ */ +/* $OpenBSD: ssh.c,v 1.393 2013/11/21 00:45:44 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -520,7 +520,9 @@ main(int ac, char **av) case 'Q': /* deprecated */ cp = NULL; if (strcasecmp(optarg, "cipher") == 0) - cp = cipher_alg_list('\n'); + cp = cipher_alg_list('\n', 0); + else if (strcasecmp(optarg, "cipher-auth") == 0) + cp = cipher_alg_list('\n', 1); else if (strcasecmp(optarg, "mac") == 0) cp = mac_alg_list('\n'); else if (strcasecmp(optarg, "kex") == 0) diff --git a/ssh_config.5 b/ssh_config.5 index 8809568a6..9dbc76ca9 100644 --- a/ssh_config.5 +++ b/ssh_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: ssh_config.5,v 1.179 2013/11/02 22:39:19 markus Exp $ -.Dd $Mdocdate: November 2 2013 $ +.\" $OpenBSD: ssh_config.5,v 1.180 2013/11/21 00:45:44 djm Exp $ +.Dd $Mdocdate: November 21 2013 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -334,7 +334,8 @@ The default is Specifies the ciphers allowed for protocol version 2 in order of preference. Multiple ciphers must be comma-separated. -The supported ciphers are +The supported ciphers are: +.Pp .Dq 3des-cbc , .Dq aes128-cbc , .Dq aes192-cbc , @@ -348,15 +349,24 @@ The supported ciphers are .Dq arcfour256 , .Dq arcfour , .Dq blowfish-cbc , +.Dq cast128-cbc , and -.Dq cast128-cbc . +.Dq chacha20-poly1305@openssh.com . +.Pp The default is: +.Pp .Bd -literal -offset 3n aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, aes128-gcm@openssh.com,aes256-gcm@openssh.com, +chacha20-poly1305@openssh.com, aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc, aes256-cbc,arcfour .Ed +.Pp +The list of available ciphers may also be obtained using the +.Fl Q +option of +.Xr ssh 1 . .It Cm ClearAllForwardings Specifies that all local, remote, and dynamic port forwardings specified in the configuration files or on the command line be diff --git a/sshd_config.5 b/sshd_config.5 index 02c45a7df..b9864fff2 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.166 2013/11/02 22:39:19 markus Exp $ -.Dd $Mdocdate: November 2 2013 $ +.\" $OpenBSD: sshd_config.5,v 1.167 2013/11/21 00:45:44 djm Exp $ +.Dd $Mdocdate: November 21 2013 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -335,7 +335,8 @@ The default is not to .It Cm Ciphers Specifies the ciphers allowed for protocol version 2. Multiple ciphers must be comma-separated. -The supported ciphers are +The supported ciphers are: +.Pp .Dq 3des-cbc , .Dq aes128-cbc , .Dq aes192-cbc , @@ -349,15 +350,24 @@ The supported ciphers are .Dq arcfour256 , .Dq arcfour , .Dq blowfish-cbc , +.Dq cast128-cbc , and -.Dq cast128-cbc . +.Dq chacha20-poly1305@openssh.com . +.Pp The default is: +.Pp .Bd -literal -offset 3n aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, aes128-gcm@openssh.com,aes256-gcm@openssh.com, +chacha20-poly1305@openssh.com, aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc, aes256-cbc,arcfour .Ed +.Pp +The list of available ciphers may also be obtained using the +.Fl Q +option of +.Xr ssh 1 . .It Cm ClientAliveCountMax Sets the number of client alive messages (see below) which may be sent without -- cgit v1.2.3 From d937dc084a087090f1cf5395822c3ac958d33759 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Thu, 5 Dec 2013 10:19:54 +1100 Subject: - deraadt@cvs.openbsd.org 2013/11/25 18:04:21 [ssh.1 ssh.c] improve -Q usage and such. One usage change is that the option is now case-sensitive ok dtucker markus djm --- ChangeLog | 5 +++++ ssh.1 | 24 +++++++++++------------- ssh.c | 20 ++++++++++---------- 3 files changed, 26 insertions(+), 23 deletions(-) (limited to 'ssh.1') diff --git a/ChangeLog b/ChangeLog index 9f2fb1017..71f5dfe34 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,11 @@ - jmc@cvs.openbsd.org 2013/11/21 08:05:09 [ssh_config.5 sshd_config.5] no need for .Pp before displays; + - deraadt@cvs.openbsd.org 2013/11/25 18:04:21 + [ssh.1 ssh.c] + improve -Q usage and such. One usage change is that the option is now + case-sensitive + ok dtucker markus djm 20131121 - (djm) OpenBSD CVS Sync diff --git a/ssh.1 b/ssh.1 index 73e208693..842affbd9 100644 --- a/ssh.1 +++ b/ssh.1 @@ -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: ssh.1,v 1.340 2013/11/21 00:45:44 djm Exp $ -.Dd $Mdocdate: November 21 2013 $ +.\" $OpenBSD: ssh.1,v 1.341 2013/11/25 18:04:21 deraadt Exp $ +.Dd $Mdocdate: November 25 2013 $ .Dt SSH 1 .Os .Sh NAME @@ -60,13 +60,13 @@ .Op Fl p Ar port .Op Fl R Oo Ar bind_address : Oc Ns Ar port : Ns Ar host : Ns Ar hostport .Op Fl S Ar ctl_path +.Op Fl Q Ar cipher | Ar cipher-auth | Ar mac | Ar kex | Ar key .Op Fl W Ar host : Ns Ar port .Op Fl w Ar local_tun Ns Op : Ns Ar remote_tun .Oo Ar user Ns @ Oc Ns Ar hostname .Op Ar command .Ek .Nm -.Fl Q Ar protocol_feature .Sh DESCRIPTION .Nm (SSH client) is a program for logging into a remote machine and for @@ -496,23 +496,21 @@ For full details of the options listed below, and their possible values, see Port to connect to on the remote host. This can be specified on a per-host basis in the configuration file. -.It Fl Q Ar protocol_feature +.It Fl Q Ar cipher | Ar cipher-auth | Ar mac | Ar kex | Ar key Queries .Nm -for the algorithms supported for the specified version 2 -.Ar protocol_feature . -The queriable features are: -.Dq cipher +for the algorithms supported for the specified version 2. +The available features are: +.Ar cipher (supported symmetric ciphers), -.Dq cipher-auth +.Ar cipher-auth (supported symmetric ciphers that support authenticated encryption), -.Dq MAC +.Ar mac (supported message integrity codes), -.Dq KEX +.Ar kex (key exchange algorithms), -.Dq key +.Ar key (key types). -Protocol features are treated case-insensitively. .It Fl q Quiet mode. Causes most warning and diagnostic messages to be suppressed. diff --git a/ssh.c b/ssh.c index 58becd708..ea5d6edc7 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.393 2013/11/21 00:45:44 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.394 2013/11/25 18:04:21 deraadt Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -199,9 +199,9 @@ usage(void) "usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" " [-D [bind_address:]port] [-E log_file] [-e escape_char]\n" " [-F configfile] [-I pkcs11] [-i identity_file]\n" -" [-L [bind_address:]port:host:hostport] [-Q protocol_feature]\n" -" [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" -" [-R [bind_address:]port:host:hostport] [-S ctl_path]\n" +" [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec]\n" +" [-O ctl_cmd] [-o option] [-p port] [-R [bind_address:]port:host:hostport]\n" +" [-S ctl_path] [-Q cipher | cipher-auth | mac | kex | key]\n" " [-W host:port] [-w local_tun[:remote_tun]]\n" " [user@]hostname [command]\n" ); @@ -517,17 +517,17 @@ main(int ac, char **av) case 'P': /* deprecated */ options.use_privileged_port = 0; break; - case 'Q': /* deprecated */ + case 'Q': cp = NULL; - if (strcasecmp(optarg, "cipher") == 0) + if (strcmp(optarg, "cipher") == 0) cp = cipher_alg_list('\n', 0); - else if (strcasecmp(optarg, "cipher-auth") == 0) + else if (strcmp(optarg, "cipher-auth") == 0) cp = cipher_alg_list('\n', 1); - else if (strcasecmp(optarg, "mac") == 0) + else if (strcmp(optarg, "mac") == 0) cp = mac_alg_list('\n'); - else if (strcasecmp(optarg, "kex") == 0) + else if (strcmp(optarg, "kex") == 0) cp = kex_alg_list('\n'); - else if (strcasecmp(optarg, "key") == 0) + else if (strcmp(optarg, "key") == 0) cp = key_alg_list(); if (cp == NULL) fatal("Unsupported query \"%s\"", optarg); -- cgit v1.2.3 From bdb352a54f82df94a548e3874b22f2d6ae90328d Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Thu, 5 Dec 2013 10:20:52 +1100 Subject: - jmc@cvs.openbsd.org 2013/11/26 12:14:54 [ssh.1 ssh.c] - put -Q in the right place - Ar was a poor choice for the arguments to -Q. i've chosen an admittedly equally poor Cm, at least consistent with the rest of the docs. also no need for multiple instances - zap a now redundant Nm - usage() sync --- ChangeLog | 8 ++++++++ ssh.1 | 9 ++++----- ssh.c | 10 +++++----- 3 files changed, 17 insertions(+), 10 deletions(-) (limited to 'ssh.1') diff --git a/ChangeLog b/ChangeLog index 71f5dfe34..f23acac18 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,14 @@ improve -Q usage and such. One usage change is that the option is now case-sensitive ok dtucker markus djm + - jmc@cvs.openbsd.org 2013/11/26 12:14:54 + [ssh.1 ssh.c] + - put -Q in the right place + - Ar was a poor choice for the arguments to -Q. i've chosen an + admittedly equally poor Cm, at least consistent with the rest + of the docs. also no need for multiple instances + - zap a now redundant Nm + - usage() sync 20131121 - (djm) OpenBSD CVS Sync diff --git a/ssh.1 b/ssh.1 index 842affbd9..fc56997f4 100644 --- a/ssh.1 +++ b/ssh.1 @@ -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: ssh.1,v 1.341 2013/11/25 18:04:21 deraadt Exp $ -.Dd $Mdocdate: November 25 2013 $ +.\" $OpenBSD: ssh.1,v 1.342 2013/11/26 12:14:54 jmc Exp $ +.Dd $Mdocdate: November 26 2013 $ .Dt SSH 1 .Os .Sh NAME @@ -58,15 +58,14 @@ .Op Fl O Ar ctl_cmd .Op Fl o Ar option .Op Fl p Ar port +.Op Fl Q Cm cipher | cipher-auth | mac | kex | key .Op Fl R Oo Ar bind_address : Oc Ns Ar port : Ns Ar host : Ns Ar hostport .Op Fl S Ar ctl_path -.Op Fl Q Ar cipher | Ar cipher-auth | Ar mac | Ar kex | Ar key .Op Fl W Ar host : Ns Ar port .Op Fl w Ar local_tun Ns Op : Ns Ar remote_tun .Oo Ar user Ns @ Oc Ns Ar hostname .Op Ar command .Ek -.Nm .Sh DESCRIPTION .Nm (SSH client) is a program for logging into a remote machine and for @@ -496,7 +495,7 @@ For full details of the options listed below, and their possible values, see Port to connect to on the remote host. This can be specified on a per-host basis in the configuration file. -.It Fl Q Ar cipher | Ar cipher-auth | Ar mac | Ar kex | Ar key +.It Fl Q Cm cipher | cipher-auth | mac | kex | key Queries .Nm for the algorithms supported for the specified version 2. diff --git a/ssh.c b/ssh.c index ea5d6edc7..6c8cd7317 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.394 2013/11/25 18:04:21 deraadt Exp $ */ +/* $OpenBSD: ssh.c,v 1.395 2013/11/26 12:14:54 jmc Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -200,10 +200,10 @@ usage(void) " [-D [bind_address:]port] [-E log_file] [-e escape_char]\n" " [-F configfile] [-I pkcs11] [-i identity_file]\n" " [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec]\n" -" [-O ctl_cmd] [-o option] [-p port] [-R [bind_address:]port:host:hostport]\n" -" [-S ctl_path] [-Q cipher | cipher-auth | mac | kex | key]\n" -" [-W host:port] [-w local_tun[:remote_tun]]\n" -" [user@]hostname [command]\n" +" [-O ctl_cmd] [-o option] [-p port]\n" +" [-Q cipher | cipher-auth | mac | kex | key]\n" +" [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port]\n" +" [-w local_tun[:remote_tun]] [user@]hostname [command]\n" ); exit(255); } -- cgit v1.2.3 From 8ba0ead6985ea14999265136b14ffd5aeec516f9 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 18 Dec 2013 17:46:27 +1100 Subject: - naddy@cvs.openbsd.org 2013/12/07 11:58:46 [ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh-keysign.8 ssh.1] [ssh_config.5 sshd.8 sshd_config.5] add missing mentions of ed25519; ok djm@ --- ChangeLog | 4 ++++ ssh-add.1 | 9 ++++++--- ssh-agent.1 | 11 +++++++---- ssh-keygen.1 | 26 ++++++++++++++++++-------- ssh-keyscan.1 | 7 ++++--- ssh-keysign.8 | 6 ++++-- ssh.1 | 20 ++++++++++++++------ ssh_config.5 | 10 ++++++---- sshd.8 | 16 ++++++++++------ sshd_config.5 | 10 ++++++---- 10 files changed, 79 insertions(+), 40 deletions(-) (limited to 'ssh.1') diff --git a/ChangeLog b/ChangeLog index 351bd0386..c162b7f5c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ - djm@cvs.openbsd.org 2013/12/07 08:08:26 [ssh-keygen.1] document -a and -o wrt new key format + - naddy@cvs.openbsd.org 2013/12/07 11:58:46 + [ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh-keysign.8 ssh.1] + [ssh_config.5 sshd.8 sshd_config.5] + add missing mentions of ed25519; ok djm@ 20131208 - (djm) [openbsd-compat/bsd-setres_id.c] Missing header; from Corinna diff --git a/ssh-add.1 b/ssh-add.1 index 44846b67e..4812448fa 100644 --- a/ssh-add.1 +++ b/ssh-add.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-add.1,v 1.58 2012/12/03 08:33:02 jmc Exp $ +.\" $OpenBSD: ssh-add.1,v 1.59 2013/12/07 11:58:46 naddy Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , 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: December 3 2012 $ +.Dd $Mdocdate: December 7 2013 $ .Dt SSH-ADD 1 .Os .Sh NAME @@ -57,7 +57,8 @@ adds private key identities to the authentication agent, When run without arguments, it adds the files .Pa ~/.ssh/id_rsa , .Pa ~/.ssh/id_dsa , -.Pa ~/.ssh/id_ecdsa +.Pa ~/.ssh/id_ecdsa , +.Pa ~/.ssh/id_ed25519 and .Pa ~/.ssh/identity . After loading a private key, @@ -169,6 +170,8 @@ Contains the protocol version 1 RSA authentication identity of the user. Contains the protocol version 2 DSA authentication identity of the user. .It Pa ~/.ssh/id_ecdsa Contains the protocol version 2 ECDSA authentication identity of the user. +.It Pa ~/.ssh/id_ed25519 +Contains the protocol version 2 ED25519 authentication identity of the user. .It Pa ~/.ssh/id_rsa Contains the protocol version 2 RSA authentication identity of the user. .El diff --git a/ssh-agent.1 b/ssh-agent.1 index bb801c902..281ecbdcf 100644 --- a/ssh-agent.1 +++ b/ssh-agent.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-agent.1,v 1.53 2010/11/21 01:01:13 djm Exp $ +.\" $OpenBSD: ssh-agent.1,v 1.54 2013/12/07 11:58:46 naddy Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -34,7 +34,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: November 21 2010 $ +.Dd $Mdocdate: December 7 2013 $ .Dt SSH-AGENT 1 .Os .Sh NAME @@ -53,7 +53,7 @@ .Sh DESCRIPTION .Nm is a program to hold private keys used for public key authentication -(RSA, DSA, ECDSA). +(RSA, DSA, ECDSA, ED25519). The idea is that .Nm is started in the beginning of an X-session or a login session, and @@ -115,7 +115,8 @@ When executed without arguments, adds the files .Pa ~/.ssh/id_rsa , .Pa ~/.ssh/id_dsa , -.Pa ~/.ssh/id_ecdsa +.Pa ~/.ssh/id_ecdsa , +.Pa ~/.ssh/id_ed25519 and .Pa ~/.ssh/identity . If the identity has a passphrase, @@ -190,6 +191,8 @@ Contains the protocol version 1 RSA authentication identity of the user. Contains the protocol version 2 DSA authentication identity of the user. .It Pa ~/.ssh/id_ecdsa Contains the protocol version 2 ECDSA authentication identity of the user. +.It Pa ~/.ssh/id_ed25519 +Contains the protocol version 2 ED25519 authentication identity of the user. .It Pa ~/.ssh/id_rsa Contains the protocol version 2 RSA authentication identity of the user. .It Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt diff --git a/ssh-keygen.1 b/ssh-keygen.1 index 689db22ff..09e401bf8 100644 --- a/ssh-keygen.1 +++ b/ssh-keygen.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keygen.1,v 1.117 2013/12/07 08:08:26 djm Exp $ +.\" $OpenBSD: ssh-keygen.1,v 1.118 2013/12/07 11:58:46 naddy Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -139,8 +139,8 @@ generates, manages and converts authentication keys for .Xr ssh 1 . .Nm -can create RSA keys for use by SSH protocol version 1 and DSA, ECDSA or RSA -keys for use by SSH protocol version 2. +can create RSA keys for use by SSH protocol version 1 and +DSA, ECDSA, ED25519 or RSA keys for use by SSH protocol version 2. The type of key to be generated is specified with the .Fl t option. @@ -167,8 +167,9 @@ Normally each user wishing to use SSH with public key authentication runs this once to create the authentication key in .Pa ~/.ssh/identity , +.Pa ~/.ssh/id_dsa , .Pa ~/.ssh/id_ecdsa , -.Pa ~/.ssh/id_dsa +.Pa ~/.ssh/id_ed25519 or .Pa ~/.ssh/id_rsa . Additionally, the system administrator may use this to generate host keys, @@ -216,7 +217,8 @@ should be placed to be activated. The options are as follows: .Bl -tag -width Ds .It Fl A -For each of the key types (rsa1, rsa, dsa and ecdsa) for which host keys +For each of the key types (rsa1, rsa, dsa, ecdsa and ed25519) +for which host keys do not exist, generate the host keys with the default key file path, an empty passphrase, default bits for the key type, and default comment. This is used by @@ -249,6 +251,9 @@ flag determines the key length by selecting from one of three elliptic curve sizes: 256, 384 or 521 bits. Attempting to use bit lengths other than these three values for ECDSA keys will fail. +ED25519 keys have a fixed length and the +.Fl b +flag will be ignored. .It Fl C Ar comment Provides a new comment. .It Fl c @@ -515,7 +520,8 @@ The possible values are .Dq rsa1 for protocol version 1 and .Dq dsa , -.Dq ecdsa +.Dq ecdsa , +.Dq ed25519 , or .Dq rsa for protocol version 2. @@ -795,8 +801,10 @@ There is no need to keep the contents of this file secret. .Pp .It Pa ~/.ssh/id_dsa .It Pa ~/.ssh/id_ecdsa +.It Pa ~/.ssh/id_ed25519 .It Pa ~/.ssh/id_rsa -Contains the protocol version 2 DSA, ECDSA or RSA authentication identity of the user. +Contains the protocol version 2 DSA, ECDSA, ED25519 or RSA +authentication identity of the user. This file should not be readable by anyone but the user. It is possible to specify a passphrase when generating the key; that passphrase will be @@ -809,8 +817,10 @@ will read this file when a login attempt is made. .Pp .It Pa ~/.ssh/id_dsa.pub .It Pa ~/.ssh/id_ecdsa.pub +.It Pa ~/.ssh/id_ed25519.pub .It Pa ~/.ssh/id_rsa.pub -Contains the protocol version 2 DSA, ECDSA or RSA public key for authentication. +Contains the protocol version 2 DSA, ECDSA, ED25519 or RSA +public key for authentication. The contents of this file should be added to .Pa ~/.ssh/authorized_keys on all machines diff --git a/ssh-keyscan.1 b/ssh-keyscan.1 index 79dd6aa1c..65ef43efd 100644 --- a/ssh-keyscan.1 +++ b/ssh-keyscan.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keyscan.1,v 1.32 2013/12/06 13:39:49 markus Exp $ +.\" $OpenBSD: ssh-keyscan.1,v 1.33 2013/12/07 11:58:46 naddy Exp $ .\" .\" Copyright 1995, 1996 by David Mazieres . .\" @@ -6,7 +6,7 @@ .\" permitted provided that due credit is given to the author and the .\" OpenBSD project by leaving this copyright notice intact. .\" -.Dd $Mdocdate: December 6 2013 $ +.Dd $Mdocdate: December 7 2013 $ .Dt SSH-KEYSCAN 1 .Os .Sh NAME @@ -89,7 +89,8 @@ The possible values are .Dq rsa1 for protocol version 1 and .Dq dsa , -.Dq ecdsa +.Dq ecdsa , +.Dq ed25519 , or .Dq rsa for protocol version 2. diff --git a/ssh-keysign.8 b/ssh-keysign.8 index 5e0b2d232..69d082954 100644 --- a/ssh-keysign.8 +++ b/ssh-keysign.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keysign.8,v 1.13 2013/07/16 00:07:52 schwarze Exp $ +.\" $OpenBSD: ssh-keysign.8,v 1.14 2013/12/07 11:58:46 naddy Exp $ .\" .\" Copyright (c) 2002 Markus Friedl. All rights reserved. .\" @@ -22,7 +22,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: July 16 2013 $ +.Dd $Mdocdate: December 7 2013 $ .Dt SSH-KEYSIGN 8 .Os .Sh NAME @@ -63,6 +63,7 @@ is enabled. .Pp .It Pa /etc/ssh/ssh_host_dsa_key .It Pa /etc/ssh/ssh_host_ecdsa_key +.It Pa /etc/ssh/ssh_host_ed25519_key .It Pa /etc/ssh/ssh_host_rsa_key These files contain the private parts of the host keys used to generate the digital signature. @@ -74,6 +75,7 @@ must be set-uid root if host-based authentication is used. .Pp .It Pa /etc/ssh/ssh_host_dsa_key-cert.pub .It Pa /etc/ssh/ssh_host_ecdsa_key-cert.pub +.It Pa /etc/ssh/ssh_host_ed25519_key-cert.pub .It Pa /etc/ssh/ssh_host_rsa_key-cert.pub If these files exist they are assumed to contain public certificate information corresponding with the private keys above. diff --git a/ssh.1 b/ssh.1 index fc56997f4..27794e2d0 100644 --- a/ssh.1 +++ b/ssh.1 @@ -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: ssh.1,v 1.342 2013/11/26 12:14:54 jmc Exp $ -.Dd $Mdocdate: November 26 2013 $ +.\" $OpenBSD: ssh.1,v 1.343 2013/12/07 11:58:46 naddy Exp $ +.Dd $Mdocdate: December 7 2013 $ .Dt SSH 1 .Os .Sh NAME @@ -279,7 +279,8 @@ The default is .Pa ~/.ssh/identity for protocol version 1, and .Pa ~/.ssh/id_dsa , -.Pa ~/.ssh/id_ecdsa +.Pa ~/.ssh/id_ecdsa , +.Pa ~/.ssh/id_ed25519 and .Pa ~/.ssh/id_rsa for protocol version 2. @@ -757,7 +758,7 @@ key pair for authentication purposes. The server knows the public key, and only the user knows the private key. .Nm implements public key authentication protocol automatically, -using one of the DSA, ECDSA or RSA algorithms. +using one of the DSA, ECDSA, ED25519 or RSA algorithms. Protocol 1 is restricted to using only RSA keys, but protocol 2 may use any. The HISTORY section of @@ -784,6 +785,8 @@ This stores the private key in (protocol 2 DSA), .Pa ~/.ssh/id_ecdsa (protocol 2 ECDSA), +.Pa ~/.ssh/id_ed25519 +(protocol 2 ED25519), or .Pa ~/.ssh/id_rsa (protocol 2 RSA) @@ -794,6 +797,8 @@ and stores the public key in (protocol 2 DSA), .Pa ~/.ssh/id_ecdsa.pub (protocol 2 ECDSA), +.Pa ~/.ssh/id_ed25519.pub +(protocol 2 ED25519), or .Pa ~/.ssh/id_rsa.pub (protocol 2 RSA) @@ -1333,8 +1338,8 @@ secret, but the recommended permissions are read/write/execute for the user, and not accessible by others. .Pp .It Pa ~/.ssh/authorized_keys -Lists the public keys (DSA/ECDSA/RSA) that can be used for logging in as -this user. +Lists the public keys (DSA, ECDSA, ED25519, RSA) +that can be used for logging in as this user. The format of this file is described in the .Xr sshd 8 manual page. @@ -1356,6 +1361,7 @@ above. .It Pa ~/.ssh/identity .It Pa ~/.ssh/id_dsa .It Pa ~/.ssh/id_ecdsa +.It Pa ~/.ssh/id_ed25519 .It Pa ~/.ssh/id_rsa Contains the private key for authentication. These files @@ -1370,6 +1376,7 @@ sensitive part of this file using 3DES. .It Pa ~/.ssh/identity.pub .It Pa ~/.ssh/id_dsa.pub .It Pa ~/.ssh/id_ecdsa.pub +.It Pa ~/.ssh/id_ed25519.pub .It Pa ~/.ssh/id_rsa.pub Contains the public key for authentication. These files are not @@ -1409,6 +1416,7 @@ The file format and configuration options are described in .It Pa /etc/ssh/ssh_host_key .It Pa /etc/ssh/ssh_host_dsa_key .It Pa /etc/ssh/ssh_host_ecdsa_key +.It Pa /etc/ssh/ssh_host_ed25519_key .It Pa /etc/ssh/ssh_host_rsa_key These files contain the private parts of the host keys and are used for host-based authentication. diff --git a/ssh_config.5 b/ssh_config.5 index 43455342a..7b2fdacbb 100644 --- a/ssh_config.5 +++ b/ssh_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: ssh_config.5,v 1.182 2013/12/06 13:39:49 markus Exp $ -.Dd $Mdocdate: December 6 2013 $ +.\" $OpenBSD: ssh_config.5,v 1.183 2013/12/07 11:58:46 naddy Exp $ +.Dd $Mdocdate: December 7 2013 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -718,6 +718,7 @@ The default for this option is: ecdsa-sha2-nistp256-cert-v01@openssh.com, ecdsa-sha2-nistp384-cert-v01@openssh.com, ecdsa-sha2-nistp521-cert-v01@openssh.com, +ssh-ed25519-cert-v01@openssh.com, ssh-rsa-cert-v01@openssh.com,ssh-dss-cert-v01@openssh.com, ssh-rsa-cert-v00@openssh.com,ssh-dss-cert-v00@openssh.com, ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, @@ -763,13 +764,14 @@ offers many different identities. The default is .Dq no . .It Cm IdentityFile -Specifies a file from which the user's DSA, ECDSA or RSA authentication +Specifies a file from which the user's DSA, ECDSA, ED25519 or RSA authentication identity is read. The default is .Pa ~/.ssh/identity for protocol version 1, and .Pa ~/.ssh/id_dsa , -.Pa ~/.ssh/id_ecdsa +.Pa ~/.ssh/id_ecdsa , +.Pa ~/.ssh/id_ed25519 and .Pa ~/.ssh/id_rsa for protocol version 2. diff --git a/sshd.8 b/sshd.8 index 62615bf6d..e6a900b06 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.272 2013/12/06 15:29:07 jmc Exp $ -.Dd $Mdocdate: December 6 2013 $ +.\" $OpenBSD: sshd.8,v 1.273 2013/12/07 11:58:46 naddy Exp $ +.Dd $Mdocdate: December 7 2013 $ .Dt SSHD 8 .Os .Sh NAME @@ -175,7 +175,8 @@ The default is .Pa /etc/ssh/ssh_host_key for protocol version 1, and .Pa /etc/ssh/ssh_host_dsa_key , -.Pa /etc/ssh/ssh_host_ecdsa_key +.Pa /etc/ssh/ssh_host_ecdsa_key . +.Pa /etc/ssh/ssh_host_ed25519_key and .Pa /etc/ssh/ssh_host_rsa_key for protocol version 2. @@ -280,7 +281,7 @@ though this can be changed via the .Cm Protocol option in .Xr sshd_config 5 . -Protocol 2 supports DSA, ECDSA and RSA keys; +Protocol 2 supports DSA, ECDSA, ED25519 and RSA keys; protocol 1 only supports RSA keys. For both protocols, each host has a host-specific key, @@ -507,6 +508,7 @@ You don't want to type them in; instead, copy the .Pa identity.pub , .Pa id_dsa.pub , .Pa id_ecdsa.pub , +.Pa id_ed25519.pub , or the .Pa id_rsa.pub file and edit it. @@ -806,8 +808,8 @@ secret, but the recommended permissions are read/write/execute for the user, and not accessible by others. .Pp .It Pa ~/.ssh/authorized_keys -Lists the public keys (DSA/ECDSA/RSA) that can be used for logging in -as this user. +Lists the public keys (DSA, ECDSA, ED25519, RSA) +that can be used for logging in as this user. The format of this file is described above. The content of the file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others. @@ -887,6 +889,7 @@ rlogin/rsh. .It Pa /etc/ssh/ssh_host_key .It Pa /etc/ssh/ssh_host_dsa_key .It Pa /etc/ssh/ssh_host_ecdsa_key +.It Pa /etc/ssh/ssh_host_ed25519_key .It Pa /etc/ssh/ssh_host_rsa_key These files contain the private parts of the host keys. These files should only be owned by root, readable only by root, and not @@ -898,6 +901,7 @@ does not start if these files are group/world-accessible. .It Pa /etc/ssh/ssh_host_key.pub .It Pa /etc/ssh/ssh_host_dsa_key.pub .It Pa /etc/ssh/ssh_host_ecdsa_key.pub +.It Pa /etc/ssh/ssh_host_ed25519_key.pub .It Pa /etc/ssh/ssh_host_rsa_key.pub These files contain the public parts of the host keys. These files should be world-readable but writable only by diff --git a/sshd_config.5 b/sshd_config.5 index 0418c86ed..0ae1740bb 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.168 2013/11/21 08:05:09 jmc Exp $ -.Dd $Mdocdate: November 21 2013 $ +.\" $OpenBSD: sshd_config.5,v 1.169 2013/12/07 11:58:46 naddy Exp $ +.Dd $Mdocdate: December 7 2013 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -540,7 +540,8 @@ The default is .Pa /etc/ssh/ssh_host_key for protocol version 1, and .Pa /etc/ssh/ssh_host_dsa_key , -.Pa /etc/ssh/ssh_host_ecdsa_key +.Pa /etc/ssh/ssh_host_ecdsa_key , +.Pa /etc/ssh/ssh_host_ed25519_key and .Pa /etc/ssh/ssh_host_rsa_key for protocol version 2. @@ -551,7 +552,8 @@ It is possible to have multiple host key files. .Dq rsa1 keys are used for version 1 and .Dq dsa , -.Dq ecdsa +.Dq ecdsa , +.Dq ed25519 or .Dq rsa are used for version 2 of the SSH protocol. -- cgit v1.2.3