summaryrefslogtreecommitdiff
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.c337
-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.c19
-rw-r--r--compat.h4
-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
-rw-r--r--regress/dhgex.sh6
-rw-r--r--regress/forwarding.sh22
-rw-r--r--regress/integrity.sh13
-rw-r--r--regress/kextype.sh7
-rw-r--r--regress/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.c15
-rw-r--r--sshd.026
-rw-r--r--sshd.832
-rw-r--r--sshd.c90
-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, 17319 insertions, 7125 deletions
diff --git a/ChangeLog b/ChangeLog
index 38de846ff..63aeae556 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,934 @@
120131006
2 - (djm) Release OpenSSH-6.7
3
420141003
5 - (djm) [sshd_config.5] typo; from Iain Morgan
6
720141001
8 - (djm) [openbsd-compat/Makefile.in openbsd-compat/kludge-fd_set.c]
9 [openbsd-compat/openbsd-compat.h] Kludge around bad glibc
10 _FORTIFY_SOURCE check that doesn't grok heap-allocated fd_sets;
11 ok dtucker@
12
1320140910
14 - (djm) [sandbox-seccomp-filter.c] Allow mremap and exit for DietLibc;
15 patch from Felix von Leitner; ok dtucker
16
1720140908
18 - (dtucker) [INSTALL] Update info about egd. ok djm@
19
2020140904
21 - (djm) [openbsd-compat/arc4random.c] Zero seed after keying PRNG
22
2320140903
24 - (djm) [defines.h sshbuf.c] Move __predict_true|false to defines.h and
25 conditionalise to avoid duplicate definition.
26 - (djm) [contrib/cygwin/ssh-host-config] Fix old code leading to
27 permissions/ACLs; from Corinna Vinschen
28
2920140830
30 - (djm) [openbsd-compat/openssl-compat.h] add
31 OPENSSL_[RD]SA_MAX_MODULUS_BITS defines for OpenSSL that lacks them
32 - (djm) [misc.c] Missing newline between functions
33 - (djm) [openbsd-compat/openssl-compat.h] add include guard
34 - (djm) [Makefile.in] Make TEST_SHELL a variable; "good idea" tim@
35
3620140827
37 - (djm) [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c]
38 [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c]
39 [regress/unittests/sshkey/common.c]
40 [regress/unittests/sshkey/test_file.c]
41 [regress/unittests/sshkey/test_fuzz.c]
42 [regress/unittests/sshkey/test_sshkey.c] Don't include openssl/ec.h
43 on !ECC OpenSSL systems
44 - (djm) [monitor.c sshd.c] SIGXFSZ needs to be ignored in postauth
45 monitor, not preauth; bz#2263
46 - (djm) [openbsd-compat/explicit_bzero.c] implement explicit_bzero()
47 using memset_s() where possible; improve fallback to indirect bzero
48 via a volatile pointer to give it more of a chance to avoid being
49 optimised away.
50
5120140825
52 - (djm) [bufec.c] Skip this file on !ECC OpenSSL
53 - (djm) [INSTALL] Recommend libcrypto be built -fPIC, mention LibreSSL,
54 update OpenSSL version requirement.
55
5620140824
57 - (djm) [sftp-server.c] Some systems (e.g. Irix) have prctl() but not
58 PR_SET_DUMPABLE, so adjust ifdef; reported by Tom Christensen
59
6020140823
61 - (djm) [sshd.c] Ignore SIGXFSZ in preauth monitor child; can explode on
62 lastlog writing on platforms with high UIDs; bz#2263
63 - (djm) [configure.ac] We now require a working vsnprintf everywhere (not
64 just for systems that lack asprintf); check for it always and extend
65 test to catch more brokenness. Fixes builds on Solaris <= 9
66
6720140822
68 - (djm) [configure.ac] include leading zero characters in OpenSSL version
69 number; fixes test for unsupported versions
70 - (djm) [sshbuf-getput-crypto.c] Fix compilation when OpenSSL lacks ECC
71 - (djm) [openbsd-compat/bsd-snprintf.c] Fix compilation failure (prototype/
72 definition mismatch) and warning for broken/missing snprintf case.
73 - (djm) [configure.ac] double braces to appease autoconf
74
7520140821
76 - (djm) [Makefile.in] fix reference to libtest_helper.a in sshkey test too.
77 - (djm) [key.h] Fix ifdefs for no-ECC OpenSSL
78 - (djm) [regress/unittests/test_helper/test_helper.c] Fix for systems that
79 don't set __progname. Diagnosed by Tom Christensen.
80
8120140820
82 - (djm) [configure.ac] Check OpenSSL version is supported at configure time;
83 suggested by Kevin Brott
84 - (djm) [Makefile.in] refer to libtest_helper.a by explicit path rather than
85 -L/-l; fixes linking problems on some platforms
86 - (djm) [sshkey.h] Fix compilation when OpenSSL lacks ECC
87 - (djm) [contrib/cygwin/README] Correct build instructions; from Corinna
88
8920140819
90 - (djm) [serverloop.c] Fix syntax error on Cygwin; from Corinna Vinschen
91 - (djm) [sshbuf.h] Fix compilation on systems without OPENSSL_HAS_ECC.
92 - (djm) [ssh-dss.c] Include openssl/dsa.h for DSA_SIG
93 - (djm) [INSTALL contrib/caldera/openssh.spec contrib/cygwin/README]
94 [contrib/redhat/openssh.spec contrib/suse/openssh.spec] Remove mentions
95 of TCP wrappers.
96
9720140811
98 - (djm) [myproposal.h] Make curve25519 KEX dependent on
99 HAVE_EVP_SHA256 instead of OPENSSL_HAS_ECC.
100
10120140810
102 - (djm) [README contrib/caldera/openssh.spec]
103 [contrib/redhat/openssh.spec contrib/suse/openssh.spec] Update versions
104
10520140801
106 - (djm) [regress/multiplex.sh] Skip test for non-OpenBSD netcat. We need
107 a better solution, but this will have to do for now.
108 - (djm) [regress/multiplex.sh] Instruct nc not to quit as soon as stdin
109 is closed; avoid regress failures when stdin is /dev/null
110 - (djm) [regress/multiplex.sh] Use -d (detach stdin) flag to disassociate
111 nc from stdin, it's more portable
112
11320140730
114 - OpenBSD CVS Sync
115 - millert@cvs.openbsd.org 2014/07/24 22:57:10
116 [ssh.1]
117 Mention UNIX-domain socket forwarding too. OK jmc@ deraadt@
118 - dtucker@cvs.openbsd.org 2014/07/25 21:22:03
119 [ssh-agent.c]
120 Clear buffer used for handling messages. This prevents keys being
121 left in memory after they have been expired or deleted in some cases
122 (but note that ssh-agent is setgid so you would still need root to
123 access them). Pointed out by Kevin Burns, ok deraadt
124 - schwarze@cvs.openbsd.org 2014/07/28 15:40:08
125 [sftp-server.8 sshd_config.5]
126 some systems no longer need /dev/log;
127 issue noticed by jirib;
128 ok deraadt
129
13020140725
131 - (djm) [regress/multiplex.sh] restore incorrectly deleted line;
132 pointed out by Christian Hesse
133
13420140722
135 - (djm) [regress/multiplex.sh] ssh mux master lost -N somehow;
136 put it back
137 - (djm) [regress/multiplex.sh] change the test for still-open Unix
138 domain sockets to be robust against nc implementations that produce
139 error messages.
140 - (dtucker) [regress/unittests/sshkey/test_{file,fuzz,sshkey}.c] Wrap ecdsa-
141 specific tests inside OPENSSL_HAS_ECC.
142 - (dtucker) OpenBSD CVS Sync
143 - dtucker@cvs.openbsd.org 2014/07/22 01:18:50
144 [key.c]
145 Prevent spam from key_load_private_pem during hostbased auth. ok djm@
146 - guenther@cvs.openbsd.org 2014/07/22 07:13:42
147 [umac.c]
148 Convert from <sys/endian.h> to the shiney new <endian.h>
149 ok dtucker@, who also confirmed that -portable handles this already
150 (ID sync only, includes.h pulls in endian.h if available.)
151 - djm@cvs.openbsd.org 2014/07/22 01:32:12
152 [regress/multiplex.sh]
153 change the test for still-open Unix domain sockets to be robust against
154 nc implementations that produce error messages. from -portable
155 (Id sync only)
156 - dtucker@cvs.openbsd.org 2014/07/22 23:23:22
157 [regress/unittests/sshkey/mktestdata.sh]
158 Sign test certs with ed25519 instead of ecdsa so that they'll work in
159 -portable on platforms that don't have ECDSA in their OpenSSL. ok djm
160 - dtucker@cvs.openbsd.org 2014/07/22 23:57:40
161 [regress/unittests/sshkey/mktestdata.sh]
162 Add $OpenBSD tag to make syncs easier
163 - dtucker@cvs.openbsd.org 2014/07/22 23:35:38
164 [regress/unittests/sshkey/testdata/*]
165 Regenerate test keys with certs signed with ed25519 instead of ecdsa.
166 These can be used in -portable on platforms that don't support ECDSA.
167
16820140721
169 - OpenBSD CVS Sync
170 - millert@cvs.openbsd.org 2014/07/15 15:54:15
171 [forwarding.sh multiplex.sh]
172 Add support for Unix domain socket forwarding. A remote TCP port
173 may be forwarded to a local Unix domain socket and vice versa or
174 both ends may be a Unix domain socket. This is a reimplementation
175 of the streamlocal patches by William Ahern from:
176 http://www.25thandclement.com/~william/projects/streamlocal.html
177 OK djm@ markus@
178 - (djm) [regress/multiplex.sh] Not all netcat accept the -N option.
179 - (dtucker) [sshkey.c] ifdef out unused variable when compiling without
180 OPENSSL_HAS_ECC.
181
18220140721
183 - (dtucker) [cipher.c openbsd-compat/openssl-compat.h] Restore the bits
184 needed to build AES CTR mode against OpenSSL 0.9.8f and above. ok djm
185 - (dtucker) [regress/unittests/sshkey/
186 {common,test_file,test_fuzz,test_sshkey}.c] Wrap stdint.h includes in
187 ifdefs.
188
18920140719
190 - (tim) [openbsd-compat/port-uw.c] Include misc.h for fwd_opts, used
191 in servconf.h.
192
19320140718
194 - OpenBSD CVS Sync
195 - millert@cvs.openbsd.org 2014/07/15 15:54:14
196 [PROTOCOL auth-options.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c]
197 [auth-rsa.c auth.c auth1.c auth2-hostbased.c auth2-kbdint.c auth2-none.c]
198 [auth2-passwd.c auth2-pubkey.c auth2.c canohost.c channels.c channels.h]
199 [clientloop.c misc.c misc.h monitor.c mux.c packet.c readconf.c]
200 [readconf.h servconf.c servconf.h serverloop.c session.c ssh-agent.c]
201 [ssh.c ssh_config.5 sshconnect.c sshconnect1.c sshconnect2.c sshd.c]
202 [sshd_config.5 sshlogin.c]
203 Add support for Unix domain socket forwarding. A remote TCP port
204 may be forwarded to a local Unix domain socket and vice versa or
205 both ends may be a Unix domain socket. This is a reimplementation
206 of the streamlocal patches by William Ahern from:
207 http://www.25thandclement.com/~william/projects/streamlocal.html
208 OK djm@ markus@
209 - jmc@cvs.openbsd.org 2014/07/16 14:48:57
210 [ssh.1]
211 add the streamlocal* options to ssh's -o list; millert says they're
212 irrelevant for scp/sftp;
213 ok markus millert
214 - djm@cvs.openbsd.org 2014/07/17 00:10:56
215 [sandbox-systrace.c]
216 ifdef SYS_sendsyslog so this will compile without patching on -stable
217 - djm@cvs.openbsd.org 2014/07/17 00:10:18
218 [mux.c]
219 preserve errno across syscall
220 - djm@cvs.openbsd.org 2014/07/17 00:12:03
221 [key.c]
222 silence "incorrect passphrase" error spam; reported and ok dtucker@
223 - djm@cvs.openbsd.org 2014/07/17 07:22:19
224 [mux.c ssh.c]
225 reflect stdio-forward ("ssh -W host:port ...") failures in exit status.
226 previously we were always returning 0. bz#2255 reported by Brendan
227 Germain; ok dtucker
228 - djm@cvs.openbsd.org 2014/07/18 02:46:01
229 [ssh-agent.c]
230 restore umask around listener socket creation (dropped in streamlocal patch
231 merge)
232 - (dtucker) [auth2-gss.c gss-serv-krb5.c] Include misc.h for fwd_opts, used
233 in servconf.h.
234 - (dtucker) [Makefile.in] Add a t-exec target to run just the executable
235 tests.
236 - (dtucker) [key.c sshkey.c] Put new ecdsa bits inside ifdef OPENSSL_HAS_ECC.
237
23820140717
239 - (djm) [digest-openssl.c] Preserve array order when disabling digests.
240 Reported by Petr Lautrbach.
241 - OpenBSD CVS Sync
242 - deraadt@cvs.openbsd.org 2014/07/11 08:09:54
243 [sandbox-systrace.c]
244 Permit use of SYS_sendsyslog from inside the sandbox. Clock is ticking,
245 update your kernels and sshd soon.. libc will start using sendsyslog()
246 in about 4 days.
247 - tedu@cvs.openbsd.org 2014/07/11 13:54:34
248 [myproposal.h]
249 by popular demand, add back hamc-sha1 to server proposal for better compat
250 with many clients still in use. ok deraadt
251
25220140715
253 - (djm) [configure.ac] Delay checks for arc4random* until after libcrypto
254 has been located; fixes builds agains libressl-portable
255
25620140711
257 - OpenBSD CVS Sync
258 - benno@cvs.openbsd.org 2014/07/09 14:15:56
259 [ssh-add.c]
260 fix ssh-add crash while loading more than one key
261 ok markus@
262
26320140709
264 - OpenBSD CVS Sync
265 - djm@cvs.openbsd.org 2014/07/07 08:19:12
266 [ssh_config.5]
267 mention that ProxyCommand is executed using shell "exec" to avoid
268 a lingering process; bz#1977
269 - djm@cvs.openbsd.org 2014/07/09 01:45:10
270 [sftp.c]
271 more useful error message when GLOB_NOSPACE occurs;
272 bz#2254, patch from Orion Poplawski
273 - djm@cvs.openbsd.org 2014/07/09 03:02:15
274 [key.c]
275 downgrade more error() to debug() to better match what old authfile.c
276 did; suppresses spurious errors with hostbased authentication enabled
277 - djm@cvs.openbsd.org 2014/07/06 07:42:03
278 [multiplex.sh test-exec.sh]
279 add a hook to the cleanup() function to kill $SSH_PID if it is set
280
281 use it to kill the mux master started in multiplex.sh (it was being left
282 around on fatal failures)
283 - djm@cvs.openbsd.org 2014/07/07 08:15:26
284 [multiplex.sh]
285 remove forced-fatal that I stuck in there to test the new cleanup
286 logic and forgot to remove...
287
28820140706
289 - OpenBSD CVS Sync
290 - djm@cvs.openbsd.org 2014/07/03 23:18:35
291 [authfile.h]
292 remove leakmalloc droppings
293 - djm@cvs.openbsd.org 2014/07/05 23:11:48
294 [channels.c]
295 fix remote-forward cancel regression; ok markus@
296
29720140704
298 - OpenBSD CVS Sync
299 - jsing@cvs.openbsd.org 2014/07/03 12:42:16
300 [cipher-chachapoly.c]
301 Call chacha_ivsetup() immediately before chacha_encrypt_bytes() - this
302 makes it easier to verify that chacha_encrypt_bytes() is only called once
303 per chacha_ivsetup() call.
304 ok djm@
305 - djm@cvs.openbsd.org 2014/07/03 22:23:46
306 [sshconnect.c]
307 when rekeying, skip file/DNS lookup if it is the same as the key sent
308 during initial key exchange. bz#2154 patch from Iain Morgan; ok markus@
309 - djm@cvs.openbsd.org 2014/07/03 22:33:41
310 [channels.c]
311 allow explicit ::1 and 127.0.0.1 forwarding bind addresses when
312 GatewayPorts=no; allows client to choose address family;
313 bz#2222 ok markus@
314 - djm@cvs.openbsd.org 2014/07/03 22:40:43
315 [servconf.c servconf.h session.c sshd.8 sshd_config.5]
316 Add a sshd_config PermitUserRC option to control whether ~/.ssh/rc is
317 executed, mirroring the no-user-rc authorized_keys option;
318 bz#2160; ok markus@
319
32020140703
321 - (djm) [digest-openssl.c configure.ac] Disable RIPEMD160 if libcrypto
322 doesn't support it.
323 - (djm) [monitor_fdpass.c] Use sys/poll.h if poll.h doesn't exist;
324 bz#2237
325 - OpenBSD CVS Sync
326 - djm@cvs.openbsd.org 2014/07/03 01:45:38
327 [sshkey.c]
328 make Ed25519 keys' title fit properly in the randomart border; bz#2247
329 based on patch from Christian Hesse
330 - djm@cvs.openbsd.org 2014/07/03 03:11:03
331 [ssh-agent.c]
332 Only cleanup agent socket in the main agent process and not in any
333 subprocesses it may have started (e.g. forked askpass). Fixes
334 agent sockets being zapped when askpass processes fatal();
335 bz#2236 patch from Dmitry V. Levin
336 - djm@cvs.openbsd.org 2014/07/03 03:15:01
337 [ssh-add.c]
338 make stdout line-buffered; saves partial output getting lost when
339 ssh-add fatal()s part-way through (e.g. when listing keys from an
340 agent that supports key types that ssh-add doesn't);
341 bz#2234, reported by Phil Pennock
342 - djm@cvs.openbsd.org 2014/07/03 03:26:43
343 [digest-openssl.c]
344 use EVP_Digest() for one-shot hash instead of creating, updating,
345 finalising and destroying a context.
346 bz#2231, based on patch from Timo Teras
347 - djm@cvs.openbsd.org 2014/07/03 03:34:09
348 [gss-serv.c session.c ssh-keygen.c]
349 standardise on NI_MAXHOST for gethostname() string lengths; about
350 1/2 the cases were using it already. Fixes bz#2239 en passant
351 - djm@cvs.openbsd.org 2014/07/03 03:47:27
352 [ssh-keygen.c]
353 When hashing or removing hosts using ssh-keygen, don't choke on
354 @revoked markers and don't remove @cert-authority markers;
355 bz#2241, reported by mlindgren AT runelind.net
356 - djm@cvs.openbsd.org 2014/07/03 04:36:45
357 [digest.h]
358 forward-declare struct sshbuf so consumers don't need to include sshbuf.h
359 - djm@cvs.openbsd.org 2014/07/03 05:32:36
360 [ssh_config.5]
361 mention '%%' escape sequence in HostName directives and how it may
362 be used to specify IPv6 link-local addresses
363 - djm@cvs.openbsd.org 2014/07/03 05:38:17
364 [ssh.1]
365 document that -g will only work in the multiplexed case if applied to
366 the mux master
367 - djm@cvs.openbsd.org 2014/07/03 06:39:19
368 [ssh.c ssh_config.5]
369 Add a %C escape sequence for LocalCommand and ControlPath that expands
370 to a unique identifer based on a has of the tuple of (local host,
371 remote user, hostname, port).
372
373 Helps avoid exceeding sockaddr_un's miserly pathname limits for mux
374 control paths.
375
376 bz#2220, based on patch from mancha1 AT zoho.com; ok markus@
377 - jmc@cvs.openbsd.org 2014/07/03 07:45:27
378 [ssh_config.5]
379 escape %C since groff thinks it part of an Rs/Re block;
380 - djm@cvs.openbsd.org 2014/07/03 11:16:55
381 [auth.c auth.h auth1.c auth2.c]
382 make the "Too many authentication failures" message include the
383 user, source address, port and protocol in a format similar to the
384 authentication success / failure messages; bz#2199, ok dtucker
385
38620140702
387 - OpenBSD CVS Sync
388 - deraadt@cvs.openbsd.org 2014/06/13 08:26:29
389 [sandbox-systrace.c]
390 permit SYS_getentropy
391 from matthew
392 - matthew@cvs.openbsd.org 2014/06/18 02:59:13
393 [sandbox-systrace.c]
394 Now that we have a dedicated getentropy(2) system call for
395 arc4random(3), we can disallow __sysctl(2) in OpenSSH's systrace
396 sandbox.
397
398 ok djm
399 - naddy@cvs.openbsd.org 2014/06/18 15:42:09
400 [sshbuf-getput-crypto.c]
401 The ssh_get_bignum functions must accept the same range of bignums
402 the corresponding ssh_put_bignum functions create. This fixes the
403 use of 16384-bit RSA keys (bug reported by Eivind Evensen).
404 ok djm@
405 - djm@cvs.openbsd.org 2014/06/24 00:52:02
406 [krl.c]
407 fix bug in KRL generation: multiple consecutive revoked certificate
408 serial number ranges could be serialised to an invalid format.
409
410 Readers of a broken KRL caused by this bug will fail closed, so no
411 should-have-been-revoked key will be accepted.
412 - djm@cvs.openbsd.org 2014/06/24 01:13:21
413 [Makefile.in auth-bsdauth.c auth-chall.c auth-options.c auth-rsa.c
414 [auth2-none.c auth2-pubkey.c authfile.c authfile.h cipher-3des1.c
415 [cipher-chachapoly.c cipher-chachapoly.h cipher.c cipher.h
416 [digest-libc.c digest-openssl.c digest.h dns.c entropy.c hmac.h
417 [hostfile.c key.c key.h krl.c monitor.c packet.c rsa.c rsa.h
418 [ssh-add.c ssh-agent.c ssh-dss.c ssh-ecdsa.c ssh-ed25519.c
419 [ssh-keygen.c ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c
420 [ssh-rsa.c sshbuf-misc.c sshbuf.h sshconnect.c sshconnect1.c
421 [sshconnect2.c sshd.c sshkey.c sshkey.h
422 [openbsd-compat/openssl-compat.c openbsd-compat/openssl-compat.h]
423 New key API: refactor key-related functions to be more library-like,
424 existing API is offered as a set of wrappers.
425
426 with and ok markus@
427
428 Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew
429 Dempsky and Ron Bowes for a detailed review a few months ago.
430 NB. This commit also removes portable OpenSSH support for OpenSSL
431 <0.9.8e.
432 - djm@cvs.openbsd.org 2014/06/24 02:19:48
433 [ssh.c]
434 don't fatal() when hostname canonicalisation fails with a
435 ProxyCommand in use; continue and allow the ProxyCommand to
436 connect anyway (e.g. to a host with a name outside the DNS
437 behind a bastion)
438 - djm@cvs.openbsd.org 2014/06/24 02:21:01
439 [scp.c]
440 when copying local->remote fails during read, don't send uninitialised
441 heap to the remote end. Reported by Jann Horn
442 - deraadt@cvs.openbsd.org 2014/06/25 14:16:09
443 [sshbuf.c]
444 unblock SIGSEGV before raising it
445 ok djm
446 - markus@cvs.openbsd.org 2014/06/27 16:41:56
447 [channels.c channels.h clientloop.c ssh.c]
448 fix remote fwding with same listen port but different listen address
449 with gerhard@, ok djm@
450 - markus@cvs.openbsd.org 2014/06/27 18:50:39
451 [ssh-add.c]
452 fix loading of private keys
453 - djm@cvs.openbsd.org 2014/06/30 12:54:39
454 [key.c]
455 suppress spurious error message when loading key with a passphrase;
456 reported by kettenis@ ok markus@
457 - djm@cvs.openbsd.org 2014/07/02 04:59:06
458 [cipher-3des1.c]
459 fix ssh protocol 1 on the server that regressed with the sshkey change
460 (sometimes fatal() after auth completed), make file return useful status
461 codes.
462 NB. Id sync only for these two. They were bundled into the sshkey merge
463 above, since it was easier to sync the entire file and then apply
464 portable-specific changed atop it.
465 - djm@cvs.openbsd.org 2014/04/30 05:32:00
466 [regress/Makefile]
467 unit tests for new buffer API; including basic fuzz testing
468 NB. Id sync only.
469 - djm@cvs.openbsd.org 2014/05/21 07:04:21
470 [regress/integrity.sh]
471 when failing because of unexpected output, show the offending output
472 - djm@cvs.openbsd.org 2014/06/24 01:04:43
473 [regress/krl.sh]
474 regress test for broken consecutive revoked serial number ranges
475 - djm@cvs.openbsd.org 2014/06/24 01:14:17
476 [Makefile.in regress/Makefile regress/unittests/Makefile]
477 [regress/unittests/sshkey/Makefile]
478 [regress/unittests/sshkey/common.c]
479 [regress/unittests/sshkey/common.h]
480 [regress/unittests/sshkey/mktestdata.sh]
481 [regress/unittests/sshkey/test_file.c]
482 [regress/unittests/sshkey/test_fuzz.c]
483 [regress/unittests/sshkey/test_sshkey.c]
484 [regress/unittests/sshkey/tests.c]
485 [regress/unittests/sshkey/testdata/dsa_1]
486 [regress/unittests/sshkey/testdata/dsa_1-cert.fp]
487 [regress/unittests/sshkey/testdata/dsa_1-cert.pub]
488 [regress/unittests/sshkey/testdata/dsa_1.fp]
489 [regress/unittests/sshkey/testdata/dsa_1.fp.bb]
490 [regress/unittests/sshkey/testdata/dsa_1.param.g]
491 [regress/unittests/sshkey/testdata/dsa_1.param.priv]
492 [regress/unittests/sshkey/testdata/dsa_1.param.pub]
493 [regress/unittests/sshkey/testdata/dsa_1.pub]
494 [regress/unittests/sshkey/testdata/dsa_1_pw]
495 [regress/unittests/sshkey/testdata/dsa_2]
496 [regress/unittests/sshkey/testdata/dsa_2.fp]
497 [regress/unittests/sshkey/testdata/dsa_2.fp.bb]
498 [regress/unittests/sshkey/testdata/dsa_2.pub]
499 [regress/unittests/sshkey/testdata/dsa_n]
500 [regress/unittests/sshkey/testdata/dsa_n_pw]
501 [regress/unittests/sshkey/testdata/ecdsa_1]
502 [regress/unittests/sshkey/testdata/ecdsa_1-cert.fp]
503 [regress/unittests/sshkey/testdata/ecdsa_1-cert.pub]
504 [regress/unittests/sshkey/testdata/ecdsa_1.fp]
505 [regress/unittests/sshkey/testdata/ecdsa_1.fp.bb]
506 [regress/unittests/sshkey/testdata/ecdsa_1.param.curve]
507 [regress/unittests/sshkey/testdata/ecdsa_1.param.priv]
508 [regress/unittests/sshkey/testdata/ecdsa_1.param.pub]
509 [regress/unittests/sshkey/testdata/ecdsa_1.pub]
510 [regress/unittests/sshkey/testdata/ecdsa_1_pw]
511 [regress/unittests/sshkey/testdata/ecdsa_2]
512 [regress/unittests/sshkey/testdata/ecdsa_2.fp]
513 [regress/unittests/sshkey/testdata/ecdsa_2.fp.bb]
514 [regress/unittests/sshkey/testdata/ecdsa_2.param.curve]
515 [regress/unittests/sshkey/testdata/ecdsa_2.param.priv]
516 [regress/unittests/sshkey/testdata/ecdsa_2.param.pub]
517 [regress/unittests/sshkey/testdata/ecdsa_2.pub]
518 [regress/unittests/sshkey/testdata/ecdsa_n]
519 [regress/unittests/sshkey/testdata/ecdsa_n_pw]
520 [regress/unittests/sshkey/testdata/ed25519_1]
521 [regress/unittests/sshkey/testdata/ed25519_1-cert.fp]
522 [regress/unittests/sshkey/testdata/ed25519_1-cert.pub]
523 [regress/unittests/sshkey/testdata/ed25519_1.fp]
524 [regress/unittests/sshkey/testdata/ed25519_1.fp.bb]
525 [regress/unittests/sshkey/testdata/ed25519_1.pub]
526 [regress/unittests/sshkey/testdata/ed25519_1_pw]
527 [regress/unittests/sshkey/testdata/ed25519_2]
528 [regress/unittests/sshkey/testdata/ed25519_2.fp]
529 [regress/unittests/sshkey/testdata/ed25519_2.fp.bb]
530 [regress/unittests/sshkey/testdata/ed25519_2.pub]
531 [regress/unittests/sshkey/testdata/pw]
532 [regress/unittests/sshkey/testdata/rsa1_1]
533 [regress/unittests/sshkey/testdata/rsa1_1.fp]
534 [regress/unittests/sshkey/testdata/rsa1_1.fp.bb]
535 [regress/unittests/sshkey/testdata/rsa1_1.param.n]
536 [regress/unittests/sshkey/testdata/rsa1_1.pub]
537 [regress/unittests/sshkey/testdata/rsa1_1_pw]
538 [regress/unittests/sshkey/testdata/rsa1_2]
539 [regress/unittests/sshkey/testdata/rsa1_2.fp]
540 [regress/unittests/sshkey/testdata/rsa1_2.fp.bb]
541 [regress/unittests/sshkey/testdata/rsa1_2.param.n]
542 [regress/unittests/sshkey/testdata/rsa1_2.pub]
543 [regress/unittests/sshkey/testdata/rsa_1]
544 [regress/unittests/sshkey/testdata/rsa_1-cert.fp]
545 [regress/unittests/sshkey/testdata/rsa_1-cert.pub]
546 [regress/unittests/sshkey/testdata/rsa_1.fp]
547 [regress/unittests/sshkey/testdata/rsa_1.fp.bb]
548 [regress/unittests/sshkey/testdata/rsa_1.param.n]
549 [regress/unittests/sshkey/testdata/rsa_1.param.p]
550 [regress/unittests/sshkey/testdata/rsa_1.param.q]
551 [regress/unittests/sshkey/testdata/rsa_1.pub]
552 [regress/unittests/sshkey/testdata/rsa_1_pw]
553 [regress/unittests/sshkey/testdata/rsa_2]
554 [regress/unittests/sshkey/testdata/rsa_2.fp]
555 [regress/unittests/sshkey/testdata/rsa_2.fp.bb]
556 [regress/unittests/sshkey/testdata/rsa_2.param.n]
557 [regress/unittests/sshkey/testdata/rsa_2.param.p]
558 [regress/unittests/sshkey/testdata/rsa_2.param.q]
559 [regress/unittests/sshkey/testdata/rsa_2.pub]
560 [regress/unittests/sshkey/testdata/rsa_n]
561 [regress/unittests/sshkey/testdata/rsa_n_pw]
562 unit and fuzz tests for new key API
563 - (djm) [sshkey.c] Conditionalise inclusion of util.h
564 - (djm) [regress/Makefile] fix execution of sshkey unit/fuzz test
565
56620140618
567 - (tim) [openssh/session.c] Work around to get chroot sftp working on UnixWare
568
56920140617
570 - (dtucker) [entropy.c openbsd-compat/openssl-compat.{c,h}
571 openbsd-compat/regress/{.cvsignore,Makefile.in,opensslvertest.c}]
572 Move the OpenSSL header/library version test into its own function and add
573 tests for it. Fix it to allow fix version upgrades (but not downgrades).
574 Prompted by chl@ via OpenSMTPD (issue #462) and Debian (bug #748150).
575 ok djm@ chl@
576
57720140616
578 - (dtucker) [defines.h] Fix undef of _PATH_MAILDIR. From rak at debian via
579 OpenSMTPD and chl@
580
58120140612
582 - (dtucker) [configure.ac] Remove tcpwrappers support, support has already
583 been removed from sshd.c.
584
58520140611
586 - (dtucker) [defines.h] Add va_copy if we don't already have it, taken from
587 openbsd-compat/bsd-asprintf.c.
588 - (dtucker) [regress/unittests/sshbuf/*.c regress/unittests/test_helper/*]
589 Wrap stdlib.h include an ifdef for platforms that don't have it.
590 - (tim) [regress/unittests/test_helper/test_helper.h] Add includes.h for
591 u_intXX_t types.
592
59320140610
594 - (dtucker) [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c
595 regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c] Only do NISTP256
596 curve tests if OpenSSL has them.
597 - (dtucker) [myprosal.h] Don't include curve25519-sha256@libssh.org in
598 the proposal if the version of OpenSSL we're using doesn't support ECC.
599 - (dtucker) [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c] ifdef
600 ECC variable too.
601 - (dtucker) OpenBSD CVS Sync
602 - djm@cvs.openbsd.org 2014/06/05 22:17:50
603 [sshconnect2.c]
604 fix inverted test that caused PKCS#11 keys that were explicitly listed
605 not to be preferred. Reported by Dirk-Willem van Gulik
606 - dtucker@cvs.openbsd.org 2014/06/10 21:46:11
607 [sshbuf.h]
608 Group ECC functions together to make things a little easier in -portable.
609 "doesn't bother me" deraadt@
610 - (dtucker) [sshbuf.h] Only declare ECC functions if building without
611 OpenSSL or if OpenSSL has ECC.
612 - (dtucker) [openbsd-compat/arc4random.c] Use explicit_bzero instead of an
613 assigment that might get optimized out. ok djm@
614 - (dtucker) [bufaux.c bufbn.c bufec.c buffer.c] Pull in includes.h for
615 compat stuff, specifically whether or not OpenSSL has ECC.
616
61720140527
618 - (djm) [cipher.c] Fix merge botch.
619 - (djm) [contrib/cygwin/ssh-host-config] Updated Cygwin ssh-host-config
620 from Corinna Vinschen, fixing a number of bugs and preparing for
621 Cygwin 1.7.30.
622 - (djm) [configure.ac openbsd-compat/bsd-cygwin_util.c]
623 [openbsd-compat/bsd-cygwin_util.h] On Cygwin, determine privilege
624 separation user at runtime, since it may need to be a domain account.
625 Patch from Corinna Vinschen.
626
62720140522
628 - (djm) [Makefile.in] typo in path
629
63020140521
631 - (djm) [commit configure.ac defines.h sshpty.c] don't attempt to use
632 vhangup on Linux. It doens't work for non-root users, and for them
633 it just messes up the tty settings.
634 - (djm) [misc.c] Use CLOCK_BOOTTIME in preference to CLOCK_MONOTONIC
635 when it is available. It takes into account time spent suspended,
636 thereby ensuring timeouts (e.g. for expiring agent keys) fire
637 correctly. bz#2228 reported by John Haxby
638
63920140519
640 - (djm) [rijndael.c rijndael.h] Sync with newly-ressurected versions ine
641 OpenBSD
642 - OpenBSD CVS Sync
643 - logan@cvs.openbsd.org 2014/04/20 09:24:26
644 [dns.c dns.h ssh-keygen.c]
645 Add support for SSHFP DNS records for ED25519 key types.
646 OK from djm@
647 - logan@cvs.openbsd.org 2014/04/21 14:36:16
648 [sftp-client.c sftp-client.h sftp.c]
649 Implement sftp upload resume support.
650 OK from djm@, with input from guenther@, mlarkin@ and
651 okan@
652 - logan@cvs.openbsd.org 2014/04/22 10:07:12
653 [sftp.c]
654 Sort the sftp command list.
655 OK from djm@
656 - logan@cvs.openbsd.org 2014/04/22 12:42:04
657 [sftp.1]
658 Document sftp upload resume.
659 OK from djm@, with feedback from okan@.
660 - jmc@cvs.openbsd.org 2014/04/22 14:16:30
661 [sftp.1]
662 zap eol whitespace;
663 - djm@cvs.openbsd.org 2014/04/23 12:42:34
664 [readconf.c]
665 don't record duplicate IdentityFiles
666 - djm@cvs.openbsd.org 2014/04/28 03:09:18
667 [authfile.c bufaux.c buffer.h channels.c krl.c mux.c packet.c packet.h]
668 [ssh-keygen.c]
669 buffer_get_string_ptr's return should be const to remind
670 callers that futzing with it will futz with the actual buffer
671 contents
672 - djm@cvs.openbsd.org 2014/04/29 13:10:30
673 [clientloop.c serverloop.c]
674 bz#1818 - don't send channel success/failre replies on channels that
675 have sent a close already; analysis and patch from Simon Tatham;
676 ok markus@
677 - markus@cvs.openbsd.org 2014/04/29 18:01:49
678 [auth.c authfd.c authfile.c bufaux.c cipher.c cipher.h hostfile.c]
679 [kex.c key.c mac.c monitor.c monitor_wrap.c myproposal.h packet.c]
680 [roaming_client.c ssh-agent.c ssh-keygen.c ssh-keyscan.c ssh-keysign.c]
681 [ssh-pkcs11.h ssh.c sshconnect.c sshconnect2.c sshd.c]
682 make compiling against OpenSSL optional (make OPENSSL=no);
683 reduces algorithms to curve25519, aes-ctr, chacha, ed25519;
684 allows us to explore further options; with and ok djm
685 - dtucker@cvs.openbsd.org 2014/04/29 19:58:50
686 [sftp.c]
687 Move nulling of variable next to where it's freed. ok markus@
688 - dtucker@cvs.openbsd.org 2014/04/29 20:36:51
689 [sftp.c]
690 Don't attempt to append a nul quote char to the filename. Should prevent
691 fatal'ing with "el_insertstr failed" when there's a single quote char
692 somewhere in the string. bz#2238, ok markus@
693 - djm@cvs.openbsd.org 2014/04/30 05:29:56
694 [bufaux.c bufbn.c bufec.c buffer.c buffer.h sshbuf-getput-basic.c]
695 [sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c sshbuf.h ssherr.c]
696 [ssherr.h]
697 New buffer API; the first installment of the conversion/replacement
698 of OpenSSH's internals to make them usable as a standalone library.
699
700 This includes a set of wrappers to make it compatible with the
701 existing buffer API so replacement can occur incrementally.
702
703 With and ok markus@
704
705 Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew
706 Dempsky and Ron Bowes for a detailed review.
707 - naddy@cvs.openbsd.org 2014/04/30 19:07:48
708 [mac.c myproposal.h umac.c]
709 UMAC can use our local fallback implementation of AES when OpenSSL isn't
710 available. Glue code straight from Ted Krovetz's original umac.c.
711 ok markus@
712 - djm@cvs.openbsd.org 2014/05/02 03:27:54
713 [chacha.h cipher-chachapoly.h digest.h hmac.h kex.h kexc25519.c]
714 [misc.h poly1305.h ssh-pkcs11.c defines.h]
715 revert __bounded change; it causes way more problems for portable than
716 it solves; pointed out by dtucker@
717 - markus@cvs.openbsd.org 2014/05/03 17:20:34
718 [monitor.c packet.c packet.h]
719 unbreak compression, by re-init-ing the compression code in the
720 post-auth child. the new buffer code is more strict, and requires
721 buffer_init() while the old code was happy after a bzero();
722 originally from djm@
723 - logan@cvs.openbsd.org 2014/05/05 07:02:30
724 [sftp.c]
725 Zap extra whitespace.
726
727 OK from djm@ and dtucker@
728 - (djm) [configure.ac] Unconditionally define WITH_OPENSSL until we write
729 portability glue to support building without libcrypto
730 - (djm) [Makefile.in configure.ac sshbuf-getput-basic.c]
731 [sshbuf-getput-crypto.c sshbuf.c] compilation and portability fixes
732 - OpenBSD CVS Sync
733 - djm@cvs.openbsd.org 2014/03/13 20:44:49
734 [login-timeout.sh]
735 this test is a sorry mess of race conditions; add another sleep
736 to avoid a failure on slow machines (at least until I find a
737 better way)
738 - djm@cvs.openbsd.org 2014/04/21 22:15:37
739 [dhgex.sh integrity.sh kextype.sh rekey.sh try-ciphers.sh]
740 repair regress tests broken by server-side default cipher/kex/mac changes
741 by ensuring that the option under test is included in the server's
742 algorithm list
743 - dtucker@cvs.openbsd.org 2014/05/03 18:46:14
744 [proxy-connect.sh]
745 Add tests for with and without compression, with and without privsep.
746 - logan@cvs.openbsd.org 2014/05/04 10:40:59
747 [connect-privsep.sh]
748 Remove the Z flag from the list of malloc options as it
749 was removed from malloc.c 10 days ago.
750
751 OK from miod@
752 - (djm) [regress/unittests/Makefile]
753 [regress/unittests/Makefile.inc]
754 [regress/unittests/sshbuf/Makefile]
755 [regress/unittests/sshbuf/test_sshbuf.c]
756 [regress/unittests/sshbuf/test_sshbuf_fixed.c]
757 [regress/unittests/sshbuf/test_sshbuf_fuzz.c]
758 [regress/unittests/sshbuf/test_sshbuf_getput_basic.c]
759 [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c]
760 [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c]
761 [regress/unittests/sshbuf/test_sshbuf_misc.c]
762 [regress/unittests/sshbuf/tests.c]
763 [regress/unittests/test_helper/Makefile]
764 [regress/unittests/test_helper/fuzz.c]
765 [regress/unittests/test_helper/test_helper.c]
766 [regress/unittests/test_helper/test_helper.h]
767 Import new unit tests from OpenBSD; not yet hooked up to build.
768 - (djm) [regress/Makefile Makefile.in]
769 [regress/unittests/sshbuf/test_sshbuf.c
770 [regress/unittests/sshbuf/test_sshbuf_fixed.c]
771 [regress/unittests/sshbuf/test_sshbuf_fuzz.c]
772 [regress/unittests/sshbuf/test_sshbuf_getput_basic.c]
773 [regress/unittests/sshbuf/test_sshbuf_getput_crypto.c]
774 [regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c]
775 [regress/unittests/sshbuf/test_sshbuf_misc.c]
776 [regress/unittests/sshbuf/tests.c]
777 [regress/unittests/test_helper/fuzz.c]
778 [regress/unittests/test_helper/test_helper.c]
779 Hook new unit tests into the build and "make tests"
780 - (djm) [sshbuf.c] need __predict_false
781
78220140430
783 - (dtucker) [defines.h] Define __GNUC_PREREQ__ macro if we don't already
784 have it. Only attempt to use __attribute__(__bounded__) for gcc.
785
78620140420
787 - OpenBSD CVS Sync
788 - djm@cvs.openbsd.org 2014/03/03 22:22:30
789 [session.c]
790 ignore enviornment variables with embedded '=' or '\0' characters;
791 spotted by Jann Horn; ok deraadt@
792 Id sync only - portable already has this.
793 - djm@cvs.openbsd.org 2014/03/12 04:44:58
794 [ssh-keyscan.c]
795 scan for Ed25519 keys by default too
796 - djm@cvs.openbsd.org 2014/03/12 04:50:32
797 [auth-bsdauth.c ssh-keygen.c]
798 don't count on things that accept arguments by reference to clear
799 things for us on error; most things do, but it's unsafe form.
800 - djm@cvs.openbsd.org 2014/03/12 04:51:12
801 [authfile.c]
802 correct test that kdf name is not "none" or "bcrypt"
803 - naddy@cvs.openbsd.org 2014/03/12 13:06:59
804 [ssh-keyscan.1]
805 scan for Ed25519 keys by default too
806 - deraadt@cvs.openbsd.org 2014/03/15 17:28:26
807 [ssh-agent.c ssh-keygen.1 ssh-keygen.c]
808 Improve usage() and documentation towards the standard form.
809 In particular, this line saves a lot of man page reading time.
810 usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa | rsa1]
811 [-N new_passphrase] [-C comment] [-f output_keyfile]
812 ok schwarze jmc
813 - tedu@cvs.openbsd.org 2014/03/17 19:44:10
814 [ssh.1]
815 old descriptions of des and blowfish are old. maybe ok deraadt
816 - tedu@cvs.openbsd.org 2014/03/19 14:42:44
817 [scp.1]
818 there is no need for rcp anymore
819 ok deraadt millert
820 - markus@cvs.openbsd.org 2014/03/25 09:40:03
821 [myproposal.h]
822 trimm default proposals.
823
824 This commit removes the weaker pre-SHA2 hashes, the broken ciphers
825 (arcfour), and the broken modes (CBC) from the default configuration
826 (the patch only changes the default, all the modes are still available
827 for the config files).
828
829 ok djm@, reminded by tedu@ & naddy@ and discussed with many
830 - deraadt@cvs.openbsd.org 2014/03/26 17:16:26
831 [myproposal.h]
832 The current sharing of myproposal[] between both client and server code
833 makes the previous diff highly unpallatable. We want to go in that
834 direction for the server, but not for the client. Sigh.
835 Brought up by naddy.
836 - markus@cvs.openbsd.org 2014/03/27 23:01:27
837 [myproposal.h ssh-keyscan.c sshconnect2.c sshd.c]
838 disable weak proposals in sshd, but keep them in ssh; ok djm@
839 - djm@cvs.openbsd.org 2014/03/26 04:55:35
840 [chacha.h cipher-chachapoly.h digest.h hmac.h kex.h kexc25519.c
841 [misc.h poly1305.h ssh-pkcs11.c]
842 use __bounded(...) attribute recently added to sys/cdefs.h instead of
843 longform __attribute__(__bounded(...));
844
845 for brevity and a warning free compilation with llvm/clang
846 - tedu@cvs.openbsd.org 2014/03/26 19:58:37
847 [sshd.8 sshd.c]
848 remove libwrap support. ok deraadt djm mfriedl
849 - naddy@cvs.openbsd.org 2014/03/28 05:17:11
850 [ssh_config.5 sshd_config.5]
851 sync available and default algorithms, improve algorithm list formatting
852 help from jmc@ and schwarze@, ok deraadt@
853 - jmc@cvs.openbsd.org 2014/03/31 13:39:34
854 [ssh-keygen.1]
855 the text for the -K option was inserted in the wrong place in -r1.108;
856 fix From: Matthew Clarke
857 - djm@cvs.openbsd.org 2014/04/01 02:05:27
858 [ssh-keysign.c]
859 include fingerprint of key not found
860 use arc4random_buf() instead of loop+arc4random()
861 - djm@cvs.openbsd.org 2014/04/01 03:34:10
862 [sshconnect.c]
863 When using VerifyHostKeyDNS with a DNSSEC resolver, down-convert any
864 certificate keys to plain keys and attempt SSHFP resolution.
865
866 Prevents a server from skipping SSHFP lookup and forcing a new-hostkey
867 dialog by offering only certificate keys.
868
869 Reported by mcv21 AT cam.ac.uk
870 - djm@cvs.openbsd.org 2014/04/01 05:32:57
871 [packet.c]
872 demote a debug3 to PACKET_DEBUG; ok markus@
873 - djm@cvs.openbsd.org 2014/04/12 04:55:53
874 [sshd.c]
875 avoid crash at exit: check that pmonitor!=NULL before dereferencing;
876 bz#2225, patch from kavi AT juniper.net
877 - djm@cvs.openbsd.org 2014/04/16 23:22:45
878 [bufaux.c]
879 skip leading zero bytes in buffer_put_bignum2_from_string();
880 reported by jan AT mojzis.com; ok markus@
881 - djm@cvs.openbsd.org 2014/04/16 23:28:12
882 [ssh-agent.1]
883 remove the identity files from this manpage - ssh-agent doesn't deal
884 with them at all and the same information is duplicated in ssh-add.1
885 (which does deal with them); prodded by deraadt@
886 - djm@cvs.openbsd.org 2014/04/18 23:52:25
887 [compat.c compat.h sshconnect2.c sshd.c version.h]
888 OpenSSH 6.5 and 6.6 have a bug that causes ~0.2% of connections
889 using the curve25519-sha256@libssh.org KEX exchange method to fail
890 when connecting with something that implements the spec properly.
891
892 Disable this KEX method when speaking to one of the affected
893 versions.
894
895 reported by Aris Adamantiadis; ok markus@
896 - djm@cvs.openbsd.org 2014/04/19 05:54:59
897 [compat.c]
898 missing wildcard; pointed out by naddy@
899 - tedu@cvs.openbsd.org 2014/04/19 14:53:48
900 [ssh-keysign.c sshd.c]
901 Delete futile calls to RAND_seed. ok djm
902 NB. Id sync only. This only applies to OpenBSD's libcrypto slashathon
903 - tedu@cvs.openbsd.org 2014/04/19 18:15:16
904 [sshd.8]
905 remove some really old rsh references
906 - tedu@cvs.openbsd.org 2014/04/19 18:42:19
907 [ssh.1]
908 delete .xr to hosts.equiv. there's still an unfortunate amount of
909 documentation referring to rhosts equivalency in here.
910 - djm@cvs.openbsd.org 2014/04/20 02:30:25
911 [misc.c misc.h umac.c]
912 use get/put_u32 to load values rather than *((UINT32 *)p) that breaks on
913 strict-alignment architectures; reported by and ok stsp@
914 - djm@cvs.openbsd.org 2014/04/20 02:49:32
915 [compat.c]
916 add a canonical 6.6 + curve25519 bignum fix fake version that I can
917 recommend people use ahead of the openssh-6.7 release
918
91920140401
920 - (djm) On platforms that support it, use prctl() to prevent sftp-server
921 from accessing /proc/self/{mem,maps}; patch from jann AT thejh.net
922 - (djm) Use full release (e.g. 6.5p1) in debug output rather than just
923 version. From des@des.no
924
92520140317
926 - (djm) [sandbox-seccomp-filter.c] Soft-fail stat() syscalls. Add XXX to
927 remind myself to add sandbox violation logging via the log socket.
928
92920140314
930 - (tim) [opensshd.init.in] Add support for ed25519
931
120140313 93220140313
2 - (djm) Release OpenSSH 6.6 933 - (djm) Release OpenSSH 6.6
3 934
@@ -2884,4 +3815,3 @@
2884 [contrib/suse/openssh.spec] Update for release 6.0 3815 [contrib/suse/openssh.spec] Update for release 6.0
2885 - (djm) [README] Update URL to release notes. 3816 - (djm) [README] Update URL to release notes.
2886 - (djm) Release openssh-6.0 3817 - (djm) Release openssh-6.0
2887
diff --git a/INSTALL b/INSTALL
index 576723048..cbbb2df59 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,22 +1,26 @@
11. Prerequisites 11. Prerequisites
2---------------- 2----------------
3 3
4You will need working installations of Zlib and OpenSSL. 4You will need working installations of Zlib and libcrypto (LibreSSL /
5OpenSSL)
5 6
6Zlib 1.1.4 or 1.2.1.2 or greater (ealier 1.2.x versions have problems): 7Zlib 1.1.4 or 1.2.1.2 or greater (ealier 1.2.x versions have problems):
7http://www.gzip.org/zlib/ 8http://www.gzip.org/zlib/
8 9
9OpenSSL 0.9.6 or greater: 10libcrypto (LibreSSL or OpenSSL >= 0.9.8f)
10http://www.openssl.org/ 11LibreSSL http://www.libressl.org/ ; or
12OpenSSL http://www.openssl.org/
11 13
12(OpenSSL 0.9.5a is partially supported, but some ciphers (SSH protocol 1 14LibreSSL/OpenSSL should be compiled as a position-independent library
13Blowfish) do not work correctly.) 15(i.e. with -fPIC) otherwise OpenSSH will not be able to link with it.
16If you must use a non-position-independent libcrypto, then you may need
17to configure OpenSSH --without-pie.
14 18
15The remaining items are optional. 19The remaining items are optional.
16 20
17NB. If you operating system supports /dev/random, you should configure 21NB. If you operating system supports /dev/random, you should configure
18OpenSSL to use it. OpenSSH relies on OpenSSL's direct support of 22libcrypto (LibreSSL/OpenSSL) to use it. OpenSSH relies on libcrypto's
19/dev/random, or failing that, either prngd or egd 23direct support of /dev/random, or failing that, either prngd or egd
20 24
21PRNGD: 25PRNGD:
22 26
@@ -27,10 +31,10 @@ http://prngd.sourceforge.net/
27 31
28EGD: 32EGD:
29 33
30The Entropy Gathering Daemon (EGD) is supported if you have a system which 34If the kernel lacks /dev/random the Entropy Gathering Daemon (EGD) is
31lacks /dev/random and don't want to use OpenSSH's internal entropy collection. 35supported only if libcrypto supports it.
32 36
33http://www.lothar.com/tech/crypto/ 37http://egd.sourceforge.net/
34 38
35PAM: 39PAM:
36 40
@@ -55,15 +59,6 @@ passphrase requester. This is maintained separately at:
55 59
56http://www.jmknoble.net/software/x11-ssh-askpass/ 60http://www.jmknoble.net/software/x11-ssh-askpass/
57 61
58TCP Wrappers:
59
60If you wish to use the TCP wrappers functionality you will need at least
61tcpd.h and libwrap.a, either in the standard include and library paths,
62or in the directory specified by --with-tcp-wrappers. Version 7.6 is
63known to work.
64
65http://ftp.porcupine.org/pub/security/index.html
66
67S/Key Libraries: 62S/Key Libraries:
68 63
69If you wish to use --with-skey then you will need the library below 64If 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.
180--with-skey=PATH will enable S/Key one time password support. You will 175--with-skey=PATH will enable S/Key one time password support. You will
181need the S/Key libraries and header files installed for this to work. 176need the S/Key libraries and header files installed for this to work.
182 177
183--with-tcp-wrappers will enable TCP Wrappers (/etc/hosts.allow|deny)
184support.
185
186--with-md5-passwords will enable the use of MD5 passwords. Enable this 178--with-md5-passwords will enable the use of MD5 passwords. Enable this
187if your operating system uses MD5 passwords and the system crypt() does 179if your operating system uses MD5 passwords and the system crypt() does
188not support them directly (see the crypt(3/3c) man page). If enabled, the 180not support them directly (see the crypt(3/3c) man page). If enabled, the
@@ -204,10 +196,11 @@ created.
204 196
205--with-xauth=PATH specifies the location of the xauth binary 197--with-xauth=PATH specifies the location of the xauth binary
206 198
207--with-ssl-dir=DIR allows you to specify where your OpenSSL libraries 199--with-ssl-dir=DIR allows you to specify where your Libre/OpenSSL
200libraries
208are installed. 201are installed.
209 202
210--with-ssl-engine enables OpenSSL's (hardware) ENGINE support 203--with-ssl-engine enables Libre/OpenSSL's (hardware) ENGINE support
211 204
212--with-4in6 Check for IPv4 in IPv6 mapped addresses and convert them to 205--with-4in6 Check for IPv4 in IPv6 mapped addresses and convert them to
213real (AF_INET) IPv4 addresses. Works around some quirks on Linux. 206real (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
266http://www.openssh.com/ 259http://www.openssh.com/
267 260
268 261
269$Id: INSTALL,v 1.88 2013/03/07 01:33:35 dtucker Exp $ 262$Id: INSTALL,v 1.91 2014/09/09 02:23:11 dtucker Exp $
diff --git a/Makefile.in b/Makefile.in
index 28a8ec41b..06be3d5d5 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,4 @@
1# $Id: Makefile.in,v 1.356 2014/02/04 00:12:56 djm Exp $ 1# $Id: Makefile.in,v 1.365 2014/08/30 06:23:07 djm Exp $
2 2
3# uncomment if you run a non bourne compatable shell. Ie. csh 3# uncomment if you run a non bourne compatable shell. Ie. csh
4#SHELL = @SH@ 4#SHELL = @SH@
@@ -29,6 +29,7 @@ SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
29PRIVSEP_PATH=@PRIVSEP_PATH@ 29PRIVSEP_PATH=@PRIVSEP_PATH@
30SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ 30SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
31STRIP_OPT=@STRIP_OPT@ 31STRIP_OPT=@STRIP_OPT@
32TEST_SHELL=@TEST_SHELL@
32 33
33PATHS= -DSSHDIR=\"$(sysconfdir)\" \ 34PATHS= -DSSHDIR=\"$(sysconfdir)\" \
34 -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \ 35 -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \
@@ -63,7 +64,16 @@ MANFMT=@MANFMT@
63 64
64TARGETS=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) 65TARGETS=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)
65 66
66LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ 67LIBOPENSSH_OBJS=\
68 ssherr.o \
69 sshbuf.o \
70 sshkey.o \
71 sshbuf-getput-basic.o \
72 sshbuf-misc.o \
73 sshbuf-getput-crypto.o
74
75LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
76 authfd.o authfile.o bufaux.o bufbn.o buffer.o \
67 canohost.o channels.o cipher.o cipher-aes.o \ 77 canohost.o channels.o cipher.o cipher-aes.o \
68 cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \ 78 cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \
69 compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \ 79 compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \
@@ -135,7 +145,7 @@ $(SSHOBJS): Makefile.in config.h
135$(SSHDOBJS): Makefile.in config.h 145$(SSHDOBJS): Makefile.in config.h
136 146
137.c.o: 147.c.o:
138 $(CC) $(CFLAGS) $(CPPFLAGS) -c $< 148 $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
139 149
140LIBCOMPAT=openbsd-compat/libopenbsd-compat.a 150LIBCOMPAT=openbsd-compat/libopenbsd-compat.a
141$(LIBCOMPAT): always 151$(LIBCOMPAT): always
@@ -214,6 +224,12 @@ umac128.o: umac.c
214clean: regressclean 224clean: regressclean
215 rm -f *.o *.a $(TARGETS) logintest config.cache config.log 225 rm -f *.o *.a $(TARGETS) logintest config.cache config.log
216 rm -f *.out core survey 226 rm -f *.out core survey
227 rm -f regress/unittests/test_helper/*.a
228 rm -f regress/unittests/test_helper/*.o
229 rm -f regress/unittests/sshbuf/*.o
230 rm -f regress/unittests/sshbuf/test_sshbuf
231 rm -f regress/unittests/sshkey/*.o
232 rm -f regress/unittests/sshkey/test_sshkey
217 (cd openbsd-compat && $(MAKE) clean) 233 (cd openbsd-compat && $(MAKE) clean)
218 234
219distclean: regressclean 235distclean: regressclean
@@ -222,6 +238,12 @@ distclean: regressclean
222 rm -f Makefile buildpkg.sh config.h config.status 238 rm -f Makefile buildpkg.sh config.h config.status
223 rm -f survey.sh openbsd-compat/regress/Makefile *~ 239 rm -f survey.sh openbsd-compat/regress/Makefile *~
224 rm -rf autom4te.cache 240 rm -rf autom4te.cache
241 rm -f regress/unittests/test_helper/*.a
242 rm -f regress/unittests/test_helper/*.o
243 rm -f regress/unittests/sshbuf/*.o
244 rm -f regress/unittests/sshbuf/test_sshbuf
245 rm -f regress/unittests/sshkey/*.o
246 rm -f regress/unittests/sshkey/test_sshkey
225 (cd openbsd-compat && $(MAKE) distclean) 247 (cd openbsd-compat && $(MAKE) distclean)
226 if test -d pkg ; then \ 248 if test -d pkg ; then \
227 rm -fr pkg ; \ 249 rm -fr pkg ; \
@@ -394,23 +416,71 @@ uninstall:
394 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 416 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
395 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 417 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
396 418
397regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c 419regress-prep:
398 [ -d `pwd`/regress ] || mkdir -p `pwd`/regress 420 [ -d `pwd`/regress ] || mkdir -p `pwd`/regress
421 [ -d `pwd`/regress/unittests ] || mkdir -p `pwd`/regress/unittests
422 [ -d `pwd`/regress/unittests/test_helper ] || \
423 mkdir -p `pwd`/regress/unittests/test_helper
424 [ -d `pwd`/regress/unittests/sshbuf ] || \
425 mkdir -p `pwd`/regress/unittests/sshbuf
426 [ -d `pwd`/regress/unittests/sshkey ] || \
427 mkdir -p `pwd`/regress/unittests/sshkey
399 [ -f `pwd`/regress/Makefile ] || \ 428 [ -f `pwd`/regress/Makefile ] || \
400 ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile 429 ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile
430
431regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c
401 $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $? \ 432 $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $? \
402 $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) 433 $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
403 434
404regress/setuid-allowed$(EXEEXT): $(srcdir)/regress/setuid-allowed.c 435regress/setuid-allowed$(EXEEXT): $(srcdir)/regress/setuid-allowed.c
405 [ -d `pwd`/regress ] || mkdir -p `pwd`/regress
406 [ -f `pwd`/regress/Makefile ] || \
407 ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile
408 $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $? \ 436 $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $? \
409 $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) 437 $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
410 438
411tests interop-tests: $(TARGETS) regress/modpipe$(EXEEXT) regress/setuid-allowed$(EXEEXT) 439UNITTESTS_TEST_HELPER_OBJS=\
440 regress/unittests/test_helper/test_helper.o \
441 regress/unittests/test_helper/fuzz.o
442
443regress/unittests/test_helper/libtest_helper.a: ${UNITTESTS_TEST_HELPER_OBJS}
444 $(AR) rv $@ $(UNITTESTS_TEST_HELPER_OBJS)
445 $(RANLIB) $@
446
447UNITTESTS_TEST_SSHBUF_OBJS=\
448 regress/unittests/sshbuf/tests.o \
449 regress/unittests/sshbuf/test_sshbuf.o \
450 regress/unittests/sshbuf/test_sshbuf_getput_basic.o \
451 regress/unittests/sshbuf/test_sshbuf_getput_crypto.o \
452 regress/unittests/sshbuf/test_sshbuf_misc.o \
453 regress/unittests/sshbuf/test_sshbuf_fuzz.o \
454 regress/unittests/sshbuf/test_sshbuf_getput_fuzz.o \
455 regress/unittests/sshbuf/test_sshbuf_fixed.o
456
457regress/unittests/sshbuf/test_sshbuf$(EXEEXT): ${UNITTESTS_TEST_SSHBUF_OBJS} \
458 regress/unittests/test_helper/libtest_helper.a libssh.a
459 $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHBUF_OBJS) \
460 regress/unittests/test_helper/libtest_helper.a \
461 -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
462
463UNITTESTS_TEST_SSHKEY_OBJS=\
464 regress/unittests/sshkey/test_fuzz.o \
465 regress/unittests/sshkey/tests.o \
466 regress/unittests/sshkey/common.o \
467 regress/unittests/sshkey/test_file.o \
468 regress/unittests/sshkey/test_sshkey.o
469
470regress/unittests/sshkey/test_sshkey$(EXEEXT): ${UNITTESTS_TEST_SSHKEY_OBJS} \
471 regress/unittests/test_helper/libtest_helper.a libssh.a
472 $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_SSHKEY_OBJS) \
473 regress/unittests/test_helper/libtest_helper.a \
474 -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
475
476REGRESS_BINARIES=\
477 regress/modpipe$(EXEEXT) \
478 regress/setuid-allowed$(EXEEXT) \
479 regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \
480 regress/unittests/sshkey/test_sshkey$(EXEEXT)
481
482tests interop-tests t-exec: regress-prep $(TARGETS) $(REGRESS_BINARIES)
412 BUILDDIR=`pwd`; \ 483 BUILDDIR=`pwd`; \
413 TEST_SHELL="@TEST_SHELL@"; \
414 TEST_SSH_SCP="$${BUILDDIR}/scp"; \ 484 TEST_SSH_SCP="$${BUILDDIR}/scp"; \
415 TEST_SSH_SSH="$${BUILDDIR}/ssh"; \ 485 TEST_SSH_SSH="$${BUILDDIR}/ssh"; \
416 TEST_SSH_SSHD="$${BUILDDIR}/sshd"; \ 486 TEST_SSH_SSHD="$${BUILDDIR}/sshd"; \
@@ -434,7 +504,6 @@ tests interop-tests: $(TARGETS) regress/modpipe$(EXEEXT) regress/setuid-allowed$
434 OBJ="$${BUILDDIR}/regress/" \ 504 OBJ="$${BUILDDIR}/regress/" \
435 PATH="$${BUILDDIR}:$${PATH}" \ 505 PATH="$${BUILDDIR}:$${PATH}" \
436 TEST_ENV=MALLOC_OPTIONS="@TEST_MALLOC_OPTIONS@" \ 506 TEST_ENV=MALLOC_OPTIONS="@TEST_MALLOC_OPTIONS@" \
437 TEST_SHELL="$${TEST_SHELL}" \
438 TEST_SSH_SCP="$${TEST_SSH_SCP}" \ 507 TEST_SSH_SCP="$${TEST_SSH_SCP}" \
439 TEST_SSH_SSH="$${TEST_SSH_SSH}" \ 508 TEST_SSH_SSH="$${TEST_SSH_SSH}" \
440 TEST_SSH_SSHD="$${TEST_SSH_SSHD}" \ 509 TEST_SSH_SSHD="$${TEST_SSH_SSHD}" \
@@ -450,6 +519,7 @@ tests interop-tests: $(TARGETS) regress/modpipe$(EXEEXT) regress/setuid-allowed$
450 TEST_SSH_CONCH="$${TEST_SSH_CONCH}" \ 519 TEST_SSH_CONCH="$${TEST_SSH_CONCH}" \
451 TEST_SSH_IPV6="$${TEST_SSH_IPV6}" \ 520 TEST_SSH_IPV6="$${TEST_SSH_IPV6}" \
452 TEST_SSH_ECC="$${TEST_SSH_ECC}" \ 521 TEST_SSH_ECC="$${TEST_SSH_ECC}" \
522 TEST_SHELL="${TEST_SHELL}" \
453 EXEEXT="$(EXEEXT)" \ 523 EXEEXT="$(EXEEXT)" \
454 $@ && echo all tests passed 524 $@ && echo all tests passed
455 525
diff --git a/PROTOCOL b/PROTOCOL
index 4a5088f90..aa59f584e 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -232,6 +232,56 @@ The contents of the "data" field for layer 2 packets is:
232The "frame" field contains an IEEE 802.3 Ethernet frame, including 232The "frame" field contains an IEEE 802.3 Ethernet frame, including
233header. 233header.
234 234
2352.4. connection: Unix domain socket forwarding
236
237OpenSSH supports local and remote Unix domain socket forwarding
238using the "streamlocal" extension. Forwarding is initiated as per
239TCP sockets but with a single path instead of a host and port.
240
241Similar to direct-tcpip, direct-streamlocal is sent by the client
242to request that the server make a connection to a Unix domain socket.
243
244 byte SSH_MSG_CHANNEL_OPEN
245 string "direct-streamlocal@openssh.com"
246 uint32 sender channel
247 uint32 initial window size
248 uint32 maximum packet size
249 string socket path
250 string reserved for future use
251
252Similar to forwarded-tcpip, forwarded-streamlocal is sent by the
253server when the client has previously send the server a streamlocal-forward
254GLOBAL_REQUEST.
255
256 byte SSH_MSG_CHANNEL_OPEN
257 string "forwarded-streamlocal@openssh.com"
258 uint32 sender channel
259 uint32 initial window size
260 uint32 maximum packet size
261 string socket path
262 string reserved for future use
263
264The reserved field is not currently defined and is ignored on the
265remote end. It is intended to be used in the future to pass
266information about the socket file, such as ownership and mode.
267The client currently sends the empty string for this field.
268
269Similar to tcpip-forward, streamlocal-forward is sent by the client
270to request remote forwarding of a Unix domain socket.
271
272 byte SSH2_MSG_GLOBAL_REQUEST
273 string "streamlocal-forward@openssh.com"
274 boolean TRUE
275 string socket path
276
277Similar to cancel-tcpip-forward, cancel-streamlocal-forward is sent
278by the client cancel the forwarding of a Unix domain socket.
279
280 byte SSH2_MSG_GLOBAL_REQUEST
281 string "cancel-streamlocal-forward@openssh.com"
282 boolean FALSE
283 string socket path
284
2353. SFTP protocol changes 2853. SFTP protocol changes
236 286
2373.1. sftp: Reversal of arguments to SSH_FXP_SYMLINK 2873.1. sftp: Reversal of arguments to SSH_FXP_SYMLINK
@@ -356,4 +406,4 @@ respond with a SSH_FXP_STATUS message.
356This extension is advertised in the SSH_FXP_VERSION hello with version 406This extension is advertised in the SSH_FXP_VERSION hello with version
357"1". 407"1".
358 408
359$OpenBSD: PROTOCOL,v 1.23 2013/12/01 23:19:05 djm Exp $ 409$OpenBSD: PROTOCOL,v 1.24 2014/07/15 15:54:14 millert Exp $
diff --git a/README b/README
index 368dca59c..b21441ae0 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
1See http://www.openssh.com/txt/release-6.6 for the release notes. 1See http://www.openssh.com/txt/release-6.7 for the release notes.
2 2
3- A Japanese translation of this document and of the OpenSSH FAQ is 3- A Japanese translation of this document and of the OpenSSH FAQ is
4- available at http://www.unixuser.org/~haruyama/security/openssh/index.html 4- available at http://www.unixuser.org/~haruyama/security/openssh/index.html
@@ -62,4 +62,4 @@ References -
62[6] http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9 62[6] http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9
63[7] http://www.openssh.com/faq.html 63[7] http://www.openssh.com/faq.html
64 64
65$Id: README,v 1.86 2014/02/27 23:03:53 djm Exp $ 65$Id: README,v 1.87 2014/08/10 01:35:06 djm Exp $
diff --git a/auth-bsdauth.c b/auth-bsdauth.c
index 0b3262b49..37ff893e6 100644
--- a/auth-bsdauth.c
+++ b/auth-bsdauth.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth-bsdauth.c,v 1.11 2007/09/21 08:15:29 djm Exp $ */ 1/* $OpenBSD: auth-bsdauth.c,v 1.13 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -26,6 +26,8 @@
26#include "includes.h" 26#include "includes.h"
27 27
28#include <sys/types.h> 28#include <sys/types.h>
29#include <stdarg.h>
30#include <stdio.h>
29 31
30#include <stdarg.h> 32#include <stdarg.h>
31 33
@@ -54,6 +56,11 @@ bsdauth_query(void *ctx, char **name, char **infotxt,
54 Authctxt *authctxt = ctx; 56 Authctxt *authctxt = ctx;
55 char *challenge = NULL; 57 char *challenge = NULL;
56 58
59 *infotxt = NULL;
60 *numprompts = 0;
61 *prompts = NULL;
62 *echo_on = NULL;
63
57 if (authctxt->as != NULL) { 64 if (authctxt->as != NULL) {
58 debug2("bsdauth_query: try reuse session"); 65 debug2("bsdauth_query: try reuse session");
59 challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE); 66 challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
diff --git a/auth-chall.c b/auth-chall.c
index 0005aa88b..5c26a403d 100644
--- a/auth-chall.c
+++ b/auth-chall.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth-chall.c,v 1.13 2013/05/17 00:13:13 djm Exp $ */ 1/* $OpenBSD: auth-chall.c,v 1.14 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -26,6 +26,9 @@
26#include "includes.h" 26#include "includes.h"
27 27
28#include <sys/types.h> 28#include <sys/types.h>
29#include <stdarg.h>
30#include <stdlib.h>
31#include <stdio.h>
29 32
30#include <stdarg.h> 33#include <stdarg.h>
31 34
@@ -34,6 +37,7 @@
34#include "hostfile.h" 37#include "hostfile.h"
35#include "auth.h" 38#include "auth.h"
36#include "log.h" 39#include "log.h"
40#include "misc.h"
37#include "servconf.h" 41#include "servconf.h"
38 42
39/* limited protocol v1 interface to kbd-interactive authentication */ 43/* limited protocol v1 interface to kbd-interactive authentication */
diff --git a/auth-krb5.c b/auth-krb5.c
index 6c62bdf54..0089b1844 100644
--- a/auth-krb5.c
+++ b/auth-krb5.c
@@ -40,6 +40,7 @@
40#include "packet.h" 40#include "packet.h"
41#include "log.h" 41#include "log.h"
42#include "buffer.h" 42#include "buffer.h"
43#include "misc.h"
43#include "servconf.h" 44#include "servconf.h"
44#include "uidswap.h" 45#include "uidswap.h"
45#include "key.h" 46#include "key.h"
diff --git a/auth-options.c b/auth-options.c
index fa209eaab..f3d9c9df8 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth-options.c,v 1.62 2013/12/19 00:27:57 djm Exp $ */ 1/* $OpenBSD: auth-options.c,v 1.64 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -26,9 +26,9 @@
26#include "log.h" 26#include "log.h"
27#include "canohost.h" 27#include "canohost.h"
28#include "buffer.h" 28#include "buffer.h"
29#include "misc.h"
29#include "channels.h" 30#include "channels.h"
30#include "servconf.h" 31#include "servconf.h"
31#include "misc.h"
32#include "key.h" 32#include "key.h"
33#include "auth-options.h" 33#include "auth-options.h"
34#include "hostfile.h" 34#include "hostfile.h"
@@ -325,6 +325,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
325 patterns[i] = '\0'; 325 patterns[i] = '\0';
326 opts++; 326 opts++;
327 p = patterns; 327 p = patterns;
328 /* XXX - add streamlocal support */
328 host = hpdelim(&p); 329 host = hpdelim(&p);
329 if (host == NULL || strlen(host) >= NI_MAXHOST) { 330 if (host == NULL || strlen(host) >= NI_MAXHOST) {
330 debug("%.100s, line %lu: Bad permitopen " 331 debug("%.100s, line %lu: Bad permitopen "
@@ -586,8 +587,8 @@ auth_cert_options(Key *k, struct passwd *pw)
586 587
587 if (key_cert_is_legacy(k)) { 588 if (key_cert_is_legacy(k)) {
588 /* All options are in the one field for v00 certs */ 589 /* All options are in the one field for v00 certs */
589 if (parse_option_list(buffer_ptr(&k->cert->critical), 590 if (parse_option_list(buffer_ptr(k->cert->critical),
590 buffer_len(&k->cert->critical), pw, 591 buffer_len(k->cert->critical), pw,
591 OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1, 592 OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1,
592 &cert_no_port_forwarding_flag, 593 &cert_no_port_forwarding_flag,
593 &cert_no_agent_forwarding_flag, 594 &cert_no_agent_forwarding_flag,
@@ -599,14 +600,14 @@ auth_cert_options(Key *k, struct passwd *pw)
599 return -1; 600 return -1;
600 } else { 601 } else {
601 /* Separate options and extensions for v01 certs */ 602 /* Separate options and extensions for v01 certs */
602 if (parse_option_list(buffer_ptr(&k->cert->critical), 603 if (parse_option_list(buffer_ptr(k->cert->critical),
603 buffer_len(&k->cert->critical), pw, 604 buffer_len(k->cert->critical), pw,
604 OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, 605 OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL,
605 &cert_forced_command, 606 &cert_forced_command,
606 &cert_source_address_done) == -1) 607 &cert_source_address_done) == -1)
607 return -1; 608 return -1;
608 if (parse_option_list(buffer_ptr(&k->cert->extensions), 609 if (parse_option_list(buffer_ptr(k->cert->extensions),
609 buffer_len(&k->cert->extensions), pw, 610 buffer_len(k->cert->extensions), pw,
610 OPTIONS_EXTENSIONS, 1, 611 OPTIONS_EXTENSIONS, 1,
611 &cert_no_port_forwarding_flag, 612 &cert_no_port_forwarding_flag,
612 &cert_no_agent_forwarding_flag, 613 &cert_no_agent_forwarding_flag,
diff --git a/auth-passwd.c b/auth-passwd.c
index 68bbd18dd..63ccf3cab 100644
--- a/auth-passwd.c
+++ b/auth-passwd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth-passwd.c,v 1.43 2007/09/21 08:15:29 djm Exp $ */ 1/* $OpenBSD: auth-passwd.c,v 1.44 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -48,6 +48,7 @@
48#include "packet.h" 48#include "packet.h"
49#include "buffer.h" 49#include "buffer.h"
50#include "log.h" 50#include "log.h"
51#include "misc.h"
51#include "servconf.h" 52#include "servconf.h"
52#include "key.h" 53#include "key.h"
53#include "hostfile.h" 54#include "hostfile.h"
diff --git a/auth-rh-rsa.c b/auth-rh-rsa.c
index b21a0f4a2..b7fd064e7 100644
--- a/auth-rh-rsa.c
+++ b/auth-rh-rsa.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth-rh-rsa.c,v 1.43 2010/03/04 10:36:03 djm Exp $ */ 1/* $OpenBSD: auth-rh-rsa.c,v 1.44 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -24,6 +24,7 @@
24#include "uidswap.h" 24#include "uidswap.h"
25#include "log.h" 25#include "log.h"
26#include "buffer.h" 26#include "buffer.h"
27#include "misc.h"
27#include "servconf.h" 28#include "servconf.h"
28#include "key.h" 29#include "key.h"
29#include "hostfile.h" 30#include "hostfile.h"
diff --git a/auth-rhosts.c b/auth-rhosts.c
index 06ae7f0b9..b5bedee8d 100644
--- a/auth-rhosts.c
+++ b/auth-rhosts.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth-rhosts.c,v 1.44 2010/03/07 11:57:13 dtucker Exp $ */ 1/* $OpenBSD: auth-rhosts.c,v 1.45 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -34,12 +34,12 @@
34#include "uidswap.h" 34#include "uidswap.h"
35#include "pathnames.h" 35#include "pathnames.h"
36#include "log.h" 36#include "log.h"
37#include "misc.h"
37#include "servconf.h" 38#include "servconf.h"
38#include "canohost.h" 39#include "canohost.h"
39#include "key.h" 40#include "key.h"
40#include "hostfile.h" 41#include "hostfile.h"
41#include "auth.h" 42#include "auth.h"
42#include "misc.h"
43 43
44/* import */ 44/* import */
45extern ServerOptions options; 45extern ServerOptions options;
diff --git a/auth-rsa.c b/auth-rsa.c
index 5dad6c3dc..e9f4ede26 100644
--- a/auth-rsa.c
+++ b/auth-rsa.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth-rsa.c,v 1.86 2014/01/27 19:18:54 markus Exp $ */ 1/* $OpenBSD: auth-rsa.c,v 1.88 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -35,6 +35,7 @@
35#include "buffer.h" 35#include "buffer.h"
36#include "pathnames.h" 36#include "pathnames.h"
37#include "log.h" 37#include "log.h"
38#include "misc.h"
38#include "servconf.h" 39#include "servconf.h"
39#include "key.h" 40#include "key.h"
40#include "auth-options.h" 41#include "auth-options.h"
@@ -45,7 +46,6 @@
45#endif 46#endif
46#include "monitor_wrap.h" 47#include "monitor_wrap.h"
47#include "ssh.h" 48#include "ssh.h"
48#include "misc.h"
49 49
50#include "digest.h" 50#include "digest.h"
51 51
@@ -144,7 +144,8 @@ auth_rsa_challenge_dialog(Key *key)
144 challenge = PRIVSEP(auth_rsa_generate_challenge(key)); 144 challenge = PRIVSEP(auth_rsa_generate_challenge(key));
145 145
146 /* Encrypt the challenge with the public key. */ 146 /* Encrypt the challenge with the public key. */
147 rsa_public_encrypt(encrypted_challenge, challenge, key->rsa); 147 if (rsa_public_encrypt(encrypted_challenge, challenge, key->rsa) != 0)
148 fatal("%s: rsa_public_encrypt failed", __func__);
148 149
149 /* Send the encrypted challenge to the client. */ 150 /* Send the encrypted challenge to the client. */
150 packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); 151 packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
diff --git a/auth.c b/auth.c
index 9a36f1dac..5e60682ce 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth.c,v 1.103 2013/05/19 02:42:42 djm Exp $ */ 1/* $OpenBSD: auth.c,v 1.106 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -56,6 +56,7 @@
56#include "groupaccess.h" 56#include "groupaccess.h"
57#include "log.h" 57#include "log.h"
58#include "buffer.h" 58#include "buffer.h"
59#include "misc.h"
59#include "servconf.h" 60#include "servconf.h"
60#include "key.h" 61#include "key.h"
61#include "hostfile.h" 62#include "hostfile.h"
@@ -63,7 +64,6 @@
63#include "auth-options.h" 64#include "auth-options.h"
64#include "canohost.h" 65#include "canohost.h"
65#include "uidswap.h" 66#include "uidswap.h"
66#include "misc.h"
67#include "packet.h" 67#include "packet.h"
68#include "loginrec.h" 68#include "loginrec.h"
69#ifdef GSSAPI 69#ifdef GSSAPI
@@ -326,6 +326,20 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
326#endif 326#endif
327} 327}
328 328
329
330void
331auth_maxtries_exceeded(Authctxt *authctxt)
332{
333 packet_disconnect("Too many authentication failures for "
334 "%s%.100s from %.200s port %d %s",
335 authctxt->valid ? "" : "invalid user ",
336 authctxt->user,
337 get_remote_ipaddr(),
338 get_remote_port(),
339 compat20 ? "ssh2" : "ssh1");
340 /* NOTREACHED */
341}
342
329/* 343/*
330 * Check whether root logins are disallowed. 344 * Check whether root logins are disallowed.
331 */ 345 */
@@ -659,6 +673,7 @@ getpwnamallow(const char *user)
659int 673int
660auth_key_is_revoked(Key *key) 674auth_key_is_revoked(Key *key)
661{ 675{
676#ifdef WITH_OPENSSL
662 char *key_fp; 677 char *key_fp;
663 678
664 if (options.revoked_keys_file == NULL) 679 if (options.revoked_keys_file == NULL)
@@ -671,6 +686,7 @@ auth_key_is_revoked(Key *key)
671 default: 686 default:
672 goto revoked; 687 goto revoked;
673 } 688 }
689#endif
674 debug3("%s: treating %s as a key list", __func__, 690 debug3("%s: treating %s as a key list", __func__,
675 options.revoked_keys_file); 691 options.revoked_keys_file);
676 switch (key_in_file(key, options.revoked_keys_file, 0)) { 692 switch (key_in_file(key, options.revoked_keys_file, 0)) {
@@ -682,6 +698,7 @@ auth_key_is_revoked(Key *key)
682 error("Revoked keys file is unreadable: refusing public key " 698 error("Revoked keys file is unreadable: refusing public key "
683 "authentication"); 699 "authentication");
684 return 1; 700 return 1;
701#ifdef WITH_OPENSSL
685 case 1: 702 case 1:
686 revoked: 703 revoked:
687 /* Key revoked */ 704 /* Key revoked */
@@ -690,6 +707,7 @@ auth_key_is_revoked(Key *key)
690 "%s key %s ", key_type(key), key_fp); 707 "%s key %s ", key_type(key), key_fp);
691 free(key_fp); 708 free(key_fp);
692 return 1; 709 return 1;
710#endif
693 } 711 }
694 fatal("key_in_file returned junk"); 712 fatal("key_in_file returned junk");
695} 713}
diff --git a/auth.h b/auth.h
index 124e59743..d081c94a6 100644
--- a/auth.h
+++ b/auth.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth.h,v 1.77 2014/01/29 06:18:35 djm Exp $ */ 1/* $OpenBSD: auth.h,v 1.78 2014/07/03 11:16:55 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000 Markus Friedl. All rights reserved.
@@ -154,6 +154,7 @@ void auth_info(Authctxt *authctxt, const char *, ...)
154 __attribute__((__format__ (printf, 2, 3))) 154 __attribute__((__format__ (printf, 2, 3)))
155 __attribute__((__nonnull__ (2))); 155 __attribute__((__nonnull__ (2)));
156void auth_log(Authctxt *, int, int, const char *, const char *); 156void auth_log(Authctxt *, int, int, const char *, const char *);
157void auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn));
157void userauth_finish(Authctxt *, int, const char *, const char *); 158void userauth_finish(Authctxt *, int, const char *, const char *);
158int auth_root_allowed(const char *); 159int auth_root_allowed(const char *);
159 160
@@ -210,8 +211,6 @@ struct passwd *fakepw(void);
210 211
211int sys_auth_passwd(Authctxt *, const char *); 212int sys_auth_passwd(Authctxt *, const char *);
212 213
213#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
214
215#define SKEY_PROMPT "\nS/Key Password: " 214#define SKEY_PROMPT "\nS/Key Password: "
216 215
217#if defined(KRB5) && !defined(HEIMDAL) 216#if defined(KRB5) && !defined(HEIMDAL)
diff --git a/auth1.c b/auth1.c
index 0f870b3b6..50388285c 100644
--- a/auth1.c
+++ b/auth1.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth1.c,v 1.80 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: auth1.c,v 1.82 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved 4 * All rights reserved
@@ -27,6 +27,7 @@
27#include "packet.h" 27#include "packet.h"
28#include "buffer.h" 28#include "buffer.h"
29#include "log.h" 29#include "log.h"
30#include "misc.h"
30#include "servconf.h" 31#include "servconf.h"
31#include "compat.h" 32#include "compat.h"
32#include "key.h" 33#include "key.h"
@@ -363,7 +364,7 @@ do_authloop(Authctxt *authctxt)
363#ifdef SSH_AUDIT_EVENTS 364#ifdef SSH_AUDIT_EVENTS
364 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); 365 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
365#endif 366#endif
366 packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 367 auth_maxtries_exceeded(authctxt);
367 } 368 }
368 369
369 packet_start(SSH_SMSG_FAILURE); 370 packet_start(SSH_SMSG_FAILURE);
diff --git a/auth2-chall.c b/auth2-chall.c
index 980250a91..ea4eb6952 100644
--- a/auth2-chall.c
+++ b/auth2-chall.c
@@ -41,6 +41,7 @@
41#include "packet.h" 41#include "packet.h"
42#include "dispatch.h" 42#include "dispatch.h"
43#include "log.h" 43#include "log.h"
44#include "misc.h"
44#include "servconf.h" 45#include "servconf.h"
45 46
46/* import */ 47/* import */
diff --git a/auth2-gss.c b/auth2-gss.c
index c28a705cb..447f896f2 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -40,6 +40,7 @@
40#include "log.h" 40#include "log.h"
41#include "dispatch.h" 41#include "dispatch.h"
42#include "buffer.h" 42#include "buffer.h"
43#include "misc.h"
43#include "servconf.h" 44#include "servconf.h"
44#include "packet.h" 45#include "packet.h"
45#include "ssh-gss.h" 46#include "ssh-gss.h"
diff --git a/auth2-hostbased.c b/auth2-hostbased.c
index 488008f62..6787e4ca4 100644
--- a/auth2-hostbased.c
+++ b/auth2-hostbased.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2-hostbased.c,v 1.17 2013/12/30 23:52:27 djm Exp $ */ 1/* $OpenBSD: auth2-hostbased.c,v 1.18 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -36,6 +36,7 @@
36#include "packet.h" 36#include "packet.h"
37#include "buffer.h" 37#include "buffer.h"
38#include "log.h" 38#include "log.h"
39#include "misc.h"
39#include "servconf.h" 40#include "servconf.h"
40#include "compat.h" 41#include "compat.h"
41#include "key.h" 42#include "key.h"
diff --git a/auth2-kbdint.c b/auth2-kbdint.c
index c39bdc62d..bf75c6059 100644
--- a/auth2-kbdint.c
+++ b/auth2-kbdint.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2-kbdint.c,v 1.6 2013/05/17 00:13:13 djm Exp $ */ 1/* $OpenBSD: auth2-kbdint.c,v 1.7 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -36,6 +36,7 @@
36#include "auth.h" 36#include "auth.h"
37#include "log.h" 37#include "log.h"
38#include "buffer.h" 38#include "buffer.h"
39#include "misc.h"
39#include "servconf.h" 40#include "servconf.h"
40 41
41/* import */ 42/* import */
diff --git a/auth2-none.c b/auth2-none.c
index c8c6c74a9..e71e2219c 100644
--- a/auth2-none.c
+++ b/auth2-none.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2-none.c,v 1.16 2010/06/25 08:46:17 djm Exp $ */ 1/* $OpenBSD: auth2-none.c,v 1.18 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -30,9 +30,10 @@
30#include <sys/uio.h> 30#include <sys/uio.h>
31 31
32#include <fcntl.h> 32#include <fcntl.h>
33#include <stdarg.h>
34#include <string.h> 33#include <string.h>
35#include <unistd.h> 34#include <unistd.h>
35#include <stdarg.h>
36#include <stdio.h>
36 37
37#include "atomicio.h" 38#include "atomicio.h"
38#include "xmalloc.h" 39#include "xmalloc.h"
@@ -42,6 +43,7 @@
42#include "packet.h" 43#include "packet.h"
43#include "log.h" 44#include "log.h"
44#include "buffer.h" 45#include "buffer.h"
46#include "misc.h"
45#include "servconf.h" 47#include "servconf.h"
46#include "compat.h" 48#include "compat.h"
47#include "ssh2.h" 49#include "ssh2.h"
diff --git a/auth2-passwd.c b/auth2-passwd.c
index 707680cd0..b638e8715 100644
--- a/auth2-passwd.c
+++ b/auth2-passwd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2-passwd.c,v 1.11 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: auth2-passwd.c,v 1.12 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -41,6 +41,7 @@
41#include "ssh-gss.h" 41#include "ssh-gss.h"
42#endif 42#endif
43#include "monitor_wrap.h" 43#include "monitor_wrap.h"
44#include "misc.h"
44#include "servconf.h" 45#include "servconf.h"
45 46
46/* import */ 47/* import */
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 0fd27bb92..f3ca96592 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2-pubkey.c,v 1.39 2013/12/30 23:52:27 djm Exp $ */ 1/* $OpenBSD: auth2-pubkey.c,v 1.41 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -48,6 +48,7 @@
48#include "packet.h" 48#include "packet.h"
49#include "buffer.h" 49#include "buffer.h"
50#include "log.h" 50#include "log.h"
51#include "misc.h"
51#include "servconf.h" 52#include "servconf.h"
52#include "compat.h" 53#include "compat.h"
53#include "key.h" 54#include "key.h"
@@ -61,7 +62,6 @@
61#include "ssh-gss.h" 62#include "ssh-gss.h"
62#endif 63#endif
63#include "monitor_wrap.h" 64#include "monitor_wrap.h"
64#include "misc.h"
65#include "authfile.h" 65#include "authfile.h"
66#include "match.h" 66#include "match.h"
67 67
@@ -230,7 +230,7 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
230} 230}
231 231
232static int 232static int
233match_principals_option(const char *principal_list, struct KeyCert *cert) 233match_principals_option(const char *principal_list, struct sshkey_cert *cert)
234{ 234{
235 char *result; 235 char *result;
236 u_int i; 236 u_int i;
@@ -250,7 +250,7 @@ match_principals_option(const char *principal_list, struct KeyCert *cert)
250} 250}
251 251
252static int 252static int
253match_principals_file(char *file, struct passwd *pw, struct KeyCert *cert) 253match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
254{ 254{
255 FILE *f; 255 FILE *f;
256 char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; 256 char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
diff --git a/auth2.c b/auth2.c
index a5490c009..d9b440ae3 100644
--- a/auth2.c
+++ b/auth2.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2.c,v 1.130 2014/01/29 06:18:35 djm Exp $ */ 1/* $OpenBSD: auth2.c,v 1.132 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -41,6 +41,7 @@
41#include "packet.h" 41#include "packet.h"
42#include "log.h" 42#include "log.h"
43#include "buffer.h" 43#include "buffer.h"
44#include "misc.h"
44#include "servconf.h" 45#include "servconf.h"
45#include "compat.h" 46#include "compat.h"
46#include "key.h" 47#include "key.h"
@@ -362,7 +363,7 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
362#ifdef SSH_AUDIT_EVENTS 363#ifdef SSH_AUDIT_EVENTS
363 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); 364 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
364#endif 365#endif
365 packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 366 auth_maxtries_exceeded(authctxt);
366 } 367 }
367 methods = authmethods_get(authctxt); 368 methods = authmethods_get(authctxt);
368 debug3("%s: failure partial=%d next methods=\"%s\"", __func__, 369 debug3("%s: failure partial=%d next methods=\"%s\"", __func__,
diff --git a/authfd.c b/authfd.c
index cea3f97b4..2d5a8dd5b 100644
--- a/authfd.c
+++ b/authfd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: authfd.c,v 1.92 2014/01/31 16:39:19 tedu Exp $ */ 1/* $OpenBSD: authfd.c,v 1.93 2014/04/29 18:01:49 markus Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -41,9 +41,6 @@
41#include <sys/un.h> 41#include <sys/un.h>
42#include <sys/socket.h> 42#include <sys/socket.h>
43 43
44#include <openssl/evp.h>
45#include <openssl/crypto.h>
46
47#include <fcntl.h> 44#include <fcntl.h>
48#include <stdlib.h> 45#include <stdlib.h>
49#include <signal.h> 46#include <signal.h>
@@ -313,8 +310,10 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi
313Key * 310Key *
314ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version) 311ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
315{ 312{
313#ifdef WITH_SSH1
316 int keybits; 314 int keybits;
317 u_int bits; 315 u_int bits;
316#endif
318 u_char *blob; 317 u_char *blob;
319 u_int blen; 318 u_int blen;
320 Key *key = NULL; 319 Key *key = NULL;
@@ -328,6 +327,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
328 * error if the packet is too short or contains corrupt data. 327 * error if the packet is too short or contains corrupt data.
329 */ 328 */
330 switch (version) { 329 switch (version) {
330#ifdef WITH_SSH1
331 case 1: 331 case 1:
332 key = key_new(KEY_RSA1); 332 key = key_new(KEY_RSA1);
333 bits = buffer_get_int(&auth->identities); 333 bits = buffer_get_int(&auth->identities);
@@ -339,6 +339,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
339 logit("Warning: identity keysize mismatch: actual %d, announced %u", 339 logit("Warning: identity keysize mismatch: actual %d, announced %u",
340 BN_num_bits(key->rsa->n), bits); 340 BN_num_bits(key->rsa->n), bits);
341 break; 341 break;
342#endif
342 case 2: 343 case 2:
343 blob = buffer_get_string(&auth->identities, &blen); 344 blob = buffer_get_string(&auth->identities, &blen);
344 *comment = buffer_get_string(&auth->identities, NULL); 345 *comment = buffer_get_string(&auth->identities, NULL);
@@ -361,6 +362,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
361 * supported) and 1 corresponding to protocol version 1.1. 362 * supported) and 1 corresponding to protocol version 1.1.
362 */ 363 */
363 364
365#ifdef WITH_SSH1
364int 366int
365ssh_decrypt_challenge(AuthenticationConnection *auth, 367ssh_decrypt_challenge(AuthenticationConnection *auth,
366 Key* key, BIGNUM *challenge, 368 Key* key, BIGNUM *challenge,
@@ -410,6 +412,7 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
410 buffer_free(&buffer); 412 buffer_free(&buffer);
411 return success; 413 return success;
412} 414}
415#endif
413 416
414/* ask agent to sign data, returns -1 on error, 0 on success */ 417/* ask agent to sign data, returns -1 on error, 0 on success */
415int 418int
@@ -457,6 +460,7 @@ ssh_agent_sign(AuthenticationConnection *auth,
457 460
458/* Encode key for a message to the agent. */ 461/* Encode key for a message to the agent. */
459 462
463#ifdef WITH_SSH1
460static void 464static void
461ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment) 465ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
462{ 466{
@@ -470,6 +474,7 @@ ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
470 buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */ 474 buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */
471 buffer_put_cstring(b, comment); 475 buffer_put_cstring(b, comment);
472} 476}
477#endif
473 478
474static void 479static void
475ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) 480ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
@@ -493,6 +498,7 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,
493 buffer_init(&msg); 498 buffer_init(&msg);
494 499
495 switch (key->type) { 500 switch (key->type) {
501#ifdef WITH_SSH1
496 case KEY_RSA1: 502 case KEY_RSA1:
497 type = constrained ? 503 type = constrained ?
498 SSH_AGENTC_ADD_RSA_ID_CONSTRAINED : 504 SSH_AGENTC_ADD_RSA_ID_CONSTRAINED :
@@ -500,6 +506,8 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,
500 buffer_put_char(&msg, type); 506 buffer_put_char(&msg, type);
501 ssh_encode_identity_rsa1(&msg, key->rsa, comment); 507 ssh_encode_identity_rsa1(&msg, key->rsa, comment);
502 break; 508 break;
509#endif
510#ifdef WITH_OPENSSL
503 case KEY_RSA: 511 case KEY_RSA:
504 case KEY_RSA_CERT: 512 case KEY_RSA_CERT:
505 case KEY_RSA_CERT_V00: 513 case KEY_RSA_CERT_V00:
@@ -508,6 +516,7 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,
508 case KEY_DSA_CERT_V00: 516 case KEY_DSA_CERT_V00:
509 case KEY_ECDSA: 517 case KEY_ECDSA:
510 case KEY_ECDSA_CERT: 518 case KEY_ECDSA_CERT:
519#endif
511 case KEY_ED25519: 520 case KEY_ED25519:
512 case KEY_ED25519_CERT: 521 case KEY_ED25519_CERT:
513 type = constrained ? 522 type = constrained ?
@@ -552,12 +561,15 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key)
552 561
553 buffer_init(&msg); 562 buffer_init(&msg);
554 563
564#ifdef WITH_SSH1
555 if (key->type == KEY_RSA1) { 565 if (key->type == KEY_RSA1) {
556 buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY); 566 buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
557 buffer_put_int(&msg, BN_num_bits(key->rsa->n)); 567 buffer_put_int(&msg, BN_num_bits(key->rsa->n));
558 buffer_put_bignum(&msg, key->rsa->e); 568 buffer_put_bignum(&msg, key->rsa->e);
559 buffer_put_bignum(&msg, key->rsa->n); 569 buffer_put_bignum(&msg, key->rsa->n);
560 } else if (key->type != KEY_UNSPEC) { 570 } else
571#endif
572 if (key->type != KEY_UNSPEC) {
561 key_to_blob(key, &blob, &blen); 573 key_to_blob(key, &blob, &blen);
562 buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); 574 buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
563 buffer_put_string(&msg, blob, blen); 575 buffer_put_string(&msg, blob, blen);
diff --git a/authfile.c b/authfile.c
index d7eaa9dec..e93d86738 100644
--- a/authfile.c
+++ b/authfile.c
@@ -1,18 +1,5 @@
1/* $OpenBSD: authfile.c,v 1.103 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: authfile.c,v 1.107 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved
6 * This file contains functions for reading and writing identity files, and
7 * for reading the passphrase from the user.
8 *
9 * As far as I am concerned, the code I have written for this software
10 * can be used freely for any purpose. Any derived versions of this
11 * software must be clearly marked as such, and if the derived work is
12 * incompatible with the protocol description in the RFC file, it must be
13 * called by a name other than "ssh" or "Secure Shell".
14 *
15 *
16 * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
17 * 4 *
18 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
@@ -43,30 +30,15 @@
43#include <sys/param.h> 30#include <sys/param.h>
44#include <sys/uio.h> 31#include <sys/uio.h>
45 32
46#include <openssl/err.h>
47#include <openssl/evp.h>
48#include <openssl/pem.h>
49
50/* compatibility with old or broken OpenSSL versions */
51#include "openbsd-compat/openssl-compat.h"
52
53#include "crypto_api.h"
54
55#include <errno.h> 33#include <errno.h>
56#include <fcntl.h> 34#include <fcntl.h>
57#include <stdarg.h>
58#include <stdio.h> 35#include <stdio.h>
36#include <stdarg.h>
59#include <stdlib.h> 37#include <stdlib.h>
60#include <string.h> 38#include <string.h>
61#include <unistd.h> 39#include <unistd.h>
62 40
63#ifdef HAVE_UTIL_H
64#include <util.h>
65#endif
66
67#include "xmalloc.h"
68#include "cipher.h" 41#include "cipher.h"
69#include "buffer.h"
70#include "key.h" 42#include "key.h"
71#include "ssh.h" 43#include "ssh.h"
72#include "log.h" 44#include "log.h"
@@ -74,903 +46,159 @@
74#include "rsa.h" 46#include "rsa.h"
75#include "misc.h" 47#include "misc.h"
76#include "atomicio.h" 48#include "atomicio.h"
77#include "uuencode.h" 49#include "sshbuf.h"
78 50#include "ssherr.h"
79/* openssh private key file format */
80#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n"
81#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n"
82#define KDFNAME "bcrypt"
83#define AUTH_MAGIC "openssh-key-v1"
84#define SALT_LEN 16
85#define DEFAULT_CIPHERNAME "aes256-cbc"
86#define DEFAULT_ROUNDS 16
87 51
88#define MAX_KEY_FILE_SIZE (1024 * 1024) 52#define MAX_KEY_FILE_SIZE (1024 * 1024)
89 53
90/* Version identification string for SSH v1 identity files. */
91static const char authfile_id_string[] =
92 "SSH PRIVATE KEY FILE FORMAT 1.1\n";
93
94static int
95key_private_to_blob2(Key *prv, Buffer *blob, const char *passphrase,
96 const char *comment, const char *ciphername, int rounds)
97{
98 u_char *key, *cp, salt[SALT_LEN];
99 size_t keylen, ivlen, blocksize, authlen;
100 u_int len, check;
101 int i, n;
102 const Cipher *c;
103 Buffer encoded, b, kdf;
104 CipherContext ctx;
105 const char *kdfname = KDFNAME;
106
107 if (rounds <= 0)
108 rounds = DEFAULT_ROUNDS;
109 if (passphrase == NULL || !strlen(passphrase)) {
110 ciphername = "none";
111 kdfname = "none";
112 } else if (ciphername == NULL)
113 ciphername = DEFAULT_CIPHERNAME;
114 else if (cipher_number(ciphername) != SSH_CIPHER_SSH2)
115 fatal("invalid cipher");
116
117 if ((c = cipher_by_name(ciphername)) == NULL)
118 fatal("unknown cipher name");
119 buffer_init(&kdf);
120 blocksize = cipher_blocksize(c);
121 keylen = cipher_keylen(c);
122 ivlen = cipher_ivlen(c);
123 authlen = cipher_authlen(c);
124 key = xcalloc(1, keylen + ivlen);
125 if (strcmp(kdfname, "none") != 0) {
126 arc4random_buf(salt, SALT_LEN);
127 if (bcrypt_pbkdf(passphrase, strlen(passphrase),
128 salt, SALT_LEN, key, keylen + ivlen, rounds) < 0)
129 fatal("bcrypt_pbkdf failed");
130 buffer_put_string(&kdf, salt, SALT_LEN);
131 buffer_put_int(&kdf, rounds);
132 }
133 cipher_init(&ctx, c, key, keylen, key + keylen , ivlen, 1);
134 explicit_bzero(key, keylen + ivlen);
135 free(key);
136
137 buffer_init(&encoded);
138 buffer_append(&encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC));
139 buffer_put_cstring(&encoded, ciphername);
140 buffer_put_cstring(&encoded, kdfname);
141 buffer_put_string(&encoded, buffer_ptr(&kdf), buffer_len(&kdf));
142 buffer_put_int(&encoded, 1); /* number of keys */
143 key_to_blob(prv, &cp, &len); /* public key */
144 buffer_put_string(&encoded, cp, len);
145
146 explicit_bzero(cp, len);
147 free(cp);
148
149 buffer_free(&kdf);
150
151 /* set up the buffer that will be encrypted */
152 buffer_init(&b);
153
154 /* Random check bytes */
155 check = arc4random();
156 buffer_put_int(&b, check);
157 buffer_put_int(&b, check);
158
159 /* append private key and comment*/
160 key_private_serialize(prv, &b);
161 buffer_put_cstring(&b, comment);
162
163 /* padding */
164 i = 0;
165 while (buffer_len(&b) % blocksize)
166 buffer_put_char(&b, ++i & 0xff);
167
168 /* length */
169 buffer_put_int(&encoded, buffer_len(&b));
170
171 /* encrypt */
172 cp = buffer_append_space(&encoded, buffer_len(&b) + authlen);
173 if (cipher_crypt(&ctx, 0, cp, buffer_ptr(&b), buffer_len(&b), 0,
174 authlen) != 0)
175 fatal("%s: cipher_crypt failed", __func__);
176 buffer_free(&b);
177 cipher_cleanup(&ctx);
178
179 /* uuencode */
180 len = 2 * buffer_len(&encoded);
181 cp = xmalloc(len);
182 n = uuencode(buffer_ptr(&encoded), buffer_len(&encoded),
183 (char *)cp, len);
184 if (n < 0)
185 fatal("%s: uuencode", __func__);
186
187 buffer_clear(blob);
188 buffer_append(blob, MARK_BEGIN, sizeof(MARK_BEGIN) - 1);
189 for (i = 0; i < n; i++) {
190 buffer_put_char(blob, cp[i]);
191 if (i % 70 == 69)
192 buffer_put_char(blob, '\n');
193 }
194 if (i % 70 != 69)
195 buffer_put_char(blob, '\n');
196 buffer_append(blob, MARK_END, sizeof(MARK_END) - 1);
197 free(cp);
198
199 return buffer_len(blob);
200}
201
202static Key *
203key_parse_private2(Buffer *blob, int type, const char *passphrase,
204 char **commentp)
205{
206 u_char *key = NULL, *cp, *salt = NULL, pad, last;
207 char *comment = NULL, *ciphername = NULL, *kdfname = NULL, *kdfp;
208 u_int keylen = 0, ivlen, blocksize, slen, klen, len, rounds, nkeys;
209 u_int check1, check2, m1len, m2len;
210 size_t authlen;
211 const Cipher *c;
212 Buffer b, encoded, copy, kdf;
213 CipherContext ctx;
214 Key *k = NULL;
215 int dlen, ret, i;
216
217 buffer_init(&b);
218 buffer_init(&kdf);
219 buffer_init(&encoded);
220 buffer_init(&copy);
221
222 /* uudecode */
223 m1len = sizeof(MARK_BEGIN) - 1;
224 m2len = sizeof(MARK_END) - 1;
225 cp = buffer_ptr(blob);
226 len = buffer_len(blob);
227 if (len < m1len || memcmp(cp, MARK_BEGIN, m1len)) {
228 debug("%s: missing begin marker", __func__);
229 goto out;
230 }
231 cp += m1len;
232 len -= m1len;
233 while (len) {
234 if (*cp != '\n' && *cp != '\r')
235 buffer_put_char(&encoded, *cp);
236 last = *cp;
237 len--;
238 cp++;
239 if (last == '\n') {
240 if (len >= m2len && !memcmp(cp, MARK_END, m2len)) {
241 buffer_put_char(&encoded, '\0');
242 break;
243 }
244 }
245 }
246 if (!len) {
247 debug("%s: no end marker", __func__);
248 goto out;
249 }
250 len = buffer_len(&encoded);
251 if ((cp = buffer_append_space(&copy, len)) == NULL) {
252 error("%s: buffer_append_space", __func__);
253 goto out;
254 }
255 if ((dlen = uudecode(buffer_ptr(&encoded), cp, len)) < 0) {
256 error("%s: uudecode failed", __func__);
257 goto out;
258 }
259 if ((u_int)dlen > len) {
260 error("%s: crazy uudecode length %d > %u", __func__, dlen, len);
261 goto out;
262 }
263 buffer_consume_end(&copy, len - dlen);
264 if (buffer_len(&copy) < sizeof(AUTH_MAGIC) ||
265 memcmp(buffer_ptr(&copy), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
266 error("%s: bad magic", __func__);
267 goto out;
268 }
269 buffer_consume(&copy, sizeof(AUTH_MAGIC));
270
271 ciphername = buffer_get_cstring_ret(&copy, NULL);
272 if (ciphername == NULL ||
273 (c = cipher_by_name(ciphername)) == NULL) {
274 error("%s: unknown cipher name", __func__);
275 goto out;
276 }
277 if ((passphrase == NULL || !strlen(passphrase)) &&
278 strcmp(ciphername, "none") != 0) {
279 /* passphrase required */
280 goto out;
281 }
282 kdfname = buffer_get_cstring_ret(&copy, NULL);
283 if (kdfname == NULL ||
284 (!strcmp(kdfname, "none") && !strcmp(kdfname, "bcrypt"))) {
285 error("%s: unknown kdf name", __func__);
286 goto out;
287 }
288 if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) {
289 error("%s: cipher %s requires kdf", __func__, ciphername);
290 goto out;
291 }
292 /* kdf options */
293 kdfp = buffer_get_string_ptr_ret(&copy, &klen);
294 if (kdfp == NULL) {
295 error("%s: kdf options not set", __func__);
296 goto out;
297 }
298 if (klen > 0) {
299 if ((cp = buffer_append_space(&kdf, klen)) == NULL) {
300 error("%s: kdf alloc failed", __func__);
301 goto out;
302 }
303 memcpy(cp, kdfp, klen);
304 }
305 /* number of keys */
306 if (buffer_get_int_ret(&nkeys, &copy) < 0) {
307 error("%s: key counter missing", __func__);
308 goto out;
309 }
310 if (nkeys != 1) {
311 error("%s: only one key supported", __func__);
312 goto out;
313 }
314 /* pubkey */
315 if ((cp = buffer_get_string_ret(&copy, &len)) == NULL) {
316 error("%s: pubkey not found", __func__);
317 goto out;
318 }
319 free(cp); /* XXX check pubkey against decrypted private key */
320
321 /* size of encrypted key blob */
322 len = buffer_get_int(&copy);
323 blocksize = cipher_blocksize(c);
324 authlen = cipher_authlen(c);
325 if (len < blocksize) {
326 error("%s: encrypted data too small", __func__);
327 goto out;
328 }
329 if (len % blocksize) {
330 error("%s: length not multiple of blocksize", __func__);
331 goto out;
332 }
333
334 /* setup key */
335 keylen = cipher_keylen(c);
336 ivlen = cipher_ivlen(c);
337 key = xcalloc(1, keylen + ivlen);
338 if (!strcmp(kdfname, "bcrypt")) {
339 if ((salt = buffer_get_string_ret(&kdf, &slen)) == NULL) {
340 error("%s: salt not set", __func__);
341 goto out;
342 }
343 if (buffer_get_int_ret(&rounds, &kdf) < 0) {
344 error("%s: rounds not set", __func__);
345 goto out;
346 }
347 if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
348 key, keylen + ivlen, rounds) < 0) {
349 error("%s: bcrypt_pbkdf failed", __func__);
350 goto out;
351 }
352 }
353
354 cp = buffer_append_space(&b, len);
355 cipher_init(&ctx, c, key, keylen, key + keylen, ivlen, 0);
356 ret = cipher_crypt(&ctx, 0, cp, buffer_ptr(&copy), len, 0, authlen);
357 cipher_cleanup(&ctx);
358 buffer_consume(&copy, len);
359
360 /* fail silently on decryption errors */
361 if (ret != 0) {
362 debug("%s: decrypt failed", __func__);
363 goto out;
364 }
365
366 if (buffer_len(&copy) != 0) {
367 error("%s: key blob has trailing data (len = %u)", __func__,
368 buffer_len(&copy));
369 goto out;
370 }
371
372 /* check bytes */
373 if (buffer_get_int_ret(&check1, &b) < 0 ||
374 buffer_get_int_ret(&check2, &b) < 0) {
375 error("check bytes missing");
376 goto out;
377 }
378 if (check1 != check2) {
379 debug("%s: decrypt failed: 0x%08x != 0x%08x", __func__,
380 check1, check2);
381 goto out;
382 }
383
384 k = key_private_deserialize(&b);
385
386 /* comment */
387 comment = buffer_get_cstring_ret(&b, NULL);
388
389 i = 0;
390 while (buffer_len(&b)) {
391 if (buffer_get_char_ret(&pad, &b) == -1 ||
392 pad != (++i & 0xff)) {
393 error("%s: bad padding", __func__);
394 key_free(k);
395 k = NULL;
396 goto out;
397 }
398 }
399
400 if (k && commentp) {
401 *commentp = comment;
402 comment = NULL;
403 }
404
405 /* XXX decode pubkey and check against private */
406 out:
407 free(ciphername);
408 free(kdfname);
409 free(salt);
410 free(comment);
411 if (key)
412 explicit_bzero(key, keylen + ivlen);
413 free(key);
414 buffer_free(&encoded);
415 buffer_free(&copy);
416 buffer_free(&kdf);
417 buffer_free(&b);
418 return k;
419}
420
421/*
422 * Serialises the authentication (private) key to a blob, encrypting it with
423 * passphrase. The identification of the blob (lowest 64 bits of n) will
424 * precede the key to provide identification of the key without needing a
425 * passphrase.
426 */
427static int
428key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase,
429 const char *comment)
430{
431 Buffer buffer, encrypted;
432 u_char buf[100], *cp;
433 int i, cipher_num;
434 CipherContext ciphercontext;
435 const Cipher *cipher;
436 u_int32_t rnd;
437
438 /*
439 * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
440 * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
441 */
442 cipher_num = (strcmp(passphrase, "") == 0) ?
443 SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
444 if ((cipher = cipher_by_number(cipher_num)) == NULL)
445 fatal("save_private_key_rsa: bad cipher");
446
447 /* This buffer is used to built the secret part of the private key. */
448 buffer_init(&buffer);
449
450 /* Put checkbytes for checking passphrase validity. */
451 rnd = arc4random();
452 buf[0] = rnd & 0xff;
453 buf[1] = (rnd >> 8) & 0xff;
454 buf[2] = buf[0];
455 buf[3] = buf[1];
456 buffer_append(&buffer, buf, 4);
457
458 /*
459 * Store the private key (n and e will not be stored because they
460 * will be stored in plain text, and storing them also in encrypted
461 * format would just give known plaintext).
462 */
463 buffer_put_bignum(&buffer, key->rsa->d);
464 buffer_put_bignum(&buffer, key->rsa->iqmp);
465 buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */
466 buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */
467
468 /* Pad the part to be encrypted until its size is a multiple of 8. */
469 while (buffer_len(&buffer) % 8 != 0)
470 buffer_put_char(&buffer, 0);
471
472 /* This buffer will be used to contain the data in the file. */
473 buffer_init(&encrypted);
474
475 /* First store keyfile id string. */
476 for (i = 0; authfile_id_string[i]; i++)
477 buffer_put_char(&encrypted, authfile_id_string[i]);
478 buffer_put_char(&encrypted, 0);
479
480 /* Store cipher type. */
481 buffer_put_char(&encrypted, cipher_num);
482 buffer_put_int(&encrypted, 0); /* For future extension */
483
484 /* Store public key. This will be in plain text. */
485 buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
486 buffer_put_bignum(&encrypted, key->rsa->n);
487 buffer_put_bignum(&encrypted, key->rsa->e);
488 buffer_put_cstring(&encrypted, comment);
489
490 /* Allocate space for the private part of the key in the buffer. */
491 cp = buffer_append_space(&encrypted, buffer_len(&buffer));
492
493 cipher_set_key_string(&ciphercontext, cipher, passphrase,
494 CIPHER_ENCRYPT);
495 if (cipher_crypt(&ciphercontext, 0, cp,
496 buffer_ptr(&buffer), buffer_len(&buffer), 0, 0) != 0)
497 fatal("%s: cipher_crypt failed", __func__);
498 cipher_cleanup(&ciphercontext);
499 explicit_bzero(&ciphercontext, sizeof(ciphercontext));
500
501 /* Destroy temporary data. */
502 explicit_bzero(buf, sizeof(buf));
503 buffer_free(&buffer);
504
505 buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted));
506 buffer_free(&encrypted);
507
508 return 1;
509}
510
511/* convert SSH v2 key in OpenSSL PEM format */
512static int
513key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase,
514 const char *comment)
515{
516 int success = 0;
517 int blen, len = strlen(_passphrase);
518 u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
519#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
520 const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
521#else
522 const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
523#endif
524 const u_char *bptr;
525 BIO *bio;
526
527 if (len > 0 && len <= 4) {
528 error("passphrase too short: have %d bytes, need > 4", len);
529 return 0;
530 }
531 if ((bio = BIO_new(BIO_s_mem())) == NULL) {
532 error("%s: BIO_new failed", __func__);
533 return 0;
534 }
535 switch (key->type) {
536 case KEY_DSA:
537 success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
538 cipher, passphrase, len, NULL, NULL);
539 break;
540#ifdef OPENSSL_HAS_ECC
541 case KEY_ECDSA:
542 success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
543 cipher, passphrase, len, NULL, NULL);
544 break;
545#endif
546 case KEY_RSA:
547 success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
548 cipher, passphrase, len, NULL, NULL);
549 break;
550 }
551 if (success) {
552 if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0)
553 success = 0;
554 else
555 buffer_append(blob, bptr, blen);
556 }
557 BIO_free(bio);
558 return success;
559}
560
561/* Save a key blob to a file */ 54/* Save a key blob to a file */
562static int 55static int
563key_save_private_blob(Buffer *keybuf, const char *filename) 56sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
564{ 57{
565 int fd; 58 int fd, oerrno;
566 59
567 if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { 60 if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
568 error("open %s failed: %s.", filename, strerror(errno)); 61 return SSH_ERR_SYSTEM_ERROR;
569 return 0; 62 if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf),
570 } 63 sshbuf_len(keybuf)) != sshbuf_len(keybuf)) {
571 if (atomicio(vwrite, fd, buffer_ptr(keybuf), 64 oerrno = errno;
572 buffer_len(keybuf)) != buffer_len(keybuf)) {
573 error("write to key file %s failed: %s", filename,
574 strerror(errno));
575 close(fd); 65 close(fd);
576 unlink(filename); 66 unlink(filename);
577 return 0; 67 errno = oerrno;
68 return SSH_ERR_SYSTEM_ERROR;
578 } 69 }
579 close(fd); 70 close(fd);
580 return 1; 71 return 0;
581}
582
583/* Serialise "key" to buffer "blob" */
584static int
585key_private_to_blob(Key *key, Buffer *blob, const char *passphrase,
586 const char *comment, int force_new_format, const char *new_format_cipher,
587 int new_format_rounds)
588{
589 switch (key->type) {
590 case KEY_RSA1:
591 return key_private_rsa1_to_blob(key, blob, passphrase, comment);
592 case KEY_DSA:
593 case KEY_ECDSA:
594 case KEY_RSA:
595 if (force_new_format) {
596 return key_private_to_blob2(key, blob, passphrase,
597 comment, new_format_cipher, new_format_rounds);
598 }
599 return key_private_pem_to_blob(key, blob, passphrase, comment);
600 case KEY_ED25519:
601 return key_private_to_blob2(key, blob, passphrase,
602 comment, new_format_cipher, new_format_rounds);
603 default:
604 error("%s: cannot save key type %d", __func__, key->type);
605 return 0;
606 }
607} 72}
608 73
609int 74int
610key_save_private(Key *key, const char *filename, const char *passphrase, 75sshkey_save_private(struct sshkey *key, const char *filename,
611 const char *comment, int force_new_format, const char *new_format_cipher, 76 const char *passphrase, const char *comment,
612 int new_format_rounds) 77 int force_new_format, const char *new_format_cipher, int new_format_rounds)
613{ 78{
614 Buffer keyblob; 79 struct sshbuf *keyblob = NULL;
615 int success = 0; 80 int r;
616 81
617 buffer_init(&keyblob); 82 if ((keyblob = sshbuf_new()) == NULL)
618 if (!key_private_to_blob(key, &keyblob, passphrase, comment, 83 return SSH_ERR_ALLOC_FAIL;
619 force_new_format, new_format_cipher, new_format_rounds)) 84 if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
85 force_new_format, new_format_cipher, new_format_rounds)) != 0)
620 goto out; 86 goto out;
621 if (!key_save_private_blob(&keyblob, filename)) 87 if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
622 goto out; 88 goto out;
623 success = 1; 89 r = 0;
624 out: 90 out:
625 buffer_free(&keyblob); 91 sshbuf_free(keyblob);
626 return success; 92 return r;
627}
628
629/*
630 * Parse the public, unencrypted portion of a RSA1 key.
631 */
632static Key *
633key_parse_public_rsa1(Buffer *blob, char **commentp)
634{
635 Key *pub;
636 Buffer copy;
637
638 /* Check that it is at least big enough to contain the ID string. */
639 if (buffer_len(blob) < sizeof(authfile_id_string)) {
640 debug3("Truncated RSA1 identifier");
641 return NULL;
642 }
643
644 /*
645 * Make sure it begins with the id string. Consume the id string
646 * from the buffer.
647 */
648 if (memcmp(buffer_ptr(blob), authfile_id_string,
649 sizeof(authfile_id_string)) != 0) {
650 debug3("Incorrect RSA1 identifier");
651 return NULL;
652 }
653 buffer_init(&copy);
654 buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
655 buffer_consume(&copy, sizeof(authfile_id_string));
656
657 /* Skip cipher type and reserved data. */
658 (void) buffer_get_char(&copy); /* cipher type */
659 (void) buffer_get_int(&copy); /* reserved */
660
661 /* Read the public key from the buffer. */
662 (void) buffer_get_int(&copy);
663 pub = key_new(KEY_RSA1);
664 buffer_get_bignum(&copy, pub->rsa->n);
665 buffer_get_bignum(&copy, pub->rsa->e);
666 if (commentp)
667 *commentp = buffer_get_string(&copy, NULL);
668 /* The encrypted private part is not parsed by this function. */
669 buffer_free(&copy);
670
671 return pub;
672} 93}
673 94
674/* Load a key from a fd into a buffer */ 95/* Load a key from a fd into a buffer */
675int 96int
676key_load_file(int fd, const char *filename, Buffer *blob) 97sshkey_load_file(int fd, const char *filename, struct sshbuf *blob)
677{ 98{
678 u_char buf[1024]; 99 u_char buf[1024];
679 size_t len; 100 size_t len;
680 struct stat st; 101 struct stat st;
102 int r;
681 103
682 if (fstat(fd, &st) < 0) { 104 if (fstat(fd, &st) < 0)
683 error("%s: fstat of key file %.200s%sfailed: %.100s", __func__, 105 return SSH_ERR_SYSTEM_ERROR;
684 filename == NULL ? "" : filename,
685 filename == NULL ? "" : " ",
686 strerror(errno));
687 return 0;
688 }
689 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 106 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
690 st.st_size > MAX_KEY_FILE_SIZE) { 107 st.st_size > MAX_KEY_FILE_SIZE)
691 toobig: 108 return SSH_ERR_INVALID_FORMAT;
692 error("%s: key file %.200s%stoo large", __func__,
693 filename == NULL ? "" : filename,
694 filename == NULL ? "" : " ");
695 return 0;
696 }
697 buffer_clear(blob);
698 for (;;) { 109 for (;;) {
699 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { 110 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
700 if (errno == EPIPE) 111 if (errno == EPIPE)
701 break; 112 break;
702 debug("%s: read from key file %.200s%sfailed: %.100s", 113 r = SSH_ERR_SYSTEM_ERROR;
703 __func__, filename == NULL ? "" : filename, 114 goto out;
704 filename == NULL ? "" : " ", strerror(errno));
705 buffer_clear(blob);
706 explicit_bzero(buf, sizeof(buf));
707 return 0;
708 } 115 }
709 buffer_append(blob, buf, len); 116 if ((r = sshbuf_put(blob, buf, len)) != 0)
710 if (buffer_len(blob) > MAX_KEY_FILE_SIZE) { 117 goto out;
711 buffer_clear(blob); 118 if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
712 explicit_bzero(buf, sizeof(buf)); 119 r = SSH_ERR_INVALID_FORMAT;
713 goto toobig; 120 goto out;
714 } 121 }
715 } 122 }
716 explicit_bzero(buf, sizeof(buf));
717 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 123 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
718 st.st_size != buffer_len(blob)) { 124 st.st_size != (off_t)sshbuf_len(blob)) {
719 debug("%s: key file %.200s%schanged size while reading", 125 r = SSH_ERR_FILE_CHANGED;
720 __func__, filename == NULL ? "" : filename, 126 goto out;
721 filename == NULL ? "" : " ");
722 buffer_clear(blob);
723 return 0;
724 } 127 }
128 r = 0;
725 129
726 return 1; 130 out:
131 explicit_bzero(buf, sizeof(buf));
132 if (r != 0)
133 sshbuf_reset(blob);
134 return r;
727} 135}
728 136
137#ifdef WITH_SSH1
729/* 138/*
730 * Loads the public part of the ssh v1 key file. Returns NULL if an error was 139 * Loads the public part of the ssh v1 key file. Returns NULL if an error was
731 * encountered (the file does not exist or is not readable), and the key 140 * encountered (the file does not exist or is not readable), and the key
732 * otherwise. 141 * otherwise.
733 */ 142 */
734static Key * 143static int
735key_load_public_rsa1(int fd, const char *filename, char **commentp) 144sshkey_load_public_rsa1(int fd, const char *filename,
145 struct sshkey **keyp, char **commentp)
736{ 146{
737 Buffer buffer; 147 struct sshbuf *b = NULL;
738 Key *pub; 148 int r;
739
740 buffer_init(&buffer);
741 if (!key_load_file(fd, filename, &buffer)) {
742 buffer_free(&buffer);
743 return NULL;
744 }
745 149
746 pub = key_parse_public_rsa1(&buffer, commentp); 150 *keyp = NULL;
747 if (pub == NULL) 151 if (commentp != NULL)
748 debug3("Could not load \"%s\" as a RSA1 public key", filename); 152 *commentp = NULL;
749 buffer_free(&buffer);
750 return pub;
751}
752
753/* load public key from private-key file, works only for SSH v1 */
754Key *
755key_load_public_type(int type, const char *filename, char **commentp)
756{
757 Key *pub;
758 int fd;
759 153
760 if (type == KEY_RSA1) { 154 if ((b = sshbuf_new()) == NULL)
761 fd = open(filename, O_RDONLY); 155 return SSH_ERR_ALLOC_FAIL;
762 if (fd < 0) 156 if ((r = sshkey_load_file(fd, filename, b)) != 0)
763 return NULL; 157 goto out;
764 pub = key_load_public_rsa1(fd, filename, commentp); 158 if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
765 close(fd); 159 goto out;
766 return pub; 160 r = 0;
767 } 161 out:
768 return NULL; 162 sshbuf_free(b);
163 return r;
769} 164}
165#endif /* WITH_SSH1 */
770 166
771static Key * 167#ifdef WITH_OPENSSL
772key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) 168/* XXX Deprecate? */
169int
170sshkey_load_private_pem(int fd, int type, const char *passphrase,
171 struct sshkey **keyp, char **commentp)
773{ 172{
774 int check1, check2, cipher_type; 173 struct sshbuf *buffer = NULL;
775 Buffer decrypted; 174 int r;
776 u_char *cp;
777 CipherContext ciphercontext;
778 const Cipher *cipher;
779 Key *prv = NULL;
780 Buffer copy;
781
782 /* Check that it is at least big enough to contain the ID string. */
783 if (buffer_len(blob) < sizeof(authfile_id_string)) {
784 debug3("Truncated RSA1 identifier");
785 return NULL;
786 }
787
788 /*
789 * Make sure it begins with the id string. Consume the id string
790 * from the buffer.
791 */
792 if (memcmp(buffer_ptr(blob), authfile_id_string,
793 sizeof(authfile_id_string)) != 0) {
794 debug3("Incorrect RSA1 identifier");
795 return NULL;
796 }
797 buffer_init(&copy);
798 buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
799 buffer_consume(&copy, sizeof(authfile_id_string));
800
801 /* Read cipher type. */
802 cipher_type = buffer_get_char(&copy);
803 (void) buffer_get_int(&copy); /* Reserved data. */
804
805 /* Read the public key from the buffer. */
806 (void) buffer_get_int(&copy);
807 prv = key_new_private(KEY_RSA1);
808
809 buffer_get_bignum(&copy, prv->rsa->n);
810 buffer_get_bignum(&copy, prv->rsa->e);
811 if (commentp)
812 *commentp = buffer_get_string(&copy, NULL);
813 else
814 (void)buffer_get_string_ptr(&copy, NULL);
815 175
816 /* Check that it is a supported cipher. */ 176 *keyp = NULL;
817 cipher = cipher_by_number(cipher_type);
818 if (cipher == NULL) {
819 debug("Unsupported RSA1 cipher %d", cipher_type);
820 buffer_free(&copy);
821 goto fail;
822 }
823 /* Initialize space for decrypted data. */
824 buffer_init(&decrypted);
825 cp = buffer_append_space(&decrypted, buffer_len(&copy));
826
827 /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
828 cipher_set_key_string(&ciphercontext, cipher, passphrase,
829 CIPHER_DECRYPT);
830 if (cipher_crypt(&ciphercontext, 0, cp,
831 buffer_ptr(&copy), buffer_len(&copy), 0, 0) != 0)
832 fatal("%s: cipher_crypt failed", __func__);
833 cipher_cleanup(&ciphercontext);
834 explicit_bzero(&ciphercontext, sizeof(ciphercontext));
835 buffer_free(&copy);
836
837 check1 = buffer_get_char(&decrypted);
838 check2 = buffer_get_char(&decrypted);
839 if (check1 != buffer_get_char(&decrypted) ||
840 check2 != buffer_get_char(&decrypted)) {
841 if (strcmp(passphrase, "") != 0)
842 debug("Bad passphrase supplied for RSA1 key");
843 /* Bad passphrase. */
844 buffer_free(&decrypted);
845 goto fail;
846 }
847 /* Read the rest of the private key. */
848 buffer_get_bignum(&decrypted, prv->rsa->d);
849 buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */
850 /* in SSL and SSH v1 p and q are exchanged */
851 buffer_get_bignum(&decrypted, prv->rsa->q); /* p */
852 buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
853
854 /* calculate p-1 and q-1 */
855 rsa_generate_additional_parameters(prv->rsa);
856
857 buffer_free(&decrypted);
858
859 /* enable blinding */
860 if (RSA_blinding_on(prv->rsa, NULL) != 1) {
861 error("%s: RSA_blinding_on failed", __func__);
862 goto fail;
863 }
864 return prv;
865
866fail:
867 if (commentp != NULL) 177 if (commentp != NULL)
868 free(*commentp); 178 *commentp = NULL;
869 key_free(prv);
870 return NULL;
871}
872
873static Key *
874key_parse_private_pem(Buffer *blob, int type, const char *passphrase,
875 char **commentp)
876{
877 EVP_PKEY *pk = NULL;
878 Key *prv = NULL;
879 char *name = "<no key>";
880 BIO *bio;
881 179
882 if ((bio = BIO_new_mem_buf(buffer_ptr(blob), 180 if ((buffer = sshbuf_new()) == NULL)
883 buffer_len(blob))) == NULL) { 181 return SSH_ERR_ALLOC_FAIL;
884 error("%s: BIO_new_mem_buf failed", __func__); 182 if ((r = sshkey_load_file(fd, NULL, buffer)) != 0)
885 return NULL; 183 goto out;
886 } 184 if ((r = sshkey_parse_private_pem_fileblob(buffer, type, passphrase,
887 185 keyp, commentp)) != 0)
888 pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase); 186 goto out;
889 BIO_free(bio); 187 r = 0;
890 if (pk == NULL) { 188 out:
891 debug("%s: PEM_read_PrivateKey failed", __func__); 189 sshbuf_free(buffer);
892 (void)ERR_get_error(); 190 return r;
893 } else if (pk->type == EVP_PKEY_RSA &&
894 (type == KEY_UNSPEC||type==KEY_RSA)) {
895 prv = key_new(KEY_UNSPEC);
896 prv->rsa = EVP_PKEY_get1_RSA(pk);
897 prv->type = KEY_RSA;
898 name = "rsa w/o comment";
899#ifdef DEBUG_PK
900 RSA_print_fp(stderr, prv->rsa, 8);
901#endif
902 if (RSA_blinding_on(prv->rsa, NULL) != 1) {
903 error("%s: RSA_blinding_on failed", __func__);
904 key_free(prv);
905 prv = NULL;
906 }
907 } else if (pk->type == EVP_PKEY_DSA &&
908 (type == KEY_UNSPEC||type==KEY_DSA)) {
909 prv = key_new(KEY_UNSPEC);
910 prv->dsa = EVP_PKEY_get1_DSA(pk);
911 prv->type = KEY_DSA;
912 name = "dsa w/o comment";
913#ifdef DEBUG_PK
914 DSA_print_fp(stderr, prv->dsa, 8);
915#endif
916#ifdef OPENSSL_HAS_ECC
917 } else if (pk->type == EVP_PKEY_EC &&
918 (type == KEY_UNSPEC||type==KEY_ECDSA)) {
919 prv = key_new(KEY_UNSPEC);
920 prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
921 prv->type = KEY_ECDSA;
922 if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 ||
923 key_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
924 key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
925 EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
926 key_ec_validate_private(prv->ecdsa) != 0) {
927 error("%s: bad ECDSA key", __func__);
928 key_free(prv);
929 prv = NULL;
930 }
931 name = "ecdsa w/o comment";
932#ifdef DEBUG_PK
933 if (prv != NULL && prv->ecdsa != NULL)
934 key_dump_ec_key(prv->ecdsa);
935#endif
936#endif /* OPENSSL_HAS_ECC */
937 } else {
938 error("%s: PEM_read_PrivateKey: mismatch or "
939 "unknown EVP_PKEY save_type %d", __func__, pk->save_type);
940 }
941 if (pk != NULL)
942 EVP_PKEY_free(pk);
943 if (prv != NULL && commentp)
944 *commentp = xstrdup(name);
945 debug("read PEM private key done: type %s",
946 prv ? key_type(prv) : "<unknown>");
947 return prv;
948}
949
950Key *
951key_load_private_pem(int fd, int type, const char *passphrase,
952 char **commentp)
953{
954 Buffer buffer;
955 Key *prv;
956
957 buffer_init(&buffer);
958 if (!key_load_file(fd, NULL, &buffer)) {
959 buffer_free(&buffer);
960 return NULL;
961 }
962 prv = key_parse_private_pem(&buffer, type, passphrase, commentp);
963 buffer_free(&buffer);
964 return prv;
965} 191}
192#endif /* WITH_OPENSSL */
966 193
194/* XXX remove error() calls from here? */
967int 195int
968key_perm_ok(int fd, const char *filename) 196sshkey_perm_ok(int fd, const char *filename)
969{ 197{
970 struct stat st; 198 struct stat st;
971 199
972 if (fstat(fd, &st) < 0) 200 if (fstat(fd, &st) < 0)
973 return 0; 201 return SSH_ERR_SYSTEM_ERROR;
974 /* 202 /*
975 * if a key owned by the user is accessed, then we check the 203 * if a key owned by the user is accessed, then we check the
976 * permissions of the file. if the key owned by a different user, 204 * permissions of the file. if the key owned by a different user,
@@ -985,298 +213,311 @@ key_perm_ok(int fd, const char *filename)
985 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 213 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
986 error("Permissions 0%3.3o for '%s' are too open.", 214 error("Permissions 0%3.3o for '%s' are too open.",
987 (u_int)st.st_mode & 0777, filename); 215 (u_int)st.st_mode & 0777, filename);
988 error("It is required that your private key files are NOT accessible by others."); 216 error("It is recommended that your private key files are NOT accessible by others.");
989 error("This private key will be ignored."); 217 error("This private key will be ignored.");
990 return 0; 218 return SSH_ERR_KEY_BAD_PERMISSIONS;
991 } 219 }
992 return 1; 220 return 0;
993} 221}
994 222
995static Key * 223/* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
996key_parse_private_type(Buffer *blob, int type, const char *passphrase, 224int
997 char **commentp) 225sshkey_load_private_type(int type, const char *filename, const char *passphrase,
226 struct sshkey **keyp, char **commentp, int *perm_ok)
998{ 227{
999 Key *k; 228 int fd, r;
229 struct sshbuf *buffer = NULL;
1000 230
1001 switch (type) { 231 *keyp = NULL;
1002 case KEY_RSA1: 232 if (commentp != NULL)
1003 return key_parse_private_rsa1(blob, passphrase, commentp); 233 *commentp = NULL;
1004 case KEY_DSA:
1005 case KEY_ECDSA:
1006 case KEY_RSA:
1007 return key_parse_private_pem(blob, type, passphrase, commentp);
1008 case KEY_ED25519:
1009 return key_parse_private2(blob, type, passphrase, commentp);
1010 case KEY_UNSPEC:
1011 if ((k = key_parse_private2(blob, type, passphrase, commentp)))
1012 return k;
1013 return key_parse_private_pem(blob, type, passphrase, commentp);
1014 default:
1015 error("%s: cannot parse key type %d", __func__, type);
1016 break;
1017 }
1018 return NULL;
1019}
1020
1021Key *
1022key_load_private_type(int type, const char *filename, const char *passphrase,
1023 char **commentp, int *perm_ok)
1024{
1025 int fd;
1026 Key *ret;
1027 Buffer buffer;
1028 234
1029 fd = open(filename, O_RDONLY); 235 if ((fd = open(filename, O_RDONLY)) < 0) {
1030 if (fd < 0) {
1031 debug("could not open key file '%s': %s", filename,
1032 strerror(errno));
1033 if (perm_ok != NULL) 236 if (perm_ok != NULL)
1034 *perm_ok = 0; 237 *perm_ok = 0;
1035 return NULL; 238 return SSH_ERR_SYSTEM_ERROR;
1036 } 239 }
1037 if (!key_perm_ok(fd, filename)) { 240 if (sshkey_perm_ok(fd, filename) != 0) {
1038 if (perm_ok != NULL) 241 if (perm_ok != NULL)
1039 *perm_ok = 0; 242 *perm_ok = 0;
1040 error("bad permissions: ignore key: %s", filename); 243 r = SSH_ERR_KEY_BAD_PERMISSIONS;
1041 close(fd); 244 goto out;
1042 return NULL;
1043 } 245 }
1044 if (perm_ok != NULL) 246 if (perm_ok != NULL)
1045 *perm_ok = 1; 247 *perm_ok = 1;
1046 248
1047 buffer_init(&buffer); 249 if ((buffer = sshbuf_new()) == NULL) {
1048 if (!key_load_file(fd, filename, &buffer)) { 250 r = SSH_ERR_ALLOC_FAIL;
1049 buffer_free(&buffer); 251 goto out;
1050 close(fd);
1051 return NULL;
1052 } 252 }
253 if ((r = sshkey_load_file(fd, filename, buffer)) != 0)
254 goto out;
255 if ((r = sshkey_parse_private_fileblob_type(buffer, type, passphrase,
256 keyp, commentp)) != 0)
257 goto out;
258 r = 0;
259 out:
1053 close(fd); 260 close(fd);
1054 ret = key_parse_private_type(&buffer, type, passphrase, commentp); 261 if (buffer != NULL)
1055 buffer_free(&buffer); 262 sshbuf_free(buffer);
1056 return ret; 263 return r;
1057} 264}
1058 265
1059Key * 266/* XXX this is almost identical to sshkey_load_private_type() */
1060key_parse_private(Buffer *buffer, const char *filename, 267int
1061 const char *passphrase, char **commentp) 268sshkey_load_private(const char *filename, const char *passphrase,
269 struct sshkey **keyp, char **commentp)
1062{ 270{
1063 Key *pub, *prv; 271 struct sshbuf *buffer = NULL;
1064 272 int r, fd;
1065 /* it's a SSH v1 key if the public key part is readable */
1066 pub = key_parse_public_rsa1(buffer, commentp);
1067 if (pub == NULL) {
1068 prv = key_parse_private_type(buffer, KEY_UNSPEC,
1069 passphrase, NULL);
1070 /* use the filename as a comment for PEM */
1071 if (commentp && prv)
1072 *commentp = xstrdup(filename);
1073 } else {
1074 key_free(pub);
1075 /* key_parse_public_rsa1() has already loaded the comment */
1076 prv = key_parse_private_type(buffer, KEY_RSA1, passphrase,
1077 NULL);
1078 }
1079 return prv;
1080}
1081 273
1082Key * 274 *keyp = NULL;
1083key_load_private(const char *filename, const char *passphrase, 275 if (commentp != NULL)
1084 char **commentp) 276 *commentp = NULL;
1085{
1086 Key *prv;
1087 Buffer buffer;
1088 int fd;
1089 277
1090 fd = open(filename, O_RDONLY); 278 if ((fd = open(filename, O_RDONLY)) < 0)
1091 if (fd < 0) { 279 return SSH_ERR_SYSTEM_ERROR;
1092 debug("could not open key file '%s': %s", filename, 280 if (sshkey_perm_ok(fd, filename) != 0) {
1093 strerror(errno)); 281 r = SSH_ERR_KEY_BAD_PERMISSIONS;
1094 return NULL; 282 goto out;
1095 }
1096 if (!key_perm_ok(fd, filename)) {
1097 error("bad permissions: ignore key: %s", filename);
1098 close(fd);
1099 return NULL;
1100 } 283 }
1101 284
1102 buffer_init(&buffer); 285 if ((buffer = sshbuf_new()) == NULL) {
1103 if (!key_load_file(fd, filename, &buffer)) { 286 r = SSH_ERR_ALLOC_FAIL;
1104 buffer_free(&buffer); 287 goto out;
1105 close(fd);
1106 return NULL;
1107 } 288 }
289 if ((r = sshkey_load_file(fd, filename, buffer)) != 0 ||
290 (r = sshkey_parse_private_fileblob(buffer, passphrase, filename,
291 keyp, commentp)) != 0)
292 goto out;
293 r = 0;
294 out:
1108 close(fd); 295 close(fd);
1109 296 if (buffer != NULL)
1110 prv = key_parse_private(&buffer, filename, passphrase, commentp); 297 sshbuf_free(buffer);
1111 buffer_free(&buffer); 298 return r;
1112 return prv;
1113} 299}
1114 300
1115static int 301static int
1116key_try_load_public(Key *k, const char *filename, char **commentp) 302sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
1117{ 303{
1118 FILE *f; 304 FILE *f;
1119 char line[SSH_MAX_PUBKEY_BYTES]; 305 char line[SSH_MAX_PUBKEY_BYTES];
1120 char *cp; 306 char *cp;
1121 u_long linenum = 0; 307 u_long linenum = 0;
308 int r;
1122 309
1123 f = fopen(filename, "r"); 310 if (commentp != NULL)
1124 if (f != NULL) { 311 *commentp = NULL;
1125 while (read_keyfile_line(f, filename, line, sizeof(line), 312 if ((f = fopen(filename, "r")) == NULL)
1126 &linenum) != -1) { 313 return SSH_ERR_SYSTEM_ERROR;
1127 cp = line; 314 while (read_keyfile_line(f, filename, line, sizeof(line),
1128 switch (*cp) { 315 &linenum) != -1) {
1129 case '#': 316 cp = line;
1130 case '\n': 317 switch (*cp) {
1131 case '\0': 318 case '#':
1132 continue; 319 case '\n':
1133 } 320 case '\0':
1134 /* Abort loading if this looks like a private key */ 321 continue;
1135 if (strncmp(cp, "-----BEGIN", 10) == 0) 322 }
1136 break; 323 /* Abort loading if this looks like a private key */
1137 /* Skip leading whitespace. */ 324 if (strncmp(cp, "-----BEGIN", 10) == 0 ||
1138 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 325 strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
1139 ; 326 break;
1140 if (*cp) { 327 /* Skip leading whitespace. */
1141 if (key_read(k, &cp) == 1) { 328 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
1142 cp[strcspn(cp, "\r\n")] = '\0'; 329 ;
1143 if (commentp) { 330 if (*cp) {
1144 *commentp = xstrdup(*cp ? 331 if ((r = sshkey_read(k, &cp)) == 0) {
1145 cp : filename); 332 cp[strcspn(cp, "\r\n")] = '\0';
1146 } 333 if (commentp) {
1147 fclose(f); 334 *commentp = strdup(*cp ?
1148 return 1; 335 cp : filename);
336 if (*commentp == NULL)
337 r = SSH_ERR_ALLOC_FAIL;
1149 } 338 }
339 fclose(f);
340 return r;
1150 } 341 }
1151 } 342 }
1152 fclose(f);
1153 } 343 }
1154 return 0; 344 fclose(f);
345 return SSH_ERR_INVALID_FORMAT;
1155} 346}
1156 347
1157/* load public key from ssh v1 private or any pubkey file */ 348/* load public key from ssh v1 private or any pubkey file */
1158Key * 349int
1159key_load_public(const char *filename, char **commentp) 350sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
1160{ 351{
1161 Key *pub; 352 struct sshkey *pub = NULL;
1162 char file[MAXPATHLEN]; 353 char file[MAXPATHLEN];
354 int r, fd;
355
356 if (keyp != NULL)
357 *keyp = NULL;
358 if (commentp != NULL)
359 *commentp = NULL;
1163 360
361 if ((fd = open(filename, O_RDONLY)) < 0)
362 goto skip;
363#ifdef WITH_SSH1
1164 /* try rsa1 private key */ 364 /* try rsa1 private key */
1165 pub = key_load_public_type(KEY_RSA1, filename, commentp); 365 r = sshkey_load_public_rsa1(fd, filename, keyp, commentp);
1166 if (pub != NULL) 366 close(fd);
1167 return pub; 367 switch (r) {
368 case SSH_ERR_INTERNAL_ERROR:
369 case SSH_ERR_ALLOC_FAIL:
370 case SSH_ERR_INVALID_ARGUMENT:
371 case SSH_ERR_SYSTEM_ERROR:
372 case 0:
373 return r;
374 }
375#endif /* WITH_SSH1 */
1168 376
377 /* try ssh2 public key */
378 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
379 return SSH_ERR_ALLOC_FAIL;
380 if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
381 if (keyp != NULL)
382 *keyp = pub;
383 return 0;
384 }
385 sshkey_free(pub);
386
387#ifdef WITH_SSH1
1169 /* try rsa1 public key */ 388 /* try rsa1 public key */
1170 pub = key_new(KEY_RSA1); 389 if ((pub = sshkey_new(KEY_RSA1)) == NULL)
1171 if (key_try_load_public(pub, filename, commentp) == 1) 390 return SSH_ERR_ALLOC_FAIL;
1172 return pub; 391 if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
1173 key_free(pub); 392 if (keyp != NULL)
393 *keyp = pub;
394 return 0;
395 }
396 sshkey_free(pub);
397#endif /* WITH_SSH1 */
1174 398
1175 /* try ssh2 public key */ 399 skip:
1176 pub = key_new(KEY_UNSPEC); 400 /* try .pub suffix */
1177 if (key_try_load_public(pub, filename, commentp) == 1) 401 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
1178 return pub; 402 return SSH_ERR_ALLOC_FAIL;
403 r = SSH_ERR_ALLOC_FAIL; /* in case strlcpy or strlcat fail */
1179 if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && 404 if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
1180 (strlcat(file, ".pub", sizeof file) < sizeof(file)) && 405 (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
1181 (key_try_load_public(pub, file, commentp) == 1)) 406 (r = sshkey_try_load_public(pub, file, commentp)) == 0) {
1182 return pub; 407 if (keyp != NULL)
1183 key_free(pub); 408 *keyp = pub;
1184 return NULL; 409 return 0;
410 }
411 sshkey_free(pub);
412 return r;
1185} 413}
1186 414
1187/* Load the certificate associated with the named private key */ 415/* Load the certificate associated with the named private key */
1188Key * 416int
1189key_load_cert(const char *filename) 417sshkey_load_cert(const char *filename, struct sshkey **keyp)
1190{ 418{
1191 Key *pub; 419 struct sshkey *pub = NULL;
1192 char *file; 420 char *file = NULL;
421 int r = SSH_ERR_INTERNAL_ERROR;
1193 422
1194 pub = key_new(KEY_UNSPEC); 423 *keyp = NULL;
1195 xasprintf(&file, "%s-cert.pub", filename); 424
1196 if (key_try_load_public(pub, file, NULL) == 1) { 425 if (asprintf(&file, "%s-cert.pub", filename) == -1)
1197 free(file); 426 return SSH_ERR_ALLOC_FAIL;
1198 return pub; 427
428 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
429 goto out;
1199 } 430 }
1200 free(file); 431 if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
1201 key_free(pub); 432 goto out;
1202 return NULL; 433
434 *keyp = pub;
435 pub = NULL;
436 r = 0;
437
438 out:
439 if (file != NULL)
440 free(file);
441 if (pub != NULL)
442 sshkey_free(pub);
443 return r;
1203} 444}
1204 445
1205/* Load private key and certificate */ 446/* Load private key and certificate */
1206Key * 447int
1207key_load_private_cert(int type, const char *filename, const char *passphrase, 448sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
1208 int *perm_ok) 449 struct sshkey **keyp, int *perm_ok)
1209{ 450{
1210 Key *key, *pub; 451 struct sshkey *key = NULL, *cert = NULL;
452 int r;
453
454 *keyp = NULL;
1211 455
1212 switch (type) { 456 switch (type) {
457#ifdef WITH_OPENSSL
1213 case KEY_RSA: 458 case KEY_RSA:
1214 case KEY_DSA: 459 case KEY_DSA:
1215 case KEY_ECDSA: 460 case KEY_ECDSA:
1216 case KEY_ED25519: 461 case KEY_ED25519:
462#endif /* WITH_OPENSSL */
463 case KEY_UNSPEC:
1217 break; 464 break;
1218 default: 465 default:
1219 error("%s: unsupported key type", __func__); 466 return SSH_ERR_KEY_TYPE_UNKNOWN;
1220 return NULL;
1221 } 467 }
1222 468
1223 if ((key = key_load_private_type(type, filename, 469 if ((r = sshkey_load_private_type(type, filename,
1224 passphrase, NULL, perm_ok)) == NULL) 470 passphrase, &key, NULL, perm_ok)) != 0 ||
1225 return NULL; 471 (r = sshkey_load_cert(filename, &cert)) != 0)
1226 472 goto out;
1227 if ((pub = key_load_cert(filename)) == NULL) {
1228 key_free(key);
1229 return NULL;
1230 }
1231 473
1232 /* Make sure the private key matches the certificate */ 474 /* Make sure the private key matches the certificate */
1233 if (key_equal_public(key, pub) == 0) { 475 if (sshkey_equal_public(key, cert) == 0) {
1234 error("%s: certificate does not match private key %s", 476 r = SSH_ERR_KEY_CERT_MISMATCH;
1235 __func__, filename); 477 goto out;
1236 } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) {
1237 error("%s: key_to_certified failed", __func__);
1238 } else {
1239 key_cert_copy(pub, key);
1240 key_free(pub);
1241 return key;
1242 } 478 }
1243 479
1244 key_free(key); 480 if ((r = sshkey_to_certified(key, sshkey_cert_is_legacy(cert))) != 0 ||
1245 key_free(pub); 481 (r = sshkey_cert_copy(cert, key)) != 0)
1246 return NULL; 482 goto out;
483 r = 0;
484 *keyp = key;
485 key = NULL;
486 out:
487 if (key != NULL)
488 sshkey_free(key);
489 if (cert != NULL)
490 sshkey_free(cert);
491 return r;
1247} 492}
1248 493
1249/* 494/*
1250 * Returns 1 if the specified "key" is listed in the file "filename", 495 * Returns success if the specified "key" is listed in the file "filename",
1251 * 0 if the key is not listed or -1 on error. 496 * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
1252 * If strict_type is set then the key type must match exactly, 497 * If strict_type is set then the key type must match exactly,
1253 * otherwise a comparison that ignores certficiate data is performed. 498 * otherwise a comparison that ignores certficiate data is performed.
1254 */ 499 */
1255int 500int
1256key_in_file(Key *key, const char *filename, int strict_type) 501sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
1257{ 502{
1258 FILE *f; 503 FILE *f;
1259 char line[SSH_MAX_PUBKEY_BYTES]; 504 char line[SSH_MAX_PUBKEY_BYTES];
1260 char *cp; 505 char *cp;
1261 u_long linenum = 0; 506 u_long linenum = 0;
1262 int ret = 0; 507 int r = 0;
1263 Key *pub; 508 struct sshkey *pub = NULL;
1264 int (*key_compare)(const Key *, const Key *) = strict_type ? 509 int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
1265 key_equal : key_equal_public; 510 strict_type ? sshkey_equal : sshkey_equal_public;
1266 511
1267 if ((f = fopen(filename, "r")) == NULL) { 512 if ((f = fopen(filename, "r")) == NULL) {
1268 if (errno == ENOENT) { 513 if (errno == ENOENT)
1269 debug("%s: keyfile \"%s\" missing", __func__, filename); 514 return SSH_ERR_KEY_NOT_FOUND;
1270 return 0; 515 else
1271 } else { 516 return SSH_ERR_SYSTEM_ERROR;
1272 error("%s: could not open keyfile \"%s\": %s", __func__,
1273 filename, strerror(errno));
1274 return -1;
1275 }
1276 } 517 }
1277 518
1278 while (read_keyfile_line(f, filename, line, sizeof(line), 519 while (read_keyfile_line(f, filename, line, sizeof(line),
1279 &linenum) != -1) { 520 &linenum) != -1) {
1280 cp = line; 521 cp = line;
1281 522
1282 /* Skip leading whitespace. */ 523 /* Skip leading whitespace. */
@@ -1291,18 +532,24 @@ key_in_file(Key *key, const char *filename, int strict_type)
1291 continue; 532 continue;
1292 } 533 }
1293 534
1294 pub = key_new(KEY_UNSPEC); 535 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
1295 if (key_read(pub, &cp) != 1) { 536 r = SSH_ERR_ALLOC_FAIL;
1296 key_free(pub); 537 goto out;
1297 continue;
1298 } 538 }
1299 if (key_compare(key, pub)) { 539 if ((r = sshkey_read(pub, &cp)) != 0)
1300 ret = 1; 540 goto out;
1301 key_free(pub); 541 if (sshkey_compare(key, pub)) {
1302 break; 542 r = 0;
543 goto out;
1303 } 544 }
1304 key_free(pub); 545 sshkey_free(pub);
546 pub = NULL;
1305 } 547 }
548 r = SSH_ERR_KEY_NOT_FOUND;
549 out:
550 if (pub != NULL)
551 sshkey_free(pub);
1306 fclose(f); 552 fclose(f);
1307 return ret; 553 return r;
1308} 554}
555
diff --git a/authfile.h b/authfile.h
index 8ba1c2dbe..03bc3958c 100644
--- a/authfile.h
+++ b/authfile.h
@@ -1,32 +1,47 @@
1/* $OpenBSD: authfile.h,v 1.17 2013/12/06 13:34:54 markus Exp $ */ 1/* $OpenBSD: authfile.h,v 1.19 2014/07/03 23:18:35 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
5 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6 * All rights reserved
7 * 5 *
8 * As far as I am concerned, the code I have written for this software 6 * Redistribution and use in source and binary forms, with or without
9 * can be used freely for any purpose. Any derived versions of this 7 * modification, are permitted provided that the following conditions
10 * software must be clearly marked as such, and if the derived work is 8 * are met:
11 * incompatible with the protocol description in the RFC file, it must be 9 * 1. Redistributions of source code must retain the above copyright
12 * called by a name other than "ssh" or "Secure Shell". 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13 */ 25 */
14 26
15#ifndef AUTHFILE_H 27#ifndef AUTHFILE_H
16#define AUTHFILE_H 28#define AUTHFILE_H
17 29
18int key_save_private(Key *, const char *, const char *, const char *, 30struct sshbuf;
19 int, const char *, int); 31struct sshkey;
20int key_load_file(int, const char *, Buffer *); 32
21Key *key_load_cert(const char *); 33int sshkey_save_private(struct sshkey *, const char *,
22Key *key_load_public(const char *, char **); 34 const char *, const char *, int, const char *, int);
23Key *key_load_public_type(int, const char *, char **); 35int sshkey_load_file(int, const char *, struct sshbuf *);
24Key *key_parse_private(Buffer *, const char *, const char *, char **); 36int sshkey_load_cert(const char *, struct sshkey **);
25Key *key_load_private(const char *, const char *, char **); 37int sshkey_load_public(const char *, struct sshkey **, char **);
26Key *key_load_private_cert(int, const char *, const char *, int *); 38int sshkey_load_private(const char *, const char *, struct sshkey **, char **);
27Key *key_load_private_type(int, const char *, const char *, char **, int *); 39int sshkey_load_private_cert(int, const char *, const char *,
28Key *key_load_private_pem(int, int, const char *, char **); 40 struct sshkey **, int *);
29int key_perm_ok(int, const char *); 41int sshkey_load_private_type(int, const char *, const char *,
30int key_in_file(Key *, const char *, int); 42 struct sshkey **, char **, int *);
43int sshkey_load_private_pem(int, int, const char *, struct sshkey **, char **);
44int sshkey_perm_ok(int, const char *);
45int sshkey_in_file(struct sshkey *, const char *, int);
31 46
32#endif 47#endif
diff --git a/bufaux.c b/bufaux.c
index e24b5fc0a..3976896a9 100644
--- a/bufaux.c
+++ b/bufaux.c
@@ -1,70 +1,40 @@
1/* $OpenBSD: bufaux.c,v 1.56 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: bufaux.c,v 1.60 2014/04/30 05:29:56 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved
6 * Auxiliary functions for storing and retrieving various data types to/from
7 * Buffers.
8 * 4 *
9 * As far as I am concerned, the code I have written for this software 5 * Permission to use, copy, modify, and distribute this software for any
10 * can be used freely for any purpose. Any derived versions of this 6 * purpose with or without fee is hereby granted, provided that the above
11 * software must be clearly marked as such, and if the derived work is 7 * copyright notice and this permission notice appear in all copies.
12 * incompatible with the protocol description in the RFC file, it must be
13 * called by a name other than "ssh" or "Secure Shell".
14 * 8 *
15 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 * SSH2 packet format added by Markus Friedl 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * Copyright (c) 2000 Markus Friedl. All rights reserved. 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 * 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * Redistribution and use in source and binary forms, with or without 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * modification, are permitted provided that the following conditions 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 * are met: 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
29 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
30 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
32 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */ 16 */
39 17
18/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
19
40#include "includes.h" 20#include "includes.h"
41 21
42#include <sys/types.h> 22#include <sys/types.h>
43 23
44#include <openssl/bn.h>
45
46#include <string.h>
47#include <stdarg.h>
48#include <stdlib.h>
49
50#include "xmalloc.h"
51#include "buffer.h" 24#include "buffer.h"
52#include "log.h" 25#include "log.h"
53#include "misc.h" 26#include "ssherr.h"
54
55/*
56 * Returns integers from the buffer (msb first).
57 */
58 27
59int 28int
60buffer_get_short_ret(u_short *ret, Buffer *buffer) 29buffer_get_short_ret(u_short *v, Buffer *buffer)
61{ 30{
62 u_char buf[2]; 31 int ret;
63 32
64 if (buffer_get_ret(buffer, (char *) buf, 2) == -1) 33 if ((ret = sshbuf_get_u16(buffer, v)) != 0) {
65 return (-1); 34 error("%s: %s", __func__, ssh_err(ret));
66 *ret = get_u16(buf); 35 return -1;
67 return (0); 36 }
37 return 0;
68} 38}
69 39
70u_short 40u_short
@@ -73,21 +43,21 @@ buffer_get_short(Buffer *buffer)
73 u_short ret; 43 u_short ret;
74 44
75 if (buffer_get_short_ret(&ret, buffer) == -1) 45 if (buffer_get_short_ret(&ret, buffer) == -1)
76 fatal("buffer_get_short: buffer error"); 46 fatal("%s: buffer error", __func__);
77 47
78 return (ret); 48 return (ret);
79} 49}
80 50
81int 51int
82buffer_get_int_ret(u_int *ret, Buffer *buffer) 52buffer_get_int_ret(u_int *v, Buffer *buffer)
83{ 53{
84 u_char buf[4]; 54 int ret;
85 55
86 if (buffer_get_ret(buffer, (char *) buf, 4) == -1) 56 if ((ret = sshbuf_get_u32(buffer, v)) != 0) {
87 return (-1); 57 error("%s: %s", __func__, ssh_err(ret));
88 if (ret != NULL) 58 return -1;
89 *ret = get_u32(buf); 59 }
90 return (0); 60 return 0;
91} 61}
92 62
93u_int 63u_int
@@ -96,21 +66,21 @@ buffer_get_int(Buffer *buffer)
96 u_int ret; 66 u_int ret;
97 67
98 if (buffer_get_int_ret(&ret, buffer) == -1) 68 if (buffer_get_int_ret(&ret, buffer) == -1)
99 fatal("buffer_get_int: buffer error"); 69 fatal("%s: buffer error", __func__);
100 70
101 return (ret); 71 return (ret);
102} 72}
103 73
104int 74int
105buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer) 75buffer_get_int64_ret(u_int64_t *v, Buffer *buffer)
106{ 76{
107 u_char buf[8]; 77 int ret;
108 78
109 if (buffer_get_ret(buffer, (char *) buf, 8) == -1) 79 if ((ret = sshbuf_get_u64(buffer, v)) != 0) {
110 return (-1); 80 error("%s: %s", __func__, ssh_err(ret));
111 if (ret != NULL) 81 return -1;
112 *ret = get_u64(buf); 82 }
113 return (0); 83 return 0;
114} 84}
115 85
116u_int64_t 86u_int64_t
@@ -119,78 +89,52 @@ buffer_get_int64(Buffer *buffer)
119 u_int64_t ret; 89 u_int64_t ret;
120 90
121 if (buffer_get_int64_ret(&ret, buffer) == -1) 91 if (buffer_get_int64_ret(&ret, buffer) == -1)
122 fatal("buffer_get_int: buffer error"); 92 fatal("%s: buffer error", __func__);
123 93
124 return (ret); 94 return (ret);
125} 95}
126 96
127/*
128 * Stores integers in the buffer, msb first.
129 */
130void 97void
131buffer_put_short(Buffer *buffer, u_short value) 98buffer_put_short(Buffer *buffer, u_short value)
132{ 99{
133 char buf[2]; 100 int ret;
134 101
135 put_u16(buf, value); 102 if ((ret = sshbuf_put_u16(buffer, value)) != 0)
136 buffer_append(buffer, buf, 2); 103 fatal("%s: %s", __func__, ssh_err(ret));
137} 104}
138 105
139void 106void
140buffer_put_int(Buffer *buffer, u_int value) 107buffer_put_int(Buffer *buffer, u_int value)
141{ 108{
142 char buf[4]; 109 int ret;
143 110
144 put_u32(buf, value); 111 if ((ret = sshbuf_put_u32(buffer, value)) != 0)
145 buffer_append(buffer, buf, 4); 112 fatal("%s: %s", __func__, ssh_err(ret));
146} 113}
147 114
148void 115void
149buffer_put_int64(Buffer *buffer, u_int64_t value) 116buffer_put_int64(Buffer *buffer, u_int64_t value)
150{ 117{
151 char buf[8]; 118 int ret;
152 119
153 put_u64(buf, value); 120 if ((ret = sshbuf_put_u64(buffer, value)) != 0)
154 buffer_append(buffer, buf, 8); 121 fatal("%s: %s", __func__, ssh_err(ret));
155} 122}
156 123
157/*
158 * Returns an arbitrary binary string from the buffer. The string cannot
159 * be longer than 256k. The returned value points to memory allocated
160 * with xmalloc; it is the responsibility of the calling function to free
161 * the data. If length_ptr is non-NULL, the length of the returned data
162 * will be stored there. A null character will be automatically appended
163 * to the returned string, and is not counted in length.
164 */
165void * 124void *
166buffer_get_string_ret(Buffer *buffer, u_int *length_ptr) 125buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
167{ 126{
127 size_t len;
128 int ret;
168 u_char *value; 129 u_char *value;
169 u_int len;
170 130
171 /* Get the length. */ 131 if ((ret = sshbuf_get_string(buffer, &value, &len)) != 0) {
172 if (buffer_get_int_ret(&len, buffer) != 0) { 132 error("%s: %s", __func__, ssh_err(ret));
173 error("buffer_get_string_ret: cannot extract length"); 133 return NULL;
174 return (NULL);
175 }
176 if (len > 256 * 1024) {
177 error("buffer_get_string_ret: bad string length %u", len);
178 return (NULL);
179 }
180 /* Allocate space for the string. Add one byte for a null character. */
181 value = xmalloc(len + 1);
182 /* Get the string. */
183 if (buffer_get_ret(buffer, value, len) == -1) {
184 error("buffer_get_string_ret: buffer_get failed");
185 free(value);
186 return (NULL);
187 } 134 }
188 /* Append a null character to make processing easier. */ 135 if (length_ptr != NULL)
189 value[len] = '\0'; 136 *length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */
190 /* Optionally return the length of the string. */ 137 return value;
191 if (length_ptr)
192 *length_ptr = len;
193 return (value);
194} 138}
195 139
196void * 140void *
@@ -199,31 +143,24 @@ buffer_get_string(Buffer *buffer, u_int *length_ptr)
199 void *ret; 143 void *ret;
200 144
201 if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL) 145 if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
202 fatal("buffer_get_string: buffer error"); 146 fatal("%s: buffer error", __func__);
203 return (ret); 147 return (ret);
204} 148}
205 149
206char * 150char *
207buffer_get_cstring_ret(Buffer *buffer, u_int *length_ptr) 151buffer_get_cstring_ret(Buffer *buffer, u_int *length_ptr)
208{ 152{
209 u_int length; 153 size_t len;
210 char *cp, *ret = buffer_get_string_ret(buffer, &length); 154 int ret;
155 char *value;
211 156
212 if (ret == NULL) 157 if ((ret = sshbuf_get_cstring(buffer, &value, &len)) != 0) {
158 error("%s: %s", __func__, ssh_err(ret));
213 return NULL; 159 return NULL;
214 if ((cp = memchr(ret, '\0', length)) != NULL) {
215 /* XXX allow \0 at end-of-string for a while, remove later */
216 if (cp == ret + length - 1)
217 error("buffer_get_cstring_ret: string contains \\0");
218 else {
219 explicit_bzero(ret, length);
220 free(ret);
221 return NULL;
222 }
223 } 160 }
224 if (length_ptr != NULL) 161 if (length_ptr != NULL)
225 *length_ptr = length; 162 *length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */
226 return ret; 163 return value;
227} 164}
228 165
229char * 166char *
@@ -232,159 +169,91 @@ buffer_get_cstring(Buffer *buffer, u_int *length_ptr)
232 char *ret; 169 char *ret;
233 170
234 if ((ret = buffer_get_cstring_ret(buffer, length_ptr)) == NULL) 171 if ((ret = buffer_get_cstring_ret(buffer, length_ptr)) == NULL)
235 fatal("buffer_get_cstring: buffer error"); 172 fatal("%s: buffer error", __func__);
236 return ret; 173 return ret;
237} 174}
238 175
239void * 176const void *
240buffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr) 177buffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr)
241{ 178{
242 void *ptr; 179 size_t len;
243 u_int len; 180 int ret;
181 const u_char *value;
244 182
245 if (buffer_get_int_ret(&len, buffer) != 0) 183 if ((ret = sshbuf_get_string_direct(buffer, &value, &len)) != 0) {
246 return NULL; 184 error("%s: %s", __func__, ssh_err(ret));
247 if (len > 256 * 1024) {
248 error("buffer_get_string_ptr: bad string length %u", len);
249 return NULL; 185 return NULL;
250 } 186 }
251 ptr = buffer_ptr(buffer); 187 if (length_ptr != NULL)
252 buffer_consume(buffer, len); 188 *length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */
253 if (length_ptr) 189 return value;
254 *length_ptr = len;
255 return (ptr);
256} 190}
257 191
258void * 192const void *
259buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr) 193buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr)
260{ 194{
261 void *ret; 195 const void *ret;
262 196
263 if ((ret = buffer_get_string_ptr_ret(buffer, length_ptr)) == NULL) 197 if ((ret = buffer_get_string_ptr_ret(buffer, length_ptr)) == NULL)
264 fatal("buffer_get_string_ptr: buffer error"); 198 fatal("%s: buffer error", __func__);
265 return (ret); 199 return (ret);
266} 200}
267 201
268/*
269 * Stores and arbitrary binary string in the buffer.
270 */
271void 202void
272buffer_put_string(Buffer *buffer, const void *buf, u_int len) 203buffer_put_string(Buffer *buffer, const void *buf, u_int len)
273{ 204{
274 buffer_put_int(buffer, len); 205 int ret;
275 buffer_append(buffer, buf, len); 206
207 if ((ret = sshbuf_put_string(buffer, buf, len)) != 0)
208 fatal("%s: %s", __func__, ssh_err(ret));
276} 209}
210
277void 211void
278buffer_put_cstring(Buffer *buffer, const char *s) 212buffer_put_cstring(Buffer *buffer, const char *s)
279{ 213{
280 if (s == NULL) 214 int ret;
281 fatal("buffer_put_cstring: s == NULL"); 215
282 buffer_put_string(buffer, s, strlen(s)); 216 if ((ret = sshbuf_put_cstring(buffer, s)) != 0)
217 fatal("%s: %s", __func__, ssh_err(ret));
283} 218}
284 219
285/*
286 * Returns a character from the buffer (0 - 255).
287 */
288int 220int
289buffer_get_char_ret(u_char *ret, Buffer *buffer) 221buffer_get_char_ret(char *v, Buffer *buffer)
290{ 222{
291 if (buffer_get_ret(buffer, ret, 1) == -1) { 223 int ret;
292 error("buffer_get_char_ret: buffer_get_ret failed"); 224
293 return (-1); 225 if ((ret = sshbuf_get_u8(buffer, (u_char *)v)) != 0) {
226 error("%s: %s", __func__, ssh_err(ret));
227 return -1;
294 } 228 }
295 return (0); 229 return 0;
296} 230}
297 231
298int 232int
299buffer_get_char(Buffer *buffer) 233buffer_get_char(Buffer *buffer)
300{ 234{
301 u_char ch; 235 char ch;
302 236
303 if (buffer_get_char_ret(&ch, buffer) == -1) 237 if (buffer_get_char_ret(&ch, buffer) == -1)
304 fatal("buffer_get_char: buffer error"); 238 fatal("%s: buffer error", __func__);
305 return ch; 239 return (u_char) ch;
306} 240}
307 241
308/*
309 * Stores a character in the buffer.
310 */
311void 242void
312buffer_put_char(Buffer *buffer, int value) 243buffer_put_char(Buffer *buffer, int value)
313{ 244{
314 char ch = value; 245 int ret;
315 246
316 buffer_append(buffer, &ch, 1); 247 if ((ret = sshbuf_put_u8(buffer, value)) != 0)
248 fatal("%s: %s", __func__, ssh_err(ret));
317} 249}
318 250
319/* Pseudo bignum functions */
320
321void *
322buffer_get_bignum2_as_string_ret(Buffer *buffer, u_int *length_ptr)
323{
324 u_int len;
325 u_char *bin, *p, *ret;
326
327 if ((p = bin = buffer_get_string_ret(buffer, &len)) == NULL) {
328 error("%s: invalid bignum", __func__);
329 return NULL;
330 }
331
332 if (len > 0 && (bin[0] & 0x80)) {
333 error("%s: negative numbers not supported", __func__);
334 free(bin);
335 return NULL;
336 }
337 if (len > 8 * 1024) {
338 error("%s: cannot handle BN of size %d", __func__, len);
339 free(bin);
340 return NULL;
341 }
342 /* Skip zero prefix on numbers with the MSB set */
343 if (len > 1 && bin[0] == 0x00 && (bin[1] & 0x80) != 0) {
344 p++;
345 len--;
346 }
347 ret = xmalloc(len);
348 memcpy(ret, p, len);
349 explicit_bzero(p, len);
350 free(bin);
351 return ret;
352}
353
354void *
355buffer_get_bignum2_as_string(Buffer *buffer, u_int *l)
356{
357 void *ret = buffer_get_bignum2_as_string_ret(buffer, l);
358
359 if (ret == NULL)
360 fatal("%s: buffer error", __func__);
361 return ret;
362}
363
364/*
365 * Stores a string using the bignum encoding rules (\0 pad if MSB set).
366 */
367void 251void
368buffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l) 252buffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l)
369{ 253{
370 u_char *buf, *p; 254 int ret;
371 int pad = 0;
372
373 if (l > 8 * 1024)
374 fatal("%s: length %u too long", __func__, l);
375 p = buf = xmalloc(l + 1);
376 /*
377 * If most significant bit is set then prepend a zero byte to
378 * avoid interpretation as a negative number.
379 */
380 if (l > 0 && (s[0] & 0x80) != 0) {
381 *p++ = '\0';
382 pad = 1;
383 }
384 memcpy(p, s, l);
385 buffer_put_string(buffer, buf, l + pad);
386 explicit_bzero(buf, l + pad);
387 free(buf);
388}
389 255
256 if ((ret = sshbuf_put_bignum2_bytes(buffer, s, l)) != 0)
257 fatal("%s: %s", __func__, ssh_err(ret));
258}
390 259
diff --git a/bufbn.c b/bufbn.c
index 1d2e01266..b7f7cb122 100644
--- a/bufbn.c
+++ b/bufbn.c
@@ -1,229 +1,103 @@
1/* $OpenBSD: bufbn.c,v 1.11 2014/02/27 08:25:09 djm Exp $*/ 1/* $OpenBSD: bufbn.c,v 1.12 2014/04/30 05:29:56 djm Exp $ */
2
2/* 3/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved
6 * Auxiliary functions for storing and retrieving various data types to/from
7 * Buffers.
8 *
9 * As far as I am concerned, the code I have written for this software
10 * can be used freely for any purpose. Any derived versions of this
11 * software must be clearly marked as such, and if the derived work is
12 * incompatible with the protocol description in the RFC file, it must be
13 * called by a name other than "ssh" or "Secure Shell".
14 *
15 *
16 * SSH2 packet format added by Markus Friedl
17 * Copyright (c) 2000 Markus Friedl. All rights reserved.
18 * 5 *
19 * Redistribution and use in source and binary forms, with or without 6 * Permission to use, copy, modify, and distribute this software for any
20 * modification, are permitted provided that the following conditions 7 * purpose with or without fee is hereby granted, provided that the above
21 * are met: 8 * copyright notice and this permission notice appear in all copies.
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * 9 *
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
29 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
30 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
31 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
32 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
33 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */ 17 */
39 18
19/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
20
40#include "includes.h" 21#include "includes.h"
41 22
42#include <sys/types.h> 23#include <sys/types.h>
43 24
44#include <openssl/bn.h>
45
46#include <string.h>
47#include <stdarg.h>
48#include <stdlib.h>
49
50#include "xmalloc.h"
51#include "buffer.h" 25#include "buffer.h"
52#include "log.h" 26#include "log.h"
53#include "misc.h" 27#include "ssherr.h"
54 28
55/*
56 * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
57 * by (bits+7)/8 bytes of binary data, msb first.
58 */
59int 29int
60buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value) 30buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
61{ 31{
62 int bits = BN_num_bits(value); 32 int ret;
63 int bin_size = (bits + 7) / 8;
64 u_char *buf = xmalloc(bin_size);
65 int oi;
66 char msg[2];
67
68 /* Get the value of in binary */
69 oi = BN_bn2bin(value, buf);
70 if (oi != bin_size) {
71 error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d",
72 oi, bin_size);
73 free(buf);
74 return (-1);
75 }
76
77 /* Store the number of bits in the buffer in two bytes, msb first. */
78 put_u16(msg, bits);
79 buffer_append(buffer, msg, 2);
80 /* Store the binary data. */
81 buffer_append(buffer, buf, oi);
82
83 explicit_bzero(buf, bin_size);
84 free(buf);
85 33
86 return (0); 34 if ((ret = sshbuf_put_bignum1(buffer, value)) != 0) {
35 error("%s: %s", __func__, ssh_err(ret));
36 return -1;
37 }
38 return 0;
87} 39}
88 40
89void 41void
90buffer_put_bignum(Buffer *buffer, const BIGNUM *value) 42buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
91{ 43{
92 if (buffer_put_bignum_ret(buffer, value) == -1) 44 if (buffer_put_bignum_ret(buffer, value) == -1)
93 fatal("buffer_put_bignum: buffer error"); 45 fatal("%s: buffer error", __func__);
94} 46}
95 47
96/*
97 * Retrieves a BIGNUM from the buffer.
98 */
99int 48int
100buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value) 49buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
101{ 50{
102 u_int bits, bytes; 51 int ret;
103 u_char buf[2], *bin;
104 52
105 /* Get the number of bits. */ 53 if ((ret = sshbuf_get_bignum1(buffer, value)) != 0) {
106 if (buffer_get_ret(buffer, (char *) buf, 2) == -1) { 54 error("%s: %s", __func__, ssh_err(ret));
107 error("buffer_get_bignum_ret: invalid length"); 55 return -1;
108 return (-1);
109 } 56 }
110 bits = get_u16(buf); 57 return 0;
111 if (bits > 65535-7) {
112 error("buffer_get_bignum_ret: cannot handle BN of size %d",
113 bits);
114 return (-1);
115 }
116 /* Compute the number of binary bytes that follow. */
117 bytes = (bits + 7) / 8;
118 if (bytes > 8 * 1024) {
119 error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes);
120 return (-1);
121 }
122 if (buffer_len(buffer) < bytes) {
123 error("buffer_get_bignum_ret: input buffer too small");
124 return (-1);
125 }
126 bin = buffer_ptr(buffer);
127 if (BN_bin2bn(bin, bytes, value) == NULL) {
128 error("buffer_get_bignum_ret: BN_bin2bn failed");
129 return (-1);
130 }
131 if (buffer_consume_ret(buffer, bytes) == -1) {
132 error("buffer_get_bignum_ret: buffer_consume failed");
133 return (-1);
134 }
135 return (0);
136} 58}
137 59
138void 60void
139buffer_get_bignum(Buffer *buffer, BIGNUM *value) 61buffer_get_bignum(Buffer *buffer, BIGNUM *value)
140{ 62{
141 if (buffer_get_bignum_ret(buffer, value) == -1) 63 if (buffer_get_bignum_ret(buffer, value) == -1)
142 fatal("buffer_get_bignum: buffer error"); 64 fatal("%s: buffer error", __func__);
143} 65}
144 66
145/*
146 * Stores a BIGNUM in the buffer in SSH2 format.
147 */
148int 67int
149buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value) 68buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
150{ 69{
151 u_int bytes; 70 int ret;
152 u_char *buf; 71
153 int oi; 72 if ((ret = sshbuf_put_bignum2(buffer, value)) != 0) {
154 u_int hasnohigh = 0; 73 error("%s: %s", __func__, ssh_err(ret));
155 74 return -1;
156 if (BN_is_zero(value)) {
157 buffer_put_int(buffer, 0);
158 return 0;
159 }
160 if (value->neg) {
161 error("buffer_put_bignum2_ret: negative numbers not supported");
162 return (-1);
163 }
164 bytes = BN_num_bytes(value) + 1; /* extra padding byte */
165 if (bytes < 2) {
166 error("buffer_put_bignum2_ret: BN too small");
167 return (-1);
168 }
169 buf = xmalloc(bytes);
170 buf[0] = 0x00;
171 /* Get the value of in binary */
172 oi = BN_bn2bin(value, buf+1);
173 if (oi < 0 || (u_int)oi != bytes - 1) {
174 error("buffer_put_bignum2_ret: BN_bn2bin() failed: "
175 "oi %d != bin_size %d", oi, bytes);
176 free(buf);
177 return (-1);
178 } 75 }
179 hasnohigh = (buf[1] & 0x80) ? 0 : 1; 76 return 0;
180 buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
181 explicit_bzero(buf, bytes);
182 free(buf);
183 return (0);
184} 77}
185 78
186void 79void
187buffer_put_bignum2(Buffer *buffer, const BIGNUM *value) 80buffer_put_bignum2(Buffer *buffer, const BIGNUM *value)
188{ 81{
189 if (buffer_put_bignum2_ret(buffer, value) == -1) 82 if (buffer_put_bignum2_ret(buffer, value) == -1)
190 fatal("buffer_put_bignum2: buffer error"); 83 fatal("%s: buffer error", __func__);
191} 84}
192 85
193int 86int
194buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value) 87buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value)
195{ 88{
196 u_int len; 89 int ret;
197 u_char *bin;
198 90
199 if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) { 91 if ((ret = sshbuf_get_bignum2(buffer, value)) != 0) {
200 error("buffer_get_bignum2_ret: invalid bignum"); 92 error("%s: %s", __func__, ssh_err(ret));
201 return (-1); 93 return -1;
202 }
203
204 if (len > 0 && (bin[0] & 0x80)) {
205 error("buffer_get_bignum2_ret: negative numbers not supported");
206 free(bin);
207 return (-1);
208 }
209 if (len > 8 * 1024) {
210 error("buffer_get_bignum2_ret: cannot handle BN of size %d",
211 len);
212 free(bin);
213 return (-1);
214 }
215 if (BN_bin2bn(bin, len, value) == NULL) {
216 error("buffer_get_bignum2_ret: BN_bin2bn failed");
217 free(bin);
218 return (-1);
219 } 94 }
220 free(bin); 95 return 0;
221 return (0);
222} 96}
223 97
224void 98void
225buffer_get_bignum2(Buffer *buffer, BIGNUM *value) 99buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
226{ 100{
227 if (buffer_get_bignum2_ret(buffer, value) == -1) 101 if (buffer_get_bignum2_ret(buffer, value) == -1)
228 fatal("buffer_get_bignum2: buffer error"); 102 fatal("%s: buffer error", __func__);
229} 103}
diff --git a/bufec.c b/bufec.c
index 89482b906..749ce9d4c 100644
--- a/bufec.c
+++ b/bufec.c
@@ -1,6 +1,7 @@
1/* $OpenBSD: bufec.c,v 1.3 2014/01/31 16:39:19 tedu Exp $ */ 1/* $OpenBSD: bufec.c,v 1.4 2014/04/30 05:29:56 djm Exp $ */
2
2/* 3/*
3 * Copyright (c) 2010 Damien Miller <djm@mindrot.org> 4 * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
4 * 5 *
5 * Permission to use, copy, modify, and distribute this software for any 6 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above 7 * purpose with or without fee is hereby granted, provided that the above
@@ -15,73 +16,29 @@
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */ 17 */
17 18
18#include "includes.h" 19/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
19 20
20#ifdef OPENSSL_HAS_ECC 21#include "includes.h"
21 22
22#include <sys/types.h> 23#include <sys/types.h>
23 24
24#include <openssl/bn.h>
25#include <openssl/ec.h>
26
27#include <string.h>
28#include <stdarg.h>
29
30#include "xmalloc.h"
31#include "buffer.h" 25#include "buffer.h"
32#include "log.h" 26#include "log.h"
33#include "misc.h" 27#include "ssherr.h"
34 28
35/* 29#ifdef OPENSSL_HAS_ECC
36 * Maximum supported EC GFp field length is 528 bits. SEC1 uncompressed
37 * encoding represents this as two bitstring points that should each
38 * be no longer than the field length, SEC1 specifies a 1 byte
39 * point type header.
40 * Being paranoid here may insulate us to parsing problems in
41 * EC_POINT_oct2point.
42 */
43#define BUFFER_MAX_ECPOINT_LEN ((528*2 / 8) + 1)
44 30
45/*
46 * Append an EC_POINT to the buffer as a string containing a SEC1 encoded
47 * uncompressed point. Fortunately OpenSSL handles the gory details for us.
48 */
49int 31int
50buffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, 32buffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
51 const EC_POINT *point) 33 const EC_POINT *point)
52{ 34{
53 u_char *buf = NULL; 35 int ret;
54 size_t len;
55 BN_CTX *bnctx;
56 int ret = -1;
57 36
58 /* Determine length */ 37 if ((ret = sshbuf_put_ec(buffer, point, curve)) != 0) {
59 if ((bnctx = BN_CTX_new()) == NULL) 38 error("%s: %s", __func__, ssh_err(ret));
60 fatal("%s: BN_CTX_new failed", __func__); 39 return -1;
61 len = EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
62 NULL, 0, bnctx);
63 if (len > BUFFER_MAX_ECPOINT_LEN) {
64 error("%s: giant EC point: len = %lu (max %u)",
65 __func__, (u_long)len, BUFFER_MAX_ECPOINT_LEN);
66 goto out;
67 }
68 /* Convert */
69 buf = xmalloc(len);
70 if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
71 buf, len, bnctx) != len) {
72 error("%s: EC_POINT_point2oct length mismatch", __func__);
73 goto out;
74 }
75 /* Append */
76 buffer_put_string(buffer, buf, len);
77 ret = 0;
78 out:
79 if (buf != NULL) {
80 explicit_bzero(buf, len);
81 free(buf);
82 } 40 }
83 BN_CTX_free(bnctx); 41 return 0;
84 return ret;
85} 42}
86 43
87void 44void
@@ -96,43 +53,13 @@ int
96buffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, 53buffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
97 EC_POINT *point) 54 EC_POINT *point)
98{ 55{
99 u_char *buf; 56 int ret;
100 u_int len;
101 BN_CTX *bnctx;
102 int ret = -1;
103 57
104 if ((buf = buffer_get_string_ret(buffer, &len)) == NULL) { 58 if ((ret = sshbuf_get_ec(buffer, point, curve)) != 0) {
105 error("%s: invalid point", __func__); 59 error("%s: %s", __func__, ssh_err(ret));
106 return -1; 60 return -1;
107 } 61 }
108 if ((bnctx = BN_CTX_new()) == NULL) 62 return 0;
109 fatal("%s: BN_CTX_new failed", __func__);
110 if (len > BUFFER_MAX_ECPOINT_LEN) {
111 error("%s: EC_POINT too long: %u > max %u", __func__,
112 len, BUFFER_MAX_ECPOINT_LEN);
113 goto out;
114 }
115 if (len == 0) {
116 error("%s: EC_POINT buffer is empty", __func__);
117 goto out;
118 }
119 if (buf[0] != POINT_CONVERSION_UNCOMPRESSED) {
120 error("%s: EC_POINT is in an incorrect form: "
121 "0x%02x (want 0x%02x)", __func__, buf[0],
122 POINT_CONVERSION_UNCOMPRESSED);
123 goto out;
124 }
125 if (EC_POINT_oct2point(curve, point, buf, len, bnctx) != 1) {
126 error("buffer_get_bignum2_ret: BN_bin2bn failed");
127 goto out;
128 }
129 /* EC_POINT_oct2point verifies that the point is on the curve for us */
130 ret = 0;
131 out:
132 BN_CTX_free(bnctx);
133 explicit_bzero(buf, len);
134 free(buf);
135 return ret;
136} 63}
137 64
138void 65void
@@ -144,3 +71,4 @@ buffer_get_ecpoint(Buffer *buffer, const EC_GROUP *curve,
144} 71}
145 72
146#endif /* OPENSSL_HAS_ECC */ 73#endif /* OPENSSL_HAS_ECC */
74
diff --git a/buffer.c b/buffer.c
index d240f6753..c5f708ab2 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1,253 +1,118 @@
1/* $OpenBSD: buffer.c,v 1.35 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: buffer.c,v 1.36 2014/04/30 05:29:56 djm Exp $ */
2
2/* 3/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 *
5 * All rights reserved 6 * Permission to use, copy, modify, and distribute this software for any
6 * Functions for manipulating fifo buffers (that can grow if needed). 7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
7 * 9 *
8 * As far as I am concerned, the code I have written for this software 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * can be used freely for any purpose. Any derived versions of this 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * software must be clearly marked as such, and if the derived work is 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * incompatible with the protocol description in the RFC file, it must be 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * called by a name other than "ssh" or "Secure Shell". 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
13 */ 17 */
14 18
15#include "includes.h" 19/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
16 20
17#include <sys/param.h> 21#include "includes.h"
18 22
19#include <stdio.h> 23#include <sys/types.h>
20#include <string.h>
21#include <stdarg.h>
22#include <stdlib.h>
23 24
24#include "xmalloc.h"
25#include "buffer.h" 25#include "buffer.h"
26#include "log.h" 26#include "log.h"
27 27#include "ssherr.h"
28#define BUFFER_MAX_CHUNK 0x100000
29#define BUFFER_MAX_LEN 0xa00000
30#define BUFFER_ALLOCSZ 0x008000
31
32/* Initializes the buffer structure. */
33
34void
35buffer_init(Buffer *buffer)
36{
37 const u_int len = 4096;
38
39 buffer->alloc = 0;
40 buffer->buf = xmalloc(len);
41 buffer->alloc = len;
42 buffer->offset = 0;
43 buffer->end = 0;
44}
45
46/* Frees any memory used for the buffer. */
47
48void
49buffer_free(Buffer *buffer)
50{
51 if (buffer->alloc > 0) {
52 explicit_bzero(buffer->buf, buffer->alloc);
53 buffer->alloc = 0;
54 free(buffer->buf);
55 }
56}
57
58/*
59 * Clears any data from the buffer, making it empty. This does not actually
60 * zero the memory.
61 */
62
63void
64buffer_clear(Buffer *buffer)
65{
66 buffer->offset = 0;
67 buffer->end = 0;
68}
69
70/* Appends data to the buffer, expanding it if necessary. */
71 28
72void 29void
73buffer_append(Buffer *buffer, const void *data, u_int len) 30buffer_append(Buffer *buffer, const void *data, u_int len)
74{ 31{
75 void *p; 32 int ret;
76 p = buffer_append_space(buffer, len);
77 memcpy(p, data, len);
78}
79 33
80static int 34 if ((ret = sshbuf_put(buffer, data, len)) != 0)
81buffer_compact(Buffer *buffer) 35 fatal("%s: %s", __func__, ssh_err(ret));
82{
83 /*
84 * If the buffer is quite empty, but all data is at the end, move the
85 * data to the beginning.
86 */
87 if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) {
88 memmove(buffer->buf, buffer->buf + buffer->offset,
89 buffer->end - buffer->offset);
90 buffer->end -= buffer->offset;
91 buffer->offset = 0;
92 return (1);
93 }
94 return (0);
95} 36}
96 37
97/*
98 * Appends space to the buffer, expanding the buffer if necessary. This does
99 * not actually copy the data into the buffer, but instead returns a pointer
100 * to the allocated region.
101 */
102
103void * 38void *
104buffer_append_space(Buffer *buffer, u_int len) 39buffer_append_space(Buffer *buffer, u_int len)
105{ 40{
106 u_int newlen; 41 int ret;
107 void *p; 42 u_char *p;
108 43
109 if (len > BUFFER_MAX_CHUNK) 44 if ((ret = sshbuf_reserve(buffer, len, &p)) != 0)
110 fatal("buffer_append_space: len %u not supported", len); 45 fatal("%s: %s", __func__, ssh_err(ret));
111 46 return p;
112 /* If the buffer is empty, start using it from the beginning. */
113 if (buffer->offset == buffer->end) {
114 buffer->offset = 0;
115 buffer->end = 0;
116 }
117restart:
118 /* If there is enough space to store all data, store it now. */
119 if (buffer->end + len < buffer->alloc) {
120 p = buffer->buf + buffer->end;
121 buffer->end += len;
122 return p;
123 }
124
125 /* Compact data back to the start of the buffer if necessary */
126 if (buffer_compact(buffer))
127 goto restart;
128
129 /* Increase the size of the buffer and retry. */
130 newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ);
131 if (newlen > BUFFER_MAX_LEN)
132 fatal("buffer_append_space: alloc %u not supported",
133 newlen);
134 buffer->buf = xrealloc(buffer->buf, 1, newlen);
135 buffer->alloc = newlen;
136 goto restart;
137 /* NOTREACHED */
138} 47}
139 48
140/*
141 * Check whether an allocation of 'len' will fit in the buffer
142 * This must follow the same math as buffer_append_space
143 */
144int 49int
145buffer_check_alloc(Buffer *buffer, u_int len) 50buffer_check_alloc(Buffer *buffer, u_int len)
146{ 51{
147 if (buffer->offset == buffer->end) { 52 int ret = sshbuf_check_reserve(buffer, len);
148 buffer->offset = 0;
149 buffer->end = 0;
150 }
151 restart:
152 if (buffer->end + len < buffer->alloc)
153 return (1);
154 if (buffer_compact(buffer))
155 goto restart;
156 if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN)
157 return (1);
158 return (0);
159}
160
161/* Returns the number of bytes of data in the buffer. */
162 53
163u_int 54 if (ret == 0)
164buffer_len(const Buffer *buffer) 55 return 1;
165{ 56 if (ret == SSH_ERR_NO_BUFFER_SPACE)
166 return buffer->end - buffer->offset; 57 return 0;
58 fatal("%s: %s", __func__, ssh_err(ret));
167} 59}
168 60
169/* Gets data from the beginning of the buffer. */
170
171int 61int
172buffer_get_ret(Buffer *buffer, void *buf, u_int len) 62buffer_get_ret(Buffer *buffer, void *buf, u_int len)
173{ 63{
174 if (len > buffer->end - buffer->offset) { 64 int ret;
175 error("buffer_get_ret: trying to get more bytes %d than in buffer %d", 65
176 len, buffer->end - buffer->offset); 66 if ((ret = sshbuf_get(buffer, buf, len)) != 0) {
177 return (-1); 67 error("%s: %s", __func__, ssh_err(ret));
68 return -1;
178 } 69 }
179 memcpy(buf, buffer->buf + buffer->offset, len); 70 return 0;
180 buffer->offset += len;
181 return (0);
182} 71}
183 72
184void 73void
185buffer_get(Buffer *buffer, void *buf, u_int len) 74buffer_get(Buffer *buffer, void *buf, u_int len)
186{ 75{
187 if (buffer_get_ret(buffer, buf, len) == -1) 76 if (buffer_get_ret(buffer, buf, len) == -1)
188 fatal("buffer_get: buffer error"); 77 fatal("%s: buffer error", __func__);
189} 78}
190 79
191/* Consumes the given number of bytes from the beginning of the buffer. */
192
193int 80int
194buffer_consume_ret(Buffer *buffer, u_int bytes) 81buffer_consume_ret(Buffer *buffer, u_int bytes)
195{ 82{
196 if (bytes > buffer->end - buffer->offset) { 83 int ret = sshbuf_consume(buffer, bytes);
197 error("buffer_consume_ret: trying to get more bytes than in buffer"); 84
198 return (-1); 85 if (ret == 0)
199 } 86 return 0;
200 buffer->offset += bytes; 87 if (ret == SSH_ERR_MESSAGE_INCOMPLETE)
201 return (0); 88 return -1;
89 fatal("%s: %s", __func__, ssh_err(ret));
202} 90}
203 91
204void 92void
205buffer_consume(Buffer *buffer, u_int bytes) 93buffer_consume(Buffer *buffer, u_int bytes)
206{ 94{
207 if (buffer_consume_ret(buffer, bytes) == -1) 95 if (buffer_consume_ret(buffer, bytes) == -1)
208 fatal("buffer_consume: buffer error"); 96 fatal("%s: buffer error", __func__);
209} 97}
210 98
211/* Consumes the given number of bytes from the end of the buffer. */
212
213int 99int
214buffer_consume_end_ret(Buffer *buffer, u_int bytes) 100buffer_consume_end_ret(Buffer *buffer, u_int bytes)
215{ 101{
216 if (bytes > buffer->end - buffer->offset) 102 int ret = sshbuf_consume_end(buffer, bytes);
217 return (-1); 103
218 buffer->end -= bytes; 104 if (ret == 0)
219 return (0); 105 return 0;
106 if (ret == SSH_ERR_MESSAGE_INCOMPLETE)
107 return -1;
108 fatal("%s: %s", __func__, ssh_err(ret));
220} 109}
221 110
222void 111void
223buffer_consume_end(Buffer *buffer, u_int bytes) 112buffer_consume_end(Buffer *buffer, u_int bytes)
224{ 113{
225 if (buffer_consume_end_ret(buffer, bytes) == -1) 114 if (buffer_consume_end_ret(buffer, bytes) == -1)
226 fatal("buffer_consume_end: trying to get more bytes than in buffer"); 115 fatal("%s: buffer error", __func__);
227}
228
229/* Returns a pointer to the first used byte in the buffer. */
230
231void *
232buffer_ptr(const Buffer *buffer)
233{
234 return buffer->buf + buffer->offset;
235} 116}
236 117
237/* Dumps the contents of the buffer to stderr. */
238 118
239void
240buffer_dump(const Buffer *buffer)
241{
242 u_int i;
243 u_char *ucp = buffer->buf;
244
245 for (i = buffer->offset; i < buffer->end; i++) {
246 fprintf(stderr, "%02x", ucp[i]);
247 if ((i-buffer->offset)%16==15)
248 fprintf(stderr, "\r\n");
249 else if ((i-buffer->offset)%2==1)
250 fprintf(stderr, " ");
251 }
252 fprintf(stderr, "\r\n");
253}
diff --git a/buffer.h b/buffer.h
index 7df8a38fa..9d853edf2 100644
--- a/buffer.h
+++ b/buffer.h
@@ -1,57 +1,58 @@
1/* $OpenBSD: buffer.h,v 1.23 2014/01/12 08:13:13 djm Exp $ */ 1/* $OpenBSD: buffer.h,v 1.25 2014/04/30 05:29:56 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
5 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6 * All rights reserved
7 * Code for manipulating FIFO buffers.
8 * 5 *
9 * As far as I am concerned, the code I have written for this software 6 * Permission to use, copy, modify, and distribute this software for any
10 * can be used freely for any purpose. Any derived versions of this 7 * purpose with or without fee is hereby granted, provided that the above
11 * software must be clearly marked as such, and if the derived work is 8 * copyright notice and this permission notice appear in all copies.
12 * incompatible with the protocol description in the RFC file, it must be 9 *
13 * called by a name other than "ssh" or "Secure Shell". 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */ 17 */
15 18
19/* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */
20
16#ifndef BUFFER_H 21#ifndef BUFFER_H
17#define BUFFER_H 22#define BUFFER_H
18 23
19typedef struct { 24#include "sshbuf.h"
20 u_char *buf; /* Buffer for data. */ 25
21 u_int alloc; /* Number of bytes allocated for data. */ 26typedef struct sshbuf Buffer;
22 u_int offset; /* Offset of first byte containing data. */
23 u_int end; /* Offset of last byte containing data. */
24} Buffer;
25 27
26void buffer_init(Buffer *); 28#define buffer_init(b) sshbuf_init(b)
27void buffer_clear(Buffer *); 29#define buffer_clear(b) sshbuf_reset(b)
28void buffer_free(Buffer *); 30#define buffer_free(b) sshbuf_free(b)
31#define buffer_dump(b) sshbuf_dump(b, stderr)
29 32
30u_int buffer_len(const Buffer *); 33/* XXX cast is safe: sshbuf never stores more than len 2^31 */
31void *buffer_ptr(const Buffer *); 34#define buffer_len(b) ((u_int) sshbuf_len(b))
35#define buffer_ptr(b) sshbuf_mutable_ptr(b)
32 36
33void buffer_append(Buffer *, const void *, u_int); 37void buffer_append(Buffer *, const void *, u_int);
34void *buffer_append_space(Buffer *, u_int); 38void *buffer_append_space(Buffer *, u_int);
35
36int buffer_check_alloc(Buffer *, u_int); 39int buffer_check_alloc(Buffer *, u_int);
37
38void buffer_get(Buffer *, void *, u_int); 40void buffer_get(Buffer *, void *, u_int);
39 41
40void buffer_consume(Buffer *, u_int); 42void buffer_consume(Buffer *, u_int);
41void buffer_consume_end(Buffer *, u_int); 43void buffer_consume_end(Buffer *, u_int);
42 44
43void buffer_dump(const Buffer *);
44 45
45int buffer_get_ret(Buffer *, void *, u_int); 46int buffer_get_ret(Buffer *, void *, u_int);
46int buffer_consume_ret(Buffer *, u_int); 47int buffer_consume_ret(Buffer *, u_int);
47int buffer_consume_end_ret(Buffer *, u_int); 48int buffer_consume_end_ret(Buffer *, u_int);
48 49
49#include <openssl/bn.h> 50#include <openssl/bn.h>
50
51void buffer_put_bignum(Buffer *, const BIGNUM *); 51void buffer_put_bignum(Buffer *, const BIGNUM *);
52void buffer_put_bignum2(Buffer *, const BIGNUM *); 52void buffer_put_bignum2(Buffer *, const BIGNUM *);
53void buffer_get_bignum(Buffer *, BIGNUM *); 53void buffer_get_bignum(Buffer *, BIGNUM *);
54void buffer_get_bignum2(Buffer *, BIGNUM *); 54void buffer_get_bignum2(Buffer *, BIGNUM *);
55void buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int);
55 56
56u_short buffer_get_short(Buffer *); 57u_short buffer_get_short(Buffer *);
57void buffer_put_short(Buffer *, u_short); 58void buffer_put_short(Buffer *, u_short);
@@ -66,13 +67,12 @@ int buffer_get_char(Buffer *);
66void buffer_put_char(Buffer *, int); 67void buffer_put_char(Buffer *, int);
67 68
68void *buffer_get_string(Buffer *, u_int *); 69void *buffer_get_string(Buffer *, u_int *);
69void *buffer_get_string_ptr(Buffer *, u_int *); 70const void *buffer_get_string_ptr(Buffer *, u_int *);
70void buffer_put_string(Buffer *, const void *, u_int); 71void buffer_put_string(Buffer *, const void *, u_int);
71char *buffer_get_cstring(Buffer *, u_int *); 72char *buffer_get_cstring(Buffer *, u_int *);
72void buffer_put_cstring(Buffer *, const char *); 73void buffer_put_cstring(Buffer *, const char *);
73 74
74#define buffer_skip_string(b) \ 75#define buffer_skip_string(b) (void)buffer_get_string_ptr(b, NULL);
75 do { u_int l = buffer_get_int(b); buffer_consume(b, l); } while (0)
76 76
77int buffer_put_bignum_ret(Buffer *, const BIGNUM *); 77int buffer_put_bignum_ret(Buffer *, const BIGNUM *);
78int buffer_get_bignum_ret(Buffer *, BIGNUM *); 78int buffer_get_bignum_ret(Buffer *, BIGNUM *);
@@ -83,20 +83,16 @@ int buffer_get_int_ret(u_int *, Buffer *);
83int buffer_get_int64_ret(u_int64_t *, Buffer *); 83int buffer_get_int64_ret(u_int64_t *, Buffer *);
84void *buffer_get_string_ret(Buffer *, u_int *); 84void *buffer_get_string_ret(Buffer *, u_int *);
85char *buffer_get_cstring_ret(Buffer *, u_int *); 85char *buffer_get_cstring_ret(Buffer *, u_int *);
86void *buffer_get_string_ptr_ret(Buffer *, u_int *); 86const void *buffer_get_string_ptr_ret(Buffer *, u_int *);
87int buffer_get_char_ret(u_char *, Buffer *); 87int buffer_get_char_ret(char *, Buffer *);
88
89void *buffer_get_bignum2_as_string_ret(Buffer *, u_int *);
90void *buffer_get_bignum2_as_string(Buffer *, u_int *);
91void buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int);
92 88
93#ifdef OPENSSL_HAS_ECC 89#ifdef OPENSSL_HAS_ECC
94#include <openssl/ec.h> 90#include <openssl/ec.h>
95
96int buffer_put_ecpoint_ret(Buffer *, const EC_GROUP *, const EC_POINT *); 91int buffer_put_ecpoint_ret(Buffer *, const EC_GROUP *, const EC_POINT *);
97void buffer_put_ecpoint(Buffer *, const EC_GROUP *, const EC_POINT *); 92void buffer_put_ecpoint(Buffer *, const EC_GROUP *, const EC_POINT *);
98int buffer_get_ecpoint_ret(Buffer *, const EC_GROUP *, EC_POINT *); 93int buffer_get_ecpoint_ret(Buffer *, const EC_GROUP *, EC_POINT *);
99void buffer_get_ecpoint(Buffer *, const EC_GROUP *, EC_POINT *); 94void buffer_get_ecpoint(Buffer *, const EC_GROUP *, EC_POINT *);
100#endif 95#endif
101 96
102#endif /* BUFFER_H */ 97#endif /* BUFFER_H */
98
diff --git a/canohost.c b/canohost.c
index a61a8c94d..a3e3bbff8 100644
--- a/canohost.c
+++ b/canohost.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: canohost.c,v 1.70 2014/01/19 04:17:29 dtucker Exp $ */ 1/* $OpenBSD: canohost.c,v 1.71 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -16,6 +16,7 @@
16 16
17#include <sys/types.h> 17#include <sys/types.h>
18#include <sys/socket.h> 18#include <sys/socket.h>
19#include <sys/un.h>
19 20
20#include <netinet/in.h> 21#include <netinet/in.h>
21#include <arpa/inet.h> 22#include <arpa/inet.h>
@@ -262,6 +263,11 @@ get_socket_address(int sock, int remote, int flags)
262 if (addr.ss_family == AF_INET6) 263 if (addr.ss_family == AF_INET6)
263 addrlen = sizeof(struct sockaddr_in6); 264 addrlen = sizeof(struct sockaddr_in6);
264 265
266 if (addr.ss_family == AF_UNIX) {
267 /* Get the Unix domain socket path. */
268 return xstrdup(((struct sockaddr_un *)&addr)->sun_path);
269 }
270
265 ipv64_normalise_mapped(&addr, &addrlen); 271 ipv64_normalise_mapped(&addr, &addrlen);
266 272
267 /* Get the address in ascii. */ 273 /* Get the address in ascii. */
@@ -384,6 +390,10 @@ get_sock_port(int sock, int local)
384 if (from.ss_family == AF_INET6) 390 if (from.ss_family == AF_INET6)
385 fromlen = sizeof(struct sockaddr_in6); 391 fromlen = sizeof(struct sockaddr_in6);
386 392
393 /* Unix domain sockets don't have a port number. */
394 if (from.ss_family == AF_UNIX)
395 return 0;
396
387 /* Return port number. */ 397 /* Return port number. */
388 if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, 398 if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
389 strport, sizeof(strport), NI_NUMERICSERV)) != 0) 399 strport, sizeof(strport), NI_NUMERICSERV)) != 0)
diff --git a/chacha.h b/chacha.h
index 4ef42cc70..40eaf2d90 100644
--- a/chacha.h
+++ b/chacha.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: chacha.h,v 1.1 2013/11/21 00:45:44 djm Exp $ */ 1/* $OpenBSD: chacha.h,v 1.3 2014/05/02 03:27:54 djm Exp $ */
2 2
3/* 3/*
4chacha-merged.c version 20080118 4chacha-merged.c version 20080118
diff --git a/channels.c b/channels.c
index 9efe89c9c..d67fdf48b 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.331 2014/02/26 20:29:29 djm Exp $ */ 1/* $OpenBSD: channels.c,v 1.336 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -42,6 +42,7 @@
42#include "includes.h" 42#include "includes.h"
43 43
44#include <sys/types.h> 44#include <sys/types.h>
45#include <sys/stat.h>
45#include <sys/ioctl.h> 46#include <sys/ioctl.h>
46#include <sys/un.h> 47#include <sys/un.h>
47#include <sys/socket.h> 48#include <sys/socket.h>
@@ -107,10 +108,15 @@ static int channel_max_fd = 0;
107 * a corrupt remote server from accessing arbitrary TCP/IP ports on our local 108 * a corrupt remote server from accessing arbitrary TCP/IP ports on our local
108 * network (which might be behind a firewall). 109 * network (which might be behind a firewall).
109 */ 110 */
111/* XXX: streamlocal wants a path instead of host:port */
112/* Overload host_to_connect; we could just make this match Forward */
113/* XXX - can we use listen_host instead of listen_path? */
110typedef struct { 114typedef struct {
111 char *host_to_connect; /* Connect to 'host'. */ 115 char *host_to_connect; /* Connect to 'host'. */
112 u_short port_to_connect; /* Connect to 'port'. */ 116 int port_to_connect; /* Connect to 'port'. */
113 u_short listen_port; /* Remote side should listen port number. */ 117 char *listen_host; /* Remote side should listen address. */
118 char *listen_path; /* Remote side should listen path. */
119 int listen_port; /* Remote side should listen port. */
114} ForwardPermission; 120} ForwardPermission;
115 121
116/* List of all permitted host/port pairs to connect by the user. */ 122/* List of all permitted host/port pairs to connect by the user. */
@@ -473,6 +479,8 @@ channel_stop_listening(void)
473 case SSH_CHANNEL_PORT_LISTENER: 479 case SSH_CHANNEL_PORT_LISTENER:
474 case SSH_CHANNEL_RPORT_LISTENER: 480 case SSH_CHANNEL_RPORT_LISTENER:
475 case SSH_CHANNEL_X11_LISTENER: 481 case SSH_CHANNEL_X11_LISTENER:
482 case SSH_CHANNEL_UNIX_LISTENER:
483 case SSH_CHANNEL_RUNIX_LISTENER:
476 channel_close_fd(&c->sock); 484 channel_close_fd(&c->sock);
477 channel_free(c); 485 channel_free(c);
478 break; 486 break;
@@ -535,6 +543,8 @@ channel_still_open(void)
535 case SSH_CHANNEL_CONNECTING: 543 case SSH_CHANNEL_CONNECTING:
536 case SSH_CHANNEL_ZOMBIE: 544 case SSH_CHANNEL_ZOMBIE:
537 case SSH_CHANNEL_ABANDONED: 545 case SSH_CHANNEL_ABANDONED:
546 case SSH_CHANNEL_UNIX_LISTENER:
547 case SSH_CHANNEL_RUNIX_LISTENER:
538 continue; 548 continue;
539 case SSH_CHANNEL_LARVAL: 549 case SSH_CHANNEL_LARVAL:
540 if (!compat20) 550 if (!compat20)
@@ -581,6 +591,8 @@ channel_find_open(void)
581 case SSH_CHANNEL_CONNECTING: 591 case SSH_CHANNEL_CONNECTING:
582 case SSH_CHANNEL_ZOMBIE: 592 case SSH_CHANNEL_ZOMBIE:
583 case SSH_CHANNEL_ABANDONED: 593 case SSH_CHANNEL_ABANDONED:
594 case SSH_CHANNEL_UNIX_LISTENER:
595 case SSH_CHANNEL_RUNIX_LISTENER:
584 continue; 596 continue;
585 case SSH_CHANNEL_LARVAL: 597 case SSH_CHANNEL_LARVAL:
586 case SSH_CHANNEL_AUTH_SOCKET: 598 case SSH_CHANNEL_AUTH_SOCKET:
@@ -631,6 +643,8 @@ channel_open_message(void)
631 case SSH_CHANNEL_ABANDONED: 643 case SSH_CHANNEL_ABANDONED:
632 case SSH_CHANNEL_MUX_CLIENT: 644 case SSH_CHANNEL_MUX_CLIENT:
633 case SSH_CHANNEL_MUX_LISTENER: 645 case SSH_CHANNEL_MUX_LISTENER:
646 case SSH_CHANNEL_UNIX_LISTENER:
647 case SSH_CHANNEL_RUNIX_LISTENER:
634 continue; 648 continue;
635 case SSH_CHANNEL_LARVAL: 649 case SSH_CHANNEL_LARVAL:
636 case SSH_CHANNEL_OPENING: 650 case SSH_CHANNEL_OPENING:
@@ -1386,7 +1400,6 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
1386static void 1400static void
1387port_open_helper(Channel *c, char *rtype) 1401port_open_helper(Channel *c, char *rtype)
1388{ 1402{
1389 int direct;
1390 char buf[1024]; 1403 char buf[1024];
1391 char *local_ipaddr = get_local_ipaddr(c->sock); 1404 char *local_ipaddr = get_local_ipaddr(c->sock);
1392 int local_port = c->sock == -1 ? 65536 : get_sock_port(c->sock, 1); 1405 int local_port = c->sock == -1 ? 65536 : get_sock_port(c->sock, 1);
@@ -1400,8 +1413,6 @@ port_open_helper(Channel *c, char *rtype)
1400 remote_port = 65535; 1413 remote_port = 65535;
1401 } 1414 }
1402 1415
1403 direct = (strcmp(rtype, "direct-tcpip") == 0);
1404
1405 snprintf(buf, sizeof buf, 1416 snprintf(buf, sizeof buf,
1406 "%s: listening port %d for %.100s port %d, " 1417 "%s: listening port %d for %.100s port %d, "
1407 "connect from %.200s port %d to %.100s port %d", 1418 "connect from %.200s port %d to %.100s port %d",
@@ -1417,18 +1428,29 @@ port_open_helper(Channel *c, char *rtype)
1417 packet_put_int(c->self); 1428 packet_put_int(c->self);
1418 packet_put_int(c->local_window_max); 1429 packet_put_int(c->local_window_max);
1419 packet_put_int(c->local_maxpacket); 1430 packet_put_int(c->local_maxpacket);
1420 if (direct) { 1431 if (strcmp(rtype, "direct-tcpip") == 0) {
1421 /* target host, port */ 1432 /* target host, port */
1422 packet_put_cstring(c->path); 1433 packet_put_cstring(c->path);
1423 packet_put_int(c->host_port); 1434 packet_put_int(c->host_port);
1435 } else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) {
1436 /* target path */
1437 packet_put_cstring(c->path);
1438 } else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
1439 /* listen path */
1440 packet_put_cstring(c->path);
1424 } else { 1441 } else {
1425 /* listen address, port */ 1442 /* listen address, port */
1426 packet_put_cstring(c->path); 1443 packet_put_cstring(c->path);
1427 packet_put_int(local_port); 1444 packet_put_int(local_port);
1428 } 1445 }
1429 /* originator host and port */ 1446 if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
1430 packet_put_cstring(remote_ipaddr); 1447 /* reserved for future owner/mode info */
1431 packet_put_int((u_int)remote_port); 1448 packet_put_cstring("");
1449 } else {
1450 /* originator host and port */
1451 packet_put_cstring(remote_ipaddr);
1452 packet_put_int((u_int)remote_port);
1453 }
1432 packet_send(); 1454 packet_send();
1433 } else { 1455 } else {
1434 packet_start(SSH_MSG_PORT_OPEN); 1456 packet_start(SSH_MSG_PORT_OPEN);
@@ -1478,14 +1500,18 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
1478 if (c->type == SSH_CHANNEL_RPORT_LISTENER) { 1500 if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
1479 nextstate = SSH_CHANNEL_OPENING; 1501 nextstate = SSH_CHANNEL_OPENING;
1480 rtype = "forwarded-tcpip"; 1502 rtype = "forwarded-tcpip";
1503 } else if (c->type == SSH_CHANNEL_RUNIX_LISTENER) {
1504 nextstate = SSH_CHANNEL_OPENING;
1505 rtype = "forwarded-streamlocal@openssh.com";
1506 } else if (c->host_port == PORT_STREAMLOCAL) {
1507 nextstate = SSH_CHANNEL_OPENING;
1508 rtype = "direct-streamlocal@openssh.com";
1509 } else if (c->host_port == 0) {
1510 nextstate = SSH_CHANNEL_DYNAMIC;
1511 rtype = "dynamic-tcpip";
1481 } else { 1512 } else {
1482 if (c->host_port == 0) { 1513 nextstate = SSH_CHANNEL_OPENING;
1483 nextstate = SSH_CHANNEL_DYNAMIC; 1514 rtype = "direct-tcpip";
1484 rtype = "dynamic-tcpip";
1485 } else {
1486 nextstate = SSH_CHANNEL_OPENING;
1487 rtype = "direct-tcpip";
1488 }
1489 } 1515 }
1490 1516
1491 addrlen = sizeof(addr); 1517 addrlen = sizeof(addr);
@@ -1498,7 +1524,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
1498 c->notbefore = monotime() + 1; 1524 c->notbefore = monotime() + 1;
1499 return; 1525 return;
1500 } 1526 }
1501 set_nodelay(newsock); 1527 if (c->host_port != PORT_STREAMLOCAL)
1528 set_nodelay(newsock);
1502 nc = channel_new(rtype, nextstate, newsock, newsock, -1, 1529 nc = channel_new(rtype, nextstate, newsock, newsock, -1,
1503 c->local_window_max, c->local_maxpacket, 0, rtype, 1); 1530 c->local_window_max, c->local_maxpacket, 0, rtype, 1);
1504 nc->listening_port = c->listening_port; 1531 nc->listening_port = c->listening_port;
@@ -1987,6 +2014,8 @@ channel_handler_init_20(void)
1987 channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; 2014 channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
1988 channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; 2015 channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
1989 channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; 2016 channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener;
2017 channel_pre[SSH_CHANNEL_UNIX_LISTENER] = &channel_pre_listener;
2018 channel_pre[SSH_CHANNEL_RUNIX_LISTENER] = &channel_pre_listener;
1990 channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; 2019 channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
1991 channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 2020 channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
1992 channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 2021 channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
@@ -1997,6 +2026,8 @@ channel_handler_init_20(void)
1997 channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; 2026 channel_post[SSH_CHANNEL_OPEN] = &channel_post_open;
1998 channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 2027 channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
1999 channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; 2028 channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener;
2029 channel_post[SSH_CHANNEL_UNIX_LISTENER] = &channel_post_port_listener;
2030 channel_post[SSH_CHANNEL_RUNIX_LISTENER] = &channel_post_port_listener;
2000 channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; 2031 channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
2001 channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 2032 channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
2002 channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 2033 channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
@@ -2315,7 +2346,7 @@ void
2315channel_input_data(int type, u_int32_t seq, void *ctxt) 2346channel_input_data(int type, u_int32_t seq, void *ctxt)
2316{ 2347{
2317 int id; 2348 int id;
2318 char *data; 2349 const u_char *data;
2319 u_int data_len, win_len; 2350 u_int data_len, win_len;
2320 Channel *c; 2351 Channel *c;
2321 2352
@@ -2637,7 +2668,7 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt)
2637 originator_string = xstrdup("unknown (remote did not supply name)"); 2668 originator_string = xstrdup("unknown (remote did not supply name)");
2638 } 2669 }
2639 packet_check_eom(); 2670 packet_check_eom();
2640 c = channel_connect_to(host, host_port, 2671 c = channel_connect_to_port(host, host_port,
2641 "connected socket", originator_string); 2672 "connected socket", originator_string);
2642 free(originator_string); 2673 free(originator_string);
2643 free(host); 2674 free(host);
@@ -2700,23 +2731,24 @@ channel_set_af(int af)
2700 * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR 2731 * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
2701 * "" (empty string), "*" -> wildcard v4/v6 2732 * "" (empty string), "*" -> wildcard v4/v6
2702 * "localhost" -> loopback v4/v6 2733 * "localhost" -> loopback v4/v6
2734 * "127.0.0.1" / "::1" -> accepted even if gateway_ports isn't set
2703 */ 2735 */
2704static const char * 2736static const char *
2705channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, 2737channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
2706 int is_client, int gateway_ports) 2738 int is_client, struct ForwardOptions *fwd_opts)
2707{ 2739{
2708 const char *addr = NULL; 2740 const char *addr = NULL;
2709 int wildcard = 0; 2741 int wildcard = 0;
2710 2742
2711 if (listen_addr == NULL) { 2743 if (listen_addr == NULL) {
2712 /* No address specified: default to gateway_ports setting */ 2744 /* No address specified: default to gateway_ports setting */
2713 if (gateway_ports) 2745 if (fwd_opts->gateway_ports)
2714 wildcard = 1; 2746 wildcard = 1;
2715 } else if (gateway_ports || is_client) { 2747 } else if (fwd_opts->gateway_ports || is_client) {
2716 if (((datafellows & SSH_OLD_FORWARD_ADDR) && 2748 if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
2717 strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) || 2749 strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
2718 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 || 2750 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
2719 (!is_client && gateway_ports == 1)) { 2751 (!is_client && fwd_opts->gateway_ports == 1)) {
2720 wildcard = 1; 2752 wildcard = 1;
2721 /* 2753 /*
2722 * Notify client if they requested a specific listen 2754 * Notify client if they requested a specific listen
@@ -2729,9 +2761,20 @@ channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
2729 "\"%s\" overridden by server " 2761 "\"%s\" overridden by server "
2730 "GatewayPorts", listen_addr); 2762 "GatewayPorts", listen_addr);
2731 } 2763 }
2732 } 2764 } else if (strcmp(listen_addr, "localhost") != 0 ||
2733 else if (strcmp(listen_addr, "localhost") != 0) 2765 strcmp(listen_addr, "127.0.0.1") == 0 ||
2766 strcmp(listen_addr, "::1") == 0) {
2767 /* Accept localhost address when GatewayPorts=yes */
2734 addr = listen_addr; 2768 addr = listen_addr;
2769 }
2770 } else if (strcmp(listen_addr, "127.0.0.1") == 0 ||
2771 strcmp(listen_addr, "::1") == 0) {
2772 /*
2773 * If a specific IPv4/IPv6 localhost address has been
2774 * requested then accept it even if gateway_ports is in
2775 * effect. This allows the client to prefer IPv4 or IPv6.
2776 */
2777 addr = listen_addr;
2735 } 2778 }
2736 if (wildcardp != NULL) 2779 if (wildcardp != NULL)
2737 *wildcardp = wildcard; 2780 *wildcardp = wildcard;
@@ -2739,9 +2782,8 @@ channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
2739} 2782}
2740 2783
2741static int 2784static int
2742channel_setup_fwd_listener(int type, const char *listen_addr, 2785channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
2743 u_short listen_port, int *allocated_listen_port, 2786 int *allocated_listen_port, struct ForwardOptions *fwd_opts)
2744 const char *host_to_connect, u_short port_to_connect, int gateway_ports)
2745{ 2787{
2746 Channel *c; 2788 Channel *c;
2747 int sock, r, success = 0, wildcard = 0, is_client; 2789 int sock, r, success = 0, wildcard = 0, is_client;
@@ -2751,7 +2793,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2751 in_port_t *lport_p; 2793 in_port_t *lport_p;
2752 2794
2753 host = (type == SSH_CHANNEL_RPORT_LISTENER) ? 2795 host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
2754 listen_addr : host_to_connect; 2796 fwd->listen_host : fwd->connect_host;
2755 is_client = (type == SSH_CHANNEL_PORT_LISTENER); 2797 is_client = (type == SSH_CHANNEL_PORT_LISTENER);
2756 2798
2757 if (host == NULL) { 2799 if (host == NULL) {
@@ -2764,9 +2806,9 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2764 } 2806 }
2765 2807
2766 /* Determine the bind address, cf. channel_fwd_bind_addr() comment */ 2808 /* Determine the bind address, cf. channel_fwd_bind_addr() comment */
2767 addr = channel_fwd_bind_addr(listen_addr, &wildcard, 2809 addr = channel_fwd_bind_addr(fwd->listen_host, &wildcard,
2768 is_client, gateway_ports); 2810 is_client, fwd_opts);
2769 debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s", 2811 debug3("%s: type %d wildcard %d addr %s", __func__,
2770 type, wildcard, (addr == NULL) ? "NULL" : addr); 2812 type, wildcard, (addr == NULL) ? "NULL" : addr);
2771 2813
2772 /* 2814 /*
@@ -2777,15 +2819,14 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2777 hints.ai_family = IPv4or6; 2819 hints.ai_family = IPv4or6;
2778 hints.ai_flags = wildcard ? AI_PASSIVE : 0; 2820 hints.ai_flags = wildcard ? AI_PASSIVE : 0;
2779 hints.ai_socktype = SOCK_STREAM; 2821 hints.ai_socktype = SOCK_STREAM;
2780 snprintf(strport, sizeof strport, "%d", listen_port); 2822 snprintf(strport, sizeof strport, "%d", fwd->listen_port);
2781 if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { 2823 if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
2782 if (addr == NULL) { 2824 if (addr == NULL) {
2783 /* This really shouldn't happen */ 2825 /* This really shouldn't happen */
2784 packet_disconnect("getaddrinfo: fatal error: %s", 2826 packet_disconnect("getaddrinfo: fatal error: %s",
2785 ssh_gai_strerror(r)); 2827 ssh_gai_strerror(r));
2786 } else { 2828 } else {
2787 error("channel_setup_fwd_listener: " 2829 error("%s: getaddrinfo(%.64s): %s", __func__, addr,
2788 "getaddrinfo(%.64s): %s", addr,
2789 ssh_gai_strerror(r)); 2830 ssh_gai_strerror(r));
2790 } 2831 }
2791 return 0; 2832 return 0;
@@ -2809,13 +2850,13 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2809 * If allocating a port for -R forwards, then use the 2850 * If allocating a port for -R forwards, then use the
2810 * same port for all address families. 2851 * same port for all address families.
2811 */ 2852 */
2812 if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && 2853 if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
2813 allocated_listen_port != NULL && *allocated_listen_port > 0) 2854 allocated_listen_port != NULL && *allocated_listen_port > 0)
2814 *lport_p = htons(*allocated_listen_port); 2855 *lport_p = htons(*allocated_listen_port);
2815 2856
2816 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), 2857 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
2817 strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 2858 strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
2818 error("channel_setup_fwd_listener: getnameinfo failed"); 2859 error("%s: getnameinfo failed", __func__);
2819 continue; 2860 continue;
2820 } 2861 }
2821 /* Create a port to listen for the host. */ 2862 /* Create a port to listen for the host. */
@@ -2852,10 +2893,10 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2852 } 2893 }
2853 2894
2854 /* 2895 /*
2855 * listen_port == 0 requests a dynamically allocated port - 2896 * fwd->listen_port == 0 requests a dynamically allocated port -
2856 * record what we got. 2897 * record what we got.
2857 */ 2898 */
2858 if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && 2899 if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
2859 allocated_listen_port != NULL && 2900 allocated_listen_port != NULL &&
2860 *allocated_listen_port == 0) { 2901 *allocated_listen_port == 0) {
2861 *allocated_listen_port = get_sock_port(sock, 1); 2902 *allocated_listen_port = get_sock_port(sock, 1);
@@ -2868,24 +2909,98 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2868 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 2909 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
2869 0, "port listener", 1); 2910 0, "port listener", 1);
2870 c->path = xstrdup(host); 2911 c->path = xstrdup(host);
2871 c->host_port = port_to_connect; 2912 c->host_port = fwd->connect_port;
2872 c->listening_addr = addr == NULL ? NULL : xstrdup(addr); 2913 c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
2873 if (listen_port == 0 && allocated_listen_port != NULL && 2914 if (fwd->listen_port == 0 && allocated_listen_port != NULL &&
2874 !(datafellows & SSH_BUG_DYNAMIC_RPORT)) 2915 !(datafellows & SSH_BUG_DYNAMIC_RPORT))
2875 c->listening_port = *allocated_listen_port; 2916 c->listening_port = *allocated_listen_port;
2876 else 2917 else
2877 c->listening_port = listen_port; 2918 c->listening_port = fwd->listen_port;
2878 success = 1; 2919 success = 1;
2879 } 2920 }
2880 if (success == 0) 2921 if (success == 0)
2881 error("channel_setup_fwd_listener: cannot listen to port: %d", 2922 error("%s: cannot listen to port: %d", __func__,
2882 listen_port); 2923 fwd->listen_port);
2883 freeaddrinfo(aitop); 2924 freeaddrinfo(aitop);
2884 return success; 2925 return success;
2885} 2926}
2886 2927
2887int 2928static int
2888channel_cancel_rport_listener(const char *host, u_short port) 2929channel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd,
2930 struct ForwardOptions *fwd_opts)
2931{
2932 struct sockaddr_un sunaddr;
2933 const char *path;
2934 Channel *c;
2935 int port, sock;
2936 mode_t omask;
2937
2938 switch (type) {
2939 case SSH_CHANNEL_UNIX_LISTENER:
2940 if (fwd->connect_path != NULL) {
2941 if (strlen(fwd->connect_path) > sizeof(sunaddr.sun_path)) {
2942 error("Local connecting path too long: %s",
2943 fwd->connect_path);
2944 return 0;
2945 }
2946 path = fwd->connect_path;
2947 port = PORT_STREAMLOCAL;
2948 } else {
2949 if (fwd->connect_host == NULL) {
2950 error("No forward host name.");
2951 return 0;
2952 }
2953 if (strlen(fwd->connect_host) >= NI_MAXHOST) {
2954 error("Forward host name too long.");
2955 return 0;
2956 }
2957 path = fwd->connect_host;
2958 port = fwd->connect_port;
2959 }
2960 break;
2961 case SSH_CHANNEL_RUNIX_LISTENER:
2962 path = fwd->listen_path;
2963 port = PORT_STREAMLOCAL;
2964 break;
2965 default:
2966 error("%s: unexpected channel type %d", __func__, type);
2967 return 0;
2968 }
2969
2970 if (fwd->listen_path == NULL) {
2971 error("No forward path name.");
2972 return 0;
2973 }
2974 if (strlen(fwd->listen_path) > sizeof(sunaddr.sun_path)) {
2975 error("Local listening path too long: %s", fwd->listen_path);
2976 return 0;
2977 }
2978
2979 debug3("%s: type %d path %s", __func__, type, fwd->listen_path);
2980
2981 /* Start a Unix domain listener. */
2982 omask = umask(fwd_opts->streamlocal_bind_mask);
2983 sock = unix_listener(fwd->listen_path, SSH_LISTEN_BACKLOG,
2984 fwd_opts->streamlocal_bind_unlink);
2985 umask(omask);
2986 if (sock < 0)
2987 return 0;
2988
2989 debug("Local forwarding listening on path %s.", fwd->listen_path);
2990
2991 /* Allocate a channel number for the socket. */
2992 c = channel_new("unix listener", type, sock, sock, -1,
2993 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
2994 0, "unix listener", 1);
2995 c->path = xstrdup(path);
2996 c->host_port = port;
2997 c->listening_port = PORT_STREAMLOCAL;
2998 c->listening_addr = xstrdup(fwd->listen_path);
2999 return 1;
3000}
3001
3002static int
3003channel_cancel_rport_listener_tcpip(const char *host, u_short port)
2889{ 3004{
2890 u_int i; 3005 u_int i;
2891 int found = 0; 3006 int found = 0;
@@ -2904,13 +3019,44 @@ channel_cancel_rport_listener(const char *host, u_short port)
2904 return (found); 3019 return (found);
2905} 3020}
2906 3021
3022static int
3023channel_cancel_rport_listener_streamlocal(const char *path)
3024{
3025 u_int i;
3026 int found = 0;
3027
3028 for (i = 0; i < channels_alloc; i++) {
3029 Channel *c = channels[i];
3030 if (c == NULL || c->type != SSH_CHANNEL_RUNIX_LISTENER)
3031 continue;
3032 if (c->path == NULL)
3033 continue;
3034 if (strcmp(c->path, path) == 0) {
3035 debug2("%s: close channel %d", __func__, i);
3036 channel_free(c);
3037 found = 1;
3038 }
3039 }
3040
3041 return (found);
3042}
3043
2907int 3044int
2908channel_cancel_lport_listener(const char *lhost, u_short lport, 3045channel_cancel_rport_listener(struct Forward *fwd)
2909 int cport, int gateway_ports) 3046{
3047 if (fwd->listen_path != NULL)
3048 return channel_cancel_rport_listener_streamlocal(fwd->listen_path);
3049 else
3050 return channel_cancel_rport_listener_tcpip(fwd->listen_host, fwd->listen_port);
3051}
3052
3053static int
3054channel_cancel_lport_listener_tcpip(const char *lhost, u_short lport,
3055 int cport, struct ForwardOptions *fwd_opts)
2910{ 3056{
2911 u_int i; 3057 u_int i;
2912 int found = 0; 3058 int found = 0;
2913 const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, gateway_ports); 3059 const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, fwd_opts);
2914 3060
2915 for (i = 0; i < channels_alloc; i++) { 3061 for (i = 0; i < channels_alloc; i++) {
2916 Channel *c = channels[i]; 3062 Channel *c = channels[i];
@@ -2939,24 +3085,68 @@ channel_cancel_lport_listener(const char *lhost, u_short lport,
2939 return (found); 3085 return (found);
2940} 3086}
2941 3087
3088static int
3089channel_cancel_lport_listener_streamlocal(const char *path)
3090{
3091 u_int i;
3092 int found = 0;
3093
3094 if (path == NULL) {
3095 error("%s: no path specified.", __func__);
3096 return 0;
3097 }
3098
3099 for (i = 0; i < channels_alloc; i++) {
3100 Channel *c = channels[i];
3101 if (c == NULL || c->type != SSH_CHANNEL_UNIX_LISTENER)
3102 continue;
3103 if (c->listening_addr == NULL)
3104 continue;
3105 if (strcmp(c->listening_addr, path) == 0) {
3106 debug2("%s: close channel %d", __func__, i);
3107 channel_free(c);
3108 found = 1;
3109 }
3110 }
3111
3112 return (found);
3113}
3114
3115int
3116channel_cancel_lport_listener(struct Forward *fwd, int cport, struct ForwardOptions *fwd_opts)
3117{
3118 if (fwd->listen_path != NULL)
3119 return channel_cancel_lport_listener_streamlocal(fwd->listen_path);
3120 else
3121 return channel_cancel_lport_listener_tcpip(fwd->listen_host, fwd->listen_port, cport, fwd_opts);
3122}
3123
2942/* protocol local port fwd, used by ssh (and sshd in v1) */ 3124/* protocol local port fwd, used by ssh (and sshd in v1) */
2943int 3125int
2944channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port, 3126channel_setup_local_fwd_listener(struct Forward *fwd, struct ForwardOptions *fwd_opts)
2945 const char *host_to_connect, u_short port_to_connect, int gateway_ports)
2946{ 3127{
2947 return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, 3128 if (fwd->listen_path != NULL) {
2948 listen_host, listen_port, NULL, host_to_connect, port_to_connect, 3129 return channel_setup_fwd_listener_streamlocal(
2949 gateway_ports); 3130 SSH_CHANNEL_UNIX_LISTENER, fwd, fwd_opts);
3131 } else {
3132 return channel_setup_fwd_listener_tcpip(SSH_CHANNEL_PORT_LISTENER,
3133 fwd, NULL, fwd_opts);
3134 }
2950} 3135}
2951 3136
2952/* protocol v2 remote port fwd, used by sshd */ 3137/* protocol v2 remote port fwd, used by sshd */
2953int 3138int
2954channel_setup_remote_fwd_listener(const char *listen_address, 3139channel_setup_remote_fwd_listener(struct Forward *fwd,
2955 u_short listen_port, int *allocated_listen_port, int gateway_ports) 3140 int *allocated_listen_port, struct ForwardOptions *fwd_opts)
2956{ 3141{
2957 return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, 3142 if (fwd->listen_path != NULL) {
2958 listen_address, listen_port, allocated_listen_port, 3143 return channel_setup_fwd_listener_streamlocal(
2959 NULL, 0, gateway_ports); 3144 SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts);
3145 } else {
3146 return channel_setup_fwd_listener_tcpip(
3147 SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port,
3148 fwd_opts);
3149 }
2960} 3150}
2961 3151
2962/* 3152/*
@@ -2987,27 +3177,32 @@ channel_rfwd_bind_host(const char *listen_host)
2987 * channel_update_permitted_opens(). 3177 * channel_update_permitted_opens().
2988 */ 3178 */
2989int 3179int
2990channel_request_remote_forwarding(const char *listen_host, u_short listen_port, 3180channel_request_remote_forwarding(struct Forward *fwd)
2991 const char *host_to_connect, u_short port_to_connect)
2992{ 3181{
2993 int type, success = 0, idx = -1; 3182 int type, success = 0, idx = -1;
2994 3183
2995 /* Send the forward request to the remote side. */ 3184 /* Send the forward request to the remote side. */
2996 if (compat20) { 3185 if (compat20) {
2997 packet_start(SSH2_MSG_GLOBAL_REQUEST); 3186 packet_start(SSH2_MSG_GLOBAL_REQUEST);
2998 packet_put_cstring("tcpip-forward"); 3187 if (fwd->listen_path != NULL) {
2999 packet_put_char(1); /* boolean: want reply */ 3188 packet_put_cstring("streamlocal-forward@openssh.com");
3000 packet_put_cstring(channel_rfwd_bind_host(listen_host)); 3189 packet_put_char(1); /* boolean: want reply */
3001 packet_put_int(listen_port); 3190 packet_put_cstring(fwd->listen_path);
3191 } else {
3192 packet_put_cstring("tcpip-forward");
3193 packet_put_char(1); /* boolean: want reply */
3194 packet_put_cstring(channel_rfwd_bind_host(fwd->listen_host));
3195 packet_put_int(fwd->listen_port);
3196 }
3002 packet_send(); 3197 packet_send();
3003 packet_write_wait(); 3198 packet_write_wait();
3004 /* Assume that server accepts the request */ 3199 /* Assume that server accepts the request */
3005 success = 1; 3200 success = 1;
3006 } else { 3201 } else if (fwd->listen_path == NULL) {
3007 packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); 3202 packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
3008 packet_put_int(listen_port); 3203 packet_put_int(fwd->listen_port);
3009 packet_put_cstring(host_to_connect); 3204 packet_put_cstring(fwd->connect_host);
3010 packet_put_int(port_to_connect); 3205 packet_put_int(fwd->connect_port);
3011 packet_send(); 3206 packet_send();
3012 packet_write_wait(); 3207 packet_write_wait();
3013 3208
@@ -3024,25 +3219,102 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
3024 packet_disconnect("Protocol error for port forward request:" 3219 packet_disconnect("Protocol error for port forward request:"
3025 "received packet type %d.", type); 3220 "received packet type %d.", type);
3026 } 3221 }
3222 } else {
3223 logit("Warning: Server does not support remote stream local forwarding.");
3027 } 3224 }
3028 if (success) { 3225 if (success) {
3029 /* Record that connection to this host/port is permitted. */ 3226 /* Record that connection to this host/port is permitted. */
3030 permitted_opens = xrealloc(permitted_opens, 3227 permitted_opens = xrealloc(permitted_opens,
3031 num_permitted_opens + 1, sizeof(*permitted_opens)); 3228 num_permitted_opens + 1, sizeof(*permitted_opens));
3032 idx = num_permitted_opens++; 3229 idx = num_permitted_opens++;
3033 permitted_opens[idx].host_to_connect = xstrdup(host_to_connect); 3230 if (fwd->connect_path != NULL) {
3034 permitted_opens[idx].port_to_connect = port_to_connect; 3231 permitted_opens[idx].host_to_connect =
3035 permitted_opens[idx].listen_port = listen_port; 3232 xstrdup(fwd->connect_path);
3233 permitted_opens[idx].port_to_connect =
3234 PORT_STREAMLOCAL;
3235 } else {
3236 permitted_opens[idx].host_to_connect =
3237 xstrdup(fwd->connect_host);
3238 permitted_opens[idx].port_to_connect =
3239 fwd->connect_port;
3240 }
3241 if (fwd->listen_path != NULL) {
3242 permitted_opens[idx].listen_host = NULL;
3243 permitted_opens[idx].listen_path =
3244 xstrdup(fwd->listen_path);
3245 permitted_opens[idx].listen_port = PORT_STREAMLOCAL;
3246 } else {
3247 permitted_opens[idx].listen_host =
3248 fwd->listen_host ? xstrdup(fwd->listen_host) : NULL;
3249 permitted_opens[idx].listen_path = NULL;
3250 permitted_opens[idx].listen_port = fwd->listen_port;
3251 }
3036 } 3252 }
3037 return (idx); 3253 return (idx);
3038} 3254}
3039 3255
3256static int
3257open_match(ForwardPermission *allowed_open, const char *requestedhost,
3258 int requestedport)
3259{
3260 if (allowed_open->host_to_connect == NULL)
3261 return 0;
3262 if (allowed_open->port_to_connect != FWD_PERMIT_ANY_PORT &&
3263 allowed_open->port_to_connect != requestedport)
3264 return 0;
3265 if (strcmp(allowed_open->host_to_connect, requestedhost) != 0)
3266 return 0;
3267 return 1;
3268}
3269
3270/*
3271 * Note that in the listen host/port case
3272 * we don't support FWD_PERMIT_ANY_PORT and
3273 * need to translate between the configured-host (listen_host)
3274 * and what we've sent to the remote server (channel_rfwd_bind_host)
3275 */
3276static int
3277open_listen_match_tcpip(ForwardPermission *allowed_open,
3278 const char *requestedhost, u_short requestedport, int translate)
3279{
3280 const char *allowed_host;
3281
3282 if (allowed_open->host_to_connect == NULL)
3283 return 0;
3284 if (allowed_open->listen_port != requestedport)
3285 return 0;
3286 if (!translate && allowed_open->listen_host == NULL &&
3287 requestedhost == NULL)
3288 return 1;
3289 allowed_host = translate ?
3290 channel_rfwd_bind_host(allowed_open->listen_host) :
3291 allowed_open->listen_host;
3292 if (allowed_host == NULL ||
3293 strcmp(allowed_host, requestedhost) != 0)
3294 return 0;
3295 return 1;
3296}
3297
3298static int
3299open_listen_match_streamlocal(ForwardPermission *allowed_open,
3300 const char *requestedpath)
3301{
3302 if (allowed_open->host_to_connect == NULL)
3303 return 0;
3304 if (allowed_open->listen_port != PORT_STREAMLOCAL)
3305 return 0;
3306 if (allowed_open->listen_path == NULL ||
3307 strcmp(allowed_open->listen_path, requestedpath) != 0)
3308 return 0;
3309 return 1;
3310}
3311
3040/* 3312/*
3041 * Request cancellation of remote forwarding of connection host:port from 3313 * Request cancellation of remote forwarding of connection host:port from
3042 * local side. 3314 * local side.
3043 */ 3315 */
3044int 3316static int
3045channel_request_rforward_cancel(const char *host, u_short port) 3317channel_request_rforward_cancel_tcpip(const char *host, u_short port)
3046{ 3318{
3047 int i; 3319 int i;
3048 3320
@@ -3050,8 +3322,7 @@ channel_request_rforward_cancel(const char *host, u_short port)
3050 return -1; 3322 return -1;
3051 3323
3052 for (i = 0; i < num_permitted_opens; i++) { 3324 for (i = 0; i < num_permitted_opens; i++) {
3053 if (permitted_opens[i].host_to_connect != NULL && 3325 if (open_listen_match_tcpip(&permitted_opens[i], host, port, 0))
3054 permitted_opens[i].listen_port == port)
3055 break; 3326 break;
3056 } 3327 }
3057 if (i >= num_permitted_opens) { 3328 if (i >= num_permitted_opens) {
@@ -3069,9 +3340,64 @@ channel_request_rforward_cancel(const char *host, u_short port)
3069 permitted_opens[i].port_to_connect = 0; 3340 permitted_opens[i].port_to_connect = 0;
3070 free(permitted_opens[i].host_to_connect); 3341 free(permitted_opens[i].host_to_connect);
3071 permitted_opens[i].host_to_connect = NULL; 3342 permitted_opens[i].host_to_connect = NULL;
3343 free(permitted_opens[i].listen_host);
3344 permitted_opens[i].listen_host = NULL;
3345 permitted_opens[i].listen_path = NULL;
3346
3347 return 0;
3348}
3349
3350/*
3351 * Request cancellation of remote forwarding of Unix domain socket
3352 * path from local side.
3353 */
3354static int
3355channel_request_rforward_cancel_streamlocal(const char *path)
3356{
3357 int i;
3358
3359 if (!compat20)
3360 return -1;
3361
3362 for (i = 0; i < num_permitted_opens; i++) {
3363 if (open_listen_match_streamlocal(&permitted_opens[i], path))
3364 break;
3365 }
3366 if (i >= num_permitted_opens) {
3367 debug("%s: requested forward not found", __func__);
3368 return -1;
3369 }
3370 packet_start(SSH2_MSG_GLOBAL_REQUEST);
3371 packet_put_cstring("cancel-streamlocal-forward@openssh.com");
3372 packet_put_char(0);
3373 packet_put_cstring(path);
3374 packet_send();
3375
3376 permitted_opens[i].listen_port = 0;
3377 permitted_opens[i].port_to_connect = 0;
3378 free(permitted_opens[i].host_to_connect);
3379 permitted_opens[i].host_to_connect = NULL;
3380 permitted_opens[i].listen_host = NULL;
3381 free(permitted_opens[i].listen_path);
3382 permitted_opens[i].listen_path = NULL;
3072 3383
3073 return 0; 3384 return 0;
3074} 3385}
3386
3387/*
3388 * Request cancellation of remote forwarding of a connection from local side.
3389 */
3390int
3391channel_request_rforward_cancel(struct Forward *fwd)
3392{
3393 if (fwd->listen_path != NULL) {
3394 return (channel_request_rforward_cancel_streamlocal(
3395 fwd->listen_path));
3396 } else {
3397 return (channel_request_rforward_cancel_tcpip(fwd->listen_host,
3398 fwd->listen_port ? fwd->listen_port : fwd->allocated_port));
3399 }
3400}
3075 3401
3076/* 3402/*
3077 * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates 3403 * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
@@ -3079,36 +3405,35 @@ channel_request_rforward_cancel(const char *host, u_short port)
3079 * message if there was an error). 3405 * message if there was an error).
3080 */ 3406 */
3081int 3407int
3082channel_input_port_forward_request(int is_root, int gateway_ports) 3408channel_input_port_forward_request(int is_root, struct ForwardOptions *fwd_opts)
3083{ 3409{
3084 u_short port, host_port;
3085 int success = 0; 3410 int success = 0;
3086 char *hostname; 3411 struct Forward fwd;
3087 3412
3088 /* Get arguments from the packet. */ 3413 /* Get arguments from the packet. */
3089 port = packet_get_int(); 3414 memset(&fwd, 0, sizeof(fwd));
3090 hostname = packet_get_string(NULL); 3415 fwd.listen_port = packet_get_int();
3091 host_port = packet_get_int(); 3416 fwd.connect_host = packet_get_string(NULL);
3417 fwd.connect_port = packet_get_int();
3092 3418
3093#ifndef HAVE_CYGWIN 3419#ifndef HAVE_CYGWIN
3094 /* 3420 /*
3095 * Check that an unprivileged user is not trying to forward a 3421 * Check that an unprivileged user is not trying to forward a
3096 * privileged port. 3422 * privileged port.
3097 */ 3423 */
3098 if (port < IPPORT_RESERVED && !is_root) 3424 if (fwd.listen_port < IPPORT_RESERVED && !is_root)
3099 packet_disconnect( 3425 packet_disconnect(
3100 "Requested forwarding of port %d but user is not root.", 3426 "Requested forwarding of port %d but user is not root.",
3101 port); 3427 fwd.listen_port);
3102 if (host_port == 0) 3428 if (fwd.connect_port == 0)
3103 packet_disconnect("Dynamic forwarding denied."); 3429 packet_disconnect("Dynamic forwarding denied.");
3104#endif 3430#endif
3105 3431
3106 /* Initiate forwarding */ 3432 /* Initiate forwarding */
3107 success = channel_setup_local_fwd_listener(NULL, port, hostname, 3433 success = channel_setup_local_fwd_listener(&fwd, fwd_opts);
3108 host_port, gateway_ports);
3109 3434
3110 /* Free the argument string. */ 3435 /* Free the argument string. */
3111 free(hostname); 3436 free(fwd.connect_host);
3112 3437
3113 return (success ? 0 : -1); 3438 return (success ? 0 : -1);
3114} 3439}
@@ -3134,6 +3459,9 @@ channel_add_permitted_opens(char *host, int port)
3134 num_permitted_opens + 1, sizeof(*permitted_opens)); 3459 num_permitted_opens + 1, sizeof(*permitted_opens));
3135 permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); 3460 permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
3136 permitted_opens[num_permitted_opens].port_to_connect = port; 3461 permitted_opens[num_permitted_opens].port_to_connect = port;
3462 permitted_opens[num_permitted_opens].listen_host = NULL;
3463 permitted_opens[num_permitted_opens].listen_path = NULL;
3464 permitted_opens[num_permitted_opens].listen_port = 0;
3137 num_permitted_opens++; 3465 num_permitted_opens++;
3138 3466
3139 all_opens_permitted = 0; 3467 all_opens_permitted = 0;
@@ -3165,6 +3493,10 @@ channel_update_permitted_opens(int idx, int newport)
3165 permitted_opens[idx].port_to_connect = 0; 3493 permitted_opens[idx].port_to_connect = 0;
3166 free(permitted_opens[idx].host_to_connect); 3494 free(permitted_opens[idx].host_to_connect);
3167 permitted_opens[idx].host_to_connect = NULL; 3495 permitted_opens[idx].host_to_connect = NULL;
3496 free(permitted_opens[idx].listen_host);
3497 permitted_opens[idx].listen_host = NULL;
3498 free(permitted_opens[idx].listen_path);
3499 permitted_opens[idx].listen_path = NULL;
3168 } 3500 }
3169} 3501}
3170 3502
@@ -3178,6 +3510,9 @@ channel_add_adm_permitted_opens(char *host, int port)
3178 permitted_adm_opens[num_adm_permitted_opens].host_to_connect 3510 permitted_adm_opens[num_adm_permitted_opens].host_to_connect
3179 = xstrdup(host); 3511 = xstrdup(host);
3180 permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port; 3512 permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
3513 permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL;
3514 permitted_adm_opens[num_adm_permitted_opens].listen_path = NULL;
3515 permitted_adm_opens[num_adm_permitted_opens].listen_port = 0;
3181 return ++num_adm_permitted_opens; 3516 return ++num_adm_permitted_opens;
3182} 3517}
3183 3518
@@ -3195,8 +3530,11 @@ channel_clear_permitted_opens(void)
3195{ 3530{
3196 int i; 3531 int i;
3197 3532
3198 for (i = 0; i < num_permitted_opens; i++) 3533 for (i = 0; i < num_permitted_opens; i++) {
3199 free(permitted_opens[i].host_to_connect); 3534 free(permitted_opens[i].host_to_connect);
3535 free(permitted_opens[i].listen_host);
3536 free(permitted_opens[i].listen_path);
3537 }
3200 free(permitted_opens); 3538 free(permitted_opens);
3201 permitted_opens = NULL; 3539 permitted_opens = NULL;
3202 num_permitted_opens = 0; 3540 num_permitted_opens = 0;
@@ -3207,8 +3545,11 @@ channel_clear_adm_permitted_opens(void)
3207{ 3545{
3208 int i; 3546 int i;
3209 3547
3210 for (i = 0; i < num_adm_permitted_opens; i++) 3548 for (i = 0; i < num_adm_permitted_opens; i++) {
3211 free(permitted_adm_opens[i].host_to_connect); 3549 free(permitted_adm_opens[i].host_to_connect);
3550 free(permitted_adm_opens[i].listen_host);
3551 free(permitted_adm_opens[i].listen_path);
3552 }
3212 free(permitted_adm_opens); 3553 free(permitted_adm_opens);
3213 permitted_adm_opens = NULL; 3554 permitted_adm_opens = NULL;
3214 num_adm_permitted_opens = 0; 3555 num_adm_permitted_opens = 0;
@@ -3246,30 +3587,32 @@ permitopen_port(const char *p)
3246 return -1; 3587 return -1;
3247} 3588}
3248 3589
3249static int
3250port_match(u_short allowedport, u_short requestedport)
3251{
3252 if (allowedport == FWD_PERMIT_ANY_PORT ||
3253 allowedport == requestedport)
3254 return 1;
3255 return 0;
3256}
3257
3258/* Try to start non-blocking connect to next host in cctx list */ 3590/* Try to start non-blocking connect to next host in cctx list */
3259static int 3591static int
3260connect_next(struct channel_connect *cctx) 3592connect_next(struct channel_connect *cctx)
3261{ 3593{
3262 int sock, saved_errno; 3594 int sock, saved_errno;
3263 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 3595 struct sockaddr_un *sunaddr;
3596 char ntop[NI_MAXHOST], strport[MAX(NI_MAXSERV,sizeof(sunaddr->sun_path))];
3264 3597
3265 for (; cctx->ai; cctx->ai = cctx->ai->ai_next) { 3598 for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
3266 if (cctx->ai->ai_family != AF_INET && 3599 switch (cctx->ai->ai_family) {
3267 cctx->ai->ai_family != AF_INET6) 3600 case AF_UNIX:
3268 continue; 3601 /* unix:pathname instead of host:port */
3269 if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen, 3602 sunaddr = (struct sockaddr_un *)cctx->ai->ai_addr;
3270 ntop, sizeof(ntop), strport, sizeof(strport), 3603 strlcpy(ntop, "unix", sizeof(ntop));
3271 NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 3604 strlcpy(strport, sunaddr->sun_path, sizeof(strport));
3272 error("connect_next: getnameinfo failed"); 3605 break;
3606 case AF_INET:
3607 case AF_INET6:
3608 if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
3609 ntop, sizeof(ntop), strport, sizeof(strport),
3610 NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
3611 error("connect_next: getnameinfo failed");
3612 continue;
3613 }
3614 break;
3615 default:
3273 continue; 3616 continue;
3274 } 3617 }
3275 if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype, 3618 if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
@@ -3292,10 +3635,11 @@ connect_next(struct channel_connect *cctx)
3292 errno = saved_errno; 3635 errno = saved_errno;
3293 continue; /* fail -- try next */ 3636 continue; /* fail -- try next */
3294 } 3637 }
3638 if (cctx->ai->ai_family != AF_UNIX)
3639 set_nodelay(sock);
3295 debug("connect_next: host %.100s ([%.100s]:%s) " 3640 debug("connect_next: host %.100s ([%.100s]:%s) "
3296 "in progress, fd=%d", cctx->host, ntop, strport, sock); 3641 "in progress, fd=%d", cctx->host, ntop, strport, sock);
3297 cctx->ai = cctx->ai->ai_next; 3642 cctx->ai = cctx->ai->ai_next;
3298 set_nodelay(sock);
3299 return sock; 3643 return sock;
3300 } 3644 }
3301 return -1; 3645 return -1;
@@ -3305,14 +3649,18 @@ static void
3305channel_connect_ctx_free(struct channel_connect *cctx) 3649channel_connect_ctx_free(struct channel_connect *cctx)
3306{ 3650{
3307 free(cctx->host); 3651 free(cctx->host);
3308 if (cctx->aitop) 3652 if (cctx->aitop) {
3309 freeaddrinfo(cctx->aitop); 3653 if (cctx->aitop->ai_family == AF_UNIX)
3654 free(cctx->aitop);
3655 else
3656 freeaddrinfo(cctx->aitop);
3657 }
3310 memset(cctx, 0, sizeof(*cctx)); 3658 memset(cctx, 0, sizeof(*cctx));
3311} 3659}
3312 3660
3313/* Return CONNECTING channel to remote host, port */ 3661/* Return CONNECTING channel to remote host:port or local socket path */
3314static Channel * 3662static Channel *
3315connect_to(const char *host, u_short port, char *ctype, char *rname) 3663connect_to(const char *name, int port, char *ctype, char *rname)
3316{ 3664{
3317 struct addrinfo hints; 3665 struct addrinfo hints;
3318 int gaierr; 3666 int gaierr;
@@ -3322,23 +3670,51 @@ connect_to(const char *host, u_short port, char *ctype, char *rname)
3322 Channel *c; 3670 Channel *c;
3323 3671
3324 memset(&cctx, 0, sizeof(cctx)); 3672 memset(&cctx, 0, sizeof(cctx));
3325 memset(&hints, 0, sizeof(hints)); 3673
3326 hints.ai_family = IPv4or6; 3674 if (port == PORT_STREAMLOCAL) {
3327 hints.ai_socktype = SOCK_STREAM; 3675 struct sockaddr_un *sunaddr;
3328 snprintf(strport, sizeof strport, "%d", port); 3676 struct addrinfo *ai;
3329 if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) { 3677
3330 error("connect_to %.100s: unknown host (%s)", host, 3678 if (strlen(name) > sizeof(sunaddr->sun_path)) {
3331 ssh_gai_strerror(gaierr)); 3679 error("%.100s: %.100s", name, strerror(ENAMETOOLONG));
3332 return NULL; 3680 return (NULL);
3681 }
3682
3683 /*
3684 * Fake up a struct addrinfo for AF_UNIX connections.
3685 * channel_connect_ctx_free() must check ai_family
3686 * and use free() not freeaddirinfo() for AF_UNIX.
3687 */
3688 ai = xmalloc(sizeof(*ai) + sizeof(*sunaddr));
3689 memset(ai, 0, sizeof(*ai) + sizeof(*sunaddr));
3690 ai->ai_addr = (struct sockaddr *)(ai + 1);
3691 ai->ai_addrlen = sizeof(*sunaddr);
3692 ai->ai_family = AF_UNIX;
3693 ai->ai_socktype = SOCK_STREAM;
3694 ai->ai_protocol = PF_UNSPEC;
3695 sunaddr = (struct sockaddr_un *)ai->ai_addr;
3696 sunaddr->sun_family = AF_UNIX;
3697 strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path));
3698 cctx.aitop = ai;
3699 } else {
3700 memset(&hints, 0, sizeof(hints));
3701 hints.ai_family = IPv4or6;
3702 hints.ai_socktype = SOCK_STREAM;
3703 snprintf(strport, sizeof strport, "%d", port);
3704 if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop)) != 0) {
3705 error("connect_to %.100s: unknown host (%s)", name,
3706 ssh_gai_strerror(gaierr));
3707 return NULL;
3708 }
3333 } 3709 }
3334 3710
3335 cctx.host = xstrdup(host); 3711 cctx.host = xstrdup(name);
3336 cctx.port = port; 3712 cctx.port = port;
3337 cctx.ai = cctx.aitop; 3713 cctx.ai = cctx.aitop;
3338 3714
3339 if ((sock = connect_next(&cctx)) == -1) { 3715 if ((sock = connect_next(&cctx)) == -1) {
3340 error("connect to %.100s port %d failed: %s", 3716 error("connect to %.100s port %d failed: %s",
3341 host, port, strerror(errno)); 3717 name, port, strerror(errno));
3342 channel_connect_ctx_free(&cctx); 3718 channel_connect_ctx_free(&cctx);
3343 return NULL; 3719 return NULL;
3344 } 3720 }
@@ -3349,13 +3725,14 @@ connect_to(const char *host, u_short port, char *ctype, char *rname)
3349} 3725}
3350 3726
3351Channel * 3727Channel *
3352channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname) 3728channel_connect_by_listen_address(const char *listen_host,
3729 u_short listen_port, char *ctype, char *rname)
3353{ 3730{
3354 int i; 3731 int i;
3355 3732
3356 for (i = 0; i < num_permitted_opens; i++) { 3733 for (i = 0; i < num_permitted_opens; i++) {
3357 if (permitted_opens[i].host_to_connect != NULL && 3734 if (open_listen_match_tcpip(&permitted_opens[i], listen_host,
3358 port_match(permitted_opens[i].listen_port, listen_port)) { 3735 listen_port, 1)) {
3359 return connect_to( 3736 return connect_to(
3360 permitted_opens[i].host_to_connect, 3737 permitted_opens[i].host_to_connect,
3361 permitted_opens[i].port_to_connect, ctype, rname); 3738 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)
3366 return NULL; 3743 return NULL;
3367} 3744}
3368 3745
3746Channel *
3747channel_connect_by_listen_path(const char *path, char *ctype, char *rname)
3748{
3749 int i;
3750
3751 for (i = 0; i < num_permitted_opens; i++) {
3752 if (open_listen_match_streamlocal(&permitted_opens[i], path)) {
3753 return connect_to(
3754 permitted_opens[i].host_to_connect,
3755 permitted_opens[i].port_to_connect, ctype, rname);
3756 }
3757 }
3758 error("WARNING: Server requests forwarding for unknown path %.100s",
3759 path);
3760 return NULL;
3761}
3762
3369/* Check if connecting to that port is permitted and connect. */ 3763/* Check if connecting to that port is permitted and connect. */
3370Channel * 3764Channel *
3371channel_connect_to(const char *host, u_short port, char *ctype, char *rname) 3765channel_connect_to_port(const char *host, u_short port, char *ctype, char *rname)
3372{ 3766{
3373 int i, permit, permit_adm = 1; 3767 int i, permit, permit_adm = 1;
3374 3768
3375 permit = all_opens_permitted; 3769 permit = all_opens_permitted;
3376 if (!permit) { 3770 if (!permit) {
3377 for (i = 0; i < num_permitted_opens; i++) 3771 for (i = 0; i < num_permitted_opens; i++)
3378 if (permitted_opens[i].host_to_connect != NULL && 3772 if (open_match(&permitted_opens[i], host, port)) {
3379 port_match(permitted_opens[i].port_to_connect, port) &&
3380 strcmp(permitted_opens[i].host_to_connect, host) == 0)
3381 permit = 1; 3773 permit = 1;
3774 break;
3775 }
3382 } 3776 }
3383 3777
3384 if (num_adm_permitted_opens > 0) { 3778 if (num_adm_permitted_opens > 0) {
3385 permit_adm = 0; 3779 permit_adm = 0;
3386 for (i = 0; i < num_adm_permitted_opens; i++) 3780 for (i = 0; i < num_adm_permitted_opens; i++)
3387 if (permitted_adm_opens[i].host_to_connect != NULL && 3781 if (open_match(&permitted_adm_opens[i], host, port)) {
3388 port_match(permitted_adm_opens[i].port_to_connect, port) &&
3389 strcmp(permitted_adm_opens[i].host_to_connect, host)
3390 == 0)
3391 permit_adm = 1; 3782 permit_adm = 1;
3783 break;
3784 }
3392 } 3785 }
3393 3786
3394 if (!permit || !permit_adm) { 3787 if (!permit || !permit_adm) {
@@ -3399,6 +3792,38 @@ channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
3399 return connect_to(host, port, ctype, rname); 3792 return connect_to(host, port, ctype, rname);
3400} 3793}
3401 3794
3795/* Check if connecting to that path is permitted and connect. */
3796Channel *
3797channel_connect_to_path(const char *path, char *ctype, char *rname)
3798{
3799 int i, permit, permit_adm = 1;
3800
3801 permit = all_opens_permitted;
3802 if (!permit) {
3803 for (i = 0; i < num_permitted_opens; i++)
3804 if (open_match(&permitted_opens[i], path, PORT_STREAMLOCAL)) {
3805 permit = 1;
3806 break;
3807 }
3808 }
3809
3810 if (num_adm_permitted_opens > 0) {
3811 permit_adm = 0;
3812 for (i = 0; i < num_adm_permitted_opens; i++)
3813 if (open_match(&permitted_adm_opens[i], path, PORT_STREAMLOCAL)) {
3814 permit_adm = 1;
3815 break;
3816 }
3817 }
3818
3819 if (!permit || !permit_adm) {
3820 logit("Received request to connect to path %.100s, "
3821 "but the request was denied.", path);
3822 return NULL;
3823 }
3824 return connect_to(path, PORT_STREAMLOCAL, ctype, rname);
3825}
3826
3402void 3827void
3403channel_send_window_changes(void) 3828channel_send_window_changes(void)
3404{ 3829{
diff --git a/channels.h b/channels.h
index 4fab9d7c4..a000c98e5 100644
--- a/channels.h
+++ b/channels.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.h,v 1.113 2013/06/07 15:37:52 dtucker Exp $ */ 1/* $OpenBSD: channels.h,v 1.115 2014/07/15 15:54:14 millert Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -56,7 +56,9 @@
56#define SSH_CHANNEL_MUX_LISTENER 15 /* Listener for mux conn. */ 56#define SSH_CHANNEL_MUX_LISTENER 15 /* Listener for mux conn. */
57#define SSH_CHANNEL_MUX_CLIENT 16 /* Conn. to mux slave */ 57#define SSH_CHANNEL_MUX_CLIENT 16 /* Conn. to mux slave */
58#define SSH_CHANNEL_ABANDONED 17 /* Abandoned session, eg mux */ 58#define SSH_CHANNEL_ABANDONED 17 /* Abandoned session, eg mux */
59#define SSH_CHANNEL_MAX_TYPE 18 59#define SSH_CHANNEL_UNIX_LISTENER 18 /* Listening on a domain socket. */
60#define SSH_CHANNEL_RUNIX_LISTENER 19 /* Listening to a R-style domain socket. */
61#define SSH_CHANNEL_MAX_TYPE 20
60 62
61#define CHANNEL_CANCEL_PORT_STATIC -1 63#define CHANNEL_CANCEL_PORT_STATIC -1
62 64
@@ -254,6 +256,8 @@ char *channel_open_message(void);
254int channel_find_open(void); 256int channel_find_open(void);
255 257
256/* tcp forwarding */ 258/* tcp forwarding */
259struct Forward;
260struct ForwardOptions;
257void channel_set_af(int af); 261void channel_set_af(int af);
258void channel_permit_all_opens(void); 262void channel_permit_all_opens(void);
259void channel_add_permitted_opens(char *, int); 263void channel_add_permitted_opens(char *, int);
@@ -263,18 +267,19 @@ void channel_update_permitted_opens(int, int);
263void channel_clear_permitted_opens(void); 267void channel_clear_permitted_opens(void);
264void channel_clear_adm_permitted_opens(void); 268void channel_clear_adm_permitted_opens(void);
265void channel_print_adm_permitted_opens(void); 269void channel_print_adm_permitted_opens(void);
266int channel_input_port_forward_request(int, int); 270int channel_input_port_forward_request(int, struct ForwardOptions *);
267Channel *channel_connect_to(const char *, u_short, char *, char *); 271Channel *channel_connect_to_port(const char *, u_short, char *, char *);
272Channel *channel_connect_to_path(const char *, char *, char *);
268Channel *channel_connect_stdio_fwd(const char*, u_short, int, int); 273Channel *channel_connect_stdio_fwd(const char*, u_short, int, int);
269Channel *channel_connect_by_listen_address(u_short, char *, char *); 274Channel *channel_connect_by_listen_address(const char *, u_short,
270int channel_request_remote_forwarding(const char *, u_short, 275 char *, char *);
271 const char *, u_short); 276Channel *channel_connect_by_listen_path(const char *, char *, char *);
272int channel_setup_local_fwd_listener(const char *, u_short, 277int channel_request_remote_forwarding(struct Forward *);
273 const char *, u_short, int); 278int channel_setup_local_fwd_listener(struct Forward *, struct ForwardOptions *);
274int channel_request_rforward_cancel(const char *host, u_short port); 279int channel_request_rforward_cancel(struct Forward *);
275int channel_setup_remote_fwd_listener(const char *, u_short, int *, int); 280int channel_setup_remote_fwd_listener(struct Forward *, int *, struct ForwardOptions *);
276int channel_cancel_rport_listener(const char *, u_short); 281int channel_cancel_rport_listener(struct Forward *);
277int channel_cancel_lport_listener(const char *, u_short, int, int); 282int channel_cancel_lport_listener(struct Forward *, int, struct ForwardOptions *);
278int permitopen_port(const char *); 283int permitopen_port(const char *);
279 284
280/* x11 forwarding */ 285/* x11 forwarding */
diff --git a/cipher-3des1.c b/cipher-3des1.c
index b2823592b..2753f9a0e 100644
--- a/cipher-3des1.c
+++ b/cipher-3des1.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: cipher-3des1.c,v 1.10 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: cipher-3des1.c,v 1.11 2014/07/02 04:59:06 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2003 Markus Friedl. All rights reserved. 3 * Copyright (c) 2003 Markus Friedl. All rights reserved.
4 * 4 *
@@ -29,13 +29,11 @@
29 29
30#include <openssl/evp.h> 30#include <openssl/evp.h>
31 31
32#include <stdarg.h>
33#include <string.h> 32#include <string.h>
34 33
35#include "xmalloc.h" 34#include "xmalloc.h"
36#include "log.h" 35#include "log.h"
37 36#include "ssherr.h"
38#include "openbsd-compat/openssl-compat.h"
39 37
40/* 38/*
41 * This is used by SSH1: 39 * This is used by SSH1:
@@ -57,7 +55,7 @@ struct ssh1_3des_ctx
57}; 55};
58 56
59const EVP_CIPHER * evp_ssh1_3des(void); 57const EVP_CIPHER * evp_ssh1_3des(void);
60void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); 58int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
61 59
62static int 60static int
63ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, 61ssh1_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,
67 u_char *k1, *k2, *k3; 65 u_char *k1, *k2, *k3;
68 66
69 if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { 67 if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
70 c = xcalloc(1, sizeof(*c)); 68 if ((c = calloc(1, sizeof(*c))) == NULL)
69 return 0;
71 EVP_CIPHER_CTX_set_app_data(ctx, c); 70 EVP_CIPHER_CTX_set_app_data(ctx, c);
72 } 71 }
73 if (key == NULL) 72 if (key == NULL)
74 return (1); 73 return 1;
75 if (enc == -1) 74 if (enc == -1)
76 enc = ctx->encrypt; 75 enc = ctx->encrypt;
77 k1 = k2 = k3 = (u_char *) key; 76 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,
85 EVP_CIPHER_CTX_init(&c->k1); 84 EVP_CIPHER_CTX_init(&c->k1);
86 EVP_CIPHER_CTX_init(&c->k2); 85 EVP_CIPHER_CTX_init(&c->k2);
87 EVP_CIPHER_CTX_init(&c->k3); 86 EVP_CIPHER_CTX_init(&c->k3);
88#ifdef SSH_OLD_EVP
89 EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc);
90 EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc);
91 EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc);
92#else
93 if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 || 87 if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
94 EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 || 88 EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
95 EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) { 89 EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
96 explicit_bzero(c, sizeof(*c)); 90 explicit_bzero(c, sizeof(*c));
97 free(c); 91 free(c);
98 EVP_CIPHER_CTX_set_app_data(ctx, NULL); 92 EVP_CIPHER_CTX_set_app_data(ctx, NULL);
99 return (0); 93 return 0;
100 } 94 }
101#endif 95 return 1;
102 return (1);
103} 96}
104 97
105static int 98static int
106ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, 99ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, size_t len)
107 LIBCRYPTO_EVP_INL_TYPE len)
108{ 100{
109 struct ssh1_3des_ctx *c; 101 struct ssh1_3des_ctx *c;
110 102
111 if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { 103 if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
112 error("ssh1_3des_cbc: no context"); 104 return 0;
113 return (0);
114 }
115#ifdef SSH_OLD_EVP
116 EVP_Cipher(&c->k1, dest, (u_char *)src, len);
117 EVP_Cipher(&c->k2, dest, dest, len);
118 EVP_Cipher(&c->k3, dest, dest, len);
119#else
120 if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 || 105 if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
121 EVP_Cipher(&c->k2, dest, dest, len) == 0 || 106 EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
122 EVP_Cipher(&c->k3, dest, dest, len) == 0) 107 EVP_Cipher(&c->k3, dest, dest, len) == 0)
123 return (0); 108 return 0;
124#endif 109 return 1;
125 return (1);
126} 110}
127 111
128static int 112static int
@@ -138,29 +122,28 @@ ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
138 free(c); 122 free(c);
139 EVP_CIPHER_CTX_set_app_data(ctx, NULL); 123 EVP_CIPHER_CTX_set_app_data(ctx, NULL);
140 } 124 }
141 return (1); 125 return 1;
142} 126}
143 127
144void 128int
145ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len) 129ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
146{ 130{
147 struct ssh1_3des_ctx *c; 131 struct ssh1_3des_ctx *c;
148 132
149 if (len != 24) 133 if (len != 24)
150 fatal("%s: bad 3des iv length: %d", __func__, len); 134 return SSH_ERR_INVALID_ARGUMENT;
151 if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL) 135 if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
152 fatal("%s: no 3des context", __func__); 136 return SSH_ERR_INTERNAL_ERROR;
153 if (doset) { 137 if (doset) {
154 debug3("%s: Installed 3DES IV", __func__);
155 memcpy(c->k1.iv, iv, 8); 138 memcpy(c->k1.iv, iv, 8);
156 memcpy(c->k2.iv, iv + 8, 8); 139 memcpy(c->k2.iv, iv + 8, 8);
157 memcpy(c->k3.iv, iv + 16, 8); 140 memcpy(c->k3.iv, iv + 16, 8);
158 } else { 141 } else {
159 debug3("%s: Copying 3DES IV", __func__);
160 memcpy(iv, c->k1.iv, 8); 142 memcpy(iv, c->k1.iv, 8);
161 memcpy(iv + 8, c->k2.iv, 8); 143 memcpy(iv + 8, c->k2.iv, 8);
162 memcpy(iv + 16, c->k3.iv, 8); 144 memcpy(iv + 16, c->k3.iv, 8);
163 } 145 }
146 return 0;
164} 147}
165 148
166const EVP_CIPHER * 149const EVP_CIPHER *
@@ -176,8 +159,6 @@ evp_ssh1_3des(void)
176 ssh1_3des.init = ssh1_3des_init; 159 ssh1_3des.init = ssh1_3des_init;
177 ssh1_3des.cleanup = ssh1_3des_cleanup; 160 ssh1_3des.cleanup = ssh1_3des_cleanup;
178 ssh1_3des.do_cipher = ssh1_3des_cbc; 161 ssh1_3des.do_cipher = ssh1_3des_cbc;
179#ifndef SSH_OLD_EVP
180 ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH; 162 ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
181#endif 163 return &ssh1_3des;
182 return (&ssh1_3des);
183} 164}
diff --git a/cipher-aesctr.c b/cipher-aesctr.c
new file mode 100644
index 000000000..a4cf61e41
--- /dev/null
+++ b/cipher-aesctr.c
@@ -0,0 +1,78 @@
1/* $OpenBSD: cipher-aesctr.c,v 1.1 2014/04/29 15:39:33 markus Exp $ */
2/*
3 * Copyright (c) 2003 Markus Friedl <markus@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/types.h>
19#include <string.h>
20
21#include "cipher-aesctr.h"
22
23/*
24 * increment counter 'ctr',
25 * the counter is of size 'len' bytes and stored in network-byte-order.
26 * (LSB at ctr[len-1], MSB at ctr[0])
27 */
28static __inline__ void
29aesctr_inc(u8 *ctr, u32 len)
30{
31 ssize_t i;
32
33#ifndef CONSTANT_TIME_INCREMENT
34 for (i = len - 1; i >= 0; i--)
35 if (++ctr[i]) /* continue on overflow */
36 return;
37#else
38 u8 x, add = 1;
39
40 for (i = len - 1; i >= 0; i--) {
41 ctr[i] += add;
42 /* constant time for: x = ctr[i] ? 1 : 0 */
43 x = ctr[i];
44 x = (x | (x >> 4)) & 0xf;
45 x = (x | (x >> 2)) & 0x3;
46 x = (x | (x >> 1)) & 0x1;
47 add *= (x^1);
48 }
49#endif
50}
51
52void
53aesctr_keysetup(aesctr_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
54{
55 x->rounds = rijndaelKeySetupEnc(x->ek, k, kbits);
56}
57
58void
59aesctr_ivsetup(aesctr_ctx *x,const u8 *iv)
60{
61 memcpy(x->ctr, iv, AES_BLOCK_SIZE);
62}
63
64void
65aesctr_encrypt_bytes(aesctr_ctx *x,const u8 *m,u8 *c,u32 bytes)
66{
67 u32 n = 0;
68 u8 buf[AES_BLOCK_SIZE];
69
70 while ((bytes--) > 0) {
71 if (n == 0) {
72 rijndaelEncrypt(x->ek, x->rounds, x->ctr, buf);
73 aesctr_inc(x->ctr, AES_BLOCK_SIZE);
74 }
75 *(c++) = *(m++) ^ buf[n];
76 n = (n + 1) % AES_BLOCK_SIZE;
77 }
78}
diff --git a/cipher-aesctr.h b/cipher-aesctr.h
new file mode 100644
index 000000000..85d55bba2
--- /dev/null
+++ b/cipher-aesctr.h
@@ -0,0 +1,35 @@
1/* $OpenBSD: cipher-aesctr.h,v 1.1 2014/04/29 15:39:33 markus Exp $ */
2/*
3 * Copyright (c) 2014 Markus Friedl
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#ifndef OPENSSH_AESCTR_H
19#define OPENSSH_AESCTR_H
20
21#include "rijndael.h"
22
23#define AES_BLOCK_SIZE 16
24
25typedef struct aesctr_ctx {
26 int rounds; /* keylen-dependent #rounds */
27 u32 ek[4*(AES_MAXROUNDS + 1)]; /* encrypt key schedule */
28 u8 ctr[AES_BLOCK_SIZE]; /* counter */
29} aesctr_ctx;
30
31void aesctr_keysetup(aesctr_ctx *x,const u8 *k,u32 kbits,u32 ivbits);
32void aesctr_ivsetup(aesctr_ctx *x,const u8 *iv);
33void aesctr_encrypt_bytes(aesctr_ctx *x,const u8 *m,u8 *c,u32 bytes);
34
35#endif
diff --git a/cipher-chachapoly.c b/cipher-chachapoly.c
index 251b94ec8..8665b41a3 100644
--- a/cipher-chachapoly.c
+++ b/cipher-chachapoly.c
@@ -14,7 +14,7 @@
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */ 15 */
16 16
17/* $OpenBSD: cipher-chachapoly.c,v 1.4 2014/01/31 16:39:19 tedu Exp $ */ 17/* $OpenBSD: cipher-chachapoly.c,v 1.6 2014/07/03 12:42:16 jsing Exp $ */
18 18
19#include "includes.h" 19#include "includes.h"
20 20
@@ -24,16 +24,18 @@
24#include <stdio.h> /* needed for misc.h */ 24#include <stdio.h> /* needed for misc.h */
25 25
26#include "log.h" 26#include "log.h"
27#include "misc.h" 27#include "sshbuf.h"
28#include "ssherr.h"
28#include "cipher-chachapoly.h" 29#include "cipher-chachapoly.h"
29 30
30void chachapoly_init(struct chachapoly_ctx *ctx, 31int chachapoly_init(struct chachapoly_ctx *ctx,
31 const u_char *key, u_int keylen) 32 const u_char *key, u_int keylen)
32{ 33{
33 if (keylen != (32 + 32)) /* 2 x 256 bit keys */ 34 if (keylen != (32 + 32)) /* 2 x 256 bit keys */
34 fatal("%s: invalid keylen %u", __func__, keylen); 35 return SSH_ERR_INVALID_ARGUMENT;
35 chacha_keysetup(&ctx->main_ctx, key, 256); 36 chacha_keysetup(&ctx->main_ctx, key, 256);
36 chacha_keysetup(&ctx->header_ctx, key + 32, 256); 37 chacha_keysetup(&ctx->header_ctx, key + 32, 256);
38 return 0;
37} 39}
38 40
39/* 41/*
@@ -52,33 +54,37 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest,
52 u_char seqbuf[8]; 54 u_char seqbuf[8];
53 const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */ 55 const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
54 u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; 56 u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
55 int r = -1; 57 int r = SSH_ERR_INTERNAL_ERROR;
56 58
57 /* 59 /*
58 * Run ChaCha20 once to generate the Poly1305 key. The IV is the 60 * Run ChaCha20 once to generate the Poly1305 key. The IV is the
59 * packet sequence number. 61 * packet sequence number.
60 */ 62 */
61 memset(poly_key, 0, sizeof(poly_key)); 63 memset(poly_key, 0, sizeof(poly_key));
62 put_u64(seqbuf, seqnr); 64 POKE_U64(seqbuf, seqnr);
63 chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); 65 chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
64 chacha_encrypt_bytes(&ctx->main_ctx, 66 chacha_encrypt_bytes(&ctx->main_ctx,
65 poly_key, poly_key, sizeof(poly_key)); 67 poly_key, poly_key, sizeof(poly_key));
66 /* Set Chacha's block counter to 1 */
67 chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
68 68
69 /* If decrypting, check tag before anything else */ 69 /* If decrypting, check tag before anything else */
70 if (!do_encrypt) { 70 if (!do_encrypt) {
71 const u_char *tag = src + aadlen + len; 71 const u_char *tag = src + aadlen + len;
72 72
73 poly1305_auth(expected_tag, src, aadlen + len, poly_key); 73 poly1305_auth(expected_tag, src, aadlen + len, poly_key);
74 if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) 74 if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
75 r = SSH_ERR_MAC_INVALID;
75 goto out; 76 goto out;
77 }
76 } 78 }
79
77 /* Crypt additional data */ 80 /* Crypt additional data */
78 if (aadlen) { 81 if (aadlen) {
79 chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); 82 chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL);
80 chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); 83 chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen);
81 } 84 }
85
86 /* Set Chacha's block counter to 1 */
87 chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
82 chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, 88 chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen,
83 dest + aadlen, len); 89 dest + aadlen, len);
84 90
@@ -88,7 +94,6 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest,
88 poly_key); 94 poly_key);
89 } 95 }
90 r = 0; 96 r = 0;
91
92 out: 97 out:
93 explicit_bzero(expected_tag, sizeof(expected_tag)); 98 explicit_bzero(expected_tag, sizeof(expected_tag));
94 explicit_bzero(seqbuf, sizeof(seqbuf)); 99 explicit_bzero(seqbuf, sizeof(seqbuf));
@@ -104,11 +109,11 @@ chachapoly_get_length(struct chachapoly_ctx *ctx,
104 u_char buf[4], seqbuf[8]; 109 u_char buf[4], seqbuf[8];
105 110
106 if (len < 4) 111 if (len < 4)
107 return -1; /* Insufficient length */ 112 return SSH_ERR_MESSAGE_INCOMPLETE;
108 put_u64(seqbuf, seqnr); 113 POKE_U64(seqbuf, seqnr);
109 chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); 114 chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL);
110 chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); 115 chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4);
111 *plenp = get_u32(buf); 116 *plenp = PEEK_U32(buf);
112 return 0; 117 return 0;
113} 118}
114 119
diff --git a/cipher-chachapoly.h b/cipher-chachapoly.h
index 1628693b2..b7072be7d 100644
--- a/cipher-chachapoly.h
+++ b/cipher-chachapoly.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: cipher-chachapoly.h,v 1.1 2013/11/21 00:45:44 djm Exp $ */ 1/* $OpenBSD: cipher-chachapoly.h,v 1.4 2014/06/24 01:13:21 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) Damien Miller 2013 <djm@mindrot.org> 4 * Copyright (c) Damien Miller 2013 <djm@mindrot.org>
@@ -28,7 +28,7 @@ struct chachapoly_ctx {
28 struct chacha_ctx main_ctx, header_ctx; 28 struct chacha_ctx main_ctx, header_ctx;
29}; 29};
30 30
31void chachapoly_init(struct chachapoly_ctx *cpctx, 31int chachapoly_init(struct chachapoly_ctx *cpctx,
32 const u_char *key, u_int keylen) 32 const u_char *key, u_int keylen)
33 __attribute__((__bounded__(__buffer__, 2, 3))); 33 __attribute__((__bounded__(__buffer__, 2, 3)));
34int chachapoly_crypt(struct chachapoly_ctx *cpctx, u_int seqnr, 34int chachapoly_crypt(struct chachapoly_ctx *cpctx, u_int seqnr,
diff --git a/cipher.c b/cipher.c
index 53d9b4fb7..638ca2d97 100644
--- a/cipher.c
+++ b/cipher.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: cipher.c,v 1.97 2014/02/07 06:55:54 djm Exp $ */ 1/* $OpenBSD: cipher.c,v 1.99 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -43,21 +43,21 @@
43#include <stdarg.h> 43#include <stdarg.h>
44#include <stdio.h> 44#include <stdio.h>
45 45
46#include "xmalloc.h"
47#include "log.h"
48#include "misc.h"
49#include "cipher.h" 46#include "cipher.h"
50#include "buffer.h" 47#include "misc.h"
48#include "sshbuf.h"
49#include "ssherr.h"
51#include "digest.h" 50#include "digest.h"
52 51
53/* compatibility with old or broken OpenSSL versions */
54#include "openbsd-compat/openssl-compat.h" 52#include "openbsd-compat/openssl-compat.h"
55 53
54#ifdef WITH_SSH1
56extern const EVP_CIPHER *evp_ssh1_bf(void); 55extern const EVP_CIPHER *evp_ssh1_bf(void);
57extern const EVP_CIPHER *evp_ssh1_3des(void); 56extern const EVP_CIPHER *evp_ssh1_3des(void);
58extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); 57extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
58#endif
59 59
60struct Cipher { 60struct sshcipher {
61 char *name; 61 char *name;
62 int number; /* for ssh1 only */ 62 int number; /* for ssh1 only */
63 u_int block_size; 63 u_int block_size;
@@ -68,15 +68,23 @@ struct Cipher {
68 u_int flags; 68 u_int flags;
69#define CFLAG_CBC (1<<0) 69#define CFLAG_CBC (1<<0)
70#define CFLAG_CHACHAPOLY (1<<1) 70#define CFLAG_CHACHAPOLY (1<<1)
71#define CFLAG_AESCTR (1<<2)
72#define CFLAG_NONE (1<<3)
73#ifdef WITH_OPENSSL
71 const EVP_CIPHER *(*evptype)(void); 74 const EVP_CIPHER *(*evptype)(void);
75#else
76 void *ignored;
77#endif
72}; 78};
73 79
74static const struct Cipher ciphers[] = { 80static const struct sshcipher ciphers[] = {
75 { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, 81#ifdef WITH_SSH1
76 { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, 82 { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
77 { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des }, 83 { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
78 { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf }, 84 { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf },
79 85#endif /* WITH_SSH1 */
86#ifdef WITH_OPENSSL
87 { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
80 { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc }, 88 { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc },
81 { "blowfish-cbc", 89 { "blowfish-cbc",
82 SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_bf_cbc }, 90 SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_bf_cbc },
@@ -93,26 +101,33 @@ static const struct Cipher ciphers[] = {
93 { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr }, 101 { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr },
94 { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr }, 102 { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr },
95 { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr }, 103 { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr },
96#ifdef OPENSSL_HAVE_EVPGCM 104# ifdef OPENSSL_HAVE_EVPGCM
97 { "aes128-gcm@openssh.com", 105 { "aes128-gcm@openssh.com",
98 SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm }, 106 SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm },
99 { "aes256-gcm@openssh.com", 107 { "aes256-gcm@openssh.com",
100 SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, 108 SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm },
101#endif 109# endif /* OPENSSL_HAVE_EVPGCM */
110#else /* WITH_OPENSSL */
111 { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, CFLAG_AESCTR, NULL },
112 { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, CFLAG_AESCTR, NULL },
113 { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, CFLAG_AESCTR, NULL },
114 { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, CFLAG_NONE, NULL },
115#endif /* WITH_OPENSSL */
102 { "chacha20-poly1305@openssh.com", 116 { "chacha20-poly1305@openssh.com",
103 SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL }, 117 SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL },
118
104 { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } 119 { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
105}; 120};
106 121
107/*--*/ 122/*--*/
108 123
109/* Returns a list of supported ciphers separated by the specified char. */ 124/* Returns a comma-separated list of supported ciphers. */
110char * 125char *
111cipher_alg_list(char sep, int auth_only) 126cipher_alg_list(char sep, int auth_only)
112{ 127{
113 char *ret = NULL; 128 char *tmp, *ret = NULL;
114 size_t nlen, rlen = 0; 129 size_t nlen, rlen = 0;
115 const Cipher *c; 130 const struct sshcipher *c;
116 131
117 for (c = ciphers; c->name != NULL; c++) { 132 for (c = ciphers; c->name != NULL; c++) {
118 if (c->number != SSH_CIPHER_SSH2) 133 if (c->number != SSH_CIPHER_SSH2)
@@ -122,7 +137,11 @@ cipher_alg_list(char sep, int auth_only)
122 if (ret != NULL) 137 if (ret != NULL)
123 ret[rlen++] = sep; 138 ret[rlen++] = sep;
124 nlen = strlen(c->name); 139 nlen = strlen(c->name);
125 ret = xrealloc(ret, 1, rlen + nlen + 2); 140 if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
141 free(ret);
142 return NULL;
143 }
144 ret = tmp;
126 memcpy(ret + rlen, c->name, nlen + 1); 145 memcpy(ret + rlen, c->name, nlen + 1);
127 rlen += nlen; 146 rlen += nlen;
128 } 147 }
@@ -130,19 +149,19 @@ cipher_alg_list(char sep, int auth_only)
130} 149}
131 150
132u_int 151u_int
133cipher_blocksize(const Cipher *c) 152cipher_blocksize(const struct sshcipher *c)
134{ 153{
135 return (c->block_size); 154 return (c->block_size);
136} 155}
137 156
138u_int 157u_int
139cipher_keylen(const Cipher *c) 158cipher_keylen(const struct sshcipher *c)
140{ 159{
141 return (c->key_len); 160 return (c->key_len);
142} 161}
143 162
144u_int 163u_int
145cipher_seclen(const Cipher *c) 164cipher_seclen(const struct sshcipher *c)
146{ 165{
147 if (strcmp("3des-cbc", c->name) == 0) 166 if (strcmp("3des-cbc", c->name) == 0)
148 return 14; 167 return 14;
@@ -150,13 +169,13 @@ cipher_seclen(const Cipher *c)
150} 169}
151 170
152u_int 171u_int
153cipher_authlen(const Cipher *c) 172cipher_authlen(const struct sshcipher *c)
154{ 173{
155 return (c->auth_len); 174 return (c->auth_len);
156} 175}
157 176
158u_int 177u_int
159cipher_ivlen(const Cipher *c) 178cipher_ivlen(const struct sshcipher *c)
160{ 179{
161 /* 180 /*
162 * Default is cipher block size, except for chacha20+poly1305 that 181 * Default is cipher block size, except for chacha20+poly1305 that
@@ -167,13 +186,13 @@ cipher_ivlen(const Cipher *c)
167} 186}
168 187
169u_int 188u_int
170cipher_get_number(const Cipher *c) 189cipher_get_number(const struct sshcipher *c)
171{ 190{
172 return (c->number); 191 return (c->number);
173} 192}
174 193
175u_int 194u_int
176cipher_is_cbc(const Cipher *c) 195cipher_is_cbc(const struct sshcipher *c)
177{ 196{
178 return (c->flags & CFLAG_CBC) != 0; 197 return (c->flags & CFLAG_CBC) != 0;
179} 198}
@@ -190,20 +209,20 @@ cipher_mask_ssh1(int client)
190 return mask; 209 return mask;
191} 210}
192 211
193const Cipher * 212const struct sshcipher *
194cipher_by_name(const char *name) 213cipher_by_name(const char *name)
195{ 214{
196 const Cipher *c; 215 const struct sshcipher *c;
197 for (c = ciphers; c->name != NULL; c++) 216 for (c = ciphers; c->name != NULL; c++)
198 if (strcmp(c->name, name) == 0) 217 if (strcmp(c->name, name) == 0)
199 return c; 218 return c;
200 return NULL; 219 return NULL;
201} 220}
202 221
203const Cipher * 222const struct sshcipher *
204cipher_by_number(int id) 223cipher_by_number(int id)
205{ 224{
206 const Cipher *c; 225 const struct sshcipher *c;
207 for (c = ciphers; c->name != NULL; c++) 226 for (c = ciphers; c->name != NULL; c++)
208 if (c->number == id) 227 if (c->number == id)
209 return c; 228 return c;
@@ -214,23 +233,22 @@ cipher_by_number(int id)
214int 233int
215ciphers_valid(const char *names) 234ciphers_valid(const char *names)
216{ 235{
217 const Cipher *c; 236 const struct sshcipher *c;
218 char *cipher_list, *cp; 237 char *cipher_list, *cp;
219 char *p; 238 char *p;
220 239
221 if (names == NULL || strcmp(names, "") == 0) 240 if (names == NULL || strcmp(names, "") == 0)
222 return 0; 241 return 0;
223 cipher_list = cp = xstrdup(names); 242 if ((cipher_list = cp = strdup(names)) == NULL)
243 return 0;
224 for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; 244 for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
225 (p = strsep(&cp, CIPHER_SEP))) { 245 (p = strsep(&cp, CIPHER_SEP))) {
226 c = cipher_by_name(p); 246 c = cipher_by_name(p);
227 if (c == NULL || c->number != SSH_CIPHER_SSH2) { 247 if (c == NULL || c->number != SSH_CIPHER_SSH2) {
228 debug("bad cipher %s [%s]", p, names);
229 free(cipher_list); 248 free(cipher_list);
230 return 0; 249 return 0;
231 } 250 }
232 } 251 }
233 debug3("ciphers ok: [%s]", names);
234 free(cipher_list); 252 free(cipher_list);
235 return 1; 253 return 1;
236} 254}
@@ -243,7 +261,7 @@ ciphers_valid(const char *names)
243int 261int
244cipher_number(const char *name) 262cipher_number(const char *name)
245{ 263{
246 const Cipher *c; 264 const struct sshcipher *c;
247 if (name == NULL) 265 if (name == NULL)
248 return -1; 266 return -1;
249 for (c = ciphers; c->name != NULL; c++) 267 for (c = ciphers; c->name != NULL; c++)
@@ -255,90 +273,104 @@ cipher_number(const char *name)
255char * 273char *
256cipher_name(int id) 274cipher_name(int id)
257{ 275{
258 const Cipher *c = cipher_by_number(id); 276 const struct sshcipher *c = cipher_by_number(id);
259 return (c==NULL) ? "<unknown>" : c->name; 277 return (c==NULL) ? "<unknown>" : c->name;
260} 278}
261 279
262void 280const char *
263cipher_init(CipherContext *cc, const Cipher *cipher, 281cipher_warning_message(const struct sshcipher_ctx *cc)
282{
283 if (cc == NULL || cc->cipher == NULL)
284 return NULL;
285 if (cc->cipher->number == SSH_CIPHER_DES)
286 return "use of DES is strongly discouraged due to "
287 "cryptographic weaknesses";
288 return NULL;
289}
290
291int
292cipher_init(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
264 const u_char *key, u_int keylen, const u_char *iv, u_int ivlen, 293 const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
265 int do_encrypt) 294 int do_encrypt)
266{ 295{
267 static int dowarn = 1; 296#ifdef WITH_OPENSSL
268#ifdef SSH_OLD_EVP 297 int ret = SSH_ERR_INTERNAL_ERROR;
269 EVP_CIPHER *type;
270#else
271 const EVP_CIPHER *type; 298 const EVP_CIPHER *type;
272 int klen; 299 int klen;
273#endif
274 u_char *junk, *discard; 300 u_char *junk, *discard;
275 301
276 if (cipher->number == SSH_CIPHER_DES) { 302 if (cipher->number == SSH_CIPHER_DES) {
277 if (dowarn) {
278 error("Warning: use of DES is strongly discouraged "
279 "due to cryptographic weaknesses");
280 dowarn = 0;
281 }
282 if (keylen > 8) 303 if (keylen > 8)
283 keylen = 8; 304 keylen = 8;
284 } 305 }
306#endif
285 cc->plaintext = (cipher->number == SSH_CIPHER_NONE); 307 cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
286 cc->encrypt = do_encrypt; 308 cc->encrypt = do_encrypt;
287 309
288 if (keylen < cipher->key_len) 310 if (keylen < cipher->key_len ||
289 fatal("cipher_init: key length %d is insufficient for %s.", 311 (iv != NULL && ivlen < cipher_ivlen(cipher)))
290 keylen, cipher->name); 312 return SSH_ERR_INVALID_ARGUMENT;
291 if (iv != NULL && ivlen < cipher_ivlen(cipher))
292 fatal("cipher_init: iv length %d is insufficient for %s.",
293 ivlen, cipher->name);
294 cc->cipher = cipher;
295 313
314 cc->cipher = cipher;
296 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { 315 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
297 chachapoly_init(&cc->cp_ctx, key, keylen); 316 return chachapoly_init(&cc->cp_ctx, key, keylen);
298 return;
299 } 317 }
300 type = (*cipher->evptype)(); 318#ifndef WITH_OPENSSL
301 EVP_CIPHER_CTX_init(&cc->evp); 319 if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
302#ifdef SSH_OLD_EVP 320 aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);
303 if (type->key_len > 0 && type->key_len != keylen) { 321 aesctr_ivsetup(&cc->ac_ctx, iv);
304 debug("cipher_init: set keylen (%d -> %d)", 322 return 0;
305 type->key_len, keylen);
306 type->key_len = keylen;
307 } 323 }
308 EVP_CipherInit(&cc->evp, type, (u_char *)key, (u_char *)iv, 324 if ((cc->cipher->flags & CFLAG_NONE) != 0)
309 (do_encrypt == CIPHER_ENCRYPT)); 325 return 0;
326 return SSH_ERR_INVALID_ARGUMENT;
310#else 327#else
328 type = (*cipher->evptype)();
329 EVP_CIPHER_CTX_init(&cc->evp);
311 if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv, 330 if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,
312 (do_encrypt == CIPHER_ENCRYPT)) == 0) 331 (do_encrypt == CIPHER_ENCRYPT)) == 0) {
313 fatal("cipher_init: EVP_CipherInit failed for %s", 332 ret = SSH_ERR_LIBCRYPTO_ERROR;
314 cipher->name); 333 goto bad;
334 }
315 if (cipher_authlen(cipher) && 335 if (cipher_authlen(cipher) &&
316 !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_IV_FIXED, 336 !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_IV_FIXED,
317 -1, (u_char *)iv)) 337 -1, (u_char *)iv)) {
318 fatal("cipher_init: EVP_CTRL_GCM_SET_IV_FIXED failed for %s", 338 ret = SSH_ERR_LIBCRYPTO_ERROR;
319 cipher->name); 339 goto bad;
340 }
320 klen = EVP_CIPHER_CTX_key_length(&cc->evp); 341 klen = EVP_CIPHER_CTX_key_length(&cc->evp);
321 if (klen > 0 && keylen != (u_int)klen) { 342 if (klen > 0 && keylen != (u_int)klen) {
322 debug2("cipher_init: set keylen (%d -> %d)", klen, keylen); 343 if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0) {
323 if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0) 344 ret = SSH_ERR_LIBCRYPTO_ERROR;
324 fatal("cipher_init: set keylen failed (%d -> %d)", 345 goto bad;
325 klen, keylen); 346 }
347 }
348 if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0) {
349 ret = SSH_ERR_LIBCRYPTO_ERROR;
350 goto bad;
326 } 351 }
327 if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0)
328 fatal("cipher_init: EVP_CipherInit: set key failed for %s",
329 cipher->name);
330#endif
331 352
332 if (cipher->discard_len > 0) { 353 if (cipher->discard_len > 0) {
333 junk = xmalloc(cipher->discard_len); 354 if ((junk = malloc(cipher->discard_len)) == NULL ||
334 discard = xmalloc(cipher->discard_len); 355 (discard = malloc(cipher->discard_len)) == NULL) {
335 if (EVP_Cipher(&cc->evp, discard, junk, 356 if (junk != NULL)
336 cipher->discard_len) == 0) 357 free(junk);
337 fatal("evp_crypt: EVP_Cipher failed during discard"); 358 ret = SSH_ERR_ALLOC_FAIL;
359 goto bad;
360 }
361 ret = EVP_Cipher(&cc->evp, discard, junk, cipher->discard_len);
338 explicit_bzero(discard, cipher->discard_len); 362 explicit_bzero(discard, cipher->discard_len);
339 free(junk); 363 free(junk);
340 free(discard); 364 free(discard);
365 if (ret != 1) {
366 ret = SSH_ERR_LIBCRYPTO_ERROR;
367 bad:
368 EVP_CIPHER_CTX_cleanup(&cc->evp);
369 return ret;
370 }
341 } 371 }
372#endif
373 return 0;
342} 374}
343 375
344/* 376/*
@@ -350,204 +382,244 @@ cipher_init(CipherContext *cc, const Cipher *cipher,
350 * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag. 382 * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag.
351 * This tag is written on encryption and verified on decryption. 383 * This tag is written on encryption and verified on decryption.
352 * Both 'aadlen' and 'authlen' can be set to 0. 384 * Both 'aadlen' and 'authlen' can be set to 0.
353 * cipher_crypt() returns 0 on success and -1 if the decryption integrity
354 * check fails.
355 */ 385 */
356int 386int
357cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, 387cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
358 u_int len, u_int aadlen, u_int authlen) 388 const u_char *src, u_int len, u_int aadlen, u_int authlen)
359{ 389{
360 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) 390 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
361 return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len, 391 return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src,
362 aadlen, authlen, cc->encrypt); 392 len, aadlen, authlen, cc->encrypt);
393 }
394#ifndef WITH_OPENSSL
395 if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
396 if (aadlen)
397 memcpy(dest, src, aadlen);
398 aesctr_encrypt_bytes(&cc->ac_ctx, src + aadlen,
399 dest + aadlen, len);
400 return 0;
401 }
402 if ((cc->cipher->flags & CFLAG_NONE) != 0) {
403 memcpy(dest, src, aadlen + len);
404 return 0;
405 }
406 return SSH_ERR_INVALID_ARGUMENT;
407#else
363 if (authlen) { 408 if (authlen) {
364 u_char lastiv[1]; 409 u_char lastiv[1];
365 410
366 if (authlen != cipher_authlen(cc->cipher)) 411 if (authlen != cipher_authlen(cc->cipher))
367 fatal("%s: authlen mismatch %d", __func__, authlen); 412 return SSH_ERR_INVALID_ARGUMENT;
368 /* increment IV */ 413 /* increment IV */
369 if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN, 414 if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN,
370 1, lastiv)) 415 1, lastiv))
371 fatal("%s: EVP_CTRL_GCM_IV_GEN", __func__); 416 return SSH_ERR_LIBCRYPTO_ERROR;
372 /* set tag on decyption */ 417 /* set tag on decyption */
373 if (!cc->encrypt && 418 if (!cc->encrypt &&
374 !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_TAG, 419 !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_TAG,
375 authlen, (u_char *)src + aadlen + len)) 420 authlen, (u_char *)src + aadlen + len))
376 fatal("%s: EVP_CTRL_GCM_SET_TAG", __func__); 421 return SSH_ERR_LIBCRYPTO_ERROR;
377 } 422 }
378 if (aadlen) { 423 if (aadlen) {
379 if (authlen && 424 if (authlen &&
380 EVP_Cipher(&cc->evp, NULL, (u_char *)src, aadlen) < 0) 425 EVP_Cipher(&cc->evp, NULL, (u_char *)src, aadlen) < 0)
381 fatal("%s: EVP_Cipher(aad) failed", __func__); 426 return SSH_ERR_LIBCRYPTO_ERROR;
382 memcpy(dest, src, aadlen); 427 memcpy(dest, src, aadlen);
383 } 428 }
384 if (len % cc->cipher->block_size) 429 if (len % cc->cipher->block_size)
385 fatal("%s: bad plaintext length %d", __func__, len); 430 return SSH_ERR_INVALID_ARGUMENT;
386 if (EVP_Cipher(&cc->evp, dest + aadlen, (u_char *)src + aadlen, 431 if (EVP_Cipher(&cc->evp, dest + aadlen, (u_char *)src + aadlen,
387 len) < 0) 432 len) < 0)
388 fatal("%s: EVP_Cipher failed", __func__); 433 return SSH_ERR_LIBCRYPTO_ERROR;
389 if (authlen) { 434 if (authlen) {
390 /* compute tag (on encrypt) or verify tag (on decrypt) */ 435 /* compute tag (on encrypt) or verify tag (on decrypt) */
391 if (EVP_Cipher(&cc->evp, NULL, NULL, 0) < 0) { 436 if (EVP_Cipher(&cc->evp, NULL, NULL, 0) < 0)
392 if (cc->encrypt) 437 return cc->encrypt ?
393 fatal("%s: EVP_Cipher(final) failed", __func__); 438 SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;
394 else
395 return -1;
396 }
397 if (cc->encrypt && 439 if (cc->encrypt &&
398 !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG, 440 !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG,
399 authlen, dest + aadlen + len)) 441 authlen, dest + aadlen + len))
400 fatal("%s: EVP_CTRL_GCM_GET_TAG", __func__); 442 return SSH_ERR_LIBCRYPTO_ERROR;
401 } 443 }
402 return 0; 444 return 0;
445#endif
403} 446}
404 447
405/* Extract the packet length, including any decryption necessary beforehand */ 448/* Extract the packet length, including any decryption necessary beforehand */
406int 449int
407cipher_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, 450cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr,
408 const u_char *cp, u_int len) 451 const u_char *cp, u_int len)
409{ 452{
410 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) 453 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
411 return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr, 454 return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr,
412 cp, len); 455 cp, len);
413 if (len < 4) 456 if (len < 4)
414 return -1; 457 return SSH_ERR_MESSAGE_INCOMPLETE;
415 *plenp = get_u32(cp); 458 *plenp = get_u32(cp);
416 return 0; 459 return 0;
417} 460}
418 461
419void 462int
420cipher_cleanup(CipherContext *cc) 463cipher_cleanup(struct sshcipher_ctx *cc)
421{ 464{
465 if (cc == NULL || cc->cipher == NULL)
466 return 0;
422 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) 467 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
423 explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx)); 468 explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx));
469 else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
470 explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx));
471#ifdef WITH_OPENSSL
424 else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) 472 else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
425 error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); 473 return SSH_ERR_LIBCRYPTO_ERROR;
474#endif
475 return 0;
426} 476}
427 477
428/* 478/*
429 * Selects the cipher, and keys if by computing the MD5 checksum of the 479 * Selects the cipher, and keys if by computing the MD5 checksum of the
430 * passphrase and using the resulting 16 bytes as the key. 480 * passphrase and using the resulting 16 bytes as the key.
431 */ 481 */
432 482int
433void 483cipher_set_key_string(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
434cipher_set_key_string(CipherContext *cc, const Cipher *cipher,
435 const char *passphrase, int do_encrypt) 484 const char *passphrase, int do_encrypt)
436{ 485{
437 u_char digest[16]; 486 u_char digest[16];
487 int r = SSH_ERR_INTERNAL_ERROR;
438 488
439 if (ssh_digest_memory(SSH_DIGEST_MD5, passphrase, strlen(passphrase), 489 if ((r = ssh_digest_memory(SSH_DIGEST_MD5,
440 digest, sizeof(digest)) < 0) 490 passphrase, strlen(passphrase),
441 fatal("%s: md5 failed", __func__); 491 digest, sizeof(digest))) != 0)
442 492 goto out;
443 cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);
444 493
494 r = cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);
495 out:
445 explicit_bzero(digest, sizeof(digest)); 496 explicit_bzero(digest, sizeof(digest));
497 return r;
446} 498}
447 499
448/* 500/*
449 * Exports an IV from the CipherContext required to export the key 501 * Exports an IV from the sshcipher_ctx required to export the key
450 * state back from the unprivileged child to the privileged parent 502 * state back from the unprivileged child to the privileged parent
451 * process. 503 * process.
452 */ 504 */
453
454int 505int
455cipher_get_keyiv_len(const CipherContext *cc) 506cipher_get_keyiv_len(const struct sshcipher_ctx *cc)
456{ 507{
457 const Cipher *c = cc->cipher; 508 const struct sshcipher *c = cc->cipher;
458 int ivlen; 509 int ivlen = 0;
459 510
460 if (c->number == SSH_CIPHER_3DES) 511 if (c->number == SSH_CIPHER_3DES)
461 ivlen = 24; 512 ivlen = 24;
462 else if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) 513 else if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
463 ivlen = 0; 514 ivlen = 0;
515#ifdef WITH_OPENSSL
464 else 516 else
465 ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); 517 ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp);
518#endif /* WITH_OPENSSL */
466 return (ivlen); 519 return (ivlen);
467} 520}
468 521
469void 522int
470cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) 523cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
471{ 524{
472 const Cipher *c = cc->cipher; 525 const struct sshcipher *c = cc->cipher;
473 int evplen; 526#ifdef WITH_OPENSSL
527 int evplen;
528#endif
474 529
475 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { 530 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
476 if (len != 0) 531 if (len != 0)
477 fatal("%s: wrong iv length %d != %d", __func__, len, 0); 532 return SSH_ERR_INVALID_ARGUMENT;
478 return; 533 return 0;
479 } 534 }
535 if ((cc->cipher->flags & CFLAG_NONE) != 0)
536 return 0;
480 537
481 switch (c->number) { 538 switch (c->number) {
539#ifdef WITH_OPENSSL
482 case SSH_CIPHER_SSH2: 540 case SSH_CIPHER_SSH2:
483 case SSH_CIPHER_DES: 541 case SSH_CIPHER_DES:
484 case SSH_CIPHER_BLOWFISH: 542 case SSH_CIPHER_BLOWFISH:
485 evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); 543 evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
486 if (evplen <= 0) 544 if (evplen == 0)
487 return; 545 return 0;
546 else if (evplen < 0)
547 return SSH_ERR_LIBCRYPTO_ERROR;
488 if ((u_int)evplen != len) 548 if ((u_int)evplen != len)
489 fatal("%s: wrong iv length %d != %d", __func__, 549 return SSH_ERR_INVALID_ARGUMENT;
490 evplen, len);
491#ifdef USE_BUILTIN_RIJNDAEL
492 if (c->evptype == evp_rijndael)
493 ssh_rijndael_iv(&cc->evp, 0, iv, len);
494 else
495#endif
496#ifndef OPENSSL_HAVE_EVPCTR 550#ifndef OPENSSL_HAVE_EVPCTR
497 if (c->evptype == evp_aes_128_ctr) 551 if (c->evptype == evp_aes_128_ctr)
498 ssh_aes_ctr_iv(&cc->evp, 0, iv, len); 552 ssh_aes_ctr_iv(&cc->evp, 0, iv, len);
499 else 553 else
500#endif 554#endif
501 memcpy(iv, cc->evp.iv, len); 555 if (cipher_authlen(c)) {
556 if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN,
557 len, iv))
558 return SSH_ERR_LIBCRYPTO_ERROR;
559 } else
560 memcpy(iv, cc->evp.iv, len);
502 break; 561 break;
562#endif
563#ifdef WITH_SSH1
503 case SSH_CIPHER_3DES: 564 case SSH_CIPHER_3DES:
504 ssh1_3des_iv(&cc->evp, 0, iv, 24); 565 return ssh1_3des_iv(&cc->evp, 0, iv, 24);
505 break; 566#endif
506 default: 567 default:
507 fatal("%s: bad cipher %d", __func__, c->number); 568 return SSH_ERR_INVALID_ARGUMENT;
508 } 569 }
570 return 0;
509} 571}
510 572
511void 573int
512cipher_set_keyiv(CipherContext *cc, u_char *iv) 574cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv)
513{ 575{
514 const Cipher *c = cc->cipher; 576 const struct sshcipher *c = cc->cipher;
515 int evplen = 0; 577#ifdef WITH_OPENSSL
578 int evplen = 0;
579#endif
516 580
517 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) 581 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
518 return; 582 return 0;
583 if ((cc->cipher->flags & CFLAG_NONE) != 0)
584 return 0;
519 585
520 switch (c->number) { 586 switch (c->number) {
587#ifdef WITH_OPENSSL
521 case SSH_CIPHER_SSH2: 588 case SSH_CIPHER_SSH2:
522 case SSH_CIPHER_DES: 589 case SSH_CIPHER_DES:
523 case SSH_CIPHER_BLOWFISH: 590 case SSH_CIPHER_BLOWFISH:
524 evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); 591 evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
525 if (evplen == 0) 592 if (evplen <= 0)
526 return; 593 return SSH_ERR_LIBCRYPTO_ERROR;
527#ifdef USE_BUILTIN_RIJNDAEL 594 if (cipher_authlen(c)) {
528 if (c->evptype == evp_rijndael) 595 /* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */
529 ssh_rijndael_iv(&cc->evp, 1, iv, evplen); 596 if (!EVP_CIPHER_CTX_ctrl(&cc->evp,
530 else 597 EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv))
531#endif 598 return SSH_ERR_LIBCRYPTO_ERROR;
532#ifndef OPENSSL_HAVE_EVPCTR 599 } else
533 if (c->evptype == evp_aes_128_ctr) 600 memcpy(cc->evp.iv, iv, evplen);
534 ssh_aes_ctr_iv(&cc->evp, 1, iv, evplen);
535 else
536#endif
537 memcpy(cc->evp.iv, iv, evplen);
538 break; 601 break;
602#endif
603#ifdef WITH_SSH1
539 case SSH_CIPHER_3DES: 604 case SSH_CIPHER_3DES:
540 ssh1_3des_iv(&cc->evp, 1, iv, 24); 605 return ssh1_3des_iv(&cc->evp, 1, (u_char *)iv, 24);
541 break; 606#endif
542 default: 607 default:
543 fatal("%s: bad cipher %d", __func__, c->number); 608 return SSH_ERR_INVALID_ARGUMENT;
544 } 609 }
610 return 0;
545} 611}
546 612
613#ifdef WITH_OPENSSL
614#define EVP_X_STATE(evp) (evp).cipher_data
615#define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size
616#endif
617
547int 618int
548cipher_get_keycontext(const CipherContext *cc, u_char *dat) 619cipher_get_keycontext(const struct sshcipher_ctx *cc, u_char *dat)
549{ 620{
550 const Cipher *c = cc->cipher; 621#ifdef WITH_OPENSSL
622 const struct sshcipher *c = cc->cipher;
551 int plen = 0; 623 int plen = 0;
552 624
553 if (c->evptype == EVP_rc4) { 625 if (c->evptype == EVP_rc4) {
@@ -557,16 +629,21 @@ cipher_get_keycontext(const CipherContext *cc, u_char *dat)
557 memcpy(dat, EVP_X_STATE(cc->evp), plen); 629 memcpy(dat, EVP_X_STATE(cc->evp), plen);
558 } 630 }
559 return (plen); 631 return (plen);
632#else
633 return 0;
634#endif
560} 635}
561 636
562void 637void
563cipher_set_keycontext(CipherContext *cc, u_char *dat) 638cipher_set_keycontext(struct sshcipher_ctx *cc, const u_char *dat)
564{ 639{
565 const Cipher *c = cc->cipher; 640#ifdef WITH_OPENSSL
641 const struct sshcipher *c = cc->cipher;
566 int plen; 642 int plen;
567 643
568 if (c->evptype == EVP_rc4) { 644 if (c->evptype == EVP_rc4) {
569 plen = EVP_X_STATE_LEN(cc->evp); 645 plen = EVP_X_STATE_LEN(cc->evp);
570 memcpy(EVP_X_STATE(cc->evp), dat, plen); 646 memcpy(EVP_X_STATE(cc->evp), dat, plen);
571 } 647 }
648#endif
572} 649}
diff --git a/cipher.h b/cipher.h
index 133d2e73d..de74c1e3b 100644
--- a/cipher.h
+++ b/cipher.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: cipher.h,v 1.44 2014/01/25 10:12:50 dtucker Exp $ */ 1/* $OpenBSD: cipher.h,v 1.46 2014/06/24 01:13:21 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -37,8 +37,10 @@
37#ifndef CIPHER_H 37#ifndef CIPHER_H
38#define CIPHER_H 38#define CIPHER_H
39 39
40#include <sys/types.h>
40#include <openssl/evp.h> 41#include <openssl/evp.h>
41#include "cipher-chachapoly.h" 42#include "cipher-chachapoly.h"
43#include "cipher-aesctr.h"
42 44
43/* 45/*
44 * Cipher types for SSH-1. New types can be added, but old types should not 46 * Cipher types for SSH-1. New types can be added, but old types should not
@@ -60,44 +62,47 @@
60#define CIPHER_ENCRYPT 1 62#define CIPHER_ENCRYPT 1
61#define CIPHER_DECRYPT 0 63#define CIPHER_DECRYPT 0
62 64
63typedef struct Cipher Cipher; 65struct sshcipher;
64typedef struct CipherContext CipherContext; 66struct sshcipher_ctx {
65
66struct Cipher;
67struct CipherContext {
68 int plaintext; 67 int plaintext;
69 int encrypt; 68 int encrypt;
70 EVP_CIPHER_CTX evp; 69 EVP_CIPHER_CTX evp;
71 struct chachapoly_ctx cp_ctx; /* XXX union with evp? */ 70 struct chachapoly_ctx cp_ctx; /* XXX union with evp? */
72 const Cipher *cipher; 71 struct aesctr_ctx ac_ctx; /* XXX union with evp? */
72 const struct sshcipher *cipher;
73}; 73};
74 74
75typedef struct sshcipher Cipher ;
76typedef struct sshcipher_ctx CipherContext ;
77
75u_int cipher_mask_ssh1(int); 78u_int cipher_mask_ssh1(int);
76const Cipher *cipher_by_name(const char *); 79const struct sshcipher *cipher_by_name(const char *);
77const Cipher *cipher_by_number(int); 80const struct sshcipher *cipher_by_number(int);
78int cipher_number(const char *); 81int cipher_number(const char *);
79char *cipher_name(int); 82char *cipher_name(int);
80int ciphers_valid(const char *); 83int ciphers_valid(const char *);
81char *cipher_alg_list(char, int); 84char *cipher_alg_list(char, int);
82void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, 85int cipher_init(struct sshcipher_ctx *, const struct sshcipher *,
83 const u_char *, u_int, int); 86 const u_char *, u_int, const u_char *, u_int, int);
84int cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, 87const char* cipher_warning_message(const struct sshcipher_ctx *);
88int cipher_crypt(struct sshcipher_ctx *, u_int, u_char *, const u_char *,
85 u_int, u_int, u_int); 89 u_int, u_int, u_int);
86int cipher_get_length(CipherContext *, u_int *, u_int, 90int cipher_get_length(struct sshcipher_ctx *, u_int *, u_int,
87 const u_char *, u_int); 91 const u_char *, u_int);
88void cipher_cleanup(CipherContext *); 92int cipher_cleanup(struct sshcipher_ctx *);
89void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int); 93int cipher_set_key_string(struct sshcipher_ctx *, const struct sshcipher *,
90u_int cipher_blocksize(const Cipher *); 94 const char *, int);
91u_int cipher_keylen(const Cipher *); 95u_int cipher_blocksize(const struct sshcipher *);
92u_int cipher_seclen(const Cipher *); 96u_int cipher_keylen(const struct sshcipher *);
93u_int cipher_authlen(const Cipher *); 97u_int cipher_seclen(const struct sshcipher *);
94u_int cipher_ivlen(const Cipher *); 98u_int cipher_authlen(const struct sshcipher *);
95u_int cipher_is_cbc(const Cipher *); 99u_int cipher_ivlen(const struct sshcipher *);
100u_int cipher_is_cbc(const struct sshcipher *);
96 101
97u_int cipher_get_number(const Cipher *); 102u_int cipher_get_number(const struct sshcipher *);
98void cipher_get_keyiv(CipherContext *, u_char *, u_int); 103int cipher_get_keyiv(struct sshcipher_ctx *, u_char *, u_int);
99void cipher_set_keyiv(CipherContext *, u_char *); 104int cipher_set_keyiv(struct sshcipher_ctx *, const u_char *);
100int cipher_get_keyiv_len(const CipherContext *); 105int cipher_get_keyiv_len(const struct sshcipher_ctx *);
101int cipher_get_keycontext(const CipherContext *, u_char *); 106int cipher_get_keycontext(const struct sshcipher_ctx *, u_char *);
102void cipher_set_keycontext(CipherContext *, u_char *); 107void cipher_set_keycontext(struct sshcipher_ctx *, const u_char *);
103#endif /* CIPHER_H */ 108#endif /* CIPHER_H */
diff --git a/clientloop.c b/clientloop.c
index 59ad3a2c3..397c96532 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.c,v 1.258 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: clientloop.c,v 1.261 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -100,13 +100,13 @@
100#include "cipher.h" 100#include "cipher.h"
101#include "kex.h" 101#include "kex.h"
102#include "log.h" 102#include "log.h"
103#include "misc.h"
103#include "readconf.h" 104#include "readconf.h"
104#include "clientloop.h" 105#include "clientloop.h"
105#include "sshconnect.h" 106#include "sshconnect.h"
106#include "authfd.h" 107#include "authfd.h"
107#include "atomicio.h" 108#include "atomicio.h"
108#include "sshpty.h" 109#include "sshpty.h"
109#include "misc.h"
110#include "match.h" 110#include "match.h"
111#include "msg.h" 111#include "msg.h"
112#include "roaming.h" 112#include "roaming.h"
@@ -871,13 +871,11 @@ static void
871process_cmdline(void) 871process_cmdline(void)
872{ 872{
873 void (*handler)(int); 873 void (*handler)(int);
874 char *s, *cmd, *cancel_host; 874 char *s, *cmd;
875 int delete = 0, local = 0, remote = 0, dynamic = 0; 875 int ok, delete = 0, local = 0, remote = 0, dynamic = 0;
876 int cancel_port, ok; 876 struct Forward fwd;
877 Forward fwd;
878 877
879 memset(&fwd, 0, sizeof(fwd)); 878 memset(&fwd, 0, sizeof(fwd));
880 fwd.listen_host = fwd.connect_host = NULL;
881 879
882 leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); 880 leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
883 handler = signal(SIGINT, SIG_IGN); 881 handler = signal(SIGINT, SIG_IGN);
@@ -943,29 +941,20 @@ process_cmdline(void)
943 941
944 /* XXX update list of forwards in options */ 942 /* XXX update list of forwards in options */
945 if (delete) { 943 if (delete) {
946 cancel_port = 0; 944 /* We pass 1 for dynamicfwd to restrict to 1 or 2 fields. */
947 cancel_host = hpdelim(&s); /* may be NULL */ 945 if (!parse_forward(&fwd, s, 1, 0)) {
948 if (s != NULL) { 946 logit("Bad forwarding close specification.");
949 cancel_port = a2port(s);
950 cancel_host = cleanhostname(cancel_host);
951 } else {
952 cancel_port = a2port(cancel_host);
953 cancel_host = NULL;
954 }
955 if (cancel_port <= 0) {
956 logit("Bad forwarding close port");
957 goto out; 947 goto out;
958 } 948 }
959 if (remote) 949 if (remote)
960 ok = channel_request_rforward_cancel(cancel_host, 950 ok = channel_request_rforward_cancel(&fwd) == 0;
961 cancel_port) == 0;
962 else if (dynamic) 951 else if (dynamic)
963 ok = channel_cancel_lport_listener(cancel_host, 952 ok = channel_cancel_lport_listener(&fwd,
964 cancel_port, 0, options.gateway_ports) > 0; 953 0, &options.fwd_opts) > 0;
965 else 954 else
966 ok = channel_cancel_lport_listener(cancel_host, 955 ok = channel_cancel_lport_listener(&fwd,
967 cancel_port, CHANNEL_CANCEL_PORT_STATIC, 956 CHANNEL_CANCEL_PORT_STATIC,
968 options.gateway_ports) > 0; 957 &options.fwd_opts) > 0;
969 if (!ok) { 958 if (!ok) {
970 logit("Unkown port forwarding."); 959 logit("Unkown port forwarding.");
971 goto out; 960 goto out;
@@ -977,16 +966,13 @@ process_cmdline(void)
977 goto out; 966 goto out;
978 } 967 }
979 if (local || dynamic) { 968 if (local || dynamic) {
980 if (!channel_setup_local_fwd_listener(fwd.listen_host, 969 if (!channel_setup_local_fwd_listener(&fwd,
981 fwd.listen_port, fwd.connect_host, 970 &options.fwd_opts)) {
982 fwd.connect_port, options.gateway_ports)) {
983 logit("Port forwarding failed."); 971 logit("Port forwarding failed.");
984 goto out; 972 goto out;
985 } 973 }
986 } else { 974 } else {
987 if (channel_request_remote_forwarding(fwd.listen_host, 975 if (channel_request_remote_forwarding(&fwd) < 0) {
988 fwd.listen_port, fwd.connect_host,
989 fwd.connect_port) < 0) {
990 logit("Port forwarding failed."); 976 logit("Port forwarding failed.");
991 goto out; 977 goto out;
992 } 978 }
@@ -999,7 +985,9 @@ out:
999 enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); 985 enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
1000 free(cmd); 986 free(cmd);
1001 free(fwd.listen_host); 987 free(fwd.listen_host);
988 free(fwd.listen_path);
1002 free(fwd.connect_host); 989 free(fwd.connect_host);
990 free(fwd.connect_path);
1003} 991}
1004 992
1005/* reasons to suppress output of an escape command in help output */ 993/* 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)
1845 originator_port = packet_get_int(); 1833 originator_port = packet_get_int();
1846 packet_check_eom(); 1834 packet_check_eom();
1847 1835
1848 debug("client_request_forwarded_tcpip: listen %s port %d, " 1836 debug("%s: listen %s port %d, originator %s port %d", __func__,
1849 "originator %s port %d", listen_address, listen_port, 1837 listen_address, listen_port, originator_address, originator_port);
1850 originator_address, originator_port);
1851 1838
1852 c = channel_connect_by_listen_address(listen_port, 1839 c = channel_connect_by_listen_address(listen_address, listen_port,
1853 "forwarded-tcpip", originator_address); 1840 "forwarded-tcpip", originator_address);
1854 1841
1855 free(originator_address); 1842 free(originator_address);
@@ -1858,6 +1845,27 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
1858} 1845}
1859 1846
1860static Channel * 1847static Channel *
1848client_request_forwarded_streamlocal(const char *request_type, int rchan)
1849{
1850 Channel *c = NULL;
1851 char *listen_path;
1852
1853 /* Get the remote path. */
1854 listen_path = packet_get_string(NULL);
1855 /* XXX: Skip reserved field for now. */
1856 if (packet_get_string_ptr(NULL) == NULL)
1857 fatal("%s: packet_get_string_ptr failed", __func__);
1858 packet_check_eom();
1859
1860 debug("%s: %s", __func__, listen_path);
1861
1862 c = channel_connect_by_listen_path(listen_path,
1863 "forwarded-streamlocal@openssh.com", "forwarded-streamlocal");
1864 free(listen_path);
1865 return c;
1866}
1867
1868static Channel *
1861client_request_x11(const char *request_type, int rchan) 1869client_request_x11(const char *request_type, int rchan)
1862{ 1870{
1863 Channel *c = NULL; 1871 Channel *c = NULL;
@@ -1984,6 +1992,8 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
1984 1992
1985 if (strcmp(ctype, "forwarded-tcpip") == 0) { 1993 if (strcmp(ctype, "forwarded-tcpip") == 0) {
1986 c = client_request_forwarded_tcpip(ctype, rchan); 1994 c = client_request_forwarded_tcpip(ctype, rchan);
1995 } else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) {
1996 c = client_request_forwarded_streamlocal(ctype, rchan);
1987 } else if (strcmp(ctype, "x11") == 0) { 1997 } else if (strcmp(ctype, "x11") == 0) {
1988 c = client_request_x11(ctype, rchan); 1998 c = client_request_x11(ctype, rchan);
1989 } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) { 1999 } 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)
2054 } 2064 }
2055 packet_check_eom(); 2065 packet_check_eom();
2056 } 2066 }
2057 if (reply && c != NULL) { 2067 if (reply && c != NULL && !(c->flags & CHAN_CLOSE_SENT)) {
2058 packet_start(success ? 2068 packet_start(success ?
2059 SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); 2069 SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
2060 packet_put_int(c->remote_id); 2070 packet_put_int(c->remote_id);
diff --git a/compat.c b/compat.c
index 9d9fabef3..4d286e8e9 100644
--- a/compat.c
+++ b/compat.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: compat.c,v 1.82 2013/12/30 23:52:27 djm Exp $ */ 1/* $OpenBSD: compat.c,v 1.85 2014/04/20 02:49:32 djm Exp $ */
2/* 2/*
3 * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. 3 * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
4 * 4 *
@@ -95,6 +95,9 @@ compat_datafellows(const char *version)
95 { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, 95 { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
96 { "OpenSSH_4*", 0 }, 96 { "OpenSSH_4*", 0 },
97 { "OpenSSH_5*", SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT}, 97 { "OpenSSH_5*", SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT},
98 { "OpenSSH_6.6.1*", SSH_NEW_OPENSSH},
99 { "OpenSSH_6.5*,"
100 "OpenSSH_6.6*", SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD},
98 { "OpenSSH*", SSH_NEW_OPENSSH }, 101 { "OpenSSH*", SSH_NEW_OPENSSH },
99 { "*MindTerm*", 0 }, 102 { "*MindTerm*", 0 },
100 { "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| 103 { "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
@@ -251,7 +254,6 @@ compat_cipher_proposal(char *cipher_prop)
251 return cipher_prop; 254 return cipher_prop;
252} 255}
253 256
254
255char * 257char *
256compat_pkalg_proposal(char *pkalg_prop) 258compat_pkalg_proposal(char *pkalg_prop)
257{ 259{
@@ -265,3 +267,16 @@ compat_pkalg_proposal(char *pkalg_prop)
265 return pkalg_prop; 267 return pkalg_prop;
266} 268}
267 269
270char *
271compat_kex_proposal(char *kex_prop)
272{
273 if (!(datafellows & SSH_BUG_CURVE25519PAD))
274 return kex_prop;
275 debug2("%s: original KEX proposal: %s", __func__, kex_prop);
276 kex_prop = filter_proposal(kex_prop, "curve25519-sha256@libssh.org");
277 debug2("%s: compat KEX proposal: %s", __func__, kex_prop);
278 if (*kex_prop == '\0')
279 fatal("No supported key exchange algorithms found");
280 return kex_prop;
281}
282
diff --git a/compat.h b/compat.h
index b174fa171..2e25d5ba9 100644
--- a/compat.h
+++ b/compat.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: compat.h,v 1.44 2013/12/30 23:52:27 djm Exp $ */ 1/* $OpenBSD: compat.h,v 1.45 2014/04/18 23:52:25 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
@@ -59,6 +59,7 @@
59#define SSH_BUG_RFWD_ADDR 0x02000000 59#define SSH_BUG_RFWD_ADDR 0x02000000
60#define SSH_NEW_OPENSSH 0x04000000 60#define SSH_NEW_OPENSSH 0x04000000
61#define SSH_BUG_DYNAMIC_RPORT 0x08000000 61#define SSH_BUG_DYNAMIC_RPORT 0x08000000
62#define SSH_BUG_CURVE25519PAD 0x10000000
62 63
63void enable_compat13(void); 64void enable_compat13(void);
64void enable_compat20(void); 65void enable_compat20(void);
@@ -66,6 +67,7 @@ void compat_datafellows(const char *);
66int proto_spec(const char *); 67int proto_spec(const char *);
67char *compat_cipher_proposal(char *); 68char *compat_cipher_proposal(char *);
68char *compat_pkalg_proposal(char *); 69char *compat_pkalg_proposal(char *);
70char *compat_kex_proposal(char *);
69 71
70extern int compat13; 72extern int compat13;
71extern int compat20; 73extern int compat20;
diff --git a/config.h.in b/config.h.in
index 0401ad181..16d620615 100644
--- a/config.h.in
+++ b/config.h.in
@@ -420,6 +420,9 @@
420/* Define to 1 if you have the `EVP_MD_CTX_init' function. */ 420/* Define to 1 if you have the `EVP_MD_CTX_init' function. */
421#undef HAVE_EVP_MD_CTX_INIT 421#undef HAVE_EVP_MD_CTX_INIT
422 422
423/* Define to 1 if you have the `EVP_ripemd160' function. */
424#undef HAVE_EVP_RIPEMD160
425
423/* Define to 1 if you have the `EVP_sha256' function. */ 426/* Define to 1 if you have the `EVP_sha256' function. */
424#undef HAVE_EVP_SHA256 427#undef HAVE_EVP_SHA256
425 428
@@ -768,6 +771,9 @@
768/* Define to 1 if you have the <memory.h> header file. */ 771/* Define to 1 if you have the <memory.h> header file. */
769#undef HAVE_MEMORY_H 772#undef HAVE_MEMORY_H
770 773
774/* Define to 1 if you have the `memset_s' function. */
775#undef HAVE_MEMSET_S
776
771/* Define to 1 if you have the `mkdtemp' function. */ 777/* Define to 1 if you have the `mkdtemp' function. */
772#undef HAVE_MKDTEMP 778#undef HAVE_MKDTEMP
773 779
@@ -1324,9 +1330,6 @@
1324/* Define if va_copy exists */ 1330/* Define if va_copy exists */
1325#undef HAVE_VA_COPY 1331#undef HAVE_VA_COPY
1326 1332
1327/* Define to 1 if you have the `vhangup' function. */
1328#undef HAVE_VHANGUP
1329
1330/* Define to 1 if you have the <vis.h> header file. */ 1333/* Define to 1 if you have the <vis.h> header file. */
1331#undef HAVE_VIS_H 1334#undef HAVE_VIS_H
1332 1335
@@ -1387,9 +1390,6 @@
1387/* Define if pututxline updates lastlog too */ 1390/* Define if pututxline updates lastlog too */
1388#undef LASTLOG_WRITE_PUTUTXLINE 1391#undef LASTLOG_WRITE_PUTUTXLINE
1389 1392
1390/* Define if you want TCP Wrappers support */
1391#undef LIBWRAP
1392
1393/* Define to whatever link() returns for "not supported" if it doesn't return 1393/* Define to whatever link() returns for "not supported" if it doesn't return
1394 EOPNOTSUPP. */ 1394 EOPNOTSUPP. */
1395#undef LINK_OPNOTSUPP_ERRNO 1395#undef LINK_OPNOTSUPP_ERRNO
@@ -1662,9 +1662,15 @@
1662/* Define if you want IRIX project management */ 1662/* Define if you want IRIX project management */
1663#undef WITH_IRIX_PROJECT 1663#undef WITH_IRIX_PROJECT
1664 1664
1665/* use libcrypto for cryptography */
1666#undef WITH_OPENSSL
1667
1665/* Define if you want SELinux support. */ 1668/* Define if you want SELinux support. */
1666#undef WITH_SELINUX 1669#undef WITH_SELINUX
1667 1670
1671/* include SSH protocol version 1 support */
1672#undef WITH_SSH1
1673
1668/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most 1674/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
1669 significant byte first (like Motorola and SPARC, unlike Intel). */ 1675 significant byte first (like Motorola and SPARC, unlike Intel). */
1670#if defined AC_APPLE_UNIVERSAL_BUILD 1676#if defined AC_APPLE_UNIVERSAL_BUILD
diff --git a/configure b/configure
index d690393a3..6815388cc 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
1#! /bin/sh 1#! /bin/sh
2# From configure.ac Revision: 1.571 . 2# From configure.ac Revision: 1.583 .
3# Guess values for system-dependent variables and create Makefiles. 3# Guess values for system-dependent variables and create Makefiles.
4# Generated by GNU Autoconf 2.68 for OpenSSH Portable. 4# Generated by GNU Autoconf 2.68 for OpenSSH Portable.
5# 5#
@@ -725,7 +725,6 @@ with_osfsia
725with_zlib 725with_zlib
726with_zlib_version_check 726with_zlib_version_check
727with_skey 727with_skey
728with_tcp_wrappers
729with_ldns 728with_ldns
730with_libedit 729with_libedit
731with_audit 730with_audit
@@ -1417,7 +1416,6 @@ Optional Packages:
1417 --with-zlib=PATH Use zlib in PATH 1416 --with-zlib=PATH Use zlib in PATH
1418 --without-zlib-version-check Disable zlib version check 1417 --without-zlib-version-check Disable zlib version check
1419 --with-skey[=PATH] Enable S/Key support (optionally in PATH) 1418 --with-skey[=PATH] Enable S/Key support (optionally in PATH)
1420 --with-tcp-wrappers[=PATH] Enable tcpwrappers support (optionally in PATH)
1421 --with-ldns[=PATH] Use ldns for DNSSEC support (optionally in PATH) 1419 --with-ldns[=PATH] Use ldns for DNSSEC support (optionally in PATH)
1422 --with-libedit[=PATH] Enable libedit support for sftp 1420 --with-libedit[=PATH] Enable libedit support for sftp
1423 --with-audit=module Enable audit support (modules=debug,bsm,linux) 1421 --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
9706fi 9704fi
9707 9705
9708 9706
9709# Check whether user wants TCP wrappers support
9710TCPW_MSG="no"
9711
9712# Check whether --with-tcp-wrappers was given.
9713if test "${with_tcp_wrappers+set}" = set; then :
9714 withval=$with_tcp_wrappers;
9715 if test "x$withval" != "xno" ; then
9716 saved_LIBS="$LIBS"
9717 saved_LDFLAGS="$LDFLAGS"
9718 saved_CPPFLAGS="$CPPFLAGS"
9719 if test -n "${withval}" && \
9720 test "x${withval}" != "xyes"; then
9721 if test -d "${withval}/lib"; then
9722 if test -n "${need_dash_r}"; then
9723 LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
9724 else
9725 LDFLAGS="-L${withval}/lib ${LDFLAGS}"
9726 fi
9727 else
9728 if test -n "${need_dash_r}"; then
9729 LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}"
9730 else
9731 LDFLAGS="-L${withval} ${LDFLAGS}"
9732 fi
9733 fi
9734 if test -d "${withval}/include"; then
9735 CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
9736 else
9737 CPPFLAGS="-I${withval} ${CPPFLAGS}"
9738 fi
9739 fi
9740 LIBS="-lwrap $LIBS"
9741 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libwrap" >&5
9742$as_echo_n "checking for libwrap... " >&6; }
9743 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
9744/* end confdefs.h. */
9745
9746#include <sys/types.h>
9747#include <sys/socket.h>
9748#include <netinet/in.h>
9749#include <tcpd.h>
9750int deny_severity = 0, allow_severity = 0;
9751
9752int
9753main ()
9754{
9755
9756 hosts_access(0);
9757
9758 ;
9759 return 0;
9760}
9761_ACEOF
9762if ac_fn_c_try_link "$LINENO"; then :
9763
9764 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
9765$as_echo "yes" >&6; }
9766
9767$as_echo "#define LIBWRAP 1" >>confdefs.h
9768
9769 SSHDLIBS="$SSHDLIBS -lwrap"
9770 TCPW_MSG="yes"
9771
9772else
9773
9774 as_fn_error $? "*** libwrap missing" "$LINENO" 5
9775
9776
9777fi
9778rm -f core conftest.err conftest.$ac_objext \
9779 conftest$ac_exeext conftest.$ac_ext
9780 LIBS="$saved_LIBS"
9781 fi
9782
9783
9784fi
9785
9786
9787# Check whether user wants to use ldns 9707# Check whether user wants to use ldns
9788LDNS_MSG="no" 9708LDNS_MSG="no"
9789 9709
@@ -10348,10 +10268,6 @@ for ac_func in \
10348 Blowfish_expandstate \ 10268 Blowfish_expandstate \
10349 Blowfish_expand0state \ 10269 Blowfish_expand0state \
10350 Blowfish_stream2word \ 10270 Blowfish_stream2word \
10351 arc4random \
10352 arc4random_buf \
10353 arc4random_stir \
10354 arc4random_uniform \
10355 asprintf \ 10271 asprintf \
10356 b64_ntop \ 10272 b64_ntop \
10357 __b64_ntop \ 10273 __b64_ntop \
@@ -10395,6 +10311,7 @@ for ac_func in \
10395 mblen \ 10311 mblen \
10396 md5_crypt \ 10312 md5_crypt \
10397 memmove \ 10313 memmove \
10314 memset_s \
10398 mkdtemp \ 10315 mkdtemp \
10399 mmap \ 10316 mmap \
10400 ngetaddrinfo \ 10317 ngetaddrinfo \
@@ -10453,7 +10370,6 @@ for ac_func in \
10453 user_from_uid \ 10370 user_from_uid \
10454 usleep \ 10371 usleep \
10455 vasprintf \ 10372 vasprintf \
10456 vhangup \
10457 vsnprintf \ 10373 vsnprintf \
10458 waitpid \ 10374 waitpid \
10459 10375
@@ -11269,11 +11185,9 @@ fi
11269 11185
11270fi 11186fi
11271 11187
11272# If we don't have a working asprintf, then we strongly depend on vsnprintf 11188# We depend on vsnprintf returning the right thing on overflow: the
11273# returning the right thing on overflow: the number of characters it tried to 11189# number of characters it tried to create (as per SUSv3)
11274# create (as per SUSv3) 11190if test "x$ac_cv_func_vsnprintf" = "xyes" ; then
11275if test "x$ac_cv_func_asprintf" != "xyes" && \
11276 test "x$ac_cv_func_vsnprintf" = "xyes" ; then
11277 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vsnprintf returns correct values on overflow" >&5 11191 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vsnprintf returns correct values on overflow" >&5
11278$as_echo_n "checking whether vsnprintf returns correct values on overflow... " >&6; } 11192$as_echo_n "checking whether vsnprintf returns correct values on overflow... " >&6; }
11279 if test "$cross_compiling" = yes; then : 11193 if test "$cross_compiling" = yes; then :
@@ -11288,10 +11202,14 @@ else
11288#include <stdio.h> 11202#include <stdio.h>
11289#include <stdarg.h> 11203#include <stdarg.h>
11290 11204
11291int x_snprintf(char *str,size_t count,const char *fmt,...) 11205int x_snprintf(char *str, size_t count, const char *fmt, ...)
11292{ 11206{
11293 size_t ret; va_list ap; 11207 size_t ret;
11294 va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap); 11208 va_list ap;
11209
11210 va_start(ap, fmt);
11211 ret = vsnprintf(str, count, fmt, ap);
11212 va_end(ap);
11295 return ret; 11213 return ret;
11296} 11214}
11297 11215
@@ -11299,8 +11217,12 @@ int
11299main () 11217main ()
11300{ 11218{
11301 11219
11302 char x[1]; 11220char x[1];
11303 exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1); 11221if (x_snprintf(x, 1, "%s %d", "hello", 12345) != 11)
11222 return 1;
11223if (x_snprintf(NULL, 0, "%s %d", "hello", 12345) != 11)
11224 return 1;
11225return 0;
11304 11226
11305 ; 11227 ;
11306 return 0; 11228 return 0;
@@ -11897,7 +11819,7 @@ main ()
11897 if(fd == NULL) 11819 if(fd == NULL)
11898 exit(1); 11820 exit(1);
11899 11821
11900 if ((rc = fprintf(fd ,"%x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0) 11822 if ((rc = fprintf(fd ,"%08x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0)
11901 exit(1); 11823 exit(1);
11902 11824
11903 exit(0); 11825 exit(0);
@@ -11954,7 +11876,8 @@ main ()
11954 if(fd == NULL) 11876 if(fd == NULL)
11955 exit(1); 11877 exit(1);
11956 11878
11957 if ((rc = fprintf(fd ,"%x (%s)\n", SSLeay(), SSLeay_version(SSLEAY_VERSION))) <0) 11879 if ((rc = fprintf(fd ,"%08x (%s)\n", SSLeay(),
11880 SSLeay_version(SSLEAY_VERSION))) <0)
11958 exit(1); 11881 exit(1);
11959 11882
11960 exit(0); 11883 exit(0);
@@ -11966,6 +11889,13 @@ _ACEOF
11966if ac_fn_c_try_run "$LINENO"; then : 11889if ac_fn_c_try_run "$LINENO"; then :
11967 11890
11968 ssl_library_ver=`cat conftest.ssllibver` 11891 ssl_library_ver=`cat conftest.ssllibver`
11892 # Check version is supported.
11893 case "$ssl_library_ver" in
11894 0090[0-7]*|009080[0-5]*)
11895 as_fn_error $? "OpenSSL >= 0.9.8f required" "$LINENO" 5
11896 ;;
11897 *) ;;
11898 esac
11969 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ssl_library_ver" >&5 11899 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ssl_library_ver" >&5
11970$as_echo "$ssl_library_ver" >&6; } 11900$as_echo "$ssl_library_ver" >&6; }
11971 11901
@@ -11981,6 +11911,18 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
11981fi 11911fi
11982 11912
11983 11913
11914# XXX make --without-openssl work
11915
11916cat >>confdefs.h <<_ACEOF
11917#define WITH_OPENSSL 1
11918_ACEOF
11919
11920
11921cat >>confdefs.h <<_ACEOF
11922#define WITH_SSH1 1
11923_ACEOF
11924
11925
11984 11926
11985# Check whether --with-openssl-header-check was given. 11927# Check whether --with-openssl-header-check was given.
11986if test "${with_openssl_header_check+set}" = set; then : 11928if test "${with_openssl_header_check+set}" = set; then :
@@ -12514,6 +12456,25 @@ else
12514fi 12456fi
12515done 12457done
12516 12458
12459# Search for RIPE-MD support in OpenSSL
12460for ac_func in EVP_ripemd160
12461do :
12462 ac_fn_c_check_func "$LINENO" "EVP_ripemd160" "ac_cv_func_EVP_ripemd160"
12463if test "x$ac_cv_func_EVP_ripemd160" = xyes; then :
12464 cat >>confdefs.h <<_ACEOF
12465#define HAVE_EVP_RIPEMD160 1
12466_ACEOF
12467
12468else
12469 unsupported_algorithms="$unsupported_algorithms \
12470 hmac-ripemd160
12471 hmac-ripemd160@openssh.com
12472 hmac-ripemd160-etm@openssh.com"
12473
12474
12475fi
12476done
12477
12517 12478
12518# Check complete ECC support in OpenSSL 12479# Check complete ECC support in OpenSSL
12519{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has NID_X9_62_prime256v1" >&5 12480{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL has NID_X9_62_prime256v1" >&5
@@ -12714,6 +12675,24 @@ fi
12714 12675
12715 12676
12716 12677
12678for ac_func in \
12679 arc4random \
12680 arc4random_buf \
12681 arc4random_stir \
12682 arc4random_uniform \
12683
12684do :
12685 as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
12686ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
12687if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
12688 cat >>confdefs.h <<_ACEOF
12689#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
12690_ACEOF
12691
12692fi
12693done
12694
12695
12717saved_LIBS="$LIBS" 12696saved_LIBS="$LIBS"
12718{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ia_openinfo in -liaf" >&5 12697{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ia_openinfo in -liaf" >&5
12719$as_echo_n "checking for ia_openinfo in -liaf... " >&6; } 12698$as_echo_n "checking for ia_openinfo in -liaf... " >&6; }
@@ -13123,7 +13102,14 @@ fi
13123rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 13102rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
13124fi 13103fi
13125 13104
13126SSH_PRIVSEP_USER=sshd 13105case "$host" in
13106*-*-cygwin*)
13107 SSH_PRIVSEP_USER=CYGWIN_SSH_PRIVSEP_USER
13108 ;;
13109*)
13110 SSH_PRIVSEP_USER=sshd
13111 ;;
13112esac
13127 13113
13128# Check whether --with-privsep-user was given. 13114# Check whether --with-privsep-user was given.
13129if test "${with_privsep_user+set}" = set; then : 13115if test "${with_privsep_user+set}" = set; then :
@@ -13136,11 +13122,19 @@ if test "${with_privsep_user+set}" = set; then :
13136 13122
13137fi 13123fi
13138 13124
13125if test "x$SSH_PRIVSEP_USER" = "xCYGWIN_SSH_PRIVSEP_USER" ; then
13126
13127cat >>confdefs.h <<_ACEOF
13128#define SSH_PRIVSEP_USER CYGWIN_SSH_PRIVSEP_USER
13129_ACEOF
13130
13131else
13139 13132
13140cat >>confdefs.h <<_ACEOF 13133cat >>confdefs.h <<_ACEOF
13141#define SSH_PRIVSEP_USER "$SSH_PRIVSEP_USER" 13134#define SSH_PRIVSEP_USER "$SSH_PRIVSEP_USER"
13142_ACEOF 13135_ACEOF
13143 13136
13137fi
13144 13138
13145 13139
13146if test "x$have_linux_no_new_privs" = "x1" ; then 13140if test "x$have_linux_no_new_privs" = "x1" ; then
@@ -19684,7 +19678,6 @@ echo " KerberosV support: $KRB5_MSG"
19684echo " SELinux support: $SELINUX_MSG" 19678echo " SELinux support: $SELINUX_MSG"
19685echo " Smartcard support: $SCARD_MSG" 19679echo " Smartcard support: $SCARD_MSG"
19686echo " S/KEY support: $SKEY_MSG" 19680echo " S/KEY support: $SKEY_MSG"
19687echo " TCP Wrappers support: $TCPW_MSG"
19688echo " MD5 password support: $MD5_MSG" 19681echo " MD5 password support: $MD5_MSG"
19689echo " libedit support: $LIBEDIT_MSG" 19682echo " libedit support: $LIBEDIT_MSG"
19690echo " Solaris process contract support: $SPC_MSG" 19683echo " Solaris process contract support: $SPC_MSG"
diff --git a/configure.ac b/configure.ac
index 7c6ce08d8..67c4486e7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
1# $Id: configure.ac,v 1.571 2014/02/21 17:09:34 tim Exp $ 1# $Id: configure.ac,v 1.583 2014/08/26 20:32:01 djm Exp $
2# 2#
3# Copyright (c) 1999-2004 Damien Miller 3# Copyright (c) 1999-2004 Damien Miller
4# 4#
@@ -15,7 +15,7 @@
15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 16
17AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org]) 17AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org])
18AC_REVISION($Revision: 1.571 $) 18AC_REVISION($Revision: 1.583 $)
19AC_CONFIG_SRCDIR([ssh.c]) 19AC_CONFIG_SRCDIR([ssh.c])
20AC_LANG([C]) 20AC_LANG([C])
21 21
@@ -1380,62 +1380,6 @@ AC_ARG_WITH([skey],
1380 ] 1380 ]
1381) 1381)
1382 1382
1383# Check whether user wants TCP wrappers support
1384TCPW_MSG="no"
1385AC_ARG_WITH([tcp-wrappers],
1386 [ --with-tcp-wrappers[[=PATH]] Enable tcpwrappers support (optionally in PATH)],
1387 [
1388 if test "x$withval" != "xno" ; then
1389 saved_LIBS="$LIBS"
1390 saved_LDFLAGS="$LDFLAGS"
1391 saved_CPPFLAGS="$CPPFLAGS"
1392 if test -n "${withval}" && \
1393 test "x${withval}" != "xyes"; then
1394 if test -d "${withval}/lib"; then
1395 if test -n "${need_dash_r}"; then
1396 LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
1397 else
1398 LDFLAGS="-L${withval}/lib ${LDFLAGS}"
1399 fi
1400 else
1401 if test -n "${need_dash_r}"; then
1402 LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}"
1403 else
1404 LDFLAGS="-L${withval} ${LDFLAGS}"
1405 fi
1406 fi
1407 if test -d "${withval}/include"; then
1408 CPPFLAGS="-I${withval}/include ${CPPFLAGS}"
1409 else
1410 CPPFLAGS="-I${withval} ${CPPFLAGS}"
1411 fi
1412 fi
1413 LIBS="-lwrap $LIBS"
1414 AC_MSG_CHECKING([for libwrap])
1415 AC_LINK_IFELSE([AC_LANG_PROGRAM([[
1416#include <sys/types.h>
1417#include <sys/socket.h>
1418#include <netinet/in.h>
1419#include <tcpd.h>
1420int deny_severity = 0, allow_severity = 0;
1421 ]], [[
1422 hosts_access(0);
1423 ]])], [
1424 AC_MSG_RESULT([yes])
1425 AC_DEFINE([LIBWRAP], [1],
1426 [Define if you want
1427 TCP Wrappers support])
1428 SSHDLIBS="$SSHDLIBS -lwrap"
1429 TCPW_MSG="yes"
1430 ], [
1431 AC_MSG_ERROR([*** libwrap missing])
1432
1433 ])
1434 LIBS="$saved_LIBS"
1435 fi
1436 ]
1437)
1438
1439# Check whether user wants to use ldns 1383# Check whether user wants to use ldns
1440LDNS_MSG="no" 1384LDNS_MSG="no"
1441AC_ARG_WITH(ldns, 1385AC_ARG_WITH(ldns,
@@ -1631,10 +1575,6 @@ AC_CHECK_FUNCS([ \
1631 Blowfish_expandstate \ 1575 Blowfish_expandstate \
1632 Blowfish_expand0state \ 1576 Blowfish_expand0state \
1633 Blowfish_stream2word \ 1577 Blowfish_stream2word \
1634 arc4random \
1635 arc4random_buf \
1636 arc4random_stir \
1637 arc4random_uniform \
1638 asprintf \ 1578 asprintf \
1639 b64_ntop \ 1579 b64_ntop \
1640 __b64_ntop \ 1580 __b64_ntop \
@@ -1678,6 +1618,7 @@ AC_CHECK_FUNCS([ \
1678 mblen \ 1618 mblen \
1679 md5_crypt \ 1619 md5_crypt \
1680 memmove \ 1620 memmove \
1621 memset_s \
1681 mkdtemp \ 1622 mkdtemp \
1682 mmap \ 1623 mmap \
1683 ngetaddrinfo \ 1624 ngetaddrinfo \
@@ -1736,7 +1677,6 @@ AC_CHECK_FUNCS([ \
1736 user_from_uid \ 1677 user_from_uid \
1737 usleep \ 1678 usleep \
1738 vasprintf \ 1679 vasprintf \
1739 vhangup \
1740 vsnprintf \ 1680 vsnprintf \
1741 waitpid \ 1681 waitpid \
1742]) 1682])
@@ -1948,11 +1888,9 @@ if test "x$ac_cv_func_snprintf" = "xyes" ; then
1948 ) 1888 )
1949fi 1889fi
1950 1890
1951# If we don't have a working asprintf, then we strongly depend on vsnprintf 1891# We depend on vsnprintf returning the right thing on overflow: the
1952# returning the right thing on overflow: the number of characters it tried to 1892# number of characters it tried to create (as per SUSv3)
1953# create (as per SUSv3) 1893if test "x$ac_cv_func_vsnprintf" = "xyes" ; then
1954if test "x$ac_cv_func_asprintf" != "xyes" && \
1955 test "x$ac_cv_func_vsnprintf" = "xyes" ; then
1956 AC_MSG_CHECKING([whether vsnprintf returns correct values on overflow]) 1894 AC_MSG_CHECKING([whether vsnprintf returns correct values on overflow])
1957 AC_RUN_IFELSE( 1895 AC_RUN_IFELSE(
1958 [AC_LANG_PROGRAM([[ 1896 [AC_LANG_PROGRAM([[
@@ -1960,15 +1898,23 @@ if test "x$ac_cv_func_asprintf" != "xyes" && \
1960#include <stdio.h> 1898#include <stdio.h>
1961#include <stdarg.h> 1899#include <stdarg.h>
1962 1900
1963int x_snprintf(char *str,size_t count,const char *fmt,...) 1901int x_snprintf(char *str, size_t count, const char *fmt, ...)
1964{ 1902{
1965 size_t ret; va_list ap; 1903 size_t ret;
1966 va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap); 1904 va_list ap;
1905
1906 va_start(ap, fmt);
1907 ret = vsnprintf(str, count, fmt, ap);
1908 va_end(ap);
1967 return ret; 1909 return ret;
1968} 1910}
1969 ]], [[ 1911 ]], [[
1970 char x[1]; 1912char x[1];
1971 exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1); 1913if (x_snprintf(x, 1, "%s %d", "hello", 12345) != 11)
1914 return 1;
1915if (x_snprintf(NULL, 0, "%s %d", "hello", 12345) != 11)
1916 return 1;
1917return 0;
1972 ]])], 1918 ]])],
1973 [AC_MSG_RESULT([yes])], 1919 [AC_MSG_RESULT([yes])],
1974 [ 1920 [
@@ -2304,7 +2250,7 @@ AC_RUN_IFELSE(
2304 if(fd == NULL) 2250 if(fd == NULL)
2305 exit(1); 2251 exit(1);
2306 2252
2307 if ((rc = fprintf(fd ,"%x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0) 2253 if ((rc = fprintf(fd ,"%08x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0)
2308 exit(1); 2254 exit(1);
2309 2255
2310 exit(0); 2256 exit(0);
@@ -2339,13 +2285,21 @@ AC_RUN_IFELSE(
2339 if(fd == NULL) 2285 if(fd == NULL)
2340 exit(1); 2286 exit(1);
2341 2287
2342 if ((rc = fprintf(fd ,"%x (%s)\n", SSLeay(), SSLeay_version(SSLEAY_VERSION))) <0) 2288 if ((rc = fprintf(fd ,"%08x (%s)\n", SSLeay(),
2289 SSLeay_version(SSLEAY_VERSION))) <0)
2343 exit(1); 2290 exit(1);
2344 2291
2345 exit(0); 2292 exit(0);
2346 ]])], 2293 ]])],
2347 [ 2294 [
2348 ssl_library_ver=`cat conftest.ssllibver` 2295 ssl_library_ver=`cat conftest.ssllibver`
2296 # Check version is supported.
2297 case "$ssl_library_ver" in
2298 0090[[0-7]]*|009080[[0-5]]*)
2299 AC_MSG_ERROR([OpenSSL >= 0.9.8f required])
2300 ;;
2301 *) ;;
2302 esac
2349 AC_MSG_RESULT([$ssl_library_ver]) 2303 AC_MSG_RESULT([$ssl_library_ver])
2350 ], 2304 ],
2351 [ 2305 [
@@ -2357,6 +2311,10 @@ AC_RUN_IFELSE(
2357 ] 2311 ]
2358) 2312)
2359 2313
2314# XXX make --without-openssl work
2315AC_DEFINE_UNQUOTED([WITH_OPENSSL], [1], [use libcrypto for cryptography])
2316AC_DEFINE_UNQUOTED([WITH_SSH1], [1], [include SSH protocol version 1 support])
2317
2360AC_ARG_WITH([openssl-header-check], 2318AC_ARG_WITH([openssl-header-check],
2361 [ --without-openssl-header-check Disable OpenSSL version consistency check], 2319 [ --without-openssl-header-check Disable OpenSSL version consistency check],
2362 [ if test "x$withval" = "xno" ; then 2320 [ if test "x$withval" = "xno" ; then
@@ -2565,6 +2523,14 @@ AC_CHECK_FUNCS([SHA256_Update EVP_sha256], ,
2565 hmac-sha2-256-etm@openssh.com hmac-sha2-512-etm@openssh.com" 2523 hmac-sha2-256-etm@openssh.com hmac-sha2-512-etm@openssh.com"
2566 ] 2524 ]
2567) 2525)
2526# Search for RIPE-MD support in OpenSSL
2527AC_CHECK_FUNCS([EVP_ripemd160], ,
2528 [unsupported_algorithms="$unsupported_algorithms \
2529 hmac-ripemd160
2530 hmac-ripemd160@openssh.com
2531 hmac-ripemd160-etm@openssh.com"
2532 ]
2533)
2568 2534
2569# Check complete ECC support in OpenSSL 2535# Check complete ECC support in OpenSSL
2570AC_MSG_CHECKING([whether OpenSSL has NID_X9_62_prime256v1]) 2536AC_MSG_CHECKING([whether OpenSSL has NID_X9_62_prime256v1])
@@ -2685,6 +2651,13 @@ fi
2685AC_SUBST([TEST_SSH_ECC]) 2651AC_SUBST([TEST_SSH_ECC])
2686AC_SUBST([COMMENT_OUT_ECC]) 2652AC_SUBST([COMMENT_OUT_ECC])
2687 2653
2654AC_CHECK_FUNCS([ \
2655 arc4random \
2656 arc4random_buf \
2657 arc4random_stir \
2658 arc4random_uniform \
2659])
2660
2688saved_LIBS="$LIBS" 2661saved_LIBS="$LIBS"
2689AC_CHECK_LIB([iaf], [ia_openinfo], [ 2662AC_CHECK_LIB([iaf], [ia_openinfo], [
2690 LIBS="$LIBS -liaf" 2663 LIBS="$LIBS -liaf"
@@ -2868,7 +2841,14 @@ if test "x$PAM_MSG" = "xyes" ; then
2868 ]) 2841 ])
2869fi 2842fi
2870 2843
2871SSH_PRIVSEP_USER=sshd 2844case "$host" in
2845*-*-cygwin*)
2846 SSH_PRIVSEP_USER=CYGWIN_SSH_PRIVSEP_USER
2847 ;;
2848*)
2849 SSH_PRIVSEP_USER=sshd
2850 ;;
2851esac
2872AC_ARG_WITH([privsep-user], 2852AC_ARG_WITH([privsep-user],
2873 [ --with-privsep-user=user Specify non-privileged user for privilege separation], 2853 [ --with-privsep-user=user Specify non-privileged user for privilege separation],
2874 [ 2854 [
@@ -2878,8 +2858,13 @@ AC_ARG_WITH([privsep-user],
2878 fi 2858 fi
2879 ] 2859 ]
2880) 2860)
2881AC_DEFINE_UNQUOTED([SSH_PRIVSEP_USER], ["$SSH_PRIVSEP_USER"], 2861if test "x$SSH_PRIVSEP_USER" = "xCYGWIN_SSH_PRIVSEP_USER" ; then
2882 [non-privileged user for privilege separation]) 2862 AC_DEFINE_UNQUOTED([SSH_PRIVSEP_USER], [CYGWIN_SSH_PRIVSEP_USER],
2863 [Cygwin function to fetch non-privileged user for privilege separation])
2864else
2865 AC_DEFINE_UNQUOTED([SSH_PRIVSEP_USER], ["$SSH_PRIVSEP_USER"],
2866 [non-privileged user for privilege separation])
2867fi
2883AC_SUBST([SSH_PRIVSEP_USER]) 2868AC_SUBST([SSH_PRIVSEP_USER])
2884 2869
2885if test "x$have_linux_no_new_privs" = "x1" ; then 2870if test "x$have_linux_no_new_privs" = "x1" ; then
@@ -4844,7 +4829,6 @@ echo " KerberosV support: $KRB5_MSG"
4844echo " SELinux support: $SELINUX_MSG" 4829echo " SELinux support: $SELINUX_MSG"
4845echo " Smartcard support: $SCARD_MSG" 4830echo " Smartcard support: $SCARD_MSG"
4846echo " S/KEY support: $SKEY_MSG" 4831echo " S/KEY support: $SKEY_MSG"
4847echo " TCP Wrappers support: $TCPW_MSG"
4848echo " MD5 password support: $MD5_MSG" 4832echo " MD5 password support: $MD5_MSG"
4849echo " libedit support: $LIBEDIT_MSG" 4833echo " libedit support: $LIBEDIT_MSG"
4850echo " Solaris process contract support: $SPC_MSG" 4834echo " Solaris process contract support: $SPC_MSG"
diff --git a/contrib/caldera/openssh.spec b/contrib/caldera/openssh.spec
index 0061fe933..0011b4dea 100644
--- a/contrib/caldera/openssh.spec
+++ b/contrib/caldera/openssh.spec
@@ -16,7 +16,7 @@
16 16
17#old cvs stuff. please update before use. may be deprecated. 17#old cvs stuff. please update before use. may be deprecated.
18%define use_stable 1 18%define use_stable 1
19%define version 6.6p1 19%define version 6.7p1
20%if %{use_stable} 20%if %{use_stable}
21 %define cvs %{nil} 21 %define cvs %{nil}
22 %define release 1 22 %define release 1
@@ -178,7 +178,6 @@ by Jim Knoble <jmknoble@pobox.com>.
178CFLAGS="$RPM_OPT_FLAGS" \ 178CFLAGS="$RPM_OPT_FLAGS" \
179%configure \ 179%configure \
180 --with-pam \ 180 --with-pam \
181 --with-tcp-wrappers \
182 --with-privsep-path=%{_var}/empty/sshd \ 181 --with-privsep-path=%{_var}/empty/sshd \
183 #leave this line for easy edits. 182 #leave this line for easy edits.
184 183
@@ -363,4 +362,4 @@ fi
363* Mon Jan 01 1998 ... 362* Mon Jan 01 1998 ...
364Template Version: 1.31 363Template Version: 1.31
365 364
366$Id: openssh.spec,v 1.83 2014/02/27 23:03:55 djm Exp $ 365$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 2562b6186..1396d99cd 100644
--- a/contrib/cygwin/README
+++ b/contrib/cygwin/README
@@ -69,7 +69,7 @@ Building OpenSSH
69Building from source is easy. Just unpack the source archive, cd to that 69Building from source is easy. Just unpack the source archive, cd to that
70directory, and call cygport: 70directory, and call cygport:
71 71
72 cygport openssh.cygport almostall 72 cygport openssh.cygport all
73 73
74You must have installed the following packages to be able to build OpenSSH 74You must have installed the following packages to be able to build OpenSSH
75with the aforementioned cygport script: 75with the aforementioned cygport script:
@@ -77,7 +77,6 @@ with the aforementioned cygport script:
77 zlib 77 zlib
78 crypt 78 crypt
79 openssl-devel 79 openssl-devel
80 libwrap-devel
81 libedit-devel 80 libedit-devel
82 libkrb5-devel 81 libkrb5-devel
83 82
diff --git a/contrib/cygwin/ssh-host-config b/contrib/cygwin/ssh-host-config
index 05efd3b3b..a7ea3e0d2 100644
--- a/contrib/cygwin/ssh-host-config
+++ b/contrib/cygwin/ssh-host-config
@@ -34,9 +34,9 @@ declare -a csih_required_commands=(
34 /usr/bin/mv coreutils 34 /usr/bin/mv coreutils
35 /usr/bin/rm coreutils 35 /usr/bin/rm coreutils
36 /usr/bin/cygpath cygwin 36 /usr/bin/cygpath cygwin
37 /usr/bin/mkpasswd cygwin
37 /usr/bin/mount cygwin 38 /usr/bin/mount cygwin
38 /usr/bin/ps cygwin 39 /usr/bin/ps cygwin
39 /usr/bin/setfacl cygwin
40 /usr/bin/umount cygwin 40 /usr/bin/umount cygwin
41 /usr/bin/cmp diffutils 41 /usr/bin/cmp diffutils
42 /usr/bin/grep grep 42 /usr/bin/grep grep
@@ -59,8 +59,9 @@ PREFIX=/usr
59SYSCONFDIR=/etc 59SYSCONFDIR=/etc
60LOCALSTATEDIR=/var 60LOCALSTATEDIR=/var
61 61
62sshd_config_configured=no
62port_number=22 63port_number=22
63privsep_configured=no 64strictmodes=yes
64privsep_used=yes 65privsep_used=yes
65cygwin_value="" 66cygwin_value=""
66user_account= 67user_account=
@@ -89,28 +90,8 @@ update_services_file() {
89 # Depends on the above mount 90 # Depends on the above mount
90 _wservices=`cygpath -w "${_services}"` 91 _wservices=`cygpath -w "${_services}"`
91 92
92 # Remove sshd 22/port from services
93 if [ `/usr/bin/grep -q 'sshd[ \t][ \t]*22' "${_services}"; echo $?` -eq 0 ]
94 then
95 /usr/bin/grep -v 'sshd[ \t][ \t]*22' "${_services}" > "${_serv_tmp}"
96 if [ -f "${_serv_tmp}" ]
97 then
98 if /usr/bin/mv "${_serv_tmp}" "${_services}"
99 then
100 csih_inform "Removing sshd from ${_wservices}"
101 else
102 csih_warning "Removing sshd from ${_wservices} failed!"
103 let ++ret
104 fi
105 /usr/bin/rm -f "${_serv_tmp}"
106 else
107 csih_warning "Removing sshd from ${_wservices} failed!"
108 let ++ret
109 fi
110 fi
111
112 # Add ssh 22/tcp and ssh 22/udp to services 93 # Add ssh 22/tcp and ssh 22/udp to services
113 if [ `/usr/bin/grep -q 'ssh[ \t][ \t]*22' "${_services}"; echo $?` -ne 0 ] 94 if [ `/usr/bin/grep -q 'ssh[[:space:]][[:space:]]*22' "${_services}"; echo $?` -ne 0 ]
114 then 95 then
115 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}" 96 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}"
116 then 97 then
@@ -132,17 +113,45 @@ update_services_file() {
132} # --- End of update_services_file --- # 113} # --- End of update_services_file --- #
133 114
134# ====================================================================== 115# ======================================================================
116# Routine: sshd_strictmodes
117# MODIFIES: strictmodes
118# ======================================================================
119sshd_strictmodes() {
120 if [ "${sshd_config_configured}" != "yes" ]
121 then
122 echo
123 csih_inform "StrictModes is set to 'yes' by default."
124 csih_inform "This is the recommended setting, but it requires that the POSIX"
125 csih_inform "permissions of the user's home directory, the user's .ssh"
126 csih_inform "directory, and the user's ssh key files are tight so that"
127 csih_inform "only the user has write permissions."
128 csih_inform "On the other hand, StrictModes don't work well with default"
129 csih_inform "Windows permissions of a home directory mounted with the"
130 csih_inform "'noacl' option, and they don't work at all if the home"
131 csih_inform "directory is on a FAT or FAT32 partition."
132 if ! csih_request "Should StrictModes be used?"
133 then
134 strictmodes=no
135 fi
136 fi
137 return 0
138}
139
140# ======================================================================
135# Routine: sshd_privsep 141# Routine: sshd_privsep
136# MODIFIES: privsep_configured privsep_used 142# MODIFIES: privsep_used
137# ====================================================================== 143# ======================================================================
138sshd_privsep() { 144sshd_privsep() {
139 local sshdconfig_tmp
140 local ret=0 145 local ret=0
141 146
142 if [ "${privsep_configured}" != "yes" ] 147 if [ "${sshd_config_configured}" != "yes" ]
143 then 148 then
144 csih_inform "Privilege separation is set to yes by default since OpenSSH 3.3." 149 echo
145 csih_inform "However, this requires a non-privileged account called 'sshd'." 150 csih_inform "Privilege separation is set to 'sandbox' by default since"
151 csih_inform "OpenSSH 6.1. This is unsupported by Cygwin and has to be set"
152 csih_inform "to 'yes' or 'no'."
153 csih_inform "However, using privilege separation requires a non-privileged account"
154 csih_inform "called 'sshd'."
146 csih_inform "For more info on privilege separation read /usr/share/doc/openssh/README.privsep." 155 csih_inform "For more info on privilege separation read /usr/share/doc/openssh/README.privsep."
147 if csih_request "Should privilege separation be used?" 156 if csih_request "Should privilege separation be used?"
148 then 157 then
@@ -159,36 +168,53 @@ sshd_privsep() {
159 privsep_used=no 168 privsep_used=no
160 fi 169 fi
161 fi 170 fi
171 return $ret
172} # --- End of sshd_privsep --- #
162 173
163 # Create default sshd_config from skeleton files in /etc/defaults/etc or 174# ======================================================================
164 # modify to add the missing privsep configuration option 175# Routine: sshd_config_tweak
165 if /usr/bin/cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1 176# ======================================================================
177sshd_config_tweak() {
178 local ret=0
179
180 # Modify sshd_config
181 csih_inform "Updating ${SYSCONFDIR}/sshd_config file"
182 if [ "${port_number}" -ne 22 ]
166 then 183 then
167 csih_inform "Updating ${SYSCONFDIR}/sshd_config file" 184 /usr/bin/sed -i -e "s/^#\?[[:space:]]*Port[[:space:]].*/Port ${port_number}/" \
168 sshdconfig_tmp=${SYSCONFDIR}/sshd_config.$$ 185 ${SYSCONFDIR}/sshd_config
169 /usr/bin/sed -e "s/^#UsePrivilegeSeparation yes/UsePrivilegeSeparation ${privsep_used}/ 186 if [ $? -ne 0 ]
170 s/^#Port 22/Port ${port_number}/
171 s/^#StrictModes yes/StrictModes no/" \
172 < ${SYSCONFDIR}/sshd_config \
173 > "${sshdconfig_tmp}"
174 if ! /usr/bin/mv "${sshdconfig_tmp}" ${SYSCONFDIR}/sshd_config
175 then 187 then
176 csih_warning "Setting privilege separation to 'yes' failed!" 188 csih_warning "Setting listening port to ${port_number} failed!"
177 csih_warning "Check your ${SYSCONFDIR}/sshd_config file!" 189 csih_warning "Check your ${SYSCONFDIR}/sshd_config file!"
178 let ++ret 190 let ++ret
191 fi
192 fi
193 if [ "${strictmodes}" = "no" ]
194 then
195 /usr/bin/sed -i -e "s/^#\?[[:space:]]*StrictModes[[:space:]].*/StrictModes no/" \
196 ${SYSCONFDIR}/sshd_config
197 if [ $? -ne 0 ]
198 then
199 csih_warning "Setting StrictModes to 'no' failed!"
200 csih_warning "Check your ${SYSCONFDIR}/sshd_config file!"
201 let ++ret
179 fi 202 fi
180 elif [ "${privsep_configured}" != "yes" ] 203 fi
204 if [ "${sshd_config_configured}" != "yes" ]
181 then 205 then
182 echo >> ${SYSCONFDIR}/sshd_config 206 /usr/bin/sed -i -e "
183 if ! echo "UsePrivilegeSeparation ${privsep_used}" >> ${SYSCONFDIR}/sshd_config 207 s/^#\?UsePrivilegeSeparation .*/UsePrivilegeSeparation ${privsep_used}/" \
208 ${SYSCONFDIR}/sshd_config
209 if [ $? -ne 0 ]
184 then 210 then
185 csih_warning "Setting privilege separation to 'yes' failed!" 211 csih_warning "Setting privilege separation failed!"
186 csih_warning "Check your ${SYSCONFDIR}/sshd_config file!" 212 csih_warning "Check your ${SYSCONFDIR}/sshd_config file!"
187 let ++ret 213 let ++ret
188 fi 214 fi
189 fi 215 fi
190 return $ret 216 return $ret
191} # --- End of sshd_privsep --- # 217} # --- End of sshd_config_tweak --- #
192 218
193# ====================================================================== 219# ======================================================================
194# Routine: update_inetd_conf 220# Routine: update_inetd_conf
@@ -207,11 +233,11 @@ update_inetd_conf() {
207 # we have inetutils-1.5 inetd.d support 233 # we have inetutils-1.5 inetd.d support
208 if [ -f "${_inetcnf}" ] 234 if [ -f "${_inetcnf}" ]
209 then 235 then
210 /usr/bin/grep -q '^[ \t]*ssh' "${_inetcnf}" && _with_comment=0 236 /usr/bin/grep -q '^[[:space:]]*ssh' "${_inetcnf}" && _with_comment=0
211 237
212 # check for sshd OR ssh in top-level inetd.conf file, and remove 238 # check for sshd OR ssh in top-level inetd.conf file, and remove
213 # will be replaced by a file in inetd.d/ 239 # will be replaced by a file in inetd.d/
214 if [ `/usr/bin/grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?` -eq 0 ] 240 if [ $(/usr/bin/grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?) -eq 0 ]
215 then 241 then
216 /usr/bin/grep -v '^[# \t]*ssh' "${_inetcnf}" >> "${_inetcnf_tmp}" 242 /usr/bin/grep -v '^[# \t]*ssh' "${_inetcnf}" >> "${_inetcnf_tmp}"
217 if [ -f "${_inetcnf_tmp}" ] 243 if [ -f "${_inetcnf_tmp}" ]
@@ -236,9 +262,9 @@ update_inetd_conf() {
236 then 262 then
237 if [ "${_with_comment}" -eq 0 ] 263 if [ "${_with_comment}" -eq 0 ]
238 then 264 then
239 /usr/bin/sed -e 's/@COMMENT@[ \t]*//' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}" 265 /usr/bin/sed -e 's/@COMMENT@[[:space:]]*//' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
240 else 266 else
241 /usr/bin/sed -e 's/@COMMENT@[ \t]*/# /' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}" 267 /usr/bin/sed -e 's/@COMMENT@[[:space:]]*/# /' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
242 fi 268 fi
243 if /usr/bin/mv "${_sshd_inetd_conf_tmp}" "${_sshd_inetd_conf}" 269 if /usr/bin/mv "${_sshd_inetd_conf_tmp}" "${_sshd_inetd_conf}"
244 then 270 then
@@ -251,13 +277,13 @@ update_inetd_conf() {
251 277
252 elif [ -f "${_inetcnf}" ] 278 elif [ -f "${_inetcnf}" ]
253 then 279 then
254 /usr/bin/grep -q '^[ \t]*sshd' "${_inetcnf}" && _with_comment=0 280 /usr/bin/grep -q '^[[:space:]]*sshd' "${_inetcnf}" && _with_comment=0
255 281
256 # check for sshd in top-level inetd.conf file, and remove 282 # check for sshd in top-level inetd.conf file, and remove
257 # will be replaced by a file in inetd.d/ 283 # will be replaced by a file in inetd.d/
258 if [ `/usr/bin/grep -q '^[# \t]*sshd' "${_inetcnf}"; echo $?` -eq 0 ] 284 if [ `/usr/bin/grep -q '^#\?[[:space:]]*sshd' "${_inetcnf}"; echo $?` -eq 0 ]
259 then 285 then
260 /usr/bin/grep -v '^[# \t]*sshd' "${_inetcnf}" >> "${_inetcnf_tmp}" 286 /usr/bin/grep -v '^#\?[[:space:]]*sshd' "${_inetcnf}" >> "${_inetcnf_tmp}"
261 if [ -f "${_inetcnf_tmp}" ] 287 if [ -f "${_inetcnf_tmp}" ]
262 then 288 then
263 if /usr/bin/mv "${_inetcnf_tmp}" "${_inetcnf}" 289 if /usr/bin/mv "${_inetcnf_tmp}" "${_inetcnf}"
@@ -305,17 +331,26 @@ check_service_files_ownership() {
305 331
306 if [ -z "${run_service_as}" ] 332 if [ -z "${run_service_as}" ]
307 then 333 then
308 accnt_name=$(/usr/bin/cygrunsrv -VQ sshd | /usr/bin/sed -ne 's/^Account *: *//gp') 334 accnt_name=$(/usr/bin/cygrunsrv -VQ sshd |
335 /usr/bin/sed -ne 's/^Account *: *//gp')
309 if [ "${accnt_name}" = "LocalSystem" ] 336 if [ "${accnt_name}" = "LocalSystem" ]
310 then 337 then
311 # Convert "LocalSystem" to "SYSTEM" as is the correct account name 338 # Convert "LocalSystem" to "SYSTEM" as is the correct account name
312 accnt_name="SYSTEM:" 339 run_service_as="SYSTEM"
313 elif [[ "${accnt_name}" =~ ^\.\\ ]] 340 else
314 then 341 dom="${accnt_name%%\\*}"
315 # Convert "." domain to local machine name 342 accnt_name="${accnt_name#*\\}"
316 accnt_name="U-${COMPUTERNAME}${accnt_name#.}," 343 if [ "${dom}" = '.' ]
344 then
345 # Check local account
346 run_service_as=$(/usr/bin/mkpasswd -l -u "${accnt_name}" |
347 /usr/bin/awk -F: '{print $1;}')
348 else
349 # Check domain
350 run_service_as=$(/usr/bin/mkpasswd -d "${dom}" -u "${accnt_name}" |
351 /usr/bin/awk -F: '{print $1;}')
352 fi
317 fi 353 fi
318 run_service_as=$(/usr/bin/grep -Fi "${accnt_name}" /etc/passwd | /usr/bin/awk -F: '{print $1;}')
319 if [ -z "${run_service_as}" ] 354 if [ -z "${run_service_as}" ]
320 then 355 then
321 csih_warning "Couldn't determine name of user running sshd service from /etc/passwd!" 356 csih_warning "Couldn't determine name of user running sshd service from /etc/passwd!"
@@ -615,32 +650,6 @@ echo
615 650
616warning_cnt=0 651warning_cnt=0
617 652
618# Check for ${SYSCONFDIR} directory
619csih_make_dir "${SYSCONFDIR}" "Cannot create global configuration files."
620if ! /usr/bin/chmod 775 "${SYSCONFDIR}" >/dev/null 2>&1
621then
622 csih_warning "Can't set permissions on ${SYSCONFDIR}!"
623 let ++warning_cnt
624fi
625if ! /usr/bin/setfacl -m u:system:rwx "${SYSCONFDIR}" >/dev/null 2>&1
626then
627 csih_warning "Can't set extended permissions on ${SYSCONFDIR}!"
628 let ++warning_cnt
629fi
630
631# Check for /var/log directory
632csih_make_dir "${LOCALSTATEDIR}/log" "Cannot create log directory."
633if ! /usr/bin/chmod 775 "${LOCALSTATEDIR}/log" >/dev/null 2>&1
634then
635 csih_warning "Can't set permissions on ${LOCALSTATEDIR}/log!"
636 let ++warning_cnt
637fi
638if ! /usr/bin/setfacl -m u:system:rwx "${LOCALSTATEDIR}/log" >/dev/null 2>&1
639then
640 csih_warning "Can't set extended permissions on ${LOCALSTATEDIR}/log!"
641 let ++warning_cnt
642fi
643
644# Create /var/log/lastlog if not already exists 653# Create /var/log/lastlog if not already exists
645if [ -e ${LOCALSTATEDIR}/log/lastlog -a ! -f ${LOCALSTATEDIR}/log/lastlog ] 654if [ -e ${LOCALSTATEDIR}/log/lastlog -a ! -f ${LOCALSTATEDIR}/log/lastlog ]
646then 655then
@@ -665,13 +674,9 @@ then
665 csih_warning "Can't set permissions on ${LOCALSTATEDIR}/empty!" 674 csih_warning "Can't set permissions on ${LOCALSTATEDIR}/empty!"
666 let ++warning_cnt 675 let ++warning_cnt
667fi 676fi
668if ! /usr/bin/setfacl -m u:system:rwx "${LOCALSTATEDIR}/empty" >/dev/null 2>&1
669then
670 csih_warning "Can't set extended permissions on ${LOCALSTATEDIR}/empty!"
671 let ++warning_cnt
672fi
673 677
674# generate missing host keys 678# generate missing host keys
679csih_inform "Generating missing SSH host keys"
675/usr/bin/ssh-keygen -A || let warning_cnt+=$? 680/usr/bin/ssh-keygen -A || let warning_cnt+=$?
676 681
677# handle ssh_config 682# handle ssh_config
@@ -690,10 +695,11 @@ fi
690csih_install_config "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults" || let ++warning_cnt 695csih_install_config "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults" || let ++warning_cnt
691if ! /usr/bin/cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1 696if ! /usr/bin/cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1
692then 697then
693 /usr/bin/grep -q UsePrivilegeSeparation ${SYSCONFDIR}/sshd_config && privsep_configured=yes 698 sshd_config_configured=yes
694fi 699fi
700sshd_strictmodes || let warning_cnt+=$?
695sshd_privsep || let warning_cnt+=$? 701sshd_privsep || let warning_cnt+=$?
696 702sshd_config_tweak || let warning_cnt+=$?
697update_services_file || let warning_cnt+=$? 703update_services_file || let warning_cnt+=$?
698update_inetd_conf || let warning_cnt+=$? 704update_inetd_conf || let warning_cnt+=$?
699install_service || let warning_cnt+=$? 705install_service || let warning_cnt+=$?
diff --git a/contrib/redhat/openssh.spec b/contrib/redhat/openssh.spec
index 96401c6ee..9bdce1e3c 100644
--- a/contrib/redhat/openssh.spec
+++ b/contrib/redhat/openssh.spec
@@ -1,4 +1,4 @@
1%define ver 6.6p1 1%define ver 6.7p1
2%define rel 1 2%define rel 1
3 3
4# OpenSSH privilege separation requires a user & group ID 4# OpenSSH privilege separation requires a user & group ID
@@ -86,7 +86,7 @@ PreReq: initscripts >= 5.00
86%else 86%else
87Requires: initscripts >= 5.20 87Requires: initscripts >= 5.20
88%endif 88%endif
89BuildRequires: perl, openssl-devel, tcp_wrappers 89BuildRequires: perl, openssl-devel
90BuildRequires: /bin/login 90BuildRequires: /bin/login
91%if ! %{build6x} 91%if ! %{build6x}
92BuildPreReq: glibc-devel, pam 92BuildPreReq: glibc-devel, pam
@@ -192,7 +192,6 @@ echo K5DIR=$K5DIR
192 --sysconfdir=%{_sysconfdir}/ssh \ 192 --sysconfdir=%{_sysconfdir}/ssh \
193 --libexecdir=%{_libexecdir}/openssh \ 193 --libexecdir=%{_libexecdir}/openssh \
194 --datadir=%{_datadir}/openssh \ 194 --datadir=%{_datadir}/openssh \
195 --with-tcp-wrappers \
196 --with-rsh=%{_bindir}/rsh \ 195 --with-rsh=%{_bindir}/rsh \
197 --with-default-path=/usr/local/bin:/bin:/usr/bin \ 196 --with-default-path=/usr/local/bin:/bin:/usr/bin \
198 --with-superuser-path=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin \ 197 --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 0515d6d7c..f87674317 100644
--- a/contrib/suse/openssh.spec
+++ b/contrib/suse/openssh.spec
@@ -13,7 +13,7 @@
13 13
14Summary: OpenSSH, a free Secure Shell (SSH) protocol implementation 14Summary: OpenSSH, a free Secure Shell (SSH) protocol implementation
15Name: openssh 15Name: openssh
16Version: 6.6p1 16Version: 6.7p1
17URL: http://www.openssh.com/ 17URL: http://www.openssh.com/
18Release: 1 18Release: 1
19Source0: openssh-%{version}.tar.gz 19Source0: openssh-%{version}.tar.gz
@@ -28,11 +28,9 @@ Provides: ssh
28# (Build[ing] Prereq[uisites] only work for RPM 2.95 and newer.) 28# (Build[ing] Prereq[uisites] only work for RPM 2.95 and newer.)
29# building prerequisites -- stuff for 29# building prerequisites -- stuff for
30# OpenSSL (openssl-devel), 30# OpenSSL (openssl-devel),
31# TCP Wrappers (tcpd-devel),
32# and Gnome (glibdev, gtkdev, and gnlibsd) 31# and Gnome (glibdev, gtkdev, and gnlibsd)
33# 32#
34BuildPrereq: openssl 33BuildPrereq: openssl
35BuildPrereq: tcpd-devel
36BuildPrereq: zlib-devel 34BuildPrereq: zlib-devel
37#BuildPrereq: glibdev 35#BuildPrereq: glibdev
38#BuildPrereq: gtkdev 36#BuildPrereq: gtkdev
@@ -140,7 +138,6 @@ CFLAGS="$RPM_OPT_FLAGS" \
140 --mandir=%{_mandir} \ 138 --mandir=%{_mandir} \
141 --with-privsep-path=/var/lib/empty \ 139 --with-privsep-path=/var/lib/empty \
142 --with-pam \ 140 --with-pam \
143 --with-tcp-wrappers \
144 --libexecdir=%{_libdir}/ssh 141 --libexecdir=%{_libdir}/ssh
145make 142make
146 143
diff --git a/defines.h b/defines.h
index 354d5b614..3ac8be987 100644
--- a/defines.h
+++ b/defines.h
@@ -25,7 +25,7 @@
25#ifndef _DEFINES_H 25#ifndef _DEFINES_H
26#define _DEFINES_H 26#define _DEFINES_H
27 27
28/* $Id: defines.h,v 1.176 2014/01/17 13:12:38 dtucker Exp $ */ 28/* $Id: defines.h,v 1.183 2014/09/02 19:33:26 djm Exp $ */
29 29
30 30
31/* Constants */ 31/* Constants */
@@ -405,7 +405,7 @@ struct winsize {
405 405
406/* user may have set a different path */ 406/* user may have set a different path */
407#if defined(_PATH_MAILDIR) && defined(MAIL_DIRECTORY) 407#if defined(_PATH_MAILDIR) && defined(MAIL_DIRECTORY)
408# undef _PATH_MAILDIR MAILDIR 408# undef _PATH_MAILDIR
409#endif /* defined(_PATH_MAILDIR) && defined(MAIL_DIRECTORY) */ 409#endif /* defined(_PATH_MAILDIR) && defined(MAIL_DIRECTORY) */
410 410
411#ifdef MAIL_DIRECTORY 411#ifdef MAIL_DIRECTORY
@@ -603,10 +603,6 @@ struct winsize {
603# define memmove(s1, s2, n) bcopy((s2), (s1), (n)) 603# define memmove(s1, s2, n) bcopy((s2), (s1), (n))
604#endif /* !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) */ 604#endif /* !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) */
605 605
606#if defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX)
607# define USE_VHANGUP
608#endif /* defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) */
609
610#ifndef GETPGRP_VOID 606#ifndef GETPGRP_VOID
611# include <unistd.h> 607# include <unistd.h>
612# define getpgrp() getpgrp(0) 608# define getpgrp() getpgrp(0)
@@ -826,4 +822,23 @@ struct winsize {
826# define arc4random_stir() 822# define arc4random_stir()
827#endif 823#endif
828 824
825#ifndef HAVE_VA_COPY
826# ifdef HAVE___VA_COPY
827# define va_copy(dest, src) __va_copy(dest, src)
828# else
829# define va_copy(dest, src) (dest) = (src)
830# endif
831#endif
832
833#ifndef __predict_true
834# if defined(__GNUC__) && \
835 ((__GNUC__ > (2)) || (__GNUC__ == (2) && __GNUC_MINOR__ >= (96)))
836# define __predict_true(exp) __builtin_expect(((exp) != 0), 1)
837# define __predict_false(exp) __builtin_expect(((exp) != 0), 0)
838# else
839# define __predict_true(exp) ((exp) != 0)
840# define __predict_false(exp) ((exp) != 0)
841# endif /* gcc version */
842#endif /* __predict_true */
843
829#endif /* _DEFINES_H */ 844#endif /* _DEFINES_H */
diff --git a/digest-libc.c b/digest-libc.c
index 1804b0698..1b4423a05 100644
--- a/digest-libc.c
+++ b/digest-libc.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: digest-libc.c,v 1.2 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: digest-libc.c,v 1.3 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2013 Damien Miller <djm@mindrot.org> 3 * Copyright (c) 2013 Damien Miller <djm@mindrot.org>
4 * Copyright (c) 2014 Markus Friedl. All rights reserved. 4 * Copyright (c) 2014 Markus Friedl. All rights reserved.
@@ -28,7 +28,8 @@
28#include <sha1.h> 28#include <sha1.h>
29#include <sha2.h> 29#include <sha2.h>
30 30
31#include "buffer.h" 31#include "ssherr.h"
32#include "sshbuf.h"
32#include "digest.h" 33#include "digest.h"
33 34
34typedef void md_init_fn(void *mdctx); 35typedef void md_init_fn(void *mdctx);
@@ -164,7 +165,7 @@ ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
164 const struct ssh_digest *digest = ssh_digest_by_alg(from->alg); 165 const struct ssh_digest *digest = ssh_digest_by_alg(from->alg);
165 166
166 if (digest == NULL || from->alg != to->alg) 167 if (digest == NULL || from->alg != to->alg)
167 return -1; 168 return SSH_ERR_INVALID_ARGUMENT;
168 memcpy(to->mdctx, from->mdctx, digest->ctx_len); 169 memcpy(to->mdctx, from->mdctx, digest->ctx_len);
169 return 0; 170 return 0;
170} 171}
@@ -175,15 +176,15 @@ ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
175 const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); 176 const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
176 177
177 if (digest == NULL) 178 if (digest == NULL)
178 return -1; 179 return SSH_ERR_INVALID_ARGUMENT;
179 digest->md_update(ctx->mdctx, m, mlen); 180 digest->md_update(ctx->mdctx, m, mlen);
180 return 0; 181 return 0;
181} 182}
182 183
183int 184int
184ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b) 185ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b)
185{ 186{
186 return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b)); 187 return ssh_digest_update(ctx, sshbuf_ptr(b), sshbuf_len(b));
187} 188}
188 189
189int 190int
@@ -192,11 +193,11 @@ ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
192 const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); 193 const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg);
193 194
194 if (digest == NULL) 195 if (digest == NULL)
195 return -1; 196 return SSH_ERR_INVALID_ARGUMENT;
196 if (dlen > UINT_MAX) 197 if (dlen > UINT_MAX)
197 return -1; 198 return SSH_ERR_INVALID_ARGUMENT;
198 if (dlen < digest->digest_len) /* No truncation allowed */ 199 if (dlen < digest->digest_len) /* No truncation allowed */
199 return -1; 200 return SSH_ERR_INVALID_ARGUMENT;
200 digest->md_final(d, ctx->mdctx); 201 digest->md_final(d, ctx->mdctx);
201 return 0; 202 return 0;
202} 203}
@@ -223,16 +224,16 @@ ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
223 struct ssh_digest_ctx *ctx = ssh_digest_start(alg); 224 struct ssh_digest_ctx *ctx = ssh_digest_start(alg);
224 225
225 if (ctx == NULL) 226 if (ctx == NULL)
226 return -1; 227 return SSH_ERR_INVALID_ARGUMENT;
227 if (ssh_digest_update(ctx, m, mlen) != 0 || 228 if (ssh_digest_update(ctx, m, mlen) != 0 ||
228 ssh_digest_final(ctx, d, dlen) != 0) 229 ssh_digest_final(ctx, d, dlen) != 0)
229 return -1; 230 return SSH_ERR_INVALID_ARGUMENT;
230 ssh_digest_free(ctx); 231 ssh_digest_free(ctx);
231 return 0; 232 return 0;
232} 233}
233 234
234int 235int
235ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen) 236ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen)
236{ 237{
237 return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen); 238 return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen);
238} 239}
diff --git a/digest-openssl.c b/digest-openssl.c
index 863d37d03..02b170341 100644
--- a/digest-openssl.c
+++ b/digest-openssl.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: digest-openssl.c,v 1.2 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: digest-openssl.c,v 1.4 2014/07/03 03:26:43 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2013 Damien Miller <djm@mindrot.org> 3 * Copyright (c) 2013 Damien Miller <djm@mindrot.org>
4 * 4 *
@@ -26,8 +26,18 @@
26 26
27#include "openbsd-compat/openssl-compat.h" 27#include "openbsd-compat/openssl-compat.h"
28 28
29#include "buffer.h" 29#include "sshbuf.h"
30#include "digest.h" 30#include "digest.h"
31#include "ssherr.h"
32
33#ifndef HAVE_EVP_RIPEMD160
34# define EVP_ripemd160 NULL
35#endif /* HAVE_EVP_RIPEMD160 */
36#ifndef HAVE_EVP_SHA256
37# define EVP_sha256 NULL
38# define EVP_sha384 NULL
39# define EVP_sha512 NULL
40#endif /* HAVE_EVP_SHA256 */
31 41
32struct ssh_digest_ctx { 42struct ssh_digest_ctx {
33 int alg; 43 int alg;
@@ -46,11 +56,9 @@ const struct ssh_digest digests[] = {
46 { SSH_DIGEST_MD5, "MD5", 16, EVP_md5 }, 56 { SSH_DIGEST_MD5, "MD5", 16, EVP_md5 },
47 { SSH_DIGEST_RIPEMD160, "RIPEMD160", 20, EVP_ripemd160 }, 57 { SSH_DIGEST_RIPEMD160, "RIPEMD160", 20, EVP_ripemd160 },
48 { SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 }, 58 { SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 },
49#ifdef HAVE_EVP_SHA256 /* XXX replace with local if missing */
50 { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 }, 59 { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 },
51 { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 }, 60 { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 },
52 { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 }, 61 { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 },
53#endif
54 { -1, NULL, 0, NULL }, 62 { -1, NULL, 0, NULL },
55}; 63};
56 64
@@ -61,6 +69,8 @@ ssh_digest_by_alg(int alg)
61 return NULL; 69 return NULL;
62 if (digests[alg].id != alg) /* sanity */ 70 if (digests[alg].id != alg) /* sanity */
63 return NULL; 71 return NULL;
72 if (digests[alg].mdfunc == NULL)
73 return NULL;
64 return &(digests[alg]); 74 return &(digests[alg]);
65} 75}
66 76
@@ -98,9 +108,11 @@ ssh_digest_start(int alg)
98int 108int
99ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) 109ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
100{ 110{
111 if (from->alg != to->alg)
112 return SSH_ERR_INVALID_ARGUMENT;
101 /* we have bcopy-style order while openssl has memcpy-style */ 113 /* we have bcopy-style order while openssl has memcpy-style */
102 if (!EVP_MD_CTX_copy_ex(&to->mdctx, &from->mdctx)) 114 if (!EVP_MD_CTX_copy_ex(&to->mdctx, &from->mdctx))
103 return -1; 115 return SSH_ERR_LIBCRYPTO_ERROR;
104 return 0; 116 return 0;
105} 117}
106 118
@@ -108,14 +120,14 @@ int
108ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) 120ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
109{ 121{
110 if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1) 122 if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1)
111 return -1; 123 return SSH_ERR_LIBCRYPTO_ERROR;
112 return 0; 124 return 0;
113} 125}
114 126
115int 127int
116ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b) 128ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b)
117{ 129{
118 return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b)); 130 return ssh_digest_update(ctx, sshbuf_ptr(b), sshbuf_len(b));
119} 131}
120 132
121int 133int
@@ -125,13 +137,13 @@ ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
125 u_int l = dlen; 137 u_int l = dlen;
126 138
127 if (dlen > UINT_MAX) 139 if (dlen > UINT_MAX)
128 return -1; 140 return SSH_ERR_INVALID_ARGUMENT;
129 if (dlen < digest->digest_len) /* No truncation allowed */ 141 if (dlen < digest->digest_len) /* No truncation allowed */
130 return -1; 142 return SSH_ERR_INVALID_ARGUMENT;
131 if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1) 143 if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1)
132 return -1; 144 return SSH_ERR_LIBCRYPTO_ERROR;
133 if (l != digest->digest_len) /* sanity */ 145 if (l != digest->digest_len) /* sanity */
134 return -1; 146 return SSH_ERR_INTERNAL_ERROR;
135 return 0; 147 return 0;
136} 148}
137 149
@@ -148,19 +160,23 @@ ssh_digest_free(struct ssh_digest_ctx *ctx)
148int 160int
149ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) 161ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
150{ 162{
151 struct ssh_digest_ctx *ctx = ssh_digest_start(alg); 163 const struct ssh_digest *digest = ssh_digest_by_alg(alg);
152 164 u_int mdlen;
153 if (ctx == NULL) 165
154 return -1; 166 if (digest == NULL)
155 if (ssh_digest_update(ctx, m, mlen) != 0 || 167 return SSH_ERR_INVALID_ARGUMENT;
156 ssh_digest_final(ctx, d, dlen) != 0) 168 if (dlen > UINT_MAX)
157 return -1; 169 return SSH_ERR_INVALID_ARGUMENT;
158 ssh_digest_free(ctx); 170 if (dlen < digest->digest_len)
171 return SSH_ERR_INVALID_ARGUMENT;
172 mdlen = dlen;
173 if (!EVP_Digest(m, mlen, d, &mdlen, digest->mdfunc(), NULL))
174 return SSH_ERR_LIBCRYPTO_ERROR;
159 return 0; 175 return 0;
160} 176}
161 177
162int 178int
163ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen) 179ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen)
164{ 180{
165 return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen); 181 return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen);
166} 182}
diff --git a/digest.h b/digest.h
index 0fb207fca..6afb197f0 100644
--- a/digest.h
+++ b/digest.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: digest.h,v 1.2 2014/01/27 18:58:14 markus Exp $ */ 1/* $OpenBSD: digest.h,v 1.6 2014/07/03 04:36:45 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2013 Damien Miller <djm@mindrot.org> 3 * Copyright (c) 2013 Damien Miller <djm@mindrot.org>
4 * 4 *
@@ -30,6 +30,7 @@
30#define SSH_DIGEST_SHA512 5 30#define SSH_DIGEST_SHA512 5
31#define SSH_DIGEST_MAX 6 31#define SSH_DIGEST_MAX 6
32 32
33struct sshbuf;
33struct ssh_digest_ctx; 34struct ssh_digest_ctx;
34 35
35/* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */ 36/* 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,
47 u_char *d, size_t dlen) 48 u_char *d, size_t dlen)
48 __attribute__((__bounded__(__buffer__, 2, 3))) 49 __attribute__((__bounded__(__buffer__, 2, 3)))
49 __attribute__((__bounded__(__buffer__, 4, 5))); 50 __attribute__((__bounded__(__buffer__, 4, 5)));
50int ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen) 51int ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen)
51 __attribute__((__bounded__(__buffer__, 3, 4))); 52 __attribute__((__bounded__(__buffer__, 3, 4)));
52 53
53/* Update API */ 54/* Update API */
54struct ssh_digest_ctx *ssh_digest_start(int alg); 55struct ssh_digest_ctx *ssh_digest_start(int alg);
55int ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) 56int ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
56 __attribute__((__bounded__(__buffer__, 2, 3))); 57 __attribute__((__bounded__(__buffer__, 2, 3)));
57int ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b); 58int ssh_digest_update_buffer(struct ssh_digest_ctx *ctx,
59 const struct sshbuf *b);
58int ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) 60int ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
59 __attribute__((__bounded__(__buffer__, 2, 3))); 61 __attribute__((__bounded__(__buffer__, 2, 3)));
60void ssh_digest_free(struct ssh_digest_ctx *ctx); 62void ssh_digest_free(struct ssh_digest_ctx *ctx);
diff --git a/dns.c b/dns.c
index 630b97ae8..c4d073cf5 100644
--- a/dns.c
+++ b/dns.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: dns.c,v 1.29 2013/05/17 00:13:13 djm Exp $ */ 1/* $OpenBSD: dns.c,v 1.31 2014/06/24 01:13:21 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2003 Wesley Griffin. All rights reserved. 4 * Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -34,6 +34,8 @@
34#include <stdarg.h> 34#include <stdarg.h>
35#include <stdio.h> 35#include <stdio.h>
36#include <string.h> 36#include <string.h>
37#include <stdarg.h>
38#include <stdlib.h>
37 39
38#include "xmalloc.h" 40#include "xmalloc.h"
39#include "key.h" 41#include "key.h"
@@ -96,6 +98,11 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
96 if (!*digest_type) 98 if (!*digest_type)
97 *digest_type = SSHFP_HASH_SHA256; 99 *digest_type = SSHFP_HASH_SHA256;
98 break; 100 break;
101 case KEY_ED25519:
102 *algorithm = SSHFP_KEY_ED25519;
103 if (!*digest_type)
104 *digest_type = SSHFP_HASH_SHA256;
105 break;
99 default: 106 default:
100 *algorithm = SSHFP_KEY_RESERVED; /* 0 */ 107 *algorithm = SSHFP_KEY_RESERVED; /* 0 */
101 *digest_type = SSHFP_HASH_RESERVED; /* 0 */ 108 *digest_type = SSHFP_HASH_RESERVED; /* 0 */
diff --git a/dns.h b/dns.h
index d5f428177..b9feae6be 100644
--- a/dns.h
+++ b/dns.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: dns.h,v 1.12 2012/05/23 03:28:28 djm Exp $ */ 1/* $OpenBSD: dns.h,v 1.13 2014/04/20 09:24:26 logan Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2003 Wesley Griffin. All rights reserved. 4 * Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -32,7 +32,8 @@ enum sshfp_types {
32 SSHFP_KEY_RESERVED = 0, 32 SSHFP_KEY_RESERVED = 0,
33 SSHFP_KEY_RSA = 1, 33 SSHFP_KEY_RSA = 1,
34 SSHFP_KEY_DSA = 2, 34 SSHFP_KEY_DSA = 2,
35 SSHFP_KEY_ECDSA = 3 35 SSHFP_KEY_ECDSA = 3,
36 SSHFP_KEY_ED25519 = 4
36}; 37};
37 38
38enum sshfp_hashes { 39enum sshfp_hashes {
diff --git a/entropy.c b/entropy.c
index 2d483b391..1e9d52ac4 100644
--- a/entropy.c
+++ b/entropy.c
@@ -43,6 +43,8 @@
43#include <openssl/crypto.h> 43#include <openssl/crypto.h>
44#include <openssl/err.h> 44#include <openssl/err.h>
45 45
46#include "openbsd-compat/openssl-compat.h"
47
46#include "ssh.h" 48#include "ssh.h"
47#include "misc.h" 49#include "misc.h"
48#include "xmalloc.h" 50#include "xmalloc.h"
@@ -209,16 +211,7 @@ seed_rng(void)
209#ifndef OPENSSL_PRNG_ONLY 211#ifndef OPENSSL_PRNG_ONLY
210 unsigned char buf[RANDOM_SEED_SIZE]; 212 unsigned char buf[RANDOM_SEED_SIZE];
211#endif 213#endif
212 /* 214 if (!ssh_compatible_openssl(OPENSSL_VERSION_NUMBER, SSLeay()))
213 * OpenSSL version numbers: MNNFFPPS: major minor fix patch status
214 * We match major, minor, fix and status (not patch) for <1.0.0.
215 * After that, we acceptable compatible fix versions (so we
216 * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed
217 * within a patch series.
218 */
219 u_long version_mask = SSLeay() >= 0x1000000f ? ~0xffff0L : ~0xff0L;
220 if (((SSLeay() ^ OPENSSL_VERSION_NUMBER) & version_mask) ||
221 (SSLeay() >> 12) < (OPENSSL_VERSION_NUMBER >> 12))
222 fatal("OpenSSL version mismatch. Built against %lx, you " 215 fatal("OpenSSL version mismatch. Built against %lx, you "
223 "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); 216 "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay());
224 217
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
index 759fa104f..795992d9f 100644
--- a/gss-serv-krb5.c
+++ b/gss-serv-krb5.c
@@ -39,6 +39,7 @@
39#include "hostfile.h" 39#include "hostfile.h"
40#include "auth.h" 40#include "auth.h"
41#include "log.h" 41#include "log.h"
42#include "misc.h"
42#include "servconf.h" 43#include "servconf.h"
43 44
44#include "buffer.h" 45#include "buffer.h"
diff --git a/gss-serv.c b/gss-serv.c
index e61b37bec..5c599247b 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: gss-serv.c,v 1.26 2014/02/26 20:28:44 djm Exp $ */ 1/* $OpenBSD: gss-serv.c,v 1.27 2014/07/03 03:34:09 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@@ -97,13 +97,13 @@ static OM_uint32
97ssh_gssapi_acquire_cred(Gssctxt *ctx) 97ssh_gssapi_acquire_cred(Gssctxt *ctx)
98{ 98{
99 OM_uint32 status; 99 OM_uint32 status;
100 char lname[MAXHOSTNAMELEN]; 100 char lname[NI_MAXHOST];
101 gss_OID_set oidset; 101 gss_OID_set oidset;
102 102
103 gss_create_empty_oid_set(&status, &oidset); 103 gss_create_empty_oid_set(&status, &oidset);
104 gss_add_oid_set_member(&status, ctx->oid, &oidset); 104 gss_add_oid_set_member(&status, ctx->oid, &oidset);
105 105
106 if (gethostname(lname, MAXHOSTNAMELEN)) { 106 if (gethostname(lname, sizeof(lname))) {
107 gss_release_oid_set(&status, &oidset); 107 gss_release_oid_set(&status, &oidset);
108 return (-1); 108 return (-1);
109 } 109 }
diff --git a/hmac.h b/hmac.h
index 2374a6955..42b33d002 100644
--- a/hmac.h
+++ b/hmac.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: hmac.h,v 1.6 2014/01/27 18:58:14 markus Exp $ */ 1/* $OpenBSD: hmac.h,v 1.9 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Markus Friedl. All rights reserved. 3 * Copyright (c) 2014 Markus Friedl. All rights reserved.
4 * 4 *
@@ -21,6 +21,7 @@
21/* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */ 21/* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */
22size_t ssh_hmac_bytes(int alg); 22size_t ssh_hmac_bytes(int alg);
23 23
24struct sshbuf;
24struct ssh_hmac_ctx; 25struct ssh_hmac_ctx;
25struct ssh_hmac_ctx *ssh_hmac_start(int alg); 26struct ssh_hmac_ctx *ssh_hmac_start(int alg);
26 27
@@ -29,7 +30,7 @@ int ssh_hmac_init(struct ssh_hmac_ctx *ctx, const void *key, size_t klen)
29 __attribute__((__bounded__(__buffer__, 2, 3))); 30 __attribute__((__bounded__(__buffer__, 2, 3)));
30int ssh_hmac_update(struct ssh_hmac_ctx *ctx, const void *m, size_t mlen) 31int ssh_hmac_update(struct ssh_hmac_ctx *ctx, const void *m, size_t mlen)
31 __attribute__((__bounded__(__buffer__, 2, 3))); 32 __attribute__((__bounded__(__buffer__, 2, 3)));
32int ssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const Buffer *b); 33int ssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const struct sshbuf *b);
33int ssh_hmac_final(struct ssh_hmac_ctx *ctx, u_char *d, size_t dlen) 34int ssh_hmac_final(struct ssh_hmac_ctx *ctx, u_char *d, size_t dlen)
34 __attribute__((__bounded__(__buffer__, 2, 3))); 35 __attribute__((__bounded__(__buffer__, 2, 3)));
35void ssh_hmac_free(struct ssh_hmac_ctx *ctx); 36void ssh_hmac_free(struct ssh_hmac_ctx *ctx);
diff --git a/hostfile.c b/hostfile.c
index 8bc9540b7..ee2daf45f 100644
--- a/hostfile.c
+++ b/hostfile.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: hostfile.c,v 1.55 2014/01/31 16:39:19 tedu Exp $ */ 1/* $OpenBSD: hostfile.c,v 1.57 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -47,6 +47,7 @@
47#include <stdio.h> 47#include <stdio.h>
48#include <stdlib.h> 48#include <stdlib.h>
49#include <string.h> 49#include <string.h>
50#include <stdarg.h>
50 51
51#include "xmalloc.h" 52#include "xmalloc.h"
52#include "match.h" 53#include "match.h"
@@ -182,6 +183,7 @@ static int
182hostfile_check_key(int bits, const Key *key, const char *host, 183hostfile_check_key(int bits, const Key *key, const char *host,
183 const char *filename, u_long linenum) 184 const char *filename, u_long linenum)
184{ 185{
186#ifdef WITH_SSH1
185 if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL) 187 if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)
186 return 1; 188 return 1;
187 if (bits != BN_num_bits(key->rsa->n)) { 189 if (bits != BN_num_bits(key->rsa->n)) {
@@ -191,6 +193,7 @@ hostfile_check_key(int bits, const Key *key, const char *host,
191 logit("Warning: replace %d with %d in %s, line %lu.", 193 logit("Warning: replace %d with %d in %s, line %lu.",
192 bits, BN_num_bits(key->rsa->n), filename, linenum); 194 bits, BN_num_bits(key->rsa->n), filename, linenum);
193 } 195 }
196#endif
194 return 1; 197 return 1;
195} 198}
196 199
@@ -296,11 +299,15 @@ load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path)
296 key = key_new(KEY_UNSPEC); 299 key = key_new(KEY_UNSPEC);
297 if (!hostfile_read_key(&cp, &kbits, key)) { 300 if (!hostfile_read_key(&cp, &kbits, key)) {
298 key_free(key); 301 key_free(key);
302#ifdef WITH_SSH1
299 key = key_new(KEY_RSA1); 303 key = key_new(KEY_RSA1);
300 if (!hostfile_read_key(&cp, &kbits, key)) { 304 if (!hostfile_read_key(&cp, &kbits, key)) {
301 key_free(key); 305 key_free(key);
302 continue; 306 continue;
303 } 307 }
308#else
309 continue;
310#endif
304 } 311 }
305 if (!hostfile_check_key(kbits, key, host, path, linenum)) 312 if (!hostfile_check_key(kbits, key, host, path, linenum))
306 continue; 313 continue;
diff --git a/kex.c b/kex.c
index 74e2b8682..a173e70e3 100644
--- a/kex.c
+++ b/kex.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kex.c,v 1.98 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: kex.c,v 1.99 2014/04/29 18:01:49 markus Exp $ */
2/* 2/*
3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -33,7 +33,9 @@
33#include <stdlib.h> 33#include <stdlib.h>
34#include <string.h> 34#include <string.h>
35 35
36#ifdef WITH_OPENSSL
36#include <openssl/crypto.h> 37#include <openssl/crypto.h>
38#endif
37 39
38#include "xmalloc.h" 40#include "xmalloc.h"
39#include "ssh2.h" 41#include "ssh2.h"
@@ -70,12 +72,13 @@ struct kexalg {
70 int hash_alg; 72 int hash_alg;
71}; 73};
72static const struct kexalg kexalgs[] = { 74static const struct kexalg kexalgs[] = {
75#ifdef WITH_OPENSSL
73 { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, 76 { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
74 { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, 77 { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
75 { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, 78 { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
76#ifdef HAVE_EVP_SHA256 79#ifdef HAVE_EVP_SHA256
77 { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, 80 { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
78#endif 81#endif /* HAVE_EVP_SHA256 */
79#ifdef OPENSSL_HAS_ECC 82#ifdef OPENSSL_HAS_ECC
80 { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, 83 { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
81 NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, 84 NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
@@ -84,12 +87,13 @@ static const struct kexalg kexalgs[] = {
84# ifdef OPENSSL_HAS_NISTP521 87# ifdef OPENSSL_HAS_NISTP521
85 { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, 88 { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
86 SSH_DIGEST_SHA512 }, 89 SSH_DIGEST_SHA512 },
87# endif 90# endif /* OPENSSL_HAS_NISTP521 */
88#endif 91#endif /* OPENSSL_HAS_ECC */
89 { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, 92 { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
93#endif /* WITH_OPENSSL */
90#ifdef HAVE_EVP_SHA256 94#ifdef HAVE_EVP_SHA256
91 { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, 95 { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
92#endif 96#endif /* HAVE_EVP_SHA256 */
93 { NULL, -1, -1, -1}, 97 { NULL, -1, -1, -1},
94}; 98};
95 99
@@ -615,6 +619,7 @@ kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen,
615 } 619 }
616} 620}
617 621
622#ifdef WITH_OPENSSL
618void 623void
619kex_derive_keys_bn(Kex *kex, u_char *hash, u_int hashlen, const BIGNUM *secret) 624kex_derive_keys_bn(Kex *kex, u_char *hash, u_int hashlen, const BIGNUM *secret)
620{ 625{
@@ -626,6 +631,7 @@ kex_derive_keys_bn(Kex *kex, u_char *hash, u_int hashlen, const BIGNUM *secret)
626 buffer_ptr(&shared_secret), buffer_len(&shared_secret)); 631 buffer_ptr(&shared_secret), buffer_len(&shared_secret));
627 buffer_free(&shared_secret); 632 buffer_free(&shared_secret);
628} 633}
634#endif
629 635
630Newkeys * 636Newkeys *
631kex_get_newkeys(int mode) 637kex_get_newkeys(int mode)
@@ -637,6 +643,7 @@ kex_get_newkeys(int mode)
637 return ret; 643 return ret;
638} 644}
639 645
646#ifdef WITH_SSH1
640void 647void
641derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, 648derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
642 u_int8_t cookie[8], u_int8_t id[16]) 649 u_int8_t cookie[8], u_int8_t id[16])
@@ -669,6 +676,7 @@ derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
669 explicit_bzero(nbuf, sizeof(nbuf)); 676 explicit_bzero(nbuf, sizeof(nbuf));
670 explicit_bzero(obuf, sizeof(obuf)); 677 explicit_bzero(obuf, sizeof(obuf));
671} 678}
679#endif
672 680
673#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) 681#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
674void 682void
diff --git a/kex.h b/kex.h
index c85680eea..4c40ec851 100644
--- a/kex.h
+++ b/kex.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: kex.h,v 1.62 2014/01/27 18:58:14 markus Exp $ */ 1/* $OpenBSD: kex.h,v 1.64 2014/05/02 03:27:54 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
diff --git a/kexc25519.c b/kexc25519.c
index ee79b4327..e3afa0055 100644
--- a/kexc25519.c
+++ b/kexc25519.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kexc25519.c,v 1.5 2014/01/31 16:39:19 tedu Exp $ */ 1/* $OpenBSD: kexc25519.c,v 1.7 2014/05/02 03:27:54 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001, 2013 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001, 2013 Markus Friedl. All rights reserved.
4 * Copyright (c) 2010 Damien Miller. All rights reserved. 4 * Copyright (c) 2010 Damien Miller. All rights reserved.
diff --git a/key.c b/key.c
index 168e1b7d7..206076159 100644
--- a/key.c
+++ b/key.c
@@ -1,2089 +1,242 @@
1/* $OpenBSD: key.c,v 1.116 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: key.c,v 1.122 2014/07/22 01:18:50 dtucker Exp $ */
2/* 2/*
3 * read_bignum(): 3 * placed in the public domain
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 *
6 * As far as I am concerned, the code I have written for this software
7 * can be used freely for any purpose. Any derived versions of this
8 * software must be clearly marked as such, and if the derived work is
9 * incompatible with the protocol description in the RFC file, it must be
10 * called by a name other than "ssh" or "Secure Shell".
11 *
12 *
13 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
14 * Copyright (c) 2008 Alexander von Gernler. All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */ 4 */
36 5
37#include "includes.h" 6#include "includes.h"
38 7
39#include <sys/param.h> 8#include <sys/param.h>
40#include <sys/types.h> 9#include <sys/types.h>
41 10#include <errno.h>
42#include "crypto_api.h"
43
44#include <openssl/evp.h>
45#include <openbsd-compat/openssl-compat.h>
46
47#include <stdarg.h> 11#include <stdarg.h>
48#include <stdio.h> 12#include <stdio.h>
49#include <string.h>
50 13
51#include "xmalloc.h" 14#define SSH_KEY_NO_DEFINE
52#include "key.h" 15#include "key.h"
53#include "rsa.h"
54#include "uuencode.h"
55#include "buffer.h"
56#include "log.h"
57#include "misc.h"
58#include "ssh2.h"
59#include "digest.h"
60
61static int to_blob(const Key *, u_char **, u_int *, int);
62static Key *key_from_blob2(const u_char *, u_int, int);
63
64static struct KeyCert *
65cert_new(void)
66{
67 struct KeyCert *cert;
68
69 cert = xcalloc(1, sizeof(*cert));
70 buffer_init(&cert->certblob);
71 buffer_init(&cert->critical);
72 buffer_init(&cert->extensions);
73 cert->key_id = NULL;
74 cert->principals = NULL;
75 cert->signature_key = NULL;
76 return cert;
77}
78
79Key *
80key_new(int type)
81{
82 Key *k;
83 RSA *rsa;
84 DSA *dsa;
85 k = xcalloc(1, sizeof(*k));
86 k->type = type;
87 k->ecdsa = NULL;
88 k->ecdsa_nid = -1;
89 k->dsa = NULL;
90 k->rsa = NULL;
91 k->cert = NULL;
92 k->ed25519_sk = NULL;
93 k->ed25519_pk = NULL;
94 switch (k->type) {
95 case KEY_RSA1:
96 case KEY_RSA:
97 case KEY_RSA_CERT_V00:
98 case KEY_RSA_CERT:
99 if ((rsa = RSA_new()) == NULL)
100 fatal("key_new: RSA_new failed");
101 if ((rsa->n = BN_new()) == NULL)
102 fatal("key_new: BN_new failed");
103 if ((rsa->e = BN_new()) == NULL)
104 fatal("key_new: BN_new failed");
105 k->rsa = rsa;
106 break;
107 case KEY_DSA:
108 case KEY_DSA_CERT_V00:
109 case KEY_DSA_CERT:
110 if ((dsa = DSA_new()) == NULL)
111 fatal("key_new: DSA_new failed");
112 if ((dsa->p = BN_new()) == NULL)
113 fatal("key_new: BN_new failed");
114 if ((dsa->q = BN_new()) == NULL)
115 fatal("key_new: BN_new failed");
116 if ((dsa->g = BN_new()) == NULL)
117 fatal("key_new: BN_new failed");
118 if ((dsa->pub_key = BN_new()) == NULL)
119 fatal("key_new: BN_new failed");
120 k->dsa = dsa;
121 break;
122#ifdef OPENSSL_HAS_ECC
123 case KEY_ECDSA:
124 case KEY_ECDSA_CERT:
125 /* Cannot do anything until we know the group */
126 break;
127#endif
128 case KEY_ED25519:
129 case KEY_ED25519_CERT:
130 /* no need to prealloc */
131 break;
132 case KEY_UNSPEC:
133 break;
134 default:
135 fatal("key_new: bad key type %d", k->type);
136 break;
137 }
138 16
139 if (key_is_cert(k)) 17#include "compat.h"
140 k->cert = cert_new(); 18#include "sshkey.h"
141 19#include "ssherr.h"
142 return k; 20#include "log.h"
143} 21#include "authfile.h"
144 22
145void 23void
146key_add_private(Key *k) 24key_add_private(Key *k)
147{ 25{
148 switch (k->type) { 26 int r;
149 case KEY_RSA1: 27
150 case KEY_RSA: 28 if ((r = sshkey_add_private(k)) != 0)
151 case KEY_RSA_CERT_V00: 29 fatal("%s: %s", __func__, ssh_err(r));
152 case KEY_RSA_CERT:
153 if ((k->rsa->d = BN_new()) == NULL)
154 fatal("key_new_private: BN_new failed");
155 if ((k->rsa->iqmp = BN_new()) == NULL)
156 fatal("key_new_private: BN_new failed");
157 if ((k->rsa->q = BN_new()) == NULL)
158 fatal("key_new_private: BN_new failed");
159 if ((k->rsa->p = BN_new()) == NULL)
160 fatal("key_new_private: BN_new failed");
161 if ((k->rsa->dmq1 = BN_new()) == NULL)
162 fatal("key_new_private: BN_new failed");
163 if ((k->rsa->dmp1 = BN_new()) == NULL)
164 fatal("key_new_private: BN_new failed");
165 break;
166 case KEY_DSA:
167 case KEY_DSA_CERT_V00:
168 case KEY_DSA_CERT:
169 if ((k->dsa->priv_key = BN_new()) == NULL)
170 fatal("key_new_private: BN_new failed");
171 break;
172 case KEY_ECDSA:
173 case KEY_ECDSA_CERT:
174 /* Cannot do anything until we know the group */
175 break;
176 case KEY_ED25519:
177 case KEY_ED25519_CERT:
178 /* no need to prealloc */
179 break;
180 case KEY_UNSPEC:
181 break;
182 default:
183 break;
184 }
185} 30}
186 31
187Key * 32Key *
188key_new_private(int type) 33key_new_private(int type)
189{ 34{
190 Key *k = key_new(type); 35 Key *ret = NULL;
191
192 key_add_private(k);
193 return k;
194}
195
196static void
197cert_free(struct KeyCert *cert)
198{
199 u_int i;
200
201 buffer_free(&cert->certblob);
202 buffer_free(&cert->critical);
203 buffer_free(&cert->extensions);
204 free(cert->key_id);
205 for (i = 0; i < cert->nprincipals; i++)
206 free(cert->principals[i]);
207 free(cert->principals);
208 if (cert->signature_key != NULL)
209 key_free(cert->signature_key);
210 free(cert);
211}
212
213void
214key_free(Key *k)
215{
216 if (k == NULL)
217 fatal("key_free: key is NULL");
218 switch (k->type) {
219 case KEY_RSA1:
220 case KEY_RSA:
221 case KEY_RSA_CERT_V00:
222 case KEY_RSA_CERT:
223 if (k->rsa != NULL)
224 RSA_free(k->rsa);
225 k->rsa = NULL;
226 break;
227 case KEY_DSA:
228 case KEY_DSA_CERT_V00:
229 case KEY_DSA_CERT:
230 if (k->dsa != NULL)
231 DSA_free(k->dsa);
232 k->dsa = NULL;
233 break;
234#ifdef OPENSSL_HAS_ECC
235 case KEY_ECDSA:
236 case KEY_ECDSA_CERT:
237 if (k->ecdsa != NULL)
238 EC_KEY_free(k->ecdsa);
239 k->ecdsa = NULL;
240 break;
241#endif
242 case KEY_ED25519:
243 case KEY_ED25519_CERT:
244 if (k->ed25519_pk) {
245 explicit_bzero(k->ed25519_pk, ED25519_PK_SZ);
246 free(k->ed25519_pk);
247 k->ed25519_pk = NULL;
248 }
249 if (k->ed25519_sk) {
250 explicit_bzero(k->ed25519_sk, ED25519_SK_SZ);
251 free(k->ed25519_sk);
252 k->ed25519_sk = NULL;
253 }
254 break;
255 case KEY_UNSPEC:
256 break;
257 default:
258 fatal("key_free: bad key type %d", k->type);
259 break;
260 }
261 if (key_is_cert(k)) {
262 if (k->cert != NULL)
263 cert_free(k->cert);
264 k->cert = NULL;
265 }
266
267 free(k);
268}
269
270static int
271cert_compare(struct KeyCert *a, struct KeyCert *b)
272{
273 if (a == NULL && b == NULL)
274 return 1;
275 if (a == NULL || b == NULL)
276 return 0;
277 if (buffer_len(&a->certblob) != buffer_len(&b->certblob))
278 return 0;
279 if (timingsafe_bcmp(buffer_ptr(&a->certblob), buffer_ptr(&b->certblob),
280 buffer_len(&a->certblob)) != 0)
281 return 0;
282 return 1;
283}
284
285/*
286 * Compare public portions of key only, allowing comparisons between
287 * certificates and plain keys too.
288 */
289int
290key_equal_public(const Key *a, const Key *b)
291{
292#ifdef OPENSSL_HAS_ECC
293 BN_CTX *bnctx;
294#endif
295 36
296 if (a == NULL || b == NULL || 37 if ((ret = sshkey_new_private(type)) == NULL)
297 key_type_plain(a->type) != key_type_plain(b->type)) 38 fatal("%s: failed", __func__);
298 return 0; 39 return ret;
299
300 switch (a->type) {
301 case KEY_RSA1:
302 case KEY_RSA_CERT_V00:
303 case KEY_RSA_CERT:
304 case KEY_RSA:
305 return a->rsa != NULL && b->rsa != NULL &&
306 BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
307 BN_cmp(a->rsa->n, b->rsa->n) == 0;
308 case KEY_DSA_CERT_V00:
309 case KEY_DSA_CERT:
310 case KEY_DSA:
311 return a->dsa != NULL && b->dsa != NULL &&
312 BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
313 BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
314 BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
315 BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
316#ifdef OPENSSL_HAS_ECC
317 case KEY_ECDSA_CERT:
318 case KEY_ECDSA:
319 if (a->ecdsa == NULL || b->ecdsa == NULL ||
320 EC_KEY_get0_public_key(a->ecdsa) == NULL ||
321 EC_KEY_get0_public_key(b->ecdsa) == NULL)
322 return 0;
323 if ((bnctx = BN_CTX_new()) == NULL)
324 fatal("%s: BN_CTX_new failed", __func__);
325 if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa),
326 EC_KEY_get0_group(b->ecdsa), bnctx) != 0 ||
327 EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa),
328 EC_KEY_get0_public_key(a->ecdsa),
329 EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) {
330 BN_CTX_free(bnctx);
331 return 0;
332 }
333 BN_CTX_free(bnctx);
334 return 1;
335#endif /* OPENSSL_HAS_ECC */
336 case KEY_ED25519:
337 case KEY_ED25519_CERT:
338 return a->ed25519_pk != NULL && b->ed25519_pk != NULL &&
339 memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0;
340 default:
341 fatal("key_equal: bad key type %d", a->type);
342 }
343 /* NOTREACHED */
344}
345
346int
347key_equal(const Key *a, const Key *b)
348{
349 if (a == NULL || b == NULL || a->type != b->type)
350 return 0;
351 if (key_is_cert(a)) {
352 if (!cert_compare(a->cert, b->cert))
353 return 0;
354 }
355 return key_equal_public(a, b);
356} 40}
357 41
358u_char* 42u_char*
359key_fingerprint_raw(const Key *k, enum fp_type dgst_type, 43key_fingerprint_raw(const Key *k, enum fp_type dgst_type,
360 u_int *dgst_raw_length) 44 u_int *dgst_raw_length)
361{ 45{
362 u_char *blob = NULL; 46 u_char *ret = NULL;
363 u_char *retval = NULL; 47 size_t dlen;
364 u_int len = 0; 48 int r;
365 int nlen, elen, hash_alg = -1; 49
366 50 if (dgst_raw_length != NULL)
367 *dgst_raw_length = 0; 51 *dgst_raw_length = 0;
368 52 if ((r = sshkey_fingerprint_raw(k, dgst_type, &ret, &dlen)) != 0)
369 /* XXX switch to DIGEST_* directly? */ 53 fatal("%s: %s", __func__, ssh_err(r));
370 switch (dgst_type) { 54 if (dlen > INT_MAX)
371 case SSH_FP_MD5: 55 fatal("%s: giant len %zu", __func__, dlen);
372 hash_alg = SSH_DIGEST_MD5; 56 *dgst_raw_length = dlen;
373 break; 57 return ret;
374 case SSH_FP_SHA1:
375 hash_alg = SSH_DIGEST_SHA1;
376 break;
377 case SSH_FP_SHA256:
378 hash_alg = SSH_DIGEST_SHA256;
379 break;
380 default:
381 fatal("%s: bad digest type %d", __func__, dgst_type);
382 }
383 switch (k->type) {
384 case KEY_RSA1:
385 nlen = BN_num_bytes(k->rsa->n);
386 elen = BN_num_bytes(k->rsa->e);
387 len = nlen + elen;
388 blob = xmalloc(len);
389 BN_bn2bin(k->rsa->n, blob);
390 BN_bn2bin(k->rsa->e, blob + nlen);
391 break;
392 case KEY_DSA:
393 case KEY_ECDSA:
394 case KEY_RSA:
395 case KEY_ED25519:
396 key_to_blob(k, &blob, &len);
397 break;
398 case KEY_DSA_CERT_V00:
399 case KEY_RSA_CERT_V00:
400 case KEY_DSA_CERT:
401 case KEY_ECDSA_CERT:
402 case KEY_RSA_CERT:
403 case KEY_ED25519_CERT:
404 /* We want a fingerprint of the _key_ not of the cert */
405 to_blob(k, &blob, &len, 1);
406 break;
407 case KEY_UNSPEC:
408 return retval;
409 default:
410 fatal("%s: bad key type %d", __func__, k->type);
411 break;
412 }
413 if (blob != NULL) {
414 retval = xmalloc(SSH_DIGEST_MAX_LENGTH);
415 if ((ssh_digest_memory(hash_alg, blob, len,
416 retval, SSH_DIGEST_MAX_LENGTH)) != 0)
417 fatal("%s: digest_memory failed", __func__);
418 explicit_bzero(blob, len);
419 free(blob);
420 *dgst_raw_length = ssh_digest_bytes(hash_alg);
421 } else {
422 fatal("%s: blob is null", __func__);
423 }
424 return retval;
425}
426
427static char *
428key_fingerprint_hex(u_char *dgst_raw, u_int dgst_raw_len)
429{
430 char *retval;
431 u_int i;
432
433 retval = xcalloc(1, dgst_raw_len * 3 + 1);
434 for (i = 0; i < dgst_raw_len; i++) {
435 char hex[4];
436 snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
437 strlcat(retval, hex, dgst_raw_len * 3 + 1);
438 }
439
440 /* Remove the trailing ':' character */
441 retval[(dgst_raw_len * 3) - 1] = '\0';
442 return retval;
443}
444
445static char *
446key_fingerprint_bubblebabble(u_char *dgst_raw, u_int dgst_raw_len)
447{
448 char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
449 char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
450 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
451 u_int i, j = 0, rounds, seed = 1;
452 char *retval;
453
454 rounds = (dgst_raw_len / 2) + 1;
455 retval = xcalloc((rounds * 6), sizeof(char));
456 retval[j++] = 'x';
457 for (i = 0; i < rounds; i++) {
458 u_int idx0, idx1, idx2, idx3, idx4;
459 if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
460 idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
461 seed) % 6;
462 idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
463 idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
464 (seed / 6)) % 6;
465 retval[j++] = vowels[idx0];
466 retval[j++] = consonants[idx1];
467 retval[j++] = vowels[idx2];
468 if ((i + 1) < rounds) {
469 idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
470 idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
471 retval[j++] = consonants[idx3];
472 retval[j++] = '-';
473 retval[j++] = consonants[idx4];
474 seed = ((seed * 5) +
475 ((((u_int)(dgst_raw[2 * i])) * 7) +
476 ((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
477 }
478 } else {
479 idx0 = seed % 6;
480 idx1 = 16;
481 idx2 = seed / 6;
482 retval[j++] = vowels[idx0];
483 retval[j++] = consonants[idx1];
484 retval[j++] = vowels[idx2];
485 }
486 }
487 retval[j++] = 'x';
488 retval[j++] = '\0';
489 return retval;
490}
491
492/*
493 * Draw an ASCII-Art representing the fingerprint so human brain can
494 * profit from its built-in pattern recognition ability.
495 * This technique is called "random art" and can be found in some
496 * scientific publications like this original paper:
497 *
498 * "Hash Visualization: a New Technique to improve Real-World Security",
499 * Perrig A. and Song D., 1999, International Workshop on Cryptographic
500 * Techniques and E-Commerce (CrypTEC '99)
501 * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
502 *
503 * The subject came up in a talk by Dan Kaminsky, too.
504 *
505 * If you see the picture is different, the key is different.
506 * If the picture looks the same, you still know nothing.
507 *
508 * The algorithm used here is a worm crawling over a discrete plane,
509 * leaving a trace (augmenting the field) everywhere it goes.
510 * Movement is taken from dgst_raw 2bit-wise. Bumping into walls
511 * makes the respective movement vector be ignored for this turn.
512 * Graphs are not unambiguous, because circles in graphs can be
513 * walked in either direction.
514 */
515
516/*
517 * Field sizes for the random art. Have to be odd, so the starting point
518 * can be in the exact middle of the picture, and FLDBASE should be >=8 .
519 * Else pictures would be too dense, and drawing the frame would
520 * fail, too, because the key type would not fit in anymore.
521 */
522#define FLDBASE 8
523#define FLDSIZE_Y (FLDBASE + 1)
524#define FLDSIZE_X (FLDBASE * 2 + 1)
525static char *
526key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k)
527{
528 /*
529 * Chars to be used after each other every time the worm
530 * intersects with itself. Matter of taste.
531 */
532 char *augmentation_string = " .o+=*BOX@%&#/^SE";
533 char *retval, *p;
534 u_char field[FLDSIZE_X][FLDSIZE_Y];
535 u_int i, b;
536 int x, y;
537 size_t len = strlen(augmentation_string) - 1;
538
539 retval = xcalloc(1, (FLDSIZE_X + 3) * (FLDSIZE_Y + 2));
540
541 /* initialize field */
542 memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
543 x = FLDSIZE_X / 2;
544 y = FLDSIZE_Y / 2;
545
546 /* process raw key */
547 for (i = 0; i < dgst_raw_len; i++) {
548 int input;
549 /* each byte conveys four 2-bit move commands */
550 input = dgst_raw[i];
551 for (b = 0; b < 4; b++) {
552 /* evaluate 2 bit, rest is shifted later */
553 x += (input & 0x1) ? 1 : -1;
554 y += (input & 0x2) ? 1 : -1;
555
556 /* assure we are still in bounds */
557 x = MAX(x, 0);
558 y = MAX(y, 0);
559 x = MIN(x, FLDSIZE_X - 1);
560 y = MIN(y, FLDSIZE_Y - 1);
561
562 /* augment the field */
563 if (field[x][y] < len - 2)
564 field[x][y]++;
565 input = input >> 2;
566 }
567 }
568
569 /* mark starting point and end point*/
570 field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
571 field[x][y] = len;
572
573 /* fill in retval */
574 snprintf(retval, FLDSIZE_X, "+--[%4s %4u]", key_type(k), key_size(k));
575 p = strchr(retval, '\0');
576
577 /* output upper border */
578 for (i = p - retval - 1; i < FLDSIZE_X; i++)
579 *p++ = '-';
580 *p++ = '+';
581 *p++ = '\n';
582
583 /* output content */
584 for (y = 0; y < FLDSIZE_Y; y++) {
585 *p++ = '|';
586 for (x = 0; x < FLDSIZE_X; x++)
587 *p++ = augmentation_string[MIN(field[x][y], len)];
588 *p++ = '|';
589 *p++ = '\n';
590 }
591
592 /* output lower border */
593 *p++ = '+';
594 for (i = 0; i < FLDSIZE_X; i++)
595 *p++ = '-';
596 *p++ = '+';
597
598 return retval;
599}
600
601char *
602key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
603{
604 char *retval = NULL;
605 u_char *dgst_raw;
606 u_int dgst_raw_len;
607
608 dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len);
609 if (!dgst_raw)
610 fatal("key_fingerprint: null from key_fingerprint_raw()");
611 switch (dgst_rep) {
612 case SSH_FP_HEX:
613 retval = key_fingerprint_hex(dgst_raw, dgst_raw_len);
614 break;
615 case SSH_FP_BUBBLEBABBLE:
616 retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
617 break;
618 case SSH_FP_RANDOMART:
619 retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len, k);
620 break;
621 default:
622 fatal("key_fingerprint: bad digest representation %d",
623 dgst_rep);
624 break;
625 }
626 explicit_bzero(dgst_raw, dgst_raw_len);
627 free(dgst_raw);
628 return retval;
629}
630
631/*
632 * Reads a multiple-precision integer in decimal from the buffer, and advances
633 * the pointer. The integer must already be initialized. This function is
634 * permitted to modify the buffer. This leaves *cpp to point just beyond the
635 * last processed (and maybe modified) character. Note that this may modify
636 * the buffer containing the number.
637 */
638static int
639read_bignum(char **cpp, BIGNUM * value)
640{
641 char *cp = *cpp;
642 int old;
643
644 /* Skip any leading whitespace. */
645 for (; *cp == ' ' || *cp == '\t'; cp++)
646 ;
647
648 /* Check that it begins with a decimal digit. */
649 if (*cp < '0' || *cp > '9')
650 return 0;
651
652 /* Save starting position. */
653 *cpp = cp;
654
655 /* Move forward until all decimal digits skipped. */
656 for (; *cp >= '0' && *cp <= '9'; cp++)
657 ;
658
659 /* Save the old terminating character, and replace it by \0. */
660 old = *cp;
661 *cp = 0;
662
663 /* Parse the number. */
664 if (BN_dec2bn(&value, *cpp) == 0)
665 return 0;
666
667 /* Restore old terminating character. */
668 *cp = old;
669
670 /* Move beyond the number and return success. */
671 *cpp = cp;
672 return 1;
673}
674
675static int
676write_bignum(FILE *f, BIGNUM *num)
677{
678 char *buf = BN_bn2dec(num);
679 if (buf == NULL) {
680 error("write_bignum: BN_bn2dec() failed");
681 return 0;
682 }
683 fprintf(f, " %s", buf);
684 OPENSSL_free(buf);
685 return 1;
686} 58}
687 59
688/* returns 1 ok, -1 error */
689int 60int
690key_read(Key *ret, char **cpp) 61key_read(Key *ret, char **cpp)
691{ 62{
692 Key *k; 63 return sshkey_read(ret, cpp) == 0 ? 1 : -1;
693 int success = -1;
694 char *cp, *space;
695 int len, n, type;
696 u_int bits;
697 u_char *blob;
698#ifdef OPENSSL_HAS_ECC
699 int curve_nid = -1;
700#endif
701
702 cp = *cpp;
703
704 switch (ret->type) {
705 case KEY_RSA1:
706 /* Get number of bits. */
707 if (*cp < '0' || *cp > '9')
708 return -1; /* Bad bit count... */
709 for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
710 bits = 10 * bits + *cp - '0';
711 if (bits == 0)
712 return -1;
713 *cpp = cp;
714 /* Get public exponent, public modulus. */
715 if (!read_bignum(cpp, ret->rsa->e))
716 return -1;
717 if (!read_bignum(cpp, ret->rsa->n))
718 return -1;
719 /* validate the claimed number of bits */
720 if ((u_int)BN_num_bits(ret->rsa->n) != bits) {
721 verbose("key_read: claimed key size %d does not match "
722 "actual %d", bits, BN_num_bits(ret->rsa->n));
723 return -1;
724 }
725 success = 1;
726 break;
727 case KEY_UNSPEC:
728 case KEY_RSA:
729 case KEY_DSA:
730 case KEY_ECDSA:
731 case KEY_ED25519:
732 case KEY_DSA_CERT_V00:
733 case KEY_RSA_CERT_V00:
734 case KEY_DSA_CERT:
735 case KEY_ECDSA_CERT:
736 case KEY_RSA_CERT:
737 case KEY_ED25519_CERT:
738 space = strchr(cp, ' ');
739 if (space == NULL) {
740 debug3("key_read: missing whitespace");
741 return -1;
742 }
743 *space = '\0';
744 type = key_type_from_name(cp);
745#ifdef OPENSSL_HAS_ECC
746 if (key_type_plain(type) == KEY_ECDSA &&
747 (curve_nid = key_ecdsa_nid_from_name(cp)) == -1) {
748 debug("key_read: invalid curve");
749 return -1;
750 }
751#endif
752 *space = ' ';
753 if (type == KEY_UNSPEC) {
754 debug3("key_read: missing keytype");
755 return -1;
756 }
757 cp = space+1;
758 if (*cp == '\0') {
759 debug3("key_read: short string");
760 return -1;
761 }
762 if (ret->type == KEY_UNSPEC) {
763 ret->type = type;
764 } else if (ret->type != type) {
765 /* is a key, but different type */
766 debug3("key_read: type mismatch");
767 return -1;
768 }
769 len = 2*strlen(cp);
770 blob = xmalloc(len);
771 n = uudecode(cp, blob, len);
772 if (n < 0) {
773 error("key_read: uudecode %s failed", cp);
774 free(blob);
775 return -1;
776 }
777 k = key_from_blob(blob, (u_int)n);
778 free(blob);
779 if (k == NULL) {
780 error("key_read: key_from_blob %s failed", cp);
781 return -1;
782 }
783 if (k->type != type) {
784 error("key_read: type mismatch: encoding error");
785 key_free(k);
786 return -1;
787 }
788#ifdef OPENSSL_HAS_ECC
789 if (key_type_plain(type) == KEY_ECDSA &&
790 curve_nid != k->ecdsa_nid) {
791 error("key_read: type mismatch: EC curve mismatch");
792 key_free(k);
793 return -1;
794 }
795#endif
796/*XXXX*/
797 if (key_is_cert(ret)) {
798 if (!key_is_cert(k)) {
799 error("key_read: loaded key is not a cert");
800 key_free(k);
801 return -1;
802 }
803 if (ret->cert != NULL)
804 cert_free(ret->cert);
805 ret->cert = k->cert;
806 k->cert = NULL;
807 }
808 if (key_type_plain(ret->type) == KEY_RSA) {
809 if (ret->rsa != NULL)
810 RSA_free(ret->rsa);
811 ret->rsa = k->rsa;
812 k->rsa = NULL;
813#ifdef DEBUG_PK
814 RSA_print_fp(stderr, ret->rsa, 8);
815#endif
816 }
817 if (key_type_plain(ret->type) == KEY_DSA) {
818 if (ret->dsa != NULL)
819 DSA_free(ret->dsa);
820 ret->dsa = k->dsa;
821 k->dsa = NULL;
822#ifdef DEBUG_PK
823 DSA_print_fp(stderr, ret->dsa, 8);
824#endif
825 }
826#ifdef OPENSSL_HAS_ECC
827 if (key_type_plain(ret->type) == KEY_ECDSA) {
828 if (ret->ecdsa != NULL)
829 EC_KEY_free(ret->ecdsa);
830 ret->ecdsa = k->ecdsa;
831 ret->ecdsa_nid = k->ecdsa_nid;
832 k->ecdsa = NULL;
833 k->ecdsa_nid = -1;
834#ifdef DEBUG_PK
835 key_dump_ec_key(ret->ecdsa);
836#endif
837 }
838#endif
839 if (key_type_plain(ret->type) == KEY_ED25519) {
840 free(ret->ed25519_pk);
841 ret->ed25519_pk = k->ed25519_pk;
842 k->ed25519_pk = NULL;
843#ifdef DEBUG_PK
844 /* XXX */
845#endif
846 }
847 success = 1;
848/*XXXX*/
849 key_free(k);
850 if (success != 1)
851 break;
852 /* advance cp: skip whitespace and data */
853 while (*cp == ' ' || *cp == '\t')
854 cp++;
855 while (*cp != '\0' && *cp != ' ' && *cp != '\t')
856 cp++;
857 *cpp = cp;
858 break;
859 default:
860 fatal("key_read: bad key type: %d", ret->type);
861 break;
862 }
863 return success;
864} 64}
865 65
866int 66int
867key_write(const Key *key, FILE *f) 67key_write(const Key *key, FILE *f)
868{ 68{
869 int n, success = 0; 69 return sshkey_write(key, f) == 0 ? 1 : 0;
870 u_int len, bits = 0;
871 u_char *blob;
872 char *uu;
873
874 if (key_is_cert(key)) {
875 if (key->cert == NULL) {
876 error("%s: no cert data", __func__);
877 return 0;
878 }
879 if (buffer_len(&key->cert->certblob) == 0) {
880 error("%s: no signed certificate blob", __func__);
881 return 0;
882 }
883 }
884
885 switch (key->type) {
886 case KEY_RSA1:
887 if (key->rsa == NULL)
888 return 0;
889 /* size of modulus 'n' */
890 bits = BN_num_bits(key->rsa->n);
891 fprintf(f, "%u", bits);
892 if (write_bignum(f, key->rsa->e) &&
893 write_bignum(f, key->rsa->n))
894 return 1;
895 error("key_write: failed for RSA key");
896 return 0;
897 case KEY_DSA:
898 case KEY_DSA_CERT_V00:
899 case KEY_DSA_CERT:
900 if (key->dsa == NULL)
901 return 0;
902 break;
903#ifdef OPENSSL_HAS_ECC
904 case KEY_ECDSA:
905 case KEY_ECDSA_CERT:
906 if (key->ecdsa == NULL)
907 return 0;
908 break;
909#endif
910 case KEY_ED25519:
911 case KEY_ED25519_CERT:
912 if (key->ed25519_pk == NULL)
913 return 0;
914 break;
915 case KEY_RSA:
916 case KEY_RSA_CERT_V00:
917 case KEY_RSA_CERT:
918 if (key->rsa == NULL)
919 return 0;
920 break;
921 default:
922 return 0;
923 }
924
925 key_to_blob(key, &blob, &len);
926 uu = xmalloc(2*len);
927 n = uuencode(blob, len, uu, 2*len);
928 if (n > 0) {
929 fprintf(f, "%s %s", key_ssh_name(key), uu);
930 success = 1;
931 }
932 free(blob);
933 free(uu);
934
935 return success;
936}
937
938const char *
939key_cert_type(const Key *k)
940{
941 switch (k->cert->type) {
942 case SSH2_CERT_TYPE_USER:
943 return "user";
944 case SSH2_CERT_TYPE_HOST:
945 return "host";
946 default:
947 return "unknown";
948 }
949}
950
951struct keytype {
952 char *name;
953 char *shortname;
954 int type;
955 int nid;
956 int cert;
957};
958static const struct keytype keytypes[] = {
959 { NULL, "RSA1", KEY_RSA1, 0, 0 },
960 { "ssh-rsa", "RSA", KEY_RSA, 0, 0 },
961 { "ssh-dss", "DSA", KEY_DSA, 0, 0 },
962 { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0 },
963#ifdef OPENSSL_HAS_ECC
964 { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0 },
965 { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0 },
966# ifdef OPENSSL_HAS_NISTP521
967 { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0 },
968# endif
969#endif /* OPENSSL_HAS_ECC */
970 { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1 },
971 { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1 },
972#ifdef OPENSSL_HAS_ECC
973 { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT",
974 KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1 },
975 { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT",
976 KEY_ECDSA_CERT, NID_secp384r1, 1 },
977# ifdef OPENSSL_HAS_NISTP521
978 { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT",
979 KEY_ECDSA_CERT, NID_secp521r1, 1 },
980# endif
981#endif /* OPENSSL_HAS_ECC */
982 { "ssh-rsa-cert-v00@openssh.com", "RSA-CERT-V00",
983 KEY_RSA_CERT_V00, 0, 1 },
984 { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00",
985 KEY_DSA_CERT_V00, 0, 1 },
986 { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT",
987 KEY_ED25519_CERT, 0, 1 },
988 { NULL, NULL, -1, -1, 0 }
989};
990
991const char *
992key_type(const Key *k)
993{
994 const struct keytype *kt;
995
996 for (kt = keytypes; kt->type != -1; kt++) {
997 if (kt->type == k->type)
998 return kt->shortname;
999 }
1000 return "unknown";
1001}
1002
1003static const char *
1004key_ssh_name_from_type_nid(int type, int nid)
1005{
1006 const struct keytype *kt;
1007
1008 for (kt = keytypes; kt->type != -1; kt++) {
1009 if (kt->type == type && (kt->nid == 0 || kt->nid == nid))
1010 return kt->name;
1011 }
1012 return "ssh-unknown";
1013}
1014
1015const char *
1016key_ssh_name(const Key *k)
1017{
1018 return key_ssh_name_from_type_nid(k->type, k->ecdsa_nid);
1019}
1020
1021const char *
1022key_ssh_name_plain(const Key *k)
1023{
1024 return key_ssh_name_from_type_nid(key_type_plain(k->type),
1025 k->ecdsa_nid);
1026}
1027
1028int
1029key_type_from_name(char *name)
1030{
1031 const struct keytype *kt;
1032
1033 for (kt = keytypes; kt->type != -1; kt++) {
1034 /* Only allow shortname matches for plain key types */
1035 if ((kt->name != NULL && strcmp(name, kt->name) == 0) ||
1036 (!kt->cert && strcasecmp(kt->shortname, name) == 0))
1037 return kt->type;
1038 }
1039 debug2("key_type_from_name: unknown key type '%s'", name);
1040 return KEY_UNSPEC;
1041}
1042
1043int
1044key_ecdsa_nid_from_name(const char *name)
1045{
1046 const struct keytype *kt;
1047
1048 for (kt = keytypes; kt->type != -1; kt++) {
1049 if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT)
1050 continue;
1051 if (kt->name != NULL && strcmp(name, kt->name) == 0)
1052 return kt->nid;
1053 }
1054 debug2("%s: unknown/non-ECDSA key type '%s'", __func__, name);
1055 return -1;
1056}
1057
1058char *
1059key_alg_list(int certs_only, int plain_only)
1060{
1061 char *ret = NULL;
1062 size_t nlen, rlen = 0;
1063 const struct keytype *kt;
1064
1065 for (kt = keytypes; kt->type != -1; kt++) {
1066 if (kt->name == NULL)
1067 continue;
1068 if ((certs_only && !kt->cert) || (plain_only && kt->cert))
1069 continue;
1070 if (ret != NULL)
1071 ret[rlen++] = '\n';
1072 nlen = strlen(kt->name);
1073 ret = xrealloc(ret, 1, rlen + nlen + 2);
1074 memcpy(ret + rlen, kt->name, nlen + 1);
1075 rlen += nlen;
1076 }
1077 return ret;
1078}
1079
1080int
1081key_type_is_cert(int type)
1082{
1083 const struct keytype *kt;
1084
1085 for (kt = keytypes; kt->type != -1; kt++) {
1086 if (kt->type == type)
1087 return kt->cert;
1088 }
1089 return 0;
1090}
1091
1092static int
1093key_type_is_valid_ca(int type)
1094{
1095 switch (type) {
1096 case KEY_RSA:
1097 case KEY_DSA:
1098 case KEY_ECDSA:
1099 case KEY_ED25519:
1100 return 1;
1101 default:
1102 return 0;
1103 }
1104}
1105
1106u_int
1107key_size(const Key *k)
1108{
1109 switch (k->type) {
1110 case KEY_RSA1:
1111 case KEY_RSA:
1112 case KEY_RSA_CERT_V00:
1113 case KEY_RSA_CERT:
1114 return BN_num_bits(k->rsa->n);
1115 case KEY_DSA:
1116 case KEY_DSA_CERT_V00:
1117 case KEY_DSA_CERT:
1118 return BN_num_bits(k->dsa->p);
1119 case KEY_ED25519:
1120 return 256; /* XXX */
1121#ifdef OPENSSL_HAS_ECC
1122 case KEY_ECDSA:
1123 case KEY_ECDSA_CERT:
1124 return key_curve_nid_to_bits(k->ecdsa_nid);
1125#endif
1126 }
1127 return 0;
1128}
1129
1130static RSA *
1131rsa_generate_private_key(u_int bits)
1132{
1133 RSA *private = RSA_new();
1134 BIGNUM *f4 = BN_new();
1135
1136 if (private == NULL)
1137 fatal("%s: RSA_new failed", __func__);
1138 if (f4 == NULL)
1139 fatal("%s: BN_new failed", __func__);
1140 if (!BN_set_word(f4, RSA_F4))
1141 fatal("%s: BN_new failed", __func__);
1142 if (!RSA_generate_key_ex(private, bits, f4, NULL))
1143 fatal("%s: key generation failed.", __func__);
1144 BN_free(f4);
1145 return private;
1146}
1147
1148static DSA*
1149dsa_generate_private_key(u_int bits)
1150{
1151 DSA *private = DSA_new();
1152
1153 if (private == NULL)
1154 fatal("%s: DSA_new failed", __func__);
1155 if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
1156 NULL, NULL))
1157 fatal("%s: DSA_generate_parameters failed", __func__);
1158 if (!DSA_generate_key(private))
1159 fatal("%s: DSA_generate_key failed.", __func__);
1160 return private;
1161}
1162
1163int
1164key_ecdsa_bits_to_nid(int bits)
1165{
1166 switch (bits) {
1167#ifdef OPENSSL_HAS_ECC
1168 case 256:
1169 return NID_X9_62_prime256v1;
1170 case 384:
1171 return NID_secp384r1;
1172# ifdef OPENSSL_HAS_NISTP521
1173 case 521:
1174 return NID_secp521r1;
1175# endif
1176#endif
1177 default:
1178 return -1;
1179 }
1180}
1181
1182#ifdef OPENSSL_HAS_ECC
1183int
1184key_ecdsa_key_to_nid(EC_KEY *k)
1185{
1186 EC_GROUP *eg;
1187 int nids[] = {
1188 NID_X9_62_prime256v1,
1189 NID_secp384r1,
1190# ifdef OPENSSL_HAS_NISTP521
1191 NID_secp521r1,
1192# endif
1193 -1
1194 };
1195 int nid;
1196 u_int i;
1197 BN_CTX *bnctx;
1198 const EC_GROUP *g = EC_KEY_get0_group(k);
1199
1200 /*
1201 * The group may be stored in a ASN.1 encoded private key in one of two
1202 * ways: as a "named group", which is reconstituted by ASN.1 object ID
1203 * or explicit group parameters encoded into the key blob. Only the
1204 * "named group" case sets the group NID for us, but we can figure
1205 * it out for the other case by comparing against all the groups that
1206 * are supported.
1207 */
1208 if ((nid = EC_GROUP_get_curve_name(g)) > 0)
1209 return nid;
1210 if ((bnctx = BN_CTX_new()) == NULL)
1211 fatal("%s: BN_CTX_new() failed", __func__);
1212 for (i = 0; nids[i] != -1; i++) {
1213 if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL)
1214 fatal("%s: EC_GROUP_new_by_curve_name failed",
1215 __func__);
1216 if (EC_GROUP_cmp(g, eg, bnctx) == 0)
1217 break;
1218 EC_GROUP_free(eg);
1219 }
1220 BN_CTX_free(bnctx);
1221 debug3("%s: nid = %d", __func__, nids[i]);
1222 if (nids[i] != -1) {
1223 /* Use the group with the NID attached */
1224 EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
1225 if (EC_KEY_set_group(k, eg) != 1)
1226 fatal("%s: EC_KEY_set_group", __func__);
1227 }
1228 return nids[i];
1229}
1230
1231static EC_KEY*
1232ecdsa_generate_private_key(u_int bits, int *nid)
1233{
1234 EC_KEY *private;
1235
1236 if ((*nid = key_ecdsa_bits_to_nid(bits)) == -1)
1237 fatal("%s: invalid key length", __func__);
1238 if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL)
1239 fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
1240 if (EC_KEY_generate_key(private) != 1)
1241 fatal("%s: EC_KEY_generate_key failed", __func__);
1242 EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE);
1243 return private;
1244} 70}
1245#endif /* OPENSSL_HAS_ECC */
1246 71
1247Key * 72Key *
1248key_generate(int type, u_int bits) 73key_generate(int type, u_int bits)
1249{ 74{
1250 Key *k = key_new(KEY_UNSPEC); 75 int r;
1251 switch (type) { 76 Key *ret = NULL;
1252 case KEY_DSA: 77
1253 k->dsa = dsa_generate_private_key(bits); 78 if ((r = sshkey_generate(type, bits, &ret)) != 0)
1254 break; 79 fatal("%s: %s", __func__, ssh_err(r));
1255#ifdef OPENSSL_HAS_ECC 80 return ret;
1256 case KEY_ECDSA:
1257 k->ecdsa = ecdsa_generate_private_key(bits, &k->ecdsa_nid);
1258 break;
1259#endif
1260 case KEY_RSA:
1261 case KEY_RSA1:
1262 k->rsa = rsa_generate_private_key(bits);
1263 break;
1264 case KEY_ED25519:
1265 k->ed25519_pk = xmalloc(ED25519_PK_SZ);
1266 k->ed25519_sk = xmalloc(ED25519_SK_SZ);
1267 crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk);
1268 break;
1269 case KEY_RSA_CERT_V00:
1270 case KEY_DSA_CERT_V00:
1271 case KEY_RSA_CERT:
1272 case KEY_DSA_CERT:
1273 fatal("key_generate: cert keys cannot be generated directly");
1274 default:
1275 fatal("key_generate: unknown type %d", type);
1276 }
1277 k->type = type;
1278 return k;
1279} 81}
1280 82
1281void 83void
1282key_cert_copy(const Key *from_key, struct Key *to_key) 84key_cert_copy(const Key *from_key, Key *to_key)
1283{ 85{
1284 u_int i; 86 int r;
1285 const struct KeyCert *from;
1286 struct KeyCert *to;
1287
1288 if (to_key->cert != NULL) {
1289 cert_free(to_key->cert);
1290 to_key->cert = NULL;
1291 }
1292 87
1293 if ((from = from_key->cert) == NULL) 88 if ((r = sshkey_cert_copy(from_key, to_key)) != 0)
1294 return; 89 fatal("%s: %s", __func__, ssh_err(r));
1295
1296 to = to_key->cert = cert_new();
1297
1298 buffer_append(&to->certblob, buffer_ptr(&from->certblob),
1299 buffer_len(&from->certblob));
1300
1301 buffer_append(&to->critical,
1302 buffer_ptr(&from->critical), buffer_len(&from->critical));
1303 buffer_append(&to->extensions,
1304 buffer_ptr(&from->extensions), buffer_len(&from->extensions));
1305
1306 to->serial = from->serial;
1307 to->type = from->type;
1308 to->key_id = from->key_id == NULL ? NULL : xstrdup(from->key_id);
1309 to->valid_after = from->valid_after;
1310 to->valid_before = from->valid_before;
1311 to->signature_key = from->signature_key == NULL ?
1312 NULL : key_from_private(from->signature_key);
1313
1314 to->nprincipals = from->nprincipals;
1315 if (to->nprincipals > CERT_MAX_PRINCIPALS)
1316 fatal("%s: nprincipals (%u) > CERT_MAX_PRINCIPALS (%u)",
1317 __func__, to->nprincipals, CERT_MAX_PRINCIPALS);
1318 if (to->nprincipals > 0) {
1319 to->principals = xcalloc(from->nprincipals,
1320 sizeof(*to->principals));
1321 for (i = 0; i < to->nprincipals; i++)
1322 to->principals[i] = xstrdup(from->principals[i]);
1323 }
1324} 90}
1325 91
1326Key * 92Key *
1327key_from_private(const Key *k) 93key_from_private(const Key *k)
1328{ 94{
1329 Key *n = NULL; 95 int r;
1330 switch (k->type) { 96 Key *ret = NULL;
1331 case KEY_DSA:
1332 case KEY_DSA_CERT_V00:
1333 case KEY_DSA_CERT:
1334 n = key_new(k->type);
1335 if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) ||
1336 (BN_copy(n->dsa->q, k->dsa->q) == NULL) ||
1337 (BN_copy(n->dsa->g, k->dsa->g) == NULL) ||
1338 (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL))
1339 fatal("key_from_private: BN_copy failed");
1340 break;
1341#ifdef OPENSSL_HAS_ECC
1342 case KEY_ECDSA:
1343 case KEY_ECDSA_CERT:
1344 n = key_new(k->type);
1345 n->ecdsa_nid = k->ecdsa_nid;
1346 if ((n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid)) == NULL)
1347 fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
1348 if (EC_KEY_set_public_key(n->ecdsa,
1349 EC_KEY_get0_public_key(k->ecdsa)) != 1)
1350 fatal("%s: EC_KEY_set_public_key failed", __func__);
1351 break;
1352#endif
1353 case KEY_RSA:
1354 case KEY_RSA1:
1355 case KEY_RSA_CERT_V00:
1356 case KEY_RSA_CERT:
1357 n = key_new(k->type);
1358 if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
1359 (BN_copy(n->rsa->e, k->rsa->e) == NULL))
1360 fatal("key_from_private: BN_copy failed");
1361 break;
1362 case KEY_ED25519:
1363 case KEY_ED25519_CERT:
1364 n = key_new(k->type);
1365 if (k->ed25519_pk != NULL) {
1366 n->ed25519_pk = xmalloc(ED25519_PK_SZ);
1367 memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
1368 }
1369 break;
1370 default:
1371 fatal("key_from_private: unknown type %d", k->type);
1372 break;
1373 }
1374 if (key_is_cert(k))
1375 key_cert_copy(k, n);
1376 return n;
1377}
1378
1379int
1380key_names_valid2(const char *names)
1381{
1382 char *s, *cp, *p;
1383
1384 if (names == NULL || strcmp(names, "") == 0)
1385 return 0;
1386 s = cp = xstrdup(names);
1387 for ((p = strsep(&cp, ",")); p && *p != '\0';
1388 (p = strsep(&cp, ","))) {
1389 switch (key_type_from_name(p)) {
1390 case KEY_RSA1:
1391 case KEY_UNSPEC:
1392 free(s);
1393 return 0;
1394 }
1395 }
1396 debug3("key names ok: [%s]", names);
1397 free(s);
1398 return 1;
1399}
1400
1401static int
1402cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen)
1403{
1404 u_char *principals, *critical, *exts, *sig_key, *sig;
1405 u_int signed_len, plen, clen, sklen, slen, kidlen, elen;
1406 Buffer tmp;
1407 char *principal;
1408 int ret = -1;
1409 int v00 = key->type == KEY_DSA_CERT_V00 ||
1410 key->type == KEY_RSA_CERT_V00;
1411
1412 buffer_init(&tmp);
1413
1414 /* Copy the entire key blob for verification and later serialisation */
1415 buffer_append(&key->cert->certblob, blob, blen);
1416
1417 elen = 0; /* Not touched for v00 certs */
1418 principals = exts = critical = sig_key = sig = NULL;
1419 if ((!v00 && buffer_get_int64_ret(&key->cert->serial, b) != 0) ||
1420 buffer_get_int_ret(&key->cert->type, b) != 0 ||
1421 (key->cert->key_id = buffer_get_cstring_ret(b, &kidlen)) == NULL ||
1422 (principals = buffer_get_string_ret(b, &plen)) == NULL ||
1423 buffer_get_int64_ret(&key->cert->valid_after, b) != 0 ||
1424 buffer_get_int64_ret(&key->cert->valid_before, b) != 0 ||
1425 (critical = buffer_get_string_ret(b, &clen)) == NULL ||
1426 (!v00 && (exts = buffer_get_string_ret(b, &elen)) == NULL) ||
1427 (v00 && buffer_get_string_ptr_ret(b, NULL) == NULL) || /* nonce */
1428 buffer_get_string_ptr_ret(b, NULL) == NULL || /* reserved */
1429 (sig_key = buffer_get_string_ret(b, &sklen)) == NULL) {
1430 error("%s: parse error", __func__);
1431 goto out;
1432 }
1433
1434 /* Signature is left in the buffer so we can calculate this length */
1435 signed_len = buffer_len(&key->cert->certblob) - buffer_len(b);
1436
1437 if ((sig = buffer_get_string_ret(b, &slen)) == NULL) {
1438 error("%s: parse error", __func__);
1439 goto out;
1440 }
1441
1442 if (key->cert->type != SSH2_CERT_TYPE_USER &&
1443 key->cert->type != SSH2_CERT_TYPE_HOST) {
1444 error("Unknown certificate type %u", key->cert->type);
1445 goto out;
1446 }
1447 97
1448 buffer_append(&tmp, principals, plen); 98 if ((r = sshkey_from_private(k, &ret)) != 0)
1449 while (buffer_len(&tmp) > 0) { 99 fatal("%s: %s", __func__, ssh_err(r));
1450 if (key->cert->nprincipals >= CERT_MAX_PRINCIPALS) {
1451 error("%s: Too many principals", __func__);
1452 goto out;
1453 }
1454 if ((principal = buffer_get_cstring_ret(&tmp, &plen)) == NULL) {
1455 error("%s: Principals data invalid", __func__);
1456 goto out;
1457 }
1458 key->cert->principals = xrealloc(key->cert->principals,
1459 key->cert->nprincipals + 1, sizeof(*key->cert->principals));
1460 key->cert->principals[key->cert->nprincipals++] = principal;
1461 }
1462
1463 buffer_clear(&tmp);
1464
1465 buffer_append(&key->cert->critical, critical, clen);
1466 buffer_append(&tmp, critical, clen);
1467 /* validate structure */
1468 while (buffer_len(&tmp) != 0) {
1469 if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL ||
1470 buffer_get_string_ptr_ret(&tmp, NULL) == NULL) {
1471 error("%s: critical option data invalid", __func__);
1472 goto out;
1473 }
1474 }
1475 buffer_clear(&tmp);
1476
1477 buffer_append(&key->cert->extensions, exts, elen);
1478 buffer_append(&tmp, exts, elen);
1479 /* validate structure */
1480 while (buffer_len(&tmp) != 0) {
1481 if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL ||
1482 buffer_get_string_ptr_ret(&tmp, NULL) == NULL) {
1483 error("%s: extension data invalid", __func__);
1484 goto out;
1485 }
1486 }
1487 buffer_clear(&tmp);
1488
1489 if ((key->cert->signature_key = key_from_blob2(sig_key, sklen, 0))
1490 == NULL) {
1491 error("%s: Signature key invalid", __func__);
1492 goto out;
1493 }
1494 if (!key_type_is_valid_ca(key->cert->signature_key->type)) {
1495 error("%s: Invalid signature key type %s (%d)", __func__,
1496 key_type(key->cert->signature_key),
1497 key->cert->signature_key->type);
1498 goto out;
1499 }
1500
1501 switch (key_verify(key->cert->signature_key, sig, slen,
1502 buffer_ptr(&key->cert->certblob), signed_len)) {
1503 case 1:
1504 ret = 0;
1505 break; /* Good signature */
1506 case 0:
1507 error("%s: Invalid signature on certificate", __func__);
1508 goto out;
1509 case -1:
1510 error("%s: Certificate signature verification failed",
1511 __func__);
1512 goto out;
1513 }
1514
1515 out:
1516 buffer_free(&tmp);
1517 free(principals);
1518 free(critical);
1519 free(exts);
1520 free(sig_key);
1521 free(sig);
1522 return ret; 100 return ret;
1523} 101}
1524 102
1525static Key * 103static void
1526key_from_blob2(const u_char *blob, u_int blen, int allow_cert) 104fatal_on_fatal_errors(int r, const char *func, int extra_fatal)
1527{ 105{
1528 Buffer b; 106 if (r == SSH_ERR_INTERNAL_ERROR ||
1529 int rlen, type; 107 r == SSH_ERR_ALLOC_FAIL ||
1530 u_int len; 108 (extra_fatal != 0 && r == extra_fatal))
1531 char *ktype = NULL, *curve = NULL; 109 fatal("%s: %s", func, ssh_err(r));
1532 u_char *pk = NULL;
1533 Key *key = NULL;
1534#ifdef OPENSSL_HAS_ECC
1535 EC_POINT *q = NULL;
1536 int nid = -1;
1537#endif
1538
1539#ifdef DEBUG_PK
1540 dump_base64(stderr, blob, blen);
1541#endif
1542 buffer_init(&b);
1543 buffer_append(&b, blob, blen);
1544 if ((ktype = buffer_get_cstring_ret(&b, NULL)) == NULL) {
1545 error("key_from_blob: can't read key type");
1546 goto out;
1547 }
1548
1549 type = key_type_from_name(ktype);
1550#ifdef OPENSSL_HAS_ECC
1551 if (key_type_plain(type) == KEY_ECDSA)
1552 nid = key_ecdsa_nid_from_name(ktype);
1553#endif
1554 if (!allow_cert && key_type_is_cert(type)) {
1555 error("key_from_blob: certificate not allowed in this context");
1556 goto out;
1557 }
1558 switch (type) {
1559 case KEY_RSA_CERT:
1560 (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
1561 /* FALLTHROUGH */
1562 case KEY_RSA:
1563 case KEY_RSA_CERT_V00:
1564 key = key_new(type);
1565 if (buffer_get_bignum2_ret(&b, key->rsa->e) == -1 ||
1566 buffer_get_bignum2_ret(&b, key->rsa->n) == -1) {
1567 error("key_from_blob: can't read rsa key");
1568 badkey:
1569 key_free(key);
1570 key = NULL;
1571 goto out;
1572 }
1573#ifdef DEBUG_PK
1574 RSA_print_fp(stderr, key->rsa, 8);
1575#endif
1576 break;
1577 case KEY_DSA_CERT:
1578 (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
1579 /* FALLTHROUGH */
1580 case KEY_DSA:
1581 case KEY_DSA_CERT_V00:
1582 key = key_new(type);
1583 if (buffer_get_bignum2_ret(&b, key->dsa->p) == -1 ||
1584 buffer_get_bignum2_ret(&b, key->dsa->q) == -1 ||
1585 buffer_get_bignum2_ret(&b, key->dsa->g) == -1 ||
1586 buffer_get_bignum2_ret(&b, key->dsa->pub_key) == -1) {
1587 error("key_from_blob: can't read dsa key");
1588 goto badkey;
1589 }
1590#ifdef DEBUG_PK
1591 DSA_print_fp(stderr, key->dsa, 8);
1592#endif
1593 break;
1594#ifdef OPENSSL_HAS_ECC
1595 case KEY_ECDSA_CERT:
1596 (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
1597 /* FALLTHROUGH */
1598 case KEY_ECDSA:
1599 key = key_new(type);
1600 key->ecdsa_nid = nid;
1601 if ((curve = buffer_get_string_ret(&b, NULL)) == NULL) {
1602 error("key_from_blob: can't read ecdsa curve");
1603 goto badkey;
1604 }
1605 if (key->ecdsa_nid != key_curve_name_to_nid(curve)) {
1606 error("key_from_blob: ecdsa curve doesn't match type");
1607 goto badkey;
1608 }
1609 if (key->ecdsa != NULL)
1610 EC_KEY_free(key->ecdsa);
1611 if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid))
1612 == NULL)
1613 fatal("key_from_blob: EC_KEY_new_by_curve_name failed");
1614 if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL)
1615 fatal("key_from_blob: EC_POINT_new failed");
1616 if (buffer_get_ecpoint_ret(&b, EC_KEY_get0_group(key->ecdsa),
1617 q) == -1) {
1618 error("key_from_blob: can't read ecdsa key point");
1619 goto badkey;
1620 }
1621 if (key_ec_validate_public(EC_KEY_get0_group(key->ecdsa),
1622 q) != 0)
1623 goto badkey;
1624 if (EC_KEY_set_public_key(key->ecdsa, q) != 1)
1625 fatal("key_from_blob: EC_KEY_set_public_key failed");
1626#ifdef DEBUG_PK
1627 key_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
1628#endif
1629 break;
1630#endif /* OPENSSL_HAS_ECC */
1631 case KEY_ED25519_CERT:
1632 (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
1633 /* FALLTHROUGH */
1634 case KEY_ED25519:
1635 if ((pk = buffer_get_string_ret(&b, &len)) == NULL) {
1636 error("key_from_blob: can't read ed25519 key");
1637 goto badkey;
1638 }
1639 if (len != ED25519_PK_SZ) {
1640 error("key_from_blob: ed25519 len %d != %d",
1641 len, ED25519_PK_SZ);
1642 goto badkey;
1643 }
1644 key = key_new(type);
1645 key->ed25519_pk = pk;
1646 pk = NULL;
1647 break;
1648 case KEY_UNSPEC:
1649 key = key_new(type);
1650 break;
1651 default:
1652 error("key_from_blob: cannot handle type %s", ktype);
1653 goto out;
1654 }
1655 if (key_is_cert(key) && cert_parse(&b, key, blob, blen) == -1) {
1656 error("key_from_blob: can't parse cert data");
1657 goto badkey;
1658 }
1659 rlen = buffer_len(&b);
1660 if (key != NULL && rlen != 0)
1661 error("key_from_blob: remaining bytes in key blob %d", rlen);
1662 out:
1663 free(ktype);
1664 free(curve);
1665 free(pk);
1666#ifdef OPENSSL_HAS_ECC
1667 if (q != NULL)
1668 EC_POINT_free(q);
1669#endif
1670 buffer_free(&b);
1671 return key;
1672} 110}
1673 111
1674Key * 112Key *
1675key_from_blob(const u_char *blob, u_int blen) 113key_from_blob(const u_char *blob, u_int blen)
1676{ 114{
1677 return key_from_blob2(blob, blen, 1); 115 int r;
116 Key *ret = NULL;
117
118 if ((r = sshkey_from_blob(blob, blen, &ret)) != 0) {
119 fatal_on_fatal_errors(r, __func__, 0);
120 error("%s: %s", __func__, ssh_err(r));
121 return NULL;
122 }
123 return ret;
1678} 124}
1679 125
1680static int 126int
1681to_blob(const Key *key, u_char **blobp, u_int *lenp, int force_plain) 127key_to_blob(const Key *key, u_char **blobp, u_int *lenp)
1682{ 128{
1683 Buffer b; 129 u_char *blob;
1684 int len, type; 130 size_t blen;
131 int r;
1685 132
1686 if (blobp != NULL) 133 if (blobp != NULL)
1687 *blobp = NULL; 134 *blobp = NULL;
1688 if (lenp != NULL) 135 if (lenp != NULL)
1689 *lenp = 0; 136 *lenp = 0;
1690 if (key == NULL) { 137 if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
1691 error("key_to_blob: key == NULL"); 138 fatal_on_fatal_errors(r, __func__, 0);
1692 return 0; 139 error("%s: %s", __func__, ssh_err(r));
1693 }
1694 buffer_init(&b);
1695 type = force_plain ? key_type_plain(key->type) : key->type;
1696 switch (type) {
1697 case KEY_DSA_CERT_V00:
1698 case KEY_RSA_CERT_V00:
1699 case KEY_DSA_CERT:
1700 case KEY_ECDSA_CERT:
1701 case KEY_RSA_CERT:
1702 case KEY_ED25519_CERT:
1703 /* Use the existing blob */
1704 buffer_append(&b, buffer_ptr(&key->cert->certblob),
1705 buffer_len(&key->cert->certblob));
1706 break;
1707 case KEY_DSA:
1708 buffer_put_cstring(&b,
1709 key_ssh_name_from_type_nid(type, key->ecdsa_nid));
1710 buffer_put_bignum2(&b, key->dsa->p);
1711 buffer_put_bignum2(&b, key->dsa->q);
1712 buffer_put_bignum2(&b, key->dsa->g);
1713 buffer_put_bignum2(&b, key->dsa->pub_key);
1714 break;
1715#ifdef OPENSSL_HAS_ECC
1716 case KEY_ECDSA:
1717 buffer_put_cstring(&b,
1718 key_ssh_name_from_type_nid(type, key->ecdsa_nid));
1719 buffer_put_cstring(&b, key_curve_nid_to_name(key->ecdsa_nid));
1720 buffer_put_ecpoint(&b, EC_KEY_get0_group(key->ecdsa),
1721 EC_KEY_get0_public_key(key->ecdsa));
1722 break;
1723#endif
1724 case KEY_RSA:
1725 buffer_put_cstring(&b,
1726 key_ssh_name_from_type_nid(type, key->ecdsa_nid));
1727 buffer_put_bignum2(&b, key->rsa->e);
1728 buffer_put_bignum2(&b, key->rsa->n);
1729 break;
1730 case KEY_ED25519:
1731 buffer_put_cstring(&b,
1732 key_ssh_name_from_type_nid(type, key->ecdsa_nid));
1733 buffer_put_string(&b, key->ed25519_pk, ED25519_PK_SZ);
1734 break;
1735 default:
1736 error("key_to_blob: unsupported key type %d", key->type);
1737 buffer_free(&b);
1738 return 0; 140 return 0;
1739 } 141 }
1740 len = buffer_len(&b); 142 if (blen > INT_MAX)
143 fatal("%s: giant len %zu", __func__, blen);
144 if (blobp != NULL)
145 *blobp = blob;
1741 if (lenp != NULL) 146 if (lenp != NULL)
1742 *lenp = len; 147 *lenp = blen;
1743 if (blobp != NULL) { 148 return blen;
1744 *blobp = xmalloc(len);
1745 memcpy(*blobp, buffer_ptr(&b), len);
1746 }
1747 explicit_bzero(buffer_ptr(&b), len);
1748 buffer_free(&b);
1749 return len;
1750}
1751
1752int
1753key_to_blob(const Key *key, u_char **blobp, u_int *lenp)
1754{
1755 return to_blob(key, blobp, lenp, 0);
1756} 149}
1757 150
1758int 151int
1759key_sign( 152key_sign(const Key *key, u_char **sigp, u_int *lenp,
1760 const Key *key,
1761 u_char **sigp, u_int *lenp,
1762 const u_char *data, u_int datalen) 153 const u_char *data, u_int datalen)
1763{ 154{
1764 switch (key->type) { 155 int r;
1765 case KEY_DSA_CERT_V00: 156 u_char *sig;
1766 case KEY_DSA_CERT: 157 size_t siglen;
1767 case KEY_DSA: 158
1768 return ssh_dss_sign(key, sigp, lenp, data, datalen); 159 if (sigp != NULL)
1769#ifdef OPENSSL_HAS_ECC 160 *sigp = NULL;
1770 case KEY_ECDSA_CERT: 161 if (lenp != NULL)
1771 case KEY_ECDSA: 162 *lenp = 0;
1772 return ssh_ecdsa_sign(key, sigp, lenp, data, datalen); 163 if ((r = sshkey_sign(key, &sig, &siglen,
1773#endif 164 data, datalen, datafellows)) != 0) {
1774 case KEY_RSA_CERT_V00: 165 fatal_on_fatal_errors(r, __func__, 0);
1775 case KEY_RSA_CERT: 166 error("%s: %s", __func__, ssh_err(r));
1776 case KEY_RSA:
1777 return ssh_rsa_sign(key, sigp, lenp, data, datalen);
1778 case KEY_ED25519:
1779 case KEY_ED25519_CERT:
1780 return ssh_ed25519_sign(key, sigp, lenp, data, datalen);
1781 default:
1782 error("key_sign: invalid key type %d", key->type);
1783 return -1; 167 return -1;
1784 } 168 }
169 if (siglen > INT_MAX)
170 fatal("%s: giant len %zu", __func__, siglen);
171 if (sigp != NULL)
172 *sigp = sig;
173 if (lenp != NULL)
174 *lenp = siglen;
175 return 0;
1785} 176}
1786 177
1787/*
1788 * key_verify returns 1 for a correct signature, 0 for an incorrect signature
1789 * and -1 on error.
1790 */
1791int 178int
1792key_verify( 179key_verify(const Key *key, const u_char *signature, u_int signaturelen,
1793 const Key *key,
1794 const u_char *signature, u_int signaturelen,
1795 const u_char *data, u_int datalen) 180 const u_char *data, u_int datalen)
1796{ 181{
1797 if (signaturelen == 0) 182 int r;
1798 return -1;
1799 183
1800 switch (key->type) { 184 if ((r = sshkey_verify(key, signature, signaturelen,
1801 case KEY_DSA_CERT_V00: 185 data, datalen, datafellows)) != 0) {
1802 case KEY_DSA_CERT: 186 fatal_on_fatal_errors(r, __func__, 0);
1803 case KEY_DSA: 187 error("%s: %s", __func__, ssh_err(r));
1804 return ssh_dss_verify(key, signature, signaturelen, data, datalen); 188 return r == SSH_ERR_SIGNATURE_INVALID ? 0 : -1;
1805#ifdef OPENSSL_HAS_ECC
1806 case KEY_ECDSA_CERT:
1807 case KEY_ECDSA:
1808 return ssh_ecdsa_verify(key, signature, signaturelen, data, datalen);
1809#endif
1810 case KEY_RSA_CERT_V00:
1811 case KEY_RSA_CERT:
1812 case KEY_RSA:
1813 return ssh_rsa_verify(key, signature, signaturelen, data, datalen);
1814 case KEY_ED25519:
1815 case KEY_ED25519_CERT:
1816 return ssh_ed25519_verify(key, signature, signaturelen, data, datalen);
1817 default:
1818 error("key_verify: invalid key type %d", key->type);
1819 return -1;
1820 } 189 }
190 return 1;
1821} 191}
1822 192
1823/* Converts a private to a public key */
1824Key * 193Key *
1825key_demote(const Key *k) 194key_demote(const Key *k)
1826{ 195{
1827 Key *pk; 196 int r;
1828 197 Key *ret = NULL;
1829 pk = xcalloc(1, sizeof(*pk));
1830 pk->type = k->type;
1831 pk->flags = k->flags;
1832 pk->ecdsa_nid = k->ecdsa_nid;
1833 pk->dsa = NULL;
1834 pk->ecdsa = NULL;
1835 pk->rsa = NULL;
1836 pk->ed25519_pk = NULL;
1837 pk->ed25519_sk = NULL;
1838
1839 switch (k->type) {
1840 case KEY_RSA_CERT_V00:
1841 case KEY_RSA_CERT:
1842 key_cert_copy(k, pk);
1843 /* FALLTHROUGH */
1844 case KEY_RSA1:
1845 case KEY_RSA:
1846 if ((pk->rsa = RSA_new()) == NULL)
1847 fatal("key_demote: RSA_new failed");
1848 if ((pk->rsa->e = BN_dup(k->rsa->e)) == NULL)
1849 fatal("key_demote: BN_dup failed");
1850 if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL)
1851 fatal("key_demote: BN_dup failed");
1852 break;
1853 case KEY_DSA_CERT_V00:
1854 case KEY_DSA_CERT:
1855 key_cert_copy(k, pk);
1856 /* FALLTHROUGH */
1857 case KEY_DSA:
1858 if ((pk->dsa = DSA_new()) == NULL)
1859 fatal("key_demote: DSA_new failed");
1860 if ((pk->dsa->p = BN_dup(k->dsa->p)) == NULL)
1861 fatal("key_demote: BN_dup failed");
1862 if ((pk->dsa->q = BN_dup(k->dsa->q)) == NULL)
1863 fatal("key_demote: BN_dup failed");
1864 if ((pk->dsa->g = BN_dup(k->dsa->g)) == NULL)
1865 fatal("key_demote: BN_dup failed");
1866 if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL)
1867 fatal("key_demote: BN_dup failed");
1868 break;
1869#ifdef OPENSSL_HAS_ECC
1870 case KEY_ECDSA_CERT:
1871 key_cert_copy(k, pk);
1872 /* FALLTHROUGH */
1873 case KEY_ECDSA:
1874 if ((pk->ecdsa = EC_KEY_new_by_curve_name(pk->ecdsa_nid)) == NULL)
1875 fatal("key_demote: EC_KEY_new_by_curve_name failed");
1876 if (EC_KEY_set_public_key(pk->ecdsa,
1877 EC_KEY_get0_public_key(k->ecdsa)) != 1)
1878 fatal("key_demote: EC_KEY_set_public_key failed");
1879 break;
1880#endif
1881 case KEY_ED25519_CERT:
1882 key_cert_copy(k, pk);
1883 /* FALLTHROUGH */
1884 case KEY_ED25519:
1885 if (k->ed25519_pk != NULL) {
1886 pk->ed25519_pk = xmalloc(ED25519_PK_SZ);
1887 memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
1888 }
1889 break;
1890 default:
1891 fatal("key_demote: bad key type %d", k->type);
1892 break;
1893 }
1894
1895 return (pk);
1896}
1897 198
1898int 199 if ((r = sshkey_demote(k, &ret)) != 0)
1899key_is_cert(const Key *k) 200 fatal("%s: %s", __func__, ssh_err(r));
1900{ 201 return ret;
1901 if (k == NULL)
1902 return 0;
1903 return key_type_is_cert(k->type);
1904}
1905
1906/* Return the cert-less equivalent to a certified key type */
1907int
1908key_type_plain(int type)
1909{
1910 switch (type) {
1911 case KEY_RSA_CERT_V00:
1912 case KEY_RSA_CERT:
1913 return KEY_RSA;
1914 case KEY_DSA_CERT_V00:
1915 case KEY_DSA_CERT:
1916 return KEY_DSA;
1917 case KEY_ECDSA_CERT:
1918 return KEY_ECDSA;
1919 case KEY_ED25519_CERT:
1920 return KEY_ED25519;
1921 default:
1922 return type;
1923 }
1924} 202}
1925 203
1926/* Convert a plain key to their _CERT equivalent */
1927int 204int
1928key_to_certified(Key *k, int legacy) 205key_to_certified(Key *k, int legacy)
1929{ 206{
1930 switch (k->type) { 207 int r;
1931 case KEY_RSA: 208
1932 k->cert = cert_new(); 209 if ((r = sshkey_to_certified(k, legacy)) != 0) {
1933 k->type = legacy ? KEY_RSA_CERT_V00 : KEY_RSA_CERT; 210 fatal_on_fatal_errors(r, __func__, 0);
1934 return 0; 211 error("%s: %s", __func__, ssh_err(r));
1935 case KEY_DSA:
1936 k->cert = cert_new();
1937 k->type = legacy ? KEY_DSA_CERT_V00 : KEY_DSA_CERT;
1938 return 0;
1939 case KEY_ECDSA:
1940 if (legacy)
1941 fatal("%s: legacy ECDSA certificates are not supported",
1942 __func__);
1943 k->cert = cert_new();
1944 k->type = KEY_ECDSA_CERT;
1945 return 0;
1946 case KEY_ED25519:
1947 if (legacy)
1948 fatal("%s: legacy ED25519 certificates are not "
1949 "supported", __func__);
1950 k->cert = cert_new();
1951 k->type = KEY_ED25519_CERT;
1952 return 0;
1953 default:
1954 error("%s: key has incorrect type %s", __func__, key_type(k));
1955 return -1; 212 return -1;
1956 } 213 }
214 return 0;
1957} 215}
1958 216
1959/* Convert a certificate to its raw key equivalent */
1960int 217int
1961key_drop_cert(Key *k) 218key_drop_cert(Key *k)
1962{ 219{
1963 if (!key_type_is_cert(k->type)) { 220 int r;
1964 error("%s: key has incorrect type %s", __func__, key_type(k)); 221
222 if ((r = sshkey_drop_cert(k)) != 0) {
223 fatal_on_fatal_errors(r, __func__, 0);
224 error("%s: %s", __func__, ssh_err(r));
1965 return -1; 225 return -1;
1966 } 226 }
1967 cert_free(k->cert);
1968 k->cert = NULL;
1969 k->type = key_type_plain(k->type);
1970 return 0; 227 return 0;
1971} 228}
1972 229
1973/* Sign a certified key, (re-)generating the signed certblob. */
1974int 230int
1975key_certify(Key *k, Key *ca) 231key_certify(Key *k, Key *ca)
1976{ 232{
1977 Buffer principals; 233 int r;
1978 u_char *ca_blob, *sig_blob, nonce[32];
1979 u_int i, ca_len, sig_len;
1980
1981 if (k->cert == NULL) {
1982 error("%s: key lacks cert info", __func__);
1983 return -1;
1984 }
1985
1986 if (!key_is_cert(k)) {
1987 error("%s: certificate has unknown type %d", __func__,
1988 k->cert->type);
1989 return -1;
1990 }
1991
1992 if (!key_type_is_valid_ca(ca->type)) {
1993 error("%s: CA key has unsupported type %s", __func__,
1994 key_type(ca));
1995 return -1;
1996 }
1997
1998 key_to_blob(ca, &ca_blob, &ca_len);
1999
2000 buffer_clear(&k->cert->certblob);
2001 buffer_put_cstring(&k->cert->certblob, key_ssh_name(k));
2002
2003 /* -v01 certs put nonce first */
2004 arc4random_buf(&nonce, sizeof(nonce));
2005 if (!key_cert_is_legacy(k))
2006 buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
2007
2008 /* XXX this substantially duplicates to_blob(); refactor */
2009 switch (k->type) {
2010 case KEY_DSA_CERT_V00:
2011 case KEY_DSA_CERT:
2012 buffer_put_bignum2(&k->cert->certblob, k->dsa->p);
2013 buffer_put_bignum2(&k->cert->certblob, k->dsa->q);
2014 buffer_put_bignum2(&k->cert->certblob, k->dsa->g);
2015 buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key);
2016 break;
2017#ifdef OPENSSL_HAS_ECC
2018 case KEY_ECDSA_CERT:
2019 buffer_put_cstring(&k->cert->certblob,
2020 key_curve_nid_to_name(k->ecdsa_nid));
2021 buffer_put_ecpoint(&k->cert->certblob,
2022 EC_KEY_get0_group(k->ecdsa),
2023 EC_KEY_get0_public_key(k->ecdsa));
2024 break;
2025#endif
2026 case KEY_RSA_CERT_V00:
2027 case KEY_RSA_CERT:
2028 buffer_put_bignum2(&k->cert->certblob, k->rsa->e);
2029 buffer_put_bignum2(&k->cert->certblob, k->rsa->n);
2030 break;
2031 case KEY_ED25519_CERT:
2032 buffer_put_string(&k->cert->certblob,
2033 k->ed25519_pk, ED25519_PK_SZ);
2034 break;
2035 default:
2036 error("%s: key has incorrect type %s", __func__, key_type(k));
2037 buffer_clear(&k->cert->certblob);
2038 free(ca_blob);
2039 return -1;
2040 }
2041
2042 /* -v01 certs have a serial number next */
2043 if (!key_cert_is_legacy(k))
2044 buffer_put_int64(&k->cert->certblob, k->cert->serial);
2045
2046 buffer_put_int(&k->cert->certblob, k->cert->type);
2047 buffer_put_cstring(&k->cert->certblob, k->cert->key_id);
2048
2049 buffer_init(&principals);
2050 for (i = 0; i < k->cert->nprincipals; i++)
2051 buffer_put_cstring(&principals, k->cert->principals[i]);
2052 buffer_put_string(&k->cert->certblob, buffer_ptr(&principals),
2053 buffer_len(&principals));
2054 buffer_free(&principals);
2055
2056 buffer_put_int64(&k->cert->certblob, k->cert->valid_after);
2057 buffer_put_int64(&k->cert->certblob, k->cert->valid_before);
2058 buffer_put_string(&k->cert->certblob,
2059 buffer_ptr(&k->cert->critical), buffer_len(&k->cert->critical));
2060
2061 /* -v01 certs have non-critical options here */
2062 if (!key_cert_is_legacy(k)) {
2063 buffer_put_string(&k->cert->certblob,
2064 buffer_ptr(&k->cert->extensions),
2065 buffer_len(&k->cert->extensions));
2066 }
2067
2068 /* -v00 certs put the nonce at the end */
2069 if (key_cert_is_legacy(k))
2070 buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
2071
2072 buffer_put_string(&k->cert->certblob, NULL, 0); /* reserved */
2073 buffer_put_string(&k->cert->certblob, ca_blob, ca_len);
2074 free(ca_blob);
2075 234
2076 /* Sign the whole mess */ 235 if ((r = sshkey_certify(k, ca)) != 0) {
2077 if (key_sign(ca, &sig_blob, &sig_len, buffer_ptr(&k->cert->certblob), 236 fatal_on_fatal_errors(r, __func__, 0);
2078 buffer_len(&k->cert->certblob)) != 0) { 237 error("%s: %s", __func__, ssh_err(r));
2079 error("%s: signature operation failed", __func__);
2080 buffer_clear(&k->cert->certblob);
2081 return -1; 238 return -1;
2082 } 239 }
2083 /* Append signature and we are done */
2084 buffer_put_string(&k->cert->certblob, sig_blob, sig_len);
2085 free(sig_blob);
2086
2087 return 0; 240 return 0;
2088} 241}
2089 242
@@ -2091,535 +244,236 @@ int
2091key_cert_check_authority(const Key *k, int want_host, int require_principal, 244key_cert_check_authority(const Key *k, int want_host, int require_principal,
2092 const char *name, const char **reason) 245 const char *name, const char **reason)
2093{ 246{
2094 u_int i, principal_matches; 247 int r;
2095 time_t now = time(NULL); 248
2096 249 if ((r = sshkey_cert_check_authority(k, want_host, require_principal,
2097 if (want_host) { 250 name, reason)) != 0) {
2098 if (k->cert->type != SSH2_CERT_TYPE_HOST) { 251 fatal_on_fatal_errors(r, __func__, 0);
2099 *reason = "Certificate invalid: not a host certificate"; 252 error("%s: %s", __func__, ssh_err(r));
2100 return -1;
2101 }
2102 } else {
2103 if (k->cert->type != SSH2_CERT_TYPE_USER) {
2104 *reason = "Certificate invalid: not a user certificate";
2105 return -1;
2106 }
2107 }
2108 if (now < 0) {
2109 error("%s: system clock lies before epoch", __func__);
2110 *reason = "Certificate invalid: not yet valid";
2111 return -1;
2112 }
2113 if ((u_int64_t)now < k->cert->valid_after) {
2114 *reason = "Certificate invalid: not yet valid";
2115 return -1;
2116 }
2117 if ((u_int64_t)now >= k->cert->valid_before) {
2118 *reason = "Certificate invalid: expired";
2119 return -1; 253 return -1;
2120 } 254 }
2121 if (k->cert->nprincipals == 0) {
2122 if (require_principal) {
2123 *reason = "Certificate lacks principal list";
2124 return -1;
2125 }
2126 } else if (name != NULL) {
2127 principal_matches = 0;
2128 for (i = 0; i < k->cert->nprincipals; i++) {
2129 if (strcmp(name, k->cert->principals[i]) == 0) {
2130 principal_matches = 1;
2131 break;
2132 }
2133 }
2134 if (!principal_matches) {
2135 *reason = "Certificate invalid: name is not a listed "
2136 "principal";
2137 return -1;
2138 }
2139 }
2140 return 0; 255 return 0;
2141} 256}
2142 257
258#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
2143int 259int
2144key_cert_is_legacy(const Key *k) 260key_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
2145{ 261{
2146 switch (k->type) { 262 int r;
2147 case KEY_DSA_CERT_V00: 263
2148 case KEY_RSA_CERT_V00: 264 if ((r = sshkey_ec_validate_public(group, public)) != 0) {
2149 return 1; 265 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
2150 default: 266 error("%s: %s", __func__, ssh_err(r));
2151 return 0; 267 return -1;
2152 } 268 }
269 return 0;
2153} 270}
2154 271
2155/* XXX: these are really begging for a table-driven approach */
2156int 272int
2157key_curve_name_to_nid(const char *name) 273key_ec_validate_private(const EC_KEY *key)
2158{ 274{
2159#ifdef OPENSSL_HAS_ECC 275 int r;
2160 if (strcmp(name, "nistp256") == 0) 276
2161 return NID_X9_62_prime256v1; 277 if ((r = sshkey_ec_validate_private(key)) != 0) {
2162 else if (strcmp(name, "nistp384") == 0) 278 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
2163 return NID_secp384r1; 279 error("%s: %s", __func__, ssh_err(r));
2164# ifdef OPENSSL_HAS_NISTP521 280 return -1;
2165 else if (strcmp(name, "nistp521") == 0) 281 }
2166 return NID_secp521r1; 282 return 0;
2167# endif
2168#endif
2169
2170 debug("%s: unsupported EC curve name \"%.100s\"", __func__, name);
2171 return -1;
2172} 283}
284#endif /* WITH_OPENSSL */
2173 285
2174u_int 286void
2175key_curve_nid_to_bits(int nid) 287key_private_serialize(const Key *key, struct sshbuf *b)
2176{ 288{
2177 switch (nid) { 289 int r;
2178#ifdef OPENSSL_HAS_ECC 290
2179 case NID_X9_62_prime256v1: 291 if ((r = sshkey_private_serialize(key, b)) != 0)
2180 return 256; 292 fatal("%s: %s", __func__, ssh_err(r));
2181 case NID_secp384r1:
2182 return 384;
2183# ifdef OPENSSL_HAS_NISTP521
2184 case NID_secp521r1:
2185 return 521;
2186# endif
2187#endif
2188 default:
2189 error("%s: unsupported EC curve nid %d", __func__, nid);
2190 return 0;
2191 }
2192} 293}
2193 294
2194const char * 295Key *
2195key_curve_nid_to_name(int nid) 296key_private_deserialize(struct sshbuf *blob)
2196{ 297{
2197#ifdef OPENSSL_HAS_ECC 298 int r;
2198 if (nid == NID_X9_62_prime256v1) 299 Key *ret = NULL;
2199 return "nistp256"; 300
2200 else if (nid == NID_secp384r1) 301 if ((r = sshkey_private_deserialize(blob, &ret)) != 0) {
2201 return "nistp384"; 302 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
2202# ifdef OPENSSL_HAS_NISTP521 303 error("%s: %s", __func__, ssh_err(r));
2203 else if (nid == NID_secp521r1) 304 return NULL;
2204 return "nistp521"; 305 }
2205# endif 306 return ret;
2206#endif
2207 error("%s: unsupported EC curve nid %d", __func__, nid);
2208 return NULL;
2209} 307}
2210 308
2211#ifdef OPENSSL_HAS_ECC 309/* authfile.c */
310
2212int 311int
2213key_ec_nid_to_hash_alg(int nid) 312key_save_private(Key *key, const char *filename, const char *passphrase,
313 const char *comment, int force_new_format, const char *new_format_cipher,
314 int new_format_rounds)
2214{ 315{
2215 int kbits = key_curve_nid_to_bits(nid); 316 int r;
2216 317
2217 if (kbits == 0) 318 if ((r = sshkey_save_private(key, filename, passphrase, comment,
2218 fatal("%s: invalid nid %d", __func__, nid); 319 force_new_format, new_format_cipher, new_format_rounds)) != 0) {
2219 /* RFC5656 section 6.2.1 */ 320 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
2220 if (kbits <= 256) 321 error("%s: %s", __func__, ssh_err(r));
2221 return SSH_DIGEST_SHA256; 322 return 0;
2222 else if (kbits <= 384) 323 }
2223 return SSH_DIGEST_SHA384; 324 return 1;
2224 else
2225 return SSH_DIGEST_SHA512;
2226} 325}
2227 326
2228int 327int
2229key_ec_validate_public(const EC_GROUP *group, const EC_POINT *public) 328key_load_file(int fd, const char *filename, struct sshbuf *blob)
2230{ 329{
2231 BN_CTX *bnctx; 330 int r;
2232 EC_POINT *nq = NULL;
2233 BIGNUM *order, *x, *y, *tmp;
2234 int ret = -1;
2235
2236 if ((bnctx = BN_CTX_new()) == NULL)
2237 fatal("%s: BN_CTX_new failed", __func__);
2238 BN_CTX_start(bnctx);
2239
2240 /*
2241 * We shouldn't ever hit this case because bignum_get_ecpoint()
2242 * refuses to load GF2m points.
2243 */
2244 if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
2245 NID_X9_62_prime_field) {
2246 error("%s: group is not a prime field", __func__);
2247 goto out;
2248 }
2249 331
2250 /* Q != infinity */ 332 if ((r = sshkey_load_file(fd, filename, blob)) != 0) {
2251 if (EC_POINT_is_at_infinity(group, public)) { 333 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
2252 error("%s: received degenerate public key (infinity)", 334 error("%s: %s", __func__, ssh_err(r));
2253 __func__); 335 return 0;
2254 goto out;
2255 } 336 }
337 return 1;
338}
2256 339
2257 if ((x = BN_CTX_get(bnctx)) == NULL || 340Key *
2258 (y = BN_CTX_get(bnctx)) == NULL || 341key_load_cert(const char *filename)
2259 (order = BN_CTX_get(bnctx)) == NULL || 342{
2260 (tmp = BN_CTX_get(bnctx)) == NULL) 343 int r;
2261 fatal("%s: BN_CTX_get failed", __func__); 344 Key *ret = NULL;
2262 345
2263 /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */ 346 if ((r = sshkey_load_cert(filename, &ret)) != 0) {
2264 if (EC_GROUP_get_order(group, order, bnctx) != 1) 347 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
2265 fatal("%s: EC_GROUP_get_order failed", __func__); 348 /* Old authfile.c ignored all file errors. */
2266 if (EC_POINT_get_affine_coordinates_GFp(group, public, 349 if (r == SSH_ERR_SYSTEM_ERROR)
2267 x, y, bnctx) != 1) 350 debug("%s: %s", __func__, ssh_err(r));
2268 fatal("%s: EC_POINT_get_affine_coordinates_GFp", __func__); 351 else
2269 if (BN_num_bits(x) <= BN_num_bits(order) / 2) { 352 error("%s: %s", __func__, ssh_err(r));
2270 error("%s: public key x coordinate too small: " 353 return NULL;
2271 "bits(x) = %d, bits(order)/2 = %d", __func__,
2272 BN_num_bits(x), BN_num_bits(order) / 2);
2273 goto out;
2274 }
2275 if (BN_num_bits(y) <= BN_num_bits(order) / 2) {
2276 error("%s: public key y coordinate too small: "
2277 "bits(y) = %d, bits(order)/2 = %d", __func__,
2278 BN_num_bits(x), BN_num_bits(order) / 2);
2279 goto out;
2280 } 354 }
355 return ret;
2281 356
2282 /* nQ == infinity (n == order of subgroup) */ 357}
2283 if ((nq = EC_POINT_new(group)) == NULL)
2284 fatal("%s: BN_CTX_tmp failed", __func__);
2285 if (EC_POINT_mul(group, nq, NULL, public, order, bnctx) != 1)
2286 fatal("%s: EC_GROUP_mul failed", __func__);
2287 if (EC_POINT_is_at_infinity(group, nq) != 1) {
2288 error("%s: received degenerate public key (nQ != infinity)",
2289 __func__);
2290 goto out;
2291 }
2292 358
2293 /* x < order - 1, y < order - 1 */ 359Key *
2294 if (!BN_sub(tmp, order, BN_value_one())) 360key_load_public(const char *filename, char **commentp)
2295 fatal("%s: BN_sub failed", __func__); 361{
2296 if (BN_cmp(x, tmp) >= 0) { 362 int r;
2297 error("%s: public key x coordinate >= group order - 1", 363 Key *ret = NULL;
2298 __func__); 364
2299 goto out; 365 if ((r = sshkey_load_public(filename, &ret, commentp)) != 0) {
2300 } 366 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
2301 if (BN_cmp(y, tmp) >= 0) { 367 /* Old authfile.c ignored all file errors. */
2302 error("%s: public key y coordinate >= group order - 1", 368 if (r == SSH_ERR_SYSTEM_ERROR)
2303 __func__); 369 debug("%s: %s", __func__, ssh_err(r));
2304 goto out; 370 else
371 error("%s: %s", __func__, ssh_err(r));
372 return NULL;
2305 } 373 }
2306 ret = 0;
2307 out:
2308 BN_CTX_free(bnctx);
2309 EC_POINT_free(nq);
2310 return ret; 374 return ret;
2311} 375}
2312 376
2313int 377Key *
2314key_ec_validate_private(const EC_KEY *key) 378key_load_private(const char *path, const char *passphrase,
2315{ 379 char **commentp)
2316 BN_CTX *bnctx; 380{
2317 BIGNUM *order, *tmp; 381 int r;
2318 int ret = -1; 382 Key *ret = NULL;
2319 383
2320 if ((bnctx = BN_CTX_new()) == NULL) 384 if ((r = sshkey_load_private(path, passphrase, &ret, commentp)) != 0) {
2321 fatal("%s: BN_CTX_new failed", __func__); 385 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
2322 BN_CTX_start(bnctx); 386 /* Old authfile.c ignored all file errors. */
2323 387 if (r == SSH_ERR_SYSTEM_ERROR ||
2324 if ((order = BN_CTX_get(bnctx)) == NULL || 388 r == SSH_ERR_KEY_WRONG_PASSPHRASE)
2325 (tmp = BN_CTX_get(bnctx)) == NULL) 389 debug("%s: %s", __func__, ssh_err(r));
2326 fatal("%s: BN_CTX_get failed", __func__); 390 else
2327 391 error("%s: %s", __func__, ssh_err(r));
2328 /* log2(private) > log2(order)/2 */ 392 return NULL;
2329 if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, bnctx) != 1)
2330 fatal("%s: EC_GROUP_get_order failed", __func__);
2331 if (BN_num_bits(EC_KEY_get0_private_key(key)) <=
2332 BN_num_bits(order) / 2) {
2333 error("%s: private key too small: "
2334 "bits(y) = %d, bits(order)/2 = %d", __func__,
2335 BN_num_bits(EC_KEY_get0_private_key(key)),
2336 BN_num_bits(order) / 2);
2337 goto out;
2338 } 393 }
394 return ret;
395}
2339 396
2340 /* private < order - 1 */ 397Key *
2341 if (!BN_sub(tmp, order, BN_value_one())) 398key_load_private_cert(int type, const char *filename, const char *passphrase,
2342 fatal("%s: BN_sub failed", __func__); 399 int *perm_ok)
2343 if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0) { 400{
2344 error("%s: private key >= group order - 1", __func__); 401 int r;
2345 goto out; 402 Key *ret = NULL;
403
404 if ((r = sshkey_load_private_cert(type, filename, passphrase,
405 &ret, perm_ok)) != 0) {
406 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
407 /* Old authfile.c ignored all file errors. */
408 if (r == SSH_ERR_SYSTEM_ERROR ||
409 r == SSH_ERR_KEY_WRONG_PASSPHRASE)
410 debug("%s: %s", __func__, ssh_err(r));
411 else
412 error("%s: %s", __func__, ssh_err(r));
413 return NULL;
2346 } 414 }
2347 ret = 0;
2348 out:
2349 BN_CTX_free(bnctx);
2350 return ret; 415 return ret;
2351} 416}
2352 417
2353#if defined(DEBUG_KEXECDH) || defined(DEBUG_PK) 418Key *
2354void 419key_load_private_type(int type, const char *filename, const char *passphrase,
2355key_dump_ec_point(const EC_GROUP *group, const EC_POINT *point) 420 char **commentp, int *perm_ok)
2356{ 421{
2357 BIGNUM *x, *y; 422 int r;
2358 BN_CTX *bnctx; 423 Key *ret = NULL;
2359 424
2360 if (point == NULL) { 425 if ((r = sshkey_load_private_type(type, filename, passphrase,
2361 fputs("point=(NULL)\n", stderr); 426 &ret, commentp, perm_ok)) != 0) {
2362 return; 427 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
428 /* Old authfile.c ignored all file errors. */
429 if (r == SSH_ERR_SYSTEM_ERROR ||
430 (r == SSH_ERR_KEY_WRONG_PASSPHRASE))
431 debug("%s: %s", __func__, ssh_err(r));
432 else
433 error("%s: %s", __func__, ssh_err(r));
434 return NULL;
2363 } 435 }
2364 if ((bnctx = BN_CTX_new()) == NULL) 436 return ret;
2365 fatal("%s: BN_CTX_new failed", __func__);
2366 BN_CTX_start(bnctx);
2367 if ((x = BN_CTX_get(bnctx)) == NULL || (y = BN_CTX_get(bnctx)) == NULL)
2368 fatal("%s: BN_CTX_get failed", __func__);
2369 if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
2370 NID_X9_62_prime_field)
2371 fatal("%s: group is not a prime field", __func__);
2372 if (EC_POINT_get_affine_coordinates_GFp(group, point, x, y, bnctx) != 1)
2373 fatal("%s: EC_POINT_get_affine_coordinates_GFp", __func__);
2374 fputs("x=", stderr);
2375 BN_print_fp(stderr, x);
2376 fputs("\ny=", stderr);
2377 BN_print_fp(stderr, y);
2378 fputs("\n", stderr);
2379 BN_CTX_free(bnctx);
2380} 437}
2381 438
2382void 439#ifdef WITH_OPENSSL
2383key_dump_ec_key(const EC_KEY *key) 440Key *
2384{ 441key_load_private_pem(int fd, int type, const char *passphrase,
2385 const BIGNUM *exponent; 442 char **commentp)
2386 443{
2387 key_dump_ec_point(EC_KEY_get0_group(key), EC_KEY_get0_public_key(key)); 444 int r;
2388 fputs("exponent=", stderr); 445 Key *ret = NULL;
2389 if ((exponent = EC_KEY_get0_private_key(key)) == NULL) 446
2390 fputs("(NULL)", stderr); 447 if ((r = sshkey_load_private_pem(fd, type, passphrase,
2391 else 448 &ret, commentp)) != 0) {
2392 BN_print_fp(stderr, EC_KEY_get0_private_key(key)); 449 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
2393 fputs("\n", stderr); 450 if (r == SSH_ERR_KEY_WRONG_PASSPHRASE)
451 debug("%s: %s", __func__, ssh_err(r));
452 else
453 error("%s: %s", __func__, ssh_err(r));
454 return NULL;
455 }
456 return ret;
2394} 457}
2395#endif /* defined(DEBUG_KEXECDH) || defined(DEBUG_PK) */ 458#endif /* WITH_OPENSSL */
2396#endif /* OPENSSL_HAS_ECC */
2397 459
2398void 460int
2399key_private_serialize(const Key *key, Buffer *b) 461key_perm_ok(int fd, const char *filename)
2400{ 462{
2401 buffer_put_cstring(b, key_ssh_name(key)); 463 return sshkey_perm_ok(fd, filename) == 0 ? 1 : 0;
2402 switch (key->type) {
2403 case KEY_RSA:
2404 buffer_put_bignum2(b, key->rsa->n);
2405 buffer_put_bignum2(b, key->rsa->e);
2406 buffer_put_bignum2(b, key->rsa->d);
2407 buffer_put_bignum2(b, key->rsa->iqmp);
2408 buffer_put_bignum2(b, key->rsa->p);
2409 buffer_put_bignum2(b, key->rsa->q);
2410 break;
2411 case KEY_RSA_CERT_V00:
2412 case KEY_RSA_CERT:
2413 if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
2414 fatal("%s: no cert/certblob", __func__);
2415 buffer_put_string(b, buffer_ptr(&key->cert->certblob),
2416 buffer_len(&key->cert->certblob));
2417 buffer_put_bignum2(b, key->rsa->d);
2418 buffer_put_bignum2(b, key->rsa->iqmp);
2419 buffer_put_bignum2(b, key->rsa->p);
2420 buffer_put_bignum2(b, key->rsa->q);
2421 break;
2422 case KEY_DSA:
2423 buffer_put_bignum2(b, key->dsa->p);
2424 buffer_put_bignum2(b, key->dsa->q);
2425 buffer_put_bignum2(b, key->dsa->g);
2426 buffer_put_bignum2(b, key->dsa->pub_key);
2427 buffer_put_bignum2(b, key->dsa->priv_key);
2428 break;
2429 case KEY_DSA_CERT_V00:
2430 case KEY_DSA_CERT:
2431 if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
2432 fatal("%s: no cert/certblob", __func__);
2433 buffer_put_string(b, buffer_ptr(&key->cert->certblob),
2434 buffer_len(&key->cert->certblob));
2435 buffer_put_bignum2(b, key->dsa->priv_key);
2436 break;
2437#ifdef OPENSSL_HAS_ECC
2438 case KEY_ECDSA:
2439 buffer_put_cstring(b, key_curve_nid_to_name(key->ecdsa_nid));
2440 buffer_put_ecpoint(b, EC_KEY_get0_group(key->ecdsa),
2441 EC_KEY_get0_public_key(key->ecdsa));
2442 buffer_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa));
2443 break;
2444 case KEY_ECDSA_CERT:
2445 if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
2446 fatal("%s: no cert/certblob", __func__);
2447 buffer_put_string(b, buffer_ptr(&key->cert->certblob),
2448 buffer_len(&key->cert->certblob));
2449 buffer_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa));
2450 break;
2451#endif /* OPENSSL_HAS_ECC */
2452 case KEY_ED25519:
2453 buffer_put_string(b, key->ed25519_pk, ED25519_PK_SZ);
2454 buffer_put_string(b, key->ed25519_sk, ED25519_SK_SZ);
2455 break;
2456 case KEY_ED25519_CERT:
2457 if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
2458 fatal("%s: no cert/certblob", __func__);
2459 buffer_put_string(b, buffer_ptr(&key->cert->certblob),
2460 buffer_len(&key->cert->certblob));
2461 buffer_put_string(b, key->ed25519_pk, ED25519_PK_SZ);
2462 buffer_put_string(b, key->ed25519_sk, ED25519_SK_SZ);
2463 break;
2464 }
2465} 464}
2466 465
2467Key * 466int
2468key_private_deserialize(Buffer *blob) 467key_in_file(Key *key, const char *filename, int strict_type)
2469{ 468{
2470 char *type_name; 469 int r;
2471 Key *k = NULL; 470
2472 u_char *cert; 471 if ((r = sshkey_in_file(key, filename, strict_type)) != 0) {
2473 u_int len, pklen, sklen; 472 fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
2474 int type; 473 if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT)
2475#ifdef OPENSSL_HAS_ECC 474 return 0;
2476 char *curve; 475 error("%s: %s", __func__, ssh_err(r));
2477 BIGNUM *exponent; 476 return r == SSH_ERR_KEY_NOT_FOUND ? 0 : -1;
2478 EC_POINT *q;
2479#endif
2480
2481 type_name = buffer_get_string(blob, NULL);
2482 type = key_type_from_name(type_name);
2483 switch (type) {
2484 case KEY_DSA:
2485 k = key_new_private(type);
2486 buffer_get_bignum2(blob, k->dsa->p);
2487 buffer_get_bignum2(blob, k->dsa->q);
2488 buffer_get_bignum2(blob, k->dsa->g);
2489 buffer_get_bignum2(blob, k->dsa->pub_key);
2490 buffer_get_bignum2(blob, k->dsa->priv_key);
2491 break;
2492 case KEY_DSA_CERT_V00:
2493 case KEY_DSA_CERT:
2494 cert = buffer_get_string(blob, &len);
2495 if ((k = key_from_blob(cert, len)) == NULL)
2496 fatal("Certificate parse failed");
2497 free(cert);
2498 key_add_private(k);
2499 buffer_get_bignum2(blob, k->dsa->priv_key);
2500 break;
2501#ifdef OPENSSL_HAS_ECC
2502 case KEY_ECDSA:
2503 k = key_new_private(type);
2504 k->ecdsa_nid = key_ecdsa_nid_from_name(type_name);
2505 curve = buffer_get_string(blob, NULL);
2506 if (k->ecdsa_nid != key_curve_name_to_nid(curve))
2507 fatal("%s: curve names mismatch", __func__);
2508 free(curve);
2509 k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
2510 if (k->ecdsa == NULL)
2511 fatal("%s: EC_KEY_new_by_curve_name failed",
2512 __func__);
2513 q = EC_POINT_new(EC_KEY_get0_group(k->ecdsa));
2514 if (q == NULL)
2515 fatal("%s: BN_new failed", __func__);
2516 if ((exponent = BN_new()) == NULL)
2517 fatal("%s: BN_new failed", __func__);
2518 buffer_get_ecpoint(blob,
2519 EC_KEY_get0_group(k->ecdsa), q);
2520 buffer_get_bignum2(blob, exponent);
2521 if (EC_KEY_set_public_key(k->ecdsa, q) != 1)
2522 fatal("%s: EC_KEY_set_public_key failed",
2523 __func__);
2524 if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1)
2525 fatal("%s: EC_KEY_set_private_key failed",
2526 __func__);
2527 if (key_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
2528 EC_KEY_get0_public_key(k->ecdsa)) != 0)
2529 fatal("%s: bad ECDSA public key", __func__);
2530 if (key_ec_validate_private(k->ecdsa) != 0)
2531 fatal("%s: bad ECDSA private key", __func__);
2532 BN_clear_free(exponent);
2533 EC_POINT_free(q);
2534 break;
2535 case KEY_ECDSA_CERT:
2536 cert = buffer_get_string(blob, &len);
2537 if ((k = key_from_blob(cert, len)) == NULL)
2538 fatal("Certificate parse failed");
2539 free(cert);
2540 key_add_private(k);
2541 if ((exponent = BN_new()) == NULL)
2542 fatal("%s: BN_new failed", __func__);
2543 buffer_get_bignum2(blob, exponent);
2544 if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1)
2545 fatal("%s: EC_KEY_set_private_key failed",
2546 __func__);
2547 if (key_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
2548 EC_KEY_get0_public_key(k->ecdsa)) != 0 ||
2549 key_ec_validate_private(k->ecdsa) != 0)
2550 fatal("%s: bad ECDSA key", __func__);
2551 BN_clear_free(exponent);
2552 break;
2553#endif
2554 case KEY_RSA:
2555 k = key_new_private(type);
2556 buffer_get_bignum2(blob, k->rsa->n);
2557 buffer_get_bignum2(blob, k->rsa->e);
2558 buffer_get_bignum2(blob, k->rsa->d);
2559 buffer_get_bignum2(blob, k->rsa->iqmp);
2560 buffer_get_bignum2(blob, k->rsa->p);
2561 buffer_get_bignum2(blob, k->rsa->q);
2562
2563 /* Generate additional parameters */
2564 rsa_generate_additional_parameters(k->rsa);
2565 break;
2566 case KEY_RSA_CERT_V00:
2567 case KEY_RSA_CERT:
2568 cert = buffer_get_string(blob, &len);
2569 if ((k = key_from_blob(cert, len)) == NULL)
2570 fatal("Certificate parse failed");
2571 free(cert);
2572 key_add_private(k);
2573 buffer_get_bignum2(blob, k->rsa->d);
2574 buffer_get_bignum2(blob, k->rsa->iqmp);
2575 buffer_get_bignum2(blob, k->rsa->p);
2576 buffer_get_bignum2(blob, k->rsa->q);
2577 break;
2578 case KEY_ED25519:
2579 k = key_new_private(type);
2580 k->ed25519_pk = buffer_get_string(blob, &pklen);
2581 k->ed25519_sk = buffer_get_string(blob, &sklen);
2582 if (pklen != ED25519_PK_SZ)
2583 fatal("%s: ed25519 pklen %d != %d",
2584 __func__, pklen, ED25519_PK_SZ);
2585 if (sklen != ED25519_SK_SZ)
2586 fatal("%s: ed25519 sklen %d != %d",
2587 __func__, sklen, ED25519_SK_SZ);
2588 break;
2589 case KEY_ED25519_CERT:
2590 cert = buffer_get_string(blob, &len);
2591 if ((k = key_from_blob(cert, len)) == NULL)
2592 fatal("Certificate parse failed");
2593 free(cert);
2594 key_add_private(k);
2595 k->ed25519_pk = buffer_get_string(blob, &pklen);
2596 k->ed25519_sk = buffer_get_string(blob, &sklen);
2597 if (pklen != ED25519_PK_SZ)
2598 fatal("%s: ed25519 pklen %d != %d",
2599 __func__, pklen, ED25519_PK_SZ);
2600 if (sklen != ED25519_SK_SZ)
2601 fatal("%s: ed25519 sklen %d != %d",
2602 __func__, sklen, ED25519_SK_SZ);
2603 break;
2604 default:
2605 free(type_name);
2606 buffer_clear(blob);
2607 return NULL;
2608 }
2609 free(type_name);
2610
2611 /* enable blinding */
2612 switch (k->type) {
2613 case KEY_RSA:
2614 case KEY_RSA_CERT_V00:
2615 case KEY_RSA_CERT:
2616 case KEY_RSA1:
2617 if (RSA_blinding_on(k->rsa, NULL) != 1) {
2618 error("%s: RSA_blinding_on failed", __func__);
2619 key_free(k);
2620 return NULL;
2621 }
2622 break;
2623 } 477 }
2624 return k; 478 return 1;
2625} 479}
diff --git a/key.h b/key.h
index d8ad13d08..c6401a576 100644
--- a/key.h
+++ b/key.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: key.h,v 1.41 2014/01/09 23:20:00 djm Exp $ */ 1/* $OpenBSD: key.h,v 1.42 2014/06/24 01:13:21 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -26,141 +26,86 @@
26#ifndef KEY_H 26#ifndef KEY_H
27#define KEY_H 27#define KEY_H
28 28
29#include "buffer.h" 29#include "sshkey.h"
30#include <openssl/rsa.h> 30
31#include <openssl/dsa.h> 31typedef struct sshkey Key;
32#ifdef OPENSSL_HAS_ECC 32
33#include <openssl/ec.h> 33#define types sshkey_types
34#define fp_type sshkey_fp_type
35#define fp_rep sshkey_fp_rep
36
37#ifndef SSH_KEY_NO_DEFINE
38#define key_new sshkey_new
39#define key_free sshkey_free
40#define key_equal_public sshkey_equal_public
41#define key_equal sshkey_equal
42#define key_fingerprint sshkey_fingerprint
43#define key_type sshkey_type
44#define key_cert_type sshkey_cert_type
45#define key_ssh_name sshkey_ssh_name
46#define key_ssh_name_plain sshkey_ssh_name_plain
47#define key_type_from_name sshkey_type_from_name
48#define key_ecdsa_nid_from_name sshkey_ecdsa_nid_from_name
49#define key_type_is_cert sshkey_type_is_cert
50#define key_size sshkey_size
51#define key_ecdsa_bits_to_nid sshkey_ecdsa_bits_to_nid
52#define key_ecdsa_key_to_nid sshkey_ecdsa_key_to_nid
53#define key_names_valid2 sshkey_names_valid2
54#define key_is_cert sshkey_is_cert
55#define key_type_plain sshkey_type_plain
56#define key_cert_is_legacy sshkey_cert_is_legacy
57#define key_curve_name_to_nid sshkey_curve_name_to_nid
58#define key_curve_nid_to_bits sshkey_curve_nid_to_bits
59#define key_curve_nid_to_name sshkey_curve_nid_to_name
60#define key_ec_nid_to_hash_alg sshkey_ec_nid_to_hash_alg
61#define key_dump_ec_point sshkey_dump_ec_point
62#define key_dump_ec_key sshkey_dump_ec_key
63#define key_fingerprint sshkey_fingerprint
34#endif 64#endif
35 65
36typedef struct Key Key; 66void key_add_private(Key *);
37enum types { 67Key *key_new_private(int);
38 KEY_RSA1, 68void key_free(Key *);
39 KEY_RSA, 69Key *key_demote(const Key *);
40 KEY_DSA, 70u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *);
41 KEY_ECDSA, 71int key_write(const Key *, FILE *);
42 KEY_ED25519, 72int key_read(Key *, char **);
43 KEY_RSA_CERT,
44 KEY_DSA_CERT,
45 KEY_ECDSA_CERT,
46 KEY_ED25519_CERT,
47 KEY_RSA_CERT_V00,
48 KEY_DSA_CERT_V00,
49 KEY_UNSPEC
50};
51enum fp_type {
52 SSH_FP_SHA1,
53 SSH_FP_MD5,
54 SSH_FP_SHA256
55};
56enum fp_rep {
57 SSH_FP_HEX,
58 SSH_FP_BUBBLEBABBLE,
59 SSH_FP_RANDOMART
60};
61
62/* key is stored in external hardware */
63#define KEY_FLAG_EXT 0x0001
64
65#define CERT_MAX_PRINCIPALS 256
66struct KeyCert {
67 Buffer certblob; /* Kept around for use on wire */
68 u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */
69 u_int64_t serial;
70 char *key_id;
71 u_int nprincipals;
72 char **principals;
73 u_int64_t valid_after, valid_before;
74 Buffer critical;
75 Buffer extensions;
76 Key *signature_key;
77};
78
79struct Key {
80 int type;
81 int flags;
82 RSA *rsa;
83 DSA *dsa;
84 int ecdsa_nid; /* NID of curve */
85#ifdef OPENSSL_HAS_ECC
86 EC_KEY *ecdsa;
87#else
88 void *ecdsa;
89#endif
90 struct KeyCert *cert;
91 u_char *ed25519_sk;
92 u_char *ed25519_pk;
93};
94
95#define ED25519_SK_SZ crypto_sign_ed25519_SECRETKEYBYTES
96#define ED25519_PK_SZ crypto_sign_ed25519_PUBLICKEYBYTES
97
98Key *key_new(int);
99void key_add_private(Key *);
100Key *key_new_private(int);
101void key_free(Key *);
102Key *key_demote(const Key *);
103int key_equal_public(const Key *, const Key *);
104int key_equal(const Key *, const Key *);
105char *key_fingerprint(const Key *, enum fp_type, enum fp_rep);
106u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *);
107const char *key_type(const Key *);
108const char *key_cert_type(const Key *);
109int key_write(const Key *, FILE *);
110int key_read(Key *, char **);
111u_int key_size(const Key *);
112 73
113Key *key_generate(int, u_int); 74Key *key_generate(int, u_int);
114Key *key_from_private(const Key *); 75Key *key_from_private(const Key *);
115int key_type_from_name(char *);
116int key_is_cert(const Key *);
117int key_type_is_cert(int);
118int key_type_plain(int);
119int key_to_certified(Key *, int); 76int key_to_certified(Key *, int);
120int key_drop_cert(Key *); 77int key_drop_cert(Key *);
121int key_certify(Key *, Key *); 78int key_certify(Key *, Key *);
122void key_cert_copy(const Key *, struct Key *); 79void key_cert_copy(const Key *, Key *);
123int key_cert_check_authority(const Key *, int, int, const char *, 80int key_cert_check_authority(const Key *, int, int, const char *,
124 const char **); 81 const char **);
125int key_cert_is_legacy(const Key *); 82char *key_alg_list(int, int);
126 83
127int key_ecdsa_nid_from_name(const char *); 84#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
128int key_curve_name_to_nid(const char *); 85int key_ec_validate_public(const EC_GROUP *, const EC_POINT *);
129const char *key_curve_nid_to_name(int); 86int key_ec_validate_private(const EC_KEY *);
130u_int key_curve_nid_to_bits(int); 87#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */
131int key_ecdsa_bits_to_nid(int);
132#ifdef OPENSSL_HAS_ECC
133int key_ecdsa_key_to_nid(EC_KEY *);
134int key_ec_nid_to_hash_alg(int nid);
135int key_ec_validate_public(const EC_GROUP *, const EC_POINT *);
136int key_ec_validate_private(const EC_KEY *);
137#endif
138char *key_alg_list(int, int);
139 88
140Key *key_from_blob(const u_char *, u_int); 89Key *key_from_blob(const u_char *, u_int);
141int key_to_blob(const Key *, u_char **, u_int *); 90int key_to_blob(const Key *, u_char **, u_int *);
142const char *key_ssh_name(const Key *);
143const char *key_ssh_name_plain(const Key *);
144int key_names_valid2(const char *);
145 91
146int key_sign(const Key *, u_char **, u_int *, const u_char *, u_int); 92int key_sign(const Key *, u_char **, u_int *, const u_char *, u_int);
147int key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); 93int key_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
148 94
149int ssh_dss_sign(const Key *, u_char **, u_int *, const u_char *, u_int); 95void key_private_serialize(const Key *, struct sshbuf *);
150int ssh_dss_verify(const Key *, const u_char *, u_int, const u_char *, u_int); 96Key *key_private_deserialize(struct sshbuf *);
151int ssh_ecdsa_sign(const Key *, u_char **, u_int *, const u_char *, u_int); 97
152int ssh_ecdsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int); 98/* authfile.c */
153int ssh_rsa_sign(const Key *, u_char **, u_int *, const u_char *, u_int); 99int key_save_private(Key *, const char *, const char *, const char *,
154int ssh_rsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int); 100 int, const char *, int);
155int ssh_ed25519_sign(const Key *, u_char **, u_int *, const u_char *, u_int); 101int key_load_file(int, const char *, struct sshbuf *);
156int ssh_ed25519_verify(const Key *, const u_char *, u_int, const u_char *, u_int); 102Key *key_load_cert(const char *);
157 103Key *key_load_public(const char *, char **);
158#if defined(OPENSSL_HAS_ECC) && (defined(DEBUG_KEXECDH) || defined(DEBUG_PK)) 104Key *key_load_private(const char *, const char *, char **);
159void key_dump_ec_point(const EC_GROUP *, const EC_POINT *); 105Key *key_load_private_cert(int, const char *, const char *, int *);
160void key_dump_ec_key(const EC_KEY *); 106Key *key_load_private_type(int, const char *, const char *, char **, int *);
161#endif 107Key *key_load_private_pem(int, int, const char *, char **);
162 108int key_perm_ok(int, const char *);
163void key_private_serialize(const Key *, Buffer *); 109int key_in_file(Key *, const char *, int);
164Key *key_private_deserialize(Buffer *);
165 110
166#endif 111#endif
diff --git a/krl.c b/krl.c
index 3b4cded05..eb31df90f 100644
--- a/krl.c
+++ b/krl.c
@@ -14,7 +14,7 @@
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */ 15 */
16 16
17/* $OpenBSD: krl.c,v 1.14 2014/01/31 16:39:19 tedu Exp $ */ 17/* $OpenBSD: krl.c,v 1.17 2014/06/24 01:13:21 djm Exp $ */
18 18
19#include "includes.h" 19#include "includes.h"
20 20
@@ -366,7 +366,7 @@ plain_key_blob(const Key *key, u_char **blob, u_int *blen)
366 } 366 }
367 r = key_to_blob(kcopy, blob, blen); 367 r = key_to_blob(kcopy, blob, blen);
368 free(kcopy); 368 free(kcopy);
369 return r == 0 ? -1 : 0; 369 return r;
370} 370}
371 371
372/* Revoke a key blob. Ownership of blob is transferred to the tree */ 372/* 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)
394 u_int len; 394 u_int len;
395 395
396 debug3("%s: revoke type %s", __func__, key_type(key)); 396 debug3("%s: revoke type %s", __func__, key_type(key));
397 if (plain_key_blob(key, &blob, &len) != 0) 397 if (plain_key_blob(key, &blob, &len) < 0)
398 return -1; 398 return -1;
399 return revoke_blob(&krl->revoked_keys, blob, len); 399 return revoke_blob(&krl->revoked_keys, blob, len);
400} 400}
@@ -575,6 +575,7 @@ revoked_certs_generate(struct revoked_certs *rc, Buffer *buf)
575 buffer_put_char(buf, state); 575 buffer_put_char(buf, state);
576 buffer_put_string(buf, 576 buffer_put_string(buf,
577 buffer_ptr(&sect), buffer_len(&sect)); 577 buffer_ptr(&sect), buffer_len(&sect));
578 buffer_clear(&sect);
578 } 579 }
579 580
580 /* If we are starting a new section then prepare it now */ 581 /* If we are starting a new section then prepare it now */
@@ -753,7 +754,8 @@ static int
753parse_revoked_certs(Buffer *buf, struct ssh_krl *krl) 754parse_revoked_certs(Buffer *buf, struct ssh_krl *krl)
754{ 755{
755 int ret = -1, nbits; 756 int ret = -1, nbits;
756 u_char type, *blob; 757 u_char type;
758 const u_char *blob;
757 u_int blen; 759 u_int blen;
758 Buffer subsect; 760 Buffer subsect;
759 u_int64_t serial, serial_lo, serial_hi; 761 u_int64_t serial, serial_lo, serial_hi;
@@ -887,7 +889,8 @@ ssh_krl_from_blob(Buffer *buf, struct ssh_krl **krlp,
887 char timestamp[64]; 889 char timestamp[64];
888 int ret = -1, r, sig_seen; 890 int ret = -1, r, sig_seen;
889 Key *key = NULL, **ca_used = NULL; 891 Key *key = NULL, **ca_used = NULL;
890 u_char type, *blob, *rdata = NULL; 892 u_char type, *rdata = NULL;
893 const u_char *blob;
891 u_int i, j, sig_off, sects_off, rlen, blen, format_version, nca_used; 894 u_int i, j, sig_off, sects_off, rlen, blen, format_version, nca_used;
892 895
893 nca_used = 0; 896 nca_used = 0;
@@ -1127,7 +1130,7 @@ is_key_revoked(struct ssh_krl *krl, const Key *key)
1127 1130
1128 /* Next, explicit keys */ 1131 /* Next, explicit keys */
1129 memset(&rb, 0, sizeof(rb)); 1132 memset(&rb, 0, sizeof(rb));
1130 if (plain_key_blob(key, &rb.blob, &rb.len) != 0) 1133 if (plain_key_blob(key, &rb.blob, &rb.len) < 0)
1131 return -1; 1134 return -1;
1132 erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); 1135 erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb);
1133 free(rb.blob); 1136 free(rb.blob);
diff --git a/mac.c b/mac.c
index 097757213..402dc984c 100644
--- a/mac.c
+++ b/mac.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: mac.c,v 1.28 2014/02/07 06:55:54 djm Exp $ */ 1/* $OpenBSD: mac.c,v 1.30 2014/04/30 19:07:48 naddy Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -175,7 +175,8 @@ mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
175 u_char m[EVP_MAX_MD_SIZE]; 175 u_char m[EVP_MAX_MD_SIZE];
176 u_int64_t for_align; 176 u_int64_t for_align;
177 } u; 177 } u;
178 u_char b[4], nonce[8]; 178 u_char b[4];
179 u_char nonce[8];
179 180
180 if (mac->mac_len > sizeof(u)) 181 if (mac->mac_len > sizeof(u))
181 fatal("mac_compute: mac too long %u %zu", 182 fatal("mac_compute: mac too long %u %zu",
diff --git a/misc.c b/misc.c
index e4c8c3238..94b05b08e 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: misc.c,v 1.92 2013/10/14 23:28:23 djm Exp $ */ 1/* $OpenBSD: misc.c,v 1.94 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Copyright (c) 2005,2006 Damien Miller. All rights reserved. 4 * Copyright (c) 2005,2006 Damien Miller. All rights reserved.
@@ -29,6 +29,7 @@
29#include <sys/types.h> 29#include <sys/types.h>
30#include <sys/ioctl.h> 30#include <sys/ioctl.h>
31#include <sys/socket.h> 31#include <sys/socket.h>
32#include <sys/un.h>
32#include <sys/param.h> 33#include <sys/param.h>
33 34
34#include <stdarg.h> 35#include <stdarg.h>
@@ -788,6 +789,20 @@ get_u32(const void *vp)
788 return (v); 789 return (v);
789} 790}
790 791
792u_int32_t
793get_u32_le(const void *vp)
794{
795 const u_char *p = (const u_char *)vp;
796 u_int32_t v;
797
798 v = (u_int32_t)p[0];
799 v |= (u_int32_t)p[1] << 8;
800 v |= (u_int32_t)p[2] << 16;
801 v |= (u_int32_t)p[3] << 24;
802
803 return (v);
804}
805
791u_int16_t 806u_int16_t
792get_u16(const void *vp) 807get_u16(const void *vp)
793{ 808{
@@ -826,6 +841,16 @@ put_u32(void *vp, u_int32_t v)
826 p[3] = (u_char)v & 0xff; 841 p[3] = (u_char)v & 0xff;
827} 842}
828 843
844void
845put_u32_le(void *vp, u_int32_t v)
846{
847 u_char *p = (u_char *)vp;
848
849 p[0] = (u_char)v & 0xff;
850 p[1] = (u_char)(v >> 8) & 0xff;
851 p[2] = (u_char)(v >> 16) & 0xff;
852 p[3] = (u_char)(v >> 24) & 0xff;
853}
829 854
830void 855void
831put_u16(void *vp, u_int16_t v) 856put_u16(void *vp, u_int16_t v)
@@ -858,17 +883,24 @@ ms_to_timeval(struct timeval *tv, int ms)
858time_t 883time_t
859monotime(void) 884monotime(void)
860{ 885{
861#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) 886#if defined(HAVE_CLOCK_GETTIME) && \
887 (defined(CLOCK_MONOTONIC) || defined(CLOCK_BOOTTIME))
862 struct timespec ts; 888 struct timespec ts;
863 static int gettime_failed = 0; 889 static int gettime_failed = 0;
864 890
865 if (!gettime_failed) { 891 if (!gettime_failed) {
892#if defined(CLOCK_BOOTTIME)
893 if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0)
894 return (ts.tv_sec);
895#endif
896#if defined(CLOCK_MONOTONIC)
866 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) 897 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
867 return (ts.tv_sec); 898 return (ts.tv_sec);
899#endif
868 debug3("clock_gettime: %s", strerror(errno)); 900 debug3("clock_gettime: %s", strerror(errno));
869 gettime_failed = 1; 901 gettime_failed = 1;
870 } 902 }
871#endif 903#endif /* HAVE_CLOCK_GETTIME && (CLOCK_MONOTONIC || CLOCK_BOOTTIME */
872 904
873 return time(NULL); 905 return time(NULL);
874} 906}
@@ -1025,6 +1057,53 @@ lowercase(char *s)
1025 for (; *s; s++) 1057 for (; *s; s++)
1026 *s = tolower((u_char)*s); 1058 *s = tolower((u_char)*s);
1027} 1059}
1060
1061int
1062unix_listener(const char *path, int backlog, int unlink_first)
1063{
1064 struct sockaddr_un sunaddr;
1065 int saved_errno, sock;
1066
1067 memset(&sunaddr, 0, sizeof(sunaddr));
1068 sunaddr.sun_family = AF_UNIX;
1069 if (strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
1070 error("%s: \"%s\" too long for Unix domain socket", __func__,
1071 path);
1072 errno = ENAMETOOLONG;
1073 return -1;
1074 }
1075
1076 sock = socket(PF_UNIX, SOCK_STREAM, 0);
1077 if (sock < 0) {
1078 saved_errno = errno;
1079 error("socket: %.100s", strerror(errno));
1080 errno = saved_errno;
1081 return -1;
1082 }
1083 if (unlink_first == 1) {
1084 if (unlink(path) != 0 && errno != ENOENT)
1085 error("unlink(%s): %.100s", path, strerror(errno));
1086 }
1087 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
1088 saved_errno = errno;
1089 error("bind: %.100s", strerror(errno));
1090 close(sock);
1091 error("%s: cannot bind to path: %s", __func__, path);
1092 errno = saved_errno;
1093 return -1;
1094 }
1095 if (listen(sock, backlog) < 0) {
1096 saved_errno = errno;
1097 error("listen: %.100s", strerror(errno));
1098 close(sock);
1099 unlink(path);
1100 error("%s: cannot listen on path: %s", __func__, path);
1101 errno = saved_errno;
1102 return -1;
1103 }
1104 return sock;
1105}
1106
1028void 1107void
1029sock_set_v6only(int s) 1108sock_set_v6only(int s)
1030{ 1109{
diff --git a/misc.h b/misc.h
index d4df619cd..374c33ce1 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: misc.h,v 1.50 2013/10/14 23:28:23 djm Exp $ */ 1/* $OpenBSD: misc.h,v 1.54 2014/07/15 15:54:14 millert Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -15,6 +15,25 @@
15#ifndef _MISC_H 15#ifndef _MISC_H
16#define _MISC_H 16#define _MISC_H
17 17
18/* Data structure for representing a forwarding request. */
19struct Forward {
20 char *listen_host; /* Host (address) to listen on. */
21 int listen_port; /* Port to forward. */
22 char *listen_path; /* Path to bind domain socket. */
23 char *connect_host; /* Host to connect. */
24 int connect_port; /* Port to connect on connect_host. */
25 char *connect_path; /* Path to connect domain socket. */
26 int allocated_port; /* Dynamically allocated listen port */
27 int handle; /* Handle for dynamic listen ports */
28};
29
30/* Common server and client forwarding options. */
31struct ForwardOptions {
32 int gateway_ports; /* Allow remote connects to forwarded ports. */
33 mode_t streamlocal_bind_mask; /* umask for streamlocal binds */
34 int streamlocal_bind_unlink; /* unlink socket before bind */
35};
36
18/* misc.c */ 37/* misc.c */
19 38
20char *chop(char *); 39char *chop(char *);
@@ -37,6 +56,7 @@ void ms_subtract_diff(struct timeval *, int *);
37void ms_to_timeval(struct timeval *, int); 56void ms_to_timeval(struct timeval *, int);
38time_t monotime(void); 57time_t monotime(void);
39void lowercase(char *s); 58void lowercase(char *s);
59int unix_listener(const char *, int, int);
40 60
41void sock_set_v6only(int); 61void sock_set_v6only(int);
42 62
@@ -68,6 +88,9 @@ int tun_open(int, int);
68#define SSH_TUNID_ERR (SSH_TUNID_ANY - 1) 88#define SSH_TUNID_ERR (SSH_TUNID_ANY - 1)
69#define SSH_TUNID_MAX (SSH_TUNID_ANY - 2) 89#define SSH_TUNID_MAX (SSH_TUNID_ANY - 2)
70 90
91/* Fake port to indicate that host field is really a path. */
92#define PORT_STREAMLOCAL -2
93
71/* Functions to extract or store big-endian words of various sizes */ 94/* Functions to extract or store big-endian words of various sizes */
72u_int64_t get_u64(const void *) 95u_int64_t get_u64(const void *)
73 __attribute__((__bounded__( __minbytes__, 1, 8))); 96 __attribute__((__bounded__( __minbytes__, 1, 8)));
@@ -82,6 +105,12 @@ void put_u32(void *, u_int32_t)
82void put_u16(void *, u_int16_t) 105void put_u16(void *, u_int16_t)
83 __attribute__((__bounded__( __minbytes__, 1, 2))); 106 __attribute__((__bounded__( __minbytes__, 1, 2)));
84 107
108/* Little-endian store/load, used by umac.c */
109u_int32_t get_u32_le(const void *)
110 __attribute__((__bounded__(__minbytes__, 1, 4)));
111void put_u32_le(void *, u_int32_t)
112 __attribute__((__bounded__(__minbytes__, 1, 4)));
113
85struct bwlimit { 114struct bwlimit {
86 size_t buflen; 115 size_t buflen;
87 u_int64_t rate, thresh, lamt; 116 u_int64_t rate, thresh, lamt;
diff --git a/moduli.0 b/moduli.0
index 7d678b459..d9aaadba9 100644
--- a/moduli.0
+++ b/moduli.0
@@ -1,4 +1,4 @@
1MODULI(5) OpenBSD Programmer's Manual MODULI(5) 1MODULI(5) File Formats Manual MODULI(5)
2 2
3NAME 3NAME
4 moduli - Diffie-Hellman moduli 4 moduli - Diffie-Hellman moduli
@@ -71,4 +71,4 @@ STANDARDS
71 the Secure Shell (SSH) Transport Layer Protocol, RFC 4419, March 2006, 71 the Secure Shell (SSH) Transport Layer Protocol, RFC 4419, March 2006,
72 2006. 72 2006.
73 73
74OpenBSD 5.5 September 26, 2012 OpenBSD 5.5 74OpenBSD 5.6 September 26, 2012 OpenBSD 5.6
diff --git a/monitor.c b/monitor.c
index 531c4f9a8..dbe29f128 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: monitor.c,v 1.131 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: monitor.c,v 1.135 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright 2002 Niels Provos <provos@citi.umich.edu> 3 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
4 * Copyright 2002 Markus Friedl <markus@openbsd.org> 4 * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -40,9 +40,10 @@
40#endif 40#endif
41#include <pwd.h> 41#include <pwd.h>
42#include <signal.h> 42#include <signal.h>
43#include <stdarg.h>
44#include <stdlib.h> 43#include <stdlib.h>
45#include <string.h> 44#include <string.h>
45#include <stdarg.h>
46#include <stdio.h>
46#include <unistd.h> 47#include <unistd.h>
47#ifdef HAVE_POLL_H 48#ifdef HAVE_POLL_H
48#include <poll.h> 49#include <poll.h>
@@ -56,7 +57,9 @@
56#include <skey.h> 57#include <skey.h>
57#endif 58#endif
58 59
60#ifdef WITH_OPENSSL
59#include <openssl/dh.h> 61#include <openssl/dh.h>
62#endif
60 63
61#include "openbsd-compat/sys-queue.h" 64#include "openbsd-compat/sys-queue.h"
62#include "atomicio.h" 65#include "atomicio.h"
@@ -84,6 +87,7 @@
84#include "sshlogin.h" 87#include "sshlogin.h"
85#include "canohost.h" 88#include "canohost.h"
86#include "log.h" 89#include "log.h"
90#include "misc.h"
87#include "servconf.h" 91#include "servconf.h"
88#include "monitor.h" 92#include "monitor.h"
89#include "monitor_mm.h" 93#include "monitor_mm.h"
@@ -92,7 +96,6 @@
92#endif 96#endif
93#include "monitor_wrap.h" 97#include "monitor_wrap.h"
94#include "monitor_fdpass.h" 98#include "monitor_fdpass.h"
95#include "misc.h"
96#include "compat.h" 99#include "compat.h"
97#include "ssh2.h" 100#include "ssh2.h"
98#include "roaming.h" 101#include "roaming.h"
@@ -185,7 +188,10 @@ int mm_answer_audit_command(int, Buffer *);
185static int monitor_read_log(struct monitor *); 188static int monitor_read_log(struct monitor *);
186 189
187static Authctxt *authctxt; 190static Authctxt *authctxt;
191
192#ifdef WITH_SSH1
188static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ 193static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */
194#endif
189 195
190/* local state for key verify */ 196/* local state for key verify */
191static u_char *key_blob = NULL; 197static u_char *key_blob = NULL;
@@ -215,7 +221,9 @@ struct mon_table {
215#define MON_PERMIT 0x1000 /* Request is permitted */ 221#define MON_PERMIT 0x1000 /* Request is permitted */
216 222
217struct mon_table mon_dispatch_proto20[] = { 223struct mon_table mon_dispatch_proto20[] = {
224#ifdef WITH_OPENSSL
218 {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, 225 {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
226#endif
219 {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, 227 {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
220 {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, 228 {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
221 {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, 229 {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
@@ -252,7 +260,9 @@ struct mon_table mon_dispatch_proto20[] = {
252}; 260};
253 261
254struct mon_table mon_dispatch_postauth20[] = { 262struct mon_table mon_dispatch_postauth20[] = {
263#ifdef WITH_OPENSSL
255 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, 264 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
265#endif
256 {MONITOR_REQ_SIGN, 0, mm_answer_sign}, 266 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
257 {MONITOR_REQ_PTY, 0, mm_answer_pty}, 267 {MONITOR_REQ_PTY, 0, mm_answer_pty},
258 {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup}, 268 {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup},
@@ -265,6 +275,7 @@ struct mon_table mon_dispatch_postauth20[] = {
265}; 275};
266 276
267struct mon_table mon_dispatch_proto15[] = { 277struct mon_table mon_dispatch_proto15[] = {
278#ifdef WITH_SSH1
268 {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, 279 {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
269 {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, 280 {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey},
270 {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid}, 281 {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid},
@@ -292,10 +303,12 @@ struct mon_table mon_dispatch_proto15[] = {
292#ifdef SSH_AUDIT_EVENTS 303#ifdef SSH_AUDIT_EVENTS
293 {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, 304 {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
294#endif 305#endif
306#endif /* WITH_SSH1 */
295 {0, 0, NULL} 307 {0, 0, NULL}
296}; 308};
297 309
298struct mon_table mon_dispatch_postauth15[] = { 310struct mon_table mon_dispatch_postauth15[] = {
311#ifdef WITH_SSH1
299 {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty}, 312 {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty},
300 {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup}, 313 {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup},
301 {MONITOR_REQ_TERM, 0, mm_answer_term}, 314 {MONITOR_REQ_TERM, 0, mm_answer_term},
@@ -303,6 +316,7 @@ struct mon_table mon_dispatch_postauth15[] = {
303 {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, 316 {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
304 {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command}, 317 {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command},
305#endif 318#endif
319#endif /* WITH_SSH1 */
306 {0, 0, NULL} 320 {0, 0, NULL}
307}; 321};
308 322
@@ -457,6 +471,9 @@ monitor_child_postauth(struct monitor *pmonitor)
457 signal(SIGHUP, &monitor_child_handler); 471 signal(SIGHUP, &monitor_child_handler);
458 signal(SIGTERM, &monitor_child_handler); 472 signal(SIGTERM, &monitor_child_handler);
459 signal(SIGINT, &monitor_child_handler); 473 signal(SIGINT, &monitor_child_handler);
474#ifdef SIGXFSZ
475 signal(SIGXFSZ, SIG_IGN);
476#endif
460 477
461 if (compat20) { 478 if (compat20) {
462 mon_dispatch = mon_dispatch_postauth20; 479 mon_dispatch = mon_dispatch_postauth20;
@@ -630,6 +647,7 @@ monitor_reset_key_state(void)
630 hostbased_chost = NULL; 647 hostbased_chost = NULL;
631} 648}
632 649
650#ifdef WITH_OPENSSL
633int 651int
634mm_answer_moduli(int sock, Buffer *m) 652mm_answer_moduli(int sock, Buffer *m)
635{ 653{
@@ -664,6 +682,7 @@ mm_answer_moduli(int sock, Buffer *m)
664 mm_request_send(sock, MONITOR_ANS_MODULI, m); 682 mm_request_send(sock, MONITOR_ANS_MODULI, m);
665 return (0); 683 return (0);
666} 684}
685#endif
667 686
668extern AuthenticationConnection *auth_conn; 687extern AuthenticationConnection *auth_conn;
669 688
@@ -1166,6 +1185,7 @@ mm_answer_keyallowed(int sock, Buffer *m)
1166 cuser, chost); 1185 cuser, chost);
1167 auth_method = "hostbased"; 1186 auth_method = "hostbased";
1168 break; 1187 break;
1188#ifdef WITH_SSH1
1169 case MM_RSAHOSTKEY: 1189 case MM_RSAHOSTKEY:
1170 key->type = KEY_RSA1; /* XXX */ 1190 key->type = KEY_RSA1; /* XXX */
1171 allowed = options.rhosts_rsa_authentication && 1191 allowed = options.rhosts_rsa_authentication &&
@@ -1175,6 +1195,7 @@ mm_answer_keyallowed(int sock, Buffer *m)
1175 auth_clear_options(); 1195 auth_clear_options();
1176 auth_method = "rsa"; 1196 auth_method = "rsa";
1177 break; 1197 break;
1198#endif
1178 default: 1199 default:
1179 fatal("%s: unknown key type %d", __func__, type); 1200 fatal("%s: unknown key type %d", __func__, type);
1180 break; 1201 break;
@@ -1511,6 +1532,7 @@ mm_answer_pty_cleanup(int sock, Buffer *m)
1511 return (0); 1532 return (0);
1512} 1533}
1513 1534
1535#ifdef WITH_SSH1
1514int 1536int
1515mm_answer_sesskey(int sock, Buffer *m) 1537mm_answer_sesskey(int sock, Buffer *m)
1516{ 1538{
@@ -1688,6 +1710,7 @@ mm_answer_rsa_response(int sock, Buffer *m)
1688 1710
1689 return (success); 1711 return (success);
1690} 1712}
1713#endif
1691 1714
1692int 1715int
1693mm_answer_term(int sock, Buffer *req) 1716mm_answer_term(int sock, Buffer *req)
@@ -1792,6 +1815,8 @@ monitor_apply_keystate(struct monitor *pmonitor)
1792 if (options.compression) 1815 if (options.compression)
1793 mm_init_compression(pmonitor->m_zlib); 1816 mm_init_compression(pmonitor->m_zlib);
1794 1817
1818 packet_set_postauth();
1819
1795 if (options.rekey_limit || options.rekey_interval) 1820 if (options.rekey_limit || options.rekey_interval)
1796 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 1821 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
1797 (time_t)options.rekey_interval); 1822 (time_t)options.rekey_interval);
@@ -1828,11 +1853,13 @@ mm_get_kex(Buffer *m)
1828 timingsafe_bcmp(kex->session_id, session_id2, session_id2_len) != 0) 1853 timingsafe_bcmp(kex->session_id, session_id2, session_id2_len) != 0)
1829 fatal("mm_get_get: internal error: bad session id"); 1854 fatal("mm_get_get: internal error: bad session id");
1830 kex->we_need = buffer_get_int(m); 1855 kex->we_need = buffer_get_int(m);
1856#ifdef WITH_OPENSSL
1831 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 1857 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
1832 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 1858 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
1833 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 1859 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
1834 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 1860 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
1835 kex->kex[KEX_ECDH_SHA2] = kexecdh_server; 1861 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
1862#endif
1836 kex->kex[KEX_C25519_SHA256] = kexc25519_server; 1863 kex->kex[KEX_C25519_SHA256] = kexc25519_server;
1837 kex->server = 1; 1864 kex->server = 1;
1838 kex->hostkey_type = buffer_get_int(m); 1865 kex->hostkey_type = buffer_get_int(m);
diff --git a/monitor_fdpass.c b/monitor_fdpass.c
index 7eb6f5c6e..100fa5660 100644
--- a/monitor_fdpass.c
+++ b/monitor_fdpass.c
@@ -34,12 +34,17 @@
34#endif 34#endif
35 35
36#include <errno.h> 36#include <errno.h>
37#ifdef HAVE_POLL_H
38#include <poll.h>
39#endif
40#include <string.h> 37#include <string.h>
41#include <stdarg.h> 38#include <stdarg.h>
42 39
40#ifdef HAVE_POLL_H
41# include <poll.h>
42#else
43# ifdef HAVE_SYS_POLL_H
44# include <sys/poll.h>
45# endif
46#endif
47
43#include "log.h" 48#include "log.h"
44#include "monitor_fdpass.h" 49#include "monitor_fdpass.h"
45 50
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 1a47e4174..45dc16951 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: monitor_wrap.c,v 1.79 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: monitor_wrap.c,v 1.80 2014/04/29 18:01:49 markus Exp $ */
2/* 2/*
3 * Copyright 2002 Niels Provos <provos@citi.umich.edu> 3 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
4 * Copyright 2002 Markus Friedl <markus@openbsd.org> 4 * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -38,14 +38,18 @@
38#include <string.h> 38#include <string.h>
39#include <unistd.h> 39#include <unistd.h>
40 40
41#ifdef WITH_OPENSSL
41#include <openssl/bn.h> 42#include <openssl/bn.h>
42#include <openssl/dh.h> 43#include <openssl/dh.h>
43#include <openssl/evp.h> 44#include <openssl/evp.h>
45#endif
44 46
45#include "openbsd-compat/sys-queue.h" 47#include "openbsd-compat/sys-queue.h"
46#include "xmalloc.h" 48#include "xmalloc.h"
47#include "ssh.h" 49#include "ssh.h"
50#ifdef WITH_OPENSSL
48#include "dh.h" 51#include "dh.h"
52#endif
49#include "buffer.h" 53#include "buffer.h"
50#include "key.h" 54#include "key.h"
51#include "cipher.h" 55#include "cipher.h"
@@ -174,6 +178,7 @@ mm_request_receive_expect(int sock, enum monitor_reqtype type, Buffer *m)
174 rtype, type); 178 rtype, type);
175} 179}
176 180
181#ifdef WITH_OPENSSL
177DH * 182DH *
178mm_choose_dh(int min, int nbits, int max) 183mm_choose_dh(int min, int nbits, int max)
179{ 184{
@@ -207,6 +212,7 @@ mm_choose_dh(int min, int nbits, int max)
207 212
208 return (dh_new_group(g, p)); 213 return (dh_new_group(g, p));
209} 214}
215#endif
210 216
211int 217int
212mm_key_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen) 218mm_key_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen)
@@ -912,6 +918,7 @@ mm_terminate(void)
912 buffer_free(&m); 918 buffer_free(&m);
913} 919}
914 920
921#ifdef WITH_SSH1
915int 922int
916mm_ssh1_session_key(BIGNUM *num) 923mm_ssh1_session_key(BIGNUM *num)
917{ 924{
@@ -931,6 +938,7 @@ mm_ssh1_session_key(BIGNUM *num)
931 938
932 return (rsafail); 939 return (rsafail);
933} 940}
941#endif
934 942
935static void 943static void
936mm_chall_setup(char **name, char **infotxt, u_int *numprompts, 944mm_chall_setup(char **name, char **infotxt, u_int *numprompts,
@@ -1078,6 +1086,7 @@ mm_ssh1_session_id(u_char session_id[16])
1078 buffer_free(&m); 1086 buffer_free(&m);
1079} 1087}
1080 1088
1089#ifdef WITH_SSH1
1081int 1090int
1082mm_auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) 1091mm_auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
1083{ 1092{
@@ -1173,6 +1182,7 @@ mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16])
1173 1182
1174 return (success); 1183 return (success);
1175} 1184}
1185#endif
1176 1186
1177#ifdef SSH_AUDIT_EVENTS 1187#ifdef SSH_AUDIT_EVENTS
1178void 1188void
diff --git a/mux.c b/mux.c
index 882fa61b5..48f7a050f 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: mux.c,v 1.44 2013/07/12 00:19:58 djm Exp $ */ 1/* $OpenBSD: mux.c,v 1.48 2014/07/17 07:22:19 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> 3 * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
4 * 4 *
@@ -105,6 +105,11 @@ struct mux_session_confirm_ctx {
105 u_int rid; 105 u_int rid;
106}; 106};
107 107
108/* Context for stdio fwd open confirmation callback */
109struct mux_stdio_confirm_ctx {
110 u_int rid;
111};
112
108/* Context for global channel callback */ 113/* Context for global channel callback */
109struct mux_channel_confirm_ctx { 114struct mux_channel_confirm_ctx {
110 u_int cid; /* channel id */ 115 u_int cid; /* channel id */
@@ -157,6 +162,7 @@ struct mux_master_state {
157#define MUX_FWD_DYNAMIC 3 162#define MUX_FWD_DYNAMIC 3
158 163
159static void mux_session_confirm(int, int, void *); 164static void mux_session_confirm(int, int, void *);
165static void mux_stdio_confirm(int, int, void *);
160 166
161static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); 167static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *);
162static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); 168static 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)
509} 515}
510 516
511static char * 517static char *
512format_forward(u_int ftype, Forward *fwd) 518format_forward(u_int ftype, struct Forward *fwd)
513{ 519{
514 char *ret; 520 char *ret;
515 521
516 switch (ftype) { 522 switch (ftype) {
517 case MUX_FWD_LOCAL: 523 case MUX_FWD_LOCAL:
518 xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d", 524 xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d",
525 (fwd->listen_path != NULL) ? fwd->listen_path :
519 (fwd->listen_host == NULL) ? 526 (fwd->listen_host == NULL) ?
520 (options.gateway_ports ? "*" : "LOCALHOST") : 527 (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
521 fwd->listen_host, fwd->listen_port, 528 fwd->listen_host, fwd->listen_port,
529 (fwd->connect_path != NULL) ? fwd->connect_path :
522 fwd->connect_host, fwd->connect_port); 530 fwd->connect_host, fwd->connect_port);
523 break; 531 break;
524 case MUX_FWD_DYNAMIC: 532 case MUX_FWD_DYNAMIC:
525 xasprintf(&ret, "dynamic forward %.200s:%d -> *", 533 xasprintf(&ret, "dynamic forward %.200s:%d -> *",
526 (fwd->listen_host == NULL) ? 534 (fwd->listen_host == NULL) ?
527 (options.gateway_ports ? "*" : "LOCALHOST") : 535 (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
528 fwd->listen_host, fwd->listen_port); 536 fwd->listen_host, fwd->listen_port);
529 break; 537 break;
530 case MUX_FWD_REMOTE: 538 case MUX_FWD_REMOTE:
531 xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d", 539 xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d",
540 (fwd->listen_path != NULL) ? fwd->listen_path :
532 (fwd->listen_host == NULL) ? 541 (fwd->listen_host == NULL) ?
533 "LOCALHOST" : fwd->listen_host, 542 "LOCALHOST" : fwd->listen_host,
534 fwd->listen_port, 543 fwd->listen_port,
544 (fwd->connect_path != NULL) ? fwd->connect_path :
535 fwd->connect_host, fwd->connect_port); 545 fwd->connect_host, fwd->connect_port);
536 break; 546 break;
537 default: 547 default:
@@ -551,14 +561,18 @@ compare_host(const char *a, const char *b)
551} 561}
552 562
553static int 563static int
554compare_forward(Forward *a, Forward *b) 564compare_forward(struct Forward *a, struct Forward *b)
555{ 565{
556 if (!compare_host(a->listen_host, b->listen_host)) 566 if (!compare_host(a->listen_host, b->listen_host))
557 return 0; 567 return 0;
568 if (!compare_host(a->listen_path, b->listen_path))
569 return 0;
558 if (a->listen_port != b->listen_port) 570 if (a->listen_port != b->listen_port)
559 return 0; 571 return 0;
560 if (!compare_host(a->connect_host, b->connect_host)) 572 if (!compare_host(a->connect_host, b->connect_host))
561 return 0; 573 return 0;
574 if (!compare_host(a->connect_path, b->connect_path))
575 return 0;
562 if (a->connect_port != b->connect_port) 576 if (a->connect_port != b->connect_port)
563 return 0; 577 return 0;
564 578
@@ -570,7 +584,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
570{ 584{
571 struct mux_channel_confirm_ctx *fctx = ctxt; 585 struct mux_channel_confirm_ctx *fctx = ctxt;
572 char *failmsg = NULL; 586 char *failmsg = NULL;
573 Forward *rfwd; 587 struct Forward *rfwd;
574 Channel *c; 588 Channel *c;
575 Buffer out; 589 Buffer out;
576 590
@@ -587,7 +601,8 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
587 rfwd = &options.remote_forwards[fctx->fid]; 601 rfwd = &options.remote_forwards[fctx->fid];
588 debug("%s: %s for: listen %d, connect %s:%d", __func__, 602 debug("%s: %s for: listen %d, connect %s:%d", __func__,
589 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", 603 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
590 rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); 604 rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path :
605 rfwd->connect_host, rfwd->connect_port);
591 if (type == SSH2_MSG_REQUEST_SUCCESS) { 606 if (type == SSH2_MSG_REQUEST_SUCCESS) {
592 if (rfwd->listen_port == 0) { 607 if (rfwd->listen_port == 0) {
593 rfwd->allocated_port = packet_get_int(); 608 rfwd->allocated_port = packet_get_int();
@@ -607,8 +622,12 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
607 } else { 622 } else {
608 if (rfwd->listen_port == 0) 623 if (rfwd->listen_port == 0)
609 channel_update_permitted_opens(rfwd->handle, -1); 624 channel_update_permitted_opens(rfwd->handle, -1);
610 xasprintf(&failmsg, "remote port forwarding failed for " 625 if (rfwd->listen_path != NULL)
611 "listen port %d", rfwd->listen_port); 626 xasprintf(&failmsg, "remote port forwarding failed for "
627 "listen path %s", rfwd->listen_path);
628 else
629 xasprintf(&failmsg, "remote port forwarding failed for "
630 "listen port %d", rfwd->listen_port);
612 } 631 }
613 fail: 632 fail:
614 error("%s: %s", __func__, failmsg); 633 error("%s: %s", __func__, failmsg);
@@ -627,34 +646,46 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
627static int 646static int
628process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 647process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
629{ 648{
630 Forward fwd; 649 struct Forward fwd;
631 char *fwd_desc = NULL; 650 char *fwd_desc = NULL;
651 char *listen_addr, *connect_addr;
632 u_int ftype; 652 u_int ftype;
633 u_int lport, cport; 653 u_int lport, cport;
634 int i, ret = 0, freefwd = 1; 654 int i, ret = 0, freefwd = 1;
635 655
636 fwd.listen_host = fwd.connect_host = NULL; 656 /* XXX - lport/cport check redundant */
637 if (buffer_get_int_ret(&ftype, m) != 0 || 657 if (buffer_get_int_ret(&ftype, m) != 0 ||
638 (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || 658 (listen_addr = buffer_get_string_ret(m, NULL)) == NULL ||
639 buffer_get_int_ret(&lport, m) != 0 || 659 buffer_get_int_ret(&lport, m) != 0 ||
640 (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || 660 (connect_addr = buffer_get_string_ret(m, NULL)) == NULL ||
641 buffer_get_int_ret(&cport, m) != 0 || 661 buffer_get_int_ret(&cport, m) != 0 ||
642 lport > 65535 || cport > 65535) { 662 (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
663 (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
643 error("%s: malformed message", __func__); 664 error("%s: malformed message", __func__);
644 ret = -1; 665 ret = -1;
645 goto out; 666 goto out;
646 } 667 }
647 fwd.listen_port = lport; 668 if (*listen_addr == '\0') {
648 fwd.connect_port = cport; 669 free(listen_addr);
649 if (*fwd.listen_host == '\0') { 670 listen_addr = NULL;
650 free(fwd.listen_host);
651 fwd.listen_host = NULL;
652 } 671 }
653 if (*fwd.connect_host == '\0') { 672 if (*connect_addr == '\0') {
654 free(fwd.connect_host); 673 free(connect_addr);
655 fwd.connect_host = NULL; 674 connect_addr = NULL;
656 } 675 }
657 676
677 memset(&fwd, 0, sizeof(fwd));
678 fwd.listen_port = lport;
679 if (fwd.listen_port == PORT_STREAMLOCAL)
680 fwd.listen_path = listen_addr;
681 else
682 fwd.listen_host = listen_addr;
683 fwd.connect_port = cport;
684 if (fwd.connect_port == PORT_STREAMLOCAL)
685 fwd.connect_path = connect_addr;
686 else
687 fwd.connect_host = connect_addr;
688
658 debug2("%s: channel %d: request %s", __func__, c->self, 689 debug2("%s: channel %d: request %s", __func__, c->self,
659 (fwd_desc = format_forward(ftype, &fwd))); 690 (fwd_desc = format_forward(ftype, &fwd)));
660 691
@@ -662,25 +693,30 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
662 ftype != MUX_FWD_DYNAMIC) { 693 ftype != MUX_FWD_DYNAMIC) {
663 logit("%s: invalid forwarding type %u", __func__, ftype); 694 logit("%s: invalid forwarding type %u", __func__, ftype);
664 invalid: 695 invalid:
665 free(fwd.listen_host); 696 free(listen_addr);
666 free(fwd.connect_host); 697 free(connect_addr);
667 buffer_put_int(r, MUX_S_FAILURE); 698 buffer_put_int(r, MUX_S_FAILURE);
668 buffer_put_int(r, rid); 699 buffer_put_int(r, rid);
669 buffer_put_cstring(r, "Invalid forwarding request"); 700 buffer_put_cstring(r, "Invalid forwarding request");
670 return 0; 701 return 0;
671 } 702 }
672 if (fwd.listen_port >= 65536) { 703 if (ftype == MUX_FWD_DYNAMIC && fwd.listen_path) {
704 logit("%s: streamlocal and dynamic forwards "
705 "are mutually exclusive", __func__);
706 goto invalid;
707 }
708 if (fwd.listen_port != PORT_STREAMLOCAL && fwd.listen_port >= 65536) {
673 logit("%s: invalid listen port %u", __func__, 709 logit("%s: invalid listen port %u", __func__,
674 fwd.listen_port); 710 fwd.listen_port);
675 goto invalid; 711 goto invalid;
676 } 712 }
677 if (fwd.connect_port >= 65536 || (ftype != MUX_FWD_DYNAMIC && 713 if ((fwd.connect_port != PORT_STREAMLOCAL && fwd.connect_port >= 65536)
678 ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) { 714 || (ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) {
679 logit("%s: invalid connect port %u", __func__, 715 logit("%s: invalid connect port %u", __func__,
680 fwd.connect_port); 716 fwd.connect_port);
681 goto invalid; 717 goto invalid;
682 } 718 }
683 if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL) { 719 if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL && fwd.connect_path == NULL) {
684 logit("%s: missing connect host", __func__); 720 logit("%s: missing connect host", __func__);
685 goto invalid; 721 goto invalid;
686 } 722 }
@@ -731,9 +767,8 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
731 } 767 }
732 768
733 if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { 769 if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) {
734 if (!channel_setup_local_fwd_listener(fwd.listen_host, 770 if (!channel_setup_local_fwd_listener(&fwd,
735 fwd.listen_port, fwd.connect_host, fwd.connect_port, 771 &options.fwd_opts)) {
736 options.gateway_ports)) {
737 fail: 772 fail:
738 logit("slave-requested %s failed", fwd_desc); 773 logit("slave-requested %s failed", fwd_desc);
739 buffer_put_int(r, MUX_S_FAILURE); 774 buffer_put_int(r, MUX_S_FAILURE);
@@ -746,8 +781,7 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
746 } else { 781 } else {
747 struct mux_channel_confirm_ctx *fctx; 782 struct mux_channel_confirm_ctx *fctx;
748 783
749 fwd.handle = channel_request_remote_forwarding(fwd.listen_host, 784 fwd.handle = channel_request_remote_forwarding(&fwd);
750 fwd.listen_port, fwd.connect_host, fwd.connect_port);
751 if (fwd.handle < 0) 785 if (fwd.handle < 0)
752 goto fail; 786 goto fail;
753 add_remote_forward(&options, &fwd); 787 add_remote_forward(&options, &fwd);
@@ -768,7 +802,9 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
768 free(fwd_desc); 802 free(fwd_desc);
769 if (freefwd) { 803 if (freefwd) {
770 free(fwd.listen_host); 804 free(fwd.listen_host);
805 free(fwd.listen_path);
771 free(fwd.connect_host); 806 free(fwd.connect_host);
807 free(fwd.connect_path);
772 } 808 }
773 return ret; 809 return ret;
774} 810}
@@ -776,36 +812,47 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
776static int 812static int
777process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 813process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
778{ 814{
779 Forward fwd, *found_fwd; 815 struct Forward fwd, *found_fwd;
780 char *fwd_desc = NULL; 816 char *fwd_desc = NULL;
781 const char *error_reason = NULL; 817 const char *error_reason = NULL;
818 char *listen_addr = NULL, *connect_addr = NULL;
782 u_int ftype; 819 u_int ftype;
783 int i, listen_port, ret = 0; 820 int i, ret = 0;
784 u_int lport, cport; 821 u_int lport, cport;
785 822
786 fwd.listen_host = fwd.connect_host = NULL;
787 if (buffer_get_int_ret(&ftype, m) != 0 || 823 if (buffer_get_int_ret(&ftype, m) != 0 ||
788 (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || 824 (listen_addr = buffer_get_string_ret(m, NULL)) == NULL ||
789 buffer_get_int_ret(&lport, m) != 0 || 825 buffer_get_int_ret(&lport, m) != 0 ||
790 (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || 826 (connect_addr = buffer_get_string_ret(m, NULL)) == NULL ||
791 buffer_get_int_ret(&cport, m) != 0 || 827 buffer_get_int_ret(&cport, m) != 0 ||
792 lport > 65535 || cport > 65535) { 828 (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
829 (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
793 error("%s: malformed message", __func__); 830 error("%s: malformed message", __func__);
794 ret = -1; 831 ret = -1;
795 goto out; 832 goto out;
796 } 833 }
797 fwd.listen_port = lport;
798 fwd.connect_port = cport;
799 834
800 if (*fwd.listen_host == '\0') { 835 if (*listen_addr == '\0') {
801 free(fwd.listen_host); 836 free(listen_addr);
802 fwd.listen_host = NULL; 837 listen_addr = NULL;
803 } 838 }
804 if (*fwd.connect_host == '\0') { 839 if (*connect_addr == '\0') {
805 free(fwd.connect_host); 840 free(connect_addr);
806 fwd.connect_host = NULL; 841 connect_addr = NULL;
807 } 842 }
808 843
844 memset(&fwd, 0, sizeof(fwd));
845 fwd.listen_port = lport;
846 if (fwd.listen_port == PORT_STREAMLOCAL)
847 fwd.listen_path = listen_addr;
848 else
849 fwd.listen_host = listen_addr;
850 fwd.connect_port = cport;
851 if (fwd.connect_port == PORT_STREAMLOCAL)
852 fwd.connect_path = connect_addr;
853 else
854 fwd.connect_host = connect_addr;
855
809 debug2("%s: channel %d: request cancel %s", __func__, c->self, 856 debug2("%s: channel %d: request cancel %s", __func__, c->self,
810 (fwd_desc = format_forward(ftype, &fwd))); 857 (fwd_desc = format_forward(ftype, &fwd)));
811 858
@@ -840,18 +887,14 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
840 * This shouldn't fail unless we confused the host/port 887 * This shouldn't fail unless we confused the host/port
841 * between options.remote_forwards and permitted_opens. 888 * between options.remote_forwards and permitted_opens.
842 * However, for dynamic allocated listen ports we need 889 * However, for dynamic allocated listen ports we need
843 * to lookup the actual listen port. 890 * to use the actual listen port.
844 */ 891 */
845 listen_port = (fwd.listen_port == 0) ? 892 if (channel_request_rforward_cancel(found_fwd) == -1)
846 found_fwd->allocated_port : fwd.listen_port;
847 if (channel_request_rforward_cancel(fwd.listen_host,
848 listen_port) == -1)
849 error_reason = "port not in permitted opens"; 893 error_reason = "port not in permitted opens";
850 } else { /* local and dynamic forwards */ 894 } else { /* local and dynamic forwards */
851 /* Ditto */ 895 /* Ditto */
852 if (channel_cancel_lport_listener(fwd.listen_host, 896 if (channel_cancel_lport_listener(&fwd, fwd.connect_port,
853 fwd.listen_port, fwd.connect_port, 897 &options.fwd_opts) == -1)
854 options.gateway_ports) == -1)
855 error_reason = "port not found"; 898 error_reason = "port not found";
856 } 899 }
857 900
@@ -860,8 +903,11 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
860 buffer_put_int(r, rid); 903 buffer_put_int(r, rid);
861 904
862 free(found_fwd->listen_host); 905 free(found_fwd->listen_host);
906 free(found_fwd->listen_path);
863 free(found_fwd->connect_host); 907 free(found_fwd->connect_host);
908 free(found_fwd->connect_path);
864 found_fwd->listen_host = found_fwd->connect_host = NULL; 909 found_fwd->listen_host = found_fwd->connect_host = NULL;
910 found_fwd->listen_path = found_fwd->connect_path = NULL;
865 found_fwd->listen_port = found_fwd->connect_port = 0; 911 found_fwd->listen_port = found_fwd->connect_port = 0;
866 } else { 912 } else {
867 buffer_put_int(r, MUX_S_FAILURE); 913 buffer_put_int(r, MUX_S_FAILURE);
@@ -870,8 +916,8 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
870 } 916 }
871 out: 917 out:
872 free(fwd_desc); 918 free(fwd_desc);
873 free(fwd.listen_host); 919 free(listen_addr);
874 free(fwd.connect_host); 920 free(connect_addr);
875 921
876 return ret; 922 return ret;
877} 923}
@@ -883,6 +929,7 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
883 char *reserved, *chost; 929 char *reserved, *chost;
884 u_int cport, i, j; 930 u_int cport, i, j;
885 int new_fd[2]; 931 int new_fd[2];
932 struct mux_stdio_confirm_ctx *cctx;
886 933
887 chost = reserved = NULL; 934 chost = reserved = NULL;
888 if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 935 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)
962 1009
963 channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); 1010 channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
964 1011
965 /* prepare reply */ 1012 cctx = xcalloc(1, sizeof(*cctx));
966 /* XXX defer until channel confirmed */ 1013 cctx->rid = rid;
967 buffer_put_int(r, MUX_S_SESSION_OPENED); 1014 channel_register_open_confirm(nc->self, mux_stdio_confirm, cctx);
968 buffer_put_int(r, rid); 1015 c->mux_pause = 1; /* stop handling messages until open_confirm done */
969 buffer_put_int(r, nc->self);
970 1016
1017 /* reply is deferred, sent by mux_session_confirm */
971 return 0; 1018 return 0;
972} 1019}
973 1020
1021/* Callback on open confirmation in mux master for a mux stdio fwd session. */
1022static void
1023mux_stdio_confirm(int id, int success, void *arg)
1024{
1025 struct mux_stdio_confirm_ctx *cctx = arg;
1026 Channel *c, *cc;
1027 Buffer reply;
1028
1029 if (cctx == NULL)
1030 fatal("%s: cctx == NULL", __func__);
1031 if ((c = channel_by_id(id)) == NULL)
1032 fatal("%s: no channel for id %d", __func__, id);
1033 if ((cc = channel_by_id(c->ctl_chan)) == NULL)
1034 fatal("%s: channel %d lacks control channel %d", __func__,
1035 id, c->ctl_chan);
1036
1037 if (!success) {
1038 debug3("%s: sending failure reply", __func__);
1039 /* prepare reply */
1040 buffer_init(&reply);
1041 buffer_put_int(&reply, MUX_S_FAILURE);
1042 buffer_put_int(&reply, cctx->rid);
1043 buffer_put_cstring(&reply, "Session open refused by peer");
1044 goto done;
1045 }
1046
1047 debug3("%s: sending success reply", __func__);
1048 /* prepare reply */
1049 buffer_init(&reply);
1050 buffer_put_int(&reply, MUX_S_SESSION_OPENED);
1051 buffer_put_int(&reply, cctx->rid);
1052 buffer_put_int(&reply, c->self);
1053
1054 done:
1055 /* Send reply */
1056 buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
1057 buffer_free(&reply);
1058
1059 if (cc->mux_pause <= 0)
1060 fatal("%s: mux_pause %d", __func__, cc->mux_pause);
1061 cc->mux_pause = 0; /* start processing messages again */
1062 c->open_confirm_ctx = NULL;
1063 free(cctx);
1064}
1065
974static int 1066static int
975process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r) 1067process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
976{ 1068{
@@ -1010,7 +1102,7 @@ mux_master_read_cb(Channel *c)
1010{ 1102{
1011 struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; 1103 struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
1012 Buffer in, out; 1104 Buffer in, out;
1013 void *ptr; 1105 const u_char *ptr;
1014 u_int type, rid, have, i; 1106 u_int type, rid, have, i;
1015 int ret = -1; 1107 int ret = -1;
1016 1108
@@ -1133,12 +1225,11 @@ mux_tty_alloc_failed(Channel *c)
1133void 1225void
1134muxserver_listen(void) 1226muxserver_listen(void)
1135{ 1227{
1136 struct sockaddr_un addr;
1137 socklen_t sun_len;
1138 mode_t old_umask; 1228 mode_t old_umask;
1139 char *orig_control_path = options.control_path; 1229 char *orig_control_path = options.control_path;
1140 char rbuf[16+1]; 1230 char rbuf[16+1];
1141 u_int i, r; 1231 u_int i, r;
1232 int oerrno;
1142 1233
1143 if (options.control_path == NULL || 1234 if (options.control_path == NULL ||
1144 options.control_master == SSHCTL_MASTER_NO) 1235 options.control_master == SSHCTL_MASTER_NO)
@@ -1163,24 +1254,12 @@ muxserver_listen(void)
1163 xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf); 1254 xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf);
1164 debug3("%s: temporary control path %s", __func__, options.control_path); 1255 debug3("%s: temporary control path %s", __func__, options.control_path);
1165 1256
1166 memset(&addr, '\0', sizeof(addr));
1167 addr.sun_family = AF_UNIX;
1168 sun_len = offsetof(struct sockaddr_un, sun_path) +
1169 strlen(options.control_path) + 1;
1170
1171 if (strlcpy(addr.sun_path, options.control_path,
1172 sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) {
1173 error("ControlPath \"%s\" too long for Unix domain socket",
1174 options.control_path);
1175 goto disable_mux_master;
1176 }
1177
1178 if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1179 fatal("%s socket(): %s", __func__, strerror(errno));
1180
1181 old_umask = umask(0177); 1257 old_umask = umask(0177);
1182 if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) { 1258 muxserver_sock = unix_listener(options.control_path, 64, 0);
1183 if (errno == EINVAL || errno == EADDRINUSE) { 1259 oerrno = errno;
1260 umask(old_umask);
1261 if (muxserver_sock < 0) {
1262 if (oerrno == EINVAL || oerrno == EADDRINUSE) {
1184 error("ControlSocket %s already exists, " 1263 error("ControlSocket %s already exists, "
1185 "disabling multiplexing", options.control_path); 1264 "disabling multiplexing", options.control_path);
1186 disable_mux_master: 1265 disable_mux_master:
@@ -1193,13 +1272,11 @@ muxserver_listen(void)
1193 options.control_path = NULL; 1272 options.control_path = NULL;
1194 options.control_master = SSHCTL_MASTER_NO; 1273 options.control_master = SSHCTL_MASTER_NO;
1195 return; 1274 return;
1196 } else 1275 } else {
1197 fatal("%s bind(): %s", __func__, strerror(errno)); 1276 /* unix_listener() logs the error */
1277 cleanup_exit(255);
1278 }
1198 } 1279 }
1199 umask(old_umask);
1200
1201 if (listen(muxserver_sock, 64) == -1)
1202 fatal("%s listen(): %s", __func__, strerror(errno));
1203 1280
1204 /* Now atomically "move" the mux socket into position */ 1281 /* Now atomically "move" the mux socket into position */
1205 if (link(options.control_path, orig_control_path) != 0) { 1282 if (link(options.control_path, orig_control_path) != 0) {
@@ -1429,7 +1506,7 @@ mux_client_read_packet(int fd, Buffer *m)
1429{ 1506{
1430 Buffer queue; 1507 Buffer queue;
1431 u_int need, have; 1508 u_int need, have;
1432 void *ptr; 1509 const u_char *ptr;
1433 int oerrno; 1510 int oerrno;
1434 1511
1435 buffer_init(&queue); 1512 buffer_init(&queue);
@@ -1593,7 +1670,7 @@ mux_client_request_terminate(int fd)
1593} 1670}
1594 1671
1595static int 1672static int
1596mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd) 1673mux_client_forward(int fd, int cancel_flag, u_int ftype, struct Forward *fwd)
1597{ 1674{
1598 Buffer m; 1675 Buffer m;
1599 char *e, *fwd_desc; 1676 char *e, *fwd_desc;
@@ -1608,11 +1685,19 @@ mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd)
1608 buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD); 1685 buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD);
1609 buffer_put_int(&m, muxclient_request_id); 1686 buffer_put_int(&m, muxclient_request_id);
1610 buffer_put_int(&m, ftype); 1687 buffer_put_int(&m, ftype);
1611 buffer_put_cstring(&m, 1688 if (fwd->listen_path != NULL) {
1612 fwd->listen_host == NULL ? "" : fwd->listen_host); 1689 buffer_put_cstring(&m, fwd->listen_path);
1690 } else {
1691 buffer_put_cstring(&m,
1692 fwd->listen_host == NULL ? "" : fwd->listen_host);
1693 }
1613 buffer_put_int(&m, fwd->listen_port); 1694 buffer_put_int(&m, fwd->listen_port);
1614 buffer_put_cstring(&m, 1695 if (fwd->connect_path != NULL) {
1615 fwd->connect_host == NULL ? "" : fwd->connect_host); 1696 buffer_put_cstring(&m, fwd->connect_path);
1697 } else {
1698 buffer_put_cstring(&m,
1699 fwd->connect_host == NULL ? "" : fwd->connect_host);
1700 }
1616 buffer_put_int(&m, fwd->connect_port); 1701 buffer_put_int(&m, fwd->connect_port);
1617 1702
1618 if (mux_client_write_packet(fd, &m) != 0) 1703 if (mux_client_write_packet(fd, &m) != 0)
@@ -1922,7 +2007,7 @@ mux_client_request_stdio_fwd(int fd)
1922 case MUX_S_FAILURE: 2007 case MUX_S_FAILURE:
1923 e = buffer_get_string(&m, NULL); 2008 e = buffer_get_string(&m, NULL);
1924 buffer_free(&m); 2009 buffer_free(&m);
1925 fatal("%s: stdio forwarding request failed: %s", __func__, e); 2010 fatal("Stdio forwarding request failed: %s", e);
1926 default: 2011 default:
1927 buffer_free(&m); 2012 buffer_free(&m);
1928 error("%s: unexpected response from master 0x%08x", 2013 error("%s: unexpected response from master 0x%08x",
diff --git a/myproposal.h b/myproposal.h
index 3a0f5aeab..b35b2b8bd 100644
--- a/myproposal.h
+++ b/myproposal.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: myproposal.h,v 1.35 2013/12/06 13:39:49 markus Exp $ */ 1/* $OpenBSD: myproposal.h,v 1.41 2014/07/11 13:54:34 tedu Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000 Markus Friedl. All rights reserved.
@@ -69,23 +69,28 @@
69#ifdef HAVE_EVP_SHA256 69#ifdef HAVE_EVP_SHA256
70# define KEX_SHA256_METHODS \ 70# define KEX_SHA256_METHODS \
71 "diffie-hellman-group-exchange-sha256," 71 "diffie-hellman-group-exchange-sha256,"
72#define KEX_CURVE25519_METHODS \
73 "curve25519-sha256@libssh.org,"
74#define SHA2_HMAC_MODES \ 72#define SHA2_HMAC_MODES \
75 "hmac-sha2-256," \ 73 "hmac-sha2-256," \
76 "hmac-sha2-512," 74 "hmac-sha2-512,"
77#else 75#else
78# define KEX_SHA256_METHODS 76# define KEX_SHA256_METHODS
79# define KEX_CURVE25519_METHODS
80# define SHA2_HMAC_MODES 77# define SHA2_HMAC_MODES
81#endif 78#endif
82 79
83# define KEX_DEFAULT_KEX \ 80#ifdef WITH_OPENSSL
81# ifdef HAVE_EVP_SHA256
82# define KEX_CURVE25519_METHODS "curve25519-sha256@libssh.org,"
83# else
84# define KEX_CURVE25519_METHODS ""
85# endif
86#define KEX_SERVER_KEX \
84 KEX_CURVE25519_METHODS \ 87 KEX_CURVE25519_METHODS \
85 KEX_ECDH_METHODS \ 88 KEX_ECDH_METHODS \
86 KEX_SHA256_METHODS \ 89 KEX_SHA256_METHODS \
90 "diffie-hellman-group14-sha1"
91
92#define KEX_CLIENT_KEX KEX_SERVER_KEX "," \
87 "diffie-hellman-group-exchange-sha1," \ 93 "diffie-hellman-group-exchange-sha1," \
88 "diffie-hellman-group14-sha1," \
89 "diffie-hellman-group1-sha1" 94 "diffie-hellman-group1-sha1"
90 95
91#define KEX_DEFAULT_PK_ALG \ 96#define KEX_DEFAULT_PK_ALG \
@@ -102,47 +107,91 @@
102 107
103/* the actual algorithms */ 108/* the actual algorithms */
104 109
105#define KEX_DEFAULT_ENCRYPT \ 110#define KEX_SERVER_ENCRYPT \
106 "aes128-ctr,aes192-ctr,aes256-ctr," \ 111 "aes128-ctr,aes192-ctr,aes256-ctr," \
107 "arcfour256,arcfour128," \
108 AESGCM_CIPHER_MODES \ 112 AESGCM_CIPHER_MODES \
109 "chacha20-poly1305@openssh.com," \ 113 "chacha20-poly1305@openssh.com"
114
115#define KEX_CLIENT_ENCRYPT KEX_SERVER_ENCRYPT "," \
116 "arcfour256,arcfour128," \
110 "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ 117 "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \
111 "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se" 118 "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se"
112 119
113#define KEX_DEFAULT_MAC \ 120#define KEX_SERVER_MAC \
114 "hmac-md5-etm@openssh.com," \
115 "hmac-sha1-etm@openssh.com," \
116 "umac-64-etm@openssh.com," \ 121 "umac-64-etm@openssh.com," \
117 "umac-128-etm@openssh.com," \ 122 "umac-128-etm@openssh.com," \
118 "hmac-sha2-256-etm@openssh.com," \ 123 "hmac-sha2-256-etm@openssh.com," \
119 "hmac-sha2-512-etm@openssh.com," \ 124 "hmac-sha2-512-etm@openssh.com," \
125 "hmac-sha1-etm@openssh.com," \
126 "umac-64@openssh.com," \
127 "umac-128@openssh.com," \
128 "hmac-sha2-256," \
129 "hmac-sha2-512," \
130 "hmac-sha1"
131
132#define KEX_CLIENT_MAC KEX_SERVER_MAC "," \
133 "hmac-md5-etm@openssh.com," \
120 "hmac-ripemd160-etm@openssh.com," \ 134 "hmac-ripemd160-etm@openssh.com," \
121 "hmac-sha1-96-etm@openssh.com," \ 135 "hmac-sha1-96-etm@openssh.com," \
122 "hmac-md5-96-etm@openssh.com," \ 136 "hmac-md5-96-etm@openssh.com," \
123 "hmac-md5," \ 137 "hmac-md5," \
124 "hmac-sha1," \
125 "umac-64@openssh.com," \
126 "umac-128@openssh.com," \
127 SHA2_HMAC_MODES \
128 "hmac-ripemd160," \ 138 "hmac-ripemd160," \
129 "hmac-ripemd160@openssh.com," \ 139 "hmac-ripemd160@openssh.com," \
130 "hmac-sha1-96," \ 140 "hmac-sha1-96," \
131 "hmac-md5-96" 141 "hmac-md5-96"
132 142
143#else
144
145#define KEX_SERVER_KEX \
146 "curve25519-sha256@libssh.org"
147#define KEX_DEFAULT_PK_ALG \
148 "ssh-ed25519-cert-v01@openssh.com," \
149 "ssh-ed25519"
150#define KEX_SERVER_ENCRYPT \
151 "aes128-ctr,aes192-ctr,aes256-ctr," \
152 "chacha20-poly1305@openssh.com"
153#define KEX_SERVER_MAC \
154 "umac-64-etm@openssh.com," \
155 "umac-128-etm@openssh.com," \
156 "hmac-sha2-256-etm@openssh.com," \
157 "hmac-sha2-512-etm@openssh.com," \
158 "hmac-sha1-etm@openssh.com," \
159 "umac-64@openssh.com," \
160 "umac-128@openssh.com," \
161 "hmac-sha2-256," \
162 "hmac-sha2-512," \
163 "hmac-sha1"
164
165#define KEX_CLIENT_KEX KEX_SERVER_KEX
166#define KEX_CLIENT_ENCRYPT KEX_SERVER_ENCRYPT
167#define KEX_CLIENT_MAC KEX_SERVER_MAC
168
169#endif /* WITH_OPENSSL */
170
133#define KEX_DEFAULT_COMP "none,zlib@openssh.com,zlib" 171#define KEX_DEFAULT_COMP "none,zlib@openssh.com,zlib"
134#define KEX_DEFAULT_LANG "" 172#define KEX_DEFAULT_LANG ""
135 173
174#define KEX_CLIENT \
175 KEX_CLIENT_KEX, \
176 KEX_DEFAULT_PK_ALG, \
177 KEX_CLIENT_ENCRYPT, \
178 KEX_CLIENT_ENCRYPT, \
179 KEX_CLIENT_MAC, \
180 KEX_CLIENT_MAC, \
181 KEX_DEFAULT_COMP, \
182 KEX_DEFAULT_COMP, \
183 KEX_DEFAULT_LANG, \
184 KEX_DEFAULT_LANG
136 185
137static char *myproposal[PROPOSAL_MAX] = { 186#define KEX_SERVER \
138 KEX_DEFAULT_KEX, 187 KEX_SERVER_KEX, \
139 KEX_DEFAULT_PK_ALG, 188 KEX_DEFAULT_PK_ALG, \
140 KEX_DEFAULT_ENCRYPT, 189 KEX_SERVER_ENCRYPT, \
141 KEX_DEFAULT_ENCRYPT, 190 KEX_SERVER_ENCRYPT, \
142 KEX_DEFAULT_MAC, 191 KEX_SERVER_MAC, \
143 KEX_DEFAULT_MAC, 192 KEX_SERVER_MAC, \
144 KEX_DEFAULT_COMP, 193 KEX_DEFAULT_COMP, \
145 KEX_DEFAULT_COMP, 194 KEX_DEFAULT_COMP, \
146 KEX_DEFAULT_LANG, 195 KEX_DEFAULT_LANG, \
147 KEX_DEFAULT_LANG 196 KEX_DEFAULT_LANG
148}; 197
diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in
index 6ecfb93d5..ab1a3e315 100644
--- a/openbsd-compat/Makefile.in
+++ b/openbsd-compat/Makefile.in
@@ -1,4 +1,4 @@
1# $Id: Makefile.in,v 1.55 2014/02/04 00:37:50 djm Exp $ 1# $Id: Makefile.in,v 1.56 2014/09/30 23:43:08 djm Exp $
2 2
3sysconfdir=@sysconfdir@ 3sysconfdir=@sysconfdir@
4piddir=@piddir@ 4piddir=@piddir@
@@ -18,7 +18,7 @@ LDFLAGS=-L. @LDFLAGS@
18 18
19OPENBSD=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 19OPENBSD=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
20 20
21COMPAT=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 21COMPAT=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
22 22
23PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o 23PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
24 24
diff --git a/openbsd-compat/arc4random.c b/openbsd-compat/arc4random.c
index eac073cc0..09dbfda16 100644
--- a/openbsd-compat/arc4random.c
+++ b/openbsd-compat/arc4random.c
@@ -87,7 +87,7 @@ _rs_stir(void)
87 _rs_init(rnd, sizeof(rnd)); 87 _rs_init(rnd, sizeof(rnd));
88 } else 88 } else
89 _rs_rekey(rnd, sizeof(rnd)); 89 _rs_rekey(rnd, sizeof(rnd));
90 memset(rnd, 0, sizeof(rnd)); 90 explicit_bzero(rnd, sizeof(rnd));
91 91
92 /* invalidate rs_buf */ 92 /* invalidate rs_buf */
93 rs_have = 0; 93 rs_have = 0;
@@ -229,7 +229,7 @@ arc4random_buf(void *_buf, size_t n)
229 buf[i] = r & 0xff; 229 buf[i] = r & 0xff;
230 r >>= 8; 230 r >>= 8;
231 } 231 }
232 i = r = 0; 232 explicit_bzero(&r, sizeof(r));
233} 233}
234#endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */ 234#endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */
235 235
diff --git a/openbsd-compat/bsd-cygwin_util.c b/openbsd-compat/bsd-cygwin_util.c
index 267e77a11..a2d82126d 100644
--- a/openbsd-compat/bsd-cygwin_util.c
+++ b/openbsd-compat/bsd-cygwin_util.c
@@ -57,6 +57,22 @@ check_ntsec(const char *filename)
57 return (pathconf(filename, _PC_POSIX_PERMISSIONS)); 57 return (pathconf(filename, _PC_POSIX_PERMISSIONS));
58} 58}
59 59
60const char *
61cygwin_ssh_privsep_user()
62{
63 static char cyg_privsep_user[DNLEN + UNLEN + 2];
64
65 if (!cyg_privsep_user[0])
66 {
67#ifdef CW_CYGNAME_FROM_WINNAME
68 if (cygwin_internal (CW_CYGNAME_FROM_WINNAME, "sshd", cyg_privsep_user,
69 sizeof cyg_privsep_user) != 0)
70#endif
71 strcpy (cyg_privsep_user, "sshd");
72 }
73 return cyg_privsep_user;
74}
75
60#define NL(x) x, (sizeof (x) - 1) 76#define NL(x) x, (sizeof (x) - 1)
61#define WENV_SIZ (sizeof (wenv_arr) / sizeof (wenv_arr[0])) 77#define WENV_SIZ (sizeof (wenv_arr) / sizeof (wenv_arr[0]))
62 78
diff --git a/openbsd-compat/bsd-cygwin_util.h b/openbsd-compat/bsd-cygwin_util.h
index 1177366f1..79cb2a197 100644
--- a/openbsd-compat/bsd-cygwin_util.h
+++ b/openbsd-compat/bsd-cygwin_util.h
@@ -1,4 +1,4 @@
1/* $Id: bsd-cygwin_util.h,v 1.17 2014/01/18 10:04:00 dtucker Exp $ */ 1/* $Id: bsd-cygwin_util.h,v 1.18 2014/05/27 04:34:43 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000, 2001, 2011, 2013 Corinna Vinschen <vinschen@redhat.com> 4 * Copyright (c) 2000, 2001, 2011, 2013 Corinna Vinschen <vinschen@redhat.com>
@@ -39,6 +39,8 @@
39/* Avoid including windows headers. */ 39/* Avoid including windows headers. */
40typedef void *HANDLE; 40typedef void *HANDLE;
41#define INVALID_HANDLE_VALUE ((HANDLE) -1) 41#define INVALID_HANDLE_VALUE ((HANDLE) -1)
42#define DNLEN 16
43#define UNLEN 256
42 44
43/* Cygwin functions for which declarations are only available when including 45/* Cygwin functions for which declarations are only available when including
44 windows headers, so we have to define them here explicitely. */ 46 windows headers, so we have to define them here explicitely. */
@@ -48,6 +50,8 @@ extern void cygwin_set_impersonation_token (const HANDLE);
48#include <sys/cygwin.h> 50#include <sys/cygwin.h>
49#include <io.h> 51#include <io.h>
50 52
53#define CYGWIN_SSH_PRIVSEP_USER (cygwin_ssh_privsep_user())
54const char *cygwin_ssh_privsep_user();
51 55
52int binary_open(const char *, int , ...); 56int binary_open(const char *, int , ...);
53int check_ntsec(const char *); 57int check_ntsec(const char *);
diff --git a/openbsd-compat/bsd-snprintf.c b/openbsd-compat/bsd-snprintf.c
index 975991e7f..23a635989 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,
538 } 538 }
539 while (*value && (cnt < max)) { 539 while (*value && (cnt < max)) {
540 DOPR_OUTCH(buffer, *currlen, maxlen, *value); 540 DOPR_OUTCH(buffer, *currlen, maxlen, *value);
541 *value++; 541 value++;
542 ++cnt; 542 ++cnt;
543 } 543 }
544 while ((padlen < 0) && (cnt < max)) { 544 while ((padlen < 0) && (cnt < max)) {
@@ -553,7 +553,7 @@ fmtstr(char *buffer, size_t *currlen, size_t maxlen,
553 553
554static int 554static int
555fmtint(char *buffer, size_t *currlen, size_t maxlen, 555fmtint(char *buffer, size_t *currlen, size_t maxlen,
556 LLONG value, int base, int min, int max, int flags) 556 intmax_t value, int base, int min, int max, int flags)
557{ 557{
558 int signvalue = 0; 558 int signvalue = 0;
559 unsigned LLONG uvalue; 559 unsigned LLONG uvalue;
diff --git a/openbsd-compat/explicit_bzero.c b/openbsd-compat/explicit_bzero.c
index b106741e5..3c85a4843 100644
--- a/openbsd-compat/explicit_bzero.c
+++ b/openbsd-compat/explicit_bzero.c
@@ -7,14 +7,34 @@
7 7
8#include "includes.h" 8#include "includes.h"
9 9
10/*
11 * explicit_bzero - don't let the compiler optimize away bzero
12 */
13
10#ifndef HAVE_EXPLICIT_BZERO 14#ifndef HAVE_EXPLICIT_BZERO
11 15
16#ifdef HAVE_MEMSET_S
17
18void
19explicit_bzero(void *p, size_t n)
20{
21 (void)memset_s(p, n, 0, n);
22}
23
24#else /* HAVE_MEMSET_S */
25
12/* 26/*
13 * explicit_bzero - don't let the compiler optimize away bzero 27 * Indirect bzero through a volatile pointer to hopefully avoid
28 * dead-store optimisation eliminating the call.
14 */ 29 */
30static void (* volatile ssh_bzero)(void *, size_t) = bzero;
31
15void 32void
16explicit_bzero(void *p, size_t n) 33explicit_bzero(void *p, size_t n)
17{ 34{
18 bzero(p, n); 35 ssh_bzero(p, n);
19} 36}
20#endif 37
38#endif /* HAVE_MEMSET_S */
39
40#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 000000000..6c2ffb64b
--- /dev/null
+++ b/openbsd-compat/kludge-fd_set.c
@@ -0,0 +1,28 @@
1/* Placed in the public domain. */
2
3/*
4 * _FORTIFY_SOURCE includes a misguided check for FD_SET(n)/FD_ISSET(b)
5 * where n > FD_SETSIZE. This breaks OpenSSH and other programs that
6 * explicitly allocate fd_sets. To avoid this, we wrap FD_SET in a
7 * function compiled without _FORTIFY_SOURCE.
8 */
9
10#include "config.h"
11
12#if defined(HAVE_FEATURES_H) && defined(_FORTIFY_SOURCE)
13# include <features.h>
14# if defined(__GNU_LIBRARY__) && defined(__GLIBC_PREREQ)
15# if __GLIBC_PREREQ(2, 15) && (_FORTIFY_SOURCE > 0)
16# undef _FORTIFY_SOURCE
17# undef __USE_FORTIFY_LEVEL
18# include <sys/socket.h>
19void kludge_FD_SET(int n, fd_set *set) {
20 FD_SET(n, set);
21}
22int kludge_FD_ISSET(int n, fd_set *set) {
23 return FD_ISSET(n, set);
24}
25# endif /* __GLIBC_PREREQ(2, 15) && (_FORTIFY_SOURCE > 0) */
26# endif /* __GNU_LIBRARY__ && __GLIBC_PREREQ */
27#endif /* HAVE_FEATURES_H && _FORTIFY_SOURCE */
28
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
index bc9888e31..ce6abae82 100644
--- a/openbsd-compat/openbsd-compat.h
+++ b/openbsd-compat/openbsd-compat.h
@@ -1,4 +1,4 @@
1/* $Id: openbsd-compat.h,v 1.61 2014/02/04 00:18:23 djm Exp $ */ 1/* $Id: openbsd-compat.h,v 1.62 2014/09/30 23:43:08 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1999-2003 Damien Miller. All rights reserved. 4 * Copyright (c) 1999-2003 Damien Miller. All rights reserved.
@@ -268,4 +268,20 @@ char *shadow_pw(struct passwd *pw);
268#include "port-tun.h" 268#include "port-tun.h"
269#include "port-uw.h" 269#include "port-uw.h"
270 270
271/* _FORTIFY_SOURCE breaks FD_ISSET(n)/FD_SET(n) for n > FD_SETSIZE. Avoid. */
272#if defined(HAVE_FEATURES_H) && defined(_FORTIFY_SOURCE)
273# include <features.h>
274# if defined(__GNU_LIBRARY__) && defined(__GLIBC_PREREQ)
275# if __GLIBC_PREREQ(2, 15) && (_FORTIFY_SOURCE > 0)
276# include <sys/socket.h> /* Ensure include guard is defined */
277# undef FD_SET
278# undef FD_ISSET
279# define FD_SET(n, set) kludge_FD_SET(n, set)
280# define FD_ISSET(n, set) kludge_FD_ISSET(n, set)
281void kludge_FD_SET(int, fd_set *);
282int kludge_FD_ISSET(int, fd_set *);
283# endif /* __GLIBC_PREREQ(2, 15) && (_FORTIFY_SOURCE > 0) */
284# endif /* __GNU_LIBRARY__ && __GLIBC_PREREQ */
285#endif /* HAVE_FEATURES_H && _FORTIFY_SOURCE */
286
271#endif /* _OPENBSD_COMPAT_H */ 287#endif /* _OPENBSD_COMPAT_H */
diff --git a/openbsd-compat/openssl-compat.c b/openbsd-compat/openssl-compat.c
index 885c121f2..36570e4ad 100644
--- a/openbsd-compat/openssl-compat.c
+++ b/openbsd-compat/openssl-compat.c
@@ -1,4 +1,4 @@
1/* $Id: openssl-compat.c,v 1.17 2014/02/13 05:38:33 dtucker Exp $ */ 1/* $Id: openssl-compat.c,v 1.19 2014/07/02 05:28:07 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au> 4 * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au>
@@ -16,6 +16,7 @@
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 17 */
18 18
19#define SSH_DONT_OVERLOAD_OPENSSL_FUNCS
19#include "includes.h" 20#include "includes.h"
20 21
21#include <stdarg.h> 22#include <stdarg.h>
@@ -26,147 +27,44 @@
26# include <openssl/conf.h> 27# include <openssl/conf.h>
27#endif 28#endif
28 29
29#ifndef HAVE_RSA_GET_DEFAULT_METHOD
30# include <openssl/rsa.h>
31#endif
32
33#include "log.h" 30#include "log.h"
34 31
35#define SSH_DONT_OVERLOAD_OPENSSL_FUNCS
36#include "openssl-compat.h" 32#include "openssl-compat.h"
37 33
38#ifdef SSH_OLD_EVP 34/*
39int 35 * OpenSSL version numbers: MNNFFPPS: major minor fix patch status
40ssh_EVP_CipherInit(EVP_CIPHER_CTX *evp, const EVP_CIPHER *type, 36 * We match major, minor, fix and status (not patch) for <1.0.0.
41 unsigned char *key, unsigned char *iv, int enc) 37 * After that, we acceptable compatible fix versions (so we
42{ 38 * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed
43 EVP_CipherInit(evp, type, key, iv, enc); 39 * within a patch series.
44 return 1; 40 */
45}
46
47int
48ssh_EVP_Cipher(EVP_CIPHER_CTX *evp, char *dst, char *src, int len)
49{
50 EVP_Cipher(evp, dst, src, len);
51 return 1;
52}
53
54int
55ssh_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *evp)
56{
57 EVP_CIPHER_CTX_cleanup(evp);
58 return 1;
59}
60#endif
61
62#ifndef HAVE_EVP_DIGESTINIT_EX
63int
64EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, void *engine)
65{
66 if (engine != NULL)
67 fatal("%s: ENGINE is not supported", __func__);
68# ifdef OPENSSL_EVP_DIGESTUPDATE_VOID
69 EVP_DigestInit(ctx, md);
70 return 1;
71# else
72 return EVP_DigestInit(ctx, md);
73# endif
74}
75#endif
76
77#ifndef HAVE_EVP_DIGESTFINAL_EX
78int
79EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s)
80{
81# ifdef OPENSSL_EVP_DIGESTUPDATE_VOID
82 EVP_DigestFinal(ctx, md, s);
83 return 1;
84# else
85 return EVP_DigestFinal(ctx, md, s);
86# endif
87}
88#endif
89
90#ifdef OPENSSL_EVP_DIGESTUPDATE_VOID
91int
92ssh_EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt)
93{
94 EVP_DigestUpdate(ctx, d, cnt);
95 return 1;
96}
97#endif
98
99#ifndef HAVE_EVP_MD_CTX_COPY_EX
100int
101EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
102{
103 return EVP_MD_CTX_copy(out, in);
104}
105#endif
106
107#ifndef HAVE_BN_IS_PRIME_EX
108int
109BN_is_prime_ex(const BIGNUM *p, int nchecks, BN_CTX *ctx, void *cb)
110{
111 if (cb != NULL)
112 fatal("%s: callback args not supported", __func__);
113 return BN_is_prime(p, nchecks, NULL, ctx, NULL);
114}
115#endif
116
117#ifndef HAVE_RSA_GENERATE_KEY_EX
118int
119RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *bn_e, void *cb)
120{
121 RSA *new_rsa, tmp_rsa;
122 unsigned long e;
123
124 if (cb != NULL)
125 fatal("%s: callback args not supported", __func__);
126 e = BN_get_word(bn_e);
127 if (e == 0xffffffffL)
128 fatal("%s: value of e too large", __func__);
129 new_rsa = RSA_generate_key(bits, e, NULL, NULL);
130 if (new_rsa == NULL)
131 return 0;
132 /* swap rsa/new_rsa then free new_rsa */
133 tmp_rsa = *rsa;
134 *rsa = *new_rsa;
135 *new_rsa = tmp_rsa;
136 RSA_free(new_rsa);
137 return 1;
138}
139#endif
140 41
141#ifndef HAVE_DSA_GENERATE_PARAMETERS_EX
142int 42int
143DSA_generate_parameters_ex(DSA *dsa, int bits, const unsigned char *seed, 43ssh_compatible_openssl(long headerver, long libver)
144 int seed_len, int *counter_ret, unsigned long *h_ret, void *cb)
145{ 44{
146 DSA *new_dsa, tmp_dsa; 45 long mask, hfix, lfix;
147 46
148 if (cb != NULL) 47 /* exact match is always OK */
149 fatal("%s: callback args not supported", __func__); 48 if (headerver == libver)
150 new_dsa = DSA_generate_parameters(bits, (unsigned char *)seed, seed_len, 49 return 1;
151 counter_ret, h_ret, NULL, NULL); 50
152 if (new_dsa == NULL) 51 /* for versions < 1.0.0, major,minor,fix,status must match */
153 return 0; 52 if (headerver < 0x1000000f) {
154 /* swap dsa/new_dsa then free new_dsa */ 53 mask = 0xfffff00fL; /* major,minor,fix,status */
155 tmp_dsa = *dsa; 54 return (headerver & mask) == (libver & mask);
156 *dsa = *new_dsa; 55 }
157 *new_dsa = tmp_dsa; 56
158 DSA_free(new_dsa); 57 /*
159 return 1; 58 * For versions >= 1.0.0, major,minor,status must match and library
160} 59 * fix version must be equal to or newer than the header.
161#endif 60 */
162 61 mask = 0xfff0000fL; /* major,minor,status */
163#ifndef HAVE_RSA_GET_DEFAULT_METHOD 62 hfix = (headerver & 0x000ff000) >> 12;
164RSA_METHOD * 63 lfix = (libver & 0x000ff000) >> 12;
165RSA_get_default_method(void) 64 if ( (headerver & mask) == (libver & mask) && lfix >= hfix)
166{ 65 return 1;
167 return RSA_PKCS1_SSLeay(); 66 return 0;
168} 67}
169#endif
170 68
171#ifdef USE_OPENSSL_ENGINE 69#ifdef USE_OPENSSL_ENGINE
172void 70void
diff --git a/openbsd-compat/openssl-compat.h b/openbsd-compat/openssl-compat.h
index 276b9706d..3695d412b 100644
--- a/openbsd-compat/openssl-compat.h
+++ b/openbsd-compat/openssl-compat.h
@@ -1,4 +1,4 @@
1/* $Id: openssl-compat.h,v 1.26 2014/02/13 05:38:33 dtucker Exp $ */ 1/* $Id: openssl-compat.h,v 1.31 2014/08/29 18:18:29 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au> 4 * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au>
@@ -16,28 +16,19 @@
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 17 */
18 18
19#ifndef _OPENSSL_COMPAT_H
20#define _OPENSSL_COMPAT_H
21
19#include "includes.h" 22#include "includes.h"
20#include <openssl/opensslv.h> 23#include <openssl/opensslv.h>
21#include <openssl/evp.h> 24#include <openssl/evp.h>
22#include <openssl/rsa.h> 25#include <openssl/rsa.h>
23#include <openssl/dsa.h> 26#include <openssl/dsa.h>
24 27
25/* Only in 0.9.8 */ 28int ssh_compatible_openssl(long, long);
26#ifndef OPENSSL_DSA_MAX_MODULUS_BITS
27# define OPENSSL_DSA_MAX_MODULUS_BITS 10000
28#endif
29#ifndef OPENSSL_RSA_MAX_MODULUS_BITS
30# define OPENSSL_RSA_MAX_MODULUS_BITS 16384
31#endif
32
33/* OPENSSL_free() is Free() in versions before OpenSSL 0.9.6 */
34#if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090600f)
35# define OPENSSL_free(x) Free(x)
36#endif
37 29
38#if OPENSSL_VERSION_NUMBER < 0x00906000L 30#if (OPENSSL_VERSION_NUMBER <= 0x0090805fL)
39# define SSH_OLD_EVP 31# error OpenSSL 0.9.8f or greater is required
40# define EVP_CIPHER_CTX_get_app_data(e) ((e)->app_data)
41#endif 32#endif
42 33
43#if OPENSSL_VERSION_NUMBER < 0x10000001L 34#if OPENSSL_VERSION_NUMBER < 0x10000001L
@@ -46,27 +37,17 @@
46# define LIBCRYPTO_EVP_INL_TYPE size_t 37# define LIBCRYPTO_EVP_INL_TYPE size_t
47#endif 38#endif
48 39
49#if (OPENSSL_VERSION_NUMBER < 0x00907000L) || defined(OPENSSL_LOBOTOMISED_AES) 40#ifndef OPENSSL_RSA_MAX_MODULUS_BITS
50# define USE_BUILTIN_RIJNDAEL 41# define OPENSSL_RSA_MAX_MODULUS_BITS 16384
51#endif 42#endif
52 43#ifndef OPENSSL_DSA_MAX_MODULUS_BITS
53#ifdef USE_BUILTIN_RIJNDAEL 44# define OPENSSL_DSA_MAX_MODULUS_BITS 10000
54# include "rijndael.h"
55# define AES_KEY rijndael_ctx
56# define AES_BLOCK_SIZE 16
57# define AES_encrypt(a, b, c) rijndael_encrypt(c, a, b)
58# define AES_set_encrypt_key(a, b, c) rijndael_set_key(c, (char *)a, b, 1)
59# define EVP_aes_128_cbc evp_rijndael
60# define EVP_aes_192_cbc evp_rijndael
61# define EVP_aes_256_cbc evp_rijndael
62const EVP_CIPHER *evp_rijndael(void);
63void ssh_rijndael_iv(EVP_CIPHER_CTX *, int, u_char *, u_int);
64#endif 45#endif
65 46
66#ifndef OPENSSL_HAVE_EVPCTR 47#ifndef OPENSSL_HAVE_EVPCTR
67#define EVP_aes_128_ctr evp_aes_128_ctr 48# define EVP_aes_128_ctr evp_aes_128_ctr
68#define EVP_aes_192_ctr evp_aes_128_ctr 49# define EVP_aes_192_ctr evp_aes_128_ctr
69#define EVP_aes_256_ctr evp_aes_128_ctr 50# define EVP_aes_256_ctr evp_aes_128_ctr
70const EVP_CIPHER *evp_aes_128_ctr(void); 51const EVP_CIPHER *evp_aes_128_ctr(void);
71void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, size_t); 52void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, size_t);
72#endif 53#endif
@@ -88,26 +69,9 @@ void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, size_t);
88# endif 69# endif
89#endif 70#endif
90 71
91#if OPENSSL_VERSION_NUMBER < 0x00907000L
92#define EVP_X_STATE(evp) &(evp).c
93#define EVP_X_STATE_LEN(evp) sizeof((evp).c)
94#else
95#define EVP_X_STATE(evp) (evp).cipher_data
96#define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size
97#endif
98
99/* OpenSSL 0.9.8e returns cipher key len not context key len */
100#if (OPENSSL_VERSION_NUMBER == 0x0090805fL)
101# define EVP_CIPHER_CTX_key_length(c) ((c)->key_len)
102#endif
103
104#ifndef HAVE_RSA_GET_DEFAULT_METHOD
105RSA_METHOD *RSA_get_default_method(void);
106#endif
107
108/* 72/*
109 * We overload some of the OpenSSL crypto functions with ssh_* equivalents 73 * We overload some of the OpenSSL crypto functions with ssh_* equivalents
110 * which cater for older and/or less featureful OpenSSL version. 74 * to automatically handle OpenSSL engine initialisation.
111 * 75 *
112 * In order for the compat library to call the real functions, it must 76 * In order for the compat library to call the real functions, it must
113 * define SSH_DONT_OVERLOAD_OPENSSL_FUNCS before including this file and 77 * define SSH_DONT_OVERLOAD_OPENSSL_FUNCS before including this file and
@@ -115,19 +79,6 @@ RSA_METHOD *RSA_get_default_method(void);
115 */ 79 */
116#ifndef SSH_DONT_OVERLOAD_OPENSSL_FUNCS 80#ifndef SSH_DONT_OVERLOAD_OPENSSL_FUNCS
117 81
118# ifdef SSH_OLD_EVP
119# ifdef EVP_Cipher
120# undef EVP_Cipher
121# endif
122# define EVP_CipherInit(a,b,c,d,e) ssh_EVP_CipherInit((a),(b),(c),(d),(e))
123# define EVP_Cipher(a,b,c,d) ssh_EVP_Cipher((a),(b),(c),(d))
124# define EVP_CIPHER_CTX_cleanup(a) ssh_EVP_CIPHER_CTX_cleanup((a))
125# endif /* SSH_OLD_EVP */
126
127# ifdef OPENSSL_EVP_DIGESTUPDATE_VOID
128# define EVP_DigestUpdate(a,b,c) ssh_EVP_DigestUpdate((a),(b),(c))
129# endif
130
131# ifdef USE_OPENSSL_ENGINE 82# ifdef USE_OPENSSL_ENGINE
132# ifdef OpenSSL_add_all_algorithms 83# ifdef OpenSSL_add_all_algorithms
133# undef OpenSSL_add_all_algorithms 84# undef OpenSSL_add_all_algorithms
@@ -135,48 +86,8 @@ RSA_METHOD *RSA_get_default_method(void);
135# define OpenSSL_add_all_algorithms() ssh_OpenSSL_add_all_algorithms() 86# define OpenSSL_add_all_algorithms() ssh_OpenSSL_add_all_algorithms()
136# endif 87# endif
137 88
138# ifndef HAVE_BN_IS_PRIME_EX
139int BN_is_prime_ex(const BIGNUM *, int, BN_CTX *, void *);
140# endif
141
142# ifndef HAVE_DSA_GENERATE_PARAMETERS_EX
143int DSA_generate_parameters_ex(DSA *, int, const unsigned char *, int, int *,
144 unsigned long *, void *);
145# endif
146
147# ifndef HAVE_RSA_GENERATE_KEY_EX
148int RSA_generate_key_ex(RSA *, int, BIGNUM *, void *);
149# endif
150
151# ifndef HAVE_EVP_DIGESTINIT_EX
152int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, void *);
153# endif
154
155# ifndef HAVE_EVP_DISESTFINAL_EX
156int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *);
157# endif
158
159# ifndef EVP_MD_CTX_COPY_EX
160int EVP_MD_CTX_copy_ex(EVP_MD_CTX *, const EVP_MD_CTX *);
161# endif
162
163int ssh_EVP_CipherInit(EVP_CIPHER_CTX *, const EVP_CIPHER *, unsigned char *,
164 unsigned char *, int);
165int ssh_EVP_Cipher(EVP_CIPHER_CTX *, char *, char *, int);
166int ssh_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *);
167void ssh_OpenSSL_add_all_algorithms(void); 89void ssh_OpenSSL_add_all_algorithms(void);
168 90
169# ifndef HAVE_HMAC_CTX_INIT
170# define HMAC_CTX_init(a)
171# endif
172
173# ifndef HAVE_EVP_MD_CTX_INIT
174# define EVP_MD_CTX_init(a)
175# endif
176
177# ifndef HAVE_EVP_MD_CTX_CLEANUP
178# define EVP_MD_CTX_cleanup(a)
179# endif
180
181#endif /* SSH_DONT_OVERLOAD_OPENSSL_FUNCS */ 91#endif /* SSH_DONT_OVERLOAD_OPENSSL_FUNCS */
182 92
93#endif /* _OPENSSL_COMPAT_H */
diff --git a/openbsd-compat/port-uw.c b/openbsd-compat/port-uw.c
index b1fbfa208..db24dbb94 100644
--- a/openbsd-compat/port-uw.c
+++ b/openbsd-compat/port-uw.c
@@ -42,6 +42,7 @@
42#include "key.h" 42#include "key.h"
43#include "auth-options.h" 43#include "auth-options.h"
44#include "log.h" 44#include "log.h"
45#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */
45#include "servconf.h" 46#include "servconf.h"
46#include "hostfile.h" 47#include "hostfile.h"
47#include "auth.h" 48#include "auth.h"
diff --git a/openbsd-compat/regress/Makefile.in b/openbsd-compat/regress/Makefile.in
index bcf214bd0..dabdb0912 100644
--- a/openbsd-compat/regress/Makefile.in
+++ b/openbsd-compat/regress/Makefile.in
@@ -1,4 +1,4 @@
1# $Id: Makefile.in,v 1.4 2006/08/19 09:12:14 dtucker Exp $ 1# $Id: Makefile.in,v 1.5 2014/06/17 13:06:08 dtucker Exp $
2 2
3sysconfdir=@sysconfdir@ 3sysconfdir=@sysconfdir@
4piddir=@piddir@ 4piddir=@piddir@
@@ -16,11 +16,11 @@ LIBS=@LIBS@
16LDFLAGS=@LDFLAGS@ $(LIBCOMPAT) 16LDFLAGS=@LDFLAGS@ $(LIBCOMPAT)
17 17
18TESTPROGS=closefromtest$(EXEEXT) snprintftest$(EXEEXT) strduptest$(EXEEXT) \ 18TESTPROGS=closefromtest$(EXEEXT) snprintftest$(EXEEXT) strduptest$(EXEEXT) \
19 strtonumtest$(EXEEXT) 19 strtonumtest$(EXEEXT) opensslvertest$(EXEEXT)
20 20
21all: t-exec ${OTHERTESTS} 21all: t-exec ${OTHERTESTS}
22 22
23%$(EXEEXT): %.c 23%$(EXEEXT): %.c $(LIBCOMPAT)
24 $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< $(LIBCOMPAT) $(LIBS) 24 $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< $(LIBCOMPAT) $(LIBS)
25 25
26t-exec: $(TESTPROGS) 26t-exec: $(TESTPROGS)
diff --git a/openbsd-compat/regress/opensslvertest.c b/openbsd-compat/regress/opensslvertest.c
new file mode 100644
index 000000000..5d019b598
--- /dev/null
+++ b/openbsd-compat/regress/opensslvertest.c
@@ -0,0 +1,69 @@
1/*
2 * Copyright (c) 2014 Darren Tucker
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19
20int ssh_compatible_openssl(long, long);
21
22struct version_test {
23 long headerver;
24 long libver;
25 int result;
26} version_tests[] = {
27 /* built with 0.9.8b release headers */
28 { 0x0090802fL, 0x0090802fL, 1}, /* exact match */
29 { 0x0090802fL, 0x0090804fL, 1}, /* newer library fix version: ok */
30 { 0x0090802fL, 0x0090801fL, 1}, /* older library fix version: ok */
31 { 0x0090802fL, 0x0090702fL, 0}, /* older library minor version: NO */
32 { 0x0090802fL, 0x0090902fL, 0}, /* newer library minor version: NO */
33 { 0x0090802fL, 0x0080802fL, 0}, /* older library major version: NO */
34 { 0x0090802fL, 0x1000100fL, 0}, /* newer library major version: NO */
35
36 /* built with 1.0.1b release headers */
37 { 0x1000101fL, 0x1000101fL, 1},/* exact match */
38 { 0x1000101fL, 0x1000102fL, 1}, /* newer library patch version: ok */
39 { 0x1000101fL, 0x1000100fL, 1}, /* older library patch version: ok */
40 { 0x1000101fL, 0x1000201fL, 1}, /* newer library fix version: ok */
41 { 0x1000101fL, 0x1000001fL, 0}, /* older library fix version: NO */
42 { 0x1000101fL, 0x1010101fL, 0}, /* newer library minor version: NO */
43 { 0x1000101fL, 0x0000101fL, 0}, /* older library major version: NO */
44 { 0x1000101fL, 0x2000101fL, 0}, /* newer library major version: NO */
45};
46
47void
48fail(long hver, long lver, int result)
49{
50 fprintf(stderr, "opensslver: header %lx library %lx != %d \n", hver, lver, result);
51 exit(1);
52}
53
54int
55main(void)
56{
57 unsigned int i;
58 int res;
59 long hver, lver;
60
61 for (i = 0; i < sizeof(version_tests) / sizeof(version_tests[0]); i++) {
62 hver = version_tests[i].headerver;
63 lver = version_tests[i].libver;
64 res = version_tests[i].result;
65 if (ssh_compatible_openssl(hver, lver) != res)
66 fail(hver, lver, res);
67 }
68 exit(0);
69}
diff --git a/opensshd.init.in b/opensshd.init.in
index 0db60caa7..517345bfb 100755
--- a/opensshd.init.in
+++ b/opensshd.init.in
@@ -21,6 +21,7 @@ HOST_KEY_RSA1=$sysconfdir/ssh_host_key
21HOST_KEY_DSA=$sysconfdir/ssh_host_dsa_key 21HOST_KEY_DSA=$sysconfdir/ssh_host_dsa_key
22HOST_KEY_RSA=$sysconfdir/ssh_host_rsa_key 22HOST_KEY_RSA=$sysconfdir/ssh_host_rsa_key
23@COMMENT_OUT_ECC@HOST_KEY_ECDSA=$sysconfdir/ssh_host_ecdsa_key 23@COMMENT_OUT_ECC@HOST_KEY_ECDSA=$sysconfdir/ssh_host_ecdsa_key
24HOST_KEY_ED25519=$sysconfdir/ssh_host_ed25519_key
24 25
25 26
26checkkeys() { 27checkkeys() {
@@ -36,6 +37,9 @@ checkkeys() {
36@COMMENT_OUT_ECC@ if [ ! -f $HOST_KEY_ECDSA ]; then 37@COMMENT_OUT_ECC@ if [ ! -f $HOST_KEY_ECDSA ]; then
37@COMMENT_OUT_ECC@ ${SSH_KEYGEN} -t ecdsa -f ${HOST_KEY_ECDSA} -N "" 38@COMMENT_OUT_ECC@ ${SSH_KEYGEN} -t ecdsa -f ${HOST_KEY_ECDSA} -N ""
38@COMMENT_OUT_ECC@ fi 39@COMMENT_OUT_ECC@ fi
40 if [ ! -f $HOST_KEY_ED25519 ]; then
41 ${SSH_KEYGEN} -t ed25519 -f ${HOST_KEY_ED25519} -N ""
42 fi
39} 43}
40 44
41stop_service() { 45stop_service() {
diff --git a/packet.c b/packet.c
index 54c0558f9..6e7b87757 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: packet.c,v 1.192 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: packet.c,v 1.198 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -66,7 +66,6 @@
66#include "crc32.h" 66#include "crc32.h"
67#include "compress.h" 67#include "compress.h"
68#include "deattack.h" 68#include "deattack.h"
69#include "channels.h"
70#include "compat.h" 69#include "compat.h"
71#include "ssh1.h" 70#include "ssh1.h"
72#include "ssh2.h" 71#include "ssh2.h"
@@ -77,7 +76,9 @@
77#include "log.h" 76#include "log.h"
78#include "canohost.h" 77#include "canohost.h"
79#include "misc.h" 78#include "misc.h"
79#include "channels.h"
80#include "ssh.h" 80#include "ssh.h"
81#include "ssherr.h"
81#include "roaming.h" 82#include "roaming.h"
82 83
83#ifdef PACKET_DEBUG 84#ifdef PACKET_DEBUG
@@ -222,6 +223,7 @@ void
222packet_set_connection(int fd_in, int fd_out) 223packet_set_connection(int fd_in, int fd_out)
223{ 224{
224 const Cipher *none = cipher_by_name("none"); 225 const Cipher *none = cipher_by_name("none");
226 int r;
225 227
226 if (none == NULL) 228 if (none == NULL)
227 fatal("packet_set_connection: cannot load cipher 'none'"); 229 fatal("packet_set_connection: cannot load cipher 'none'");
@@ -229,10 +231,11 @@ packet_set_connection(int fd_in, int fd_out)
229 active_state = alloc_session_state(); 231 active_state = alloc_session_state();
230 active_state->connection_in = fd_in; 232 active_state->connection_in = fd_in;
231 active_state->connection_out = fd_out; 233 active_state->connection_out = fd_out;
232 cipher_init(&active_state->send_context, none, (const u_char *)"", 234 if ((r = cipher_init(&active_state->send_context, none,
233 0, NULL, 0, CIPHER_ENCRYPT); 235 (const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 ||
234 cipher_init(&active_state->receive_context, none, (const u_char *)"", 236 (r = cipher_init(&active_state->receive_context, none,
235 0, NULL, 0, CIPHER_DECRYPT); 237 (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0)
238 fatal("%s: cipher_init: %s", __func__, ssh_err(r));
236 active_state->newkeys[MODE_IN] = active_state->newkeys[MODE_OUT] = NULL; 239 active_state->newkeys[MODE_IN] = active_state->newkeys[MODE_OUT] = NULL;
237 if (!active_state->initialized) { 240 if (!active_state->initialized) {
238 active_state->initialized = 1; 241 active_state->initialized = 1;
@@ -329,13 +332,15 @@ void
329packet_get_keyiv(int mode, u_char *iv, u_int len) 332packet_get_keyiv(int mode, u_char *iv, u_int len)
330{ 333{
331 CipherContext *cc; 334 CipherContext *cc;
335 int r;
332 336
333 if (mode == MODE_OUT) 337 if (mode == MODE_OUT)
334 cc = &active_state->send_context; 338 cc = &active_state->send_context;
335 else 339 else
336 cc = &active_state->receive_context; 340 cc = &active_state->receive_context;
337 341
338 cipher_get_keyiv(cc, iv, len); 342 if ((r = cipher_get_keyiv(cc, iv, len)) != 0)
343 fatal("%s: cipher_get_keyiv: %s", __func__, ssh_err(r));
339} 344}
340 345
341int 346int
@@ -381,13 +386,15 @@ void
381packet_set_iv(int mode, u_char *dat) 386packet_set_iv(int mode, u_char *dat)
382{ 387{
383 CipherContext *cc; 388 CipherContext *cc;
389 int r;
384 390
385 if (mode == MODE_OUT) 391 if (mode == MODE_OUT)
386 cc = &active_state->send_context; 392 cc = &active_state->send_context;
387 else 393 else
388 cc = &active_state->receive_context; 394 cc = &active_state->receive_context;
389 395
390 cipher_set_keyiv(cc, dat); 396 if ((r = cipher_set_keyiv(cc, dat)) != 0)
397 fatal("%s: cipher_set_keyiv: %s", __func__, ssh_err(r));
391} 398}
392 399
393int 400int
@@ -552,6 +559,7 @@ void
552packet_set_encryption_key(const u_char *key, u_int keylen, int number) 559packet_set_encryption_key(const u_char *key, u_int keylen, int number)
553{ 560{
554 const Cipher *cipher = cipher_by_number(number); 561 const Cipher *cipher = cipher_by_number(number);
562 int r;
555 563
556 if (cipher == NULL) 564 if (cipher == NULL)
557 fatal("packet_set_encryption_key: unknown cipher number %d", number); 565 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)
561 fatal("packet_set_encryption_key: keylen too big: %d", keylen); 569 fatal("packet_set_encryption_key: keylen too big: %d", keylen);
562 memcpy(active_state->ssh1_key, key, keylen); 570 memcpy(active_state->ssh1_key, key, keylen);
563 active_state->ssh1_keylen = keylen; 571 active_state->ssh1_keylen = keylen;
564 cipher_init(&active_state->send_context, cipher, key, keylen, NULL, 572 if ((r = cipher_init(&active_state->send_context, cipher,
565 0, CIPHER_ENCRYPT); 573 key, keylen, NULL, 0, CIPHER_ENCRYPT)) != 0 ||
566 cipher_init(&active_state->receive_context, cipher, key, keylen, NULL, 574 (r = cipher_init(&active_state->receive_context, cipher,
567 0, CIPHER_DECRYPT); 575 key, keylen, NULL, 0, CIPHER_DECRYPT)) != 0)
576 fatal("%s: cipher_init: %s", __func__, ssh_err(r));
568} 577}
569 578
570u_int 579u_int
@@ -630,6 +639,7 @@ packet_put_raw(const void *buf, u_int len)
630 buffer_append(&active_state->outgoing_packet, buf, len); 639 buffer_append(&active_state->outgoing_packet, buf, len);
631} 640}
632 641
642#ifdef WITH_OPENSSL
633void 643void
634packet_put_bignum(BIGNUM * value) 644packet_put_bignum(BIGNUM * value)
635{ 645{
@@ -641,6 +651,7 @@ packet_put_bignum2(BIGNUM * value)
641{ 651{
642 buffer_put_bignum2(&active_state->outgoing_packet, value); 652 buffer_put_bignum2(&active_state->outgoing_packet, value);
643} 653}
654#endif
644 655
645#ifdef OPENSSL_HAS_ECC 656#ifdef OPENSSL_HAS_ECC
646void 657void
@@ -742,7 +753,7 @@ set_newkeys(int mode)
742 Comp *comp; 753 Comp *comp;
743 CipherContext *cc; 754 CipherContext *cc;
744 u_int64_t *max_blocks; 755 u_int64_t *max_blocks;
745 int crypt_type; 756 int r, crypt_type;
746 757
747 debug2("set_newkeys: mode %d", mode); 758 debug2("set_newkeys: mode %d", mode);
748 759
@@ -784,8 +795,9 @@ set_newkeys(int mode)
784 if (cipher_authlen(enc->cipher) == 0 && mac_init(mac) == 0) 795 if (cipher_authlen(enc->cipher) == 0 && mac_init(mac) == 0)
785 mac->enabled = 1; 796 mac->enabled = 1;
786 DBG(debug("cipher_init_context: %d", mode)); 797 DBG(debug("cipher_init_context: %d", mode));
787 cipher_init(cc, enc->cipher, enc->key, enc->key_len, 798 if ((r = cipher_init(cc, enc->cipher, enc->key, enc->key_len,
788 enc->iv, enc->iv_len, crypt_type); 799 enc->iv, enc->iv_len, crypt_type)) != 0)
800 fatal("%s: cipher_init: %s", __func__, ssh_err(r));
789 /* Deleting the keys does not gain extra security */ 801 /* Deleting the keys does not gain extra security */
790 /* explicit_bzero(enc->iv, enc->block_size); 802 /* explicit_bzero(enc->iv, enc->block_size);
791 explicit_bzero(enc->key, enc->key_len); 803 explicit_bzero(enc->key, enc->key_len);
@@ -912,8 +924,8 @@ packet_send2_wrapped(void)
912 roundup(active_state->extra_pad, block_size); 924 roundup(active_state->extra_pad, block_size);
913 pad = active_state->extra_pad - 925 pad = active_state->extra_pad -
914 ((len + padlen) % active_state->extra_pad); 926 ((len + padlen) % active_state->extra_pad);
915 debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)", 927 DBG(debug3("%s: adding %d (len %d padlen %d extra_pad %d)",
916 pad, len, padlen, active_state->extra_pad); 928 __func__, pad, len, padlen, active_state->extra_pad));
917 padlen += pad; 929 padlen += pad;
918 active_state->extra_pad = 0; 930 active_state->extra_pad = 0;
919 } 931 }
@@ -1569,6 +1581,7 @@ packet_get_int64(void)
1569 * must have been initialized before this call. 1581 * must have been initialized before this call.
1570 */ 1582 */
1571 1583
1584#ifdef WITH_OPENSSL
1572void 1585void
1573packet_get_bignum(BIGNUM * value) 1586packet_get_bignum(BIGNUM * value)
1574{ 1587{
@@ -1598,6 +1611,7 @@ packet_get_raw(u_int *length_ptr)
1598 *length_ptr = bytes; 1611 *length_ptr = bytes;
1599 return buffer_ptr(&active_state->incoming_packet); 1612 return buffer_ptr(&active_state->incoming_packet);
1600} 1613}
1614#endif
1601 1615
1602int 1616int
1603packet_remaining(void) 1617packet_remaining(void)
@@ -1618,7 +1632,7 @@ packet_get_string(u_int *length_ptr)
1618 return buffer_get_string(&active_state->incoming_packet, length_ptr); 1632 return buffer_get_string(&active_state->incoming_packet, length_ptr);
1619} 1633}
1620 1634
1621void * 1635const void *
1622packet_get_string_ptr(u_int *length_ptr) 1636packet_get_string_ptr(u_int *length_ptr)
1623{ 1637{
1624 return buffer_get_string_ptr(&active_state->incoming_packet, length_ptr); 1638 return buffer_get_string_ptr(&active_state->incoming_packet, length_ptr);
@@ -2055,3 +2069,23 @@ packet_restore_state(void)
2055 add_recv_bytes(len); 2069 add_recv_bytes(len);
2056 } 2070 }
2057} 2071}
2072
2073/* Reset after_authentication and reset compression in post-auth privsep */
2074void
2075packet_set_postauth(void)
2076{
2077 Comp *comp;
2078 int mode;
2079
2080 debug("%s: called", __func__);
2081 /* This was set in net child, but is not visible in user child */
2082 active_state->after_authentication = 1;
2083 active_state->rekeying = 0;
2084 for (mode = 0; mode < MODE_MAX; mode++) {
2085 if (active_state->newkeys[mode] == NULL)
2086 continue;
2087 comp = &active_state->newkeys[mode]->comp;
2088 if (comp && comp->enabled)
2089 packet_init_compression();
2090 }
2091}
diff --git a/packet.h b/packet.h
index f8edf851c..e7b5fcba9 100644
--- a/packet.h
+++ b/packet.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: packet.h,v 1.59 2013/07/12 00:19:59 djm Exp $ */ 1/* $OpenBSD: packet.h,v 1.61 2014/05/03 17:20:34 markus Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -70,7 +70,7 @@ void packet_get_ecpoint(const EC_GROUP *, EC_POINT *);
70void *packet_get_raw(u_int *length_ptr); 70void *packet_get_raw(u_int *length_ptr);
71void *packet_get_string(u_int *length_ptr); 71void *packet_get_string(u_int *length_ptr);
72char *packet_get_cstring(u_int *length_ptr); 72char *packet_get_cstring(u_int *length_ptr);
73void *packet_get_string_ptr(u_int *length_ptr); 73const void *packet_get_string_ptr(u_int *length_ptr);
74void packet_disconnect(const char *fmt,...) __attribute__((noreturn)) __attribute__((format(printf, 1, 2))); 74void packet_disconnect(const char *fmt,...) __attribute__((noreturn)) __attribute__((format(printf, 1, 2)));
75void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2))); 75void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
76 76
@@ -120,6 +120,7 @@ time_t packet_get_rekey_timeout(void);
120 120
121void packet_backup_state(void); 121void packet_backup_state(void);
122void packet_restore_state(void); 122void packet_restore_state(void);
123void packet_set_postauth(void);
123 124
124void *packet_get_input(void); 125void *packet_get_input(void);
125void *packet_get_output(void); 126void *packet_get_output(void);
diff --git a/platform.c b/platform.c
index 30fc60909..ee313da55 100644
--- a/platform.c
+++ b/platform.c
@@ -1,4 +1,4 @@
1/* $Id: platform.c,v 1.21 2014/01/21 01:59:29 tim Exp $ */ 1/* $Id: platform.c,v 1.22 2014/07/18 04:11:26 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2006 Darren Tucker. All rights reserved. 4 * Copyright (c) 2006 Darren Tucker. All rights reserved.
@@ -25,6 +25,7 @@
25 25
26#include "log.h" 26#include "log.h"
27#include "buffer.h" 27#include "buffer.h"
28#include "misc.h"
28#include "servconf.h" 29#include "servconf.h"
29#include "key.h" 30#include "key.h"
30#include "hostfile.h" 31#include "hostfile.h"
diff --git a/poly1305.h b/poly1305.h
index 221efc462..f7db5f8d7 100644
--- a/poly1305.h
+++ b/poly1305.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: poly1305.h,v 1.2 2013/12/19 22:57:13 djm Exp $ */ 1/* $OpenBSD: poly1305.h,v 1.4 2014/05/02 03:27:54 djm Exp $ */
2 2
3/* 3/*
4 * Public Domain poly1305 from Andrew Moon 4 * Public Domain poly1305 from Andrew Moon
diff --git a/readconf.c b/readconf.c
index dc884c9b1..7948ce1cd 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.c,v 1.218 2014/02/23 20:11:36 djm Exp $ */ 1/* $OpenBSD: readconf.c,v 1.220 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -18,6 +18,7 @@
18#include <sys/stat.h> 18#include <sys/stat.h>
19#include <sys/socket.h> 19#include <sys/socket.h>
20#include <sys/wait.h> 20#include <sys/wait.h>
21#include <sys/un.h>
21 22
22#include <netinet/in.h> 23#include <netinet/in.h>
23#include <netinet/in_systm.h> 24#include <netinet/in_systm.h>
@@ -48,9 +49,9 @@
48#include "pathnames.h" 49#include "pathnames.h"
49#include "log.h" 50#include "log.h"
50#include "key.h" 51#include "key.h"
52#include "misc.h"
51#include "readconf.h" 53#include "readconf.h"
52#include "match.h" 54#include "match.h"
53#include "misc.h"
54#include "buffer.h" 55#include "buffer.h"
55#include "kex.h" 56#include "kex.h"
56#include "mac.h" 57#include "mac.h"
@@ -149,6 +150,7 @@ typedef enum {
149 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, 150 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
150 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, 151 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
151 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, 152 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
153 oStreamLocalBindMask, oStreamLocalBindUnlink,
152 oIgnoredUnknownOption, oDeprecated, oUnsupported 154 oIgnoredUnknownOption, oDeprecated, oUnsupported
153} OpCodes; 155} OpCodes;
154 156
@@ -261,6 +263,8 @@ static struct {
261 { "canonicalizehostname", oCanonicalizeHostname }, 263 { "canonicalizehostname", oCanonicalizeHostname },
262 { "canonicalizemaxdots", oCanonicalizeMaxDots }, 264 { "canonicalizemaxdots", oCanonicalizeMaxDots },
263 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, 265 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
266 { "streamlocalbindmask", oStreamLocalBindMask },
267 { "streamlocalbindunlink", oStreamLocalBindUnlink },
264 { "ignoreunknown", oIgnoreUnknown }, 268 { "ignoreunknown", oIgnoreUnknown },
265 269
266 { NULL, oBadOption } 270 { NULL, oBadOption }
@@ -272,12 +276,13 @@ static struct {
272 */ 276 */
273 277
274void 278void
275add_local_forward(Options *options, const Forward *newfwd) 279add_local_forward(Options *options, const struct Forward *newfwd)
276{ 280{
277 Forward *fwd; 281 struct Forward *fwd;
278#ifndef NO_IPPORT_RESERVED_CONCEPT 282#ifndef NO_IPPORT_RESERVED_CONCEPT
279 extern uid_t original_real_uid; 283 extern uid_t original_real_uid;
280 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0) 284 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0 &&
285 newfwd->listen_path == NULL)
281 fatal("Privileged ports can only be forwarded by root."); 286 fatal("Privileged ports can only be forwarded by root.");
282#endif 287#endif
283 options->local_forwards = xrealloc(options->local_forwards, 288 options->local_forwards = xrealloc(options->local_forwards,
@@ -287,8 +292,10 @@ add_local_forward(Options *options, const Forward *newfwd)
287 292
288 fwd->listen_host = newfwd->listen_host; 293 fwd->listen_host = newfwd->listen_host;
289 fwd->listen_port = newfwd->listen_port; 294 fwd->listen_port = newfwd->listen_port;
295 fwd->listen_path = newfwd->listen_path;
290 fwd->connect_host = newfwd->connect_host; 296 fwd->connect_host = newfwd->connect_host;
291 fwd->connect_port = newfwd->connect_port; 297 fwd->connect_port = newfwd->connect_port;
298 fwd->connect_path = newfwd->connect_path;
292} 299}
293 300
294/* 301/*
@@ -297,9 +304,9 @@ add_local_forward(Options *options, const Forward *newfwd)
297 */ 304 */
298 305
299void 306void
300add_remote_forward(Options *options, const Forward *newfwd) 307add_remote_forward(Options *options, const struct Forward *newfwd)
301{ 308{
302 Forward *fwd; 309 struct Forward *fwd;
303 310
304 options->remote_forwards = xrealloc(options->remote_forwards, 311 options->remote_forwards = xrealloc(options->remote_forwards,
305 options->num_remote_forwards + 1, 312 options->num_remote_forwards + 1,
@@ -308,8 +315,10 @@ add_remote_forward(Options *options, const Forward *newfwd)
308 315
309 fwd->listen_host = newfwd->listen_host; 316 fwd->listen_host = newfwd->listen_host;
310 fwd->listen_port = newfwd->listen_port; 317 fwd->listen_port = newfwd->listen_port;
318 fwd->listen_path = newfwd->listen_path;
311 fwd->connect_host = newfwd->connect_host; 319 fwd->connect_host = newfwd->connect_host;
312 fwd->connect_port = newfwd->connect_port; 320 fwd->connect_port = newfwd->connect_port;
321 fwd->connect_path = newfwd->connect_path;
313 fwd->handle = newfwd->handle; 322 fwd->handle = newfwd->handle;
314 fwd->allocated_port = 0; 323 fwd->allocated_port = 0;
315} 324}
@@ -321,7 +330,9 @@ clear_forwardings(Options *options)
321 330
322 for (i = 0; i < options->num_local_forwards; i++) { 331 for (i = 0; i < options->num_local_forwards; i++) {
323 free(options->local_forwards[i].listen_host); 332 free(options->local_forwards[i].listen_host);
333 free(options->local_forwards[i].listen_path);
324 free(options->local_forwards[i].connect_host); 334 free(options->local_forwards[i].connect_host);
335 free(options->local_forwards[i].connect_path);
325 } 336 }
326 if (options->num_local_forwards > 0) { 337 if (options->num_local_forwards > 0) {
327 free(options->local_forwards); 338 free(options->local_forwards);
@@ -330,7 +341,9 @@ clear_forwardings(Options *options)
330 options->num_local_forwards = 0; 341 options->num_local_forwards = 0;
331 for (i = 0; i < options->num_remote_forwards; i++) { 342 for (i = 0; i < options->num_remote_forwards; i++) {
332 free(options->remote_forwards[i].listen_host); 343 free(options->remote_forwards[i].listen_host);
344 free(options->remote_forwards[i].listen_path);
333 free(options->remote_forwards[i].connect_host); 345 free(options->remote_forwards[i].connect_host);
346 free(options->remote_forwards[i].connect_path);
334 } 347 }
335 if (options->num_remote_forwards > 0) { 348 if (options->num_remote_forwards > 0) {
336 free(options->remote_forwards); 349 free(options->remote_forwards);
@@ -345,6 +358,7 @@ add_identity_file(Options *options, const char *dir, const char *filename,
345 int userprovided) 358 int userprovided)
346{ 359{
347 char *path; 360 char *path;
361 int i;
348 362
349 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES) 363 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
350 fatal("Too many identity files specified (max %d)", 364 fatal("Too many identity files specified (max %d)",
@@ -355,6 +369,16 @@ add_identity_file(Options *options, const char *dir, const char *filename,
355 else 369 else
356 (void)xasprintf(&path, "%.100s%.100s", dir, filename); 370 (void)xasprintf(&path, "%.100s%.100s", dir, filename);
357 371
372 /* Avoid registering duplicates */
373 for (i = 0; i < options->num_identity_files; i++) {
374 if (options->identity_file_userprovided[i] == userprovided &&
375 strcmp(options->identity_files[i], path) == 0) {
376 debug2("%s: ignoring duplicate key %s", __func__, path);
377 free(path);
378 return;
379 }
380 }
381
358 options->identity_file_userprovided[options->num_identity_files] = 382 options->identity_file_userprovided[options->num_identity_files] =
359 userprovided; 383 userprovided;
360 options->identity_files[options->num_identity_files++] = path; 384 options->identity_files[options->num_identity_files++] = path;
@@ -704,7 +728,7 @@ process_config_line(Options *options, struct passwd *pw, const char *host,
704 LogLevel *log_level_ptr; 728 LogLevel *log_level_ptr;
705 long long val64; 729 long long val64;
706 size_t len; 730 size_t len;
707 Forward fwd; 731 struct Forward fwd;
708 const struct multistate *multistate_ptr; 732 const struct multistate *multistate_ptr;
709 struct allowed_cname *cname; 733 struct allowed_cname *cname;
710 734
@@ -794,7 +818,7 @@ parse_time:
794 goto parse_time; 818 goto parse_time;
795 819
796 case oGatewayPorts: 820 case oGatewayPorts:
797 intptr = &options->gateway_ports; 821 intptr = &options->fwd_opts.gateway_ports;
798 goto parse_flag; 822 goto parse_flag;
799 823
800 case oExitOnForwardFailure: 824 case oExitOnForwardFailure:
@@ -1394,6 +1418,21 @@ parse_int:
1394 intptr = &options->canonicalize_fallback_local; 1418 intptr = &options->canonicalize_fallback_local;
1395 goto parse_flag; 1419 goto parse_flag;
1396 1420
1421 case oStreamLocalBindMask:
1422 arg = strdelim(&s);
1423 if (!arg || *arg == '\0')
1424 fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1425 /* Parse mode in octal format */
1426 value = strtol(arg, &endofnumber, 8);
1427 if (arg == endofnumber || value < 0 || value > 0777)
1428 fatal("%.200s line %d: Bad mask.", filename, linenum);
1429 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1430 break;
1431
1432 case oStreamLocalBindUnlink:
1433 intptr = &options->fwd_opts.streamlocal_bind_unlink;
1434 goto parse_flag;
1435
1397 case oDeprecated: 1436 case oDeprecated:
1398 debug("%s line %d: Deprecated option \"%s\"", 1437 debug("%s line %d: Deprecated option \"%s\"",
1399 filename, linenum, keyword); 1438 filename, linenum, keyword);
@@ -1491,7 +1530,9 @@ initialize_options(Options * options)
1491 options->forward_x11_timeout = -1; 1530 options->forward_x11_timeout = -1;
1492 options->exit_on_forward_failure = -1; 1531 options->exit_on_forward_failure = -1;
1493 options->xauth_location = NULL; 1532 options->xauth_location = NULL;
1494 options->gateway_ports = -1; 1533 options->fwd_opts.gateway_ports = -1;
1534 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1535 options->fwd_opts.streamlocal_bind_unlink = -1;
1495 options->use_privileged_port = -1; 1536 options->use_privileged_port = -1;
1496 options->rsa_authentication = -1; 1537 options->rsa_authentication = -1;
1497 options->pubkey_authentication = -1; 1538 options->pubkey_authentication = -1;
@@ -1604,8 +1645,12 @@ fill_default_options(Options * options)
1604 options->exit_on_forward_failure = 0; 1645 options->exit_on_forward_failure = 0;
1605 if (options->xauth_location == NULL) 1646 if (options->xauth_location == NULL)
1606 options->xauth_location = _PATH_XAUTH; 1647 options->xauth_location = _PATH_XAUTH;
1607 if (options->gateway_ports == -1) 1648 if (options->fwd_opts.gateway_ports == -1)
1608 options->gateway_ports = 0; 1649 options->fwd_opts.gateway_ports = 0;
1650 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
1651 options->fwd_opts.streamlocal_bind_mask = 0177;
1652 if (options->fwd_opts.streamlocal_bind_unlink == -1)
1653 options->fwd_opts.streamlocal_bind_unlink = 0;
1609 if (options->use_privileged_port == -1) 1654 if (options->use_privileged_port == -1)
1610 options->use_privileged_port = 0; 1655 options->use_privileged_port = 0;
1611 if (options->rsa_authentication == -1) 1656 if (options->rsa_authentication == -1)
@@ -1757,22 +1802,92 @@ fill_default_options(Options * options)
1757 /* options->preferred_authentications will be set in ssh */ 1802 /* options->preferred_authentications will be set in ssh */
1758} 1803}
1759 1804
1805struct fwdarg {
1806 char *arg;
1807 int ispath;
1808};
1809
1810/*
1811 * parse_fwd_field
1812 * parses the next field in a port forwarding specification.
1813 * sets fwd to the parsed field and advances p past the colon
1814 * or sets it to NULL at end of string.
1815 * returns 0 on success, else non-zero.
1816 */
1817static int
1818parse_fwd_field(char **p, struct fwdarg *fwd)
1819{
1820 char *ep, *cp = *p;
1821 int ispath = 0;
1822
1823 if (*cp == '\0') {
1824 *p = NULL;
1825 return -1; /* end of string */
1826 }
1827
1828 /*
1829 * A field escaped with square brackets is used literally.
1830 * XXX - allow ']' to be escaped via backslash?
1831 */
1832 if (*cp == '[') {
1833 /* find matching ']' */
1834 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
1835 if (*ep == '/')
1836 ispath = 1;
1837 }
1838 /* no matching ']' or not at end of field. */
1839 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
1840 return -1;
1841 /* NUL terminate the field and advance p past the colon */
1842 *ep++ = '\0';
1843 if (*ep != '\0')
1844 *ep++ = '\0';
1845 fwd->arg = cp + 1;
1846 fwd->ispath = ispath;
1847 *p = ep;
1848 return 0;
1849 }
1850
1851 for (cp = *p; *cp != '\0'; cp++) {
1852 switch (*cp) {
1853 case '\\':
1854 memmove(cp, cp + 1, strlen(cp + 1) + 1);
1855 cp++;
1856 break;
1857 case '/':
1858 ispath = 1;
1859 break;
1860 case ':':
1861 *cp++ = '\0';
1862 goto done;
1863 }
1864 }
1865done:
1866 fwd->arg = *p;
1867 fwd->ispath = ispath;
1868 *p = cp;
1869 return 0;
1870}
1871
1760/* 1872/*
1761 * parse_forward 1873 * parse_forward
1762 * parses a string containing a port forwarding specification of the form: 1874 * parses a string containing a port forwarding specification of the form:
1763 * dynamicfwd == 0 1875 * dynamicfwd == 0
1764 * [listenhost:]listenport:connecthost:connectport 1876 * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
1877 * listenpath:connectpath
1765 * dynamicfwd == 1 1878 * dynamicfwd == 1
1766 * [listenhost:]listenport 1879 * [listenhost:]listenport
1767 * returns number of arguments parsed or zero on error 1880 * returns number of arguments parsed or zero on error
1768 */ 1881 */
1769int 1882int
1770parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd) 1883parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1771{ 1884{
1885 struct fwdarg fwdargs[4];
1886 char *p, *cp;
1772 int i; 1887 int i;
1773 char *p, *cp, *fwdarg[4];
1774 1888
1775 memset(fwd, '\0', sizeof(*fwd)); 1889 memset(fwd, 0, sizeof(*fwd));
1890 memset(fwdargs, 0, sizeof(fwdargs));
1776 1891
1777 cp = p = xstrdup(fwdspec); 1892 cp = p = xstrdup(fwdspec);
1778 1893
@@ -1780,39 +1895,70 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1780 while (isspace((u_char)*cp)) 1895 while (isspace((u_char)*cp))
1781 cp++; 1896 cp++;
1782 1897
1783 for (i = 0; i < 4; ++i) 1898 for (i = 0; i < 4; ++i) {
1784 if ((fwdarg[i] = hpdelim(&cp)) == NULL) 1899 if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
1785 break; 1900 break;
1901 }
1786 1902
1787 /* Check for trailing garbage */ 1903 /* Check for trailing garbage */
1788 if (cp != NULL) 1904 if (cp != NULL && *cp != '\0') {
1789 i = 0; /* failure */ 1905 i = 0; /* failure */
1906 }
1790 1907
1791 switch (i) { 1908 switch (i) {
1792 case 1: 1909 case 1:
1793 fwd->listen_host = NULL; 1910 if (fwdargs[0].ispath) {
1794 fwd->listen_port = a2port(fwdarg[0]); 1911 fwd->listen_path = xstrdup(fwdargs[0].arg);
1912 fwd->listen_port = PORT_STREAMLOCAL;
1913 } else {
1914 fwd->listen_host = NULL;
1915 fwd->listen_port = a2port(fwdargs[0].arg);
1916 }
1795 fwd->connect_host = xstrdup("socks"); 1917 fwd->connect_host = xstrdup("socks");
1796 break; 1918 break;
1797 1919
1798 case 2: 1920 case 2:
1799 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1921 if (fwdargs[0].ispath && fwdargs[1].ispath) {
1800 fwd->listen_port = a2port(fwdarg[1]); 1922 fwd->listen_path = xstrdup(fwdargs[0].arg);
1801 fwd->connect_host = xstrdup("socks"); 1923 fwd->listen_port = PORT_STREAMLOCAL;
1924 fwd->connect_path = xstrdup(fwdargs[1].arg);
1925 fwd->connect_port = PORT_STREAMLOCAL;
1926 } else if (fwdargs[1].ispath) {
1927 fwd->listen_host = NULL;
1928 fwd->listen_port = a2port(fwdargs[0].arg);
1929 fwd->connect_path = xstrdup(fwdargs[1].arg);
1930 fwd->connect_port = PORT_STREAMLOCAL;
1931 } else {
1932 fwd->listen_host = xstrdup(fwdargs[0].arg);
1933 fwd->listen_port = a2port(fwdargs[1].arg);
1934 fwd->connect_host = xstrdup("socks");
1935 }
1802 break; 1936 break;
1803 1937
1804 case 3: 1938 case 3:
1805 fwd->listen_host = NULL; 1939 if (fwdargs[0].ispath) {
1806 fwd->listen_port = a2port(fwdarg[0]); 1940 fwd->listen_path = xstrdup(fwdargs[0].arg);
1807 fwd->connect_host = xstrdup(cleanhostname(fwdarg[1])); 1941 fwd->listen_port = PORT_STREAMLOCAL;
1808 fwd->connect_port = a2port(fwdarg[2]); 1942 fwd->connect_host = xstrdup(fwdargs[1].arg);
1943 fwd->connect_port = a2port(fwdargs[2].arg);
1944 } else if (fwdargs[2].ispath) {
1945 fwd->listen_host = xstrdup(fwdargs[0].arg);
1946 fwd->listen_port = a2port(fwdargs[1].arg);
1947 fwd->connect_path = xstrdup(fwdargs[2].arg);
1948 fwd->connect_port = PORT_STREAMLOCAL;
1949 } else {
1950 fwd->listen_host = NULL;
1951 fwd->listen_port = a2port(fwdargs[0].arg);
1952 fwd->connect_host = xstrdup(fwdargs[1].arg);
1953 fwd->connect_port = a2port(fwdargs[2].arg);
1954 }
1809 break; 1955 break;
1810 1956
1811 case 4: 1957 case 4:
1812 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1958 fwd->listen_host = xstrdup(fwdargs[0].arg);
1813 fwd->listen_port = a2port(fwdarg[1]); 1959 fwd->listen_port = a2port(fwdargs[1].arg);
1814 fwd->connect_host = xstrdup(cleanhostname(fwdarg[2])); 1960 fwd->connect_host = xstrdup(fwdargs[2].arg);
1815 fwd->connect_port = a2port(fwdarg[3]); 1961 fwd->connect_port = a2port(fwdargs[3].arg);
1816 break; 1962 break;
1817 default: 1963 default:
1818 i = 0; /* failure */ 1964 i = 0; /* failure */
@@ -1824,29 +1970,42 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1824 if (!(i == 1 || i == 2)) 1970 if (!(i == 1 || i == 2))
1825 goto fail_free; 1971 goto fail_free;
1826 } else { 1972 } else {
1827 if (!(i == 3 || i == 4)) 1973 if (!(i == 3 || i == 4)) {
1828 goto fail_free; 1974 if (fwd->connect_path == NULL &&
1829 if (fwd->connect_port <= 0) 1975 fwd->listen_path == NULL)
1976 goto fail_free;
1977 }
1978 if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
1830 goto fail_free; 1979 goto fail_free;
1831 } 1980 }
1832 1981
1833 if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0)) 1982 if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
1983 (!remotefwd && fwd->listen_port == 0))
1834 goto fail_free; 1984 goto fail_free;
1835
1836 if (fwd->connect_host != NULL && 1985 if (fwd->connect_host != NULL &&
1837 strlen(fwd->connect_host) >= NI_MAXHOST) 1986 strlen(fwd->connect_host) >= NI_MAXHOST)
1838 goto fail_free; 1987 goto fail_free;
1988 /* XXX - if connecting to a remote socket, max sun len may not match this host */
1989 if (fwd->connect_path != NULL &&
1990 strlen(fwd->connect_path) >= PATH_MAX_SUN)
1991 goto fail_free;
1839 if (fwd->listen_host != NULL && 1992 if (fwd->listen_host != NULL &&
1840 strlen(fwd->listen_host) >= NI_MAXHOST) 1993 strlen(fwd->listen_host) >= NI_MAXHOST)
1841 goto fail_free; 1994 goto fail_free;
1842 1995 if (fwd->listen_path != NULL &&
1996 strlen(fwd->listen_path) >= PATH_MAX_SUN)
1997 goto fail_free;
1843 1998
1844 return (i); 1999 return (i);
1845 2000
1846 fail_free: 2001 fail_free:
1847 free(fwd->connect_host); 2002 free(fwd->connect_host);
1848 fwd->connect_host = NULL; 2003 fwd->connect_host = NULL;
2004 free(fwd->connect_path);
2005 fwd->connect_path = NULL;
1849 free(fwd->listen_host); 2006 free(fwd->listen_host);
1850 fwd->listen_host = NULL; 2007 fwd->listen_host = NULL;
2008 free(fwd->listen_path);
2009 fwd->listen_path = NULL;
1851 return (0); 2010 return (0);
1852} 2011}
diff --git a/readconf.h b/readconf.h
index 75e3f8f7a..0b9cb777a 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.h,v 1.101 2014/02/23 20:11:36 djm Exp $ */ 1/* $OpenBSD: readconf.h,v 1.102 2014/07/15 15:54:14 millert Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -16,21 +16,12 @@
16#ifndef READCONF_H 16#ifndef READCONF_H
17#define READCONF_H 17#define READCONF_H
18 18
19/* Data structure for representing a forwarding request. */
20
21typedef struct {
22 char *listen_host; /* Host (address) to listen on. */
23 int listen_port; /* Port to forward. */
24 char *connect_host; /* Host to connect. */
25 int connect_port; /* Port to connect on connect_host. */
26 int allocated_port; /* Dynamically allocated listen port */
27 int handle; /* Handle for dynamic listen ports */
28} Forward;
29/* Data structure for representing option data. */ 19/* Data structure for representing option data. */
30 20
31#define MAX_SEND_ENV 256 21#define MAX_SEND_ENV 256
32#define SSH_MAX_HOSTS_FILES 32 22#define SSH_MAX_HOSTS_FILES 32
33#define MAX_CANON_DOMAINS 32 23#define MAX_CANON_DOMAINS 32
24#define PATH_MAX_SUN (sizeof((struct sockaddr_un *)0)->sun_path)
34 25
35struct allowed_cname { 26struct allowed_cname {
36 char *source_list; 27 char *source_list;
@@ -44,7 +35,7 @@ typedef struct {
44 int forward_x11_trusted; /* Trust Forward X11 display. */ 35 int forward_x11_trusted; /* Trust Forward X11 display. */
45 int exit_on_forward_failure; /* Exit if bind(2) fails for -L/-R */ 36 int exit_on_forward_failure; /* Exit if bind(2) fails for -L/-R */
46 char *xauth_location; /* Location for xauth program */ 37 char *xauth_location; /* Location for xauth program */
47 int gateway_ports; /* Allow remote connects to forwarded ports. */ 38 struct ForwardOptions fwd_opts; /* forwarding options */
48 int use_privileged_port; /* Don't use privileged port if false. */ 39 int use_privileged_port; /* Don't use privileged port if false. */
49 int rhosts_rsa_authentication; /* Try rhosts with RSA 40 int rhosts_rsa_authentication; /* Try rhosts with RSA
50 * authentication. */ 41 * authentication. */
@@ -106,11 +97,11 @@ typedef struct {
106 97
107 /* Local TCP/IP forward requests. */ 98 /* Local TCP/IP forward requests. */
108 int num_local_forwards; 99 int num_local_forwards;
109 Forward *local_forwards; 100 struct Forward *local_forwards;
110 101
111 /* Remote TCP/IP forward requests. */ 102 /* Remote TCP/IP forward requests. */
112 int num_remote_forwards; 103 int num_remote_forwards;
113 Forward *remote_forwards; 104 struct Forward *remote_forwards;
114 int clear_forwardings; 105 int clear_forwardings;
115 106
116 int enable_ssh_keysign; 107 int enable_ssh_keysign;
@@ -181,12 +172,12 @@ int process_config_line(Options *, struct passwd *, const char *, char *,
181 const char *, int, int *, int); 172 const char *, int, int *, int);
182int read_config_file(const char *, struct passwd *, const char *, 173int read_config_file(const char *, struct passwd *, const char *,
183 Options *, int); 174 Options *, int);
184int parse_forward(Forward *, const char *, int, int); 175int parse_forward(struct Forward *, const char *, int, int);
185int default_ssh_port(void); 176int default_ssh_port(void);
186int option_clear_or_none(const char *); 177int option_clear_or_none(const char *);
187 178
188void add_local_forward(Options *, const Forward *); 179void add_local_forward(Options *, const struct Forward *);
189void add_remote_forward(Options *, const Forward *); 180void add_remote_forward(Options *, const struct Forward *);
190void add_identity_file(Options *, const char *, const char *, int); 181void add_identity_file(Options *, const char *, const char *, int);
191 182
192#endif /* READCONF_H */ 183#endif /* READCONF_H */
diff --git a/regress/Makefile b/regress/Makefile
index 6e3b8d634..3feb7a997 100644
--- a/regress/Makefile
+++ b/regress/Makefile
@@ -1,6 +1,6 @@
1# $OpenBSD: Makefile,v 1.68 2014/01/25 04:35:32 dtucker Exp $ 1# $OpenBSD: Makefile,v 1.70 2014/06/24 01:14:17 djm Exp $
2 2
3REGRESS_TARGETS= t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t-exec 3REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t-exec
4tests: $(REGRESS_TARGETS) 4tests: $(REGRESS_TARGETS)
5 5
6# Interop tests are not run by default 6# Interop tests are not run by default
@@ -180,3 +180,11 @@ t-exec-interop: ${INTEROP_TESTS:=.sh}
180 180
181# Not run by default 181# Not run by default
182interop: ${INTEROP_TARGETS} 182interop: ${INTEROP_TARGETS}
183
184# Unit tests, built by top-level Makefile
185unit:
186 set -e ; if test -z "${SKIP_UNIT}" ; then \
187 ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
188 ${.OBJDIR}/unittests/sshkey/test_sshkey \
189 -d ${.CURDIR}//unittests/sshkey/testdata ; \
190 fi
diff --git a/regress/connect-privsep.sh b/regress/connect-privsep.sh
index 94cc64acf..41cb7af69 100644
--- a/regress/connect-privsep.sh
+++ b/regress/connect-privsep.sh
@@ -1,4 +1,4 @@
1# $OpenBSD: connect-privsep.sh,v 1.4 2012/07/02 14:37:06 dtucker Exp $ 1# $OpenBSD: connect-privsep.sh,v 1.5 2014/05/04 10:40:59 logan Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="proxy connect with privsep" 4tid="proxy connect with privsep"
@@ -26,7 +26,7 @@ done
26 26
27# Because sandbox is sensitive to changes in libc, especially malloc, retest 27# Because sandbox is sensitive to changes in libc, especially malloc, retest
28# with every malloc.conf option (and none). 28# with every malloc.conf option (and none).
29for m in '' A F G H J P R S X Z '<' '>'; do 29for m in '' A F G H J P R S X '<' '>'; do
30 for p in 1 2; do 30 for p in 1 2; do
31 env MALLOC_OPTIONS="$m" ${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 true 31 env MALLOC_OPTIONS="$m" ${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 true
32 if [ $? -ne 0 ]; then 32 if [ $? -ne 0 ]; then
diff --git a/regress/dhgex.sh b/regress/dhgex.sh
index 4c1a3d83c..57fca4a32 100644
--- a/regress/dhgex.sh
+++ b/regress/dhgex.sh
@@ -1,10 +1,11 @@
1# $OpenBSD: dhgex.sh,v 1.1 2014/01/25 04:35:32 dtucker Exp $ 1# $OpenBSD: dhgex.sh,v 1.2 2014/04/21 22:15:37 djm Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="dhgex" 4tid="dhgex"
5 5
6LOG=${TEST_SSH_LOGFILE} 6LOG=${TEST_SSH_LOGFILE}
7rm -f ${LOG} 7rm -f ${LOG}
8cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
8 9
9kexs=`${SSH} -Q kex | grep diffie-hellman-group-exchange` 10kexs=`${SSH} -Q kex | grep diffie-hellman-group-exchange`
10 11
@@ -14,6 +15,9 @@ ssh_test_dhgex()
14 cipher="$1"; shift 15 cipher="$1"; shift
15 kex="$1"; shift 16 kex="$1"; shift
16 17
18 cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
19 echo "KexAlgorithms=$kex" >> $OBJ/sshd_proxy
20 echo "Ciphers=$cipher" >> $OBJ/sshd_proxy
17 rm -f ${LOG} 21 rm -f ${LOG}
18 opts="-oKexAlgorithms=$kex -oCiphers=$cipher" 22 opts="-oKexAlgorithms=$kex -oCiphers=$cipher"
19 groupsz="1024<$bits<8192" 23 groupsz="1024<$bits<8192"
diff --git a/regress/forwarding.sh b/regress/forwarding.sh
index 94873f22c..f799d4951 100644
--- a/regress/forwarding.sh
+++ b/regress/forwarding.sh
@@ -1,4 +1,4 @@
1# $OpenBSD: forwarding.sh,v 1.11 2013/06/10 21:56:43 dtucker Exp $ 1# $OpenBSD: forwarding.sh,v 1.12 2014/07/15 15:54:15 millert Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="local and remote forwarding" 4tid="local and remote forwarding"
@@ -28,7 +28,7 @@ for p in 1 2; do
28 trace "transfer over forwarded channels and check result" 28 trace "transfer over forwarded channels and check result"
29 ${SSH} -$q -F $OBJ/ssh_config -p$last -o 'ConnectionAttempts=4' \ 29 ${SSH} -$q -F $OBJ/ssh_config -p$last -o 'ConnectionAttempts=4' \
30 somehost cat ${DATA} > ${COPY} 30 somehost cat ${DATA} > ${COPY}
31 test -f ${COPY} || fail "failed copy of ${DATA}" 31 test -s ${COPY} || fail "failed copy of ${DATA}"
32 cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}" 32 cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}"
33 33
34 sleep 10 34 sleep 10
@@ -114,8 +114,24 @@ for p in 1 2; do
114 trace "config file: transfer over forwarded channels and check result" 114 trace "config file: transfer over forwarded channels and check result"
115 ${SSH} -F $OBJ/ssh_config -p${base}02 -o 'ConnectionAttempts=4' \ 115 ${SSH} -F $OBJ/ssh_config -p${base}02 -o 'ConnectionAttempts=4' \
116 somehost cat ${DATA} > ${COPY} 116 somehost cat ${DATA} > ${COPY}
117 test -f ${COPY} || fail "failed copy of ${DATA}" 117 test -s ${COPY} || fail "failed copy of ${DATA}"
118 cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}" 118 cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}"
119 119
120 wait 120 wait
121done 121done
122
123for p in 2; do
124 trace "transfer over chained unix domain socket forwards and check result"
125 rm -f $OBJ/unix-[123].fwd
126 ${SSH} -f -F $OBJ/ssh_config -R${base}01:[$OBJ/unix-1.fwd] somehost sleep 10
127 ${SSH} -f -F $OBJ/ssh_config -L[$OBJ/unix-1.fwd]:[$OBJ/unix-2.fwd] somehost sleep 10
128 ${SSH} -f -F $OBJ/ssh_config -R[$OBJ/unix-2.fwd]:[$OBJ/unix-3.fwd] somehost sleep 10
129 ${SSH} -f -F $OBJ/ssh_config -L[$OBJ/unix-3.fwd]:127.0.0.1:$PORT somehost sleep 10
130 ${SSH} -F $OBJ/ssh_config -p${base}01 -o 'ConnectionAttempts=4' \
131 somehost cat ${DATA} > ${COPY}
132 test -s ${COPY} || fail "failed copy ${DATA}"
133 cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}"
134
135 #wait
136 sleep 10
137done
diff --git a/regress/integrity.sh b/regress/integrity.sh
index 852d82690..d3a489ff7 100644
--- a/regress/integrity.sh
+++ b/regress/integrity.sh
@@ -1,7 +1,8 @@
1# $OpenBSD: integrity.sh,v 1.12 2013/11/21 03:18:51 djm Exp $ 1# $OpenBSD: integrity.sh,v 1.14 2014/05/21 07:04:21 djm Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="integrity" 4tid="integrity"
5cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
5 6
6# start at byte 2900 (i.e. after kex) and corrupt at different offsets 7# start at byte 2900 (i.e. after kex) and corrupt at different offsets
7# XXX the test hangs if we modify the low bytes of the packet length 8# XXX the test hangs if we modify the low bytes of the packet length
@@ -34,11 +35,15 @@ for m in $macs; do
34 # avoid modifying the high bytes of the length 35 # avoid modifying the high bytes of the length
35 continue 36 continue
36 fi 37 fi
38 cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
37 # modify output from sshd at offset $off 39 # modify output from sshd at offset $off
38 pxy="proxycommand=$cmd | $OBJ/modpipe -wm xor:$off:1" 40 pxy="proxycommand=$cmd | $OBJ/modpipe -wm xor:$off:1"
39 if ssh -Q cipher-auth | grep "^${m}\$" >/dev/null 2>&1 ; then 41 if ssh -Q cipher-auth | grep "^${m}\$" >/dev/null 2>&1 ; then
42 echo "Ciphers=$m" >> $OBJ/sshd_proxy
40 macopt="-c $m" 43 macopt="-c $m"
41 else 44 else
45 echo "Ciphers=aes128-ctr" >> $OBJ/sshd_proxy
46 echo "MACs=$m" >> $OBJ/sshd_proxy
42 macopt="-m $m -c aes128-ctr" 47 macopt="-m $m -c aes128-ctr"
43 fi 48 fi
44 verbose "test $tid: $m @$off" 49 verbose "test $tid: $m @$off"
@@ -49,14 +54,14 @@ for m in $macs; do
49 fail "ssh -m $m succeeds with bit-flip at $off" 54 fail "ssh -m $m succeeds with bit-flip at $off"
50 fi 55 fi
51 ecnt=`expr $ecnt + 1` 56 ecnt=`expr $ecnt + 1`
52 output=$(tail -2 $TEST_SSH_LOGFILE | egrep -v "^debug" | \ 57 out=$(tail -2 $TEST_SSH_LOGFILE | egrep -v "^debug" | \
53 tr -s '\r\n' '.') 58 tr -s '\r\n' '.')
54 case "$output" in 59 case "$out" in
55 Bad?packet*) elen=`expr $elen + 1`; skip=3;; 60 Bad?packet*) elen=`expr $elen + 1`; skip=3;;
56 Corrupted?MAC* | Decryption?integrity?check?failed*) 61 Corrupted?MAC* | Decryption?integrity?check?failed*)
57 emac=`expr $emac + 1`; skip=0;; 62 emac=`expr $emac + 1`; skip=0;;
58 padding*) epad=`expr $epad + 1`; skip=0;; 63 padding*) epad=`expr $epad + 1`; skip=0;;
59 *) fail "unexpected error mac $m at $off";; 64 *) fail "unexpected error mac $m at $off: $out";;
60 esac 65 esac
61 done 66 done
62 verbose "test $tid: $ecnt errors: mac $emac padding $epad length $elen" 67 verbose "test $tid: $ecnt errors: mac $emac padding $epad length $elen"
diff --git a/regress/kextype.sh b/regress/kextype.sh
index 8c2ac09d6..6f952f4e4 100644
--- a/regress/kextype.sh
+++ b/regress/kextype.sh
@@ -1,4 +1,4 @@
1# $OpenBSD: kextype.sh,v 1.4 2013/11/07 04:26:56 dtucker Exp $ 1# $OpenBSD: kextype.sh,v 1.5 2014/04/21 22:15:37 djm Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="login with different key exchange algorithms" 4tid="login with different key exchange algorithms"
@@ -7,6 +7,11 @@ TIME=/usr/bin/time
7cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak 7cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
8cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak 8cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak
9 9
10# Make server accept all key exchanges.
11ALLKEX=`ssh -Q kex`
12KEXOPT=`echo $ALLKEX | tr ' ' ,`
13echo "KexAlgorithms=$KEXOPT" >> $OBJ/sshd_proxy
14
10tries="1 2 3 4" 15tries="1 2 3 4"
11for k in `${SSH} -Q kex`; do 16for k in `${SSH} -Q kex`; do
12 verbose "kex $k" 17 verbose "kex $k"
diff --git a/regress/krl.sh b/regress/krl.sh
index 09246371c..287384b4a 100644
--- a/regress/krl.sh
+++ b/regress/krl.sh
@@ -1,4 +1,4 @@
1# $OpenBSD: krl.sh,v 1.2 2013/11/21 03:15:46 djm Exp $ 1# $OpenBSD: krl.sh,v 1.3 2014/06/24 01:04:43 djm Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="key revocation lists" 4tid="key revocation lists"
@@ -37,6 +37,9 @@ serial: 700-797
37serial: 798 37serial: 798
38serial: 799 38serial: 799
39serial: 599-701 39serial: 599-701
40# Some multiple consecutive serial number ranges
41serial: 10000-20000
42serial: 30000-40000
40EOF 43EOF
41 44
42# A specification that revokes some certificated by key ID. 45# A specification that revokes some certificated by key ID.
diff --git a/regress/login-timeout.sh b/regress/login-timeout.sh
index d9b48f391..eb76f554b 100644
--- a/regress/login-timeout.sh
+++ b/regress/login-timeout.sh
@@ -1,4 +1,4 @@
1# $OpenBSD: login-timeout.sh,v 1.6 2014/02/27 20:04:16 djm Exp $ 1# $OpenBSD: login-timeout.sh,v 1.7 2014/03/13 20:44:49 djm Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="connect after login grace timeout" 4tid="connect after login grace timeout"
@@ -22,6 +22,7 @@ $SUDO kill `$SUDO cat $PIDFILE`
22trace "test login grace without privsep" 22trace "test login grace without privsep"
23echo "UsePrivilegeSeparation no" >> $OBJ/sshd_config 23echo "UsePrivilegeSeparation no" >> $OBJ/sshd_config
24start_sshd 24start_sshd
25sleep 1
25 26
26(echo SSH-2.0-fake; sleep 60) | telnet 127.0.0.1 ${PORT} >/dev/null 2>&1 & 27(echo SSH-2.0-fake; sleep 60) | telnet 127.0.0.1 ${PORT} >/dev/null 2>&1 &
27sleep 15 28sleep 15
diff --git a/regress/multiplex.sh b/regress/multiplex.sh
index 3e697e691..8ee140be6 100644
--- a/regress/multiplex.sh
+++ b/regress/multiplex.sh
@@ -1,10 +1,26 @@
1# $OpenBSD: multiplex.sh,v 1.21 2013/05/17 04:29:14 dtucker Exp $ 1# $OpenBSD: multiplex.sh,v 1.25 2014/07/22 01:32:12 djm Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4CTL=/tmp/openssh.regress.ctl-sock.$$ 4CTL=/tmp/openssh.regress.ctl-sock.$$
5 5
6tid="connection multiplexing" 6tid="connection multiplexing"
7 7
8if have_prog nc ; then
9 if nc -h 2>&1 | grep -- -N >/dev/null; then
10 NC="nc -N";
11 elif nc -h 2>&1 | grep -- "-U.*Use UNIX" >/dev/null ; then
12 NC="nc"
13 else
14 echo "nc is incompatible"
15 fi
16fi
17
18if test -z "$NC" ; then
19 echo "skipped (no compatible nc found)"
20 exit 0
21fi
22
23trace "will use ProxyCommand $proxycmd"
8if config_defined DISABLE_FD_PASSING ; then 24if config_defined DISABLE_FD_PASSING ; then
9 echo "skipped (not supported on this platform)" 25 echo "skipped (not supported on this platform)"
10 exit 0 26 exit 0
@@ -29,7 +45,8 @@ start_mux_master()
29 trace "start master, fork to background" 45 trace "start master, fork to background"
30 ${SSH} -Nn2 -MS$CTL -F $OBJ/ssh_config -oSendEnv="_XXX_TEST" somehost \ 46 ${SSH} -Nn2 -MS$CTL -F $OBJ/ssh_config -oSendEnv="_XXX_TEST" somehost \
31 -E $TEST_REGRESS_LOGFILE 2>&1 & 47 -E $TEST_REGRESS_LOGFILE 2>&1 &
32 MASTER_PID=$! 48 # NB. $SSH_PID will be killed by test-exec.sh:cleanup on fatal errors.
49 SSH_PID=$!
33 wait_for_mux_master_ready 50 wait_for_mux_master_ready
34} 51}
35 52
@@ -71,6 +88,25 @@ test -f ${COPY} || fail "scp: failed copy ${DATA}"
71cmp ${DATA} ${COPY} || fail "scp: corrupted copy of ${DATA}" 88cmp ${DATA} ${COPY} || fail "scp: corrupted copy of ${DATA}"
72 89
73rm -f ${COPY} 90rm -f ${COPY}
91verbose "test $tid: forward"
92trace "forward over TCP/IP and check result"
93$NC -l 127.0.0.1 $((${PORT} + 1)) < ${DATA} &
94netcat_pid=$!
95${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
96$NC -d 127.0.0.1 $((${PORT} + 2)) > ${COPY} < /dev/null
97cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}"
98kill $netcat_pid 2>/dev/null
99rm -f ${COPY} $OBJ/unix-[123].fwd
100
101trace "forward over UNIX and check result"
102$NC -Ul $OBJ/unix-1.fwd < ${DATA} &
103netcat_pid=$!
104${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L$OBJ/unix-2.fwd:$OBJ/unix-1.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1
105${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R$OBJ/unix-3.fwd:$OBJ/unix-2.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1
106$NC -d -U $OBJ/unix-3.fwd > ${COPY} </dev/null
107cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}"
108kill $netcat_pid 2>/dev/null
109rm -f ${COPY} $OBJ/unix-[123].fwd
74 110
75for s in 0 1 4 5 44; do 111for s in 0 1 4 5 44; do
76 trace "exit status $s over multiplexed connection" 112 trace "exit status $s over multiplexed connection"
@@ -95,7 +131,7 @@ verbose "test $tid: cmd check"
95${SSH} -F $OBJ/ssh_config -S $CTL -Ocheck otherhost >>$TEST_REGRESS_LOGFILE 2>&1 \ 131${SSH} -F $OBJ/ssh_config -S $CTL -Ocheck otherhost >>$TEST_REGRESS_LOGFILE 2>&1 \
96 || fail "check command failed" 132 || fail "check command failed"
97 133
98verbose "test $tid: cmd forward local" 134verbose "test $tid: cmd forward local (TCP)"
99${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L $P:localhost:$PORT otherhost \ 135${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L $P:localhost:$PORT otherhost \
100 || fail "request local forward failed" 136 || fail "request local forward failed"
101${SSH} -F $OBJ/ssh_config -p$P otherhost true \ 137${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 \
105${SSH} -F $OBJ/ssh_config -p$P otherhost true \ 141${SSH} -F $OBJ/ssh_config -p$P otherhost true \
106 && fail "local forward port still listening" 142 && fail "local forward port still listening"
107 143
108verbose "test $tid: cmd forward remote" 144verbose "test $tid: cmd forward remote (TCP)"
109${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R $P:localhost:$PORT otherhost \ 145${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R $P:localhost:$PORT otherhost \
110 || fail "request remote forward failed" 146 || fail "request remote forward failed"
111${SSH} -F $OBJ/ssh_config -p$P otherhost true \ 147${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 \
115${SSH} -F $OBJ/ssh_config -p$P otherhost true \ 151${SSH} -F $OBJ/ssh_config -p$P otherhost true \
116 && fail "remote forward port still listening" 152 && fail "remote forward port still listening"
117 153
154verbose "test $tid: cmd forward local (UNIX)"
155${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L $OBJ/unix-1.fwd:localhost:$PORT otherhost \
156 || fail "request local forward failed"
157echo "" | $NC -U $OBJ/unix-1.fwd | grep "Protocol mismatch" >/dev/null 2>&1 \
158 || fail "connect to local forward path failed"
159${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -L $OBJ/unix-1.fwd:localhost:$PORT otherhost \
160 || fail "cancel local forward failed"
161N=$(echo "xyzzy" | $NC -U $OBJ/unix-1.fwd 2>&1 | grep "xyzzy" | wc -l)
162test ${N} -eq 0 || fail "local forward path still listening"
163rm -f $OBJ/unix-1.fwd
164
165verbose "test $tid: cmd forward remote (UNIX)"
166${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R $OBJ/unix-1.fwd:localhost:$PORT otherhost \
167 || fail "request remote forward failed"
168echo "" | $NC -U $OBJ/unix-1.fwd | grep "Protocol mismatch" >/dev/null 2>&1 \
169 || fail "connect to remote forwarded path failed"
170${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -R $OBJ/unix-1.fwd:localhost:$PORT otherhost \
171 || fail "cancel remote forward failed"
172N=$(echo "xyzzy" | $NC -U $OBJ/unix-1.fwd 2>&1 | grep "xyzzy" | wc -l)
173test ${N} -eq 0 || fail "remote forward path still listening"
174rm -f $OBJ/unix-1.fwd
175
118verbose "test $tid: cmd exit" 176verbose "test $tid: cmd exit"
119${SSH} -F $OBJ/ssh_config -S $CTL -Oexit otherhost >>$TEST_REGRESS_LOGFILE 2>&1 \ 177${SSH} -F $OBJ/ssh_config -S $CTL -Oexit otherhost >>$TEST_REGRESS_LOGFILE 2>&1 \
120 || fail "send exit command failed" 178 || fail "send exit command failed"
121 179
122# Wait for master to exit 180# Wait for master to exit
123wait $MASTER_PID 181wait $SSH_PID
124kill -0 $MASTER_PID >/dev/null 2>&1 && fail "exit command failed" 182kill -0 $SSH_PID >/dev/null 2>&1 && fail "exit command failed"
125 183
126# Restart master and test -O stop command with master using -N 184# Restart master and test -O stop command with master using -N
127verbose "test $tid: cmd stop" 185verbose "test $tid: cmd stop"
@@ -138,6 +196,8 @@ ${SSH} -F $OBJ/ssh_config -S $CTL -Ostop otherhost >>$TEST_REGRESS_LOGFILE 2>&1
138# wait until both long-running command and master have exited. 196# wait until both long-running command and master have exited.
139wait $SLEEP_PID 197wait $SLEEP_PID
140[ $! != 0 ] || fail "waiting for concurrent command" 198[ $! != 0 ] || fail "waiting for concurrent command"
141wait $MASTER_PID 199wait $SSH_PID
142[ $! != 0 ] || fail "waiting for master stop" 200[ $! != 0 ] || fail "waiting for master stop"
143kill -0 $MASTER_PID >/dev/null 2>&1 && fail "stop command failed" 201kill -0 $SSH_PID >/dev/null 2>&1 && fatal "stop command failed"
202SSH_PID="" # Already gone, so don't kill in cleanup
203
diff --git a/regress/proxy-connect.sh b/regress/proxy-connect.sh
index 76e602dd6..023ba7367 100644
--- a/regress/proxy-connect.sh
+++ b/regress/proxy-connect.sh
@@ -1,26 +1,31 @@
1# $OpenBSD: proxy-connect.sh,v 1.6 2013/03/07 00:20:34 djm Exp $ 1# $OpenBSD: proxy-connect.sh,v 1.7 2014/05/03 18:46:14 dtucker Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="proxy connect" 4tid="proxy connect"
5 5
6verbose "plain username" 6mv $OBJ/sshd_proxy $OBJ/sshd_proxy.orig
7for p in 1 2; do 7
8 ${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 true 8for ps in no yes; do
9 if [ $? -ne 0 ]; then 9 cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
10 fail "ssh proxyconnect protocol $p failed" 10 echo "UsePrivilegeSeparation $ps" >> $OBJ/sshd_proxy
11 fi 11
12 SSH_CONNECTION=`${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 'echo $SSH_CONNECTION'` 12 for p in 1 2; do
13 for c in no yes; do
14 verbose "plain username protocol $p privsep=$ps comp=$c"
15 opts="-$p -oCompression=$c -F $OBJ/ssh_proxy"
16 SSH_CONNECTION=`${SSH} $opts 999.999.999.999 'echo $SSH_CONNECTION'`
13 if [ $? -ne 0 ]; then 17 if [ $? -ne 0 ]; then
14 fail "ssh proxyconnect protocol $p failed" 18 fail "ssh proxyconnect protocol $p privsep=$ps comp=$c failed"
15 fi 19 fi
16 if [ "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ]; then 20 if [ "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ]; then
17 fail "bad SSH_CONNECTION" 21 fail "bad SSH_CONNECTION protocol $p privsep=$ps comp=$c"
18 fi 22 fi
23 done
24 done
19done 25done
20 26
21verbose "username with style"
22for p in 1 2; do 27for p in 1 2; do
28 verbose "username with style protocol $p"
23 ${SSH} -$p -F $OBJ/ssh_proxy ${USER}:style@999.999.999.999 true || \ 29 ${SSH} -$p -F $OBJ/ssh_proxy ${USER}:style@999.999.999.999 true || \
24 fail "ssh proxyconnect protocol $p failed" 30 fail "ssh proxyconnect protocol $p failed"
25done 31done
26
diff --git a/regress/rekey.sh b/regress/rekey.sh
index cf9401ea0..fd452b034 100644
--- a/regress/rekey.sh
+++ b/regress/rekey.sh
@@ -1,4 +1,4 @@
1# $OpenBSD: rekey.sh,v 1.14 2013/11/21 03:18:51 djm Exp $ 1# $OpenBSD: rekey.sh,v 1.15 2014/04/21 22:15:37 djm Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="rekey" 4tid="rekey"
@@ -6,14 +6,22 @@ tid="rekey"
6LOG=${TEST_SSH_LOGFILE} 6LOG=${TEST_SSH_LOGFILE}
7 7
8rm -f ${LOG} 8rm -f ${LOG}
9cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
9 10
10# Test rekeying based on data volume only. 11# Test rekeying based on data volume only.
11# Arguments will be passed to ssh. 12# Arguments will be passed to ssh.
12ssh_data_rekeying() 13ssh_data_rekeying()
13{ 14{
15 _kexopt=$1 ; shift
16 _opts="$@"
17 if ! test -z "$_kexopts" ; then
18 cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
19 echo "$_kexopt" >> $OBJ/sshd_proxy
20 _opts="$_opts -o$_kexopt"
21 fi
14 rm -f ${COPY} ${LOG} 22 rm -f ${COPY} ${LOG}
15 ${SSH} <${DATA} -oCompression=no $@ -v -F $OBJ/ssh_proxy somehost \ 23 _opts="$_opts -oCompression=no"
16 "cat > ${COPY}" 24 ${SSH} <${DATA} $_opts -v -F $OBJ/ssh_proxy somehost "cat > ${COPY}"
17 if [ $? -ne 0 ]; then 25 if [ $? -ne 0 ]; then
18 fail "ssh failed ($@)" 26 fail "ssh failed ($@)"
19 fi 27 fi
@@ -41,7 +49,7 @@ done
41 49
42for opt in $opts; do 50for opt in $opts; do
43 verbose "client rekey $opt" 51 verbose "client rekey $opt"
44 ssh_data_rekeying -oRekeyLimit=256k -o$opt 52 ssh_data_rekeying "$opt" -oRekeyLimit=256k
45done 53done
46 54
47# AEAD ciphers are magical so test with all KexAlgorithms 55# AEAD ciphers are magical so test with all KexAlgorithms
@@ -49,14 +57,14 @@ if ${SSH} -Q cipher-auth | grep '^.*$' >/dev/null 2>&1 ; then
49 for c in `${SSH} -Q cipher-auth`; do 57 for c in `${SSH} -Q cipher-auth`; do
50 for kex in `${SSH} -Q kex`; do 58 for kex in `${SSH} -Q kex`; do
51 verbose "client rekey $c $kex" 59 verbose "client rekey $c $kex"
52 ssh_data_rekeying -oRekeyLimit=256k -oCiphers=$c -oKexAlgorithms=$kex 60 ssh_data_rekeying "KexAlgorithms=$kex" -oRekeyLimit=256k -oCiphers=$c
53 done 61 done
54 done 62 done
55fi 63fi
56 64
57for s in 16 1k 128k 256k; do 65for s in 16 1k 128k 256k; do
58 verbose "client rekeylimit ${s}" 66 verbose "client rekeylimit ${s}"
59 ssh_data_rekeying -oCompression=no -oRekeyLimit=$s 67 ssh_data_rekeying "" -oCompression=no -oRekeyLimit=$s
60done 68done
61 69
62for s in 5 10; do 70for s in 5 10; do
diff --git a/regress/test-exec.sh b/regress/test-exec.sh
index aac8aa5c2..a1bab832f 100644
--- a/regress/test-exec.sh
+++ b/regress/test-exec.sh
@@ -1,4 +1,4 @@
1# $OpenBSD: test-exec.sh,v 1.47 2013/11/09 05:41:34 dtucker Exp $ 1# $OpenBSD: test-exec.sh,v 1.48 2014/07/06 07:42:03 djm Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4#SUDO=sudo 4#SUDO=sudo
@@ -240,13 +240,20 @@ md5 () {
240# helper 240# helper
241cleanup () 241cleanup ()
242{ 242{
243 if [ "x$SSH_PID" != "x" ]; then
244 if [ $SSH_PID -lt 2 ]; then
245 echo bad pid for ssh: $SSH_PID
246 else
247 kill $SSH_PID
248 fi
249 fi
243 if [ -f $PIDFILE ]; then 250 if [ -f $PIDFILE ]; then
244 pid=`$SUDO cat $PIDFILE` 251 pid=`$SUDO cat $PIDFILE`
245 if [ "X$pid" = "X" ]; then 252 if [ "X$pid" = "X" ]; then
246 echo no sshd running 253 echo no sshd running
247 else 254 else
248 if [ $pid -lt 2 ]; then 255 if [ $pid -lt 2 ]; then
249 echo bad pid for ssh: $pid 256 echo bad pid for sshd: $pid
250 else 257 else
251 $SUDO kill $pid 258 $SUDO kill $pid
252 trace "wait for sshd to exit" 259 trace "wait for sshd to exit"
diff --git a/regress/try-ciphers.sh b/regress/try-ciphers.sh
index ac34cedbf..2881ce16c 100644
--- a/regress/try-ciphers.sh
+++ b/regress/try-ciphers.sh
@@ -1,13 +1,18 @@
1# $OpenBSD: try-ciphers.sh,v 1.22 2013/11/21 03:18:51 djm Exp $ 1# $OpenBSD: try-ciphers.sh,v 1.23 2014/04/21 22:15:37 djm Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="try ciphers" 4tid="try ciphers"
5 5
6cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
7
6for c in `${SSH} -Q cipher`; do 8for c in `${SSH} -Q cipher`; do
7 n=0 9 n=0
8 for m in `${SSH} -Q mac`; do 10 for m in `${SSH} -Q mac`; do
9 trace "proto 2 cipher $c mac $m" 11 trace "proto 2 cipher $c mac $m"
10 verbose "test $tid: proto 2 cipher $c mac $m" 12 verbose "test $tid: proto 2 cipher $c mac $m"
13 cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
14 echo "Ciphers=$c" >> $OBJ/sshd_proxy
15 echo "MACs=$m" >> $OBJ/sshd_proxy
11 ${SSH} -F $OBJ/ssh_proxy -2 -m $m -c $c somehost true 16 ${SSH} -F $OBJ/ssh_proxy -2 -m $m -c $c somehost true
12 if [ $? -ne 0 ]; then 17 if [ $? -ne 0 ]; then
13 fail "ssh -2 failed with mac $m cipher $c" 18 fail "ssh -2 failed with mac $m cipher $c"
diff --git a/regress/unittests/Makefile b/regress/unittests/Makefile
new file mode 100644
index 000000000..bdb4574e2
--- /dev/null
+++ b/regress/unittests/Makefile
@@ -0,0 +1,5 @@
1# $OpenBSD: Makefile,v 1.1 2014/04/30 05:32:00 djm Exp $
2
3SUBDIR= test_helper sshbuf sshkey
4
5.include <bsd.subdir.mk>
diff --git a/regress/unittests/Makefile.inc b/regress/unittests/Makefile.inc
new file mode 100644
index 000000000..4c3363749
--- /dev/null
+++ b/regress/unittests/Makefile.inc
@@ -0,0 +1,59 @@
1# $OpenBSD: Makefile.inc,v 1.1 2014/04/30 05:32:00 djm Exp $
2
3.include <bsd.own.mk>
4.include <bsd.obj.mk>
5
6# enable warnings
7WARNINGS=Yes
8
9DEBUG=-g
10CFLAGS+= -fstack-protector-all
11CDIAGFLAGS= -Wall
12CDIAGFLAGS+= -Wextra
13CDIAGFLAGS+= -Werror
14CDIAGFLAGS+= -Wchar-subscripts
15CDIAGFLAGS+= -Wcomment
16CDIAGFLAGS+= -Wformat
17CDIAGFLAGS+= -Wformat-security
18CDIAGFLAGS+= -Wimplicit
19CDIAGFLAGS+= -Winline
20CDIAGFLAGS+= -Wmissing-declarations
21CDIAGFLAGS+= -Wmissing-prototypes
22CDIAGFLAGS+= -Wparentheses
23CDIAGFLAGS+= -Wpointer-arith
24CDIAGFLAGS+= -Wpointer-sign
25CDIAGFLAGS+= -Wreturn-type
26CDIAGFLAGS+= -Wshadow
27CDIAGFLAGS+= -Wsign-compare
28CDIAGFLAGS+= -Wstrict-aliasing
29CDIAGFLAGS+= -Wstrict-prototypes
30CDIAGFLAGS+= -Wswitch
31CDIAGFLAGS+= -Wtrigraphs
32CDIAGFLAGS+= -Wuninitialized
33CDIAGFLAGS+= -Wunused
34.if ${COMPILER_VERSION} == "gcc4"
35CDIAGFLAGS+= -Wold-style-definition
36.endif
37
38SSHREL=../../../../../usr.bin/ssh
39
40CFLAGS+=-I${.CURDIR}/../test_helper -I${.CURDIR}/${SSHREL}
41
42.if exists(${.CURDIR}/../test_helper/${__objdir})
43LDADD+=-L${.CURDIR}/../test_helper/${__objdir} -ltest_helper
44DPADD+=${.CURDIR}/../test_helper/${__objdir}/libtest_helper.a
45.else
46LDADD+=-L${.CURDIR}/../test_helper -ltest_helper
47DPADD+=${.CURDIR}/../test_helper/libtest_helper.a
48.endif
49
50.if exists(${.CURDIR}/${SSHREL}/lib/${__objdir})
51LDADD+=-L${.CURDIR}/${SSHREL}/lib/${__objdir} -lssh
52DPADD+=${.CURDIR}/${SSHREL}/lib/${__objdir}/libssh.a
53.else
54LDADD+=-L${.CURDIR}/${SSHREL}/lib -lssh
55DPADD+=${.CURDIR}/${SSHREL}/lib/libssh.a
56.endif
57
58LDADD+= -lcrypto
59DPADD+= ${LIBCRYPTO}
diff --git a/regress/unittests/sshbuf/Makefile b/regress/unittests/sshbuf/Makefile
new file mode 100644
index 000000000..85f99ac38
--- /dev/null
+++ b/regress/unittests/sshbuf/Makefile
@@ -0,0 +1,14 @@
1# $OpenBSD: Makefile,v 1.1 2014/04/30 05:32:00 djm Exp $
2
3PROG=test_sshbuf
4SRCS=tests.c
5SRCS+=test_sshbuf.c
6SRCS+=test_sshbuf_getput_basic.c
7SRCS+=test_sshbuf_getput_crypto.c
8SRCS+=test_sshbuf_misc.c
9SRCS+=test_sshbuf_fuzz.c
10SRCS+=test_sshbuf_getput_fuzz.c
11SRCS+=test_sshbuf_fixed.c
12
13.include <bsd.regress.mk>
14
diff --git a/regress/unittests/sshbuf/test_sshbuf.c b/regress/unittests/sshbuf/test_sshbuf.c
new file mode 100644
index 000000000..ee77d6934
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf.c
@@ -0,0 +1,240 @@
1/* $OpenBSD: test_sshbuf.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
2/*
3 * Regress test for sshbuf.h buffer API
4 *
5 * Placed in the public domain
6 */
7
8#define SSHBUF_INTERNAL 1 /* access internals for testing */
9#include "includes.h"
10
11#include <sys/types.h>
12#include <sys/param.h>
13#include <stdio.h>
14#ifdef HAVE_STDINT_H
15# include <stdint.h>
16#endif
17#include <stdlib.h>
18#include <string.h>
19
20#include "../test_helper/test_helper.h"
21
22#include "ssherr.h"
23#include "sshbuf.h"
24
25void sshbuf_tests(void);
26
27void
28sshbuf_tests(void)
29{
30 struct sshbuf *p1;
31 const u_char *cdp;
32 u_char *dp;
33 size_t sz;
34 int r;
35
36 TEST_START("allocate sshbuf");
37 p1 = sshbuf_new();
38 ASSERT_PTR_NE(p1, NULL);
39 TEST_DONE();
40
41 TEST_START("max size on fresh buffer");
42 ASSERT_SIZE_T_GT(sshbuf_max_size(p1), 0);
43 TEST_DONE();
44
45 TEST_START("available on fresh buffer");
46 ASSERT_SIZE_T_GT(sshbuf_avail(p1), 0);
47 TEST_DONE();
48
49 TEST_START("len = 0 on empty buffer");
50 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
51 TEST_DONE();
52
53 TEST_START("set valid max size");
54 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 65536), 0);
55 ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 65536);
56 TEST_DONE();
57
58 TEST_START("available on limited buffer");
59 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 65536);
60 TEST_DONE();
61
62 TEST_START("free");
63 sshbuf_free(p1);
64 TEST_DONE();
65
66 TEST_START("consume on empty buffer");
67 p1 = sshbuf_new();
68 ASSERT_PTR_NE(p1, NULL);
69 ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0);
70 ASSERT_INT_EQ(sshbuf_consume(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE);
71 sshbuf_free(p1);
72 TEST_DONE();
73
74 TEST_START("consume_end on empty buffer");
75 p1 = sshbuf_new();
76 ASSERT_PTR_NE(p1, NULL);
77 ASSERT_INT_EQ(sshbuf_consume_end(p1, 0), 0);
78 ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE);
79 sshbuf_free(p1);
80 TEST_DONE();
81
82 TEST_START("reserve space");
83 p1 = sshbuf_new();
84 ASSERT_PTR_NE(p1, NULL);
85 r = sshbuf_reserve(p1, 1, &dp);
86 ASSERT_INT_EQ(r, 0);
87 ASSERT_PTR_NE(dp, NULL);
88 *dp = 0x11;
89 r = sshbuf_reserve(p1, 3, &dp);
90 ASSERT_INT_EQ(r, 0);
91 ASSERT_PTR_NE(dp, NULL);
92 *dp++ = 0x22;
93 *dp++ = 0x33;
94 *dp++ = 0x44;
95 TEST_DONE();
96
97 TEST_START("sshbuf_len on filled buffer");
98 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
99 TEST_DONE();
100
101 TEST_START("sshbuf_ptr on filled buffer");
102 cdp = sshbuf_ptr(p1);
103 ASSERT_PTR_NE(cdp, NULL);
104 ASSERT_U8_EQ(cdp[0], 0x11);
105 ASSERT_U8_EQ(cdp[1], 0x22);
106 ASSERT_U8_EQ(cdp[2], 0x33);
107 ASSERT_U8_EQ(cdp[3], 0x44);
108 TEST_DONE();
109
110 TEST_START("consume on filled buffer");
111 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
112 ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0);
113 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
114 r = sshbuf_consume(p1, 64);
115 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
116 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
117 ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0);
118 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 3);
119 cdp = sshbuf_ptr(p1);
120 ASSERT_PTR_NE(p1, NULL);
121 ASSERT_U8_EQ(cdp[0], 0x22);
122 ASSERT_INT_EQ(sshbuf_consume(p1, 2), 0);
123 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
124 cdp = sshbuf_ptr(p1);
125 ASSERT_PTR_NE(p1, NULL);
126 ASSERT_U8_EQ(cdp[0], 0x44);
127 r = sshbuf_consume(p1, 2);
128 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
129 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
130 ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0);
131 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
132 r = sshbuf_consume(p1, 1);
133 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
134 sshbuf_free(p1);
135 TEST_DONE();
136
137 TEST_START("consume_end on filled buffer");
138 p1 = sshbuf_new();
139 ASSERT_PTR_NE(p1, NULL);
140 r = sshbuf_reserve(p1, 4, &dp);
141 ASSERT_INT_EQ(r, 0);
142 ASSERT_PTR_NE(dp, NULL);
143 *dp++ = 0x11;
144 *dp++ = 0x22;
145 *dp++ = 0x33;
146 *dp++ = 0x44;
147 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
148 r = sshbuf_consume_end(p1, 5);
149 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
150 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
151 ASSERT_INT_EQ(sshbuf_consume_end(p1, 3), 0);
152 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
153 cdp = sshbuf_ptr(p1);
154 ASSERT_PTR_NE(cdp, NULL);
155 ASSERT_U8_EQ(*cdp, 0x11);
156 r = sshbuf_consume_end(p1, 2);
157 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
158 ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), 0);
159 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
160 sshbuf_free(p1);
161 TEST_DONE();
162
163 TEST_START("fill limited buffer");
164 p1 = sshbuf_new();
165 ASSERT_PTR_NE(p1, NULL);
166 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0);
167 ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
168 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223);
169 r = sshbuf_reserve(p1, 1223, &dp);
170 ASSERT_INT_EQ(r, 0);
171 ASSERT_PTR_NE(dp, NULL);
172 memset(dp, 0xd7, 1223);
173 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223);
174 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 0);
175 r = sshbuf_reserve(p1, 1, &dp);
176 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
177 ASSERT_PTR_EQ(dp, NULL);
178 TEST_DONE();
179
180 TEST_START("consume and force compaction");
181 ASSERT_INT_EQ(sshbuf_consume(p1, 223), 0);
182 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000);
183 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223);
184 r = sshbuf_reserve(p1, 224, &dp);
185 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
186 ASSERT_PTR_EQ(dp, NULL);
187 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000);
188 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223);
189 r = sshbuf_reserve(p1, 223, &dp);
190 ASSERT_INT_EQ(r, 0);
191 ASSERT_PTR_NE(dp, NULL);
192 memset(dp, 0x7d, 223);
193 cdp = sshbuf_ptr(p1);
194 ASSERT_PTR_NE(cdp, NULL);
195 ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000);
196 ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223);
197 TEST_DONE();
198
199 TEST_START("resize full buffer");
200 r = sshbuf_set_max_size(p1, 1000);
201 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
202 sz = roundup(1223 + SSHBUF_SIZE_INC * 3, SSHBUF_SIZE_INC);
203 ASSERT_INT_EQ(sshbuf_set_max_size(p1, sz), 0);
204 ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
205 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - 1223);
206 ASSERT_INT_EQ(sshbuf_len(p1), 1223);
207 TEST_DONE();
208
209 /* NB. uses sshbuf internals */
210 TEST_START("alloc chunking");
211 r = sshbuf_reserve(p1, 1, &dp);
212 ASSERT_INT_EQ(r, 0);
213 ASSERT_PTR_NE(dp, NULL);
214 *dp = 0xff;
215 cdp = sshbuf_ptr(p1);
216 ASSERT_PTR_NE(cdp, NULL);
217 ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000);
218 ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223);
219 ASSERT_MEM_FILLED_EQ(cdp + 1223, 0xff, 1);
220 ASSERT_SIZE_T_EQ(sshbuf_alloc(p1) % SSHBUF_SIZE_INC, 0);
221 sshbuf_free(p1);
222 TEST_DONE();
223
224 TEST_START("reset buffer");
225 p1 = sshbuf_new();
226 ASSERT_PTR_NE(p1, NULL);
227 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0);
228 ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
229 r = sshbuf_reserve(p1, 1223, &dp);
230 ASSERT_INT_EQ(r, 0);
231 ASSERT_PTR_NE(dp, NULL);
232 memset(dp, 0xd7, 1223);
233 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223);
234 sshbuf_reset(p1);
235 ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
236 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
237 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223);
238 sshbuf_free(p1);
239 TEST_DONE();
240}
diff --git a/regress/unittests/sshbuf/test_sshbuf_fixed.c b/regress/unittests/sshbuf/test_sshbuf_fixed.c
new file mode 100644
index 000000000..df4925f7c
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_fixed.c
@@ -0,0 +1,126 @@
1/* $OpenBSD: test_sshbuf_fixed.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
2/*
3 * Regress test for sshbuf.h buffer API
4 *
5 * Placed in the public domain
6 */
7
8#define SSHBUF_INTERNAL 1 /* access internals for testing */
9#include "includes.h"
10
11#include <sys/types.h>
12#include <sys/param.h>
13#include <stdio.h>
14#ifdef HAVE_STDINT_H
15# include <stdint.h>
16#endif
17#include <stdlib.h>
18#include <string.h>
19
20#include "../test_helper/test_helper.h"
21
22#include "sshbuf.h"
23#include "ssherr.h"
24
25void sshbuf_fixed(void);
26
27const u_char test_buf[] = "\x01\x12\x34\x56\x78\x00\x00\x00\x05hello";
28
29void
30sshbuf_fixed(void)
31{
32 struct sshbuf *p1, *p2, *p3;
33 u_char c;
34 char *s;
35 u_int i;
36 size_t l;
37
38 TEST_START("sshbuf_from");
39 p1 = sshbuf_from(test_buf, sizeof(test_buf));
40 ASSERT_PTR_NE(p1, NULL);
41 ASSERT_PTR_EQ(sshbuf_mutable_ptr(p1), NULL);
42 ASSERT_INT_EQ(sshbuf_check_reserve(p1, 1), SSH_ERR_BUFFER_READ_ONLY);
43 ASSERT_INT_EQ(sshbuf_reserve(p1, 1, NULL), SSH_ERR_BUFFER_READ_ONLY);
44 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 200), SSH_ERR_BUFFER_READ_ONLY);
45 ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), SSH_ERR_BUFFER_READ_ONLY);
46 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 0);
47 ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf);
48 sshbuf_free(p1);
49 TEST_DONE();
50
51 TEST_START("sshbuf_from data");
52 p1 = sshbuf_from(test_buf, sizeof(test_buf) - 1);
53 ASSERT_PTR_NE(p1, NULL);
54 ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf);
55 ASSERT_INT_EQ(sshbuf_get_u8(p1, &c), 0);
56 ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf + 1);
57 ASSERT_U8_EQ(c, 1);
58 ASSERT_INT_EQ(sshbuf_get_u32(p1, &i), 0);
59 ASSERT_PTR_EQ(sshbuf_ptr(p1), test_buf + 5);
60 ASSERT_U32_EQ(i, 0x12345678);
61 ASSERT_INT_EQ(sshbuf_get_cstring(p1, &s, &l), 0);
62 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
63 ASSERT_STRING_EQ(s, "hello");
64 ASSERT_SIZE_T_EQ(l, 5);
65 sshbuf_free(p1);
66 free(s);
67 TEST_DONE();
68
69 TEST_START("sshbuf_fromb ");
70 p1 = sshbuf_new();
71 ASSERT_PTR_NE(p1, NULL);
72 ASSERT_U_INT_EQ(sshbuf_refcount(p1), 1);
73 ASSERT_PTR_EQ(sshbuf_parent(p1), NULL);
74 ASSERT_INT_EQ(sshbuf_put(p1, test_buf, sizeof(test_buf) - 1), 0);
75 p2 = sshbuf_fromb(p1);
76 ASSERT_PTR_NE(p2, NULL);
77 ASSERT_U_INT_EQ(sshbuf_refcount(p1), 2);
78 ASSERT_PTR_EQ(sshbuf_parent(p1), NULL);
79 ASSERT_PTR_EQ(sshbuf_parent(p2), p1);
80 ASSERT_PTR_EQ(sshbuf_ptr(p2), sshbuf_ptr(p1));
81 ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
82 ASSERT_PTR_NE(sshbuf_ptr(p2), NULL);
83 ASSERT_PTR_EQ(sshbuf_mutable_ptr(p1), NULL);
84 ASSERT_PTR_EQ(sshbuf_mutable_ptr(p2), NULL);
85 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sshbuf_len(p2));
86 ASSERT_INT_EQ(sshbuf_get_u8(p2, &c), 0);
87 ASSERT_PTR_EQ(sshbuf_ptr(p2), sshbuf_ptr(p1) + 1);
88 ASSERT_U8_EQ(c, 1);
89 ASSERT_INT_EQ(sshbuf_get_u32(p2, &i), 0);
90 ASSERT_PTR_EQ(sshbuf_ptr(p2), sshbuf_ptr(p1) + 5);
91 ASSERT_U32_EQ(i, 0x12345678);
92 ASSERT_INT_EQ(sshbuf_get_cstring(p2, &s, &l), 0);
93 ASSERT_SIZE_T_EQ(sshbuf_len(p2), 0);
94 ASSERT_STRING_EQ(s, "hello");
95 ASSERT_SIZE_T_EQ(l, 5);
96 sshbuf_free(p1);
97 ASSERT_U_INT_EQ(sshbuf_refcount(p1), 1);
98 sshbuf_free(p2);
99 free(s);
100 TEST_DONE();
101
102 TEST_START("sshbuf_froms");
103 p1 = sshbuf_new();
104 ASSERT_PTR_NE(p1, NULL);
105 ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x01), 0);
106 ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), 0);
107 ASSERT_INT_EQ(sshbuf_put_cstring(p1, "hello"), 0);
108 p2 = sshbuf_new();
109 ASSERT_PTR_NE(p2, NULL);
110 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(test_buf) - 1);
111 ASSERT_INT_EQ(sshbuf_put_stringb(p2, p1), 0);
112 ASSERT_SIZE_T_EQ(sshbuf_len(p2), sizeof(test_buf) + 4 - 1);
113 ASSERT_INT_EQ(sshbuf_froms(p2, &p3), 0);
114 ASSERT_SIZE_T_EQ(sshbuf_len(p2), 0);
115 ASSERT_PTR_NE(p3, NULL);
116 ASSERT_PTR_NE(sshbuf_ptr(p3), NULL);
117 ASSERT_SIZE_T_EQ(sshbuf_len(p3), sizeof(test_buf) - 1);
118 ASSERT_MEM_EQ(sshbuf_ptr(p3), test_buf, sizeof(test_buf) - 1);
119 sshbuf_free(p3);
120 ASSERT_INT_EQ(sshbuf_put_stringb(p2, p1), 0);
121 ASSERT_INT_EQ(sshbuf_consume_end(p2, 1), 0);
122 ASSERT_INT_EQ(sshbuf_froms(p2, &p3), SSH_ERR_MESSAGE_INCOMPLETE);
123 ASSERT_PTR_EQ(p3, NULL);
124 sshbuf_free(p2);
125 sshbuf_free(p1);
126}
diff --git a/regress/unittests/sshbuf/test_sshbuf_fuzz.c b/regress/unittests/sshbuf/test_sshbuf_fuzz.c
new file mode 100644
index 000000000..c52376b53
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_fuzz.c
@@ -0,0 +1,127 @@
1/* $OpenBSD: test_sshbuf_fuzz.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
2/*
3 * Regress test for sshbuf.h buffer API
4 *
5 * Placed in the public domain
6 */
7
8#include "includes.h"
9
10#include <sys/types.h>
11#include <sys/param.h>
12#include <stdio.h>
13#ifdef HAVE_STDINT_H
14# include <stdint.h>
15#endif
16#include <stdlib.h>
17#include <string.h>
18
19#include "../test_helper/test_helper.h"
20
21#include "ssherr.h"
22#include "sshbuf.h"
23
24#define NUM_FUZZ_TESTS (1 << 18)
25
26void sshbuf_fuzz_tests(void);
27
28void
29sshbuf_fuzz_tests(void)
30{
31 struct sshbuf *p1;
32 u_char *dp;
33 size_t sz, sz2, i;
34 u_int32_t r;
35 int ret;
36
37 /* NB. uses sshbuf internals */
38 TEST_START("fuzz alloc/dealloc");
39 p1 = sshbuf_new();
40 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 16 * 1024), 0);
41 ASSERT_PTR_NE(p1, NULL);
42 ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
43 ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
44 for (i = 0; i < NUM_FUZZ_TESTS; i++) {
45 r = arc4random_uniform(10);
46 if (r == 0) {
47 /* 10% chance: small reserve */
48 r = arc4random_uniform(10);
49 fuzz_reserve:
50 sz = sshbuf_avail(p1);
51 sz2 = sshbuf_len(p1);
52 ret = sshbuf_reserve(p1, r, &dp);
53 if (ret < 0) {
54 ASSERT_PTR_EQ(dp, NULL);
55 ASSERT_SIZE_T_LT(sz, r);
56 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
57 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
58 } else {
59 ASSERT_PTR_NE(dp, NULL);
60 ASSERT_SIZE_T_GE(sz, r);
61 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - r);
62 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 + r);
63 memset(dp, arc4random_uniform(255) + 1, r);
64 }
65 } else if (r < 3) {
66 /* 20% chance: big reserve */
67 r = arc4random_uniform(8 * 1024);
68 goto fuzz_reserve;
69 } else if (r == 3) {
70 /* 10% chance: small consume */
71 r = arc4random_uniform(10);
72 fuzz_consume:
73 sz = sshbuf_avail(p1);
74 sz2 = sshbuf_len(p1);
75 /* 50% change consume from end, otherwise start */
76 ret = ((arc4random() & 1) ?
77 sshbuf_consume : sshbuf_consume_end)(p1, r);
78 if (ret < 0) {
79 ASSERT_SIZE_T_LT(sz2, r);
80 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz);
81 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2);
82 } else {
83 ASSERT_SIZE_T_GE(sz2, r);
84 ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz + r);
85 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 - r);
86 }
87 } else if (r < 8) {
88 /* 40% chance: big consume */
89 r = arc4random_uniform(2 * 1024);
90 goto fuzz_consume;
91 } else if (r == 8) {
92 /* 10% chance: reset max size */
93 r = arc4random_uniform(16 * 1024);
94 sz = sshbuf_max_size(p1);
95 if (sshbuf_set_max_size(p1, r) < 0)
96 ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
97 else
98 ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), r);
99 } else {
100 if (arc4random_uniform(8192) == 0) {
101 /* tiny chance: new buffer */
102 ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
103 ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
104 sshbuf_free(p1);
105 p1 = sshbuf_new();
106 ASSERT_PTR_NE(p1, NULL);
107 ASSERT_INT_EQ(sshbuf_set_max_size(p1,
108 16 * 1024), 0);
109 } else {
110 /* Almost 10%: giant reserve */
111 /* use arc4random_buf for r > 2^32 on 64 bit */
112 arc4random_buf(&r, sizeof(r));
113 while (r < SSHBUF_SIZE_MAX / 2) {
114 r <<= 1;
115 r |= arc4random() & 1;
116 }
117 goto fuzz_reserve;
118 }
119 }
120 ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
121 ASSERT_SIZE_T_LE(sshbuf_max_size(p1), 16 * 1024);
122 }
123 ASSERT_PTR_NE(sshbuf_ptr(p1), NULL);
124 ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1));
125 sshbuf_free(p1);
126 TEST_DONE();
127}
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 000000000..966e8432b
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_getput_basic.c
@@ -0,0 +1,484 @@
1/* $OpenBSD: test_sshbuf_getput_basic.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
2/*
3 * Regress test for sshbuf.h buffer API
4 *
5 * Placed in the public domain
6 */
7
8#include "includes.h"
9
10#include <sys/types.h>
11#include <sys/param.h>
12#include <stdio.h>
13#ifdef HAVE_STDINT_H
14# include <stdint.h>
15#endif
16#include <stdlib.h>
17#include <string.h>
18
19#include "../test_helper/test_helper.h"
20#include "ssherr.h"
21#include "sshbuf.h"
22
23void sshbuf_getput_basic_tests(void);
24
25void
26sshbuf_getput_basic_tests(void)
27{
28 struct sshbuf *p1, *p2;
29 const u_char *cd;
30 u_char *d, d2[32], x[] = {
31 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x00, 0x99
32 };
33 u_int64_t v64;
34 u_int32_t v32;
35 u_int16_t v16;
36 u_char v8;
37 size_t s;
38 char *s2;
39 int r;
40 u_char bn1[] = { 0x00, 0x00, 0x00 };
41 u_char bn2[] = { 0x00, 0x00, 0x01, 0x02 };
42 u_char bn3[] = { 0x00, 0x80, 0x09 };
43 u_char bn_exp1[] = { 0x00, 0x00, 0x00, 0x00 };
44 u_char bn_exp2[] = { 0x00, 0x00, 0x00, 0x02, 0x01, 0x02 };
45 u_char bn_exp3[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x80, 0x09 };
46
47 TEST_START("PEEK_U64");
48 ASSERT_U64_EQ(PEEK_U64(x), 0x1122334455667788ULL);
49 TEST_DONE();
50
51 TEST_START("PEEK_U32");
52 ASSERT_U32_EQ(PEEK_U32(x), 0x11223344);
53 TEST_DONE();
54
55 TEST_START("PEEK_U16");
56 ASSERT_U16_EQ(PEEK_U16(x), 0x1122);
57 TEST_DONE();
58
59 TEST_START("POKE_U64");
60 bzero(d2, sizeof(d2));
61 POKE_U64(d2, 0x1122334455667788ULL);
62 ASSERT_MEM_EQ(d2, x, 8);
63 TEST_DONE();
64
65 TEST_START("POKE_U32");
66 bzero(d2, sizeof(d2));
67 POKE_U32(d2, 0x11223344);
68 ASSERT_MEM_EQ(d2, x, 4);
69 TEST_DONE();
70
71 TEST_START("POKE_U16");
72 bzero(d2, sizeof(d2));
73 POKE_U16(d2, 0x1122);
74 ASSERT_MEM_EQ(d2, x, 2);
75 TEST_DONE();
76
77 TEST_START("sshbuf_put");
78 p1 = sshbuf_new();
79 ASSERT_PTR_NE(p1, NULL);
80 ASSERT_INT_EQ(sshbuf_put(p1, x, 5), 0);
81 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 5);
82 cd = sshbuf_ptr(p1);
83 ASSERT_PTR_NE(cd, NULL);
84 ASSERT_U8_EQ(cd[0], 0x11);
85 ASSERT_U8_EQ(cd[1], 0x22);
86 ASSERT_U8_EQ(cd[2], 0x33);
87 ASSERT_U8_EQ(cd[3], 0x44);
88 ASSERT_U8_EQ(cd[4], 0x55);
89 TEST_DONE();
90
91 TEST_START("sshbuf_get");
92 ASSERT_INT_EQ(sshbuf_get(p1, d2, 4), 0);
93 ASSERT_MEM_EQ(d2, x, 4);
94 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
95 ASSERT_U8_EQ(*(sshbuf_ptr(p1)), 0x55);
96 TEST_DONE();
97
98 TEST_START("sshbuf_get truncated");
99 r = sshbuf_get(p1, d2, 4);
100 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
101 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
102 ASSERT_U8_EQ(*(sshbuf_ptr(p1)), 0x55);
103 TEST_DONE();
104
105 TEST_START("sshbuf_put truncated");
106 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 4), 0);
107 r = sshbuf_put(p1, x, 5);
108 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
109 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
110 sshbuf_free(p1);
111 TEST_DONE();
112
113 TEST_START("sshbuf_get_u64");
114 p1 = sshbuf_new();
115 ASSERT_PTR_NE(p1, NULL);
116 ASSERT_INT_EQ(sshbuf_put(p1, x, 10), 0);
117 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 10);
118 ASSERT_INT_EQ(sshbuf_get_u64(p1, &v64), 0);
119 ASSERT_U64_EQ(v64, 0x1122334455667788ULL);
120 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
121 TEST_DONE();
122
123 TEST_START("sshbuf_get_u64 truncated");
124 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
125 r = sshbuf_get_u64(p1, &v64);
126 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
127 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
128 sshbuf_free(p1);
129 TEST_DONE();
130
131 TEST_START("sshbuf_get_u32");
132 p1 = sshbuf_new();
133 ASSERT_PTR_NE(p1, NULL);
134 ASSERT_INT_EQ(sshbuf_put(p1, x, 10), 0);
135 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 10);
136 ASSERT_INT_EQ(sshbuf_get_u32(p1, &v32), 0);
137 ASSERT_U32_EQ(v32, 0x11223344);
138 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 6);
139 ASSERT_INT_EQ(sshbuf_get_u32(p1, &v32), 0);
140 ASSERT_U32_EQ(v32, 0x55667788);
141 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
142 TEST_DONE();
143
144 TEST_START("sshbuf_get_u32 truncated");
145 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
146 r = sshbuf_get_u32(p1, &v32);
147 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
148 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
149 sshbuf_free(p1);
150 TEST_DONE();
151
152 TEST_START("sshbuf_get_u16");
153 p1 = sshbuf_new();
154 ASSERT_PTR_NE(p1, NULL);
155 ASSERT_INT_EQ(sshbuf_put(p1, x, 9), 0);
156 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 9);
157 ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
158 ASSERT_U16_EQ(v16, 0x1122);
159 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 7);
160 ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
161 ASSERT_U16_EQ(v16, 0x3344);
162 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 5);
163 ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
164 ASSERT_U16_EQ(v16, 0x5566);
165 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 3);
166 ASSERT_INT_EQ(sshbuf_get_u16(p1, &v16), 0);
167 ASSERT_U16_EQ(v16, 0x7788);
168 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
169 TEST_DONE();
170
171 TEST_START("sshbuf_get_u16 truncated");
172 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
173 r = sshbuf_get_u16(p1, &v16);
174 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
175 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
176 sshbuf_free(p1);
177 TEST_DONE();
178
179 TEST_START("sshbuf_get_u8");
180 p1 = sshbuf_new();
181 ASSERT_PTR_NE(p1, NULL);
182 ASSERT_INT_EQ(sshbuf_put(p1, x, 2), 0);
183 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
184 ASSERT_INT_EQ(sshbuf_get_u8(p1, &v8), 0);
185 ASSERT_U8_EQ(v8, 0x11);
186 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
187 ASSERT_INT_EQ(sshbuf_get_u8(p1, &v8), 0);
188 ASSERT_U8_EQ(v8, 0x22);
189 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
190 TEST_DONE();
191
192 TEST_START("sshbuf_get_u8 truncated");
193 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
194 r = sshbuf_get_u8(p1, &v8);
195 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
196 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
197 sshbuf_free(p1);
198 TEST_DONE();
199
200 TEST_START("sshbuf_put_u64");
201 p1 = sshbuf_new();
202 ASSERT_PTR_NE(p1, NULL);
203 ASSERT_INT_EQ(sshbuf_put_u64(p1, 0x1122334455667788ULL), 0);
204 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 8);
205 ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 8);
206 sshbuf_free(p1);
207 TEST_DONE();
208
209 TEST_START("sshbuf_put_u64 exact");
210 p1 = sshbuf_new();
211 ASSERT_PTR_NE(p1, NULL);
212 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 8), 0);
213 ASSERT_INT_EQ(sshbuf_put_u64(p1, 0x1122334455667788ULL), 0);
214 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 8);
215 ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 8);
216 sshbuf_free(p1);
217 TEST_DONE();
218
219 TEST_START("sshbuf_put_u64 limited");
220 p1 = sshbuf_new();
221 ASSERT_PTR_NE(p1, NULL);
222 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 7), 0);
223 r = sshbuf_put_u64(p1, 0x1122334455667788ULL);
224 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
225 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
226 sshbuf_free(p1);
227 TEST_DONE();
228
229 TEST_START("sshbuf_put_u32");
230 p1 = sshbuf_new();
231 ASSERT_PTR_NE(p1, NULL);
232 ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x11223344), 0);
233 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
234 ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 4);
235 sshbuf_free(p1);
236 TEST_DONE();
237
238 TEST_START("sshbuf_put_u32 exact");
239 p1 = sshbuf_new();
240 ASSERT_PTR_NE(p1, NULL);
241 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 4), 0);
242 ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x11223344), 0);
243 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
244 ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 4);
245 sshbuf_free(p1);
246 TEST_DONE();
247
248 TEST_START("sshbuf_put_u32 limited");
249 p1 = sshbuf_new();
250 ASSERT_PTR_NE(p1, NULL);
251 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 3), 0);
252 r = sshbuf_put_u32(p1, 0x11223344);
253 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
254 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
255 sshbuf_free(p1);
256 TEST_DONE();
257
258 TEST_START("sshbuf_put_u16");
259 p1 = sshbuf_new();
260 ASSERT_PTR_NE(p1, NULL);
261 ASSERT_INT_EQ(sshbuf_put_u16(p1, 0x1122), 0);
262 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
263 ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 2);
264 sshbuf_free(p1);
265 TEST_DONE();
266
267 TEST_START("sshbuf_put_u16");
268 p1 = sshbuf_new();
269 ASSERT_PTR_NE(p1, NULL);
270 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 2), 0);
271 ASSERT_INT_EQ(sshbuf_put_u16(p1, 0x1122), 0);
272 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
273 ASSERT_MEM_EQ(sshbuf_ptr(p1), x, 2);
274 sshbuf_free(p1);
275 TEST_DONE();
276
277 TEST_START("sshbuf_put_u16 limited");
278 p1 = sshbuf_new();
279 ASSERT_PTR_NE(p1, NULL);
280 ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1), 0);
281 r = sshbuf_put_u16(p1, 0x1122);
282 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
283 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
284 sshbuf_free(p1);
285 TEST_DONE();
286
287 TEST_START("sshbuf_get_string");
288 p1 = sshbuf_new();
289 ASSERT_PTR_NE(p1, NULL);
290 ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
291 ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
292 ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
293 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4 + 4);
294 ASSERT_INT_EQ(sshbuf_get_string(p1, &d, &s), 0);
295 ASSERT_SIZE_T_EQ(s, sizeof(x));
296 ASSERT_MEM_EQ(d, x, sizeof(x));
297 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
298 free(d);
299 sshbuf_free(p1);
300 TEST_DONE();
301
302 TEST_START("sshbuf_get_string exact");
303 p1 = sshbuf_new();
304 ASSERT_PTR_NE(p1, NULL);
305 ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(x) + 4), 0);
306 ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
307 ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
308 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
309 ASSERT_INT_EQ(sshbuf_get_string(p1, &d, &s), 0);
310 ASSERT_SIZE_T_EQ(s, sizeof(x));
311 ASSERT_MEM_EQ(d, x, sizeof(x));
312 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
313 free(d);
314 sshbuf_free(p1);
315 TEST_DONE();
316
317 TEST_START("sshbuf_get_string truncated");
318 p1 = sshbuf_new();
319 ASSERT_PTR_NE(p1, NULL);
320 ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
321 ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
322 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
323 ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), 0);
324 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 3);
325 r = sshbuf_get_string(p1, &d, &s);
326 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
327 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 3);
328 sshbuf_free(p1);
329 TEST_DONE();
330
331 TEST_START("sshbuf_get_string giant");
332 p1 = sshbuf_new();
333 ASSERT_PTR_NE(p1, NULL);
334 ASSERT_INT_EQ(sshbuf_put_u32(p1, 0xffffffff), 0);
335 ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
336 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
337 r = sshbuf_get_string(p1, &d, &s);
338 ASSERT_INT_EQ(r, SSH_ERR_STRING_TOO_LARGE);
339 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
340 sshbuf_free(p1);
341 TEST_DONE();
342
343 TEST_START("sshbuf_get_cstring giant");
344 p1 = sshbuf_new();
345 ASSERT_PTR_NE(p1, NULL);
346 ASSERT_INT_EQ(sshbuf_put_u32(p1, 0xffffffff), 0);
347 ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
348 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
349 r = sshbuf_get_cstring(p1, &s2, &s);
350 ASSERT_INT_EQ(r, SSH_ERR_STRING_TOO_LARGE);
351 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
352 sshbuf_free(p1);
353 TEST_DONE();
354
355 TEST_START("sshbuf_get_cstring embedded \\0");
356 p1 = sshbuf_new();
357 ASSERT_PTR_NE(p1, NULL);
358 ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x)), 0);
359 ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x)), 0);
360 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
361 r = sshbuf_get_cstring(p1, &s2, NULL);
362 ASSERT_INT_EQ(r, SSH_ERR_INVALID_FORMAT);
363 sshbuf_free(p1);
364 TEST_DONE();
365
366 TEST_START("sshbuf_get_cstring trailing \\0");
367 p1 = sshbuf_new();
368 ASSERT_PTR_NE(p1, NULL);
369 ASSERT_INT_EQ(sshbuf_put_u32(p1, sizeof(x) - 1), 0);
370 ASSERT_INT_EQ(sshbuf_put(p1, x, sizeof(x) - 1), 0);
371 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4 - 1);
372 ASSERT_INT_EQ(sshbuf_get_cstring(p1, &s2, &s), 0);
373 ASSERT_SIZE_T_EQ(s, sizeof(x) - 1);
374 ASSERT_MEM_EQ(s2, x, s);
375 free(s2);
376 sshbuf_free(p1);
377 TEST_DONE();
378
379 TEST_START("sshbuf_put_string");
380 p1 = sshbuf_new();
381 ASSERT_PTR_NE(p1, NULL);
382 ASSERT_INT_EQ(sshbuf_put_string(p1, x, sizeof(x)), 0);
383 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(x) + 4);
384 ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), sizeof(x));
385 ASSERT_MEM_EQ(sshbuf_ptr(p1) + 4, x, sizeof(x));
386 sshbuf_free(p1);
387 TEST_DONE();
388
389 TEST_START("sshbuf_put_string limited");
390 p1 = sshbuf_new();
391 ASSERT_PTR_NE(p1, NULL);
392 ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(x) + 4 - 1), 0);
393 r = sshbuf_put_string(p1, x, sizeof(x));
394 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
395 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
396 sshbuf_free(p1);
397 TEST_DONE();
398
399 TEST_START("sshbuf_put_string giant");
400 p1 = sshbuf_new();
401 ASSERT_PTR_NE(p1, NULL);
402 r = sshbuf_put_string(p1, (void *)0x01, 0xfffffffc);
403 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
404 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
405 sshbuf_free(p1);
406 TEST_DONE();
407
408 TEST_START("sshbuf_putf");
409 p1 = sshbuf_new();
410 ASSERT_PTR_NE(p1, NULL);
411 r = sshbuf_putf(p1, "%s %d %x", "hello", 23, 0x5f);
412 ASSERT_INT_EQ(r, 0);
413 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 11);
414 ASSERT_MEM_EQ(sshbuf_ptr(p1), "hello 23 5f", 11);
415 sshbuf_free(p1);
416 TEST_DONE();
417
418 TEST_START("sshbuf_putb");
419 p1 = sshbuf_new();
420 ASSERT_PTR_NE(p1, NULL);
421 p2 = sshbuf_new();
422 ASSERT_PTR_NE(p2, NULL);
423 ASSERT_INT_EQ(sshbuf_put(p1, "blahblahblah", 12), 0);
424 ASSERT_INT_EQ(sshbuf_putb(p2, p1), 0);
425 sshbuf_free(p1);
426 ASSERT_SIZE_T_EQ(sshbuf_len(p2), 12);
427 ASSERT_MEM_EQ(sshbuf_ptr(p2), "blahblahblah", 12);
428 sshbuf_free(p2);
429 TEST_DONE();
430
431 TEST_START("sshbuf_put_bignum2_bytes empty buf");
432 p1 = sshbuf_new();
433 ASSERT_PTR_NE(p1, NULL);
434 ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, NULL, 0), 0);
435 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp1));
436 ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp1, sizeof(bn_exp1));
437 sshbuf_free(p1);
438 TEST_DONE();
439
440 TEST_START("sshbuf_put_bignum2_bytes all zeroes");
441 p1 = sshbuf_new();
442 ASSERT_PTR_NE(p1, NULL);
443 ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, bn1, sizeof(bn1)), 0);
444 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp1));
445 ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp1, sizeof(bn_exp1));
446 sshbuf_free(p1);
447 TEST_DONE();
448
449 TEST_START("sshbuf_put_bignum2_bytes simple");
450 p1 = sshbuf_new();
451 ASSERT_PTR_NE(p1, NULL);
452 ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, bn2+2, sizeof(bn2)-2), 0);
453 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp2));
454 ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp2, sizeof(bn_exp2));
455 sshbuf_free(p1);
456 TEST_DONE();
457
458 TEST_START("sshbuf_put_bignum2_bytes leading zero");
459 p1 = sshbuf_new();
460 ASSERT_PTR_NE(p1, NULL);
461 ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, bn2, sizeof(bn2)), 0);
462 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp2));
463 ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp2, sizeof(bn_exp2));
464 sshbuf_free(p1);
465 TEST_DONE();
466
467 TEST_START("sshbuf_put_bignum2_bytes neg");
468 p1 = sshbuf_new();
469 ASSERT_PTR_NE(p1, NULL);
470 ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, bn3+1, sizeof(bn3)-1), 0);
471 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp3));
472 ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp3, sizeof(bn_exp3));
473 sshbuf_free(p1);
474 TEST_DONE();
475
476 TEST_START("sshbuf_put_bignum2_bytes neg and leading zero");
477 p1 = sshbuf_new();
478 ASSERT_PTR_NE(p1, NULL);
479 ASSERT_INT_EQ(sshbuf_put_bignum2_bytes(p1, bn3, sizeof(bn3)), 0);
480 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(bn_exp3));
481 ASSERT_MEM_EQ(sshbuf_ptr(p1), bn_exp3, sizeof(bn_exp3));
482 sshbuf_free(p1);
483 TEST_DONE();
484}
diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c
new file mode 100644
index 000000000..0c4c71ecd
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c
@@ -0,0 +1,409 @@
1/* $OpenBSD: test_sshbuf_getput_crypto.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
2/*
3 * Regress test for sshbuf.h buffer API
4 *
5 * Placed in the public domain
6 */
7
8#include "includes.h"
9
10#include <sys/types.h>
11#include <sys/param.h>
12#include <stdio.h>
13#ifdef HAVE_STDINT_H
14# include <stdint.h>
15#endif
16#include <stdlib.h>
17#include <string.h>
18
19#include <openssl/bn.h>
20#include <openssl/objects.h>
21#ifdef OPENSSL_HAS_NISTP256
22# include <openssl/ec.h>
23#endif
24
25#include "../test_helper/test_helper.h"
26#include "ssherr.h"
27#include "sshbuf.h"
28
29void sshbuf_getput_crypto_tests(void);
30
31void
32sshbuf_getput_crypto_tests(void)
33{
34 struct sshbuf *p1;
35 const u_char *d;
36 size_t s;
37 BIGNUM *bn, *bn2;
38 /* This one has num_bits != num_bytes * 8 to test bignum1 encoding */
39 const char *hexbn1 = "0102030405060708090a0b0c0d0e0f10";
40 /* This one has MSB set to test bignum2 encoding negative-avoidance */
41 const char *hexbn2 = "f0e0d0c0b0a0908070605040302010007fff11";
42 u_char expbn1[] = {
43 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
44 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
45 };
46 u_char expbn2[] = {
47 0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80,
48 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00,
49 0x7f, 0xff, 0x11
50 };
51#ifdef OPENSSL_HAS_NISTP256
52 BIGNUM *bn_x, *bn_y;
53 int ec256_nid = NID_X9_62_prime256v1;
54 char *ec256_x = "0C828004839D0106AA59575216191357"
55 "34B451459DADB586677EF9DF55784999";
56 char *ec256_y = "4D196B50F0B4E94B3C73E3A9D4CD9DF2"
57 "C8F9A35E42BDD047550F69D80EC23CD4";
58 u_char expec256[] = {
59 0x04,
60 0x0c, 0x82, 0x80, 0x04, 0x83, 0x9d, 0x01, 0x06,
61 0xaa, 0x59, 0x57, 0x52, 0x16, 0x19, 0x13, 0x57,
62 0x34, 0xb4, 0x51, 0x45, 0x9d, 0xad, 0xb5, 0x86,
63 0x67, 0x7e, 0xf9, 0xdf, 0x55, 0x78, 0x49, 0x99,
64 0x4d, 0x19, 0x6b, 0x50, 0xf0, 0xb4, 0xe9, 0x4b,
65 0x3c, 0x73, 0xe3, 0xa9, 0xd4, 0xcd, 0x9d, 0xf2,
66 0xc8, 0xf9, 0xa3, 0x5e, 0x42, 0xbd, 0xd0, 0x47,
67 0x55, 0x0f, 0x69, 0xd8, 0x0e, 0xc2, 0x3c, 0xd4
68 };
69 EC_KEY *eck;
70 EC_POINT *ecp;
71#endif
72 int r;
73
74#define MKBN(b, bnn) \
75 do { \
76 bnn = NULL; \
77 ASSERT_INT_GT(BN_hex2bn(&bnn, b), 0); \
78 } while (0)
79
80 TEST_START("sshbuf_put_bignum1");
81 MKBN(hexbn1, bn);
82 p1 = sshbuf_new();
83 ASSERT_PTR_NE(p1, NULL);
84 ASSERT_INT_EQ(sshbuf_put_bignum1(p1, bn), 0);
85 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 2);
86 ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), (u_int16_t)BN_num_bits(bn));
87 ASSERT_MEM_EQ(sshbuf_ptr(p1) + 2, expbn1, sizeof(expbn1));
88 BN_free(bn);
89 sshbuf_free(p1);
90 TEST_DONE();
91
92 TEST_START("sshbuf_put_bignum1 limited");
93 MKBN(hexbn1, bn);
94 p1 = sshbuf_new();
95 ASSERT_PTR_NE(p1, NULL);
96 ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 1), 0);
97 r = sshbuf_put_bignum1(p1, bn);
98 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
99 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
100 BN_free(bn);
101 sshbuf_free(p1);
102 TEST_DONE();
103
104 TEST_START("sshbuf_put_bignum1 bn2");
105 MKBN(hexbn2, bn);
106 p1 = sshbuf_new();
107 ASSERT_PTR_NE(p1, NULL);
108 ASSERT_INT_EQ(sshbuf_put_bignum1(p1, bn), 0);
109 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 2);
110 ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), (u_int16_t)BN_num_bits(bn));
111 ASSERT_MEM_EQ(sshbuf_ptr(p1) + 2, expbn2, sizeof(expbn2));
112 BN_free(bn);
113 sshbuf_free(p1);
114 TEST_DONE();
115
116 TEST_START("sshbuf_put_bignum1 bn2 limited");
117 MKBN(hexbn2, bn);
118 p1 = sshbuf_new();
119 ASSERT_PTR_NE(p1, NULL);
120 ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 1), 0);
121 r = sshbuf_put_bignum1(p1, bn);
122 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
123 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
124 BN_free(bn);
125 sshbuf_free(p1);
126 TEST_DONE();
127
128 TEST_START("sshbuf_put_bignum2");
129 MKBN(hexbn1, bn);
130 p1 = sshbuf_new();
131 ASSERT_PTR_NE(p1, NULL);
132 ASSERT_INT_EQ(sshbuf_put_bignum2(p1, bn), 0);
133 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 4);
134 ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), (u_int32_t)BN_num_bytes(bn));
135 ASSERT_MEM_EQ(sshbuf_ptr(p1) + 4, expbn1, sizeof(expbn1));
136 BN_free(bn);
137 sshbuf_free(p1);
138 TEST_DONE();
139
140 TEST_START("sshbuf_put_bignum2 limited");
141 MKBN(hexbn1, bn);
142 p1 = sshbuf_new();
143 ASSERT_PTR_NE(p1, NULL);
144 ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 3), 0);
145 r = sshbuf_put_bignum2(p1, bn);
146 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
147 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
148 BN_free(bn);
149 sshbuf_free(p1);
150 TEST_DONE();
151
152 TEST_START("sshbuf_put_bignum2 bn2");
153 MKBN(hexbn2, bn);
154 p1 = sshbuf_new();
155 ASSERT_PTR_NE(p1, NULL);
156 ASSERT_INT_EQ(sshbuf_put_bignum2(p1, bn), 0);
157 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 4 + 1); /* MSB */
158 ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), (u_int32_t)BN_num_bytes(bn) + 1);
159 ASSERT_U8_EQ(*(sshbuf_ptr(p1) + 4), 0x00);
160 ASSERT_MEM_EQ(sshbuf_ptr(p1) + 5, expbn2, sizeof(expbn2));
161 BN_free(bn);
162 sshbuf_free(p1);
163 TEST_DONE();
164
165 TEST_START("sshbuf_put_bignum2 bn2 limited");
166 MKBN(hexbn2, bn);
167 p1 = sshbuf_new();
168 ASSERT_PTR_NE(p1, NULL);
169 ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn2) + 3), 0);
170 r = sshbuf_put_bignum2(p1, bn);
171 ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
172 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
173 BN_free(bn);
174 sshbuf_free(p1);
175 TEST_DONE();
176
177 TEST_START("sshbuf_get_bignum1");
178 MKBN(hexbn1, bn);
179 p1 = sshbuf_new();
180 ASSERT_PTR_NE(p1, NULL);
181 ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
182 ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1)), 0);
183 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1));
184 ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
185 bn2 = BN_new();
186 ASSERT_INT_EQ(sshbuf_get_bignum1(p1, bn2), 0);
187 ASSERT_BIGNUM_EQ(bn, bn2);
188 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
189 BN_free(bn);
190 BN_free(bn2);
191 sshbuf_free(p1);
192 TEST_DONE();
193
194 TEST_START("sshbuf_get_bignum1 truncated");
195 MKBN(hexbn1, bn);
196 p1 = sshbuf_new();
197 ASSERT_PTR_NE(p1, NULL);
198 ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
199 ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1) - 1), 0);
200 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1) - 1);
201 bn2 = BN_new();
202 r = sshbuf_get_bignum1(p1, bn2);
203 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
204 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1) - 1);
205 BN_free(bn);
206 BN_free(bn2);
207 sshbuf_free(p1);
208 TEST_DONE();
209
210 TEST_START("sshbuf_get_bignum1 giant");
211 MKBN(hexbn1, bn);
212 p1 = sshbuf_new();
213 ASSERT_PTR_NE(p1, NULL);
214 ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xffff), 0);
215 ASSERT_INT_EQ(sshbuf_reserve(p1, (0xffff + 7) / 8, NULL), 0);
216 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + ((0xffff + 7) / 8));
217 bn2 = BN_new();
218 r = sshbuf_get_bignum1(p1, bn2);
219 ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_TOO_LARGE);
220 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + ((0xffff + 7) / 8));
221 BN_free(bn);
222 BN_free(bn2);
223 sshbuf_free(p1);
224 TEST_DONE();
225
226 TEST_START("sshbuf_get_bignum1 bn2");
227 MKBN(hexbn2, bn);
228 p1 = sshbuf_new();
229 ASSERT_PTR_NE(p1, NULL);
230 ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
231 ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0);
232 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2));
233 ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
234 bn2 = BN_new();
235 ASSERT_INT_EQ(sshbuf_get_bignum1(p1, bn2), 0);
236 ASSERT_BIGNUM_EQ(bn, bn2);
237 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
238 BN_free(bn);
239 BN_free(bn2);
240 sshbuf_free(p1);
241 TEST_DONE();
242
243 TEST_START("sshbuf_get_bignum1 bn2 truncated");
244 MKBN(hexbn2, bn);
245 p1 = sshbuf_new();
246 ASSERT_PTR_NE(p1, NULL);
247 ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0);
248 ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2) - 1), 0);
249 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2) - 1);
250 bn2 = BN_new();
251 r = sshbuf_get_bignum1(p1, bn2);
252 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
253 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2) - 1);
254 BN_free(bn);
255 BN_free(bn2);
256 sshbuf_free(p1);
257 TEST_DONE();
258
259 TEST_START("sshbuf_get_bignum2");
260 MKBN(hexbn1, bn);
261 p1 = sshbuf_new();
262 ASSERT_PTR_NE(p1, NULL);
263 ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0);
264 ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1)), 0);
265 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4 + sizeof(expbn1));
266 ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
267 bn2 = BN_new();
268 ASSERT_INT_EQ(sshbuf_get_bignum2(p1, bn2), 0);
269 ASSERT_BIGNUM_EQ(bn, bn2);
270 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
271 BN_free(bn);
272 BN_free(bn2);
273 sshbuf_free(p1);
274 TEST_DONE();
275
276 TEST_START("sshbuf_get_bignum2 truncated");
277 MKBN(hexbn1, bn);
278 p1 = sshbuf_new();
279 ASSERT_PTR_NE(p1, NULL);
280 ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0);
281 ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1) - 1), 0);
282 bn2 = BN_new();
283 r = sshbuf_get_bignum2(p1, bn2);
284 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
285 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 3);
286 BN_free(bn);
287 BN_free(bn2);
288 sshbuf_free(p1);
289 TEST_DONE();
290
291 TEST_START("sshbuf_get_bignum2 giant");
292 MKBN(hexbn1, bn);
293 p1 = sshbuf_new();
294 ASSERT_PTR_NE(p1, NULL);
295 ASSERT_INT_EQ(sshbuf_put_u32(p1, 65536), 0);
296 ASSERT_INT_EQ(sshbuf_reserve(p1, 65536, NULL), 0);
297 bn2 = BN_new();
298 r = sshbuf_get_bignum2(p1, bn2);
299 ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_TOO_LARGE);
300 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 65536 + 4);
301 BN_free(bn);
302 BN_free(bn2);
303 sshbuf_free(p1);
304 TEST_DONE();
305
306 TEST_START("sshbuf_get_bignum2 bn2");
307 MKBN(hexbn2, bn);
308 p1 = sshbuf_new();
309 ASSERT_PTR_NE(p1, NULL);
310 ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn) + 1), 0); /* MSB */
311 ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0);
312 ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0);
313 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4 + 1 + sizeof(expbn2));
314 ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0);
315 bn2 = BN_new();
316 ASSERT_INT_EQ(sshbuf_get_bignum2(p1, bn2), 0);
317 ASSERT_BIGNUM_EQ(bn, bn2);
318 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
319 BN_free(bn);
320 BN_free(bn2);
321 sshbuf_free(p1);
322 TEST_DONE();
323
324 TEST_START("sshbuf_get_bignum2 bn2 truncated");
325 MKBN(hexbn2, bn);
326 p1 = sshbuf_new();
327 ASSERT_PTR_NE(p1, NULL);
328 ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn) + 1), 0);
329 ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0);
330 ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2) - 1), 0);
331 bn2 = BN_new();
332 r = sshbuf_get_bignum2(p1, bn2);
333 ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
334 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 1 + 4 - 1);
335 BN_free(bn);
336 BN_free(bn2);
337 sshbuf_free(p1);
338 TEST_DONE();
339
340 TEST_START("sshbuf_get_bignum2 bn2 negative");
341 MKBN(hexbn2, bn);
342 p1 = sshbuf_new();
343 ASSERT_PTR_NE(p1, NULL);
344 ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0);
345 ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0);
346 bn2 = BN_new();
347 r = sshbuf_get_bignum2(p1, bn2);
348 ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_IS_NEGATIVE);
349 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 4);
350 BN_free(bn);
351 BN_free(bn2);
352 sshbuf_free(p1);
353 TEST_DONE();
354
355#ifdef OPENSSL_HAS_NISTP256
356 TEST_START("sshbuf_put_ec");
357 eck = EC_KEY_new_by_curve_name(ec256_nid);
358 ASSERT_PTR_NE(eck, NULL);
359 ecp = EC_POINT_new(EC_KEY_get0_group(eck));
360 ASSERT_PTR_NE(ecp, NULL);
361 MKBN(ec256_x, bn_x);
362 MKBN(ec256_y, bn_y);
363 ASSERT_INT_EQ(EC_POINT_set_affine_coordinates_GFp(
364 EC_KEY_get0_group(eck), ecp, bn_x, bn_y, NULL), 1);
365 ASSERT_INT_EQ(EC_KEY_set_public_key(eck, ecp), 1);
366 BN_free(bn_x);
367 BN_free(bn_y);
368 EC_POINT_free(ecp);
369 p1 = sshbuf_new();
370 ASSERT_PTR_NE(p1, NULL);
371 ASSERT_INT_EQ(sshbuf_put_eckey(p1, eck), 0);
372 ASSERT_INT_EQ(sshbuf_get_string_direct(p1, &d, &s), 0);
373 ASSERT_SIZE_T_EQ(s, sizeof(expec256));
374 ASSERT_MEM_EQ(d, expec256, sizeof(expec256));
375 sshbuf_free(p1);
376 EC_KEY_free(eck);
377 TEST_DONE();
378
379 TEST_START("sshbuf_get_ec");
380 eck = EC_KEY_new_by_curve_name(ec256_nid);
381 ASSERT_PTR_NE(eck, NULL);
382 p1 = sshbuf_new();
383 ASSERT_PTR_NE(p1, NULL);
384 ASSERT_INT_EQ(sshbuf_put_string(p1, expec256, sizeof(expec256)), 0);
385 ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expec256) + 4);
386 ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0);
387 ASSERT_INT_EQ(sshbuf_get_eckey(p1, eck), 0);
388 bn_x = BN_new();
389 bn_y = BN_new();
390 ASSERT_PTR_NE(bn_x, NULL);
391 ASSERT_PTR_NE(bn_y, NULL);
392 ASSERT_INT_EQ(EC_POINT_get_affine_coordinates_GFp(
393 EC_KEY_get0_group(eck), EC_KEY_get0_public_key(eck),
394 bn_x, bn_y, NULL), 1);
395 MKBN(ec256_x, bn);
396 MKBN(ec256_y, bn2);
397 ASSERT_INT_EQ(BN_cmp(bn_x, bn), 0);
398 ASSERT_INT_EQ(BN_cmp(bn_y, bn2), 0);
399 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
400 sshbuf_free(p1);
401 EC_KEY_free(eck);
402 BN_free(bn_x);
403 BN_free(bn_y);
404 BN_free(bn);
405 BN_free(bn2);
406 TEST_DONE();
407#endif
408}
409
diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c b/regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c
new file mode 100644
index 000000000..8c3269b13
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c
@@ -0,0 +1,130 @@
1/* $OpenBSD: test_sshbuf_getput_fuzz.c,v 1.2 2014/05/02 02:54:00 djm Exp $ */
2/*
3 * Regress test for sshbuf.h buffer API
4 *
5 * Placed in the public domain
6 */
7
8#include "includes.h"
9
10#include <sys/types.h>
11#include <sys/param.h>
12#include <stdio.h>
13#ifdef HAVE_STDINT_H
14# include <stdint.h>
15#endif
16#include <stdlib.h>
17#include <string.h>
18
19#include <openssl/bn.h>
20#include <openssl/objects.h>
21#ifdef OPENSSL_HAS_NISTP256
22# include <openssl/ec.h>
23#endif
24
25#include "../test_helper/test_helper.h"
26#include "ssherr.h"
27#include "sshbuf.h"
28
29void sshbuf_getput_fuzz_tests(void);
30
31static void
32attempt_parse_blob(u_char *blob, size_t len)
33{
34 struct sshbuf *p1;
35 BIGNUM *bn;
36#ifdef OPENSSL_HAS_NISTP256
37 EC_KEY *eck;
38#endif
39 u_char *s;
40 size_t l;
41 u_int8_t u8;
42 u_int16_t u16;
43 u_int32_t u32;
44 u_int64_t u64;
45
46 p1 = sshbuf_new();
47 ASSERT_PTR_NE(p1, NULL);
48 ASSERT_INT_EQ(sshbuf_put(p1, blob, len), 0);
49 sshbuf_get_u8(p1, &u8);
50 sshbuf_get_u16(p1, &u16);
51 sshbuf_get_u32(p1, &u32);
52 sshbuf_get_u64(p1, &u64);
53 if (sshbuf_get_string(p1, &s, &l) == 0) {
54 bzero(s, l);
55 free(s);
56 }
57 bn = BN_new();
58 sshbuf_get_bignum1(p1, bn);
59 BN_clear_free(bn);
60 bn = BN_new();
61 sshbuf_get_bignum2(p1, bn);
62 BN_clear_free(bn);
63#ifdef OPENSSL_HAS_NISTP256
64 eck = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
65 ASSERT_PTR_NE(eck, NULL);
66 sshbuf_get_eckey(p1, eck);
67 EC_KEY_free(eck);
68#endif
69 sshbuf_free(p1);
70}
71
72
73static void
74onerror(void *fuzz)
75{
76 fprintf(stderr, "Failed during fuzz:\n");
77 fuzz_dump((struct fuzz *)fuzz);
78}
79
80void
81sshbuf_getput_fuzz_tests(void)
82{
83 u_char blob[] = {
84 /* u8 */
85 0xd0,
86 /* u16 */
87 0xc0, 0xde,
88 /* u32 */
89 0xfa, 0xce, 0xde, 0xad,
90 /* u64 */
91 0xfe, 0xed, 0xac, 0x1d, 0x1f, 0x1c, 0xbe, 0xef,
92 /* string */
93 0x00, 0x00, 0x00, 0x09,
94 'O', ' ', 'G', 'o', 'r', 'g', 'o', 'n', '!',
95 /* bignum1 */
96 0x79,
97 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
98 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
99 /* bignum2 */
100 0x00, 0x00, 0x00, 0x14,
101 0x00,
102 0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80,
103 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00,
104 0x7f, 0xff, 0x11,
105 /* EC point (NIST-256 curve) */
106 0x00, 0x00, 0x00, 0x41,
107 0x04,
108 0x0c, 0x82, 0x80, 0x04, 0x83, 0x9d, 0x01, 0x06,
109 0xaa, 0x59, 0x57, 0x52, 0x16, 0x19, 0x13, 0x57,
110 0x34, 0xb4, 0x51, 0x45, 0x9d, 0xad, 0xb5, 0x86,
111 0x67, 0x7e, 0xf9, 0xdf, 0x55, 0x78, 0x49, 0x99,
112 0x4d, 0x19, 0x6b, 0x50, 0xf0, 0xb4, 0xe9, 0x4b,
113 0x3c, 0x73, 0xe3, 0xa9, 0xd4, 0xcd, 0x9d, 0xf2,
114 0xc8, 0xf9, 0xa3, 0x5e, 0x42, 0xbd, 0xd0, 0x47,
115 0x55, 0x0f, 0x69, 0xd8, 0x0e, 0xc2, 0x3c, 0xd4,
116 };
117 struct fuzz *fuzz;
118
119 TEST_START("fuzz blob parsing");
120 fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | FUZZ_2_BIT_FLIP |
121 FUZZ_1_BYTE_FLIP | FUZZ_2_BYTE_FLIP |
122 FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END, blob, sizeof(blob));
123 TEST_ONERROR(onerror, fuzz);
124 for(; !fuzz_done(fuzz); fuzz_next(fuzz))
125 attempt_parse_blob(blob, sizeof(blob));
126 fuzz_cleanup(fuzz);
127 TEST_DONE();
128 TEST_ONERROR(NULL, NULL);
129}
130
diff --git a/regress/unittests/sshbuf/test_sshbuf_misc.c b/regress/unittests/sshbuf/test_sshbuf_misc.c
new file mode 100644
index 000000000..f155491a0
--- /dev/null
+++ b/regress/unittests/sshbuf/test_sshbuf_misc.c
@@ -0,0 +1,138 @@
1/* $OpenBSD: test_sshbuf_misc.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
2/*
3 * Regress test for sshbuf.h buffer API
4 *
5 * Placed in the public domain
6 */
7
8#include "includes.h"
9
10#include <sys/types.h>
11#include <sys/param.h>
12#include <stdio.h>
13#ifdef HAVE_STDINT_H
14# include <stdint.h>
15#endif
16#include <stdlib.h>
17#include <string.h>
18
19#include "../test_helper/test_helper.h"
20
21#include "sshbuf.h"
22
23void sshbuf_misc_tests(void);
24
25void
26sshbuf_misc_tests(void)
27{
28 struct sshbuf *p1;
29 char tmp[512], *p;
30 FILE *out;
31 size_t sz;
32
33 TEST_START("sshbuf_dump");
34 out = tmpfile();
35 ASSERT_PTR_NE(out, NULL);
36 p1 = sshbuf_new();
37 ASSERT_PTR_NE(p1, NULL);
38 ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), 0);
39 sshbuf_dump(p1, out);
40 fflush(out);
41 rewind(out);
42 sz = fread(tmp, 1, sizeof(tmp), out);
43 ASSERT_INT_EQ(ferror(out), 0);
44 ASSERT_INT_NE(feof(out), 0);
45 ASSERT_SIZE_T_GT(sz, 0);
46 tmp[sz] = '\0';
47 ASSERT_PTR_NE(strstr(tmp, "12 34 56 78"), NULL);
48 fclose(out);
49 sshbuf_free(p1);
50 TEST_DONE();
51
52 TEST_START("sshbuf_dtob16");
53 p1 = sshbuf_new();
54 ASSERT_PTR_NE(p1, NULL);
55 ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), 0);
56 p = sshbuf_dtob16(p1);
57 ASSERT_PTR_NE(p, NULL);
58 ASSERT_STRING_EQ(p, "12345678");
59 free(p);
60 sshbuf_free(p1);
61 TEST_DONE();
62
63 TEST_START("sshbuf_dtob64 len 1");
64 p1 = sshbuf_new();
65 ASSERT_PTR_NE(p1, NULL);
66 ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0);
67 p = sshbuf_dtob64(p1);
68 ASSERT_PTR_NE(p, NULL);
69 ASSERT_STRING_EQ(p, "EQ==");
70 free(p);
71 sshbuf_free(p1);
72 TEST_DONE();
73
74 TEST_START("sshbuf_dtob64 len 2");
75 p1 = sshbuf_new();
76 ASSERT_PTR_NE(p1, NULL);
77 ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0);
78 ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x22), 0);
79 p = sshbuf_dtob64(p1);
80 ASSERT_PTR_NE(p, NULL);
81 ASSERT_STRING_EQ(p, "ESI=");
82 free(p);
83 sshbuf_free(p1);
84 TEST_DONE();
85
86 TEST_START("sshbuf_dtob64 len 3");
87 p1 = sshbuf_new();
88 ASSERT_PTR_NE(p1, NULL);
89 ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0);
90 ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x22), 0);
91 ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x33), 0);
92 p = sshbuf_dtob64(p1);
93 ASSERT_PTR_NE(p, NULL);
94 ASSERT_STRING_EQ(p, "ESIz");
95 free(p);
96 sshbuf_free(p1);
97 TEST_DONE();
98
99 TEST_START("sshbuf_dtob64 len 8191");
100 p1 = sshbuf_new();
101 ASSERT_PTR_NE(p1, NULL);
102 ASSERT_INT_EQ(sshbuf_reserve(p1, 8192, NULL), 0);
103 bzero(sshbuf_mutable_ptr(p1), 8192);
104 p = sshbuf_dtob64(p1);
105 ASSERT_PTR_NE(p, NULL);
106 ASSERT_SIZE_T_EQ(strlen(p), ((8191 + 2) / 3) * 4);
107 free(p);
108 sshbuf_free(p1);
109 TEST_DONE();
110
111 TEST_START("sshbuf_b64tod len 1");
112 p1 = sshbuf_new();
113 ASSERT_PTR_NE(p1, NULL);
114 ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A=="), 0);
115 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
116 ASSERT_U8_EQ(*sshbuf_ptr(p1), 0xd0);
117 sshbuf_free(p1);
118 TEST_DONE();
119
120 TEST_START("sshbuf_b64tod len 2");
121 p1 = sshbuf_new();
122 ASSERT_PTR_NE(p1, NULL);
123 ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A8="), 0);
124 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2);
125 ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), 0xd00f);
126 sshbuf_free(p1);
127 TEST_DONE();
128
129 TEST_START("sshbuf_b64tod len 4");
130 p1 = sshbuf_new();
131 ASSERT_PTR_NE(p1, NULL);
132 ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A/QDw=="), 0);
133 ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
134 ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), 0xd00fd00f);
135 sshbuf_free(p1);
136 TEST_DONE();
137}
138
diff --git a/regress/unittests/sshbuf/tests.c b/regress/unittests/sshbuf/tests.c
new file mode 100644
index 000000000..1557e4342
--- /dev/null
+++ b/regress/unittests/sshbuf/tests.c
@@ -0,0 +1,28 @@
1/* $OpenBSD: tests.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
2/*
3 * Regress test for sshbuf.h buffer API
4 *
5 * Placed in the public domain
6 */
7
8#include "../test_helper/test_helper.h"
9
10void sshbuf_tests(void);
11void sshbuf_getput_basic_tests(void);
12void sshbuf_getput_crypto_tests(void);
13void sshbuf_misc_tests(void);
14void sshbuf_fuzz_tests(void);
15void sshbuf_getput_fuzz_tests(void);
16void sshbuf_fixed(void);
17
18void
19tests(void)
20{
21 sshbuf_tests();
22 sshbuf_getput_basic_tests();
23 sshbuf_getput_crypto_tests();
24 sshbuf_misc_tests();
25 sshbuf_fuzz_tests();
26 sshbuf_getput_fuzz_tests();
27 sshbuf_fixed();
28}
diff --git a/regress/unittests/sshkey/Makefile b/regress/unittests/sshkey/Makefile
new file mode 100644
index 000000000..1bcd26676
--- /dev/null
+++ b/regress/unittests/sshkey/Makefile
@@ -0,0 +1,13 @@
1# $OpenBSD: Makefile,v 1.1 2014/06/24 01:14:18 djm Exp $
2
3TEST_ENV= "MALLOC_OPTIONS=AFGJPRX"
4
5PROG=test_sshkey
6SRCS=tests.c test_sshkey.c test_file.c test_fuzz.c common.c
7REGRESS_TARGETS=run-regress-${PROG}
8
9run-regress-${PROG}: ${PROG}
10 env ${TEST_ENV} ./${PROG} -d ${.CURDIR}/testdata
11
12.include <bsd.regress.mk>
13
diff --git a/regress/unittests/sshkey/common.c b/regress/unittests/sshkey/common.c
new file mode 100644
index 000000000..0a4b3a90c
--- /dev/null
+++ b/regress/unittests/sshkey/common.c
@@ -0,0 +1,84 @@
1/* $OpenBSD: common.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */
2/*
3 * Helpers for key API tests
4 *
5 * Placed in the public domain
6 */
7
8#include "includes.h"
9
10#include <sys/types.h>
11#include <sys/param.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <stdio.h>
15#ifdef HAVE_STDINT_H
16#include <stdint.h>
17#endif
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21
22#include <openssl/bn.h>
23#include <openssl/rsa.h>
24#include <openssl/dsa.h>
25#include <openssl/objects.h>
26#ifdef OPENSSL_HAS_NISTP256
27# include <openssl/ec.h>
28#endif
29
30#include "../test_helper/test_helper.h"
31
32#include "ssherr.h"
33#include "authfile.h"
34#include "sshkey.h"
35#include "sshbuf.h"
36
37#include "common.h"
38
39struct sshbuf *
40load_file(const char *name)
41{
42 int fd;
43 struct sshbuf *ret;
44
45 ASSERT_PTR_NE(ret = sshbuf_new(), NULL);
46 ASSERT_INT_NE(fd = open(test_data_file(name), O_RDONLY), -1);
47 ASSERT_INT_EQ(sshkey_load_file(fd, name, ret), 0);
48 close(fd);
49 return ret;
50}
51
52struct sshbuf *
53load_text_file(const char *name)
54{
55 struct sshbuf *ret = load_file(name);
56 const u_char *p;
57
58 /* Trim whitespace at EOL */
59 for (p = sshbuf_ptr(ret); sshbuf_len(ret) > 0;) {
60 if (p[sshbuf_len(ret) - 1] == '\r' ||
61 p[sshbuf_len(ret) - 1] == '\t' ||
62 p[sshbuf_len(ret) - 1] == ' ' ||
63 p[sshbuf_len(ret) - 1] == '\n')
64 ASSERT_INT_EQ(sshbuf_consume_end(ret, 1), 0);
65 else
66 break;
67 }
68 /* \0 terminate */
69 ASSERT_INT_EQ(sshbuf_put_u8(ret, 0), 0);
70 return ret;
71}
72
73BIGNUM *
74load_bignum(const char *name)
75{
76 BIGNUM *ret = NULL;
77 struct sshbuf *buf;
78
79 buf = load_text_file(name);
80 ASSERT_INT_NE(BN_hex2bn(&ret, (const char *)sshbuf_ptr(buf)), 0);
81 sshbuf_free(buf);
82 return ret;
83}
84
diff --git a/regress/unittests/sshkey/common.h b/regress/unittests/sshkey/common.h
new file mode 100644
index 000000000..bf7d19dce
--- /dev/null
+++ b/regress/unittests/sshkey/common.h
@@ -0,0 +1,16 @@
1/* $OpenBSD: common.h,v 1.1 2014/06/24 01:14:18 djm Exp $ */
2/*
3 * Helpers for key API tests
4 *
5 * Placed in the public domain
6 */
7
8/* Load a binary file into a buffer */
9struct sshbuf *load_file(const char *name);
10
11/* Load a text file into a buffer */
12struct sshbuf *load_text_file(const char *name);
13
14/* Load a bignum from a file */
15BIGNUM *load_bignum(const char *name);
16
diff --git a/regress/unittests/sshkey/mktestdata.sh b/regress/unittests/sshkey/mktestdata.sh
new file mode 100755
index 000000000..ee1fe3962
--- /dev/null
+++ b/regress/unittests/sshkey/mktestdata.sh
@@ -0,0 +1,190 @@
1#!/bin/sh
2# $OpenBSD: mktestdata.sh,v 1.3 2014/07/22 23:57:40 dtucker Exp $
3
4PW=mekmitasdigoat
5
6rsa1_params() {
7 _in="$1"
8 _outbase="$2"
9 set -e
10 ssh-keygen -f $_in -e -m pkcs8 | \
11 openssl rsa -noout -text -pubin | \
12 awk '/^Modulus:$/,/^Exponent:/' | \
13 grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.n
14 # XXX need conversion support in ssh-keygen for the other params
15 for x in n ; do
16 echo "" >> ${_outbase}.$x
17 echo ============ ${_outbase}.$x
18 cat ${_outbase}.$x
19 echo ============
20 done
21}
22
23rsa_params() {
24 _in="$1"
25 _outbase="$2"
26 set -e
27 openssl rsa -noout -text -in $_in | \
28 awk '/^modulus:$/,/^publicExponent:/' | \
29 grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.n
30 openssl rsa -noout -text -in $_in | \
31 awk '/^prime1:$/,/^prime2:/' | \
32 grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.p
33 openssl rsa -noout -text -in $_in | \
34 awk '/^prime2:$/,/^exponent1:/' | \
35 grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.q
36 for x in n p q ; do
37 echo "" >> ${_outbase}.$x
38 echo ============ ${_outbase}.$x
39 cat ${_outbase}.$x
40 echo ============
41 done
42}
43
44dsa_params() {
45 _in="$1"
46 _outbase="$2"
47 set -e
48 openssl dsa -noout -text -in $_in | \
49 awk '/^priv:$/,/^pub:/' | \
50 grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.priv
51 openssl dsa -noout -text -in $_in | \
52 awk '/^pub:/,/^P:/' | #\
53 grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.pub
54 openssl dsa -noout -text -in $_in | \
55 awk '/^G:/,0' | \
56 grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.g
57 for x in priv pub g ; do
58 echo "" >> ${_outbase}.$x
59 echo ============ ${_outbase}.$x
60 cat ${_outbase}.$x
61 echo ============
62 done
63}
64
65ecdsa_params() {
66 _in="$1"
67 _outbase="$2"
68 set -e
69 openssl ec -noout -text -in $_in | \
70 awk '/^priv:$/,/^pub:/' | \
71 grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.priv
72 openssl ec -noout -text -in $_in | \
73 awk '/^pub:/,/^ASN1 OID:/' | #\
74 grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.pub
75 openssl ec -noout -text -in $_in | \
76 grep "ASN1 OID:" | tr -d '\n' | \
77 sed 's/.*: //;s/ *$//' > ${_outbase}.curve
78 for x in priv pub curve ; do
79 echo "" >> ${_outbase}.$x
80 echo ============ ${_outbase}.$x
81 cat ${_outbase}.$x
82 echo ============
83 done
84}
85
86set -ex
87
88cd testdata
89
90rm -f rsa1_1 rsa_1 dsa_1 ecdsa_1 ed25519_1
91rm -f rsa1_2 rsa_2 dsa_2 ecdsa_2 ed25519_2
92rm -f rsa_n dsa_n ecdsa_n # new-format keys
93rm -f rsa1_1_pw rsa_1_pw dsa_1_pw ecdsa_1_pw ed25519_1_pw
94rm -f rsa_n_pw dsa_n_pw ecdsa_n_pw
95rm -f pw *.pub *.bn.* *.param.* *.fp *.fp.bb
96
97ssh-keygen -t rsa1 -b 768 -C "RSA1 test key #1" -N "" -f rsa1_1
98ssh-keygen -t rsa -b 768 -C "RSA test key #1" -N "" -f rsa_1
99ssh-keygen -t dsa -b 1024 -C "DSA test key #1" -N "" -f dsa_1
100ssh-keygen -t ecdsa -b 256 -C "ECDSA test key #1" -N "" -f ecdsa_1
101ssh-keygen -t ed25519 -C "ED25519 test key #1" -N "" -f ed25519_1
102
103ssh-keygen -t rsa1 -b 2048 -C "RSA1 test key #2" -N "" -f rsa1_2
104ssh-keygen -t rsa -b 2048 -C "RSA test key #2" -N "" -f rsa_2
105ssh-keygen -t dsa -b 1024 -C "DSA test key #2" -N "" -f dsa_2
106ssh-keygen -t ecdsa -b 521 -C "ECDSA test key #2" -N "" -f ecdsa_2
107ssh-keygen -t ed25519 -C "ED25519 test key #1" -N "" -f ed25519_2
108
109cp rsa_1 rsa_n
110cp dsa_1 dsa_n
111cp ecdsa_1 ecdsa_n
112
113cp rsa1_1 rsa1_1_pw
114cp rsa_1 rsa_1_pw
115cp dsa_1 dsa_1_pw
116cp ecdsa_1 ecdsa_1_pw
117cp ed25519_1 ed25519_1_pw
118cp rsa_1 rsa_n_pw
119cp dsa_1 dsa_n_pw
120cp ecdsa_1 ecdsa_n_pw
121
122ssh-keygen -pf rsa1_1_pw -N "$PW"
123ssh-keygen -pf rsa_1_pw -N "$PW"
124ssh-keygen -pf dsa_1_pw -N "$PW"
125ssh-keygen -pf ecdsa_1_pw -N "$PW"
126ssh-keygen -pf ed25519_1_pw -N "$PW"
127ssh-keygen -opf rsa_n_pw -N "$PW"
128ssh-keygen -opf dsa_n_pw -N "$PW"
129ssh-keygen -opf ecdsa_n_pw -N "$PW"
130
131rsa1_params rsa1_1 rsa1_1.param
132rsa1_params rsa1_2 rsa1_2.param
133rsa_params rsa_1 rsa_1.param
134rsa_params rsa_2 rsa_2.param
135dsa_params dsa_1 dsa_1.param
136dsa_params dsa_1 dsa_1.param
137ecdsa_params ecdsa_1 ecdsa_1.param
138ecdsa_params ecdsa_2 ecdsa_2.param
139# XXX ed25519 params
140
141ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
142 -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
143 -V 19990101:20110101 -z 1 rsa_1.pub
144ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
145 -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
146 -V 19990101:20110101 -z 2 dsa_1.pub
147ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
148 -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
149 -V 19990101:20110101 -z 3 ecdsa_1.pub
150ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
151 -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
152 -V 19990101:20110101 -z 4 ed25519_1.pub
153
154ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \
155 -V 19990101:20110101 -z 5 rsa_1.pub
156ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \
157 -V 19990101:20110101 -z 6 dsa_1.pub
158ssh-keygen -s ecdsa_1 -I julius -n host1,host2 -h \
159 -V 19990101:20110101 -z 7 ecdsa_1.pub
160ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \
161 -V 19990101:20110101 -z 8 ed25519_1.pub
162
163ssh-keygen -lf rsa1_1 | awk '{print $2}' > rsa1_1.fp
164ssh-keygen -lf rsa_1 | awk '{print $2}' > rsa_1.fp
165ssh-keygen -lf dsa_1 | awk '{print $2}' > dsa_1.fp
166ssh-keygen -lf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp
167ssh-keygen -lf ed25519_1 | awk '{print $2}' > ed25519_1.fp
168ssh-keygen -lf rsa1_2 | awk '{print $2}' > rsa1_2.fp
169ssh-keygen -lf rsa_2 | awk '{print $2}' > rsa_2.fp
170ssh-keygen -lf dsa_2 | awk '{print $2}' > dsa_2.fp
171ssh-keygen -lf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp
172ssh-keygen -lf ed25519_2 | awk '{print $2}' > ed25519_2.fp
173
174ssh-keygen -lf dsa_1-cert.pub | awk '{print $2}' > dsa_1-cert.fp
175ssh-keygen -lf ecdsa_1-cert.pub | awk '{print $2}' > ecdsa_1-cert.fp
176ssh-keygen -lf ed25519_1-cert.pub | awk '{print $2}' > ed25519_1-cert.fp
177ssh-keygen -lf rsa_1-cert.pub | awk '{print $2}' > rsa_1-cert.fp
178
179ssh-keygen -Bf rsa1_1 | awk '{print $2}' > rsa1_1.fp.bb
180ssh-keygen -Bf rsa_1 | awk '{print $2}' > rsa_1.fp.bb
181ssh-keygen -Bf dsa_1 | awk '{print $2}' > dsa_1.fp.bb
182ssh-keygen -Bf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp.bb
183ssh-keygen -Bf ed25519_1 | awk '{print $2}' > ed25519_1.fp.bb
184ssh-keygen -Bf rsa1_2 | awk '{print $2}' > rsa1_2.fp.bb
185ssh-keygen -Bf rsa_2 | awk '{print $2}' > rsa_2.fp.bb
186ssh-keygen -Bf dsa_2 | awk '{print $2}' > dsa_2.fp.bb
187ssh-keygen -Bf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp.bb
188ssh-keygen -Bf ed25519_2 | awk '{print $2}' > ed25519_2.fp.bb
189
190echo "$PW" > pw
diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c
new file mode 100644
index 000000000..764f7fb76
--- /dev/null
+++ b/regress/unittests/sshkey/test_file.c
@@ -0,0 +1,457 @@
1/* $OpenBSD: test_file.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */
2/*
3 * Regress test for sshkey.h key management API
4 *
5 * Placed in the public domain
6 */
7
8#include "includes.h"
9
10#include <sys/types.h>
11#include <sys/param.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <stdio.h>
15#ifdef HAVE_STDINT_H
16#include <stdint.h>
17#endif
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21
22#include <openssl/bn.h>
23#include <openssl/rsa.h>
24#include <openssl/dsa.h>
25#include <openssl/objects.h>
26#ifdef OPENSSL_HAS_NISTP256
27# include <openssl/ec.h>
28#endif
29
30#include "../test_helper/test_helper.h"
31
32#include "ssherr.h"
33#include "authfile.h"
34#include "sshkey.h"
35#include "sshbuf.h"
36
37#include "common.h"
38
39void sshkey_file_tests(void);
40
41void
42sshkey_file_tests(void)
43{
44 struct sshkey *k1, *k2;
45 struct sshbuf *buf, *pw;
46 BIGNUM *a, *b, *c;
47 char *cp;
48
49 TEST_START("load passphrase");
50 pw = load_text_file("pw");
51 TEST_DONE();
52
53 TEST_START("parse RSA1 from private");
54 buf = load_file("rsa1_1");
55 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "rsa1_1",
56 &k1, NULL), 0);
57 sshbuf_free(buf);
58 ASSERT_PTR_NE(k1, NULL);
59 a = load_bignum("rsa1_1.param.n");
60 ASSERT_BIGNUM_EQ(k1->rsa->n, a);
61 BN_free(a);
62 TEST_DONE();
63
64 TEST_START("parse RSA1 from private w/ passphrase");
65 buf = load_file("rsa1_1_pw");
66 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
67 (const char *)sshbuf_ptr(pw), "rsa1_1_pw", &k2, NULL), 0);
68 sshbuf_free(buf);
69 ASSERT_PTR_NE(k2, NULL);
70 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
71 sshkey_free(k2);
72 TEST_DONE();
73
74 TEST_START("load RSA1 from public");
75 ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa1_1.pub"), &k2,
76 NULL), 0);
77 ASSERT_PTR_NE(k2, NULL);
78 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
79 sshkey_free(k2);
80 TEST_DONE();
81
82 TEST_START("RSA1 key hex fingerprint");
83 buf = load_text_file("rsa1_1.fp");
84 cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX);
85 ASSERT_PTR_NE(cp, NULL);
86 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
87 sshbuf_free(buf);
88 free(cp);
89 TEST_DONE();
90
91 TEST_START("RSA1 key bubblebabble fingerprint");
92 buf = load_text_file("rsa1_1.fp.bb");
93 cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE);
94 ASSERT_PTR_NE(cp, NULL);
95 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
96 sshbuf_free(buf);
97 free(cp);
98 TEST_DONE();
99
100 sshkey_free(k1);
101
102 TEST_START("parse RSA from private");
103 buf = load_file("rsa_1");
104 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "rsa_1",
105 &k1, NULL), 0);
106 sshbuf_free(buf);
107 ASSERT_PTR_NE(k1, NULL);
108 a = load_bignum("rsa_1.param.n");
109 b = load_bignum("rsa_1.param.p");
110 c = load_bignum("rsa_1.param.q");
111 ASSERT_BIGNUM_EQ(k1->rsa->n, a);
112 ASSERT_BIGNUM_EQ(k1->rsa->p, b);
113 ASSERT_BIGNUM_EQ(k1->rsa->q, c);
114 BN_free(a);
115 BN_free(b);
116 BN_free(c);
117 TEST_DONE();
118
119 TEST_START("parse RSA from private w/ passphrase");
120 buf = load_file("rsa_1_pw");
121 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
122 (const char *)sshbuf_ptr(pw), "rsa_1_pw", &k2, NULL), 0);
123 sshbuf_free(buf);
124 ASSERT_PTR_NE(k2, NULL);
125 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
126 sshkey_free(k2);
127 TEST_DONE();
128
129 TEST_START("parse RSA from new-format");
130 buf = load_file("rsa_n");
131 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
132 "", "rsa_n", &k2, NULL), 0);
133 sshbuf_free(buf);
134 ASSERT_PTR_NE(k2, NULL);
135 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
136 sshkey_free(k2);
137 TEST_DONE();
138
139 TEST_START("parse RSA from new-format w/ passphrase");
140 buf = load_file("rsa_n_pw");
141 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
142 (const char *)sshbuf_ptr(pw), "rsa_n_pw", &k2, NULL), 0);
143 sshbuf_free(buf);
144 ASSERT_PTR_NE(k2, NULL);
145 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
146 sshkey_free(k2);
147 TEST_DONE();
148
149 TEST_START("load RSA from public");
150 ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2,
151 NULL), 0);
152 ASSERT_PTR_NE(k2, NULL);
153 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
154 sshkey_free(k2);
155 TEST_DONE();
156
157 TEST_START("load RSA cert");
158 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k2), 0);
159 ASSERT_PTR_NE(k2, NULL);
160 ASSERT_INT_EQ(k2->type, KEY_RSA_CERT);
161 ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
162 ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
163 TEST_DONE();
164
165 TEST_START("RSA key hex fingerprint");
166 buf = load_text_file("rsa_1.fp");
167 cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX);
168 ASSERT_PTR_NE(cp, NULL);
169 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
170 sshbuf_free(buf);
171 free(cp);
172 TEST_DONE();
173
174 TEST_START("RSA cert hex fingerprint");
175 buf = load_text_file("rsa_1-cert.fp");
176 cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX);
177 ASSERT_PTR_NE(cp, NULL);
178 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
179 sshbuf_free(buf);
180 free(cp);
181 sshkey_free(k2);
182 TEST_DONE();
183
184 TEST_START("RSA key bubblebabble fingerprint");
185 buf = load_text_file("rsa_1.fp.bb");
186 cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE);
187 ASSERT_PTR_NE(cp, NULL);
188 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
189 sshbuf_free(buf);
190 free(cp);
191 TEST_DONE();
192
193 sshkey_free(k1);
194
195 TEST_START("parse DSA from private");
196 buf = load_file("dsa_1");
197 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "dsa_1",
198 &k1, NULL), 0);
199 sshbuf_free(buf);
200 ASSERT_PTR_NE(k1, NULL);
201 a = load_bignum("dsa_1.param.g");
202 b = load_bignum("dsa_1.param.priv");
203 c = load_bignum("dsa_1.param.pub");
204 ASSERT_BIGNUM_EQ(k1->dsa->g, a);
205 ASSERT_BIGNUM_EQ(k1->dsa->priv_key, b);
206 ASSERT_BIGNUM_EQ(k1->dsa->pub_key, c);
207 BN_free(a);
208 BN_free(b);
209 BN_free(c);
210 TEST_DONE();
211
212 TEST_START("parse DSA from private w/ passphrase");
213 buf = load_file("dsa_1_pw");
214 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
215 (const char *)sshbuf_ptr(pw), "dsa_1_pw", &k2, NULL), 0);
216 sshbuf_free(buf);
217 ASSERT_PTR_NE(k2, NULL);
218 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
219 sshkey_free(k2);
220 TEST_DONE();
221
222 TEST_START("parse DSA from new-format");
223 buf = load_file("dsa_n");
224 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
225 "", "dsa_n", &k2, NULL), 0);
226 sshbuf_free(buf);
227 ASSERT_PTR_NE(k2, NULL);
228 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
229 sshkey_free(k2);
230 TEST_DONE();
231
232 TEST_START("parse DSA from new-format w/ passphrase");
233 buf = load_file("dsa_n_pw");
234 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
235 (const char *)sshbuf_ptr(pw), "dsa_n_pw", &k2, NULL), 0);
236 sshbuf_free(buf);
237 ASSERT_PTR_NE(k2, NULL);
238 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
239 sshkey_free(k2);
240 TEST_DONE();
241
242 TEST_START("load DSA from public");
243 ASSERT_INT_EQ(sshkey_load_public(test_data_file("dsa_1.pub"), &k2,
244 NULL), 0);
245 ASSERT_PTR_NE(k2, NULL);
246 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
247 sshkey_free(k2);
248 TEST_DONE();
249
250 TEST_START("load DSA cert");
251 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("dsa_1"), &k2), 0);
252 ASSERT_PTR_NE(k2, NULL);
253 ASSERT_INT_EQ(k2->type, KEY_DSA_CERT);
254 ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
255 ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
256 TEST_DONE();
257
258 TEST_START("DSA key hex fingerprint");
259 buf = load_text_file("dsa_1.fp");
260 cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX);
261 ASSERT_PTR_NE(cp, NULL);
262 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
263 sshbuf_free(buf);
264 free(cp);
265 TEST_DONE();
266
267 TEST_START("DSA cert hex fingerprint");
268 buf = load_text_file("dsa_1-cert.fp");
269 cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX);
270 ASSERT_PTR_NE(cp, NULL);
271 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
272 sshbuf_free(buf);
273 free(cp);
274 sshkey_free(k2);
275 TEST_DONE();
276
277 TEST_START("DSA key bubblebabble fingerprint");
278 buf = load_text_file("dsa_1.fp.bb");
279 cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE);
280 ASSERT_PTR_NE(cp, NULL);
281 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
282 sshbuf_free(buf);
283 free(cp);
284 TEST_DONE();
285
286 sshkey_free(k1);
287
288#ifdef OPENSSL_HAS_ECC
289 TEST_START("parse ECDSA from private");
290 buf = load_file("ecdsa_1");
291 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "ecdsa_1",
292 &k1, NULL), 0);
293 sshbuf_free(buf);
294 ASSERT_PTR_NE(k1, NULL);
295 buf = load_text_file("ecdsa_1.param.curve");
296 ASSERT_STRING_EQ((const char *)sshbuf_ptr(buf),
297 OBJ_nid2sn(k1->ecdsa_nid));
298 sshbuf_free(buf);
299 a = load_bignum("ecdsa_1.param.priv");
300 b = load_bignum("ecdsa_1.param.pub");
301 c = EC_POINT_point2bn(EC_KEY_get0_group(k1->ecdsa),
302 EC_KEY_get0_public_key(k1->ecdsa), POINT_CONVERSION_UNCOMPRESSED,
303 NULL, NULL);
304 ASSERT_PTR_NE(c, NULL);
305 ASSERT_BIGNUM_EQ(EC_KEY_get0_private_key(k1->ecdsa), a);
306 ASSERT_BIGNUM_EQ(b, c);
307 BN_free(a);
308 BN_free(b);
309 BN_free(c);
310 TEST_DONE();
311
312 TEST_START("parse ECDSA from private w/ passphrase");
313 buf = load_file("ecdsa_1_pw");
314 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
315 (const char *)sshbuf_ptr(pw), "ecdsa_1_pw", &k2, NULL), 0);
316 sshbuf_free(buf);
317 ASSERT_PTR_NE(k2, NULL);
318 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
319 sshkey_free(k2);
320 TEST_DONE();
321
322 TEST_START("parse ECDSA from new-format");
323 buf = load_file("ecdsa_n");
324 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
325 "", "ecdsa_n", &k2, NULL), 0);
326 sshbuf_free(buf);
327 ASSERT_PTR_NE(k2, NULL);
328 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
329 sshkey_free(k2);
330 TEST_DONE();
331
332 TEST_START("parse ECDSA from new-format w/ passphrase");
333 buf = load_file("ecdsa_n_pw");
334 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
335 (const char *)sshbuf_ptr(pw), "ecdsa_n_pw", &k2, NULL), 0);
336 sshbuf_free(buf);
337 ASSERT_PTR_NE(k2, NULL);
338 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
339 sshkey_free(k2);
340 TEST_DONE();
341
342 TEST_START("load ECDSA from public");
343 ASSERT_INT_EQ(sshkey_load_public(test_data_file("ecdsa_1.pub"), &k2,
344 NULL), 0);
345 ASSERT_PTR_NE(k2, NULL);
346 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
347 sshkey_free(k2);
348 TEST_DONE();
349
350 TEST_START("load ECDSA cert");
351 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ecdsa_1"), &k2), 0);
352 ASSERT_PTR_NE(k2, NULL);
353 ASSERT_INT_EQ(k2->type, KEY_ECDSA_CERT);
354 ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
355 ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
356 TEST_DONE();
357
358 TEST_START("ECDSA key hex fingerprint");
359 buf = load_text_file("ecdsa_1.fp");
360 cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX);
361 ASSERT_PTR_NE(cp, NULL);
362 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
363 sshbuf_free(buf);
364 free(cp);
365 TEST_DONE();
366
367 TEST_START("ECDSA cert hex fingerprint");
368 buf = load_text_file("ecdsa_1-cert.fp");
369 cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX);
370 ASSERT_PTR_NE(cp, NULL);
371 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
372 sshbuf_free(buf);
373 free(cp);
374 sshkey_free(k2);
375 TEST_DONE();
376
377 TEST_START("ECDSA key bubblebabble fingerprint");
378 buf = load_text_file("ecdsa_1.fp.bb");
379 cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE);
380 ASSERT_PTR_NE(cp, NULL);
381 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
382 sshbuf_free(buf);
383 free(cp);
384 TEST_DONE();
385
386 sshkey_free(k1);
387#endif /* OPENSSL_HAS_ECC */
388
389 TEST_START("parse Ed25519 from private");
390 buf = load_file("ed25519_1");
391 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "ed25519_1",
392 &k1, NULL), 0);
393 sshbuf_free(buf);
394 ASSERT_PTR_NE(k1, NULL);
395 ASSERT_INT_EQ(k1->type, KEY_ED25519);
396 /* XXX check key contents */
397 TEST_DONE();
398
399 TEST_START("parse Ed25519 from private w/ passphrase");
400 buf = load_file("ed25519_1_pw");
401 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
402 (const char *)sshbuf_ptr(pw), "ed25519_1_pw", &k2, NULL), 0);
403 sshbuf_free(buf);
404 ASSERT_PTR_NE(k2, NULL);
405 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
406 sshkey_free(k2);
407 TEST_DONE();
408
409 TEST_START("load Ed25519 from public");
410 ASSERT_INT_EQ(sshkey_load_public(test_data_file("ed25519_1.pub"), &k2,
411 NULL), 0);
412 ASSERT_PTR_NE(k2, NULL);
413 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
414 sshkey_free(k2);
415 TEST_DONE();
416
417 TEST_START("load Ed25519 cert");
418 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ed25519_1"), &k2), 0);
419 ASSERT_PTR_NE(k2, NULL);
420 ASSERT_INT_EQ(k2->type, KEY_ED25519_CERT);
421 ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
422 ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
423 TEST_DONE();
424
425 TEST_START("Ed25519 key hex fingerprint");
426 buf = load_text_file("ed25519_1.fp");
427 cp = sshkey_fingerprint(k1, SSH_FP_MD5, SSH_FP_HEX);
428 ASSERT_PTR_NE(cp, NULL);
429 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
430 sshbuf_free(buf);
431 free(cp);
432 TEST_DONE();
433
434 TEST_START("Ed25519 cert hex fingerprint");
435 buf = load_text_file("ed25519_1-cert.fp");
436 cp = sshkey_fingerprint(k2, SSH_FP_MD5, SSH_FP_HEX);
437 ASSERT_PTR_NE(cp, NULL);
438 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
439 sshbuf_free(buf);
440 free(cp);
441 sshkey_free(k2);
442 TEST_DONE();
443
444 TEST_START("Ed25519 key bubblebabble fingerprint");
445 buf = load_text_file("ed25519_1.fp.bb");
446 cp = sshkey_fingerprint(k1, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE);
447 ASSERT_PTR_NE(cp, NULL);
448 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
449 sshbuf_free(buf);
450 free(cp);
451 TEST_DONE();
452
453 sshkey_free(k1);
454
455 sshbuf_free(pw);
456
457}
diff --git a/regress/unittests/sshkey/test_fuzz.c b/regress/unittests/sshkey/test_fuzz.c
new file mode 100644
index 000000000..a3f61a6df
--- /dev/null
+++ b/regress/unittests/sshkey/test_fuzz.c
@@ -0,0 +1,406 @@
1/* $OpenBSD: test_fuzz.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */
2/*
3 * Fuzz tests for key parsing
4 *
5 * Placed in the public domain
6 */
7
8#include "includes.h"
9
10#include <sys/types.h>
11#include <sys/param.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <stdio.h>
15#ifdef HAVE_STDINT_H
16#include <stdint.h>
17#endif
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21
22#include <openssl/bn.h>
23#include <openssl/rsa.h>
24#include <openssl/dsa.h>
25#include <openssl/objects.h>
26#ifdef OPENSSL_HAS_NISTP256
27# include <openssl/ec.h>
28#endif
29
30#include "../test_helper/test_helper.h"
31
32#include "ssherr.h"
33#include "authfile.h"
34#include "sshkey.h"
35#include "sshbuf.h"
36
37#include "common.h"
38
39void sshkey_fuzz_tests(void);
40
41static void
42onerror(void *fuzz)
43{
44 fprintf(stderr, "Failed during fuzz:\n");
45 fuzz_dump((struct fuzz *)fuzz);
46}
47
48static void
49public_fuzz(struct sshkey *k)
50{
51 struct sshkey *k1;
52 struct sshbuf *buf;
53 struct fuzz *fuzz;
54
55 ASSERT_PTR_NE(buf = sshbuf_new(), NULL);
56 ASSERT_INT_EQ(sshkey_to_blob_buf(k, buf), 0);
57 /* XXX need a way to run the tests in "slow, but complete" mode */
58 fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | /* XXX too slow FUZZ_2_BIT_FLIP | */
59 FUZZ_1_BYTE_FLIP | /* XXX too slow FUZZ_2_BYTE_FLIP | */
60 FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END,
61 sshbuf_mutable_ptr(buf), sshbuf_len(buf));
62 ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(buf), sshbuf_len(buf),
63 &k1), 0);
64 sshkey_free(k1);
65 sshbuf_free(buf);
66 TEST_ONERROR(onerror, fuzz);
67 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
68 if (sshkey_from_blob(fuzz_ptr(fuzz), fuzz_len(fuzz), &k1) == 0)
69 sshkey_free(k1);
70 }
71 fuzz_cleanup(fuzz);
72}
73
74static void
75sig_fuzz(struct sshkey *k)
76{
77 struct fuzz *fuzz;
78 u_char *sig, c[] = "some junk to be signed";
79 size_t l;
80
81 ASSERT_INT_EQ(sshkey_sign(k, &sig, &l, c, sizeof(c), 0), 0);
82 ASSERT_SIZE_T_GT(l, 0);
83 fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | /* too slow FUZZ_2_BIT_FLIP | */
84 FUZZ_1_BYTE_FLIP | FUZZ_2_BYTE_FLIP |
85 FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END, sig, l);
86 ASSERT_INT_EQ(sshkey_verify(k, sig, l, c, sizeof(c), 0), 0);
87 free(sig);
88 TEST_ONERROR(onerror, fuzz);
89 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
90 sshkey_verify(k, fuzz_ptr(fuzz), fuzz_len(fuzz),
91 c, sizeof(c), 0);
92 }
93 fuzz_cleanup(fuzz);
94}
95
96void
97sshkey_fuzz_tests(void)
98{
99 struct sshkey *k1;
100 struct sshbuf *buf, *fuzzed;
101 struct fuzz *fuzz;
102 int r;
103
104 TEST_START("fuzz RSA1 private");
105 buf = load_file("rsa1_1");
106 fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP |
107 FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END,
108 sshbuf_mutable_ptr(buf), sshbuf_len(buf));
109 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
110 &k1, NULL), 0);
111 sshkey_free(k1);
112 sshbuf_free(buf);
113 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
114 TEST_ONERROR(onerror, fuzz);
115 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
116 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
117 ASSERT_INT_EQ(r, 0);
118 if (sshkey_parse_private_fileblob(fuzzed, "", "key",
119 &k1, NULL) == 0)
120 sshkey_free(k1);
121 sshbuf_reset(fuzzed);
122 }
123 sshbuf_free(fuzzed);
124 fuzz_cleanup(fuzz);
125 TEST_DONE();
126
127 TEST_START("fuzz RSA1 public");
128 buf = load_file("rsa1_1_pw");
129 fuzz = fuzz_begin(FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP |
130 FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END,
131 sshbuf_mutable_ptr(buf), sshbuf_len(buf));
132 ASSERT_INT_EQ(sshkey_parse_public_rsa1_fileblob(buf, &k1, NULL), 0);
133 sshkey_free(k1);
134 sshbuf_free(buf);
135 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
136 TEST_ONERROR(onerror, fuzz);
137 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
138 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
139 ASSERT_INT_EQ(r, 0);
140 if (sshkey_parse_public_rsa1_fileblob(fuzzed, &k1, NULL) == 0)
141 sshkey_free(k1);
142 sshbuf_reset(fuzzed);
143 }
144 sshbuf_free(fuzzed);
145 fuzz_cleanup(fuzz);
146 TEST_DONE();
147
148 TEST_START("fuzz RSA private");
149 buf = load_file("rsa_1");
150 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
151 sshbuf_len(buf));
152 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
153 &k1, NULL), 0);
154 sshkey_free(k1);
155 sshbuf_free(buf);
156 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
157 TEST_ONERROR(onerror, fuzz);
158 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
159 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
160 ASSERT_INT_EQ(r, 0);
161 if (sshkey_parse_private_fileblob(fuzzed, "", "key",
162 &k1, NULL) == 0)
163 sshkey_free(k1);
164 sshbuf_reset(fuzzed);
165 }
166 sshbuf_free(fuzzed);
167 fuzz_cleanup(fuzz);
168 TEST_DONE();
169
170 TEST_START("fuzz RSA new-format private");
171 buf = load_file("rsa_n");
172 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
173 sshbuf_len(buf));
174 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
175 &k1, NULL), 0);
176 sshkey_free(k1);
177 sshbuf_free(buf);
178 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
179 TEST_ONERROR(onerror, fuzz);
180 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
181 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
182 ASSERT_INT_EQ(r, 0);
183 if (sshkey_parse_private_fileblob(fuzzed, "", "key",
184 &k1, NULL) == 0)
185 sshkey_free(k1);
186 sshbuf_reset(fuzzed);
187 }
188 sshbuf_free(fuzzed);
189 fuzz_cleanup(fuzz);
190 TEST_DONE();
191
192 TEST_START("fuzz DSA private");
193 buf = load_file("dsa_1");
194 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
195 sshbuf_len(buf));
196 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
197 &k1, NULL), 0);
198 sshkey_free(k1);
199 sshbuf_free(buf);
200 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
201 TEST_ONERROR(onerror, fuzz);
202 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
203 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
204 ASSERT_INT_EQ(r, 0);
205 if (sshkey_parse_private_fileblob(fuzzed, "", "key",
206 &k1, NULL) == 0)
207 sshkey_free(k1);
208 sshbuf_reset(fuzzed);
209 }
210 sshbuf_free(fuzzed);
211 fuzz_cleanup(fuzz);
212 TEST_DONE();
213
214 TEST_START("fuzz DSA new-format private");
215 buf = load_file("dsa_n");
216 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
217 sshbuf_len(buf));
218 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
219 &k1, NULL), 0);
220 sshkey_free(k1);
221 sshbuf_free(buf);
222 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
223 TEST_ONERROR(onerror, fuzz);
224 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
225 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
226 ASSERT_INT_EQ(r, 0);
227 if (sshkey_parse_private_fileblob(fuzzed, "", "key",
228 &k1, NULL) == 0)
229 sshkey_free(k1);
230 sshbuf_reset(fuzzed);
231 }
232 sshbuf_free(fuzzed);
233 fuzz_cleanup(fuzz);
234 TEST_DONE();
235
236#ifdef OPENSSL_HAS_ECC
237 TEST_START("fuzz ECDSA private");
238 buf = load_file("ecdsa_1");
239 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
240 sshbuf_len(buf));
241 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
242 &k1, NULL), 0);
243 sshkey_free(k1);
244 sshbuf_free(buf);
245 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
246 TEST_ONERROR(onerror, fuzz);
247 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
248 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
249 ASSERT_INT_EQ(r, 0);
250 if (sshkey_parse_private_fileblob(fuzzed, "", "key",
251 &k1, NULL) == 0)
252 sshkey_free(k1);
253 sshbuf_reset(fuzzed);
254 }
255 sshbuf_free(fuzzed);
256 fuzz_cleanup(fuzz);
257 TEST_DONE();
258
259 TEST_START("fuzz ECDSA new-format private");
260 buf = load_file("ecdsa_n");
261 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
262 sshbuf_len(buf));
263 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
264 &k1, NULL), 0);
265 sshkey_free(k1);
266 sshbuf_free(buf);
267 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
268 TEST_ONERROR(onerror, fuzz);
269 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
270 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
271 ASSERT_INT_EQ(r, 0);
272 if (sshkey_parse_private_fileblob(fuzzed, "", "key",
273 &k1, NULL) == 0)
274 sshkey_free(k1);
275 sshbuf_reset(fuzzed);
276 }
277 sshbuf_free(fuzzed);
278 fuzz_cleanup(fuzz);
279 TEST_DONE();
280#endif
281
282 TEST_START("fuzz Ed25519 private");
283 buf = load_file("ed25519_1");
284 fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf),
285 sshbuf_len(buf));
286 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
287 &k1, NULL), 0);
288 sshkey_free(k1);
289 sshbuf_free(buf);
290 ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL);
291 TEST_ONERROR(onerror, fuzz);
292 for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
293 r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz));
294 ASSERT_INT_EQ(r, 0);
295 if (sshkey_parse_private_fileblob(fuzzed, "", "key",
296 &k1, NULL) == 0)
297 sshkey_free(k1);
298 sshbuf_reset(fuzzed);
299 }
300 sshbuf_free(fuzzed);
301 fuzz_cleanup(fuzz);
302 TEST_DONE();
303
304 TEST_START("fuzz RSA public");
305 buf = load_file("rsa_1");
306 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
307 &k1, NULL), 0);
308 sshbuf_free(buf);
309 public_fuzz(k1);
310 sshkey_free(k1);
311 TEST_DONE();
312
313 TEST_START("fuzz RSA cert");
314 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k1), 0);
315 public_fuzz(k1);
316 sshkey_free(k1);
317 TEST_DONE();
318
319 TEST_START("fuzz DSA public");
320 buf = load_file("dsa_1");
321 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
322 &k1, NULL), 0);
323 sshbuf_free(buf);
324 public_fuzz(k1);
325 sshkey_free(k1);
326 TEST_DONE();
327
328 TEST_START("fuzz DSA cert");
329 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("dsa_1"), &k1), 0);
330 public_fuzz(k1);
331 sshkey_free(k1);
332 TEST_DONE();
333
334#ifdef OPENSSL_HAS_ECC
335 TEST_START("fuzz ECDSA public");
336 buf = load_file("ecdsa_1");
337 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
338 &k1, NULL), 0);
339 sshbuf_free(buf);
340 public_fuzz(k1);
341 sshkey_free(k1);
342 TEST_DONE();
343
344 TEST_START("fuzz ECDSA cert");
345 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ecdsa_1"), &k1), 0);
346 public_fuzz(k1);
347 sshkey_free(k1);
348 TEST_DONE();
349#endif
350
351 TEST_START("fuzz Ed25519 public");
352 buf = load_file("ed25519_1");
353 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
354 &k1, NULL), 0);
355 sshbuf_free(buf);
356 public_fuzz(k1);
357 sshkey_free(k1);
358 TEST_DONE();
359
360 TEST_START("fuzz Ed25519 cert");
361 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ed25519_1"), &k1), 0);
362 public_fuzz(k1);
363 sshkey_free(k1);
364 TEST_DONE();
365
366 TEST_START("fuzz RSA sig");
367 buf = load_file("rsa_1");
368 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
369 &k1, NULL), 0);
370 sshbuf_free(buf);
371 sig_fuzz(k1);
372 sshkey_free(k1);
373 TEST_DONE();
374
375 TEST_START("fuzz DSA sig");
376 buf = load_file("dsa_1");
377 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
378 &k1, NULL), 0);
379 sshbuf_free(buf);
380 sig_fuzz(k1);
381 sshkey_free(k1);
382 TEST_DONE();
383
384#ifdef OPENSSL_HAS_ECC
385 TEST_START("fuzz ECDSA sig");
386 buf = load_file("ecdsa_1");
387 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
388 &k1, NULL), 0);
389 sshbuf_free(buf);
390 sig_fuzz(k1);
391 sshkey_free(k1);
392 TEST_DONE();
393#endif
394
395 TEST_START("fuzz Ed25519 sig");
396 buf = load_file("ed25519_1");
397 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", "key",
398 &k1, NULL), 0);
399 sshbuf_free(buf);
400 sig_fuzz(k1);
401 sshkey_free(k1);
402 TEST_DONE();
403
404/* XXX fuzz decoded new-format blobs too */
405
406}
diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c
new file mode 100644
index 000000000..ef0c67956
--- /dev/null
+++ b/regress/unittests/sshkey/test_sshkey.c
@@ -0,0 +1,357 @@
1/* $OpenBSD: test_sshkey.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */
2/*
3 * Regress test for sshkey.h key management API
4 *
5 * Placed in the public domain
6 */
7
8#include "includes.h"
9
10#include <sys/types.h>
11#include <sys/param.h>
12#include <stdio.h>
13#ifdef HAVE_STDINT_H
14#include <stdint.h>
15#endif
16#include <stdlib.h>
17#include <string.h>
18
19#include <openssl/bn.h>
20#include <openssl/rsa.h>
21#include <openssl/dsa.h>
22#ifdef OPENSSL_HAS_NISTP256
23# include <openssl/ec.h>
24#endif
25
26#include "../test_helper/test_helper.h"
27
28#include "ssherr.h"
29#include "sshbuf.h"
30#define SSHBUF_INTERNAL 1 /* access internals for testing */
31#include "sshkey.h"
32
33#include "authfile.h"
34#include "common.h"
35#include "ssh2.h"
36
37void sshkey_tests(void);
38
39static void
40build_cert(struct sshbuf *b, const struct sshkey *k, const char *type,
41 const struct sshkey *sign_key, const struct sshkey *ca_key)
42{
43 struct sshbuf *ca_buf, *pk, *principals, *critopts, *exts;
44 u_char *sigblob;
45 size_t siglen;
46
47 ca_buf = sshbuf_new();
48 ASSERT_INT_EQ(sshkey_to_blob_buf(ca_key, ca_buf), 0);
49
50 /*
51 * Get the public key serialisation by rendering the key and skipping
52 * the type string. This is a bit of a hack :/
53 */
54 pk = sshbuf_new();
55 ASSERT_INT_EQ(sshkey_plain_to_blob_buf(k, pk), 0);
56 ASSERT_INT_EQ(sshbuf_skip_string(pk), 0);
57
58 principals = sshbuf_new();
59 ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gsamsa"), 0);
60 ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gregor"), 0);
61
62 critopts = sshbuf_new();
63 /* XXX fill this in */
64
65 exts = sshbuf_new();
66 /* XXX fill this in */
67
68 ASSERT_INT_EQ(sshbuf_put_cstring(b, type), 0);
69 ASSERT_INT_EQ(sshbuf_put_cstring(b, "noncenoncenonce!"), 0); /* nonce */
70 ASSERT_INT_EQ(sshbuf_putb(b, pk), 0); /* public key serialisation */
71 ASSERT_INT_EQ(sshbuf_put_u64(b, 1234), 0); /* serial */
72 ASSERT_INT_EQ(sshbuf_put_u32(b, SSH2_CERT_TYPE_USER), 0); /* type */
73 ASSERT_INT_EQ(sshbuf_put_cstring(b, "gregor"), 0); /* key ID */
74 ASSERT_INT_EQ(sshbuf_put_stringb(b, principals), 0); /* principals */
75 ASSERT_INT_EQ(sshbuf_put_u64(b, 0), 0); /* start */
76 ASSERT_INT_EQ(sshbuf_put_u64(b, 0xffffffffffffffffULL), 0); /* end */
77 ASSERT_INT_EQ(sshbuf_put_stringb(b, critopts), 0); /* options */
78 ASSERT_INT_EQ(sshbuf_put_stringb(b, exts), 0); /* extensions */
79 ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */
80 ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */
81 ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen,
82 sshbuf_ptr(b), sshbuf_len(b), 0), 0);
83 ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */
84
85 free(sigblob);
86 sshbuf_free(ca_buf);
87 sshbuf_free(exts);
88 sshbuf_free(critopts);
89 sshbuf_free(principals);
90 sshbuf_free(pk);
91}
92
93void
94sshkey_tests(void)
95{
96 struct sshkey *k1, *k2, *k3, *k4, *kr, *kd, *ke, *kf;
97 struct sshbuf *b;
98
99 TEST_START("new invalid");
100 k1 = sshkey_new(-42);
101 ASSERT_PTR_EQ(k1, NULL);
102 TEST_DONE();
103
104 TEST_START("new/free KEY_UNSPEC");
105 k1 = sshkey_new(KEY_UNSPEC);
106 ASSERT_PTR_NE(k1, NULL);
107 sshkey_free(k1);
108 TEST_DONE();
109
110 TEST_START("new/free KEY_RSA1");
111 k1 = sshkey_new(KEY_RSA1);
112 ASSERT_PTR_NE(k1, NULL);
113 ASSERT_PTR_NE(k1->rsa, NULL);
114 ASSERT_PTR_NE(k1->rsa->n, NULL);
115 ASSERT_PTR_NE(k1->rsa->e, NULL);
116 ASSERT_PTR_EQ(k1->rsa->p, NULL);
117 sshkey_free(k1);
118 TEST_DONE();
119
120 TEST_START("new/free KEY_RSA");
121 k1 = sshkey_new(KEY_RSA);
122 ASSERT_PTR_NE(k1, NULL);
123 ASSERT_PTR_NE(k1->rsa, NULL);
124 ASSERT_PTR_NE(k1->rsa->n, NULL);
125 ASSERT_PTR_NE(k1->rsa->e, NULL);
126 ASSERT_PTR_EQ(k1->rsa->p, NULL);
127 sshkey_free(k1);
128 TEST_DONE();
129
130 TEST_START("new/free KEY_DSA");
131 k1 = sshkey_new(KEY_DSA);
132 ASSERT_PTR_NE(k1, NULL);
133 ASSERT_PTR_NE(k1->dsa, NULL);
134 ASSERT_PTR_NE(k1->dsa->g, NULL);
135 ASSERT_PTR_EQ(k1->dsa->priv_key, NULL);
136 sshkey_free(k1);
137 TEST_DONE();
138
139 TEST_START("new/free KEY_ECDSA");
140 k1 = sshkey_new(KEY_ECDSA);
141 ASSERT_PTR_NE(k1, NULL);
142 ASSERT_PTR_EQ(k1->ecdsa, NULL); /* Can't allocate without NID */
143 sshkey_free(k1);
144 TEST_DONE();
145
146 TEST_START("new/free KEY_ED25519");
147 k1 = sshkey_new(KEY_ED25519);
148 ASSERT_PTR_NE(k1, NULL);
149 /* These should be blank until key loaded or generated */
150 ASSERT_PTR_EQ(k1->ed25519_sk, NULL);
151 ASSERT_PTR_EQ(k1->ed25519_pk, NULL);
152 sshkey_free(k1);
153 TEST_DONE();
154
155 TEST_START("new_private KEY_RSA");
156 k1 = sshkey_new_private(KEY_RSA);
157 ASSERT_PTR_NE(k1, NULL);
158 ASSERT_PTR_NE(k1->rsa, NULL);
159 ASSERT_PTR_NE(k1->rsa->n, NULL);
160 ASSERT_PTR_NE(k1->rsa->e, NULL);
161 ASSERT_PTR_NE(k1->rsa->p, NULL);
162 ASSERT_INT_EQ(sshkey_add_private(k1), 0);
163 sshkey_free(k1);
164 TEST_DONE();
165
166 TEST_START("new_private KEY_DSA");
167 k1 = sshkey_new_private(KEY_DSA);
168 ASSERT_PTR_NE(k1, NULL);
169 ASSERT_PTR_NE(k1->dsa, NULL);
170 ASSERT_PTR_NE(k1->dsa->g, NULL);
171 ASSERT_PTR_NE(k1->dsa->priv_key, NULL);
172 ASSERT_INT_EQ(sshkey_add_private(k1), 0);
173 sshkey_free(k1);
174 TEST_DONE();
175
176 TEST_START("generate KEY_RSA too small modulus");
177 ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 128, &k1),
178 SSH_ERR_INVALID_ARGUMENT);
179 ASSERT_PTR_EQ(k1, NULL);
180 TEST_DONE();
181
182 TEST_START("generate KEY_RSA too large modulus");
183 ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 1 << 20, &k1),
184 SSH_ERR_INVALID_ARGUMENT);
185 ASSERT_PTR_EQ(k1, NULL);
186 TEST_DONE();
187
188 TEST_START("generate KEY_DSA wrong bits");
189 ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 2048, &k1),
190 SSH_ERR_INVALID_ARGUMENT);
191 ASSERT_PTR_EQ(k1, NULL);
192 sshkey_free(k1);
193 TEST_DONE();
194
195 TEST_START("generate KEY_ECDSA wrong bits");
196 ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 42, &k1),
197 SSH_ERR_INVALID_ARGUMENT);
198 ASSERT_PTR_EQ(k1, NULL);
199 sshkey_free(k1);
200 TEST_DONE();
201
202 TEST_START("generate KEY_RSA");
203 ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 768, &kr), 0);
204 ASSERT_PTR_NE(kr, NULL);
205 ASSERT_PTR_NE(kr->rsa, NULL);
206 ASSERT_PTR_NE(kr->rsa->n, NULL);
207 ASSERT_PTR_NE(kr->rsa->e, NULL);
208 ASSERT_PTR_NE(kr->rsa->p, NULL);
209 ASSERT_INT_EQ(BN_num_bits(kr->rsa->n), 768);
210 TEST_DONE();
211
212 TEST_START("generate KEY_DSA");
213 ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &kd), 0);
214 ASSERT_PTR_NE(kd, NULL);
215 ASSERT_PTR_NE(kd->dsa, NULL);
216 ASSERT_PTR_NE(kd->dsa->g, NULL);
217 ASSERT_PTR_NE(kd->dsa->priv_key, NULL);
218 TEST_DONE();
219
220#ifdef OPENSSL_HAS_ECC
221 TEST_START("generate KEY_ECDSA");
222 ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &ke), 0);
223 ASSERT_PTR_NE(ke, NULL);
224 ASSERT_PTR_NE(ke->ecdsa, NULL);
225 ASSERT_PTR_NE(EC_KEY_get0_public_key(ke->ecdsa), NULL);
226 ASSERT_PTR_NE(EC_KEY_get0_private_key(ke->ecdsa), NULL);
227 TEST_DONE();
228#endif
229
230 TEST_START("generate KEY_ED25519");
231 ASSERT_INT_EQ(sshkey_generate(KEY_ED25519, 256, &kf), 0);
232 ASSERT_PTR_NE(kf, NULL);
233 ASSERT_INT_EQ(kf->type, KEY_ED25519);
234 ASSERT_PTR_NE(kf->ed25519_pk, NULL);
235 ASSERT_PTR_NE(kf->ed25519_sk, NULL);
236 TEST_DONE();
237
238 TEST_START("demote KEY_RSA");
239 ASSERT_INT_EQ(sshkey_demote(kr, &k1), 0);
240 ASSERT_PTR_NE(k1, NULL);
241 ASSERT_PTR_NE(kr, k1);
242 ASSERT_INT_EQ(k1->type, KEY_RSA);
243 ASSERT_PTR_NE(k1->rsa, NULL);
244 ASSERT_PTR_NE(k1->rsa->n, NULL);
245 ASSERT_PTR_NE(k1->rsa->e, NULL);
246 ASSERT_PTR_EQ(k1->rsa->p, NULL);
247 TEST_DONE();
248
249 TEST_START("equal KEY_RSA/demoted KEY_RSA");
250 ASSERT_INT_EQ(sshkey_equal(kr, k1), 1);
251 sshkey_free(k1);
252 TEST_DONE();
253
254 TEST_START("demote KEY_DSA");
255 ASSERT_INT_EQ(sshkey_demote(kd, &k1), 0);
256 ASSERT_PTR_NE(k1, NULL);
257 ASSERT_PTR_NE(kd, k1);
258 ASSERT_INT_EQ(k1->type, KEY_DSA);
259 ASSERT_PTR_NE(k1->dsa, NULL);
260 ASSERT_PTR_NE(k1->dsa->g, NULL);
261 ASSERT_PTR_EQ(k1->dsa->priv_key, NULL);
262 TEST_DONE();
263
264 TEST_START("equal KEY_DSA/demoted KEY_DSA");
265 ASSERT_INT_EQ(sshkey_equal(kd, k1), 1);
266 sshkey_free(k1);
267 TEST_DONE();
268
269#ifdef OPENSSL_HAS_ECC
270 TEST_START("demote KEY_ECDSA");
271 ASSERT_INT_EQ(sshkey_demote(ke, &k1), 0);
272 ASSERT_PTR_NE(k1, NULL);
273 ASSERT_PTR_NE(ke, k1);
274 ASSERT_INT_EQ(k1->type, KEY_ECDSA);
275 ASSERT_PTR_NE(k1->ecdsa, NULL);
276 ASSERT_INT_EQ(k1->ecdsa_nid, ke->ecdsa_nid);
277 ASSERT_PTR_NE(EC_KEY_get0_public_key(ke->ecdsa), NULL);
278 ASSERT_PTR_EQ(EC_KEY_get0_private_key(k1->ecdsa), NULL);
279 TEST_DONE();
280
281 TEST_START("equal KEY_ECDSA/demoted KEY_ECDSA");
282 ASSERT_INT_EQ(sshkey_equal(ke, k1), 1);
283 sshkey_free(k1);
284 TEST_DONE();
285#endif
286
287 TEST_START("demote KEY_ED25519");
288 ASSERT_INT_EQ(sshkey_demote(kf, &k1), 0);
289 ASSERT_PTR_NE(k1, NULL);
290 ASSERT_PTR_NE(kf, k1);
291 ASSERT_INT_EQ(k1->type, KEY_ED25519);
292 ASSERT_PTR_NE(k1->ed25519_pk, NULL);
293 ASSERT_PTR_EQ(k1->ed25519_sk, NULL);
294 TEST_DONE();
295
296 TEST_START("equal KEY_ED25519/demoted KEY_ED25519");
297 ASSERT_INT_EQ(sshkey_equal(kf, k1), 1);
298 sshkey_free(k1);
299 TEST_DONE();
300
301 TEST_START("equal mismatched key types");
302 ASSERT_INT_EQ(sshkey_equal(kd, kr), 0);
303#ifdef OPENSSL_HAS_ECC
304 ASSERT_INT_EQ(sshkey_equal(kd, ke), 0);
305 ASSERT_INT_EQ(sshkey_equal(kr, ke), 0);
306 ASSERT_INT_EQ(sshkey_equal(ke, kf), 0);
307#endif
308 ASSERT_INT_EQ(sshkey_equal(kd, kf), 0);
309 TEST_DONE();
310
311 TEST_START("equal different keys");
312 ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 768, &k1), 0);
313 ASSERT_INT_EQ(sshkey_equal(kr, k1), 0);
314 sshkey_free(k1);
315 ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &k1), 0);
316 ASSERT_INT_EQ(sshkey_equal(kd, k1), 0);
317 sshkey_free(k1);
318#ifdef OPENSSL_HAS_ECC
319 ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &k1), 0);
320 ASSERT_INT_EQ(sshkey_equal(ke, k1), 0);
321 sshkey_free(k1);
322#endif
323 ASSERT_INT_EQ(sshkey_generate(KEY_ED25519, 256, &k1), 0);
324 ASSERT_INT_EQ(sshkey_equal(kf, k1), 0);
325 sshkey_free(k1);
326 TEST_DONE();
327
328 sshkey_free(kr);
329 sshkey_free(kd);
330#ifdef OPENSSL_HAS_ECC
331 sshkey_free(ke);
332#endif
333 sshkey_free(kf);
334
335/* XXX certify test */
336/* XXX sign test */
337/* XXX verify test */
338
339 TEST_START("nested certificate");
340 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k1), 0);
341 ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2,
342 NULL), 0);
343 b = load_file("rsa_2");
344 ASSERT_INT_EQ(sshkey_parse_private_fileblob(b, "", "rsa_1",
345 &k3, NULL), 0);
346 sshbuf_reset(b);
347 build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1);
348 ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k4),
349 SSH_ERR_KEY_CERT_INVALID_SIGN_KEY);
350 ASSERT_PTR_EQ(k4, NULL);
351 sshbuf_free(b);
352 sshkey_free(k1);
353 sshkey_free(k2);
354 sshkey_free(k3);
355 TEST_DONE();
356
357}
diff --git a/regress/unittests/sshkey/testdata/dsa_1 b/regress/unittests/sshkey/testdata/dsa_1
new file mode 100644
index 000000000..34346869f
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1
@@ -0,0 +1,12 @@
1-----BEGIN DSA PRIVATE KEY-----
2MIIBuwIBAAKBgQCxBNwH8TmLXqiZa0b9pxC6W+zS4Voqp8S+QwecYpNPTmhjaUYI
3E/aJWAzFVtdbysLM89ukvw/z8qBkbMSefdypKmjUtgv51ZD4nfV4Wxb+G+1QExHr
4M+kowOOL3XbcsdbPLUt8vxDJbBlQRch4zyai7CWjQR3JFXpR8sevUFJxSQIVAIdE
5oncp2DEY2U/ZZnIyGCwApCzfAoGARW+eewZTv1Eosxv3ANKx372pf5+fQKwnWizI
6j5z/GY3w3xobRCP9FiL4K3Nip2FvHLTGpRrlfm19RWYAg77VsNgztC4V9C8QrKWc
7WJdkUkoQpZ3VoO25rO13hmIelkal3omKCF4ZE/edeF3d2B8DlzYs0aBcjTCMDrub
8/CJILcYCgYEAgJt9jefGQi4Sl5F8h3jYo52LygE8sNYyurElMKVmyhFSKJ1Ifi9j
94hNp2jZzu7jpZWhYndUoPaG6gbRB7fL3p5knlRo3P2Dznd6u6NAdhrADWW+JX9n1
10/EMKUv0h8rRFI/3b9RY1HVVzBQH7V3sNJ6iekH8JqOy1liCMaMylw4gCFBl7Lc6V
11hmTiTuhLXjoRdCZS/p/m
12-----END DSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/dsa_1-cert.fp b/regress/unittests/sshkey/testdata/dsa_1-cert.fp
new file mode 100644
index 000000000..56ee1f89b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1-cert.fp
@@ -0,0 +1 @@
5a:4a:41:8c:4e:fa:4c:52:19:f9:39:49:31:fb:fd:74
diff --git a/regress/unittests/sshkey/testdata/dsa_1-cert.pub b/regress/unittests/sshkey/testdata/dsa_1-cert.pub
new file mode 100644
index 000000000..023edf136
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1-cert.pub
@@ -0,0 +1 @@
ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgj8zueN51MSQ7jW3fFwqyJWA3DycAAavQ8WgMHqcUG7YAAACBALEE3AfxOYteqJlrRv2nELpb7NLhWiqnxL5DB5xik09OaGNpRggT9olYDMVW11vKwszz26S/D/PyoGRsxJ593KkqaNS2C/nVkPid9XhbFv4b7VATEesz6SjA44vddtyx1s8tS3y/EMlsGVBFyHjPJqLsJaNBHckVelHyx69QUnFJAAAAFQCHRKJ3KdgxGNlP2WZyMhgsAKQs3wAAAIBFb557BlO/USizG/cA0rHfval/n59ArCdaLMiPnP8ZjfDfGhtEI/0WIvgrc2KnYW8ctMalGuV+bX1FZgCDvtWw2DO0LhX0LxCspZxYl2RSShClndWg7bms7XeGYh6WRqXeiYoIXhkT9514Xd3YHwOXNizRoFyNMIwOu5v8IkgtxgAAAIEAgJt9jefGQi4Sl5F8h3jYo52LygE8sNYyurElMKVmyhFSKJ1Ifi9j4hNp2jZzu7jpZWhYndUoPaG6gbRB7fL3p5knlRo3P2Dznd6u6NAdhrADWW+JX9n1/EMKUv0h8rRFI/3b9RY1HVVzBQH7V3sNJ6iekH8JqOy1liCMaMylw4gAAAAAAAAABgAAAAIAAAAGanVsaXVzAAAAEgAAAAVob3N0MQAAAAVob3N0MgAAAAA2i4NgAAAAAE0d4eAAAAAAAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAILk95V5J3LKVx8bcLSB4073R7d0aAvR8gJrPvnV0D3MQAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEA6qftqozw0ah9PG9obAg8iOPwQv6AsT9t/1G69eArSd9Am85OKIhAvYguI1Xtr9rw78X/Xk+6HtyAOF3QemaQD dsa_1.pub
diff --git a/regress/unittests/sshkey/testdata/dsa_1.fp b/regress/unittests/sshkey/testdata/dsa_1.fp
new file mode 100644
index 000000000..56ee1f89b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.fp
@@ -0,0 +1 @@
5a:4a:41:8c:4e:fa:4c:52:19:f9:39:49:31:fb:fd:74
diff --git a/regress/unittests/sshkey/testdata/dsa_1.fp.bb b/regress/unittests/sshkey/testdata/dsa_1.fp.bb
new file mode 100644
index 000000000..07dd9b418
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.fp.bb
@@ -0,0 +1 @@
xosat-baneh-gocad-relek-kepur-mibip-motog-bykyb-hisug-mysus-tuxix
diff --git a/regress/unittests/sshkey/testdata/dsa_1.param.g b/regress/unittests/sshkey/testdata/dsa_1.param.g
new file mode 100644
index 000000000..4b09f6d18
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.param.g
@@ -0,0 +1 @@
456f9e7b0653bf5128b31bf700d2b1dfbda97f9f9f40ac275a2cc88f9cff198df0df1a1b4423fd1622f82b7362a7616f1cb4c6a51ae57e6d7d45660083bed5b0d833b42e15f42f10aca59c589764524a10a59dd5a0edb9aced7786621e9646a5de898a085e1913f79d785dddd81f0397362cd1a05c8d308c0ebb9bfc22482dc6
diff --git a/regress/unittests/sshkey/testdata/dsa_1.param.priv b/regress/unittests/sshkey/testdata/dsa_1.param.priv
new file mode 100644
index 000000000..2dd737cbe
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.param.priv
@@ -0,0 +1 @@
197b2dce958664e24ee84b5e3a11742652fe9fe6
diff --git a/regress/unittests/sshkey/testdata/dsa_1.param.pub b/regress/unittests/sshkey/testdata/dsa_1.param.pub
new file mode 100644
index 000000000..b23d7207f
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.param.pub
@@ -0,0 +1 @@
00809b7d8de7c6422e1297917c8778d8a39d8bca013cb0d632bab12530a566ca1152289d487e2f63e21369da3673bbb8e96568589dd5283da1ba81b441edf2f7a79927951a373f60f39ddeaee8d01d86b003596f895fd9f5fc430a52fd21f2b44523fddbf516351d55730501fb577b0d27a89e907f09a8ecb596208c68cca5c388
diff --git a/regress/unittests/sshkey/testdata/dsa_1.pub b/regress/unittests/sshkey/testdata/dsa_1.pub
new file mode 100644
index 000000000..89681970c
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1.pub
@@ -0,0 +1 @@
ssh-dss AAAAB3NzaC1kc3MAAACBALEE3AfxOYteqJlrRv2nELpb7NLhWiqnxL5DB5xik09OaGNpRggT9olYDMVW11vKwszz26S/D/PyoGRsxJ593KkqaNS2C/nVkPid9XhbFv4b7VATEesz6SjA44vddtyx1s8tS3y/EMlsGVBFyHjPJqLsJaNBHckVelHyx69QUnFJAAAAFQCHRKJ3KdgxGNlP2WZyMhgsAKQs3wAAAIBFb557BlO/USizG/cA0rHfval/n59ArCdaLMiPnP8ZjfDfGhtEI/0WIvgrc2KnYW8ctMalGuV+bX1FZgCDvtWw2DO0LhX0LxCspZxYl2RSShClndWg7bms7XeGYh6WRqXeiYoIXhkT9514Xd3YHwOXNizRoFyNMIwOu5v8IkgtxgAAAIEAgJt9jefGQi4Sl5F8h3jYo52LygE8sNYyurElMKVmyhFSKJ1Ifi9j4hNp2jZzu7jpZWhYndUoPaG6gbRB7fL3p5knlRo3P2Dznd6u6NAdhrADWW+JX9n1/EMKUv0h8rRFI/3b9RY1HVVzBQH7V3sNJ6iekH8JqOy1liCMaMylw4g= DSA test key #1
diff --git a/regress/unittests/sshkey/testdata/dsa_1_pw b/regress/unittests/sshkey/testdata/dsa_1_pw
new file mode 100644
index 000000000..1402153a0
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_1_pw
@@ -0,0 +1,15 @@
1-----BEGIN DSA PRIVATE KEY-----
2Proc-Type: 4,ENCRYPTED
3DEK-Info: AES-128-CBC,9E668E24E7B9D658E3E7D0446B32B376
4
5hDjDLbfCAQutblxLuyNzSLxISSgXTgyzq8St9GE0lUtEc7i0xGNWwoWpFSbtD9y1
6yTG5UkhATQt56SY1ABfXZ21wieYuEEQeSJi0gwUQNNt2SwwITx4EdzDedWiHjikt
7jbzH3v33agp/odw2X9wY6zu75y9CeW9o7SszRl286DliWIHJmhMlbb8r7jRqu62H
8s5YYxD0xS1ipWauxklmIXMWNZHcARo8ZiJOuNdLshrSrl8DUW9P6F89FvxclQzKr
944u3OBm7KbgPvPURDFLgNP6uCGBjzHvhHTpzVBxmQzCl3aGgsTKXiwJ1eupNjntB
10ji0EnbznvoxR6qhXxw/WQ+MnWlWqTXka/2qaB6m3oJv+Zn7cPCJ5kvHnhr2JmNMl
11igTh4Ov4LZLyNgO0Lbec4KyxW9QInRV5CY4Pu5lhqHteiPmOIGMWFtuh8Bb8Kg2q
12VvXnPo5I3FjqV7UhDduO1Wn558sBZWQPqRbHVPN6wXJuM3HGkBl+aNjn0qddv9tr
13VFJd/xdly2Ne81g3CB8jysE+3WEOrV9kdybocp/EhSOzP4i6pjWlyWdR5+CgbvRm
14TUIeIaQbmPIB5251o5YK+Q==
15-----END DSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/dsa_2 b/regress/unittests/sshkey/testdata/dsa_2
new file mode 100644
index 000000000..b189dc821
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_2
@@ -0,0 +1,12 @@
1-----BEGIN DSA PRIVATE KEY-----
2MIIBuwIBAAKBgQDoMxCTyBnLPSO7CRU3RyfJLANLKBZ3/LdcsyNaARctaRA5gzRb
3XdTFFU+rWKfxv+otm0KyCOepLtWy8tjKRYb7Ni46USlGwtM0Adx/3vR4iWNfipDP
4K2V4O97JyMe3wsbF7siC01U4b8Ki+J44iFG9nuRnOTHqUWI615mraQRwlQIVAMsX
5nsPGH8QrU11F1ScAIfZC165dAoGACCXyOHFkxABpJDtJs6AE7Hl3XjI4dnlim/XH
6Y60W6gcO7gHSE2r2ljCubJqoUXmxd5mLKgnu91jIG/4URwDM4V7pb2k99sXpAi8I
7L52eQl88C0bRD9+lEJfR4PMT39EccDRPB4+E055RoYQZ/McIyad8sF3Qwt084Eq+
8IkUt2coCgYEAxZRpCY82sM9Mu4B0EcH6O8seRqIRScmelljhUtKxuvf2PChwIWkR
9HK9lORHBE3iKyurC5Muf3abuHKwMFjrOjHKOTqXBRrDZ7RgLQA0aUAQD3lWc9OTP
10NShjphpq5xr0HZB31eJg3/Mo6KxYlRpzMXbTyenZP0XLICSSAywvTDoCFG5whl2k
11Y2FLGfi9V6ylUVH6jKgE
12-----END DSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/dsa_2.fp b/regress/unittests/sshkey/testdata/dsa_2.fp
new file mode 100644
index 000000000..ba9de82a8
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_2.fp
@@ -0,0 +1 @@
72:5f:50:6b:e5:64:c5:62:21:92:3f:8b:10:9b:9f:1a
diff --git a/regress/unittests/sshkey/testdata/dsa_2.fp.bb b/regress/unittests/sshkey/testdata/dsa_2.fp.bb
new file mode 100644
index 000000000..37a5221a7
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_2.fp.bb
@@ -0,0 +1 @@
xesoh-mebaf-feced-lenuz-sicam-pevok-bosak-nogaz-ligen-fekef-fixex
diff --git a/regress/unittests/sshkey/testdata/dsa_2.pub b/regress/unittests/sshkey/testdata/dsa_2.pub
new file mode 100644
index 000000000..6ed2736b1
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_2.pub
@@ -0,0 +1 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAOgzEJPIGcs9I7sJFTdHJ8ksA0soFnf8t1yzI1oBFy1pEDmDNFtd1MUVT6tYp/G/6i2bQrII56ku1bLy2MpFhvs2LjpRKUbC0zQB3H/e9HiJY1+KkM8rZXg73snIx7fCxsXuyILTVThvwqL4njiIUb2e5Gc5MepRYjrXmatpBHCVAAAAFQDLF57Dxh/EK1NdRdUnACH2QteuXQAAAIAIJfI4cWTEAGkkO0mzoATseXdeMjh2eWKb9cdjrRbqBw7uAdITavaWMK5smqhRebF3mYsqCe73WMgb/hRHAMzhXulvaT32xekCLwgvnZ5CXzwLRtEP36UQl9Hg8xPf0RxwNE8Hj4TTnlGhhBn8xwjJp3ywXdDC3TzgSr4iRS3ZygAAAIEAxZRpCY82sM9Mu4B0EcH6O8seRqIRScmelljhUtKxuvf2PChwIWkRHK9lORHBE3iKyurC5Muf3abuHKwMFjrOjHKOTqXBRrDZ7RgLQA0aUAQD3lWc9OTPNShjphpq5xr0HZB31eJg3/Mo6KxYlRpzMXbTyenZP0XLICSSAywvTDo= DSA test key #2
diff --git a/regress/unittests/sshkey/testdata/dsa_n b/regress/unittests/sshkey/testdata/dsa_n
new file mode 100644
index 000000000..34346869f
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_n
@@ -0,0 +1,12 @@
1-----BEGIN DSA PRIVATE KEY-----
2MIIBuwIBAAKBgQCxBNwH8TmLXqiZa0b9pxC6W+zS4Voqp8S+QwecYpNPTmhjaUYI
3E/aJWAzFVtdbysLM89ukvw/z8qBkbMSefdypKmjUtgv51ZD4nfV4Wxb+G+1QExHr
4M+kowOOL3XbcsdbPLUt8vxDJbBlQRch4zyai7CWjQR3JFXpR8sevUFJxSQIVAIdE
5oncp2DEY2U/ZZnIyGCwApCzfAoGARW+eewZTv1Eosxv3ANKx372pf5+fQKwnWizI
6j5z/GY3w3xobRCP9FiL4K3Nip2FvHLTGpRrlfm19RWYAg77VsNgztC4V9C8QrKWc
7WJdkUkoQpZ3VoO25rO13hmIelkal3omKCF4ZE/edeF3d2B8DlzYs0aBcjTCMDrub
8/CJILcYCgYEAgJt9jefGQi4Sl5F8h3jYo52LygE8sNYyurElMKVmyhFSKJ1Ifi9j
94hNp2jZzu7jpZWhYndUoPaG6gbRB7fL3p5knlRo3P2Dznd6u6NAdhrADWW+JX9n1
10/EMKUv0h8rRFI/3b9RY1HVVzBQH7V3sNJ6iekH8JqOy1liCMaMylw4gCFBl7Lc6V
11hmTiTuhLXjoRdCZS/p/m
12-----END DSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/dsa_n_pw b/regress/unittests/sshkey/testdata/dsa_n_pw
new file mode 100644
index 000000000..42f70dd23
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/dsa_n_pw
@@ -0,0 +1,22 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABD5nB+Nkw
3LNoPtAG7C3IdXmAAAAEAAAAAEAAAGyAAAAB3NzaC1kc3MAAACBALEE3AfxOYteqJlrRv2n
4ELpb7NLhWiqnxL5DB5xik09OaGNpRggT9olYDMVW11vKwszz26S/D/PyoGRsxJ593KkqaN
5S2C/nVkPid9XhbFv4b7VATEesz6SjA44vddtyx1s8tS3y/EMlsGVBFyHjPJqLsJaNBHckV
6elHyx69QUnFJAAAAFQCHRKJ3KdgxGNlP2WZyMhgsAKQs3wAAAIBFb557BlO/USizG/cA0r
7Hfval/n59ArCdaLMiPnP8ZjfDfGhtEI/0WIvgrc2KnYW8ctMalGuV+bX1FZgCDvtWw2DO0
8LhX0LxCspZxYl2RSShClndWg7bms7XeGYh6WRqXeiYoIXhkT9514Xd3YHwOXNizRoFyNMI
9wOu5v8IkgtxgAAAIEAgJt9jefGQi4Sl5F8h3jYo52LygE8sNYyurElMKVmyhFSKJ1Ifi9j
104hNp2jZzu7jpZWhYndUoPaG6gbRB7fL3p5knlRo3P2Dznd6u6NAdhrADWW+JX9n1/EMKUv
110h8rRFI/3b9RY1HVVzBQH7V3sNJ6iekH8JqOy1liCMaMylw4gAAAHw8P1DtkBulOGv85qf
12P+md2+LL+NKufVzHl9k2UKQFjeqY6uqs4HSDqvhXe7oiXd5mz6I7orxjtKU9hGjNF4ABUD
13OawVGe/GCRUQ4WgpAgDnqQLeFcdIwtMSIrRZU6xjs314EI7TM7IIiG26JEuXDfZI1e7C3y
14Cc38ZsP3zmg/UjgcCQar5c4n++vhOmeO36+fcUyZ1QlR05SaEtFYJA+otP3RmKTiDwob8Q
15zRMr8Y57i2NTTtFjkmnnnQCibP62yz7N22Dve7RTOH8jiaW7p02Vn/6WmCarevN1rxtLLR
16lkuWtPoKY8z/Ktcev8YE9f2+9H2TfXDRKYqIEfxgZLCJ4yP2gxDe6zurabS0hAO1CP+ej5
17htdJM3/rTqHAIevXX5uhIDmMvRHnLGldaIX1xux8TIJvSfMkYNIwscIP4kx7BGMk04vXtW
185DLm6IZhzw9T3hjr8R0kBugmT6/h9vD5iN1D+wiHIhHYzQKMU9nOeFNsMBFWgJjU0l8VlF
19gEjEMgAEfwynnmIoKB1iA/0em1tdU3naS59DBK+buE0trxUpTAAB5z8yPhAm6DdqrPE8cA
20N3HlMoWrbCuak2A0uyOlEJjPg4UJUnv12ve2c9pAMsAu/4CAszCEM0prR+qd/RA4nn4M5u
21Xrny2wNtt/DybCkA==
22-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1 b/regress/unittests/sshkey/testdata/ecdsa_1
new file mode 100644
index 000000000..aec73dd61
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1
@@ -0,0 +1,5 @@
1-----BEGIN EC PRIVATE KEY-----
2MHcCAQEEIFghsFR1K95tz8qOl3+tX6fv8a/O6AfNbxOSFZX3ihxooAoGCCqGSM49
3AwEHoUQDQgAEalpgP0BOePHtTw0Pus4tdhTb8P9yWUZluvLf1D8vrHImT+G4vr/W
4xo5iXGKQVEifuUVyLkAW2kDrq8J/szeRiQ==
5-----END EC PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1-cert.fp b/regress/unittests/sshkey/testdata/ecdsa_1-cert.fp
new file mode 100644
index 000000000..a56dbc8d0
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1-cert.fp
@@ -0,0 +1 @@
f7:be:4c:02:65:ed:4c:11:af:ab:a8:dd:0a:92:e7:44
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1-cert.pub b/regress/unittests/sshkey/testdata/ecdsa_1-cert.pub
new file mode 100644
index 000000000..29b06a4dd
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1-cert.pub
@@ -0,0 +1 @@
ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgjpoHehzmM54xz776HOiTOLPhkOwSWyXOMYeqDhDEcLgAAAAIbmlzdHAyNTYAAABBBGpaYD9ATnjx7U8ND7rOLXYU2/D/cllGZbry39Q/L6xyJk/huL6/1saOYlxikFRIn7lFci5AFtpA66vCf7M3kYkAAAAAAAAABwAAAAIAAAAGanVsaXVzAAAAEgAAAAVob3N0MQAAAAVob3N0MgAAAAA2i4NgAAAAAE0d4eAAAAAAAAAAAAAAAAAAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGpaYD9ATnjx7U8ND7rOLXYU2/D/cllGZbry39Q/L6xyJk/huL6/1saOYlxikFRIn7lFci5AFtpA66vCf7M3kYkAAABjAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAABIAAAAIFZM1PXlXf0a3VuGs7MVdWSealDXprT1nN5hQTg+m+EYAAAAIGN1yNXWEY5V315NhOD3mBuh/xCpfDn5rZjF4YntA7du ecdsa_1.pub
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.fp b/regress/unittests/sshkey/testdata/ecdsa_1.fp
new file mode 100644
index 000000000..a56dbc8d0
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.fp
@@ -0,0 +1 @@
f7:be:4c:02:65:ed:4c:11:af:ab:a8:dd:0a:92:e7:44
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.fp.bb b/regress/unittests/sshkey/testdata/ecdsa_1.fp.bb
new file mode 100644
index 000000000..f01a5dd44
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.fp.bb
@@ -0,0 +1 @@
xotah-hecal-zibyb-nadug-romuc-hator-venum-hobip-ruluh-ripus-naxix
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.param.curve b/regress/unittests/sshkey/testdata/ecdsa_1.param.curve
new file mode 100644
index 000000000..fa0400467
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.param.curve
@@ -0,0 +1 @@
prime256v1
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.param.priv b/regress/unittests/sshkey/testdata/ecdsa_1.param.priv
new file mode 100644
index 000000000..3475f1fe9
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.param.priv
@@ -0,0 +1 @@
5821b054752bde6dcfca8e977fad5fa7eff1afcee807cd6f13921595f78a1c68
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.param.pub b/regress/unittests/sshkey/testdata/ecdsa_1.param.pub
new file mode 100644
index 000000000..11847a394
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.param.pub
@@ -0,0 +1 @@
046a5a603f404e78f1ed4f0d0fbace2d7614dbf0ff72594665baf2dfd43f2fac72264fe1b8bebfd6c68e625c629054489fb945722e4016da40ebabc27fb3379189
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1.pub b/regress/unittests/sshkey/testdata/ecdsa_1.pub
new file mode 100644
index 000000000..eca1620bc
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1.pub
@@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGpaYD9ATnjx7U8ND7rOLXYU2/D/cllGZbry39Q/L6xyJk/huL6/1saOYlxikFRIn7lFci5AFtpA66vCf7M3kYk= ECDSA test key #1
diff --git a/regress/unittests/sshkey/testdata/ecdsa_1_pw b/regress/unittests/sshkey/testdata/ecdsa_1_pw
new file mode 100644
index 000000000..071154ab2
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_1_pw
@@ -0,0 +1,8 @@
1-----BEGIN EC PRIVATE KEY-----
2Proc-Type: 4,ENCRYPTED
3DEK-Info: AES-128-CBC,74C8AEA5BFAFCC2B1C8B13DE671F5610
4
5vUsgOvCqezxPmcZcFqrSy9Y1MMlVguY0h9cfSPFC7gUrRr+45uCOYX5bOwEXecKn
6/9uCXZtlBwwqDS9iK5IPoUrjEHvzI5rVbHWUxDrEOVbsfiDuCxrQM19It6QIqC1v
7OSQEdXuBWR5WmhKNc3dqLbWsU8u2s60YwKQmZrj9nM4=
8-----END EC PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2 b/regress/unittests/sshkey/testdata/ecdsa_2
new file mode 100644
index 000000000..76ae07ad4
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2
@@ -0,0 +1,7 @@
1-----BEGIN EC PRIVATE KEY-----
2MIHcAgEBBEIBg4kVxUfoo/RE/78/QBRqG6PZuHZ82eLnhmZVzBa7XREUiYI/Jw7r
3Qwp4FTBVfXL76Pt5AyBMf+52aVeOUlLRERSgBwYFK4EEACOhgYkDgYYABACNTJ5O
4uNo5dNgIQRLHzKU91m7immKFiutJ6BlDbkRkKr+Envj13J6HOgYvOTm0n7SPlKHS
5STZ4/T36d/rzQOAbIwEnbbwD9HMj6IzE4WH9lJzH7Zy7Tcyu6dOM8L7nOxCp3DUk
6F3aAnPSFJhD7NN0jBWOFsD6uy1OmaTklPfRAnCt1MQ==
7-----END EC PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.fp b/regress/unittests/sshkey/testdata/ecdsa_2.fp
new file mode 100644
index 000000000..eb4bbdf03
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.fp
@@ -0,0 +1 @@
51:bd:ff:2b:6d:26:9b:90:f9:e1:4a:ca:a0:29:8e:70
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.fp.bb b/regress/unittests/sshkey/testdata/ecdsa_2.fp.bb
new file mode 100644
index 000000000..267bc63fd
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.fp.bb
@@ -0,0 +1 @@
xuzaz-zuzuk-virop-vypah-zumel-gylak-selih-fevad-varag-zynif-haxox
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.param.curve b/regress/unittests/sshkey/testdata/ecdsa_2.param.curve
new file mode 100644
index 000000000..617ea2fb8
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.param.curve
@@ -0,0 +1 @@
secp521r1
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.param.priv b/regress/unittests/sshkey/testdata/ecdsa_2.param.priv
new file mode 100644
index 000000000..537cdaac3
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.param.priv
@@ -0,0 +1 @@
01838915c547e8a3f444ffbf3f40146a1ba3d9b8767cd9e2e7866655cc16bb5d111489823f270eeb430a781530557d72fbe8fb7903204c7fee7669578e5252d11114
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.param.pub b/regress/unittests/sshkey/testdata/ecdsa_2.param.pub
new file mode 100644
index 000000000..3352ac769
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.param.pub
@@ -0,0 +1 @@
04008d4c9e4eb8da3974d8084112c7cca53dd66ee29a62858aeb49e819436e44642abf849ef8f5dc9e873a062f3939b49fb48f94a1d2493678fd3dfa77faf340e01b2301276dbc03f47323e88cc4e161fd949cc7ed9cbb4dccaee9d38cf0bee73b10a9dc35241776809cf4852610fb34dd23056385b03eaecb53a66939253df4409c2b7531
diff --git a/regress/unittests/sshkey/testdata/ecdsa_2.pub b/regress/unittests/sshkey/testdata/ecdsa_2.pub
new file mode 100644
index 000000000..34e1881dd
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_2.pub
@@ -0,0 +1 @@
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACNTJ5OuNo5dNgIQRLHzKU91m7immKFiutJ6BlDbkRkKr+Envj13J6HOgYvOTm0n7SPlKHSSTZ4/T36d/rzQOAbIwEnbbwD9HMj6IzE4WH9lJzH7Zy7Tcyu6dOM8L7nOxCp3DUkF3aAnPSFJhD7NN0jBWOFsD6uy1OmaTklPfRAnCt1MQ== ECDSA test key #2
diff --git a/regress/unittests/sshkey/testdata/ecdsa_n b/regress/unittests/sshkey/testdata/ecdsa_n
new file mode 100644
index 000000000..aec73dd61
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_n
@@ -0,0 +1,5 @@
1-----BEGIN EC PRIVATE KEY-----
2MHcCAQEEIFghsFR1K95tz8qOl3+tX6fv8a/O6AfNbxOSFZX3ihxooAoGCCqGSM49
3AwEHoUQDQgAEalpgP0BOePHtTw0Pus4tdhTb8P9yWUZluvLf1D8vrHImT+G4vr/W
4xo5iXGKQVEifuUVyLkAW2kDrq8J/szeRiQ==
5-----END EC PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_n_pw b/regress/unittests/sshkey/testdata/ecdsa_n_pw
new file mode 100644
index 000000000..75d585908
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_n_pw
@@ -0,0 +1,9 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABBXqI6Z6o
3uRM+jAwdhnDoIMAAAAEAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz
4dHAyNTYAAABBBGpaYD9ATnjx7U8ND7rOLXYU2/D/cllGZbry39Q/L6xyJk/huL6/1saOYl
5xikFRIn7lFci5AFtpA66vCf7M3kYkAAACwYMnoCTqvUTG0ktSSMNsOZLCdal5J4avEpM1L
6sV9SL/RVcwo3ChprhwsnQsaAtMiJCRcHerKgD9qy1MNNaE5VNfVJ0Ih/7ut04cbFKed8p6
70V+w8WP7WvFffBPoHn+GGbQd1FDGzHhXUB61pH8Qzd1bI/sld/XEtMk7iYjNGQe9Rt0RaK
8Wi8trwaA0Fb2w/EFnrdsFFxrIhQEqYBdEQJo782IqAsMG9OwUaM0vy+8bcI=
9-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ed25519_1 b/regress/unittests/sshkey/testdata/ed25519_1
new file mode 100644
index 000000000..a537ae13d
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1
@@ -0,0 +1,7 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
3QyNTUxOQAAACC5PeVeSdyylcfG3C0geNO90e3dGgL0fICaz751dA9zEAAAAJglsAcYJbAH
4GAAAAAtzc2gtZWQyNTUxOQAAACC5PeVeSdyylcfG3C0geNO90e3dGgL0fICaz751dA9zEA
5AAAED6HJ8Bh8tdQvhMd5o8IxtIwBv8/FV48FpBFWAbYdsIsLk95V5J3LKVx8bcLSB4073R
67d0aAvR8gJrPvnV0D3MQAAAAE0VEMjU1MTkgdGVzdCBrZXkgIzEBAg==
7-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ed25519_1-cert.fp b/regress/unittests/sshkey/testdata/ed25519_1-cert.fp
new file mode 100644
index 000000000..e6d23d0b8
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1-cert.fp
@@ -0,0 +1 @@
19:08:8e:7e:4d:e5:de:86:2a:09:47:65:eb:0a:51:2f
diff --git a/regress/unittests/sshkey/testdata/ed25519_1-cert.pub b/regress/unittests/sshkey/testdata/ed25519_1-cert.pub
new file mode 100644
index 000000000..ad0b9a888
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1-cert.pub
@@ -0,0 +1 @@
ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIHmdL66MkkOvncpc0W4MdvlJZMfQthHiOUv+XKm7gvzOAAAAILk95V5J3LKVx8bcLSB4073R7d0aAvR8gJrPvnV0D3MQAAAAAAAAAAgAAAACAAAABmp1bGl1cwAAABIAAAAFaG9zdDEAAAAFaG9zdDIAAAAANouDYAAAAABNHeHgAAAAAAAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACC5PeVeSdyylcfG3C0geNO90e3dGgL0fICaz751dA9zEAAAAFMAAAALc3NoLWVkMjU1MTkAAABAsUStKm1z3Rtvwy3eXE1DrgVp6kix2iEQXfB66IHX2UpAj5yl0eQGXWTSEDIxHDIb0SJvUH43OWX0PrEeAs0mAA== ed25519_1.pub
diff --git a/regress/unittests/sshkey/testdata/ed25519_1.fp b/regress/unittests/sshkey/testdata/ed25519_1.fp
new file mode 100644
index 000000000..e6d23d0b8
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1.fp
@@ -0,0 +1 @@
19:08:8e:7e:4d:e5:de:86:2a:09:47:65:eb:0a:51:2f
diff --git a/regress/unittests/sshkey/testdata/ed25519_1.fp.bb b/regress/unittests/sshkey/testdata/ed25519_1.fp.bb
new file mode 100644
index 000000000..591a711b4
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1.fp.bb
@@ -0,0 +1 @@
xofip-nuhoh-botam-cypeg-panig-tunef-bimav-numeb-nikic-gocyf-paxax
diff --git a/regress/unittests/sshkey/testdata/ed25519_1.pub b/regress/unittests/sshkey/testdata/ed25519_1.pub
new file mode 100644
index 000000000..633e05077
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1.pub
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILk95V5J3LKVx8bcLSB4073R7d0aAvR8gJrPvnV0D3MQ ED25519 test key #1
diff --git a/regress/unittests/sshkey/testdata/ed25519_1_pw b/regress/unittests/sshkey/testdata/ed25519_1_pw
new file mode 100644
index 000000000..9fc635208
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_1_pw
@@ -0,0 +1,8 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABAlT1eewp
39gl0gue+sSrBWKAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAILk95V5J3LKVx8bc
4LSB4073R7d0aAvR8gJrPvnV0D3MQAAAAoMrL9ixIQHoJ86DcKMGt26+bCeaoyGjW5hha2Y
5IxAZ+rRvNjUuv3MGvbUxtUpPZkTP/vk2fVSCuCD9St5Lbt/LKdIk2MfWIFbjZ6iEfdzxz0
6DHmsSDMps8dbePqqIPULR8av447jEzQEkUc8GSR6WqFSJOjJ8OvrJat1KcEK7V2tjZnLS1
7GoLMqVAtCVhuXwUkeJiRQE/JRl172hxB+LAVw=
8-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ed25519_2 b/regress/unittests/sshkey/testdata/ed25519_2
new file mode 100644
index 000000000..a6e5f0040
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_2
@@ -0,0 +1,7 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
3QyNTUxOQAAACBXUfO5Kid+jhRnyVt+1r9wj2FN/mZ6RfgGdySeYoq4WAAAAJjGeKsZxnir
4GQAAAAtzc2gtZWQyNTUxOQAAACBXUfO5Kid+jhRnyVt+1r9wj2FN/mZ6RfgGdySeYoq4WA
5AAAEB+gn4gGClQl2WMeOkikY+w0A0kSw1KH4Oyami7hlypsFdR87kqJ36OFGfJW37Wv3CP
6YU3+ZnpF+AZ3JJ5iirhYAAAAE0VEMjU1MTkgdGVzdCBrZXkgIzEBAg==
7-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ed25519_2.fp b/regress/unittests/sshkey/testdata/ed25519_2.fp
new file mode 100644
index 000000000..02c684f36
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_2.fp
@@ -0,0 +1 @@
5c:c9:ae:a3:0c:aa:28:29:b8:fc:7c:64:ba:6e:e9:c9
diff --git a/regress/unittests/sshkey/testdata/ed25519_2.fp.bb b/regress/unittests/sshkey/testdata/ed25519_2.fp.bb
new file mode 100644
index 000000000..ebe782e2c
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_2.fp.bb
@@ -0,0 +1 @@
xenoz-tovup-zecyt-hohar-motam-sugid-fecyz-tutyk-gosom-ginar-kixux
diff --git a/regress/unittests/sshkey/testdata/ed25519_2.pub b/regress/unittests/sshkey/testdata/ed25519_2.pub
new file mode 100644
index 000000000..37b93352a
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_2.pub
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFdR87kqJ36OFGfJW37Wv3CPYU3+ZnpF+AZ3JJ5iirhY ED25519 test key #1
diff --git a/regress/unittests/sshkey/testdata/pw b/regress/unittests/sshkey/testdata/pw
new file mode 100644
index 000000000..8a1dff98a
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/pw
@@ -0,0 +1 @@
mekmitasdigoat
diff --git a/regress/unittests/sshkey/testdata/rsa1_1 b/regress/unittests/sshkey/testdata/rsa1_1
new file mode 100644
index 000000000..d22014e88
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1
Binary files differ
diff --git a/regress/unittests/sshkey/testdata/rsa1_1.fp b/regress/unittests/sshkey/testdata/rsa1_1.fp
new file mode 100644
index 000000000..782ece0db
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1.fp
@@ -0,0 +1 @@
a8:82:9b:98:c5:e6:19:d6:83:39:9f:4d:3a:8f:7c:80
diff --git a/regress/unittests/sshkey/testdata/rsa1_1.fp.bb b/regress/unittests/sshkey/testdata/rsa1_1.fp.bb
new file mode 100644
index 000000000..caaf9511a
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1.fp.bb
@@ -0,0 +1 @@
xukib-cymuf-mylib-kecih-rogyb-sorid-belys-kytem-dinin-cicil-kyxex
diff --git a/regress/unittests/sshkey/testdata/rsa1_1.param.n b/regress/unittests/sshkey/testdata/rsa1_1.param.n
new file mode 100644
index 000000000..4ceb37362
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1.param.n
@@ -0,0 +1 @@
00cf68059e5c7743318d740d3ebb55eb577891c9c3098817703f4c3157285055c2daa50102509ebdcade324e541c965e2931fd3459052fe65d013722da805d7ec8ef5b97cc006789d0566c5578b23e7aaa5be2b055d85798030cdead2eb2cc4eb3
diff --git a/regress/unittests/sshkey/testdata/rsa1_1.pub b/regress/unittests/sshkey/testdata/rsa1_1.pub
new file mode 100644
index 000000000..56cf30d30
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1.pub
@@ -0,0 +1 @@
768 65537 1257820658919101781627826212425999371251377782154008557690434337796299274692579921603319269571889066123773172648045269780061837011867522525764583065919572648969392756890567918758763032103894830246827894023662422727333291801518558899 RSA1 test key #1
diff --git a/regress/unittests/sshkey/testdata/rsa1_1_pw b/regress/unittests/sshkey/testdata/rsa1_1_pw
new file mode 100644
index 000000000..3113dbc0f
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_1_pw
Binary files differ
diff --git a/regress/unittests/sshkey/testdata/rsa1_2 b/regress/unittests/sshkey/testdata/rsa1_2
new file mode 100644
index 000000000..e75e665ff
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_2
Binary files differ
diff --git a/regress/unittests/sshkey/testdata/rsa1_2.fp b/regress/unittests/sshkey/testdata/rsa1_2.fp
new file mode 100644
index 000000000..c3325371d
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_2.fp
@@ -0,0 +1 @@
c0:83:1c:97:5f:32:77:7e:e4:e3:e9:29:b9:eb:76:9c
diff --git a/regress/unittests/sshkey/testdata/rsa1_2.fp.bb b/regress/unittests/sshkey/testdata/rsa1_2.fp.bb
new file mode 100644
index 000000000..cd8037140
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_2.fp.bb
@@ -0,0 +1 @@
xifad-vevot-sozyl-fapeb-meryf-kylut-cydiv-firik-gavyb-lanad-kaxox
diff --git a/regress/unittests/sshkey/testdata/rsa1_2.param.n b/regress/unittests/sshkey/testdata/rsa1_2.param.n
new file mode 100644
index 000000000..f8143a4b9
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_2.param.n
@@ -0,0 +1 @@
00b08a9fa386aceaab2ec3e9cdc7e6cb4eac9e98620279eed6762e1f513739a417ac8a86231fad3b8727a9de994973a7aae674a132547341984ade91aa1c22f01d2f0204ea7fa121969c367a5d04bda384066cf94e0b56d1efc47f50ca28e90603547df41c0676550d82d369f699b457d4f0f077999d9e76ab679fbf4206d418dbabed1823f14e4ddf3aac987686e6b006f8a23ea6af13b4c0e5b1fb5b1eb4db2f47b229422c450574cae9c64db5dcfce050836b6bdfa8fb541b4d426444a5ea20ad51a25d3048414ced2e199da2997968273e8beb10f3a351e98a57b00dadfa8f00a39bb55be94dae898fda6021d728f32b2ec93edd16e51073be3ac7511e5085
diff --git a/regress/unittests/sshkey/testdata/rsa1_2.pub b/regress/unittests/sshkey/testdata/rsa1_2.pub
new file mode 100644
index 000000000..de1afbb8b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa1_2.pub
@@ -0,0 +1 @@
2048 65537 22286299513474010485021611215236051675183880694440075228245854420062562171290421803318459093678819161498086077099067169041536315773126601869537036602014639497662916952995546870691495931205282427606841521014293638607226118353743812583642616889028731910222603216563207637006843580936568089467160095319593442255227365472917576488012409542775346105980501967996562422764758836868135158147777193940857952623773420292946843206784104932927528915610322518810753953608862466374219925252817405397507396462117715293725218947744085154122395590957537510003558169729949140038634486299736757269280065662263306737701939154762092925061 RSA1 test key #2
diff --git a/regress/unittests/sshkey/testdata/rsa_1 b/regress/unittests/sshkey/testdata/rsa_1
new file mode 100644
index 000000000..09e79a72e
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1
@@ -0,0 +1,12 @@
1-----BEGIN RSA PRIVATE KEY-----
2MIIBywIBAAJhAM/6MDmVVm/uNQmZpOcthoAAgMDUg7G4H6ZLLyPEhboKaBBHvIdw
3ZdDmB+0LDf3D1aWXyUd2/pCkCysiBzqd/523zAzjY7HayqL6A940AxKBBbWLn+X6
4i2yJR7dTOYkk6QIDAQABAmAgKanBjfWzE5yCIo+c7K5rJyjCKVtAZaAHYIMmveKM
5VcWoFt/x9hDY0GoTX21HfDxLX8oDxnsmhsOrnvSmgUChFwkm45eSETqeVDWwIVFA
6FGL1s38xQsciWZWBFNppAIECMQD7nslReAxwz/Ad++ACXswfJg1l2wUQ1gJA3zh3
7jln6a4s3aV1zxbKlIn8iqBv0BZkCMQDTmO4WqyNnin73XCZs0DWu7GsfcuaH8QnD
8wqPjJgrclTZXedxHkeqO2oyZW4mLC9ECMBb/blsZ49kzyDiVWuYcj/+Q1MyodhAR
932bagCi9RBAVYEYSRU5dlXRucLxULSnikQIxAJ5teY5Vcru6kZfJUifUuO0QrKAu
10WnbcPVBqMmUHfchsm/RhFFIt6W4uKmlEhTYrkQIxAMAStb7QCU3yU6ZkN7uL22Zs
11498i4jY6y+VEXv+L9O09VdlEnXhbUisOhy1bhyS3yg==
12-----END RSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/rsa_1-cert.fp b/regress/unittests/sshkey/testdata/rsa_1-cert.fp
new file mode 100644
index 000000000..bf9c2e362
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1-cert.fp
@@ -0,0 +1 @@
be:27:4c:16:27:f5:04:03:62:a8:b7:91:df:a5:b1:3b
diff --git a/regress/unittests/sshkey/testdata/rsa_1-cert.pub b/regress/unittests/sshkey/testdata/rsa_1-cert.pub
new file mode 100644
index 000000000..51b1ce0dd
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1-cert.pub
@@ -0,0 +1 @@
ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg1i9Ueveqg9sFSGsEYmsQqlI+dpC3nqhucPfwBVo3DtcAAAADAQABAAAAYQDP+jA5lVZv7jUJmaTnLYaAAIDA1IOxuB+mSy8jxIW6CmgQR7yHcGXQ5gftCw39w9Wll8lHdv6QpAsrIgc6nf+dt8wM42Ox2sqi+gPeNAMSgQW1i5/l+otsiUe3UzmJJOkAAAAAAAAABQAAAAIAAAAGanVsaXVzAAAAEgAAAAVob3N0MQAAAAVob3N0MgAAAAA2i4NgAAAAAE0d4eAAAAAAAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAILk95V5J3LKVx8bcLSB4073R7d0aAvR8gJrPvnV0D3MQAAAAUwAAAAtzc2gtZWQyNTUxOQAAAED0TLf2Mv2F9TBt1Skf/1vviUgt7bt9xvL5HqugnVDfKaEg+RNKgfa5Rtpteb39EODkH8v4FJPWlmNG0F9w0cYF rsa_1.pub
diff --git a/regress/unittests/sshkey/testdata/rsa_1.fp b/regress/unittests/sshkey/testdata/rsa_1.fp
new file mode 100644
index 000000000..bf9c2e362
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.fp
@@ -0,0 +1 @@
be:27:4c:16:27:f5:04:03:62:a8:b7:91:df:a5:b1:3b
diff --git a/regress/unittests/sshkey/testdata/rsa_1.fp.bb b/regress/unittests/sshkey/testdata/rsa_1.fp.bb
new file mode 100644
index 000000000..448133bad
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.fp.bb
@@ -0,0 +1 @@
xetif-zuvul-nylyc-vykor-lumac-gyhyv-bacih-cimyk-sycen-gikym-pixax
diff --git a/regress/unittests/sshkey/testdata/rsa_1.param.n b/regress/unittests/sshkey/testdata/rsa_1.param.n
new file mode 100644
index 000000000..2ffc2ba7e
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.param.n
@@ -0,0 +1 @@
00cffa303995566fee350999a4e72d86800080c0d483b1b81fa64b2f23c485ba0a681047bc877065d0e607ed0b0dfdc3d5a597c94776fe90a40b2b22073a9dff9db7cc0ce363b1dacaa2fa03de3403128105b58b9fe5fa8b6c8947b753398924e9
diff --git a/regress/unittests/sshkey/testdata/rsa_1.param.p b/regress/unittests/sshkey/testdata/rsa_1.param.p
new file mode 100644
index 000000000..4fcf148c3
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.param.p
@@ -0,0 +1 @@
00fb9ec951780c70cff01dfbe0025ecc1f260d65db0510d60240df38778e59fa6b8b37695d73c5b2a5227f22a81bf40599
diff --git a/regress/unittests/sshkey/testdata/rsa_1.param.q b/regress/unittests/sshkey/testdata/rsa_1.param.q
new file mode 100644
index 000000000..3473f5144
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.param.q
@@ -0,0 +1 @@
00d398ee16ab23678a7ef75c266cd035aeec6b1f72e687f109c3c2a3e3260adc95365779dc4791ea8eda8c995b898b0bd1
diff --git a/regress/unittests/sshkey/testdata/rsa_1.pub b/regress/unittests/sshkey/testdata/rsa_1.pub
new file mode 100644
index 000000000..889fdae86
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1.pub
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAYQDP+jA5lVZv7jUJmaTnLYaAAIDA1IOxuB+mSy8jxIW6CmgQR7yHcGXQ5gftCw39w9Wll8lHdv6QpAsrIgc6nf+dt8wM42Ox2sqi+gPeNAMSgQW1i5/l+otsiUe3UzmJJOk= RSA test key #1
diff --git a/regress/unittests/sshkey/testdata/rsa_1_pw b/regress/unittests/sshkey/testdata/rsa_1_pw
new file mode 100644
index 000000000..71637a59b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_1_pw
@@ -0,0 +1,15 @@
1-----BEGIN RSA PRIVATE KEY-----
2Proc-Type: 4,ENCRYPTED
3DEK-Info: AES-128-CBC,1E851A01F12A49FDC256E7A665C61D4B
4
5+sfWU7kg3idmHL6vShby5LXnfF4bZDPhJjv89uldae7qPEgEW8qS8o0Ssokxf7Au
6/vTQnbSB+gy/qZaUOykOzqiV1YL7UfkbOkM2QYnzzrVeGzI5RZ0G9iH8HBn2owQ+
7Ejf1UKDUVZEea5X0IwQRfE0zaZqFS4tyEex0iKz8dI4FvyabKLZsCs1DBGO7A3ml
8LgP947mh10yKWTP2fbq8LOhDUEWCXrh2NzuH6Rl5nNyC4MNQEkLzK1wL7J/WCNaL
9sciYmuqEQRDikDDQQFZw2wjBD638fhK+IhuN3VGegiXFnu5C+p9kzUvqVk4X9g2r
10BMmlP0pceFv/fEwtNNaeI2Tt7mIsWsZTmCqdzOUAYqGIiNjzykWw64nMO3TpVpbA
11i4854RhblbeiyjENbMVPU6BAk4fx7OJvDElLxwN43CS3U0MldbI7A4uG3B3RTSCj
121rGxRNAHWC3q3zzrn6gLwrUVje4iTedaKItLIHQeo1A091Tr8AqQdZi/Ck2Ju0Hl
134Qdwzjw1Y5n1Akm+EWh31ydxtUQ0YBOz/W6DKwTNA1D8oH9bZBG4f0pnvVhtttAO
14WKj+DUqMa+f3OOmQ9UXlitk2pEgjeMngTgfQnhZiCts=
15-----END RSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/rsa_2 b/regress/unittests/sshkey/testdata/rsa_2
new file mode 100644
index 000000000..058cf777a
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2
@@ -0,0 +1,27 @@
1-----BEGIN RSA PRIVATE KEY-----
2MIIEowIBAAKCAQEAlDS/ygeFfsR/mhZK/XMHU/gzRogPuMQIYUd17WDjMprA6dQb
3ckTDrNm/mrf09I6YAhjgooEL16oWM1z6cesDE0KwaJsy6uTmXFMLO+Ha4mtFHhmu
4tiyJcQ9MKKr0vC64384WQZygZk0OlVz7x9WSPiGXzal5MzsX4TYq5B05o2Cb+epA
5FxK0c8cdYZD0Sy57gWRpRA3yJq4zh/hks98jzn0XA3HAJA39MKhUG5tf5e6z5BeP
6Yi5FvdnDQ9WcasRiEvkmHbg59pbgg/Lbsl6OgZQruS8hKiJ3YBARt2euCCeg7qAF
7KbXRR9TMwfphH3Ai4Oi/w6HPRAhdrwooA/gKkQIDAQABAoIBAH22OLB/rMaYmrvz
8COzvM1oQgD3lj6Bj98+8M9WEh3MXPWeaGSXWGjx1/0aXn1oJ0fqFa5Wr7IWkqmwr
9A+y5McSWntg8PPZt7tCFSFQlAetonhooIsA4CuUx2qHsUOeGoh6EyvAgkRX1atdb
10Jd6d1AyLph43EK1aBKltrvgLqiZfs7mcuwyvKtN9ktdKY2FDhn6DHpm9pE9MEHJV
11Xv1isNc6a0qNoRlKqxrSZHNEN4fbjLw31wBySzmmnIog5wVEwaHeASwLJT6TmuIZ
12eZxnd7/jMwRZWH8ZIGKvkTMp4fYzK9QkehO7A2HFD3FPDBVrkSJjqRdkujF8vu1C
130RwrD1kCgYEAxFXUoE1ero6vp9akvR/mw94kYjXE/YOz1yi0KTkZUs6gURc8Kzsm
14MzlEZ31rnngE4jQHYAvuPEfiqcnUgylW3QuevMgo2hCLYO7aG5C0fk8TeOiuvnrF
15YPO8rSJWk/BgdrPtzu45P7jmWsjkHn+y+t8cKvq1sZY40sn2YgIhYK8CgYEAwT6j
165tReI6sxpHltPUbvOdpD04eL6ggBAKwzb5aBoa/Dj+sU1zg5uyY8diggQEEznlBW
17iWTQmmmfy1ef9i6YAwNuZveKOrVwNMcdubQJ2X26XoFrmA59PjsbLtr1bdUb02gz
186P5x6pcw5qzEq0mddgvHiU3RhL24xdc1LW8nmL8CgYEAmgaT1macPuklmNBlURGz
194jll5b41GoW2EreWDzkCStpbHwLRa0DuCQWGSoI0aY/SlPsoRgtWDOiAQ59ZHsTR
20pnw1PfjxQ5HzJkp7xWBSmTzEE/jHDhwWuKa+gD0OGuVbaARkLhDpzLnrzZEIlXyt
21Fu7tlDI3VGh7j7Jtnhn5wXUCgYBKmPbGfcaVeFmih2lfFUn2CEbUmmetgUd5zf/R
22HMWP9/zDStlxt3e5winm5tiEVWcqvxKY2T0Zzppr8biDXTs7NpDg2MAYp7/X7+GO
23tWxz8/AE2WsCeN1qL4Dv1oCV1IV4V6pqUAcDqzeqZJlLEhDh5+wwGcU+u8pfPRN/
24JYCgmwKBgDa+kXPqzcc6vzD9cwEEk4ftn9/Vk2yBx0XOu8RdEkRhXj1QXGJckCqh
25FkXzVbuurFhsBt+H0B4arw+51T9fVCZqfcaU34u+Qa/FQvTod4OJUSRxYUaDqygs
26VTyuP+zGZlIw7JWktxjVazENsM/ef5wBH0Nf839OZbPVDLfn7K0j
27-----END RSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/rsa_2.fp b/regress/unittests/sshkey/testdata/rsa_2.fp
new file mode 100644
index 000000000..53939f413
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.fp
@@ -0,0 +1 @@
fb:8f:7b:26:3d:42:40:ef:ed:f1:ed:ee:66:9e:ba:b0
diff --git a/regress/unittests/sshkey/testdata/rsa_2.fp.bb b/regress/unittests/sshkey/testdata/rsa_2.fp.bb
new file mode 100644
index 000000000..e90a3571a
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.fp.bb
@@ -0,0 +1 @@
xepev-gupub-vuvyg-femiv-gonat-defiv-hirak-betub-pahut-veryd-hexix
diff --git a/regress/unittests/sshkey/testdata/rsa_2.param.n b/regress/unittests/sshkey/testdata/rsa_2.param.n
new file mode 100644
index 000000000..389de4226
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.param.n
@@ -0,0 +1 @@
009434bfca07857ec47f9a164afd730753f83346880fb8c408614775ed60e3329ac0e9d41b7244c3acd9bf9ab7f4f48e980218e0a2810bd7aa16335cfa71eb031342b0689b32eae4e65c530b3be1dae26b451e19aeb62c89710f4c28aaf4bc2eb8dfce16419ca0664d0e955cfbc7d5923e2197cda979333b17e1362ae41d39a3609bf9ea401712b473c71d6190f44b2e7b816469440df226ae3387f864b3df23ce7d170371c0240dfd30a8541b9b5fe5eeb3e4178f622e45bdd9c343d59c6ac46212f9261db839f696e083f2dbb25e8e81942bb92f212a2277601011b767ae0827a0eea00529b5d147d4ccc1fa611f7022e0e8bfc3a1cf44085daf0a2803f80a91
diff --git a/regress/unittests/sshkey/testdata/rsa_2.param.p b/regress/unittests/sshkey/testdata/rsa_2.param.p
new file mode 100644
index 000000000..c3c9a130a
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.param.p
@@ -0,0 +1 @@
00c455d4a04d5eae8eafa7d6a4bd1fe6c3de246235c4fd83b3d728b429391952cea051173c2b3b26333944677d6b9e7804e23407600bee3c47e2a9c9d4832956dd0b9ebcc828da108b60eeda1b90b47e4f1378e8aebe7ac560f3bcad225693f06076b3edceee393fb8e65ac8e41e7fb2fadf1c2afab5b19638d2c9f662022160af
diff --git a/regress/unittests/sshkey/testdata/rsa_2.param.q b/regress/unittests/sshkey/testdata/rsa_2.param.q
new file mode 100644
index 000000000..728c474b0
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.param.q
@@ -0,0 +1 @@
00c13ea3e6d45e23ab31a4796d3d46ef39da43d3878bea080100ac336f9681a1afc38feb14d73839bb263c7628204041339e50568964d09a699fcb579ff62e9803036e66f78a3ab57034c71db9b409d97dba5e816b980e7d3e3b1b2edaf56dd51bd36833e8fe71ea9730e6acc4ab499d760bc7894dd184bdb8c5d7352d6f2798bf
diff --git a/regress/unittests/sshkey/testdata/rsa_2.pub b/regress/unittests/sshkey/testdata/rsa_2.pub
new file mode 100644
index 000000000..ed9f78cad
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_2.pub
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUNL/KB4V+xH+aFkr9cwdT+DNGiA+4xAhhR3XtYOMymsDp1BtyRMOs2b+at/T0jpgCGOCigQvXqhYzXPpx6wMTQrBomzLq5OZcUws74dria0UeGa62LIlxD0woqvS8LrjfzhZBnKBmTQ6VXPvH1ZI+IZfNqXkzOxfhNirkHTmjYJv56kAXErRzxx1hkPRLLnuBZGlEDfImrjOH+GSz3yPOfRcDccAkDf0wqFQbm1/l7rPkF49iLkW92cND1ZxqxGIS+SYduDn2luCD8tuyXo6BlCu5LyEqIndgEBG3Z64IJ6DuoAUptdFH1MzB+mEfcCLg6L/Doc9ECF2vCigD+AqR RSA test key #2
diff --git a/regress/unittests/sshkey/testdata/rsa_n b/regress/unittests/sshkey/testdata/rsa_n
new file mode 100644
index 000000000..09e79a72e
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_n
@@ -0,0 +1,12 @@
1-----BEGIN RSA PRIVATE KEY-----
2MIIBywIBAAJhAM/6MDmVVm/uNQmZpOcthoAAgMDUg7G4H6ZLLyPEhboKaBBHvIdw
3ZdDmB+0LDf3D1aWXyUd2/pCkCysiBzqd/523zAzjY7HayqL6A940AxKBBbWLn+X6
4i2yJR7dTOYkk6QIDAQABAmAgKanBjfWzE5yCIo+c7K5rJyjCKVtAZaAHYIMmveKM
5VcWoFt/x9hDY0GoTX21HfDxLX8oDxnsmhsOrnvSmgUChFwkm45eSETqeVDWwIVFA
6FGL1s38xQsciWZWBFNppAIECMQD7nslReAxwz/Ad++ACXswfJg1l2wUQ1gJA3zh3
7jln6a4s3aV1zxbKlIn8iqBv0BZkCMQDTmO4WqyNnin73XCZs0DWu7GsfcuaH8QnD
8wqPjJgrclTZXedxHkeqO2oyZW4mLC9ECMBb/blsZ49kzyDiVWuYcj/+Q1MyodhAR
932bagCi9RBAVYEYSRU5dlXRucLxULSnikQIxAJ5teY5Vcru6kZfJUifUuO0QrKAu
10WnbcPVBqMmUHfchsm/RhFFIt6W4uKmlEhTYrkQIxAMAStb7QCU3yU6ZkN7uL22Zs
11498i4jY6y+VEXv+L9O09VdlEnXhbUisOhy1bhyS3yg==
12-----END RSA PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/rsa_n_pw b/regress/unittests/sshkey/testdata/rsa_n_pw
new file mode 100644
index 000000000..0166fd5f1
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/rsa_n_pw
@@ -0,0 +1,14 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABClELgtaZ
3qAmMwESpqXDN0uAAAAEAAAAAEAAAB3AAAAB3NzaC1yc2EAAAADAQABAAAAYQDP+jA5lVZv
47jUJmaTnLYaAAIDA1IOxuB+mSy8jxIW6CmgQR7yHcGXQ5gftCw39w9Wll8lHdv6QpAsrIg
5c6nf+dt8wM42Ox2sqi+gPeNAMSgQW1i5/l+otsiUe3UzmJJOkAAAGgwJpHy/nshQa9+Jbw
6yomvgNMYvuuoD7Ll7iCY/RFFGXivTkki27C9q0qx3afauSLQQWFanGhjeJn7JPy98lMcVl
7qnn5XOE5+xxZqA8ONOBD8eH0KBcTH17DH1A1z94p5zZ1VJKIWsBZ0krxgHIXcdv9ucAckj
8N0vAEBm+0wsfy2TTOtuqXvcj65wFwknpyy/SSvU0QTr99FiYe9PIhIslBHO6wlqxfKj+Tm
9E/nCb75dAVu6gTtS2P0pdOqV/V7VHX5C0z3BROqpKDJJcVeoc7vRkEl+MWfvvQrG66IPEW
10luohFXPDPDrxu1zDduyRsmNwpBHChi2rFhxtsjxNK0svMwESeCCKAWmPxnzLJfvMbTCv00
11SpaCr7WhtzsGt73axqSkeOdynp5NNrN7MEdwruMZFirF4BcI2z2H9ugpS+qbLPuE2H5vln
12h7NSwBUNwmZ+4TC8MXFH9KIpRg8dNhf66OU610LYiN4+ZfOYCmfQfgQuBGhMTYFMY6O4SB
13NCdIavvWY6rDSBq7QC1f4rHpwiXxpkiE43Rd8fM32TaPlBPtA=
14-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/tests.c b/regress/unittests/sshkey/tests.c
new file mode 100644
index 000000000..13f265cdb
--- /dev/null
+++ b/regress/unittests/sshkey/tests.c
@@ -0,0 +1,27 @@
1/* $OpenBSD: tests.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */
2/*
3 * Regress test for sshbuf.h buffer API
4 *
5 * Placed in the public domain
6 */
7
8#include "includes.h"
9
10#include <openssl/evp.h>
11
12#include "../test_helper/test_helper.h"
13
14void sshkey_tests(void);
15void sshkey_file_tests(void);
16void sshkey_fuzz_tests(void);
17
18void
19tests(void)
20{
21 OpenSSL_add_all_algorithms();
22 ERR_load_CRYPTO_strings();
23
24 sshkey_tests();
25 sshkey_file_tests();
26 sshkey_fuzz_tests();
27}
diff --git a/regress/unittests/test_helper/Makefile b/regress/unittests/test_helper/Makefile
new file mode 100644
index 000000000..3e90903ef
--- /dev/null
+++ b/regress/unittests/test_helper/Makefile
@@ -0,0 +1,13 @@
1# $OpenBSD: Makefile,v 1.1 2014/04/30 05:32:00 djm Exp $
2
3LIB= test_helper
4SRCS= test_helper.c fuzz.c
5
6DEBUGLIBS= no
7NOPROFILE= yes
8NOPIC= yes
9
10install:
11 @echo -n
12
13.include <bsd.lib.mk>
diff --git a/regress/unittests/test_helper/fuzz.c b/regress/unittests/test_helper/fuzz.c
new file mode 100644
index 000000000..77c6e7cad
--- /dev/null
+++ b/regress/unittests/test_helper/fuzz.c
@@ -0,0 +1,378 @@
1/* $OpenBSD: fuzz.c,v 1.3 2014/05/02 09:41:32 andre Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller <djm@mindrot.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* Utility functions/framework for fuzz tests */
19
20#include "includes.h"
21
22#include <sys/types.h>
23
24#include <assert.h>
25#include <ctype.h>
26#include <stdio.h>
27#ifdef HAVE_STDINT_H
28# include <stdint.h>
29#endif
30#include <stdlib.h>
31#include <string.h>
32#include <assert.h>
33
34#include "test_helper.h"
35
36/* #define FUZZ_DEBUG */
37
38#ifdef FUZZ_DEBUG
39# define FUZZ_DBG(x) do { \
40 printf("%s:%d %s: ", __FILE__, __LINE__, __func__); \
41 printf x; \
42 printf("\n"); \
43 fflush(stdout); \
44 } while (0)
45#else
46# define FUZZ_DBG(x)
47#endif
48
49/* For brevity later */
50typedef unsigned long long fuzz_ullong;
51
52/* For base-64 fuzzing */
53static const char fuzz_b64chars[] =
54 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
55
56struct fuzz {
57 /* Fuzz method currently in use */
58 int strategy;
59
60 /* Fuzz methods remaining */
61 int strategies;
62
63 /* Original seed data blob */
64 void *seed;
65 size_t slen;
66
67 /* Current working copy of seed with fuzz mutations applied */
68 u_char *fuzzed;
69
70 /* Used by fuzz methods */
71 size_t o1, o2;
72};
73
74static const char *
75fuzz_ntop(u_int n)
76{
77 switch (n) {
78 case 0:
79 return "NONE";
80 case FUZZ_1_BIT_FLIP:
81 return "FUZZ_1_BIT_FLIP";
82 case FUZZ_2_BIT_FLIP:
83 return "FUZZ_2_BIT_FLIP";
84 case FUZZ_1_BYTE_FLIP:
85 return "FUZZ_1_BYTE_FLIP";
86 case FUZZ_2_BYTE_FLIP:
87 return "FUZZ_2_BYTE_FLIP";
88 case FUZZ_TRUNCATE_START:
89 return "FUZZ_TRUNCATE_START";
90 case FUZZ_TRUNCATE_END:
91 return "FUZZ_TRUNCATE_END";
92 case FUZZ_BASE64:
93 return "FUZZ_BASE64";
94 default:
95 abort();
96 }
97}
98
99void
100fuzz_dump(struct fuzz *fuzz)
101{
102 u_char *p = fuzz_ptr(fuzz);
103 size_t i, j, len = fuzz_len(fuzz);
104
105 switch (fuzz->strategy) {
106 case FUZZ_1_BIT_FLIP:
107 fprintf(stderr, "%s case %zu of %zu (bit: %zu)\n",
108 fuzz_ntop(fuzz->strategy),
109 fuzz->o1, fuzz->slen * 8, fuzz->o1);
110 break;
111 case FUZZ_2_BIT_FLIP:
112 fprintf(stderr, "%s case %llu of %llu (bits: %zu, %zu)\n",
113 fuzz_ntop(fuzz->strategy),
114 (((fuzz_ullong)fuzz->o2) * fuzz->slen * 8) + fuzz->o1,
115 ((fuzz_ullong)fuzz->slen * 8) * fuzz->slen * 8,
116 fuzz->o1, fuzz->o2);
117 break;
118 case FUZZ_1_BYTE_FLIP:
119 fprintf(stderr, "%s case %zu of %zu (byte: %zu)\n",
120 fuzz_ntop(fuzz->strategy),
121 fuzz->o1, fuzz->slen, fuzz->o1);
122 break;
123 case FUZZ_2_BYTE_FLIP:
124 fprintf(stderr, "%s case %llu of %llu (bytes: %zu, %zu)\n",
125 fuzz_ntop(fuzz->strategy),
126 (((fuzz_ullong)fuzz->o2) * fuzz->slen) + fuzz->o1,
127 ((fuzz_ullong)fuzz->slen) * fuzz->slen,
128 fuzz->o1, fuzz->o2);
129 break;
130 case FUZZ_TRUNCATE_START:
131 fprintf(stderr, "%s case %zu of %zu (offset: %zu)\n",
132 fuzz_ntop(fuzz->strategy),
133 fuzz->o1, fuzz->slen, fuzz->o1);
134 break;
135 case FUZZ_TRUNCATE_END:
136 fprintf(stderr, "%s case %zu of %zu (offset: %zu)\n",
137 fuzz_ntop(fuzz->strategy),
138 fuzz->o1, fuzz->slen, fuzz->o1);
139 break;
140 case FUZZ_BASE64:
141 assert(fuzz->o2 < sizeof(fuzz_b64chars) - 1);
142 fprintf(stderr, "%s case %llu of %llu (offset: %zu char: %c)\n",
143 fuzz_ntop(fuzz->strategy),
144 (fuzz->o1 * (fuzz_ullong)64) + fuzz->o2,
145 fuzz->slen * (fuzz_ullong)64, fuzz->o1,
146 fuzz_b64chars[fuzz->o2]);
147 break;
148 default:
149 abort();
150 }
151
152 fprintf(stderr, "fuzz context %p len = %zu\n", fuzz, len);
153 for (i = 0; i < len; i += 16) {
154 fprintf(stderr, "%.4zd: ", i);
155 for (j = i; j < i + 16; j++) {
156 if (j < len)
157 fprintf(stderr, "%02x ", p[j]);
158 else
159 fprintf(stderr, " ");
160 }
161 fprintf(stderr, " ");
162 for (j = i; j < i + 16; j++) {
163 if (j < len) {
164 if (isascii(p[j]) && isprint(p[j]))
165 fprintf(stderr, "%c", p[j]);
166 else
167 fprintf(stderr, ".");
168 }
169 }
170 fprintf(stderr, "\n");
171 }
172}
173
174struct fuzz *
175fuzz_begin(u_int strategies, const void *p, size_t l)
176{
177 struct fuzz *ret = calloc(sizeof(*ret), 1);
178
179 assert(p != NULL);
180 assert(ret != NULL);
181 ret->seed = malloc(l);
182 assert(ret->seed != NULL);
183 memcpy(ret->seed, p, l);
184 ret->slen = l;
185 ret->strategies = strategies;
186
187 assert(ret->slen < SIZE_MAX / 8);
188 assert(ret->strategies <= (FUZZ_MAX|(FUZZ_MAX-1)));
189
190 FUZZ_DBG(("begin, ret = %p", ret));
191
192 fuzz_next(ret);
193 return ret;
194}
195
196void
197fuzz_cleanup(struct fuzz *fuzz)
198{
199 FUZZ_DBG(("cleanup, fuzz = %p", fuzz));
200 assert(fuzz != NULL);
201 assert(fuzz->seed != NULL);
202 assert(fuzz->fuzzed != NULL);
203 free(fuzz->seed);
204 free(fuzz->fuzzed);
205 free(fuzz);
206}
207
208static int
209fuzz_strategy_done(struct fuzz *fuzz)
210{
211 FUZZ_DBG(("fuzz = %p, strategy = %s, o1 = %zu, o2 = %zu, slen = %zu",
212 fuzz, fuzz_ntop(fuzz->strategy), fuzz->o1, fuzz->o2, fuzz->slen));
213
214 switch (fuzz->strategy) {
215 case FUZZ_1_BIT_FLIP:
216 return fuzz->o1 >= fuzz->slen * 8;
217 case FUZZ_2_BIT_FLIP:
218 return fuzz->o2 >= fuzz->slen * 8;
219 case FUZZ_2_BYTE_FLIP:
220 return fuzz->o2 >= fuzz->slen;
221 case FUZZ_1_BYTE_FLIP:
222 case FUZZ_TRUNCATE_START:
223 case FUZZ_TRUNCATE_END:
224 case FUZZ_BASE64:
225 return fuzz->o1 >= fuzz->slen;
226 default:
227 abort();
228 }
229}
230
231void
232fuzz_next(struct fuzz *fuzz)
233{
234 u_int i;
235
236 FUZZ_DBG(("start, fuzz = %p, strategy = %s, strategies = 0x%lx, "
237 "o1 = %zu, o2 = %zu, slen = %zu", fuzz, fuzz_ntop(fuzz->strategy),
238 (u_long)fuzz->strategies, fuzz->o1, fuzz->o2, fuzz->slen));
239
240 if (fuzz->strategy == 0 || fuzz_strategy_done(fuzz)) {
241 /* If we are just starting out, we need to allocate too */
242 if (fuzz->fuzzed == NULL) {
243 FUZZ_DBG(("alloc"));
244 fuzz->fuzzed = calloc(fuzz->slen, 1);
245 }
246 /* Pick next strategy */
247 FUZZ_DBG(("advance"));
248 for (i = 1; i <= FUZZ_MAX; i <<= 1) {
249 if ((fuzz->strategies & i) != 0) {
250 fuzz->strategy = i;
251 break;
252 }
253 }
254 FUZZ_DBG(("selected = %u", fuzz->strategy));
255 if (fuzz->strategy == 0) {
256 FUZZ_DBG(("done, no more strategies"));
257 return;
258 }
259 fuzz->strategies &= ~(fuzz->strategy);
260 fuzz->o1 = fuzz->o2 = 0;
261 }
262
263 assert(fuzz->fuzzed != NULL);
264
265 switch (fuzz->strategy) {
266 case FUZZ_1_BIT_FLIP:
267 assert(fuzz->o1 / 8 < fuzz->slen);
268 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
269 fuzz->fuzzed[fuzz->o1 / 8] ^= 1 << (fuzz->o1 % 8);
270 fuzz->o1++;
271 break;
272 case FUZZ_2_BIT_FLIP:
273 assert(fuzz->o1 / 8 < fuzz->slen);
274 assert(fuzz->o2 / 8 < fuzz->slen);
275 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
276 fuzz->fuzzed[fuzz->o1 / 8] ^= 1 << (fuzz->o1 % 8);
277 fuzz->fuzzed[fuzz->o2 / 8] ^= 1 << (fuzz->o2 % 8);
278 fuzz->o1++;
279 if (fuzz->o1 >= fuzz->slen * 8) {
280 fuzz->o1 = 0;
281 fuzz->o2++;
282 }
283 break;
284 case FUZZ_1_BYTE_FLIP:
285 assert(fuzz->o1 < fuzz->slen);
286 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
287 fuzz->fuzzed[fuzz->o1] ^= 0xff;
288 fuzz->o1++;
289 break;
290 case FUZZ_2_BYTE_FLIP:
291 assert(fuzz->o1 < fuzz->slen);
292 assert(fuzz->o2 < fuzz->slen);
293 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
294 fuzz->fuzzed[fuzz->o1] ^= 0xff;
295 fuzz->fuzzed[fuzz->o2] ^= 0xff;
296 fuzz->o1++;
297 if (fuzz->o1 >= fuzz->slen) {
298 fuzz->o1 = 0;
299 fuzz->o2++;
300 }
301 break;
302 case FUZZ_TRUNCATE_START:
303 case FUZZ_TRUNCATE_END:
304 assert(fuzz->o1 < fuzz->slen);
305 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
306 fuzz->o1++;
307 break;
308 case FUZZ_BASE64:
309 assert(fuzz->o1 < fuzz->slen);
310 assert(fuzz->o2 < sizeof(fuzz_b64chars) - 1);
311 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
312 fuzz->fuzzed[fuzz->o1] = fuzz_b64chars[fuzz->o2];
313 fuzz->o2++;
314 if (fuzz->o2 >= sizeof(fuzz_b64chars) - 1) {
315 fuzz->o2 = 0;
316 fuzz->o1++;
317 }
318 break;
319 default:
320 abort();
321 }
322
323 FUZZ_DBG(("done, fuzz = %p, strategy = %s, strategies = 0x%lx, "
324 "o1 = %zu, o2 = %zu, slen = %zu", fuzz, fuzz_ntop(fuzz->strategy),
325 (u_long)fuzz->strategies, fuzz->o1, fuzz->o2, fuzz->slen));
326}
327
328int
329fuzz_done(struct fuzz *fuzz)
330{
331 FUZZ_DBG(("fuzz = %p, strategies = 0x%lx", fuzz,
332 (u_long)fuzz->strategies));
333
334 return fuzz_strategy_done(fuzz) && fuzz->strategies == 0;
335}
336
337size_t
338fuzz_len(struct fuzz *fuzz)
339{
340 assert(fuzz->fuzzed != NULL);
341 switch (fuzz->strategy) {
342 case FUZZ_1_BIT_FLIP:
343 case FUZZ_2_BIT_FLIP:
344 case FUZZ_1_BYTE_FLIP:
345 case FUZZ_2_BYTE_FLIP:
346 case FUZZ_BASE64:
347 return fuzz->slen;
348 case FUZZ_TRUNCATE_START:
349 case FUZZ_TRUNCATE_END:
350 assert(fuzz->o1 <= fuzz->slen);
351 return fuzz->slen - fuzz->o1;
352 default:
353 abort();
354 }
355}
356
357u_char *
358fuzz_ptr(struct fuzz *fuzz)
359{
360 assert(fuzz->fuzzed != NULL);
361 switch (fuzz->strategy) {
362 case FUZZ_1_BIT_FLIP:
363 case FUZZ_2_BIT_FLIP:
364 case FUZZ_1_BYTE_FLIP:
365 case FUZZ_2_BYTE_FLIP:
366 case FUZZ_BASE64:
367 return fuzz->fuzzed;
368 case FUZZ_TRUNCATE_START:
369 assert(fuzz->o1 <= fuzz->slen);
370 return fuzz->fuzzed + fuzz->o1;
371 case FUZZ_TRUNCATE_END:
372 assert(fuzz->o1 <= fuzz->slen);
373 return fuzz->fuzzed;
374 default:
375 abort();
376 }
377}
378
diff --git a/regress/unittests/test_helper/test_helper.c b/regress/unittests/test_helper/test_helper.c
new file mode 100644
index 000000000..d0bc67833
--- /dev/null
+++ b/regress/unittests/test_helper/test_helper.c
@@ -0,0 +1,471 @@
1/* $OpenBSD: test_helper.c,v 1.2 2014/05/02 09:41:32 andre Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller <djm@mindrot.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* Utility functions/framework for regress tests */
19
20#include "includes.h"
21
22#include <sys/types.h>
23#include <sys/param.h>
24
25#include <fcntl.h>
26#include <stdio.h>
27#ifdef HAVE_STDINT_H
28# include <stdint.h>
29#endif
30#include <stdlib.h>
31#include <string.h>
32#include <assert.h>
33#include <unistd.h>
34
35#include <openssl/bn.h>
36
37#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
38# include <vis.h>
39#endif
40
41#include "test_helper.h"
42
43#define TEST_CHECK_INT(r, pred) do { \
44 switch (pred) { \
45 case TEST_EQ: \
46 if (r == 0) \
47 return; \
48 break; \
49 case TEST_NE: \
50 if (r != 0) \
51 return; \
52 break; \
53 case TEST_LT: \
54 if (r < 0) \
55 return; \
56 break; \
57 case TEST_LE: \
58 if (r <= 0) \
59 return; \
60 break; \
61 case TEST_GT: \
62 if (r > 0) \
63 return; \
64 break; \
65 case TEST_GE: \
66 if (r >= 0) \
67 return; \
68 break; \
69 default: \
70 abort(); \
71 } \
72 } while (0)
73
74#define TEST_CHECK(x1, x2, pred) do { \
75 switch (pred) { \
76 case TEST_EQ: \
77 if (x1 == x2) \
78 return; \
79 break; \
80 case TEST_NE: \
81 if (x1 != x2) \
82 return; \
83 break; \
84 case TEST_LT: \
85 if (x1 < x2) \
86 return; \
87 break; \
88 case TEST_LE: \
89 if (x1 <= x2) \
90 return; \
91 break; \
92 case TEST_GT: \
93 if (x1 > x2) \
94 return; \
95 break; \
96 case TEST_GE: \
97 if (x1 >= x2) \
98 return; \
99 break; \
100 default: \
101 abort(); \
102 } \
103 } while (0)
104
105extern char *__progname;
106
107static int verbose_mode = 0;
108static int quiet_mode = 0;
109static char *active_test_name = NULL;
110static u_int test_number = 0;
111static test_onerror_func_t *test_onerror = NULL;
112static void *onerror_ctx = NULL;
113static const char *data_dir = NULL;
114
115int
116main(int argc, char **argv)
117{
118 int ch;
119
120 /* Handle systems without __progname */
121 if (__progname == NULL) {
122 __progname = strrchr(argv[0], '/');
123 if (__progname == NULL || __progname[1] == '\0')
124 __progname = argv[0];
125 else
126 __progname++;
127 if ((__progname = strdup(__progname)) == NULL) {
128 fprintf(stderr, "strdup failed\n");
129 exit(1);
130 }
131 }
132
133 while ((ch = getopt(argc, argv, "vqd:")) != -1) {
134 switch (ch) {
135 case 'd':
136 data_dir = optarg;
137 break;
138 case 'q':
139 verbose_mode = 0;
140 quiet_mode = 1;
141 break;
142 case 'v':
143 verbose_mode = 1;
144 quiet_mode = 0;
145 break;
146 default:
147 fprintf(stderr, "Unrecognised command line option\n");
148 fprintf(stderr, "Usage: %s [-v]\n", __progname);
149 exit(1);
150 }
151 }
152 setvbuf(stdout, NULL, _IONBF, 0);
153 if (!quiet_mode)
154 printf("%s: ", __progname);
155 if (verbose_mode)
156 printf("\n");
157
158 tests();
159
160 if (!quiet_mode)
161 printf(" %u tests ok\n", test_number);
162 return 0;
163}
164
165const char *
166test_data_file(const char *name)
167{
168 static char ret[PATH_MAX];
169
170 if (data_dir != NULL)
171 snprintf(ret, sizeof(ret), "%s/%s", data_dir, name);
172 else
173 strlcpy(ret, name, sizeof(ret));
174 if (access(ret, F_OK) != 0) {
175 fprintf(stderr, "Cannot access data file %s: %s\n",
176 ret, strerror(errno));
177 exit(1);
178 }
179 return ret;
180}
181
182void
183test_start(const char *n)
184{
185 assert(active_test_name == NULL);
186 assert((active_test_name = strdup(n)) != NULL);
187 if (verbose_mode)
188 printf("test %u - \"%s\": ", test_number, active_test_name);
189 test_number++;
190}
191
192void
193set_onerror_func(test_onerror_func_t *f, void *ctx)
194{
195 test_onerror = f;
196 onerror_ctx = ctx;
197}
198
199void
200test_done(void)
201{
202 assert(active_test_name != NULL);
203 free(active_test_name);
204 active_test_name = NULL;
205 if (verbose_mode)
206 printf("OK\n");
207 else if (!quiet_mode) {
208 printf(".");
209 fflush(stdout);
210 }
211}
212
213void
214ssl_err_check(const char *file, int line)
215{
216 long openssl_error = ERR_get_error();
217
218 if (openssl_error == 0)
219 return;
220
221 fprintf(stderr, "\n%s:%d: uncaught OpenSSL error: %s",
222 file, line, ERR_error_string(openssl_error, NULL));
223 abort();
224}
225
226static const char *
227pred_name(enum test_predicate p)
228{
229 switch (p) {
230 case TEST_EQ:
231 return "EQ";
232 case TEST_NE:
233 return "NE";
234 case TEST_LT:
235 return "LT";
236 case TEST_LE:
237 return "LE";
238 case TEST_GT:
239 return "GT";
240 case TEST_GE:
241 return "GE";
242 default:
243 return "UNKNOWN";
244 }
245}
246
247static void
248test_die(void)
249{
250 if (test_onerror != NULL)
251 test_onerror(onerror_ctx);
252 abort();
253}
254
255static void
256test_header(const char *file, int line, const char *a1, const char *a2,
257 const char *name, enum test_predicate pred)
258{
259 fprintf(stderr, "\n%s:%d test #%u \"%s\"\n",
260 file, line, test_number, active_test_name);
261 fprintf(stderr, "ASSERT_%s_%s(%s%s%s) failed:\n",
262 name, pred_name(pred), a1,
263 a2 != NULL ? ", " : "", a2 != NULL ? a2 : "");
264}
265
266void
267assert_bignum(const char *file, int line, const char *a1, const char *a2,
268 const BIGNUM *aa1, const BIGNUM *aa2, enum test_predicate pred)
269{
270 int r = BN_cmp(aa1, aa2);
271
272 TEST_CHECK_INT(r, pred);
273 test_header(file, line, a1, a2, "BIGNUM", pred);
274 fprintf(stderr, "%12s = 0x%s\n", a1, BN_bn2hex(aa1));
275 fprintf(stderr, "%12s = 0x%s\n", a2, BN_bn2hex(aa2));
276 test_die();
277}
278
279void
280assert_string(const char *file, int line, const char *a1, const char *a2,
281 const char *aa1, const char *aa2, enum test_predicate pred)
282{
283 int r = strcmp(aa1, aa2);
284
285 TEST_CHECK_INT(r, pred);
286 test_header(file, line, a1, a2, "STRING", pred);
287 fprintf(stderr, "%12s = %s (len %zu)\n", a1, aa1, strlen(aa1));
288 fprintf(stderr, "%12s = %s (len %zu)\n", a2, aa2, strlen(aa2));
289 test_die();
290}
291
292static char *
293tohex(const void *_s, size_t l)
294{
295 u_int8_t *s = (u_int8_t *)_s;
296 size_t i, j;
297 const char *hex = "0123456789abcdef";
298 char *r = malloc((l * 2) + 1);
299
300 assert(r != NULL);
301 for (i = j = 0; i < l; i++) {
302 r[j++] = hex[(s[i] >> 4) & 0xf];
303 r[j++] = hex[s[i] & 0xf];
304 }
305 r[j] = '\0';
306 return r;
307}
308
309void
310assert_mem(const char *file, int line, const char *a1, const char *a2,
311 const void *aa1, const void *aa2, size_t l, enum test_predicate pred)
312{
313 int r = memcmp(aa1, aa2, l);
314
315 TEST_CHECK_INT(r, pred);
316 test_header(file, line, a1, a2, "STRING", pred);
317 fprintf(stderr, "%12s = %s (len %zu)\n", a1, tohex(aa1, MIN(l, 256)), l);
318 fprintf(stderr, "%12s = %s (len %zu)\n", a2, tohex(aa2, MIN(l, 256)), l);
319 test_die();
320}
321
322static int
323memvalcmp(const u_int8_t *s, u_char v, size_t l, size_t *where)
324{
325 size_t i;
326
327 for (i = 0; i < l; i++) {
328 if (s[i] != v) {
329 *where = i;
330 return 1;
331 }
332 }
333 return 0;
334}
335
336void
337assert_mem_filled(const char *file, int line, const char *a1,
338 const void *aa1, u_char v, size_t l, enum test_predicate pred)
339{
340 size_t where = -1;
341 int r = memvalcmp(aa1, v, l, &where);
342 char tmp[64];
343
344 if (l == 0)
345 return;
346 TEST_CHECK_INT(r, pred);
347 test_header(file, line, a1, NULL, "MEM_ZERO", pred);
348 fprintf(stderr, "%20s = %s%s (len %zu)\n", a1,
349 tohex(aa1, MIN(l, 20)), l > 20 ? "..." : "", l);
350 snprintf(tmp, sizeof(tmp), "(%s)[%zu]", a1, where);
351 fprintf(stderr, "%20s = 0x%02x (expected 0x%02x)\n", tmp,
352 ((u_char *)aa1)[where], v);
353 test_die();
354}
355
356void
357assert_int(const char *file, int line, const char *a1, const char *a2,
358 int aa1, int aa2, enum test_predicate pred)
359{
360 TEST_CHECK(aa1, aa2, pred);
361 test_header(file, line, a1, a2, "INT", pred);
362 fprintf(stderr, "%12s = %d\n", a1, aa1);
363 fprintf(stderr, "%12s = %d\n", a2, aa2);
364 test_die();
365}
366
367void
368assert_size_t(const char *file, int line, const char *a1, const char *a2,
369 size_t aa1, size_t aa2, enum test_predicate pred)
370{
371 TEST_CHECK(aa1, aa2, pred);
372 test_header(file, line, a1, a2, "SIZE_T", pred);
373 fprintf(stderr, "%12s = %zu\n", a1, aa1);
374 fprintf(stderr, "%12s = %zu\n", a2, aa2);
375 test_die();
376}
377
378void
379assert_u_int(const char *file, int line, const char *a1, const char *a2,
380 u_int aa1, u_int aa2, enum test_predicate pred)
381{
382 TEST_CHECK(aa1, aa2, pred);
383 test_header(file, line, a1, a2, "U_INT", pred);
384 fprintf(stderr, "%12s = %u / 0x%x\n", a1, aa1, aa1);
385 fprintf(stderr, "%12s = %u / 0x%x\n", a2, aa2, aa2);
386 test_die();
387}
388
389void
390assert_long_long(const char *file, int line, const char *a1, const char *a2,
391 long long aa1, long long aa2, enum test_predicate pred)
392{
393 TEST_CHECK(aa1, aa2, pred);
394 test_header(file, line, a1, a2, "LONG LONG", pred);
395 fprintf(stderr, "%12s = %lld / 0x%llx\n", a1, aa1, aa1);
396 fprintf(stderr, "%12s = %lld / 0x%llx\n", a2, aa2, aa2);
397 test_die();
398}
399
400void
401assert_char(const char *file, int line, const char *a1, const char *a2,
402 char aa1, char aa2, enum test_predicate pred)
403{
404 char buf[8];
405
406 TEST_CHECK(aa1, aa2, pred);
407 test_header(file, line, a1, a2, "CHAR", pred);
408 fprintf(stderr, "%12s = '%s' / 0x02%x\n", a1,
409 vis(buf, aa1, VIS_SAFE|VIS_NL|VIS_TAB|VIS_OCTAL, 0), aa1);
410 fprintf(stderr, "%12s = '%s' / 0x02%x\n", a1,
411 vis(buf, aa2, VIS_SAFE|VIS_NL|VIS_TAB|VIS_OCTAL, 0), aa2);
412 test_die();
413}
414
415void
416assert_u8(const char *file, int line, const char *a1, const char *a2,
417 u_int8_t aa1, u_int8_t aa2, enum test_predicate pred)
418{
419 TEST_CHECK(aa1, aa2, pred);
420 test_header(file, line, a1, a2, "U8", pred);
421 fprintf(stderr, "%12s = 0x%02x %u\n", a1, aa1, aa1);
422 fprintf(stderr, "%12s = 0x%02x %u\n", a2, aa2, aa2);
423 test_die();
424}
425
426void
427assert_u16(const char *file, int line, const char *a1, const char *a2,
428 u_int16_t aa1, u_int16_t aa2, enum test_predicate pred)
429{
430 TEST_CHECK(aa1, aa2, pred);
431 test_header(file, line, a1, a2, "U16", pred);
432 fprintf(stderr, "%12s = 0x%04x %u\n", a1, aa1, aa1);
433 fprintf(stderr, "%12s = 0x%04x %u\n", a2, aa2, aa2);
434 test_die();
435}
436
437void
438assert_u32(const char *file, int line, const char *a1, const char *a2,
439 u_int32_t aa1, u_int32_t aa2, enum test_predicate pred)
440{
441 TEST_CHECK(aa1, aa2, pred);
442 test_header(file, line, a1, a2, "U32", pred);
443 fprintf(stderr, "%12s = 0x%08x %u\n", a1, aa1, aa1);
444 fprintf(stderr, "%12s = 0x%08x %u\n", a2, aa2, aa2);
445 test_die();
446}
447
448void
449assert_u64(const char *file, int line, const char *a1, const char *a2,
450 u_int64_t aa1, u_int64_t aa2, enum test_predicate pred)
451{
452 TEST_CHECK(aa1, aa2, pred);
453 test_header(file, line, a1, a2, "U64", pred);
454 fprintf(stderr, "%12s = 0x%016llx %llu\n", a1,
455 (unsigned long long)aa1, (unsigned long long)aa1);
456 fprintf(stderr, "%12s = 0x%016llx %llu\n", a2,
457 (unsigned long long)aa2, (unsigned long long)aa2);
458 test_die();
459}
460
461void
462assert_ptr(const char *file, int line, const char *a1, const char *a2,
463 const void *aa1, const void *aa2, enum test_predicate pred)
464{
465 TEST_CHECK(aa1, aa2, pred);
466 test_header(file, line, a1, a2, "PTR", pred);
467 fprintf(stderr, "%12s = %p\n", a1, aa1);
468 fprintf(stderr, "%12s = %p\n", a2, aa2);
469 test_die();
470}
471
diff --git a/regress/unittests/test_helper/test_helper.h b/regress/unittests/test_helper/test_helper.h
new file mode 100644
index 000000000..a398c615f
--- /dev/null
+++ b/regress/unittests/test_helper/test_helper.h
@@ -0,0 +1,292 @@
1/* $OpenBSD: test_helper.h,v 1.3 2014/05/02 09:41:32 andre Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller <djm@mindrot.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* Utility functions/framework for regress tests */
19
20#ifndef _TEST_HELPER_H
21#define _TEST_HELPER_H
22
23#include "includes.h"
24
25#include <sys/types.h>
26#ifdef HAVE_STDINT_H
27# include <stdint.h>
28#endif
29
30#include <openssl/bn.h>
31#include <openssl/err.h>
32
33enum test_predicate {
34 TEST_EQ, TEST_NE, TEST_LT, TEST_LE, TEST_GT, TEST_GE
35};
36typedef void (test_onerror_func_t)(void *);
37
38/* Supplied by test suite */
39void tests(void);
40
41const char *test_data_file(const char *name);
42void test_start(const char *n);
43void set_onerror_func(test_onerror_func_t *f, void *ctx);
44void test_done(void);
45void ssl_err_check(const char *file, int line);
46void assert_bignum(const char *file, int line,
47 const char *a1, const char *a2,
48 const BIGNUM *aa1, const BIGNUM *aa2, enum test_predicate pred);
49void assert_string(const char *file, int line,
50 const char *a1, const char *a2,
51 const char *aa1, const char *aa2, enum test_predicate pred);
52void assert_mem(const char *file, int line,
53 const char *a1, const char *a2,
54 const void *aa1, const void *aa2, size_t l, enum test_predicate pred);
55void assert_mem_filled(const char *file, int line,
56 const char *a1,
57 const void *aa1, u_char v, size_t l, enum test_predicate pred);
58void assert_int(const char *file, int line,
59 const char *a1, const char *a2,
60 int aa1, int aa2, enum test_predicate pred);
61void assert_size_t(const char *file, int line,
62 const char *a1, const char *a2,
63 size_t aa1, size_t aa2, enum test_predicate pred);
64void assert_u_int(const char *file, int line,
65 const char *a1, const char *a2,
66 u_int aa1, u_int aa2, enum test_predicate pred);
67void assert_long_long(const char *file, int line,
68 const char *a1, const char *a2,
69 long long aa1, long long aa2, enum test_predicate pred);
70void assert_char(const char *file, int line,
71 const char *a1, const char *a2,
72 char aa1, char aa2, enum test_predicate pred);
73void assert_ptr(const char *file, int line,
74 const char *a1, const char *a2,
75 const void *aa1, const void *aa2, enum test_predicate pred);
76void assert_u8(const char *file, int line,
77 const char *a1, const char *a2,
78 u_int8_t aa1, u_int8_t aa2, enum test_predicate pred);
79void assert_u16(const char *file, int line,
80 const char *a1, const char *a2,
81 u_int16_t aa1, u_int16_t aa2, enum test_predicate pred);
82void assert_u32(const char *file, int line,
83 const char *a1, const char *a2,
84 u_int32_t aa1, u_int32_t aa2, enum test_predicate pred);
85void assert_u64(const char *file, int line,
86 const char *a1, const char *a2,
87 u_int64_t aa1, u_int64_t aa2, enum test_predicate pred);
88
89#define TEST_START(n) test_start(n)
90#define TEST_DONE() test_done()
91#define TEST_ONERROR(f, c) set_onerror_func(f, c)
92#define SSL_ERR_CHECK() ssl_err_check(__FILE__, __LINE__)
93
94#define ASSERT_BIGNUM_EQ(a1, a2) \
95 assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
96#define ASSERT_STRING_EQ(a1, a2) \
97 assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
98#define ASSERT_MEM_EQ(a1, a2, l) \
99 assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_EQ)
100#define ASSERT_MEM_FILLED_EQ(a1, c, l) \
101 assert_mem_filled(__FILE__, __LINE__, #a1, a1, c, l, TEST_EQ)
102#define ASSERT_MEM_ZERO_EQ(a1, l) \
103 assert_mem_filled(__FILE__, __LINE__, #a1, a1, '\0', l, TEST_EQ)
104#define ASSERT_INT_EQ(a1, a2) \
105 assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
106#define ASSERT_SIZE_T_EQ(a1, a2) \
107 assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
108#define ASSERT_U_INT_EQ(a1, a2) \
109 assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
110#define ASSERT_LONG_LONG_EQ(a1, a2) \
111 assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
112#define ASSERT_CHAR_EQ(a1, a2) \
113 assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
114#define ASSERT_PTR_EQ(a1, a2) \
115 assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
116#define ASSERT_U8_EQ(a1, a2) \
117 assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
118#define ASSERT_U16_EQ(a1, a2) \
119 assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
120#define ASSERT_U32_EQ(a1, a2) \
121 assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
122#define ASSERT_U64_EQ(a1, a2) \
123 assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_EQ)
124
125#define ASSERT_BIGNUM_NE(a1, a2) \
126 assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
127#define ASSERT_STRING_NE(a1, a2) \
128 assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
129#define ASSERT_MEM_NE(a1, a2, l) \
130 assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_NE)
131#define ASSERT_MEM_ZERO_NE(a1, l) \
132 assert_mem_filled(__FILE__, __LINE__, #a1, a1, '\0', l, TEST_NE)
133#define ASSERT_INT_NE(a1, a2) \
134 assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
135#define ASSERT_SIZE_T_NE(a1, a2) \
136 assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
137#define ASSERT_U_INT_NE(a1, a2) \
138 assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
139#define ASSERT_LONG_LONG_NE(a1, a2) \
140 assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
141#define ASSERT_CHAR_NE(a1, a2) \
142 assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
143#define ASSERT_PTR_NE(a1, a2) \
144 assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
145#define ASSERT_U8_NE(a1, a2) \
146 assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
147#define ASSERT_U16_NE(a1, a2) \
148 assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
149#define ASSERT_U32_NE(a1, a2) \
150 assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
151#define ASSERT_U64_NE(a1, a2) \
152 assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_NE)
153
154#define ASSERT_BIGNUM_LT(a1, a2) \
155 assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
156#define ASSERT_STRING_LT(a1, a2) \
157 assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
158#define ASSERT_MEM_LT(a1, a2, l) \
159 assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_LT)
160#define ASSERT_INT_LT(a1, a2) \
161 assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
162#define ASSERT_SIZE_T_LT(a1, a2) \
163 assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
164#define ASSERT_U_INT_LT(a1, a2) \
165 assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
166#define ASSERT_LONG_LONG_LT(a1, a2) \
167 assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
168#define ASSERT_CHAR_LT(a1, a2) \
169 assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
170#define ASSERT_PTR_LT(a1, a2) \
171 assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
172#define ASSERT_U8_LT(a1, a2) \
173 assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
174#define ASSERT_U16_LT(a1, a2) \
175 assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
176#define ASSERT_U32_LT(a1, a2) \
177 assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
178#define ASSERT_U64_LT(a1, a2) \
179 assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LT)
180
181#define ASSERT_BIGNUM_LE(a1, a2) \
182 assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
183#define ASSERT_STRING_LE(a1, a2) \
184 assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
185#define ASSERT_MEM_LE(a1, a2, l) \
186 assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_LE)
187#define ASSERT_INT_LE(a1, a2) \
188 assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
189#define ASSERT_SIZE_T_LE(a1, a2) \
190 assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
191#define ASSERT_U_INT_LE(a1, a2) \
192 assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
193#define ASSERT_LONG_LONG_LE(a1, a2) \
194 assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
195#define ASSERT_CHAR_LE(a1, a2) \
196 assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
197#define ASSERT_PTR_LE(a1, a2) \
198 assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
199#define ASSERT_U8_LE(a1, a2) \
200 assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
201#define ASSERT_U16_LE(a1, a2) \
202 assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
203#define ASSERT_U32_LE(a1, a2) \
204 assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
205#define ASSERT_U64_LE(a1, a2) \
206 assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_LE)
207
208#define ASSERT_BIGNUM_GT(a1, a2) \
209 assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
210#define ASSERT_STRING_GT(a1, a2) \
211 assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
212#define ASSERT_MEM_GT(a1, a2, l) \
213 assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_GT)
214#define ASSERT_INT_GT(a1, a2) \
215 assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
216#define ASSERT_SIZE_T_GT(a1, a2) \
217 assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
218#define ASSERT_U_INT_GT(a1, a2) \
219 assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
220#define ASSERT_LONG_LONG_GT(a1, a2) \
221 assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
222#define ASSERT_CHAR_GT(a1, a2) \
223 assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
224#define ASSERT_PTR_GT(a1, a2) \
225 assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
226#define ASSERT_U8_GT(a1, a2) \
227 assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
228#define ASSERT_U16_GT(a1, a2) \
229 assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
230#define ASSERT_U32_GT(a1, a2) \
231 assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
232#define ASSERT_U64_GT(a1, a2) \
233 assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GT)
234
235#define ASSERT_BIGNUM_GE(a1, a2) \
236 assert_bignum(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
237#define ASSERT_STRING_GE(a1, a2) \
238 assert_string(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
239#define ASSERT_MEM_GE(a1, a2, l) \
240 assert_mem(__FILE__, __LINE__, #a1, #a2, a1, a2, l, TEST_GE)
241#define ASSERT_INT_GE(a1, a2) \
242 assert_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
243#define ASSERT_SIZE_T_GE(a1, a2) \
244 assert_size_t(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
245#define ASSERT_U_INT_GE(a1, a2) \
246 assert_u_int(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
247#define ASSERT_LONG_LONG_GE(a1, a2) \
248 assert_long_long(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
249#define ASSERT_CHAR_GE(a1, a2) \
250 assert_char(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
251#define ASSERT_PTR_GE(a1, a2) \
252 assert_ptr(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
253#define ASSERT_U8_GE(a1, a2) \
254 assert_u8(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
255#define ASSERT_U16_GE(a1, a2) \
256 assert_u16(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
257#define ASSERT_U32_GE(a1, a2) \
258 assert_u32(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
259#define ASSERT_U64_GE(a1, a2) \
260 assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
261
262/* Fuzzing support */
263
264struct fuzz;
265#define FUZZ_1_BIT_FLIP 0x00000001 /* Flip one bit at a time */
266#define FUZZ_2_BIT_FLIP 0x00000002 /* Flip two bits at a time */
267#define FUZZ_1_BYTE_FLIP 0x00000004 /* Flip one byte at a time */
268#define FUZZ_2_BYTE_FLIP 0x00000008 /* Flip two bytes at a time */
269#define FUZZ_TRUNCATE_START 0x00000010 /* Truncate from beginning */
270#define FUZZ_TRUNCATE_END 0x00000020 /* Truncate from end */
271#define FUZZ_BASE64 0x00000040 /* Try all base64 chars */
272#define FUZZ_MAX FUZZ_BASE64
273
274/* Start fuzzing a blob of data with selected strategies (bitmask) */
275struct fuzz *fuzz_begin(u_int strategies, const void *p, size_t l);
276
277/* Free a fuzz context */
278void fuzz_cleanup(struct fuzz *fuzz);
279
280/* Prepare the next fuzz case in the series */
281void fuzz_next(struct fuzz *fuzz);
282
283/* Determine whether the current fuzz sequence is exhausted (nonzero = yes) */
284int fuzz_done(struct fuzz *fuzz);
285
286/* Return the length and a pointer to the current fuzzed case */
287size_t fuzz_len(struct fuzz *fuzz);
288u_char *fuzz_ptr(struct fuzz *fuzz);
289
290/* Dump the current fuzz case to stderr */
291void fuzz_dump(struct fuzz *fuzz);
292#endif /* _TEST_HELPER_H */
diff --git a/rijndael.c b/rijndael.c
index 7432ea2e4..cde90789e 100644
--- a/rijndael.c
+++ b/rijndael.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: rijndael.c,v 1.16 2004/06/23 00:39:38 mouring Exp $ */ 1/* $OpenBSD: rijndael.c,v 1.18 2014/04/29 15:42:07 markus Exp $ */
2 2
3/** 3/**
4 * rijndael-alg-fst.c 4 * rijndael-alg-fst.c
@@ -25,6 +25,7 @@
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28
28#include "includes.h" 29#include "includes.h"
29 30
30#include <stdlib.h> 31#include <stdlib.h>
@@ -32,7 +33,7 @@
32 33
33#include "rijndael.h" 34#include "rijndael.h"
34 35
35#define FULL_UNROLL 36#undef FULL_UNROLL
36 37
37/* 38/*
38Te0[x] = S [x].[02, 01, 01, 03]; 39Te0[x] = S [x].[02, 01, 01, 03];
@@ -247,7 +248,6 @@ static const u32 Te2[256] = {
247 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, 248 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
248}; 249};
249static const u32 Te3[256] = { 250static const u32 Te3[256] = {
250
251 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 251 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
252 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 252 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
253 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 253 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
@@ -532,7 +532,6 @@ static const u32 Td2[256] = {
532 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, 532 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
533 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 533 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
534 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, 534 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
535
536 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 535 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
537 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 536 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
538 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, 537 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
@@ -724,8 +723,10 @@ static const u32 rcon[] = {
724 * 723 *
725 * @return the number of rounds for the given cipher key size. 724 * @return the number of rounds for the given cipher key size.
726 */ 725 */
727static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { 726int
728 int i = 0; 727rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits)
728{
729 int i = 0;
729 u32 temp; 730 u32 temp;
730 731
731 rk[0] = GETU32(cipherKey ); 732 rk[0] = GETU32(cipherKey );
@@ -786,9 +787,9 @@ static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int
786 rk[ 9] = rk[ 1] ^ rk[ 8]; 787 rk[ 9] = rk[ 1] ^ rk[ 8];
787 rk[10] = rk[ 2] ^ rk[ 9]; 788 rk[10] = rk[ 2] ^ rk[ 9];
788 rk[11] = rk[ 3] ^ rk[10]; 789 rk[11] = rk[ 3] ^ rk[10];
789 if (++i == 7) { 790 if (++i == 7) {
790 return 14; 791 return 14;
791 } 792 }
792 temp = rk[11]; 793 temp = rk[11];
793 rk[12] = rk[ 4] ^ 794 rk[12] = rk[ 4] ^
794 (Te4[(temp >> 24) ] & 0xff000000) ^ 795 (Te4[(temp >> 24) ] & 0xff000000) ^
@@ -797,7 +798,7 @@ static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int
797 (Te4[(temp ) & 0xff] & 0x000000ff); 798 (Te4[(temp ) & 0xff] & 0x000000ff);
798 rk[13] = rk[ 5] ^ rk[12]; 799 rk[13] = rk[ 5] ^ rk[12];
799 rk[14] = rk[ 6] ^ rk[13]; 800 rk[14] = rk[ 6] ^ rk[13];
800 rk[15] = rk[ 7] ^ rk[14]; 801 rk[15] = rk[ 7] ^ rk[14];
801 rk += 8; 802 rk += 8;
802 } 803 }
803 } 804 }
@@ -809,18 +810,21 @@ static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int
809 * 810 *
810 * @return the number of rounds for the given cipher key size. 811 * @return the number of rounds for the given cipher key size.
811 */ 812 */
812static int 813int
813rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits, 814rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits,
814 int have_encrypt) { 815 int have_encrypt)
816{
815 int Nr, i, j; 817 int Nr, i, j;
816 u32 temp; 818 u32 temp;
817 819
818 if (have_encrypt) { 820 /* expand the cipher key: */
821 if (have_encrypt > 0) {
822 /* Already done */
819 Nr = have_encrypt; 823 Nr = have_encrypt;
820 } else { 824 } else {
821 /* expand the cipher key: */
822 Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); 825 Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
823 } 826 }
827
824 /* invert the order of the round keys: */ 828 /* invert the order of the round keys: */
825 for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { 829 for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
826 temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; 830 temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp;
@@ -855,7 +859,10 @@ rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits,
855 return Nr; 859 return Nr;
856} 860}
857 861
858static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) { 862void
863rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16],
864 u8 ct[16])
865{
859 u32 s0, s1, s2, s3, t0, t1, t2, t3; 866 u32 s0, s1, s2, s3, t0, t1, t2, t3;
860#ifndef FULL_UNROLL 867#ifndef FULL_UNROLL
861 int r; 868 int r;
@@ -871,50 +878,50 @@ static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16
871 s3 = GETU32(pt + 12) ^ rk[3]; 878 s3 = GETU32(pt + 12) ^ rk[3];
872#ifdef FULL_UNROLL 879#ifdef FULL_UNROLL
873 /* round 1: */ 880 /* round 1: */
874 t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; 881 t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
875 t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; 882 t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
876 t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; 883 t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
877 t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; 884 t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
878 /* round 2: */ 885 /* round 2: */
879 s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; 886 s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
880 s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; 887 s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
881 s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; 888 s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
882 s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; 889 s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
883 /* round 3: */ 890 /* round 3: */
884 t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; 891 t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
885 t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; 892 t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
886 t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; 893 t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
887 t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; 894 t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
888 /* round 4: */ 895 /* round 4: */
889 s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; 896 s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
890 s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; 897 s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
891 s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; 898 s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
892 s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; 899 s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
893 /* round 5: */ 900 /* round 5: */
894 t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; 901 t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
895 t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; 902 t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
896 t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; 903 t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
897 t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; 904 t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
898 /* round 6: */ 905 /* round 6: */
899 s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; 906 s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
900 s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; 907 s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
901 s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; 908 s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
902 s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; 909 s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
903 /* round 7: */ 910 /* round 7: */
904 t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; 911 t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
905 t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; 912 t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
906 t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; 913 t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
907 t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; 914 t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
908 /* round 8: */ 915 /* round 8: */
909 s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; 916 s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
910 s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; 917 s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
911 s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; 918 s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
912 s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; 919 s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
913 /* round 9: */ 920 /* round 9: */
914 t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; 921 t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
915 t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; 922 t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
916 t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; 923 t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
917 t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; 924 t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
918 if (Nr > 10) { 925 if (Nr > 10) {
919 /* round 10: */ 926 /* round 10: */
920 s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; 927 s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
@@ -1036,7 +1043,10 @@ static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16
1036 PUTU32(ct + 12, s3); 1043 PUTU32(ct + 12, s3);
1037} 1044}
1038 1045
1039static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) { 1046static void
1047rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16],
1048 u8 pt[16])
1049{
1040 u32 s0, s1, s2, s3, t0, t1, t2, t3; 1050 u32 s0, s1, s2, s3, t0, t1, t2, t3;
1041#ifndef FULL_UNROLL 1051#ifndef FULL_UNROLL
1042 int r; 1052 int r;
@@ -1187,33 +1197,33 @@ static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16
1187 * apply last round and 1197 * apply last round and
1188 * map cipher state to byte array block: 1198 * map cipher state to byte array block:
1189 */ 1199 */
1190 s0 = 1200 s0 =
1191 (Td4[(t0 >> 24) ] & 0xff000000) ^ 1201 (Td4[(t0 >> 24) ] & 0xff000000) ^
1192 (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ 1202 (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
1193 (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ 1203 (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
1194 (Td4[(t1 ) & 0xff] & 0x000000ff) ^ 1204 (Td4[(t1 ) & 0xff] & 0x000000ff) ^
1195 rk[0]; 1205 rk[0];
1196 PUTU32(pt , s0); 1206 PUTU32(pt , s0);
1197 s1 = 1207 s1 =
1198 (Td4[(t1 >> 24) ] & 0xff000000) ^ 1208 (Td4[(t1 >> 24) ] & 0xff000000) ^
1199 (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ 1209 (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
1200 (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ 1210 (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
1201 (Td4[(t2 ) & 0xff] & 0x000000ff) ^ 1211 (Td4[(t2 ) & 0xff] & 0x000000ff) ^
1202 rk[1]; 1212 rk[1];
1203 PUTU32(pt + 4, s1); 1213 PUTU32(pt + 4, s1);
1204 s2 = 1214 s2 =
1205 (Td4[(t2 >> 24) ] & 0xff000000) ^ 1215 (Td4[(t2 >> 24) ] & 0xff000000) ^
1206 (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ 1216 (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
1207 (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ 1217 (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
1208 (Td4[(t3 ) & 0xff] & 0x000000ff) ^ 1218 (Td4[(t3 ) & 0xff] & 0x000000ff) ^
1209 rk[2]; 1219 rk[2];
1210 PUTU32(pt + 8, s2); 1220 PUTU32(pt + 8, s2);
1211 s3 = 1221 s3 =
1212 (Td4[(t3 >> 24) ] & 0xff000000) ^ 1222 (Td4[(t3 >> 24) ] & 0xff000000) ^
1213 (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ 1223 (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
1214 (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ 1224 (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
1215 (Td4[(t0 ) & 0xff] & 0x000000ff) ^ 1225 (Td4[(t0 ) & 0xff] & 0x000000ff) ^
1216 rk[3]; 1226 rk[3];
1217 PUTU32(pt + 12, s3); 1227 PUTU32(pt + 12, s3);
1218} 1228}
1219 1229
diff --git a/rijndael.h b/rijndael.h
index c614bb188..53e74e0a8 100644
--- a/rijndael.h
+++ b/rijndael.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: rijndael.h,v 1.12 2001/12/19 07:18:56 deraadt Exp $ */ 1/* $OpenBSD: rijndael.h,v 1.14 2014/04/29 15:42:07 markus Exp $ */
2 2
3/** 3/**
4 * rijndael-alg-fst.h 4 * rijndael-alg-fst.h
@@ -25,27 +25,32 @@
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28#ifndef __RIJNDAEL_H 28#ifndef _PRIVATE_RIJNDAEL_H
29#define __RIJNDAEL_H 29#define _PRIVATE_RIJNDAEL_H
30 30
31#define MAXKC (256/32) 31#define AES_MAXKEYBITS (256)
32#define MAXKB (256/8) 32#define AES_MAXKEYBYTES (AES_MAXKEYBITS/8)
33#define MAXNR 14 33/* for 256-bit keys, fewer for less */
34#define AES_MAXROUNDS 14
34 35
35typedef unsigned char u8; 36typedef unsigned char u8;
36typedef unsigned short u16; 37typedef unsigned short u16;
37typedef unsigned int u32; 38typedef unsigned int u32;
38 39
40int rijndaelKeySetupEnc(unsigned int [], const unsigned char [], int);
41void rijndaelEncrypt(const unsigned int [], int, const unsigned char [],
42 unsigned char []);
43
39/* The structure for key information */ 44/* The structure for key information */
40typedef struct { 45typedef struct {
41 int decrypt; 46 int decrypt;
42 int Nr; /* key-length-dependent number of rounds */ 47 int Nr; /* key-length-dependent number of rounds */
43 u32 ek[4*(MAXNR + 1)]; /* encrypt key schedule */ 48 u32 ek[4*(AES_MAXROUNDS + 1)]; /* encrypt key schedule */
44 u32 dk[4*(MAXNR + 1)]; /* decrypt key schedule */ 49 u32 dk[4*(AES_MAXROUNDS + 1)]; /* decrypt key schedule */
45} rijndael_ctx; 50} rijndael_ctx;
46 51
47void rijndael_set_key(rijndael_ctx *, u_char *, int, int); 52void rijndael_set_key(rijndael_ctx *, u_char *, int, int);
48void rijndael_decrypt(rijndael_ctx *, u_char *, u_char *); 53void rijndael_decrypt(rijndael_ctx *, u_char *, u_char *);
49void rijndael_encrypt(rijndael_ctx *, u_char *, u_char *); 54void rijndael_encrypt(rijndael_ctx *, u_char *, u_char *);
50 55
51#endif /* __RIJNDAEL_H */ 56#endif /* _PRIVATE_RIJNDAEL_H */
diff --git a/roaming_client.c b/roaming_client.c
index de049cdc1..5e5c28b2b 100644
--- a/roaming_client.c
+++ b/roaming_client.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: roaming_client.c,v 1.7 2014/01/09 23:20:00 djm Exp $ */ 1/* $OpenBSD: roaming_client.c,v 1.8 2014/04/29 18:01:49 markus Exp $ */
2/* 2/*
3 * Copyright (c) 2004-2009 AppGate Network Security AB 3 * Copyright (c) 2004-2009 AppGate Network Security AB
4 * 4 *
@@ -28,9 +28,6 @@
28#include <string.h> 28#include <string.h>
29#include <unistd.h> 29#include <unistd.h>
30 30
31#include <openssl/crypto.h>
32#include <openssl/sha.h>
33
34#include "xmalloc.h" 31#include "xmalloc.h"
35#include "buffer.h" 32#include "buffer.h"
36#include "channels.h" 33#include "channels.h"
diff --git a/rsa.c b/rsa.c
index d0b5bbf5e..5ecacef90 100644
--- a/rsa.c
+++ b/rsa.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: rsa.c,v 1.31 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: rsa.c,v 1.32 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -67,85 +67,122 @@
67#include <stdarg.h> 67#include <stdarg.h>
68#include <string.h> 68#include <string.h>
69 69
70#include "xmalloc.h"
71#include "rsa.h" 70#include "rsa.h"
72#include "log.h" 71#include "log.h"
72#include "ssherr.h"
73 73
74void 74int
75rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key) 75rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
76{ 76{
77 u_char *inbuf, *outbuf; 77 u_char *inbuf = NULL, *outbuf = NULL;
78 int len, ilen, olen; 78 int len, ilen, olen, r = SSH_ERR_INTERNAL_ERROR;
79 79
80 if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e)) 80 if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e))
81 fatal("rsa_public_encrypt() exponent too small or not odd"); 81 return SSH_ERR_INVALID_ARGUMENT;
82 82
83 olen = BN_num_bytes(key->n); 83 olen = BN_num_bytes(key->n);
84 outbuf = xmalloc(olen); 84 if ((outbuf = malloc(olen)) == NULL) {
85 r = SSH_ERR_ALLOC_FAIL;
86 goto out;
87 }
85 88
86 ilen = BN_num_bytes(in); 89 ilen = BN_num_bytes(in);
87 inbuf = xmalloc(ilen); 90 if ((inbuf = malloc(ilen)) == NULL) {
91 r = SSH_ERR_ALLOC_FAIL;
92 goto out;
93 }
88 BN_bn2bin(in, inbuf); 94 BN_bn2bin(in, inbuf);
89 95
90 if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key, 96 if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key,
91 RSA_PKCS1_PADDING)) <= 0) 97 RSA_PKCS1_PADDING)) <= 0) {
92 fatal("rsa_public_encrypt() failed"); 98 r = SSH_ERR_LIBCRYPTO_ERROR;
99 goto out;
100 }
93 101
94 if (BN_bin2bn(outbuf, len, out) == NULL) 102 if (BN_bin2bn(outbuf, len, out) == NULL) {
95 fatal("rsa_public_encrypt: BN_bin2bn failed"); 103 r = SSH_ERR_LIBCRYPTO_ERROR;
104 goto out;
105 }
106 r = 0;
96 107
97 explicit_bzero(outbuf, olen); 108 out:
98 explicit_bzero(inbuf, ilen); 109 if (outbuf != NULL) {
99 free(outbuf); 110 explicit_bzero(outbuf, olen);
100 free(inbuf); 111 free(outbuf);
112 }
113 if (inbuf != NULL) {
114 explicit_bzero(inbuf, ilen);
115 free(inbuf);
116 }
117 return r;
101} 118}
102 119
103int 120int
104rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key) 121rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
105{ 122{
106 u_char *inbuf, *outbuf; 123 u_char *inbuf = NULL, *outbuf = NULL;
107 int len, ilen, olen; 124 int len, ilen, olen, r = SSH_ERR_INTERNAL_ERROR;
108 125
109 olen = BN_num_bytes(key->n); 126 olen = BN_num_bytes(key->n);
110 outbuf = xmalloc(olen); 127 if ((outbuf = malloc(olen)) == NULL) {
128 r = SSH_ERR_ALLOC_FAIL;
129 goto out;
130 }
111 131
112 ilen = BN_num_bytes(in); 132 ilen = BN_num_bytes(in);
113 inbuf = xmalloc(ilen); 133 if ((inbuf = malloc(ilen)) == NULL) {
134 r = SSH_ERR_ALLOC_FAIL;
135 goto out;
136 }
114 BN_bn2bin(in, inbuf); 137 BN_bn2bin(in, inbuf);
115 138
116 if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key, 139 if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key,
117 RSA_PKCS1_PADDING)) <= 0) { 140 RSA_PKCS1_PADDING)) <= 0) {
118 error("rsa_private_decrypt() failed"); 141 r = SSH_ERR_LIBCRYPTO_ERROR;
119 } else { 142 goto out;
120 if (BN_bin2bn(outbuf, len, out) == NULL) 143 } else if (BN_bin2bn(outbuf, len, out) == NULL) {
121 fatal("rsa_private_decrypt: BN_bin2bn failed"); 144 r = SSH_ERR_LIBCRYPTO_ERROR;
145 goto out;
146 }
147 r = 0;
148 out:
149 if (outbuf != NULL) {
150 explicit_bzero(outbuf, olen);
151 free(outbuf);
152 }
153 if (inbuf != NULL) {
154 explicit_bzero(inbuf, ilen);
155 free(inbuf);
122 } 156 }
123 explicit_bzero(outbuf, olen); 157 return r;
124 explicit_bzero(inbuf, ilen);
125 free(outbuf);
126 free(inbuf);
127 return len;
128} 158}
129 159
130/* calculate p-1 and q-1 */ 160/* calculate p-1 and q-1 */
131void 161int
132rsa_generate_additional_parameters(RSA *rsa) 162rsa_generate_additional_parameters(RSA *rsa)
133{ 163{
134 BIGNUM *aux; 164 BIGNUM *aux = NULL;
135 BN_CTX *ctx; 165 BN_CTX *ctx = NULL;
166 int r;
136 167
137 if ((aux = BN_new()) == NULL)
138 fatal("rsa_generate_additional_parameters: BN_new failed");
139 if ((ctx = BN_CTX_new()) == NULL) 168 if ((ctx = BN_CTX_new()) == NULL)
140 fatal("rsa_generate_additional_parameters: BN_CTX_new failed"); 169 return SSH_ERR_ALLOC_FAIL;
170 if ((aux = BN_new()) == NULL) {
171 r = SSH_ERR_ALLOC_FAIL;
172 goto out;
173 }
141 174
142 if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) || 175 if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) ||
143 (BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) || 176 (BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) ||
144 (BN_sub(aux, rsa->p, BN_value_one()) == 0) || 177 (BN_sub(aux, rsa->p, BN_value_one()) == 0) ||
145 (BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0)) 178 (BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0)) {
146 fatal("rsa_generate_additional_parameters: BN_sub/mod failed"); 179 r = SSH_ERR_LIBCRYPTO_ERROR;
147 180 goto out;
181 }
182 r = 0;
183 out:
148 BN_clear_free(aux); 184 BN_clear_free(aux);
149 BN_CTX_free(ctx); 185 BN_CTX_free(ctx);
186 return r;
150} 187}
151 188
diff --git a/rsa.h b/rsa.h
index b841ea4e1..c476707d5 100644
--- a/rsa.h
+++ b/rsa.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: rsa.h,v 1.16 2006/03/25 22:22:43 djm Exp $ */ 1/* $OpenBSD: rsa.h,v 1.17 2014/06/24 01:13:21 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -19,8 +19,8 @@
19#include <openssl/bn.h> 19#include <openssl/bn.h>
20#include <openssl/rsa.h> 20#include <openssl/rsa.h>
21 21
22void rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *); 22int rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *);
23int rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *); 23int rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *);
24void rsa_generate_additional_parameters(RSA *); 24int rsa_generate_additional_parameters(RSA *);
25 25
26#endif /* RSA_H */ 26#endif /* RSA_H */
diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c
index c0c17c2fc..b6f6258f2 100644
--- a/sandbox-seccomp-filter.c
+++ b/sandbox-seccomp-filter.c
@@ -25,6 +25,8 @@
25 */ 25 */
26/* #define SANDBOX_SECCOMP_FILTER_DEBUG 1 */ 26/* #define SANDBOX_SECCOMP_FILTER_DEBUG 1 */
27 27
28/* XXX it should be possible to do logging via the log socket safely */
29
28#ifdef SANDBOX_SECCOMP_FILTER_DEBUG 30#ifdef SANDBOX_SECCOMP_FILTER_DEBUG
29/* Use the kernel headers in case of an older toolchain. */ 31/* Use the kernel headers in case of an older toolchain. */
30# include <asm/siginfo.h> 32# include <asm/siginfo.h>
@@ -89,6 +91,7 @@ static const struct sock_filter preauth_insns[] = {
89 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 91 BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
90 offsetof(struct seccomp_data, nr)), 92 offsetof(struct seccomp_data, nr)),
91 SC_DENY(open, EACCES), 93 SC_DENY(open, EACCES),
94 SC_DENY(stat, EACCES),
92 SC_ALLOW(getpid), 95 SC_ALLOW(getpid),
93 SC_ALLOW(gettimeofday), 96 SC_ALLOW(gettimeofday),
94 SC_ALLOW(clock_gettime), 97 SC_ALLOW(clock_gettime),
@@ -115,6 +118,10 @@ static const struct sock_filter preauth_insns[] = {
115#ifdef __NR_mmap 118#ifdef __NR_mmap
116 SC_ALLOW(mmap), 119 SC_ALLOW(mmap),
117#endif 120#endif
121#ifdef __dietlibc__
122 SC_ALLOW(mremap),
123 SC_ALLOW(exit),
124#endif
118 SC_ALLOW(munmap), 125 SC_ALLOW(munmap),
119 SC_ALLOW(exit_group), 126 SC_ALLOW(exit_group),
120#ifdef __NR_rt_sigprocmask 127#ifdef __NR_rt_sigprocmask
diff --git a/sandbox-systrace.c b/sandbox-systrace.c
index 6706c9a80..aaa3d8f0a 100644
--- a/sandbox-systrace.c
+++ b/sandbox-systrace.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sandbox-systrace.c,v 1.9 2014/01/31 16:39:19 tedu Exp $ */ 1/* $OpenBSD: sandbox-systrace.c,v 1.13 2014/07/17 00:10:56 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2011 Damien Miller <djm@mindrot.org> 3 * Copyright (c) 2011 Damien Miller <djm@mindrot.org>
4 * 4 *
@@ -52,7 +52,17 @@ struct sandbox_policy {
52static const struct sandbox_policy preauth_policy[] = { 52static const struct sandbox_policy preauth_policy[] = {
53 { SYS_open, SYSTR_POLICY_NEVER }, 53 { SYS_open, SYSTR_POLICY_NEVER },
54 54
55#ifdef SYS_getentropy
56 /* OpenBSD 5.6 and newer use getentropy(2) to seed arc4random(3). */
57 { SYS_getentropy, SYSTR_POLICY_PERMIT },
58#else
59 /* Previous releases used sysctl(3)'s kern.arnd variable. */
55 { SYS___sysctl, SYSTR_POLICY_PERMIT }, 60 { SYS___sysctl, SYSTR_POLICY_PERMIT },
61#endif
62
63#ifdef SYS_sendsyslog
64 { SYS_sendsyslog, SYSTR_POLICY_PERMIT },
65#endif
56 { SYS_close, SYSTR_POLICY_PERMIT }, 66 { SYS_close, SYSTR_POLICY_PERMIT },
57 { SYS_exit, SYSTR_POLICY_PERMIT }, 67 { SYS_exit, SYSTR_POLICY_PERMIT },
58 { SYS_getpid, SYSTR_POLICY_PERMIT }, 68 { SYS_getpid, SYSTR_POLICY_PERMIT },
diff --git a/scp.0 b/scp.0
index b9eeffc4e..0495f2555 100644
--- a/scp.0
+++ b/scp.0
@@ -1,4 +1,4 @@
1SCP(1) OpenBSD Reference Manual SCP(1) 1SCP(1) General Commands Manual SCP(1)
2 2
3NAME 3NAME
4 scp - secure copy (remote file copy program) 4 scp - secure copy (remote file copy program)
@@ -11,8 +11,8 @@ SYNOPSIS
11DESCRIPTION 11DESCRIPTION
12 scp copies files between hosts on a network. It uses ssh(1) for data 12 scp copies files between hosts on a network. It uses ssh(1) for data
13 transfer, and uses the same authentication and provides the same security 13 transfer, and uses the same authentication and provides the same security
14 as ssh(1). Unlike rcp(1), scp will ask for passwords or passphrases if 14 as ssh(1). scp will ask for passwords or passphrases if they are needed
15 they are needed for authentication. 15 for authentication.
16 16
17 File names may contain a user and host specification to indicate that the 17 File names may contain a user and host specification to indicate that the
18 file is to be copied to/from that host. Local file names can be made 18 file is to be copied to/from that host. Local file names can be made
@@ -125,8 +125,7 @@ DESCRIPTION
125 -P port 125 -P port
126 Specifies the port to connect to on the remote host. Note that 126 Specifies the port to connect to on the remote host. Note that
127 this option is written with a capital `P', because -p is already 127 this option is written with a capital `P', because -p is already
128 reserved for preserving the times and modes of the file in 128 reserved for preserving the times and modes of the file.
129 rcp(1).
130 129
131 -p Preserves modification times, access times, and modes from the 130 -p Preserves modification times, access times, and modes from the
132 original file. 131 original file.
@@ -149,15 +148,15 @@ EXIT STATUS
149 The scp utility exits 0 on success, and >0 if an error occurs. 148 The scp utility exits 0 on success, and >0 if an error occurs.
150 149
151SEE ALSO 150SEE ALSO
152 rcp(1), sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), 151 sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), ssh_config(5),
153 ssh_config(5), sshd(8) 152 sshd(8)
154 153
155HISTORY 154HISTORY
156 scp is based on the rcp(1) program in BSD source code from the Regents of 155 scp is based on the rcp program in BSD source code from the Regents of
157 the University of California. 156 the University of California.
158 157
159AUTHORS 158AUTHORS
160 Timo Rinne <tri@iki.fi> 159 Timo Rinne <tri@iki.fi>
161 Tatu Ylonen <ylo@cs.hut.fi> 160 Tatu Ylonen <ylo@cs.hut.fi>
162 161
163OpenBSD 5.5 October 20, 2013 OpenBSD 5.5 162OpenBSD 5.6 March 19, 2014 OpenBSD 5.6
diff --git a/scp.1 b/scp.1
index 3b67cff0e..1791b6189 100644
--- a/scp.1
+++ b/scp.1
@@ -8,9 +8,9 @@
8.\" 8.\"
9.\" Created: Sun May 7 00:14:37 1995 ylo 9.\" Created: Sun May 7 00:14:37 1995 ylo
10.\" 10.\"
11.\" $OpenBSD: scp.1,v 1.61 2013/10/20 09:51:26 djm Exp $ 11.\" $OpenBSD: scp.1,v 1.62 2014/03/19 14:42:44 tedu Exp $
12.\" 12.\"
13.Dd $Mdocdate: October 20 2013 $ 13.Dd $Mdocdate: March 19 2014 $
14.Dt SCP 1 14.Dt SCP 1
15.Os 15.Os
16.Sh NAME 16.Sh NAME
@@ -49,8 +49,6 @@ It uses
49for data transfer, and uses the same authentication and provides the 49for data transfer, and uses the same authentication and provides the
50same security as 50same security as
51.Xr ssh 1 . 51.Xr ssh 1 .
52Unlike
53.Xr rcp 1 ,
54.Nm 52.Nm
55will ask for passwords or passphrases if they are needed for 53will ask for passwords or passphrases if they are needed for
56authentication. 54authentication.
@@ -191,8 +189,7 @@ Note that this option is written with a capital
191.Sq P , 189.Sq P ,
192because 190because
193.Fl p 191.Fl p
194is already reserved for preserving the times and modes of the file in 192is already reserved for preserving the times and modes of the file.
195.Xr rcp 1 .
196.It Fl p 193.It Fl p
197Preserves modification times, access times, and modes from the 194Preserves modification times, access times, and modes from the
198original file. 195original file.
@@ -225,7 +222,6 @@ debugging connection, authentication, and configuration problems.
225.Sh EXIT STATUS 222.Sh EXIT STATUS
226.Ex -std scp 223.Ex -std scp
227.Sh SEE ALSO 224.Sh SEE ALSO
228.Xr rcp 1 ,
229.Xr sftp 1 , 225.Xr sftp 1 ,
230.Xr ssh 1 , 226.Xr ssh 1 ,
231.Xr ssh-add 1 , 227.Xr ssh-add 1 ,
@@ -235,9 +231,7 @@ debugging connection, authentication, and configuration problems.
235.Xr sshd 8 231.Xr sshd 8
236.Sh HISTORY 232.Sh HISTORY
237.Nm 233.Nm
238is based on the 234is based on the rcp program in
239.Xr rcp 1
240program in
241.Bx 235.Bx
242source code from the Regents of the University of California. 236source code from the Regents of the University of California.
243.Sh AUTHORS 237.Sh AUTHORS
diff --git a/scp.c b/scp.c
index 18d3b1dc9..1ec3b7087 100644
--- a/scp.c
+++ b/scp.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: scp.c,v 1.179 2013/11/20 20:53:10 deraadt Exp $ */ 1/* $OpenBSD: scp.c,v 1.180 2014/06/24 02:21:01 djm Exp $ */
2/* 2/*
3 * scp - secure remote copy. This is basically patched BSD rcp which 3 * scp - secure remote copy. This is basically patched BSD rcp which
4 * uses ssh to do the data transfer (instead of using rcmd). 4 * uses ssh to do the data transfer (instead of using rcmd).
@@ -747,7 +747,7 @@ source(int argc, char **argv)
747 static BUF buffer; 747 static BUF buffer;
748 BUF *bp; 748 BUF *bp;
749 off_t i, statbytes; 749 off_t i, statbytes;
750 size_t amt; 750 size_t amt, nr;
751 int fd = -1, haderr, indx; 751 int fd = -1, haderr, indx;
752 char *last, *name, buf[2048], encname[MAXPATHLEN]; 752 char *last, *name, buf[2048], encname[MAXPATHLEN];
753 int len; 753 int len;
@@ -820,12 +820,16 @@ next: if (fd != -1) {
820 if (i + (off_t)amt > stb.st_size) 820 if (i + (off_t)amt > stb.st_size)
821 amt = stb.st_size - i; 821 amt = stb.st_size - i;
822 if (!haderr) { 822 if (!haderr) {
823 if (atomicio(read, fd, bp->buf, amt) != amt) 823 if ((nr = atomicio(read, fd,
824 bp->buf, amt)) != amt) {
824 haderr = errno; 825 haderr = errno;
826 memset(bp->buf + nr, 0, amt - nr);
827 }
825 } 828 }
826 /* Keep writing after error to retain sync */ 829 /* Keep writing after error to retain sync */
827 if (haderr) { 830 if (haderr) {
828 (void)atomicio(vwrite, remout, bp->buf, amt); 831 (void)atomicio(vwrite, remout, bp->buf, amt);
832 memset(bp->buf, 0, amt);
829 continue; 833 continue;
830 } 834 }
831 if (atomicio6(vwrite, remout, bp->buf, amt, scpio, 835 if (atomicio6(vwrite, remout, bp->buf, amt, scpio,
diff --git a/servconf.c b/servconf.c
index 7ba65d51d..b7f329447 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,5 +1,5 @@
1 1
2/* $OpenBSD: servconf.c,v 1.249 2014/01/29 06:18:35 djm Exp $ */ 2/* $OpenBSD: servconf.c,v 1.251 2014/07/15 15:54:14 millert Exp $ */
3/* 3/*
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved 5 * All rights reserved
@@ -39,10 +39,10 @@
39#include "ssh.h" 39#include "ssh.h"
40#include "log.h" 40#include "log.h"
41#include "buffer.h" 41#include "buffer.h"
42#include "misc.h"
42#include "servconf.h" 43#include "servconf.h"
43#include "compat.h" 44#include "compat.h"
44#include "pathnames.h" 45#include "pathnames.h"
45#include "misc.h"
46#include "cipher.h" 46#include "cipher.h"
47#include "key.h" 47#include "key.h"
48#include "kex.h" 48#include "kex.h"
@@ -93,6 +93,7 @@ initialize_server_options(ServerOptions *options)
93 options->x11_display_offset = -1; 93 options->x11_display_offset = -1;
94 options->x11_use_localhost = -1; 94 options->x11_use_localhost = -1;
95 options->permit_tty = -1; 95 options->permit_tty = -1;
96 options->permit_user_rc = -1;
96 options->xauth_location = NULL; 97 options->xauth_location = NULL;
97 options->strict_modes = -1; 98 options->strict_modes = -1;
98 options->tcp_keep_alive = -1; 99 options->tcp_keep_alive = -1;
@@ -119,6 +120,7 @@ initialize_server_options(ServerOptions *options)
119 options->rekey_limit = -1; 120 options->rekey_limit = -1;
120 options->rekey_interval = -1; 121 options->rekey_interval = -1;
121 options->allow_tcp_forwarding = -1; 122 options->allow_tcp_forwarding = -1;
123 options->allow_streamlocal_forwarding = -1;
122 options->allow_agent_forwarding = -1; 124 options->allow_agent_forwarding = -1;
123 options->num_allow_users = 0; 125 options->num_allow_users = 0;
124 options->num_deny_users = 0; 126 options->num_deny_users = 0;
@@ -128,7 +130,9 @@ initialize_server_options(ServerOptions *options)
128 options->macs = NULL; 130 options->macs = NULL;
129 options->kex_algorithms = NULL; 131 options->kex_algorithms = NULL;
130 options->protocol = SSH_PROTO_UNKNOWN; 132 options->protocol = SSH_PROTO_UNKNOWN;
131 options->gateway_ports = -1; 133 options->fwd_opts.gateway_ports = -1;
134 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
135 options->fwd_opts.streamlocal_bind_unlink = -1;
132 options->num_subsystems = 0; 136 options->num_subsystems = 0;
133 options->max_startups_begin = -1; 137 options->max_startups_begin = -1;
134 options->max_startups_rate = -1; 138 options->max_startups_rate = -1;
@@ -216,6 +220,8 @@ fill_default_server_options(ServerOptions *options)
216 options->xauth_location = _PATH_XAUTH; 220 options->xauth_location = _PATH_XAUTH;
217 if (options->permit_tty == -1) 221 if (options->permit_tty == -1)
218 options->permit_tty = 1; 222 options->permit_tty = 1;
223 if (options->permit_user_rc == -1)
224 options->permit_user_rc = 1;
219 if (options->strict_modes == -1) 225 if (options->strict_modes == -1)
220 options->strict_modes = 1; 226 options->strict_modes = 1;
221 if (options->tcp_keep_alive == -1) 227 if (options->tcp_keep_alive == -1)
@@ -266,10 +272,12 @@ fill_default_server_options(ServerOptions *options)
266 options->rekey_interval = 0; 272 options->rekey_interval = 0;
267 if (options->allow_tcp_forwarding == -1) 273 if (options->allow_tcp_forwarding == -1)
268 options->allow_tcp_forwarding = FORWARD_ALLOW; 274 options->allow_tcp_forwarding = FORWARD_ALLOW;
275 if (options->allow_streamlocal_forwarding == -1)
276 options->allow_streamlocal_forwarding = FORWARD_ALLOW;
269 if (options->allow_agent_forwarding == -1) 277 if (options->allow_agent_forwarding == -1)
270 options->allow_agent_forwarding = 1; 278 options->allow_agent_forwarding = 1;
271 if (options->gateway_ports == -1) 279 if (options->fwd_opts.gateway_ports == -1)
272 options->gateway_ports = 0; 280 options->fwd_opts.gateway_ports = 0;
273 if (options->max_startups == -1) 281 if (options->max_startups == -1)
274 options->max_startups = 100; 282 options->max_startups = 100;
275 if (options->max_startups_rate == -1) 283 if (options->max_startups_rate == -1)
@@ -300,6 +308,10 @@ fill_default_server_options(ServerOptions *options)
300 options->ip_qos_bulk = IPTOS_THROUGHPUT; 308 options->ip_qos_bulk = IPTOS_THROUGHPUT;
301 if (options->version_addendum == NULL) 309 if (options->version_addendum == NULL)
302 options->version_addendum = xstrdup(""); 310 options->version_addendum = xstrdup("");
311 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
312 options->fwd_opts.streamlocal_bind_mask = 0177;
313 if (options->fwd_opts.streamlocal_bind_unlink == -1)
314 options->fwd_opts.streamlocal_bind_unlink = 0;
303 /* Turn privilege separation on by default */ 315 /* Turn privilege separation on by default */
304 if (use_privsep == -1) 316 if (use_privsep == -1)
305 use_privsep = PRIVSEP_NOSANDBOX; 317 use_privsep = PRIVSEP_NOSANDBOX;
@@ -347,7 +359,9 @@ typedef enum {
347 sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, 359 sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
348 sKexAlgorithms, sIPQoS, sVersionAddendum, 360 sKexAlgorithms, sIPQoS, sVersionAddendum,
349 sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, 361 sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
350 sAuthenticationMethods, sHostKeyAgent, 362 sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
363 sStreamLocalBindMask, sStreamLocalBindUnlink,
364 sAllowStreamLocalForwarding,
351 sDeprecated, sUnsupported 365 sDeprecated, sUnsupported
352} ServerOpCodes; 366} ServerOpCodes;
353 367
@@ -460,6 +474,7 @@ static struct {
460 { "acceptenv", sAcceptEnv, SSHCFG_ALL }, 474 { "acceptenv", sAcceptEnv, SSHCFG_ALL },
461 { "permittunnel", sPermitTunnel, SSHCFG_ALL }, 475 { "permittunnel", sPermitTunnel, SSHCFG_ALL },
462 { "permittty", sPermitTTY, SSHCFG_ALL }, 476 { "permittty", sPermitTTY, SSHCFG_ALL },
477 { "permituserrc", sPermitUserRC, SSHCFG_ALL },
463 { "match", sMatch, SSHCFG_ALL }, 478 { "match", sMatch, SSHCFG_ALL },
464 { "permitopen", sPermitOpen, SSHCFG_ALL }, 479 { "permitopen", sPermitOpen, SSHCFG_ALL },
465 { "forcecommand", sForceCommand, SSHCFG_ALL }, 480 { "forcecommand", sForceCommand, SSHCFG_ALL },
@@ -474,6 +489,9 @@ static struct {
474 { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL }, 489 { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
475 { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, 490 { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
476 { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL }, 491 { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
492 { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
493 { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
494 { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
477 { NULL, sBadOption, 0 } 495 { NULL, sBadOption, 0 }
478}; 496};
479 497
@@ -1130,6 +1148,10 @@ process_server_config_line(ServerOptions *options, char *line,
1130 intptr = &options->permit_tty; 1148 intptr = &options->permit_tty;
1131 goto parse_flag; 1149 goto parse_flag;
1132 1150
1151 case sPermitUserRC:
1152 intptr = &options->permit_user_rc;
1153 goto parse_flag;
1154
1133 case sStrictModes: 1155 case sStrictModes:
1134 intptr = &options->strict_modes; 1156 intptr = &options->strict_modes;
1135 goto parse_flag; 1157 goto parse_flag;
@@ -1187,7 +1209,7 @@ process_server_config_line(ServerOptions *options, char *line,
1187 break; 1209 break;
1188 1210
1189 case sGatewayPorts: 1211 case sGatewayPorts:
1190 intptr = &options->gateway_ports; 1212 intptr = &options->fwd_opts.gateway_ports;
1191 multistate_ptr = multistate_gatewayports; 1213 multistate_ptr = multistate_gatewayports;
1192 goto parse_multistate; 1214 goto parse_multistate;
1193 1215
@@ -1222,6 +1244,11 @@ process_server_config_line(ServerOptions *options, char *line,
1222 multistate_ptr = multistate_tcpfwd; 1244 multistate_ptr = multistate_tcpfwd;
1223 goto parse_multistate; 1245 goto parse_multistate;
1224 1246
1247 case sAllowStreamLocalForwarding:
1248 intptr = &options->allow_streamlocal_forwarding;
1249 multistate_ptr = multistate_tcpfwd;
1250 goto parse_multistate;
1251
1225 case sAllowAgentForwarding: 1252 case sAllowAgentForwarding:
1226 intptr = &options->allow_agent_forwarding; 1253 intptr = &options->allow_agent_forwarding;
1227 goto parse_flag; 1254 goto parse_flag;
@@ -1620,6 +1647,22 @@ process_server_config_line(ServerOptions *options, char *line,
1620 } 1647 }
1621 return 0; 1648 return 0;
1622 1649
1650 case sStreamLocalBindMask:
1651 arg = strdelim(&cp);
1652 if (!arg || *arg == '\0')
1653 fatal("%s line %d: missing StreamLocalBindMask argument.",
1654 filename, linenum);
1655 /* Parse mode in octal format */
1656 value = strtol(arg, &p, 8);
1657 if (arg == p || value < 0 || value > 0777)
1658 fatal("%s line %d: Bad mask.", filename, linenum);
1659 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1660 break;
1661
1662 case sStreamLocalBindUnlink:
1663 intptr = &options->fwd_opts.streamlocal_bind_unlink;
1664 goto parse_flag;
1665
1623 case sDeprecated: 1666 case sDeprecated:
1624 logit("%s line %d: Deprecated option %s", 1667 logit("%s line %d: Deprecated option %s",
1625 filename, linenum, arg); 1668 filename, linenum, arg);
@@ -1759,13 +1802,15 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
1759 M_CP_INTOPT(permit_empty_passwd); 1802 M_CP_INTOPT(permit_empty_passwd);
1760 1803
1761 M_CP_INTOPT(allow_tcp_forwarding); 1804 M_CP_INTOPT(allow_tcp_forwarding);
1805 M_CP_INTOPT(allow_streamlocal_forwarding);
1762 M_CP_INTOPT(allow_agent_forwarding); 1806 M_CP_INTOPT(allow_agent_forwarding);
1763 M_CP_INTOPT(permit_tun); 1807 M_CP_INTOPT(permit_tun);
1764 M_CP_INTOPT(gateway_ports); 1808 M_CP_INTOPT(fwd_opts.gateway_ports);
1765 M_CP_INTOPT(x11_display_offset); 1809 M_CP_INTOPT(x11_display_offset);
1766 M_CP_INTOPT(x11_forwarding); 1810 M_CP_INTOPT(x11_forwarding);
1767 M_CP_INTOPT(x11_use_localhost); 1811 M_CP_INTOPT(x11_use_localhost);
1768 M_CP_INTOPT(permit_tty); 1812 M_CP_INTOPT(permit_tty);
1813 M_CP_INTOPT(permit_user_rc);
1769 M_CP_INTOPT(max_sessions); 1814 M_CP_INTOPT(max_sessions);
1770 M_CP_INTOPT(max_authtries); 1815 M_CP_INTOPT(max_authtries);
1771 M_CP_INTOPT(ip_qos_interactive); 1816 M_CP_INTOPT(ip_qos_interactive);
@@ -1858,6 +1903,8 @@ fmt_intarg(ServerOpCodes code, int val)
1858 return fmt_multistate_int(val, multistate_privsep); 1903 return fmt_multistate_int(val, multistate_privsep);
1859 case sAllowTcpForwarding: 1904 case sAllowTcpForwarding:
1860 return fmt_multistate_int(val, multistate_tcpfwd); 1905 return fmt_multistate_int(val, multistate_tcpfwd);
1906 case sAllowStreamLocalForwarding:
1907 return fmt_multistate_int(val, multistate_tcpfwd);
1861 case sProtocol: 1908 case sProtocol:
1862 switch (val) { 1909 switch (val) {
1863 case SSH_PROTO_1: 1910 case SSH_PROTO_1:
@@ -2007,15 +2054,17 @@ dump_config(ServerOptions *o)
2007 dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding); 2054 dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
2008 dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost); 2055 dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
2009 dump_cfg_fmtint(sPermitTTY, o->permit_tty); 2056 dump_cfg_fmtint(sPermitTTY, o->permit_tty);
2057 dump_cfg_fmtint(sPermitUserRC, o->permit_user_rc);
2010 dump_cfg_fmtint(sStrictModes, o->strict_modes); 2058 dump_cfg_fmtint(sStrictModes, o->strict_modes);
2011 dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive); 2059 dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
2012 dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd); 2060 dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
2013 dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env); 2061 dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
2014 dump_cfg_fmtint(sUseLogin, o->use_login); 2062 dump_cfg_fmtint(sUseLogin, o->use_login);
2015 dump_cfg_fmtint(sCompression, o->compression); 2063 dump_cfg_fmtint(sCompression, o->compression);
2016 dump_cfg_fmtint(sGatewayPorts, o->gateway_ports); 2064 dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
2017 dump_cfg_fmtint(sUseDNS, o->use_dns); 2065 dump_cfg_fmtint(sUseDNS, o->use_dns);
2018 dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); 2066 dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
2067 dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
2019 dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); 2068 dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
2020 2069
2021 /* string arguments */ 2070 /* string arguments */
diff --git a/servconf.h b/servconf.h
index 752d1c5ae..766db3a3d 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: servconf.h,v 1.112 2014/01/29 06:18:35 djm Exp $ */ 1/* $OpenBSD: servconf.h,v 1.114 2014/07/15 15:54:14 millert Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -83,6 +83,7 @@ typedef struct {
83 int x11_use_localhost; /* If true, use localhost for fake X11 server. */ 83 int x11_use_localhost; /* If true, use localhost for fake X11 server. */
84 char *xauth_location; /* Location of xauth program */ 84 char *xauth_location; /* Location of xauth program */
85 int permit_tty; /* If false, deny pty allocation */ 85 int permit_tty; /* If false, deny pty allocation */
86 int permit_user_rc; /* If false, deny ~/.ssh/rc execution */
86 int strict_modes; /* If true, require string home dir modes. */ 87 int strict_modes; /* If true, require string home dir modes. */
87 int tcp_keep_alive; /* If true, set SO_KEEPALIVE. */ 88 int tcp_keep_alive; /* If true, set SO_KEEPALIVE. */
88 int ip_qos_interactive; /* IP ToS/DSCP/class for interactive */ 89 int ip_qos_interactive; /* IP ToS/DSCP/class for interactive */
@@ -91,7 +92,7 @@ typedef struct {
91 char *macs; /* Supported SSH2 macs. */ 92 char *macs; /* Supported SSH2 macs. */
92 char *kex_algorithms; /* SSH2 kex methods in order of preference. */ 93 char *kex_algorithms; /* SSH2 kex methods in order of preference. */
93 int protocol; /* Supported protocol versions. */ 94 int protocol; /* Supported protocol versions. */
94 int gateway_ports; /* If true, allow remote connects to forwarded ports. */ 95 struct ForwardOptions fwd_opts; /* forwarding options */
95 SyslogFacility log_facility; /* Facility for system logging. */ 96 SyslogFacility log_facility; /* Facility for system logging. */
96 LogLevel log_level; /* Level for system logging. */ 97 LogLevel log_level; /* Level for system logging. */
97 int rhosts_rsa_authentication; /* If true, permit rhosts RSA 98 int rhosts_rsa_authentication; /* If true, permit rhosts RSA
@@ -123,6 +124,7 @@ typedef struct {
123 int use_login; /* If true, login(1) is used */ 124 int use_login; /* If true, login(1) is used */
124 int compression; /* If true, compression is allowed */ 125 int compression; /* If true, compression is allowed */
125 int allow_tcp_forwarding; /* One of FORWARD_* */ 126 int allow_tcp_forwarding; /* One of FORWARD_* */
127 int allow_streamlocal_forwarding; /* One of FORWARD_* */
126 int allow_agent_forwarding; 128 int allow_agent_forwarding;
127 u_int num_allow_users; 129 u_int num_allow_users;
128 char *allow_users[MAX_ALLOW_USERS]; 130 char *allow_users[MAX_ALLOW_USERS];
diff --git a/serverloop.c b/serverloop.c
index 2f8e3a06a..e92f9e27b 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: serverloop.c,v 1.170 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: serverloop.c,v 1.172 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -61,6 +61,7 @@
61#include "packet.h" 61#include "packet.h"
62#include "buffer.h" 62#include "buffer.h"
63#include "log.h" 63#include "log.h"
64#include "misc.h"
64#include "servconf.h" 65#include "servconf.h"
65#include "canohost.h" 66#include "canohost.h"
66#include "sshpty.h" 67#include "sshpty.h"
@@ -77,7 +78,6 @@
77#include "dispatch.h" 78#include "dispatch.h"
78#include "auth-options.h" 79#include "auth-options.h"
79#include "serverloop.h" 80#include "serverloop.h"
80#include "misc.h"
81#include "roaming.h" 81#include "roaming.h"
82 82
83extern ServerOptions options; 83extern ServerOptions options;
@@ -970,7 +970,7 @@ server_request_direct_tcpip(void)
970 /* XXX fine grained permissions */ 970 /* XXX fine grained permissions */
971 if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 && 971 if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 &&
972 !no_port_forwarding_flag) { 972 !no_port_forwarding_flag) {
973 c = channel_connect_to(target, target_port, 973 c = channel_connect_to_port(target, target_port,
974 "direct-tcpip", "direct-tcpip"); 974 "direct-tcpip", "direct-tcpip");
975 } else { 975 } else {
976 logit("refused local port forward: " 976 logit("refused local port forward: "
@@ -985,6 +985,38 @@ server_request_direct_tcpip(void)
985} 985}
986 986
987static Channel * 987static Channel *
988server_request_direct_streamlocal(void)
989{
990 Channel *c = NULL;
991 char *target, *originator;
992 u_short originator_port;
993
994 target = packet_get_string(NULL);
995 originator = packet_get_string(NULL);
996 originator_port = packet_get_int();
997 packet_check_eom();
998
999 debug("server_request_direct_streamlocal: originator %s port %d, target %s",
1000 originator, originator_port, target);
1001
1002 /* XXX fine grained permissions */
1003 if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 &&
1004 !no_port_forwarding_flag) {
1005 c = channel_connect_to_path(target,
1006 "direct-streamlocal@openssh.com", "direct-streamlocal");
1007 } else {
1008 logit("refused streamlocal port forward: "
1009 "originator %s port %d, target %s",
1010 originator, originator_port, target);
1011 }
1012
1013 free(originator);
1014 free(target);
1015
1016 return c;
1017}
1018
1019static Channel *
988server_request_tun(void) 1020server_request_tun(void)
989{ 1021{
990 Channel *c = NULL; 1022 Channel *c = NULL;
@@ -1081,6 +1113,8 @@ server_input_channel_open(int type, u_int32_t seq, void *ctxt)
1081 c = server_request_session(); 1113 c = server_request_session();
1082 } else if (strcmp(ctype, "direct-tcpip") == 0) { 1114 } else if (strcmp(ctype, "direct-tcpip") == 0) {
1083 c = server_request_direct_tcpip(); 1115 c = server_request_direct_tcpip();
1116 } else if (strcmp(ctype, "direct-streamlocal@openssh.com") == 0) {
1117 c = server_request_direct_streamlocal();
1084 } else if (strcmp(ctype, "tun@openssh.com") == 0) { 1118 } else if (strcmp(ctype, "tun@openssh.com") == 0) {
1085 c = server_request_tun(); 1119 c = server_request_tun();
1086 } 1120 }
@@ -1125,47 +1159,74 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
1125 /* -R style forwarding */ 1159 /* -R style forwarding */
1126 if (strcmp(rtype, "tcpip-forward") == 0) { 1160 if (strcmp(rtype, "tcpip-forward") == 0) {
1127 struct passwd *pw; 1161 struct passwd *pw;
1128 char *listen_address; 1162 struct Forward fwd;
1129 u_short listen_port;
1130 1163
1131 pw = the_authctxt->pw; 1164 pw = the_authctxt->pw;
1132 if (pw == NULL || !the_authctxt->valid) 1165 if (pw == NULL || !the_authctxt->valid)
1133 fatal("server_input_global_request: no/invalid user"); 1166 fatal("server_input_global_request: no/invalid user");
1134 listen_address = packet_get_string(NULL); 1167 memset(&fwd, 0, sizeof(fwd));
1135 listen_port = (u_short)packet_get_int(); 1168 fwd.listen_host = packet_get_string(NULL);
1169 fwd.listen_port = (u_short)packet_get_int();
1136 debug("server_input_global_request: tcpip-forward listen %s port %d", 1170 debug("server_input_global_request: tcpip-forward listen %s port %d",
1137 listen_address, listen_port); 1171 fwd.listen_host, fwd.listen_port);
1138 1172
1139 /* check permissions */ 1173 /* check permissions */
1140 if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 || 1174 if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 ||
1141 no_port_forwarding_flag || 1175 no_port_forwarding_flag ||
1142 (!want_reply && listen_port == 0) 1176 (!want_reply && fwd.listen_port == 0)
1143#ifndef NO_IPPORT_RESERVED_CONCEPT 1177#ifndef NO_IPPORT_RESERVED_CONCEPT
1144 || (listen_port != 0 && listen_port < IPPORT_RESERVED && 1178 || (fwd.listen_port != 0 && fwd.listen_port < IPPORT_RESERVED &&
1145 pw->pw_uid != 0) 1179 pw->pw_uid != 0)
1146#endif 1180#endif
1147 ) { 1181 ) {
1148 success = 0; 1182 success = 0;
1149 packet_send_debug("Server has disabled port forwarding."); 1183 packet_send_debug("Server has disabled port forwarding.");
1150 } else { 1184 } else {
1151 /* Start listening on the port */ 1185 /* Start listening on the port */
1152 success = channel_setup_remote_fwd_listener( 1186 success = channel_setup_remote_fwd_listener(&fwd,
1153 listen_address, listen_port, 1187 &allocated_listen_port, &options.fwd_opts);
1154 &allocated_listen_port, options.gateway_ports);
1155 } 1188 }
1156 free(listen_address); 1189 free(fwd.listen_host);
1157 } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) { 1190 } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
1158 char *cancel_address; 1191 struct Forward fwd;
1159 u_short cancel_port;
1160 1192
1161 cancel_address = packet_get_string(NULL); 1193 memset(&fwd, 0, sizeof(fwd));
1162 cancel_port = (u_short)packet_get_int(); 1194 fwd.listen_host = packet_get_string(NULL);
1195 fwd.listen_port = (u_short)packet_get_int();
1163 debug("%s: cancel-tcpip-forward addr %s port %d", __func__, 1196 debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
1164 cancel_address, cancel_port); 1197 fwd.listen_host, fwd.listen_port);
1198
1199 success = channel_cancel_rport_listener(&fwd);
1200 free(fwd.listen_host);
1201 } else if (strcmp(rtype, "streamlocal-forward@openssh.com") == 0) {
1202 struct Forward fwd;
1203
1204 memset(&fwd, 0, sizeof(fwd));
1205 fwd.listen_path = packet_get_string(NULL);
1206 debug("server_input_global_request: streamlocal-forward listen path %s",
1207 fwd.listen_path);
1208
1209 /* check permissions */
1210 if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0
1211 || no_port_forwarding_flag) {
1212 success = 0;
1213 packet_send_debug("Server has disabled port forwarding.");
1214 } else {
1215 /* Start listening on the socket */
1216 success = channel_setup_remote_fwd_listener(
1217 &fwd, NULL, &options.fwd_opts);
1218 }
1219 free(fwd.listen_path);
1220 } else if (strcmp(rtype, "cancel-streamlocal-forward@openssh.com") == 0) {
1221 struct Forward fwd;
1222
1223 memset(&fwd, 0, sizeof(fwd));
1224 fwd.listen_path = packet_get_string(NULL);
1225 debug("%s: cancel-streamlocal-forward path %s", __func__,
1226 fwd.listen_path);
1165 1227
1166 success = channel_cancel_rport_listener(cancel_address, 1228 success = channel_cancel_rport_listener(&fwd);
1167 cancel_port); 1229 free(fwd.listen_path);
1168 free(cancel_address);
1169 } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) { 1230 } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
1170 no_more_sessions = 1; 1231 no_more_sessions = 1;
1171 success = 1; 1232 success = 1;
@@ -1204,7 +1265,7 @@ server_input_channel_req(int type, u_int32_t seq, void *ctxt)
1204 } else if ((c->type == SSH_CHANNEL_LARVAL || 1265 } else if ((c->type == SSH_CHANNEL_LARVAL ||
1205 c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0) 1266 c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0)
1206 success = session_input_channel_req(c, rtype); 1267 success = session_input_channel_req(c, rtype);
1207 if (reply) { 1268 if (reply && !(c->flags & CHAN_CLOSE_SENT)) {
1208 packet_start(success ? 1269 packet_start(success ?
1209 SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); 1270 SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
1210 packet_put_int(c->remote_id); 1271 packet_put_int(c->remote_id);
diff --git a/session.c b/session.c
index 2bcf8185c..3e96557b8 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: session.c,v 1.270 2014/01/31 16:39:19 tedu Exp $ */ 1/* $OpenBSD: session.c,v 1.274 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved 4 * All rights reserved
@@ -49,6 +49,7 @@
49#include <errno.h> 49#include <errno.h>
50#include <fcntl.h> 50#include <fcntl.h>
51#include <grp.h> 51#include <grp.h>
52#include <netdb.h>
52#ifdef HAVE_PATHS_H 53#ifdef HAVE_PATHS_H
53#include <paths.h> 54#include <paths.h>
54#endif 55#endif
@@ -83,11 +84,11 @@
83#include "authfd.h" 84#include "authfd.h"
84#include "pathnames.h" 85#include "pathnames.h"
85#include "log.h" 86#include "log.h"
87#include "misc.h"
86#include "servconf.h" 88#include "servconf.h"
87#include "sshlogin.h" 89#include "sshlogin.h"
88#include "serverloop.h" 90#include "serverloop.h"
89#include "canohost.h" 91#include "canohost.h"
90#include "misc.h"
91#include "session.h" 92#include "session.h"
92#include "kex.h" 93#include "kex.h"
93#include "monitor_wrap.h" 94#include "monitor_wrap.h"
@@ -182,7 +183,6 @@ auth_input_request_forwarding(struct passwd * pw)
182{ 183{
183 Channel *nc; 184 Channel *nc;
184 int sock = -1; 185 int sock = -1;
185 struct sockaddr_un sunaddr;
186 186
187 if (auth_sock_name != NULL) { 187 if (auth_sock_name != NULL) {
188 error("authentication forwarding requested twice."); 188 error("authentication forwarding requested twice.");
@@ -208,33 +208,15 @@ auth_input_request_forwarding(struct passwd * pw)
208 xasprintf(&auth_sock_name, "%s/agent.%ld", 208 xasprintf(&auth_sock_name, "%s/agent.%ld",
209 auth_sock_dir, (long) getpid()); 209 auth_sock_dir, (long) getpid());
210 210
211 /* Create the socket. */ 211 /* Start a Unix listener on auth_sock_name. */
212 sock = socket(AF_UNIX, SOCK_STREAM, 0); 212 sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0);
213 if (sock < 0) {
214 error("socket: %.100s", strerror(errno));
215 restore_uid();
216 goto authsock_err;
217 }
218
219 /* Bind it to the name. */
220 memset(&sunaddr, 0, sizeof(sunaddr));
221 sunaddr.sun_family = AF_UNIX;
222 strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
223
224 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
225 error("bind: %.100s", strerror(errno));
226 restore_uid();
227 goto authsock_err;
228 }
229 213
230 /* Restore the privileged uid. */ 214 /* Restore the privileged uid. */
231 restore_uid(); 215 restore_uid();
232 216
233 /* Start listening on the socket. */ 217 /* Check for socket/bind/listen failure. */
234 if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { 218 if (sock < 0)
235 error("listen: %.100s", strerror(errno));
236 goto authsock_err; 219 goto authsock_err;
237 }
238 220
239 /* Allocate a channel for the authentication agent socket. */ 221 /* Allocate a channel for the authentication agent socket. */
240 nc = channel_new("auth socket", 222 nc = channel_new("auth socket",
@@ -273,6 +255,7 @@ do_authenticated(Authctxt *authctxt)
273 setproctitle("%s", authctxt->pw->pw_name); 255 setproctitle("%s", authctxt->pw->pw_name);
274 256
275 /* setup the channel layer */ 257 /* setup the channel layer */
258 /* XXX - streamlocal? */
276 if (no_port_forwarding_flag || 259 if (no_port_forwarding_flag ||
277 (options.allow_tcp_forwarding & FORWARD_LOCAL) == 0) 260 (options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
278 channel_disable_adm_local_opens(); 261 channel_disable_adm_local_opens();
@@ -392,7 +375,7 @@ do_authenticated1(Authctxt *authctxt)
392 } 375 }
393 debug("Received TCP/IP port forwarding request."); 376 debug("Received TCP/IP port forwarding request.");
394 if (channel_input_port_forward_request(s->pw->pw_uid == 0, 377 if (channel_input_port_forward_request(s->pw->pw_uid == 0,
395 options.gateway_ports) < 0) { 378 &options.fwd_opts) < 0) {
396 debug("Port forwarding failed."); 379 debug("Port forwarding failed.");
397 break; 380 break;
398 } 381 }
@@ -1358,7 +1341,8 @@ do_rc_files(Session *s, const char *shell)
1358 1341
1359 /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */ 1342 /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
1360 if (!s->is_subsystem && options.adm_forced_command == NULL && 1343 if (!s->is_subsystem && options.adm_forced_command == NULL &&
1361 !no_user_rc && stat(_PATH_SSH_USER_RC, &st) >= 0) { 1344 !no_user_rc && options.permit_user_rc &&
1345 stat(_PATH_SSH_USER_RC, &st) >= 0) {
1362 snprintf(cmd, sizeof cmd, "%s -c '%s %s'", 1346 snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
1363 shell, _PATH_BSHELL, _PATH_SSH_USER_RC); 1347 shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
1364 if (debug_flag) 1348 if (debug_flag)
@@ -1505,6 +1489,9 @@ void
1505do_setusercontext(struct passwd *pw) 1489do_setusercontext(struct passwd *pw)
1506{ 1490{
1507 char *chroot_path, *tmp; 1491 char *chroot_path, *tmp;
1492#ifdef USE_LIBIAF
1493 int doing_chroot = 0;
1494#endif
1508 1495
1509 platform_setusercontext(pw); 1496 platform_setusercontext(pw);
1510 1497
@@ -1544,6 +1531,9 @@ do_setusercontext(struct passwd *pw)
1544 /* Make sure we don't attempt to chroot again */ 1531 /* Make sure we don't attempt to chroot again */
1545 free(options.chroot_directory); 1532 free(options.chroot_directory);
1546 options.chroot_directory = NULL; 1533 options.chroot_directory = NULL;
1534#ifdef USE_LIBIAF
1535 doing_chroot = 1;
1536#endif
1547 } 1537 }
1548 1538
1549#ifdef HAVE_LOGIN_CAP 1539#ifdef HAVE_LOGIN_CAP
@@ -1558,7 +1548,14 @@ do_setusercontext(struct passwd *pw)
1558 (void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUMASK); 1548 (void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUMASK);
1559#else 1549#else
1560# ifdef USE_LIBIAF 1550# ifdef USE_LIBIAF
1561 if (set_id(pw->pw_name) != 0) { 1551/* In a chroot environment, the set_id() will always fail; typically
1552 * because of the lack of necessary authentication services and runtime
1553 * such as ./usr/lib/libiaf.so, ./usr/lib/libpam.so.1, and ./etc/passwd
1554 * We skip it in the internal sftp chroot case.
1555 * We'll lose auditing and ACLs but permanently_set_uid will
1556 * take care of the rest.
1557 */
1558 if ((doing_chroot == 0) && set_id(pw->pw_name) != 0) {
1562 fatal("set_id(%s) Failed", pw->pw_name); 1559 fatal("set_id(%s) Failed", pw->pw_name);
1563 } 1560 }
1564# endif /* USE_LIBIAF */ 1561# endif /* USE_LIBIAF */
@@ -2640,7 +2637,7 @@ session_setup_x11fwd(Session *s)
2640{ 2637{
2641 struct stat st; 2638 struct stat st;
2642 char display[512], auth_display[512]; 2639 char display[512], auth_display[512];
2643 char hostname[MAXHOSTNAMELEN]; 2640 char hostname[NI_MAXHOST];
2644 u_int i; 2641 u_int i;
2645 2642
2646 if (no_x11_forwarding_flag) { 2643 if (no_x11_forwarding_flag) {
diff --git a/sftp-client.c b/sftp-client.c
index 2f5907c85..990b58d14 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-client.c,v 1.114 2014/01/31 16:39:19 tedu Exp $ */ 1/* $OpenBSD: sftp-client.c,v 1.115 2014/04/21 14:36:16 logan Exp $ */
2/* 2/*
3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4 * 4 *
@@ -1420,7 +1420,7 @@ download_dir(struct sftp_conn *conn, char *src, char *dst,
1420 1420
1421int 1421int
1422do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, 1422do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1423 int preserve_flag, int fsync_flag) 1423 int preserve_flag, int resume, int fsync_flag)
1424{ 1424{
1425 int local_fd; 1425 int local_fd;
1426 int status = SSH2_FX_OK; 1426 int status = SSH2_FX_OK;
@@ -1429,7 +1429,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1429 char *handle, *data; 1429 char *handle, *data;
1430 Buffer msg; 1430 Buffer msg;
1431 struct stat sb; 1431 struct stat sb;
1432 Attrib a; 1432 Attrib a, *c = NULL;
1433 u_int32_t startid; 1433 u_int32_t startid;
1434 u_int32_t ackid; 1434 u_int32_t ackid;
1435 struct outstanding_ack { 1435 struct outstanding_ack {
@@ -1467,6 +1467,26 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1467 if (!preserve_flag) 1467 if (!preserve_flag)
1468 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1468 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1469 1469
1470 if (resume) {
1471 /* Get remote file size if it exists */
1472 if ((c = do_stat(conn, remote_path, 0)) == NULL) {
1473 close(local_fd);
1474 return -1;
1475 }
1476
1477 if ((off_t)c->size >= sb.st_size) {
1478 error("destination file bigger or same size as "
1479 "source file");
1480 close(local_fd);
1481 return -1;
1482 }
1483
1484 if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) {
1485 close(local_fd);
1486 return -1;
1487 }
1488 }
1489
1470 buffer_init(&msg); 1490 buffer_init(&msg);
1471 1491
1472 /* Send open request */ 1492 /* Send open request */
@@ -1474,7 +1494,8 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1474 buffer_put_char(&msg, SSH2_FXP_OPEN); 1494 buffer_put_char(&msg, SSH2_FXP_OPEN);
1475 buffer_put_int(&msg, id); 1495 buffer_put_int(&msg, id);
1476 buffer_put_cstring(&msg, remote_path); 1496 buffer_put_cstring(&msg, remote_path);
1477 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); 1497 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
1498 (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC));
1478 encode_attrib(&msg, &a); 1499 encode_attrib(&msg, &a);
1479 send_msg(conn, &msg); 1500 send_msg(conn, &msg);
1480 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1501 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
@@ -1493,7 +1514,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1493 data = xmalloc(conn->transfer_buflen); 1514 data = xmalloc(conn->transfer_buflen);
1494 1515
1495 /* Read from local and write to remote */ 1516 /* Read from local and write to remote */
1496 offset = progress_counter = 0; 1517 offset = progress_counter = (resume ? c->size : 0);
1497 if (showprogress) 1518 if (showprogress)
1498 start_progress_meter(local_path, sb.st_size, 1519 start_progress_meter(local_path, sb.st_size,
1499 &progress_counter); 1520 &progress_counter);
@@ -1608,7 +1629,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1608 1629
1609static int 1630static int
1610upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, 1631upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1611 int preserve_flag, int print_flag, int fsync_flag) 1632 int preserve_flag, int print_flag, int resume, int fsync_flag)
1612{ 1633{
1613 int ret = 0, status; 1634 int ret = 0, status;
1614 DIR *dirp; 1635 DIR *dirp;
@@ -1677,12 +1698,12 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1677 continue; 1698 continue;
1678 1699
1679 if (upload_dir_internal(conn, new_src, new_dst, 1700 if (upload_dir_internal(conn, new_src, new_dst,
1680 depth + 1, preserve_flag, print_flag, 1701 depth + 1, preserve_flag, print_flag, resume,
1681 fsync_flag) == -1) 1702 fsync_flag) == -1)
1682 ret = -1; 1703 ret = -1;
1683 } else if (S_ISREG(sb.st_mode)) { 1704 } else if (S_ISREG(sb.st_mode)) {
1684 if (do_upload(conn, new_src, new_dst, 1705 if (do_upload(conn, new_src, new_dst,
1685 preserve_flag, fsync_flag) == -1) { 1706 preserve_flag, resume, fsync_flag) == -1) {
1686 error("Uploading of file %s to %s failed!", 1707 error("Uploading of file %s to %s failed!",
1687 new_src, new_dst); 1708 new_src, new_dst);
1688 ret = -1; 1709 ret = -1;
@@ -1701,7 +1722,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1701 1722
1702int 1723int
1703upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, 1724upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag,
1704 int print_flag, int fsync_flag) 1725 int print_flag, int resume, int fsync_flag)
1705{ 1726{
1706 char *dst_canon; 1727 char *dst_canon;
1707 int ret; 1728 int ret;
@@ -1712,7 +1733,7 @@ upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag,
1712 } 1733 }
1713 1734
1714 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, 1735 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
1715 print_flag, fsync_flag); 1736 print_flag, resume, fsync_flag);
1716 1737
1717 free(dst_canon); 1738 free(dst_canon);
1718 return ret; 1739 return ret;
diff --git a/sftp-client.h b/sftp-client.h
index ba92ad01a..967840b9c 100644
--- a/sftp-client.h
+++ b/sftp-client.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-client.h,v 1.24 2013/10/17 00:30:13 djm Exp $ */ 1/* $OpenBSD: sftp-client.h,v 1.25 2014/04/21 14:36:16 logan Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 4 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@@ -120,13 +120,13 @@ int download_dir(struct sftp_conn *, char *, char *, Attrib *, int,
120 * Upload 'local_path' to 'remote_path'. Preserve permissions and times 120 * Upload 'local_path' to 'remote_path'. Preserve permissions and times
121 * if 'pflag' is set 121 * if 'pflag' is set
122 */ 122 */
123int do_upload(struct sftp_conn *, char *, char *, int, int); 123int do_upload(struct sftp_conn *, char *, char *, int, int, int);
124 124
125/* 125/*
126 * Recursively upload 'local_directory' to 'remote_directory'. Preserve 126 * Recursively upload 'local_directory' to 'remote_directory'. Preserve
127 * times if 'pflag' is set 127 * times if 'pflag' is set
128 */ 128 */
129int upload_dir(struct sftp_conn *, char *, char *, int, int, int); 129int upload_dir(struct sftp_conn *, char *, char *, int, int, int, int);
130 130
131/* Concatenate paths, taking care of slashes. Caller must free result. */ 131/* Concatenate paths, taking care of slashes. Caller must free result. */
132char *path_append(char *, char *); 132char *path_append(char *, char *);
diff --git a/sftp-server.0 b/sftp-server.0
index ce7ddc07f..d811e252d 100644
--- a/sftp-server.0
+++ b/sftp-server.0
@@ -1,4 +1,4 @@
1SFTP-SERVER(8) OpenBSD System Manager's Manual SFTP-SERVER(8) 1SFTP-SERVER(8) System Manager's Manual SFTP-SERVER(8)
2 2
3NAME 3NAME
4 sftp-server - SFTP server subsystem 4 sftp-server - SFTP server subsystem
@@ -76,9 +76,10 @@ DESCRIPTION
76 Sets an explicit umask(2) to be applied to newly-created files 76 Sets an explicit umask(2) to be applied to newly-created files
77 and directories, instead of the user's default mask. 77 and directories, instead of the user's default mask.
78 78
79 For logging to work, sftp-server must be able to access /dev/log. Use of 79 On some systems, sftp-server must be able to access /dev/log for logging
80 sftp-server in a chroot configuration therefore requires that syslogd(8) 80 to work, and use of sftp-server in a chroot configuration therefore
81 establish a logging socket inside the chroot directory. 81 requires that syslogd(8) establish a logging socket inside the chroot
82 directory.
82 83
83SEE ALSO 84SEE ALSO
84 sftp(1), ssh(1), sshd_config(5), sshd(8) 85 sftp(1), ssh(1), sshd_config(5), sshd(8)
@@ -92,4 +93,4 @@ HISTORY
92AUTHORS 93AUTHORS
93 Markus Friedl <markus@openbsd.org> 94 Markus Friedl <markus@openbsd.org>
94 95
95OpenBSD 5.5 October 14, 2013 OpenBSD 5.5 96OpenBSD 5.6 July 28, 2014 OpenBSD 5.6
diff --git a/sftp-server.8 b/sftp-server.8
index 1e0b277b4..75d8d8d53 100644
--- a/sftp-server.8
+++ b/sftp-server.8
@@ -1,4 +1,4 @@
1.\" $OpenBSD: sftp-server.8,v 1.25 2013/10/14 14:18:56 jmc Exp $ 1.\" $OpenBSD: sftp-server.8,v 1.26 2014/07/28 15:40:08 schwarze Exp $
2.\" 2.\"
3.\" Copyright (c) 2000 Markus Friedl. All rights reserved. 3.\" Copyright (c) 2000 Markus Friedl. All rights reserved.
4.\" 4.\"
@@ -22,7 +22,7 @@
22.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24.\" 24.\"
25.Dd $Mdocdate: October 14 2013 $ 25.Dd $Mdocdate: July 28 2014 $
26.Dt SFTP-SERVER 8 26.Dt SFTP-SERVER 8
27.Os 27.Os
28.Sh NAME 28.Sh NAME
@@ -140,11 +140,11 @@ to be applied to newly-created files and directories, instead of the
140user's default mask. 140user's default mask.
141.El 141.El
142.Pp 142.Pp
143For logging to work, 143On some systems,
144.Nm 144.Nm
145must be able to access 145must be able to access
146.Pa /dev/log . 146.Pa /dev/log
147Use of 147for logging to work, and use of
148.Nm 148.Nm
149in a chroot configuration therefore requires that 149in a chroot configuration therefore requires that
150.Xr syslogd 8 150.Xr syslogd 8
diff --git a/sftp-server.c b/sftp-server.c
index b8eb59c36..0177130cf 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -29,6 +29,9 @@
29#ifdef HAVE_SYS_STATVFS_H 29#ifdef HAVE_SYS_STATVFS_H
30#include <sys/statvfs.h> 30#include <sys/statvfs.h>
31#endif 31#endif
32#ifdef HAVE_SYS_PRCTL_H
33#include <sys/prctl.h>
34#endif
32 35
33#include <dirent.h> 36#include <dirent.h>
34#include <errno.h> 37#include <errno.h>
@@ -1523,6 +1526,17 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1523 1526
1524 log_init(__progname, log_level, log_facility, log_stderr); 1527 log_init(__progname, log_level, log_facility, log_stderr);
1525 1528
1529#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
1530 /*
1531 * On Linux, we should try to avoid making /proc/self/{mem,maps}
1532 * available to the user so that sftp access doesn't automatically
1533 * imply arbitrary code execution access that will break
1534 * restricted configurations.
1535 */
1536 if (prctl(PR_SET_DUMPABLE, 0) != 0)
1537 fatal("unable to make the process undumpable");
1538#endif /* defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) */
1539
1526 if ((cp = getenv("SSH_CONNECTION")) != NULL) { 1540 if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1527 client_addr = xstrdup(cp); 1541 client_addr = xstrdup(cp);
1528 if ((cp = strchr(client_addr, ' ')) == NULL) { 1542 if ((cp = strchr(client_addr, ' ')) == NULL) {
diff --git a/sftp.0 b/sftp.0
index 7139aac43..e37043455 100644
--- a/sftp.0
+++ b/sftp.0
@@ -1,4 +1,4 @@
1SFTP(1) OpenBSD Reference Manual SFTP(1) 1SFTP(1) General Commands Manual SFTP(1)
2 2
3NAME 3NAME
4 sftp - secure file transfer program 4 sftp - secure file transfer program
@@ -44,9 +44,9 @@ DESCRIPTION
44 44
45 -6 Forces sftp to use IPv6 addresses only. 45 -6 Forces sftp to use IPv6 addresses only.
46 46
47 -a Attempt to continue interrupted downloads rather than overwriting 47 -a Attempt to continue interrupted transfers rather than overwriting
48 existing partial or complete copies of files. If the remote file 48 existing partial or complete copies of files. If the partial
49 contents differ from the partial local copy then the resultant 49 contents differ from those being transferred, then the resultant
50 file is likely to be corrupt. 50 file is likely to be corrupt.
51 51
52 -B buffer_size 52 -B buffer_size
@@ -60,10 +60,11 @@ DESCRIPTION
60 used in conjunction with non-interactive authentication. A 60 used in conjunction with non-interactive authentication. A
61 batchfile of `-' may be used to indicate standard input. sftp 61 batchfile of `-' may be used to indicate standard input. sftp
62 will abort if any of the following commands fail: get, put, 62 will abort if any of the following commands fail: get, put,
63 reget, rename, ln, rm, mkdir, chdir, ls, lchdir, chmod, chown, 63 reget, reput, rename, ln, rm, mkdir, chdir, ls, lchdir, chmod,
64 chgrp, lpwd, df, symlink, and lmkdir. Termination on error can 64 chown, chgrp, lpwd, df, symlink, and lmkdir. Termination on
65 be suppressed on a command by command basis by prefixing the 65 error can be suppressed on a command by command basis by
66 command with a `-' character (for example, -rm /tmp/blah*). 66 prefixing the command with a `-' character (for example, -rm
67 /tmp/blah*).
67 68
68 -C Enables compression (via ssh's -C flag). 69 -C Enables compression (via ssh's -C flag).
69 70
@@ -310,7 +311,7 @@ INTERACTIVE COMMANDS
310 progress 311 progress
311 Toggle display of progress meter. 312 Toggle display of progress meter.
312 313
313 put [-fPpr] local-path [remote-path] 314 put [-afPpr] local-path [remote-path]
314 Upload local-path and store it on the remote machine. If the 315 Upload local-path and store it on the remote machine. If the
315 remote path name is not specified, it is given the same name it 316 remote path name is not specified, it is given the same name it
316 has on the local machine. local-path may contain glob(3) 317 has on the local machine. local-path may contain glob(3)
@@ -318,6 +319,12 @@ INTERACTIVE COMMANDS
318 remote-path is specified, then remote-path must specify a 319 remote-path is specified, then remote-path must specify a
319 directory. 320 directory.
320 321
322 If the -a flag is specified, then attempt to resume partial
323 transfers of existing files. Note that resumption assumes that
324 any partial copy of the remote file matches the local copy. If
325 the local file contents differ from the remote local copy then
326 the resultant file is likely to be corrupt.
327
321 If the -f flag is specified, then a request will be sent to the 328 If the -f flag is specified, then a request will be sent to the
322 server to call fsync(2) after the file has been transferred. 329 server to call fsync(2) after the file has been transferred.
323 Note that this is only supported by servers that implement the 330 Note that this is only supported by servers that implement the
@@ -338,6 +345,10 @@ INTERACTIVE COMMANDS
338 Resume download of remote-path. Equivalent to get with the -a 345 Resume download of remote-path. Equivalent to get with the -a
339 flag set. 346 flag set.
340 347
348 reput [-Ppr] [local-path] remote-path
349 Resume upload of [local-path]. Equivalent to put with the -a
350 flag set.
351
341 rename oldpath newpath 352 rename oldpath newpath
342 Rename remote file from oldpath to newpath. 353 Rename remote file from oldpath to newpath.
343 354
@@ -367,4 +378,4 @@ SEE ALSO
367 T. Ylonen and S. Lehtinen, SSH File Transfer Protocol, draft-ietf-secsh- 378 T. Ylonen and S. Lehtinen, SSH File Transfer Protocol, draft-ietf-secsh-
368 filexfer-00.txt, January 2001, work in progress material. 379 filexfer-00.txt, January 2001, work in progress material.
369 380
370OpenBSD 5.5 October 20, 2013 OpenBSD 5.5 381OpenBSD 5.6 April 22, 2014 OpenBSD 5.6
diff --git a/sftp.1 b/sftp.1
index a700c2adb..7eb9970ab 100644
--- a/sftp.1
+++ b/sftp.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: sftp.1,v 1.97 2013/10/20 09:51:26 djm Exp $ 1.\" $OpenBSD: sftp.1,v 1.99 2014/04/22 14:16:30 jmc Exp $
2.\" 2.\"
3.\" Copyright (c) 2001 Damien Miller. All rights reserved. 3.\" Copyright (c) 2001 Damien Miller. All rights reserved.
4.\" 4.\"
@@ -22,7 +22,7 @@
22.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24.\" 24.\"
25.Dd $Mdocdate: October 20 2013 $ 25.Dd $Mdocdate: April 22 2014 $
26.Dt SFTP 1 26.Dt SFTP 1
27.Os 27.Os
28.Sh NAME 28.Sh NAME
@@ -108,10 +108,10 @@ Forces
108.Nm 108.Nm
109to use IPv6 addresses only. 109to use IPv6 addresses only.
110.It Fl a 110.It Fl a
111Attempt to continue interrupted downloads rather than overwriting existing 111Attempt to continue interrupted transfers rather than overwriting
112partial or complete copies of files. 112existing partial or complete copies of files.
113If the remote file contents differ from the partial local copy then the 113If the partial contents differ from those being transferred,
114resultant file is likely to be corrupt. 114then the resultant file is likely to be corrupt.
115.It Fl B Ar buffer_size 115.It Fl B Ar buffer_size
116Specify the size of the buffer that 116Specify the size of the buffer that
117.Nm 117.Nm
@@ -134,7 +134,7 @@ may be used to indicate standard input.
134.Nm 134.Nm
135will abort if any of the following 135will abort if any of the following
136commands fail: 136commands fail:
137.Ic get , put , reget , rename , ln , 137.Ic get , put , reget , reput, rename , ln ,
138.Ic rm , mkdir , chdir , ls , 138.Ic rm , mkdir , chdir , ls ,
139.Ic lchdir , chmod , chown , 139.Ic lchdir , chmod , chown ,
140.Ic chgrp , lpwd , df , symlink , 140.Ic chgrp , lpwd , df , symlink ,
@@ -495,7 +495,7 @@ Create remote directory specified by
495.It Ic progress 495.It Ic progress
496Toggle display of progress meter. 496Toggle display of progress meter.
497.It Xo Ic put 497.It Xo Ic put
498.Op Fl fPpr 498.Op Fl afPpr
499.Ar local-path 499.Ar local-path
500.Op Ar remote-path 500.Op Ar remote-path
501.Xc 501.Xc
@@ -515,6 +515,15 @@ is specified, then
515must specify a directory. 515must specify a directory.
516.Pp 516.Pp
517If the 517If the
518.Fl a
519flag is specified, then attempt to resume partial
520transfers of existing files.
521Note that resumption assumes that any partial copy of the remote file
522matches the local copy.
523If the local file contents differ from the remote local copy then
524the resultant file is likely to be corrupt.
525.Pp
526If the
518.Fl f 527.Fl f
519flag is specified, then a request will be sent to the server to call 528flag is specified, then a request will be sent to the server to call
520.Xr fsync 2 529.Xr fsync 2
@@ -552,6 +561,18 @@ Equivalent to
552with the 561with the
553.Fl a 562.Fl a
554flag set. 563flag set.
564.It Xo Ic reput
565.Op Fl Ppr
566.Op Ar local-path
567.Ar remote-path
568.Xc
569Resume upload of
570.Op Ar local-path .
571Equivalent to
572.Ic put
573with the
574.Fl a
575flag set.
555.It Ic rename Ar oldpath Ar newpath 576.It Ic rename Ar oldpath Ar newpath
556Rename remote file from 577Rename remote file from
557.Ar oldpath 578.Ar oldpath
diff --git a/sftp.c b/sftp.c
index ad1f8c84d..ff4d63d5c 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp.c,v 1.158 2013/11/20 20:54:10 deraadt Exp $ */ 1/* $OpenBSD: sftp.c,v 1.164 2014/07/09 01:45:10 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4 * 4 *
@@ -88,7 +88,7 @@ int showprogress = 1;
88/* When this option is set, we always recursively download/upload directories */ 88/* When this option is set, we always recursively download/upload directories */
89int global_rflag = 0; 89int global_rflag = 0;
90 90
91/* When this option is set, we resume download if possible */ 91/* When this option is set, we resume download or upload if possible */
92int global_aflag = 0; 92int global_aflag = 0;
93 93
94/* When this option is set, the file transfers will always preserve times */ 94/* When this option is set, the file transfers will always preserve times */
@@ -151,14 +151,15 @@ enum sftp_command {
151 I_PUT, 151 I_PUT,
152 I_PWD, 152 I_PWD,
153 I_QUIT, 153 I_QUIT,
154 I_REGET,
154 I_RENAME, 155 I_RENAME,
156 I_REPUT,
155 I_RM, 157 I_RM,
156 I_RMDIR, 158 I_RMDIR,
157 I_SHELL, 159 I_SHELL,
158 I_SYMLINK, 160 I_SYMLINK,
159 I_VERSION, 161 I_VERSION,
160 I_PROGRESS, 162 I_PROGRESS,
161 I_REGET,
162}; 163};
163 164
164struct CMD { 165struct CMD {
@@ -201,6 +202,7 @@ static const struct CMD cmds[] = {
201 { "quit", I_QUIT, NOARGS }, 202 { "quit", I_QUIT, NOARGS },
202 { "reget", I_REGET, REMOTE }, 203 { "reget", I_REGET, REMOTE },
203 { "rename", I_RENAME, REMOTE }, 204 { "rename", I_RENAME, REMOTE },
205 { "reput", I_REPUT, LOCAL },
204 { "rm", I_RM, REMOTE }, 206 { "rm", I_RM, REMOTE },
205 { "rmdir", I_RMDIR, REMOTE }, 207 { "rmdir", I_RMDIR, REMOTE },
206 { "symlink", I_SYMLINK, REMOTE }, 208 { "symlink", I_SYMLINK, REMOTE },
@@ -250,6 +252,7 @@ help(void)
250 "exit Quit sftp\n" 252 "exit Quit sftp\n"
251 "get [-Ppr] remote [local] Download file\n" 253 "get [-Ppr] remote [local] Download file\n"
252 "reget remote [local] Resume download file\n" 254 "reget remote [local] Resume download file\n"
255 "reput [local] remote Resume upload file\n"
253 "help Display this help text\n" 256 "help Display this help text\n"
254 "lcd path Change local directory to 'path'\n" 257 "lcd path Change local directory to 'path'\n"
255 "lls [ls-options [path]] Display local directory listing\n" 258 "lls [ls-options [path]] Display local directory listing\n"
@@ -586,15 +589,19 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd,
586 char *abs_dst = NULL; 589 char *abs_dst = NULL;
587 glob_t g; 590 glob_t g;
588 char *filename, *tmp=NULL; 591 char *filename, *tmp=NULL;
589 int i, err = 0; 592 int i, r, err = 0;
590 593
591 abs_src = xstrdup(src); 594 abs_src = xstrdup(src);
592 abs_src = make_absolute(abs_src, pwd); 595 abs_src = make_absolute(abs_src, pwd);
593 memset(&g, 0, sizeof(g)); 596 memset(&g, 0, sizeof(g));
594 597
595 debug3("Looking up %s", abs_src); 598 debug3("Looking up %s", abs_src);
596 if (remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) { 599 if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) {
597 error("File \"%s\" not found.", abs_src); 600 if (r == GLOB_NOSPACE) {
601 error("Too many matches for \"%s\".", abs_src);
602 } else {
603 error("File \"%s\" not found.", abs_src);
604 }
598 err = -1; 605 err = -1;
599 goto out; 606 goto out;
600 } 607 }
@@ -660,7 +667,7 @@ out:
660 667
661static int 668static int
662process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, 669process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
663 int pflag, int rflag, int fflag) 670 int pflag, int rflag, int resume, int fflag)
664{ 671{
665 char *tmp_dst = NULL; 672 char *tmp_dst = NULL;
666 char *abs_dst = NULL; 673 char *abs_dst = NULL;
@@ -723,16 +730,20 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
723 } 730 }
724 free(tmp); 731 free(tmp);
725 732
726 if (!quiet) 733 resume |= global_aflag;
734 if (!quiet && resume)
735 printf("Resuming upload of %s to %s\n", g.gl_pathv[i],
736 abs_dst);
737 else if (!quiet && !resume)
727 printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); 738 printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
728 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { 739 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
729 if (upload_dir(conn, g.gl_pathv[i], abs_dst, 740 if (upload_dir(conn, g.gl_pathv[i], abs_dst,
730 pflag || global_pflag, 1, 741 pflag || global_pflag, 1, resume,
731 fflag || global_fflag) == -1) 742 fflag || global_fflag) == -1)
732 err = -1; 743 err = -1;
733 } else { 744 } else {
734 if (do_upload(conn, g.gl_pathv[i], abs_dst, 745 if (do_upload(conn, g.gl_pathv[i], abs_dst,
735 pflag || global_pflag, 746 pflag || global_pflag, resume,
736 fflag || global_fflag) == -1) 747 fflag || global_fflag) == -1)
737 err = -1; 748 err = -1;
738 } 749 }
@@ -855,19 +866,23 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
855{ 866{
856 char *fname, *lname; 867 char *fname, *lname;
857 glob_t g; 868 glob_t g;
858 int err; 869 int err, r;
859 struct winsize ws; 870 struct winsize ws;
860 u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80; 871 u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80;
861 872
862 memset(&g, 0, sizeof(g)); 873 memset(&g, 0, sizeof(g));
863 874
864 if (remote_glob(conn, path, 875 if ((r = remote_glob(conn, path,
865 GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT, 876 GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT,
866 NULL, &g) || 877 NULL, &g)) != 0 ||
867 (g.gl_pathc && !g.gl_matchc)) { 878 (g.gl_pathc && !g.gl_matchc)) {
868 if (g.gl_pathc) 879 if (g.gl_pathc)
869 globfree(&g); 880 globfree(&g);
870 error("Can't ls: \"%s\" not found", path); 881 if (r == GLOB_NOSPACE) {
882 error("Can't ls: Too many matches for \"%s\"", path);
883 } else {
884 error("Can't ls: \"%s\" not found", path);
885 }
871 return -1; 886 return -1;
872 } 887 }
873 888
@@ -1186,8 +1201,9 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
1186} 1201}
1187 1202
1188static int 1203static int
1189parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag, 1204parse_args(const char **cpp, int *ignore_errors, int *aflag,
1190 int *hflag, int *iflag, int *lflag, int *pflag, int *rflag, int *sflag, 1205 int *fflag, int *hflag, int *iflag, int *lflag, int *pflag,
1206 int *rflag, int *sflag,
1191 unsigned long *n_arg, char **path1, char **path2) 1207 unsigned long *n_arg, char **path1, char **path2)
1192{ 1208{
1193 const char *cmd, *cp = *cpp; 1209 const char *cmd, *cp = *cpp;
@@ -1239,6 +1255,7 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag,
1239 switch (cmdnum) { 1255 switch (cmdnum) {
1240 case I_GET: 1256 case I_GET:
1241 case I_REGET: 1257 case I_REGET:
1258 case I_REPUT:
1242 case I_PUT: 1259 case I_PUT:
1243 if ((optidx = parse_getput_flags(cmd, argv, argc, 1260 if ((optidx = parse_getput_flags(cmd, argv, argc,
1244 aflag, fflag, pflag, rflag)) == -1) 1261 aflag, fflag, pflag, rflag)) == -1)
@@ -1256,11 +1273,6 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag,
1256 /* Destination is not globbed */ 1273 /* Destination is not globbed */
1257 undo_glob_escape(*path2); 1274 undo_glob_escape(*path2);
1258 } 1275 }
1259 if (*aflag && cmdnum == I_PUT) {
1260 /* XXX implement resume for uploads */
1261 error("Resume is not supported for uploads");
1262 return -1;
1263 }
1264 break; 1276 break;
1265 case I_LINK: 1277 case I_LINK:
1266 if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) 1278 if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
@@ -1382,7 +1394,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1382 int err_abort) 1394 int err_abort)
1383{ 1395{
1384 char *path1, *path2, *tmp; 1396 char *path1, *path2, *tmp;
1385 int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0, iflag = 0; 1397 int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0,
1398 iflag = 0;
1386 int lflag = 0, pflag = 0, rflag = 0, sflag = 0; 1399 int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
1387 int cmdnum, i; 1400 int cmdnum, i;
1388 unsigned long n_arg = 0; 1401 unsigned long n_arg = 0;
@@ -1415,9 +1428,12 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1415 err = process_get(conn, path1, path2, *pwd, pflag, 1428 err = process_get(conn, path1, path2, *pwd, pflag,
1416 rflag, aflag, fflag); 1429 rflag, aflag, fflag);
1417 break; 1430 break;
1431 case I_REPUT:
1432 aflag = 1;
1433 /* FALLTHROUGH */
1418 case I_PUT: 1434 case I_PUT:
1419 err = process_put(conn, path1, path2, *pwd, pflag, 1435 err = process_put(conn, path1, path2, *pwd, pflag,
1420 rflag, fflag); 1436 rflag, aflag, fflag);
1421 break; 1437 break;
1422 case I_RENAME: 1438 case I_RENAME:
1423 path1 = make_absolute(path1, *pwd); 1439 path1 = make_absolute(path1, *pwd);
@@ -1834,6 +1850,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1834 pwdlen = tmplen + 1; /* track last seen '/' */ 1850 pwdlen = tmplen + 1; /* track last seen '/' */
1835 } 1851 }
1836 free(tmp); 1852 free(tmp);
1853 tmp = NULL;
1837 1854
1838 if (g.gl_matchc == 0) 1855 if (g.gl_matchc == 0)
1839 goto out; 1856 goto out;
@@ -1841,7 +1858,6 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1841 if (g.gl_matchc > 1) 1858 if (g.gl_matchc > 1)
1842 complete_display(g.gl_pathv, pwdlen); 1859 complete_display(g.gl_pathv, pwdlen);
1843 1860
1844 tmp = NULL;
1845 /* Don't try to extend globs */ 1861 /* Don't try to extend globs */
1846 if (file == NULL || hadglob) 1862 if (file == NULL || hadglob)
1847 goto out; 1863 goto out;
@@ -1904,7 +1920,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1904 lf = el_line(el); 1920 lf = el_line(el);
1905 if (g.gl_matchc == 1) { 1921 if (g.gl_matchc == 1) {
1906 i = 0; 1922 i = 0;
1907 if (!terminated) 1923 if (!terminated && quote != '\0')
1908 ins[i++] = quote; 1924 ins[i++] = quote;
1909 if (*(lf->cursor - 1) != '/' && 1925 if (*(lf->cursor - 1) != '/' &&
1910 (lastarg || *(lf->cursor) != ' ')) 1926 (lastarg || *(lf->cursor) != ' '))
diff --git a/ssh-add.0 b/ssh-add.0
index ba43fee69..f16165ae5 100644
--- a/ssh-add.0
+++ b/ssh-add.0
@@ -1,4 +1,4 @@
1SSH-ADD(1) OpenBSD Reference Manual SSH-ADD(1) 1SSH-ADD(1) General Commands Manual SSH-ADD(1)
2 2
3NAME 3NAME
4 ssh-add - adds private key identities to the authentication agent 4 ssh-add - adds private key identities to the authentication agent
@@ -120,4 +120,4 @@ AUTHORS
120 created OpenSSH. Markus Friedl contributed the support for SSH protocol 120 created OpenSSH. Markus Friedl contributed the support for SSH protocol
121 versions 1.5 and 2.0. 121 versions 1.5 and 2.0.
122 122
123OpenBSD 5.5 December 7, 2013 OpenBSD 5.5 123OpenBSD 5.6 December 7, 2013 OpenBSD 5.6
diff --git a/ssh-add.c b/ssh-add.c
index 3421452af..78a3359ad 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-add.c,v 1.109 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: ssh-add.c,v 1.113 2014/07/09 14:15:56 benno Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -62,6 +62,7 @@
62#include "authfile.h" 62#include "authfile.h"
63#include "pathnames.h" 63#include "pathnames.h"
64#include "misc.h" 64#include "misc.h"
65#include "ssherr.h"
65 66
66/* argv0 */ 67/* argv0 */
67extern char *__progname; 68extern char *__progname;
@@ -170,7 +171,7 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
170 Key *private, *cert; 171 Key *private, *cert;
171 char *comment = NULL; 172 char *comment = NULL;
172 char msg[1024], *certpath = NULL; 173 char msg[1024], *certpath = NULL;
173 int fd, perms_ok, ret = -1; 174 int r, fd, perms_ok, ret = -1;
174 Buffer keyblob; 175 Buffer keyblob;
175 176
176 if (strcmp(filename, "-") == 0) { 177 if (strcmp(filename, "-") == 0) {
@@ -201,12 +202,18 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
201 close(fd); 202 close(fd);
202 203
203 /* At first, try empty passphrase */ 204 /* At first, try empty passphrase */
204 private = key_parse_private(&keyblob, filename, "", &comment); 205 if ((r = sshkey_parse_private_fileblob(&keyblob, "", filename,
206 &private, &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE)
207 fatal("Cannot parse %s: %s", filename, ssh_err(r));
208 /* try last */
209 if (private == NULL && pass != NULL) {
210 if ((r = sshkey_parse_private_fileblob(&keyblob, pass, filename,
211 &private, &comment)) != 0 &&
212 r != SSH_ERR_KEY_WRONG_PASSPHRASE)
213 fatal("Cannot parse %s: %s", filename, ssh_err(r));
214 }
205 if (comment == NULL) 215 if (comment == NULL)
206 comment = xstrdup(filename); 216 comment = xstrdup(filename);
207 /* try last */
208 if (private == NULL && pass != NULL)
209 private = key_parse_private(&keyblob, filename, pass, NULL);
210 if (private == NULL) { 217 if (private == NULL) {
211 /* clear passphrase since it did not work */ 218 /* clear passphrase since it did not work */
212 clear_pass(); 219 clear_pass();
@@ -220,8 +227,11 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
220 buffer_free(&keyblob); 227 buffer_free(&keyblob);
221 return -1; 228 return -1;
222 } 229 }
223 private = key_parse_private(&keyblob, filename, pass, 230 if ((r = sshkey_parse_private_fileblob(&keyblob,
224 &comment); 231 pass, filename, &private, NULL)) != 0 &&
232 r != SSH_ERR_KEY_WRONG_PASSPHRASE)
233 fatal("Cannot parse %s: %s",
234 filename, ssh_err(r));
225 if (private != NULL) 235 if (private != NULL)
226 break; 236 break;
227 clear_pass(); 237 clear_pass();
@@ -427,6 +437,8 @@ main(int argc, char **argv)
427 437
428 OpenSSL_add_all_algorithms(); 438 OpenSSL_add_all_algorithms();
429 439
440 setlinebuf(stdout);
441
430 /* At first, get a connection to the authentication agent. */ 442 /* At first, get a connection to the authentication agent. */
431 ac = ssh_get_authentication_connection(); 443 ac = ssh_get_authentication_connection();
432 if (ac == NULL) { 444 if (ac == NULL) {
diff --git a/ssh-agent.0 b/ssh-agent.0
index c11523db3..cac40e048 100644
--- a/ssh-agent.0
+++ b/ssh-agent.0
@@ -1,4 +1,4 @@
1SSH-AGENT(1) OpenBSD Reference Manual SSH-AGENT(1) 1SSH-AGENT(1) General Commands Manual SSH-AGENT(1)
2 2
3NAME 3NAME
4 ssh-agent - authentication agent 4 ssh-agent - authentication agent
@@ -9,12 +9,18 @@ SYNOPSIS
9 9
10DESCRIPTION 10DESCRIPTION
11 ssh-agent is a program to hold private keys used for public key 11 ssh-agent is a program to hold private keys used for public key
12 authentication (RSA, DSA, ECDSA, ED25519). The idea is that ssh-agent is 12 authentication (RSA, DSA, ECDSA, ED25519). ssh-agent is usually started
13 started in the beginning of an X-session or a login session, and all 13 in the beginning of an X-session or a login session, and all other
14 other windows or programs are started as clients to the ssh-agent 14 windows or programs are started as clients to the ssh-agent program.
15 program. Through use of environment variables the agent can be located 15 Through use of environment variables the agent can be located and
16 and automatically used for authentication when logging in to other 16 automatically used for authentication when logging in to other machines
17 machines using ssh(1). 17 using ssh(1).
18
19 The agent initially does not have any private keys. Keys are added using
20 ssh-add(1). Multiple identities may be stored in ssh-agent concurrently
21 and ssh(1) will automatically use them if present. ssh-add(1) is also
22 used to remove keys from ssh-agent and to query the keys that are held in
23 one.
18 24
19 The options are as follows: 25 The options are as follows:
20 26
@@ -44,17 +50,6 @@ DESCRIPTION
44 If a commandline is given, this is executed as a subprocess of the agent. 50 If a commandline is given, this is executed as a subprocess of the agent.
45 When the command dies, so does the agent. 51 When the command dies, so does the agent.
46 52
47 The agent initially does not have any private keys. Keys are added using
48 ssh-add(1). When executed without arguments, ssh-add(1) adds the files
49 ~/.ssh/id_rsa, ~/.ssh/id_dsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ed25519 and
50 ~/.ssh/identity. If the identity has a passphrase, ssh-add(1) asks for
51 the passphrase on the terminal if it has one or from a small X11 program
52 if running under X11. If neither of these is the case then the
53 authentication will fail. It then sends the identity to the agent.
54 Several identities can be stored in the agent; the agent can
55 automatically use any of these identities. ssh-add -l displays the
56 identities currently held by the agent.
57
58 The idea is that the agent is run in the user's local PC, laptop, or 53 The idea is that the agent is run in the user's local PC, laptop, or
59 terminal. Authentication data need not be stored on any other machine, 54 terminal. Authentication data need not be stored on any other machine,
60 and authentication passphrases never go over the network. However, the 55 and authentication passphrases never go over the network. However, the
@@ -89,26 +84,6 @@ DESCRIPTION
89 terminates. 84 terminates.
90 85
91FILES 86FILES
92 ~/.ssh/identity
93 Contains the protocol version 1 RSA authentication identity of
94 the user.
95
96 ~/.ssh/id_dsa
97 Contains the protocol version 2 DSA authentication identity of
98 the user.
99
100 ~/.ssh/id_ecdsa
101 Contains the protocol version 2 ECDSA authentication identity of
102 the user.
103
104 ~/.ssh/id_ed25519
105 Contains the protocol version 2 ED25519 authentication identity
106 of the user.
107
108 ~/.ssh/id_rsa
109 Contains the protocol version 2 RSA authentication identity of
110 the user.
111
112 $TMPDIR/ssh-XXXXXXXXXX/agent.<ppid> 87 $TMPDIR/ssh-XXXXXXXXXX/agent.<ppid>
113 UNIX-domain sockets used to contain the connection to the 88 UNIX-domain sockets used to contain the connection to the
114 authentication agent. These sockets should only be readable by 89 authentication agent. These sockets should only be readable by
@@ -125,4 +100,4 @@ AUTHORS
125 created OpenSSH. Markus Friedl contributed the support for SSH protocol 100 created OpenSSH. Markus Friedl contributed the support for SSH protocol
126 versions 1.5 and 2.0. 101 versions 1.5 and 2.0.
127 102
128OpenBSD 5.5 December 7, 2013 OpenBSD 5.5 103OpenBSD 5.6 April 16, 2014 OpenBSD 5.6
diff --git a/ssh-agent.1 b/ssh-agent.1
index 281ecbdcf..a1e634fe0 100644
--- a/ssh-agent.1
+++ b/ssh-agent.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: ssh-agent.1,v 1.54 2013/12/07 11:58:46 naddy Exp $ 1.\" $OpenBSD: ssh-agent.1,v 1.55 2014/04/16 23:28:12 djm Exp $
2.\" 2.\"
3.\" Author: Tatu Ylonen <ylo@cs.hut.fi> 3.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
4.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -34,7 +34,7 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.Dd $Mdocdate: December 7 2013 $ 37.Dd $Mdocdate: April 16 2014 $
38.Dt SSH-AGENT 1 38.Dt SSH-AGENT 1
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -54,9 +54,8 @@
54.Nm 54.Nm
55is a program to hold private keys used for public key authentication 55is a program to hold private keys used for public key authentication
56(RSA, DSA, ECDSA, ED25519). 56(RSA, DSA, ECDSA, ED25519).
57The idea is that
58.Nm 57.Nm
59is started in the beginning of an X-session or a login session, and 58is usually started in the beginning of an X-session or a login session, and
60all other windows or programs are started as clients to the ssh-agent 59all other windows or programs are started as clients to the ssh-agent
61program. 60program.
62Through use of environment variables the agent can be located 61Through use of environment variables the agent can be located
@@ -64,6 +63,19 @@ and automatically used for authentication when logging in to other
64machines using 63machines using
65.Xr ssh 1 . 64.Xr ssh 1 .
66.Pp 65.Pp
66The agent initially does not have any private keys.
67Keys are added using
68.Xr ssh-add 1 .
69Multiple identities may be stored in
70.Nm
71concurrently and
72.Xr ssh 1
73will automatically use them if present.
74.Xr ssh-add 1
75is also used to remove keys from
76.Nm
77and to query the keys that are held in one.
78.Pp
67The options are as follows: 79The options are as follows:
68.Bl -tag -width Ds 80.Bl -tag -width Ds
69.It Fl a Ar bind_address 81.It Fl a Ar bind_address
@@ -107,29 +119,6 @@ Without this option the default maximum lifetime is forever.
107If a commandline is given, this is executed as a subprocess of the agent. 119If a commandline is given, this is executed as a subprocess of the agent.
108When the command dies, so does the agent. 120When the command dies, so does the agent.
109.Pp 121.Pp
110The agent initially does not have any private keys.
111Keys are added using
112.Xr ssh-add 1 .
113When executed without arguments,
114.Xr ssh-add 1
115adds the files
116.Pa ~/.ssh/id_rsa ,
117.Pa ~/.ssh/id_dsa ,
118.Pa ~/.ssh/id_ecdsa ,
119.Pa ~/.ssh/id_ed25519
120and
121.Pa ~/.ssh/identity .
122If the identity has a passphrase,
123.Xr ssh-add 1
124asks for the passphrase on the terminal if it has one or from a small X11
125program if running under X11.
126If neither of these is the case then the authentication will fail.
127It then sends the identity to the agent.
128Several identities can be stored in the
129agent; the agent can automatically use any of these identities.
130.Ic ssh-add -l
131displays the identities currently held by the agent.
132.Pp
133The idea is that the agent is run in the user's local PC, laptop, or 122The idea is that the agent is run in the user's local PC, laptop, or
134terminal. 123terminal.
135Authentication data need not be stored on any other 124Authentication data need not be stored on any other
@@ -185,16 +174,6 @@ The agent exits automatically when the command given on the command
185line terminates. 174line terminates.
186.Sh FILES 175.Sh FILES
187.Bl -tag -width Ds 176.Bl -tag -width Ds
188.It Pa ~/.ssh/identity
189Contains the protocol version 1 RSA authentication identity of the user.
190.It Pa ~/.ssh/id_dsa
191Contains the protocol version 2 DSA authentication identity of the user.
192.It Pa ~/.ssh/id_ecdsa
193Contains the protocol version 2 ECDSA authentication identity of the user.
194.It Pa ~/.ssh/id_ed25519
195Contains the protocol version 2 ED25519 authentication identity of the user.
196.It Pa ~/.ssh/id_rsa
197Contains the protocol version 2 RSA authentication identity of the user.
198.It Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt 177.It Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt
199.Ux Ns -domain 178.Ux Ns -domain
200sockets used to contain the connection to the authentication agent. 179sockets used to contain the connection to the authentication agent.
diff --git a/ssh-agent.c b/ssh-agent.c
index ba2461211..25f10c549 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-agent.c,v 1.183 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: ssh-agent.c,v 1.190 2014/07/25 21:22:03 dtucker Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -49,8 +49,10 @@
49#endif 49#endif
50#include "openbsd-compat/sys-queue.h" 50#include "openbsd-compat/sys-queue.h"
51 51
52#ifdef WITH_OPENSSL
52#include <openssl/evp.h> 53#include <openssl/evp.h>
53#include "openbsd-compat/openssl-compat.h" 54#include "openbsd-compat/openssl-compat.h"
55#endif
54 56
55#include <errno.h> 57#include <errno.h>
56#include <fcntl.h> 58#include <fcntl.h>
@@ -124,6 +126,9 @@ int max_fd = 0;
124pid_t parent_pid = -1; 126pid_t parent_pid = -1;
125time_t parent_alive_interval = 0; 127time_t parent_alive_interval = 0;
126 128
129/* pid of process for which cleanup_socket is applicable */
130pid_t cleanup_pid = 0;
131
127/* pathname and directory for AUTH_SOCKET */ 132/* pathname and directory for AUTH_SOCKET */
128char socket_name[MAXPATHLEN]; 133char socket_name[MAXPATHLEN];
129char socket_dir[MAXPATHLEN]; 134char socket_dir[MAXPATHLEN];
@@ -221,9 +226,11 @@ process_request_identities(SocketEntry *e, int version)
221 buffer_put_int(&msg, tab->nentries); 226 buffer_put_int(&msg, tab->nentries);
222 TAILQ_FOREACH(id, &tab->idlist, next) { 227 TAILQ_FOREACH(id, &tab->idlist, next) {
223 if (id->key->type == KEY_RSA1) { 228 if (id->key->type == KEY_RSA1) {
229#ifdef WITH_SSH1
224 buffer_put_int(&msg, BN_num_bits(id->key->rsa->n)); 230 buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
225 buffer_put_bignum(&msg, id->key->rsa->e); 231 buffer_put_bignum(&msg, id->key->rsa->e);
226 buffer_put_bignum(&msg, id->key->rsa->n); 232 buffer_put_bignum(&msg, id->key->rsa->n);
233#endif
227 } else { 234 } else {
228 u_char *blob; 235 u_char *blob;
229 u_int blen; 236 u_int blen;
@@ -238,6 +245,7 @@ process_request_identities(SocketEntry *e, int version)
238 buffer_free(&msg); 245 buffer_free(&msg);
239} 246}
240 247
248#ifdef WITH_SSH1
241/* ssh1 only */ 249/* ssh1 only */
242static void 250static void
243process_authentication_challenge1(SocketEntry *e) 251process_authentication_challenge1(SocketEntry *e)
@@ -273,7 +281,7 @@ process_authentication_challenge1(SocketEntry *e)
273 if (id != NULL && (!id->confirm || confirm_key(id) == 0)) { 281 if (id != NULL && (!id->confirm || confirm_key(id) == 0)) {
274 Key *private = id->key; 282 Key *private = id->key;
275 /* Decrypt the challenge using the private key. */ 283 /* Decrypt the challenge using the private key. */
276 if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) 284 if (rsa_private_decrypt(challenge, challenge, private->rsa) != 0)
277 goto failure; 285 goto failure;
278 286
279 /* The response is MD5 of decrypted challenge plus session id. */ 287 /* The response is MD5 of decrypted challenge plus session id. */
@@ -308,6 +316,7 @@ send:
308 BN_clear_free(challenge); 316 BN_clear_free(challenge);
309 buffer_free(&msg); 317 buffer_free(&msg);
310} 318}
319#endif
311 320
312/* ssh2 only */ 321/* ssh2 only */
313static void 322static void
@@ -359,12 +368,16 @@ process_sign_request2(SocketEntry *e)
359static void 368static void
360process_remove_identity(SocketEntry *e, int version) 369process_remove_identity(SocketEntry *e, int version)
361{ 370{
362 u_int blen, bits; 371 u_int blen;
363 int success = 0; 372 int success = 0;
364 Key *key = NULL; 373 Key *key = NULL;
365 u_char *blob; 374 u_char *blob;
375#ifdef WITH_SSH1
376 u_int bits;
377#endif /* WITH_SSH1 */
366 378
367 switch (version) { 379 switch (version) {
380#ifdef WITH_SSH1
368 case 1: 381 case 1:
369 key = key_new(KEY_RSA1); 382 key = key_new(KEY_RSA1);
370 bits = buffer_get_int(&e->request); 383 bits = buffer_get_int(&e->request);
@@ -375,6 +388,7 @@ process_remove_identity(SocketEntry *e, int version)
375 logit("Warning: identity keysize mismatch: actual %u, announced %u", 388 logit("Warning: identity keysize mismatch: actual %u, announced %u",
376 key_size(key), bits); 389 key_size(key), bits);
377 break; 390 break;
391#endif /* WITH_SSH1 */
378 case 2: 392 case 2:
379 blob = buffer_get_string(&e->request, &blen); 393 blob = buffer_get_string(&e->request, &blen);
380 key = key_from_blob(blob, blen); 394 key = key_from_blob(blob, blen);
@@ -471,6 +485,7 @@ process_add_identity(SocketEntry *e, int version)
471 Key *k = NULL; 485 Key *k = NULL;
472 486
473 switch (version) { 487 switch (version) {
488#ifdef WITH_SSH1
474 case 1: 489 case 1:
475 k = key_new_private(KEY_RSA1); 490 k = key_new_private(KEY_RSA1);
476 (void) buffer_get_int(&e->request); /* ignored */ 491 (void) buffer_get_int(&e->request); /* ignored */
@@ -484,7 +499,9 @@ process_add_identity(SocketEntry *e, int version)
484 buffer_get_bignum(&e->request, k->rsa->p); /* q */ 499 buffer_get_bignum(&e->request, k->rsa->p); /* q */
485 500
486 /* Generate additional parameters */ 501 /* Generate additional parameters */
487 rsa_generate_additional_parameters(k->rsa); 502 if (rsa_generate_additional_parameters(k->rsa) != 0)
503 fatal("%s: rsa_generate_additional_parameters "
504 "error", __func__);
488 505
489 /* enable blinding */ 506 /* enable blinding */
490 if (RSA_blinding_on(k->rsa, NULL) != 1) { 507 if (RSA_blinding_on(k->rsa, NULL) != 1) {
@@ -493,6 +510,7 @@ process_add_identity(SocketEntry *e, int version)
493 goto send; 510 goto send;
494 } 511 }
495 break; 512 break;
513#endif /* WITH_SSH1 */
496 case 2: 514 case 2:
497 k = key_private_deserialize(&e->request); 515 k = key_private_deserialize(&e->request);
498 if (k == NULL) { 516 if (k == NULL) {
@@ -501,11 +519,10 @@ process_add_identity(SocketEntry *e, int version)
501 } 519 }
502 break; 520 break;
503 } 521 }
504 comment = buffer_get_string(&e->request, NULL); 522 if (k == NULL)
505 if (k == NULL) {
506 free(comment);
507 goto send; 523 goto send;
508 } 524 comment = buffer_get_string(&e->request, NULL);
525
509 while (buffer_len(&e->request)) { 526 while (buffer_len(&e->request)) {
510 switch ((type = buffer_get_char(&e->request))) { 527 switch ((type = buffer_get_char(&e->request))) {
511 case SSH_AGENT_CONSTRAIN_LIFETIME: 528 case SSH_AGENT_CONSTRAIN_LIFETIME:
@@ -733,6 +750,7 @@ process_message(SocketEntry *e)
733 case SSH_AGENTC_UNLOCK: 750 case SSH_AGENTC_UNLOCK:
734 process_lock_agent(e, type == SSH_AGENTC_LOCK); 751 process_lock_agent(e, type == SSH_AGENTC_LOCK);
735 break; 752 break;
753#ifdef WITH_SSH1
736 /* ssh1 */ 754 /* ssh1 */
737 case SSH_AGENTC_RSA_CHALLENGE: 755 case SSH_AGENTC_RSA_CHALLENGE:
738 process_authentication_challenge1(e); 756 process_authentication_challenge1(e);
@@ -750,6 +768,7 @@ process_message(SocketEntry *e)
750 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES: 768 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
751 process_remove_all_identities(e, 1); 769 process_remove_all_identities(e, 1);
752 break; 770 break;
771#endif
753 /* ssh2 */ 772 /* ssh2 */
754 case SSH2_AGENTC_SIGN_REQUEST: 773 case SSH2_AGENTC_SIGN_REQUEST:
755 process_sign_request2(e); 774 process_sign_request2(e);
@@ -949,6 +968,7 @@ after_select(fd_set *readset, fd_set *writeset)
949 break; 968 break;
950 } 969 }
951 buffer_append(&sockets[i].input, buf, len); 970 buffer_append(&sockets[i].input, buf, len);
971 explicit_bzero(buf, sizeof(buf));
952 process_message(&sockets[i]); 972 process_message(&sockets[i]);
953 } 973 }
954 break; 974 break;
@@ -960,6 +980,9 @@ after_select(fd_set *readset, fd_set *writeset)
960static void 980static void
961cleanup_socket(void) 981cleanup_socket(void)
962{ 982{
983 if (cleanup_pid != 0 && getpid() != cleanup_pid)
984 return;
985 debug("%s: cleanup", __func__);
963 if (socket_name[0]) 986 if (socket_name[0])
964 unlink(socket_name); 987 unlink(socket_name);
965 if (socket_dir[0]) 988 if (socket_dir[0])
@@ -1001,15 +1024,10 @@ check_parent_exists(void)
1001static void 1024static void
1002usage(void) 1025usage(void)
1003{ 1026{
1004 fprintf(stderr, "usage: %s [options] [command [arg ...]]\n", 1027 fprintf(stderr,
1005 __progname); 1028 "usage: ssh-agent [-c | -s] [-d] [-a bind_address] [-t life]\n"
1006 fprintf(stderr, "Options:\n"); 1029 " [command [arg ...]]\n"
1007 fprintf(stderr, " -c Generate C-shell commands on stdout.\n"); 1030 " ssh-agent [-c | -s] -k\n");
1008 fprintf(stderr, " -s Generate Bourne shell commands on stdout.\n");
1009 fprintf(stderr, " -k Kill the current agent.\n");
1010 fprintf(stderr, " -d Debug mode.\n");
1011 fprintf(stderr, " -a socket Bind agent socket to given name.\n");
1012 fprintf(stderr, " -t life Default identity lifetime (seconds).\n");
1013 exit(1); 1031 exit(1);
1014} 1032}
1015 1033
@@ -1021,17 +1039,16 @@ main(int ac, char **av)
1021 u_int nalloc; 1039 u_int nalloc;
1022 char *shell, *format, *pidstr, *agentsocket = NULL; 1040 char *shell, *format, *pidstr, *agentsocket = NULL;
1023 fd_set *readsetp = NULL, *writesetp = NULL; 1041 fd_set *readsetp = NULL, *writesetp = NULL;
1024 struct sockaddr_un sunaddr;
1025#ifdef HAVE_SETRLIMIT 1042#ifdef HAVE_SETRLIMIT
1026 struct rlimit rlim; 1043 struct rlimit rlim;
1027#endif 1044#endif
1028 int prev_mask;
1029 extern int optind; 1045 extern int optind;
1030 extern char *optarg; 1046 extern char *optarg;
1031 pid_t pid; 1047 pid_t pid;
1032 char pidstrbuf[1 + 3 * sizeof pid]; 1048 char pidstrbuf[1 + 3 * sizeof pid];
1033 struct timeval *tvp = NULL; 1049 struct timeval *tvp = NULL;
1034 size_t len; 1050 size_t len;
1051 mode_t prev_mask;
1035 1052
1036 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 1053 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1037 sanitise_stdfd(); 1054 sanitise_stdfd();
@@ -1045,7 +1062,9 @@ main(int ac, char **av)
1045 prctl(PR_SET_DUMPABLE, 0); 1062 prctl(PR_SET_DUMPABLE, 0);
1046#endif 1063#endif
1047 1064
1065#ifdef WITH_OPENSSL
1048 OpenSSL_add_all_algorithms(); 1066 OpenSSL_add_all_algorithms();
1067#endif
1049 1068
1050 __progname = ssh_get_progname(av[0]); 1069 __progname = ssh_get_progname(av[0]);
1051 seed_rng(); 1070 seed_rng();
@@ -1142,27 +1161,14 @@ main(int ac, char **av)
1142 * Create socket early so it will exist before command gets run from 1161 * Create socket early so it will exist before command gets run from
1143 * the parent. 1162 * the parent.
1144 */ 1163 */
1145 sock = socket(AF_UNIX, SOCK_STREAM, 0);
1146 if (sock < 0) {
1147 perror("socket");
1148 *socket_name = '\0'; /* Don't unlink any existing file */
1149 cleanup_exit(1);
1150 }
1151 memset(&sunaddr, 0, sizeof(sunaddr));
1152 sunaddr.sun_family = AF_UNIX;
1153 strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
1154 prev_mask = umask(0177); 1164 prev_mask = umask(0177);
1155 if (bind(sock, (struct sockaddr *) &sunaddr, sizeof(sunaddr)) < 0) { 1165 sock = unix_listener(socket_name, SSH_LISTEN_BACKLOG, 0);
1156 perror("bind"); 1166 if (sock < 0) {
1167 /* XXX - unix_listener() calls error() not perror() */
1157 *socket_name = '\0'; /* Don't unlink any existing file */ 1168 *socket_name = '\0'; /* Don't unlink any existing file */
1158 umask(prev_mask);
1159 cleanup_exit(1); 1169 cleanup_exit(1);
1160 } 1170 }
1161 umask(prev_mask); 1171 umask(prev_mask);
1162 if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
1163 perror("listen");
1164 cleanup_exit(1);
1165 }
1166 1172
1167 /* 1173 /*
1168 * Fork, and have the parent execute the command, if any, or present 1174 * Fork, and have the parent execute the command, if any, or present
@@ -1231,6 +1237,8 @@ main(int ac, char **av)
1231 1237
1232skip: 1238skip:
1233 1239
1240 cleanup_pid = getpid();
1241
1234#ifdef ENABLE_PKCS11 1242#ifdef ENABLE_PKCS11
1235 pkcs11_init(0); 1243 pkcs11_init(0);
1236#endif 1244#endif
diff --git a/ssh-dss.c b/ssh-dss.c
index 6b4abcb7d..9643d90d8 100644
--- a/ssh-dss.c
+++ b/ssh-dss.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-dss.c,v 1.31 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: ssh-dss.c,v 1.32 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -28,162 +28,192 @@
28#include <sys/types.h> 28#include <sys/types.h>
29 29
30#include <openssl/bn.h> 30#include <openssl/bn.h>
31#include <openssl/dsa.h>
31#include <openssl/evp.h> 32#include <openssl/evp.h>
32 33
33#include <stdarg.h> 34#include <stdarg.h>
34#include <string.h> 35#include <string.h>
35 36
36#include "xmalloc.h" 37#include "sshbuf.h"
37#include "buffer.h"
38#include "compat.h" 38#include "compat.h"
39#include "log.h" 39#include "ssherr.h"
40#include "key.h"
41#include "digest.h" 40#include "digest.h"
41#define SSHKEY_INTERNAL
42#include "sshkey.h"
42 43
43#define INTBLOB_LEN 20 44#define INTBLOB_LEN 20
44#define SIGBLOB_LEN (2*INTBLOB_LEN) 45#define SIGBLOB_LEN (2*INTBLOB_LEN)
45 46
46int 47int
47ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp, 48ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
48 const u_char *data, u_int datalen) 49 const u_char *data, size_t datalen, u_int compat)
49{ 50{
50 DSA_SIG *sig; 51 DSA_SIG *sig = NULL;
51 u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; 52 u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
52 u_int rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 53 size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
53 Buffer b; 54 struct sshbuf *b = NULL;
54 55 int ret = SSH_ERR_INVALID_ARGUMENT;
55 if (key == NULL || key_type_plain(key->type) != KEY_DSA || 56
56 key->dsa == NULL) { 57 if (lenp != NULL)
57 error("%s: no DSA key", __func__); 58 *lenp = 0;
58 return -1; 59 if (sigp != NULL)
59 } 60 *sigp = NULL;
60 61
61 if (ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 62 if (key == NULL || key->dsa == NULL ||
62 digest, sizeof(digest)) != 0) { 63 sshkey_type_plain(key->type) != KEY_DSA)
63 error("%s: ssh_digest_memory failed", __func__); 64 return SSH_ERR_INVALID_ARGUMENT;
64 return -1; 65 if (dlen == 0)
65 } 66 return SSH_ERR_INTERNAL_ERROR;
66 67
67 sig = DSA_do_sign(digest, dlen, key->dsa); 68 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
68 explicit_bzero(digest, sizeof(digest)); 69 digest, sizeof(digest))) != 0)
69 70 goto out;
70 if (sig == NULL) { 71
71 error("ssh_dss_sign: sign failed"); 72 if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
72 return -1; 73 ret = SSH_ERR_LIBCRYPTO_ERROR;
74 goto out;
73 } 75 }
74 76
75 rlen = BN_num_bytes(sig->r); 77 rlen = BN_num_bytes(sig->r);
76 slen = BN_num_bytes(sig->s); 78 slen = BN_num_bytes(sig->s);
77 if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 79 if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
78 error("bad sig size %u %u", rlen, slen); 80 ret = SSH_ERR_INTERNAL_ERROR;
79 DSA_SIG_free(sig); 81 goto out;
80 return -1;
81 } 82 }
82 explicit_bzero(sigblob, SIGBLOB_LEN); 83 explicit_bzero(sigblob, SIGBLOB_LEN);
83 BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen); 84 BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
84 BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen); 85 BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen);
85 DSA_SIG_free(sig);
86 86
87 if (datafellows & SSH_BUG_SIGBLOB) { 87 if (compat & SSH_BUG_SIGBLOB) {
88 if (lenp != NULL)
89 *lenp = SIGBLOB_LEN;
90 if (sigp != NULL) { 88 if (sigp != NULL) {
91 *sigp = xmalloc(SIGBLOB_LEN); 89 if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) {
90 ret = SSH_ERR_ALLOC_FAIL;
91 goto out;
92 }
92 memcpy(*sigp, sigblob, SIGBLOB_LEN); 93 memcpy(*sigp, sigblob, SIGBLOB_LEN);
93 } 94 }
95 if (lenp != NULL)
96 *lenp = SIGBLOB_LEN;
97 ret = 0;
94 } else { 98 } else {
95 /* ietf-drafts */ 99 /* ietf-drafts */
96 buffer_init(&b); 100 if ((b = sshbuf_new()) == NULL) {
97 buffer_put_cstring(&b, "ssh-dss"); 101 ret = SSH_ERR_ALLOC_FAIL;
98 buffer_put_string(&b, sigblob, SIGBLOB_LEN); 102 goto out;
99 len = buffer_len(&b); 103 }
100 if (lenp != NULL) 104 if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
101 *lenp = len; 105 (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
106 goto out;
107 len = sshbuf_len(b);
102 if (sigp != NULL) { 108 if (sigp != NULL) {
103 *sigp = xmalloc(len); 109 if ((*sigp = malloc(len)) == NULL) {
104 memcpy(*sigp, buffer_ptr(&b), len); 110 ret = SSH_ERR_ALLOC_FAIL;
111 goto out;
112 }
113 memcpy(*sigp, sshbuf_ptr(b), len);
105 } 114 }
106 buffer_free(&b); 115 if (lenp != NULL)
116 *lenp = len;
117 ret = 0;
107 } 118 }
108 return 0; 119 out:
120 explicit_bzero(digest, sizeof(digest));
121 if (sig != NULL)
122 DSA_SIG_free(sig);
123 if (b != NULL)
124 sshbuf_free(b);
125 return ret;
109} 126}
127
110int 128int
111ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen, 129ssh_dss_verify(const struct sshkey *key,
112 const u_char *data, u_int datalen) 130 const u_char *signature, size_t signaturelen,
131 const u_char *data, size_t datalen, u_int compat)
113{ 132{
114 DSA_SIG *sig; 133 DSA_SIG *sig = NULL;
115 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; 134 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
116 u_int len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 135 size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
117 int rlen, ret; 136 int ret = SSH_ERR_INTERNAL_ERROR;
118 Buffer b; 137 struct sshbuf *b = NULL;
119 138 char *ktype = NULL;
120 if (key == NULL || key_type_plain(key->type) != KEY_DSA || 139
121 key->dsa == NULL) { 140 if (key == NULL || key->dsa == NULL ||
122 error("%s: no DSA key", __func__); 141 sshkey_type_plain(key->type) != KEY_DSA)
123 return -1; 142 return SSH_ERR_INVALID_ARGUMENT;
124 } 143 if (dlen == 0)
144 return SSH_ERR_INTERNAL_ERROR;
125 145
126 /* fetch signature */ 146 /* fetch signature */
127 if (datafellows & SSH_BUG_SIGBLOB) { 147 if (compat & SSH_BUG_SIGBLOB) {
128 sigblob = xmalloc(signaturelen); 148 if ((sigblob = malloc(signaturelen)) == NULL)
149 return SSH_ERR_ALLOC_FAIL;
129 memcpy(sigblob, signature, signaturelen); 150 memcpy(sigblob, signature, signaturelen);
130 len = signaturelen; 151 len = signaturelen;
131 } else { 152 } else {
132 /* ietf-drafts */ 153 /* ietf-drafts */
133 char *ktype; 154 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
134 buffer_init(&b); 155 return SSH_ERR_ALLOC_FAIL;
135 buffer_append(&b, signature, signaturelen); 156 if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
136 ktype = buffer_get_cstring(&b, NULL); 157 sshbuf_get_string(b, &sigblob, &len) != 0) {
158 ret = SSH_ERR_INVALID_FORMAT;
159 goto out;
160 }
137 if (strcmp("ssh-dss", ktype) != 0) { 161 if (strcmp("ssh-dss", ktype) != 0) {
138 error("%s: cannot handle type %s", __func__, ktype); 162 ret = SSH_ERR_KEY_TYPE_MISMATCH;
139 buffer_free(&b); 163 goto out;
140 free(ktype);
141 return -1;
142 } 164 }
143 free(ktype); 165 if (sshbuf_len(b) != 0) {
144 sigblob = buffer_get_string(&b, &len); 166 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
145 rlen = buffer_len(&b); 167 goto out;
146 buffer_free(&b);
147 if (rlen != 0) {
148 error("%s: remaining bytes in signature %d",
149 __func__, rlen);
150 free(sigblob);
151 return -1;
152 } 168 }
153 } 169 }
154 170
155 if (len != SIGBLOB_LEN) { 171 if (len != SIGBLOB_LEN) {
156 fatal("bad sigbloblen %u != SIGBLOB_LEN", len); 172 ret = SSH_ERR_INVALID_FORMAT;
173 goto out;
157 } 174 }
158 175
159 /* parse signature */ 176 /* parse signature */
160 if ((sig = DSA_SIG_new()) == NULL) 177 if ((sig = DSA_SIG_new()) == NULL ||
161 fatal("%s: DSA_SIG_new failed", __func__); 178 (sig->r = BN_new()) == NULL ||
162 if ((sig->r = BN_new()) == NULL) 179 (sig->s = BN_new()) == NULL) {
163 fatal("%s: BN_new failed", __func__); 180 ret = SSH_ERR_ALLOC_FAIL;
164 if ((sig->s = BN_new()) == NULL) 181 goto out;
165 fatal("ssh_dss_verify: BN_new failed"); 182 }
166 if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) || 183 if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) ||
167 (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) 184 (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) {
168 fatal("%s: BN_bin2bn failed", __func__); 185 ret = SSH_ERR_LIBCRYPTO_ERROR;
169 186 goto out;
170 /* clean up */ 187 }
171 explicit_bzero(sigblob, len);
172 free(sigblob);
173 188
174 /* sha1 the data */ 189 /* sha1 the data */
175 if (ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 190 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
176 digest, sizeof(digest)) != 0) { 191 digest, sizeof(digest))) != 0)
177 error("%s: digest_memory failed", __func__); 192 goto out;
178 return -1; 193
194 switch (DSA_do_verify(digest, dlen, sig, key->dsa)) {
195 case 1:
196 ret = 0;
197 break;
198 case 0:
199 ret = SSH_ERR_SIGNATURE_INVALID;
200 goto out;
201 default:
202 ret = SSH_ERR_LIBCRYPTO_ERROR;
203 goto out;
179 } 204 }
180 205
181 ret = DSA_do_verify(digest, dlen, sig, key->dsa); 206 out:
182 explicit_bzero(digest, sizeof(digest)); 207 explicit_bzero(digest, sizeof(digest));
183 208 if (sig != NULL)
184 DSA_SIG_free(sig); 209 DSA_SIG_free(sig);
185 210 if (b != NULL)
186 debug("%s: signature %s", __func__, 211 sshbuf_free(b);
187 ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); 212 if (ktype != NULL)
213 free(ktype);
214 if (sigblob != NULL) {
215 explicit_bzero(sigblob, len);
216 free(sigblob);
217 }
188 return ret; 218 return ret;
189} 219}
diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c
index 551c9c460..1119db045 100644
--- a/ssh-ecdsa.c
+++ b/ssh-ecdsa.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-ecdsa.c,v 1.10 2014/02/03 23:28:00 djm Exp $ */ 1/* $OpenBSD: ssh-ecdsa.c,v 1.11 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Copyright (c) 2010 Damien Miller. All rights reserved. 4 * Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -37,141 +37,155 @@
37 37
38#include <string.h> 38#include <string.h>
39 39
40#include "xmalloc.h" 40#include "sshbuf.h"
41#include "buffer.h" 41#include "ssherr.h"
42#include "compat.h"
43#include "log.h"
44#include "key.h"
45#include "digest.h" 42#include "digest.h"
43#define SSHKEY_INTERNAL
44#include "sshkey.h"
46 45
46/* ARGSUSED */
47int 47int
48ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp, 48ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
49 const u_char *data, u_int datalen) 49 const u_char *data, size_t datalen, u_int compat)
50{ 50{
51 ECDSA_SIG *sig; 51 ECDSA_SIG *sig = NULL;
52 int hash_alg; 52 int hash_alg;
53 u_char digest[SSH_DIGEST_MAX_LENGTH]; 53 u_char digest[SSH_DIGEST_MAX_LENGTH];
54 u_int len, dlen; 54 size_t len, dlen;
55 Buffer b, bb; 55 struct sshbuf *b = NULL, *bb = NULL;
56 int ret = SSH_ERR_INTERNAL_ERROR;
56 57
57 if (key == NULL || key_type_plain(key->type) != KEY_ECDSA || 58 if (lenp != NULL)
58 key->ecdsa == NULL) { 59 *lenp = 0;
59 error("%s: no ECDSA key", __func__); 60 if (sigp != NULL)
60 return -1; 61 *sigp = NULL;
62
63 if (key == NULL || key->ecdsa == NULL ||
64 sshkey_type_plain(key->type) != KEY_ECDSA)
65 return SSH_ERR_INVALID_ARGUMENT;
66
67 if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
68 (dlen = ssh_digest_bytes(hash_alg)) == 0)
69 return SSH_ERR_INTERNAL_ERROR;
70 if ((ret = ssh_digest_memory(hash_alg, data, datalen,
71 digest, sizeof(digest))) != 0)
72 goto out;
73
74 if ((sig = ECDSA_do_sign(digest, dlen, key->ecdsa)) == NULL) {
75 ret = SSH_ERR_LIBCRYPTO_ERROR;
76 goto out;
61 } 77 }
62 78
63 hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid); 79 if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) {
64 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 80 ret = SSH_ERR_ALLOC_FAIL;
65 error("%s: bad hash algorithm %d", __func__, hash_alg); 81 goto out;
66 return -1;
67 }
68 if (ssh_digest_memory(hash_alg, data, datalen,
69 digest, sizeof(digest)) != 0) {
70 error("%s: digest_memory failed", __func__);
71 return -1;
72 } 82 }
73 83 if ((ret = sshbuf_put_bignum2(bb, sig->r)) != 0 ||
74 sig = ECDSA_do_sign(digest, dlen, key->ecdsa); 84 (ret = sshbuf_put_bignum2(bb, sig->s)) != 0)
75 explicit_bzero(digest, sizeof(digest)); 85 goto out;
76 86 if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 ||
77 if (sig == NULL) { 87 (ret = sshbuf_put_stringb(b, bb)) != 0)
78 error("%s: sign failed", __func__); 88 goto out;
79 return -1; 89 len = sshbuf_len(b);
90 if (sigp != NULL) {
91 if ((*sigp = malloc(len)) == NULL) {
92 ret = SSH_ERR_ALLOC_FAIL;
93 goto out;
94 }
95 memcpy(*sigp, sshbuf_ptr(b), len);
80 } 96 }
81
82 buffer_init(&bb);
83 buffer_put_bignum2(&bb, sig->r);
84 buffer_put_bignum2(&bb, sig->s);
85 ECDSA_SIG_free(sig);
86
87 buffer_init(&b);
88 buffer_put_cstring(&b, key_ssh_name_plain(key));
89 buffer_put_string(&b, buffer_ptr(&bb), buffer_len(&bb));
90 buffer_free(&bb);
91 len = buffer_len(&b);
92 if (lenp != NULL) 97 if (lenp != NULL)
93 *lenp = len; 98 *lenp = len;
94 if (sigp != NULL) { 99 ret = 0;
95 *sigp = xmalloc(len); 100 out:
96 memcpy(*sigp, buffer_ptr(&b), len); 101 explicit_bzero(digest, sizeof(digest));
97 } 102 if (b != NULL)
98 buffer_free(&b); 103 sshbuf_free(b);
99 104 if (bb != NULL)
100 return 0; 105 sshbuf_free(bb);
106 if (sig != NULL)
107 ECDSA_SIG_free(sig);
108 return ret;
101} 109}
110
111/* ARGSUSED */
102int 112int
103ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen, 113ssh_ecdsa_verify(const struct sshkey *key,
104 const u_char *data, u_int datalen) 114 const u_char *signature, size_t signaturelen,
115 const u_char *data, size_t datalen, u_int compat)
105{ 116{
106 ECDSA_SIG *sig; 117 ECDSA_SIG *sig = NULL;
107 int hash_alg; 118 int hash_alg;
108 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; 119 u_char digest[SSH_DIGEST_MAX_LENGTH];
109 u_int len, dlen; 120 size_t dlen;
110 int rlen, ret; 121 int ret = SSH_ERR_INTERNAL_ERROR;
111 Buffer b, bb; 122 struct sshbuf *b = NULL, *sigbuf = NULL;
112 char *ktype; 123 char *ktype = NULL;
113 124
114 if (key == NULL || key_type_plain(key->type) != KEY_ECDSA || 125 if (key == NULL || key->ecdsa == NULL ||
115 key->ecdsa == NULL) { 126 sshkey_type_plain(key->type) != KEY_ECDSA)
116 error("%s: no ECDSA key", __func__); 127 return SSH_ERR_INVALID_ARGUMENT;
117 return -1; 128
118 } 129 if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
130 (dlen = ssh_digest_bytes(hash_alg)) == 0)
131 return SSH_ERR_INTERNAL_ERROR;
119 132
120 /* fetch signature */ 133 /* fetch signature */
121 buffer_init(&b); 134 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
122 buffer_append(&b, signature, signaturelen); 135 return SSH_ERR_ALLOC_FAIL;
123 ktype = buffer_get_string(&b, NULL); 136 if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
124 if (strcmp(key_ssh_name_plain(key), ktype) != 0) { 137 sshbuf_froms(b, &sigbuf) != 0) {
125 error("%s: cannot handle type %s", __func__, ktype); 138 ret = SSH_ERR_INVALID_FORMAT;
126 buffer_free(&b); 139 goto out;
127 free(ktype);
128 return -1;
129 } 140 }
130 free(ktype); 141 if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) {
131 sigblob = buffer_get_string(&b, &len); 142 ret = SSH_ERR_KEY_TYPE_MISMATCH;
132 rlen = buffer_len(&b); 143 goto out;
133 buffer_free(&b); 144 }
134 if (rlen != 0) { 145 if (sshbuf_len(b) != 0) {
135 error("%s: remaining bytes in signature %d", __func__, rlen); 146 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
136 free(sigblob); 147 goto out;
137 return -1;
138 } 148 }
139 149
140 /* parse signature */ 150 /* parse signature */
141 if ((sig = ECDSA_SIG_new()) == NULL) 151 if ((sig = ECDSA_SIG_new()) == NULL) {
142 fatal("%s: ECDSA_SIG_new failed", __func__); 152 ret = SSH_ERR_ALLOC_FAIL;
143 153 goto out;
144 buffer_init(&bb); 154 }
145 buffer_append(&bb, sigblob, len); 155 if (sshbuf_get_bignum2(sigbuf, sig->r) != 0 ||
146 buffer_get_bignum2(&bb, sig->r); 156 sshbuf_get_bignum2(sigbuf, sig->s) != 0) {
147 buffer_get_bignum2(&bb, sig->s); 157 ret = SSH_ERR_INVALID_FORMAT;
148 if (buffer_len(&bb) != 0) 158 goto out;
149 fatal("%s: remaining bytes in inner sigblob", __func__); 159 }
150 buffer_free(&bb); 160 if (sshbuf_len(sigbuf) != 0) {
151 161 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
152 /* clean up */ 162 goto out;
153 explicit_bzero(sigblob, len);
154 free(sigblob);
155
156 /* hash the data */
157 hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid);
158 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
159 error("%s: bad hash algorithm %d", __func__, hash_alg);
160 return -1;
161 } 163 }
162 if (ssh_digest_memory(hash_alg, data, datalen, 164 if ((ret = ssh_digest_memory(hash_alg, data, datalen,
163 digest, sizeof(digest)) != 0) { 165 digest, sizeof(digest))) != 0)
164 error("%s: digest_memory failed", __func__); 166 goto out;
165 return -1; 167
168 switch (ECDSA_do_verify(digest, dlen, sig, key->ecdsa)) {
169 case 1:
170 ret = 0;
171 break;
172 case 0:
173 ret = SSH_ERR_SIGNATURE_INVALID;
174 goto out;
175 default:
176 ret = SSH_ERR_LIBCRYPTO_ERROR;
177 goto out;
166 } 178 }
167 179
168 ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa); 180 out:
169 explicit_bzero(digest, sizeof(digest)); 181 explicit_bzero(digest, sizeof(digest));
170 182 if (sigbuf != NULL)
171 ECDSA_SIG_free(sig); 183 sshbuf_free(sigbuf);
172 184 if (b != NULL)
173 debug("%s: signature %s", __func__, 185 sshbuf_free(b);
174 ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); 186 if (sig != NULL)
187 ECDSA_SIG_free(sig);
188 free(ktype);
175 return ret; 189 return ret;
176} 190}
177 191
diff --git a/ssh-ed25519.c b/ssh-ed25519.c
index 160d1f23b..cb87d4790 100644
--- a/ssh-ed25519.c
+++ b/ssh-ed25519.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-ed25519.c,v 1.3 2014/02/23 20:03:42 djm Exp $ */ 1/* $OpenBSD: ssh-ed25519.c,v 1.4 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2013 Markus Friedl <markus@openbsd.org> 3 * Copyright (c) 2013 Markus Friedl <markus@openbsd.org>
4 * 4 *
@@ -18,132 +18,149 @@
18#include "includes.h" 18#include "includes.h"
19 19
20#include <sys/types.h> 20#include <sys/types.h>
21#include <limits.h>
21 22
22#include "crypto_api.h" 23#include "crypto_api.h"
23 24
24#include <limits.h>
25#include <string.h> 25#include <string.h>
26#include <stdarg.h> 26#include <stdarg.h>
27 27
28#include "xmalloc.h" 28#include "xmalloc.h"
29#include "log.h" 29#include "log.h"
30#include "buffer.h" 30#include "buffer.h"
31#include "key.h" 31#define SSHKEY_INTERNAL
32#include "sshkey.h"
33#include "ssherr.h"
32#include "ssh.h" 34#include "ssh.h"
33 35
34int 36int
35ssh_ed25519_sign(const Key *key, u_char **sigp, u_int *lenp, 37ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
36 const u_char *data, u_int datalen) 38 const u_char *data, size_t datalen, u_int compat)
37{ 39{
38 u_char *sig; 40 u_char *sig = NULL;
39 u_int slen, len; 41 size_t slen = 0, len;
40 unsigned long long smlen; 42 unsigned long long smlen;
41 int ret; 43 int r, ret;
42 Buffer b; 44 struct sshbuf *b = NULL;
43 45
44 if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || 46 if (lenp != NULL)
45 key->ed25519_sk == NULL) { 47 *lenp = 0;
46 error("%s: no ED25519 key", __func__); 48 if (sigp != NULL)
47 return -1; 49 *sigp = NULL;
48 }
49 50
50 if (datalen >= UINT_MAX - crypto_sign_ed25519_BYTES) { 51 if (key == NULL ||
51 error("%s: datalen %u too long", __func__, datalen); 52 sshkey_type_plain(key->type) != KEY_ED25519 ||
52 return -1; 53 key->ed25519_sk == NULL ||
53 } 54 datalen >= INT_MAX - crypto_sign_ed25519_BYTES)
55 return SSH_ERR_INVALID_ARGUMENT;
54 smlen = slen = datalen + crypto_sign_ed25519_BYTES; 56 smlen = slen = datalen + crypto_sign_ed25519_BYTES;
55 sig = xmalloc(slen); 57 if ((sig = malloc(slen)) == NULL)
58 return SSH_ERR_ALLOC_FAIL;
56 59
57 if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, 60 if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen,
58 key->ed25519_sk)) != 0 || smlen <= datalen) { 61 key->ed25519_sk)) != 0 || smlen <= datalen) {
59 error("%s: crypto_sign_ed25519 failed: %d", __func__, ret); 62 r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
60 free(sig); 63 goto out;
61 return -1;
62 } 64 }
63 /* encode signature */ 65 /* encode signature */
64 buffer_init(&b); 66 if ((b = sshbuf_new()) == NULL) {
65 buffer_put_cstring(&b, "ssh-ed25519"); 67 r = SSH_ERR_ALLOC_FAIL;
66 buffer_put_string(&b, sig, smlen - datalen); 68 goto out;
67 len = buffer_len(&b); 69 }
70 if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 ||
71 (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
72 goto out;
73 len = sshbuf_len(b);
74 if (sigp != NULL) {
75 if ((*sigp = malloc(len)) == NULL) {
76 r = SSH_ERR_ALLOC_FAIL;
77 goto out;
78 }
79 memcpy(*sigp, sshbuf_ptr(b), len);
80 }
68 if (lenp != NULL) 81 if (lenp != NULL)
69 *lenp = len; 82 *lenp = len;
70 if (sigp != NULL) { 83 /* success */
71 *sigp = xmalloc(len); 84 r = 0;
72 memcpy(*sigp, buffer_ptr(&b), len); 85 out:
86 sshbuf_free(b);
87 if (sig != NULL) {
88 explicit_bzero(sig, slen);
89 free(sig);
73 } 90 }
74 buffer_free(&b);
75 explicit_bzero(sig, slen);
76 free(sig);
77 91
78 return 0; 92 return r;
79} 93}
80 94
81int 95int
82ssh_ed25519_verify(const Key *key, const u_char *signature, u_int signaturelen, 96ssh_ed25519_verify(const struct sshkey *key,
83 const u_char *data, u_int datalen) 97 const u_char *signature, size_t signaturelen,
98 const u_char *data, size_t datalen, u_int compat)
84{ 99{
85 Buffer b; 100 struct sshbuf *b = NULL;
86 char *ktype; 101 char *ktype = NULL;
87 u_char *sigblob, *sm, *m; 102 const u_char *sigblob;
88 u_int len; 103 u_char *sm = NULL, *m = NULL;
89 unsigned long long smlen, mlen; 104 size_t len;
90 int rlen, ret; 105 unsigned long long smlen = 0, mlen = 0;
106 int r, ret;
91 107
92 if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || 108 if (key == NULL ||
93 key->ed25519_pk == NULL) { 109 sshkey_type_plain(key->type) != KEY_ED25519 ||
94 error("%s: no ED25519 key", __func__); 110 key->ed25519_pk == NULL ||
95 return -1; 111 datalen >= INT_MAX - crypto_sign_ed25519_BYTES)
96 } 112 return SSH_ERR_INVALID_ARGUMENT;
97 buffer_init(&b); 113
98 buffer_append(&b, signature, signaturelen); 114 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
99 ktype = buffer_get_cstring(&b, NULL); 115 return SSH_ERR_ALLOC_FAIL;
116 if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
117 (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
118 goto out;
100 if (strcmp("ssh-ed25519", ktype) != 0) { 119 if (strcmp("ssh-ed25519", ktype) != 0) {
101 error("%s: cannot handle type %s", __func__, ktype); 120 r = SSH_ERR_KEY_TYPE_MISMATCH;
102 buffer_free(&b); 121 goto out;
103 free(ktype);
104 return -1;
105 } 122 }
106 free(ktype); 123 if (sshbuf_len(b) != 0) {
107 sigblob = buffer_get_string(&b, &len); 124 r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
108 rlen = buffer_len(&b); 125 goto out;
109 buffer_free(&b);
110 if (rlen != 0) {
111 error("%s: remaining bytes in signature %d", __func__, rlen);
112 free(sigblob);
113 return -1;
114 } 126 }
115 if (len > crypto_sign_ed25519_BYTES) { 127 if (len > crypto_sign_ed25519_BYTES) {
116 error("%s: len %u > crypto_sign_ed25519_BYTES %u", __func__, 128 r = SSH_ERR_INVALID_FORMAT;
117 len, crypto_sign_ed25519_BYTES); 129 goto out;
118 free(sigblob);
119 return -1;
120 } 130 }
131 if (datalen >= SIZE_MAX - len)
132 return SSH_ERR_INVALID_ARGUMENT;
121 smlen = len + datalen; 133 smlen = len + datalen;
122 sm = xmalloc(smlen); 134 mlen = smlen;
135 if ((sm = malloc(smlen)) == NULL || (m = xmalloc(mlen)) == NULL) {
136 r = SSH_ERR_ALLOC_FAIL;
137 goto out;
138 }
123 memcpy(sm, sigblob, len); 139 memcpy(sm, sigblob, len);
124 memcpy(sm+len, data, datalen); 140 memcpy(sm+len, data, datalen);
125 mlen = smlen;
126 m = xmalloc(mlen);
127 if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, 141 if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen,
128 key->ed25519_pk)) != 0) { 142 key->ed25519_pk)) != 0) {
129 debug2("%s: crypto_sign_ed25519_open failed: %d", 143 debug2("%s: crypto_sign_ed25519_open failed: %d",
130 __func__, ret); 144 __func__, ret);
131 } 145 }
132 if (ret == 0 && mlen != datalen) { 146 if (ret != 0 || mlen != datalen) {
133 debug2("%s: crypto_sign_ed25519_open " 147 r = SSH_ERR_SIGNATURE_INVALID;
134 "mlen != datalen (%llu != %u)", __func__, mlen, datalen); 148 goto out;
135 ret = -1;
136 } 149 }
137 /* XXX compare 'm' and 'data' ? */ 150 /* XXX compare 'm' and 'data' ? */
138 151 /* success */
139 explicit_bzero(sigblob, len); 152 r = 0;
140 explicit_bzero(sm, smlen); 153 out:
141 explicit_bzero(m, smlen); /* NB. mlen may be invalid if ret != 0 */ 154 if (sm != NULL) {
142 free(sigblob); 155 explicit_bzero(sm, smlen);
143 free(sm); 156 free(sm);
144 free(m); 157 }
145 debug("%s: signature %scorrect", __func__, (ret != 0) ? "in" : ""); 158 if (m != NULL) {
146 159 explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */
147 /* translate return code carefully */ 160 free(m);
148 return (ret == 0) ? 1 : -1; 161 }
162 sshbuf_free(b);
163 free(ktype);
164 return r;
149} 165}
166
diff --git a/ssh-keygen.0 b/ssh-keygen.0
index c43678ff0..648f3017f 100644
--- a/ssh-keygen.0
+++ b/ssh-keygen.0
@@ -1,11 +1,11 @@
1SSH-KEYGEN(1) OpenBSD Reference Manual SSH-KEYGEN(1) 1SSH-KEYGEN(1) General Commands Manual SSH-KEYGEN(1)
2 2
3NAME 3NAME
4 ssh-keygen - authentication key generation, management and conversion 4 ssh-keygen - authentication key generation, management and conversion
5 5
6SYNOPSIS 6SYNOPSIS
7 ssh-keygen [-q] [-b bits] [-t type] [-N new_passphrase] [-C comment] 7 ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa | rsa1]
8 [-f output_keyfile] 8 [-N new_passphrase] [-C comment] [-f output_keyfile]
9 ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile] 9 ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]
10 ssh-keygen -i [-m key_format] [-f input_keyfile] 10 ssh-keygen -i [-m key_format] [-f input_keyfile]
11 ssh-keygen -e [-m key_format] [-f input_keyfile] 11 ssh-keygen -e [-m key_format] [-f input_keyfile]
@@ -164,7 +164,9 @@ DESCRIPTION
164 164
165 -i This option will read an unencrypted private (or public) key file 165 -i This option will read an unencrypted private (or public) key file
166 in the format specified by the -m option and print an OpenSSH 166 in the format specified by the -m option and print an OpenSSH
167 compatible private (or public) key to stdout. 167 compatible private (or public) key to stdout. This option allows
168 importing keys from other software, including several commercial
169 SSH implementations. The default import format is ``RFC4716''.
168 170
169 -J num_lines 171 -J num_lines
170 Exit after screening the specified number of lines while 172 Exit after screening the specified number of lines while
@@ -178,9 +180,7 @@ DESCRIPTION
178 Write the last line processed to the file checkpt while 180 Write the last line processed to the file checkpt while
179 performing DH candidate screening using the -T option. This will 181 performing DH candidate screening using the -T option. This will
180 be used to skip lines in the input file that have already been 182 be used to skip lines in the input file that have already been
181 processed if the job is restarted. This option allows importing 183 processed if the job is restarted.
182 keys from other software, including several commercial SSH
183 implementations. The default import format is ``RFC4716''.
184 184
185 -k Generate a KRL file. In this mode, ssh-keygen will generate a 185 -k Generate a KRL file. In this mode, ssh-keygen will generate a
186 KRL file at the location specified via the -f flag that revokes 186 KRL file at the location specified via the -f flag that revokes
@@ -313,7 +313,7 @@ DESCRIPTION
313 Test DH group exchange candidate primes (generated using the -G 313 Test DH group exchange candidate primes (generated using the -G
314 option) for safety. 314 option) for safety.
315 315
316 -t type 316 -t dsa | ecdsa | ed25519 | rsa | rsa1
317 Specifies the type of key to create. The possible values are 317 Specifies the type of key to create. The possible values are
318 ``rsa1'' for protocol version 1 and ``dsa'', ``ecdsa'', 318 ``rsa1'' for protocol version 1 and ``dsa'', ``ecdsa'',
319 ``ed25519'', or ``rsa'' for protocol version 2. 319 ``ed25519'', or ``rsa'' for protocol version 2.
@@ -559,4 +559,4 @@ AUTHORS
559 created OpenSSH. Markus Friedl contributed the support for SSH protocol 559 created OpenSSH. Markus Friedl contributed the support for SSH protocol
560 versions 1.5 and 2.0. 560 versions 1.5 and 2.0.
561 561
562OpenBSD 5.5 February 5, 2014 OpenBSD 5.5 562OpenBSD 5.6 March 31, 2014 OpenBSD 5.6
diff --git a/ssh-keygen.1 b/ssh-keygen.1
index 12e00d416..723a0162e 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: ssh-keygen.1,v 1.120 2014/02/05 20:13:25 naddy Exp $ 1.\" $OpenBSD: ssh-keygen.1,v 1.122 2014/03/31 13:39:34 jmc Exp $
2.\" 2.\"
3.\" Author: Tatu Ylonen <ylo@cs.hut.fi> 3.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
4.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -35,7 +35,7 @@
35.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37.\" 37.\"
38.Dd $Mdocdate: February 5 2014 $ 38.Dd $Mdocdate: March 31 2014 $
39.Dt SSH-KEYGEN 1 39.Dt SSH-KEYGEN 1
40.Os 40.Os
41.Sh NAME 41.Sh NAME
@@ -46,7 +46,7 @@
46.Nm ssh-keygen 46.Nm ssh-keygen
47.Op Fl q 47.Op Fl q
48.Op Fl b Ar bits 48.Op Fl b Ar bits
49.Op Fl t Ar type 49.Op Fl t Cm dsa | ecdsa | ed25519 | rsa | rsa1
50.Op Fl N Ar new_passphrase 50.Op Fl N Ar new_passphrase
51.Op Fl C Ar comment 51.Op Fl C Ar comment
52.Op Fl f Ar output_keyfile 52.Op Fl f Ar output_keyfile
@@ -332,6 +332,10 @@ in the format specified by the
332.Fl m 332.Fl m
333option and print an OpenSSH compatible private 333option and print an OpenSSH compatible private
334(or public) key to stdout. 334(or public) key to stdout.
335This option allows importing keys from other software, including several
336commercial SSH implementations.
337The default import format is
338.Dq RFC4716 .
335.It Fl J Ar num_lines 339.It Fl J Ar num_lines
336Exit after screening the specified number of lines 340Exit after screening the specified number of lines
337while performing DH candidate screening using the 341while performing DH candidate screening using the
@@ -350,10 +354,6 @@ while performing DH candidate screening using the
350option. 354option.
351This will be used to skip lines in the input file that have already been 355This will be used to skip lines in the input file that have already been
352processed if the job is restarted. 356processed if the job is restarted.
353This option allows importing keys from other software, including several
354commercial SSH implementations.
355The default import format is
356.Dq RFC4716 .
357.It Fl k 357.It Fl k
358Generate a KRL file. 358Generate a KRL file.
359In this mode, 359In this mode,
@@ -514,7 +514,7 @@ section for details.
514Test DH group exchange candidate primes (generated using the 514Test DH group exchange candidate primes (generated using the
515.Fl G 515.Fl G
516option) for safety. 516option) for safety.
517.It Fl t Ar type 517.It Fl t Cm dsa | ecdsa | ed25519 | rsa | rsa1
518Specifies the type of key to create. 518Specifies the type of key to create.
519The possible values are 519The possible values are
520.Dq rsa1 520.Dq rsa1
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 2a316bcea..23058ee99 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.241 2014/02/05 20:13:25 naddy Exp $ */ 1/* $OpenBSD: ssh-keygen.c,v 1.249 2014/07/03 03:47:27 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -165,7 +165,7 @@ int rounds = 0;
165/* argv0 */ 165/* argv0 */
166extern char *__progname; 166extern char *__progname;
167 167
168char hostname[MAXHOSTNAMELEN]; 168char hostname[NI_MAXHOST];
169 169
170/* moduli.c */ 170/* moduli.c */
171int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *); 171int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
@@ -195,6 +195,7 @@ type_bits_valid(int type, u_int32_t *bitsp)
195 fprintf(stderr, "key bits exceeds maximum %d\n", maxbits); 195 fprintf(stderr, "key bits exceeds maximum %d\n", maxbits);
196 exit(1); 196 exit(1);
197 } 197 }
198#ifdef WITH_OPENSSL
198 if (type == KEY_DSA && *bitsp != 1024) 199 if (type == KEY_DSA && *bitsp != 1024)
199 fatal("DSA keys must be 1024 bits"); 200 fatal("DSA keys must be 1024 bits");
200 else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 768) 201 else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 768)
@@ -202,6 +203,7 @@ type_bits_valid(int type, u_int32_t *bitsp)
202 else if (type == KEY_ECDSA && key_ecdsa_bits_to_nid(*bitsp) == -1) 203 else if (type == KEY_ECDSA && key_ecdsa_bits_to_nid(*bitsp) == -1)
203 fatal("Invalid ECDSA key length - valid lengths are " 204 fatal("Invalid ECDSA key length - valid lengths are "
204 "256, 384 or 521 bits"); 205 "256, 384 or 521 bits");
206#endif
205} 207}
206 208
207static void 209static void
@@ -278,6 +280,7 @@ load_identity(char *filename)
278#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" 280#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
279#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb 281#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
280 282
283#ifdef WITH_OPENSSL
281static void 284static void
282do_convert_to_ssh2(struct passwd *pw, Key *k) 285do_convert_to_ssh2(struct passwd *pw, Key *k)
283{ 286{
@@ -408,7 +411,7 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
408 Buffer b; 411 Buffer b;
409 Key *key = NULL; 412 Key *key = NULL;
410 char *type, *cipher; 413 char *type, *cipher;
411 u_char *sig, data[] = "abcde12345"; 414 u_char *sig = NULL, data[] = "abcde12345";
412 int magic, rlen, ktype, i1, i2, i3, i4; 415 int magic, rlen, ktype, i1, i2, i3, i4;
413 u_int slen; 416 u_int slen;
414 u_long e; 417 u_long e;
@@ -479,7 +482,9 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
479 buffer_get_bignum_bits(&b, key->rsa->iqmp); 482 buffer_get_bignum_bits(&b, key->rsa->iqmp);
480 buffer_get_bignum_bits(&b, key->rsa->q); 483 buffer_get_bignum_bits(&b, key->rsa->q);
481 buffer_get_bignum_bits(&b, key->rsa->p); 484 buffer_get_bignum_bits(&b, key->rsa->p);
482 rsa_generate_additional_parameters(key->rsa); 485 if (rsa_generate_additional_parameters(key->rsa) != 0)
486 fatal("%s: rsa_generate_additional_parameters "
487 "error", __func__);
483 break; 488 break;
484 } 489 }
485 rlen = buffer_len(&b); 490 rlen = buffer_len(&b);
@@ -711,6 +716,7 @@ do_convert_from(struct passwd *pw)
711 key_free(k); 716 key_free(k);
712 exit(0); 717 exit(0);
713} 718}
719#endif
714 720
715static void 721static void
716do_print_public(struct passwd *pw) 722do_print_public(struct passwd *pw)
@@ -981,7 +987,7 @@ do_gen_all_hostkeys(struct passwd *pw)
981} 987}
982 988
983static void 989static void
984printhost(FILE *f, const char *name, Key *public, int ca, int hash) 990printhost(FILE *f, const char *name, Key *public, int ca, int revoked, int hash)
985{ 991{
986 if (print_fingerprint) { 992 if (print_fingerprint) {
987 enum fp_rep rep; 993 enum fp_rep rep;
@@ -1001,7 +1007,8 @@ printhost(FILE *f, const char *name, Key *public, int ca, int hash)
1001 } else { 1007 } else {
1002 if (hash && (name = host_hash(name, NULL, 0)) == NULL) 1008 if (hash && (name = host_hash(name, NULL, 0)) == NULL)
1003 fatal("hash_host failed"); 1009 fatal("hash_host failed");
1004 fprintf(f, "%s%s%s ", ca ? CA_MARKER : "", ca ? " " : "", name); 1010 fprintf(f, "%s%s%s ", ca ? CA_MARKER " " : "",
1011 revoked ? REVOKE_MARKER " " : "" , name);
1005 if (!key_write(public, f)) 1012 if (!key_write(public, f))
1006 fatal("key_write failed"); 1013 fatal("key_write failed");
1007 fprintf(f, "\n"); 1014 fprintf(f, "\n");
@@ -1016,7 +1023,7 @@ do_known_hosts(struct passwd *pw, const char *name)
1016 char *cp, *cp2, *kp, *kp2; 1023 char *cp, *cp2, *kp, *kp2;
1017 char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; 1024 char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
1018 int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; 1025 int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
1019 int ca; 1026 int ca, revoked;
1020 int found_key = 0; 1027 int found_key = 0;
1021 1028
1022 if (!have_identity) { 1029 if (!have_identity) {
@@ -1030,6 +1037,7 @@ do_known_hosts(struct passwd *pw, const char *name)
1030 if ((in = fopen(identity_file, "r")) == NULL) 1037 if ((in = fopen(identity_file, "r")) == NULL)
1031 fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); 1038 fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
1032 1039
1040 /* XXX this code is a mess; refactor -djm */
1033 /* 1041 /*
1034 * Find hosts goes to stdout, hash and deletions happen in-place 1042 * Find hosts goes to stdout, hash and deletions happen in-place
1035 * A corner case is ssh-keygen -HF foo, which should go to stdout 1043 * A corner case is ssh-keygen -HF foo, which should go to stdout
@@ -1073,7 +1081,7 @@ do_known_hosts(struct passwd *pw, const char *name)
1073 fprintf(out, "%s\n", cp); 1081 fprintf(out, "%s\n", cp);
1074 continue; 1082 continue;
1075 } 1083 }
1076 /* Check whether this is a CA key */ 1084 /* Check whether this is a CA key or revocation marker */
1077 if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 && 1085 if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 &&
1078 (cp[sizeof(CA_MARKER) - 1] == ' ' || 1086 (cp[sizeof(CA_MARKER) - 1] == ' ' ||
1079 cp[sizeof(CA_MARKER) - 1] == '\t')) { 1087 cp[sizeof(CA_MARKER) - 1] == '\t')) {
@@ -1081,6 +1089,14 @@ do_known_hosts(struct passwd *pw, const char *name)
1081 cp += sizeof(CA_MARKER); 1089 cp += sizeof(CA_MARKER);
1082 } else 1090 } else
1083 ca = 0; 1091 ca = 0;
1092 if (strncasecmp(cp, REVOKE_MARKER,
1093 sizeof(REVOKE_MARKER) - 1) == 0 &&
1094 (cp[sizeof(REVOKE_MARKER) - 1] == ' ' ||
1095 cp[sizeof(REVOKE_MARKER) - 1] == '\t')) {
1096 revoked = 1;
1097 cp += sizeof(REVOKE_MARKER);
1098 } else
1099 revoked = 0;
1084 1100
1085 /* Find the end of the host name portion. */ 1101 /* Find the end of the host name portion. */
1086 for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) 1102 for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
@@ -1124,20 +1140,23 @@ do_known_hosts(struct passwd *pw, const char *name)
1124 printf("# Host %s found: " 1140 printf("# Host %s found: "
1125 "line %d type %s%s\n", name, 1141 "line %d type %s%s\n", name,
1126 num, key_type(pub), 1142 num, key_type(pub),
1127 ca ? " (CA key)" : ""); 1143 ca ? " (CA key)" :
1128 printhost(out, cp, pub, ca, 0); 1144 revoked? " (revoked)" : "");
1145 printhost(out, cp, pub, ca, revoked, 0);
1129 found_key = 1; 1146 found_key = 1;
1130 } 1147 }
1131 if (delete_host) { 1148 if (delete_host) {
1132 if (!c && !ca) 1149 if (!c || ca || revoked) {
1133 printhost(out, cp, pub, ca, 0); 1150 printhost(out, cp, pub,
1134 else 1151 ca, revoked, 0);
1152 } else {
1135 printf("# Host %s found: " 1153 printf("# Host %s found: "
1136 "line %d type %s\n", name, 1154 "line %d type %s\n", name,
1137 num, key_type(pub)); 1155 num, key_type(pub));
1156 }
1138 } 1157 }
1139 } else if (hash_hosts) 1158 } else if (hash_hosts)
1140 printhost(out, cp, pub, ca, 0); 1159 printhost(out, cp, pub, ca, revoked, 0);
1141 } else { 1160 } else {
1142 if (find_host || delete_host) { 1161 if (find_host || delete_host) {
1143 c = (match_hostname(name, cp, 1162 c = (match_hostname(name, cp,
@@ -1148,38 +1167,43 @@ do_known_hosts(struct passwd *pw, const char *name)
1148 "line %d type %s%s\n", name, 1167 "line %d type %s%s\n", name,
1149 num, key_type(pub), 1168 num, key_type(pub),
1150 ca ? " (CA key)" : ""); 1169 ca ? " (CA key)" : "");
1151 printhost(out, name, pub, 1170 printhost(out, name, pub, ca, revoked,
1152 ca, hash_hosts && !ca); 1171 hash_hosts && !(ca || revoked));
1153 found_key = 1; 1172 found_key = 1;
1154 } 1173 }
1155 if (delete_host) { 1174 if (delete_host) {
1156 if (!c && !ca) 1175 if (!c || ca || revoked) {
1157 printhost(out, cp, pub, ca, 0); 1176 printhost(out, cp, pub,
1158 else 1177 ca, revoked, 0);
1178 } else {
1159 printf("# Host %s found: " 1179 printf("# Host %s found: "
1160 "line %d type %s\n", name, 1180 "line %d type %s\n", name,
1161 num, key_type(pub)); 1181 num, key_type(pub));
1182 }
1162 } 1183 }
1184 } else if (hash_hosts && (ca || revoked)) {
1185 /* Don't hash CA and revoked keys' hostnames */
1186 printhost(out, cp, pub, ca, revoked, 0);
1187 has_unhashed = 1;
1163 } else if (hash_hosts) { 1188 } else if (hash_hosts) {
1189 /* Hash each hostname separately */
1164 for (cp2 = strsep(&cp, ","); 1190 for (cp2 = strsep(&cp, ",");
1165 cp2 != NULL && *cp2 != '\0'; 1191 cp2 != NULL && *cp2 != '\0';
1166 cp2 = strsep(&cp, ",")) { 1192 cp2 = strsep(&cp, ",")) {
1167 if (ca) { 1193 if (strcspn(cp2, "*?!") !=
1168 fprintf(stderr, "Warning: "
1169 "ignoring CA key for host: "
1170 "%.64s\n", cp2);
1171 printhost(out, cp2, pub, ca, 0);
1172 } else if (strcspn(cp2, "*?!") !=
1173 strlen(cp2)) { 1194 strlen(cp2)) {
1174 fprintf(stderr, "Warning: " 1195 fprintf(stderr, "Warning: "
1175 "ignoring host name with " 1196 "ignoring host name with "
1176 "metacharacters: %.64s\n", 1197 "metacharacters: %.64s\n",
1177 cp2); 1198 cp2);
1178 printhost(out, cp2, pub, ca, 0); 1199 printhost(out, cp2, pub, ca,
1179 } else 1200 revoked, 0);
1180 printhost(out, cp2, pub, ca, 1); 1201 has_unhashed = 1;
1202 } else {
1203 printhost(out, cp2, pub, ca,
1204 revoked, 1);
1205 }
1181 } 1206 }
1182 has_unhashed = 1;
1183 } 1207 }
1184 } 1208 }
1185 key_free(pub); 1209 key_free(pub);
@@ -1589,7 +1613,9 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
1589 } 1613 }
1590 } 1614 }
1591 1615
1616#ifdef ENABLE_PKCS11
1592 pkcs11_init(1); 1617 pkcs11_init(1);
1618#endif
1593 tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); 1619 tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
1594 if (pkcs11provider != NULL) { 1620 if (pkcs11provider != NULL) {
1595 if ((ca = load_pkcs11_key(tmp)) == NULL) 1621 if ((ca = load_pkcs11_key(tmp)) == NULL)
@@ -1631,12 +1657,12 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
1631 public->cert->valid_after = cert_valid_from; 1657 public->cert->valid_after = cert_valid_from;
1632 public->cert->valid_before = cert_valid_to; 1658 public->cert->valid_before = cert_valid_to;
1633 if (v00) { 1659 if (v00) {
1634 prepare_options_buf(&public->cert->critical, 1660 prepare_options_buf(public->cert->critical,
1635 OPTIONS_CRITICAL|OPTIONS_EXTENSIONS); 1661 OPTIONS_CRITICAL|OPTIONS_EXTENSIONS);
1636 } else { 1662 } else {
1637 prepare_options_buf(&public->cert->critical, 1663 prepare_options_buf(public->cert->critical,
1638 OPTIONS_CRITICAL); 1664 OPTIONS_CRITICAL);
1639 prepare_options_buf(&public->cert->extensions, 1665 prepare_options_buf(public->cert->extensions,
1640 OPTIONS_EXTENSIONS); 1666 OPTIONS_EXTENSIONS);
1641 } 1667 }
1642 public->cert->signature_key = key_from_private(ca); 1668 public->cert->signature_key = key_from_private(ca);
@@ -1672,7 +1698,9 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
1672 key_free(public); 1698 key_free(public);
1673 free(out); 1699 free(out);
1674 } 1700 }
1701#ifdef ENABLE_PKCS11
1675 pkcs11_terminate(); 1702 pkcs11_terminate();
1703#endif
1676 exit(0); 1704 exit(0);
1677} 1705}
1678 1706
@@ -1820,8 +1848,8 @@ add_cert_option(char *opt)
1820static void 1848static void
1821show_options(const Buffer *optbuf, int v00, int in_critical) 1849show_options(const Buffer *optbuf, int v00, int in_critical)
1822{ 1850{
1823 char *name; 1851 char *name, *arg;
1824 u_char *data; 1852 const u_char *data;
1825 u_int dlen; 1853 u_int dlen;
1826 Buffer options, option; 1854 Buffer options, option;
1827 1855
@@ -1844,9 +1872,9 @@ show_options(const Buffer *optbuf, int v00, int in_critical)
1844 else if ((v00 || in_critical) && 1872 else if ((v00 || in_critical) &&
1845 (strcmp(name, "force-command") == 0 || 1873 (strcmp(name, "force-command") == 0 ||
1846 strcmp(name, "source-address") == 0)) { 1874 strcmp(name, "source-address") == 0)) {
1847 data = buffer_get_string(&option, NULL); 1875 arg = buffer_get_cstring(&option, NULL);
1848 printf(" %s\n", data); 1876 printf(" %s\n", arg);
1849 free(data); 1877 free(arg);
1850 } else { 1878 } else {
1851 printf(" UNKNOWN OPTION (len %u)\n", 1879 printf(" UNKNOWN OPTION (len %u)\n",
1852 buffer_len(&option)); 1880 buffer_len(&option));
@@ -1905,24 +1933,25 @@ do_show_cert(struct passwd *pw)
1905 printf("\n"); 1933 printf("\n");
1906 } 1934 }
1907 printf(" Critical Options: "); 1935 printf(" Critical Options: ");
1908 if (buffer_len(&key->cert->critical) == 0) 1936 if (buffer_len(key->cert->critical) == 0)
1909 printf("(none)\n"); 1937 printf("(none)\n");
1910 else { 1938 else {
1911 printf("\n"); 1939 printf("\n");
1912 show_options(&key->cert->critical, v00, 1); 1940 show_options(key->cert->critical, v00, 1);
1913 } 1941 }
1914 if (!v00) { 1942 if (!v00) {
1915 printf(" Extensions: "); 1943 printf(" Extensions: ");
1916 if (buffer_len(&key->cert->extensions) == 0) 1944 if (buffer_len(key->cert->extensions) == 0)
1917 printf("(none)\n"); 1945 printf("(none)\n");
1918 else { 1946 else {
1919 printf("\n"); 1947 printf("\n");
1920 show_options(&key->cert->extensions, v00, 0); 1948 show_options(key->cert->extensions, v00, 0);
1921 } 1949 }
1922 } 1950 }
1923 exit(0); 1951 exit(0);
1924} 1952}
1925 1953
1954#ifdef WITH_OPENSSL
1926static void 1955static void
1927load_krl(const char *path, struct ssh_krl **krlp) 1956load_krl(const char *path, struct ssh_krl **krlp)
1928{ 1957{
@@ -2145,60 +2174,40 @@ do_check_krl(struct passwd *pw, int argc, char **argv)
2145 ssh_krl_free(krl); 2174 ssh_krl_free(krl);
2146 exit(ret); 2175 exit(ret);
2147} 2176}
2177#endif
2148 2178
2149static void 2179static void
2150usage(void) 2180usage(void)
2151{ 2181{
2152 fprintf(stderr, "usage: %s [options]\n", __progname); 2182 fprintf(stderr,
2153 fprintf(stderr, "Options:\n"); 2183 "usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa | rsa1]\n"
2154 fprintf(stderr, " -A Generate non-existent host keys for all key types.\n"); 2184 " [-N new_passphrase] [-C comment] [-f output_keyfile]\n"
2155 fprintf(stderr, " -a number Number of KDF rounds for new key format or moduli primality tests.\n"); 2185 " ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]\n"
2156 fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); 2186 " ssh-keygen -i [-m key_format] [-f input_keyfile]\n"
2157 fprintf(stderr, " -b bits Number of bits in the key to create.\n"); 2187 " ssh-keygen -e [-m key_format] [-f input_keyfile]\n"
2158 fprintf(stderr, " -C comment Provide new comment.\n"); 2188 " ssh-keygen -y [-f input_keyfile]\n"
2159 fprintf(stderr, " -c Change comment in private and public key files.\n"); 2189 " ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]\n"
2190 " ssh-keygen -l [-f input_keyfile]\n"
2191 " ssh-keygen -B [-f input_keyfile]\n");
2160#ifdef ENABLE_PKCS11 2192#ifdef ENABLE_PKCS11
2161 fprintf(stderr, " -D pkcs11 Download public key from pkcs11 token.\n"); 2193 fprintf(stderr,
2194 " ssh-keygen -D pkcs11\n");
2162#endif 2195#endif
2163 fprintf(stderr, " -e Export OpenSSH to foreign format key file.\n"); 2196 fprintf(stderr,
2164 fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); 2197 " ssh-keygen -F hostname [-f known_hosts_file] [-l]\n"
2165 fprintf(stderr, " -f filename Filename of the key file.\n"); 2198 " ssh-keygen -H [-f known_hosts_file]\n"
2166 fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); 2199 " ssh-keygen -R hostname [-f known_hosts_file]\n"
2167 fprintf(stderr, " -g Use generic DNS resource record format.\n"); 2200 " ssh-keygen -r hostname [-f input_keyfile] [-g]\n"
2168 fprintf(stderr, " -H Hash names in known_hosts file.\n"); 2201 " ssh-keygen -G output_file [-v] [-b bits] [-M memory] [-S start_point]\n"
2169 fprintf(stderr, " -h Generate host certificate instead of a user certificate.\n"); 2202 " ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n"
2170 fprintf(stderr, " -I key_id Key identifier to include in certificate.\n"); 2203 " [-j start_line] [-K checkpt] [-W generator]\n"
2171 fprintf(stderr, " -i Import foreign format to OpenSSH key file.\n"); 2204 " ssh-keygen -s ca_key -I certificate_identity [-h] [-n principals]\n"
2172 fprintf(stderr, " -J number Screen this number of moduli lines.\n"); 2205 " [-O option] [-V validity_interval] [-z serial_number] file ...\n"
2173 fprintf(stderr, " -j number Start screening moduli at specified line.\n"); 2206 " ssh-keygen -L [-f input_keyfile]\n"
2174 fprintf(stderr, " -K checkpt Write checkpoints to this file.\n"); 2207 " ssh-keygen -A\n"
2175 fprintf(stderr, " -k Generate a KRL file.\n"); 2208 " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n"
2176 fprintf(stderr, " -L Print the contents of a certificate.\n"); 2209 " file ...\n"
2177 fprintf(stderr, " -l Show fingerprint of key file.\n"); 2210 " ssh-keygen -Q -f krl_file file ...\n");
2178 fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n");
2179 fprintf(stderr, " -m key_fmt Conversion format for -e/-i (PEM|PKCS8|RFC4716).\n");
2180 fprintf(stderr, " -N phrase Provide new passphrase.\n");
2181 fprintf(stderr, " -n name,... User/host principal names to include in certificate\n");
2182 fprintf(stderr, " -O option Specify a certificate option.\n");
2183 fprintf(stderr, " -o Enforce new private key format.\n");
2184 fprintf(stderr, " -P phrase Provide old passphrase.\n");
2185 fprintf(stderr, " -p Change passphrase of private key file.\n");
2186 fprintf(stderr, " -Q Test whether key(s) are revoked in KRL.\n");
2187 fprintf(stderr, " -q Quiet.\n");
2188 fprintf(stderr, " -R hostname Remove host from known_hosts file.\n");
2189 fprintf(stderr, " -r hostname Print DNS resource record.\n");
2190 fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n");
2191 fprintf(stderr, " -s ca_key Certify keys with CA key.\n");
2192 fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n");
2193 fprintf(stderr, " -t type Specify type of key to create.\n");
2194 fprintf(stderr, " -u Update KRL rather than creating a new one.\n");
2195 fprintf(stderr, " -V from:to Specify certificate validity interval.\n");
2196 fprintf(stderr, " -v Verbose.\n");
2197 fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n");
2198 fprintf(stderr, " -y Read private key file and print public key.\n");
2199 fprintf(stderr, " -Z cipher Specify a cipher for new private key format.\n");
2200 fprintf(stderr, " -z serial Specify a serial number.\n");
2201
2202 exit(1); 2211 exit(1);
2203} 2212}
2204 2213
@@ -2469,6 +2478,7 @@ main(int argc, char **argv)
2469 printf("Cannot use -l with -H or -R.\n"); 2478 printf("Cannot use -l with -H or -R.\n");
2470 usage(); 2479 usage();
2471 } 2480 }
2481#ifdef WITH_OPENSSL
2472 if (gen_krl) { 2482 if (gen_krl) {
2473 do_gen_krl(pw, update_krl, argc, argv); 2483 do_gen_krl(pw, update_krl, argc, argv);
2474 return (0); 2484 return (0);
@@ -2477,6 +2487,7 @@ main(int argc, char **argv)
2477 do_check_krl(pw, argc, argv); 2487 do_check_krl(pw, argc, argv);
2478 return (0); 2488 return (0);
2479 } 2489 }
2490#endif
2480 if (ca_key_path != NULL) { 2491 if (ca_key_path != NULL) {
2481 if (cert_key_id == NULL) 2492 if (cert_key_id == NULL)
2482 fatal("Must specify key id (-I) when certifying"); 2493 fatal("Must specify key id (-I) when certifying");
@@ -2494,10 +2505,12 @@ main(int argc, char **argv)
2494 do_change_passphrase(pw); 2505 do_change_passphrase(pw);
2495 if (change_comment) 2506 if (change_comment)
2496 do_change_comment(pw); 2507 do_change_comment(pw);
2508#ifdef WITH_OPENSSL
2497 if (convert_to) 2509 if (convert_to)
2498 do_convert_to(pw); 2510 do_convert_to(pw);
2499 if (convert_from) 2511 if (convert_from)
2500 do_convert_from(pw); 2512 do_convert_from(pw);
2513#endif
2501 if (print_public) 2514 if (print_public)
2502 do_print_public(pw); 2515 do_print_public(pw);
2503 if (rr_hostname != NULL) { 2516 if (rr_hostname != NULL) {
@@ -2519,7 +2532,8 @@ main(int argc, char **argv)
2519 _PATH_HOST_DSA_KEY_FILE, rr_hostname); 2532 _PATH_HOST_DSA_KEY_FILE, rr_hostname);
2520 n += do_print_resource_record(pw, 2533 n += do_print_resource_record(pw,
2521 _PATH_HOST_ECDSA_KEY_FILE, rr_hostname); 2534 _PATH_HOST_ECDSA_KEY_FILE, rr_hostname);
2522 2535 n += do_print_resource_record(pw,
2536 _PATH_HOST_ED25519_KEY_FILE, rr_hostname);
2523 if (n == 0) 2537 if (n == 0)
2524 fatal("no keys found."); 2538 fatal("no keys found.");
2525 exit(0); 2539 exit(0);
diff --git a/ssh-keyscan.0 b/ssh-keyscan.0
index 638c19b48..853bd5152 100644
--- a/ssh-keyscan.0
+++ b/ssh-keyscan.0
@@ -1,4 +1,4 @@
1SSH-KEYSCAN(1) OpenBSD Reference Manual SSH-KEYSCAN(1) 1SSH-KEYSCAN(1) General Commands Manual SSH-KEYSCAN(1)
2 2
3NAME 3NAME
4 ssh-keyscan - gather ssh public keys 4 ssh-keyscan - gather ssh public keys
@@ -51,7 +51,8 @@ DESCRIPTION
51 The possible values are ``rsa1'' for protocol version 1 and 51 The possible values are ``rsa1'' for protocol version 1 and
52 ``dsa'', ``ecdsa'', ``ed25519'', or ``rsa'' for protocol version 52 ``dsa'', ``ecdsa'', ``ed25519'', or ``rsa'' for protocol version
53 2. Multiple values may be specified by separating them with 53 2. Multiple values may be specified by separating them with
54 commas. The default is to fetch ``rsa'' and ``ecdsa'' keys. 54 commas. The default is to fetch ``rsa'', ``ecdsa'', and
55 ``ed25519'' keys.
55 56
56 -v Verbose mode. Causes ssh-keyscan to print debugging messages 57 -v Verbose mode. Causes ssh-keyscan to print debugging messages
57 about its progress. 58 about its progress.
@@ -69,11 +70,11 @@ FILES
69 70
70 1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4 71 1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4
71 72
72 Output format for rsa1 keys: 73 Output format for RSA1 keys:
73 74
74 host-or-namelist bits exponent modulus 75 host-or-namelist bits exponent modulus
75 76
76 Output format for rsa, dsa and ecdsa keys: 77 Output format for RSA, DSA, ECDSA, and ED25519 keys:
77 78
78 host-or-namelist keytype base64-encoded-key 79 host-or-namelist keytype base64-encoded-key
79 80
@@ -90,7 +91,7 @@ EXAMPLES
90 Find all hosts from the file ssh_hosts which have new or different keys 91 Find all hosts from the file ssh_hosts which have new or different keys
91 from those in the sorted file ssh_known_hosts: 92 from those in the sorted file ssh_known_hosts:
92 93
93 $ ssh-keyscan -t rsa,dsa,ecdsa -f ssh_hosts | \ 94 $ ssh-keyscan -t rsa,dsa,ecdsa,ed25519 -f ssh_hosts | \
94 sort -u - ssh_known_hosts | diff ssh_known_hosts - 95 sort -u - ssh_known_hosts | diff ssh_known_hosts -
95 96
96SEE ALSO 97SEE ALSO
@@ -107,4 +108,4 @@ BUGS
107 This is because it opens a connection to the ssh port, reads the public 108 This is because it opens a connection to the ssh port, reads the public
108 key, and drops the connection as soon as it gets the key. 109 key, and drops the connection as soon as it gets the key.
109 110
110OpenBSD 5.5 January 28, 2014 OpenBSD 5.5 111OpenBSD 5.6 March 12, 2014 OpenBSD 5.6
diff --git a/ssh-keyscan.1 b/ssh-keyscan.1
index dae4fd9fb..5c32ea9c7 100644
--- a/ssh-keyscan.1
+++ b/ssh-keyscan.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: ssh-keyscan.1,v 1.34 2014/01/28 14:13:39 jmc Exp $ 1.\" $OpenBSD: ssh-keyscan.1,v 1.35 2014/03/12 13:06:59 naddy Exp $
2.\" 2.\"
3.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. 3.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
4.\" 4.\"
@@ -6,7 +6,7 @@
6.\" permitted provided that due credit is given to the author and the 6.\" permitted provided that due credit is given to the author and the
7.\" OpenBSD project by leaving this copyright notice intact. 7.\" OpenBSD project by leaving this copyright notice intact.
8.\" 8.\"
9.Dd $Mdocdate: January 28 2014 $ 9.Dd $Mdocdate: March 12 2014 $
10.Dt SSH-KEYSCAN 1 10.Dt SSH-KEYSCAN 1
11.Os 11.Os
12.Sh NAME 12.Sh NAME
@@ -98,9 +98,10 @@ or
98for protocol version 2. 98for protocol version 2.
99Multiple values may be specified by separating them with commas. 99Multiple values may be specified by separating them with commas.
100The default is to fetch 100The default is to fetch
101.Dq rsa 101.Dq rsa ,
102.Dq ecdsa ,
102and 103and
103.Dq ecdsa 104.Dq ed25519
104keys. 105keys.
105.It Fl v 106.It Fl v
106Verbose mode. 107Verbose mode.
@@ -124,12 +125,12 @@ Input format:
1241.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4 1251.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4
125.Ed 126.Ed
126.Pp 127.Pp
127Output format for rsa1 keys: 128Output format for RSA1 keys:
128.Bd -literal 129.Bd -literal
129host-or-namelist bits exponent modulus 130host-or-namelist bits exponent modulus
130.Ed 131.Ed
131.Pp 132.Pp
132Output format for rsa, dsa and ecdsa keys: 133Output format for RSA, DSA, ECDSA, and ED25519 keys:
133.Bd -literal 134.Bd -literal
134host-or-namelist keytype base64-encoded-key 135host-or-namelist keytype base64-encoded-key
135.Ed 136.Ed
@@ -158,7 +159,7 @@ Find all hosts from the file
158which have new or different keys from those in the sorted file 159which have new or different keys from those in the sorted file
159.Pa ssh_known_hosts : 160.Pa ssh_known_hosts :
160.Bd -literal 161.Bd -literal
161$ ssh-keyscan -t rsa,dsa,ecdsa -f ssh_hosts | \e 162$ ssh-keyscan -t rsa,dsa,ecdsa,ed25519 -f ssh_hosts | \e
162 sort -u - ssh_known_hosts | diff ssh_known_hosts - 163 sort -u - ssh_known_hosts | diff ssh_known_hosts -
163.Ed 164.Ed
164.Sh SEE ALSO 165.Sh SEE ALSO
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
index 8d0a6b8d8..3fabfba14 100644
--- a/ssh-keyscan.c
+++ b/ssh-keyscan.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keyscan.c,v 1.89 2013/12/06 13:39:49 markus Exp $ */ 1/* $OpenBSD: ssh-keyscan.c,v 1.92 2014/04/29 18:01:49 markus Exp $ */
2/* 2/*
3 * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. 3 * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
4 * 4 *
@@ -58,7 +58,7 @@ int ssh_port = SSH_DEFAULT_PORT;
58#define KT_ECDSA 8 58#define KT_ECDSA 8
59#define KT_ED25519 16 59#define KT_ED25519 16
60 60
61int get_keytypes = KT_RSA|KT_ECDSA;/* Get RSA and ECDSA keys by default */ 61int get_keytypes = KT_RSA|KT_ECDSA|KT_ED25519;
62 62
63int hash_hosts = 0; /* Hash hostname on output */ 63int hash_hosts = 0; /* Hash hostname on output */
64 64
@@ -182,6 +182,7 @@ strnnsep(char **stringp, char *delim)
182 return (tok); 182 return (tok);
183} 183}
184 184
185#ifdef WITH_SSH1
185static Key * 186static Key *
186keygrab_ssh1(con *c) 187keygrab_ssh1(con *c)
187{ 188{
@@ -215,6 +216,7 @@ keygrab_ssh1(con *c)
215 216
216 return (rsa); 217 return (rsa);
217} 218}
219#endif
218 220
219static int 221static int
220hostjump(Key *hostkey) 222hostjump(Key *hostkey)
@@ -242,6 +244,7 @@ ssh2_capable(int remote_major, int remote_minor)
242static Key * 244static Key *
243keygrab_ssh2(con *c) 245keygrab_ssh2(con *c)
244{ 246{
247 char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
245 int j; 248 int j;
246 249
247 packet_set_connection(c->c_fd, c->c_fd); 250 packet_set_connection(c->c_fd, c->c_fd);
@@ -252,11 +255,13 @@ keygrab_ssh2(con *c)
252 (c->c_keytype == KT_ED25519 ? "ssh-ed25519" : 255 (c->c_keytype == KT_ED25519 ? "ssh-ed25519" :
253 "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521")); 256 "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521"));
254 c->c_kex = kex_setup(myproposal); 257 c->c_kex = kex_setup(myproposal);
258#ifdef WITH_OPENSSL
255 c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; 259 c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
256 c->c_kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; 260 c->c_kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
257 c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 261 c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
258 c->c_kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 262 c->c_kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
259 c->c_kex->kex[KEX_ECDH_SHA2] = kexecdh_client; 263 c->c_kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
264#endif
260 c->c_kex->kex[KEX_C25519_SHA256] = kexc25519_client; 265 c->c_kex->kex[KEX_C25519_SHA256] = kexc25519_client;
261 c->c_kex->verify_host_key = hostjump; 266 c->c_kex->verify_host_key = hostjump;
262 267
@@ -506,10 +511,12 @@ conread(int s)
506 c->c_data = xmalloc(c->c_len); 511 c->c_data = xmalloc(c->c_len);
507 c->c_status = CS_KEYS; 512 c->c_status = CS_KEYS;
508 break; 513 break;
514#ifdef WITH_SSH1
509 case CS_KEYS: 515 case CS_KEYS:
510 keyprint(c, keygrab_ssh1(c)); 516 keyprint(c, keygrab_ssh1(c));
511 confree(s); 517 confree(s);
512 return; 518 return;
519#endif
513 default: 520 default:
514 fatal("conread: invalid status %d", c->c_status); 521 fatal("conread: invalid status %d", c->c_status);
515 break; 522 break;
diff --git a/ssh-keysign.0 b/ssh-keysign.0
index 5f18b54e3..c34125b72 100644
--- a/ssh-keysign.0
+++ b/ssh-keysign.0
@@ -1,4 +1,4 @@
1SSH-KEYSIGN(8) OpenBSD System Manager's Manual SSH-KEYSIGN(8) 1SSH-KEYSIGN(8) System Manager's Manual SSH-KEYSIGN(8)
2 2
3NAME 3NAME
4 ssh-keysign - ssh helper program for host-based authentication 4 ssh-keysign - ssh helper program for host-based authentication
@@ -50,4 +50,4 @@ HISTORY
50AUTHORS 50AUTHORS
51 Markus Friedl <markus@openbsd.org> 51 Markus Friedl <markus@openbsd.org>
52 52
53OpenBSD 5.5 December 7, 2013 OpenBSD 5.5 53OpenBSD 5.6 December 7, 2013 OpenBSD 5.6
diff --git a/ssh-keysign.c b/ssh-keysign.c
index 6bde8ad17..d95bb7d9d 100644
--- a/ssh-keysign.c
+++ b/ssh-keysign.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keysign.c,v 1.39 2013/12/06 13:39:49 markus Exp $ */ 1/* $OpenBSD: ssh-keysign.c,v 1.42 2014/04/29 18:01:49 markus Exp $ */
2/* 2/*
3 * Copyright (c) 2002 Markus Friedl. All rights reserved. 3 * Copyright (c) 2002 Markus Friedl. All rights reserved.
4 * 4 *
@@ -155,7 +155,7 @@ main(int argc, char **argv)
155 struct passwd *pw; 155 struct passwd *pw;
156 int key_fd[NUM_KEYTYPES], i, found, version = 2, fd; 156 int key_fd[NUM_KEYTYPES], i, found, version = 2, fd;
157 u_char *signature, *data; 157 u_char *signature, *data;
158 char *host; 158 char *host, *fp;
159 u_int slen, dlen; 159 u_int slen, dlen;
160 u_int32_t rnd[256]; 160 u_int32_t rnd[256];
161 161
@@ -201,8 +201,7 @@ main(int argc, char **argv)
201 fatal("could not open any host key"); 201 fatal("could not open any host key");
202 202
203 OpenSSL_add_all_algorithms(); 203 OpenSSL_add_all_algorithms();
204 for (i = 0; i < 256; i++) 204 arc4random_buf(rnd, sizeof(rnd));
205 rnd[i] = arc4random();
206 RAND_seed(rnd, sizeof(rnd)); 205 RAND_seed(rnd, sizeof(rnd));
207 206
208 found = 0; 207 found = 0;
@@ -210,8 +209,11 @@ main(int argc, char **argv)
210 keys[i] = NULL; 209 keys[i] = NULL;
211 if (key_fd[i] == -1) 210 if (key_fd[i] == -1)
212 continue; 211 continue;
212#ifdef WITH_OPENSSL
213/* XXX wrong api */
213 keys[i] = key_load_private_pem(key_fd[i], KEY_UNSPEC, 214 keys[i] = key_load_private_pem(key_fd[i], KEY_UNSPEC,
214 NULL, NULL); 215 NULL, NULL);
216#endif
215 close(key_fd[i]); 217 close(key_fd[i]);
216 if (keys[i] != NULL) 218 if (keys[i] != NULL)
217 found = 1; 219 found = 1;
@@ -243,8 +245,11 @@ main(int argc, char **argv)
243 break; 245 break;
244 } 246 }
245 } 247 }
246 if (!found) 248 if (!found) {
247 fatal("no matching hostkey found"); 249 fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
250 fatal("no matching hostkey found for key %s %s",
251 key_type(key), fp);
252 }
248 253
249 if (key_sign(keys[i], &signature, &slen, data, dlen) != 0) 254 if (key_sign(keys[i], &signature, &slen, data, dlen) != 0)
250 fatal("key_sign failed"); 255 fatal("key_sign failed");
diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c
index 6c9f9d2c1..8c74864aa 100644
--- a/ssh-pkcs11-client.c
+++ b/ssh-pkcs11-client.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-pkcs11-client.c,v 1.4 2013/05/17 00:13:14 djm Exp $ */ 1/* $OpenBSD: ssh-pkcs11-client.c,v 1.5 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2010 Markus Friedl. All rights reserved. 3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
4 * 4 *
@@ -30,6 +30,8 @@
30#include <unistd.h> 30#include <unistd.h>
31#include <errno.h> 31#include <errno.h>
32 32
33#include <openssl/rsa.h>
34
33#include "pathnames.h" 35#include "pathnames.h"
34#include "xmalloc.h" 36#include "xmalloc.h"
35#include "buffer.h" 37#include "buffer.h"
diff --git a/ssh-pkcs11-helper.0 b/ssh-pkcs11-helper.0
index 20d62f7a9..279ec5486 100644
--- a/ssh-pkcs11-helper.0
+++ b/ssh-pkcs11-helper.0
@@ -1,4 +1,4 @@
1SSH-PKCS11-HELPER(8) OpenBSD System Manager's Manual SSH-PKCS11-HELPER(8) 1SSH-PKCS11-HELPER(8) System Manager's Manual SSH-PKCS11-HELPER(8)
2 2
3NAME 3NAME
4 ssh-pkcs11-helper - ssh-agent helper program for PKCS#11 support 4 ssh-pkcs11-helper - ssh-agent helper program for PKCS#11 support
@@ -22,4 +22,4 @@ HISTORY
22AUTHORS 22AUTHORS
23 Markus Friedl <markus@openbsd.org> 23 Markus Friedl <markus@openbsd.org>
24 24
25OpenBSD 5.5 July 16, 2013 OpenBSD 5.5 25OpenBSD 5.6 July 16, 2013 OpenBSD 5.6
diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c
index b7c52beb8..0b1d8e4cc 100644
--- a/ssh-pkcs11-helper.c
+++ b/ssh-pkcs11-helper.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-pkcs11-helper.c,v 1.7 2013/12/02 02:56:17 djm Exp $ */ 1/* $OpenBSD: ssh-pkcs11-helper.c,v 1.8 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2010 Markus Friedl. All rights reserved. 3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
4 * 4 *
@@ -169,7 +169,7 @@ process_sign(void)
169{ 169{
170 u_char *blob, *data, *signature = NULL; 170 u_char *blob, *data, *signature = NULL;
171 u_int blen, dlen, slen = 0; 171 u_int blen, dlen, slen = 0;
172 int ok = -1, ret; 172 int ok = -1;
173 Key *key, *found; 173 Key *key, *found;
174 Buffer msg; 174 Buffer msg;
175 175
@@ -179,6 +179,9 @@ process_sign(void)
179 179
180 if ((key = key_from_blob(blob, blen)) != NULL) { 180 if ((key = key_from_blob(blob, blen)) != NULL) {
181 if ((found = lookup_key(key)) != NULL) { 181 if ((found = lookup_key(key)) != NULL) {
182#ifdef WITH_OPENSSL
183 int ret;
184
182 slen = RSA_size(key->rsa); 185 slen = RSA_size(key->rsa);
183 signature = xmalloc(slen); 186 signature = xmalloc(slen);
184 if ((ret = RSA_private_encrypt(dlen, data, signature, 187 if ((ret = RSA_private_encrypt(dlen, data, signature,
@@ -186,6 +189,7 @@ process_sign(void)
186 slen = ret; 189 slen = ret;
187 ok = 0; 190 ok = 0;
188 } 191 }
192#endif /* WITH_OPENSSL */
189 } 193 }
190 key_free(key); 194 key_free(key);
191 } 195 }
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
index c49cbf42b..c96be3bd2 100644
--- a/ssh-pkcs11.c
+++ b/ssh-pkcs11.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-pkcs11.c,v 1.11 2013/11/13 13:48:20 markus Exp $ */ 1/* $OpenBSD: ssh-pkcs11.c,v 1.14 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2010 Markus Friedl. All rights reserved. 3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
4 * 4 *
@@ -520,7 +520,7 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
520 key = key_new(KEY_UNSPEC); 520 key = key_new(KEY_UNSPEC);
521 key->rsa = rsa; 521 key->rsa = rsa;
522 key->type = KEY_RSA; 522 key->type = KEY_RSA;
523 key->flags |= KEY_FLAG_EXT; 523 key->flags |= SSHKEY_FLAG_EXT;
524 if (pkcs11_key_included(keysp, nkeys, key)) { 524 if (pkcs11_key_included(keysp, nkeys, key)) {
525 key_free(key); 525 key_free(key);
526 } else { 526 } else {
diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h
index 59f456adf..4d2efda13 100644
--- a/ssh-pkcs11.h
+++ b/ssh-pkcs11.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-pkcs11.h,v 1.2 2010/02/24 06:12:53 djm Exp $ */ 1/* $OpenBSD: ssh-pkcs11.h,v 1.3 2014/04/29 18:01:49 markus Exp $ */
2/* 2/*
3 * Copyright (c) 2010 Markus Friedl. All rights reserved. 3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
4 * 4 *
@@ -18,3 +18,7 @@ int pkcs11_init(int);
18void pkcs11_terminate(void); 18void pkcs11_terminate(void);
19int pkcs11_add_provider(char *, char *, Key ***); 19int pkcs11_add_provider(char *, char *, Key ***);
20int pkcs11_del_provider(char *); 20int pkcs11_del_provider(char *);
21
22#if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11)
23#undef ENABLE_PKCS11
24#endif
diff --git a/ssh-rsa.c b/ssh-rsa.c
index c6f25b3ee..fec1953b4 100644
--- a/ssh-rsa.c
+++ b/ssh-rsa.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-rsa.c,v 1.51 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: ssh-rsa.c,v 1.52 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> 3 * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
4 * 4 *
@@ -25,163 +25,167 @@
25#include <stdarg.h> 25#include <stdarg.h>
26#include <string.h> 26#include <string.h>
27 27
28#include "xmalloc.h" 28#include "sshbuf.h"
29#include "log.h"
30#include "buffer.h"
31#include "key.h"
32#include "compat.h" 29#include "compat.h"
33#include "misc.h" 30#include "ssherr.h"
34#include "ssh.h" 31#define SSHKEY_INTERNAL
32#include "sshkey.h"
35#include "digest.h" 33#include "digest.h"
36 34
37static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); 35static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *);
38 36
39/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 37/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
40int 38int
41ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, 39ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
42 const u_char *data, u_int datalen) 40 const u_char *data, size_t datalen, u_int compat)
43{ 41{
44 int hash_alg; 42 int hash_alg;
45 u_char digest[SSH_DIGEST_MAX_LENGTH], *sig; 43 u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
46 u_int slen, dlen, len; 44 size_t slen;
47 int ok, nid; 45 u_int dlen, len;
48 Buffer b; 46 int nid, ret = SSH_ERR_INTERNAL_ERROR;
47 struct sshbuf *b = NULL;
49 48
50 if (key == NULL || key_type_plain(key->type) != KEY_RSA || 49 if (lenp != NULL)
51 key->rsa == NULL) { 50 *lenp = 0;
52 error("%s: no RSA key", __func__); 51 if (sigp != NULL)
53 return -1; 52 *sigp = NULL;
54 } 53
54 if (key == NULL || key->rsa == NULL ||
55 sshkey_type_plain(key->type) != KEY_RSA)
56 return SSH_ERR_INVALID_ARGUMENT;
57 slen = RSA_size(key->rsa);
58 if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
59 return SSH_ERR_INVALID_ARGUMENT;
55 60
56 /* hash the data */ 61 /* hash the data */
57 hash_alg = SSH_DIGEST_SHA1; 62 hash_alg = SSH_DIGEST_SHA1;
58 nid = NID_sha1; 63 nid = NID_sha1;
59 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 64 if ((dlen = ssh_digest_bytes(hash_alg)) == 0)
60 error("%s: bad hash algorithm %d", __func__, hash_alg); 65 return SSH_ERR_INTERNAL_ERROR;
61 return -1; 66 if ((ret = ssh_digest_memory(hash_alg, data, datalen,
62 } 67 digest, sizeof(digest))) != 0)
63 if (ssh_digest_memory(hash_alg, data, datalen, 68 goto out;
64 digest, sizeof(digest)) != 0) {
65 error("%s: ssh_digest_memory failed", __func__);
66 return -1;
67 }
68
69 slen = RSA_size(key->rsa);
70 sig = xmalloc(slen);
71
72 ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
73 explicit_bzero(digest, sizeof(digest));
74 69
75 if (ok != 1) { 70 if ((sig = malloc(slen)) == NULL) {
76 int ecode = ERR_get_error(); 71 ret = SSH_ERR_ALLOC_FAIL;
72 goto out;
73 }
77 74
78 error("%s: RSA_sign failed: %s", __func__, 75 if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) {
79 ERR_error_string(ecode, NULL)); 76 ret = SSH_ERR_LIBCRYPTO_ERROR;
80 free(sig); 77 goto out;
81 return -1;
82 } 78 }
83 if (len < slen) { 79 if (len < slen) {
84 u_int diff = slen - len; 80 size_t diff = slen - len;
85 debug("slen %u > len %u", slen, len);
86 memmove(sig + diff, sig, len); 81 memmove(sig + diff, sig, len);
87 explicit_bzero(sig, diff); 82 explicit_bzero(sig, diff);
88 } else if (len > slen) { 83 } else if (len > slen) {
89 error("%s: slen %u slen2 %u", __func__, slen, len); 84 ret = SSH_ERR_INTERNAL_ERROR;
90 free(sig); 85 goto out;
91 return -1;
92 } 86 }
93 /* encode signature */ 87 /* encode signature */
94 buffer_init(&b); 88 if ((b = sshbuf_new()) == NULL) {
95 buffer_put_cstring(&b, "ssh-rsa"); 89 ret = SSH_ERR_ALLOC_FAIL;
96 buffer_put_string(&b, sig, slen); 90 goto out;
97 len = buffer_len(&b); 91 }
92 if ((ret = sshbuf_put_cstring(b, "ssh-rsa")) != 0 ||
93 (ret = sshbuf_put_string(b, sig, slen)) != 0)
94 goto out;
95 len = sshbuf_len(b);
96 if (sigp != NULL) {
97 if ((*sigp = malloc(len)) == NULL) {
98 ret = SSH_ERR_ALLOC_FAIL;
99 goto out;
100 }
101 memcpy(*sigp, sshbuf_ptr(b), len);
102 }
98 if (lenp != NULL) 103 if (lenp != NULL)
99 *lenp = len; 104 *lenp = len;
100 if (sigp != NULL) { 105 ret = 0;
101 *sigp = xmalloc(len); 106 out:
102 memcpy(*sigp, buffer_ptr(&b), len); 107 explicit_bzero(digest, sizeof(digest));
108 if (sig != NULL) {
109 explicit_bzero(sig, slen);
110 free(sig);
103 } 111 }
104 buffer_free(&b); 112 if (b != NULL)
105 explicit_bzero(sig, slen); 113 sshbuf_free(b);
106 free(sig);
107
108 return 0; 114 return 0;
109} 115}
110 116
111int 117int
112ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, 118ssh_rsa_verify(const struct sshkey *key,
113 const u_char *data, u_int datalen) 119 const u_char *signature, size_t signaturelen,
120 const u_char *data, size_t datalen, u_int compat)
114{ 121{
115 Buffer b; 122 char *ktype = NULL;
116 int hash_alg; 123 int hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
117 char *ktype; 124 size_t len, diff, modlen, dlen;
118 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; 125 struct sshbuf *b = NULL;
119 u_int len, dlen, modlen; 126 u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
120 int rlen, ret;
121 127
122 if (key == NULL || key_type_plain(key->type) != KEY_RSA || 128 if (key == NULL || key->rsa == NULL ||
123 key->rsa == NULL) { 129 sshkey_type_plain(key->type) != KEY_RSA ||
124 error("%s: no RSA key", __func__); 130 BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
125 return -1; 131 return SSH_ERR_INVALID_ARGUMENT;
126 }
127 132
128 if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { 133 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
129 error("%s: RSA modulus too small: %d < minimum %d bits", 134 return SSH_ERR_ALLOC_FAIL;
130 __func__, BN_num_bits(key->rsa->n), 135 if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
131 SSH_RSA_MINIMUM_MODULUS_SIZE); 136 ret = SSH_ERR_INVALID_FORMAT;
132 return -1; 137 goto out;
133 } 138 }
134 buffer_init(&b);
135 buffer_append(&b, signature, signaturelen);
136 ktype = buffer_get_cstring(&b, NULL);
137 if (strcmp("ssh-rsa", ktype) != 0) { 139 if (strcmp("ssh-rsa", ktype) != 0) {
138 error("%s: cannot handle type %s", __func__, ktype); 140 ret = SSH_ERR_KEY_TYPE_MISMATCH;
139 buffer_free(&b); 141 goto out;
140 free(ktype);
141 return -1;
142 } 142 }
143 free(ktype); 143 if (sshbuf_get_string(b, &sigblob, &len) != 0) {
144 sigblob = buffer_get_string(&b, &len); 144 ret = SSH_ERR_INVALID_FORMAT;
145 rlen = buffer_len(&b); 145 goto out;
146 buffer_free(&b); 146 }
147 if (rlen != 0) { 147 if (sshbuf_len(b) != 0) {
148 error("%s: remaining bytes in signature %d", __func__, rlen); 148 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
149 free(sigblob); 149 goto out;
150 return -1;
151 } 150 }
152 /* RSA_verify expects a signature of RSA_size */ 151 /* RSA_verify expects a signature of RSA_size */
153 modlen = RSA_size(key->rsa); 152 modlen = RSA_size(key->rsa);
154 if (len > modlen) { 153 if (len > modlen) {
155 error("%s: len %u > modlen %u", __func__, len, modlen); 154 ret = SSH_ERR_KEY_BITS_MISMATCH;
156 free(sigblob); 155 goto out;
157 return -1;
158 } else if (len < modlen) { 156 } else if (len < modlen) {
159 u_int diff = modlen - len; 157 diff = modlen - len;
160 debug("%s: add padding: modlen %u > len %u", __func__, 158 osigblob = sigblob;
161 modlen, len); 159 if ((sigblob = realloc(sigblob, modlen)) == NULL) {
162 sigblob = xrealloc(sigblob, 1, modlen); 160 sigblob = osigblob; /* put it back for clear/free */
161 ret = SSH_ERR_ALLOC_FAIL;
162 goto out;
163 }
163 memmove(sigblob + diff, sigblob, len); 164 memmove(sigblob + diff, sigblob, len);
164 explicit_bzero(sigblob, diff); 165 explicit_bzero(sigblob, diff);
165 len = modlen; 166 len = modlen;
166 } 167 }
167 /* hash the data */
168 hash_alg = SSH_DIGEST_SHA1; 168 hash_alg = SSH_DIGEST_SHA1;
169 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 169 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
170 error("%s: bad hash algorithm %d", __func__, hash_alg); 170 ret = SSH_ERR_INTERNAL_ERROR;
171 return -1; 171 goto out;
172 }
173 if (ssh_digest_memory(hash_alg, data, datalen,
174 digest, sizeof(digest)) != 0) {
175 error("%s: ssh_digest_memory failed", __func__);
176 return -1;
177 } 172 }
173 if ((ret = ssh_digest_memory(hash_alg, data, datalen,
174 digest, sizeof(digest))) != 0)
175 goto out;
178 176
179 ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 177 ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len,
180 key->rsa); 178 key->rsa);
179 out:
180 if (sigblob != NULL) {
181 explicit_bzero(sigblob, len);
182 free(sigblob);
183 }
184 if (ktype != NULL)
185 free(ktype);
186 if (b != NULL)
187 sshbuf_free(b);
181 explicit_bzero(digest, sizeof(digest)); 188 explicit_bzero(digest, sizeof(digest));
182 explicit_bzero(sigblob, len);
183 free(sigblob);
184 debug("%s: signature %scorrect", __func__, (ret == 0) ? "in" : "");
185 return ret; 189 return ret;
186} 190}
187 191
@@ -204,15 +208,15 @@ static const u_char id_sha1[] = {
204}; 208};
205 209
206static int 210static int
207openssh_RSA_verify(int hash_alg, u_char *hash, u_int hashlen, 211openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
208 u_char *sigbuf, u_int siglen, RSA *rsa) 212 u_char *sigbuf, size_t siglen, RSA *rsa)
209{ 213{
210 u_int ret, rsasize, oidlen = 0, hlen = 0; 214 size_t ret, rsasize = 0, oidlen = 0, hlen = 0;
211 int len, oidmatch, hashmatch; 215 int len, oidmatch, hashmatch;
212 const u_char *oid = NULL; 216 const u_char *oid = NULL;
213 u_char *decrypted = NULL; 217 u_char *decrypted = NULL;
214 218
215 ret = 0; 219 ret = SSH_ERR_INTERNAL_ERROR;
216 switch (hash_alg) { 220 switch (hash_alg) {
217 case SSH_DIGEST_SHA1: 221 case SSH_DIGEST_SHA1:
218 oid = id_sha1; 222 oid = id_sha1;
@@ -223,37 +227,39 @@ openssh_RSA_verify(int hash_alg, u_char *hash, u_int hashlen,
223 goto done; 227 goto done;
224 } 228 }
225 if (hashlen != hlen) { 229 if (hashlen != hlen) {
226 error("bad hashlen"); 230 ret = SSH_ERR_INVALID_ARGUMENT;
227 goto done; 231 goto done;
228 } 232 }
229 rsasize = RSA_size(rsa); 233 rsasize = RSA_size(rsa);
230 if (siglen == 0 || siglen > rsasize) { 234 if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
231 error("bad siglen"); 235 siglen == 0 || siglen > rsasize) {
236 ret = SSH_ERR_INVALID_ARGUMENT;
237 goto done;
238 }
239 if ((decrypted = malloc(rsasize)) == NULL) {
240 ret = SSH_ERR_ALLOC_FAIL;
232 goto done; 241 goto done;
233 } 242 }
234 decrypted = xmalloc(rsasize);
235 if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 243 if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
236 RSA_PKCS1_PADDING)) < 0) { 244 RSA_PKCS1_PADDING)) < 0) {
237 error("RSA_public_decrypt failed: %s", 245 ret = SSH_ERR_LIBCRYPTO_ERROR;
238 ERR_error_string(ERR_get_error(), NULL));
239 goto done; 246 goto done;
240 } 247 }
241 if (len < 0 || (u_int)len != hlen + oidlen) { 248 if (len < 0 || (size_t)len != hlen + oidlen) {
242 error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); 249 ret = SSH_ERR_INVALID_FORMAT;
243 goto done; 250 goto done;
244 } 251 }
245 oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 252 oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
246 hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 253 hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
247 if (!oidmatch) { 254 if (!oidmatch || !hashmatch) {
248 error("oid mismatch"); 255 ret = SSH_ERR_SIGNATURE_INVALID;
249 goto done;
250 }
251 if (!hashmatch) {
252 error("hash mismatch");
253 goto done; 256 goto done;
254 } 257 }
255 ret = 1; 258 ret = 0;
256done: 259done:
257 free(decrypted); 260 if (decrypted) {
261 explicit_bzero(decrypted, rsasize);
262 free(decrypted);
263 }
258 return ret; 264 return ret;
259} 265}
diff --git a/ssh.0 b/ssh.0
index 16868cfca..70ea37733 100644
--- a/ssh.0
+++ b/ssh.0
@@ -1,4 +1,4 @@
1SSH(1) OpenBSD Reference Manual SSH(1) 1SSH(1) General Commands Manual SSH(1)
2 2
3NAME 3NAME
4 ssh - OpenSSH SSH client (remote login program) 4 ssh - OpenSSH SSH client (remote login program)
@@ -17,8 +17,9 @@ DESCRIPTION
17 ssh (SSH client) is a program for logging into a remote machine and for 17 ssh (SSH client) is a program for logging into a remote machine and for
18 executing commands on a remote machine. It is intended to replace rlogin 18 executing commands on a remote machine. It is intended to replace rlogin
19 and rsh, and provide secure encrypted communications between two 19 and rsh, and provide secure encrypted communications between two
20 untrusted hosts over an insecure network. X11 connections and arbitrary 20 untrusted hosts over an insecure network. X11 connections, arbitrary TCP
21 TCP ports can also be forwarded over the secure channel. 21 ports and UNIX-domain sockets can also be forwarded over the secure
22 channel.
22 23
23 ssh connects and logs into the specified hostname (with optional user 24 ssh connects and logs into the specified hostname (with optional user
24 name). The user must prove his/her identity to the remote machine using 25 name). The user must prove his/her identity to the remote machine using
@@ -58,28 +59,21 @@ DESCRIPTION
58 address. 59 address.
59 60
60 -C Requests compression of all data (including stdin, stdout, 61 -C Requests compression of all data (including stdin, stdout,
61 stderr, and data for forwarded X11 and TCP connections). The 62 stderr, and data for forwarded X11, TCP and UNIX-domain
62 compression algorithm is the same used by gzip(1), and the 63 connections). The compression algorithm is the same used by
63 ``level'' can be controlled by the CompressionLevel option for 64 gzip(1), and the ``level'' can be controlled by the
64 protocol version 1. Compression is desirable on modem lines and 65 CompressionLevel option for protocol version 1. Compression is
65 other slow connections, but will only slow down things on fast 66 desirable on modem lines and other slow connections, but will
66 networks. The default value can be set on a host-by-host basis 67 only slow down things on fast networks. The default value can be
67 in the configuration files; see the Compression option. 68 set on a host-by-host basis in the configuration files; see the
69 Compression option.
68 70
69 -c cipher_spec 71 -c cipher_spec
70 Selects the cipher specification for encrypting the session. 72 Selects the cipher specification for encrypting the session.
71 73
72 Protocol version 1 allows specification of a single cipher. The 74 Protocol version 1 allows specification of a single cipher. The
73 supported values are ``3des'', ``blowfish'', and ``des''. 3des 75 supported values are ``3des'', ``blowfish'', and ``des''. For
74 (triple-des) is an encrypt-decrypt-encrypt triple with three 76 protocol version 2, cipher_spec is a comma-separated list of
75 different keys. It is believed to be secure. blowfish is a fast
76 block cipher; it appears very secure and is much faster than
77 3des. des is only supported in the ssh client for
78 interoperability with legacy protocol 1 implementations that do
79 not support the 3des cipher. Its use is strongly discouraged due
80 to cryptographic weaknesses. The default is ``3des''.
81
82 For protocol version 2, cipher_spec is a comma-separated list of
83 ciphers listed in order of preference. See the Ciphers keyword 77 ciphers listed in order of preference. See the Ciphers keyword
84 in ssh_config(5) for more information. 78 in ssh_config(5) for more information.
85 79
@@ -133,7 +127,9 @@ DESCRIPTION
133 port forwards to be successfully established before placing 127 port forwards to be successfully established before placing
134 itself in the background. 128 itself in the background.
135 129
136 -g Allows remote hosts to connect to local forwarded ports. 130 -g Allows remote hosts to connect to local forwarded ports. If used
131 on a multiplexed connection, then this option must be specified
132 on the master process.
137 133
138 -I pkcs11 134 -I pkcs11
139 Specify the PKCS#11 shared library ssh should use to communicate 135 Specify the PKCS#11 shared library ssh should use to communicate
@@ -286,6 +282,8 @@ DESCRIPTION
286 SendEnv 282 SendEnv
287 ServerAliveInterval 283 ServerAliveInterval
288 ServerAliveCountMax 284 ServerAliveCountMax
285 StreamLocalBindMask
286 StreamLocalBindUnlink
289 StrictHostKeyChecking 287 StrictHostKeyChecking
290 TCPKeepAlive 288 TCPKeepAlive
291 Tunnel 289 Tunnel
@@ -890,7 +888,7 @@ EXIT STATUS
890 888
891SEE ALSO 889SEE ALSO
892 scp(1), sftp(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), ssh-keyscan(1), 890 scp(1), sftp(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), ssh-keyscan(1),
893 tun(4), hosts.equiv(5), ssh_config(5), ssh-keysign(8), sshd(8) 891 tun(4), ssh_config(5), ssh-keysign(8), sshd(8)
894 892
895STANDARDS 893STANDARDS
896 S. Lehtinen and C. Lonvick, The Secure Shell (SSH) Protocol Assigned 894 S. Lehtinen and C. Lonvick, The Secure Shell (SSH) Protocol Assigned
@@ -943,4 +941,4 @@ AUTHORS
943 created OpenSSH. Markus Friedl contributed the support for SSH protocol 941 created OpenSSH. Markus Friedl contributed the support for SSH protocol
944 versions 1.5 and 2.0. 942 versions 1.5 and 2.0.
945 943
946OpenBSD 5.5 December 7, 2013 OpenBSD 5.5 944OpenBSD 5.6 July 24, 2014 OpenBSD 5.6
diff --git a/ssh.1 b/ssh.1
index 27794e2d0..fa5cfb2c2 100644
--- a/ssh.1
+++ b/ssh.1
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: ssh.1,v 1.343 2013/12/07 11:58:46 naddy Exp $ 36.\" $OpenBSD: ssh.1,v 1.348 2014/07/24 22:57:10 millert Exp $
37.Dd $Mdocdate: December 7 2013 $ 37.Dd $Mdocdate: July 24 2014 $
38.Dt SSH 1 38.Dt SSH 1
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -73,8 +73,9 @@ executing commands on a remote machine.
73It is intended to replace rlogin and rsh, 73It is intended to replace rlogin and rsh,
74and provide secure encrypted communications between 74and provide secure encrypted communications between
75two untrusted hosts over an insecure network. 75two untrusted hosts over an insecure network.
76X11 connections and arbitrary TCP ports 76X11 connections, arbitrary TCP ports and
77can also be forwarded over the secure channel. 77.Ux Ns -domain
78sockets can also be forwarded over the secure channel.
78.Pp 79.Pp
79.Nm 80.Nm
80connects and logs into the specified 81connects and logs into the specified
@@ -131,7 +132,9 @@ of the connection.
131Only useful on systems with more than one address. 132Only useful on systems with more than one address.
132.It Fl C 133.It Fl C
133Requests compression of all data (including stdin, stdout, stderr, and 134Requests compression of all data (including stdin, stdout, stderr, and
134data for forwarded X11 and TCP connections). 135data for forwarded X11, TCP and
136.Ux Ns -domain
137connections).
135The compression algorithm is the same used by 138The compression algorithm is the same used by
136.Xr gzip 1 , 139.Xr gzip 1 ,
137and the 140and the
@@ -154,23 +157,6 @@ The supported values are
154.Dq blowfish , 157.Dq blowfish ,
155and 158and
156.Dq des . 159.Dq des .
157.Ar 3des
158(triple-des) is an encrypt-decrypt-encrypt triple with three different keys.
159It is believed to be secure.
160.Ar blowfish
161is a fast block cipher; it appears very secure and is much faster than
162.Ar 3des .
163.Ar des
164is only supported in the
165.Nm
166client for interoperability with legacy protocol 1 implementations
167that do not support the
168.Ar 3des
169cipher.
170Its use is strongly discouraged due to cryptographic weaknesses.
171The default is
172.Dq 3des .
173.Pp
174For protocol version 2, 160For protocol version 2,
175.Ar cipher_spec 161.Ar cipher_spec
176is a comma-separated list of ciphers 162is a comma-separated list of ciphers
@@ -267,6 +253,8 @@ will wait for all remote port forwards to be successfully established
267before placing itself in the background. 253before placing itself in the background.
268.It Fl g 254.It Fl g
269Allows remote hosts to connect to local forwarded ports. 255Allows remote hosts to connect to local forwarded ports.
256If used on a multiplexed connection, then this option must be specified
257on the master process.
270.It Fl I Ar pkcs11 258.It Fl I Ar pkcs11
271Specify the PKCS#11 shared library 259Specify the PKCS#11 shared library
272.Nm 260.Nm
@@ -481,6 +469,8 @@ For full details of the options listed below, and their possible values, see
481.It SendEnv 469.It SendEnv
482.It ServerAliveInterval 470.It ServerAliveInterval
483.It ServerAliveCountMax 471.It ServerAliveCountMax
472.It StreamLocalBindMask
473.It StreamLocalBindUnlink
484.It StrictHostKeyChecking 474.It StrictHostKeyChecking
485.It TCPKeepAlive 475.It TCPKeepAlive
486.It Tunnel 476.It Tunnel
@@ -1465,7 +1455,6 @@ if an error occurred.
1465.Xr ssh-keygen 1 , 1455.Xr ssh-keygen 1 ,
1466.Xr ssh-keyscan 1 , 1456.Xr ssh-keyscan 1 ,
1467.Xr tun 4 , 1457.Xr tun 4 ,
1468.Xr hosts.equiv 5 ,
1469.Xr ssh_config 5 , 1458.Xr ssh_config 5 ,
1470.Xr ssh-keysign 8 , 1459.Xr ssh-keysign 8 ,
1471.Xr sshd 8 1460.Xr sshd 8
diff --git a/ssh.c b/ssh.c
index 1e6cb9000..26e9681b7 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.401 2014/02/26 20:18:37 djm Exp $ */ 1/* $OpenBSD: ssh.c,v 1.407 2014/07/17 07:22:19 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -71,8 +71,10 @@
71#include <netinet/in.h> 71#include <netinet/in.h>
72#include <arpa/inet.h> 72#include <arpa/inet.h>
73 73
74#ifdef WITH_OPENSSL
74#include <openssl/evp.h> 75#include <openssl/evp.h>
75#include <openssl/err.h> 76#include <openssl/err.h>
77#endif
76#include "openbsd-compat/openssl-compat.h" 78#include "openbsd-compat/openssl-compat.h"
77#include "openbsd-compat/sys-queue.h" 79#include "openbsd-compat/sys-queue.h"
78 80
@@ -83,6 +85,7 @@
83#include "canohost.h" 85#include "canohost.h"
84#include "compat.h" 86#include "compat.h"
85#include "cipher.h" 87#include "cipher.h"
88#include "digest.h"
86#include "packet.h" 89#include "packet.h"
87#include "buffer.h" 90#include "buffer.h"
88#include "channels.h" 91#include "channels.h"
@@ -93,9 +96,9 @@
93#include "dispatch.h" 96#include "dispatch.h"
94#include "clientloop.h" 97#include "clientloop.h"
95#include "log.h" 98#include "log.h"
99#include "misc.h"
96#include "readconf.h" 100#include "readconf.h"
97#include "sshconnect.h" 101#include "sshconnect.h"
98#include "misc.h"
99#include "kex.h" 102#include "kex.h"
100#include "mac.h" 103#include "mac.h"
101#include "sshpty.h" 104#include "sshpty.h"
@@ -420,8 +423,11 @@ main(int ac, char **av)
420 int timeout_ms; 423 int timeout_ms;
421 extern int optind, optreset; 424 extern int optind, optreset;
422 extern char *optarg; 425 extern char *optarg;
423 Forward fwd; 426 struct Forward fwd;
424 struct addrinfo *addrs = NULL; 427 struct addrinfo *addrs = NULL;
428 struct ssh_digest_ctx *md;
429 u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
430 char *conn_hash_hex;
425 431
426 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 432 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
427 sanitise_stdfd(); 433 sanitise_stdfd();
@@ -539,7 +545,7 @@ main(int ac, char **av)
539 options.forward_x11_trusted = 1; 545 options.forward_x11_trusted = 1;
540 break; 546 break;
541 case 'g': 547 case 'g':
542 options.gateway_ports = 1; 548 options.fwd_opts.gateway_ports = 1;
543 break; 549 break;
544 case 'O': 550 case 'O':
545 if (stdio_forward_host != NULL) 551 if (stdio_forward_host != NULL)
@@ -631,7 +637,13 @@ main(int ac, char **av)
631 break; 637 break;
632 case 'V': 638 case 'V':
633 fprintf(stderr, "%s, %s\n", 639 fprintf(stderr, "%s, %s\n",
634 SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); 640 SSH_RELEASE,
641#ifdef WITH_OPENSSL
642 SSLeay_version(SSLEAY_VERSION)
643#else
644 "without OpenSSL"
645#endif
646 );
635 if (opt == 'V') 647 if (opt == 'V')
636 exit(0); 648 exit(0);
637 break; 649 break;
@@ -828,8 +840,10 @@ main(int ac, char **av)
828 840
829 host_arg = xstrdup(host); 841 host_arg = xstrdup(host);
830 842
843#ifdef WITH_OPENSSL
831 OpenSSL_add_all_algorithms(); 844 OpenSSL_add_all_algorithms();
832 ERR_load_crypto_strings(); 845 ERR_load_crypto_strings();
846#endif
833 847
834 /* Initialize the command to execute on remote host. */ 848 /* Initialize the command to execute on remote host. */
835 buffer_init(&command); 849 buffer_init(&command);
@@ -876,7 +890,13 @@ main(int ac, char **av)
876 SYSLOG_FACILITY_USER, !use_syslog); 890 SYSLOG_FACILITY_USER, !use_syslog);
877 891
878 if (debug_flag) 892 if (debug_flag)
879 logit("%s, %s", SSH_VERSION, SSLeay_version(SSLEAY_VERSION)); 893 logit("%s, %s", SSH_RELEASE,
894#ifdef WITH_OPENSSL
895 SSLeay_version(SSLEAY_VERSION)
896#else
897 "without OpenSSL"
898#endif
899 );
880 900
881 /* Parse the configuration files */ 901 /* Parse the configuration files */
882 process_config_files(pw); 902 process_config_files(pw);
@@ -914,10 +934,14 @@ main(int ac, char **av)
914 if (addrs == NULL && options.num_permitted_cnames != 0 && 934 if (addrs == NULL && options.num_permitted_cnames != 0 &&
915 (option_clear_or_none(options.proxy_command) || 935 (option_clear_or_none(options.proxy_command) ||
916 options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) { 936 options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
917 if ((addrs = resolve_host(host, options.port, 1, 937 if ((addrs = resolve_host(host, options.port,
918 cname, sizeof(cname))) == NULL) 938 option_clear_or_none(options.proxy_command),
919 cleanup_exit(255); /* resolve_host logs the error */ 939 cname, sizeof(cname))) == NULL) {
920 check_follow_cname(&host, cname); 940 /* Don't fatal proxied host names not in the DNS */
941 if (option_clear_or_none(options.proxy_command))
942 cleanup_exit(255); /* logged in resolve_host */
943 } else
944 check_follow_cname(&host, cname);
921 } 945 }
922 946
923 /* 947 /*
@@ -982,12 +1006,29 @@ main(int ac, char **av)
982 shorthost[strcspn(thishost, ".")] = '\0'; 1006 shorthost[strcspn(thishost, ".")] = '\0';
983 snprintf(portstr, sizeof(portstr), "%d", options.port); 1007 snprintf(portstr, sizeof(portstr), "%d", options.port);
984 1008
1009 if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
1010 ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
1011 ssh_digest_update(md, host, strlen(host)) < 0 ||
1012 ssh_digest_update(md, portstr, strlen(portstr)) < 0 ||
1013 ssh_digest_update(md, options.user, strlen(options.user)) < 0 ||
1014 ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
1015 fatal("%s: mux digest failed", __func__);
1016 ssh_digest_free(md);
1017 conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
1018
985 if (options.local_command != NULL) { 1019 if (options.local_command != NULL) {
986 debug3("expanding LocalCommand: %s", options.local_command); 1020 debug3("expanding LocalCommand: %s", options.local_command);
987 cp = options.local_command; 1021 cp = options.local_command;
988 options.local_command = percent_expand(cp, "d", pw->pw_dir, 1022 options.local_command = percent_expand(cp,
989 "h", host, "l", thishost, "n", host_arg, "r", options.user, 1023 "C", conn_hash_hex,
990 "p", portstr, "u", pw->pw_name, "L", shorthost, 1024 "L", shorthost,
1025 "d", pw->pw_dir,
1026 "h", host,
1027 "l", thishost,
1028 "n", host_arg,
1029 "p", portstr,
1030 "r", options.user,
1031 "u", pw->pw_name,
991 (char *)NULL); 1032 (char *)NULL);
992 debug3("expanded LocalCommand: %s", options.local_command); 1033 debug3("expanded LocalCommand: %s", options.local_command);
993 free(cp); 1034 free(cp);
@@ -997,12 +1038,20 @@ main(int ac, char **av)
997 cp = tilde_expand_filename(options.control_path, 1038 cp = tilde_expand_filename(options.control_path,
998 original_real_uid); 1039 original_real_uid);
999 free(options.control_path); 1040 free(options.control_path);
1000 options.control_path = percent_expand(cp, "h", host, 1041 options.control_path = percent_expand(cp,
1001 "l", thishost, "n", host_arg, "r", options.user, 1042 "C", conn_hash_hex,
1002 "p", portstr, "u", pw->pw_name, "L", shorthost, 1043 "L", shorthost,
1044 "h", host,
1045 "l", thishost,
1046 "n", host_arg,
1047 "p", portstr,
1048 "r", options.user,
1049 "u", pw->pw_name,
1003 (char *)NULL); 1050 (char *)NULL);
1004 free(cp); 1051 free(cp);
1005 } 1052 }
1053 free(conn_hash_hex);
1054
1006 if (muxclient_command != 0 && options.control_path == NULL) 1055 if (muxclient_command != 0 && options.control_path == NULL)
1007 fatal("No ControlPath specified for \"-O\" command"); 1056 fatal("No ControlPath specified for \"-O\" command");
1008 if (options.control_path != NULL) 1057 if (options.control_path != NULL)
@@ -1256,13 +1305,17 @@ fork_postauth(void)
1256static void 1305static void
1257ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) 1306ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
1258{ 1307{
1259 Forward *rfwd = (Forward *)ctxt; 1308 struct Forward *rfwd = (struct Forward *)ctxt;
1260 1309
1261 /* XXX verbose() on failure? */ 1310 /* XXX verbose() on failure? */
1262 debug("remote forward %s for: listen %d, connect %s:%d", 1311 debug("remote forward %s for: listen %s%s%d, connect %s:%d",
1263 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", 1312 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
1264 rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); 1313 rfwd->listen_path ? rfwd->listen_path :
1265 if (rfwd->listen_port == 0) { 1314 rfwd->listen_host ? rfwd->listen_host : "",
1315 (rfwd->listen_path || rfwd->listen_host) ? ":" : "",
1316 rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path :
1317 rfwd->connect_host, rfwd->connect_port);
1318 if (rfwd->listen_path == NULL && rfwd->listen_port == 0) {
1266 if (type == SSH2_MSG_REQUEST_SUCCESS) { 1319 if (type == SSH2_MSG_REQUEST_SUCCESS) {
1267 rfwd->allocated_port = packet_get_int(); 1320 rfwd->allocated_port = packet_get_int();
1268 logit("Allocated port %u for remote forward to %s:%d", 1321 logit("Allocated port %u for remote forward to %s:%d",
@@ -1276,12 +1329,21 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
1276 } 1329 }
1277 1330
1278 if (type == SSH2_MSG_REQUEST_FAILURE) { 1331 if (type == SSH2_MSG_REQUEST_FAILURE) {
1279 if (options.exit_on_forward_failure) 1332 if (options.exit_on_forward_failure) {
1280 fatal("Error: remote port forwarding failed for " 1333 if (rfwd->listen_path != NULL)
1281 "listen port %d", rfwd->listen_port); 1334 fatal("Error: remote port forwarding failed "
1282 else 1335 "for listen path %s", rfwd->listen_path);
1283 logit("Warning: remote port forwarding failed for " 1336 else
1284 "listen port %d", rfwd->listen_port); 1337 fatal("Error: remote port forwarding failed "
1338 "for listen port %d", rfwd->listen_port);
1339 } else {
1340 if (rfwd->listen_path != NULL)
1341 logit("Warning: remote port forwarding failed "
1342 "for listen path %s", rfwd->listen_path);
1343 else
1344 logit("Warning: remote port forwarding failed "
1345 "for listen port %d", rfwd->listen_port);
1346 }
1285 } 1347 }
1286 if (++remote_forward_confirms_received == options.num_remote_forwards) { 1348 if (++remote_forward_confirms_received == options.num_remote_forwards) {
1287 debug("All remote forwarding requests processed"); 1349 debug("All remote forwarding requests processed");
@@ -1298,6 +1360,13 @@ client_cleanup_stdio_fwd(int id, void *arg)
1298} 1360}
1299 1361
1300static void 1362static void
1363ssh_stdio_confirm(int id, int success, void *arg)
1364{
1365 if (!success)
1366 fatal("stdio forwarding failed");
1367}
1368
1369static void
1301ssh_init_stdio_forwarding(void) 1370ssh_init_stdio_forwarding(void)
1302{ 1371{
1303 Channel *c; 1372 Channel *c;
@@ -1317,6 +1386,7 @@ ssh_init_stdio_forwarding(void)
1317 stdio_forward_port, in, out)) == NULL) 1386 stdio_forward_port, in, out)) == NULL)
1318 fatal("%s: channel_connect_stdio_fwd failed", __func__); 1387 fatal("%s: channel_connect_stdio_fwd failed", __func__);
1319 channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0); 1388 channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0);
1389 channel_register_open_confirm(c->self, ssh_stdio_confirm, NULL);
1320} 1390}
1321 1391
1322static void 1392static void
@@ -1329,18 +1399,18 @@ ssh_init_forwarding(void)
1329 for (i = 0; i < options.num_local_forwards; i++) { 1399 for (i = 0; i < options.num_local_forwards; i++) {
1330 debug("Local connections to %.200s:%d forwarded to remote " 1400 debug("Local connections to %.200s:%d forwarded to remote "
1331 "address %.200s:%d", 1401 "address %.200s:%d",
1402 (options.local_forwards[i].listen_path != NULL) ?
1403 options.local_forwards[i].listen_path :
1332 (options.local_forwards[i].listen_host == NULL) ? 1404 (options.local_forwards[i].listen_host == NULL) ?
1333 (options.gateway_ports ? "*" : "LOCALHOST") : 1405 (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
1334 options.local_forwards[i].listen_host, 1406 options.local_forwards[i].listen_host,
1335 options.local_forwards[i].listen_port, 1407 options.local_forwards[i].listen_port,
1408 (options.local_forwards[i].connect_path != NULL) ?
1409 options.local_forwards[i].connect_path :
1336 options.local_forwards[i].connect_host, 1410 options.local_forwards[i].connect_host,
1337 options.local_forwards[i].connect_port); 1411 options.local_forwards[i].connect_port);
1338 success += channel_setup_local_fwd_listener( 1412 success += channel_setup_local_fwd_listener(
1339 options.local_forwards[i].listen_host, 1413 &options.local_forwards[i], &options.fwd_opts);
1340 options.local_forwards[i].listen_port,
1341 options.local_forwards[i].connect_host,
1342 options.local_forwards[i].connect_port,
1343 options.gateway_ports);
1344 } 1414 }
1345 if (i > 0 && success != i && options.exit_on_forward_failure) 1415 if (i > 0 && success != i && options.exit_on_forward_failure)
1346 fatal("Could not request local forwarding."); 1416 fatal("Could not request local forwarding.");
@@ -1351,17 +1421,18 @@ ssh_init_forwarding(void)
1351 for (i = 0; i < options.num_remote_forwards; i++) { 1421 for (i = 0; i < options.num_remote_forwards; i++) {
1352 debug("Remote connections from %.200s:%d forwarded to " 1422 debug("Remote connections from %.200s:%d forwarded to "
1353 "local address %.200s:%d", 1423 "local address %.200s:%d",
1424 (options.remote_forwards[i].listen_path != NULL) ?
1425 options.remote_forwards[i].listen_path :
1354 (options.remote_forwards[i].listen_host == NULL) ? 1426 (options.remote_forwards[i].listen_host == NULL) ?
1355 "LOCALHOST" : options.remote_forwards[i].listen_host, 1427 "LOCALHOST" : options.remote_forwards[i].listen_host,
1356 options.remote_forwards[i].listen_port, 1428 options.remote_forwards[i].listen_port,
1429 (options.remote_forwards[i].connect_path != NULL) ?
1430 options.remote_forwards[i].connect_path :
1357 options.remote_forwards[i].connect_host, 1431 options.remote_forwards[i].connect_host,
1358 options.remote_forwards[i].connect_port); 1432 options.remote_forwards[i].connect_port);
1359 options.remote_forwards[i].handle = 1433 options.remote_forwards[i].handle =
1360 channel_request_remote_forwarding( 1434 channel_request_remote_forwarding(
1361 options.remote_forwards[i].listen_host, 1435 &options.remote_forwards[i]);
1362 options.remote_forwards[i].listen_port,
1363 options.remote_forwards[i].connect_host,
1364 options.remote_forwards[i].connect_port);
1365 if (options.remote_forwards[i].handle < 0) { 1436 if (options.remote_forwards[i].handle < 0) {
1366 if (options.exit_on_forward_failure) 1437 if (options.exit_on_forward_failure)
1367 fatal("Could not request remote forwarding."); 1438 fatal("Could not request remote forwarding.");
diff --git a/ssh_config.0 b/ssh_config.0
index 6fbd10d61..c40ce5f08 100644
--- a/ssh_config.0
+++ b/ssh_config.0
@@ -1,4 +1,4 @@
1SSH_CONFIG(5) OpenBSD Programmer's Manual SSH_CONFIG(5) 1SSH_CONFIG(5) File Formats Manual SSH_CONFIG(5)
2 2
3NAME 3NAME
4 ssh_config - OpenSSH SSH client configuration files 4 ssh_config - OpenSSH SSH client configuration files
@@ -176,19 +176,30 @@ DESCRIPTION
176 preference. Multiple ciphers must be comma-separated. The 176 preference. Multiple ciphers must be comma-separated. The
177 supported ciphers are: 177 supported ciphers are:
178 178
179 ``3des-cbc'', ``aes128-cbc'', ``aes192-cbc'', ``aes256-cbc'', 179 3des-cbc
180 ``aes128-ctr'', ``aes192-ctr'', ``aes256-ctr'', 180 aes128-cbc
181 ``aes128-gcm@openssh.com'', ``aes256-gcm@openssh.com'', 181 aes192-cbc
182 ``arcfour128'', ``arcfour256'', ``arcfour'', ``blowfish-cbc'', 182 aes256-cbc
183 ``cast128-cbc'', and ``chacha20-poly1305@openssh.com''. 183 aes128-ctr
184 aes192-ctr
185 aes256-ctr
186 aes128-gcm@openssh.com
187 aes256-gcm@openssh.com
188 arcfour
189 arcfour128
190 arcfour256
191 blowfish-cbc
192 cast128-cbc
193 chacha20-poly1305@openssh.com
184 194
185 The default is: 195 The default is:
186 196
187 aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, 197 aes128-ctr,aes192-ctr,aes256-ctr,
188 aes128-gcm@openssh.com,aes256-gcm@openssh.com, 198 aes128-gcm@openssh.com,aes256-gcm@openssh.com,
189 chacha20-poly1305@openssh.com, 199 chacha20-poly1305@openssh.com,
190 aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc, 200 arcfour256,arcfour128,
191 aes256-cbc,arcfour 201 aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,
202 aes192-cbc,aes256-cbc,arcfour
192 203
193 The list of available ciphers may also be obtained using the -Q 204 The list of available ciphers may also be obtained using the -Q
194 option of ssh(1). 205 option of ssh(1).
@@ -261,10 +272,12 @@ DESCRIPTION
261 any domain name), `%h' will be substituted by the target host 272 any domain name), `%h' will be substituted by the target host
262 name, `%n' will be substituted by the original target host name 273 name, `%n' will be substituted by the original target host name
263 specified on the command line, `%p' the destination port, `%r' by 274 specified on the command line, `%p' the destination port, `%r' by
264 the remote login username, and `%u' by the username of the user 275 the remote login username, `%u' by the username of the user
265 running ssh(1). It is recommended that any ControlPath used for 276 running ssh(1), and `%C' by a hash of the concatenation:
266 opportunistic connection sharing include at least %h, %p, and %r. 277 %l%h%p%r. It is recommended that any ControlPath used for
267 This ensures that shared connections are uniquely identified. 278 opportunistic connection sharing include at least %h, %p, and %r
279 (or alternatively %C). This ensures that shared connections are
280 uniquely identified.
268 281
269 ControlPersist 282 ControlPersist
270 When used in conjunction with ControlMaster, specifies that the 283 When used in conjunction with ControlMaster, specifies that the
@@ -437,10 +450,13 @@ DESCRIPTION
437 specify nicknames or abbreviations for hosts. If the hostname 450 specify nicknames or abbreviations for hosts. If the hostname
438 contains the character sequence `%h', then this will be replaced 451 contains the character sequence `%h', then this will be replaced
439 with the host name specified on the command line (this is useful 452 with the host name specified on the command line (this is useful
440 for manipulating unqualified names). The default is the name 453 for manipulating unqualified names). The character sequence `%%'
441 given on the command line. Numeric IP addresses are also 454 will be replaced by a single `%' character, which may be used
442 permitted (both on the command line and in HostName 455 when specifying IPv6 link-local addresses.
443 specifications). 456
457 The default is the name given on the command line. Numeric IP
458 addresses are also permitted (both on the command line and in
459 HostName specifications).
444 460
445 IdentitiesOnly 461 IdentitiesOnly
446 Specifies that ssh(1) should only use the authentication identity 462 Specifies that ssh(1) should only use the authentication identity
@@ -517,8 +533,8 @@ DESCRIPTION
517 curve25519-sha256@libssh.org, 533 curve25519-sha256@libssh.org,
518 ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, 534 ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
519 diffie-hellman-group-exchange-sha256, 535 diffie-hellman-group-exchange-sha256,
520 diffie-hellman-group-exchange-sha1,
521 diffie-hellman-group14-sha1, 536 diffie-hellman-group14-sha1,
537 diffie-hellman-group-exchange-sha1,
522 diffie-hellman-group1-sha1 538 diffie-hellman-group1-sha1
523 539
524 LocalCommand 540 LocalCommand
@@ -529,7 +545,8 @@ DESCRIPTION
529 performed: `%d' (local user's home directory), `%h' (remote host 545 performed: `%d' (local user's home directory), `%h' (remote host
530 name), `%l' (local host name), `%n' (host name as provided on the 546 name), `%l' (local host name), `%n' (host name as provided on the
531 command line), `%p' (remote port), `%r' (remote user name) or 547 command line), `%p' (remote port), `%r' (remote user name) or
532 `%u' (local user name). 548 `%u' (local user name) or `%C' by a hash of the concatenation:
549 %l%h%p%r.
533 550
534 The command is run synchronously and does not have access to the 551 The command is run synchronously and does not have access to the
535 session of the ssh(1) that spawned it. It should not be used for 552 session of the ssh(1) that spawned it. It should not be used for
@@ -568,13 +585,14 @@ DESCRIPTION
568 calculate the MAC after encryption (encrypt-then-mac). These are 585 calculate the MAC after encryption (encrypt-then-mac). These are
569 considered safer and their use recommended. The default is: 586 considered safer and their use recommended. The default is:
570 587
571 hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com,
572 umac-64-etm@openssh.com,umac-128-etm@openssh.com, 588 umac-64-etm@openssh.com,umac-128-etm@openssh.com,
573 hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com, 589 hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,
574 hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com, 590 umac-64@openssh.com,umac-128@openssh.com,
575 hmac-md5-96-etm@openssh.com, 591 hmac-sha2-256,hmac-sha2-512,
576 hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com, 592 hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com,
577 hmac-sha2-256,hmac-sha2-512,hmac-ripemd160, 593 hmac-ripemd160-etm@openssh.com,
594 hmac-sha1-96-etm@openssh.com,hmac-md5-96-etm@openssh.com,
595 hmac-md5,hmac-sha1,hmac-ripemd160,
578 hmac-sha1-96,hmac-md5-96 596 hmac-sha1-96,hmac-md5-96
579 597
580 NoHostAuthenticationForLocalhost 598 NoHostAuthenticationForLocalhost
@@ -628,17 +646,19 @@ DESCRIPTION
628 ProxyCommand 646 ProxyCommand
629 Specifies the command to use to connect to the server. The 647 Specifies the command to use to connect to the server. The
630 command string extends to the end of the line, and is executed 648 command string extends to the end of the line, and is executed
631 with the user's shell. In the command string, any occurrence of 649 using the user's shell `exec' directive to avoid a lingering
632 `%h' will be substituted by the host name to connect, `%p' by the 650 shell process.
633 port, and `%r' by the remote user name. The command can be 651
634 basically anything, and should read from its standard input and 652 In the command string, any occurrence of `%h' will be substituted
635 write to its standard output. It should eventually connect an 653 by the host name to connect, `%p' by the port, and `%r' by the
636 sshd(8) server running on some machine, or execute sshd -i 654 remote user name. The command can be basically anything, and
637 somewhere. Host key management will be done using the HostName 655 should read from its standard input and write to its standard
638 of the host being connected (defaulting to the name typed by the 656 output. It should eventually connect an sshd(8) server running
639 user). Setting the command to ``none'' disables this option 657 on some machine, or execute sshd -i somewhere. Host key
640 entirely. Note that CheckHostIP is not available for connects 658 management will be done using the HostName of the host being
641 with a proxy command. 659 connected (defaulting to the name typed by the user). Setting
660 the command to ``none'' disables this option entirely. Note that
661 CheckHostIP is not available for connects with a proxy command.
642 662
643 This directive is useful in conjunction with nc(1) and its proxy 663 This directive is useful in conjunction with nc(1) and its proxy
644 support. For example, the following directive would connect via 664 support. For example, the following directive would connect via
@@ -751,6 +771,27 @@ DESCRIPTION
751 default is 0, indicating that these messages will not be sent to 771 default is 0, indicating that these messages will not be sent to
752 the server. This option applies to protocol version 2 only. 772 the server. This option applies to protocol version 2 only.
753 773
774 StreamLocalBindMask
775 Sets the octal file creation mode mask (umask) used when creating
776 a Unix-domain socket file for local or remote port forwarding.
777 This option is only used for port forwarding to a Unix-domain
778 socket file.
779
780 The default value is 0177, which creates a Unix-domain socket
781 file that is readable and writable only by the owner. Note that
782 not all operating systems honor the file mode on Unix-domain
783 socket files.
784
785 StreamLocalBindUnlink
786 Specifies whether to remove an existing Unix-domain socket file
787 for local or remote port forwarding before creating a new one.
788 If the socket file already exists and StreamLocalBindUnlink is
789 not enabled, ssh will be unable to forward the port to the Unix-
790 domain socket file. This option is only used for port forwarding
791 to a Unix-domain socket file.
792
793 The argument must be ``yes'' or ``no''. The default is ``no''.
794
754 StrictHostKeyChecking 795 StrictHostKeyChecking
755 If this flag is set to ``yes'', ssh(1) will never automatically 796 If this flag is set to ``yes'', ssh(1) will never automatically
756 add host keys to the ~/.ssh/known_hosts file, and refuses to 797 add host keys to the ~/.ssh/known_hosts file, and refuses to
@@ -886,4 +927,4 @@ AUTHORS
886 created OpenSSH. Markus Friedl contributed the support for SSH protocol 927 created OpenSSH. Markus Friedl contributed the support for SSH protocol
887 versions 1.5 and 2.0. 928 versions 1.5 and 2.0.
888 929
889OpenBSD 5.5 February 23, 2014 OpenBSD 5.5 930OpenBSD 5.6 July 15, 2014 OpenBSD 5.6
diff --git a/ssh_config.5 b/ssh_config.5
index b5803920f..f9ede7a31 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: ssh_config.5,v 1.185 2014/02/23 20:11:36 djm Exp $ 36.\" $OpenBSD: ssh_config.5,v 1.191 2014/07/15 15:54:14 millert Exp $
37.Dd $Mdocdate: February 23 2014 $ 37.Dd $Mdocdate: July 15 2014 $
38.Dt SSH_CONFIG 5 38.Dt SSH_CONFIG 5
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -342,30 +342,47 @@ in order of preference.
342Multiple ciphers must be comma-separated. 342Multiple ciphers must be comma-separated.
343The supported ciphers are: 343The supported ciphers are:
344.Pp 344.Pp
345.Dq 3des-cbc , 345.Bl -item -compact -offset indent
346.Dq aes128-cbc , 346.It
347.Dq aes192-cbc , 3473des-cbc
348.Dq aes256-cbc , 348.It
349.Dq aes128-ctr , 349aes128-cbc
350.Dq aes192-ctr , 350.It
351.Dq aes256-ctr , 351aes192-cbc
352.Dq aes128-gcm@openssh.com , 352.It
353.Dq aes256-gcm@openssh.com , 353aes256-cbc
354.Dq arcfour128 , 354.It
355.Dq arcfour256 , 355aes128-ctr
356.Dq arcfour , 356.It
357.Dq blowfish-cbc , 357aes192-ctr
358.Dq cast128-cbc , 358.It
359and 359aes256-ctr
360.Dq chacha20-poly1305@openssh.com . 360.It
361aes128-gcm@openssh.com
362.It
363aes256-gcm@openssh.com
364.It
365arcfour
366.It
367arcfour128
368.It
369arcfour256
370.It
371blowfish-cbc
372.It
373cast128-cbc
374.It
375chacha20-poly1305@openssh.com
376.El
361.Pp 377.Pp
362The default is: 378The default is:
363.Bd -literal -offset 3n 379.Bd -literal -offset indent
364aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, 380aes128-ctr,aes192-ctr,aes256-ctr,
365aes128-gcm@openssh.com,aes256-gcm@openssh.com, 381aes128-gcm@openssh.com,aes256-gcm@openssh.com,
366chacha20-poly1305@openssh.com, 382chacha20-poly1305@openssh.com,
367aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc, 383arcfour256,arcfour128,
368aes256-cbc,arcfour 384aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,
385aes192-cbc,aes256-cbc,arcfour
369.Ed 386.Ed
370.Pp 387.Pp
371The list of available ciphers may also be obtained using the 388The list of available ciphers may also be obtained using the
@@ -482,14 +499,16 @@ specified on the command line,
482.Ql %p 499.Ql %p
483the destination port, 500the destination port,
484.Ql %r 501.Ql %r
485by the remote login username, and 502by the remote login username,
486.Ql %u 503.Ql %u
487by the username of the user running 504by the username of the user running
488.Xr ssh 1 . 505.Xr ssh 1 , and
506.Ql \&%C
507by a hash of the concatenation: %l%h%p%r.
489It is recommended that any 508It is recommended that any
490.Cm ControlPath 509.Cm ControlPath
491used for opportunistic connection sharing include 510used for opportunistic connection sharing include
492at least %h, %p, and %r. 511at least %h, %p, and %r (or alternatively %C).
493This ensures that shared connections are uniquely identified. 512This ensures that shared connections are uniquely identified.
494.It Cm ControlPersist 513.It Cm ControlPersist
495When used in conjunction with 514When used in conjunction with
@@ -746,6 +765,12 @@ If the hostname contains the character sequence
746.Ql %h , 765.Ql %h ,
747then this will be replaced with the host name specified on the command line 766then this will be replaced with the host name specified on the command line
748(this is useful for manipulating unqualified names). 767(this is useful for manipulating unqualified names).
768The character sequence
769.Ql %%
770will be replaced by a single
771.Ql %
772character, which may be used when specifying IPv6 link-local addresses.
773.Pp
749The default is the name given on the command line. 774The default is the name given on the command line.
750Numeric IP addresses are also permitted (both on the command line and in 775Numeric IP addresses are also permitted (both on the command line and in
751.Cm HostName 776.Cm HostName
@@ -893,8 +918,8 @@ The default is:
893curve25519-sha256@libssh.org, 918curve25519-sha256@libssh.org,
894ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, 919ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
895diffie-hellman-group-exchange-sha256, 920diffie-hellman-group-exchange-sha256,
896diffie-hellman-group-exchange-sha1,
897diffie-hellman-group14-sha1, 921diffie-hellman-group14-sha1,
922diffie-hellman-group-exchange-sha1,
898diffie-hellman-group1-sha1 923diffie-hellman-group1-sha1
899.Ed 924.Ed
900.It Cm LocalCommand 925.It Cm LocalCommand
@@ -916,7 +941,9 @@ The following escape character substitutions will be performed:
916.Ql %r 941.Ql %r
917(remote user name) or 942(remote user name) or
918.Ql %u 943.Ql %u
919(local user name). 944(local user name) or
945.Ql \&%C
946by a hash of the concatenation: %l%h%p%r.
920.Pp 947.Pp
921The command is run synchronously and does not have access to the 948The command is run synchronously and does not have access to the
922session of the 949session of the
@@ -974,13 +1001,14 @@ calculate the MAC after encryption (encrypt-then-mac).
974These are considered safer and their use recommended. 1001These are considered safer and their use recommended.
975The default is: 1002The default is:
976.Bd -literal -offset indent 1003.Bd -literal -offset indent
977hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com,
978umac-64-etm@openssh.com,umac-128-etm@openssh.com, 1004umac-64-etm@openssh.com,umac-128-etm@openssh.com,
979hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com, 1005hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,
980hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com, 1006umac-64@openssh.com,umac-128@openssh.com,
981hmac-md5-96-etm@openssh.com, 1007hmac-sha2-256,hmac-sha2-512,
982hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com, 1008hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com,
983hmac-sha2-256,hmac-sha2-512,hmac-ripemd160, 1009hmac-ripemd160-etm@openssh.com,
1010hmac-sha1-96-etm@openssh.com,hmac-md5-96-etm@openssh.com,
1011hmac-md5,hmac-sha1,hmac-ripemd160,
984hmac-sha1-96,hmac-md5-96 1012hmac-sha1-96,hmac-md5-96
985.Ed 1013.Ed
986.It Cm NoHostAuthenticationForLocalhost 1014.It Cm NoHostAuthenticationForLocalhost
@@ -1058,8 +1086,11 @@ The default is
1058.It Cm ProxyCommand 1086.It Cm ProxyCommand
1059Specifies the command to use to connect to the server. 1087Specifies the command to use to connect to the server.
1060The command 1088The command
1061string extends to the end of the line, and is executed with 1089string extends to the end of the line, and is executed
1062the user's shell. 1090using the user's shell
1091.Ql exec
1092directive to avoid a lingering shell process.
1093.Pp
1063In the command string, any occurrence of 1094In the command string, any occurrence of
1064.Ql %h 1095.Ql %h
1065will be substituted by the host name to 1096will be substituted by the host name to
@@ -1272,6 +1303,33 @@ channel to request a response from the server.
1272The default 1303The default
1273is 0, indicating that these messages will not be sent to the server. 1304is 0, indicating that these messages will not be sent to the server.
1274This option applies to protocol version 2 only. 1305This option applies to protocol version 2 only.
1306.It Cm StreamLocalBindMask
1307Sets the octal file creation mode mask
1308.Pq umask
1309used when creating a Unix-domain socket file for local or remote
1310port forwarding.
1311This option is only used for port forwarding to a Unix-domain socket file.
1312.Pp
1313The default value is 0177, which creates a Unix-domain socket file that is
1314readable and writable only by the owner.
1315Note that not all operating systems honor the file mode on Unix-domain
1316socket files.
1317.It Cm StreamLocalBindUnlink
1318Specifies whether to remove an existing Unix-domain socket file for local
1319or remote port forwarding before creating a new one.
1320If the socket file already exists and
1321.Cm StreamLocalBindUnlink
1322is not enabled,
1323.Nm ssh
1324will be unable to forward the port to the Unix-domain socket file.
1325This option is only used for port forwarding to a Unix-domain socket file.
1326.Pp
1327The argument must be
1328.Dq yes
1329or
1330.Dq no .
1331The default is
1332.Dq no .
1275.It Cm StrictHostKeyChecking 1333.It Cm StrictHostKeyChecking
1276If this flag is set to 1334If this flag is set to
1277.Dq yes , 1335.Dq yes ,
diff --git a/sshbuf-getput-basic.c b/sshbuf-getput-basic.c
new file mode 100644
index 000000000..b7d0758c2
--- /dev/null
+++ b/sshbuf-getput-basic.c
@@ -0,0 +1,421 @@
1/* $OpenBSD: sshbuf-getput-basic.c,v 1.1 2014/04/30 05:29:56 djm Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#define SSHBUF_INTERNAL
19#include "includes.h"
20
21#include <sys/types.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25
26#include "ssherr.h"
27#include "sshbuf.h"
28
29int
30sshbuf_get(struct sshbuf *buf, void *v, size_t len)
31{
32 const u_char *p = sshbuf_ptr(buf);
33 int r;
34
35 if ((r = sshbuf_consume(buf, len)) < 0)
36 return r;
37 if (v != NULL)
38 memcpy(v, p, len);
39 return 0;
40}
41
42int
43sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
44{
45 const u_char *p = sshbuf_ptr(buf);
46 int r;
47
48 if ((r = sshbuf_consume(buf, 8)) < 0)
49 return r;
50 if (valp != NULL)
51 *valp = PEEK_U64(p);
52 return 0;
53}
54
55int
56sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
57{
58 const u_char *p = sshbuf_ptr(buf);
59 int r;
60
61 if ((r = sshbuf_consume(buf, 4)) < 0)
62 return r;
63 if (valp != NULL)
64 *valp = PEEK_U32(p);
65 return 0;
66}
67
68int
69sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
70{
71 const u_char *p = sshbuf_ptr(buf);
72 int r;
73
74 if ((r = sshbuf_consume(buf, 2)) < 0)
75 return r;
76 if (valp != NULL)
77 *valp = PEEK_U16(p);
78 return 0;
79}
80
81int
82sshbuf_get_u8(struct sshbuf *buf, u_char *valp)
83{
84 const u_char *p = sshbuf_ptr(buf);
85 int r;
86
87 if ((r = sshbuf_consume(buf, 1)) < 0)
88 return r;
89 if (valp != NULL)
90 *valp = (u_int8_t)*p;
91 return 0;
92}
93
94int
95sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
96{
97 const u_char *val;
98 size_t len;
99 int r;
100
101 if (valp != NULL)
102 *valp = NULL;
103 if (lenp != NULL)
104 *lenp = 0;
105 if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
106 return r;
107 if (valp != NULL) {
108 if ((*valp = malloc(len + 1)) == NULL) {
109 SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
110 return SSH_ERR_ALLOC_FAIL;
111 }
112 memcpy(*valp, val, len);
113 (*valp)[len] = '\0';
114 }
115 if (lenp != NULL)
116 *lenp = len;
117 return 0;
118}
119
120int
121sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
122{
123 size_t len;
124 const u_char *p;
125 int r;
126
127 if (valp != NULL)
128 *valp = NULL;
129 if (lenp != NULL)
130 *lenp = 0;
131 if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
132 return r;
133 if (valp != 0)
134 *valp = p;
135 if (lenp != NULL)
136 *lenp = len;
137 if (sshbuf_consume(buf, len + 4) != 0) {
138 /* Shouldn't happen */
139 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
140 SSHBUF_ABORT();
141 return SSH_ERR_INTERNAL_ERROR;
142 }
143 return 0;
144}
145
146int
147sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
148 size_t *lenp)
149{
150 u_int32_t len;
151 const u_char *p = sshbuf_ptr(buf);
152
153 if (valp != NULL)
154 *valp = NULL;
155 if (lenp != NULL)
156 *lenp = 0;
157 if (sshbuf_len(buf) < 4) {
158 SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
159 return SSH_ERR_MESSAGE_INCOMPLETE;
160 }
161 len = PEEK_U32(p);
162 if (len > SSHBUF_SIZE_MAX - 4) {
163 SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
164 return SSH_ERR_STRING_TOO_LARGE;
165 }
166 if (sshbuf_len(buf) - 4 < len) {
167 SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
168 return SSH_ERR_MESSAGE_INCOMPLETE;
169 }
170 if (valp != 0)
171 *valp = p + 4;
172 if (lenp != NULL)
173 *lenp = len;
174 return 0;
175}
176
177int
178sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
179{
180 size_t len;
181 const u_char *p, *z;
182 int r;
183
184 if (valp != NULL)
185 *valp = NULL;
186 if (lenp != NULL)
187 *lenp = 0;
188 if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
189 return r;
190 /* Allow a \0 only at the end of the string */
191 if (len > 0 &&
192 (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
193 SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
194 return SSH_ERR_INVALID_FORMAT;
195 }
196 if ((r = sshbuf_skip_string(buf)) != 0)
197 return -1;
198 if (valp != NULL) {
199 if ((*valp = malloc(len + 1)) == NULL) {
200 SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
201 return SSH_ERR_ALLOC_FAIL;
202 }
203 memcpy(*valp, p, len);
204 (*valp)[len] = '\0';
205 }
206 if (lenp != NULL)
207 *lenp = (size_t)len;
208 return 0;
209}
210
211int
212sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
213{
214 u_int32_t len;
215 u_char *p;
216 int r;
217
218 /*
219 * Use sshbuf_peek_string_direct() to figure out if there is
220 * a complete string in 'buf' and copy the string directly
221 * into 'v'.
222 */
223 if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
224 (r = sshbuf_get_u32(buf, &len)) != 0 ||
225 (r = sshbuf_reserve(v, len, &p)) != 0 ||
226 (r = sshbuf_get(buf, p, len)) != 0)
227 return r;
228 return 0;
229}
230
231int
232sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
233{
234 u_char *p;
235 int r;
236
237 if ((r = sshbuf_reserve(buf, len, &p)) < 0)
238 return r;
239 memcpy(p, v, len);
240 return 0;
241}
242
243int
244sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
245{
246 return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
247}
248
249int
250sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
251{
252 va_list ap;
253 int r;
254
255 va_start(ap, fmt);
256 r = sshbuf_putfv(buf, fmt, ap);
257 va_end(ap);
258 return r;
259}
260
261int
262sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
263{
264 va_list ap2;
265 int r, len;
266 u_char *p;
267
268 va_copy(ap2, ap);
269 if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
270 r = SSH_ERR_INVALID_ARGUMENT;
271 goto out;
272 }
273 if (len == 0) {
274 r = 0;
275 goto out; /* Nothing to do */
276 }
277 va_end(ap2);
278 va_copy(ap2, ap);
279 if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
280 goto out;
281 if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
282 r = SSH_ERR_INTERNAL_ERROR;
283 goto out; /* Shouldn't happen */
284 }
285 /* Consume terminating \0 */
286 if ((r = sshbuf_consume_end(buf, 1)) != 0)
287 goto out;
288 r = 0;
289 out:
290 va_end(ap2);
291 return r;
292}
293
294int
295sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
296{
297 u_char *p;
298 int r;
299
300 if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
301 return r;
302 POKE_U64(p, val);
303 return 0;
304}
305
306int
307sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
308{
309 u_char *p;
310 int r;
311
312 if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
313 return r;
314 POKE_U32(p, val);
315 return 0;
316}
317
318int
319sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
320{
321 u_char *p;
322 int r;
323
324 if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
325 return r;
326 POKE_U16(p, val);
327 return 0;
328}
329
330int
331sshbuf_put_u8(struct sshbuf *buf, u_char val)
332{
333 u_char *p;
334 int r;
335
336 if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
337 return r;
338 p[0] = val;
339 return 0;
340}
341
342int
343sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
344{
345 u_char *d;
346 int r;
347
348 if (len > SSHBUF_SIZE_MAX - 4) {
349 SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
350 return SSH_ERR_NO_BUFFER_SPACE;
351 }
352 if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
353 return r;
354 POKE_U32(d, len);
355 memcpy(d + 4, v, len);
356 return 0;
357}
358
359int
360sshbuf_put_cstring(struct sshbuf *buf, const char *v)
361{
362 return sshbuf_put_string(buf, (u_char *)v, strlen(v));
363}
364
365int
366sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
367{
368 return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
369}
370
371int
372sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
373{
374 const u_char *p;
375 size_t len;
376 struct sshbuf *ret;
377 int r;
378
379 if (buf == NULL || bufp == NULL)
380 return SSH_ERR_INVALID_ARGUMENT;
381 *bufp = NULL;
382 if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
383 return r;
384 if ((ret = sshbuf_from(p, len)) == NULL)
385 return SSH_ERR_ALLOC_FAIL;
386 if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */
387 (r = sshbuf_set_parent(ret, buf)) != 0) {
388 sshbuf_free(ret);
389 return r;
390 }
391 *bufp = ret;
392 return 0;
393}
394
395int
396sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
397{
398 u_char *d;
399 const u_char *s = (const u_char *)v;
400 int r, prepend;
401
402 if (len > SSHBUF_SIZE_MAX - 5) {
403 SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
404 return SSH_ERR_NO_BUFFER_SPACE;
405 }
406 /* Skip leading zero bytes */
407 for (; len > 0 && *s == 0; len--, s++)
408 ;
409 /*
410 * If most significant bit is set then prepend a zero byte to
411 * avoid interpretation as a negative number.
412 */
413 prepend = len > 0 && (s[0] & 0x80) != 0;
414 if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
415 return r;
416 POKE_U32(d, len + prepend);
417 if (prepend)
418 d[4] = 0;
419 memcpy(d + 4 + prepend, s, len);
420 return 0;
421}
diff --git a/sshbuf-getput-crypto.c b/sshbuf-getput-crypto.c
new file mode 100644
index 000000000..74351d3e5
--- /dev/null
+++ b/sshbuf-getput-crypto.c
@@ -0,0 +1,237 @@
1/* $OpenBSD: sshbuf-getput-crypto.c,v 1.2 2014/06/18 15:42:09 naddy Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#define SSHBUF_INTERNAL
19#include "includes.h"
20
21#include <sys/types.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25
26#include <openssl/bn.h>
27#ifdef OPENSSL_HAS_ECC
28# include <openssl/ec.h>
29#endif /* OPENSSL_HAS_ECC */
30
31#include "ssherr.h"
32#include "sshbuf.h"
33
34int
35sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v)
36{
37 const u_char *d;
38 size_t len;
39 int r;
40
41 if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
42 return r;
43 /* Refuse negative (MSB set) bignums */
44 if ((len != 0 && (*d & 0x80) != 0))
45 return SSH_ERR_BIGNUM_IS_NEGATIVE;
46 /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
47 if (len > SSHBUF_MAX_BIGNUM + 1 ||
48 (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
49 return SSH_ERR_BIGNUM_TOO_LARGE;
50 if (v != NULL && BN_bin2bn(d, len, v) == NULL)
51 return SSH_ERR_ALLOC_FAIL;
52 /* Consume the string */
53 if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
54 /* Shouldn't happen */
55 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
56 SSHBUF_ABORT();
57 return SSH_ERR_INTERNAL_ERROR;
58 }
59 return 0;
60}
61
62int
63sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v)
64{
65 const u_char *d = sshbuf_ptr(buf);
66 u_int16_t len_bits;
67 size_t len_bytes;
68
69 /* Length in bits */
70 if (sshbuf_len(buf) < 2)
71 return SSH_ERR_MESSAGE_INCOMPLETE;
72 len_bits = PEEK_U16(d);
73 len_bytes = (len_bits + 7) >> 3;
74 if (len_bytes > SSHBUF_MAX_BIGNUM)
75 return SSH_ERR_BIGNUM_TOO_LARGE;
76 if (sshbuf_len(buf) < 2 + len_bytes)
77 return SSH_ERR_MESSAGE_INCOMPLETE;
78 if (v != NULL && BN_bin2bn(d + 2, len_bytes, v) == NULL)
79 return SSH_ERR_ALLOC_FAIL;
80 if (sshbuf_consume(buf, 2 + len_bytes) != 0) {
81 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
82 SSHBUF_ABORT();
83 return SSH_ERR_INTERNAL_ERROR;
84 }
85 return 0;
86}
87
88#ifdef OPENSSL_HAS_ECC
89static int
90get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g)
91{
92 /* Refuse overlong bignums */
93 if (len == 0 || len > SSHBUF_MAX_ECPOINT)
94 return SSH_ERR_ECPOINT_TOO_LARGE;
95 /* Only handle uncompressed points */
96 if (*d != POINT_CONVERSION_UNCOMPRESSED)
97 return SSH_ERR_INVALID_FORMAT;
98 if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1)
99 return SSH_ERR_INVALID_FORMAT; /* XXX assumption */
100 return 0;
101}
102
103int
104sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g)
105{
106 const u_char *d;
107 size_t len;
108 int r;
109
110 if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
111 return r;
112 if ((r = get_ec(d, len, v, g)) != 0)
113 return r;
114 /* Skip string */
115 if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
116 /* Shouldn't happen */
117 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
118 SSHBUF_ABORT();
119 return SSH_ERR_INTERNAL_ERROR;
120 }
121 return 0;
122}
123
124int
125sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v)
126{
127 EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v));
128 int r;
129 const u_char *d;
130 size_t len;
131
132 if (pt == NULL) {
133 SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
134 return SSH_ERR_ALLOC_FAIL;
135 }
136 if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) {
137 EC_POINT_free(pt);
138 return r;
139 }
140 if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) {
141 EC_POINT_free(pt);
142 return r;
143 }
144 if (EC_KEY_set_public_key(v, pt) != 1) {
145 EC_POINT_free(pt);
146 return SSH_ERR_ALLOC_FAIL; /* XXX assumption */
147 }
148 EC_POINT_free(pt);
149 /* Skip string */
150 if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
151 /* Shouldn't happen */
152 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
153 SSHBUF_ABORT();
154 return SSH_ERR_INTERNAL_ERROR;
155 }
156 return 0;
157}
158#endif /* OPENSSL_HAS_ECC */
159
160int
161sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v)
162{
163 u_char d[SSHBUF_MAX_BIGNUM + 1];
164 int len = BN_num_bytes(v), prepend = 0, r;
165
166 if (len < 0 || len > SSHBUF_MAX_BIGNUM)
167 return SSH_ERR_INVALID_ARGUMENT;
168 *d = '\0';
169 if (BN_bn2bin(v, d + 1) != len)
170 return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
171 /* If MSB is set, prepend a \0 */
172 if (len > 0 && (d[1] & 0x80) != 0)
173 prepend = 1;
174 if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) {
175 bzero(d, sizeof(d));
176 return r;
177 }
178 bzero(d, sizeof(d));
179 return 0;
180}
181
182int
183sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v)
184{
185 int r, len_bits = BN_num_bits(v);
186 size_t len_bytes = (len_bits + 7) / 8;
187 u_char d[SSHBUF_MAX_BIGNUM], *dp;
188
189 if (len_bits < 0 || len_bytes > SSHBUF_MAX_BIGNUM)
190 return SSH_ERR_INVALID_ARGUMENT;
191 if (BN_bn2bin(v, d) != (int)len_bytes)
192 return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
193 if ((r = sshbuf_reserve(buf, len_bytes + 2, &dp)) < 0) {
194 bzero(d, sizeof(d));
195 return r;
196 }
197 POKE_U16(dp, len_bits);
198 memcpy(dp + 2, d, len_bytes);
199 bzero(d, sizeof(d));
200 return 0;
201}
202
203#ifdef OPENSSL_HAS_ECC
204int
205sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g)
206{
207 u_char d[SSHBUF_MAX_ECPOINT];
208 BN_CTX *bn_ctx;
209 size_t len;
210 int ret;
211
212 if ((bn_ctx = BN_CTX_new()) == NULL)
213 return SSH_ERR_ALLOC_FAIL;
214 if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
215 NULL, 0, bn_ctx)) > SSHBUF_MAX_ECPOINT) {
216 BN_CTX_free(bn_ctx);
217 return SSH_ERR_INVALID_ARGUMENT;
218 }
219 if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
220 d, len, bn_ctx) != len) {
221 BN_CTX_free(bn_ctx);
222 return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
223 }
224 BN_CTX_free(bn_ctx);
225 ret = sshbuf_put_string(buf, d, len);
226 bzero(d, len);
227 return ret;
228}
229
230int
231sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
232{
233 return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v),
234 EC_KEY_get0_group(v));
235}
236#endif /* OPENSSL_HAS_ECC */
237
diff --git a/sshbuf-misc.c b/sshbuf-misc.c
new file mode 100644
index 000000000..bfeffe674
--- /dev/null
+++ b/sshbuf-misc.c
@@ -0,0 +1,135 @@
1/* $OpenBSD: sshbuf-misc.c,v 1.2 2014/06/24 01:13:21 djm Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "includes.h"
19
20#include <sys/types.h>
21#include <sys/socket.h>
22#include <netinet/in.h>
23#include <errno.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <limits.h>
27#include <string.h>
28#include <resolv.h>
29#include <ctype.h>
30
31#include "ssherr.h"
32#define SSHBUF_INTERNAL
33#include "sshbuf.h"
34
35void
36sshbuf_dump_data(const void *s, size_t len, FILE *f)
37{
38 size_t i, j;
39 const u_char *p = (const u_char *)s;
40
41 for (i = 0; i < len; i += 16) {
42 fprintf(f, "%.4zd: ", i);
43 for (j = i; j < i + 16; j++) {
44 if (j < len)
45 fprintf(f, "%02x ", p[j]);
46 else
47 fprintf(f, " ");
48 }
49 fprintf(f, " ");
50 for (j = i; j < i + 16; j++) {
51 if (j < len) {
52 if (isascii(p[j]) && isprint(p[j]))
53 fprintf(f, "%c", p[j]);
54 else
55 fprintf(f, ".");
56 }
57 }
58 fprintf(f, "\n");
59 }
60}
61
62void
63sshbuf_dump(struct sshbuf *buf, FILE *f)
64{
65 fprintf(f, "buffer %p len = %zu\n", buf, sshbuf_len(buf));
66 sshbuf_dump_data(sshbuf_ptr(buf), sshbuf_len(buf), f);
67}
68
69char *
70sshbuf_dtob16(struct sshbuf *buf)
71{
72 size_t i, j, len = sshbuf_len(buf);
73 const u_char *p = sshbuf_ptr(buf);
74 char *ret;
75 const char hex[] = "0123456789abcdef";
76
77 if (len == 0)
78 return strdup("");
79 if (SIZE_MAX / 2 <= len || (ret = malloc(len * 2 + 1)) == NULL)
80 return NULL;
81 for (i = j = 0; i < len; i++) {
82 ret[j++] = hex[(p[i] >> 4) & 0xf];
83 ret[j++] = hex[p[i] & 0xf];
84 }
85 ret[j] = '\0';
86 return ret;
87}
88
89char *
90sshbuf_dtob64(struct sshbuf *buf)
91{
92 size_t len = sshbuf_len(buf), plen;
93 const u_char *p = sshbuf_ptr(buf);
94 char *ret;
95 int r;
96
97 if (len == 0)
98 return strdup("");
99 plen = ((len + 2) / 3) * 4 + 1;
100 if (SIZE_MAX / 2 <= len || (ret = malloc(plen)) == NULL)
101 return NULL;
102 if ((r = b64_ntop(p, len, ret, plen)) == -1) {
103 bzero(ret, plen);
104 free(ret);
105 return NULL;
106 }
107 return ret;
108}
109
110int
111sshbuf_b64tod(struct sshbuf *buf, const char *b64)
112{
113 size_t plen = strlen(b64);
114 int nlen, r;
115 u_char *p;
116
117 if (plen == 0)
118 return 0;
119 if ((p = malloc(plen)) == NULL)
120 return SSH_ERR_ALLOC_FAIL;
121 if ((nlen = b64_pton(b64, p, plen)) < 0) {
122 bzero(p, plen);
123 free(p);
124 return SSH_ERR_INVALID_FORMAT;
125 }
126 if ((r = sshbuf_put(buf, p, nlen)) < 0) {
127 bzero(p, plen);
128 free(p);
129 return r;
130 }
131 bzero(p, plen);
132 free(p);
133 return 0;
134}
135
diff --git a/sshbuf.c b/sshbuf.c
new file mode 100644
index 000000000..78f5340a1
--- /dev/null
+++ b/sshbuf.c
@@ -0,0 +1,406 @@
1/* $OpenBSD: sshbuf.c,v 1.2 2014/06/25 14:16:09 deraadt Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#define SSHBUF_INTERNAL
19#include "includes.h"
20
21#include <sys/types.h>
22#include <sys/param.h>
23#include <signal.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27
28#include "ssherr.h"
29#include "sshbuf.h"
30
31static inline int
32sshbuf_check_sanity(const struct sshbuf *buf)
33{
34 SSHBUF_TELL("sanity");
35 if (__predict_false(buf == NULL ||
36 (!buf->readonly && buf->d != buf->cd) ||
37 buf->refcount < 1 || buf->refcount > SSHBUF_REFS_MAX ||
38 buf->cd == NULL ||
39 (buf->dont_free && (buf->readonly || buf->parent != NULL)) ||
40 buf->max_size > SSHBUF_SIZE_MAX ||
41 buf->alloc > buf->max_size ||
42 buf->size > buf->alloc ||
43 buf->off > buf->size)) {
44 /* Do not try to recover from corrupted buffer internals */
45 SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
46 signal(SIGSEGV, SIG_DFL);
47 raise(SIGSEGV);
48 return SSH_ERR_INTERNAL_ERROR;
49 }
50 return 0;
51}
52
53static void
54sshbuf_maybe_pack(struct sshbuf *buf, int force)
55{
56 SSHBUF_DBG(("force %d", force));
57 SSHBUF_TELL("pre-pack");
58 if (buf->off == 0 || buf->readonly || buf->refcount > 1)
59 return;
60 if (force ||
61 (buf->off >= SSHBUF_PACK_MIN && buf->off >= buf->size / 2)) {
62 memmove(buf->d, buf->d + buf->off, buf->size - buf->off);
63 buf->size -= buf->off;
64 buf->off = 0;
65 SSHBUF_TELL("packed");
66 }
67}
68
69struct sshbuf *
70sshbuf_new(void)
71{
72 struct sshbuf *ret;
73
74 if ((ret = calloc(sizeof(*ret), 1)) == NULL)
75 return NULL;
76 ret->alloc = SSHBUF_SIZE_INIT;
77 ret->max_size = SSHBUF_SIZE_MAX;
78 ret->readonly = 0;
79 ret->refcount = 1;
80 ret->parent = NULL;
81 if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL) {
82 free(ret);
83 return NULL;
84 }
85 return ret;
86}
87
88struct sshbuf *
89sshbuf_from(const void *blob, size_t len)
90{
91 struct sshbuf *ret;
92
93 if (blob == NULL || len > SSHBUF_SIZE_MAX ||
94 (ret = calloc(sizeof(*ret), 1)) == NULL)
95 return NULL;
96 ret->alloc = ret->size = ret->max_size = len;
97 ret->readonly = 1;
98 ret->refcount = 1;
99 ret->parent = NULL;
100 ret->cd = blob;
101 ret->d = NULL;
102 return ret;
103}
104
105int
106sshbuf_set_parent(struct sshbuf *child, struct sshbuf *parent)
107{
108 int r;
109
110 if ((r = sshbuf_check_sanity(child)) != 0 ||
111 (r = sshbuf_check_sanity(parent)) != 0)
112 return r;
113 child->parent = parent;
114 child->parent->refcount++;
115 return 0;
116}
117
118struct sshbuf *
119sshbuf_fromb(struct sshbuf *buf)
120{
121 struct sshbuf *ret;
122
123 if (sshbuf_check_sanity(buf) != 0)
124 return NULL;
125 if ((ret = sshbuf_from(sshbuf_ptr(buf), sshbuf_len(buf))) == NULL)
126 return NULL;
127 if (sshbuf_set_parent(ret, buf) != 0) {
128 sshbuf_free(ret);
129 return NULL;
130 }
131 return ret;
132}
133
134void
135sshbuf_init(struct sshbuf *ret)
136{
137 bzero(ret, sizeof(*ret));
138 ret->alloc = SSHBUF_SIZE_INIT;
139 ret->max_size = SSHBUF_SIZE_MAX;
140 ret->readonly = 0;
141 ret->dont_free = 1;
142 ret->refcount = 1;
143 if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL)
144 ret->alloc = 0;
145}
146
147void
148sshbuf_free(struct sshbuf *buf)
149{
150 int dont_free = 0;
151
152 if (buf == NULL)
153 return;
154 /*
155 * The following will leak on insane buffers, but this is the safest
156 * course of action - an invalid pointer or already-freed pointer may
157 * have been passed to us and continuing to scribble over memory would
158 * be bad.
159 */
160 if (sshbuf_check_sanity(buf) != 0)
161 return;
162 /*
163 * If we are a child, the free our parent to decrement its reference
164 * count and possibly free it.
165 */
166 if (buf->parent != NULL) {
167 sshbuf_free(buf->parent);
168 buf->parent = NULL;
169 }
170 /*
171 * If we are a parent with still-extant children, then don't free just
172 * yet. The last child's call to sshbuf_free should decrement our
173 * refcount to 0 and trigger the actual free.
174 */
175 buf->refcount--;
176 if (buf->refcount > 0)
177 return;
178 dont_free = buf->dont_free;
179 if (!buf->readonly) {
180 bzero(buf->d, buf->alloc);
181 free(buf->d);
182 }
183 bzero(buf, sizeof(*buf));
184 if (!dont_free)
185 free(buf);
186}
187
188void
189sshbuf_reset(struct sshbuf *buf)
190{
191 u_char *d;
192
193 if (buf->readonly || buf->refcount > 1) {
194 /* Nonsensical. Just make buffer appear empty */
195 buf->off = buf->size;
196 return;
197 }
198 if (sshbuf_check_sanity(buf) == 0)
199 bzero(buf->d, buf->alloc);
200 buf->off = buf->size = 0;
201 if (buf->alloc != SSHBUF_SIZE_INIT) {
202 if ((d = realloc(buf->d, SSHBUF_SIZE_INIT)) != NULL) {
203 buf->cd = buf->d = d;
204 buf->alloc = SSHBUF_SIZE_INIT;
205 }
206 }
207}
208
209size_t
210sshbuf_max_size(const struct sshbuf *buf)
211{
212 return buf->max_size;
213}
214
215size_t
216sshbuf_alloc(const struct sshbuf *buf)
217{
218 return buf->alloc;
219}
220
221const struct sshbuf *
222sshbuf_parent(const struct sshbuf *buf)
223{
224 return buf->parent;
225}
226
227u_int
228sshbuf_refcount(const struct sshbuf *buf)
229{
230 return buf->refcount;
231}
232
233int
234sshbuf_set_max_size(struct sshbuf *buf, size_t max_size)
235{
236 size_t rlen;
237 u_char *dp;
238 int r;
239
240 SSHBUF_DBG(("set max buf = %p len = %zu", buf, max_size));
241 if ((r = sshbuf_check_sanity(buf)) != 0)
242 return r;
243 if (max_size == buf->max_size)
244 return 0;
245 if (buf->readonly || buf->refcount > 1)
246 return SSH_ERR_BUFFER_READ_ONLY;
247 if (max_size > SSHBUF_SIZE_MAX)
248 return SSH_ERR_NO_BUFFER_SPACE;
249 /* pack and realloc if necessary */
250 sshbuf_maybe_pack(buf, max_size < buf->size);
251 if (max_size < buf->alloc && max_size > buf->size) {
252 if (buf->size < SSHBUF_SIZE_INIT)
253 rlen = SSHBUF_SIZE_INIT;
254 else
255 rlen = roundup(buf->size, SSHBUF_SIZE_INC);
256 if (rlen > max_size)
257 rlen = max_size;
258 bzero(buf->d + buf->size, buf->alloc - buf->size);
259 SSHBUF_DBG(("new alloc = %zu", rlen));
260 if ((dp = realloc(buf->d, rlen)) == NULL)
261 return SSH_ERR_ALLOC_FAIL;
262 buf->cd = buf->d = dp;
263 buf->alloc = rlen;
264 }
265 SSHBUF_TELL("new-max");
266 if (max_size < buf->alloc)
267 return SSH_ERR_NO_BUFFER_SPACE;
268 buf->max_size = max_size;
269 return 0;
270}
271
272size_t
273sshbuf_len(const struct sshbuf *buf)
274{
275 if (sshbuf_check_sanity(buf) != 0)
276 return 0;
277 return buf->size - buf->off;
278}
279
280size_t
281sshbuf_avail(const struct sshbuf *buf)
282{
283 if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1)
284 return 0;
285 return buf->max_size - (buf->size - buf->off);
286}
287
288const u_char *
289sshbuf_ptr(const struct sshbuf *buf)
290{
291 if (sshbuf_check_sanity(buf) != 0)
292 return NULL;
293 return buf->cd + buf->off;
294}
295
296u_char *
297sshbuf_mutable_ptr(const struct sshbuf *buf)
298{
299 if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1)
300 return NULL;
301 return buf->d + buf->off;
302}
303
304int
305sshbuf_check_reserve(const struct sshbuf *buf, size_t len)
306{
307 int r;
308
309 if ((r = sshbuf_check_sanity(buf)) != 0)
310 return r;
311 if (buf->readonly || buf->refcount > 1)
312 return SSH_ERR_BUFFER_READ_ONLY;
313 SSHBUF_TELL("check");
314 /* Check that len is reasonable and that max_size + available < len */
315 if (len > buf->max_size || buf->max_size - len < buf->size - buf->off)
316 return SSH_ERR_NO_BUFFER_SPACE;
317 return 0;
318}
319
320int
321sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp)
322{
323 size_t rlen, need;
324 u_char *dp;
325 int r;
326
327 if (dpp != NULL)
328 *dpp = NULL;
329
330 SSHBUF_DBG(("reserve buf = %p len = %zu", buf, len));
331 if ((r = sshbuf_check_reserve(buf, len)) != 0)
332 return r;
333 /*
334 * If the requested allocation appended would push us past max_size
335 * then pack the buffer, zeroing buf->off.
336 */
337 sshbuf_maybe_pack(buf, buf->size + len > buf->max_size);
338 SSHBUF_TELL("reserve");
339 if (len + buf->size > buf->alloc) {
340 /*
341 * Prefer to alloc in SSHBUF_SIZE_INC units, but
342 * allocate less if doing so would overflow max_size.
343 */
344 need = len + buf->size - buf->alloc;
345 rlen = roundup(buf->alloc + need, SSHBUF_SIZE_INC);
346 SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen));
347 if (rlen > buf->max_size)
348 rlen = buf->alloc + need;
349 SSHBUF_DBG(("adjusted rlen %zu", rlen));
350 if ((dp = realloc(buf->d, rlen)) == NULL) {
351 SSHBUF_DBG(("realloc fail"));
352 if (dpp != NULL)
353 *dpp = NULL;
354 return SSH_ERR_ALLOC_FAIL;
355 }
356 buf->alloc = rlen;
357 buf->cd = buf->d = dp;
358 if ((r = sshbuf_check_reserve(buf, len)) < 0) {
359 /* shouldn't fail */
360 if (dpp != NULL)
361 *dpp = NULL;
362 return r;
363 }
364 }
365 dp = buf->d + buf->size;
366 buf->size += len;
367 SSHBUF_TELL("done");
368 if (dpp != NULL)
369 *dpp = dp;
370 return 0;
371}
372
373int
374sshbuf_consume(struct sshbuf *buf, size_t len)
375{
376 int r;
377
378 SSHBUF_DBG(("len = %zu", len));
379 if ((r = sshbuf_check_sanity(buf)) != 0)
380 return r;
381 if (len == 0)
382 return 0;
383 if (len > sshbuf_len(buf))
384 return SSH_ERR_MESSAGE_INCOMPLETE;
385 buf->off += len;
386 SSHBUF_TELL("done");
387 return 0;
388}
389
390int
391sshbuf_consume_end(struct sshbuf *buf, size_t len)
392{
393 int r;
394
395 SSHBUF_DBG(("len = %zu", len));
396 if ((r = sshbuf_check_sanity(buf)) != 0)
397 return r;
398 if (len == 0)
399 return 0;
400 if (len > sshbuf_len(buf))
401 return SSH_ERR_MESSAGE_INCOMPLETE;
402 buf->size -= len;
403 SSHBUF_TELL("done");
404 return 0;
405}
406
diff --git a/sshbuf.h b/sshbuf.h
new file mode 100644
index 000000000..3602bc53f
--- /dev/null
+++ b/sshbuf.h
@@ -0,0 +1,336 @@
1/* $OpenBSD: sshbuf.h,v 1.3 2014/06/24 01:13:21 djm Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#ifndef _SSHBUF_H
19#define _SSHBUF_H
20
21#include <sys/types.h>
22#include <stdarg.h>
23#include <stdio.h>
24#ifdef WITH_OPENSSL
25# include <openssl/bn.h>
26# ifdef OPENSSL_HAS_ECC
27# include <openssl/ec.h>
28# endif /* OPENSSL_HAS_ECC */
29#endif /* WITH_OPENSSL */
30
31#define SSHBUF_SIZE_MAX 0x8000000 /* Hard maximum size */
32#define SSHBUF_REFS_MAX 0x100000 /* Max child buffers */
33#define SSHBUF_MAX_BIGNUM (16384 / 8) /* Max bignum *bytes* */
34#define SSHBUF_MAX_ECPOINT ((528 * 2 / 8) + 1) /* Max EC point *bytes* */
35
36/*
37 * NB. do not depend on the internals of this. It will be made opaque
38 * one day.
39 */
40struct sshbuf {
41 u_char *d; /* Data */
42 const u_char *cd; /* Const data */
43 size_t off; /* First available byte is buf->d + buf->off */
44 size_t size; /* Last byte is buf->d + buf->size - 1 */
45 size_t max_size; /* Maximum size of buffer */
46 size_t alloc; /* Total bytes allocated to buf->d */
47 int readonly; /* Refers to external, const data */
48 int dont_free; /* Kludge to support sshbuf_init */
49 u_int refcount; /* Tracks self and number of child buffers */
50 struct sshbuf *parent; /* If child, pointer to parent */
51};
52
53#ifndef SSHBUF_NO_DEPREACTED
54/*
55 * NB. Please do not use sshbuf_init() in new code. Please use sshbuf_new()
56 * instead. sshbuf_init() is deprectated and will go away soon (it is
57 * only included to allow compat with buffer_* in OpenSSH)
58 */
59void sshbuf_init(struct sshbuf *buf);
60#endif
61
62/*
63 * Create a new sshbuf buffer.
64 * Returns pointer to buffer on success, or NULL on allocation failure.
65 */
66struct sshbuf *sshbuf_new(void);
67
68/*
69 * Create a new, read-only sshbuf buffer from existing data.
70 * Returns pointer to buffer on success, or NULL on allocation failure.
71 */
72struct sshbuf *sshbuf_from(const void *blob, size_t len);
73
74/*
75 * Create a new, read-only sshbuf buffer from the contents of an existing
76 * buffer. The contents of "buf" must not change in the lifetime of the
77 * resultant buffer.
78 * Returns pointer to buffer on success, or NULL on allocation failure.
79 */
80struct sshbuf *sshbuf_fromb(struct sshbuf *buf);
81
82/*
83 * Create a new, read-only sshbuf buffer from the contents of a string in
84 * an existing buffer (the string is consumed in the process).
85 * The contents of "buf" must not change in the lifetime of the resultant
86 * buffer.
87 * Returns pointer to buffer on success, or NULL on allocation failure.
88 */
89int sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp);
90
91/*
92 * Clear and free buf
93 */
94void sshbuf_free(struct sshbuf *buf);
95
96/*
97 * Reset buf, clearing its contents. NB. max_size is preserved.
98 */
99void sshbuf_reset(struct sshbuf *buf);
100
101/*
102 * Return the maximum size of buf
103 */
104size_t sshbuf_max_size(const struct sshbuf *buf);
105
106/*
107 * Set the maximum size of buf
108 * Returns 0 on success, or a negative SSH_ERR_* error code on failure.
109 */
110int sshbuf_set_max_size(struct sshbuf *buf, size_t max_size);
111
112/*
113 * Returns the length of data in buf
114 */
115size_t sshbuf_len(const struct sshbuf *buf);
116
117/*
118 * Returns number of bytes left in buffer before hitting max_size.
119 */
120size_t sshbuf_avail(const struct sshbuf *buf);
121
122/*
123 * Returns a read-only pointer to the start of the the data in buf
124 */
125const u_char *sshbuf_ptr(const struct sshbuf *buf);
126
127/*
128 * Returns a mutable pointer to the start of the the data in buf, or
129 * NULL if the buffer is read-only.
130 */
131u_char *sshbuf_mutable_ptr(const struct sshbuf *buf);
132
133/*
134 * Check whether a reservation of size len will succeed in buf
135 * Safer to use than direct comparisons again sshbuf_avail as it copes
136 * with unsigned overflows correctly.
137 * Returns 0 on success, or a negative SSH_ERR_* error code on failure.
138 */
139int sshbuf_check_reserve(const struct sshbuf *buf, size_t len);
140
141/*
142 * Reserve len bytes in buf.
143 * Returns 0 on success and a pointer to the first reserved byte via the
144 * optional dpp parameter or a negative * SSH_ERR_* error code on failure.
145 */
146int sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp);
147
148/*
149 * Consume len bytes from the start of buf
150 * Returns 0 on success, or a negative SSH_ERR_* error code on failure.
151 */
152int sshbuf_consume(struct sshbuf *buf, size_t len);
153
154/*
155 * Consume len bytes from the end of buf
156 * Returns 0 on success, or a negative SSH_ERR_* error code on failure.
157 */
158int sshbuf_consume_end(struct sshbuf *buf, size_t len);
159
160/* Extract or deposit some bytes */
161int sshbuf_get(struct sshbuf *buf, void *v, size_t len);
162int sshbuf_put(struct sshbuf *buf, const void *v, size_t len);
163int sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v);
164
165/* Append using a printf(3) format */
166int sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
167 __attribute__((format(printf, 2, 3)));
168int sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap);
169
170/* Functions to extract or store big-endian words of various sizes */
171int sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp);
172int sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp);
173int sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp);
174int sshbuf_get_u8(struct sshbuf *buf, u_char *valp);
175int sshbuf_put_u64(struct sshbuf *buf, u_int64_t val);
176int sshbuf_put_u32(struct sshbuf *buf, u_int32_t val);
177int sshbuf_put_u16(struct sshbuf *buf, u_int16_t val);
178int sshbuf_put_u8(struct sshbuf *buf, u_char val);
179
180/*
181 * Functions to extract or store SSH wire encoded strings (u32 len || data)
182 * The "cstring" variants admit no \0 characters in the string contents.
183 * Caller must free *valp.
184 */
185int sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp);
186int sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp);
187int sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v);
188int sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len);
189int sshbuf_put_cstring(struct sshbuf *buf, const char *v);
190int sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v);
191
192/*
193 * "Direct" variant of sshbuf_get_string, returns pointer into the sshbuf to
194 * avoid an malloc+memcpy. The pointer is guaranteed to be valid until the
195 * next sshbuf-modifying function call. Caller does not free.
196 */
197int sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp,
198 size_t *lenp);
199
200/* Skip past a string */
201#define sshbuf_skip_string(buf) sshbuf_get_string_direct(buf, NULL, NULL)
202
203/* Another variant: "peeks" into the buffer without modifying it */
204int sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
205 size_t *lenp);
206
207/*
208 * Functions to extract or store SSH wire encoded bignums and elliptic
209 * curve points.
210 */
211int sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len);
212#ifdef WITH_OPENSSL
213int sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v);
214int sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v);
215int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v);
216int sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v);
217# ifdef OPENSSL_HAS_ECC
218int sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g);
219int sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v);
220int sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g);
221int sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v);
222# endif /* OPENSSL_HAS_ECC */
223#endif /* WITH_OPENSSL */
224
225/* Dump the contents of the buffer in a human-readable format */
226void sshbuf_dump(struct sshbuf *buf, FILE *f);
227
228/* Dump specified memory in a human-readable format */
229void sshbuf_dump_data(const void *s, size_t len, FILE *f);
230
231/* Return the hexadecimal representation of the contents of the buffer */
232char *sshbuf_dtob16(struct sshbuf *buf);
233
234/* Encode the contents of the buffer as base64 */
235char *sshbuf_dtob64(struct sshbuf *buf);
236
237/* Decode base64 data and append it to the buffer */
238int sshbuf_b64tod(struct sshbuf *buf, const char *b64);
239
240/* Macros for decoding/encoding integers */
241#define PEEK_U64(p) \
242 (((u_int64_t)(((u_char *)(p))[0]) << 56) | \
243 ((u_int64_t)(((u_char *)(p))[1]) << 48) | \
244 ((u_int64_t)(((u_char *)(p))[2]) << 40) | \
245 ((u_int64_t)(((u_char *)(p))[3]) << 32) | \
246 ((u_int64_t)(((u_char *)(p))[4]) << 24) | \
247 ((u_int64_t)(((u_char *)(p))[5]) << 16) | \
248 ((u_int64_t)(((u_char *)(p))[6]) << 8) | \
249 (u_int64_t)(((u_char *)(p))[7]))
250#define PEEK_U32(p) \
251 (((u_int32_t)(((u_char *)(p))[0]) << 24) | \
252 ((u_int32_t)(((u_char *)(p))[1]) << 16) | \
253 ((u_int32_t)(((u_char *)(p))[2]) << 8) | \
254 (u_int32_t)(((u_char *)(p))[3]))
255#define PEEK_U16(p) \
256 (((u_int16_t)(((u_char *)(p))[0]) << 8) | \
257 (u_int16_t)(((u_char *)(p))[1]))
258
259#define POKE_U64(p, v) \
260 do { \
261 ((u_char *)(p))[0] = (((u_int64_t)(v)) >> 56) & 0xff; \
262 ((u_char *)(p))[1] = (((u_int64_t)(v)) >> 48) & 0xff; \
263 ((u_char *)(p))[2] = (((u_int64_t)(v)) >> 40) & 0xff; \
264 ((u_char *)(p))[3] = (((u_int64_t)(v)) >> 32) & 0xff; \
265 ((u_char *)(p))[4] = (((u_int64_t)(v)) >> 24) & 0xff; \
266 ((u_char *)(p))[5] = (((u_int64_t)(v)) >> 16) & 0xff; \
267 ((u_char *)(p))[6] = (((u_int64_t)(v)) >> 8) & 0xff; \
268 ((u_char *)(p))[7] = ((u_int64_t)(v)) & 0xff; \
269 } while (0)
270#define POKE_U32(p, v) \
271 do { \
272 ((u_char *)(p))[0] = (((u_int64_t)(v)) >> 24) & 0xff; \
273 ((u_char *)(p))[1] = (((u_int64_t)(v)) >> 16) & 0xff; \
274 ((u_char *)(p))[2] = (((u_int64_t)(v)) >> 8) & 0xff; \
275 ((u_char *)(p))[3] = ((u_int64_t)(v)) & 0xff; \
276 } while (0)
277#define POKE_U16(p, v) \
278 do { \
279 ((u_char *)(p))[0] = (((u_int64_t)(v)) >> 8) & 0xff; \
280 ((u_char *)(p))[1] = ((u_int64_t)(v)) & 0xff; \
281 } while (0)
282
283/* Internal definitions follow. Exposed for regress tests */
284#ifdef SSHBUF_INTERNAL
285
286/*
287 * Return the allocation size of buf
288 */
289size_t sshbuf_alloc(const struct sshbuf *buf);
290
291/*
292 * Increment the reference count of buf.
293 */
294int sshbuf_set_parent(struct sshbuf *child, struct sshbuf *parent);
295
296/*
297 * Return the parent buffer of buf, or NULL if it has no parent.
298 */
299const struct sshbuf *sshbuf_parent(const struct sshbuf *buf);
300
301/*
302 * Return the reference count of buf
303 */
304u_int sshbuf_refcount(const struct sshbuf *buf);
305
306# define SSHBUF_SIZE_INIT 256 /* Initial allocation */
307# define SSHBUF_SIZE_INC 256 /* Preferred increment length */
308# define SSHBUF_PACK_MIN 8192 /* Minimim packable offset */
309
310/* # define SSHBUF_ABORT abort */
311/* # define SSHBUF_DEBUG */
312
313# ifndef SSHBUF_ABORT
314# define SSHBUF_ABORT()
315# endif
316
317# ifdef SSHBUF_DEBUG
318# define SSHBUF_TELL(what) do { \
319 printf("%s:%d %s: %s size %zu alloc %zu off %zu max %zu\n", \
320 __FILE__, __LINE__, __func__, what, \
321 buf->size, buf->alloc, buf->off, buf->max_size); \
322 fflush(stdout); \
323 } while (0)
324# define SSHBUF_DBG(x) do { \
325 printf("%s:%d %s: ", __FILE__, __LINE__, __func__); \
326 printf x; \
327 printf("\n"); \
328 fflush(stdout); \
329 } while (0)
330# else
331# define SSHBUF_TELL(what)
332# define SSHBUF_DBG(x)
333# endif
334#endif /* SSHBUF_INTERNAL */
335
336#endif /* _SSHBUF_H */
diff --git a/sshconnect.c b/sshconnect.c
index 573d7a8e8..ac09eae67 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.246 2014/02/06 22:21:01 djm Exp $ */ 1/* $OpenBSD: sshconnect.c,v 1.251 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -54,9 +54,9 @@
54#include "sshconnect.h" 54#include "sshconnect.h"
55#include "hostfile.h" 55#include "hostfile.h"
56#include "log.h" 56#include "log.h"
57#include "misc.h"
57#include "readconf.h" 58#include "readconf.h"
58#include "atomicio.h" 59#include "atomicio.h"
59#include "misc.h"
60#include "dns.h" 60#include "dns.h"
61#include "roaming.h" 61#include "roaming.h"
62#include "monitor_fdpass.h" 62#include "monitor_fdpass.h"
@@ -65,6 +65,7 @@
65 65
66char *client_version_string = NULL; 66char *client_version_string = NULL;
67char *server_version_string = NULL; 67char *server_version_string = NULL;
68Key *previous_host_key = NULL;
68 69
69static int matching_host_key_dns = 0; 70static int matching_host_key_dns = 0;
70 71
@@ -709,7 +710,7 @@ check_host_cert(const char *host, const Key *host_key)
709 error("%s", reason); 710 error("%s", reason);
710 return 0; 711 return 0;
711 } 712 }
712 if (buffer_len(&host_key->cert->critical) != 0) { 713 if (buffer_len(host_key->cert->critical) != 0) {
713 error("Certificate for %s contains unsupported " 714 error("Certificate for %s contains unsupported "
714 "critical options(s)", host); 715 "critical options(s)", host);
715 return 0; 716 return 0;
@@ -1217,36 +1218,60 @@ fail:
1217int 1218int
1218verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) 1219verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
1219{ 1220{
1220 int flags = 0; 1221 int r = -1, flags = 0;
1221 char *fp; 1222 char *fp;
1223 Key *plain = NULL;
1222 1224
1223 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 1225 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
1224 debug("Server host key: %s %s", key_type(host_key), fp); 1226 debug("Server host key: %s %s", key_type(host_key), fp);
1225 free(fp); 1227 free(fp);
1226 1228
1227 /* XXX certs are not yet supported for DNS */ 1229 if (key_equal(previous_host_key, host_key)) {
1228 if (!key_is_cert(host_key) && options.verify_host_key_dns && 1230 debug("%s: server host key matches cached key", __func__);
1229 verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { 1231 return 0;
1230 if (flags & DNS_VERIFY_FOUND) { 1232 }
1231
1232 if (options.verify_host_key_dns == 1 &&
1233 flags & DNS_VERIFY_MATCH &&
1234 flags & DNS_VERIFY_SECURE)
1235 return 0;
1236 1233
1237 if (flags & DNS_VERIFY_MATCH) { 1234 if (options.verify_host_key_dns) {
1238 matching_host_key_dns = 1; 1235 /*
1239 } else { 1236 * XXX certs are not yet supported for DNS, so downgrade
1240 warn_changed_key(host_key); 1237 * them and try the plain key.
1241 error("Update the SSHFP RR in DNS with the new " 1238 */
1242 "host key to get rid of this message."); 1239 plain = key_from_private(host_key);
1240 if (key_is_cert(plain))
1241 key_drop_cert(plain);
1242 if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) {
1243 if (flags & DNS_VERIFY_FOUND) {
1244 if (options.verify_host_key_dns == 1 &&
1245 flags & DNS_VERIFY_MATCH &&
1246 flags & DNS_VERIFY_SECURE) {
1247 key_free(plain);
1248 r = 0;
1249 goto done;
1250 }
1251 if (flags & DNS_VERIFY_MATCH) {
1252 matching_host_key_dns = 1;
1253 } else {
1254 warn_changed_key(plain);
1255 error("Update the SSHFP RR in DNS "
1256 "with the new host key to get rid "
1257 "of this message.");
1258 }
1243 } 1259 }
1244 } 1260 }
1261 key_free(plain);
1245 } 1262 }
1246 1263
1247 return check_host_key(host, hostaddr, options.port, host_key, RDRW, 1264 r = check_host_key(host, hostaddr, options.port, host_key, RDRW,
1248 options.user_hostfiles, options.num_user_hostfiles, 1265 options.user_hostfiles, options.num_user_hostfiles,
1249 options.system_hostfiles, options.num_system_hostfiles); 1266 options.system_hostfiles, options.num_system_hostfiles);
1267
1268done:
1269 if (r == 0 && host_key != NULL) {
1270 key_free(previous_host_key);
1271 previous_host_key = key_from_private(host_key);
1272 }
1273
1274 return r;
1250} 1275}
1251 1276
1252/* 1277/*
@@ -1282,8 +1307,12 @@ ssh_login(Sensitive *sensitive, const char *orighost,
1282 ssh_kex2(host, hostaddr, port); 1307 ssh_kex2(host, hostaddr, port);
1283 ssh_userauth2(local_user, server_user, host, sensitive); 1308 ssh_userauth2(local_user, server_user, host, sensitive);
1284 } else { 1309 } else {
1310#ifdef WITH_SSH1
1285 ssh_kex(host, hostaddr); 1311 ssh_kex(host, hostaddr);
1286 ssh_userauth1(local_user, server_user, host, sensitive); 1312 ssh_userauth1(local_user, server_user, host, sensitive);
1313#else
1314 fatal("ssh1 is not unsupported");
1315#endif
1287 } 1316 }
1288 free(local_user); 1317 free(local_user);
1289} 1318}
diff --git a/sshconnect1.c b/sshconnect1.c
index 921408ec1..dd12a3af2 100644
--- a/sshconnect1.c
+++ b/sshconnect1.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect1.c,v 1.74 2014/02/02 03:44:32 djm Exp $ */ 1/* $OpenBSD: sshconnect1.c,v 1.76 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -38,11 +38,11 @@
38#include "kex.h" 38#include "kex.h"
39#include "uidswap.h" 39#include "uidswap.h"
40#include "log.h" 40#include "log.h"
41#include "misc.h"
41#include "readconf.h" 42#include "readconf.h"
42#include "authfd.h" 43#include "authfd.h"
43#include "sshconnect.h" 44#include "sshconnect.h"
44#include "authfile.h" 45#include "authfile.h"
45#include "misc.h"
46#include "canohost.h" 46#include "canohost.h"
47#include "hostfile.h" 47#include "hostfile.h"
48#include "auth.h" 48#include "auth.h"
@@ -166,7 +166,7 @@ respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
166 166
167 /* Decrypt the challenge using the private key. */ 167 /* Decrypt the challenge using the private key. */
168 /* XXX think about Bleichenbacher, too */ 168 /* XXX think about Bleichenbacher, too */
169 if (rsa_private_decrypt(challenge, challenge, prv) <= 0) 169 if (rsa_private_decrypt(challenge, challenge, prv) != 0)
170 packet_disconnect( 170 packet_disconnect(
171 "respond_to_rsa_challenge: rsa_private_decrypt failed"); 171 "respond_to_rsa_challenge: rsa_private_decrypt failed");
172 172
@@ -253,7 +253,7 @@ try_rsa_authentication(int idx)
253 * load the private key. Try first with empty passphrase; if it 253 * load the private key. Try first with empty passphrase; if it
254 * fails, ask for a passphrase. 254 * fails, ask for a passphrase.
255 */ 255 */
256 if (public->flags & KEY_FLAG_EXT) 256 if (public->flags & SSHKEY_FLAG_EXT)
257 private = public; 257 private = public;
258 else 258 else
259 private = key_load_private_type(KEY_RSA1, authfile, "", NULL, 259 private = key_load_private_type(KEY_RSA1, authfile, "", NULL,
@@ -302,7 +302,7 @@ try_rsa_authentication(int idx)
302 respond_to_rsa_challenge(challenge, private->rsa); 302 respond_to_rsa_challenge(challenge, private->rsa);
303 303
304 /* Destroy the private key unless it in external hardware. */ 304 /* Destroy the private key unless it in external hardware. */
305 if (!(private->flags & KEY_FLAG_EXT)) 305 if (!(private->flags & SSHKEY_FLAG_EXT))
306 key_free(private); 306 key_free(private);
307 307
308 /* We no longer need the challenge. */ 308 /* We no longer need the challenge. */
@@ -592,8 +592,9 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
592 BN_num_bits(server_key->rsa->n), 592 BN_num_bits(server_key->rsa->n),
593 SSH_KEY_BITS_RESERVED); 593 SSH_KEY_BITS_RESERVED);
594 } 594 }
595 rsa_public_encrypt(key, key, server_key->rsa); 595 if (rsa_public_encrypt(key, key, server_key->rsa) != 0 ||
596 rsa_public_encrypt(key, key, host_key->rsa); 596 rsa_public_encrypt(key, key, host_key->rsa) != 0)
597 fatal("%s: rsa_public_encrypt failed", __func__);
597 } else { 598 } else {
598 /* Host key has smaller modulus (or they are equal). */ 599 /* Host key has smaller modulus (or they are equal). */
599 if (BN_num_bits(server_key->rsa->n) < 600 if (BN_num_bits(server_key->rsa->n) <
@@ -604,8 +605,9 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
604 BN_num_bits(host_key->rsa->n), 605 BN_num_bits(host_key->rsa->n),
605 SSH_KEY_BITS_RESERVED); 606 SSH_KEY_BITS_RESERVED);
606 } 607 }
607 rsa_public_encrypt(key, key, host_key->rsa); 608 if (rsa_public_encrypt(key, key, host_key->rsa) != 0 ||
608 rsa_public_encrypt(key, key, server_key->rsa); 609 rsa_public_encrypt(key, key, server_key->rsa) != 0)
610 fatal("%s: rsa_public_encrypt failed", __func__);
609 } 611 }
610 612
611 /* Destroy the public keys since we no longer need them. */ 613 /* Destroy the public keys since we no longer need them. */
diff --git a/sshconnect2.c b/sshconnect2.c
index 7f4ff4189..68f7f4fdd 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect2.c,v 1.204 2014/02/02 03:44:32 djm Exp $ */ 1/* $OpenBSD: sshconnect2.c,v 1.210 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Copyright (c) 2008 Damien Miller. All rights reserved. 4 * Copyright (c) 2008 Damien Miller. All rights reserved.
@@ -61,8 +61,8 @@
61#include "dh.h" 61#include "dh.h"
62#include "authfd.h" 62#include "authfd.h"
63#include "log.h" 63#include "log.h"
64#include "readconf.h"
65#include "misc.h" 64#include "misc.h"
65#include "readconf.h"
66#include "match.h" 66#include "match.h"
67#include "dispatch.h" 67#include "dispatch.h"
68#include "canohost.h" 68#include "canohost.h"
@@ -156,6 +156,7 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
156void 156void
157ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) 157ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
158{ 158{
159 char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
159 Kex *kex; 160 Kex *kex;
160 161
161 xxx_host = host; 162 xxx_host = host;
@@ -195,6 +196,8 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
195 } 196 }
196 if (options.kex_algorithms != NULL) 197 if (options.kex_algorithms != NULL)
197 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; 198 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
199 myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
200 myproposal[PROPOSAL_KEX_ALGS]);
198 201
199 if (options.rekey_limit || options.rekey_interval) 202 if (options.rekey_limit || options.rekey_interval)
200 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 203 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
@@ -202,11 +205,13 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
202 205
203 /* start key exchange */ 206 /* start key exchange */
204 kex = kex_setup(myproposal); 207 kex = kex_setup(myproposal);
208#ifdef WITH_OPENSSL
205 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; 209 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
206 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; 210 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
207 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 211 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
208 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 212 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
209 kex->kex[KEX_ECDH_SHA2] = kexecdh_client; 213 kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
214#endif
210 kex->kex[KEX_C25519_SHA256] = kexc25519_client; 215 kex->kex[KEX_C25519_SHA256] = kexc25519_client;
211 kex->client_version_string=client_version_string; 216 kex->client_version_string=client_version_string;
212 kex->server_version_string=server_version_string; 217 kex->server_version_string=server_version_string;
@@ -965,7 +970,7 @@ identity_sign(Identity *id, u_char **sigp, u_int *lenp,
965 * we have already loaded the private key or 970 * we have already loaded the private key or
966 * the private key is stored in external hardware 971 * the private key is stored in external hardware
967 */ 972 */
968 if (id->isprivate || (id->key->flags & KEY_FLAG_EXT)) 973 if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))
969 return (key_sign(id->key, sigp, lenp, data, datalen)); 974 return (key_sign(id->key, sigp, lenp, data, datalen));
970 /* load the private key from the file */ 975 /* load the private key from the file */
971 if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL) 976 if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL)
@@ -1173,12 +1178,12 @@ pubkey_prepare(Authctxt *authctxt)
1173 } 1178 }
1174 /* Prefer PKCS11 keys that are explicitly listed */ 1179 /* Prefer PKCS11 keys that are explicitly listed */
1175 TAILQ_FOREACH_SAFE(id, &files, next, tmp) { 1180 TAILQ_FOREACH_SAFE(id, &files, next, tmp) {
1176 if (id->key == NULL || (id->key->flags & KEY_FLAG_EXT) == 0) 1181 if (id->key == NULL || (id->key->flags & SSHKEY_FLAG_EXT) == 0)
1177 continue; 1182 continue;
1178 found = 0; 1183 found = 0;
1179 TAILQ_FOREACH(id2, &files, next) { 1184 TAILQ_FOREACH(id2, &files, next) {
1180 if (id2->key == NULL || 1185 if (id2->key == NULL ||
1181 (id2->key->flags & KEY_FLAG_EXT) != 0) 1186 (id2->key->flags & SSHKEY_FLAG_EXT) == 0)
1182 continue; 1187 continue;
1183 if (key_equal(id->key, id2->key)) { 1188 if (key_equal(id->key, id2->key)) {
1184 TAILQ_REMOVE(&files, id, next); 1189 TAILQ_REMOVE(&files, id, next);
diff --git a/sshd.0 b/sshd.0
index c61d51535..3008e01bd 100644
--- a/sshd.0
+++ b/sshd.0
@@ -1,4 +1,4 @@
1SSHD(8) OpenBSD System Manager's Manual SSHD(8) 1SSHD(8) System Manager's Manual SSHD(8)
2 2
3NAME 3NAME
4 sshd - OpenSSH SSH daemon 4 sshd - OpenSSH SSH daemon
@@ -11,7 +11,7 @@ SYNOPSIS
11 11
12DESCRIPTION 12DESCRIPTION
13 sshd (OpenSSH Daemon) is the daemon program for ssh(1). Together these 13 sshd (OpenSSH Daemon) is the daemon program for ssh(1). Together these
14 programs replace rlogin(1) and rsh(1), and provide secure encrypted 14 programs replace rlogin and rsh, and provide secure encrypted
15 communications between two untrusted hosts over an insecure network. 15 communications between two untrusted hosts over an insecure network.
16 16
17 sshd listens for connections from clients. It is normally started at 17 sshd listens for connections from clients. It is normally started at
@@ -228,9 +228,10 @@ LOGIN PROCESS
228 228
229 7. Changes to user's home directory. 229 7. Changes to user's home directory.
230 230
231 8. If ~/.ssh/rc exists, runs it; else if /etc/ssh/sshrc exists, 231 8. If ~/.ssh/rc exists and the sshd_config(5) PermitUserRC option
232 runs it; otherwise runs xauth. The ``rc'' files are given the 232 is set, runs it; else if /etc/ssh/sshrc exists, runs it;
233 X11 authentication protocol and cookie in standard input. See 233 otherwise runs xauth. The ``rc'' files are given the X11
234 authentication protocol and cookie in standard input. See
234 SSHRC, below. 235 SSHRC, below.
235 236
236 9. Runs user's shell or command. 237 9. Runs user's shell or command.
@@ -545,11 +546,6 @@ FILES
545 directory becomes accessible. This file should be writable only 546 directory becomes accessible. This file should be writable only
546 by the user, and need not be readable by anyone else. 547 by the user, and need not be readable by anyone else.
547 548
548 /etc/hosts.allow
549 /etc/hosts.deny
550 Access controls that should be enforced by tcp-wrappers are
551 defined here. Further details are described in hosts_access(5).
552
553 /etc/hosts.equiv 549 /etc/hosts.equiv
554 This file is for host-based authentication (see ssh(1)). It 550 This file is for host-based authentication (see ssh(1)). It
555 should only be writable by root. 551 should only be writable by root.
@@ -625,8 +621,8 @@ FILES
625 621
626SEE ALSO 622SEE ALSO
627 scp(1), sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), 623 scp(1), sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1),
628 ssh-keyscan(1), chroot(2), hosts_access(5), login.conf(5), moduli(5), 624 ssh-keyscan(1), chroot(2), login.conf(5), moduli(5), sshd_config(5),
629 sshd_config(5), inetd(8), sftp-server(8) 625 inetd(8), sftp-server(8)
630 626
631AUTHORS 627AUTHORS
632 OpenSSH is a derivative of the original and free ssh 1.2.12 release by 628 OpenSSH is a derivative of the original and free ssh 1.2.12 release by
@@ -636,8 +632,4 @@ AUTHORS
636 versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support 632 versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support
637 for privilege separation. 633 for privilege separation.
638 634
639CAVEATS 635OpenBSD 5.6 July 3, 2014 OpenBSD 5.6
640 System security is not improved unless rshd, rlogind, and rexecd are
641 disabled (thus completely disabling rlogin and rsh into the machine).
642
643OpenBSD 5.5 December 7, 2013 OpenBSD 5.5
diff --git a/sshd.8 b/sshd.8
index e6a900b06..01459d637 100644
--- a/sshd.8
+++ b/sshd.8
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: sshd.8,v 1.273 2013/12/07 11:58:46 naddy Exp $ 36.\" $OpenBSD: sshd.8,v 1.276 2014/07/03 22:40:43 djm Exp $
37.Dd $Mdocdate: December 7 2013 $ 37.Dd $Mdocdate: July 3 2014 $
38.Dt SSHD 8 38.Dt SSHD 8
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -60,10 +60,7 @@
60.Nm 60.Nm
61(OpenSSH Daemon) is the daemon program for 61(OpenSSH Daemon) is the daemon program for
62.Xr ssh 1 . 62.Xr ssh 1 .
63Together these programs replace 63Together these programs replace rlogin and rsh,
64.Xr rlogin 1
65and
66.Xr rsh 1 ,
67and provide secure encrypted communications between two untrusted hosts 64and provide secure encrypted communications between two untrusted hosts
68over an insecure network. 65over an insecure network.
69.Pp 66.Pp
@@ -411,7 +408,10 @@ Changes to user's home directory.
411.It 408.It
412If 409If
413.Pa ~/.ssh/rc 410.Pa ~/.ssh/rc
414exists, runs it; else if 411exists and the
412.Xr sshd_config 5
413.Cm PermitUserRC
414option is set, runs it; else if
415.Pa /etc/ssh/sshrc 415.Pa /etc/ssh/sshrc
416exists, runs 416exists, runs
417it; otherwise runs xauth. 417it; otherwise runs xauth.
@@ -851,12 +851,6 @@ the user's home directory becomes accessible.
851This file should be writable only by the user, and need not be 851This file should be writable only by the user, and need not be
852readable by anyone else. 852readable by anyone else.
853.Pp 853.Pp
854.It Pa /etc/hosts.allow
855.It Pa /etc/hosts.deny
856Access controls that should be enforced by tcp-wrappers are defined here.
857Further details are described in
858.Xr hosts_access 5 .
859.Pp
860.It Pa /etc/hosts.equiv 854.It Pa /etc/hosts.equiv
861This file is for host-based authentication (see 855This file is for host-based authentication (see
862.Xr ssh 1 ) . 856.Xr ssh 1 ) .
@@ -960,7 +954,6 @@ The content of this file is not sensitive; it can be world-readable.
960.Xr ssh-keygen 1 , 954.Xr ssh-keygen 1 ,
961.Xr ssh-keyscan 1 , 955.Xr ssh-keyscan 1 ,
962.Xr chroot 2 , 956.Xr chroot 2 ,
963.Xr hosts_access 5 ,
964.Xr login.conf 5 , 957.Xr login.conf 5 ,
965.Xr moduli 5 , 958.Xr moduli 5 ,
966.Xr sshd_config 5 , 959.Xr sshd_config 5 ,
@@ -977,14 +970,3 @@ Markus Friedl contributed the support for SSH
977protocol versions 1.5 and 2.0. 970protocol versions 1.5 and 2.0.
978Niels Provos and Markus Friedl contributed support 971Niels Provos and Markus Friedl contributed support
979for privilege separation. 972for privilege separation.
980.Sh CAVEATS
981System security is not improved unless
982.Nm rshd ,
983.Nm rlogind ,
984and
985.Nm rexecd
986are disabled (thus completely disabling
987.Xr rlogin
988and
989.Xr rsh
990into the machine).
diff --git a/sshd.c b/sshd.c
index 7523de977..481d00155 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshd.c,v 1.420 2014/02/26 21:53:37 markus Exp $ */ 1/* $OpenBSD: sshd.c,v 1.428 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -72,10 +72,12 @@
72#include <string.h> 72#include <string.h>
73#include <unistd.h> 73#include <unistd.h>
74 74
75#ifdef WITH_OPENSSL
75#include <openssl/dh.h> 76#include <openssl/dh.h>
76#include <openssl/bn.h> 77#include <openssl/bn.h>
77#include <openssl/rand.h> 78#include <openssl/rand.h>
78#include "openbsd-compat/openssl-compat.h" 79#include "openbsd-compat/openssl-compat.h"
80#endif
79 81
80#ifdef HAVE_SECUREWARE 82#ifdef HAVE_SECUREWARE
81#include <sys/security.h> 83#include <sys/security.h>
@@ -91,6 +93,7 @@
91#include "packet.h" 93#include "packet.h"
92#include "log.h" 94#include "log.h"
93#include "buffer.h" 95#include "buffer.h"
96#include "misc.h"
94#include "servconf.h" 97#include "servconf.h"
95#include "uidswap.h" 98#include "uidswap.h"
96#include "compat.h" 99#include "compat.h"
@@ -98,7 +101,6 @@
98#include "digest.h" 101#include "digest.h"
99#include "key.h" 102#include "key.h"
100#include "kex.h" 103#include "kex.h"
101#include "dh.h"
102#include "myproposal.h" 104#include "myproposal.h"
103#include "authfile.h" 105#include "authfile.h"
104#include "pathnames.h" 106#include "pathnames.h"
@@ -107,7 +109,6 @@
107#include "hostfile.h" 109#include "hostfile.h"
108#include "auth.h" 110#include "auth.h"
109#include "authfd.h" 111#include "authfd.h"
110#include "misc.h"
111#include "msg.h" 112#include "msg.h"
112#include "dispatch.h" 113#include "dispatch.h"
113#include "channels.h" 114#include "channels.h"
@@ -122,13 +123,6 @@
122#include "ssh-sandbox.h" 123#include "ssh-sandbox.h"
123#include "version.h" 124#include "version.h"
124 125
125#ifdef LIBWRAP
126#include <tcpd.h>
127#include <syslog.h>
128int allow_severity;
129int deny_severity;
130#endif /* LIBWRAP */
131
132#ifndef O_NOCTTY 126#ifndef O_NOCTTY
133#define O_NOCTTY 0 127#define O_NOCTTY 0
134#endif 128#endif
@@ -263,7 +257,9 @@ struct passwd *privsep_pw = NULL;
263void destroy_sensitive_data(void); 257void destroy_sensitive_data(void);
264void demote_sensitive_data(void); 258void demote_sensitive_data(void);
265 259
260#ifdef WITH_SSH1
266static void do_ssh1_kex(void); 261static void do_ssh1_kex(void);
262#endif
267static void do_ssh2_kex(void); 263static void do_ssh2_kex(void);
268 264
269/* 265/*
@@ -938,7 +934,13 @@ static void
938usage(void) 934usage(void)
939{ 935{
940 fprintf(stderr, "%s, %s\n", 936 fprintf(stderr, "%s, %s\n",
941 SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); 937 SSH_RELEASE,
938#ifdef WITH_OPENSSL
939 SSLeay_version(SSLEAY_VERSION)
940#else
941 "without OpenSSL"
942#endif
943 );
942 fprintf(stderr, 944 fprintf(stderr,
943"usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_cert_file]\n" 945"usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_cert_file]\n"
944" [-E log_file] [-f config_file] [-g login_grace_time]\n" 946" [-E log_file] [-f config_file] [-g login_grace_time]\n"
@@ -971,6 +973,7 @@ send_rexec_state(int fd, Buffer *conf)
971 buffer_init(&m); 973 buffer_init(&m);
972 buffer_put_cstring(&m, buffer_ptr(conf)); 974 buffer_put_cstring(&m, buffer_ptr(conf));
973 975
976#ifdef WITH_SSH1
974 if (sensitive_data.server_key != NULL && 977 if (sensitive_data.server_key != NULL &&
975 sensitive_data.server_key->type == KEY_RSA1) { 978 sensitive_data.server_key->type == KEY_RSA1) {
976 buffer_put_int(&m, 1); 979 buffer_put_int(&m, 1);
@@ -981,6 +984,7 @@ send_rexec_state(int fd, Buffer *conf)
981 buffer_put_bignum(&m, sensitive_data.server_key->rsa->p); 984 buffer_put_bignum(&m, sensitive_data.server_key->rsa->p);
982 buffer_put_bignum(&m, sensitive_data.server_key->rsa->q); 985 buffer_put_bignum(&m, sensitive_data.server_key->rsa->q);
983 } else 986 } else
987#endif
984 buffer_put_int(&m, 0); 988 buffer_put_int(&m, 0);
985 989
986#ifndef OPENSSL_PRNG_ONLY 990#ifndef OPENSSL_PRNG_ONLY
@@ -1017,6 +1021,7 @@ recv_rexec_state(int fd, Buffer *conf)
1017 free(cp); 1021 free(cp);
1018 1022
1019 if (buffer_get_int(&m)) { 1023 if (buffer_get_int(&m)) {
1024#ifdef WITH_SSH1
1020 if (sensitive_data.server_key != NULL) 1025 if (sensitive_data.server_key != NULL)
1021 key_free(sensitive_data.server_key); 1026 key_free(sensitive_data.server_key);
1022 sensitive_data.server_key = key_new_private(KEY_RSA1); 1027 sensitive_data.server_key = key_new_private(KEY_RSA1);
@@ -1026,8 +1031,13 @@ recv_rexec_state(int fd, Buffer *conf)
1026 buffer_get_bignum(&m, sensitive_data.server_key->rsa->iqmp); 1031 buffer_get_bignum(&m, sensitive_data.server_key->rsa->iqmp);
1027 buffer_get_bignum(&m, sensitive_data.server_key->rsa->p); 1032 buffer_get_bignum(&m, sensitive_data.server_key->rsa->p);
1028 buffer_get_bignum(&m, sensitive_data.server_key->rsa->q); 1033 buffer_get_bignum(&m, sensitive_data.server_key->rsa->q);
1029 rsa_generate_additional_parameters( 1034 if (rsa_generate_additional_parameters(
1030 sensitive_data.server_key->rsa); 1035 sensitive_data.server_key->rsa) != 0)
1036 fatal("%s: rsa_generate_additional_parameters "
1037 "error", __func__);
1038#else
1039 fatal("ssh1 not supported");
1040#endif
1031 } 1041 }
1032 1042
1033#ifndef OPENSSL_PRNG_ONLY 1043#ifndef OPENSSL_PRNG_ONLY
@@ -1550,7 +1560,9 @@ main(int ac, char **av)
1550 else 1560 else
1551 closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); 1561 closefrom(REEXEC_DEVCRYPTO_RESERVED_FD);
1552 1562
1563#ifdef WITH_OPENSSL
1553 OpenSSL_add_all_algorithms(); 1564 OpenSSL_add_all_algorithms();
1565#endif
1554 1566
1555 /* If requested, redirect the logs to the specified logfile. */ 1567 /* If requested, redirect the logs to the specified logfile. */
1556 if (logfile != NULL) { 1568 if (logfile != NULL) {
@@ -1655,7 +1667,12 @@ main(int ac, char **av)
1655 } 1667 }
1656 1668
1657 debug("sshd version %s, %s", SSH_VERSION, 1669 debug("sshd version %s, %s", SSH_VERSION,
1658 SSLeay_version(SSLEAY_VERSION)); 1670#ifdef WITH_OPENSSL
1671 SSLeay_version(SSLEAY_VERSION)
1672#else
1673 "without OpenSSL"
1674#endif
1675 );
1659 1676
1660 /* Store privilege separation user for later use if required. */ 1677 /* Store privilege separation user for later use if required. */
1661 if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) { 1678 if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) {
@@ -1777,6 +1794,8 @@ main(int ac, char **av)
1777 debug("host certificate: #%d type %d %s", j, key->type, 1794 debug("host certificate: #%d type %d %s", j, key->type,
1778 key_type(key)); 1795 key_type(key));
1779 } 1796 }
1797
1798#ifdef WITH_SSH1
1780 /* Check certain values for sanity. */ 1799 /* Check certain values for sanity. */
1781 if (options.protocol & SSH_PROTO_1) { 1800 if (options.protocol & SSH_PROTO_1) {
1782 if (options.server_key_bits < 512 || 1801 if (options.server_key_bits < 512 ||
@@ -1801,6 +1820,7 @@ main(int ac, char **av)
1801 options.server_key_bits); 1820 options.server_key_bits);
1802 } 1821 }
1803 } 1822 }
1823#endif
1804 1824
1805 if (use_privsep) { 1825 if (use_privsep) {
1806 struct stat st; 1826 struct stat st;
@@ -2034,24 +2054,6 @@ main(int ac, char **av)
2034#ifdef SSH_AUDIT_EVENTS 2054#ifdef SSH_AUDIT_EVENTS
2035 audit_connection_from(remote_ip, remote_port); 2055 audit_connection_from(remote_ip, remote_port);
2036#endif 2056#endif
2037#ifdef LIBWRAP
2038 allow_severity = options.log_facility|LOG_INFO;
2039 deny_severity = options.log_facility|LOG_WARNING;
2040 /* Check whether logins are denied from this host. */
2041 if (packet_connection_is_on_socket()) {
2042 struct request_info req;
2043
2044 request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0);
2045 fromhost(&req);
2046
2047 if (!hosts_access(&req)) {
2048 debug("Connection refused by tcp wrapper");
2049 refuse(&req);
2050 /* NOTREACHED */
2051 fatal("libwrap refuse returns");
2052 }
2053 }
2054#endif /* LIBWRAP */
2055 2057
2056 /* Log the connection. */ 2058 /* Log the connection. */
2057 verbose("Connection from %s port %d on %s port %d", 2059 verbose("Connection from %s port %d on %s port %d",
@@ -2102,8 +2104,12 @@ main(int ac, char **av)
2102 do_ssh2_kex(); 2104 do_ssh2_kex();
2103 do_authentication2(authctxt); 2105 do_authentication2(authctxt);
2104 } else { 2106 } else {
2107#ifdef WITH_SSH1
2105 do_ssh1_kex(); 2108 do_ssh1_kex();
2106 do_authentication(authctxt); 2109 do_authentication(authctxt);
2110#else
2111 fatal("ssh1 not supported");
2112#endif
2107 } 2113 }
2108 /* 2114 /*
2109 * If we use privilege separation, the unprivileged child transfers 2115 * If we use privilege separation, the unprivileged child transfers
@@ -2187,6 +2193,7 @@ main(int ac, char **av)
2187 exit(0); 2193 exit(0);
2188} 2194}
2189 2195
2196#ifdef WITH_SSH1
2190/* 2197/*
2191 * Decrypt session_key_int using our private server key and private host key 2198 * Decrypt session_key_int using our private server key and private host key
2192 * (key with larger modulus first). 2199 * (key with larger modulus first).
@@ -2210,10 +2217,10 @@ ssh1_session_key(BIGNUM *session_key_int)
2210 SSH_KEY_BITS_RESERVED); 2217 SSH_KEY_BITS_RESERVED);
2211 } 2218 }
2212 if (rsa_private_decrypt(session_key_int, session_key_int, 2219 if (rsa_private_decrypt(session_key_int, session_key_int,
2213 sensitive_data.server_key->rsa) <= 0) 2220 sensitive_data.server_key->rsa) != 0)
2214 rsafail++; 2221 rsafail++;
2215 if (rsa_private_decrypt(session_key_int, session_key_int, 2222 if (rsa_private_decrypt(session_key_int, session_key_int,
2216 sensitive_data.ssh1_host_key->rsa) <= 0) 2223 sensitive_data.ssh1_host_key->rsa) != 0)
2217 rsafail++; 2224 rsafail++;
2218 } else { 2225 } else {
2219 /* Host key has bigger modulus (or they are equal). */ 2226 /* Host key has bigger modulus (or they are equal). */
@@ -2228,14 +2235,15 @@ ssh1_session_key(BIGNUM *session_key_int)
2228 SSH_KEY_BITS_RESERVED); 2235 SSH_KEY_BITS_RESERVED);
2229 } 2236 }
2230 if (rsa_private_decrypt(session_key_int, session_key_int, 2237 if (rsa_private_decrypt(session_key_int, session_key_int,
2231 sensitive_data.ssh1_host_key->rsa) < 0) 2238 sensitive_data.ssh1_host_key->rsa) != 0)
2232 rsafail++; 2239 rsafail++;
2233 if (rsa_private_decrypt(session_key_int, session_key_int, 2240 if (rsa_private_decrypt(session_key_int, session_key_int,
2234 sensitive_data.server_key->rsa) < 0) 2241 sensitive_data.server_key->rsa) != 0)
2235 rsafail++; 2242 rsafail++;
2236 } 2243 }
2237 return (rsafail); 2244 return (rsafail);
2238} 2245}
2246
2239/* 2247/*
2240 * SSH1 key exchange 2248 * SSH1 key exchange
2241 */ 2249 */
@@ -2413,6 +2421,7 @@ do_ssh1_kex(void)
2413 packet_send(); 2421 packet_send();
2414 packet_write_wait(); 2422 packet_write_wait();
2415} 2423}
2424#endif
2416 2425
2417void 2426void
2418sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen, 2427sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen,
@@ -2437,6 +2446,7 @@ sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen,
2437static void 2446static void
2438do_ssh2_kex(void) 2447do_ssh2_kex(void)
2439{ 2448{
2449 char *myproposal[PROPOSAL_MAX] = { KEX_SERVER };
2440 Kex *kex; 2450 Kex *kex;
2441 2451
2442 if (options.ciphers != NULL) { 2452 if (options.ciphers != NULL) {
@@ -2462,6 +2472,9 @@ do_ssh2_kex(void)
2462 if (options.kex_algorithms != NULL) 2472 if (options.kex_algorithms != NULL)
2463 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; 2473 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
2464 2474
2475 myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
2476 myproposal[PROPOSAL_KEX_ALGS]);
2477
2465 if (options.rekey_limit || options.rekey_interval) 2478 if (options.rekey_limit || options.rekey_interval)
2466 packet_set_rekey_limits((u_int32_t)options.rekey_limit, 2479 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
2467 (time_t)options.rekey_interval); 2480 (time_t)options.rekey_interval);
@@ -2471,11 +2484,13 @@ do_ssh2_kex(void)
2471 2484
2472 /* start key exchange */ 2485 /* start key exchange */
2473 kex = kex_setup(myproposal); 2486 kex = kex_setup(myproposal);
2487#ifdef WITH_OPENSSL
2474 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 2488 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
2475 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 2489 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
2476 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 2490 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
2477 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 2491 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
2478 kex->kex[KEX_ECDH_SHA2] = kexecdh_server; 2492 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
2493#endif
2479 kex->kex[KEX_C25519_SHA256] = kexc25519_server; 2494 kex->kex[KEX_C25519_SHA256] = kexc25519_server;
2480 kex->server = 1; 2495 kex->server = 1;
2481 kex->client_version_string=client_version_string; 2496 kex->client_version_string=client_version_string;
@@ -2508,7 +2523,8 @@ cleanup_exit(int i)
2508{ 2523{
2509 if (the_authctxt) { 2524 if (the_authctxt) {
2510 do_cleanup(the_authctxt); 2525 do_cleanup(the_authctxt);
2511 if (use_privsep && privsep_is_preauth && pmonitor->m_pid > 1) { 2526 if (use_privsep && privsep_is_preauth &&
2527 pmonitor != NULL && pmonitor->m_pid > 1) {
2512 debug("Killing privsep child %d", pmonitor->m_pid); 2528 debug("Killing privsep child %d", pmonitor->m_pid);
2513 if (kill(pmonitor->m_pid, SIGKILL) != 0 && 2529 if (kill(pmonitor->m_pid, SIGKILL) != 0 &&
2514 errno != ESRCH) 2530 errno != ESRCH)
diff --git a/sshd_config.0 b/sshd_config.0
index 413c26008..1c82d449f 100644
--- a/sshd_config.0
+++ b/sshd_config.0
@@ -1,4 +1,4 @@
1SSHD_CONFIG(5) OpenBSD Programmer's Manual SSHD_CONFIG(5) 1SSHD_CONFIG(5) File Formats Manual SSHD_CONFIG(5)
2 2
3NAME 3NAME
4 sshd_config - OpenSSH SSH daemon configuration file 4 sshd_config - OpenSSH SSH daemon configuration file
@@ -62,6 +62,16 @@ DESCRIPTION
62 are also denied shell access, as they can always install their 62 are also denied shell access, as they can always install their
63 own forwarders. 63 own forwarders.
64 64
65 AllowStreamLocalForwarding
66 Specifies whether StreamLocal (Unix-domain socket) forwarding is
67 permitted. The available options are ``yes'' or ``all'' to allow
68 StreamLocal forwarding, ``no'' to prevent all StreamLocal
69 forwarding, ``local'' to allow local (from the perspective of
70 ssh(1)) forwarding only or ``remote'' to allow remote forwarding
71 only. The default is ``yes''. Note that disabling StreamLocal
72 forwarding does not improve security unless users are also denied
73 shell access, as they can always install their own forwarders.
74
65 AllowUsers 75 AllowUsers
66 This keyword can be followed by a list of user name patterns, 76 This keyword can be followed by a list of user name patterns,
67 separated by spaces. If specified, login is allowed only for 77 separated by spaces. If specified, login is allowed only for
@@ -168,7 +178,7 @@ DESCRIPTION
168 178
169 ChallengeResponseAuthentication 179 ChallengeResponseAuthentication
170 Specifies whether challenge-response authentication is allowed 180 Specifies whether challenge-response authentication is allowed
171 (e.g. via PAM or though authentication styles supported in 181 (e.g. via PAM or through authentication styles supported in
172 login.conf(5)) The default is ``yes''. 182 login.conf(5)) The default is ``yes''.
173 183
174 ChrootDirectory 184 ChrootDirectory
@@ -191,8 +201,9 @@ DESCRIPTION
191 stderr(4), arandom(4) and tty(4) devices. For file transfer 201 stderr(4), arandom(4) and tty(4) devices. For file transfer
192 sessions using ``sftp'', no additional configuration of the 202 sessions using ``sftp'', no additional configuration of the
193 environment is necessary if the in-process sftp server is used, 203 environment is necessary if the in-process sftp server is used,
194 though sessions which use logging do require /dev/log inside the 204 though sessions which use logging may require /dev/log inside the
195 chroot directory (see sftp-server(8) for details). 205 chroot directory on some operating systems (see sftp-server(8)
206 for details).
196 207
197 The default is not to chroot(2). 208 The default is not to chroot(2).
198 209
@@ -200,19 +211,27 @@ DESCRIPTION
200 Specifies the ciphers allowed for protocol version 2. Multiple 211 Specifies the ciphers allowed for protocol version 2. Multiple
201 ciphers must be comma-separated. The supported ciphers are: 212 ciphers must be comma-separated. The supported ciphers are:
202 213
203 ``3des-cbc'', ``aes128-cbc'', ``aes192-cbc'', ``aes256-cbc'', 214 3des-cbc
204 ``aes128-ctr'', ``aes192-ctr'', ``aes256-ctr'', 215 aes128-cbc
205 ``aes128-gcm@openssh.com'', ``aes256-gcm@openssh.com'', 216 aes192-cbc
206 ``arcfour128'', ``arcfour256'', ``arcfour'', ``blowfish-cbc'', 217 aes256-cbc
207 ``cast128-cbc'', and ``chacha20-poly1305@openssh.com''. 218 aes128-ctr
219 aes192-ctr
220 aes256-ctr
221 aes128-gcm@openssh.com
222 aes256-gcm@openssh.com
223 arcfour
224 arcfour128
225 arcfour256
226 blowfish-cbc
227 cast128-cbc
228 chacha20-poly1305@openssh.com
208 229
209 The default is: 230 The default is:
210 231
211 aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, 232 aes128-ctr,aes192-ctr,aes256-ctr,
212 aes128-gcm@openssh.com,aes256-gcm@openssh.com, 233 aes128-gcm@openssh.com,aes256-gcm@openssh.com,
213 chacha20-poly1305@openssh.com, 234 chacha20-poly1305@openssh.com
214 aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,
215 aes256-cbc,arcfour
216 235
217 The list of available ciphers may also be obtained using the -Q 236 The list of available ciphers may also be obtained using the -Q
218 option of ssh(1). 237 option of ssh(1).
@@ -403,14 +422,24 @@ DESCRIPTION
403 422
404 KexAlgorithms 423 KexAlgorithms
405 Specifies the available KEX (Key Exchange) algorithms. Multiple 424 Specifies the available KEX (Key Exchange) algorithms. Multiple
406 algorithms must be comma-separated. The default is 425 algorithms must be comma-separated. The supported algorithms
426 are:
427
428 curve25519-sha256@libssh.org
429 diffie-hellman-group1-sha1
430 diffie-hellman-group14-sha1
431 diffie-hellman-group-exchange-sha1
432 diffie-hellman-group-exchange-sha256
433 ecdh-sha2-nistp256
434 ecdh-sha2-nistp384
435 ecdh-sha2-nistp521
436
437 The default is:
407 438
408 curve25519-sha256@libssh.org, 439 curve25519-sha256@libssh.org,
409 ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, 440 ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
410 diffie-hellman-group-exchange-sha256, 441 diffie-hellman-group-exchange-sha256,
411 diffie-hellman-group-exchange-sha1, 442 diffie-hellman-group14-sha1
412 diffie-hellman-group14-sha1,
413 diffie-hellman-group1-sha1
414 443
415 KeyRegenerationInterval 444 KeyRegenerationInterval
416 In protocol version 1, the ephemeral server key is automatically 445 In protocol version 1, the ephemeral server key is automatically
@@ -452,16 +481,33 @@ DESCRIPTION
452 data integrity protection. Multiple algorithms must be comma- 481 data integrity protection. Multiple algorithms must be comma-
453 separated. The algorithms that contain ``-etm'' calculate the 482 separated. The algorithms that contain ``-etm'' calculate the
454 MAC after encryption (encrypt-then-mac). These are considered 483 MAC after encryption (encrypt-then-mac). These are considered
455 safer and their use recommended. The default is: 484 safer and their use recommended. The supported MACs are:
485
486 hmac-md5
487 hmac-md5-96
488 hmac-ripemd160
489 hmac-sha1
490 hmac-sha1-96
491 hmac-sha2-256
492 hmac-sha2-512
493 umac-64@openssh.com
494 umac-128@openssh.com
495 hmac-md5-etm@openssh.com
496 hmac-md5-96-etm@openssh.com
497 hmac-ripemd160-etm@openssh.com
498 hmac-sha1-etm@openssh.com
499 hmac-sha1-96-etm@openssh.com
500 hmac-sha2-256-etm@openssh.com
501 hmac-sha2-512-etm@openssh.com
502 umac-64-etm@openssh.com
503 umac-128-etm@openssh.com
504
505 The default is:
456 506
457 hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com,
458 umac-64-etm@openssh.com,umac-128-etm@openssh.com, 507 umac-64-etm@openssh.com,umac-128-etm@openssh.com,
459 hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com, 508 hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,
460 hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com, 509 umac-64@openssh.com,umac-128@openssh.com,
461 hmac-md5-96-etm@openssh.com, 510 hmac-sha2-256,hmac-sha2-512
462 hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com,
463 hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,
464 hmac-sha1-96,hmac-md5-96
465 511
466 Match Introduces a conditional block. If all of the criteria on the 512 Match Introduces a conditional block. If all of the criteria on the
467 Match line are satisfied, the keywords on the following lines 513 Match line are satisfied, the keywords on the following lines
@@ -496,7 +542,7 @@ DESCRIPTION
496 KbdInteractiveAuthentication, KerberosAuthentication, 542 KbdInteractiveAuthentication, KerberosAuthentication,
497 MaxAuthTries, MaxSessions, PasswordAuthentication, 543 MaxAuthTries, MaxSessions, PasswordAuthentication,
498 PermitEmptyPasswords, PermitOpen, PermitRootLogin, PermitTTY, 544 PermitEmptyPasswords, PermitOpen, PermitRootLogin, PermitTTY,
499 PermitTunnel, PubkeyAuthentication, RekeyLimit, 545 PermitTunnel, PermitUserRC, PubkeyAuthentication, RekeyLimit,
500 RhostsRSAAuthentication, RSAAuthentication, X11DisplayOffset, 546 RhostsRSAAuthentication, RSAAuthentication, X11DisplayOffset,
501 X11Forwarding and X11UseLocalHost. 547 X11Forwarding and X11UseLocalHost.
502 548
@@ -580,6 +626,10 @@ DESCRIPTION
580 bypass access restrictions in some configurations using 626 bypass access restrictions in some configurations using
581 mechanisms such as LD_PRELOAD. 627 mechanisms such as LD_PRELOAD.
582 628
629 PermitUserRC
630 Specifies whether any ~/.ssh/rc file is executed. The default is
631 ``yes''.
632
583 PidFile 633 PidFile
584 Specifies the file that contains the process ID of the SSH 634 Specifies the file that contains the process ID of the SSH
585 daemon. The default is /var/run/sshd.pid. 635 daemon. The default is /var/run/sshd.pid.
@@ -650,6 +700,27 @@ DESCRIPTION
650 Defines the number of bits in the ephemeral protocol version 1 700 Defines the number of bits in the ephemeral protocol version 1
651 server key. The minimum value is 512, and the default is 1024. 701 server key. The minimum value is 512, and the default is 1024.
652 702
703 StreamLocalBindMask
704 Sets the octal file creation mode mask (umask) used when creating
705 a Unix-domain socket file for local or remote port forwarding.
706 This option is only used for port forwarding to a Unix-domain
707 socket file.
708
709 The default value is 0177, which creates a Unix-domain socket
710 file that is readable and writable only by the owner. Note that
711 not all operating systems honor the file mode on Unix-domain
712 socket files.
713
714 StreamLocalBindUnlink
715 Specifies whether to remove an existing Unix-domain socket file
716 for local or remote port forwarding before creating a new one.
717 If the socket file already exists and StreamLocalBindUnlink is
718 not enabled, sshd will be unable to forward the port to the Unix-
719 domain socket file. This option is only used for port forwarding
720 to a Unix-domain socket file.
721
722 The argument must be ``yes'' or ``no''. The default is ``no''.
723
653 StrictModes 724 StrictModes
654 Specifies whether sshd(8) should check file modes and ownership 725 Specifies whether sshd(8) should check file modes and ownership
655 of the user's files and home directory before accepting login. 726 of the user's files and home directory before accepting login.
@@ -832,4 +903,4 @@ AUTHORS
832 versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support 903 versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support
833 for privilege separation. 904 for privilege separation.
834 905
835OpenBSD 5.5 February 27, 2014 OpenBSD 5.5 906OpenBSD 5.6 July 28, 2014 OpenBSD 5.6
diff --git a/sshd_config.5 b/sshd_config.5
index ce71efe3c..fd44abe75 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: sshd_config.5,v 1.172 2014/02/27 22:47:07 djm Exp $ 36.\" $OpenBSD: sshd_config.5,v 1.176 2014/07/28 15:40:08 schwarze Exp $
37.Dd $Mdocdate: February 27 2014 $ 37.Dd $Mdocdate: July 28 2014 $
38.Dt SSHD_CONFIG 5 38.Dt SSHD_CONFIG 5
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -140,6 +140,26 @@ The default is
140Note that disabling TCP forwarding does not improve security unless 140Note that disabling TCP forwarding does not improve security unless
141users are also denied shell access, as they can always install their 141users are also denied shell access, as they can always install their
142own forwarders. 142own forwarders.
143.It Cm AllowStreamLocalForwarding
144Specifies whether StreamLocal (Unix-domain socket) forwarding is permitted.
145The available options are
146.Dq yes
147or
148.Dq all
149to allow StreamLocal forwarding,
150.Dq no
151to prevent all StreamLocal forwarding,
152.Dq local
153to allow local (from the perspective of
154.Xr ssh 1 )
155forwarding only or
156.Dq remote
157to allow remote forwarding only.
158The default is
159.Dq yes .
160Note that disabling StreamLocal forwarding does not improve security unless
161users are also denied shell access, as they can always install their
162own forwarders.
143.It Cm AllowUsers 163.It Cm AllowUsers
144This keyword can be followed by a list of user name patterns, separated 164This keyword can be followed by a list of user name patterns, separated
145by spaces. 165by spaces.
@@ -283,7 +303,7 @@ This option is only available for protocol version 2.
283By default, no banner is displayed. 303By default, no banner is displayed.
284.It Cm ChallengeResponseAuthentication 304.It Cm ChallengeResponseAuthentication
285Specifies whether challenge-response authentication is allowed (e.g. via 305Specifies whether challenge-response authentication is allowed (e.g. via
286PAM or though authentication styles supported in 306PAM or through authentication styles supported in
287.Xr login.conf 5 ) 307.Xr login.conf 5 )
288The default is 308The default is
289.Dq yes . 309.Dq yes .
@@ -324,9 +344,9 @@ For file transfer sessions using
324.Dq sftp , 344.Dq sftp ,
325no additional configuration of the environment is necessary if the 345no additional configuration of the environment is necessary if the
326in-process sftp server is used, 346in-process sftp server is used,
327though sessions which use logging do require 347though sessions which use logging may require
328.Pa /dev/log 348.Pa /dev/log
329inside the chroot directory (see 349inside the chroot directory on some operating systems (see
330.Xr sftp-server 8 350.Xr sftp-server 8
331for details). 351for details).
332.Pp 352.Pp
@@ -337,30 +357,44 @@ Specifies the ciphers allowed for protocol version 2.
337Multiple ciphers must be comma-separated. 357Multiple ciphers must be comma-separated.
338The supported ciphers are: 358The supported ciphers are:
339.Pp 359.Pp
340.Dq 3des-cbc , 360.Bl -item -compact -offset indent
341.Dq aes128-cbc , 361.It
342.Dq aes192-cbc , 3623des-cbc
343.Dq aes256-cbc , 363.It
344.Dq aes128-ctr , 364aes128-cbc
345.Dq aes192-ctr , 365.It
346.Dq aes256-ctr , 366aes192-cbc
347.Dq aes128-gcm@openssh.com , 367.It
348.Dq aes256-gcm@openssh.com , 368aes256-cbc
349.Dq arcfour128 , 369.It
350.Dq arcfour256 , 370aes128-ctr
351.Dq arcfour , 371.It
352.Dq blowfish-cbc , 372aes192-ctr
353.Dq cast128-cbc , 373.It
354and 374aes256-ctr
355.Dq chacha20-poly1305@openssh.com . 375.It
376aes128-gcm@openssh.com
377.It
378aes256-gcm@openssh.com
379.It
380arcfour
381.It
382arcfour128
383.It
384arcfour256
385.It
386blowfish-cbc
387.It
388cast128-cbc
389.It
390chacha20-poly1305@openssh.com
391.El
356.Pp 392.Pp
357The default is: 393The default is:
358.Bd -literal -offset 3n 394.Bd -literal -offset indent
359aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, 395aes128-ctr,aes192-ctr,aes256-ctr,
360aes128-gcm@openssh.com,aes256-gcm@openssh.com, 396aes128-gcm@openssh.com,aes256-gcm@openssh.com,
361chacha20-poly1305@openssh.com, 397chacha20-poly1305@openssh.com
362aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,
363aes256-cbc,arcfour
364.Ed 398.Ed
365.Pp 399.Pp
366The list of available ciphers may also be obtained using the 400The list of available ciphers may also be obtained using the
@@ -672,14 +706,33 @@ The default is
672.It Cm KexAlgorithms 706.It Cm KexAlgorithms
673Specifies the available KEX (Key Exchange) algorithms. 707Specifies the available KEX (Key Exchange) algorithms.
674Multiple algorithms must be comma-separated. 708Multiple algorithms must be comma-separated.
675The default is 709The supported algorithms are:
710.Pp
711.Bl -item -compact -offset indent
712.It
713curve25519-sha256@libssh.org
714.It
715diffie-hellman-group1-sha1
716.It
717diffie-hellman-group14-sha1
718.It
719diffie-hellman-group-exchange-sha1
720.It
721diffie-hellman-group-exchange-sha256
722.It
723ecdh-sha2-nistp256
724.It
725ecdh-sha2-nistp384
726.It
727ecdh-sha2-nistp521
728.El
729.Pp
730The default is:
676.Bd -literal -offset indent 731.Bd -literal -offset indent
677curve25519-sha256@libssh.org, 732curve25519-sha256@libssh.org,
678ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, 733ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
679diffie-hellman-group-exchange-sha256, 734diffie-hellman-group-exchange-sha256,
680diffie-hellman-group-exchange-sha1, 735diffie-hellman-group14-sha1
681diffie-hellman-group14-sha1,
682diffie-hellman-group1-sha1
683.Ed 736.Ed
684.It Cm KeyRegenerationInterval 737.It Cm KeyRegenerationInterval
685In protocol version 1, the ephemeral server key is automatically regenerated 738In protocol version 1, the ephemeral server key is automatically regenerated
@@ -751,16 +804,53 @@ The algorithms that contain
751.Dq -etm 804.Dq -etm
752calculate the MAC after encryption (encrypt-then-mac). 805calculate the MAC after encryption (encrypt-then-mac).
753These are considered safer and their use recommended. 806These are considered safer and their use recommended.
807The supported MACs are:
808.Pp
809.Bl -item -compact -offset indent
810.It
811hmac-md5
812.It
813hmac-md5-96
814.It
815hmac-ripemd160
816.It
817hmac-sha1
818.It
819hmac-sha1-96
820.It
821hmac-sha2-256
822.It
823hmac-sha2-512
824.It
825umac-64@openssh.com
826.It
827umac-128@openssh.com
828.It
829hmac-md5-etm@openssh.com
830.It
831hmac-md5-96-etm@openssh.com
832.It
833hmac-ripemd160-etm@openssh.com
834.It
835hmac-sha1-etm@openssh.com
836.It
837hmac-sha1-96-etm@openssh.com
838.It
839hmac-sha2-256-etm@openssh.com
840.It
841hmac-sha2-512-etm@openssh.com
842.It
843umac-64-etm@openssh.com
844.It
845umac-128-etm@openssh.com
846.El
847.Pp
754The default is: 848The default is:
755.Bd -literal -offset indent 849.Bd -literal -offset indent
756hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com,
757umac-64-etm@openssh.com,umac-128-etm@openssh.com, 850umac-64-etm@openssh.com,umac-128-etm@openssh.com,
758hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com, 851hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,
759hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com, 852umac-64@openssh.com,umac-128@openssh.com,
760hmac-md5-96-etm@openssh.com, 853hmac-sha2-256,hmac-sha2-512
761hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com,
762hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,
763hmac-sha1-96,hmac-md5-96
764.Ed 854.Ed
765.It Cm Match 855.It Cm Match
766Introduces a conditional block. 856Introduces a conditional block.
@@ -842,6 +932,7 @@ Available keywords are
842.Cm PermitRootLogin , 932.Cm PermitRootLogin ,
843.Cm PermitTTY , 933.Cm PermitTTY ,
844.Cm PermitTunnel , 934.Cm PermitTunnel ,
935.Cm PermitUserRC ,
845.Cm PubkeyAuthentication , 936.Cm PubkeyAuthentication ,
846.Cm RekeyLimit , 937.Cm RekeyLimit ,
847.Cm RhostsRSAAuthentication , 938.Cm RhostsRSAAuthentication ,
@@ -990,6 +1081,12 @@ The default is
990Enabling environment processing may enable users to bypass access 1081Enabling environment processing may enable users to bypass access
991restrictions in some configurations using mechanisms such as 1082restrictions in some configurations using mechanisms such as
992.Ev LD_PRELOAD . 1083.Ev LD_PRELOAD .
1084.It Cm PermitUserRC
1085Specifies whether any
1086.Pa ~/.ssh/rc
1087file is executed.
1088The default is
1089.Dq yes .
993.It Cm PidFile 1090.It Cm PidFile
994Specifies the file that contains the process ID of the 1091Specifies the file that contains the process ID of the
995SSH daemon. 1092SSH daemon.
@@ -1094,6 +1191,33 @@ This option applies to protocol version 1 only.
1094.It Cm ServerKeyBits 1191.It Cm ServerKeyBits
1095Defines the number of bits in the ephemeral protocol version 1 server key. 1192Defines the number of bits in the ephemeral protocol version 1 server key.
1096The minimum value is 512, and the default is 1024. 1193The minimum value is 512, and the default is 1024.
1194.It Cm StreamLocalBindMask
1195Sets the octal file creation mode mask
1196.Pq umask
1197used when creating a Unix-domain socket file for local or remote
1198port forwarding.
1199This option is only used for port forwarding to a Unix-domain socket file.
1200.Pp
1201The default value is 0177, which creates a Unix-domain socket file that is
1202readable and writable only by the owner.
1203Note that not all operating systems honor the file mode on Unix-domain
1204socket files.
1205.It Cm StreamLocalBindUnlink
1206Specifies whether to remove an existing Unix-domain socket file for local
1207or remote port forwarding before creating a new one.
1208If the socket file already exists and
1209.Cm StreamLocalBindUnlink
1210is not enabled,
1211.Nm sshd
1212will be unable to forward the port to the Unix-domain socket file.
1213This option is only used for port forwarding to a Unix-domain socket file.
1214.Pp
1215The argument must be
1216.Dq yes
1217or
1218.Dq no .
1219The default is
1220.Dq no .
1097.It Cm StrictModes 1221.It Cm StrictModes
1098Specifies whether 1222Specifies whether
1099.Xr sshd 8 1223.Xr sshd 8
diff --git a/ssherr.c b/ssherr.c
new file mode 100644
index 000000000..49fbb71de
--- /dev/null
+++ b/ssherr.c
@@ -0,0 +1,131 @@
1/* $OpenBSD: ssherr.c,v 1.1 2014/04/30 05:29:56 djm Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <errno.h>
19#include <string.h>
20#include "ssherr.h"
21
22const char *
23ssh_err(int n)
24{
25 switch (n) {
26 case SSH_ERR_SUCCESS:
27 return "success";
28 case SSH_ERR_INTERNAL_ERROR:
29 return "unexpected internal error";
30 case SSH_ERR_ALLOC_FAIL:
31 return "memory allocation failed";
32 case SSH_ERR_MESSAGE_INCOMPLETE:
33 return "incomplete message";
34 case SSH_ERR_INVALID_FORMAT:
35 return "invalid format";
36 case SSH_ERR_BIGNUM_IS_NEGATIVE:
37 return "bignum is negative";
38 case SSH_ERR_STRING_TOO_LARGE:
39 return "string is too large";
40 case SSH_ERR_BIGNUM_TOO_LARGE:
41 return "bignum is too large";
42 case SSH_ERR_ECPOINT_TOO_LARGE:
43 return "elliptic curve point is too large";
44 case SSH_ERR_NO_BUFFER_SPACE:
45 return "insufficient buffer space";
46 case SSH_ERR_INVALID_ARGUMENT:
47 return "invalid argument";
48 case SSH_ERR_KEY_BITS_MISMATCH:
49 return "key bits do not match";
50 case SSH_ERR_EC_CURVE_INVALID:
51 return "invalid elliptic curve";
52 case SSH_ERR_KEY_TYPE_MISMATCH:
53 return "key type does not match";
54 case SSH_ERR_KEY_TYPE_UNKNOWN:
55 return "unknown or unsupported key type";
56 case SSH_ERR_EC_CURVE_MISMATCH:
57 return "elliptic curve does not match";
58 case SSH_ERR_EXPECTED_CERT:
59 return "plain key provided where certificate required";
60 case SSH_ERR_KEY_LACKS_CERTBLOB:
61 return "key lacks certificate data";
62 case SSH_ERR_KEY_CERT_UNKNOWN_TYPE:
63 return "unknown/unsupported certificate type";
64 case SSH_ERR_KEY_CERT_INVALID_SIGN_KEY:
65 return "invalid certificate signing key";
66 case SSH_ERR_KEY_INVALID_EC_VALUE:
67 return "invalid elliptic curve value";
68 case SSH_ERR_SIGNATURE_INVALID:
69 return "incorrect signature";
70 case SSH_ERR_LIBCRYPTO_ERROR:
71 return "error in libcrypto"; /* XXX fetch and return */
72 case SSH_ERR_UNEXPECTED_TRAILING_DATA:
73 return "unexpected bytes remain after decoding";
74 case SSH_ERR_SYSTEM_ERROR:
75 return strerror(errno);
76 case SSH_ERR_KEY_CERT_INVALID:
77 return "invalid certificate";
78 case SSH_ERR_AGENT_COMMUNICATION:
79 return "communication with agent failed";
80 case SSH_ERR_AGENT_FAILURE:
81 return "agent refused operation";
82 case SSH_ERR_DH_GEX_OUT_OF_RANGE:
83 return "DH GEX group out of range";
84 case SSH_ERR_DISCONNECTED:
85 return "disconnected";
86 case SSH_ERR_MAC_INVALID:
87 return "message authentication code incorrect";
88 case SSH_ERR_NO_CIPHER_ALG_MATCH:
89 return "no matching cipher found";
90 case SSH_ERR_NO_MAC_ALG_MATCH:
91 return "no matching MAC found";
92 case SSH_ERR_NO_COMPRESS_ALG_MATCH:
93 return "no matching compression method found";
94 case SSH_ERR_NO_KEX_ALG_MATCH:
95 return "no matching key exchange method found";
96 case SSH_ERR_NO_HOSTKEY_ALG_MATCH:
97 return "no matching host key type found";
98 case SSH_ERR_PROTOCOL_MISMATCH:
99 return "protocol version mismatch";
100 case SSH_ERR_NO_PROTOCOL_VERSION:
101 return "could not read protocol version";
102 case SSH_ERR_NO_HOSTKEY_LOADED:
103 return "could not load host key";
104 case SSH_ERR_NEED_REKEY:
105 return "rekeying not supported by peer";
106 case SSH_ERR_PASSPHRASE_TOO_SHORT:
107 return "passphrase is too short (minimum four characters)";
108 case SSH_ERR_FILE_CHANGED:
109 return "file changed while reading";
110 case SSH_ERR_KEY_UNKNOWN_CIPHER:
111 return "key encrypted using unsupported cipher";
112 case SSH_ERR_KEY_WRONG_PASSPHRASE:
113 return "incorrect passphrase supplied to decrypt private key";
114 case SSH_ERR_KEY_BAD_PERMISSIONS:
115 return "bad permissions";
116 case SSH_ERR_KEY_CERT_MISMATCH:
117 return "certificate does not match key";
118 case SSH_ERR_KEY_NOT_FOUND:
119 return "key not found";
120 case SSH_ERR_AGENT_NOT_PRESENT:
121 return "agent not present";
122 case SSH_ERR_AGENT_NO_IDENTITIES:
123 return "agent contains no identities";
124 case SSH_ERR_KRL_BAD_MAGIC:
125 return "KRL file has invalid magic number";
126 case SSH_ERR_KEY_REVOKED:
127 return "Key is revoked";
128 default:
129 return "unknown error";
130 }
131}
diff --git a/ssherr.h b/ssherr.h
new file mode 100644
index 000000000..106f786ea
--- /dev/null
+++ b/ssherr.h
@@ -0,0 +1,80 @@
1/* $OpenBSD: ssherr.h,v 1.1 2014/04/30 05:29:56 djm Exp $ */
2/*
3 * Copyright (c) 2011 Damien Miller
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#ifndef _SSHERR_H
19#define _SSHERR_H
20
21/* XXX are these too granular? not granular enough? I can't decide - djm */
22
23/* Error codes */
24#define SSH_ERR_SUCCESS 0
25#define SSH_ERR_INTERNAL_ERROR -1
26#define SSH_ERR_ALLOC_FAIL -2
27#define SSH_ERR_MESSAGE_INCOMPLETE -3
28#define SSH_ERR_INVALID_FORMAT -4
29#define SSH_ERR_BIGNUM_IS_NEGATIVE -5
30#define SSH_ERR_STRING_TOO_LARGE -6
31#define SSH_ERR_BIGNUM_TOO_LARGE -7
32#define SSH_ERR_ECPOINT_TOO_LARGE -8
33#define SSH_ERR_NO_BUFFER_SPACE -9
34#define SSH_ERR_INVALID_ARGUMENT -10
35#define SSH_ERR_KEY_BITS_MISMATCH -11
36#define SSH_ERR_EC_CURVE_INVALID -12
37#define SSH_ERR_KEY_TYPE_MISMATCH -13
38#define SSH_ERR_KEY_TYPE_UNKNOWN -14 /* XXX UNSUPPORTED? */
39#define SSH_ERR_EC_CURVE_MISMATCH -15
40#define SSH_ERR_EXPECTED_CERT -16
41#define SSH_ERR_KEY_LACKS_CERTBLOB -17
42#define SSH_ERR_KEY_CERT_UNKNOWN_TYPE -18
43#define SSH_ERR_KEY_CERT_INVALID_SIGN_KEY -19
44#define SSH_ERR_KEY_INVALID_EC_VALUE -20
45#define SSH_ERR_SIGNATURE_INVALID -21
46#define SSH_ERR_LIBCRYPTO_ERROR -22
47#define SSH_ERR_UNEXPECTED_TRAILING_DATA -23
48#define SSH_ERR_SYSTEM_ERROR -24
49#define SSH_ERR_KEY_CERT_INVALID -25
50#define SSH_ERR_AGENT_COMMUNICATION -26
51#define SSH_ERR_AGENT_FAILURE -27
52#define SSH_ERR_DH_GEX_OUT_OF_RANGE -28
53#define SSH_ERR_DISCONNECTED -29
54#define SSH_ERR_MAC_INVALID -30
55#define SSH_ERR_NO_CIPHER_ALG_MATCH -31
56#define SSH_ERR_NO_MAC_ALG_MATCH -32
57#define SSH_ERR_NO_COMPRESS_ALG_MATCH -33
58#define SSH_ERR_NO_KEX_ALG_MATCH -34
59#define SSH_ERR_NO_HOSTKEY_ALG_MATCH -35
60#define SSH_ERR_NO_HOSTKEY_LOADED -36
61#define SSH_ERR_PROTOCOL_MISMATCH -37
62#define SSH_ERR_NO_PROTOCOL_VERSION -38
63#define SSH_ERR_NEED_REKEY -39
64#define SSH_ERR_PASSPHRASE_TOO_SHORT -40
65#define SSH_ERR_FILE_CHANGED -41
66#define SSH_ERR_KEY_UNKNOWN_CIPHER -42
67#define SSH_ERR_KEY_WRONG_PASSPHRASE -43
68#define SSH_ERR_KEY_BAD_PERMISSIONS -44
69#define SSH_ERR_KEY_CERT_MISMATCH -45
70#define SSH_ERR_KEY_NOT_FOUND -46
71#define SSH_ERR_AGENT_NOT_PRESENT -47
72#define SSH_ERR_AGENT_NO_IDENTITIES -48
73#define SSH_ERR_BUFFER_READ_ONLY -49
74#define SSH_ERR_KRL_BAD_MAGIC -50
75#define SSH_ERR_KEY_REVOKED -51
76
77/* Translate a numeric error code to a human-readable error string */
78const char *ssh_err(int n);
79
80#endif /* _SSHERR_H */
diff --git a/sshkey.c b/sshkey.c
new file mode 100644
index 000000000..fdd0c8a89
--- /dev/null
+++ b/sshkey.c
@@ -0,0 +1,3856 @@
1/* $OpenBSD: sshkey.c,v 1.3 2014/07/03 01:45:38 djm Exp $ */
2/*
3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
4 * Copyright (c) 2008 Alexander von Gernler. All rights reserved.
5 * Copyright (c) 2010,2011 Damien Miller. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "includes.h"
29
30#include <sys/param.h>
31#include <sys/types.h>
32
33#include <openssl/evp.h>
34#include <openssl/err.h>
35#include <openssl/pem.h>
36
37#include "crypto_api.h"
38
39#include <errno.h>
40#include <stdio.h>
41#include <string.h>
42#ifdef HAVE_UTIL_H
43#include <util.h>
44#endif /* HAVE_UTIL_H */
45
46#include "ssh2.h"
47#include "ssherr.h"
48#include "misc.h"
49#include "sshbuf.h"
50#include "rsa.h"
51#include "cipher.h"
52#include "digest.h"
53#define SSHKEY_INTERNAL
54#include "sshkey.h"
55
56/* openssh private key file format */
57#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n"
58#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n"
59#define MARK_BEGIN_LEN (sizeof(MARK_BEGIN) - 1)
60#define MARK_END_LEN (sizeof(MARK_END) - 1)
61#define KDFNAME "bcrypt"
62#define AUTH_MAGIC "openssh-key-v1"
63#define SALT_LEN 16
64#define DEFAULT_CIPHERNAME "aes256-cbc"
65#define DEFAULT_ROUNDS 16
66
67/* Version identification string for SSH v1 identity files. */
68#define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n"
69
70static int sshkey_from_blob_internal(const u_char *blob, size_t blen,
71 struct sshkey **keyp, int allow_cert);
72
73/* Supported key types */
74struct keytype {
75 const char *name;
76 const char *shortname;
77 int type;
78 int nid;
79 int cert;
80};
81static const struct keytype keytypes[] = {
82 { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0 },
83 { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT",
84 KEY_ED25519_CERT, 0, 1 },
85#ifdef WITH_OPENSSL
86 { NULL, "RSA1", KEY_RSA1, 0, 0 },
87 { "ssh-rsa", "RSA", KEY_RSA, 0, 0 },
88 { "ssh-dss", "DSA", KEY_DSA, 0, 0 },
89# ifdef OPENSSL_HAS_ECC
90 { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0 },
91 { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0 },
92# ifdef OPENSSL_HAS_NISTP521
93 { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0 },
94# endif /* OPENSSL_HAS_NISTP521 */
95# endif /* OPENSSL_HAS_ECC */
96 { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1 },
97 { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1 },
98# ifdef OPENSSL_HAS_ECC
99 { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT",
100 KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1 },
101 { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT",
102 KEY_ECDSA_CERT, NID_secp384r1, 1 },
103# ifdef OPENSSL_HAS_NISTP521
104 { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT",
105 KEY_ECDSA_CERT, NID_secp521r1, 1 },
106# endif /* OPENSSL_HAS_NISTP521 */
107# endif /* OPENSSL_HAS_ECC */
108 { "ssh-rsa-cert-v00@openssh.com", "RSA-CERT-V00",
109 KEY_RSA_CERT_V00, 0, 1 },
110 { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00",
111 KEY_DSA_CERT_V00, 0, 1 },
112#endif /* WITH_OPENSSL */
113 { NULL, NULL, -1, -1, 0 }
114};
115
116const char *
117sshkey_type(const struct sshkey *k)
118{
119 const struct keytype *kt;
120
121 for (kt = keytypes; kt->type != -1; kt++) {
122 if (kt->type == k->type)
123 return kt->shortname;
124 }
125 return "unknown";
126}
127
128static const char *
129sshkey_ssh_name_from_type_nid(int type, int nid)
130{
131 const struct keytype *kt;
132
133 for (kt = keytypes; kt->type != -1; kt++) {
134 if (kt->type == type && (kt->nid == 0 || kt->nid == nid))
135 return kt->name;
136 }
137 return "ssh-unknown";
138}
139
140int
141sshkey_type_is_cert(int type)
142{
143 const struct keytype *kt;
144
145 for (kt = keytypes; kt->type != -1; kt++) {
146 if (kt->type == type)
147 return kt->cert;
148 }
149 return 0;
150}
151
152const char *
153sshkey_ssh_name(const struct sshkey *k)
154{
155 return sshkey_ssh_name_from_type_nid(k->type, k->ecdsa_nid);
156}
157
158const char *
159sshkey_ssh_name_plain(const struct sshkey *k)
160{
161 return sshkey_ssh_name_from_type_nid(sshkey_type_plain(k->type),
162 k->ecdsa_nid);
163}
164
165int
166sshkey_type_from_name(const char *name)
167{
168 const struct keytype *kt;
169
170 for (kt = keytypes; kt->type != -1; kt++) {
171 /* Only allow shortname matches for plain key types */
172 if ((kt->name != NULL && strcmp(name, kt->name) == 0) ||
173 (!kt->cert && strcasecmp(kt->shortname, name) == 0))
174 return kt->type;
175 }
176 return KEY_UNSPEC;
177}
178
179int
180sshkey_ecdsa_nid_from_name(const char *name)
181{
182 const struct keytype *kt;
183
184 for (kt = keytypes; kt->type != -1; kt++) {
185 if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT)
186 continue;
187 if (kt->name != NULL && strcmp(name, kt->name) == 0)
188 return kt->nid;
189 }
190 return -1;
191}
192
193char *
194key_alg_list(int certs_only, int plain_only)
195{
196 char *tmp, *ret = NULL;
197 size_t nlen, rlen = 0;
198 const struct keytype *kt;
199
200 for (kt = keytypes; kt->type != -1; kt++) {
201 if (kt->name == NULL)
202 continue;
203 if ((certs_only && !kt->cert) || (plain_only && kt->cert))
204 continue;
205 if (ret != NULL)
206 ret[rlen++] = '\n';
207 nlen = strlen(kt->name);
208 if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
209 free(ret);
210 return NULL;
211 }
212 ret = tmp;
213 memcpy(ret + rlen, kt->name, nlen + 1);
214 rlen += nlen;
215 }
216 return ret;
217}
218
219int
220sshkey_names_valid2(const char *names)
221{
222 char *s, *cp, *p;
223
224 if (names == NULL || strcmp(names, "") == 0)
225 return 0;
226 if ((s = cp = strdup(names)) == NULL)
227 return 0;
228 for ((p = strsep(&cp, ",")); p && *p != '\0';
229 (p = strsep(&cp, ","))) {
230 switch (sshkey_type_from_name(p)) {
231 case KEY_RSA1:
232 case KEY_UNSPEC:
233 free(s);
234 return 0;
235 }
236 }
237 free(s);
238 return 1;
239}
240
241u_int
242sshkey_size(const struct sshkey *k)
243{
244 switch (k->type) {
245#ifdef WITH_OPENSSL
246 case KEY_RSA1:
247 case KEY_RSA:
248 case KEY_RSA_CERT_V00:
249 case KEY_RSA_CERT:
250 return BN_num_bits(k->rsa->n);
251 case KEY_DSA:
252 case KEY_DSA_CERT_V00:
253 case KEY_DSA_CERT:
254 return BN_num_bits(k->dsa->p);
255 case KEY_ECDSA:
256 case KEY_ECDSA_CERT:
257 return sshkey_curve_nid_to_bits(k->ecdsa_nid);
258#endif /* WITH_OPENSSL */
259 case KEY_ED25519:
260 case KEY_ED25519_CERT:
261 return 256; /* XXX */
262 }
263 return 0;
264}
265
266int
267sshkey_cert_is_legacy(const struct sshkey *k)
268{
269 switch (k->type) {
270 case KEY_DSA_CERT_V00:
271 case KEY_RSA_CERT_V00:
272 return 1;
273 default:
274 return 0;
275 }
276}
277
278static int
279sshkey_type_is_valid_ca(int type)
280{
281 switch (type) {
282 case KEY_RSA:
283 case KEY_DSA:
284 case KEY_ECDSA:
285 case KEY_ED25519:
286 return 1;
287 default:
288 return 0;
289 }
290}
291
292int
293sshkey_is_cert(const struct sshkey *k)
294{
295 if (k == NULL)
296 return 0;
297 return sshkey_type_is_cert(k->type);
298}
299
300/* Return the cert-less equivalent to a certified key type */
301int
302sshkey_type_plain(int type)
303{
304 switch (type) {
305 case KEY_RSA_CERT_V00:
306 case KEY_RSA_CERT:
307 return KEY_RSA;
308 case KEY_DSA_CERT_V00:
309 case KEY_DSA_CERT:
310 return KEY_DSA;
311 case KEY_ECDSA_CERT:
312 return KEY_ECDSA;
313 case KEY_ED25519_CERT:
314 return KEY_ED25519;
315 default:
316 return type;
317 }
318}
319
320#ifdef WITH_OPENSSL
321/* XXX: these are really begging for a table-driven approach */
322int
323sshkey_curve_name_to_nid(const char *name)
324{
325 if (strcmp(name, "nistp256") == 0)
326 return NID_X9_62_prime256v1;
327 else if (strcmp(name, "nistp384") == 0)
328 return NID_secp384r1;
329# ifdef OPENSSL_HAS_NISTP521
330 else if (strcmp(name, "nistp521") == 0)
331 return NID_secp521r1;
332# endif /* OPENSSL_HAS_NISTP521 */
333 else
334 return -1;
335}
336
337u_int
338sshkey_curve_nid_to_bits(int nid)
339{
340 switch (nid) {
341 case NID_X9_62_prime256v1:
342 return 256;
343 case NID_secp384r1:
344 return 384;
345# ifdef OPENSSL_HAS_NISTP521
346 case NID_secp521r1:
347 return 521;
348# endif /* OPENSSL_HAS_NISTP521 */
349 default:
350 return 0;
351 }
352}
353
354int
355sshkey_ecdsa_bits_to_nid(int bits)
356{
357 switch (bits) {
358 case 256:
359 return NID_X9_62_prime256v1;
360 case 384:
361 return NID_secp384r1;
362# ifdef OPENSSL_HAS_NISTP521
363 case 521:
364 return NID_secp521r1;
365# endif /* OPENSSL_HAS_NISTP521 */
366 default:
367 return -1;
368 }
369}
370
371const char *
372sshkey_curve_nid_to_name(int nid)
373{
374 switch (nid) {
375 case NID_X9_62_prime256v1:
376 return "nistp256";
377 case NID_secp384r1:
378 return "nistp384";
379# ifdef OPENSSL_HAS_NISTP521
380 case NID_secp521r1:
381 return "nistp521";
382# endif /* OPENSSL_HAS_NISTP521 */
383 default:
384 return NULL;
385 }
386}
387
388int
389sshkey_ec_nid_to_hash_alg(int nid)
390{
391 int kbits = sshkey_curve_nid_to_bits(nid);
392
393 if (kbits <= 0)
394 return -1;
395
396 /* RFC5656 section 6.2.1 */
397 if (kbits <= 256)
398 return SSH_DIGEST_SHA256;
399 else if (kbits <= 384)
400 return SSH_DIGEST_SHA384;
401 else
402 return SSH_DIGEST_SHA512;
403}
404#endif /* WITH_OPENSSL */
405
406static void
407cert_free(struct sshkey_cert *cert)
408{
409 u_int i;
410
411 if (cert == NULL)
412 return;
413 if (cert->certblob != NULL)
414 sshbuf_free(cert->certblob);
415 if (cert->critical != NULL)
416 sshbuf_free(cert->critical);
417 if (cert->extensions != NULL)
418 sshbuf_free(cert->extensions);
419 if (cert->key_id != NULL)
420 free(cert->key_id);
421 for (i = 0; i < cert->nprincipals; i++)
422 free(cert->principals[i]);
423 if (cert->principals != NULL)
424 free(cert->principals);
425 if (cert->signature_key != NULL)
426 sshkey_free(cert->signature_key);
427 explicit_bzero(cert, sizeof(*cert));
428 free(cert);
429}
430
431static struct sshkey_cert *
432cert_new(void)
433{
434 struct sshkey_cert *cert;
435
436 if ((cert = calloc(1, sizeof(*cert))) == NULL)
437 return NULL;
438 if ((cert->certblob = sshbuf_new()) == NULL ||
439 (cert->critical = sshbuf_new()) == NULL ||
440 (cert->extensions = sshbuf_new()) == NULL) {
441 cert_free(cert);
442 return NULL;
443 }
444 cert->key_id = NULL;
445 cert->principals = NULL;
446 cert->signature_key = NULL;
447 return cert;
448}
449
450struct sshkey *
451sshkey_new(int type)
452{
453 struct sshkey *k;
454#ifdef WITH_OPENSSL
455 RSA *rsa;
456 DSA *dsa;
457#endif /* WITH_OPENSSL */
458
459 if ((k = calloc(1, sizeof(*k))) == NULL)
460 return NULL;
461 k->type = type;
462 k->ecdsa = NULL;
463 k->ecdsa_nid = -1;
464 k->dsa = NULL;
465 k->rsa = NULL;
466 k->cert = NULL;
467 k->ed25519_sk = NULL;
468 k->ed25519_pk = NULL;
469 switch (k->type) {
470#ifdef WITH_OPENSSL
471 case KEY_RSA1:
472 case KEY_RSA:
473 case KEY_RSA_CERT_V00:
474 case KEY_RSA_CERT:
475 if ((rsa = RSA_new()) == NULL ||
476 (rsa->n = BN_new()) == NULL ||
477 (rsa->e = BN_new()) == NULL) {
478 if (rsa != NULL)
479 RSA_free(rsa);
480 free(k);
481 return NULL;
482 }
483 k->rsa = rsa;
484 break;
485 case KEY_DSA:
486 case KEY_DSA_CERT_V00:
487 case KEY_DSA_CERT:
488 if ((dsa = DSA_new()) == NULL ||
489 (dsa->p = BN_new()) == NULL ||
490 (dsa->q = BN_new()) == NULL ||
491 (dsa->g = BN_new()) == NULL ||
492 (dsa->pub_key = BN_new()) == NULL) {
493 if (dsa != NULL)
494 DSA_free(dsa);
495 free(k);
496 return NULL;
497 }
498 k->dsa = dsa;
499 break;
500 case KEY_ECDSA:
501 case KEY_ECDSA_CERT:
502 /* Cannot do anything until we know the group */
503 break;
504#endif /* WITH_OPENSSL */
505 case KEY_ED25519:
506 case KEY_ED25519_CERT:
507 /* no need to prealloc */
508 break;
509 case KEY_UNSPEC:
510 break;
511 default:
512 free(k);
513 return NULL;
514 break;
515 }
516
517 if (sshkey_is_cert(k)) {
518 if ((k->cert = cert_new()) == NULL) {
519 sshkey_free(k);
520 return NULL;
521 }
522 }
523
524 return k;
525}
526
527int
528sshkey_add_private(struct sshkey *k)
529{
530 switch (k->type) {
531#ifdef WITH_OPENSSL
532 case KEY_RSA1:
533 case KEY_RSA:
534 case KEY_RSA_CERT_V00:
535 case KEY_RSA_CERT:
536#define bn_maybe_alloc_failed(p) (p == NULL && (p = BN_new()) == NULL)
537 if (bn_maybe_alloc_failed(k->rsa->d) ||
538 bn_maybe_alloc_failed(k->rsa->iqmp) ||
539 bn_maybe_alloc_failed(k->rsa->q) ||
540 bn_maybe_alloc_failed(k->rsa->p) ||
541 bn_maybe_alloc_failed(k->rsa->dmq1) ||
542 bn_maybe_alloc_failed(k->rsa->dmp1))
543 return SSH_ERR_ALLOC_FAIL;
544 break;
545 case KEY_DSA:
546 case KEY_DSA_CERT_V00:
547 case KEY_DSA_CERT:
548 if (bn_maybe_alloc_failed(k->dsa->priv_key))
549 return SSH_ERR_ALLOC_FAIL;
550 break;
551#undef bn_maybe_alloc_failed
552 case KEY_ECDSA:
553 case KEY_ECDSA_CERT:
554 /* Cannot do anything until we know the group */
555 break;
556#endif /* WITH_OPENSSL */
557 case KEY_ED25519:
558 case KEY_ED25519_CERT:
559 /* no need to prealloc */
560 break;
561 case KEY_UNSPEC:
562 break;
563 default:
564 return SSH_ERR_INVALID_ARGUMENT;
565 }
566 return 0;
567}
568
569struct sshkey *
570sshkey_new_private(int type)
571{
572 struct sshkey *k = sshkey_new(type);
573
574 if (k == NULL)
575 return NULL;
576 if (sshkey_add_private(k) != 0) {
577 sshkey_free(k);
578 return NULL;
579 }
580 return k;
581}
582
583void
584sshkey_free(struct sshkey *k)
585{
586 if (k == NULL)
587 return;
588 switch (k->type) {
589#ifdef WITH_OPENSSL
590 case KEY_RSA1:
591 case KEY_RSA:
592 case KEY_RSA_CERT_V00:
593 case KEY_RSA_CERT:
594 if (k->rsa != NULL)
595 RSA_free(k->rsa);
596 k->rsa = NULL;
597 break;
598 case KEY_DSA:
599 case KEY_DSA_CERT_V00:
600 case KEY_DSA_CERT:
601 if (k->dsa != NULL)
602 DSA_free(k->dsa);
603 k->dsa = NULL;
604 break;
605# ifdef OPENSSL_HAS_ECC
606 case KEY_ECDSA:
607 case KEY_ECDSA_CERT:
608 if (k->ecdsa != NULL)
609 EC_KEY_free(k->ecdsa);
610 k->ecdsa = NULL;
611 break;
612# endif /* OPENSSL_HAS_ECC */
613#endif /* WITH_OPENSSL */
614 case KEY_ED25519:
615 case KEY_ED25519_CERT:
616 if (k->ed25519_pk) {
617 explicit_bzero(k->ed25519_pk, ED25519_PK_SZ);
618 free(k->ed25519_pk);
619 k->ed25519_pk = NULL;
620 }
621 if (k->ed25519_sk) {
622 explicit_bzero(k->ed25519_sk, ED25519_SK_SZ);
623 free(k->ed25519_sk);
624 k->ed25519_sk = NULL;
625 }
626 break;
627 case KEY_UNSPEC:
628 break;
629 default:
630 break;
631 }
632 if (sshkey_is_cert(k))
633 cert_free(k->cert);
634 explicit_bzero(k, sizeof(*k));
635 free(k);
636}
637
638static int
639cert_compare(struct sshkey_cert *a, struct sshkey_cert *b)
640{
641 if (a == NULL && b == NULL)
642 return 1;
643 if (a == NULL || b == NULL)
644 return 0;
645 if (sshbuf_len(a->certblob) != sshbuf_len(b->certblob))
646 return 0;
647 if (timingsafe_bcmp(sshbuf_ptr(a->certblob), sshbuf_ptr(b->certblob),
648 sshbuf_len(a->certblob)) != 0)
649 return 0;
650 return 1;
651}
652
653/*
654 * Compare public portions of key only, allowing comparisons between
655 * certificates and plain keys too.
656 */
657int
658sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
659{
660#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
661 BN_CTX *bnctx;
662#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
663
664 if (a == NULL || b == NULL ||
665 sshkey_type_plain(a->type) != sshkey_type_plain(b->type))
666 return 0;
667
668 switch (a->type) {
669#ifdef WITH_OPENSSL
670 case KEY_RSA1:
671 case KEY_RSA_CERT_V00:
672 case KEY_RSA_CERT:
673 case KEY_RSA:
674 return a->rsa != NULL && b->rsa != NULL &&
675 BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
676 BN_cmp(a->rsa->n, b->rsa->n) == 0;
677 case KEY_DSA_CERT_V00:
678 case KEY_DSA_CERT:
679 case KEY_DSA:
680 return a->dsa != NULL && b->dsa != NULL &&
681 BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
682 BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
683 BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
684 BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
685# ifdef OPENSSL_HAS_ECC
686 case KEY_ECDSA_CERT:
687 case KEY_ECDSA:
688 if (a->ecdsa == NULL || b->ecdsa == NULL ||
689 EC_KEY_get0_public_key(a->ecdsa) == NULL ||
690 EC_KEY_get0_public_key(b->ecdsa) == NULL)
691 return 0;
692 if ((bnctx = BN_CTX_new()) == NULL)
693 return 0;
694 if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa),
695 EC_KEY_get0_group(b->ecdsa), bnctx) != 0 ||
696 EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa),
697 EC_KEY_get0_public_key(a->ecdsa),
698 EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) {
699 BN_CTX_free(bnctx);
700 return 0;
701 }
702 BN_CTX_free(bnctx);
703 return 1;
704# endif /* OPENSSL_HAS_ECC */
705#endif /* WITH_OPENSSL */
706 case KEY_ED25519:
707 case KEY_ED25519_CERT:
708 return a->ed25519_pk != NULL && b->ed25519_pk != NULL &&
709 memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0;
710 default:
711 return 0;
712 }
713 /* NOTREACHED */
714}
715
716int
717sshkey_equal(const struct sshkey *a, const struct sshkey *b)
718{
719 if (a == NULL || b == NULL || a->type != b->type)
720 return 0;
721 if (sshkey_is_cert(a)) {
722 if (!cert_compare(a->cert, b->cert))
723 return 0;
724 }
725 return sshkey_equal_public(a, b);
726}
727
728static int
729to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain)
730{
731 int type, ret = SSH_ERR_INTERNAL_ERROR;
732 const char *typename;
733
734 if (key == NULL)
735 return SSH_ERR_INVALID_ARGUMENT;
736
737 type = force_plain ? sshkey_type_plain(key->type) : key->type;
738 typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
739
740 switch (type) {
741#ifdef WITH_OPENSSL
742 case KEY_DSA_CERT_V00:
743 case KEY_RSA_CERT_V00:
744 case KEY_DSA_CERT:
745 case KEY_ECDSA_CERT:
746 case KEY_RSA_CERT:
747#endif /* WITH_OPENSSL */
748 case KEY_ED25519_CERT:
749 /* Use the existing blob */
750 /* XXX modified flag? */
751 if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0)
752 return ret;
753 break;
754#ifdef WITH_OPENSSL
755 case KEY_DSA:
756 if (key->dsa == NULL)
757 return SSH_ERR_INVALID_ARGUMENT;
758 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
759 (ret = sshbuf_put_bignum2(b, key->dsa->p)) != 0 ||
760 (ret = sshbuf_put_bignum2(b, key->dsa->q)) != 0 ||
761 (ret = sshbuf_put_bignum2(b, key->dsa->g)) != 0 ||
762 (ret = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0)
763 return ret;
764 break;
765# ifdef OPENSSL_HAS_ECC
766 case KEY_ECDSA:
767 if (key->ecdsa == NULL)
768 return SSH_ERR_INVALID_ARGUMENT;
769 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
770 (ret = sshbuf_put_cstring(b,
771 sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
772 (ret = sshbuf_put_eckey(b, key->ecdsa)) != 0)
773 return ret;
774 break;
775# endif
776 case KEY_RSA:
777 if (key->rsa == NULL)
778 return SSH_ERR_INVALID_ARGUMENT;
779 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
780 (ret = sshbuf_put_bignum2(b, key->rsa->e)) != 0 ||
781 (ret = sshbuf_put_bignum2(b, key->rsa->n)) != 0)
782 return ret;
783 break;
784#endif /* WITH_OPENSSL */
785 case KEY_ED25519:
786 if (key->ed25519_pk == NULL)
787 return SSH_ERR_INVALID_ARGUMENT;
788 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
789 (ret = sshbuf_put_string(b,
790 key->ed25519_pk, ED25519_PK_SZ)) != 0)
791 return ret;
792 break;
793 default:
794 return SSH_ERR_KEY_TYPE_UNKNOWN;
795 }
796 return 0;
797}
798
799int
800sshkey_to_blob_buf(const struct sshkey *key, struct sshbuf *b)
801{
802 return to_blob_buf(key, b, 0);
803}
804
805int
806sshkey_plain_to_blob_buf(const struct sshkey *key, struct sshbuf *b)
807{
808 return to_blob_buf(key, b, 1);
809}
810
811static int
812to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain)
813{
814 int ret = SSH_ERR_INTERNAL_ERROR;
815 size_t len;
816 struct sshbuf *b = NULL;
817
818 if (lenp != NULL)
819 *lenp = 0;
820 if (blobp != NULL)
821 *blobp = NULL;
822 if ((b = sshbuf_new()) == NULL)
823 return SSH_ERR_ALLOC_FAIL;
824 if ((ret = to_blob_buf(key, b, force_plain)) != 0)
825 goto out;
826 len = sshbuf_len(b);
827 if (lenp != NULL)
828 *lenp = len;
829 if (blobp != NULL) {
830 if ((*blobp = malloc(len)) == NULL) {
831 ret = SSH_ERR_ALLOC_FAIL;
832 goto out;
833 }
834 memcpy(*blobp, sshbuf_ptr(b), len);
835 }
836 ret = 0;
837 out:
838 sshbuf_free(b);
839 return ret;
840}
841
842int
843sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
844{
845 return to_blob(key, blobp, lenp, 0);
846}
847
848int
849sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
850{
851 return to_blob(key, blobp, lenp, 1);
852}
853
854int
855sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type,
856 u_char **retp, size_t *lenp)
857{
858 u_char *blob = NULL, *ret = NULL;
859 size_t blob_len = 0;
860 int hash_alg = -1, r = SSH_ERR_INTERNAL_ERROR;
861
862 if (retp != NULL)
863 *retp = NULL;
864 if (lenp != NULL)
865 *lenp = 0;
866
867 switch (dgst_type) {
868 case SSH_FP_MD5:
869 hash_alg = SSH_DIGEST_MD5;
870 break;
871 case SSH_FP_SHA1:
872 hash_alg = SSH_DIGEST_SHA1;
873 break;
874 case SSH_FP_SHA256:
875 hash_alg = SSH_DIGEST_SHA256;
876 break;
877 default:
878 r = SSH_ERR_INVALID_ARGUMENT;
879 goto out;
880 }
881
882 if (k->type == KEY_RSA1) {
883#ifdef WITH_OPENSSL
884 int nlen = BN_num_bytes(k->rsa->n);
885 int elen = BN_num_bytes(k->rsa->e);
886
887 blob_len = nlen + elen;
888 if (nlen >= INT_MAX - elen ||
889 (blob = malloc(blob_len)) == NULL) {
890 r = SSH_ERR_ALLOC_FAIL;
891 goto out;
892 }
893 BN_bn2bin(k->rsa->n, blob);
894 BN_bn2bin(k->rsa->e, blob + nlen);
895#endif /* WITH_OPENSSL */
896 } else if ((r = to_blob(k, &blob, &blob_len, 1)) != 0)
897 goto out;
898 if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) {
899 r = SSH_ERR_ALLOC_FAIL;
900 goto out;
901 }
902 if ((r = ssh_digest_memory(hash_alg, blob, blob_len,
903 ret, SSH_DIGEST_MAX_LENGTH)) != 0)
904 goto out;
905 /* success */
906 if (retp != NULL) {
907 *retp = ret;
908 ret = NULL;
909 }
910 if (lenp != NULL)
911 *lenp = ssh_digest_bytes(hash_alg);
912 r = 0;
913 out:
914 free(ret);
915 if (blob != NULL) {
916 explicit_bzero(blob, blob_len);
917 free(blob);
918 }
919 return r;
920}
921
922static char *
923fingerprint_hex(u_char *dgst_raw, size_t dgst_raw_len)
924{
925 char *retval;
926 size_t i;
927
928 if ((retval = calloc(1, dgst_raw_len * 3 + 1)) == NULL)
929 return NULL;
930 for (i = 0; i < dgst_raw_len; i++) {
931 char hex[4];
932 snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
933 strlcat(retval, hex, dgst_raw_len * 3 + 1);
934 }
935
936 /* Remove the trailing ':' character */
937 retval[(dgst_raw_len * 3) - 1] = '\0';
938 return retval;
939}
940
941static char *
942fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len)
943{
944 char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
945 char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
946 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
947 u_int i, j = 0, rounds, seed = 1;
948 char *retval;
949
950 rounds = (dgst_raw_len / 2) + 1;
951 if ((retval = calloc(rounds, 6)) == NULL)
952 return NULL;
953 retval[j++] = 'x';
954 for (i = 0; i < rounds; i++) {
955 u_int idx0, idx1, idx2, idx3, idx4;
956 if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
957 idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
958 seed) % 6;
959 idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
960 idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
961 (seed / 6)) % 6;
962 retval[j++] = vowels[idx0];
963 retval[j++] = consonants[idx1];
964 retval[j++] = vowels[idx2];
965 if ((i + 1) < rounds) {
966 idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
967 idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
968 retval[j++] = consonants[idx3];
969 retval[j++] = '-';
970 retval[j++] = consonants[idx4];
971 seed = ((seed * 5) +
972 ((((u_int)(dgst_raw[2 * i])) * 7) +
973 ((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
974 }
975 } else {
976 idx0 = seed % 6;
977 idx1 = 16;
978 idx2 = seed / 6;
979 retval[j++] = vowels[idx0];
980 retval[j++] = consonants[idx1];
981 retval[j++] = vowels[idx2];
982 }
983 }
984 retval[j++] = 'x';
985 retval[j++] = '\0';
986 return retval;
987}
988
989/*
990 * Draw an ASCII-Art representing the fingerprint so human brain can
991 * profit from its built-in pattern recognition ability.
992 * This technique is called "random art" and can be found in some
993 * scientific publications like this original paper:
994 *
995 * "Hash Visualization: a New Technique to improve Real-World Security",
996 * Perrig A. and Song D., 1999, International Workshop on Cryptographic
997 * Techniques and E-Commerce (CrypTEC '99)
998 * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
999 *
1000 * The subject came up in a talk by Dan Kaminsky, too.
1001 *
1002 * If you see the picture is different, the key is different.
1003 * If the picture looks the same, you still know nothing.
1004 *
1005 * The algorithm used here is a worm crawling over a discrete plane,
1006 * leaving a trace (augmenting the field) everywhere it goes.
1007 * Movement is taken from dgst_raw 2bit-wise. Bumping into walls
1008 * makes the respective movement vector be ignored for this turn.
1009 * Graphs are not unambiguous, because circles in graphs can be
1010 * walked in either direction.
1011 */
1012
1013/*
1014 * Field sizes for the random art. Have to be odd, so the starting point
1015 * can be in the exact middle of the picture, and FLDBASE should be >=8 .
1016 * Else pictures would be too dense, and drawing the frame would
1017 * fail, too, because the key type would not fit in anymore.
1018 */
1019#define FLDBASE 8
1020#define FLDSIZE_Y (FLDBASE + 1)
1021#define FLDSIZE_X (FLDBASE * 2 + 1)
1022static char *
1023fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
1024 const struct sshkey *k)
1025{
1026 /*
1027 * Chars to be used after each other every time the worm
1028 * intersects with itself. Matter of taste.
1029 */
1030 char *augmentation_string = " .o+=*BOX@%&#/^SE";
1031 char *retval, *p, title[FLDSIZE_X];
1032 u_char field[FLDSIZE_X][FLDSIZE_Y];
1033 size_t i, tlen;
1034 u_int b;
1035 int x, y, r;
1036 size_t len = strlen(augmentation_string) - 1;
1037
1038 if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL)
1039 return NULL;
1040
1041 /* initialize field */
1042 memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
1043 x = FLDSIZE_X / 2;
1044 y = FLDSIZE_Y / 2;
1045
1046 /* process raw key */
1047 for (i = 0; i < dgst_raw_len; i++) {
1048 int input;
1049 /* each byte conveys four 2-bit move commands */
1050 input = dgst_raw[i];
1051 for (b = 0; b < 4; b++) {
1052 /* evaluate 2 bit, rest is shifted later */
1053 x += (input & 0x1) ? 1 : -1;
1054 y += (input & 0x2) ? 1 : -1;
1055
1056 /* assure we are still in bounds */
1057 x = MAX(x, 0);
1058 y = MAX(y, 0);
1059 x = MIN(x, FLDSIZE_X - 1);
1060 y = MIN(y, FLDSIZE_Y - 1);
1061
1062 /* augment the field */
1063 if (field[x][y] < len - 2)
1064 field[x][y]++;
1065 input = input >> 2;
1066 }
1067 }
1068
1069 /* mark starting point and end point*/
1070 field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
1071 field[x][y] = len;
1072
1073 /* assemble title */
1074 r = snprintf(title, sizeof(title), "[%s %u]",
1075 sshkey_type(k), sshkey_size(k));
1076 /* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */
1077 if (r < 0 || r > (int)sizeof(title))
1078 snprintf(title, sizeof(title), "[%s]", sshkey_type(k));
1079 tlen = strlen(title);
1080
1081 /* output upper border */
1082 p = retval;
1083 *p++ = '+';
1084 for (i = 0; i < (FLDSIZE_X - tlen) / 2; i++)
1085 *p++ = '-';
1086 memcpy(p, title, tlen);
1087 p += tlen;
1088 for (i = p - retval - 1; i < FLDSIZE_X; i++)
1089 *p++ = '-';
1090 *p++ = '+';
1091 *p++ = '\n';
1092
1093 /* output content */
1094 for (y = 0; y < FLDSIZE_Y; y++) {
1095 *p++ = '|';
1096 for (x = 0; x < FLDSIZE_X; x++)
1097 *p++ = augmentation_string[MIN(field[x][y], len)];
1098 *p++ = '|';
1099 *p++ = '\n';
1100 }
1101
1102 /* output lower border */
1103 *p++ = '+';
1104 for (i = 0; i < FLDSIZE_X; i++)
1105 *p++ = '-';
1106 *p++ = '+';
1107
1108 return retval;
1109}
1110
1111char *
1112sshkey_fingerprint(const struct sshkey *k, enum sshkey_fp_type dgst_type,
1113 enum sshkey_fp_rep dgst_rep)
1114{
1115 char *retval = NULL;
1116 u_char *dgst_raw;
1117 size_t dgst_raw_len;
1118
1119 if (sshkey_fingerprint_raw(k, dgst_type, &dgst_raw, &dgst_raw_len) != 0)
1120 return NULL;
1121 switch (dgst_rep) {
1122 case SSH_FP_HEX:
1123 retval = fingerprint_hex(dgst_raw, dgst_raw_len);
1124 break;
1125 case SSH_FP_BUBBLEBABBLE:
1126 retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
1127 break;
1128 case SSH_FP_RANDOMART:
1129 retval = fingerprint_randomart(dgst_raw, dgst_raw_len, k);
1130 break;
1131 default:
1132 explicit_bzero(dgst_raw, dgst_raw_len);
1133 free(dgst_raw);
1134 return NULL;
1135 }
1136 explicit_bzero(dgst_raw, dgst_raw_len);
1137 free(dgst_raw);
1138 return retval;
1139}
1140
1141#ifdef WITH_SSH1
1142/*
1143 * Reads a multiple-precision integer in decimal from the buffer, and advances
1144 * the pointer. The integer must already be initialized. This function is
1145 * permitted to modify the buffer. This leaves *cpp to point just beyond the
1146 * last processed character.
1147 */
1148static int
1149read_decimal_bignum(char **cpp, BIGNUM *v)
1150{
1151 char *cp;
1152 size_t e;
1153 int skip = 1; /* skip white space */
1154
1155 cp = *cpp;
1156 while (*cp == ' ' || *cp == '\t')
1157 cp++;
1158 e = strspn(cp, "0123456789");
1159 if (e == 0)
1160 return SSH_ERR_INVALID_FORMAT;
1161 if (e > SSHBUF_MAX_BIGNUM * 3)
1162 return SSH_ERR_BIGNUM_TOO_LARGE;
1163 if (cp[e] == '\0')
1164 skip = 0;
1165 else if (index(" \t\r\n", cp[e]) == NULL)
1166 return SSH_ERR_INVALID_FORMAT;
1167 cp[e] = '\0';
1168 if (BN_dec2bn(&v, cp) <= 0)
1169 return SSH_ERR_INVALID_FORMAT;
1170 *cpp = cp + e + skip;
1171 return 0;
1172}
1173#endif /* WITH_SSH1 */
1174
1175/* returns 0 ok, and < 0 error */
1176int
1177sshkey_read(struct sshkey *ret, char **cpp)
1178{
1179 struct sshkey *k;
1180 int retval = SSH_ERR_INVALID_FORMAT;
1181 char *cp, *space;
1182 int r, type, curve_nid = -1;
1183 struct sshbuf *blob;
1184#ifdef WITH_SSH1
1185 char *ep;
1186 u_long bits;
1187#endif /* WITH_SSH1 */
1188
1189 cp = *cpp;
1190
1191 switch (ret->type) {
1192 case KEY_RSA1:
1193#ifdef WITH_SSH1
1194 /* Get number of bits. */
1195 bits = strtoul(cp, &ep, 10);
1196 if (*cp == '\0' || index(" \t\r\n", *ep) == NULL ||
1197 bits == 0 || bits > SSHBUF_MAX_BIGNUM * 8)
1198 return SSH_ERR_INVALID_FORMAT; /* Bad bit count... */
1199 /* Get public exponent, public modulus. */
1200 if ((r = read_decimal_bignum(&ep, ret->rsa->e)) < 0)
1201 return r;
1202 if ((r = read_decimal_bignum(&ep, ret->rsa->n)) < 0)
1203 return r;
1204 *cpp = ep;
1205 /* validate the claimed number of bits */
1206 if (BN_num_bits(ret->rsa->n) != (int)bits)
1207 return SSH_ERR_KEY_BITS_MISMATCH;
1208 retval = 0;
1209#endif /* WITH_SSH1 */
1210 break;
1211 case KEY_UNSPEC:
1212 case KEY_RSA:
1213 case KEY_DSA:
1214 case KEY_ECDSA:
1215 case KEY_ED25519:
1216 case KEY_DSA_CERT_V00:
1217 case KEY_RSA_CERT_V00:
1218 case KEY_DSA_CERT:
1219 case KEY_ECDSA_CERT:
1220 case KEY_RSA_CERT:
1221 case KEY_ED25519_CERT:
1222 space = strchr(cp, ' ');
1223 if (space == NULL)
1224 return SSH_ERR_INVALID_FORMAT;
1225 *space = '\0';
1226 type = sshkey_type_from_name(cp);
1227 if (sshkey_type_plain(type) == KEY_ECDSA &&
1228 (curve_nid = sshkey_ecdsa_nid_from_name(cp)) == -1)
1229 return SSH_ERR_EC_CURVE_INVALID;
1230 *space = ' ';
1231 if (type == KEY_UNSPEC)
1232 return SSH_ERR_INVALID_FORMAT;
1233 cp = space+1;
1234 if (*cp == '\0')
1235 return SSH_ERR_INVALID_FORMAT;
1236 if (ret->type == KEY_UNSPEC) {
1237 ret->type = type;
1238 } else if (ret->type != type)
1239 return SSH_ERR_KEY_TYPE_MISMATCH;
1240 if ((blob = sshbuf_new()) == NULL)
1241 return SSH_ERR_ALLOC_FAIL;
1242 /* trim comment */
1243 space = strchr(cp, ' ');
1244 if (space)
1245 *space = '\0';
1246 if ((r = sshbuf_b64tod(blob, cp)) != 0) {
1247 sshbuf_free(blob);
1248 return r;
1249 }
1250 if ((r = sshkey_from_blob(sshbuf_ptr(blob),
1251 sshbuf_len(blob), &k)) != 0) {
1252 sshbuf_free(blob);
1253 return r;
1254 }
1255 sshbuf_free(blob);
1256 if (k->type != type) {
1257 sshkey_free(k);
1258 return SSH_ERR_KEY_TYPE_MISMATCH;
1259 }
1260 if (sshkey_type_plain(type) == KEY_ECDSA &&
1261 curve_nid != k->ecdsa_nid) {
1262 sshkey_free(k);
1263 return SSH_ERR_EC_CURVE_MISMATCH;
1264 }
1265/*XXXX*/
1266 if (sshkey_is_cert(ret)) {
1267 if (!sshkey_is_cert(k)) {
1268 sshkey_free(k);
1269 return SSH_ERR_EXPECTED_CERT;
1270 }
1271 if (ret->cert != NULL)
1272 cert_free(ret->cert);
1273 ret->cert = k->cert;
1274 k->cert = NULL;
1275 }
1276#ifdef WITH_OPENSSL
1277 if (sshkey_type_plain(ret->type) == KEY_RSA) {
1278 if (ret->rsa != NULL)
1279 RSA_free(ret->rsa);
1280 ret->rsa = k->rsa;
1281 k->rsa = NULL;
1282#ifdef DEBUG_PK
1283 RSA_print_fp(stderr, ret->rsa, 8);
1284#endif
1285 }
1286 if (sshkey_type_plain(ret->type) == KEY_DSA) {
1287 if (ret->dsa != NULL)
1288 DSA_free(ret->dsa);
1289 ret->dsa = k->dsa;
1290 k->dsa = NULL;
1291#ifdef DEBUG_PK
1292 DSA_print_fp(stderr, ret->dsa, 8);
1293#endif
1294 }
1295# ifdef OPENSSL_HAS_ECC
1296 if (sshkey_type_plain(ret->type) == KEY_ECDSA) {
1297 if (ret->ecdsa != NULL)
1298 EC_KEY_free(ret->ecdsa);
1299 ret->ecdsa = k->ecdsa;
1300 ret->ecdsa_nid = k->ecdsa_nid;
1301 k->ecdsa = NULL;
1302 k->ecdsa_nid = -1;
1303#ifdef DEBUG_PK
1304 sshkey_dump_ec_key(ret->ecdsa);
1305#endif
1306 }
1307# endif /* OPENSSL_HAS_ECC */
1308#endif /* WITH_OPENSSL */
1309 if (sshkey_type_plain(ret->type) == KEY_ED25519) {
1310 free(ret->ed25519_pk);
1311 ret->ed25519_pk = k->ed25519_pk;
1312 k->ed25519_pk = NULL;
1313#ifdef DEBUG_PK
1314 /* XXX */
1315#endif
1316 }
1317 retval = 0;
1318/*XXXX*/
1319 sshkey_free(k);
1320 if (retval != 0)
1321 break;
1322 /* advance cp: skip whitespace and data */
1323 while (*cp == ' ' || *cp == '\t')
1324 cp++;
1325 while (*cp != '\0' && *cp != ' ' && *cp != '\t')
1326 cp++;
1327 *cpp = cp;
1328 break;
1329 default:
1330 return SSH_ERR_INVALID_ARGUMENT;
1331 }
1332 return retval;
1333}
1334
1335int
1336sshkey_write(const struct sshkey *key, FILE *f)
1337{
1338 int ret = SSH_ERR_INTERNAL_ERROR;
1339 struct sshbuf *b = NULL, *bb = NULL;
1340 char *uu = NULL;
1341#ifdef WITH_SSH1
1342 u_int bits = 0;
1343 char *dec_e = NULL, *dec_n = NULL;
1344#endif /* WITH_SSH1 */
1345
1346 if (sshkey_is_cert(key)) {
1347 if (key->cert == NULL)
1348 return SSH_ERR_EXPECTED_CERT;
1349 if (sshbuf_len(key->cert->certblob) == 0)
1350 return SSH_ERR_KEY_LACKS_CERTBLOB;
1351 }
1352 if ((b = sshbuf_new()) == NULL)
1353 return SSH_ERR_ALLOC_FAIL;
1354 switch (key->type) {
1355#ifdef WITH_SSH1
1356 case KEY_RSA1:
1357 if (key->rsa == NULL || key->rsa->e == NULL ||
1358 key->rsa->n == NULL) {
1359 ret = SSH_ERR_INVALID_ARGUMENT;
1360 goto out;
1361 }
1362 if ((dec_e = BN_bn2dec(key->rsa->e)) == NULL ||
1363 (dec_n = BN_bn2dec(key->rsa->n)) == NULL) {
1364 ret = SSH_ERR_ALLOC_FAIL;
1365 goto out;
1366 }
1367 /* size of modulus 'n' */
1368 if ((bits = BN_num_bits(key->rsa->n)) <= 0) {
1369 ret = SSH_ERR_INVALID_ARGUMENT;
1370 goto out;
1371 }
1372 if ((ret = sshbuf_putf(b, "%u %s %s", bits, dec_e, dec_n)) != 0)
1373 goto out;
1374#endif /* WITH_SSH1 */
1375 break;
1376#ifdef WITH_OPENSSL
1377 case KEY_DSA:
1378 case KEY_DSA_CERT_V00:
1379 case KEY_DSA_CERT:
1380 case KEY_ECDSA:
1381 case KEY_ECDSA_CERT:
1382 case KEY_RSA:
1383 case KEY_RSA_CERT_V00:
1384 case KEY_RSA_CERT:
1385#endif /* WITH_OPENSSL */
1386 case KEY_ED25519:
1387 case KEY_ED25519_CERT:
1388 if ((bb = sshbuf_new()) == NULL) {
1389 ret = SSH_ERR_ALLOC_FAIL;
1390 goto out;
1391 }
1392 if ((ret = sshkey_to_blob_buf(key, bb)) != 0)
1393 goto out;
1394 if ((uu = sshbuf_dtob64(bb)) == NULL) {
1395 ret = SSH_ERR_ALLOC_FAIL;
1396 goto out;
1397 }
1398 if ((ret = sshbuf_putf(b, "%s ", sshkey_ssh_name(key))) != 0)
1399 goto out;
1400 if ((ret = sshbuf_put(b, uu, strlen(uu))) != 0)
1401 goto out;
1402 break;
1403 default:
1404 ret = SSH_ERR_KEY_TYPE_UNKNOWN;
1405 goto out;
1406 }
1407 if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) {
1408 if (feof(f))
1409 errno = EPIPE;
1410 ret = SSH_ERR_SYSTEM_ERROR;
1411 goto out;
1412 }
1413 ret = 0;
1414 out:
1415 if (b != NULL)
1416 sshbuf_free(b);
1417 if (bb != NULL)
1418 sshbuf_free(bb);
1419 if (uu != NULL)
1420 free(uu);
1421#ifdef WITH_SSH1
1422 if (dec_e != NULL)
1423 OPENSSL_free(dec_e);
1424 if (dec_n != NULL)
1425 OPENSSL_free(dec_n);
1426#endif /* WITH_SSH1 */
1427 return ret;
1428}
1429
1430const char *
1431sshkey_cert_type(const struct sshkey *k)
1432{
1433 switch (k->cert->type) {
1434 case SSH2_CERT_TYPE_USER:
1435 return "user";
1436 case SSH2_CERT_TYPE_HOST:
1437 return "host";
1438 default:
1439 return "unknown";
1440 }
1441}
1442
1443#ifdef WITH_OPENSSL
1444static int
1445rsa_generate_private_key(u_int bits, RSA **rsap)
1446{
1447 RSA *private = NULL;
1448 BIGNUM *f4 = NULL;
1449 int ret = SSH_ERR_INTERNAL_ERROR;
1450
1451 if (rsap == NULL ||
1452 bits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
1453 bits > SSHBUF_MAX_BIGNUM * 8)
1454 return SSH_ERR_INVALID_ARGUMENT;
1455 *rsap = NULL;
1456 if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) {
1457 ret = SSH_ERR_ALLOC_FAIL;
1458 goto out;
1459 }
1460 if (!BN_set_word(f4, RSA_F4) ||
1461 !RSA_generate_key_ex(private, bits, f4, NULL)) {
1462 ret = SSH_ERR_LIBCRYPTO_ERROR;
1463 goto out;
1464 }
1465 *rsap = private;
1466 private = NULL;
1467 ret = 0;
1468 out:
1469 if (private != NULL)
1470 RSA_free(private);
1471 if (f4 != NULL)
1472 BN_free(f4);
1473 return ret;
1474}
1475
1476static int
1477dsa_generate_private_key(u_int bits, DSA **dsap)
1478{
1479 DSA *private;
1480 int ret = SSH_ERR_INTERNAL_ERROR;
1481
1482 if (dsap == NULL || bits != 1024)
1483 return SSH_ERR_INVALID_ARGUMENT;
1484 if ((private = DSA_new()) == NULL) {
1485 ret = SSH_ERR_ALLOC_FAIL;
1486 goto out;
1487 }
1488 *dsap = NULL;
1489 if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
1490 NULL, NULL) || !DSA_generate_key(private)) {
1491 DSA_free(private);
1492 ret = SSH_ERR_LIBCRYPTO_ERROR;
1493 goto out;
1494 }
1495 *dsap = private;
1496 private = NULL;
1497 ret = 0;
1498 out:
1499 if (private != NULL)
1500 DSA_free(private);
1501 return ret;
1502}
1503
1504# ifdef OPENSSL_HAS_ECC
1505int
1506sshkey_ecdsa_key_to_nid(EC_KEY *k)
1507{
1508 EC_GROUP *eg;
1509 int nids[] = {
1510 NID_X9_62_prime256v1,
1511 NID_secp384r1,
1512# ifdef OPENSSL_HAS_NISTP521
1513 NID_secp521r1,
1514# endif /* OPENSSL_HAS_NISTP521 */
1515 -1
1516 };
1517 int nid;
1518 u_int i;
1519 BN_CTX *bnctx;
1520 const EC_GROUP *g = EC_KEY_get0_group(k);
1521
1522 /*
1523 * The group may be stored in a ASN.1 encoded private key in one of two
1524 * ways: as a "named group", which is reconstituted by ASN.1 object ID
1525 * or explicit group parameters encoded into the key blob. Only the
1526 * "named group" case sets the group NID for us, but we can figure
1527 * it out for the other case by comparing against all the groups that
1528 * are supported.
1529 */
1530 if ((nid = EC_GROUP_get_curve_name(g)) > 0)
1531 return nid;
1532 if ((bnctx = BN_CTX_new()) == NULL)
1533 return -1;
1534 for (i = 0; nids[i] != -1; i++) {
1535 if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) {
1536 BN_CTX_free(bnctx);
1537 return -1;
1538 }
1539 if (EC_GROUP_cmp(g, eg, bnctx) == 0)
1540 break;
1541 EC_GROUP_free(eg);
1542 }
1543 BN_CTX_free(bnctx);
1544 if (nids[i] != -1) {
1545 /* Use the group with the NID attached */
1546 EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
1547 if (EC_KEY_set_group(k, eg) != 1) {
1548 EC_GROUP_free(eg);
1549 return -1;
1550 }
1551 }
1552 return nids[i];
1553}
1554
1555static int
1556ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap)
1557{
1558 EC_KEY *private;
1559 int ret = SSH_ERR_INTERNAL_ERROR;
1560
1561 if (nid == NULL || ecdsap == NULL ||
1562 (*nid = sshkey_ecdsa_bits_to_nid(bits)) == -1)
1563 return SSH_ERR_INVALID_ARGUMENT;
1564 *ecdsap = NULL;
1565 if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) {
1566 ret = SSH_ERR_ALLOC_FAIL;
1567 goto out;
1568 }
1569 if (EC_KEY_generate_key(private) != 1) {
1570 ret = SSH_ERR_LIBCRYPTO_ERROR;
1571 goto out;
1572 }
1573 EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE);
1574 *ecdsap = private;
1575 private = NULL;
1576 ret = 0;
1577 out:
1578 if (private != NULL)
1579 EC_KEY_free(private);
1580 return ret;
1581}
1582# endif /* OPENSSL_HAS_ECC */
1583#endif /* WITH_OPENSSL */
1584
1585int
1586sshkey_generate(int type, u_int bits, struct sshkey **keyp)
1587{
1588 struct sshkey *k;
1589 int ret = SSH_ERR_INTERNAL_ERROR;
1590
1591 if (keyp == NULL)
1592 return SSH_ERR_INVALID_ARGUMENT;
1593 *keyp = NULL;
1594 if ((k = sshkey_new(KEY_UNSPEC)) == NULL)
1595 return SSH_ERR_ALLOC_FAIL;
1596 switch (type) {
1597 case KEY_ED25519:
1598 if ((k->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL ||
1599 (k->ed25519_sk = malloc(ED25519_SK_SZ)) == NULL) {
1600 ret = SSH_ERR_ALLOC_FAIL;
1601 break;
1602 }
1603 crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk);
1604 ret = 0;
1605 break;
1606#ifdef WITH_OPENSSL
1607 case KEY_DSA:
1608 ret = dsa_generate_private_key(bits, &k->dsa);
1609 break;
1610# ifdef OPENSSL_HAS_ECC
1611 case KEY_ECDSA:
1612 ret = ecdsa_generate_private_key(bits, &k->ecdsa_nid,
1613 &k->ecdsa);
1614 break;
1615# endif /* OPENSSL_HAS_ECC */
1616 case KEY_RSA:
1617 case KEY_RSA1:
1618 ret = rsa_generate_private_key(bits, &k->rsa);
1619 break;
1620#endif /* WITH_OPENSSL */
1621 default:
1622 ret = SSH_ERR_INVALID_ARGUMENT;
1623 }
1624 if (ret == 0) {
1625 k->type = type;
1626 *keyp = k;
1627 } else
1628 sshkey_free(k);
1629 return ret;
1630}
1631
1632int
1633sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key)
1634{
1635 u_int i;
1636 const struct sshkey_cert *from;
1637 struct sshkey_cert *to;
1638 int ret = SSH_ERR_INTERNAL_ERROR;
1639
1640 if (to_key->cert != NULL) {
1641 cert_free(to_key->cert);
1642 to_key->cert = NULL;
1643 }
1644
1645 if ((from = from_key->cert) == NULL)
1646 return SSH_ERR_INVALID_ARGUMENT;
1647
1648 if ((to = to_key->cert = cert_new()) == NULL)
1649 return SSH_ERR_ALLOC_FAIL;
1650
1651 if ((ret = sshbuf_putb(to->certblob, from->certblob)) != 0 ||
1652 (ret = sshbuf_putb(to->critical, from->critical)) != 0 ||
1653 (ret = sshbuf_putb(to->extensions, from->extensions) != 0))
1654 return ret;
1655
1656 to->serial = from->serial;
1657 to->type = from->type;
1658 if (from->key_id == NULL)
1659 to->key_id = NULL;
1660 else if ((to->key_id = strdup(from->key_id)) == NULL)
1661 return SSH_ERR_ALLOC_FAIL;
1662 to->valid_after = from->valid_after;
1663 to->valid_before = from->valid_before;
1664 if (from->signature_key == NULL)
1665 to->signature_key = NULL;
1666 else if ((ret = sshkey_from_private(from->signature_key,
1667 &to->signature_key)) != 0)
1668 return ret;
1669
1670 if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS)
1671 return SSH_ERR_INVALID_ARGUMENT;
1672 if (from->nprincipals > 0) {
1673 if ((to->principals = calloc(from->nprincipals,
1674 sizeof(*to->principals))) == NULL)
1675 return SSH_ERR_ALLOC_FAIL;
1676 for (i = 0; i < from->nprincipals; i++) {
1677 to->principals[i] = strdup(from->principals[i]);
1678 if (to->principals[i] == NULL) {
1679 to->nprincipals = i;
1680 return SSH_ERR_ALLOC_FAIL;
1681 }
1682 }
1683 }
1684 to->nprincipals = from->nprincipals;
1685 return 0;
1686}
1687
1688int
1689sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
1690{
1691 struct sshkey *n = NULL;
1692 int ret = SSH_ERR_INTERNAL_ERROR;
1693
1694 if (pkp != NULL)
1695 *pkp = NULL;
1696
1697 switch (k->type) {
1698#ifdef WITH_OPENSSL
1699 case KEY_DSA:
1700 case KEY_DSA_CERT_V00:
1701 case KEY_DSA_CERT:
1702 if ((n = sshkey_new(k->type)) == NULL)
1703 return SSH_ERR_ALLOC_FAIL;
1704 if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) ||
1705 (BN_copy(n->dsa->q, k->dsa->q) == NULL) ||
1706 (BN_copy(n->dsa->g, k->dsa->g) == NULL) ||
1707 (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL)) {
1708 sshkey_free(n);
1709 return SSH_ERR_ALLOC_FAIL;
1710 }
1711 break;
1712# ifdef OPENSSL_HAS_ECC
1713 case KEY_ECDSA:
1714 case KEY_ECDSA_CERT:
1715 if ((n = sshkey_new(k->type)) == NULL)
1716 return SSH_ERR_ALLOC_FAIL;
1717 n->ecdsa_nid = k->ecdsa_nid;
1718 n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
1719 if (n->ecdsa == NULL) {
1720 sshkey_free(n);
1721 return SSH_ERR_ALLOC_FAIL;
1722 }
1723 if (EC_KEY_set_public_key(n->ecdsa,
1724 EC_KEY_get0_public_key(k->ecdsa)) != 1) {
1725 sshkey_free(n);
1726 return SSH_ERR_LIBCRYPTO_ERROR;
1727 }
1728 break;
1729# endif /* OPENSSL_HAS_ECC */
1730 case KEY_RSA:
1731 case KEY_RSA1:
1732 case KEY_RSA_CERT_V00:
1733 case KEY_RSA_CERT:
1734 if ((n = sshkey_new(k->type)) == NULL)
1735 return SSH_ERR_ALLOC_FAIL;
1736 if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
1737 (BN_copy(n->rsa->e, k->rsa->e) == NULL)) {
1738 sshkey_free(n);
1739 return SSH_ERR_ALLOC_FAIL;
1740 }
1741 break;
1742#endif /* WITH_OPENSSL */
1743 case KEY_ED25519:
1744 case KEY_ED25519_CERT:
1745 if ((n = sshkey_new(k->type)) == NULL)
1746 return SSH_ERR_ALLOC_FAIL;
1747 if (k->ed25519_pk != NULL) {
1748 if ((n->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
1749 sshkey_free(n);
1750 return SSH_ERR_ALLOC_FAIL;
1751 }
1752 memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
1753 }
1754 break;
1755 default:
1756 return SSH_ERR_KEY_TYPE_UNKNOWN;
1757 }
1758 if (sshkey_is_cert(k)) {
1759 if ((ret = sshkey_cert_copy(k, n)) != 0) {
1760 sshkey_free(n);
1761 return ret;
1762 }
1763 }
1764 *pkp = n;
1765 return 0;
1766}
1767
1768static int
1769cert_parse(struct sshbuf *b, struct sshkey *key, const u_char *blob,
1770 size_t blen)
1771{
1772 u_char *principals = NULL, *critical = NULL, *exts = NULL;
1773 u_char *sig_key = NULL, *sig = NULL;
1774 size_t signed_len, plen, clen, sklen, slen, kidlen, elen;
1775 struct sshbuf *tmp;
1776 char *principal;
1777 int ret = SSH_ERR_INTERNAL_ERROR;
1778 int v00 = sshkey_cert_is_legacy(key);
1779 char **oprincipals;
1780
1781 if ((tmp = sshbuf_new()) == NULL)
1782 return SSH_ERR_ALLOC_FAIL;
1783
1784 /* Copy the entire key blob for verification and later serialisation */
1785 if ((ret = sshbuf_put(key->cert->certblob, blob, blen)) != 0)
1786 return ret;
1787
1788 elen = 0; /* Not touched for v00 certs */
1789 principals = exts = critical = sig_key = sig = NULL;
1790 if ((!v00 && (ret = sshbuf_get_u64(b, &key->cert->serial)) != 0) ||
1791 (ret = sshbuf_get_u32(b, &key->cert->type)) != 0 ||
1792 (ret = sshbuf_get_cstring(b, &key->cert->key_id, &kidlen)) != 0 ||
1793 (ret = sshbuf_get_string(b, &principals, &plen)) != 0 ||
1794 (ret = sshbuf_get_u64(b, &key->cert->valid_after)) != 0 ||
1795 (ret = sshbuf_get_u64(b, &key->cert->valid_before)) != 0 ||
1796 (ret = sshbuf_get_string(b, &critical, &clen)) != 0 ||
1797 (!v00 && (ret = sshbuf_get_string(b, &exts, &elen)) != 0) ||
1798 (v00 && (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0) ||
1799 (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 ||
1800 (ret = sshbuf_get_string(b, &sig_key, &sklen)) != 0) {
1801 /* XXX debug print error for ret */
1802 ret = SSH_ERR_INVALID_FORMAT;
1803 goto out;
1804 }
1805
1806 /* Signature is left in the buffer so we can calculate this length */
1807 signed_len = sshbuf_len(key->cert->certblob) - sshbuf_len(b);
1808
1809 if ((ret = sshbuf_get_string(b, &sig, &slen)) != 0) {
1810 ret = SSH_ERR_INVALID_FORMAT;
1811 goto out;
1812 }
1813
1814 if (key->cert->type != SSH2_CERT_TYPE_USER &&
1815 key->cert->type != SSH2_CERT_TYPE_HOST) {
1816 ret = SSH_ERR_KEY_CERT_UNKNOWN_TYPE;
1817 goto out;
1818 }
1819
1820 if ((ret = sshbuf_put(tmp, principals, plen)) != 0)
1821 goto out;
1822 while (sshbuf_len(tmp) > 0) {
1823 if (key->cert->nprincipals >= SSHKEY_CERT_MAX_PRINCIPALS) {
1824 ret = SSH_ERR_INVALID_FORMAT;
1825 goto out;
1826 }
1827 if ((ret = sshbuf_get_cstring(tmp, &principal, &plen)) != 0) {
1828 ret = SSH_ERR_INVALID_FORMAT;
1829 goto out;
1830 }
1831 oprincipals = key->cert->principals;
1832 key->cert->principals = realloc(key->cert->principals,
1833 (key->cert->nprincipals + 1) *
1834 sizeof(*key->cert->principals));
1835 if (key->cert->principals == NULL) {
1836 free(principal);
1837 key->cert->principals = oprincipals;
1838 ret = SSH_ERR_ALLOC_FAIL;
1839 goto out;
1840 }
1841 key->cert->principals[key->cert->nprincipals++] = principal;
1842 }
1843
1844 sshbuf_reset(tmp);
1845
1846 if ((ret = sshbuf_put(key->cert->critical, critical, clen)) != 0 ||
1847 (ret = sshbuf_put(tmp, critical, clen)) != 0)
1848 goto out;
1849
1850 /* validate structure */
1851 while (sshbuf_len(tmp) != 0) {
1852 if ((ret = sshbuf_get_string_direct(tmp, NULL, NULL)) != 0 ||
1853 (ret = sshbuf_get_string_direct(tmp, NULL, NULL)) != 0) {
1854 ret = SSH_ERR_INVALID_FORMAT;
1855 goto out;
1856 }
1857 }
1858 sshbuf_reset(tmp);
1859
1860 if ((ret = sshbuf_put(key->cert->extensions, exts, elen)) != 0 ||
1861 (ret = sshbuf_put(tmp, exts, elen)) != 0)
1862 goto out;
1863
1864 /* validate structure */
1865 while (sshbuf_len(tmp) != 0) {
1866 if ((ret = sshbuf_get_string_direct(tmp, NULL, NULL)) != 0 ||
1867 (ret = sshbuf_get_string_direct(tmp, NULL, NULL)) != 0) {
1868 ret = SSH_ERR_INVALID_FORMAT;
1869 goto out;
1870 }
1871 }
1872 sshbuf_reset(tmp);
1873
1874 if (sshkey_from_blob_internal(sig_key, sklen,
1875 &key->cert->signature_key, 0) != 0) {
1876 ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1877 goto out;
1878 }
1879 if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) {
1880 ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1881 goto out;
1882 }
1883
1884 if ((ret = sshkey_verify(key->cert->signature_key, sig, slen,
1885 sshbuf_ptr(key->cert->certblob), signed_len, 0)) != 0)
1886 goto out;
1887 ret = 0;
1888
1889 out:
1890 sshbuf_free(tmp);
1891 free(principals);
1892 free(critical);
1893 free(exts);
1894 free(sig_key);
1895 free(sig);
1896 return ret;
1897}
1898
1899static int
1900sshkey_from_blob_internal(const u_char *blob, size_t blen,
1901 struct sshkey **keyp, int allow_cert)
1902{
1903 struct sshbuf *b = NULL;
1904 int type, nid = -1, ret = SSH_ERR_INTERNAL_ERROR;
1905 char *ktype = NULL, *curve = NULL;
1906 struct sshkey *key = NULL;
1907 size_t len;
1908 u_char *pk = NULL;
1909#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
1910 EC_POINT *q = NULL;
1911#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
1912
1913#ifdef DEBUG_PK /* XXX */
1914 dump_base64(stderr, blob, blen);
1915#endif
1916 *keyp = NULL;
1917 if ((b = sshbuf_from(blob, blen)) == NULL)
1918 return SSH_ERR_ALLOC_FAIL;
1919 if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
1920 ret = SSH_ERR_INVALID_FORMAT;
1921 goto out;
1922 }
1923
1924 type = sshkey_type_from_name(ktype);
1925 if (sshkey_type_plain(type) == KEY_ECDSA)
1926 nid = sshkey_ecdsa_nid_from_name(ktype);
1927 if (!allow_cert && sshkey_type_is_cert(type)) {
1928 ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1929 goto out;
1930 }
1931 switch (type) {
1932#ifdef WITH_OPENSSL
1933 case KEY_RSA_CERT:
1934 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1935 ret = SSH_ERR_INVALID_FORMAT;
1936 goto out;
1937 }
1938 /* FALLTHROUGH */
1939 case KEY_RSA:
1940 case KEY_RSA_CERT_V00:
1941 if ((key = sshkey_new(type)) == NULL) {
1942 ret = SSH_ERR_ALLOC_FAIL;
1943 goto out;
1944 }
1945 if (sshbuf_get_bignum2(b, key->rsa->e) == -1 ||
1946 sshbuf_get_bignum2(b, key->rsa->n) == -1) {
1947 ret = SSH_ERR_INVALID_FORMAT;
1948 goto out;
1949 }
1950#ifdef DEBUG_PK
1951 RSA_print_fp(stderr, key->rsa, 8);
1952#endif
1953 break;
1954 case KEY_DSA_CERT:
1955 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1956 ret = SSH_ERR_INVALID_FORMAT;
1957 goto out;
1958 }
1959 /* FALLTHROUGH */
1960 case KEY_DSA:
1961 case KEY_DSA_CERT_V00:
1962 if ((key = sshkey_new(type)) == NULL) {
1963 ret = SSH_ERR_ALLOC_FAIL;
1964 goto out;
1965 }
1966 if (sshbuf_get_bignum2(b, key->dsa->p) == -1 ||
1967 sshbuf_get_bignum2(b, key->dsa->q) == -1 ||
1968 sshbuf_get_bignum2(b, key->dsa->g) == -1 ||
1969 sshbuf_get_bignum2(b, key->dsa->pub_key) == -1) {
1970 ret = SSH_ERR_INVALID_FORMAT;
1971 goto out;
1972 }
1973#ifdef DEBUG_PK
1974 DSA_print_fp(stderr, key->dsa, 8);
1975#endif
1976 break;
1977 case KEY_ECDSA_CERT:
1978 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1979 ret = SSH_ERR_INVALID_FORMAT;
1980 goto out;
1981 }
1982 /* FALLTHROUGH */
1983# ifdef OPENSSL_HAS_ECC
1984 case KEY_ECDSA:
1985 if ((key = sshkey_new(type)) == NULL) {
1986 ret = SSH_ERR_ALLOC_FAIL;
1987 goto out;
1988 }
1989 key->ecdsa_nid = nid;
1990 if (sshbuf_get_cstring(b, &curve, NULL) != 0) {
1991 ret = SSH_ERR_INVALID_FORMAT;
1992 goto out;
1993 }
1994 if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
1995 ret = SSH_ERR_EC_CURVE_MISMATCH;
1996 goto out;
1997 }
1998 if (key->ecdsa != NULL)
1999 EC_KEY_free(key->ecdsa);
2000 if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid))
2001 == NULL) {
2002 ret = SSH_ERR_EC_CURVE_INVALID;
2003 goto out;
2004 }
2005 if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) {
2006 ret = SSH_ERR_ALLOC_FAIL;
2007 goto out;
2008 }
2009 if (sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa)) != 0) {
2010 ret = SSH_ERR_INVALID_FORMAT;
2011 goto out;
2012 }
2013 if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa),
2014 q) != 0) {
2015 ret = SSH_ERR_KEY_INVALID_EC_VALUE;
2016 goto out;
2017 }
2018 if (EC_KEY_set_public_key(key->ecdsa, q) != 1) {
2019 /* XXX assume it is a allocation error */
2020 ret = SSH_ERR_ALLOC_FAIL;
2021 goto out;
2022 }
2023#ifdef DEBUG_PK
2024 sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
2025#endif
2026 break;
2027# endif /* OPENSSL_HAS_ECC */
2028#endif /* WITH_OPENSSL */
2029 case KEY_ED25519_CERT:
2030 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
2031 ret = SSH_ERR_INVALID_FORMAT;
2032 goto out;
2033 }
2034 /* FALLTHROUGH */
2035 case KEY_ED25519:
2036 if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
2037 goto out;
2038 if (len != ED25519_PK_SZ) {
2039 ret = SSH_ERR_INVALID_FORMAT;
2040 goto out;
2041 }
2042 if ((key = sshkey_new(type)) == NULL) {
2043 ret = SSH_ERR_ALLOC_FAIL;
2044 goto out;
2045 }
2046 key->ed25519_pk = pk;
2047 pk = NULL;
2048 break;
2049 case KEY_UNSPEC:
2050 if ((key = sshkey_new(type)) == NULL) {
2051 ret = SSH_ERR_ALLOC_FAIL;
2052 goto out;
2053 }
2054 break;
2055 default:
2056 ret = SSH_ERR_KEY_TYPE_UNKNOWN;
2057 goto out;
2058 }
2059
2060 /* Parse certificate potion */
2061 if (sshkey_is_cert(key) &&
2062 (ret = cert_parse(b, key, blob, blen)) != 0)
2063 goto out;
2064
2065 if (key != NULL && sshbuf_len(b) != 0) {
2066 ret = SSH_ERR_INVALID_FORMAT;
2067 goto out;
2068 }
2069 ret = 0;
2070 *keyp = key;
2071 key = NULL;
2072 out:
2073 sshbuf_free(b);
2074 sshkey_free(key);
2075 free(ktype);
2076 free(curve);
2077 free(pk);
2078#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
2079 if (q != NULL)
2080 EC_POINT_free(q);
2081#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
2082 return ret;
2083}
2084
2085int
2086sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp)
2087{
2088 return sshkey_from_blob_internal(blob, blen, keyp, 1);
2089}
2090
2091int
2092sshkey_sign(const struct sshkey *key,
2093 u_char **sigp, size_t *lenp,
2094 const u_char *data, size_t datalen, u_int compat)
2095{
2096 if (sigp != NULL)
2097 *sigp = NULL;
2098 if (lenp != NULL)
2099 *lenp = 0;
2100 if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
2101 return SSH_ERR_INVALID_ARGUMENT;
2102 switch (key->type) {
2103#ifdef WITH_OPENSSL
2104 case KEY_DSA_CERT_V00:
2105 case KEY_DSA_CERT:
2106 case KEY_DSA:
2107 return ssh_dss_sign(key, sigp, lenp, data, datalen, compat);
2108# ifdef OPENSSL_HAS_ECC
2109 case KEY_ECDSA_CERT:
2110 case KEY_ECDSA:
2111 return ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat);
2112# endif /* OPENSSL_HAS_ECC */
2113 case KEY_RSA_CERT_V00:
2114 case KEY_RSA_CERT:
2115 case KEY_RSA:
2116 return ssh_rsa_sign(key, sigp, lenp, data, datalen, compat);
2117#endif /* WITH_OPENSSL */
2118 case KEY_ED25519:
2119 case KEY_ED25519_CERT:
2120 return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat);
2121 default:
2122 return SSH_ERR_KEY_TYPE_UNKNOWN;
2123 }
2124}
2125
2126/*
2127 * ssh_key_verify returns 0 for a correct signature and < 0 on error.
2128 */
2129int
2130sshkey_verify(const struct sshkey *key,
2131 const u_char *sig, size_t siglen,
2132 const u_char *data, size_t dlen, u_int compat)
2133{
2134 if (siglen == 0)
2135 return -1;
2136
2137 if (dlen > SSH_KEY_MAX_SIGN_DATA_SIZE)
2138 return SSH_ERR_INVALID_ARGUMENT;
2139 switch (key->type) {
2140#ifdef WITH_OPENSSL
2141 case KEY_DSA_CERT_V00:
2142 case KEY_DSA_CERT:
2143 case KEY_DSA:
2144 return ssh_dss_verify(key, sig, siglen, data, dlen, compat);
2145# ifdef OPENSSL_HAS_ECC
2146 case KEY_ECDSA_CERT:
2147 case KEY_ECDSA:
2148 return ssh_ecdsa_verify(key, sig, siglen, data, dlen, compat);
2149# endif /* OPENSSL_HAS_ECC */
2150 case KEY_RSA_CERT_V00:
2151 case KEY_RSA_CERT:
2152 case KEY_RSA:
2153 return ssh_rsa_verify(key, sig, siglen, data, dlen, compat);
2154#endif /* WITH_OPENSSL */
2155 case KEY_ED25519:
2156 case KEY_ED25519_CERT:
2157 return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat);
2158 default:
2159 return SSH_ERR_KEY_TYPE_UNKNOWN;
2160 }
2161}
2162
2163/* Converts a private to a public key */
2164int
2165sshkey_demote(const struct sshkey *k, struct sshkey **dkp)
2166{
2167 struct sshkey *pk;
2168 int ret = SSH_ERR_INTERNAL_ERROR;
2169
2170 if (dkp != NULL)
2171 *dkp = NULL;
2172
2173 if ((pk = calloc(1, sizeof(*pk))) == NULL)
2174 return SSH_ERR_ALLOC_FAIL;
2175 pk->type = k->type;
2176 pk->flags = k->flags;
2177 pk->ecdsa_nid = k->ecdsa_nid;
2178 pk->dsa = NULL;
2179 pk->ecdsa = NULL;
2180 pk->rsa = NULL;
2181 pk->ed25519_pk = NULL;
2182 pk->ed25519_sk = NULL;
2183
2184 switch (k->type) {
2185#ifdef WITH_OPENSSL
2186 case KEY_RSA_CERT_V00:
2187 case KEY_RSA_CERT:
2188 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2189 goto fail;
2190 /* FALLTHROUGH */
2191 case KEY_RSA1:
2192 case KEY_RSA:
2193 if ((pk->rsa = RSA_new()) == NULL ||
2194 (pk->rsa->e = BN_dup(k->rsa->e)) == NULL ||
2195 (pk->rsa->n = BN_dup(k->rsa->n)) == NULL) {
2196 ret = SSH_ERR_ALLOC_FAIL;
2197 goto fail;
2198 }
2199 break;
2200 case KEY_DSA_CERT_V00:
2201 case KEY_DSA_CERT:
2202 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2203 goto fail;
2204 /* FALLTHROUGH */
2205 case KEY_DSA:
2206 if ((pk->dsa = DSA_new()) == NULL ||
2207 (pk->dsa->p = BN_dup(k->dsa->p)) == NULL ||
2208 (pk->dsa->q = BN_dup(k->dsa->q)) == NULL ||
2209 (pk->dsa->g = BN_dup(k->dsa->g)) == NULL ||
2210 (pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) {
2211 ret = SSH_ERR_ALLOC_FAIL;
2212 goto fail;
2213 }
2214 break;
2215 case KEY_ECDSA_CERT:
2216 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2217 goto fail;
2218 /* FALLTHROUGH */
2219# ifdef OPENSSL_HAS_ECC
2220 case KEY_ECDSA:
2221 pk->ecdsa = EC_KEY_new_by_curve_name(pk->ecdsa_nid);
2222 if (pk->ecdsa == NULL) {
2223 ret = SSH_ERR_ALLOC_FAIL;
2224 goto fail;
2225 }
2226 if (EC_KEY_set_public_key(pk->ecdsa,
2227 EC_KEY_get0_public_key(k->ecdsa)) != 1) {
2228 ret = SSH_ERR_LIBCRYPTO_ERROR;
2229 goto fail;
2230 }
2231 break;
2232# endif /* OPENSSL_HAS_ECC */
2233#endif /* WITH_OPENSSL */
2234 case KEY_ED25519_CERT:
2235 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2236 goto fail;
2237 /* FALLTHROUGH */
2238 case KEY_ED25519:
2239 if (k->ed25519_pk != NULL) {
2240 if ((pk->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
2241 ret = SSH_ERR_ALLOC_FAIL;
2242 goto fail;
2243 }
2244 memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
2245 }
2246 break;
2247 default:
2248 ret = SSH_ERR_KEY_TYPE_UNKNOWN;
2249 fail:
2250 sshkey_free(pk);
2251 return ret;
2252 }
2253 *dkp = pk;
2254 return 0;
2255}
2256
2257/* Convert a plain key to their _CERT equivalent */
2258int
2259sshkey_to_certified(struct sshkey *k, int legacy)
2260{
2261 int newtype;
2262
2263 switch (k->type) {
2264#ifdef WITH_OPENSSL
2265 case KEY_RSA:
2266 newtype = legacy ? KEY_RSA_CERT_V00 : KEY_RSA_CERT;
2267 break;
2268 case KEY_DSA:
2269 newtype = legacy ? KEY_DSA_CERT_V00 : KEY_DSA_CERT;
2270 break;
2271 case KEY_ECDSA:
2272 if (legacy)
2273 return SSH_ERR_INVALID_ARGUMENT;
2274 newtype = KEY_ECDSA_CERT;
2275 break;
2276#endif /* WITH_OPENSSL */
2277 case KEY_ED25519:
2278 if (legacy)
2279 return SSH_ERR_INVALID_ARGUMENT;
2280 newtype = KEY_ED25519_CERT;
2281 break;
2282 default:
2283 return SSH_ERR_INVALID_ARGUMENT;
2284 }
2285 if ((k->cert = cert_new()) == NULL)
2286 return SSH_ERR_ALLOC_FAIL;
2287 k->type = newtype;
2288 return 0;
2289}
2290
2291/* Convert a certificate to its raw key equivalent */
2292int
2293sshkey_drop_cert(struct sshkey *k)
2294{
2295 if (!sshkey_type_is_cert(k->type))
2296 return SSH_ERR_KEY_TYPE_UNKNOWN;
2297 cert_free(k->cert);
2298 k->cert = NULL;
2299 k->type = sshkey_type_plain(k->type);
2300 return 0;
2301}
2302
2303/* Sign a certified key, (re-)generating the signed certblob. */
2304int
2305sshkey_certify(struct sshkey *k, struct sshkey *ca)
2306{
2307 struct sshbuf *principals = NULL;
2308 u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32];
2309 size_t i, ca_len, sig_len;
2310 int ret = SSH_ERR_INTERNAL_ERROR;
2311 struct sshbuf *cert;
2312
2313 if (k == NULL || k->cert == NULL ||
2314 k->cert->certblob == NULL || ca == NULL)
2315 return SSH_ERR_INVALID_ARGUMENT;
2316 if (!sshkey_is_cert(k))
2317 return SSH_ERR_KEY_TYPE_UNKNOWN;
2318 if (!sshkey_type_is_valid_ca(ca->type))
2319 return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
2320
2321 if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0)
2322 return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
2323
2324 cert = k->cert->certblob; /* for readability */
2325 sshbuf_reset(cert);
2326 if ((ret = sshbuf_put_cstring(cert, sshkey_ssh_name(k))) != 0)
2327 goto out;
2328
2329 /* -v01 certs put nonce first */
2330 arc4random_buf(&nonce, sizeof(nonce));
2331 if (!sshkey_cert_is_legacy(k)) {
2332 if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0)
2333 goto out;
2334 }
2335
2336 /* XXX this substantially duplicates to_blob(); refactor */
2337 switch (k->type) {
2338#ifdef WITH_OPENSSL
2339 case KEY_DSA_CERT_V00:
2340 case KEY_DSA_CERT:
2341 if ((ret = sshbuf_put_bignum2(cert, k->dsa->p)) != 0 ||
2342 (ret = sshbuf_put_bignum2(cert, k->dsa->q)) != 0 ||
2343 (ret = sshbuf_put_bignum2(cert, k->dsa->g)) != 0 ||
2344 (ret = sshbuf_put_bignum2(cert, k->dsa->pub_key)) != 0)
2345 goto out;
2346 break;
2347# ifdef OPENSSL_HAS_ECC
2348 case KEY_ECDSA_CERT:
2349 if ((ret = sshbuf_put_cstring(cert,
2350 sshkey_curve_nid_to_name(k->ecdsa_nid))) != 0 ||
2351 (ret = sshbuf_put_ec(cert,
2352 EC_KEY_get0_public_key(k->ecdsa),
2353 EC_KEY_get0_group(k->ecdsa))) != 0)
2354 goto out;
2355 break;
2356# endif /* OPENSSL_HAS_ECC */
2357 case KEY_RSA_CERT_V00:
2358 case KEY_RSA_CERT:
2359 if ((ret = sshbuf_put_bignum2(cert, k->rsa->e)) != 0 ||
2360 (ret = sshbuf_put_bignum2(cert, k->rsa->n)) != 0)
2361 goto out;
2362 break;
2363#endif /* WITH_OPENSSL */
2364 case KEY_ED25519_CERT:
2365 if ((ret = sshbuf_put_string(cert,
2366 k->ed25519_pk, ED25519_PK_SZ)) != 0)
2367 goto out;
2368 break;
2369 default:
2370 ret = SSH_ERR_INVALID_ARGUMENT;
2371 }
2372
2373 /* -v01 certs have a serial number next */
2374 if (!sshkey_cert_is_legacy(k)) {
2375 if ((ret = sshbuf_put_u64(cert, k->cert->serial)) != 0)
2376 goto out;
2377 }
2378
2379 if ((ret = sshbuf_put_u32(cert, k->cert->type)) != 0 ||
2380 (ret = sshbuf_put_cstring(cert, k->cert->key_id)) != 0)
2381 goto out;
2382
2383 if ((principals = sshbuf_new()) == NULL) {
2384 ret = SSH_ERR_ALLOC_FAIL;
2385 goto out;
2386 }
2387 for (i = 0; i < k->cert->nprincipals; i++) {
2388 if ((ret = sshbuf_put_cstring(principals,
2389 k->cert->principals[i])) != 0)
2390 goto out;
2391 }
2392 if ((ret = sshbuf_put_stringb(cert, principals)) != 0 ||
2393 (ret = sshbuf_put_u64(cert, k->cert->valid_after)) != 0 ||
2394 (ret = sshbuf_put_u64(cert, k->cert->valid_before)) != 0 ||
2395 (ret = sshbuf_put_stringb(cert, k->cert->critical)) != 0)
2396 goto out;
2397
2398 /* -v01 certs have non-critical options here */
2399 if (!sshkey_cert_is_legacy(k)) {
2400 if ((ret = sshbuf_put_stringb(cert, k->cert->extensions)) != 0)
2401 goto out;
2402 }
2403
2404 /* -v00 certs put the nonce at the end */
2405 if (sshkey_cert_is_legacy(k)) {
2406 if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0)
2407 goto out;
2408 }
2409
2410 if ((ret = sshbuf_put_string(cert, NULL, 0)) != 0 || /* Reserved */
2411 (ret = sshbuf_put_string(cert, ca_blob, ca_len)) != 0)
2412 goto out;
2413
2414 /* Sign the whole mess */
2415 if ((ret = sshkey_sign(ca, &sig_blob, &sig_len, sshbuf_ptr(cert),
2416 sshbuf_len(cert), 0)) != 0)
2417 goto out;
2418
2419 /* Append signature and we are done */
2420 if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0)
2421 goto out;
2422 ret = 0;
2423 out:
2424 if (ret != 0)
2425 sshbuf_reset(cert);
2426 if (sig_blob != NULL)
2427 free(sig_blob);
2428 if (ca_blob != NULL)
2429 free(ca_blob);
2430 if (principals != NULL)
2431 sshbuf_free(principals);
2432 return ret;
2433}
2434
2435int
2436sshkey_cert_check_authority(const struct sshkey *k,
2437 int want_host, int require_principal,
2438 const char *name, const char **reason)
2439{
2440 u_int i, principal_matches;
2441 time_t now = time(NULL);
2442
2443 if (reason != NULL)
2444 *reason = NULL;
2445
2446 if (want_host) {
2447 if (k->cert->type != SSH2_CERT_TYPE_HOST) {
2448 *reason = "Certificate invalid: not a host certificate";
2449 return SSH_ERR_KEY_CERT_INVALID;
2450 }
2451 } else {
2452 if (k->cert->type != SSH2_CERT_TYPE_USER) {
2453 *reason = "Certificate invalid: not a user certificate";
2454 return SSH_ERR_KEY_CERT_INVALID;
2455 }
2456 }
2457 if (now < 0) {
2458 /* yikes - system clock before epoch! */
2459 *reason = "Certificate invalid: not yet valid";
2460 return SSH_ERR_KEY_CERT_INVALID;
2461 }
2462 if ((u_int64_t)now < k->cert->valid_after) {
2463 *reason = "Certificate invalid: not yet valid";
2464 return SSH_ERR_KEY_CERT_INVALID;
2465 }
2466 if ((u_int64_t)now >= k->cert->valid_before) {
2467 *reason = "Certificate invalid: expired";
2468 return SSH_ERR_KEY_CERT_INVALID;
2469 }
2470 if (k->cert->nprincipals == 0) {
2471 if (require_principal) {
2472 *reason = "Certificate lacks principal list";
2473 return SSH_ERR_KEY_CERT_INVALID;
2474 }
2475 } else if (name != NULL) {
2476 principal_matches = 0;
2477 for (i = 0; i < k->cert->nprincipals; i++) {
2478 if (strcmp(name, k->cert->principals[i]) == 0) {
2479 principal_matches = 1;
2480 break;
2481 }
2482 }
2483 if (!principal_matches) {
2484 *reason = "Certificate invalid: name is not a listed "
2485 "principal";
2486 return SSH_ERR_KEY_CERT_INVALID;
2487 }
2488 }
2489 return 0;
2490}
2491
2492int
2493sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
2494{
2495 int r = SSH_ERR_INTERNAL_ERROR;
2496
2497 if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0)
2498 goto out;
2499 switch (key->type) {
2500#ifdef WITH_OPENSSL
2501 case KEY_RSA:
2502 if ((r = sshbuf_put_bignum2(b, key->rsa->n)) != 0 ||
2503 (r = sshbuf_put_bignum2(b, key->rsa->e)) != 0 ||
2504 (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 ||
2505 (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 ||
2506 (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 ||
2507 (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0)
2508 goto out;
2509 break;
2510 case KEY_RSA_CERT_V00:
2511 case KEY_RSA_CERT:
2512 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2513 r = SSH_ERR_INVALID_ARGUMENT;
2514 goto out;
2515 }
2516 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2517 (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 ||
2518 (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 ||
2519 (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 ||
2520 (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0)
2521 goto out;
2522 break;
2523 case KEY_DSA:
2524 if ((r = sshbuf_put_bignum2(b, key->dsa->p)) != 0 ||
2525 (r = sshbuf_put_bignum2(b, key->dsa->q)) != 0 ||
2526 (r = sshbuf_put_bignum2(b, key->dsa->g)) != 0 ||
2527 (r = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0 ||
2528 (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0)
2529 goto out;
2530 break;
2531 case KEY_DSA_CERT_V00:
2532 case KEY_DSA_CERT:
2533 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2534 r = SSH_ERR_INVALID_ARGUMENT;
2535 goto out;
2536 }
2537 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2538 (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0)
2539 goto out;
2540 break;
2541# ifdef OPENSSL_HAS_ECC
2542 case KEY_ECDSA:
2543 if ((r = sshbuf_put_cstring(b,
2544 sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
2545 (r = sshbuf_put_eckey(b, key->ecdsa)) != 0 ||
2546 (r = sshbuf_put_bignum2(b,
2547 EC_KEY_get0_private_key(key->ecdsa))) != 0)
2548 goto out;
2549 break;
2550 case KEY_ECDSA_CERT:
2551 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2552 r = SSH_ERR_INVALID_ARGUMENT;
2553 goto out;
2554 }
2555 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2556 (r = sshbuf_put_bignum2(b,
2557 EC_KEY_get0_private_key(key->ecdsa))) != 0)
2558 goto out;
2559 break;
2560# endif /* OPENSSL_HAS_ECC */
2561#endif /* WITH_OPENSSL */
2562 case KEY_ED25519:
2563 if ((r = sshbuf_put_string(b, key->ed25519_pk,
2564 ED25519_PK_SZ)) != 0 ||
2565 (r = sshbuf_put_string(b, key->ed25519_sk,
2566 ED25519_SK_SZ)) != 0)
2567 goto out;
2568 break;
2569 case KEY_ED25519_CERT:
2570 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2571 r = SSH_ERR_INVALID_ARGUMENT;
2572 goto out;
2573 }
2574 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2575 (r = sshbuf_put_string(b, key->ed25519_pk,
2576 ED25519_PK_SZ)) != 0 ||
2577 (r = sshbuf_put_string(b, key->ed25519_sk,
2578 ED25519_SK_SZ)) != 0)
2579 goto out;
2580 break;
2581 default:
2582 r = SSH_ERR_INVALID_ARGUMENT;
2583 goto out;
2584 }
2585 /* success */
2586 r = 0;
2587 out:
2588 return r;
2589}
2590
2591int
2592sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
2593{
2594 char *tname = NULL, *curve = NULL;
2595 struct sshkey *k = NULL;
2596 const u_char *cert;
2597 size_t len, pklen = 0, sklen = 0;
2598 int type, r = SSH_ERR_INTERNAL_ERROR;
2599 u_char *ed25519_pk = NULL, *ed25519_sk = NULL;
2600#ifdef WITH_OPENSSL
2601 BIGNUM *exponent = NULL;
2602#endif /* WITH_OPENSSL */
2603
2604 if (kp != NULL)
2605 *kp = NULL;
2606 if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0)
2607 goto out;
2608 type = sshkey_type_from_name(tname);
2609 switch (type) {
2610#ifdef WITH_OPENSSL
2611 case KEY_DSA:
2612 if ((k = sshkey_new_private(type)) == NULL) {
2613 r = SSH_ERR_ALLOC_FAIL;
2614 goto out;
2615 }
2616 if ((r = sshbuf_get_bignum2(buf, k->dsa->p)) != 0 ||
2617 (r = sshbuf_get_bignum2(buf, k->dsa->q)) != 0 ||
2618 (r = sshbuf_get_bignum2(buf, k->dsa->g)) != 0 ||
2619 (r = sshbuf_get_bignum2(buf, k->dsa->pub_key)) != 0 ||
2620 (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0)
2621 goto out;
2622 break;
2623 case KEY_DSA_CERT_V00:
2624 case KEY_DSA_CERT:
2625 if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 ||
2626 (r = sshkey_from_blob(cert, len, &k)) != 0 ||
2627 (r = sshkey_add_private(k)) != 0 ||
2628 (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0)
2629 goto out;
2630 break;
2631# ifdef OPENSSL_HAS_ECC
2632 case KEY_ECDSA:
2633 if ((k = sshkey_new_private(type)) == NULL) {
2634 r = SSH_ERR_ALLOC_FAIL;
2635 goto out;
2636 }
2637 if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) {
2638 r = SSH_ERR_INVALID_ARGUMENT;
2639 goto out;
2640 }
2641 if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0)
2642 goto out;
2643 if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
2644 r = SSH_ERR_EC_CURVE_MISMATCH;
2645 goto out;
2646 }
2647 k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
2648 if (k->ecdsa == NULL || (exponent = BN_new()) == NULL) {
2649 r = SSH_ERR_LIBCRYPTO_ERROR;
2650 goto out;
2651 }
2652 if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0 ||
2653 (r = sshbuf_get_bignum2(buf, exponent)))
2654 goto out;
2655 if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) {
2656 r = SSH_ERR_LIBCRYPTO_ERROR;
2657 goto out;
2658 }
2659 if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
2660 EC_KEY_get0_public_key(k->ecdsa)) != 0) ||
2661 (r = sshkey_ec_validate_private(k->ecdsa)) != 0)
2662 goto out;
2663 break;
2664 case KEY_ECDSA_CERT:
2665 if ((exponent = BN_new()) == NULL) {
2666 r = SSH_ERR_LIBCRYPTO_ERROR;
2667 goto out;
2668 }
2669 if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 ||
2670 (r = sshkey_from_blob(cert, len, &k)) != 0 ||
2671 (r = sshkey_add_private(k)) != 0 ||
2672 (r = sshbuf_get_bignum2(buf, exponent)) != 0)
2673 goto out;
2674 if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) {
2675 r = SSH_ERR_LIBCRYPTO_ERROR;
2676 goto out;
2677 }
2678 if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
2679 EC_KEY_get0_public_key(k->ecdsa)) != 0) ||
2680 (r = sshkey_ec_validate_private(k->ecdsa)) != 0)
2681 goto out;
2682 break;
2683# endif /* OPENSSL_HAS_ECC */
2684 case KEY_RSA:
2685 if ((k = sshkey_new_private(type)) == NULL) {
2686 r = SSH_ERR_ALLOC_FAIL;
2687 goto out;
2688 }
2689 if ((r = sshbuf_get_bignum2(buf, k->rsa->n)) != 0 ||
2690 (r = sshbuf_get_bignum2(buf, k->rsa->e)) != 0 ||
2691 (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 ||
2692 (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 ||
2693 (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 ||
2694 (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
2695 (r = rsa_generate_additional_parameters(k->rsa)) != 0)
2696 goto out;
2697 break;
2698 case KEY_RSA_CERT_V00:
2699 case KEY_RSA_CERT:
2700 if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 ||
2701 (r = sshkey_from_blob(cert, len, &k)) != 0 ||
2702 (r = sshkey_add_private(k)) != 0 ||
2703 (r = sshbuf_get_bignum2(buf, k->rsa->d) != 0) ||
2704 (r = sshbuf_get_bignum2(buf, k->rsa->iqmp) != 0) ||
2705 (r = sshbuf_get_bignum2(buf, k->rsa->p) != 0) ||
2706 (r = sshbuf_get_bignum2(buf, k->rsa->q) != 0) ||
2707 (r = rsa_generate_additional_parameters(k->rsa)) != 0)
2708 goto out;
2709 break;
2710#endif /* WITH_OPENSSL */
2711 case KEY_ED25519:
2712 if ((k = sshkey_new_private(type)) == NULL) {
2713 r = SSH_ERR_ALLOC_FAIL;
2714 goto out;
2715 }
2716 if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 ||
2717 (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0)
2718 goto out;
2719 if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) {
2720 r = SSH_ERR_INVALID_FORMAT;
2721 goto out;
2722 }
2723 k->ed25519_pk = ed25519_pk;
2724 k->ed25519_sk = ed25519_sk;
2725 ed25519_pk = ed25519_sk = NULL;
2726 break;
2727 case KEY_ED25519_CERT:
2728 if ((r = sshbuf_get_string_direct(buf, &cert, &len)) != 0 ||
2729 (r = sshkey_from_blob(cert, len, &k)) != 0 ||
2730 (r = sshkey_add_private(k)) != 0 ||
2731 (r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 ||
2732 (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0)
2733 goto out;
2734 if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) {
2735 r = SSH_ERR_INVALID_FORMAT;
2736 goto out;
2737 }
2738 k->ed25519_pk = ed25519_pk;
2739 k->ed25519_sk = ed25519_sk;
2740 ed25519_pk = ed25519_sk = NULL;
2741 break;
2742 default:
2743 r = SSH_ERR_KEY_TYPE_UNKNOWN;
2744 goto out;
2745 }
2746#ifdef WITH_OPENSSL
2747 /* enable blinding */
2748 switch (k->type) {
2749 case KEY_RSA:
2750 case KEY_RSA_CERT_V00:
2751 case KEY_RSA_CERT:
2752 case KEY_RSA1:
2753 if (RSA_blinding_on(k->rsa, NULL) != 1) {
2754 r = SSH_ERR_LIBCRYPTO_ERROR;
2755 goto out;
2756 }
2757 break;
2758 }
2759#endif /* WITH_OPENSSL */
2760 /* success */
2761 r = 0;
2762 if (kp != NULL) {
2763 *kp = k;
2764 k = NULL;
2765 }
2766 out:
2767 free(tname);
2768 free(curve);
2769#ifdef WITH_OPENSSL
2770 if (exponent != NULL)
2771 BN_clear_free(exponent);
2772#endif /* WITH_OPENSSL */
2773 sshkey_free(k);
2774 if (ed25519_pk != NULL) {
2775 explicit_bzero(ed25519_pk, pklen);
2776 free(ed25519_pk);
2777 }
2778 if (ed25519_sk != NULL) {
2779 explicit_bzero(ed25519_sk, sklen);
2780 free(ed25519_sk);
2781 }
2782 return r;
2783}
2784
2785#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
2786int
2787sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
2788{
2789 BN_CTX *bnctx;
2790 EC_POINT *nq = NULL;
2791 BIGNUM *order, *x, *y, *tmp;
2792 int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
2793
2794 if ((bnctx = BN_CTX_new()) == NULL)
2795 return SSH_ERR_ALLOC_FAIL;
2796 BN_CTX_start(bnctx);
2797
2798 /*
2799 * We shouldn't ever hit this case because bignum_get_ecpoint()
2800 * refuses to load GF2m points.
2801 */
2802 if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
2803 NID_X9_62_prime_field)
2804 goto out;
2805
2806 /* Q != infinity */
2807 if (EC_POINT_is_at_infinity(group, public))
2808 goto out;
2809
2810 if ((x = BN_CTX_get(bnctx)) == NULL ||
2811 (y = BN_CTX_get(bnctx)) == NULL ||
2812 (order = BN_CTX_get(bnctx)) == NULL ||
2813 (tmp = BN_CTX_get(bnctx)) == NULL) {
2814 ret = SSH_ERR_ALLOC_FAIL;
2815 goto out;
2816 }
2817
2818 /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */
2819 if (EC_GROUP_get_order(group, order, bnctx) != 1 ||
2820 EC_POINT_get_affine_coordinates_GFp(group, public,
2821 x, y, bnctx) != 1) {
2822 ret = SSH_ERR_LIBCRYPTO_ERROR;
2823 goto out;
2824 }
2825 if (BN_num_bits(x) <= BN_num_bits(order) / 2 ||
2826 BN_num_bits(y) <= BN_num_bits(order) / 2)
2827 goto out;
2828
2829 /* nQ == infinity (n == order of subgroup) */
2830 if ((nq = EC_POINT_new(group)) == NULL) {
2831 ret = SSH_ERR_ALLOC_FAIL;
2832 goto out;
2833 }
2834 if (EC_POINT_mul(group, nq, NULL, public, order, bnctx) != 1) {
2835 ret = SSH_ERR_LIBCRYPTO_ERROR;
2836 goto out;
2837 }
2838 if (EC_POINT_is_at_infinity(group, nq) != 1)
2839 goto out;
2840
2841 /* x < order - 1, y < order - 1 */
2842 if (!BN_sub(tmp, order, BN_value_one())) {
2843 ret = SSH_ERR_LIBCRYPTO_ERROR;
2844 goto out;
2845 }
2846 if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0)
2847 goto out;
2848 ret = 0;
2849 out:
2850 BN_CTX_free(bnctx);
2851 if (nq != NULL)
2852 EC_POINT_free(nq);
2853 return ret;
2854}
2855
2856int
2857sshkey_ec_validate_private(const EC_KEY *key)
2858{
2859 BN_CTX *bnctx;
2860 BIGNUM *order, *tmp;
2861 int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
2862
2863 if ((bnctx = BN_CTX_new()) == NULL)
2864 return SSH_ERR_ALLOC_FAIL;
2865 BN_CTX_start(bnctx);
2866
2867 if ((order = BN_CTX_get(bnctx)) == NULL ||
2868 (tmp = BN_CTX_get(bnctx)) == NULL) {
2869 ret = SSH_ERR_ALLOC_FAIL;
2870 goto out;
2871 }
2872
2873 /* log2(private) > log2(order)/2 */
2874 if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, bnctx) != 1) {
2875 ret = SSH_ERR_LIBCRYPTO_ERROR;
2876 goto out;
2877 }
2878 if (BN_num_bits(EC_KEY_get0_private_key(key)) <=
2879 BN_num_bits(order) / 2)
2880 goto out;
2881
2882 /* private < order - 1 */
2883 if (!BN_sub(tmp, order, BN_value_one())) {
2884 ret = SSH_ERR_LIBCRYPTO_ERROR;
2885 goto out;
2886 }
2887 if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0)
2888 goto out;
2889 ret = 0;
2890 out:
2891 BN_CTX_free(bnctx);
2892 return ret;
2893}
2894
2895void
2896sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point)
2897{
2898 BIGNUM *x, *y;
2899 BN_CTX *bnctx;
2900
2901 if (point == NULL) {
2902 fputs("point=(NULL)\n", stderr);
2903 return;
2904 }
2905 if ((bnctx = BN_CTX_new()) == NULL) {
2906 fprintf(stderr, "%s: BN_CTX_new failed\n", __func__);
2907 return;
2908 }
2909 BN_CTX_start(bnctx);
2910 if ((x = BN_CTX_get(bnctx)) == NULL ||
2911 (y = BN_CTX_get(bnctx)) == NULL) {
2912 fprintf(stderr, "%s: BN_CTX_get failed\n", __func__);
2913 return;
2914 }
2915 if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
2916 NID_X9_62_prime_field) {
2917 fprintf(stderr, "%s: group is not a prime field\n", __func__);
2918 return;
2919 }
2920 if (EC_POINT_get_affine_coordinates_GFp(group, point, x, y,
2921 bnctx) != 1) {
2922 fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n",
2923 __func__);
2924 return;
2925 }
2926 fputs("x=", stderr);
2927 BN_print_fp(stderr, x);
2928 fputs("\ny=", stderr);
2929 BN_print_fp(stderr, y);
2930 fputs("\n", stderr);
2931 BN_CTX_free(bnctx);
2932}
2933
2934void
2935sshkey_dump_ec_key(const EC_KEY *key)
2936{
2937 const BIGNUM *exponent;
2938
2939 sshkey_dump_ec_point(EC_KEY_get0_group(key),
2940 EC_KEY_get0_public_key(key));
2941 fputs("exponent=", stderr);
2942 if ((exponent = EC_KEY_get0_private_key(key)) == NULL)
2943 fputs("(NULL)", stderr);
2944 else
2945 BN_print_fp(stderr, EC_KEY_get0_private_key(key));
2946 fputs("\n", stderr);
2947}
2948#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
2949
2950static int
2951sshkey_private_to_blob2(const struct sshkey *prv, struct sshbuf *blob,
2952 const char *passphrase, const char *comment, const char *ciphername,
2953 int rounds)
2954{
2955 u_char *cp, *b64 = NULL, *key = NULL, *pubkeyblob = NULL;
2956 u_char salt[SALT_LEN];
2957 size_t i, pubkeylen, keylen, ivlen, blocksize, authlen;
2958 u_int check;
2959 int r = SSH_ERR_INTERNAL_ERROR;
2960 struct sshcipher_ctx ciphercontext;
2961 const struct sshcipher *cipher;
2962 const char *kdfname = KDFNAME;
2963 struct sshbuf *encoded = NULL, *encrypted = NULL, *kdf = NULL;
2964
2965 memset(&ciphercontext, 0, sizeof(ciphercontext));
2966
2967 if (rounds <= 0)
2968 rounds = DEFAULT_ROUNDS;
2969 if (passphrase == NULL || !strlen(passphrase)) {
2970 ciphername = "none";
2971 kdfname = "none";
2972 } else if (ciphername == NULL)
2973 ciphername = DEFAULT_CIPHERNAME;
2974 else if (cipher_number(ciphername) != SSH_CIPHER_SSH2) {
2975 r = SSH_ERR_INVALID_ARGUMENT;
2976 goto out;
2977 }
2978 if ((cipher = cipher_by_name(ciphername)) == NULL) {
2979 r = SSH_ERR_INTERNAL_ERROR;
2980 goto out;
2981 }
2982
2983 if ((kdf = sshbuf_new()) == NULL ||
2984 (encoded = sshbuf_new()) == NULL ||
2985 (encrypted = sshbuf_new()) == NULL) {
2986 r = SSH_ERR_ALLOC_FAIL;
2987 goto out;
2988 }
2989 blocksize = cipher_blocksize(cipher);
2990 keylen = cipher_keylen(cipher);
2991 ivlen = cipher_ivlen(cipher);
2992 authlen = cipher_authlen(cipher);
2993 if ((key = calloc(1, keylen + ivlen)) == NULL) {
2994 r = SSH_ERR_ALLOC_FAIL;
2995 goto out;
2996 }
2997 if (strcmp(kdfname, "bcrypt") == 0) {
2998 arc4random_buf(salt, SALT_LEN);
2999 if (bcrypt_pbkdf(passphrase, strlen(passphrase),
3000 salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) {
3001 r = SSH_ERR_INVALID_ARGUMENT;
3002 goto out;
3003 }
3004 if ((r = sshbuf_put_string(kdf, salt, SALT_LEN)) != 0 ||
3005 (r = sshbuf_put_u32(kdf, rounds)) != 0)
3006 goto out;
3007 } else if (strcmp(kdfname, "none") != 0) {
3008 /* Unsupported KDF type */
3009 r = SSH_ERR_KEY_UNKNOWN_CIPHER;
3010 goto out;
3011 }
3012 if ((r = cipher_init(&ciphercontext, cipher, key, keylen,
3013 key + keylen, ivlen, 1)) != 0)
3014 goto out;
3015
3016 if ((r = sshbuf_put(encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC))) != 0 ||
3017 (r = sshbuf_put_cstring(encoded, ciphername)) != 0 ||
3018 (r = sshbuf_put_cstring(encoded, kdfname)) != 0 ||
3019 (r = sshbuf_put_stringb(encoded, kdf)) != 0 ||
3020 (r = sshbuf_put_u32(encoded, 1)) != 0 || /* number of keys */
3021 (r = sshkey_to_blob(prv, &pubkeyblob, &pubkeylen)) != 0 ||
3022 (r = sshbuf_put_string(encoded, pubkeyblob, pubkeylen)) != 0)
3023 goto out;
3024
3025 /* set up the buffer that will be encrypted */
3026
3027 /* Random check bytes */
3028 check = arc4random();
3029 if ((r = sshbuf_put_u32(encrypted, check)) != 0 ||
3030 (r = sshbuf_put_u32(encrypted, check)) != 0)
3031 goto out;
3032
3033 /* append private key and comment*/
3034 if ((r = sshkey_private_serialize(prv, encrypted)) != 0 ||
3035 (r = sshbuf_put_cstring(encrypted, comment)) != 0)
3036 goto out;
3037
3038 /* padding */
3039 i = 0;
3040 while (sshbuf_len(encrypted) % blocksize) {
3041 if ((r = sshbuf_put_u8(encrypted, ++i & 0xff)) != 0)
3042 goto out;
3043 }
3044
3045 /* length in destination buffer */
3046 if ((r = sshbuf_put_u32(encoded, sshbuf_len(encrypted))) != 0)
3047 goto out;
3048
3049 /* encrypt */
3050 if ((r = sshbuf_reserve(encoded,
3051 sshbuf_len(encrypted) + authlen, &cp)) != 0)
3052 goto out;
3053 if ((r = cipher_crypt(&ciphercontext, 0, cp,
3054 sshbuf_ptr(encrypted), sshbuf_len(encrypted), 0, authlen)) != 0)
3055 goto out;
3056
3057 /* uuencode */
3058 if ((b64 = sshbuf_dtob64(encoded)) == NULL) {
3059 r = SSH_ERR_ALLOC_FAIL;
3060 goto out;
3061 }
3062
3063 sshbuf_reset(blob);
3064 if ((r = sshbuf_put(blob, MARK_BEGIN, MARK_BEGIN_LEN)) != 0)
3065 goto out;
3066 for (i = 0; i < strlen(b64); i++) {
3067 if ((r = sshbuf_put_u8(blob, b64[i])) != 0)
3068 goto out;
3069 /* insert line breaks */
3070 if (i % 70 == 69 && (r = sshbuf_put_u8(blob, '\n')) != 0)
3071 goto out;
3072 }
3073 if (i % 70 != 69 && (r = sshbuf_put_u8(blob, '\n')) != 0)
3074 goto out;
3075 if ((r = sshbuf_put(blob, MARK_END, MARK_END_LEN)) != 0)
3076 goto out;
3077
3078 /* success */
3079 r = 0;
3080
3081 out:
3082 sshbuf_free(kdf);
3083 sshbuf_free(encoded);
3084 sshbuf_free(encrypted);
3085 cipher_cleanup(&ciphercontext);
3086 explicit_bzero(salt, sizeof(salt));
3087 if (key != NULL) {
3088 explicit_bzero(key, keylen + ivlen);
3089 free(key);
3090 }
3091 if (pubkeyblob != NULL) {
3092 explicit_bzero(pubkeyblob, pubkeylen);
3093 free(pubkeyblob);
3094 }
3095 if (b64 != NULL) {
3096 explicit_bzero(b64, strlen(b64));
3097 free(b64);
3098 }
3099 return r;
3100}
3101
3102static int
3103sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
3104 struct sshkey **keyp, char **commentp)
3105{
3106 char *comment = NULL, *ciphername = NULL, *kdfname = NULL;
3107 const struct sshcipher *cipher = NULL;
3108 const u_char *cp;
3109 int r = SSH_ERR_INTERNAL_ERROR;
3110 size_t encoded_len;
3111 size_t i, keylen = 0, ivlen = 0, slen = 0;
3112 struct sshbuf *encoded = NULL, *decoded = NULL;
3113 struct sshbuf *kdf = NULL, *decrypted = NULL;
3114 struct sshcipher_ctx ciphercontext;
3115 struct sshkey *k = NULL;
3116 u_char *key = NULL, *salt = NULL, *dp, pad, last;
3117 u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
3118
3119 memset(&ciphercontext, 0, sizeof(ciphercontext));
3120 if (keyp != NULL)
3121 *keyp = NULL;
3122 if (commentp != NULL)
3123 *commentp = NULL;
3124
3125 if ((encoded = sshbuf_new()) == NULL ||
3126 (decoded = sshbuf_new()) == NULL ||
3127 (decrypted = sshbuf_new()) == NULL) {
3128 r = SSH_ERR_ALLOC_FAIL;
3129 goto out;
3130 }
3131
3132 /* check preamble */
3133 cp = sshbuf_ptr(blob);
3134 encoded_len = sshbuf_len(blob);
3135 if (encoded_len < (MARK_BEGIN_LEN + MARK_END_LEN) ||
3136 memcmp(cp, MARK_BEGIN, MARK_BEGIN_LEN) != 0) {
3137 r = SSH_ERR_INVALID_FORMAT;
3138 goto out;
3139 }
3140 cp += MARK_BEGIN_LEN;
3141 encoded_len -= MARK_BEGIN_LEN;
3142
3143 /* Look for end marker, removing whitespace as we go */
3144 while (encoded_len > 0) {
3145 if (*cp != '\n' && *cp != '\r') {
3146 if ((r = sshbuf_put_u8(encoded, *cp)) != 0)
3147 goto out;
3148 }
3149 last = *cp;
3150 encoded_len--;
3151 cp++;
3152 if (last == '\n') {
3153 if (encoded_len >= MARK_END_LEN &&
3154 memcmp(cp, MARK_END, MARK_END_LEN) == 0) {
3155 /* \0 terminate */
3156 if ((r = sshbuf_put_u8(encoded, 0)) != 0)
3157 goto out;
3158 break;
3159 }
3160 }
3161 }
3162 if (encoded_len == 0) {
3163 r = SSH_ERR_INVALID_FORMAT;
3164 goto out;
3165 }
3166
3167 /* decode base64 */
3168 if ((r = sshbuf_b64tod(decoded, sshbuf_ptr(encoded))) != 0)
3169 goto out;
3170
3171 /* check magic */
3172 if (sshbuf_len(decoded) < sizeof(AUTH_MAGIC) ||
3173 memcmp(sshbuf_ptr(decoded), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
3174 r = SSH_ERR_INVALID_FORMAT;
3175 goto out;
3176 }
3177 /* parse public portion of key */
3178 if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
3179 (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 ||
3180 (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 ||
3181 (r = sshbuf_froms(decoded, &kdf)) != 0 ||
3182 (r = sshbuf_get_u32(decoded, &nkeys)) != 0 ||
3183 (r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */
3184 (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0)
3185 goto out;
3186
3187 if ((cipher = cipher_by_name(ciphername)) == NULL) {
3188 r = SSH_ERR_KEY_UNKNOWN_CIPHER;
3189 goto out;
3190 }
3191 if ((passphrase == NULL || strlen(passphrase) == 0) &&
3192 strcmp(ciphername, "none") != 0) {
3193 /* passphrase required */
3194 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3195 goto out;
3196 }
3197 if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) {
3198 r = SSH_ERR_KEY_UNKNOWN_CIPHER;
3199 goto out;
3200 }
3201 if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) {
3202 r = SSH_ERR_INVALID_FORMAT;
3203 goto out;
3204 }
3205 if (nkeys != 1) {
3206 /* XXX only one key supported */
3207 r = SSH_ERR_INVALID_FORMAT;
3208 goto out;
3209 }
3210
3211 /* check size of encrypted key blob */
3212 blocksize = cipher_blocksize(cipher);
3213 if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) {
3214 r = SSH_ERR_INVALID_FORMAT;
3215 goto out;
3216 }
3217
3218 /* setup key */
3219 keylen = cipher_keylen(cipher);
3220 ivlen = cipher_ivlen(cipher);
3221 if ((key = calloc(1, keylen + ivlen)) == NULL) {
3222 r = SSH_ERR_ALLOC_FAIL;
3223 goto out;
3224 }
3225 if (strcmp(kdfname, "bcrypt") == 0) {
3226 if ((r = sshbuf_get_string(kdf, &salt, &slen)) != 0 ||
3227 (r = sshbuf_get_u32(kdf, &rounds)) != 0)
3228 goto out;
3229 if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
3230 key, keylen + ivlen, rounds) < 0) {
3231 r = SSH_ERR_INVALID_FORMAT;
3232 goto out;
3233 }
3234 }
3235
3236 /* decrypt private portion of key */
3237 if ((r = sshbuf_reserve(decrypted, encrypted_len, &dp)) != 0 ||
3238 (r = cipher_init(&ciphercontext, cipher, key, keylen,
3239 key + keylen, ivlen, 0)) != 0)
3240 goto out;
3241 if ((r = cipher_crypt(&ciphercontext, 0, dp, sshbuf_ptr(decoded),
3242 sshbuf_len(decoded), 0, cipher_authlen(cipher))) != 0) {
3243 /* an integrity error here indicates an incorrect passphrase */
3244 if (r == SSH_ERR_MAC_INVALID)
3245 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3246 goto out;
3247 }
3248 if ((r = sshbuf_consume(decoded, encrypted_len)) != 0)
3249 goto out;
3250 /* there should be no trailing data */
3251 if (sshbuf_len(decoded) != 0) {
3252 r = SSH_ERR_INVALID_FORMAT;
3253 goto out;
3254 }
3255
3256 /* check check bytes */
3257 if ((r = sshbuf_get_u32(decrypted, &check1)) != 0 ||
3258 (r = sshbuf_get_u32(decrypted, &check2)) != 0)
3259 goto out;
3260 if (check1 != check2) {
3261 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3262 goto out;
3263 }
3264
3265 /* Load the private key and comment */
3266 if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 ||
3267 (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0)
3268 goto out;
3269
3270 /* Check deterministic padding */
3271 i = 0;
3272 while (sshbuf_len(decrypted)) {
3273 if ((r = sshbuf_get_u8(decrypted, &pad)) != 0)
3274 goto out;
3275 if (pad != (++i & 0xff)) {
3276 r = SSH_ERR_INVALID_FORMAT;
3277 goto out;
3278 }
3279 }
3280
3281 /* XXX decode pubkey and check against private */
3282
3283 /* success */
3284 r = 0;
3285 if (keyp != NULL) {
3286 *keyp = k;
3287 k = NULL;
3288 }
3289 if (commentp != NULL) {
3290 *commentp = comment;
3291 comment = NULL;
3292 }
3293 out:
3294 pad = 0;
3295 cipher_cleanup(&ciphercontext);
3296 free(ciphername);
3297 free(kdfname);
3298 free(comment);
3299 if (salt != NULL) {
3300 explicit_bzero(salt, slen);
3301 free(salt);
3302 }
3303 if (key != NULL) {
3304 explicit_bzero(key, keylen + ivlen);
3305 free(key);
3306 }
3307 sshbuf_free(encoded);
3308 sshbuf_free(decoded);
3309 sshbuf_free(kdf);
3310 sshbuf_free(decrypted);
3311 sshkey_free(k);
3312 return r;
3313}
3314
3315#if WITH_SSH1
3316/*
3317 * Serialises the authentication (private) key to a blob, encrypting it with
3318 * passphrase. The identification of the blob (lowest 64 bits of n) will
3319 * precede the key to provide identification of the key without needing a
3320 * passphrase.
3321 */
3322static int
3323sshkey_private_rsa1_to_blob(struct sshkey *key, struct sshbuf *blob,
3324 const char *passphrase, const char *comment)
3325{
3326 struct sshbuf *buffer = NULL, *encrypted = NULL;
3327 u_char buf[8];
3328 int r, cipher_num;
3329 struct sshcipher_ctx ciphercontext;
3330 const struct sshcipher *cipher;
3331 u_char *cp;
3332
3333 /*
3334 * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
3335 * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
3336 */
3337 cipher_num = (strcmp(passphrase, "") == 0) ?
3338 SSH_CIPHER_NONE : SSH_CIPHER_3DES;
3339 if ((cipher = cipher_by_number(cipher_num)) == NULL)
3340 return SSH_ERR_INTERNAL_ERROR;
3341
3342 /* This buffer is used to build the secret part of the private key. */
3343 if ((buffer = sshbuf_new()) == NULL)
3344 return SSH_ERR_ALLOC_FAIL;
3345
3346 /* Put checkbytes for checking passphrase validity. */
3347 if ((r = sshbuf_reserve(buffer, 4, &cp)) != 0)
3348 goto out;
3349 arc4random_buf(cp, 2);
3350 memcpy(cp + 2, cp, 2);
3351
3352 /*
3353 * Store the private key (n and e will not be stored because they
3354 * will be stored in plain text, and storing them also in encrypted
3355 * format would just give known plaintext).
3356 * Note: q and p are stored in reverse order to SSL.
3357 */
3358 if ((r = sshbuf_put_bignum1(buffer, key->rsa->d)) != 0 ||
3359 (r = sshbuf_put_bignum1(buffer, key->rsa->iqmp)) != 0 ||
3360 (r = sshbuf_put_bignum1(buffer, key->rsa->q)) != 0 ||
3361 (r = sshbuf_put_bignum1(buffer, key->rsa->p)) != 0)
3362 goto out;
3363
3364 /* Pad the part to be encrypted to a size that is a multiple of 8. */
3365 explicit_bzero(buf, 8);
3366 if ((r = sshbuf_put(buffer, buf, 8 - (sshbuf_len(buffer) % 8))) != 0)
3367 goto out;
3368
3369 /* This buffer will be used to contain the data in the file. */
3370 if ((encrypted = sshbuf_new()) == NULL) {
3371 r = SSH_ERR_ALLOC_FAIL;
3372 goto out;
3373 }
3374
3375 /* First store keyfile id string. */
3376 if ((r = sshbuf_put(encrypted, LEGACY_BEGIN,
3377 sizeof(LEGACY_BEGIN))) != 0)
3378 goto out;
3379
3380 /* Store cipher type and "reserved" field. */
3381 if ((r = sshbuf_put_u8(encrypted, cipher_num)) != 0 ||
3382 (r = sshbuf_put_u32(encrypted, 0)) != 0)
3383 goto out;
3384
3385 /* Store public key. This will be in plain text. */
3386 if ((r = sshbuf_put_u32(encrypted, BN_num_bits(key->rsa->n))) != 0 ||
3387 (r = sshbuf_put_bignum1(encrypted, key->rsa->n) != 0) ||
3388 (r = sshbuf_put_bignum1(encrypted, key->rsa->e) != 0) ||
3389 (r = sshbuf_put_cstring(encrypted, comment) != 0))
3390 goto out;
3391
3392 /* Allocate space for the private part of the key in the buffer. */
3393 if ((r = sshbuf_reserve(encrypted, sshbuf_len(buffer), &cp)) != 0)
3394 goto out;
3395
3396 if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase,
3397 CIPHER_ENCRYPT)) != 0)
3398 goto out;
3399 if ((r = cipher_crypt(&ciphercontext, 0, cp,
3400 sshbuf_ptr(buffer), sshbuf_len(buffer), 0, 0)) != 0)
3401 goto out;
3402 if ((r = cipher_cleanup(&ciphercontext)) != 0)
3403 goto out;
3404
3405 r = sshbuf_putb(blob, encrypted);
3406
3407 out:
3408 explicit_bzero(&ciphercontext, sizeof(ciphercontext));
3409 explicit_bzero(buf, sizeof(buf));
3410 if (buffer != NULL)
3411 sshbuf_free(buffer);
3412 if (encrypted != NULL)
3413 sshbuf_free(encrypted);
3414
3415 return r;
3416}
3417#endif /* WITH_SSH1 */
3418
3419#ifdef WITH_OPENSSL
3420/* convert SSH v2 key in OpenSSL PEM format */
3421static int
3422sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *blob,
3423 const char *_passphrase, const char *comment)
3424{
3425 int success, r;
3426 int blen, len = strlen(_passphrase);
3427 u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
3428#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
3429 const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
3430#else
3431 const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
3432#endif
3433 const u_char *bptr;
3434 BIO *bio = NULL;
3435
3436 if (len > 0 && len <= 4)
3437 return SSH_ERR_PASSPHRASE_TOO_SHORT;
3438 if ((bio = BIO_new(BIO_s_mem())) == NULL)
3439 return SSH_ERR_ALLOC_FAIL;
3440
3441 switch (key->type) {
3442 case KEY_DSA:
3443 success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
3444 cipher, passphrase, len, NULL, NULL);
3445 break;
3446#ifdef OPENSSL_HAS_ECC
3447 case KEY_ECDSA:
3448 success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
3449 cipher, passphrase, len, NULL, NULL);
3450 break;
3451#endif
3452 case KEY_RSA:
3453 success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
3454 cipher, passphrase, len, NULL, NULL);
3455 break;
3456 default:
3457 success = 0;
3458 break;
3459 }
3460 if (success == 0) {
3461 r = SSH_ERR_LIBCRYPTO_ERROR;
3462 goto out;
3463 }
3464 if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) {
3465 r = SSH_ERR_INTERNAL_ERROR;
3466 goto out;
3467 }
3468 if ((r = sshbuf_put(blob, bptr, blen)) != 0)
3469 goto out;
3470 r = 0;
3471 out:
3472 BIO_free(bio);
3473 return r;
3474}
3475#endif /* WITH_OPENSSL */
3476
3477/* Serialise "key" to buffer "blob" */
3478int
3479sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
3480 const char *passphrase, const char *comment,
3481 int force_new_format, const char *new_format_cipher, int new_format_rounds)
3482{
3483 switch (key->type) {
3484#ifdef WITH_OPENSSL
3485 case KEY_RSA1:
3486 return sshkey_private_rsa1_to_blob(key, blob,
3487 passphrase, comment);
3488 case KEY_DSA:
3489 case KEY_ECDSA:
3490 case KEY_RSA:
3491 if (force_new_format) {
3492 return sshkey_private_to_blob2(key, blob, passphrase,
3493 comment, new_format_cipher, new_format_rounds);
3494 }
3495 return sshkey_private_pem_to_blob(key, blob,
3496 passphrase, comment);
3497#endif /* WITH_OPENSSL */
3498 case KEY_ED25519:
3499 return sshkey_private_to_blob2(key, blob, passphrase,
3500 comment, new_format_cipher, new_format_rounds);
3501 default:
3502 return SSH_ERR_KEY_TYPE_UNKNOWN;
3503 }
3504}
3505
3506#ifdef WITH_SSH1
3507/*
3508 * Parse the public, unencrypted portion of a RSA1 key.
3509 */
3510int
3511sshkey_parse_public_rsa1_fileblob(struct sshbuf *blob,
3512 struct sshkey **keyp, char **commentp)
3513{
3514 int r;
3515 struct sshkey *pub = NULL;
3516 struct sshbuf *copy = NULL;
3517
3518 if (keyp != NULL)
3519 *keyp = NULL;
3520 if (commentp != NULL)
3521 *commentp = NULL;
3522
3523 /* Check that it is at least big enough to contain the ID string. */
3524 if (sshbuf_len(blob) < sizeof(LEGACY_BEGIN))
3525 return SSH_ERR_INVALID_FORMAT;
3526
3527 /*
3528 * Make sure it begins with the id string. Consume the id string
3529 * from the buffer.
3530 */
3531 if (memcmp(sshbuf_ptr(blob), LEGACY_BEGIN, sizeof(LEGACY_BEGIN)) != 0)
3532 return SSH_ERR_INVALID_FORMAT;
3533 /* Make a working copy of the keyblob and skip past the magic */
3534 if ((copy = sshbuf_fromb(blob)) == NULL)
3535 return SSH_ERR_ALLOC_FAIL;
3536 if ((r = sshbuf_consume(copy, sizeof(LEGACY_BEGIN))) != 0)
3537 goto out;
3538
3539 /* Skip cipher type, reserved data and key bits. */
3540 if ((r = sshbuf_get_u8(copy, NULL)) != 0 || /* cipher type */
3541 (r = sshbuf_get_u32(copy, NULL)) != 0 || /* reserved */
3542 (r = sshbuf_get_u32(copy, NULL)) != 0) /* key bits */
3543 goto out;
3544
3545 /* Read the public key from the buffer. */
3546 if ((pub = sshkey_new(KEY_RSA1)) == NULL ||
3547 (r = sshbuf_get_bignum1(copy, pub->rsa->n)) != 0 ||
3548 (r = sshbuf_get_bignum1(copy, pub->rsa->e)) != 0)
3549 goto out;
3550
3551 /* Finally, the comment */
3552 if ((r = sshbuf_get_string(copy, (u_char**)commentp, NULL)) != 0)
3553 goto out;
3554
3555 /* The encrypted private part is not parsed by this function. */
3556
3557 r = 0;
3558 if (keyp != NULL)
3559 *keyp = pub;
3560 else
3561 sshkey_free(pub);
3562 pub = NULL;
3563
3564 out:
3565 if (copy != NULL)
3566 sshbuf_free(copy);
3567 if (pub != NULL)
3568 sshkey_free(pub);
3569 return r;
3570}
3571
3572static int
3573sshkey_parse_private_rsa1(struct sshbuf *blob, const char *passphrase,
3574 struct sshkey **keyp, char **commentp)
3575{
3576 int r;
3577 u_int16_t check1, check2;
3578 u_int8_t cipher_type;
3579 struct sshbuf *decrypted = NULL, *copy = NULL;
3580 u_char *cp;
3581 char *comment = NULL;
3582 struct sshcipher_ctx ciphercontext;
3583 const struct sshcipher *cipher;
3584 struct sshkey *prv = NULL;
3585
3586 *keyp = NULL;
3587 if (commentp != NULL)
3588 *commentp = NULL;
3589
3590 /* Check that it is at least big enough to contain the ID string. */
3591 if (sshbuf_len(blob) < sizeof(LEGACY_BEGIN))
3592 return SSH_ERR_INVALID_FORMAT;
3593
3594 /*
3595 * Make sure it begins with the id string. Consume the id string
3596 * from the buffer.
3597 */
3598 if (memcmp(sshbuf_ptr(blob), LEGACY_BEGIN, sizeof(LEGACY_BEGIN)) != 0)
3599 return SSH_ERR_INVALID_FORMAT;
3600
3601 if ((prv = sshkey_new_private(KEY_RSA1)) == NULL) {
3602 r = SSH_ERR_ALLOC_FAIL;
3603 goto out;
3604 }
3605 if ((copy = sshbuf_fromb(blob)) == NULL ||
3606 (decrypted = sshbuf_new()) == NULL) {
3607 r = SSH_ERR_ALLOC_FAIL;
3608 goto out;
3609 }
3610 if ((r = sshbuf_consume(copy, sizeof(LEGACY_BEGIN))) != 0)
3611 goto out;
3612
3613 /* Read cipher type. */
3614 if ((r = sshbuf_get_u8(copy, &cipher_type)) != 0 ||
3615 (r = sshbuf_get_u32(copy, NULL)) != 0) /* reserved */
3616 goto out;
3617
3618 /* Read the public key and comment from the buffer. */
3619 if ((r = sshbuf_get_u32(copy, NULL)) != 0 || /* key bits */
3620 (r = sshbuf_get_bignum1(copy, prv->rsa->n)) != 0 ||
3621 (r = sshbuf_get_bignum1(copy, prv->rsa->e)) != 0 ||
3622 (r = sshbuf_get_cstring(copy, &comment, NULL)) != 0)
3623 goto out;
3624
3625 /* Check that it is a supported cipher. */
3626 cipher = cipher_by_number(cipher_type);
3627 if (cipher == NULL) {
3628 r = SSH_ERR_KEY_UNKNOWN_CIPHER;
3629 goto out;
3630 }
3631 /* Initialize space for decrypted data. */
3632 if ((r = sshbuf_reserve(decrypted, sshbuf_len(copy), &cp)) != 0)
3633 goto out;
3634
3635 /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
3636 if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase,
3637 CIPHER_DECRYPT)) != 0)
3638 goto out;
3639 if ((r = cipher_crypt(&ciphercontext, 0, cp,
3640 sshbuf_ptr(copy), sshbuf_len(copy), 0, 0)) != 0) {
3641 cipher_cleanup(&ciphercontext);
3642 goto out;
3643 }
3644 if ((r = cipher_cleanup(&ciphercontext)) != 0)
3645 goto out;
3646
3647 if ((r = sshbuf_get_u16(decrypted, &check1)) != 0 ||
3648 (r = sshbuf_get_u16(decrypted, &check2)) != 0)
3649 goto out;
3650 if (check1 != check2) {
3651 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3652 goto out;
3653 }
3654
3655 /* Read the rest of the private key. */
3656 if ((r = sshbuf_get_bignum1(decrypted, prv->rsa->d)) != 0 ||
3657 (r = sshbuf_get_bignum1(decrypted, prv->rsa->iqmp)) != 0 ||
3658 (r = sshbuf_get_bignum1(decrypted, prv->rsa->q)) != 0 ||
3659 (r = sshbuf_get_bignum1(decrypted, prv->rsa->p)) != 0)
3660 goto out;
3661
3662 /* calculate p-1 and q-1 */
3663 if ((r = rsa_generate_additional_parameters(prv->rsa)) != 0)
3664 goto out;
3665
3666 /* enable blinding */
3667 if (RSA_blinding_on(prv->rsa, NULL) != 1) {
3668 r = SSH_ERR_LIBCRYPTO_ERROR;
3669 goto out;
3670 }
3671 r = 0;
3672 *keyp = prv;
3673 prv = NULL;
3674 if (commentp != NULL) {
3675 *commentp = comment;
3676 comment = NULL;
3677 }
3678 out:
3679 explicit_bzero(&ciphercontext, sizeof(ciphercontext));
3680 if (comment != NULL)
3681 free(comment);
3682 if (prv != NULL)
3683 sshkey_free(prv);
3684 if (copy != NULL)
3685 sshbuf_free(copy);
3686 if (decrypted != NULL)
3687 sshbuf_free(decrypted);
3688 return r;
3689}
3690#endif /* WITH_SSH1 */
3691
3692#ifdef WITH_OPENSSL
3693/* XXX make private once ssh-keysign.c fixed */
3694int
3695sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
3696 const char *passphrase, struct sshkey **keyp, char **commentp)
3697{
3698 EVP_PKEY *pk = NULL;
3699 struct sshkey *prv = NULL;
3700 char *name = "<no key>";
3701 BIO *bio = NULL;
3702 int r;
3703
3704 *keyp = NULL;
3705 if (commentp != NULL)
3706 *commentp = NULL;
3707
3708 if ((bio = BIO_new(BIO_s_mem())) == NULL || sshbuf_len(blob) > INT_MAX)
3709 return SSH_ERR_ALLOC_FAIL;
3710 if (BIO_write(bio, sshbuf_ptr(blob), sshbuf_len(blob)) !=
3711 (int)sshbuf_len(blob)) {
3712 r = SSH_ERR_ALLOC_FAIL;
3713 goto out;
3714 }
3715
3716 if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL,
3717 (char *)passphrase)) == NULL) {
3718 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3719 goto out;
3720 }
3721 if (pk->type == EVP_PKEY_RSA &&
3722 (type == KEY_UNSPEC || type == KEY_RSA)) {
3723 if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3724 r = SSH_ERR_ALLOC_FAIL;
3725 goto out;
3726 }
3727 prv->rsa = EVP_PKEY_get1_RSA(pk);
3728 prv->type = KEY_RSA;
3729 name = "rsa w/o comment";
3730#ifdef DEBUG_PK
3731 RSA_print_fp(stderr, prv->rsa, 8);
3732#endif
3733 if (RSA_blinding_on(prv->rsa, NULL) != 1) {
3734 r = SSH_ERR_LIBCRYPTO_ERROR;
3735 goto out;
3736 }
3737 } else if (pk->type == EVP_PKEY_DSA &&
3738 (type == KEY_UNSPEC || type == KEY_DSA)) {
3739 if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3740 r = SSH_ERR_ALLOC_FAIL;
3741 goto out;
3742 }
3743 prv->dsa = EVP_PKEY_get1_DSA(pk);
3744 prv->type = KEY_DSA;
3745 name = "dsa w/o comment";
3746#ifdef DEBUG_PK
3747 DSA_print_fp(stderr, prv->dsa, 8);
3748#endif
3749#ifdef OPENSSL_HAS_ECC
3750 } else if (pk->type == EVP_PKEY_EC &&
3751 (type == KEY_UNSPEC || type == KEY_ECDSA)) {
3752 if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3753 r = SSH_ERR_ALLOC_FAIL;
3754 goto out;
3755 }
3756 prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
3757 prv->type = KEY_ECDSA;
3758 prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa);
3759 if (prv->ecdsa_nid == -1 ||
3760 sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
3761 sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
3762 EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
3763 sshkey_ec_validate_private(prv->ecdsa) != 0) {
3764 r = SSH_ERR_INVALID_FORMAT;
3765 goto out;
3766 }
3767 name = "ecdsa w/o comment";
3768# ifdef DEBUG_PK
3769 if (prv != NULL && prv->ecdsa != NULL)
3770 sshkey_dump_ec_key(prv->ecdsa);
3771# endif
3772#endif /* OPENSSL_HAS_ECC */
3773 } else {
3774 r = SSH_ERR_INVALID_FORMAT;
3775 goto out;
3776 }
3777 if (commentp != NULL &&
3778 (*commentp = strdup(name)) == NULL) {
3779 r = SSH_ERR_ALLOC_FAIL;
3780 goto out;
3781 }
3782 r = 0;
3783 *keyp = prv;
3784 prv = NULL;
3785 out:
3786 BIO_free(bio);
3787 if (pk != NULL)
3788 EVP_PKEY_free(pk);
3789 if (prv != NULL)
3790 sshkey_free(prv);
3791 return r;
3792}
3793#endif /* WITH_OPENSSL */
3794
3795int
3796sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
3797 const char *passphrase, struct sshkey **keyp, char **commentp)
3798{
3799 int r;
3800
3801 *keyp = NULL;
3802 if (commentp != NULL)
3803 *commentp = NULL;
3804
3805 switch (type) {
3806#ifdef WITH_OPENSSL
3807 case KEY_RSA1:
3808 return sshkey_parse_private_rsa1(blob, passphrase,
3809 keyp, commentp);
3810 case KEY_DSA:
3811 case KEY_ECDSA:
3812 case KEY_RSA:
3813 return sshkey_parse_private_pem_fileblob(blob, type, passphrase,
3814 keyp, commentp);
3815#endif /* WITH_OPENSSL */
3816 case KEY_ED25519:
3817 return sshkey_parse_private2(blob, type, passphrase,
3818 keyp, commentp);
3819 case KEY_UNSPEC:
3820 if ((r = sshkey_parse_private2(blob, type, passphrase, keyp,
3821 commentp)) == 0)
3822 return 0;
3823#ifdef WITH_OPENSSL
3824 return sshkey_parse_private_pem_fileblob(blob, type, passphrase,
3825 keyp, commentp);
3826#else
3827 return SSH_ERR_INVALID_FORMAT;
3828#endif /* WITH_OPENSSL */
3829 default:
3830 return SSH_ERR_KEY_TYPE_UNKNOWN;
3831 }
3832}
3833
3834int
3835sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase,
3836 const char *filename, struct sshkey **keyp, char **commentp)
3837{
3838 int r;
3839
3840 if (keyp != NULL)
3841 *keyp = NULL;
3842 if (commentp != NULL)
3843 *commentp = NULL;
3844
3845#ifdef WITH_SSH1
3846 /* it's a SSH v1 key if the public key part is readable */
3847 if ((r = sshkey_parse_public_rsa1_fileblob(buffer, NULL, NULL)) == 0) {
3848 return sshkey_parse_private_fileblob_type(buffer, KEY_RSA1,
3849 passphrase, keyp, commentp);
3850 }
3851#endif /* WITH_SSH1 */
3852 if ((r = sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,
3853 passphrase, keyp, commentp)) == 0)
3854 return 0;
3855 return r;
3856}
diff --git a/sshkey.h b/sshkey.h
new file mode 100644
index 000000000..450b30c1f
--- /dev/null
+++ b/sshkey.h
@@ -0,0 +1,232 @@
1/* $OpenBSD: sshkey.h,v 1.1 2014/06/24 01:16:58 djm Exp $ */
2
3/*
4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26#ifndef SSHKEY_H
27#define SSHKEY_H
28
29#include <sys/types.h>
30
31#ifdef WITH_OPENSSL
32#include <openssl/rsa.h>
33#include <openssl/dsa.h>
34# ifdef OPENSSL_HAS_ECC
35# include <openssl/ec.h>
36# else /* OPENSSL_HAS_ECC */
37# define EC_KEY void
38# define EC_GROUP void
39# define EC_POINT void
40# endif /* OPENSSL_HAS_ECC */
41#else /* WITH_OPENSSL */
42# define RSA void
43# define DSA void
44# define EC_KEY void
45# define EC_GROUP void
46# define EC_POINT void
47#endif /* WITH_OPENSSL */
48
49#define SSH_RSA_MINIMUM_MODULUS_SIZE 768
50#define SSH_KEY_MAX_SIGN_DATA_SIZE (1 << 20)
51
52struct sshbuf;
53
54/* Key types */
55enum sshkey_types {
56 KEY_RSA1,
57 KEY_RSA,
58 KEY_DSA,
59 KEY_ECDSA,
60 KEY_ED25519,
61 KEY_RSA_CERT,
62 KEY_DSA_CERT,
63 KEY_ECDSA_CERT,
64 KEY_ED25519_CERT,
65 KEY_RSA_CERT_V00,
66 KEY_DSA_CERT_V00,
67 KEY_UNSPEC
68};
69
70/* Fingerprint hash algorithms */
71enum sshkey_fp_type {
72 SSH_FP_SHA1,
73 SSH_FP_MD5,
74 SSH_FP_SHA256
75};
76
77/* Fingerprint representation formats */
78enum sshkey_fp_rep {
79 SSH_FP_HEX,
80 SSH_FP_BUBBLEBABBLE,
81 SSH_FP_RANDOMART
82};
83
84/* key is stored in external hardware */
85#define SSHKEY_FLAG_EXT 0x0001
86
87#define SSHKEY_CERT_MAX_PRINCIPALS 256
88/* XXX opaquify? */
89struct sshkey_cert {
90 struct sshbuf *certblob; /* Kept around for use on wire */
91 u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */
92 u_int64_t serial;
93 char *key_id;
94 u_int nprincipals;
95 char **principals;
96 u_int64_t valid_after, valid_before;
97 struct sshbuf *critical;
98 struct sshbuf *extensions;
99 struct sshkey *signature_key;
100};
101
102/* XXX opaquify? */
103struct sshkey {
104 int type;
105 int flags;
106 RSA *rsa;
107 DSA *dsa;
108 int ecdsa_nid; /* NID of curve */
109 EC_KEY *ecdsa;
110 u_char *ed25519_sk;
111 u_char *ed25519_pk;
112 struct sshkey_cert *cert;
113};
114
115#define ED25519_SK_SZ crypto_sign_ed25519_SECRETKEYBYTES
116#define ED25519_PK_SZ crypto_sign_ed25519_PUBLICKEYBYTES
117
118struct sshkey *sshkey_new(int);
119int sshkey_add_private(struct sshkey *);
120struct sshkey *sshkey_new_private(int);
121void sshkey_free(struct sshkey *);
122int sshkey_demote(const struct sshkey *, struct sshkey **);
123int sshkey_equal_public(const struct sshkey *,
124 const struct sshkey *);
125int sshkey_equal(const struct sshkey *, const struct sshkey *);
126char *sshkey_fingerprint(const struct sshkey *,
127 enum sshkey_fp_type, enum sshkey_fp_rep);
128int sshkey_fingerprint_raw(const struct sshkey *k,
129 enum sshkey_fp_type dgst_type, u_char **retp, size_t *lenp);
130const char *sshkey_type(const struct sshkey *);
131const char *sshkey_cert_type(const struct sshkey *);
132int sshkey_write(const struct sshkey *, FILE *);
133int sshkey_read(struct sshkey *, char **);
134u_int sshkey_size(const struct sshkey *);
135
136int sshkey_generate(int type, u_int bits, struct sshkey **keyp);
137int sshkey_from_private(const struct sshkey *, struct sshkey **);
138int sshkey_type_from_name(const char *);
139int sshkey_is_cert(const struct sshkey *);
140int sshkey_type_is_cert(int);
141int sshkey_type_plain(int);
142int sshkey_to_certified(struct sshkey *, int);
143int sshkey_drop_cert(struct sshkey *);
144int sshkey_certify(struct sshkey *, struct sshkey *);
145int sshkey_cert_copy(const struct sshkey *, struct sshkey *);
146int sshkey_cert_check_authority(const struct sshkey *, int, int,
147 const char *, const char **);
148int sshkey_cert_is_legacy(const struct sshkey *);
149
150int sshkey_ecdsa_nid_from_name(const char *);
151int sshkey_curve_name_to_nid(const char *);
152const char * sshkey_curve_nid_to_name(int);
153u_int sshkey_curve_nid_to_bits(int);
154int sshkey_ecdsa_bits_to_nid(int);
155int sshkey_ecdsa_key_to_nid(EC_KEY *);
156int sshkey_ec_nid_to_hash_alg(int nid);
157int sshkey_ec_validate_public(const EC_GROUP *, const EC_POINT *);
158int sshkey_ec_validate_private(const EC_KEY *);
159const char *sshkey_ssh_name(const struct sshkey *);
160const char *sshkey_ssh_name_plain(const struct sshkey *);
161int sshkey_names_valid2(const char *);
162char *key_alg_list(int, int);
163
164int sshkey_from_blob(const u_char *, size_t, struct sshkey **);
165int sshkey_to_blob_buf(const struct sshkey *, struct sshbuf *);
166int sshkey_to_blob(const struct sshkey *, u_char **, size_t *);
167int sshkey_plain_to_blob_buf(const struct sshkey *, struct sshbuf *);
168int sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *);
169
170int sshkey_sign(const struct sshkey *, u_char **, size_t *,
171 const u_char *, size_t, u_int);
172int sshkey_verify(const struct sshkey *, const u_char *, size_t,
173 const u_char *, size_t, u_int);
174
175/* for debug */
176void sshkey_dump_ec_point(const EC_GROUP *, const EC_POINT *);
177void sshkey_dump_ec_key(const EC_KEY *);
178
179/* private key parsing and serialisation */
180int sshkey_private_serialize(const struct sshkey *key, struct sshbuf *buf);
181int sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **keyp);
182
183/* private key file format parsing and serialisation */
184int sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
185 const char *passphrase, const char *comment,
186 int force_new_format, const char *new_format_cipher, int new_format_rounds);
187int sshkey_parse_public_rsa1_fileblob(struct sshbuf *blob,
188 struct sshkey **keyp, char **commentp);
189int sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
190 const char *passphrase, struct sshkey **keyp, char **commentp);
191int sshkey_parse_private_fileblob(struct sshbuf *buffer,
192 const char *passphrase, const char *filename, struct sshkey **keyp,
193 char **commentp);
194int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
195 const char *passphrase, struct sshkey **keyp, char **commentp);
196
197#ifdef SSHKEY_INTERNAL
198int ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
199 const u_char *data, size_t datalen, u_int compat);
200int ssh_rsa_verify(const struct sshkey *key,
201 const u_char *signature, size_t signaturelen,
202 const u_char *data, size_t datalen, u_int compat);
203int ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
204 const u_char *data, size_t datalen, u_int compat);
205int ssh_dss_verify(const struct sshkey *key,
206 const u_char *signature, size_t signaturelen,
207 const u_char *data, size_t datalen, u_int compat);
208int ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
209 const u_char *data, size_t datalen, u_int compat);
210int ssh_ecdsa_verify(const struct sshkey *key,
211 const u_char *signature, size_t signaturelen,
212 const u_char *data, size_t datalen, u_int compat);
213int ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
214 const u_char *data, size_t datalen, u_int compat);
215int ssh_ed25519_verify(const struct sshkey *key,
216 const u_char *signature, size_t signaturelen,
217 const u_char *data, size_t datalen, u_int compat);
218#endif
219
220#if !defined(WITH_OPENSSL)
221# undef RSA
222# undef DSA
223# undef EC_KEY
224# undef EC_GROUP
225# undef EC_POINT
226#elif !defined(OPENSSL_HAS_ECC)
227# undef EC_KEY
228# undef EC_GROUP
229# undef EC_POINT
230#endif
231
232#endif /* SSHKEY_H */
diff --git a/sshlogin.c b/sshlogin.c
index e79ca9b47..7b951c844 100644
--- a/sshlogin.c
+++ b/sshlogin.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshlogin.c,v 1.28 2014/01/31 16:39:19 tedu Exp $ */ 1/* $OpenBSD: sshlogin.c,v 1.29 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -58,6 +58,7 @@
58#include "loginrec.h" 58#include "loginrec.h"
59#include "log.h" 59#include "log.h"
60#include "buffer.h" 60#include "buffer.h"
61#include "misc.h"
61#include "servconf.h" 62#include "servconf.h"
62 63
63extern Buffer loginmsg; 64extern Buffer loginmsg;
diff --git a/sshpty.c b/sshpty.c
index bbbc0fefe..a2059b76d 100644
--- a/sshpty.c
+++ b/sshpty.c
@@ -99,9 +99,6 @@ void
99pty_make_controlling_tty(int *ttyfd, const char *tty) 99pty_make_controlling_tty(int *ttyfd, const char *tty)
100{ 100{
101 int fd; 101 int fd;
102#ifdef USE_VHANGUP
103 void *old;
104#endif /* USE_VHANGUP */
105 102
106#ifdef _UNICOS 103#ifdef _UNICOS
107 if (setsid() < 0) 104 if (setsid() < 0)
@@ -157,21 +154,11 @@ pty_make_controlling_tty(int *ttyfd, const char *tty)
157 if (setpgrp(0,0) < 0) 154 if (setpgrp(0,0) < 0)
158 error("SETPGRP %s",strerror(errno)); 155 error("SETPGRP %s",strerror(errno));
159#endif /* NEED_SETPGRP */ 156#endif /* NEED_SETPGRP */
160#ifdef USE_VHANGUP
161 old = signal(SIGHUP, SIG_IGN);
162 vhangup();
163 signal(SIGHUP, old);
164#endif /* USE_VHANGUP */
165 fd = open(tty, O_RDWR); 157 fd = open(tty, O_RDWR);
166 if (fd < 0) { 158 if (fd < 0) {
167 error("%.100s: %.100s", tty, strerror(errno)); 159 error("%.100s: %.100s", tty, strerror(errno));
168 } else { 160 } else {
169#ifdef USE_VHANGUP
170 close(*ttyfd);
171 *ttyfd = fd;
172#else /* USE_VHANGUP */
173 close(fd); 161 close(fd);
174#endif /* USE_VHANGUP */
175 } 162 }
176 /* Verify that we now have a controlling tty. */ 163 /* Verify that we now have a controlling tty. */
177 fd = open(_PATH_TTY, O_WRONLY); 164 fd = open(_PATH_TTY, O_WRONLY);
diff --git a/umac.c b/umac.c
index 0c62145fa..6eb55b26e 100644
--- a/umac.c
+++ b/umac.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: umac.c,v 1.8 2013/11/08 00:39:15 djm Exp $ */ 1/* $OpenBSD: umac.c,v 1.11 2014/07/22 07:13:42 guenther Exp $ */
2/* ----------------------------------------------------------------------- 2/* -----------------------------------------------------------------------
3 * 3 *
4 * umac.c -- C Implementation UMAC Message Authentication 4 * umac.c -- C Implementation UMAC Message Authentication
@@ -73,13 +73,15 @@
73 73
74#include "includes.h" 74#include "includes.h"
75#include <sys/types.h> 75#include <sys/types.h>
76
77#include "xmalloc.h"
78#include "umac.h"
79#include <string.h> 76#include <string.h>
77#include <stdio.h>
80#include <stdlib.h> 78#include <stdlib.h>
81#include <stddef.h> 79#include <stddef.h>
82 80
81#include "xmalloc.h"
82#include "umac.h"
83#include "misc.h"
84
83/* ---------------------------------------------------------------------- */ 85/* ---------------------------------------------------------------------- */
84/* --- Primitive Data Types --- */ 86/* --- Primitive Data Types --- */
85/* ---------------------------------------------------------------------- */ 87/* ---------------------------------------------------------------------- */
@@ -131,41 +133,17 @@ typedef unsigned int UWORD; /* Register */
131/* --- Endian Conversion --- Forcing assembly on some platforms */ 133/* --- Endian Conversion --- Forcing assembly on some platforms */
132/* ---------------------------------------------------------------------- */ 134/* ---------------------------------------------------------------------- */
133 135
134#if HAVE_SWAP32
135#define LOAD_UINT32_REVERSED(p) (swap32(*(const UINT32 *)(p)))
136#define STORE_UINT32_REVERSED(p,v) (*(UINT32 *)(p) = swap32(v))
137#else /* HAVE_SWAP32 */
138
139static UINT32 LOAD_UINT32_REVERSED(const void *ptr)
140{
141 UINT32 temp = *(const UINT32 *)ptr;
142 temp = (temp >> 24) | ((temp & 0x00FF0000) >> 8 )
143 | ((temp & 0x0000FF00) << 8 ) | (temp << 24);
144 return (UINT32)temp;
145}
146
147# if (__LITTLE_ENDIAN__)
148static void STORE_UINT32_REVERSED(void *ptr, UINT32 x)
149{
150 UINT32 i = (UINT32)x;
151 *(UINT32 *)ptr = (i >> 24) | ((i & 0x00FF0000) >> 8 )
152 | ((i & 0x0000FF00) << 8 ) | (i << 24);
153}
154# endif /* __LITTLE_ENDIAN */
155#endif /* HAVE_SWAP32 */
156
157/* The following definitions use the above reversal-primitives to do the right
158 * thing on endian specific load and stores.
159 */
160
161#if (__LITTLE_ENDIAN__) 136#if (__LITTLE_ENDIAN__)
162#define LOAD_UINT32_LITTLE(ptr) (*(const UINT32 *)(ptr)) 137#define LOAD_UINT32_REVERSED(p) get_u32(p)
163#define STORE_UINT32_BIG(ptr,x) STORE_UINT32_REVERSED(ptr,x) 138#define STORE_UINT32_REVERSED(p,v) put_u32(p,v)
164#else 139#else
165#define LOAD_UINT32_LITTLE(ptr) LOAD_UINT32_REVERSED(ptr) 140#define LOAD_UINT32_REVERSED(p) get_u32_le(p)
166#define STORE_UINT32_BIG(ptr,x) (*(UINT32 *)(ptr) = (UINT32)(x)) 141#define STORE_UINT32_REVERSED(p,v) put_u32_le(p,v)
167#endif 142#endif
168 143
144#define LOAD_UINT32_LITTLE(p) (get_u32_le(p))
145#define STORE_UINT32_BIG(p,v) put_u32(p, v)
146
169/* ---------------------------------------------------------------------- */ 147/* ---------------------------------------------------------------------- */
170/* ---------------------------------------------------------------------- */ 148/* ---------------------------------------------------------------------- */
171/* ----- Begin KDF & PDF Section ---------------------------------------- */ 149/* ----- Begin KDF & PDF Section ---------------------------------------- */
@@ -176,6 +154,7 @@ static void STORE_UINT32_REVERSED(void *ptr, UINT32 x)
176#define AES_BLOCK_LEN 16 154#define AES_BLOCK_LEN 16
177 155
178/* OpenSSL's AES */ 156/* OpenSSL's AES */
157#ifdef WITH_OPENSSL
179#include "openbsd-compat/openssl-compat.h" 158#include "openbsd-compat/openssl-compat.h"
180#ifndef USE_BUILTIN_RIJNDAEL 159#ifndef USE_BUILTIN_RIJNDAEL
181# include <openssl/aes.h> 160# include <openssl/aes.h>
@@ -185,6 +164,16 @@ typedef AES_KEY aes_int_key[1];
185 AES_encrypt((u_char *)(in),(u_char *)(out),(AES_KEY *)int_key) 164 AES_encrypt((u_char *)(in),(u_char *)(out),(AES_KEY *)int_key)
186#define aes_key_setup(key,int_key) \ 165#define aes_key_setup(key,int_key) \
187 AES_set_encrypt_key((const u_char *)(key),UMAC_KEY_LEN*8,int_key) 166 AES_set_encrypt_key((const u_char *)(key),UMAC_KEY_LEN*8,int_key)
167#else
168#include "rijndael.h"
169#define AES_ROUNDS ((UMAC_KEY_LEN / 4) + 6)
170typedef UINT8 aes_int_key[AES_ROUNDS+1][4][4]; /* AES internal */
171#define aes_encryption(in,out,int_key) \
172 rijndaelEncrypt((u32 *)(int_key), AES_ROUNDS, (u8 *)(in), (u8 *)(out))
173#define aes_key_setup(key,int_key) \
174 rijndaelKeySetupEnc((u32 *)(int_key), (const unsigned char *)(key), \
175 UMAC_KEY_LEN*8)
176#endif
188 177
189/* The user-supplied UMAC key is stretched using AES in a counter 178/* The user-supplied UMAC key is stretched using AES in a counter
190 * mode to supply all random bits needed by UMAC. The kdf function takes 179 * mode to supply all random bits needed by UMAC. The kdf function takes
diff --git a/version.h b/version.h
index a1579ace1..cc8a079a9 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
1/* $OpenBSD: version.h,v 1.70 2014/02/27 22:57:40 djm Exp $ */ 1/* $OpenBSD: version.h,v 1.71 2014/04/18 23:52:25 djm Exp $ */
2 2
3#define SSH_VERSION "OpenSSH_6.6" 3#define SSH_VERSION "OpenSSH_6.7"
4 4
5#define SSH_PORTABLE "p1" 5#define SSH_PORTABLE "p1"
6#define SSH_RELEASE SSH_VERSION SSH_PORTABLE 6#define SSH_RELEASE SSH_VERSION SSH_PORTABLE