Upgrade to OpenSSH 6.8p1.

This commit is contained in:
Dag-Erling Smørgrav 2016-01-19 18:28:23 +00:00
commit bc5531debe
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=294332
332 changed files with 30386 additions and 14369 deletions

28
crypto/openssh/.cvsignore Normal file
View File

@ -0,0 +1,28 @@
*.0
*.out
Makefile
autom4te.cache
buildit.sh
buildpkg.sh
config.cache
config.h
config.h.in
config.log
config.status
configure
openssh.xml
opensshd.init
scp
sftp
sftp-server
ssh
ssh-add
ssh-agent
ssh-keygen
ssh-keyscan
ssh-keysign
ssh-pkcs11-helper
sshd
stamp-h.in
survey
survey.sh

File diff suppressed because it is too large Load Diff

View File

@ -65,28 +65,33 @@ MANFMT=@MANFMT@
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT)
LIBOPENSSH_OBJS=\
ssh_api.o \
ssherr.o \
sshbuf.o \
sshkey.o \
sshbuf-getput-basic.o \
sshbuf-misc.o \
sshbuf-getput-crypto.o
sshbuf-getput-crypto.o \
krl.o \
bitmap.o
LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
authfd.o authfile.o bufaux.o bufbn.o buffer.o \
canohost.o channels.o cipher.o cipher-aes.o \
authfd.o authfile.o bufaux.o bufbn.o bufec.o buffer.o \
canohost.o channels.o cipher.o cipher-aes.o cipher-aesctr.o \
cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \
compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \
log.o match.o md-sha256.o moduli.o nchan.o packet.o \
compat.o crc32.o deattack.o fatal.o hostfile.o \
log.o match.o md-sha256.o moduli.o nchan.o packet.o opacket.o \
readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o \
monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.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 \
ssh-pkcs11.o krl.o smult_curve25519_ref.o \
kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \
ssh-ed25519.o digest-openssl.o hmac.o \
sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o
ssh-pkcs11.o smult_curve25519_ref.o \
poly1305.o chacha.o cipher-chachapoly.o \
ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \
sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \
kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \
kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
sshconnect.o sshconnect1.o sshconnect2.o mux.o \
@ -99,8 +104,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
auth-chall.o auth2-chall.o groupaccess.o \
auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
auth2-none.o auth2-passwd.o auth2-pubkey.o \
monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
kexc25519s.o auth-krb5.o \
monitor_mm.o monitor.o monitor_wrap.o auth-krb5.o \
auth2-gss.o gss-serv.o gss-serv-krb5.o \
loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
sftp-server.o sftp-common.o \
@ -230,6 +234,12 @@ clean: regressclean
rm -f regress/unittests/sshbuf/test_sshbuf
rm -f regress/unittests/sshkey/*.o
rm -f regress/unittests/sshkey/test_sshkey
rm -f regress/unittests/bitmap/*.o
rm -f regress/unittests/bitmap/test_bitmap
rm -f regress/unittests/hostkeys/*.o
rm -f regress/unittests/hostkeys/test_hostkeys
rm -f regress/unittests/kex/*.o
rm -f regress/unittests/kex/test_kex
(cd openbsd-compat && $(MAKE) clean)
distclean: regressclean
@ -244,6 +254,12 @@ distclean: regressclean
rm -f regress/unittests/sshbuf/test_sshbuf
rm -f regress/unittests/sshkey/*.o
rm -f regress/unittests/sshkey/test_sshkey
rm -f regress/unittests/bitmap/*.o
rm -f regress/unittests/bitmap/test_bitmap
rm -f regress/unittests/hostkeys/*.o
rm -f regress/unittests/hostkeys/test_hostkeys
rm -f regress/unittests/kex/*.o
rm -f regress/unittests/kex/test_kex
(cd openbsd-compat && $(MAKE) distclean)
if test -d pkg ; then \
rm -fr pkg ; \
@ -417,15 +433,21 @@ uninstall:
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
regress-prep:
[ -d `pwd`/regress ] || mkdir -p `pwd`/regress
[ -d `pwd`/regress/unittests ] || mkdir -p `pwd`/regress/unittests
[ -d `pwd`/regress/unittests/test_helper ] || \
[ -d `pwd`/regress ] || mkdir -p `pwd`/regress
[ -d `pwd`/regress/unittests ] || mkdir -p `pwd`/regress/unittests
[ -d `pwd`/regress/unittests/test_helper ] || \
mkdir -p `pwd`/regress/unittests/test_helper
[ -d `pwd`/regress/unittests/sshbuf ] || \
[ -d `pwd`/regress/unittests/sshbuf ] || \
mkdir -p `pwd`/regress/unittests/sshbuf
[ -d `pwd`/regress/unittests/sshkey ] || \
[ -d `pwd`/regress/unittests/sshkey ] || \
mkdir -p `pwd`/regress/unittests/sshkey
[ -f `pwd`/regress/Makefile ] || \
[ -d `pwd`/regress/unittests/bitmap ] || \
mkdir -p `pwd`/regress/unittests/bitmap
[ -d `pwd`/regress/unittests/hostkeys ] || \
mkdir -p `pwd`/regress/unittests/hostkeys
[ -d `pwd`/regress/unittests/kex ] || \
mkdir -p `pwd`/regress/unittests/kex
[ -f `pwd`/regress/Makefile ] || \
ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile
regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c
@ -436,6 +458,10 @@ regress/setuid-allowed$(EXEEXT): $(srcdir)/regress/setuid-allowed.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $? \
$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
regress/netcat$(EXEEXT): $(srcdir)/regress/netcat.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $? \
$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
UNITTESTS_TEST_HELPER_OBJS=\
regress/unittests/test_helper/test_helper.o \
regress/unittests/test_helper/fuzz.o
@ -473,11 +499,46 @@ regress/unittests/sshkey/test_sshkey$(EXEEXT): ${UNITTESTS_TEST_SSHKEY_OBJS} \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
UNITTESTS_TEST_BITMAP_OBJS=\
regress/unittests/bitmap/tests.o
regress/unittests/bitmap/test_bitmap$(EXEEXT): ${UNITTESTS_TEST_BITMAP_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_BITMAP_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
UNITTESTS_TEST_KEX_OBJS=\
regress/unittests/kex/tests.o \
regress/unittests/kex/test_kex.o \
roaming_dummy.o
regress/unittests/kex/test_kex$(EXEEXT): ${UNITTESTS_TEST_KEX_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_KEX_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
UNITTESTS_TEST_HOSTKEYS_OBJS=\
regress/unittests/hostkeys/tests.o \
regress/unittests/hostkeys/test_iterate.o
regress/unittests/hostkeys/test_hostkeys$(EXEEXT): \
${UNITTESTS_TEST_HOSTKEYS_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_HOSTKEYS_OBJS) \
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
REGRESS_BINARIES=\
regress/modpipe$(EXEEXT) \
regress/setuid-allowed$(EXEEXT) \
regress/netcat$(EXEEXT) \
regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \
regress/unittests/sshkey/test_sshkey$(EXEEXT)
regress/unittests/sshkey/test_sshkey$(EXEEXT) \
regress/unittests/bitmap/test_bitmap$(EXEEXT) \
regress/unittests/hostkeys/test_hostkeys$(EXEEXT) \
regress/unittests/kex/test_kex$(EXEEXT)
tests interop-tests t-exec: regress-prep $(TARGETS) $(REGRESS_BINARIES)
BUILDDIR=`pwd`; \

View File

@ -40,8 +40,8 @@ http://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt
"ecdsa-sha2-nistp521-cert-v01@openssh.com"
OpenSSH introduces new public key algorithms to support certificate
authentication for users and hostkeys. These methods are documented in
the file PROTOCOL.certkeys
authentication for users and host keys. These methods are documented
in the file PROTOCOL.certkeys
1.4. transport: Elliptic Curve cryptography
@ -282,6 +282,53 @@ by the client cancel the forwarding of a Unix domain socket.
boolean FALSE
string socket path
2.5. connection: hostkey update and rotation "hostkeys-00@openssh.com"
and "hostkeys-prove-00@openssh.com"
OpenSSH supports a protocol extension allowing a server to inform
a client of all its protocol v.2 host keys after user-authentication
has completed.
byte SSH_MSG_GLOBAL_REQUEST
string "hostkeys-00@openssh.com"
string[] hostkeys
Upon receiving this message, a client should check which of the
supplied host keys are present in known_hosts. For keys that are
not present, it should send a "hostkeys-prove@openssh.com" message
to request the server prove ownership of the private half of the
key.
byte SSH_MSG_GLOBAL_REQUEST
string "hostkeys-prove-00@openssh.com"
char 1 /* want-reply */
string[] hostkeys
When a server receives this message, it should generate a signature
using each requested key over the following:
string "hostkeys-prove-00@openssh.com"
string session identifier
string hostkey
These signatures should be included in the reply, in the order matching
the hostkeys in the request:
byte SSH_MSG_REQUEST_SUCCESS
string[] signatures
When the client receives this reply (and not a failure), it should
validate the signatures and may update its known_hosts file, adding keys
that it has not seen before and deleting keys for the server host that
are no longer offered.
These extensions let a client learn key types that it had not previously
encountered, thereby allowing it to potentially upgrade from weaker
key algorithms to better ones. It also supports graceful key rotation:
a server may offer multiple keys of the same type for a period (to
give clients an opportunity to learn them using this extension) before
removing the deprecated key from those offered.
3. SFTP protocol changes
3.1. sftp: Reversal of arguments to SSH_FXP_SYMLINK
@ -406,4 +453,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.24 2014/07/15 15:54:14 millert Exp $
$OpenBSD: PROTOCOL,v 1.27 2015/02/20 22:17:21 djm Exp $

View File

@ -37,7 +37,7 @@ The available section types are:
#define KRL_SECTION_FINGERPRINT_SHA1 3
#define KRL_SECTION_SIGNATURE 4
3. Certificate serial section
2. Certificate section
These sections use type KRL_SECTION_CERTIFICATES to revoke certificates by
serial number or key ID. The consist of the CA key that issued the
@ -47,6 +47,11 @@ ignored.
string ca_key
string reserved
Where "ca_key" is the standard SSH wire serialisation of the CA's
public key. Alternately, "ca_key" may be an empty string to indicate
the certificate section applies to all CAs (this is most useful when
revoking key IDs).
Followed by one or more sections:
byte cert_section_type
@ -161,4 +166,4 @@ Implementations that retrieve KRLs over untrusted channels must verify
signatures. Signature sections are optional for KRLs distributed by
trusted means.
$OpenBSD: PROTOCOL.krl,v 1.2 2013/01/18 00:24:58 djm Exp $
$OpenBSD: PROTOCOL.krl,v 1.3 2015/01/30 01:10:33 djm Exp $

View File

@ -1,4 +1,4 @@
See http://www.openssh.com/txt/release-6.7 for the release notes.
See http://www.openssh.com/txt/release-6.8 for the release notes.
- A Japanese translation of this document and of the OpenSSH FAQ is
- available at http://www.unixuser.org/~haruyama/security/openssh/index.html

View File

