upstream: move client/server SSH-* banners to buffers under

ssh->kex and factor out the banner exchange. This eliminates some common code
from the client and server.

Also be more strict about handling \r characters - these should only
be accepted immediately before \n (pointed out by Jann Horn).

Inspired by a patch from Markus Schmidt.
(lots of) feedback and ok markus@

OpenBSD-Commit-ID: 1cc7885487a6754f63641d7d3279b0941890275b
This commit is contained in:
djm@openbsd.org 2018-12-27 03:25:24 +00:00 committed by Damien Miller
parent 434b587afe
commit 0a843d9a0e
27 changed files with 548 additions and 494 deletions

View File

@ -60,8 +60,8 @@ gss-serv.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-comp
hash.o: crypto_api.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h digest.h log.h ssherr.h
hmac.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshbuf.h digest.h hmac.h
hostfile.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h match.h sshkey.h hostfile.h log.h misc.h ssherr.h digest.h hmac.h
kex.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h kex.h mac.h log.h match.h misc.h monitor.h ssherr.h sshbuf.h
kex.o: digest.h
kex.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh.h ssh2.h atomicio.h version.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h kex.h mac.h log.h match.h misc.h
kex.o: monitor.h ssherr.h sshbuf.h digest.h
kexc25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshbuf.h ssh2.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h kex.h mac.h log.h digest.h ssherr.h
kexc25519c.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h kex.h mac.h log.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h ssh2.h sshbuf.h digest.h ssherr.h
kexc25519s.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h kex.h mac.h log.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h ssh2.h sshbuf.h ssherr.h
@ -149,7 +149,7 @@ sshbuf-getput-crypto.o: includes.h config.h defines.h platform.h openbsd-compat/
sshbuf-misc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssherr.h sshbuf.h
sshbuf.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssherr.h sshbuf.h misc.h
sshconnect.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h hostfile.h ssh.h sshbuf.h packet.h openbsd-compat/sys-queue.h dispatch.h opacket.h compat.h sshkey.h sshconnect.h log.h misc.h readconf.h atomicio.h dns.h monitor_fdpass.h ssh2.h version.h authfile.h
sshconnect.o: ssherr.h authfd.h
sshconnect.o: ssherr.h authfd.h kex.h mac.h
sshconnect2.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshbuf.h packet.h dispatch.h opacket.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h kex.h mac.h myproposal.h
sshconnect2.o: sshconnect.h authfile.h dh.h authfd.h log.h misc.h readconf.h match.h canohost.h msg.h pathnames.h uidswap.h hostfile.h ssherr.h utf8.h
sshd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/rmd160.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h opacket.h log.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h chacha.h

View File

@ -186,7 +186,7 @@ ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o
ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o readconf.o uidswap.o
ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o readconf.o uidswap.o compat.o
$(LD) -o $@ ssh-keysign.o readconf.o uidswap.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o

View File

@ -1,4 +1,4 @@
/* $OpenBSD: atomicio.h,v 1.11 2010/09/22 22:58:51 djm Exp $ */
/* $OpenBSD: atomicio.h,v 1.12 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2006 Damien Miller. All rights reserved.
@ -29,6 +29,8 @@
#ifndef _ATOMICIO_H
#define _ATOMICIO_H
struct iovec;
/*
* Ensure all of data on socket comes through. f==read || f==vwrite
*/

