diff options
68 files changed, 3236 insertions, 979 deletions
diff --git a/crypto/openssh/ChangeLog b/crypto/openssh/ChangeLog index a08e1a7..6a3f64a 100644 --- a/crypto/openssh/ChangeLog +++ b/crypto/openssh/ChangeLog @@ -1,3 +1,522 @@ +20100823 + - (djm) Release OpenSSH-5.6p1 + +20100816 + - (dtucker) [configure.ac openbsd-compat/Makefile.in + openbsd-compat/openbsd-compat.h openbsd-compat/strptime.c] Add strptime to + the compat library which helps on platforms like old IRIX. Based on work + by djm, tested by Tom Christensen. + - OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/08/12 21:49:44 + [ssh.c] + close any extra file descriptors inherited from parent at start and + reopen stdin/stdout to /dev/null when forking for ControlPersist. + + prevents tools that fork and run a captive ssh for communication from + failing to exit when the ssh completes while they wait for these fds to + close. The inherited fds may persist arbitrarily long if a background + mux master has been started by ControlPersist. cvs and scp were effected + by this. + + "please commit" markus@ + - (djm) [regress/README.regress] typo + +20100812 + - (tim) [regress/login-timeout.sh regress/reconfigure.sh regress/reexec.sh + regress/test-exec.sh] Under certain conditions when testing with sudo + tests would fail because the pidfile could not be read by a regular user. + "cat: cannot open ...../regress/pidfile: Permission denied (error 13)" + Make sure cat is run by $SUDO. no objection from me. djm@ + - (tim) [auth.c] add cast to quiet compiler. Change only affects SVR5 systems. + +20100809 + - (djm) bz#1561: don't bother setting IFF_UP on tun(4) device if it is + already set. Makes FreeBSD user openable tunnels useful; patch from + richard.burakowski+ossh AT mrburak.net, ok dtucker@ + - (dtucker) bug #1530: strip trailing ":" from hostname in ssh-copy-id. + based in part on a patch from Colin Watson, ok djm@ + +20100809 + - OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/08/08 16:26:42 + [version.h] + crank to 5.6 + - (djm) [README contrib/caldera/openssh.spec contrib/redhat/openssh.spec] + [contrib/suse/openssh.spec] Crank version numbers + +20100805 + - OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/08/04 05:37:01 + [ssh.1 ssh_config.5 sshd.8] + Remove mentions of weird "addr/port" alternate address format for IPv6 + addresses combinations. It hasn't worked for ages and we have supported + the more commen "[addr]:port" format for a long time. ok jmc@ markus@ + - djm@cvs.openbsd.org 2010/08/04 05:40:39 + [PROTOCOL.certkeys ssh-keygen.c] + tighten the rules for certificate encoding by requiring that options + appear in lexical order and make our ssh-keygen comply. ok markus@ + - djm@cvs.openbsd.org 2010/08/04 05:42:47 + [auth.c auth2-hostbased.c authfile.c authfile.h ssh-keysign.8] + [ssh-keysign.c ssh.c] + enable certificates for hostbased authentication, from Iain Morgan; + "looks ok" markus@ + - djm@cvs.openbsd.org 2010/08/04 05:49:22 + [authfile.c] + commited the wrong version of the hostbased certificate diff; this + version replaces some strlc{py,at} verbosity with xasprintf() at + the request of markus@ + - djm@cvs.openbsd.org 2010/08/04 06:07:11 + [ssh-keygen.1 ssh-keygen.c] + Support CA keys in PKCS#11 tokens; feedback and ok markus@ + - djm@cvs.openbsd.org 2010/08/04 06:08:40 + [ssh-keysign.c] + clean for -Wuninitialized (Id sync only; portable had this change) + - djm@cvs.openbsd.org 2010/08/05 13:08:42 + [channels.c] + Fix a trio of bugs in the local/remote window calculation for datagram + data channels (i.e. TunnelForward): + + Calculate local_consumed correctly in channel_handle_wfd() by measuring + the delta to buffer_len(c->output) from when we start to when we finish. + The proximal problem here is that the output_filter we use in portable + modified the length of the dequeued datagram (to futz with the headers + for !OpenBSD). + + In channel_output_poll(), don't enqueue datagrams that won't fit in the + peer's advertised packet size (highly unlikely to ever occur) or which + won't fit in the peer's remaining window (more likely). + + In channel_input_data(), account for the 4-byte string header in + datagram packets that we accept from the peer and enqueue in c->output. + + report, analysis and testing 2/3 cases from wierbows AT us.ibm.com; + "looks good" markus@ + +20100803 + - (dtucker) [monitor.c] Bug #1795: Initialize the values to be returned from + PAM to sane values in case the PAM method doesn't write to them. Spotted by + Bitman Zhou, ok djm@. + - OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/07/16 04:45:30 + [ssh-keygen.c] + avoid bogus compiler warning + - djm@cvs.openbsd.org 2010/07/16 14:07:35 + [ssh-rsa.c] + more timing paranoia - compare all parts of the expected decrypted + data before returning. AFAIK not exploitable in the SSH protocol. + "groovy" deraadt@ + - djm@cvs.openbsd.org 2010/07/19 03:16:33 + [sftp-client.c] + bz#1797: fix swapped args in upload_dir_internal(), breaking recursive + upload depth checks and causing verbose printing of transfers to always + be turned on; patch from imorgan AT nas.nasa.gov + - djm@cvs.openbsd.org 2010/07/19 09:15:12 + [clientloop.c readconf.c readconf.h ssh.c ssh_config.5] + add a "ControlPersist" option that automatically starts a background + ssh(1) multiplex master when connecting. This connection can stay alive + indefinitely, or can be set to automatically close after a user-specified + duration of inactivity. bz#1330 - patch by dwmw2 AT infradead.org, but + further hacked on by wmertens AT cisco.com, apb AT cequrux.com, + martin-mindrot-bugzilla AT earth.li and myself; "looks ok" markus@ + - djm@cvs.openbsd.org 2010/07/21 02:10:58 + [misc.c] + sync timingsafe_bcmp() with the one dempsky@ committed to sys/lib/libkern + - dtucker@cvs.openbsd.org 2010/07/23 08:49:25 + [ssh.1] + Ciphers is documented in ssh_config(5) these days + +20100819 + - (dtucker) [contrib/ssh-copy-ud.1] Bug #1786: update ssh-copy-id.1 with more + details about its behaviour WRT existing directories. Patch from + asguthrie at gmail com, ok djm. + +20100716 + - (djm) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/07/02 04:32:44 + [misc.c] + unbreak strdelim() skipping past quoted strings, e.g. + AllowUsers "blah blah" blah + was broken; report and fix in bz#1757 from bitman.zhou AT centrify.com + ok dtucker; + - djm@cvs.openbsd.org 2010/07/12 22:38:52 + [ssh.c] + Make ExitOnForwardFailure work with fork-after-authentication ("ssh -f") + for protocol 2. ok markus@ + - djm@cvs.openbsd.org 2010/07/12 22:41:13 + [ssh.c ssh_config.5] + expand %h to the hostname in ssh_config Hostname options. While this + sounds useless, it is actually handy for working with unqualified + hostnames: + + Host *.* + Hostname %h + Host * + Hostname %h.example.org + + "I like it" markus@ + - djm@cvs.openbsd.org 2010/07/13 11:52:06 + [auth-rsa.c channels.c jpake.c key.c misc.c misc.h monitor.c] + [packet.c ssh-rsa.c] + implement a timing_safe_cmp() function to compare memory without leaking + timing information by short-circuiting like memcmp() and use it for + some of the more sensitive comparisons (though nothing high-value was + readily attackable anyway); "looks ok" markus@ + - djm@cvs.openbsd.org 2010/07/13 23:13:16 + [auth-rsa.c channels.c jpake.c key.c misc.c misc.h monitor.c packet.c] + [ssh-rsa.c] + s/timing_safe_cmp/timingsafe_bcmp/g + - jmc@cvs.openbsd.org 2010/07/14 17:06:58 + [ssh.1] + finally ssh synopsis looks nice again! this commit just removes a ton of + hacks we had in place to make it work with old groff; + - schwarze@cvs.openbsd.org 2010/07/15 21:20:38 + [ssh-keygen.1] + repair incorrect block nesting, which screwed up indentation; + problem reported and fix OK by jmc@ + +20100714 + - (tim) [contrib/redhat/openssh.spec] Bug 1796: Test for skip_x11_askpass + (line 77) should have been for no_x11_askpass. + +20100702 + - (djm) OpenBSD CVS Sync + - jmc@cvs.openbsd.org 2010/06/26 00:57:07 + [ssh_config.5] + tweak previous; + - djm@cvs.openbsd.org 2010/06/26 23:04:04 + [ssh.c] + oops, forgot to #include <canohost.h>; spotted and patch from chl@ + - djm@cvs.openbsd.org 2010/06/29 23:15:30 + [ssh-keygen.1 ssh-keygen.c] + allow import (-i) and export (-e) of PEM and PKCS#8 encoded keys; + bz#1749; ok markus@ + - djm@cvs.openbsd.org 2010/06/29 23:16:46 + [auth2-pubkey.c sshd_config.5] + allow key options (command="..." and friends) in AuthorizedPrincipals; + ok markus@ + - jmc@cvs.openbsd.org 2010/06/30 07:24:25 + [ssh-keygen.1] + tweak previous; + - jmc@cvs.openbsd.org 2010/06/30 07:26:03 + [ssh-keygen.c] + sort usage(); + - jmc@cvs.openbsd.org 2010/06/30 07:28:34 + [sshd_config.5] + tweak previous; + - millert@cvs.openbsd.org 2010/07/01 13:06:59 + [scp.c] + Fix a longstanding problem where if you suspend scp at the + password/passphrase prompt the terminal mode is not restored. + OK djm@ + - phessler@cvs.openbsd.org 2010/06/27 19:19:56 + [regress/Makefile] + fix how we run the tests so we can successfully use SUDO='sudo -E' + in our env + - djm@cvs.openbsd.org 2010/06/29 23:59:54 + [cert-userkey.sh] + regress tests for key options in AuthorizedPrincipals + +20100627 + - (tim) [openbsd-compat/port-uw.c] Reorder includes. auth-options.h now needs + key.h. + +20100626 + - (djm) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/05/21 05:00:36 + [misc.c] + colon() returns char*, so s/return (0)/return NULL/ + - markus@cvs.openbsd.org 2010/06/08 21:32:19 + [ssh-pkcs11.c] + check length of value returned C_GetAttributValue for != 0 + from mdrtbugzilla@codefive.co.uk; bugzilla #1773; ok dtucker@ + - djm@cvs.openbsd.org 2010/06/17 07:07:30 + [mux.c] + Correct sizing of object to be allocated by calloc(), replacing + sizeof(state) with sizeof(*state). This worked by accident since + the struct contained a single int at present, but could have broken + in the future. patch from hyc AT symas.com + - djm@cvs.openbsd.org 2010/06/18 00:58:39 + [sftp.c] + unbreak ls in working directories that contains globbing characters in + their pathnames. bz#1655 reported by vgiffin AT apple.com + - djm@cvs.openbsd.org 2010/06/18 03:16:03 + [session.c] + Missing check for chroot_director == "none" (we already checked against + NULL); bz#1564 from Jan.Pechanec AT Sun.COM + - djm@cvs.openbsd.org 2010/06/18 04:43:08 + [sftp-client.c] + fix memory leak in do_realpath() error path; bz#1771, patch from + anicka AT suse.cz + - djm@cvs.openbsd.org 2010/06/22 04:22:59 + [servconf.c sshd_config.5] + expose some more sshd_config options inside Match blocks: + AuthorizedKeysFile AuthorizedPrincipalsFile + HostbasedUsesNameFromPacketOnly PermitTunnel + bz#1764; feedback from imorgan AT nas.nasa.gov; ok dtucker@ + - djm@cvs.openbsd.org 2010/06/22 04:32:06 + [ssh-keygen.c] + standardise error messages when attempting to open private key + files to include "progname: filename: error reason" + bz#1783; ok dtucker@ + - djm@cvs.openbsd.org 2010/06/22 04:49:47 + [auth.c] + queue auth debug messages for bad ownership or permissions on the user's + keyfiles. These messages will be sent after the user has successfully + authenticated (where our client will display them with LogLevel=debug). + bz#1554; ok dtucker@ + - djm@cvs.openbsd.org 2010/06/22 04:54:30 + [ssh-keyscan.c] + replace verbose and overflow-prone Linebuf code with read_keyfile_line() + based on patch from joachim AT joachimschipper.nl; bz#1565; ok dtucker@ + - djm@cvs.openbsd.org 2010/06/22 04:59:12 + [session.c] + include the user name on "subsystem request for ..." log messages; + bz#1571; ok dtucker@ + - djm@cvs.openbsd.org 2010/06/23 02:59:02 + [ssh-keygen.c] + fix printing of extensions in v01 certificates that I broke in r1.190 + - djm@cvs.openbsd.org 2010/06/25 07:14:46 + [channels.c mux.c readconf.c readconf.h ssh.h] + bz#1327: remove hardcoded limit of 100 permitopen clauses and port + forwards per direction; ok markus@ stevesk@ + - djm@cvs.openbsd.org 2010/06/25 07:20:04 + [channels.c session.c] + bz#1750: fix requirement for /dev/null inside ChrootDirectory for + internal-sftp accidentally introduced in r1.253 by removing the code + that opens and dup /dev/null to stderr and modifying the channels code + to read stderr but discard it instead; ok markus@ + - djm@cvs.openbsd.org 2010/06/25 08:46:17 + [auth1.c auth2-none.c] + skip the initial check for access with an empty password when + PermitEmptyPasswords=no; bz#1638; ok markus@ + - djm@cvs.openbsd.org 2010/06/25 23:10:30 + [ssh.c] + log the hostname and address that we connected to at LogLevel=verbose + after authentication is successful to mitigate "phishing" attacks by + servers with trusted keys that accept authentication silently and + automatically before presenting fake password/passphrase prompts; + "nice!" markus@ + - djm@cvs.openbsd.org 2010/06/25 23:10:30 + [ssh.c] + log the hostname and address that we connected to at LogLevel=verbose + after authentication is successful to mitigate "phishing" attacks by + servers with trusted keys that accept authentication silently and + automatically before presenting fake password/passphrase prompts; + "nice!" markus@ + +20100622 + - (djm) [loginrec.c] crank LINFO_NAMESIZE (username length) to 512 + bz#1579; ok dtucker + +20100618 + - (djm) [contrib/ssh-copy-id] Update key file explicitly under ~ + rather than assuming that $CWD == $HOME. bz#1500, patch from + timothy AT gelter.com + +20100617 + - (tim) [contrib/cygwin/README] Remove a reference to the obsolete + minires-devel package, and to add the reference to the libedit-devel + package since CYgwin now provides libedit. Patch from Corinna Vinschen. + +20100521 + - (djm) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/05/07 11:31:26 + [regress/Makefile regress/cert-userkey.sh] + regress tests for AuthorizedPrincipalsFile and "principals=" key option. + feedback and ok markus@ + - djm@cvs.openbsd.org 2010/05/11 02:58:04 + [auth-rsa.c] + don't accept certificates marked as "cert-authority" here; ok markus@ + - djm@cvs.openbsd.org 2010/05/14 00:47:22 + [ssh-add.c] + check that the certificate matches the corresponding private key before + grafting it on + - djm@cvs.openbsd.org 2010/05/14 23:29:23 + [channels.c channels.h mux.c ssh.c] + Pause the mux channel while waiting for reply from aynch callbacks. + Prevents misordering of replies if new requests arrive while waiting. + + Extend channel open confirm callback to allow signalling failure + conditions as well as success. Use this to 1) fix a memory leak, 2) + start using the above pause mechanism and 3) delay sending a success/ + failure message on mux slave session open until we receive a reply from + the server. + + motivated by and with feedback from markus@ + - markus@cvs.openbsd.org 2010/05/16 12:55:51 + [PROTOCOL.mux clientloop.h mux.c readconf.c readconf.h ssh.1 ssh.c] + mux support for remote forwarding with dynamic port allocation, + use with + LPORT=`ssh -S muxsocket -R0:localhost:25 -O forward somehost` + feedback and ok djm@ + - djm@cvs.openbsd.org 2010/05/20 11:25:26 + [auth2-pubkey.c] + fix logspam when key options (from="..." especially) deny non-matching + keys; reported by henning@ also bz#1765; ok markus@ dtucker@ + - djm@cvs.openbsd.org 2010/05/20 23:46:02 + [PROTOCOL.certkeys auth-options.c ssh-keygen.c] + Move the permit-* options to the non-critical "extensions" field for v01 + certificates. The logic is that if another implementation fails to + implement them then the connection just loses features rather than fails + outright. + + ok markus@ + +20100511 + - (dtucker) [Makefile.in] Bug #1770: Link libopenbsd-compat twice to solve + circular dependency problem on old or odd platforms. From Tom Lane, ok + djm@. + - (djm) [openbsd-compat/openssl-compat.h] Fix build breakage on older + libcrypto by defining OPENSSL_[DR]SA_MAX_MODULUS_BITS if they aren't + already. ok dtucker@ + +20100510 + - OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/04/23 01:47:41 + [ssh-keygen.c] + bz#1740: display a more helpful error message when $HOME is + inaccessible while trying to create .ssh directory. Based on patch + from jchadima AT redhat.com; ok dtucker@ + - djm@cvs.openbsd.org 2010/04/23 22:27:38 + [mux.c] + set "detach_close" flag when registering channel cleanup callbacks. + This causes the channel to close normally when its fds close and + hangs when terminating a mux slave using ~. bz#1758; ok markus@ + - djm@cvs.openbsd.org 2010/04/23 22:42:05 + [session.c] + set stderr to /dev/null for subsystems rather than just closing it. + avoids hangs if a subsystem or shell initialisation writes to stderr. + bz#1750; ok markus@ + - djm@cvs.openbsd.org 2010/04/23 22:48:31 + [ssh-keygen.c] + refuse to generate keys longer than OPENSSL_[RD]SA_MAX_MODULUS_BITS, + since we would refuse to use them anyway. bz#1516; ok dtucker@ + - djm@cvs.openbsd.org 2010/04/26 22:28:24 + [sshconnect2.c] + bz#1502: authctxt.success is declared as an int, but passed by + reference to function that accepts sig_atomic_t*. Convert it to + the latter; ok markus@ dtucker@ + - djm@cvs.openbsd.org 2010/05/01 02:50:50 + [PROTOCOL.certkeys] + typo; jmeltzer@ + - dtucker@cvs.openbsd.org 2010/05/05 04:22:09 + [sftp.c] + restore mput and mget which got lost in the tab-completion changes. + found by Kenneth Whitaker, ok djm@ + - djm@cvs.openbsd.org 2010/05/07 11:30:30 + [auth-options.c auth-options.h auth.c auth.h auth2-pubkey.c] + [key.c servconf.c servconf.h sshd.8 sshd_config.5] + add some optional indirection to matching of principal names listed + in certificates. Currently, a certificate must include the a user's name + to be accepted for authentication. This change adds the ability to + specify a list of certificate principal names that are acceptable. + + When authenticating using a CA trusted through ~/.ssh/authorized_keys, + this adds a new principals="name1[,name2,...]" key option. + + For CAs listed through sshd_config's TrustedCAKeys option, a new config + option "AuthorizedPrincipalsFile" specifies a per-user file containing + the list of acceptable names. + + If either option is absent, the current behaviour of requiring the + username to appear in principals continues to apply. + + These options are useful for role accounts, disjoint account namespaces + and "user@realm"-style naming policies in certificates. + + feedback and ok markus@ + - jmc@cvs.openbsd.org 2010/05/07 12:49:17 + [sshd_config.5] + tweak previous; + +20100423 + - (dtucker) [configure.ac] Bug #1756: Check for the existence of a lib64 dir + in the openssl install directory (some newer openssl versions do this on at + least some amd64 platforms). + +20100418 + - OpenBSD CVS Sync + - jmc@cvs.openbsd.org 2010/04/16 06:45:01 + [ssh_config.5] + tweak previous; ok djm + - jmc@cvs.openbsd.org 2010/04/16 06:47:04 + [ssh-keygen.1 ssh-keygen.c] + tweak previous; ok djm + - djm@cvs.openbsd.org 2010/04/16 21:14:27 + [sshconnect.c] + oops, %r => remote username, not %u + - djm@cvs.openbsd.org 2010/04/16 01:58:45 + [regress/cert-hostkey.sh regress/cert-userkey.sh] + regression tests for v01 certificate format + includes interop tests for v00 certs + - (dtucker) [contrib/aix/buildbff.sh] Fix creation of ssh_prng_cmds.default + file. + +20100416 + - (djm) Release openssh-5.5p1 + - OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/03/26 03:13:17 + [bufaux.c] + allow buffer_get_int_ret/buffer_get_int64_ret to take a NULL pointer + argument to allow skipping past values in a buffer + - jmc@cvs.openbsd.org 2010/03/26 06:54:36 + [ssh.1] + tweak previous; + - jmc@cvs.openbsd.org 2010/03/27 14:26:55 + [ssh_config.5] + tweak previous; ok dtucker + - djm@cvs.openbsd.org 2010/04/10 00:00:16 + [ssh.c] + bz#1746 - suppress spurious tty warning when using -O and stdin + is not a tty; ok dtucker@ markus@ + - djm@cvs.openbsd.org 2010/04/10 00:04:30 + [sshconnect.c] + fix terminology: we didn't find a certificate in known_hosts, we found + a CA key + - djm@cvs.openbsd.org 2010/04/10 02:08:44 + [clientloop.c] + bz#1698: kill channel when pty allocation requests fail. Fixed + stuck client if the server refuses pty allocation. + ok dtucker@ "think so" markus@ + - djm@cvs.openbsd.org 2010/04/10 02:10:56 + [sshconnect2.c] + show the key type that we are offering in debug(), helps distinguish + between certs and plain keys as the path to the private key is usually + the same. + - djm@cvs.openbsd.org 2010/04/10 05:48:16 + [mux.c] + fix NULL dereference; from matthew.haub AT alumni.adelaide.edu.au + - djm@cvs.openbsd.org 2010/04/14 22:27:42 + [ssh_config.5 sshconnect.c] + expand %r => remote username in ssh_config:ProxyCommand; + ok deraadt markus + - markus@cvs.openbsd.org 2010/04/15 20:32:55 + [ssh-pkcs11.c] + retry lookup for private key if there's no matching key with CKA_SIGN + attribute enabled; this fixes fixes MuscleCard support (bugzilla #1736) + ok djm@ + - djm@cvs.openbsd.org 2010/04/16 01:47:26 + [PROTOCOL.certkeys auth-options.c auth-options.h auth-rsa.c] + [auth2-pubkey.c authfd.c key.c key.h myproposal.h ssh-add.c] + [ssh-agent.c ssh-dss.c ssh-keygen.1 ssh-keygen.c ssh-rsa.c] + [sshconnect.c sshconnect2.c sshd.c] + revised certificate format ssh-{dss,rsa}-cert-v01@openssh.com with the + following changes: + + move the nonce field to the beginning of the certificate where it can + better protect against chosen-prefix attacks on the signature hash + + Rename "constraints" field to "critical options" + + Add a new non-critical "extensions" field + + Add a serial number + + The older format is still support for authentication and cert generation + (use "ssh-keygen -t v00 -s ca_key ..." to generate a v00 certificate) + + ok markus@ + 20100410 - (dtucker) [configure.ac] Put the check for the existence of getaddrinfo back so we disable the IPv6 tests if we don't have it. diff --git a/crypto/openssh/PROTOCOL.certkeys b/crypto/openssh/PROTOCOL.certkeys index 1ed9e20..1d1be13 100644 --- a/crypto/openssh/PROTOCOL.certkeys +++ b/crypto/openssh/PROTOCOL.certkeys @@ -16,7 +16,7 @@ These protocol extensions build on the simple public key authentication system already in SSH to allow certificate-based authentication. The certificates used are not traditional X.509 certificates, with numerous options and complex encoding rules, but something rather -more minimal: a key, some identity information and usage constraints +more minimal: a key, some identity information and usage options that have been signed with some other trusted key. A sshd server may be configured to allow authentication via certified @@ -27,7 +27,7 @@ of acceptance of certified host keys, by adding a similar ability to specify CA keys in ~/.ssh/known_hosts. Certified keys are represented using two new key types: -ssh-rsa-cert-v00@openssh.com and ssh-dss-cert-v00@openssh.com that +ssh-rsa-cert-v01@openssh.com and ssh-dss-cert-v01@openssh.com that include certification information along with the public key that is used to sign challenges. ssh-keygen performs the CA signing operation. @@ -47,7 +47,7 @@ in RFC4252 section 7. New public key formats ---------------------- -The ssh-rsa-cert-v00@openssh.com and ssh-dss-cert-v00@openssh.com key +The ssh-rsa-cert-v01@openssh.com and ssh-dss-cert-v01@openssh.com key types take a similar high-level format (note: data types and encoding are as per RFC4251 section 5). The serialised wire encoding of these certificates is also used for storing them on disk. @@ -57,42 +57,55 @@ these certificates is also used for storing them on disk. RSA certificate - string "ssh-rsa-cert-v00@openssh.com" + string "ssh-rsa-cert-v01@openssh.com" + string nonce mpint e mpint n + uint64 serial uint32 type string key id string valid principals uint64 valid after uint64 valid before - string constraints - string nonce + string critical options + string extensions string reserved string signature key string signature DSA certificate - string "ssh-dss-cert-v00@openssh.com" + string "ssh-dss-cert-v01@openssh.com" + string nonce mpint p mpint q mpint g mpint y + uint64 serial uint32 type string key id string valid principals uint64 valid after uint64 valid before - string constraints - string nonce + string critical options + string extensions string reserved string signature key string signature +The nonce field is a CA-provided random bitstring of arbitrary length +(but typically 16 or 32 bytes) included to make attacks that depend on +inducing collisions in the signature hash infeasible. + e and n are the RSA exponent and public modulus respectively. p, q, g, y are the DSA parameters as described in FIPS-186-2. +serial is an optional certificate serial number set by the CA to +provide an abbreviated way to refer to certificates from that CA. +If a CA does not wish to number its certificates it must set this +field to zero. + type specifies whether this certificate is for identification of a user or a host using a SSH_CERT_TYPE_... value. @@ -112,13 +125,15 @@ certificate. Each represents a time in seconds since 1970-01-01 00:00:00. A certificate is considered valid if: valid after <= current time < valid before -constraints is a set of zero or more key constraints encoded as below. +criticial options is a set of zero or more key options encoded as +below. All such options are "critical" in the sense that an implementation +must refuse to authorise a key that has an unrecognised option. -The nonce field is a CA-provided random bitstring of arbitrary length -(but typically 16 or 32 bytes) included to make attacks that depend on -inducing collisions in the signature hash infeasible. +extensions is a set of zero or more optional extensions. These extensions +are not critical, and an implementation that encounters one that it does +not recognise may safely ignore it. -The reserved field is current unused and is ignored in this version of +The reserved field is currently unused and is ignored in this version of the protocol. signature key contains the CA key used to sign the certificate. @@ -132,22 +147,25 @@ up to, and including the signature key. Signatures are computed and encoded according to the rules defined for the CA's public key algorithm (RFC4253 section 6.6 for ssh-rsa and ssh-dss). -Constraints ------------ +Critical options +---------------- -The constraints section of the certificate specifies zero or more -constraints on the certificates validity. The format of this field +The critical options section of the certificate specifies zero or more +options on the certificates validity. The format of this field is a sequence of zero or more tuples: string name string data -The name field identifies the constraint and the data field encodes -constraint-specific information (see below). All constraints are -"critical", if an implementation does not recognise a constraint +Options must be lexically ordered by "name" if they appear in the +sequence. + +The name field identifies the option and the data field encodes +option-specific information (see below). All options are +"critical", if an implementation does not recognise a option then the validating party should refuse to accept the certificate. -The supported constraints and the contents and structure of their +The supported options and the contents and structure of their data fields are: Name Format Description @@ -157,37 +175,51 @@ force-command string Specifies a command that is executed ssh command-line) whenever this key is used for authentication. +source-address string Comma-separated list of source addresses + from which this certificate is accepted + for authentication. Addresses are + specified in CIDR format (nn.nn.nn.nn/nn + or hhhh::hhhh/nn). + If this option is not present then + certificates may be presented from any + source address. + +Extensions +---------- + +The extensions section of the certificate specifies zero or more +non-critical certificate extensions. The encoding and ordering of +extensions in this field is identical to that of the critical options. +If an implementation does not recognise an extension, then it should +ignore it. + +The supported extensions and the contents and structure of their data +fields are: + +Name Format Description +----------------------------------------------------------------------------- permit-X11-forwarding empty Flag indicating that X11 forwarding should be permitted. X11 forwarding will - be refused if this constraint is absent. + be refused if this option is absent. permit-agent-forwarding empty Flag indicating that agent forwarding should be allowed. Agent forwarding must not be permitted unless this - constraint is present. + option is present. permit-port-forwarding empty Flag indicating that port-forwarding - should be allowed. If this constraint is + should be allowed. If this option is not present then no port forwarding will be allowed. permit-pty empty Flag indicating that PTY allocation should be permitted. In the absence of - this constraint PTY allocation will be + this option PTY allocation will be disabled. permit-user-rc empty Flag indicating that execution of ~/.ssh/rc should be permitted. Execution of this script will not be permitted if - this constraint is not present. - -source-address string Comma-separated list of source addresses - from which this certificate is accepted - for authentication. Addresses are - specified in CIDR format (nn.nn.nn.nn/nn - or hhhh::hhhh/nn). - If this constraint is not present then - certificates may be presented from any - source address. + this option is not present. -$OpenBSD: PROTOCOL.certkeys,v 1.3 2010/03/03 22:50:40 djm Exp $ +$OpenBSD: PROTOCOL.certkeys,v 1.7 2010/08/04 05:40:39 djm Exp $ diff --git a/crypto/openssh/PROTOCOL.mux b/crypto/openssh/PROTOCOL.mux index d22f737..1d8c463 100644 --- a/crypto/openssh/PROTOCOL.mux +++ b/crypto/openssh/PROTOCOL.mux @@ -109,8 +109,14 @@ A client may request the master to establish a port forward: forwarding type may be MUX_FWD_LOCAL, MUX_FWD_REMOTE, MUX_FWD_DYNAMIC. -A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a -MUX_S_FAILURE. +A server may reply with a MUX_S_OK, a MUX_S_REMOTE_PORT, a +MUX_S_PERMISSION_DENIED or a MUX_S_FAILURE. + +For dynamically allocated listen port the server replies with + + uint32 MUX_S_REMOTE_PORT + uint32 client request id + uint32 allocated remote listen port 5. Requesting closure of port forwards @@ -178,6 +184,7 @@ The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason: #define MUX_S_EXIT_MESSAGE 0x80000004 #define MUX_S_ALIVE 0x80000005 #define MUX_S_SESSION_OPENED 0x80000006 +#define MUX_S_REMOTE_PORT 0x80000007 #define MUX_FWD_LOCAL 1 #define MUX_FWD_REMOTE 2 @@ -193,4 +200,4 @@ XXX server->client error/warning notifications XXX port0 rfwd (need custom response message) XXX send signals via mux -$OpenBSD: PROTOCOL.mux,v 1.1 2010/01/26 01:28:35 djm Exp $ +$OpenBSD: PROTOCOL.mux,v 1.2 2010/05/16 12:55:51 markus Exp $ diff --git a/crypto/openssh/README b/crypto/openssh/README index a29f200..4eaa545 100644 --- a/crypto/openssh/README +++ b/crypto/openssh/README @@ -1,4 +1,4 @@ -See http://www.openssh.com/txt/release-5.5 for the release notes. +See http://www.openssh.com/txt/release-5.6 for the release notes. - A Japanese translation of this document and of the OpenSSH FAQ is - available at http://www.unixuser.org/~haruyama/security/openssh/index.html @@ -62,4 +62,4 @@ References - [6] http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9 [7] http://www.openssh.com/faq.html -$Id: README,v 1.73 2010/03/21 19:11:55 djm Exp $ +$Id: README,v 1.74 2010/08/08 16:32:06 djm Exp $ diff --git a/crypto/openssh/auth-options.c b/crypto/openssh/auth-options.c index 69b314f..a704024 100644 --- a/crypto/openssh/auth-options.c +++ b/crypto/openssh/auth-options.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-options.c,v 1.49 2010/03/16 15:46:52 stevesk Exp $ */ +/* $OpenBSD: auth-options.c,v 1.52 2010/05/20 23:46:02 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -27,10 +27,10 @@ #include "canohost.h" #include "buffer.h" #include "channels.h" -#include "auth-options.h" #include "servconf.h" #include "misc.h" #include "key.h" +#include "auth-options.h" #include "hostfile.h" #include "auth.h" #ifdef GSSAPI @@ -55,6 +55,9 @@ struct envstring *custom_environment = NULL; /* "tunnel=" option. */ int forced_tun_device = -1; +/* "principals=" option. */ +char *authorized_principals = NULL; + extern ServerOptions options; void @@ -76,6 +79,10 @@ auth_clear_options(void) xfree(forced_command); forced_command = NULL; } + if (authorized_principals) { + xfree(authorized_principals); + authorized_principals = NULL; + } forced_tun_device = -1; channel_clear_permitted_opens(); } @@ -141,6 +148,8 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) cp = "command=\""; if (strncasecmp(opts, cp, strlen(cp)) == 0) { opts += strlen(cp); + if (forced_command != NULL) + xfree(forced_command); forced_command = xmalloc(strlen(opts) + 1); i = 0; while (*opts) { @@ -167,6 +176,38 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) opts++; goto next_option; } + cp = "principals=\""; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + opts += strlen(cp); + if (authorized_principals != NULL) + xfree(authorized_principals); + authorized_principals = xmalloc(strlen(opts) + 1); + i = 0; + while (*opts) { + if (*opts == '"') + break; + if (*opts == '\\' && opts[1] == '"') { + opts += 2; + authorized_principals[i++] = '"'; + continue; + } + authorized_principals[i++] = *opts++; + } + if (!*opts) { + debug("%.100s, line %lu: missing end quote", + file, linenum); + auth_debug_add("%.100s, line %lu: missing end quote", + file, linenum); + xfree(authorized_principals); + authorized_principals = NULL; + goto bad_option; + } + authorized_principals[i] = '\0'; + auth_debug_add("principals: %.900s", + authorized_principals); + opts++; + goto next_option; + } cp = "environment=\""; if (options.permit_user_env && strncasecmp(opts, cp, strlen(cp)) == 0) { @@ -376,123 +417,147 @@ bad_option: return 0; } -/* - * Set options from certificate constraints. These supersede user key options - * so this must be called after auth_parse_options(). - */ -int -auth_cert_constraints(Buffer *c_orig, struct passwd *pw) +#define OPTIONS_CRITICAL 1 +#define OPTIONS_EXTENSIONS 2 +static int +parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw, + u_int which, int crit, + int *cert_no_port_forwarding_flag, + int *cert_no_agent_forwarding_flag, + int *cert_no_x11_forwarding_flag, + int *cert_no_pty_flag, + int *cert_no_user_rc, + char **cert_forced_command, + int *cert_source_address_done) { + char *command, *allowed; + const char *remote_ip; u_char *name = NULL, *data_blob = NULL; u_int nlen, dlen, clen; Buffer c, data; - int ret = -1; - - int cert_no_port_forwarding_flag = 1; - int cert_no_agent_forwarding_flag = 1; - int cert_no_x11_forwarding_flag = 1; - int cert_no_pty_flag = 1; - int cert_no_user_rc = 1; - char *cert_forced_command = NULL; - int cert_source_address_done = 0; + int ret = -1, found; buffer_init(&data); /* Make copy to avoid altering original */ buffer_init(&c); - buffer_append(&c, buffer_ptr(c_orig), buffer_len(c_orig)); + buffer_append(&c, optblob, optblob_len); while (buffer_len(&c) > 0) { if ((name = buffer_get_string_ret(&c, &nlen)) == NULL || (data_blob = buffer_get_string_ret(&c, &dlen)) == NULL) { - error("Certificate constraints corrupt"); + error("Certificate options corrupt"); goto out; } buffer_append(&data, data_blob, dlen); - debug3("found certificate constraint \"%.100s\" len %u", + debug3("found certificate option \"%.100s\" len %u", name, dlen); if (strlen(name) != nlen) { error("Certificate constraint name contains \\0"); goto out; } - if (strcmp(name, "permit-X11-forwarding") == 0) - cert_no_x11_forwarding_flag = 0; - else if (strcmp(name, "permit-agent-forwarding") == 0) - cert_no_agent_forwarding_flag = 0; - else if (strcmp(name, "permit-port-forwarding") == 0) - cert_no_port_forwarding_flag = 0; - else if (strcmp(name, "permit-pty") == 0) - cert_no_pty_flag = 0; - else if (strcmp(name, "permit-user-rc") == 0) - cert_no_user_rc = 0; - else if (strcmp(name, "force-command") == 0) { - char *command = buffer_get_string_ret(&data, &clen); - - if (command == NULL) { - error("Certificate constraint \"%s\" corrupt", - name); - goto out; + found = 0; + if ((which & OPTIONS_EXTENSIONS) != 0) { + if (strcmp(name, "permit-X11-forwarding") == 0) { + *cert_no_x11_forwarding_flag = 0; + found = 1; + } else if (strcmp(name, + "permit-agent-forwarding") == 0) { + *cert_no_agent_forwarding_flag = 0; + found = 1; + } else if (strcmp(name, + "permit-port-forwarding") == 0) { + *cert_no_port_forwarding_flag = 0; + found = 1; + } else if (strcmp(name, "permit-pty") == 0) { + *cert_no_pty_flag = 0; + found = 1; + } else if (strcmp(name, "permit-user-rc") == 0) { + *cert_no_user_rc = 0; + found = 1; } - if (strlen(command) != clen) { - error("force-command constraint contains \\0"); - goto out; - } - if (cert_forced_command != NULL) { - error("Certificate has multiple " - "force-command constraints"); - xfree(command); - goto out; - } - cert_forced_command = command; - } else if (strcmp(name, "source-address") == 0) { - char *allowed = buffer_get_string_ret(&data, &clen); - const char *remote_ip = get_remote_ipaddr(); - - if (allowed == NULL) { - error("Certificate constraint \"%s\" corrupt", - name); - goto out; - } - if (strlen(allowed) != clen) { - error("source-address constraint contains \\0"); - goto out; - } - if (cert_source_address_done++) { - error("Certificate has multiple " - "source-address constraints"); - xfree(allowed); - goto out; + } + if (!found && (which & OPTIONS_CRITICAL) != 0) { + if (strcmp(name, "force-command") == 0) { + if ((command = buffer_get_string_ret(&data, + &clen)) == NULL) { + error("Certificate constraint \"%s\" " + "corrupt", name); + goto out; + } + if (strlen(command) != clen) { + error("force-command constraint " + "contains \\0"); + goto out; + } + if (*cert_forced_command != NULL) { + error("Certificate has multiple " + "force-command options"); + xfree(command); + goto out; + } + *cert_forced_command = command; + found = 1; } - switch (addr_match_cidr_list(remote_ip, allowed)) { - case 1: - /* accepted */ - xfree(allowed); - break; - case 0: - /* no match */ - logit("Authentication tried for %.100s with " - "valid certificate but not from a " - "permitted host (ip=%.200s).", - pw->pw_name, remote_ip); - auth_debug_add("Your address '%.200s' is not " - "permitted to use this certificate for " - "login.", remote_ip); - xfree(allowed); - goto out; - case -1: - error("Certificate source-address contents " - "invalid"); - xfree(allowed); - goto out; + if (strcmp(name, "source-address") == 0) { + if ((allowed = buffer_get_string_ret(&data, + &clen)) == NULL) { + error("Certificate constraint " + "\"%s\" corrupt", name); + goto out; + } + if (strlen(allowed) != clen) { + error("source-address constraint " + "contains \\0"); + goto out; + } + if ((*cert_source_address_done)++) { + error("Certificate has multiple " + "source-address options"); + xfree(allowed); + goto out; + } + remote_ip = get_remote_ipaddr(); + switch (addr_match_cidr_list(remote_ip, + allowed)) { + case 1: + /* accepted */ + xfree(allowed); + break; + case 0: + /* no match */ + logit("Authentication tried for %.100s " + "with valid certificate but not " + "from a permitted host " + "(ip=%.200s).", pw->pw_name, + remote_ip); + auth_debug_add("Your address '%.200s' " + "is not permitted to use this " + "certificate for login.", + remote_ip); + xfree(allowed); + goto out; + case -1: + error("Certificate source-address " + "contents invalid"); + xfree(allowed); + goto out; + } + found = 1; } - } else { - error("Certificate constraint \"%s\" is not supported", - name); - goto out; } - if (buffer_len(&data) != 0) { - error("Certificate constraint \"%s\" corrupt " + if (!found) { + if (crit) { + error("Certificate critical option \"%s\" " + "is not supported", name); + goto out; + } else { + logit("Certificate extension \"%s\" " + "is not supported", name); + } + } else if (buffer_len(&data) != 0) { + error("Certificate option \"%s\" corrupt " "(extra data)", name); goto out; } @@ -501,10 +566,73 @@ auth_cert_constraints(Buffer *c_orig, struct passwd *pw) xfree(data_blob); name = data_blob = NULL; } - - /* successfully parsed all constraints */ + /* successfully parsed all options */ ret = 0; + out: + if (ret != 0 && + cert_forced_command != NULL && + *cert_forced_command != NULL) { + xfree(*cert_forced_command); + *cert_forced_command = NULL; + } + if (name != NULL) + xfree(name); + if (data_blob != NULL) + xfree(data_blob); + buffer_free(&data); + buffer_free(&c); + return ret; +} + +/* + * Set options from critical certificate options. These supersede user key + * options so this must be called after auth_parse_options(). + */ +int +auth_cert_options(Key *k, struct passwd *pw) +{ + int cert_no_port_forwarding_flag = 1; + int cert_no_agent_forwarding_flag = 1; + int cert_no_x11_forwarding_flag = 1; + int cert_no_pty_flag = 1; + int cert_no_user_rc = 1; + char *cert_forced_command = NULL; + int cert_source_address_done = 0; + + if (key_cert_is_legacy(k)) { + /* All options are in the one field for v00 certs */ + if (parse_option_list(buffer_ptr(&k->cert->critical), + buffer_len(&k->cert->critical), pw, + OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1, + &cert_no_port_forwarding_flag, + &cert_no_agent_forwarding_flag, + &cert_no_x11_forwarding_flag, + &cert_no_pty_flag, + &cert_no_user_rc, + &cert_forced_command, + &cert_source_address_done) == -1) + return -1; + } else { + /* Separate options and extensions for v01 certs */ + if (parse_option_list(buffer_ptr(&k->cert->critical), + buffer_len(&k->cert->critical), pw, + OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, + &cert_forced_command, + &cert_source_address_done) == -1) + return -1; + if (parse_option_list(buffer_ptr(&k->cert->extensions), + buffer_len(&k->cert->extensions), pw, + OPTIONS_EXTENSIONS, 1, + &cert_no_port_forwarding_flag, + &cert_no_agent_forwarding_flag, + &cert_no_x11_forwarding_flag, + &cert_no_pty_flag, + &cert_no_user_rc, + NULL, NULL) == -1) + return -1; + } + no_port_forwarding_flag |= cert_no_port_forwarding_flag; no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; @@ -516,14 +644,6 @@ auth_cert_constraints(Buffer *c_orig, struct passwd *pw) xfree(forced_command); forced_command = cert_forced_command; } - - out: - if (name != NULL) - xfree(name); - if (data_blob != NULL) - xfree(data_blob); - buffer_free(&data); - buffer_free(&c); - return ret; + return 0; } diff --git a/crypto/openssh/auth-options.h b/crypto/openssh/auth-options.h index 694edc8..7455c94 100644 --- a/crypto/openssh/auth-options.h +++ b/crypto/openssh/auth-options.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-options.h,v 1.18 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: auth-options.h,v 1.20 2010/05/07 11:30:29 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -31,9 +31,10 @@ extern char *forced_command; extern struct envstring *custom_environment; extern int forced_tun_device; extern int key_is_cert_authority; +extern char *authorized_principals; int auth_parse_options(struct passwd *, char *, char *, u_long); void auth_clear_options(void); -int auth_cert_constraints(Buffer *, struct passwd *); +int auth_cert_options(Key *, struct passwd *); #endif diff --git a/crypto/openssh/auth-rsa.c b/crypto/openssh/auth-rsa.c index 65571a8..56702d1 100644 --- a/crypto/openssh/auth-rsa.c +++ b/crypto/openssh/auth-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-rsa.c,v 1.74 2010/03/04 10:36:03 djm Exp $ */ +/* $OpenBSD: auth-rsa.c,v 1.78 2010/07/13 23:13:16 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -34,11 +34,11 @@ #include "uidswap.h" #include "match.h" #include "buffer.h" -#include "auth-options.h" #include "pathnames.h" #include "log.h" #include "servconf.h" #include "key.h" +#include "auth-options.h" #include "hostfile.h" #include "auth.h" #ifdef GSSAPI @@ -116,7 +116,7 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) MD5_Final(mdbuf, &md); /* Verify that the response is the original challenge. */ - if (memcmp(response, mdbuf, 16) != 0) { + if (timingsafe_bcmp(response, mdbuf, 16) != 0) { /* Wrong answer. */ return (0); } @@ -256,7 +256,8 @@ auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) */ if (!auth_parse_options(pw, key_options, file, linenum)) continue; - + if (key_is_cert_authority) + continue; /* break out, this key is allowed */ allowed = 1; break; diff --git a/crypto/openssh/auth.c b/crypto/openssh/auth.c index 2917414..c50db1e 100644 --- a/crypto/openssh/auth.c +++ b/crypto/openssh/auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.c,v 1.86 2010/03/05 02:58:11 djm Exp $ */ +/* $OpenBSD: auth.c,v 1.89 2010/08/04 05:42:47 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -144,7 +144,7 @@ allowed_user(struct passwd * pw) locked = 1; #endif #ifdef USE_LIBIAF - free(passwd); + free((void *) passwd); #endif /* USE_LIBIAF */ if (locked) { logit("User %.100s not allowed because account is locked", @@ -367,6 +367,14 @@ authorized_keys_file2(struct passwd *pw) return expand_authorized_keys(options.authorized_keys_file2, pw); } +char * +authorized_principals_file(struct passwd *pw) +{ + if (options.authorized_principals_file == NULL) + return NULL; + return expand_authorized_keys(options.authorized_principals_file, pw); +} + /* return ok if key exists in sysfile or userfile */ HostStatus check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, @@ -378,7 +386,7 @@ check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, HostStatus host_status; /* Check if we know the host and its host key. */ - found = key_new(key->type); + found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); host_status = check_host_in_hostfile(sysfile, host, key, found, NULL); if (host_status != HOST_OK && userfile != NULL) { @@ -390,6 +398,8 @@ check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, logit("Authentication refused for %.100s: " "bad owner or modes for %.200s", pw->pw_name, user_hostfile); + auth_debug_add("Ignored %.200s: bad ownership or modes", + user_hostfile); } else { temporarily_use_uid(pw); host_status = check_host_in_hostfile(user_hostfile, @@ -478,21 +488,18 @@ secure_filename(FILE *f, const char *file, struct passwd *pw, return 0; } -FILE * -auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) +static FILE * +auth_openfile(const char *file, struct passwd *pw, int strict_modes, + int log_missing, char *file_type) { char line[1024]; struct stat st; int fd; FILE *f; - /* - * Open the file containing the authorized keys - * Fail quietly if file does not exist - */ if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) { - if (errno != ENOENT) - debug("Could not open keyfile '%s': %s", file, + if (log_missing || errno != ENOENT) + debug("Could not open %s '%s': %s", file_type, file, strerror(errno)); return NULL; } @@ -502,8 +509,8 @@ auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) return NULL; } if (!S_ISREG(st.st_mode)) { - logit("User %s authorized keys %s is not a regular file", - pw->pw_name, file); + logit("User %s %s %s is not a regular file", + pw->pw_name, file_type, file); close(fd); return NULL; } @@ -516,12 +523,27 @@ auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) secure_filename(f, file, pw, line, sizeof(line)) != 0) { fclose(f); logit("Authentication refused: %s", line); + auth_debug_add("Ignored %s: %s", file_type, line); return NULL; } return f; } + +FILE * +auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) +{ + return auth_openfile(file, pw, strict_modes, 1, "authorized keys"); +} + +FILE * +auth_openprincipals(const char *file, struct passwd *pw, int strict_modes) +{ + return auth_openfile(file, pw, strict_modes, 0, + "authorized principals"); +} + struct passwd * getpwnamallow(const char *user) { diff --git a/crypto/openssh/auth.h b/crypto/openssh/auth.h index a65b87d..77317ae 100644 --- a/crypto/openssh/auth.h +++ b/crypto/openssh/auth.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.h,v 1.65 2010/03/04 10:36:03 djm Exp $ */ +/* $OpenBSD: auth.h,v 1.66 2010/05/07 11:30:29 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -169,8 +169,10 @@ void abandon_challenge_response(Authctxt *); char *authorized_keys_file(struct passwd *); char *authorized_keys_file2(struct passwd *); +char *authorized_principals_file(struct passwd *); FILE *auth_openkeyfile(const char *, struct passwd *, int); +FILE *auth_openprincipals(const char *, struct passwd *, int); int auth_key_is_revoked(Key *); HostStatus diff --git a/crypto/openssh/auth1.c b/crypto/openssh/auth1.c index 1801661..bf442db 100644 --- a/crypto/openssh/auth1.c +++ b/crypto/openssh/auth1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth1.c,v 1.73 2008/07/04 23:30:16 djm Exp $ */ +/* $OpenBSD: auth1.c,v 1.74 2010/06/25 08:46:17 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved @@ -244,7 +244,7 @@ do_authloop(Authctxt *authctxt) authctxt->valid ? "" : "invalid user ", authctxt->user); /* If the user has no password, accept authentication immediately. */ - if (options.password_authentication && + if (options.permit_empty_passwd && options.password_authentication && #ifdef KRB5 (!options.kerberos_authentication || options.kerberos_or_local_passwd) && #endif diff --git a/crypto/openssh/auth2-hostbased.c b/crypto/openssh/auth2-hostbased.c index 7216465..cdf442f 100644 --- a/crypto/openssh/auth2-hostbased.c +++ b/crypto/openssh/auth2-hostbased.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-hostbased.c,v 1.13 2010/03/04 10:36:03 djm Exp $ */ +/* $OpenBSD: auth2-hostbased.c,v 1.14 2010/08/04 05:42:47 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -141,9 +141,10 @@ int hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, Key *key) { - const char *resolvedname, *ipaddr, *lookup; + const char *resolvedname, *ipaddr, *lookup, *reason; HostStatus host_status; int len; + char *fp; if (auth_key_is_revoked(key)) return 0; @@ -174,16 +175,40 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, } debug2("userauth_hostbased: access allowed by auth_rhosts2"); + if (key_is_cert(key) && + key_cert_check_authority(key, 1, 0, lookup, &reason)) { + error("%s", reason); + auth_debug_add("%s", reason); + return 0; + } + host_status = check_key_in_hostfiles(pw, key, lookup, _PATH_SSH_SYSTEM_HOSTFILE, options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE); /* backward compat if no key has been found. */ - if (host_status == HOST_NEW) + if (host_status == HOST_NEW) { host_status = check_key_in_hostfiles(pw, key, lookup, _PATH_SSH_SYSTEM_HOSTFILE2, options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE2); + } + + if (host_status == HOST_OK) { + if (key_is_cert(key)) { + fp = key_fingerprint(key->cert->signature_key, + SSH_FP_MD5, SSH_FP_HEX); + verbose("Accepted certificate ID \"%s\" signed by " + "%s CA %s from %s@%s", key->cert->key_id, + key_type(key->cert->signature_key), fp, + cuser, lookup); + } else { + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + verbose("Accepted %s public key %s from %s@%s", + key_type(key), fp, cuser, lookup); + } + xfree(fp); + } return (host_status == HOST_OK); } diff --git a/crypto/openssh/auth2-none.c b/crypto/openssh/auth2-none.c index 08f2f93..c8c6c74 100644 --- a/crypto/openssh/auth2-none.c +++ b/crypto/openssh/auth2-none.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-none.c,v 1.15 2008/07/02 12:36:39 djm Exp $ */ +/* $OpenBSD: auth2-none.c,v 1.16 2010/06/25 08:46:17 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -61,7 +61,7 @@ userauth_none(Authctxt *authctxt) { none_enabled = 0; packet_check_eom(); - if (options.password_authentication) + if (options.permit_empty_passwd && options.password_authentication) return (PRIVSEP(auth_password(authctxt, ""))); return (0); } diff --git a/crypto/openssh/auth2-pubkey.c b/crypto/openssh/auth2-pubkey.c index c4cadf4..35cf79c 100644 --- a/crypto/openssh/auth2-pubkey.c +++ b/crypto/openssh/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.22 2010/03/10 23:27:17 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.26 2010/06/29 23:16:46 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -57,6 +57,7 @@ #include "monitor_wrap.h" #include "misc.h" #include "authfile.h" +#include "match.h" /* import */ extern ServerOptions options; @@ -176,6 +177,83 @@ done: return authenticated; } +static int +match_principals_option(const char *principal_list, struct KeyCert *cert) +{ + char *result; + u_int i; + + /* XXX percent_expand() sequences for authorized_principals? */ + + for (i = 0; i < cert->nprincipals; i++) { + if ((result = match_list(cert->principals[i], + principal_list, NULL)) != NULL) { + debug3("matched principal from key options \"%.100s\"", + result); + xfree(result); + return 1; + } + } + return 0; +} + +static int +match_principals_file(char *file, struct passwd *pw, struct KeyCert *cert) +{ + FILE *f; + char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; + u_long linenum = 0; + u_int i; + + temporarily_use_uid(pw); + debug("trying authorized principals file %s", file); + if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { + restore_uid(); + return 0; + } + while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { + /* Skip leading whitespace. */ + for (cp = line; *cp == ' ' || *cp == '\t'; cp++) + ; + /* Skip blank and comment lines. */ + if ((ep = strchr(cp, '#')) != NULL) + *ep = '\0'; + if (!*cp || *cp == '\n') + continue; + /* Trim trailing whitespace. */ + ep = cp + strlen(cp) - 1; + while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) + *ep-- = '\0'; + /* + * If the line has internal whitespace then assume it has + * key options. + */ + line_opts = NULL; + if ((ep = strrchr(cp, ' ')) != NULL || + (ep = strrchr(cp, '\t')) != NULL) { + for (; *ep == ' ' || *ep == '\t'; ep++) + ;; + line_opts = cp; + cp = ep; + } + for (i = 0; i < cert->nprincipals; i++) { + if (strcmp(cp, cert->principals[i]) == 0) { + debug3("matched principal from file \"%.100s\"", + cert->principals[i]); + if (auth_parse_options(pw, line_opts, + file, linenum) != 1) + continue; + fclose(f); + restore_uid(); + return 1; + } + } + } + fclose(f); + restore_uid(); + return 0; +} + /* return 1 if user allows given key */ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) @@ -233,26 +311,39 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) continue; } } - if (auth_parse_options(pw, key_options, file, linenum) != 1) - continue; - if (key->type == KEY_RSA_CERT || key->type == KEY_DSA_CERT) { - if (!key_is_cert_authority) - continue; + if (key_is_cert(key)) { if (!key_equal(found, key->cert->signature_key)) continue; + if (auth_parse_options(pw, key_options, file, + linenum) != 1) + continue; + if (!key_is_cert_authority) + continue; fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); debug("matching CA found: file %s, line %lu, %s %s", file, linenum, key_type(found), fp); - if (key_cert_check_authority(key, 0, 0, pw->pw_name, - &reason) != 0) { + /* + * If the user has specified a list of principals as + * a key option, then prefer that list to matching + * their username in the certificate principals list. + */ + if (authorized_principals != NULL && + !match_principals_option(authorized_principals, + key->cert)) { + reason = "Certificate does not contain an " + "authorized principal"; + fail_reason: xfree(fp); error("%s", reason); auth_debug_add("%s", reason); continue; } - if (auth_cert_constraints(&key->cert->constraints, - pw) != 0) { + if (key_cert_check_authority(key, 0, 0, + authorized_principals == NULL ? pw->pw_name : NULL, + &reason) != 0) + goto fail_reason; + if (auth_cert_options(key, pw) != 0) { xfree(fp); continue; } @@ -262,7 +353,12 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) xfree(fp); found_key = 1; break; - } else if (!key_is_cert_authority && key_equal(found, key)) { + } else if (key_equal(found, key)) { + if (auth_parse_options(pw, key_options, file, + linenum) != 1) + continue; + if (key_is_cert_authority) + continue; found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); @@ -285,7 +381,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) static int user_cert_trusted_ca(struct passwd *pw, Key *key) { - char *ca_fp; + char *ca_fp, *principals_file = NULL; const char *reason; int ret = 0; @@ -302,12 +398,25 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) options.trusted_user_ca_keys); goto out; } - if (key_cert_check_authority(key, 0, 1, pw->pw_name, &reason) != 0) { - error("%s", reason); - auth_debug_add("%s", reason); - goto out; + /* + * If AuthorizedPrincipals is in use, then compare the certificate + * principals against the names in that file rather than matching + * against the username. + */ + if ((principals_file = authorized_principals_file(pw)) != NULL) { + if (!match_principals_file(principals_file, pw, key->cert)) { + reason = "Certificate does not contain an " + "authorized principal"; + fail_reason: + error("%s", reason); + auth_debug_add("%s", reason); + goto out; + } } - if (auth_cert_constraints(&key->cert->constraints, pw) != 0) + if (key_cert_check_authority(key, 0, 1, + principals_file == NULL ? pw->pw_name : NULL, &reason) != 0) + goto fail_reason; + if (auth_cert_options(key, pw) != 0) goto out; verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s", @@ -316,6 +425,8 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) ret = 1; out: + if (principals_file != NULL) + xfree(principals_file); if (ca_fp != NULL) xfree(ca_fp); return ret; diff --git a/crypto/openssh/authfd.c b/crypto/openssh/authfd.c index 28a8cf2..739722f 100644 --- a/crypto/openssh/authfd.c +++ b/crypto/openssh/authfd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.c,v 1.82 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: authfd.c,v 1.83 2010/04/16 01:47:26 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -483,6 +483,7 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) buffer_put_bignum2(b, key->rsa->p); buffer_put_bignum2(b, key->rsa->q); break; + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) fatal("%s: no cert/certblob", __func__); @@ -500,6 +501,7 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) buffer_put_bignum2(b, key->dsa->pub_key); buffer_put_bignum2(b, key->dsa->priv_key); break; + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) fatal("%s: no cert/certblob", __func__); @@ -535,8 +537,10 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, break; case KEY_RSA: case KEY_RSA_CERT: + case KEY_RSA_CERT_V00: case KEY_DSA: case KEY_DSA_CERT: + case KEY_DSA_CERT_V00: type = constrained ? SSH2_AGENTC_ADD_ID_CONSTRAINED : SSH2_AGENTC_ADD_IDENTITY; diff --git a/crypto/openssh/authfile.c b/crypto/openssh/authfile.c index 224c6aa..2bd8878 100644 --- a/crypto/openssh/authfile.c +++ b/crypto/openssh/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.80 2010/03/04 10:36:03 djm Exp $ */ +/* $OpenBSD: authfile.c,v 1.82 2010/08/04 05:49:22 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -693,6 +693,66 @@ key_load_public(const char *filename, char **commentp) return NULL; } +/* Load the certificate associated with the named private key */ +Key * +key_load_cert(const char *filename) +{ + Key *pub; + char *file; + + pub = key_new(KEY_UNSPEC); + xasprintf(&file, "%s-cert.pub", filename); + if (key_try_load_public(pub, file, NULL) == 1) { + xfree(file); + return pub; + } + xfree(file); + key_free(pub); + return NULL; +} + +/* Load private key and certificate */ +Key * +key_load_private_cert(int type, const char *filename, const char *passphrase, + int *perm_ok) +{ + Key *key, *pub; + + switch (type) { + case KEY_RSA: + case KEY_DSA: + break; + default: + error("%s: unsupported key type", __func__); + return NULL; + } + + if ((key = key_load_private_type(type, filename, + passphrase, NULL, perm_ok)) == NULL) + return NULL; + + if ((pub = key_load_cert(filename)) == NULL) { + key_free(key); + return NULL; + } + + /* Make sure the private key matches the certificate */ + if (key_equal_public(key, pub) == 0) { + error("%s: certificate does not match private key %s", + __func__, filename); + } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) { + error("%s: key_to_certified failed", __func__); + } else { + key_cert_copy(pub, key); + key_free(pub); + return key; + } + + key_free(key); + key_free(pub); + return NULL; +} + /* * Returns 1 if the specified "key" is listed in the file "filename", * 0 if the key is not listed or -1 on error. diff --git a/crypto/openssh/authfile.h b/crypto/openssh/authfile.h index 6dfa478..6745dc0 100644 --- a/crypto/openssh/authfile.h +++ b/crypto/openssh/authfile.h @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.h,v 1.14 2010/03/04 10:36:03 djm Exp $ */ +/* $OpenBSD: authfile.h,v 1.15 2010/08/04 05:42:47 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -16,9 +16,11 @@ #define AUTHFILE_H int key_save_private(Key *, const char *, const char *, const char *); +Key *key_load_cert(const char *); Key *key_load_public(const char *, char **); Key *key_load_public_type(int, const char *, char **); Key *key_load_private(const char *, const char *, char **); +Key *key_load_private_cert(int, const char *, const char *, int *); Key *key_load_private_type(int, const char *, const char *, char **, int *); Key *key_load_private_pem(int, int, const char *, char **); int key_perm_ok(int, const char *); diff --git a/crypto/openssh/bufaux.c b/crypto/openssh/bufaux.c index 4ef19c4..854fd51 100644 --- a/crypto/openssh/bufaux.c +++ b/crypto/openssh/bufaux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bufaux.c,v 1.48 2010/02/02 22:49:34 djm Exp $ */ +/* $OpenBSD: bufaux.c,v 1.49 2010/03/26 03:13:17 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -84,7 +84,8 @@ buffer_get_int_ret(u_int *ret, Buffer *buffer) if (buffer_get_ret(buffer, (char *) buf, 4) == -1) return (-1); - *ret = get_u32(buf); + if (ret != NULL) + *ret = get_u32(buf); return (0); } @@ -106,7 +107,8 @@ buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer) if (buffer_get_ret(buffer, (char *) buf, 8) == -1) return (-1); - *ret = get_u64(buf); + if (ret != NULL) + *ret = get_u64(buf); return (0); } diff --git a/crypto/openssh/channels.c b/crypto/openssh/channels.c index a55d278..1cd5004 100644 --- a/crypto/openssh/channels.c +++ b/crypto/openssh/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.303 2010/01/30 21:12:08 djm Exp $ */ +/* $OpenBSD: channels.c,v 1.309 2010/08/05 13:08:42 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -114,10 +114,10 @@ typedef struct { } ForwardPermission; /* List of all permitted host/port pairs to connect by the user. */ -static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; +static ForwardPermission *permitted_opens = NULL; /* List of all permitted host/port pairs to connect by the admin. */ -static ForwardPermission permitted_adm_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; +static ForwardPermission *permitted_adm_opens = NULL; /* Number of permitted host/port pairs in the array permitted by the user. */ static int num_permitted_opens = 0; @@ -330,6 +330,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, c->ctl_chan = -1; c->mux_rcb = NULL; c->mux_ctx = NULL; + c->mux_pause = 0; c->delayed = 1; /* prevent call to channel_post handler */ TAILQ_INIT(&c->status_confirms); debug("channel %d: new [%s]", found, remote_name); @@ -703,7 +704,7 @@ channel_register_status_confirm(int id, channel_confirm_cb *cb, } void -channel_register_open_confirm(int id, channel_callback_fn *fn, void *ctx) +channel_register_open_confirm(int id, channel_open_fn *fn, void *ctx) { Channel *c = channel_lookup(id); @@ -838,8 +839,9 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset) if (c->extended_usage == CHAN_EXTENDED_WRITE && buffer_len(&c->extended) > 0) FD_SET(c->efd, writeset); - else if (!(c->flags & CHAN_EOF_SENT) && - c->extended_usage == CHAN_EXTENDED_READ && + else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) && + (c->extended_usage == CHAN_EXTENDED_READ || + c->extended_usage == CHAN_EXTENDED_IGNORE) && buffer_len(&c->extended) < c->remote_window) FD_SET(c->efd, readset); } @@ -915,7 +917,7 @@ x11_open_helper(Buffer *b) } /* Check if authentication data matches our fake data. */ if (data_len != x11_fake_data_len || - memcmp(ucp + 12 + ((proto_len + 3) & ~3), + timingsafe_bcmp(ucp + 12 + ((proto_len + 3) & ~3), x11_fake_data, x11_fake_data_len) != 0) { debug2("X11 auth data does not match fake data."); return -1; @@ -991,7 +993,7 @@ channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset) static void channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset) { - if (c->istate == CHAN_INPUT_OPEN && + if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause && buffer_check_alloc(&c->input, CHAN_RBUF)) FD_SET(c->rfd, readset); if (c->istate == CHAN_INPUT_WAIT_DRAIN) { @@ -1642,13 +1644,14 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset) { struct termios tio; u_char *data = NULL, *buf; - u_int dlen; + u_int dlen, olen = 0; int len; /* Send buffered output data to the socket. */ if (c->wfd != -1 && FD_ISSET(c->wfd, writeset) && buffer_len(&c->output) > 0) { + olen = buffer_len(&c->output); if (c->output_filter != NULL) { if ((buf = c->output_filter(c, &data, &dlen)) == NULL) { debug2("channel %d: filter stops", c->self); @@ -1667,7 +1670,6 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset) if (c->datagram) { /* ignore truncated writes, datagrams might get lost */ - c->local_consumed += dlen + 4; len = write(c->wfd, buf, dlen); xfree(data); if (len < 0 && (errno == EINTR || errno == EAGAIN || @@ -1680,7 +1682,7 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset) chan_write_failed(c); return -1; } - return 1; + goto out; } #ifdef _AIX /* XXX: Later AIX versions can't push as much data to tty */ @@ -1722,10 +1724,10 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset) } #endif buffer_consume(&c->output, len); - if (compat20 && len > 0) { - c->local_consumed += len; - } } + out: + if (compat20 && olen > 0) + c->local_consumed += olen - buffer_len(&c->output); return 1; } @@ -1755,7 +1757,9 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset) buffer_consume(&c->extended, len); c->local_consumed += len; } - } else if (c->extended_usage == CHAN_EXTENDED_READ && + } else if (c->efd != -1 && + (c->extended_usage == CHAN_EXTENDED_READ || + c->extended_usage == CHAN_EXTENDED_IGNORE) && (c->detach_close || FD_ISSET(c->efd, readset))) { len = read(c->efd, buf, sizeof(buf)); debug2("channel %d: read %d from efd %d", @@ -1768,7 +1772,11 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset) c->self, c->efd); channel_close_fd(&c->efd); } else { - buffer_append(&c->extended, buf, len); + if (c->extended_usage == CHAN_EXTENDED_IGNORE) { + debug3("channel %d: discard efd", + c->self); + } else + buffer_append(&c->extended, buf, len); } } } @@ -1840,7 +1848,7 @@ channel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset) if (!compat20) fatal("%s: entered with !compat20", __func__); - if (c->rfd != -1 && FD_ISSET(c->rfd, readset) && + if (c->rfd != -1 && !c->mux_pause && FD_ISSET(c->rfd, readset) && (c->istate == CHAN_INPUT_OPEN || c->istate == CHAN_INPUT_WAIT_DRAIN)) { /* @@ -2164,6 +2172,14 @@ channel_output_poll(void) data = buffer_get_string(&c->input, &dlen); + if (dlen > c->remote_window || + dlen > c->remote_maxpacket) { + debug("channel %d: datagram " + "too big for channel", + c->self); + xfree(data); + continue; + } packet_start(SSH2_MSG_CHANNEL_DATA); packet_put_int(c->remote_id); packet_put_string(data, dlen); @@ -2249,7 +2265,7 @@ channel_input_data(int type, u_int32_t seq, void *ctxt) { int id; char *data; - u_int data_len; + u_int data_len, win_len; Channel *c; /* Get the channel number and verify it. */ @@ -2265,6 +2281,9 @@ channel_input_data(int type, u_int32_t seq, void *ctxt) /* Get the data. */ data = packet_get_string_ptr(&data_len); + win_len = data_len; + if (c->datagram) + win_len += 4; /* string length header */ /* * Ignore data for protocol > 1.3 if output end is no longer open. @@ -2275,23 +2294,23 @@ channel_input_data(int type, u_int32_t seq, void *ctxt) */ if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) { if (compat20) { - c->local_window -= data_len; - c->local_consumed += data_len; + c->local_window -= win_len; + c->local_consumed += win_len; } return; } if (compat20) { - if (data_len > c->local_maxpacket) { + if (win_len > c->local_maxpacket) { logit("channel %d: rcvd big packet %d, maxpack %d", - c->self, data_len, c->local_maxpacket); + c->self, win_len, c->local_maxpacket); } - if (data_len > c->local_window) { + if (win_len > c->local_window) { logit("channel %d: rcvd too much data %d, win %d", - c->self, data_len, c->local_window); + c->self, win_len, c->local_window); return; } - c->local_window -= data_len; + c->local_window -= win_len; } if (c->datagram) buffer_put_string(&c->output, data, data_len); @@ -2463,7 +2482,7 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) c->remote_maxpacket = packet_get_int(); if (c->open_confirm) { debug2("callback start"); - c->open_confirm(c->self, c->open_confirm_ctx); + c->open_confirm(c->self, 1, c->open_confirm_ctx); debug2("callback done"); } debug2("channel %d: open confirm rwindow %u rmax %u", c->self, @@ -2514,6 +2533,11 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt) xfree(msg); if (lang != NULL) xfree(lang); + if (c->open_confirm) { + debug2("callback start"); + c->open_confirm(c->self, 0, c->open_confirm_ctx); + debug2("callback done"); + } } packet_check_eom(); /* Schedule the channel for cleanup/deletion. */ @@ -2832,10 +2856,6 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port, { int type, success = 0; - /* Record locally that connection to this host/port is permitted. */ - if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) - fatal("channel_request_remote_forwarding: too many forwards"); - /* Send the forward request to the remote side. */ if (compat20) { const char *address_to_bind; @@ -2885,6 +2905,9 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port, } } if (success) { + /* Record that connection to this host/port is permitted. */ + permitted_opens = xrealloc(permitted_opens, + num_permitted_opens + 1, sizeof(*permitted_opens)); permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; permitted_opens[num_permitted_opens].listen_port = listen_port; @@ -2982,10 +3005,10 @@ channel_permit_all_opens(void) void channel_add_permitted_opens(char *host, int port) { - if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) - fatal("channel_add_permitted_opens: too many forwards"); debug("allow port forwarding to host %s port %d", host, port); + permitted_opens = xrealloc(permitted_opens, + num_permitted_opens + 1, sizeof(*permitted_opens)); permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); permitted_opens[num_permitted_opens].port_to_connect = port; num_permitted_opens++; @@ -2996,10 +3019,10 @@ channel_add_permitted_opens(char *host, int port) int channel_add_adm_permitted_opens(char *host, int port) { - if (num_adm_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) - fatal("channel_add_adm_permitted_opens: too many forwards"); debug("config allows port forwarding to host %s port %d", host, port); + permitted_adm_opens = xrealloc(permitted_adm_opens, + num_adm_permitted_opens + 1, sizeof(*permitted_adm_opens)); permitted_adm_opens[num_adm_permitted_opens].host_to_connect = xstrdup(host); permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port; @@ -3014,6 +3037,10 @@ channel_clear_permitted_opens(void) for (i = 0; i < num_permitted_opens; i++) if (permitted_opens[i].host_to_connect != NULL) xfree(permitted_opens[i].host_to_connect); + if (num_permitted_opens > 0) { + xfree(permitted_opens); + permitted_opens = NULL; + } num_permitted_opens = 0; } @@ -3025,6 +3052,10 @@ channel_clear_adm_permitted_opens(void) for (i = 0; i < num_adm_permitted_opens; i++) if (permitted_adm_opens[i].host_to_connect != NULL) xfree(permitted_adm_opens[i].host_to_connect); + if (num_adm_permitted_opens > 0) { + xfree(permitted_adm_opens); + permitted_adm_opens = NULL; + } num_adm_permitted_opens = 0; } diff --git a/crypto/openssh/channels.h b/crypto/openssh/channels.h index cc71885..0680ed0 100644 --- a/crypto/openssh/channels.h +++ b/crypto/openssh/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.103 2010/01/26 01:28:35 djm Exp $ */ +/* $OpenBSD: channels.h,v 1.104 2010/05/14 23:29:23 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -60,6 +60,7 @@ struct Channel; typedef struct Channel Channel; +typedef void channel_open_fn(int, int, void *); typedef void channel_callback_fn(int, void *); typedef int channel_infilter_fn(struct Channel *, char *, int); typedef void channel_filter_cleanup_fn(int, void *); @@ -130,7 +131,7 @@ struct Channel { char *ctype; /* type */ /* callback */ - channel_callback_fn *open_confirm; + channel_open_fn *open_confirm; void *open_confirm_ctx; channel_callback_fn *detach_user; int detach_close; @@ -151,6 +152,7 @@ struct Channel { /* multiplexing protocol hook, called for each packet received */ mux_callback_fn *mux_rcb; void *mux_ctx; + int mux_pause; }; #define CHAN_EXTENDED_IGNORE 0 @@ -208,7 +210,7 @@ void channel_stop_listening(void); void channel_send_open(int); void channel_request_start(int, char *, int); void channel_register_cleanup(int, channel_callback_fn *, int); -void channel_register_open_confirm(int, channel_callback_fn *, void *); +void channel_register_open_confirm(int, channel_open_fn *, void *); void channel_register_filter(int, channel_infilter_fn *, channel_outfilter_fn *, channel_filter_cleanup_fn *, void *); void channel_register_status_confirm(int, channel_confirm_cb *, diff --git a/crypto/openssh/clientloop.c b/crypto/openssh/clientloop.c index 9ab56b4..de79793 100644 --- a/crypto/openssh/clientloop.c +++ b/crypto/openssh/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.219 2010/03/13 21:10:38 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.222 2010/07/19 09:15:12 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -145,6 +145,9 @@ static volatile sig_atomic_t received_signal = 0; /* Flag indicating whether the user's terminal is in non-blocking mode. */ static int in_non_blocking_mode = 0; +/* Time when backgrounded control master using ControlPersist should exit */ +static time_t control_persist_exit_time = 0; + /* Common data for the client loop code. */ volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ static int escape_char1; /* Escape character. (proto1 only) */ @@ -155,11 +158,12 @@ static int stdin_eof; /* EOF has been encountered on stderr. */ static Buffer stdin_buffer; /* Buffer for stdin data. */ static Buffer stdout_buffer; /* Buffer for stdout data. */ static Buffer stderr_buffer; /* Buffer for stderr data. */ -static u_int buffer_high;/* Soft max buffer size. */ +static u_int buffer_high; /* Soft max buffer size. */ static int connection_in; /* Connection to server (input). */ static int connection_out; /* Connection to server (output). */ static int need_rekeying; /* Set to non-zero if rekeying is requested. */ -static int session_closed = 0; /* In SSH2: login session closed. */ +static int session_closed; /* In SSH2: login session closed. */ +static int x11_refuse_time; /* If >0, refuse x11 opens after this time. */ static void client_init_dispatch(void); int session_ident = -1; @@ -251,10 +255,38 @@ get_current_time(void) return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; } +/* + * Sets control_persist_exit_time to the absolute time when the + * backgrounded control master should exit due to expiry of the + * ControlPersist timeout. Sets it to 0 if we are not a backgrounded + * control master process, or if there is no ControlPersist timeout. + */ +static void +set_control_persist_exit_time(void) +{ + if (muxserver_sock == -1 || !options.control_persist + || options.control_persist_timeout == 0) + /* not using a ControlPersist timeout */ + control_persist_exit_time = 0; + else if (channel_still_open()) { + /* some client connections are still open */ + if (control_persist_exit_time > 0) + debug2("%s: cancel scheduled exit", __func__); + control_persist_exit_time = 0; + } else if (control_persist_exit_time <= 0) { + /* a client connection has recently closed */ + control_persist_exit_time = time(NULL) + + (time_t)options.control_persist_timeout; + debug2("%s: schedule exit in %d seconds", __func__, + options.control_persist_timeout); + } + /* else we are already counting down to the timeout */ +} + #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" void client_x11_get_proto(const char *display, const char *xauth_path, - u_int trusted, char **_proto, char **_data) + u_int trusted, u_int timeout, char **_proto, char **_data) { char cmd[1024]; char line[512]; @@ -264,6 +296,7 @@ client_x11_get_proto(const char *display, const char *xauth_path, int got_data = 0, generated = 0, do_unlink = 0, i; char *xauthdir, *xauthfile; struct stat st; + u_int now; xauthdir = xauthfile = NULL; *_proto = proto; @@ -299,11 +332,18 @@ client_x11_get_proto(const char *display, const char *xauth_path, xauthdir); snprintf(cmd, sizeof(cmd), "%s -f %s generate %s " SSH_X11_PROTO - " untrusted timeout 1200 2>" _PATH_DEVNULL, - xauth_path, xauthfile, display); + " untrusted timeout %u 2>" _PATH_DEVNULL, + xauth_path, xauthfile, display, timeout); debug2("x11_get_proto: %s", cmd); if (system(cmd) == 0) generated = 1; + if (x11_refuse_time == 0) { + now = time(NULL) + 1; + if (UINT_MAX - timeout < now) + x11_refuse_time = UINT_MAX; + else + x11_refuse_time = now + timeout; + } } } @@ -524,6 +564,7 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, u_int *nallocp, int rekeying) { struct timeval tv, *tvp; + int timeout_secs; int ret; /* Add any selections by the channel mechanism. */ @@ -567,16 +608,27 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, /* * Wait for something to happen. This will suspend the process until * some selected descriptor can be read, written, or has some other - * event pending. + * event pending, or a timeout expires. */ - if (options.server_alive_interval == 0 || !compat20) + timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */ + if (options.server_alive_interval > 0 && compat20) + timeout_secs = options.server_alive_interval; + set_control_persist_exit_time(); + if (control_persist_exit_time > 0) { + timeout_secs = MIN(timeout_secs, + control_persist_exit_time - time(NULL)); + if (timeout_secs < 0) + timeout_secs = 0; + } + if (timeout_secs == INT_MAX) tvp = NULL; else { - tv.tv_sec = options.server_alive_interval; + tv.tv_sec = timeout_secs; tv.tv_usec = 0; tvp = &tv; } + ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); if (ret < 0) { char buf[100]; @@ -1469,6 +1521,18 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) */ if (FD_ISSET(connection_out, writeset)) packet_write_poll(); + + /* + * If we are a backgrounded control master, and the + * timeout has expired without any active client + * connections, then quit. + */ + if (control_persist_exit_time > 0) { + if (time(NULL) >= control_persist_exit_time) { + debug("ControlPersist timeout expired"); + break; + } + } } if (readset) xfree(readset); @@ -1686,6 +1750,11 @@ client_request_x11(const char *request_type, int rchan) "malicious server."); return NULL; } + if (x11_refuse_time != 0 && time(NULL) >= x11_refuse_time) { + verbose("Rejected X11 connection after ForwardX11Timeout " + "expired"); + return NULL; + } originator = packet_get_string(NULL); if (datafellows & SSH_BUG_X11FWD) { debug2("buggy server: x11 request w/o originator_port"); @@ -1912,7 +1981,7 @@ client_session2_setup(int id, int want_tty, int want_subsystem, memset(&ws, 0, sizeof(ws)); channel_request_start(id, "pty-req", 1); - client_expect_confirm(id, "PTY allocation", 0); + client_expect_confirm(id, "PTY allocation", 1); packet_put_cstring(term != NULL ? term : ""); packet_put_int((u_int)ws.ws_col); packet_put_int((u_int)ws.ws_row); diff --git a/crypto/openssh/clientloop.h b/crypto/openssh/clientloop.h index 0b8257b..52115db 100644 --- a/crypto/openssh/clientloop.h +++ b/crypto/openssh/clientloop.h @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.h,v 1.23 2010/01/26 01:28:35 djm Exp $ */ +/* $OpenBSD: clientloop.h,v 1.25 2010/06/25 23:15:36 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -39,7 +39,7 @@ /* Client side main loop for the interactive session. */ int client_loop(int, int, int); -void client_x11_get_proto(const char *, const char *, u_int, +void client_x11_get_proto(const char *, const char *, u_int, u_int, char **, char **); void client_global_request_reply_fwd(int, u_int32_t, void *); void client_session2_setup(int, int, int, const char *, struct termios *, @@ -63,6 +63,7 @@ void client_register_global_confirm(global_confirm_cb *, void *); #define SSHMUX_COMMAND_ALIVE_CHECK 2 /* Check master is alive */ #define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */ #define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */ +#define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */ void muxserver_listen(void); void muxclient(const char *); diff --git a/crypto/openssh/config.h b/crypto/openssh/config.h index 01fc523..c89920b 100644 --- a/crypto/openssh/config.h +++ b/crypto/openssh/config.h @@ -904,6 +904,9 @@ /* Define to 1 if you have the `strnvis' function. */ /* #undef HAVE_STRNVIS */ +/* Define to 1 if you have the `strptime' function. */ +#define HAVE_STRPTIME 1 + /* Define to 1 if you have the `strsep' function. */ #define HAVE_STRSEP 1 diff --git a/crypto/openssh/config.h.in b/crypto/openssh/config.h.in index a43ad57..4ff407f 100644 --- a/crypto/openssh/config.h.in +++ b/crypto/openssh/config.h.in @@ -900,6 +900,9 @@ /* Define to 1 if you have the `strnvis' function. */ #undef HAVE_STRNVIS +/* Define to 1 if you have the `strptime' function. */ +#undef HAVE_STRPTIME + /* Define to 1 if you have the `strsep' function. */ #undef HAVE_STRSEP diff --git a/crypto/openssh/jpake.c b/crypto/openssh/jpake.c index 1306610..cdf65f5 100644 --- a/crypto/openssh/jpake.c +++ b/crypto/openssh/jpake.c @@ -1,4 +1,4 @@ -/* $OpenBSD: jpake.c,v 1.2 2009/03/05 07:18:19 djm Exp $ */ +/* $OpenBSD: jpake.c,v 1.4 2010/07/13 23:13:16 djm Exp $ */ /* * Copyright (c) 2008 Damien Miller. All rights reserved. * @@ -434,7 +434,7 @@ jpake_check_confirm(const BIGNUM *k, if (peer_confirm_hash_len != expected_confirm_hash_len) error("%s: confirmation length mismatch (my %u them %u)", __func__, expected_confirm_hash_len, peer_confirm_hash_len); - else if (memcmp(peer_confirm_hash, expected_confirm_hash, + else if (timingsafe_bcmp(peer_confirm_hash, expected_confirm_hash, expected_confirm_hash_len) == 0) success = 1; bzero(expected_confirm_hash, expected_confirm_hash_len); diff --git a/crypto/openssh/key.c b/crypto/openssh/key.c index 66592c7..e4aa25c 100644 --- a/crypto/openssh/key.c +++ b/crypto/openssh/key.c @@ -1,4 +1,4 @@ -/* $OpenBSD: key.c,v 1.86 2010/03/15 19:40:02 stevesk Exp $ */ +/* $OpenBSD: key.c,v 1.90 2010/07/13 23:13:16 djm Exp $ */ /* * read_bignum(): * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -52,6 +52,7 @@ #include "uuencode.h" #include "buffer.h" #include "log.h" +#include "misc.h" #include "ssh2.h" static struct KeyCert * @@ -61,7 +62,8 @@ cert_new(void) cert = xcalloc(1, sizeof(*cert)); buffer_init(&cert->certblob); - buffer_init(&cert->constraints); + buffer_init(&cert->critical); + buffer_init(&cert->extensions); cert->key_id = NULL; cert->principals = NULL; cert->signature_key = NULL; @@ -82,6 +84,7 @@ key_new(int type) switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: if ((rsa = RSA_new()) == NULL) fatal("key_new: RSA_new failed"); @@ -92,6 +95,7 @@ key_new(int type) k->rsa = rsa; break; case KEY_DSA: + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: if ((dsa = DSA_new()) == NULL) fatal("key_new: DSA_new failed"); @@ -124,6 +128,7 @@ key_add_private(Key *k) switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: if ((k->rsa->d = BN_new()) == NULL) fatal("key_new_private: BN_new failed"); @@ -139,6 +144,7 @@ key_add_private(Key *k) fatal("key_new_private: BN_new failed"); break; case KEY_DSA: + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: if ((k->dsa->priv_key = BN_new()) == NULL) fatal("key_new_private: BN_new failed"); @@ -165,7 +171,8 @@ cert_free(struct KeyCert *cert) u_int i; buffer_free(&cert->certblob); - buffer_free(&cert->constraints); + buffer_free(&cert->critical); + buffer_free(&cert->extensions); if (cert->key_id != NULL) xfree(cert->key_id); for (i = 0; i < cert->nprincipals; i++) @@ -184,12 +191,14 @@ key_free(Key *k) switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: if (k->rsa != NULL) RSA_free(k->rsa); k->rsa = NULL; break; case KEY_DSA: + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: if (k->dsa != NULL) DSA_free(k->dsa); @@ -219,7 +228,7 @@ cert_compare(struct KeyCert *a, struct KeyCert *b) return 0; if (buffer_len(&a->certblob) != buffer_len(&b->certblob)) return 0; - if (memcmp(buffer_ptr(&a->certblob), buffer_ptr(&b->certblob), + if (timingsafe_bcmp(buffer_ptr(&a->certblob), buffer_ptr(&b->certblob), buffer_len(&a->certblob)) != 0) return 0; return 1; @@ -238,11 +247,13 @@ key_equal_public(const Key *a, const Key *b) switch (a->type) { case KEY_RSA1: + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: case KEY_RSA: return a->rsa != NULL && b->rsa != NULL && BN_cmp(a->rsa->e, b->rsa->e) == 0 && BN_cmp(a->rsa->n, b->rsa->n) == 0; + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: case KEY_DSA: return a->dsa != NULL && b->dsa != NULL && @@ -304,6 +315,8 @@ key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length) case KEY_RSA: key_to_blob(k, &blob, &len); break; + case KEY_DSA_CERT_V00: + case KEY_RSA_CERT_V00: case KEY_DSA_CERT: case KEY_RSA_CERT: /* We want a fingerprint of the _key_ not of the cert */ @@ -631,6 +644,8 @@ key_read(Key *ret, char **cpp) case KEY_UNSPEC: case KEY_RSA: case KEY_DSA: + case KEY_DSA_CERT_V00: + case KEY_RSA_CERT_V00: case KEY_DSA_CERT: case KEY_RSA_CERT: space = strchr(cp, ' '); @@ -757,11 +772,13 @@ key_write(const Key *key, FILE *f) error("key_write: failed for RSA key"); return 0; case KEY_DSA: + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: if (key->dsa == NULL) return 0; break; case KEY_RSA: + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: if (key->rsa == NULL) return 0; @@ -793,6 +810,10 @@ key_type(const Key *k) return "RSA"; case KEY_DSA: return "DSA"; + case KEY_RSA_CERT_V00: + return "RSA-CERT-V00"; + case KEY_DSA_CERT_V00: + return "DSA-CERT-V00"; case KEY_RSA_CERT: return "RSA-CERT"; case KEY_DSA_CERT: @@ -822,10 +843,14 @@ key_ssh_name(const Key *k) return "ssh-rsa"; case KEY_DSA: return "ssh-dss"; - case KEY_RSA_CERT: + case KEY_RSA_CERT_V00: return "ssh-rsa-cert-v00@openssh.com"; - case KEY_DSA_CERT: + case KEY_DSA_CERT_V00: return "ssh-dss-cert-v00@openssh.com"; + case KEY_RSA_CERT: + return "ssh-rsa-cert-v01@openssh.com"; + case KEY_DSA_CERT: + return "ssh-dss-cert-v01@openssh.com"; } return "ssh-unknown"; } @@ -836,9 +861,11 @@ key_size(const Key *k) switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: return BN_num_bits(k->rsa->n); case KEY_DSA: + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: return BN_num_bits(k->dsa->p); } @@ -882,6 +909,8 @@ key_generate(int type, u_int bits) case KEY_RSA1: k->rsa = rsa_generate_private_key(bits); break; + case KEY_RSA_CERT_V00: + case KEY_DSA_CERT_V00: case KEY_RSA_CERT: case KEY_DSA_CERT: fatal("key_generate: cert keys cannot be generated directly"); @@ -912,9 +941,12 @@ key_cert_copy(const Key *from_key, struct Key *to_key) buffer_append(&to->certblob, buffer_ptr(&from->certblob), buffer_len(&from->certblob)); - buffer_append(&to->constraints, buffer_ptr(&from->constraints), - buffer_len(&from->constraints)); + buffer_append(&to->critical, + buffer_ptr(&from->critical), buffer_len(&from->critical)); + buffer_append(&to->extensions, + buffer_ptr(&from->extensions), buffer_len(&from->extensions)); + to->serial = from->serial; to->type = from->type; to->key_id = from->key_id == NULL ? NULL : xstrdup(from->key_id); to->valid_after = from->valid_after; @@ -940,6 +972,7 @@ key_from_private(const Key *k) Key *n = NULL; switch (k->type) { case KEY_DSA: + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: n = key_new(k->type); if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) || @@ -950,6 +983,7 @@ key_from_private(const Key *k) break; case KEY_RSA: case KEY_RSA1: + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: n = key_new(k->type); if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) || @@ -979,8 +1013,12 @@ key_type_from_name(char *name) } else if (strcmp(name, "ssh-dss") == 0) { return KEY_DSA; } else if (strcmp(name, "ssh-rsa-cert-v00@openssh.com") == 0) { - return KEY_RSA_CERT; + return KEY_RSA_CERT_V00; } else if (strcmp(name, "ssh-dss-cert-v00@openssh.com") == 0) { + return KEY_DSA_CERT_V00; + } else if (strcmp(name, "ssh-rsa-cert-v01@openssh.com") == 0) { + return KEY_RSA_CERT; + } else if (strcmp(name, "ssh-dss-cert-v01@openssh.com") == 0) { return KEY_DSA_CERT; } debug2("key_type_from_name: unknown key type '%s'", name); @@ -1012,26 +1050,31 @@ key_names_valid2(const char *names) static int cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen) { - u_char *principals, *constraints, *sig_key, *sig; - u_int signed_len, plen, clen, sklen, slen, kidlen; + u_char *principals, *critical, *exts, *sig_key, *sig; + u_int signed_len, plen, clen, sklen, slen, kidlen, elen; Buffer tmp; char *principal; int ret = -1; + int v00 = key->type == KEY_DSA_CERT_V00 || + key->type == KEY_RSA_CERT_V00; buffer_init(&tmp); /* Copy the entire key blob for verification and later serialisation */ buffer_append(&key->cert->certblob, blob, blen); - principals = constraints = sig_key = sig = NULL; - if (buffer_get_int_ret(&key->cert->type, b) != 0 || + elen = 0; /* Not touched for v00 certs */ + principals = exts = critical = sig_key = sig = NULL; + if ((!v00 && buffer_get_int64_ret(&key->cert->serial, b) != 0) || + buffer_get_int_ret(&key->cert->type, b) != 0 || (key->cert->key_id = buffer_get_string_ret(b, &kidlen)) == NULL || (principals = buffer_get_string_ret(b, &plen)) == NULL || buffer_get_int64_ret(&key->cert->valid_after, b) != 0 || buffer_get_int64_ret(&key->cert->valid_before, b) != 0 || - (constraints = buffer_get_string_ret(b, &clen)) == NULL || - /* skip nonce */ buffer_get_string_ptr_ret(b, NULL) == NULL || - /* skip reserved */ buffer_get_string_ptr_ret(b, NULL) == NULL || + (critical = buffer_get_string_ret(b, &clen)) == NULL || + (!v00 && (exts = buffer_get_string_ret(b, &elen)) == NULL) || + (v00 && buffer_get_string_ptr_ret(b, NULL) == NULL) || /* nonce */ + buffer_get_string_ptr_ret(b, NULL) == NULL || /* reserved */ (sig_key = buffer_get_string_ret(b, &sklen)) == NULL) { error("%s: parse error", __func__); goto out; @@ -1078,13 +1121,25 @@ cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen) buffer_clear(&tmp); - buffer_append(&key->cert->constraints, constraints, clen); - buffer_append(&tmp, constraints, clen); + buffer_append(&key->cert->critical, critical, clen); + buffer_append(&tmp, critical, clen); /* validate structure */ while (buffer_len(&tmp) != 0) { if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL || buffer_get_string_ptr_ret(&tmp, NULL) == NULL) { - error("%s: Constraints data invalid", __func__); + error("%s: critical option data invalid", __func__); + goto out; + } + } + buffer_clear(&tmp); + + buffer_append(&key->cert->extensions, exts, elen); + buffer_append(&tmp, exts, elen); + /* validate structure */ + while (buffer_len(&tmp) != 0) { + if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL || + buffer_get_string_ptr_ret(&tmp, NULL) == NULL) { + error("%s: extension data invalid", __func__); goto out; } } @@ -1121,8 +1176,10 @@ cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen) buffer_free(&tmp); if (principals != NULL) xfree(principals); - if (constraints != NULL) - xfree(constraints); + if (critical != NULL) + xfree(critical); + if (exts != NULL) + xfree(exts); if (sig_key != NULL) xfree(sig_key); if (sig != NULL) @@ -1151,8 +1208,11 @@ key_from_blob(const u_char *blob, u_int blen) type = key_type_from_name(ktype); switch (type) { - case KEY_RSA: case KEY_RSA_CERT: + (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */ + /* FALLTHROUGH */ + case KEY_RSA: + case KEY_RSA_CERT_V00: key = key_new(type); if (buffer_get_bignum2_ret(&b, key->rsa->e) == -1 || buffer_get_bignum2_ret(&b, key->rsa->n) == -1) { @@ -1166,8 +1226,11 @@ key_from_blob(const u_char *blob, u_int blen) RSA_print_fp(stderr, key->rsa, 8); #endif break; - case KEY_DSA: case KEY_DSA_CERT: + (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */ + /* FALLTHROUGH */ + case KEY_DSA: + case KEY_DSA_CERT_V00: key = key_new(type); if (buffer_get_bignum2_ret(&b, key->dsa->p) == -1 || buffer_get_bignum2_ret(&b, key->dsa->q) == -1 || @@ -1213,6 +1276,8 @@ key_to_blob(const Key *key, u_char **blobp, u_int *lenp) } buffer_init(&b); switch (key->type) { + case KEY_DSA_CERT_V00: + case KEY_RSA_CERT_V00: case KEY_DSA_CERT: case KEY_RSA_CERT: /* Use the existing blob */ @@ -1255,9 +1320,11 @@ key_sign( const u_char *data, u_int datalen) { switch (key->type) { + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: case KEY_DSA: return ssh_dss_sign(key, sigp, lenp, data, datalen); + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: case KEY_RSA: return ssh_rsa_sign(key, sigp, lenp, data, datalen); @@ -1281,9 +1348,11 @@ key_verify( return -1; switch (key->type) { + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: case KEY_DSA: return ssh_dss_verify(key, signature, signaturelen, data, datalen); + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: case KEY_RSA: return ssh_rsa_verify(key, signature, signaturelen, data, datalen); @@ -1306,6 +1375,7 @@ key_demote(const Key *k) pk->rsa = NULL; switch (k->type) { + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: key_cert_copy(k, pk); /* FALLTHROUGH */ @@ -1318,6 +1388,7 @@ key_demote(const Key *k) if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL) fatal("key_demote: BN_dup failed"); break; + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: key_cert_copy(k, pk); /* FALLTHROUGH */ @@ -1344,8 +1415,17 @@ key_demote(const Key *k) int key_is_cert(const Key *k) { - return k != NULL && - (k->type == KEY_RSA_CERT || k->type == KEY_DSA_CERT); + if (k == NULL) + return 0; + switch (k->type) { + case KEY_RSA_CERT_V00: + case KEY_DSA_CERT_V00: + case KEY_RSA_CERT: + case KEY_DSA_CERT: + return 1; + default: + return 0; + } } /* Return the cert-less equivalent to a certified key type */ @@ -1353,8 +1433,10 @@ int key_type_plain(int type) { switch (type) { + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: return KEY_RSA; + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: return KEY_DSA; default: @@ -1364,16 +1446,16 @@ key_type_plain(int type) /* Convert a KEY_RSA or KEY_DSA to their _CERT equivalent */ int -key_to_certified(Key *k) +key_to_certified(Key *k, int legacy) { switch (k->type) { case KEY_RSA: k->cert = cert_new(); - k->type = KEY_RSA_CERT; + k->type = legacy ? KEY_RSA_CERT_V00 : KEY_RSA_CERT; return 0; case KEY_DSA: k->cert = cert_new(); - k->type = KEY_DSA_CERT; + k->type = legacy ? KEY_DSA_CERT_V00 : KEY_DSA_CERT; return 0; default: error("%s: key has incorrect type %s", __func__, key_type(k)); @@ -1386,10 +1468,12 @@ int key_drop_cert(Key *k) { switch (k->type) { + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: cert_free(k->cert); k->type = KEY_RSA; return 0; + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: cert_free(k->cert); k->type = KEY_DSA; @@ -1430,13 +1514,21 @@ key_certify(Key *k, Key *ca) buffer_clear(&k->cert->certblob); buffer_put_cstring(&k->cert->certblob, key_ssh_name(k)); + /* -v01 certs put nonce first */ + if (k->type == KEY_DSA_CERT || k->type == KEY_RSA_CERT) { + arc4random_buf(&nonce, sizeof(nonce)); + buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce)); + } + switch (k->type) { + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: buffer_put_bignum2(&k->cert->certblob, k->dsa->p); buffer_put_bignum2(&k->cert->certblob, k->dsa->q); buffer_put_bignum2(&k->cert->certblob, k->dsa->g); buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key); break; + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: buffer_put_bignum2(&k->cert->certblob, k->rsa->e); buffer_put_bignum2(&k->cert->certblob, k->rsa->n); @@ -1448,6 +1540,10 @@ key_certify(Key *k, Key *ca) return -1; } + /* -v01 certs have a serial number next */ + if (k->type == KEY_DSA_CERT || k->type == KEY_RSA_CERT) + buffer_put_int64(&k->cert->certblob, k->cert->serial); + buffer_put_int(&k->cert->certblob, k->cert->type); buffer_put_cstring(&k->cert->certblob, k->cert->key_id); @@ -1461,11 +1557,19 @@ key_certify(Key *k, Key *ca) buffer_put_int64(&k->cert->certblob, k->cert->valid_after); buffer_put_int64(&k->cert->certblob, k->cert->valid_before); buffer_put_string(&k->cert->certblob, - buffer_ptr(&k->cert->constraints), - buffer_len(&k->cert->constraints)); + buffer_ptr(&k->cert->critical), buffer_len(&k->cert->critical)); + + /* -v01 certs have non-critical options here */ + if (k->type == KEY_DSA_CERT || k->type == KEY_RSA_CERT) { + buffer_put_string(&k->cert->certblob, + buffer_ptr(&k->cert->extensions), + buffer_len(&k->cert->extensions)); + } + + /* -v00 certs put the nonce at the end */ + if (k->type == KEY_DSA_CERT_V00 || k->type == KEY_RSA_CERT_V00) + buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce)); - arc4random_buf(&nonce, sizeof(nonce)); - buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce)); buffer_put_string(&k->cert->certblob, NULL, 0); /* reserved */ buffer_put_string(&k->cert->certblob, ca_blob, ca_len); xfree(ca_blob); @@ -1520,7 +1624,7 @@ key_cert_check_authority(const Key *k, int want_host, int require_principal, *reason = "Certificate lacks principal list"; return -1; } - } else { + } else if (name != NULL) { principal_matches = 0; for (i = 0; i < k->cert->nprincipals; i++) { if (strcmp(name, k->cert->principals[i]) == 0) { @@ -1536,3 +1640,15 @@ key_cert_check_authority(const Key *k, int want_host, int require_principal, } return 0; } + +int +key_cert_is_legacy(Key *k) +{ + switch (k->type) { + case KEY_DSA_CERT_V00: + case KEY_RSA_CERT_V00: + return 1; + default: + return 0; + } +} diff --git a/crypto/openssh/key.h b/crypto/openssh/key.h index 4f17777..11d30ea 100644 --- a/crypto/openssh/key.h +++ b/crypto/openssh/key.h @@ -1,4 +1,4 @@ -/* $OpenBSD: key.h,v 1.29 2010/03/15 19:40:02 stevesk Exp $ */ +/* $OpenBSD: key.h,v 1.30 2010/04/16 01:47:26 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -37,6 +37,8 @@ enum types { KEY_DSA, KEY_RSA_CERT, KEY_DSA_CERT, + KEY_RSA_CERT_V00, + KEY_DSA_CERT_V00, KEY_UNSPEC }; enum fp_type { @@ -56,11 +58,13 @@ enum fp_rep { struct KeyCert { Buffer certblob; /* Kept around for use on wire */ u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */ + u_int64_t serial; char *key_id; u_int nprincipals; char **principals; u_int64_t valid_after, valid_before; - Buffer constraints; + Buffer critical; + Buffer extensions; Key *signature_key; }; @@ -92,12 +96,13 @@ Key *key_from_private(const Key *); int key_type_from_name(char *); int key_is_cert(const Key *); int key_type_plain(int); -int key_to_certified(Key *); +int key_to_certified(Key *, int); int key_drop_cert(Key *); int key_certify(Key *, Key *); void key_cert_copy(const Key *, struct Key *); int key_cert_check_authority(const Key *, int, int, const char *, const char **); +int key_cert_is_legacy(Key *); Key *key_from_blob(const u_char *, u_int); int key_to_blob(const Key *, u_char **, u_int *); diff --git a/crypto/openssh/loginrec.h b/crypto/openssh/loginrec.h index 859e1a6..84b4865 100644 --- a/crypto/openssh/loginrec.h +++ b/crypto/openssh/loginrec.h @@ -56,7 +56,7 @@ union login_netinfo { /* string lengths - set very long */ #define LINFO_PROGSIZE 64 #define LINFO_LINESIZE 64 -#define LINFO_NAMESIZE 128 +#define LINFO_NAMESIZE 512 #define LINFO_HOSTSIZE 256 struct logininfo { diff --git a/crypto/openssh/misc.c b/crypto/openssh/misc.c index e1f7231..a82e793 100644 --- a/crypto/openssh/misc.c +++ b/crypto/openssh/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.75 2010/01/09 23:04:13 dtucker Exp $ */ +/* $OpenBSD: misc.c,v 1.80 2010/07/21 02:10:58 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005,2006 Damien Miller. All rights reserved. @@ -178,6 +178,7 @@ strdelim(char **s) return (NULL); /* no matching quote */ } else { *s[0] = '\0'; + *s += strspn(*s + 1, WHITESPACE) + 1; return (old); } } @@ -425,7 +426,7 @@ colon(char *cp) int flag = 0; if (*cp == ':') /* Leading colon is part of file name. */ - return (0); + return NULL; if (*cp == '[') flag = 1; @@ -437,9 +438,9 @@ colon(char *cp) if (*cp == ':' && !flag) return (cp); if (*cp == '/') - return (0); + return NULL; } - return (0); + return NULL; } /* function to assist building execv() arguments */ @@ -849,6 +850,16 @@ ms_to_timeval(struct timeval *tv, int ms) tv->tv_usec = (ms % 1000) * 1000; } +int +timingsafe_bcmp(const void *b1, const void *b2, size_t n) +{ + const unsigned char *p1 = b1, *p2 = b2; + int ret = 0; + + for (; n > 0; n--) + ret |= *p1++ ^ *p2++; + return (ret != 0); +} void sock_set_v6only(int s) { diff --git a/crypto/openssh/misc.h b/crypto/openssh/misc.h index 32073ac..bb799f6 100644 --- a/crypto/openssh/misc.h +++ b/crypto/openssh/misc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.h,v 1.41 2010/01/09 23:04:13 dtucker Exp $ */ +/* $OpenBSD: misc.h,v 1.43 2010/07/13 23:13:16 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -36,6 +36,7 @@ void sanitise_stdfd(void); void ms_subtract_diff(struct timeval *, int *); void ms_to_timeval(struct timeval *, int); void sock_set_v6only(int); +int timingsafe_bcmp(const void *, const void *, size_t); struct passwd *pwcopy(struct passwd *); const char *ssh_gai_strerror(int); diff --git a/crypto/openssh/monitor.c b/crypto/openssh/monitor.c index 334aedd..9eb4e35 100644 --- a/crypto/openssh/monitor.c +++ b/crypto/openssh/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.106 2010/03/07 11:57:13 dtucker Exp $ */ +/* $OpenBSD: monitor.c,v 1.108 2010/07/13 23:13:16 djm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * Copyright 2002 Markus Friedl <markus@openbsd.org> @@ -518,7 +518,7 @@ monitor_allowed_key(u_char *blob, u_int bloblen) { /* make sure key is allowed */ if (key_blob == NULL || key_bloblen != bloblen || - memcmp(key_blob, blob, key_bloblen)) + timingsafe_bcmp(key_blob, blob, key_bloblen)) return (0); return (1); } @@ -922,8 +922,8 @@ mm_answer_pam_init_ctx(int sock, Buffer *m) int mm_answer_pam_query(int sock, Buffer *m) { - char *name, *info, **prompts; - u_int i, num, *echo_on; + char *name = NULL, *info = NULL, **prompts = NULL; + u_int i, num = 0, *echo_on = 0; int ret; debug3("%s", __func__); @@ -1103,14 +1103,14 @@ monitor_valid_userblob(u_char *data, u_int datalen) len = buffer_len(&b); if ((session_id2 == NULL) || (len < session_id2_len) || - (memcmp(p, session_id2, session_id2_len) != 0)) + (timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) fail++; buffer_consume(&b, session_id2_len); } else { p = buffer_get_string(&b, &len); if ((session_id2 == NULL) || (len != session_id2_len) || - (memcmp(p, session_id2, session_id2_len) != 0)) + (timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) fail++; xfree(p); } @@ -1158,7 +1158,7 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, p = buffer_get_string(&b, &len); if ((session_id2 == NULL) || (len != session_id2_len) || - (memcmp(p, session_id2, session_id2_len) != 0)) + (timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) fail++; xfree(p); @@ -1682,9 +1682,9 @@ mm_get_kex(Buffer *m) kex = xcalloc(1, sizeof(*kex)); kex->session_id = buffer_get_string(m, &kex->session_id_len); - if ((session_id2 == NULL) || - (kex->session_id_len != session_id2_len) || - (memcmp(kex->session_id, session_id2, session_id2_len) != 0)) + if (session_id2 == NULL || + kex->session_id_len != session_id2_len || + timingsafe_bcmp(kex->session_id, session_id2, session_id2_len) != 0) fatal("mm_get_get: internal error: bad session id"); kex->we_need = buffer_get_int(m); kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; diff --git a/crypto/openssh/mux.c b/crypto/openssh/mux.c index 825fb7a..5c3857e 100644 --- a/crypto/openssh/mux.c +++ b/crypto/openssh/mux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mux.c,v 1.14 2010/01/30 02:54:53 djm Exp $ */ +/* $OpenBSD: mux.c,v 1.21 2010/06/25 23:15:36 djm Exp $ */ /* * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> * @@ -71,6 +71,7 @@ #include "xmalloc.h" #include "log.h" #include "ssh.h" +#include "ssh2.h" #include "pathnames.h" #include "misc.h" #include "match.h" @@ -106,6 +107,14 @@ struct mux_session_confirm_ctx { char *term; struct termios tio; char **env; + u_int rid; +}; + +/* Context for global channel callback */ +struct mux_channel_confirm_ctx { + u_int cid; /* channel id */ + u_int rid; /* request id */ + int fid; /* forward id */ }; /* fd to control socket */ @@ -143,13 +152,14 @@ struct mux_master_state { #define MUX_S_EXIT_MESSAGE 0x80000004 #define MUX_S_ALIVE 0x80000005 #define MUX_S_SESSION_OPENED 0x80000006 +#define MUX_S_REMOTE_PORT 0x80000007 /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ #define MUX_FWD_LOCAL 1 #define MUX_FWD_REMOTE 2 #define MUX_FWD_DYNAMIC 3 -static void mux_session_confirm(int, void *); +static void mux_session_confirm(int, int, void *); static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); @@ -206,7 +216,7 @@ mux_master_control_cleanup_cb(int cid, void *unused) fatal("%s: channel_by_id(%i) == NULL", __func__, cid); if (c->remote_id != -1) { if ((sc = channel_by_id(c->remote_id)) == NULL) - debug2("%s: channel %d n session channel %d", + fatal("%s: channel %d missing session channel %d", __func__, c->self, c->remote_id); c->remote_id = -1; sc->ctl_chan = -1; @@ -301,6 +311,7 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) /* Reply for SSHMUX_COMMAND_OPEN */ cctx = xcalloc(1, sizeof(*cctx)); cctx->term = NULL; + cctx->rid = rid; cmd = reserved = NULL; if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || buffer_get_int_ret(&cctx->want_tty, m) != 0 || @@ -454,14 +465,10 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) channel_send_open(nc->self); channel_register_open_confirm(nc->self, mux_session_confirm, cctx); - channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 0); - - /* prepare reply */ - /* XXX defer until mux_session_confirm() fires */ - buffer_put_int(r, MUX_S_SESSION_OPENED); - buffer_put_int(r, rid); - buffer_put_int(r, nc->self); + c->mux_pause = 1; /* stop handling messages until open_confirm done */ + channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); + /* reply is deferred, sent by mux_session_confirm */ return 0; } @@ -559,6 +566,61 @@ compare_forward(Forward *a, Forward *b) return 1; } +static void +mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) +{ + struct mux_channel_confirm_ctx *fctx = ctxt; + char *failmsg = NULL; + Forward *rfwd; + Channel *c; + Buffer out; + + if ((c = channel_by_id(fctx->cid)) == NULL) { + /* no channel for reply */ + error("%s: unknown channel", __func__); + return; + } + buffer_init(&out); + if (fctx->fid >= options.num_remote_forwards) { + xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid); + goto fail; + } + rfwd = &options.remote_forwards[fctx->fid]; + debug("%s: %s for: listen %d, connect %s:%d", __func__, + type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", + rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); + if (type == SSH2_MSG_REQUEST_SUCCESS) { + if (rfwd->listen_port == 0) { + rfwd->allocated_port = packet_get_int(); + logit("Allocated port %u for mux remote forward" + " to %s:%d", rfwd->allocated_port, + rfwd->connect_host, rfwd->connect_port); + buffer_put_int(&out, MUX_S_REMOTE_PORT); + buffer_put_int(&out, fctx->rid); + buffer_put_int(&out, rfwd->allocated_port); + } else { + buffer_put_int(&out, MUX_S_OK); + buffer_put_int(&out, fctx->rid); + } + goto out; + } else { + xasprintf(&failmsg, "remote port forwarding failed for " + "listen port %d", rfwd->listen_port); + } + fail: + error("%s: %s", __func__, failmsg); + buffer_put_int(&out, MUX_S_FAILURE); + buffer_put_int(&out, fctx->rid); + buffer_put_cstring(&out, failmsg); + xfree(failmsg); + out: + buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out)); + buffer_free(&out); + if (c->mux_pause <= 0) + fatal("%s: mux_pause %d", __func__, c->mux_pause); + c->mux_pause = 0; /* start processing messages again */ +} + static int process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) { @@ -594,15 +656,16 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) ftype != MUX_FWD_DYNAMIC) { logit("%s: invalid forwarding type %u", __func__, ftype); invalid: - xfree(fwd.listen_host); - xfree(fwd.connect_host); + if (fwd.listen_host) + xfree(fwd.listen_host); + if (fwd.connect_host) + xfree(fwd.connect_host); buffer_put_int(r, MUX_S_FAILURE); buffer_put_int(r, rid); buffer_put_cstring(r, "Invalid forwarding request"); return 0; } - /* XXX support rport0 forwarding with reply of port assigned */ - if (fwd.listen_port == 0 || fwd.listen_port >= 65536) { + if (fwd.listen_port >= 65536) { logit("%s: invalid listen port %u", __func__, fwd.listen_port); goto invalid; @@ -637,8 +700,17 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) case MUX_FWD_REMOTE: for (i = 0; i < options.num_remote_forwards; i++) { if (compare_forward(&fwd, - options.remote_forwards + i)) - goto exists; + options.remote_forwards + i)) { + if (fwd.listen_port != 0) + goto exists; + debug2("%s: found allocated port", + __func__); + buffer_put_int(r, MUX_S_REMOTE_PORT); + buffer_put_int(r, rid); + buffer_put_int(r, + options.remote_forwards[i].allocated_port); + goto out; + } } break; } @@ -655,9 +727,7 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) } if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { - if (options.num_local_forwards + 1 >= - SSH_MAX_FORWARDS_PER_DIRECTION || - channel_setup_local_fwd_listener(fwd.listen_host, + if (channel_setup_local_fwd_listener(fwd.listen_host, fwd.listen_port, fwd.connect_host, fwd.connect_port, options.gateway_ports) < 0) { fail: @@ -670,14 +740,22 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) add_local_forward(&options, &fwd); freefwd = 0; } else { - /* XXX wait for remote to confirm */ - if (options.num_remote_forwards + 1 >= - SSH_MAX_FORWARDS_PER_DIRECTION || - channel_request_remote_forwarding(fwd.listen_host, + struct mux_channel_confirm_ctx *fctx; + + if (channel_request_remote_forwarding(fwd.listen_host, fwd.listen_port, fwd.connect_host, fwd.connect_port) < 0) goto fail; add_remote_forward(&options, &fwd); + fctx = xcalloc(1, sizeof(*fctx)); + fctx->cid = c->self; + fctx->rid = rid; + fctx->fid = options.num_remote_forwards - 1; + client_register_global_confirm(mux_confirm_remote_forward, + fctx); freefwd = 0; + c->mux_pause = 1; /* wait for mux_confirm_remote_forward */ + /* delayed reply in mux_confirm_remote_forward */ + goto out; } buffer_put_int(r, MUX_S_OK); buffer_put_int(r, rid); @@ -826,7 +904,7 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) debug2("%s: channel_new: %d linked to control channel %d", __func__, nc->self, nc->ctl_chan); - channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 0); + channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); /* prepare reply */ /* XXX defer until channel confirmed */ @@ -849,7 +927,7 @@ mux_master_read_cb(Channel *c) /* Setup ctx and */ if (c->mux_ctx == NULL) { - state = xcalloc(1, sizeof(state)); + state = xcalloc(1, sizeof(*state)); c->mux_ctx = state; channel_register_cleanup(c->self, mux_master_control_cleanup_cb, 0); @@ -1000,26 +1078,43 @@ muxserver_listen(void) /* Callback on open confirmation in mux master for a mux client session. */ static void -mux_session_confirm(int id, void *arg) +mux_session_confirm(int id, int success, void *arg) { struct mux_session_confirm_ctx *cctx = arg; const char *display; - Channel *c; + Channel *c, *cc; int i; + Buffer reply; if (cctx == NULL) fatal("%s: cctx == NULL", __func__); if ((c = channel_by_id(id)) == NULL) fatal("%s: no channel for id %d", __func__, id); + if ((cc = channel_by_id(c->ctl_chan)) == NULL) + fatal("%s: channel %d lacks control channel %d", __func__, + id, c->ctl_chan); + + if (!success) { + debug3("%s: sending failure reply", __func__); + /* prepare reply */ + buffer_init(&reply); + buffer_put_int(&reply, MUX_S_FAILURE); + buffer_put_int(&reply, cctx->rid); + buffer_put_cstring(&reply, "Session open refused by peer"); + goto done; + } display = getenv("DISPLAY"); if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { char *proto, *data; + /* Get reasonable local authentication information. */ client_x11_get_proto(display, options.xauth_location, - options.forward_x11_trusted, &proto, &data); + options.forward_x11_trusted, options.forward_x11_timeout, + &proto, &data); /* Request forwarding with authentication spoofing. */ - debug("Requesting X11 forwarding with authentication spoofing."); + debug("Requesting X11 forwarding with authentication " + "spoofing."); x11_request_forwarding_with_spoofing(id, display, proto, data); /* XXX wait for reply */ } @@ -1033,6 +1128,21 @@ mux_session_confirm(int id, void *arg) client_session2_setup(id, cctx->want_tty, cctx->want_subsys, cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); + debug3("%s: sending success reply", __func__); + /* prepare reply */ + buffer_init(&reply); + buffer_put_int(&reply, MUX_S_SESSION_OPENED); + buffer_put_int(&reply, cctx->rid); + buffer_put_int(&reply, c->self); + + done: + /* Send reply */ + buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); + buffer_free(&reply); + + if (cc->mux_pause <= 0) + fatal("%s: mux_pause %d", __func__, cc->mux_pause); + cc->mux_pause = 0; /* start processing messages again */ c->open_confirm_ctx = NULL; buffer_free(&cctx->cmd); xfree(cctx->term); @@ -1365,6 +1475,15 @@ mux_client_request_forward(int fd, u_int ftype, Forward *fwd) switch (type) { case MUX_S_OK: break; + case MUX_S_REMOTE_PORT: + fwd->allocated_port = buffer_get_int(&m); + logit("Allocated port %u for remote forward to %s:%d", + fwd->allocated_port, + fwd->connect_host ? fwd->connect_host : "", + fwd->connect_port); + if (muxclient_command == SSHMUX_COMMAND_FORWARD) + fprintf(stdout, "%u\n", fwd->allocated_port); + break; case MUX_S_PERMISSION_DENIED: e = buffer_get_string(&m, NULL); buffer_free(&m); @@ -1731,6 +1850,10 @@ muxclient(const char *path) mux_client_request_terminate(sock); fprintf(stderr, "Exit request sent.\r\n"); exit(0); + case SSHMUX_COMMAND_FORWARD: + if (mux_client_request_forwards(sock) != 0) + fatal("%s: master forward request failed", __func__); + exit(0); case SSHMUX_COMMAND_OPEN: if (mux_client_request_forwards(sock) != 0) { error("%s: master forward request failed", __func__); diff --git a/crypto/openssh/myproposal.h b/crypto/openssh/myproposal.h index 98f27fd..7bedfab 100644 --- a/crypto/openssh/myproposal.h +++ b/crypto/openssh/myproposal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: myproposal.h,v 1.24 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: myproposal.h,v 1.25 2010/04/16 01:47:26 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -40,9 +40,12 @@ "diffie-hellman-group1-sha1" #endif -#define KEX_DEFAULT_PK_ALG "ssh-rsa-cert-v00@openssh.com," \ - "ssh-dss-cert-v00@openssh.com," \ - "ssh-rsa,ssh-dss" +#define KEX_DEFAULT_PK_ALG \ + "ssh-rsa-cert-v01@openssh.com," \ + "ssh-dss-cert-v01@openssh.com," \ + "ssh-rsa-cert-v00@openssh.com," \ + "ssh-dss-cert-v00@openssh.com," \ + "ssh-rsa,ssh-dss" #define KEX_DEFAULT_ENCRYPT \ "aes128-ctr,aes192-ctr,aes256-ctr," \ diff --git a/crypto/openssh/openbsd-compat/openbsd-compat.h b/crypto/openssh/openbsd-compat/openbsd-compat.h index cad2408..e15d2bd 100644 --- a/crypto/openssh/openbsd-compat/openbsd-compat.h +++ b/crypto/openssh/openbsd-compat/openbsd-compat.h @@ -1,4 +1,4 @@ -/* $Id: openbsd-compat.h,v 1.49 2010/01/16 12:58:37 dtucker Exp $ */ +/* $Id: openbsd-compat.h,v 1.50 2010/08/16 03:15:23 dtucker Exp $ */ /* * Copyright (c) 1999-2003 Damien Miller. All rights reserved. @@ -87,6 +87,11 @@ int setenv(register const char *name, register const char *value, int rewrite); void strmode(int mode, char *p); #endif +#ifndef HAVE_STRPTIME +#include <time.h> +char *strptime(const char *buf, const char *fmt, struct tm *tm); +#endif + #if !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP) int mkstemps(char *path, int slen); int mkstemp(char *path); diff --git a/crypto/openssh/openbsd-compat/openssl-compat.h b/crypto/openssh/openbsd-compat/openssl-compat.h index fcc7628..b7caa65 100644 --- a/crypto/openssh/openbsd-compat/openssl-compat.h +++ b/crypto/openssh/openbsd-compat/openssl-compat.h @@ -1,4 +1,4 @@ -/* $Id: openssl-compat.h,v 1.14 2009/03/07 11:22:35 dtucker Exp $ */ +/* $Id: openssl-compat.h,v 1.15 2010/05/12 07:50:02 djm Exp $ */ /* * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au> @@ -18,6 +18,16 @@ #include "includes.h" #include <openssl/evp.h> +#include <openssl/rsa.h> +#include <openssl/dsa.h> + +/* Only in 0.9.8 */ +#ifndef OPENSSL_DSA_MAX_MODULUS_BITS +# define OPENSSL_DSA_MAX_MODULUS_BITS 10000 +#endif +#ifndef OPENSSL_RSA_MAX_MODULUS_BITS +# define OPENSSL_RSA_MAX_MODULUS_BITS 16384 +#endif /* OPENSSL_free() is Free() in versions before OpenSSL 0.9.6 */ #if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090600f) @@ -97,3 +107,4 @@ int ssh_EVP_Cipher(EVP_CIPHER_CTX *, char *, char *, int); int ssh_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *); void ssh_SSLeay_add_all_algorithms(void); #endif /* SSH_DONT_OVERLOAD_OPENSSL_FUNCS */ + diff --git a/crypto/openssh/openbsd-compat/port-tun.c b/crypto/openssh/openbsd-compat/port-tun.c index ddc92d0..0d756f7 100644 --- a/crypto/openssh/openbsd-compat/port-tun.c +++ b/crypto/openssh/openbsd-compat/port-tun.c @@ -173,9 +173,11 @@ sys_tun_open(int tun, int mode) if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) goto failed; - ifr.ifr_flags |= IFF_UP; - if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) - goto failed; + if ((ifr.ifr_flags & IFF_UP) == 0) { + ifr.ifr_flags |= IFF_UP; + if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) + goto failed; + } close(sock); return (fd); diff --git a/crypto/openssh/openbsd-compat/port-uw.c b/crypto/openssh/openbsd-compat/port-uw.c index be9905a..b1fbfa2 100644 --- a/crypto/openssh/openbsd-compat/port-uw.c +++ b/crypto/openssh/openbsd-compat/port-uw.c @@ -39,10 +39,10 @@ #include "xmalloc.h" #include "packet.h" #include "buffer.h" +#include "key.h" #include "auth-options.h" #include "log.h" #include "servconf.h" -#include "key.h" #include "hostfile.h" #include "auth.h" #include "ssh.h" diff --git a/crypto/openssh/openbsd-compat/strptime.c b/crypto/openssh/openbsd-compat/strptime.c new file mode 100644 index 0000000..d8d83d9 --- /dev/null +++ b/crypto/openssh/openbsd-compat/strptime.c @@ -0,0 +1,401 @@ +/* $OpenBSD: strptime.c,v 1.12 2008/06/26 05:42:05 ray Exp $ */ +/* $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */ + +/*- + * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code was contributed to The NetBSD Foundation by Klaus Klein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* OPENBSD ORIGINAL: lib/libc/time/strptime.c */ + +#include "includes.h" + +#ifndef HAVE_STRPTIME + +#define TM_YEAR_BASE 1900 /* from tzfile.h */ + +#include <ctype.h> +#include <locale.h> +#include <string.h> +#include <time.h> + +/* #define _ctloc(x) (_CurrentTimeLocale->x) */ + +/* + * We do not implement alternate representations. However, we always + * check whether a given modifier is allowed for a certain conversion. + */ +#define _ALT_E 0x01 +#define _ALT_O 0x02 +#define _LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); } + + +static int _conv_num(const unsigned char **, int *, int, int); +static char *_strptime(const char *, const char *, struct tm *, int); + + +char * +strptime(const char *buf, const char *fmt, struct tm *tm) +{ + return(_strptime(buf, fmt, tm, 1)); +} + +static char * +_strptime(const char *buf, const char *fmt, struct tm *tm, int initialize) +{ + unsigned char c; + const unsigned char *bp; + size_t len; + int alt_format, i; + static int century, relyear; + + if (initialize) { + century = TM_YEAR_BASE; + relyear = -1; + } + + bp = (unsigned char *)buf; + while ((c = *fmt) != '\0') { + /* Clear `alternate' modifier prior to new conversion. */ + alt_format = 0; + + /* Eat up white-space. */ + if (isspace(c)) { + while (isspace(*bp)) + bp++; + + fmt++; + continue; + } + + if ((c = *fmt++) != '%') + goto literal; + + +again: switch (c = *fmt++) { + case '%': /* "%%" is converted to "%". */ +literal: + if (c != *bp++) + return (NULL); + + break; + + /* + * "Alternative" modifiers. Just set the appropriate flag + * and start over again. + */ + case 'E': /* "%E?" alternative conversion modifier. */ + _LEGAL_ALT(0); + alt_format |= _ALT_E; + goto again; + + case 'O': /* "%O?" alternative conversion modifier. */ + _LEGAL_ALT(0); + alt_format |= _ALT_O; + goto again; + + /* + * "Complex" conversion rules, implemented through recursion. + */ +#if 0 + case 'c': /* Date and time, using the locale's format. */ + _LEGAL_ALT(_ALT_E); + if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, 0))) + return (NULL); + break; +#endif + case 'D': /* The date as "%m/%d/%y". */ + _LEGAL_ALT(0); + if (!(bp = _strptime(bp, "%m/%d/%y", tm, 0))) + return (NULL); + break; + + case 'R': /* The time as "%H:%M". */ + _LEGAL_ALT(0); + if (!(bp = _strptime(bp, "%H:%M", tm, 0))) + return (NULL); + break; + + case 'r': /* The time as "%I:%M:%S %p". */ + _LEGAL_ALT(0); + if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, 0))) + return (NULL); + break; + + case 'T': /* The time as "%H:%M:%S". */ + _LEGAL_ALT(0); + if (!(bp = _strptime(bp, "%H:%M:%S", tm, 0))) + return (NULL); + break; +#if 0 + case 'X': /* The time, using the locale's format. */ + _LEGAL_ALT(_ALT_E); + if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, 0))) + return (NULL); + break; + + case 'x': /* The date, using the locale's format. */ + _LEGAL_ALT(_ALT_E); + if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, 0))) + return (NULL); + break; +#endif + /* + * "Elementary" conversion rules. + */ +#if 0 + case 'A': /* The day of week, using the locale's form. */ + case 'a': + _LEGAL_ALT(0); + for (i = 0; i < 7; i++) { + /* Full name. */ + len = strlen(_ctloc(day[i])); + if (strncasecmp(_ctloc(day[i]), bp, len) == 0) + break; + + /* Abbreviated name. */ + len = strlen(_ctloc(abday[i])); + if (strncasecmp(_ctloc(abday[i]), bp, len) == 0) + break; + } + + /* Nothing matched. */ + if (i == 7) + return (NULL); + + tm->tm_wday = i; + bp += len; + break; + + case 'B': /* The month, using the locale's form. */ + case 'b': + case 'h': + _LEGAL_ALT(0); + for (i = 0; i < 12; i++) { + /* Full name. */ + len = strlen(_ctloc(mon[i])); + if (strncasecmp(_ctloc(mon[i]), bp, len) == 0) + break; + + /* Abbreviated name. */ + len = strlen(_ctloc(abmon[i])); + if (strncasecmp(_ctloc(abmon[i]), bp, len) == 0) + break; + } + + /* Nothing matched. */ + if (i == 12) + return (NULL); + + tm->tm_mon = i; + bp += len; + break; +#endif + + case 'C': /* The century number. */ + _LEGAL_ALT(_ALT_E); + if (!(_conv_num(&bp, &i, 0, 99))) + return (NULL); + + century = i * 100; + break; + + case 'd': /* The day of month. */ + case 'e': + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_mday, 1, 31))) + return (NULL); + break; + + case 'k': /* The hour (24-hour clock representation). */ + _LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'H': + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_hour, 0, 23))) + return (NULL); + break; + + case 'l': /* The hour (12-hour clock representation). */ + _LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'I': + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_hour, 1, 12))) + return (NULL); + break; + + case 'j': /* The day of year. */ + _LEGAL_ALT(0); + if (!(_conv_num(&bp, &tm->tm_yday, 1, 366))) + return (NULL); + tm->tm_yday--; + break; + + case 'M': /* The minute. */ + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_min, 0, 59))) + return (NULL); + break; + + case 'm': /* The month. */ + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_mon, 1, 12))) + return (NULL); + tm->tm_mon--; + break; + +#if 0 + case 'p': /* The locale's equivalent of AM/PM. */ + _LEGAL_ALT(0); + /* AM? */ + len = strlen(_ctloc(am_pm[0])); + if (strncasecmp(_ctloc(am_pm[0]), bp, len) == 0) { + if (tm->tm_hour > 12) /* i.e., 13:00 AM ?! */ + return (NULL); + else if (tm->tm_hour == 12) + tm->tm_hour = 0; + + bp += len; + break; + } + /* PM? */ + len = strlen(_ctloc(am_pm[1])); + if (strncasecmp(_ctloc(am_pm[1]), bp, len) == 0) { + if (tm->tm_hour > 12) /* i.e., 13:00 PM ?! */ + return (NULL); + else if (tm->tm_hour < 12) + tm->tm_hour += 12; + + bp += len; + break; + } + + /* Nothing matched. */ + return (NULL); +#endif + case 'S': /* The seconds. */ + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_sec, 0, 61))) + return (NULL); + break; + + case 'U': /* The week of year, beginning on sunday. */ + case 'W': /* The week of year, beginning on monday. */ + _LEGAL_ALT(_ALT_O); + /* + * XXX This is bogus, as we can not assume any valid + * information present in the tm structure at this + * point to calculate a real value, so just check the + * range for now. + */ + if (!(_conv_num(&bp, &i, 0, 53))) + return (NULL); + break; + + case 'w': /* The day of week, beginning on sunday. */ + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &tm->tm_wday, 0, 6))) + return (NULL); + break; + + case 'Y': /* The year. */ + _LEGAL_ALT(_ALT_E); + if (!(_conv_num(&bp, &i, 0, 9999))) + return (NULL); + + relyear = -1; + tm->tm_year = i - TM_YEAR_BASE; + break; + + case 'y': /* The year within the century (2 digits). */ + _LEGAL_ALT(_ALT_E | _ALT_O); + if (!(_conv_num(&bp, &relyear, 0, 99))) + return (NULL); + break; + + /* + * Miscellaneous conversions. + */ + case 'n': /* Any kind of white-space. */ + case 't': + _LEGAL_ALT(0); + while (isspace(*bp)) + bp++; + break; + + + default: /* Unknown/unsupported conversion. */ + return (NULL); + } + + + } + + /* + * We need to evaluate the two digit year spec (%y) + * last as we can get a century spec (%C) at any time. + */ + if (relyear != -1) { + if (century == TM_YEAR_BASE) { + if (relyear <= 68) + tm->tm_year = relyear + 2000 - TM_YEAR_BASE; + else + tm->tm_year = relyear + 1900 - TM_YEAR_BASE; + } else { + tm->tm_year = relyear + century - TM_YEAR_BASE; + } + } + + return ((char *)bp); +} + + +static int +_conv_num(const unsigned char **buf, int *dest, int llim, int ulim) +{ + int result = 0; + int rulim = ulim; + + if (**buf < '0' || **buf > '9') + return (0); + + /* we use rulim to break out of the loop when we run out of digits */ + do { + result *= 10; + result += *(*buf)++ - '0'; + rulim /= 10; + } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9'); + + if (result < llim || result > ulim) + return (0); + + *dest = result; + return (1); +} + +#endif /* HAVE_STRPTIME */ + diff --git a/crypto/openssh/packet.c b/crypto/openssh/packet.c index 994e35b..48f7fe6 100644 --- a/crypto/openssh/packet.c +++ b/crypto/openssh/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.166 2009/06/27 09:29:06 andreas Exp $ */ +/* $OpenBSD: packet.c,v 1.168 2010/07/13 23:13:16 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -1307,7 +1307,7 @@ packet_read_poll2(u_int32_t *seqnr_p) macbuf = mac_compute(mac, active_state->p_read.seqnr, buffer_ptr(&active_state->incoming_packet), buffer_len(&active_state->incoming_packet)); - if (memcmp(macbuf, buffer_ptr(&active_state->input), + if (timingsafe_bcmp(macbuf, buffer_ptr(&active_state->input), mac->mac_len) != 0) { logit("Corrupted MAC on input."); if (need > PACKET_MAX_SIZE) diff --git a/crypto/openssh/readconf.c b/crypto/openssh/readconf.c index 6c4bb34..9d6091f 100644 --- a/crypto/openssh/readconf.c +++ b/crypto/openssh/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.183 2010/02/08 10:50:20 markus Exp $ */ +/* $OpenBSD: readconf.c,v 1.187 2010/07/19 09:15:12 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -113,8 +113,8 @@ __RCSID("$FreeBSD$"); typedef enum { oBadOption, - oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts, - oExitOnForwardFailure, + oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, + oGatewayPorts, oExitOnForwardFailure, oPasswordAuthentication, oRSAAuthentication, oChallengeResponseAuthentication, oXAuthLocation, oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, @@ -131,7 +131,8 @@ typedef enum { oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, - oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, + oSendEnv, oControlPath, oControlMaster, oControlPersist, + oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, oVersionAddendum, @@ -147,6 +148,7 @@ static struct { { "forwardagent", oForwardAgent }, { "forwardx11", oForwardX11 }, { "forwardx11trusted", oForwardX11Trusted }, + { "forwardx11timeout", oForwardX11Timeout }, { "exitonforwardfailure", oExitOnForwardFailure }, { "xauthlocation", oXAuthLocation }, { "gatewayports", oGatewayPorts }, @@ -228,6 +230,7 @@ static struct { { "sendenv", oSendEnv }, { "controlpath", oControlPath }, { "controlmaster", oControlMaster }, + { "controlpersist", oControlPersist }, { "hashknownhosts", oHashKnownHosts }, { "tunnel", oTunnel }, { "tunneldevice", oTunnelDevice }, @@ -272,8 +275,9 @@ add_local_forward(Options *options, const Forward *newfwd) if (newfwd->listen_port < ipport_reserved && original_real_uid != 0) fatal("Privileged ports can only be forwarded by root."); #endif - if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION) - fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION); + options->local_forwards = xrealloc(options->local_forwards, + options->num_local_forwards + 1, + sizeof(*options->local_forwards)); fwd = &options->local_forwards[options->num_local_forwards++]; fwd->listen_host = newfwd->listen_host; @@ -291,15 +295,17 @@ void add_remote_forward(Options *options, const Forward *newfwd) { Forward *fwd; - if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION) - fatal("Too many remote forwards (max %d).", - SSH_MAX_FORWARDS_PER_DIRECTION); + + options->remote_forwards = xrealloc(options->remote_forwards, + options->num_remote_forwards + 1, + sizeof(*options->remote_forwards)); fwd = &options->remote_forwards[options->num_remote_forwards++]; fwd->listen_host = newfwd->listen_host; fwd->listen_port = newfwd->listen_port; fwd->connect_host = newfwd->connect_host; fwd->connect_port = newfwd->connect_port; + fwd->allocated_port = 0; } static void @@ -312,12 +318,20 @@ clear_forwardings(Options *options) xfree(options->local_forwards[i].listen_host); xfree(options->local_forwards[i].connect_host); } + if (options->num_local_forwards > 0) { + xfree(options->local_forwards); + options->local_forwards = NULL; + } options->num_local_forwards = 0; for (i = 0; i < options->num_remote_forwards; i++) { if (options->remote_forwards[i].listen_host != NULL) xfree(options->remote_forwards[i].listen_host); xfree(options->remote_forwards[i].connect_host); } + if (options->num_remote_forwards > 0) { + xfree(options->remote_forwards); + options->remote_forwards = NULL; + } options->num_remote_forwards = 0; options->tun_open = SSH_TUNMODE_NO; } @@ -420,6 +434,10 @@ parse_flag: case oForwardX11Trusted: intptr = &options->forward_x11_trusted; goto parse_flag; + + case oForwardX11Timeout: + intptr = &options->forward_x11_timeout; + goto parse_time; case oGatewayPorts: intptr = &options->gateway_ports; @@ -883,6 +901,30 @@ parse_int: *intptr = value; break; + case oControlPersist: + /* no/false/yes/true, or a time spec */ + intptr = &options->control_persist; + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing ControlPersist" + " argument.", filename, linenum); + value = 0; + value2 = 0; /* timeout */ + if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) + value = 0; + else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) + value = 1; + else if ((value2 = convtime(arg)) >= 0) + value = 1; + else + fatal("%.200s line %d: Bad ControlPersist argument.", + filename, linenum); + if (*activep && *intptr == -1) { + *intptr = value; + options->control_persist_timeout = value2; + } + break; + case oHashKnownHosts: intptr = &options->hash_known_hosts; goto parse_flag; @@ -1031,6 +1073,7 @@ initialize_options(Options * options) options->forward_agent = -1; options->forward_x11 = -1; options->forward_x11_trusted = -1; + options->forward_x11_timeout = -1; options->exit_on_forward_failure = -1; options->xauth_location = NULL; options->gateway_ports = -1; @@ -1071,7 +1114,9 @@ initialize_options(Options * options) options->user_hostfile = NULL; options->system_hostfile2 = NULL; options->user_hostfile2 = NULL; + options->local_forwards = NULL; options->num_local_forwards = 0; + options->remote_forwards = NULL; options->num_remote_forwards = 0; options->clear_forwardings = -1; options->log_level = SYSLOG_LEVEL_NOT_SET; @@ -1088,6 +1133,8 @@ initialize_options(Options * options) options->num_send_env = 0; options->control_path = NULL; options->control_master = -1; + options->control_persist = -1; + options->control_persist_timeout = 0; options->hash_known_hosts = -1; options->tun_open = -1; options->tun_local = -1; @@ -1115,6 +1162,8 @@ fill_default_options(Options * options) options->forward_x11 = 0; if (options->forward_x11_trusted == -1) options->forward_x11_trusted = 0; + if (options->forward_x11_timeout == -1) + options->forward_x11_timeout = 1200; if (options->exit_on_forward_failure == -1) options->exit_on_forward_failure = 0; if (options->xauth_location == NULL) @@ -1221,6 +1270,10 @@ fill_default_options(Options * options) options->server_alive_count_max = 3; if (options->control_master == -1) options->control_master = 0; + if (options->control_persist == -1) { + options->control_persist = 0; + options->control_persist_timeout = 0; + } if (options->hash_known_hosts == -1) options->hash_known_hosts = 0; if (options->tun_open == -1) diff --git a/crypto/openssh/readconf.h b/crypto/openssh/readconf.h index 4264751..95d1046 100644 --- a/crypto/openssh/readconf.h +++ b/crypto/openssh/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.82 2010/02/08 10:50:20 markus Exp $ */ +/* $OpenBSD: readconf.h,v 1.86 2010/07/19 09:15:12 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -23,6 +23,7 @@ typedef struct { int listen_port; /* Port to forward. */ char *connect_host; /* Host to connect. */ int connect_port; /* Port to connect on connect_host. */ + int allocated_port; /* Dynamically allocated listen port */ } Forward; /* Data structure for representing option data. */ @@ -31,6 +32,7 @@ typedef struct { typedef struct { int forward_agent; /* Forward authentication agent. */ int forward_x11; /* Forward X11 display. */ + int forward_x11_timeout; /* Expiration for Cookies */ int forward_x11_trusted; /* Trust Forward X11 display. */ int exit_on_forward_failure; /* Exit if bind(2) fails for -L/-R */ char *xauth_location; /* Location for xauth program */ @@ -93,11 +95,11 @@ typedef struct { /* Local TCP/IP forward requests. */ int num_local_forwards; - Forward local_forwards[SSH_MAX_FORWARDS_PER_DIRECTION]; + Forward *local_forwards; /* Remote TCP/IP forward requests. */ int num_remote_forwards; - Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION]; + Forward *remote_forwards; int clear_forwardings; int enable_ssh_keysign; @@ -112,6 +114,8 @@ typedef struct { char *control_path; int control_master; + int control_persist; /* ControlPersist flag */ + int control_persist_timeout; /* ControlPersist timeout (seconds) */ int hash_known_hosts; diff --git a/crypto/openssh/scp.c b/crypto/openssh/scp.c index 09efb82..e07de42 100644 --- a/crypto/openssh/scp.c +++ b/crypto/openssh/scp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scp.c,v 1.165 2009/12/20 07:28:36 guenther Exp $ */ +/* $OpenBSD: scp.c,v 1.166 2010/07/01 13:06:59 millert Exp $ */ /* * scp - secure remote copy. This is basically patched BSD rcp which * uses ssh to do the data transfer (instead of using rcmd). @@ -156,6 +156,20 @@ killchild(int signo) exit(1); } +static void +suspchild(int signo) +{ + int status; + + if (do_cmd_pid > 1) { + kill(do_cmd_pid, signo); + while (waitpid(do_cmd_pid, &status, WUNTRACED) == -1 && + errno == EINTR) + ; + kill(getpid(), SIGSTOP); + } +} + static int do_local_cmd(arglist *a) { @@ -232,6 +246,10 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) close(reserved[0]); close(reserved[1]); + signal(SIGTSTP, suspchild); + signal(SIGTTIN, suspchild); + signal(SIGTTOU, suspchild); + /* Fork a child to execute the command on the remote host using ssh. */ do_cmd_pid = fork(); if (do_cmd_pid == 0) { diff --git a/crypto/openssh/servconf.c b/crypto/openssh/servconf.c index 626f38c..506cf2e 100644 --- a/crypto/openssh/servconf.c +++ b/crypto/openssh/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.207 2010/03/25 23:38:28 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.209 2010/06/22 04:22:59 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved @@ -133,6 +133,7 @@ initialize_server_options(ServerOptions *options) options->zero_knowledge_password_authentication = -1; options->revoked_keys_file = NULL; options->trusted_user_ca_keys = NULL; + options->authorized_principals_file = NULL; } void @@ -312,7 +313,7 @@ typedef enum { sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, sZeroKnowledgePasswordAuthentication, sHostCertificate, - sRevokedKeys, sTrustedUserCAKeys, + sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, sVersionAddendum, sDeprecated, sUnsupported } ServerOpCodes; @@ -348,7 +349,7 @@ static struct { { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL }, { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL }, { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL }, - { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_GLOBAL }, + { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL }, { "rsaauthentication", sRSAAuthentication, SSHCFG_ALL }, { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL }, { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */ @@ -423,11 +424,11 @@ static struct { { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL }, { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL }, { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL }, - { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL }, - { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL }, + { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL }, + { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_ALL }, { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL}, { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL }, - { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL }, + { "permittunnel", sPermitTunnel, SSHCFG_ALL }, { "match", sMatch, SSHCFG_ALL }, { "permitopen", sPermitOpen, SSHCFG_ALL }, { "forcecommand", sForceCommand, SSHCFG_ALL }, @@ -435,6 +436,7 @@ static struct { { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, + { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL }, { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, { NULL, sBadOption, 0 } }; @@ -1222,10 +1224,14 @@ process_server_config_line(ServerOptions *options, char *line, * AuthorizedKeysFile /etc/ssh_keys/%u */ case sAuthorizedKeysFile: + charptr = &options->authorized_keys_file; + goto parse_tilde_filename; case sAuthorizedKeysFile2: - charptr = (opcode == sAuthorizedKeysFile) ? - &options->authorized_keys_file : - &options->authorized_keys_file2; + charptr = &options->authorized_keys_file2; + goto parse_tilde_filename; + case sAuthorizedPrincipalsFile: + charptr = &options->authorized_principals_file; + parse_tilde_filename: arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: missing file name.", @@ -1451,6 +1457,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) M_CP_INTOPT(pubkey_authentication); M_CP_INTOPT(kerberos_authentication); M_CP_INTOPT(hostbased_authentication); + M_CP_INTOPT(hostbased_uses_name_from_packet_only); M_CP_INTOPT(kbd_interactive_authentication); M_CP_INTOPT(zero_knowledge_password_authentication); M_CP_INTOPT(permit_root_login); @@ -1458,6 +1465,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) M_CP_INTOPT(allow_tcp_forwarding); M_CP_INTOPT(allow_agent_forwarding); + M_CP_INTOPT(permit_tun); M_CP_INTOPT(gateway_ports); M_CP_INTOPT(x11_display_offset); M_CP_INTOPT(x11_forwarding); @@ -1472,6 +1480,9 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) M_CP_STROPT(chroot_directory); M_CP_STROPT(trusted_user_ca_keys); M_CP_STROPT(revoked_keys_file); + M_CP_STROPT(authorized_keys_file); + M_CP_STROPT(authorized_keys_file2); + M_CP_STROPT(authorized_principals_file); } #undef M_CP_INTOPT @@ -1693,6 +1704,8 @@ dump_config(ServerOptions *o) dump_cfg_string(sChrootDirectory, o->chroot_directory); dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); dump_cfg_string(sRevokedKeys, o->revoked_keys_file); + dump_cfg_string(sAuthorizedPrincipalsFile, + o->authorized_principals_file); /* string arguments requiring a lookup */ dump_cfg_string(sLogLevel, log_level_name(o->log_level)); diff --git a/crypto/openssh/servconf.h b/crypto/openssh/servconf.h index 860009f..45d2a2a 100644 --- a/crypto/openssh/servconf.h +++ b/crypto/openssh/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.92 2010/03/04 10:36:03 djm Exp $ */ +/* $OpenBSD: servconf.h,v 1.93 2010/05/07 11:30:30 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -156,6 +156,7 @@ typedef struct { char *chroot_directory; char *revoked_keys_file; char *trusted_user_ca_keys; + char *authorized_principals_file; } ServerOptions; void initialize_server_options(ServerOptions *); diff --git a/crypto/openssh/session.c b/crypto/openssh/session.c index 9fa7213..bc4d7a9 100644 --- a/crypto/openssh/session.c +++ b/crypto/openssh/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.252 2010/03/07 11:57:13 dtucker Exp $ */ +/* $OpenBSD: session.c,v 1.256 2010/06/25 07:20:04 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved @@ -48,6 +48,7 @@ __RCSID("$FreeBSD$"); #include <arpa/inet.h> #include <errno.h> +#include <fcntl.h> #include <grp.h> #ifdef HAVE_PATHS_H #include <paths.h> @@ -105,7 +106,7 @@ __RCSID("$FreeBSD$"); /* func */ Session *session_new(void); -void session_set_fds(Session *, int, int, int, int); +void session_set_fds(Session *, int, int, int, int, int); void session_pty_cleanup(Session *); void session_proctitle(Session *); int session_setup_x11fwd(Session *); @@ -448,6 +449,9 @@ do_exec_no_pty(Session *s, const char *command) #ifdef USE_PIPES int pin[2], pout[2], perr[2]; + if (s == NULL) + fatal("do_exec_no_pty: no session"); + /* Allocate pipes for communicating with the program. */ if (pipe(pin) < 0) { error("%s: pipe in: %.100s", __func__, strerror(errno)); @@ -460,7 +464,8 @@ do_exec_no_pty(Session *s, const char *command) return -1; } if (pipe(perr) < 0) { - error("%s: pipe err: %.100s", __func__, strerror(errno)); + error("%s: pipe err: %.100s", __func__, + strerror(errno)); close(pin[0]); close(pin[1]); close(pout[0]); @@ -470,22 +475,23 @@ do_exec_no_pty(Session *s, const char *command) #else int inout[2], err[2]; + if (s == NULL) + fatal("do_exec_no_pty: no session"); + /* Uses socket pairs to communicate with the program. */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) { error("%s: socketpair #1: %.100s", __func__, strerror(errno)); return -1; } if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) { - error("%s: socketpair #2: %.100s", __func__, strerror(errno)); + error("%s: socketpair #2: %.100s", __func__, + strerror(errno)); close(inout[0]); close(inout[1]); return -1; } #endif - if (s == NULL) - fatal("do_exec_no_pty: no session"); - session_proctitle(s); /* Fork the child. */ @@ -596,11 +602,8 @@ do_exec_no_pty(Session *s, const char *command) close(perr[1]); if (compat20) { - if (s->is_subsystem) { - close(perr[0]); - perr[0] = -1; - } - session_set_fds(s, pin[1], pout[0], perr[0], 0); + session_set_fds(s, pin[1], pout[0], perr[0], + s->is_subsystem, 0); } else { /* Enter the interactive session. */ server_loop(pid, pin[1], pout[0], perr[0]); @@ -616,10 +619,8 @@ do_exec_no_pty(Session *s, const char *command) * handle the case that fdin and fdout are the same. */ if (compat20) { - session_set_fds(s, inout[1], inout[1], - s->is_subsystem ? -1 : err[1], 0); - if (s->is_subsystem) - close(err[1]); + session_set_fds(s, inout[1], inout[1], err[1], + s->is_subsystem, 0); } else { server_loop(pid, inout[1], inout[1], err[1]); /* server_loop has closed inout[1] and err[1]. */ @@ -741,7 +742,7 @@ do_exec_pty(Session *s, const char *command) s->ptymaster = ptymaster; packet_set_interactive(1); if (compat20) { - session_set_fds(s, ptyfd, fdout, -1, 1); + session_set_fds(s, ptyfd, fdout, -1, 1, 1); } else { server_loop(pid, ptyfd, fdout, -1); /* server_loop _has_ closed ptyfd and fdout. */ @@ -1804,7 +1805,8 @@ do_child(Session *s, const char *command) #ifdef HAVE_LOGIN_CAP r = login_getcapbool(lc, "requirehome", 0); #endif - if (r || options.chroot_directory == NULL) + if (r || options.chroot_directory == NULL || + strcasecmp(options.chroot_directory, "none") == 0) fprintf(stderr, "Could not chdir to home " "directory %s: %s\n", pw->pw_dir, strerror(errno)); @@ -2149,7 +2151,8 @@ session_subsystem_req(Session *s) u_int i; packet_check_eom(); - logit("subsystem request for %.100s", subsys); + logit("subsystem request for %.100s by user %s", subsys, + s->pw->pw_name); for (i = 0; i < options.num_subsystems; i++) { if (strcmp(subsys, options.subsystem_name[i]) == 0) { @@ -2331,7 +2334,8 @@ session_input_channel_req(Channel *c, const char *rtype) } void -session_set_fds(Session *s, int fdin, int fdout, int fderr, int is_tty) +session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr, + int is_tty) { if (!compat20) fatal("session_set_fds: called for proto != 2.0"); @@ -2343,7 +2347,7 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr, int is_tty) fatal("no channel for session %d", s->self); channel_set_fds(s->chanid, fdout, fdin, fderr, - fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, + ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, 1, is_tty, CHAN_SES_WINDOW_DEFAULT); } diff --git a/crypto/openssh/sftp-client.c b/crypto/openssh/sftp-client.c index 6124c0f..9dab477 100644 --- a/crypto/openssh/sftp-client.c +++ b/crypto/openssh/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.90 2009/10/11 10:41:26 dtucker Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.92 2010/07/19 03:16:33 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * @@ -713,7 +713,8 @@ do_realpath(struct sftp_conn *conn, char *path) u_int status = buffer_get_int(&msg); error("Couldn't canonicalise: %s", fx2txt(status)); - return(NULL); + buffer_free(&msg); + return NULL; } else if (type != SSH2_FXP_NAME) fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", SSH2_FXP_NAME, type); @@ -1522,7 +1523,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, continue; if (upload_dir_internal(conn, new_src, new_dst, - pflag, depth + 1, printflag) == -1) + pflag, printflag, depth + 1) == -1) ret = -1; } else if (S_ISREG(sb.st_mode)) { if (do_upload(conn, new_src, new_dst, pflag) == -1) { diff --git a/crypto/openssh/sftp.c b/crypto/openssh/sftp.c index d65d4ec..229f129 100644 --- a/crypto/openssh/sftp.c +++ b/crypto/openssh/sftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.c,v 1.123 2010/01/27 19:21:39 djm Exp $ */ +/* $OpenBSD: sftp.c,v 1.125 2010/06/18 00:58:39 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * @@ -181,6 +181,8 @@ static const struct CMD cmds[] = { { "ls", I_LS, REMOTE }, { "lumask", I_LUMASK, NOARGS }, { "mkdir", I_MKDIR, REMOTE }, + { "mget", I_GET, REMOTE }, + { "mput", I_PUT, LOCAL }, { "progress", I_PROGRESS, NOARGS }, { "put", I_PUT, LOCAL }, { "pwd", I_PWD, REMOTE }, @@ -1366,7 +1368,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, break; case I_LS: if (!path1) { - do_globbed_ls(conn, *pwd, *pwd, lflag); + do_ls_dir(conn, *pwd, *pwd, lflag); break; } diff --git a/crypto/openssh/ssh-add.c b/crypto/openssh/ssh-add.c index ad9f7a8..fb641ec 100644 --- a/crypto/openssh/ssh-add.c +++ b/crypto/openssh/ssh-add.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-add.c,v 1.94 2010/03/01 11:07:06 otto Exp $ */ +/* $OpenBSD: ssh-add.c,v 1.96 2010/05/14 00:47:22 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -194,7 +194,7 @@ add_file(AuthenticationConnection *ac, const char *filename) "Lifetime set to %d seconds\n", lifetime); if (confirm != 0) fprintf(stderr, - "The user has to confirm each use of the key\n"); + "The user must confirm each use of the key\n"); } else { fprintf(stderr, "Could not add identity: %s\n", filename); } @@ -202,29 +202,37 @@ add_file(AuthenticationConnection *ac, const char *filename) /* Now try to add the certificate flavour too */ xasprintf(&certpath, "%s-cert.pub", filename); - if ((cert = key_load_public(certpath, NULL)) != NULL) { - /* Graft with private bits */ - if (key_to_certified(private) != 0) - fatal("%s: key_to_certified failed", __func__); - key_cert_copy(cert, private); + if ((cert = key_load_public(certpath, NULL)) == NULL) + goto out; + + if (!key_equal_public(cert, private)) { + error("Certificate %s does not match private key %s", + certpath, filename); key_free(cert); + goto out; + } - if (ssh_add_identity_constrained(ac, private, comment, - lifetime, confirm)) { - fprintf(stderr, "Certificate added: %s (%s)\n", - certpath, private->cert->key_id); - if (lifetime != 0) - fprintf(stderr, "Lifetime set to %d seconds\n", - lifetime); - if (confirm != 0) - fprintf(stderr, "The user has to confirm each " - "use of the key\n"); - } else { - error("Certificate %s (%s) add failed", certpath, - private->cert->key_id); - } + /* Graft with private bits */ + if (key_to_certified(private, key_cert_is_legacy(cert)) != 0) { + error("%s: key_to_certified failed", __func__); + key_free(cert); + goto out; } + key_cert_copy(cert, private); + key_free(cert); + if (!ssh_add_identity_constrained(ac, private, comment, + lifetime, confirm)) { + error("Certificate %s (%s) add failed", certpath, + private->cert->key_id); + } + fprintf(stderr, "Certificate added: %s (%s)\n", certpath, + private->cert->key_id); + if (lifetime != 0) + fprintf(stderr, "Lifetime set to %d seconds\n", lifetime); + if (confirm != 0) + fprintf(stderr, "The user must confirm each use of the key\n"); + out: xfree(certpath); xfree(comment); key_free(private); diff --git a/crypto/openssh/ssh-agent.c b/crypto/openssh/ssh-agent.c index 320591b..edd65a2 100644 --- a/crypto/openssh/ssh-agent.c +++ b/crypto/openssh/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.165 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.166 2010/04/16 01:47:26 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -501,6 +501,7 @@ process_add_identity(SocketEntry *e, int version) buffer_get_bignum2(&e->request, k->dsa->pub_key); buffer_get_bignum2(&e->request, k->dsa->priv_key); break; + case KEY_DSA_CERT_V00: case KEY_DSA_CERT: cert = buffer_get_string(&e->request, &len); if ((k = key_from_blob(cert, len)) == NULL) @@ -521,6 +522,7 @@ process_add_identity(SocketEntry *e, int version) /* Generate additional parameters */ rsa_generate_additional_parameters(k->rsa); break; + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: cert = buffer_get_string(&e->request, &len); if ((k = key_from_blob(cert, len)) == NULL) @@ -541,6 +543,7 @@ process_add_identity(SocketEntry *e, int version) /* enable blinding */ switch (k->type) { case KEY_RSA: + case KEY_RSA_CERT_V00: case KEY_RSA_CERT: case KEY_RSA1: if (RSA_blinding_on(k->rsa, NULL) != 1) { diff --git a/crypto/openssh/ssh-dss.c b/crypto/openssh/ssh-dss.c index 449f493..175e4d0 100644 --- a/crypto/openssh/ssh-dss.c +++ b/crypto/openssh/ssh-dss.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-dss.c,v 1.25 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: ssh-dss.c,v 1.26 2010/04/16 01:47:26 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -53,9 +53,8 @@ ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp, u_int rlen, slen, len, dlen; Buffer b; - if (key == NULL || - (key->type != KEY_DSA && key->type != KEY_DSA_CERT) || - key->dsa == NULL) { + if (key == NULL || key->dsa == NULL || (key->type != KEY_DSA && + key->type != KEY_DSA_CERT && key->type != KEY_DSA_CERT_V00)) { error("ssh_dss_sign: no DSA key"); return -1; } @@ -118,9 +117,8 @@ ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen, int rlen, ret; Buffer b; - if (key == NULL || - (key->type != KEY_DSA && key->type != KEY_DSA_CERT) || - key->dsa == NULL) { + if (key == NULL || key->dsa == NULL || (key->type != KEY_DSA && + key->type != KEY_DSA_CERT && key->type != KEY_DSA_CERT_V00)) { error("ssh_dss_verify: no DSA key"); return -1; } diff --git a/crypto/openssh/ssh-keygen.1 b/crypto/openssh/ssh-keygen.1 index 855a1d5..5a04fc0 100644 --- a/crypto/openssh/ssh-keygen.1 +++ b/crypto/openssh/ssh-keygen.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keygen.1,v 1.92 2010/03/13 23:38:13 jmc Exp $ +.\" $OpenBSD: ssh-keygen.1,v 1.98 2010/08/04 06:07:11 djm Exp $ .\" $FreeBSD$ .\" .\" -*- nroff -*- @@ -38,15 +38,15 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd March 13, 2010 +.Dd August 4, 2010 .Dt SSH-KEYGEN 1 .Os .Sh NAME .Nm ssh-keygen .Nd authentication key generation, management and conversion .Sh SYNOPSIS -.Nm ssh-keygen .Bk -words +.Nm ssh-keygen .Op Fl q .Op Fl b Ar bits .Fl t Ar type @@ -60,9 +60,11 @@ .Op Fl f Ar keyfile .Nm ssh-keygen .Fl i +.Op Fl m Ar key_format .Op Fl f Ar input_keyfile .Nm ssh-keygen .Fl e +.Op Fl m Ar key_format .Op Fl f Ar input_keyfile .Nm ssh-keygen .Fl y @@ -111,8 +113,9 @@ .Fl I Ar certificate_identity .Op Fl h .Op Fl n Ar principals -.Op Fl O Ar constraint +.Op Fl O Ar option .Op Fl V Ar validity_interval +.Op Fl z Ar serial_number .Ar .Nm ssh-keygen .Fl L @@ -213,13 +216,20 @@ the passphrase if the key has one, and for the new comment. .It Fl D Ar pkcs11 Download the RSA public keys provided by the PKCS#11 shared library .Ar pkcs11 . +When used in combination with +.Fl s , +this option indicates that a CA key resides in a PKCS#11 token (see the +.Sx CERTIFICATES +section for details). .It Fl e This option will read a private or public OpenSSH key file and -print the key in -RFC 4716 SSH Public Key File Format -to stdout. -This option allows exporting keys for use by several commercial -SSH implementations. +print to stdout the key in one of the formats specified by the +.Fl m +option. +The default export format is +.Dq RFC4716 . +This option allows exporting OpenSSH keys for use by other programs, including +several commercial SSH implementations. .It Fl F Ar hostname Search for the specified .Ar hostname @@ -270,13 +280,14 @@ Please see the section for details. .It Fl i This option will read an unencrypted private (or public) key file -in SSH2-compatible format and print an OpenSSH compatible private +in the format specified by the +.Fl m +option and print an OpenSSH compatible private (or public) key to stdout. -.Nm -also reads the -RFC 4716 SSH Public Key File Format. -This option allows importing keys from several commercial -SSH implementations. +This option allows importing keys from other software, including several +commercial SSH implementations. +The default import format is +.Dq RFC4716 . .It Fl L Prints the contents of a certificate. .It Fl l @@ -291,6 +302,22 @@ an ASCII art representation of the key is supplied with the fingerprint. .It Fl M Ar memory Specify the amount of memory to use (in megabytes) when generating candidate moduli for DH-GEX. +.It Fl m Ar key_format +Specify a key format for the +.Fl i +(import) or +.Fl e +(export) conversion options. +The supported key formats are: +.Dq RFC4716 +(RFC 4716/SSH2 public or private key), +.Dq PKCS8 +(PEM PKCS8 public key) +or +.Dq PEM +(PEM public key). +The default conversion format is +.Dq RFC4716 . .It Fl N Ar new_passphrase Provides the new passphrase. .It Fl n Ar principals @@ -300,13 +327,13 @@ Multiple principals may be specified, separated by commas. Please see the .Sx CERTIFICATES section for details. -.It Fl O Ar constraint -Specify a certificate constraint when signing a key. +.It Fl O Ar option +Specify a certificate option when signing a key. This option may be specified multiple times. Please see the .Sx CERTIFICATES section for details. -The constraints that are valid for user certificates are: +The options that are valid for user certificates are: .Bl -tag -width Ds .It Ic clear Clear all enabled permissions. @@ -356,7 +383,7 @@ is a comma-separated list of one or more address/netmask pairs in CIDR format. .El .Pp -At present, no constraints are valid for host keys. +At present, no options are valid for host keys. .It Fl P Ar passphrase Provides the (old) passphrase. .It Fl p @@ -442,6 +469,10 @@ Specify desired generator when testing candidate moduli for DH-GEX. .It Fl y This option will read a private OpenSSH format file and print an OpenSSH public key to stdout. +.It Fl z Ar serial_number +Specifies a serial number to be embedded in the certificate to distinguish +this certificate from others from the same CA. +The default serial number is zero. .El .Sh MODULI GENERATION .Nm @@ -502,7 +533,7 @@ that both ends of a connection share common moduli. supports signing of keys to produce certificates that may be used for user or host authentication. Certificates consist of a public key, some identity information, zero or -more principal (user or host) names and an optional set of constraints that +more principal (user or host) names and a set of options that are signed by a Certification Authority (CA) key. Clients or servers may then trust only the CA key and verify its signature on a certificate rather than trusting many user/host keys. @@ -528,7 +559,17 @@ option: .Pp The host certificate will be output to .Pa /path/to/host_key-cert.pub . -In both cases, +.Pp +It is possible to sign using a CA key stored in a PKCS#11 token by +providing the token library using +.Fl D +and identifying the CA key by providing its public half as an argument +to +.Fl s : +.Pp +.Dl $ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id host_key.pub +.Pp +In all cases, .Ar key_id is a "key identifier" that is logged by the server when the certificate is used for authentication. @@ -542,11 +583,11 @@ To generate a certificate for a specified set of principals: .Dl "$ ssh-keygen -s ca_key -I key_id -h -n host.domain user_key.pub" .Pp Additional limitations on the validity and use of user certificates may -be specified through certificate constraints. -A constrained certificate may disable features of the SSH session, may be +be specified through certificate options. +A certificate option may disable features of the SSH session, may be valid only when presented from particular source addresses or may force the use of a specific command. -For a list of valid certificate constraints, see the documentation for the +For a list of valid certificate options, see the documentation for the .Fl O option above. .Pp diff --git a/crypto/openssh/ssh-keygen.c b/crypto/openssh/ssh-keygen.c index 37e516f..d90b1df 100644 --- a/crypto/openssh/ssh-keygen.c +++ b/crypto/openssh/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.185 2010/03/15 19:40:02 stevesk Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.197 2010/08/04 06:07:11 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -105,6 +105,9 @@ char *identity_comment = NULL; /* Path to CA key when certifying keys. */ char *ca_key_path = NULL; +/* Certificate serial number */ +long long cert_serial = 0; + /* Key type when certifying */ u_int cert_key_type = SSH2_CERT_TYPE_USER; @@ -118,27 +121,34 @@ char *cert_principals = NULL; u_int64_t cert_valid_from = 0; u_int64_t cert_valid_to = ~0ULL; -/* Certificate constraints */ -#define CONSTRAINT_X_FWD (1) -#define CONSTRAINT_AGENT_FWD (1<<1) -#define CONSTRAINT_PORT_FWD (1<<2) -#define CONSTRAINT_PTY (1<<3) -#define CONSTRAINT_USER_RC (1<<4) -#define CONSTRAINT_DEFAULT (CONSTRAINT_X_FWD|CONSTRAINT_AGENT_FWD| \ - CONSTRAINT_PORT_FWD|CONSTRAINT_PTY| \ - CONSTRAINT_USER_RC) -u_int32_t constraint_flags = CONSTRAINT_DEFAULT; -char *constraint_command = NULL; -char *constraint_src_addr = NULL; - -/* Dump public key file in format used by real and the original SSH 2 */ -int convert_to_ssh2 = 0; -int convert_from_ssh2 = 0; +/* Certificate options */ +#define CERTOPT_X_FWD (1) +#define CERTOPT_AGENT_FWD (1<<1) +#define CERTOPT_PORT_FWD (1<<2) +#define CERTOPT_PTY (1<<3) +#define CERTOPT_USER_RC (1<<4) +#define CERTOPT_DEFAULT (CERTOPT_X_FWD|CERTOPT_AGENT_FWD| \ + CERTOPT_PORT_FWD|CERTOPT_PTY|CERTOPT_USER_RC) +u_int32_t certflags_flags = CERTOPT_DEFAULT; +char *certflags_command = NULL; +char *certflags_src_addr = NULL; + +/* Conversion to/from various formats */ +int convert_to = 0; +int convert_from = 0; +enum { + FMT_RFC4716, + FMT_PKCS8, + FMT_PEM +} convert_format = FMT_RFC4716; int print_public = 0; int print_generic = 0; char *key_type_name = NULL; +/* Load key from this PKCS#11 provider */ +char *pkcs11provider = NULL; + /* argv0 */ extern char *__progname; @@ -161,9 +171,13 @@ ask_filename(struct passwd *pw, const char *prompt) case KEY_RSA1: name = _PATH_SSH_CLIENT_IDENTITY; break; + case KEY_DSA_CERT: + case KEY_DSA_CERT_V00: case KEY_DSA: name = _PATH_SSH_CLIENT_ID_DSA; break; + case KEY_RSA_CERT: + case KEY_RSA_CERT_V00: case KEY_RSA: name = _PATH_SSH_CLIENT_ID_RSA; break; @@ -209,30 +223,12 @@ load_identity(char *filename) #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb static void -do_convert_to_ssh2(struct passwd *pw) +do_convert_to_ssh2(struct passwd *pw, Key *k) { - Key *k; u_int len; u_char *blob; char comment[61]; - struct stat st; - if (!have_identity) - ask_filename(pw, "Enter file in which the key is"); - if (stat(identity_file, &st) < 0) { - perror(identity_file); - exit(1); - } - if ((k = key_load_public(identity_file, NULL)) == NULL) { - if ((k = load_identity(identity_file)) == NULL) { - fprintf(stderr, "load failed\n"); - exit(1); - } - } - if (k->type == KEY_RSA1) { - fprintf(stderr, "version 1 keys are not supported\n"); - exit(1); - } if (key_to_blob(k, &blob, &len) <= 0) { fprintf(stderr, "key_to_blob failed\n"); exit(1); @@ -253,6 +249,81 @@ do_convert_to_ssh2(struct passwd *pw) } static void +do_convert_to_pkcs8(Key *k) +{ + switch (key_type_plain(k->type)) { + case KEY_RSA: + if (!PEM_write_RSA_PUBKEY(stdout, k->rsa)) + fatal("PEM_write_RSA_PUBKEY failed"); + break; + case KEY_DSA: + if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) + fatal("PEM_write_DSA_PUBKEY failed"); + break; + default: + fatal("%s: unsupported key type %s", __func__, key_type(k)); + } + exit(0); +} + +static void +do_convert_to_pem(Key *k) +{ + switch (key_type_plain(k->type)) { + case KEY_RSA: + if (!PEM_write_RSAPublicKey(stdout, k->rsa)) + fatal("PEM_write_RSAPublicKey failed"); + break; +#if notyet /* OpenSSH 0.9.8 lacks this function */ + case KEY_DSA: + if (!PEM_write_DSAPublicKey(stdout, k->dsa)) + fatal("PEM_write_DSAPublicKey failed"); + break; +#endif + default: + fatal("%s: unsupported key type %s", __func__, key_type(k)); + } + exit(0); +} + +static void +do_convert_to(struct passwd *pw) +{ + Key *k; + struct stat st; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) + fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); + if ((k = key_load_public(identity_file, NULL)) == NULL) { + if ((k = load_identity(identity_file)) == NULL) { + fprintf(stderr, "load failed\n"); + exit(1); + } + } + if (k->type == KEY_RSA1) { + fprintf(stderr, "version 1 keys are not supported\n"); + exit(1); + } + + switch (convert_format) { + case FMT_RFC4716: + do_convert_to_ssh2(pw, k); + break; + case FMT_PKCS8: + do_convert_to_pkcs8(k); + break; + case FMT_PEM: + do_convert_to_pem(k); + break; + default: + fatal("%s: unknown key format %d", __func__, convert_format); + } + exit(0); +} + +static void buffer_get_bignum_bits(Buffer *b, BIGNUM *value) { u_int bignum_bits = buffer_get_int(b); @@ -390,29 +461,18 @@ get_line(FILE *fp, char *line, size_t len) } static void -do_convert_from_ssh2(struct passwd *pw) +do_convert_from_ssh2(struct passwd *pw, Key **k, int *private) { - Key *k; int blen; u_int len; char line[1024]; u_char blob[8096]; char encoded[8096]; - struct stat st; - int escaped = 0, private = 0, ok; + int escaped = 0; FILE *fp; - if (!have_identity) - ask_filename(pw, "Enter file in which the key is"); - if (stat(identity_file, &st) < 0) { - perror(identity_file); - exit(1); - } - fp = fopen(identity_file, "r"); - if (fp == NULL) { - perror(identity_file); - exit(1); - } + if ((fp = fopen(identity_file, "r")) == NULL) + fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); encoded[0] = '\0'; while ((blen = get_line(fp, line, sizeof(line))) != -1) { if (line[blen - 1] == '\\') @@ -420,7 +480,7 @@ do_convert_from_ssh2(struct passwd *pw) if (strncmp(line, "----", 4) == 0 || strstr(line, ": ") != NULL) { if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) - private = 1; + *private = 1; if (strstr(line, " END ") != NULL) { break; } @@ -445,26 +505,130 @@ do_convert_from_ssh2(struct passwd *pw) fprintf(stderr, "uudecode failed.\n"); exit(1); } - k = private ? + *k = *private ? do_convert_private_ssh2_from_blob(blob, blen) : key_from_blob(blob, blen); - if (k == NULL) { + if (*k == NULL) { fprintf(stderr, "decode blob failed.\n"); exit(1); } - ok = private ? - (k->type == KEY_DSA ? - PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) : - PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) : - key_write(k, stdout); + fclose(fp); +} + +static void +do_convert_from_pkcs8(Key **k, int *private) +{ + EVP_PKEY *pubkey; + FILE *fp; + + if ((fp = fopen(identity_file, "r")) == NULL) + fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); + if ((pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { + fatal("%s: %s is not a recognised public key format", __func__, + identity_file); + } + fclose(fp); + switch (EVP_PKEY_type(pubkey->type)) { + case EVP_PKEY_RSA: + *k = key_new(KEY_UNSPEC); + (*k)->type = KEY_RSA; + (*k)->rsa = EVP_PKEY_get1_RSA(pubkey); + break; + case EVP_PKEY_DSA: + *k = key_new(KEY_UNSPEC); + (*k)->type = KEY_DSA; + (*k)->dsa = EVP_PKEY_get1_DSA(pubkey); + break; + default: + fatal("%s: unsupported pubkey type %d", __func__, + EVP_PKEY_type(pubkey->type)); + } + EVP_PKEY_free(pubkey); + return; +} + +static void +do_convert_from_pem(Key **k, int *private) +{ + FILE *fp; + RSA *rsa; +#ifdef notyet + DSA *dsa; +#endif + + if ((fp = fopen(identity_file, "r")) == NULL) + fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); + if ((rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL)) != NULL) { + *k = key_new(KEY_UNSPEC); + (*k)->type = KEY_RSA; + (*k)->rsa = rsa; + fclose(fp); + return; + } +#if notyet /* OpenSSH 0.9.8 lacks this function */ + rewind(fp); + if ((dsa = PEM_read_DSAPublicKey(fp, NULL, NULL, NULL)) != NULL) { + *k = key_new(KEY_UNSPEC); + (*k)->type = KEY_DSA; + (*k)->dsa = dsa; + fclose(fp); + return; + } +#endif + fatal("%s: unrecognised raw private key format", __func__); +} + +static void +do_convert_from(struct passwd *pw) +{ + Key *k = NULL; + int private = 0, ok = 0; + struct stat st; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) + fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); + + switch (convert_format) { + case FMT_RFC4716: + do_convert_from_ssh2(pw, &k, &private); + break; + case FMT_PKCS8: + do_convert_from_pkcs8(&k, &private); + break; + case FMT_PEM: + do_convert_from_pem(&k, &private); + break; + default: + fatal("%s: unknown key format %d", __func__, convert_format); + } + + if (!private) + ok = key_write(k, stdout); + if (ok) + fprintf(stdout, "\n"); + else { + switch (k->type) { + case KEY_DSA: + ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, + NULL, 0, NULL, NULL); + break; + case KEY_RSA: + ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, + NULL, 0, NULL, NULL); + break; + default: + fatal("%s: unsupported key type %s", __func__, + key_type(k)); + } + } + if (!ok) { fprintf(stderr, "key write failed\n"); exit(1); } key_free(k); - if (!private) - fprintf(stdout, "\n"); - fclose(fp); exit(0); } @@ -493,7 +657,7 @@ do_print_public(struct passwd *pw) } static void -do_download(struct passwd *pw, char *pkcs11provider) +do_download(struct passwd *pw) { #ifdef ENABLE_PKCS11 Key **keys = NULL; @@ -555,67 +719,68 @@ do_fingerprint(struct passwd *pw) comment = NULL; } - f = fopen(identity_file, "r"); - if (f != NULL) { - while (fgets(line, sizeof(line), f)) { - if ((cp = strchr(line, '\n')) == NULL) { - error("line %d too long: %.40s...", - num + 1, line); - skip = 1; - continue; - } - num++; - if (skip) { - skip = 0; - continue; - } - *cp = '\0'; + if ((f = fopen(identity_file, "r")) == NULL) + fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); - /* Skip leading whitespace, empty and comment lines. */ - for (cp = line; *cp == ' ' || *cp == '\t'; cp++) - ; - if (!*cp || *cp == '\n' || *cp == '#') - continue; - i = strtol(cp, &ep, 10); - if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { - int quoted = 0; - comment = cp; - for (; *cp && (quoted || (*cp != ' ' && - *cp != '\t')); cp++) { - if (*cp == '\\' && cp[1] == '"') - cp++; /* Skip both */ - else if (*cp == '"') - quoted = !quoted; - } - if (!*cp) - continue; - *cp++ = '\0'; + while (fgets(line, sizeof(line), f)) { + if ((cp = strchr(line, '\n')) == NULL) { + error("line %d too long: %.40s...", + num + 1, line); + skip = 1; + continue; + } + num++; + if (skip) { + skip = 0; + continue; + } + *cp = '\0'; + + /* Skip leading whitespace, empty and comment lines. */ + for (cp = line; *cp == ' ' || *cp == '\t'; cp++) + ; + if (!*cp || *cp == '\n' || *cp == '#') + continue; + i = strtol(cp, &ep, 10); + if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { + int quoted = 0; + comment = cp; + for (; *cp && (quoted || (*cp != ' ' && + *cp != '\t')); cp++) { + if (*cp == '\\' && cp[1] == '"') + cp++; /* Skip both */ + else if (*cp == '"') + quoted = !quoted; } - ep = cp; - public = key_new(KEY_RSA1); + if (!*cp) + continue; + *cp++ = '\0'; + } + ep = cp; + public = key_new(KEY_RSA1); + if (key_read(public, &cp) != 1) { + cp = ep; + key_free(public); + public = key_new(KEY_UNSPEC); if (key_read(public, &cp) != 1) { - cp = ep; key_free(public); - public = key_new(KEY_UNSPEC); - if (key_read(public, &cp) != 1) { - key_free(public); - continue; - } + continue; } - comment = *cp ? cp : comment; - fp = key_fingerprint(public, fptype, rep); - ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); - printf("%u %s %s (%s)\n", key_size(public), fp, - comment ? comment : "no comment", key_type(public)); - if (log_level >= SYSLOG_LEVEL_VERBOSE) - printf("%s\n", ra); - xfree(ra); - xfree(fp); - key_free(public); - invalid = 0; } - fclose(f); + comment = *cp ? cp : comment; + fp = key_fingerprint(public, fptype, rep); + ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); + printf("%u %s %s (%s)\n", key_size(public), fp, + comment ? comment : "no comment", key_type(public)); + if (log_level >= SYSLOG_LEVEL_VERBOSE) + printf("%s\n", ra); + xfree(ra); + xfree(fp); + key_free(public); + invalid = 0; } + fclose(f); + if (invalid) { printf("%s is not a public key file.\n", identity_file); exit(1); @@ -670,7 +835,7 @@ do_known_hosts(struct passwd *pw, const char *name) have_identity = 1; } if ((in = fopen(identity_file, "r")) == NULL) - fatal("fopen: %s", strerror(errno)); + fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); /* * Find hosts goes to stdout, hash and deletions happen in-place @@ -1104,7 +1269,7 @@ fmt_validity(u_int64_t valid_from, u_int64_t valid_to) } static void -add_flag_constraint(Buffer *c, const char *name) +add_flag_option(Buffer *c, const char *name) { debug3("%s: %s", __func__, name); buffer_put_cstring(c, name); @@ -1112,7 +1277,7 @@ add_flag_constraint(Buffer *c, const char *name) } static void -add_string_constraint(Buffer *c, const char *name, const char *value) +add_string_option(Buffer *c, const char *name, const char *value) { Buffer b; @@ -1126,25 +1291,62 @@ add_string_constraint(Buffer *c, const char *name, const char *value) buffer_free(&b); } +#define OPTIONS_CRITICAL 1 +#define OPTIONS_EXTENSIONS 2 static void -prepare_constraint_buf(Buffer *c) +prepare_options_buf(Buffer *c, int which) { - buffer_clear(c); - if ((constraint_flags & CONSTRAINT_X_FWD) != 0) - add_flag_constraint(c, "permit-X11-forwarding"); - if ((constraint_flags & CONSTRAINT_AGENT_FWD) != 0) - add_flag_constraint(c, "permit-agent-forwarding"); - if ((constraint_flags & CONSTRAINT_PORT_FWD) != 0) - add_flag_constraint(c, "permit-port-forwarding"); - if ((constraint_flags & CONSTRAINT_PTY) != 0) - add_flag_constraint(c, "permit-pty"); - if ((constraint_flags & CONSTRAINT_USER_RC) != 0) - add_flag_constraint(c, "permit-user-rc"); - if (constraint_command != NULL) - add_string_constraint(c, "force-command", constraint_command); - if (constraint_src_addr != NULL) - add_string_constraint(c, "source-address", constraint_src_addr); + if ((which & OPTIONS_CRITICAL) != 0 && + certflags_command != NULL) + add_string_option(c, "force-command", certflags_command); + if ((which & OPTIONS_EXTENSIONS) != 0 && + (certflags_flags & CERTOPT_AGENT_FWD) != 0) + add_flag_option(c, "permit-agent-forwarding"); + if ((which & OPTIONS_EXTENSIONS) != 0 && + (certflags_flags & CERTOPT_PORT_FWD) != 0) + add_flag_option(c, "permit-port-forwarding"); + if ((which & OPTIONS_EXTENSIONS) != 0 && + (certflags_flags & CERTOPT_PTY) != 0) + add_flag_option(c, "permit-pty"); + if ((which & OPTIONS_EXTENSIONS) != 0 && + (certflags_flags & CERTOPT_USER_RC) != 0) + add_flag_option(c, "permit-user-rc"); + if ((which & OPTIONS_EXTENSIONS) != 0 && + (certflags_flags & CERTOPT_X_FWD) != 0) + add_flag_option(c, "permit-X11-forwarding"); + if ((which & OPTIONS_CRITICAL) != 0 && + certflags_src_addr != NULL) + add_string_option(c, "source-address", certflags_src_addr); +} + +static Key * +load_pkcs11_key(char *path) +{ +#ifdef ENABLE_PKCS11 + Key **keys = NULL, *public, *private = NULL; + int i, nkeys; + + if ((public = key_load_public(path, NULL)) == NULL) + fatal("Couldn't load CA public key \"%s\"", path); + + nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase, &keys); + debug3("%s: %d keys", __func__, nkeys); + if (nkeys <= 0) + fatal("cannot read public key from pkcs11"); + for (i = 0; i < nkeys; i++) { + if (key_equal_public(public, keys[i])) { + private = keys[i]; + continue; + } + key_free(keys[i]); + } + xfree(keys); + key_free(public); + return private; +#else + fatal("no pkcs11 support"); +#endif /* ENABLE_PKCS11 */ } static void @@ -1155,9 +1357,33 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) Key *ca, *public; char *otmp, *tmp, *cp, *out, *comment, **plist = NULL; FILE *f; + int v00 = 0; /* legacy keys */ + + if (key_type_name != NULL) { + switch (key_type_from_name(key_type_name)) { + case KEY_RSA_CERT_V00: + case KEY_DSA_CERT_V00: + v00 = 1; + break; + case KEY_UNSPEC: + if (strcasecmp(key_type_name, "v00") == 0) { + v00 = 1; + break; + } else if (strcasecmp(key_type_name, "v01") == 0) + break; + /* FALLTHROUGH */ + default: + fprintf(stderr, "unknown key type %s\n", key_type_name); + exit(1); + } + } + pkcs11_init(1); tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); - if ((ca = load_identity(tmp)) == NULL) + if (pkcs11provider != NULL) { + if ((ca = load_pkcs11_key(tmp)) == NULL) + fatal("No PKCS#11 key matching %s found", ca_key_path); + } else if ((ca = load_identity(tmp)) == NULL) fatal("Couldn't load CA key \"%s\"", tmp); xfree(tmp); @@ -1183,15 +1409,24 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) __func__, tmp, key_type(public)); /* Prepare certificate to sign */ - if (key_to_certified(public) != 0) + if (key_to_certified(public, v00) != 0) fatal("Could not upgrade key %s to certificate", tmp); public->cert->type = cert_key_type; + public->cert->serial = (u_int64_t)cert_serial; public->cert->key_id = xstrdup(cert_key_id); public->cert->nprincipals = n; public->cert->principals = plist; public->cert->valid_after = cert_valid_from; public->cert->valid_before = cert_valid_to; - prepare_constraint_buf(&public->cert->constraints); + if (v00) { + prepare_options_buf(&public->cert->critical, + OPTIONS_CRITICAL|OPTIONS_EXTENSIONS); + } else { + prepare_options_buf(&public->cert->critical, + OPTIONS_CRITICAL); + prepare_options_buf(&public->cert->extensions, + OPTIONS_EXTENSIONS); + } public->cert->signature_key = key_from_private(ca); if (key_certify(public, ca) != 0) @@ -1212,17 +1447,19 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) fprintf(f, " %s\n", comment); fclose(f); - if (!quiet) - logit("Signed %s key %s: id \"%s\"%s%s valid %s", - cert_key_type == SSH2_CERT_TYPE_USER?"user":"host", - out, cert_key_id, + if (!quiet) { + logit("Signed %s key %s: id \"%s\" serial %llu%s%s " + "valid %s", key_cert_type(public), + out, public->cert->key_id, public->cert->serial, cert_principals != NULL ? " for " : "", cert_principals != NULL ? cert_principals : "", fmt_validity(cert_valid_from, cert_valid_to)); + } key_free(public); xfree(out); } + pkcs11_terminate(); exit(0); } @@ -1321,50 +1558,92 @@ parse_cert_times(char *timespec) } static void -add_cert_constraint(char *opt) +add_cert_option(char *opt) { char *val; if (strcmp(opt, "clear") == 0) - constraint_flags = 0; + certflags_flags = 0; else if (strcasecmp(opt, "no-x11-forwarding") == 0) - constraint_flags &= ~CONSTRAINT_X_FWD; + certflags_flags &= ~CERTOPT_X_FWD; else if (strcasecmp(opt, "permit-x11-forwarding") == 0) - constraint_flags |= CONSTRAINT_X_FWD; + certflags_flags |= CERTOPT_X_FWD; else if (strcasecmp(opt, "no-agent-forwarding") == 0) - constraint_flags &= ~CONSTRAINT_AGENT_FWD; + certflags_flags &= ~CERTOPT_AGENT_FWD; else if (strcasecmp(opt, "permit-agent-forwarding") == 0) - constraint_flags |= CONSTRAINT_AGENT_FWD; + certflags_flags |= CERTOPT_AGENT_FWD; else if (strcasecmp(opt, "no-port-forwarding") == 0) - constraint_flags &= ~CONSTRAINT_PORT_FWD; + certflags_flags &= ~CERTOPT_PORT_FWD; else if (strcasecmp(opt, "permit-port-forwarding") == 0) - constraint_flags |= CONSTRAINT_PORT_FWD; + certflags_flags |= CERTOPT_PORT_FWD; else if (strcasecmp(opt, "no-pty") == 0) - constraint_flags &= ~CONSTRAINT_PTY; + certflags_flags &= ~CERTOPT_PTY; else if (strcasecmp(opt, "permit-pty") == 0) - constraint_flags |= CONSTRAINT_PTY; + certflags_flags |= CERTOPT_PTY; else if (strcasecmp(opt, "no-user-rc") == 0) - constraint_flags &= ~CONSTRAINT_USER_RC; + certflags_flags &= ~CERTOPT_USER_RC; else if (strcasecmp(opt, "permit-user-rc") == 0) - constraint_flags |= CONSTRAINT_USER_RC; + certflags_flags |= CERTOPT_USER_RC; else if (strncasecmp(opt, "force-command=", 14) == 0) { val = opt + 14; if (*val == '\0') - fatal("Empty force-command constraint"); - if (constraint_command != NULL) + fatal("Empty force-command option"); + if (certflags_command != NULL) fatal("force-command already specified"); - constraint_command = xstrdup(val); + certflags_command = xstrdup(val); } else if (strncasecmp(opt, "source-address=", 15) == 0) { val = opt + 15; if (*val == '\0') - fatal("Empty source-address constraint"); - if (constraint_src_addr != NULL) + fatal("Empty source-address option"); + if (certflags_src_addr != NULL) fatal("source-address already specified"); if (addr_match_cidr_list(NULL, val) != 0) fatal("Invalid source-address list"); - constraint_src_addr = xstrdup(val); + certflags_src_addr = xstrdup(val); } else - fatal("Unsupported certificate constraint \"%s\"", opt); + fatal("Unsupported certificate option \"%s\"", opt); +} + +static void +show_options(const Buffer *optbuf, int v00, int in_critical) +{ + u_char *name, *data; + u_int dlen; + Buffer options, option; + + buffer_init(&options); + buffer_append(&options, buffer_ptr(optbuf), buffer_len(optbuf)); + + buffer_init(&option); + while (buffer_len(&options) != 0) { + name = buffer_get_string(&options, NULL); + data = buffer_get_string_ptr(&options, &dlen); + buffer_append(&option, data, dlen); + printf(" %s", name); + if ((v00 || !in_critical) && + (strcmp(name, "permit-X11-forwarding") == 0 || + strcmp(name, "permit-agent-forwarding") == 0 || + strcmp(name, "permit-port-forwarding") == 0 || + strcmp(name, "permit-pty") == 0 || + strcmp(name, "permit-user-rc") == 0)) + printf("\n"); + else if ((v00 || in_critical) && + (strcmp(name, "force-command") == 0 || + strcmp(name, "source-address") == 0)) { + data = buffer_get_string(&option, NULL); + printf(" %s\n", data); + xfree(data); + } else { + printf(" UNKNOWN OPTION (len %u)\n", + buffer_len(&option)); + buffer_clear(&option); + } + xfree(name); + if (buffer_len(&option) != 0) + fatal("Option corrupt: extra data at end"); + } + buffer_free(&option); + buffer_free(&options); } static void @@ -1373,31 +1652,31 @@ do_show_cert(struct passwd *pw) Key *key; struct stat st; char *key_fp, *ca_fp; - Buffer constraints, constraint; - u_char *name, *data; - u_int i, dlen; + u_int i, v00; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); - if (stat(identity_file, &st) < 0) { - perror(identity_file); - exit(1); - } + if (stat(identity_file, &st) < 0) + fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); if ((key = key_load_public(identity_file, NULL)) == NULL) fatal("%s is not a public key", identity_file); if (!key_is_cert(key)) fatal("%s is not a certificate", identity_file); - + v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00; + key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ca_fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5, SSH_FP_HEX); printf("%s:\n", identity_file); - printf(" %s %s certificate %s\n", key_type(key), - key_cert_type(key), key_fp); - printf(" Signed by %s CA %s\n", + printf(" Type: %s %s certificate\n", key_ssh_name(key), + key_cert_type(key)); + printf(" Public key: %s %s\n", key_type(key), key_fp); + printf(" Signing CA: %s %s\n", key_type(key->cert->signature_key), ca_fp); - printf(" Key ID \"%s\"\n", key->cert->key_id); + printf(" Key ID: \"%s\"\n", key->cert->key_id); + if (!v00) + printf(" Serial: %llu\n", key->cert->serial); printf(" Valid: %s\n", fmt_validity(key->cert->valid_after, key->cert->valid_before)); printf(" Principals: "); @@ -1409,45 +1688,22 @@ do_show_cert(struct passwd *pw) key->cert->principals[i]); printf("\n"); } - printf(" Constraints: "); - if (buffer_len(&key->cert->constraints) == 0) + printf(" Critical Options: "); + if (buffer_len(&key->cert->critical) == 0) printf("(none)\n"); else { printf("\n"); - buffer_init(&constraints); - buffer_append(&constraints, - buffer_ptr(&key->cert->constraints), - buffer_len(&key->cert->constraints)); - buffer_init(&constraint); - while (buffer_len(&constraints) != 0) { - name = buffer_get_string(&constraints, NULL); - data = buffer_get_string_ptr(&constraints, &dlen); - buffer_append(&constraint, data, dlen); - printf(" %s", name); - if (strcmp(name, "permit-X11-forwarding") == 0 || - strcmp(name, "permit-agent-forwarding") == 0 || - strcmp(name, "permit-port-forwarding") == 0 || - strcmp(name, "permit-pty") == 0 || - strcmp(name, "permit-user-rc") == 0) - printf("\n"); - else if (strcmp(name, "force-command") == 0 || - strcmp(name, "source-address") == 0) { - data = buffer_get_string(&constraint, NULL); - printf(" %s\n", data); - xfree(data); - } else { - printf(" UNKNOWN CONSTRAINT (len %u)\n", - buffer_len(&constraint)); - buffer_clear(&constraint); - } - xfree(name); - if (buffer_len(&constraint) != 0) - fatal("Constraint corrupt: extra data at end"); + show_options(&key->cert->critical, v00, 1); + } + if (!v00) { + printf(" Extensions: "); + if (buffer_len(&key->cert->extensions) == 0) + printf("(none)\n"); + else { + printf("\n"); + show_options(&key->cert->extensions, v00, 0); } - buffer_free(&constraint); - buffer_free(&constraints); } - exit(0); } @@ -1464,7 +1720,7 @@ usage(void) #ifdef ENABLE_PKCS11 fprintf(stderr, " -D pkcs11 Download public key from pkcs11 token.\n"); #endif - fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n"); + fprintf(stderr, " -e Export OpenSSH to foreign format key file.\n"); fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); fprintf(stderr, " -f filename Filename of the key file.\n"); fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); @@ -1472,26 +1728,28 @@ usage(void) fprintf(stderr, " -H Hash names in known_hosts file.\n"); fprintf(stderr, " -h Generate host certificate instead of a user certificate.\n"); fprintf(stderr, " -I key_id Key identifier to include in certificate.\n"); - fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); + fprintf(stderr, " -i Import foreign format to OpenSSH key file.\n"); fprintf(stderr, " -L Print the contents of a certificate.\n"); fprintf(stderr, " -l Show fingerprint of key file.\n"); fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); - fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); + fprintf(stderr, " -m key_fmt Conversion format for -e/-i (PEM|PKCS8|RFC4716).\n"); fprintf(stderr, " -N phrase Provide new passphrase.\n"); - fprintf(stderr, " -O cnstr Specify a certificate constraint.\n"); + fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); + fprintf(stderr, " -O option Specify a certificate option.\n"); fprintf(stderr, " -P phrase Provide old passphrase.\n"); fprintf(stderr, " -p Change passphrase of private key file.\n"); fprintf(stderr, " -q Quiet.\n"); fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); fprintf(stderr, " -r hostname Print DNS resource record.\n"); - fprintf(stderr, " -s ca_key Certify keys with CA key.\n"); fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); + fprintf(stderr, " -s ca_key Certify keys with CA key.\n"); fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); fprintf(stderr, " -t type Specify type of key to create.\n"); fprintf(stderr, " -V from:to Specify certificate validity interval.\n"); fprintf(stderr, " -v Verbose.\n"); fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); fprintf(stderr, " -y Read private key file and print public key.\n"); + fprintf(stderr, " -z serial Specify a serial number.\n"); exit(1); } @@ -1503,12 +1761,12 @@ int main(int argc, char **argv) { char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; - char out_file[MAXPATHLEN], *pkcs11provider = NULL; - char *rr_hostname = NULL; + char out_file[MAXPATHLEN], *rr_hostname = NULL; Key *private, *public; struct passwd *pw; struct stat st; int opt, type, fd; + u_int maxbits; u_int32_t memory = 0, generator_wanted = 0, trials = 100; int do_gen_candidates = 0, do_screen_candidates = 0; BIGNUM *start = NULL; @@ -1540,8 +1798,8 @@ main(int argc, char **argv) exit(1); } - while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:N:n:" - "O:C:r:g:R:T:G:M:S:s:a:V:W:")) != -1) { + while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:m:N:n:" + "O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) { switch (opt) { case 'b': bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); @@ -1572,6 +1830,21 @@ main(int argc, char **argv) case 'B': print_bubblebabble = 1; break; + case 'm': + if (strcasecmp(optarg, "RFC4716") == 0 || + strcasecmp(optarg, "ssh2") == 0) { + convert_format = FMT_RFC4716; + break; + } + if (strcasecmp(optarg, "PKCS8") == 0) { + convert_format = FMT_PKCS8; + break; + } + if (strcasecmp(optarg, "PEM") == 0) { + convert_format = FMT_PEM; + break; + } + fatal("Unsupported conversion format \"%s\"", optarg); case 'n': cert_principals = optarg; break; @@ -1597,7 +1870,7 @@ main(int argc, char **argv) identity_new_passphrase = optarg; break; case 'O': - add_cert_constraint(optarg); + add_cert_option(optarg); break; case 'C': identity_comment = optarg; @@ -1608,16 +1881,16 @@ main(int argc, char **argv) case 'e': case 'x': /* export key */ - convert_to_ssh2 = 1; + convert_to = 1; break; case 'h': cert_key_type = SSH2_CERT_TYPE_HOST; - constraint_flags = 0; + certflags_flags = 0; break; case 'i': case 'X': /* import key */ - convert_from_ssh2 = 1; + convert_from = 1; break; case 'y': print_public = 1; @@ -1661,9 +1934,8 @@ main(int argc, char **argv) break; case 'M': memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); - if (errstr) { + if (errstr) fatal("Memory limit is %s: %s", errstr, optarg); - } break; case 'G': do_gen_candidates = 1; @@ -1685,6 +1957,11 @@ main(int argc, char **argv) case 'V': parse_cert_times(optarg); break; + case 'z': + cert_serial = strtonum(optarg, 0, LLONG_MAX, &errstr); + if (errstr) + fatal("Invalid serial number: %s", errstr); + break; case '?': default: usage(); @@ -1729,10 +2006,10 @@ main(int argc, char **argv) do_change_passphrase(pw); if (change_comment) do_change_comment(pw); - if (convert_to_ssh2) - do_convert_to_ssh2(pw); - if (convert_from_ssh2) - do_convert_from_ssh2(pw); + if (convert_to) + do_convert_to(pw); + if (convert_from) + do_convert_from(pw); if (print_public) do_print_public(pw); if (rr_hostname != NULL) { @@ -1759,7 +2036,7 @@ main(int argc, char **argv) } } if (pkcs11provider != NULL) - do_download(pw, pkcs11provider); + do_download(pw); if (do_gen_candidates) { FILE *out = fopen(out_file, "w"); @@ -1811,6 +2088,12 @@ main(int argc, char **argv) } if (bits == 0) bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS; + maxbits = (type == KEY_DSA) ? + OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS; + if (bits > maxbits) { + fprintf(stderr, "key bits exceeds maximum %d\n", maxbits); + exit(1); + } if (type == KEY_DSA && bits != 1024) fatal("DSA keys must be 1024 bits"); if (!quiet) @@ -1826,13 +2109,19 @@ main(int argc, char **argv) ask_filename(pw, "Enter file in which to save the key"); /* Create ~/.ssh directory if it doesn't already exist. */ - snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); - if (strstr(identity_file, dotsshdir) != NULL && - stat(dotsshdir, &st) < 0) { - if (mkdir(dotsshdir, 0700) < 0) - error("Could not create directory '%s'.", dotsshdir); - else if (!quiet) - printf("Created directory '%s'.\n", dotsshdir); + snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", + pw->pw_dir, _PATH_SSH_USER_DIR); + if (strstr(identity_file, dotsshdir) != NULL) { + if (stat(dotsshdir, &st) < 0) { + if (errno != ENOENT) { + error("Could not stat %s: %s", dotsshdir, + strerror(errno)); + } else if (mkdir(dotsshdir, 0700) < 0) { + error("Could not create directory '%s': %s", + dotsshdir, strerror(errno)); + } else if (!quiet) + printf("Created directory '%s'.\n", dotsshdir); + } } /* If the file already exists, ask the user to confirm. */ if (stat(identity_file, &st) >= 0) { diff --git a/crypto/openssh/ssh-keyscan.c b/crypto/openssh/ssh-keyscan.c index 7afe446..b6cf427 100644 --- a/crypto/openssh/ssh-keyscan.c +++ b/crypto/openssh/ssh-keyscan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keyscan.c,v 1.81 2010/01/09 23:04:13 dtucker Exp $ */ +/* $OpenBSD: ssh-keyscan.c,v 1.82 2010/06/22 04:54:30 djm Exp $ */ /* * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. * @@ -104,122 +104,6 @@ typedef struct Connection { TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */ con *fdcon; -/* - * This is just a wrapper around fgets() to make it usable. - */ - -/* Stress-test. Increase this later. */ -#define LINEBUF_SIZE 16 - -typedef struct { - char *buf; - u_int size; - int lineno; - const char *filename; - FILE *stream; - void (*errfun) (const char *,...); -} Linebuf; - -static Linebuf * -Linebuf_alloc(const char *filename, void (*errfun) (const char *,...)) -{ - Linebuf *lb; - - if (!(lb = malloc(sizeof(*lb)))) { - if (errfun) - (*errfun) ("linebuf (%s): malloc failed\n", - filename ? filename : "(stdin)"); - return (NULL); - } - if (filename) { - lb->filename = filename; - if (!(lb->stream = fopen(filename, "r"))) { - xfree(lb); - if (errfun) - (*errfun) ("%s: %s\n", filename, strerror(errno)); - return (NULL); - } - } else { - lb->filename = "(stdin)"; - lb->stream = stdin; - } - - if (!(lb->buf = malloc((lb->size = LINEBUF_SIZE)))) { - if (errfun) - (*errfun) ("linebuf (%s): malloc failed\n", lb->filename); - xfree(lb); - return (NULL); - } - lb->errfun = errfun; - lb->lineno = 0; - return (lb); -} - -static void -Linebuf_free(Linebuf * lb) -{ - fclose(lb->stream); - xfree(lb->buf); - xfree(lb); -} - -#if 0 -static void -Linebuf_restart(Linebuf * lb) -{ - clearerr(lb->stream); - rewind(lb->stream); - lb->lineno = 0; -} - -static int -Linebuf_lineno(Linebuf * lb) -{ - return (lb->lineno); -} -#endif - -static char * -Linebuf_getline(Linebuf * lb) -{ - size_t n = 0; - void *p; - - lb->lineno++; - for (;;) { - /* Read a line */ - if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) { - if (ferror(lb->stream) && lb->errfun) - (*lb->errfun)("%s: %s\n", lb->filename, - strerror(errno)); - return (NULL); - } - n = strlen(lb->buf); - - /* Return it or an error if it fits */ - if (n > 0 && lb->buf[n - 1] == '\n') { - lb->buf[n - 1] = '\0'; - return (lb->buf); - } - if (n != lb->size - 1) { - if (lb->errfun) - (*lb->errfun)("%s: skipping incomplete last line\n", - lb->filename); - return (NULL); - } - /* Double the buffer if we need more space */ - lb->size *= 2; - if ((p = realloc(lb->buf, lb->size)) == NULL) { - lb->size /= 2; - if (lb->errfun) - (*lb->errfun)("linebuf (%s): realloc failed\n", - lb->filename); - return (NULL); - } - lb->buf = p; - } -} - static int fdlim_get(int hard) { @@ -724,8 +608,10 @@ int main(int argc, char **argv) { int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO; - int opt, fopt_count = 0; - char *tname; + int opt, fopt_count = 0, j; + char *tname, *cp, line[NI_MAXHOST]; + FILE *fp; + u_long linenum; extern int optind; extern char *optarg; @@ -826,19 +712,40 @@ main(int argc, char **argv) read_wait_nfdset = howmany(maxfd, NFDBITS); read_wait = xcalloc(read_wait_nfdset, sizeof(fd_mask)); - if (fopt_count) { - Linebuf *lb; - char *line; - int j; + for (j = 0; j < fopt_count; j++) { + if (argv[j] == NULL) + fp = stdin; + else if ((fp = fopen(argv[j], "r")) == NULL) + fatal("%s: %s: %s", __progname, argv[j], + strerror(errno)); + linenum = 0; + + while (read_keyfile_line(fp, + argv[j] == NULL ? "(stdin)" : argv[j], line, sizeof(line), + &linenum) != -1) { + /* Chomp off trailing whitespace and comments */ + if ((cp = strchr(line, '#')) == NULL) + cp = line + strlen(line) - 1; + while (cp >= line) { + if (*cp == ' ' || *cp == '\t' || + *cp == '\n' || *cp == '#') + *cp-- = '\0'; + else + break; + } - for (j = 0; j < fopt_count; j++) { - lb = Linebuf_alloc(argv[j], error); - if (!lb) + /* Skip empty lines */ + if (*line == '\0') continue; - while ((line = Linebuf_getline(lb)) != NULL) - do_host(line); - Linebuf_free(lb); + + do_host(line); } + + if (ferror(fp)) + fatal("%s: %s: %s", __progname, argv[j], + strerror(errno)); + + fclose(fp); } while (optind < argc) diff --git a/crypto/openssh/ssh-keysign.8 b/crypto/openssh/ssh-keysign.8 index 40aaca2..abee1ea 100644 --- a/crypto/openssh/ssh-keysign.8 +++ b/crypto/openssh/ssh-keysign.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keysign.8,v 1.9 2007/05/31 19:20:16 jmc Exp $ +.\" $OpenBSD: ssh-keysign.8,v 1.10 2010/08/04 05:42:47 djm Exp $ .\" .\" Copyright (c) 2002 Markus Friedl. All rights reserved. .\" @@ -22,7 +22,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd May 31, 2007 +.Dd August 4, 2010 .Dt SSH-KEYSIGN 8 .Os .Sh NAME @@ -68,6 +68,9 @@ accessible to others. Since they are readable only by root, .Nm must be set-uid root if host-based authentication is used. +.It Pa /etc/ssh/ssh_host_dsa_key-cert.pub, /etc/ssh/ssh_host_rsa_key-cert.pub +If these files exist they are assumed to contain public certificate +information corresponding with the private keys above. .El .Sh SEE ALSO .Xr ssh 1 , diff --git a/crypto/openssh/ssh-keysign.c b/crypto/openssh/ssh-keysign.c index 0fdcebb..0c70770 100644 --- a/crypto/openssh/ssh-keysign.c +++ b/crypto/openssh/ssh-keysign.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keysign.c,v 1.30 2010/01/13 01:20:20 dtucker Exp $ */ +/* $OpenBSD: ssh-keysign.c,v 1.32 2010/08/04 06:08:40 djm Exp $ */ /* * Copyright (c) 2002 Markus Friedl. All rights reserved. * @@ -232,7 +232,7 @@ main(int argc, char **argv) found = 0; for (i = 0; i < 2; i++) { if (keys[i] != NULL && - key_equal(key, keys[i])) { + key_equal_public(key, keys[i])) { found = 1; break; } diff --git a/crypto/openssh/ssh-pkcs11.c b/crypto/openssh/ssh-pkcs11.c index f0192dc..286c232 100644 --- a/crypto/openssh/ssh-pkcs11.c +++ b/crypto/openssh/ssh-pkcs11.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11.c,v 1.4 2010/02/24 06:12:53 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11.c,v 1.6 2010/06/08 21:32:19 markus Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * @@ -187,6 +187,34 @@ pkcs11_rsa_finish(RSA *rsa) return (rv); } +/* find a single 'obj' for given attributes */ +static int +pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr, + CK_ULONG nattr, CK_OBJECT_HANDLE *obj) +{ + CK_FUNCTION_LIST *f; + CK_SESSION_HANDLE session; + CK_ULONG nfound = 0; + CK_RV rv; + int ret = -1; + + f = p->function_list; + session = p->slotinfo[slotidx].session; + if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) { + error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv); + return (-1); + } + if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK || + nfound != 1) { + debug("C_FindObjects failed (nfound %lu nattr %lu): %lu", + nfound, nattr, rv); + } else + ret = 0; + if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK) + error("C_FindObjectsFinal failed: %lu", rv); + return (ret); +} + /* openssl callback doing the actual signing operation */ static int pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, @@ -196,7 +224,7 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, struct pkcs11_slotinfo *si; CK_FUNCTION_LIST *f; CK_OBJECT_HANDLE obj; - CK_ULONG tlen = 0, nfound = 0; + CK_ULONG tlen = 0; CK_RV rv; CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY; CK_BBOOL true_val = CK_TRUE; @@ -247,13 +275,10 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, } key_filter[1].pValue = k11->keyid; key_filter[1].ulValueLen = k11->keyid_len; - if ((rv = f->C_FindObjectsInit(si->session, key_filter, 3)) != CKR_OK) { - error("C_FindObjectsInit failed: %lu", rv); - return (-1); - } - if ((rv = f->C_FindObjects(si->session, &obj, 1, &nfound)) != CKR_OK || - nfound != 1) { - error("C_FindObjects failed (%lu nfound): %lu", nfound, rv); + /* try to find object w/CKA_SIGN first, retry w/o */ + if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 && + pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) { + error("cannot find private key"); } else if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) { error("C_SignInit failed: %lu", rv); } else { @@ -265,8 +290,6 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, else error("C_Sign failed: %lu", rv); } - if ((rv = f->C_FindObjectsFinal(si->session)) != CKR_OK) - error("C_FindObjectsFinal failed: %lu", rv); return (rval); } @@ -410,7 +433,13 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp, error("C_GetAttributeValue failed: %lu", rv); continue; } - /* allocate buffers for attributes, XXX check ulValueLen? */ + /* check that none of the attributes are zero length */ + if (attribs[0].ulValueLen == 0 || + attribs[1].ulValueLen == 0 || + attribs[2].ulValueLen == 0) { + continue; + } + /* allocate buffers for attributes */ for (i = 0; i < 3; i++) attribs[i].pValue = xmalloc(attribs[i].ulValueLen); /* retrieve ID, modulus and public exponent of RSA key */ diff --git a/crypto/openssh/ssh-rsa.c b/crypto/openssh/ssh-rsa.c index 842857f..c471ff3 100644 --- a/crypto/openssh/ssh-rsa.c +++ b/crypto/openssh/ssh-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-rsa.c,v 1.40 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: ssh-rsa.c,v 1.44 2010/07/16 14:07:35 djm Exp $ */ /* * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> * @@ -30,6 +30,7 @@ #include "buffer.h" #include "key.h" #include "compat.h" +#include "misc.h" #include "ssh.h" static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); @@ -46,9 +47,8 @@ ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, int ok, nid; Buffer b; - if (key == NULL || - (key->type != KEY_RSA && key->type != KEY_RSA_CERT) || - key->rsa == NULL) { + if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA && + key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) { error("ssh_rsa_sign: no RSA key"); return -1; } @@ -115,9 +115,8 @@ ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, u_int len, dlen, modlen; int rlen, ret, nid; - if (key == NULL || - (key->type != KEY_RSA && key->type != KEY_RSA_CERT) || - key->rsa == NULL) { + if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA && + key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) { error("ssh_rsa_verify: no RSA key"); return -1; } @@ -212,7 +211,7 @@ openssh_RSA_verify(int type, u_char *hash, u_int hashlen, u_char *sigbuf, u_int siglen, RSA *rsa) { u_int ret, rsasize, oidlen = 0, hlen = 0; - int len; + int len, oidmatch, hashmatch; const u_char *oid = NULL; u_char *decrypted = NULL; @@ -251,11 +250,13 @@ openssh_RSA_verify(int type, u_char *hash, u_int hashlen, error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); goto done; } - if (memcmp(decrypted, oid, oidlen) != 0) { + oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; + hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; + if (!oidmatch) { error("oid mismatch"); goto done; } - if (memcmp(decrypted + oidlen, hash, hlen) != 0) { + if (!hashmatch) { error("hash mismatch"); goto done; } diff --git a/crypto/openssh/ssh.1 b/crypto/openssh/ssh.1 index 33cbc99..d5cd60c 100644 --- a/crypto/openssh/ssh.1 +++ b/crypto/openssh/ssh.1 @@ -34,9 +34,9 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.303 2010/03/26 00:26:58 djm Exp $ +.\" $OpenBSD: ssh.1,v 1.308 2010/08/04 05:37:01 djm Exp $ .\" $FreeBSD$ -.Dd March 26, 2010 +.Dd August 4 2010 .Dt SSH 1 .Os .Sh NAME @@ -44,46 +44,28 @@ .Nd OpenSSH SSH client (remote login program) .Sh SYNOPSIS .Nm ssh +.Bk -words .Op Fl 1246AaCfgKkMNnqsTtVvXxYy .Op Fl b Ar bind_address .Op Fl c Ar cipher_spec -.Oo Fl D\ \& -.Sm off -.Oo Ar bind_address : Oc -.Ar port -.Sm on -.Oc +.Op Fl D Oo Ar bind_address : Oc Ns Ar port .Op Fl e Ar escape_char .Op Fl F Ar configfile .Op Fl I Ar pkcs11 -.Bk -words .Op Fl i Ar identity_file -.Ek -.Oo Fl L\ \& -.Sm off -.Oo Ar bind_address : Oc -.Ar port : host : hostport -.Sm on -.Oc -.Bk -words +.Op Fl L Oo Ar bind_address : Oc Ns Ar port : Ns Ar host : Ns Ar hostport .Op Fl l Ar login_name -.Ek .Op Fl m Ar mac_spec .Op Fl O Ar ctl_cmd .Op Fl o Ar option .Op Fl p Ar port -.Oo Fl R\ \& -.Sm off -.Oo Ar bind_address : Oc -.Ar port : host : hostport -.Sm on -.Oc +.Op Fl R Oo Ar bind_address : Oc Ns Ar port : Ns Ar host : Ns Ar hostport .Op Fl S Ar ctl_path .Op Fl W Ar host : Ns Ar port -.Oo Fl w Ar local_tun Ns -.Op : Ns Ar remote_tun Oc +.Op Fl w Ar local_tun Ns Op : Ns Ar remote_tun .Oo Ar user Ns @ Oc Ns Ar hostname .Op Ar command +.Ek .Sh DESCRIPTION .Nm (SSH client) is a program for logging into a remote machine and for @@ -195,7 +177,9 @@ is a comma-separated list of ciphers listed in order of preference. See the .Cm Ciphers -keyword for more information. +keyword in +.Xr ssh_config 5 +for more information. .It Fl D Xo .Sm off .Oo Ar bind_address : Oc @@ -219,14 +203,7 @@ will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be specified in the configuration file. .Pp -IPv6 addresses can be specified with an alternative syntax: -.Sm off -.Xo -.Op Ar bind_address No / -.Ar port -.Xc -.Sm on -or by enclosing the address in square brackets. +IPv6 addresses can be specified by enclosing the address in square brackets. Only the superuser can forward privileged ports. By default, the local port is bound in accordance with the .Cm GatewayPorts @@ -337,15 +314,7 @@ port .Ar hostport from the remote machine. Port forwardings can also be specified in the configuration file. -IPv6 addresses can be specified with an alternative syntax: -.Sm off -.Xo -.Op Ar bind_address No / -.Ar port No / Ar host No / -.Ar hostport -.Xc -.Sm on -or by enclosing the address in square brackets. +IPv6 addresses can be specified by enclosing the address in square brackets. Only the superuser can forward privileged ports. By default, the local port is bound in accordance with the .Cm GatewayPorts @@ -422,7 +391,9 @@ option is specified, the argument is interpreted and passed to the master process. Valid commands are: .Dq check -(check that the master process is running) and +(check that the master process is running), +.Dq forward +(request forwardings without command execution) and .Dq exit (request the master to exit). .It Fl o Ar option @@ -527,15 +498,7 @@ from the local machine. Port forwardings can also be specified in the configuration file. Privileged ports can be forwarded only when logging in as root on the remote machine. -IPv6 addresses can be specified by enclosing the address in square braces or -using an alternative syntax: -.Sm off -.Xo -.Op Ar bind_address No / -.Ar host No / Ar port No / -.Ar hostport -.Xc . -.Sm on +IPv6 addresses can be specified by enclosing the address in square braces. .Pp By default, the listening socket on the server will be bound to the loopback interface only. @@ -559,8 +522,11 @@ argument is .Ql 0 , the listen port will be dynamically allocated on the server and reported to the client at run time. +When used together with +.Ic -O forward +the allocated port will be printed to the standard output. .It Fl S Ar ctl_path -Specifies the location of a control socket for connection sharing +Specifies the location of a control socket for connection sharing, or the string .Dq none to disable connection sharing. diff --git a/crypto/openssh/ssh.c b/crypto/openssh/ssh.c index 884d7e9..11eac21 100644 --- a/crypto/openssh/ssh.c +++ b/crypto/openssh/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.335 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.346 2010/08/12 21:49:44 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -80,6 +80,7 @@ __RCSID("$FreeBSD$"); #include "ssh.h" #include "ssh1.h" #include "ssh2.h" +#include "canohost.h" #include "compat.h" #include "cipher.h" #include "packet.h" @@ -128,6 +129,15 @@ int no_shell_flag = 0; int stdin_null_flag = 0; /* + * Flag indicating that the current process should be backgrounded and + * a new slave launched in the foreground for ControlPersist. + */ +int need_controlpersist_detach = 0; + +/* Copies of flags for ControlPersist foreground slave */ +int ostdin_null_flag, ono_shell_flag, ono_tty_flag, otty_flag; + +/* * Flag indicating that ssh should fork after authentication. This is useful * so that the passphrase can be entered manually, and then ssh goes to the * background. @@ -229,6 +239,12 @@ main(int ac, char **av) init_rng(); /* + * Discard other fds that are hanging around. These can cause problem + * with backgrounded ssh processes started by ControlPersist. + */ + closefrom(STDERR_FILENO + 1); + + /* * Save the original real uid. It will be needed later (uid-swapping * may clobber the real uid). */ @@ -328,6 +344,8 @@ main(int ac, char **av) fatal("Multiplexing command already specified"); if (strcmp(optarg, "check") == 0) muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK; + else if (strcmp(optarg, "forward") == 0) + muxclient_command = SSHMUX_COMMAND_FORWARD; else if (strcmp(optarg, "exit") == 0) muxclient_command = SSHMUX_COMMAND_TERMINATE; else @@ -621,7 +639,7 @@ main(int ac, char **av) tty_flag = 1; /* Force no tty */ - if (no_tty_flag) + if (no_tty_flag || muxclient_command != 0) tty_flag = 0; /* Do not allocate a tty if stdin is not a tty. */ if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) { @@ -677,6 +695,11 @@ main(int ac, char **av) options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; } + if (options.hostname != NULL) { + host = percent_expand(options.hostname, + "h", host, (char *)NULL); + } + if (options.local_command != NULL) { char thishost[NI_MAXHOST]; @@ -686,16 +709,12 @@ main(int ac, char **av) debug3("expanding LocalCommand: %s", options.local_command); cp = options.local_command; options.local_command = percent_expand(cp, "d", pw->pw_dir, - "h", options.hostname? options.hostname : host, - "l", thishost, "n", host, "r", options.user, "p", buf, - "u", pw->pw_name, (char *)NULL); + "h", host, "l", thishost, "n", host, "r", options.user, + "p", buf, "u", pw->pw_name, (char *)NULL); debug3("expanded LocalCommand: %s", options.local_command); xfree(cp); } - if (options.hostname != NULL) - host = options.hostname; - /* Find canonic host name. */ if (strchr(host, '.') == 0) { struct addrinfo hints; @@ -779,26 +798,34 @@ main(int ac, char **av) sensitive_data.external_keysign = 0; if (options.rhosts_rsa_authentication || options.hostbased_authentication) { - sensitive_data.nkeys = 3; + sensitive_data.nkeys = 5; sensitive_data.keys = xcalloc(sensitive_data.nkeys, sizeof(Key)); PRIV_START; sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, _PATH_HOST_KEY_FILE, "", NULL, NULL); - sensitive_data.keys[1] = key_load_private_type(KEY_DSA, + sensitive_data.keys[1] = key_load_private_cert(KEY_DSA, + _PATH_HOST_DSA_KEY_FILE, "", NULL); + sensitive_data.keys[2] = key_load_private_cert(KEY_RSA, + _PATH_HOST_RSA_KEY_FILE, "", NULL); + sensitive_data.keys[3] = key_load_private_type(KEY_DSA, _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); - sensitive_data.keys[2] = key_load_private_type(KEY_RSA, + sensitive_data.keys[4] = key_load_private_type(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); PRIV_END; if (options.hostbased_authentication == 1 && sensitive_data.keys[0] == NULL && - sensitive_data.keys[1] == NULL && - sensitive_data.keys[2] == NULL) { - sensitive_data.keys[1] = key_load_public( + sensitive_data.keys[3] == NULL && + sensitive_data.keys[4] == NULL) { + sensitive_data.keys[1] = key_load_cert( + _PATH_HOST_DSA_KEY_FILE); + sensitive_data.keys[2] = key_load_cert( + _PATH_HOST_RSA_KEY_FILE); + sensitive_data.keys[3] = key_load_public( _PATH_HOST_DSA_KEY_FILE, NULL); - sensitive_data.keys[2] = key_load_public( + sensitive_data.keys[4] = key_load_public( _PATH_HOST_RSA_KEY_FILE, NULL); sensitive_data.external_keysign = 1; } @@ -845,6 +872,13 @@ main(int ac, char **av) ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw, timeout_ms); + if (packet_connection_is_on_socket()) { + verbose("Authenticated to %s ([%s]:%d).", host, + get_remote_ipaddr(), get_remote_port()); + } else { + verbose("Authenticated to %s (via proxy).", host); + } + /* We no longer need the private host keys. Clear them now. */ if (sensitive_data.nkeys != 0) { for (i = 0; i < sensitive_data.nkeys; i++) { @@ -884,6 +918,61 @@ main(int ac, char **av) return exit_status; } +static void +control_persist_detach(void) +{ + pid_t pid; + int devnull; + + debug("%s: backgrounding master process", __func__); + + /* + * master (current process) into the background, and make the + * foreground process a client of the backgrounded master. + */ + switch ((pid = fork())) { + case -1: + fatal("%s: fork: %s", __func__, strerror(errno)); + case 0: + /* Child: master process continues mainloop */ + break; + default: + /* Parent: set up mux slave to connect to backgrounded master */ + debug2("%s: background process is %ld", __func__, (long)pid); + stdin_null_flag = ostdin_null_flag; + no_shell_flag = ono_shell_flag; + no_tty_flag = ono_tty_flag; + tty_flag = otty_flag; + close(muxserver_sock); + muxserver_sock = -1; + muxclient(options.control_path); + /* muxclient() doesn't return on success. */ + fatal("Failed to connect to new control master"); + } + if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { + error("%s: open(\"/dev/null\"): %s", __func__, + strerror(errno)); + } else { + if (dup2(devnull, STDIN_FILENO) == -1 || + dup2(devnull, STDOUT_FILENO) == -1) + error("%s: dup2: %s", __func__, strerror(errno)); + if (devnull > STDERR_FILENO) + close(devnull); + } +} + +/* Do fork() after authentication. Used by "ssh -f" */ +static void +fork_postauth(void) +{ + if (need_controlpersist_detach) + control_persist_detach(); + debug("forking to background"); + fork_after_authentication_flag = 0; + if (daemon(1, 1) < 0) + fatal("daemon() failed: %.200s", strerror(errno)); +} + /* Callback for remote forward global requests */ static void ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) @@ -895,9 +984,10 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); if (type == SSH2_MSG_REQUEST_SUCCESS && rfwd->listen_port == 0) { + rfwd->allocated_port = packet_get_int(); logit("Allocated port %u for remote forward to %s:%d", - packet_get_int(), - rfwd->connect_host, rfwd->connect_port); + rfwd->allocated_port, + rfwd->connect_host, rfwd->connect_port); } if (type == SSH2_MSG_REQUEST_FAILURE) { @@ -910,12 +1000,8 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) } if (++remote_forward_confirms_received == options.num_remote_forwards) { debug("All remote forwarding requests processed"); - if (fork_after_authentication_flag) { - fork_after_authentication_flag = 0; - if (daemon(1, 1) < 0) - fatal("daemon() failed: %.200s", - strerror(errno)); - } + if (fork_after_authentication_flag) + fork_postauth(); } } @@ -1111,7 +1197,9 @@ ssh_session(void) char *proto, *data; /* Get reasonable local authentication information. */ client_x11_get_proto(display, options.xauth_location, - options.forward_x11_trusted, &proto, &data); + options.forward_x11_trusted, + options.forward_x11_timeout, + &proto, &data); /* Request forwarding with authentication spoofing. */ debug("Requesting X11 forwarding with authentication " "spoofing."); @@ -1157,12 +1245,13 @@ ssh_session(void) * If requested and we are not interested in replies to remote * forwarding requests, then let ssh continue in the background. */ - if (fork_after_authentication_flag && - (!options.exit_on_forward_failure || - options.num_remote_forwards == 0)) { - fork_after_authentication_flag = 0; - if (daemon(1, 1) < 0) - fatal("daemon() failed: %.200s", strerror(errno)); + if (fork_after_authentication_flag) { + if (options.exit_on_forward_failure && + options.num_remote_forwards > 0) { + debug("deferring postauth fork until remote forward " + "confirmation received"); + } else + fork_postauth(); } /* @@ -1193,18 +1282,22 @@ ssh_session(void) /* request pty/x11/agent/tcpfwd/shell for channel */ static void -ssh_session2_setup(int id, void *arg) +ssh_session2_setup(int id, int success, void *arg) { extern char **environ; const char *display; int interactive = tty_flag; + if (!success) + return; /* No need for error message, channels code sens one */ + display = getenv("DISPLAY"); if (options.forward_x11 && display != NULL) { char *proto, *data; /* Get reasonable local authentication information. */ client_x11_get_proto(display, options.xauth_location, - options.forward_x11_trusted, &proto, &data); + options.forward_x11_trusted, + options.forward_x11_timeout, &proto, &data); /* Request forwarding with authentication spoofing. */ debug("Requesting X11 forwarding with authentication " "spoofing."); @@ -1281,6 +1374,31 @@ ssh_session2(void) /* XXX should be pre-session */ ssh_init_forwarding(); + /* Start listening for multiplex clients */ + muxserver_listen(); + + /* + * If we are in control persist mode, then prepare to background + * ourselves and have a foreground client attach as a control + * slave. NB. we must save copies of the flags that we override for + * the backgrounding, since we defer attachment of the slave until + * after the connection is fully established (in particular, + * async rfwd replies have been received for ExitOnForwardFailure). + */ + if (options.control_persist && muxserver_sock != -1) { + ostdin_null_flag = stdin_null_flag; + ono_shell_flag = no_shell_flag; + ono_tty_flag = no_tty_flag; + otty_flag = tty_flag; + stdin_null_flag = 1; + no_shell_flag = 1; + no_tty_flag = 1; + tty_flag = 0; + if (!fork_after_authentication_flag) + need_controlpersist_detach = 1; + fork_after_authentication_flag = 1; + } + if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) id = ssh_session2_open(); @@ -1299,14 +1417,17 @@ ssh_session2(void) options.permit_local_command) ssh_local_cmd(options.local_command); - /* Start listening for multiplex clients */ - muxserver_listen(); - - /* If requested, let ssh continue in the background. */ + /* + * If requested and we are not interested in replies to remote + * forwarding requests, then let ssh continue in the background. + */ if (fork_after_authentication_flag) { - fork_after_authentication_flag = 0; - if (daemon(1, 1) < 0) - fatal("daemon() failed: %.200s", strerror(errno)); + if (options.exit_on_forward_failure && + options.num_remote_forwards > 0) { + debug("deferring postauth fork until remote forward " + "confirmation received"); + } else + fork_postauth(); } if (options.use_roaming) diff --git a/crypto/openssh/ssh.h b/crypto/openssh/ssh.h index 186cfff..c94633b 100644 --- a/crypto/openssh/ssh.h +++ b/crypto/openssh/ssh.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.h,v 1.78 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: ssh.h,v 1.79 2010/06/25 07:14:46 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -18,9 +18,6 @@ /* Default port number. */ #define SSH_DEFAULT_PORT 22 -/* Maximum number of TCP/IP ports forwarded per direction. */ -#define SSH_MAX_FORWARDS_PER_DIRECTION 100 - /* * Maximum number of RSA authentication identity files that can be specified * in configuration files or on the command line. diff --git a/crypto/openssh/ssh_config b/crypto/openssh/ssh_config index 3bda1b9..e0c7f69 100644 --- a/crypto/openssh/ssh_config +++ b/crypto/openssh/ssh_config @@ -46,4 +46,4 @@ # PermitLocalCommand no # VisualHostKey no # ProxyCommand ssh -q -W %h:%p gateway.example.com -# VersionAddendum FreeBSD-20100428 +# VersionAddendum FreeBSD-20101111 diff --git a/crypto/openssh/ssh_config.5 b/crypto/openssh/ssh_config.5 index ec6cd56..e36e574 100644 --- a/crypto/openssh/ssh_config.5 +++ b/crypto/openssh/ssh_config.5 @@ -34,9 +34,9 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.130 2010/03/26 01:06:13 dtucker Exp $ +.\" $OpenBSD: ssh_config.5,v 1.138 2010/08/04 05:37:01 djm Exp $ .\" $FreeBSD$ -.Dd March 26, 2010 +.Dd August 4, 2010 .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -320,6 +320,28 @@ It is recommended that any used for opportunistic connection sharing include at least %h, %p, and %r. This ensures that shared connections are uniquely identified. +.It Cm ControlPersist +When used in conjunction with +.Cm ControlMaster , +specifies that the master connection should remain open +in the background (waiting for future client connections) +after the initial client connection has been closed. +If set to +.Dq no , +then the master connection will not be placed into the background, +and will close as soon as the initial client connection is closed. +If set to +.Dq yes , +then the master connection will remain in the background indefinitely +(until killed or closed via a mechanism such as the +.Xr ssh 1 +.Dq Fl O No exit +option). +If set to a time in seconds, or a time in any of the formats documented in +.Xr sshd_config 5 , +then the backgrounded master connection will automatically terminate +after it has remained idle (with no client connections) for the +specified time. .It Cm DynamicForward Specifies that a TCP port on the local machine be forwarded over the secure channel, and the application @@ -330,9 +352,7 @@ The argument must be .Sm off .Oo Ar bind_address : Oc Ar port . .Sm on -IPv6 addresses can be specified by enclosing addresses in square brackets or -by using an alternative syntax: -.Oo Ar bind_address Ns / Oc Ns Ar port . +IPv6 addresses can be specified by enclosing addresses in square brackets. By default, the local port is bound in accordance with the .Cm GatewayPorts setting. @@ -433,6 +453,17 @@ An attacker may then be able to perform activities such as keystroke monitoring if the .Cm ForwardX11Trusted option is also enabled. +.It Cm ForwardX11Timeout +Specify a timeout for untrusted X11 forwarding +using the format described in the +.Sx TIME FORMATS +section of +.Xr sshd_config 5 . +X11 connections received by +.Xr ssh 1 +after this time will be refused. +The default is to disable untrusted X11 forwarding after twenty minutes has +elapsed. .It Cm ForwardX11Trusted If this option is set to .Dq yes , @@ -527,6 +558,10 @@ or for multiple servers running on a single host. .It Cm HostName Specifies the real host name to log into. This can be used to specify nicknames or abbreviations for hosts. +If the hostname contains the character sequence +.Ql %h , +then this will be replaced with the host name specified on the commandline +(this is useful for manipulating unqualified names). The default is the name given on the command line. Numeric IP addresses are also permitted (both on the command line and in .Cm HostName @@ -642,11 +677,7 @@ The first argument must be .Sm on and the second argument must be .Ar host : Ns Ar hostport . -IPv6 addresses can be specified by enclosing addresses in square brackets or -by using an alternative syntax: -.Oo Ar bind_address Ns / Oc Ns Ar port -and -.Ar host Ns / Ns Ar hostport . +IPv6 addresses can be specified by enclosing addresses in square brackets. Multiple forwardings may be specified, and additional forwardings can be given on the command line. Only the superuser can forward privileged ports. @@ -733,10 +764,12 @@ authentication methods. This allows a client to prefer one method (e.g.\& .Cm keyboard-interactive ) over another method (e.g.\& -.Cm password ) -The default for this option is: -.Do gssapi-with-mic,hostbased,publickey,keyboard-interactive,password -.Dc . +.Cm password ) . +The default is: +.Bd -literal -offset indent +gssapi-with-mic,hostbased,publickey, +keyboard-interactive,password +.Ed .It Cm Protocol Specifies the protocol versions .Xr ssh 1 @@ -758,12 +791,14 @@ Specifies the command to use to connect to the server. The command string extends to the end of the line, and is executed with the user's shell. -In the command string, +In the command string, any occurrence of .Ql %h will be substituted by the host name to -connect and +connect, .Ql %p -by the port. +by the port, and +.Ql %r +by the remote user name. The command can be basically anything, and should read from its standard input and write to its standard output. It should eventually connect an @@ -822,11 +857,7 @@ The first argument must be .Sm on and the second argument must be .Ar host : Ns Ar hostport . -IPv6 addresses can be specified by enclosing addresses in square brackets -or by using an alternative syntax: -.Oo Ar bind_address Ns / Oc Ns Ar port -and -.Ar host Ns / Ns Ar hostport . +IPv6 addresses can be specified by enclosing addresses in square brackets. Multiple forwardings may be specified, and additional forwardings can be given on the command line. Privileged ports can be forwarded only when @@ -1083,7 +1114,7 @@ in Specifies a string to append to the regular version string to identify OS- or site-specific modifications. The default is -.Dq FreeBSD-20100428 . +.Dq FreeBSD-20101111 . .It Cm VisualHostKey If this flag is set to .Dq yes , diff --git a/crypto/openssh/sshconnect.c b/crypto/openssh/sshconnect.c index a54d942..f84d5bb 100644 --- a/crypto/openssh/sshconnect.c +++ b/crypto/openssh/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.220 2010/03/04 10:36:03 djm Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.224 2010/04/16 21:14:27 djm Exp $ */ /* $FreeBSD$ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -102,8 +102,8 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) * (e.g. Solaris) */ xasprintf(&tmp, "exec %s", proxy_command); - command_string = percent_expand(tmp, "h", host, - "p", strport, (char *)NULL); + command_string = percent_expand(tmp, "h", host, "p", strport, + "r", options.user, (char *)NULL); xfree(tmp); /* Create pipes for communicating with the proxy. */ @@ -587,9 +587,9 @@ check_host_cert(const char *host, const Key *host_key) error("%s", reason); return 0; } - if (buffer_len(&host_key->cert->constraints) != 0) { - error("Certificate for %s contains unsupported constraint(s)", - host); + if (buffer_len(&host_key->cert->critical) != 0) { + error("Certificate for %s contains unsupported " + "critical options(s)", host); return 0; } return 1; @@ -740,7 +740,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, debug("Host '%.200s' is known and matches the %s host %s.", host, type, want_cert ? "certificate" : "key"); debug("Found %s in %s:%d", - want_cert ? "certificate" : "key", host_file, host_line); + want_cert ? "CA key" : "key", host_file, host_line); if (want_cert && !check_host_cert(hostname, host_key)) goto fail; if (options.check_host_ip && ip_status == HOST_NEW) { diff --git a/crypto/openssh/sshconnect2.c b/crypto/openssh/sshconnect2.c index 2a5943e..4c379ae 100644 --- a/crypto/openssh/sshconnect2.c +++ b/crypto/openssh/sshconnect2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect2.c,v 1.180 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: sshconnect2.c,v 1.183 2010/04/26 22:28:24 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved. @@ -195,7 +195,7 @@ struct Authctxt { const char *host; const char *service; Authmethod *method; - int success; + sig_atomic_t success; char *authlist; /* pubkey */ Idlist keys; @@ -1140,8 +1140,11 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) u_int skip = 0; int ret = -1; int have_sig = 1; + char *fp; - debug3("sign_and_send_pubkey"); + fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); + debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); + xfree(fp); if (key_to_blob(id->key, &blob, &bloblen) == 0) { /* we cannot handle this key */ @@ -1398,7 +1401,8 @@ userauth_pubkey(Authctxt *authctxt) * private key instead */ if (id->key && id->key->type != KEY_RSA1) { - debug("Offering public key: %s", id->filename); + debug("Offering %s public key: %s", key_type(id->key), + id->filename); sent = send_pubkey_test(authctxt, id); } else if (id->key == NULL) { debug("Trying private key: %s", id->filename); diff --git a/crypto/openssh/sshd.8 b/crypto/openssh/sshd.8 index 96bb26e..17909b8 100644 --- a/crypto/openssh/sshd.8 +++ b/crypto/openssh/sshd.8 @@ -34,9 +34,9 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd.8,v 1.255 2010/03/05 06:50:35 jmc Exp $ +.\" $OpenBSD: sshd.8,v 1.257 2010/08/04 05:37:01 djm Exp $ .\" $FreeBSD$ -.Dd March 5, 2010 +.Dd August 4, 2010 .Dt SSHD 8 .Os .Sh NAME @@ -598,13 +598,23 @@ Limit local .Li ``ssh -L'' port forwarding such that it may only connect to the specified host and port. -IPv6 addresses can be specified with an alternative syntax: -.Ar host Ns / Ns Ar port . +IPv6 addresses can be specified by enclosing the address in square brackets. Multiple .Cm permitopen options may be applied separated by commas. No pattern matching is performed on the specified hostnames, they must be literal domains or addresses. +.It Cm principals="principals" +On a +.Cm cert-authority +line, specifies allowed principals for certificate authentication as a +comma-separated list. +At least one name from the list must appear in the certificate's +list of principals for the certificate to be accepted. +This option is ignored for keys that are not marked as trusted certificate +signers using the +.Cm cert-authority +option. .It Cm tunnel="n" Force a .Xr tun 4 diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c index 5bd7cd4..d3f5bb8 100644 --- a/crypto/openssh/sshd.c +++ b/crypto/openssh/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.374 2010/03/07 11:57:13 dtucker Exp $ */ +/* $OpenBSD: sshd.c,v 1.375 2010/04/16 01:47:26 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -755,6 +755,8 @@ list_hostkey_types(void) if (key == NULL) continue; switch (key->type) { + case KEY_RSA_CERT_V00: + case KEY_DSA_CERT_V00: case KEY_RSA_CERT: case KEY_DSA_CERT: if (buffer_len(&b) > 0) @@ -778,10 +780,17 @@ get_hostkey_by_type(int type, int need_private) Key *key; for (i = 0; i < options.num_host_key_files; i++) { - if (type == KEY_RSA_CERT || type == KEY_DSA_CERT) + switch (type) { + case KEY_RSA_CERT_V00: + case KEY_DSA_CERT_V00: + case KEY_RSA_CERT: + case KEY_DSA_CERT: key = sensitive_data.host_certificates[i]; - else + break; + default: key = sensitive_data.host_keys[i]; + break; + } if (key != NULL && key->type == type) return need_private ? sensitive_data.host_keys[i] : key; diff --git a/crypto/openssh/sshd_config b/crypto/openssh/sshd_config index 3c700f0..bb8d24bc 100644 --- a/crypto/openssh/sshd_config +++ b/crypto/openssh/sshd_config @@ -14,7 +14,7 @@ # Note that some of FreeBSD's defaults differ from OpenBSD's, and # FreeBSD has a few additional options. -#VersionAddendum FreeBSD-20100428 +#VersionAddendum FreeBSD-20101111 #Port 22 #AddressFamily any diff --git a/crypto/openssh/sshd_config.5 b/crypto/openssh/sshd_config.5 index 4e918c4..cea5297 100644 --- a/crypto/openssh/sshd_config.5 +++ b/crypto/openssh/sshd_config.5 @@ -34,9 +34,9 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.120 2010/03/04 23:17:25 djm Exp $ +.\" $OpenBSD: sshd_config.5,v 1.125 2010/06/30 07:28:34 jmc Exp $ .\" $FreeBSD$ -.Dd March 4, 2010 +.Dd June 30, 2010 .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -156,6 +156,10 @@ for more information on patterns. .It Cm AuthorizedKeysFile Specifies the file that contains the public keys that can be used for user authentication. +The format is described in the +.Sx AUTHORIZED_KEYS FILE FORMAT +section of +.Xr sshd 8 . .Cm AuthorizedKeysFile may contain tokens of the form %T which are substituted during connection setup. @@ -168,6 +172,47 @@ is taken to be an absolute path or one relative to the user's home directory. The default is .Dq .ssh/authorized_keys . +.It Cm AuthorizedPrincipalsFile +Specifies a file that lists principal names that are accepted for +certificate authentication. +When using certificates signed by a key listed in +.Cm TrustedUserCAKeys , +this file lists names, one of which must appear in the certificate for it +to be accepted for authentication. +Names are listed one per line preceded by key options (as described +in +.Sx AUTHORIZED_KEYS FILE FORMAT +in +.Xr sshd 8 ) . +Empty lines and comments starting with +.Ql # +are ignored. +.Pp +.Cm AuthorizedPrincipalsFile +may contain tokens of the form %T which are substituted during connection +setup. +The following tokens are defined: %% is replaced by a literal '%', +%h is replaced by the home directory of the user being authenticated, and +%u is replaced by the username of that user. +After expansion, +.Cm AuthorizedPrincipalsFile +is taken to be an absolute path or one relative to the user's home +directory. +.Pp +The default is not to use a principals file \(en in this case, the username +of the user must appear in a certificate's principals list for it to be +accepted. +Note that +.Cm AuthorizedPrincipalsFile +is only used when authentication proceeds using a CA listed in +.Cm TrustedUserCAKeys +and is not consulted for certification authorities trusted via +.Pa ~/.ssh/authorized_keys , +though the +.Cm principals= +key option offers a similar facility (see +.Xr sshd 8 +for details). .It Cm Banner The contents of the specified file are sent to the remote user before authentication is allowed. @@ -609,12 +654,15 @@ keyword. Available keywords are .Cm AllowAgentForwarding , .Cm AllowTcpForwarding , +.Cm AuthorizedKeysFile , +.Cm AuthorizedPrincipalsFile , .Cm Banner , .Cm ChrootDirectory , .Cm ForceCommand , .Cm GatewayPorts , .Cm GSSAPIAuthentication , .Cm HostbasedAuthentication , +.Cm HostbasedUsesNameFromPacketOnly , .Cm KbdInteractiveAuthentication , .Cm KerberosAuthentication , .Cm MaxAuthTries , @@ -623,6 +671,7 @@ Available keywords are .Cm PermitEmptyPasswords , .Cm PermitOpen , .Cm PermitRootLogin , +.Cm PermitTunnel , .Cm PubkeyAuthentication , .Cm RhostsRSAAuthentication , .Cm RSAAuthentication , @@ -988,7 +1037,7 @@ The default is Specifies a string to append to the regular version string to identify OS- or site-specific modifications. The default is -.Dq FreeBSD-20100428 . +.Dq FreeBSD-20101111 . .It Cm X11DisplayOffset Specifies the first display number available for .Xr sshd 8 Ns 's diff --git a/crypto/openssh/version.h b/crypto/openssh/version.h index 6cc8d84..20aeb01 100644 --- a/crypto/openssh/version.h +++ b/crypto/openssh/version.h @@ -1,12 +1,12 @@ -/* $OpenBSD: version.h,v 1.58 2010/03/16 16:36:49 djm Exp $ */ +/* $OpenBSD: version.h,v 1.59 2010/08/08 16:26:42 djm Exp $ */ /* $FreeBSD$ */ #ifndef SSH_VERSION #define SSH_VERSION (ssh_version_get()) #define SSH_RELEASE (ssh_version_get()) -#define SSH_VERSION_BASE "OpenSSH_5.5p1" -#define SSH_VERSION_ADDENDUM "FreeBSD-20100428" +#define SSH_VERSION_BASE "OpenSSH_5.6p1" +#define SSH_VERSION_ADDENDUM "FreeBSD-20101111" const char *ssh_version_get(void); void ssh_version_set_addendum(const char *); |