@ -1,4 +1,4 @@
/* $OpenBSD: atomicio.c,v 1.26 2010/09/22 22:58:51 djm Exp $ */
/* $OpenBSD: atomicio.c,v 1.27 2015/01/16 06:40:12 deraadt Exp $ */
/*
* Copyright (c) 2006 Damien Miller. All rights reserved.
* Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
@ -41,6 +41,7 @@
#endif
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include "atomicio.h"

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-options.c,v 1.64 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: auth-options.c,v 1.65 2015/01/14 10:30:34 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -21,15 +21,19 @@
#include <stdarg.h>
#include "openbsd-compat/sys-queue.h"
#include "key.h" /* XXX for typedef */
#include "buffer.h" /* XXX for typedef */
#include "xmalloc.h"
#include "match.h"
#include "ssherr.h"
#include "log.h"
#include "canohost.h"
#include "buffer.h"
#include "sshbuf.h"
#include "misc.h"
#include "channels.h"
#include "servconf.h"
#include "key.h"
#include "sshkey.h"
#include "auth-options.h"
#include "hostfile.h"
#include "auth.h"
@ -417,7 +421,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
#define OPTIONS_CRITICAL 1
#define OPTIONS_EXTENSIONS 2
static int
parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw,
parse_option_list(struct sshbuf *oblob, struct passwd *pw,
u_int which, int crit,
int *cert_no_port_forwarding_flag,
int *cert_no_agent_forwarding_flag,
@ -430,26 +434,25 @@ parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw,
char *command, *allowed;
const char *remote_ip;
char *name = NULL;
u_char *data_blob = NULL;
u_int nlen, dlen, clen;
Buffer c, data;
int ret = -1, result, found;
struct sshbuf *c = NULL, *data = NULL;
int r, ret = -1, result, found;
buffer_init(&data);
if ((c = sshbuf_fromb(oblob)) == NULL) {
error("%s: sshbuf_fromb failed", __func__);
goto out;
}
/* Make copy to avoid altering original */
buffer_init(&c);
buffer_append(&c, optblob, optblob_len);
while (buffer_len(&c) > 0) {
if ((name = buffer_get_cstring_ret(&c, &nlen)) == NULL ||
(data_blob = buffer_get_string_ret(&c, &dlen)) == NULL) {
error("Certificate options corrupt");
while (sshbuf_len(c) > 0) {
sshbuf_free(data);
data = NULL;
if ((r = sshbuf_get_cstring(c, &name, NULL)) != 0 ||
(r = sshbuf_froms(c, &data)) != 0) {
error("Unable to parse certificate options: %s",
ssh_err(r));
goto out;
}
buffer_append(&data, data_blob, dlen);
debug3("found certificate option \"%.100s\" len %u",
name, dlen);
debug3("found certificate option \"%.100s\" len %zu",
name, sshbuf_len(data));
found = 0;
if ((which & OPTIONS_EXTENSIONS) != 0) {
if (strcmp(name, "permit-X11-forwarding") == 0) {
@ -473,10 +476,10 @@ parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw,
}
if (!found && (which & OPTIONS_CRITICAL) != 0) {
if (strcmp(name, "force-command") == 0) {
if ((command = buffer_get_cstring_ret(&data,
&clen)) == NULL) {
error("Certificate constraint \"%s\" "
"corrupt", name);
if ((r = sshbuf_get_cstring(data, &command,
NULL)) != 0) {
error("Unable to parse \"%s\" "
"section: %s", name, ssh_err(r));
goto out;
}
if (*cert_forced_command != NULL) {
@ -489,10 +492,10 @@ parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw,
found = 1;
}
if (strcmp(name, "source-address") == 0) {
if ((allowed = buffer_get_cstring_ret(&data,
&clen)) == NULL) {
error("Certificate constraint "
"\"%s\" corrupt", name);
if ((r = sshbuf_get_cstring(data, &allowed,
NULL)) != 0) {
error("Unable to parse \"%s\" "
"section: %s", name, ssh_err(r));
goto out;
}
if ((*cert_source_address_done)++) {
@ -540,16 +543,13 @@ parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw,
logit("Certificate extension \"%s\" "
"is not supported", name);
}
} else if (buffer_len(&data) != 0) {
} else if (sshbuf_len(data) != 0) {
error("Certificate option \"%s\" corrupt "
"(extra data)", name);
goto out;
}
buffer_clear(&data);
free(name);
free(data_blob);
name = NULL;
data_blob = NULL;
}
/* successfully parsed all options */
ret = 0;
@ -563,10 +563,8 @@ parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw,
}
if (name != NULL)
free(name);
if (data_blob != NULL)
free(data_blob);
buffer_free(&data);
buffer_free(&c);
sshbuf_free(data);
sshbuf_free(c);
return ret;
}
@ -575,7 +573,7 @@ parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw,
* options so this must be called after auth_parse_options().
*/
int
auth_cert_options(Key *k, struct passwd *pw)
auth_cert_options(struct sshkey *k, struct passwd *pw)
{
int cert_no_port_forwarding_flag = 1;
int cert_no_agent_forwarding_flag = 1;
@ -585,10 +583,9 @@ auth_cert_options(Key *k, struct passwd *pw)
char *cert_forced_command = NULL;
int cert_source_address_done = 0;
if (key_cert_is_legacy(k)) {
if (sshkey_cert_is_legacy(k)) {
/* All options are in the one field for v00 certs */
if (parse_option_list(buffer_ptr(k->cert->critical),
buffer_len(k->cert->critical), pw,
if (parse_option_list(k->cert->critical, pw,
OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1,
&cert_no_port_forwarding_flag,
&cert_no_agent_forwarding_flag,
@ -600,14 +597,12 @@ auth_cert_options(Key *k, struct passwd *pw)
return -1;
} else {
/* Separate options and extensions for v01 certs */
if (parse_option_list(buffer_ptr(k->cert->critical),
buffer_len(k->cert->critical), pw,
if (parse_option_list(k->cert->critical, pw,
OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL,
&cert_forced_command,
&cert_source_address_done) == -1)
return -1;
if (parse_option_list(buffer_ptr(k->cert->extensions),
buffer_len(k->cert->extensions), pw,
if (parse_option_list(k->cert->extensions, pw,
OPTIONS_EXTENSIONS, 1,
&cert_no_port_forwarding_flag,
&cert_no_agent_forwarding_flag,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-options.h,v 1.20 2010/05/07 11:30:29 djm Exp $ */
/* $OpenBSD: auth-options.h,v 1.21 2015/01/14 10:30:34 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -35,6 +35,6 @@ extern char *authorized_principals;
int auth_parse_options(struct passwd *, char *, char *, u_long);
void auth_clear_options(void);
int auth_cert_options(Key *, struct passwd *);
int auth_cert_options(struct sshkey *, struct passwd *);
#endif

View File

@ -15,6 +15,8 @@
#include "includes.h"
#ifdef WITH_SSH1
#include <sys/types.h>
#include <pwd.h>
@ -102,3 +104,5 @@ auth_rhosts_rsa(Authctxt *authctxt, char *cuser, Key *client_host_key)
packet_send_debug("Rhosts with RSA host authentication accepted.");
return 1;
}
#endif /* WITH_SSH1 */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-rhosts.c,v 1.45 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: auth-rhosts.c,v 1.46 2014/12/23 22:42:48 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -57,7 +57,8 @@ check_rhosts_file(const char *filename, const char *hostname,
const char *server_user)
{
FILE *f;
char buf[1024]; /* Must not be larger than host, user, dummy below. */
#define RBUFLN 1024
char buf[RBUFLN];/* Must not be larger than host, user, dummy below. */
int fd;
struct stat st;
@ -80,8 +81,9 @@ check_rhosts_file(const char *filename, const char *hostname,
return 0;
}
while (fgets(buf, sizeof(buf), f)) {
/* All three must be at least as big as buf to avoid overflows. */
char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
/* All three must have length >= buf to avoid overflows. */
char hostbuf[RBUFLN], userbuf[RBUFLN], dummy[RBUFLN];
char *host, *user, *cp;
int negated;
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
@ -140,8 +142,8 @@ check_rhosts_file(const char *filename, const char *hostname,
/* Check for empty host/user names (particularly '+'). */
if (!host[0] || !user[0]) {
/* We come here if either was '+' or '-'. */
auth_debug_add("Ignoring wild host/user names in %.100s.",
filename);
auth_debug_add("Ignoring wild host/user names "
"in %.100s.", filename);
continue;
}
/* Verify that host name matches. */
@ -149,7 +151,8 @@ check_rhosts_file(const char *filename, const char *hostname,
if (!innetgr(host + 1, hostname, NULL, NULL) &&
!innetgr(host + 1, ipaddr, NULL, NULL))
continue;
} else if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0)
} else if (strcasecmp(host, hostname) &&
strcmp(host, ipaddr) != 0)
continue; /* Different hostname. */
/* Verify that user name matches. */
@ -208,7 +211,8 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam
/* Switch to the user's uid. */
temporarily_use_uid(pw);
/*
* Quick check: if the user has no .shosts or .rhosts files, return
* Quick check: if the user has no .shosts or .rhosts files and
* no system hosts.equiv/shosts.equiv files exist then return
* failure immediately without doing costly lookups from name
* servers.
*/
@ -223,27 +227,38 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam
/* Switch back to privileged uid. */
restore_uid();
/* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */
/*
* Deny if The user has no .shosts or .rhosts file and there
* are no system-wide files.
*/
if (!rhosts_files[rhosts_file_index] &&
stat(_PATH_RHOSTS_EQUIV, &st) < 0 &&
stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0)
stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0) {
debug3("%s: no hosts access files exist", __func__);
return 0;
}
/* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
if (pw->pw_uid != 0) {
/*
* If not logging in as superuser, try /etc/hosts.equiv and
* shosts.equiv.
*/
if (pw->pw_uid == 0)
debug3("%s: root user, ignoring system hosts files", __func__);
else {
if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr,
client_user, pw->pw_name)) {
auth_debug_add("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
hostname, ipaddr);
auth_debug_add("Accepted for %.100s [%.100s] by "
"/etc/hosts.equiv.", hostname, ipaddr);
return 1;
}
if (check_rhosts_file(_PATH_SSH_HOSTS_EQUIV, hostname, ipaddr,
client_user, pw->pw_name)) {
auth_debug_add("Accepted for %.100s [%.100s] by %.100s.",
hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV);
auth_debug_add("Accepted for %.100s [%.100s] by "
"%.100s.", hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV);
return 1;
}
}
/*
* Check that the home directory is owned by root or the user, and is
* not group or world writable.
@ -290,20 +305,25 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam
auth_debug_add("Bad file modes for %.200s", buf);
continue;
}
/* Check if we have been configured to ignore .rhosts and .shosts files. */
/*
* Check if we have been configured to ignore .rhosts
* and .shosts files.
*/
if (options.ignore_rhosts) {
auth_debug_add("Server has been configured to ignore %.100s.",
rhosts_files[rhosts_file_index]);
auth_debug_add("Server has been configured to "
"ignore %.100s.", rhosts_files[rhosts_file_index]);
continue;
}
/* Check if authentication is permitted by the file. */
if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) {
if (check_rhosts_file(buf, hostname, ipaddr,
client_user, pw->pw_name)) {
auth_debug_add("Accepted by %.100s.",
rhosts_files[rhosts_file_index]);
/* Restore the privileged uid. */
restore_uid();
auth_debug_add("Accepted host %s ip %s client_user %s server_user %s",
hostname, ipaddr, client_user, pw->pw_name);
auth_debug_add("Accepted host %s ip %s client_user "
"%s server_user %s", hostname, ipaddr,
client_user, pw->pw_name);
return 1;
}
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-rsa.c,v 1.88 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: auth-rsa.c,v 1.90 2015/01/28 22:36:00 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -16,6 +16,8 @@
#include "includes.h"
#ifdef WITH_SSH1
#include <sys/types.h>
#include <sys/stat.h>
@ -236,7 +238,9 @@ rsa_key_allowed_in_file(struct passwd *pw, char *file,
"actual %d vs. announced %d.",
file, linenum, BN_num_bits(key->rsa->n), bits);
fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT)) == NULL)
continue;
debug("matching key found: file %s, line %lu %s %s",
file, linenum, key_type(key), fp);
free(fp);
@ -341,3 +345,5 @@ auth_rsa(Authctxt *authctxt, BIGNUM *client_n)
packet_send_debug("RSA authentication accepted.");
return (1);
}
#endif /* WITH_SSH1 */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.c,v 1.106 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: auth.c,v 1.110 2015/02/25 17:29:38 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -28,7 +28,6 @@ __RCSID("$FreeBSD$");
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <netinet/in.h>
@ -51,6 +50,7 @@ __RCSID("$FreeBSD$");
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include "xmalloc.h"
#include "match.h"
@ -72,7 +72,8 @@ __RCSID("$FreeBSD$");
#endif
#include "authfile.h"
#include "monitor_wrap.h"
#include "krl.h"
#include "authfile.h"
#include "ssherr.h"
#include "compat.h"
/* import */
@ -331,13 +332,14 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
void
auth_maxtries_exceeded(Authctxt *authctxt)
{
packet_disconnect("Too many authentication failures for "
error("maximum authentication attempts exceeded for "
"%s%.100s from %.200s port %d %s",
authctxt->valid ? "" : "invalid user ",
authctxt->user,
get_remote_ipaddr(),
get_remote_port(),
compat20 ? "ssh2" : "ssh1");
packet_disconnect("Too many authentication failures");
/* NOTREACHED */
}
@ -376,7 +378,7 @@ auth_root_allowed(const char *method)
char *
expand_authorized_keys(const char *filename, struct passwd *pw)
{
char *file, ret[MAXPATHLEN];
char *file, ret[PATH_MAX];
int i;
file = percent_expand(filename, "h", pw->pw_dir,
@ -468,7 +470,7 @@ int
auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
uid_t uid, char *err, size_t errlen)
{
char buf[MAXPATHLEN], homedir[MAXPATHLEN];
char buf[PATH_MAX], homedir[PATH_MAX];
char *cp;
int comparehome = 0;
struct stat st;
@ -674,43 +676,39 @@ getpwnamallow(const char *user)
int
auth_key_is_revoked(Key *key)
{
#ifdef WITH_OPENSSL
char *key_fp;
char *fp = NULL;
int r;
if (options.revoked_keys_file == NULL)
return 0;
switch (ssh_krl_file_contains_key(options.revoked_keys_file, key)) {
if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
error("%s: fingerprint key: %s", __func__, ssh_err(r));
goto out;
}
r = sshkey_check_revoked(key, options.revoked_keys_file);
switch (r) {
case 0:
return 0; /* Not revoked */
case -2:
break; /* Not a KRL */
break; /* not revoked */
case SSH_ERR_KEY_REVOKED:
error("Authentication key %s %s revoked by file %s",
sshkey_type(key), fp, options.revoked_keys_file);
goto out;
default:
goto revoked;
error("Error checking authentication key %s %s in "
"revoked keys file %s: %s", sshkey_type(key), fp,
options.revoked_keys_file, ssh_err(r));
goto out;
}
#endif
debug3("%s: treating %s as a key list", __func__,
options.revoked_keys_file);
switch (key_in_file(key, options.revoked_keys_file, 0)) {
case 0:
/* key not revoked */
return 0;
case -1:
/* Error opening revoked_keys_file: refuse all keys */
error("Revoked keys file is unreadable: refusing public key "
"authentication");
return 1;
#ifdef WITH_OPENSSL
case 1:
revoked:
/* Key revoked */
key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
error("WARNING: authentication attempt with a revoked "
"%s key %s ", key_type(key), key_fp);
free(key_fp);
return 1;
#endif
}
fatal("key_in_file returned junk");
/* Success */
r = 0;
out:
free(fp);
return r == 0 ? 0 : 1;
}
void

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.h,v 1.78 2014/07/03 11:16:55 djm Exp $ */
/* $OpenBSD: auth.h,v 1.82 2015/02/16 22:13:32 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -42,6 +42,9 @@
#include <krb5.h>
#endif
struct ssh;
struct sshkey;
typedef struct Authctxt Authctxt;
typedef struct Authmethod Authmethod;
typedef struct KbdintDevice KbdintDevice;
@ -75,6 +78,9 @@ struct Authctxt {
#endif
Buffer *loginmsg;
void *methoddata;
struct sshkey **prev_userkeys;
u_int nprev_userkeys;
};
/*
* Every authentication method has to handle authentication requests for
@ -123,6 +129,8 @@ int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
int user_key_allowed(struct passwd *, Key *);
void pubkey_auth_info(Authctxt *, const Key *, const char *, ...)
__attribute__((__format__ (printf, 3, 4)));
void auth2_record_userkey(Authctxt *, struct sshkey *);
int auth2_userkey_already_used(Authctxt *, struct sshkey *);
struct stat;
int auth_secure_path(const char *, struct stat *, const char *, uid_t,
@ -195,12 +203,13 @@ check_key_in_hostfiles(struct passwd *, Key *, const char *,
/* hostkey handling */
Key *get_hostkey_by_index(int);
Key *get_hostkey_public_by_index(int);
Key *get_hostkey_public_by_type(int);
Key *get_hostkey_private_by_type(int);
int get_hostkey_index(Key *);
Key *get_hostkey_public_by_index(int, struct ssh *);
Key *get_hostkey_public_by_type(int, int, struct ssh *);
Key *get_hostkey_private_by_type(int, int, struct ssh *);
int get_hostkey_index(Key *, int, struct ssh *);
int ssh1_session_key(BIGNUM *);
void sshd_hostkey_sign(Key *, Key *, u_char **, u_int *, u_char *, u_int);
int sshd_hostkey_sign(Key *, Key *, u_char **, size_t *,
const u_char *, size_t, u_int);
/* debug messages during authentication */
void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2)));

View File

@ -12,6 +12,8 @@
#include "includes.h"
#ifdef WITH_SSH1
#include <sys/types.h>
#include <stdarg.h>
@ -438,3 +440,5 @@ do_authentication(Authctxt *authctxt)
packet_send();
packet_write_wait();
}
#endif /* WITH_SSH1 */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-chall.c,v 1.41 2014/02/02 03:44:31 djm Exp $ */
/* $OpenBSD: auth2-chall.c,v 1.42 2015/01/19 20:07:45 markus Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Per Allansson. All rights reserved.
@ -49,7 +49,7 @@ extern ServerOptions options;
static int auth2_challenge_start(Authctxt *);
static int send_userauth_info_request(Authctxt *);
static void input_userauth_info_response(int, u_int32_t, void *);
static int input_userauth_info_response(int, u_int32_t, void *);
#ifdef BSD_AUTH
extern KbdintDevice bsdauth_device;
@ -284,7 +284,7 @@ send_userauth_info_request(Authctxt *authctxt)
return 1;
}
static void
static int
input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
@ -349,6 +349,7 @@ input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
}
userauth_finish(authctxt, authenticated, "keyboard-interactive",
devicename);
return 0;
}
void

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-gss.c,v 1.21 2014/02/26 20:28:44 djm Exp $ */
/* $OpenBSD: auth2-gss.c,v 1.22 2015/01/19 20:07:45 markus Exp $ */
/*
* Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@ -48,10 +48,10 @@
extern ServerOptions options;
static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
static void input_gssapi_errtok(int, u_int32_t, void *);
static int input_gssapi_token(int type, u_int32_t plen, void *ctxt);
static int input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
static int input_gssapi_errtok(int, u_int32_t, void *);
/*
* We only support those mechanisms that we know about (ie ones that we know
@ -126,7 +126,7 @@ userauth_gssapi(Authctxt *authctxt)
return (0);
}
static void
static int
input_gssapi_token(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
@ -178,9 +178,10 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
}
gss_release_buffer(&min_status, &send_tok);
return 0;
}
static void
static int
input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
@ -212,6 +213,7 @@ input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
/* The client will have already moved on to the next auth */
gss_release_buffer(&maj_status, &send_tok);
return 0;
}
/*
@ -220,7 +222,7 @@ input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
* which only enables it once the GSSAPI exchange is complete.
*/
static void
static int
input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
@ -244,9 +246,10 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
return 0;
}
static void
static int
input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
@ -284,6 +287,7 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
return 0;
}
Authmethod method_gssapi = {

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-hostbased.c,v 1.18 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: auth2-hostbased.c,v 1.24 2015/01/28 22:36:00 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -48,6 +48,7 @@
#endif
#include "monitor_wrap.h"
#include "pathnames.h"
#include "match.h"
/* import */
extern ServerOptions options;
@ -107,6 +108,14 @@ userauth_hostbased(Authctxt *authctxt)
"signature format");
goto done;
}
if (match_pattern_list(sshkey_ssh_name(key),
options.hostbased_key_types,
strlen(options.hostbased_key_types), 0) != 1) {
logit("%s: key type %s not in HostbasedAcceptedKeyTypes",
__func__, sshkey_type(key));
goto done;
}
service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
authctxt->service;
buffer_init(&b);
@ -163,7 +172,7 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
resolvedname = get_canonical_hostname(options.use_dns);
ipaddr = get_remote_ipaddr();
debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
debug2("%s: chost %s resolvedname %s ipaddr %s", __func__,
chost, resolvedname, ipaddr);
if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
@ -172,19 +181,27 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
}
if (options.hostbased_uses_name_from_packet_only) {
if (auth_rhosts2(pw, cuser, chost, chost) == 0)
if (auth_rhosts2(pw, cuser, chost, chost) == 0) {
debug2("%s: auth_rhosts2 refused "
"user \"%.100s\" host \"%.100s\" (from packet)",
__func__, cuser, chost);
return 0;
}
lookup = chost;
} else {
if (strcasecmp(resolvedname, chost) != 0)
logit("userauth_hostbased mismatch: "
"client sends %s, but we resolve %s to %s",
chost, ipaddr, resolvedname);
if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0)
if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0) {
debug2("%s: auth_rhosts2 refused "
"user \"%.100s\" host \"%.100s\" addr \"%.100s\"",
__func__, cuser, resolvedname, ipaddr);
return 0;
}
lookup = resolvedname;
}
debug2("userauth_hostbased: access allowed by auth_rhosts2");
debug2("%s: access allowed by auth_rhosts2", __func__);
if (key_is_cert(key) &&
key_cert_check_authority(key, 1, 0, lookup, &reason)) {
@ -207,14 +224,17 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
if (host_status == HOST_OK) {
if (key_is_cert(key)) {
fp = key_fingerprint(key->cert->signature_key,
SSH_FP_MD5, SSH_FP_HEX);
if ((fp = sshkey_fingerprint(key->cert->signature_key,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal("%s: sshkey_fingerprint fail", __func__);
verbose("Accepted certificate ID \"%s\" signed by "
"%s CA %s from %s@%s", key->cert->key_id,
key_type(key->cert->signature_key), fp,
cuser, lookup);
} else {
fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
if ((fp = sshkey_fingerprint(key,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal("%s: sshkey_fingerprint fail", __func__);
verbose("Accepted %s public key %s from %s@%s",
key_type(key), fp, cuser, lookup);
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-pubkey.c,v 1.41 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: auth2-pubkey.c,v 1.47 2015/02/17 00:14:05 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -41,6 +41,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <limits.h>
#include "xmalloc.h"
#include "ssh.h"
@ -122,6 +123,17 @@ userauth_pubkey(Authctxt *authctxt)
"signature scheme");
goto done;
}
if (auth2_userkey_already_used(authctxt, key)) {
logit("refusing previously-used %s key", key_type(key));
goto done;
}
if (match_pattern_list(sshkey_ssh_name(key), options.pubkey_key_types,
strlen(options.pubkey_key_types), 0) != 1) {
logit("%s: key type %s not in PubkeyAcceptedKeyTypes",
__func__, sshkey_ssh_name(key));
goto done;
}
if (have_sig) {
sig = packet_get_string(&slen);
packet_check_eom();
@ -159,8 +171,12 @@ userauth_pubkey(Authctxt *authctxt)
authenticated = 0;
if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
buffer_len(&b))) == 1)
buffer_len(&b))) == 1) {
authenticated = 1;
/* Record the successful key to prevent reuse */
auth2_record_userkey(authctxt, key);
key = NULL; /* Don't free below */
}
buffer_free(&b);
free(sig);
} else {
@ -212,17 +228,20 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
}
if (key_is_cert(key)) {
fp = key_fingerprint(key->cert->signature_key,
SSH_FP_MD5, SSH_FP_HEX);
fp = sshkey_fingerprint(key->cert->signature_key,
options.fingerprint_hash, SSH_FP_DEFAULT);
auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s",
key_type(key), key->cert->key_id,
(unsigned long long)key->cert->serial,
key_type(key->cert->signature_key), fp,
key_type(key->cert->signature_key),
fp == NULL ? "(null)" : fp,
extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
free(fp);
} else {
fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
auth_info(authctxt, "%s %s%s%s", key_type(key), fp,
fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT);
auth_info(authctxt, "%s %s%s%s", key_type(key),
fp == NULL ? "(null)" : fp,
extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
free(fp);
}
@ -365,8 +384,9 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
continue;
if (!key_is_cert_authority)
continue;
fp = key_fingerprint(found, SSH_FP_MD5,
SSH_FP_HEX);
if ((fp = sshkey_fingerprint(found,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
continue;
debug("matching CA found: file %s, line %lu, %s %s",
file, linenum, key_type(found), fp);
/*
@ -405,11 +425,13 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
continue;
if (key_is_cert_authority)
continue;
found_key = 1;
fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
if ((fp = sshkey_fingerprint(found,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
continue;
debug("matching key found: file %s, line %lu %s %s",
file, linenum, key_type(found), fp);
free(fp);
found_key = 1;
break;
}
}
@ -431,11 +453,12 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
return 0;
ca_fp = key_fingerprint(key->cert->signature_key,
SSH_FP_MD5, SSH_FP_HEX);
if ((ca_fp = sshkey_fingerprint(key->cert->signature_key,
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
return 0;
if (key_in_file(key->cert->signature_key,
options.trusted_user_ca_keys, 1) != 1) {
if (sshkey_in_file(key->cert->signature_key,
options.trusted_user_ca_keys, 1, 0) != 0) {
debug2("%s: CA %s %s is not listed in %s", __func__,
key_type(key->cert->signature_key), ca_fp,
options.trusted_user_ca_keys);
@ -680,6 +703,35 @@ user_key_allowed(struct passwd *pw, Key *key)
return success;
}
/* Records a public key in the list of previously-successful keys */
void
auth2_record_userkey(Authctxt *authctxt, struct sshkey *key)
{
struct sshkey **tmp;
if (authctxt->nprev_userkeys >= INT_MAX ||
(tmp = reallocarray(authctxt->prev_userkeys,
authctxt->nprev_userkeys + 1, sizeof(*tmp))) == NULL)
fatal("%s: reallocarray failed", __func__);
authctxt->prev_userkeys = tmp;
authctxt->prev_userkeys[authctxt->nprev_userkeys] = key;
authctxt->nprev_userkeys++;
}
/* Checks whether a key has already been used successfully for authentication */
int
auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key)
{
u_int i;
for (i = 0; i < authctxt->nprev_userkeys; i++) {
if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) {
return 1;
}
}
return 0;
}
Authmethod method_pubkey = {
"publickey",
userauth_pubkey,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2.c,v 1.132 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: auth2.c,v 1.135 2015/01/19 20:07:45 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -89,8 +89,8 @@ Authmethod *authmethods[] = {
/* protocol */
static void input_service_request(int, u_int32_t, void *);
static void input_userauth_request(int, u_int32_t, void *);
static int input_service_request(int, u_int32_t, void *);
static int input_userauth_request(int, u_int32_t, void *);
/* helper */
static Authmethod *authmethod_lookup(Authctxt *, const char *);
@ -153,9 +153,7 @@ userauth_banner(void)
{
char *banner = NULL;
if (options.banner == NULL ||
strcasecmp(options.banner, "none") == 0 ||
(datafellows & SSH_BUG_BANNER) != 0)
if (options.banner == NULL || (datafellows & SSH_BUG_BANNER) != 0)
return;
if ((banner = PRIVSEP(auth2_read_banner())) == NULL)
@ -178,7 +176,7 @@ do_authentication2(Authctxt *authctxt)
}
/*ARGSUSED*/
static void
static int
input_service_request(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
@ -209,10 +207,11 @@ input_service_request(int type, u_int32_t seq, void *ctxt)
packet_disconnect("bad service request %s", service);
}
free(service);
return 0;
}
/*ARGSUSED*/
static void
static int
input_userauth_request(int type, u_int32_t seq, void *ctxt)
{
Authctxt *authctxt = ctxt;
@ -316,6 +315,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
free(service);
free(user);
free(method);
return 0;
}
void
@ -386,7 +386,7 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
} else {
/* Allow initial try of "none" auth without failure penalty */
if (!authctxt->server_caused_failure &&
if (!partial && !authctxt->server_caused_failure &&
(authctxt->attempt > 1 || strcmp(method, "none") != 0))
authctxt->failures++;
if (authctxt->failures >= options.max_authtries) {

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfd.h,v 1.37 2009/08/27 17:44:52 djm Exp $ */
/* $OpenBSD: authfd.h,v 1.38 2015/01/14 20:05:27 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -16,6 +16,33 @@
#ifndef AUTHFD_H
#define AUTHFD_H
/* List of identities returned by ssh_fetch_identitylist() */
struct ssh_identitylist {
size_t nkeys;
struct sshkey **keys;
char **comments;
};
int ssh_get_authentication_socket(int *fdp);
void ssh_close_authentication_socket(int sock);
int ssh_lock_agent(int sock, int lock, const char *password);
int ssh_fetch_identitylist(int sock, int version,
struct ssh_identitylist **idlp);
void ssh_free_identitylist(struct ssh_identitylist *idl);
int ssh_add_identity_constrained(int sock, struct sshkey *key,
const char *comment, u_int life, u_int confirm);
int ssh_remove_identity(int sock, struct sshkey *key);
int ssh_update_card(int sock, int add, const char *reader_id,
const char *pin, u_int life, u_int confirm);
int ssh_remove_all_identities(int sock, int version);
int ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge,
u_char session_id[16], u_char response[16]);
int ssh_agent_sign(int sock, struct sshkey *key,
u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat);
/* Messages for the authentication agent connection. */
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
@ -60,35 +87,4 @@
#define SSH_AGENT_OLD_SIGNATURE 0x01
typedef struct {
int fd;
Buffer identities;
int howmany;
} AuthenticationConnection;
int ssh_agent_present(void);
int ssh_get_authentication_socket(void);
void ssh_close_authentication_socket(int);
AuthenticationConnection *ssh_get_authentication_connection(void);
void ssh_close_authentication_connection(AuthenticationConnection *);
int ssh_get_num_identities(AuthenticationConnection *, int);
Key *ssh_get_first_identity(AuthenticationConnection *, char **, int);
Key *ssh_get_next_identity(AuthenticationConnection *, char **, int);
int ssh_add_identity_constrained(AuthenticationConnection *, Key *,
const char *, u_int, u_int);
int ssh_remove_identity(AuthenticationConnection *, Key *);
int ssh_remove_all_identities(AuthenticationConnection *, int);
int ssh_lock_agent(AuthenticationConnection *, int, const char *);
int ssh_update_card(AuthenticationConnection *, int, const char *,
const char *, u_int, u_int);
int
ssh_decrypt_challenge(AuthenticationConnection *, Key *, BIGNUM *, u_char[16],
u_int, u_char[16]);
int
ssh_agent_sign(AuthenticationConnection *, Key *, u_char **, u_int *, u_char *,
u_int);
#endif /* AUTHFD_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfile.c,v 1.107 2014/06/24 01:13:21 djm Exp $ */
/* $OpenBSD: authfile.c,v 1.111 2015/02/23 16:55:51 djm Exp $ */
/*
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
*
@ -27,7 +27,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/uio.h>
#include <errno.h>
@ -37,6 +36,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include "cipher.h"
#include "key.h"
@ -48,6 +48,7 @@
#include "atomicio.h"
#include "sshbuf.h"
#include "ssherr.h"
#include "krl.h"
#define MAX_KEY_FILE_SIZE (1024 * 1024)
@ -94,7 +95,7 @@ sshkey_save_private(struct sshkey *key, const char *filename,
/* Load a key from a fd into a buffer */
int
sshkey_load_file(int fd, const char *filename, struct sshbuf *blob)
sshkey_load_file(int fd, struct sshbuf *blob)
{
u_char buf[1024];
size_t len;
@ -141,8 +142,7 @@ sshkey_load_file(int fd, const char *filename, struct sshbuf *blob)
* otherwise.
*/
static int
sshkey_load_public_rsa1(int fd, const char *filename,
struct sshkey **keyp, char **commentp)
sshkey_load_public_rsa1(int fd, struct sshkey **keyp, char **commentp)
{
struct sshbuf *b = NULL;
int r;
@ -153,7 +153,7 @@ sshkey_load_public_rsa1(int fd, const char *filename,
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshkey_load_file(fd, filename, b)) != 0)
if ((r = sshkey_load_file(fd, b)) != 0)
goto out;
if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
goto out;
@ -164,33 +164,6 @@ sshkey_load_public_rsa1(int fd, const char *filename,
}
#endif /* WITH_SSH1 */
#ifdef WITH_OPENSSL
/* XXX Deprecate? */
int
sshkey_load_private_pem(int fd, int type, const char *passphrase,
struct sshkey **keyp, char **commentp)
{
struct sshbuf *buffer = NULL;
int r;
*keyp = NULL;
if (commentp != NULL)
*commentp = NULL;
if ((buffer = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshkey_load_file(fd, NULL, buffer)) != 0)
goto out;
if ((r = sshkey_parse_private_pem_fileblob(buffer, type, passphrase,
keyp, commentp)) != 0)
goto out;
r = 0;
out:
sshbuf_free(buffer);
return r;
}
#endif /* WITH_OPENSSL */
/* XXX remove error() calls from here? */
int
sshkey_perm_ok(int fd, const char *filename)
@ -226,7 +199,6 @@ sshkey_load_private_type(int type, const char *filename, const char *passphrase,
struct sshkey **keyp, char **commentp, int *perm_ok)
{
int fd, r;
struct sshbuf *buffer = NULL;
*keyp = NULL;
if (commentp != NULL)
@ -246,18 +218,31 @@ sshkey_load_private_type(int type, const char *filename, const char *passphrase,
if (perm_ok != NULL)
*perm_ok = 1;
r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
out:
close(fd);
return r;
}
int
sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
struct sshkey **keyp, char **commentp)
{
struct sshbuf *buffer = NULL;
int r;
if ((buffer = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshkey_load_file(fd, filename, buffer)) != 0)
goto out;
if ((r = sshkey_parse_private_fileblob_type(buffer, type, passphrase,
keyp, commentp)) != 0)
if ((r = sshkey_load_file(fd, buffer)) != 0 ||
(r = sshkey_parse_private_fileblob_type(buffer, type,
passphrase, keyp, commentp)) != 0)
goto out;
/* success */
r = 0;
out:
close(fd);
if (buffer != NULL)
sshbuf_free(buffer);
return r;
@ -286,7 +271,7 @@ sshkey_load_private(const char *filename, const char *passphrase,
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshkey_load_file(fd, filename, buffer)) != 0 ||
if ((r = sshkey_load_file(fd, buffer)) != 0 ||
(r = sshkey_parse_private_fileblob(buffer, passphrase, filename,
keyp, commentp)) != 0)
goto out;
@ -350,7 +335,7 @@ int
sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
{
struct sshkey *pub = NULL;
char file[MAXPATHLEN];
char file[PATH_MAX];
int r, fd;
if (keyp != NULL)
@ -358,11 +343,13 @@ sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
if (commentp != NULL)
*commentp = NULL;
/* XXX should load file once and attempt to parse each format */
if ((fd = open(filename, O_RDONLY)) < 0)
goto skip;
#ifdef WITH_SSH1
/* try rsa1 private key */
r = sshkey_load_public_rsa1(fd, filename, keyp, commentp);
r = sshkey_load_public_rsa1(fd, keyp, commentp);
close(fd);
switch (r) {
case SSH_ERR_INTERNAL_ERROR:
@ -409,6 +396,7 @@ sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
return 0;
}
sshkey_free(pub);
return r;
}
@ -494,11 +482,14 @@ sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
/*
* Returns success if the specified "key" is listed in the file "filename",
* SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
* If strict_type is set then the key type must match exactly,
* If "strict_type" is set then the key type must match exactly,
* otherwise a comparison that ignores certficiate data is performed.
* If "check_ca" is set and "key" is a certificate, then its CA key is
* also checked and sshkey_in_file() will return success if either is found.
*/
int
sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
int check_ca)
{
FILE *f;
char line[SSH_MAX_PUBKEY_BYTES];
@ -509,12 +500,8 @@ sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
strict_type ? sshkey_equal : sshkey_equal_public;
if ((f = fopen(filename, "r")) == NULL) {
if (errno == ENOENT)
return SSH_ERR_KEY_NOT_FOUND;
else
return SSH_ERR_SYSTEM_ERROR;
}
if ((f = fopen(filename, "r")) == NULL)
return SSH_ERR_SYSTEM_ERROR;
while (read_keyfile_line(f, filename, line, sizeof(line),
&linenum) != -1) {
@ -538,7 +525,9 @@ sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
}
if ((r = sshkey_read(pub, &cp)) != 0)
goto out;
if (sshkey_compare(key, pub)) {
if (sshkey_compare(key, pub) ||
(check_ca && sshkey_is_cert(key) &&
sshkey_compare(key->cert->signature_key, pub))) {
r = 0;
goto out;
}
@ -553,3 +542,37 @@ sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
return r;
}
/*
* Checks whether the specified key is revoked, returning 0 if not,
* SSH_ERR_KEY_REVOKED if it is or another error code if something
* unexpected happened.
* This will check both the key and, if it is a certificate, its CA key too.
* "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
*/
int
sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
{
int r;
r = ssh_krl_file_contains_key(revoked_keys_file, key);
/* If this was not a KRL to begin with then continue below */
if (r != SSH_ERR_KRL_BAD_MAGIC)
return r;
/*
* If the file is not a KRL or we can't handle KRLs then attempt to
* parse the file as a flat list of keys.
*/
switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
case 0:
/* Key found => revoked */
return SSH_ERR_KEY_REVOKED;
case SSH_ERR_KEY_NOT_FOUND:
/* Key not found => not revoked */
return 0;
default:
/* Some other error occurred */
return r;
}
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfile.h,v 1.19 2014/07/03 23:18:35 djm Exp $ */
/* $OpenBSD: authfile.h,v 1.21 2015/01/08 10:14:08 djm Exp $ */
/*
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
@ -30,9 +30,12 @@
struct sshbuf;
struct sshkey;
/* XXX document these */
/* XXX some of these could probably be merged/retired */
int sshkey_save_private(struct sshkey *, const char *,
const char *, const char *, int, const char *, int);
int sshkey_load_file(int, const char *, struct sshbuf *);
int sshkey_load_file(int, struct sshbuf *);
int sshkey_load_cert(const char *, struct sshkey **);
int sshkey_load_public(const char *, struct sshkey **, char **);
int sshkey_load_private(const char *, const char *, struct sshkey **, char **);
@ -40,8 +43,10 @@ int sshkey_load_private_cert(int, const char *, const char *,
struct sshkey **, int *);
int sshkey_load_private_type(int, const char *, const char *,
struct sshkey **, char **, int *);
int sshkey_load_private_pem(int, int, const char *, struct sshkey **, char **);
int sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
struct sshkey **keyp, char **commentp);
int sshkey_perm_ok(int, const char *);
int sshkey_in_file(struct sshkey *, const char *, int);
int sshkey_in_file(struct sshkey *, const char *, int, int);
int sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file);
#endif

212
crypto/openssh/bitmap.c Normal file
View File

@ -0,0 +1,212 @@
/*
* Copyright (c) 2015 Damien Miller <djm@mindrot.org>
*
* 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.
*/
#include "includes.h"
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include "bitmap.h"
#define BITMAP_WTYPE u_int
#define BITMAP_MAX (1<<24)
#define BITMAP_BYTES (sizeof(BITMAP_WTYPE))
#define BITMAP_BITS (sizeof(BITMAP_WTYPE) * 8)
#define BITMAP_WMASK ((BITMAP_WTYPE)BITMAP_BITS - 1)
struct bitmap {
BITMAP_WTYPE *d;
size_t len; /* number of words allocated */
size_t top; /* index of top word allocated */
};
struct bitmap *
bitmap_new(void)
{
struct bitmap *ret;
if ((ret = calloc(1, sizeof(*ret))) == NULL)
return NULL;
if ((ret->d = calloc(1, BITMAP_BYTES)) == NULL) {
free(ret);
return NULL;
}
ret->len = 1;
ret->top = 0;
return ret;
}
void
bitmap_free(struct bitmap *b)
{
if (b != NULL && b->d != NULL) {
memset(b->d, 0, b->len);
free(b->d);
}
free(b);
}
void
bitmap_zero(struct bitmap *b)
{
memset(b->d, 0, b->len * BITMAP_BYTES);
b->top = 0;
}
int
bitmap_test_bit(struct bitmap *b, u_int n)
{
if (b->top >= b->len)
return 0; /* invalid */
if (b->len == 0 || (n / BITMAP_BITS) > b->top)
return 0;
return (b->d[n / BITMAP_BITS] >> (n & BITMAP_WMASK)) & 1;
}
static int
reserve(struct bitmap *b, u_int n)
{
BITMAP_WTYPE *tmp;
size_t nlen;
if (b->top >= b->len || n > BITMAP_MAX)
return -1; /* invalid */
nlen = (n / BITMAP_BITS) + 1;
if (b->len < nlen) {
if ((tmp = reallocarray(b->d, nlen, BITMAP_BYTES)) == NULL)
return -1;
b->d = tmp;
memset(b->d + b->len, 0, (nlen - b->len) * BITMAP_BYTES);
b->len = nlen;
}
return 0;
}
int
bitmap_set_bit(struct bitmap *b, u_int n)
{
int r;
size_t offset;
if ((r = reserve(b, n)) != 0)
return r;
offset = n / BITMAP_BITS;
if (offset > b->top)
b->top = offset;
b->d[offset] |= (BITMAP_WTYPE)1 << (n & BITMAP_WMASK);
return 0;
}
/* Resets b->top to point to the most significant bit set in b->d */
static void
retop(struct bitmap *b)
{
if (b->top >= b->len)
return;
while (b->top > 0 && b->d[b->top] == 0)
b->top--;
}
void
bitmap_clear_bit(struct bitmap *b, u_int n)
{
size_t offset;
if (b->top >= b->len || n > BITMAP_MAX)
return; /* invalid */
offset = n / BITMAP_BITS;
if (offset > b->top)
return;
b->d[offset] &= ~((BITMAP_WTYPE)1 << (n & BITMAP_WMASK));
/* The top may have changed as a result of the clear */
retop(b);
}
size_t
bitmap_nbits(struct bitmap *b)
{
size_t bits;
BITMAP_WTYPE w;
retop(b);
if (b->top >= b->len)
return 0; /* invalid */
if (b->len == 0 || (b->top == 0 && b->d[0] == 0))
return 0;
/* Find MSB set */
w = b->d[b->top];
bits = (b->top + 1) * BITMAP_BITS;
while (!(w & ((BITMAP_WTYPE)1 << (BITMAP_BITS - 1)))) {
w <<= 1;
bits--;
}
return bits;
}
size_t
bitmap_nbytes(struct bitmap *b)
{
return (bitmap_nbits(b) + 7) / 8;
}
int
bitmap_to_string(struct bitmap *b, void *p, size_t l)
{
u_char *s = (u_char *)p;
size_t i, j, k, need = bitmap_nbytes(b);
if (l < need || b->top >= b->len)
return -1;
if (l > need)
l = need;
/* Put the bytes from LSB backwards */
for (i = k = 0; i < b->top + 1; i++) {
for (j = 0; j < BITMAP_BYTES; j++) {
if (k >= l)
break;
s[need - 1 - k++] = (b->d[i] >> (j * 8)) & 0xff;
}
}
return 0;
}
int
bitmap_from_string(struct bitmap *b, const void *p, size_t l)
{
int r;
size_t i, offset, shift;
u_char *s = (u_char *)p;
if (l > BITMAP_MAX / 8)
return -1;
if ((r = reserve(b, l * 8)) != 0)
return r;
bitmap_zero(b);
if (l == 0)
return 0;
b->top = offset = ((l + (BITMAP_BYTES - 1)) / BITMAP_BYTES) - 1;
shift = ((l + (BITMAP_BYTES - 1)) % BITMAP_BYTES) * 8;
for (i = 0; i < l; i++) {
b->d[offset] |= (BITMAP_WTYPE)s[i] << shift;
if (shift == 0) {
offset--;
shift = BITMAP_BITS - 8;
} else
shift -= 8;
}
retop(b);
return 0;
}

56
crypto/openssh/bitmap.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2015 Damien Miller <djm@mindrot.org>
*
* 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 _BITMAP_H
#define _BITMAP_H
#include <sys/types.h>
/* Simple bit vector routines */
struct bitmap;
/* Allocate a new bitmap. Returns NULL on allocation failure. */
struct bitmap *bitmap_new(void);
/* Free a bitmap */
void bitmap_free(struct bitmap *b);
/* Zero an existing bitmap */
void bitmap_zero(struct bitmap *b);
/* Test whether a bit is set in a bitmap. */
int bitmap_test_bit(struct bitmap *b, u_int n);
/* Set a bit in a bitmap. Returns 0 on success or -1 on error */
int bitmap_set_bit(struct bitmap *b, u_int n);
/* Clear a bit in a bitmap */
void bitmap_clear_bit(struct bitmap *b, u_int n);
/* Return the number of bits in a bitmap (i.e. the position of the MSB) */
size_t bitmap_nbits(struct bitmap *b);
/* Return the number of bytes needed to represent a bitmap */
size_t bitmap_nbytes(struct bitmap *b);
/* Convert a bitmap to a big endian byte string */
int bitmap_to_string(struct bitmap *b, void *p, size_t l);
/* Convert a big endian byte string to a bitmap */
int bitmap_from_string(struct bitmap *b, const void *p, size_t l);
#endif /* _BITMAP_H */

View File

@ -20,12 +20,15 @@
#include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h>
#include "buffer.h"
#include "log.h"
#include "ssherr.h"
#ifdef WITH_SSH1
int
buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
{
@ -63,6 +66,7 @@ buffer_get_bignum(Buffer *buffer, BIGNUM *value)
if (buffer_get_bignum_ret(buffer, value) == -1)
fatal("%s: buffer error", __func__);
}
#endif /* WITH_SSH1 */
int
buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
@ -101,3 +105,5 @@ buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
if (buffer_get_bignum2_ret(buffer, value) == -1)
fatal("%s: buffer error", __func__);
}
#endif /* WITH_OPENSSL */

View File

@ -48,6 +48,7 @@ int buffer_get_ret(Buffer *, void *, u_int);
int buffer_consume_ret(Buffer *, u_int);
int buffer_consume_end_ret(Buffer *, u_int);
#include <openssl/objects.h>
#include <openssl/bn.h>
void buffer_put_bignum(Buffer *, const BIGNUM *);
void buffer_put_bignum2(Buffer *, const BIGNUM *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: canohost.c,v 1.71 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: canohost.c,v 1.72 2015/03/01 15:44:40 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -260,24 +260,29 @@ get_socket_address(int sock, int remote, int flags)
}
/* Work around Linux IPv6 weirdness */
if (addr.ss_family == AF_INET6)
if (addr.ss_family == AF_INET6) {
addrlen = sizeof(struct sockaddr_in6);
ipv64_normalise_mapped(&addr, &addrlen);
}
if (addr.ss_family == AF_UNIX) {
switch (addr.ss_family) {
case AF_INET:
case AF_INET6:
/* Get the address in ascii. */
if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop,
sizeof(ntop), NULL, 0, flags)) != 0) {
error("get_socket_address: getnameinfo %d failed: %s",
flags, ssh_gai_strerror(r));
return NULL;
}
return xstrdup(ntop);
case AF_UNIX:
/* Get the Unix domain socket path. */
return xstrdup(((struct sockaddr_un *)&addr)->sun_path);
}
ipv64_normalise_mapped(&addr, &addrlen);
/* Get the address in ascii. */
if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop,
sizeof(ntop), NULL, 0, flags)) != 0) {
error("get_socket_address: getnameinfo %d failed: %s", flags,
ssh_gai_strerror(r));
default:
/* We can't look up remote Unix domain sockets. */
return NULL;
}
return xstrdup(ntop);
}
char *
@ -390,8 +395,8 @@ get_sock_port(int sock, int local)
if (from.ss_family == AF_INET6)
fromlen = sizeof(struct sockaddr_in6);
/* Unix domain sockets don't have a port number. */
if (from.ss_family == AF_UNIX)
/* Non-inet sockets don't have a port number. */
if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
return 0;
/* Return port number. */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.c,v 1.336 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: channels.c,v 1.341 2015/02/06 23:21:59 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -43,6 +43,7 @@
__RCSID("$FreeBSD$");
#include <sys/types.h>
#include <sys/param.h> /* MIN MAX */
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/un.h>
@ -57,6 +58,9 @@ __RCSID("$FreeBSD$");
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -670,7 +674,7 @@ channel_open_message(void)
}
}
buffer_append(&buffer, "\0", 1);
cp = xstrdup(buffer_ptr(&buffer));
cp = xstrdup((char *)buffer_ptr(&buffer));
buffer_free(&buffer);
return cp;
}
@ -1056,7 +1060,7 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
len = sizeof(s4_req);
if (have < len)
return 0;
p = buffer_ptr(&c->input);
p = (char *)buffer_ptr(&c->input);
need = 1;
/* SOCKS4A uses an invalid IP address 0.0.0.x */
@ -1086,7 +1090,7 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
buffer_get(&c->input, (char *)&s4_req.dest_port, 2);
buffer_get(&c->input, (char *)&s4_req.dest_addr, 4);
have = buffer_len(&c->input);
p = buffer_ptr(&c->input);
p = (char *)buffer_ptr(&c->input);
if (memchr(p, '\0', have) == NULL)
fatal("channel %d: decode socks4: user not nul terminated",
c->self);
@ -1106,7 +1110,7 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
c->path = xstrdup(host);
} else { /* SOCKS4A: two strings */
have = buffer_len(&c->input);
p = buffer_ptr(&c->input);
p = (char *)buffer_ptr(&c->input);
len = strlen(p);
debug2("channel %d: decode socks4a: host %s/%d",
c->self, p, len);
@ -2183,7 +2187,7 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
nfdset = howmany(n+1, NFDBITS);
/* Explicitly test here, because xrealloc isn't always called */
if (nfdset && SIZE_T_MAX / nfdset < sizeof(fd_mask))
if (nfdset && SIZE_MAX / nfdset < sizeof(fd_mask))
fatal("channel_prepare_select: max_fd (%d) is too large", n);
sz = nfdset * sizeof(fd_mask);
@ -2343,7 +2347,7 @@ channel_output_poll(void)
/* -- protocol input */
/* ARGSUSED */
void
int
channel_input_data(int type, u_int32_t seq, void *ctxt)
{
int id;
@ -2360,7 +2364,7 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
/* Ignore any data for non-open channels (might happen on close) */
if (c->type != SSH_CHANNEL_OPEN &&
c->type != SSH_CHANNEL_X11_OPEN)
return;
return 0;
/* Get the data. */
data = packet_get_string_ptr(&data_len);
@ -2380,7 +2384,7 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
c->local_window -= win_len;
c->local_consumed += win_len;
}
return;
return 0;
}
if (compat20) {
@ -2391,7 +2395,7 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
if (win_len > c->local_window) {
logit("channel %d: rcvd too much data %d, win %d",
c->self, win_len, c->local_window);
return;
return 0;
}
c->local_window -= win_len;
}
@ -2400,10 +2404,11 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
else
buffer_append(&c->output, data, data_len);
packet_check_eom();
return 0;
}
/* ARGSUSED */
void
int
channel_input_extended_data(int type, u_int32_t seq, void *ctxt)
{
int id;
@ -2419,7 +2424,7 @@ channel_input_extended_data(int type, u_int32_t seq, void *ctxt)
packet_disconnect("Received extended_data for bad channel %d.", id);
if (c->type != SSH_CHANNEL_OPEN) {
logit("channel %d: ext data for non open", id);
return;
return 0;
}
if (c->flags & CHAN_EOF_RCVD) {
if (datafellows & SSH_BUG_EXTEOF)
@ -2433,7 +2438,7 @@ channel_input_extended_data(int type, u_int32_t seq, void *ctxt)
c->extended_usage != CHAN_EXTENDED_WRITE ||
tcode != SSH2_EXTENDED_DATA_STDERR) {
logit("channel %d: bad ext data", c->self);
return;
return 0;
}
data = packet_get_string(&data_len);
packet_check_eom();
@ -2441,16 +2446,17 @@ channel_input_extended_data(int type, u_int32_t seq, void *ctxt)
logit("channel %d: rcvd too much extended_data %d, win %d",
c->self, data_len, c->local_window);
free(data);
return;
return 0;
}
debug2("channel %d: rcvd ext data %d", c->self, data_len);
c->local_window -= data_len;
buffer_append(&c->extended, data, data_len);
free(data);
return 0;
}
/* ARGSUSED */
void
int
channel_input_ieof(int type, u_int32_t seq, void *ctxt)
{
int id;
@ -2470,11 +2476,11 @@ channel_input_ieof(int type, u_int32_t seq, void *ctxt)
if (buffer_len(&c->input) == 0)
chan_ibuf_empty(c);
}
return 0;
}
/* ARGSUSED */
void
int
channel_input_close(int type, u_int32_t seq, void *ctxt)
{
int id;
@ -2509,11 +2515,12 @@ channel_input_close(int type, u_int32_t seq, void *ctxt)
buffer_clear(&c->input);
c->type = SSH_CHANNEL_OUTPUT_DRAINING;
}
return 0;
}
/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
/* ARGSUSED */
void
int
channel_input_oclose(int type, u_int32_t seq, void *ctxt)
{
int id = packet_get_int();
@ -2523,10 +2530,11 @@ channel_input_oclose(int type, u_int32_t seq, void *ctxt)
if (c == NULL)
packet_disconnect("Received oclose for nonexistent channel %d.", id);
chan_rcvd_oclose(c);
return 0;
}
/* ARGSUSED */
void
int
channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt)
{
int id = packet_get_int();
@ -2540,10 +2548,11 @@ channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt)
packet_disconnect("Received close confirmation for "
"non-closed channel %d (type %d).", id, c->type);
channel_free(c);
return 0;
}
/* ARGSUSED */
void
int
channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
{
int id, remote_id;
@ -2572,6 +2581,7 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
c->remote_window, c->remote_maxpacket);
}
packet_check_eom();
return 0;
}
static char *
@ -2591,7 +2601,7 @@ reason2txt(int reason)
}
/* ARGSUSED */
void
int
channel_input_open_failure(int type, u_int32_t seq, void *ctxt)
{
int id, reason;
@ -2623,10 +2633,11 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt)
packet_check_eom();
/* Schedule the channel for cleanup/deletion. */
chan_mark_dead(c);
return 0;
}
/* ARGSUSED */
void
int
channel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
{
Channel *c;
@ -2634,7 +2645,7 @@ channel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
u_int adjust;
if (!compat20)
return;
return 0;
/* Get the channel number and verify it. */
id = packet_get_int();
@ -2642,16 +2653,17 @@ channel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
if (c == NULL) {
logit("Received window adjust for non-open channel %d.", id);
return;
return 0;
}
adjust = packet_get_int();
packet_check_eom();
debug2("channel %d: rcvd adjust %u", id, adjust);
c->remote_window += adjust;
return 0;
}
/* ARGSUSED */
void
int
channel_input_port_open(int type, u_int32_t seq, void *ctxt)
{
Channel *c = NULL;
@ -2679,10 +2691,11 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt)
packet_send();
} else
c->remote_id = remote_id;
return 0;
}
/* ARGSUSED */
void
int
channel_input_status_confirm(int type, u_int32_t seq, void *ctxt)
{
Channel *c;
@ -2699,15 +2712,15 @@ channel_input_status_confirm(int type, u_int32_t seq, void *ctxt)
if ((c = channel_lookup(id)) == NULL) {
logit("channel_input_status_confirm: %d: unknown", id);
return;
return 0;
}
;
if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
return;
return 0;
cc->cb(type, c, cc->ctx);
TAILQ_REMOVE(&c->status_confirms, cc, entry);
explicit_bzero(cc, sizeof(*cc));
free(cc);
return 0;
}
/* -- tcp forwarding */
@ -4095,7 +4108,7 @@ x11_connect_display(void)
*/
/* ARGSUSED */
void
int
x11_input_open(int type, u_int32_t seq, void *ctxt)
{
Channel *c = NULL;
@ -4135,11 +4148,12 @@ x11_input_open(int type, u_int32_t seq, void *ctxt)
packet_put_int(c->self);
}
packet_send();
return 0;
}
/* dummy protocol handler that denies SSH-1 requests (agent/x11) */
/* ARGSUSED */
void
int
deny_input_open(int type, u_int32_t seq, void *ctxt)
{
int rchan = packet_get_int();
@ -4159,6 +4173,7 @@ deny_input_open(int type, u_int32_t seq, void *ctxt)
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
packet_put_int(rchan);
packet_send();
return 0;
}
/*

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.h,v 1.115 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: channels.h,v 1.116 2015/01/19 20:07:45 markus Exp $ */
/* $FreeBSD$ */
/*
@ -231,17 +231,17 @@ void channel_send_window_changes(void);
/* protocol handler */
void channel_input_close(int, u_int32_t, void *);
void channel_input_close_confirmation(int, u_int32_t, void *);
void channel_input_data(int, u_int32_t, void *);
void channel_input_extended_data(int, u_int32_t, void *);
void channel_input_ieof(int, u_int32_t, void *);
void channel_input_oclose(int, u_int32_t, void *);
void channel_input_open_confirmation(int, u_int32_t, void *);
void channel_input_open_failure(int, u_int32_t, void *);
void channel_input_port_open(int, u_int32_t, void *);
void channel_input_window_adjust(int, u_int32_t, void *);
void channel_input_status_confirm(int, u_int32_t, void *);
int channel_input_close(int, u_int32_t, void *);
int channel_input_close_confirmation(int, u_int32_t, void *);
int channel_input_data(int, u_int32_t, void *);
int channel_input_extended_data(int, u_int32_t, void *);
int channel_input_ieof(int, u_int32_t, void *);
int channel_input_oclose(int, u_int32_t, void *);
int channel_input_open_confirmation(int, u_int32_t, void *);
int channel_input_open_failure(int, u_int32_t, void *);
int channel_input_port_open(int, u_int32_t, void *);
int channel_input_window_adjust(int, u_int32_t, void *);
int channel_input_status_confirm(int, u_int32_t, void *);
/* file descriptor handling (read/write) */
@ -287,10 +287,10 @@ int permitopen_port(const char *);
int x11_connect_display(void);
int x11_create_display_inet(int, int, int, u_int *, int **);
void x11_input_open(int, u_int32_t, void *);
int x11_input_open(int, u_int32_t, void *);
void x11_request_forwarding_with_spoofing(int, const char *, const char *,
const char *, int);
void deny_input_open(int, u_int32_t, void *);
int deny_input_open(int, u_int32_t, void *);
/* agent forwarding */

View File

@ -1,15 +1,10 @@
/* $OpenBSD: cipher-3des1.c,v 1.11 2014/07/02 04:59:06 djm Exp $ */
/* $OpenBSD: cipher-3des1.c,v 1.12 2015/01/14 10:24:42 markus Exp $ */
/*
* Copyright (c) 2003 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@ -26,13 +21,9 @@
#include "includes.h"
#include <sys/types.h>
#include <string.h>
#include <openssl/evp.h>
#include <string.h>
#include "xmalloc.h"
#include "log.h"
#include "ssherr.h"
/*
@ -151,7 +142,7 @@ evp_ssh1_3des(void)
{
static EVP_CIPHER ssh1_3des;
memset(&ssh1_3des, 0, sizeof(EVP_CIPHER));
memset(&ssh1_3des, 0, sizeof(ssh1_3des));
ssh1_3des.nid = NID_undef;
ssh1_3des.block_size = 8;
ssh1_3des.iv_len = 0;

View File

@ -1,6 +1,6 @@
/* $OpenBSD: cipher-aesctr.c,v 1.1 2014/04/29 15:39:33 markus Exp $ */
/* $OpenBSD: cipher-aesctr.c,v 1.2 2015/01/14 10:24:42 markus Exp $ */
/*
* Copyright (c) 2003 Markus Friedl <markus@openbsd.org>
* Copyright (c) 2003 Markus Friedl. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -15,9 +15,13 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <sys/types.h>
#include <string.h>
#ifndef WITH_OPENSSL
#include "cipher-aesctr.h"
/*
@ -25,7 +29,7 @@
* the counter is of size 'len' bytes and stored in network-byte-order.
* (LSB at ctr[len-1], MSB at ctr[0])
*/
static __inline__ void
static inline void
aesctr_inc(u8 *ctr, u32 len)
{
ssize_t i;
@ -76,3 +80,4 @@ aesctr_encrypt_bytes(aesctr_ctx *x,const u8 *m,u8 *c,u32 bytes)
n = (n + 1) % AES_BLOCK_SIZE;
}
}
#endif /* !WITH_OPENSSL */

View File

@ -1,15 +1,10 @@
/* $OpenBSD: cipher-bf1.c,v 1.6 2010/10/01 23:05:32 djm Exp $ */
/* $OpenBSD: cipher-bf1.c,v 1.7 2015/01/14 10:24:42 markus Exp $ */
/*
* Copyright (c) 2003 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@ -25,15 +20,14 @@
#include "includes.h"
#include <sys/types.h>
#ifdef WITH_OPENSSL
#include <openssl/evp.h>
#include <sys/types.h>
#include <stdarg.h>
#include <string.h>
#include "xmalloc.h"
#include "log.h"
#include <openssl/evp.h>
#include "openbsd-compat/openssl-compat.h"
@ -106,3 +100,4 @@ evp_ssh1_bf(void)
ssh1_bf.key_len = 32;
return (&ssh1_bf);
}
#endif /* WITH_OPENSSL */

View File

@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $OpenBSD: cipher-chachapoly.c,v 1.6 2014/07/03 12:42:16 jsing Exp $ */
/* $OpenBSD: cipher-chachapoly.c,v 1.7 2015/01/14 10:24:42 markus Exp $ */
#include "includes.h"
@ -116,4 +116,3 @@ chachapoly_get_length(struct chachapoly_ctx *ctx,
*plenp = PEEK_U32(buf);
return 0;
}

View File