294
kex.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.c,v 1.142 2018/12/07 03:39:40 djm Exp $ */
/* $OpenBSD: kex.c,v 1.143 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
@ -25,19 +25,25 @@
#include "includes.h"
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#ifdef WITH_OPENSSL
#include <openssl/crypto.h>
#include <openssl/dh.h>
#endif
#include "ssh.h"
#include "ssh2.h"
#include "atomicio.h"
#include "version.h"
#include "packet.h"
#include "compat.h"
#include "cipher.h"
@ -578,32 +584,20 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
return SSH_ERR_INTERNAL_ERROR;
}
int
kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp)
struct kex *
kex_new(void)
{
struct kex *kex;
int r;
*kexp = NULL;
if ((kex = calloc(1, sizeof(*kex))) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((kex->peer = sshbuf_new()) == NULL ||
(kex->my = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = kex_prop2buf(kex->my, proposal)) != 0)
goto out;
kex->done = 0;
kex->flags = KEX_INITIAL;
kex_reset_dispatch(ssh);
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
r = 0;
*kexp = kex;
out:
if (r != 0)
if ((kex = calloc(1, sizeof(*kex))) == NULL ||
(kex->peer = sshbuf_new()) == NULL ||
(kex->my = sshbuf_new()) == NULL ||
(kex->client_version = sshbuf_new()) == NULL ||
(kex->server_version = sshbuf_new()) == NULL) {
kex_free(kex);
return r;
return NULL;
}
return kex;
}
void
@ -642,6 +636,9 @@ kex_free(struct kex *kex)
{
u_int mode;
if (kex == NULL)
return;
#ifdef WITH_OPENSSL
DH_free(kex->dh);
#ifdef OPENSSL_HAS_ECC
@ -654,21 +651,34 @@ kex_free(struct kex *kex)
}
sshbuf_free(kex->peer);
sshbuf_free(kex->my);
sshbuf_free(kex->client_version);
sshbuf_free(kex->server_version);
free(kex->session_id);
free(kex->client_version_string);
free(kex->server_version_string);
free(kex->failed_choice);
free(kex->hostkey_alg);
free(kex->name);
free(kex);
}
int
kex_ready(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
{
int r;
if ((r = kex_prop2buf(ssh->kex->my, proposal)) != 0)
return r;
ssh->kex->flags = KEX_INITIAL;
kex_reset_dispatch(ssh);
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
return 0;
}
int
kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
{
int r;
if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0)
if ((r = kex_ready(ssh, proposal)) != 0)
return r;
if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */
kex_free(ssh->kex);
@ -1043,3 +1053,233 @@ dump_digest(char *msg, u_char *digest, int len)
sshbuf_dump_data(digest, len, stderr);
}
#endif
/*
* Send a plaintext error message to the peer, suffixed by \r\n.
* Only used during banner exchange, and there only for the server.
*/
static void
send_error(struct ssh *ssh, char *msg)
{
char *crnl = "\r\n";
if (!ssh->kex->server)
return;
if (atomicio(vwrite, ssh_packet_get_connection_out(ssh),
msg, strlen(msg)) != strlen(msg) ||
atomicio(vwrite, ssh_packet_get_connection_out(ssh),
crnl, strlen(crnl)) != strlen(crnl))
error("%s: write: %.100s", __func__, strerror(errno));
}
/*
* Sends our identification string and waits for the peer's. Will block for
* up to timeout_ms (or indefinitely if timeout_ms <= 0).
* Returns on 0 success or a ssherr.h code on failure.
*/
int
kex_exchange_identification(struct ssh *ssh, int timeout_ms,
const char *version_addendum)
{
int remote_major, remote_minor, mismatch;
size_t len, i, n;
int r, expect_nl;
u_char c;
struct sshbuf *our_version = ssh->kex->server ?
ssh->kex->server_version : ssh->kex->client_version;
struct sshbuf *peer_version = ssh->kex->server ?
ssh->kex->client_version : ssh->kex->server_version;
char *our_version_string = NULL, *peer_version_string = NULL;
char *cp, *remote_version = NULL;
/* Prepare and send our banner */
sshbuf_reset(our_version);
if (version_addendum != NULL && *version_addendum == '\0')
version_addendum = NULL;
if ((r = sshbuf_putf(our_version, "SSH-%d.%d-%.100s%s%s\r\n",
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION,
version_addendum == NULL ? "" : " ",
version_addendum == NULL ? "" : version_addendum)) != 0) {
error("%s: sshbuf_putf: %s", __func__, ssh_err(r));
goto out;
}
if (atomicio(vwrite, ssh_packet_get_connection_out(ssh),
sshbuf_mutable_ptr(our_version),
sshbuf_len(our_version)) != sshbuf_len(our_version)) {
error("%s: write: %.100s", __func__, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto out;
}
if ((r = sshbuf_consume_end(our_version, 2)) != 0) { /* trim \r\n */
error("%s: sshbuf_consume_end: %s", __func__, ssh_err(r));
goto out;
}
our_version_string = sshbuf_dup_string(our_version);
if (our_version_string == NULL) {
error("%s: sshbuf_dup_string failed", __func__);
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
debug("Local version string %.100s", our_version_string);
/* Read other side's version identification. */
for (n = 0; ; n++) {
if (n >= SSH_MAX_PRE_BANNER_LINES) {
send_error(ssh, "No SSH identification string "
"received.");
error("%s: No SSH version received in first %u lines "
"from server", __func__, SSH_MAX_PRE_BANNER_LINES);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
sshbuf_reset(peer_version);
expect_nl = 0;
for (i = 0; ; i++) {
if (timeout_ms > 0) {
r = waitrfd(ssh_packet_get_connection_in(ssh),
&timeout_ms);
if (r == -1 && errno == ETIMEDOUT) {
send_error(ssh, "Timed out waiting "
"for SSH identification string.");
error("Connection timed out during "
"banner exchange");
r = SSH_ERR_CONN_TIMEOUT;
goto out;
} else if (r == -1) {
error("%s: %s",
__func__, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto out;
}
}
len = atomicio(read, ssh_packet_get_connection_in(ssh),
&c, 1);
if (len != 1 && errno == EPIPE) {
error("%s: Connection closed by remote host",
__func__);
r = SSH_ERR_CONN_CLOSED;
goto out;
} else if (len != 1) {
error("%s: read: %.100s",
__func__, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto out;
}
if (c == '\r') {
expect_nl = 1;
continue;
}
if (c == '\n')
break;
if (c == '\0' || expect_nl) {
error("%s: banner line contains invalid "
"characters", __func__);
goto invalid;
}
if ((r = sshbuf_put_u8(peer_version, c)) != 0) {
error("%s: sshbuf_put: %s",
__func__, ssh_err(r));
goto out;
}
if (sshbuf_len(peer_version) > SSH_MAX_BANNER_LEN) {
error("%s: banner line too long", __func__);
goto invalid;
}
}
/* Is this an actual protocol banner? */
if (sshbuf_len(peer_version) > 4 &&
memcmp(sshbuf_ptr(peer_version), "SSH-", 4) == 0)
break;
/* If not, then just log the line and continue */
if ((cp = sshbuf_dup_string(peer_version)) == NULL) {
error("%s: sshbuf_dup_string failed", __func__);
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* Do not accept lines before the SSH ident from a client */
if (ssh->kex->server) {
error("%s: client sent invalid protocol identifier "
"\"%.256s\"", __func__, cp);
free(cp);
goto invalid;
}
debug("%s: banner line %zu: %s", __func__, n, cp);
free(cp);
}
peer_version_string = sshbuf_dup_string(peer_version);
if (peer_version_string == NULL)
error("%s: sshbuf_dup_string failed", __func__);
/* XXX must be same size for sscanf */
if ((remote_version = calloc(1, sshbuf_len(peer_version))) == NULL) {
error("%s: calloc failed", __func__);
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/*
* Check that the versions match. In future this might accept
* several versions and set appropriate flags to handle them.
*/
if (sscanf(peer_version_string, "SSH-%d.%d-%[^\n]\n",
&remote_major, &remote_minor, remote_version) != 3) {
error("Bad remote protocol version identification: '%.100s'",
peer_version_string);
invalid:
send_error(ssh, "Invalid SSH identification string.");
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
debug("Remote protocol version %d.%d, remote software version %.100s",
remote_major, remote_minor, remote_version);
ssh->compat = compat_datafellows(remote_version);
mismatch = 0;
switch (remote_major) {
case 2:
break;
case 1:
if (remote_minor != 99)
mismatch = 1;
break;
default:
mismatch = 1;
break;
}
if (mismatch) {
error("Protocol major versions differ: %d vs. %d",
PROTOCOL_MAJOR_2, remote_major);
send_error(ssh, "Protocol major versions differ.");
r = SSH_ERR_NO_PROTOCOL_VERSION;
goto out;
}
if (ssh->kex->server && (ssh->compat & SSH_BUG_PROBE) != 0) {
logit("probed from %s port %d with %s. Don't panic.",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
peer_version_string);
r = SSH_ERR_CONN_CLOSED; /* XXX */
goto out;
}
if (ssh->kex->server && (ssh->compat & SSH_BUG_SCANNER) != 0) {
logit("scanned from %s port %d with %s. Don't panic.",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
peer_version_string);
r = SSH_ERR_CONN_CLOSED; /* XXX */
goto out;
}
if ((ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
logit("Remote version \"%.100s\" uses unsafe RSA signature "
"scheme; disabling use of RSA keys", remote_version);
}
/* success */
r = 0;
out:
free(our_version_string);
free(peer_version_string);
free(remote_version);
return r;
}

20
kex.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.h,v 1.92 2018/12/07 03:39:40 djm Exp $ */
/* $OpenBSD: kex.h,v 1.93 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -145,12 +145,12 @@ struct kex {
int ext_info_c;
struct sshbuf *my;
struct sshbuf *peer;
struct sshbuf *client_version;
struct sshbuf *server_version;
sig_atomic_t done;
u_int flags;
int hash_alg;
int ec_nid;
char *client_version_string;
char *server_version_string;
char *failed_choice;
int (*verify_host_key)(struct sshkey *, struct ssh *);
struct sshkey *(*load_host_public_key)(int, int, struct ssh *);
@ -173,7 +173,10 @@ char *kex_alg_list(char);
char *kex_names_cat(const char *, const char *);
int kex_assemble_names(char **, const char *, const char *);
int kex_new(struct ssh *, char *[PROPOSAL_MAX], struct kex **);
int kex_exchange_identification(struct ssh *, int, const char *);
struct kex *kex_new(void);
int kex_ready(struct ssh *, char *[PROPOSAL_MAX]);
int kex_setup(struct ssh *, char *[PROPOSAL_MAX]);
void kex_free_newkeys(struct newkeys *);
void kex_free(struct kex *);
@ -199,22 +202,23 @@ int kexecdh_server(struct ssh *);
int kexc25519_client(struct ssh *);
int kexc25519_server(struct ssh *);
int kex_dh_hash(int, const char *, const char *,
int kex_dh_hash(int, const struct sshbuf *, const struct sshbuf *,
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
const BIGNUM *, const BIGNUM *, const BIGNUM *, u_char *, size_t *);
int kexgex_hash(int, const char *, const char *,
int kexgex_hash(int, const struct sshbuf *, const struct sshbuf *,
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
int, int, int,
const BIGNUM *, const BIGNUM *, const BIGNUM *,
const BIGNUM *, const BIGNUM *,
u_char *, size_t *);
int kex_ecdh_hash(int, const EC_GROUP *, const char *, const char *,
int kex_ecdh_hash(int, const EC_GROUP *,
const struct sshbuf *, const struct sshbuf *,
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
const EC_POINT *, const EC_POINT *, const BIGNUM *, u_char *, size_t *);
int kex_c25519_hash(int, const char *, const char *,
int kex_c25519_hash(int, const struct sshbuf *, const struct sshbuf *,
const u_char *, size_t, const u_char *, size_t,
const u_char *, size_t, const u_char *, const u_char *,
const u_char *, size_t, u_char *, size_t *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexc25519.c,v 1.10 2016/05/02 08:49:03 djm Exp $ */
/* $OpenBSD: kexc25519.c,v 1.11 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2001, 2013 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -84,8 +84,8 @@ kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
int
kex_c25519_hash(
int hash_alg,
const char *client_version_string,
const char *server_version_string,
const struct sshbuf *client_version,
const struct sshbuf *server_version,
const u_char *ckexinit, size_t ckexinitlen,
const u_char *skexinit, size_t skexinitlen,
const u_char *serverhostkeyblob, size_t sbloblen,
@ -101,8 +101,8 @@ kex_c25519_hash(
return SSH_ERR_INVALID_ARGUMENT;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_cstring(b, client_version_string)) < 0 ||
(r = sshbuf_put_cstring(b, server_version_string)) < 0 ||
if ((r = sshbuf_put_stringb(b, client_version)) < 0 ||
(r = sshbuf_put_stringb(b, server_version)) < 0 ||
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
(r = sshbuf_put_u32(b, ckexinitlen+1)) < 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) < 0 ||

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexc25519c.c,v 1.9 2017/12/18 02:25:15 djm Exp $ */
/* $OpenBSD: kexc25519c.c,v 1.10 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -129,8 +129,8 @@ input_kex_c25519_reply(int type, u_int32_t seq, struct ssh *ssh)
hashlen = sizeof(hash);
if ((r = kex_c25519_hash(
kex->hash_alg,
kex->client_version_string,
kex->server_version_string,
kex->client_version,
kex->server_version,
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
server_host_key_blob, sbloblen,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexc25519s.c,v 1.11 2017/05/31 04:19:28 djm Exp $ */
/* $OpenBSD: kexc25519s.c,v 1.12 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -110,8 +110,8 @@ input_kex_c25519_init(int type, u_int32_t seq, struct ssh *ssh)
hashlen = sizeof(hash);
if ((r = kex_c25519_hash(
kex->hash_alg,
kex->client_version_string,
kex->server_version_string,
kex->client_version,
kex->server_version,
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
server_host_key_blob, sbloblen,

10
kexdh.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexdh.c,v 1.26 2016/05/02 10:26:04 djm Exp $ */
/* $OpenBSD: kexdh.c,v 1.27 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@ -46,8 +46,8 @@
int
kex_dh_hash(
int hash_alg,
const char *client_version_string,
const char *server_version_string,
const struct sshbuf *client_version,
const struct sshbuf *server_version,
const u_char *ckexinit, size_t ckexinitlen,
const u_char *skexinit, size_t skexinitlen,
const u_char *serverhostkeyblob, size_t sbloblen,
@ -63,8 +63,8 @@ kex_dh_hash(
return SSH_ERR_INVALID_ARGUMENT;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 ||
(r = sshbuf_put_cstring(b, server_version_string)) != 0 ||
if ((r = sshbuf_put_stringb(b, client_version)) < 0 ||
(r = sshbuf_put_stringb(b, server_version)) < 0 ||
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
(r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexdhc.c,v 1.22 2018/02/07 02:06:51 jsing Exp $ */
/* $OpenBSD: kexdhc.c,v 1.24 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@ -178,8 +178,8 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
hashlen = sizeof(hash);
if ((r = kex_dh_hash(
kex->hash_alg,
kex->client_version_string,
kex->server_version_string,
kex->client_version,
kex->server_version,
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
server_host_key_blob, sbloblen,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexdhs.c,v 1.27 2018/04/10 00:10:49 djm Exp $ */
/* $OpenBSD: kexdhs.c,v 1.29 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@ -166,8 +166,8 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
hashlen = sizeof(hash);
if ((r = kex_dh_hash(
kex->hash_alg,
kex->client_version_string,
kex->server_version_string,
kex->client_version,
kex->server_version,
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
server_host_key_blob, sbloblen,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexecdh.c,v 1.6 2015/01/19 20:16:15 markus Exp $ */
/* $OpenBSD: kexecdh.c,v 1.7 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -50,8 +50,8 @@ int
kex_ecdh_hash(
int hash_alg,
const EC_GROUP *ec_group,
const char *client_version_string,
const char *server_version_string,
const struct sshbuf *client_version,
const struct sshbuf *server_version,
const u_char *ckexinit, size_t ckexinitlen,
const u_char *skexinit, size_t skexinitlen,
const u_char *serverhostkeyblob, size_t sbloblen,
@ -67,8 +67,8 @@ kex_ecdh_hash(
return SSH_ERR_INVALID_ARGUMENT;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 ||
(r = sshbuf_put_cstring(b, server_version_string)) != 0 ||
if ((r = sshbuf_put_stringb(b, client_version)) < 0 ||
(r = sshbuf_put_stringb(b, server_version)) < 0 ||
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
(r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexecdhc.c,v 1.13 2018/02/07 02:06:51 jsing Exp $ */
/* $OpenBSD: kexecdhc.c,v 1.14 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -175,8 +175,8 @@ input_kex_ecdh_reply(int type, u_int32_t seq, struct ssh *ssh)
if ((r = kex_ecdh_hash(
kex->hash_alg,
group,
kex->client_version_string,
kex->server_version_string,
kex->client_version,
kex->server_version,
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
server_host_key_blob, sbloblen,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexecdhs.c,v 1.17 2018/02/07 02:06:51 jsing Exp $ */
/* $OpenBSD: kexecdhs.c,v 1.18 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -145,8 +145,8 @@ input_kex_ecdh_init(int type, u_int32_t seq, struct ssh *ssh)
if ((r = kex_ecdh_hash(
kex->hash_alg,
group,
kex->client_version_string,
kex->server_version_string,
kex->client_version,
kex->server_version,
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
server_host_key_blob, sbloblen,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexgex.c,v 1.29 2015/01/19 20:16:15 markus Exp $ */
/* $OpenBSD: kexgex.c,v 1.30 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@ -46,8 +46,8 @@
int
kexgex_hash(
int hash_alg,
const char *client_version_string,
const char *server_version_string,
const struct sshbuf *client_version,
const struct sshbuf *server_version,
const u_char *ckexinit, size_t ckexinitlen,
const u_char *skexinit, size_t skexinitlen,
const u_char *serverhostkeyblob, size_t sbloblen,
@ -66,8 +66,8 @@ kexgex_hash(
return SSH_ERR_INVALID_ARGUMENT;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 ||
(r = sshbuf_put_cstring(b, server_version_string)) != 0 ||
if ((r = sshbuf_put_stringb(b, client_version)) < 0 ||
(r = sshbuf_put_stringb(b, server_version)) < 0 ||
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
(r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexgexc.c,v 1.27 2018/02/07 02:06:51 jsing Exp $ */
/* $OpenBSD: kexgexc.c,v 1.29 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@ -222,8 +222,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
hashlen = sizeof(hash);
if ((r = kexgex_hash(
kex->hash_alg,
kex->client_version_string,
kex->server_version_string,
kex->client_version,
kex->server_version,
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
server_host_key_blob, sbloblen,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexgexs.c,v 1.35 2018/10/04 00:04:41 djm Exp $ */
/* $OpenBSD: kexgexs.c,v 1.36 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@ -198,8 +198,8 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
hashlen = sizeof(hash);
if ((r = kexgex_hash(
kex->hash_alg,
kex->client_version_string,
kex->server_version_string,
kex->client_version,
kex->server_version,
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
server_host_key_blob, sbloblen,

77
misc.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.c,v 1.135 2018/12/07 04:36:09 dtucker Exp $ */
/* $OpenBSD: misc.c,v 1.136 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
@ -38,6 +38,7 @@
#ifdef HAVE_LIBGEN_H
# include <libgen.h>
#endif
#include <poll.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
@ -234,6 +235,80 @@ set_rdomain(int fd, const char *name)
#endif
}
/*
* Wait up to *timeoutp milliseconds for fd to be readable. Updates
* *timeoutp with time remaining.
* Returns 0 if fd ready or -1 on timeout or error (see errno).
*/
int
waitrfd(int fd, int *timeoutp)
{
struct pollfd pfd;
struct timeval t_start;
int oerrno, r;
monotime_tv(&t_start);
pfd.fd = fd;
pfd.events = POLLIN;
for (; *timeoutp >= 0;) {
r = poll(&pfd, 1, *timeoutp);
oerrno = errno;
ms_subtract_diff(&t_start, timeoutp);
errno = oerrno;
if (r > 0)
return 0;
else if (r == -1 && errno != EAGAIN)
return -1;
else if (r == 0)
break;
}
/* timeout */
errno = ETIMEDOUT;
return -1;
}
/*
* Attempt a non-blocking connect(2) to the specified address, waiting up to
* *timeoutp milliseconds for the connection to complete. If the timeout is
* <=0, then wait indefinitely.
*
* Returns 0 on success or -1 on failure.
*/
int
timeout_connect(int sockfd, const struct sockaddr *serv_addr,
socklen_t addrlen, int *timeoutp)
{
int optval = 0;
socklen_t optlen = sizeof(optval);
/* No timeout: just do a blocking connect() */
if (timeoutp == NULL || *timeoutp <= 0)
return connect(sockfd, serv_addr, addrlen);
set_nonblock(sockfd);
if (connect(sockfd, serv_addr, addrlen) == 0) {
/* Succeeded already? */
unset_nonblock(sockfd);
return 0;
} else if (errno != EINPROGRESS)
return -1;
if (waitrfd(sockfd, timeoutp) == -1)
return -1;
/* Completed or failed */
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) {
debug("getsockopt: %s", strerror(errno));
return -1;
}
if (optval != 0) {
errno = optval;
return -1;
}
unset_nonblock(sockfd);
return 0;
}
/* Characters considered whitespace in strsep calls. */
#define WHITESPACE " \t\r\n"
#define QUOTE "\""

5
misc.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.h,v 1.77 2018/12/07 04:36:09 dtucker Exp $ */
/* $OpenBSD: misc.h,v 1.78 2018/12/27 03:25:25 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -17,6 +17,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
/* Data structure for representing a forwarding request. */
struct Forward {
@ -51,6 +52,8 @@ void set_nodelay(int);
int set_reuseaddr(int);
char *get_rdomain(int);
int set_rdomain(int, const char *);
int waitrfd(int, int *);
int timeout_connect(int, const struct sockaddr *, socklen_t, int *);
int a2port(const char *);
int a2tun(const char *, int *);
char *put_host_port(const char *, u_short);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.c,v 1.277 2018/07/16 03:09:13 djm Exp $ */
/* $OpenBSD: packet.c,v 1.278 2018/12/27 03:25:25 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -58,6 +58,7 @@
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <poll.h>
#include <signal.h>
#include <time.h>
@ -228,6 +229,7 @@ ssh_alloc_session_state(void)
if ((ssh = calloc(1, sizeof(*ssh))) == NULL ||
(state = calloc(1, sizeof(*state))) == NULL ||
(ssh->kex = kex_new()) == NULL ||
(state->input = sshbuf_new()) == NULL ||
(state->output = sshbuf_new()) == NULL ||
(state->outgoing_packet = sshbuf_new()) == NULL ||
@ -250,6 +252,10 @@ ssh_alloc_session_state(void)
ssh->state = state;
return ssh;
fail:
if (ssh) {
kex_free(ssh->kex);
free(ssh);
}
if (state) {
sshbuf_free(state->input);
sshbuf_free(state->output);
@ -257,7 +263,6 @@ ssh_alloc_session_state(void)
sshbuf_free(state->outgoing_packet);
free(state);
}
free(ssh);
return NULL;
}
@ -272,8 +277,7 @@ ssh_packet_set_input_hook(struct ssh *ssh, ssh_packet_hook_fn *hook, void *ctx)
int
ssh_packet_is_rekeying(struct ssh *ssh)
{
return ssh->state->rekeying ||
(ssh->kex != NULL && ssh->kex->done == 0);
return ssh->state->rekeying || ssh->kex->done == 0;
}
/*
@ -932,7 +936,7 @@ ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len)
return 0;
/* Haven't keyed yet or KEX in progress. */
if (ssh->kex == NULL || ssh_packet_is_rekeying(ssh))
if (ssh_packet_is_rekeying(ssh))
return 0;
/* Peer can't rekey */
@ -2123,6 +2127,7 @@ void
ssh_packet_set_server(struct ssh *ssh)
{
ssh->state->server_side = 1;
ssh->kex->server = 1; /* XXX unify? */
}
void
@ -2175,9 +2180,9 @@ kex_to_blob(struct sshbuf *m, struct kex *kex)
(r = sshbuf_put_u32(m, kex->kex_type)) != 0 ||
(r = sshbuf_put_stringb(m, kex->my)) != 0 ||
(r = sshbuf_put_stringb(m, kex->peer)) != 0 ||
(r = sshbuf_put_u32(m, kex->flags)) != 0 ||
(r = sshbuf_put_cstring(m, kex->client_version_string)) != 0 ||
(r = sshbuf_put_cstring(m, kex->server_version_string)) != 0)
(r = sshbuf_put_stringb(m, kex->client_version)) != 0 ||
(r = sshbuf_put_stringb(m, kex->server_version)) != 0 ||
(r = sshbuf_put_u32(m, kex->flags)) != 0)
return r;
return 0;
}
@ -2327,12 +2332,8 @@ kex_from_blob(struct sshbuf *m, struct kex **kexp)
struct kex *kex;
int r;
if ((kex = calloc(1, sizeof(struct kex))) == NULL ||
(kex->my = sshbuf_new()) == NULL ||
(kex->peer = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((kex = kex_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_get_string(m, &kex->session_id, &kex->session_id_len)) != 0 ||
(r = sshbuf_get_u32(m, &kex->we_need)) != 0 ||
(r = sshbuf_get_cstring(m, &kex->hostkey_alg, NULL)) != 0 ||
@ -2341,23 +2342,20 @@ kex_from_blob(struct sshbuf *m, struct kex **kexp)
(r = sshbuf_get_u32(m, &kex->kex_type)) != 0 ||
(r = sshbuf_get_stringb(m, kex->my)) != 0 ||
(r = sshbuf_get_stringb(m, kex->peer)) != 0 ||
(r = sshbuf_get_u32(m, &kex->flags)) != 0 ||
(r = sshbuf_get_cstring(m, &kex->client_version_string, NULL)) != 0 ||
(r = sshbuf_get_cstring(m, &kex->server_version_string, NULL)) != 0)
(r = sshbuf_get_stringb(m, kex->client_version)) != 0 ||
(r = sshbuf_get_stringb(m, kex->server_version)) != 0 ||
(r = sshbuf_get_u32(m, &kex->flags)) != 0)
goto out;
kex->server = 1;
kex->done = 1;
r = 0;
out:
if (r != 0 || kexp == NULL) {
if (kex != NULL) {
sshbuf_free(kex->my);
sshbuf_free(kex->peer);
free(kex);
}
kex_free(kex);
if (kexp != NULL)
*kexp = NULL;
} else {
kex_free(*kexp);
*kexp = kex;
}
return r;

4
ssh.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.496 2018/11/23 05:08:07 djm Exp $ */
/* $OpenBSD: ssh.c,v 1.497 2018/12/27 03:25:25 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1490,7 +1490,7 @@ main(int ac, char **av)
signal(SIGCHLD, main_sigchld_handler);
/* Log into the remote system. Never returns if the login fails. */
ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
ssh_login(ssh, &sensitive_data, host, (struct sockaddr *)&hostaddr,
options.port, pw, timeout_ms);
if (packet_connection_is_on_socket()) {

6
ssh.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh.h,v 1.88 2018/06/06 18:29:18 markus Exp $ */
/* $OpenBSD: ssh.h,v 1.89 2018/12/27 03:25:25 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -93,3 +93,7 @@
/* Listen backlog for sshd, ssh-agent and forwarding sockets */
#define SSH_LISTEN_BACKLOG 128
/* Limits for banner exchange */
#define SSH_MAX_BANNER_LEN 8192
#define SSH_MAX_PRE_BANNER_LINES 1024

125
ssh_api.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh_api.c,v 1.8 2017/04/30 23:13:25 djm Exp $ */
/* $OpenBSD: ssh_api.c,v 1.9 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2012 Markus Friedl. All rights reserved.
*
@ -34,8 +34,8 @@
#include <string.h>
int _ssh_exchange_banner(struct ssh *);
int _ssh_send_banner(struct ssh *, char **);
int _ssh_read_banner(struct ssh *, char **);
int _ssh_send_banner(struct ssh *, struct sshbuf *);
int _ssh_read_banner(struct ssh *, struct sshbuf *);
int _ssh_order_hostkeyalgs(struct ssh *);
int _ssh_verify_host_key(struct sshkey *, struct ssh *);
struct sshkey *_ssh_host_public_key(int, int, struct ssh *);
@ -92,7 +92,7 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params)
/* Initialize key exchange */
proposal = kex_params ? kex_params->proposal : myproposal;
if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) {
if ((r = kex_ready(ssh, proposal)) != 0) {
ssh_free(ssh);
return r;
}
@ -236,8 +236,8 @@ ssh_packet_next(struct ssh *ssh, u_char *typep)
* enough data.
*/
*typep = SSH_MSG_NONE;
if (ssh->kex->client_version_string == NULL ||
ssh->kex->server_version_string == NULL)
if (sshbuf_len(ssh->kex->client_version) == 0 ||
sshbuf_len(ssh->kex->server_version) == 0)
return _ssh_exchange_banner(ssh);
/*
* If we enough data and a dispatch function then
@ -312,39 +312,46 @@ ssh_input_space(struct ssh *ssh, size_t len)
/* Read other side's version identification. */
int
_ssh_read_banner(struct ssh *ssh, char **bannerp)
_ssh_read_banner(struct ssh *ssh, struct sshbuf *banner)
{
struct sshbuf *input;
const char *s;
char buf[256], remote_version[256]; /* must be same size! */
struct sshbuf *input = ssh_packet_get_input(ssh);
const char *mismatch = "Protocol mismatch.\r\n";
int r, remote_major, remote_minor;
size_t i, n, j, len;
const u_char *s = sshbuf_ptr(input);
u_char c;
char *cp, *remote_version;
int r, remote_major, remote_minor, expect_nl;
size_t n, j;
*bannerp = NULL;
input = ssh_packet_get_input(ssh);
len = sshbuf_len(input);
s = (const char *)sshbuf_ptr(input);
for (j = n = 0;;) {
for (i = 0; i < sizeof(buf) - 1; i++) {
if (j >= len)
return (0);
buf[i] = s[j++];
if (buf[i] == '\r') {
buf[i] = '\n';
buf[i + 1] = 0;
continue; /**XXX wait for \n */
sshbuf_reset(banner);
expect_nl = 0;
for (;;) {
if (j >= sshbuf_len(input))
return 0; /* insufficient data in input buf */
c = s[j++];
if (c == '\r') {
expect_nl = 1;
continue;
}
if (buf[i] == '\n') {
buf[i + 1] = 0;
if (c == '\n')
break;
if (expect_nl)
goto bad;
if ((r = sshbuf_put_u8(banner, c)) != 0)
return r;
if (sshbuf_len(banner) > SSH_MAX_BANNER_LEN)
goto bad;
}
}
buf[sizeof(buf) - 1] = 0;
if (strncmp(buf, "SSH-", 4) == 0)
if (sshbuf_len(banner) >= 4 &&
memcmp(sshbuf_ptr(banner), "SSH-", 4) == 0)
break;
debug("ssh_exchange_identification: %s", buf);
if (ssh->kex->server || ++n > 65536) {
if ((cp = sshbuf_dup_string(banner)) == NULL)
return SSH_ERR_ALLOC_FAIL;
debug("%s: %s", __func__, cp);
free(cp);
/* Accept lines before banner only on client */
if (ssh->kex->server || ++n > SSH_MAX_PRE_BANNER_LINES) {
bad:
if ((r = sshbuf_put(ssh_packet_get_output(ssh),
mismatch, strlen(mismatch))) != 0)
return r;
@ -354,11 +361,17 @@ _ssh_read_banner(struct ssh *ssh, char **bannerp)
if ((r = sshbuf_consume(input, j)) != 0)
return r;
if ((cp = sshbuf_dup_string(banner)) == NULL)
return SSH_ERR_ALLOC_FAIL;
/* XXX remote version must be the same size as banner for sscanf */
if ((remote_version = calloc(1, sshbuf_len(banner))) == NULL)
return SSH_ERR_ALLOC_FAIL;
/*
* Check that the versions match. In future this might accept
* several versions and set appropriate flags to handle them.
*/
if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
if (sscanf(cp, "SSH-%d.%d-%[^\n]\n",
&remote_major, &remote_minor, remote_version) != 3)
return SSH_ERR_INVALID_FORMAT;
debug("Remote protocol version %d.%d, remote software version %.100s",
@ -371,27 +384,29 @@ _ssh_read_banner(struct ssh *ssh, char **bannerp)
}
if (remote_major != 2)
return SSH_ERR_PROTOCOL_MISMATCH;
chop(buf);
debug("Remote version string %.100s", buf);
if ((*bannerp = strdup(buf)) == NULL)
return SSH_ERR_ALLOC_FAIL;
debug("Remote version string %.100s", cp);
free(cp);
return 0;
}
/* Send our own protocol version identification. */
int
_ssh_send_banner(struct ssh *ssh, char **bannerp)
_ssh_send_banner(struct ssh *ssh, struct sshbuf *banner)
{
char buf[256];
char *cp;
int r;
snprintf(buf, sizeof buf, "SSH-2.0-%.100s\r\n", SSH_VERSION);
if ((r = sshbuf_put(ssh_packet_get_output(ssh), buf, strlen(buf))) != 0)
if ((r = sshbuf_putf(banner, "SSH-2.0-%.100s\r\n", SSH_VERSION)) != 0)
return r;
chop(buf);
debug("Local version string %.100s", buf);
if ((*bannerp = strdup(buf)) == NULL)
if ((r = sshbuf_putb(ssh_packet_get_output(ssh), banner)) != 0)
return r;
/* Remove trailing \r\n */
if ((r = sshbuf_consume_end(banner, 2)) != 0)
return r;
if ((cp = sshbuf_dup_string(banner)) == NULL)
return SSH_ERR_ALLOC_FAIL;
debug("Local version string %.100s", cp);
free(cp);
return 0;
}
@ -408,25 +423,25 @@ _ssh_exchange_banner(struct ssh *ssh)
r = 0;
if (kex->server) {
if (kex->server_version_string == NULL)
r = _ssh_send_banner(ssh, &kex->server_version_string);
if (sshbuf_len(ssh->kex->server_version) == 0)
r = _ssh_send_banner(ssh, ssh->kex->server_version);
if (r == 0 &&
kex->server_version_string != NULL &&
kex->client_version_string == NULL)
r = _ssh_read_banner(ssh, &kex->client_version_string);
sshbuf_len(ssh->kex->server_version) != 0 &&
sshbuf_len(ssh->kex->client_version) == 0)
r = _ssh_read_banner(ssh, ssh->kex->client_version);
} else {
if (kex->server_version_string == NULL)
r = _ssh_read_banner(ssh, &kex->server_version_string);
if (sshbuf_len(ssh->kex->server_version) == 0)
r = _ssh_read_banner(ssh, ssh->kex->server_version);
if (r == 0 &&
kex->server_version_string != NULL &&
kex->client_version_string == NULL)
r = _ssh_send_banner(ssh, &kex->client_version_string);
sshbuf_len(ssh->kex->server_version) != 0 &&
sshbuf_len(ssh->kex->client_version) == 0)
r = _ssh_send_banner(ssh, ssh->kex->client_version);
}
if (r != 0)
return r;
/* start initial kex as soon as we have exchanged the banners */
if (kex->server_version_string != NULL &&
kex->client_version_string != NULL) {
if (sshbuf_len(ssh->kex->server_version) != 0 &&
sshbuf_len(ssh->kex->client_version) != 0) {
if ((r = _ssh_order_hostkeyalgs(ssh)) != 0 ||
(r = kex_send_kexinit(ssh)) != 0)
return r;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect.c,v 1.308 2018/11/18 22:43:29 dtucker Exp $ */
/* $OpenBSD: sshconnect.c,v 1.309 2018/12/27 03:25:25 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -68,9 +68,8 @@
#include "authfile.h"
#include "ssherr.h"
#include "authfd.h"
#include "kex.h"
char *client_version_string = NULL;
char *server_version_string = NULL;
struct sshkey *previous_host_key = NULL;
static int matching_host_key_dns = 0;
@ -444,73 +443,6 @@ fail:
return sock;
}
/*
* Wait up to *timeoutp milliseconds for fd to be readable. Updates
* *timeoutp with time remaining.
* Returns 0 if fd ready or -1 on timeout or error (see errno).
*/
static int
waitrfd(int fd, int *timeoutp)
{
struct pollfd pfd;
struct timeval t_start;
int oerrno, r;
monotime_tv(&t_start);
pfd.fd = fd;
pfd.events = POLLIN;
for (; *timeoutp >= 0;) {
r = poll(&pfd, 1, *timeoutp);
oerrno = errno;
ms_subtract_diff(&t_start, timeoutp);
errno = oerrno;
if (r > 0)
return 0;
else if (r == -1 && errno != EAGAIN)
return -1;
else if (r == 0)
break;
}
/* timeout */
errno = ETIMEDOUT;
return -1;
}
static int
timeout_connect(int sockfd, const struct sockaddr *serv_addr,
socklen_t addrlen, int *timeoutp)
{
int optval = 0;
socklen_t optlen = sizeof(optval);
/* No timeout: just do a blocking connect() */
if (*timeoutp <= 0)
return connect(sockfd, serv_addr, addrlen);
set_nonblock(sockfd);
if (connect(sockfd, serv_addr, addrlen) == 0) {
/* Succeeded already? */
unset_nonblock(sockfd);
return 0;
} else if (errno != EINPROGRESS)
return -1;
if (waitrfd(sockfd, timeoutp) == -1)
return -1;
/* Completed or failed */
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) {
debug("getsockopt: %s", strerror(errno));
return -1;
}
if (optval != 0) {
errno = optval;
return -1;
}
unset_nonblock(sockfd);
return 0;
}
/*
* Opens a TCP/IP connection to the remote server on the given host.
* The address of the remote host will be returned in hostaddr.
@ -629,110 +561,6 @@ ssh_connect(struct ssh *ssh, const char *host, struct addrinfo *addrs,
return ssh_proxy_connect(ssh, host, port, options.proxy_command);
}
static void
send_client_banner(int connection_out, int minor1)
{
/* Send our own protocol version identification. */
xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n",
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION);
if (atomicio(vwrite, connection_out, client_version_string,
strlen(client_version_string)) != strlen(client_version_string))
fatal("write: %.100s", strerror(errno));
chop(client_version_string);
debug("Local version string %.100s", client_version_string);
}
/*
* Waits for the server identification string, and sends our own
* identification string.
*/
void
ssh_exchange_identification(int timeout_ms)
{
char buf[256], remote_version[256]; /* must be same size! */
int remote_major, remote_minor, mismatch;
int connection_in = packet_get_connection_in();
int connection_out = packet_get_connection_out();
u_int i, n;
size_t len;
int rc;
send_client_banner(connection_out, 0);
/* Read other side's version identification. */
for (n = 0;;) {
for (i = 0; i < sizeof(buf) - 1; i++) {
if (timeout_ms > 0) {
rc = waitrfd(connection_in, &timeout_ms);
if (rc == -1 && errno == ETIMEDOUT) {
fatal("Connection timed out during "
"banner exchange");
} else if (rc == -1) {
fatal("%s: %s",
__func__, strerror(errno));
}
}
len = atomicio(read, connection_in, &buf[i], 1);
if (len != 1 && errno == EPIPE)
fatal("ssh_exchange_identification: "
"Connection closed by remote host");
else if (len != 1)
fatal("ssh_exchange_identification: "
"read: %.100s", strerror(errno));
if (buf[i] == '\r') {
buf[i] = '\n';
buf[i + 1] = 0;
continue; /**XXX wait for \n */
}
if (buf[i] == '\n') {
buf[i + 1] = 0;
break;
}
if (++n > 65536)
fatal("ssh_exchange_identification: "
"No banner received");
}
buf[sizeof(buf) - 1] = 0;
if (strncmp(buf, "SSH-", 4) == 0)
break;
debug("ssh_exchange_identification: %s", buf);
}
server_version_string = xstrdup(buf);
/*
* Check that the versions match. In future this might accept
* several versions and set appropriate flags to handle them.
*/
if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
&remote_major, &remote_minor, remote_version) != 3)
fatal("Bad remote protocol version identification: '%.100s'", buf);
debug("Remote protocol version %d.%d, remote software version %.100s",
remote_major, remote_minor, remote_version);
active_state->compat = compat_datafellows(remote_version);
mismatch = 0;
switch (remote_major) {
case 2:
break;
case 1:
if (remote_minor != 99)
mismatch = 1;
break;
default:
mismatch = 1;
break;
}
if (mismatch)
fatal("Protocol major versions differ: %d vs. %d",
PROTOCOL_MAJOR_2, remote_major);
if ((datafellows & SSH_BUG_RSASIGMD5) != 0)
logit("Server version \"%.100s\" uses unsafe RSA signature "
"scheme; disabling use of RSA keys", remote_version);
chop(server_version_string);
}
/* defaults to 'no' */
static int
confirm(const char *prompt)
@ -1426,7 +1254,7 @@ out:
* This function does not require super-user privileges.
*/
void
ssh_login(Sensitive *sensitive, const char *orighost,
ssh_login(struct ssh *ssh, Sensitive *sensitive, const char *orighost,
struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms)
{
char *host;
@ -1440,16 +1268,17 @@ ssh_login(Sensitive *sensitive, const char *orighost,
lowercase(host);
/* Exchange protocol version identification strings with the server. */
ssh_exchange_identification(timeout_ms);
if (kex_exchange_identification(ssh, timeout_ms, NULL) != 0)
cleanup_exit(255); /* error already logged */
/* Put the connection into non-blocking mode. */
packet_set_nonblocking();
ssh_packet_set_nonblocking(ssh);
/* key exchange */
/* authenticate user */
debug("Authenticating to %s:%d as '%s'", host, port, server_user);
ssh_kex2(host, hostaddr, port);
ssh_userauth2(local_user, server_user, host, sensitive);
ssh_kex2(ssh, host, hostaddr, port);
ssh_userauth2(ssh, local_user, server_user, host, sensitive);
free(local_user);
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect.h,v 1.35 2018/07/19 10:28:47 dtucker Exp $ */
/* $OpenBSD: sshconnect.h,v 1.36 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -37,21 +37,18 @@ int ssh_connect(struct ssh *, const char *, struct addrinfo *,
struct sockaddr_storage *, u_short, int, int, int *, int);
void ssh_kill_proxy_command(void);
void ssh_login(Sensitive *, const char *, struct sockaddr *, u_short,
struct passwd *, int);
void ssh_exchange_identification(int);
void ssh_login(struct ssh *, Sensitive *, const char *,
struct sockaddr *, u_short, struct passwd *, int);
int verify_host_key(char *, struct sockaddr *, struct sshkey *);
void get_hostfile_hostname_ipaddr(char *, struct sockaddr *, u_short,
char **, char **);
void ssh_kex(char *, struct sockaddr *);
void ssh_kex2(char *, struct sockaddr *, u_short);
void ssh_kex2(struct ssh *ssh, char *, struct sockaddr *, u_short);
void ssh_userauth1(const char *, const char *, char *, Sensitive *);
void ssh_userauth2(const char *, const char *, char *, Sensitive *);
void ssh_userauth2(struct ssh *ssh, const char *, const char *,
char *, Sensitive *);
void ssh_put_password(char *);
int ssh_local_cmd(const char *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect2.c,v 1.290 2018/11/28 06:00:38 djm Exp $ */
/* $OpenBSD: sshconnect2.c,v 1.291 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved.
@ -155,11 +155,10 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
}
void
ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
{
char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
char *s, *all_key;
struct kex *kex;
int r;
xxx_host = host;
@ -199,36 +198,33 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
options.rekey_interval);
/* start key exchange */
if ((r = kex_setup(active_state, myproposal)) != 0)
if ((r = kex_setup(ssh, myproposal)) != 0)
fatal("kex_setup: %s", ssh_err(r));
kex = active_state->kex;
#ifdef WITH_OPENSSL
kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
kex->kex[KEX_DH_GRP14_SHA256] = kexdh_client;
kex->kex[KEX_DH_GRP16_SHA512] = kexdh_client;
kex->kex[KEX_DH_GRP18_SHA512] = kexdh_client;
kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
ssh->kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
ssh->kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
ssh->kex->kex[KEX_DH_GRP14_SHA256] = kexdh_client;
ssh->kex->kex[KEX_DH_GRP16_SHA512] = kexdh_client;
ssh->kex->kex[KEX_DH_GRP18_SHA512] = kexdh_client;
ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
# ifdef OPENSSL_HAS_ECC
kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
ssh->kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
# endif
#endif
kex->kex[KEX_C25519_SHA256] = kexc25519_client;
kex->client_version_string=client_version_string;
kex->server_version_string=server_version_string;
kex->verify_host_key=&verify_host_key_callback;
ssh->kex->kex[KEX_C25519_SHA256] = kexc25519_client;
ssh->kex->verify_host_key=&verify_host_key_callback;
ssh_dispatch_run_fatal(active_state, DISPATCH_BLOCK, &kex->done);
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done);
/* remove ext-info from the KEX proposals for rekeying */
myproposal[PROPOSAL_KEX_ALGS] =
compat_kex_proposal(options.kex_algorithms);
if ((r = kex_prop2buf(kex->my, myproposal)) != 0)
if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0)
fatal("kex_prop2buf: %s", ssh_err(r));
session_id2 = kex->session_id;
session_id2_len = kex->session_id_len;
session_id2 = ssh->kex->session_id;
session_id2_len = ssh->kex->session_id_len;
#ifdef DEBUG_KEXDH
/* send 1st encrypted/maced/compressed message */
@ -365,10 +361,9 @@ Authmethod authmethods[] = {
};
void
ssh_userauth2(const char *local_user, const char *server_user, char *host,
Sensitive *sensitive)
ssh_userauth2(struct ssh *ssh, const char *local_user,
const char *server_user, char *host, Sensitive *sensitive)
{
struct ssh *ssh = active_state;
Authctxt authctxt;
int r;
@ -392,8 +387,10 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
authctxt.info_req_seen = 0;
authctxt.agent_fd = -1;
pubkey_prepare(&authctxt);
if (authctxt.method == NULL)
fatal("ssh_userauth2: internal error: cannot send userauth none request");
if (authctxt.method == NULL) {
fatal("%s: internal error: cannot send userauth none request",
__func__);
}
if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 ||

118
sshd.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshd.c,v 1.519 2018/11/19 04:12:32 djm Exp $ */
/* $OpenBSD: sshd.c,v 1.520 2018/12/27 03:25:25 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -180,13 +180,6 @@ char **rexec_argv;
int listen_socks[MAX_LISTEN_SOCKS];
int num_listen_socks = 0;
/*
* the client's version string, passed by sshd2 in compat mode. if != NULL,
* sshd will skip the version-number exchange
*/
char *client_version_string = NULL;
char *server_version_string = NULL;
/* Daemon's agent connection */
int auth_sock = -1;
int have_agent = 0;
@ -363,108 +356,6 @@ grace_alarm_handler(int sig)
ssh_remote_ipaddr(active_state), ssh_remote_port(active_state));
}
static void
sshd_exchange_identification(struct ssh *ssh, int sock_in, int sock_out)
{
u_int i;
int remote_major, remote_minor;
char *s;
char buf[256]; /* Must not be larger than remote_version. */
char remote_version[256]; /* Must be at least as big as buf. */
xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s\r\n",
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION,
*options.version_addendum == '\0' ? "" : " ",
options.version_addendum);
/* Send our protocol version identification. */
if (atomicio(vwrite, sock_out, server_version_string,
strlen(server_version_string))
!= strlen(server_version_string)) {
logit("Could not write ident string to %s port %d",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
cleanup_exit(255);
}
/* Read other sides version identification. */
memset(buf, 0, sizeof(buf));
for (i = 0; i < sizeof(buf) - 1; i++) {
if (atomicio(read, sock_in, &buf[i], 1) != 1) {
logit("Did not receive identification string "
"from %s port %d",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
cleanup_exit(255);
}
if (buf[i] == '\r') {
buf[i] = 0;
/* Kludge for F-Secure Macintosh < 1.0.2 */
if (i == 12 &&
strncmp(buf, "SSH-1.5-W1.0", 12) == 0)
break;
continue;
}
if (buf[i] == '\n') {
buf[i] = 0;
break;
}
}
buf[sizeof(buf) - 1] = 0;
client_version_string = xstrdup(buf);
/*
* Check that the versions match. In future this might accept
* several versions and set appropriate flags to handle them.
*/
if (sscanf(client_version_string, "SSH-%d.%d-%[^\n]\n",
&remote_major, &remote_minor, remote_version) != 3) {
s = "Protocol mismatch.\n";
(void) atomicio(vwrite, sock_out, s, strlen(s));
logit("Bad protocol version identification '%.100s' "
"from %s port %d", client_version_string,
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
close(sock_in);
close(sock_out);
cleanup_exit(255);
}
debug("Client protocol version %d.%d; client software version %.100s",
remote_major, remote_minor, remote_version);
ssh->compat = compat_datafellows(remote_version);
if ((ssh->compat & SSH_BUG_PROBE) != 0) {
logit("probed from %s port %d with %s. Don't panic.",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
client_version_string);
cleanup_exit(255);
}
if ((ssh->compat & SSH_BUG_SCANNER) != 0) {
logit("scanned from %s port %d with %s. Don't panic.",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
client_version_string);
cleanup_exit(255);
}
if ((ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
logit("Client version \"%.100s\" uses unsafe RSA signature "
"scheme; disabling use of RSA keys", remote_version);
}
chop(server_version_string);
debug("Local version string %.200s", server_version_string);
if (remote_major != 2 &&
!(remote_major == 1 && remote_minor == 99)) {
s = "Protocol major versions differ.\n";
(void) atomicio(vwrite, sock_out, s, strlen(s));
close(sock_in);
close(sock_out);
logit("Protocol major versions differ for %s port %d: "
"%.200s vs. %.200s",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
server_version_string, client_version_string);
cleanup_exit(255);
}
}
/* Destroy the host and server keys. They will no longer be needed. */
void
destroy_sensitive_data(void)
@ -2115,7 +2006,9 @@ main(int ac, char **av)
if (!debug_flag)
alarm(options.login_grace_time);
sshd_exchange_identification(ssh, sock_in, sock_out);
if (kex_exchange_identification(ssh, -1, options.version_addendum) != 0)
cleanup_exit(255); /* error already logged */
packet_set_nonblocking();
/* allocate authentication context */
@ -2303,9 +2196,6 @@ do_ssh2_kex(void)
# endif
#endif
kex->kex[KEX_C25519_SHA256] = kexc25519_server;
kex->server = 1;
kex->client_version_string=client_version_string;
kex->server_version_string=server_version_string;
kex->load_host_public_key=&get_hostkey_public_by_type;
kex->load_host_private_key=&get_hostkey_private_by_type;
kex->host_key_index=&get_hostkey_index;