aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog932
-rw-r--r--INSTALL43
-rw-r--r--Makefile.in90
-rw-r--r--PROTOCOL52
-rw-r--r--README4
-rw-r--r--auth-bsdauth.c9
-rw-r--r--auth-chall.c6
-rw-r--r--auth-krb5.c1
-rw-r--r--auth-options.c17
-rw-r--r--auth-passwd.c3
-rw-r--r--auth-rh-rsa.c3
-rw-r--r--auth-rhosts.c4
-rw-r--r--auth-rsa.c7
-rw-r--r--auth.c22
-rw-r--r--auth.h5
-rw-r--r--auth1.c5
-rw-r--r--auth2-chall.c1
-rw-r--r--auth2-gss.c1
-rw-r--r--auth2-hostbased.c3
-rw-r--r--auth2-kbdint.c3
-rw-r--r--auth2-none.c6
-rw-r--r--auth2-passwd.c3
-rw-r--r--auth2-pubkey.c8
-rw-r--r--auth2.c5
-rw-r--r--authfd.c22
-rw-r--r--authfile.c1395
-rw-r--r--authfile.h59
-rw-r--r--bufaux.c340
-rw-r--r--bufbn.c210
-rw-r--r--bufec.c106
-rw-r--r--buffer.c245
-rw-r--r--buffer.h68
-rw-r--r--canohost.c12
-rw-r--r--chacha.h2
-rw-r--r--channels.c693
-rw-r--r--channels.h31
-rw-r--r--cipher-3des1.c57
-rw-r--r--cipher-aesctr.c78
-rw-r--r--cipher-aesctr.h35
-rw-r--r--cipher-chachapoly.c31
-rw-r--r--cipher-chachapoly.h4
-rw-r--r--cipher.c407
-rw-r--r--cipher.h59
-rw-r--r--clientloop.c82
-rw-r--r--compat.c2
-rw-r--r--compat.h2
-rw-r--r--config.h.in18
-rwxr-xr-xconfigure193
-rw-r--r--configure.ac142
-rw-r--r--contrib/caldera/openssh.spec5
-rw-r--r--contrib/cygwin/README3
-rw-r--r--contrib/cygwin/ssh-host-config198
-rw-r--r--contrib/redhat/openssh.spec5
-rw-r--r--contrib/suse/openssh.spec5
-rw-r--r--defines.h27
-rw-r--r--digest-libc.c27
-rw-r--r--digest-openssl.c60
-rw-r--r--digest.h8
-rw-r--r--dns.c9
-rw-r--r--dns.h5
-rw-r--r--entropy.c13
-rw-r--r--gss-serv-krb5.c1
-rw-r--r--gss-serv.c6
-rw-r--r--hmac.h5
-rw-r--r--hostfile.c9
-rw-r--r--kex.c18
-rw-r--r--kex.h2
-rw-r--r--kexc25519.c2
-rw-r--r--key.c2750
-rw-r--r--key.h187
-rw-r--r--krl.c15
-rw-r--r--mac.c5
-rw-r--r--misc.c85
-rw-r--r--misc.h31
-rw-r--r--moduli.04
-rw-r--r--monitor.c33
-rw-r--r--monitor_fdpass.c11
-rw-r--r--monitor_wrap.c12
-rw-r--r--mux.c275
-rw-r--r--myproposal.h103
-rw-r--r--openbsd-compat/Makefile.in4
-rw-r--r--openbsd-compat/arc4random.c4
-rw-r--r--openbsd-compat/bsd-cygwin_util.c16
-rw-r--r--openbsd-compat/bsd-cygwin_util.h6
-rw-r--r--openbsd-compat/bsd-snprintf.c4
-rw-r--r--openbsd-compat/explicit_bzero.c26
-rw-r--r--openbsd-compat/kludge-fd_set.c28
-rw-r--r--openbsd-compat/openbsd-compat.h18
-rw-r--r--openbsd-compat/openssl-compat.c166
-rw-r--r--openbsd-compat/openssl-compat.h121
-rw-r--r--openbsd-compat/port-uw.c1
-rw-r--r--openbsd-compat/regress/Makefile.in6
-rw-r--r--openbsd-compat/regress/opensslvertest.c69
-rwxr-xr-xopensshd.init.in4
-rw-r--r--packet.c70
-rw-r--r--packet.h5
-rw-r--r--platform.c3
-rw-r--r--poly1305.h2
-rw-r--r--readconf.c235
-rw-r--r--readconf.h25
-rw-r--r--regress/Makefile12
-rw-r--r--regress/connect-privsep.sh4
-rwxr-xr-xregress/dhgex.sh6
-rw-r--r--regress/forwarding.sh22
-rwxr-xr-xregress/integrity.sh13
-rwxr-xr-xregress/kextype.sh7
-rwxr-xr-xregress/krl.sh5
-rw-r--r--regress/login-timeout.sh3
-rw-r--r--regress/multiplex.sh76
-rw-r--r--regress/proxy-connect.sh29
-rw-r--r--regress/rekey.sh20
-rw-r--r--regress/test-exec.sh11
-rw-r--r--regress/try-ciphers.sh7
-rw-r--r--regress/unittests/Makefile5
-rw-r--r--regress/unittests/Makefile.inc59
-rw-r--r--regress/unittests/sshbuf/Makefile14
-rw-r--r--regress/unittests/sshbuf/test_sshbuf.c240
-rw-r--r--regress/unittests/sshbuf/test_sshbuf_fixed.c126
-rw-r--r--regress/unittests/sshbuf/test_sshbuf_fuzz.c127
-rw-r--r--regress/unittests/sshbuf/test_sshbuf_getput_basic.c484
-rw-r--r--regress/unittests/sshbuf/test_sshbuf_getput_crypto.c409
-rw-r--r--regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c130
-rw-r--r--regress/unittests/sshbuf/test_sshbuf_misc.c138
-rw-r--r--regress/unittests/sshbuf/tests.c28
-rw-r--r--regress/unittests/sshkey/Makefile13
-rw-r--r--regress/unittests/sshkey/common.c84
-rw-r--r--regress/unittests/sshkey/common.h16
-rwxr-xr-xregress/unittests/sshkey/mktestdata.sh190
-rw-r--r--regress/unittests/sshkey/test_file.c457
-rw-r--r--regress/unittests/sshkey/test_fuzz.c406
-rw-r--r--regress/unittests/sshkey/test_sshkey.c357
-rw-r--r--regress/unittests/sshkey/testdata/dsa_112
-rw-r--r--regress/unittests/sshkey/testdata/dsa_1-cert.fp1
-rw-r--r--regress/unittests/sshkey/testdata/dsa_1-cert.pub1
-rw-r--r--regress/unittests/sshkey/testdata/dsa_1.fp1
-rw-r--r--regress/unittests/sshkey/testdata/dsa_1.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/dsa_1.param.g1
-rw-r--r--regress/unittests/sshkey/testdata/dsa_1.param.priv1
-rw-r--r--regress/unittests/sshkey/testdata/dsa_1.param.pub1
-rw-r--r--regress/unittests/sshkey/testdata/dsa_1.pub1
-rw-r--r--regress/unittests/sshkey/testdata/dsa_1_pw15
-rw-r--r--regress/unittests/sshkey/testdata/dsa_212
-rw-r--r--regress/unittests/sshkey/testdata/dsa_2.fp1
-rw-r--r--regress/unittests/sshkey/testdata/dsa_2.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/dsa_2.pub1
-rw-r--r--regress/unittests/sshkey/testdata/dsa_n12
-rw-r--r--regress/unittests/sshkey/testdata/dsa_n_pw22
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_15
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_1-cert.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_1-cert.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_1.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_1.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_1.param.curve1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_1.param.priv1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_1.param.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_1.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_1_pw8
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_27
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_2.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_2.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_2.param.curve1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_2.param.priv1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_2.param.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_2.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_n5
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_n_pw9
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_17
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_1-cert.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_1-cert.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_1.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_1.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_1.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_1_pw8
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_27
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_2.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_2.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_2.pub1
-rw-r--r--regress/unittests/sshkey/testdata/pw1
-rw-r--r--regress/unittests/sshkey/testdata/rsa1_1bin0 -> 421 bytes
-rw-r--r--regress/unittests/sshkey/testdata/rsa1_1.fp1
-rw-r--r--regress/unittests/sshkey/testdata/rsa1_1.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/rsa1_1.param.n1
-rw-r--r--regress/unittests/sshkey/testdata/rsa1_1.pub1
-rw-r--r--regress/unittests/sshkey/testdata/rsa1_1_pwbin0 -> 421 bytes
-rw-r--r--regress/unittests/sshkey/testdata/rsa1_2bin0 -> 981 bytes
-rw-r--r--regress/unittests/sshkey/testdata/rsa1_2.fp1
-rw-r--r--regress/unittests/sshkey/testdata/rsa1_2.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/rsa1_2.param.n1
-rw-r--r--regress/unittests/sshkey/testdata/rsa1_2.pub1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_112
-rw-r--r--regress/unittests/sshkey/testdata/rsa_1-cert.fp1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_1-cert.pub1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_1.fp1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_1.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_1.param.n1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_1.param.p1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_1.param.q1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_1.pub1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_1_pw15
-rw-r--r--regress/unittests/sshkey/testdata/rsa_227
-rw-r--r--regress/unittests/sshkey/testdata/rsa_2.fp1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_2.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_2.param.n1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_2.param.p1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_2.param.q1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_2.pub1
-rw-r--r--regress/unittests/sshkey/testdata/rsa_n12
-rw-r--r--regress/unittests/sshkey/testdata/rsa_n_pw14
-rw-r--r--regress/unittests/sshkey/tests.c27
-rw-r--r--regress/unittests/test_helper/Makefile13
-rw-r--r--regress/unittests/test_helper/fuzz.c378
-rw-r--r--regress/unittests/test_helper/test_helper.c471
-rw-r--r--regress/unittests/test_helper/test_helper.h292
-rw-r--r--rijndael.c170
-rw-r--r--rijndael.h25
-rw-r--r--roaming_client.c5
-rw-r--r--rsa.c113
-rw-r--r--rsa.h6
-rw-r--r--sandbox-seccomp-filter.c7
-rw-r--r--sandbox-systrace.c12
-rw-r--r--scp.017
-rw-r--r--scp.114
-rw-r--r--scp.c10
-rw-r--r--servconf.c67
-rw-r--r--servconf.h6
-rw-r--r--serverloop.c109
-rw-r--r--session.c55
-rw-r--r--sftp-client.c41
-rw-r--r--sftp-client.h6
-rw-r--r--sftp-server.011
-rw-r--r--sftp-server.810
-rw-r--r--sftp-server.c14
-rw-r--r--sftp.031
-rw-r--r--sftp.137
-rw-r--r--sftp.c66
-rw-r--r--ssh-add.04
-rw-r--r--ssh-add.c28
-rw-r--r--ssh-agent.053
-rw-r--r--ssh-agent.153
-rw-r--r--ssh-agent.c78
-rw-r--r--ssh-dss.c238
-rw-r--r--ssh-ecdsa.c232
-rw-r--r--ssh-ed25519.c183
-rw-r--r--ssh-keygen.018
-rw-r--r--ssh-keygen.116
-rw-r--r--ssh-keygen.c194
-rw-r--r--ssh-keyscan.013
-rw-r--r--ssh-keyscan.115
-rw-r--r--ssh-keyscan.c11
-rw-r--r--ssh-keysign.04
-rw-r--r--ssh-keysign.c17
-rw-r--r--ssh-pkcs11-client.c4
-rw-r--r--ssh-pkcs11-helper.04
-rw-r--r--ssh-pkcs11-helper.c8
-rw-r--r--ssh-pkcs11.c4
-rw-r--r--ssh-pkcs11.h6
-rw-r--r--ssh-rsa.c260
-rw-r--r--ssh.044
-rw-r--r--ssh.135
-rw-r--r--ssh.c143
-rw-r--r--ssh_config.0117
-rw-r--r--ssh_config.5126
-rw-r--r--sshbuf-getput-basic.c421
-rw-r--r--sshbuf-getput-crypto.c237
-rw-r--r--sshbuf-misc.c135
-rw-r--r--sshbuf.c406
-rw-r--r--sshbuf.h336
-rw-r--r--sshconnect.c69
-rw-r--r--sshconnect1.c20
-rw-r--r--sshconnect2.c13
-rw-r--r--sshd.026
-rw-r--r--sshd.832
-rw-r--r--sshd.c87
-rw-r--r--sshd_config.0125
-rw-r--r--sshd_config.5196
-rw-r--r--ssherr.c131
-rw-r--r--ssherr.h80
-rw-r--r--sshkey.c3856
-rw-r--r--sshkey.h232
-rw-r--r--sshlogin.c3
-rw-r--r--sshpty.c13
-rw-r--r--umac.c59
-rw-r--r--version.h4
283 files changed, 17296 insertions, 7127 deletions
diff --git a/ChangeLog b/ChangeLog
index 38de846ff004..63aeae5564a4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,934 @@
+20131006
+ - (djm) Release OpenSSH-6.7
+
+20141003
+ - (djm) [sshd_config.5] typo; from Iain Morgan
+
+20141001
+ - (djm) [openbsd-compat/Makefile.in openbsd-compat/kludge-fd_set.c]
+ [openbsd-compat/openbsd-compat.h] Kludge around bad glibc
+ _FORTIFY_SOURCE check that doesn't grok heap-allocated fd_sets;
+ ok dtucker@
+
+20140910
+ - (djm) [sandbox-seccomp-filter.c] Allow mremap and exit for DietLibc;
+ patch from Felix von Leitner; ok dtucker
+
+20140908
+ - (dtucker) [INSTALL] Update info about egd. ok djm@
+
+20140904
+ - (djm) [openbsd-compat/arc4random.c] Zero seed after keying PRNG
+
+20140903
+ - (djm) [defines.h sshbuf.c] Move __predict_true|false to defines.h and
+ conditionalise to avoid duplicate definition.
+ - (djm) [contrib/cygwin/ssh-host-config] Fix old code leading to
+ permissions/ACLs; from Corinna Vinschen
+
+20140830
+ - (djm) [openbsd-compat/openssl-compat.h] add
+ OPENSSL_[RD]SA_MAX_MODULUS_BITS defines for OpenSSL that lacks them
+ - (djm) [misc.c] Missing newline between functions
+ - (djm) [openbsd-compat/openssl-compat.h] add include guard
+ - (djm) [Makefile.in] Make TEST_SHELL a variable; "good idea" tim@
+
+20140827
+ - (djm) [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c]
+ [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c]
+ [regress/unittests/sshkey/common.c]
+ [regress/unittests/sshkey/test_file.c]
+ [regress/unittests/sshkey/test_fuzz.c]
+ [regress/unittests/sshkey/test_sshkey.c] Don't include openssl/ec.h
+ on !ECC OpenSSL systems
+ - (djm) [monitor.c sshd.c] SIGXFSZ needs to be ignored in postauth
+ monitor, not preauth; bz#2263
+ - (djm) [openbsd-compat/explicit_bzero.c] implement explicit_bzero()
+ using memset_s() where possible; improve fallback to indirect bzero
+ via a volatile pointer to give it more of a chance to avoid being
+ optimised away.
+
+20140825
+ - (djm) [bufec.c] Skip this file on !ECC OpenSSL
+ - (djm) [INSTALL] Recommend libcrypto be built -fPIC, mention LibreSSL,
+ update OpenSSL version requirement.
+
+20140824
+ - (djm) [sftp-server.c] Some systems (e.g. Irix) have prctl() but not
+ PR_SET_DUMPABLE, so adjust ifdef; reported by Tom Christensen
+
+20140823
+ - (djm) [sshd.c] Ignore SIGXFSZ in preauth monitor child; can explode on
+ lastlog writing on platforms with high UIDs; bz#2263
+ - (djm) [configure.ac] We now require a working vsnprintf everywhere (not
+ just for systems that lack asprintf); check for it always and extend
+ test to catch more brokenness. Fixes builds on Solaris <= 9
+
+20140822
+ - (djm) [configure.ac] include leading zero characters in OpenSSL version
+ number; fixes test for unsupported versions
+ - (djm) [sshbuf-getput-crypto.c] Fix compilation when OpenSSL lacks ECC
+ - (djm) [openbsd-compat/bsd-snprintf.c] Fix compilation failure (prototype/
+ definition mismatch) and warning for broken/missing snprintf case.
+ - (djm) [configure.ac] double braces to appease autoconf
+
+20140821
+ - (djm) [Makefile.in] fix reference to libtest_helper.a in sshkey test too.
+ - (djm) [key.h] Fix ifdefs for no-ECC OpenSSL
+ - (djm) [regress/unittests/test_helper/test_helper.c] Fix for systems that
+ don't set __progname. Diagnosed by Tom Christensen.
+
+20140820
+ - (djm) [configure.ac] Check OpenSSL version is supported at configure time;
+ suggested by Kevin Brott
+ - (djm) [Makefile.in] refer to libtest_helper.a by explicit path rather than
+ -L/-l; fixes linking problems on some platforms
+ - (djm) [sshkey.h] Fix compilation when OpenSSL lacks ECC
+ - (djm) [contrib/cygwin/README] Correct build instructions; from Corinna
+
+20140819
+ - (djm) [serverloop.c] Fix syntax error on Cygwin; from Corinna Vinschen
+ - (djm) [sshbuf.h] Fix compilation on systems without OPENSSL_HAS_ECC.
+ - (djm) [ssh-dss.c] Include openssl/dsa.h for DSA_SIG
+ - (djm) [INSTALL contrib/caldera/openssh.spec contrib/cygwin/README]
+ [contrib/redhat/openssh.spec contrib/suse/openssh.spec] Remove mentions
+ of TCP wrappers.
+
+20140811
+ - (djm) [myproposal.h] Make curve25519 KEX dependent on
+ HAVE_EVP_SHA256 instead of OPENSSL_HAS_ECC.
+
+20140810
+ - (djm) [README contrib/caldera/openssh.spec]
+ [contrib/redhat/openssh.spec contrib/suse/openssh.spec] Update versions
+
+20140801
+ - (djm) [regress/multiplex.sh] Skip test for non-OpenBSD netcat. We need
+ a better solution, but this will have to do for now.
+ - (djm) [regress/multiplex.sh] Instruct nc not to quit as soon as stdin
+ is closed; avoid regress failures when stdin is /dev/null
+ - (djm) [regress/multiplex.sh] Use -d (detach stdin) flag to disassociate
+ nc from stdin, it's more portable
+
+20140730
+ - OpenBSD CVS Sync
+ - millert@cvs.openbsd.org 2014/07/24 22:57:10
+ [ssh.1]
+ Mention UNIX-domain socket forwarding too. OK jmc@ deraadt@
+ - dtucker@cvs.openbsd.org 2014/07/25 21:22:03
+ [ssh-agent.c]
+ Clear buffer used for handling messages. This prevents keys being
+ left in memory after they have been expired or deleted in some cases
+ (but note that ssh-agent is setgid so you would still need root to
+ access them). Pointed out by Kevin Burns, ok deraadt
+ - schwarze@cvs.openbsd.org 2014/07/28 15:40:08
+ [sftp-server.8 sshd_config.5]
+ some systems no longer need /dev/log;
+ issue noticed by jirib;
+ ok deraadt
+
+20140725
+ - (djm) [regress/multiplex.sh] restore incorrectly deleted line;
+ pointed out by Christian Hesse
+
+20140722
+ - (djm) [regress/multiplex.sh] ssh mux master lost -N somehow;
+ put it back
+ - (djm) [regress/multiplex.sh] change the test for still-open Unix
+ domain sockets to be robust against nc implementations that produce
+ error messages.
+ - (dtucker) [regress/unittests/sshkey/test_{file,fuzz,sshkey}.c] Wrap ecdsa-
+ specific tests inside OPENSSL_HAS_ECC.
+ - (dtucker) OpenBSD CVS Sync
+ - dtucker@cvs.openbsd.org 2014/07/22 01:18:50
+ [key.c]
+ Prevent spam from key_load_private_pem during hostbased auth. ok djm@
+ - guenther@cvs.openbsd.org 2014/07/22 07:13:42
+ [umac.c]
+ Convert from <sys/endian.h> to the shiney new <endian.h>
+ ok dtucker@, who also confirmed that -portable handles this already
+ (ID sync only, includes.h pulls in endian.h if available.)
+ - djm@cvs.openbsd.org 2014/07/22 01:32:12
+ [regress/multiplex.sh]
+ change the test for still-open Unix domain sockets to be robust against
+ nc implementations that produce error messages. from -portable
+ (Id sync only)
+ - dtucker@cvs.openbsd.org 2014/07/22 23:23:22
+ [regress/unittests/sshkey/mktestdata.sh]
+ Sign test certs with ed25519 instead of ecdsa so that they'll work in
+ -portable on platforms that don't have ECDSA in their OpenSSL. ok djm
+ - dtucker@cvs.openbsd.org 2014/07/22 23:57:40
+ [regress/unittests/sshkey/mktestdata.sh]
+ Add $OpenBSD tag to make syncs easier
+ - dtucker@cvs.openbsd.org 2014/07/22 23:35:38
+ [regress/unittests/sshkey/testdata/*]
+ Regenerate test keys with certs signed with ed25519 instead of ecdsa.
+ These can be used in -portable on platforms that don't support ECDSA.
+
+20140721
+ - OpenBSD CVS Sync
+ - millert@cvs.openbsd.org 2014/07/15 15:54:15
+ [forwarding.sh multiplex.sh]
+ Add support for Unix domain socket forwarding. A remote TCP port
+ may be forwarded to a local Unix domain socket and vice versa or
+ both ends may be a Unix domain socket. This is a reimplementation
+ of the streamlocal patches by William Ahern from:
+ http://www.25thandclement.com/~william/projects/streamlocal.html
+ OK djm@ markus@
+ - (djm) [regress/multiplex.sh] Not all netcat accept the -N option.
+ - (dtucker) [sshkey.c] ifdef out unused variable when compiling without
+ OPENSSL_HAS_ECC.
+
+20140721
+ - (dtucker) [cipher.c openbsd-compat/openssl-compat.h] Restore the bits
+ needed to build AES CTR mode against OpenSSL 0.9.8f and above. ok djm
+ - (dtucker) [regress/unittests/sshkey/
+ {common,test_file,test_fuzz,test_sshkey}.c] Wrap stdint.h includes in
+ ifdefs.
+
+20140719
+ - (tim) [openbsd-compat/port-uw.c] Include misc.h for fwd_opts, used
+ in servconf.h.
+
+20140718
+ - OpenBSD CVS Sync
+ - millert@cvs.openbsd.org 2014/07/15 15:54:14
+ [PROTOCOL auth-options.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c]
+ [auth-rsa.c auth.c auth1.c auth2-hostbased.c auth2-kbdint.c auth2-none.c]
+ [auth2-passwd.c auth2-pubkey.c auth2.c canohost.c channels.c channels.h]
+ [clientloop.c misc.c misc.h monitor.c mux.c packet.c readconf.c]
+ [readconf.h servconf.c servconf.h serverloop.c session.c ssh-agent.c]
+ [ssh.c ssh_config.5 sshconnect.c sshconnect1.c sshconnect2.c sshd.c]
+ [sshd_config.5 sshlogin.c]
+ Add support for Unix domain socket forwarding. A remote TCP port
+ may be forwarded to a local Unix domain socket and vice versa or
+ both ends may be a Unix domain socket. This is a reimplementation
+ of the streamlocal patches by William Ahern from:
+ http://www.25thandclement.com/~william/projects/streamlocal.html
+ OK djm@ markus@
+ - jmc@cvs.openbsd.org 2014/07/16 14:48:57
+ [ssh.1]
+ add the streamlocal* options to ssh's -o list; millert says they're
+ irrelevant for scp/sftp;
+ ok markus millert
+ - djm@cvs.openbsd.org 2014/07/17 00:10:56
+ [sandbox-systrace.c]
+ ifdef SYS_sendsyslog so this will compile without patching on -stable
+ - djm@cvs.openbsd.org 2014/07/17 00:10:18
+ [mux.c]
+ preserve errno across syscall
+ - djm@cvs.openbsd.org 2014/07/17 00:12:03
+ [key.c]
+ silence "incorrect passphrase" error spam; reported and ok dtucker@
+ - djm@cvs.openbsd.org 2014/07/17 07:22:19
+ [mux.c ssh.c]
+ reflect stdio-forward ("ssh -W host:port ...") failures in exit status.
+ previously we were always returning 0. bz#2255 reported by Brendan
+ Germain; ok dtucker
+ - djm@cvs.openbsd.org 2014/07/18 02:46:01
+ [ssh-agent.c]
+ restore umask around listener socket creation (dropped in streamlocal patch
+ merge)
+ - (dtucker) [auth2-gss.c gss-serv-krb5.c] Include misc.h for fwd_opts, used
+ in servconf.h.
+ - (dtucker) [Makefile.in] Add a t-exec target to run just the executable
+ tests.
+ - (dtucker) [key.c sshkey.c] Put new ecdsa bits inside ifdef OPENSSL_HAS_ECC.
+
+20140717
+ - (djm) [digest-openssl.c] Preserve array order when disabling digests.
+ Reported by Petr Lautrbach.
+ - OpenBSD CVS Sync
+ - deraadt@cvs.openbsd.org 2014/07/11 08:09:54
+ [sandbox-systrace.c]
+ Permit use of SYS_sendsyslog from inside the sandbox. Clock is ticking,
+ update your kernels and sshd soon.. libc will start using sendsyslog()
+ in about 4 days.
+ - tedu@cvs.openbsd.org 2014/07/11 13:54:34
+ [myproposal.h]
+ by popular demand, add back hamc-sha1 to server proposal for better compat
+ with many clients still in use. ok deraadt
+
+20140715
+ - (djm) [configure.ac] Delay checks for arc4random* until after libcrypto
+ has been located; fixes builds agains libressl-portable
+
+20140711
+ - OpenBSD CVS Sync
+ - benno@cvs.openbsd.org 2014/07/09 14:15:56
+ [ssh-add.c]
+ fix ssh-add crash while loading more than one key
+ ok markus@
+
+20140709
+ - OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2014/07/07 08:19:12
+ [ssh_config.5]
+ mention that ProxyCommand is executed using shell "exec" to avoid
+ a lingering process; bz#1977
+ - djm@cvs.openbsd.org 2014/07/09 01:45:10
+ [sftp.c]
+ more useful error message when GLOB_NOSPACE occurs;
+ bz#2254, patch from Orion Poplawski
+ - djm@cvs.openbsd.org 2014/07/09 03:02:15
+ [key.c]
+ downgrade more error() to debug() to better match what old authfile.c
+ did; suppresses spurious errors with hostbased authentication enabled
+ - djm@cvs.openbsd.org 2014/07/06 07:42:03
+ [multiplex.sh test-exec.sh]
+ add a hook to the cleanup() function to kill $SSH_PID if it is set
+
+ use it to kill the mux master started in multiplex.sh (it was being left
+ around on fatal failures)
+ - djm@cvs.openbsd.org 2014/07/07 08:15:26
+ [multiplex.sh]
+ remove forced-fatal that I stuck in there to test the new cleanup
+ logic and forgot to remove...
+
+20140706
+ - OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2014/07/03 23:18:35
+ [authfile.h]
+ remove leakmalloc droppings
+ - djm@cvs.openbsd.org 2014/07/05 23:11:48
+ [channels.c]
+ fix remote-forward cancel regression; ok markus@
+
+20140704
+ - OpenBSD CVS Sync
+ - jsing@cvs.openbsd.org 2014/07/03 12:42:16
+ [cipher-chachapoly.c]
+ Call chacha_ivsetup() immediately before chacha_encrypt_bytes() - this
+ makes it easier to verify that chacha_encrypt_bytes() is only called once
+ per chacha_ivsetup() call.
+ ok djm@
+ - djm@cvs.openbsd.org 2014/07/03 22:23:46
+ [sshconnect.c]
+ when rekeying, skip file/DNS lookup if it is the same as the key sent
+ during initial key exchange. bz#2154 patch from Iain Morgan; ok markus@
+ - djm@cvs.openbsd.org 2014/07/03 22:33:41
+ [channels.c]
+ allow explicit ::1 and 127.0.0.1 forwarding bind addresses when
+ GatewayPorts=no; allows client to choose address family;
+ bz#2222 ok markus@
+ - djm@cvs.openbsd.org 2014/07/03 22:40:43
+ [servconf.c servconf.h session.c sshd.8 sshd_config.5]
+ Add a sshd_config PermitUserRC option to control whether ~/.ssh/rc is
+ executed, mirroring the no-user-rc authorized_keys option;
+ bz#2160; ok markus@
+
+20140703
+ - (djm) [digest-openssl.c configure.ac] Disable RIPEMD160 if libcrypto
+ doesn't support it.
+ - (djm) [monitor_fdpass.c] Use sys/poll.h if poll.h doesn't exist;
+ bz#2237
+ - OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2014/07/03 01:45:38
+ [sshkey.c]
+ make Ed25519 keys' title fit properly in the randomart border; bz#2247
+ based on patch from Christian Hesse
+ - djm@cvs.openbsd.org 2014/07/03 03:11:03
+ [ssh-agent.c]
+ Only cleanup agent socket in the main agent process and not in any
+ subprocesses it may have started (e.g. forked askpass). Fixes
+ agent sockets being zapped when askpass processes fatal();
+ bz#2236 patch from Dmitry V. Levin
+ - djm@cvs.openbsd.org 2014/07/03 03:15:01
+ [ssh-add.c]
+ make stdout line-buffered; saves partial output getting lost when
+ ssh-add fatal()s part-way through (e.g. when listing keys from an
+ agent that supports key types that ssh-add doesn't);
+ bz#2234, reported by Phil Pennock
+ - djm@cvs.openbsd.org 2014/07/03 03:26:43
+ [digest-openssl.c]
+ use EVP_Digest() for one-shot hash instead of creating, updating,
+ finalising and destroying a context.
+ bz#2231, based on patch from Timo Teras
+ - djm@cvs.openbsd.org 2014/07/03 03:34:09
+ [gss-serv.c session.c ssh-keygen.c]
+ standardise on NI_MAXHOST for gethostname() string lengths; about
+ 1/2 the cases were using it already. Fixes bz#2239 en passant
+ - djm@cvs.openbsd.org 2014/07/03 03:47:27
+ [ssh-keygen.c]
+ When hashing or removing hosts using ssh-keygen, don't choke on
+ @revoked markers and don't remove @cert-authority markers;
+ bz#2241, reported by mlindgren AT runelind.net
+ - djm@cvs.openbsd.org 2014/07/03 04:36:45
+ [digest.h]
+ forward-declare struct sshbuf so consumers don't need to include sshbuf.h
+ - djm@cvs.openbsd.org 2014/07/03 05:32:36
+ [ssh_config.5]
+ mention '%%' escape sequence in HostName directives and how it may
+ be used to specify IPv6 link-local addresses
+ - djm@cvs.openbsd.org 2014/07/03 05:38:17
+ [ssh.1]
+ document that -g will only work in the multiplexed case if applied to
+ the mux master
+ - djm@cvs.openbsd.org 2014/07/03 06:39:19
+ [ssh.c ssh_config.5]
+ Add a %C escape sequence for LocalCommand and ControlPath that expands
+ to a unique identifer based on a has of the tuple of (local host,
+ remote user, hostname, port).
+
+ Helps avoid exceeding sockaddr_un's miserly pathname limits for mux
+ control paths.
+
+ bz#2220, based on patch from mancha1 AT zoho.com; ok markus@
+ - jmc@cvs.openbsd.org 2014/07/03 07:45:27
+ [ssh_config.5]
+ escape %C since groff thinks it part of an Rs/Re block;
+ - djm@cvs.openbsd.org 2014/07/03 11:16:55
+ [auth.c auth.h auth1.c auth2.c]
+ make the "Too many authentication failures" message include the
+ user, source address, port and protocol in a format similar to the
+ authentication success / failure messages; bz#2199, ok dtucker
+
+20140702
+ - OpenBSD CVS Sync
+ - deraadt@cvs.openbsd.org 2014/06/13 08:26:29
+ [sandbox-systrace.c]
+ permit SYS_getentropy
+ from matthew
+ - matthew@cvs.openbsd.org 2014/06/18 02:59:13
+ [sandbox-systrace.c]
+ Now that we have a dedicated getentropy(2) system call for
+ arc4random(3), we can disallow __sysctl(2) in OpenSSH's systrace
+ sandbox.
+
+ ok djm
+ - naddy@cvs.openbsd.org 2014/06/18 15:42:09
+ [sshbuf-getput-crypto.c]
+ The ssh_get_bignum functions must accept the same range of bignums
+ the corresponding ssh_put_bignum functions create. This fixes the
+ use of 16384-bit RSA keys (bug reported by Eivind Evensen).
+ ok djm@
+ - djm@cvs.openbsd.org 2014/06/24 00:52:02
+ [krl.c]
+ fix bug in KRL generation: multiple consecutive revoked certificate
+ serial number ranges could be serialised to an invalid format.
+
+ Readers of a broken KRL caused by this bug will fail closed, so no
+ should-have-been-revoked key will be accepted.
+ - djm@cvs.openbsd.org 2014/06/24 01:13:21
+ [Makefile.in auth-bsdauth.c auth-chall.c auth-options.c auth-rsa.c
+ [auth2-none.c auth2-pubkey.c authfile.c authfile.h cipher-3des1.c
+ [cipher-chachapoly.c cipher-chachapoly.h cipher.c cipher.h
+ [digest-libc.c digest-openssl.c digest.h dns.c entropy.c hmac.h
+ [hostfile.c key.c key.h krl.c monitor.c packet.c rsa.c rsa.h
+ [ssh-add.c ssh-agent.c ssh-dss.c ssh-ecdsa.c ssh-ed25519.c
+ [ssh-keygen.c ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c
+ [ssh-rsa.c sshbuf-misc.c sshbuf.h sshconnect.c sshconnect1.c
+ [sshconnect2.c sshd.c sshkey.c sshkey.h
+ [openbsd-compat/openssl-compat.c openbsd-compat/openssl-compat.h]
+ New key API: refactor key-related functions to be more library-like,
+ existing API is offered as a set of wrappers.
+
+ with and ok markus@
+
+ Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew
+ Dempsky and Ron Bowes for a detailed review a few months ago.
+ NB. This commit also removes portable OpenSSH support for OpenSSL
+ <0.9.8e.
+ - djm@cvs.openbsd.org 2014/06/24 02:19:48
+ [ssh.c]
+ don't fatal() when hostname canonicalisation fails with a
+ ProxyCommand in use; continue and allow the ProxyCommand to
+ connect anyway (e.g. to a host with a name outside the DNS
+ behind a bastion)
+ - djm@cvs.openbsd.org 2014/06/24 02:21:01
+ [scp.c]
+ when copying local->remote fails during read, don't send uninitialised
+ heap to the remote end. Reported by Jann Horn
+ - deraadt@cvs.openbsd.org 2014/06/25 14:16:09
+ [sshbuf.c]
+ unblock SIGSEGV before raising it
+ ok djm
+ - markus@cvs.openbsd.org 2014/06/27 16:41:56
+ [channels.c channels.h clientloop.c ssh.c]
+ fix remote fwding with same listen port but different listen address
+ with gerhard@, ok djm@
+ - markus@cvs.openbsd.org 2014/06/27 18:50:39
+ [ssh-add.c]
+ fix loading of private keys
+ - djm@cvs.openbsd.org 2014/06/30 12:54:39
+ [key.c]
+ suppress spurious error message when loading key with a passphrase;
+ reported by kettenis@ ok markus@
+ - djm@cvs.openbsd.org 2014/07/02 04:59:06
+ [cipher-3des1.c]
+ fix ssh protocol 1 on the server that regressed with the sshkey change
+ (sometimes fatal() after auth completed), make file return useful status
+ codes.
+ NB. Id sync only for these two. They were bundled into the sshkey merge
+ above, since it was easier to sync the entire file and then apply
+ portable-specific changed atop it.
+ - djm@cvs.openbsd.org 2014/04/30 05:32:00
+ [regress/Makefile]
+ unit tests for new buffer API; including basic fuzz testing
+ NB. Id sync only.
+ - djm@cvs.openbsd.org 2014/05/21 07:04:21
+ [regress/integrity.sh]
+ when failing because of unexpected output, show the offending output
+ - djm@cvs.openbsd.org 2014/06/24 01:04:43
+ [regress/krl.sh]
+ regress test for broken consecutive revoked serial number ranges
+ - djm@cvs.openbsd.org 2014/06/24 01:14:17
+ [Makefile.in regress/Makefile regress/unittests/Makefile]
+ [regress/unittests/sshkey/Makefile]
+ [regress/unittests/sshkey/common.c]
+ [regress/unittests/sshkey/common.h]
+ [regress/unittests/sshkey/mktestdata.sh]
+ [regress/unittests/sshkey/test_file.c]
+ [regress/unittests/sshkey/test_fuzz.c]
+ [regress/unittests/sshkey/test_sshkey.c]
+ [regress/unittests/sshkey/tests.c]
+ [regress/unittests/sshkey/testdata/dsa_1]
+ [regress/unittests/sshkey/testdata/dsa_1-cert.fp]
+ [regress/unittests/sshkey/testdata/dsa_1-cert.pub]
+ [regress/unittests/sshkey/testdata/dsa_1.fp]
+ [regress/unittests/sshkey/testdata/dsa_1.fp.bb]
+ [regress/unittests/sshkey/testdata/dsa_1.param.g]
+ [regress/unittests/sshkey/testdata/dsa_1.param.priv]
+ [regress/unittests/sshkey/testdata/dsa_1.param.pub]
+ [regress/unittests/sshkey/testdata/dsa_1.pub]
+ [regress/unittests/sshkey/testdata/dsa_1_pw]
+ [regress/unittests/sshkey/testdata/dsa_2]
+ [regress/unittests/sshkey/testdata/dsa_2.fp]
+ [regress/unittests/sshkey/testdata/dsa_2.fp.bb]
+ [regress/unittests/sshkey/testdata/dsa_2.pub]
+ [regress/unittests/sshkey/testdata/dsa_n]
+ [regress/unittests/sshkey/testdata/dsa_n_pw]
+ [regress/unittests/sshkey/testdata/ecdsa_1]
+ [regress/unittests/sshkey/testdata/ecdsa_1-cert.fp]
+ [regress/unittests/sshkey/testdata/ecdsa_1-cert.pub]
+ [regress/unittests/sshkey/testdata/ecdsa_1.fp]
+ [regress/unittests/sshkey/testdata/ecdsa_1.fp.bb]
+ [regress/unittests/sshkey/testdata/ecdsa_1.param.curve]
+ [regress/unittests/sshkey/testdata/ecdsa_1.param.priv]
+ [regress/unittests/sshkey/testdata/ecdsa_1.param.pub]
+ [regress/unittests/sshkey/testdata/ecdsa_1.pub]
+ [regress/unittests/sshkey/testdata/ecdsa_1_pw]
+ [regress/unittests/sshkey/testdata/ecdsa_2]
+ [regress/unittests/sshkey/testdata/ecdsa_2.fp]
+ [regress/unittests/sshkey/testdata/ecdsa_2.fp.bb]
+ [regress/unittests/sshkey/testdata/ecdsa_2.param.curve]
+ [regress/unittests/sshkey/testdata/ecdsa_2.param.priv]
+ [regress/unittests/sshkey/testdata/ecdsa_2.param.pub]
+ [regress/unittests/sshkey/testdata/ecdsa_2.pub]
+ [regress/unittests/sshkey/testdata/ecdsa_n]
+ [regress/unittests/sshkey/testdata/ecdsa_n_pw]
+ [regress/unittests/sshkey/testdata/ed25519_1]
+ [regress/unittests/sshkey/testdata/ed25519_1-cert.fp]
+ [regress/unittests/sshkey/testdata/ed25519_1-cert.pub]
+ [regress/unittests/sshkey/testdata/ed25519_1.fp]
+ [regress/unittests/sshkey/testdata/ed25519_1.fp.bb]
+ [regress/unittests/sshkey/testdata/ed25519_1.pub]
+ [regress/unittests/sshkey/testdata/ed25519_1_pw]
+ [regress/unittests/sshkey/testdata/ed25519_2]
+ [regress/unittests/sshkey/testdata/ed25519_2.fp]
+ [regress/unittests/sshkey/testdata/ed25519_2.fp.bb]
+ [regress/unittests/sshkey/testdata/ed25519_2.pub]
+ [regress/unittests/sshkey/testdata/pw]
+ [regress/unittests/sshkey/testdata/rsa1_1]
+ [regress/unittests/sshkey/testdata/rsa1_1.fp]
+ [regress/unittests/sshkey/testdata/rsa1_1.fp.bb]
+ [regress/unittests/sshkey/testdata/rsa1_1.param.n]
+ [regress/unittests/sshkey/testdata/rsa1_1.pub]
+ [regress/unittests/sshkey/testdata/rsa1_1_pw]
+ [regress/unittests/sshkey/testdata/rsa1_2]
+ [regress/unittests/sshkey/testdata/rsa1_2.fp]
+ [regress/unittests/sshkey/testdata/rsa1_2.fp.bb]
+ [regress/unittests/sshkey/testdata/rsa1_2.param.n]
+ [regress/unittests/sshkey/testdata/rsa1_2.pub]
+ [regress/unittests/sshkey/testdata/rsa_1]
+ [regress/unittests/sshkey/testdata/rsa_1-cert.fp]
+ [regress/unittests/sshkey/testdata/rsa_1-cert.pub]
+ [regress/unittests/sshkey/testdata/rsa_1.fp]
+ [regress/unittests/sshkey/testdata/rsa_1.fp.bb]
+ [regress/unittests/sshkey/testdata/rsa_1.param.n]
+ [regress/unittests/sshkey/testdata/rsa_1.param.p]
+ [regress/unittests/sshkey/testdata/rsa_1.param.q]
+ [regress/unittests/sshkey/testdata/rsa_1.pub]
+ [regress/unittests/sshkey/testdata/rsa_1_pw]
+ [regress/unittests/sshkey/testdata/rsa_2]
+ [regress/unittests/sshkey/testdata/rsa_2.fp]
+ [regress/unittests/sshkey/testdata/rsa_2.fp.bb]
+ [regress/unittests/sshkey/testdata/rsa_2.param.n]
+ [regress/unittests/sshkey/testdata/rsa_2.param.p]
+ [regress/unittests/sshkey/testdata/rsa_2.param.q]
+ [regress/unittests/sshkey/testdata/rsa_2.pub]
+ [regress/unittests/sshkey/testdata/rsa_n]
+ [regress/unittests/sshkey/testdata/rsa_n_pw]
+ unit and fuzz tests for new key API
+ - (djm) [sshkey.c] Conditionalise inclusion of util.h
+ - (djm) [regress/Makefile] fix execution of sshkey unit/fuzz test
+
+20140618
+ - (tim) [openssh/session.c] Work around to get chroot sftp working on UnixWare
+
+20140617
+ - (dtucker) [entropy.c openbsd-compat/openssl-compat.{c,h}
+ openbsd-compat/regress/{.cvsignore,Makefile.in,opensslvertest.c}]
+ Move the OpenSSL header/library version test into its own function and add
+ tests for it. Fix it to allow fix version upgrades (but not downgrades).
+ Prompted by chl@ via OpenSMTPD (issue #462) and Debian (bug #748150).
+ ok djm@ chl@
+
+20140616
+ - (dtucker) [defines.h] Fix undef of _PATH_MAILDIR. From rak at debian via
+ OpenSMTPD and chl@
+
+20140612
+ - (dtucker) [configure.ac] Remove tcpwrappers support, support has already
+ been removed from sshd.c.
+
+20140611
+ - (dtucker) [defines.h] Add va_copy if we don't already have it, taken from
+ openbsd-compat/bsd-asprintf.c.
+ - (dtucker) [regress/unittests/sshbuf/*.c regress/unittests/test_helper/*]
+ Wrap stdlib.h include an ifdef for platforms that don't have it.
+ - (tim) [regress/unittests/test_helper/test_helper.h] Add includes.h for
+ u_intXX_t types.
+
+20140610
+ - (dtucker) [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c
+ regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c] Only do NISTP256
+ curve tests if OpenSSL has them.
+ - (dtucker) [myprosal.h] Don't include curve25519-sha256@libssh.org in
+ the proposal if the version of OpenSSL we're using doesn't support ECC.
+ - (dtucker) [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c] ifdef
+ ECC variable too.
+ - (dtucker) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2014/06/05 22:17:50
+ [sshconnect2.c]
+ fix inverted test that caused PKCS#11 keys that were explicitly listed
+ not to be preferred. Reported by Dirk-Willem van Gulik
+ - dtucker@cvs.openbsd.org 2014/06/10 21:46:11
+ [sshbuf.h]
+ Group ECC functions together to make things a little easier in -portable.
+ "doesn't bother me" deraadt@
+ - (dtucker) [sshbuf.h] Only declare ECC functions if building without
+ OpenSSL or if OpenSSL has ECC.
+ - (dtucker) [openbsd-compat/arc4random.c] Use explicit_bzero instead of an
+ assigment that might get optimized out. ok djm@
+ - (dtucker) [bufaux.c bufbn.c bufec.c buffer.c] Pull in includes.h for
+ compat stuff, specifically whether or not OpenSSL has ECC.
+
+20140527
+ - (djm) [cipher.c] Fix merge botch.
+ - (djm) [contrib/cygwin/ssh-host-config] Updated Cygwin ssh-host-config
+ from Corinna Vinschen, fixing a number of bugs and preparing for
+ Cygwin 1.7.30.
+ - (djm) [configure.ac openbsd-compat/bsd-cygwin_util.c]
+ [openbsd-compat/bsd-cygwin_util.h] On Cygwin, determine privilege
+ separation user at runtime, since it may need to be a domain account.
+ Patch from Corinna Vinschen.
+
+20140522
+ - (djm) [Makefile.in] typo in path
+
+20140521
+ - (djm) [commit configure.ac defines.h sshpty.c] don't attempt to use
+ vhangup on Linux. It doens't work for non-root users, and for them
+ it just messes up the tty settings.
+ - (djm) [misc.c] Use CLOCK_BOOTTIME in preference to CLOCK_MONOTONIC
+ when it is available. It takes into account time spent suspended,
+ thereby ensuring timeouts (e.g. for expiring agent keys) fire
+ correctly. bz#2228 reported by John Haxby
+
+20140519
+ - (djm) [rijndael.c rijndael.h] Sync with newly-ressurected versions ine
+ OpenBSD
+ - OpenBSD CVS Sync
+ - logan@cvs.openbsd.org 2014/04/20 09:24:26
+ [dns.c dns.h ssh-keygen.c]
+ Add support for SSHFP DNS records for ED25519 key types.
+ OK from djm@
+ - logan@cvs.openbsd.org 2014/04/21 14:36:16
+ [sftp-client.c sftp-client.h sftp.c]
+ Implement sftp upload resume support.
+ OK from djm@, with input from guenther@, mlarkin@ and
+ okan@
+ - logan@cvs.openbsd.org 2014/04/22 10:07:12
+ [sftp.c]
+ Sort the sftp command list.
+ OK from djm@
+ - logan@cvs.openbsd.org 2014/04/22 12:42:04
+ [sftp.1]
+ Document sftp upload resume.
+ OK from djm@, with feedback from okan@.
+ - jmc@cvs.openbsd.org 2014/04/22 14:16:30
+ [sftp.1]
+ zap eol whitespace;
+ - djm@cvs.openbsd.org 2014/04/23 12:42:34
+ [readconf.c]
+ don't record duplicate IdentityFiles
+ - djm@cvs.openbsd.org 2014/04/28 03:09:18
+ [authfile.c bufaux.c buffer.h channels.c krl.c mux.c packet.c packet.h]
+ [ssh-keygen.c]
+ buffer_get_string_ptr's return should be const to remind
+ callers that futzing with it will futz with the actual buffer
+ contents
+ - djm@cvs.openbsd.org 2014/04/29 13:10:30
+ [clientloop.c serverloop.c]
+ bz#1818 - don't send channel success/failre replies on channels that
+ have sent a close already; analysis and patch from Simon Tatham;
+ ok markus@
+ - markus@cvs.openbsd.org 2014/04/29 18:01:49
+ [auth.c authfd.c authfile.c bufaux.c cipher.c cipher.h hostfile.c]
+ [kex.c key.c mac.c monitor.c monitor_wrap.c myproposal.h packet.c]
+ [roaming_client.c ssh-agent.c ssh-keygen.c ssh-keyscan.c ssh-keysign.c]
+ [ssh-pkcs11.h ssh.c sshconnect.c sshconnect2.c sshd.c]
+ make compiling against OpenSSL optional (make OPENSSL=no);
+ reduces algorithms to curve25519, aes-ctr, chacha, ed25519;
+ allows us to explore further options; with and ok djm
+ - dtucker@cvs.openbsd.org 2014/04/29 19:58:50
+ [sftp.c]
+ Move nulling of variable next to where it's freed. ok markus@
+ - dtucker@cvs.openbsd.org 2014/04/29 20:36:51
+ [sftp.c]
+ Don't attempt to append a nul quote char to the filename. Should prevent
+ fatal'ing with "el_insertstr failed" when there's a single quote char
+ somewhere in the string. bz#2238, ok markus@
+ - djm@cvs.openbsd.org 2014/04/30 05:29:56
+ [bufaux.c bufbn.c bufec.c buffer.c buffer.h sshbuf-getput-basic.c]
+ [sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c sshbuf.h ssherr.c]
+ [ssherr.h]
+ New buffer API; the first installment of the conversion/replacement
+ of OpenSSH's internals to make them usable as a standalone library.
+
+ This includes a set of wrappers to make it compatible with the
+ existing buffer API so replacement can occur incrementally.
+
+ With and ok markus@
+
+ Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew
+ Dempsky and Ron Bowes for a detailed review.
+ - naddy@cvs.openbsd.org 2014/04/30 19:07:48
+ [mac.c myproposal.h umac.c]
+ UMAC can use our local fallback implementation of AES when OpenSSL isn't
+ available. Glue code straight from Ted Krovetz's original umac.c.
+ ok markus@
+ - djm@cvs.openbsd.org 2014/05/02 03:27:54
+ [chacha.h cipher-chachapoly.h digest.h hmac.h kex.h kexc25519.c]
+ [misc.h poly1305.h ssh-pkcs11.c defines.h]
+ revert __bounded change; it causes way more problems for portable than
+ it solves; pointed out by dtucker@
+ - markus@cvs.openbsd.org 2014/05/03 17:20:34
+ [monitor.c packet.c packet.h]
+ unbreak compression, by re-init-ing the compression code in the
+ post-auth child. the new buffer code is more strict, and requires
+ buffer_init() while the old code was happy after a bzero();
+ originally from djm@
+ - logan@cvs.openbsd.org 2014/05/05 07:02:30
+ [sftp.c]
+ Zap extra whitespace.
+
+ OK from djm@ and dtucker@
+ - (djm) [configure.ac] Unconditionally define WITH_OPENSSL until we write
+ portability glue to support building without libcrypto
+ - (djm) [Makefile.in configure.ac sshbuf-getput-basic.c]
+ [sshbuf-getput-crypto.c sshbuf.c] compilation and portability fixes
+ - OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2014/03/13 20:44:49
+ [login-timeout.sh]
+ this test is a sorry mess of race conditions; add another sleep
+ to avoid a failure on slow machines (at least until I find a
+ better way)
+ - djm@cvs.openbsd.org 2014/04/21 22:15:37
+ [dhgex.sh integrity.sh kextype.sh rekey.sh try-ciphers.sh]
+ repair regress tests broken by server-side default cipher/kex/mac changes
+ by ensuring that the option under test is included in the server's
+ algorithm list
+ - dtucker@cvs.openbsd.org 2014/05/03 18:46:14
+ [proxy-connect.sh]
+ Add tests for with and without compression, with and without privsep.
+ - logan@cvs.openbsd.org 2014/05/04 10:40:59
+ [connect-privsep.sh]
+ Remove the Z flag from the list of malloc options as it
+ was removed from malloc.c 10 days ago.
+
+ OK from miod@
+ - (djm) [regress/unittests/Makefile]
+ [regress/unittests/Makefile.inc]
+ [regress/unittests/sshbuf/Makefile]
+ [regress/unittests/sshbuf/test_sshbuf.c]
+ [regress/unittests/sshbuf/test_sshbuf_fixed.c]
+ [regress/unittests/sshbuf/test_sshbuf_fuzz.c]
+ [regress/unittests/sshbuf/test_sshbuf_getput_basic.c]
+ [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c]
+ [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c]
+ [regress/unittests/sshbuf/test_sshbuf_misc.c]
+ [regress/unittests/sshbuf/tests.c]
+ [regress/unittests/test_helper/Makefile]
+ [regress/unittests/test_helper/fuzz.c]
+ [regress/unittests/test_helper/test_helper.c]
+ [regress/unittests/test_helper/test_helper.h]
+ Import new unit tests from OpenBSD; not yet hooked up to build.
+ - (djm) [regress/Makefile Makefile.in]
+ [regress/unittests/sshbuf/test_sshbuf.c
+ [regress/unittests/sshbuf/test_sshbuf_fixed.c]
+ [regress/unittests/sshbuf/test_sshbuf_fuzz.c]
+ [regress/unittests/sshbuf/test_sshbuf_getput_basic.c]
+ [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c]
+ [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c]
+ [regress/unittests/sshbuf/test_sshbuf_misc.c]
+ [regress/unittests/sshbuf/tests.c]
+ [regress/unittests/test_helper/fuzz.c]
+ [regress/unittests/test_helper/test_helper.c]
+ Hook new unit tests into the build and "make tests"
+ - (djm) [sshbuf.c] need __predict_false
+
+20140430
+ - (dtucker) [defines.h] Define __GNUC_PREREQ__ macro if we don't already
+ have it. Only attempt to use __attribute__(__bounded__) for gcc.
+
+20140420
+ - OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2014/03/03 22:22:30
+ [session.c]
+ ignore enviornment variables with embedded '=' or '\0' characters;
+ spotted by Jann Horn; ok deraadt@
+ Id sync only - portable already has this.
+ - djm@cvs.openbsd.org 2014/03/12 04:44:58
+ [ssh-keyscan.c]
+ scan for Ed25519 keys by default too
+ - djm@cvs.openbsd.org 2014/03/12 04:50:32
+ [auth-bsdauth.c ssh-keygen.c]
+ don't count on things that accept arguments by reference to clear
+ things for us on error; most things do, but it's unsafe form.
+ - djm@cvs.openbsd.org 2014/03/12 04:51:12
+ [authfile.c]
+ correct test that kdf name is not "none" or "bcrypt"
+ - naddy@cvs.openbsd.org 2014/03/12 13:06:59
+ [ssh-keyscan.1]
+ scan for Ed25519 keys by default too
+ - deraadt@cvs.openbsd.org 2014/03/15 17:28:26
+ [ssh-agent.c ssh-keygen.1 ssh-keygen.c]
+ Improve usage() and documentation towards the standard form.
+ In particular, this line saves a lot of man page reading time.
+ usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa | rsa1]
+ [-N new_passphrase] [-C comment] [-f output_keyfile]
+ ok schwarze jmc
+ - tedu@cvs.openbsd.org 2014/03/17 19:44:10
+ [ssh.1]
+ old descriptions of des and blowfish are old. maybe ok deraadt
+ - tedu@cvs.openbsd.org 2014/03/19 14:42:44
+ [scp.1]
+ there is no need for rcp anymore
+ ok deraadt millert
+ - markus@cvs.openbsd.org 2014/03/25 09:40:03
+ [myproposal.h]
+ trimm default proposals.
+
+ This commit removes the weaker pre-SHA2 hashes, the broken ciphers
+ (arcfour), and the broken modes (CBC) from the default configuration
+ (the patch only changes the default, all the modes are still available
+ for the config files).
+
+ ok djm@, reminded by tedu@ & naddy@ and discussed with many
+ - deraadt@cvs.openbsd.org 2014/03/26 17:16:26
+ [myproposal.h]
+ The current sharing of myproposal[] between both client and server code
+ makes the previous diff highly unpallatable. We want to go in that
+ direction for the server, but not for the client. Sigh.
+ Brought up by naddy.
+ - markus@cvs.openbsd.org 2014/03/27 23:01:27
+ [myproposal.h ssh-keyscan.c sshconnect2.c sshd.c]
+ disable weak proposals in sshd, but keep them in ssh; ok djm@
+ - djm@cvs.openbsd.org 2014/03/26 04:55:35
+ [chacha.h cipher-chachapoly.h digest.h hmac.h kex.h kexc25519.c
+ [misc.h poly1305.h ssh-pkcs11.c]
+ use __bounded(...) attribute recently added to sys/cdefs.h instead of
+ longform __attribute__(__bounded(...));
+
+ for brevity and a warning free compilation with llvm/clang
+ - tedu@cvs.openbsd.org 2014/03/26 19:58:37
+ [sshd.8 sshd.c]
+ remove libwrap support. ok deraadt djm mfriedl
+ - naddy@cvs.openbsd.org 2014/03/28 05:17:11
+ [ssh_config.5 sshd_config.5]
+ sync available and default algorithms, improve algorithm list formatting
+ help from jmc@ and schwarze@, ok deraadt@
+ - jmc@cvs.openbsd.org 2014/03/31 13:39:34
+ [ssh-keygen.1]
+ the text for the -K option was inserted in the wrong place in -r1.108;
+ fix From: Matthew Clarke
+ - djm@cvs.openbsd.org 2014/04/01 02:05:27
+ [ssh-keysign.c]
+ include fingerprint of key not found
+ use arc4random_buf() instead of loop+arc4random()
+ - djm@cvs.openbsd.org 2014/04/01 03:34:10
+ [sshconnect.c]
+ When using VerifyHostKeyDNS with a DNSSEC resolver, down-convert any
+ certificate keys to plain keys and attempt SSHFP resolution.
+
+ Prevents a server from skipping SSHFP lookup and forcing a new-hostkey
+ dialog by offering only certificate keys.
+
+ Reported by mcv21 AT cam.ac.uk
+ - djm@cvs.openbsd.org 2014/04/01 05:32:57
+ [packet.c]
+ demote a debug3 to PACKET_DEBUG; ok markus@
+ - djm@cvs.openbsd.org 2014/04/12 04:55:53
+ [sshd.c]
+ avoid crash at exit: check that pmonitor!=NULL before dereferencing;
+ bz#2225, patch from kavi AT juniper.net
+ - djm@cvs.openbsd.org 2014/04/16 23:22:45
+ [bufaux.c]
+ skip leading zero bytes in buffer_put_bignum2_from_string();
+ reported by jan AT mojzis.com; ok markus@
+ - djm@cvs.openbsd.org 2014/04/16 23:28:12
+ [ssh-agent.1]
+ remove the identity files from this manpage - ssh-agent doesn't deal
+ with them at all and the same information is duplicated in ssh-add.1
+ (which does deal with them); prodded by deraadt@
+ - djm@cvs.openbsd.org 2014/04/18 23:52:25
+ [compat.c compat.h sshconnect2.c sshd.c version.h]
+ OpenSSH 6.5 and 6.6 have a bug that causes ~0.2% of connections
+ using the curve25519-sha256@libssh.org KEX exchange method to fail
+ when connecting with something that implements the spec properly.
+
+ Disable this KEX method when speaking to one of the affected
+ versions.
+
+ reported by Aris Adamantiadis; ok markus@
+ - djm@cvs.openbsd.org 2014/04/19 05:54:59
+ [compat.c]
+ missing wildcard; pointed out by naddy@
+ - tedu@cvs.openbsd.org 2014/04/19 14:53:48
+ [ssh-keysign.c sshd.c]
+ Delete futile calls to RAND_seed. ok djm
+ NB. Id sync only. This only applies to OpenBSD's libcrypto slashathon
+ - tedu@cvs.openbsd.org 2014/04/19 18:15:16
+ [sshd.8]
+ remove some really old rsh references
+ - tedu@cvs.openbsd.org 2014/04/19 18:42:19
+ [ssh.1]
+ delete .xr to hosts.equiv. there's still an unfortunate amount of
+ documentation referring to rhosts equivalency in here.
+ - djm@cvs.openbsd.org 2014/04/20 02:30:25
+ [misc.c misc.h umac.c]
+ use get/put_u32 to load values rather than *((UINT32 *)p) that breaks on
+ strict-alignment architectures; reported by and ok stsp@
+ - djm@cvs.openbsd.org 2014/04/20 02:49:32
+ [compat.c]
+ add a canonical 6.6 + curve25519 bignum fix fake version that I can
+ recommend people use ahead of the openssh-6.7 release
+
+20140401
+ - (djm) On platforms that support it, use prctl() to prevent sftp-server
+ from accessing /proc/self/{mem,maps}; patch from jann AT thejh.net
+ - (djm) Use full release (e.g. 6.5p1) in debug output rather than just
+ version. From des@des.no
+
+20140317
+ - (djm) [sandbox-seccomp-filter.c] Soft-fail stat() syscalls. Add XXX to
+ remind myself to add sandbox violation logging via the log socket.
+
+20140314
+ - (tim) [opensshd.init.in] Add support for ed25519
+
20140313
- (djm) Release OpenSSH 6.6
@@ -2884,4 +3815,3 @@
[contrib/suse/openssh.spec] Update for release 6.0
- (djm) [README] Update URL to release notes.
- (djm) Release openssh-6.0
-
diff --git a/INSTALL b/INSTALL
index 576723048f06..cbbb2df591f2 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,22 +1,26 @@
1. Prerequisites
----------------
-You will need working installations of Zlib and OpenSSL.
+You will need working installations of Zlib and libcrypto (LibreSSL /
+OpenSSL)
Zlib 1.1.4 or 1.2.1.2 or greater (ealier 1.2.x versions have problems):
http://www.gzip.org/zlib/
-OpenSSL 0.9.6 or greater:
-http://www.openssl.org/
+libcrypto (LibreSSL or OpenSSL >= 0.9.8f)
+LibreSSL http://www.libressl.org/ ; or
+OpenSSL http://www.openssl.org/
-(OpenSSL 0.9.5a is partially supported, but some ciphers (SSH protocol 1
-Blowfish) do not work correctly.)
+LibreSSL/OpenSSL should be compiled as a position-independent library
+(i.e. with -fPIC) otherwise OpenSSH will not be able to link with it.
+If you must use a non-position-independent libcrypto, then you may need
+to configure OpenSSH --without-pie.
The remaining items are optional.
NB. If you operating system supports /dev/random, you should configure
-OpenSSL to use it. OpenSSH relies on OpenSSL's direct support of
-/dev/random, or failing that, either prngd or egd
+libcrypto (LibreSSL/OpenSSL) to use it. OpenSSH relies on libcrypto's
+direct support of /dev/random, or failing that, either prngd or egd
PRNGD:
@@ -27,10 +31,10 @@ http://prngd.sourceforge.net/
EGD:
-The Entropy Gathering Daemon (EGD) is supported if you have a system which
-lacks /dev/random and don't want to use OpenSSH's internal entropy collection.
+If the kernel lacks /dev/random the Entropy Gathering Daemon (EGD) is
+supported only if libcrypto supports it.
-http://www.lothar.com/tech/crypto/
+http://egd.sourceforge.net/
PAM:
@@ -55,15 +59,6 @@ passphrase requester. This is maintained separately at:
http://www.jmknoble.net/software/x11-ssh-askpass/
-TCP Wrappers:
-
-If you wish to use the TCP wrappers functionality you will need at least
-tcpd.h and libwrap.a, either in the standard include and library paths,
-or in the directory specified by --with-tcp-wrappers. Version 7.6 is
-known to work.
-
-http://ftp.porcupine.org/pub/security/index.html
-
S/Key Libraries:
If you wish to use --with-skey then you will need the library below
@@ -180,9 +175,6 @@ Integration Architecture. The default for OSF1 machines is enable.
--with-skey=PATH will enable S/Key one time password support. You will
need the S/Key libraries and header files installed for this to work.
---with-tcp-wrappers will enable TCP Wrappers (/etc/hosts.allow|deny)
-support.
-
--with-md5-passwords will enable the use of MD5 passwords. Enable this
if your operating system uses MD5 passwords and the system crypt() does
not support them directly (see the crypt(3/3c) man page). If enabled, the
@@ -204,10 +196,11 @@ created.
--with-xauth=PATH specifies the location of the xauth binary
---with-ssl-dir=DIR allows you to specify where your OpenSSL libraries
+--with-ssl-dir=DIR allows you to specify where your Libre/OpenSSL
+libraries
are installed.
---with-ssl-engine enables OpenSSL's (hardware) ENGINE support
+--with-ssl-engine enables Libre/OpenSSL's (hardware) ENGINE support
--with-4in6 Check for IPv4 in IPv6 mapped addresses and convert them to
real (AF_INET) IPv4 addresses. Works around some quirks on Linux.
@@ -266,4 +259,4 @@ Please refer to the "reporting bugs" section of the webpage at
http://www.openssh.com/
-$Id: INSTALL,v 1.88 2013/03/07 01:33:35 dtucker Exp $
+$Id: INSTALL,v 1.91 2014/09/09 02:23:11 dtucker Exp $
diff --git a/Makefile.in b/Makefile.in
index 28a8ec41b509..06be3d5d5ae4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,4 @@
-# $Id: Makefile.in,v 1.356 2014/02/04 00:12:56 djm Exp $
+# $Id: Makefile.in,v 1.365 2014/08/30 06:23:07 djm Exp $
# uncomment if you run a non bourne compatable shell. Ie. csh
#SHELL = @SH@
@@ -29,6 +29,7 @@ SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
PRIVSEP_PATH=@PRIVSEP_PATH@
SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
STRIP_OPT=@STRIP_OPT@
+TEST_SHELL=@TEST_SHELL@
PATHS= -DSSHDIR=\"$(sysconfdir)\" \
-D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \
@@ -63,7 +64,16 @@ 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)
-LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \
+LIBOPENSSH_OBJS=\
+ ssherr.o \
+ sshbuf.o \
+ sshkey.o \
+ sshbuf-getput-basic.o \
+ sshbuf-misc.o \
+ sshbuf-getput-crypto.o
+
+LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
+ authfd.o authfile.o bufaux.o bufbn.o buffer.o \
canohost.o channels.o cipher.o cipher-aes.o \
cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \
compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \
@@ -135,7 +145,7 @@ $(SSHOBJS): Makefile.in config.h
$(SSHDOBJS): Makefile.in config.h
.c.o:
- $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
LIBCOMPAT=openbsd-compat/libopenbsd-compat.a
$(LIBCOMPAT): always
@@ -214,6 +224,12 @@ umac128.o: umac.c
clean: regressclean
rm -f *.o *.a $(TARGETS) logintest config.cache config.log
rm -f *.out core survey
+ rm -f regress/unittests/test_helper/*.a
+ rm -f regress/unittests/test_helper/*.o
+ rm -f regress/unittests/sshbuf/*.o
+ rm -f regress/unittests/sshbuf/test_sshbuf
+ rm -f regress/unittests/sshkey/*.o
+ rm -f regress/unittests/sshkey/test_sshkey
(cd openbsd-compat && $(MAKE) clean)
distclean: regressclean
@@ -222,6 +238,12 @@ distclean: regressclean
rm -f Makefile buildpkg.sh config.h config.status
rm -f survey.sh openbsd-compat/regress/Makefile *~
rm -rf autom4te.cache
+ rm -f regress/unittests/test_helper/*.a
+ rm -f regress/unittests/test_helper/*.o
+ rm -f regress/unittests/sshbuf/*.o
+ rm -f regress/unittests/sshbuf/test_sshbuf
+ rm -f regress/unittests/sshkey/*.o
+ rm -f regress/unittests/sshkey/test_sshkey
(cd openbsd-compat && $(MAKE) distclean)
if test -d pkg ; then \
rm -fr pkg ; \
@@ -394,23 +416,71 @@ uninstall:
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
-regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c
+regress-prep:
[ -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 ] || \
+ mkdir -p `pwd`/regress/unittests/sshbuf
+ [ -d `pwd`/regress/unittests/sshkey ] || \
+ mkdir -p `pwd`/regress/unittests/sshkey
[ -f `pwd`/regress/Makefile ] || \
ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile
+
+regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $? \
$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
regress/setuid-allowed$(EXEEXT): $(srcdir)/regress/setuid-allowed.c
- [ -d `pwd`/regress ] || mkdir -p `pwd`/regress
- [ -f `pwd`/regress/Makefile ] || \
- ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $? \
$(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
-tests interop-tests: $(TARGETS) regress/modpipe$(EXEEXT) regress/setuid-allowed$(EXEEXT)
+UNITTESTS_TEST_HELPER_OBJS=\
+ regress/unittests/test_helper/test_helper.o \
+ regress/unittests/test_helper/fuzz.o
+
+regress/unittests/test_helper/libtest_helper.a: ${UNITTESTS_TEST_HELPER_OBJS}
+ $(AR) rv $@ $(UNITTESTS_TEST_HELPER_OBJS)
+ $(RANLIB) $@
+
+UNITTESTS_TEST_SSHBUF_OBJS=\
+ regress/unittests/sshbuf/tests.o \
+ regress/unittests/sshbuf/test_sshbuf.o \
+ regress/unittests/sshbuf/test_sshbuf_getput_basic.o \
+ regress/unittests/sshbuf/test_sshbuf_getput_crypto.o \
+ regress/unittests/sshbuf/test_sshbuf_misc.o \
+ regress/unittests/sshbuf/test_sshbuf_fuzz.o \
+ regress/unittests/sshbuf/test_sshbuf_getput_fuzz.o \
+ regress/unittests/sshbuf/test_sshbuf_fixed.o
+
+regress/unittests/sshbuf/test_sshbuf$(EXEEXT): ${UNITTESTS_TEST_SSHBUF_OBJS} \
+ regress/unittests/test_helper/libtest_helper.a libssh.a
+ $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHBUF_OBJS) \
+ regress/unittests/test_helper/libtest_helper.a \
+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+
+UNITTESTS_TEST_SSHKEY_OBJS=\
+ regress/unittests/sshkey/test_fuzz.o \
+ regress/unittests/sshkey/tests.o \
+ regress/unittests/sshkey/common.o \
+ regress/unittests/sshkey/test_file.o \
+ regress/unittests/sshkey/test_sshkey.o
+
+regress/unittests/sshkey/test_sshkey$(EXEEXT): ${UNITTESTS_TEST_SSHKEY_OBJS} \
+ regress/unittests/test_helper/libtest_helper.a libssh.a
+ $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHKEY_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/unittests/sshbuf/test_sshbuf$(EXEEXT) \
+ regress/unittests/sshkey/test_sshkey$(EXEEXT)
+
+tests interop-tests t-exec: regress-prep $(TARGETS) $(REGRESS_BINARIES)
BUILDDIR=`pwd`; \
- TEST_SHELL="@TEST_SHELL@"; \
TEST_SSH_SCP="$${BUILDDIR}/scp"; \
TEST_SSH_SSH="$${BUILDDIR}/ssh"; \
TEST_SSH_SSHD="$${BUILDDIR}/sshd"; \
@@ -434,7 +504,6 @@ tests interop-tests: $(TARGETS) regress/modpipe$(EXEEXT) regress/setuid-allowed$
OBJ="$${BUILDDIR}/regress/" \
PATH="$${BUILDDIR}:$${PATH}" \
TEST_ENV=MALLOC_OPTIONS="@TEST_MALLOC_OPTIONS@" \
- TEST_SHELL="$${TEST_SHELL}" \
TEST_SSH_SCP="$${TEST_SSH_SCP}" \
TEST_SSH_SSH="$${TEST_SSH_SSH}" \
TEST_SSH_SSHD="$${TEST_SSH_SSHD}" \
@@ -450,6 +519,7 @@ tests interop-tests: $(TARGETS) regress/modpipe$(EXEEXT) regress/setuid-allowed$
TEST_SSH_CONCH="$${TEST_SSH_CONCH}" \
TEST_SSH_IPV6="$${TEST_SSH_IPV6}" \
TEST_SSH_ECC="$${TEST_SSH_ECC}" \
+ TEST_SHELL="${TEST_SHELL}" \
EXEEXT="$(EXEEXT)" \
$@ && echo all tests passed
diff --git a/PROTOCOL b/PROTOCOL
index 4a5088f90b50..aa59f584eeb4 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -232,6 +232,56 @@ The contents of the "data" field for layer 2 packets is:
The "frame" field contains an IEEE 802.3 Ethernet frame, including
header.
+2.4. connection: Unix domain socket forwarding
+
+OpenSSH supports local and remote Unix domain socket forwarding
+using the "streamlocal" extension. Forwarding is initiated as per
+TCP sockets but with a single path instead of a host and port.
+
+Similar to direct-tcpip, direct-streamlocal is sent by the client
+to request that the server make a connection to a Unix domain socket.
+
+ byte SSH_MSG_CHANNEL_OPEN
+ string "direct-streamlocal@openssh.com"
+ uint32 sender channel
+ uint32 initial window size
+ uint32 maximum packet size
+ string socket path
+ string reserved for future use
+
+Similar to forwarded-tcpip, forwarded-streamlocal is sent by the
+server when the client has previously send the server a streamlocal-forward
+GLOBAL_REQUEST.
+
+ byte SSH_MSG_CHANNEL_OPEN
+ string "forwarded-streamlocal@openssh.com"
+ uint32 sender channel
+ uint32 initial window size
+ uint32 maximum packet size
+ string socket path
+ string reserved for future use
+
+The reserved field is not currently defined and is ignored on the
+remote end. It is intended to be used in the future to pass
+information about the socket file, such as ownership and mode.
+The client currently sends the empty string for this field.
+
+Similar to tcpip-forward, streamlocal-forward is sent by the client
+to request remote forwarding of a Unix domain socket.
+
+ byte SSH2_MSG_GLOBAL_REQUEST
+ string "streamlocal-forward@openssh.com"
+ boolean TRUE
+ string socket path
+
+Similar to cancel-tcpip-forward, cancel-streamlocal-forward is sent
+by the client cancel the forwarding of a Unix domain socket.
+
+ byte SSH2_MSG_GLOBAL_REQUEST
+ string "cancel-streamlocal-forward@openssh.com"
+ boolean FALSE
+ string socket path
+
3. SFTP protocol changes
3.1. sftp: Reversal of arguments to SSH_FXP_SYMLINK
@@ -356,4 +406,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.23 2013/12/01 23:19:05 djm Exp $
+$OpenBSD: PROTOCOL,v 1.24 2014/07/15 15:54:14 millert Exp $
diff --git a/README b/README
index 368dca59c39a..b21441ae0683 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-See http://www.openssh.com/txt/release-6.6 for the release notes.
+See http://www.openssh.com/txt/release-6.7 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
@@ -62,4 +62,4 @@ References -
[6] http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9
[7] http://www.openssh.com/faq.html
-$Id: README,v 1.86 2014/02/27 23:03:53 djm Exp $
+$Id: README,v 1.87 2014/08/10 01:35:06 djm Exp $
diff --git a/auth-bsdauth.c b/auth-bsdauth.c
index 0b3262b49fc6..37ff893e6938 100644
--- a/auth-bsdauth.c
+++ b/auth-bsdauth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-bsdauth.c,v 1.11 2007/09/21 08:15:29 djm Exp $ */
+/* $OpenBSD: auth-bsdauth.c,v 1.13 2014/06/24 01:13:21 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@@ -26,6 +26,8 @@
#include "includes.h"
#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
#include <stdarg.h>
@@ -54,6 +56,11 @@ bsdauth_query(void *ctx, char **name, char **infotxt,
Authctxt *authctxt = ctx;
char *challenge = NULL;
+ *infotxt = NULL;
+ *numprompts = 0;
+ *prompts = NULL;
+ *echo_on = NULL;
+
if (authctxt->as != NULL) {
debug2("bsdauth_query: try reuse session");
challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
diff --git a/auth-chall.c b/auth-chall.c
index 0005aa88bf8a..5c26a403dff9 100644
--- a/auth-chall.c
+++ b/auth-chall.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-chall.c,v 1.13 2013/05/17 00:13:13 djm Exp $ */
+/* $OpenBSD: auth-chall.c,v 1.14 2014/06/24 01:13:21 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@@ -26,6 +26,9 @@
#include "includes.h"
#include <sys/types.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
#include <stdarg.h>
@@ -34,6 +37,7 @@
#include "hostfile.h"
#include "auth.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
/* limited protocol v1 interface to kbd-interactive authentication */
diff --git a/auth-krb5.c b/auth-krb5.c
index 6c62bdf54a51..0089b18440a9 100644
--- a/auth-krb5.c
+++ b/auth-krb5.c
@@ -40,6 +40,7 @@
#include "packet.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "uidswap.h"
#include "key.h"
diff --git a/auth-options.c b/auth-options.c
index fa209eaab813..f3d9c9df820f 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.c,v 1.62 2013/12/19 00:27:57 djm Exp $ */
+/* $OpenBSD: auth-options.c,v 1.64 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -26,9 +26,9 @@
#include "log.h"
#include "canohost.h"
#include "buffer.h"
+#include "misc.h"
#include "channels.h"
#include "servconf.h"
-#include "misc.h"
#include "key.h"
#include "auth-options.h"
#include "hostfile.h"
@@ -325,6 +325,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
patterns[i] = '\0';
opts++;
p = patterns;
+ /* XXX - add streamlocal support */
host = hpdelim(&p);
if (host == NULL || strlen(host) >= NI_MAXHOST) {
debug("%.100s, line %lu: Bad permitopen "
@@ -586,8 +587,8 @@ auth_cert_options(Key *k, struct passwd *pw)
if (key_cert_is_legacy(k)) {
/* All options are in the one field for v00 certs */
- if (parse_option_list(buffer_ptr(&k->cert->critical),
- buffer_len(&k->cert->critical), pw,
+ if (parse_option_list(buffer_ptr(k->cert->critical),
+ buffer_len(k->cert->critical), pw,
OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1,
&cert_no_port_forwarding_flag,
&cert_no_agent_forwarding_flag,
@@ -599,14 +600,14 @@ 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(buffer_ptr(k->cert->critical),
+ buffer_len(k->cert->critical), pw,
OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL,
&cert_forced_command,
&cert_source_address_done) == -1)
return -1;
- if (parse_option_list(buffer_ptr(&k->cert->extensions),
- buffer_len(&k->cert->extensions), pw,
+ if (parse_option_list(buffer_ptr(k->cert->extensions),
+ buffer_len(k->cert->extensions), pw,
OPTIONS_EXTENSIONS, 1,
&cert_no_port_forwarding_flag,
&cert_no_agent_forwarding_flag,
diff --git a/auth-passwd.c b/auth-passwd.c
index 68bbd18ddd97..63ccf3cabe7d 100644
--- a/auth-passwd.c
+++ b/auth-passwd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-passwd.c,v 1.43 2007/09/21 08:15:29 djm Exp $ */
+/* $OpenBSD: auth-passwd.c,v 1.44 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -48,6 +48,7 @@
#include "packet.h"
#include "buffer.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "key.h"
#include "hostfile.h"
diff --git a/auth-rh-rsa.c b/auth-rh-rsa.c
index b21a0f4a2f80..b7fd064e7dc8 100644
--- a/auth-rh-rsa.c
+++ b/auth-rh-rsa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rh-rsa.c,v 1.43 2010/03/04 10:36:03 djm Exp $ */
+/* $OpenBSD: auth-rh-rsa.c,v 1.44 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -24,6 +24,7 @@
#include "uidswap.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "key.h"
#include "hostfile.h"
diff --git a/auth-rhosts.c b/auth-rhosts.c
index 06ae7f0b9e7d..b5bedee8d40d 100644
--- a/auth-rhosts.c
+++ b/auth-rhosts.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rhosts.c,v 1.44 2010/03/07 11:57:13 dtucker Exp $ */
+/* $OpenBSD: auth-rhosts.c,v 1.45 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -34,12 +34,12 @@
#include "uidswap.h"
#include "pathnames.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "canohost.h"
#include "key.h"
#include "hostfile.h"
#include "auth.h"
-#include "misc.h"
/* import */
extern ServerOptions options;
diff --git a/auth-rsa.c b/auth-rsa.c
index 5dad6c3dc98a..e9f4ede26a77 100644
--- a/auth-rsa.c
+++ b/auth-rsa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rsa.c,v 1.86 2014/01/27 19:18:54 markus Exp $ */
+/* $OpenBSD: auth-rsa.c,v 1.88 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -35,6 +35,7 @@
#include "buffer.h"
#include "pathnames.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "key.h"
#include "auth-options.h"
@@ -45,7 +46,6 @@
#endif
#include "monitor_wrap.h"
#include "ssh.h"
-#include "misc.h"
#include "digest.h"
@@ -144,7 +144,8 @@ auth_rsa_challenge_dialog(Key *key)
challenge = PRIVSEP(auth_rsa_generate_challenge(key));
/* Encrypt the challenge with the public key. */
- rsa_public_encrypt(encrypted_challenge, challenge, key->rsa);
+ if (rsa_public_encrypt(encrypted_challenge, challenge, key->rsa) != 0)
+ fatal("%s: rsa_public_encrypt failed", __func__);
/* Send the encrypted challenge to the client. */
packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
diff --git a/auth.c b/auth.c
index 9a36f1dac59d..5e60682ce28b 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.103 2013/05/19 02:42:42 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.106 2014/07/15 15:54:14 millert Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -56,6 +56,7 @@
#include "groupaccess.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "key.h"
#include "hostfile.h"
@@ -63,7 +64,6 @@
#include "auth-options.h"
#include "canohost.h"
#include "uidswap.h"
-#include "misc.h"
#include "packet.h"
#include "loginrec.h"
#ifdef GSSAPI
@@ -326,6 +326,20 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
#endif
}
+
+void
+auth_maxtries_exceeded(Authctxt *authctxt)
+{
+ packet_disconnect("Too many authentication failures for "
+ "%s%.100s from %.200s port %d %s",
+ authctxt->valid ? "" : "invalid user ",
+ authctxt->user,
+ get_remote_ipaddr(),
+ get_remote_port(),
+ compat20 ? "ssh2" : "ssh1");
+ /* NOTREACHED */
+}
+
/*
* Check whether root logins are disallowed.
*/
@@ -659,6 +673,7 @@ getpwnamallow(const char *user)
int
auth_key_is_revoked(Key *key)
{
+#ifdef WITH_OPENSSL
char *key_fp;
if (options.revoked_keys_file == NULL)
@@ -671,6 +686,7 @@ auth_key_is_revoked(Key *key)
default:
goto revoked;
}
+#endif
debug3("%s: treating %s as a key list", __func__,
options.revoked_keys_file);
switch (key_in_file(key, options.revoked_keys_file, 0)) {
@@ -682,6 +698,7 @@ auth_key_is_revoked(Key *key)
error("Revoked keys file is unreadable: refusing public key "
"authentication");
return 1;
+#ifdef WITH_OPENSSL
case 1:
revoked:
/* Key revoked */
@@ -690,6 +707,7 @@ auth_key_is_revoked(Key *key)
"%s key %s ", key_type(key), key_fp);
free(key_fp);
return 1;
+#endif
}
fatal("key_in_file returned junk");
}
diff --git a/auth.h b/auth.h
index 124e597436f8..d081c94a6f36 100644
--- a/auth.h
+++ b/auth.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.h,v 1.77 2014/01/29 06:18:35 djm Exp $ */
+/* $OpenBSD: auth.h,v 1.78 2014/07/03 11:16:55 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@@ -154,6 +154,7 @@ void auth_info(Authctxt *authctxt, const char *, ...)
__attribute__((__format__ (printf, 2, 3)))
__attribute__((__nonnull__ (2)));
void auth_log(Authctxt *, int, int, const char *, const char *);
+void auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn));
void userauth_finish(Authctxt *, int, const char *, const char *);
int auth_root_allowed(const char *);
@@ -210,8 +211,6 @@ struct passwd *fakepw(void);
int sys_auth_passwd(Authctxt *, const char *);
-#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
-
#define SKEY_PROMPT "\nS/Key Password: "
#if defined(KRB5) && !defined(HEIMDAL)
diff --git a/auth1.c b/auth1.c
index 0f870b3b6d3d..50388285ce4c 100644
--- a/auth1.c
+++ b/auth1.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth1.c,v 1.80 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: auth1.c,v 1.82 2014/07/15 15:54:14 millert Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@@ -27,6 +27,7 @@
#include "packet.h"
#include "buffer.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "key.h"
@@ -363,7 +364,7 @@ do_authloop(Authctxt *authctxt)
#ifdef SSH_AUDIT_EVENTS
PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
#endif
- packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
+ auth_maxtries_exceeded(authctxt);
}
packet_start(SSH_SMSG_FAILURE);
diff --git a/auth2-chall.c b/auth2-chall.c
index 980250a91c3e..ea4eb6952f8c 100644
--- a/auth2-chall.c
+++ b/auth2-chall.c
@@ -41,6 +41,7 @@
#include "packet.h"
#include "dispatch.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
/* import */
diff --git a/auth2-gss.c b/auth2-gss.c
index c28a705cb6c9..447f896f2b55 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -40,6 +40,7 @@
#include "log.h"
#include "dispatch.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "packet.h"
#include "ssh-gss.h"
diff --git a/auth2-hostbased.c b/auth2-hostbased.c
index 488008f62289..6787e4ca4186 100644
--- a/auth2-hostbased.c
+++ b/auth2-hostbased.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-hostbased.c,v 1.17 2013/12/30 23:52:27 djm Exp $ */
+/* $OpenBSD: auth2-hostbased.c,v 1.18 2014/07/15 15:54:14 millert Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -36,6 +36,7 @@
#include "packet.h"
#include "buffer.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "key.h"
diff --git a/auth2-kbdint.c b/auth2-kbdint.c
index c39bdc62da37..bf75c6059f1e 100644
--- a/auth2-kbdint.c
+++ b/auth2-kbdint.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-kbdint.c,v 1.6 2013/05/17 00:13:13 djm Exp $ */
+/* $OpenBSD: auth2-kbdint.c,v 1.7 2014/07/15 15:54:14 millert Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -36,6 +36,7 @@
#include "auth.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
/* import */
diff --git a/auth2-none.c b/auth2-none.c
index c8c6c74a9347..e71e2219cff1 100644
--- a/auth2-none.c
+++ b/auth2-none.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-none.c,v 1.16 2010/06/25 08:46:17 djm Exp $ */
+/* $OpenBSD: auth2-none.c,v 1.18 2014/07/15 15:54:14 millert Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -30,9 +30,10 @@
#include <sys/uio.h>
#include <fcntl.h>
-#include <stdarg.h>
#include <string.h>
#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
#include "atomicio.h"
#include "xmalloc.h"
@@ -42,6 +43,7 @@
#include "packet.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "ssh2.h"
diff --git a/auth2-passwd.c b/auth2-passwd.c
index 707680cd0535..b638e8715bb2 100644
--- a/auth2-passwd.c
+++ b/auth2-passwd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-passwd.c,v 1.11 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: auth2-passwd.c,v 1.12 2014/07/15 15:54:14 millert Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -41,6 +41,7 @@
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
+#include "misc.h"
#include "servconf.h"
/* import */
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 0fd27bb9283c..f3ca96592b95 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.39 2013/12/30 23:52:27 djm Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.41 2014/07/15 15:54:14 millert Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -48,6 +48,7 @@
#include "packet.h"
#include "buffer.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "key.h"
@@ -61,7 +62,6 @@
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
-#include "misc.h"
#include "authfile.h"
#include "match.h"
@@ -230,7 +230,7 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
}
static int
-match_principals_option(const char *principal_list, struct KeyCert *cert)
+match_principals_option(const char *principal_list, struct sshkey_cert *cert)
{
char *result;
u_int i;
@@ -250,7 +250,7 @@ match_principals_option(const char *principal_list, struct KeyCert *cert)
}
static int
-match_principals_file(char *file, struct passwd *pw, struct KeyCert *cert)
+match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
{
FILE *f;
char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
diff --git a/auth2.c b/auth2.c
index a5490c009057..d9b440ae38f2 100644
--- a/auth2.c
+++ b/auth2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2.c,v 1.130 2014/01/29 06:18:35 djm Exp $ */
+/* $OpenBSD: auth2.c,v 1.132 2014/07/15 15:54:14 millert Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -41,6 +41,7 @@
#include "packet.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "key.h"
@@ -362,7 +363,7 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
#ifdef SSH_AUDIT_EVENTS
PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
#endif
- packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
+ auth_maxtries_exceeded(authctxt);
}
methods = authmethods_get(authctxt);
debug3("%s: failure partial=%d next methods=\"%s\"", __func__,
diff --git a/authfd.c b/authfd.c
index cea3f97b4146..2d5a8dd5bb49 100644
--- a/authfd.c
+++ b/authfd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: authfd.c,v 1.92 2014/01/31 16:39:19 tedu Exp $ */
+/* $OpenBSD: authfd.c,v 1.93 2014/04/29 18:01:49 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -41,9 +41,6 @@
#include <sys/un.h>
#include <sys/socket.h>
-#include <openssl/evp.h>
-#include <openssl/crypto.h>
-
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
@@ -313,8 +310,10 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi
Key *
ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
{
+#ifdef WITH_SSH1
int keybits;
u_int bits;
+#endif
u_char *blob;
u_int blen;
Key *key = NULL;
@@ -328,6 +327,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
* error if the packet is too short or contains corrupt data.
*/
switch (version) {
+#ifdef WITH_SSH1
case 1:
key = key_new(KEY_RSA1);
bits = buffer_get_int(&auth->identities);
@@ -339,6 +339,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
logit("Warning: identity keysize mismatch: actual %d, announced %u",
BN_num_bits(key->rsa->n), bits);
break;
+#endif
case 2:
blob = buffer_get_string(&auth->identities, &blen);
*comment = buffer_get_string(&auth->identities, NULL);
@@ -361,6 +362,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
* supported) and 1 corresponding to protocol version 1.1.
*/
+#ifdef WITH_SSH1
int
ssh_decrypt_challenge(AuthenticationConnection *auth,
Key* key, BIGNUM *challenge,
@@ -410,6 +412,7 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
buffer_free(&buffer);
return success;
}
+#endif
/* ask agent to sign data, returns -1 on error, 0 on success */
int
@@ -457,6 +460,7 @@ ssh_agent_sign(AuthenticationConnection *auth,
/* Encode key for a message to the agent. */
+#ifdef WITH_SSH1
static void
ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
{
@@ -470,6 +474,7 @@ ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */
buffer_put_cstring(b, comment);
}
+#endif
static void
ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
@@ -493,6 +498,7 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,
buffer_init(&msg);
switch (key->type) {
+#ifdef WITH_SSH1
case KEY_RSA1:
type = constrained ?
SSH_AGENTC_ADD_RSA_ID_CONSTRAINED :
@@ -500,6 +506,8 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,
buffer_put_char(&msg, type);
ssh_encode_identity_rsa1(&msg, key->rsa, comment);
break;
+#endif
+#ifdef WITH_OPENSSL
case KEY_RSA:
case KEY_RSA_CERT:
case KEY_RSA_CERT_V00:
@@ -508,6 +516,7 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,
case KEY_DSA_CERT_V00:
case KEY_ECDSA:
case KEY_ECDSA_CERT:
+#endif
case KEY_ED25519:
case KEY_ED25519_CERT:
type = constrained ?
@@ -552,12 +561,15 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key)
buffer_init(&msg);
+#ifdef WITH_SSH1
if (key->type == KEY_RSA1) {
buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
buffer_put_int(&msg, BN_num_bits(key->rsa->n));
buffer_put_bignum(&msg, key->rsa->e);
buffer_put_bignum(&msg, key->rsa->n);
- } else if (key->type != KEY_UNSPEC) {
+ } else
+#endif
+ if (key->type != KEY_UNSPEC) {
key_to_blob(key, &blob, &blen);
buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
buffer_put_string(&msg, blob, blen);
diff --git a/authfile.c b/authfile.c
index d7eaa9dec49c..e93d8673860c 100644
--- a/authfile.c
+++ b/authfile.c
@@ -1,18 +1,5 @@
-/* $OpenBSD: authfile.c,v 1.103 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: authfile.c,v 1.107 2014/06/24 01:13:21 djm Exp $ */
/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * This file contains functions for reading and writing identity files, and
- * for reading the passphrase from the user.
- *
- * 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".
- *
- *
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,30 +30,15 @@
#include <sys/param.h>
#include <sys/uio.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-
-/* compatibility with old or broken OpenSSL versions */
-#include "openbsd-compat/openssl-compat.h"
-
-#include "crypto_api.h"
-
#include <errno.h>
#include <fcntl.h>
-#include <stdarg.h>
#include <stdio.h>
+#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#ifdef HAVE_UTIL_H
-#include <util.h>
-#endif
-
-#include "xmalloc.h"
#include "cipher.h"
-#include "buffer.h"
#include "key.h"
#include "ssh.h"
#include "log.h"
@@ -74,903 +46,159 @@
#include "rsa.h"
#include "misc.h"
#include "atomicio.h"
-#include "uuencode.h"
-
-/* openssh private key file format */
-#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n"
-#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n"
-#define KDFNAME "bcrypt"
-#define AUTH_MAGIC "openssh-key-v1"
-#define SALT_LEN 16
-#define DEFAULT_CIPHERNAME "aes256-cbc"
-#define DEFAULT_ROUNDS 16
+#include "sshbuf.h"
+#include "ssherr.h"
#define MAX_KEY_FILE_SIZE (1024 * 1024)
-/* Version identification string for SSH v1 identity files. */
-static const char authfile_id_string[] =
- "SSH PRIVATE KEY FILE FORMAT 1.1\n";
-
-static int
-key_private_to_blob2(Key *prv, Buffer *blob, const char *passphrase,
- const char *comment, const char *ciphername, int rounds)
-{
- u_char *key, *cp, salt[SALT_LEN];
- size_t keylen, ivlen, blocksize, authlen;
- u_int len, check;
- int i, n;
- const Cipher *c;
- Buffer encoded, b, kdf;
- CipherContext ctx;
- const char *kdfname = KDFNAME;
-
- if (rounds <= 0)
- rounds = DEFAULT_ROUNDS;
- if (passphrase == NULL || !strlen(passphrase)) {
- ciphername = "none";
- kdfname = "none";
- } else if (ciphername == NULL)
- ciphername = DEFAULT_CIPHERNAME;
- else if (cipher_number(ciphername) != SSH_CIPHER_SSH2)
- fatal("invalid cipher");
-
- if ((c = cipher_by_name(ciphername)) == NULL)
- fatal("unknown cipher name");
- buffer_init(&kdf);
- blocksize = cipher_blocksize(c);
- keylen = cipher_keylen(c);
- ivlen = cipher_ivlen(c);
- authlen = cipher_authlen(c);
- key = xcalloc(1, keylen + ivlen);
- if (strcmp(kdfname, "none") != 0) {
- arc4random_buf(salt, SALT_LEN);
- if (bcrypt_pbkdf(passphrase, strlen(passphrase),
- salt, SALT_LEN, key, keylen + ivlen, rounds) < 0)
- fatal("bcrypt_pbkdf failed");
- buffer_put_string(&kdf, salt, SALT_LEN);
- buffer_put_int(&kdf, rounds);
- }
- cipher_init(&ctx, c, key, keylen, key + keylen , ivlen, 1);
- explicit_bzero(key, keylen + ivlen);
- free(key);
-
- buffer_init(&encoded);
- buffer_append(&encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC));
- buffer_put_cstring(&encoded, ciphername);
- buffer_put_cstring(&encoded, kdfname);
- buffer_put_string(&encoded, buffer_ptr(&kdf), buffer_len(&kdf));
- buffer_put_int(&encoded, 1); /* number of keys */
- key_to_blob(prv, &cp, &len); /* public key */
- buffer_put_string(&encoded, cp, len);
-
- explicit_bzero(cp, len);
- free(cp);
-
- buffer_free(&kdf);
-
- /* set up the buffer that will be encrypted */
- buffer_init(&b);
-
- /* Random check bytes */
- check = arc4random();
- buffer_put_int(&b, check);
- buffer_put_int(&b, check);
-
- /* append private key and comment*/
- key_private_serialize(prv, &b);
- buffer_put_cstring(&b, comment);
-
- /* padding */
- i = 0;
- while (buffer_len(&b) % blocksize)
- buffer_put_char(&b, ++i & 0xff);
-
- /* length */
- buffer_put_int(&encoded, buffer_len(&b));
-
- /* encrypt */
- cp = buffer_append_space(&encoded, buffer_len(&b) + authlen);
- if (cipher_crypt(&ctx, 0, cp, buffer_ptr(&b), buffer_len(&b), 0,
- authlen) != 0)
- fatal("%s: cipher_crypt failed", __func__);
- buffer_free(&b);
- cipher_cleanup(&ctx);
-
- /* uuencode */
- len = 2 * buffer_len(&encoded);
- cp = xmalloc(len);
- n = uuencode(buffer_ptr(&encoded), buffer_len(&encoded),
- (char *)cp, len);
- if (n < 0)
- fatal("%s: uuencode", __func__);
-
- buffer_clear(blob);
- buffer_append(blob, MARK_BEGIN, sizeof(MARK_BEGIN) - 1);
- for (i = 0; i < n; i++) {
- buffer_put_char(blob, cp[i]);
- if (i % 70 == 69)
- buffer_put_char(blob, '\n');
- }
- if (i % 70 != 69)
- buffer_put_char(blob, '\n');
- buffer_append(blob, MARK_END, sizeof(MARK_END) - 1);
- free(cp);
-
- return buffer_len(blob);
-}
-
-static Key *
-key_parse_private2(Buffer *blob, int type, const char *passphrase,
- char **commentp)
-{
- u_char *key = NULL, *cp, *salt = NULL, pad, last;
- char *comment = NULL, *ciphername = NULL, *kdfname = NULL, *kdfp;
- u_int keylen = 0, ivlen, blocksize, slen, klen, len, rounds, nkeys;
- u_int check1, check2, m1len, m2len;
- size_t authlen;
- const Cipher *c;
- Buffer b, encoded, copy, kdf;
- CipherContext ctx;
- Key *k = NULL;
- int dlen, ret, i;
-
- buffer_init(&b);
- buffer_init(&kdf);
- buffer_init(&encoded);
- buffer_init(&copy);
-
- /* uudecode */
- m1len = sizeof(MARK_BEGIN) - 1;
- m2len = sizeof(MARK_END) - 1;
- cp = buffer_ptr(blob);
- len = buffer_len(blob);
- if (len < m1len || memcmp(cp, MARK_BEGIN, m1len)) {
- debug("%s: missing begin marker", __func__);
- goto out;
- }
- cp += m1len;
- len -= m1len;
- while (len) {
- if (*cp != '\n' && *cp != '\r')
- buffer_put_char(&encoded, *cp);
- last = *cp;
- len--;
- cp++;
- if (last == '\n') {
- if (len >= m2len && !memcmp(cp, MARK_END, m2len)) {
- buffer_put_char(&encoded, '\0');
- break;
- }
- }
- }
- if (!len) {
- debug("%s: no end marker", __func__);
- goto out;
- }
- len = buffer_len(&encoded);
- if ((cp = buffer_append_space(&copy, len)) == NULL) {
- error("%s: buffer_append_space", __func__);
- goto out;
- }
- if ((dlen = uudecode(buffer_ptr(&encoded), cp, len)) < 0) {
- error("%s: uudecode failed", __func__);
- goto out;
- }
- if ((u_int)dlen > len) {
- error("%s: crazy uudecode length %d > %u", __func__, dlen, len);
- goto out;
- }
- buffer_consume_end(&copy, len - dlen);
- if (buffer_len(&copy) < sizeof(AUTH_MAGIC) ||
- memcmp(buffer_ptr(&copy), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
- error("%s: bad magic", __func__);
- goto out;
- }
- buffer_consume(&copy, sizeof(AUTH_MAGIC));
-
- ciphername = buffer_get_cstring_ret(&copy, NULL);
- if (ciphername == NULL ||
- (c = cipher_by_name(ciphername)) == NULL) {
- error("%s: unknown cipher name", __func__);
- goto out;
- }
- if ((passphrase == NULL || !strlen(passphrase)) &&
- strcmp(ciphername, "none") != 0) {
- /* passphrase required */
- goto out;
- }
- kdfname = buffer_get_cstring_ret(&copy, NULL);
- if (kdfname == NULL ||
- (!strcmp(kdfname, "none") && !strcmp(kdfname, "bcrypt"))) {
- error("%s: unknown kdf name", __func__);
- goto out;
- }
- if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) {
- error("%s: cipher %s requires kdf", __func__, ciphername);
- goto out;
- }
- /* kdf options */
- kdfp = buffer_get_string_ptr_ret(&copy, &klen);
- if (kdfp == NULL) {
- error("%s: kdf options not set", __func__);
- goto out;
- }
- if (klen > 0) {
- if ((cp = buffer_append_space(&kdf, klen)) == NULL) {
- error("%s: kdf alloc failed", __func__);
- goto out;
- }
- memcpy(cp, kdfp, klen);
- }
- /* number of keys */
- if (buffer_get_int_ret(&nkeys, &copy) < 0) {
- error("%s: key counter missing", __func__);
- goto out;
- }
- if (nkeys != 1) {
- error("%s: only one key supported", __func__);
- goto out;
- }
- /* pubkey */
- if ((cp = buffer_get_string_ret(&copy, &len)) == NULL) {
- error("%s: pubkey not found", __func__);
- goto out;
- }
- free(cp); /* XXX check pubkey against decrypted private key */
-
- /* size of encrypted key blob */
- len = buffer_get_int(&copy);
- blocksize = cipher_blocksize(c);
- authlen = cipher_authlen(c);
- if (len < blocksize) {
- error("%s: encrypted data too small", __func__);
- goto out;
- }
- if (len % blocksize) {
- error("%s: length not multiple of blocksize", __func__);
- goto out;
- }
-
- /* setup key */
- keylen = cipher_keylen(c);
- ivlen = cipher_ivlen(c);
- key = xcalloc(1, keylen + ivlen);
- if (!strcmp(kdfname, "bcrypt")) {
- if ((salt = buffer_get_string_ret(&kdf, &slen)) == NULL) {
- error("%s: salt not set", __func__);
- goto out;
- }
- if (buffer_get_int_ret(&rounds, &kdf) < 0) {
- error("%s: rounds not set", __func__);
- goto out;
- }
- if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
- key, keylen + ivlen, rounds) < 0) {
- error("%s: bcrypt_pbkdf failed", __func__);
- goto out;
- }
- }
-
- cp = buffer_append_space(&b, len);
- cipher_init(&ctx, c, key, keylen, key + keylen, ivlen, 0);
- ret = cipher_crypt(&ctx, 0, cp, buffer_ptr(&copy), len, 0, authlen);
- cipher_cleanup(&ctx);
- buffer_consume(&copy, len);
-
- /* fail silently on decryption errors */
- if (ret != 0) {
- debug("%s: decrypt failed", __func__);
- goto out;
- }
-
- if (buffer_len(&copy) != 0) {
- error("%s: key blob has trailing data (len = %u)", __func__,
- buffer_len(&copy));
- goto out;
- }
-
- /* check bytes */
- if (buffer_get_int_ret(&check1, &b) < 0 ||
- buffer_get_int_ret(&check2, &b) < 0) {
- error("check bytes missing");
- goto out;
- }
- if (check1 != check2) {
- debug("%s: decrypt failed: 0x%08x != 0x%08x", __func__,
- check1, check2);
- goto out;
- }
-
- k = key_private_deserialize(&b);
-
- /* comment */
- comment = buffer_get_cstring_ret(&b, NULL);
-
- i = 0;
- while (buffer_len(&b)) {
- if (buffer_get_char_ret(&pad, &b) == -1 ||
- pad != (++i & 0xff)) {
- error("%s: bad padding", __func__);
- key_free(k);
- k = NULL;
- goto out;
- }
- }
-
- if (k && commentp) {
- *commentp = comment;
- comment = NULL;
- }
-
- /* XXX decode pubkey and check against private */
- out:
- free(ciphername);
- free(kdfname);
- free(salt);
- free(comment);
- if (key)
- explicit_bzero(key, keylen + ivlen);
- free(key);
- buffer_free(&encoded);
- buffer_free(&copy);
- buffer_free(&kdf);
- buffer_free(&b);
- return k;
-}
-
-/*
- * Serialises the authentication (private) key to a blob, encrypting it with
- * passphrase. The identification of the blob (lowest 64 bits of n) will
- * precede the key to provide identification of the key without needing a
- * passphrase.
- */
-static int
-key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase,
- const char *comment)
-{
- Buffer buffer, encrypted;
- u_char buf[100], *cp;
- int i, cipher_num;
- CipherContext ciphercontext;
- const Cipher *cipher;
- u_int32_t rnd;
-
- /*
- * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
- * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
- */
- cipher_num = (strcmp(passphrase, "") == 0) ?
- SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
- if ((cipher = cipher_by_number(cipher_num)) == NULL)
- fatal("save_private_key_rsa: bad cipher");
-
- /* This buffer is used to built the secret part of the private key. */
- buffer_init(&buffer);
-
- /* Put checkbytes for checking passphrase validity. */
- rnd = arc4random();
- buf[0] = rnd & 0xff;
- buf[1] = (rnd >> 8) & 0xff;
- buf[2] = buf[0];
- buf[3] = buf[1];
- buffer_append(&buffer, buf, 4);
-
- /*
- * Store the private key (n and e will not be stored because they
- * will be stored in plain text, and storing them also in encrypted
- * format would just give known plaintext).
- */
- buffer_put_bignum(&buffer, key->rsa->d);
- buffer_put_bignum(&buffer, key->rsa->iqmp);
- buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */
- buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */
-
- /* Pad the part to be encrypted until its size is a multiple of 8. */
- while (buffer_len(&buffer) % 8 != 0)
- buffer_put_char(&buffer, 0);
-
- /* This buffer will be used to contain the data in the file. */
- buffer_init(&encrypted);
-
- /* First store keyfile id string. */
- for (i = 0; authfile_id_string[i]; i++)
- buffer_put_char(&encrypted, authfile_id_string[i]);
- buffer_put_char(&encrypted, 0);
-
- /* Store cipher type. */
- buffer_put_char(&encrypted, cipher_num);
- buffer_put_int(&encrypted, 0); /* For future extension */
-
- /* Store public key. This will be in plain text. */
- buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
- buffer_put_bignum(&encrypted, key->rsa->n);
- buffer_put_bignum(&encrypted, key->rsa->e);
- buffer_put_cstring(&encrypted, comment);
-
- /* Allocate space for the private part of the key in the buffer. */
- cp = buffer_append_space(&encrypted, buffer_len(&buffer));
-
- cipher_set_key_string(&ciphercontext, cipher, passphrase,
- CIPHER_ENCRYPT);
- if (cipher_crypt(&ciphercontext, 0, cp,
- buffer_ptr(&buffer), buffer_len(&buffer), 0, 0) != 0)
- fatal("%s: cipher_crypt failed", __func__);
- cipher_cleanup(&ciphercontext);
- explicit_bzero(&ciphercontext, sizeof(ciphercontext));
-
- /* Destroy temporary data. */
- explicit_bzero(buf, sizeof(buf));
- buffer_free(&buffer);
-
- buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted));
- buffer_free(&encrypted);
-
- return 1;
-}
-
-/* convert SSH v2 key in OpenSSL PEM format */
-static int
-key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase,
- const char *comment)
-{
- int success = 0;
- int blen, len = strlen(_passphrase);
- u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
-#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
- const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
-#else
- const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
-#endif
- const u_char *bptr;
- BIO *bio;
-
- if (len > 0 && len <= 4) {
- error("passphrase too short: have %d bytes, need > 4", len);
- return 0;
- }
- if ((bio = BIO_new(BIO_s_mem())) == NULL) {
- error("%s: BIO_new failed", __func__);
- return 0;
- }
- switch (key->type) {
- case KEY_DSA:
- success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
- cipher, passphrase, len, NULL, NULL);
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA:
- success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
- cipher, passphrase, len, NULL, NULL);
- break;
-#endif
- case KEY_RSA:
- success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
- cipher, passphrase, len, NULL, NULL);
- break;
- }
- if (success) {
- if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0)
- success = 0;
- else
- buffer_append(blob, bptr, blen);
- }
- BIO_free(bio);
- return success;
-}
-
/* Save a key blob to a file */
static int
-key_save_private_blob(Buffer *keybuf, const char *filename)
+sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
{
- int fd;
+ int fd, oerrno;
- if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
- error("open %s failed: %s.", filename, strerror(errno));
- return 0;
- }
- if (atomicio(vwrite, fd, buffer_ptr(keybuf),
- buffer_len(keybuf)) != buffer_len(keybuf)) {
- error("write to key file %s failed: %s", filename,
- strerror(errno));
+ if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
+ return SSH_ERR_SYSTEM_ERROR;
+ if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf),
+ sshbuf_len(keybuf)) != sshbuf_len(keybuf)) {
+ oerrno = errno;
close(fd);
unlink(filename);
- return 0;
+ errno = oerrno;
+ return SSH_ERR_SYSTEM_ERROR;
}
close(fd);
- return 1;
-}
-
-/* Serialise "key" to buffer "blob" */
-static int
-key_private_to_blob(Key *key, Buffer *blob, const char *passphrase,
- const char *comment, int force_new_format, const char *new_format_cipher,
- int new_format_rounds)
-{
- switch (key->type) {
- case KEY_RSA1:
- return key_private_rsa1_to_blob(key, blob, passphrase, comment);
- case KEY_DSA:
- case KEY_ECDSA:
- case KEY_RSA:
- if (force_new_format) {
- return key_private_to_blob2(key, blob, passphrase,
- comment, new_format_cipher, new_format_rounds);
- }
- return key_private_pem_to_blob(key, blob, passphrase, comment);
- case KEY_ED25519:
- return key_private_to_blob2(key, blob, passphrase,
- comment, new_format_cipher, new_format_rounds);
- default:
- error("%s: cannot save key type %d", __func__, key->type);
- return 0;
- }
+ return 0;
}
int
-key_save_private(Key *key, const char *filename, const char *passphrase,
- const char *comment, int force_new_format, const char *new_format_cipher,
- int new_format_rounds)
+sshkey_save_private(struct sshkey *key, const char *filename,
+ const char *passphrase, const char *comment,
+ int force_new_format, const char *new_format_cipher, int new_format_rounds)
{
- Buffer keyblob;
- int success = 0;
+ struct sshbuf *keyblob = NULL;
+ int r;
- buffer_init(&keyblob);
- if (!key_private_to_blob(key, &keyblob, passphrase, comment,
- force_new_format, new_format_cipher, new_format_rounds))
+ if ((keyblob = sshbuf_new()) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
+ force_new_format, new_format_cipher, new_format_rounds)) != 0)
goto out;
- if (!key_save_private_blob(&keyblob, filename))
+ if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
goto out;
- success = 1;
+ r = 0;
out:
- buffer_free(&keyblob);
- return success;
-}
-
-/*
- * Parse the public, unencrypted portion of a RSA1 key.
- */
-static Key *
-key_parse_public_rsa1(Buffer *blob, char **commentp)
-{
- Key *pub;
- Buffer copy;
-
- /* Check that it is at least big enough to contain the ID string. */
- if (buffer_len(blob) < sizeof(authfile_id_string)) {
- debug3("Truncated RSA1 identifier");
- return NULL;
- }
-
- /*
- * Make sure it begins with the id string. Consume the id string
- * from the buffer.
- */
- if (memcmp(buffer_ptr(blob), authfile_id_string,
- sizeof(authfile_id_string)) != 0) {
- debug3("Incorrect RSA1 identifier");
- return NULL;
- }
- buffer_init(&copy);
- buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
- buffer_consume(&copy, sizeof(authfile_id_string));
-
- /* Skip cipher type and reserved data. */
- (void) buffer_get_char(&copy); /* cipher type */
- (void) buffer_get_int(&copy); /* reserved */
-
- /* Read the public key from the buffer. */
- (void) buffer_get_int(&copy);
- pub = key_new(KEY_RSA1);
- buffer_get_bignum(&copy, pub->rsa->n);
- buffer_get_bignum(&copy, pub->rsa->e);
- if (commentp)
- *commentp = buffer_get_string(&copy, NULL);
- /* The encrypted private part is not parsed by this function. */
- buffer_free(&copy);
-
- return pub;
+ sshbuf_free(keyblob);
+ return r;
}
/* Load a key from a fd into a buffer */
int
-key_load_file(int fd, const char *filename, Buffer *blob)
+sshkey_load_file(int fd, const char *filename, struct sshbuf *blob)
{
u_char buf[1024];
size_t len;
struct stat st;
+ int r;
- if (fstat(fd, &st) < 0) {
- error("%s: fstat of key file %.200s%sfailed: %.100s", __func__,
- filename == NULL ? "" : filename,
- filename == NULL ? "" : " ",
- strerror(errno));
- return 0;
- }
+ if (fstat(fd, &st) < 0)
+ return SSH_ERR_SYSTEM_ERROR;
if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
- st.st_size > MAX_KEY_FILE_SIZE) {
- toobig:
- error("%s: key file %.200s%stoo large", __func__,
- filename == NULL ? "" : filename,
- filename == NULL ? "" : " ");
- return 0;
- }
- buffer_clear(blob);
+ st.st_size > MAX_KEY_FILE_SIZE)
+ return SSH_ERR_INVALID_FORMAT;
for (;;) {
if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
if (errno == EPIPE)
break;
- debug("%s: read from key file %.200s%sfailed: %.100s",
- __func__, filename == NULL ? "" : filename,
- filename == NULL ? "" : " ", strerror(errno));
- buffer_clear(blob);
- explicit_bzero(buf, sizeof(buf));
- return 0;
+ r = SSH_ERR_SYSTEM_ERROR;
+ goto out;
}
- buffer_append(blob, buf, len);
- if (buffer_len(blob) > MAX_KEY_FILE_SIZE) {
- buffer_clear(blob);
- explicit_bzero(buf, sizeof(buf));
- goto toobig;
+ if ((r = sshbuf_put(blob, buf, len)) != 0)
+ goto out;
+ if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
+ r = SSH_ERR_INVALID_FORMAT;
+ goto out;
}
}
- explicit_bzero(buf, sizeof(buf));
if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
- st.st_size != buffer_len(blob)) {
- debug("%s: key file %.200s%schanged size while reading",
- __func__, filename == NULL ? "" : filename,
- filename == NULL ? "" : " ");
- buffer_clear(blob);
- return 0;
+ st.st_size != (off_t)sshbuf_len(blob)) {
+ r = SSH_ERR_FILE_CHANGED;
+ goto out;
}
+ r = 0;
- return 1;
+ out:
+ explicit_bzero(buf, sizeof(buf));
+ if (r != 0)
+ sshbuf_reset(blob);
+ return r;
}
+#ifdef WITH_SSH1
/*
* Loads the public part of the ssh v1 key file. Returns NULL if an error was
* encountered (the file does not exist or is not readable), and the key
* otherwise.
*/
-static Key *
-key_load_public_rsa1(int fd, const char *filename, char **commentp)
+static int
+sshkey_load_public_rsa1(int fd, const char *filename,
+ struct sshkey **keyp, char **commentp)
{
- Buffer buffer;
- Key *pub;
-
- buffer_init(&buffer);
- if (!key_load_file(fd, filename, &buffer)) {
- buffer_free(&buffer);
- return NULL;
- }
+ struct sshbuf *b = NULL;
+ int r;
- pub = key_parse_public_rsa1(&buffer, commentp);
- if (pub == NULL)
- debug3("Could not load \"%s\" as a RSA1 public key", filename);
- buffer_free(&buffer);
- return pub;
-}
-
-/* load public key from private-key file, works only for SSH v1 */
-Key *
-key_load_public_type(int type, const char *filename, char **commentp)
-{
- Key *pub;
- int fd;
+ *keyp = NULL;
+ if (commentp != NULL)
+ *commentp = NULL;
- if (type == KEY_RSA1) {
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- return NULL;
- pub = key_load_public_rsa1(fd, filename, commentp);
- close(fd);
- return pub;
- }
- return NULL;
+ if ((b = sshbuf_new()) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if ((r = sshkey_load_file(fd, filename, b)) != 0)
+ goto out;
+ if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
+ goto out;
+ r = 0;
+ out:
+ sshbuf_free(b);
+ return r;
}
+#endif /* WITH_SSH1 */
-static Key *
-key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
+#ifdef WITH_OPENSSL
+/* XXX Deprecate? */
+int
+sshkey_load_private_pem(int fd, int type, const char *passphrase,
+ struct sshkey **keyp, char **commentp)
{
- int check1, check2, cipher_type;
- Buffer decrypted;
- u_char *cp;
- CipherContext ciphercontext;
- const Cipher *cipher;
- Key *prv = NULL;
- Buffer copy;
-
- /* Check that it is at least big enough to contain the ID string. */
- if (buffer_len(blob) < sizeof(authfile_id_string)) {
- debug3("Truncated RSA1 identifier");
- return NULL;
- }
-
- /*
- * Make sure it begins with the id string. Consume the id string
- * from the buffer.
- */
- if (memcmp(buffer_ptr(blob), authfile_id_string,
- sizeof(authfile_id_string)) != 0) {
- debug3("Incorrect RSA1 identifier");
- return NULL;
- }
- buffer_init(&copy);
- buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
- buffer_consume(&copy, sizeof(authfile_id_string));
-
- /* Read cipher type. */
- cipher_type = buffer_get_char(&copy);
- (void) buffer_get_int(&copy); /* Reserved data. */
-
- /* Read the public key from the buffer. */
- (void) buffer_get_int(&copy);
- prv = key_new_private(KEY_RSA1);
-
- buffer_get_bignum(&copy, prv->rsa->n);
- buffer_get_bignum(&copy, prv->rsa->e);
- if (commentp)
- *commentp = buffer_get_string(&copy, NULL);
- else
- (void)buffer_get_string_ptr(&copy, NULL);
+ struct sshbuf *buffer = NULL;
+ int r;
- /* Check that it is a supported cipher. */
- cipher = cipher_by_number(cipher_type);
- if (cipher == NULL) {
- debug("Unsupported RSA1 cipher %d", cipher_type);
- buffer_free(&copy);
- goto fail;
- }
- /* Initialize space for decrypted data. */
- buffer_init(&decrypted);
- cp = buffer_append_space(&decrypted, buffer_len(&copy));
-
- /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
- cipher_set_key_string(&ciphercontext, cipher, passphrase,
- CIPHER_DECRYPT);
- if (cipher_crypt(&ciphercontext, 0, cp,
- buffer_ptr(&copy), buffer_len(&copy), 0, 0) != 0)
- fatal("%s: cipher_crypt failed", __func__);
- cipher_cleanup(&ciphercontext);
- explicit_bzero(&ciphercontext, sizeof(ciphercontext));
- buffer_free(&copy);
-
- check1 = buffer_get_char(&decrypted);
- check2 = buffer_get_char(&decrypted);
- if (check1 != buffer_get_char(&decrypted) ||
- check2 != buffer_get_char(&decrypted)) {
- if (strcmp(passphrase, "") != 0)
- debug("Bad passphrase supplied for RSA1 key");
- /* Bad passphrase. */
- buffer_free(&decrypted);
- goto fail;
- }
- /* Read the rest of the private key. */
- buffer_get_bignum(&decrypted, prv->rsa->d);
- buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */
- /* in SSL and SSH v1 p and q are exchanged */
- buffer_get_bignum(&decrypted, prv->rsa->q); /* p */
- buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
-
- /* calculate p-1 and q-1 */
- rsa_generate_additional_parameters(prv->rsa);
-
- buffer_free(&decrypted);
-
- /* enable blinding */
- if (RSA_blinding_on(prv->rsa, NULL) != 1) {
- error("%s: RSA_blinding_on failed", __func__);
- goto fail;
- }
- return prv;
-
-fail:
+ *keyp = NULL;
if (commentp != NULL)
- free(*commentp);
- key_free(prv);
- return NULL;
-}
-
-static Key *
-key_parse_private_pem(Buffer *blob, int type, const char *passphrase,
- char **commentp)
-{
- EVP_PKEY *pk = NULL;
- Key *prv = NULL;
- char *name = "<no key>";
- BIO *bio;
+ *commentp = NULL;
- if ((bio = BIO_new_mem_buf(buffer_ptr(blob),
- buffer_len(blob))) == NULL) {
- error("%s: BIO_new_mem_buf failed", __func__);
- return NULL;
- }
-
- pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase);
- BIO_free(bio);
- if (pk == NULL) {
- debug("%s: PEM_read_PrivateKey failed", __func__);
- (void)ERR_get_error();
- } else if (pk->type == EVP_PKEY_RSA &&
- (type == KEY_UNSPEC||type==KEY_RSA)) {
- prv = key_new(KEY_UNSPEC);
- prv->rsa = EVP_PKEY_get1_RSA(pk);
- prv->type = KEY_RSA;
- name = "rsa w/o comment";
-#ifdef DEBUG_PK
- RSA_print_fp(stderr, prv->rsa, 8);
-#endif
- if (RSA_blinding_on(prv->rsa, NULL) != 1) {
- error("%s: RSA_blinding_on failed", __func__);
- key_free(prv);
- prv = NULL;
- }
- } else if (pk->type == EVP_PKEY_DSA &&
- (type == KEY_UNSPEC||type==KEY_DSA)) {
- prv = key_new(KEY_UNSPEC);
- prv->dsa = EVP_PKEY_get1_DSA(pk);
- prv->type = KEY_DSA;
- name = "dsa w/o comment";
-#ifdef DEBUG_PK
- DSA_print_fp(stderr, prv->dsa, 8);
-#endif
-#ifdef OPENSSL_HAS_ECC
- } else if (pk->type == EVP_PKEY_EC &&
- (type == KEY_UNSPEC||type==KEY_ECDSA)) {
- prv = key_new(KEY_UNSPEC);
- prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
- prv->type = KEY_ECDSA;
- if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 ||
- key_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
- key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
- EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
- key_ec_validate_private(prv->ecdsa) != 0) {
- error("%s: bad ECDSA key", __func__);
- key_free(prv);
- prv = NULL;
- }
- name = "ecdsa w/o comment";
-#ifdef DEBUG_PK
- if (prv != NULL && prv->ecdsa != NULL)
- key_dump_ec_key(prv->ecdsa);
-#endif
-#endif /* OPENSSL_HAS_ECC */
- } else {
- error("%s: PEM_read_PrivateKey: mismatch or "
- "unknown EVP_PKEY save_type %d", __func__, pk->save_type);
- }
- if (pk != NULL)
- EVP_PKEY_free(pk);
- if (prv != NULL && commentp)
- *commentp = xstrdup(name);
- debug("read PEM private key done: type %s",
- prv ? key_type(prv) : "<unknown>");
- return prv;
-}
-
-Key *
-key_load_private_pem(int fd, int type, const char *passphrase,
- char **commentp)
-{
- Buffer buffer;
- Key *prv;
-
- buffer_init(&buffer);
- if (!key_load_file(fd, NULL, &buffer)) {
- buffer_free(&buffer);
- return NULL;
- }
- prv = key_parse_private_pem(&buffer, type, passphrase, commentp);
- buffer_free(&buffer);
- return prv;
+ 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
-key_perm_ok(int fd, const char *filename)
+sshkey_perm_ok(int fd, const char *filename)
{
struct stat st;
if (fstat(fd, &st) < 0)
- return 0;
+ return SSH_ERR_SYSTEM_ERROR;
/*
* if a key owned by the user is accessed, then we check the
* permissions of the file. if the key owned by a different user,
@@ -985,298 +213,311 @@ key_perm_ok(int fd, const char *filename)
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("Permissions 0%3.3o for '%s' are too open.",
(u_int)st.st_mode & 0777, filename);
- error("It is required that your private key files are NOT accessible by others.");
+ error("It is recommended that your private key files are NOT accessible by others.");
error("This private key will be ignored.");
- return 0;
+ return SSH_ERR_KEY_BAD_PERMISSIONS;
}
- return 1;
+ return 0;
}
-static Key *
-key_parse_private_type(Buffer *blob, int type, const char *passphrase,
- char **commentp)
+/* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
+int
+sshkey_load_private_type(int type, const char *filename, const char *passphrase,
+ struct sshkey **keyp, char **commentp, int *perm_ok)
{
- Key *k;
+ int fd, r;
+ struct sshbuf *buffer = NULL;
- switch (type) {
- case KEY_RSA1:
- return key_parse_private_rsa1(blob, passphrase, commentp);
- case KEY_DSA:
- case KEY_ECDSA:
- case KEY_RSA:
- return key_parse_private_pem(blob, type, passphrase, commentp);
- case KEY_ED25519:
- return key_parse_private2(blob, type, passphrase, commentp);
- case KEY_UNSPEC:
- if ((k = key_parse_private2(blob, type, passphrase, commentp)))
- return k;
- return key_parse_private_pem(blob, type, passphrase, commentp);
- default:
- error("%s: cannot parse key type %d", __func__, type);
- break;
- }
- return NULL;
-}
-
-Key *
-key_load_private_type(int type, const char *filename, const char *passphrase,
- char **commentp, int *perm_ok)
-{
- int fd;
- Key *ret;
- Buffer buffer;
+ *keyp = NULL;
+ if (commentp != NULL)
+ *commentp = NULL;
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- debug("could not open key file '%s': %s", filename,
- strerror(errno));
+ if ((fd = open(filename, O_RDONLY)) < 0) {
if (perm_ok != NULL)
*perm_ok = 0;
- return NULL;
+ return SSH_ERR_SYSTEM_ERROR;
}
- if (!key_perm_ok(fd, filename)) {
+ if (sshkey_perm_ok(fd, filename) != 0) {
if (perm_ok != NULL)
*perm_ok = 0;
- error("bad permissions: ignore key: %s", filename);
- close(fd);
- return NULL;
+ r = SSH_ERR_KEY_BAD_PERMISSIONS;
+ goto out;
}
if (perm_ok != NULL)
*perm_ok = 1;
- buffer_init(&buffer);
- if (!key_load_file(fd, filename, &buffer)) {
- buffer_free(&buffer);
- close(fd);
- return NULL;
+ 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)
+ goto out;
+ r = 0;
+ out:
close(fd);
- ret = key_parse_private_type(&buffer, type, passphrase, commentp);
- buffer_free(&buffer);
- return ret;
+ if (buffer != NULL)
+ sshbuf_free(buffer);
+ return r;
}
-Key *
-key_parse_private(Buffer *buffer, const char *filename,
- const char *passphrase, char **commentp)
+/* XXX this is almost identical to sshkey_load_private_type() */
+int
+sshkey_load_private(const char *filename, const char *passphrase,
+ struct sshkey **keyp, char **commentp)
{
- Key *pub, *prv;
-
- /* it's a SSH v1 key if the public key part is readable */
- pub = key_parse_public_rsa1(buffer, commentp);
- if (pub == NULL) {
- prv = key_parse_private_type(buffer, KEY_UNSPEC,
- passphrase, NULL);
- /* use the filename as a comment for PEM */
- if (commentp && prv)
- *commentp = xstrdup(filename);
- } else {
- key_free(pub);
- /* key_parse_public_rsa1() has already loaded the comment */
- prv = key_parse_private_type(buffer, KEY_RSA1, passphrase,
- NULL);
- }
- return prv;
-}
+ struct sshbuf *buffer = NULL;
+ int r, fd;
-Key *
-key_load_private(const char *filename, const char *passphrase,
- char **commentp)
-{
- Key *prv;
- Buffer buffer;
- int fd;
+ *keyp = NULL;
+ if (commentp != NULL)
+ *commentp = NULL;
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- debug("could not open key file '%s': %s", filename,
- strerror(errno));
- return NULL;
- }
- if (!key_perm_ok(fd, filename)) {
- error("bad permissions: ignore key: %s", filename);
- close(fd);
- return NULL;
+ if ((fd = open(filename, O_RDONLY)) < 0)
+ return SSH_ERR_SYSTEM_ERROR;
+ if (sshkey_perm_ok(fd, filename) != 0) {
+ r = SSH_ERR_KEY_BAD_PERMISSIONS;
+ goto out;
}
- buffer_init(&buffer);
- if (!key_load_file(fd, filename, &buffer)) {
- buffer_free(&buffer);
- close(fd);
- return NULL;
+ if ((buffer = sshbuf_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
}
+ if ((r = sshkey_load_file(fd, filename, buffer)) != 0 ||
+ (r = sshkey_parse_private_fileblob(buffer, passphrase, filename,
+ keyp, commentp)) != 0)
+ goto out;
+ r = 0;
+ out:
close(fd);
-
- prv = key_parse_private(&buffer, filename, passphrase, commentp);
- buffer_free(&buffer);
- return prv;
+ if (buffer != NULL)
+ sshbuf_free(buffer);
+ return r;
}
static int
-key_try_load_public(Key *k, const char *filename, char **commentp)
+sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
{
FILE *f;
char line[SSH_MAX_PUBKEY_BYTES];
char *cp;
u_long linenum = 0;
+ int r;
- f = fopen(filename, "r");
- if (f != NULL) {
- while (read_keyfile_line(f, filename, line, sizeof(line),
- &linenum) != -1) {
- cp = line;
- switch (*cp) {
- case '#':
- case '\n':
- case '\0':
- continue;
- }
- /* Abort loading if this looks like a private key */
- if (strncmp(cp, "-----BEGIN", 10) == 0)
- break;
- /* Skip leading whitespace. */
- for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
- ;
- if (*cp) {
- if (key_read(k, &cp) == 1) {
- cp[strcspn(cp, "\r\n")] = '\0';
- if (commentp) {
- *commentp = xstrdup(*cp ?
- cp : filename);
- }
- fclose(f);
- return 1;
+ if (commentp != NULL)
+ *commentp = NULL;
+ if ((f = fopen(filename, "r")) == NULL)
+ return SSH_ERR_SYSTEM_ERROR;
+ while (read_keyfile_line(f, filename, line, sizeof(line),
+ &linenum) != -1) {
+ cp = line;
+ switch (*cp) {
+ case '#':
+ case '\n':
+ case '\0':
+ continue;
+ }
+ /* Abort loading if this looks like a private key */
+ if (strncmp(cp, "-----BEGIN", 10) == 0 ||
+ strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
+ break;
+ /* Skip leading whitespace. */
+ for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
+ ;
+ if (*cp) {
+ if ((r = sshkey_read(k, &cp)) == 0) {
+ cp[strcspn(cp, "\r\n")] = '\0';
+ if (commentp) {
+ *commentp = strdup(*cp ?
+ cp : filename);
+ if (*commentp == NULL)
+ r = SSH_ERR_ALLOC_FAIL;
}
+ fclose(f);
+ return r;
}
}
- fclose(f);
}
- return 0;
+ fclose(f);
+ return SSH_ERR_INVALID_FORMAT;
}
/* load public key from ssh v1 private or any pubkey file */
-Key *
-key_load_public(const char *filename, char **commentp)
+int
+sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
{
- Key *pub;
+ struct sshkey *pub = NULL;
char file[MAXPATHLEN];
+ int r, fd;
+
+ if (keyp != NULL)
+ *keyp = NULL;
+ if (commentp != NULL)
+ *commentp = NULL;
+ if ((fd = open(filename, O_RDONLY)) < 0)
+ goto skip;
+#ifdef WITH_SSH1
/* try rsa1 private key */
- pub = key_load_public_type(KEY_RSA1, filename, commentp);
- if (pub != NULL)
- return pub;
+ r = sshkey_load_public_rsa1(fd, filename, keyp, commentp);
+ close(fd);
+ switch (r) {
+ case SSH_ERR_INTERNAL_ERROR:
+ case SSH_ERR_ALLOC_FAIL:
+ case SSH_ERR_INVALID_ARGUMENT:
+ case SSH_ERR_SYSTEM_ERROR:
+ case 0:
+ return r;
+ }
+#endif /* WITH_SSH1 */
+ /* try ssh2 public key */
+ if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
+ if (keyp != NULL)
+ *keyp = pub;
+ return 0;
+ }
+ sshkey_free(pub);
+
+#ifdef WITH_SSH1
/* try rsa1 public key */
- pub = key_new(KEY_RSA1);
- if (key_try_load_public(pub, filename, commentp) == 1)
- return pub;
- key_free(pub);
+ if ((pub = sshkey_new(KEY_RSA1)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
+ if (keyp != NULL)
+ *keyp = pub;
+ return 0;
+ }
+ sshkey_free(pub);
+#endif /* WITH_SSH1 */
- /* try ssh2 public key */
- pub = key_new(KEY_UNSPEC);
- if (key_try_load_public(pub, filename, commentp) == 1)
- return pub;
+ skip:
+ /* try .pub suffix */
+ if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ r = SSH_ERR_ALLOC_FAIL; /* in case strlcpy or strlcat fail */
if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
(strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
- (key_try_load_public(pub, file, commentp) == 1))
- return pub;
- key_free(pub);
- return NULL;
+ (r = sshkey_try_load_public(pub, file, commentp)) == 0) {
+ if (keyp != NULL)
+ *keyp = pub;
+ return 0;
+ }
+ sshkey_free(pub);
+ return r;
}
/* Load the certificate associated with the named private key */
-Key *
-key_load_cert(const char *filename)
+int
+sshkey_load_cert(const char *filename, struct sshkey **keyp)
{
- Key *pub;
- char *file;
+ struct sshkey *pub = NULL;
+ char *file = NULL;
+ int r = SSH_ERR_INTERNAL_ERROR;
- pub = key_new(KEY_UNSPEC);
- xasprintf(&file, "%s-cert.pub", filename);
- if (key_try_load_public(pub, file, NULL) == 1) {
- free(file);
- return pub;
+ *keyp = NULL;
+
+ if (asprintf(&file, "%s-cert.pub", filename) == -1)
+ return SSH_ERR_ALLOC_FAIL;
+
+ if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
+ goto out;
}
- free(file);
- key_free(pub);
- return NULL;
+ if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
+ goto out;
+
+ *keyp = pub;
+ pub = NULL;
+ r = 0;
+
+ out:
+ if (file != NULL)
+ free(file);
+ if (pub != NULL)
+ sshkey_free(pub);
+ return r;
}
/* Load private key and certificate */
-Key *
-key_load_private_cert(int type, const char *filename, const char *passphrase,
- int *perm_ok)
+int
+sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
+ struct sshkey **keyp, int *perm_ok)
{
- Key *key, *pub;
+ struct sshkey *key = NULL, *cert = NULL;
+ int r;
+
+ *keyp = NULL;
switch (type) {
+#ifdef WITH_OPENSSL
case KEY_RSA:
case KEY_DSA:
case KEY_ECDSA:
case KEY_ED25519:
+#endif /* WITH_OPENSSL */
+ case KEY_UNSPEC:
break;
default:
- error("%s: unsupported key type", __func__);
- return NULL;
+ return SSH_ERR_KEY_TYPE_UNKNOWN;
}
- if ((key = key_load_private_type(type, filename,
- passphrase, NULL, perm_ok)) == NULL)
- return NULL;
-
- if ((pub = key_load_cert(filename)) == NULL) {
- key_free(key);
- return NULL;
- }
+ if ((r = sshkey_load_private_type(type, filename,
+ passphrase, &key, NULL, perm_ok)) != 0 ||
+ (r = sshkey_load_cert(filename, &cert)) != 0)
+ goto out;
/* Make sure the private key matches the certificate */
- if (key_equal_public(key, pub) == 0) {
- error("%s: certificate does not match private key %s",
- __func__, filename);
- } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) {
- error("%s: key_to_certified failed", __func__);
- } else {
- key_cert_copy(pub, key);
- key_free(pub);
- return key;
+ if (sshkey_equal_public(key, cert) == 0) {
+ r = SSH_ERR_KEY_CERT_MISMATCH;
+ goto out;
}
- key_free(key);
- key_free(pub);
- return NULL;
+ if ((r = sshkey_to_certified(key, sshkey_cert_is_legacy(cert))) != 0 ||
+ (r = sshkey_cert_copy(cert, key)) != 0)
+ goto out;
+ r = 0;
+ *keyp = key;
+ key = NULL;
+ out:
+ if (key != NULL)
+ sshkey_free(key);
+ if (cert != NULL)
+ sshkey_free(cert);
+ return r;
}
/*
- * Returns 1 if the specified "key" is listed in the file "filename",
- * 0 if the key is not listed or -1 on error.
+ * 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,
* otherwise a comparison that ignores certficiate data is performed.
*/
int
-key_in_file(Key *key, const char *filename, int strict_type)
+sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
{
FILE *f;
char line[SSH_MAX_PUBKEY_BYTES];
char *cp;
u_long linenum = 0;
- int ret = 0;
- Key *pub;
- int (*key_compare)(const Key *, const Key *) = strict_type ?
- key_equal : key_equal_public;
+ int r = 0;
+ struct sshkey *pub = NULL;
+ 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) {
- debug("%s: keyfile \"%s\" missing", __func__, filename);
- return 0;
- } else {
- error("%s: could not open keyfile \"%s\": %s", __func__,
- filename, strerror(errno));
- return -1;
- }
+ if (errno == ENOENT)
+ return SSH_ERR_KEY_NOT_FOUND;
+ else
+ return SSH_ERR_SYSTEM_ERROR;
}
while (read_keyfile_line(f, filename, line, sizeof(line),
- &linenum) != -1) {
+ &linenum) != -1) {
cp = line;
/* Skip leading whitespace. */
@@ -1291,18 +532,24 @@ key_in_file(Key *key, const char *filename, int strict_type)
continue;
}
- pub = key_new(KEY_UNSPEC);
- if (key_read(pub, &cp) != 1) {
- key_free(pub);
- continue;
+ if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
}
- if (key_compare(key, pub)) {
- ret = 1;
- key_free(pub);
- break;
+ if ((r = sshkey_read(pub, &cp)) != 0)
+ goto out;
+ if (sshkey_compare(key, pub)) {
+ r = 0;
+ goto out;
}
- key_free(pub);
+ sshkey_free(pub);
+ pub = NULL;
}
+ r = SSH_ERR_KEY_NOT_FOUND;
+ out:
+ if (pub != NULL)
+ sshkey_free(pub);
fclose(f);
- return ret;
+ return r;
}
+
diff --git a/authfile.h b/authfile.h
index 8ba1c2dbe5fd..03bc3958c740 100644
--- a/authfile.h
+++ b/authfile.h
@@ -1,32 +1,47 @@
-/* $OpenBSD: authfile.h,v 1.17 2013/12/06 13:34:54 markus Exp $ */
+/* $OpenBSD: authfile.h,v 1.19 2014/07/03 23:18:35 djm Exp $ */
/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
+ * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
*
- * 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".
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef AUTHFILE_H
#define AUTHFILE_H
-int key_save_private(Key *, const char *, const char *, const char *,
- int, const char *, int);
-int key_load_file(int, const char *, Buffer *);
-Key *key_load_cert(const char *);
-Key *key_load_public(const char *, char **);
-Key *key_load_public_type(int, const char *, char **);
-Key *key_parse_private(Buffer *, const char *, 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);
+struct sshbuf;
+struct sshkey;
+
+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_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 **);
+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_perm_ok(int, const char *);
+int sshkey_in_file(struct sshkey *, const char *, int);
#endif
diff --git a/bufaux.c b/bufaux.c
index f6a6f2ab246a..3976896a99e1 100644
--- a/bufaux.c
+++ b/bufaux.c
@@ -1,70 +1,40 @@
-/* $OpenBSD: bufaux.c,v 1.57 2014/04/16 23:22:45 djm Exp $ */
+/* $OpenBSD: bufaux.c,v 1.60 2014/04/30 05:29:56 djm Exp $ */
/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * Auxiliary functions for storing and retrieving various data types to/from
- * Buffers.
+ * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
*
- * 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".
+ * 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.
*
- *
- * SSH2 packet format added by Markus Friedl
- * Copyright (c) 2000 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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.
*/
+/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
+
#include "includes.h"
#include <sys/types.h>
-#include <openssl/bn.h>
-
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-
-#include "xmalloc.h"
#include "buffer.h"
#include "log.h"
-#include "misc.h"
-
-/*
- * Returns integers from the buffer (msb first).
- */
+#include "ssherr.h"
int
-buffer_get_short_ret(u_short *ret, Buffer *buffer)
+buffer_get_short_ret(u_short *v, Buffer *buffer)
{
- u_char buf[2];
+ int ret;
- if (buffer_get_ret(buffer, (char *) buf, 2) == -1)
- return (-1);
- *ret = get_u16(buf);
- return (0);
+ if ((ret = sshbuf_get_u16(buffer, v)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
+ return -1;
+ }
+ return 0;
}
u_short
@@ -73,21 +43,21 @@ buffer_get_short(Buffer *buffer)
u_short ret;
if (buffer_get_short_ret(&ret, buffer) == -1)
- fatal("buffer_get_short: buffer error");
+ fatal("%s: buffer error", __func__);
return (ret);
}
int
-buffer_get_int_ret(u_int *ret, Buffer *buffer)
+buffer_get_int_ret(u_int *v, Buffer *buffer)
{
- u_char buf[4];
+ int ret;
- if (buffer_get_ret(buffer, (char *) buf, 4) == -1)
- return (-1);
- if (ret != NULL)
- *ret = get_u32(buf);
- return (0);
+ if ((ret = sshbuf_get_u32(buffer, v)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
+ return -1;
+ }
+ return 0;
}
u_int
@@ -96,21 +66,21 @@ buffer_get_int(Buffer *buffer)
u_int ret;
if (buffer_get_int_ret(&ret, buffer) == -1)
- fatal("buffer_get_int: buffer error");
+ fatal("%s: buffer error", __func__);
return (ret);
}
int
-buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer)
+buffer_get_int64_ret(u_int64_t *v, Buffer *buffer)
{
- u_char buf[8];
+ int ret;
- if (buffer_get_ret(buffer, (char *) buf, 8) == -1)
- return (-1);
- if (ret != NULL)
- *ret = get_u64(buf);
- return (0);
+ if ((ret = sshbuf_get_u64(buffer, v)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
+ return -1;
+ }
+ return 0;
}
u_int64_t
@@ -119,78 +89,52 @@ buffer_get_int64(Buffer *buffer)
u_int64_t ret;
if (buffer_get_int64_ret(&ret, buffer) == -1)
- fatal("buffer_get_int: buffer error");
+ fatal("%s: buffer error", __func__);
return (ret);
}
-/*
- * Stores integers in the buffer, msb first.
- */
void
buffer_put_short(Buffer *buffer, u_short value)
{
- char buf[2];
+ int ret;
- put_u16(buf, value);
- buffer_append(buffer, buf, 2);
+ if ((ret = sshbuf_put_u16(buffer, value)) != 0)
+ fatal("%s: %s", __func__, ssh_err(ret));
}
void
buffer_put_int(Buffer *buffer, u_int value)
{
- char buf[4];
+ int ret;
- put_u32(buf, value);
- buffer_append(buffer, buf, 4);
+ if ((ret = sshbuf_put_u32(buffer, value)) != 0)
+ fatal("%s: %s", __func__, ssh_err(ret));
}
void
buffer_put_int64(Buffer *buffer, u_int64_t value)
{
- char buf[8];
+ int ret;
- put_u64(buf, value);
- buffer_append(buffer, buf, 8);
+ if ((ret = sshbuf_put_u64(buffer, value)) != 0)
+ fatal("%s: %s", __func__, ssh_err(ret));
}
-/*
- * Returns an arbitrary binary string from the buffer. The string cannot
- * be longer than 256k. The returned value points to memory allocated
- * with xmalloc; it is the responsibility of the calling function to free
- * the data. If length_ptr is non-NULL, the length of the returned data
- * will be stored there. A null character will be automatically appended
- * to the returned string, and is not counted in length.
- */
void *
buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
{
+ size_t len;
+ int ret;
u_char *value;
- u_int len;
- /* Get the length. */
- if (buffer_get_int_ret(&len, buffer) != 0) {
- error("buffer_get_string_ret: cannot extract length");
- return (NULL);
- }
- if (len > 256 * 1024) {
- error("buffer_get_string_ret: bad string length %u", len);
- return (NULL);
- }
- /* Allocate space for the string. Add one byte for a null character. */
- value = xmalloc(len + 1);
- /* Get the string. */
- if (buffer_get_ret(buffer, value, len) == -1) {
- error("buffer_get_string_ret: buffer_get failed");
- free(value);
- return (NULL);
+ if ((ret = sshbuf_get_string(buffer, &value, &len)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
+ return NULL;
}
- /* Append a null character to make processing easier. */
- value[len] = '\0';
- /* Optionally return the length of the string. */
- if (length_ptr)
- *length_ptr = len;
- return (value);
+ if (length_ptr != NULL)
+ *length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */
+ return value;
}
void *
@@ -199,31 +143,24 @@ buffer_get_string(Buffer *buffer, u_int *length_ptr)
void *ret;
if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
- fatal("buffer_get_string: buffer error");
+ fatal("%s: buffer error", __func__);
return (ret);
}
char *
buffer_get_cstring_ret(Buffer *buffer, u_int *length_ptr)
{
- u_int length;
- char *cp, *ret = buffer_get_string_ret(buffer, &length);
+ size_t len;
+ int ret;
+ char *value;
- if (ret == NULL)
+ if ((ret = sshbuf_get_cstring(buffer, &value, &len)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
return NULL;
- if ((cp = memchr(ret, '\0', length)) != NULL) {
- /* XXX allow \0 at end-of-string for a while, remove later */
- if (cp == ret + length - 1)
- error("buffer_get_cstring_ret: string contains \\0");
- else {
- explicit_bzero(ret, length);
- free(ret);
- return NULL;
- }
}
if (length_ptr != NULL)
- *length_ptr = length;
- return ret;
+ *length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */
+ return value;
}
char *
@@ -232,162 +169,91 @@ buffer_get_cstring(Buffer *buffer, u_int *length_ptr)
char *ret;
if ((ret = buffer_get_cstring_ret(buffer, length_ptr)) == NULL)
- fatal("buffer_get_cstring: buffer error");
+ fatal("%s: buffer error", __func__);
return ret;
}
-void *
+const void *
buffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr)
{
- void *ptr;
- u_int len;
+ size_t len;
+ int ret;
+ const u_char *value;
- if (buffer_get_int_ret(&len, buffer) != 0)
- return NULL;
- if (len > 256 * 1024) {
- error("buffer_get_string_ptr: bad string length %u", len);
+ if ((ret = sshbuf_get_string_direct(buffer, &value, &len)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
return NULL;
}
- ptr = buffer_ptr(buffer);
- buffer_consume(buffer, len);
- if (length_ptr)
- *length_ptr = len;
- return (ptr);
+ if (length_ptr != NULL)
+ *length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */
+ return value;
}
-void *
+const void *
buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr)
{
- void *ret;
+ const void *ret;
if ((ret = buffer_get_string_ptr_ret(buffer, length_ptr)) == NULL)
- fatal("buffer_get_string_ptr: buffer error");
+ fatal("%s: buffer error", __func__);
return (ret);
}
-/*
- * Stores and arbitrary binary string in the buffer.
- */
void
buffer_put_string(Buffer *buffer, const void *buf, u_int len)
{
- buffer_put_int(buffer, len);
- buffer_append(buffer, buf, len);
+ int ret;
+
+ if ((ret = sshbuf_put_string(buffer, buf, len)) != 0)
+ fatal("%s: %s", __func__, ssh_err(ret));
}
+
void
buffer_put_cstring(Buffer *buffer, const char *s)
{
- if (s == NULL)
- fatal("buffer_put_cstring: s == NULL");
- buffer_put_string(buffer, s, strlen(s));
+ int ret;
+
+ if ((ret = sshbuf_put_cstring(buffer, s)) != 0)
+ fatal("%s: %s", __func__, ssh_err(ret));
}
-/*
- * Returns a character from the buffer (0 - 255).
- */
int
-buffer_get_char_ret(u_char *ret, Buffer *buffer)
+buffer_get_char_ret(char *v, Buffer *buffer)
{
- if (buffer_get_ret(buffer, ret, 1) == -1) {
- error("buffer_get_char_ret: buffer_get_ret failed");
- return (-1);
+ int ret;
+
+ if ((ret = sshbuf_get_u8(buffer, (u_char *)v)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
+ return -1;
}
- return (0);
+ return 0;
}
int
buffer_get_char(Buffer *buffer)
{
- u_char ch;
+ char ch;
if (buffer_get_char_ret(&ch, buffer) == -1)
- fatal("buffer_get_char: buffer error");
- return ch;
+ fatal("%s: buffer error", __func__);
+ return (u_char) ch;
}
-/*
- * Stores a character in the buffer.
- */
void
buffer_put_char(Buffer *buffer, int value)
{
- char ch = value;
+ int ret;
- buffer_append(buffer, &ch, 1);
+ if ((ret = sshbuf_put_u8(buffer, value)) != 0)
+ fatal("%s: %s", __func__, ssh_err(ret));
}
-/* Pseudo bignum functions */
-
-void *
-buffer_get_bignum2_as_string_ret(Buffer *buffer, u_int *length_ptr)
-{
- u_int len;
- u_char *bin, *p, *ret;
-
- if ((p = bin = buffer_get_string_ret(buffer, &len)) == NULL) {
- error("%s: invalid bignum", __func__);
- return NULL;
- }
-
- if (len > 0 && (bin[0] & 0x80)) {
- error("%s: negative numbers not supported", __func__);
- free(bin);
- return NULL;
- }
- if (len > 8 * 1024) {
- error("%s: cannot handle BN of size %d", __func__, len);
- free(bin);
- return NULL;
- }
- /* Skip zero prefix on numbers with the MSB set */
- if (len > 1 && bin[0] == 0x00 && (bin[1] & 0x80) != 0) {
- p++;
- len--;
- }
- ret = xmalloc(len);
- memcpy(ret, p, len);
- explicit_bzero(p, len);
- free(bin);
- return ret;
-}
-
-void *
-buffer_get_bignum2_as_string(Buffer *buffer, u_int *l)
-{
- void *ret = buffer_get_bignum2_as_string_ret(buffer, l);
-
- if (ret == NULL)
- fatal("%s: buffer error", __func__);
- return ret;
-}
-
-/*
- * Stores a string using the bignum encoding rules (\0 pad if MSB set).
- */
void
buffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l)
{
- u_char *buf, *p;
- int pad = 0;
-
- if (l > 8 * 1024)
- fatal("%s: length %u too long", __func__, l);
- /* Skip leading zero bytes */
- for (; l > 0 && *s == 0; l--, s++)
- ;
- p = buf = xmalloc(l + 1);
- /*
- * If most significant bit is set then prepend a zero byte to
- * avoid interpretation as a negative number.
- */
- if (l > 0 && (s[0] & 0x80) != 0) {
- *p++ = '\0';
- pad = 1;
- }
- memcpy(p, s, l);
- buffer_put_string(buffer, buf, l + pad);
- explicit_bzero(buf, l + pad);
- free(buf);
-}
+ int ret;
+ if ((ret = sshbuf_put_bignum2_bytes(buffer, s, l)) != 0)
+ fatal("%s: %s", __func__, ssh_err(ret));
+}
diff --git a/bufbn.c b/bufbn.c
index 1d2e01266eeb..b7f7cb122a22 100644
--- a/bufbn.c
+++ b/bufbn.c
@@ -1,229 +1,103 @@
-/* $OpenBSD: bufbn.c,v 1.11 2014/02/27 08:25:09 djm Exp $*/
+/* $OpenBSD: bufbn.c,v 1.12 2014/04/30 05:29:56 djm Exp $ */
+
/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * Auxiliary functions for storing and retrieving various data types to/from
- * Buffers.
- *
- * 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".
- *
- *
- * SSH2 packet format added by Markus Friedl
- * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
*
- * 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
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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.
*/
+/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
+
#include "includes.h"
#include <sys/types.h>
-#include <openssl/bn.h>
-
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-
-#include "xmalloc.h"
#include "buffer.h"
#include "log.h"
-#include "misc.h"
+#include "ssherr.h"
-/*
- * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
- * by (bits+7)/8 bytes of binary data, msb first.
- */
int
buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
{
- int bits = BN_num_bits(value);
- int bin_size = (bits + 7) / 8;
- u_char *buf = xmalloc(bin_size);
- int oi;
- char msg[2];
-
- /* Get the value of in binary */
- oi = BN_bn2bin(value, buf);
- if (oi != bin_size) {
- error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d",
- oi, bin_size);
- free(buf);
- return (-1);
- }
-
- /* Store the number of bits in the buffer in two bytes, msb first. */
- put_u16(msg, bits);
- buffer_append(buffer, msg, 2);
- /* Store the binary data. */
- buffer_append(buffer, buf, oi);
-
- explicit_bzero(buf, bin_size);
- free(buf);
+ int ret;
- return (0);
+ if ((ret = sshbuf_put_bignum1(buffer, value)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
+ return -1;
+ }
+ return 0;
}
void
buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
{
if (buffer_put_bignum_ret(buffer, value) == -1)
- fatal("buffer_put_bignum: buffer error");
+ fatal("%s: buffer error", __func__);
}
-/*
- * Retrieves a BIGNUM from the buffer.
- */
int
buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
{
- u_int bits, bytes;
- u_char buf[2], *bin;
+ int ret;
- /* Get the number of bits. */
- if (buffer_get_ret(buffer, (char *) buf, 2) == -1) {
- error("buffer_get_bignum_ret: invalid length");
- return (-1);
+ if ((ret = sshbuf_get_bignum1(buffer, value)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
+ return -1;
}
- bits = get_u16(buf);
- if (bits > 65535-7) {
- error("buffer_get_bignum_ret: cannot handle BN of size %d",
- bits);
- return (-1);
- }
- /* Compute the number of binary bytes that follow. */
- bytes = (bits + 7) / 8;
- if (bytes > 8 * 1024) {
- error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes);
- return (-1);
- }
- if (buffer_len(buffer) < bytes) {
- error("buffer_get_bignum_ret: input buffer too small");
- return (-1);
- }
- bin = buffer_ptr(buffer);
- if (BN_bin2bn(bin, bytes, value) == NULL) {
- error("buffer_get_bignum_ret: BN_bin2bn failed");
- return (-1);
- }
- if (buffer_consume_ret(buffer, bytes) == -1) {
- error("buffer_get_bignum_ret: buffer_consume failed");
- return (-1);
- }
- return (0);
+ return 0;
}
void
buffer_get_bignum(Buffer *buffer, BIGNUM *value)
{
if (buffer_get_bignum_ret(buffer, value) == -1)
- fatal("buffer_get_bignum: buffer error");
+ fatal("%s: buffer error", __func__);
}
-/*
- * Stores a BIGNUM in the buffer in SSH2 format.
- */
int
buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
{
- u_int bytes;
- u_char *buf;
- int oi;
- u_int hasnohigh = 0;
-
- if (BN_is_zero(value)) {
- buffer_put_int(buffer, 0);
- return 0;
- }
- if (value->neg) {
- error("buffer_put_bignum2_ret: negative numbers not supported");
- return (-1);
- }
- bytes = BN_num_bytes(value) + 1; /* extra padding byte */
- if (bytes < 2) {
- error("buffer_put_bignum2_ret: BN too small");
- return (-1);
- }
- buf = xmalloc(bytes);
- buf[0] = 0x00;
- /* Get the value of in binary */
- oi = BN_bn2bin(value, buf+1);
- if (oi < 0 || (u_int)oi != bytes - 1) {
- error("buffer_put_bignum2_ret: BN_bn2bin() failed: "
- "oi %d != bin_size %d", oi, bytes);
- free(buf);
- return (-1);
+ int ret;
+
+ if ((ret = sshbuf_put_bignum2(buffer, value)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
+ return -1;
}
- hasnohigh = (buf[1] & 0x80) ? 0 : 1;
- buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
- explicit_bzero(buf, bytes);
- free(buf);
- return (0);
+ return 0;
}
void
buffer_put_bignum2(Buffer *buffer, const BIGNUM *value)
{
if (buffer_put_bignum2_ret(buffer, value) == -1)
- fatal("buffer_put_bignum2: buffer error");
+ fatal("%s: buffer error", __func__);
}
int
buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value)
{
- u_int len;
- u_char *bin;
+ int ret;
- if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) {
- error("buffer_get_bignum2_ret: invalid bignum");
- return (-1);
- }
-
- if (len > 0 && (bin[0] & 0x80)) {
- error("buffer_get_bignum2_ret: negative numbers not supported");
- free(bin);
- return (-1);
- }
- if (len > 8 * 1024) {
- error("buffer_get_bignum2_ret: cannot handle BN of size %d",
- len);
- free(bin);
- return (-1);
- }
- if (BN_bin2bn(bin, len, value) == NULL) {
- error("buffer_get_bignum2_ret: BN_bin2bn failed");
- free(bin);
- return (-1);
+ if ((ret = sshbuf_get_bignum2(buffer, value)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
+ return -1;
}
- free(bin);
- return (0);
+ return 0;
}
void
buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
{
if (buffer_get_bignum2_ret(buffer, value) == -1)
- fatal("buffer_get_bignum2: buffer error");
+ fatal("%s: buffer error", __func__);
}
diff --git a/bufec.c b/bufec.c
index 89482b906ef1..749ce9d4c2a6 100644
--- a/bufec.c
+++ b/bufec.c
@@ -1,6 +1,7 @@
-/* $OpenBSD: bufec.c,v 1.3 2014/01/31 16:39:19 tedu Exp $ */
+/* $OpenBSD: bufec.c,v 1.4 2014/04/30 05:29:56 djm Exp $ */
+
/*
- * Copyright (c) 2010 Damien Miller <djm@mindrot.org>
+ * Copyright (c) 2012 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
@@ -15,73 +16,29 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "includes.h"
+/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
-#ifdef OPENSSL_HAS_ECC
+#include "includes.h"
#include <sys/types.h>
-#include <openssl/bn.h>
-#include <openssl/ec.h>
-
-#include <string.h>
-#include <stdarg.h>
-
-#include "xmalloc.h"
#include "buffer.h"
#include "log.h"
-#include "misc.h"
+#include "ssherr.h"
-/*
- * Maximum supported EC GFp field length is 528 bits. SEC1 uncompressed
- * encoding represents this as two bitstring points that should each
- * be no longer than the field length, SEC1 specifies a 1 byte
- * point type header.
- * Being paranoid here may insulate us to parsing problems in
- * EC_POINT_oct2point.
- */
-#define BUFFER_MAX_ECPOINT_LEN ((528*2 / 8) + 1)
+#ifdef OPENSSL_HAS_ECC
-/*
- * Append an EC_POINT to the buffer as a string containing a SEC1 encoded
- * uncompressed point. Fortunately OpenSSL handles the gory details for us.
- */
int
buffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
const EC_POINT *point)
{
- u_char *buf = NULL;
- size_t len;
- BN_CTX *bnctx;
- int ret = -1;
+ int ret;
- /* Determine length */
- if ((bnctx = BN_CTX_new()) == NULL)
- fatal("%s: BN_CTX_new failed", __func__);
- len = EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
- NULL, 0, bnctx);
- if (len > BUFFER_MAX_ECPOINT_LEN) {
- error("%s: giant EC point: len = %lu (max %u)",
- __func__, (u_long)len, BUFFER_MAX_ECPOINT_LEN);
- goto out;
- }
- /* Convert */
- buf = xmalloc(len);
- if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
- buf, len, bnctx) != len) {
- error("%s: EC_POINT_point2oct length mismatch", __func__);
- goto out;
- }
- /* Append */
- buffer_put_string(buffer, buf, len);
- ret = 0;
- out:
- if (buf != NULL) {
- explicit_bzero(buf, len);
- free(buf);
+ if ((ret = sshbuf_put_ec(buffer, point, curve)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
+ return -1;
}
- BN_CTX_free(bnctx);
- return ret;
+ return 0;
}
void
@@ -96,43 +53,13 @@ int
buffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
EC_POINT *point)
{
- u_char *buf;
- u_int len;
- BN_CTX *bnctx;
- int ret = -1;
+ int ret;
- if ((buf = buffer_get_string_ret(buffer, &len)) == NULL) {
- error("%s: invalid point", __func__);
+ if ((ret = sshbuf_get_ec(buffer, point, curve)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
return -1;
}
- if ((bnctx = BN_CTX_new()) == NULL)
- fatal("%s: BN_CTX_new failed", __func__);
- if (len > BUFFER_MAX_ECPOINT_LEN) {
- error("%s: EC_POINT too long: %u > max %u", __func__,
- len, BUFFER_MAX_ECPOINT_LEN);
- goto out;
- }
- if (len == 0) {
- error("%s: EC_POINT buffer is empty", __func__);
- goto out;
- }
- if (buf[0] != POINT_CONVERSION_UNCOMPRESSED) {
- error("%s: EC_POINT is in an incorrect form: "
- "0x%02x (want 0x%02x)", __func__, buf[0],
- POINT_CONVERSION_UNCOMPRESSED);
- goto out;
- }
- if (EC_POINT_oct2point(curve, point, buf, len, bnctx) != 1) {
- error("buffer_get_bignum2_ret: BN_bin2bn failed");
- goto out;
- }
- /* EC_POINT_oct2point verifies that the point is on the curve for us */
- ret = 0;
- out:
- BN_CTX_free(bnctx);
- explicit_bzero(buf, len);
- free(buf);
- return ret;
+ return 0;
}
void
@@ -144,3 +71,4 @@ buffer_get_ecpoint(Buffer *buffer, const EC_GROUP *curve,
}
#endif /* OPENSSL_HAS_ECC */
+
diff --git a/buffer.c b/buffer.c
index d240f6753221..c5f708ab2e10 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1,253 +1,118 @@
-/* $OpenBSD: buffer.c,v 1.35 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: buffer.c,v 1.36 2014/04/30 05:29:56 djm Exp $ */
+
/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * Functions for manipulating fifo buffers (that can grow if needed).
+ * Copyright (c) 2012 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.
*
- * 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".
+ * 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"
+/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
-#include <sys/param.h>
+#include "includes.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
+#include <sys/types.h>
-#include "xmalloc.h"
#include "buffer.h"
#include "log.h"
-
-#define BUFFER_MAX_CHUNK 0x100000
-#define BUFFER_MAX_LEN 0xa00000
-#define BUFFER_ALLOCSZ 0x008000
-
-/* Initializes the buffer structure. */
-
-void
-buffer_init(Buffer *buffer)
-{
- const u_int len = 4096;
-
- buffer->alloc = 0;
- buffer->buf = xmalloc(len);
- buffer->alloc = len;
- buffer->offset = 0;
- buffer->end = 0;
-}
-
-/* Frees any memory used for the buffer. */
-
-void
-buffer_free(Buffer *buffer)
-{
- if (buffer->alloc > 0) {
- explicit_bzero(buffer->buf, buffer->alloc);
- buffer->alloc = 0;
- free(buffer->buf);
- }
-}
-
-/*
- * Clears any data from the buffer, making it empty. This does not actually
- * zero the memory.
- */
-
-void
-buffer_clear(Buffer *buffer)
-{
- buffer->offset = 0;
- buffer->end = 0;
-}
-
-/* Appends data to the buffer, expanding it if necessary. */
+#include "ssherr.h"
void
buffer_append(Buffer *buffer, const void *data, u_int len)
{
- void *p;
- p = buffer_append_space(buffer, len);
- memcpy(p, data, len);
-}
+ int ret;
-static int
-buffer_compact(Buffer *buffer)
-{
- /*
- * If the buffer is quite empty, but all data is at the end, move the
- * data to the beginning.
- */
- if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) {
- memmove(buffer->buf, buffer->buf + buffer->offset,
- buffer->end - buffer->offset);
- buffer->end -= buffer->offset;
- buffer->offset = 0;
- return (1);
- }
- return (0);
+ if ((ret = sshbuf_put(buffer, data, len)) != 0)
+ fatal("%s: %s", __func__, ssh_err(ret));
}
-/*
- * Appends space to the buffer, expanding the buffer if necessary. This does
- * not actually copy the data into the buffer, but instead returns a pointer
- * to the allocated region.
- */
-
void *
buffer_append_space(Buffer *buffer, u_int len)
{
- u_int newlen;
- void *p;
+ int ret;
+ u_char *p;
- if (len > BUFFER_MAX_CHUNK)
- fatal("buffer_append_space: len %u not supported", len);
-
- /* If the buffer is empty, start using it from the beginning. */
- if (buffer->offset == buffer->end) {
- buffer->offset = 0;
- buffer->end = 0;
- }
-restart:
- /* If there is enough space to store all data, store it now. */
- if (buffer->end + len < buffer->alloc) {
- p = buffer->buf + buffer->end;
- buffer->end += len;
- return p;
- }
-
- /* Compact data back to the start of the buffer if necessary */
- if (buffer_compact(buffer))
- goto restart;
-
- /* Increase the size of the buffer and retry. */
- newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ);
- if (newlen > BUFFER_MAX_LEN)
- fatal("buffer_append_space: alloc %u not supported",
- newlen);
- buffer->buf = xrealloc(buffer->buf, 1, newlen);
- buffer->alloc = newlen;
- goto restart;
- /* NOTREACHED */
+ if ((ret = sshbuf_reserve(buffer, len, &p)) != 0)
+ fatal("%s: %s", __func__, ssh_err(ret));
+ return p;
}
-/*
- * Check whether an allocation of 'len' will fit in the buffer
- * This must follow the same math as buffer_append_space
- */
int
buffer_check_alloc(Buffer *buffer, u_int len)
{
- if (buffer->offset == buffer->end) {
- buffer->offset = 0;
- buffer->end = 0;
- }
- restart:
- if (buffer->end + len < buffer->alloc)
- return (1);
- if (buffer_compact(buffer))
- goto restart;
- if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN)
- return (1);
- return (0);
-}
-
-/* Returns the number of bytes of data in the buffer. */
+ int ret = sshbuf_check_reserve(buffer, len);
-u_int
-buffer_len(const Buffer *buffer)
-{
- return buffer->end - buffer->offset;
+ if (ret == 0)
+ return 1;
+ if (ret == SSH_ERR_NO_BUFFER_SPACE)
+ return 0;
+ fatal("%s: %s", __func__, ssh_err(ret));
}
-/* Gets data from the beginning of the buffer. */
-
int
buffer_get_ret(Buffer *buffer, void *buf, u_int len)
{
- if (len > buffer->end - buffer->offset) {
- error("buffer_get_ret: trying to get more bytes %d than in buffer %d",
- len, buffer->end - buffer->offset);
- return (-1);
+ int ret;
+
+ if ((ret = sshbuf_get(buffer, buf, len)) != 0) {
+ error("%s: %s", __func__, ssh_err(ret));
+ return -1;
}
- memcpy(buf, buffer->buf + buffer->offset, len);
- buffer->offset += len;
- return (0);
+ return 0;
}
void
buffer_get(Buffer *buffer, void *buf, u_int len)
{
if (buffer_get_ret(buffer, buf, len) == -1)
- fatal("buffer_get: buffer error");
+ fatal("%s: buffer error", __func__);
}
-/* Consumes the given number of bytes from the beginning of the buffer. */
-
int
buffer_consume_ret(Buffer *buffer, u_int bytes)
{
- if (bytes > buffer->end - buffer->offset) {
- error("buffer_consume_ret: trying to get more bytes than in buffer");
- return (-1);
- }
- buffer->offset += bytes;
- return (0);
+ int ret = sshbuf_consume(buffer, bytes);
+
+ if (ret == 0)
+ return 0;
+ if (ret == SSH_ERR_MESSAGE_INCOMPLETE)
+ return -1;
+ fatal("%s: %s", __func__, ssh_err(ret));
}
void
buffer_consume(Buffer *buffer, u_int bytes)
{
if (buffer_consume_ret(buffer, bytes) == -1)
- fatal("buffer_consume: buffer error");
+ fatal("%s: buffer error", __func__);
}
-/* Consumes the given number of bytes from the end of the buffer. */
-
int
buffer_consume_end_ret(Buffer *buffer, u_int bytes)
{
- if (bytes > buffer->end - buffer->offset)
- return (-1);
- buffer->end -= bytes;
- return (0);
+ int ret = sshbuf_consume_end(buffer, bytes);
+
+ if (ret == 0)
+ return 0;
+ if (ret == SSH_ERR_MESSAGE_INCOMPLETE)
+ return -1;
+ fatal("%s: %s", __func__, ssh_err(ret));
}
void
buffer_consume_end(Buffer *buffer, u_int bytes)
{
if (buffer_consume_end_ret(buffer, bytes) == -1)
- fatal("buffer_consume_end: trying to get more bytes than in buffer");
-}
-
-/* Returns a pointer to the first used byte in the buffer. */
-
-void *
-buffer_ptr(const Buffer *buffer)
-{
- return buffer->buf + buffer->offset;
+ fatal("%s: buffer error", __func__);
}
-/* Dumps the contents of the buffer to stderr. */
-void
-buffer_dump(const Buffer *buffer)
-{
- u_int i;
- u_char *ucp = buffer->buf;
-
- for (i = buffer->offset; i < buffer->end; i++) {
- fprintf(stderr, "%02x", ucp[i]);
- if ((i-buffer->offset)%16==15)
- fprintf(stderr, "\r\n");
- else if ((i-buffer->offset)%2==1)
- fprintf(stderr, " ");
- }
- fprintf(stderr, "\r\n");
-}
diff --git a/buffer.h b/buffer.h
index 7df8a38fa18d..9d853edf2da2 100644
--- a/buffer.h
+++ b/buffer.h
@@ -1,57 +1,58 @@
-/* $OpenBSD: buffer.h,v 1.23 2014/01/12 08:13:13 djm Exp $ */
+/* $OpenBSD: buffer.h,v 1.25 2014/04/30 05:29:56 djm Exp $ */
/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- * All rights reserved
- * Code for manipulating FIFO buffers.
+ * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
*
- * 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".
+ * 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.
*/
+/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
+
#ifndef BUFFER_H
#define BUFFER_H
-typedef struct {
- u_char *buf; /* Buffer for data. */
- u_int alloc; /* Number of bytes allocated for data. */
- u_int offset; /* Offset of first byte containing data. */
- u_int end; /* Offset of last byte containing data. */
-} Buffer;
+#include "sshbuf.h"
+
+typedef struct sshbuf Buffer;
-void buffer_init(Buffer *);
-void buffer_clear(Buffer *);
-void buffer_free(Buffer *);
+#define buffer_init(b) sshbuf_init(b)
+#define buffer_clear(b) sshbuf_reset(b)
+#define buffer_free(b) sshbuf_free(b)
+#define buffer_dump(b) sshbuf_dump(b, stderr)
-u_int buffer_len(const Buffer *);
-void *buffer_ptr(const Buffer *);
+/* XXX cast is safe: sshbuf never stores more than len 2^31 */
+#define buffer_len(b) ((u_int) sshbuf_len(b))
+#define buffer_ptr(b) sshbuf_mutable_ptr(b)
void buffer_append(Buffer *, const void *, u_int);
void *buffer_append_space(Buffer *, u_int);
-
int buffer_check_alloc(Buffer *, u_int);
-
void buffer_get(Buffer *, void *, u_int);
void buffer_consume(Buffer *, u_int);
void buffer_consume_end(Buffer *, u_int);
-void buffer_dump(const Buffer *);
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/bn.h>
-
void buffer_put_bignum(Buffer *, const BIGNUM *);
void buffer_put_bignum2(Buffer *, const BIGNUM *);
void buffer_get_bignum(Buffer *, BIGNUM *);
void buffer_get_bignum2(Buffer *, BIGNUM *);
+void buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int);
u_short buffer_get_short(Buffer *);
void buffer_put_short(Buffer *, u_short);
@@ -66,13 +67,12 @@ int buffer_get_char(Buffer *);
void buffer_put_char(Buffer *, int);
void *buffer_get_string(Buffer *, u_int *);
-void *buffer_get_string_ptr(Buffer *, u_int *);
+const void *buffer_get_string_ptr(Buffer *, u_int *);
void buffer_put_string(Buffer *, const void *, u_int);
char *buffer_get_cstring(Buffer *, u_int *);
void buffer_put_cstring(Buffer *, const char *);
-#define buffer_skip_string(b) \
- do { u_int l = buffer_get_int(b); buffer_consume(b, l); } while (0)
+#define buffer_skip_string(b) (void)buffer_get_string_ptr(b, NULL);
int buffer_put_bignum_ret(Buffer *, const BIGNUM *);
int buffer_get_bignum_ret(Buffer *, BIGNUM *);
@@ -83,20 +83,16 @@ int buffer_get_int_ret(u_int *, Buffer *);
int buffer_get_int64_ret(u_int64_t *, Buffer *);
void *buffer_get_string_ret(Buffer *, u_int *);
char *buffer_get_cstring_ret(Buffer *, u_int *);
-void *buffer_get_string_ptr_ret(Buffer *, u_int *);
-int buffer_get_char_ret(u_char *, Buffer *);
-
-void *buffer_get_bignum2_as_string_ret(Buffer *, u_int *);
-void *buffer_get_bignum2_as_string(Buffer *, u_int *);
-void buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int);
+const void *buffer_get_string_ptr_ret(Buffer *, u_int *);
+int buffer_get_char_ret(char *, Buffer *);
#ifdef OPENSSL_HAS_ECC
#include <openssl/ec.h>
-
int buffer_put_ecpoint_ret(Buffer *, const EC_GROUP *, const EC_POINT *);
void buffer_put_ecpoint(Buffer *, const EC_GROUP *, const EC_POINT *);
int buffer_get_ecpoint_ret(Buffer *, const EC_GROUP *, EC_POINT *);
void buffer_get_ecpoint(Buffer *, const EC_GROUP *, EC_POINT *);
#endif
-#endif /* BUFFER_H */
+#endif /* BUFFER_H */
+
diff --git a/canohost.c b/canohost.c
index a61a8c94d429..a3e3bbff80b3 100644
--- a/canohost.c
+++ b/canohost.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: canohost.c,v 1.70 2014/01/19 04:17:29 dtucker Exp $ */
+/* $OpenBSD: canohost.c,v 1.71 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -16,6 +16,7 @@
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -262,6 +263,11 @@ get_socket_address(int sock, int remote, int flags)
if (addr.ss_family == AF_INET6)
addrlen = sizeof(struct sockaddr_in6);
+ if (addr.ss_family == 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. */
@@ -384,6 +390,10 @@ 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)
+ return 0;
+
/* Return port number. */
if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
strport, sizeof(strport), NI_NUMERICSERV)) != 0)
diff --git a/chacha.h b/chacha.h
index 4ef42cc70cf1..40eaf2d90093 100644
--- a/chacha.h
+++ b/chacha.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: chacha.h,v 1.1 2013/11/21 00:45:44 djm Exp $ */
+/* $OpenBSD: chacha.h,v 1.3 2014/05/02 03:27:54 djm Exp $ */
/*
chacha-merged.c version 20080118
diff --git a/channels.c b/channels.c
index 9efe89c9cdfc..d67fdf48b1fa 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.331 2014/02/26 20:29:29 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.336 2014/07/15 15:54:14 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/stat.h>
#include <sys/ioctl.h>
#include <sys/un.h>
#include <sys/socket.h>
@@ -107,10 +108,15 @@ static int channel_max_fd = 0;
* a corrupt remote server from accessing arbitrary TCP/IP ports on our local
* network (which might be behind a firewall).
*/
+/* XXX: streamlocal wants a path instead of host:port */
+/* Overload host_to_connect; we could just make this match Forward */
+/* XXX - can we use listen_host instead of listen_path? */
typedef struct {
char *host_to_connect; /* Connect to 'host'. */
- u_short port_to_connect; /* Connect to 'port'. */
- u_short listen_port; /* Remote side should listen port number. */
+ int port_to_connect; /* Connect to 'port'. */
+ char *listen_host; /* Remote side should listen address. */
+ char *listen_path; /* Remote side should listen path. */
+ int listen_port; /* Remote side should listen port. */
} ForwardPermission;
/* List of all permitted host/port pairs to connect by the user. */
@@ -473,6 +479,8 @@ channel_stop_listening(void)
case SSH_CHANNEL_PORT_LISTENER:
case SSH_CHANNEL_RPORT_LISTENER:
case SSH_CHANNEL_X11_LISTENER:
+ case SSH_CHANNEL_UNIX_LISTENER:
+ case SSH_CHANNEL_RUNIX_LISTENER:
channel_close_fd(&c->sock);
channel_free(c);
break;
@@ -535,6 +543,8 @@ channel_still_open(void)
case SSH_CHANNEL_CONNECTING:
case SSH_CHANNEL_ZOMBIE:
case SSH_CHANNEL_ABANDONED:
+ case SSH_CHANNEL_UNIX_LISTENER:
+ case SSH_CHANNEL_RUNIX_LISTENER:
continue;
case SSH_CHANNEL_LARVAL:
if (!compat20)
@@ -581,6 +591,8 @@ channel_find_open(void)
case SSH_CHANNEL_CONNECTING:
case SSH_CHANNEL_ZOMBIE:
case SSH_CHANNEL_ABANDONED:
+ case SSH_CHANNEL_UNIX_LISTENER:
+ case SSH_CHANNEL_RUNIX_LISTENER:
continue;
case SSH_CHANNEL_LARVAL:
case SSH_CHANNEL_AUTH_SOCKET:
@@ -631,6 +643,8 @@ channel_open_message(void)
case SSH_CHANNEL_ABANDONED:
case SSH_CHANNEL_MUX_CLIENT:
case SSH_CHANNEL_MUX_LISTENER:
+ case SSH_CHANNEL_UNIX_LISTENER:
+ case SSH_CHANNEL_RUNIX_LISTENER:
continue;
case SSH_CHANNEL_LARVAL:
case SSH_CHANNEL_OPENING:
@@ -1386,7 +1400,6 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
static void
port_open_helper(Channel *c, char *rtype)
{
- int direct;
char buf[1024];
char *local_ipaddr = get_local_ipaddr(c->sock);
int local_port = c->sock == -1 ? 65536 : get_sock_port(c->sock, 1);
@@ -1400,8 +1413,6 @@ port_open_helper(Channel *c, char *rtype)
remote_port = 65535;
}
- direct = (strcmp(rtype, "direct-tcpip") == 0);
-
snprintf(buf, sizeof buf,
"%s: listening port %d for %.100s port %d, "
"connect from %.200s port %d to %.100s port %d",
@@ -1417,18 +1428,29 @@ port_open_helper(Channel *c, char *rtype)
packet_put_int(c->self);
packet_put_int(c->local_window_max);
packet_put_int(c->local_maxpacket);
- if (direct) {
+ if (strcmp(rtype, "direct-tcpip") == 0) {
/* target host, port */
packet_put_cstring(c->path);
packet_put_int(c->host_port);
+ } else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) {
+ /* target path */
+ packet_put_cstring(c->path);
+ } else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
+ /* listen path */
+ packet_put_cstring(c->path);
} else {
/* listen address, port */
packet_put_cstring(c->path);
packet_put_int(local_port);
}
- /* originator host and port */
- packet_put_cstring(remote_ipaddr);
- packet_put_int((u_int)remote_port);
+ if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
+ /* reserved for future owner/mode info */
+ packet_put_cstring("");
+ } else {
+ /* originator host and port */
+ packet_put_cstring(remote_ipaddr);
+ packet_put_int((u_int)remote_port);
+ }
packet_send();
} else {
packet_start(SSH_MSG_PORT_OPEN);
@@ -1478,14 +1500,18 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
nextstate = SSH_CHANNEL_OPENING;
rtype = "forwarded-tcpip";
+ } else if (c->type == SSH_CHANNEL_RUNIX_LISTENER) {
+ nextstate = SSH_CHANNEL_OPENING;
+ rtype = "forwarded-streamlocal@openssh.com";
+ } else if (c->host_port == PORT_STREAMLOCAL) {
+ nextstate = SSH_CHANNEL_OPENING;
+ rtype = "direct-streamlocal@openssh.com";
+ } else if (c->host_port == 0) {
+ nextstate = SSH_CHANNEL_DYNAMIC;
+ rtype = "dynamic-tcpip";
} else {
- if (c->host_port == 0) {
- nextstate = SSH_CHANNEL_DYNAMIC;
- rtype = "dynamic-tcpip";
- } else {
- nextstate = SSH_CHANNEL_OPENING;
- rtype = "direct-tcpip";
- }
+ nextstate = SSH_CHANNEL_OPENING;
+ rtype = "direct-tcpip";
}
addrlen = sizeof(addr);
@@ -1498,7 +1524,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
c->notbefore = monotime() + 1;
return;
}
- set_nodelay(newsock);
+ if (c->host_port != PORT_STREAMLOCAL)
+ set_nodelay(newsock);
nc = channel_new(rtype, nextstate, newsock, newsock, -1,
c->local_window_max, c->local_maxpacket, 0, rtype, 1);
nc->listening_port = c->listening_port;
@@ -1987,6 +2014,8 @@ channel_handler_init_20(void)
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener;
+ channel_pre[SSH_CHANNEL_UNIX_LISTENER] = &channel_pre_listener;
+ channel_pre[SSH_CHANNEL_RUNIX_LISTENER] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
@@ -1997,6 +2026,8 @@ channel_handler_init_20(void)
channel_post[SSH_CHANNEL_OPEN] = &channel_post_open;
channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener;
+ channel_post[SSH_CHANNEL_UNIX_LISTENER] = &channel_post_port_listener;
+ channel_post[SSH_CHANNEL_RUNIX_LISTENER] = &channel_post_port_listener;
channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
@@ -2315,7 +2346,7 @@ void
channel_input_data(int type, u_int32_t seq, void *ctxt)
{
int id;
- char *data;
+ const u_char *data;
u_int data_len, win_len;
Channel *c;
@@ -2637,7 +2668,7 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt)
originator_string = xstrdup("unknown (remote did not supply name)");
}
packet_check_eom();
- c = channel_connect_to(host, host_port,
+ c = channel_connect_to_port(host, host_port,
"connected socket", originator_string);
free(originator_string);
free(host);
@@ -2700,23 +2731,24 @@ channel_set_af(int af)
* "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
* "" (empty string), "*" -> wildcard v4/v6
* "localhost" -> loopback v4/v6
+ * "127.0.0.1" / "::1" -> accepted even if gateway_ports isn't set
*/
static const char *
channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
- int is_client, int gateway_ports)
+ int is_client, struct ForwardOptions *fwd_opts)
{
const char *addr = NULL;
int wildcard = 0;
if (listen_addr == NULL) {
/* No address specified: default to gateway_ports setting */
- if (gateway_ports)
+ if (fwd_opts->gateway_ports)
wildcard = 1;
- } else if (gateway_ports || is_client) {
+ } else if (fwd_opts->gateway_ports || is_client) {
if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
*listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
- (!is_client && gateway_ports == 1)) {
+ (!is_client && fwd_opts->gateway_ports == 1)) {
wildcard = 1;
/*
* Notify client if they requested a specific listen
@@ -2729,9 +2761,20 @@ channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
"\"%s\" overridden by server "
"GatewayPorts", listen_addr);
}
- }
- else if (strcmp(listen_addr, "localhost") != 0)
+ } else if (strcmp(listen_addr, "localhost") != 0 ||
+ strcmp(listen_addr, "127.0.0.1") == 0 ||
+ strcmp(listen_addr, "::1") == 0) {
+ /* Accept localhost address when GatewayPorts=yes */
addr = listen_addr;
+ }
+ } else if (strcmp(listen_addr, "127.0.0.1") == 0 ||
+ strcmp(listen_addr, "::1") == 0) {
+ /*
+ * If a specific IPv4/IPv6 localhost address has been
+ * requested then accept it even if gateway_ports is in
+ * effect. This allows the client to prefer IPv4 or IPv6.
+ */
+ addr = listen_addr;
}
if (wildcardp != NULL)
*wildcardp = wildcard;
@@ -2739,9 +2782,8 @@ channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
}
static int
-channel_setup_fwd_listener(int type, const char *listen_addr,
- u_short listen_port, int *allocated_listen_port,
- const char *host_to_connect, u_short port_to_connect, int gateway_ports)
+channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
+ int *allocated_listen_port, struct ForwardOptions *fwd_opts)
{
Channel *c;
int sock, r, success = 0, wildcard = 0, is_client;
@@ -2751,7 +2793,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
in_port_t *lport_p;
host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
- listen_addr : host_to_connect;
+ fwd->listen_host : fwd->connect_host;
is_client = (type == SSH_CHANNEL_PORT_LISTENER);
if (host == NULL) {
@@ -2764,9 +2806,9 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
}
/* Determine the bind address, cf. channel_fwd_bind_addr() comment */
- addr = channel_fwd_bind_addr(listen_addr, &wildcard,
- is_client, gateway_ports);
- debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s",
+ addr = channel_fwd_bind_addr(fwd->listen_host, &wildcard,
+ is_client, fwd_opts);
+ debug3("%s: type %d wildcard %d addr %s", __func__,
type, wildcard, (addr == NULL) ? "NULL" : addr);
/*
@@ -2777,15 +2819,14 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
hints.ai_family = IPv4or6;
hints.ai_flags = wildcard ? AI_PASSIVE : 0;
hints.ai_socktype = SOCK_STREAM;
- snprintf(strport, sizeof strport, "%d", listen_port);
+ snprintf(strport, sizeof strport, "%d", fwd->listen_port);
if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
if (addr == NULL) {
/* This really shouldn't happen */
packet_disconnect("getaddrinfo: fatal error: %s",
ssh_gai_strerror(r));
} else {
- error("channel_setup_fwd_listener: "
- "getaddrinfo(%.64s): %s", addr,
+ error("%s: getaddrinfo(%.64s): %s", __func__, addr,
ssh_gai_strerror(r));
}
return 0;
@@ -2809,13 +2850,13 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
* If allocating a port for -R forwards, then use the
* same port for all address families.
*/
- if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
+ if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
allocated_listen_port != NULL && *allocated_listen_port > 0)
*lport_p = htons(*allocated_listen_port);
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
- error("channel_setup_fwd_listener: getnameinfo failed");
+ error("%s: getnameinfo failed", __func__);
continue;
}
/* Create a port to listen for the host. */
@@ -2852,10 +2893,10 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
}
/*
- * listen_port == 0 requests a dynamically allocated port -
+ * fwd->listen_port == 0 requests a dynamically allocated port -
* record what we got.
*/
- if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
+ if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
allocated_listen_port != NULL &&
*allocated_listen_port == 0) {
*allocated_listen_port = get_sock_port(sock, 1);
@@ -2868,24 +2909,98 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
0, "port listener", 1);
c->path = xstrdup(host);
- c->host_port = port_to_connect;
+ c->host_port = fwd->connect_port;
c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
- if (listen_port == 0 && allocated_listen_port != NULL &&
+ if (fwd->listen_port == 0 && allocated_listen_port != NULL &&
!(datafellows & SSH_BUG_DYNAMIC_RPORT))
c->listening_port = *allocated_listen_port;
else
- c->listening_port = listen_port;
+ c->listening_port = fwd->listen_port;
success = 1;
}
if (success == 0)
- error("channel_setup_fwd_listener: cannot listen to port: %d",
- listen_port);
+ error("%s: cannot listen to port: %d", __func__,
+ fwd->listen_port);
freeaddrinfo(aitop);
return success;
}
-int
-channel_cancel_rport_listener(const char *host, u_short port)
+static int
+channel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd,
+ struct ForwardOptions *fwd_opts)
+{
+ struct sockaddr_un sunaddr;
+ const char *path;
+ Channel *c;
+ int port, sock;
+ mode_t omask;
+
+ switch (type) {
+ case SSH_CHANNEL_UNIX_LISTENER:
+ if (fwd->connect_path != NULL) {
+ if (strlen(fwd->connect_path) > sizeof(sunaddr.sun_path)) {
+ error("Local connecting path too long: %s",
+ fwd->connect_path);
+ return 0;
+ }
+ path = fwd->connect_path;
+ port = PORT_STREAMLOCAL;
+ } else {
+ if (fwd->connect_host == NULL) {
+ error("No forward host name.");
+ return 0;
+ }
+ if (strlen(fwd->connect_host) >= NI_MAXHOST) {
+ error("Forward host name too long.");
+ return 0;
+ }
+ path = fwd->connect_host;
+ port = fwd->connect_port;
+ }
+ break;
+ case SSH_CHANNEL_RUNIX_LISTENER:
+ path = fwd->listen_path;
+ port = PORT_STREAMLOCAL;
+ break;
+ default:
+ error("%s: unexpected channel type %d", __func__, type);
+ return 0;
+ }
+
+ if (fwd->listen_path == NULL) {
+ error("No forward path name.");
+ return 0;
+ }
+ if (strlen(fwd->listen_path) > sizeof(sunaddr.sun_path)) {
+ error("Local listening path too long: %s", fwd->listen_path);
+ return 0;
+ }
+
+ debug3("%s: type %d path %s", __func__, type, fwd->listen_path);
+
+ /* Start a Unix domain listener. */
+ omask = umask(fwd_opts->streamlocal_bind_mask);
+ sock = unix_listener(fwd->listen_path, SSH_LISTEN_BACKLOG,
+ fwd_opts->streamlocal_bind_unlink);
+ umask(omask);
+ if (sock < 0)
+ return 0;
+
+ debug("Local forwarding listening on path %s.", fwd->listen_path);
+
+ /* Allocate a channel number for the socket. */
+ c = channel_new("unix listener", type, sock, sock, -1,
+ CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
+ 0, "unix listener", 1);
+ c->path = xstrdup(path);
+ c->host_port = port;
+ c->listening_port = PORT_STREAMLOCAL;
+ c->listening_addr = xstrdup(fwd->listen_path);
+ return 1;
+}
+
+static int
+channel_cancel_rport_listener_tcpip(const char *host, u_short port)
{
u_int i;
int found = 0;
@@ -2904,13 +3019,44 @@ channel_cancel_rport_listener(const char *host, u_short port)
return (found);
}
+static int
+channel_cancel_rport_listener_streamlocal(const char *path)
+{
+ u_int i;
+ int found = 0;
+
+ for (i = 0; i < channels_alloc; i++) {
+ Channel *c = channels[i];
+ if (c == NULL || c->type != SSH_CHANNEL_RUNIX_LISTENER)
+ continue;
+ if (c->path == NULL)
+ continue;
+ if (strcmp(c->path, path) == 0) {
+ debug2("%s: close channel %d", __func__, i);
+ channel_free(c);
+ found = 1;
+ }
+ }
+
+ return (found);
+}
+
int
-channel_cancel_lport_listener(const char *lhost, u_short lport,
- int cport, int gateway_ports)
+channel_cancel_rport_listener(struct Forward *fwd)
+{
+ if (fwd->listen_path != NULL)
+ return channel_cancel_rport_listener_streamlocal(fwd->listen_path);
+ else
+ return channel_cancel_rport_listener_tcpip(fwd->listen_host, fwd->listen_port);
+}
+
+static int
+channel_cancel_lport_listener_tcpip(const char *lhost, u_short lport,
+ int cport, struct ForwardOptions *fwd_opts)
{
u_int i;
int found = 0;
- const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, gateway_ports);
+ const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, fwd_opts);
for (i = 0; i < channels_alloc; i++) {
Channel *c = channels[i];
@@ -2939,24 +3085,68 @@ channel_cancel_lport_listener(const char *lhost, u_short lport,
return (found);
}
+static int
+channel_cancel_lport_listener_streamlocal(const char *path)
+{
+ u_int i;
+ int found = 0;
+
+ if (path == NULL) {
+ error("%s: no path specified.", __func__);
+ return 0;
+ }
+
+ for (i = 0; i < channels_alloc; i++) {
+ Channel *c = channels[i];
+ if (c == NULL || c->type != SSH_CHANNEL_UNIX_LISTENER)
+ continue;
+ if (c->listening_addr == NULL)
+ continue;
+ if (strcmp(c->listening_addr, path) == 0) {
+ debug2("%s: close channel %d", __func__, i);
+ channel_free(c);
+ found = 1;
+ }
+ }
+
+ return (found);
+}
+
+int
+channel_cancel_lport_listener(struct Forward *fwd, int cport, struct ForwardOptions *fwd_opts)
+{
+ if (fwd->listen_path != NULL)
+ return channel_cancel_lport_listener_streamlocal(fwd->listen_path);
+ else
+ return channel_cancel_lport_listener_tcpip(fwd->listen_host, fwd->listen_port, cport, fwd_opts);
+}
+
/* protocol local port fwd, used by ssh (and sshd in v1) */
int
-channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port,
- const char *host_to_connect, u_short port_to_connect, int gateway_ports)
+channel_setup_local_fwd_listener(struct Forward *fwd, struct ForwardOptions *fwd_opts)
{
- return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER,
- listen_host, listen_port, NULL, host_to_connect, port_to_connect,
- gateway_ports);
+ if (fwd->listen_path != NULL) {
+ return channel_setup_fwd_listener_streamlocal(
+ SSH_CHANNEL_UNIX_LISTENER, fwd, fwd_opts);
+ } else {
+ return channel_setup_fwd_listener_tcpip(SSH_CHANNEL_PORT_LISTENER,
+ fwd, NULL, fwd_opts);
+ }
}
/* protocol v2 remote port fwd, used by sshd */
int
-channel_setup_remote_fwd_listener(const char *listen_address,
- u_short listen_port, int *allocated_listen_port, int gateway_ports)
+channel_setup_remote_fwd_listener(struct Forward *fwd,
+ int *allocated_listen_port, struct ForwardOptions *fwd_opts)
{
- return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER,
- listen_address, listen_port, allocated_listen_port,
- NULL, 0, gateway_ports);
+ if (fwd->listen_path != NULL) {
+ return channel_setup_fwd_listener_streamlocal(
+ SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts);
+ } else {
+ return channel_setup_fwd_listener_tcpip(
+ SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port,
+ fwd_opts);
+ }
}
/*
@@ -2987,27 +3177,32 @@ channel_rfwd_bind_host(const char *listen_host)
* channel_update_permitted_opens().
*/
int
-channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
- const char *host_to_connect, u_short port_to_connect)
+channel_request_remote_forwarding(struct Forward *fwd)
{
int type, success = 0, idx = -1;
/* Send the forward request to the remote side. */
if (compat20) {
packet_start(SSH2_MSG_GLOBAL_REQUEST);
- packet_put_cstring("tcpip-forward");
- packet_put_char(1); /* boolean: want reply */
- packet_put_cstring(channel_rfwd_bind_host(listen_host));
- packet_put_int(listen_port);
+ if (fwd->listen_path != NULL) {
+ packet_put_cstring("streamlocal-forward@openssh.com");
+ packet_put_char(1); /* boolean: want reply */
+ packet_put_cstring(fwd->listen_path);
+ } else {
+ packet_put_cstring("tcpip-forward");
+ packet_put_char(1); /* boolean: want reply */
+ packet_put_cstring(channel_rfwd_bind_host(fwd->listen_host));
+ packet_put_int(fwd->listen_port);
+ }
packet_send();
packet_write_wait();
/* Assume that server accepts the request */
success = 1;
- } else {
+ } else if (fwd->listen_path == NULL) {
packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
- packet_put_int(listen_port);
- packet_put_cstring(host_to_connect);
- packet_put_int(port_to_connect);
+ packet_put_int(fwd->listen_port);
+ packet_put_cstring(fwd->connect_host);
+ packet_put_int(fwd->connect_port);
packet_send();
packet_write_wait();
@@ -3024,25 +3219,102 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
packet_disconnect("Protocol error for port forward request:"
"received packet type %d.", type);
}
+ } else {
+ logit("Warning: Server does not support remote stream local forwarding.");
}
if (success) {
/* Record that connection to this host/port is permitted. */
permitted_opens = xrealloc(permitted_opens,
num_permitted_opens + 1, sizeof(*permitted_opens));
idx = num_permitted_opens++;
- permitted_opens[idx].host_to_connect = xstrdup(host_to_connect);
- permitted_opens[idx].port_to_connect = port_to_connect;
- permitted_opens[idx].listen_port = listen_port;
+ if (fwd->connect_path != NULL) {
+ permitted_opens[idx].host_to_connect =
+ xstrdup(fwd->connect_path);
+ permitted_opens[idx].port_to_connect =
+ PORT_STREAMLOCAL;
+ } else {
+ permitted_opens[idx].host_to_connect =
+ xstrdup(fwd->connect_host);
+ permitted_opens[idx].port_to_connect =
+ fwd->connect_port;
+ }
+ if (fwd->listen_path != NULL) {
+ permitted_opens[idx].listen_host = NULL;
+ permitted_opens[idx].listen_path =
+ xstrdup(fwd->listen_path);
+ permitted_opens[idx].listen_port = PORT_STREAMLOCAL;
+ } else {
+ permitted_opens[idx].listen_host =
+ fwd->listen_host ? xstrdup(fwd->listen_host) : NULL;
+ permitted_opens[idx].listen_path = NULL;
+ permitted_opens[idx].listen_port = fwd->listen_port;
+ }
}
return (idx);
}
+static int
+open_match(ForwardPermission *allowed_open, const char *requestedhost,
+ int requestedport)
+{
+ if (allowed_open->host_to_connect == NULL)
+ return 0;
+ if (allowed_open->port_to_connect != FWD_PERMIT_ANY_PORT &&
+ allowed_open->port_to_connect != requestedport)
+ return 0;
+ if (strcmp(allowed_open->host_to_connect, requestedhost) != 0)
+ return 0;
+ return 1;
+}
+
+/*
+ * Note that in the listen host/port case
+ * we don't support FWD_PERMIT_ANY_PORT and
+ * need to translate between the configured-host (listen_host)
+ * and what we've sent to the remote server (channel_rfwd_bind_host)
+ */
+static int
+open_listen_match_tcpip(ForwardPermission *allowed_open,
+ const char *requestedhost, u_short requestedport, int translate)
+{
+ const char *allowed_host;
+
+ if (allowed_open->host_to_connect == NULL)
+ return 0;
+ if (allowed_open->listen_port != requestedport)
+ return 0;
+ if (!translate && allowed_open->listen_host == NULL &&
+ requestedhost == NULL)
+ return 1;
+ allowed_host = translate ?
+ channel_rfwd_bind_host(allowed_open->listen_host) :
+ allowed_open->listen_host;
+ if (allowed_host == NULL ||
+ strcmp(allowed_host, requestedhost) != 0)
+ return 0;
+ return 1;
+}
+
+static int
+open_listen_match_streamlocal(ForwardPermission *allowed_open,
+ const char *requestedpath)
+{
+ if (allowed_open->host_to_connect == NULL)
+ return 0;
+ if (allowed_open->listen_port != PORT_STREAMLOCAL)
+ return 0;
+ if (allowed_open->listen_path == NULL ||
+ strcmp(allowed_open->listen_path, requestedpath) != 0)
+ return 0;
+ return 1;
+}
+
/*
* Request cancellation of remote forwarding of connection host:port from
* local side.
*/
-int
-channel_request_rforward_cancel(const char *host, u_short port)
+static int
+channel_request_rforward_cancel_tcpip(const char *host, u_short port)
{
int i;
@@ -3050,8 +3322,7 @@ channel_request_rforward_cancel(const char *host, u_short port)
return -1;
for (i = 0; i < num_permitted_opens; i++) {
- if (permitted_opens[i].host_to_connect != NULL &&
- permitted_opens[i].listen_port == port)
+ if (open_listen_match_tcpip(&permitted_opens[i], host, port, 0))
break;
}
if (i >= num_permitted_opens) {
@@ -3069,9 +3340,64 @@ channel_request_rforward_cancel(const char *host, u_short port)
permitted_opens[i].port_to_connect = 0;
free(permitted_opens[i].host_to_connect);
permitted_opens[i].host_to_connect = NULL;
+ free(permitted_opens[i].listen_host);
+ permitted_opens[i].listen_host = NULL;
+ permitted_opens[i].listen_path = NULL;
+
+ return 0;
+}
+
+/*
+ * Request cancellation of remote forwarding of Unix domain socket
+ * path from local side.
+ */
+static int
+channel_request_rforward_cancel_streamlocal(const char *path)
+{
+ int i;
+
+ if (!compat20)
+ return -1;
+
+ for (i = 0; i < num_permitted_opens; i++) {
+ if (open_listen_match_streamlocal(&permitted_opens[i], path))
+ break;
+ }
+ if (i >= num_permitted_opens) {
+ debug("%s: requested forward not found", __func__);
+ return -1;
+ }
+ packet_start(SSH2_MSG_GLOBAL_REQUEST);
+ packet_put_cstring("cancel-streamlocal-forward@openssh.com");
+ packet_put_char(0);
+ packet_put_cstring(path);
+ packet_send();
+
+ permitted_opens[i].listen_port = 0;
+ permitted_opens[i].port_to_connect = 0;
+ free(permitted_opens[i].host_to_connect);
+ permitted_opens[i].host_to_connect = NULL;
+ permitted_opens[i].listen_host = NULL;
+ free(permitted_opens[i].listen_path);
+ permitted_opens[i].listen_path = NULL;
return 0;
}
+
+/*
+ * Request cancellation of remote forwarding of a connection from local side.
+ */
+int
+channel_request_rforward_cancel(struct Forward *fwd)
+{
+ if (fwd->listen_path != NULL) {
+ return (channel_request_rforward_cancel_streamlocal(
+ fwd->listen_path));
+ } else {
+ return (channel_request_rforward_cancel_tcpip(fwd->listen_host,
+ fwd->listen_port ? fwd->listen_port : fwd->allocated_port));
+ }
+}
/*
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
@@ -3079,36 +3405,35 @@ channel_request_rforward_cancel(const char *host, u_short port)
* message if there was an error).
*/
int
-channel_input_port_forward_request(int is_root, int gateway_ports)
+channel_input_port_forward_request(int is_root, struct ForwardOptions *fwd_opts)
{
- u_short port, host_port;
int success = 0;
- char *hostname;
+ struct Forward fwd;
/* Get arguments from the packet. */
- port = packet_get_int();
- hostname = packet_get_string(NULL);
- host_port = packet_get_int();
+ memset(&fwd, 0, sizeof(fwd));
+ fwd.listen_port = packet_get_int();
+ fwd.connect_host = packet_get_string(NULL);
+ fwd.connect_port = packet_get_int();
#ifndef HAVE_CYGWIN
/*
* Check that an unprivileged user is not trying to forward a
* privileged port.
*/
- if (port < IPPORT_RESERVED && !is_root)
+ if (fwd.listen_port < IPPORT_RESERVED && !is_root)
packet_disconnect(
"Requested forwarding of port %d but user is not root.",
- port);
- if (host_port == 0)
+ fwd.listen_port);
+ if (fwd.connect_port == 0)
packet_disconnect("Dynamic forwarding denied.");
#endif
/* Initiate forwarding */
- success = channel_setup_local_fwd_listener(NULL, port, hostname,
- host_port, gateway_ports);
+ success = channel_setup_local_fwd_listener(&fwd, fwd_opts);
/* Free the argument string. */
- free(hostname);
+ free(fwd.connect_host);
return (success ? 0 : -1);
}
@@ -3134,6 +3459,9 @@ channel_add_permitted_opens(char *host, int port)
num_permitted_opens + 1, sizeof(*permitted_opens));
permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
permitted_opens[num_permitted_opens].port_to_connect = port;
+ permitted_opens[num_permitted_opens].listen_host = NULL;
+ permitted_opens[num_permitted_opens].listen_path = NULL;
+ permitted_opens[num_permitted_opens].listen_port = 0;
num_permitted_opens++;
all_opens_permitted = 0;
@@ -3165,6 +3493,10 @@ channel_update_permitted_opens(int idx, int newport)
permitted_opens[idx].port_to_connect = 0;
free(permitted_opens[idx].host_to_connect);
permitted_opens[idx].host_to_connect = NULL;
+ free(permitted_opens[idx].listen_host);
+ permitted_opens[idx].listen_host = NULL;
+ free(permitted_opens[idx].listen_path);
+ permitted_opens[idx].listen_path = NULL;
}
}
@@ -3178,6 +3510,9 @@ channel_add_adm_permitted_opens(char *host, int port)
permitted_adm_opens[num_adm_permitted_opens].host_to_connect
= xstrdup(host);
permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
+ permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL;
+ permitted_adm_opens[num_adm_permitted_opens].listen_path = NULL;
+ permitted_adm_opens[num_adm_permitted_opens].listen_port = 0;
return ++num_adm_permitted_opens;
}
@@ -3195,8 +3530,11 @@ channel_clear_permitted_opens(void)
{
int i;
- for (i = 0; i < num_permitted_opens; i++)
+ for (i = 0; i < num_permitted_opens; i++) {
free(permitted_opens[i].host_to_connect);
+ free(permitted_opens[i].listen_host);
+ free(permitted_opens[i].listen_path);
+ }
free(permitted_opens);
permitted_opens = NULL;
num_permitted_opens = 0;
@@ -3207,8 +3545,11 @@ channel_clear_adm_permitted_opens(void)
{
int i;
- for (i = 0; i < num_adm_permitted_opens; i++)
+ for (i = 0; i < num_adm_permitted_opens; i++) {
free(permitted_adm_opens[i].host_to_connect);
+ free(permitted_adm_opens[i].listen_host);
+ free(permitted_adm_opens[i].listen_path);
+ }
free(permitted_adm_opens);
permitted_adm_opens = NULL;
num_adm_permitted_opens = 0;
@@ -3246,30 +3587,32 @@ permitopen_port(const char *p)
return -1;
}
-static int
-port_match(u_short allowedport, u_short requestedport)
-{
- if (allowedport == FWD_PERMIT_ANY_PORT ||
- allowedport == requestedport)
- return 1;
- return 0;
-}
-
/* Try to start non-blocking connect to next host in cctx list */
static int
connect_next(struct channel_connect *cctx)
{
int sock, saved_errno;
- char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+ struct sockaddr_un *sunaddr;
+ char ntop[NI_MAXHOST], strport[MAX(NI_MAXSERV,sizeof(sunaddr->sun_path))];
for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
- if (cctx->ai->ai_family != AF_INET &&
- cctx->ai->ai_family != AF_INET6)
- continue;
- if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
- ntop, sizeof(ntop), strport, sizeof(strport),
- NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
- error("connect_next: getnameinfo failed");
+ switch (cctx->ai->ai_family) {
+ case AF_UNIX:
+ /* unix:pathname instead of host:port */
+ sunaddr = (struct sockaddr_un *)cctx->ai->ai_addr;
+ strlcpy(ntop, "unix", sizeof(ntop));
+ strlcpy(strport, sunaddr->sun_path, sizeof(strport));
+ break;
+ case AF_INET:
+ case AF_INET6:
+ if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
+ ntop, sizeof(ntop), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+ error("connect_next: getnameinfo failed");
+ continue;
+ }
+ break;
+ default:
continue;
}
if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
@@ -3292,10 +3635,11 @@ connect_next(struct channel_connect *cctx)
errno = saved_errno;
continue; /* fail -- try next */
}
+ if (cctx->ai->ai_family != AF_UNIX)
+ set_nodelay(sock);
debug("connect_next: host %.100s ([%.100s]:%s) "
"in progress, fd=%d", cctx->host, ntop, strport, sock);
cctx->ai = cctx->ai->ai_next;
- set_nodelay(sock);
return sock;
}
return -1;
@@ -3305,14 +3649,18 @@ static void
channel_connect_ctx_free(struct channel_connect *cctx)
{
free(cctx->host);
- if (cctx->aitop)
- freeaddrinfo(cctx->aitop);
+ if (cctx->aitop) {
+ if (cctx->aitop->ai_family == AF_UNIX)
+ free(cctx->aitop);
+ else
+ freeaddrinfo(cctx->aitop);
+ }
memset(cctx, 0, sizeof(*cctx));
}
-/* Return CONNECTING channel to remote host, port */
+/* Return CONNECTING channel to remote host:port or local socket path */
static Channel *
-connect_to(const char *host, u_short port, char *ctype, char *rname)
+connect_to(const char *name, int port, char *ctype, char *rname)
{
struct addrinfo hints;
int gaierr;
@@ -3322,23 +3670,51 @@ connect_to(const char *host, u_short port, char *ctype, char *rname)
Channel *c;
memset(&cctx, 0, sizeof(cctx));
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = IPv4or6;
- hints.ai_socktype = SOCK_STREAM;
- snprintf(strport, sizeof strport, "%d", port);
- if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) {
- error("connect_to %.100s: unknown host (%s)", host,
- ssh_gai_strerror(gaierr));
- return NULL;
+
+ if (port == PORT_STREAMLOCAL) {
+ struct sockaddr_un *sunaddr;
+ struct addrinfo *ai;
+
+ if (strlen(name) > sizeof(sunaddr->sun_path)) {
+ error("%.100s: %.100s", name, strerror(ENAMETOOLONG));
+ return (NULL);
+ }
+
+ /*
+ * Fake up a struct addrinfo for AF_UNIX connections.
+ * channel_connect_ctx_free() must check ai_family
+ * and use free() not freeaddirinfo() for AF_UNIX.
+ */
+ ai = xmalloc(sizeof(*ai) + sizeof(*sunaddr));
+ memset(ai, 0, sizeof(*ai) + sizeof(*sunaddr));
+ ai->ai_addr = (struct sockaddr *)(ai + 1);
+ ai->ai_addrlen = sizeof(*sunaddr);
+ ai->ai_family = AF_UNIX;
+ ai->ai_socktype = SOCK_STREAM;
+ ai->ai_protocol = PF_UNSPEC;
+ sunaddr = (struct sockaddr_un *)ai->ai_addr;
+ sunaddr->sun_family = AF_UNIX;
+ strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path));
+ cctx.aitop = ai;
+ } else {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = IPv4or6;
+ hints.ai_socktype = SOCK_STREAM;
+ snprintf(strport, sizeof strport, "%d", port);
+ if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop)) != 0) {
+ error("connect_to %.100s: unknown host (%s)", name,
+ ssh_gai_strerror(gaierr));
+ return NULL;
+ }
}
- cctx.host = xstrdup(host);
+ cctx.host = xstrdup(name);
cctx.port = port;
cctx.ai = cctx.aitop;
if ((sock = connect_next(&cctx)) == -1) {
error("connect to %.100s port %d failed: %s",
- host, port, strerror(errno));
+ name, port, strerror(errno));
channel_connect_ctx_free(&cctx);
return NULL;
}
@@ -3349,13 +3725,14 @@ connect_to(const char *host, u_short port, char *ctype, char *rname)
}
Channel *
-channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname)
+channel_connect_by_listen_address(const char *listen_host,
+ u_short listen_port, char *ctype, char *rname)
{
int i;
for (i = 0; i < num_permitted_opens; i++) {
- if (permitted_opens[i].host_to_connect != NULL &&
- port_match(permitted_opens[i].listen_port, listen_port)) {
+ if (open_listen_match_tcpip(&permitted_opens[i], listen_host,
+ listen_port, 1)) {
return connect_to(
permitted_opens[i].host_to_connect,
permitted_opens[i].port_to_connect, ctype, rname);
@@ -3366,29 +3743,45 @@ channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname)
return NULL;
}
+Channel *
+channel_connect_by_listen_path(const char *path, char *ctype, char *rname)
+{
+ int i;
+
+ for (i = 0; i < num_permitted_opens; i++) {
+ if (open_listen_match_streamlocal(&permitted_opens[i], path)) {
+ return connect_to(
+ permitted_opens[i].host_to_connect,
+ permitted_opens[i].port_to_connect, ctype, rname);
+ }
+ }
+ error("WARNING: Server requests forwarding for unknown path %.100s",
+ path);
+ return NULL;
+}
+
/* Check if connecting to that port is permitted and connect. */
Channel *
-channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
+channel_connect_to_port(const char *host, u_short port, char *ctype, char *rname)
{
int i, permit, permit_adm = 1;
permit = all_opens_permitted;
if (!permit) {
for (i = 0; i < num_permitted_opens; i++)
- if (permitted_opens[i].host_to_connect != NULL &&
- port_match(permitted_opens[i].port_to_connect, port) &&
- strcmp(permitted_opens[i].host_to_connect, host) == 0)
+ if (open_match(&permitted_opens[i], host, port)) {
permit = 1;
+ break;
+ }
}
if (num_adm_permitted_opens > 0) {
permit_adm = 0;
for (i = 0; i < num_adm_permitted_opens; i++)
- if (permitted_adm_opens[i].host_to_connect != NULL &&
- port_match(permitted_adm_opens[i].port_to_connect, port) &&
- strcmp(permitted_adm_opens[i].host_to_connect, host)
- == 0)
+ if (open_match(&permitted_adm_opens[i], host, port)) {
permit_adm = 1;
+ break;
+ }
}
if (!permit || !permit_adm) {
@@ -3399,6 +3792,38 @@ channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
return connect_to(host, port, ctype, rname);
}
+/* Check if connecting to that path is permitted and connect. */
+Channel *
+channel_connect_to_path(const char *path, char *ctype, char *rname)
+{
+ int i, permit, permit_adm = 1;
+
+ permit = all_opens_permitted;
+ if (!permit) {
+ for (i = 0; i < num_permitted_opens; i++)
+ if (open_match(&permitted_opens[i], path, PORT_STREAMLOCAL)) {
+ permit = 1;
+ break;
+ }
+ }
+
+ if (num_adm_permitted_opens > 0) {
+ permit_adm = 0;
+ for (i = 0; i < num_adm_permitted_opens; i++)
+ if (open_match(&permitted_adm_opens[i], path, PORT_STREAMLOCAL)) {
+ permit_adm = 1;
+ break;
+ }
+ }
+
+ if (!permit || !permit_adm) {
+ logit("Received request to connect to path %.100s, "
+ "but the request was denied.", path);
+ return NULL;
+ }
+ return connect_to(path, PORT_STREAMLOCAL, ctype, rname);
+}
+
void
channel_send_window_changes(void)
{
diff --git a/channels.h b/channels.h
index 4fab9d7c4323..a000c98e5ad6 100644
--- a/channels.h
+++ b/channels.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.113 2013/06/07 15:37:52 dtucker Exp $ */
+/* $OpenBSD: channels.h,v 1.115 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -56,7 +56,9 @@
#define SSH_CHANNEL_MUX_LISTENER 15 /* Listener for mux conn. */
#define SSH_CHANNEL_MUX_CLIENT 16 /* Conn. to mux slave */
#define SSH_CHANNEL_ABANDONED 17 /* Abandoned session, eg mux */
-#define SSH_CHANNEL_MAX_TYPE 18
+#define SSH_CHANNEL_UNIX_LISTENER 18 /* Listening on a domain socket. */
+#define SSH_CHANNEL_RUNIX_LISTENER 19 /* Listening to a R-style domain socket. */
+#define SSH_CHANNEL_MAX_TYPE 20
#define CHANNEL_CANCEL_PORT_STATIC -1
@@ -254,6 +256,8 @@ char *channel_open_message(void);
int channel_find_open(void);
/* tcp forwarding */
+struct Forward;
+struct ForwardOptions;
void channel_set_af(int af);
void channel_permit_all_opens(void);
void channel_add_permitted_opens(char *, int);
@@ -263,18 +267,19 @@ void channel_update_permitted_opens(int, int);
void channel_clear_permitted_opens(void);
void channel_clear_adm_permitted_opens(void);
void channel_print_adm_permitted_opens(void);
-int channel_input_port_forward_request(int, int);
-Channel *channel_connect_to(const char *, u_short, char *, char *);
+int channel_input_port_forward_request(int, struct ForwardOptions *);
+Channel *channel_connect_to_port(const char *, u_short, char *, char *);
+Channel *channel_connect_to_path(const char *, char *, char *);
Channel *channel_connect_stdio_fwd(const char*, u_short, int, int);
-Channel *channel_connect_by_listen_address(u_short, char *, char *);
-int channel_request_remote_forwarding(const char *, u_short,
- const char *, u_short);
-int channel_setup_local_fwd_listener(const char *, u_short,
- const char *, u_short, int);
-int channel_request_rforward_cancel(const char *host, u_short port);
-int channel_setup_remote_fwd_listener(const char *, u_short, int *, int);
-int channel_cancel_rport_listener(const char *, u_short);
-int channel_cancel_lport_listener(const char *, u_short, int, int);
+Channel *channel_connect_by_listen_address(const char *, u_short,
+ char *, char *);
+Channel *channel_connect_by_listen_path(const char *, char *, char *);
+int channel_request_remote_forwarding(struct Forward *);
+int channel_setup_local_fwd_listener(struct Forward *, struct ForwardOptions *);
+int channel_request_rforward_cancel(struct Forward *);
+int channel_setup_remote_fwd_listener(struct Forward *, int *, struct ForwardOptions *);
+int channel_cancel_rport_listener(struct Forward *);
+int channel_cancel_lport_listener(struct Forward *, int, struct ForwardOptions *);
int permitopen_port(const char *);
/* x11 forwarding */
diff --git a/cipher-3des1.c b/cipher-3des1.c
index b2823592b455..2753f9a0e147 100644
--- a/cipher-3des1.c
+++ b/cipher-3des1.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cipher-3des1.c,v 1.10 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: cipher-3des1.c,v 1.11 2014/07/02 04:59:06 djm Exp $ */
/*
* Copyright (c) 2003 Markus Friedl. All rights reserved.
*
@@ -29,13 +29,11 @@
#include <openssl/evp.h>
-#include <stdarg.h>
#include <string.h>
#include "xmalloc.h"
#include "log.h"
-
-#include "openbsd-compat/openssl-compat.h"
+#include "ssherr.h"
/*
* This is used by SSH1:
@@ -57,7 +55,7 @@ struct ssh1_3des_ctx
};
const EVP_CIPHER * evp_ssh1_3des(void);
-void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
+int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
static int
ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
@@ -67,11 +65,12 @@ ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
u_char *k1, *k2, *k3;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
- c = xcalloc(1, sizeof(*c));
+ if ((c = calloc(1, sizeof(*c))) == NULL)
+ return 0;
EVP_CIPHER_CTX_set_app_data(ctx, c);
}
if (key == NULL)
- return (1);
+ return 1;
if (enc == -1)
enc = ctx->encrypt;
k1 = k2 = k3 = (u_char *) key;
@@ -85,44 +84,29 @@ ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
EVP_CIPHER_CTX_init(&c->k1);
EVP_CIPHER_CTX_init(&c->k2);
EVP_CIPHER_CTX_init(&c->k3);
-#ifdef SSH_OLD_EVP
- EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc);
- EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc);
- EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc);
-#else
if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
explicit_bzero(c, sizeof(*c));
free(c);
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
- return (0);
+ return 0;
}
-#endif
- return (1);
+ return 1;
}
static int
-ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
- LIBCRYPTO_EVP_INL_TYPE len)
+ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, size_t len)
{
struct ssh1_3des_ctx *c;
- if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
- error("ssh1_3des_cbc: no context");
- return (0);
- }
-#ifdef SSH_OLD_EVP
- EVP_Cipher(&c->k1, dest, (u_char *)src, len);
- EVP_Cipher(&c->k2, dest, dest, len);
- EVP_Cipher(&c->k3, dest, dest, len);
-#else
+ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
+ return 0;
if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
EVP_Cipher(&c->k3, dest, dest, len) == 0)
- return (0);
-#endif
- return (1);
+ return 0;
+ return 1;
}
static int
@@ -138,29 +122,28 @@ ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
free(c);
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
}
- return (1);
+ return 1;
}
-void
+int
ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
{
struct ssh1_3des_ctx *c;
if (len != 24)
- fatal("%s: bad 3des iv length: %d", __func__, len);
+ return SSH_ERR_INVALID_ARGUMENT;
if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
- fatal("%s: no 3des context", __func__);
+ return SSH_ERR_INTERNAL_ERROR;
if (doset) {
- debug3("%s: Installed 3DES IV", __func__);
memcpy(c->k1.iv, iv, 8);
memcpy(c->k2.iv, iv + 8, 8);
memcpy(c->k3.iv, iv + 16, 8);
} else {
- debug3("%s: Copying 3DES IV", __func__);
memcpy(iv, c->k1.iv, 8);
memcpy(iv + 8, c->k2.iv, 8);
memcpy(iv + 16, c->k3.iv, 8);
}
+ return 0;
}
const EVP_CIPHER *
@@ -176,8 +159,6 @@ evp_ssh1_3des(void)
ssh1_3des.init = ssh1_3des_init;
ssh1_3des.cleanup = ssh1_3des_cleanup;
ssh1_3des.do_cipher = ssh1_3des_cbc;
-#ifndef SSH_OLD_EVP
ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
-#endif
- return (&ssh1_3des);
+ return &ssh1_3des;
}
diff --git a/cipher-aesctr.c b/cipher-aesctr.c
new file mode 100644
index 000000000000..a4cf61e41e59
--- /dev/null
+++ b/cipher-aesctr.c
@@ -0,0 +1,78 @@
+/* $OpenBSD: cipher-aesctr.c,v 1.1 2014/04/29 15:39:33 markus Exp $ */
+/*
+ * Copyright (c) 2003 Markus Friedl <markus@openbsd.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 <sys/types.h>
+#include <string.h>
+
+#include "cipher-aesctr.h"
+
+/*
+ * increment counter 'ctr',
+ * 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
+aesctr_inc(u8 *ctr, u32 len)
+{
+ ssize_t i;
+
+#ifndef CONSTANT_TIME_INCREMENT
+ for (i = len - 1; i >= 0; i--)
+ if (++ctr[i]) /* continue on overflow */
+ return;
+#else
+ u8 x, add = 1;
+
+ for (i = len - 1; i >= 0; i--) {
+ ctr[i] += add;
+ /* constant time for: x = ctr[i] ? 1 : 0 */
+ x = ctr[i];
+ x = (x | (x >> 4)) & 0xf;
+ x = (x | (x >> 2)) & 0x3;
+ x = (x | (x >> 1)) & 0x1;
+ add *= (x^1);
+ }
+#endif
+}
+
+void
+aesctr_keysetup(aesctr_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
+{
+ x->rounds = rijndaelKeySetupEnc(x->ek, k, kbits);
+}
+
+void
+aesctr_ivsetup(aesctr_ctx *x,const u8 *iv)
+{
+ memcpy(x->ctr, iv, AES_BLOCK_SIZE);
+}
+
+void
+aesctr_encrypt_bytes(aesctr_ctx *x,const u8 *m,u8 *c,u32 bytes)
+{
+ u32 n = 0;
+ u8 buf[AES_BLOCK_SIZE];
+
+ while ((bytes--) > 0) {
+ if (n == 0) {
+ rijndaelEncrypt(x->ek, x->rounds, x->ctr, buf);
+ aesctr_inc(x->ctr, AES_BLOCK_SIZE);
+ }
+ *(c++) = *(m++) ^ buf[n];
+ n = (n + 1) % AES_BLOCK_SIZE;
+ }
+}
diff --git a/cipher-aesctr.h b/cipher-aesctr.h
new file mode 100644
index 000000000000..85d55bba291e
--- /dev/null
+++ b/cipher-aesctr.h
@@ -0,0 +1,35 @@
+/* $OpenBSD: cipher-aesctr.h,v 1.1 2014/04/29 15:39:33 markus Exp $ */
+/*
+ * Copyright (c) 2014 Markus Friedl
+ *
+ * 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 OPENSSH_AESCTR_H
+#define OPENSSH_AESCTR_H
+
+#include "rijndael.h"
+
+#define AES_BLOCK_SIZE 16
+
+typedef struct aesctr_ctx {
+ int rounds; /* keylen-dependent #rounds */
+ u32 ek[4*(AES_MAXROUNDS + 1)]; /* encrypt key schedule */
+ u8 ctr[AES_BLOCK_SIZE]; /* counter */
+} aesctr_ctx;
+
+void aesctr_keysetup(aesctr_ctx *x,const u8 *k,u32 kbits,u32 ivbits);
+void aesctr_ivsetup(aesctr_ctx *x,const u8 *iv);
+void aesctr_encrypt_bytes(aesctr_ctx *x,const u8 *m,u8 *c,u32 bytes);
+
+#endif
diff --git a/cipher-chachapoly.c b/cipher-chachapoly.c
index 251b94ec8c6a..8665b41a308d 100644
--- a/cipher-chachapoly.c
+++ b/cipher-chachapoly.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $OpenBSD: cipher-chachapoly.c,v 1.4 2014/01/31 16:39:19 tedu Exp $ */
+/* $OpenBSD: cipher-chachapoly.c,v 1.6 2014/07/03 12:42:16 jsing Exp $ */
#include "includes.h"
@@ -24,16 +24,18 @@
#include <stdio.h> /* needed for misc.h */
#include "log.h"
-#include "misc.h"
+#include "sshbuf.h"
+#include "ssherr.h"
#include "cipher-chachapoly.h"
-void chachapoly_init(struct chachapoly_ctx *ctx,
+int chachapoly_init(struct chachapoly_ctx *ctx,
const u_char *key, u_int keylen)
{
if (keylen != (32 + 32)) /* 2 x 256 bit keys */
- fatal("%s: invalid keylen %u", __func__, keylen);
+ return SSH_ERR_INVALID_ARGUMENT;
chacha_keysetup(&ctx->main_ctx, key, 256);
chacha_keysetup(&ctx->header_ctx, key + 32, 256);
+ return 0;
}
/*
@@ -52,33 +54,37 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest,
u_char seqbuf[8];
const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
- int r = -1;
+ int r = SSH_ERR_INTERNAL_ERROR;
/*
* Run ChaCha20 once to generate the Poly1305 key. The IV is the
* packet sequence number.
*/
memset(poly_key, 0, sizeof(poly_key));
- put_u64(seqbuf, seqnr);
+ POKE_U64(seqbuf, seqnr);
chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
chacha_encrypt_bytes(&ctx->main_ctx,
poly_key, poly_key, sizeof(poly_key));
- /* Set Chacha's block counter to 1 */
- chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
/* If decrypting, check tag before anything else */
if (!do_encrypt) {
const u_char *tag = src + aadlen + len;
poly1305_auth(expected_tag, src, aadlen + len, poly_key);
- if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0)
+ if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
+ r = SSH_ERR_MAC_INVALID;
goto out;
+ }
}
+
/* Crypt additional data */
if (aadlen) {
chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL);
chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen);
}
+
+ /* Set Chacha's block counter to 1 */
+ chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen,
dest + aadlen, len);
@@ -88,7 +94,6 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest,
poly_key);
}
r = 0;
-
out:
explicit_bzero(expected_tag, sizeof(expected_tag));
explicit_bzero(seqbuf, sizeof(seqbuf));
@@ -104,11 +109,11 @@ chachapoly_get_length(struct chachapoly_ctx *ctx,
u_char buf[4], seqbuf[8];
if (len < 4)
- return -1; /* Insufficient length */
- put_u64(seqbuf, seqnr);
+ return SSH_ERR_MESSAGE_INCOMPLETE;
+ POKE_U64(seqbuf, seqnr);
chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL);
chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4);
- *plenp = get_u32(buf);
+ *plenp = PEEK_U32(buf);
return 0;
}
diff --git a/cipher-chachapoly.h b/cipher-chachapoly.h
index 1628693b200a..b7072be7d9d6 100644
--- a/cipher-chachapoly.h
+++ b/cipher-chachapoly.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cipher-chachapoly.h,v 1.1 2013/11/21 00:45:44 djm Exp $ */
+/* $OpenBSD: cipher-chachapoly.h,v 1.4 2014/06/24 01:13:21 djm Exp $ */
/*
* Copyright (c) Damien Miller 2013 <djm@mindrot.org>
@@ -28,7 +28,7 @@ struct chachapoly_ctx {
struct chacha_ctx main_ctx, header_ctx;
};
-void chachapoly_init(struct chachapoly_ctx *cpctx,
+int chachapoly_init(struct chachapoly_ctx *cpctx,
const u_char *key, u_int keylen)
__attribute__((__bounded__(__buffer__, 2, 3)));
int chachapoly_crypt(struct chachapoly_ctx *cpctx, u_int seqnr,
diff --git a/cipher.c b/cipher.c
index 53d9b4fb7131..638ca2d971dd 100644
--- a/cipher.c
+++ b/cipher.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cipher.c,v 1.97 2014/02/07 06:55:54 djm Exp $ */
+/* $OpenBSD: cipher.c,v 1.99 2014/06/24 01:13:21 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -43,21 +43,21 @@
#include <stdarg.h>
#include <stdio.h>
-#include "xmalloc.h"
-#include "log.h"
-#include "misc.h"
#include "cipher.h"
-#include "buffer.h"
+#include "misc.h"
+#include "sshbuf.h"
+#include "ssherr.h"
#include "digest.h"
-/* compatibility with old or broken OpenSSL versions */
#include "openbsd-compat/openssl-compat.h"
+#ifdef WITH_SSH1
extern const EVP_CIPHER *evp_ssh1_bf(void);
extern const EVP_CIPHER *evp_ssh1_3des(void);
-extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
+extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
+#endif
-struct Cipher {
+struct sshcipher {
char *name;
int number; /* for ssh1 only */
u_int block_size;
@@ -68,15 +68,23 @@ struct Cipher {
u_int flags;
#define CFLAG_CBC (1<<0)
#define CFLAG_CHACHAPOLY (1<<1)
+#define CFLAG_AESCTR (1<<2)
+#define CFLAG_NONE (1<<3)
+#ifdef WITH_OPENSSL
const EVP_CIPHER *(*evptype)(void);
+#else
+ void *ignored;
+#endif
};
-static const struct Cipher ciphers[] = {
- { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
+static const struct sshcipher ciphers[] = {
+#ifdef WITH_SSH1
{ "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
{ "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
{ "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf },
-
+#endif /* WITH_SSH1 */
+#ifdef WITH_OPENSSL
+ { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
{ "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc },
{ "blowfish-cbc",
SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_bf_cbc },
@@ -93,26 +101,33 @@ static const struct Cipher ciphers[] = {
{ "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr },
{ "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr },
{ "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr },
-#ifdef OPENSSL_HAVE_EVPGCM
+# ifdef OPENSSL_HAVE_EVPGCM
{ "aes128-gcm@openssh.com",
SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm },
{ "aes256-gcm@openssh.com",
SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm },
-#endif
+# endif /* OPENSSL_HAVE_EVPGCM */
+#else /* WITH_OPENSSL */
+ { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, CFLAG_AESCTR, NULL },
+ { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, CFLAG_AESCTR, NULL },
+ { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, CFLAG_AESCTR, NULL },
+ { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, CFLAG_NONE, NULL },
+#endif /* WITH_OPENSSL */
{ "chacha20-poly1305@openssh.com",
SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL },
+
{ NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
};
/*--*/
-/* Returns a list of supported ciphers separated by the specified char. */
+/* Returns a comma-separated list of supported ciphers. */
char *
cipher_alg_list(char sep, int auth_only)
{
- char *ret = NULL;
+ char *tmp, *ret = NULL;
size_t nlen, rlen = 0;
- const Cipher *c;
+ const struct sshcipher *c;
for (c = ciphers; c->name != NULL; c++) {
if (c->number != SSH_CIPHER_SSH2)
@@ -122,7 +137,11 @@ cipher_alg_list(char sep, int auth_only)
if (ret != NULL)
ret[rlen++] = sep;
nlen = strlen(c->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, c->name, nlen + 1);
rlen += nlen;
}
@@ -130,19 +149,19 @@ cipher_alg_list(char sep, int auth_only)
}
u_int
-cipher_blocksize(const Cipher *c)
+cipher_blocksize(const struct sshcipher *c)
{
return (c->block_size);
}
u_int
-cipher_keylen(const Cipher *c)
+cipher_keylen(const struct sshcipher *c)
{
return (c->key_len);
}
u_int
-cipher_seclen(const Cipher *c)
+cipher_seclen(const struct sshcipher *c)
{
if (strcmp("3des-cbc", c->name) == 0)
return 14;
@@ -150,13 +169,13 @@ cipher_seclen(const Cipher *c)
}
u_int
-cipher_authlen(const Cipher *c)
+cipher_authlen(const struct sshcipher *c)
{
return (c->auth_len);
}
u_int
-cipher_ivlen(const Cipher *c)
+cipher_ivlen(const struct sshcipher *c)
{
/*
* Default is cipher block size, except for chacha20+poly1305 that
@@ -167,13 +186,13 @@ cipher_ivlen(const Cipher *c)
}
u_int
-cipher_get_number(const Cipher *c)
+cipher_get_number(const struct sshcipher *c)
{
return (c->number);
}
u_int
-cipher_is_cbc(const Cipher *c)
+cipher_is_cbc(const struct sshcipher *c)
{
return (c->flags & CFLAG_CBC) != 0;
}
@@ -190,20 +209,20 @@ cipher_mask_ssh1(int client)
return mask;
}
-const Cipher *
+const struct sshcipher *
cipher_by_name(const char *name)
{
- const Cipher *c;
+ const struct sshcipher *c;
for (c = ciphers; c->name != NULL; c++)
if (strcmp(c->name, name) == 0)
return c;
return NULL;
}
-const Cipher *
+const struct sshcipher *
cipher_by_number(int id)
{
- const Cipher *c;
+ const struct sshcipher *c;
for (c = ciphers; c->name != NULL; c++)
if (c->number == id)
return c;
@@ -214,23 +233,22 @@ cipher_by_number(int id)
int
ciphers_valid(const char *names)
{
- const Cipher *c;
+ const struct sshcipher *c;
char *cipher_list, *cp;
char *p;
if (names == NULL || strcmp(names, "") == 0)
return 0;
- cipher_list = cp = xstrdup(names);
+ if ((cipher_list = cp = strdup(names)) == NULL)
+ return 0;
for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
(p = strsep(&cp, CIPHER_SEP))) {
c = cipher_by_name(p);
if (c == NULL || c->number != SSH_CIPHER_SSH2) {
- debug("bad cipher %s [%s]", p, names);
free(cipher_list);
return 0;
}
}
- debug3("ciphers ok: [%s]", names);
free(cipher_list);
return 1;
}
@@ -243,7 +261,7 @@ ciphers_valid(const char *names)
int
cipher_number(const char *name)
{
- const Cipher *c;
+ const struct sshcipher *c;
if (name == NULL)
return -1;
for (c = ciphers; c->name != NULL; c++)
@@ -255,90 +273,104 @@ cipher_number(const char *name)
char *
cipher_name(int id)
{
- const Cipher *c = cipher_by_number(id);
+ const struct sshcipher *c = cipher_by_number(id);
return (c==NULL) ? "<unknown>" : c->name;
}
-void
-cipher_init(CipherContext *cc, const Cipher *cipher,
+const char *
+cipher_warning_message(const struct sshcipher_ctx *cc)
+{
+ if (cc == NULL || cc->cipher == NULL)
+ return NULL;
+ if (cc->cipher->number == SSH_CIPHER_DES)
+ return "use of DES is strongly discouraged due to "
+ "cryptographic weaknesses";
+ return NULL;
+}
+
+int
+cipher_init(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
int do_encrypt)
{
- static int dowarn = 1;
-#ifdef SSH_OLD_EVP
- EVP_CIPHER *type;
-#else
+#ifdef WITH_OPENSSL
+ int ret = SSH_ERR_INTERNAL_ERROR;
const EVP_CIPHER *type;
int klen;
-#endif
u_char *junk, *discard;
if (cipher->number == SSH_CIPHER_DES) {
- if (dowarn) {
- error("Warning: use of DES is strongly discouraged "
- "due to cryptographic weaknesses");
- dowarn = 0;
- }
if (keylen > 8)
keylen = 8;
}
+#endif
cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
cc->encrypt = do_encrypt;
- if (keylen < cipher->key_len)
- fatal("cipher_init: key length %d is insufficient for %s.",
- keylen, cipher->name);
- if (iv != NULL && ivlen < cipher_ivlen(cipher))
- fatal("cipher_init: iv length %d is insufficient for %s.",
- ivlen, cipher->name);
- cc->cipher = cipher;
+ if (keylen < cipher->key_len ||
+ (iv != NULL && ivlen < cipher_ivlen(cipher)))
+ return SSH_ERR_INVALID_ARGUMENT;
+ cc->cipher = cipher;
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
- chachapoly_init(&cc->cp_ctx, key, keylen);
- return;
+ return chachapoly_init(&cc->cp_ctx, key, keylen);
}
- type = (*cipher->evptype)();
- EVP_CIPHER_CTX_init(&cc->evp);
-#ifdef SSH_OLD_EVP
- if (type->key_len > 0 && type->key_len != keylen) {
- debug("cipher_init: set keylen (%d -> %d)",
- type->key_len, keylen);
- type->key_len = keylen;
+#ifndef WITH_OPENSSL
+ if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
+ aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);
+ aesctr_ivsetup(&cc->ac_ctx, iv);
+ return 0;
}
- EVP_CipherInit(&cc->evp, type, (u_char *)key, (u_char *)iv,
- (do_encrypt == CIPHER_ENCRYPT));
+ if ((cc->cipher->flags & CFLAG_NONE) != 0)
+ return 0;
+ return SSH_ERR_INVALID_ARGUMENT;
#else
+ type = (*cipher->evptype)();
+ EVP_CIPHER_CTX_init(&cc->evp);
if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,
- (do_encrypt == CIPHER_ENCRYPT)) == 0)
- fatal("cipher_init: EVP_CipherInit failed for %s",
- cipher->name);
+ (do_encrypt == CIPHER_ENCRYPT)) == 0) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto bad;
+ }
if (cipher_authlen(cipher) &&
!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_IV_FIXED,
- -1, (u_char *)iv))
- fatal("cipher_init: EVP_CTRL_GCM_SET_IV_FIXED failed for %s",
- cipher->name);
+ -1, (u_char *)iv)) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto bad;
+ }
klen = EVP_CIPHER_CTX_key_length(&cc->evp);
if (klen > 0 && keylen != (u_int)klen) {
- debug2("cipher_init: set keylen (%d -> %d)", klen, keylen);
- if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0)
- fatal("cipher_init: set keylen failed (%d -> %d)",
- klen, keylen);
+ if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto bad;
+ }
+ }
+ if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto bad;
}
- if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0)
- fatal("cipher_init: EVP_CipherInit: set key failed for %s",
- cipher->name);
-#endif
if (cipher->discard_len > 0) {
- junk = xmalloc(cipher->discard_len);
- discard = xmalloc(cipher->discard_len);
- if (EVP_Cipher(&cc->evp, discard, junk,
- cipher->discard_len) == 0)
- fatal("evp_crypt: EVP_Cipher failed during discard");
+ if ((junk = malloc(cipher->discard_len)) == NULL ||
+ (discard = malloc(cipher->discard_len)) == NULL) {
+ if (junk != NULL)
+ free(junk);
+ ret = SSH_ERR_ALLOC_FAIL;
+ goto bad;
+ }
+ ret = EVP_Cipher(&cc->evp, discard, junk, cipher->discard_len);
explicit_bzero(discard, cipher->discard_len);
free(junk);
free(discard);
+ if (ret != 1) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ bad:
+ EVP_CIPHER_CTX_cleanup(&cc->evp);
+ return ret;
+ }
}
+#endif
+ return 0;
}
/*
@@ -350,204 +382,244 @@ cipher_init(CipherContext *cc, const Cipher *cipher,
* Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag.
* This tag is written on encryption and verified on decryption.
* Both 'aadlen' and 'authlen' can be set to 0.
- * cipher_crypt() returns 0 on success and -1 if the decryption integrity
- * check fails.
*/
int
-cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src,
- u_int len, u_int aadlen, u_int authlen)
+cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
+ const u_char *src, u_int len, u_int aadlen, u_int authlen)
{
- if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
- return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len,
- aadlen, authlen, cc->encrypt);
+ if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
+ return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src,
+ len, aadlen, authlen, cc->encrypt);
+ }
+#ifndef WITH_OPENSSL
+ if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
+ if (aadlen)
+ memcpy(dest, src, aadlen);
+ aesctr_encrypt_bytes(&cc->ac_ctx, src + aadlen,
+ dest + aadlen, len);
+ return 0;
+ }
+ if ((cc->cipher->flags & CFLAG_NONE) != 0) {
+ memcpy(dest, src, aadlen + len);
+ return 0;
+ }
+ return SSH_ERR_INVALID_ARGUMENT;
+#else
if (authlen) {
u_char lastiv[1];
if (authlen != cipher_authlen(cc->cipher))
- fatal("%s: authlen mismatch %d", __func__, authlen);
+ return SSH_ERR_INVALID_ARGUMENT;
/* increment IV */
if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN,
1, lastiv))
- fatal("%s: EVP_CTRL_GCM_IV_GEN", __func__);
+ return SSH_ERR_LIBCRYPTO_ERROR;
/* set tag on decyption */
if (!cc->encrypt &&
!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_TAG,
authlen, (u_char *)src + aadlen + len))
- fatal("%s: EVP_CTRL_GCM_SET_TAG", __func__);
+ return SSH_ERR_LIBCRYPTO_ERROR;
}
if (aadlen) {
if (authlen &&
EVP_Cipher(&cc->evp, NULL, (u_char *)src, aadlen) < 0)
- fatal("%s: EVP_Cipher(aad) failed", __func__);
+ return SSH_ERR_LIBCRYPTO_ERROR;
memcpy(dest, src, aadlen);
}
if (len % cc->cipher->block_size)
- fatal("%s: bad plaintext length %d", __func__, len);
+ return SSH_ERR_INVALID_ARGUMENT;
if (EVP_Cipher(&cc->evp, dest + aadlen, (u_char *)src + aadlen,
len) < 0)
- fatal("%s: EVP_Cipher failed", __func__);
+ return SSH_ERR_LIBCRYPTO_ERROR;
if (authlen) {
/* compute tag (on encrypt) or verify tag (on decrypt) */
- if (EVP_Cipher(&cc->evp, NULL, NULL, 0) < 0) {
- if (cc->encrypt)
- fatal("%s: EVP_Cipher(final) failed", __func__);
- else
- return -1;
- }
+ if (EVP_Cipher(&cc->evp, NULL, NULL, 0) < 0)
+ return cc->encrypt ?
+ SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;
if (cc->encrypt &&
!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG,
authlen, dest + aadlen + len))
- fatal("%s: EVP_CTRL_GCM_GET_TAG", __func__);
+ return SSH_ERR_LIBCRYPTO_ERROR;
}
return 0;
+#endif
}
/* Extract the packet length, including any decryption necessary beforehand */
int
-cipher_get_length(CipherContext *cc, u_int *plenp, u_int seqnr,
+cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr,
const u_char *cp, u_int len)
{
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr,
cp, len);
if (len < 4)
- return -1;
+ return SSH_ERR_MESSAGE_INCOMPLETE;
*plenp = get_u32(cp);
return 0;
}
-void
-cipher_cleanup(CipherContext *cc)
+int
+cipher_cleanup(struct sshcipher_ctx *cc)
{
+ if (cc == NULL || cc->cipher == NULL)
+ return 0;
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx));
+ else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
+ explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx));
+#ifdef WITH_OPENSSL
else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
- error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed");
+ return SSH_ERR_LIBCRYPTO_ERROR;
+#endif
+ return 0;
}
/*
* Selects the cipher, and keys if by computing the MD5 checksum of the
* passphrase and using the resulting 16 bytes as the key.
*/
-
-void
-cipher_set_key_string(CipherContext *cc, const Cipher *cipher,
+int
+cipher_set_key_string(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
const char *passphrase, int do_encrypt)
{
u_char digest[16];
+ int r = SSH_ERR_INTERNAL_ERROR;
- if (ssh_digest_memory(SSH_DIGEST_MD5, passphrase, strlen(passphrase),
- digest, sizeof(digest)) < 0)
- fatal("%s: md5 failed", __func__);
-
- cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);
+ if ((r = ssh_digest_memory(SSH_DIGEST_MD5,
+ passphrase, strlen(passphrase),
+ digest, sizeof(digest))) != 0)
+ goto out;
+ r = cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);
+ out:
explicit_bzero(digest, sizeof(digest));
+ return r;
}
/*
- * Exports an IV from the CipherContext required to export the key
+ * Exports an IV from the sshcipher_ctx required to export the key
* state back from the unprivileged child to the privileged parent
* process.
*/
-
int
-cipher_get_keyiv_len(const CipherContext *cc)
+cipher_get_keyiv_len(const struct sshcipher_ctx *cc)
{
- const Cipher *c = cc->cipher;
- int ivlen;
+ const struct sshcipher *c = cc->cipher;
+ int ivlen = 0;
if (c->number == SSH_CIPHER_3DES)
ivlen = 24;
else if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
ivlen = 0;
+#ifdef WITH_OPENSSL
else
ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp);
+#endif /* WITH_OPENSSL */
return (ivlen);
}
-void
-cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
+int
+cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
{
- const Cipher *c = cc->cipher;
- int evplen;
+ const struct sshcipher *c = cc->cipher;
+#ifdef WITH_OPENSSL
+ int evplen;
+#endif
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
if (len != 0)
- fatal("%s: wrong iv length %d != %d", __func__, len, 0);
- return;
+ return SSH_ERR_INVALID_ARGUMENT;
+ return 0;
}
+ if ((cc->cipher->flags & CFLAG_NONE) != 0)
+ return 0;
switch (c->number) {
+#ifdef WITH_OPENSSL
case SSH_CIPHER_SSH2:
case SSH_CIPHER_DES:
case SSH_CIPHER_BLOWFISH:
evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
- if (evplen <= 0)
- return;
+ if (evplen == 0)
+ return 0;
+ else if (evplen < 0)
+ return SSH_ERR_LIBCRYPTO_ERROR;
if ((u_int)evplen != len)
- fatal("%s: wrong iv length %d != %d", __func__,
- evplen, len);
-#ifdef USE_BUILTIN_RIJNDAEL
- if (c->evptype == evp_rijndael)
- ssh_rijndael_iv(&cc->evp, 0, iv, len);
- else
-#endif
+ return SSH_ERR_INVALID_ARGUMENT;
#ifndef OPENSSL_HAVE_EVPCTR
if (c->evptype == evp_aes_128_ctr)
ssh_aes_ctr_iv(&cc->evp, 0, iv, len);
else
#endif
- memcpy(iv, cc->evp.iv, len);
+ if (cipher_authlen(c)) {
+ if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN,
+ len, iv))
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ } else
+ memcpy(iv, cc->evp.iv, len);
break;
+#endif
+#ifdef WITH_SSH1
case SSH_CIPHER_3DES:
- ssh1_3des_iv(&cc->evp, 0, iv, 24);
- break;
+ return ssh1_3des_iv(&cc->evp, 0, iv, 24);
+#endif
default:
- fatal("%s: bad cipher %d", __func__, c->number);
+ return SSH_ERR_INVALID_ARGUMENT;
}
+ return 0;
}
-void
-cipher_set_keyiv(CipherContext *cc, u_char *iv)
+int
+cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv)
{
- const Cipher *c = cc->cipher;
- int evplen = 0;
+ const struct sshcipher *c = cc->cipher;
+#ifdef WITH_OPENSSL
+ int evplen = 0;
+#endif
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
- return;
+ return 0;
+ if ((cc->cipher->flags & CFLAG_NONE) != 0)
+ return 0;
switch (c->number) {
+#ifdef WITH_OPENSSL
case SSH_CIPHER_SSH2:
case SSH_CIPHER_DES:
case SSH_CIPHER_BLOWFISH:
evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
- if (evplen == 0)
- return;
-#ifdef USE_BUILTIN_RIJNDAEL
- if (c->evptype == evp_rijndael)
- ssh_rijndael_iv(&cc->evp, 1, iv, evplen);
- else
-#endif
-#ifndef OPENSSL_HAVE_EVPCTR
- if (c->evptype == evp_aes_128_ctr)
- ssh_aes_ctr_iv(&cc->evp, 1, iv, evplen);
- else
-#endif
- memcpy(cc->evp.iv, iv, evplen);
+ if (evplen <= 0)
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ if (cipher_authlen(c)) {
+ /* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */
+ if (!EVP_CIPHER_CTX_ctrl(&cc->evp,
+ EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv))
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ } else
+ memcpy(cc->evp.iv, iv, evplen);
break;
+#endif
+#ifdef WITH_SSH1
case SSH_CIPHER_3DES:
- ssh1_3des_iv(&cc->evp, 1, iv, 24);
- break;
+ return ssh1_3des_iv(&cc->evp, 1, (u_char *)iv, 24);
+#endif
default:
- fatal("%s: bad cipher %d", __func__, c->number);
+ return SSH_ERR_INVALID_ARGUMENT;
}
+ return 0;
}
+#ifdef WITH_OPENSSL
+#define EVP_X_STATE(evp) (evp).cipher_data
+#define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size
+#endif
+
int
-cipher_get_keycontext(const CipherContext *cc, u_char *dat)
+cipher_get_keycontext(const struct sshcipher_ctx *cc, u_char *dat)
{
- const Cipher *c = cc->cipher;
+#ifdef WITH_OPENSSL
+ const struct sshcipher *c = cc->cipher;
int plen = 0;
if (c->evptype == EVP_rc4) {
@@ -557,16 +629,21 @@ cipher_get_keycontext(const CipherContext *cc, u_char *dat)
memcpy(dat, EVP_X_STATE(cc->evp), plen);
}
return (plen);
+#else
+ return 0;
+#endif
}
void
-cipher_set_keycontext(CipherContext *cc, u_char *dat)
+cipher_set_keycontext(struct sshcipher_ctx *cc, const u_char *dat)
{
- const Cipher *c = cc->cipher;
+#ifdef WITH_OPENSSL
+ const struct sshcipher *c = cc->cipher;
int plen;
if (c->evptype == EVP_rc4) {
plen = EVP_X_STATE_LEN(cc->evp);
memcpy(EVP_X_STATE(cc->evp), dat, plen);
}
+#endif
}
diff --git a/cipher.h b/cipher.h
index 133d2e73d2ec..de74c1e3b38d 100644
--- a/cipher.h
+++ b/cipher.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cipher.h,v 1.44 2014/01/25 10:12:50 dtucker Exp $ */
+/* $OpenBSD: cipher.h,v 1.46 2014/06/24 01:13:21 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -37,8 +37,10 @@
#ifndef CIPHER_H
#define CIPHER_H
+#include <sys/types.h>
#include <openssl/evp.h>
#include "cipher-chachapoly.h"
+#include "cipher-aesctr.h"
/*
* Cipher types for SSH-1. New types can be added, but old types should not
@@ -60,44 +62,47 @@
#define CIPHER_ENCRYPT 1
#define CIPHER_DECRYPT 0
-typedef struct Cipher Cipher;
-typedef struct CipherContext CipherContext;
-
-struct Cipher;
-struct CipherContext {
+struct sshcipher;
+struct sshcipher_ctx {
int plaintext;
int encrypt;
EVP_CIPHER_CTX evp;
struct chachapoly_ctx cp_ctx; /* XXX union with evp? */
- const Cipher *cipher;
+ struct aesctr_ctx ac_ctx; /* XXX union with evp? */
+ const struct sshcipher *cipher;
};
+typedef struct sshcipher Cipher ;
+typedef struct sshcipher_ctx CipherContext ;
+
u_int cipher_mask_ssh1(int);
-const Cipher *cipher_by_name(const char *);
-const Cipher *cipher_by_number(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);
int ciphers_valid(const char *);
char *cipher_alg_list(char, int);
-void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int,
- const u_char *, u_int, int);
-int cipher_crypt(CipherContext *, u_int, u_char *, const u_char *,
+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(CipherContext *, u_int *, u_int,
+int cipher_get_length(struct sshcipher_ctx *, u_int *, u_int,
const u_char *, u_int);
-void cipher_cleanup(CipherContext *);
-void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int);
-u_int cipher_blocksize(const Cipher *);
-u_int cipher_keylen(const Cipher *);
-u_int cipher_seclen(const Cipher *);
-u_int cipher_authlen(const Cipher *);
-u_int cipher_ivlen(const Cipher *);
-u_int cipher_is_cbc(const Cipher *);
+int cipher_cleanup(struct sshcipher_ctx *);
+int cipher_set_key_string(struct sshcipher_ctx *, const struct sshcipher *,
+ const char *, int);
+u_int cipher_blocksize(const struct sshcipher *);
+u_int cipher_keylen(const struct sshcipher *);
+u_int cipher_seclen(const struct sshcipher *);
+u_int cipher_authlen(const struct sshcipher *);
+u_int cipher_ivlen(const struct sshcipher *);
+u_int cipher_is_cbc(const struct sshcipher *);
-u_int cipher_get_number(const Cipher *);
-void cipher_get_keyiv(CipherContext *, u_char *, u_int);
-void cipher_set_keyiv(CipherContext *, u_char *);
-int cipher_get_keyiv_len(const CipherContext *);
-int cipher_get_keycontext(const CipherContext *, u_char *);
-void cipher_set_keycontext(CipherContext *, u_char *);
+u_int cipher_get_number(const struct sshcipher *);
+int cipher_get_keyiv(struct sshcipher_ctx *, u_char *, u_int);
+int cipher_set_keyiv(struct sshcipher_ctx *, const u_char *);
+int cipher_get_keyiv_len(const struct sshcipher_ctx *);
+int cipher_get_keycontext(const struct sshcipher_ctx *, u_char *);
+void cipher_set_keycontext(struct sshcipher_ctx *, const u_char *);
#endif /* CIPHER_H */
diff --git a/clientloop.c b/clientloop.c
index 59ad3a2c36a9..397c96532b6c 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.258 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.261 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -100,13 +100,13 @@
#include "cipher.h"
#include "kex.h"
#include "log.h"
+#include "misc.h"
#include "readconf.h"
#include "clientloop.h"
#include "sshconnect.h"
#include "authfd.h"
#include "atomicio.h"
#include "sshpty.h"
-#include "misc.h"
#include "match.h"
#include "msg.h"
#include "roaming.h"
@@ -871,13 +871,11 @@ static void
process_cmdline(void)
{
void (*handler)(int);
- char *s, *cmd, *cancel_host;
- int delete = 0, local = 0, remote = 0, dynamic = 0;
- int cancel_port, ok;
- Forward fwd;
+ char *s, *cmd;
+ int ok, delete = 0, local = 0, remote = 0, dynamic = 0;
+ struct Forward fwd;
memset(&fwd, 0, sizeof(fwd));
- fwd.listen_host = fwd.connect_host = NULL;
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
handler = signal(SIGINT, SIG_IGN);
@@ -943,29 +941,20 @@ process_cmdline(void)
/* XXX update list of forwards in options */
if (delete) {
- cancel_port = 0;
- cancel_host = hpdelim(&s); /* may be NULL */
- if (s != NULL) {
- cancel_port = a2port(s);
- cancel_host = cleanhostname(cancel_host);
- } else {
- cancel_port = a2port(cancel_host);
- cancel_host = NULL;
- }
- if (cancel_port <= 0) {
- logit("Bad forwarding close port");
+ /* We pass 1 for dynamicfwd to restrict to 1 or 2 fields. */
+ if (!parse_forward(&fwd, s, 1, 0)) {
+ logit("Bad forwarding close specification.");
goto out;
}
if (remote)
- ok = channel_request_rforward_cancel(cancel_host,
- cancel_port) == 0;
+ ok = channel_request_rforward_cancel(&fwd) == 0;
else if (dynamic)
- ok = channel_cancel_lport_listener(cancel_host,
- cancel_port, 0, options.gateway_ports) > 0;
+ ok = channel_cancel_lport_listener(&fwd,
+ 0, &options.fwd_opts) > 0;
else
- ok = channel_cancel_lport_listener(cancel_host,
- cancel_port, CHANNEL_CANCEL_PORT_STATIC,
- options.gateway_ports) > 0;
+ ok = channel_cancel_lport_listener(&fwd,
+ CHANNEL_CANCEL_PORT_STATIC,
+ &options.fwd_opts) > 0;
if (!ok) {
logit("Unkown port forwarding.");
goto out;
@@ -977,16 +966,13 @@ process_cmdline(void)
goto out;
}
if (local || dynamic) {
- if (!channel_setup_local_fwd_listener(fwd.listen_host,
- fwd.listen_port, fwd.connect_host,
- fwd.connect_port, options.gateway_ports)) {
+ if (!channel_setup_local_fwd_listener(&fwd,
+ &options.fwd_opts)) {
logit("Port forwarding failed.");
goto out;
}
} else {
- if (channel_request_remote_forwarding(fwd.listen_host,
- fwd.listen_port, fwd.connect_host,
- fwd.connect_port) < 0) {
+ if (channel_request_remote_forwarding(&fwd) < 0) {
logit("Port forwarding failed.");
goto out;
}
@@ -999,7 +985,9 @@ out:
enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
free(cmd);
free(fwd.listen_host);
+ free(fwd.listen_path);
free(fwd.connect_host);
+ free(fwd.connect_path);
}
/* reasons to suppress output of an escape command in help output */
@@ -1845,11 +1833,10 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
originator_port = packet_get_int();
packet_check_eom();
- debug("client_request_forwarded_tcpip: listen %s port %d, "
- "originator %s port %d", listen_address, listen_port,
- originator_address, originator_port);
+ debug("%s: listen %s port %d, originator %s port %d", __func__,
+ listen_address, listen_port, originator_address, originator_port);
- c = channel_connect_by_listen_address(listen_port,
+ c = channel_connect_by_listen_address(listen_address, listen_port,
"forwarded-tcpip", originator_address);
free(originator_address);
@@ -1858,6 +1845,27 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
}
static Channel *
+client_request_forwarded_streamlocal(const char *request_type, int rchan)
+{
+ Channel *c = NULL;
+ char *listen_path;
+
+ /* Get the remote path. */
+ listen_path = packet_get_string(NULL);
+ /* XXX: Skip reserved field for now. */
+ if (packet_get_string_ptr(NULL) == NULL)
+ fatal("%s: packet_get_string_ptr failed", __func__);
+ packet_check_eom();
+
+ debug("%s: %s", __func__, listen_path);
+
+ c = channel_connect_by_listen_path(listen_path,
+ "forwarded-streamlocal@openssh.com", "forwarded-streamlocal");
+ free(listen_path);
+ return c;
+}
+
+static Channel *
client_request_x11(const char *request_type, int rchan)
{
Channel *c = NULL;
@@ -1984,6 +1992,8 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
if (strcmp(ctype, "forwarded-tcpip") == 0) {
c = client_request_forwarded_tcpip(ctype, rchan);
+ } else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) {
+ c = client_request_forwarded_streamlocal(ctype, rchan);
} else if (strcmp(ctype, "x11") == 0) {
c = client_request_x11(ctype, rchan);
} else if (strcmp(ctype, "auth-agent@openssh.com") == 0) {
@@ -2054,7 +2064,7 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
}
packet_check_eom();
}
- if (reply && c != NULL) {
+ if (reply && c != NULL && !(c->flags & CHAN_CLOSE_SENT)) {
packet_start(success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
packet_put_int(c->remote_id);
diff --git a/compat.c b/compat.c
index 2709dc5cfdc8..4d286e8e9a44 100644
--- a/compat.c
+++ b/compat.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: compat.c,v 1.82 2013/12/30 23:52:27 djm Exp $ */
+/* $OpenBSD: compat.c,v 1.85 2014/04/20 02:49:32 djm Exp $ */
/*
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
diff --git a/compat.h b/compat.h
index a6c3f3d7acd9..2e25d5ba9911 100644
--- a/compat.h
+++ b/compat.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: compat.h,v 1.44 2013/12/30 23:52:27 djm Exp $ */
+/* $OpenBSD: compat.h,v 1.45 2014/04/18 23:52:25 djm Exp $ */
/*
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
diff --git a/config.h.in b/config.h.in
index 0401ad181583..16d620615d0b 100644
--- a/config.h.in
+++ b/config.h.in
@@ -420,6 +420,9 @@
/* Define to 1 if you have the `EVP_MD_CTX_init' function. */
#undef HAVE_EVP_MD_CTX_INIT
+/* Define to 1 if you have the `EVP_ripemd160' function. */
+#undef HAVE_EVP_RIPEMD160
+
/* Define to 1 if you have the `EVP_sha256' function. */
#undef HAVE_EVP_SHA256
@@ -768,6 +771,9 @@
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
+/* Define to 1 if you have the `memset_s' function. */
+#undef HAVE_MEMSET_S
+
/* Define to 1 if you have the `mkdtemp' function. */
#undef HAVE_MKDTEMP
@@ -1324,9 +1330,6 @@
/* Define if va_copy exists */
#undef HAVE_VA_COPY
-/* Define to 1 if you have the `vhangup' function. */
-#undef HAVE_VHANGUP
-
/* Define to 1 if you have the <vis.h> header file. */
#undef HAVE_VIS_H
@@ -1387,9 +1390,6 @@
/* Define if pututxline updates lastlog too */
#undef LASTLOG_WRITE_PUTUTXLINE
-/* Define if you want TCP Wrappers support */
-#undef LIBWRAP
-
/* Define to whatever link() returns for "not supported" if it doesn't return
EOPNOTSUPP. */
#undef LINK_OPNOTSUPP_ERRNO
@@ -1662,9 +1662,15 @@
/* Define if you want IRIX project management */
#undef WITH_IRIX_PROJECT
+/* use libcrypto for cryptography */
+#undef WITH_OPENSSL
+
/* Define if you want SELinux support. */
#undef WITH_SELINUX
+/* 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
diff --git a/configure b/configure
index d690393a369a..6815388ccb45 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.ac Revision: 1.571 .
+# From configure.ac Revision: 1.583 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.68 for OpenSSH Portable.
#
@@ -725,7 +725,6 @@ with_osfsia
with_zlib
with_zlib_version_check
with_skey
-with_tcp_wrappers
with_ldns
with_libedit
with_audit
@@ -1417,7 +1416,6 @@ Optional Packages:
--with-zlib=PATH Use zlib in PATH
--without-zlib-version-check Disable zlib version check
--with-skey[=PATH] Enable S/Key support (optionally in PATH)
- --with-tcp-wrappers[=PATH] Enable tcpwrappers support (optionally in PATH)
--with-ldns[=PATH] Use ldns for DNSSEC support (optionally in PATH)
--with-libedit[=PATH] Enable libedit support for sftp
--with-audit=module Enable audit support (modules=debug,bsm,linux)
@@ -9706,84 +9704,6 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-# Check whether user wants TCP wrappers support
-TCPW_MSG="no"
-
-# Check whether --with-tcp-wrappers was given.
-if test "${with_tcp_wrappers+set}" = set; then :
- withval=$with_tcp_wrappers;
- if test "x$withval" != "xno" ; then
- saved_LIBS="$LIBS"
- saved_LDFLAGS="$LDFLAGS"
- saved_CPPFLAGS="$CPPFLAGS"
- if test -n "${withval}" && \
- test "x${withval}" != "xyes"; then
- if test -d "${withval}/lib"; then
- if test -n "${need_dash_r}"; then
- LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
- else
- LDFLAGS="-L${withval}/lib ${LDFLAGS}"
- fi
- else
- if test -n "${need_dash_r}"; then
- LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}"
- else
- LDFLAGS="-L${withval} ${LDFLAGS}"
- fi
- fi
- if test -d "${withval}/include"; then
- CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
- else
- CPPFLAGS="-I${withval} ${CPPFLAGS}"
- fi
- fi
- LIBS="-lwrap $LIBS"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libwrap" >&5
-$as_echo_n "checking for libwrap... " >&6; }
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <tcpd.h>
-int deny_severity = 0, allow_severity = 0;
-
-int
-main ()
-{
-
- hosts_access(0);
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define LIBWRAP 1" >>confdefs.h
-
- SSHDLIBS="$SSHDLIBS -lwrap"
- TCPW_MSG="yes"
-
-else
-
- as_fn_error $? "*** libwrap missing" "$LINENO" 5
-
-
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
- LIBS="$saved_LIBS"
- fi
-
-
-fi
-
-
# Check whether user wants to use ldns
LDNS_MSG="no"
@@ -10348,10 +10268,6 @@ for ac_func in \
Blowfish_expandstate \
Blowfish_expand0state \
Blowfish_stream2word \
- arc4random \
- arc4random_buf \
- arc4random_stir \
- arc4random_uniform \
asprintf \
b64_ntop \
__b64_ntop \
@@ -10395,6 +10311,7 @@ for ac_func in \
mblen \
md5_crypt \
memmove \
+ memset_s \
mkdtemp \
mmap \
ngetaddrinfo \
@@ -10453,7 +10370,6 @@ for ac_func in \
user_from_uid \
usleep \
vasprintf \
- vhangup \
vsnprintf \
waitpid \
@@ -11269,11 +11185,9 @@ fi
fi
-# If we don't have a working asprintf, then we strongly depend on vsnprintf
-# returning the right thing on overflow: the number of characters it tried to
-# create (as per SUSv3)
-if test "x$ac_cv_func_asprintf" != "xyes" && \
- test "x$ac_cv_func_vsnprintf" = "xyes" ; then
+# We depend on vsnprintf returning the right thing on overflow: the
+# number of characters it tried to create (as per SUSv3)
+if test "x$ac_cv_func_vsnprintf" = "xyes" ; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vsnprintf returns correct values on overflow" >&5
$as_echo_n "checking whether vsnprintf returns correct values on overflow... " >&6; }
if test "$cross_compiling" = yes; then :
@@ -11288,10 +11202,14 @@ else
#include <stdio.h>
#include <stdarg.h>
-int x_snprintf(char *str,size_t count,const char *fmt,...)
+int x_snprintf(char *str, size_t count, const char *fmt, ...)
{
- size_t ret; va_list ap;
- va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap);
+ size_t ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(str, count, fmt, ap);
+ va_end(ap);
return ret;
}
@@ -11299,8 +11217,12 @@ int
main ()
{
- char x[1];
- exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1);
+char x[1];
+if (x_snprintf(x, 1, "%s %d", "hello", 12345) != 11)
+ return 1;
+if (x_snprintf(NULL, 0, "%s %d", "hello", 12345) != 11)
+ return 1;
+return 0;
;
return 0;
@@ -11897,7 +11819,7 @@ main ()
if(fd == NULL)
exit(1);
- if ((rc = fprintf(fd ,"%x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0)
+ if ((rc = fprintf(fd ,"%08x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0)
exit(1);
exit(0);
@@ -11954,7 +11876,8 @@ main ()
if(fd == NULL)
exit(1);
- if ((rc = fprintf(fd ,"%x (%s)\n", SSLeay(), SSLeay_version(SSLEAY_VERSION))) <0)
+ if ((rc = fprintf(fd ,"%08x (%s)\n", SSLeay(),
+ SSLeay_version(SSLEAY_VERSION))) <0)
exit(1);
exit(0);
@@ -11966,6 +11889,13 @@ _ACEOF
if ac_fn_c_try_run "$LINENO"; then :
ssl_library_ver=`cat conftest.ssllibver`
+ # Check version is supported.
+ case "$ssl_library_ver" in
+ 0090[0-7]*|009080[0-5]*)
+ as_fn_error $? "OpenSSL >= 0.9.8f required" "$LINENO" 5
+ ;;
+ *) ;;
+ esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ssl_library_ver" >&5
$as_echo "$ssl_library_ver" >&6; }
@@ -11981,6 +11911,18 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
fi
+# XXX make --without-openssl work
+
+cat >>confdefs.h <<_ACEOF
+#define WITH_OPENSSL 1
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define WITH_SSH1 1
+_ACEOF
+
+
# Check whether --with-openssl-header-check was given.
if test "${with_openssl_header_check+set}" = set; then :
@@ -12514,6 +12456,25 @@ else
fi
done
+# Search for RIPE-MD support in OpenSSL
+for ac_func in EVP_ripemd160
+do :
+ ac_fn_c_check_func "$LINENO" "EVP_ripemd160" "ac_cv_func_EVP_ripemd160"
+if test "x$ac_cv_func_EVP_ripemd160" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_EVP_RIPEMD160 1
+_ACEOF
+
+else
+ unsupported_algorithms="$unsupported_algorithms \
+ hmac-ripemd160
+ hmac-ripemd160@openssh.com
+ hmac-ripemd160-etm@openssh.com"
+
+
+fi
+done
+
# Check complete ECC support in OpenSSL
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has NID_X9_62_prime256v1" >&5
@@ -12714,6 +12675,24 @@ fi
+for ac_func in \
+ arc4random \
+ arc4random_buf \
+ arc4random_stir \
+ arc4random_uniform \
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
saved_LIBS="$LIBS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ia_openinfo in -liaf" >&5
$as_echo_n "checking for ia_openinfo in -liaf... " >&6; }
@@ -13123,7 +13102,14 @@ fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-SSH_PRIVSEP_USER=sshd
+case "$host" in
+*-*-cygwin*)
+ SSH_PRIVSEP_USER=CYGWIN_SSH_PRIVSEP_USER
+ ;;
+*)
+ SSH_PRIVSEP_USER=sshd
+ ;;
+esac
# Check whether --with-privsep-user was given.
if test "${with_privsep_user+set}" = set; then :
@@ -13136,11 +13122,19 @@ if test "${with_privsep_user+set}" = set; then :
fi
+if test "x$SSH_PRIVSEP_USER" = "xCYGWIN_SSH_PRIVSEP_USER" ; then
+
+cat >>confdefs.h <<_ACEOF
+#define SSH_PRIVSEP_USER CYGWIN_SSH_PRIVSEP_USER
+_ACEOF
+
+else
cat >>confdefs.h <<_ACEOF
#define SSH_PRIVSEP_USER "$SSH_PRIVSEP_USER"
_ACEOF
+fi
if test "x$have_linux_no_new_privs" = "x1" ; then
@@ -19684,7 +19678,6 @@ echo " KerberosV support: $KRB5_MSG"
echo " SELinux support: $SELINUX_MSG"
echo " Smartcard support: $SCARD_MSG"
echo " S/KEY support: $SKEY_MSG"
-echo " TCP Wrappers support: $TCPW_MSG"
echo " MD5 password support: $MD5_MSG"
echo " libedit support: $LIBEDIT_MSG"
echo " Solaris process contract support: $SPC_MSG"
diff --git a/configure.ac b/configure.ac
index 7c6ce08d8c4d..67c4486e7fe2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-# $Id: configure.ac,v 1.571 2014/02/21 17:09:34 tim Exp $
+# $Id: configure.ac,v 1.583 2014/08/26 20:32:01 djm Exp $
#
# Copyright (c) 1999-2004 Damien Miller
#
@@ -15,7 +15,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org])
-AC_REVISION($Revision: 1.571 $)
+AC_REVISION($Revision: 1.583 $)
AC_CONFIG_SRCDIR([ssh.c])
AC_LANG([C])
@@ -1380,62 +1380,6 @@ AC_ARG_WITH([skey],
]
)
-# Check whether user wants TCP wrappers support
-TCPW_MSG="no"
-AC_ARG_WITH([tcp-wrappers],
- [ --with-tcp-wrappers[[=PATH]] Enable tcpwrappers support (optionally in PATH)],
- [
- if test "x$withval" != "xno" ; then
- saved_LIBS="$LIBS"
- saved_LDFLAGS="$LDFLAGS"
- saved_CPPFLAGS="$CPPFLAGS"
- if test -n "${withval}" && \
- test "x${withval}" != "xyes"; then
- if test -d "${withval}/lib"; then
- if test -n "${need_dash_r}"; then
- LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
- else
- LDFLAGS="-L${withval}/lib ${LDFLAGS}"
- fi
- else
- if test -n "${need_dash_r}"; then
- LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}"
- else
- LDFLAGS="-L${withval} ${LDFLAGS}"
- fi
- fi
- if test -d "${withval}/include"; then
- CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
- else
- CPPFLAGS="-I${withval} ${CPPFLAGS}"
- fi
- fi
- LIBS="-lwrap $LIBS"
- AC_MSG_CHECKING([for libwrap])
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <tcpd.h>
-int deny_severity = 0, allow_severity = 0;
- ]], [[
- hosts_access(0);
- ]])], [
- AC_MSG_RESULT([yes])
- AC_DEFINE([LIBWRAP], [1],
- [Define if you want
- TCP Wrappers support])
- SSHDLIBS="$SSHDLIBS -lwrap"
- TCPW_MSG="yes"
- ], [
- AC_MSG_ERROR([*** libwrap missing])
-
- ])
- LIBS="$saved_LIBS"
- fi
- ]
-)
-
# Check whether user wants to use ldns
LDNS_MSG="no"
AC_ARG_WITH(ldns,
@@ -1631,10 +1575,6 @@ AC_CHECK_FUNCS([ \
Blowfish_expandstate \
Blowfish_expand0state \
Blowfish_stream2word \
- arc4random \
- arc4random_buf \
- arc4random_stir \
- arc4random_uniform \
asprintf \
b64_ntop \
__b64_ntop \
@@ -1678,6 +1618,7 @@ AC_CHECK_FUNCS([ \
mblen \
md5_crypt \
memmove \
+ memset_s \
mkdtemp \
mmap \
ngetaddrinfo \
@@ -1736,7 +1677,6 @@ AC_CHECK_FUNCS([ \
user_from_uid \
usleep \
vasprintf \
- vhangup \
vsnprintf \
waitpid \
])
@@ -1948,11 +1888,9 @@ if test "x$ac_cv_func_snprintf" = "xyes" ; then
)
fi
-# If we don't have a working asprintf, then we strongly depend on vsnprintf
-# returning the right thing on overflow: the number of characters it tried to
-# create (as per SUSv3)
-if test "x$ac_cv_func_asprintf" != "xyes" && \
- test "x$ac_cv_func_vsnprintf" = "xyes" ; then
+# We depend on vsnprintf returning the right thing on overflow: the
+# number of characters it tried to create (as per SUSv3)
+if test "x$ac_cv_func_vsnprintf" = "xyes" ; then
AC_MSG_CHECKING([whether vsnprintf returns correct values on overflow])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
@@ -1960,15 +1898,23 @@ if test "x$ac_cv_func_asprintf" != "xyes" && \
#include <stdio.h>
#include <stdarg.h>
-int x_snprintf(char *str,size_t count,const char *fmt,...)
+int x_snprintf(char *str, size_t count, const char *fmt, ...)
{
- size_t ret; va_list ap;
- va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap);
+ size_t ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(str, count, fmt, ap);
+ va_end(ap);
return ret;
}
]], [[
- char x[1];
- exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1);
+char x[1];
+if (x_snprintf(x, 1, "%s %d", "hello", 12345) != 11)
+ return 1;
+if (x_snprintf(NULL, 0, "%s %d", "hello", 12345) != 11)
+ return 1;
+return 0;
]])],
[AC_MSG_RESULT([yes])],
[
@@ -2304,7 +2250,7 @@ AC_RUN_IFELSE(
if(fd == NULL)
exit(1);
- if ((rc = fprintf(fd ,"%x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0)
+ if ((rc = fprintf(fd ,"%08x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0)
exit(1);
exit(0);
@@ -2339,13 +2285,21 @@ AC_RUN_IFELSE(
if(fd == NULL)
exit(1);
- if ((rc = fprintf(fd ,"%x (%s)\n", SSLeay(), SSLeay_version(SSLEAY_VERSION))) <0)
+ if ((rc = fprintf(fd ,"%08x (%s)\n", SSLeay(),
+ SSLeay_version(SSLEAY_VERSION))) <0)
exit(1);
exit(0);
]])],
[
ssl_library_ver=`cat conftest.ssllibver`
+ # Check version is supported.
+ case "$ssl_library_ver" in
+ 0090[[0-7]]*|009080[[0-5]]*)
+ AC_MSG_ERROR([OpenSSL >= 0.9.8f required])
+ ;;
+ *) ;;
+ esac
AC_MSG_RESULT([$ssl_library_ver])
],
[
@@ -2357,6 +2311,10 @@ AC_RUN_IFELSE(
]
)
+# XXX make --without-openssl work
+AC_DEFINE_UNQUOTED([WITH_OPENSSL], [1], [use libcrypto for cryptography])
+AC_DEFINE_UNQUOTED([WITH_SSH1], [1], [include SSH protocol version 1 support])
+
AC_ARG_WITH([openssl-header-check],
[ --without-openssl-header-check Disable OpenSSL version consistency check],
[ if test "x$withval" = "xno" ; then
@@ -2565,6 +2523,14 @@ AC_CHECK_FUNCS([SHA256_Update EVP_sha256], ,
hmac-sha2-256-etm@openssh.com hmac-sha2-512-etm@openssh.com"
]
)
+# Search for RIPE-MD support in OpenSSL
+AC_CHECK_FUNCS([EVP_ripemd160], ,
+ [unsupported_algorithms="$unsupported_algorithms \
+ hmac-ripemd160
+ hmac-ripemd160@openssh.com
+ hmac-ripemd160-etm@openssh.com"
+ ]
+)
# Check complete ECC support in OpenSSL
AC_MSG_CHECKING([whether OpenSSL has NID_X9_62_prime256v1])
@@ -2685,6 +2651,13 @@ fi
AC_SUBST([TEST_SSH_ECC])
AC_SUBST([COMMENT_OUT_ECC])
+AC_CHECK_FUNCS([ \
+ arc4random \
+ arc4random_buf \
+ arc4random_stir \
+ arc4random_uniform \
+])
+
saved_LIBS="$LIBS"
AC_CHECK_LIB([iaf], [ia_openinfo], [
LIBS="$LIBS -liaf"
@@ -2868,7 +2841,14 @@ if test "x$PAM_MSG" = "xyes" ; then
])
fi
-SSH_PRIVSEP_USER=sshd
+case "$host" in
+*-*-cygwin*)
+ SSH_PRIVSEP_USER=CYGWIN_SSH_PRIVSEP_USER
+ ;;
+*)
+ SSH_PRIVSEP_USER=sshd
+ ;;
+esac
AC_ARG_WITH([privsep-user],
[ --with-privsep-user=user Specify non-privileged user for privilege separation],
[
@@ -2878,8 +2858,13 @@ AC_ARG_WITH([privsep-user],
fi
]
)
-AC_DEFINE_UNQUOTED([SSH_PRIVSEP_USER], ["$SSH_PRIVSEP_USER"],
- [non-privileged user for privilege separation])
+if test "x$SSH_PRIVSEP_USER" = "xCYGWIN_SSH_PRIVSEP_USER" ; then
+ AC_DEFINE_UNQUOTED([SSH_PRIVSEP_USER], [CYGWIN_SSH_PRIVSEP_USER],
+ [Cygwin function to fetch non-privileged user for privilege separation])
+else
+ AC_DEFINE_UNQUOTED([SSH_PRIVSEP_USER], ["$SSH_PRIVSEP_USER"],
+ [non-privileged user for privilege separation])
+fi
AC_SUBST([SSH_PRIVSEP_USER])
if test "x$have_linux_no_new_privs" = "x1" ; then
@@ -4844,7 +4829,6 @@ echo " KerberosV support: $KRB5_MSG"
echo " SELinux support: $SELINUX_MSG"
echo " Smartcard support: $SCARD_MSG"
echo " S/KEY support: $SKEY_MSG"
-echo " TCP Wrappers support: $TCPW_MSG"
echo " MD5 password support: $MD5_MSG"
echo " libedit support: $LIBEDIT_MSG"
echo " Solaris process contract support: $SPC_MSG"
diff --git a/contrib/caldera/openssh.spec b/contrib/caldera/openssh.spec
index 0061fe933d29..0011b4deaeb5 100644
--- a/contrib/caldera/openssh.spec
+++ b/contrib/caldera/openssh.spec
@@ -16,7 +16,7 @@
#old cvs stuff. please update before use. may be deprecated.
%define use_stable 1
-%define version 6.6p1
+%define version 6.7p1
%if %{use_stable}
%define cvs %{nil}
%define release 1
@@ -178,7 +178,6 @@ by Jim Knoble <jmknoble@pobox.com>.
CFLAGS="$RPM_OPT_FLAGS" \
%configure \
--with-pam \
- --with-tcp-wrappers \
--with-privsep-path=%{_var}/empty/sshd \
#leave this line for easy edits.
@@ -363,4 +362,4 @@ fi
* Mon Jan 01 1998 ...
Template Version: 1.31
-$Id: openssh.spec,v 1.83 2014/02/27 23:03:55 djm Exp $
+$Id: openssh.spec,v 1.85 2014/08/19 01:36:08 djm Exp $
diff --git a/contrib/cygwin/README b/contrib/cygwin/README
index 2562b61865f1..1396d99cd81f 100644
--- a/contrib/cygwin/README
+++ b/contrib/cygwin/README
@@ -69,7 +69,7 @@ Building OpenSSH
Building from source is easy. Just unpack the source archive, cd to that
directory, and call cygport:
- cygport openssh.cygport almostall
+ cygport openssh.cygport all
You must have installed the following packages to be able to build OpenSSH
with the aforementioned cygport script:
@@ -77,7 +77,6 @@ with the aforementioned cygport script:
zlib
crypt
openssl-devel
- libwrap-devel
libedit-devel
libkrb5-devel
diff --git a/contrib/cygwin/ssh-host-config b/contrib/cygwin/ssh-host-config
index 05efd3b3bf6b..a7ea3e0d2d3e 100644
--- a/contrib/cygwin/ssh-host-config
+++ b/contrib/cygwin/ssh-host-config
@@ -34,9 +34,9 @@ declare -a csih_required_commands=(
/usr/bin/mv coreutils
/usr/bin/rm coreutils
/usr/bin/cygpath cygwin
+ /usr/bin/mkpasswd cygwin
/usr/bin/mount cygwin
/usr/bin/ps cygwin
- /usr/bin/setfacl cygwin
/usr/bin/umount cygwin
/usr/bin/cmp diffutils
/usr/bin/grep grep
@@ -59,8 +59,9 @@ PREFIX=/usr
SYSCONFDIR=/etc
LOCALSTATEDIR=/var
+sshd_config_configured=no
port_number=22
-privsep_configured=no
+strictmodes=yes
privsep_used=yes
cygwin_value=""
user_account=
@@ -89,28 +90,8 @@ update_services_file() {
# Depends on the above mount
_wservices=`cygpath -w "${_services}"`
- # Remove sshd 22/port from services
- if [ `/usr/bin/grep -q 'sshd[ \t][ \t]*22' "${_services}"; echo $?` -eq 0 ]
- then
- /usr/bin/grep -v 'sshd[ \t][ \t]*22' "${_services}" > "${_serv_tmp}"
- if [ -f "${_serv_tmp}" ]
- then
- if /usr/bin/mv "${_serv_tmp}" "${_services}"
- then
- csih_inform "Removing sshd from ${_wservices}"
- else
- csih_warning "Removing sshd from ${_wservices} failed!"
- let ++ret
- fi
- /usr/bin/rm -f "${_serv_tmp}"
- else
- csih_warning "Removing sshd from ${_wservices} failed!"
- let ++ret
- fi
- fi
-
# Add ssh 22/tcp and ssh 22/udp to services
- if [ `/usr/bin/grep -q 'ssh[ \t][ \t]*22' "${_services}"; echo $?` -ne 0 ]
+ if [ `/usr/bin/grep -q 'ssh[[:space:]][[:space:]]*22' "${_services}"; echo $?` -ne 0 ]
then
if /usr/bin/awk '{ if ( $2 ~ /^23\/tcp/ ) print "ssh 22/tcp'"${_spaces}"'SSH Remote Login Protocol\nssh 22/udp'"${_spaces}"'SSH Remote Login Protocol"; print $0; }' < "${_services}" > "${_serv_tmp}"
then
@@ -132,17 +113,45 @@ update_services_file() {
} # --- End of update_services_file --- #
# ======================================================================
+# Routine: sshd_strictmodes
+# MODIFIES: strictmodes
+# ======================================================================
+sshd_strictmodes() {
+ if [ "${sshd_config_configured}" != "yes" ]
+ then
+ echo
+ csih_inform "StrictModes is set to 'yes' by default."
+ csih_inform "This is the recommended setting, but it requires that the POSIX"
+ csih_inform "permissions of the user's home directory, the user's .ssh"
+ csih_inform "directory, and the user's ssh key files are tight so that"
+ csih_inform "only the user has write permissions."
+ csih_inform "On the other hand, StrictModes don't work well with default"
+ csih_inform "Windows permissions of a home directory mounted with the"
+ csih_inform "'noacl' option, and they don't work at all if the home"
+ csih_inform "directory is on a FAT or FAT32 partition."
+ if ! csih_request "Should StrictModes be used?"
+ then
+ strictmodes=no
+ fi
+ fi
+ return 0
+}
+
+# ======================================================================
# Routine: sshd_privsep
-# MODIFIES: privsep_configured privsep_used
+# MODIFIES: privsep_used
# ======================================================================
sshd_privsep() {
- local sshdconfig_tmp
local ret=0
- if [ "${privsep_configured}" != "yes" ]
+ if [ "${sshd_config_configured}" != "yes" ]
then
- csih_inform "Privilege separation is set to yes by default since OpenSSH 3.3."
- csih_inform "However, this requires a non-privileged account called 'sshd'."
+ echo
+ csih_inform "Privilege separation is set to 'sandbox' by default since"
+ csih_inform "OpenSSH 6.1. This is unsupported by Cygwin and has to be set"
+ csih_inform "to 'yes' or 'no'."
+ csih_inform "However, using privilege separation requires a non-privileged account"
+ csih_inform "called 'sshd'."
csih_inform "For more info on privilege separation read /usr/share/doc/openssh/README.privsep."
if csih_request "Should privilege separation be used?"
then
@@ -159,36 +168,53 @@ sshd_privsep() {
privsep_used=no
fi
fi
+ return $ret
+} # --- End of sshd_privsep --- #
- # Create default sshd_config from skeleton files in /etc/defaults/etc or
- # modify to add the missing privsep configuration option
- if /usr/bin/cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1
+# ======================================================================
+# Routine: sshd_config_tweak
+# ======================================================================
+sshd_config_tweak() {
+ local ret=0
+
+ # Modify sshd_config
+ csih_inform "Updating ${SYSCONFDIR}/sshd_config file"
+ if [ "${port_number}" -ne 22 ]
then
- csih_inform "Updating ${SYSCONFDIR}/sshd_config file"
- sshdconfig_tmp=${SYSCONFDIR}/sshd_config.$$
- /usr/bin/sed -e "s/^#UsePrivilegeSeparation yes/UsePrivilegeSeparation ${privsep_used}/
- s/^#Port 22/Port ${port_number}/
- s/^#StrictModes yes/StrictModes no/" \
- < ${SYSCONFDIR}/sshd_config \
- > "${sshdconfig_tmp}"
- if ! /usr/bin/mv "${sshdconfig_tmp}" ${SYSCONFDIR}/sshd_config
+ /usr/bin/sed -i -e "s/^#\?[[:space:]]*Port[[:space:]].*/Port ${port_number}/" \
+ ${SYSCONFDIR}/sshd_config
+ if [ $? -ne 0 ]
then
- csih_warning "Setting privilege separation to 'yes' failed!"
- csih_warning "Check your ${SYSCONFDIR}/sshd_config file!"
- let ++ret
+ csih_warning "Setting listening port to ${port_number} failed!"
+ csih_warning "Check your ${SYSCONFDIR}/sshd_config file!"
+ let ++ret
+ fi
+ fi
+ if [ "${strictmodes}" = "no" ]
+ then
+ /usr/bin/sed -i -e "s/^#\?[[:space:]]*StrictModes[[:space:]].*/StrictModes no/" \
+ ${SYSCONFDIR}/sshd_config
+ if [ $? -ne 0 ]
+ then
+ csih_warning "Setting StrictModes to 'no' failed!"
+ csih_warning "Check your ${SYSCONFDIR}/sshd_config file!"
+ let ++ret
fi
- elif [ "${privsep_configured}" != "yes" ]
+ fi
+ if [ "${sshd_config_configured}" != "yes" ]
then
- echo >> ${SYSCONFDIR}/sshd_config
- if ! echo "UsePrivilegeSeparation ${privsep_used}" >> ${SYSCONFDIR}/sshd_config
+ /usr/bin/sed -i -e "
+ s/^#\?UsePrivilegeSeparation .*/UsePrivilegeSeparation ${privsep_used}/" \
+ ${SYSCONFDIR}/sshd_config
+ if [ $? -ne 0 ]
then
- csih_warning "Setting privilege separation to 'yes' failed!"
- csih_warning "Check your ${SYSCONFDIR}/sshd_config file!"
- let ++ret
+ csih_warning "Setting privilege separation failed!"
+ csih_warning "Check your ${SYSCONFDIR}/sshd_config file!"
+ let ++ret
fi
fi
return $ret
-} # --- End of sshd_privsep --- #
+} # --- End of sshd_config_tweak --- #
# ======================================================================
# Routine: update_inetd_conf
@@ -207,11 +233,11 @@ update_inetd_conf() {
# we have inetutils-1.5 inetd.d support
if [ -f "${_inetcnf}" ]
then
- /usr/bin/grep -q '^[ \t]*ssh' "${_inetcnf}" && _with_comment=0
+ /usr/bin/grep -q '^[[:space:]]*ssh' "${_inetcnf}" && _with_comment=0
# check for sshd OR ssh in top-level inetd.conf file, and remove
# will be replaced by a file in inetd.d/
- if [ `/usr/bin/grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?` -eq 0 ]
+ if [ $(/usr/bin/grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?) -eq 0 ]
then
/usr/bin/grep -v '^[# \t]*ssh' "${_inetcnf}" >> "${_inetcnf_tmp}"
if [ -f "${_inetcnf_tmp}" ]
@@ -236,9 +262,9 @@ update_inetd_conf() {
then
if [ "${_with_comment}" -eq 0 ]
then
- /usr/bin/sed -e 's/@COMMENT@[ \t]*//' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
+ /usr/bin/sed -e 's/@COMMENT@[[:space:]]*//' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
else
- /usr/bin/sed -e 's/@COMMENT@[ \t]*/# /' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
+ /usr/bin/sed -e 's/@COMMENT@[[:space:]]*/# /' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
fi
if /usr/bin/mv "${_sshd_inetd_conf_tmp}" "${_sshd_inetd_conf}"
then
@@ -251,13 +277,13 @@ update_inetd_conf() {
elif [ -f "${_inetcnf}" ]
then
- /usr/bin/grep -q '^[ \t]*sshd' "${_inetcnf}" && _with_comment=0
+ /usr/bin/grep -q '^[[:space:]]*sshd' "${_inetcnf}" && _with_comment=0
# check for sshd in top-level inetd.conf file, and remove
# will be replaced by a file in inetd.d/
- if [ `/usr/bin/grep -q '^[# \t]*sshd' "${_inetcnf}"; echo $?` -eq 0 ]
+ if [ `/usr/bin/grep -q '^#\?[[:space:]]*sshd' "${_inetcnf}"; echo $?` -eq 0 ]
then
- /usr/bin/grep -v '^[# \t]*sshd' "${_inetcnf}" >> "${_inetcnf_tmp}"
+ /usr/bin/grep -v '^#\?[[:space:]]*sshd' "${_inetcnf}" >> "${_inetcnf_tmp}"
if [ -f "${_inetcnf_tmp}" ]
then
if /usr/bin/mv "${_inetcnf_tmp}" "${_inetcnf}"
@@ -305,17 +331,26 @@ check_service_files_ownership() {
if [ -z "${run_service_as}" ]
then
- accnt_name=$(/usr/bin/cygrunsrv -VQ sshd | /usr/bin/sed -ne 's/^Account *: *//gp')
+ accnt_name=$(/usr/bin/cygrunsrv -VQ sshd |
+ /usr/bin/sed -ne 's/^Account *: *//gp')
if [ "${accnt_name}" = "LocalSystem" ]
then
# Convert "LocalSystem" to "SYSTEM" as is the correct account name
- accnt_name="SYSTEM:"
- elif [[ "${accnt_name}" =~ ^\.\\ ]]
- then
- # Convert "." domain to local machine name
- accnt_name="U-${COMPUTERNAME}${accnt_name#.},"
+ run_service_as="SYSTEM"
+ else
+ dom="${accnt_name%%\\*}"
+ accnt_name="${accnt_name#*\\}"
+ if [ "${dom}" = '.' ]
+ then
+ # Check local account
+ run_service_as=$(/usr/bin/mkpasswd -l -u "${accnt_name}" |
+ /usr/bin/awk -F: '{print $1;}')
+ else
+ # Check domain
+ run_service_as=$(/usr/bin/mkpasswd -d "${dom}" -u "${accnt_name}" |
+ /usr/bin/awk -F: '{print $1;}')
+ fi
fi
- run_service_as=$(/usr/bin/grep -Fi "${accnt_name}" /etc/passwd | /usr/bin/awk -F: '{print $1;}')
if [ -z "${run_service_as}" ]
then
csih_warning "Couldn't determine name of user running sshd service from /etc/passwd!"
@@ -615,32 +650,6 @@ echo
warning_cnt=0
-# Check for ${SYSCONFDIR} directory
-csih_make_dir "${SYSCONFDIR}" "Cannot create global configuration files."
-if ! /usr/bin/chmod 775 "${SYSCONFDIR}" >/dev/null 2>&1
-then
- csih_warning "Can't set permissions on ${SYSCONFDIR}!"
- let ++warning_cnt
-fi
-if ! /usr/bin/setfacl -m u:system:rwx "${SYSCONFDIR}" >/dev/null 2>&1
-then
- csih_warning "Can't set extended permissions on ${SYSCONFDIR}!"
- let ++warning_cnt
-fi
-
-# Check for /var/log directory
-csih_make_dir "${LOCALSTATEDIR}/log" "Cannot create log directory."
-if ! /usr/bin/chmod 775 "${LOCALSTATEDIR}/log" >/dev/null 2>&1
-then
- csih_warning "Can't set permissions on ${LOCALSTATEDIR}/log!"
- let ++warning_cnt
-fi
-if ! /usr/bin/setfacl -m u:system:rwx "${LOCALSTATEDIR}/log" >/dev/null 2>&1
-then
- csih_warning "Can't set extended permissions on ${LOCALSTATEDIR}/log!"
- let ++warning_cnt
-fi
-
# Create /var/log/lastlog if not already exists
if [ -e ${LOCALSTATEDIR}/log/lastlog -a ! -f ${LOCALSTATEDIR}/log/lastlog ]
then
@@ -665,13 +674,9 @@ then
csih_warning "Can't set permissions on ${LOCALSTATEDIR}/empty!"
let ++warning_cnt
fi
-if ! /usr/bin/setfacl -m u:system:rwx "${LOCALSTATEDIR}/empty" >/dev/null 2>&1
-then
- csih_warning "Can't set extended permissions on ${LOCALSTATEDIR}/empty!"
- let ++warning_cnt
-fi
# generate missing host keys
+csih_inform "Generating missing SSH host keys"
/usr/bin/ssh-keygen -A || let warning_cnt+=$?
# handle ssh_config
@@ -690,10 +695,11 @@ fi
csih_install_config "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults" || let ++warning_cnt
if ! /usr/bin/cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1
then
- /usr/bin/grep -q UsePrivilegeSeparation ${SYSCONFDIR}/sshd_config && privsep_configured=yes
+ sshd_config_configured=yes
fi
+sshd_strictmodes || let warning_cnt+=$?
sshd_privsep || let warning_cnt+=$?
-
+sshd_config_tweak || let warning_cnt+=$?
update_services_file || let warning_cnt+=$?
update_inetd_conf || let warning_cnt+=$?
install_service || let warning_cnt+=$?
diff --git a/contrib/redhat/openssh.spec b/contrib/redhat/openssh.spec
index 96401c6ee32b..9bdce1e3c225 100644
--- a/contrib/redhat/openssh.spec
+++ b/contrib/redhat/openssh.spec
@@ -1,4 +1,4 @@
-%define ver 6.6p1
+%define ver 6.7p1
%define rel 1
# OpenSSH privilege separation requires a user & group ID
@@ -86,7 +86,7 @@ PreReq: initscripts >= 5.00
%else
Requires: initscripts >= 5.20
%endif
-BuildRequires: perl, openssl-devel, tcp_wrappers
+BuildRequires: perl, openssl-devel
BuildRequires: /bin/login
%if ! %{build6x}
BuildPreReq: glibc-devel, pam
@@ -192,7 +192,6 @@ echo K5DIR=$K5DIR
--sysconfdir=%{_sysconfdir}/ssh \
--libexecdir=%{_libexecdir}/openssh \
--datadir=%{_datadir}/openssh \
- --with-tcp-wrappers \
--with-rsh=%{_bindir}/rsh \
--with-default-path=/usr/local/bin:/bin:/usr/bin \
--with-superuser-path=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin \
diff --git a/contrib/suse/openssh.spec b/contrib/suse/openssh.spec
index 0515d6d7cd87..f87674317682 100644
--- a/contrib/suse/openssh.spec
+++ b/contrib/suse/openssh.spec
@@ -13,7 +13,7 @@
Summary: OpenSSH, a free Secure Shell (SSH) protocol implementation
Name: openssh
-Version: 6.6p1
+Version: 6.7p1
URL: http://www.openssh.com/
Release: 1
Source0: openssh-%{version}.tar.gz
@@ -28,11 +28,9 @@ Provides: ssh
# (Build[ing] Prereq[uisites] only work for RPM 2.95 and newer.)
# building prerequisites -- stuff for
# OpenSSL (openssl-devel),
-# TCP Wrappers (tcpd-devel),
# and Gnome (glibdev, gtkdev, and gnlibsd)
#
BuildPrereq: openssl
-BuildPrereq: tcpd-devel
BuildPrereq: zlib-devel
#BuildPrereq: glibdev
#BuildPrereq: gtkdev
@@ -140,7 +138,6 @@ CFLAGS="$RPM_OPT_FLAGS" \
--mandir=%{_mandir} \
--with-privsep-path=/var/lib/empty \
--with-pam \
- --with-tcp-wrappers \
--libexecdir=%{_libdir}/ssh
make
diff --git a/defines.h b/defines.h
index 354d5b614cec..3ac8be987539 100644
--- a/defines.h
+++ b/defines.h
@@ -25,7 +25,7 @@
#ifndef _DEFINES_H
#define _DEFINES_H
-/* $Id: defines.h,v 1.176 2014/01/17 13:12:38 dtucker Exp $ */
+/* $Id: defines.h,v 1.183 2014/09/02 19:33:26 djm Exp $ */
/* Constants */
@@ -405,7 +405,7 @@ struct winsize {
/* user may have set a different path */
#if defined(_PATH_MAILDIR) && defined(MAIL_DIRECTORY)
-# undef _PATH_MAILDIR MAILDIR
+# undef _PATH_MAILDIR
#endif /* defined(_PATH_MAILDIR) && defined(MAIL_DIRECTORY) */
#ifdef MAIL_DIRECTORY
@@ -603,10 +603,6 @@ struct winsize {
# define memmove(s1, s2, n) bcopy((s2), (s1), (n))
#endif /* !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) */
-#if defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX)
-# define USE_VHANGUP
-#endif /* defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) */
-
#ifndef GETPGRP_VOID
# include <unistd.h>
# define getpgrp() getpgrp(0)
@@ -826,4 +822,23 @@ struct winsize {
# define arc4random_stir()
#endif
+#ifndef HAVE_VA_COPY
+# ifdef HAVE___VA_COPY
+# define va_copy(dest, src) __va_copy(dest, src)
+# else
+# define va_copy(dest, src) (dest) = (src)
+# endif
+#endif
+
+#ifndef __predict_true
+# if defined(__GNUC__) && \
+ ((__GNUC__ > (2)) || (__GNUC__ == (2) && __GNUC_MINOR__ >= (96)))
+# define __predict_true(exp) __builtin_expect(((exp) != 0), 1)
+# define __predict_false(exp) __builtin_expect(((exp) != 0), 0)
+# else
+# define __predict_true(exp) ((exp) != 0)
+# define __predict_false(exp) ((exp) != 0)
+# endif /* gcc version */
+#endif /* __predict_true */
+
#endif /* _DEFINES_H */
diff --git a/digest-libc.c b/digest-libc.c
index 1804b069840b..1b4423a05cf6 100644
--- a/digest-libc.c
+++ b/digest-libc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: digest-libc.c,v 1.2 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: digest-libc.c,v 1.3 2014/06/24 01:13:21 djm Exp $ */
/*
* Copyright (c) 2013 Damien Miller <djm@mindrot.org>
* Copyright (c) 2014 Markus Friedl. All rights reserved.
@@ -28,7 +28,8 @@
#include <sha1.h>
#include <sha2.h>
-#include "buffer.h"
+#include "ssherr.h"
+#include "sshbuf.h"
#include "digest.h"
typedef void md_init_fn(void *mdctx);
@@ -164,7 +165,7 @@ ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
const struct ssh_digest *digest = ssh_digest_by_alg(from->alg);
if (digest == NULL || from->alg != to->alg)
- return -1;
+ return SSH_ERR_INVALID_ARGUMENT;
memcpy(to->mdctx, from->mdctx, digest->ctx_len);
return 0;
}
@@ -175,15 +176,15 @@ ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
if (digest == NULL)
- return -1;
+ return SSH_ERR_INVALID_ARGUMENT;
digest->md_update(ctx->mdctx, m, mlen);
return 0;
}
int
-ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b)
+ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b)
{
- return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b));
+ return ssh_digest_update(ctx, sshbuf_ptr(b), sshbuf_len(b));
}
int
@@ -192,11 +193,11 @@ ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
if (digest == NULL)
- return -1;
+ return SSH_ERR_INVALID_ARGUMENT;
if (dlen > UINT_MAX)
- return -1;
+ return SSH_ERR_INVALID_ARGUMENT;
if (dlen < digest->digest_len) /* No truncation allowed */
- return -1;
+ return SSH_ERR_INVALID_ARGUMENT;
digest->md_final(d, ctx->mdctx);
return 0;
}
@@ -223,16 +224,16 @@ ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
struct ssh_digest_ctx *ctx = ssh_digest_start(alg);
if (ctx == NULL)
- return -1;
+ return SSH_ERR_INVALID_ARGUMENT;
if (ssh_digest_update(ctx, m, mlen) != 0 ||
ssh_digest_final(ctx, d, dlen) != 0)
- return -1;
+ return SSH_ERR_INVALID_ARGUMENT;
ssh_digest_free(ctx);
return 0;
}
int
-ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen)
+ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen)
{
- return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen);
+ return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen);
}
diff --git a/digest-openssl.c b/digest-openssl.c
index 863d37d03b8c..02b1703412d2 100644
--- a/digest-openssl.c
+++ b/digest-openssl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: digest-openssl.c,v 1.2 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: digest-openssl.c,v 1.4 2014/07/03 03:26:43 djm Exp $ */
/*
* Copyright (c) 2013 Damien Miller <djm@mindrot.org>
*
@@ -26,8 +26,18 @@
#include "openbsd-compat/openssl-compat.h"
-#include "buffer.h"
+#include "sshbuf.h"
#include "digest.h"
+#include "ssherr.h"
+
+#ifndef HAVE_EVP_RIPEMD160
+# define EVP_ripemd160 NULL
+#endif /* HAVE_EVP_RIPEMD160 */
+#ifndef HAVE_EVP_SHA256
+# define EVP_sha256 NULL
+# define EVP_sha384 NULL
+# define EVP_sha512 NULL
+#endif /* HAVE_EVP_SHA256 */
struct ssh_digest_ctx {
int alg;
@@ -46,11 +56,9 @@ const struct ssh_digest digests[] = {
{ SSH_DIGEST_MD5, "MD5", 16, EVP_md5 },
{ SSH_DIGEST_RIPEMD160, "RIPEMD160", 20, EVP_ripemd160 },
{ SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 },
-#ifdef HAVE_EVP_SHA256 /* XXX replace with local if missing */
{ SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 },
{ SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 },
{ SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 },
-#endif
{ -1, NULL, 0, NULL },
};
@@ -61,6 +69,8 @@ ssh_digest_by_alg(int alg)
return NULL;
if (digests[alg].id != alg) /* sanity */
return NULL;
+ if (digests[alg].mdfunc == NULL)
+ return NULL;
return &(digests[alg]);
}
@@ -98,9 +108,11 @@ ssh_digest_start(int alg)
int
ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
{
+ if (from->alg != to->alg)
+ return SSH_ERR_INVALID_ARGUMENT;
/* we have bcopy-style order while openssl has memcpy-style */
if (!EVP_MD_CTX_copy_ex(&to->mdctx, &from->mdctx))
- return -1;
+ return SSH_ERR_LIBCRYPTO_ERROR;
return 0;
}
@@ -108,14 +120,14 @@ int
ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
{
if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1)
- return -1;
+ return SSH_ERR_LIBCRYPTO_ERROR;
return 0;
}
int
-ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b)
+ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b)
{
- return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b));
+ return ssh_digest_update(ctx, sshbuf_ptr(b), sshbuf_len(b));
}
int
@@ -125,13 +137,13 @@ ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
u_int l = dlen;
if (dlen > UINT_MAX)
- return -1;
+ return SSH_ERR_INVALID_ARGUMENT;
if (dlen < digest->digest_len) /* No truncation allowed */
- return -1;
+ return SSH_ERR_INVALID_ARGUMENT;
if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1)
- return -1;
+ return SSH_ERR_LIBCRYPTO_ERROR;
if (l != digest->digest_len) /* sanity */
- return -1;
+ return SSH_ERR_INTERNAL_ERROR;
return 0;
}
@@ -148,19 +160,23 @@ ssh_digest_free(struct ssh_digest_ctx *ctx)
int
ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
{
- struct ssh_digest_ctx *ctx = ssh_digest_start(alg);
-
- if (ctx == NULL)
- return -1;
- if (ssh_digest_update(ctx, m, mlen) != 0 ||
- ssh_digest_final(ctx, d, dlen) != 0)
- return -1;
- ssh_digest_free(ctx);
+ const struct ssh_digest *digest = ssh_digest_by_alg(alg);
+ u_int mdlen;
+
+ if (digest == NULL)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if (dlen > UINT_MAX)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if (dlen < digest->digest_len)
+ return SSH_ERR_INVALID_ARGUMENT;
+ mdlen = dlen;
+ if (!EVP_Digest(m, mlen, d, &mdlen, digest->mdfunc(), NULL))
+ return SSH_ERR_LIBCRYPTO_ERROR;
return 0;
}
int
-ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen)
+ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen)
{
- return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen);
+ return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen);
}
diff --git a/digest.h b/digest.h
index 0fb207fcaa17..6afb197f0a28 100644
--- a/digest.h
+++ b/digest.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: digest.h,v 1.2 2014/01/27 18:58:14 markus Exp $ */
+/* $OpenBSD: digest.h,v 1.6 2014/07/03 04:36:45 djm Exp $ */
/*
* Copyright (c) 2013 Damien Miller <djm@mindrot.org>
*
@@ -30,6 +30,7 @@
#define SSH_DIGEST_SHA512 5
#define SSH_DIGEST_MAX 6
+struct sshbuf;
struct ssh_digest_ctx;
/* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */
@@ -47,14 +48,15 @@ int ssh_digest_memory(int alg, const void *m, size_t mlen,
u_char *d, size_t dlen)
__attribute__((__bounded__(__buffer__, 2, 3)))
__attribute__((__bounded__(__buffer__, 4, 5)));
-int ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen)
+int ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen)
__attribute__((__bounded__(__buffer__, 3, 4)));
/* Update API */
struct ssh_digest_ctx *ssh_digest_start(int alg);
int ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
__attribute__((__bounded__(__buffer__, 2, 3)));
-int ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b);
+int ssh_digest_update_buffer(struct ssh_digest_ctx *ctx,
+ const struct sshbuf *b);
int ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
__attribute__((__bounded__(__buffer__, 2, 3)));
void ssh_digest_free(struct ssh_digest_ctx *ctx);
diff --git a/dns.c b/dns.c
index 630b97ae84dc..c4d073cf50fa 100644
--- a/dns.c
+++ b/dns.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.c,v 1.29 2013/05/17 00:13:13 djm Exp $ */
+/* $OpenBSD: dns.c,v 1.31 2014/06/24 01:13:21 djm Exp $ */
/*
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -34,6 +34,8 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
#include "xmalloc.h"
#include "key.h"
@@ -96,6 +98,11 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
if (!*digest_type)
*digest_type = SSHFP_HASH_SHA256;
break;
+ case KEY_ED25519:
+ *algorithm = SSHFP_KEY_ED25519;
+ if (!*digest_type)
+ *digest_type = SSHFP_HASH_SHA256;
+ break;
default:
*algorithm = SSHFP_KEY_RESERVED; /* 0 */
*digest_type = SSHFP_HASH_RESERVED; /* 0 */
diff --git a/dns.h b/dns.h
index d5f428177803..b9feae6bef64 100644
--- a/dns.h
+++ b/dns.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.h,v 1.12 2012/05/23 03:28:28 djm Exp $ */
+/* $OpenBSD: dns.h,v 1.13 2014/04/20 09:24:26 logan Exp $ */
/*
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -32,7 +32,8 @@ enum sshfp_types {
SSHFP_KEY_RESERVED = 0,
SSHFP_KEY_RSA = 1,
SSHFP_KEY_DSA = 2,
- SSHFP_KEY_ECDSA = 3
+ SSHFP_KEY_ECDSA = 3,
+ SSHFP_KEY_ED25519 = 4
};
enum sshfp_hashes {
diff --git a/entropy.c b/entropy.c
index 2d483b39174c..1e9d52ac4605 100644
--- a/entropy.c
+++ b/entropy.c
@@ -43,6 +43,8 @@
#include <openssl/crypto.h>
#include <openssl/err.h>
+#include "openbsd-compat/openssl-compat.h"
+
#include "ssh.h"
#include "misc.h"
#include "xmalloc.h"
@@ -209,16 +211,7 @@ seed_rng(void)
#ifndef OPENSSL_PRNG_ONLY
unsigned char buf[RANDOM_SEED_SIZE];
#endif
- /*
- * OpenSSL version numbers: MNNFFPPS: major minor fix patch status
- * We match major, minor, fix and status (not patch) for <1.0.0.
- * After that, we acceptable compatible fix versions (so we
- * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed
- * within a patch series.
- */
- u_long version_mask = SSLeay() >= 0x1000000f ? ~0xffff0L : ~0xff0L;
- if (((SSLeay() ^ OPENSSL_VERSION_NUMBER) & version_mask) ||
- (SSLeay() >> 12) < (OPENSSL_VERSION_NUMBER >> 12))
+ if (!ssh_compatible_openssl(OPENSSL_VERSION_NUMBER, SSLeay()))
fatal("OpenSSL version mismatch. Built against %lx, you "
"have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay());
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
index 759fa104f782..795992d9f7d9 100644
--- a/gss-serv-krb5.c
+++ b/gss-serv-krb5.c
@@ -39,6 +39,7 @@
#include "hostfile.h"
#include "auth.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "buffer.h"
diff --git a/gss-serv.c b/gss-serv.c
index e61b37becc76..5c599247bb21 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gss-serv.c,v 1.26 2014/02/26 20:28:44 djm Exp $ */
+/* $OpenBSD: gss-serv.c,v 1.27 2014/07/03 03:34:09 djm Exp $ */
/*
* Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@@ -97,13 +97,13 @@ static OM_uint32
ssh_gssapi_acquire_cred(Gssctxt *ctx)
{
OM_uint32 status;
- char lname[MAXHOSTNAMELEN];
+ char lname[NI_MAXHOST];
gss_OID_set oidset;
gss_create_empty_oid_set(&status, &oidset);
gss_add_oid_set_member(&status, ctx->oid, &oidset);
- if (gethostname(lname, MAXHOSTNAMELEN)) {
+ if (gethostname(lname, sizeof(lname))) {
gss_release_oid_set(&status, &oidset);
return (-1);
}
diff --git a/hmac.h b/hmac.h
index 2374a6955793..42b33d002889 100644
--- a/hmac.h
+++ b/hmac.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: hmac.h,v 1.6 2014/01/27 18:58:14 markus Exp $ */
+/* $OpenBSD: hmac.h,v 1.9 2014/06/24 01:13:21 djm Exp $ */
/*
* Copyright (c) 2014 Markus Friedl. All rights reserved.
*
@@ -21,6 +21,7 @@
/* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */
size_t ssh_hmac_bytes(int alg);
+struct sshbuf;
struct ssh_hmac_ctx;
struct ssh_hmac_ctx *ssh_hmac_start(int alg);
@@ -29,7 +30,7 @@ int ssh_hmac_init(struct ssh_hmac_ctx *ctx, const void *key, size_t klen)
__attribute__((__bounded__(__buffer__, 2, 3)));
int ssh_hmac_update(struct ssh_hmac_ctx *ctx, const void *m, size_t mlen)
__attribute__((__bounded__(__buffer__, 2, 3)));
-int ssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const Buffer *b);
+int ssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const struct sshbuf *b);
int ssh_hmac_final(struct ssh_hmac_ctx *ctx, u_char *d, size_t dlen)
__attribute__((__bounded__(__buffer__, 2, 3)));
void ssh_hmac_free(struct ssh_hmac_ctx *ctx);
diff --git a/hostfile.c b/hostfile.c
index 8bc9540b71de..ee2daf45f020 100644
--- a/hostfile.c
+++ b/hostfile.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hostfile.c,v 1.55 2014/01/31 16:39:19 tedu Exp $ */
+/* $OpenBSD: hostfile.c,v 1.57 2014/06/24 01:13:21 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -47,6 +47,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
#include "xmalloc.h"
#include "match.h"
@@ -182,6 +183,7 @@ 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)) {
@@ -191,6 +193,7 @@ hostfile_check_key(int bits, const Key *key, const char *host,
logit("Warning: replace %d with %d in %s, line %lu.",
bits, BN_num_bits(key->rsa->n), filename, linenum);
}
+#endif
return 1;
}
@@ -296,11 +299,15 @@ load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path)
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;
diff --git a/kex.c b/kex.c
index 74e2b8682e12..a173e70e381c 100644
--- a/kex.c
+++ b/kex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.c,v 1.98 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: kex.c,v 1.99 2014/04/29 18:01:49 markus Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
@@ -33,7 +33,9 @@
#include <stdlib.h>
#include <string.h>
+#ifdef WITH_OPENSSL
#include <openssl/crypto.h>
+#endif
#include "xmalloc.h"
#include "ssh2.h"
@@ -70,12 +72,13 @@ struct kexalg {
int hash_alg;
};
static const struct kexalg kexalgs[] = {
+#ifdef WITH_OPENSSL
{ KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
{ KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
#ifdef HAVE_EVP_SHA256
{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
-#endif
+#endif /* HAVE_EVP_SHA256 */
#ifdef OPENSSL_HAS_ECC
{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
@@ -84,12 +87,13 @@ static const struct kexalg kexalgs[] = {
# ifdef OPENSSL_HAS_NISTP521
{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
SSH_DIGEST_SHA512 },
-# endif
-#endif
+# 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
{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
-#endif
+#endif /* HAVE_EVP_SHA256 */
{ NULL, -1, -1, -1},
};
@@ -615,6 +619,7 @@ kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen,
}
}
+#ifdef WITH_OPENSSL
void
kex_derive_keys_bn(Kex *kex, u_char *hash, u_int hashlen, const BIGNUM *secret)
{
@@ -626,6 +631,7 @@ kex_derive_keys_bn(Kex *kex, u_char *hash, u_int hashlen, const BIGNUM *secret)
buffer_ptr(&shared_secret), buffer_len(&shared_secret));
buffer_free(&shared_secret);
}
+#endif
Newkeys *
kex_get_newkeys(int mode)
@@ -637,6 +643,7 @@ kex_get_newkeys(int mode)
return ret;
}
+#ifdef WITH_SSH1
void
derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
u_int8_t cookie[8], u_int8_t id[16])
@@ -669,6 +676,7 @@ derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
explicit_bzero(nbuf, sizeof(nbuf));
explicit_bzero(obuf, sizeof(obuf));
}
+#endif
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
void
diff --git a/kex.h b/kex.h
index c85680eea4dd..4c40ec851859 100644
--- a/kex.h
+++ b/kex.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.h,v 1.62 2014/01/27 18:58:14 markus Exp $ */
+/* $OpenBSD: kex.h,v 1.64 2014/05/02 03:27:54 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
diff --git a/kexc25519.c b/kexc25519.c
index ee79b4327ee1..e3afa005512a 100644
--- a/kexc25519.c
+++ b/kexc25519.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexc25519.c,v 1.5 2014/01/31 16:39:19 tedu Exp $ */
+/* $OpenBSD: kexc25519.c,v 1.7 2014/05/02 03:27:54 djm Exp $ */
/*
* Copyright (c) 2001, 2013 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
diff --git a/key.c b/key.c
index 168e1b7d7d3a..206076159a9c 100644
--- a/key.c
+++ b/key.c
@@ -1,2089 +1,242 @@
-/* $OpenBSD: key.c,v 1.116 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: key.c,v 1.122 2014/07/22 01:18:50 dtucker Exp $ */
/*
- * read_bignum():
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- *
- * 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".
- *
- *
- * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
- * Copyright (c) 2008 Alexander von Gernler. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * placed in the public domain
*/
#include "includes.h"
#include <sys/param.h>
#include <sys/types.h>
-
-#include "crypto_api.h"
-
-#include <openssl/evp.h>
-#include <openbsd-compat/openssl-compat.h>
-
+#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
-#include <string.h>
-#include "xmalloc.h"
+#define SSH_KEY_NO_DEFINE
#include "key.h"
-#include "rsa.h"
-#include "uuencode.h"
-#include "buffer.h"
-#include "log.h"
-#include "misc.h"
-#include "ssh2.h"
-#include "digest.h"
-
-static int to_blob(const Key *, u_char **, u_int *, int);
-static Key *key_from_blob2(const u_char *, u_int, int);
-
-static struct KeyCert *
-cert_new(void)
-{
- struct KeyCert *cert;
-
- cert = xcalloc(1, sizeof(*cert));
- buffer_init(&cert->certblob);
- buffer_init(&cert->critical);
- buffer_init(&cert->extensions);
- cert->key_id = NULL;
- cert->principals = NULL;
- cert->signature_key = NULL;
- return cert;
-}
-
-Key *
-key_new(int type)
-{
- Key *k;
- RSA *rsa;
- DSA *dsa;
- k = xcalloc(1, sizeof(*k));
- k->type = type;
- k->ecdsa = NULL;
- k->ecdsa_nid = -1;
- k->dsa = NULL;
- k->rsa = NULL;
- k->cert = NULL;
- k->ed25519_sk = NULL;
- k->ed25519_pk = NULL;
- switch (k->type) {
- case KEY_RSA1:
- case KEY_RSA:
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- if ((rsa = RSA_new()) == NULL)
- fatal("key_new: RSA_new failed");
- if ((rsa->n = BN_new()) == NULL)
- fatal("key_new: BN_new failed");
- if ((rsa->e = BN_new()) == NULL)
- fatal("key_new: BN_new failed");
- k->rsa = rsa;
- break;
- case KEY_DSA:
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- if ((dsa = DSA_new()) == NULL)
- fatal("key_new: DSA_new failed");
- if ((dsa->p = BN_new()) == NULL)
- fatal("key_new: BN_new failed");
- if ((dsa->q = BN_new()) == NULL)
- fatal("key_new: BN_new failed");
- if ((dsa->g = BN_new()) == NULL)
- fatal("key_new: BN_new failed");
- if ((dsa->pub_key = BN_new()) == NULL)
- fatal("key_new: BN_new failed");
- k->dsa = dsa;
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA:
- case KEY_ECDSA_CERT:
- /* Cannot do anything until we know the group */
- break;
-#endif
- case KEY_ED25519:
- case KEY_ED25519_CERT:
- /* no need to prealloc */
- break;
- case KEY_UNSPEC:
- break;
- default:
- fatal("key_new: bad key type %d", k->type);
- break;
- }
- if (key_is_cert(k))
- k->cert = cert_new();
-
- return k;
-}
+#include "compat.h"
+#include "sshkey.h"
+#include "ssherr.h"
+#include "log.h"
+#include "authfile.h"
void
key_add_private(Key *k)
{
- switch (k->type) {
- case KEY_RSA1:
- case KEY_RSA:
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- if ((k->rsa->d = BN_new()) == NULL)
- fatal("key_new_private: BN_new failed");
- if ((k->rsa->iqmp = BN_new()) == NULL)
- fatal("key_new_private: BN_new failed");
- if ((k->rsa->q = BN_new()) == NULL)
- fatal("key_new_private: BN_new failed");
- if ((k->rsa->p = BN_new()) == NULL)
- fatal("key_new_private: BN_new failed");
- if ((k->rsa->dmq1 = BN_new()) == NULL)
- fatal("key_new_private: BN_new failed");
- if ((k->rsa->dmp1 = BN_new()) == NULL)
- fatal("key_new_private: BN_new failed");
- break;
- case KEY_DSA:
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- if ((k->dsa->priv_key = BN_new()) == NULL)
- fatal("key_new_private: BN_new failed");
- break;
- case KEY_ECDSA:
- case KEY_ECDSA_CERT:
- /* Cannot do anything until we know the group */
- break;
- case KEY_ED25519:
- case KEY_ED25519_CERT:
- /* no need to prealloc */
- break;
- case KEY_UNSPEC:
- break;
- default:
- break;
- }
+ int r;
+
+ if ((r = sshkey_add_private(k)) != 0)
+ fatal("%s: %s", __func__, ssh_err(r));
}
Key *
key_new_private(int type)
{
- Key *k = key_new(type);
-
- key_add_private(k);
- return k;
-}
-
-static void
-cert_free(struct KeyCert *cert)
-{
- u_int i;
-
- buffer_free(&cert->certblob);
- buffer_free(&cert->critical);
- buffer_free(&cert->extensions);
- free(cert->key_id);
- for (i = 0; i < cert->nprincipals; i++)
- free(cert->principals[i]);
- free(cert->principals);
- if (cert->signature_key != NULL)
- key_free(cert->signature_key);
- free(cert);
-}
-
-void
-key_free(Key *k)
-{
- if (k == NULL)
- fatal("key_free: key is NULL");
- switch (k->type) {
- case KEY_RSA1:
- case KEY_RSA:
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- if (k->rsa != NULL)
- RSA_free(k->rsa);
- k->rsa = NULL;
- break;
- case KEY_DSA:
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- if (k->dsa != NULL)
- DSA_free(k->dsa);
- k->dsa = NULL;
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA:
- case KEY_ECDSA_CERT:
- if (k->ecdsa != NULL)
- EC_KEY_free(k->ecdsa);
- k->ecdsa = NULL;
- break;
-#endif
- case KEY_ED25519:
- case KEY_ED25519_CERT:
- if (k->ed25519_pk) {
- explicit_bzero(k->ed25519_pk, ED25519_PK_SZ);
- free(k->ed25519_pk);
- k->ed25519_pk = NULL;
- }
- if (k->ed25519_sk) {
- explicit_bzero(k->ed25519_sk, ED25519_SK_SZ);
- free(k->ed25519_sk);
- k->ed25519_sk = NULL;
- }
- break;
- case KEY_UNSPEC:
- break;
- default:
- fatal("key_free: bad key type %d", k->type);
- break;
- }
- if (key_is_cert(k)) {
- if (k->cert != NULL)
- cert_free(k->cert);
- k->cert = NULL;
- }
-
- free(k);
-}
-
-static int
-cert_compare(struct KeyCert *a, struct KeyCert *b)
-{
- if (a == NULL && b == NULL)
- return 1;
- if (a == NULL || b == NULL)
- return 0;
- if (buffer_len(&a->certblob) != buffer_len(&b->certblob))
- return 0;
- if (timingsafe_bcmp(buffer_ptr(&a->certblob), buffer_ptr(&b->certblob),
- buffer_len(&a->certblob)) != 0)
- return 0;
- return 1;
-}
-
-/*
- * Compare public portions of key only, allowing comparisons between
- * certificates and plain keys too.
- */
-int
-key_equal_public(const Key *a, const Key *b)
-{
-#ifdef OPENSSL_HAS_ECC
- BN_CTX *bnctx;
-#endif
+ Key *ret = NULL;
- if (a == NULL || b == NULL ||
- key_type_plain(a->type) != key_type_plain(b->type))
- return 0;
-
- switch (a->type) {
- case KEY_RSA1:
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- case KEY_RSA:
- return a->rsa != NULL && b->rsa != NULL &&
- BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
- BN_cmp(a->rsa->n, b->rsa->n) == 0;
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- case KEY_DSA:
- return a->dsa != NULL && b->dsa != NULL &&
- BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
- BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
- BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
- BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA_CERT:
- case KEY_ECDSA:
- if (a->ecdsa == NULL || b->ecdsa == NULL ||
- EC_KEY_get0_public_key(a->ecdsa) == NULL ||
- EC_KEY_get0_public_key(b->ecdsa) == NULL)
- return 0;
- if ((bnctx = BN_CTX_new()) == NULL)
- fatal("%s: BN_CTX_new failed", __func__);
- if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa),
- EC_KEY_get0_group(b->ecdsa), bnctx) != 0 ||
- EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa),
- EC_KEY_get0_public_key(a->ecdsa),
- EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) {
- BN_CTX_free(bnctx);
- return 0;
- }
- BN_CTX_free(bnctx);
- return 1;
-#endif /* OPENSSL_HAS_ECC */
- case KEY_ED25519:
- case KEY_ED25519_CERT:
- return a->ed25519_pk != NULL && b->ed25519_pk != NULL &&
- memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0;
- default:
- fatal("key_equal: bad key type %d", a->type);
- }
- /* NOTREACHED */
-}
-
-int
-key_equal(const Key *a, const Key *b)
-{
- if (a == NULL || b == NULL || a->type != b->type)
- return 0;
- if (key_is_cert(a)) {
- if (!cert_compare(a->cert, b->cert))
- return 0;
- }
- return key_equal_public(a, b);
+ if ((ret = sshkey_new_private(type)) == NULL)
+ fatal("%s: failed", __func__);
+ return ret;
}
u_char*
key_fingerprint_raw(const Key *k, enum fp_type dgst_type,
u_int *dgst_raw_length)
{
- u_char *blob = NULL;
- u_char *retval = NULL;
- u_int len = 0;
- int nlen, elen, hash_alg = -1;
-
- *dgst_raw_length = 0;
-
- /* XXX switch to DIGEST_* directly? */
- switch (dgst_type) {
- case SSH_FP_MD5:
- hash_alg = SSH_DIGEST_MD5;
- break;
- case SSH_FP_SHA1:
- hash_alg = SSH_DIGEST_SHA1;
- break;
- case SSH_FP_SHA256:
- hash_alg = SSH_DIGEST_SHA256;
- break;
- default:
- fatal("%s: bad digest type %d", __func__, dgst_type);
- }
- switch (k->type) {
- case KEY_RSA1:
- nlen = BN_num_bytes(k->rsa->n);
- elen = BN_num_bytes(k->rsa->e);
- len = nlen + elen;
- blob = xmalloc(len);
- BN_bn2bin(k->rsa->n, blob);
- BN_bn2bin(k->rsa->e, blob + nlen);
- break;
- case KEY_DSA:
- case KEY_ECDSA:
- case KEY_RSA:
- case KEY_ED25519:
- key_to_blob(k, &blob, &len);
- break;
- case KEY_DSA_CERT_V00:
- case KEY_RSA_CERT_V00:
- case KEY_DSA_CERT:
- case KEY_ECDSA_CERT:
- case KEY_RSA_CERT:
- case KEY_ED25519_CERT:
- /* We want a fingerprint of the _key_ not of the cert */
- to_blob(k, &blob, &len, 1);
- break;
- case KEY_UNSPEC:
- return retval;
- default:
- fatal("%s: bad key type %d", __func__, k->type);
- break;
- }
- if (blob != NULL) {
- retval = xmalloc(SSH_DIGEST_MAX_LENGTH);
- if ((ssh_digest_memory(hash_alg, blob, len,
- retval, SSH_DIGEST_MAX_LENGTH)) != 0)
- fatal("%s: digest_memory failed", __func__);
- explicit_bzero(blob, len);
- free(blob);
- *dgst_raw_length = ssh_digest_bytes(hash_alg);
- } else {
- fatal("%s: blob is null", __func__);
- }
- return retval;
-}
-
-static char *
-key_fingerprint_hex(u_char *dgst_raw, u_int dgst_raw_len)
-{
- char *retval;
- u_int i;
-
- retval = xcalloc(1, dgst_raw_len * 3 + 1);
- for (i = 0; i < dgst_raw_len; i++) {
- char hex[4];
- snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
- strlcat(retval, hex, dgst_raw_len * 3 + 1);
- }
-
- /* Remove the trailing ':' character */
- retval[(dgst_raw_len * 3) - 1] = '\0';
- return retval;
-}
-
-static char *
-key_fingerprint_bubblebabble(u_char *dgst_raw, u_int dgst_raw_len)
-{
- char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
- char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
- 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
- u_int i, j = 0, rounds, seed = 1;
- char *retval;
-
- rounds = (dgst_raw_len / 2) + 1;
- retval = xcalloc((rounds * 6), sizeof(char));
- retval[j++] = 'x';
- for (i = 0; i < rounds; i++) {
- u_int idx0, idx1, idx2, idx3, idx4;
- if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
- idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
- seed) % 6;
- idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
- idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
- (seed / 6)) % 6;
- retval[j++] = vowels[idx0];
- retval[j++] = consonants[idx1];
- retval[j++] = vowels[idx2];
- if ((i + 1) < rounds) {
- idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
- idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
- retval[j++] = consonants[idx3];
- retval[j++] = '-';
- retval[j++] = consonants[idx4];
- seed = ((seed * 5) +
- ((((u_int)(dgst_raw[2 * i])) * 7) +
- ((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
- }
- } else {
- idx0 = seed % 6;
- idx1 = 16;
- idx2 = seed / 6;
- retval[j++] = vowels[idx0];
- retval[j++] = consonants[idx1];
- retval[j++] = vowels[idx2];
- }
- }
- retval[j++] = 'x';
- retval[j++] = '\0';
- return retval;
-}
-
-/*
- * Draw an ASCII-Art representing the fingerprint so human brain can
- * profit from its built-in pattern recognition ability.
- * This technique is called "random art" and can be found in some
- * scientific publications like this original paper:
- *
- * "Hash Visualization: a New Technique to improve Real-World Security",
- * Perrig A. and Song D., 1999, International Workshop on Cryptographic
- * Techniques and E-Commerce (CrypTEC '99)
- * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
- *
- * The subject came up in a talk by Dan Kaminsky, too.
- *
- * If you see the picture is different, the key is different.
- * If the picture looks the same, you still know nothing.
- *
- * The algorithm used here is a worm crawling over a discrete plane,
- * leaving a trace (augmenting the field) everywhere it goes.
- * Movement is taken from dgst_raw 2bit-wise. Bumping into walls
- * makes the respective movement vector be ignored for this turn.
- * Graphs are not unambiguous, because circles in graphs can be
- * walked in either direction.
- */
-
-/*
- * Field sizes for the random art. Have to be odd, so the starting point
- * can be in the exact middle of the picture, and FLDBASE should be >=8 .
- * Else pictures would be too dense, and drawing the frame would
- * fail, too, because the key type would not fit in anymore.
- */
-#define FLDBASE 8
-#define FLDSIZE_Y (FLDBASE + 1)
-#define FLDSIZE_X (FLDBASE * 2 + 1)
-static char *
-key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k)
-{
- /*
- * Chars to be used after each other every time the worm
- * intersects with itself. Matter of taste.
- */
- char *augmentation_string = " .o+=*BOX@%&#/^SE";
- char *retval, *p;
- u_char field[FLDSIZE_X][FLDSIZE_Y];
- u_int i, b;
- int x, y;
- size_t len = strlen(augmentation_string) - 1;
-
- retval = xcalloc(1, (FLDSIZE_X + 3) * (FLDSIZE_Y + 2));
-
- /* initialize field */
- memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
- x = FLDSIZE_X / 2;
- y = FLDSIZE_Y / 2;
-
- /* process raw key */
- for (i = 0; i < dgst_raw_len; i++) {
- int input;
- /* each byte conveys four 2-bit move commands */
- input = dgst_raw[i];
- for (b = 0; b < 4; b++) {
- /* evaluate 2 bit, rest is shifted later */
- x += (input & 0x1) ? 1 : -1;
- y += (input & 0x2) ? 1 : -1;
-
- /* assure we are still in bounds */
- x = MAX(x, 0);
- y = MAX(y, 0);
- x = MIN(x, FLDSIZE_X - 1);
- y = MIN(y, FLDSIZE_Y - 1);
-
- /* augment the field */
- if (field[x][y] < len - 2)
- field[x][y]++;
- input = input >> 2;
- }
- }
-
- /* mark starting point and end point*/
- field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
- field[x][y] = len;
-
- /* fill in retval */
- snprintf(retval, FLDSIZE_X, "+--[%4s %4u]", key_type(k), key_size(k));
- p = strchr(retval, '\0');
-
- /* output upper border */
- for (i = p - retval - 1; i < FLDSIZE_X; i++)
- *p++ = '-';
- *p++ = '+';
- *p++ = '\n';
-
- /* output content */
- for (y = 0; y < FLDSIZE_Y; y++) {
- *p++ = '|';
- for (x = 0; x < FLDSIZE_X; x++)
- *p++ = augmentation_string[MIN(field[x][y], len)];
- *p++ = '|';
- *p++ = '\n';
- }
-
- /* output lower border */
- *p++ = '+';
- for (i = 0; i < FLDSIZE_X; i++)
- *p++ = '-';
- *p++ = '+';
-
- return retval;
-}
-
-char *
-key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
-{
- char *retval = NULL;
- u_char *dgst_raw;
- u_int dgst_raw_len;
-
- dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len);
- if (!dgst_raw)
- fatal("key_fingerprint: null from key_fingerprint_raw()");
- switch (dgst_rep) {
- case SSH_FP_HEX:
- retval = key_fingerprint_hex(dgst_raw, dgst_raw_len);
- break;
- case SSH_FP_BUBBLEBABBLE:
- retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
- break;
- case SSH_FP_RANDOMART:
- retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len, k);
- break;
- default:
- fatal("key_fingerprint: bad digest representation %d",
- dgst_rep);
- break;
- }
- explicit_bzero(dgst_raw, dgst_raw_len);
- free(dgst_raw);
- return retval;
-}
-
-/*
- * Reads a multiple-precision integer in decimal from the buffer, and advances
- * the pointer. The integer must already be initialized. This function is
- * permitted to modify the buffer. This leaves *cpp to point just beyond the
- * last processed (and maybe modified) character. Note that this may modify
- * the buffer containing the number.
- */
-static int
-read_bignum(char **cpp, BIGNUM * value)
-{
- char *cp = *cpp;
- int old;
-
- /* Skip any leading whitespace. */
- for (; *cp == ' ' || *cp == '\t'; cp++)
- ;
-
- /* Check that it begins with a decimal digit. */
- if (*cp < '0' || *cp > '9')
- return 0;
-
- /* Save starting position. */
- *cpp = cp;
-
- /* Move forward until all decimal digits skipped. */
- for (; *cp >= '0' && *cp <= '9'; cp++)
- ;
-
- /* Save the old terminating character, and replace it by \0. */
- old = *cp;
- *cp = 0;
-
- /* Parse the number. */
- if (BN_dec2bn(&value, *cpp) == 0)
- return 0;
-
- /* Restore old terminating character. */
- *cp = old;
-
- /* Move beyond the number and return success. */
- *cpp = cp;
- return 1;
-}
-
-static int
-write_bignum(FILE *f, BIGNUM *num)
-{
- char *buf = BN_bn2dec(num);
- if (buf == NULL) {
- error("write_bignum: BN_bn2dec() failed");
- return 0;
- }
- fprintf(f, " %s", buf);
- OPENSSL_free(buf);
- return 1;
+ 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;
}
-/* returns 1 ok, -1 error */
int
key_read(Key *ret, char **cpp)
{
- Key *k;
- int success = -1;
- char *cp, *space;
- int len, n, type;
- u_int bits;
- u_char *blob;
-#ifdef OPENSSL_HAS_ECC
- int curve_nid = -1;
-#endif
-
- cp = *cpp;
-
- switch (ret->type) {
- case KEY_RSA1:
- /* Get number of bits. */
- if (*cp < '0' || *cp > '9')
- return -1; /* Bad bit count... */
- for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
- bits = 10 * bits + *cp - '0';
- if (bits == 0)
- return -1;
- *cpp = cp;
- /* Get public exponent, public modulus. */
- if (!read_bignum(cpp, ret->rsa->e))
- return -1;
- if (!read_bignum(cpp, ret->rsa->n))
- return -1;
- /* validate the claimed number of bits */
- if ((u_int)BN_num_bits(ret->rsa->n) != bits) {
- verbose("key_read: claimed key size %d does not match "
- "actual %d", bits, BN_num_bits(ret->rsa->n));
- return -1;
- }
- success = 1;
- break;
- case KEY_UNSPEC:
- case KEY_RSA:
- case KEY_DSA:
- case KEY_ECDSA:
- case KEY_ED25519:
- case KEY_DSA_CERT_V00:
- case KEY_RSA_CERT_V00:
- case KEY_DSA_CERT:
- case KEY_ECDSA_CERT:
- case KEY_RSA_CERT:
- case KEY_ED25519_CERT:
- space = strchr(cp, ' ');
- if (space == NULL) {
- debug3("key_read: missing whitespace");
- return -1;
- }
- *space = '\0';
- type = key_type_from_name(cp);
-#ifdef OPENSSL_HAS_ECC
- if (key_type_plain(type) == KEY_ECDSA &&
- (curve_nid = key_ecdsa_nid_from_name(cp)) == -1) {
- debug("key_read: invalid curve");
- return -1;
- }
-#endif
- *space = ' ';
- if (type == KEY_UNSPEC) {
- debug3("key_read: missing keytype");
- return -1;
- }
- cp = space+1;
- if (*cp == '\0') {
- debug3("key_read: short string");
- return -1;
- }
- if (ret->type == KEY_UNSPEC) {
- ret->type = type;
- } else if (ret->type != type) {
- /* is a key, but different type */
- debug3("key_read: type mismatch");
- return -1;
- }
- len = 2*strlen(cp);
- blob = xmalloc(len);
- n = uudecode(cp, blob, len);
- if (n < 0) {
- error("key_read: uudecode %s failed", cp);
- free(blob);
- return -1;
- }
- k = key_from_blob(blob, (u_int)n);
- free(blob);
- if (k == NULL) {
- error("key_read: key_from_blob %s failed", cp);
- return -1;
- }
- if (k->type != type) {
- error("key_read: type mismatch: encoding error");
- key_free(k);
- return -1;
- }
-#ifdef OPENSSL_HAS_ECC
- if (key_type_plain(type) == KEY_ECDSA &&
- curve_nid != k->ecdsa_nid) {
- error("key_read: type mismatch: EC curve mismatch");
- key_free(k);
- return -1;
- }
-#endif
-/*XXXX*/
- if (key_is_cert(ret)) {
- if (!key_is_cert(k)) {
- error("key_read: loaded key is not a cert");
- key_free(k);
- return -1;
- }
- if (ret->cert != NULL)
- cert_free(ret->cert);
- ret->cert = k->cert;
- k->cert = NULL;
- }
- if (key_type_plain(ret->type) == KEY_RSA) {
- if (ret->rsa != NULL)
- RSA_free(ret->rsa);
- ret->rsa = k->rsa;
- k->rsa = NULL;
-#ifdef DEBUG_PK
- RSA_print_fp(stderr, ret->rsa, 8);
-#endif
- }
- if (key_type_plain(ret->type) == KEY_DSA) {
- if (ret->dsa != NULL)
- DSA_free(ret->dsa);
- ret->dsa = k->dsa;
- k->dsa = NULL;
-#ifdef DEBUG_PK
- DSA_print_fp(stderr, ret->dsa, 8);
-#endif
- }
-#ifdef OPENSSL_HAS_ECC
- if (key_type_plain(ret->type) == KEY_ECDSA) {
- if (ret->ecdsa != NULL)
- EC_KEY_free(ret->ecdsa);
- ret->ecdsa = k->ecdsa;
- ret->ecdsa_nid = k->ecdsa_nid;
- k->ecdsa = NULL;
- k->ecdsa_nid = -1;
-#ifdef DEBUG_PK
- key_dump_ec_key(ret->ecdsa);
-#endif
- }
-#endif
- if (key_type_plain(ret->type) == KEY_ED25519) {
- free(ret->ed25519_pk);
- ret->ed25519_pk = k->ed25519_pk;
- k->ed25519_pk = NULL;
-#ifdef DEBUG_PK
- /* XXX */
-#endif
- }
- success = 1;
-/*XXXX*/
- key_free(k);
- if (success != 1)
- break;
- /* advance cp: skip whitespace and data */
- while (*cp == ' ' || *cp == '\t')
- cp++;
- while (*cp != '\0' && *cp != ' ' && *cp != '\t')
- cp++;
- *cpp = cp;
- break;
- default:
- fatal("key_read: bad key type: %d", ret->type);
- break;
- }
- return success;
+ return sshkey_read(ret, cpp) == 0 ? 1 : -1;
}
int
key_write(const Key *key, FILE *f)
{
- int n, success = 0;
- u_int len, bits = 0;
- u_char *blob;
- char *uu;
-
- if (key_is_cert(key)) {
- if (key->cert == NULL) {
- error("%s: no cert data", __func__);
- return 0;
- }
- if (buffer_len(&key->cert->certblob) == 0) {
- error("%s: no signed certificate blob", __func__);
- return 0;
- }
- }
-
- switch (key->type) {
- case KEY_RSA1:
- if (key->rsa == NULL)
- return 0;
- /* size of modulus 'n' */
- bits = BN_num_bits(key->rsa->n);
- fprintf(f, "%u", bits);
- if (write_bignum(f, key->rsa->e) &&
- write_bignum(f, key->rsa->n))
- return 1;
- error("key_write: failed for RSA key");
- return 0;
- case KEY_DSA:
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- if (key->dsa == NULL)
- return 0;
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA:
- case KEY_ECDSA_CERT:
- if (key->ecdsa == NULL)
- return 0;
- break;
-#endif
- case KEY_ED25519:
- case KEY_ED25519_CERT:
- if (key->ed25519_pk == NULL)
- return 0;
- break;
- case KEY_RSA:
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- if (key->rsa == NULL)
- return 0;
- break;
- default:
- return 0;
- }
-
- key_to_blob(key, &blob, &len);
- uu = xmalloc(2*len);
- n = uuencode(blob, len, uu, 2*len);
- if (n > 0) {
- fprintf(f, "%s %s", key_ssh_name(key), uu);
- success = 1;
- }
- free(blob);
- free(uu);
-
- return success;
-}
-
-const char *
-key_cert_type(const Key *k)
-{
- switch (k->cert->type) {
- case SSH2_CERT_TYPE_USER:
- return "user";
- case SSH2_CERT_TYPE_HOST:
- return "host";
- default:
- return "unknown";
- }
-}
-
-struct keytype {
- char *name;
- char *shortname;
- int type;
- int nid;
- int cert;
-};
-static const struct keytype keytypes[] = {
- { NULL, "RSA1", KEY_RSA1, 0, 0 },
- { "ssh-rsa", "RSA", KEY_RSA, 0, 0 },
- { "ssh-dss", "DSA", KEY_DSA, 0, 0 },
- { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0 },
-#ifdef OPENSSL_HAS_ECC
- { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0 },
- { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0 },
-# ifdef OPENSSL_HAS_NISTP521
- { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0 },
-# endif
-#endif /* OPENSSL_HAS_ECC */
- { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1 },
- { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1 },
-#ifdef OPENSSL_HAS_ECC
- { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT",
- KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1 },
- { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT",
- KEY_ECDSA_CERT, NID_secp384r1, 1 },
-# ifdef OPENSSL_HAS_NISTP521
- { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT",
- KEY_ECDSA_CERT, NID_secp521r1, 1 },
-# endif
-#endif /* OPENSSL_HAS_ECC */
- { "ssh-rsa-cert-v00@openssh.com", "RSA-CERT-V00",
- KEY_RSA_CERT_V00, 0, 1 },
- { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00",
- KEY_DSA_CERT_V00, 0, 1 },
- { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT",
- KEY_ED25519_CERT, 0, 1 },
- { NULL, NULL, -1, -1, 0 }
-};
-
-const char *
-key_type(const Key *k)
-{
- const struct keytype *kt;
-
- for (kt = keytypes; kt->type != -1; kt++) {
- if (kt->type == k->type)
- return kt->shortname;
- }
- return "unknown";
-}
-
-static const char *
-key_ssh_name_from_type_nid(int type, int nid)
-{
- const struct keytype *kt;
-
- for (kt = keytypes; kt->type != -1; kt++) {
- if (kt->type == type && (kt->nid == 0 || kt->nid == nid))
- return kt->name;
- }
- return "ssh-unknown";
-}
-
-const char *
-key_ssh_name(const Key *k)
-{
- return key_ssh_name_from_type_nid(k->type, k->ecdsa_nid);
-}
-
-const char *
-key_ssh_name_plain(const Key *k)
-{
- return key_ssh_name_from_type_nid(key_type_plain(k->type),
- k->ecdsa_nid);
-}
-
-int
-key_type_from_name(char *name)
-{
- const struct keytype *kt;
-
- for (kt = keytypes; kt->type != -1; kt++) {
- /* Only allow shortname matches for plain key types */
- if ((kt->name != NULL && strcmp(name, kt->name) == 0) ||
- (!kt->cert && strcasecmp(kt->shortname, name) == 0))
- return kt->type;
- }
- debug2("key_type_from_name: unknown key type '%s'", name);
- return KEY_UNSPEC;
-}
-
-int
-key_ecdsa_nid_from_name(const char *name)
-{
- const struct keytype *kt;
-
- for (kt = keytypes; kt->type != -1; kt++) {
- if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT)
- continue;
- if (kt->name != NULL && strcmp(name, kt->name) == 0)
- return kt->nid;
- }
- debug2("%s: unknown/non-ECDSA key type '%s'", __func__, name);
- return -1;
-}
-
-char *
-key_alg_list(int certs_only, int plain_only)
-{
- char *ret = NULL;
- size_t nlen, rlen = 0;
- const struct keytype *kt;
-
- for (kt = keytypes; kt->type != -1; kt++) {
- if (kt->name == NULL)
- continue;
- if ((certs_only && !kt->cert) || (plain_only && kt->cert))
- continue;
- if (ret != NULL)
- ret[rlen++] = '\n';
- nlen = strlen(kt->name);
- ret = xrealloc(ret, 1, rlen + nlen + 2);
- memcpy(ret + rlen, kt->name, nlen + 1);
- rlen += nlen;
- }
- return ret;
-}
-
-int
-key_type_is_cert(int type)
-{
- const struct keytype *kt;
-
- for (kt = keytypes; kt->type != -1; kt++) {
- if (kt->type == type)
- return kt->cert;
- }
- return 0;
-}
-
-static int
-key_type_is_valid_ca(int type)
-{
- switch (type) {
- case KEY_RSA:
- case KEY_DSA:
- case KEY_ECDSA:
- case KEY_ED25519:
- return 1;
- default:
- return 0;
- }
-}
-
-u_int
-key_size(const Key *k)
-{
- switch (k->type) {
- case KEY_RSA1:
- case KEY_RSA:
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- return BN_num_bits(k->rsa->n);
- case KEY_DSA:
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- return BN_num_bits(k->dsa->p);
- case KEY_ED25519:
- return 256; /* XXX */
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA:
- case KEY_ECDSA_CERT:
- return key_curve_nid_to_bits(k->ecdsa_nid);
-#endif
- }
- return 0;
-}
-
-static RSA *
-rsa_generate_private_key(u_int bits)
-{
- RSA *private = RSA_new();
- BIGNUM *f4 = BN_new();
-
- if (private == NULL)
- fatal("%s: RSA_new failed", __func__);
- if (f4 == NULL)
- fatal("%s: BN_new failed", __func__);
- if (!BN_set_word(f4, RSA_F4))
- fatal("%s: BN_new failed", __func__);
- if (!RSA_generate_key_ex(private, bits, f4, NULL))
- fatal("%s: key generation failed.", __func__);
- BN_free(f4);
- return private;
-}
-
-static DSA*
-dsa_generate_private_key(u_int bits)
-{
- DSA *private = DSA_new();
-
- if (private == NULL)
- fatal("%s: DSA_new failed", __func__);
- if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
- NULL, NULL))
- fatal("%s: DSA_generate_parameters failed", __func__);
- if (!DSA_generate_key(private))
- fatal("%s: DSA_generate_key failed.", __func__);
- return private;
-}
-
-int
-key_ecdsa_bits_to_nid(int bits)
-{
- switch (bits) {
-#ifdef OPENSSL_HAS_ECC
- case 256:
- return NID_X9_62_prime256v1;
- case 384:
- return NID_secp384r1;
-# ifdef OPENSSL_HAS_NISTP521
- case 521:
- return NID_secp521r1;
-# endif
-#endif
- default:
- return -1;
- }
-}
-
-#ifdef OPENSSL_HAS_ECC
-int
-key_ecdsa_key_to_nid(EC_KEY *k)
-{
- EC_GROUP *eg;
- int nids[] = {
- NID_X9_62_prime256v1,
- NID_secp384r1,
-# ifdef OPENSSL_HAS_NISTP521
- NID_secp521r1,
-# endif
- -1
- };
- int nid;
- u_int i;
- BN_CTX *bnctx;
- const EC_GROUP *g = EC_KEY_get0_group(k);
-
- /*
- * The group may be stored in a ASN.1 encoded private key in one of two
- * ways: as a "named group", which is reconstituted by ASN.1 object ID
- * or explicit group parameters encoded into the key blob. Only the
- * "named group" case sets the group NID for us, but we can figure
- * it out for the other case by comparing against all the groups that
- * are supported.
- */
- if ((nid = EC_GROUP_get_curve_name(g)) > 0)
- return nid;
- if ((bnctx = BN_CTX_new()) == NULL)
- fatal("%s: BN_CTX_new() failed", __func__);
- for (i = 0; nids[i] != -1; i++) {
- if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL)
- fatal("%s: EC_GROUP_new_by_curve_name failed",
- __func__);
- if (EC_GROUP_cmp(g, eg, bnctx) == 0)
- break;
- EC_GROUP_free(eg);
- }
- BN_CTX_free(bnctx);
- debug3("%s: nid = %d", __func__, nids[i]);
- if (nids[i] != -1) {
- /* Use the group with the NID attached */
- EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
- if (EC_KEY_set_group(k, eg) != 1)
- fatal("%s: EC_KEY_set_group", __func__);
- }
- return nids[i];
-}
-
-static EC_KEY*
-ecdsa_generate_private_key(u_int bits, int *nid)
-{
- EC_KEY *private;
-
- if ((*nid = key_ecdsa_bits_to_nid(bits)) == -1)
- fatal("%s: invalid key length", __func__);
- if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL)
- fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
- if (EC_KEY_generate_key(private) != 1)
- fatal("%s: EC_KEY_generate_key failed", __func__);
- EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE);
- return private;
+ return sshkey_write(key, f) == 0 ? 1 : 0;
}
-#endif /* OPENSSL_HAS_ECC */
Key *
key_generate(int type, u_int bits)
{
- Key *k = key_new(KEY_UNSPEC);
- switch (type) {
- case KEY_DSA:
- k->dsa = dsa_generate_private_key(bits);
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA:
- k->ecdsa = ecdsa_generate_private_key(bits, &k->ecdsa_nid);
- break;
-#endif
- case KEY_RSA:
- case KEY_RSA1:
- k->rsa = rsa_generate_private_key(bits);
- break;
- case KEY_ED25519:
- k->ed25519_pk = xmalloc(ED25519_PK_SZ);
- k->ed25519_sk = xmalloc(ED25519_SK_SZ);
- crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk);
- break;
- case KEY_RSA_CERT_V00:
- case KEY_DSA_CERT_V00:
- case KEY_RSA_CERT:
- case KEY_DSA_CERT:
- fatal("key_generate: cert keys cannot be generated directly");
- default:
- fatal("key_generate: unknown type %d", type);
- }
- k->type = type;
- return k;
+ int r;
+ Key *ret = NULL;
+
+ if ((r = sshkey_generate(type, bits, &ret)) != 0)
+ fatal("%s: %s", __func__, ssh_err(r));
+ return ret;
}
void
-key_cert_copy(const Key *from_key, struct Key *to_key)
+key_cert_copy(const Key *from_key, Key *to_key)
{
- u_int i;
- const struct KeyCert *from;
- struct KeyCert *to;
-
- if (to_key->cert != NULL) {
- cert_free(to_key->cert);
- to_key->cert = NULL;
- }
+ int r;
- if ((from = from_key->cert) == NULL)
- return;
-
- to = to_key->cert = cert_new();
-
- buffer_append(&to->certblob, buffer_ptr(&from->certblob),
- buffer_len(&from->certblob));
-
- buffer_append(&to->critical,
- buffer_ptr(&from->critical), buffer_len(&from->critical));
- buffer_append(&to->extensions,
- buffer_ptr(&from->extensions), buffer_len(&from->extensions));
-
- to->serial = from->serial;
- to->type = from->type;
- to->key_id = from->key_id == NULL ? NULL : xstrdup(from->key_id);
- to->valid_after = from->valid_after;
- to->valid_before = from->valid_before;
- to->signature_key = from->signature_key == NULL ?
- NULL : key_from_private(from->signature_key);
-
- to->nprincipals = from->nprincipals;
- if (to->nprincipals > CERT_MAX_PRINCIPALS)
- fatal("%s: nprincipals (%u) > CERT_MAX_PRINCIPALS (%u)",
- __func__, to->nprincipals, CERT_MAX_PRINCIPALS);
- if (to->nprincipals > 0) {
- to->principals = xcalloc(from->nprincipals,
- sizeof(*to->principals));
- for (i = 0; i < to->nprincipals; i++)
- to->principals[i] = xstrdup(from->principals[i]);
- }
+ if ((r = sshkey_cert_copy(from_key, to_key)) != 0)
+ fatal("%s: %s", __func__, ssh_err(r));
}
Key *
key_from_private(const Key *k)
{
- Key *n = NULL;
- switch (k->type) {
- case KEY_DSA:
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- n = key_new(k->type);
- if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) ||
- (BN_copy(n->dsa->q, k->dsa->q) == NULL) ||
- (BN_copy(n->dsa->g, k->dsa->g) == NULL) ||
- (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL))
- fatal("key_from_private: BN_copy failed");
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA:
- case KEY_ECDSA_CERT:
- n = key_new(k->type);
- n->ecdsa_nid = k->ecdsa_nid;
- if ((n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid)) == NULL)
- fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
- if (EC_KEY_set_public_key(n->ecdsa,
- EC_KEY_get0_public_key(k->ecdsa)) != 1)
- fatal("%s: EC_KEY_set_public_key failed", __func__);
- break;
-#endif
- case KEY_RSA:
- case KEY_RSA1:
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- n = key_new(k->type);
- if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
- (BN_copy(n->rsa->e, k->rsa->e) == NULL))
- fatal("key_from_private: BN_copy failed");
- break;
- case KEY_ED25519:
- case KEY_ED25519_CERT:
- n = key_new(k->type);
- if (k->ed25519_pk != NULL) {
- n->ed25519_pk = xmalloc(ED25519_PK_SZ);
- memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
- }
- break;
- default:
- fatal("key_from_private: unknown type %d", k->type);
- break;
- }
- if (key_is_cert(k))
- key_cert_copy(k, n);
- return n;
-}
-
-int
-key_names_valid2(const char *names)
-{
- char *s, *cp, *p;
-
- if (names == NULL || strcmp(names, "") == 0)
- return 0;
- s = cp = xstrdup(names);
- for ((p = strsep(&cp, ",")); p && *p != '\0';
- (p = strsep(&cp, ","))) {
- switch (key_type_from_name(p)) {
- case KEY_RSA1:
- case KEY_UNSPEC:
- free(s);
- return 0;
- }
- }
- debug3("key names ok: [%s]", names);
- free(s);
- return 1;
-}
-
-static int
-cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen)
-{
- u_char *principals, *critical, *exts, *sig_key, *sig;
- u_int signed_len, plen, clen, sklen, slen, kidlen, elen;
- Buffer tmp;
- char *principal;
- int ret = -1;
- int v00 = key->type == KEY_DSA_CERT_V00 ||
- key->type == KEY_RSA_CERT_V00;
-
- buffer_init(&tmp);
-
- /* Copy the entire key blob for verification and later serialisation */
- buffer_append(&key->cert->certblob, blob, blen);
-
- elen = 0; /* Not touched for v00 certs */
- principals = exts = critical = sig_key = sig = NULL;
- if ((!v00 && buffer_get_int64_ret(&key->cert->serial, b) != 0) ||
- buffer_get_int_ret(&key->cert->type, b) != 0 ||
- (key->cert->key_id = buffer_get_cstring_ret(b, &kidlen)) == NULL ||
- (principals = buffer_get_string_ret(b, &plen)) == NULL ||
- buffer_get_int64_ret(&key->cert->valid_after, b) != 0 ||
- buffer_get_int64_ret(&key->cert->valid_before, b) != 0 ||
- (critical = buffer_get_string_ret(b, &clen)) == NULL ||
- (!v00 && (exts = buffer_get_string_ret(b, &elen)) == NULL) ||
- (v00 && buffer_get_string_ptr_ret(b, NULL) == NULL) || /* nonce */
- buffer_get_string_ptr_ret(b, NULL) == NULL || /* reserved */
- (sig_key = buffer_get_string_ret(b, &sklen)) == NULL) {
- error("%s: parse error", __func__);
- goto out;
- }
-
- /* Signature is left in the buffer so we can calculate this length */
- signed_len = buffer_len(&key->cert->certblob) - buffer_len(b);
-
- if ((sig = buffer_get_string_ret(b, &slen)) == NULL) {
- error("%s: parse error", __func__);
- goto out;
- }
-
- if (key->cert->type != SSH2_CERT_TYPE_USER &&
- key->cert->type != SSH2_CERT_TYPE_HOST) {
- error("Unknown certificate type %u", key->cert->type);
- goto out;
- }
+ int r;
+ Key *ret = NULL;
- buffer_append(&tmp, principals, plen);
- while (buffer_len(&tmp) > 0) {
- if (key->cert->nprincipals >= CERT_MAX_PRINCIPALS) {
- error("%s: Too many principals", __func__);
- goto out;
- }
- if ((principal = buffer_get_cstring_ret(&tmp, &plen)) == NULL) {
- error("%s: Principals data invalid", __func__);
- goto out;
- }
- key->cert->principals = xrealloc(key->cert->principals,
- key->cert->nprincipals + 1, sizeof(*key->cert->principals));
- key->cert->principals[key->cert->nprincipals++] = principal;
- }
-
- buffer_clear(&tmp);
-
- buffer_append(&key->cert->critical, critical, clen);
- buffer_append(&tmp, critical, clen);
- /* validate structure */
- while (buffer_len(&tmp) != 0) {
- if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL ||
- buffer_get_string_ptr_ret(&tmp, NULL) == NULL) {
- error("%s: critical option data invalid", __func__);
- goto out;
- }
- }
- buffer_clear(&tmp);
-
- buffer_append(&key->cert->extensions, exts, elen);
- buffer_append(&tmp, exts, elen);
- /* validate structure */
- while (buffer_len(&tmp) != 0) {
- if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL ||
- buffer_get_string_ptr_ret(&tmp, NULL) == NULL) {
- error("%s: extension data invalid", __func__);
- goto out;
- }
- }
- buffer_clear(&tmp);
-
- if ((key->cert->signature_key = key_from_blob2(sig_key, sklen, 0))
- == NULL) {
- error("%s: Signature key invalid", __func__);
- goto out;
- }
- if (!key_type_is_valid_ca(key->cert->signature_key->type)) {
- error("%s: Invalid signature key type %s (%d)", __func__,
- key_type(key->cert->signature_key),
- key->cert->signature_key->type);
- goto out;
- }
-
- switch (key_verify(key->cert->signature_key, sig, slen,
- buffer_ptr(&key->cert->certblob), signed_len)) {
- case 1:
- ret = 0;
- break; /* Good signature */
- case 0:
- error("%s: Invalid signature on certificate", __func__);
- goto out;
- case -1:
- error("%s: Certificate signature verification failed",
- __func__);
- goto out;
- }
-
- out:
- buffer_free(&tmp);
- free(principals);
- free(critical);
- free(exts);
- free(sig_key);
- free(sig);
+ if ((r = sshkey_from_private(k, &ret)) != 0)
+ fatal("%s: %s", __func__, ssh_err(r));
return ret;
}
-static Key *
-key_from_blob2(const u_char *blob, u_int blen, int allow_cert)
+static void
+fatal_on_fatal_errors(int r, const char *func, int extra_fatal)
{
- Buffer b;
- int rlen, type;
- u_int len;
- char *ktype = NULL, *curve = NULL;
- u_char *pk = NULL;
- Key *key = NULL;
-#ifdef OPENSSL_HAS_ECC
- EC_POINT *q = NULL;
- int nid = -1;
-#endif
-
-#ifdef DEBUG_PK
- dump_base64(stderr, blob, blen);
-#endif
- buffer_init(&b);
- buffer_append(&b, blob, blen);
- if ((ktype = buffer_get_cstring_ret(&b, NULL)) == NULL) {
- error("key_from_blob: can't read key type");
- goto out;
- }
-
- type = key_type_from_name(ktype);
-#ifdef OPENSSL_HAS_ECC
- if (key_type_plain(type) == KEY_ECDSA)
- nid = key_ecdsa_nid_from_name(ktype);
-#endif
- if (!allow_cert && key_type_is_cert(type)) {
- error("key_from_blob: certificate not allowed in this context");
- goto out;
- }
- switch (type) {
- case KEY_RSA_CERT:
- (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
- /* FALLTHROUGH */
- case KEY_RSA:
- case KEY_RSA_CERT_V00:
- key = key_new(type);
- if (buffer_get_bignum2_ret(&b, key->rsa->e) == -1 ||
- buffer_get_bignum2_ret(&b, key->rsa->n) == -1) {
- error("key_from_blob: can't read rsa key");
- badkey:
- key_free(key);
- key = NULL;
- goto out;
- }
-#ifdef DEBUG_PK
- RSA_print_fp(stderr, key->rsa, 8);
-#endif
- break;
- case KEY_DSA_CERT:
- (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
- /* FALLTHROUGH */
- case KEY_DSA:
- case KEY_DSA_CERT_V00:
- key = key_new(type);
- if (buffer_get_bignum2_ret(&b, key->dsa->p) == -1 ||
- buffer_get_bignum2_ret(&b, key->dsa->q) == -1 ||
- buffer_get_bignum2_ret(&b, key->dsa->g) == -1 ||
- buffer_get_bignum2_ret(&b, key->dsa->pub_key) == -1) {
- error("key_from_blob: can't read dsa key");
- goto badkey;
- }
-#ifdef DEBUG_PK
- DSA_print_fp(stderr, key->dsa, 8);
-#endif
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA_CERT:
- (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
- /* FALLTHROUGH */
- case KEY_ECDSA:
- key = key_new(type);
- key->ecdsa_nid = nid;
- if ((curve = buffer_get_string_ret(&b, NULL)) == NULL) {
- error("key_from_blob: can't read ecdsa curve");
- goto badkey;
- }
- if (key->ecdsa_nid != key_curve_name_to_nid(curve)) {
- error("key_from_blob: ecdsa curve doesn't match type");
- goto badkey;
- }
- if (key->ecdsa != NULL)
- EC_KEY_free(key->ecdsa);
- if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid))
- == NULL)
- fatal("key_from_blob: EC_KEY_new_by_curve_name failed");
- if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL)
- fatal("key_from_blob: EC_POINT_new failed");
- if (buffer_get_ecpoint_ret(&b, EC_KEY_get0_group(key->ecdsa),
- q) == -1) {
- error("key_from_blob: can't read ecdsa key point");
- goto badkey;
- }
- if (key_ec_validate_public(EC_KEY_get0_group(key->ecdsa),
- q) != 0)
- goto badkey;
- if (EC_KEY_set_public_key(key->ecdsa, q) != 1)
- fatal("key_from_blob: EC_KEY_set_public_key failed");
-#ifdef DEBUG_PK
- key_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
-#endif
- break;
-#endif /* OPENSSL_HAS_ECC */
- case KEY_ED25519_CERT:
- (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
- /* FALLTHROUGH */
- case KEY_ED25519:
- if ((pk = buffer_get_string_ret(&b, &len)) == NULL) {
- error("key_from_blob: can't read ed25519 key");
- goto badkey;
- }
- if (len != ED25519_PK_SZ) {
- error("key_from_blob: ed25519 len %d != %d",
- len, ED25519_PK_SZ);
- goto badkey;
- }
- key = key_new(type);
- key->ed25519_pk = pk;
- pk = NULL;
- break;
- case KEY_UNSPEC:
- key = key_new(type);
- break;
- default:
- error("key_from_blob: cannot handle type %s", ktype);
- goto out;
- }
- if (key_is_cert(key) && cert_parse(&b, key, blob, blen) == -1) {
- error("key_from_blob: can't parse cert data");
- goto badkey;
- }
- rlen = buffer_len(&b);
- if (key != NULL && rlen != 0)
- error("key_from_blob: remaining bytes in key blob %d", rlen);
- out:
- free(ktype);
- free(curve);
- free(pk);
-#ifdef OPENSSL_HAS_ECC
- if (q != NULL)
- EC_POINT_free(q);
-#endif
- buffer_free(&b);
- return key;
+ if (r == SSH_ERR_INTERNAL_ERROR ||
+ r == SSH_ERR_ALLOC_FAIL ||
+ (extra_fatal != 0 && r == extra_fatal))
+ fatal("%s: %s", func, ssh_err(r));
}
Key *
key_from_blob(const u_char *blob, u_int blen)
{
- return key_from_blob2(blob, blen, 1);
+ int r;
+ Key *ret = NULL;
+
+ if ((r = sshkey_from_blob(blob, blen, &ret)) != 0) {
+ fatal_on_fatal_errors(r, __func__, 0);
+ error("%s: %s", __func__, ssh_err(r));
+ return NULL;
+ }
+ return ret;
}
-static int
-to_blob(const Key *key, u_char **blobp, u_int *lenp, int force_plain)
+int
+key_to_blob(const Key *key, u_char **blobp, u_int *lenp)
{
- Buffer b;
- int len, type;
+ u_char *blob;
+ size_t blen;
+ int r;
if (blobp != NULL)
*blobp = NULL;
if (lenp != NULL)
*lenp = 0;
- if (key == NULL) {
- error("key_to_blob: key == NULL");
- return 0;
- }
- buffer_init(&b);
- type = force_plain ? key_type_plain(key->type) : key->type;
- switch (type) {
- case KEY_DSA_CERT_V00:
- case KEY_RSA_CERT_V00:
- case KEY_DSA_CERT:
- case KEY_ECDSA_CERT:
- case KEY_RSA_CERT:
- case KEY_ED25519_CERT:
- /* Use the existing blob */
- buffer_append(&b, buffer_ptr(&key->cert->certblob),
- buffer_len(&key->cert->certblob));
- break;
- case KEY_DSA:
- buffer_put_cstring(&b,
- key_ssh_name_from_type_nid(type, key->ecdsa_nid));
- buffer_put_bignum2(&b, key->dsa->p);
- buffer_put_bignum2(&b, key->dsa->q);
- buffer_put_bignum2(&b, key->dsa->g);
- buffer_put_bignum2(&b, key->dsa->pub_key);
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA:
- buffer_put_cstring(&b,
- key_ssh_name_from_type_nid(type, key->ecdsa_nid));
- buffer_put_cstring(&b, key_curve_nid_to_name(key->ecdsa_nid));
- buffer_put_ecpoint(&b, EC_KEY_get0_group(key->ecdsa),
- EC_KEY_get0_public_key(key->ecdsa));
- break;
-#endif
- case KEY_RSA:
- buffer_put_cstring(&b,
- key_ssh_name_from_type_nid(type, key->ecdsa_nid));
- buffer_put_bignum2(&b, key->rsa->e);
- buffer_put_bignum2(&b, key->rsa->n);
- break;
- case KEY_ED25519:
- buffer_put_cstring(&b,
- key_ssh_name_from_type_nid(type, key->ecdsa_nid));
- buffer_put_string(&b, key->ed25519_pk, ED25519_PK_SZ);
- break;
- default:
- error("key_to_blob: unsupported key type %d", key->type);
- buffer_free(&b);
+ if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
+ fatal_on_fatal_errors(r, __func__, 0);
+ error("%s: %s", __func__, ssh_err(r));
return 0;
}
- len = buffer_len(&b);
+ if (blen > INT_MAX)
+ fatal("%s: giant len %zu", __func__, blen);
+ if (blobp != NULL)
+ *blobp = blob;
if (lenp != NULL)
- *lenp = len;
- if (blobp != NULL) {
- *blobp = xmalloc(len);
- memcpy(*blobp, buffer_ptr(&b), len);
- }
- explicit_bzero(buffer_ptr(&b), len);
- buffer_free(&b);
- return len;
-}
-
-int
-key_to_blob(const Key *key, u_char **blobp, u_int *lenp)
-{
- return to_blob(key, blobp, lenp, 0);
+ *lenp = blen;
+ return blen;
}
int
-key_sign(
- const Key *key,
- u_char **sigp, u_int *lenp,
+key_sign(const Key *key, u_char **sigp, u_int *lenp,
const u_char *data, u_int datalen)
{
- switch (key->type) {
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- case KEY_DSA:
- return ssh_dss_sign(key, sigp, lenp, data, datalen);
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA_CERT:
- case KEY_ECDSA:
- return ssh_ecdsa_sign(key, sigp, lenp, data, datalen);
-#endif
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- case KEY_RSA:
- return ssh_rsa_sign(key, sigp, lenp, data, datalen);
- case KEY_ED25519:
- case KEY_ED25519_CERT:
- return ssh_ed25519_sign(key, sigp, lenp, data, datalen);
- default:
- error("key_sign: invalid key type %d", key->type);
+ int r;
+ u_char *sig;
+ size_t siglen;
+
+ if (sigp != NULL)
+ *sigp = NULL;
+ if (lenp != NULL)
+ *lenp = 0;
+ if ((r = sshkey_sign(key, &sig, &siglen,
+ data, datalen, datafellows)) != 0) {
+ fatal_on_fatal_errors(r, __func__, 0);
+ error("%s: %s", __func__, ssh_err(r));
return -1;
}
+ if (siglen > INT_MAX)
+ fatal("%s: giant len %zu", __func__, siglen);
+ if (sigp != NULL)
+ *sigp = sig;
+ if (lenp != NULL)
+ *lenp = siglen;
+ return 0;
}
-/*
- * key_verify returns 1 for a correct signature, 0 for an incorrect signature
- * and -1 on error.
- */
int
-key_verify(
- const Key *key,
- const u_char *signature, u_int signaturelen,
+key_verify(const Key *key, const u_char *signature, u_int signaturelen,
const u_char *data, u_int datalen)
{
- if (signaturelen == 0)
- return -1;
+ int r;
- switch (key->type) {
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- case KEY_DSA:
- return ssh_dss_verify(key, signature, signaturelen, data, datalen);
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA_CERT:
- case KEY_ECDSA:
- return ssh_ecdsa_verify(key, signature, signaturelen, data, datalen);
-#endif
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- case KEY_RSA:
- return ssh_rsa_verify(key, signature, signaturelen, data, datalen);
- case KEY_ED25519:
- case KEY_ED25519_CERT:
- return ssh_ed25519_verify(key, signature, signaturelen, data, datalen);
- default:
- error("key_verify: invalid key type %d", key->type);
- return -1;
+ if ((r = sshkey_verify(key, signature, signaturelen,
+ data, datalen, datafellows)) != 0) {
+ fatal_on_fatal_errors(r, __func__, 0);
+ error("%s: %s", __func__, ssh_err(r));
+ return r == SSH_ERR_SIGNATURE_INVALID ? 0 : -1;
}
+ return 1;
}
-/* Converts a private to a public key */
Key *
key_demote(const Key *k)
{
- Key *pk;
-
- pk = xcalloc(1, sizeof(*pk));
- pk->type = k->type;
- pk->flags = k->flags;
- pk->ecdsa_nid = k->ecdsa_nid;
- pk->dsa = NULL;
- pk->ecdsa = NULL;
- pk->rsa = NULL;
- pk->ed25519_pk = NULL;
- pk->ed25519_sk = NULL;
-
- switch (k->type) {
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- key_cert_copy(k, pk);
- /* FALLTHROUGH */
- case KEY_RSA1:
- case KEY_RSA:
- if ((pk->rsa = RSA_new()) == NULL)
- fatal("key_demote: RSA_new failed");
- if ((pk->rsa->e = BN_dup(k->rsa->e)) == NULL)
- fatal("key_demote: BN_dup failed");
- if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL)
- fatal("key_demote: BN_dup failed");
- break;
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- key_cert_copy(k, pk);
- /* FALLTHROUGH */
- case KEY_DSA:
- if ((pk->dsa = DSA_new()) == NULL)
- fatal("key_demote: DSA_new failed");
- if ((pk->dsa->p = BN_dup(k->dsa->p)) == NULL)
- fatal("key_demote: BN_dup failed");
- if ((pk->dsa->q = BN_dup(k->dsa->q)) == NULL)
- fatal("key_demote: BN_dup failed");
- if ((pk->dsa->g = BN_dup(k->dsa->g)) == NULL)
- fatal("key_demote: BN_dup failed");
- if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL)
- fatal("key_demote: BN_dup failed");
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA_CERT:
- key_cert_copy(k, pk);
- /* FALLTHROUGH */
- case KEY_ECDSA:
- if ((pk->ecdsa = EC_KEY_new_by_curve_name(pk->ecdsa_nid)) == NULL)
- fatal("key_demote: EC_KEY_new_by_curve_name failed");
- if (EC_KEY_set_public_key(pk->ecdsa,
- EC_KEY_get0_public_key(k->ecdsa)) != 1)
- fatal("key_demote: EC_KEY_set_public_key failed");
- break;
-#endif
- case KEY_ED25519_CERT:
- key_cert_copy(k, pk);
- /* FALLTHROUGH */
- case KEY_ED25519:
- if (k->ed25519_pk != NULL) {
- pk->ed25519_pk = xmalloc(ED25519_PK_SZ);
- memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
- }
- break;
- default:
- fatal("key_demote: bad key type %d", k->type);
- break;
- }
-
- return (pk);
-}
+ int r;
+ Key *ret = NULL;
-int
-key_is_cert(const Key *k)
-{
- if (k == NULL)
- return 0;
- return key_type_is_cert(k->type);
-}
-
-/* Return the cert-less equivalent to a certified key type */
-int
-key_type_plain(int type)
-{
- switch (type) {
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- return KEY_RSA;
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- return KEY_DSA;
- case KEY_ECDSA_CERT:
- return KEY_ECDSA;
- case KEY_ED25519_CERT:
- return KEY_ED25519;
- default:
- return type;
- }
+ if ((r = sshkey_demote(k, &ret)) != 0)
+ fatal("%s: %s", __func__, ssh_err(r));
+ return ret;
}
-/* Convert a plain key to their _CERT equivalent */
int
key_to_certified(Key *k, int legacy)
{
- switch (k->type) {
- case KEY_RSA:
- k->cert = cert_new();
- k->type = legacy ? KEY_RSA_CERT_V00 : KEY_RSA_CERT;
- return 0;
- case KEY_DSA:
- k->cert = cert_new();
- k->type = legacy ? KEY_DSA_CERT_V00 : KEY_DSA_CERT;
- return 0;
- case KEY_ECDSA:
- if (legacy)
- fatal("%s: legacy ECDSA certificates are not supported",
- __func__);
- k->cert = cert_new();
- k->type = KEY_ECDSA_CERT;
- return 0;
- case KEY_ED25519:
- if (legacy)
- fatal("%s: legacy ED25519 certificates are not "
- "supported", __func__);
- k->cert = cert_new();
- k->type = KEY_ED25519_CERT;
- return 0;
- default:
- error("%s: key has incorrect type %s", __func__, key_type(k));
+ int r;
+
+ if ((r = sshkey_to_certified(k, legacy)) != 0) {
+ fatal_on_fatal_errors(r, __func__, 0);
+ error("%s: %s", __func__, ssh_err(r));
return -1;
}
+ return 0;
}
-/* Convert a certificate to its raw key equivalent */
int
key_drop_cert(Key *k)
{
- if (!key_type_is_cert(k->type)) {
- error("%s: key has incorrect type %s", __func__, key_type(k));
+ int r;
+
+ if ((r = sshkey_drop_cert(k)) != 0) {
+ fatal_on_fatal_errors(r, __func__, 0);
+ error("%s: %s", __func__, ssh_err(r));
return -1;
}
- cert_free(k->cert);
- k->cert = NULL;
- k->type = key_type_plain(k->type);
return 0;
}
-/* Sign a certified key, (re-)generating the signed certblob. */
int
key_certify(Key *k, Key *ca)
{
- Buffer principals;
- u_char *ca_blob, *sig_blob, nonce[32];
- u_int i, ca_len, sig_len;
-
- if (k->cert == NULL) {
- error("%s: key lacks cert info", __func__);
- return -1;
- }
-
- if (!key_is_cert(k)) {
- error("%s: certificate has unknown type %d", __func__,
- k->cert->type);
- return -1;
- }
-
- if (!key_type_is_valid_ca(ca->type)) {
- error("%s: CA key has unsupported type %s", __func__,
- key_type(ca));
- return -1;
- }
-
- key_to_blob(ca, &ca_blob, &ca_len);
-
- buffer_clear(&k->cert->certblob);
- buffer_put_cstring(&k->cert->certblob, key_ssh_name(k));
-
- /* -v01 certs put nonce first */
- arc4random_buf(&nonce, sizeof(nonce));
- if (!key_cert_is_legacy(k))
- buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
-
- /* XXX this substantially duplicates to_blob(); refactor */
- switch (k->type) {
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- buffer_put_bignum2(&k->cert->certblob, k->dsa->p);
- buffer_put_bignum2(&k->cert->certblob, k->dsa->q);
- buffer_put_bignum2(&k->cert->certblob, k->dsa->g);
- buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key);
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA_CERT:
- buffer_put_cstring(&k->cert->certblob,
- key_curve_nid_to_name(k->ecdsa_nid));
- buffer_put_ecpoint(&k->cert->certblob,
- EC_KEY_get0_group(k->ecdsa),
- EC_KEY_get0_public_key(k->ecdsa));
- break;
-#endif
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- buffer_put_bignum2(&k->cert->certblob, k->rsa->e);
- buffer_put_bignum2(&k->cert->certblob, k->rsa->n);
- break;
- case KEY_ED25519_CERT:
- buffer_put_string(&k->cert->certblob,
- k->ed25519_pk, ED25519_PK_SZ);
- break;
- default:
- error("%s: key has incorrect type %s", __func__, key_type(k));
- buffer_clear(&k->cert->certblob);
- free(ca_blob);
- return -1;
- }
-
- /* -v01 certs have a serial number next */
- if (!key_cert_is_legacy(k))
- buffer_put_int64(&k->cert->certblob, k->cert->serial);
-
- buffer_put_int(&k->cert->certblob, k->cert->type);
- buffer_put_cstring(&k->cert->certblob, k->cert->key_id);
-
- buffer_init(&principals);
- for (i = 0; i < k->cert->nprincipals; i++)
- buffer_put_cstring(&principals, k->cert->principals[i]);
- buffer_put_string(&k->cert->certblob, buffer_ptr(&principals),
- buffer_len(&principals));
- buffer_free(&principals);
-
- buffer_put_int64(&k->cert->certblob, k->cert->valid_after);
- buffer_put_int64(&k->cert->certblob, k->cert->valid_before);
- buffer_put_string(&k->cert->certblob,
- buffer_ptr(&k->cert->critical), buffer_len(&k->cert->critical));
-
- /* -v01 certs have non-critical options here */
- if (!key_cert_is_legacy(k)) {
- buffer_put_string(&k->cert->certblob,
- buffer_ptr(&k->cert->extensions),
- buffer_len(&k->cert->extensions));
- }
-
- /* -v00 certs put the nonce at the end */
- if (key_cert_is_legacy(k))
- buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
-
- buffer_put_string(&k->cert->certblob, NULL, 0); /* reserved */
- buffer_put_string(&k->cert->certblob, ca_blob, ca_len);
- free(ca_blob);
+ int r;
- /* Sign the whole mess */
- if (key_sign(ca, &sig_blob, &sig_len, buffer_ptr(&k->cert->certblob),
- buffer_len(&k->cert->certblob)) != 0) {
- error("%s: signature operation failed", __func__);
- buffer_clear(&k->cert->certblob);
+ if ((r = sshkey_certify(k, ca)) != 0) {
+ fatal_on_fatal_errors(r, __func__, 0);
+ error("%s: %s", __func__, ssh_err(r));
return -1;
}
- /* Append signature and we are done */
- buffer_put_string(&k->cert->certblob, sig_blob, sig_len);
- free(sig_blob);
-
return 0;
}
@@ -2091,535 +244,236 @@ int
key_cert_check_authority(const Key *k, int want_host, int require_principal,
const char *name, const char **reason)
{
- u_int i, principal_matches;
- time_t now = time(NULL);
-
- if (want_host) {
- if (k->cert->type != SSH2_CERT_TYPE_HOST) {
- *reason = "Certificate invalid: not a host certificate";
- return -1;
- }
- } else {
- if (k->cert->type != SSH2_CERT_TYPE_USER) {
- *reason = "Certificate invalid: not a user certificate";
- return -1;
- }
- }
- if (now < 0) {
- error("%s: system clock lies before epoch", __func__);
- *reason = "Certificate invalid: not yet valid";
- return -1;
- }
- if ((u_int64_t)now < k->cert->valid_after) {
- *reason = "Certificate invalid: not yet valid";
- return -1;
- }
- if ((u_int64_t)now >= k->cert->valid_before) {
- *reason = "Certificate invalid: expired";
+ int r;
+
+ if ((r = sshkey_cert_check_authority(k, want_host, require_principal,
+ name, reason)) != 0) {
+ fatal_on_fatal_errors(r, __func__, 0);
+ error("%s: %s", __func__, ssh_err(r));
return -1;
}
- if (k->cert->nprincipals == 0) {
- if (require_principal) {
- *reason = "Certificate lacks principal list";
- return -1;
- }
- } else if (name != NULL) {
- principal_matches = 0;
- for (i = 0; i < k->cert->nprincipals; i++) {
- if (strcmp(name, k->cert->principals[i]) == 0) {
- principal_matches = 1;
- break;
- }
- }
- if (!principal_matches) {
- *reason = "Certificate invalid: name is not a listed "
- "principal";
- return -1;
- }
- }
return 0;
}
+#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
int
-key_cert_is_legacy(const Key *k)
+key_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
{
- switch (k->type) {
- case KEY_DSA_CERT_V00:
- case KEY_RSA_CERT_V00:
- return 1;
- default:
- return 0;
+ int r;
+
+ if ((r = sshkey_ec_validate_public(group, public)) != 0) {
+ fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
+ error("%s: %s", __func__, ssh_err(r));
+ return -1;
}
+ return 0;
}
-/* XXX: these are really begging for a table-driven approach */
int
-key_curve_name_to_nid(const char *name)
+key_ec_validate_private(const EC_KEY *key)
{
-#ifdef OPENSSL_HAS_ECC
- if (strcmp(name, "nistp256") == 0)
- return NID_X9_62_prime256v1;
- else if (strcmp(name, "nistp384") == 0)
- return NID_secp384r1;
-# ifdef OPENSSL_HAS_NISTP521
- else if (strcmp(name, "nistp521") == 0)
- return NID_secp521r1;
-# endif
-#endif
-
- debug("%s: unsupported EC curve name \"%.100s\"", __func__, name);
- return -1;
+ int r;
+
+ if ((r = sshkey_ec_validate_private(key)) != 0) {
+ fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
+ error("%s: %s", __func__, ssh_err(r));
+ return -1;
+ }
+ return 0;
}
+#endif /* WITH_OPENSSL */
-u_int
-key_curve_nid_to_bits(int nid)
+void
+key_private_serialize(const Key *key, struct sshbuf *b)
{
- switch (nid) {
-#ifdef OPENSSL_HAS_ECC
- case NID_X9_62_prime256v1:
- return 256;
- case NID_secp384r1:
- return 384;
-# ifdef OPENSSL_HAS_NISTP521
- case NID_secp521r1:
- return 521;
-# endif
-#endif
- default:
- error("%s: unsupported EC curve nid %d", __func__, nid);
- return 0;
- }
+ int r;
+
+ if ((r = sshkey_private_serialize(key, b)) != 0)
+ fatal("%s: %s", __func__, ssh_err(r));
}
-const char *
-key_curve_nid_to_name(int nid)
+Key *
+key_private_deserialize(struct sshbuf *blob)
{
-#ifdef OPENSSL_HAS_ECC
- if (nid == NID_X9_62_prime256v1)
- return "nistp256";
- else if (nid == NID_secp384r1)
- return "nistp384";
-# ifdef OPENSSL_HAS_NISTP521
- else if (nid == NID_secp521r1)
- return "nistp521";
-# endif
-#endif
- error("%s: unsupported EC curve nid %d", __func__, nid);
- return NULL;
+ int r;
+ Key *ret = NULL;
+
+ if ((r = sshkey_private_deserialize(blob, &ret)) != 0) {
+ fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
+ error("%s: %s", __func__, ssh_err(r));
+ return NULL;
+ }
+ return ret;
}
-#ifdef OPENSSL_HAS_ECC
+/* authfile.c */
+
int
-key_ec_nid_to_hash_alg(int nid)
+key_save_private(Key *key, const char *filename, const char *passphrase,
+ const char *comment, int force_new_format, const char *new_format_cipher,
+ int new_format_rounds)
{
- int kbits = key_curve_nid_to_bits(nid);
-
- if (kbits == 0)
- fatal("%s: invalid nid %d", __func__, nid);
- /* RFC5656 section 6.2.1 */
- if (kbits <= 256)
- return SSH_DIGEST_SHA256;
- else if (kbits <= 384)
- return SSH_DIGEST_SHA384;
- else
- return SSH_DIGEST_SHA512;
+ int r;
+
+ if ((r = sshkey_save_private(key, filename, passphrase, comment,
+ force_new_format, new_format_cipher, new_format_rounds)) != 0) {
+ fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
+ error("%s: %s", __func__, ssh_err(r));
+ return 0;
+ }
+ return 1;
}
int
-key_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
+key_load_file(int fd, const char *filename, struct sshbuf *blob)
{
- BN_CTX *bnctx;
- EC_POINT *nq = NULL;
- BIGNUM *order, *x, *y, *tmp;
- int ret = -1;
-
- if ((bnctx = BN_CTX_new()) == NULL)
- fatal("%s: BN_CTX_new failed", __func__);
- BN_CTX_start(bnctx);
-
- /*
- * We shouldn't ever hit this case because bignum_get_ecpoint()
- * refuses to load GF2m points.
- */
- if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
- NID_X9_62_prime_field) {
- error("%s: group is not a prime field", __func__);
- goto out;
- }
+ int r;
- /* Q != infinity */
- if (EC_POINT_is_at_infinity(group, public)) {
- error("%s: received degenerate public key (infinity)",
- __func__);
- goto out;
+ if ((r = sshkey_load_file(fd, filename, blob)) != 0) {
+ fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
+ error("%s: %s", __func__, ssh_err(r));
+ return 0;
}
+ return 1;
+}
- if ((x = BN_CTX_get(bnctx)) == NULL ||
- (y = BN_CTX_get(bnctx)) == NULL ||
- (order = BN_CTX_get(bnctx)) == NULL ||
- (tmp = BN_CTX_get(bnctx)) == NULL)
- fatal("%s: BN_CTX_get failed", __func__);
-
- /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */
- if (EC_GROUP_get_order(group, order, bnctx) != 1)
- fatal("%s: EC_GROUP_get_order failed", __func__);
- if (EC_POINT_get_affine_coordinates_GFp(group, public,
- x, y, bnctx) != 1)
- fatal("%s: EC_POINT_get_affine_coordinates_GFp", __func__);
- if (BN_num_bits(x) <= BN_num_bits(order) / 2) {
- error("%s: public key x coordinate too small: "
- "bits(x) = %d, bits(order)/2 = %d", __func__,
- BN_num_bits(x), BN_num_bits(order) / 2);
- goto out;
- }
- if (BN_num_bits(y) <= BN_num_bits(order) / 2) {
- error("%s: public key y coordinate too small: "
- "bits(y) = %d, bits(order)/2 = %d", __func__,
- BN_num_bits(x), BN_num_bits(order) / 2);
- goto out;
+Key *
+key_load_cert(const char *filename)
+{
+ int r;
+ Key *ret = NULL;
+
+ if ((r = sshkey_load_cert(filename, &ret)) != 0) {
+ fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
+ /* Old authfile.c ignored all file errors. */
+ if (r == SSH_ERR_SYSTEM_ERROR)
+ debug("%s: %s", __func__, ssh_err(r));
+ else
+ error("%s: %s", __func__, ssh_err(r));
+ return NULL;
}
+ return ret;
- /* nQ == infinity (n == order of subgroup) */
- if ((nq = EC_POINT_new(group)) == NULL)
- fatal("%s: BN_CTX_tmp failed", __func__);
- if (EC_POINT_mul(group, nq, NULL, public, order, bnctx) != 1)
- fatal("%s: EC_GROUP_mul failed", __func__);
- if (EC_POINT_is_at_infinity(group, nq) != 1) {
- error("%s: received degenerate public key (nQ != infinity)",
- __func__);
- goto out;
- }
+}
- /* x < order - 1, y < order - 1 */
- if (!BN_sub(tmp, order, BN_value_one()))
- fatal("%s: BN_sub failed", __func__);
- if (BN_cmp(x, tmp) >= 0) {
- error("%s: public key x coordinate >= group order - 1",
- __func__);
- goto out;
- }
- if (BN_cmp(y, tmp) >= 0) {
- error("%s: public key y coordinate >= group order - 1",
- __func__);
- goto out;
+Key *
+key_load_public(const char *filename, char **commentp)
+{
+ int r;
+ Key *ret = NULL;
+
+ if ((r = sshkey_load_public(filename, &ret, commentp)) != 0) {
+ fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
+ /* Old authfile.c ignored all file errors. */
+ if (r == SSH_ERR_SYSTEM_ERROR)
+ debug("%s: %s", __func__, ssh_err(r));
+ else
+ error("%s: %s", __func__, ssh_err(r));
+ return NULL;
}
- ret = 0;
- out:
- BN_CTX_free(bnctx);
- EC_POINT_free(nq);
return ret;
}
-int
-key_ec_validate_private(const EC_KEY *key)
-{
- BN_CTX *bnctx;
- BIGNUM *order, *tmp;
- int ret = -1;
-
- if ((bnctx = BN_CTX_new()) == NULL)
- fatal("%s: BN_CTX_new failed", __func__);
- BN_CTX_start(bnctx);
-
- if ((order = BN_CTX_get(bnctx)) == NULL ||
- (tmp = BN_CTX_get(bnctx)) == NULL)
- fatal("%s: BN_CTX_get failed", __func__);
-
- /* log2(private) > log2(order)/2 */
- if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, bnctx) != 1)
- fatal("%s: EC_GROUP_get_order failed", __func__);
- if (BN_num_bits(EC_KEY_get0_private_key(key)) <=
- BN_num_bits(order) / 2) {
- error("%s: private key too small: "
- "bits(y) = %d, bits(order)/2 = %d", __func__,
- BN_num_bits(EC_KEY_get0_private_key(key)),
- BN_num_bits(order) / 2);
- goto out;
+Key *
+key_load_private(const char *path, const char *passphrase,
+ char **commentp)
+{
+ int r;
+ Key *ret = NULL;
+
+ if ((r = sshkey_load_private(path, passphrase, &ret, commentp)) != 0) {
+ fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
+ /* Old authfile.c ignored all file errors. */
+ if (r == SSH_ERR_SYSTEM_ERROR ||
+ 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;
+}
- /* private < order - 1 */
- if (!BN_sub(tmp, order, BN_value_one()))
- fatal("%s: BN_sub failed", __func__);
- if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0) {
- error("%s: private key >= group order - 1", __func__);
- goto out;
+Key *
+key_load_private_cert(int type, const char *filename, const char *passphrase,
+ int *perm_ok)
+{
+ int r;
+ Key *ret = NULL;
+
+ if ((r = sshkey_load_private_cert(type, filename, passphrase,
+ &ret, perm_ok)) != 0) {
+ fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
+ /* Old authfile.c ignored all file errors. */
+ if (r == SSH_ERR_SYSTEM_ERROR ||
+ r == SSH_ERR_KEY_WRONG_PASSPHRASE)
+ debug("%s: %s", __func__, ssh_err(r));
+ else
+ error("%s: %s", __func__, ssh_err(r));
+ return NULL;
}
- ret = 0;
- out:
- BN_CTX_free(bnctx);
return ret;
}
-#if defined(DEBUG_KEXECDH) || defined(DEBUG_PK)
-void
-key_dump_ec_point(const EC_GROUP *group, const EC_POINT *point)
-{
- BIGNUM *x, *y;
- BN_CTX *bnctx;
-
- if (point == NULL) {
- fputs("point=(NULL)\n", stderr);
- return;
+Key *
+key_load_private_type(int type, const char *filename, const char *passphrase,
+ char **commentp, int *perm_ok)
+{
+ int r;
+ Key *ret = NULL;
+
+ if ((r = sshkey_load_private_type(type, filename, passphrase,
+ &ret, commentp, perm_ok)) != 0) {
+ fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
+ /* Old authfile.c ignored all file errors. */
+ if (r == SSH_ERR_SYSTEM_ERROR ||
+ (r == SSH_ERR_KEY_WRONG_PASSPHRASE))
+ debug("%s: %s", __func__, ssh_err(r));
+ else
+ error("%s: %s", __func__, ssh_err(r));
+ return NULL;
}
- if ((bnctx = BN_CTX_new()) == NULL)
- fatal("%s: BN_CTX_new failed", __func__);
- BN_CTX_start(bnctx);
- if ((x = BN_CTX_get(bnctx)) == NULL || (y = BN_CTX_get(bnctx)) == NULL)
- fatal("%s: BN_CTX_get failed", __func__);
- if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
- NID_X9_62_prime_field)
- fatal("%s: group is not a prime field", __func__);
- if (EC_POINT_get_affine_coordinates_GFp(group, point, x, y, bnctx) != 1)
- fatal("%s: EC_POINT_get_affine_coordinates_GFp", __func__);
- fputs("x=", stderr);
- BN_print_fp(stderr, x);
- fputs("\ny=", stderr);
- BN_print_fp(stderr, y);
- fputs("\n", stderr);
- BN_CTX_free(bnctx);
+ return ret;
}
-void
-key_dump_ec_key(const EC_KEY *key)
-{
- const BIGNUM *exponent;
-
- key_dump_ec_point(EC_KEY_get0_group(key), EC_KEY_get0_public_key(key));
- fputs("exponent=", stderr);
- if ((exponent = EC_KEY_get0_private_key(key)) == NULL)
- fputs("(NULL)", stderr);
- else
- BN_print_fp(stderr, EC_KEY_get0_private_key(key));
- fputs("\n", stderr);
+#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 /* defined(DEBUG_KEXECDH) || defined(DEBUG_PK) */
-#endif /* OPENSSL_HAS_ECC */
+#endif /* WITH_OPENSSL */
-void
-key_private_serialize(const Key *key, Buffer *b)
+int
+key_perm_ok(int fd, const char *filename)
{
- buffer_put_cstring(b, key_ssh_name(key));
- switch (key->type) {
- case KEY_RSA:
- buffer_put_bignum2(b, key->rsa->n);
- buffer_put_bignum2(b, key->rsa->e);
- buffer_put_bignum2(b, key->rsa->d);
- buffer_put_bignum2(b, key->rsa->iqmp);
- buffer_put_bignum2(b, key->rsa->p);
- buffer_put_bignum2(b, key->rsa->q);
- break;
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
- fatal("%s: no cert/certblob", __func__);
- buffer_put_string(b, buffer_ptr(&key->cert->certblob),
- buffer_len(&key->cert->certblob));
- buffer_put_bignum2(b, key->rsa->d);
- buffer_put_bignum2(b, key->rsa->iqmp);
- buffer_put_bignum2(b, key->rsa->p);
- buffer_put_bignum2(b, key->rsa->q);
- break;
- case KEY_DSA:
- buffer_put_bignum2(b, key->dsa->p);
- buffer_put_bignum2(b, key->dsa->q);
- buffer_put_bignum2(b, key->dsa->g);
- buffer_put_bignum2(b, key->dsa->pub_key);
- buffer_put_bignum2(b, key->dsa->priv_key);
- break;
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
- fatal("%s: no cert/certblob", __func__);
- buffer_put_string(b, buffer_ptr(&key->cert->certblob),
- buffer_len(&key->cert->certblob));
- buffer_put_bignum2(b, key->dsa->priv_key);
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA:
- buffer_put_cstring(b, key_curve_nid_to_name(key->ecdsa_nid));
- buffer_put_ecpoint(b, EC_KEY_get0_group(key->ecdsa),
- EC_KEY_get0_public_key(key->ecdsa));
- buffer_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa));
- break;
- case KEY_ECDSA_CERT:
- if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
- fatal("%s: no cert/certblob", __func__);
- buffer_put_string(b, buffer_ptr(&key->cert->certblob),
- buffer_len(&key->cert->certblob));
- buffer_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa));
- break;
-#endif /* OPENSSL_HAS_ECC */
- case KEY_ED25519:
- buffer_put_string(b, key->ed25519_pk, ED25519_PK_SZ);
- buffer_put_string(b, key->ed25519_sk, ED25519_SK_SZ);
- break;
- case KEY_ED25519_CERT:
- if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
- fatal("%s: no cert/certblob", __func__);
- buffer_put_string(b, buffer_ptr(&key->cert->certblob),
- buffer_len(&key->cert->certblob));
- buffer_put_string(b, key->ed25519_pk, ED25519_PK_SZ);
- buffer_put_string(b, key->ed25519_sk, ED25519_SK_SZ);
- break;
- }
+ return sshkey_perm_ok(fd, filename) == 0 ? 1 : 0;
}
-Key *
-key_private_deserialize(Buffer *blob)
+int
+key_in_file(Key *key, const char *filename, int strict_type)
{
- char *type_name;
- Key *k = NULL;
- u_char *cert;
- u_int len, pklen, sklen;
- int type;
-#ifdef OPENSSL_HAS_ECC
- char *curve;
- BIGNUM *exponent;
- EC_POINT *q;
-#endif
-
- type_name = buffer_get_string(blob, NULL);
- type = key_type_from_name(type_name);
- switch (type) {
- case KEY_DSA:
- k = key_new_private(type);
- buffer_get_bignum2(blob, k->dsa->p);
- buffer_get_bignum2(blob, k->dsa->q);
- buffer_get_bignum2(blob, k->dsa->g);
- buffer_get_bignum2(blob, k->dsa->pub_key);
- buffer_get_bignum2(blob, k->dsa->priv_key);
- break;
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- cert = buffer_get_string(blob, &len);
- if ((k = key_from_blob(cert, len)) == NULL)
- fatal("Certificate parse failed");
- free(cert);
- key_add_private(k);
- buffer_get_bignum2(blob, k->dsa->priv_key);
- break;
-#ifdef OPENSSL_HAS_ECC
- case KEY_ECDSA:
- k = key_new_private(type);
- k->ecdsa_nid = key_ecdsa_nid_from_name(type_name);
- curve = buffer_get_string(blob, NULL);
- if (k->ecdsa_nid != key_curve_name_to_nid(curve))
- fatal("%s: curve names mismatch", __func__);
- free(curve);
- k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
- if (k->ecdsa == NULL)
- fatal("%s: EC_KEY_new_by_curve_name failed",
- __func__);
- q = EC_POINT_new(EC_KEY_get0_group(k->ecdsa));
- if (q == NULL)
- fatal("%s: BN_new failed", __func__);
- if ((exponent = BN_new()) == NULL)
- fatal("%s: BN_new failed", __func__);
- buffer_get_ecpoint(blob,
- EC_KEY_get0_group(k->ecdsa), q);
- buffer_get_bignum2(blob, exponent);
- if (EC_KEY_set_public_key(k->ecdsa, q) != 1)
- fatal("%s: EC_KEY_set_public_key failed",
- __func__);
- if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1)
- fatal("%s: EC_KEY_set_private_key failed",
- __func__);
- if (key_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
- EC_KEY_get0_public_key(k->ecdsa)) != 0)
- fatal("%s: bad ECDSA public key", __func__);
- if (key_ec_validate_private(k->ecdsa) != 0)
- fatal("%s: bad ECDSA private key", __func__);
- BN_clear_free(exponent);
- EC_POINT_free(q);
- break;
- case KEY_ECDSA_CERT:
- cert = buffer_get_string(blob, &len);
- if ((k = key_from_blob(cert, len)) == NULL)
- fatal("Certificate parse failed");
- free(cert);
- key_add_private(k);
- if ((exponent = BN_new()) == NULL)
- fatal("%s: BN_new failed", __func__);
- buffer_get_bignum2(blob, exponent);
- if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1)
- fatal("%s: EC_KEY_set_private_key failed",
- __func__);
- if (key_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
- EC_KEY_get0_public_key(k->ecdsa)) != 0 ||
- key_ec_validate_private(k->ecdsa) != 0)
- fatal("%s: bad ECDSA key", __func__);
- BN_clear_free(exponent);
- break;
-#endif
- case KEY_RSA:
- k = key_new_private(type);
- buffer_get_bignum2(blob, k->rsa->n);
- buffer_get_bignum2(blob, k->rsa->e);
- buffer_get_bignum2(blob, k->rsa->d);
- buffer_get_bignum2(blob, k->rsa->iqmp);
- buffer_get_bignum2(blob, k->rsa->p);
- buffer_get_bignum2(blob, k->rsa->q);
-
- /* Generate additional parameters */
- rsa_generate_additional_parameters(k->rsa);
- break;
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- cert = buffer_get_string(blob, &len);
- if ((k = key_from_blob(cert, len)) == NULL)
- fatal("Certificate parse failed");
- free(cert);
- key_add_private(k);
- buffer_get_bignum2(blob, k->rsa->d);
- buffer_get_bignum2(blob, k->rsa->iqmp);
- buffer_get_bignum2(blob, k->rsa->p);
- buffer_get_bignum2(blob, k->rsa->q);
- break;
- case KEY_ED25519:
- k = key_new_private(type);
- k->ed25519_pk = buffer_get_string(blob, &pklen);
- k->ed25519_sk = buffer_get_string(blob, &sklen);
- if (pklen != ED25519_PK_SZ)
- fatal("%s: ed25519 pklen %d != %d",
- __func__, pklen, ED25519_PK_SZ);
- if (sklen != ED25519_SK_SZ)
- fatal("%s: ed25519 sklen %d != %d",
- __func__, sklen, ED25519_SK_SZ);
- break;
- case KEY_ED25519_CERT:
- cert = buffer_get_string(blob, &len);
- if ((k = key_from_blob(cert, len)) == NULL)
- fatal("Certificate parse failed");
- free(cert);
- key_add_private(k);
- k->ed25519_pk = buffer_get_string(blob, &pklen);
- k->ed25519_sk = buffer_get_string(blob, &sklen);
- if (pklen != ED25519_PK_SZ)
- fatal("%s: ed25519 pklen %d != %d",
- __func__, pklen, ED25519_PK_SZ);
- if (sklen != ED25519_SK_SZ)
- fatal("%s: ed25519 sklen %d != %d",
- __func__, sklen, ED25519_SK_SZ);
- break;
- default:
- free(type_name);
- buffer_clear(blob);
- return NULL;
- }
- free(type_name);
-
- /* enable blinding */
- switch (k->type) {
- case KEY_RSA:
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- case KEY_RSA1:
- if (RSA_blinding_on(k->rsa, NULL) != 1) {
- error("%s: RSA_blinding_on failed", __func__);
- key_free(k);
- return NULL;
- }
- break;
+ 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 k;
+ return 1;
}
diff --git a/key.h b/key.h
index d8ad13d080b8..c6401a576fc4 100644
--- a/key.h
+++ b/key.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.h,v 1.41 2014/01/09 23:20:00 djm Exp $ */
+/* $OpenBSD: key.h,v 1.42 2014/06/24 01:13:21 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -26,141 +26,86 @@
#ifndef KEY_H
#define KEY_H
-#include "buffer.h"
-#include <openssl/rsa.h>
-#include <openssl/dsa.h>
-#ifdef OPENSSL_HAS_ECC
-#include <openssl/ec.h>
+#include "sshkey.h"
+
+typedef struct sshkey Key;
+
+#define types sshkey_types
+#define fp_type sshkey_fp_type
+#define fp_rep sshkey_fp_rep
+
+#ifndef SSH_KEY_NO_DEFINE
+#define key_new sshkey_new
+#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
+#define key_ssh_name_plain sshkey_ssh_name_plain
+#define key_type_from_name sshkey_type_from_name
+#define key_ecdsa_nid_from_name sshkey_ecdsa_nid_from_name
+#define key_type_is_cert sshkey_type_is_cert
+#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
+#define key_curve_name_to_nid sshkey_curve_name_to_nid
+#define key_curve_nid_to_bits sshkey_curve_nid_to_bits
+#define key_curve_nid_to_name sshkey_curve_nid_to_name
+#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
-typedef struct Key Key;
-enum types {
- KEY_RSA1,
- KEY_RSA,
- KEY_DSA,
- KEY_ECDSA,
- KEY_ED25519,
- KEY_RSA_CERT,
- KEY_DSA_CERT,
- KEY_ECDSA_CERT,
- KEY_ED25519_CERT,
- KEY_RSA_CERT_V00,
- KEY_DSA_CERT_V00,
- KEY_UNSPEC
-};
-enum fp_type {
- SSH_FP_SHA1,
- SSH_FP_MD5,
- SSH_FP_SHA256
-};
-enum fp_rep {
- SSH_FP_HEX,
- SSH_FP_BUBBLEBABBLE,
- SSH_FP_RANDOMART
-};
-
-/* key is stored in external hardware */
-#define KEY_FLAG_EXT 0x0001
-
-#define CERT_MAX_PRINCIPALS 256
-struct KeyCert {
- Buffer certblob; /* Kept around for use on wire */
- u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */
- u_int64_t serial;
- char *key_id;
- u_int nprincipals;
- char **principals;
- u_int64_t valid_after, valid_before;
- Buffer critical;
- Buffer extensions;
- Key *signature_key;
-};
-
-struct Key {
- int type;
- int flags;
- RSA *rsa;
- DSA *dsa;
- int ecdsa_nid; /* NID of curve */
-#ifdef OPENSSL_HAS_ECC
- EC_KEY *ecdsa;
-#else
- void *ecdsa;
-#endif
- struct KeyCert *cert;
- u_char *ed25519_sk;
- u_char *ed25519_pk;
-};
-
-#define ED25519_SK_SZ crypto_sign_ed25519_SECRETKEYBYTES
-#define ED25519_PK_SZ crypto_sign_ed25519_PUBLICKEYBYTES
-
-Key *key_new(int);
-void key_add_private(Key *);
-Key *key_new_private(int);
-void key_free(Key *);
-Key *key_demote(const Key *);
-int key_equal_public(const Key *, const Key *);
-int key_equal(const Key *, const Key *);
-char *key_fingerprint(const Key *, enum fp_type, enum fp_rep);
-u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *);
-const char *key_type(const Key *);
-const char *key_cert_type(const Key *);
-int key_write(const Key *, FILE *);
-int key_read(Key *, char **);
-u_int key_size(const Key *);
+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 **);
Key *key_generate(int, u_int);
Key *key_from_private(const Key *);
-int key_type_from_name(char *);
-int key_is_cert(const Key *);
-int key_type_is_cert(int);
-int key_type_plain(int);
int key_to_certified(Key *, int);
int key_drop_cert(Key *);
int key_certify(Key *, Key *);
-void key_cert_copy(const Key *, struct Key *);
+void key_cert_copy(const Key *, Key *);
int key_cert_check_authority(const Key *, int, int, const char *,
const char **);
-int key_cert_is_legacy(const Key *);
+char *key_alg_list(int, int);
-int key_ecdsa_nid_from_name(const char *);
-int key_curve_name_to_nid(const char *);
-const char *key_curve_nid_to_name(int);
-u_int key_curve_nid_to_bits(int);
-int key_ecdsa_bits_to_nid(int);
-#ifdef OPENSSL_HAS_ECC
-int key_ecdsa_key_to_nid(EC_KEY *);
-int key_ec_nid_to_hash_alg(int nid);
-int key_ec_validate_public(const EC_GROUP *, const EC_POINT *);
-int key_ec_validate_private(const EC_KEY *);
-#endif
-char *key_alg_list(int, int);
+#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
+int key_ec_validate_public(const EC_GROUP *, const EC_POINT *);
+int key_ec_validate_private(const EC_KEY *);
+#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */
-Key *key_from_blob(const u_char *, u_int);
-int key_to_blob(const Key *, u_char **, u_int *);
-const char *key_ssh_name(const Key *);
-const char *key_ssh_name_plain(const Key *);
-int key_names_valid2(const char *);
+Key *key_from_blob(const u_char *, u_int);
+int key_to_blob(const Key *, u_char **, u_int *);
int key_sign(const Key *, u_char **, u_int *, const u_char *, u_int);
int key_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
-int ssh_dss_sign(const Key *, u_char **, u_int *, const u_char *, u_int);
-int ssh_dss_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
-int ssh_ecdsa_sign(const Key *, u_char **, u_int *, const u_char *, u_int);
-int ssh_ecdsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
-int ssh_rsa_sign(const Key *, u_char **, u_int *, const u_char *, u_int);
-int ssh_rsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
-int ssh_ed25519_sign(const Key *, u_char **, u_int *, const u_char *, u_int);
-int ssh_ed25519_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
-
-#if defined(OPENSSL_HAS_ECC) && (defined(DEBUG_KEXECDH) || defined(DEBUG_PK))
-void key_dump_ec_point(const EC_GROUP *, const EC_POINT *);
-void key_dump_ec_key(const EC_KEY *);
-#endif
-
-void key_private_serialize(const Key *, Buffer *);
-Key *key_private_deserialize(Buffer *);
+void key_private_serialize(const Key *, struct sshbuf *);
+Key *key_private_deserialize(struct sshbuf *);
+
+/* authfile.c */
+int key_save_private(Key *, const char *, const char *, const char *,
+ int, const char *, int);
+int key_load_file(int, const char *, struct sshbuf *);
+Key *key_load_cert(const char *);
+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
diff --git a/krl.c b/krl.c
index 3b4cded052b4..eb31df90fdc1 100644
--- a/krl.c
+++ b/krl.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $OpenBSD: krl.c,v 1.14 2014/01/31 16:39:19 tedu Exp $ */
+/* $OpenBSD: krl.c,v 1.17 2014/06/24 01:13:21 djm Exp $ */
#include "includes.h"
@@ -366,7 +366,7 @@ plain_key_blob(const Key *key, u_char **blob, u_int *blen)
}
r = key_to_blob(kcopy, blob, blen);
free(kcopy);
- return r == 0 ? -1 : 0;
+ return r;
}
/* Revoke a key blob. Ownership of blob is transferred to the tree */
@@ -394,7 +394,7 @@ ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const Key *key)
u_int len;
debug3("%s: revoke type %s", __func__, key_type(key));
- if (plain_key_blob(key, &blob, &len) != 0)
+ if (plain_key_blob(key, &blob, &len) < 0)
return -1;
return revoke_blob(&krl->revoked_keys, blob, len);
}
@@ -575,6 +575,7 @@ revoked_certs_generate(struct revoked_certs *rc, Buffer *buf)
buffer_put_char(buf, state);
buffer_put_string(buf,
buffer_ptr(&sect), buffer_len(&sect));
+ buffer_clear(&sect);
}
/* If we are starting a new section then prepare it now */
@@ -753,7 +754,8 @@ static int
parse_revoked_certs(Buffer *buf, struct ssh_krl *krl)
{
int ret = -1, nbits;
- u_char type, *blob;
+ u_char type;
+ const u_char *blob;
u_int blen;
Buffer subsect;
u_int64_t serial, serial_lo, serial_hi;
@@ -887,7 +889,8 @@ ssh_krl_from_blob(Buffer *buf, struct ssh_krl **krlp,
char timestamp[64];
int ret = -1, r, sig_seen;
Key *key = NULL, **ca_used = NULL;
- u_char type, *blob, *rdata = NULL;
+ u_char type, *rdata = NULL;
+ const u_char *blob;
u_int i, j, sig_off, sects_off, rlen, blen, format_version, nca_used;
nca_used = 0;
@@ -1127,7 +1130,7 @@ is_key_revoked(struct ssh_krl *krl, const Key *key)
/* Next, explicit keys */
memset(&rb, 0, sizeof(rb));
- if (plain_key_blob(key, &rb.blob, &rb.len) != 0)
+ if (plain_key_blob(key, &rb.blob, &rb.len) < 0)
return -1;
erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb);
free(rb.blob);
diff --git a/mac.c b/mac.c
index 0977572130bb..402dc984ce69 100644
--- a/mac.c
+++ b/mac.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mac.c,v 1.28 2014/02/07 06:55:54 djm Exp $ */
+/* $OpenBSD: mac.c,v 1.30 2014/04/30 19:07:48 naddy Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@@ -175,7 +175,8 @@ mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
u_char m[EVP_MAX_MD_SIZE];
u_int64_t for_align;
} u;
- u_char b[4], nonce[8];
+ u_char b[4];
+ u_char nonce[8];
if (mac->mac_len > sizeof(u))
fatal("mac_compute: mac too long %u %zu",
diff --git a/misc.c b/misc.c
index e4c8c3238074..94b05b08e271 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.92 2013/10/14 23:28:23 djm Exp $ */
+/* $OpenBSD: misc.c,v 1.94 2014/07/15 15:54:14 millert Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <sys/param.h>
#include <stdarg.h>
@@ -788,6 +789,20 @@ get_u32(const void *vp)
return (v);
}
+u_int32_t
+get_u32_le(const void *vp)
+{
+ const u_char *p = (const u_char *)vp;
+ u_int32_t v;
+
+ v = (u_int32_t)p[0];
+ v |= (u_int32_t)p[1] << 8;
+ v |= (u_int32_t)p[2] << 16;
+ v |= (u_int32_t)p[3] << 24;
+
+ return (v);
+}
+
u_int16_t
get_u16(const void *vp)
{
@@ -826,6 +841,16 @@ put_u32(void *vp, u_int32_t v)
p[3] = (u_char)v & 0xff;
}
+void
+put_u32_le(void *vp, u_int32_t v)
+{
+ u_char *p = (u_char *)vp;
+
+ p[0] = (u_char)v & 0xff;
+ p[1] = (u_char)(v >> 8) & 0xff;
+ p[2] = (u_char)(v >> 16) & 0xff;
+ p[3] = (u_char)(v >> 24) & 0xff;
+}
void
put_u16(void *vp, u_int16_t v)
@@ -858,17 +883,24 @@ ms_to_timeval(struct timeval *tv, int ms)
time_t
monotime(void)
{
-#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+#if defined(HAVE_CLOCK_GETTIME) && \
+ (defined(CLOCK_MONOTONIC) || defined(CLOCK_BOOTTIME))
struct timespec ts;
static int gettime_failed = 0;
if (!gettime_failed) {
+#if defined(CLOCK_BOOTTIME)
+ if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0)
+ return (ts.tv_sec);
+#endif
+#if defined(CLOCK_MONOTONIC)
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
return (ts.tv_sec);
+#endif
debug3("clock_gettime: %s", strerror(errno));
gettime_failed = 1;
}
-#endif
+#endif /* HAVE_CLOCK_GETTIME && (CLOCK_MONOTONIC || CLOCK_BOOTTIME */
return time(NULL);
}
@@ -1025,6 +1057,53 @@ lowercase(char *s)
for (; *s; s++)
*s = tolower((u_char)*s);
}
+
+int
+unix_listener(const char *path, int backlog, int unlink_first)
+{
+ struct sockaddr_un sunaddr;
+ int saved_errno, sock;
+
+ memset(&sunaddr, 0, sizeof(sunaddr));
+ sunaddr.sun_family = AF_UNIX;
+ if (strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
+ error("%s: \"%s\" too long for Unix domain socket", __func__,
+ path);
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ saved_errno = errno;
+ error("socket: %.100s", strerror(errno));
+ errno = saved_errno;
+ return -1;
+ }
+ if (unlink_first == 1) {
+ if (unlink(path) != 0 && errno != ENOENT)
+ error("unlink(%s): %.100s", path, strerror(errno));
+ }
+ if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
+ saved_errno = errno;
+ error("bind: %.100s", strerror(errno));
+ close(sock);
+ error("%s: cannot bind to path: %s", __func__, path);
+ errno = saved_errno;
+ return -1;
+ }
+ if (listen(sock, backlog) < 0) {
+ saved_errno = errno;
+ error("listen: %.100s", strerror(errno));
+ close(sock);
+ unlink(path);
+ error("%s: cannot listen on path: %s", __func__, path);
+ errno = saved_errno;
+ return -1;
+ }
+ return sock;
+}
+
void
sock_set_v6only(int s)
{
diff --git a/misc.h b/misc.h
index d4df619cd042..374c33ce14b3 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.50 2013/10/14 23:28:23 djm Exp $ */
+/* $OpenBSD: misc.h,v 1.54 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -15,6 +15,25 @@
#ifndef _MISC_H
#define _MISC_H
+/* Data structure for representing a forwarding request. */
+struct Forward {
+ char *listen_host; /* Host (address) to listen on. */
+ int listen_port; /* Port to forward. */
+ char *listen_path; /* Path to bind domain socket. */
+ char *connect_host; /* Host to connect. */
+ int connect_port; /* Port to connect on connect_host. */
+ char *connect_path; /* Path to connect domain socket. */
+ int allocated_port; /* Dynamically allocated listen port */
+ int handle; /* Handle for dynamic listen ports */
+};
+
+/* Common server and client forwarding options. */
+struct ForwardOptions {
+ int gateway_ports; /* Allow remote connects to forwarded ports. */
+ mode_t streamlocal_bind_mask; /* umask for streamlocal binds */
+ int streamlocal_bind_unlink; /* unlink socket before bind */
+};
+
/* misc.c */
char *chop(char *);
@@ -37,6 +56,7 @@ void ms_subtract_diff(struct timeval *, int *);
void ms_to_timeval(struct timeval *, int);
time_t monotime(void);
void lowercase(char *s);
+int unix_listener(const char *, int, int);
void sock_set_v6only(int);
@@ -68,6 +88,9 @@ int tun_open(int, int);
#define SSH_TUNID_ERR (SSH_TUNID_ANY - 1)
#define SSH_TUNID_MAX (SSH_TUNID_ANY - 2)
+/* Fake port to indicate that host field is really a path. */
+#define PORT_STREAMLOCAL -2
+
/* Functions to extract or store big-endian words of various sizes */
u_int64_t get_u64(const void *)
__attribute__((__bounded__( __minbytes__, 1, 8)));
@@ -82,6 +105,12 @@ void put_u32(void *, u_int32_t)
void put_u16(void *, u_int16_t)
__attribute__((__bounded__( __minbytes__, 1, 2)));
+/* Little-endian store/load, used by umac.c */
+u_int32_t get_u32_le(const void *)
+ __attribute__((__bounded__(__minbytes__, 1, 4)));
+void put_u32_le(void *, u_int32_t)
+ __attribute__((__bounded__(__minbytes__, 1, 4)));
+
struct bwlimit {
size_t buflen;
u_int64_t rate, thresh, lamt;
diff --git a/moduli.0 b/moduli.0
index 7d678b459434..d9aaadba9855 100644
--- a/moduli.0
+++ b/moduli.0
@@ -1,4 +1,4 @@
-MODULI(5) OpenBSD Programmer's Manual MODULI(5)
+MODULI(5) File Formats Manual MODULI(5)
NAME
moduli - Diffie-Hellman moduli
@@ -71,4 +71,4 @@ STANDARDS
the Secure Shell (SSH) Transport Layer Protocol, RFC 4419, March 2006,
2006.
-OpenBSD 5.5 September 26, 2012 OpenBSD 5.5
+OpenBSD 5.6 September 26, 2012 OpenBSD 5.6
diff --git a/monitor.c b/monitor.c
index 531c4f9a8518..dbe29f128dbe 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.131 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: monitor.c,v 1.135 2014/07/15 15:54:14 millert Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -40,9 +40,10 @@
#endif
#include <pwd.h>
#include <signal.h>
-#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
#include <unistd.h>
#ifdef HAVE_POLL_H
#include <poll.h>
@@ -56,7 +57,9 @@
#include <skey.h>
#endif
+#ifdef WITH_OPENSSL
#include <openssl/dh.h>
+#endif
#include "openbsd-compat/sys-queue.h"
#include "atomicio.h"
@@ -84,6 +87,7 @@
#include "sshlogin.h"
#include "canohost.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "monitor.h"
#include "monitor_mm.h"
@@ -92,7 +96,6 @@
#endif
#include "monitor_wrap.h"
#include "monitor_fdpass.h"
-#include "misc.h"
#include "compat.h"
#include "ssh2.h"
#include "roaming.h"
@@ -185,7 +188,10 @@ int mm_answer_audit_command(int, Buffer *);
static int monitor_read_log(struct monitor *);
static Authctxt *authctxt;
+
+#ifdef WITH_SSH1
static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */
+#endif
/* local state for key verify */
static u_char *key_blob = NULL;
@@ -215,7 +221,9 @@ struct mon_table {
#define MON_PERMIT 0x1000 /* Request is permitted */
struct mon_table mon_dispatch_proto20[] = {
+#ifdef WITH_OPENSSL
{MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
+#endif
{MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
{MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
{MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
@@ -252,7 +260,9 @@ struct mon_table mon_dispatch_proto20[] = {
};
struct mon_table mon_dispatch_postauth20[] = {
+#ifdef WITH_OPENSSL
{MONITOR_REQ_MODULI, 0, mm_answer_moduli},
+#endif
{MONITOR_REQ_SIGN, 0, mm_answer_sign},
{MONITOR_REQ_PTY, 0, mm_answer_pty},
{MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup},
@@ -265,6 +275,7 @@ struct mon_table mon_dispatch_postauth20[] = {
};
struct mon_table mon_dispatch_proto15[] = {
+#ifdef WITH_SSH1
{MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
{MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey},
{MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid},
@@ -292,10 +303,12 @@ struct mon_table mon_dispatch_proto15[] = {
#ifdef SSH_AUDIT_EVENTS
{MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
#endif
+#endif /* WITH_SSH1 */
{0, 0, NULL}
};
struct mon_table mon_dispatch_postauth15[] = {
+#ifdef WITH_SSH1
{MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty},
{MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup},
{MONITOR_REQ_TERM, 0, mm_answer_term},
@@ -303,6 +316,7 @@ struct mon_table mon_dispatch_postauth15[] = {
{MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
{MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command},
#endif
+#endif /* WITH_SSH1 */
{0, 0, NULL}
};
@@ -457,6 +471,9 @@ monitor_child_postauth(struct monitor *pmonitor)
signal(SIGHUP, &monitor_child_handler);
signal(SIGTERM, &monitor_child_handler);
signal(SIGINT, &monitor_child_handler);
+#ifdef SIGXFSZ
+ signal(SIGXFSZ, SIG_IGN);
+#endif
if (compat20) {
mon_dispatch = mon_dispatch_postauth20;
@@ -630,6 +647,7 @@ monitor_reset_key_state(void)
hostbased_chost = NULL;
}
+#ifdef WITH_OPENSSL
int
mm_answer_moduli(int sock, Buffer *m)
{
@@ -664,6 +682,7 @@ mm_answer_moduli(int sock, Buffer *m)
mm_request_send(sock, MONITOR_ANS_MODULI, m);
return (0);
}
+#endif
extern AuthenticationConnection *auth_conn;
@@ -1166,6 +1185,7 @@ mm_answer_keyallowed(int sock, Buffer *m)
cuser, chost);
auth_method = "hostbased";
break;
+#ifdef WITH_SSH1
case MM_RSAHOSTKEY:
key->type = KEY_RSA1; /* XXX */
allowed = options.rhosts_rsa_authentication &&
@@ -1175,6 +1195,7 @@ mm_answer_keyallowed(int sock, Buffer *m)
auth_clear_options();
auth_method = "rsa";
break;
+#endif
default:
fatal("%s: unknown key type %d", __func__, type);
break;
@@ -1511,6 +1532,7 @@ mm_answer_pty_cleanup(int sock, Buffer *m)
return (0);
}
+#ifdef WITH_SSH1
int
mm_answer_sesskey(int sock, Buffer *m)
{
@@ -1688,6 +1710,7 @@ mm_answer_rsa_response(int sock, Buffer *m)
return (success);
}
+#endif
int
mm_answer_term(int sock, Buffer *req)
@@ -1792,6 +1815,8 @@ monitor_apply_keystate(struct monitor *pmonitor)
if (options.compression)
mm_init_compression(pmonitor->m_zlib);
+ packet_set_postauth();
+
if (options.rekey_limit || options.rekey_interval)
packet_set_rekey_limits((u_int32_t)options.rekey_limit,
(time_t)options.rekey_interval);
@@ -1828,11 +1853,13 @@ mm_get_kex(Buffer *m)
timingsafe_bcmp(kex->session_id, session_id2, session_id2_len) != 0)
fatal("mm_get_get: internal error: bad session id");
kex->we_need = buffer_get_int(m);
+#ifdef WITH_OPENSSL
kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
+#endif
kex->kex[KEX_C25519_SHA256] = kexc25519_server;
kex->server = 1;
kex->hostkey_type = buffer_get_int(m);
diff --git a/monitor_fdpass.c b/monitor_fdpass.c
index 7eb6f5c6e1f3..100fa5660972 100644
--- a/monitor_fdpass.c
+++ b/monitor_fdpass.c
@@ -34,12 +34,17 @@
#endif
#include <errno.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
#include <string.h>
#include <stdarg.h>
+#ifdef HAVE_POLL_H
+# include <poll.h>
+#else
+# ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+# endif
+#endif
+
#include "log.h"
#include "monitor_fdpass.h"
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 1a47e41745d1..45dc16951e5b 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.c,v 1.79 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.80 2014/04/29 18:01:49 markus Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -38,14 +38,18 @@
#include <string.h>
#include <unistd.h>
+#ifdef WITH_OPENSSL
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/evp.h>
+#endif
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
+#ifdef WITH_OPENSSL
#include "dh.h"
+#endif
#include "buffer.h"
#include "key.h"
#include "cipher.h"
@@ -174,6 +178,7 @@ mm_request_receive_expect(int sock, enum monitor_reqtype type, Buffer *m)
rtype, type);
}
+#ifdef WITH_OPENSSL
DH *
mm_choose_dh(int min, int nbits, int max)
{
@@ -207,6 +212,7 @@ mm_choose_dh(int min, int nbits, int max)
return (dh_new_group(g, p));
}
+#endif
int
mm_key_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen)
@@ -912,6 +918,7 @@ mm_terminate(void)
buffer_free(&m);
}
+#ifdef WITH_SSH1
int
mm_ssh1_session_key(BIGNUM *num)
{
@@ -931,6 +938,7 @@ mm_ssh1_session_key(BIGNUM *num)
return (rsafail);
}
+#endif
static void
mm_chall_setup(char **name, char **infotxt, u_int *numprompts,
@@ -1078,6 +1086,7 @@ mm_ssh1_session_id(u_char session_id[16])
buffer_free(&m);
}
+#ifdef WITH_SSH1
int
mm_auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
{
@@ -1173,6 +1182,7 @@ mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16])
return (success);
}
+#endif
#ifdef SSH_AUDIT_EVENTS
void
diff --git a/mux.c b/mux.c
index 882fa61b5f01..48f7a050fd6b 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mux.c,v 1.44 2013/07/12 00:19:58 djm Exp $ */
+/* $OpenBSD: mux.c,v 1.48 2014/07/17 07:22:19 djm Exp $ */
/*
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
*
@@ -105,6 +105,11 @@ struct mux_session_confirm_ctx {
u_int rid;
};
+/* Context for stdio fwd open confirmation callback */
+struct mux_stdio_confirm_ctx {
+ u_int rid;
+};
+
/* Context for global channel callback */
struct mux_channel_confirm_ctx {
u_int cid; /* channel id */
@@ -157,6 +162,7 @@ struct mux_master_state {
#define MUX_FWD_DYNAMIC 3
static void mux_session_confirm(int, int, void *);
+static void mux_stdio_confirm(int, int, void *);
static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *);
static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *);
@@ -509,29 +515,33 @@ process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
static char *
-format_forward(u_int ftype, Forward *fwd)
+format_forward(u_int ftype, struct Forward *fwd)
{
char *ret;
switch (ftype) {
case MUX_FWD_LOCAL:
xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d",
+ (fwd->listen_path != NULL) ? fwd->listen_path :
(fwd->listen_host == NULL) ?
- (options.gateway_ports ? "*" : "LOCALHOST") :
+ (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
fwd->listen_host, fwd->listen_port,
+ (fwd->connect_path != NULL) ? fwd->connect_path :
fwd->connect_host, fwd->connect_port);
break;
case MUX_FWD_DYNAMIC:
xasprintf(&ret, "dynamic forward %.200s:%d -> *",
(fwd->listen_host == NULL) ?
- (options.gateway_ports ? "*" : "LOCALHOST") :
+ (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
fwd->listen_host, fwd->listen_port);
break;
case MUX_FWD_REMOTE:
xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d",
+ (fwd->listen_path != NULL) ? fwd->listen_path :
(fwd->listen_host == NULL) ?
"LOCALHOST" : fwd->listen_host,
fwd->listen_port,
+ (fwd->connect_path != NULL) ? fwd->connect_path :
fwd->connect_host, fwd->connect_port);
break;
default:
@@ -551,14 +561,18 @@ compare_host(const char *a, const char *b)
}
static int
-compare_forward(Forward *a, Forward *b)
+compare_forward(struct Forward *a, struct Forward *b)
{
if (!compare_host(a->listen_host, b->listen_host))
return 0;
+ if (!compare_host(a->listen_path, b->listen_path))
+ return 0;
if (a->listen_port != b->listen_port)
return 0;
if (!compare_host(a->connect_host, b->connect_host))
return 0;
+ if (!compare_host(a->connect_path, b->connect_path))
+ return 0;
if (a->connect_port != b->connect_port)
return 0;
@@ -570,7 +584,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
{
struct mux_channel_confirm_ctx *fctx = ctxt;
char *failmsg = NULL;
- Forward *rfwd;
+ struct Forward *rfwd;
Channel *c;
Buffer out;
@@ -587,7 +601,8 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
rfwd = &options.remote_forwards[fctx->fid];
debug("%s: %s for: listen %d, connect %s:%d", __func__,
type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
- rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
+ rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path :
+ rfwd->connect_host, rfwd->connect_port);
if (type == SSH2_MSG_REQUEST_SUCCESS) {
if (rfwd->listen_port == 0) {
rfwd->allocated_port = packet_get_int();
@@ -607,8 +622,12 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
} else {
if (rfwd->listen_port == 0)
channel_update_permitted_opens(rfwd->handle, -1);
- xasprintf(&failmsg, "remote port forwarding failed for "
- "listen port %d", rfwd->listen_port);
+ if (rfwd->listen_path != NULL)
+ xasprintf(&failmsg, "remote port forwarding failed for "
+ "listen path %s", rfwd->listen_path);
+ else
+ xasprintf(&failmsg, "remote port forwarding failed for "
+ "listen port %d", rfwd->listen_port);
}
fail:
error("%s: %s", __func__, failmsg);
@@ -627,34 +646,46 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
static int
process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
{
- Forward fwd;
+ struct Forward fwd;
char *fwd_desc = NULL;
+ char *listen_addr, *connect_addr;
u_int ftype;
u_int lport, cport;
int i, ret = 0, freefwd = 1;
- fwd.listen_host = fwd.connect_host = NULL;
+ /* XXX - lport/cport check redundant */
if (buffer_get_int_ret(&ftype, m) != 0 ||
- (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
+ (listen_addr = buffer_get_string_ret(m, NULL)) == NULL ||
buffer_get_int_ret(&lport, m) != 0 ||
- (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
+ (connect_addr = buffer_get_string_ret(m, NULL)) == NULL ||
buffer_get_int_ret(&cport, m) != 0 ||
- lport > 65535 || cport > 65535) {
+ (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
+ (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
error("%s: malformed message", __func__);
ret = -1;
goto out;
}
- fwd.listen_port = lport;
- fwd.connect_port = cport;
- if (*fwd.listen_host == '\0') {
- free(fwd.listen_host);
- fwd.listen_host = NULL;
+ if (*listen_addr == '\0') {
+ free(listen_addr);
+ listen_addr = NULL;
}
- if (*fwd.connect_host == '\0') {
- free(fwd.connect_host);
- fwd.connect_host = NULL;
+ if (*connect_addr == '\0') {
+ free(connect_addr);
+ connect_addr = NULL;
}
+ memset(&fwd, 0, sizeof(fwd));
+ fwd.listen_port = lport;
+ if (fwd.listen_port == PORT_STREAMLOCAL)
+ fwd.listen_path = listen_addr;
+ else
+ fwd.listen_host = listen_addr;
+ fwd.connect_port = cport;
+ if (fwd.connect_port == PORT_STREAMLOCAL)
+ fwd.connect_path = connect_addr;
+ else
+ fwd.connect_host = connect_addr;
+
debug2("%s: channel %d: request %s", __func__, c->self,
(fwd_desc = format_forward(ftype, &fwd)));
@@ -662,25 +693,30 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
ftype != MUX_FWD_DYNAMIC) {
logit("%s: invalid forwarding type %u", __func__, ftype);
invalid:
- free(fwd.listen_host);
- free(fwd.connect_host);
+ free(listen_addr);
+ free(connect_addr);
buffer_put_int(r, MUX_S_FAILURE);
buffer_put_int(r, rid);
buffer_put_cstring(r, "Invalid forwarding request");
return 0;
}
- if (fwd.listen_port >= 65536) {
+ if (ftype == MUX_FWD_DYNAMIC && fwd.listen_path) {
+ logit("%s: streamlocal and dynamic forwards "
+ "are mutually exclusive", __func__);
+ goto invalid;
+ }
+ if (fwd.listen_port != PORT_STREAMLOCAL && fwd.listen_port >= 65536) {
logit("%s: invalid listen port %u", __func__,
fwd.listen_port);
goto invalid;
}
- if (fwd.connect_port >= 65536 || (ftype != MUX_FWD_DYNAMIC &&
- ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) {
+ if ((fwd.connect_port != PORT_STREAMLOCAL && fwd.connect_port >= 65536)
+ || (ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) {
logit("%s: invalid connect port %u", __func__,
fwd.connect_port);
goto invalid;
}
- if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL) {
+ if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL && fwd.connect_path == NULL) {
logit("%s: missing connect host", __func__);
goto invalid;
}
@@ -731,9 +767,8 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) {
- if (!channel_setup_local_fwd_listener(fwd.listen_host,
- fwd.listen_port, fwd.connect_host, fwd.connect_port,
- options.gateway_ports)) {
+ if (!channel_setup_local_fwd_listener(&fwd,
+ &options.fwd_opts)) {
fail:
logit("slave-requested %s failed", fwd_desc);
buffer_put_int(r, MUX_S_FAILURE);
@@ -746,8 +781,7 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
} else {
struct mux_channel_confirm_ctx *fctx;
- fwd.handle = channel_request_remote_forwarding(fwd.listen_host,
- fwd.listen_port, fwd.connect_host, fwd.connect_port);
+ fwd.handle = channel_request_remote_forwarding(&fwd);
if (fwd.handle < 0)
goto fail;
add_remote_forward(&options, &fwd);
@@ -768,7 +802,9 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
free(fwd_desc);
if (freefwd) {
free(fwd.listen_host);
+ free(fwd.listen_path);
free(fwd.connect_host);
+ free(fwd.connect_path);
}
return ret;
}
@@ -776,36 +812,47 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
static int
process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
{
- Forward fwd, *found_fwd;
+ struct Forward fwd, *found_fwd;
char *fwd_desc = NULL;
const char *error_reason = NULL;
+ char *listen_addr = NULL, *connect_addr = NULL;
u_int ftype;
- int i, listen_port, ret = 0;
+ int i, ret = 0;
u_int lport, cport;
- fwd.listen_host = fwd.connect_host = NULL;
if (buffer_get_int_ret(&ftype, m) != 0 ||
- (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
+ (listen_addr = buffer_get_string_ret(m, NULL)) == NULL ||
buffer_get_int_ret(&lport, m) != 0 ||
- (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
+ (connect_addr = buffer_get_string_ret(m, NULL)) == NULL ||
buffer_get_int_ret(&cport, m) != 0 ||
- lport > 65535 || cport > 65535) {
+ (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
+ (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
error("%s: malformed message", __func__);
ret = -1;
goto out;
}
- fwd.listen_port = lport;
- fwd.connect_port = cport;
- if (*fwd.listen_host == '\0') {
- free(fwd.listen_host);
- fwd.listen_host = NULL;
+ if (*listen_addr == '\0') {
+ free(listen_addr);
+ listen_addr = NULL;
}
- if (*fwd.connect_host == '\0') {
- free(fwd.connect_host);
- fwd.connect_host = NULL;
+ if (*connect_addr == '\0') {
+ free(connect_addr);
+ connect_addr = NULL;
}
+ memset(&fwd, 0, sizeof(fwd));
+ fwd.listen_port = lport;
+ if (fwd.listen_port == PORT_STREAMLOCAL)
+ fwd.listen_path = listen_addr;
+ else
+ fwd.listen_host = listen_addr;
+ fwd.connect_port = cport;
+ if (fwd.connect_port == PORT_STREAMLOCAL)
+ fwd.connect_path = connect_addr;
+ else
+ fwd.connect_host = connect_addr;
+
debug2("%s: channel %d: request cancel %s", __func__, c->self,
(fwd_desc = format_forward(ftype, &fwd)));
@@ -840,18 +887,14 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
* This shouldn't fail unless we confused the host/port
* between options.remote_forwards and permitted_opens.
* However, for dynamic allocated listen ports we need
- * to lookup the actual listen port.
+ * to use the actual listen port.
*/
- listen_port = (fwd.listen_port == 0) ?
- found_fwd->allocated_port : fwd.listen_port;
- if (channel_request_rforward_cancel(fwd.listen_host,
- listen_port) == -1)
+ if (channel_request_rforward_cancel(found_fwd) == -1)
error_reason = "port not in permitted opens";
} else { /* local and dynamic forwards */
/* Ditto */
- if (channel_cancel_lport_listener(fwd.listen_host,
- fwd.listen_port, fwd.connect_port,
- options.gateway_ports) == -1)
+ if (channel_cancel_lport_listener(&fwd, fwd.connect_port,
+ &options.fwd_opts) == -1)
error_reason = "port not found";
}
@@ -860,8 +903,11 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
buffer_put_int(r, rid);
free(found_fwd->listen_host);
+ free(found_fwd->listen_path);
free(found_fwd->connect_host);
+ free(found_fwd->connect_path);
found_fwd->listen_host = found_fwd->connect_host = NULL;
+ found_fwd->listen_path = found_fwd->connect_path = NULL;
found_fwd->listen_port = found_fwd->connect_port = 0;
} else {
buffer_put_int(r, MUX_S_FAILURE);
@@ -870,8 +916,8 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
out:
free(fwd_desc);
- free(fwd.listen_host);
- free(fwd.connect_host);
+ free(listen_addr);
+ free(connect_addr);
return ret;
}
@@ -883,6 +929,7 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
char *reserved, *chost;
u_int cport, i, j;
int new_fd[2];
+ struct mux_stdio_confirm_ctx *cctx;
chost = reserved = NULL;
if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
@@ -962,15 +1009,60 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
- /* prepare reply */
- /* XXX defer until channel confirmed */
- buffer_put_int(r, MUX_S_SESSION_OPENED);
- buffer_put_int(r, rid);
- buffer_put_int(r, nc->self);
+ cctx = xcalloc(1, sizeof(*cctx));
+ cctx->rid = rid;
+ channel_register_open_confirm(nc->self, mux_stdio_confirm, cctx);
+ c->mux_pause = 1; /* stop handling messages until open_confirm done */
+ /* reply is deferred, sent by mux_session_confirm */
return 0;
}
+/* Callback on open confirmation in mux master for a mux stdio fwd session. */
+static void
+mux_stdio_confirm(int id, int success, void *arg)
+{
+ struct mux_stdio_confirm_ctx *cctx = arg;
+ Channel *c, *cc;
+ Buffer reply;
+
+ if (cctx == NULL)
+ fatal("%s: cctx == NULL", __func__);
+ if ((c = channel_by_id(id)) == NULL)
+ fatal("%s: no channel for id %d", __func__, id);
+ if ((cc = channel_by_id(c->ctl_chan)) == NULL)
+ fatal("%s: channel %d lacks control channel %d", __func__,
+ id, c->ctl_chan);
+
+ if (!success) {
+ debug3("%s: sending failure reply", __func__);
+ /* prepare reply */
+ buffer_init(&reply);
+ buffer_put_int(&reply, MUX_S_FAILURE);
+ buffer_put_int(&reply, cctx->rid);
+ buffer_put_cstring(&reply, "Session open refused by peer");
+ goto done;
+ }
+
+ debug3("%s: sending success reply", __func__);
+ /* prepare reply */
+ buffer_init(&reply);
+ buffer_put_int(&reply, MUX_S_SESSION_OPENED);
+ buffer_put_int(&reply, cctx->rid);
+ buffer_put_int(&reply, c->self);
+
+ done:
+ /* Send reply */
+ buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
+ buffer_free(&reply);
+
+ if (cc->mux_pause <= 0)
+ fatal("%s: mux_pause %d", __func__, cc->mux_pause);
+ cc->mux_pause = 0; /* start processing messages again */
+ c->open_confirm_ctx = NULL;
+ free(cctx);
+}
+
static int
process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
{
@@ -1010,7 +1102,7 @@ mux_master_read_cb(Channel *c)
{
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
Buffer in, out;
- void *ptr;
+ const u_char *ptr;
u_int type, rid, have, i;
int ret = -1;
@@ -1133,12 +1225,11 @@ mux_tty_alloc_failed(Channel *c)
void
muxserver_listen(void)
{
- struct sockaddr_un addr;
- socklen_t sun_len;
mode_t old_umask;
char *orig_control_path = options.control_path;
char rbuf[16+1];
u_int i, r;
+ int oerrno;
if (options.control_path == NULL ||
options.control_master == SSHCTL_MASTER_NO)
@@ -1163,24 +1254,12 @@ muxserver_listen(void)
xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf);
debug3("%s: temporary control path %s", __func__, options.control_path);
- memset(&addr, '\0', sizeof(addr));
- addr.sun_family = AF_UNIX;
- sun_len = offsetof(struct sockaddr_un, sun_path) +
- strlen(options.control_path) + 1;
-
- if (strlcpy(addr.sun_path, options.control_path,
- sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) {
- error("ControlPath \"%s\" too long for Unix domain socket",
- options.control_path);
- goto disable_mux_master;
- }
-
- if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
- fatal("%s socket(): %s", __func__, strerror(errno));
-
old_umask = umask(0177);
- if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) {
- if (errno == EINVAL || errno == EADDRINUSE) {
+ muxserver_sock = unix_listener(options.control_path, 64, 0);
+ oerrno = errno;
+ umask(old_umask);
+ if (muxserver_sock < 0) {
+ if (oerrno == EINVAL || oerrno == EADDRINUSE) {
error("ControlSocket %s already exists, "
"disabling multiplexing", options.control_path);
disable_mux_master:
@@ -1193,13 +1272,11 @@ muxserver_listen(void)
options.control_path = NULL;
options.control_master = SSHCTL_MASTER_NO;
return;
- } else
- fatal("%s bind(): %s", __func__, strerror(errno));
+ } else {
+ /* unix_listener() logs the error */
+ cleanup_exit(255);
+ }
}
- umask(old_umask);
-
- if (listen(muxserver_sock, 64) == -1)
- fatal("%s listen(): %s", __func__, strerror(errno));
/* Now atomically "move" the mux socket into position */
if (link(options.control_path, orig_control_path) != 0) {
@@ -1429,7 +1506,7 @@ mux_client_read_packet(int fd, Buffer *m)
{
Buffer queue;
u_int need, have;
- void *ptr;
+ const u_char *ptr;
int oerrno;
buffer_init(&queue);
@@ -1593,7 +1670,7 @@ mux_client_request_terminate(int fd)
}
static int
-mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd)
+mux_client_forward(int fd, int cancel_flag, u_int ftype, struct Forward *fwd)
{
Buffer m;
char *e, *fwd_desc;
@@ -1608,11 +1685,19 @@ mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd)
buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD);
buffer_put_int(&m, muxclient_request_id);
buffer_put_int(&m, ftype);
- buffer_put_cstring(&m,
- fwd->listen_host == NULL ? "" : fwd->listen_host);
+ if (fwd->listen_path != NULL) {
+ buffer_put_cstring(&m, fwd->listen_path);
+ } else {
+ buffer_put_cstring(&m,
+ fwd->listen_host == NULL ? "" : fwd->listen_host);
+ }
buffer_put_int(&m, fwd->listen_port);
- buffer_put_cstring(&m,
- fwd->connect_host == NULL ? "" : fwd->connect_host);
+ if (fwd->connect_path != NULL) {
+ buffer_put_cstring(&m, fwd->connect_path);
+ } else {
+ buffer_put_cstring(&m,
+ fwd->connect_host == NULL ? "" : fwd->connect_host);
+ }
buffer_put_int(&m, fwd->connect_port);
if (mux_client_write_packet(fd, &m) != 0)
@@ -1922,7 +2007,7 @@ mux_client_request_stdio_fwd(int fd)
case MUX_S_FAILURE:
e = buffer_get_string(&m, NULL);
buffer_free(&m);
- fatal("%s: stdio forwarding request failed: %s", __func__, e);
+ fatal("Stdio forwarding request failed: %s", e);
default:
buffer_free(&m);
error("%s: unexpected response from master 0x%08x",
diff --git a/myproposal.h b/myproposal.h
index 3a0f5aeabd6a..b35b2b8bdf7c 100644
--- a/myproposal.h
+++ b/myproposal.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: myproposal.h,v 1.35 2013/12/06 13:39:49 markus Exp $ */
+/* $OpenBSD: myproposal.h,v 1.41 2014/07/11 13:54:34 tedu Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@@ -69,23 +69,28 @@
#ifdef HAVE_EVP_SHA256
# define KEX_SHA256_METHODS \
"diffie-hellman-group-exchange-sha256,"
-#define KEX_CURVE25519_METHODS \
- "curve25519-sha256@libssh.org,"
#define SHA2_HMAC_MODES \
"hmac-sha2-256," \
"hmac-sha2-512,"
#else
# define KEX_SHA256_METHODS
-# define KEX_CURVE25519_METHODS
# define SHA2_HMAC_MODES
#endif
-# define KEX_DEFAULT_KEX \
+#ifdef WITH_OPENSSL
+# ifdef HAVE_EVP_SHA256
+# define KEX_CURVE25519_METHODS "curve25519-sha256@libssh.org,"
+# else
+# define KEX_CURVE25519_METHODS ""
+# endif
+#define KEX_SERVER_KEX \
KEX_CURVE25519_METHODS \
KEX_ECDH_METHODS \
KEX_SHA256_METHODS \
+ "diffie-hellman-group14-sha1"
+
+#define KEX_CLIENT_KEX KEX_SERVER_KEX "," \
"diffie-hellman-group-exchange-sha1," \
- "diffie-hellman-group14-sha1," \
"diffie-hellman-group1-sha1"
#define KEX_DEFAULT_PK_ALG \
@@ -102,47 +107,91 @@
/* the actual algorithms */
-#define KEX_DEFAULT_ENCRYPT \
+#define KEX_SERVER_ENCRYPT \
"aes128-ctr,aes192-ctr,aes256-ctr," \
- "arcfour256,arcfour128," \
AESGCM_CIPHER_MODES \
- "chacha20-poly1305@openssh.com," \
+ "chacha20-poly1305@openssh.com"
+
+#define KEX_CLIENT_ENCRYPT KEX_SERVER_ENCRYPT "," \
+ "arcfour256,arcfour128," \
"aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \
"aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se"
-#define KEX_DEFAULT_MAC \
- "hmac-md5-etm@openssh.com," \
- "hmac-sha1-etm@openssh.com," \
+#define KEX_SERVER_MAC \
"umac-64-etm@openssh.com," \
"umac-128-etm@openssh.com," \
"hmac-sha2-256-etm@openssh.com," \
"hmac-sha2-512-etm@openssh.com," \
+ "hmac-sha1-etm@openssh.com," \
+ "umac-64@openssh.com," \
+ "umac-128@openssh.com," \
+ "hmac-sha2-256," \
+ "hmac-sha2-512," \
+ "hmac-sha1"
+
+#define KEX_CLIENT_MAC KEX_SERVER_MAC "," \
+ "hmac-md5-etm@openssh.com," \
"hmac-ripemd160-etm@openssh.com," \
"hmac-sha1-96-etm@openssh.com," \
"hmac-md5-96-etm@openssh.com," \
"hmac-md5," \
- "hmac-sha1," \
- "umac-64@openssh.com," \
- "umac-128@openssh.com," \
- SHA2_HMAC_MODES \
"hmac-ripemd160," \
"hmac-ripemd160@openssh.com," \
"hmac-sha1-96," \
"hmac-md5-96"
+#else
+
+#define KEX_SERVER_KEX \
+ "curve25519-sha256@libssh.org"
+#define KEX_DEFAULT_PK_ALG \
+ "ssh-ed25519-cert-v01@openssh.com," \
+ "ssh-ed25519"
+#define KEX_SERVER_ENCRYPT \
+ "aes128-ctr,aes192-ctr,aes256-ctr," \
+ "chacha20-poly1305@openssh.com"
+#define KEX_SERVER_MAC \
+ "umac-64-etm@openssh.com," \
+ "umac-128-etm@openssh.com," \
+ "hmac-sha2-256-etm@openssh.com," \
+ "hmac-sha2-512-etm@openssh.com," \
+ "hmac-sha1-etm@openssh.com," \
+ "umac-64@openssh.com," \
+ "umac-128@openssh.com," \
+ "hmac-sha2-256," \
+ "hmac-sha2-512," \
+ "hmac-sha1"
+
+#define KEX_CLIENT_KEX KEX_SERVER_KEX
+#define KEX_CLIENT_ENCRYPT KEX_SERVER_ENCRYPT
+#define KEX_CLIENT_MAC KEX_SERVER_MAC
+
+#endif /* WITH_OPENSSL */
+
#define KEX_DEFAULT_COMP "none,zlib@openssh.com,zlib"
#define KEX_DEFAULT_LANG ""
+#define KEX_CLIENT \
+ KEX_CLIENT_KEX, \
+ KEX_DEFAULT_PK_ALG, \
+ KEX_CLIENT_ENCRYPT, \
+ KEX_CLIENT_ENCRYPT, \
+ KEX_CLIENT_MAC, \
+ KEX_CLIENT_MAC, \
+ KEX_DEFAULT_COMP, \
+ KEX_DEFAULT_COMP, \
+ KEX_DEFAULT_LANG, \
+ KEX_DEFAULT_LANG
-static char *myproposal[PROPOSAL_MAX] = {
- KEX_DEFAULT_KEX,
- KEX_DEFAULT_PK_ALG,
- KEX_DEFAULT_ENCRYPT,
- KEX_DEFAULT_ENCRYPT,
- KEX_DEFAULT_MAC,
- KEX_DEFAULT_MAC,
- KEX_DEFAULT_COMP,
- KEX_DEFAULT_COMP,
- KEX_DEFAULT_LANG,
+#define KEX_SERVER \
+ KEX_SERVER_KEX, \
+ KEX_DEFAULT_PK_ALG, \
+ KEX_SERVER_ENCRYPT, \
+ KEX_SERVER_ENCRYPT, \
+ KEX_SERVER_MAC, \
+ KEX_SERVER_MAC, \
+ KEX_DEFAULT_COMP, \
+ KEX_DEFAULT_COMP, \
+ KEX_DEFAULT_LANG, \
KEX_DEFAULT_LANG
-};
+
diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in
index 6ecfb93d55ca..ab1a3e315db2 100644
--- a/openbsd-compat/Makefile.in
+++ b/openbsd-compat/Makefile.in
@@ -1,4 +1,4 @@
-# $Id: Makefile.in,v 1.55 2014/02/04 00:37:50 djm Exp $
+# $Id: Makefile.in,v 1.56 2014/09/30 23:43:08 djm Exp $
sysconfdir=@sysconfdir@
piddir=@piddir@
@@ -18,7 +18,7 @@ LDFLAGS=-L. @LDFLAGS@
OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt_long.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o realpath.o rresvport.o setenv.o setproctitle.o sha2.o sigact.o strlcat.o strlcpy.o strmode.o strnlen.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o strtoull.o timingsafe_bcmp.o vis.o blowfish.o bcrypt_pbkdf.o explicit_bzero.o
-COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
+COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o kludge-fd_set.o
PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
diff --git a/openbsd-compat/arc4random.c b/openbsd-compat/arc4random.c
index eac073cc01b7..09dbfda16492 100644
--- a/openbsd-compat/arc4random.c
+++ b/openbsd-compat/arc4random.c
@@ -87,7 +87,7 @@ _rs_stir(void)
_rs_init(rnd, sizeof(rnd));
} else
_rs_rekey(rnd, sizeof(rnd));
- memset(rnd, 0, sizeof(rnd));
+ explicit_bzero(rnd, sizeof(rnd));
/* invalidate rs_buf */
rs_have = 0;
@@ -229,7 +229,7 @@ arc4random_buf(void *_buf, size_t n)
buf[i] = r & 0xff;
r >>= 8;
}
- i = r = 0;
+ explicit_bzero(&r, sizeof(r));
}
#endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */
diff --git a/openbsd-compat/bsd-cygwin_util.c b/openbsd-compat/bsd-cygwin_util.c
index 267e77a11b29..a2d82126df98 100644
--- a/openbsd-compat/bsd-cygwin_util.c
+++ b/openbsd-compat/bsd-cygwin_util.c
@@ -57,6 +57,22 @@ check_ntsec(const char *filename)
return (pathconf(filename, _PC_POSIX_PERMISSIONS));
}
+const char *
+cygwin_ssh_privsep_user()
+{
+ static char cyg_privsep_user[DNLEN + UNLEN + 2];
+
+ if (!cyg_privsep_user[0])
+ {
+#ifdef CW_CYGNAME_FROM_WINNAME
+ if (cygwin_internal (CW_CYGNAME_FROM_WINNAME, "sshd", cyg_privsep_user,
+ sizeof cyg_privsep_user) != 0)
+#endif
+ strcpy (cyg_privsep_user, "sshd");
+ }
+ return cyg_privsep_user;
+}
+
#define NL(x) x, (sizeof (x) - 1)
#define WENV_SIZ (sizeof (wenv_arr) / sizeof (wenv_arr[0]))
diff --git a/openbsd-compat/bsd-cygwin_util.h b/openbsd-compat/bsd-cygwin_util.h
index 1177366f1b05..79cb2a197c1e 100644
--- a/openbsd-compat/bsd-cygwin_util.h
+++ b/openbsd-compat/bsd-cygwin_util.h
@@ -1,4 +1,4 @@
-/* $Id: bsd-cygwin_util.h,v 1.17 2014/01/18 10:04:00 dtucker Exp $ */
+/* $Id: bsd-cygwin_util.h,v 1.18 2014/05/27 04:34:43 djm Exp $ */
/*
* Copyright (c) 2000, 2001, 2011, 2013 Corinna Vinschen <vinschen@redhat.com>
@@ -39,6 +39,8 @@
/* Avoid including windows headers. */
typedef void *HANDLE;
#define INVALID_HANDLE_VALUE ((HANDLE) -1)
+#define DNLEN 16
+#define UNLEN 256
/* Cygwin functions for which declarations are only available when including
windows headers, so we have to define them here explicitely. */
@@ -48,6 +50,8 @@ extern void cygwin_set_impersonation_token (const HANDLE);
#include <sys/cygwin.h>
#include <io.h>
+#define CYGWIN_SSH_PRIVSEP_USER (cygwin_ssh_privsep_user())
+const char *cygwin_ssh_privsep_user();
int binary_open(const char *, int , ...);
int check_ntsec(const char *);
diff --git a/openbsd-compat/bsd-snprintf.c b/openbsd-compat/bsd-snprintf.c
index 975991e7fab8..23a6359898e8 100644
--- a/openbsd-compat/bsd-snprintf.c
+++ b/openbsd-compat/bsd-snprintf.c
@@ -538,7 +538,7 @@ fmtstr(char *buffer, size_t *currlen, size_t maxlen,
}
while (*value && (cnt < max)) {
DOPR_OUTCH(buffer, *currlen, maxlen, *value);
- *value++;
+ value++;
++cnt;
}
while ((padlen < 0) && (cnt < max)) {
@@ -553,7 +553,7 @@ fmtstr(char *buffer, size_t *currlen, size_t maxlen,
static int
fmtint(char *buffer, size_t *currlen, size_t maxlen,
- LLONG value, int base, int min, int max, int flags)
+ intmax_t value, int base, int min, int max, int flags)
{
int signvalue = 0;
unsigned LLONG uvalue;
diff --git a/openbsd-compat/explicit_bzero.c b/openbsd-compat/explicit_bzero.c
index b106741e5a10..3c85a4843a47 100644
--- a/openbsd-compat/explicit_bzero.c
+++ b/openbsd-compat/explicit_bzero.c
@@ -7,14 +7,34 @@
#include "includes.h"
+/*
+ * explicit_bzero - don't let the compiler optimize away bzero
+ */
+
#ifndef HAVE_EXPLICIT_BZERO
+#ifdef HAVE_MEMSET_S
+
+void
+explicit_bzero(void *p, size_t n)
+{
+ (void)memset_s(p, n, 0, n);
+}
+
+#else /* HAVE_MEMSET_S */
+
/*
- * explicit_bzero - don't let the compiler optimize away bzero
+ * Indirect bzero through a volatile pointer to hopefully avoid
+ * dead-store optimisation eliminating the call.
*/
+static void (* volatile ssh_bzero)(void *, size_t) = bzero;
+
void
explicit_bzero(void *p, size_t n)
{
- bzero(p, n);
+ ssh_bzero(p, n);
}
-#endif
+
+#endif /* HAVE_MEMSET_S */
+
+#endif /* HAVE_EXPLICIT_BZERO */
diff --git a/openbsd-compat/kludge-fd_set.c b/openbsd-compat/kludge-fd_set.c
new file mode 100644
index 000000000000..6c2ffb64bddb
--- /dev/null
+++ b/openbsd-compat/kludge-fd_set.c
@@ -0,0 +1,28 @@
+/* Placed in the public domain. */
+
+/*
+ * _FORTIFY_SOURCE includes a misguided check for FD_SET(n)/FD_ISSET(b)
+ * where n > FD_SETSIZE. This breaks OpenSSH and other programs that
+ * explicitly allocate fd_sets. To avoid this, we wrap FD_SET in a
+ * function compiled without _FORTIFY_SOURCE.
+ */
+
+#include "config.h"
+
+#if defined(HAVE_FEATURES_H) && defined(_FORTIFY_SOURCE)
+# include <features.h>
+# if defined(__GNU_LIBRARY__) && defined(__GLIBC_PREREQ)
+# if __GLIBC_PREREQ(2, 15) && (_FORTIFY_SOURCE > 0)
+# undef _FORTIFY_SOURCE
+# undef __USE_FORTIFY_LEVEL
+# include <sys/socket.h>
+void kludge_FD_SET(int n, fd_set *set) {
+ FD_SET(n, set);
+}
+int kludge_FD_ISSET(int n, fd_set *set) {
+ return FD_ISSET(n, set);
+}
+# endif /* __GLIBC_PREREQ(2, 15) && (_FORTIFY_SOURCE > 0) */
+# endif /* __GNU_LIBRARY__ && __GLIBC_PREREQ */
+#endif /* HAVE_FEATURES_H && _FORTIFY_SOURCE */
+
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
index bc9888e31ae9..ce6abae8237c 100644
--- a/openbsd-compat/openbsd-compat.h
+++ b/openbsd-compat/openbsd-compat.h
@@ -1,4 +1,4 @@
-/* $Id: openbsd-compat.h,v 1.61 2014/02/04 00:18:23 djm Exp $ */
+/* $Id: openbsd-compat.h,v 1.62 2014/09/30 23:43:08 djm Exp $ */
/*
* Copyright (c) 1999-2003 Damien Miller. All rights reserved.
@@ -268,4 +268,20 @@ char *shadow_pw(struct passwd *pw);
#include "port-tun.h"
#include "port-uw.h"
+/* _FORTIFY_SOURCE breaks FD_ISSET(n)/FD_SET(n) for n > FD_SETSIZE. Avoid. */
+#if defined(HAVE_FEATURES_H) && defined(_FORTIFY_SOURCE)
+# include <features.h>
+# if defined(__GNU_LIBRARY__) && defined(__GLIBC_PREREQ)
+# if __GLIBC_PREREQ(2, 15) && (_FORTIFY_SOURCE > 0)
+# include <sys/socket.h> /* Ensure include guard is defined */
+# undef FD_SET
+# undef FD_ISSET
+# define FD_SET(n, set) kludge_FD_SET(n, set)
+# define FD_ISSET(n, set) kludge_FD_ISSET(n, set)
+void kludge_FD_SET(int, fd_set *);
+int kludge_FD_ISSET(int, fd_set *);
+# endif /* __GLIBC_PREREQ(2, 15) && (_FORTIFY_SOURCE > 0) */
+# endif /* __GNU_LIBRARY__ && __GLIBC_PREREQ */
+#endif /* HAVE_FEATURES_H && _FORTIFY_SOURCE */
+
#endif /* _OPENBSD_COMPAT_H */
diff --git a/openbsd-compat/openssl-compat.c b/openbsd-compat/openssl-compat.c
index 885c121f2b58..36570e4ade44 100644
--- a/openbsd-compat/openssl-compat.c
+++ b/openbsd-compat/openssl-compat.c
@@ -1,4 +1,4 @@
-/* $Id: openssl-compat.c,v 1.17 2014/02/13 05:38:33 dtucker Exp $ */
+/* $Id: openssl-compat.c,v 1.19 2014/07/02 05:28:07 djm Exp $ */
/*
* Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au>
@@ -16,6 +16,7 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define SSH_DONT_OVERLOAD_OPENSSL_FUNCS
#include "includes.h"
#include <stdarg.h>
@@ -26,147 +27,44 @@
# include <openssl/conf.h>
#endif
-#ifndef HAVE_RSA_GET_DEFAULT_METHOD
-# include <openssl/rsa.h>
-#endif
-
#include "log.h"
-#define SSH_DONT_OVERLOAD_OPENSSL_FUNCS
#include "openssl-compat.h"
-#ifdef SSH_OLD_EVP
-int
-ssh_EVP_CipherInit(EVP_CIPHER_CTX *evp, const EVP_CIPHER *type,
- unsigned char *key, unsigned char *iv, int enc)
-{
- EVP_CipherInit(evp, type, key, iv, enc);
- return 1;
-}
-
-int
-ssh_EVP_Cipher(EVP_CIPHER_CTX *evp, char *dst, char *src, int len)
-{
- EVP_Cipher(evp, dst, src, len);
- return 1;
-}
-
-int
-ssh_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *evp)
-{
- EVP_CIPHER_CTX_cleanup(evp);
- return 1;
-}
-#endif
-
-#ifndef HAVE_EVP_DIGESTINIT_EX
-int
-EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, void *engine)
-{
- if (engine != NULL)
- fatal("%s: ENGINE is not supported", __func__);
-# ifdef OPENSSL_EVP_DIGESTUPDATE_VOID
- EVP_DigestInit(ctx, md);
- return 1;
-# else
- return EVP_DigestInit(ctx, md);
-# endif
-}
-#endif
-
-#ifndef HAVE_EVP_DIGESTFINAL_EX
-int
-EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s)
-{
-# ifdef OPENSSL_EVP_DIGESTUPDATE_VOID
- EVP_DigestFinal(ctx, md, s);
- return 1;
-# else
- return EVP_DigestFinal(ctx, md, s);
-# endif
-}
-#endif
-
-#ifdef OPENSSL_EVP_DIGESTUPDATE_VOID
-int
-ssh_EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt)
-{
- EVP_DigestUpdate(ctx, d, cnt);
- return 1;
-}
-#endif
-
-#ifndef HAVE_EVP_MD_CTX_COPY_EX
-int
-EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
-{
- return EVP_MD_CTX_copy(out, in);
-}
-#endif
-
-#ifndef HAVE_BN_IS_PRIME_EX
-int
-BN_is_prime_ex(const BIGNUM *p, int nchecks, BN_CTX *ctx, void *cb)
-{
- if (cb != NULL)
- fatal("%s: callback args not supported", __func__);
- return BN_is_prime(p, nchecks, NULL, ctx, NULL);
-}
-#endif
-
-#ifndef HAVE_RSA_GENERATE_KEY_EX
-int
-RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *bn_e, void *cb)
-{
- RSA *new_rsa, tmp_rsa;
- unsigned long e;
-
- if (cb != NULL)
- fatal("%s: callback args not supported", __func__);
- e = BN_get_word(bn_e);
- if (e == 0xffffffffL)
- fatal("%s: value of e too large", __func__);
- new_rsa = RSA_generate_key(bits, e, NULL, NULL);
- if (new_rsa == NULL)
- return 0;
- /* swap rsa/new_rsa then free new_rsa */
- tmp_rsa = *rsa;
- *rsa = *new_rsa;
- *new_rsa = tmp_rsa;
- RSA_free(new_rsa);
- return 1;
-}
-#endif
+/*
+ * OpenSSL version numbers: MNNFFPPS: major minor fix patch status
+ * We match major, minor, fix and status (not patch) for <1.0.0.
+ * After that, we acceptable compatible fix versions (so we
+ * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed
+ * within a patch series.
+ */
-#ifndef HAVE_DSA_GENERATE_PARAMETERS_EX
int
-DSA_generate_parameters_ex(DSA *dsa, int bits, const unsigned char *seed,
- int seed_len, int *counter_ret, unsigned long *h_ret, void *cb)
+ssh_compatible_openssl(long headerver, long libver)
{
- DSA *new_dsa, tmp_dsa;
-
- if (cb != NULL)
- fatal("%s: callback args not supported", __func__);
- new_dsa = DSA_generate_parameters(bits, (unsigned char *)seed, seed_len,
- counter_ret, h_ret, NULL, NULL);
- if (new_dsa == NULL)
- return 0;
- /* swap dsa/new_dsa then free new_dsa */
- tmp_dsa = *dsa;
- *dsa = *new_dsa;
- *new_dsa = tmp_dsa;
- DSA_free(new_dsa);
- return 1;
-}
-#endif
-
-#ifndef HAVE_RSA_GET_DEFAULT_METHOD
-RSA_METHOD *
-RSA_get_default_method(void)
-{
- return RSA_PKCS1_SSLeay();
+ long mask, hfix, lfix;
+
+ /* exact match is always OK */
+ if (headerver == libver)
+ return 1;
+
+ /* for versions < 1.0.0, major,minor,fix,status must match */
+ if (headerver < 0x1000000f) {
+ mask = 0xfffff00fL; /* major,minor,fix,status */
+ return (headerver & mask) == (libver & mask);
+ }
+
+ /*
+ * For versions >= 1.0.0, major,minor,status must match and library
+ * fix version must be equal to or newer than the header.
+ */
+ mask = 0xfff0000fL; /* major,minor,status */
+ hfix = (headerver & 0x000ff000) >> 12;
+ lfix = (libver & 0x000ff000) >> 12;
+ if ( (headerver & mask) == (libver & mask) && lfix >= hfix)
+ return 1;
+ return 0;
}
-#endif
#ifdef USE_OPENSSL_ENGINE
void
diff --git a/openbsd-compat/openssl-compat.h b/openbsd-compat/openssl-compat.h
index 276b9706d273..3695d412b0c2 100644
--- a/openbsd-compat/openssl-compat.h
+++ b/openbsd-compat/openssl-compat.h
@@ -1,4 +1,4 @@
-/* $Id: openssl-compat.h,v 1.26 2014/02/13 05:38:33 dtucker Exp $ */
+/* $Id: openssl-compat.h,v 1.31 2014/08/29 18:18:29 djm Exp $ */
/*
* Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au>
@@ -16,28 +16,19 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#ifndef _OPENSSL_COMPAT_H
+#define _OPENSSL_COMPAT_H
+
#include "includes.h"
#include <openssl/opensslv.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
-/* Only in 0.9.8 */
-#ifndef OPENSSL_DSA_MAX_MODULUS_BITS
-# define OPENSSL_DSA_MAX_MODULUS_BITS 10000
-#endif
-#ifndef OPENSSL_RSA_MAX_MODULUS_BITS
-# define OPENSSL_RSA_MAX_MODULUS_BITS 16384
-#endif
-
-/* OPENSSL_free() is Free() in versions before OpenSSL 0.9.6 */
-#if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090600f)
-# define OPENSSL_free(x) Free(x)
-#endif
+int ssh_compatible_openssl(long, long);
-#if OPENSSL_VERSION_NUMBER < 0x00906000L
-# define SSH_OLD_EVP
-# define EVP_CIPHER_CTX_get_app_data(e) ((e)->app_data)
+#if (OPENSSL_VERSION_NUMBER <= 0x0090805fL)
+# error OpenSSL 0.9.8f or greater is required
#endif
#if OPENSSL_VERSION_NUMBER < 0x10000001L
@@ -46,27 +37,17 @@
# define LIBCRYPTO_EVP_INL_TYPE size_t
#endif
-#if (OPENSSL_VERSION_NUMBER < 0x00907000L) || defined(OPENSSL_LOBOTOMISED_AES)
-# define USE_BUILTIN_RIJNDAEL
+#ifndef OPENSSL_RSA_MAX_MODULUS_BITS
+# define OPENSSL_RSA_MAX_MODULUS_BITS 16384
#endif
-
-#ifdef USE_BUILTIN_RIJNDAEL
-# include "rijndael.h"
-# define AES_KEY rijndael_ctx
-# define AES_BLOCK_SIZE 16
-# define AES_encrypt(a, b, c) rijndael_encrypt(c, a, b)
-# define AES_set_encrypt_key(a, b, c) rijndael_set_key(c, (char *)a, b, 1)
-# define EVP_aes_128_cbc evp_rijndael
-# define EVP_aes_192_cbc evp_rijndael
-# define EVP_aes_256_cbc evp_rijndael
-const EVP_CIPHER *evp_rijndael(void);
-void ssh_rijndael_iv(EVP_CIPHER_CTX *, int, u_char *, u_int);
+#ifndef OPENSSL_DSA_MAX_MODULUS_BITS
+# define OPENSSL_DSA_MAX_MODULUS_BITS 10000
#endif
#ifndef OPENSSL_HAVE_EVPCTR
-#define EVP_aes_128_ctr evp_aes_128_ctr
-#define EVP_aes_192_ctr evp_aes_128_ctr
-#define EVP_aes_256_ctr evp_aes_128_ctr
+# define EVP_aes_128_ctr evp_aes_128_ctr
+# define EVP_aes_192_ctr evp_aes_128_ctr
+# define EVP_aes_256_ctr evp_aes_128_ctr
const EVP_CIPHER *evp_aes_128_ctr(void);
void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, size_t);
#endif
@@ -88,26 +69,9 @@ void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, size_t);
# endif
#endif
-#if OPENSSL_VERSION_NUMBER < 0x00907000L
-#define EVP_X_STATE(evp) &(evp).c
-#define EVP_X_STATE_LEN(evp) sizeof((evp).c)
-#else
-#define EVP_X_STATE(evp) (evp).cipher_data
-#define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size
-#endif
-
-/* OpenSSL 0.9.8e returns cipher key len not context key len */
-#if (OPENSSL_VERSION_NUMBER == 0x0090805fL)
-# define EVP_CIPHER_CTX_key_length(c) ((c)->key_len)
-#endif
-
-#ifndef HAVE_RSA_GET_DEFAULT_METHOD
-RSA_METHOD *RSA_get_default_method(void);
-#endif
-
/*
* We overload some of the OpenSSL crypto functions with ssh_* equivalents
- * which cater for older and/or less featureful OpenSSL version.
+ * to automatically handle OpenSSL engine initialisation.
*
* In order for the compat library to call the real functions, it must
* define SSH_DONT_OVERLOAD_OPENSSL_FUNCS before including this file and
@@ -115,19 +79,6 @@ RSA_METHOD *RSA_get_default_method(void);
*/
#ifndef SSH_DONT_OVERLOAD_OPENSSL_FUNCS
-# ifdef SSH_OLD_EVP
-# ifdef EVP_Cipher
-# undef EVP_Cipher
-# endif
-# define EVP_CipherInit(a,b,c,d,e) ssh_EVP_CipherInit((a),(b),(c),(d),(e))
-# define EVP_Cipher(a,b,c,d) ssh_EVP_Cipher((a),(b),(c),(d))
-# define EVP_CIPHER_CTX_cleanup(a) ssh_EVP_CIPHER_CTX_cleanup((a))
-# endif /* SSH_OLD_EVP */
-
-# ifdef OPENSSL_EVP_DIGESTUPDATE_VOID
-# define EVP_DigestUpdate(a,b,c) ssh_EVP_DigestUpdate((a),(b),(c))
-# endif
-
# ifdef USE_OPENSSL_ENGINE
# ifdef OpenSSL_add_all_algorithms
# undef OpenSSL_add_all_algorithms
@@ -135,48 +86,8 @@ RSA_METHOD *RSA_get_default_method(void);
# define OpenSSL_add_all_algorithms() ssh_OpenSSL_add_all_algorithms()
# endif
-# ifndef HAVE_BN_IS_PRIME_EX
-int BN_is_prime_ex(const BIGNUM *, int, BN_CTX *, void *);
-# endif
-
-# ifndef HAVE_DSA_GENERATE_PARAMETERS_EX
-int DSA_generate_parameters_ex(DSA *, int, const unsigned char *, int, int *,
- unsigned long *, void *);
-# endif
-
-# ifndef HAVE_RSA_GENERATE_KEY_EX
-int RSA_generate_key_ex(RSA *, int, BIGNUM *, void *);
-# endif
-
-# ifndef HAVE_EVP_DIGESTINIT_EX
-int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, void *);
-# endif
-
-# ifndef HAVE_EVP_DISESTFINAL_EX
-int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *);
-# endif
-
-# ifndef EVP_MD_CTX_COPY_EX
-int EVP_MD_CTX_copy_ex(EVP_MD_CTX *, const EVP_MD_CTX *);
-# endif
-
-int ssh_EVP_CipherInit(EVP_CIPHER_CTX *, const EVP_CIPHER *, unsigned char *,
- unsigned char *, int);
-int ssh_EVP_Cipher(EVP_CIPHER_CTX *, char *, char *, int);
-int ssh_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *);
void ssh_OpenSSL_add_all_algorithms(void);
-# ifndef HAVE_HMAC_CTX_INIT
-# define HMAC_CTX_init(a)
-# endif
-
-# ifndef HAVE_EVP_MD_CTX_INIT
-# define EVP_MD_CTX_init(a)
-# endif
-
-# ifndef HAVE_EVP_MD_CTX_CLEANUP
-# define EVP_MD_CTX_cleanup(a)
-# endif
-
#endif /* SSH_DONT_OVERLOAD_OPENSSL_FUNCS */
+#endif /* _OPENSSL_COMPAT_H */
diff --git a/openbsd-compat/port-uw.c b/openbsd-compat/port-uw.c
index b1fbfa208557..db24dbb94414 100644
--- a/openbsd-compat/port-uw.c
+++ b/openbsd-compat/port-uw.c
@@ -42,6 +42,7 @@
#include "key.h"
#include "auth-options.h"
#include "log.h"
+#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */
#include "servconf.h"
#include "hostfile.h"
#include "auth.h"
diff --git a/openbsd-compat/regress/Makefile.in b/openbsd-compat/regress/Makefile.in
index bcf214bd0217..dabdb091211d 100644
--- a/openbsd-compat/regress/Makefile.in
+++ b/openbsd-compat/regress/Makefile.in
@@ -1,4 +1,4 @@
-# $Id: Makefile.in,v 1.4 2006/08/19 09:12:14 dtucker Exp $
+# $Id: Makefile.in,v 1.5 2014/06/17 13:06:08 dtucker Exp $
sysconfdir=@sysconfdir@
piddir=@piddir@
@@ -16,11 +16,11 @@ LIBS=@LIBS@
LDFLAGS=@LDFLAGS@ $(LIBCOMPAT)
TESTPROGS=closefromtest$(EXEEXT) snprintftest$(EXEEXT) strduptest$(EXEEXT) \
- strtonumtest$(EXEEXT)
+ strtonumtest$(EXEEXT) opensslvertest$(EXEEXT)
all: t-exec ${OTHERTESTS}
-%$(EXEEXT): %.c
+%$(EXEEXT): %.c $(LIBCOMPAT)
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< $(LIBCOMPAT) $(LIBS)
t-exec: $(TESTPROGS)
diff --git a/openbsd-compat/regress/opensslvertest.c b/openbsd-compat/regress/opensslvertest.c
new file mode 100644
index 000000000000..5d019b5981a2
--- /dev/null
+++ b/openbsd-compat/regress/opensslvertest.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014 Darren Tucker
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+int ssh_compatible_openssl(long, long);
+
+struct version_test {
+ long headerver;
+ long libver;
+ int result;
+} version_tests[] = {
+ /* built with 0.9.8b release headers */
+ { 0x0090802fL, 0x0090802fL, 1}, /* exact match */
+ { 0x0090802fL, 0x0090804fL, 1}, /* newer library fix version: ok */
+ { 0x0090802fL, 0x0090801fL, 1}, /* older library fix version: ok */
+ { 0x0090802fL, 0x0090702fL, 0}, /* older library minor version: NO */
+ { 0x0090802fL, 0x0090902fL, 0}, /* newer library minor version: NO */
+ { 0x0090802fL, 0x0080802fL, 0}, /* older library major version: NO */
+ { 0x0090802fL, 0x1000100fL, 0}, /* newer library major version: NO */
+
+ /* built with 1.0.1b release headers */
+ { 0x1000101fL, 0x1000101fL, 1},/* exact match */
+ { 0x1000101fL, 0x1000102fL, 1}, /* newer library patch version: ok */
+ { 0x1000101fL, 0x1000100fL, 1}, /* older library patch version: ok */
+ { 0x1000101fL, 0x1000201fL, 1}, /* newer library fix version: ok */
+ { 0x1000101fL, 0x1000001fL, 0}, /* older library fix version: NO */
+ { 0x1000101fL, 0x1010101fL, 0}, /* newer library minor version: NO */
+ { 0x1000101fL, 0x0000101fL, 0}, /* older library major version: NO */
+ { 0x1000101fL, 0x2000101fL, 0}, /* newer library major version: NO */
+};
+
+void
+fail(long hver, long lver, int result)
+{
+ fprintf(stderr, "opensslver: header %lx library %lx != %d \n", hver, lver, result);
+ exit(1);
+}
+
+int
+main(void)
+{
+ unsigned int i;
+ int res;
+ long hver, lver;
+
+ for (i = 0; i < sizeof(version_tests) / sizeof(version_tests[0]); i++) {
+ hver = version_tests[i].headerver;
+ lver = version_tests[i].libver;
+ res = version_tests[i].result;
+ if (ssh_compatible_openssl(hver, lver) != res)
+ fail(hver, lver, res);
+ }
+ exit(0);
+}
diff --git a/opensshd.init.in b/opensshd.init.in
index 0db60caa7511..517345bfb7b9 100755
--- a/opensshd.init.in
+++ b/opensshd.init.in
@@ -21,6 +21,7 @@ HOST_KEY_RSA1=$sysconfdir/ssh_host_key
HOST_KEY_DSA=$sysconfdir/ssh_host_dsa_key
HOST_KEY_RSA=$sysconfdir/ssh_host_rsa_key
@COMMENT_OUT_ECC@HOST_KEY_ECDSA=$sysconfdir/ssh_host_ecdsa_key
+HOST_KEY_ED25519=$sysconfdir/ssh_host_ed25519_key
checkkeys() {
@@ -36,6 +37,9 @@ checkkeys() {
@COMMENT_OUT_ECC@ if [ ! -f $HOST_KEY_ECDSA ]; then
@COMMENT_OUT_ECC@ ${SSH_KEYGEN} -t ecdsa -f ${HOST_KEY_ECDSA} -N ""
@COMMENT_OUT_ECC@ fi
+ if [ ! -f $HOST_KEY_ED25519 ]; then
+ ${SSH_KEYGEN} -t ed25519 -f ${HOST_KEY_ED25519} -N ""
+ fi
}
stop_service() {
diff --git a/packet.c b/packet.c
index 54c0558f9952..6e7b87757f5f 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.192 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: packet.c,v 1.198 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -66,7 +66,6 @@
#include "crc32.h"
#include "compress.h"
#include "deattack.h"
-#include "channels.h"
#include "compat.h"
#include "ssh1.h"
#include "ssh2.h"
@@ -77,7 +76,9 @@
#include "log.h"
#include "canohost.h"
#include "misc.h"
+#include "channels.h"
#include "ssh.h"
+#include "ssherr.h"
#include "roaming.h"
#ifdef PACKET_DEBUG
@@ -222,6 +223,7 @@ void
packet_set_connection(int fd_in, int fd_out)
{
const Cipher *none = cipher_by_name("none");
+ int r;
if (none == NULL)
fatal("packet_set_connection: cannot load cipher 'none'");
@@ -229,10 +231,11 @@ packet_set_connection(int fd_in, int fd_out)
active_state = alloc_session_state();
active_state->connection_in = fd_in;
active_state->connection_out = fd_out;
- cipher_init(&active_state->send_context, none, (const u_char *)"",
- 0, NULL, 0, CIPHER_ENCRYPT);
- cipher_init(&active_state->receive_context, none, (const u_char *)"",
- 0, NULL, 0, CIPHER_DECRYPT);
+ if ((r = cipher_init(&active_state->send_context, none,
+ (const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 ||
+ (r = cipher_init(&active_state->receive_context, none,
+ (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0)
+ fatal("%s: cipher_init: %s", __func__, ssh_err(r));
active_state->newkeys[MODE_IN] = active_state->newkeys[MODE_OUT] = NULL;
if (!active_state->initialized) {
active_state->initialized = 1;
@@ -329,13 +332,15 @@ void
packet_get_keyiv(int mode, u_char *iv, u_int len)
{
CipherContext *cc;
+ int r;
if (mode == MODE_OUT)
cc = &active_state->send_context;
else
cc = &active_state->receive_context;
- cipher_get_keyiv(cc, iv, len);
+ if ((r = cipher_get_keyiv(cc, iv, len)) != 0)
+ fatal("%s: cipher_get_keyiv: %s", __func__, ssh_err(r));
}
int
@@ -381,13 +386,15 @@ void
packet_set_iv(int mode, u_char *dat)
{
CipherContext *cc;
+ int r;
if (mode == MODE_OUT)
cc = &active_state->send_context;
else
cc = &active_state->receive_context;
- cipher_set_keyiv(cc, dat);
+ if ((r = cipher_set_keyiv(cc, dat)) != 0)
+ fatal("%s: cipher_set_keyiv: %s", __func__, ssh_err(r));
}
int
@@ -552,6 +559,7 @@ void
packet_set_encryption_key(const u_char *key, u_int keylen, int number)
{
const Cipher *cipher = cipher_by_number(number);
+ int r;
if (cipher == NULL)
fatal("packet_set_encryption_key: unknown cipher number %d", number);
@@ -561,10 +569,11 @@ packet_set_encryption_key(const u_char *key, u_int keylen, int number)
fatal("packet_set_encryption_key: keylen too big: %d", keylen);
memcpy(active_state->ssh1_key, key, keylen);
active_state->ssh1_keylen = keylen;
- cipher_init(&active_state->send_context, cipher, key, keylen, NULL,
- 0, CIPHER_ENCRYPT);
- cipher_init(&active_state->receive_context, cipher, key, keylen, NULL,
- 0, CIPHER_DECRYPT);
+ if ((r = cipher_init(&active_state->send_context, cipher,
+ key, keylen, NULL, 0, CIPHER_ENCRYPT)) != 0 ||
+ (r = cipher_init(&active_state->receive_context, cipher,
+ key, keylen, NULL, 0, CIPHER_DECRYPT)) != 0)
+ fatal("%s: cipher_init: %s", __func__, ssh_err(r));
}
u_int
@@ -630,6 +639,7 @@ packet_put_raw(const void *buf, u_int len)
buffer_append(&active_state->outgoing_packet, buf, len);
}
+#ifdef WITH_OPENSSL
void
packet_put_bignum(BIGNUM * value)
{
@@ -641,6 +651,7 @@ packet_put_bignum2(BIGNUM * value)
{
buffer_put_bignum2(&active_state->outgoing_packet, value);
}
+#endif
#ifdef OPENSSL_HAS_ECC
void
@@ -742,7 +753,7 @@ set_newkeys(int mode)
Comp *comp;
CipherContext *cc;
u_int64_t *max_blocks;
- int crypt_type;
+ int r, crypt_type;
debug2("set_newkeys: mode %d", mode);
@@ -784,8 +795,9 @@ set_newkeys(int mode)
if (cipher_authlen(enc->cipher) == 0 && mac_init(mac) == 0)
mac->enabled = 1;
DBG(debug("cipher_init_context: %d", mode));
- cipher_init(cc, enc->cipher, enc->key, enc->key_len,
- enc->iv, enc->iv_len, crypt_type);
+ if ((r = cipher_init(cc, enc->cipher, enc->key, enc->key_len,
+ enc->iv, enc->iv_len, crypt_type)) != 0)
+ fatal("%s: cipher_init: %s", __func__, ssh_err(r));
/* Deleting the keys does not gain extra security */
/* explicit_bzero(enc->iv, enc->block_size);
explicit_bzero(enc->key, enc->key_len);
@@ -912,8 +924,8 @@ packet_send2_wrapped(void)
roundup(active_state->extra_pad, block_size);
pad = active_state->extra_pad -
((len + padlen) % active_state->extra_pad);
- debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)",
- pad, len, padlen, active_state->extra_pad);
+ DBG(debug3("%s: adding %d (len %d padlen %d extra_pad %d)",
+ __func__, pad, len, padlen, active_state->extra_pad));
padlen += pad;
active_state->extra_pad = 0;
}
@@ -1569,6 +1581,7 @@ packet_get_int64(void)
* must have been initialized before this call.
*/
+#ifdef WITH_OPENSSL
void
packet_get_bignum(BIGNUM * value)
{
@@ -1598,6 +1611,7 @@ packet_get_raw(u_int *length_ptr)
*length_ptr = bytes;
return buffer_ptr(&active_state->incoming_packet);
}
+#endif
int
packet_remaining(void)
@@ -1618,7 +1632,7 @@ packet_get_string(u_int *length_ptr)
return buffer_get_string(&active_state->incoming_packet, length_ptr);
}
-void *
+const void *
packet_get_string_ptr(u_int *length_ptr)
{
return buffer_get_string_ptr(&active_state->incoming_packet, length_ptr);
@@ -2055,3 +2069,23 @@ packet_restore_state(void)
add_recv_bytes(len);
}
}
+
+/* Reset after_authentication and reset compression in post-auth privsep */
+void
+packet_set_postauth(void)
+{
+ Comp *comp;
+ int mode;
+
+ debug("%s: called", __func__);
+ /* This was set in net child, but is not visible in user child */
+ active_state->after_authentication = 1;
+ active_state->rekeying = 0;
+ for (mode = 0; mode < MODE_MAX; mode++) {
+ if (active_state->newkeys[mode] == NULL)
+ continue;
+ comp = &active_state->newkeys[mode]->comp;
+ if (comp && comp->enabled)
+ packet_init_compression();
+ }
+}
diff --git a/packet.h b/packet.h
index f8edf851c210..e7b5fcba9fb0 100644
--- a/packet.h
+++ b/packet.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.h,v 1.59 2013/07/12 00:19:59 djm Exp $ */
+/* $OpenBSD: packet.h,v 1.61 2014/05/03 17:20:34 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -70,7 +70,7 @@ void packet_get_ecpoint(const EC_GROUP *, EC_POINT *);
void *packet_get_raw(u_int *length_ptr);
void *packet_get_string(u_int *length_ptr);
char *packet_get_cstring(u_int *length_ptr);
-void *packet_get_string_ptr(u_int *length_ptr);
+const void *packet_get_string_ptr(u_int *length_ptr);
void packet_disconnect(const char *fmt,...) __attribute__((noreturn)) __attribute__((format(printf, 1, 2)));
void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
@@ -120,6 +120,7 @@ time_t packet_get_rekey_timeout(void);
void packet_backup_state(void);
void packet_restore_state(void);
+void packet_set_postauth(void);
void *packet_get_input(void);
void *packet_get_output(void);
diff --git a/platform.c b/platform.c
index 30fc60909c8b..ee313da55930 100644
--- a/platform.c
+++ b/platform.c
@@ -1,4 +1,4 @@
-/* $Id: platform.c,v 1.21 2014/01/21 01:59:29 tim Exp $ */
+/* $Id: platform.c,v 1.22 2014/07/18 04:11:26 djm Exp $ */
/*
* Copyright (c) 2006 Darren Tucker. All rights reserved.
@@ -25,6 +25,7 @@
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "key.h"
#include "hostfile.h"
diff --git a/poly1305.h b/poly1305.h
index 221efc462e1b..f7db5f8d7c98 100644
--- a/poly1305.h
+++ b/poly1305.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: poly1305.h,v 1.2 2013/12/19 22:57:13 djm Exp $ */
+/* $OpenBSD: poly1305.h,v 1.4 2014/05/02 03:27:54 djm Exp $ */
/*
* Public Domain poly1305 from Andrew Moon
diff --git a/readconf.c b/readconf.c
index dc884c9b1e34..7948ce1cda71 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.218 2014/02/23 20:11:36 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.220 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -18,6 +18,7 @@
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -48,9 +49,9 @@
#include "pathnames.h"
#include "log.h"
#include "key.h"
+#include "misc.h"
#include "readconf.h"
#include "match.h"
-#include "misc.h"
#include "buffer.h"
#include "kex.h"
#include "mac.h"
@@ -149,6 +150,7 @@ typedef enum {
oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
+ oStreamLocalBindMask, oStreamLocalBindUnlink,
oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
@@ -261,6 +263,8 @@ static struct {
{ "canonicalizehostname", oCanonicalizeHostname },
{ "canonicalizemaxdots", oCanonicalizeMaxDots },
{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
+ { "streamlocalbindmask", oStreamLocalBindMask },
+ { "streamlocalbindunlink", oStreamLocalBindUnlink },
{ "ignoreunknown", oIgnoreUnknown },
{ NULL, oBadOption }
@@ -272,12 +276,13 @@ static struct {
*/
void
-add_local_forward(Options *options, const Forward *newfwd)
+add_local_forward(Options *options, const struct Forward *newfwd)
{
- Forward *fwd;
+ struct Forward *fwd;
#ifndef NO_IPPORT_RESERVED_CONCEPT
extern uid_t original_real_uid;
- if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
+ if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0 &&
+ newfwd->listen_path == NULL)
fatal("Privileged ports can only be forwarded by root.");
#endif
options->local_forwards = xrealloc(options->local_forwards,
@@ -287,8 +292,10 @@ add_local_forward(Options *options, const Forward *newfwd)
fwd->listen_host = newfwd->listen_host;
fwd->listen_port = newfwd->listen_port;
+ fwd->listen_path = newfwd->listen_path;
fwd->connect_host = newfwd->connect_host;
fwd->connect_port = newfwd->connect_port;
+ fwd->connect_path = newfwd->connect_path;
}
/*
@@ -297,9 +304,9 @@ add_local_forward(Options *options, const Forward *newfwd)
*/
void
-add_remote_forward(Options *options, const Forward *newfwd)
+add_remote_forward(Options *options, const struct Forward *newfwd)
{
- Forward *fwd;
+ struct Forward *fwd;
options->remote_forwards = xrealloc(options->remote_forwards,
options->num_remote_forwards + 1,
@@ -308,8 +315,10 @@ add_remote_forward(Options *options, const Forward *newfwd)
fwd->listen_host = newfwd->listen_host;
fwd->listen_port = newfwd->listen_port;
+ fwd->listen_path = newfwd->listen_path;
fwd->connect_host = newfwd->connect_host;
fwd->connect_port = newfwd->connect_port;
+ fwd->connect_path = newfwd->connect_path;
fwd->handle = newfwd->handle;
fwd->allocated_port = 0;
}
@@ -321,7 +330,9 @@ clear_forwardings(Options *options)
for (i = 0; i < options->num_local_forwards; i++) {
free(options->local_forwards[i].listen_host);
+ free(options->local_forwards[i].listen_path);
free(options->local_forwards[i].connect_host);
+ free(options->local_forwards[i].connect_path);
}
if (options->num_local_forwards > 0) {
free(options->local_forwards);
@@ -330,7 +341,9 @@ clear_forwardings(Options *options)
options->num_local_forwards = 0;
for (i = 0; i < options->num_remote_forwards; i++) {
free(options->remote_forwards[i].listen_host);
+ free(options->remote_forwards[i].listen_path);
free(options->remote_forwards[i].connect_host);
+ free(options->remote_forwards[i].connect_path);
}
if (options->num_remote_forwards > 0) {
free(options->remote_forwards);
@@ -345,6 +358,7 @@ add_identity_file(Options *options, const char *dir, const char *filename,
int userprovided)
{
char *path;
+ int i;
if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
fatal("Too many identity files specified (max %d)",
@@ -355,6 +369,16 @@ add_identity_file(Options *options, const char *dir, const char *filename,
else
(void)xasprintf(&path, "%.100s%.100s", dir, filename);
+ /* Avoid registering duplicates */
+ for (i = 0; i < options->num_identity_files; i++) {
+ if (options->identity_file_userprovided[i] == userprovided &&
+ strcmp(options->identity_files[i], path) == 0) {
+ debug2("%s: ignoring duplicate key %s", __func__, path);
+ free(path);
+ return;
+ }
+ }
+
options->identity_file_userprovided[options->num_identity_files] =
userprovided;
options->identity_files[options->num_identity_files++] = path;
@@ -704,7 +728,7 @@ process_config_line(Options *options, struct passwd *pw, const char *host,
LogLevel *log_level_ptr;
long long val64;
size_t len;
- Forward fwd;
+ struct Forward fwd;
const struct multistate *multistate_ptr;
struct allowed_cname *cname;
@@ -794,7 +818,7 @@ parse_time:
goto parse_time;
case oGatewayPorts:
- intptr = &options->gateway_ports;
+ intptr = &options->fwd_opts.gateway_ports;
goto parse_flag;
case oExitOnForwardFailure:
@@ -1394,6 +1418,21 @@ parse_int:
intptr = &options->canonicalize_fallback_local;
goto parse_flag;
+ case oStreamLocalBindMask:
+ arg = strdelim(&s);
+ if (!arg || *arg == '\0')
+ fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
+ /* Parse mode in octal format */
+ value = strtol(arg, &endofnumber, 8);
+ if (arg == endofnumber || value < 0 || value > 0777)
+ fatal("%.200s line %d: Bad mask.", filename, linenum);
+ options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
+ break;
+
+ case oStreamLocalBindUnlink:
+ intptr = &options->fwd_opts.streamlocal_bind_unlink;
+ goto parse_flag;
+
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
@@ -1491,7 +1530,9 @@ initialize_options(Options * options)
options->forward_x11_timeout = -1;
options->exit_on_forward_failure = -1;
options->xauth_location = NULL;
- options->gateway_ports = -1;
+ options->fwd_opts.gateway_ports = -1;
+ options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
+ options->fwd_opts.streamlocal_bind_unlink = -1;
options->use_privileged_port = -1;
options->rsa_authentication = -1;
options->pubkey_authentication = -1;
@@ -1604,8 +1645,12 @@ fill_default_options(Options * options)
options->exit_on_forward_failure = 0;
if (options->xauth_location == NULL)
options->xauth_location = _PATH_XAUTH;
- if (options->gateway_ports == -1)
- options->gateway_ports = 0;
+ if (options->fwd_opts.gateway_ports == -1)
+ options->fwd_opts.gateway_ports = 0;
+ if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
+ options->fwd_opts.streamlocal_bind_mask = 0177;
+ if (options->fwd_opts.streamlocal_bind_unlink == -1)
+ options->fwd_opts.streamlocal_bind_unlink = 0;
if (options->use_privileged_port == -1)
options->use_privileged_port = 0;
if (options->rsa_authentication == -1)
@@ -1757,22 +1802,92 @@ fill_default_options(Options * options)
/* options->preferred_authentications will be set in ssh */
}
+struct fwdarg {
+ char *arg;
+ int ispath;
+};
+
+/*
+ * parse_fwd_field
+ * parses the next field in a port forwarding specification.
+ * sets fwd to the parsed field and advances p past the colon
+ * or sets it to NULL at end of string.
+ * returns 0 on success, else non-zero.
+ */
+static int
+parse_fwd_field(char **p, struct fwdarg *fwd)
+{
+ char *ep, *cp = *p;
+ int ispath = 0;
+
+ if (*cp == '\0') {
+ *p = NULL;
+ return -1; /* end of string */
+ }
+
+ /*
+ * A field escaped with square brackets is used literally.
+ * XXX - allow ']' to be escaped via backslash?
+ */
+ if (*cp == '[') {
+ /* find matching ']' */
+ for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
+ if (*ep == '/')
+ ispath = 1;
+ }
+ /* no matching ']' or not at end of field. */
+ if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
+ return -1;
+ /* NUL terminate the field and advance p past the colon */
+ *ep++ = '\0';
+ if (*ep != '\0')
+ *ep++ = '\0';
+ fwd->arg = cp + 1;
+ fwd->ispath = ispath;
+ *p = ep;
+ return 0;
+ }
+
+ for (cp = *p; *cp != '\0'; cp++) {
+ switch (*cp) {
+ case '\\':
+ memmove(cp, cp + 1, strlen(cp + 1) + 1);
+ cp++;
+ break;
+ case '/':
+ ispath = 1;
+ break;
+ case ':':
+ *cp++ = '\0';
+ goto done;
+ }
+ }
+done:
+ fwd->arg = *p;
+ fwd->ispath = ispath;
+ *p = cp;
+ return 0;
+}
+
/*
* parse_forward
* parses a string containing a port forwarding specification of the form:
* dynamicfwd == 0
- * [listenhost:]listenport:connecthost:connectport
+ * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
+ * listenpath:connectpath
* dynamicfwd == 1
* [listenhost:]listenport
* returns number of arguments parsed or zero on error
*/
int
-parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
+parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
{
+ struct fwdarg fwdargs[4];
+ char *p, *cp;
int i;
- char *p, *cp, *fwdarg[4];
- memset(fwd, '\0', sizeof(*fwd));
+ memset(fwd, 0, sizeof(*fwd));
+ memset(fwdargs, 0, sizeof(fwdargs));
cp = p = xstrdup(fwdspec);
@@ -1780,39 +1895,70 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
while (isspace((u_char)*cp))
cp++;
- for (i = 0; i < 4; ++i)
- if ((fwdarg[i] = hpdelim(&cp)) == NULL)
+ for (i = 0; i < 4; ++i) {
+ if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
break;
+ }
/* Check for trailing garbage */
- if (cp != NULL)
+ if (cp != NULL && *cp != '\0') {
i = 0; /* failure */
+ }
switch (i) {
case 1:
- fwd->listen_host = NULL;
- fwd->listen_port = a2port(fwdarg[0]);
+ if (fwdargs[0].ispath) {
+ fwd->listen_path = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = PORT_STREAMLOCAL;
+ } else {
+ fwd->listen_host = NULL;
+ fwd->listen_port = a2port(fwdargs[0].arg);
+ }
fwd->connect_host = xstrdup("socks");
break;
case 2:
- fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
- fwd->listen_port = a2port(fwdarg[1]);
- fwd->connect_host = xstrdup("socks");
+ if (fwdargs[0].ispath && fwdargs[1].ispath) {
+ fwd->listen_path = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = PORT_STREAMLOCAL;
+ fwd->connect_path = xstrdup(fwdargs[1].arg);
+ fwd->connect_port = PORT_STREAMLOCAL;
+ } else if (fwdargs[1].ispath) {
+ fwd->listen_host = NULL;
+ fwd->listen_port = a2port(fwdargs[0].arg);
+ fwd->connect_path = xstrdup(fwdargs[1].arg);
+ fwd->connect_port = PORT_STREAMLOCAL;
+ } else {
+ fwd->listen_host = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = a2port(fwdargs[1].arg);
+ fwd->connect_host = xstrdup("socks");
+ }
break;
case 3:
- fwd->listen_host = NULL;
- fwd->listen_port = a2port(fwdarg[0]);
- fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
- fwd->connect_port = a2port(fwdarg[2]);
+ if (fwdargs[0].ispath) {
+ fwd->listen_path = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = PORT_STREAMLOCAL;
+ fwd->connect_host = xstrdup(fwdargs[1].arg);
+ fwd->connect_port = a2port(fwdargs[2].arg);
+ } else if (fwdargs[2].ispath) {
+ fwd->listen_host = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = a2port(fwdargs[1].arg);
+ fwd->connect_path = xstrdup(fwdargs[2].arg);
+ fwd->connect_port = PORT_STREAMLOCAL;
+ } else {
+ fwd->listen_host = NULL;
+ fwd->listen_port = a2port(fwdargs[0].arg);
+ fwd->connect_host = xstrdup(fwdargs[1].arg);
+ fwd->connect_port = a2port(fwdargs[2].arg);
+ }
break;
case 4:
- fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
- fwd->listen_port = a2port(fwdarg[1]);
- fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
- fwd->connect_port = a2port(fwdarg[3]);
+ fwd->listen_host = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = a2port(fwdargs[1].arg);
+ fwd->connect_host = xstrdup(fwdargs[2].arg);
+ fwd->connect_port = a2port(fwdargs[3].arg);
break;
default:
i = 0; /* failure */
@@ -1824,29 +1970,42 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
if (!(i == 1 || i == 2))
goto fail_free;
} else {
- if (!(i == 3 || i == 4))
- goto fail_free;
- if (fwd->connect_port <= 0)
+ if (!(i == 3 || i == 4)) {
+ if (fwd->connect_path == NULL &&
+ fwd->listen_path == NULL)
+ goto fail_free;
+ }
+ if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
goto fail_free;
}
- if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
+ if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
+ (!remotefwd && fwd->listen_port == 0))
goto fail_free;
-
if (fwd->connect_host != NULL &&
strlen(fwd->connect_host) >= NI_MAXHOST)
goto fail_free;
+ /* XXX - if connecting to a remote socket, max sun len may not match this host */
+ if (fwd->connect_path != NULL &&
+ strlen(fwd->connect_path) >= PATH_MAX_SUN)
+ goto fail_free;
if (fwd->listen_host != NULL &&
strlen(fwd->listen_host) >= NI_MAXHOST)
goto fail_free;
-
+ if (fwd->listen_path != NULL &&
+ strlen(fwd->listen_path) >= PATH_MAX_SUN)
+ goto fail_free;
return (i);
fail_free:
free(fwd->connect_host);
fwd->connect_host = NULL;
+ free(fwd->connect_path);
+ fwd->connect_path = NULL;
free(fwd->listen_host);
fwd->listen_host = NULL;
+ free(fwd->listen_path);
+ fwd->listen_path = NULL;
return (0);
}
diff --git a/readconf.h b/readconf.h
index 75e3f8f7ae38..0b9cb777a676 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.101 2014/02/23 20:11:36 djm Exp $ */
+/* $OpenBSD: readconf.h,v 1.102 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -16,21 +16,12 @@
#ifndef READCONF_H
#define READCONF_H
-/* Data structure for representing a forwarding request. */
-
-typedef struct {
- char *listen_host; /* Host (address) to listen on. */
- int listen_port; /* Port to forward. */
- char *connect_host; /* Host to connect. */
- int connect_port; /* Port to connect on connect_host. */
- int allocated_port; /* Dynamically allocated listen port */
- int handle; /* Handle for dynamic listen ports */
-} Forward;
/* Data structure for representing option data. */
#define MAX_SEND_ENV 256
#define SSH_MAX_HOSTS_FILES 32
#define MAX_CANON_DOMAINS 32
+#define PATH_MAX_SUN (sizeof((struct sockaddr_un *)0)->sun_path)
struct allowed_cname {
char *source_list;
@@ -44,7 +35,7 @@ typedef struct {
int forward_x11_trusted; /* Trust Forward X11 display. */
int exit_on_forward_failure; /* Exit if bind(2) fails for -L/-R */
char *xauth_location; /* Location for xauth program */
- int gateway_ports; /* Allow remote connects to forwarded ports. */
+ struct ForwardOptions fwd_opts; /* forwarding options */
int use_privileged_port; /* Don't use privileged port if false. */
int rhosts_rsa_authentication; /* Try rhosts with RSA
* authentication. */
@@ -106,11 +97,11 @@ typedef struct {
/* Local TCP/IP forward requests. */
int num_local_forwards;
- Forward *local_forwards;
+ struct Forward *local_forwards;
/* Remote TCP/IP forward requests. */
int num_remote_forwards;
- Forward *remote_forwards;
+ struct Forward *remote_forwards;
int clear_forwardings;
int enable_ssh_keysign;
@@ -181,12 +172,12 @@ int process_config_line(Options *, struct passwd *, const char *, char *,
const char *, int, int *, int);
int read_config_file(const char *, struct passwd *, const char *,
Options *, int);
-int parse_forward(Forward *, const char *, int, int);
+int parse_forward(struct Forward *, const char *, int, int);
int default_ssh_port(void);
int option_clear_or_none(const char *);
-void add_local_forward(Options *, const Forward *);
-void add_remote_forward(Options *, const Forward *);
+void add_local_forward(Options *, const struct Forward *);
+void add_remote_forward(Options *, const struct Forward *);
void add_identity_file(Options *, const char *, const char *, int);
#endif /* READCONF_H */
diff --git a/regress/Makefile b/regress/Makefile
index 6e3b8d634e2a..3feb7a997b6d 100644
--- a/regress/Makefile
+++ b/regress/Makefile
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.68 2014/01/25 04:35:32 dtucker Exp $
+# $OpenBSD: Makefile,v 1.70 2014/06/24 01:14:17 djm Exp $
-REGRESS_TARGETS= t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t-exec
+REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t-exec
tests: $(REGRESS_TARGETS)
# Interop tests are not run by default
@@ -180,3 +180,11 @@ t-exec-interop: ${INTEROP_TESTS:=.sh}
# Not run by default
interop: ${INTEROP_TARGETS}
+
+# Unit tests, built by top-level Makefile
+unit:
+ set -e ; if test -z "${SKIP_UNIT}" ; then \
+ ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
+ ${.OBJDIR}/unittests/sshkey/test_sshkey \
+ -d ${.CURDIR}//unittests/sshkey/testdata ; \
+ fi
diff --git a/regress/connect-privsep.sh b/regress/connect-privsep.sh
index 94cc64acf5de..41cb7af69641 100644
--- a/regress/connect-privsep.sh
+++ b/regress/connect-privsep.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: connect-privsep.sh,v 1.4 2012/07/02 14:37:06 dtucker Exp $
+# $OpenBSD: connect-privsep.sh,v 1.5 2014/05/04 10:40:59 logan Exp $
# Placed in the Public Domain.
tid="proxy connect with privsep"
@@ -26,7 +26,7 @@ done
# Because sandbox is sensitive to changes in libc, especially malloc, retest
# with every malloc.conf option (and none).
-for m in '' A F G H J P R S X Z '<' '>'; do
+for m in '' A F G H J P R S X '<' '>'; do
for p in 1 2; do
env MALLOC_OPTIONS="$m" ${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 true
if [ $? -ne 0 ]; then
diff --git a/regress/dhgex.sh b/regress/dhgex.sh
index 4c1a3d83cec2..57fca4a32e94 100755
--- a/regress/dhgex.sh
+++ b/regress/dhgex.sh
@@ -1,10 +1,11 @@
-# $OpenBSD: dhgex.sh,v 1.1 2014/01/25 04:35:32 dtucker Exp $
+# $OpenBSD: dhgex.sh,v 1.2 2014/04/21 22:15:37 djm Exp $
# Placed in the Public Domain.
tid="dhgex"
LOG=${TEST_SSH_LOGFILE}
rm -f ${LOG}
+cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
kexs=`${SSH} -Q kex | grep diffie-hellman-group-exchange`
@@ -14,6 +15,9 @@ ssh_test_dhgex()
cipher="$1"; shift
kex="$1"; shift
+ cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
+ echo "KexAlgorithms=$kex" >> $OBJ/sshd_proxy
+ echo "Ciphers=$cipher" >> $OBJ/sshd_proxy
rm -f ${LOG}
opts="-oKexAlgorithms=$kex -oCiphers=$cipher"
groupsz="1024<$bits<8192"
diff --git a/regress/forwarding.sh b/regress/forwarding.sh
index 94873f22c24c..f799d49514ab 100644
--- a/regress/forwarding.sh
+++ b/regress/forwarding.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: forwarding.sh,v 1.11 2013/06/10 21:56:43 dtucker Exp $
+# $OpenBSD: forwarding.sh,v 1.12 2014/07/15 15:54:15 millert Exp $
# Placed in the Public Domain.
tid="local and remote forwarding"
@@ -28,7 +28,7 @@ for p in 1 2; do
trace "transfer over forwarded channels and check result"
${SSH} -$q -F $OBJ/ssh_config -p$last -o 'ConnectionAttempts=4' \
somehost cat ${DATA} > ${COPY}
- test -f ${COPY} || fail "failed copy of ${DATA}"
+ test -s ${COPY} || fail "failed copy of ${DATA}"
cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}"
sleep 10
@@ -114,8 +114,24 @@ for p in 1 2; do
trace "config file: transfer over forwarded channels and check result"
${SSH} -F $OBJ/ssh_config -p${base}02 -o 'ConnectionAttempts=4' \
somehost cat ${DATA} > ${COPY}
- test -f ${COPY} || fail "failed copy of ${DATA}"
+ test -s ${COPY} || fail "failed copy of ${DATA}"
cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}"
wait
done
+
+for p in 2; do
+ trace "transfer over chained unix domain socket forwards and check result"
+ rm -f $OBJ/unix-[123].fwd
+ ${SSH} -f -F $OBJ/ssh_config -R${base}01:[$OBJ/unix-1.fwd] somehost sleep 10
+ ${SSH} -f -F $OBJ/ssh_config -L[$OBJ/unix-1.fwd]:[$OBJ/unix-2.fwd] somehost sleep 10
+ ${SSH} -f -F $OBJ/ssh_config -R[$OBJ/unix-2.fwd]:[$OBJ/unix-3.fwd] somehost sleep 10
+ ${SSH} -f -F $OBJ/ssh_config -L[$OBJ/unix-3.fwd]:127.0.0.1:$PORT somehost sleep 10
+ ${SSH} -F $OBJ/ssh_config -p${base}01 -o 'ConnectionAttempts=4' \
+ somehost cat ${DATA} > ${COPY}
+ test -s ${COPY} || fail "failed copy ${DATA}"
+ cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}"
+
+ #wait
+ sleep 10
+done
diff --git a/regress/integrity.sh b/regress/integrity.sh
index 852d82690e9c..d3a489ff78a0 100755
--- a/regress/integrity.sh
+++ b/regress/integrity.sh
@@ -1,7 +1,8 @@
-# $OpenBSD: integrity.sh,v 1.12 2013/11/21 03:18:51 djm Exp $
+# $OpenBSD: integrity.sh,v 1.14 2014/05/21 07:04:21 djm Exp $
# Placed in the Public Domain.
tid="integrity"
+cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
# start at byte 2900 (i.e. after kex) and corrupt at different offsets
# XXX the test hangs if we modify the low bytes of the packet length
@@ -34,11 +35,15 @@ for m in $macs; do
# avoid modifying the high bytes of the length
continue
fi
+ cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
# modify output from sshd at offset $off
pxy="proxycommand=$cmd | $OBJ/modpipe -wm xor:$off:1"
if ssh -Q cipher-auth | grep "^${m}\$" >/dev/null 2>&1 ; then
+ echo "Ciphers=$m" >> $OBJ/sshd_proxy
macopt="-c $m"
else
+ echo "Ciphers=aes128-ctr" >> $OBJ/sshd_proxy
+ echo "MACs=$m" >> $OBJ/sshd_proxy
macopt="-m $m -c aes128-ctr"
fi
verbose "test $tid: $m @$off"
@@ -49,14 +54,14 @@ for m in $macs; do
fail "ssh -m $m succeeds with bit-flip at $off"
fi
ecnt=`expr $ecnt + 1`
- output=$(tail -2 $TEST_SSH_LOGFILE | egrep -v "^debug" | \
+ out=$(tail -2 $TEST_SSH_LOGFILE | egrep -v "^debug" | \
tr -s '\r\n' '.')
- case "$output" in
+ case "$out" in
Bad?packet*) elen=`expr $elen + 1`; skip=3;;
Corrupted?MAC* | Decryption?integrity?check?failed*)
emac=`expr $emac + 1`; skip=0;;
padding*) epad=`expr $epad + 1`; skip=0;;
- *) fail "unexpected error mac $m at $off";;
+ *) fail "unexpected error mac $m at $off: $out";;
esac
done
verbose "test $tid: $ecnt errors: mac $emac padding $epad length $elen"
diff --git a/regress/kextype.sh b/regress/kextype.sh
index 8c2ac09d66d7..6f952f4e4acd 100755
--- a/regress/kextype.sh
+++ b/regress/kextype.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: kextype.sh,v 1.4 2013/11/07 04:26:56 dtucker Exp $
+# $OpenBSD: kextype.sh,v 1.5 2014/04/21 22:15:37 djm Exp $
# Placed in the Public Domain.
tid="login with different key exchange algorithms"
@@ -7,6 +7,11 @@ TIME=/usr/bin/time
cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak
+# Make server accept all key exchanges.
+ALLKEX=`ssh -Q kex`
+KEXOPT=`echo $ALLKEX | tr ' ' ,`
+echo "KexAlgorithms=$KEXOPT" >> $OBJ/sshd_proxy
+
tries="1 2 3 4"
for k in `${SSH} -Q kex`; do
verbose "kex $k"
diff --git a/regress/krl.sh b/regress/krl.sh
index 09246371c558..287384b4af2b 100755
--- a/regress/krl.sh
+++ b/regress/krl.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: krl.sh,v 1.2 2013/11/21 03:15:46 djm Exp $
+# $OpenBSD: krl.sh,v 1.3 2014/06/24 01:04:43 djm Exp $
# Placed in the Public Domain.
tid="key revocation lists"
@@ -37,6 +37,9 @@ serial: 700-797
serial: 798
serial: 799
serial: 599-701
+# Some multiple consecutive serial number ranges
+serial: 10000-20000
+serial: 30000-40000
EOF
# A specification that revokes some certificated by key ID.
diff --git a/regress/login-timeout.sh b/regress/login-timeout.sh
index d9b48f391021..eb76f554b459 100644
--- a/regress/login-timeout.sh
+++ b/regress/login-timeout.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: login-timeout.sh,v 1.6 2014/02/27 20:04:16 djm Exp $
+# $OpenBSD: login-timeout.sh,v 1.7 2014/03/13 20:44:49 djm Exp $
# Placed in the Public Domain.
tid="connect after login grace timeout"
@@ -22,6 +22,7 @@ $SUDO kill `$SUDO cat $PIDFILE`
trace "test login grace without privsep"
echo "UsePrivilegeSeparation no" >> $OBJ/sshd_config
start_sshd
+sleep 1
(echo SSH-2.0-fake; sleep 60) | telnet 127.0.0.1 ${PORT} >/dev/null 2>&1 &
sleep 15
diff --git a/regress/multiplex.sh b/regress/multiplex.sh
index 3e697e691eb2..8ee140be6dd9 100644
--- a/regress/multiplex.sh
+++ b/regress/multiplex.sh
@@ -1,10 +1,26 @@
-# $OpenBSD: multiplex.sh,v 1.21 2013/05/17 04:29:14 dtucker Exp $
+# $OpenBSD: multiplex.sh,v 1.25 2014/07/22 01:32:12 djm Exp $
# Placed in the Public Domain.
CTL=/tmp/openssh.regress.ctl-sock.$$
tid="connection multiplexing"
+if have_prog nc ; then
+ if nc -h 2>&1 | grep -- -N >/dev/null; then
+ NC="nc -N";
+ elif nc -h 2>&1 | grep -- "-U.*Use UNIX" >/dev/null ; then
+ NC="nc"
+ else
+ echo "nc is incompatible"
+ fi
+fi
+
+if test -z "$NC" ; then
+ echo "skipped (no compatible nc found)"
+ exit 0
+fi
+
+trace "will use ProxyCommand $proxycmd"
if config_defined DISABLE_FD_PASSING ; then
echo "skipped (not supported on this platform)"
exit 0
@@ -29,7 +45,8 @@ start_mux_master()
trace "start master, fork to background"
${SSH} -Nn2 -MS$CTL -F $OBJ/ssh_config -oSendEnv="_XXX_TEST" somehost \
-E $TEST_REGRESS_LOGFILE 2>&1 &
- MASTER_PID=$!
+ # NB. $SSH_PID will be killed by test-exec.sh:cleanup on fatal errors.
+ SSH_PID=$!
wait_for_mux_master_ready
}
@@ -71,6 +88,25 @@ test -f ${COPY} || fail "scp: failed copy ${DATA}"
cmp ${DATA} ${COPY} || fail "scp: corrupted copy of ${DATA}"
rm -f ${COPY}
+verbose "test $tid: forward"
+trace "forward over TCP/IP and check result"
+$NC -l 127.0.0.1 $((${PORT} + 1)) < ${DATA} &
+netcat_pid=$!
+${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L127.0.0.1:$((${PORT} + 2)):127.0.0.1:$((${PORT} + 1)) otherhost >>$TEST_SSH_LOGFILE 2>&1
+$NC -d 127.0.0.1 $((${PORT} + 2)) > ${COPY} < /dev/null
+cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}"
+kill $netcat_pid 2>/dev/null
+rm -f ${COPY} $OBJ/unix-[123].fwd
+
+trace "forward over UNIX and check result"
+$NC -Ul $OBJ/unix-1.fwd < ${DATA} &
+netcat_pid=$!
+${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L$OBJ/unix-2.fwd:$OBJ/unix-1.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1
+${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R$OBJ/unix-3.fwd:$OBJ/unix-2.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1
+$NC -d -U $OBJ/unix-3.fwd > ${COPY} </dev/null
+cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}"
+kill $netcat_pid 2>/dev/null
+rm -f ${COPY} $OBJ/unix-[123].fwd
for s in 0 1 4 5 44; do
trace "exit status $s over multiplexed connection"
@@ -95,7 +131,7 @@ verbose "test $tid: cmd check"
${SSH} -F $OBJ/ssh_config -S $CTL -Ocheck otherhost >>$TEST_REGRESS_LOGFILE 2>&1 \
|| fail "check command failed"
-verbose "test $tid: cmd forward local"
+verbose "test $tid: cmd forward local (TCP)"
${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L $P:localhost:$PORT otherhost \
|| fail "request local forward failed"
${SSH} -F $OBJ/ssh_config -p$P otherhost true \
@@ -105,7 +141,7 @@ ${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -L $P:localhost:$PORT otherhost \
${SSH} -F $OBJ/ssh_config -p$P otherhost true \
&& fail "local forward port still listening"
-verbose "test $tid: cmd forward remote"
+verbose "test $tid: cmd forward remote (TCP)"
${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R $P:localhost:$PORT otherhost \
|| fail "request remote forward failed"
${SSH} -F $OBJ/ssh_config -p$P otherhost true \
@@ -115,13 +151,35 @@ ${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -R $P:localhost:$PORT otherhost \
${SSH} -F $OBJ/ssh_config -p$P otherhost true \
&& fail "remote forward port still listening"
+verbose "test $tid: cmd forward local (UNIX)"
+${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L $OBJ/unix-1.fwd:localhost:$PORT otherhost \
+ || fail "request local forward failed"
+echo "" | $NC -U $OBJ/unix-1.fwd | grep "Protocol mismatch" >/dev/null 2>&1 \
+ || fail "connect to local forward path failed"
+${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -L $OBJ/unix-1.fwd:localhost:$PORT otherhost \
+ || fail "cancel local forward failed"
+N=$(echo "xyzzy" | $NC -U $OBJ/unix-1.fwd 2>&1 | grep "xyzzy" | wc -l)
+test ${N} -eq 0 || fail "local forward path still listening"
+rm -f $OBJ/unix-1.fwd
+
+verbose "test $tid: cmd forward remote (UNIX)"
+${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R $OBJ/unix-1.fwd:localhost:$PORT otherhost \
+ || fail "request remote forward failed"
+echo "" | $NC -U $OBJ/unix-1.fwd | grep "Protocol mismatch" >/dev/null 2>&1 \
+ || fail "connect to remote forwarded path failed"
+${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -R $OBJ/unix-1.fwd:localhost:$PORT otherhost \
+ || fail "cancel remote forward failed"
+N=$(echo "xyzzy" | $NC -U $OBJ/unix-1.fwd 2>&1 | grep "xyzzy" | wc -l)
+test ${N} -eq 0 || fail "remote forward path still listening"
+rm -f $OBJ/unix-1.fwd
+
verbose "test $tid: cmd exit"
${SSH} -F $OBJ/ssh_config -S $CTL -Oexit otherhost >>$TEST_REGRESS_LOGFILE 2>&1 \
|| fail "send exit command failed"
# Wait for master to exit
-wait $MASTER_PID
-kill -0 $MASTER_PID >/dev/null 2>&1 && fail "exit command failed"
+wait $SSH_PID
+kill -0 $SSH_PID >/dev/null 2>&1 && fail "exit command failed"
# Restart master and test -O stop command with master using -N
verbose "test $tid: cmd stop"
@@ -138,6 +196,8 @@ ${SSH} -F $OBJ/ssh_config -S $CTL -Ostop otherhost >>$TEST_REGRESS_LOGFILE 2>&1
# wait until both long-running command and master have exited.
wait $SLEEP_PID
[ $! != 0 ] || fail "waiting for concurrent command"
-wait $MASTER_PID
+wait $SSH_PID
[ $! != 0 ] || fail "waiting for master stop"
-kill -0 $MASTER_PID >/dev/null 2>&1 && fail "stop command failed"
+kill -0 $SSH_PID >/dev/null 2>&1 && fatal "stop command failed"
+SSH_PID="" # Already gone, so don't kill in cleanup
+
diff --git a/regress/proxy-connect.sh b/regress/proxy-connect.sh
index 76e602dd6ae5..023ba73678dd 100644
--- a/regress/proxy-connect.sh
+++ b/regress/proxy-connect.sh
@@ -1,26 +1,31 @@
-# $OpenBSD: proxy-connect.sh,v 1.6 2013/03/07 00:20:34 djm Exp $
+# $OpenBSD: proxy-connect.sh,v 1.7 2014/05/03 18:46:14 dtucker Exp $
# Placed in the Public Domain.
tid="proxy connect"
-verbose "plain username"
-for p in 1 2; do
- ${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 true
- if [ $? -ne 0 ]; then
- fail "ssh proxyconnect protocol $p failed"
- fi
- SSH_CONNECTION=`${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 'echo $SSH_CONNECTION'`
+mv $OBJ/sshd_proxy $OBJ/sshd_proxy.orig
+
+for ps in no yes; do
+ cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
+ echo "UsePrivilegeSeparation $ps" >> $OBJ/sshd_proxy
+
+ for p in 1 2; do
+ for c in no yes; do
+ verbose "plain username protocol $p privsep=$ps comp=$c"
+ opts="-$p -oCompression=$c -F $OBJ/ssh_proxy"
+ SSH_CONNECTION=`${SSH} $opts 999.999.999.999 'echo $SSH_CONNECTION'`
if [ $? -ne 0 ]; then
- fail "ssh proxyconnect protocol $p failed"
+ fail "ssh proxyconnect protocol $p privsep=$ps comp=$c failed"
fi
if [ "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ]; then
- fail "bad SSH_CONNECTION"
+ fail "bad SSH_CONNECTION protocol $p privsep=$ps comp=$c"
fi
+ done
+ done
done
-verbose "username with style"
for p in 1 2; do
+ verbose "username with style protocol $p"
${SSH} -$p -F $OBJ/ssh_proxy ${USER}:style@999.999.999.999 true || \
fail "ssh proxyconnect protocol $p failed"
done
-
diff --git a/regress/rekey.sh b/regress/rekey.sh
index cf9401ea014f..fd452b034518 100644
--- a/regress/rekey.sh
+++ b/regress/rekey.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: rekey.sh,v 1.14 2013/11/21 03:18:51 djm Exp $
+# $OpenBSD: rekey.sh,v 1.15 2014/04/21 22:15:37 djm Exp $
# Placed in the Public Domain.
tid="rekey"
@@ -6,14 +6,22 @@ tid="rekey"
LOG=${TEST_SSH_LOGFILE}
rm -f ${LOG}
+cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
# Test rekeying based on data volume only.
# Arguments will be passed to ssh.
ssh_data_rekeying()
{
+ _kexopt=$1 ; shift
+ _opts="$@"
+ if ! test -z "$_kexopts" ; then
+ cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
+ echo "$_kexopt" >> $OBJ/sshd_proxy
+ _opts="$_opts -o$_kexopt"
+ fi
rm -f ${COPY} ${LOG}
- ${SSH} <${DATA} -oCompression=no $@ -v -F $OBJ/ssh_proxy somehost \
- "cat > ${COPY}"
+ _opts="$_opts -oCompression=no"
+ ${SSH} <${DATA} $_opts -v -F $OBJ/ssh_proxy somehost "cat > ${COPY}"
if [ $? -ne 0 ]; then
fail "ssh failed ($@)"
fi
@@ -41,7 +49,7 @@ done
for opt in $opts; do
verbose "client rekey $opt"
- ssh_data_rekeying -oRekeyLimit=256k -o$opt
+ ssh_data_rekeying "$opt" -oRekeyLimit=256k
done
# AEAD ciphers are magical so test with all KexAlgorithms
@@ -49,14 +57,14 @@ if ${SSH} -Q cipher-auth | grep '^.*$' >/dev/null 2>&1 ; then
for c in `${SSH} -Q cipher-auth`; do
for kex in `${SSH} -Q kex`; do
verbose "client rekey $c $kex"
- ssh_data_rekeying -oRekeyLimit=256k -oCiphers=$c -oKexAlgorithms=$kex
+ ssh_data_rekeying "KexAlgorithms=$kex" -oRekeyLimit=256k -oCiphers=$c
done
done
fi
for s in 16 1k 128k 256k; do
verbose "client rekeylimit ${s}"
- ssh_data_rekeying -oCompression=no -oRekeyLimit=$s
+ ssh_data_rekeying "" -oCompression=no -oRekeyLimit=$s
done
for s in 5 10; do
diff --git a/regress/test-exec.sh b/regress/test-exec.sh
index aac8aa5c2f6e..a1bab832f81c 100644
--- a/regress/test-exec.sh
+++ b/regress/test-exec.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: test-exec.sh,v 1.47 2013/11/09 05:41:34 dtucker Exp $
+# $OpenBSD: test-exec.sh,v 1.48 2014/07/06 07:42:03 djm Exp $
# Placed in the Public Domain.
#SUDO=sudo
@@ -240,13 +240,20 @@ md5 () {
# helper
cleanup ()
{
+ if [ "x$SSH_PID" != "x" ]; then
+ if [ $SSH_PID -lt 2 ]; then
+ echo bad pid for ssh: $SSH_PID
+ else
+ kill $SSH_PID
+ fi
+ fi
if [ -f $PIDFILE ]; then
pid=`$SUDO cat $PIDFILE`
if [ "X$pid" = "X" ]; then
echo no sshd running
else
if [ $pid -lt 2 ]; then
- echo bad pid for ssh: $pid
+ echo bad pid for sshd: $pid
else
$SUDO kill $pid
trace "wait for sshd to exit"
diff --git a/regress/try-ciphers.sh b/regress/try-ciphers.sh
index ac34cedbf910..2881ce16c13b 100644
--- a/regress/try-ciphers.sh
+++ b/regress/try-ciphers.sh
@@ -1,13 +1,18 @@
-# $OpenBSD: try-ciphers.sh,v 1.22 2013/11/21 03:18:51 djm Exp $
+# $OpenBSD: try-ciphers.sh,v 1.23 2014/04/21 22:15:37 djm Exp $
# Placed in the Public Domain.
tid="try ciphers"
+cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
+
for c in `${SSH} -Q cipher`; do
n=0
for m in `${SSH} -Q mac`; do
trace "proto 2 cipher $c mac $m"
verbose "test $tid: proto 2 cipher $c mac $m"
+ cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
+ echo "Ciphers=$c" >> $OBJ/sshd_proxy
+ echo "MACs=$m" >> $OBJ/sshd_proxy
${SSH} -F $OBJ/ssh_proxy -2 -m $m -c $c somehost true
if [ $? -ne 0 ]; then
fail "ssh -2 failed with mac $m cipher $c"
diff --git a/regress/unittests/Makefile b/regress/unittests/Makefile
new file mode 100644
index 000000000000..bdb4574e2f55
--- /dev/null
+++ b/regress/unittests/Makefile
@@ -0,0 +1,5 @@
+# $OpenBSD: Makefile,v 1.1 2014/04/30 05:32:00 djm Exp $
+
+SUBDIR= test_helper sshbuf sshkey
+
+.include <bsd.subdir.mk>
diff --git a/regress/unittests/Makefile.inc b/regress/unittests/Makefile.inc
new file mode 100644
index 000000000000..4c33637495c0
--- /dev/null
+++ b/regress/unittests/Makefile.inc
@@ -0,0 +1,59 @@
+# $OpenBSD: Makefile.inc,v 1.1 2014/04/30 05:32:00 djm Exp $
+
+.include <bsd.own.mk>
+.include <bsd.obj.mk>
+
+# enable warnings
+WARNINGS=Yes
+
+DEBUG=-g
+CFLAGS+= -fstack-protector-all
+CDIAGFLAGS= -Wall
+CDIAGFLAGS+= -Wextra
+CDIAGFLAGS+= -Werror
+CDIAGFLAGS+= -Wchar-subscripts
+CDIAGFLAGS+= -Wcomment
+CDIAGFLAGS+= -Wformat
+CDIAGFLAGS+= -Wformat-security
+CDIAGFLAGS+= -Wimplicit
+CDIAGFLAGS+= -Winline
+CDIAGFLAGS+= -Wmissing-declarations
+CDIAGFLAGS+= -Wmissing-prototypes
+CDIAGFLAGS+= -Wparentheses
+CDIAGFLAGS+= -Wpointer-arith
+CDIAGFLAGS+= -Wpointer-sign
+CDIAGFLAGS+= -Wreturn-type
+CDIAGFLAGS+= -Wshadow
+CDIAGFLAGS+= -Wsign-compare
+CDIAGFLAGS+= -Wstrict-aliasing
+CDIAGFLAGS+= -Wstrict-prototypes
+CDIAGFLAGS+= -Wswitch
+CDIAGFLAGS+= -Wtrigraphs
+CDIAGFLAGS+= -Wuninitialized
+CDIAGFLAGS+= -Wunused
+.if ${COMPILER_VERSION} == "gcc4"
+CDIAGFLAGS+= -Wold-style-definition
+.endif
+
+SSHREL=../../../../../usr.bin/ssh
+
+CFLAGS+=-I${.CURDIR}/../test_helper -I${.CURDIR}/${SSHREL}
+
+.if exists(${.CURDIR}/../test_helper/${__objdir})
+LDADD+=-L${.CURDIR}/../test_helper/${__objdir} -ltest_helper
+DPADD+=${.CURDIR}/../test_helper/${__objdir}/libtest_helper.a
+.else
+LDADD+=-L${.CURDIR}/../test_helper -ltest_helper
+DPADD+=${.CURDIR}/../test_helper/libtest_helper.a
+.endif
+
+.if exists(${.CURDIR}/${SSHREL}/lib/${__objdir})
+LDADD+=-L${.CURDIR}/${SSHREL}/lib/${__objdir} -lssh
+DPADD+=${.CURDIR}/${SSHREL}/lib/${__objdir}/libssh.a
+.else
+LDADD+=-L${.CURDIR}/${SSHREL}/lib -lssh
+DPADD+=${.CURDIR}/${SSHREL}/lib/libssh.a
+.endif
+
+LDADD+= -lcrypto
+DPADD+= ${LIBCRYPTO}
diff --git a/regress/unittests/sshbuf/Makefile b/regress/unittests/sshbuf/Makefile
new file mode 100644
index 000000000000..85f99ac38314
--- /dev/null
+++ b/regress/unittests/sshbuf/Makefile
@@ -0,0 +1,14 @@
+# $OpenBSD: Makefile,v 1.1 2014/04/30 05:32:00 djm Exp $
+
+PROG=test_sshbuf
+SRCS=tests.c
+SRCS+=test_sshbuf.c
+SRCS+=test_sshbuf_getput_basic.c
+SRCS+=test_sshbuf_getput_crypto.c
+SRCS+=test_sshbuf_misc.c
+SRCS+=test_sshbuf_fuzz.c
+SRCS+=test_sshbuf_getput_fuzz.c
+SRCS+=test_sshbuf_fixed.c
+
+.include <bsd.regress.mk>
+
diff --git a/regress/unittests/sshbuf/test_sshbuf.c b/regress/unittests/sshbuf/test_sshbuf.c
new file mode 100644
index 000000000000..ee77d6934a4d
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf.c
@@ -0,0 +1,240 @@
+/* $OpenBSD: test_sshbuf.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#define SSHBUF_INTERNAL 1 /* access internals for testing */
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "ssherr.h"
+#include "sshbuf.h"
+
+void sshbuf_tests(void);
+
+void
+sshbuf_tests(void)
+{
+ struct sshbuf *p1;
+ const u_char *cdp;
+ u_char *dp;
+ size_t sz;
+ int r;
+
+ TEST_START("allocate sshbuf");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ TEST_DONE();
+
+ TEST_START("max size on fresh buffer");
+ ASSERT_SIZE_T_GT(sshbuf_max_size(p1), 0);
+ TEST_DONE();
+
+ TEST_START("available on fresh buffer");
+ ASSERT_SIZE_T_GT(sshbuf_avail(p1), 0);
+ TEST_DONE();
+
+ TEST_START("len = 0 on empty buffer");
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ TEST_DONE();
+
+ TEST_START("set valid max size");
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 65536), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 65536);
+ TEST_DONE();
+
+ TEST_START("available on limited buffer");
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 65536);
+ TEST_DONE();
+
+ TEST_START("free");
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("consume on empty buffer");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0);
+ ASSERT_INT_EQ(sshbuf_consume(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("consume_end on empty buffer");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_consume_end(p1, 0), 0);
+ ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("reserve space");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ r = sshbuf_reserve(p1, 1, &dp);
+ ASSERT_INT_EQ(r, 0);
+ ASSERT_PTR_NE(dp, NULL);
+ *dp = 0x11;
+ r = sshbuf_reserve(p1, 3, &dp);
+ ASSERT_INT_EQ(r, 0);
+ ASSERT_PTR_NE(dp, NULL);
+ *dp++ = 0x22;
+ *dp++ = 0x33;
+ *dp++ = 0x44;
+ TEST_DONE();
+
+ TEST_START("sshbuf_len on filled buffer");
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+ TEST_DONE();
+
+ TEST_START("sshbuf_ptr on filled buffer");
+ cdp = sshbuf_ptr(p1);
+ ASSERT_PTR_NE(cdp, NULL);
+ ASSERT_U8_EQ(cdp[0], 0x11);
+ ASSERT_U8_EQ(cdp[1], 0x22);
+ ASSERT_U8_EQ(cdp[2], 0x33);
+ ASSERT_U8_EQ(cdp[3], 0x44);
+ TEST_DONE();
+
+ TEST_START("consume on filled buffer");
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+ ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+ r = sshbuf_consume(p1, 64);
+ ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+ ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 3);
+ cdp = sshbuf_ptr(p1);
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_U8_EQ(cdp[0], 0x22);
+ ASSERT_INT_EQ(sshbuf_consume(p1, 2), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+ cdp = sshbuf_ptr(p1);
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_U8_EQ(cdp[0], 0x44);
+ r = sshbuf_consume(p1, 2);
+ ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+ ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ r = sshbuf_consume(p1, 1);
+ ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("consume_end on filled buffer");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ r = sshbuf_reserve(p1, 4, &dp);
+ ASSERT_INT_EQ(r, 0);
+ ASSERT_PTR_NE(dp, NULL);
+ *dp++ = 0x11;
+ *dp++ = 0x22;
+ *dp++ = 0x33;
+ *dp++ = 0x44;
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+ r = sshbuf_consume_end(p1, 5);
+ ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+ ASSERT_INT_EQ(sshbuf_consume_end(p1, 3), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+ cdp = sshbuf_ptr(p1);
+ ASSERT_PTR_NE(cdp, NULL);
+ ASSERT_U8_EQ(*cdp, 0x11);
+ r = sshbuf_consume_end(p1, 2);
+ ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+ ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("fill limited buffer");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223);
+ r = sshbuf_reserve(p1, 1223, &dp);
+ ASSERT_INT_EQ(r, 0);
+ ASSERT_PTR_NE(dp, NULL);
+ memset(dp, 0xd7, 1223);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223);
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 0);
+ r = sshbuf_reserve(p1, 1, &dp);
+ ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+ ASSERT_PTR_EQ(dp, NULL);
+ TEST_DONE();
+
+ TEST_START("consume and force compaction");
+ ASSERT_INT_EQ(sshbuf_consume(p1, 223), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000);
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223);
+ r = sshbuf_reserve(p1, 224, &dp);
+ ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+ ASSERT_PTR_EQ(dp, NULL);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000);
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223);
+ r = sshbuf_reserve(p1, 223, &dp);
+ ASSERT_INT_EQ(r, 0);
+ ASSERT_PTR_NE(dp, NULL);
+ memset(dp, 0x7d, 223);
+ cdp = sshbuf_ptr(p1);
+ ASSERT_PTR_NE(cdp, NULL);
+ ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000);
+ ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223);
+ TEST_DONE();
+
+ TEST_START("resize full buffer");
+ r = sshbuf_set_max_size(p1, 1000);
+ ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+ sz = roundup(1223 + SSHBUF_SIZE_INC * 3, SSHBUF_SIZE_INC);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, sz), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - 1223);
+ ASSERT_INT_EQ(sshbuf_len(p1), 1223);
+ TEST_DONE();
+
+ /* NB. uses sshbuf internals */
+ TEST_START("alloc chunking");
+ r = sshbuf_reserve(p1, 1, &dp);
+ ASSERT_INT_EQ(r, 0);
+ ASSERT_PTR_NE(dp, NULL);
+ *dp = 0xff;
+ cdp = sshbuf_ptr(p1);
+ ASSERT_PTR_NE(cdp, NULL);
+ ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000);
+ ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223);
+ ASSERT_MEM_FILLED_EQ(cdp + 1223, 0xff, 1);
+ ASSERT_SIZE_T_EQ(sshbuf_alloc(p1) % SSHBUF_SIZE_INC, 0);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("reset buffer");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
+ r = sshbuf_reserve(p1, 1223, &dp);
+ ASSERT_INT_EQ(r, 0);
+ ASSERT_PTR_NE(dp, NULL);
+ memset(dp, 0xd7, 1223);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223);
+ sshbuf_reset(p1);
+ ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223);
+ sshbuf_free(p1);
+ TEST_DONE();
+}
diff --git a/regress/unittests/sshbuf/test_sshbuf_fixed.c b/regress/unittests/sshbuf/test_sshbuf_fixed.c
new file mode 100644
index 000000000000..df4925f7c6f6
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_fixed.c
@@ -0,0 +1,126 @@
+/* $OpenBSD: test_sshbuf_fixed.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#define SSHBUF_INTERNAL 1 /* access internals for testing */
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "sshbuf.h"
+#include "ssherr.h"
+
+void sshbuf_fixed(void);
+
+const u_char test_buf[] = "\x01\x12\x34\x56\x78\x00\x00\x00\x05hello";
+
+void
+sshbuf_fixed(void)
+{
+ struct sshbuf *p1, *p2, *p3;
+ u_char c;
+ char *s;
+ u_int i;
+ size_t l;
+
+ TEST_START("sshbuf_from");
+ p1 = sshbuf_from(test_buf, sizeof(test_buf));
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_PTR_EQ(sshbuf_mutable_ptr(p1), NULL);
+ ASSERT_INT_EQ(sshbuf_check_reserve(p1, 1), SSH_ERR_BUFFER_READ_ONLY);
+ ASSERT_INT_EQ(sshbuf_reserve(p1, 1, NULL), SSH_ERR_BUFFER_READ_ONLY);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 200), SSH_ERR_BUFFER_READ_ONLY);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), SSH_ERR_BUFFER_READ_ONLY);
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 0);
+ ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_from data");
+ p1 = sshbuf_from(test_buf, sizeof(test_buf) - 1);
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf);
+ ASSERT_INT_EQ(sshbuf_get_u8(p1, &c), 0);
+ ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf + 1);
+ ASSERT_U8_EQ(c, 1);
+ ASSERT_INT_EQ(sshbuf_get_u32(p1, &i), 0);
+ ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf + 5);
+ ASSERT_U32_EQ(i, 0x12345678);
+ ASSERT_INT_EQ(sshbuf_get_cstring(p1, &s, &l), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ ASSERT_STRING_EQ(s, "hello");
+ ASSERT_SIZE_T_EQ(l, 5);
+ sshbuf_free(p1);
+ free(s);
+ TEST_DONE();
+
+ TEST_START("sshbuf_fromb ");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_U_INT_EQ(sshbuf_refcount(p1), 1);
+ ASSERT_PTR_EQ(sshbuf_parent(p1), NULL);
+ ASSERT_INT_EQ(sshbuf_put(p1, test_buf, sizeof(test_buf) - 1), 0);
+ p2 = sshbuf_fromb(p1);
+ ASSERT_PTR_NE(p2, NULL);
+ ASSERT_U_INT_EQ(sshbuf_refcount(p1), 2);
+ ASSERT_PTR_EQ(sshbuf_parent(p1), NULL);
+ ASSERT_PTR_EQ(sshbuf_parent(p2), p1);
+ ASSERT_PTR_EQ(sshbuf_ptr(p2), sshbuf_ptr(p1));
+ ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
+ ASSERT_PTR_NE(sshbuf_ptr(p2), NULL);
+ ASSERT_PTR_EQ(sshbuf_mutable_ptr(p1), NULL);
+ ASSERT_PTR_EQ(sshbuf_mutable_ptr(p2), NULL);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sshbuf_len(p2));
+ ASSERT_INT_EQ(sshbuf_get_u8(p2, &c), 0);
+ ASSERT_PTR_EQ(sshbuf_ptr(p2), sshbuf_ptr(p1) + 1);
+ ASSERT_U8_EQ(c, 1);
+ ASSERT_INT_EQ(sshbuf_get_u32(p2, &i), 0);
+ ASSERT_PTR_EQ(sshbuf_ptr(p2), sshbuf_ptr(p1) + 5);
+ ASSERT_U32_EQ(i, 0x12345678);
+ ASSERT_INT_EQ(sshbuf_get_cstring(p2, &s, &l), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p2), 0);
+ ASSERT_STRING_EQ(s, "hello");
+ ASSERT_SIZE_T_EQ(l, 5);
+ sshbuf_free(p1);
+ ASSERT_U_INT_EQ(sshbuf_refcount(p1), 1);
+ sshbuf_free(p2);
+ free(s);
+ TEST_DONE();
+
+ TEST_START("sshbuf_froms");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x01), 0);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), 0);
+ ASSERT_INT_EQ(sshbuf_put_cstring(p1, "hello"), 0);
+ p2 = sshbuf_new();
+ ASSERT_PTR_NE(p2, NULL);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(test_buf) - 1);
+ ASSERT_INT_EQ(sshbuf_put_stringb(p2, p1), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p2), sizeof(test_buf) + 4 - 1);
+ ASSERT_INT_EQ(sshbuf_froms(p2, &p3), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p2), 0);
+ ASSERT_PTR_NE(p3, NULL);
+ ASSERT_PTR_NE(sshbuf_ptr(p3), NULL);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p3), sizeof(test_buf) - 1);
+ ASSERT_MEM_EQ(sshbuf_ptr(p3), test_buf, sizeof(test_buf) - 1);
+ sshbuf_free(p3);
+ ASSERT_INT_EQ(sshbuf_put_stringb(p2, p1), 0);
+ ASSERT_INT_EQ(sshbuf_consume_end(p2, 1), 0);
+ ASSERT_INT_EQ(sshbuf_froms(p2, &p3), SSH_ERR_MESSAGE_INCOMPLETE);
+ ASSERT_PTR_EQ(p3, NULL);
+ sshbuf_free(p2);
+ sshbuf_free(p1);
+}
diff --git a/regress/unittests/sshbuf/test_sshbuf_fuzz.c b/regress/unittests/sshbuf/test_sshbuf_fuzz.c
new file mode 100644
index 000000000000..c52376b531a3
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_fuzz.c
@@ -0,0 +1,127 @@
+/* $OpenBSD: test_sshbuf_fuzz.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "ssherr.h"
+#include "sshbuf.h"
+
+#define NUM_FUZZ_TESTS (1 << 18)
+
+void sshbuf_fuzz_tests(void);
+
+void
+sshbuf_fuzz_tests(void)
+{
+ struct sshbuf *p1;
+ u_char *dp;
+ size_t sz, sz2, i;
+ u_int32_t r;
+ int ret;
+
+ /* NB. uses sshbuf internals */
+ TEST_START("fuzz alloc/dealloc");
+ p1 = sshbuf_new();
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 16 * 1024), 0);
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
+ ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
+ for (i = 0; i < NUM_FUZZ_TESTS; i++) {
+ r = arc4random_uniform(10);
+ if (r == 0) {
+ /* 10% chance: small reserve */
+ r = arc4random_uniform(10);
+ fuzz_reserve:
+ sz = sshbuf_avail(p1);
+ sz2 = sshbuf_len(p1);
+ ret = sshbuf_reserve(p1, r, &dp);
+ if (ret < 0) {
+ ASSERT_PTR_EQ(dp, NULL);
+ ASSERT_SIZE_T_LT(sz, r);
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
+ } else {
+ ASSERT_PTR_NE(dp, NULL);
+ ASSERT_SIZE_T_GE(sz, r);
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - r);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 + r);
+ memset(dp, arc4random_uniform(255) + 1, r);
+ }
+ } else if (r < 3) {
+ /* 20% chance: big reserve */
+ r = arc4random_uniform(8 * 1024);
+ goto fuzz_reserve;
+ } else if (r == 3) {
+ /* 10% chance: small consume */
+ r = arc4random_uniform(10);
+ fuzz_consume:
+ sz = sshbuf_avail(p1);
+ sz2 = sshbuf_len(p1);
+ /* 50% change consume from end, otherwise start */
+ ret = ((arc4random() & 1) ?
+ sshbuf_consume : sshbuf_consume_end)(p1, r);
+ if (ret < 0) {
+ ASSERT_SIZE_T_LT(sz2, r);
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
+ } else {
+ ASSERT_SIZE_T_GE(sz2, r);
+ ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz + r);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 - r);
+ }
+ } else if (r < 8) {
+ /* 40% chance: big consume */
+ r = arc4random_uniform(2 * 1024);
+ goto fuzz_consume;
+ } else if (r == 8) {
+ /* 10% chance: reset max size */
+ r = arc4random_uniform(16 * 1024);
+ sz = sshbuf_max_size(p1);
+ if (sshbuf_set_max_size(p1, r) < 0)
+ ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
+ else
+ ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), r);
+ } else {
+ if (arc4random_uniform(8192) == 0) {
+ /* tiny chance: new buffer */
+ ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
+ ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
+ sshbuf_free(p1);
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1,
+ 16 * 1024), 0);
+ } else {
+ /* Almost 10%: giant reserve */
+ /* use arc4random_buf for r > 2^32 on 64 bit */
+ arc4random_buf(&r, sizeof(r));
+ while (r < SSHBUF_SIZE_MAX / 2) {
+ r <<= 1;
+ r |= arc4random() & 1;
+ }
+ goto fuzz_reserve;
+ }
+ }
+ ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
+ ASSERT_SIZE_T_LE(sshbuf_max_size(p1), 16 * 1024);
+ }
+ ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
+ ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
+ sshbuf_free(p1);
+ TEST_DONE();
+}
diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_basic.c b/regress/unittests/sshbuf/test_sshbuf_getput_basic.c
new file mode 100644
index 000000000000..966e8432b2d6
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_getput_basic.c
@@ -0,0 +1,484 @@
+/* $OpenBSD: test_sshbuf_getput_basic.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+#include "ssherr.h"
+#include "sshbuf.h"
+
+void sshbuf_getput_basic_tests(void);
+
+void
+sshbuf_getput_basic_tests(void)
+{
+ struct sshbuf *p1, *p2;
+ const u_char *cd;
+ u_char *d, d2[32], x[] = {
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x00, 0x99
+ };
+ u_int64_t v64;
+ u_int32_t v32;
+ u_int16_t v16;
+ u_char v8;
+ size_t s;
+ char *s2;
+ int r;
+ u_char bn1[] = { 0x00, 0x00, 0x00 };
+ u_char bn2[] = { 0x00, 0x00, 0x01, 0x02 };
+ u_char bn3[] = { 0x00, 0x80, 0x09 };
+ u_char bn_exp1[] = { 0x00, 0x00, 0x00, 0x00 };
+ u_char bn_exp2[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 0x02 };
+ u_char bn_exp3[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x80, 0x09 };
+
+ TEST_START("PEEK_U64");
+ ASSERT_U64_EQ(PEEK_U64(x), 0x1122334455667788ULL);
+ TEST_DONE();
+
+ TEST_START("PEEK_U32");
+ ASSERT_U32_EQ(PEEK_U32(x), 0x11223344);
+ TEST_DONE();
+
+ TEST_START("PEEK_U16");
+ ASSERT_U16_EQ(PEEK_U16(x), 0x1122);
+ TEST_DONE();
+
+ TEST_START("POKE_U64");
+ bzero(d2, sizeof(d2));
+ POKE_U64(d2, 0x1122334455667788ULL);
+ ASSERT_MEM_EQ(d2, x, 8);
+ TEST_DONE();
+
+ TEST_START("POKE_U32");
+ bzero(d2, sizeof(d2));
+ POKE_U32(d2, 0x11223344);
+ ASSERT_MEM_EQ(d2, x, 4);
+ TEST_DONE();
+
+ TEST_START("POKE_U16");
+ bzero(d2, sizeof(d2));
+ POKE_U16(d2, 0x1122);
+ ASSERT_MEM_EQ(d2, x, 2);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, 5), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 5);
+ cd = sshbuf_ptr(p1);
+ ASSERT_PTR_NE(cd, NULL);
+ ASSERT_U8_EQ(cd[0], 0x11);
+ ASSERT_U8_EQ(cd[1], 0x22);
+ ASSERT_U8_EQ(cd[2], 0x33);
+ ASSERT_U8_EQ(cd[3], 0x44);
+ ASSERT_U8_EQ(cd[4], 0x55);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get");
+ ASSERT_INT_EQ(sshbuf_get(p1, d2, 4), 0);
+ ASSERT_MEM_EQ(d2, x, 4);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+ ASSERT_U8_EQ(*(sshbuf_ptr(p1)), 0x55);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get truncated");
+ r = sshbuf_get(p1, d2, 4);
+ ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+ ASSERT_U8_EQ(*(sshbuf_ptr(p1)), 0x55);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put truncated");
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 4), 0);
+ r = sshbuf_put(p1, x, 5);
+ ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_u64");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, 10), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 10);
+ ASSERT_INT_EQ(sshbuf_get_u64(p1, &v64), 0);
+ ASSERT_U64_EQ(v64, 0x1122334455667788ULL);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_u64 truncated");
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+ r = sshbuf_get_u64(p1, &v64);
+ ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_u32");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, 10), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 10);
+ ASSERT_INT_EQ(sshbuf_get_u32(p1, &v32), 0);
+ ASSERT_U32_EQ(v32, 0x11223344);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 6);
+ ASSERT_INT_EQ(sshbuf_get_u32(p1, &v32), 0);
+ ASSERT_U32_EQ(v32, 0x55667788);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_u32 truncated");
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+ r = sshbuf_get_u32(p1, &v32);
+ ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_u16");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, 9), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 9);
+ ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
+ ASSERT_U16_EQ(v16, 0x1122);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 7);
+ ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
+ ASSERT_U16_EQ(v16, 0x3344);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 5);
+ ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
+ ASSERT_U16_EQ(v16, 0x5566);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 3);
+ ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
+ ASSERT_U16_EQ(v16, 0x7788);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_u16 truncated");
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+ r = sshbuf_get_u16(p1, &v16);
+ ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_u8");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, 2), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+ ASSERT_INT_EQ(sshbuf_get_u8(p1, &v8), 0);
+ ASSERT_U8_EQ(v8, 0x11);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
+ ASSERT_INT_EQ(sshbuf_get_u8(p1, &v8), 0);
+ ASSERT_U8_EQ(v8, 0x22);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_u8 truncated");
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ r = sshbuf_get_u8(p1, &v8);
+ ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_u64");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put_u64(p1, 0x1122334455667788ULL), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 8);
+ ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 8);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_u64 exact");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 8), 0);
+ ASSERT_INT_EQ(sshbuf_put_u64(p1, 0x1122334455667788ULL), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 8);
+ ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 8);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_u64 limited");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 7), 0);
+ r = sshbuf_put_u64(p1, 0x1122334455667788ULL);
+ ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_u32");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x11223344), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+ ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 4);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_u32 exact");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 4), 0);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x11223344), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+ ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 4);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_u32 limited");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 3), 0);
+ r = sshbuf_put_u32(p1, 0x11223344);
+ ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_u16");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put_u16(p1, 0x1122), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+ ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 2);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_u16");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 2), 0);
+ ASSERT_INT_EQ(sshbuf_put_u16(p1, 0x1122), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
+ ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 2);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_u16 limited");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1), 0);
+ r = sshbuf_put_u16(p1, 0x1122);
+ ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_string");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4 + 4);
+ ASSERT_INT_EQ(sshbuf_get_string(p1, &d, &s), 0);
+ ASSERT_SIZE_T_EQ(s, sizeof(x));
+ ASSERT_MEM_EQ(d, x, sizeof(x));
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
+ free(d);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_string exact");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(x) + 4), 0);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+ ASSERT_INT_EQ(sshbuf_get_string(p1, &d, &s), 0);
+ ASSERT_SIZE_T_EQ(s, sizeof(x));
+ ASSERT_MEM_EQ(d, x, sizeof(x));
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ free(d);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_string truncated");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+ ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 3);
+ r = sshbuf_get_string(p1, &d, &s);
+ ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 3);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_string giant");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, 0xffffffff), 0);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+ r = sshbuf_get_string(p1, &d, &s);
+ ASSERT_INT_EQ(r, SSH_ERR_STRING_TOO_LARGE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_cstring giant");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, 0xffffffff), 0);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+ r = sshbuf_get_cstring(p1, &s2, &s);
+ ASSERT_INT_EQ(r, SSH_ERR_STRING_TOO_LARGE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_cstring embedded \\0");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+ r = sshbuf_get_cstring(p1, &s2, NULL);
+ ASSERT_INT_EQ(r, SSH_ERR_INVALID_FORMAT);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_get_cstring trailing \\0");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x) - 1), 0);
+ ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x) - 1), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4 - 1);
+ ASSERT_INT_EQ(sshbuf_get_cstring(p1, &s2, &s), 0);
+ ASSERT_SIZE_T_EQ(s, sizeof(x) - 1);
+ ASSERT_MEM_EQ(s2, x, s);
+ free(s2);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_string");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_put_string(p1, x, sizeof(x)), 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
+ ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), sizeof(x));
+ ASSERT_MEM_EQ(sshbuf_ptr(p1) + 4, x, sizeof(x));
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_string limited");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(x) + 4 - 1), 0);
+ r = sshbuf_put_string(p1, x, sizeof(x));
+ ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_put_string giant");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ r = sshbuf_put_string(p1, (void *)0x01, 0xfffffffc);
+ ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_putf");
+ p1 = sshbuf_new();
+ ASSERT_PTR_NE(p1, NULL);
+ r = sshbuf_putf(p1, "%s %d %x", "hello", 23, 0x5f);
+ ASSERT_INT_EQ(r, 0);
+ ASSERT_SIZE_T_EQ(sshbuf_len(p1), 11);
+ ASSERT_MEM_EQ(sshbuf_ptr(p1), "hello 23 5f", 11);
+ sshbuf_free(p1);
+ TEST_DONE();
+
+ TEST_START("sshbuf_putb");
+ p1 = sshbuf_new();