@ -16,7 +16,7 @@
*/
#include "includes.h"
#ifndef OPENSSL_HAVE_EVPCTR
#if defined(WITH_OPENSSL) && !defined(OPENSSL_HAVE_EVPCTR)
#include <sys/types.h>
#include <stdarg.h>
@ -143,4 +143,4 @@ evp_aes_128_ctr(void)
return (&aes_ctr);
}
#endif /* OPENSSL_HAVE_EVPCTR */
#endif /* defined(WITH_OPENSSL) && !defined(OPENSSL_HAVE_EVPCTR) */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: cipher.c,v 1.99 2014/06/24 01:13:21 djm Exp $ */
/* $OpenBSD: cipher.c,v 1.100 2015/01/14 10:29:45 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -512,6 +512,8 @@ cipher_get_keyiv_len(const struct sshcipher_ctx *cc)
ivlen = 24;
else if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
ivlen = 0;
else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
ivlen = sizeof(cc->ac_ctx.ctr);
#ifdef WITH_OPENSSL
else
ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp);
@ -532,6 +534,12 @@ cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
return SSH_ERR_INVALID_ARGUMENT;
return 0;
}
if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
if (len != sizeof(cc->ac_ctx.ctr))
return SSH_ERR_INVALID_ARGUMENT;
memcpy(iv, cc->ac_ctx.ctr, len);
return 0;
}
if ((cc->cipher->flags & CFLAG_NONE) != 0)
return 0;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: cipher.h,v 1.46 2014/06/24 01:13:21 djm Exp $ */
/* $OpenBSD: cipher.h,v 1.47 2015/01/14 10:24:42 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -72,19 +72,19 @@ struct sshcipher_ctx {
const struct sshcipher *cipher;
};
typedef struct sshcipher Cipher ;
typedef struct sshcipher_ctx CipherContext ;
typedef struct sshcipher Cipher;
typedef struct sshcipher_ctx CipherContext;
u_int cipher_mask_ssh1(int);
const struct sshcipher *cipher_by_name(const char *);
const struct sshcipher *cipher_by_number(int);
int cipher_number(const char *);
char *cipher_name(int);
const char *cipher_warning_message(const struct sshcipher_ctx *);
int ciphers_valid(const char *);
char *cipher_alg_list(char, int);
int cipher_init(struct sshcipher_ctx *, const struct sshcipher *,
const u_char *, u_int, const u_char *, u_int, int);
const char* cipher_warning_message(const struct sshcipher_ctx *);
int cipher_crypt(struct sshcipher_ctx *, u_int, u_char *, const u_char *,
u_int, u_int, u_int);
int cipher_get_length(struct sshcipher_ctx *, u_int *, u_int,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.261 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: clientloop.c,v 1.272 2015/02/25 19:54:02 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -62,9 +62,9 @@
#include "includes.h"
__RCSID("$FreeBSD$");
#include <sys/param.h> /* MIN MAX */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
@ -86,6 +86,7 @@ __RCSID("$FreeBSD$");
#include <termios.h>
#include <pwd.h>
#include <unistd.h>
#include <limits.h>
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
@ -111,6 +112,8 @@ __RCSID("$FreeBSD$");
#include "match.h"
#include "msg.h"
#include "roaming.h"
#include "ssherr.h"
#include "hostfile.h"
/* import options */
extern Options options;
@ -192,9 +195,6 @@ TAILQ_HEAD(global_confirms, global_confirm);
static struct global_confirms global_confirms =
TAILQ_HEAD_INITIALIZER(global_confirms);
/*XXX*/
extern Kex *xxx_kex;
void ssh_process_session2_setup(int, int, int, Buffer *);
/* Restores stdin to blocking mode. */
@ -342,12 +342,12 @@ client_x11_get_proto(const char *display, const char *xauth_path,
display = xdisplay;
}
if (trusted == 0) {
xauthdir = xmalloc(MAXPATHLEN);
xauthfile = xmalloc(MAXPATHLEN);
mktemp_proto(xauthdir, MAXPATHLEN);
xauthdir = xmalloc(PATH_MAX);
xauthfile = xmalloc(PATH_MAX);
mktemp_proto(xauthdir, PATH_MAX);
if (mkdtemp(xauthdir) != NULL) {
do_unlink = 1;
snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile",
snprintf(xauthfile, PATH_MAX, "%s/xauthfile",
xauthdir);
snprintf(cmd, sizeof(cmd),
"%s -f %s generate %s " SSH_X11_PROTO
@ -539,13 +539,13 @@ client_check_window_change(void)
}
}
static void
static int
client_global_request_reply(int type, u_int32_t seq, void *ctxt)
{
struct global_confirm *gc;
if ((gc = TAILQ_FIRST(&global_confirms)) == NULL)
return;
return 0;
if (gc->cb != NULL)
gc->cb(type, seq, gc->ctx);
if (--gc->ref_count <= 0) {
@ -555,6 +555,7 @@ client_global_request_reply(int type, u_int32_t seq, void *ctxt)
}
packet_set_alive_timeouts(0);
return 0;
}
static void
@ -1415,8 +1416,7 @@ client_process_output(fd_set *writeset)
static void
client_process_buffered_input_packets(void)
{
dispatch_run(DISPATCH_NONBLOCK, &quit_pending,
compat20 ? xxx_kex : NULL);
dispatch_run(DISPATCH_NONBLOCK, &quit_pending, active_state);
}
/* scan buf[] for '~' before sending data to the peer */
@ -1470,7 +1470,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
{
fd_set *readset = NULL, *writeset = NULL;
double start_time, total_time;
int max_fd = 0, max_fd2 = 0, len, rekeying = 0;
int r, max_fd = 0, max_fd2 = 0, len, rekeying = 0;
u_int64_t ibytes, obytes;
u_int nalloc = 0;
char buf[100];
@ -1555,7 +1555,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
if (compat20 && session_closed && !channel_still_open())
break;
rekeying = (xxx_kex != NULL && !xxx_kex->done);
rekeying = (active_state->kex != NULL && !active_state->kex->done);
if (rekeying) {
debug("rekeying in progress");
@ -1599,8 +1599,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
channel_after_select(readset, writeset);
if (need_rekeying || packet_need_rekeying()) {
debug("need rekeying");
xxx_kex->done = 0;
kex_send_kexinit(xxx_kex);
active_state->kex->done = 0;
if ((r = kex_send_kexinit(active_state)) != 0)
fatal("%s: kex_send_kexinit: %s",
__func__, ssh_err(r));
need_rekeying = 0;
}
}
@ -1729,8 +1731,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
/* Report bytes transferred, and transfer rates. */
total_time = get_current_time() - start_time;
packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes);
packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes);
packet_get_bytes(&ibytes, &obytes);
verbose("Transferred: sent %llu, received %llu bytes, in %.1f seconds",
(unsigned long long)obytes, (unsigned long long)ibytes, total_time);
if (total_time > 0)
@ -1743,7 +1744,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
/*********/
static void
static int
client_input_stdout_data(int type, u_int32_t seq, void *ctxt)
{
u_int data_len;
@ -1752,8 +1753,9 @@ client_input_stdout_data(int type, u_int32_t seq, void *ctxt)
buffer_append(&stdout_buffer, data, data_len);
explicit_bzero(data, data_len);
free(data);
return 0;
}
static void
static int
client_input_stderr_data(int type, u_int32_t seq, void *ctxt)
{
u_int data_len;
@ -1762,8 +1764,9 @@ client_input_stderr_data(int type, u_int32_t seq, void *ctxt)
buffer_append(&stderr_buffer, data, data_len);
explicit_bzero(data, data_len);
free(data);
return 0;
}
static void
static int
client_input_exit_status(int type, u_int32_t seq, void *ctxt)
{
exit_status = packet_get_int();
@ -1778,12 +1781,14 @@ client_input_exit_status(int type, u_int32_t seq, void *ctxt)
packet_write_wait();
/* Flag that we want to exit. */
quit_pending = 1;
return 0;
}
static void
static int
client_input_agent_open(int type, u_int32_t seq, void *ctxt)
{
Channel *c = NULL;
int remote_id, sock;
int r, remote_id, sock;
/* Read the remote channel number from the message. */
remote_id = packet_get_int();
@ -1793,7 +1798,11 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt)
* Get a connection to the local authentication agent (this may again
* get forwarded).
*/
sock = ssh_get_authentication_socket();
if ((r = ssh_get_authentication_socket(&sock)) != 0 &&
r != SSH_ERR_AGENT_NOT_PRESENT)
debug("%s: ssh_get_authentication_socket: %s",
__func__, ssh_err(r));
/*
* If we could not connect the agent, send an error message back to
@ -1818,6 +1827,7 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt)
packet_put_int(c->self);
}
packet_send();
return 0;
}
static Channel *
@ -1911,7 +1921,7 @@ static Channel *
client_request_agent(const char *request_type, int rchan)
{
Channel *c = NULL;
int sock;
int r, sock;
if (!options.forward_agent) {
error("Warning: ssh server tried agent forwarding.");
@ -1919,9 +1929,12 @@ client_request_agent(const char *request_type, int rchan)
"malicious server.");
return NULL;
}
sock = ssh_get_authentication_socket();
if (sock < 0)
if ((r = ssh_get_authentication_socket(&sock)) != 0) {
if (r != SSH_ERR_AGENT_NOT_PRESENT)
debug("%s: ssh_get_authentication_socket: %s",
__func__, ssh_err(r));
return NULL;
}
c = channel_new("authentication agent connection",
SSH_CHANNEL_OPEN, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
@ -1975,7 +1988,7 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun)
}
/* XXXX move to generic input handler */
static void
static int
client_input_channel_open(int type, u_int32_t seq, void *ctxt)
{
Channel *c = NULL;
@ -2026,8 +2039,10 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
packet_send();
}
free(ctype);
return 0;
}
static void
static int
client_input_channel_req(int type, u_int32_t seq, void *ctxt)
{
Channel *c = NULL;
@ -2072,18 +2087,395 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
packet_send();
}
free(rtype);
return 0;
}
struct hostkeys_update_ctx {
/* The hostname and (optionally) IP address string for the server */
char *host_str, *ip_str;
/*
* Keys received from the server and a flag for each indicating
* whether they already exist in known_hosts.
* keys_seen is filled in by hostkeys_find() and later (for new
* keys) by client_global_hostkeys_private_confirm().
*/
struct sshkey **keys;
int *keys_seen;
size_t nkeys;
size_t nnew;
/*
* Keys that are in known_hosts, but were not present in the update
* from the server (i.e. scheduled to be deleted).
* Filled in by hostkeys_find().
*/
struct sshkey **old_keys;
size_t nold;
};
static void
hostkeys_update_ctx_free(struct hostkeys_update_ctx *ctx)
{
size_t i;
if (ctx == NULL)
return;
for (i = 0; i < ctx->nkeys; i++)
sshkey_free(ctx->keys[i]);
free(ctx->keys);
free(ctx->keys_seen);
for (i = 0; i < ctx->nold; i++)
sshkey_free(ctx->old_keys[i]);
free(ctx->old_keys);
free(ctx->host_str);
free(ctx->ip_str);
free(ctx);
}
static int
hostkeys_find(struct hostkey_foreach_line *l, void *_ctx)
{
struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
size_t i;
struct sshkey **tmp;
if (l->status != HKF_STATUS_MATCHED || l->key == NULL ||
l->key->type == KEY_RSA1)
return 0;
/* Mark off keys we've already seen for this host */
for (i = 0; i < ctx->nkeys; i++) {
if (sshkey_equal(l->key, ctx->keys[i])) {
debug3("%s: found %s key at %s:%ld", __func__,
sshkey_ssh_name(ctx->keys[i]), l->path, l->linenum);
ctx->keys_seen[i] = 1;
return 0;
}
}
/* This line contained a key that not offered by the server */
debug3("%s: deprecated %s key at %s:%ld", __func__,
sshkey_ssh_name(l->key), l->path, l->linenum);
if ((tmp = reallocarray(ctx->old_keys, ctx->nold + 1,
sizeof(*ctx->old_keys))) == NULL)
fatal("%s: reallocarray failed nold = %zu",
__func__, ctx->nold);
ctx->old_keys = tmp;
ctx->old_keys[ctx->nold++] = l->key;
l->key = NULL;
return 0;
}
static void
update_known_hosts(struct hostkeys_update_ctx *ctx)
{
int r, was_raw = 0;
int loglevel = options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK ?
SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_VERBOSE;
char *fp, *response;
size_t i;
for (i = 0; i < ctx->nkeys; i++) {
if (ctx->keys_seen[i] != 2)
continue;
if ((fp = sshkey_fingerprint(ctx->keys[i],
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal("%s: sshkey_fingerprint failed", __func__);
do_log2(loglevel, "Learned new hostkey: %s %s",
sshkey_type(ctx->keys[i]), fp);
free(fp);
}
for (i = 0; i < ctx->nold; i++) {
if ((fp = sshkey_fingerprint(ctx->old_keys[i],
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
fatal("%s: sshkey_fingerprint failed", __func__);
do_log2(loglevel, "Deprecating obsolete hostkey: %s %s",
sshkey_type(ctx->old_keys[i]), fp);
free(fp);
}
if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) {
if (get_saved_tio() != NULL) {
leave_raw_mode(1);
was_raw = 1;
}
response = NULL;
for (i = 0; !quit_pending && i < 3; i++) {
free(response);
response = read_passphrase("Accept updated hostkeys? "
"(yes/no): ", RP_ECHO);
if (strcasecmp(response, "yes") == 0)
break;
else if (quit_pending || response == NULL ||
strcasecmp(response, "no") == 0) {
options.update_hostkeys = 0;
break;
} else {
do_log2(loglevel, "Please enter "
"\"yes\" or \"no\"");
}
}
if (quit_pending || i >= 3 || response == NULL)
options.update_hostkeys = 0;
free(response);
if (was_raw)
enter_raw_mode(1);
}
/*
* Now that all the keys are verified, we can go ahead and replace
* them in known_hosts (assuming SSH_UPDATE_HOSTKEYS_ASK didn't
* cancel the operation).
*/
if (options.update_hostkeys != 0 &&
(r = hostfile_replace_entries(options.user_hostfiles[0],
ctx->host_str, ctx->ip_str, ctx->keys, ctx->nkeys,
options.hash_known_hosts, 0,
options.fingerprint_hash)) != 0)
error("%s: hostfile_replace_entries failed: %s",
__func__, ssh_err(r));
}
static void
client_global_hostkeys_private_confirm(int type, u_int32_t seq, void *_ctx)
{
struct ssh *ssh = active_state; /* XXX */
struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
size_t i, ndone;
struct sshbuf *signdata;
int r;
const u_char *sig;
size_t siglen;
if (ctx->nnew == 0)
fatal("%s: ctx->nnew == 0", __func__); /* sanity */
if (type != SSH2_MSG_REQUEST_SUCCESS) {
error("Server failed to confirm ownership of "
"private host keys");
hostkeys_update_ctx_free(ctx);
return;
}
if ((signdata = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
/* Don't want to accidentally accept an unbound signature */
if (ssh->kex->session_id_len == 0)
fatal("%s: ssh->kex->session_id_len == 0", __func__);
/*
* Expect a signature for each of the ctx->nnew private keys we
* haven't seen before. They will be in the same order as the
* ctx->keys where the corresponding ctx->keys_seen[i] == 0.
*/
for (ndone = i = 0; i < ctx->nkeys; i++) {
if (ctx->keys_seen[i])
continue;
/* Prepare data to be signed: session ID, unique string, key */
sshbuf_reset(signdata);
if ( (r = sshbuf_put_cstring(signdata,
"hostkeys-prove-00@openssh.com")) != 0 ||
(r = sshbuf_put_string(signdata, ssh->kex->session_id,
ssh->kex->session_id_len)) != 0 ||
(r = sshkey_puts(ctx->keys[i], signdata)) != 0)
fatal("%s: failed to prepare signature: %s",
__func__, ssh_err(r));
/* Extract and verify signature */
if ((r = sshpkt_get_string_direct(ssh, &sig, &siglen)) != 0) {
error("%s: couldn't parse message: %s",
__func__, ssh_err(r));
goto out;
}
if ((r = sshkey_verify(ctx->keys[i], sig, siglen,
sshbuf_ptr(signdata), sshbuf_len(signdata), 0)) != 0) {
error("%s: server gave bad signature for %s key %zu",
__func__, sshkey_type(ctx->keys[i]), i);
goto out;
}
/* Key is good. Mark it as 'seen' */
ctx->keys_seen[i] = 2;
ndone++;
}
if (ndone != ctx->nnew)
fatal("%s: ndone != ctx->nnew (%zu / %zu)", __func__,
ndone, ctx->nnew); /* Shouldn't happen */
ssh_packet_check_eom(ssh);
/* Make the edits to known_hosts */
update_known_hosts(ctx);
out:
hostkeys_update_ctx_free(ctx);
}
/*
* Handle hostkeys-00@openssh.com global request to inform the client of all
* the server's hostkeys. The keys are checked against the user's
* HostkeyAlgorithms preference before they are accepted.
*/
static int
client_input_hostkeys(void)
{
struct ssh *ssh = active_state; /* XXX */
const u_char *blob = NULL;
size_t i, len = 0;
struct sshbuf *buf = NULL;
struct sshkey *key = NULL, **tmp;
int r;
char *fp;
static int hostkeys_seen = 0; /* XXX use struct ssh */
extern struct sockaddr_storage hostaddr; /* XXX from ssh.c */
struct hostkeys_update_ctx *ctx = NULL;
if (hostkeys_seen)
fatal("%s: server already sent hostkeys", __func__);
if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK &&
options.batch_mode)
return 1; /* won't ask in batchmode, so don't even try */
if (!options.update_hostkeys || options.num_user_hostfiles <= 0)
return 1;
ctx = xcalloc(1, sizeof(*ctx));
while (ssh_packet_remaining(ssh) > 0) {
sshkey_free(key);
key = NULL;
if ((r = sshpkt_get_string_direct(ssh, &blob, &len)) != 0) {
error("%s: couldn't parse message: %s",
__func__, ssh_err(r));
goto out;
}
if ((r = sshkey_from_blob(blob, len, &key)) != 0) {
error("%s: parse key: %s", __func__, ssh_err(r));
goto out;
}
fp = sshkey_fingerprint(key, options.fingerprint_hash,
SSH_FP_DEFAULT);
debug3("%s: received %s key %s", __func__,
sshkey_type(key), fp);
free(fp);
/* Check that the key is accepted in HostkeyAlgorithms */
if (options.hostkeyalgorithms != NULL &&
match_pattern_list(sshkey_ssh_name(key),
options.hostkeyalgorithms,
strlen(options.hostkeyalgorithms), 0) != 1) {
debug3("%s: %s key not permitted by HostkeyAlgorithms",
__func__, sshkey_ssh_name(key));
continue;
}
/* Skip certs */
if (sshkey_is_cert(key)) {
debug3("%s: %s key is a certificate; skipping",
__func__, sshkey_ssh_name(key));
continue;
}
/* Ensure keys are unique */
for (i = 0; i < ctx->nkeys; i++) {
if (sshkey_equal(key, ctx->keys[i])) {
error("%s: received duplicated %s host key",
__func__, sshkey_ssh_name(key));
goto out;
}
}
/* Key is good, record it */
if ((tmp = reallocarray(ctx->keys, ctx->nkeys + 1,
sizeof(*ctx->keys))) == NULL)
fatal("%s: reallocarray failed nkeys = %zu",
__func__, ctx->nkeys);
ctx->keys = tmp;
ctx->keys[ctx->nkeys++] = key;
key = NULL;
}
if (ctx->nkeys == 0) {
debug("%s: server sent no hostkeys", __func__);
goto out;
}
if ((ctx->keys_seen = calloc(ctx->nkeys,
sizeof(*ctx->keys_seen))) == NULL)
fatal("%s: calloc failed", __func__);
get_hostfile_hostname_ipaddr(host,
options.check_host_ip ? (struct sockaddr *)&hostaddr : NULL,
options.port, &ctx->host_str,
options.check_host_ip ? &ctx->ip_str : NULL);
/* Find which keys we already know about. */
if ((r = hostkeys_foreach(options.user_hostfiles[0], hostkeys_find,
ctx, ctx->host_str, ctx->ip_str,
HKF_WANT_PARSE_KEY|HKF_WANT_MATCH)) != 0) {
error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r));
goto out;
}
/* Figure out if we have any new keys to add */
ctx->nnew = 0;
for (i = 0; i < ctx->nkeys; i++) {
if (!ctx->keys_seen[i])
ctx->nnew++;
}
debug3("%s: %zu keys from server: %zu new, %zu retained. %zu to remove",
__func__, ctx->nkeys, ctx->nnew, ctx->nkeys - ctx->nnew, ctx->nold);
if (ctx->nnew == 0 && ctx->nold != 0) {
/* We have some keys to remove. Just do it. */
update_known_hosts(ctx);
} else if (ctx->nnew != 0) {
/*
* We have received hitherto-unseen keys from the server.
* Ask the server to confirm ownership of the private halves.
*/
debug3("%s: asking server to prove ownership for %zu keys",
__func__, ctx->nnew);
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh,
"hostkeys-prove-00@openssh.com")) != 0 ||
(r = sshpkt_put_u8(ssh, 1)) != 0) /* bool: want reply */
fatal("%s: cannot prepare packet: %s",
__func__, ssh_err(r));
if ((buf = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new", __func__);
for (i = 0; i < ctx->nkeys; i++) {
if (ctx->keys_seen[i])
continue;
sshbuf_reset(buf);
if ((r = sshkey_putb(ctx->keys[i], buf)) != 0)
fatal("%s: sshkey_putb: %s",
__func__, ssh_err(r));
if ((r = sshpkt_put_stringb(ssh, buf)) != 0)
fatal("%s: sshpkt_put_string: %s",
__func__, ssh_err(r));
}
if ((r = sshpkt_send(ssh)) != 0)
fatal("%s: sshpkt_send: %s", __func__, ssh_err(r));
client_register_global_confirm(
client_global_hostkeys_private_confirm, ctx);
ctx = NULL; /* will be freed in callback */
}
/* Success */
out:
hostkeys_update_ctx_free(ctx);
sshkey_free(key);
sshbuf_free(buf);
/*
* NB. Return success for all cases. The server doesn't need to know
* what the client does with its hosts file.
*/
return 1;
}
static int
client_input_global_request(int type, u_int32_t seq, void *ctxt)
{
char *rtype;
int want_reply;
int success = 0;
rtype = packet_get_string(NULL);
rtype = packet_get_cstring(NULL);
want_reply = packet_get_char();
debug("client_input_global_request: rtype %s want_reply %d",
rtype, want_reply);
if (strcmp(rtype, "hostkeys-00@openssh.com") == 0)
success = client_input_hostkeys();
if (want_reply) {
packet_start(success ?
SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
@ -2091,6 +2483,7 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt)
packet_write_wait();
}
free(rtype);
return 0;
}
void

View File

@ -1,4 +1,4 @@
/* $OpenBSD: compat.c,v 1.85 2014/04/20 02:49:32 djm Exp $ */
/* $OpenBSD: compat.c,v 1.87 2015/01/19 20:20:20 markus Exp $ */
/*
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
@ -58,7 +58,7 @@ enable_compat13(void)
compat13 = 1;
}
/* datafellows bug compatibility */
void
u_int
compat_datafellows(const char *version)
{
int i;
@ -175,13 +175,14 @@ compat_datafellows(const char *version)
for (i = 0; check[i].pat; i++) {
if (match_pattern_list(version, check[i].pat,
strlen(check[i].pat), 0) == 1) {
datafellows = check[i].bugs;
debug("match: %s pat %s compat 0x%08x",
version, check[i].pat, datafellows);
return;
version, check[i].pat, check[i].bugs);
datafellows = check[i].bugs; /* XXX for now */
return check[i].bugs;
}
}
debug("no match: %s", version);
return 0;
}
#define SEP ","
@ -193,7 +194,9 @@ proto_spec(const char *spec)
if (spec == NULL)
return ret;
q = s = xstrdup(spec);
q = s = strdup(spec);
if (s == NULL)
return ret;
for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) {
switch (atoi(p)) {
case 1:
@ -235,7 +238,7 @@ filter_proposal(char *proposal, const char *filter)
debug2("Compat: skipping algorithm \"%s\"", cp);
}
buffer_append(&b, "\0", 1);
fix_prop = xstrdup(buffer_ptr(&b));
fix_prop = xstrdup((char *)buffer_ptr(&b));
buffer_free(&b);
free(orig_prop);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: compat.h,v 1.45 2014/04/18 23:52:25 djm Exp $ */
/* $OpenBSD: compat.h,v 1.46 2015/01/19 20:20:20 markus Exp $ */
/* $FreeBSD$ */
/*
@ -64,7 +64,7 @@
void enable_compat13(void);
void enable_compat20(void);
void compat_datafellows(const char *);
u_int compat_datafellows(const char *);
int proto_spec(const char *);
char *compat_cipher_proposal(char *);
char *compat_pkalg_proposal(char *);

View File

@ -1,167 +0,0 @@
/* $OpenBSD: compress.c,v 1.26 2010/09/08 04:13:31 deraadt Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Interface to packet compression for ssh.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#include "includes.h"
#include <sys/types.h>
#include <stdarg.h>
#include "log.h"
#include "buffer.h"
#include "compress.h"
#include <zlib.h>
z_stream incoming_stream;
z_stream outgoing_stream;
static int compress_init_send_called = 0;
static int compress_init_recv_called = 0;
static int inflate_failed = 0;
static int deflate_failed = 0;
/*
* Initializes compression; level is compression level from 1 to 9
* (as in gzip).
*/
void
buffer_compress_init_send(int level)
{
if (compress_init_send_called == 1)
deflateEnd(&outgoing_stream);
compress_init_send_called = 1;
debug("Enabling compression at level %d.", level);
if (level < 1 || level > 9)
fatal("Bad compression level %d.", level);
deflateInit(&outgoing_stream, level);
}
void
buffer_compress_init_recv(void)
{
if (compress_init_recv_called == 1)
inflateEnd(&incoming_stream);
compress_init_recv_called = 1;
inflateInit(&incoming_stream);
}
/* Frees any data structures allocated for compression. */
void
buffer_compress_uninit(void)
{
debug("compress outgoing: raw data %llu, compressed %llu, factor %.2f",
(unsigned long long)outgoing_stream.total_in,
(unsigned long long)outgoing_stream.total_out,
outgoing_stream.total_in == 0 ? 0.0 :
(double) outgoing_stream.total_out / outgoing_stream.total_in);
debug("compress incoming: raw data %llu, compressed %llu, factor %.2f",
(unsigned long long)incoming_stream.total_out,
(unsigned long long)incoming_stream.total_in,
incoming_stream.total_out == 0 ? 0.0 :
(double) incoming_stream.total_in / incoming_stream.total_out);
if (compress_init_recv_called == 1 && inflate_failed == 0)
inflateEnd(&incoming_stream);
if (compress_init_send_called == 1 && deflate_failed == 0)
deflateEnd(&outgoing_stream);
}
/*
* Compresses the contents of input_buffer into output_buffer. All packets
* compressed using this function will form a single compressed data stream;
* however, data will be flushed at the end of every call so that each
* output_buffer can be decompressed independently (but in the appropriate
* order since they together form a single compression stream) by the
* receiver. This appends the compressed data to the output buffer.
*/
void
buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
{
u_char buf[4096];
int status;
/* This case is not handled below. */
if (buffer_len(input_buffer) == 0)
return;
/* Input is the contents of the input buffer. */
outgoing_stream.next_in = buffer_ptr(input_buffer);
outgoing_stream.avail_in = buffer_len(input_buffer);
/* Loop compressing until deflate() returns with avail_out != 0. */
do {
/* Set up fixed-size output buffer. */
outgoing_stream.next_out = buf;
outgoing_stream.avail_out = sizeof(buf);
/* Compress as much data into the buffer as possible. */
status = deflate(&outgoing_stream, Z_PARTIAL_FLUSH);
switch (status) {
case Z_OK:
/* Append compressed data to output_buffer. */
buffer_append(output_buffer, buf,
sizeof(buf) - outgoing_stream.avail_out);
break;
default:
deflate_failed = 1;
fatal("buffer_compress: deflate returned %d", status);
/* NOTREACHED */
}
} while (outgoing_stream.avail_out == 0);
}
/*
* Uncompresses the contents of input_buffer into output_buffer. All packets
* uncompressed using this function will form a single compressed data
* stream; however, data will be flushed at the end of every call so that
* each output_buffer. This must be called for the same size units that the
* buffer_compress was called, and in the same order that buffers compressed
* with that. This appends the uncompressed data to the output buffer.
*/
void
buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
{
u_char buf[4096];
int status;
incoming_stream.next_in = buffer_ptr(input_buffer);
incoming_stream.avail_in = buffer_len(input_buffer);
for (;;) {
/* Set up fixed-size output buffer. */
incoming_stream.next_out = buf;
incoming_stream.avail_out = sizeof(buf);
status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);
switch (status) {
case Z_OK:
buffer_append(output_buffer, buf,
sizeof(buf) - incoming_stream.avail_out);
break;
case Z_BUF_ERROR:
/*
* Comments in zlib.h say that we should keep calling
* inflate() until we get an error. This appears to
* be the error that we get.
*/
return;
default:
inflate_failed = 1;
fatal("buffer_uncompress: inflate returned %d", status);
/* NOTREACHED */
}
}
}

View File

@ -1,25 +0,0 @@
/* $OpenBSD: compress.h,v 1.12 2006/03/25 22:22:43 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Interface to packet compression for ssh.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#ifndef COMPRESS_H
#define COMPRESS_H
void buffer_compress_init_send(int);
void buffer_compress_init_recv(void);
void buffer_compress_uninit(void);
void buffer_compress(Buffer *, Buffer *);
void buffer_uncompress(Buffer *, Buffer *);
#endif /* COMPRESS_H */

View File

@ -292,6 +292,10 @@
/* Define if your libraries define daemon() */
#define HAVE_DAEMON 1
/* Define to 1 if you have the declaration of `AI_NUMERICSERV', and to 0 if
you don't. */
#define HAVE_DECL_AI_NUMERICSERV 1
/* Define to 1 if you have the declaration of `authenticate', and to 0 if you
don't. */
/* #undef HAVE_DECL_AUTHENTICATE */
@ -875,6 +879,9 @@
/* Define to 1 if you have the <readpassphrase.h> header file. */
#define HAVE_READPASSPHRASE_H 1
/* Define to 1 if you have the `reallocarray' function. */
#define HAVE_REALLOCARRAY 1
/* Define to 1 if you have the `realpath' function. */
#define HAVE_REALPATH 1
@ -1471,7 +1478,7 @@
/* libcrypto is missing AES 192 and 256 bit functions */
/* #undef OPENSSL_LOBOTOMISED_AES */
/* Define if you want OpenSSL's internally seeded PRNG only */
/* Define if you want the OpenSSL internally seeded PRNG only */
#define OPENSSL_PRNG_ONLY 1
/* Define to the address where bug reports for this package should be sent. */

View File

@ -291,6 +291,10 @@
/* Define if your libraries define daemon() */
#undef HAVE_DAEMON
/* Define to 1 if you have the declaration of `AI_NUMERICSERV', and to 0 if
you don't. */
#undef HAVE_DECL_AI_NUMERICSERV
/* Define to 1 if you have the declaration of `authenticate', and to 0 if you
don't. */
#undef HAVE_DECL_AUTHENTICATE
@ -874,6 +878,9 @@
/* Define to 1 if you have the <readpassphrase.h> header file. */
#undef HAVE_READPASSPHRASE_H
/* Define to 1 if you have the `reallocarray' function. */
#undef HAVE_REALLOCARRAY
/* Define to 1 if you have the `realpath' function. */
#undef HAVE_REALPATH
@ -1470,7 +1477,7 @@
/* libcrypto is missing AES 192 and 256 bit functions */
#undef OPENSSL_LOBOTOMISED_AES
/* Define if you want OpenSSL's internally seeded PRNG only */
/* Define if you want the OpenSSL internally seeded PRNG only */
#undef OPENSSL_PRNG_ONLY
/* Define to the address where bug reports for this package should be sent. */

1039
crypto/openssh/configure vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,12 +4,12 @@ all:
@echo "Valid targets: gnome-ssh-askpass1 gnome-ssh-askpass2"
gnome-ssh-askpass1: gnome-ssh-askpass1.c
$(CC) `gnome-config --cflags gnome gnomeui` \
$(CC) $(CFLAGS) `gnome-config --cflags gnome gnomeui` \
gnome-ssh-askpass1.c -o gnome-ssh-askpass1 \
`gnome-config --libs gnome gnomeui`
gnome-ssh-askpass2: gnome-ssh-askpass2.c
$(CC) `$(PKG_CONFIG) --cflags gtk+-2.0` \
$(CC) $(CFLAGS) `$(PKG_CONFIG) --cflags gtk+-2.0` \
gnome-ssh-askpass2.c -o gnome-ssh-askpass2 \
`$(PKG_CONFIG) --libs gtk+-2.0 x11`

View File

@ -1,365 +0,0 @@
# Some of this will need re-evaluation post-LSB. The SVIdir is there
# because the link appeared broken. The rest is for easy compilation,
# the tradeoff open to discussion. (LC957)
%define SVIdir /etc/rc.d/init.d
%{!?_defaultdocdir:%define _defaultdocdir %{_prefix}/share/doc/packages}
%{!?SVIcdir:%define SVIcdir /etc/sysconfig/daemons}
%define _mandir %{_prefix}/share/man/en
%define _sysconfdir /etc/ssh
%define _libexecdir %{_libdir}/ssh
# Do we want to disable root_login? (1=yes 0=no)
%define no_root_login 0
#old cvs stuff. please update before use. may be deprecated.
%define use_stable 1
%define version 6.7p1
%if %{use_stable}
%define cvs %{nil}
%define release 1
%else
%define cvs cvs20050315
%define release 0r1
%endif
%define xsa x11-ssh-askpass
%define askpass %{xsa}-1.2.4.1
# OpenSSH privilege separation requires a user & group ID
%define sshd_uid 67
%define sshd_gid 67
Name : openssh
Version : %{version}%{cvs}
Release : %{release}
Group : System/Network
Summary : OpenSSH free Secure Shell (SSH) implementation.
Summary(de) : OpenSSH - freie Implementation der Secure Shell (SSH).
Summary(es) : OpenSSH implementación libre de Secure Shell (SSH).
Summary(fr) : Implémentation libre du shell sécurisé OpenSSH (SSH).
Summary(it) : Implementazione gratuita OpenSSH della Secure Shell.
Summary(pt) : Implementação livre OpenSSH do protocolo 'Secure Shell' (SSH).
Summary(pt_BR) : Implementação livre OpenSSH do protocolo Secure Shell (SSH).
Copyright : BSD
Packager : Raymund Will <ray@caldera.de>
URL : http://www.openssh.com/
Obsoletes : ssh, ssh-clients, openssh-clients
BuildRoot : /tmp/%{name}-%{version}
BuildRequires : XFree86-imake
# %{use_stable}==1: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable
# %{use_stable}==0: :pserver:cvs@bass.directhit.com:/cvs/openssh_cvs
Source0: see-above:/.../openssh-%{version}.tar.gz
%if %{use_stable}
Source1: see-above:/.../openssh-%{version}.tar.gz.asc
%endif
Source2: http://www.jmknoble.net/software/%{xsa}/%{askpass}.tar.gz
Source3: http://www.openssh.com/faq.html
%Package server
Group : System/Network
Requires : openssh = %{version}
Obsoletes : ssh-server
Summary : OpenSSH Secure Shell protocol server (sshd).
Summary(de) : OpenSSH Secure Shell Protocol-Server (sshd).
Summary(es) : Servidor del protocolo OpenSSH Secure Shell (sshd).
Summary(fr) : Serveur de protocole du shell sécurisé OpenSSH (sshd).
Summary(it) : Server OpenSSH per il protocollo Secure Shell (sshd).
Summary(pt) : Servidor do protocolo 'Secure Shell' OpenSSH (sshd).
Summary(pt_BR) : Servidor do protocolo Secure Shell OpenSSH (sshd).
%Package askpass
Group : System/Network
Requires : openssh = %{version}
URL : http://www.jmknoble.net/software/x11-ssh-askpass/
Obsoletes : ssh-extras
Summary : OpenSSH X11 pass-phrase dialog.
Summary(de) : OpenSSH X11 Passwort-Dialog.
Summary(es) : Aplicación de petición de frase clave OpenSSH X11.
Summary(fr) : Dialogue pass-phrase X11 d'OpenSSH.
Summary(it) : Finestra di dialogo X11 per la frase segreta di OpenSSH.
Summary(pt) : Diálogo de pedido de senha para X11 do OpenSSH.
Summary(pt_BR) : Diálogo de pedido de senha para X11 do OpenSSH.
%Description
OpenSSH (Secure Shell) provides access to a remote system. It replaces
telnet, rlogin, rexec, and rsh, and provides secure encrypted
communications between two untrusted hosts over an insecure network.
X11 connections and arbitrary TCP/IP ports can also be forwarded over
the secure channel.
%Description -l de
OpenSSH (Secure Shell) stellt den Zugang zu anderen Rechnern her. Es ersetzt
telnet, rlogin, rexec und rsh und stellt eine sichere, verschlüsselte
Verbindung zwischen zwei nicht vertrauenswürdigen Hosts über eine unsicheres
Netzwerk her. X11 Verbindungen und beliebige andere TCP/IP Ports können ebenso
über den sicheren Channel weitergeleitet werden.
%Description -l es
OpenSSH (Secure Shell) proporciona acceso a sistemas remotos. Reemplaza a
telnet, rlogin, rexec, y rsh, y proporciona comunicaciones seguras encriptadas
entre dos equipos entre los que no se ha establecido confianza a través de una
red insegura. Las conexiones X11 y puertos TCP/IP arbitrarios también pueden
ser canalizadas sobre el canal seguro.
%Description -l fr
OpenSSH (Secure Shell) fournit un accès à un système distant. Il remplace
telnet, rlogin, rexec et rsh, tout en assurant des communications cryptées
securisées entre deux hôtes non fiabilisés sur un réseau non sécurisé. Des
connexions X11 et des ports TCP/IP arbitraires peuvent également être
transmis sur le canal sécurisé.
%Description -l it
OpenSSH (Secure Shell) fornisce l'accesso ad un sistema remoto.
Sostituisce telnet, rlogin, rexec, e rsh, e fornisce comunicazioni sicure
e crittate tra due host non fidati su una rete non sicura. Le connessioni
X11 ad una porta TCP/IP arbitraria possono essere inoltrate attraverso
un canale sicuro.
%Description -l pt
OpenSSH (Secure Shell) fornece acesso a um sistema remoto. Substitui o
telnet, rlogin, rexec, e o rsh e fornece comunicações seguras e cifradas
entre duas máquinas sem confiança mútua sobre uma rede insegura.
Ligações X11 e portos TCP/IP arbitrários também poder ser reenviados
pelo canal seguro.
%Description -l pt_BR
O OpenSSH (Secure Shell) fornece acesso a um sistema remoto. Substitui o
telnet, rlogin, rexec, e o rsh e fornece comunicações seguras e criptografadas
entre duas máquinas sem confiança mútua sobre uma rede insegura.
Ligações X11 e portas TCP/IP arbitrárias também podem ser reenviadas
pelo canal seguro.
%Description server
This package installs the sshd, the server portion of OpenSSH.
%Description -l de server
Dieses Paket installiert den sshd, den Server-Teil der OpenSSH.
%Description -l es server
Este paquete instala sshd, la parte servidor de OpenSSH.
%Description -l fr server
Ce paquetage installe le 'sshd', partie serveur de OpenSSH.
%Description -l it server
Questo pacchetto installa sshd, il server di OpenSSH.
%Description -l pt server
Este pacote intala o sshd, o servidor do OpenSSH.
%Description -l pt_BR server
Este pacote intala o sshd, o servidor do OpenSSH.
%Description askpass
This package contains an X11-based pass-phrase dialog used per
default by ssh-add(1). It is based on %{askpass}
by Jim Knoble <jmknoble@pobox.com>.
%Prep
%setup %([ -z "%{cvs}" ] || echo "-n %{name}_cvs") -a2
%if ! %{use_stable}
autoreconf
%endif
%Build
CFLAGS="$RPM_OPT_FLAGS" \
%configure \
--with-pam \
--with-privsep-path=%{_var}/empty/sshd \
#leave this line for easy edits.
%__make
cd %{askpass}
%configure \
#leave this line for easy edits.
xmkmf
%__make includes
%__make
%Install
[ %{buildroot} != "/" ] && rm -rf %{buildroot}
make install DESTDIR=%{buildroot}
%makeinstall -C %{askpass} \
BINDIR=%{_libexecdir} \
MANPATH=%{_mandir} \
DESTDIR=%{buildroot}
# OpenLinux specific configuration
mkdir -p %{buildroot}{/etc/pam.d,%{SVIcdir},%{SVIdir}}
mkdir -p %{buildroot}%{_var}/empty/sshd
# enabling X11 forwarding on the server is convenient and okay,
# on the client side it's a potential security risk!
%__perl -pi -e 's:#X11Forwarding no:X11Forwarding yes:g' \
%{buildroot}%{_sysconfdir}/sshd_config
%if %{no_root_login}
%__perl -pi -e 's:#PermitRootLogin yes:PermitRootLogin no:g' \
%{buildroot}%{_sysconfdir}/sshd_config
%endif
install -m644 contrib/caldera/sshd.pam %{buildroot}/etc/pam.d/sshd
# FIXME: disabled, find out why this doesn't work with nis
%__perl -pi -e 's:(.*pam_limits.*):#$1:' \
%{buildroot}/etc/pam.d/sshd
install -m 0755 contrib/caldera/sshd.init %{buildroot}%{SVIdir}/sshd
# the last one is needless, but more future-proof
find %{buildroot}%{SVIdir} -type f -exec \
%__perl -pi -e 's:\@SVIdir\@:%{SVIdir}:g;\
s:\@sysconfdir\@:%{_sysconfdir}:g; \
s:/usr/sbin:%{_sbindir}:g'\
\{\} \;
cat <<-EoD > %{buildroot}%{SVIcdir}/sshd
IDENT=sshd
DESCRIPTIVE="OpenSSH secure shell daemon"
# This service will be marked as 'skipped' on boot if there
# is no host key. Use ssh-host-keygen to generate one
ONBOOT="yes"
OPTIONS=""
EoD
SKG=%{buildroot}%{_sbindir}/ssh-host-keygen
install -m 0755 contrib/caldera/ssh-host-keygen $SKG
# Fix up some path names in the keygen toy^Hol
%__perl -pi -e 's:\@sysconfdir\@:%{_sysconfdir}:g; \
s:\@sshkeygen\@:%{_bindir}/ssh-keygen:g' \
%{buildroot}%{_sbindir}/ssh-host-keygen
# This looks terrible. Expect it to change.
# install remaining docs
DocD="%{buildroot}%{_defaultdocdir}/%{name}-%{version}"
mkdir -p $DocD/%{askpass}
cp -a CREDITS ChangeLog LICENCE OVERVIEW README* TODO PROTOCOL* $DocD
install -p -m 0444 %{SOURCE3} $DocD/faq.html
cp -a %{askpass}/{README,ChangeLog,TODO,SshAskpass*.ad} $DocD/%{askpass}
%if %{use_stable}
cp -p %{askpass}/%{xsa}.man $DocD/%{askpass}/%{xsa}.1
%else
cp -p %{askpass}/%{xsa}.man %{buildroot}%{_mandir}man1/%{xsa}.1
ln -s %{xsa}.1 %{buildroot}%{_mandir}man1/ssh-askpass.1
%endif
find %{buildroot}%{_mandir} -type f -not -name '*.gz' -print0 | xargs -0r %__gzip -9nf
rm %{buildroot}%{_mandir}/man1/slogin.1 && \
ln -s %{_mandir}/man1/ssh.1.gz \
%{buildroot}%{_mandir}/man1/slogin.1.gz
%Clean
#%{rmDESTDIR}
[ %{buildroot} != "/" ] && rm -rf %{buildroot}
%Post
# Generate host key when none is present to get up and running,
# both client and server require this for host-based auth!
# ssh-host-keygen checks for existing keys.
/usr/sbin/ssh-host-keygen
: # to protect the rpm database
%pre server
%{_sbindir}/groupadd -g %{sshd_gid} sshd 2>/dev/null || :
%{_sbindir}/useradd -d /var/empty/sshd -s /bin/false -u %{sshd_uid} \
-c "SSH Daemon virtual user" -g sshd sshd 2>/dev/null || :
: # to protect the rpm database
%Post server
if [ -x %{LSBinit}-install ]; then
%{LSBinit}-install sshd
else
lisa --SysV-init install sshd S55 2:3:4:5 K45 0:1:6
fi
! %{SVIdir}/sshd status || %{SVIdir}/sshd restart
: # to protect the rpm database
%PreUn server
[ "$1" = 0 ] || exit 0
! %{SVIdir}/sshd status || %{SVIdir}/sshd stop
if [ -x %{LSBinit}-remove ]; then
%{LSBinit}-remove sshd
else
lisa --SysV-init remove sshd $1
fi
: # to protect the rpm database
%Files
%defattr(-,root,root)
%dir %{_sysconfdir}
%config %{_sysconfdir}/ssh_config
%{_bindir}/scp
%{_bindir}/sftp
%{_bindir}/ssh
%{_bindir}/slogin
%{_bindir}/ssh-add
%attr(2755,root,nobody) %{_bindir}/ssh-agent
%{_bindir}/ssh-keygen
%{_bindir}/ssh-keyscan
%dir %{_libexecdir}
%attr(4711,root,root) %{_libexecdir}/ssh-keysign
%{_libexecdir}/ssh-pkcs11-helper
%{_sbindir}/ssh-host-keygen
%dir %{_defaultdocdir}/%{name}-%{version}
%{_defaultdocdir}/%{name}-%{version}/CREDITS
%{_defaultdocdir}/%{name}-%{version}/ChangeLog
%{_defaultdocdir}/%{name}-%{version}/LICENCE
%{_defaultdocdir}/%{name}-%{version}/OVERVIEW
%{_defaultdocdir}/%{name}-%{version}/README*
%{_defaultdocdir}/%{name}-%{version}/TODO
%{_defaultdocdir}/%{name}-%{version}/faq.html
%{_mandir}/man1/*
%{_mandir}/man8/ssh-keysign.8.gz
%{_mandir}/man8/ssh-pkcs11-helper.8.gz
%{_mandir}/man5/ssh_config.5.gz
%Files server
%defattr(-,root,root)
%dir %{_var}/empty/sshd
%config %{SVIdir}/sshd
%config /etc/pam.d/sshd
%config %{_sysconfdir}/moduli
%config %{_sysconfdir}/sshd_config
%config %{SVIcdir}/sshd
%{_libexecdir}/sftp-server
%{_sbindir}/sshd
%{_mandir}/man5/moduli.5.gz
%{_mandir}/man5/sshd_config.5.gz
%{_mandir}/man8/sftp-server.8.gz
%{_mandir}/man8/sshd.8.gz
%Files askpass
%defattr(-,root,root)
%{_libexecdir}/ssh-askpass
%{_libexecdir}/x11-ssh-askpass
%{_defaultdocdir}/%{name}-%{version}/%{askpass}
%ChangeLog
* Tue Jan 18 2011 Tim Rice <tim@multitalents.net>
- Use CFLAGS from Makefile instead of RPM so build completes.
- Signatures were changed to .asc since 4.1p1.
* Mon Jan 01 1998 ...
Template Version: 1.31
$Id: openssh.spec,v 1.85 2014/08/19 01:36:08 djm Exp $

View File

@ -1,36 +0,0 @@
#! /bin/sh
#
# $Id: ssh-host-keygen,v 1.3 2008/11/03 09:16:01 djm Exp $
#
# This script is normally run only *once* for a given host
# (in a given period of time) -- on updates/upgrades/recovery
# the ssh_host_key* files _should_ be retained! Otherwise false
# "man-in-the-middle-attack" alerts will frighten unsuspecting
# clients...
keydir=@sysconfdir@
keygen=@sshkeygen@
if [ -f $keydir/ssh_host_key -o \
-f $keydir/ssh_host_key.pub ]; then
echo "You already have an SSH1 RSA host key in $keydir/ssh_host_key."
else
echo "Generating SSH1 RSA host key."
$keygen -t rsa1 -f $keydir/ssh_host_key -C '' -N ''
fi
if [ -f $keydir/ssh_host_rsa_key -o \
-f $keydir/ssh_host_rsa_key.pub ]; then
echo "You already have an SSH2 RSA host key in $keydir/ssh_host_rsa_key."
else
echo "Generating SSH2 RSA host key."
$keygen -t rsa -f $keydir/ssh_host_rsa_key -C '' -N ''
fi
if [ -f $keydir/ssh_host_dsa_key -o \
-f $keydir/ssh_host_dsa_key.pub ]; then
echo "You already have an SSH2 DSA host key in $keydir/ssh_host_dsa_key."
else
echo "Generating SSH2 DSA host key."
$keygen -t dsa -f $keydir/ssh_host_dsa_key -C '' -N ''
fi

View File

@ -1,125 +0,0 @@
#! /bin/bash
#
# $Id: sshd.init,v 1.4 2003/11/21 12:48:57 djm Exp $
#
### BEGIN INIT INFO
# Provides:
# Required-Start: $network
# Required-Stop:
# Default-Start: 3 4 5
# Default-Stop: 0 1 2 6
# Description: sshd
# Bring up/down the OpenSSH secure shell daemon.
### END INIT INFO
#
# Written by Miquel van Smoorenburg <miquels@drinkel.ow.org>.
# Modified for Debian GNU/Linux by Ian Murdock <imurdock@gnu.ai.mit.edu>.
# Modified for OpenLinux by Raymund Will <ray@caldera.de>
NAME=sshd
DAEMON=/usr/sbin/$NAME
# Hack-Alert(TM)! This is necessary to get around the 'reload'-problem
# created by recent OpenSSH daemon/ssd combinations. See Caldera internal
# PR [linux/8278] for details...
PIDF=/var/run/$NAME.pid
NAME=$DAEMON
_status() {
[ -z "$1" ] || local pidf="$1"
local ret=-1
local pid
if [ -n "$pidf" ] && [ -r "$pidf" ]; then
pid=$(head -1 $pidf)
else
pid=$(pidof $NAME)
fi
if [ ! -e $SVIlock ]; then
# no lock-file => not started == stopped?
ret=3
elif [ -n "$pidf" -a ! -f "$pidf" ] || [ -z "$pid" ]; then
# pid-file given but not present or no pid => died, but was not stopped
ret=2
elif [ -r /proc/$pid/cmdline ] &&
echo -ne $NAME'\000' | cmp -s - /proc/$pid/cmdline; then
# pid-file given and present or pid found => check process...
# but don't compare exe, as this will fail after an update!
# compares OK => all's well, that ends well...
ret=0
else
# no such process or exe does not match => stale pid-file or process died
# just recently...
ret=1
fi
return $ret
}
# Source function library (and set vital variables).
. @SVIdir@/functions
case "$1" in
start)
[ ! -e $SVIlock ] || exit 0
[ -x $DAEMON ] || exit 5
SVIemptyConfig @sysconfdir@/sshd_config && exit 6
if [ ! \( -f @sysconfdir@/ssh_host_key -a \
-f @sysconfdir@/ssh_host_key.pub \) -a \
! \( -f @sysconfdir@/ssh_host_rsa_key -a \
-f @sysconfdir@/ssh_host_rsa_key.pub \) -a \
! \( -f @sysconfdir@/ssh_host_dsa_key -a \
-f @sysconfdir@/ssh_host_dsa_key.pub \) ]; then
echo "$SVIsubsys: host key not initialized: skipped!"
echo "$SVIsubsys: use ssh-host-keygen to generate one!"
exit 6
fi
echo -n "Starting $SVIsubsys services: "
ssd -S -x $DAEMON -n $NAME -- $OPTIONS
ret=$?
echo "."
touch $SVIlock
;;
stop)
[ -e $SVIlock ] || exit 0
echo -n "Stopping $SVIsubsys services: "
ssd -K -p $PIDF -n $NAME
ret=$?
echo "."
rm -f $SVIlock
;;
force-reload|reload)
[ -e $SVIlock ] || exit 0
echo "Reloading $SVIsubsys configuration files: "
ssd -K --signal 1 -q -p $PIDF -n $NAME
ret=$?
echo "done."
;;
restart)
$0 stop
$0 start
ret=$?
;;
status)
_status $PIDF
ret=$?
;;
*)
echo "Usage: $SVIscript {[re]start|stop|[force-]reload|status}"
ret=2
;;
esac
exit $ret

View File

@ -1,8 +0,0 @@
#%PAM-1.0
auth required /lib/security/pam_pwdb.so shadow nodelay
account required /lib/security/pam_nologin.so
account required /lib/security/pam_pwdb.so
password required /lib/security/pam_cracklib.so
password required /lib/security/pam_pwdb.so shadow nullok use_authtok
session required /lib/security/pam_pwdb.so
session required /lib/security/pam_limits.so

View File

@ -1,6 +1,6 @@
#!/bin/bash
#
# ssh-host-config, Copyright 2000-2011 Red Hat Inc.
# ssh-host-config, Copyright 2000-2014 Red Hat Inc.
#
# This file is part of the Cygwin port of OpenSSH.
#
@ -61,6 +61,7 @@ LOCALSTATEDIR=/var
sshd_config_configured=no
port_number=22
service_name=sshd
strictmodes=yes
privsep_used=yes
cygwin_value=""
@ -353,11 +354,9 @@ check_service_files_ownership() {
fi
if [ -z "${run_service_as}" ]
then
csih_warning "Couldn't determine name of user running sshd service from /etc/passwd!"
csih_warning "Couldn't determine name of user running sshd service from account database!"
csih_warning "As a result, this script cannot make sure that the files used"
csih_warning "by the sshd service belong to the user running the service."
csih_warning "Please re-run the mkpasswd tool to make sure the /etc/passwd"
csih_warning "file is in a good shape."
return 1
fi
fi
@ -410,7 +409,7 @@ install_service() {
local ret=0
echo
if /usr/bin/cygrunsrv -Q sshd >/dev/null 2>&1
if /usr/bin/cygrunsrv -Q ${service_name} >/dev/null 2>&1
then
csih_inform "Sshd service is already installed."
check_service_files_ownership "" || let ret+=$?
@ -466,7 +465,7 @@ install_service() {
fi
if [ -z "${password}" ]
then
if /usr/bin/cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd \
if /usr/bin/cygrunsrv -I ${service_name} -d "CYGWIN ${service_name}" -p /usr/sbin/sshd \
-a "-D" -y tcpip "${cygwin_env[@]}"
then
echo
@ -476,20 +475,20 @@ install_service() {
csih_inform "will start automatically after the next reboot."
fi
else
if /usr/bin/cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd \
if /usr/bin/cygrunsrv -I ${service_name} -d "CYGWIN ${service_name}" -p /usr/sbin/sshd \
-a "-D" -y tcpip "${cygwin_env[@]}" \
-u "${run_service_as}" -w "${password}"
then
/usr/bin/editrights -u "${run_service_as}" -a SeServiceLogonRight
echo
csih_inform "The sshd service has been installed under the '${run_service_as}'"
csih_inform "account. To start the service now, call \`net start sshd' or"
csih_inform "\`cygrunsrv -S sshd'. Otherwise, it will start automatically"
csih_inform "account. To start the service now, call \`net start ${service_name}' or"
csih_inform "\`cygrunsrv -S ${service_name}'. Otherwise, it will start automatically"
csih_inform "after the next reboot."
fi
fi
if /usr/bin/cygrunsrv -Q sshd >/dev/null 2>&1
if /usr/bin/cygrunsrv -Q ${service_name} >/dev/null 2>&1
then
check_service_files_ownership "${run_service_as}" || let ret+=$?
else
@ -563,6 +562,11 @@ do
shift
;;
-N | --name )
service_name=$1
shift
;;
-p | --port )
port_number=$1
shift
@ -592,6 +596,7 @@ do
echo " --yes -y Answer all questions with \"yes\" automatically."
echo " --no -n Answer all questions with \"no\" automatically."
echo " --cygwin -c <options> Use \"options\" as value for CYGWIN environment var."
echo " --name -N <name> sshd windows service name."
echo " --port -p <n> sshd listens on port n."
echo " --user -u <account> privileged user for service, default 'cyg_server'."
echo " --pwd -w <passwd> Use \"pwd\" as password for privileged user."
@ -625,10 +630,7 @@ then
csih_warning "However, it seems your account does not have these privileges."
csih_warning "Here's the list of groups in your user token:"
echo
for i in $(/usr/bin/id -G)
do
/usr/bin/awk -F: "/[^:]*:[^:]*:$i:/{ print \" \" \$1; }" /etc/group
done
/usr/bin/id -Gnz | xargs -0n1 echo " "
echo
csih_warning "This usually means you're running this script from a non-admin"
csih_warning "desktop session, or in a non-elevated shell under UAC control."

View File

@ -1,6 +1,6 @@
#!/bin/bash
#
# ssh-user-config, Copyright 2000-2008 Red Hat Inc.
# ssh-user-config, Copyright 2000-2014 Red Hat Inc.
#
# This file is part of the Cygwin port of OpenSSH.
#
@ -75,19 +75,18 @@ readonly -f create_identity
# pwdhome
# ======================================================================
check_user_homedir() {
local uid=$(id -u)
pwdhome=$(awk -F: '{ if ( $3 == '${uid}' ) print $6; }' < ${SYSCONFDIR}/passwd)
pwdhome=$(getent passwd $UID | awk -F: '{ print $6; }')
if [ "X${pwdhome}" = "X" ]
then
csih_error_multi \
"There is no home directory set for you in ${SYSCONFDIR}/passwd." \
"There is no home directory set for you in the account database." \
'Setting $HOME is not sufficient!'
fi
if [ ! -d "${pwdhome}" ]
then
csih_error_multi \
"${pwdhome} is set in ${SYSCONFDIR}/passwd as your home directory" \
"${pwdhome} is set in the account database as your home directory" \
'but it is not a valid directory. Cannot create user identity files.'
fi
@ -96,7 +95,7 @@ check_user_homedir() {
if [ "X${pwdhome}" = "X/" ]
then
# But first raise a warning!
csih_warning "Your home directory in ${SYSCONFDIR}/passwd is set to root (/). This is not recommended!"
csih_warning "Your home directory in the account database is set to root (/). This is not recommended!"
if csih_request "Would you like to proceed anyway?"
then
pwdhome=''
@ -106,7 +105,7 @@ check_user_homedir() {
fi
fi
if [ -d "${pwdhome}" -a csih_is_nt -a -n "`chmod -c g-w,o-w "${pwdhome}"`" ]
if [ -d "${pwdhome}" -a -n "`chmod -c g-w,o-w "${pwdhome}"`" ]
then
echo
csih_warning 'group and other have been revoked write permission to your home'
@ -149,9 +148,10 @@ readonly -f check_user_dot_ssh_dir
# pwdhome -- check_user_homedir()
# ======================================================================
fix_authorized_keys_perms() {
if [ csih_is_nt -a -e "${pwdhome}/.ssh/authorized_keys" ]
if [ -e "${pwdhome}/.ssh/authorized_keys" ]
then
if ! setfacl -m "u::rw-,g::---,o::---" "${pwdhome}/.ssh/authorized_keys"
setfacl -b "${pwdhome}/.ssh/authorized_keys" 2>/dev/null || echo -n
if ! chmod u-x,g-wx,o-wx "${pwdhome}/.ssh/authorized_keys"
then
csih_warning "Setting correct permissions to ${pwdhome}/.ssh/authorized_keys"
csih_warning "failed. Please care for the correct permissions. The minimum requirement"
@ -243,15 +243,6 @@ done
# Action!
# ======================================================================
# Check passwd file
if [ ! -f ${SYSCONFDIR}/passwd ]
then
csih_error_multi \
"${SYSCONFDIR}/passwd is nonexistant. Please generate an ${SYSCONFDIR}/passwd file" \
'first using mkpasswd. Check if it contains an entry for you and' \
'please care for the home directory in your entry as well.'
fi
check_user_homedir
check_user_dot_ssh_dir
create_identity id_rsa rsa "SSH2 RSA"

View File

@ -1,4 +1,4 @@
%define ver 6.7p1
%define ver 6.8p1
%define rel 1
# OpenSSH privilege separation requires a user & group ID

View File

@ -13,7 +13,7 @@
Summary: OpenSSH, a free Secure Shell (SSH) protocol implementation
Name: openssh
Version: 6.7p1
Version: 6.8p1
URL: http://www.openssh.com/
Release: 1
Source0: openssh-%{version}.tar.gz

View File

@ -1,4 +1,4 @@
/* $OpenBSD: deattack.c,v 1.30 2006/09/16 19:53:37 djm Exp $ */
/* $OpenBSD: deattack.c,v 1.32 2015/01/20 23:14:00 deraadt Exp $ */
/*
* Cryptographic attack detector for ssh - source code
*
@ -20,16 +20,13 @@
#include "includes.h"
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "xmalloc.h"
#include "deattack.h"
#include "log.h"
#include "crc32.h"
#include "sshbuf.h"
#include "misc.h"
/*
@ -66,7 +63,7 @@
/* Hash function (Input keys are cipher results) */
#define HASH(x) get_u32(x)
#define HASH(x) PEEK_U32(x)
#define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE))
@ -79,10 +76,10 @@ crc_update(u_int32_t *a, u_int32_t b)
/* detect if a block is used in a particular pattern */
static int
check_crc(u_char *S, u_char *buf, u_int32_t len)
check_crc(const u_char *S, const u_char *buf, u_int32_t len)
{
u_int32_t crc;
u_char *c;
const u_char *c;
crc = 0;
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
@ -94,36 +91,44 @@ check_crc(u_char *S, u_char *buf, u_int32_t len)
crc_update(&crc, 0);
}
}
return (crc == 0);
return crc == 0;
}
void
deattack_init(struct deattack_ctx *dctx)
{
bzero(dctx, sizeof(*dctx));
dctx->n = HASH_MINSIZE / HASH_ENTRYSIZE;
}
/* Detect a crc32 compensation attack on a packet */
int
detect_attack(u_char *buf, u_int32_t len)
detect_attack(struct deattack_ctx *dctx, const u_char *buf, u_int32_t len)
{
static u_int16_t *h = (u_int16_t *) NULL;
static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
u_int32_t i, j;
u_int32_t l, same;
u_char *c;
u_char *d;
u_int32_t i, j, l, same;
u_int16_t *tmp;
const u_char *c, *d;
if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
len % SSH_BLOCKSIZE != 0) {
fatal("detect_attack: bad length %d", len);
}
for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
len % SSH_BLOCKSIZE != 0)
return DEATTACK_ERROR;
for (l = dctx->n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
;
if (h == NULL) {
debug("Installing crc compensation attack detector.");
h = (u_int16_t *) xcalloc(l, HASH_ENTRYSIZE);
n = l;
if (dctx->h == NULL) {
if ((dctx->h = calloc(l, HASH_ENTRYSIZE)) == NULL)
return DEATTACK_ERROR;
dctx->n = l;
} else {
if (l > n) {
h = (u_int16_t *)xrealloc(h, l, HASH_ENTRYSIZE);
n = l;
if (l > dctx->n) {
if ((tmp = reallocarray(dctx->h, l, HASH_ENTRYSIZE))
== NULL) {
free(dctx->h);
dctx->h = NULL;
return DEATTACK_ERROR;
}
dctx->h = tmp;
dctx->n = l;
}
}
@ -132,29 +137,29 @@ detect_attack(u_char *buf, u_int32_t len)
for (d = buf; d < c; d += SSH_BLOCKSIZE) {
if (!CMP(c, d)) {
if ((check_crc(c, buf, len)))
return (DEATTACK_DETECTED);
return DEATTACK_DETECTED;
else
break;
}
}
}
return (DEATTACK_OK);
return DEATTACK_OK;
}
memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
memset(dctx->h, HASH_UNUSEDCHAR, dctx->n * HASH_ENTRYSIZE);
for (c = buf, same = j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED;
i = (i + 1) & (n - 1)) {
if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
for (i = HASH(c) & (dctx->n - 1); dctx->h[i] != HASH_UNUSED;
i = (i + 1) & (dctx->n - 1)) {
if (!CMP(c, buf + dctx->h[i] * SSH_BLOCKSIZE)) {
if (++same > MAX_IDENTICAL)
return (DEATTACK_DOS_DETECTED);
return DEATTACK_DOS_DETECTED;
if (check_crc(c, buf, len))
return (DEATTACK_DETECTED);
return DEATTACK_DETECTED;
else
break;
}
}
h[i] = j;
dctx->h[i] = j;
}
return (DEATTACK_OK);
return DEATTACK_OK;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: deattack.h,v 1.10 2006/09/16 19:53:37 djm Exp $ */
/* $OpenBSD: deattack.h,v 1.11 2015/01/19 19:52:16 markus Exp $ */
/*
* Cryptographic attack detector for ssh - Header file
@ -26,6 +26,13 @@
#define DEATTACK_OK 0
#define DEATTACK_DETECTED 1
#define DEATTACK_DOS_DETECTED 2
#define DEATTACK_ERROR 3
int detect_attack(u_char *, u_int32_t);
struct deattack_ctx {
u_int16_t *h;
u_int32_t n;
};
void deattack_init(struct deattack_ctx *);
int detect_attack(struct deattack_ctx *, const u_char *, u_int32_t);
#endif

View File

@ -105,6 +105,17 @@ enum
# endif /* PATH_MAX */
#endif /* MAXPATHLEN */
#ifndef HOST_NAME_MAX
# include "netdb.h" /* for MAXHOSTNAMELEN */
# if defined(_POSIX_HOST_NAME_MAX)
# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
# elif defined(MAXHOSTNAMELEN)
# define HOST_NAME_MAX MAXHOSTNAMELEN
# else
# define HOST_NAME_MAX 255
# endif
#endif /* HOST_NAME_MAX */
#if defined(HAVE_DECL_MAXSYMLINKS) && HAVE_DECL_MAXSYMLINKS == 0
# define MAXSYMLINKS 5
#endif
@ -586,6 +597,12 @@ struct winsize {
# undef HAVE_GAI_STRERROR
#endif
#if defined(HAVE_GETADDRINFO)
# if defined(HAVE_DECL_AI_NUMERICSERV) && HAVE_DECL_AI_NUMERICSERV == 0
# define AI_NUMERICSERV 0
# endif
#endif
#if defined(BROKEN_UPDWTMPX) && defined(HAVE_UPDWTMPX)
# undef HAVE_UPDWTMPX
#endif
@ -805,14 +822,6 @@ struct winsize {
# define SSH_IOBUFSZ 8192
#endif
#ifndef _NSIG
# ifdef NSIG
# define _NSIG NSIG
# else
# define _NSIG 128
# endif
#endif
/*
* Platforms that have arc4random_uniform() and not arc4random_stir()
* shouldn't need the latter.

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dh.c,v 1.53 2013/11/21 00:45:44 djm Exp $ */
/* $OpenBSD: dh.c,v 1.55 2015/01/20 23:14:00 deraadt Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
*
@ -25,7 +25,7 @@
#include "includes.h"
#include <sys/param.h>
#include <sys/param.h> /* MIN */
#include <openssl/bn.h>
#include <openssl/dh.h>
@ -34,11 +34,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "dh.h"
#include "pathnames.h"
#include "log.h"
#include "misc.h"
#include "ssherr.h"
static int
parse_prime(int linenum, char *line, struct dhgroup *dhg)
@ -107,10 +109,11 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
goto fail;
}
if ((dhg->g = BN_new()) == NULL)
fatal("parse_prime: BN_new failed");
if ((dhg->p = BN_new()) == NULL)
fatal("parse_prime: BN_new failed");
if ((dhg->g = BN_new()) == NULL ||
(dhg->p = BN_new()) == NULL) {
error("parse_prime: BN_new failed");
goto fail;
}
if (BN_hex2bn(&dhg->g, gen) == 0) {
error("moduli:%d: could not parse generator value", linenum);
goto fail;
@ -128,7 +131,6 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
error("moduli:%d: generator is invalid", linenum);
goto fail;
}
return 1;
fail:
@ -137,7 +139,6 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
if (dhg->p != NULL)
BN_clear_free(dhg->p);
dhg->g = dhg->p = NULL;
error("Bad prime description in line %d", linenum);
return 0;
}
@ -200,9 +201,11 @@ choose_dh(int min, int wantbits, int max)
break;
}
fclose(f);
if (linenum != which+1)
fatal("WARNING: line %d disappeared in %s, giving up",
if (linenum != which+1) {
logit("WARNING: line %d disappeared in %s, giving up",
which, _PATH_DH_PRIMES);
return (dh_new_group14());
}
return (dh_new_group(dhg.g, dhg.p));
}
@ -251,22 +254,22 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
return 0;
}
void
int
dh_gen_key(DH *dh, int need)
{
int pbits;
if (need <= 0)
fatal("%s: need <= 0", __func__);
if (dh->p == NULL)
fatal("%s: dh->p == NULL", __func__);
if ((pbits = BN_num_bits(dh->p)) <= 0)
fatal("%s: bits(p) <= 0", __func__);
if (need < 0 || dh->p == NULL ||
(pbits = BN_num_bits(dh->p)) <= 0 ||
need > INT_MAX / 2 || 2 * need >= pbits)
return SSH_ERR_INVALID_ARGUMENT;
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__);
if (DH_generate_key(dh) == 0 ||
!dh_pub_is_valid(dh, dh->pub_key)) {
BN_clear_free(dh->priv_key);
return SSH_ERR_LIBCRYPTO_ERROR;
}
return 0;
}
DH *
@ -275,13 +278,12 @@ dh_new_group_asc(const char *gen, const char *modulus)
DH *dh;
if ((dh = DH_new()) == NULL)
fatal("dh_new_group_asc: DH_new");
if (BN_hex2bn(&dh->p, modulus) == 0)
fatal("BN_hex2bn p");
if (BN_hex2bn(&dh->g, gen) == 0)
fatal("BN_hex2bn g");
return NULL;
if (BN_hex2bn(&dh->p, modulus) == 0 ||
BN_hex2bn(&dh->g, gen) == 0) {
DH_free(dh);
return NULL;
}
return (dh);
}
@ -296,7 +298,7 @@ dh_new_group(BIGNUM *gen, BIGNUM *modulus)
DH *dh;
if ((dh = DH_new()) == NULL)
fatal("dh_new_group: DH_new");
return NULL;
dh->p = modulus;
dh->g = gen;
@ -344,7 +346,7 @@ dh_new_group14(void)
* from RFC4419 section 3.
*/
int
u_int
dh_estimate(int bits)
{
if (bits <= 112)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dh.h,v 1.11 2013/10/08 11:42:13 dtucker Exp $ */
/* $OpenBSD: dh.h,v 1.12 2015/01/19 20:16:15 markus Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
@ -38,10 +38,10 @@ DH *dh_new_group(BIGNUM *, BIGNUM *);
DH *dh_new_group1(void);
DH *dh_new_group14(void);
void dh_gen_key(DH *, int);
int dh_gen_key(DH *, int);
int dh_pub_is_valid(DH *, BIGNUM *);
int dh_estimate(int);
u_int dh_estimate(int);
/* Min and max values from RFC4419. */
#define DH_GRP_MIN 1024

View File

@ -1,4 +1,4 @@
/* $OpenBSD: digest-libc.c,v 1.3 2014/06/24 01:13:21 djm Exp $ */
/* $OpenBSD: digest-libc.c,v 1.4 2014/12/21 22:27:56 djm Exp $ */
/*
* Copyright (c) 2013 Damien Miller <djm@mindrot.org>
* Copyright (c) 2014 Markus Friedl. All rights reserved.
@ -18,15 +18,19 @@
#include "includes.h"
#ifndef WITH_OPENSSL
#include <sys/types.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#if 0
#include <md5.h>
#include <rmd160.h>
#include <sha1.h>
#include <sha2.h>
#endif
#include "ssherr.h"
#include "sshbuf.h"
@ -89,30 +93,30 @@ const struct ssh_digest digests[SSH_DIGEST_MAX] = {
"SHA256",
SHA256_BLOCK_LENGTH,
SHA256_DIGEST_LENGTH,
sizeof(SHA2_CTX),
(md_init_fn *) SHA256Init,
(md_update_fn *) SHA256Update,
(md_final_fn *) SHA256Final
sizeof(SHA256_CTX),
(md_init_fn *) SHA256_Init,
(md_update_fn *) SHA256_Update,
(md_final_fn *) SHA256_Final
},
{
SSH_DIGEST_SHA384,
"SHA384",
SHA384_BLOCK_LENGTH,
SHA384_DIGEST_LENGTH,
sizeof(SHA2_CTX),
(md_init_fn *) SHA384Init,
(md_update_fn *) SHA384Update,
(md_final_fn *) SHA384Final
sizeof(SHA384_CTX),
(md_init_fn *) SHA384_Init,
(md_update_fn *) SHA384_Update,
(md_final_fn *) SHA384_Final
},
{
SSH_DIGEST_SHA512,
"SHA512",
SHA512_BLOCK_LENGTH,
SHA512_DIGEST_LENGTH,
sizeof(SHA2_CTX),
(md_init_fn *) SHA512Init,
(md_update_fn *) SHA512Update,
(md_final_fn *) SHA512Final
sizeof(SHA512_CTX),
(md_init_fn *) SHA512_Init,
(md_update_fn *) SHA512_Update,
(md_final_fn *) SHA512_Final
}
};
@ -126,6 +130,26 @@ ssh_digest_by_alg(int alg)
return &(digests[alg]);
}
int
ssh_digest_alg_by_name(const char *name)
{
int alg;
for (alg = 0; alg < SSH_DIGEST_MAX; alg++) {
if (strcasecmp(name, digests[alg].name) == 0)
return digests[alg].id;
}
return -1;
}
const char *
ssh_digest_alg_name(int alg)
{
const struct ssh_digest *digest = ssh_digest_by_alg(alg);
return digest == NULL ? NULL : digest->name;
}
size_t
ssh_digest_bytes(int alg)
{
@ -237,3 +261,4 @@ ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen)
{
return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen);
}
#endif /* !WITH_OPENSSL */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: digest-openssl.c,v 1.4 2014/07/03 03:26:43 djm Exp $ */
/* $OpenBSD: digest-openssl.c,v 1.5 2014/12/21 22:27:56 djm Exp $ */
/*
* Copyright (c) 2013 Damien Miller <djm@mindrot.org>
*
@ -17,6 +17,8 @@
#include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h>
#include <limits.h>
#include <stdlib.h>
@ -74,6 +76,26 @@ ssh_digest_by_alg(int alg)
return &(digests[alg]);
}
int
ssh_digest_alg_by_name(const char *name)
{
int alg;
for (alg = 0; digests[alg].id != -1; alg++) {
if (strcasecmp(name, digests[alg].name) == 0)
return digests[alg].id;
}
return -1;
}
const char *
ssh_digest_alg_name(int alg)
{
const struct ssh_digest *digest = ssh_digest_by_alg(alg);
return digest == NULL ? NULL : digest->name;
}
size_t
ssh_digest_bytes(int alg)
{
@ -180,3 +202,4 @@ ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen)
{
return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen);
}
#endif /* WITH_OPENSSL */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: digest.h,v 1.6 2014/07/03 04:36:45 djm Exp $ */
/* $OpenBSD: digest.h,v 1.7 2014/12/21 22:27:56 djm Exp $ */
/*
* Copyright (c) 2013 Damien Miller <djm@mindrot.org>
*
@ -33,6 +33,12 @@
struct sshbuf;
struct ssh_digest_ctx;
/* Looks up a digest algorithm by name */
int ssh_digest_alg_by_name(const char *name);
/* Returns the algorithm name for a digest identifier */
const char *ssh_digest_alg_name(int alg);
/* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */
size_t ssh_digest_bytes(int alg);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dispatch.c,v 1.22 2008/10/31 15:05:34 stevesk Exp $ */
/* $OpenBSD: dispatch.c,v 1.26 2015/02/12 20:34:19 dtucker Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -36,69 +36,123 @@
#include "dispatch.h"
#include "packet.h"
#include "compat.h"
#include "ssherr.h"
#define DISPATCH_MAX 255
dispatch_fn *dispatch[DISPATCH_MAX];
void
dispatch_protocol_error(int type, u_int32_t seq, void *ctxt)
int
dispatch_protocol_error(int type, u_int32_t seq, void *ctx)
{
struct ssh *ssh = active_state; /* XXX */
int r;
logit("dispatch_protocol_error: type %d seq %u", type, seq);
if (!compat20)
fatal("protocol error");
packet_start(SSH2_MSG_UNIMPLEMENTED);
packet_put_int(seq);
packet_send();
packet_write_wait();
if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
(r = sshpkt_put_u32(ssh, seq)) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
sshpkt_fatal(ssh, __func__, r);
return 0;
}
void
dispatch_protocol_ignore(int type, u_int32_t seq, void *ctxt)
int
dispatch_protocol_ignore(int type, u_int32_t seq, void *ssh)
{
logit("dispatch_protocol_ignore: type %d seq %u", type, seq);
return 0;
}
void
dispatch_init(dispatch_fn *dflt)
ssh_dispatch_init(struct ssh *ssh, dispatch_fn *dflt)
{
u_int i;
for (i = 0; i < DISPATCH_MAX; i++)
dispatch[i] = dflt;
ssh->dispatch[i] = dflt;
}
void
dispatch_range(u_int from, u_int to, dispatch_fn *fn)
ssh_dispatch_range(struct ssh *ssh, u_int from, u_int to, dispatch_fn *fn)
{
u_int i;
for (i = from; i <= to; i++) {
if (i >= DISPATCH_MAX)
break;
dispatch[i] = fn;
ssh->dispatch[i] = fn;
}
}
void
dispatch_set(int type, dispatch_fn *fn)
{
dispatch[type] = fn;
}
void
dispatch_run(int mode, volatile sig_atomic_t *done, void *ctxt)
{
for (;;) {
int type;
u_int32_t seqnr;
void
ssh_dispatch_set(struct ssh *ssh, int type, dispatch_fn *fn)
{
ssh->dispatch[type] = fn;
}
int
ssh_dispatch_run(struct ssh *ssh, int mode, volatile sig_atomic_t *done,
void *ctxt)
{
int r;
u_char type;
u_int32_t seqnr;
for (;;) {
if (mode == DISPATCH_BLOCK) {
type = packet_read_seqnr(&seqnr);
r = ssh_packet_read_seqnr(ssh, &type, &seqnr);
if (r != 0)
return r;
} else {
type = packet_read_poll_seqnr(&seqnr);
r = ssh_packet_read_poll_seqnr(ssh, &type, &seqnr);
if (r != 0)
return r;
if (type == SSH_MSG_NONE)
return;
return 0;
}
if (type > 0 && type < DISPATCH_MAX &&
ssh->dispatch[type] != NULL) {
if (ssh->dispatch_skip_packets) {
debug2("skipped packet (type %u)", type);
ssh->dispatch_skip_packets--;
continue;
}
/* XXX 'ssh' will replace 'ctxt' later */
r = (*ssh->dispatch[type])(type, seqnr, ctxt);
if (r != 0)
return r;
} else {
r = sshpkt_disconnect(ssh,
"protocol error: rcvd type %d", type);
if (r != 0)
return r;
return SSH_ERR_DISCONNECTED;
}
if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL)
(*dispatch[type])(type, seqnr, ctxt);
else
packet_disconnect("protocol error: rcvd type %d", type);
if (done != NULL && *done)
return;
return 0;
}
}
void
ssh_dispatch_run_fatal(struct ssh *ssh, int mode, volatile sig_atomic_t *done,
void *ctxt)
{
int r;
if ((r = ssh_dispatch_run(ssh, mode, done, ctxt)) != 0) {
switch (r) {
case SSH_ERR_CONN_CLOSED:
logit("Connection closed by %.200s",
ssh_remote_ipaddr(ssh));
cleanup_exit(255);
case SSH_ERR_CONN_TIMEOUT:
logit("Connection to %.200s timed out while "
"waiting to read", ssh_remote_ipaddr(ssh));
cleanup_exit(255);
case SSH_ERR_DISCONNECTED:
logit("Disconnected from %.200s",
ssh_remote_ipaddr(ssh));
cleanup_exit(255);
default:
fatal("%s: %s", __func__, ssh_err(r));
}
}
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dispatch.h,v 1.11 2006/04/20 09:27:09 djm Exp $ */
/* $OpenBSD: dispatch.h,v 1.12 2015/01/19 20:07:45 markus Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -24,18 +24,35 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <signal.h>
#ifndef DISPATCH_H
#define DISPATCH_H
#define DISPATCH_MAX 255
enum {
DISPATCH_BLOCK,
DISPATCH_NONBLOCK
};
typedef void dispatch_fn(int, u_int32_t, void *);
struct ssh;
void dispatch_init(dispatch_fn *);
void dispatch_set(int, dispatch_fn *);
void dispatch_range(u_int, u_int, dispatch_fn *);
void dispatch_run(int, volatile sig_atomic_t *, void *);
void dispatch_protocol_error(int, u_int32_t, void *);
void dispatch_protocol_ignore(int, u_int32_t, void *);
typedef int dispatch_fn(int, u_int32_t, void *);
int dispatch_protocol_error(int, u_int32_t, void *);
int dispatch_protocol_ignore(int, u_int32_t, void *);
void ssh_dispatch_init(struct ssh *, dispatch_fn *);
void ssh_dispatch_set(struct ssh *, int, dispatch_fn *);
void ssh_dispatch_range(struct ssh *, u_int, u_int, dispatch_fn *);
int ssh_dispatch_run(struct ssh *, int, volatile sig_atomic_t *, void *);
void ssh_dispatch_run_fatal(struct ssh *, int, volatile sig_atomic_t *, void *);
#define dispatch_init(dflt) \
ssh_dispatch_init(active_state, (dflt))
#define dispatch_range(from, to, fn) \
ssh_dispatch_range(active_state, (from), (to), (fn))
#define dispatch_set(type, fn) \
ssh_dispatch_set(active_state, (type), (fn))
#define dispatch_run(mode, done, ctxt) \
ssh_dispatch_run_fatal(active_state, (mode), (done), (ctxt))
#endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dns.c,v 1.31 2014/06/24 01:13:21 djm Exp $ */
/* $OpenBSD: dns.c,v 1.34 2015/01/28 22:36:00 djm Exp $ */
/*
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
@ -38,9 +38,11 @@
#include <stdlib.h>
#include "xmalloc.h"
#include "key.h"
#include "sshkey.h"
#include "ssherr.h"
#include "dns.h"
#include "log.h"
#include "digest.h"
static const char *errset_text[] = {
"success", /* 0 ERRSET_SUCCESS */
@ -77,10 +79,10 @@ dns_result_totext(unsigned int res)
*/
static int
dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
u_char **digest, u_int *digest_len, Key *key)
u_char **digest, size_t *digest_len, struct sshkey *key)
{
int success = 0;
enum fp_type fp_type = 0;
int r, success = 0;
int fp_alg = -1;
switch (key->type) {
case KEY_RSA:
@ -110,19 +112,20 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
switch (*digest_type) {
case SSHFP_HASH_SHA1:
fp_type = SSH_FP_SHA1;
fp_alg = SSH_DIGEST_SHA1;
break;
case SSHFP_HASH_SHA256:
fp_type = SSH_FP_SHA256;
fp_alg = SSH_DIGEST_SHA256;
break;
default:
*digest_type = SSHFP_HASH_RESERVED; /* 0 */
}
if (*algorithm && *digest_type) {
*digest = key_fingerprint_raw(key, fp_type, digest_len);
if (*digest == NULL)
fatal("dns_read_key: null from key_fingerprint_raw()");
if ((r = sshkey_fingerprint_raw(key, fp_alg, digest,
digest_len)) != 0)
fatal("%s: sshkey_fingerprint_raw: %s", __func__,
ssh_err(r));
success = 1;
} else {
*digest = NULL;
@ -138,7 +141,7 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
*/
static int
dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type,
u_char **digest, u_int *digest_len, u_char *rdata, int rdata_len)
u_char **digest, size_t *digest_len, u_char *rdata, int rdata_len)
{
int success = 0;
@ -199,7 +202,7 @@ is_numeric_hostname(const char *hostname)
*/
int
verify_host_key_dns(const char *hostname, struct sockaddr *address,
Key *hostkey, int *flags)
struct sshkey *hostkey, int *flags)
{
u_int counter;
int result;
@ -208,12 +211,12 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
u_int8_t hostkey_algorithm;
u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED;
u_char *hostkey_digest;
u_int hostkey_digest_len;
size_t hostkey_digest_len;
u_int8_t dnskey_algorithm;
u_int8_t dnskey_digest_type;
u_char *dnskey_digest;
u_int dnskey_digest_len;
size_t dnskey_digest_len;
*flags = 0;
@ -291,7 +294,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
free(dnskey_digest);
}
free(hostkey_digest); /* from key_fingerprint_raw() */
free(hostkey_digest); /* from sshkey_fingerprint_raw() */
freerrset(fingerprints);
if (*flags & DNS_VERIFY_FOUND)
@ -309,13 +312,13 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
* Export the fingerprint of a key as a DNS resource record
*/
int
export_dns_rr(const char *hostname, Key *key, FILE *f, int generic)
export_dns_rr(const char *hostname, struct sshkey *key, FILE *f, int generic)
{
u_int8_t rdata_pubkey_algorithm = 0;
u_int8_t rdata_digest_type = SSHFP_HASH_RESERVED;
u_int8_t dtype;
u_char *rdata_digest;
u_int i, rdata_digest_len;
size_t i, rdata_digest_len;
int success = 0;
for (dtype = SSHFP_HASH_SHA1; dtype < SSHFP_HASH_MAX; dtype++) {
@ -323,7 +326,7 @@ export_dns_rr(const char *hostname, Key *key, FILE *f, int generic)
if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type,
&rdata_digest, &rdata_digest_len, key)) {
if (generic) {
fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ",
fprintf(f, "%s IN TYPE%d \\# %zu %02x %02x ",
hostname, DNS_RDATATYPE_SSHFP,
2 + rdata_digest_len,
rdata_pubkey_algorithm, rdata_digest_type);
@ -334,7 +337,7 @@ export_dns_rr(const char *hostname, Key *key, FILE *f, int generic)
for (i = 0; i < rdata_digest_len; i++)
fprintf(f, "%02x", rdata_digest[i]);
fprintf(f, "\n");
free(rdata_digest); /* from key_fingerprint_raw() */
free(rdata_digest); /* from sshkey_fingerprint_raw() */
success = 1;
}
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dns.h,v 1.13 2014/04/20 09:24:26 logan Exp $ */
/* $OpenBSD: dns.h,v 1.14 2015/01/15 09:40:00 djm Exp $ */
/*
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
@ -50,7 +50,8 @@ enum sshfp_hashes {
#define DNS_VERIFY_MATCH 0x00000002
#define DNS_VERIFY_SECURE 0x00000004
int verify_host_key_dns(const char *, struct sockaddr *, Key *, int *);
int export_dns_rr(const char *, Key *, FILE *, int);
int verify_host_key_dns(const char *, struct sockaddr *,
struct sshkey *, int *);
int export_dns_rr(const char *, struct sshkey *, FILE *, int);
#endif /* DNS_H */

View File

@ -24,6 +24,8 @@
#include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_UN_H
@ -230,3 +232,13 @@ seed_rng(void)
if (RAND_status() != 1)
fatal("PRNG is not seeded");
}
#else /* WITH_OPENSSL */
/* Handled in arc4random() */
void
seed_rng(void)
{
}
#endif /* WITH_OPENSSL */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ge25519.h,v 1.3 2013/12/09 11:03:45 markus Exp $ */
/* $OpenBSD: ge25519.h,v 1.4 2015/02/16 18:26:26 miod Exp $ */
/*
* Public Domain, Authors: Daniel J. Bernstein, Niels Duif, Tanja Lange,
@ -28,7 +28,7 @@ typedef struct
fe25519 t;
} ge25519;
const ge25519 ge25519_base;
extern const ge25519 ge25519_base;
int ge25519_unpackneg_vartime(ge25519 *r, const unsigned char p[32]);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: groupaccess.c,v 1.14 2013/05/17 00:13:13 djm Exp $ */
/* $OpenBSD: groupaccess.c,v 1.15 2015/01/20 23:14:00 deraadt Exp $ */
/*
* Copyright (c) 2001 Kevin Steves. All rights reserved.
*
@ -26,13 +26,13 @@
#include "includes.h"
#include <sys/types.h>
#include <sys/param.h>
#include <grp.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "xmalloc.h"
#include "groupaccess.h"

View File

@ -1,4 +1,4 @@
/* $OpenBSD: gss-genr.c,v 1.22 2013/11/08 00:39:15 djm Exp $ */
/* $OpenBSD: gss-genr.c,v 1.23 2015/01/20 23:14:00 deraadt Exp $ */
/*
* Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
@ -31,6 +31,7 @@
#include <sys/types.h>
#include <sys/param.h>
#include <limits.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>

View File

@ -1,4 +1,4 @@
/* $OpenBSD: gss-serv.c,v 1.27 2014/07/03 03:34:09 djm Exp $ */
/* $OpenBSD: gss-serv.c,v 1.28 2015/01/20 23:14:00 deraadt Exp $ */
/*
* Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@ -29,7 +29,6 @@
#ifdef GSSAPI
#include <sys/types.h>
#include <sys/param.h>
#include <stdarg.h>
#include <string.h>

View File

@ -1,4 +1,4 @@
/* $OpenBSD: hmac.c,v 1.10 2014/01/31 16:39:19 tedu Exp $ */
/* $OpenBSD: hmac.c,v 1.11 2015/01/15 21:37:14 markus Exp $ */
/*
* Copyright (c) 2014 Markus Friedl. All rights reserved.
*
@ -20,7 +20,7 @@
#include <sys/types.h>
#include <string.h>
#include "buffer.h"
#include "sshbuf.h"
#include "digest.h"
#include "hmac.h"
@ -96,7 +96,7 @@ ssh_hmac_update(struct ssh_hmac_ctx *ctx, const void *m, size_t mlen)
}
int
ssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const Buffer *b)
ssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const struct sshbuf *b)
{
return ssh_digest_update_buffer(ctx->digest, b);
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: hostfile.c,v 1.57 2014/06/24 01:13:21 djm Exp $ */
/* $OpenBSD: hostfile.c,v 1.64 2015/02/16 22:08:57 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -39,22 +39,26 @@
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <errno.h>
#include <resolv.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include "xmalloc.h"
#include "match.h"
#include "key.h"
#include "sshkey.h"
#include "hostfile.h"
#include "log.h"
#include "misc.h"
#include "ssherr.h"
#include "digest.h"
#include "hmac.h"
@ -63,6 +67,8 @@ struct hostkeys {
u_int num_entries;
};
/* XXX hmac is too easy to dictionary attack; use bcrypt? */
static int
extract_salt(const char *s, u_int l, u_char *salt, size_t salt_len)
{
@ -155,15 +161,16 @@ host_hash(const char *host, const char *name_from_hostfile, u_int src_len)
*/
int
hostfile_read_key(char **cpp, int *bitsp, Key *ret)
hostfile_read_key(char **cpp, u_int *bitsp, struct sshkey *ret)
{
char *cp;
int r;
/* Skip leading whitespace. */
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
;
if (key_read(ret, &cp) != 1)
if ((r = sshkey_read(ret, &cp)) != 0)
return 0;
/* Skip trailing whitespace. */
@ -172,28 +179,8 @@ hostfile_read_key(char **cpp, int *bitsp, Key *ret)
/* Return results. */
*cpp = cp;
if (bitsp != NULL) {
if ((*bitsp = key_size(ret)) <= 0)
return 0;
}
return 1;
}
static int
hostfile_check_key(int bits, const Key *key, const char *host,
const char *filename, u_long linenum)
{
#ifdef WITH_SSH1
if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)
return 1;
if (bits != BN_num_bits(key->rsa->n)) {
logit("Warning: %s, line %lu: keysize mismatch for host %s: "
"actual %d vs. announced %d.",
filename, linenum, host, BN_num_bits(key->rsa->n), bits);
logit("Warning: replace %d with %d in %s, line %lu.",
bits, BN_num_bits(key->rsa->n), filename, linenum);
}
#endif
if (bitsp != NULL)
*bitsp = sshkey_size(ret);
return 1;
}
@ -241,95 +228,65 @@ init_hostkeys(void)
return ret;
}
struct load_callback_ctx {
const char *host;
u_long num_loaded;
struct hostkeys *hostkeys;
};
static int
record_hostkey(struct hostkey_foreach_line *l, void *_ctx)
{
struct load_callback_ctx *ctx = (struct load_callback_ctx *)_ctx;
struct hostkeys *hostkeys = ctx->hostkeys;
struct hostkey_entry *tmp;
if (l->status == HKF_STATUS_INVALID) {
error("%s:%ld: parse error in hostkeys file",
l->path, l->linenum);
return 0;
}
debug3("%s: found %skey type %s in file %s:%lu", __func__,
l->marker == MRK_NONE ? "" :
(l->marker == MRK_CA ? "ca " : "revoked "),
sshkey_type(l->key), l->path, l->linenum);
if ((tmp = reallocarray(hostkeys->entries,
hostkeys->num_entries + 1, sizeof(*hostkeys->entries))) == NULL)
return SSH_ERR_ALLOC_FAIL;
hostkeys->entries = tmp;
hostkeys->entries[hostkeys->num_entries].host = xstrdup(ctx->host);
hostkeys->entries[hostkeys->num_entries].file = xstrdup(l->path);
hostkeys->entries[hostkeys->num_entries].line = l->linenum;
hostkeys->entries[hostkeys->num_entries].key = l->key;
l->key = NULL; /* steal it */
hostkeys->entries[hostkeys->num_entries].marker = l->marker;
hostkeys->num_entries++;
ctx->num_loaded++;
return 0;
}
void
load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path)
{
FILE *f;
char line[8192];
u_long linenum = 0, num_loaded = 0;
char *cp, *cp2, *hashed_host;
HostkeyMarker marker;
Key *key;
int kbits;
int r;
struct load_callback_ctx ctx;
if ((f = fopen(path, "r")) == NULL)
return;
debug3("%s: loading entries for host \"%.100s\" from file \"%s\"",
__func__, host, path);
while (read_keyfile_line(f, path, line, sizeof(line), &linenum) == 0) {
cp = line;
ctx.host = host;
ctx.num_loaded = 0;
ctx.hostkeys = hostkeys;
/* Skip any leading whitespace, comments and empty lines. */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
if (!*cp || *cp == '#' || *cp == '\n')
continue;
if ((marker = check_markers(&cp)) == MRK_ERROR) {
verbose("%s: invalid marker at %s:%lu",
__func__, path, linenum);
continue;
}
/* Find the end of the host name portion. */
for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
;
/* Check if the host name matches. */
if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1) {
if (*cp != HASH_DELIM)
continue;
hashed_host = host_hash(host, cp, (u_int) (cp2 - cp));
if (hashed_host == NULL) {
debug("Invalid hashed host line %lu of %s",
linenum, path);
continue;
}
if (strncmp(hashed_host, cp, (u_int) (cp2 - cp)) != 0)
continue;
}
/* Got a match. Skip host name. */
cp = cp2;
/*
* Extract the key from the line. This will skip any leading
* whitespace. Ignore badly formatted lines.
*/
key = key_new(KEY_UNSPEC);
if (!hostfile_read_key(&cp, &kbits, key)) {
key_free(key);
#ifdef WITH_SSH1
key = key_new(KEY_RSA1);
if (!hostfile_read_key(&cp, &kbits, key)) {
key_free(key);
continue;
}
#else
continue;
#endif
}
if (!hostfile_check_key(kbits, key, host, path, linenum))
continue;
debug3("%s: found %skey type %s in file %s:%lu", __func__,
marker == MRK_NONE ? "" :
(marker == MRK_CA ? "ca " : "revoked "),
key_type(key), path, linenum);
hostkeys->entries = xrealloc(hostkeys->entries,
hostkeys->num_entries + 1, sizeof(*hostkeys->entries));
hostkeys->entries[hostkeys->num_entries].host = xstrdup(host);
hostkeys->entries[hostkeys->num_entries].file = xstrdup(path);
hostkeys->entries[hostkeys->num_entries].line = linenum;
hostkeys->entries[hostkeys->num_entries].key = key;
hostkeys->entries[hostkeys->num_entries].marker = marker;
hostkeys->num_entries++;
num_loaded++;
if ((r = hostkeys_foreach(path, record_hostkey, &ctx, host, NULL,
HKF_WANT_MATCH|HKF_WANT_PARSE_KEY)) != 0) {
if (r != SSH_ERR_SYSTEM_ERROR && errno != ENOENT)
debug("%s: hostkeys_foreach failed for %s: %s",
__func__, path, ssh_err(r));
}
debug3("%s: loaded %lu keys", __func__, num_loaded);
fclose(f);
return;
}
if (ctx.num_loaded != 0)
debug3("%s: loaded %lu keys from %s", __func__,
ctx.num_loaded, host);
}
void
free_hostkeys(struct hostkeys *hostkeys)
@ -339,7 +296,7 @@ free_hostkeys(struct hostkeys *hostkeys)
for (i = 0; i < hostkeys->num_entries; i++) {
free(hostkeys->entries[i].host);
free(hostkeys->entries[i].file);
key_free(hostkeys->entries[i].key);
sshkey_free(hostkeys->entries[i].key);
explicit_bzero(hostkeys->entries + i, sizeof(*hostkeys->entries));
}
free(hostkeys->entries);
@ -348,18 +305,18 @@ free_hostkeys(struct hostkeys *hostkeys)
}
static int
check_key_not_revoked(struct hostkeys *hostkeys, Key *k)
check_key_not_revoked(struct hostkeys *hostkeys, struct sshkey *k)
{
int is_cert = key_is_cert(k);
int is_cert = sshkey_is_cert(k);
u_int i;
for (i = 0; i < hostkeys->num_entries; i++) {
if (hostkeys->entries[i].marker != MRK_REVOKE)
continue;
if (key_equal_public(k, hostkeys->entries[i].key))
if (sshkey_equal_public(k, hostkeys->entries[i].key))
return -1;
if (is_cert &&
key_equal_public(k->cert->signature_key,
sshkey_equal_public(k->cert->signature_key,
hostkeys->entries[i].key))
return -1;
}
@ -383,11 +340,11 @@ check_key_not_revoked(struct hostkeys *hostkeys, Key *k)
*/
static HostStatus
check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
Key *k, int keytype, const struct hostkey_entry **found)
struct sshkey *k, int keytype, const struct hostkey_entry **found)
{
u_int i;
HostStatus end_return = HOST_NEW;
int want_cert = key_is_cert(k);
int want_cert = sshkey_is_cert(k);
HostkeyMarker want_marker = want_cert ? MRK_CA : MRK_NONE;
int proto = (k ? k->type : keytype) == KEY_RSA1 ? 1 : 2;
@ -411,7 +368,7 @@ check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
break;
}
if (want_cert) {
if (key_equal_public(k->cert->signature_key,
if (sshkey_equal_public(k->cert->signature_key,
hostkeys->entries[i].key)) {
/* A matching CA exists */
end_return = HOST_OK;
@ -420,7 +377,7 @@ check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
break;
}
} else {
if (key_equal(k, hostkeys->entries[i].key)) {
if (sshkey_equal(k, hostkeys->entries[i].key)) {
end_return = HOST_OK;
if (found != NULL)
*found = hostkeys->entries + i;
@ -439,9 +396,9 @@ check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
}
return end_return;
}
HostStatus
check_key_in_hostkeys(struct hostkeys *hostkeys, Key *key,
check_key_in_hostkeys(struct hostkeys *hostkeys, struct sshkey *key,
const struct hostkey_entry **found)
{
if (key == NULL)
@ -457,40 +414,438 @@ lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype,
found) == HOST_FOUND);
}
static int
write_host_entry(FILE *f, const char *host, const char *ip,
const struct sshkey *key, int store_hash)
{
int r, success = 0;
char *hashed_host = NULL;
if (store_hash) {
if ((hashed_host = host_hash(host, NULL, 0)) == NULL) {
error("%s: host_hash failed", __func__);
return 0;
}
fprintf(f, "%s ", hashed_host);
} else if (ip != NULL)
fprintf(f, "%s,%s ", host, ip);
else
fprintf(f, "%s ", host);
if ((r = sshkey_write(key, f)) == 0)
success = 1;
else
error("%s: sshkey_write failed: %s", __func__, ssh_err(r));
fputc('\n', f);
return success;
}
/*
* Appends an entry to the host file. Returns false if the entry could not
* be appended.
*/
int
add_host_to_hostfile(const char *filename, const char *host, const Key *key,
int store_hash)
add_host_to_hostfile(const char *filename, const char *host,
const struct sshkey *key, int store_hash)
{
FILE *f;
int success = 0;
char *hashed_host = NULL;
int success;
if (key == NULL)
return 1; /* XXX ? */
f = fopen(filename, "a");
if (!f)
return 0;
if (store_hash) {
if ((hashed_host = host_hash(host, NULL, 0)) == NULL) {
error("add_host_to_hostfile: host_hash failed");
fclose(f);
return 0;
}
}
fprintf(f, "%s ", store_hash ? hashed_host : host);
if (key_write(key, f)) {
success = 1;
} else {
error("add_host_to_hostfile: saving key in %s failed", filename);
}
fprintf(f, "\n");
success = write_host_entry(f, host, NULL, key, store_hash);
fclose(f);
return success;
}
struct host_delete_ctx {
FILE *out;
int quiet;
const char *host;
int *skip_keys; /* XXX split for host/ip? might want to ensure both */
struct sshkey * const *keys;
size_t nkeys;
int modified;
};
static int
host_delete(struct hostkey_foreach_line *l, void *_ctx)
{
struct host_delete_ctx *ctx = (struct host_delete_ctx *)_ctx;
int loglevel = ctx->quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE;
size_t i;
if (l->status == HKF_STATUS_MATCHED) {
if (l->marker != MRK_NONE) {
/* Don't remove CA and revocation lines */
fprintf(ctx->out, "%s\n", l->line);
return 0;
}
/* XXX might need a knob for this later */
/* Don't remove RSA1 keys */
if (l->key->type == KEY_RSA1) {
fprintf(ctx->out, "%s\n", l->line);
return 0;
}
/*
* If this line contains one of the keys that we will be
* adding later, then don't change it and mark the key for
* skipping.
*/
for (i = 0; i < ctx->nkeys; i++) {
if (sshkey_equal(ctx->keys[i], l->key)) {
ctx->skip_keys[i] = 1;
fprintf(ctx->out, "%s\n", l->line);
debug3("%s: %s key already at %s:%ld", __func__,
sshkey_type(l->key), l->path, l->linenum);
return 0;
}
}
/*
* Hostname matches and has no CA/revoke marker, delete it
* by *not* writing the line to ctx->out.
*/
do_log2(loglevel, "%s%s%s:%ld: Removed %s key for host %s",
ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "",
l->path, l->linenum, sshkey_type(l->key), ctx->host);
ctx->modified = 1;
return 0;
}
/* Retain non-matching hosts and invalid lines when deleting */
if (l->status == HKF_STATUS_INVALID) {
do_log2(loglevel, "%s%s%s:%ld: invalid known_hosts entry",
ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "",
l->path, l->linenum);
}
fprintf(ctx->out, "%s\n", l->line);
return 0;
}
int
hostfile_replace_entries(const char *filename, const char *host, const char *ip,
struct sshkey **keys, size_t nkeys, int store_hash, int quiet, int hash_alg)
{
int r, fd, oerrno = 0;
int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE;
struct host_delete_ctx ctx;
char *fp, *temp = NULL, *back = NULL;
mode_t omask;
size_t i;
omask = umask(077);
memset(&ctx, 0, sizeof(ctx));
ctx.host = host;
ctx.quiet = quiet;
if ((ctx.skip_keys = calloc(nkeys, sizeof(*ctx.skip_keys))) == NULL)
return SSH_ERR_ALLOC_FAIL;
ctx.keys = keys;
ctx.nkeys = nkeys;
ctx.modified = 0;
/*
* Prepare temporary file for in-place deletion.
*/
if ((r = asprintf(&temp, "%s.XXXXXXXXXXX", filename)) < 0 ||
(r = asprintf(&back, "%s.old", filename)) < 0) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
if ((fd = mkstemp(temp)) == -1) {
oerrno = errno;
error("%s: mkstemp: %s", __func__, strerror(oerrno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
if ((ctx.out = fdopen(fd, "w")) == NULL) {
oerrno = errno;
close(fd);
error("%s: fdopen: %s", __func__, strerror(oerrno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
/* Remove all entries for the specified host from the file */
if ((r = hostkeys_foreach(filename, host_delete, &ctx, host, ip,
HKF_WANT_PARSE_KEY)) != 0) {
error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r));
goto fail;
}
/* Add the requested keys */
for (i = 0; i < nkeys; i++) {
if (ctx.skip_keys[i])
continue;
if ((fp = sshkey_fingerprint(keys[i], hash_alg,
SSH_FP_DEFAULT)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto fail;
}
do_log2(loglevel, "%s%sAdding new key for %s to %s: %s %s",
quiet ? __func__ : "", quiet ? ": " : "", host, filename,
sshkey_ssh_name(keys[i]), fp);
free(fp);
if (!write_host_entry(ctx.out, host, ip, keys[i], store_hash)) {
r = SSH_ERR_INTERNAL_ERROR;
goto fail;
}
ctx.modified = 1;
}
fclose(ctx.out);
ctx.out = NULL;
if (ctx.modified) {
/* Backup the original file and replace it with the temporary */
if (unlink(back) == -1 && errno != ENOENT) {
oerrno = errno;
error("%s: unlink %.100s: %s", __func__,
back, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
if (link(filename, back) == -1) {
oerrno = errno;
error("%s: link %.100s to %.100s: %s", __func__,
filename, back, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
if (rename(temp, filename) == -1) {
oerrno = errno;
error("%s: rename \"%s\" to \"%s\": %s", __func__,
temp, filename, strerror(errno));
r = SSH_ERR_SYSTEM_ERROR;
goto fail;
}
} else {
/* No changes made; just delete the temporary file */
if (unlink(temp) != 0)
error("%s: unlink \"%s\": %s", __func__,
temp, strerror(errno));
}
/* success */
r = 0;
fail:
if (temp != NULL && r != 0)
unlink(temp);
free(temp);
free(back);
if (ctx.out != NULL)
fclose(ctx.out);
free(ctx.skip_keys);
umask(omask);
if (r == SSH_ERR_SYSTEM_ERROR)
errno = oerrno;
return r;
}
static int
match_maybe_hashed(const char *host, const char *names, int *was_hashed)
{
int hashed = *names == HASH_DELIM;
const char *hashed_host;
size_t nlen = strlen(names);
if (was_hashed != NULL)
*was_hashed = hashed;
if (hashed) {
if ((hashed_host = host_hash(host, names, nlen)) == NULL)
return -1;
return nlen == strlen(hashed_host) &&
strncmp(hashed_host, names, nlen) == 0;
}
return match_hostname(host, names, nlen) == 1;
}
int
hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
const char *host, const char *ip, u_int options)
{
FILE *f;
char line[8192], oline[8192], ktype[128];
u_long linenum = 0;
char *cp, *cp2;
u_int kbits;
int hashed;
int s, r = 0;
struct hostkey_foreach_line lineinfo;
size_t l;
memset(&lineinfo, 0, sizeof(lineinfo));
if (host == NULL && (options & HKF_WANT_MATCH) != 0)
return SSH_ERR_INVALID_ARGUMENT;
if ((f = fopen(path, "r")) == NULL)
return SSH_ERR_SYSTEM_ERROR;
debug3("%s: reading file \"%s\"", __func__, path);
while (read_keyfile_line(f, path, line, sizeof(line), &linenum) == 0) {
line[strcspn(line, "\n")] = '\0';
strlcpy(oline, line, sizeof(oline));
sshkey_free(lineinfo.key);
memset(&lineinfo, 0, sizeof(lineinfo));
lineinfo.path = path;
lineinfo.linenum = linenum;
lineinfo.line = oline;
lineinfo.marker = MRK_NONE;
lineinfo.status = HKF_STATUS_OK;
lineinfo.keytype = KEY_UNSPEC;
/* Skip any leading whitespace, comments and empty lines. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
;
if (!*cp || *cp == '#' || *cp == '\n') {
if ((options & HKF_WANT_MATCH) == 0) {
lineinfo.status = HKF_STATUS_COMMENT;
if ((r = callback(&lineinfo, ctx)) != 0)
break;
}
continue;
}
if ((lineinfo.marker = check_markers(&cp)) == MRK_ERROR) {
verbose("%s: invalid marker at %s:%lu",
__func__, path, linenum);
if ((options & HKF_WANT_MATCH) == 0)
goto bad;
continue;
}
/* Find the end of the host name portion. */
for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
;
lineinfo.hosts = cp;
*cp2++ = '\0';
/* Check if the host name matches. */
if (host != NULL) {
if ((s = match_maybe_hashed(host, lineinfo.hosts,
&hashed)) == -1) {
debug2("%s: %s:%ld: bad host hash \"%.32s\"",
__func__, path, linenum, lineinfo.hosts);
goto bad;
}
if (s == 1) {
lineinfo.status = HKF_STATUS_MATCHED;
lineinfo.match |= HKF_MATCH_HOST |
(hashed ? HKF_MATCH_HOST_HASHED : 0);
}
/* Try matching IP address if supplied */
if (ip != NULL) {
if ((s = match_maybe_hashed(ip, lineinfo.hosts,
&hashed)) == -1) {
debug2("%s: %s:%ld: bad ip hash "
"\"%.32s\"", __func__, path,
linenum, lineinfo.hosts);
goto bad;
}
if (s == 1) {
lineinfo.status = HKF_STATUS_MATCHED;
lineinfo.match |= HKF_MATCH_IP |
(hashed ? HKF_MATCH_IP_HASHED : 0);
}
}
/*
* Skip this line if host matching requested and
* neither host nor address matched.
*/
if ((options & HKF_WANT_MATCH) != 0 &&
lineinfo.status != HKF_STATUS_MATCHED)
continue;
}
/* Got a match. Skip host name and any following whitespace */
for (; *cp2 == ' ' || *cp2 == '\t'; cp2++)
;
if (*cp2 == '\0' || *cp2 == '#') {
debug2("%s:%ld: truncated before key type",
path, linenum);
goto bad;
}
lineinfo.rawkey = cp = cp2;
if ((options & HKF_WANT_PARSE_KEY) != 0) {
/*
* Extract the key from the line. This will skip
* any leading whitespace. Ignore badly formatted
* lines.
*/
if ((lineinfo.key = sshkey_new(KEY_UNSPEC)) == NULL) {
error("%s: sshkey_new failed", __func__);
r = SSH_ERR_ALLOC_FAIL;
break;
}
if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) {
#ifdef WITH_SSH1
sshkey_free(lineinfo.key);
lineinfo.key = sshkey_new(KEY_RSA1);
if (lineinfo.key == NULL) {
error("%s: sshkey_new fail", __func__);
r = SSH_ERR_ALLOC_FAIL;
break;
}
if (!hostfile_read_key(&cp, &kbits,
lineinfo.key))
goto bad;
#else
goto bad;
#endif
}
lineinfo.keytype = lineinfo.key->type;
lineinfo.comment = cp;
} else {
/* Extract and parse key type */
l = strcspn(lineinfo.rawkey, " \t");
if (l <= 1 || l >= sizeof(ktype) ||
lineinfo.rawkey[l] == '\0')
goto bad;
memcpy(ktype, lineinfo.rawkey, l);
ktype[l] = '\0';
lineinfo.keytype = sshkey_type_from_name(ktype);
#ifdef WITH_SSH1
/*
* Assume RSA1 if the first component is a short
* decimal number.
*/
if (lineinfo.keytype == KEY_UNSPEC && l < 8 &&
strspn(ktype, "0123456789") == l)
lineinfo.keytype = KEY_RSA1;
#endif
/*
* Check that something other than whitespace follows
* the key type. This won't catch all corruption, but
* it does catch trivial truncation.
*/
cp2 += l; /* Skip past key type */
for (; *cp2 == ' ' || *cp2 == '\t'; cp2++)
;
if (*cp2 == '\0' || *cp2 == '#') {
debug2("%s:%ld: truncated after key type",
path, linenum);
lineinfo.keytype = KEY_UNSPEC;
}
if (lineinfo.keytype == KEY_UNSPEC) {
bad:
sshkey_free(lineinfo.key);
lineinfo.key = NULL;
lineinfo.status = HKF_STATUS_INVALID;
if ((r = callback(&lineinfo, ctx)) != 0)
break;
continue;
}
}
if ((r = callback(&lineinfo, ctx)) != 0)
break;
}
sshkey_free(lineinfo.key);
fclose(f);
return r;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: hostfile.h,v 1.20 2013/07/12 00:19:58 djm Exp $ */
/* $OpenBSD: hostfile.h,v 1.24 2015/02/16 22:08:57 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -26,7 +26,7 @@ struct hostkey_entry {
char *host;
char *file;
u_long line;
Key *key;
struct sshkey *key;
HostkeyMarker marker;
};
struct hostkeys;
@ -35,13 +35,18 @@ struct hostkeys *init_hostkeys(void);
void load_hostkeys(struct hostkeys *, const char *, const char *);
void free_hostkeys(struct hostkeys *);
HostStatus check_key_in_hostkeys(struct hostkeys *, Key *,
HostStatus check_key_in_hostkeys(struct hostkeys *, struct sshkey *,
const struct hostkey_entry **);
int lookup_key_in_hostkeys_by_type(struct hostkeys *, int,
const struct hostkey_entry **);
int hostfile_read_key(char **, int *, Key *);
int add_host_to_hostfile(const char *, const char *, const Key *, int);
int hostfile_read_key(char **, u_int *, struct sshkey *);
int add_host_to_hostfile(const char *, const char *,
const struct sshkey *, int);
int hostfile_replace_entries(const char *filename,
const char *host, const char *ip, struct sshkey **keys, size_t nkeys,
int store_hash, int quiet, int hash_alg);
#define HASH_MAGIC "|1|"
#define HASH_DELIM '|'
@ -51,4 +56,53 @@ int add_host_to_hostfile(const char *, const char *, const Key *, int);
char *host_hash(const char *, const char *, u_int);
/*
* Iterate through a hostkeys file, optionally parsing keys and matching
* hostnames. Allows access to the raw keyfile lines to allow
* streaming edits to the file to take place.
*/
#define HKF_WANT_MATCH (1) /* return only matching hosts/addrs */
#define HKF_WANT_PARSE_KEY (1<<1) /* need key parsed */
#define HKF_STATUS_OK 0 /* Line parsed, didn't match host */
#define HKF_STATUS_INVALID 1 /* line had parse error */
#define HKF_STATUS_COMMENT 2 /* valid line contained no key */
#define HKF_STATUS_MATCHED 3 /* hostname or IP matched */
#define HKF_MATCH_HOST (1) /* hostname matched */
#define HKF_MATCH_IP (1<<1) /* address matched */
#define HKF_MATCH_HOST_HASHED (1<<2) /* hostname was hashed */
#define HKF_MATCH_IP_HASHED (1<<3) /* address was hashed */
/* XXX HKF_MATCH_KEY_TYPE? */
/*
* The callback function receives this as an argument for each matching
* hostkey line. The callback may "steal" the 'key' field by setting it to NULL.
* If a parse error occurred, then "hosts" and subsequent options may be NULL.
*/
struct hostkey_foreach_line {
const char *path; /* Path of file */
u_long linenum; /* Line number */
u_int status; /* One of HKF_STATUS_* */
u_int match; /* Zero or more of HKF_MATCH_* OR'd together */
char *line; /* Entire key line; mutable by callback */
int marker; /* CA/revocation markers; indicated by MRK_* value */
const char *hosts; /* Raw hosts text, may be hashed or list multiple */
const char *rawkey; /* Text of key and any comment following it */
int keytype; /* Type of key; KEY_UNSPEC for invalid/comment lines */
struct sshkey *key; /* Key, if parsed ok and HKF_WANT_MATCH_HOST set */
const char *comment; /* Any comment following the key */
};
/*
* Callback fires for each line (or matching line if a HKF_WANT_* option
* is set). The foreach loop will terminate if the callback returns a non-
* zero exit status.
*/
typedef int hostkeys_foreach_fn(struct hostkey_foreach_line *l, void *ctx);
/* Iterate over a hostkeys file */
int hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
const char *host, const char *ip, u_int options);
#endif

View File

@ -23,10 +23,11 @@
#endif
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h> /* For CMSG_* */
#ifdef HAVE_LIMITS_H
# include <limits.h> /* For PATH_MAX */
# include <limits.h> /* For PATH_MAX, _POSIX_HOST_NAME_MAX */
#endif
#ifdef HAVE_BSTRING_H
# include <bstring.h>
@ -166,7 +167,9 @@
# endif
#endif
#ifdef WITH_OPENSSL
#include <openssl/opensslv.h> /* For OPENSSL_VERSION_NUMBER */
#endif
#include "defines.h"

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.c,v 1.99 2014/04/29 18:01:49 markus Exp $ */
/* $OpenBSD: kex.c,v 1.105 2015/01/30 00:22:25 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
@ -25,7 +25,7 @@
#include "includes.h"
#include <sys/param.h>
#include <sys/param.h> /* MAX roundup */
#include <signal.h>
#include <stdarg.h>
@ -37,20 +37,22 @@
#include <openssl/crypto.h>
#endif
#include "xmalloc.h"
#include "ssh2.h"
#include "buffer.h"
#include "packet.h"
#include "compat.h"
#include "cipher.h"
#include "key.h"
#include "sshkey.h"
#include "kex.h"
#include "log.h"
#include "mac.h"
#include "match.h"
#include "misc.h"
#include "dispatch.h"
#include "monitor.h"
#include "roaming.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "digest.h"
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
@ -62,12 +64,12 @@ extern const EVP_MD *evp_ssh_sha256(void);
#endif
/* prototype */
static void kex_kexinit_finish(Kex *);
static void kex_choose_conf(Kex *);
static int kex_choose_conf(struct ssh *);
static int kex_input_newkeys(int, u_int32_t, void *);
struct kexalg {
char *name;
int type;
u_int type;
int ec_nid;
int hash_alg;
};
@ -89,18 +91,17 @@ static const struct kexalg kexalgs[] = {
SSH_DIGEST_SHA512 },
# endif /* OPENSSL_HAS_NISTP521 */
#endif /* OPENSSL_HAS_ECC */
{ KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
#endif /* WITH_OPENSSL */
#ifdef HAVE_EVP_SHA256
#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
#endif /* HAVE_EVP_SHA256 */
#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
{ NULL, -1, -1, -1},
};
char *
kex_alg_list(char sep)
{
char *ret = NULL;
char *ret = NULL, *tmp;
size_t nlen, rlen = 0;
const struct kexalg *k;
@ -108,7 +109,11 @@ kex_alg_list(char sep)
if (ret != NULL)
ret[rlen++] = sep;
nlen = strlen(k->name);
ret = xrealloc(ret, 1, rlen + nlen + 2);
if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
free(ret);
return NULL;
}
ret = tmp;
memcpy(ret + rlen, k->name, nlen + 1);
rlen += nlen;
}
@ -135,7 +140,8 @@ kex_names_valid(const char *names)
if (names == NULL || strcmp(names, "") == 0)
return 0;
s = cp = xstrdup(names);
if ((s = cp = strdup(names)) == NULL)
return 0;
for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) {
if (kex_alg_by_name(p) == NULL) {
@ -150,56 +156,75 @@ kex_names_valid(const char *names)
}
/* put algorithm proposal into buffer */
static void
kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX])
int
kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
{
u_int i;
int r;
sshbuf_reset(b);
buffer_clear(b);
/*
* add a dummy cookie, the cookie will be overwritten by
* kex_send_kexinit(), each time a kexinit is set
*/
for (i = 0; i < KEX_COOKIE_LEN; i++)
buffer_put_char(b, 0);
for (i = 0; i < PROPOSAL_MAX; i++)
buffer_put_cstring(b, proposal[i]);
buffer_put_char(b, 0); /* first_kex_packet_follows */
buffer_put_int(b, 0); /* uint32 reserved */
for (i = 0; i < KEX_COOKIE_LEN; i++) {
if ((r = sshbuf_put_u8(b, 0)) != 0)
return r;
}
for (i = 0; i < PROPOSAL_MAX; i++) {
if ((r = sshbuf_put_cstring(b, proposal[i])) != 0)
return r;
}
if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */
(r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */
return r;
return 0;
}
/* parse buffer and return algorithm proposal */
static char **
kex_buf2prop(Buffer *raw, int *first_kex_follows)
int
kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
{
Buffer b;
struct sshbuf *b = NULL;
u_char v;
u_int i;
char **proposal;
char **proposal = NULL;
int r;
proposal = xcalloc(PROPOSAL_MAX, sizeof(char *));
buffer_init(&b);
buffer_append(&b, buffer_ptr(raw), buffer_len(raw));
/* skip cookie */
for (i = 0; i < KEX_COOKIE_LEN; i++)
buffer_get_char(&b);
*propp = NULL;
if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((b = sshbuf_fromb(raw)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */
goto out;
/* extract kex init proposal strings */
for (i = 0; i < PROPOSAL_MAX; i++) {
proposal[i] = buffer_get_cstring(&b,NULL);
if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0)
goto out;
debug2("kex_parse_kexinit: %s", proposal[i]);
}
/* first kex follows / reserved */
i = buffer_get_char(&b);
if ((r = sshbuf_get_u8(b, &v)) != 0 ||
(r = sshbuf_get_u32(b, &i)) != 0)
goto out;
if (first_kex_follows != NULL)
*first_kex_follows = i;
debug2("kex_parse_kexinit: first_kex_follows %d ", i);
i = buffer_get_int(&b);
debug2("kex_parse_kexinit: first_kex_follows %d ", v);
debug2("kex_parse_kexinit: reserved %u ", i);
buffer_free(&b);
return proposal;
r = 0;
*propp = proposal;
out:
if (r != 0 && proposal != NULL)
kex_prop_free(proposal);
sshbuf_free(b);
return r;
}
static void
void
kex_prop_free(char **proposal)
{
u_int i;
@ -210,97 +235,111 @@ kex_prop_free(char **proposal)
}
/* ARGSUSED */
static void
static int
kex_protocol_error(int type, u_int32_t seq, void *ctxt)
{
error("Hm, kex protocol error: type %d seq %u", type, seq);
return 0;
}
static void
kex_reset_dispatch(void)
kex_reset_dispatch(struct ssh *ssh)
{
dispatch_range(SSH2_MSG_TRANSPORT_MIN,
ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN,
SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
void
kex_finish(Kex *kex)
int
kex_send_newkeys(struct ssh *ssh)
{
kex_reset_dispatch();
int r;
packet_start(SSH2_MSG_NEWKEYS);
packet_send();
/* packet_write_wait(); */
kex_reset_dispatch(ssh);
if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
return r;
debug("SSH2_MSG_NEWKEYS sent");
debug("expecting SSH2_MSG_NEWKEYS");
packet_read_expect(SSH2_MSG_NEWKEYS);
packet_check_eom();
debug("SSH2_MSG_NEWKEYS received");
ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
return 0;
}
static int
kex_input_newkeys(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
int r;
debug("SSH2_MSG_NEWKEYS received");
ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error);
if ((r = sshpkt_get_end(ssh)) != 0)
return r;
kex->done = 1;
buffer_clear(&kex->peer);
/* buffer_clear(&kex->my); */
sshbuf_reset(kex->peer);
/* sshbuf_reset(kex->my); */
kex->flags &= ~KEX_INIT_SENT;
free(kex->name);
kex->name = NULL;
return 0;
}
void
kex_send_kexinit(Kex *kex)
int
kex_send_kexinit(struct ssh *ssh)
{
u_int32_t rnd = 0;
u_char *cookie;
u_int i;
struct kex *kex = ssh->kex;
int r;
if (kex == NULL) {
error("kex_send_kexinit: no kex, cannot rekey");
return;
}
if (kex->flags & KEX_INIT_SENT) {
debug("KEX_INIT_SENT");
return;
}
if (kex == NULL)
return SSH_ERR_INTERNAL_ERROR;
if (kex->flags & KEX_INIT_SENT)
return 0;
kex->done = 0;
/* generate a random cookie */
if (buffer_len(&kex->my) < KEX_COOKIE_LEN)
fatal("kex_send_kexinit: kex proposal too short");
cookie = buffer_ptr(&kex->my);
for (i = 0; i < KEX_COOKIE_LEN; i++) {
if (i % 4 == 0)
rnd = arc4random();
cookie[i] = rnd;
rnd >>= 8;
}
packet_start(SSH2_MSG_KEXINIT);
packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my));
packet_send();
if (sshbuf_len(kex->my) < KEX_COOKIE_LEN)
return SSH_ERR_INVALID_FORMAT;
if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL)
return SSH_ERR_INTERNAL_ERROR;
arc4random_buf(cookie, KEX_COOKIE_LEN);
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 ||
(r = sshpkt_putb(ssh, kex->my)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
return r;
debug("SSH2_MSG_KEXINIT sent");
kex->flags |= KEX_INIT_SENT;
return 0;
}
/* ARGSUSED */
void
int
kex_input_kexinit(int type, u_int32_t seq, void *ctxt)
{
char *ptr;
u_int i, dlen;
Kex *kex = (Kex *)ctxt;
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
const u_char *ptr;
u_int i;
size_t dlen;
int r;
debug("SSH2_MSG_KEXINIT received");
if (kex == NULL)
fatal("kex_input_kexinit: no kex, cannot rekey");
return SSH_ERR_INVALID_ARGUMENT;
ptr = packet_get_raw(&dlen);
buffer_append(&kex->peer, ptr, dlen);
ptr = sshpkt_ptr(ssh, &dlen);
if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
return r;
/* discard packet */
for (i = 0; i < KEX_COOKIE_LEN; i++)
packet_get_char();
if ((r = sshpkt_get_u8(ssh, NULL)) != 0)
return r;
for (i = 0; i < PROPOSAL_MAX; i++)
free(packet_get_string(NULL));
if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0)
return r;
/*
* XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
* KEX method has the server move first, but a server might be using
@ -311,55 +350,129 @@ kex_input_kexinit(int type, u_int32_t seq, void *ctxt)
* for cases where the server *doesn't* go first. I guess we should
* ignore it when it is set for these cases, which is what we do now.
*/
(void) packet_get_char(); /* first_kex_follows */
(void) packet_get_int(); /* reserved */
packet_check_eom();
if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */
(r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */
(r = sshpkt_get_end(ssh)) != 0)
return r;
kex_kexinit_finish(kex);
}
Kex *
kex_setup(char *proposal[PROPOSAL_MAX])
{
Kex *kex;
kex = xcalloc(1, sizeof(*kex));
buffer_init(&kex->peer);
buffer_init(&kex->my);
kex_prop2buf(&kex->my, proposal);
kex->done = 0;
kex_send_kexinit(kex); /* we start */
kex_reset_dispatch();
return kex;
}
static void
kex_kexinit_finish(Kex *kex)
{
if (!(kex->flags & KEX_INIT_SENT))
kex_send_kexinit(kex);
if ((r = kex_send_kexinit(ssh)) != 0)
return r;
if ((r = kex_choose_conf(ssh)) != 0)
return r;
kex_choose_conf(kex);
if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
return (kex->kex[kex->kex_type])(ssh);
if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX &&
kex->kex[kex->kex_type] != NULL) {
(kex->kex[kex->kex_type])(kex);
} else {
fatal("Unsupported key exchange %d", kex->kex_type);
}
return SSH_ERR_INTERNAL_ERROR;
}
static void
choose_enc(Enc *enc, char *client, char *server)
int
kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp)
{
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_reset_dispatch(ssh);
r = 0;
*kexp = kex;
out:
if (r != 0)
kex_free(kex);
return r;
}
void
kex_free_newkeys(struct newkeys *newkeys)
{
if (newkeys == NULL)
return;
if (newkeys->enc.key) {
explicit_bzero(newkeys->enc.key, newkeys->enc.key_len);
free(newkeys->enc.key);
newkeys->enc.key = NULL;
}
if (newkeys->enc.iv) {
explicit_bzero(newkeys->enc.iv, newkeys->enc.block_size);
free(newkeys->enc.iv);
newkeys->enc.iv = NULL;
}
free(newkeys->enc.name);
explicit_bzero(&newkeys->enc, sizeof(newkeys->enc));
free(newkeys->comp.name);
explicit_bzero(&newkeys->comp, sizeof(newkeys->comp));
mac_clear(&newkeys->mac);
if (newkeys->mac.key) {
explicit_bzero(newkeys->mac.key, newkeys->mac.key_len);
free(newkeys->mac.key);
newkeys->mac.key = NULL;
}
free(newkeys->mac.name);
explicit_bzero(&newkeys->mac, sizeof(newkeys->mac));
explicit_bzero(newkeys, sizeof(*newkeys));
free(newkeys);
}
void
kex_free(struct kex *kex)
{
u_int mode;
#ifdef WITH_OPENSSL
if (kex->dh)
DH_free(kex->dh);
#ifdef OPENSSL_HAS_ECC
if (kex->ec_client_key)
EC_KEY_free(kex->ec_client_key);
#endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
for (mode = 0; mode < MODE_MAX; mode++) {
kex_free_newkeys(kex->newkeys[mode]);
kex->newkeys[mode] = NULL;
}
sshbuf_free(kex->peer);
sshbuf_free(kex->my);
free(kex->session_id);
free(kex->client_version_string);
free(kex->server_version_string);
free(kex);
}
int
kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
{
int r;
if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0)
return r;
if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */
kex_free(ssh->kex);
ssh->kex = NULL;
return r;
}
return 0;
}
static int
choose_enc(struct sshenc *enc, char *client, char *server)
{
char *name = match_list(client, server, NULL);
if (name == NULL)
fatal("no matching cipher found: client %s server %s",
client, server);
return SSH_ERR_NO_CIPHER_ALG_MATCH;
if ((enc->cipher = cipher_by_name(name)) == NULL)
fatal("matching cipher is not supported: %s", name);
return SSH_ERR_INTERNAL_ERROR;
enc->name = name;
enc->enabled = 0;
enc->iv = NULL;
@ -367,31 +480,34 @@ choose_enc(Enc *enc, char *client, char *server)
enc->key = NULL;
enc->key_len = cipher_keylen(enc->cipher);
enc->block_size = cipher_blocksize(enc->cipher);
return 0;
}
static void
choose_mac(Mac *mac, char *client, char *server)
static int
choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server)
{
char *name = match_list(client, server, NULL);
if (name == NULL)
fatal("no matching mac found: client %s server %s",
client, server);
return SSH_ERR_NO_MAC_ALG_MATCH;
if (mac_setup(mac, name) < 0)
fatal("unsupported mac %s", name);
return SSH_ERR_INTERNAL_ERROR;
/* truncate the key */
if (datafellows & SSH_BUG_HMAC)
if (ssh->compat & SSH_BUG_HMAC)
mac->key_len = 16;
mac->name = name;
mac->key = NULL;
mac->enabled = 0;
return 0;
}
static void
choose_comp(Comp *comp, char *client, char *server)
static int
choose_comp(struct sshcomp *comp, char *client, char *server)
{
char *name = match_list(client, server, NULL);
if (name == NULL)
fatal("no matching comp found: client %s server %s", client, server);
return SSH_ERR_NO_COMPRESS_ALG_MATCH;
if (strcmp(name, "zlib@openssh.com") == 0) {
comp->type = COMP_DELAYED;
} else if (strcmp(name, "zlib") == 0) {
@ -399,36 +515,42 @@ choose_comp(Comp *comp, char *client, char *server)
} else if (strcmp(name, "none") == 0) {
comp->type = COMP_NONE;
} else {
fatal("unsupported comp %s", name);
return SSH_ERR_INTERNAL_ERROR;
}
comp->name = name;
return 0;
}
static void
choose_kex(Kex *k, char *client, char *server)
static int
choose_kex(struct kex *k, char *client, char *server)
{
const struct kexalg *kexalg;
k->name = match_list(client, server, NULL);
if (k->name == NULL)
fatal("Unable to negotiate a key exchange method");
return SSH_ERR_NO_KEX_ALG_MATCH;
if ((kexalg = kex_alg_by_name(k->name)) == NULL)
fatal("unsupported kex alg %s", k->name);
return SSH_ERR_INTERNAL_ERROR;
k->kex_type = kexalg->type;
k->hash_alg = kexalg->hash_alg;
k->ec_nid = kexalg->ec_nid;
return 0;
}
static void
choose_hostkeyalg(Kex *k, char *client, char *server)
static int
choose_hostkeyalg(struct kex *k, char *client, char *server)
{
char *hostkeyalg = match_list(client, server, NULL);
if (hostkeyalg == NULL)
fatal("no hostkey alg");
k->hostkey_type = key_type_from_name(hostkeyalg);
return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
k->hostkey_type = sshkey_type_from_name(hostkeyalg);
if (k->hostkey_type == KEY_UNSPEC)
fatal("bad hostkey alg '%s'", hostkeyalg);
return SSH_ERR_INTERNAL_ERROR;
k->hostkey_nid = sshkey_ecdsa_nid_from_name(hostkeyalg);
free(hostkeyalg);
return 0;
}
static int
@ -455,18 +577,20 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
return (1);
}
static void
kex_choose_conf(Kex *kex)
static int
kex_choose_conf(struct ssh *ssh)
{
Newkeys *newkeys;
char **my, **peer;
struct kex *kex = ssh->kex;
struct newkeys *newkeys;
char **my = NULL, **peer = NULL;
char **cprop, **sprop;
int nenc, nmac, ncomp;
u_int mode, ctos, need, dh_need, authlen;
int first_kex_follows, type;
int r, first_kex_follows;
my = kex_buf2prop(&kex->my, NULL);
peer = kex_buf2prop(&kex->peer, &first_kex_follows);
if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 ||
(r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0)
goto out;
if (kex->server) {
cprop=peer;
@ -478,8 +602,9 @@ kex_choose_conf(Kex *kex)
/* Check whether server offers roaming */
if (!kex->server) {
char *roaming;
roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL);
char *roaming = match_list(KEX_RESUME,
peer[PROPOSAL_KEX_ALGS], NULL);
if (roaming) {
kex->roaming = 1;
free(roaming);
@ -488,28 +613,39 @@ kex_choose_conf(Kex *kex)
/* Algorithm Negotiation */
for (mode = 0; mode < MODE_MAX; mode++) {
newkeys = xcalloc(1, sizeof(*newkeys));
if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
kex->newkeys[mode] = newkeys;
ctos = (!kex->server && mode == MODE_OUT) ||
(kex->server && mode == MODE_IN);
nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
choose_enc(&newkeys->enc, cprop[nenc], sprop[nenc]);
/* ignore mac for authenticated encryption */
if ((r = choose_enc(&newkeys->enc, cprop[nenc],
sprop[nenc])) != 0)
goto out;
authlen = cipher_authlen(newkeys->enc.cipher);
if (authlen == 0)
choose_mac(&newkeys->mac, cprop[nmac], sprop[nmac]);
choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]);
/* ignore mac for authenticated encryption */
if (authlen == 0 &&
(r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
sprop[nmac])) != 0)
goto out;
if ((r = choose_comp(&newkeys->comp, cprop[ncomp],
sprop[ncomp])) != 0)
goto out;
debug("kex: %s %s %s %s",
ctos ? "client->server" : "server->client",
newkeys->enc.name,
authlen == 0 ? newkeys->mac.name : "<implicit>",
newkeys->comp.name);
}
choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
sprop[PROPOSAL_KEX_ALGS])) != 0 ||
(r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0)
goto out;
need = dh_need = 0;
for (mode = 0; mode < MODE_MAX; mode++) {
newkeys = kex->newkeys[mode];
@ -528,45 +664,47 @@ kex_choose_conf(Kex *kex)
/* ignore the next message if the proposals do not match */
if (first_kex_follows && !proposals_match(my, peer) &&
!(datafellows & SSH_BUG_FIRSTKEX)) {
type = packet_read();
debug2("skipping next packet (type %u)", type);
}
!(ssh->compat & SSH_BUG_FIRSTKEX))
ssh->dispatch_skip_packets = 1;
r = 0;
out:
kex_prop_free(my);
kex_prop_free(peer);
return r;
}
static u_char *
derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen,
const u_char *shared_secret, u_int slen)
static int
derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
const struct sshbuf *shared_secret, u_char **keyp)
{
Buffer b;
struct ssh_digest_ctx *hashctx;
struct kex *kex = ssh->kex;
struct ssh_digest_ctx *hashctx = NULL;
char c = id;
u_int have;
size_t mdsz;
u_char *digest;
int r;
if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0)
fatal("bad kex md size %zu", mdsz);
digest = xmalloc(roundup(need, mdsz));
buffer_init(&b);
buffer_append(&b, shared_secret, slen);
return SSH_ERR_INVALID_ARGUMENT;
if ((digest = calloc(1, roundup(need, mdsz))) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* K1 = HASH(K || H || "A" || session_id) */
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL)
fatal("%s: ssh_digest_start failed", __func__);
if (ssh_digest_update_buffer(hashctx, &b) != 0 ||
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
ssh_digest_update(hashctx, hash, hashlen) != 0 ||
ssh_digest_update(hashctx, &c, 1) != 0 ||
ssh_digest_update(hashctx, kex->session_id,
kex->session_id_len) != 0)
fatal("%s: ssh_digest_update failed", __func__);
if (ssh_digest_final(hashctx, digest, mdsz) != 0)
fatal("%s: ssh_digest_final failed", __func__);
kex->session_id_len) != 0 ||
ssh_digest_final(hashctx, digest, mdsz) != 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
ssh_digest_free(hashctx);
hashctx = NULL;
/*
* expand key:
@ -574,107 +712,115 @@ derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen,
* Key = K1 || K2 || ... || Kn
*/
for (have = mdsz; need > have; have += mdsz) {
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL)
fatal("%s: ssh_digest_start failed", __func__);
if (ssh_digest_update_buffer(hashctx, &b) != 0 ||
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
ssh_digest_update(hashctx, hash, hashlen) != 0 ||
ssh_digest_update(hashctx, digest, have) != 0)
fatal("%s: ssh_digest_update failed", __func__);
if (ssh_digest_final(hashctx, digest + have, mdsz) != 0)
fatal("%s: ssh_digest_final failed", __func__);
ssh_digest_update(hashctx, digest, have) != 0 ||
ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
ssh_digest_free(hashctx);
hashctx = NULL;
}
buffer_free(&b);
#ifdef DEBUG_KEX
fprintf(stderr, "key '%c'== ", c);
dump_digest("key", digest, need);
#endif
return digest;
*keyp = digest;
digest = NULL;
r = 0;
out:
if (digest)
free(digest);
ssh_digest_free(hashctx);
return r;
}
Newkeys *current_keys[MODE_MAX];
#define NKEYS 6
void
kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen,
const u_char *shared_secret, u_int slen)
int
kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
const struct sshbuf *shared_secret)
{
struct kex *kex = ssh->kex;
u_char *keys[NKEYS];
u_int i, mode, ctos;
u_int i, j, mode, ctos;
int r;
for (i = 0; i < NKEYS; i++) {
keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen,
shared_secret, slen);
if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen,
shared_secret, &keys[i])) != 0) {
for (j = 0; j < i; j++)
free(keys[j]);
return r;
}
}
debug2("kex_derive_keys");
for (mode = 0; mode < MODE_MAX; mode++) {
current_keys[mode] = kex->newkeys[mode];
kex->newkeys[mode] = NULL;
ctos = (!kex->server && mode == MODE_OUT) ||
(kex->server && mode == MODE_IN);
current_keys[mode]->enc.iv = keys[ctos ? 0 : 1];
current_keys[mode]->enc.key = keys[ctos ? 2 : 3];
current_keys[mode]->mac.key = keys[ctos ? 4 : 5];
kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1];
kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3];
kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5];
}
return 0;
}
#ifdef WITH_OPENSSL
void
kex_derive_keys_bn(Kex *kex, u_char *hash, u_int hashlen, const BIGNUM *secret)
int
kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen,
const BIGNUM *secret)
{
Buffer shared_secret;
struct sshbuf *shared_secret;
int r;
buffer_init(&shared_secret);
buffer_put_bignum2(&shared_secret, secret);
kex_derive_keys(kex, hash, hashlen,
buffer_ptr(&shared_secret), buffer_len(&shared_secret));
buffer_free(&shared_secret);
if ((shared_secret = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0)
r = kex_derive_keys(ssh, hash, hashlen, shared_secret);
sshbuf_free(shared_secret);
return r;
}
#endif
Newkeys *
kex_get_newkeys(int mode)
{
Newkeys *ret;
ret = current_keys[mode];
current_keys[mode] = NULL;
return ret;
}
#ifdef WITH_SSH1
void
int
derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
u_int8_t cookie[8], u_int8_t id[16])
{
u_int8_t nbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
int len;
struct ssh_digest_ctx *hashctx;
u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
struct ssh_digest_ctx *hashctx = NULL;
size_t hlen, slen;
int r;
if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL)
fatal("%s: ssh_digest_start", __func__);
len = BN_num_bytes(host_modulus);
if (len < (512 / 8) || (u_int)len > sizeof(nbuf))
fatal("%s: bad host modulus (len %d)", __func__, len);
BN_bn2bin(host_modulus, nbuf);
if (ssh_digest_update(hashctx, nbuf, len) != 0)
fatal("%s: ssh_digest_update failed", __func__);
len = BN_num_bytes(server_modulus);
if (len < (512 / 8) || (u_int)len > sizeof(nbuf))
fatal("%s: bad server modulus (len %d)", __func__, len);
BN_bn2bin(server_modulus, nbuf);
if (ssh_digest_update(hashctx, nbuf, len) != 0 ||
ssh_digest_update(hashctx, cookie, 8) != 0)
fatal("%s: ssh_digest_update failed", __func__);
if (ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0)
fatal("%s: ssh_digest_final failed", __func__);
hlen = BN_num_bytes(host_modulus);
slen = BN_num_bytes(server_modulus);
if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) ||
slen < (512 / 8) || (u_int)slen > sizeof(sbuf))
return SSH_ERR_KEY_BITS_MISMATCH;
if (BN_bn2bin(host_modulus, hbuf) <= 0 ||
BN_bn2bin(server_modulus, sbuf) <= 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (ssh_digest_update(hashctx, hbuf, hlen) != 0 ||
ssh_digest_update(hashctx, sbuf, slen) != 0 ||
ssh_digest_update(hashctx, cookie, 8) != 0 ||
ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5));
explicit_bzero(nbuf, sizeof(nbuf));
r = 0;
out:
ssh_digest_free(hashctx);
explicit_bzero(hbuf, sizeof(hbuf));
explicit_bzero(sbuf, sizeof(sbuf));
explicit_bzero(obuf, sizeof(obuf));
return r;
}
#endif
@ -682,16 +828,7 @@ derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
void
dump_digest(char *msg, u_char *digest, int len)
{
int i;
fprintf(stderr, "%s\n", msg);
for (i = 0; i < len; i++) {
fprintf(stderr, "%02x", digest[i]);
if (i%32 == 31)
fprintf(stderr, "\n");
else if (i%8 == 7)
fprintf(stderr, " ");
}
fprintf(stderr, "\n");
sshbuf_dump_data(digest, len, stderr);
}
#endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.h,v 1.64 2014/05/02 03:27:54 djm Exp $ */
/* $OpenBSD: kex.h,v 1.71 2015/02/16 22:13:32 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -26,13 +26,28 @@
#ifndef KEX_H
#define KEX_H
#include <signal.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#ifdef OPENSSL_HAS_ECC
#include <openssl/ec.h>
#include "mac.h"
#include "buffer.h" /* XXX for typedef */
#include "key.h" /* XXX for typedef */
#ifdef WITH_LEAKMALLOC
#include "leakmalloc.h"
#endif
#ifdef WITH_OPENSSL
# ifdef OPENSSL_HAS_ECC
# include <openssl/ec.h>
# else /* OPENSSL_HAS_ECC */
# define EC_KEY void
# define EC_GROUP void
# define EC_POINT void
# endif /* OPENSSL_HAS_ECC */
#else /* WITH_OPENSSL */
# define EC_KEY void
# define EC_GROUP void
# define EC_POINT void
#endif /* WITH_OPENSSL */
#define KEX_COOKIE_LEN 16
#define KEX_DH1 "diffie-hellman-group1-sha1"
@ -49,6 +64,8 @@
#define COMP_ZLIB 1
#define COMP_DELAYED 2
#define CURVE25519_SIZE 32
enum kex_init_proposals {
PROPOSAL_KEX_ALGS,
PROPOSAL_SERVER_HOST_KEY_ALGS,
@ -81,15 +98,9 @@ enum kex_exchange {
#define KEX_INIT_SENT 0x0001
typedef struct Kex Kex;
typedef struct Mac Mac;
typedef struct Comp Comp;
typedef struct Enc Enc;
typedef struct Newkeys Newkeys;
struct Enc {
struct sshenc {
char *name;
const Cipher *cipher;
const struct sshcipher *cipher;
int enabled;
u_int key_len;
u_int iv_len;
@ -97,108 +108,120 @@ struct Enc {
u_char *key;
u_char *iv;
};
struct Mac {
char *name;
int enabled;
u_int mac_len;
u_char *key;
u_int key_len;
int type;
int etm; /* Encrypt-then-MAC */
struct ssh_hmac_ctx *hmac_ctx;
struct umac_ctx *umac_ctx;
};
struct Comp {
int type;
struct sshcomp {
u_int type;
int enabled;
char *name;
};
struct Newkeys {
Enc enc;
Mac mac;
Comp comp;
struct newkeys {
struct sshenc enc;
struct sshmac mac;
struct sshcomp comp;
};
struct Kex {
struct ssh;
struct kex {
u_char *session_id;
u_int session_id_len;
Newkeys *newkeys[MODE_MAX];
size_t session_id_len;
struct newkeys *newkeys[MODE_MAX];
u_int we_need;
u_int dh_need;
int server;
char *name;
int hostkey_type;
int kex_type;
int hostkey_nid;
u_int kex_type;
int roaming;
Buffer my;
Buffer peer;
struct sshbuf *my;
struct sshbuf *peer;
sig_atomic_t done;
int flags;
u_int flags;
int hash_alg;
int ec_nid;
char *client_version_string;
char *server_version_string;
int (*verify_host_key)(Key *);
Key *(*load_host_public_key)(int);
Key *(*load_host_private_key)(int);
int (*host_key_index)(Key *);
void (*sign)(Key *, Key *, u_char **, u_int *, u_char *, u_int);
void (*kex[KEX_MAX])(Kex *);
int (*verify_host_key)(struct sshkey *, struct ssh *);
struct sshkey *(*load_host_public_key)(int, int, struct ssh *);
struct sshkey *(*load_host_private_key)(int, int, struct ssh *);
int (*host_key_index)(struct sshkey *, int, struct ssh *);
int (*sign)(struct sshkey *, struct sshkey *,
u_char **, size_t *, const u_char *, size_t, u_int);
int (*kex[KEX_MAX])(struct ssh *);
/* kex specific state */
DH *dh; /* DH */
u_int min, max, nbits; /* GEX */
EC_KEY *ec_client_key; /* ECDH */
const EC_GROUP *ec_group; /* ECDH */
u_char c25519_client_key[CURVE25519_SIZE]; /* 25519 */
u_char c25519_client_pubkey[CURVE25519_SIZE]; /* 25519 */
};
int kex_names_valid(const char *);
char *kex_alg_list(char);
Kex *kex_setup(char *[PROPOSAL_MAX]);
void kex_finish(Kex *);
int kex_new(struct ssh *, char *[PROPOSAL_MAX], struct kex **);
int kex_setup(struct ssh *, char *[PROPOSAL_MAX]);
void kex_free_newkeys(struct newkeys *);
void kex_free(struct kex *);
void kex_send_kexinit(Kex *);
void kex_input_kexinit(int, u_int32_t, void *);
void kex_derive_keys(Kex *, u_char *, u_int, const u_char *, u_int);
void kex_derive_keys_bn(Kex *, u_char *, u_int, const BIGNUM *);
int kex_buf2prop(struct sshbuf *, int *, char ***);
int kex_prop2buf(struct sshbuf *, char *proposal[PROPOSAL_MAX]);
void kex_prop_free(char **);
Newkeys *kex_get_newkeys(int);
int kex_send_kexinit(struct ssh *);
int kex_input_kexinit(int, u_int32_t, void *);
int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *);
int kex_derive_keys_bn(struct ssh *, u_char *, u_int, const BIGNUM *);
int kex_send_newkeys(struct ssh *);
void kexdh_client(Kex *);
void kexdh_server(Kex *);
void kexgex_client(Kex *);
void kexgex_server(Kex *);
void kexecdh_client(Kex *);
void kexecdh_server(Kex *);
void kexc25519_client(Kex *);
void kexc25519_server(Kex *);
int kexdh_client(struct ssh *);
int kexdh_server(struct ssh *);
int kexgex_client(struct ssh *);
int kexgex_server(struct ssh *);
int kexecdh_client(struct ssh *);
int kexecdh_server(struct ssh *);
int kexc25519_client(struct ssh *);
int kexc25519_server(struct ssh *);
void
kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
void
kexgex_hash(int, char *, char *, char *, int, char *,
int, u_char *, int, int, int, int, BIGNUM *, BIGNUM *, BIGNUM *,
BIGNUM *, BIGNUM *, u_char **, u_int *);
#ifdef OPENSSL_HAS_ECC
void
kex_ecdh_hash(int, const EC_GROUP *, char *, char *, char *, int,
char *, int, u_char *, int, const EC_POINT *, const EC_POINT *,
const BIGNUM *, u_char **, u_int *);
#endif
void
kex_c25519_hash(int, char *, char *, char *, int,
char *, int, u_char *, int, const u_char *, const u_char *,
const u_char *, u_int, u_char **, u_int *);
int kex_dh_hash(const char *, const char *,
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 *);
#define CURVE25519_SIZE 32
void kexc25519_keygen(u_char[CURVE25519_SIZE], u_char[CURVE25519_SIZE])
int kexgex_hash(int, const char *, const char *,
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 *,
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 *, const char *, size_t,
const char *, size_t, const u_char *, size_t, const u_char *, const u_char *,
const u_char *, size_t, u_char *, size_t *);
void kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
void kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
const u_char pub[CURVE25519_SIZE], Buffer *out)
int kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
void
int
derive_ssh1_session_id(BIGNUM *, BIGNUM *, u_int8_t[8], u_int8_t[16]);
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
void dump_digest(char *, u_char *, int);
#endif
#if !defined(WITH_OPENSSL) || !defined(OPENSSL_HAS_ECC)
# undef EC_KEY
# undef EC_GROUP
# undef EC_POINT
#endif
#endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexc25519.c,v 1.7 2014/05/02 03:27:54 djm Exp $ */
/* $OpenBSD: kexc25519.c,v 1.8 2015/01/19 20:16:15 markus Exp $ */
/*
* Copyright (c) 2001, 2013 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -35,13 +35,14 @@
#include <openssl/bn.h>
#include <openssl/evp.h>
#include "buffer.h"
#include "sshbuf.h"
#include "ssh2.h"
#include "key.h"
#include "sshkey.h"
#include "cipher.h"
#include "kex.h"
#include "log.h"
#include "digest.h"
#include "ssherr.h"
extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE],
const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE])
@ -58,65 +59,70 @@ kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
crypto_scalarmult_curve25519(pub, key, basepoint);
}
void
int
kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
const u_char pub[CURVE25519_SIZE], Buffer *out)
const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
{
u_char shared_key[CURVE25519_SIZE];
int r;
crypto_scalarmult_curve25519(shared_key, key, pub);
#ifdef DEBUG_KEXECDH
dump_digest("shared secret", shared_key, CURVE25519_SIZE);
#endif
buffer_clear(out);
buffer_put_bignum2_from_string(out, shared_key, CURVE25519_SIZE);
sshbuf_reset(out);
r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
explicit_bzero(shared_key, CURVE25519_SIZE);
return r;
}
void
int
kex_c25519_hash(
int hash_alg,
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
u_char *serverhostkeyblob, int sbloblen,
const char *client_version_string,
const char *server_version_string,
const char *ckexinit, size_t ckexinitlen,
const char *skexinit, size_t skexinitlen,
const u_char *serverhostkeyblob, size_t sbloblen,
const u_char client_dh_pub[CURVE25519_SIZE],
const u_char server_dh_pub[CURVE25519_SIZE],
const u_char *shared_secret, u_int secretlen,
u_char **hash, u_int *hashlen)
const u_char *shared_secret, size_t secretlen,
u_char *hash, size_t *hashlen)
{
Buffer b;
static u_char digest[SSH_DIGEST_MAX_LENGTH];
buffer_init(&b);
buffer_put_cstring(&b, client_version_string);
buffer_put_cstring(&b, server_version_string);
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
buffer_put_string(&b, client_dh_pub, CURVE25519_SIZE);
buffer_put_string(&b, server_dh_pub, CURVE25519_SIZE);
buffer_append(&b, shared_secret, secretlen);
struct sshbuf *b;
int r;
if (*hashlen < ssh_digest_bytes(hash_alg))
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 ||
/* 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 ||
(r = sshbuf_put(b, ckexinit, ckexinitlen)) < 0 ||
(r = sshbuf_put_u32(b, skexinitlen+1)) < 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) < 0 ||
(r = sshbuf_put(b, skexinit, skexinitlen)) < 0 ||
(r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) < 0 ||
(r = sshbuf_put_string(b, client_dh_pub, CURVE25519_SIZE)) < 0 ||
(r = sshbuf_put_string(b, server_dh_pub, CURVE25519_SIZE)) < 0 ||
(r = sshbuf_put(b, shared_secret, secretlen)) < 0) {
sshbuf_free(b);
return r;
}
#ifdef DEBUG_KEX
buffer_dump(&b);
sshbuf_dump(b, stderr);
#endif
if (ssh_digest_buffer(hash_alg, &b, digest, sizeof(digest)) != 0)
fatal("%s: digest_buffer failed", __func__);
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest("hash", digest, ssh_digest_bytes(hash_alg));
#endif
*hash = digest;
if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
sshbuf_free(b);
return SSH_ERR_LIBCRYPTO_ERROR;
}
sshbuf_free(b);
*hashlen = ssh_digest_bytes(hash_alg);
#ifdef DEBUG_KEX
dump_digest("hash", hash, *hashlen);
#endif
return 0;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexc25519c.c,v 1.4 2014/01/12 08:13:13 djm Exp $ */
/* $OpenBSD: kexc25519c.c,v 1.7 2015/01/26 06:10:03 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -33,97 +33,138 @@
#include <string.h>
#include <signal.h>
#include "xmalloc.h"
#include "buffer.h"
#include "key.h"
#include "sshkey.h"
#include "cipher.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "ssh2.h"
#include "sshbuf.h"
#include "digest.h"
#include "ssherr.h"
void
kexc25519_client(Kex *kex)
static int
input_kex_c25519_reply(int type, u_int32_t seq, void *ctxt);
int
kexc25519_client(struct ssh *ssh)
{
Key *server_host_key;
u_char client_key[CURVE25519_SIZE];
u_char client_pubkey[CURVE25519_SIZE];
u_char *server_pubkey = NULL;
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *hash;
u_int slen, sbloblen, hashlen;
Buffer shared_secret;
kexc25519_keygen(client_key, client_pubkey);
packet_start(SSH2_MSG_KEX_ECDH_INIT);
packet_put_string(client_pubkey, sizeof(client_pubkey));
packet_send();
debug("sending SSH2_MSG_KEX_ECDH_INIT");
struct kex *kex = ssh->kex;
int r;
kexc25519_keygen(kex->c25519_client_key, kex->c25519_client_pubkey);
#ifdef DEBUG_KEXECDH
dump_digest("client private key:", client_key, sizeof(client_key));
dump_digest("client private key:", kex->c25519_client_key,
sizeof(kex->c25519_client_key));
#endif
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
(r = sshpkt_put_string(ssh, kex->c25519_client_pubkey,
sizeof(kex->c25519_client_pubkey))) != 0 ||
(r = sshpkt_send(ssh)) != 0)
return r;
debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
packet_read_expect(SSH2_MSG_KEX_ECDH_REPLY);
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_c25519_reply);
return 0;
}
static int
input_kex_c25519_reply(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
struct sshkey *server_host_key = NULL;
struct sshbuf *shared_secret = NULL;
u_char *server_pubkey = NULL;
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t slen, pklen, sbloblen, hashlen;
int r;
if (kex->verify_host_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
/* hostkey */
server_host_key_blob = packet_get_string(&sbloblen);
server_host_key = key_from_blob(server_host_key_blob, sbloblen);
if (server_host_key == NULL)
fatal("cannot decode server_host_key_blob");
if (server_host_key->type != kex->hostkey_type)
fatal("type mismatch for decoded server_host_key_blob");
if (kex->verify_host_key == NULL)
fatal("cannot verify server_host_key");
if (kex->verify_host_key(server_host_key) == -1)
fatal("server_host_key verification failed");
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
&sbloblen)) != 0 ||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
&server_host_key)) != 0)
goto out;
if (server_host_key->type != kex->hostkey_type ||
(kex->hostkey_type == KEY_ECDSA &&
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
if (kex->verify_host_key(server_host_key, ssh) == -1) {
r = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
/* Q_S, server public key */
server_pubkey = packet_get_string(&slen);
if (slen != CURVE25519_SIZE)
fatal("Incorrect size for server Curve25519 pubkey: %d", slen);
/* signed H */
if ((r = sshpkt_get_string(ssh, &server_pubkey, &pklen)) != 0 ||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
if (pklen != CURVE25519_SIZE) {
r = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
#ifdef DEBUG_KEXECDH
dump_digest("server public key:", server_pubkey, CURVE25519_SIZE);
#endif
/* signed H */
signature = packet_get_string(&slen);
packet_check_eom();
buffer_init(&shared_secret);
kexc25519_shared_key(client_key, server_pubkey, &shared_secret);
if ((shared_secret = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = kexc25519_shared_key(kex->c25519_client_key, server_pubkey,
shared_secret)) < 0)
goto out;
/* calc and verify H */
kex_c25519_hash(
hashlen = sizeof(hash);
if ((r = kex_c25519_hash(
kex->hash_alg,
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->my), buffer_len(&kex->my),
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
server_host_key_blob, sbloblen,
client_pubkey,
kex->c25519_client_pubkey,
server_pubkey,
buffer_ptr(&shared_secret), buffer_len(&shared_secret),
&hash, &hashlen
);
free(server_host_key_blob);
free(server_pubkey);
if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1)
fatal("key_verify failed for server_host_key");
key_free(server_host_key);
free(signature);
sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
hash, &hashlen)) < 0)
goto out;
if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
ssh->compat)) != 0)
goto out;
/* save session id */
if (kex->session_id == NULL) {
kex->session_id_len = hashlen;
kex->session_id = xmalloc(kex->session_id_len);
kex->session_id = malloc(kex->session_id_len);
if (kex->session_id == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(kex->session_id, hash, kex->session_id_len);
}
kex_derive_keys(kex, hash, hashlen,
buffer_ptr(&shared_secret), buffer_len(&shared_secret));
buffer_free(&shared_secret);
kex_finish(kex);
if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
out:
explicit_bzero(hash, sizeof(hash));
explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
free(server_host_key_blob);
free(server_pubkey);
free(signature);
sshkey_free(server_host_key);
sshbuf_free(shared_secret);
return r;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexc25519s.c,v 1.4 2014/01/12 08:13:13 djm Exp $ */
/* $OpenBSD: kexc25519s.c,v 1.8 2015/01/26 06:10:03 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -30,97 +30,129 @@
#include <string.h>
#include <signal.h>
#include "xmalloc.h"
#include "buffer.h"
#include "key.h"
#include "sshkey.h"
#include "cipher.h"
#include "digest.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "ssh2.h"
#include "sshbuf.h"
#include "ssherr.h"
void
kexc25519_server(Kex *kex)
static int input_kex_c25519_init(int, u_int32_t, void *);
int
kexc25519_server(struct ssh *ssh)
{
Key *server_host_private, *server_host_public;
debug("expecting SSH2_MSG_KEX_ECDH_INIT");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_c25519_init);
return 0;
}
static int
input_kex_c25519_init(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
struct sshkey *server_host_private, *server_host_public;
struct sshbuf *shared_secret = NULL;
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char server_key[CURVE25519_SIZE];
u_char *client_pubkey = NULL;
u_char server_pubkey[CURVE25519_SIZE];
u_char *hash;
u_int slen, sbloblen, hashlen;
Buffer shared_secret;
u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t slen, pklen, sbloblen, hashlen;
int r;
/* generate private key */
kexc25519_keygen(server_key, server_pubkey);
#ifdef DEBUG_KEXECDH
dump_digest("server private key:", server_key, sizeof(server_key));
#endif
if (kex->load_host_public_key == NULL ||
kex->load_host_private_key == NULL)
fatal("Cannot load hostkey");
server_host_public = kex->load_host_public_key(kex->hostkey_type);
if (server_host_public == NULL)
fatal("Unsupported hostkey type %d", kex->hostkey_type);
server_host_private = kex->load_host_private_key(kex->hostkey_type);
debug("expecting SSH2_MSG_KEX_ECDH_INIT");
packet_read_expect(SSH2_MSG_KEX_ECDH_INIT);
client_pubkey = packet_get_string(&slen);
if (slen != CURVE25519_SIZE)
fatal("Incorrect size for server Curve25519 pubkey: %d", slen);
packet_check_eom();
kex->load_host_private_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
server_host_public = kex->load_host_public_key(kex->hostkey_type,
kex->hostkey_nid, ssh);
server_host_private = kex->load_host_private_key(kex->hostkey_type,
kex->hostkey_nid, ssh);
if (server_host_public == NULL) {
r = SSH_ERR_NO_HOSTKEY_LOADED;
goto out;
}
if ((r = sshpkt_get_string(ssh, &client_pubkey, &pklen)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
if (pklen != CURVE25519_SIZE) {
r = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
#ifdef DEBUG_KEXECDH
dump_digest("client public key:", client_pubkey, CURVE25519_SIZE);
#endif
buffer_init(&shared_secret);
kexc25519_shared_key(server_key, client_pubkey, &shared_secret);
if ((shared_secret = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = kexc25519_shared_key(server_key, client_pubkey,
shared_secret)) < 0)
goto out;
/* calc H */
key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
kex_c25519_hash(
if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
&sbloblen)) != 0)
goto out;
hashlen = sizeof(hash);
if ((r = kex_c25519_hash(
kex->hash_alg,
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
buffer_ptr(&kex->my), buffer_len(&kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
server_host_key_blob, sbloblen,
client_pubkey,
server_pubkey,
buffer_ptr(&shared_secret), buffer_len(&shared_secret),
&hash, &hashlen
);
sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
hash, &hashlen)) < 0)
goto out;
/* save session id := H */
if (kex->session_id == NULL) {
kex->session_id_len = hashlen;
kex->session_id = xmalloc(kex->session_id_len);
kex->session_id = malloc(kex->session_id_len);
if (kex->session_id == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(kex->session_id, hash, kex->session_id_len);
}
/* sign H */
kex->sign(server_host_private, server_host_public, &signature, &slen,
hash, hashlen);
/* destroy_sensitive_data(); */
if ((r = kex->sign(server_host_private, server_host_public,
&signature, &slen, hash, hashlen, ssh->compat)) < 0)
goto out;
/* send server hostkey, ECDH pubkey 'Q_S' and signed H */
packet_start(SSH2_MSG_KEX_ECDH_REPLY);
packet_put_string(server_host_key_blob, sbloblen);
packet_put_string(server_pubkey, sizeof(server_pubkey));
packet_put_string(signature, slen);
packet_send();
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
(r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
(r = sshpkt_put_string(ssh, server_pubkey, sizeof(server_pubkey))) != 0 ||
(r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
free(signature);
if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
out:
explicit_bzero(hash, sizeof(hash));
explicit_bzero(server_key, sizeof(server_key));
free(server_host_key_blob);
/* have keys, free server key */
free(signature);
free(client_pubkey);
kex_derive_keys(kex, hash, hashlen,
buffer_ptr(&shared_secret), buffer_len(&shared_secret));
buffer_free(&shared_secret);
kex_finish(kex);
sshbuf_free(shared_secret);
return r;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexdh.c,v 1.24 2014/01/09 23:20:00 djm Exp $ */
/* $OpenBSD: kexdh.c,v 1.25 2015/01/19 20:16:15 markus Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@ -25,63 +25,69 @@
#include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h>
#include <signal.h>
#include <openssl/evp.h>
#include "buffer.h"
#include "ssh2.h"
#include "key.h"
#include "sshkey.h"
#include "cipher.h"
#include "kex.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "digest.h"
#include "log.h"
void
int
kex_dh_hash(
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
u_char *serverhostkeyblob, int sbloblen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret,
u_char **hash, u_int *hashlen)
const char *client_version_string,
const char *server_version_string,
const u_char *ckexinit, size_t ckexinitlen,
const u_char *skexinit, size_t skexinitlen,
const u_char *serverhostkeyblob, size_t sbloblen,
const BIGNUM *client_dh_pub,
const BIGNUM *server_dh_pub,
const BIGNUM *shared_secret,
u_char *hash, size_t *hashlen)
{
Buffer b;
static u_char digest[SSH_DIGEST_MAX_LENGTH];
buffer_init(&b);
buffer_put_cstring(&b, client_version_string);
buffer_put_cstring(&b, server_version_string);
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
buffer_put_bignum2(&b, client_dh_pub);
buffer_put_bignum2(&b, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
struct sshbuf *b;
int r;
if (*hashlen < ssh_digest_bytes(SSH_DIGEST_SHA1))
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 ||
/* 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 ||
(r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
(r = sshbuf_put_u32(b, skexinitlen+1)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
(r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
(r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
(r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 ||
(r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 ||
(r = sshbuf_put_bignum2(b, shared_secret)) != 0) {
sshbuf_free(b);
return r;
}
#ifdef DEBUG_KEX
buffer_dump(&b);
sshbuf_dump(b, stderr);
#endif
if (ssh_digest_buffer(SSH_DIGEST_SHA1, &b, digest, sizeof(digest)) != 0)
fatal("%s: ssh_digest_buffer failed", __func__);
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest("hash", digest, ssh_digest_bytes(SSH_DIGEST_SHA1));
#endif
*hash = digest;
if (ssh_digest_buffer(SSH_DIGEST_SHA1, b, hash, *hashlen) != 0) {
sshbuf_free(b);
return SSH_ERR_LIBCRYPTO_ERROR;
}
sshbuf_free(b);
*hashlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
#ifdef DEBUG_KEX
dump_digest("hash", hash, *hashlen);
#endif
return 0;
}
#endif /* WITH_OPENSSL */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexdhc.c,v 1.15 2014/02/02 03:44:31 djm Exp $ */
/* $OpenBSD: kexdhc.c,v 1.18 2015/01/26 06:10:03 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@ -25,6 +25,8 @@
#include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h>
#include <openssl/dh.h>
@ -34,128 +36,177 @@
#include <string.h>
#include <signal.h>
#include "xmalloc.h"
#include "buffer.h"
#include "key.h"
#include "sshkey.h"
#include "cipher.h"
#include "digest.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "dh.h"
#include "ssh2.h"
#include "dispatch.h"
#include "compat.h"
#include "ssherr.h"
#include "sshbuf.h"
void
kexdh_client(Kex *kex)
static int input_kex_dh(int, u_int32_t, void *);
int
kexdh_client(struct ssh *ssh)
{
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
DH *dh;
Key *server_host_key;
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf, *hash;
u_int klen, slen, sbloblen, hashlen;
int kout;
struct kex *kex = ssh->kex;
int r;
/* generate and send 'e', client DH public key */
switch (kex->kex_type) {
case KEX_DH_GRP1_SHA1:
dh = dh_new_group1();
kex->dh = dh_new_group1();
break;
case KEX_DH_GRP14_SHA1:
dh = dh_new_group14();
kex->dh = dh_new_group14();
break;
default:
fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if (kex->dh == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
dh_gen_key(dh, kex->we_need * 8);
packet_start(SSH2_MSG_KEXDH_INIT);
packet_put_bignum2(dh->pub_key);
packet_send();
debug("sending SSH2_MSG_KEXDH_INIT");
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
(r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
DHparams_print_fp(stderr, kex->dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
BN_print_fp(stderr, kex->dh->pub_key);
fprintf(stderr, "\n");
#endif
debug("expecting SSH2_MSG_KEXDH_REPLY");
packet_read_expect(SSH2_MSG_KEXDH_REPLY);
ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh);
r = 0;
out:
return r;
}
static int
input_kex_dh(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
struct sshkey *server_host_key = NULL;
u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t klen = 0, slen, sbloblen, hashlen;
int kout, r;
if (kex->verify_host_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
/* key, cert */
server_host_key_blob = packet_get_string(&sbloblen);
server_host_key = key_from_blob(server_host_key_blob, sbloblen);
if (server_host_key == NULL)
fatal("cannot decode server_host_key_blob");
if (server_host_key->type != kex->hostkey_type)
fatal("type mismatch for decoded server_host_key_blob");
if (kex->verify_host_key == NULL)
fatal("cannot verify server_host_key");
if (kex->verify_host_key(server_host_key) == -1)
fatal("server_host_key verification failed");
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
&sbloblen)) != 0 ||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
&server_host_key)) != 0)
goto out;
if (server_host_key->type != kex->hostkey_type ||
(kex->hostkey_type == KEY_ECDSA &&
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
if (kex->verify_host_key(server_host_key, ssh) == -1) {
r = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
/* DH parameter f, server public DH key */
if ((dh_server_pub = BN_new()) == NULL)
fatal("dh_server_pub == NULL");
packet_get_bignum2(dh_server_pub);
if ((dh_server_pub = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* signed H */
if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_server_pub= ");
BN_print_fp(stderr, dh_server_pub);
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_server_pub));
#endif
if (!dh_pub_is_valid(kex->dh, dh_server_pub)) {
sshpkt_disconnect(ssh, "bad server public DH value");
r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out;
}
/* signed H */
signature = packet_get_string(&slen);
packet_check_eom();
if (!dh_pub_is_valid(dh, dh_server_pub))
packet_disconnect("bad server public DH value");
klen = DH_size(dh);
kbuf = xmalloc(klen);
if ((kout = DH_compute_key(kbuf, dh_server_pub, dh)) < 0)
fatal("DH_compute_key: failed");
klen = DH_size(kex->dh);
if ((kbuf = malloc(klen)) == NULL ||
(shared_secret = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
if ((shared_secret = BN_new()) == NULL)
fatal("kexdh_client: BN_new failed");
if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
fatal("kexdh_client: BN_bin2bn failed");
explicit_bzero(kbuf, klen);
free(kbuf);
/* calc and verify H */
kex_dh_hash(
hashlen = sizeof(hash);
if ((r = kex_dh_hash(
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->my), buffer_len(&kex->my),
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
server_host_key_blob, sbloblen,
dh->pub_key,
kex->dh->pub_key,
dh_server_pub,
shared_secret,
&hash, &hashlen
);
free(server_host_key_blob);
BN_clear_free(dh_server_pub);
DH_free(dh);
hash, &hashlen)) != 0)
goto out;
if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1)
fatal("key_verify failed for server_host_key");
key_free(server_host_key);
free(signature);
if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
ssh->compat)) != 0)
goto out;
/* save session id */
if (kex->session_id == NULL) {
kex->session_id_len = hashlen;
kex->session_id = xmalloc(kex->session_id_len);
kex->session_id = malloc(kex->session_id_len);
if (kex->session_id == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(kex->session_id, hash, kex->session_id_len);
}
kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
out:
explicit_bzero(hash, sizeof(hash));
DH_free(kex->dh);
kex->dh = NULL;
if (dh_server_pub)
BN_clear_free(dh_server_pub);
if (kbuf) {
explicit_bzero(kbuf, klen);
free(kbuf);
}
if (shared_secret)
BN_clear_free(shared_secret);
sshkey_free(server_host_key);
free(server_host_key_blob);
free(signature);
return r;
}
#endif /* WITH_OPENSSL */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexdhs.c,v 1.18 2014/02/02 03:44:31 djm Exp $ */
/* $OpenBSD: kexdhs.c,v 1.22 2015/01/26 06:10:03 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@ -25,6 +25,8 @@
#include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h>
#include <stdarg.h>
@ -33,55 +35,89 @@
#include <openssl/dh.h>
#include "xmalloc.h"
#include "buffer.h"
#include "key.h"
#include "sshkey.h"
#include "cipher.h"
#include "digest.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "dh.h"
#include "ssh2.h"
void
kexdh_server(Kex *kex)
#include "dispatch.h"
#include "compat.h"
#include "ssherr.h"
#include "sshbuf.h"
static int input_kex_dh_init(int, u_int32_t, void *);
int
kexdh_server(struct ssh *ssh)
{
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
DH *dh;
Key *server_host_public, *server_host_private;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int sbloblen, klen, hashlen, slen;
int kout;
struct kex *kex = ssh->kex;
int r;
/* generate server DH public key */
switch (kex->kex_type) {
case KEX_DH_GRP1_SHA1:
dh = dh_new_group1();
kex->dh = dh_new_group1();
break;
case KEX_DH_GRP14_SHA1:
dh = dh_new_group14();
kex->dh = dh_new_group14();
break;
default:
fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
dh_gen_key(dh, kex->we_need * 8);
if (kex->dh == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
goto out;
debug("expecting SSH2_MSG_KEXDH_INIT");
packet_read_expect(SSH2_MSG_KEXDH_INIT);
ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_INIT, &input_kex_dh_init);
r = 0;
out:
return r;
}
int
input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
struct sshkey *server_host_public, *server_host_private;
u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t sbloblen, slen;
size_t klen = 0, hashlen;
int kout, r;
if (kex->load_host_public_key == NULL ||
kex->load_host_private_key == NULL)
fatal("Cannot load hostkey");
server_host_public = kex->load_host_public_key(kex->hostkey_type);
if (server_host_public == NULL)
fatal("Unsupported hostkey type %d", kex->hostkey_type);
server_host_private = kex->load_host_private_key(kex->hostkey_type);
kex->load_host_private_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
server_host_public = kex->load_host_public_key(kex->hostkey_type,
kex->hostkey_nid, ssh);
server_host_private = kex->load_host_private_key(kex->hostkey_type,
kex->hostkey_nid, ssh);
if (server_host_public == NULL) {
r = SSH_ERR_NO_HOSTKEY_LOADED;
goto out;
}
/* key, cert */
if ((dh_client_pub = BN_new()) == NULL)
fatal("dh_client_pub == NULL");
packet_get_bignum2(dh_client_pub);
packet_check_eom();
if ((dh_client_pub = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_client_pub= ");
@ -91,70 +127,90 @@ kexdh_server(Kex *kex)
#endif
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
DHparams_print_fp(stderr, kex->dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
BN_print_fp(stderr, kex->dh->pub_key);
fprintf(stderr, "\n");
#endif
if (!dh_pub_is_valid(dh, dh_client_pub))
packet_disconnect("bad client public DH value");
if (!dh_pub_is_valid(kex->dh, dh_client_pub)) {
sshpkt_disconnect(ssh, "bad client public DH value");
r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out;
}
klen = DH_size(dh);
kbuf = xmalloc(klen);
if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0)
fatal("DH_compute_key: failed");
klen = DH_size(kex->dh);
if ((kbuf = malloc(klen)) == NULL ||
(shared_secret = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 ||
BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
if ((shared_secret = BN_new()) == NULL)
fatal("kexdh_server: BN_new failed");
if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
fatal("kexdh_server: BN_bin2bn failed");
explicit_bzero(kbuf, klen);
free(kbuf);
key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
&sbloblen)) != 0)
goto out;
/* calc H */
kex_dh_hash(
hashlen = sizeof(hash);
if ((r = kex_dh_hash(
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
buffer_ptr(&kex->my), buffer_len(&kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
server_host_key_blob, sbloblen,
dh_client_pub,
dh->pub_key,
kex->dh->pub_key,
shared_secret,
&hash, &hashlen
);
BN_clear_free(dh_client_pub);
hash, &hashlen)) != 0)
goto out;
/* save session id := H */
if (kex->session_id == NULL) {
kex->session_id_len = hashlen;
kex->session_id = xmalloc(kex->session_id_len);
kex->session_id = malloc(kex->session_id_len);
if (kex->session_id == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(kex->session_id, hash, kex->session_id_len);
}
/* sign H */
kex->sign(server_host_private, server_host_public, &signature, &slen,
hash, hashlen);
if ((r = kex->sign(server_host_private, server_host_public,
&signature, &slen, hash, hashlen, ssh->compat)) < 0)
goto out;
/* destroy_sensitive_data(); */
/* send server hostkey, DH pubkey 'f' and singed H */
packet_start(SSH2_MSG_KEXDH_REPLY);
packet_put_string(server_host_key_blob, sbloblen);
packet_put_bignum2(dh->pub_key); /* f */
packet_put_string(signature, slen);
packet_send();
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_REPLY)) != 0 ||
(r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */
(r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
free(signature);
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
out:
explicit_bzero(hash, sizeof(hash));
DH_free(kex->dh);
kex->dh = NULL;
if (dh_client_pub)
BN_clear_free(dh_client_pub);
if (kbuf) {
explicit_bzero(kbuf, klen);
free(kbuf);
}
if (shared_secret)
BN_clear_free(shared_secret);
free(server_host_key_blob);
/* have keys, free DH */
DH_free(dh);
kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
free(signature);
return r;
}
#endif /* WITH_OPENSSL */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexecdh.c,v 1.5 2014/01/09 23:20:00 djm Exp $ */
/* $OpenBSD: kexecdh.c,v 1.6 2015/01/19 20:16:15 markus Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -26,7 +26,7 @@
#include "includes.h"
#ifdef OPENSSL_HAS_ECC
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
#include <sys/types.h>
@ -38,60 +38,63 @@
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include "buffer.h"
#include "ssh2.h"
#include "key.h"
#include "sshkey.h"
#include "cipher.h"
#include "kex.h"
#include "log.h"
#include "sshbuf.h"
#include "digest.h"
#include "ssherr.h"
void
int
kex_ecdh_hash(
int hash_alg,
const EC_GROUP *ec_group,
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
u_char *serverhostkeyblob, int sbloblen,
const char *client_version_string,
const char *server_version_string,
const u_char *ckexinit, size_t ckexinitlen,
const u_char *skexinit, size_t skexinitlen,
const u_char *serverhostkeyblob, size_t sbloblen,
const EC_POINT *client_dh_pub,
const EC_POINT *server_dh_pub,
const BIGNUM *shared_secret,
u_char **hash, u_int *hashlen)
u_char *hash, size_t *hashlen)
{
Buffer b;
static u_char digest[SSH_DIGEST_MAX_LENGTH];
buffer_init(&b);
buffer_put_cstring(&b, client_version_string);
buffer_put_cstring(&b, server_version_string);
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
buffer_put_ecpoint(&b, ec_group, client_dh_pub);
buffer_put_ecpoint(&b, ec_group, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
struct sshbuf *b;
int r;
if (*hashlen < ssh_digest_bytes(hash_alg))
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 ||
/* 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 ||
(r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
(r = sshbuf_put_u32(b, skexinitlen+1)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
(r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
(r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
(r = sshbuf_put_ec(b, client_dh_pub, ec_group)) != 0 ||
(r = sshbuf_put_ec(b, server_dh_pub, ec_group)) != 0 ||
(r = sshbuf_put_bignum2(b, shared_secret)) != 0) {
sshbuf_free(b);
return r;
}
#ifdef DEBUG_KEX
buffer_dump(&b);
sshbuf_dump(b, stderr);
#endif
if (ssh_digest_buffer(hash_alg, &b, digest, sizeof(digest)) != 0)
fatal("%s: ssh_digest_buffer failed", __func__);
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest("hash", digest, ssh_digest_bytes(hash_alg));
#endif
*hash = digest;
if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
sshbuf_free(b);
return SSH_ERR_LIBCRYPTO_ERROR;
}
sshbuf_free(b);
*hashlen = ssh_digest_bytes(hash_alg);
#ifdef DEBUG_KEX
dump_digest("hash", hash, *hashlen);
#endif
return 0;
}
#endif /* OPENSSL_HAS_ECC */
#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexecdhc.c,v 1.7 2014/02/02 03:44:31 djm Exp $ */
/* $OpenBSD: kexecdhc.c,v 1.10 2015/01/26 06:10:03 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -26,140 +26,203 @@
#include "includes.h"
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include "xmalloc.h"
#include "buffer.h"
#include "key.h"
#include <openssl/ecdh.h>
#include "sshkey.h"
#include "cipher.h"
#include "digest.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "dh.h"
#include "ssh2.h"
#include "dispatch.h"
#include "compat.h"
#include "ssherr.h"
#include "sshbuf.h"
#ifdef OPENSSL_HAS_ECC
static int input_kex_ecdh_reply(int, u_int32_t, void *);
#include <openssl/ecdh.h>
void
kexecdh_client(Kex *kex)
int
kexecdh_client(struct ssh *ssh)
{
EC_KEY *client_key;
EC_POINT *server_public;
struct kex *kex = ssh->kex;
EC_KEY *client_key = NULL;
const EC_GROUP *group;
BIGNUM *shared_secret;
Key *server_host_key;
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf, *hash;
u_int klen, slen, sbloblen, hashlen;
const EC_POINT *public_key;
int r;
if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL)
fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
if (EC_KEY_generate_key(client_key) != 1)
fatal("%s: EC_KEY_generate_key failed", __func__);
if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (EC_KEY_generate_key(client_key) != 1) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
group = EC_KEY_get0_group(client_key);
public_key = EC_KEY_get0_public_key(client_key);
packet_start(SSH2_MSG_KEX_ECDH_INIT);
packet_put_ecpoint(group, EC_KEY_get0_public_key(client_key));
packet_send();
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
(r = sshpkt_put_ec(ssh, public_key, group)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
debug("sending SSH2_MSG_KEX_ECDH_INIT");
#ifdef DEBUG_KEXECDH
fputs("client private key:\n", stderr);
key_dump_ec_key(client_key);
sshkey_dump_ec_key(client_key);
#endif
kex->ec_client_key = client_key;
kex->ec_group = group;
client_key = NULL; /* owned by the kex */
debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
packet_read_expect(SSH2_MSG_KEX_ECDH_REPLY);
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_ecdh_reply);
r = 0;
out:
if (client_key)
EC_KEY_free(client_key);
return r;
}
static int
input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
const EC_GROUP *group;
EC_POINT *server_public = NULL;
EC_KEY *client_key;
BIGNUM *shared_secret = NULL;
struct sshkey *server_host_key = NULL;
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t slen, sbloblen;
size_t klen = 0, hashlen;
int r;
if (kex->verify_host_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
group = kex->ec_group;
client_key = kex->ec_client_key;
/* hostkey */
server_host_key_blob = packet_get_string(&sbloblen);
server_host_key = key_from_blob(server_host_key_blob, sbloblen);
if (server_host_key == NULL)
fatal("cannot decode server_host_key_blob");
if (server_host_key->type != kex->hostkey_type)
fatal("type mismatch for decoded server_host_key_blob");
if (kex->verify_host_key == NULL)
fatal("cannot verify server_host_key");
if (kex->verify_host_key(server_host_key) == -1)
fatal("server_host_key verification failed");
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
&sbloblen)) != 0 ||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
&server_host_key)) != 0)
goto out;
if (server_host_key->type != kex->hostkey_type ||
(kex->hostkey_type == KEY_ECDSA &&
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
if (kex->verify_host_key(server_host_key, ssh) == -1) {
r = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
/* Q_S, server public key */
if ((server_public = EC_POINT_new(group)) == NULL)
fatal("%s: EC_POINT_new failed", __func__);
packet_get_ecpoint(group, server_public);
if (key_ec_validate_public(group, server_public) != 0)
fatal("%s: invalid server public key", __func__);
/* signed H */
if ((server_public = EC_POINT_new(group)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshpkt_get_ec(ssh, server_public, group)) != 0 ||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXECDH
fputs("server public key:\n", stderr);
key_dump_ec_point(group, server_public);
sshkey_dump_ec_point(group, server_public);
#endif
/* signed H */
signature = packet_get_string(&slen);
packet_check_eom();
if (sshkey_ec_validate_public(group, server_public) != 0) {
sshpkt_disconnect(ssh, "invalid server public key");
r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out;
}
klen = (EC_GROUP_get_degree(group) + 7) / 8;
kbuf = xmalloc(klen);
if ((kbuf = malloc(klen)) == NULL ||
(shared_secret = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (ECDH_compute_key(kbuf, klen, server_public,
client_key, NULL) != (int)klen)
fatal("%s: ECDH_compute_key failed", __func__);
client_key, NULL) != (int)klen ||
BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
#ifdef DEBUG_KEXECDH
dump_digest("shared secret", kbuf, klen);
#endif
if ((shared_secret = BN_new()) == NULL)
fatal("%s: BN_new failed", __func__);
if (BN_bin2bn(kbuf, klen, shared_secret) == NULL)
fatal("%s: BN_bin2bn failed", __func__);
explicit_bzero(kbuf, klen);
free(kbuf);
/* calc and verify H */
kex_ecdh_hash(
hashlen = sizeof(hash);
if ((r = kex_ecdh_hash(
kex->hash_alg,
group,
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->my), buffer_len(&kex->my),
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
server_host_key_blob, sbloblen,
EC_KEY_get0_public_key(client_key),
server_public,
shared_secret,
&hash, &hashlen
);
free(server_host_key_blob);
EC_POINT_clear_free(server_public);
EC_KEY_free(client_key);
hash, &hashlen)) != 0)
goto out;
if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1)
fatal("key_verify failed for server_host_key");
key_free(server_host_key);
free(signature);
if ((r = sshkey_verify(server_host_key, signature, slen, hash,
hashlen, ssh->compat)) != 0)
goto out;
/* save session id */
if (kex->session_id == NULL) {
kex->session_id_len = hashlen;
kex->session_id = xmalloc(kex->session_id_len);
kex->session_id = malloc(kex->session_id_len);
if (kex->session_id == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(kex->session_id, hash, kex->session_id_len);
}
kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
out:
explicit_bzero(hash, sizeof(hash));
if (kex->ec_client_key) {
EC_KEY_free(kex->ec_client_key);
kex->ec_client_key = NULL;
}
if (server_public)
EC_POINT_clear_free(server_public);
if (kbuf) {
explicit_bzero(kbuf, klen);
free(kbuf);
}
if (shared_secret)
BN_clear_free(shared_secret);
sshkey_free(server_host_key);
free(server_host_key_blob);
free(signature);
return r;
}
#else /* OPENSSL_HAS_ECC */
void
kexecdh_client(Kex *kex)
{
fatal("ECC support is not enabled");
}
#endif /* OPENSSL_HAS_ECC */
#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexecdhs.c,v 1.10 2014/02/02 03:44:31 djm Exp $ */
/* $OpenBSD: kexecdhs.c,v 1.14 2015/01/26 06:10:03 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@ -26,136 +26,183 @@
#include "includes.h"
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
#include <sys/types.h>
#include <string.h>
#include <signal.h>
#include "xmalloc.h"
#include "buffer.h"
#include "key.h"
#include <openssl/ecdh.h>
#include "sshkey.h"
#include "cipher.h"
#include "digest.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "ssh2.h"
#ifdef OPENSSL_HAS_ECC
#include "dispatch.h"
#include "compat.h"
#include "ssherr.h"
#include "sshbuf.h"
#include <openssl/ecdh.h>
static int input_kex_ecdh_init(int, u_int32_t, void *);
void
kexecdh_server(Kex *kex)
int
kexecdh_server(struct ssh *ssh)
{
EC_POINT *client_public;
EC_KEY *server_key;
const EC_GROUP *group;
BIGNUM *shared_secret;
Key *server_host_private, *server_host_public;
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf, *hash;
u_int klen, slen, sbloblen, hashlen;
debug("expecting SSH2_MSG_KEX_ECDH_INIT");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_ecdh_init);
return 0;
}
if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL)
fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
if (EC_KEY_generate_key(server_key) != 1)
fatal("%s: EC_KEY_generate_key failed", __func__);
static int
input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
EC_POINT *client_public;
EC_KEY *server_key = NULL;
const EC_GROUP *group;
const EC_POINT *public_key;
BIGNUM *shared_secret = NULL;
struct sshkey *server_host_private, *server_host_public;
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t slen, sbloblen;
size_t klen = 0, hashlen;
int r;
if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (EC_KEY_generate_key(server_key) != 1) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
group = EC_KEY_get0_group(server_key);
#ifdef DEBUG_KEXECDH
fputs("server private key:\n", stderr);
key_dump_ec_key(server_key);
sshkey_dump_ec_key(server_key);
#endif
if (kex->load_host_public_key == NULL ||
kex->load_host_private_key == NULL)
fatal("Cannot load hostkey");
server_host_public = kex->load_host_public_key(kex->hostkey_type);
if (server_host_public == NULL)
fatal("Unsupported hostkey type %d", kex->hostkey_type);
server_host_private = kex->load_host_private_key(kex->hostkey_type);
debug("expecting SSH2_MSG_KEX_ECDH_INIT");
packet_read_expect(SSH2_MSG_KEX_ECDH_INIT);
if ((client_public = EC_POINT_new(group)) == NULL)
fatal("%s: EC_POINT_new failed", __func__);
packet_get_ecpoint(group, client_public);
packet_check_eom();
if (key_ec_validate_public(group, client_public) != 0)
fatal("%s: invalid client public key", __func__);
kex->load_host_private_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
server_host_public = kex->load_host_public_key(kex->hostkey_type,
kex->hostkey_nid, ssh);
server_host_private = kex->load_host_private_key(kex->hostkey_type,
kex->hostkey_nid, ssh);
if (server_host_public == NULL) {
r = SSH_ERR_NO_HOSTKEY_LOADED;
goto out;
}
if ((client_public = EC_POINT_new(group)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshpkt_get_ec(ssh, client_public, group)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXECDH
fputs("client public key:\n", stderr);
key_dump_ec_point(group, client_public);
sshkey_dump_ec_point(group, client_public);
#endif
if (sshkey_ec_validate_public(group, client_public) != 0) {
sshpkt_disconnect(ssh, "invalid client public key");
r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out;
}
/* Calculate shared_secret */
klen = (EC_GROUP_get_degree(group) + 7) / 8;
kbuf = xmalloc(klen);
if ((kbuf = malloc(klen)) == NULL ||
(shared_secret = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if (ECDH_compute_key(kbuf, klen, client_public,
server_key, NULL) != (int)klen)
fatal("%s: ECDH_compute_key failed", __func__);
server_key, NULL) != (int)klen ||
BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
#ifdef DEBUG_KEXDH
#ifdef DEBUG_KEXECDH
dump_digest("shared secret", kbuf, klen);
#endif
if ((shared_secret = BN_new()) == NULL)
fatal("%s: BN_new failed", __func__);
if (BN_bin2bn(kbuf, klen, shared_secret) == NULL)
fatal("%s: BN_bin2bn failed", __func__);
explicit_bzero(kbuf, klen);
free(kbuf);
/* calc H */
key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
kex_ecdh_hash(
if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
&sbloblen)) != 0)
goto out;
hashlen = sizeof(hash);
if ((r = kex_ecdh_hash(
kex->hash_alg,
group,
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
buffer_ptr(&kex->my), buffer_len(&kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
server_host_key_blob, sbloblen,
client_public,
EC_KEY_get0_public_key(server_key),
shared_secret,
&hash, &hashlen
);
EC_POINT_clear_free(client_public);
hash, &hashlen)) != 0)
goto out;
/* save session id := H */
if (kex->session_id == NULL) {
kex->session_id_len = hashlen;
kex->session_id = xmalloc(kex->session_id_len);
kex->session_id = malloc(kex->session_id_len);
if (kex->session_id == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(kex->session_id, hash, kex->session_id_len);
}
/* sign H */
kex->sign(server_host_private, server_host_public, &signature, &slen,
hash, hashlen);
if ((r = kex->sign(server_host_private, server_host_public,
&signature, &slen, hash, hashlen, ssh->compat)) < 0)
goto out;
/* destroy_sensitive_data(); */
public_key = EC_KEY_get0_public_key(server_key);
/* send server hostkey, ECDH pubkey 'Q_S' and signed H */
packet_start(SSH2_MSG_KEX_ECDH_REPLY);
packet_put_string(server_host_key_blob, sbloblen);
packet_put_ecpoint(group, EC_KEY_get0_public_key(server_key));
packet_put_string(signature, slen);
packet_send();
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
(r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
(r = sshpkt_put_ec(ssh, public_key, group)) != 0 ||
(r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
free(signature);
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
out:
explicit_bzero(hash, sizeof(hash));
if (kex->ec_client_key) {
EC_KEY_free(kex->ec_client_key);
kex->ec_client_key = NULL;
}
if (server_key)
EC_KEY_free(server_key);
if (kbuf) {
explicit_bzero(kbuf, klen);
free(kbuf);
}
if (shared_secret)
BN_clear_free(shared_secret);
free(server_host_key_blob);
/* have keys, free server key */
EC_KEY_free(server_key);
free(signature);
return r;
}
#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */
kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
}
#else /* OPENSSL_HAS_ECC */
void
kexecdh_server(Kex *kex)
{
fatal("ECC support is not enabled");
}
#endif /* OPENSSL_HAS_ECC */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexgex.c,v 1.28 2014/01/09 23:20:00 djm Exp $ */
/* $OpenBSD: kexgex.c,v 1.29 2015/01/19 20:16:15 markus Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@ -26,73 +26,77 @@
#include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h>
#include <openssl/evp.h>
#include <signal.h>
#include "buffer.h"
#include "key.h"
#include "sshkey.h"
#include "cipher.h"
#include "kex.h"
#include "ssh2.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "digest.h"
#include "log.h"
void
int
kexgex_hash(
int hash_alg,
char *client_version_string,
char *server_version_string,
char *ckexinit, int ckexinitlen,
char *skexinit, int skexinitlen,
u_char *serverhostkeyblob, int sbloblen,
int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen,
BIGNUM *client_dh_pub,
BIGNUM *server_dh_pub,
BIGNUM *shared_secret,
u_char **hash, u_int *hashlen)
const char *client_version_string,
const char *server_version_string,
const u_char *ckexinit, size_t ckexinitlen,
const u_char *skexinit, size_t skexinitlen,
const u_char *serverhostkeyblob, size_t sbloblen,
int min, int wantbits, int max,
const BIGNUM *prime,
const BIGNUM *gen,
const BIGNUM *client_dh_pub,
const BIGNUM *server_dh_pub,
const BIGNUM *shared_secret,
u_char *hash, size_t *hashlen)
{
Buffer b;
static u_char digest[SSH_DIGEST_MAX_LENGTH];
struct sshbuf *b;
int r;
buffer_init(&b);
buffer_put_cstring(&b, client_version_string);
buffer_put_cstring(&b, server_version_string);
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
buffer_put_int(&b, ckexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, ckexinit, ckexinitlen);
buffer_put_int(&b, skexinitlen+1);
buffer_put_char(&b, SSH2_MSG_KEXINIT);
buffer_append(&b, skexinit, skexinitlen);
buffer_put_string(&b, serverhostkeyblob, sbloblen);
if (min == -1 || max == -1)
buffer_put_int(&b, wantbits);
else {
buffer_put_int(&b, min);
buffer_put_int(&b, wantbits);
buffer_put_int(&b, max);
if (*hashlen < ssh_digest_bytes(SSH_DIGEST_SHA1))
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 ||
/* 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 ||
(r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
(r = sshbuf_put_u32(b, skexinitlen+1)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
(r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
(r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
(min != -1 && (r = sshbuf_put_u32(b, min)) != 0) ||
(r = sshbuf_put_u32(b, wantbits)) != 0 ||
(max != -1 && (r = sshbuf_put_u32(b, max)) != 0) ||
(r = sshbuf_put_bignum2(b, prime)) != 0 ||
(r = sshbuf_put_bignum2(b, gen)) != 0 ||
(r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 ||
(r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 ||
(r = sshbuf_put_bignum2(b, shared_secret)) != 0) {
sshbuf_free(b);
return r;
}
buffer_put_bignum2(&b, prime);
buffer_put_bignum2(&b, gen);
buffer_put_bignum2(&b, client_dh_pub);
buffer_put_bignum2(&b, server_dh_pub);
buffer_put_bignum2(&b, shared_secret);
#ifdef DEBUG_KEXDH
buffer_dump(&b);
sshbuf_dump(b, stderr);
#endif
if (ssh_digest_buffer(hash_alg, &b, digest, sizeof(digest)) != 0)
fatal("%s: ssh_digest_buffer failed", __func__);
buffer_free(&b);
#ifdef DEBUG_KEX
dump_digest("hash", digest, ssh_digest_bytes(hash_alg));
#endif
*hash = digest;
if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
sshbuf_free(b);
return SSH_ERR_LIBCRYPTO_ERROR;
}
sshbuf_free(b);
*hashlen = ssh_digest_bytes(hash_alg);
#ifdef DEBUG_KEXDH
dump_digest("hash", hash, *hashlen);
#endif
return 0;
}
#endif /* WITH_OPENSSL */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexgexc.c,v 1.17 2014/02/02 03:44:31 djm Exp $ */
/* $OpenBSD: kexgexc.c,v 1.20 2015/01/26 06:10:03 djm Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@ -26,6 +26,8 @@
#include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h>
#include <openssl/dh.h>
@ -35,173 +37,243 @@
#include <string.h>
#include <signal.h>
#include "xmalloc.h"
#include "buffer.h"
#include "key.h"
#include "sshkey.h"
#include "cipher.h"
#include "digest.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
#include "dh.h"
#include "ssh2.h"
#include "compat.h"
#include "dispatch.h"
#include "ssherr.h"
#include "sshbuf.h"
void
kexgex_client(Kex *kex)
static int input_kex_dh_gex_group(int, u_int32_t, void *);
static int input_kex_dh_gex_reply(int, u_int32_t, void *);
int
kexgex_client(struct ssh *ssh)
{
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
BIGNUM *p = NULL, *g = NULL;
Key *server_host_key;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int klen, slen, sbloblen, hashlen;
int kout;
int min, max, nbits;
DH *dh;
struct kex *kex = ssh->kex;
int r;
u_int nbits;
nbits = dh_estimate(kex->dh_need * 8);
if (datafellows & SSH_OLD_DHGEX) {
kex->min = DH_GRP_MIN;
kex->max = DH_GRP_MAX;
kex->nbits = nbits;
if (ssh->compat & SSH_OLD_DHGEX) {
/* Old GEX request */
packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
packet_put_int(nbits);
min = DH_GRP_MIN;
max = DH_GRP_MAX;
debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", nbits);
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD))
!= 0 ||
(r = sshpkt_put_u32(ssh, kex->nbits)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", kex->nbits);
} else {
/* New GEX request */
min = DH_GRP_MIN;
max = DH_GRP_MAX;
packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
packet_put_int(min);
packet_put_int(nbits);
packet_put_int(max);
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 ||
(r = sshpkt_put_u32(ssh, kex->min)) != 0 ||
(r = sshpkt_put_u32(ssh, kex->nbits)) != 0 ||
(r = sshpkt_put_u32(ssh, kex->max)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent",
min, nbits, max);
kex->min, kex->nbits, kex->max);
}
#ifdef DEBUG_KEXDH
fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
min, nbits, max);
kex->min, kex->nbits, kex->max);
#endif
packet_send();
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP,
&input_kex_dh_gex_group);
r = 0;
out:
return r;
}
debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP);
static int
input_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
BIGNUM *p = NULL, *g = NULL;
int r, bits;
if ((p = BN_new()) == NULL)
fatal("BN_new");
packet_get_bignum2(p);
if ((g = BN_new()) == NULL)
fatal("BN_new");
packet_get_bignum2(g);
packet_check_eom();
debug("got SSH2_MSG_KEX_DH_GEX_GROUP");
if (BN_num_bits(p) < min || BN_num_bits(p) > max)
fatal("DH_GEX group out of range: %d !< %d !< %d",
min, BN_num_bits(p), max);
dh = dh_new_group(g, p);
dh_gen_key(dh, kex->we_need * 8);
if ((p = BN_new()) == NULL ||
(g = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshpkt_get_bignum2(ssh, p)) != 0 ||
(r = sshpkt_get_bignum2(ssh, g)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
if ((bits = BN_num_bits(p)) < 0 ||
(u_int)bits < kex->min || (u_int)bits > kex->max) {
r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
goto out;
}
if ((kex->dh = dh_new_group(g, p)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
p = g = NULL; /* belong to kex->dh now */
/* generate and send 'e', client DH public key */
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
(r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
DHparams_print_fp(stderr, kex->dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
BN_print_fp(stderr, kex->dh->pub_key);
fprintf(stderr, "\n");
#endif
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL);
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply);
r = 0;
out:
if (p)
BN_clear_free(p);
if (g)
BN_clear_free(g);
return r;
}
debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
/* generate and send 'e', client DH public key */
packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
packet_put_bignum2(dh->pub_key);
packet_send();
debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY);
static int
input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
struct sshkey *server_host_key = NULL;
u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t klen = 0, slen, sbloblen, hashlen;
int kout, r;
debug("got SSH2_MSG_KEX_DH_GEX_REPLY");
if (kex->verify_host_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
/* key, cert */
server_host_key_blob = packet_get_string(&sbloblen);
server_host_key = key_from_blob(server_host_key_blob, sbloblen);
if (server_host_key == NULL)
fatal("cannot decode server_host_key_blob");
if (server_host_key->type != kex->hostkey_type)
fatal("type mismatch for decoded server_host_key_blob");
if (kex->verify_host_key == NULL)
fatal("cannot verify server_host_key");
if (kex->verify_host_key(server_host_key) == -1)
fatal("server_host_key verification failed");
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
&sbloblen)) != 0 ||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
&server_host_key)) != 0)
goto out;
if (server_host_key->type != kex->hostkey_type) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
if (server_host_key->type != kex->hostkey_type ||
(kex->hostkey_type == KEY_ECDSA &&
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
if (kex->verify_host_key(server_host_key, ssh) == -1) {
r = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
/* DH parameter f, server public DH key */
if ((dh_server_pub = BN_new()) == NULL)
fatal("dh_server_pub == NULL");
packet_get_bignum2(dh_server_pub);
if ((dh_server_pub = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
/* signed H */
if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_server_pub= ");
BN_print_fp(stderr, dh_server_pub);
fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_server_pub));
#endif
if (!dh_pub_is_valid(kex->dh, dh_server_pub)) {
sshpkt_disconnect(ssh, "bad server public DH value");
r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out;
}
/* signed H */
signature = packet_get_string(&slen);
packet_check_eom();
if (!dh_pub_is_valid(dh, dh_server_pub))
packet_disconnect("bad server public DH value");
klen = DH_size(dh);
kbuf = xmalloc(klen);
if ((kout = DH_compute_key(kbuf, dh_server_pub, dh)) < 0)
fatal("DH_compute_key: failed");
klen = DH_size(kex->dh);
if ((kbuf = malloc(klen)) == NULL ||
(shared_secret = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
if ((shared_secret = BN_new()) == NULL)
fatal("kexgex_client: BN_new failed");
if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
fatal("kexgex_client: BN_bin2bn failed");
explicit_bzero(kbuf, klen);
free(kbuf);
if (datafellows & SSH_OLD_DHGEX)
min = max = -1;
if (ssh->compat & SSH_OLD_DHGEX)
kex->min = kex->max = -1;
/* calc and verify H */
kexgex_hash(
hashlen = sizeof(hash);
if ((r = kexgex_hash(
kex->hash_alg,
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->my), buffer_len(&kex->my),
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
server_host_key_blob, sbloblen,
min, nbits, max,
dh->p, dh->g,
dh->pub_key,
kex->min, kex->nbits, kex->max,
kex->dh->p, kex->dh->g,
kex->dh->pub_key,
dh_server_pub,
shared_secret,
&hash, &hashlen
);
hash, &hashlen)) != 0)
goto out;
/* have keys, free DH */
DH_free(dh);
free(server_host_key_blob);
BN_clear_free(dh_server_pub);
if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1)
fatal("key_verify failed for server_host_key");
key_free(server_host_key);
free(signature);
if ((r = sshkey_verify(server_host_key, signature, slen, hash,
hashlen, ssh->compat)) != 0)
goto out;
/* save session id */
if (kex->session_id == NULL) {
kex->session_id_len = hashlen;
kex->session_id = xmalloc(kex->session_id_len);
kex->session_id = malloc(kex->session_id_len);
if (kex->session_id == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(kex->session_id, hash, kex->session_id_len);
}
kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
out:
explicit_bzero(hash, sizeof(hash));
DH_free(kex->dh);
kex->dh = NULL;
if (dh_server_pub)
BN_clear_free(dh_server_pub);
if (kbuf) {
explicit_bzero(kbuf, klen);
free(kbuf);
}
if (shared_secret)
BN_clear_free(shared_secret);
sshkey_free(server_host_key);
free(server_host_key_blob);
free(signature);
return r;
}
#endif /* WITH_OPENSSL */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexgexs.c,v 1.19 2014/02/02 03:44:31 djm Exp $ */
/* $OpenBSD: kexgexs.c,v 1.24 2015/01/26 06:10:03 djm Exp $ */
/*
* Copyright (c) 2000 Niels Provos. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@ -26,7 +26,9 @@
#include "includes.h"
#include <sys/param.h>
#ifdef WITH_OPENSSL
#include <sys/param.h> /* MIN MAX */
#include <stdarg.h>
#include <stdio.h>
@ -35,10 +37,9 @@
#include <openssl/dh.h>
#include "xmalloc.h"
#include "buffer.h"
#include "key.h"
#include "sshkey.h"
#include "cipher.h"
#include "digest.h"
#include "kex.h"
#include "log.h"
#include "packet.h"
@ -49,33 +50,43 @@
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
#include "dispatch.h"
#include "ssherr.h"
#include "sshbuf.h"
void
kexgex_server(Kex *kex)
static int input_kex_dh_gex_request(int, u_int32_t, void *);
static int input_kex_dh_gex_init(int, u_int32_t, void *);
int
kexgex_server(struct ssh *ssh)
{
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
Key *server_host_public, *server_host_private;
DH *dh;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int sbloblen, klen, slen, hashlen;
int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1;
int type, kout;
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD,
&input_kex_dh_gex_request);
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST,
&input_kex_dh_gex_request);
debug("expecting SSH2_MSG_KEX_DH_GEX_REQUEST");
return 0;
}
if (kex->load_host_public_key == NULL ||
kex->load_host_private_key == NULL)
fatal("Cannot load hostkey");
server_host_public = kex->load_host_public_key(kex->hostkey_type);
if (server_host_public == NULL)
fatal("Unsupported hostkey type %d", kex->hostkey_type);
server_host_private = kex->load_host_private_key(kex->hostkey_type);
static int
input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
int r;
u_int min = 0, max = 0, nbits = 0;
type = packet_read();
switch (type) {
case SSH2_MSG_KEX_DH_GEX_REQUEST:
debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
omin = min = packet_get_int();
onbits = nbits = packet_get_int();
omax = max = packet_get_int();
if ((r = sshpkt_get_u32(ssh, &min)) != 0 ||
(r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
(r = sshpkt_get_u32(ssh, &max)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
kex->nbits = nbits;
kex->min = min;
kex->max = max;
min = MAX(DH_GRP_MIN, min);
max = MIN(DH_GRP_MAX, max);
nbits = MAX(DH_GRP_MIN, nbits);
@ -83,45 +94,89 @@ kexgex_server(Kex *kex)
break;
case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
onbits = nbits = packet_get_int();
if ((r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
kex->nbits = nbits;
/* unused for old GEX */
omin = min = DH_GRP_MIN;
omax = max = DH_GRP_MAX;
kex->min = min = DH_GRP_MIN;
kex->max = max = DH_GRP_MAX;
break;
default:
fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
packet_check_eom();
if (omax < omin || onbits < omin || omax < onbits)
fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
omin, onbits, omax);
if (kex->max < kex->min || kex->nbits < kex->min ||
kex->max < kex->nbits) {
r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
goto out;
}
/* Contact privileged parent */
dh = PRIVSEP(choose_dh(min, nbits, max));
if (dh == NULL)
packet_disconnect("Protocol error: no matching DH grp found");
kex->dh = PRIVSEP(choose_dh(min, nbits, max));
if (kex->dh == NULL) {
sshpkt_disconnect(ssh, "no matching DH grp found");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
packet_put_bignum2(dh->p);
packet_put_bignum2(dh->g);
packet_send();
/* flush */
packet_write_wait();
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->p)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->g)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
/* Compute our exchange value in parallel with the client */
dh_gen_key(dh, kex->we_need * 8);
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
goto out;
/* old KEX does not use min/max in kexgex_hash() */
if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
kex->min = kex->max = -1;
debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT);
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init);
r = 0;
out:
return r;
}
static int
input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
struct sshkey *server_host_public, *server_host_private;
u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t sbloblen, slen;
size_t klen = 0, hashlen;
int kout, r;
if (kex->load_host_public_key == NULL ||
kex->load_host_private_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
server_host_public = kex->load_host_public_key(kex->hostkey_type,
kex->hostkey_nid, ssh);
server_host_private = kex->load_host_private_key(kex->hostkey_type,
kex->hostkey_nid, ssh);
if (server_host_public == NULL) {
r = SSH_ERR_NO_HOSTKEY_LOADED;
goto out;
}
/* key, cert */
if ((dh_client_pub = BN_new()) == NULL)
fatal("dh_client_pub == NULL");
packet_get_bignum2(dh_client_pub);
packet_check_eom();
if ((dh_client_pub = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0)
goto out;
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_client_pub= ");
@ -131,78 +186,92 @@ kexgex_server(Kex *kex)
#endif
#ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, dh);
DHparams_print_fp(stderr, kex->dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->pub_key);
BN_print_fp(stderr, kex->dh->pub_key);
fprintf(stderr, "\n");
#endif
if (!dh_pub_is_valid(dh, dh_client_pub))
packet_disconnect("bad client public DH value");
if (!dh_pub_is_valid(kex->dh, dh_client_pub)) {
sshpkt_disconnect(ssh, "bad client public DH value");
r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out;
}
klen = DH_size(dh);
kbuf = xmalloc(klen);
if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0)
fatal("DH_compute_key: failed");
klen = DH_size(kex->dh);
if ((kbuf = malloc(klen)) == NULL ||
(shared_secret = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 ||
BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
#ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout);
#endif
if ((shared_secret = BN_new()) == NULL)
fatal("kexgex_server: BN_new failed");
if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
fatal("kexgex_server: BN_bin2bn failed");
explicit_bzero(kbuf, klen);
free(kbuf);
key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
omin = min = omax = max = -1;
if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
&sbloblen)) != 0)
goto out;
/* calc H */
kexgex_hash(
hashlen = sizeof(hash);
if ((r = kexgex_hash(
kex->hash_alg,
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
buffer_ptr(&kex->my), buffer_len(&kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
server_host_key_blob, sbloblen,
omin, onbits, omax,
dh->p, dh->g,
kex->min, kex->nbits, kex->max,
kex->dh->p, kex->dh->g,
dh_client_pub,
dh->pub_key,
kex->dh->pub_key,
shared_secret,
&hash, &hashlen
);
BN_clear_free(dh_client_pub);
hash, &hashlen)) != 0)
goto out;
/* save session id := H */
if (kex->session_id == NULL) {
kex->session_id_len = hashlen;
kex->session_id = xmalloc(kex->session_id_len);
kex->session_id = malloc(kex->session_id_len);
if (kex->session_id == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
memcpy(kex->session_id, hash, kex->session_id_len);
}
/* sign H */
kex->sign(server_host_private, server_host_public, &signature, &slen,
hash, hashlen);
if ((r = kex->sign(server_host_private, server_host_public,
&signature, &slen, hash, hashlen, ssh->compat)) < 0)
goto out;
/* destroy_sensitive_data(); */
/* send server hostkey, DH pubkey 'f' and singed H */
debug("SSH2_MSG_KEX_DH_GEX_REPLY sent");
packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
packet_put_string(server_host_key_blob, sbloblen);
packet_put_bignum2(dh->pub_key); /* f */
packet_put_string(signature, slen);
packet_send();
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 ||
(r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */
(r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
goto out;
free(signature);
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh);
out:
DH_free(kex->dh);
kex->dh = NULL;
if (dh_client_pub)
BN_clear_free(dh_client_pub);
if (kbuf) {
explicit_bzero(kbuf, klen);
free(kbuf);
}
if (shared_secret)
BN_clear_free(shared_secret);
free(server_host_key_blob);
/* have keys, free DH */
DH_free(dh);
kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
BN_clear_free(shared_secret);
kex_finish(kex);
free(signature);
return r;
}
#endif /* WITH_OPENSSL */

View File

@ -1,15 +1,15 @@
/* $OpenBSD: key.c,v 1.122 2014/07/22 01:18:50 dtucker Exp $ */
/* $OpenBSD: key.c,v 1.127 2015/01/28 22:36:00 djm Exp $ */
/*
* placed in the public domain
*/
#include "includes.h"
#include <sys/param.h>
#include <sys/types.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <limits.h>
#define SSH_KEY_NO_DEFINE
#include "key.h"
@ -39,24 +39,6 @@ key_new_private(int type)
return ret;
}
u_char*
key_fingerprint_raw(const Key *k, enum fp_type dgst_type,
u_int *dgst_raw_length)
{
u_char *ret = NULL;
size_t dlen;
int r;
if (dgst_raw_length != NULL)
*dgst_raw_length = 0;
if ((r = sshkey_fingerprint_raw(k, dgst_type, &ret, &dlen)) != 0)
fatal("%s: %s", __func__, ssh_err(r));
if (dlen > INT_MAX)
fatal("%s: giant len %zu", __func__, dlen);
*dgst_raw_length = dlen;
return ret;
}
int
key_read(Key *ret, char **cpp)
{
@ -329,7 +311,7 @@ key_load_file(int fd, const char *filename, struct sshbuf *blob)
{
int r;
if ((r = sshkey_load_file(fd, filename, blob)) != 0) {
if ((r = sshkey_load_file(fd, blob)) != 0) {
fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
error("%s: %s", __func__, ssh_err(r));
return 0;
@ -436,44 +418,9 @@ key_load_private_type(int type, const char *filename, const char *passphrase,
return ret;
}
#ifdef WITH_OPENSSL
Key *
key_load_private_pem(int fd, int type, const char *passphrase,
char **commentp)
{
int r;
Key *ret = NULL;
if ((r = sshkey_load_private_pem(fd, type, passphrase,
&ret, commentp)) != 0) {
fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
if (r == SSH_ERR_KEY_WRONG_PASSPHRASE)
debug("%s: %s", __func__, ssh_err(r));
else
error("%s: %s", __func__, ssh_err(r));
return NULL;
}
return ret;
}
#endif /* WITH_OPENSSL */
int
key_perm_ok(int fd, const char *filename)
{
return sshkey_perm_ok(fd, filename) == 0 ? 1 : 0;
}
int
key_in_file(Key *key, const char *filename, int strict_type)
{
int r;
if ((r = sshkey_in_file(key, filename, strict_type)) != 0) {
fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT)
return 0;
error("%s: %s", __func__, ssh_err(r));
return r == SSH_ERR_KEY_NOT_FOUND ? 0 : -1;
}
return 1;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: key.h,v 1.42 2014/06/24 01:13:21 djm Exp $ */
/* $OpenBSD: key.h,v 1.47 2015/01/28 22:36:00 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -39,7 +39,6 @@ typedef struct sshkey Key;
#define key_free sshkey_free
#define key_equal_public sshkey_equal_public
#define key_equal sshkey_equal
#define key_fingerprint sshkey_fingerprint
#define key_type sshkey_type
#define key_cert_type sshkey_cert_type
#define key_ssh_name sshkey_ssh_name
@ -50,7 +49,6 @@ typedef struct sshkey Key;
#define key_size sshkey_size
#define key_ecdsa_bits_to_nid sshkey_ecdsa_bits_to_nid
#define key_ecdsa_key_to_nid sshkey_ecdsa_key_to_nid
#define key_names_valid2 sshkey_names_valid2
#define key_is_cert sshkey_is_cert
#define key_type_plain sshkey_type_plain
#define key_cert_is_legacy sshkey_cert_is_legacy
@ -60,14 +58,12 @@ typedef struct sshkey Key;
#define key_ec_nid_to_hash_alg sshkey_ec_nid_to_hash_alg
#define key_dump_ec_point sshkey_dump_ec_point
#define key_dump_ec_key sshkey_dump_ec_key
#define key_fingerprint sshkey_fingerprint
#endif
void key_add_private(Key *);
Key *key_new_private(int);
void key_free(Key *);
Key *key_demote(const Key *);
u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *);
int key_write(const Key *, FILE *);
int key_read(Key *, char **);
@ -104,8 +100,6 @@ Key *key_load_public(const char *, char **);
Key *key_load_private(const char *, const char *, char **);
Key *key_load_private_cert(int, const char *, const char *, int *);
Key *key_load_private_type(int, const char *, const char *, char **, int *);
Key *key_load_private_pem(int, int, const char *, char **);
int key_perm_ok(int, const char *);
int key_in_file(Key *, const char *, int);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $OpenBSD: krl.h,v 1.2 2013/01/18 00:24:58 djm Exp $ */
/* $OpenBSD: krl.h,v 1.4 2015/01/13 19:06:49 djm Exp $ */
#ifndef _KRL_H
#define _KRL_H
@ -36,28 +36,30 @@
#define KRL_SECTION_CERT_SERIAL_BITMAP 0x22
#define KRL_SECTION_CERT_KEY_ID 0x23
struct sshkey;
struct sshbuf;
struct ssh_krl;
struct ssh_krl *ssh_krl_init(void);
void ssh_krl_free(struct ssh_krl *krl);
void ssh_krl_set_version(struct ssh_krl *krl, u_int64_t version);
void ssh_krl_set_sign_key(struct ssh_krl *krl, const Key *sign_key);
void ssh_krl_set_comment(struct ssh_krl *krl, const char *comment);
int ssh_krl_revoke_cert_by_serial(struct ssh_krl *krl, const Key *ca_key,
u_int64_t serial);
int ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl, const Key *ca_key,
u_int64_t lo, u_int64_t hi);
int ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, const Key *ca_key,
const char *key_id);
int ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const Key *key);
int ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const Key *key);
int ssh_krl_revoke_key(struct ssh_krl *krl, const Key *key);
int ssh_krl_to_blob(struct ssh_krl *krl, Buffer *buf, const Key **sign_keys,
u_int nsign_keys);
int ssh_krl_from_blob(Buffer *buf, struct ssh_krl **krlp,
const Key **sign_ca_keys, u_int nsign_ca_keys);
int ssh_krl_check_key(struct ssh_krl *krl, const Key *key);
int ssh_krl_file_contains_key(const char *path, const Key *key);
void ssh_krl_set_sign_key(struct ssh_krl *krl, const struct sshkey *sign_key);
int ssh_krl_set_comment(struct ssh_krl *krl, const char *comment);
int ssh_krl_revoke_cert_by_serial(struct ssh_krl *krl,
const struct sshkey *ca_key, u_int64_t serial);
int ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl,
const struct sshkey *ca_key, u_int64_t lo, u_int64_t hi);
int ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl,
const struct sshkey *ca_key, const char *key_id);
int ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key);
int ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const struct sshkey *key);
int ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key);
int ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf,
const struct sshkey **sign_keys, u_int nsign_keys);
int ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp,
const struct sshkey **sign_ca_keys, size_t nsign_ca_keys);
int ssh_krl_check_key(struct ssh_krl *krl, const struct sshkey *key);
int ssh_krl_file_contains_key(const char *path, const struct sshkey *key);
#endif /* _KRL_H */

