Vendor import of OpenSSH 6.8p1.
This commit is contained in:
parent
c0bbca73c6
commit
c1e0861503
28
.cvsignore
Normal file
28
.cvsignore
Normal 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
|
101
Makefile.in
101
Makefile.in
@ -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`; \
|
||||
|
53
PROTOCOL
53
PROTOCOL
@ -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 $
|
||||
|
@ -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 $
|
||||
|
2
README
2
README
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
10
auth-rsa.c
10
auth-rsa.c
@ -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 */
|
||||
|
72
auth.c
72
auth.c
@ -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.
|
||||
*
|
||||
@ -27,7 +27,6 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
@ -50,6 +49,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "match.h"
|
||||
@ -71,7 +71,8 @@
|
||||
#endif
|
||||
#include "authfile.h"
|
||||
#include "monitor_wrap.h"
|
||||
#include "krl.h"
|
||||
#include "authfile.h"
|
||||
#include "ssherr.h"
|
||||
#include "compat.h"
|
||||
|
||||
/* import */
|
||||
@ -330,13 +331,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 */
|
||||
}
|
||||
|
||||
@ -375,7 +377,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,
|
||||
@ -467,7 +469,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;
|
||||
@ -673,43 +675,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
|
||||
|
21
auth.h
21
auth.h
@ -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)));
|
||||
|
4
auth1.c
4
auth1.c
@ -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 */
|
||||
|
@ -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;
|
||||
@ -279,7 +279,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;
|
||||
@ -344,6 +344,7 @@ input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
userauth_finish(authctxt, authenticated, "keyboard-interactive",
|
||||
devicename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
22
auth2-gss.c
22
auth2-gss.c
@ -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 = {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
18
auth2.c
18
auth2.c
@ -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.
|
||||
*
|
||||
@ -87,8 +87,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 *);
|
||||
@ -151,9 +151,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)
|
||||
@ -176,7 +174,7 @@ do_authentication2(Authctxt *authctxt)
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static void
|
||||
static int
|
||||
input_service_request(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
Authctxt *authctxt = ctxt;
|
||||
@ -207,10 +205,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;
|
||||
@ -286,6 +285,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
|
||||
free(service);
|
||||
free(user);
|
||||
free(method);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -356,7 +356,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) {
|
||||
|
60
authfd.h
60
authfd.h
@ -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 */
|
||||
|
125
authfile.c
125
authfile.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
13
authfile.h
13
authfile.h
@ -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
bitmap.c
Normal file
212
bitmap.c
Normal 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
bitmap.h
Normal file
56
bitmap.h
Normal 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 */
|
6
bufbn.c
6
bufbn.c
@ -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 */
|
||||
|
1
buffer.h
1
buffer.h
@ -47,6 +47,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 *);
|
||||
|
35
canohost.c
35
canohost.c
@ -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. */
|
||||
|
77
channels.c
77
channels.c
@ -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
|
||||
@ -42,6 +42,7 @@
|
||||
#include "includes.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h> /* MIN MAX */
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/un.h>
|
||||
@ -56,6 +57,9 @@
|
||||
#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>
|
||||
@ -669,7 +673,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;
|
||||
}
|
||||
@ -1055,7 +1059,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 */
|
||||
@ -1085,7 +1089,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);
|
||||
@ -1105,7 +1109,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);
|
||||
@ -2182,7 +2186,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);
|
||||
|
||||
@ -2342,7 +2346,7 @@ channel_output_poll(void)
|
||||
/* -- protocol input */
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
int
|
||||
channel_input_data(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
int id;
|
||||
@ -2359,7 +2363,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);
|
||||
@ -2379,7 +2383,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) {
|
||||
@ -2390,7 +2394,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;
|
||||
}
|
||||
@ -2399,10 +2403,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;
|
||||
@ -2418,7 +2423,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)
|
||||
@ -2432,7 +2437,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();
|
||||
@ -2440,16 +2445,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;
|
||||
@ -2469,11 +2475,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;
|
||||
@ -2508,11 +2514,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();
|
||||
@ -2522,10 +2529,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();
|
||||
@ -2539,10 +2547,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;
|
||||
@ -2571,6 +2580,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 *
|
||||
@ -2590,7 +2600,7 @@ reason2txt(int reason)
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
int
|
||||
channel_input_open_failure(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
int id, reason;
|
||||
@ -2622,10 +2632,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;
|
||||
@ -2633,7 +2644,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();
|
||||
@ -2641,16 +2652,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;
|
||||
@ -2678,10 +2690,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;
|
||||
@ -2698,15 +2711,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 */
|
||||
@ -4094,7 +4107,7 @@ x11_connect_display(void)
|
||||
*/
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
int
|
||||
x11_input_open(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
@ -4134,11 +4147,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();
|
||||
@ -4158,6 +4172,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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
28
channels.h
28
channels.h
@ -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 $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -230,17 +230,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) */
|
||||
|
||||
@ -286,10 +286,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 */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
21
cipher-bf1.c
21
cipher-bf1.c
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) */
|
||||
|
10
cipher.c
10
cipher.c
@ -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;
|
||||
|
||||
|
8
cipher.h
8
cipher.h
@ -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,
|
||||
|
455
clientloop.c
455
clientloop.c
@ -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
|
||||
@ -61,9 +61,9 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#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
|
||||
@ -85,6 +85,7 @@
|
||||
#include <termios.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "openbsd-compat/sys-queue.h"
|
||||
#include "xmalloc.h"
|
||||
@ -110,6 +111,8 @@
|
||||
#include "match.h"
|
||||
#include "msg.h"
|
||||
#include "roaming.h"
|
||||
#include "ssherr.h"
|
||||
#include "hostfile.h"
|
||||
|
||||
/* import options */
|
||||
extern Options options;
|
||||
@ -191,9 +194,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. */
|
||||
@ -341,12 +341,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
|
||||
@ -538,13 +538,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) {
|
||||
@ -554,6 +554,7 @@ client_global_request_reply(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
|
||||
packet_set_alive_timeouts(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1414,8 +1415,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 */
|
||||
@ -1469,7 +1469,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];
|
||||
@ -1554,7 +1554,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");
|
||||
@ -1598,8 +1598,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;
|
||||
}
|
||||
}
|
||||
@ -1728,8 +1730,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)
|
||||
@ -1742,7 +1743,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;
|
||||
@ -1751,8 +1752,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;
|
||||
@ -1761,8 +1763,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();
|
||||
@ -1777,12 +1780,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();
|
||||
@ -1792,7 +1797,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
|
||||
@ -1817,6 +1826,7 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt)
|
||||
packet_put_int(c->self);
|
||||
}
|
||||
packet_send();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Channel *
|
||||
@ -1910,7 +1920,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.");
|
||||
@ -1918,9 +1928,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,
|
||||
@ -1974,7 +1987,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;
|
||||
@ -2025,8 +2038,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;
|
||||
@ -2071,18 +2086,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);
|
||||
@ -2090,6 +2482,7 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt)
|
||||
packet_write_wait();
|
||||
}
|
||||
free(rtype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
17
compat.c
17
compat.c
@ -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.
|
||||
*
|
||||
@ -57,7 +57,7 @@ enable_compat13(void)
|
||||
compat13 = 1;
|
||||
}
|
||||
/* datafellows bug compatibility */
|
||||
void
|
||||
u_int
|
||||
compat_datafellows(const char *version)
|
||||
{
|
||||
int i;
|
||||
@ -174,13 +174,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 ","
|
||||
@ -192,7 +193,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:
|
||||
@ -234,7 +237,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);
|
||||
|
||||
|
4
compat.h
4
compat.h
@ -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 $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
|
||||
@ -63,7 +63,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 *);
|
||||
|
167
compress.c
167
compress.c
@ -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 */
|
||||
}
|
||||
}
|
||||
}
|
25
compress.h
25
compress.h
@ -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 */
|
41
config.h.in
41
config.h.in
@ -1,8 +1,5 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||
|
||||
/* Define if you have a getaddrinfo that fails for the all-zeros IPv6 address
|
||||
*/
|
||||
#undef AIX_GETNAMEINFO_HACK
|
||||
@ -291,6 +288,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 +875,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
|
||||
|
||||
@ -1096,28 +1100,28 @@
|
||||
/* define if you have struct in6_addr data type */
|
||||
#undef HAVE_STRUCT_IN6_ADDR
|
||||
|
||||
/* Define to 1 if `pw_change' is a member of `struct passwd'. */
|
||||
/* Define to 1 if `pw_change' is member of `struct passwd'. */
|
||||
#undef HAVE_STRUCT_PASSWD_PW_CHANGE
|
||||
|
||||
/* Define to 1 if `pw_class' is a member of `struct passwd'. */
|
||||
/* Define to 1 if `pw_class' is member of `struct passwd'. */
|
||||
#undef HAVE_STRUCT_PASSWD_PW_CLASS
|
||||
|
||||
/* Define to 1 if `pw_expire' is a member of `struct passwd'. */
|
||||
/* Define to 1 if `pw_expire' is member of `struct passwd'. */
|
||||
#undef HAVE_STRUCT_PASSWD_PW_EXPIRE
|
||||
|
||||
/* Define to 1 if `pw_gecos' is a member of `struct passwd'. */
|
||||
/* Define to 1 if `pw_gecos' is member of `struct passwd'. */
|
||||
#undef HAVE_STRUCT_PASSWD_PW_GECOS
|
||||
|
||||
/* define if you have struct sockaddr_in6 data type */
|
||||
#undef HAVE_STRUCT_SOCKADDR_IN6
|
||||
|
||||
/* Define to 1 if `sin6_scope_id' is a member of `struct sockaddr_in6'. */
|
||||
/* Define to 1 if `sin6_scope_id' is member of `struct sockaddr_in6'. */
|
||||
#undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
|
||||
/* define if you have struct sockaddr_storage data type */
|
||||
#undef HAVE_STRUCT_SOCKADDR_STORAGE
|
||||
|
||||
/* Define to 1 if `st_blksize' is a member of `struct stat'. */
|
||||
/* Define to 1 if `st_blksize' is member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_BLKSIZE
|
||||
|
||||
/* Define to 1 if the system has the type `struct timespec'. */
|
||||
@ -1467,7 +1471,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. */
|
||||
@ -1482,9 +1486,6 @@
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
@ -1671,17 +1672,9 @@
|
||||
/* include SSH protocol version 1 support */
|
||||
#undef WITH_SSH1
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif
|
||||
/* Define to 1 if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
#undef WORDS_BIGENDIAN
|
||||
|
||||
/* Define if xauth is found in your path */
|
||||
#undef XAUTH_PATH
|
||||
|
951
configure.ac
951
configure.ac
File diff suppressed because it is too large
Load Diff
@ -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`
|
||||
|
||||
|
@ -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 $
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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."
|
||||
|
@ -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"
|
||||
|
@ -1,4 +1,4 @@
|
||||
%define ver 6.7p1
|
||||
%define ver 6.8p1
|
||||
%define rel 1
|
||||
|
||||
# OpenSSH privilege separation requires a user & group ID
|
||||
|
@ -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
|
||||
|
81
deattack.c
81
deattack.c
@ -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;
|
||||
}
|
||||
|
11
deattack.h
11
deattack.h
@ -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
|
||||
|
25
defines.h
25
defines.h
@ -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.
|
||||
|
62
dh.c
62
dh.c
@ -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)
|
||||
|
6
dh.h
6
dh.h
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
8
digest.h
8
digest.h
@ -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);
|
||||
|
||||
|
126
dispatch.c
126
dispatch.c
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
35
dispatch.h
35
dispatch.h
@ -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
|
||||
|
41
dns.c
41
dns.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
7
dns.h
7
dns.h
@ -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 */
|
||||
|
12
entropy.c
12
entropy.c
@ -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 */
|
||||
|
@ -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]);
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
6
hmac.c
6
hmac.c
@ -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);
|
||||
}
|
||||
|
637
hostfile.c
637
hostfile.c
@ -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;
|
||||
}
|
||||
|
64
hostfile.h
64
hostfile.h
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
667
kex.c
667
kex.c
@ -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
|
||||
|
185
kex.h
185
kex.h
@ -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
|
||||
|
94
kexc25519.c
94
kexc25519.c
@ -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;
|
||||
}
|
||||
|
161
kexc25519c.c
161
kexc25519c.c
@ -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;
|
||||
}
|
||||
|
132
kexc25519s.c
132
kexc25519s.c
@ -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;
|
||||
}
|
||||
|
92
kexdh.c
92
kexdh.c
@ -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 */
|
||||
|
199
kexdhc.c
199
kexdhc.c
@ -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 */
|
||||
|
188
kexdhs.c
188
kexdhs.c
@ -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 */
|
||||
|
87
kexecdh.c
87
kexecdh.c
@ -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) */
|
||||
|
221
kexecdhc.c
221
kexecdhc.c
@ -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) */
|
||||
|
||||
|
203
kexecdhs.c
203
kexecdhs.c
@ -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 */
|
||||
|
108
kexgex.c
108
kexgex.c
@ -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 */
|
||||
|
296
kexgexc.c
296
kexgexc.c
@ -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 */
|
||||
|
261
kexgexs.c
261
kexgexs.c
@ -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 */
|
||||
|
59
key.c
59
key.c
@ -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;
|
||||
}
|
||||
|
8
key.h
8
key.h
@ -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
|
||||
|
38
krl.h
38
krl.h
@ -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 */
|
||||
|
||||
|
10
loginrec.c
10
loginrec.c
@ -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
|
||||
|
96
mac.c
96
mac.c
@ -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;
|
||||
}
|
||||
|
30
mac.h
30
mac.h
@ -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 */
|
||||
|
6
misc.c
6
misc.c
@ -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.
|
||||
@ -30,8 +30,8 @@
|
||||
#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>
|
||||
@ -551,7 +551,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);
|
||||
|
6
moduli.0
6
moduli.0
@ -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
|
||||
|
14
moduli.c
14
moduli.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: moduli.c,v 1.28 2013/10/24 00:49:49 dtucker Exp $ */
|
||||
/* $OpenBSD: moduli.c,v 1.30 2015/01/20 23:14:00 deraadt Exp $ */
|
||||
/*
|
||||
* Copyright 1994 Phil Karn <karn@qualcomm.com>
|
||||
* Copyright 1996-1998, 2003 William Allen Simpson <wsimpson@greendragon.com>
|
||||
@ -39,7 +39,9 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
#include <sys/param.h> /* MAX */
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
@ -52,6 +54,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "dh.h"
|
||||
@ -447,11 +450,11 @@ static void
|
||||
write_checkpoint(char *cpfile, u_int32_t lineno)
|
||||
{
|
||||
FILE *fp;
|
||||
char tmp[MAXPATHLEN];
|
||||
char tmp[PATH_MAX];
|
||||
int r;
|
||||
|
||||
r = snprintf(tmp, sizeof(tmp), "%s.XXXXXXXXXX", cpfile);
|
||||
if (r == -1 || r >= MAXPATHLEN) {
|
||||
if (r == -1 || r >= PATH_MAX) {
|
||||
logit("write_checkpoint: temp pathname too long");
|
||||
return;
|
||||
}
|
||||
@ -461,6 +464,7 @@ write_checkpoint(char *cpfile, u_int32_t lineno)
|
||||
}
|
||||
if ((fp = fdopen(r, "w")) == NULL) {
|
||||
logit("write_checkpoint: fdopen: %s", strerror(errno));
|
||||
unlink(tmp);
|
||||
close(r);
|
||||
return;
|
||||
}
|
||||
@ -801,3 +805,5 @@ prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted,
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user