ssh

v6.0-rc0

SSH Application

The ssh application implements the Secure Shell (SSH) protocol and provides an SSH File Transfer Protocol (SFTP) client and server.

Description

The ssh application is an implementation of the SSH protocol in Erlang. ssh offers API functions to write customized SSH clients and servers as well as making the Erlang shell available over SSH. An SFTP client (ssh_sftp) and server (ssh_sftpd) are also included. The SFTP server can be enabled via the subsystems daemon option.

Dependencies

The ssh application uses the applications public_key and crypto to handle public keys and encryption. Hence, these applications must be loaded for the ssh application to work. The call ssh:start/0 will do the necessary calls to application:start/1,2 before it starts the ssh itself.

Configuration

The SSH application uses Configuration Parameters. Where to set them are described in config User's Guide with SSH details in Configuration in SSH.

Some special configuration files from OpenSSH are also used:

known_hosts

authorized_keys

authorized_keys2

id_dsa (supported but disabled by default)

id_rsa (SHA1 sign/verify are supported but disabled by default from OTP-24)

id_ecdsa

id_ed25519

id_ed448

ssh_host_dsa_key (supported but disabled by default)

ssh_host_rsa_key (SHA1 sign/verify are supported but disabled by default from OTP-24)

ssh_host_ecdsa_key

ssh_host_ed25519_key

ssh_host_ed448_key

By default, ssh looks for id_*, known_hosts, and authorized_keys in ~/.ssh, and for the ssh_host_*_key files in /etc/ssh. These locations can be changed by the options user_dir and system_dir. More about where to set them is described in Configuration in SSH.

Public key handling can also be customized through a callback module that implements the behaviors ssh_client_key_api and ssh_server_key_api.

See also the default callback module documentation in ssh_file.

Disabled public key algorithms can be enabled with the preferred_algorithms or modify_algorithms options. See Example 9 in Configuring algorithms in SSH for a description.

Public Keys

id_* are the users private key files. Notice that the public key is part of the private key so the ssh application does not use the id_*.pub files. These are for the user's convenience when it is needed to convey the user's public key.

See ssh_file for details.

Known Hosts

The known_hosts file contains a list of approved servers and their public keys. Once a server is listed, it can be verified without user interaction.

See ssh_file for details.

Authorized Keys

The authorized_key file keeps track of the user's authorized public keys. The most common use of this file is to let users log in without entering their password, which is supported by the Erlang ssh daemon.

See ssh_file for details.

Host Keys

RSA, DSA (if enabled), ECDSA, ED25519 and ED448 host keys are supported and are expected to be found in files named ssh_host_rsa_key, ssh_host_dsa_key, ssh_host_ecdsa_key, ssh_host_ed25519_key and ssh_host_ed448_key.

See ssh_file for details.

Error Logger and Event Handlers

The ssh application uses the default OTP error logger to log unexpected errors or print information about special events.

Supported Specifications and Standards

The supported SSH version is 2.0.

Algorithms

The actual set of algorithms may vary depending on which OpenSSL crypto library that is installed on the machine. For the list on a particular installation, use the command ssh:default_algorithms/0. The user may override the default algorithm configuration both on the server side and the client side. See the options preferred_algorithms and modify_algorithms in the ssh:daemon/1,2,3 and ssh:connect/3,4 functions.

Supported algorithms are (in the default order):

Key exchange algorithms

mlkem768x25519-sha256

curve25519-sha256

curve25519-sha256@libssh.org

curve448-sha512

ecdh-sha2-nistp521

ecdh-sha2-nistp384

ecdh-sha2-nistp256

diffie-hellman-group-exchange-sha256

diffie-hellman-group16-sha512

diffie-hellman-group18-sha512

diffie-hellman-group14-sha256

The following unsecure SHA1 algorithms are now disabled by default:

(diffie-hellman-group14-sha1)

(diffie-hellman-group-exchange-sha1)

(diffie-hellman-group1-sha1)

They can be enabled with the preferred_algorithms or modify_algorithms options. Use for example the Option value {modify_algorithms, [{append, [{kex,['diffie-hellman-group1-sha1']}]}]})

Public key algorithms

ssh-ed25519

ssh-ed448

ecdsa-sha2-nistp521

ecdsa-sha2-nistp384

ecdsa-sha2-nistp256

rsa-sha2-512

rsa-sha2-256

The following unsecure SHA1 algorithms are supported but disabled by default:

(ssh-dss)

(ssh-rsa)

Disabled public key algorithms can be enabled with the preferred_algorithms or modify_algorithms options. See Example 9 in Configuring algorithms in SSH for a description.

MAC algorithms

hmac-sha2-512-etm@openssh.com

hmac-sha2-256-etm@openssh.com

hmac-sha2-512

hmac-sha2-256

hmac-sha1-etm@openssh.com

hmac-sha1

The following unsecure SHA1 algorithm is disabled by default:

(hmac-sha1-96)

It can be enabled with the preferred_algorithms or modify_algorithms options. Use for example the Option value {modify_algorithms, [{append, [{mac,['hmac-sha1-96']}]}]})

Encryption algorithms (ciphers)

aes256-gcm@openssh.com

aes256-ctr

aes192-ctr

aes128-gcm@openssh.com

aes128-ctr

chacha20-poly1305@openssh.com

aes256-cbc

aes192-cbc

aes128-cbc

3des-cbc

The following unsecure algorithms are disabled by default:

(AEAD_AES_128_GCM)

(AEAD_AES_256_GCM)

See the text at the description of the rfc 5647 further down for more information regarding AEAD_AES_*_GCM.

Following the internet de-facto standard, the cipher and mac algorithm AEAD_AES_128_GCM is selected when the cipher aes128-gcm@openssh.com is negotiated. The cipher and mac algorithm AEAD_AES_256_GCM is selected when the cipher aes256-gcm@openssh.com is negotiated.

Compression algorithms

none

zlib@openssh.com

The following compression algorithm is deprecated in SSH and disabled by default:

(zlib)

It can be enabled with the preferred_algorithms or modify_algorithms options.

Unicode support

Unicode filenames are supported if the emulator and the underlying OS supports it. See file manual page in Kernel for information about this subject.

The shell and the cli both support unicode.

RFCs

The following RFCs are supported:

RFC 4251, The Secure Shell (SSH) Protocol Architecture.

Except

9.4.6 Host-Based Authentication

9.5.2 Proxy Forwarding

9.5.3 X11 Forwarding

RFC 4252, The Secure Shell (SSH) Authentication Protocol.

Except

9. Host-Based Authentication: "hostbased"

RFC 4253, The Secure Shell (SSH) Transport Layer Protocol.

Except

8.1. diffie-hellman-group1-sha1

6.6. Public Key Algorithms

ssh-dss

ssh-rsa

They are disabled by default as they now are regarded insecure, but they can be enabled with the preferred_algorithms or modify_algorithms options. See Example 8 (diffie-hellman-group1-sha1) and Example 9 (ssh-dss) in Configuring algorithms in SSH for descriptions.

RFC 4254, The Secure Shell (SSH) Connection Protocol.

Except

6.3. X11 Forwarding

7. TCP/IP Port Forwarding

RFC 4256, Generic Message Exchange Authentication for the Secure Shell Protocol (SSH).

Except

num-prompts > 1

password changing

other identification methods than userid-password

RFC 4419, Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer Protocol.

Except

4.1. diffie-hellman-group-exchange-sha1

It is disabled by default as it now is regarded insecure, but it can be enabled with the preferred_algorithms or modify_algorithms options.

RFC 4716, The Secure Shell (SSH) Public Key File Format.

RFC 5647, AES Galois Counter Mode for the Secure Shell Transport Layer Protocol.

There is an ambiguity in the synchronized selection of cipher and mac algorithm. This is resolved by OpenSSH in the ciphers aes128-gcm@openssh.com and aes256-gcm@openssh.com which are implemented. If the explicit ciphers and macs AEAD_AES_128_GCM or AEAD_AES_256_GCM are needed, they could be enabled with the options preferred_algorithms or modify_algorithms.

Warning

If the client or the server is not Erlang/OTP, it is the users responsibility to check that other implementation has the same interpretation of AEAD_AES_*_GCM as the Erlang/OTP SSH before enabling them. The aes*-gcm@openssh.com variants are always safe to use since they lack the ambiguity.

The second paragraph in section 5.1 is resolved as:

If the negotiated cipher is AEAD_AES_128_GCM, the mac algorithm is set to AEAD_AES_128_GCM.

If the negotiated cipher is AEAD_AES_256_GCM, the mac algorithm is set to AEAD_AES_256_GCM.

If the mac algorithm is AEAD_AES_128_GCM, the cipher is set to AEAD_AES_128_GCM.

If the mac algorithm is AEAD_AES_256_GCM, the cipher is set to AEAD_AES_256_GCM.

The first rule that matches when read in order from the top is applied

RFC 5656, Elliptic Curve Algorithm Integration in the Secure Shell Transport Layer.

Except

5. ECMQV Key Exchange

6.4. ECMQV Key Exchange and Verification Method Name

7.2. ECMQV Message Numbers

10.2. Recommended Curves

RFC 6668, SHA-2 Data Integrity Verification for the Secure Shell (SSH) Transport Layer Protocol

Comment: Defines hmac-sha2-256 and hmac-sha2-512

Draft-ietf-curdle-ssh-kex-sha2 (work in progress), Key Exchange (KEX) Method Updates and Recommendations for Secure Shell (SSH).

Deviations:

diffie-hellman-group1-sha1

diffie-hellman-group-exchange-sha1

diffie-hellman-group14-sha1

are not enabled by default as they now are regarded insecure, but are still supported and can be enabled with the options preferred_algorithms or modify_algorithms.

RFC 8332, Use of RSA Keys with SHA-256 and SHA-512 in the Secure Shell (SSH) Protocol.

RFC 8308, Extension Negotiation in the Secure Shell (SSH) Protocol.

Implemented are:

The Extension Negotiation Mechanism

The extension server-sig-algs

Secure Shell (SSH) Key Exchange Method Using Curve25519 and Curve448

RFC 8709 Ed25519 and Ed448 public key algorithms for the Secure Shell (SSH) protocol

draft-kampanakis-curdle-ssh-pq-ke, Post-Quantum Traditional Hybrid Key Exchange for SSH.

Comment: Implements mlkem768x25519-sha256. The ML-KEM-768 component is defined by NIST FIPS 203.

See Also

application

SSH Release Notes

Ssh 6.0

Fixed Bugs and Malfunctions

Password-based authentication has been updated to follow current security best practices. Key-based authentication remains recommended for production systems.

Own Id: OTP-19982 Aux Id: PR-10571

Added explicit size validation guards for pre-authentication SSH messages to improve defense-in-depth against DoS attacks. Messages now have per-field size limits based on RFC specifications:

Transport layer messages (DISCONNECT, IGNORE, DEBUG)

Key exchange messages (DH, ECDH, DH-GEX)

Service request messages (SERVICE_REQUEST, SERVICE_ACCEPT, EXT_INFO)

This change enhances the existing 256KB global packet size limit with granular per-message validation. Compliant implementations are not affected.

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19995 Aux Id: PR-10739

The SFTP subsystem root option now properly rejects relative paths at daemon startup. Previously, relative paths would cause unpredictable behavior as file operations resolved relative to the Erlang VM's current working directory. The option now requires an absolute path or empty string.

POTENTIAL INCOMPATIBILITY

Own Id: OTP-20019 Aux Id: PR-10820

Dynamic atom creation has been replaced with static lookups in ssh_transport and ssh_connection, using a dedicated OID-to-algorithm mapping function in ssh_message.

Own Id: OTP-20127 Aux Id: PR-11078

Improvements and New Features

Using KEX strict extension names as specified in draft-ietf-sshm-strict-kex-00. Pre standard names are still supported.

Own Id: OTP-19709 Aux Id: PR-10115

Added an alive option to detect and terminate dead SSH connections. Functionally equivalent to OpenSSH's ClientAlive/ServerAlive settings.

Own Id: OTP-19750 Aux Id: PR-9125, PR-10372

ssh:stop_deamon now uses supervisor:stop for shutting down daemons. With this change, the scenario when ssh:stop_daemon is called for a non-existing process results in calling process exiting. Previously an error tuple was returned (which was not documented).

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19801 Aux Id: PR-10253

The default key exchange algorithm is now mlkem768x25519-sha256, a hybrid quantum-resistant algorithm combining ML-KEM-768 with X25519. This provides protection against both classical and quantum computer attacks while maintaining backward compatibility through automatic fallback to other algorithms when peers don't support it.

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19965 Aux Id: PR-10656

The SSH daemon now defaults to disabled for shell and exec services, implementing the "secure by default" principle. This prevents authenticated users from executing arbitrary Erlang code unless explicitly configured.

Applications requiring shell or exec functionality must now explicitly enable:

  %% Enable Erlang shell
  ssh:daemon(Port, [{shell, {shell, start, []}} | Options])

  %% Enable Erlang term evaluation via exec
  ssh:daemon(Port, [{exec, erlang_eval} | Options])

  %% Restore complete old behavior
  ssh:daemon(Port, [{shell, {shell, start, []}},
                    {exec, erlang_eval}
                    | Options])

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19969 Aux Id: PR-10970, PR-11080, ERIERL-1319

Added SFTP resource limits section to hardening guide covering max_handles, max_path, and max_files with deployment recommendations.

Own Id: OTP-20031 Aux Id: PR-10838

Added support for -unsafe attributes, which is used to mark functions as unsafe to use.

This is similar to but separate from deprecation, and the compiler will by default now generate warnings for calls to functions in Erlang/OTP that are known to be always unsafe.

Furthermore, xref can now be used to find calls to functions in another application that lack a -doc attribute (undocumented_function_calls), calls to functions in another application marked -doc false. (private_function_calls), as well as calls to unsafe functions (unsafe_function_calls).

Own Id: OTP-20066 Aux Id: PR-10839

The SFTP subsystem is no longer enabled by default when starting an SSH daemon. To enable it, add the subsystems option explicitly:

ssh:daemon(Port, [{subsystems, [ssh_sftpd:subsystem_spec([])]} | Options])

POTENTIAL INCOMPATIBILITY

Own Id: OTP-20078 Aux Id: PR-10970

The SSH hardening guide has been improved with a timeout overview table replacing the previous image, corrected terminology ("authenticated" instead of "authorized"), and new examples for loopback binding, public key user checking, and password lockout using ETS.

Own Id: OTP-20079 Aux Id: PR-10970

With this change usage of zlib compression algorithm in SSH is deprecated and scheduled for removal in OTP 30.0

Own Id: OTP-20099 Aux Id: PR-11010

Updated SSH documentation with current OTP 29 algorithm defaults, including the new mlkem768x25519-sha256 post-quantum key exchange. Fixed stale examples, typos, and improved document structure.

Own Id: OTP-20100 Aux Id: PR-11012

Ssh 5.5.2

Fixed Bugs and Malfunctions

Fixed a vulnerability in the SFTP server where file attributes could be modified outside the configured root directory. When using FSETSTAT on an open file handle, the operation used the path stored in the handle without verifying it was within the root directory, allowing attribute changes to files outside the chroot boundary.

Thanks to John Downey.

Own Id: OTP-20081 Aux Id: PR-11027, CVE-2026-32147

Ssh 5.5.1

Fixed Bugs and Malfunctions

Fixed path traversal vulnerability in SFTP server's root option allowing authenticated users to access sibling directories with matching name prefixes. The root option used string prefix matching instead of path component validation. With {root, "/home/user1"}, attackers could access /home/user10/ or /home/user123/. Thanks to Luigino Camastra, Aisle Research.

Own Id: OTP-20009 Aux Id: PR-10811, CVE-2026-23942

Fixed excessive memory usage vulnerability in SSH compression allowing attackers to consume system resources through decompression bombs. The 'zlib' and 'zlib@openssh.com' algorithms lacked decompression size limits, allowing 256 KB packets to expand to 255 MB (1029:1 ratio). This could lead to crashes on systems with limited memory.

The fix removes zlib from default compression algorithms and implements decompression size limits for both algorithms. Thanks to Igor Morgenstern at Aisle Research

Own Id: OTP-20011 Aux Id: PR-10813, CVE-2026-23943

Ssh 5.5

Fixed Bugs and Malfunctions

The type specification for the CbInitArgs parameter in ssh_client_channel:start/4 and ssh_client_channel:start_link/4 has been relaxed from [term()] to term(). This eliminates false Dialyzer warnings when passing non-list arguments (such as maps or atoms) to these functions. This change is backward compatible as term() includes [term()].

Own Id: OTP-19976 Aux Id: GH-10351, PR-10673

Improvements and New Features

Added support for the PQC key exchange (kex) algorithm mlkem768x25519-sha256, a hybrid quantum-resistant algorithm combining ML-KEM-768 with X25519.

Own Id: OTP-19824 Aux Id: PR-10512, PR-10655

Ssh 5.4.1

Fixed Bugs and Malfunctions

Fix handling of the SSH "each side may guess" key-exchange mechanism as defined in RFC 4253, Section 7.

Own Id: OTP-19864 Aux Id: GH-8676, PR-10575

Fix ssh_file:encode handling of OpenSSH V1 private keys generated by public_key module. Also correct type specifications for OpenSSH V1 keys in ssh_file encode and decode operations.

Own Id: OTP-19915 Aux Id: PR-10539

Ssh 5.4

Improvements and New Features

Adjustment in ssh_file module allowing inclusion of Erlang/OTP license in test files containing keys.

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19743 Aux Id: PR-10177

Ssh 5.3.4

Fixed Bugs and Malfunctions

With this change user space buffers are used to limit ssh hello message size instead of kernel buffers

Own Id: OTP-19839 Aux Id: ERIERL-1273, PR-10350

Ssh 5.3.3

Fixed Bugs and Malfunctions

Option max_handles can be configured for sshd running SFTP. The positive integer value limits amount of file handles opened for a connection (by default 1000 is used).

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19701 Aux Id: CVE-2025-48041, PR-10157

Avoid decoding KEX messages providing too many algorithms. This change does not introduce new limitation but assures it is enforced earlier in processing chain. Adjustments in error logging during handshake.

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19741 Aux Id: CVE-2025-48040, PR-10162

A new 'max_path' option is now available in the sshd configuration, allowing administrators to set the maximum allowable path length. By default, this value is set to 4096 characters.

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19742 Aux Id: CVE-2025-48039, PR-10155

Reject file handles exceeding size specified in RFCs (256 bytes).

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19748 Aux Id: CVE-2025-48038, PR-10156

Ssh 5.3.2

Fixed Bugs and Malfunctions

Fix file handle id generation.

Own Id: OTP-19691 Aux Id: PR-10003

Fixes a badmatch error, when SFTP operation cannot be processed due to channel closed in parallel.

Own Id: OTP-19707 Aux Id: GH-9655, PR-10035, PR-10036

Ssh 5.3.1

Fixed Bugs and Malfunctions

Various channel closing robustness improvements. Avoid crashes when channel handling process closes channel and immediately exits. Avoid breaking the protocol by sending duplicated channel-close messages. Cleanup channels which timeout during closing procedure.

Own Id: OTP-19634 Aux Id: GH-9102, PR-9103

Improved interoperability with clients acting as Paramiko.

Own Id: OTP-19637 Aux Id: GH-6463, PR-9838

Ssh 5.3

Fixed Bugs and Malfunctions

The implementation of the ssh server-side supervision tree has been improved.

Own Id: OTP-19324 Aux Id: PR-8968, GH-8223

SSH daemon accepts fun as tcpip_tunnel_in option. This provides more control over TCP connection tunnel handle by server.

Own Id: OTP-19566 Aux Id: PR-9571

Improvements and New Features

The Erlang SSH daemon now uses the same backend to handle multiline functionality as the Erlang shell.

Own Id: OTP-19226 Aux Id: PR-8805

CBC algorithms are not offered by default. See Configuring algorithms in SSH if you wish to enable them.

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19420 Aux Id: PR-9277

Daemon can be configured (bannerfun option) to send banner message at the beginning of user authentication.

Own Id: OTP-19535 Aux Id: PR-9149

The license and copyright header has changed format to include an SPDX-License-Identifier. At the same time, most files have been updated to follow a uniform standard for license headers.

Own Id: OTP-19575 Aux Id: PR-9670

For interoperability reasons, SSH ignore message with no length specified is treated as message with zero length specified - it will not cause decode error.

Own Id: OTP-19586 Aux Id: PR-9214

Documentation improvements.

Own Id: OTP-19596 Aux Id: PR-9298

Ssh 5.2.11.7

Fixed Bugs and Malfunctions

Fixed a vulnerability in the SFTP server where file attributes could be modified outside the configured root directory. When using FSETSTAT on an open file handle, the operation used the path stored in the handle without verifying it was within the root directory, allowing attribute changes to files outside the chroot boundary.

Thanks to John Downey.

Own Id: OTP-20081 Aux Id: PR-11027, CVE-2026-32147

Ssh 5.2.11.6

Fixed Bugs and Malfunctions

Fixed path traversal vulnerability in SFTP server's root option allowing authenticated users to access sibling directories with matching name prefixes. The root option used string prefix matching instead of path component validation. With {root, "/home/user1"}, attackers could access /home/user10/ or /home/user123/. Thanks to Luigino Camastra, Aisle Research.

Own Id: OTP-20009 Aux Id: PR-10811, CVE-2026-23942

Fixed excessive memory usage vulnerability in SSH compression allowing attackers to consume system resources through decompression bombs. The 'zlib' and 'zlib@openssh.com' algorithms lacked decompression size limits, allowing 256 KB packets to expand to 255 MB (1029:1 ratio). This could lead to crashes on systems with limited memory.

The fix removes zlib from default compression algorithms and implements decompression size limits for both algorithms. Thanks to Igor Morgenstern at Aisle Research

Own Id: OTP-20011 Aux Id: PR-10813, CVE-2026-23943

Ssh 5.2.11.5

Fixed Bugs and Malfunctions

Fix handling of the SSH "each side may guess" key-exchange mechanism as defined in RFC 4253, Section 7.

Own Id: OTP-19864 Aux Id: GH-8676, PR-10575

Ssh 5.2.11.4

Fixed Bugs and Malfunctions

With this change user space buffers are used to limit ssh hello message size instead of kernel buffers

Own Id: OTP-19839 Aux Id: ERIERL-1273, PR-10350

Ssh 5.2.11.3

Fixed Bugs and Malfunctions

Option max_handles can be configured for sshd running SFTP. The positive integer value limits amount of file handles opened for a connection (by default 1000 is used).

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19701 Aux Id: CVE-2025-48041, PR-10157

Avoid decoding KEX messages providing too many algorithms. This change does not introduce new limitation but assures it is enforced earlier in processing chain. Adjustments in error logging during handshake.

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19741 Aux Id: CVE-2025-48040, PR-10162

A new 'max_path' option is now available in the sshd configuration, allowing administrators to set the maximum allowable path length. By default, this value is set to 4096 characters.

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19742 Aux Id: CVE-2025-48039, PR-10155

Reject file handles exceeding size specified in RFCs (256 bytes).

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19748 Aux Id: CVE-2025-48038, PR-10156

Ssh 5.2.11.2

Fixed Bugs and Malfunctions

Fix file handle id generation.

Own Id: OTP-19691 Aux Id: PR-10003

Fixes a badmatch error, when SFTP operation cannot be processed due to channel closed in parallel.

Own Id: OTP-19707 Aux Id: GH-9655, PR-10035, PR-10036

Ssh 5.2.11.1

Fixed Bugs and Malfunctions

Various channel closing robustness improvements. Avoid crashes when channel handling process closes channel and immediately exits. Avoid breaking the protocol by sending duplicated channel-close messages. Cleanup channels which timeout during closing procedure.

Own Id: OTP-19634 Aux Id: GH-9102, PR-9103

Improved interoperability with clients acting as Paramiko.

Own Id: OTP-19637 Aux Id: GH-6463, PR-9838

Ssh 5.2.11

Fixed Bugs and Malfunctions

Fix KEX strict implementation according to draft-miller-sshm-strict-kex-01 document.

Thanks to Fabian Bäumer, Marcel Maehren, Marcus Brinkmann, and Jörg Schwenk from the Ruhr University Bochum for finding and responsibly disclosing this vulnerability to the Erlang/OTP project.

Own Id: OTP-19625 Aux Id: CVE-2025-46712

Ssh 5.2.10

Fixed Bugs and Malfunctions

Reception of wrong Unicode does not cause unnecessary processing. US-ASCII fields are not decoded as Unicode.

Own Id: OTP-19582 Aux Id: PR-9679

SSH daemon disconnects upon receiving connection protocol message for unauthenticated used.

Thanks to Fabian Bäumer, Marcel Maehren, Marcus Brinkmann, Nurullah Erinola, Jörg Schwenk (Ruhr University Bochum).

Own Id: OTP-19595 Aux Id: CVE-2025-32433

Ssh 5.2.9

Fixed Bugs and Malfunctions

Reception of malicious KEX init message does not result with ssh daemon excessive memory usage.

Own Id: OTP-19543 Aux Id: CVE-2025-30211

Call to ssh:daemon_replace_options does not crash when argument is not a valid daemon ref.

Own Id: OTP-19559 Aux Id: GH-9554, PR-9545

Ssh 5.2.8

Fixed Bugs and Malfunctions

Minor documentation improvements.

Own Id: OTP-19410 Aux Id: PR-9188

Function specification for ssh_sftp:start_channel/2 is fixed.

Own Id: OTP-19475 Aux Id: PR-9368, GH-9359

Ssh 5.2.7

Fixed Bugs and Malfunctions

SFTP packets exceeding max packet size are not processed and dropped.

Own Id: OTP-19466 Aux Id: ERIERL-1173, CVE-2025-26618

Ssh 5.2.6

Fixed Bugs and Malfunctions

With this change, type specs for ssh:connection_info/1,2 functions are fixed so they include {error, term()} return value.

Own Id: OTP-19388 Aux Id: ERIERL-1165, PR-9161

With this change, ssh client accepts a banner sent during processing keyboard interactive user authentication.

Own Id: OTP-19392 Aux Id: PR-9139, GH-9065

With this change, large sftp transfers does not hang. Redundant window adjustment are not requested.

Own Id: OTP-19435 Aux Id: PR-9309

Ssh 5.2.5

Fixed Bugs and Malfunctions

Documentation is polished after OTP-27 migration to markdown.

Own Id: OTP-19335 Aux Id: PR-9021

Ssh 5.2.4

Fixed Bugs and Malfunctions

With this change, ssh connection does not crash upon receiving exit-signal message for an already terminated channel.

Own Id: OTP-19326 Aux Id: PR-8995, GH-8929

Ssh 5.2.3

Fixed Bugs and Malfunctions

With this change, a race condition is removed from ssh client connection setup procedure.

Own Id: OTP-19124 Aux Id: GH-7550, PR-8766

With this change, ssh:connect is not affected by presence of EXIT message in queue.

Own Id: OTP-19246 Aux Id: GH-8223, PR-8854

With this change, ssh appends {active, false} option after socket options received from user - so that false value is always used.

Own Id: OTP-19247 Aux Id: PR-8226

Ssh 5.2.2

Fixed Bugs and Malfunctions

The SSh daemon started with a TCP port number argument will now re-try obtaining a listen socket before returning an error to the user.

Own Id: OTP-19170 Aux Id: GH-7746

Robustness has been improved by monitoring the connection handler process before casting the socket control notification.

Own Id: OTP-19173 Aux Id: PR-8310

Ssh 5.2.1

Fixed Bugs and Malfunctions

With this change, race condition between connection closing and automatic window adjustment is fixed.

Own Id: OTP-19109 Aux Id: PR-8345

Ssh 5.2

Fixed Bugs and Malfunctions

SSH processes are now assigned labels for troubleshooting purposes.

Own Id: OTP-19017 Aux Id: PR-8249

With this change, ssh client will automatically adjust transfer window size for commands executed remotely over SSH.

Own Id: OTP-19057 Aux Id: PR-8345, GH-7483

Improvements and New Features

The shell now pages long output from the documentation help command (h(Module)), auto completions and the search command.

Own Id: OTP-18846 Aux Id: PR-7845

The documentation has been migrated to use Markdown and ExDoc.

Own Id: OTP-18955 Aux Id: PR-8026

Updated types and specs for all API modules.

Own Id: OTP-18961

Ssh 5.1.4.15

Fixed Bugs and Malfunctions

Fixed a vulnerability in the SFTP server where file attributes could be modified outside the configured root directory. When using FSETSTAT on an open file handle, the operation used the path stored in the handle without verifying it was within the root directory, allowing attribute changes to files outside the chroot boundary.

Thanks to John Downey.

Own Id: OTP-20081 Aux Id: PR-11027, CVE-2026-32147

Ssh 5.1.4.14

Fixed Bugs and Malfunctions

Fixed path traversal vulnerability in SFTP server's root option allowing authenticated users to access sibling directories with matching name prefixes. The root option used string prefix matching instead of path component validation. With {root, "/home/user1"}, attackers could access /home/user10/ or /home/user123/. Thanks to Luigino Camastra, Aisle Research.

Own Id: OTP-20009 Aux Id: PR-10811, CVE-2026-23942

Fixed excessive memory usage vulnerability in SSH compression allowing attackers to consume system resources through decompression bombs. The 'zlib' and 'zlib@openssh.com' algorithms lacked decompression size limits, allowing 256 KB packets to expand to 255 MB (1029:1 ratio). This could lead to crashes on systems with limited memory.

The fix removes zlib from default compression algorithms and implements decompression size limits for both algorithms. Thanks to Igor Morgenstern at Aisle Research

Own Id: OTP-20011 Aux Id: PR-10813, CVE-2026-23943

Ssh 5.1.4.13

Fixed Bugs and Malfunctions

With this change user space buffers are used to limit ssh hello message size instead of kernel buffers

Own Id: OTP-19839 Aux Id: ERIERL-1273, PR-10350

Ssh 5.1.4.12

Fixed Bugs and Malfunctions

Option max_handles can be configured for sshd running SFTP. The positive integer value limits amount of file handles opened for a connection (by default 1000 is used).

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-19701 Aux Id: CVE-2025-48041, PR-10157

Avoid decoding KEX messages providing too many algorithms. This change does not introduce new limitation but assures it is enforced earlier in processing chain. Adjustments in error logging during handshake.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-19741 Aux Id: CVE-2025-48040, PR-10162

A new 'max_path' option is now available in the sshd configuration, allowing administrators to set the maximum allowable path length. By default, this value is set to 4096 characters.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-19742 Aux Id: CVE-2025-48039, PR-10155

Reject file handles exceeding size specified in RFCs (256 bytes).

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-19748 Aux Id: CVE-2025-48038, PR-10156

Ssh 5.1.4.11

Fixed Bugs and Malfunctions

Fix file handle id generation.

Own Id: OTP-19691 Aux Id: PR-10003

Fixes a badmatch error, when SFTP operation cannot be processed due to channel closed in parallel.

Own Id: OTP-19707 Aux Id: GH-9655, PR-10035, PR-10036

Ssh 5.1.4.10

Fixed Bugs and Malfunctions

Various channel closing robustness improvements. Avoid crashes when channel handling process closes channel and immediately exits. Avoid breaking the protocol by sending duplicated channel-close messages. Cleanup channels which timeout during closing procedure.

Own Id: OTP-19634 Aux Id: GH-9102, PR-9103

Improved interoperability with clients acting as Paramiko.

Own Id: OTP-19637 Aux Id: GH-6463, PR-9838

Ssh 5.1.4.9

Fixed Bugs and Malfunctions

Fix KEX strict implementation according to draft-miller-sshm-strict-kex-01 document.

Thanks to Fabian Bäumer, Marcel Maehren, Marcus Brinkmann, and Jörg Schwenk from the Ruhr University Bochum for finding and responsibly disclosing this vulnerability to the Erlang/OTP project.

Own Id: OTP-19625 Aux Id: CVE-2025-46712

Ssh 5.1.4.8

Fixed Bugs and Malfunctions

Reception of wrong Unicode does not cause unnecessary processing. US-ASCII fields are not decoded as Unicode.

Own Id: OTP-19582 Aux Id: PR-9679

SSH daemon disconnects upon receiving connection protocol message for unauthenticated used.

Thanks to Fabian Bäumer, Marcel Maehren, Marcus Brinkmann, Nurullah Erinola, Jörg Schwenk (Ruhr University Bochum).

Own Id: OTP-19595 Aux Id: CVE-2025-32433

Ssh 5.1.4.7

Fixed Bugs and Malfunctions

Reception of malicious KEX init message does not result with ssh daemon excessive memory usage.

Own Id: OTP-19543 Aux Id: CVE-2025-30211

Call to ssh:daemon_replace_options does not crash when argument is not a valid daemon ref.

Own Id: OTP-19559 Aux Id: GH-9554, PR-9545

Ssh 5.1.4.6

Fixed Bugs and Malfunctions

SFTP packets exceeding max packet size are not processed and dropped.

Own Id: OTP-19466 Aux Id: ERIERL-1173, CVE-2025-26618

Ssh 5.1.4.5

Fixed Bugs and Malfunctions

With this change, type specs for ssh:connection_info/1,2 functions are fixed so they include {error, term()} return value.

Own Id: OTP-19388 Aux Id: ERIERL-1165, PR-9161

With this change, ssh client accepts a banner sent during processing keyboard interactive user authentication.

Own Id: OTP-19392 Aux Id: PR-9139, GH-9065

With this change, large sftp transfers does not hang. Redundant window adjustment are not requested.

Own Id: OTP-19435 Aux Id: PR-9309

Ssh 5.1.4.4

Fixed Bugs and Malfunctions

With this change, ssh connection does not crash upon receiving exit-signal message for an already terminated channel.

Own Id: OTP-19326 Aux Id: PR-8995, GH-8929

Ssh 5.1.4.3

Fixed Bugs and Malfunctions

With this change, a race condition is removed from ssh client connection setup procedure.

Own Id: OTP-19124 Aux Id: GH-7550, PR-8766

With this change, ssh:connect is not affected by presence of EXIT message in queue.

Own Id: OTP-19246 Aux Id: GH-8223, PR-8854

With this change, ssh appends {active, false} option after socket options received from user - so that false value is always used.

Own Id: OTP-19247 Aux Id: PR-8226

Ssh 5.1.4.2

Fixed Bugs and Malfunctions

With this change, ssh daemon started with TCP port number argument will re-try to obtain listen socket before returning error to user.

Own Id: OTP-19170 Aux Id: GH-7746

With this change, robustness is improved by monitoring connection handler process before casting socket control notification.

Own Id: OTP-19173 Aux Id: PR-8310

Ssh 5.1.4.1

Fixed Bugs and Malfunctions

With this change, ssh client will automatically adjust transfer window size for commands executed remotely over SSH.

Own Id: OTP-19057 Aux Id: PR-8345, GH-7483

With this change, race condition between connection closing and automatic window adjustment is fixed.

Own Id: OTP-19109 Aux Id: PR-8345

Ssh 5.1.4

Fixed Bugs and Malfunctions

With this change, owner and group file attributes decoding is fixed and results with value of integer type.

Own Id: OTP-19013 Aux Id: GH-7897, PR-8220

Ssh 5.1.3

Fixed Bugs and Malfunctions

With this change, acceptor_sup is not started for ssh client as it is not needed in that role.

Own Id: OTP-18974

With this change, more secure algorithms are preferred by ssh and documentation is updated to reflect that.

Own Id: OTP-18986

With this change, KEX strict terminal message is emitted with debug verbosity.

Own Id: OTP-19002 Aux Id: ERIERL-1041

Fix reading of password for ssh client when in user_interactive mode.

Own Id: OTP-19007 Aux Id: ERIERL-1049

Ssh 5.1.2

Fixed Bugs and Malfunctions

With this change, Curve25519 and Curve448 KEX methods become most preferred (related to RFC8731).

Own Id: OTP-18964

Ssh 5.1.1

Fixed Bugs and Malfunctions

With this change (being response to CVE-2023-48795), ssh can negotiate "strict KEX" OpenSSH extension with peers supporting it; also 'chacha20-poly1305@openssh.com' algorithm becomes a less preferred cipher.

If strict KEX availability cannot be ensured on both connection sides, affected encryption modes(CHACHA and CBC) can be disabled with standard ssh configuration. This will provide protection against vulnerability, but at a cost of affecting interoperability. See Configuring algorithms in SSH.

Thanks to Fabian Bäumer, Marcus Brinkmann and Jörg Schwenk.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-18897

Ssh 5.1

Fixed Bugs and Malfunctions

Replaced unintentional Erlang Public License 1.1 headers in some files with the intended Apache License 2.0 header.

Own Id: OTP-18815 Aux Id: PR-7780

Avoid outputting ansi escape sequences to dumb ssh clients.

Own Id: OTP-18861 Aux Id: PR-7627

With this change, connection handler does not execute socket operations until it becomes socket owner. Previously errors could occur if connection handler tried to work with socket whose owner exited.

Own Id: OTP-18869 Aux Id: PR-7849,GH-7571

Improvements and New Features

With this change, reverse search works with ssh shell and non dumb terminals.

Own Id: OTP-18730 Aux Id: PR-7499

Ssh 5.0.1

Fixed Bugs and Malfunctions

Added multiline editing support to ssh clients connected through OTP ssh daemon.

Own Id: OTP-18653 Aux Id: PR-7242

Ssh 5.0

Improvements and New Features

The ssh_cli has been updated to work with the changes introduced in the new Erlang shell implementation.

Own Id: OTP-18231 Aux Id: OTP-17932 PR-6144

Typing Ctrl+L in a shell now clears the screen and redraws the current line instead of only redrawing the current line. To only redraw the current line, you must now type Alt+L. This brings the behaviour of Ctrl+L closer to how bash and other shells work.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-18285 Aux Id: PR-6262

Deprecates dbg:stop_clear/0 because it is simply a function alias to dbg:stop/0

Own Id: OTP-18478 Aux Id: GH-6903

The implementation has been fixed to use proc_lib:init_fail/2,3 where appropriate, instead of proc_lib:init_ack/1,2.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-18490 Aux Id: OTP-18471, GH-6339, PR-6843

Ssh 4.15.3.13

Fixed Bugs and Malfunctions

Fix KEX strict implementation according to draft-miller-sshm-strict-kex-01 document.

Thanks to Fabian Bäumer, Marcel Maehren, Marcus Brinkmann, and Jörg Schwenk from the Ruhr University Bochum for finding and responsibly disclosing this vulnerability to the Erlang/OTP project.

Own Id: OTP-19625 Aux Id: CVE-2025-46712

Ssh 4.15.3.12

Fixed Bugs and Malfunctions

Reception of wrong Unicode does not cause unnecessary processing. US-ASCII fields are not decoded as Unicode.

Own Id: OTP-19582 Aux Id: PR-9679

SSH daemon disconnects upon receiving connection protocol message for unauthenticated used.

Thanks to Fabian Bäumer, Marcel Maehren, Marcus Brinkmann, Nurullah Erinola, Jörg Schwenk (Ruhr University Bochum).

Own Id: OTP-19595 Aux Id: CVE-2025-32433

Ssh 4.15.3.11

Fixed Bugs and Malfunctions

Reception of malicious KEX init message does not result with ssh daemon excessive memory usage.

Own Id: OTP-19543 Aux Id: CVE-2025-30211

Call to ssh:daemon_replace_options does not crash when argument is not a valid daemon ref.

Own Id: OTP-19559 Aux Id: GH-9554, PR-9545

Ssh 4.15.3.10

Fixed Bugs and Malfunctions

SFTP packets exceeding max packet size are not processed and dropped.

Own Id: OTP-19466 Aux Id: ERIERL-1173, CVE-2025-26618

Ssh 4.15.3.9

Fixed Bugs and Malfunctions

With this change, type specs for ssh:connection_info/1,2 functions are fixed so they include {error, term()} return value.

Own Id: OTP-19388 Aux Id: ERIERL-1165, PR-9161

With this change, ssh client accepts a banner sent during processing keyboard interactive user authentication.

Own Id: OTP-19392 Aux Id: PR-9139, GH-9065

With this change, large sftp transfers does not hang. Redundant window adjustment are not requested.

Own Id: OTP-19435 Aux Id: PR-9309

Ssh 4.15.3.8

Fixed Bugs and Malfunctions

With this change, ssh connection does not crash upon receiving exit-signal message for an already terminated channel.

Own Id: OTP-19326 Aux Id: PR-8995, GH-8929

Ssh 4.15.3.7

Fixed Bugs and Malfunctions

With this change, a race condition is removed from ssh client connection setup procedure.

Own Id: OTP-19124 Aux Id: GH-7550, PR-8766

With this change, ssh:connect is not affected by presence of EXIT message in queue.

Own Id: OTP-19246 Aux Id: GH-8223, PR-8854

With this change, ssh appends {active, false} option after socket options received from user - so that false value is always used.

Own Id: OTP-19247 Aux Id: PR-8226

Ssh 4.15.3.6

Fixed Bugs and Malfunctions

The SSh daemon started with a TCP port number argument will now re-try obtaining a listen socket before returning an error to the user.

Own Id: OTP-19170 Aux Id: GH-7746

Robustness has been improved by monitoring the connection handler process before casting the socket control notification.

Own Id: OTP-19173 Aux Id: PR-8310

Ssh 4.15.3.5

Fixed Bugs and Malfunctions

With this change, ssh client will automatically adjust transfer window size for commands executed remotely over SSH.

Own Id: OTP-19057 Aux Id: PR-8345, GH-7483

With this change, race condition between connection closing and automatic window adjustment is fixed.

Own Id: OTP-19109 Aux Id: PR-8345

Ssh 4.15.3.4

Fixed Bugs and Malfunctions

With this change, owner and group file attributes decoding is fixed and results with value of integer type.

Own Id: OTP-19013 Aux Id: GH-7897, PR-8220

Ssh 4.15.3.3

Fixed Bugs and Malfunctions

With this change, more secure algorithms are preferred by ssh and documentation is updated to reflect that.

Own Id: OTP-18986

With this change, KEX strict terminal message is emitted with debug verbosity.

Own Id: OTP-19002 Aux Id: ERIERL-1041

Ssh 4.15.3.2

Fixed Bugs and Malfunctions

With this change, Curve25519 and Curve448 KEX methods become most preferred (related to RFC8731).

Own Id: OTP-18964

Ssh 4.15.3.1

Fixed Bugs and Malfunctions

With this change, connection handler does not execute socket operations until it becomes socket owner. Previously errors could occur if connection handler tried to work with socket whose owner exited.

Own Id: OTP-18869 Aux Id: PR-7849,GH-7571

With this change (being response to CVE-2023-48795), ssh can negotiate "strict KEX" OpenSSH extension with peers supporting it; also 'chacha20-poly1305@openssh.com' algorithm becomes a less preferred cipher.

If strict KEX availability cannot be ensured on both connection sides, affected encryption modes(CHACHA and CBC) can be disabled with standard ssh configuration. This will provide protection against vulnerability, but at a cost of affecting interoperability. See Configuring algorithms in SSH.

Thanks to Fabian Bäumer, Marcus Brinkmann and Jörg Schwenk.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-18897

Ssh 4.15.3

Fixed Bugs and Malfunctions

With this change, PKCS8 formatted private key file is properly decoded and SSH daemon with such key can be started.

Own Id: OTP-18446 Aux Id: GH-6475

Improvements and New Features

Replace size/1 with either tuple_size/1 or byte_size/1

The size/1 BIF is not optimized by the JIT, and its use can result in worse types for Dialyzer.

When one knows that the value being tested must be a tuple, tuple_size/1 should always be preferred.

When one knows that the value being tested must be a binary, byte_size/1 should be preferred. However, byte_size/1 also accepts a bitstring (rounding up size to a whole number of bytes), so one must make sure that the call to byte_size/ is preceded by a call to is_binary/1 to ensure that bitstrings are rejected. Note that the compiler removes redundant calls to is_binary/1, so if one is not sure whether previous code had made sure that the argument is a binary, it does not harm to add an is_binary/1 test immediately before the call to byte_size/1.

Own Id: OTP-18432 Aux Id: GH-6672,PR-6793,PR-6784,PR-6787,PR-6785,PR-6682,PR-6800,PR-6797,PR-6798,PR-6799,PR-6796,PR-6813,PR-6671,PR-6673,PR-6684,PR-6694,GH-6677,PR-6696,PR-6670,PR-6674

Ssh 4.15.2

Fixed Bugs and Malfunctions

With this change, ssh application does not crash when formatting some of info reports for unsuccessful connections.

Own Id: OTP-18386 Aux Id: PR-6611

With this change, ssh does not log extensively long messages.

Own Id: OTP-18417 Aux Id: DAFH-1349,ERIERL-888,IA18357

Ssh 4.15.1

Fixed Bugs and Malfunctions

graceful shutdown of ssh_conection_handler when connection is closed by peer

Own Id: OTP-18326 Aux Id: ERIERL-865

Ssh 4.15

Fixed Bugs and Malfunctions

Handling rare race condition at channel close.

Own Id: OTP-18220 Aux Id: ERIERL-666, ERIERL-661

Improvements and New Features

New ssh option no_auth_needed to skip the ssh authentication. Use with caution!

Own Id: OTP-18134 Aux Id: GH-6021

This change fixes dialyzer warnings generated for inets/httpd examples (includes needed adjustment of spec for ssh_sftp module).

Own Id: OTP-18178 Aux Id: ERIERL-833, ERIERL-834, ERIERL-835

The new function ssh:daemon_replace_options/2 makes it possible to change the Options in a running SSH server.

Established connections are not affected, only those created after the call to this new function.

Own Id: OTP-18196

Add a timeout as option max_initial_idle_time. It closes a connection that does not allocate a channel within the timeout time.

For more information about timeouts, see the Timeouts section in the User's Guide Hardening chapter.

Own Id: OTP-18207 Aux Id: PR-6231

Ssh 4.14.1

Fixed Bugs and Malfunctions

Binaries can be limited in logs with the parameter max_log_item_len. The default value is 500 bytes.

Own Id: OTP-18094

Ssh 4.14

Improvements and New Features

The representation of Edward curves (ed25519 and ed448) inside ssh had a temporary representation (ed_pri and ed_pub).

That is now changed to the public_key form. See the manual for more information.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-17920

Former internal function ssh_file:extract_public_key/1 documented publicly.

Internally it was previously in ssh_transport.

Own Id: OTP-18079 Aux Id: GH-5767

Ssh 4.13.2.6

Fixed Bugs and Malfunctions

With this change, more secure algorithms are preferred by ssh and documentation is updated to reflect that.

Own Id: OTP-18986

With this change, KEX strict terminal message is emitted with debug verbosity.

Own Id: OTP-19002 Aux Id: ERIERL-1041

With this change, owner and group file attributes decoding is fixed and results with value of integer type.

Own Id: OTP-19013 Aux Id: GH-7897, PR-8220

Ssh 4.13.2.5

Fixed Bugs and Malfunctions

With this change, Curve25519 and Curve448 KEX methods become most preferred (related to RFC8731).

Own Id: OTP-18964

Ssh 4.13.2.4

Fixed Bugs and Malfunctions

With this change, connection handler does not execute socket operations until it becomes socket owner. Previously errors could occur if connection handler tried to work with socket whose owner exited.

Own Id: OTP-18869 Aux Id: PR-7849,GH-7571

With this change (being response to CVE-2023-48795), ssh can negotiate "strict KEX" OpenSSH extension with peers supporting it; also 'chacha20-poly1305@openssh.com' algorithm becomes a less preferred cipher.

If strict KEX availability cannot be ensured on both connection sides, affected encryption modes(CHACHA and CBC) can be disabled with standard ssh configuration. This will provide protection against vulnerability, but at a cost of affecting interoperability. See Configuring algorithms in SSH.

Thanks to Fabian Bäumer, Marcus Brinkmann and Jörg Schwenk.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-18897

Ssh 4.13.2.3

Fixed Bugs and Malfunctions

With this change, error logging related crashes in ssh_connection_handler module are fixed.

Own Id: OTP-18620 Aux Id: OTP-18386,PR-6611

Ssh 4.13.2.2

Fixed Bugs and Malfunctions

With this change, ssh application does not crash when formatting some of info reports for unsuccessful connections.

Own Id: OTP-18386 Aux Id: PR-6611

With this change, ssh does not log extensively long messages.

Own Id: OTP-18417 Aux Id: DAFH-1349,ERIERL-888,IA18357

Ssh 4.13.2.1

Fixed Bugs and Malfunctions

Binaries can be limited in logs with the parameter max_log_item_len. The default value is 500 bytes.

Own Id: OTP-18094

Ssh 4.13.2

Fixed Bugs and Malfunctions

Fix makefile dependency bugs.

Own Id: OTP-17847 Aux Id: PR-5574 GH-5548

Fixed faulty OpenSSH decoding of Ed25519/Ed448 keys in the OpenSSH format openssh_key_v1.

Own Id: OTP-17868 Aux Id: PR-5520

Correction of ssh_file typing, specially for the experimental openssh-key-v1 encoding.

Own Id: OTP-17912 Aux Id: GH-5680

Improper tag for private ED keys when encoding with ssh:encode/2.

The tuple had ed_priv as first element, but should have had ed_pri. This is now corrected.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-17928 Aux Id: PR-5679

Improvements and New Features

Add support for Ed25519/Ed448 SSH host keys in the RFC 4716 format ("-----BEGIN EC PRIVATE KEY-----") generated by for example openssl or via Erlang functions (i.e. public_key:generate_key({namedCurve, ed25519})).

Ed25519 SSH host keys generated by ssh-keygen was, and are still, supported.

Own Id: OTP-17857 Aux Id: PR-5532

Ssh 4.13.1

Fixed Bugs and Malfunctions

The ssh sever parallel_login option was missing in OTP-24

Own Id: OTP-17850 Aux Id: ERIERL-764

Ssh 4.13

Fixed Bugs and Malfunctions

The value of the connect_timeout option is now used as default value for the negotiation timeout.

Own Id: OTP-17707 Aux Id: ERIERL-706

Improvements and New Features

Add better error handling in connect/2,3,4. Detect incorrect arguments and return an informative error tuple instead of throwing a function_clause or similar.

Own Id: OTP-17515 Aux Id: ERIERL-648

Make ssh algorithm selection better handle dynamic changes changes in crypto fips mode.

Own Id: OTP-17795

Ssh 4.12.5

Fixed Bugs and Malfunctions

Fixed a race condition in the acceptor loop: if a client disconnected immediately after the tcp connect, the server could cease handling connection on that address:port.

Own Id: OTP-17764 Aux Id: ERIERL-726

Ssh 4.12.4

Fixed Bugs and Malfunctions

Fixed that a slow start (>30s) of a client subsystem could cause a log entry with the password.

Own Id: OTP-17390 Aux Id: ERIERL-648

Fixed an error when running as an sftp server and a client requests a directory contents listing.

The fix is to handle the error code {error, eacces} as {error, enoent} in the ssh_sftpd:get_attrs/5 internal function; that is, just skip it.

Own Id: OTP-17586 Aux Id: GH-5014

Improvements and New Features

The "Key exchange failed" Info Report is now more informative.

Own Id: OTP-17450 Aux Id: ERIERL-655

Ssh 4.12.3

Fixed Bugs and Malfunctions

Filter out sensitive data (passwords etc) from progress reports and supervisor reports.

Own Id: OTP-17468 Aux Id: ERIERL-656

Ssh 4.12.2

Fixed Bugs and Malfunctions

Avoid an extra blank line in the ssh known_hosts file

Own Id: OTP-17427

Ssh 4.12.1

Improvements and New Features

Add missing known_hosts and authorized_keys file types to ssh_file:decode/2 and ssh_file:encode/2.

Own Id: OTP-17397

Ssh 4.12

Fixed Bugs and Malfunctions

Missing runtime dependencies has been added to this application.

Own Id: OTP-17243 Aux Id: PR-4557

The send window handling is changed to not initialize a too large window on some occasions.

Own Id: OTP-17353

Improvements and New Features

Removed usage of erlang:is_port/1 from the SSH implementation.

Own Id: OTP-16750

Internal connection setup refactoring.

Own Id: OTP-17051

Refactor SSH fsm into a (hopefully) more comprehensible set of gen_statem callback-files.

Own Id: OTP-17140

The RSA SHA1 sign/verify variants are disabled by default. That is, ssh-rsa is disabled by default as well as the SHA1 sign/verify with RSA keys from id_rsa and ssh_host_rsa_key. All SHA2 sign/verify are enabled by default.

The reason is that SHA1 is now considered easy to break.

To enable RSA with SHA1, for example for a very old and unsafe peer, see Example 9 in the User's Guide chapter Configuring algorithms in SSH.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-17259 Aux Id: OTP-16511, ERIERL-619

Adapt ssh supervisors to the new 'significant' and 'auto_shutdown' flags in supervisor.

Own Id: OTP-17322 Aux Id: PR-4638, EEP-56, OTP-17334

The functions public_key:ssh_encode/2, public_key:ssh_decode/2, public_key:ssh_hostkey_fingerprint/1 and public_key:ssh_hostkey_fingerprint/2 are deprecated.

Replacement functions are available in SSH, see the Deprecations chapter in the Erlang/OTP documentation.

Own Id: OTP-17352

Ssh 4.11.1.7

Fixed Bugs and Malfunctions

With this change (being response to CVE-2023-48795), ssh can negotiate "strict KEX" OpenSSH extension with peers supporting it; also 'chacha20-poly1305@openssh.com' algorithm becomes a less preferred cipher.

If strict KEX availability cannot be ensured on both connection sides, affected encryption modes(CHACHA and CBC) can be disabled with standard ssh configuration. This will provide protection against vulnerability, but at a cost of affecting interoperability. See Configuring algorithms in SSH User's Guide.

Thanks to Fabian Bäumer, Marcus Brinkmann and Jörg Schwenk.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-18897

With this change, KEX strict terminal message is emitted with debug verbosity.

Own Id: OTP-19002 Aux Id: ERIERL-1041

Ssh 4.11.1.6

Fixed Bugs and Malfunctions

Binaries can be limited in logs with the parameter max_log_item_len. The default value is 500 bytes.

Own Id: OTP-18094

Ssh 4.11.1.5

Fixed Bugs and Malfunctions

Fixed problem with blocked server after multiple restarts. Applies to daemons with options {parallel_login,true} and also {max_sessions, int()>0}.

Own Id: OTP-17835 Aux Id: ERIERL-721

Ssh 4.11.1.4

Fixed Bugs and Malfunctions

The value of the connect_timeout option is now used as default value for the negotiation timeout.

Own Id: OTP-17707 Aux Id: ERIERL-706

Ssh 4.11.1.3

Fixed Bugs and Malfunctions

Filter out sensitive data (passwords etc) from progress reports and supervisor reports.

Own Id: OTP-17468 Aux Id: ERIERL-656

Improvements and New Features

The "Key exchange failed" Info Report is now more informative.

Own Id: OTP-17450 Aux Id: ERIERL-655

Ssh 4.11.1.2

Fixed Bugs and Malfunctions

Avoid an extra blank line in the ssh known_hosts file

Own Id: OTP-17427

Ssh 4.11.1.1

Fixed Bugs and Malfunctions

Fixed that a slow start (>30s) of a client subsystem could cause a log entry with the password.

Own Id: OTP-17390 Aux Id: ERIERL-648

Ssh 4.11.1

Fixed Bugs and Malfunctions

The idle_time timer was not cancelled when a channel was opened within the timeout time on an empty connection that have had channels previously.

Own Id: OTP-17279

Ssh 4.11

Improvements and New Features

The long name field in SSH_FXP_NAME responses to display file information in sftp version 3 now contains the expanded format defined in the sftp draft. It is similar to what is returned by "ls -l" on Unix systems.

Own Id: OTP-17197 Aux Id: PR- 3049

Ssh 4.10.8

Fixed Bugs and Malfunctions

Don't timeout slow connection setups and tear-downs. A rare crash risk for the controller is also removed.

Own Id: OTP-17173 Aux Id: ERIERL-581

Ssh 4.10.7

Fixed Bugs and Malfunctions

The SSH daemon erroneously replaced LF with CRLF also when there was no pty requested from the server.

Own Id: OTP-17108 Aux Id: ERL-1442

Ssh 4.10.6

Fixed Bugs and Malfunctions

Fixed problems in the ssh cli/shell handling. Most important are:

the ssh:shell function did sometimes cause the input to be echoed twice,

the ssh:shell function didn't transfer the LANG and LC_ALL shell variables to the connected server which sometimes made Unicode handling erroneous,

Unicode was not always transferred correctly to and from the peer.

Own Id: OTP-16799

The SSH protocol message SSH_MSG_DISCONNECT was sometimes sent instead of SSH_MSG_CHANNEL_FAILURE

Own Id: OTP-16900

The ssh_cli module now always sends the exit-status to connected clients so they can use that to check for successful command execution.

Own Id: OTP-16908 Aux Id: PR-2753

Improvements and New Features

A new option pk_check_user enables checking of the client's user name in the server when doing public key authentication.

Own Id: OTP-16889

Ssh 4.10.5

Fixed Bugs and Malfunctions

An ssh-client can take an accepted socket from a listening socket and do an ssh:connect/2 on it.

Multiple clients on sockets accepted from the same listening socket had stopped working. This is corrected now.

Own Id: OTP-17021 Aux Id: ERIERL-567

Ssh 4.10.4.1

Fixed Bugs and Malfunctions

Filter out sensitive data (passwords etc) from progress reports and supervisor reports.

Own Id: OTP-17468 Aux Id: ERIERL-656

Ssh 4.10.4

Fixed Bugs and Malfunctions

The inet option raw was not passed on from the ssh option list to inet.

Own Id: OTP-17016 Aux Id: ERIERL-562

Ssh 4.10.3

Fixed Bugs and Malfunctions

A supervisor sub-tree could be left if the connection handler process is brutally killed. This will make the max_sessions checking option to count the existing sessions erroneously and could finally block further sessions.

Own Id: OTP-17006 Aux Id: ERIERL-556

Ssh 4.10.2

Fixed Bugs and Malfunctions

Fix decoder bug.

Own Id: OTP-16904

Ssh 4.10.1

Fixed Bugs and Malfunctions

Fixed a bug when a message to ssh-agent was divided into separate packets.

Own Id: OTP-16761 Aux Id: PR-2679

Fix a bug that could crash the cli server if a too large cli-window was requested from the client.

Own Id: OTP-16791 Aux Id: ERIERL-520

Improvements and New Features

Increased test coverage.

Own Id: OTP-14106

A chapter about hardening the OTP SSH is added to the User's Guide.

Own Id: OTP-16411

The internal Diffie-Hellman high level API for key generation was slow in old and by OpenSSL now unsupported cryptolib versions (1.0.1 and earlier).

If such a cryptolib is used anyhow, the low-level API is used internally in the crypto application.

Own Id: OTP-16774

A new timeout is defined for daemons: hello_timeout.

The timeout is supposed to be used as a simple DoS attack protection. It closes an incoming TCP-connection if no valid first SSH message is received from the client within the timeout limit after the TCP initial connection setup.

The initial value is 30s by compatibility reasons, but could be lowered if needed, for example in the code or in a config file.

Own Id: OTP-16803

Ssh 4.10

Fixed Bugs and Malfunctions

Fix error in ssh_sftpd typespec.

Own Id: OTP-16363

Improvements and New Features

The plug-in file ssh_file.erl, that is responsible for default file handling, is re-factored, optimized and re-written.

Own Id: OTP-11688 Aux Id: OTP-12699

OpenSSH 6.5 introduced a new file representation of keys called openssh-key-v1.

OTP/SSH had an experimental implementation of this format. That implementation is now improved and supported with the exception of handling encrypted keys.

Own Id: OTP-15434

TCP/IP port forwarding, a.k.a tunneling a.k.a tcp-forward/direct-tcp is implemented. In the OpenSSH client, this corresponds to the options -L and -R.

The client or server listens to a specified socket, and when something connects to it with TCP/IP, that connection is forwarded in an encrypted tunnel to the peer. The peer then connects to a predefined IP/port pair and then acts as a proxy.

See the manual, ssh:tcpip_tunnel_to_server/6 and ssh:tcpip_tunnel_from_server/6.

The functionality is disabled per default but can be enabled when starting a daemon.

Own Id: OTP-15998 Aux Id: PR-2376, PR-2368

The client-side of the supervisor tree (under sshc_sup) was previously not complete; the channel handling processes were handled with links but had no supervisors.

This is now corrected with a client-side supervisor tree under sshc_sup, similar to the server-side supervisor tree under sshd_sup.

Own Id: OTP-16026 Aux Id: PR-2368, (OTP-15998)

The extension posix-rename@openssh.com is added to the ssh/sftp rename operation.

Own Id: OTP-16289 Aux Id: PR-2448

Calls of deprecated functions in the Old Crypto API are replaced by calls of their substitutions.

Own Id: OTP-16346

The default known_hosts file handling is improved to include ports.

The handling of the contents in that file is updated to support the full syntax, with exception of 1) the wildcard '?', 2) wildcards in canonical names and 3) the option '@cert-authority'

Own Id: OTP-16506

The MAC (Message Authorization Code) algorithms

hmac-sha1-etm@openssh.com

hmac-sha2-256-etm@openssh.com

hmac-sha2-512-etm@openssh.com

are implemented.

Own Id: OTP-16508

The key-exchange algorithms 'diffie-hellman-group14-sha1' and 'diffie-hellman-group-exchange-sha1' are disabled per default. The reason is that SHA1 now is considered insecure.

They can be enabled if needed, see SSH (App).

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-16509

The public key algorithm 'ssh-dss' is disabled per default. The reason is that it is now considered as insecure.

It can be enabled if needed, see SSH (App).

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-16510

The public key 'ssh-rsa' is now considered as insecure because of its usage of SHA1.

It is therefore deprecated and will no longer be enabled per default in OTP-24.0.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-16511

An option optimize (optimize_key_lookup) is introduced for the file interface ssh_file.erl

The option enables the user to select between the default handling which is fast but memory consuming vs memory efficient but not as fast. The effect might be observable only for large files.

See the manual for ssh_file:is_host_key/5 and ssh_file:is_auth_key/3.

Own Id: OTP-16512

The ssh agent is now implemented in the ssh_agent key callback module.

Enable with the the option {key_cb, {ssh_agent, []}} in for example ssh:connect/3.

See the ssh_agent manual for details.

Own Id: OTP-16513

Algorithm configuration could now be done in a .config file.

This is useful for example to enable an algorithm that is disabled by default. It could now be enabled in an .config-file without changing the code,

See the SSH User's Guide chapter "Configuration in SSH".

Own Id: OTP-16540

Documented which gen_tcp socket options can't be used in calls to ssh:connect and ssh:daemon.

Own Id: OTP-16589

Added kb_int_fun_4() to the authentication_daemon_options() to enable generating dynamic keyboard-interactive prompts from the user's state returned from the authentication fun pwdfun_4().

Own Id: OTP-16622 Aux Id: PR-2604

Ssh 4.9.1.5

Fixed Bugs and Malfunctions

With this change (being response to CVE-2023-48795), ssh can negotiate "strict KEX" OpenSSH extension with peers supporting it; also 'chacha20-poly1305@openssh.com' algorithm becomes a less preferred cipher.

If strict KEX availability cannot be ensured on both connection sides, affected encryption modes(CHACHA and CBC) can be disabled with standard ssh configuration. This will provide protection against vulnerability, but at a cost of affecting interoperability. See Configuring algorithms in SSH User's Guide.

Thanks to Fabian Bäumer, Marcus Brinkmann and Jörg Schwenk.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-18897

With this change, KEX strict terminal message is emitted with debug verbosity.

Own Id: OTP-19002 Aux Id: ERIERL-1041

Ssh 4.9.1.4

Fixed Bugs and Malfunctions

The value of the connect_timeout option is now used as default value for the negotiation timeout.

Own Id: OTP-17707 Aux Id: ERIERL-706

Ssh 4.9.1.3

Fixed Bugs and Malfunctions

The idle_time timer was not cancelled when a channel was opened within the timeout time on an empty connection that have had channels previously.

Own Id: OTP-17279

Ssh 4.9.1.2

Fixed Bugs and Malfunctions

Fix decoder bug.

Own Id: OTP-16904

Ssh 4.9.1.1

Fixed Bugs and Malfunctions

Fix a bug that could crash the cli server if a too large cli-window was requested from the client.

Own Id: OTP-16791 Aux Id: ERIERL-520

Improvements and New Features

A new timeout is defined for daemons: hello_timeout.

It closes an incoming TCP-connection if no valid 1st message is received from the client within the timeout limit.

Own Id: OTP-16803

Ssh 4.9.1

Fixed Bugs and Malfunctions

Potential hazard between re-keying decision and socket close.

Own Id: OTP-16462 Aux Id: ERIERL-464

Ssh 4.9

Fixed Bugs and Malfunctions

Unicode problems for ssh_sftp:write fixed.

Own Id: OTP-16377

Improvements and New Features

Changes to the internal api of the experimental ssh_dbg tool.

Own Id: OTP-16353

The new functions ssh:set_sock_opts/2 and ssh:get_sock_opts/2 sets and reads option values for the underlying TCP stream.

Own Id: OTP-16485

Ssh 4.8.2

Fixed Bugs and Malfunctions

Fixed that ssh_connection:send could allocate a large amount of memory if given an iolist() as input data.

Own Id: OTP-16373

Safe atom conversions.

Own Id: OTP-16375

Constant time comparisons added.

Own Id: OTP-16376

Ssh 4.8.1

Fixed Bugs and Malfunctions

The ssh cli (e.g shell) server behaved strangely when characters were inserted in a string such that the last characters tried to wrap the line.

Own Id: OTP-14849 Aux Id: ERL-545

If an OTP SSH server was serving an "exec" request and the executed code used Erlang standard_io for input/output, the I/O was erroneously handled by the server's group leader, so the I/O turned up in the the server's Erlang shell (if any). The user at the client side did therefore not see that I/O.

This is corrected now, so the client - for example the ssh OS shell command - handles the I/O. The user could send input to the server side exec handling code by writing on the terminal, and server side output from for example io:format is presented on the terminal - not only the functional result.

NOTE 1: Servers executing exec requests with the old, undocumented ways of specifying the custom exec handler is not changed. Changed are only the two cases where the server's 'exec' option either:

is not specified (i.e. using the default shell) or,

it has the {direct, fun(...) -> ... end} value format.

NOTE 2: Previously an end-of-line marker was appended on the result and error reports at the client side. They are removed now and the error reports are slightly enhanced.

TECHNICAL DETAILS: The server's device standard_input receives data events from the exec request's channel, and the device standard_output is sending its data by data events to the client on that channel. The result is that standard_io is now performed by the client's group leader.

Own Id: OTP-15417 Aux Id: OTP-16108

The functions ssh:shell/1,2,3 left the connection open when they returned. That leakage is fixed now.

Own Id: OTP-16047

Corrected that an Erlang SSH server could return the status code 4294967295 instead of 255 on some errors of an exec request.

Own Id: OTP-16123

Improvements and New Features

Internal simplification of ssh_sftp/ssh_xfer

Own Id: OTP-15972

The documentation of One-Time Execution in the User's Guide is updated with more examples.

Own Id: OTP-16108 Aux Id: OTP-15417

The new value 'disabled' is introduced in the SSH daemon options 'exec' and 'shell'. Previously they lacked a clear way of disabling them.

Own Id: OTP-16113

The old algorithms 'aes192_cbc', 'aes256_cbc' and 'hmac-sha1-96' are added for compatibility with older peers.

The mac 'hmac-sha1-96' is nowadays not recommended and must therefore be explicitly enabled. Use for example the Option value {modify_algorithms, [{append, [{mac,['hmac-sha1-96']}]}]}

Own Id: OTP-16170

Ssh 4.8

Fixed Bugs and Malfunctions

Fixed wrong type definition for the daemon option subsystems.

Own Id: OTP-15820

Fixed a possible SSH logging crash if there was a problem in an early stage of session setup.

Own Id: OTP-15962 Aux Id: ERL-990

Improvements and New Features

The documentation for the modules ssh_connection, ssh_sftp and ssh_sftpd are now generated from the -spec:s.

Own Id: OTP-15395

Internal cleanup including removal of the internal file ssh_userauth.hrl.

Own Id: OTP-15876 Aux Id: PR-2255, PR-2256

Removed unused definitions in ssh.hrl.

Own Id: OTP-15929 Aux Id: PR-2297

Removed unused fields in the internal #connection{} record.

Own Id: OTP-15984

To get information of a connection_ref() from for example ssh:connect/3, there was previously one function available namely ssh:connection_info/2. This ticket adds ssh:connection_info/1 which returns all information.

For daemons (servers) started with for example ssh:daemon/2 the function ssh:daemon_info/1 returning all information was available. This ticket adds ssh:daemon_info/2 which returns only the information specified in the second argument.

The info of connections and of daemons now also includes the item 'options'. Only those options that does not have their default values are returned.

For a connection also the items 'algorithms' and 'channels' are added.

Own Id: OTP-16040

Ssh 4.7.7

Improvements and New Features

SSH uses the new crypto API.

Own Id: OTP-15673

Ssh 4.7.6.6

Fixed Bugs and Malfunctions

The idle_time timer was not cancelled when a channel was opened within the timeout time on an empty connection that have had channels previously.

Own Id: OTP-17279

Ssh 4.7.6.5

Fixed Bugs and Malfunctions

Fix decoder bug.

Own Id: OTP-16904

Ssh 4.7.6.4

Fixed Bugs and Malfunctions

Potential hazard between re-keying decision and socket close.

Own Id: OTP-16462 Aux Id: ERIERL-464

Ssh 4.7.6.3

Fixed Bugs and Malfunctions

Fixed that ssh_connection:send could allocate a large amount of memory if given an iolist() as input data.

Own Id: OTP-16373

Safe atom conversions.

Own Id: OTP-16375

Constant time comparisons added.

Own Id: OTP-16376

Ssh 4.7.6.2

Fixed Bugs and Malfunctions

The ssh cli (e.g shell) server behaved strangely when characters were inserted in a string so that the last characters tried to wrap the line.

Own Id: OTP-14849 Aux Id: ERL-545

Ssh 4.7.6.1

Fixed Bugs and Malfunctions

Fixed a possible SSH logging crash if there was a problem in an early stage of session setup.

Own Id: OTP-15962 Aux Id: ERL-990

Ssh 4.7.6

Improvements and New Features

When an SSH server receives the very first message on a new TCP connection, and that message is not the expected one, the 64 first bytes of the received message are now dumped in the INFO REPORT that reports the Protocol Error.

This facilitates the debugging of who sends the bad message or of detecting a possible port scanning.

Own Id: OTP-15772

Ssh 4.7.5

Fixed Bugs and Malfunctions

The callback ssh_channel:init/1 was missing in OTP-21

Own Id: OTP-15762

If a client was connected to an server on an already open socket, the callback fun(PeerName,FingerPrint) in the accept_callback option passed the local name in the argument PeerName instead of the remote name.

Own Id: OTP-15763

Ssh 4.7.4

Fixed Bugs and Malfunctions

SSH sftp daemon now accepts an SSH_FXP_STAT message encoded according to the wrong sftp version. Some clients sends such messages.

Own Id: OTP-15498 Aux Id: ERL-822, PR-2077

Ssh 4.7.3

Fixed Bugs and Malfunctions

Fixed port leakage if a ssh:daemon call failed.

Own Id: OTP-15397 Aux Id: ERL-801

Ssh 4.7.2

Fixed Bugs and Malfunctions

Incompatibility with newer OpenSSH fixed. Previously versions 7.8 and later could cause Erlang SSH to exit.

Own Id: OTP-15413

The 'exec' option for ssh daemons had wrong format in the documentation.

Own Id: OTP-15416

Improvements and New Features

Added public key methods ssh-ed25519 and ssh-ed448.

Requires OpenSSL 1.1.1 or higher as cryptolib under the OTP application crypto.

Own Id: OTP-15094 Aux Id: OTP-15419

The SSH property tests are now adapted to the PropEr testing tool.

Own Id: OTP-15312

The term "user" was not documented in the SSH app. A new chapter with terminology is added to the User's Manual where the term "user" is defined.

A reference manual page about the module ssh_file is also added. This is the default callback module for user's keys, host keys etc.

Own Id: OTP-15314

Host and user key checking is made more robust.

Own Id: OTP-15424

Ssh 4.7.1

Improvements and New Features

Extended the undocumented ssh_dbg debug module with an api for a circular trace buffer. This makes it easy to record the last low-level events before an error is detected. It is intended for solving difficult errors.

Own Id: OTP-15020

The key exchange methods 'curve25519-sha256@libssh.org', 'curve25519-sha256' and 'curve448-sha512' are implemented. The last two are defined in https://tools.ietf.org/html/draft-ietf-curdle-ssh-curves

They all depends on that OpenSSL 1.1.1 or higher is used as cryptolib.

Own Id: OTP-15133 Aux Id: OTP-15240

The cipher 'chacha20-poly1305@openssh.com' is now supported if OpenSSL 1.1.1 or higher is used as cryptolib.

Own Id: OTP-15209 Aux Id: OTP-15164

Ssh 4.7

Fixed Bugs and Malfunctions

If the daemon port listener is restarted, it could potentially fail with eaddrinuse if the timing is unlucky. It will now retry and exponentially back off the listener restart a few times before failing.

Own Id: OTP-14955

A channel callback module always got the module name as reason in a call to terminate. Now it will get the proper Reason, usually 'normal'.

Own Id: OTP-15084

Improvements and New Features

The option exec has new option values defined to make it much more easy to implement an own exec server.

An option called exec for daemons implementing the handling of 'exec' requests has existed a long time but has been undocumented. The old undocumented value - as well as its behavior - is kept for compatibility EXCEPT that error messages are changed and are sent as "stderror" text.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-14851

Updated ssh_connection:shell/2 documentation.

Own Id: OTP-14880

The experimental ssh_dbg module is completely re-written. Its purpose is to make tracing and debugging easier on deployed systems.

Own Id: OTP-14896

The SSH supervisor structure has been slightly changed. This makes stopping the ssh application considerably faster if there are open connections. This is important in for example restarts.

Own Id: OTP-14988

The type specifications in SSH are completely reworked and the following types are renamed:

ssh:ssh_connection_ref() is changed to ssh:connection_ref(),

ssh:ssh_daemon_ref() is changed to ssh:daemon_ref(),

ssh:ssh_channel_id() is changed to ssh:channel_id().

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-15002 Aux Id: OTP-15030

The internal timer handling in SSH is now based on the gen_statem timers.

Own Id: OTP-15019

Removed the undocumented and unused modules ssh_client_key.erl and ssh_server_key.erl.

Own Id: OTP-15028

The Reference Manual pages are partly updated.

The ssh page is now generated from specs and types, is restructured and is partly rephrased.

The ssh_channel, ssh_connection, ssh_client_key_api, ssh_server_key_api and ssh_sftp pages are updated with links, correct type names and some minor changes.

Own Id: OTP-15030 Aux Id: OTP-15002

The behaviors ssh_channel and ssh_daemon_channel are renamed to ssh_client_channel and ssh_server_channel respectively.

The old modules are kept for compatibility but should preferably be replaced when updating callback modules referring them.

Own Id: OTP-15041

New test suite for channels.

Own Id: OTP-15051

The rekey_limit option could now set the max time as well as the previously max data amount.

Own Id: OTP-15069 Aux Id: ERL-617

Changed process exit supervision from links to monitors.

Own Id: OTP-15082

Better handling of misbehaving channel callback modules.

Own Id: OTP-15083

A new moduli file is generated. This file is used for the recommended diffie-hellman-group-exchange-sha256 key exchange algorithm in SSH.

Own Id: OTP-15113

Ssh 4.6.9.7

Fixed Bugs and Malfunctions

Fixed possible hanging in ssh_sftp:stop_channel/1.

Own Id: OTP-16507 Aux Id: ERIERL-470

Ssh 4.6.9.6

Fixed Bugs and Malfunctions

Fixed that ssh_connection:send could allocate a large amount of memory if given an iolist() as input data.

Own Id: OTP-16373

Safe atom conversions.

Own Id: OTP-16375

Constant time comparisons added.

Own Id: OTP-16376

Ssh 4.6.9.5

Fixed Bugs and Malfunctions

The ssh cli (e.g shell) server behaved strangely when characters were inserted in a string so that the last characters tried to wrap the line.

Own Id: OTP-14849 Aux Id: ERL-545

Ssh 4.6.9.4

Fixed Bugs and Malfunctions

If a client was connected to an server on an already open socket, the callback fun(PeerName,FingerPrint) in the accept_callback option passed the local name in the argument PeerName instead of the remote name.

Own Id: OTP-15763

Ssh 4.6.9.3

Fixed Bugs and Malfunctions

Fixed port leakage if a ssh:daemon call failed.

Own Id: OTP-15397 Aux Id: ERL-801

Ssh 4.6.9.2

Fixed Bugs and Malfunctions

Incompatibility with newer OpenSSH fixed. Previously versions 7.8 and later could cause Erlang SSH to exit.

Own Id: OTP-15413

Ssh 4.6.9.1

Fixed Bugs and Malfunctions

SFTP clients reported the error reason "" if a non-OTP sftp server was killed during a long file transmission.

Now the signal name (for example "KILL") will be the error reason if the server's reason is empty.

The documentation also lacked type information about this class of errors.

Own Id: OTP-15148 Aux Id: ERIERL-194

Fix ssh_sftp decode error for sftp protocol version 4

Own Id: OTP-15149 Aux Id: ERIERL-199

Ssh 4.6.9

Fixed Bugs and Malfunctions

Host key hash erroneously calculated for clients following draft-00 of RFC 4419, for example PuTTY

Own Id: OTP-15064

Renegotiation could fail in some states

Own Id: OTP-15066

Ssh 4.6.8

Fixed Bugs and Malfunctions

An ssh_sftp server (running version 6) could fail if it is told to remove a file which in fact is a directory.

Own Id: OTP-15004

Fix rare spurious shutdowns of ssh servers when receiving {'EXIT',_,normal} messages.

Own Id: OTP-15018

Ssh 4.6.7

Fixed Bugs and Malfunctions

Fix bad spec in ssh.hrl: double_algs().

Own Id: OTP-14990

Ssh 4.6.6

Fixed Bugs and Malfunctions

Remove a blocking risk when a channel is closed and an operation is tried on that channel after at least a second's time gap.

Own Id: OTP-14939

Improvements and New Features

Added ssh_compat_SUITE.

This suite contains a number of interoperability tests mainly with OpenSSH. The tests start docker containers with different OpenSSH and OpenSSL/LibreSSLcryptolib versions and performs a number of tests of supported algorithms.

All login methods and all user's public key types are tested both for the client and the server.

All algorithms for kex, cipher, host key, mac and compressions are tested with a number of exec and sftp tests, both for the client and the server.

Own Id: OTP-14194 Aux Id: OTP-12487

Default exec is disabled when a user-defined shell is enabled.

Own Id: OTP-14881

Ssh 4.6.5

Fixed Bugs and Malfunctions

Adjusted supervisor timeouts

Own Id: OTP-14907

Remove ERROR messages for slow process exits

Own Id: OTP-14930

Improvements and New Features

Add option save_accepted_host to ssh:connection. This option, if set to false, inhibits saving host keys to e.g the file known_hosts.

Own Id: OTP-14935

Ssh 4.6.4

Fixed Bugs and Malfunctions

Fix problem with OpenSSH 7.2 (and later) clients that has used sha1 instead of sha2 for rsa-sha-256/512 user's public keys.

Own Id: OTP-14827 Aux Id: ERL-531

Ssh 4.6.3

Fixed Bugs and Malfunctions

Passphrase option for ecdsa public keys was missing.

Own Id: OTP-14602

Improvements and New Features

The host and user public key handling is hardened so that a faulty plugin can't deliver a key of wrong type.

Better checks in the server of the available hostkey's types at start and at each accept.

Better checks in the client of the available user public key types at connect.

Own Id: OTP-14676 Aux Id: ERIERL-52, OTP-14570

SSH can now fetch the host key from the private keys stored in an Engine. See the crypto application for details about Engines.

Own Id: OTP-14757

Ssh 4.6.2

Fixed Bugs and Malfunctions

Trailing white space was removed at end of the hello-string. This caused interoperability problems with some other ssh-implementations (e.g OpenSSH 7.3p1 on Solaris 11)

Own Id: OTP-14763 Aux Id: ERIERL-74

Fixes that tcp connections that was immediately closed (SYN, SYNACK, ACK, RST) by a client could be left in a zombie state.

Own Id: OTP-14778 Aux Id: ERIERL-104

Ssh 4.6.1

Fixed Bugs and Malfunctions

Fixed broken printout

Own Id: OTP-14645

Improvements and New Features

Disable aes_gcm ciphers if peer is OpenSSH 6.2 which is known to have trouble with them in some cases.

Own Id: OTP-14638

Ssh 4.6

Fixed Bugs and Malfunctions

Enables the ssh_io module to also accept binary values when reading standard_io instead of getting stuck in the receive clause.

Own Id: OTP-14506 Aux Id: PR1503

Previously, the file owner access permission in response to ssh_sftp:read_file_info/2 function was always read_write. With this fix, the actual value of file owner access permission is added to the returning record. That value is calculated from file mode value.

Own Id: OTP-14550 Aux Id: PR1533

Improvements and New Features

A new option modify_algorithms is implemented. It enables specifying changes on the default algorithms list. See the reference manual and the SSH User's Guide chapter "Configuring algorithms in SSH".

Own Id: OTP-14568

Ssh 4.5.1

Fixed Bugs and Malfunctions

All unknown options are sent to the transport handler regardless of type.

Own Id: OTP-14541 Aux Id: EIRERL-63

Ssh 4.5

Improvements and New Features

The internal handling of SSH options is re-written.

Previously there were no checks if a client option was given to a daemon or vice versa. This is corrected now. If your code has e.g. a client-only option in a call to start a daemon, the call will fail.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-12872

Modernization of key exchange algorithms. See draft-ietf-curdle-ssh-kex-sha2 for a discussion.

Removed an outdated weak algorithm and added stronger replacements to keep interoperability with other modern ssh clients and servers. The default ordering of the algorithms is also adjusted.

Retired: The nowadays unsecure key-exchange diffie-hellman-group1-sha1 is not enabled by default, but can be enabled with the option preferred-algorithms.

Added: The new stronger key-exchange diffie-hellman-group16-sha512, diffie-hellman-group18-sha512 and diffie-hellman-group14-sha256 are added and enabled by default.

The questionable [RFC 6194] sha1-based algorithms diffie-hellman-group-exchange-sha1 and diffie-hellman-group14-sha1 are however still kept enabled by default for compatibility with ancient clients and servers that lack modern key-exchange alternatives. When the draft-ietf-curdle-ssh-kex-sha2 becomes an rfc, those sha1-based algorithms and diffie-hellman-group1-sha1 will be deprecated by IETF. They might then be removed from the default list in Erlang/OTP.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-14110

Modernized internal representation of sftp by use of maps.

Own Id: OTP-14117

The Extension Negotiation Mechanism and the extension server-sig-algs in draft-ietf-curdle-ssh-ext-info-05 are implemented.

The related draft-ietf-curdle-rsa-sha2-05 is implemented and introduces the signature algorithms rsa-sha2-256 and rsa-sha2-512.

Own Id: OTP-14193

The 'timeout' and 'connect_timeout' handling in ssh_sftp:start_channel documentation is clarified.

Own Id: OTP-14216

The functions ssh:connect, ssh:shell and ssh:start_channel now accept an IP-tuple as Host destination argument.

Own Id: OTP-14243

The function ssh:daemon_info/1 now returns Host and Profile as well as the Port info in the property list.

Own Id: OTP-14259

Removed the option public_key_alg which was deprecated in 18.2. Use pref_public_key_algs instead.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-14263

The SSH application is refactored regarding daemon starting. The resolution of contradicting Host argument and ip option were not described. There were also strange corner cases when the 'any' value was used in Host argument or ip option. This is (hopefully) resolved now, but it may cause incompatibilities for code using both Host and the ip option. The value 'loopback' has been added for a correct way of naming those addresses.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-14264

The supervisor code is refactored. The naming of listening IP-Port-Profile triples are slightly changed to improve consistency in strange corner cases as resolved by OTP-14264

Own Id: OTP-14267 Aux Id: OTP-14266

The idle_time option can now be used in daemons.

Own Id: OTP-14312

Added test cases for IETF-CURDLE Extension Negotiation (ext-info)

Own Id: OTP-14361

Testcases for IETF-CURDLE extension server-sig-algs including rsa-sha2-*

Own Id: OTP-14362 Aux Id: OTP-14361

The option auth_methods can now also be used in clients to select which authentication options that are used and in which order.

Own Id: OTP-14399

Checks that a ECDSA public key (ecdsa-sha2-nistp*) stored in a file has the correct size.

Own Id: OTP-14410

Ssh 4.4.2.4

Fixed Bugs and Malfunctions

Fix rare spurious shutdowns of ssh servers when receiving {'EXIT',_,normal} messages.

Own Id: OTP-15018

Host key hash erroneously calculated for clients following draft-00 of RFC 4419, for example PuTTY

Own Id: OTP-15064

Renegotiation could fail in some states

Own Id: OTP-15066

Ssh 4.4.2.3

Fixed Bugs and Malfunctions

An ssh_sftp server (running version 6) could fail if it is told to remove a file which in fact is a directory.

Own Id: OTP-15004

Ssh 4.4.2.2

Improvements and New Features

Default exec is disabled when a user-defined shell is enabled.

Own Id: OTP-14881

Ssh 4.4.2.1

Fixed Bugs and Malfunctions

Trailing white space was removed at end of the hello-string. This caused interoperability problems with some other ssh-implementations (e.g OpenSSH 7.3p1 on Solaris 11)

Own Id: OTP-14763 Aux Id: ERIERL-74

Ssh 4.4.2

Fixed Bugs and Malfunctions

ssh:daemon_info/1 crashed if the listening IP was not 'any'

Own Id: OTP-14298 Aux Id: seq13294

Ssh 4.4.1

Fixed Bugs and Malfunctions

Fix bug when opening connections. If the tcp setup failed, that would in some cases not result in an error return value.

Own Id: OTP-14108

Reduce information leakage in case of decryption errors.

Own Id: OTP-14109

The key exchange algorithm diffie-hellman-group-exchange-sha* has a server-option {dh_gex_limits,{Min,Max}}. There was a hostkey signature validation error on the client side if the option was used and the Min or the Max differed from the corresponding values obtained from the client.

This bug is now corrected.

Own Id: OTP-14166

The sftpd server now correctly uses root_dir and cwd when resolving file paths if both are provided. The cwd handling is also corrected.

Thanks to kape1395!

Own Id: OTP-14225 Aux Id: PR-1331, PR-1335

Ssh_cli used a function that does not handle non-utf8 unicode correctly.

Own Id: OTP-14230 Aux Id: ERL-364

Improvements and New Features

The implementation of the key exchange algorithms diffie-hellman-group-exchange-sha* are optimized, up to a factor of 11 for the slowest ( = biggest and safest) group size.

Own Id: OTP-14169 Aux Id: seq-13261

The ssh host key fingerprint generation now also takes a list of algorithms and returns a list of corresponding fingerprints. See public_key:ssh_hostkey_fingerprint/2 and the option silently_accept_hosts in ssh:connect.

Own Id: OTP-14223

Ssh 4.4

Fixed Bugs and Malfunctions

A file read with an sftp client could loose data if the packet_size is set to larger than 64k. This is corrected now in such a way that the packet_size is silently lowered if there is a risk for data loss.

Own Id: OTP-13857 Aux Id: ERL-238, OTP-13858

When user defined SSH shell REPL process exits with reason normal, the SSH channel callback module should report successful exit status to the SSH client. This provides simple way for SSH clients to check for successful completion of executed commands. (Thanks to isvilen)

Own Id: OTP-13905 Aux Id: PR-1173

Improvements and New Features

Extended the option silently_accept_hosts for ssh:connect to make it possible for the client to check the SSH host key fingerprint string. Se the reference manual for SSH.

Own Id: OTP-13887 Aux Id: OTP-13888

Ssh 4.3.6

Fixed Bugs and Malfunctions

Re-negotiation problems with OpenSSH client solved.

Own Id: OTP-13972

Ssh 4.3.5

Fixed Bugs and Malfunctions

If a client illegaly sends an info-line and then immediately closes the TCP-connection, a badmatch exception was raised.

Own Id: OTP-13966

Ssh 4.3.4

Fixed Bugs and Malfunctions

Intermittent ssh ERROR REPORT mentioning nonblocking_sender

Own Id: OTP-13953 Aux Id: seq13199

Ssh 4.3.3

Fixed Bugs and Malfunctions

Handle all possible exit values that should be interpreted as {error, closed}. Failing to do so could lead to unexpected crashes for users of the ssh application.

Own Id: OTP-13932 Aux Id: seq13189

Ssh 4.3.2

Fixed Bugs and Malfunctions

Upgrade of an established client connection could crash because the ssh client supervisors children had wrong type. This is fixed now.

Own Id: OTP-13782 Aux Id: seq13158

Partly checks the public key early in public key authorization

Own Id: OTP-13847 Aux Id: defensics-ssh3.1.0-190243,205277,219318

Corrected handling of SHA for ECDSA (Elliptic curve public keys)

Own Id: OTP-13850 Aux Id: defensics-ssh3.1.0-214168

Problems found by test suites as well as by Codenomicon/Defensics fixed: - reduce max random padding to 15 bytes (Codenomicon/Defensics) - inclomplete pdu handling (Codenomicon/Defensics) - badmatch in test suite - non-blocking send fixes deadlock in ssh_connection_SUITE:interrupted_send

Own Id: OTP-13854

Caller is now notified when a tcp close is received.

Own Id: OTP-13859 Aux Id: seq13177

Improvements and New Features

Use application:ensure_all_started/2 instead of hard-coding deps

Own Id: OTP-13843 Aux Id: PR-1147

Ssh 4.3.1

Fixed Bugs and Malfunctions

SSH client does not any longer retry a bad password given as option to ssh:connect et al.

Own Id: OTP-13674 Aux Id: TR-HU92273

Removed possible hanging risk for a certain timing sequence when communicating client and server executes on the same node.

Own Id: OTP-13715

Ssh 4.3

Improvements and New Features

A socket created and connected by gen_tcp could now be used as input to ssh:connect, ssh:shell, ssh_sftp:start_channel and ssh:daemon.

Own Id: OTP-12860

Some time optimization mainly in message encoding.

Own Id: OTP-13131

Optimized the sftp client time by setting new packet and window sizes.

Own Id: OTP-13175

The ssh_connection_handler module in SSH is changed and now uses the new behaviour gen_statem.

The module can be used as an example of a gen_statem callback module but with a warning: This commit of ssh is just a straightforward port from gen_fsm to gen_statem with some code cleaning. Since the state machine and the state callbacks are almost unchanged the ssh module does not demonstrate the full potential of the new behaviour.

The "new" state machine uses compound states. The ssh server and client state machines are quite similar but differences exist. With gen_fsm there were flags in the user data which in fact implemented "substates". Now with gen_statem those are made explicit in the state names, eg. the state userauth and the binary role-flag becomes the two state names {userauth, server} and {userauth, client}.

Own Id: OTP-13267

The {error, Reason} tuples returned from ssh_sftp api functions are described.

Own Id: OTP-13347 Aux Id: ERL-86

Added -spec in ssh

Own Id: OTP-13479

It is now possible to call ssh:daemon/{1,2,3} with Port=0. This makes the daemon select a free listening tcp port before opening it. To find this port number after the call, use the new function ssh:daemon_info/1. See the reference manual for details.

Own Id: OTP-13527

Ssh 4.2.2.6

Fixed Bugs and Malfunctions

Fix rare spurious shutdowns of ssh servers when receiving {'EXIT',_,normal} messages.

Own Id: OTP-15018

Ssh 4.2.2.5

Improvements and New Features

Default exec is disabled when a user-defined shell is enabled.

Own Id: OTP-14881

Ssh 4.2.2.4

Fixed Bugs and Malfunctions

Trailing white space was removed at end of the hello-string. This caused interoperability problems with some other ssh-implementations (e.g OpenSSH 7.3p1 on Solaris 11)

Own Id: OTP-14763 Aux Id: ERIERL-74

Ssh 4.2.2.3

Fixed Bugs and Malfunctions

The key exchange algorithm diffie-hellman-group-exchange-sha* has a server-option {dh_gex_limits,{Min,Max}}. There was a hostkey signature validation error on the client side if the option was used and the Min or the Max differed from the corresponding values obtained from the client.

This bug is now corrected.

Own Id: OTP-14166

Improvements and New Features

Key exchange algorithms diffie-hellman-group-exchange-sha* optimized, up to a factor of 11 for the slowest ( = biggest and safest) one.

Own Id: OTP-14169 Aux Id: seq-13261

Ssh 4.2.2.2

Fixed Bugs and Malfunctions

Upgrade of an established client connection could crash because the ssh client supervisors children had wrong type. This is fixed now.

Own Id: OTP-13782 Aux Id: seq13158

Ssh 4.2.2.1

Fixed Bugs and Malfunctions

SSH client does not any longer retry a bad password given as option to ssh:connect et al.

Own Id: OTP-13674 Aux Id: TR-HU92273

Ssh 4.2.2

Fixed Bugs and Malfunctions

Documentation correction of ssh_sftp:position/4

Thanks to Rabbe Fogelholm.

Own Id: OTP-13305 Aux Id: ERL-87

Ssh 4.2.1

Fixed Bugs and Malfunctions

The authentication method 'keyboard-interactive' failed in the Erlang client when the server after successful authentication continued by asking for zero more passwords.

Own Id: OTP-13225

Ssh 4.2

Fixed Bugs and Malfunctions

Better error handling in ssh_file. There was some rare errors when a NFS-mounted file was opened by ssh_file and then remotely deleted during reading. That caused an endless loop.

That bug is now fixed.

Own Id: OTP-12699 Aux Id: OTP-11688

Fixed a bug in the compression algorithm zlib@openssh.com.

Own Id: OTP-12759

It is now possible to start more than one daemon with a file descriptor given in option fd. Each daemon must of course have a unique file descriptor.

Own Id: OTP-12966 Aux Id: seq12945

Fixed a bug that caused the option dh_gex_limit to be ignored.

Own Id: OTP-13029

A problem is fixed with the ssh:connect option pref_public_key_algs specifying user keys.

Own Id: OTP-13158

Improvements and New Features

Document updates in the ssh reference manual: app doc file and ssh_connection.

Own Id: OTP-12003

The authorization phase is made stateful to prevent ssh acting on messages sent in wrong order.

Own Id: OTP-12787

Testcases for bad message lengths and for bad subfield lengths added.

Own Id: OTP-12792 Aux Id: Codenomicon #5214, 6166

The 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384' and 'ecdsa-sha2-nistp521' signature algorithms for ssh are implemented. See RFC 5656.

Own Id: OTP-12936

The crypto algorithms 'aes192-ctr' and 'aes256-ctr' are implemented. See RFC 4344.

Own Id: OTP-12939

The ciphers and macs AEAD_AES_128_GCM and AEAD_AES_256_GCM are implemented but not enabled per default. See the SSH App Reference Manual and RFC5647 for details.

The ciphers aes128-gcm@openssh.com and aes256-gcm@openssh.com are also implemented and available in the default configuration.

Own Id: OTP-13018

The ssh:daemon option dh_gex_groups is extended to read a user provided ssh moduli file with generator-modulus pairs. The file is in openssh format.

Own Id: OTP-13052 Aux Id: OTP-13054

There is now a file (public_key/priv/moduli) which lists size-generator-modulus triples. The purpose is to give servers the possibility to select the crypto primes randomly among a list of pregenerated triples. This reduces the risk for some attacks on diffie-hellman negotiation.

See the reference manual for public_key:dh_gex_group/4 where the handling of this is described.

The ssh server (ssh:daemon) uses this.

Own Id: OTP-13054 Aux Id: OTP-13052

The ssh:daemon option pwdfun now also takes a fun/4. This enables the user to 1) check userid-password in another way than the builtin algorithm, 2) implement rate limiting per user or source IP or IP+Port, and 3) implement blocking of missbehaving peers.

The old fun/2 still works as previously.

Own Id: OTP-13055 Aux Id: OTP-13053

There is now a new option to make the server limit the size range of moduli available for the diffie-hellman group exchange negotiation. See option {dh_gex_limits,{Min,Max}} in ssh:daemon/3.

Own Id: OTP-13066

Ecdh key exchange now validates compressed and uncompressed keys as defined in rfc5656

Own Id: OTP-13067

Search order for the .ssh directory are changed so $HOME is tried before init:get_argument(home).

Own Id: OTP-13109

The sftp receive window handling is optimized so it will not update the remote end too often. This makes "sftp mget" considerable faster.

Own Id: OTP-13130

The option key_cb is extended to take an optional list that is passed to the callback module as an option. With this it is possible to have different keys depending on which host that is connected. Another possibility is to write a callback module that fetches keys etc from a database.

Thanks to Vipin Nair.

Own Id: OTP-13156

Ssh 4.1.3

Known Bugs and Problems

SSH_MSG_KEX_DH_GEX_REQUEST_OLD implemented to make PuTTY work with erl server.

Own Id: OTP-13140

Ssh 4.1.2

Fixed Bugs and Malfunctions

Add a 1024 group to the list of key group-exchange groups

Own Id: OTP-13046

Ssh 4.1.1

Improvements and New Features

A new option max_channels limits the number of channels with active server-side subsystems that are accepted.

Own Id: OTP-13036

Ssh 4.1

Fixed Bugs and Malfunctions

Send an understandable disconnect message when the key exchange phase can't find a common algorithm. There are also some test cases added.

Own Id: OTP-11531

The third parameter in ssh_sftp:write_file is now accepting iolists again. Unicode handling adjusted.

Own Id: OTP-12853 Aux Id: seq12891

Improvements and New Features

First part of ssh test suite re-organization and extension.

Own Id: OTP-12230

The key exchange algorithms 'ecdh-sha2-nistp256', 'ecdh-sha2-nistp384' and 'ecdh-sha2-nistp521' are implemented. See RFC 5656.

This raises the security level considerably.

Own Id: OTP-12622 Aux Id: OTP-12671, OTP-12672

The key exchange algorithm 'diffie-hellman-group14-sha1' is implemented. See RFC 4253.

This raises the security level.

Own Id: OTP-12671 Aux Id: OTP-12672, OTP-12622

The key exchange algorithms 'diffie-hellman-group-exchange-sha1' and 'diffie-hellman-group-exchange-sha256' are implemented. See RFC 4419.

This raises the security level.

Own Id: OTP-12672 Aux Id: OTP-12671, OTP-12622

Adding random length extra padding as recommended in RFC 4253 section 6.

Own Id: OTP-12831

New test library for low-level protocol testing. There is also a test suite using it for some preliminary tests. The intention is to build on that for more testing of individual ssh messages. See lib/ssh/test/ssh_trpt_test_lib.erl and ssh_protocol_SUITE.erl in the same directory.

Own Id: OTP-12858

Increased default values for diffie-hellman-group-exchange-sha* to Min = 1024, N = 6144, Max = 8192.

Added 6144 and 8192 bit default gex groups.

Own Id: OTP-12937

The mac algorithm 'hmac-sha2-512' is implemented. See RFC 6668.

Own Id: OTP-12938

Ssh 4.0

Fixed Bugs and Malfunctions

Ssh crashed if a message was sent on a channel with packet_size = 0.

A new option for ssh:daemon is also introduced: minimal_remote_max_packet_size. This option sets the least max packet size declaration that the daemon will accept from a client. The default value is 0 to maintain compatibility with OpenSSH and the rfc:s.

Own Id: OTP-12645 Aux Id: seq12816

Included test of the 'e' and 'f' parameters in diffie-hellman key exchange as specified in rfc 4253 section 8.

Own Id: OTP-12649

Fixes the bug that once the rekey_limit bytes (by default, 1GB) had been transmitted the connection was rekeyed every minute, not after the next transferred 'rekey_limit' chunk.

Thanks to Simon Cornish for the report and the fix!

Own Id: OTP-12692

Fixes a bug that causes an SFTP connection to always fail when {timeout, Timeout} option is used with ssh_sftp:start_channel.

Thanks to Simon Cornish

Own Id: OTP-12708

Fix various ssh key exchange problems.

Thanks to Simon Cornish

Own Id: OTP-12760 Aux Id: pull req 715

The options system_dir and user_dir assumes that the value is a path to a directory which is readable. This is now checked early, so ssh:daemon and ssh:connect will fail with an error message immediately.

Own Id: OTP-12788

A daemon now checks that a client doesn't try to authorize with methods not in the option auth_methods.

Own Id: OTP-12790

Disconnectfun now should trigger on all disconnects.

Own Id: OTP-12811

Improvements and New Features

Better usage of binary matching in ssh_auth.erl and ssh_message.erl

Own Id: OTP-11697

A new option 'preferred_algorithms' is available for ssh:daemon and ssh:connect.

This option defines the algorithms presented to the peer in the algorithm negotiation phase of the ssh protocol.

The default list can be obtained from the new function ssh:default_algorithms/0.

* INCOMPATIBILITY with removed undocumented options 'role' and 'compression' *

Own Id: OTP-12029

The internal group to user_drv protocol has been changed to be synchronous in order to guarantee that output sent to a process implementing the user_drv protocol is printed before replying. This protocol is used by the standard_output device and the ssh application when acting as a client.

This change changes the previous unlimited buffer when printing to standard_io and other devices that end up in user_drv to 1KB.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-12240

If ssh_connection:subsystem/4 fails we do not want to crash but rather terminate gracefully.

Own Id: OTP-12648 Aux Id: seq12834

New option id_string for ssh:daemon and ssh:connect for limiting banner grabbing attempts.

The possible values are: {id_string,string()} and {id_string,random}. The latter will make ssh generate a random nonsense id-string for each new connection.

Own Id: OTP-12659

To enable the ssh daemon to run in a virtualized environment, where there can be more that one server that has the same ip-address and port, we add a new option profile.

Own Id: OTP-12675

Upgrade test suite added.

Own Id: OTP-12676

A new option for handling the SSH_MSG_DEBUG message's printouts. A fun could be given in the options that will be called whenever the SSH_MSG_DEBUG message arrives. This enables the user to format the printout or just discard it.

Own Id: OTP-12738 Aux Id: seq12860

Testcase improvements and corrections:

* Add testcases for the disconnectfun option on both server and client sides

* Timeout testcases adjusted for slow machines where they sometimes failed

Own Id: OTP-12786

The option disconnectfun can now be used both on the client and server side.

Own Id: OTP-12789

A new option unknown_msgfun/2 for ssh:connect and ssh:daemon for handling unknown messages. With the option it is possible to intercept before an INFO log message is generated.

One usage is to filter out messages that are not wanted in the error logger as info reports. An example of such a message is the 'etimedout' tcp error message that will be received if a connection has keep_alive and the peer is restarted.

Own Id: OTP-12813 Aux Id: seq12881

Ssh 3.2.4

Fixed Bugs and Malfunctions

Gracefully terminate if sockets is unexpectedly closed.

Own Id: OTP-12782

Made Codenomicon Defensics test suite pass:

limit number of algorithms in kexinit message

check 'e' and 'f' parameters in kexdh

implement 'keyboard-interactive' user authentication on server side

return plain text message to bad version exchange message

Own Id: OTP-12784

Ssh 3.2.3

Fixed Bugs and Malfunctions

A new option for handling the SSH_MSG_DEBUG message's printouts. A fun could be given in the options that will be called whenever the SSH_MSG_DEBUG message arrives. This enables the user to format the printout or just discard it.

Own Id: OTP-12738 Aux Id: seq12860

Ssh 3.2.2

Improvements and New Features

New option id_string for ssh:daemon and ssh:connect for limiting banner grabbing attempts.

The possible values are: {id_string,string()} and {id_string,random}. The latter will make ssh generate a random nonsense id-string for each new connection.

Own Id: OTP-12659

Ssh 3.2.1

Fixed Bugs and Malfunctions

Ssh crashed if a message was sent on a channel with packet_size = 0.

A new option for ssh:daemon is also introduced: minimal_remote_max_packet_size. This option sets the least max packet size declaration that the daemon will accept from a client. The default value is 0 to maintain compatibility with OpenSSH and the rfc:s.

Own Id: OTP-12645 Aux Id: seq12816

Ssh 3.2

Fixed Bugs and Malfunctions

If a channel is closed by the peer while using a function with call semantics in ssh_connection.erl return {error, closed}. Document that the functions can return {error, timeout | closed} and not only ssh_request_status()

Own Id: OTP-12004

Bug that causes ssh:connect to return {error,int()} instead of {error,timeout} when ssh handshake takes too long time.

Own Id: OTP-12369

Documentation corrections. (Thanks to Rabbe Fogelholm)

Own Id: OTP-12399

Improvements and New Features

Example of ssh_connection:exec added.

Own Id: OTP-12558

Ssh 3.1

Fixed Bugs and Malfunctions

Make sure the clean rule for ssh, ssl, eunit and otp_mibs actually removes generated files.

Own Id: OTP-12200

Improved Property Tests (Thanks to Thomas, John and Tobias at QuviQ)

Own Id: OTP-12256

Correct typo of renegotiate that could cause rekeying to fail

Own Id: OTP-12277 Aux Id: seq12736

The {timeout, Timeout} option passed to ssh_sftp:start_channel was not applied to the early phases of the SSH protocol. This patch passes the Timeout through to ssh:connect. In case the timeout occurs during these phases, {error, timeout} is returned. (Thanks to Simon Cornish)

Own Id: OTP-12306

Improvements and New Features

Added API functions ptty_alloc/3 and ptty_alloc/4, to allocate a pseudo tty.

Own Id: OTP-11542 Aux Id: seq12493, OTP-11631

Supports tar file creation on other media than file systems mounted on the local machine.

The erl_tar api is extended with erl_tar:init/3 that enables usage of user provided media storage routines. A ssh-specific set of such routines is hidden in the new function ssh_sftp:open_tar/3 to simplify creating a tar archive on a remote ssh server.

A chunked file reading option is added to erl_tar:add/3,4 to save memory on e.g small embedded systems. The size of the slices read from a file in that case can be specified.

Own Id: OTP-12180 Aux Id: seq12715

Always send SSH_DISCONNECT protocol messages when peer sends corrupt messages.

Own Id: OTP-12185

Hooks for funs that can change binaries sent to remote sites from erl_tar for renote tar file creation are added. See ssh_sftp:open_tar/3,4 for details. The hooks could also be used to read remote tar files that need transformation before file extraction.

Those hooks are intended for encryption and decryption of tar files. Effort is put into memory, disk and network resource economy.

Own Id: OTP-12312 Aux Id: OTP-12180

Ssh 3.0.8

Fixed Bugs and Malfunctions

Fixes of login blocking after port scanning.

Own Id: OTP-12247 Aux Id: seq12726

Ssh 3.0.7

Fixed Bugs and Malfunctions

Add option sftp_vsn to SFTP

Own Id: OTP-12227

Improvements and New Features

Fix option user_interaction to work as expected. When password authentication is implemented with ssh keyboard-interactive method and the password is already supplied, so that we do not need to query user, then connections should succeed even though user_interaction option is set to false.

Own Id: OTP-11329 Aux Id: seq12420, seq12335

Ssh 3.0.6

Fixed Bugs and Malfunctions

Gracefully handle bad data from the client when expecting ssh version exchange.

Own Id: OTP-12157 Aux Id: seq12706

When restarting an ssh daemon, that was stopped with ssh:stop_listner/ [1,2] new options given shall replace old ones.

Own Id: OTP-12168 Aux Id: seq12711

Improvements and New Features

ssh now has a format_status function to avoid printing sensitive information in error loggs.

Own Id: OTP-12030

Known Bugs and Problems

The option parallel_login didn't work with the value true. All logins were serial.

Own Id: OTP-12194

Ssh 3.0.5

Fixed Bugs and Malfunctions

When starting an ssh-daemon giving the option {parallel_login, true}, the timeout for authentication negotiation ({negotiation_timeout, integer()}) was never removed.

This caused the session to always be terminated after the timeout if parallel_login was set.

Own Id: OTP-12057 Aux Id: seq12663

Improvements and New Features

Warning: this is experimental and may disappear or change without previous warning.

Experimental support for running Quickcheck and PropEr tests from common_test suites is added to common_test. See the reference manual for the new module ct_property_testing.

Experimental property tests are added under lib/{inet,ssh}/test/property_test. They can be run directly or from the commont_test suites inet/ftp_property_test_SUITE.erl and ssh/test/ssh_property_test_SUITE.erl.

See the code in the test directories and the man page for details.

(Thanks to Tuncer Ayaz for a patch adding Triq)

Own Id: OTP-12119

Ssh 3.0.4

Fixed Bugs and Malfunctions

When starting an ssh-daemon giving the option {parallel_login, true}, the timeout for authentication negotiation ({negotiation_timeout, integer()}) was never removed.

This caused the session to always be terminated after the timeout if parallel_login was set.

Own Id: OTP-12057 Aux Id: seq12663

Ssh 3.0.3

Fixed Bugs and Malfunctions

Removed mail address from error reports and corrected spelling error (Stacktace -> stacktrace)

Own Id: OTP-11883 Aux Id: seq12586

Decode/encode fixes in SSH_MSG_IGNORE and SSH_MSG_UNIMPLEMENTED.

Own Id: OTP-11983

Improvements and New Features

Accepts that some older OpenSSH clients sends incorrect disconnect messages.

Own Id: OTP-11972

Handle inet and inet6 option correctly

Own Id: OTP-11976

Ssh 3.0.2

Fixed Bugs and Malfunctions

Fixed timeout bug in ssh:connect.

Own Id: OTP-11908

Improvements and New Features

Option max_sessions added to ssh:daemon/{2,3}. This option, if set, limits the number of simultaneous connections accepted by the daemon.

Own Id: OTP-11885

Ssh 3.0.1

Fixed Bugs and Malfunctions

Fixes the problem that ssh_cli in some cases could delay the prompt if a tty was not requested by the client.

Own Id: OTP-10732

The variable NewCol is now correctly calculated allowing for tab-completion of function calls even when preceded with blank space (Thanks to Alexander Demidenko)

Own Id: OTP-11566

Fix incorrect dialyzer spec and types, also enhance documentation.

Thanks to Ayaz Tuncer.

Own Id: OTP-11627

Fixed a bug when ssh:exec executes a linux command on a linux ssh daemon. If the result is sent back from standard error, the length information was not stripped off correctly.

Own Id: OTP-11667

Fixed a bug with the ssh file 'known_hosts' which made the file grow with many equal entries.

Own Id: OTP-11671

Some local implementations of removing the last element from a list are replaced by lists:droplast/1. Note that this requires at least stdlib-2.0, which is the stdlib version delivered in OTP 17.0. (Thanks to Hans Svensson)

Own Id: OTP-11678

Bug fix for ssh:daemon/2,3 so that the failfun is called when it should.

Own Id: OTP-11680

Fixed bug which crashed ssh when SSH_MSG_KEX_DH_GEX_GROUP is received. This could cause a vm-crash for eheap_alloc during garbage collect.

Own Id: OTP-11696 Aux Id: 12547, 12532

Fixes a bug that breaks keyboard-interactive authentication. Thanks to Simon Cornish for reporting and suggesting a fix.

Own Id: OTP-11698

dialyzer specs are now correct for ssh:start/0, ssh:start/1, ssh:stop/0 and ssh_connection_handler:open_channel/5. (Thanks to Johannes Weißl )

Own Id: OTP-11705

Application upgrade (appup) files are corrected for the following applications:

asn1, common_test, compiler, crypto, debugger, dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe, inets, observer, odbc, os_mon, otp_mibs, parsetools, percept, public_key, reltool, runtime_tools, ssh, syntax_tools, test_server, tools, typer, webtool, wx, xmerl

A new test utility for testing appup files is added to test_server. This is now used by most applications in OTP.

(Thanks to Tobias Schlager)

Own Id: OTP-11744

Fixed dialyzer warning for ssh_connection:send.

Own Id: OTP-11821

ssh:daemon/2,3 : Added options negotiation_timeout and parallel_login to tune the authentication behaviour.

Own Id: OTP-11823

Improvements and New Features

Ssh now fully supports unicode filenames, filecontents, shell and cli. Please note that the underlying os and emulator must also give support for unicode. You may want to start the emulator with "erl +fnu" on Linux.

Own Id: OTP-10953

Ssh 3.0

Fixed Bugs and Malfunctions

The ssh cli is now faster at close and before new prompt.

Own Id: OTP-11339 Aux Id: seq12423

Ssh process structure was redesigned to better map to what is truly parallel this has solved a lot of strange timing issues that sometimes would occur, for instance a process leak could happen when a lot of connections where taken up and down in parallel in a short period of time. Also backwards compatible clauses to "original" but never supported features has been removed.

Impact: Increases flow efficiency

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-11363

Fix various typos in erts, kernel and ssh. Thanks to Martin Hässler.

Own Id: OTP-11414

Correct private_key type documentation in ssh_server_key_api. Thanks to Tristan Sloughter.

Own Id: OTP-11449

The functions in ssh_no_io.erl did not mimic the functions in ssh_io.erl correctly, the arity was incorrect for some functions which caused ssh to fail in the wrong way.

Own Id: OTP-11490

Improvements and New Features

Add option to disallow CLI

Own Id: OTP-10976

Add sockname and user to ssh:connection_info/2

Own Id: OTP-11296

Ssh 2.1.8

Improvements and New Features

Do not chmod ~/.ssh unnecessarily.

Own Id: OTP-11189

Make ssh_cli.erl handle CTRL+C. Thanks to Stefan Zegenhagen.

Own Id: OTP-11199

Clarified timeout options in documentation.

Own Id: OTP-11249

Add openssh_zlib compression type to ssh_transport. Thanks to Louis-Philippe Gauthier.

Own Id: OTP-11256

Ssh 2.1.7

Fixed Bugs and Malfunctions

ssh:daemon will get fed with an argument even if it is not a valid expression.

Own Id: OTP-10975

Improvements and New Features

Properly ignore everything in lib/ssh/doc/html/. Thanks to Anthony Ramine.

Own Id: OTP-10983

Integrate elliptic curve contribution from Andreas Schultz

In order to be able to support elliptic curve cipher suites in SSL/TLS, additions to handle elliptic curve infrastructure has been added to public_key and crypto.

This also has resulted in a rewrite of the crypto API to gain consistency and remove unnecessary overhead. All OTP applications using crypto has been updated to use the new API.

Impact: Elliptic curve cryptography (ECC) offers equivalent security with smaller key sizes than other public key algorithms. Smaller key sizes result in savings for power, memory, bandwidth, and computational cost that make ECC especially attractive for constrained environments.

Own Id: OTP-11009

Ssh 2.1.6

Fixed Bugs and Malfunctions

Fixed timing rekeying bug.

Own Id: OTP-10940

Ssh 2.1.5

Fixed Bugs and Malfunctions

Bug in rekeying for daemon fixed.

Own Id: OTP-10911

Improvements and New Features

Enhanced error message and added test for ssh clients trying to start non existing subsystems.

Own Id: OTP-10714

Ssh 2.1.4

Improvements and New Features

Better quality on the error messages for when key exchange failed.

Own Id: OTP-10553 Aux Id: seq12152

Fix link to documentation for ssh:connect/3,4. Thanks to Martin Hässler.

Own Id: OTP-10862

Ssh 2.1.3

Fixed Bugs and Malfunctions

It is now possible to send an empty binary using ssh_connection:send/3, this corner case previously caused ssh_connection:send to hang.

Own Id: OTP-9478 Aux Id: kunagi-226 [137]

Fix typo in keyboard-interactive string. Thanks to Daniel Goertzen

Own Id: OTP-10456

ssh_connectino:send/3 will not return until all data has been sent. Previously it could return too early, resulting in things such premature close of the connection. Also improved error handling of closed SSH channels.

Own Id: OTP-10467

Fixed ssh_cli.erl crashes because #state.buf is yet 'undefined'.

Fixed Client terminateing connections due to channel_request message response is sent to the wrong id.

Affected SSH clients: - all clients based on SSH-2.0-TrileadSSH2Java_213 (problem #1) - SSH Term Pro (problem #2)

Thanks to Stefan Zegenhagen

Own Id: OTP-10475

Fixed various syntax errors in SSH appup file

Own Id: OTP-10657

Improvements and New Features

SSH_FX_FILE_IS_A_DIRECTORY message for sftp implemented

Own Id: OTP-6406 Aux Id: kunagi-218 [129]

SSH Rekeying fixed

Own Id: OTP-7785 Aux Id: kunagi-220 [131]

Added User Guide for the SSH application

Own Id: OTP-7786 Aux Id: kunagi-221 [132]

Documentation regarding failfun, connectfun and disconnectfun provided

Own Id: OTP-7792 Aux Id: kunagi-222 [133]

SSH connection timer implementation

New option, {idle_time, integer()}, sets a timeout on connection when no channels are active, defaults to infinity

Own Id: OTP-10514 Aux Id: seq12020

Some examples overflowing the width of PDF pages have been corrected.

Own Id: OTP-10665

Fixed internal error on when client and server cannot agree o which authmethod to use.

Own Id: OTP-10731 Aux Id: seq12237

Ssh 2.1.2.1

Improvements and New Features

Removed error report in ssh_connection_handler triggered by badmatch failure.

Own Id: OTP-11188

Ssh 2.1.2

Fixed Bugs and Malfunctions

SSH quiet mode

A new option to ssh:connect/3,4, quiet_mode. If true, the client will not print out anything on authorization.

Own Id: OTP-10429 Aux Id: kunagi-273 [184]

Restrict which key algorithms to use

A new option to ssh:connect/3,4 is introduced, public_key_algs, where you can restrict which key algorithms to use and in which order to try them.

Own Id: OTP-10498 Aux Id: kunagi-289 [200]

Confidentiality of client password

Unsets clients password after authentication.

Own Id: OTP-10511 Aux Id: kunagi-292 [203]

Fixed user interaction for SSH

It's now available to accept hosts and input password

Own Id: OTP-10513 Aux Id: kunagi-293 [204]

Ssh 2.1.1

Fixed Bugs and Malfunctions

Ssh now only sends one channel close message under all circumstances, before it would sometimes incorrectly send two.

Own Id: OTP-10060

The options check mistreated the ip_v6_disable-option, and did not handle some, at the moment, undocumented options correctly.

Own Id: OTP-10061

The channel id in a channel failure message, sent to the peer, is now in all cases the remote channel id

Own Id: OTP-10062

Improved handling of multiple closes to avoid occasional crashes when a channel is closed more than once.

Own Id: OTP-10112

Fix lib/src/test/ssh_basic_SUITE.erl to fix IPv6 option typos

Fixed incorrect option "ipv6_disable" to "ipv6_disabled" as documented in the ssh manual.

Own Id: OTP-10219

SSH: Make "auth_methods" server option re-usable

The 'auth_methods' option is used by the server side of the SSH code to tell a connecting SSH client about the authentication methods that are supported by the server. The code still extracts and handles the 'auth_methods' option from Opts in appropriate places, but the Opts checking code in ssh.erl didn't allow that option to be specified.

Own Id: OTP-10224

Use the correct channel id when adjusting the channel window

Own Id: OTP-10232

Ssh 2.1

Fixed Bugs and Malfunctions

All keys in authorized_keys are considered, wrongly only the first one was before.

Own Id: OTP-7235

ssh daemon now properly handles ras host keys, in previous versions only dsa host keys sufficed to set up a connection.

Own Id: OTP-7677

ssh:shell/3 and ssh:connect/3 does not hang anymore if connection negotiation fails

Own Id: OTP-8111

Improve check so that we will not try to read ssh packet length indicator if not sure we have enough data.

Own Id: OTP-8380

Do not try to use user interaction when it is disabled.

Own Id: OTP-9466 Aux Id: seq11886

Improved error handling of internal errors i the ssh connection handling process

Own Id: OTP-9905

sftp daemon generates file handles correct

Own Id: OTP-9948

Improvements and New Features

Document supported algorithms

Own Id: OTP-8109

Graceful handling of premature close from an sftp client.

Own Id: OTP-9391 Aux Id: seq11838

Changed ssh implementation to use the public_key application for all public key handling. This is also a first step for enabling a callback API for supplying public keys and handling keys protected with password phrases.

Additionally the test suites where improved so that they do not copy the users keys to test server directories as this is a security liability. Also ipv6 and file access issues found in the process has been fixed.

This change also solves OTP-7677 and OTP-7235

This changes also involves some updates to public_keys ssh-functions.

Own Id: OTP-9911

Added options for the ssh client to support user keys files that are password protected.

Own Id: OTP-10036 Aux Id: OTP-6400, Seq10595

Ssh 2.0.9

Improvements and New Features

Erlang/OTP can now be built using parallel make if you limit the number of jobs, for instance using 'make -j6' or 'make -j10'. 'make -j' does not work at the moment because of some missing dependencies.

Own Id: OTP-9451

Ssh behaviours now use the new directive "-callback". Parameters will be further specified in a later version of ssh.

Own Id: OTP-9796

Ssh 2.0.8

Fixed Bugs and Malfunctions

Calling ssh_sftp:stop_channel/1 resulted in that the trap_exit flag was set to true for the invoking process.

Own Id: OTP-9386 Aux Id: seq11865

Ssh 2.0.7

Fixed Bugs and Malfunctions

An unexpected message would crash the ssh_connection_handler and close the connection. Now an error message is generated instead.

Own Id: OTP-9273

Ssh 2.0.6

Fixed Bugs and Malfunctions

A memory leak has been fixed. I.e. per terminated connection the size of a pid and the length of a user name string was not cleared.

Own Id: OTP-9232

Ssh 2.0.5

Improvements and New Features

Strengthened random number generation. (Thanks to Geoff Cant)

Own Id: OTP-9225

Ssh 2.0.4

Fixed Bugs and Malfunctions

In some cases SSH returned {error, normal} when a channel was terminated unexpectedly. This has now been changed to {error, channel_closed}.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-8987 Aux Id: seq11748

SSH did not handle the error reason enetunreach when trying to open a IPv6 connection.

Own Id: OTP-9031

Improvements and New Features

It is now possible to use SSH to sign and verify binary data.

Own Id: OTP-8986

SSH now ensures that the .ssh directory exists before trying to access files located in that directory.

Own Id: OTP-9010

Ssh 2.0.3

Fixed Bugs and Malfunctions

The fix regarding OTP-8849 was not included in the previous version as stated.

Own Id: OTP-8918

Ssh 2.0.2

Fixed Bugs and Malfunctions

The ssh_system_sup did not catch noproc and shutdown messages.

Own Id: OTP-8863

In some cases a crash report was generated when a connection was closing down. This was caused by a race condition between two processes.

Own Id: OTP-8881 Aux Id: seq11656, seq11648

Improvements and New Features

SSH no longer use deprecated public_key functions.

Own Id: OTP-8849

Ssh 2.0.1

Fixed Bugs and Malfunctions

SSH in some cases terminated channels with reason normal when it should have been shutdown.

Own Id: OTP-8714

SSH in some cases generated a crash report when a channel was closed in a normal way.

Own Id: OTP-8735 Aux Id: seq11615

The processes ssh_subsystem_sup and one ssh_channel_sup was not terminated when a connection was closed.

Own Id: OTP-8807

Ssh 2.0

Fixed Bugs and Malfunctions

The function ssh:connect/4 was not exported.

Own Id: OTP-8550 Aux Id:

Aligned error message with used version (SSH_FX_FAILURE vs SSH_FX_NOT_A_DIRECTORY, the latter introduced in version 6).

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-8644 Aux Id: seq11574

Resolved race condition when another connection is started before a channel is opened in the first connection.

Own Id: OTP-8645 Aux Id: seq11577

Improvements and New Features

The configuration parameter ip_v6_disabled is now available, which makes it possible for the user to alter the IP version SSH shall use.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-8535 Aux Id:

The ssh_connection:send operation now accepts infinity as timeout.

Own Id: OTP-8534 Aux Id:

The connection handler now include stack traces when a channel message is not handled correctly.

Own Id: OTP-8524 Aux Id:

Removed deprecated modules (ssh_ssh, ssh_sshd and ssh_cm) and functions (ssh_sftp:connect and ssh_sftp:stop).

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-8596 Aux Id:

Ssh 1.1.8

Fixed Bugs and Malfunctions

In some cases SSH ceased to collect more data from the transport layer.

Own Id: OTP-8401 Aux Id: seq11479

Improvements and New Features

Old release notes removed.

Own Id: OTP-8356 Aux Id:

Ssh 1.1.7

Fixed Bugs and Malfunctions

Now clear all processes when a connection is terminated.

Own Id: OTP-8121 Aux Id:

In some rare cases the connection handler could enter an infinite loop.

Own Id: OTP-8277 Aux Id: seq11428

If an SFTP server did not respond with EOF, the function ssh_sftp:list_dir/2/3 would enter an infinite loop.

Own Id: OTP-8278 Aux Id: seq11450

Improvements and New Features

The documentation is now built with open source tools (xsltproc and fop) that exists on most platforms. One visible change is that the frames are removed.

Own Id: OTP-8201 Aux Id:

Ssh 1.1.6

Fixed Bugs and Malfunctions

ssh_sftp:start_channel did not handle all possible return values from ssh_channel:start correctly.

Own Id: OTP-8176 Aux Id:

SFTPD did not handle rename command (version 4) correctly.

Own Id: OTP-8175 Aux Id: seq11373

If a connection manager already had been terminated it could cause a channel to generate a crash report when it was about to stop.

Own Id: OTP-8174 Aux Id: seq11377

Requests could result in badarg or badmatch EXIT messages in the connection manager if the channel no longer existed.

Own Id: OTP-8173 Aux Id: seq11379

ssh_transport:unpack/3 could cause a badarg error.

Own Id: OTP-8162 Aux Id:

Improvements and New Features

The encryption algorithm aes128-cbc is now supported. Requires that crypto-1.6.1 is available.

Own Id: OTP-8110 Aux Id:

Ssh 1.1.5

Fixed Bugs and Malfunctions

ssh_sftp:start_channel/3 did not handle timeout correctly.

Own Id: OTP-8159 Aux Id: seq11386

If a progress message was not received after invoking ssh:connect/3 the call could hang for ever. A timeout option has also been added.

Own Id: OTP-8160 Aux Id: seq11386

A comma has been missing in the ssh.appup file since SSH-1.0.2.

Own Id: OTP-8161 Aux Id:

Ssh 1.1.4

Fixed Bugs and Malfunctions

SSH sometimes caused a crash report at disconnect.

Own Id: OTP-8071 Aux Id: seq11319

Ssh 1.1.3

Fixed Bugs and Malfunctions

The operation ssh_sftp:stop_channel/1 returned an exception if the connection already had been closed.

Own Id: OTP-7996 Aux Id: seq11281

SSH did not handle if supervisor:start_child/2 returned {error, already_present}.

Own Id: OTP-8034 Aux Id: seq11307

SSH no longer cause supervisor reports when a connection is terminated in a controlled manner.

Own Id: OTP-8035 Aux Id: seq11308

Ssh 1.1.2

Fixed Bugs and Malfunctions

Ssh confused local and remote channel id's, which in some cases resulted in that messages were discarded.

Own Id: OTP-7914 Aux Id: seq11234

Ssh could not handle echo values other than 0 and 1.

Own Id: OTP-7917 Aux Id: seq11238

A crash occurred if a non-valid channel reference was received.

Own Id: OTP-7918 Aux Id: seq11238

Sftpd connections was not closed after receiving eof from a client.

Own Id: OTP-7921 Aux Id: seq11222

It was not possible to start a SFTP subsystem on certain platforms, i.e. those who do not support symbolic links.

Own Id: OTP-7930 Aux Id:

In some cases the message {ssh_cm, ssh_connection_ref(), {closed, ssh_channel_id()}} was not passed to the registered callback module.

Own Id: OTP-7957 Aux Id:

Improvements and New Features

By using the sftpd option {max_files, Integer}, the message size for READDIR commands can be reduced.

Own Id: OTP-7919 Aux Id: seq11230

Ssh 1.1.1

Fixed Bugs and Malfunctions

The erlang ssh server has presented itself incorrectly, using the special version ssh-1.99, although it never has supported versions below 2.0. Since ssh-1.1 client versions below 2.0 are correctly rejected instead of letting the server crash later on. Alas the problem with the presentation string was not discovered until after ssh.1.1 was released. Now the server will present itself as ssh-2.0.

Own Id: OTP-7795

An internal function call used an incorrect parameter, which caused problem when the old listen API was used. This was introduced in Ssh-1.1.

Own Id: OTP-7920 Aux Id: seq11211

Improvements and New Features

Ssh timeouts will now behave as expected i.e. defaults to infinity only the user of the ssh application can know of a reasonable timeout value for their application.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-7807

The implementation of timeouts added as a patch in ssh-1.0.1 was slightly changed and is now documented.

Own Id: OTP-7808

To honor the multiplexing of channels over one ssh connection concept ssh_sftp:connect/ [1,2,3] is deprecated and replaced by ssh_sftp:start_channel/[1,2,3] and ssh_sftp:stop/1 is deprecated and replaced by ssh_sftp:stop_channel/1 and to stop the ssh connection ssh:close/ 1 should be called.

Own Id: OTP-7809

Added the message {ssh_channel_up, ChannelId, ConnectionManager} that shall be handled by the channel callback handle_msg/2. This makes the function handle_msg/2 a mandatory function for ssh channels implementations which it was not in ssh-1.1.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-7828

Ssh 1.1

Fixed Bugs and Malfunctions

A flaw in the implementation of the supervision tree caused the ssh daemon to close the connections to all currently logged in users if one user logged out. Another problem related to the supervision tree caused the closing down of clients to leak processes i.e. all processes was not shutdown correctly.

Own Id: OTP-7676

Tabs could cause ssh_cli to print things in a surprising way.

Own Id: OTP-7683 Aux Id: seq11102

[sftp, sftpd] - Added patch to make sftp timestamps more correct, in the long run it would be nice to have better support in file to be able to make it always behave correctly now it will be correct 99 % of time instead of almost never correct, at least on unix-based platforms.

Own Id: OTP-7685 Aux Id: seq11082

[sftpd] - Added patch to further improve handling of symbolic links in the sftp-server.

Own Id: OTP-7766 Aux Id: seq11101

Ssh incorrectly sent the local id instead of the remote id of a channel to the peer. For simpler cases these ids often happen to have the same value. One case when they do not is when the client sends an exec command two times in a raw on the same ssh connection (different channels of course as the channel will be closed when the exec command has been evaluated) .

Own Id: OTP-7767

Packet data could be lost under high load due to the fact that buffered data was sometimes wrongly discarded before it had been sent.

Own Id: OTP-7768

Improved ipv6-handling as some assumptions about inet functions where incorrect.

Own Id: OTP-7770

Improvements and New Features

Added new API function ssh:connection_info/2.

Own Id: OTP-7456

Now starts ssh channel processes later avoiding synchronization problems between processes.

Own Id: OTP-7516

Ssh now rejects old versions of the ssh protocol for security reasons. (Even if they where not correctly rejected before the connection would probably have failed anyway due to other reasons.)

Own Id: OTP-7645 Aux Id: seq11094

New API module ssh_channel has been added. This is a behaviour to facilitate the implementation of ssh clients and plug in subsystems to the ssh daemon. Note that this slightly changes the options to the API function ssh:daemon/[1,2,3] deprecating all no longer documented options. Note that the new API enforces the "logical way" of using the old API i.e. making the subsystem process part of the ssh applications supervisor tree, so missuses of the old API are not compatible with the new API.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-7769

Known Bugs and Problems

Public keys protected by a password are currently not handled by the erlang ssh application.

Own Id: OTP-6400 Aux Id: 10595

Ssh 1.0.2

Fixed Bugs and Malfunctions

[sftpd] - Listing of symbolic link directories should now work as expected.

Own Id: OTP-7141 Aux Id: seq10856

Ssh 1.0.1

Fixed Bugs and Malfunctions

[sftp] - When listing a directory with more than 100 files only the first 100 where listed. This has now been fixed.

Own Id: OTP-7318 Aux Id: seq10953

When restarting an ssh-system the expected return value from ssh_system_sup:restart_acceptor/2 was incorrect, this is no longer the case.

Own Id: OTP-7564 Aux Id: seq11055

A few minor bugs where fixed in ssh_userreg.erl and ssh_connection_manager and a a ssh_cli option was added to restore backwards compatibility with the old ssh_cm - API.

Own Id: OTP-7565

Fixed bug in ipv6 support and added option to disable ipv6 as a workaround for badly configured computers.

Own Id: OTP-7566

Improvements and New Features

[sftp] - Option added to set timeout value in sftp.

Own Id: OTP-7305 Aux Id: seq10945

Ssh 1.0

Fixed Bugs and Malfunctions

Removed some special handling of prompts that made ssh behave differently than openssh.

Own Id: OTP-7485 Aux Id: seq11025

Bug in encoding of pty opts has been fixed.

Own Id: OTP-7504

Improvements and New Features

The architecture of the ssh processes has been reconstructed to fit in a supervision tree as to become a real OTP application and benefit from this when starting and stopping.

Own Id: OTP-7356 Aux Id: seq10899

Support for pty option echo off added. Requires kernel from R12B-4.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-7502 Aux Id: seq10959

The ssh API has been enhanced a lot of old API functions has become deprecated.

Own Id: OTP-7503

SSH Protocol Introduction

SSH is a protocol for secure remote logon and other secure network services over an insecure network.

Scope and Purpose

SSH provides a single, full-duplex, and byte-oriented connection between client and server. The protocol also provides privacy, integrity, server authentication, and man-in-the-middle protection.

The ssh application is an implementation of the SSH Transport, Connection and Authentication Layer Protocols in Erlang. It provides the following:

API functions to write customized SSH clients and servers applications

The Erlang shell available over SSH, enabled via the shell daemon option

An SFTP client (ssh_sftp) and server (ssh_sftpd), enabled via the subsystems daemon option

Prerequisites

It is assumed that the reader is familiar with the Erlang programming language, concepts of OTP, and has a basic understanding of public keys.

Protocol Overview

Conceptually, the SSH protocol can be partitioned into four layers:

---
title: SSH Protocol Architecture (RFC 4251)
---

block-beta
    columns 4

    Shell Exec SFTP Custom
    l1["Connection / Channels\n(RFC 4254)"]:4
    l2["Authentication\n(RFC 4252)"]:4
    l3["Transport\n(RFC 4253)"]:4
    l4["TCP/IP"]:4

Transport Protocol

The SSH Transport Protocol is a secure, low-level transport. It provides strong encryption, cryptographic host authentication, and integrity protection. A minimum of Message Authentication Code (MAC) and encryption algorithms are supported. For details, see the ssh manual page in ssh.

Authentication Protocol

The SSH Authentication Protocol is a general-purpose user authentication protocol run over the SSH Transport Layer Protocol. The ssh application supports user authentication as follows:

Using public key technology. RSA and DSA, X509-certificates are not supported.

Using keyboard-interactive authentication. This is suitable for interactive authentication methods that do not need any special software support on the client side. Instead, all authentication data is entered from the keyboard.

Using a pure password-based authentication scheme. Here, the plain text password is encrypted before sent over the network.

Several configuration options for authentication handling are available in ssh:connect/3,4 and ssh:daemon/2,3.

The public key handling can be customized by implementing the following behaviours from ssh:

Module ssh_client_key_api.

Module ssh_server_key_api.

Connection Protocol

The SSH Connection Protocol provides application-support services over the transport pipe, for example, channel multiplexing, flow control, remote program execution, signal propagation, and connection forwarding. Functions for handling the SSH Connection Protocol can be found in the module ssh_connection in ssh.

Channels

All terminal sessions, forwarded connections, and so on, are channels. Multiple channels are multiplexed into a single connection. All channels are flow-controlled. This means that no data is sent to a channel peer until a message is received to indicate that window space is available. The initial window size specifies how many bytes of channel data that can be sent to the channel peer without adjusting the window. Typically, an SSH client opens a channel, sends data (commands), receives data (control information), and then closes the channel. The ssh_client_channel behaviour handles generic parts of SSH channel management. This makes it easy to write your own SSH client/server processes that use flow-control and thus opens for more focus on the application logic.

Channels come in the following three flavors:

Subsystem - Named services that can be run as part of an SSH server, such as SFTP (ssh_sftpd). No subsystems are enabled by default. The Erlang ssh daemon can be configured to run any Erlang-implemented SSH subsystem.

Shell - Interactive shell. By default the Erlang daemon does not expose the Erlang shell. It can be enabled with option {shell, {shell, start, []}}. The shell can be customized by providing your own read-eval-print loop. You can also provide your own Command-Line Interface (CLI) implementation, but that is much more work.

Exec - By default one-time remote execution of commands is disabled. See function ssh_connection:exec/4 for more information.

Where to Find More Information

For detailed information about the SSH protocol, refer to the following Request for Comments(RFCs):

RFC 4250 - Protocol Assigned Numbers

RFC 4251 - Protocol Architecture

RFC 4252 - Authentication Protocol

RFC 4253 - Transport Layer Protocol

RFC 4254 - Connection Protocol

RFC 4344 - Transport Layer Encryption Modes

RFC 4716 - Public Key File Format

Examples

The following examples use the utility function ssh:start/0 to start all needed applications (crypto, public_key, and ssh). All examples are run in an Erlang shell, or in a bash shell, using OpenSSH to illustrate how the ssh application can be used. The examples are run as the user otptest on a local network where the user is authorized to log in over ssh to the host ssh.example.com.

If nothing else is stated, it is presumed that the otptest user has an entry in the authorized_keys file of ssh.example.com (allowed to log in over ssh without entering a password). Also, ssh.example.com is a known host in the known_hosts file of the user otptest. This means that host-verification can be done without user-interaction.

Using the Erlang ssh Terminal Client

The user otptest, which has bash as default shell, uses the ssh:shell/1 client to connect to the OpenSSH daemon running on a host called ssh.example.com:

1> ssh:start().
ok
2> {ok, S} = ssh:shell("ssh.example.com").
otptest@ssh.example.com:> pwd
/home/otptest
otptest@ssh.example.com:> exit
logout
3>

Running an Erlang ssh Daemon

The system_dir option must be a directory containing a host key file and it defaults to /etc/ssh. For details, see Section Configuration in ssh.

Note

Normally, the /etc/ssh directory is only readable by root.

The option user_dir defaults to directory ~/.ssh.

Step 1. To run the example without root privileges, generate new host keys and user keys:

$bash> ssh-keygen -t rsa -f /tmp/ssh_daemon/ssh_host_rsa_key
[...]
$bash> ssh-keygen -t rsa -f /tmp/otptest_user/.ssh/id_rsa
[...]

Step 2. Create the file /tmp/otptest_user/.ssh/authorized_keys and add the content of /tmp/otptest_user/.ssh/id_rsa.pub.

Step 3. Start the Erlang ssh daemon:

1> ssh:start().
ok
2> {ok, Sshd} = ssh:daemon(8989, [{system_dir, "/tmp/ssh_daemon"},
                                  {user_dir, "/tmp/otptest_user/.ssh"},
                                  {shell, {shell, start, []}},
                                  {exec, erlang_eval}]).
{ok,<0.54.0>}
3>

Step 4. Use the OpenSSH client from a shell to connect to the Erlang ssh daemon:

$bash> ssh ssh.example.com -p 8989  -i /tmp/otptest_user/.ssh/id_rsa \
                  -o UserKnownHostsFile=/tmp/otptest_user/.ssh/known_hosts
The authenticity of host 'ssh.example.com' can't be established.
RSA key fingerprint is 14:81:80:50:b1:1f:57:dd:93:a8:2d:2f:dd:90:ae:a8.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'ssh.example.com' (RSA) to the list of known hosts.
Eshell V5.10  (abort with ^G)
1>

There are two ways of shutting down an ssh daemon, see Step 5a and Step 5b.

Step 5a. Shut down the Erlang ssh daemon so that it stops the listener but leaves existing connections, started by the listener, operational:

3> ssh:stop_listener(Sshd).
ok
4>

Step 5b. Shut down the Erlang ssh daemon so that it stops the listener and all connections started by the listener:

3> ssh:stop_daemon(Sshd).
ok
4>

One-Time Execution

Erlang Client Contacting OpenSSH Server

In the following example, the Erlang shell is the client process that receives the channel replies as Erlang messages.

Do an one-time execution of a remote OS command ("pwd") over ssh to the ssh server of the OS at the host "ssh.example.com":

1> ssh:start().
ok
2> {ok, ConnectionRef} = ssh:connect("ssh.example.com", 22, []).
{ok,<0.57.0>}
3> {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity).
{ok,0}
4> success = ssh_connection:exec(ConnectionRef, ChannelId, "pwd", infinity).
5> flush(). % Get all pending messages. NOTE: ordering may vary!
Shell got {ssh_cm,<0.57.0>,{data,0,0,<<"/home/otptest\n">>}}
Shell got {ssh_cm,<0.57.0>,{eof,0}}
Shell got {ssh_cm,<0.57.0>,{exit_status,0,0}}
Shell got {ssh_cm,<0.57.0>,{closed,0}}
ok
6> ssh:connection_info(ConnectionRef, channels).
{channels,[]}
7>

See ssh_connection and ssh_connection:exec/4 for finding documentation of the channel messages.

To collect the channel messages in a program, use receive...end instead of flush/1:

5> receive
5>     {ssh_cm, ConnectionRef, {data, ChannelId, Type, Result}} when Type == 0 ->
5>         {ok,Result};
5>     {ssh_cm, ConnectionRef, {data, ChannelId, Type, Result}} when Type == 1 ->
5>         {error,Result}
5> end.
{ok,<<"/home/otptest\n">>}
6>

Note

Only the exec channel is closed after the one-time execution. The connection is still up and can handle previously opened channels. It is also possible to open a new channel:

% try to open a new channel to check if the ConnectionRef is still open
7> {ok, NewChannelId} = ssh_connection:session_channel(ConnectionRef, infinity).
{ok,1}
8>

To close the connection, call the function ssh:close(ConnectionRef). As an alternative, set the option {idle_time, 1} when opening the connection. This will cause the connection to be closed automatically when there are no channels open for the specified time period, in this case 1 ms.

OpenSSH and Erlang Clients to Erlang Daemon

An Erlang SSH daemon could be called for one-time execution of a "command". The "command" must be as if entered into the erlang shell, that is a sequence of Erlang expressions ended by a period (.). Variables bound in that sequence will keep their bindings throughout the expression sequence. The bindings are disposed when the result is returned.

Here is an example of a suitable expression sequence:

A=1, B=2, 3 == (A + B).

It evaluates to true if submitted to the Erlang daemon started in Step 3 above:

$bash> ssh ssh.example.com -p 8989 "A=1, B=2, 3 == (A + B)."
true
$bash>

The same example but now using the Erlang ssh client to contact the Erlang server:

1> {ok, ConnectionRef} = ssh:connect("ssh.example.com", 8989, []).
{ok,<0.216.0>}
2> {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity).
{ok,0}
3> success = ssh_connection:exec(ConnectionRef, ChannelId,
                                 "A=1, B=2, 3 == (A + B).",
                                 infinity).
success
4> flush().
Shell got {ssh_cm,<0.216.0>,{data,0,0,<<"true">>}}
Shell got {ssh_cm,<0.216.0>,{exit_status,0,0}}
Shell got {ssh_cm,<0.216.0>,{eof,0}}
Shell got {ssh_cm,<0.216.0>,{closed,0}}
ok
5>

Note

Erlang shell specific functions and control sequences like for example h(). are not supported.

I/O from a function called in an Erlang ssh daemon

Output to stdout on the server side is also displayed as well as the resulting term from the function call:

$bash> ssh ssh.example.com -p 8989 'io:format("Hello!~n~nHow are ~p?~n",[you]).'
Hello!

How are you?
ok
$bash>

And similar for reading from stdin. As an example we use io:read/1 which displays the argument as a prompt on stdout, reads a term from stdin and returns it in an ok-tuple:

$bash> ssh ssh.example.com -p 8989 'io:read("write something: ").'
write something: [a,b,c].
{ok,[a,b,c]}
$bash>

The same example but using the Erlang ssh client:

Eshell V10.5.2  (abort with ^G)
1> ssh:start().
ok
2> {ok, ConnectionRef} = ssh:connect(loopback, 8989, []).
{ok,<0.92.0>}
3> {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity).
{ok,0}
4> success = ssh_connection:exec(ConnectionRef, ChannelId,
                                 "io:read(\"write something: \").",
                                 infinity).
success
5> flush().
Shell got {ssh_cm,<0.92.0>,{data,0,0,<<"write something: ">>}}
ok
% All data is sent as binaries with string contents:
6> ok = ssh_connection:send(ConnectionRef, ChannelId, <<"[a,b,c].">>).
ok
7> flush().
ok
%% Nothing is received, because the io:read/1
%% requires the input line to end with a newline.

%% Send a newline (it could have been included in the last send):
8> ssh_connection:send(ConnectionRef, ChannelId, <<"\n">>).
ok
9> flush().
Shell got {ssh_cm,<0.92.0>,{data,0,0,<<"{ok,[a,b,c]}">>}}
Shell got {ssh_cm,<0.92.0>,{exit_status,0,0}}
Shell got {ssh_cm,<0.92.0>,{eof,0}}
Shell got {ssh_cm,<0.92.0>,{closed,0}}
ok
10>

Configuring the server's (daemon's) command execution

By default, one-time execution of commands is disabled — clients receive "Prohibited." on stderr with exit status 255. The daemon started in Step 3 above explicitly enables the built-in Erlang term evaluator with {exec, erlang_eval}.

To tailor the input language or restrict the possible functions to call, install an alternative evaluator with {exec, {direct, Fun}}. See ssh:daemon/2,3 and exec_daemon_option() for details.

Start the daemon with a reference to a fun() that handles the evaluation:

1> ssh:start().
ok
2> MyEvaluator = fun("1") -> {ok, some_value};
                    ("2") -> {ok, some_other_value};
                    ("3") -> {ok, V} = io:read("input erlang term>> "),
                             {ok, V};
                    (Err) -> {error,{bad_input,Err}}
                 end.
3> {ok, Sshd} = ssh:daemon(1234, [{system_dir, "/tmp/ssh_daemon"},
                                  {user_dir, "/tmp/otptest_user/.ssh"},
                                  {exec, {direct,MyEvaluator}}
                                 ]).
{ok,<0.275.0>}
4>

The fun() in the exec option could take up to three arguments (Cmd, User and ClientAddress). See the exec_daemon_option() for the details.

And call it:

$bash> ssh localhost -p 1234 1
some_value
$bash> ssh localhost -p 1234 2
some_other_value
# I/O works:
$bash> ssh localhost -p 1234 3
input erlang term>> abc.
abc
# Check that Erlang evaluation is disabled:
$bash> ssh localhost -p 1234 1+ 2.
**Error** {bad_input,"1+ 2."}
$bash>

Note

Spaces are preserved and no . is needed at the end — that was required by the default evaluator.

The error return in the Erlang client (The text as data type 1 and exit_status 255):

2> {ok, ConnectionRef} = ssh:connect(loopback, 1234, []).
{ok,<0.92.0>}
3> {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity).
{ok,0}
4> success = ssh_connection:exec(ConnectionRef, ChannelId, "1+ 2.", infinity).
success
5> flush().
Shell got {ssh_cm,<0.106.0>,{data,0,1,<<"**Error** {bad_input,\"1+ 2.\"}">>}}
Shell got {ssh_cm,<0.106.0>,{exit_status,0,255}}
Shell got {ssh_cm,<0.106.0>,{eof,0}}
Shell got {ssh_cm,<0.106.0>,{closed,0}}
ok
6>

Note

The {direct, ...} wrapper is required to distinguish from a legacy evaluator interface that lacks I/O support. The legacy form is undocumented and discouraged.

SFTP Server

The SFTP subsystem is not enabled by default. To start an SSH daemon with SFTP, configure the subsystems option explicitly:

1> ssh:start().
ok
2> ssh:daemon(8989, [{system_dir, "/tmp/ssh_daemon"},
                     {user_dir, "/tmp/otptest_user/.ssh"},
                     {subsystems, [ssh_sftpd:subsystem_spec([
                                            {cwd, "/tmp/sftp/example"},
                                            {max_handles, 1000},  % default
                                            {max_path, 4096}      % default
                                           ])
                                  ]}]).
{ok,<0.54.0>}
3>

Run the OpenSSH SFTP client:

$bash> sftp -oPort=8989 -o IdentityFile=/tmp/otptest_user/.ssh/id_rsa \
            -o UserKnownHostsFile=/tmp/otptest_user/.ssh/known_hosts ssh.example.com
Connecting to ssh.example.com...
sftp> pwd
Remote working directory: /tmp/sftp/example
sftp>

SFTP Client

Note

This assumes the remote SSH server has the SFTP subsystem enabled. OpenSSH enables it by default.

Fetch a file with the Erlang SFTP client:

1> ssh:start().
ok
2> {ok, ChannelPid, Connection} = ssh_sftp:start_channel("ssh.example.com", []).
{ok,<0.57.0>,<0.51.0>}
3> ssh_sftp:read_file(ChannelPid, "/home/otptest/test.txt").
{ok,<<"This is a test file\n">>}

SFTP Client with TAR Compression

Basic example

This is an example of writing and then reading a tar file:

{ok,HandleWrite} = ssh_sftp:open_tar(ChannelPid, ?tar_file_name, [write]),
ok = erl_tar:add(HandleWrite, .... ),
ok = erl_tar:add(HandleWrite, .... ),
...
ok = erl_tar:add(HandleWrite, .... ),
ok = erl_tar:close(HandleWrite),

%% And for reading
{ok,HandleRead} = ssh_sftp:open_tar(ChannelPid, ?tar_file_name, [read]),
{ok,NameValueList} = erl_tar:extract(HandleRead,[memory]),
ok = erl_tar:close(HandleRead),

Example with encryption

The previous Basic example can be extended with encryption and decryption as follows:

%% First three parameters depending on which crypto type we select:
Key = <<"This is a 256 bit key. abcdefghi">>,
Ivec0 = crypto:strong_rand_bytes(16),
DataSize = 1024,  % DataSize rem 16 = 0 for aes_cbc

%% Initialization of the CryptoState, in this case it is the Ivector.
InitFun = fun() -> {ok, Ivec0, DataSize} end,

%% How to encrypt:
EncryptFun =
    fun(PlainBin,Ivec) ->
        EncryptedBin = crypto:block_encrypt(aes_cbc256, Key, Ivec, PlainBin),
        {ok, EncryptedBin, crypto:next_iv(aes_cbc,EncryptedBin)}
    end,

%% What to do with the very last block:
CloseFun =
    fun(PlainBin, Ivec) ->
        EncryptedBin = crypto:block_encrypt(aes_cbc256, Key, Ivec,
                                            pad(16,PlainBin) %% Last chunk
                                           ),
       {ok, EncryptedBin}
    end,

Cw = {InitFun,EncryptFun,CloseFun},
{ok,HandleWrite} = ssh_sftp:open_tar(ChannelPid, ?tar_file_name, [write,{crypto,Cw}]),
ok = erl_tar:add(HandleWrite, .... ),
ok = erl_tar:add(HandleWrite, .... ),
...
ok = erl_tar:add(HandleWrite, .... ),
ok = erl_tar:close(HandleWrite),

%% And for decryption (in this crypto example we could use the same InitFun
%% as for encryption):
DecryptFun =
    fun(EncryptedBin,Ivec) ->
        PlainBin = crypto:block_decrypt(aes_cbc256, Key, Ivec, EncryptedBin),
       {ok, PlainBin, crypto:next_iv(aes_cbc,EncryptedBin)}
    end,

Cr = {InitFun,DecryptFun},
{ok,HandleRead} = ssh_sftp:open_tar(ChannelPid, ?tar_file_name, [read,{crypto,Cr}]),
{ok,NameValueList} = erl_tar:extract(HandleRead,[memory]),
ok = erl_tar:close(HandleRead),

Creating a Subsystem

A small ssh subsystem that echoes N bytes can be implemented as shown in the following example:

-module(ssh_echo_server).
-behaviour(ssh_server_channel).
-record(state, {
    n,
    id,
    cm
}).
-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]).

init([N]) ->
    {ok, #state{n = N}}.

handle_msg({ssh_channel_up, ChannelId, ConnectionManager}, State) ->
    {ok, State#state{id = ChannelId,
                     cm = ConnectionManager}}.

handle_ssh_msg({ssh_cm, CM, {data, ChannelId, 0, Data}}, #state{n = N} = State) ->
    M = N - byte_size(Data),
    case M > 0 of
        true ->
            ssh_connection:send(CM, ChannelId, Data),
            {ok, State#state{n = M}};
        false ->
            <<SendData:N/binary, _/binary>> = Data,
            ssh_connection:send(CM, ChannelId, SendData),
            ssh_connection:send_eof(CM, ChannelId),
            {stop, ChannelId, State}
    end;
handle_ssh_msg({ssh_cm, _ConnectionManager,
                {data, _ChannelId, 1, Data}}, State) ->
    logger:notice(" ~p~n", [binary_to_list(Data)]),
    {ok, State};

handle_ssh_msg({ssh_cm, _ConnectionManager, {eof, _ChannelId}}, State) ->
    {ok, State};

handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) ->
    %% Ignore signals according to RFC 4254 section 6.9.
    {ok, State};

handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, _Error, _}},
               State) ->
    {stop, ChannelId, State};

handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, _Status}}, State) ->
    {stop, ChannelId, State}.

terminate(_Reason, _State) ->
    ok.

The subsystem can be run on the host ssh.example.com with the generated keys, as described in Section Running an Erlang ssh Daemon:

1> ssh:start().
ok
2> ssh:daemon(8989, [{system_dir, "/tmp/ssh_daemon"},
                     {user_dir, "/tmp/otptest_user/.ssh"},
                     {subsystems, [{"echo_n", {ssh_echo_server, [10]}}]}]).
{ok,<0.54.0>}
3>

Then connect from an Erlang client:

1> ssh:start().
ok
2> {ok, ConnectionRef} = ssh:connect("ssh.example.com", 8989,
                                    [{user_dir, "/tmp/otptest_user/.ssh"}]).
 {ok,<0.57.0>}
3> {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity).
4> success = ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity).
5> ok = ssh_connection:send(ConnectionRef, ChannelId, "0123456789", infinity).
6> flush().
{ssh_cm, <0.57.0>, {data, 0, 0, <<"0123456789">>}}
{ssh_cm, <0.57.0>, {eof, 0}}
{ssh_cm, <0.57.0>, {closed, 0}}
7> {error, closed} = ssh_connection:send(ConnectionRef, ChannelId, "10", infinity).

See also ssh_client_channel.

Terminology

This chapter explains terms that may cause confusion.

The term "user" is used differently in OpenSSH and SSH in Erlang/OTP. The reason is the different environments and use cases that are not immediately obvious. The following sections explain the differences and give a rationale for why Erlang/OTP handles "user" as it does.

The Term "user" in OpenSSH

Many have been in contact with the command 'ssh' on a Linux machine (or similar) to remotely log in on another machine. One types

ssh host

to log in on the machine named host. The command prompts for your password on the remote host and then you can read, write and execute as your user name has rights on the remote host. There are stronger variants with pre-distributed keys or certificates, but that are for now just details in the authentication process.

You could log in as the user anotheruser with

ssh anotheruser@host

and you will then be enabled to act as anotheruser on the host if authorized correctly.

So what does "your user name has rights" mean? In a UNIX/Linux/etc context it is exactly as that context: The user could read, write and execute programs according to the OS rules. In addition, the user has a home directory ($HOME) and there is a $HOME/.ssh/ directory with ssh-specific files.

Password Authentication

When SSH tries to log in to a host, the ssh protocol communicates the user name (as a string) and a password. The remote ssh server checks that there is such a user defined and that the provided password is acceptable.

If so, the user is authorized.

Public Key Authentication

This is a stronger method where the ssh protocol brings the user name, the user's public key and some cryptographic information which we could ignore here.

The ssh server on the remote host checks:

That the user has a home directory,

that home directory contains a .ssh/ directory and

the .ssh/ directory contains the public key just received in the authorized_keys file

if so, the user is authorized.

After a Successful Authentication

After a successful incoming authentication, a new process runs as the just authenticated user.

Next step is to start a service according to the ssh request. In case of a request of a shell, a new one is started which handles the OS-commands that arrives from the client (that's "you").

In case of a sftp request, an sftp server is started in with the user's rights. So it could read, write or delete files if allowed for that user.

The Term "user" in Erlang/OTP SSH

For the Erlang/OTP SSH server the situation is different. The server executes in an Erlang process in the Erlang emulator which in turn executes in an OS process. The emulator does not try to change its user when authenticated over the SSH protocol. So the remote user name is only for authentication purposes in the Erlang/OTP SSH application.

Password Authentication

The Erlang/OTP SSH server checks the user name and password in the following order:

If a pwdfun is defined, that one is called and the returned boolean is the authentication result.

Else, if the user_passwords option is defined and the username and the password matches, the authentication is a success.

Else, if the option password is defined and matches the password the authentication is a success.

Warning

The password option is intended for testing only.

Public Key Authentication

The user name, public key and cryptographic data (a signature) that is sent by the client are used as follows (some steps left out for clarity):

A callback module is selected using the options key_cb.

The callback module is used to check that the provided public key is one of the user's pre-stored. In case of the default callback module, the files authorized_keys and authorized_keys2 are searched in a directory found in the following order:

If the option user_dir_fun is defined, that fun is called and the returned directory is used,

Else, If the option user_dir is defined, that directory is used,

Else the subdirectory .ssh in the home directory of the user executing the OS process of the Erlang emulator is used.

If the provided public key is not found, the authentication fails.

Finally, if the provided public key is found, the signature provided by the client is checked with the public key.

After a Successful Authentication

Note

Shell, exec, and SFTP are disabled by default. They must be explicitly enabled in the daemon options. See the Hardening guide for details.

After a successful authentication an Erlang process is handling the service request from the remote ssh client. The rights of that process are those of the user of the OS process running the Erlang emulator.

If a shell service request arrives to the server, an Erlang shell is opened in the server's emulator. The rights in that shell is independent of the just authenticated user.

In case of an sftp request, an sftp server is started with the rights of the user of the Erlang emulator's OS process, provided the SFTP subsystem is enabled. So with sftp, the file access rights are those of the OS process running the Erlang emulator, regardless of the authenticated SSH user.

So after an authentication, the user name is not used anymore and has no influence.

Authentication vs Authorization

Authentication verifies identity ("are you who you claim to be?"). Authorization grants permissions ("are you allowed to do this?").

The OpenSSH file authorized_keys is named from a historical convention. Checking a key against this file is authentication, not authorization. Erlang/OTP SSH uses the same filename for compatibility with OpenSSH.

In Erlang/OTP SSH, after successful authentication all operations run with the rights of the OS process running the Erlang emulator, regardless of the authenticated SSH user. See the sections above for details.

Configuration in SSH

The OTP SSH application can be configured by a large number of Options. This chapter will not go into details of what each of the options does. It will however describe and define different ways by which they could be entered.

Options for hardening are described in the Hardening SSH chapter. How the options for algorithm configuration interact are described in the Configuring algorithms in SSH chapter.

Setting Options

There are two ways to set an option:

In the Options parameter in the Erlang code in a call to for example ssh:daemon/3 or ssh:connect/3 or any of their variants. Example:

ssh:connect(22, [{user,"foo"}])

In OTP Configuration Parameters:

In the erl command line:

erl -ssh user \"foo\"

In the ssh.app file, in the env part

{application, ssh,
 [{description, "SSH-2 for Erlang/OTP"},
  {vsn, "4.9"},
  {modules, [ssh,
        ...
        ssh_xfer]},
  {registered, []},
  {applications, [kernel, stdlib, crypto, public_key]},
  {env, [{user, "bar"}]}, % <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< HERE
  {mod, {ssh_app, []}},
       ...

In a .config file:

erl -config ex1

where ex1.config contains:

[{ssh, [{user, "foo"}]}].

If the option is intended only for a server or for a client, it may be set in this way:

[{ssh, [{server_options, [{user, "foo"}]},
        {client_options, [{user, "bar"}]}]}].

A server (daemon) will use the user name foo, and a client will use the name bar.

Precedence

If an option is set in more than one way, what happens?

There is an ordering, which is:

Level 0: Hard-coded default values in the OTP SSH source code

Level 1: OTP Configuration Parameters

Level 2: Options in the OTP Configuration Parameters server_options or client_options

Level 3: Options in argument list to a function

If the same option is set at two different levels, the one at the highest level is used.

Note

The only exception is the modify_algorithms common option. They are all applied in ascending level order on the set of algorithms. So a modify_algorithms on level one is applied before one of level two and so on.

If there is an preferred_algorithms option on some level the whole set is replaced by that in that option and all modify_algorithms are applied in level ordering.

The reason for applying all modify_algorithms in level order, is to enable the user to add an algorithm that has been removed from the default set without code changes, only by adding an option in a config file. This can be used to interoperate with legacy systems that still uses algorithms no longer considered secure enough to be supported by default.

Algorithm Configuration

There is a separate chapter about how preferred_algorithms and modify_algorithms co-operate. How the different configuration levels affect them, is described here in this section.

Algorithms Before and After ssh:start/0

If the application SSH is not started, the command ssh:default_algorithms/0 delivers the list of default (hardcoded) algorithms with respect to the support in the current cryptolib.

If the application SSH is started, the command ssh:default_algorithms/0 delivers the list of algorithms after application of level 0 and level 1 configurations.

Here is an example. The config-file has the following contents:

$ cat ex2.config
[{ssh, [{preferred_algorithms, [{cipher, ['aes192-ctr']},
                                {public_key, ['ssh-rsa']},
                                {kex, ['ecdh-sha2-nistp384']},
                                {mac, ['hmac-sha1']}]}]}].

Erlang is started with ex2.config as configuration and we check the default set of algorithms before starting ssh:

$ erl -config ex2
Erlang/OTP 29 [erts-16.3.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit:ns]

Eshell V16.3.1 (press Ctrl+G to abort, type help(). for help)
1> ssh:default_algorithms().
[{kex,['mlkem768x25519-sha256','curve25519-sha256',
       'curve25519-sha256@libssh.org','curve448-sha512',
       'ecdh-sha2-nistp521','ecdh-sha2-nistp384',
       'ecdh-sha2-nistp256',
       'diffie-hellman-group-exchange-sha256',
       'diffie-hellman-group16-sha512',
       'diffie-hellman-group18-sha512',
       'diffie-hellman-group14-sha256']},
 {public_key,['ssh-ed25519','ssh-ed448','ecdsa-sha2-nistp521',
              'ecdsa-sha2-nistp384','ecdsa-sha2-nistp256',
              'rsa-sha2-512','rsa-sha2-256']},
 {cipher,[{client2server,['aes256-gcm@openssh.com','aes256-ctr',
                          'aes192-ctr','aes128-gcm@openssh.com',
                          'aes128-ctr',
                          'chacha20-poly1305@openssh.com']},
          {server2client,['aes256-gcm@openssh.com','aes256-ctr',
                          'aes192-ctr','aes128-gcm@openssh.com',
                          'aes128-ctr',
                          'chacha20-poly1305@openssh.com']}]},
 {mac,[{client2server,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']},
       {server2client,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']}]},
 {compression,[{client2server,[none,'zlib@openssh.com']},
               {server2client,[none,'zlib@openssh.com']}]}]

Note that the algorithms in the file ex2.config is not yet applied. They will be when we start ssh:

2> ssh:start().
ok
3> ssh:default_algorithms().
[{kex,['ecdh-sha2-nistp384']},
 {public_key,['ssh-rsa']},
 {cipher,[{client2server,['aes192-ctr']},
          {server2client,['aes192-ctr']}]},
 {mac,[{client2server,['hmac-sha1']},
       {server2client,['hmac-sha1']}]},
 {compression,[{client2server,[none,'zlib@openssh.com']},
               {server2client,[none,'zlib@openssh.com']}]}]
4>

We see that the algorithm set is changed to the one in the ex2.config. Since compression is not specified in the file, the hard-coded default is still used for that entry.

Options in ssh:connect and ssh:daemon

Both when the client establishes a connection with ssh:connect or other functions, or a daemon is started with ssh:daemon, the option lists in the function calls are also used.

If a client is started (ssh:connect et al), the environment variable client_options is used. Similarly for a daemon the server_options variable is handled.

If any preferred_algorithms is present, the one with the highest level is used, that is, the Option list parameter has the highest priority. Then the modify_algorithms on all levels in order starting with level 0 are applied.

We continue the example above by connecting to a server and modifying the kex algorithm set. We remove the only one ('ecdh-sha2-nistp384') and add 'curve25519-sha256@libssh.org' by appending it to the now empty list:

4> {ok,C} = ssh:connect(loopback, 22,
     [{modify_algorithms,
         [{rm,     [{kex, ['ecdh-sha2-nistp384']}]},
          {append, [{kex, ['curve25519-sha256@libssh.org']}]}]}]).
{ok,<0.118.0>}

We check which algorithms are negotiated by the client and the server, and note that the (only) kex algorithm 'curve25519-sha256@libssh.org' was selected:

5> ssh:connection_info(C, algorithms).
{algorithms,[{kex,'curve25519-sha256@libssh.org'},
             {hkey,'ssh-rsa'},
             {send_mac,'hmac-sha1'},
             {recv_mac,'hmac-sha1'},
             {encrypt,'aes192-ctr'},
             {decrypt,'aes192-ctr'},
             {compress,none},
             {decompress,none},
             {send_ext_info,false},
             {recv_ext_info,true}]}

Example: modify_algorithms Across Levels

We will now check if the modify_algorithms on a lower level is applied to a preferred_algorithms on a higher level. We will do that by enabling the ssh-dss algorithm that is supported, but not in the default set.

The config file ex3.config has the contents:

[{ssh, [{modify_algorithms,
         [{prepend, [{public_key, ['ssh-dss']}]}]}]}].

A newly started erlang shell shows that no 'ssh-dss' is present in the public_key entry:

1> proplists:get_value(public_key, ssh:default_algorithms()).
['ssh-ed25519','ssh-ed448','ecdsa-sha2-nistp521',
 'ecdsa-sha2-nistp384','ecdsa-sha2-nistp256',
 'rsa-sha2-512','rsa-sha2-256']
2>

A call to ssh:connect/3 removes all algorithms but one of each type:

2> ssh:start().
ok
3> {ok,C} = ssh:connect(loopback, 22,
     [{preferred_algorithms,
         [{public_key, ['ecdsa-sha2-nistp256']},
          {kex, ['ecdh-sha2-nistp256']},
          {cipher, ['chacha20-poly1305@openssh.com']},
          {mac, ['hmac-sha2-256']},
          {compression, [none]}]}]).
{ok,<0.101.0>}
4> ssh:connection_info(C,algorithms).
{algorithms,[{kex,'ecdh-sha2-nistp256'},
             {hkey,'ssh-dss'},
             {send_mac,'chacha20-poly1305@openssh.com'},
             {recv_mac,'chacha20-poly1305@openssh.com'},
             {encrypt,'chacha20-poly1305@openssh.com'},
             {decrypt,'chacha20-poly1305@openssh.com'},
             {compress,none},
             {decompress,none},
             {send_ext_info,false},
             {recv_ext_info,true}]}
5>

But 'ssh-dss' is selected although the call inserted only 'ecdsa-sha2-nistp256' as acceptable.

This example showed that we could augment the set of algorithms with a config-file without the need to change the actual call.

For demonstration purposes we used prepend instead of append. This forces the negotiation to select ssh-dss since the full list of public key algorithms was ['ssh-dss','ecdsa-sha2-nistp256']. Normally it is safer to append a non-default algorithm.

Configuring algorithms in SSH

To fully understand how to configure the algorithms, it is essential to have a basic understanding of the SSH protocol and how OTP SSH application handles the corresponding items.

The first section will give a short background of the SSH protocol while later sections describe the implementation and provide some examples.

How the different levels of configuration interact with this, see the section Algorithm Configuration in the chapter Configuration in SSH.

Algorithm Negotiation in SSH

SSH uses different sets of algorithms in different phases of a session. Which algorithms to use is negotiated by the client and the server at the beginning of a session. See RFC 4253, "The Secure Shell (SSH) Transport Layer Protocol" for details.

The negotiation is simple: both peers send their list of supported algorithms to the other party. The first algorithm on the client's list that is also on the server's list is selected. So it is the client's ordering of the list that gives the priority for the algorithms.

There are five lists exchanged in the connection setup. Three of them are also divided in two directions, to and from the server.

The lists are (named as in the SSH application's options):

kex - Key exchange

An algorithm is selected for computing a secret encryption key. Among examples are: the old and weak 'diffie-hellman-group-exchange-sha1' and the modern 'mlkem768x25519-sha256' (a post-quantum hybrid key exchange).

public_key - Server host key

The asymmetric encryption algorithm used in the server's private-public host key pair. Examples include the well-known RSA 'ssh-rsa' and elliptic curve 'ecdsa-sha2-nistp521'.

cipher - Symmetric cipher algorithm used for the payload encryption. This algorithm will use the key calculated in the kex phase (together with other info) to generate the actual key used. Examples are triple-DES '3des-cbc' and one of many AES variants 'aes192-ctr'.

This list is actually two - one for each direction server-to-client and client-to-server. Therefore it is possible but rare to have different algorithms in the two directions in one connection.

mac - Message authentication code

"Check sum" of each message sent between the peers. Examples are SHA 'hmac-sha1' and SHA2 'hmac-sha2-512'.

This list is also divided into two for the both directions

compression - If and how to compress the message. Examples are none, that is, no compression, zlib for pre-authentication compression (deprecated in SSH and it's usage is scheduled for removal in OTP 30.0), and 'zlib@openssh.com' for post-authentication compression.

This list is also divided into two for the both directions

Default Algorithms

The set of algorithms that the SSH application uses by default depends on the algorithms supported by the:

crypto application,

The cryptolib OTP is linked with, usually the one the OS uses, probably OpenSSL,

and finally what the SSH application implements

Due to this, it is impossible to list in documentation what algorithms are available in a certain installation.

There is an important command to list the actual algorithms and their ordering: ssh:default_algorithms/0.

0> ssh:default_algorithms().
[{kex,['mlkem768x25519-sha256','curve25519-sha256',
       'curve25519-sha256@libssh.org','curve448-sha512',
       'ecdh-sha2-nistp521','ecdh-sha2-nistp384','ecdh-sha2-nistp256',
       'diffie-hellman-group-exchange-sha256',
       'diffie-hellman-group16-sha512',
       'diffie-hellman-group18-sha512',
       'diffie-hellman-group14-sha256']},
 {public_key,['ssh-ed25519','ssh-ed448','ecdsa-sha2-nistp521',
              'ecdsa-sha2-nistp384','ecdsa-sha2-nistp256',
              'rsa-sha2-512','rsa-sha2-256']},
 {cipher,[{client2server,['aes256-gcm@openssh.com','aes256-ctr',
                          'aes192-ctr','aes128-gcm@openssh.com',
                          'aes128-ctr',
                          'chacha20-poly1305@openssh.com']},
          {server2client,['aes256-gcm@openssh.com','aes256-ctr',
                          'aes192-ctr','aes128-gcm@openssh.com',
                          'aes128-ctr',
                          'chacha20-poly1305@openssh.com']}]},
 {mac,[{client2server,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']},
       {server2client,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']}]},
 {compression,[{client2server,[none,'zlib@openssh.com']},
               {server2client,[none,'zlib@openssh.com']}]}]

To change the algorithm list, there are two options which can be used in ssh:connect/2,3,4 and ssh:daemon/2,3. The options could of course be used in all other functions that initiates connections.

The options are preferred_algorithms and modify_algorithms. The first one replaces the default set, while the latter modifies the default set.

Replacing Defaults: preferred_algorithms

See the Reference Manual for details

Here follows a series of examples ranging from simple to more complex.

To foresee the effect of an option there is an experimental function ssh:chk_algos_opts(Opts). It applies the options preferred_algorithms and modify_algorithms in the same way as ssh:daemon, ssh:connect and their friends does.

Example 1

Replace the kex algorithms list with the single algorithm 'diffie-hellman-group14-sha256':

1> ssh:chk_algos_opts(
     [{preferred_algorithms,
         [{kex, ['diffie-hellman-group14-sha256']}]}]).
[{kex,['diffie-hellman-group14-sha256']},
 {public_key,['ssh-ed25519','ssh-ed448','ecdsa-sha2-nistp521',
              'ecdsa-sha2-nistp384','ecdsa-sha2-nistp256',
              'rsa-sha2-512','rsa-sha2-256']},
 {cipher,[{client2server,['aes256-gcm@openssh.com','aes256-ctr',
                          'aes192-ctr','aes128-gcm@openssh.com',
                          'aes128-ctr',
                          'chacha20-poly1305@openssh.com']},
          {server2client,['aes256-gcm@openssh.com','aes256-ctr',
                          'aes192-ctr','aes128-gcm@openssh.com',
                          'aes128-ctr',
                          'chacha20-poly1305@openssh.com']}]},
 {mac,[{client2server,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']},
       {server2client,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']}]},
 {compression,[{client2server,[none,'zlib@openssh.com']},
               {server2client,[none,'zlib@openssh.com']}]}]

Note that the unmentioned lists (public_key, cipher, mac and compression) are unchanged.

Example 2

In the lists that are divided in two for the two directions (for example cipher) it is possible to change both directions at once:

2> ssh:chk_algos_opts(
     [{preferred_algorithms,
         [{cipher, ['aes128-ctr']}]}]).
[{kex,['mlkem768x25519-sha256','curve25519-sha256',
       'curve25519-sha256@libssh.org','curve448-sha512',
       'ecdh-sha2-nistp521','ecdh-sha2-nistp384','ecdh-sha2-nistp256',
       'diffie-hellman-group-exchange-sha256',
       'diffie-hellman-group16-sha512',
       'diffie-hellman-group18-sha512',
       'diffie-hellman-group14-sha256']},
 {public_key,['ssh-ed25519','ssh-ed448','ecdsa-sha2-nistp521',
              'ecdsa-sha2-nistp384','ecdsa-sha2-nistp256',
              'rsa-sha2-512','rsa-sha2-256']},
 {cipher,[{client2server,['aes128-ctr']},
          {server2client,['aes128-ctr']}]},
 {mac,[{client2server,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']},
       {server2client,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']}]},
 {compression,[{client2server,[none,'zlib@openssh.com']},
               {server2client,[none,'zlib@openssh.com']}]}]

Note that both lists in cipher has been changed to the provided value ('aes128-ctr').

Example 3

In the lists that are divided in two for the two directions (for example cipher) it is possible to change only one of the directions:

3> ssh:chk_algos_opts(
     [{preferred_algorithms,
         [{cipher, [{client2server, ['aes128-ctr']}]}]}]).
[{kex,['mlkem768x25519-sha256','curve25519-sha256',
       'curve25519-sha256@libssh.org','curve448-sha512',
       'ecdh-sha2-nistp521','ecdh-sha2-nistp384','ecdh-sha2-nistp256',
       'diffie-hellman-group-exchange-sha256',
       'diffie-hellman-group16-sha512',
       'diffie-hellman-group18-sha512',
       'diffie-hellman-group14-sha256']},
 {public_key,['ssh-ed25519','ssh-ed448','ecdsa-sha2-nistp521',
              'ecdsa-sha2-nistp384','ecdsa-sha2-nistp256',
              'rsa-sha2-512','rsa-sha2-256']},
 {cipher,[{client2server,['aes128-ctr']},
          {server2client,['aes256-gcm@openssh.com','aes256-ctr',
                          'aes192-ctr','aes128-gcm@openssh.com',
                          'aes128-ctr',
                          'chacha20-poly1305@openssh.com']}]},
 {mac,[{client2server,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']},
       {server2client,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']}]},
 {compression,[{client2server,[none,'zlib@openssh.com']},
               {server2client,[none,'zlib@openssh.com']}]}]

Example 4

It is of course possible to change more than one list:

4> ssh:chk_algos_opts(
     [{preferred_algorithms,
         [{cipher, ['aes128-ctr']},
          {mac, ['hmac-sha2-256']},
          {kex, ['ecdh-sha2-nistp384']},
          {public_key, ['ssh-rsa']},
          {compression, [{server2client, [none]},
                         {client2server, [zlib]}]}]}]).
[{kex,['ecdh-sha2-nistp384']},
 {public_key,['ssh-rsa']},
 {cipher,[{client2server,['aes128-ctr']},
          {server2client,['aes128-ctr']}]},
 {mac,[{client2server,['hmac-sha2-256']},
       {server2client,['hmac-sha2-256']}]},
 {compression,[{client2server,[zlib]},
               {server2client,[none]}]}]

Note that the order of the tuples in the lists does not matter.

Modifying Defaults: modify_algorithms

A situation where it might be useful to add an algorithm is when one need to use a supported but disabled one. An example is the 'diffie-hellman-group1-sha1' which nowadays is very unsecure and therefore disabled. It is however still supported and might be used.

The option preferred_algorithms may be complicated to use for adding or removing single algorithms. First one has to list them with ssh:default_algorithms() and then do changes in the lists.

To facilitate addition or removal of algorithms the option modify_algorithms is available. See the Reference Manual for details.

The option takes a list with instructions to append, prepend or remove algorithms:

{modify_algorithms, [{append,  ...},
                     {prepend, ...},
                     {rm,      ...}]}

Each of the ... can be a algs_list() as the argument to the preferred_algorithms option.

Example 5

As an example let's add the Diffie-Hellman Group1 first in the kex list. It is supported according to Supported algorithms.

5> ssh:chk_algos_opts(
     [{modify_algorithms,
         [{prepend, [{kex, ['diffie-hellman-group1-sha1']}]}]}]).
[{kex,['diffie-hellman-group1-sha1','mlkem768x25519-sha256',
       'curve25519-sha256','curve25519-sha256@libssh.org',
       'curve448-sha512','ecdh-sha2-nistp521','ecdh-sha2-nistp384',
       'ecdh-sha2-nistp256','diffie-hellman-group-exchange-sha256',
       'diffie-hellman-group16-sha512',
       'diffie-hellman-group18-sha512',
       'diffie-hellman-group14-sha256']},
 {public_key,['ssh-ed25519','ssh-ed448','ecdsa-sha2-nistp521',
              'ecdsa-sha2-nistp384','ecdsa-sha2-nistp256',
              'rsa-sha2-512','rsa-sha2-256']},
 {cipher,[{client2server,['aes256-gcm@openssh.com','aes256-ctr',
                          'aes192-ctr','aes128-gcm@openssh.com',
                          'aes128-ctr',
                          'chacha20-poly1305@openssh.com']},
          {server2client,['aes256-gcm@openssh.com','aes256-ctr',
                          'aes192-ctr','aes128-gcm@openssh.com',
                          'aes128-ctr',
                          'chacha20-poly1305@openssh.com']}]},
 {mac,[{client2server,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']},
       {server2client,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']}]},
 {compression,[{client2server,[none,'zlib@openssh.com']},
               {server2client,[none,'zlib@openssh.com']}]}]

And the result shows that the Diffie-Hellman Group1 is added at the head of the kex list

Example 6

In this example, we in put the 'diffie-hellman-group1-sha1' first and also move the 'ecdh-sha2-nistp521' to the end in the kex list, that is, append it.

6> ssh:chk_algos_opts(
     [{modify_algorithms,
         [{prepend, [{kex, ['diffie-hellman-group1-sha1']}]},
          {append,  [{kex, ['ecdh-sha2-nistp521']}]}]}]).
[{kex,['diffie-hellman-group1-sha1','mlkem768x25519-sha256',
       'curve25519-sha256','curve25519-sha256@libssh.org',
       'curve448-sha512','ecdh-sha2-nistp384','ecdh-sha2-nistp256',
       'diffie-hellman-group-exchange-sha256',
       'diffie-hellman-group16-sha512',
       'diffie-hellman-group18-sha512',
       'diffie-hellman-group14-sha256','ecdh-sha2-nistp521']},
 {public_key,['ssh-ed25519','ssh-ed448','ecdsa-sha2-nistp521',
              'ecdsa-sha2-nistp384','ecdsa-sha2-nistp256',
              'rsa-sha2-512','rsa-sha2-256']},
 {cipher,[{client2server,['aes256-gcm@openssh.com','aes256-ctr',
                          'aes192-ctr','aes128-gcm@openssh.com',
                          'aes128-ctr',
                          'chacha20-poly1305@openssh.com']},
          {server2client,['aes256-gcm@openssh.com','aes256-ctr',
                          'aes192-ctr','aes128-gcm@openssh.com',
                          'aes128-ctr',
                          'chacha20-poly1305@openssh.com']}]},
 {mac,[{client2server,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']},
       {server2client,['hmac-sha2-512-etm@openssh.com',
                       'hmac-sha2-256-etm@openssh.com',
                       'hmac-sha2-512','hmac-sha2-256',
                       'hmac-sha1-etm@openssh.com','hmac-sha1']}]},
 {compression,[{client2server,[none,'zlib@openssh.com']},
               {server2client,[none,'zlib@openssh.com']}]}]

Note that the appended algorithm is removed from its original place and then appended to the same list.

Example 7

In this example, we use both options (preferred_algorithms and modify_algorithms) and also try to prepend an unsupported algorithm. Any unsupported algorithm is quietly removed.

7> ssh:chk_algos_opts(
     [{preferred_algorithms,
         [{cipher, ['aes128-ctr']},
          {mac, ['hmac-sha2-256']},
          {kex, ['ecdh-sha2-nistp384']},
          {public_key, ['ssh-rsa']},
          {compression, [{server2client, [none]},
                         {client2server, [zlib]}]}]},
      {modify_algorithms,
         [{prepend, [{kex, ['some unsupported algorithm']}]},
          {append,  [{kex, ['diffie-hellman-group1-sha1']}]}]}]).
[{kex,['ecdh-sha2-nistp384','diffie-hellman-group1-sha1']},
 {public_key,['ssh-rsa']},
 {cipher,[{client2server,['aes128-ctr']},
          {server2client,['aes128-ctr']}]},
 {mac,[{client2server,['hmac-sha2-256']},
       {server2client,['hmac-sha2-256']}]},
 {compression,[{client2server,[zlib]},
               {server2client,[none]}]}]

It is of course questionable why anyone would like to use the both these options together, but it is possible if an unforeseen need should arise.

Example 8

In this example, we need to use a diffie-hellman-group1-sha1 key exchange algorithm although it is unsafe and disabled by default.

We use the modify_algorithms option, because we want to keep all other algorithm definitions.

We add the option:

  {modify_algorithms, [{append, [{kex,['diffie-hellman-group1-sha1']}]}]}

either to the Options list in a function call, in the ssh.app file or in a .config file for the erl command. See the chapter Configuration in SSH in the SSH User's Guide.

Example 9

In this example, we need to use a DSA key for sign and verify. It might be either as a user's key, a host's key or both.

To do that, we enable the 'ssh-dss' algorithm that is disabled by default by security reasons. We use the modify_algorithms option, because we want to keep all other algorithm definitions.

We add the option:

  {modify_algorithms, [{append, [{public_key,['ssh-dss']}]}]}

either to the Options list in a function call, in the ssh.app file or in a .config file for the erl command. See the chapter Configuration in SSH in the SSH User's Guide.

Hardening

The Erlang/OTP SSH application is intended to be used in other applications as a library.

Ensure the Erlang VM runs as a non-root OS user. All SSH services (shell, exec, SFTP) inherit the OS-level rights of the VM process. See Terminology for details on the rights model.

Different applications using this library may have very different requirements. One application could be running on a high performance server, while another is running on a small device with very limited cpu capacity. For example, the first one may accept many users simultaneously logged in, while the second one wants to limit them to only one.

That simple example shows that it is impossible to deliver the SSH application with default values on hardening options as well on other options that suit every need.

The purpose of this guide is to discuss the different hardening options available, as a guide to the reader. Configuration in general is described in the Configuration in SSH chapter.

DoS Resilience (Server)

The following applies to daemons (servers).

DoS (Denial of Service) attacks are hard to fight at the node level. Here are firewalls and other means needed, but that is out of scope for this guide. However, some measures could be taken in the configuration of the SSH server to increase the resilence. The options to use are:

Counters and Parallelism

max_sessions - The maximum number of simultaneous sessions that are accepted at any time for this daemon. This includes sessions that are being authenticated. The default is that an unlimited number of simultaneous sessions are allowed. It is a good candidate to set if the capacity of the server is low or a capacity margin is needed.

max_channels - The maximum number of channels that are accepted for each connection. The default is unlimited.

parallel_login - If set to false (the default value), only one login is handled at a time. If set to true, the number of simultaneous login attempts are limited by the value of the max_sessions option.

Timeouts

hello_timeout - If the client fails to send the first ssh message after a tcp connection setup within this time (in milliseconds), the connection is closed. The default value is 30 seconds. This is actually a generous time, so it can lowered to make the daemon less prone to DoS attacks.

negotiation_timeout - Maximum time in milliseconds for the authentication negotiation counted from the TCP connection establishment. If the client fails to log in within this time the connection is closed. The default value is 2 minutes. It is quite a long time, but can lowered if the client is supposed to be fast like if it is a program logging in.

idle_time - Sets a time-out on a connection when no channels are left after closing the final one. It defaults to infinity.

max_initial_idle_time - Sets a time-out on a connection that will expire if no channel is opened on the connection. The timeout is started when the authentication phase is completed. It defaults to infinity.

alive - Sets the interval and the maximum number of alive messages that may be sent without receiving any message back. Alive messages are typically used to detect that a connection became unresponsive.

The following table clarifies when a timeout is started and when it triggers:

# | Event | Timeout started | Timeout ended
1 | TCP connected | hello_timeout, negotiation_timeout |
2 | First SSH message received |  | hello_timeout
3 | Key Exchange finished |  |
4 | Authenticated | max_initial_idle_time | negotiation_timeout
5 | Channel 1 opened |  | max_initial_idle_time
6 | Channel n opened |  |
7 | Channel x_1 closed |  |
8 | Channel x_n closed (all channels closed) | idle_time |
9 | Connection closed |  | idle_time

Compression

SSH supports compression of the data stream.

Reasonable finite max_sessions option is highly recommended if compression is used to prevent excessive resource usage by the compression library. See Counters and parallelism.

The 'zlib@openssh.com' algorithm is recommended because it only activates after successful authentication.

The 'zlib' algorithm (deprecated in SSH and it's usage is scheduled for removal in OTP 30.0) is not recommended because it activates before authentication completes, allowing unauthenticated clients to expose potential vulnerabilities in compression libraries, and increases attack surface of compression-based side-channel and traffic-analysis attacks.

In both algorithms decompression is protected by a size limit that prevents excessive memory consumption.

Reducing Attack Surface

Shell and Exec Services

A daemon has two services for evaluating tasks on behalf of a remote client. The exec server-side service takes a string provided by the client, evaluates it and returns the result. The shell function enables the client to open a shell in the shell host.

The options exec and shell are disabled per default. The same options could also install handlers for the string(s) passed from the client to the server.

SFTP Subsystem

The SFTP subsystem is not enabled by default. When enabled, SFTP provides access to the file system with the rights of the OS process running the Erlang emulator, regardless of the authenticated SSH user. See the Terminology section for details.

The subsystems option controls which subsystems are available. To enable SFTP:

ssh:daemon({192, 168, 1, 10}, Port,
           [{subsystems, [ssh_sftpd:subsystem_spec([])]} | Options]).

Root directory isolation

The root option (see ssh_sftpd) restricts SFTP users to a specific directory tree, preventing access to files outside that directory.

ssh:daemon(Port, [
    {subsystems, [ssh_sftpd:subsystem_spec([{root, "/home/sftpuser"}])]},
    ...
]).

The root option is configured per daemon, not per user. All users connecting to the same daemon share the same root directory. For per-user isolation, consider running separate daemon instances on different ports or using OS-level mechanisms (PAM chroot, containers, file permissions).

For high-security deployments, combine the root option with OS-level isolation mechanisms such as chroot jails, containers, or mandatory access control (SELinux, AppArmor).

Resource limits

When enabling the SFTP subsystem via ssh_sftpd:subsystem_spec/1, additional resource limits can be configured to protect against resource exhaustion attacks:

max_handles limits the maximum number of file and directory handles that can be opened simultaneously per SFTP connection. The default is 1000.

Recommended values by deployment type:

High-security/restricted environments: 100-256

Minimal attack surface

Suitable for simple file transfers

May impact batch operations

Standard production: 500-1000

Balances security and functionality

Supports most legitimate use cases

Recommended for general deployments

Note: The default value is 1000

High-throughput automation: 1000-2000

For backup systems, CI/CD pipelines

Parallel file operations

Monitor actual usage before increasing

max_path limits the maximum path length accepted from SFTP clients. The default is 4096 bytes.

Recommended values:

Standard: 4096 (default)

Accommodates most filesystem limits

Linux: typically 4096 bytes

Windows: 260 characters (legacy), 32767 (extended)

Restricted environments: 1024-2048

If application uses shorter paths

Additional defense layer

Verify compatibility first

max_files limits the number of filenames returned per READDIR request. The default is 0 (unlimited).

This option prevents memory exhaustion from large directory listings. Unlike max_handles and max_path, this is primarily a performance/memory protection rather than security mitigation.

Recommended values:

Standard: 0 (unlimited, default)

No artificial restrictions

Client handles pagination

Large directories: 1000-10000

Prevents memory spikes

Improves response time

Memory-constrained systems: 100-1000

Embedded systems

Resource-limited containers

Example configuration

ssh:daemon(Port, [
    {system_dir, "/etc/ssh"},
    {subsystems, [
        ssh_sftpd:subsystem_spec([
            {root, "/sftp/chroot"},
            {max_handles, 256},
            {max_path, 4096},
            {max_files, 1000}
        ])
    ]},
    {max_sessions, 10}
]).

See ssh_sftpd for complete documentation of subsystem options.

The ID String

One way to reduce the risk of intrusion is to not convey which software and which version the intruder is connected to. This limits the risk of an intruder exploiting known faults or peculiarities learned by reading the public code.

Each SSH client or daemon presents themselves to each other with brand and version. This may look like

SSH-2.0-Erlang/4.10

or

SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3

This brand and version may be changed with the option id_string. We start a daemon with that option:

        ssh:daemon({192, 168, 1, 10}, 1234, [{id_string,"hi there"}, ... ]).

and the daemon will present itself as:

SSH-2.0-hi there

It is possible to replace the string with one randomly generated for each connection attempt. See the reference manual for id_string.

Cryptographic Hardening

Algorithm Selection

One of the cornerstones of security in SSH is cryptography. The development in crypto analysis is fast, and yesterday's secure algorithms are unsafe today. Therefore some algorithms are no longer enabled by default and that group grows with time. See the SSH (App) for a list of supported and disabled algorithms. In the User's Guide the chapter Configuring algorithms in SSH describes the options for enabling or disabling algorithms - preferred_algorithms and modify_algorithms.

Post-Quantum Key Exchange

The mlkem768x25519-sha256 algorithm provides quantum-resistant key exchange using a hybrid construction that combines ML-KEM-768 (NIST FIPS 203) with X25519. When the underlying crypto library supports ML-KEM, this algorithm is negotiated by default as the highest-priority key exchange method. No configuration is needed to enable it.

Re-Keying

In the setup of the SSH connection a secret cipher key is generated by co-operation of the client and the server. Keeping this key secret is crucial for keeping the communication secret. As time passes and encrypted messages are exchanged, the probability that a listener could guess that key increases.

The SSH protocol therefore has a special operation defined - key re-negotiation or re-keying. Any side (client or server) could initiate the re-keying and the result is a new cipher key. The result is that the eavesdropper has to restart its evil and dirty craftsmanship.

See the option rekey_limit for a description.

Verifying the Remote Daemon (Server) in an SSH Client

Every SSH server presents a public key - the host key - to the client while keeping the corresponding private key in relatively safe privacy.

The client checks that the host that presented the public key also possesses the private key of the key-pair. That check is part of the SSH protocol.

But how can the client know that the host really is the one that it tried to connect to and not an evil one impersonating the expected one using its own valid key-pair? There are two alternatives available with the default key handling plugin ssh_file. The alternatives are:

Pre-store the host key - For the default handler ssh_file, store the valid host keys in the file known_hosts and set the option silently_accept_hosts to false. Alternatively, write a specialized key handler using the SSH client key API that accesses the pre-shared key in some other way.

Pre-store the "fingerprint" (checksum) of the host key - Use silently_accept_hosts with a callback: accept_callback() or {HashAlgoSpec, accept_callback()}.

Verifying the Remote Client in a Daemon (Server)

Password checking - The default password checking is with the list in the user_passwords option in the SSH daemon. It could be replaced with a pwdfun plugin. The arity four variant (pwdfun_4()) can also be used for introducing delays after failed password checking attempts. Here is a simple example of such a pwdfun:

fun(User, Password, _PeerAddress, State) ->
        case lists:member({User,Password}, my_user_pwds()) of
            true ->
                {true, undefined}; % Reset delay time
            false when State == undefined ->
                timer:sleep(1000),
                {false, 2000}; % Next delay is 2000 ms
            false when is_integer(State) ->
                timer:sleep(State),
                {false, 2*State} % Double the delay for each failure
        end
end.

If a public key is used for logging in, there is normally no checking of the user name. It could be enabled by setting the option pk_check_user to true. In that case the pwdfun will get the atom pubkey in the password argument.

Client Connection Options

A client could limit the time for the initial tcp connection establishment with the option connect_timeout. The time is in milliseconds, and the initial value is infinity.

The negotiation (session setup time) time can be limited with the parameter NegotiationTimeout in a call establishing an ssh session, for example ssh:connect/3.

Network-Level Security

IP Binding Restrictions

ssh:daemon/1 and ssh:daemon/2 bind to all network interfaces by default. For hardened deployments, use ssh:daemon/3 with an explicit IP address or loopback:

ssh:daemon({192, 168, 1, 10}, 2222, Options).  % Specific interface
ssh:daemon(loopback, 2222, Options).            % Localhost only

Note: In the examples above, HostAddress (1st argument) takes precedence over a potentially provided {ip, Address} in Options (3rd argument).

Advanced Authentication

The following techniques provide enhanced authentication controls using custom callbacks. These require implementation specific to your environment.

Public Key Validation

Use a custom key_cb module implementing the ssh_server_key_api behaviour. The is_auth_key callback can enforce client key strength requirements (e.g. reject RSA keys shorter than 2048 bits) and log key usage for auditing. Enable pk_check_user to verify that the username is known before accepting public key authentication.

ssh:daemon({192, 168, 1, 10}, Port, [
    {key_cb, {my_key_handler, []}},
    {pk_check_user, true}
]).

Account Lockout Policies

Use pwdfun with an ETS table to track failed attempts across connections and lock accounts after repeated failures. Return disconnect when the account is locked — this immediately terminates the connection with SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE:

Note

The lockout example below is conceptual. With parallel_login enabled, race conditions may reduce lockout accuracy.

lockout_pwdfun(User, Password, _PeerAddr, State) ->
    case ets:lookup(ssh_lockouts, {locked, User}) of
        [_] ->
            disconnect;
        [] ->
            case validate_password(User, Password) of
                true ->
                    ets:delete(ssh_lockouts, {attempts, User}),
                    {true, State};
                false ->
                    N = ets:update_counter(ssh_lockouts,
                            {attempts, User}, 1,
                            {{attempts, User}, 0}),
                    case N >= ?LOCKOUT_THRESHOLD of
                        true ->
                            ets:insert(ssh_lockouts,
                                {{locked, User}, true}),
                            ets:delete(ssh_lockouts,
                                {attempts, User});
                        false ->
                            ok
                    end,
                    {false, State}
            end
    end.

ssh

Main API of the ssh application

This is the interface module for the SSH application. The Secure Shell (SSH) Protocol is a protocol for secure remote login and other secure network services over an insecure network. See ssh for details of supported RFCs, versions, algorithms and unicode handling.

With the SSH application it is possible to start clients and to start daemons (servers).

Clients are started with connect/2, connect/3 or connect/4. They open an encrypted connection on top of TCP/IP. In that encrypted connection one or more channels could be opened with ssh_connection:session_channel/2,4.

Each channel is an isolated "pipe" between a client-side process and a server-side process. Those process pairs could handle for example file transfers (sftp) or remote command execution (shell, exec and/or cli). If a custom shell is implemented, the user of the client could execute the special commands remotely. Note that the user is not necessarily a human but probably a system interfacing the SSH application.

A server-side subssystem (channel) server is requested by the client with ssh_connection:subsystem/4.

A server (daemon) is started with daemon/1, daemon/2 or daemon/3. Possible channel handlers (subsystems) are declared with the subsystem option when the daemon is started.

To just run a shell on a remote machine, there are functions that bundles the needed three steps needed into one: shell/1,2,3. Similarly, to just open an sftp (file transfer) connection to a remote machine, the simplest way is to use ssh_sftp:start_channel/1,2,3.

To write your own client channel handler, use the behaviour ssh_client_channel. For server channel handlers use ssh_server_channel behaviour (replaces ssh_daemon_channel).

Both clients and daemons accept options that control the exact behaviour. Some options are common to both. The three sets are called Client Options, Daemon Options and Common Options.

The descriptions of the options uses the Erlang Type Language with explaining text.

Note

See also SSH Application Reference and Examples section.

Keys and files

A number of objects must be present for the SSH application to work. Those objects are per default stored in files. The default names, paths and file formats are the same as for OpenSSH. Keys could be generated with the ssh-keygen program from OpenSSH. See the User's Guide.

The paths could easily be changed by options: user_dir and system_dir.

A completely different storage could be interfaced by writing callback modules using the behaviours ssh_client_key_api and/or ssh_server_key_api. A callback module is installed with the option key_cb to the client and/or the daemon.

Daemons

The keys are by default stored in files:

Mandatory: one or more Host key(s), both private and public. Default is to store them in the directory /etc/ssh in the files

ssh_host_dsa_key and ssh_host_dsa_key.pub

ssh_host_rsa_key and ssh_host_rsa_key.pub

ssh_host_ecdsa_key and ssh_host_ecdsa_key.pub

The host keys directory could be changed with the option system_dir.

Optional: one or more User's public key in case of publickey authorization. Default is to store them concatenated in the file .ssh/authorized_keys in the user's home directory.

The user keys directory could be changed with the option user_dir.

Clients

The keys and some other data are by default stored in files in the directory .ssh in the user's home directory.

The directory could be changed with the option user_dir.

Optional: a list of Host public key(s) for previously connected hosts. This list is handled by the SSH application without any need of user assistance. The default is to store them in the file known_hosts.

The host_accepting_client_options/0 are associated with this list of keys.

Optional: one or more User's private key(s) in case of publickey authorization. The default files are

id_dsa and id_dsa.pub

id_rsa and id_rsa.pub

id_ecdsa and id_ecdsa.pub

Summary

Types: Client Options

accept_callback()

accept_hosts()

authentication_client_options()

client_option()

Options for clients. The individual options are further explained below or by following the hyperlinks.

client_options()

connect_timeout_client_option()

Sets a timeout on the transport layer connect time. For gen_tcp the time is in milli-seconds and the default value is infinity.

diffie_hellman_group_exchange_client_option()

Sets the three diffie-hellman-group-exchange parameters that guides the connected server in choosing a group. See RFC 4419 for the details. The default value is {1024, 6144, 8192}.

fingerprint()

fp_digest_alg()

host_accepting_client_options()

recv_ext_info_client_option()

Make the client tell the server that the client accepts extension negotiation, that is, include ext-info-c in the kexinit message sent. See RFC 8308 for details and ssh for a list of currently implemented extensions.

Types: Common Options

alg_entry()

algs_list()

alive_common_option()

This option is used to configure the alive messages. Alive messages are sent through the encrypted channel and are typically used to detect that a connection became unresponsive.

auth_methods_common_option()

Comma-separated string that determines which authentication methods that the client shall support and in which order they are tried. Defaults to "publickey,keyboard-interactive,password"

cipher_alg()

common_option()

The options above can be used both in clients and in daemons (servers). They are further explained below.

common_options()

compression_alg()

disabled_cipher_alg()

disabled_mac_alg()

disconnectfun_common_option()

Provides a fun to implement your own logging or other handling at disconnects.

double_algs(AlgType)

List of algorithms to use in the algorithm negotiation. The default algs_list/0 can be obtained from default_algorithms/0.

fd_common_option()

Allows an existing file-descriptor to be used (passed on to the transport protocol).

id_string_common_option()

The string the daemon will present to a connecting peer initially. The default value is "Erlang/VSN" where VSN is the ssh application version number.

inet_common_option()

IP version to use when the host address is specified as any.

kex_alg()

key_cb_common_option()

Module implementing the behaviour ssh_client_key_api and/or ssh_server_key_api. Can be used to customize the handling of public keys. If callback options are provided along with the module name, they are made available to the callback module via the options passed to it under the key 'key_cb_private'.

limit_bytes()

limit_time()

Sets the limit when rekeying is to be initiated. Both the max time and max amount of data could be configured

mac_alg()

max_idle_time_common_option()

Sets a time-out on a connection when no channels are open. Defaults to infinity. The unit is milliseconds.

max_log_item_len_common_option()

Sets a limit for the size of a logged item excluding a header. The unit is bytes and the value defaults to 500.

modify_algorithms_common_option()

modify_algs_list()

Modifies the list of algorithms to use in the algorithm negotiation. The modifications are applied after the option preferred_algorithms (if existing) is applied.

pref_public_key_algs_common_option()

List of user (client) public key algorithms to try to use.

preferred_algorithms_common_option()

profile_common_option()

Used together with ip-address and port to uniquely identify a ssh daemon. This can be useful in a virtualized environment, where there can be more that one server that has the same ip-address and port. If this property is not explicitly set, it is assumed that the the ip-address and port uniquely identifies the SSH daemon.

pubkey_alg()

rekey_limit_common_option()

ssh_msg_debug_fun_common_option()

Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG. The last three parameters are from the message, see RFC 4253, section 11.3. The connection_ref/0 is the reference to the connection on which the message arrived. The return value from the fun is not checked.

unexpectedfun_common_option()

Provides a fun to implement your own logging or other action when an unexpected message arrives. If the fun returns report the usual info report is issued but if skip is returned no report is generated.

Types: Daemon Options

authentication_daemon_options()

callbacks_daemon_options()

daemon_option()

Options for daemons. The individual options are further explained below or by following the hyperlinks.

daemon_options()

deprecated_exec_opt()

Old-style exec specification that are kept for compatibility, but should not be used in new programs

diffie_hellman_group_exchange_daemon_option()

exec_daemon_option()

exec_fun()

The default is disabled.

'exec_fun/1'()

'exec_fun/2'()

'exec_fun/3'()

exec_result()

This option changes how the daemon executes exec-requests from clients. The term in the return value is formatted to a string if it is a non-string type. No trailing newline is added in the ok-case.

exec_spec()

explicit_group()

explicit_group_file()

hardening_daemon_options()

For more information about hardening, see the Hardening section in the User's Guide chapter.

hello_timeout_daemon_option()

Maximum time in milliseconds for the first part of the ssh session setup, the hello message exchange. Defaults to 30000 ms (30 seconds). If the client fails to send the first message within this time, the connection is closed.

kb_int_fun_3()

kb_int_fun_4()

kb_int_tuple()

max_initial_idle_time_daemon_option()

Maximum time in milliseconds for the first channel start after completion of the authentication negotiation. Defaults to infinity.

negotiation_timeout_daemon_option()

Maximum time in milliseconds for the authentication negotiation. Defaults to 120000 ms (2 minutes). If the client fails to log in within this time, the connection is closed.

prompt_texts()

pwdfun_2()

Equivalent to pwdfun_4/0.

pwdfun_4()

send_ext_info_daemon_option()

Make the server (daemon) tell the client that the server accepts extension negotiation, that is, include ext-info-s in the kexinit message sent. See RFC 8308 for details and ssh for a list of currently implemented extensions.

shell_daemon_option()

Equivalent to 'shell_fun/2'/0.

shell_fun()

The default is disabled.

'shell_fun/1'()

Equivalent to 'shell_fun/2'/0.

'shell_fun/2'()

Defines the read-eval-print loop used in a daemon when a shell is requested by the client.

shell_spec()

ssh_cli_daemon_option()

Provides your own CLI implementation in a daemon.

ssh_moduli_file()

subsystem_daemon_option()

subsystem_spec()

Defines a subsystem in the daemon.

subsystem_specs()

tcpip_tunnel_in_daemon_option()

Enables (true) or disables (false) the possibility to tunnel a TCP/IP connection in to a server. Disabled per default.

tcpip_tunnel_out_daemon_option()

Enables (true) or disables (false) the possibility to tunnel a TCP/IP connection out of a server. Disabled per default.

Types: Deprecated

ssh_channel_id()

ssh_connection_ref()

ssh_daemon_ref()

Types: Legacy Algorithms

legacy_cipher_alg()

legacy_compression_alg() deprecated

Deprecated: the use of zlib compression in SSH will be removed in OTP 30.0. Use none or zlib@openssh.com instead.

legacy_kex_alg()

legacy_mac_alg()

legacy_pubkey_alg()

Types

channel_id()

Opaque data type representing a channel inside a connection.

conn_info_algs()

conn_info_channels()

connection_info_tuple()

Return values from the connection_info/1 and connection_info/2 functions.

connection_ref()

Opaque data type representing a connection between a client and a server (daemon).

daemon_info_tuple()

Return values from the daemon_info/1 and daemon_info/2 functions.

daemon_ref()

Opaque data type representing a daemon.

experimental_client_options()

Experimental options that should not to be used in products.

experimental_common_options()

Experimental options that should not to be used in products.

experimental_daemon_options()

Experimental options that should not to be used in products.

host()

ip_port()

mod_args()

mod_fun_args()

open_socket()

The socket is supposed to be result of a gen_tcp:connect or a gen_tcp:accept. The socket must be in passive mode (that is, opened with the option {active,false}).

protocol_version()

role()

software_version()

version()

Functions

close(ConnectionRef)

Closes an SSH connection.

connect(OpenTcpSocket, Options)

Equivalent to connect/4.

connect/3

Equivalent to connect/4.

connect(Host, Port, Options, NegotiationTimeout)

Connects to an SSH server at the Host on Port.

connection_info(ConnectionRef)

Equivalent to connection_info/2.

connection_info(ConnectionRef, Key)

Returns information about a connection intended for e.g debugging or logging.

daemon(Port)

Equivalent to daemon/3.

daemon/2

Equivalent to daemon/3.

daemon(HostAddress, Port, Options)

Starts a server listening for SSH connections on the given port. If the Port is 0, a random free port is selected. See daemon_info/1 about how to find the selected port number.

daemon_info(DaemonRef)

Equivalent to daemon_info/2.

daemon_info/2

Returns information about a daemon intended for e.g debugging or logging.

daemon_replace_options(DaemonRef, NewUserOptions)

Replaces the options in a running daemon with the options in NewUserOptions. Only connections established after this call are affected, already established connections are not.

default_algorithms()

Returns a key-value list, where the keys are the different types of algorithms and the values are the algorithms themselves.

get_sock_opts(ConnectionRef, SocketGetOptions)

Get tcp socket option values of the tcp-socket below an ssh connection.

hostkey_fingerprint(Key)

Equivalent to hostkey_fingerprint/2.

hostkey_fingerprint(TypeOrTypes, Key)

hostkey_fingerprint([DigestType], HostKey) -> [string()]hostkey_fingerprint(DigestType, HostKey) -> string()

set_sock_opts(ConnectionRef, SocketOptions)

Sets tcp socket options on the tcp-socket below an ssh connection.

shell/1

Equivalent to shell/3.

shell(Dest, Options)

Equivalent to shell/3.

shell(Host, Port, Options)

Connects to an SSH server at Host and Port (defaults to 22) and starts an interactive shell on that remote host.

start()

Equivalent to start/1.

start(Type)

Utility function that starts the applications crypto, public_key, and ssh. Default type is temporary. For more information, see the application manual page in Kernel.

stop()

Stops the ssh application. For more information, see the application manual page in Kernel.

stop_daemon(DaemonRef)

Equivalent to stop_daemon/3.

stop_daemon(Address, Port)

Equivalent to stop_daemon/3.

stop_daemon(Address, Port, Profile)

Stops the listener and all connections started by the listener.

stop_listener(SysSup)

Equivalent to stop_listener/3.

stop_listener(Address, Port)

Equivalent to stop_listener/3.

stop_listener(Address, Port, Profile)

Stops the listener, but leaves existing connections started by the listener operational.

tcpip_tunnel_from_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort)

Equivalent to tcpip_tunnel_from_server/6.

tcpip_tunnel_from_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort, Timeout)

Asks the remote server of ConnectionRef to listen to ListenHost:ListenPort. When someone connects that address, the connection is forwarded in an encrypted channel from the server to the client. The client (that is, at the node that calls this function) then connects to ConnectToHost:ConnectToPort.

tcpip_tunnel_to_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort)

Equivalent to tcpip_tunnel_to_server/6.

tcpip_tunnel_to_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort, Timeout)

Tells the local client to listen to ListenHost:ListenPort. When someone connects to that address, the connection is forwarded in an encrypted channel to the peer server of ConnectionRef. That server then connects to ConnectToHost:ConnectToPort.

Types: Client Options

accept_callback()

-type accept_callback() ::
          fun((PeerName :: string(), fingerprint()) -> boolean()) |
          fun((PeerName :: string(), Port :: inet:port_number(), fingerprint()) -> boolean()).

accept_hosts()

-type accept_hosts() ::
          boolean() | accept_callback() | {HashAlgoSpec :: fp_digest_alg(), accept_callback()}.

authentication_client_options()

-type authentication_client_options() :: {user, string()} | {password, string()}.

user - Provides the username. If this option is not given, ssh reads from the environment (LOGNAME or USER on UNIX, USERNAME on Windows).

password - Provides a password for password authentication. If this option is not given, the user is asked for a password, if the password authentication method is attempted.

client_option()

-type client_option() ::
          ssh_file:pubkey_passphrase_client_options() |
          host_accepting_client_options() |
          authentication_client_options() |
          diffie_hellman_group_exchange_client_option() |
          connect_timeout_client_option() |
          recv_ext_info_client_option() |
          gen_tcp:connect_option() |
          common_option() |
          experimental_client_options().

Options for clients. The individual options are further explained below or by following the hyperlinks.

Note that not every gen_tcp:connect_option/0 is accepted. See set_sock_opts/2 for a list of prohibited options.

Also note that setting a gen_tcp:connect_option/0 could change the socket in a way that impacts the ssh client's behaviour negatively. You use it on your own risk.

client_options()

-type client_options() :: [client_option()].

connect_timeout_client_option()

-type connect_timeout_client_option() :: {connect_timeout, timeout()}.

Sets a timeout on the transport layer connect time. For gen_tcp the time is in milli-seconds and the default value is infinity.

See the parameter Timeout in connect/4 for a timeout of the negotiation phase.

diffie_hellman_group_exchange_client_option()

-type diffie_hellman_group_exchange_client_option() ::
          {dh_gex_limits, {Min :: pos_integer(), I :: pos_integer(), Max :: pos_integer()}}.

Sets the three diffie-hellman-group-exchange parameters that guides the connected server in choosing a group. See RFC 4419 for the details. The default value is {1024, 6144, 8192}.

fingerprint()

-type fingerprint() :: string() | [string()].

fp_digest_alg()

-type fp_digest_alg() :: md5 | crypto:sha1() | crypto:sha2().

host_accepting_client_options()

-type host_accepting_client_options() ::
          {silently_accept_hosts, accept_hosts()} |
          {user_interaction, boolean()} |
          {save_accepted_host, boolean()} |
          {quiet_mode, boolean()}.

silently_accept_hosts - This option guides the connect function on how to act when the connected server presents a Host Key that the client has not seen before. The default is to ask the user with a question on stdio of whether to accept or reject the new Host Key. See the option user_dir for specifying the path to the file known_hosts where previously accepted Host Keys are recorded. See also the option key_cb for the general way to handle keys.

The option can be given in three different forms as seen above:

The value is a boolean/0. The value true will make the client accept any unknown Host Key without any user interaction. The value false preserves the default behaviour of asking the user on stdio.

An accept_callback/0 will be called and the boolean return value true will make the client accept the Host Key. A return value of false will make the client to reject the Host Key and as a result the connection will be closed. The arguments to the fun are:

PeerName - a string with the name or address of the remote host.

FingerPrint - the fingerprint of the Host Key as hostkey_fingerprint/1 calculates it.

A tuple {HashAlgoSpec, accept_callback}. The HashAlgoSpec specifies which hash algorithm shall be used to calculate the fingerprint used in the call of the accept_callback/0. The HashALgoSpec is either an atom or a list of atoms as the first argument in hostkey_fingerprint/2. If it is a list of hash algorithm names, the FingerPrint argument in the accept_callback/0 will be a list of fingerprints in the same order as the corresponding name in the HashAlgoSpec list.

user_interaction - If false, disables the client to connect to the server if any user interaction is needed, such as accepting the server to be added to the known_hosts file, or supplying a password.

Even if user interaction is allowed it can be suppressed by other options, such as silently_accept_hosts and password. However, those options are not always desirable to use from a security point of view.

Defaults to true.

save_accepted_host - If true, the client saves an accepted host key to avoid the accept question the next time the same host is connected. If the option key_cb is not present, the key is saved in the file "known_hosts". See option user_dir for the location of that file.

If false, the key is not saved and the key will still be unknown at the next access of the same host.

Defaults to true

quiet_mode - If true, the client does not print anything on authorization.

Defaults to false

recv_ext_info_client_option()

-type recv_ext_info_client_option() :: {recv_ext_info, boolean()}.

Make the client tell the server that the client accepts extension negotiation, that is, include ext-info-c in the kexinit message sent. See RFC 8308 for details and ssh for a list of currently implemented extensions.

Default value is true which is compatible with other implementations not supporting ext-info.

Types: Common Options

alg_entry()

-type alg_entry() ::
          {kex, [kex_alg()]} |
          {public_key, [pubkey_alg()]} |
          {cipher, double_algs(cipher_alg())} |
          {mac, double_algs(mac_alg())} |
          {compression, double_algs(compression_alg())}.

algs_list()

-type algs_list() :: [alg_entry()].

alive_common_option()

-type alive_common_option() ::
          {alive, #{count_max := CountMax :: pos_integer(), interval := Interval :: timeout()}}.

This option is used to configure the alive messages. Alive messages are sent through the encrypted channel and are typically used to detect that a connection became unresponsive.

count_max sets the maximum number of alive messages which may be sent without receiving any messages back from the peer. If this threshold is reached the connection will be terminated. interval sets a timeout interval, in milliseconds, after which, if no data has been received from the peer, a message to request a response from the peer is sent.

The default is #{count_max => 3, interval => infinity}, which means that alive messages will not be sent to the peer, since the interval is set to infinity.

No alive messages are sent during renegotiation, however, a timeout derived from the alive parameters is set to ensure that unresponsive connections are terminated.

auth_methods_common_option()

-type auth_methods_common_option() :: {auth_methods, string()}.

Comma-separated string that determines which authentication methods that the client shall support and in which order they are tried. Defaults to "publickey,keyboard-interactive,password"

Note that the client is free to use any order and to exclude methods.

cipher_alg()

-type cipher_alg() ::
          'aes128-ctr' | 'aes128-gcm@openssh.com' | 'aes192-ctr' | 'aes256-ctr' |
          'aes256-gcm@openssh.com' | 'chacha20-poly1305@openssh.com' |
          disabled_cipher_alg() |
          legacy_cipher_alg().

common_option()

-type common_option() ::
          ssh_file:user_dir_common_option() |
          profile_common_option() |
          max_idle_time_common_option() |
          max_log_item_len_common_option() |
          key_cb_common_option() |
          disconnectfun_common_option() |
          unexpectedfun_common_option() |
          ssh_msg_debug_fun_common_option() |
          rekey_limit_common_option() |
          id_string_common_option() |
          pref_public_key_algs_common_option() |
          preferred_algorithms_common_option() |
          modify_algorithms_common_option() |
          auth_methods_common_option() |
          inet_common_option() |
          fd_common_option() |
          alive_common_option().

The options above can be used both in clients and in daemons (servers). They are further explained below.

common_options()

-type common_options() :: [common_option()].

compression_alg()

-type compression_alg() :: none | 'zlib@openssh.com' | legacy_compression_alg().

disabled_cipher_alg()

-type disabled_cipher_alg() :: 'AEAD_AES_128_GCM' | 'AEAD_AES_256_GCM'.

disabled_mac_alg()

-type disabled_mac_alg() :: 'AEAD_AES_128_GCM' | 'AEAD_AES_256_GCM'.

disconnectfun_common_option()

-type disconnectfun_common_option() :: {disconnectfun, fun((Reason :: term()) -> void | any())}.

Provides a fun to implement your own logging or other handling at disconnects.

double_algs(AlgType)

-type double_algs(AlgType) :: [{client2server, [AlgType]} | {server2client, [AlgType]}] | [AlgType].

List of algorithms to use in the algorithm negotiation. The default algs_list/0 can be obtained from default_algorithms/0.

If an alg_entry() is missing in the algs_list(), the default value is used for that entry.

Here is an example of this option:

	  {preferred_algorithms,
	  [{public_key,['ssh-rsa','ssh-dss']},
	  {cipher,[{client2server,['aes128-ctr']},
          {server2client,['aes128-cbc','3des-cbc']}]},
	  {mac,['hmac-sha2-256','hmac-sha1']},
	  {compression,[none,zlib]}
	  ]
	  }

The example specifies different algorithms in the two directions (client2server and server2client), for cipher but specifies the same algorithms for mac and compression in both directions. The kex (key exchange) is implicit but public_key is set explicitly.

For background and more examples see the User's Guide.

If an algorithm name occurs more than once in a list, the behaviour is undefined. The tags in the property lists are also assumed to occur at most one time.

Warning

Changing the values can make a connection less secure. Do not change unless you know exactly what you are doing. If you do not understand the values then you are not supposed to change them.

fd_common_option()

-type fd_common_option() :: {fd, gen_tcp:socket()}.

Allows an existing file-descriptor to be used (passed on to the transport protocol).

id_string_common_option()

-type id_string_common_option() ::
          {id_string, string() | random | {random, Nmin :: pos_integer(), Nmax :: pos_integer()}}.

The string the daemon will present to a connecting peer initially. The default value is "Erlang/VSN" where VSN is the ssh application version number.

The value random will cause a random string to be created at each connection attempt. This is to make it a bit more difficult for a malicious peer to find the ssh software brand and version.

The value {random, Nmin, Nmax} will make a random string with at least Nmin characters and at most Nmax characters.

inet_common_option()

-type inet_common_option() :: {inet, inet | inet6}.

IP version to use when the host address is specified as any.

kex_alg()

-type kex_alg() ::
          'diffie-hellman-group-exchange-sha256' | 'diffie-hellman-group14-sha256' |
          'diffie-hellman-group16-sha512' | 'diffie-hellman-group18-sha512' | 'curve25519-sha256' |
          'curve25519-sha256@libssh.org' | 'curve448-sha512' | 'ecdh-sha2-nistp256' |
          'ecdh-sha2-nistp384' | 'ecdh-sha2-nistp521' | 'mlkem768x25519-sha256' |
          legacy_kex_alg().

key_cb_common_option()

-type key_cb_common_option() :: {key_cb, Module :: atom() | {Module :: atom(), Opts :: [term()]}}.

Module implementing the behaviour ssh_client_key_api and/or ssh_server_key_api. Can be used to customize the handling of public keys. If callback options are provided along with the module name, they are made available to the callback module via the options passed to it under the key 'key_cb_private'.

The Opts defaults to [] when only the Module is specified.

The default value of this option is {ssh_file, []}. See also the manpage of ssh_file.

A call to the call-back function F will be

	  Module:F(..., [{key_cb_private,Opts}|UserOptions])

where ... are arguments to F as in ssh_client_key_api and/or ssh_server_key_api. The UserOptions are the options given to ssh:connect, ssh:shell or ssh:daemon.

limit_bytes()

-type limit_bytes() :: non_neg_integer() | infinity.

limit_time()

-type limit_time() :: pos_integer() | infinity.

Sets the limit when rekeying is to be initiated. Both the max time and max amount of data could be configured:

{Minutes, Bytes} initiate rekeying when any of the limits are reached.

Bytes initiate rekeying when Bytes number of bytes are transferred, or at latest after one hour.

When a rekeying is done, both the timer and the byte counter are restarted. Defaults to one hour and one GByte.

If Minutes is set to infinity, no rekeying will ever occur due to that max time has passed. Setting Bytes to infinity will inhibit rekeying after a certain amount of data has been transferred. If the option value is set to {infinity, infinity}, no rekeying will be initiated. Note that rekeying initiated by the peer will still be performed.

mac_alg()

-type mac_alg() ::
          'hmac-sha1' | 'hmac-sha1-etm@openssh.com' | 'hmac-sha2-256' | 'hmac-sha2-512' |
          'hmac-sha2-256-etm@openssh.com' | 'hmac-sha2-512-etm@openssh.com' |
          disabled_mac_alg() |
          legacy_mac_alg().

max_idle_time_common_option()

-type max_idle_time_common_option() :: {idle_time, timeout()}.

Sets a time-out on a connection when no channels are open. Defaults to infinity. The unit is milliseconds.

The timeout is not active until channels are started, so it does not limit the time from the connection creation to the first channel opening.

For more information about timeouts, see the Timeouts section in the User's Guide Hardening chapter.

max_log_item_len_common_option()

-type max_log_item_len_common_option() :: {max_log_item_len, limit_bytes()}.

Sets a limit for the size of a logged item excluding a header. The unit is bytes and the value defaults to 500.

modify_algorithms_common_option()

-type modify_algorithms_common_option() :: {modify_algorithms, modify_algs_list()}.

modify_algs_list()

-type modify_algs_list() :: [{append, algs_list()} | {prepend, algs_list()} | {rm, algs_list()}].

Modifies the list of algorithms to use in the algorithm negotiation. The modifications are applied after the option preferred_algorithms (if existing) is applied.

The algorithm for modifications works like this:

Input is the modify_algs_list/0 and a set of algorithms A obtained from the preferred_algorithms option if existing, or else from the ssh:default_algorithms/0.

The head of the modify_algs_list/0 modifies A giving the result A'.

The possible modifications are:

Append or prepend supported but not enabled algorithm(s) to the list of algorithms. If the wanted algorithms already are in A they will first be removed and then appended or prepended,

Remove (rm) one or more algorithms from A.

Repeat the modification step with the tail of modify_algs_list/0 and the resulting A'.

If an unsupported algorithm is in the modify_algs_list/0, it will be silently ignored

If there are more than one modify_algorithms options, the result is undefined.

Here is an example of this option:

	  {modify_algorithms,
	  [{prepend, [{kex, ['diffie-hellman-group1-sha1']}],
	  {rm,      [{compression, [none]}]}
	  ]
	  }

The example specifies that:

the old key exchange algorithm 'diffie-hellman-group1-sha1' should be the main alternative. It will be the main alternative since it is prepened to the list

The compression algorithm none (= no compression) is removed so compression is enforced

For background and more examples see the User's Guide.

pref_public_key_algs_common_option()

-type pref_public_key_algs_common_option() :: {pref_public_key_algs, [pubkey_alg()]}.

List of user (client) public key algorithms to try to use.

The default value is the public_key entry in the list returned by ssh:default_algorithms/0.

If there is no public key of a specified type available, the corresponding entry is ignored. Note that the available set is dependent on the underlying cryptolib and current user's public keys.

See also the option user_dir for specifying the path to the user's keys.

preferred_algorithms_common_option()

-type preferred_algorithms_common_option() :: {preferred_algorithms, algs_list()}.

profile_common_option()

-type profile_common_option() :: {profile, atom()}.

Used together with ip-address and port to uniquely identify a ssh daemon. This can be useful in a virtualized environment, where there can be more that one server that has the same ip-address and port. If this property is not explicitly set, it is assumed that the the ip-address and port uniquely identifies the SSH daemon.

pubkey_alg()

-type pubkey_alg() ::
          'ecdsa-sha2-nistp256' | 'ecdsa-sha2-nistp384' | 'ecdsa-sha2-nistp521' | 'ssh-ed25519' |
          'ssh-ed448' | 'rsa-sha2-256' | 'rsa-sha2-512' |
          legacy_pubkey_alg().

rekey_limit_common_option()

-type rekey_limit_common_option() ::
          {rekey_limit, Bytes :: limit_bytes() | {Minutes :: limit_time(), Bytes :: limit_bytes()}}.

ssh_msg_debug_fun_common_option()

-type ssh_msg_debug_fun_common_option() ::
          {ssh_msg_debug_fun,
           fun((ssh:connection_ref(),
                AlwaysDisplay :: boolean(),
                Msg :: binary(),
                LanguageTag :: binary()) ->
                   any())}.

Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG. The last three parameters are from the message, see RFC 4253, section 11.3. The connection_ref/0 is the reference to the connection on which the message arrived. The return value from the fun is not checked.

The default behaviour is ignore the message. To get a printout for each message with AlwaysDisplay = true, use for example {ssh_msg_debug_fun, fun(_,true,M,_)-> io:format("DEBUG: ~p~n", [M]) end}

unexpectedfun_common_option()

-type unexpectedfun_common_option() ::
          {unexpectedfun, fun((Message :: term(), {Host :: term(), Port :: term()}) -> report | skip)}.

Provides a fun to implement your own logging or other action when an unexpected message arrives. If the fun returns report the usual info report is issued but if skip is returned no report is generated.

Types: Daemon Options

authentication_daemon_options()

-type authentication_daemon_options() ::
          ssh_file:system_dir_daemon_option() |
          {auth_method_kb_interactive_data, prompt_texts()} |
          {user_passwords, [{UserName :: string(), Pwd :: string()}]} |
          {pk_check_user, boolean()} |
          {password, string()} |
          {pwdfun, pwdfun_2() | pwdfun_4()} |
          {no_auth_needed, boolean()}.

callbacks_daemon_options()

-type callbacks_daemon_options() ::
          {failfun,
           fun((User :: string(), Peer :: {inet:ip_address(), inet:port_number()}, Reason :: term()) ->
                   _)} |
          {connectfun,
           fun((User :: string(), Peer :: {inet:ip_address(), inet:port_number()}, Method :: string()) ->
                   _)} |
          {bannerfun, fun((User :: string()) -> binary())}.

connectfun - Provides a fun to implement your own logging when a user authenticates to the server.

failfun - Provides a fun to implement your own logging when a user fails to authenticate.

bannerfun - Provides a fun to implement the construction of a banner text that is sent at the beginning of the user authentication. The banner will not be sent if the function does not return a binary.

daemon_option()

-type daemon_option() ::
          subsystem_daemon_option() |
          shell_daemon_option() |
          exec_daemon_option() |
          ssh_cli_daemon_option() |
          tcpip_tunnel_out_daemon_option() |
          tcpip_tunnel_in_daemon_option() |
          authentication_daemon_options() |
          diffie_hellman_group_exchange_daemon_option() |
          max_initial_idle_time_daemon_option() |
          negotiation_timeout_daemon_option() |
          hello_timeout_daemon_option() |
          hardening_daemon_options() |
          callbacks_daemon_options() |
          send_ext_info_daemon_option() |
          gen_tcp:listen_option() |
          common_option() |
          experimental_daemon_options().

Options for daemons. The individual options are further explained below or by following the hyperlinks.

Note that not every gen_tcp:listen_option/0 is accepted. See set_sock_opts/2 for a list of prohibited options.

Also note that setting a gen_tcp:listen_option/0 could change the socket in a way that impacts the ssh deamon's behaviour negatively. You use it on your own risk.

daemon_options()

-type daemon_options() :: [daemon_option()].

deprecated_exec_opt()

-type deprecated_exec_opt() :: fun() | mod_fun_args().

Old-style exec specification that are kept for compatibility, but should not be used in new programs

diffie_hellman_group_exchange_daemon_option()

-type diffie_hellman_group_exchange_daemon_option() ::
          {dh_gex_groups, [explicit_group()] | explicit_group_file() | ssh_moduli_file()} |
          {dh_gex_limits, {Min :: pos_integer(), Max :: pos_integer()}}.

exec_daemon_option()

-type exec_daemon_option() :: {exec, exec_spec()}.

exec_fun()

-type exec_fun() :: 'exec_fun/1'() | 'exec_fun/2'() | 'exec_fun/3'().

The default is disabled.

Value erlang_eval enables evaluation of Erlang terms via exec requests. This works when the shell option is either disabled (no shell) or {shell, start, []} (Erlang shell). It does not work with custom shells.

To restore the behavior from OTP versions prior to OTP @OTP-19969@, configure:

ssh:daemon(Port, [{shell, {shell, start, []}},
                  {exec, erlang_eval}
                  | Options])

For new code, consider using {direct, Fun} for more controlled exec handling.

'exec_fun/1'()

-type 'exec_fun/1'() :: fun((Cmd :: string()) -> exec_result()).

'exec_fun/2'()

-type 'exec_fun/2'() :: fun((Cmd :: string(), User :: string()) -> exec_result()).

'exec_fun/3'()

-type 'exec_fun/3'() ::
          fun((Cmd :: string(), User :: string(), ClientAddr :: ip_port()) -> exec_result()).

exec_result()

-type exec_result() :: {ok, Result :: term()} | {error, Reason :: term()}.

This option changes how the daemon executes exec-requests from clients. The term in the return value is formatted to a string if it is a non-string type. No trailing newline is added in the ok-case.

See the User's Guide section on One-Time Execution for examples.

Error texts are returned on channel-type 1 which usually is piped to stderr on e.g Linux systems. Texts from a successful execution are returned on channel-type 0 and will in similar manner be piped to stdout. The exit-status code is set to 0 for success and 255 for errors. The exact results presented on the client side depends on the client and the client's operating system.

In case of the {direct, exec_fun()} variant or erlang_eval, all reads from standard_input will be from the received data-events of type 0. Those are sent by the client. Similarly all writes to standard_output will be sent as data-events to the client. An OS shell client like the command 'ssh' will usually use stdin and stdout for the user interface.

The option cooperates with the daemon-option shell in the following way:

1. If neither the exec-option nor the shell-option is present: - Both default to disabled. No exec-requests or shell-requests are executed. This is the default behavior since @OTP-19969@. To restore the previous behavior, set {shell, {shell, start, []}} and {exec, erlang_eval}.

2. If the exec_spec's value is disabled (the shell-option may or may not be present): - No exec-requests are executed but shell-requests are not affected, they follow the shell_spec's value.

3. If the exec-option is present and the exec_spec value =/= disabled (the shell-option may or may not be present): - The exec_spec fun() is called with the same number of parameters as the arity of the fun, and the result is returned to the client. Shell-requests are not affected, they follow the shell_spec's value.

4. If the exec_spec's value is erlang_eval, and the shell-option is disabled or set to the default Erlang shell {shell, start, []}: - The default Erlang evaluator is used for exec requests. The result is returned to the client. Shell-requests follow the shell_spec's value.

5. If the exec_spec's value is erlang_eval, and the shell-option is present with a value that is neither the default Erlang shell nor disabled: - The exec-request is not evaluated and an error message is returned to the client. Shell-requests are executed according to the value of the shell_spec.

6. If the exec-option is absent (defaults to disabled), and the shell_spec's value is disabled: - Neither exec-requests nor shell-requests are executed.

If a custom CLI is installed (see the option ssh_cli) the rules above are replaced by thoose implied by the custom CLI.

Note

The exec-option has existed for a long time but has not previously been documented. The old definition and behaviour are retained but obey the rules 1-6 above if conflicting. The old and undocumented style should not be used in new programs.

exec_spec()

-type exec_spec() :: {direct, exec_fun()} | disabled | deprecated_exec_opt() | erlang_eval.

explicit_group()

-type explicit_group() :: {Size :: pos_integer(), G :: pos_integer(), P :: pos_integer()}.

explicit_group_file()

-type explicit_group_file() :: {file, string()}.

hardening_daemon_options()

-type hardening_daemon_options() ::
          {max_sessions, pos_integer()} |
          {max_channels, pos_integer()} |
          {parallel_login, boolean()} |
          {minimal_remote_max_packet_size, pos_integer()}.

For more information about hardening, see the Hardening section in the User's Guide chapter.

max_sessions - The maximum number of simultaneous sessions that are accepted at any time for this daemon. This includes sessions that are being authorized. Thus, if set to N, and N clients have connected but not started the login process, connection attempt N+1 is aborted. If N connections are authenticated and still logged in, no more logins are accepted until one of the existing ones log out.

The counter is per listening port. Thus, if two daemons are started, one with {max_sessions,N} and the other with {max_sessions,M}, in total N+M connections are accepted for the whole ssh application.

Notice that if parallel_login is false, only one client at a time can be in the authentication phase.

By default, this option is not set. This means that the number is not limited.

max_channels - The maximum number of channels with active remote subsystem that are accepted for each connection to this daemon

By default, this option is not set. This means that the number is not limited.

parallel_login - If set to false (the default value), only one login is handled at a time. If set to true, an unlimited number of login attempts are allowed simultaneously.

If the max_sessions option is set to N and parallel_login is set to true, the maximum number of simultaneous login attempts at any time is limited to N-K, where K is the number of authenticated connections present at this daemon.

Warning

Do not enable parallel_logins without protecting the server by other means, for example, by the max_sessions option or a firewall configuration. If set to true, there is no protection against DOS attacks.

minimal_remote_max_packet_size - The least maximum packet size that the daemon will accept in channel open requests from the client. The default value is 0.

hello_timeout_daemon_option()

-type hello_timeout_daemon_option() :: {hello_timeout, timeout()}.

Maximum time in milliseconds for the first part of the ssh session setup, the hello message exchange. Defaults to 30000 ms (30 seconds). If the client fails to send the first message within this time, the connection is closed.

For more information about timeouts, see the Timeouts section in the User's Guide Hardening chapter.

kb_int_fun_3()

-type kb_int_fun_3() ::
          fun((Peer :: ip_port(), User :: string(), Service :: string()) -> kb_int_tuple()).

kb_int_fun_4()

-type kb_int_fun_4() ::
          fun((Peer :: ip_port(), User :: string(), Service :: string(), State :: any()) ->
                  kb_int_tuple()).

kb_int_tuple()

-type kb_int_tuple() ::
          {Name :: string(), Instruction :: string(), Prompt :: string(), Echo :: boolean()}.

max_initial_idle_time_daemon_option()

-type max_initial_idle_time_daemon_option() :: {max_initial_idle_time, timeout()}.

Maximum time in milliseconds for the first channel start after completion of the authentication negotiation. Defaults to infinity.

For more information about timeouts, see the Timeouts section in the User's Guide Hardening chapter.

negotiation_timeout_daemon_option()

-type negotiation_timeout_daemon_option() :: {negotiation_timeout, timeout()}.

Maximum time in milliseconds for the authentication negotiation. Defaults to 120000 ms (2 minutes). If the client fails to log in within this time, the connection is closed.

For more information about timeouts, see the Timeouts section in the User's Guide Hardening chapter.

prompt_texts()

-type prompt_texts() :: kb_int_tuple() | kb_int_fun_3() | kb_int_fun_4().

pwdfun_2()

-type pwdfun_2() :: fun((User :: string(), Password :: string() | pubkey) -> boolean()).

Equivalent to pwdfun_4/0.

pwdfun_4()

-type pwdfun_4() ::
          fun((User :: string(),
               Password :: string() | pubkey,
               PeerAddress :: ip_port(),
               State :: any()) ->
                  boolean() | disconnect | {boolean(), NewState :: any()}).

auth_method_kb_interactive_data - Sets the text strings that the daemon sends to the client for presentation to the user when using keyboard-interactive authentication.

If the fun/3 or fun/4 is used, it is called when the actual authentication occurs and may therefore return dynamic data like time, remote ip etc.

The parameter Echo guides the client about need to hide the password.

The default value is: {auth_method_kb_interactive_data, {"SSH server", "Enter password for \""++User++"\"", "password: ", false}>

user_passwords - Provides passwords for password authentication. The passwords are used when someone tries to connect to the server and public key user-authentication fails. The option provides a list of valid usernames and the corresponding passwords.

Warning

Note that this is very insecure due to the plain-text passwords; it is intended for test purposes. Use the pwdfun option to handle the password checking instead.

pk_check_user - Enables checking of the client's user name in the server when doing public key authentication. It is disabled by default.

The term "user" is used differently in OpenSSH and SSH in Erlang/OTP: see more in the User's Guide.

If the option is enabled, and no pwdfun is present, the user name must present in the user_passwords for the check to succeed but the value of the password is not checked.

In case of a pwdfun checking the user, the atom pubkey is put in the password argument.

password - Provides a global password that authenticates any user.

Warning

Intended to facilitate testing.

From a security perspective this option makes the server very vulnerable.

pwdfun with pwdfun_4/0 - Provides a function for password validation. This could used for calling an external system or handling passwords stored as hash values.

This fun can also be used to make delays in authentication tries for example by calling timer:sleep/1.

To facilitate for instance counting of failed tries, the State variable could be used. This state is per connection only. The first time the pwdfun is called for a connection, the State variable has the value undefined.

The fun should return:

true if the user and password is valid

false if the user or password is invalid

disconnect if a SSH_MSG_DISCONNECT message should be sent immediately. It will be followed by a close of the underlying tcp connection.

{true, NewState:any()} if the user and password is valid

{false, NewState:any()} if the user or password is invalid

A third usage is to block login attempts from a missbehaving peer. The State described above can be used for this. The return value disconnect is useful for this.

In case of the pk_check_user is set, the atom pubkey is put in the password argument when validating a public key login. The pwdfun is then responsible to check that the user name is valid.

pwdfun with pwdfun_2/0 - Provides a function for password validation. This function is called with user and password as strings, and returns:

true if the user and password is valid

false if the user or password is invalid

In case of the pk_check_user is set, the atom pubkey is put in the password argument when validating a public key login. The pwdfun is then responsible to check that the user name is valid.

This variant is kept for compatibility.

no_auth_needed - If true, a client is authenticated without any need of providing any password or key.

This option is only intended for very special applications due to the high risk of accepting any connecting client.

The default value is false.

send_ext_info_daemon_option()

-type send_ext_info_daemon_option() :: {send_ext_info, boolean()}.

Make the server (daemon) tell the client that the server accepts extension negotiation, that is, include ext-info-s in the kexinit message sent. See RFC 8308 for details and ssh for a list of currently implemented extensions.

Default value is true which is compatible with other implementations not supporting ext-info.

shell_daemon_option()

-type shell_daemon_option() :: {shell, shell_spec()}.

Equivalent to 'shell_fun/2'/0.

shell_fun()

-type shell_fun() :: 'shell_fun/1'() | 'shell_fun/2'().

The default is disabled.

To enable the Erlang shell:

ssh:daemon(Port, [{shell, {shell, start, []}} | Options])

'shell_fun/1'()

-type 'shell_fun/1'() :: fun((User :: string()) -> pid()).

Equivalent to 'shell_fun/2'/0.

'shell_fun/2'()

-type 'shell_fun/2'() :: fun((User :: string(), PeerAddr :: inet:ip_address()) -> pid()).

Defines the read-eval-print loop used in a daemon when a shell is requested by the client.

See the option exec-option for a description of how the daemon executes shell-requests and exec-requests depending on the shell- and exec-options.

shell_spec()

-type shell_spec() :: mod_fun_args() | shell_fun() | disabled.

ssh_cli_daemon_option()

-type ssh_cli_daemon_option() :: {ssh_cli, mod_args() | no_cli}.

Provides your own CLI implementation in a daemon.

It is a channel callback module that implements a shell and command execution. The shell's read-eval-print loop can be customized, using the option shell. This means less work than implementing an own CLI channel. If ssh_cli is set to no_cli, the CLI channels like shell and exec are disabled and only subsystem channels are allowed.

ssh_moduli_file()

-type ssh_moduli_file() :: {ssh_moduli_file, string()}.

dh_gex_groups - Defines the groups the server may choose among when diffie-hellman-group-exchange is negotiated. See RFC 4419 for details. The three variants of this option are:

{Size=integer(),G=integer(),P=integer()} - The groups are given explicitly in this list. There may be several elements with the same Size. In such a case, the server will choose one randomly in the negotiated Size.

{file,filename()} - The file must have one or more three-tuples {Size=integer(),G=integer(),P=integer()} terminated by a dot. The file is read when the daemon starts.

{ssh_moduli_file,filename()} - The file must be in ssh-keygen moduli file format. The file is read when the daemon starts.

The default list is fetched from the public_key application.

dh_gex_limits - Limits what a client can ask for in diffie-hellman-group-exchange. The limits will be {MaxUsed = min(MaxClient,Max), MinUsed = max(MinClient,Min)} where MaxClient and MinClient are the values proposed by a connecting client.

The default value is {0,infinity}.

If MaxUsed < MinUsed in a key exchange, it will fail with a disconnect.

See RFC 4419 for the function of the Max and Min values.

subsystem_daemon_option()

-type subsystem_daemon_option() :: {subsystems, subsystem_specs()}.

subsystem_spec()

-type subsystem_spec() :: {Name :: string(), mod_args()}.

Defines a subsystem in the daemon.

The subsystem_name is the name that a client requests to start with for example ssh_connection:subsystem/4.

The channel_callback is the module that implements the ssh_server_channel (replaces ssh_daemon_channel) behaviour in the daemon. See the section Creating a Subsystem in the User's Guide for more information and an example.

If the subsystems option is not present, the default is an empty list and no subsystems are enabled.

To enable the SFTP subsystem:

ssh:daemon(Port, [{subsystems, [ssh_sftpd:subsystem_spec([])]} | Options])

subsystem_specs()

-type subsystem_specs() :: [subsystem_spec()].

tcpip_tunnel_in_daemon_option()

-type tcpip_tunnel_in_daemon_option() ::
          {tcpip_tunnel_in,
           boolean() |
           (Callback :: fun((HostName :: string(), inet:port_number()) -> boolean() | denied))}.

Enables (true) or disables (false) the possibility to tunnel a TCP/IP connection in to a server. Disabled per default.

Set Callback function to allow/deny/log tunnel connections.

tcpip_tunnel_out_daemon_option()

-type tcpip_tunnel_out_daemon_option() :: {tcpip_tunnel_out, boolean()}.

Enables (true) or disables (false) the possibility to tunnel a TCP/IP connection out of a server. Disabled per default.

Types: Deprecated

ssh_channel_id()

-opaque ssh_channel_id()

ssh_connection_ref()

-opaque ssh_connection_ref()

ssh_daemon_ref()

-opaque ssh_daemon_ref()

Types: Legacy Algorithms

legacy_cipher_alg()

-type legacy_cipher_alg() :: 'aes128-cbc' | 'aes192-cbc' | 'aes256-cbc' | '3des-cbc'.

legacy_compression_alg()

This type is deprecated. use 'none' or 'zlib@openssh.com' instead.

-type legacy_compression_alg() :: zlib.

Deprecated: the use of zlib compression in SSH will be removed in OTP 30.0. Use none or zlib@openssh.com instead.

legacy_kex_alg()

-type legacy_kex_alg() ::
          'diffie-hellman-group1-sha1' | 'diffie-hellman-group14-sha1' |
          'diffie-hellman-group-exchange-sha1'.

legacy_mac_alg()

-type legacy_mac_alg() :: 'hmac-sha1-96'.

legacy_pubkey_alg()

-type legacy_pubkey_alg() :: 'ssh-rsa' | 'ssh-dss'.

Types

channel_id()

-opaque channel_id()

Opaque data type representing a channel inside a connection.

Returned by the functions ssh_connection:session_channel/2,4.

conn_info_algs()

-type conn_info_algs() ::
          [{kex, kex_alg()} |
           {hkey, pubkey_alg()} |
           {encrypt, cipher_alg()} |
           {decrypt, cipher_alg()} |
           {send_mac, mac_alg()} |
           {recv_mac, mac_alg()} |
           {compress, compression_alg()} |
           {decompress, compression_alg()} |
           {send_ext_info, boolean()} |
           {recv_ext_info, boolean()}].

conn_info_channels()

-type conn_info_channels() :: [proplists:proplist()].

connection_info_tuple()

-type connection_info_tuple() ::
          {client_version, version()} |
          {server_version, version()} |
          {user, string()} |
          {peer, {inet:hostname(), ip_port()}} |
          {sockname, ip_port()} |
          {options, client_options()} |
          {algorithms, conn_info_algs()} |
          {channels, conn_info_channels()}.

Return values from the connection_info/1 and connection_info/2 functions.

Note

Note that options info tuple contains only items with nondefault values.

connection_ref()

-type connection_ref() :: pid().

Opaque data type representing a connection between a client and a server (daemon).

Returned by the functions connect/2,3,4 and ssh_sftp:start_channel/2,3.

daemon_info_tuple()

-type daemon_info_tuple() ::
          {port, inet:port_number()} |
          {ip, inet:ip_address()} |
          {profile, atom()} |
          {options, daemon_options()}.

Return values from the daemon_info/1 and daemon_info/2 functions.

Note

Note that options info tuple contains only items with nondefault values.

daemon_ref()

-opaque daemon_ref()

Opaque data type representing a daemon.

Returned by the functions daemon/1,2,3.

experimental_client_options()

-type experimental_client_options() ::
          {keyboard_interact_fun,
           fun((Name :: iodata(),
                Instruction :: iodata(),
                Prompts :: [{Prompt :: iodata(), Echo :: boolean()}]) ->
                   [Response :: iodata()])} |
          experimental_common_options().

Experimental options that should not to be used in products.

experimental_common_options()

-type experimental_common_options() ::
          {transport, {atom(), atom(), atom()}} |
          {vsn, {non_neg_integer(), non_neg_integer()}} |
          {tstflg, [term()]} |
          ssh_file:user_dir_fun_common_option() |
          {max_random_length_padding, non_neg_integer()}.

Experimental options that should not to be used in products.

experimental_daemon_options()

-type experimental_daemon_options() :: {infofun, fun()} | experimental_common_options().

Experimental options that should not to be used in products.

host()

-type host() :: string() | inet:ip_address() | loopback.

ip_port()

-type ip_port() :: {inet:ip_address(), inet:port_number()}.

mod_args()

-type mod_args() :: {Module :: atom(), Args :: list()}.

mod_fun_args()

-type mod_fun_args() :: {Module :: atom(), Function :: atom(), Args :: list()}.

open_socket()

-type open_socket() :: gen_tcp:socket().

The socket is supposed to be result of a gen_tcp:connect or a gen_tcp:accept. The socket must be in passive mode (that is, opened with the option {active,false}).

protocol_version()

-type protocol_version() :: {Major :: pos_integer(), Minor :: non_neg_integer()}.

role()

-type role() :: client | server.

software_version()

-type software_version() :: string().

version()

-type version() :: {protocol_version(), software_version()}.

Functions

close(ConnectionRef)

-spec close(ConnectionRef) -> ok | {error, term()} when ConnectionRef :: connection_ref().

Closes an SSH connection.

connect(OpenTcpSocket, Options)

(since OTP 19.0)

-spec connect(OpenTcpSocket, Options) -> {ok, connection_ref()} | {error, term()}
                 when OpenTcpSocket :: open_socket(), Options :: client_options().

Equivalent to connect/4.

connect/3

-spec connect(open_socket(), client_options(), timeout()) -> {ok, connection_ref()} | {error, term()};
             (host(), inet:port_number(), client_options()) -> {ok, connection_ref()} | {error, term()}.

Equivalent to connect/4.

connect(Host, Port, Options, NegotiationTimeout)

-spec connect(Host, Port, Options, NegotiationTimeout) -> {ok, connection_ref()} | {error, term()}
                 when
                     Host :: host(),
                     Port :: inet:port_number(),
                     Options :: client_options(),
                     NegotiationTimeout :: timeout().

Connects to an SSH server at the Host on Port.

As an alternative, an already open TCP socket could be passed to the function in TcpSocket. The SSH initiation and negotiation will be initiated on that one with the SSH that should be at the other end.

No channel is started. This is done by calling ssh_connection:session_channel/2,4.

The NegotiationTimeout is in milli-seconds. The default value is infinity or the value of the connect_timeout option, if present. For connection timeout, use the option connect_timeout.

connection_info(ConnectionRef)

(since OTP 22.1)

-spec connection_info(ConnectionRef) -> InfoTupleList | {error, term()}
                         when
                             ConnectionRef :: connection_ref(),
                             InfoTupleList :: [InfoTuple],
                             InfoTuple :: connection_info_tuple().

Equivalent to connection_info/2.

connection_info(ConnectionRef, Key)

-spec connection_info(ConnectionRef, ItemList | Item) -> InfoTupleList | InfoTuple | {error, term()}
                         when
                             ConnectionRef :: connection_ref(),
                             ItemList :: [Item],
                             Item ::
                                 client_version | server_version | user | peer | sockname | options |
                                 algorithms | sockname,
                             InfoTupleList :: [InfoTuple],
                             InfoTuple :: connection_info_tuple().

Returns information about a connection intended for e.g debugging or logging.

When the Key is a single Item, the result is a single InfoTuple

daemon(Port)

-spec daemon(inet:port_number()) -> {ok, daemon_ref()} | {error, term()}.

Equivalent to daemon/3.

daemon/2

-spec daemon(inet:port_number() | open_socket(), daemon_options()) ->
                {ok, daemon_ref()} | {error, term()}.

Equivalent to daemon/3.

daemon(HostAddress, Port, Options)

-spec daemon(any | inet:ip_address(), inet:port_number(), daemon_options()) ->
                {ok, daemon_ref()} | {error, term()};
            (socket, open_socket(), daemon_options()) -> {ok, daemon_ref()} | {error, term()}.

Starts a server listening for SSH connections on the given port. If the Port is 0, a random free port is selected. See daemon_info/1 about how to find the selected port number.

As an alternative, an already open TCP socket could be passed to the function in TcpSocket. The SSH initiation and negotiation will be initiated on that one when an SSH starts at the other end of the TCP socket.

For a description of the options, see Daemon Options.

Please note that by historical reasons both the HostAddress argument and the gen_tcp connect_option() {ip,Address} set the listening address. This is a source of possible inconsistent settings.

The rules for handling the two address passing options are:

if HostAddress is an IP-address, that IP-address is the listening address. An 'ip'-option will be discarded if present.

if HostAddress is the atom loopback, the listening address is loopback and an loopback address will be chosen by the underlying layers. An 'ip'-option will be discarded if present.

if HostAddress is the atom any and no 'ip'-option is present, the listening address is any and the socket will listen to all addresses

if HostAddress is any and an 'ip'-option is present, the listening address is set to the value of the 'ip'-option

daemon_info(DaemonRef)

(since OTP 19.0)

-spec daemon_info(DaemonRef) -> {ok, InfoTupleList} | {error, bad_daemon_ref}
                     when
                         DaemonRef :: daemon_ref(),
                         InfoTupleList :: [InfoTuple],
                         InfoTuple :: daemon_info_tuple().

Equivalent to daemon_info/2.

daemon_info/2

(since OTP 22.1)

-spec daemon_info(DaemonRef, ItemList | Item) -> InfoTupleList | InfoTuple | {error, bad_daemon_ref}
                     when
                         DaemonRef :: daemon_ref(),
                         ItemList :: [Item],
                         Item :: ip | port | profile | options,
                         InfoTupleList :: [InfoTuple],
                         InfoTuple :: daemon_info_tuple().

Returns information about a daemon intended for e.g debugging or logging.

When the Key is a single Item, the result is a single InfoTuple

Note that daemon_info/1 and daemon_info/2 returns different types due to compatibility reasons.

daemon_replace_options(DaemonRef, NewUserOptions)

(since OTP 25.1)

-spec daemon_replace_options(DaemonRef, NewUserOptions) -> {ok, daemon_ref()} | {error, term()}
                                when DaemonRef :: daemon_ref(), NewUserOptions :: daemon_options().

Replaces the options in a running daemon with the options in NewUserOptions. Only connections established after this call are affected, already established connections are not.

Note

In the final phase of this function, the listening process is restarted. Therfore a connection attempt to the daemon in this final phase could fail.

The handling of Erlang configurations is described in the User's Guide; see chapters Configuration in SSH and Configuring algorithms in SSH.

default_algorithms()

(since OTP 18.0)

-spec default_algorithms() -> algs_list().

Returns a key-value list, where the keys are the different types of algorithms and the values are the algorithms themselves.

See the User's Guide for an example.

get_sock_opts(ConnectionRef, SocketGetOptions)

(since OTP 22.3)

-spec get_sock_opts(ConnectionRef, SocketGetOptions) -> ok | {error, inet:posix()}
                       when
                           ConnectionRef :: connection_ref(),
                           SocketGetOptions :: [gen_tcp:option_name()].

Get tcp socket option values of the tcp-socket below an ssh connection.

This function calls the inet:getopts/2, read that documentation.

hostkey_fingerprint(Key)

(since OTP 24.0)

-spec hostkey_fingerprint(public_key:public_key()) -> string().

Equivalent to hostkey_fingerprint/2.

hostkey_fingerprint(TypeOrTypes, Key)

(since OTP 24.0)

-spec hostkey_fingerprint(TypeOrTypes, Key) -> StringOrString
                             when
                                 TypeOrTypes :: public_key:digest_type() | [public_key:digest_type()],
                                 Key :: public_key:public_key(),
                                 StringOrString :: string() | [string()].

hostkey_fingerprint([DigestType], HostKey) -> [string()]hostkey_fingerprint(DigestType, HostKey) -> string()

Calculates a ssh fingerprint from a public host key as openssh does.

The algorithm in hostkey_fingerprint/1 is md5 to be compatible with older ssh-keygen commands. The string from the second variant is prepended by the algorithm name in uppercase as in newer ssh-keygen commands.

Examples:

 2> ssh:hostkey_fingerprint(Key).
 "f5:64:a6:c1:5a:cb:9f:0a:10:46:a2:5c:3e:2f:57:84"

 3> ssh:hostkey_fingerprint(md5,Key).
 "MD5:f5:64:a6:c1:5a:cb:9f:0a:10:46:a2:5c:3e:2f:57:84"

 4> ssh:hostkey_fingerprint(sha,Key).
 "SHA1:bSLY/C4QXLDL/Iwmhyg0PGW9UbY"

 5> ssh:hostkey_fingerprint(sha256,Key).
 "SHA256:aZGXhabfbf4oxglxltItWeHU7ub3Dc31NcNw2cMJePQ"

 6> ssh:hostkey_fingerprint([sha,sha256],Key).
 ["SHA1:bSLY/C4QXLDL/Iwmhyg0PGW9UbY",
  "SHA256:aZGXhabfbf4oxglxltItWeHU7ub3Dc31NcNw2cMJePQ"]

set_sock_opts(ConnectionRef, SocketOptions)

(since OTP 22.3)

-spec set_sock_opts(ConnectionRef, SocketOptions) -> ok | {error, inet:posix()}
                       when ConnectionRef :: connection_ref(), SocketOptions :: [gen_tcp:option()].

Sets tcp socket options on the tcp-socket below an ssh connection.

This function calls the inet:setopts/2, read that documentation and for gen_tcp:option/0.

All gen_tcp socket options except

active

deliver

mode and

packet

are allowed. The excluded options are reserved by the SSH application.

Warning

This is an extremely dangerous function. You use it on your own risk.

Some options are OS and OS version dependent. Do not use it unless you know what effect your option values will have on an TCP stream.

Some values may destroy the functionality of the SSH protocol.

shell/1

-spec shell(open_socket() | host() | connection_ref()) -> _.

Equivalent to shell/3.

shell(Dest, Options)

-spec shell(open_socket() | host(), client_options()) -> _.

Equivalent to shell/3.

shell(Host, Port, Options)

-spec shell(Host, Port, Options) -> _
               when Host :: host(), Port :: inet:port_number(), Options :: client_options().

Connects to an SSH server at Host and Port (defaults to 22) and starts an interactive shell on that remote host.

As an alternative, an already open TCP socket could be passed to the function in TcpSocket. The SSH initiation and negotiation will be initiated on that one and finally a shell will be started on the host at the other end of the TCP socket.

For a description of the options, see Client Options.

The function waits for user input, and does not return until the remote shell is ended (that is, exit from the shell).

start()

-spec start() -> ok | {error, term()}.

Equivalent to start/1.

start(Type)

-spec start(Type) -> ok | {error, term()} when Type :: permanent | transient | temporary.

Utility function that starts the applications crypto, public_key, and ssh. Default type is temporary. For more information, see the application manual page in Kernel.

stop()

-spec stop() -> ok | {error, term()}.

Stops the ssh application. For more information, see the application manual page in Kernel.

stop_daemon(DaemonRef)

-spec stop_daemon(DaemonRef :: daemon_ref()) -> ok.

Equivalent to stop_daemon/3.

stop_daemon(Address, Port)

-spec stop_daemon(inet:ip_address(), inet:port_number()) -> ok.

Equivalent to stop_daemon/3.

stop_daemon(Address, Port, Profile)

(since OTP 21.0)

-spec stop_daemon(any | inet:ip_address(), inet:port_number(), atom()) -> ok.

Stops the listener and all connections started by the listener.

If the daemon process does not exist, the call exits the calling process with reason noproc.

stop_listener(SysSup)

-spec stop_listener(daemon_ref()) -> ok.

Equivalent to stop_listener/3.

stop_listener(Address, Port)

-spec stop_listener(inet:ip_address(), inet:port_number()) -> ok.

Equivalent to stop_listener/3.

stop_listener(Address, Port, Profile)

(since OTP 21.0)

-spec stop_listener(any | inet:ip_address(), inet:port_number(), term()) -> ok.

Stops the listener, but leaves existing connections started by the listener operational.

tcpip_tunnel_from_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort)

(since OTP 23.0)

-spec tcpip_tunnel_from_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort) ->
                                  {ok, TrueListenPort} | {error, term()}
                                  when
                                      ConnectionRef :: connection_ref(),
                                      ListenHost :: host(),
                                      ListenPort :: inet:port_number(),
                                      ConnectToHost :: host(),
                                      ConnectToPort :: inet:port_number(),
                                      TrueListenPort :: inet:port_number().

Equivalent to tcpip_tunnel_from_server/6.

tcpip_tunnel_from_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort, Timeout)

(since OTP 23.0)

-spec tcpip_tunnel_from_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort,
                               Timeout) ->
                                  {ok, TrueListenPort} | {error, term()}
                                  when
                                      ConnectionRef :: connection_ref(),
                                      ListenHost :: host(),
                                      ListenPort :: inet:port_number(),
                                      ConnectToHost :: host(),
                                      ConnectToPort :: inet:port_number(),
                                      Timeout :: timeout(),
                                      TrueListenPort :: inet:port_number().

Asks the remote server of ConnectionRef to listen to ListenHost:ListenPort. When someone connects that address, the connection is forwarded in an encrypted channel from the server to the client. The client (that is, at the node that calls this function) then connects to ConnectToHost:ConnectToPort.

The returned TrueListenPort is the port that is listened to. It is the same as ListenPort, except when ListenPort = 0. In that case a free port is selected by the underlying OS.

Note that in case of an Erlang/OTP SSH server (daemon) as peer, that server must have been started with the option tcpip_tunnel_out to allow the connection.

tcpip_tunnel_to_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort)

(since OTP 23.0)

-spec tcpip_tunnel_to_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort) ->
                                {ok, TrueListenPort} | {error, term()}
                                when
                                    ConnectionRef :: connection_ref(),
                                    ListenHost :: host(),
                                    ListenPort :: inet:port_number(),
                                    ConnectToHost :: host(),
                                    ConnectToPort :: inet:port_number(),
                                    TrueListenPort :: inet:port_number().

Equivalent to tcpip_tunnel_to_server/6.

tcpip_tunnel_to_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort, Timeout)

(since OTP 23.0)

-spec tcpip_tunnel_to_server(ConnectionRef, ListenHost, ListenPort, ConnectToHost, ConnectToPort,
                             Timeout) ->
                                {ok, TrueListenPort} | {error, term()}
                                when
                                    ConnectionRef :: connection_ref(),
                                    ListenHost :: host(),
                                    ListenPort :: inet:port_number(),
                                    ConnectToHost :: host(),
                                    ConnectToPort :: inet:port_number(),
                                    Timeout :: timeout(),
                                    TrueListenPort :: inet:port_number().

Tells the local client to listen to ListenHost:ListenPort. When someone connects to that address, the connection is forwarded in an encrypted channel to the peer server of ConnectionRef. That server then connects to ConnectToHost:ConnectToPort.

The returned TrueListenPort is the port that is listened to. It is the same as ListenPort, except when ListenPort = 0. In that case a free port is selected by the underlying OS.

Note that in case of an Erlang/OTP SSH server (daemon) as peer, that server must have been started with the option tcpip_tunnel_in to allow the connection.

ssh_agent

Callback module for using an SSH agent instead of the default ssh_file callback.

This module defines a callback handler for the communication with an SSH Agent and can be used to replace the default callback. This allows to issue signing requests to an agent that stores SSH private keys to perform authentication.

Ssh_agent implements the ssh_client_key_api, to allow it to be used by setting the option key_cb when starting a client (with for example ssh:connect, ssh:shell ).

      {key_cb, {ssh_agent, []}}

The agent communication is established through a UNIX domain socket. By default, the socket path will be fetched from the SSH_AUTH_SOCK environment variable, which is the default socket path in the agent implementation of OpenSSH.

In order to set a different socket path the socket_path option can be set.

      {key_cb, {ssh_agent, [{socket_path, SocketPath}]}}

Note

The functions are Callbacks for the SSH application. They are not intended to be called from the user's code!

Summary

Types: Options

call_ssh_file_option()

The module which the add_host_key and is_host_key callbacks are delegated to. Defaults to the ssh_file module.

socket_path_option()

Sets the socket path for the communication with the agent.

timeout_option()

Sets the time-out in milliseconds when communicating with the agent via the socket. The default value is 1000.

Functions

add_host_key(Host, PublicKey, Options)

Equivalent to add_host_key/4.

add_host_key(Host, Port, PublicKey, Options)

This callback is delegated to the ssh_file module.

is_host_key(Key, Host, Algorithm, Options)

Equivalent to is_host_key/5.

is_host_key(Key, PeerName, Port, Algorithm, Opts)

This callback is delegated to the ssh_file module.

user_key(Algorithm, Options)

Types and description

Types: Options

call_ssh_file_option()

(since OTP 23.0)

-type call_ssh_file_option() :: {call_ssh_file, atom()}.

The module which the add_host_key and is_host_key callbacks are delegated to. Defaults to the ssh_file module.

socket_path_option()

(since OTP 23.0)

-type socket_path_option() :: {socket_path, string()}.

Sets the socket path for the communication with the agent.

timeout_option()

(since OTP 23.0)

-type timeout_option() :: {timeout, timeout()}.

Sets the time-out in milliseconds when communicating with the agent via the socket. The default value is 1000.

Functions

add_host_key(Host, PublicKey, Options)

(since OTP 23.0)

-spec add_host_key(string(), public_key:public_key(), Options) -> ok | {error, Error :: term()}
                      when Options :: ssh_client_key_api:client_key_cb_options(call_ssh_file_option()).

Equivalent to add_host_key/4.

add_host_key(Host, Port, PublicKey, Options)

(since OTP 23.0)

-spec add_host_key(Host, inet:port_number(), public_key:public_key(), Options) -> Result
                      when
                          Host ::
                              inet:ip_address() |
                              inet:hostname() |
                              [inet:ip_address() | inet:hostname()],
                          Options :: ssh_client_key_api:client_key_cb_options(call_ssh_file_option()),
                          Result :: ok | {error, Error :: term()}.

This callback is delegated to the ssh_file module.

is_host_key(Key, Host, Algorithm, Options)

(since OTP 23.0)

-spec is_host_key(Key :: public_key:public_key(),
                  Host :: string(),
                  Algorithm :: ssh:pubkey_alg(),
                  Options) ->
                     boolean()
                     when Options :: ssh_client_key_api:client_key_cb_options(call_ssh_file_option()).

Equivalent to is_host_key/5.

is_host_key(Key, PeerName, Port, Algorithm, Opts)

(since OTP 23.0)

-spec is_host_key(public_key:public_key(), Host, inet:port_number(), ssh:pubkey_alg(), Options) ->
                     boolean()
                     when
                         Host ::
                             inet:ip_address() | inet:hostname() | [inet:ip_address() | inet:hostname()],
                         Options :: ssh_client_key_api:client_key_cb_options(call_ssh_file_option()).

This callback is delegated to the ssh_file module.

user_key(Algorithm, Options)

(since OTP 23.0)

-spec user_key(Algorithm :: ssh:pubkey_alg(), Options) -> Result
                  when
                      Result ::
                          {ok, public_key:private_key()} |
                          {ok, {ssh2_pubkey, PubKeyBlob :: binary()}} |
                          {error, string()},
                      Options ::
                          ssh_client_key_api:client_key_cb_options(socket_path_option() |
                                                                   timeout_option()).

Types and description

See the api description in ssh_client_key_api, Module:user_key/2.

ssh_client_channel behaviour

SSH services (clients and servers) are implemented as channels that are multiplexed over an SSH connection and communicates over the SSH Connection Protocol. This module provides a callback API that takes care of generic channel aspects for clients, such as flow control and close messages. It lets the callback functions take care of the service (application) specific parts. This behavior also ensures that the channel process honors the principal of an OTP-process so that it can be part of a supervisor tree. This is a requirement of channel processes implementing a subsystem that will be added to the ssh applications supervisor tree.

Note

This module replaces ssh_channel.

The old module is still available for compatibility, but should not be used for new programs. The old module will not be maintained except for some error corrections

Note

When implementing a ssh subsystem for daemons, use -behaviour(ssh_server_channel) (Replaces ssh_daemon_channel) instead.

Dont

Functions in this module are not supposed to be called outside a module implementing this behaviour!

Callback timeouts

The timeout values that can be returned by the callback functions have the same semantics as in a gen_server. If the time-out occurs, handle_msg/2 is called as handle_msg(timeout, State).

Summary

Types

client()

Callbacks

code_change(OldVsn, State, Extra)

Converts process state when code is changed.

handle_call(Request, From, State)

Handles messages sent by calling call/2,3

handle_cast(Request, State)

Handles messages sent by calling cast/2.

handle_msg(Msg, State)

Handles other messages than SSH Connection Protocol, call, or cast messages sent to the channel.

handle_ssh_msg/2

Handles SSH Connection Protocol messages that may need service-specific attention. For details, see ssh_connection:event/0.

init(Args)

Makes necessary initializations and returns the initial channel state if the initializations succeed.

terminate(Reason, State)

This function is called by a channel process when it is about to terminate. Before this function is called, ssh_connection:close/2 is called, if it has not been called earlier. This function does any necessary cleaning up. When it returns, the channel process terminates with reason Reason. The return value is ignored.

Functions

call(ChannelRef, Msg)

Equivalent to call/3.

call(ChannelRef, Msg, Timeout)

Makes a synchronous call to the channel process by sending a message and waiting until a reply arrives, or a time-out occurs. The channel calls Module:handle_call/3 to handle the message. If the channel process does not exist, {error, closed} is returned.

cast(ChannelRef, Msg)

Sends an asynchronous message to the channel process and returns ok immediately, ignoring if the destination node or channel process does not exist. The channel calls Module:handle_cast/2 to handle the message.

enter_loop(State)

Makes an existing process an ssh_client_channel (replaces ssh_channel) process.

init(Args)

Initiates a client channel.

reply(Client, Reply)

This function can be used by a channel to send a reply to a client that called call/[2,3] when the reply cannot be defined in the return value of Module:handle_call/3.

start(SshConnection, ChannelId, ChannelCb, CbInitArgs)

Equivalent to start_link/4.

start_link(SshConnection, ChannelId, ChannelCb, CbInitArgs)

Starts a process that handles an SSH channel. It is called internally, by the ssh daemon, or explicitly by the ssh client implementations. The behavior sets the trap_exit flag to true.

Types

client()

(since OTP 21.0)

-opaque client()

Callbacks

code_change(OldVsn, State, Extra)

(since OTP 21.0)

-callback code_change(OldVsn :: term() | {down, term()}, State :: term(), Extra :: term()) ->
                         {ok, NewState :: term()} | {error, Reason :: term()}.

Converts process state when code is changed.

This function is called by a client-side channel when it is to update its internal state during a release upgrade or downgrade, that is, when the instruction {update,Module,Change,...}, where Change={advanced,Extra}, is given in the appup file. For more information, refer to Section 9.11.6 Release Handling Instructions in the System Documentation.

Note

Soft upgrade according to the OTP release concept is not straight forward for the server side, as subsystem channel processes are spawned by the ssh application and hence added to its supervisor tree. The subsystem channels can be upgraded when upgrading the user application, if the callback functions can handle two versions of the state, but this function cannot be used in the normal way.

handle_call(Request, From, State)

(since OTP 21.0)

-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()}, State :: term()) ->
                         {reply, Reply :: term(), NewState :: term()} |
                         {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} |
                         {noreply, NewState :: term()} |
                         {noreply, NewState :: term(), timeout() | hibernate} |
                         {stop, Reason :: term(), Reply :: term(), NewState :: term()} |
                         {stop, Reason :: term(), NewState :: term()}.

Handles messages sent by calling call/2,3

For more detailed information on time-outs,, see Section Callback timeouts.

handle_cast(Request, State)

(since OTP 21.0)

-callback handle_cast(Request :: term(), State :: term()) ->
                         {noreply, NewState :: term()} |
                         {noreply, NewState :: term(), timeout() | hibernate} |
                         {stop, Reason :: term(), NewState :: term()}.

Handles messages sent by calling cast/2.

For more detailed information on time-outs, see Section Callback timeouts.

handle_msg(Msg, State)

(since OTP 21.0)

-callback handle_msg(Msg :: term(), State :: term()) ->
                        {ok, State :: term()} | {stop, ChannelId :: ssh:channel_id(), State :: term()}.

Handles other messages than SSH Connection Protocol, call, or cast messages sent to the channel.

Possible Erlang 'EXIT' messages is to be handled by this function and all channels are to handle the following message.

{ssh_channel_up, ssh:channel_id/0 , ssh:connection_ref/0 } - This is the first message that the channel receives. It is sent just before the init/1 function returns successfully. This is especially useful if the server wants to send a message to the client without first receiving a message from it. If the message is not useful for your particular scenario, ignore it by immediately returning {ok, State}.

handle_ssh_msg/2

(since OTP 21.0)

-callback handle_ssh_msg(ssh_connection:event(), State :: term()) ->
                            {ok, State :: term()} | {stop, ChannelId :: ssh:channel_id(), State :: term()}.

Handles SSH Connection Protocol messages that may need service-specific attention. For details, see ssh_connection:event/0.

The following message is taken care of by the ssh_client_channel behavior.

{closed, ssh:channel_id/0 } - The channel behavior sends a close message to the other side, if such a message has not already been sent. Then it terminates the channel with reason normal.

init(Args)

(since OTP 21.0)

-callback init(Args :: term()) ->
                  {ok, State :: term()} |
                  {ok, State :: term(), timeout() | hibernate} |
                  {stop, Reason :: term()} |
                  ignore.

Makes necessary initializations and returns the initial channel state if the initializations succeed.

For more detailed information on time-outs, see Section Callback timeouts.

terminate(Reason, State)

(since OTP 21.0)

-callback terminate(Reason :: normal | shutdown | {shutdown, term()} | term(), State :: term()) -> term().

This function is called by a channel process when it is about to terminate. Before this function is called, ssh_connection:close/2 is called, if it has not been called earlier. This function does any necessary cleaning up. When it returns, the channel process terminates with reason Reason. The return value is ignored.

Functions

call(ChannelRef, Msg)

(since OTP 21.0)

-spec call(ChannelRef, Msg) -> Reply | {error, Reason}
              when ChannelRef :: pid(), Msg :: term(), Reply :: term(), Reason :: closed | timeout.

Equivalent to call/3.

call(ChannelRef, Msg, Timeout)

(since OTP 21.0)

-spec call(ChannelRef, Msg, Timeout) -> Reply | {error, Reason}
              when
                  ChannelRef :: pid(),
                  Msg :: term(),
                  Timeout :: timeout(),
                  Reply :: term(),
                  Reason :: closed | timeout.

Makes a synchronous call to the channel process by sending a message and waiting until a reply arrives, or a time-out occurs. The channel calls Module:handle_call/3 to handle the message. If the channel process does not exist, {error, closed} is returned.

cast(ChannelRef, Msg)

(since OTP 21.0)

-spec cast(ChannelRef, Msg) -> ok when ChannelRef :: pid(), Msg :: term().

Sends an asynchronous message to the channel process and returns ok immediately, ignoring if the destination node or channel process does not exist. The channel calls Module:handle_cast/2 to handle the message.

enter_loop(State)

(since OTP 21.0)

-spec enter_loop(State) -> no_return() when State :: term().

Makes an existing process an ssh_client_channel (replaces ssh_channel) process.

Does not return, instead the calling process enters the ssh_client_channel (replaces ssh_channel) process receive loop and become an ssh_client_channel process. The process must have been started using one of the start functions in proc_lib, see the proc_lib manual page in STDLIB. The user is responsible for any initialization of the process and must call init/1.

init(Args)

(since OTP 21.0)

-spec init(Args) -> {ok, State} | {ok, State, Timeout} | {stop, Reason}
              when
                  Args :: [[{Option :: term(), Value :: term()}]],
                  State :: term(),
                  Timeout :: timeout(),
                  Reason :: term().

Initiates a client channel.

The following options must be present:

{channel_cb, atom()} - The module that implements the channel behaviour.

{init_args(), term()} - The arguments to the init function of the callback module.

{cm, ssh:connection_ref/0 } - Reference to the ssh connection as returned by ssh:connect/3.

{channel_id, ssh:channel_id/0 } - Id of the ssh channel as returned by ssh_connection:session_channel/2,4.

Note

This function is normally not called by the user. The user only needs to call if the channel process needs to be started with help of proc_lib instead of calling start/4 or start_link/4.

reply(Client, Reply)

(since OTP 21.0)

-spec reply(Client, Reply) -> _ when Client :: client(), Reply :: term().

This function can be used by a channel to send a reply to a client that called call/[2,3] when the reply cannot be defined in the return value of Module:handle_call/3.

Client must be the From argument provided to the callback function handle_call/3. Reply is an arbitrary term, which is given back to the client as the return value of [call/[2,3].](call/2)

start(SshConnection, ChannelId, ChannelCb, CbInitArgs)

(since OTP 21.0)

-spec start(SshConnection, ChannelId, ChannelCb, CbInitArgs) ->
               {ok, ChannelRef} | {error, Reason :: term()}
               when
                   SshConnection :: ssh:connection_ref(),
                   ChannelId :: ssh:channel_id(),
                   ChannelCb :: atom(),
                   CbInitArgs :: term(),
                   ChannelRef :: pid().

Equivalent to start_link/4.

start_link(SshConnection, ChannelId, ChannelCb, CbInitArgs)

(since OTP 21.0)

-spec start_link(SshConnection, ChannelId, ChannelCb, CbInitArgs) ->
                    {ok, ChannelRef} | {error, Reason :: term()}
                    when
                        SshConnection :: ssh:connection_ref(),
                        ChannelId :: ssh:channel_id(),
                        ChannelCb :: atom(),
                        CbInitArgs :: term(),
                        ChannelRef :: pid().

Starts a process that handles an SSH channel. It is called internally, by the ssh daemon, or explicitly by the ssh client implementations. The behavior sets the trap_exit flag to true.

The CbInitArgs parameter can be any Erlang term and will be passed as-is to the callback module's init/1 function. Common patterns include:

A list of parameters: [Param1, Param2, ...]

A map: #{key => value}

A single value: an atom, tuple, or other term

ssh_client_key_api behaviour

-behaviour(ssh_client_key_api).

Behavior describing the API for public key handling of an SSH client. By implementing the callbacks defined in this behavior, the public key handling of an SSH client can be customized. By default the ssh application implements this behavior with help of the standard OpenSSH files, see the ssh application manual.

Summary

Types

client_key_cb_options(T)

Options provided to ssh:connect/3,4.

Callbacks

add_host_key(Host, PublicKey, Options)

This function is retired in favour for Module:add_host_key/4 which is the preferred API function. The calling SSH application will still try the add_host_key/3 if the call to add_host_key/4 failed.

add_host_key(Host, Port, PublicKey, Options)

Adds a host key to the set of trusted host keys.

is_host_key(Key, Host, Algorithm, Options)

This function is retired in favour for Module:is_host_key/5 which is the preferred API function. The calling SSH application will still try the is_host_key/4 if the call to is_host_key/5 failed.

is_host_key(Key, Host, Port, Algorithm, Options)

Checks if a host key is trusted.

sign(PubKeyBlob, SigData, Options)

Sign the SigData with the private key corresponding to PubKeyBlob.

user_key(Algorithm, Options)

Fetches the users public key matching the Algorithm. Some key callback modules may return {ssh2_pubkey, PubKeyBlob :: binary()}.

Types

client_key_cb_options(T)

(since OTP R16B)

-type client_key_cb_options(T) :: [{key_cb_private, [T]} | ssh:client_option()].

Options provided to ssh:connect/3,4.

The option list given in the key_cb option is available with the key key_cb_private.

Callbacks

add_host_key(Host, PublicKey, Options)

(since OTP R16B) (optional)

-callback add_host_key(Host :: string(),
                       PublicKey :: public_key:public_key(),
                       Options :: client_key_cb_options(any())) ->
                          ok | {error, term()}.

This function is retired in favour for Module:add_host_key/4 which is the preferred API function. The calling SSH application will still try the add_host_key/3 if the call to add_host_key/4 failed.

Adds a host key to the set of trusted host keys.

add_host_key(Host, Port, PublicKey, Options)

(since OTP R16B) (optional)

-callback add_host_key(Host :: inet:ip_address() | inet:hostname() | [inet:ip_address() | inet:hostname()],
                       Port :: inet:port_number(),
                       PublicKey :: public_key:public_key(),
                       Options :: client_key_cb_options(any())) ->
                          ok | {error, term()}.

Adds a host key to the set of trusted host keys.

This function is preferred to the old Module:add_host_key/3 since it also uses the peer host port number and may return an error message.

The OTP/SSH application first calls this function in the callback module, and then the old Module:add_host_key/3 for compatibility.

is_host_key(Key, Host, Algorithm, Options)

(since OTP R16B) (optional)

-callback is_host_key(Key :: public_key:public_key(),
                      Host :: string(),
                      Algorithm :: ssh:pubkey_alg(),
                      Options :: client_key_cb_options(any())) ->
                         boolean().

This function is retired in favour for Module:is_host_key/5 which is the preferred API function. The calling SSH application will still try the is_host_key/4 if the call to is_host_key/5 failed.

Checks if a host key is trusted.

is_host_key(Key, Host, Port, Algorithm, Options)

(since OTP 23.0) (optional)

-callback is_host_key(Key :: public_key:public_key(),
                      Host :: inet:ip_address() | inet:hostname() | [inet:ip_address() | inet:hostname()],
                      Port :: inet:port_number(),
                      Algorithm :: ssh:pubkey_alg(),
                      Options :: client_key_cb_options(any())) ->
                         boolean() | {error, term()}.

Checks if a host key is trusted.

This function is preferred to the old Module:is_host_key/4 since it also uses the peer host port number and may return an error message.

The OTP/SSH application first calls this function in the callback module, and then the old Module:is_host_key/4 for compatibility.

sign(PubKeyBlob, SigData, Options)

(since OTP 23.0) (optional)

-callback sign(PubKeyBlob :: binary(), SigData :: binary(), Options :: client_key_cb_options(any())) ->
                  Blob :: binary().

Sign the SigData with the private key corresponding to PubKeyBlob.

user_key(Algorithm, Options)

(since OTP R16B)

-callback user_key(Algorithm :: ssh:pubkey_alg(), Options :: client_key_cb_options(any())) ->
                      {ok, public_key:private_key()} |
                      {ok, {ssh2_pubkey, PubKeyBlob :: binary()}} |
                      {error, string()}.

Fetches the users public key matching the Algorithm. Some key callback modules may return {ssh2_pubkey, PubKeyBlob :: binary()}.

Note

The private key contains the public key.

ssh_connection

This module provides API functions to send SSH Connection Protocol events to the other side of an SSH channel.

The SSH Connection Protocol (RFC 4254) is used by clients and servers, that is, SSH channels, to communicate over the SSH connection. The API functions in this module send SSH Connection Protocol events, which are received as messages by the remote channel handling the remote channel. The Erlang format of thoose messages is (see also below):

{ssh_cm, ssh:connection_ref/0 , channel_msg/0 }

If the ssh_client_channel behavior is used to implement the channel process, these messages are handled by handle_ssh_msg/2.

Summary

Types: Closing a Channel

closed_ch_msg()

This event is sent as a result of calling ssh_connection:close/2. Both the handling of this event and sending it are taken care of by the ssh_client_channel behavior.

eof_ch_msg()

Indicates that the other side sends no more data. This event is sent as a result of calling ssh_connection:send_eof/2.

Types: Data Transfer

data_ch_msg()

Data has arrived on the channel. This event is sent as a result of calling ssh_connection:send/3,4,5.

Types: Environment Variable

env_ch_msg()

Environment variables can be passed to the shell/command to be started later. This event is sent as a result of calling ssh_connection:setenv/5.

Types: Exit Status

exit_signal_ch_msg()

A remote execution can terminate violently because of a signal. Then this message can be received. For details on valid string values, see RFC 4254 Section 6.10, which shows a special case of these signals.

exit_status_ch_msg()

When the command running at the other end terminates, the following message can be sent to return the exit status of the command. A zero exit_status usually means that the command terminated successfully. This event is sent as a result of calling ssh_connection:exit_status/3.

Types: General

channel_msg()

As mentioned in the introduction, the SSH Connection Protocol events are handled as messages. When writing a channel handling process without using the support by the ssh_client_channel behavior the process must handle thoose messages.

event()

want_reply()

Messages that include a WantReply expect the channel handling process to call ssh_connection:reply_request/4 with the boolean value of WantReply as the second argument.

Types: Pseudo-Terminal

pty_ch_msg()

term_mode()

A pseudo-terminal has been requested for the session. Terminal is the value of the TERM environment variable value, that is, vt100. Zero dimension parameters must be ignored. The character/row dimensions override the pixel dimensions (when non-zero). Pixel dimensions refer to the drawable area of the window. Opcode in the TerminalModes list is the mnemonic name, represented as a lowercase Erlang atom, defined in RFC 4254, Section 8. It can also be an Opcode if the mnemonic name is not listed in the RFC. Example: OP code: 53, mnemonic name ECHO erlang atom: echo. This event is sent as a result of calling ssh_connection:ptty_alloc/4.

Types: Shell or Command

exec_ch_msg()

This message requests that the server starts execution of the given command. This event is sent as a result of calling ssh_connection:exec/4 .

shell_ch_msg()

This message requests that the user default shell is started at the other end. This event is sent as a result of calling ssh_connection:shell/2.

Types: Signals

signal_ch_msg()

A signal can be delivered to the remote process/service using the following message. Some systems do not support signals, in which case they are to ignore this message. There is currently no function to generate this event as the signals referred to are on OS-level and not something generated by an Erlang program.

Types: Window Change

window_change_ch_msg()

When the window (terminal) size changes on the client side, it can send a message to the server side to inform it of the new dimensions. No API function generates this event.

Types

channel_id()

connection_ref()

reason()

The result of a call.

req_status()

The status of a request. Corresponds to the SSH_MSG_CHANNEL_SUCCESS and SSH_MSG_CHANNEL_FAILURE values in RFC 4254, Section 5.4.

result()

ssh_data_type_code()

The valid values are 0 ("normal") and 1 ("stderr"), see RFC 4254, Section 5.2.

Functions

adjust_window(ConnectionRef, ChannelId, NumOfBytes)

Adjusts the SSH flow control window. This is to be done by both the client- and server-side channel processes.

close(ConnectionRef, ChannelId)

A server- or client-channel process can choose to close their session by sending a close event.

exec(ConnectionRef, ChannelId, Command, Timeout)

Is to be called by a client-channel process to request that the server starts executing the given command. The result is several messages according to the following pattern. The last message is a channel close message, as the exec request is a one-time execution that closes the channel when it is done.

exit_status(ConnectionRef, ChannelId, Status)

Is to be called by a server-channel process to send the exit status of a command to the client.

ptty_alloc(ConnectionRef, ChannelId, Options)

Equivalent to ptty_alloc/4.

ptty_alloc(ConnectionRef, ChannelId, Options, Timeout)

Sends an SSH Connection Protocol pty_req, to allocate a pseudo-terminal. Is to be called by an SSH client process.

reply_request(ConnectionRef, WantReply, Status, ChannelId)

Sends status replies to requests where the requester has stated that it wants a status report, that is, WantReply = true. If WantReply is false, calling this function becomes a "noop". Is to be called while handling an SSH Connection Protocol message containing a WantReply boolean value.

send(ConnectionRef, ChannelId, Data)

Equivalent to send/5.

send(ConnectionRef, ChannelId, Type, Data)

Depending on input arguments equivalent to one of send/5 calls specified below.

send(ConnectionRef, ChannelId, Type, Data, TimeOut)

Is to be called by client- and server-channel processes to send data to each other.

send_eof(ConnectionRef, ChannelId)

Sends EOF on channel ChannelId.

session_channel(ConnectionRef, Timeout)

Equivalent to session_channel/4.

session_channel(ConnectionRef, InitialWindowSize, MaxPacketSize, Timeout)

Opens a channel for an SSH session. The channel id returned from this function is the id used as input to the other functions in this module.

setenv(ConnectionRef, ChannelId, Var, Value, Timeout)

Environment variables can be passed before starting the shell/command. Is to be called by a client channel processes.

shell(ConnectionRef, ChannelId)

Is to be called by a client channel process to request that the user default shell (typically defined in /etc/passwd in Unix systems) is executed at the server end.

subsystem(ConnectionRef, ChannelId, Subsystem, Timeout)

Is to be called by a client-channel process for requesting to execute a predefined subsystem on the server.

Types: Closing a Channel

closed_ch_msg()

(RFC 4254, section 5.3)

-type closed_ch_msg() :: {closed, ssh:channel_id()}.

This event is sent as a result of calling ssh_connection:close/2. Both the handling of this event and sending it are taken care of by the ssh_client_channel behavior.

eof_ch_msg()

(RFC 4254, section 5.3)

-type eof_ch_msg() :: {eof, ssh:channel_id()}.

Indicates that the other side sends no more data. This event is sent as a result of calling ssh_connection:send_eof/2.

Types: Data Transfer

data_ch_msg()

(RFC 4254, section 5.2)

-type data_ch_msg() :: {data, ssh:channel_id(), ssh_data_type_code(), Data :: binary()}.

Data has arrived on the channel. This event is sent as a result of calling ssh_connection:send/3,4,5.

Types: Environment Variable

env_ch_msg()

(RFC 4254, section 6.4)

-type env_ch_msg() :: {env, ssh:channel_id(), want_reply(), Var :: string(), Value :: string()}.

Environment variables can be passed to the shell/command to be started later. This event is sent as a result of calling ssh_connection:setenv/5.

Types: Exit Status

exit_signal_ch_msg()

(RFC 4254, section 6.10)

-type exit_signal_ch_msg() ::
          {exit_signal,
           ssh:channel_id(),
           ExitSignal :: string(),
           ErrorMsg :: string(),
           LanguageString :: string()}.

A remote execution can terminate violently because of a signal. Then this message can be received. For details on valid string values, see RFC 4254 Section 6.10, which shows a special case of these signals.

exit_status_ch_msg()

(RFC 4254, section 6.10)

-type exit_status_ch_msg() :: {exit_status, ssh:channel_id(), ExitStatus :: non_neg_integer()}.

When the command running at the other end terminates, the following message can be sent to return the exit status of the command. A zero exit_status usually means that the command terminated successfully. This event is sent as a result of calling ssh_connection:exit_status/3.

Types: General

channel_msg()

-type channel_msg() ::
          data_ch_msg() |
          eof_ch_msg() |
          closed_ch_msg() |
          pty_ch_msg() |
          env_ch_msg() |
          shell_ch_msg() |
          exec_ch_msg() |
          signal_ch_msg() |
          window_change_ch_msg() |
          exit_status_ch_msg() |
          exit_signal_ch_msg().

As mentioned in the introduction, the SSH Connection Protocol events are handled as messages. When writing a channel handling process without using the support by the ssh_client_channel behavior the process must handle thoose messages.

event()

-type event() :: {ssh_cm, ssh:connection_ref(), channel_msg()}.

want_reply()

-type want_reply() :: boolean().

Messages that include a WantReply expect the channel handling process to call ssh_connection:reply_request/4 with the boolean value of WantReply as the second argument.

Types: Pseudo-Terminal

pty_ch_msg()

(RFC 4254, section 6.2)

-type pty_ch_msg() ::
          {pty,
           ssh:channel_id(),
           want_reply(),
           {Terminal :: string(),
            CharWidth :: non_neg_integer(),
            RowHeight :: non_neg_integer(),
            PixelWidth :: non_neg_integer(),
            PixelHeight :: non_neg_integer(),
            TerminalModes :: [term_mode()]}}.

term_mode()

(RFC 4254, section 6.2)

-type term_mode() :: {Opcode :: atom() | byte(), Value :: non_neg_integer()}.

A pseudo-terminal has been requested for the session. Terminal is the value of the TERM environment variable value, that is, vt100. Zero dimension parameters must be ignored. The character/row dimensions override the pixel dimensions (when non-zero). Pixel dimensions refer to the drawable area of the window. Opcode in the TerminalModes list is the mnemonic name, represented as a lowercase Erlang atom, defined in RFC 4254, Section 8. It can also be an Opcode if the mnemonic name is not listed in the RFC. Example: OP code: 53, mnemonic name ECHO erlang atom: echo. This event is sent as a result of calling ssh_connection:ptty_alloc/4.

Types: Shell or Command

exec_ch_msg()

(RFC 4254, section 6.5)

-type exec_ch_msg() :: {exec, ssh:channel_id(), want_reply(), Command :: string()}.

This message requests that the server starts execution of the given command. This event is sent as a result of calling ssh_connection:exec/4 .

shell_ch_msg()

(RFC 4254, section 6.5)

-type shell_ch_msg() :: {shell, ssh:channel_id(), want_reply()}.

This message requests that the user default shell is started at the other end. This event is sent as a result of calling ssh_connection:shell/2.

Types: Signals

signal_ch_msg()

(RFC 4254, section 6.9)

-type signal_ch_msg() :: {signal, ssh:channel_id(), SignalName :: string()}.

A signal can be delivered to the remote process/service using the following message. Some systems do not support signals, in which case they are to ignore this message. There is currently no function to generate this event as the signals referred to are on OS-level and not something generated by an Erlang program.

Types: Window Change

window_change_ch_msg()

(RFC 4254, section 6.7)

-type window_change_ch_msg() ::
          {window_change,
           ssh:channel_id(),
           CharWidth :: non_neg_integer(),
           RowHeight :: non_neg_integer(),
           PixelWidth :: non_neg_integer(),
           PixelHeight :: non_neg_integer()}.

When the window (terminal) size changes on the client side, it can send a message to the server side to inform it of the new dimensions. No API function generates this event.

Types

channel_id()

-type channel_id() :: ssh:channel_id().

connection_ref()

-type connection_ref() :: ssh:connection_ref().

reason()

-type reason() :: closed | timeout.

The result of a call.

If the request reached the peer, was handled and the response reached the requesting node the req_status/0 is the status reported from the peer.

If not, the reason/0 indicates what went wrong:

closed - indicates that the channel or connection was closed when trying to send the request

timeout - indicates that the operation exceeded a time limit

req_status()

-type req_status() :: success | failure.

The status of a request. Corresponds to the SSH_MSG_CHANNEL_SUCCESS and SSH_MSG_CHANNEL_FAILURE values in RFC 4254, Section 5.4.

result()

-type result() :: req_status() | {error, reason()}.

ssh_data_type_code()

-type ssh_data_type_code() :: non_neg_integer().

The valid values are 0 ("normal") and 1 ("stderr"), see RFC 4254, Section 5.2.

Functions

adjust_window(ConnectionRef, ChannelId, NumOfBytes)

-spec adjust_window(ConnectionRef, ChannelId, NumOfBytes) -> ok
                       when
                           ConnectionRef :: ssh:connection_ref(),
                           ChannelId :: ssh:channel_id(),
                           NumOfBytes :: integer().

Adjusts the SSH flow control window. This is to be done by both the client- and server-side channel processes.

Note

Channels implemented with the ssh_client_channel behavior do not normally need to call this function as flow control is handled by the behavior. The behavior adjusts the window every time the callback handle_ssh_msg/2 returns after processing channel data.

close(ConnectionRef, ChannelId)

-spec close(ConnectionRef, ChannelId) -> ok
               when ConnectionRef :: ssh:connection_ref(), ChannelId :: ssh:channel_id().

A server- or client-channel process can choose to close their session by sending a close event.

Note

This function is called by the ssh_client_channel behavior when the channel is terminated, see ssh_client_channel. Thus, channels implemented with the behavior are not to call this function explicitly.

exec(ConnectionRef, ChannelId, Command, Timeout)

-spec exec(ConnectionRef, ChannelId, Command, Timeout) -> result()
              when
                  ConnectionRef :: ssh:connection_ref(),
                  ChannelId :: ssh:channel_id(),
                  Command :: string(),
                  Timeout :: timeout().

Is to be called by a client-channel process to request that the server starts executing the given command. The result is several messages according to the following pattern. The last message is a channel close message, as the exec request is a one-time execution that closes the channel when it is done.

N x data message(s) - The result of executing the command can be only one line or thousands of lines depending on the command.

0 or 1 x eof message - Indicates that no more data is to be sent.

0 or 1 x exit signal message - Not all systems send signals. For details on valid string values, see RFC 4254, Section 6.10

0 or 1 x exit status message - It is recommended by the SSH Connection Protocol to send this message, but that is not always the case.

1 x closed status message - Indicates that the ssh_client_channel started for the execution of the command has now been shut down.

See the User's Guide section on One-Time Execution for examples.

Note

In case when command generates large amount of output data, manual window adjustment might be necessary in order to receive it. see ssh_connectino:adjust_window/3

exit_status(ConnectionRef, ChannelId, Status)

-spec exit_status(ConnectionRef, ChannelId, Status) -> ok
                     when
                         ConnectionRef :: ssh:connection_ref(),
                         ChannelId :: ssh:channel_id(),
                         Status :: integer().

Is to be called by a server-channel process to send the exit status of a command to the client.

ptty_alloc(ConnectionRef, ChannelId, Options)

(since OTP 17.5)

-spec ptty_alloc(ConnectionRef, ChannelId, Options) -> result()
                    when
                        ConnectionRef :: ssh:connection_ref(),
                        ChannelId :: ssh:channel_id(),
                        Options :: proplists:proplist().

Equivalent to ptty_alloc/4.

ptty_alloc(ConnectionRef, ChannelId, Options, Timeout)

(since OTP 17.4)

-spec ptty_alloc(ConnectionRef, ChannelId, Options, Timeout) -> result()
                    when
                        ConnectionRef :: ssh:connection_ref(),
                        ChannelId :: ssh:channel_id(),
                        Options :: proplists:proplist(),
                        Timeout :: timeout().

Sends an SSH Connection Protocol pty_req, to allocate a pseudo-terminal. Is to be called by an SSH client process.

Options:

{term, string()} - Defaults to os:getenv("TERM") or vt100 if it is undefined.

{width, integer()} - Defaults to 80 if pixel_width is not defined.

{height, integer()} - Defaults to 24 if pixel_height is not defined.

{pixel_width, integer()} - Is disregarded if width is defined.

{pixel_height, integer()} - Is disregarded if height is defined.

{pty_opts, [{posix_atom(), integer()}]} - Option can be an empty list. Otherwise, see possible POSIX names in Section 8 in RFC 4254.

reply_request(ConnectionRef, WantReply, Status, ChannelId)

-spec reply_request(ConnectionRef, WantReply, Status, ChannelId) -> ok
                       when
                           ConnectionRef :: ssh:connection_ref(),
                           WantReply :: boolean(),
                           Status :: req_status(),
                           ChannelId :: ssh:channel_id().

Sends status replies to requests where the requester has stated that it wants a status report, that is, WantReply = true. If WantReply is false, calling this function becomes a "noop". Is to be called while handling an SSH Connection Protocol message containing a WantReply boolean value.

send(ConnectionRef, ChannelId, Data)

-spec send(connection_ref(), channel_id(), iodata()) -> ok | {error, reason()}.

Equivalent to send/5.

send(ConnectionRef, ChannelId, Type, Data)

-spec send(connection_ref(), channel_id(), iodata(), timeout()) -> ok | {error, reason()};
          (connection_ref(), channel_id(), ssh_data_type_code(), iodata()) -> ok | {error, reason()}.

Depending on input arguments equivalent to one of send/5 calls specified below.

Equivalent to send(ConnectionRef, ChannelId, 0, Data, TimeOut) if called with TimeOut being integer.

Equivalent to send(ConnectionRef, ChannelId, 0, Data, infinity) if called with TimeOut being infinity atom.

Equivalent to send(ConnectionRef, ChannelId, Type, Data, infinity) if called with last argument which is not integer or infinity atom.

send(ConnectionRef, ChannelId, Type, Data, TimeOut)

-spec send(connection_ref(), channel_id(), ssh_data_type_code(), iodata(), timeout()) ->
              ok | {error, reason()}.

Is to be called by client- and server-channel processes to send data to each other.

The function subsystem/4 and subsequent calls of send/3,4,5 must be executed in the same process.

send_eof(ConnectionRef, ChannelId)

-spec send_eof(ConnectionRef, ChannelId) -> ok | {error, closed}
                  when ConnectionRef :: ssh:connection_ref(), ChannelId :: ssh:channel_id().

Sends EOF on channel ChannelId.

session_channel(ConnectionRef, Timeout)

-spec session_channel(ConnectionRef, Timeout) -> Result
                         when
                             ConnectionRef :: ssh:connection_ref(),
                             Timeout :: timeout(),
                             Result :: {ok, ssh:channel_id()} | {error, reason()}.

Equivalent to session_channel/4.

session_channel(ConnectionRef, InitialWindowSize, MaxPacketSize, Timeout)

-spec session_channel(ConnectionRef, InitialWindowSize, MaxPacketSize, Timeout) -> Result
                         when
                             ConnectionRef :: ssh:connection_ref(),
                             InitialWindowSize :: pos_integer() | undefined,
                             MaxPacketSize :: pos_integer() | undefined,
                             Timeout :: timeout(),
                             Result :: {ok, ssh:channel_id()} | {error, reason()}.

Opens a channel for an SSH session. The channel id returned from this function is the id used as input to the other functions in this module.

setenv(ConnectionRef, ChannelId, Var, Value, Timeout)

-spec setenv(ConnectionRef, ChannelId, Var, Value, Timeout) -> success
                when
                    ConnectionRef :: ssh:connection_ref(),
                    ChannelId :: ssh:channel_id(),
                    Var :: string(),
                    Value :: string(),
                    Timeout :: timeout().

Environment variables can be passed before starting the shell/command. Is to be called by a client channel processes.

shell(ConnectionRef, ChannelId)

-spec shell(ConnectionRef, ChannelId) -> Result
               when
                   ConnectionRef :: ssh:connection_ref(),
                   ChannelId :: ssh:channel_id(),
                   Result :: ok | success | failure | {error, timeout}.

Is to be called by a client channel process to request that the user default shell (typically defined in /etc/passwd in Unix systems) is executed at the server end.

Note: the return value is ok instead of success unlike in other functions in this module. This is a fault that was introduced so long ago that any change would break a large number of existing software.

subsystem(ConnectionRef, ChannelId, Subsystem, Timeout)

-spec subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) -> result()
                   when
                       ConnectionRef :: ssh:connection_ref(),
                       ChannelId :: ssh:channel_id(),
                       Subsystem :: string(),
                       Timeout :: timeout().

Is to be called by a client-channel process for requesting to execute a predefined subsystem on the server.

The function subsystem/4 and subsequent calls of send/3,4,5 must be executed in the same process.

ssh_file

Default callback module for the client's and server's database operations in the ssh application

This module is the default callback handler for the client's and the server's user and host "database" operations. All data, for instance key pairs, are stored in files in the normal file system. This page documents the files, where they are stored and configuration options for this callback module.

The intention is to be compatible with the OpenSSH storage in files. Therefore it mimics directories and filenames of OpenSSH.

Ssh_file implements the ssh_server_key_api and the ssh_client_key_api. This enables the user to make an own interface using for example a database handler.

Such another callback module could be used by setting the option key_cb when starting a client or a server (with for example ssh:connect, ssh:daemon or ssh:shell ).

Callbacks

The callback functions (host_key/2, is_auth_key/3, user_key/2, is_host_key/5, add_host_key/4) are called by the SSH application internally. They are documented here to show which files and options the default implementation uses. See ssh_server_key_api and ssh_client_key_api for the callback specifications.

The public API functions are decode/2, encode/2, and extract_public_key/1.

Files, directories and who uses them

Daemons

Daemons uses all files stored in the SYSDIR directory.

Optionally, in case of publickey authorization, one or more of the remote user's public keys in the USERDIR directory are used. See the files USERDIR/authorized_keys and USERDIR/authorized_keys2.

Clients

Clients uses all files stored in the USERDIR directory.

Directory contents

LOCALUSER
The user name of the OS process running the Erlang virtual machine (emulator).

SYSDIR
This is the directory holding the server's files:

ssh_host_dsa_key - private dss host key (optional)

ssh_host_rsa_key - private rsa host key (optional)

ssh_host_ecdsa_key - private ecdsa host key (optional)

ssh_host_ed25519_key - private eddsa host key for curve 25519 (optional)

ssh_host_ed448_key - private eddsa host key for curve 448 (optional)

The key files could be generated with OpenSSH's ssh-keygen command.

At least one host key must be defined. The default value of SYSDIR is /etc/ssh.

For security reasons, this directory is normally accessible only to the root user.

To change the SYSDIR, see the system_dir option.

USERDIR
This is the directory holding the files:

authorized_keys and, as second alternative authorized_keys2 - the user's public keys are stored concatenated in one of those files.

It is composed of lines as for OpenSSH:

(options)? keytype base64-encoded-key comment

where

options :: option(,option)*
option :: % All options are skipped
keytype :: 'ssh-dsa'
         | 'ssh-rsa'
         | 'ssh-ecdsa-nistp256'
     | 'ssh-ecdsa-nistp384'
         | 'ssh-ecdsa-nistp521'
         | 'ssh-ed25519'
     | 'ssh-ed448'
base64-encoded-key :: % The user's public key
comment :: % Comments are skipped

known_hosts - host keys from hosts visited concatenated. The file is created and used by the client.

It is composed of lines as for OpenSSH:

(option)? pattern(,pattern)* keytype key (comment)?

where

option :: '@revoked'
pattern :: host | '[' host ']:' port
host :: ip-address | hostname | '*'
port :: portnumber | '*'
keytype :: 'ssh-dsa'
         | 'ssh-rsa'
         | 'ssh-ecdsa-nistp256'
     | 'ssh-ecdsa-nistp384'
         | 'ssh-ecdsa-nistp521'
         | 'ssh-ed25519'
     | 'ssh-ed448'
key :: % encoded key from eg ssh_host_*.pub

id_dsa - private dss user key (optional)

id_rsa - private rsa user key (optional)

id_ecdsa - private ecdsa user key (optional)

id_ed25519 - private eddsa user key for curve 25519 (optional)

id_ed448 - private eddsa user key for curve 448 (optional)

The key files could be generated with OpenSSH's ssh-keygen command.

The default value of USERDIR is /home/LOCALUSER/.ssh.

To change the USERDIR, see the user_dir option

Summary

Types: Options

experimental_openssh_key_v1_decode()

experimental_openssh_key_v1_encode()

key()

The key representation

openssh_key_v1_attributes()

Types for the experimental implementation of the openssh_key_v1 format.

optimize_key_lookup()

Make the handling of large files fast by setting time, but this will use more memory. The space variant shrinks the memory requirements, but with a higher time consumption.

pubkey_passphrase_client_options()

If the user's DSA, RSA or ECDSA key is protected by a passphrase, it can be supplied with those options.

system_dir_daemon_option()

Sets the system directory.

user2dir()

Sets the user directory dynamically by evaluating the user2dir function.

user_dir_common_option()

Sets the user directory.

user_dir_fun_common_option()

API

decode(SshBin, Type)

Decodes an SSH file-binary.

encode(InData, Type)

Encodes a list of SSH file entries (public keys and attributes) to a binary.

extract_public_key(PrivKey)

Fetches the public key from a private key.

Callback Implementations

add_host_key(Host, Port, Key, Options)

Implements ssh_client_key_api:add_host_key/4.

host_key(Algorithm, Options)

Implements ssh_server_key_api:host_key/2.

is_auth_key(Key, User, Options)

Implements ssh_server_key_api:is_auth_key/3.

is_host_key(Key, Host, Port, Algorithm, Options)

Implements ssh_client_key_api:is_host_key/5.

user_key(Algorithm, Options)

Implements ssh_client_key_api:user_key/2.

Types: Options

experimental_openssh_key_v1_decode()

(since OTP 21.2)

-type experimental_openssh_key_v1_decode() :: [{key(), openssh_key_v1_attributes()}].

experimental_openssh_key_v1_encode()

(since OTP 21.2)

-type experimental_openssh_key_v1_encode() ::
          [{[{public_key:public_key(), public_key:private_key(), Comment :: binary()} |
             {public_key:private_key(), Comment :: binary()}],
            openssh_key_v1_attributes()}].

key()

(since OTP 21.2)

-type key() :: public_key:public_key() | public_key:private_key().

The key representation

openssh_key_v1_attributes()

(since OTP 21.2)

-type openssh_key_v1_attributes() :: [{atom(), term()}].

Types for the experimental implementation of the openssh_key_v1 format.

optimize_key_lookup()

(since OTP 21.2)

-type optimize_key_lookup() :: {optimize, time | space}.

Make the handling of large files fast by setting time, but this will use more memory. The space variant shrinks the memory requirements, but with a higher time consumption.

To set it, set the option {key_cb, {ssh_file, [{optimize,TimeOrSpace}]} in the call of ssh:connect/3, ssh:daemon/2 or similar function call that initiates an ssh connection.

pubkey_passphrase_client_options()

(since OTP 21.2)

-type pubkey_passphrase_client_options() ::
          {dsa_pass_phrase, string()} | {rsa_pass_phrase, string()} | {ecdsa_pass_phrase, string()}.

If the user's DSA, RSA or ECDSA key is protected by a passphrase, it can be supplied with those options.

Note that EdDSA passhrases (Curves 25519 and 448) are not implemented.

system_dir_daemon_option()

(since OTP 21.2)

-type system_dir_daemon_option() :: {system_dir, string()}.

Sets the system directory.

user2dir()

(since OTP 21.2)

-type user2dir() :: fun((RemoteUserName :: string()) -> UserDir :: string()).

Sets the user directory dynamically by evaluating the user2dir function.

user_dir_common_option()

(since OTP 21.2)

-type user_dir_common_option() :: {user_dir, string()}.

Sets the user directory.

user_dir_fun_common_option()

(since OTP 21.2)

-type user_dir_fun_common_option() :: {user_dir_fun, user2dir()}.

API

decode(SshBin, Type)

(since OTP 24.0)

-spec decode(SshBin, Type) -> Decoded | {error, term()}
                when
                    SshBin :: binary(),
                    Type ::
                        ssh2_pubkey | public_key | openssh_key | rfc4716_key | openssh_key_v1 |
                        known_hosts | auth_keys,
                    Decoded ::
                        Decoded_ssh2_pubkey | Decoded_public | Decoded_openssh | Decoded_rfc4716 |
                        Decoded_openssh_key_v1 | Decoded_known_hosts | Decoded_auth_keys,
                    Decoded_ssh2_pubkey :: public_key:public_key(),
                    Decoded_public :: Decoded_rfc4716 | Decoded_openssh_key_v1 | Decoded_openssh,
                    Decoded_openssh :: [{public_key:public_key(), [{comment, string()}]}],
                    Decoded_rfc4716 :: [{key(), [{headers, Attrs}]}],
                    Decoded_openssh_key_v1 :: experimental_openssh_key_v1_decode(),
                    Decoded_known_hosts ::
                        [{public_key:public_key(), [{comment, string()} | {hostnames, [string()]}]}],
                    Decoded_auth_keys ::
                        [{public_key:public_key(), [{comment, string()} | {options, [string()]}]}],
                    Attrs :: {Key :: string(), Value :: string()}.

Decodes an SSH file-binary.

If Type is public_key the binary can be either an RFC4716 public key or an OpenSSH public key.

Note

The implementation of the openssh_key_v1 format is still experimental.

encode(InData, Type)

(since OTP 24.0)

-spec encode(InData, Type) -> binary() | {error, term()}
                when
                    Type ::
                        ssh2_pubkey | openssh_key | rfc4716_key | openssh_key_v1 | known_hosts |
                        auth_keys,
                    InData ::
                        InData_ssh2_pubkey | InData_openssh | InData_rfc4716 | InData_openssh_key_v1 |
                        InData_known_hosts | InData_auth_keys,
                    InData_ssh2_pubkey :: public_key:public_key(),
                    InData_openssh :: [{public_key:public_key(), [{comment, string()}]}],
                    InData_rfc4716 :: [{key(), [{headers, Attrs}]}],
                    InData_openssh_key_v1 :: experimental_openssh_key_v1_encode(),
                    InData_known_hosts ::
                        [{public_key:public_key(), [{comment, string()} | {hostnames, [string()]}]}],
                    InData_auth_keys ::
                        [{public_key:public_key(), [{comment, string()} | {options, [string()]}]}],
                    Attrs :: {Key :: string(), Value :: string()}.

Encodes a list of SSH file entries (public keys and attributes) to a binary.

Note

The implementation of the openssh_key_v1 format is still experimental.

extract_public_key(PrivKey)

(since OTP 25.0)

-spec extract_public_key(PrivKey) -> PubKey
                            when PrivKey :: public_key:private_key(), PubKey :: public_key:public_key().

Fetches the public key from a private key.

Callback Implementations

add_host_key(Host, Port, Key, Options)

(since OTP 23.0)

-spec add_host_key(Host, Port, Key, Options) -> Result
                      when
                          Host ::
                              inet:ip_address() |
                              inet:hostname() |
                              [inet:ip_address() | inet:hostname()],
                          Port :: inet:port_number(),
                          Key :: public_key:public_key(),
                          Options :: ssh_client_key_api:client_key_cb_options(none()),
                          Result :: ok | {error, term()}.

Implements ssh_client_key_api:add_host_key/4.

Option

user_dir

File

USERDIR/known_hosts

host_key(Algorithm, Options)

(since OTP 21.2)

-spec host_key(Algorithm, Options) -> Result
                  when
                      Algorithm :: ssh:pubkey_alg(),
                      Result :: {ok, public_key:private_key()} | {error, term()},
                      Options :: ssh_server_key_api:daemon_key_cb_options(none()).

Implements ssh_server_key_api:host_key/2.

Options

system_dir

Files

SYSDIR/ssh_host_rsa_key

SYSDIR/ssh_host_dsa_key

SYSDIR/ssh_host_ecdsa_key

SYSDIR/ssh_host_ed25519_key

SYSDIR/ssh_host_ed448_key

is_auth_key(Key, User, Options)

(since OTP 21.2)

-spec is_auth_key(Key, User, Options) -> boolean()
                     when
                         Key :: public_key:public_key(),
                         User :: string(),
                         Options :: ssh_server_key_api:daemon_key_cb_options(optimize_key_lookup()).

Implements ssh_server_key_api:is_auth_key/3.

Options

user_dir_fun

user_dir

Files

USERDIR/authorized_keys

USERDIR/authorized_keys2

This functions discards all options in the beginning of the lines of thoose files when reading them.

is_host_key(Key, Host, Port, Algorithm, Options)

(since OTP 23.0)

-spec is_host_key(Key, Host, Port, Algorithm, Options) -> Result
                     when
                         Key :: public_key:public_key(),
                         Host ::
                             inet:ip_address() | inet:hostname() | [inet:ip_address() | inet:hostname()],
                         Port :: inet:port_number(),
                         Algorithm :: ssh:pubkey_alg(),
                         Options :: ssh_client_key_api:client_key_cb_options(optimize_key_lookup()),
                         Result :: boolean() | {error, term()}.

Implements ssh_client_key_api:is_host_key/5.

Option

user_dir

File

USERDIR/known_hosts

user_key(Algorithm, Options)

(since OTP 21.2)

-spec user_key(Algorithm, Options) -> Result
                  when
                      Algorithm :: ssh:pubkey_alg(),
                      Result :: {ok, public_key:private_key()} | {error, string()},
                      Options :: ssh_client_key_api:client_key_cb_options(none()).

Implements ssh_client_key_api:user_key/2.

Options

user_dir

dsa_pass_phrase

rsa_pass_phrase

ecdsa_pass_phrase

Note that EdDSA passhrases (Curves 25519 and 448) are not implemented.

Files

USERDIR/id_dsa

USERDIR/id_rsa

USERDIR/id_ecdsa

USERDIR/id_ed25519

USERDIR/id_ed448

ssh_server_channel behaviour

-behaviour(ssh_server_channel). (Replaces ssh_daemon_channel)

Note

This module replaces ssh_daemon_channel.

The old module is still available for compatibility, but should not be used for new programs. The old module will not be maintained except for some error corrections

SSH services (clients and servers) are implemented as channels that are multiplexed over an SSH connection and communicates over the SSH Connection Protocol. This module provides a callback API that takes care of generic channel aspects for daemons, such as flow control and close messages. It lets the callback functions take care of the service (application) specific parts. This behavior also ensures that the channel process honors the principal of an OTP-process so that it can be part of a supervisor tree. This is a requirement of channel processes implementing a subsystem that will be added to the ssh applications supervisor tree.

Note

When implementing a client subsystem handler, use -behaviour(ssh_client_channel) instead.

Summary

Callbacks

handle_msg(Msg, State)

Handles other messages than SSH Connection Protocol, call, or cast messages sent to the channel.

handle_ssh_msg/2

Handles SSH Connection Protocol messages that may need service-specific attention. For details, see ssh_connection:event/0.

init(Args)

Makes necessary initializations and returns the initial channel state if the initializations succeed.

terminate(Reason, State)

This function is called by a channel process when it is about to terminate. Before this function is called, ssh_connection:close/2 is called, if it has not been called earlier. This function does any necessary cleaning up. When it returns, the channel process terminates with reason Reason. The return value is ignored.

Callbacks

handle_msg(Msg, State)

(since OTP 21.0)

-callback handle_msg(Msg :: term(), State :: term()) ->
                        {ok, State :: term()} | {stop, ChannelId :: ssh:channel_id(), State :: term()}.

Handles other messages than SSH Connection Protocol, call, or cast messages sent to the channel.

Possible Erlang 'EXIT' messages is to be handled by this function and all channels are to handle the following message.

{ssh_channel_up, ssh:channel_id/0 , ssh:connection_ref/0 } - This is the first message that the channel receives. This is especially useful if the server wants to send a message to the client without first receiving a message from it. If the message is not useful for your particular scenario, ignore it by immediately returning {ok, State}.

handle_ssh_msg/2

(since OTP 21.0)

-callback handle_ssh_msg(ssh_connection:event(), State :: term()) ->
                            {ok, State :: term()} | {stop, ChannelId :: ssh:channel_id(), State :: term()}.

Handles SSH Connection Protocol messages that may need service-specific attention. For details, see ssh_connection:event/0.

The following message is taken care of by the ssh_server_channel behavior.

{closed, ssh:channel_id/0 } - The channel behavior sends a close message to the other side, if such a message has not already been sent. Then it terminates the channel with reason normal.

init(Args)

(since OTP 21.0)

-callback init(Args :: term()) ->
                  {ok, State :: term()} |
                  {ok, State :: term(), timeout() | hibernate} |
                  {stop, Reason :: term()} |
                  ignore.

Makes necessary initializations and returns the initial channel state if the initializations succeed.

The time-out values that can be returned have the same semantics as in a gen_server. If the time-out occurs, handle_msg/2 is called as handle_msg(timeout, State).

terminate(Reason, State)

(since OTP 21.0)

-callback terminate(Reason :: normal | shutdown | {shutdown, term()} | term(), State :: term()) -> term().

This function is called by a channel process when it is about to terminate. Before this function is called, ssh_connection:close/2 is called, if it has not been called earlier. This function does any necessary cleaning up. When it returns, the channel process terminates with reason Reason. The return value is ignored.

ssh_server_key_api behaviour

-behaviour(ssh_server_key_api).

Behaviour describing the API for public key handling of an SSH server. By implementing the callbacks defined in this behavior, the public key handling of an SSH server can be customized. By default the SSH application implements this behavior with help of the standard OpenSSH files, see the ssh application manual.

Summary

Types

daemon_key_cb_options(T)

Options provided to ssh:daemon/2,3.

Callbacks

host_key(Algorithm, DaemonOptions)

Fetches the private key of the host.

is_auth_key(PublicKey, User, DaemonOptions)

Checks if the user key is authorized.

Types

daemon_key_cb_options(T)

(since OTP R16B)

-type daemon_key_cb_options(T) :: [{key_cb_private, [T]} | ssh:daemon_option()].

Options provided to ssh:daemon/2,3.

The option list given in the key_cb option is available with the key key_cb_private.

Callbacks

host_key(Algorithm, DaemonOptions)

(since OTP R16B)

-callback host_key(Algorithm :: ssh:pubkey_alg(), DaemonOptions :: daemon_key_cb_options(any())) ->
                      {ok, PrivateKey :: public_key:private_key()} | {error, term()}.

Fetches the private key of the host.

is_auth_key(PublicKey, User, DaemonOptions)

(since OTP R16B)

-callback is_auth_key(PublicKey :: public_key:public_key(),
                      User :: string(),
                      DaemonOptions :: daemon_key_cb_options(any())) ->
                         boolean().

Checks if the user key is authorized.

ssh_sftp

SFTP client.

This module implements an SSH FTP (SFTP) client. SFTP is a secure, encrypted file transfer service available for SSH.

Summary

Types: Crypto open_tar

chunk_size()

crypto_fun()

crypto_result()

The initial crypto_state/0 returned from the init_fun/0 is folded into repeated applications of the crypto_fun/0 in the tar_crypto_spec. The binary returned from that fun is sent to the remote SFTP server and the new crypto_state/0 is used in the next call of the crypto_fun/0.

crypto_state()

The init_fun/0 in the tar_crypto_spec is applied once prior to any other crypto operation. The intention is that this function initiates the encryption or decryption for example by calling crypto:crypto_init/4 or similar. The crypto_state/0 is the state such a function may return.

decrypt_spec()

Specifies the encryption or decryption applied to tar files when using open_tar/3 or open_tar/4.

encrypt_spec()

final_fun()

If doing encryption, the final_fun/0 in the tar_crypto_spec is applied to the last piece of data. The final_fun/0 is responsible for padding (if needed) and encryption of that last piece.

init_fun()

tar_crypto_spec()

Types

reason()

A description of the reason why an operation failed.

sftp_option()

Specifies available SFTP options.

Functions

apread(ChannelPid, Handle, Position, Len)

The apread/4 function reads from a specified position, combining the position/3 and aread/3 functions.

apwrite(ChannelPid, Handle, Position, Data)

The apwrite/4 function writes to a specified position, combining the position/3 and awrite/3 functions.

aread(ChannelPid, Handle, Len)

Reads from an open file, without waiting for the result. If the handle is valid, the function returns {async, N}, where N is a term guaranteed to be unique between calls of aread. The actual data is sent as a message to the calling process. This message has the form {async_reply, N, Result}, where Result is the result from the read, either {ok, Data}, eof, or {error, reason()}.

awrite(ChannelPid, Handle, Data)

Writes to an open file, without waiting for the result. If the handle is valid, the function returns {async, N}, where N is a term guaranteed to be unique between calls of awrite. The result of the write operation is sent as a message to the calling process. This message has the form {async_reply, N, Result}, where Result is the result from the write, either ok, or {error, reason()}.

close(ChannelPid, Handle)

Equivalent to close/3.

close(ChannelPid, Handle, Timeout)

Closes a handle to an open file or directory on the server.

del_dir(ChannelPid, Name)

Equivalent to del_dir/3.

del_dir(ChannelPid, Name, Timeout)

Deletes a directory specified by Name. The directory must be empty before it can be successfully deleted.

delete(ChannelPid, Name)

Equivalent to delete/3.

delete(ChannelPid, Name, Timeout)

Deletes the file specified by Name.

list_dir(ChannelPid, Path)

Equivalent to list_dir/3.

list_dir(ChannelPid, Path, Timeout)

Lists the given directory on the server, returning the filenames as a list of strings.

make_dir(ChannelPid, Name)

Equivalent to make_dir/3.

make_dir(ChannelPid, Name, Timeout)

Creates a directory specified by Name. Name must be a full path to a new directory. The directory can only be created in an existing directory.

make_symlink(ChannelPid, Name, Target)

Equivalent to make_symlink/4.

make_symlink(ChannelPid, Name, Target, Timeout)

Creates a symbolic link pointing to Target with the name Name.

open(ChannelPid, Name, Mode)

Equivalent to open/4.

open(ChannelPid, Name, Mode, Timeout)

Opens a file on the server and returns a handle, which can be used for reading or writing.

open_tar(ChannelPid, Path, Mode)

Equivalent to open_tar/4.

open_tar(ChannelPid, Path, Mode, Timeout)

Opens a handle to a tar file on the server, associated with ChannelPid. The handle can be used for remote tar creation and extraction. The actual writing and reading is performed by calls to erl_tar:add/3,4 and erl_tar:extract/2. Note: The erl_tar:init/3 function should not be called, that one is called by this open_tar function.

opendir(ChannelPid, Path)

Equivalent to opendir/3.

opendir(ChannelPid, Path, Timeout)

Opens a handle to a directory on the server. The handle can be used for reading directory contents.

position(ChannelPid, Handle, Location)

Equivalent to position/4.

position(ChannelPid, Handle, Location, Timeout)

Sets the file position of the file referenced by Handle. Returns {ok, NewPosition} (as an absolute offset) if successful, otherwise {error, reason()}. Location is one of the following

pread(ChannelPid, Handle, Position, Len)

Equivalent to pread/5.

pread(ChannelPid, Handle, Position, Len, Timeout)

The pread/3,4 function reads from a specified position, combining the position/3 and read/3,4 functions.

pwrite(ChannelPid, Handle, Position, Data)

Equivalent to pwrite/5.

pwrite(ChannelPid, Handle, Position, Data, Timeout)

The pwrite/3,4 function writes to a specified position, combining the position/3 and write/3,4 functions.

read(ChannelPid, Handle, Len)

Equivalent to read/4.

read(ChannelPid, Handle, Len, Timeout)

Reads Len bytes from the file referenced by Handle. Returns {ok, Data}, eof, or {error, reason()}. If the file is opened with binary, Data is a binary, otherwise it is a string.

read_file(ChannelPid, File)

Equivalent to read_file/3.

read_file(ChannelPid, File, Timeout)

Reads a file from the server, and returns the data in a binary.

read_file_info(ChannelPid, Name)

Equivalent to read_file_info/3.

read_file_info(ChannelPid, Name, Timeout)

Returns a file_info record from the file system object specified by Name or Handle. See file:read_file_info/2 for information about the record.

read_link(ChannelPid, Name)

Equivalent to read_link/3.

read_link(ChannelPid, Name, Timeout)

Reads the link target from the symbolic link specified by name.

read_link_info(ChannelPid, Name)

Equivalent to read_link_info/3.

read_link_info(ChannelPid, Name, Timeout)

Returns a file_info record from the symbolic link specified by Name or Handle. See file:read_link_info/2 for information about the record.

rename(ChannelPid, OldName, NewName)

Equivalent to rename/4.

rename(ChannelPid, OldName, NewName, Timeout)

Renames a file named OldName and gives it the name NewName.

start_channel(Dest)

Equivalent to start_channel/2.

start_channel/2

Starts new ssh channel for communicating with the SFTP server.

start_channel(Host, Port, UserOptions0)

Starts new ssh connection and channel for communicating with the SFTP server.

stop_channel(ChannelPid)

Stops an SFTP channel. Does not close the SSH connection. Use ssh:close/1 to close it.

write(ChannelPid, Handle, Data)

Equivalent to write/4.

write(ChannelPid, Handle, Data, Timeout)

Writes data to the file referenced by Handle. The file is to be opened with write or append flag. Returns ok if successful or {error, reason()} otherwise.

write_file(ChannelPid, File, Data)

Equivalent to write_file/4.

write_file(ChannelPid, File, Data, Timeout)

Writes a file to the server. The file is created if it does not exist but overwritten if it exists.

write_file_info(ChannelPid, Name, FileInfo)

Equivalent to write_file_info/4.

write_file_info(ChannelPid, Name, FileInfo, Timeout)

Writes file information from a file_info record to the file specified by Name. See file:write_file_info/2,3 for information about the record.

Types: Crypto open_tar

chunk_size()

-type chunk_size() :: undefined | pos_integer().

crypto_fun()

-type crypto_fun() :: fun((TextIn :: binary(), crypto_state()) -> crypto_result()).

crypto_result()

-type crypto_result() ::
          {ok, TextOut :: binary(), crypto_state()} |
          {ok, TextOut :: binary(), crypto_state(), chunk_size()}.

The initial crypto_state/0 returned from the init_fun/0 is folded into repeated applications of the crypto_fun/0 in the tar_crypto_spec. The binary returned from that fun is sent to the remote SFTP server and the new crypto_state/0 is used in the next call of the crypto_fun/0.

If the crypto_fun/0 reurns a chunk_size/0, that value is as block size for further blocks in calls to crypto_fun/0.

crypto_state()

-type crypto_state() :: any().

The init_fun/0 in the tar_crypto_spec is applied once prior to any other crypto operation. The intention is that this function initiates the encryption or decryption for example by calling crypto:crypto_init/4 or similar. The crypto_state/0 is the state such a function may return.

If the selected cipher needs to have the input data partitioned into blocks of a certain size, the init_fun/0 should return the second form of return value with the chunk_size/0 set to the block size. If the chunk_size/0 is undefined, the size of the PlainBins varies, because this is intended for stream crypto, whereas a fixed chunk_size/0 is intended for block crypto. A chunk_size/0 can be changed in the return from the crypto_fun/0. The value can be changed between pos_integer/0 and undefined.

decrypt_spec()

-type decrypt_spec() :: {init_fun(), crypto_fun()}.

Specifies the encryption or decryption applied to tar files when using open_tar/3 or open_tar/4.

The encryption or decryption is applied to the generated stream of bytes prior to sending the resulting stream to the SFTP server.

For code examples see Section Example with encryption in the ssh Users Guide.

encrypt_spec()

-type encrypt_spec() :: {init_fun(), crypto_fun(), final_fun()}.

final_fun()

-type final_fun() :: fun((FinalTextIn :: binary(), crypto_state()) -> {ok, FinalTextOut :: binary()}).

If doing encryption, the final_fun/0 in the tar_crypto_spec is applied to the last piece of data. The final_fun/0 is responsible for padding (if needed) and encryption of that last piece.

init_fun()

-type init_fun() :: fun(() -> {ok, crypto_state()}) | fun(() -> {ok, crypto_state(), chunk_size()}).

tar_crypto_spec()

-type tar_crypto_spec() :: encrypt_spec() | decrypt_spec().

Types

reason()

-type reason() :: atom() | string() | tuple().

A description of the reason why an operation failed.

The atom/0 value is formed from the sftp error codes in the protocol-level responses as defined in draft-ietf-secsh-filexfer-13 section 9.1. The codes are named as SSH_FX_* which are transformed into lowercase of the star-part. E.g. the error code SSH_FX_NO_SUCH_FILE will cause the reason/0 to be no_such_file.

The string/0 reason is the error information from the server in case of an exit-signal. If that information is empty, the reason is the exit signal name.

The tuple/0 reason are other errors like for example {exit_status,1}.

sftp_option()

-type sftp_option() ::
          {timeout, timeout()} |
          {sftp_vsn, pos_integer()} |
          {window_size, pos_integer()} |
          {packet_size, pos_integer()}.

Specifies available SFTP options.

Functions

apread(ChannelPid, Handle, Position, Len)

-spec apread(ChannelPid, Handle, Position, Len) -> {async, N} | Error
                when
                    ChannelPid :: pid(),
                    Handle :: term(),
                    Position :: integer(),
                    Len :: integer(),
                    Error :: {error, reason()},
                    N :: term().

The apread/4 function reads from a specified position, combining the position/3 and aread/3 functions.

apwrite(ChannelPid, Handle, Position, Data)

-spec apwrite(ChannelPid, Handle, Position, Data) -> {async, N} | Error
                 when
                     ChannelPid :: pid(),
                     Handle :: term(),
                     Position :: integer(),
                     Data :: binary(),
                     Error :: {error, reason()},
                     N :: term().

The apwrite/4 function writes to a specified position, combining the position/3 and awrite/3 functions.

aread(ChannelPid, Handle, Len)

-spec aread(ChannelPid, Handle, Len) -> {async, N} | Error
               when
                   ChannelPid :: pid(),
                   Handle :: term(),
                   Len :: integer(),
                   Error :: {error, reason()},
                   N :: term().

Reads from an open file, without waiting for the result. If the handle is valid, the function returns {async, N}, where N is a term guaranteed to be unique between calls of aread. The actual data is sent as a message to the calling process. This message has the form {async_reply, N, Result}, where Result is the result from the read, either {ok, Data}, eof, or {error, reason()}.

awrite(ChannelPid, Handle, Data)

-spec awrite(ChannelPid, Handle, Data) -> {async, N} | Error
                when
                    ChannelPid :: pid(),
                    Handle :: term(),
                    Data :: binary(),
                    Error :: {error, reason()},
                    N :: term().

Writes to an open file, without waiting for the result. If the handle is valid, the function returns {async, N}, where N is a term guaranteed to be unique between calls of awrite. The result of the write operation is sent as a message to the calling process. This message has the form {async_reply, N, Result}, where Result is the result from the write, either ok, or {error, reason()}.

close(ChannelPid, Handle)

-spec close(ChannelPid, Handle) -> ok | Error
               when ChannelPid :: pid(), Handle :: term(), Error :: {error, reason()}.

Equivalent to close/3.

close(ChannelPid, Handle, Timeout)

-spec close(ChannelPid, Handle, Timeout) -> ok | Error
               when
                   ChannelPid :: pid(),
                   Handle :: term(),
                   Timeout :: timeout(),
                   Error :: {error, reason()}.

Closes a handle to an open file or directory on the server.

del_dir(ChannelPid, Name)

-spec del_dir(ChannelPid, Name) -> ok | Error
                 when ChannelPid :: pid(), Name :: string(), Error :: {error, reason()}.

Equivalent to del_dir/3.

del_dir(ChannelPid, Name, Timeout)

-spec del_dir(ChannelPid, Name, Timeout) -> ok | Error
                 when
                     ChannelPid :: pid(),
                     Name :: string(),
                     Timeout :: timeout(),
                     Error :: {error, reason()}.

Deletes a directory specified by Name. The directory must be empty before it can be successfully deleted.

delete(ChannelPid, Name)

-spec delete(ChannelPid, Name) -> ok | Error
                when ChannelPid :: pid(), Name :: string(), Error :: {error, reason()}.

Equivalent to delete/3.

delete(ChannelPid, Name, Timeout)

-spec delete(ChannelPid, Name, Timeout) -> ok | Error
                when
                    ChannelPid :: pid(),
                    Name :: string(),
                    Timeout :: timeout(),
                    Error :: {error, reason()}.

Deletes the file specified by Name.

list_dir(ChannelPid, Path)

-spec list_dir(ChannelPid, Path) -> {ok, FileNames} | Error
                  when
                      ChannelPid :: pid(),
                      Path :: string(),
                      FileNames :: [FileName],
                      FileName :: string(),
                      Error :: {error, reason()}.

Equivalent to list_dir/3.

list_dir(ChannelPid, Path, Timeout)

-spec list_dir(ChannelPid, Path, Timeout) -> {ok, FileNames} | Error
                  when
                      ChannelPid :: pid(),
                      Path :: string(),
                      Timeout :: timeout(),
                      FileNames :: [FileName],
                      FileName :: string(),
                      Error :: {error, reason()}.

Lists the given directory on the server, returning the filenames as a list of strings.

make_dir(ChannelPid, Name)

-spec make_dir(ChannelPid, Name) -> ok | Error
                  when ChannelPid :: pid(), Name :: string(), Error :: {error, reason()}.

Equivalent to make_dir/3.

make_dir(ChannelPid, Name, Timeout)

-spec make_dir(ChannelPid, Name, Timeout) -> ok | Error
                  when
                      ChannelPid :: pid(),
                      Name :: string(),
                      Timeout :: timeout(),
                      Error :: {error, reason()}.

Creates a directory specified by Name. Name must be a full path to a new directory. The directory can only be created in an existing directory.

make_symlink(ChannelPid, Name, Target)

-spec make_symlink(ChannelPid, Name, Target) -> ok | Error
                      when
                          ChannelPid :: pid(),
                          Name :: string(),
                          Target :: string(),
                          Error :: {error, reason()}.

Equivalent to make_symlink/4.

make_symlink(ChannelPid, Name, Target, Timeout)

-spec make_symlink(ChannelPid, Name, Target, Timeout) -> ok | Error
                      when
                          ChannelPid :: pid(),
                          Name :: string(),
                          Target :: string(),
                          Timeout :: timeout(),
                          Error :: {error, reason()}.

Creates a symbolic link pointing to Target with the name Name.

open(ChannelPid, Name, Mode)

-spec open(ChannelPid, Name, Mode) -> {ok, Handle} | Error
              when
                  ChannelPid :: pid(),
                  Name :: string(),
                  Mode :: [read | write | append | binary | raw],
                  Handle :: term(),
                  Error :: {error, reason()}.

Equivalent to open/4.

open(ChannelPid, Name, Mode, Timeout)

-spec open(ChannelPid, Name, Mode, Timeout) -> {ok, Handle} | Error
              when
                  ChannelPid :: pid(),
                  Name :: string(),
                  Mode :: [read | write | append | binary | raw],
                  Timeout :: timeout(),
                  Handle :: term(),
                  Error :: {error, reason()}.

Opens a file on the server and returns a handle, which can be used for reading or writing.

open_tar(ChannelPid, Path, Mode)

(since OTP 17.4)

-spec open_tar(ChannelPid, Path, Mode) -> {ok, Handle} | Error
                  when
                      ChannelPid :: pid(),
                      Path :: string(),
                      Mode :: [read | write | {crypto, tar_crypto_spec()}],
                      Handle :: term(),
                      Error :: {error, reason()}.

Equivalent to open_tar/4.

open_tar(ChannelPid, Path, Mode, Timeout)

(since OTP 17.4)

-spec open_tar(ChannelPid, Path, Mode, Timeout) -> {ok, Handle} | Error
                  when
                      ChannelPid :: pid(),
                      Path :: string(),
                      Mode :: [read | write | {crypto, tar_crypto_spec()}],
                      Timeout :: timeout(),
                      Handle :: term(),
                      Error :: {error, reason()}.

Opens a handle to a tar file on the server, associated with ChannelPid. The handle can be used for remote tar creation and extraction. The actual writing and reading is performed by calls to erl_tar:add/3,4 and erl_tar:extract/2. Note: The erl_tar:init/3 function should not be called, that one is called by this open_tar function.

For code examples see Section SFTP Client with TAR Compression in the ssh Users Guide.

The crypto mode option is explained in the data types section above, see Crypto operations for open_tar. Encryption is assumed if the Mode contains write, and decryption if the Mode contains read.

opendir(ChannelPid, Path)

-spec opendir(ChannelPid, Path) -> {ok, Handle} | Error
                 when
                     ChannelPid :: pid(), Path :: string(), Handle :: term(), Error :: {error, reason()}.

Equivalent to opendir/3.

opendir(ChannelPid, Path, Timeout)

-spec opendir(ChannelPid, Path, Timeout) -> {ok, Handle} | Error
                 when
                     ChannelPid :: pid(),
                     Path :: string(),
                     Timeout :: timeout(),
                     Handle :: term(),
                     Error :: {error, reason()}.

Opens a handle to a directory on the server. The handle can be used for reading directory contents.

position(ChannelPid, Handle, Location)

-spec position(ChannelPid, Handle, Location) -> {ok, NewPosition} | Error
                  when
                      ChannelPid :: pid(),
                      Handle :: term(),
                      Location ::
                          Offset | {bof, Offset} | {cur, Offset} | {eof, Offset} | bof | cur | eof,
                      Offset :: integer(),
                      NewPosition :: integer(),
                      Error :: {error, reason()}.

Equivalent to position/4.

position(ChannelPid, Handle, Location, Timeout)

-spec position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition} | Error
                  when
                      ChannelPid :: pid(),
                      Handle :: term(),
                      Location ::
                          Offset | {bof, Offset} | {cur, Offset} | {eof, Offset} | bof | cur | eof,
                      Timeout :: timeout(),
                      Offset :: integer(),
                      NewPosition :: integer(),
                      Error :: {error, reason()}.

Sets the file position of the file referenced by Handle. Returns {ok, NewPosition} (as an absolute offset) if successful, otherwise {error, reason()}. Location is one of the following:

Offset - The same as {bof, Offset}.

{bof, Offset} - Absolute offset.

{cur, Offset} - Offset from the current position.

{eof, Offset} - Offset from the end of file.

bof | cur | eof - The same as eariler with Offset 0, that is, {bof, 0} | {cur, 0} | {eof, 0}.

pread(ChannelPid, Handle, Position, Len)

-spec pread(ChannelPid, Handle, Position, Len) -> {ok, Data} | eof | Error
               when
                   ChannelPid :: pid(),
                   Handle :: term(),
                   Position :: integer(),
                   Len :: integer(),
                   Data :: string() | binary(),
                   Error :: {error, reason()}.

Equivalent to pread/5.

pread(ChannelPid, Handle, Position, Len, Timeout)

-spec pread(ChannelPid, Handle, Position, Len, Timeout) -> {ok, Data} | eof | Error
               when
                   ChannelPid :: pid(),
                   Handle :: term(),
                   Position :: integer(),
                   Len :: integer(),
                   Timeout :: timeout(),
                   Data :: string() | binary(),
                   Error :: {error, reason()}.

The pread/3,4 function reads from a specified position, combining the position/3 and read/3,4 functions.

pwrite(ChannelPid, Handle, Position, Data)

-spec pwrite(ChannelPid, Handle, Position, Data) -> ok | Error
                when
                    ChannelPid :: pid(),
                    Handle :: term(),
                    Position :: integer(),
                    Data :: iolist(),
                    Error :: {error, reason()}.

Equivalent to pwrite/5.

pwrite(ChannelPid, Handle, Position, Data, Timeout)

-spec pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | Error
                when
                    ChannelPid :: pid(),
                    Handle :: term(),
                    Position :: integer(),
                    Data :: iolist(),
                    Timeout :: timeout(),
                    Error :: {error, reason()}.

The pwrite/3,4 function writes to a specified position, combining the position/3 and write/3,4 functions.

read(ChannelPid, Handle, Len)

-spec read(ChannelPid, Handle, Len) -> {ok, Data} | eof | Error
              when
                  ChannelPid :: pid(),
                  Handle :: term(),
                  Len :: integer(),
                  Data :: string() | binary(),
                  Error :: {error, reason()}.

Equivalent to read/4.

read(ChannelPid, Handle, Len, Timeout)

-spec read(ChannelPid, Handle, Len, Timeout) -> {ok, Data} | eof | Error
              when
                  ChannelPid :: pid(),
                  Handle :: term(),
                  Len :: integer(),
                  Timeout :: timeout(),
                  Data :: string() | binary(),
                  Error :: {error, reason()}.

Reads Len bytes from the file referenced by Handle. Returns {ok, Data}, eof, or {error, reason()}. If the file is opened with binary, Data is a binary, otherwise it is a string.

If the file is read past eof, only the remaining bytes are read and returned. If no bytes are read, eof is returned.

read_file(ChannelPid, File)

-spec read_file(ChannelPid, File) -> {ok, Data} | Error
                   when
                       ChannelPid :: pid(),
                       File :: string(),
                       Data :: binary(),
                       Error :: {error, reason()}.

Equivalent to read_file/3.

read_file(ChannelPid, File, Timeout)

-spec read_file(ChannelPid, File, Timeout) -> {ok, Data} | Error
                   when
                       ChannelPid :: pid(),
                       File :: string(),
                       Data :: binary(),
                       Timeout :: timeout(),
                       Error :: {error, reason()}.

Reads a file from the server, and returns the data in a binary.

read_file_info(ChannelPid, Name)

-spec read_file_info(ChannelPid, Name) -> {ok, FileInfo} | Error
                        when
                            ChannelPid :: pid(),
                            Name :: string(),
                            FileInfo :: file:file_info(),
                            Error :: {error, reason()}.

Equivalent to read_file_info/3.

read_file_info(ChannelPid, Name, Timeout)

-spec read_file_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | Error
                        when
                            ChannelPid :: pid(),
                            Name :: string(),
                            Timeout :: timeout(),
                            FileInfo :: file:file_info(),
                            Error :: {error, reason()}.

Returns a file_info record from the file system object specified by Name or Handle. See file:read_file_info/2 for information about the record.

Depending on the underlying OS:es links might be followed and info on the final file, directory etc is returned. See read_link_info/2 on how to get information on links instead.

read_link(ChannelPid, Name)

-spec read_link(ChannelPid, Name) -> {ok, Target} | Error
                   when
                       ChannelPid :: pid(),
                       Name :: string(),
                       Target :: string(),
                       Error :: {error, reason()}.

Equivalent to read_link/3.

read_link(ChannelPid, Name, Timeout)

-spec read_link(ChannelPid, Name, Timeout) -> {ok, Target} | Error
                   when
                       ChannelPid :: pid(),
                       Name :: string(),
                       Target :: string(),
                       Timeout :: timeout(),
                       Error :: {error, reason()}.

Reads the link target from the symbolic link specified by name.

read_link_info(ChannelPid, Name)

-spec read_link_info(ChannelPid, Name) -> {ok, FileInfo} | Error
                        when
                            ChannelPid :: pid(),
                            Name :: string(),
                            FileInfo :: file:file_info(),
                            Error :: {error, reason()}.

Equivalent to read_link_info/3.

read_link_info(ChannelPid, Name, Timeout)

-spec read_link_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | Error
                        when
                            ChannelPid :: pid(),
                            Name :: string(),
                            FileInfo :: file:file_info(),
                            Timeout :: timeout(),
                            Error :: {error, reason()}.

Returns a file_info record from the symbolic link specified by Name or Handle. See file:read_link_info/2 for information about the record.

rename(ChannelPid, OldName, NewName)

-spec rename(ChannelPid, OldName, NewName) -> ok | Error
                when
                    ChannelPid :: pid(),
                    OldName :: string(),
                    NewName :: string(),
                    Error :: {error, reason()}.

Equivalent to rename/4.

rename(ChannelPid, OldName, NewName, Timeout)

-spec rename(ChannelPid, OldName, NewName, Timeout) -> ok | Error
                when
                    ChannelPid :: pid(),
                    OldName :: string(),
                    NewName :: string(),
                    Timeout :: timeout(),
                    Error :: {error, reason()}.

Renames a file named OldName and gives it the name NewName.

start_channel(Dest)

-spec start_channel(ssh:open_socket() | ssh:connection_ref() | ssh:host()) ->
                       {ok, pid()} | {ok, pid(), ssh:connection_ref()} | {error, reason()}.

Equivalent to start_channel/2.

start_channel/2

-spec start_channel(ssh:open_socket(), [ssh:client_option() | sftp_option()]) ->
                       {ok, pid(), ssh:connection_ref()} | {error, reason()};
                   (ssh:connection_ref(), [ssh:client_option() | sftp_option()]) ->
                       {ok, pid()} | {ok, pid(), ssh:connection_ref()} | {error, reason()};
                   (ssh:host(), [ssh:client_option() | sftp_option()]) ->
                       {ok, pid(), ssh:connection_ref()} | {error, reason()}.

Starts new ssh channel for communicating with the SFTP server.

Starts an ssh channel when first argument is a connection reference.

Equivalent to start_channel(Host, 22, UserOptions) when first argument is recognized as network host.

Otherwise, first argument is treated as a network socket which will be used for establishing new SSH connection. New connection reference will be used for starting an SSH channel.

The returned pid for this process is to be used as input to all other API functions in this module.

See also (start_channel/3).

start_channel(Host, Port, UserOptions0)

-spec start_channel(ssh:host(), inet:port_number(), [ssh:client_option() | sftp_option()]) ->
                       {ok, pid(), ssh:connection_ref()} | {error, reason()}.

Starts new ssh connection and channel for communicating with the SFTP server.

The returned pid for this process is to be used as input to all other API functions in this module.

Options:

{timeout, timeout()} - There are two ways to set a timeout for the underlying ssh connection:

If the connection timeout option connect_timeout is set, that value is used also for the negotiation timeout and this option (timeout) is ignored.

Otherwise, this option (timeout) is used as the negotiation timeout only and there is no connection timeout set

The value defaults to infinity.

{sftp_vsn, integer()} - Desired SFTP protocol version. The actual version is the minimum of the desired version and the maximum supported versions by the SFTP server.

All other options are directly passed to ssh:connect/3 or ignored if a connection is already provided.

stop_channel(ChannelPid)

-spec stop_channel(ChannelPid) -> ok when ChannelPid :: pid().

Stops an SFTP channel. Does not close the SSH connection. Use ssh:close/1 to close it.

write(ChannelPid, Handle, Data)

-spec write(ChannelPid, Handle, Data) -> ok | Error
               when ChannelPid :: pid(), Handle :: term(), Data :: iodata(), Error :: {error, reason()}.

Equivalent to write/4.

write(ChannelPid, Handle, Data, Timeout)

-spec write(ChannelPid, Handle, Data, Timeout) -> ok | Error
               when
                   ChannelPid :: pid(),
                   Handle :: term(),
                   Data :: iodata(),
                   Timeout :: timeout(),
                   Error :: {error, reason()}.

Writes data to the file referenced by Handle. The file is to be opened with write or append flag. Returns ok if successful or {error, reason()} otherwise.

write_file(ChannelPid, File, Data)

-spec write_file(ChannelPid, File, Data) -> ok | Error
                    when
                        ChannelPid :: pid(),
                        File :: string(),
                        Data :: iodata(),
                        Error :: {error, reason()}.

Equivalent to write_file/4.

write_file(ChannelPid, File, Data, Timeout)

-spec write_file(ChannelPid, File, Data, Timeout) -> ok | Error
                    when
                        ChannelPid :: pid(),
                        File :: string(),
                        Data :: iodata(),
                        Timeout :: timeout(),
                        Error :: {error, reason()}.

Writes a file to the server. The file is created if it does not exist but overwritten if it exists.

write_file_info(ChannelPid, Name, FileInfo)

-spec write_file_info(ChannelPid, Name, FileInfo) -> ok | Error
                         when
                             ChannelPid :: pid(),
                             Name :: string(),
                             FileInfo :: file:file_info(),
                             Error :: {error, reason()}.

Equivalent to write_file_info/4.

write_file_info(ChannelPid, Name, FileInfo, Timeout)

-spec write_file_info(ChannelPid, Name, FileInfo, Timeout) -> ok | Error
                         when
                             ChannelPid :: pid(),
                             Name :: string(),
                             FileInfo :: file:file_info(),
                             Timeout :: timeout(),
                             Error :: {error, reason()}.

Writes file information from a file_info record to the file specified by Name. See file:write_file_info/2,3 for information about the record.

ssh_sftpd

Specifies the channel process to handle an SFTP subsystem.

Specifies a channel process to handle an SFTP subsystem.

Summary

Functions

subsystem_spec(Options)

Is to be used together with ssh:daemon/[1,2,3]

Functions

subsystem_spec(Options)

-spec subsystem_spec(Options) -> Spec
                        when
                            Options ::
                                [{cwd, string()} |
                                 {file_handler, CbMod | {CbMod, FileState}} |
                                 {max_files, integer()} |
                                 {max_handles, integer()} |
                                 {max_path, integer()} |
                                 {root, string()} |
                                 {sftpd_vsn, integer()}],
                            Spec :: {Name, {CbMod, Options}},
                            Name :: string(),
                            CbMod :: atom(),
                            FileState :: term().

Is to be used together with ssh:daemon/[1,2,3]

The Name is "sftp" and CbMod is the name of the Erlang module implementing the subsystem using the ssh_server_channel (replaces ssh_daemon_channel) behaviour.

Options:

cwd - Sets the initial current working directory for the server.

file_handler - Determines which module to call for accessing the file server. The default value is ssh_sftpd_file, which uses the file and filelib APIs to access the standard OTP file server. This option can be used to plug in other file servers.

max_files - The default value is 0, which means that there is no upper limit. If supplied, the number of filenames returned to the SFTP client per READDIR request is limited to at most the given value.

max_handles - The default value is 1000. Positive integer value represents the maximum number of file handles allowed for a connection.

(Note: separate limitation might be also enforced by underlying operating system)

max_path - The default value is 4096. Positive integer value represents the maximum path length which cannot be exceeded in data provided by the SFTP client. (Note: limitations might be also enforced by underlying operating system)

root - Sets the SFTP root directory. Must be an absolute path (e.g., /tmp). Then the user cannot see any files above this root. If, for example, the root directory is set to /tmp, then the user sees this directory as /. If the user then writes cd /etc, the user moves to /tmp/etc.

Note: This provides application-level isolation. For additional security, consider using OS-level chroot or similar mechanisms. See the SFTP subsystem section in the Hardening guide for deployment recommendations.

sftpd_vsn - Sets the SFTP version to use. Defaults to 5. Version 6 is under development and limited.