View File

@ -787,12 +787,12 @@ construct_utmpx(struct logininfo *li, struct utmpx *utx)
/* this is just a 128-bit IPv6 address */
if (li->hostaddr.sa.sa_family == AF_INET6) {
sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);
memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
memcpy(utx->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
ut->ut_addr_v6[0] = ut->ut_addr_v6[3];
ut->ut_addr_v6[1] = 0;
ut->ut_addr_v6[2] = 0;
ut->ut_addr_v6[3] = 0;
utx->ut_addr_v6[0] = utx->ut_addr_v6[3];
utx->ut_addr_v6[1] = 0;
utx->ut_addr_v6[2] = 0;
utx->ut_addr_v6[3] = 0;
}
}
# endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: mac.c,v 1.30 2014/04/30 19:07:48 naddy Exp $ */
/* $OpenBSD: mac.c,v 1.32 2015/01/15 18:32:54 naddy Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@ -27,22 +27,16 @@
#include <sys/types.h>
#include <stdarg.h>
#include <string.h>
#include <signal.h>
#include "xmalloc.h"
#include "log.h"
#include "cipher.h"
#include "buffer.h"
#include "key.h"
#include "kex.h"
#include "mac.h"
#include "misc.h"
#include <stdio.h>
#include "digest.h"
#include "hmac.h"
#include "umac.h"
#include "mac.h"
#include "misc.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "openbsd-compat/openssl-compat.h"
@ -95,7 +89,7 @@ static const struct macalg macs[] = {
char *
mac_alg_list(char sep)
{
char *ret = NULL;
char *ret = NULL, *tmp;
size_t nlen, rlen = 0;
const struct macalg *m;
@ -103,20 +97,24 @@ mac_alg_list(char sep)
if (ret != NULL)
ret[rlen++] = sep;
nlen = strlen(m->name);
ret = xrealloc(ret, 1, rlen + nlen + 2);
if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
free(ret);
return NULL;
}
ret = tmp;
memcpy(ret + rlen, m->name, nlen + 1);
rlen += nlen;
}
return ret;
}
static void
mac_setup_by_alg(Mac *mac, const struct macalg *macalg)
static int
mac_setup_by_alg(struct sshmac *mac, const struct macalg *macalg)
{
mac->type = macalg->type;
if (mac->type == SSH_DIGEST) {
if ((mac->hmac_ctx = ssh_hmac_start(macalg->alg)) == NULL)
fatal("ssh_hmac_start(alg=%d) failed", macalg->alg);
return SSH_ERR_ALLOC_FAIL;
mac->key_len = mac->mac_len = ssh_hmac_bytes(macalg->alg);
} else {
mac->mac_len = macalg->len / 8;
@ -126,61 +124,61 @@ mac_setup_by_alg(Mac *mac, const struct macalg *macalg)
if (macalg->truncatebits != 0)
mac->mac_len = macalg->truncatebits / 8;
mac->etm = macalg->etm;
return 0;
}
int
mac_setup(Mac *mac, char *name)
mac_setup(struct sshmac *mac, char *name)
{
const struct macalg *m;
for (m = macs; m->name != NULL; m++) {
if (strcmp(name, m->name) != 0)
continue;
if (mac != NULL) {
mac_setup_by_alg(mac, m);
debug2("mac_setup: setup %s", name);
}
return (0);
if (mac != NULL)
return mac_setup_by_alg(mac, m);
return 0;
}
debug2("mac_setup: unknown %s", name);
return (-1);
return SSH_ERR_INVALID_ARGUMENT;
}
int
mac_init(Mac *mac)
mac_init(struct sshmac *mac)
{
if (mac->key == NULL)
fatal("%s: no key", __func__);
return SSH_ERR_INVALID_ARGUMENT;
switch (mac->type) {
case SSH_DIGEST:
if (mac->hmac_ctx == NULL ||
ssh_hmac_init(mac->hmac_ctx, mac->key, mac->key_len) < 0)
return -1;
return SSH_ERR_INVALID_ARGUMENT;
return 0;
case SSH_UMAC:
mac->umac_ctx = umac_new(mac->key);
if ((mac->umac_ctx = umac_new(mac->key)) == NULL)
return SSH_ERR_ALLOC_FAIL;
return 0;
case SSH_UMAC128:
mac->umac_ctx = umac128_new(mac->key);
if ((mac->umac_ctx = umac128_new(mac->key)) == NULL)
return SSH_ERR_ALLOC_FAIL;
return 0;
default:
return -1;
return SSH_ERR_INVALID_ARGUMENT;
}
}
u_char *
mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
int
mac_compute(struct sshmac *mac, u_int32_t seqno, const u_char *data, int datalen,
u_char *digest, size_t dlen)
{
static union {
u_char m[EVP_MAX_MD_SIZE];
u_char m[SSH_DIGEST_MAX_LENGTH];
u_int64_t for_align;
} u;
u_char b[4];
u_char nonce[8];
if (mac->mac_len > sizeof(u))
fatal("mac_compute: mac too long %u %zu",
mac->mac_len, sizeof(u));
return SSH_ERR_INTERNAL_ERROR;
switch (mac->type) {
case SSH_DIGEST:
@ -190,10 +188,10 @@ mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
ssh_hmac_update(mac->hmac_ctx, b, sizeof(b)) < 0 ||
ssh_hmac_update(mac->hmac_ctx, data, datalen) < 0 ||
ssh_hmac_final(mac->hmac_ctx, u.m, sizeof(u.m)) < 0)
fatal("ssh_hmac failed");
return SSH_ERR_LIBCRYPTO_ERROR;
break;
case SSH_UMAC:
put_u64(nonce, seqno);
POKE_U64(nonce, seqno);
umac_update(mac->umac_ctx, data, datalen);
umac_final(mac->umac_ctx, u.m, nonce);
break;
@ -203,13 +201,18 @@ mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
umac128_final(mac->umac_ctx, u.m, nonce);
break;
default:
fatal("mac_compute: unknown MAC type");
return SSH_ERR_INVALID_ARGUMENT;
}
return (u.m);
if (digest != NULL) {
if (dlen > mac->mac_len)
dlen = mac->mac_len;
memcpy(digest, u.m, dlen);
}
return 0;
}
void
mac_clear(Mac *mac)
mac_clear(struct sshmac *mac)
{
if (mac->type == SSH_UMAC) {
if (mac->umac_ctx != NULL)
@ -231,17 +234,16 @@ mac_valid(const char *names)
char *maclist, *cp, *p;
if (names == NULL || strcmp(names, "") == 0)
return (0);
maclist = cp = xstrdup(names);
return 0;
if ((maclist = cp = strdup(names)) == NULL)
return 0;
for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0';
(p = strsep(&cp, MAC_SEP))) {
if (mac_setup(NULL, p) < 0) {
debug("bad mac %s [%s]", p, names);
free(maclist);
return (0);
return 0;
}
}
debug3("macs ok: [%s]", names);
free(maclist);
return (1);
return 1;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: mac.h,v 1.8 2013/11/07 11:58:27 dtucker Exp $ */
/* $OpenBSD: mac.h,v 1.9 2015/01/13 19:31:40 markus Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@ -23,9 +23,29 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SSHMAC_H
#define SSHMAC_H
#include <sys/types.h>
struct sshmac {
char *name;
int enabled;
u_int mac_len;
u_char *key;
u_int key_len;
int type;
int etm; /* Encrypt-then-MAC */
struct ssh_hmac_ctx *hmac_ctx;
struct umac_ctx *umac_ctx;
};
int mac_valid(const char *);
char *mac_alg_list(char);
int mac_setup(Mac *, char *);
int mac_init(Mac *);
u_char *mac_compute(Mac *, u_int32_t, u_char *, int);
void mac_clear(Mac *);
int mac_setup(struct sshmac *, char *);
int mac_init(struct sshmac *);
int mac_compute(struct sshmac *, u_int32_t, const u_char *, int,
u_char *, size_t);
void mac_clear(struct sshmac *);
#endif /* SSHMAC_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.c,v 1.94 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: misc.c,v 1.96 2015/01/16 06:40:12 deraadt Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
@ -31,8 +31,8 @@ __RCSID("$FreeBSD$");
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/param.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@ -552,7 +552,7 @@ tilde_expand_filename(const char *filename, uid_t uid)
if (path != NULL)
filename = path + 1;
if (xasprintf(&ret, "%s%s%s", pw->pw_dir, sep, filename) >= MAXPATHLEN)
if (xasprintf(&ret, "%s%s%s", pw->pw_dir, sep, filename) >= PATH_MAX)
fatal("tilde_expand_filename: Path too long");
return (ret);

View File

@ -1,7 +1,7 @@
MODULI(5) File Formats Manual MODULI(5)
NAME
moduli - Diffie-Hellman moduli
moduli M-bM-^@M-^S Diffie-Hellman moduli
DESCRIPTION
The /etc/moduli file contains prime numbers and generators for use by
@ -38,7 +38,7 @@ DESCRIPTION
bitmask of the following values:
0x00 Not tested.
0x01 Composite number - not prime.
0x01 Composite number M-bM-^@M-^S not prime.
0x02 Sieve of Eratosthenes.
0x04 Probabilistic Miller-Rabin primality tests.
@ -71,4 +71,4 @@ STANDARDS
the Secure Shell (SSH) Transport Layer Protocol, RFC 4419, March 2006,
2006.
OpenBSD 5.6 September 26, 2012 OpenBSD 5.6
OpenBSD 5.7 September 26, 2012 OpenBSD 5.7

Some files were not shown because too many files have changed in this diff Show More