 |
 |
 |
 |
 |
 |
| |
|
Dropbear SSH DaemonNameCYGPKG_NET_DROPBEAR -- provide SSH daemon support Synopsis#include <dropbear.h>
extern int cyg_dropbear_connections;
|
void cyg_dropbear_init(const cyg_dropbear_data* data);
void cyg_dropbear_done(cyg_dropbear_handle handle, int exit_code);
int cyg_dropbear_get_stderr(cyg_dropbear_handle handle);
const char* cyg_dropbear_get_username(cyg_dropbear_handle handle);
const struct sockaddr_storage* cyg_dropbear_get_addr(cyg_dropbear_handle handle);
DescriptionNote: Dropbear is distributed as an optional set of eCos
packages. These packages are not provided as standard within eCosPro
Developer's Kits.
CYGPKG_NET_DROPBEAR is a port to eCos of some of
the ssh functionality of the dropbear
server code. The port only provides a subset of the standard dropbear
functionality. Only the server or daemon side is supported, allowing
remote clients to log in to an eCos system, but it is not possible for
an eCos application to act as an ssh client and log in to a remote
system. Public/private key authentication is supported, and password
authentication is supported as well if the application developer so
chooses. Agent forwarding, X11 forwarding, compression and scp are not
supported.
This document assumes the reader has a basic understanding of both ssh
operation and of TCP/IP network programming. Information on both of
these can be readily obtained from other sources if desired. The eCos
port of dropbear does behave rather differently from dropbear or other
ssh implementations in a conventional setup such as a network of Linux
workstations. eCos does not support multiple processes or shell
executables. The dropbear code runs in separate threads within the
eCos application, started by a call to
cyg_dropbear_init, rather than as a separate
daemon process. Authentication does not necessarily involve reading in
files such as ~/.ssh/authorized_keys or
/etc/passwd. Instead the application developer
has to write a number of callback functions to supply the necessary
information and can decide how best to implement those functions -
which may involve file I/O if that happens to be convenient. When an
ssh connection is established the dropbear code will not start up a
new shell process inside a pseudo terminal. Instead the dropbear code
will create a local TCP/IP socket and pass one end of this to the
application. Data coming from the network will be decrypted and sent
down the local socket, to be read by application code. Data written by
the application to the local socket will be encrypted and sent over
the network to the ssh client.
The eCos dropbear package comes with two working examples in the
misc/hangman and misc/shell directories which should be
examined in conjunction with this documentation.
APIThe internals of the dropbear code are not directly accessible to
application code. Instead dropbear runs in a number of internal
threads, interacting with the application via local TCP/IP sockets and
a number of callback functions.
InitializationThe main entry point to dropbear functionality is the function
cyg_dropbear_init. This should be called by the
application when the dropbear code can start running, any time after
the network connection has been activated. It takes a single argument, a
pointer to a cyg_dropbear_data data
structure. That structure should be filled in by the application with
information needed by the dropbear code, including pointers to various
callback functions.
typedef struct cyg_dropbear_data {
const char* db_rsa_private_host_key;
int db_rsa_private_host_keylen;
const char* db_dss_private_host_key;
int db_dss_private_host_keylen;
cyg_bool (*db_accept_connection)(struct sockaddr_storage*);
void (*db_connected)(int, cyg_dropbear_handle);
void (*db_get_public_keys)(char*, char*,
struct sockaddr_storage*, char **);
void (*db_free_public_keys)(char**);
cyg_bool (*db_authenticate_password)(char*,
struct sockaddr_storage *, char*);
void (*db_logger)(const char*, va_list);
} cyg_dropbear_data;
|
The cyg_dropbear_data structure will
be accessed regularly by the dropbear code so must not be overwritten
or freed by the application. Typically it will be statically allocated.
The initialization function will start the main dropbear thread,
running at configurable priority
CYGNUM_NET_DROPBEAR_THREAD_PRI. This thread will
initialize the dropbear package. It will then bind to the desired
TCP/IP port on address INADDR_ANY. The default port
is 22 as per ssh but this can be changed via
CYGNUM_NET_DROPBEAR_NETWORK_PORT. The thread will
accept new connections from remote clients and start a separate worker
thread for each connection, again running at priority
CYGNUM_NET_DROPBEAR_THREAD_PRI. Usually the main
dropbear thread will also assist with setting up the local connection.
cyg_dropbear_init will return once the main
thread has been started.
Host KeysAs an ssh daemon the dropbear code requires a private host key. This
can be either a DSS key or an RSA key, but preferably both should be
supplied. Private keys can be generated using the
dropbearkey host utility. The host key is used
primarily by clients to uniquely identify a given machine, in
conjunction with an ssh known_hosts file.
The application should supply one or two host keys via the
db_rsa_private_host_key,
db_rsa_private_host_keylen,
db_dss_private_host_key and
db_dss_private_host_keylen fields of the
cyg_dropbear_data structure passed to
cyg_dropbear_init.
Conventional ssh usage dictates that all units should have unique
private host keys. That implies that the host keys should be held in a
file system or in non-volatile flash memory and customized on a
per-unit basis. Generating new host keys on startup is undesirable
because it would result in different keys after every reboot,
defeating the purpose of the known_hosts file. In
practice it may be acceptable to use a single set of host keys for all
units, but it is up to the application developer to consider the
security implications.
New Connections CallbackWhen the main dropbear thread accepts a new ssh connection from the
network it will start a new worker thread to handle that connection.
Before any data is exchanged over the TCP/IP socket the worker thread
will call back into the application so that the latter can decide
whether or not a new connection should be accepted at this time.
cyg_bool
application_accept_connection_callback(struct sockaddr_storage* addr)
{
…
}
|
A pointer to this callback function should be stored in the
db_accept_connection field of the
cyg_dropbear_data structure passed to
cyg_dropbear_init. The callback's argument is the
address of the connecting client. Typically this will be an IPv4
sockaddr_in address but the
ss_family field of the
sockaddr_storage structure should be checked.
The client's address can be used to restrict incoming connections to
certain networks or even to individual hosts. This offers some
increase security along similar lines to a firewall, albeit only for
ssh traffic, but it may cause problems in future if it ever becomes
necessary to access the unit from a different network or host.
Another common use for the new connections callback is to limit the
number of concurrent connections, and thus limit the resources
consumed. To facilitate this the dropbear code exports an integer
cyg_dropbear_connections which holds the current
number of client connections.
The callback should return zero if the new connection should be
declined, non-zero if the dropbear code should proceed with key
exchange and authentication.
The use of a new connection callback is optional. If the application
does not want to perform any checks at this time then it can use a
NULL pointer for the db_accept_connection
field.
Key Authentication CallbackAfter the new connections callback the dropbear worker thread will
engage in a key exchange with the client. This allows the client to
verify information in the known_hosts file with
the daemon's private host key or keys. The exchange also involves
negotiating a mutually acceptable encryption protocol and deciding
what user authentication mechanisms are supported. The dropbear daemon
supports public/private key authentication and password
authentication.
For public/private key authentication the client will generate a
message using the private key, and the daemon can validate this
message using the public key. In a conventional ssh setup the public
keys come from a file ~/.ssh/authorized_keys or
~/.ssh/authorized_keys2, but the eCos dropbear
port does not assume the presence of a file system. Instead it is the
application's responsibility to provide the public keys, and a
callback mechanism is used.
void
application_get_public_keys(char* algo,
char* username,
struct sockaddr_storage* addr,
char** keys)
{
…
}
void
application_free_public_keys(char** keys)
{
…
}
|
Pointers to these callback functions should be stored in the
db_get_public_keys and
db_free_public_keys fields of the
cyg_dropbear_data structure passed to
cyg_dropbear_init. The first argument to the
get_public_keys callback identifies the type of key, usually
ssh-dss or ssh-rsa. The second
and third arguments supply the user name and the client's network
address. Together these three arguments can be used to restrict which
public keys are supplied to the dropbear code for validation. Strictly
this is optional since the public keys for e.g. a different user are
not going to match anyway, but the validation requires significant cpu
cycles.
The fourth argument points at a static array of up to
CYGNUM_NET_DROPBEAR_MAXIMUM_PUBLIC_KEYS entries.
This array will be initialized to NULL pointers. The get_public_keys
callback should fill in zero or more array entries with pointers to
public key strings. These strings may be statically or dynamically
allocated. If the latter, the free_public_keys callback will be
invoked to release the memory when the validation has finished.
Within the dropbear code a mutex is used to ensure that only one
worker thread at a time will attempt public key authentication. Hence
the callback functions can assume that there will be only one call to
get_public_keys at a time and that free_public_keys will be called
before the next get_public_keys. This allows the callbacks to use
static data with no need for additional locking.
Support for public/private key authentication is optional. If the
application is only interested in password authentication then it can
use a NULL pointer for the
db_get_public_keys field. If all public
keys are statically allocated then a NULL pointer can be used for
db_free_public_keys field.
Password Authentication CallbackIf public/private key authentication fails then the dropbear code can
support password authentication instead. The ssh client will encrypt
the password before sending it over the wires. The dropbear code will
decrypt it and will pass the plain text password to an application
callback for verification.
cyg_bool
application_authenticate_password(char* username,
struct sockaddr_storage* addr,
char* password)
{
…
}
|
A pointer to this callback function should be stored in the
db_authenticate_password field of the
cyg_dropbear_data structure passed to
cyg_dropbear_init.
It is up to the application developer to decide how to validate the
password. A very simple approach would just involve comparing it with
a constant string. However that approach is not very secure: if there
is any way to read the unit's memory directly, for example via jtag
debug hardware, then it will be possible to extract the password
directly from memory. A more advanced approach would involve
encryption, for example using much the same techniques as for a Unix
/etc/passwd file.
Support for password authentication is optional and can be disabled
simply by not supplying the callback function.
Connected CallbackIn a conventional ssh environment, once authentication has succeeded
the daemon will open a pseudo tty, fork a new process, and start a
shell running in that process. eCos does not have pseudo ttys,
processes, or shells, so a different approach is needed. The dropbear
worker thread for this ssh session will establish a local socket
connection and will pass this socket on to the application. Encrypted
data coming from the network will be decrypted by the dropbear worker
thread and then sent down the local socket to the application. When
the application writes plain text data down the local socket the
dropbear worker thread will read it, encrypt it, and sent it to the
ssh client over the network. As far as the application is concerned it
can just read and
write data via the local socket, and it need not
concern itself with ssh protocols or encryption. Other standard
network programming techniques such as select can
be used as desired.
To inform the application that authentication has succeeded and that
the local socket connection has been established, the dropbear code
will invoke another callback function:
void
application_connected(int socket, cyg_dropbear_handle handle)
{
…
}
|
A pointer to this function should be placed in the
db_connected field of the
cyg_dropbear_data structure passed to
cyg_dropbear_init. The first argument is a file
descriptor for the local socket, for use by the application code.
The second argument is a handle that can be used to get additional
information about the connection, and that must be used to shut down
the connection.
The connected callback runs from inside the main dropbear thread. It
should not run the relevant application code directly, since that
would prevent the dropbear code from accepting any new ssh
connections. Instead the callback should arrange for some other part
of the application to handle traffic for this connection. This can be
done in various ways, for example by waking up an existing thread,
creating a new one, or adding the socket file descriptor to an
fd_set structure which gets monitored
elsewhere in the application.
The socket passed to the connected callback is still an ordinary
blocking socket, but can be turned into a non-blocking socket if
desired using the standard FIONBIO
ioctl. In the absence of pseudo tty support the
socket provides raw terminal functionality. Typically input will
appear a character at a time rather than a line at a time, and any
line editing functionality has to be supplied by the application.
It is also up to the application to implement carriage return/linefeed
processing, to handle special input characters like ctrl-C or ctrl-D,
and so on.
Strictly the use of the connected callback is optional. Application
developers can choose to accept the local socket connection in their
own code rather than leave it to the main dropbear thread, as that may
make it easier to port existing code. It is still necessary to obtain
the cyg_dropbear_handle so that the
connection can be closed down correctly. The hangman example program
illustrates how to do this.
stderr channel
By default the dropbear code only sets up stdin and stdout channels.
If a stderr channel is needed as well then the configuration option
CYGIMP_NET_DROPBEAR_SUPPORT_STDERR should be
enabled. An additional function
cyg_dropbear_get_stderr then becomes available.
This function should be called only from the connected callback. It
returns a file descriptor for a new local socket which can be used for
stderr output, or -1 if the system has run out of sockets or file
descriptors.
Use of cyg_dropbear_get_stderr is optional, so
applications can decide on a per-connection basis whether or not a
stderr channel is needed.
Connection InformationOnce a connection has been established and the connected callback has
been invoked, application code can retrieve some additional
information about this connection.
cyg_dropbear_get_username will provide the user
name supplied during authentication, and
cyg_dropbear_get_addr will return the network
address of the ssh client.
Closing ConnectionAn ssh connection can be shut down in one of two ways. If the client
is terminated then the eCos application will detect an end of file
condition on the local socket and can close its end of the connection.
Alternatively the eCos application can decide to close its end
unilaterally. Either way closing the connection involves two steps.
The close system call should be used on the file
descriptor for the local socket, and on the one for the stderr socket
if cyg_dropbear_get_stderr has been used. Next
cyg_dropbear_done should be invoked using the
cyg_dropbear_handle provided by the connected
callback. Calling cyg_dropbear_done is analogous
to the shell process exiting in a conventional ssh environment. The
second argument corresponds to the exit code of that process, so a
value of 0 indicates no error. The
cyg_dropbear_handle ceases to be valid during
the call to cyg_dropbear_done so the application
must ensure the handle will not be used concurrently by another thread
or after the done call.
Note: If cyg_dropbear_done is not called when closing
down an ssh connection then the dropbear worker thread associated with
that connection will never terminate, and any resources allocated will
not be released. If this happens repeatedly then the system will run
out of memory and fail.
Logging CallbackThe dropbear code includes support for logging various events. In a
conventional ssh environment these log messages will end up in the
system log files, but when running under eCos that approach is usually
inappropriate. Instead by default the log messages will just be
discarded, but if desired the application can capture the messages by
installing a logging callback in the
db_logger field of the
cyg_dropbear_data structure:
void
application_logger(char* format, va_list args)
{
…
}
|
ConfigurationThe eCos dropbear port is intended to work in conjunction with the
full BSD TCP/IP package and has numerous dependencies. Most of these
can be satisfied simply by creating the eCos configuration using the
net template. The dropbear package has additional dependencies on the
LibTomMath multi-precision arithmetic package
CYGPKG_MATH_LIBTOMMATH and the LibTomCrypt
cryptography library CYGPKG_CRYPT_LIBTOMCRYPT, so
those packages will have to be added explicitly to the configuration
alongside CYGPKG_NET_DROPBEAR. The dropbear package
provides a number of additional configuration options.
CYGIMP_NET_DROPBEAR_SUPPORT_STDERRWhen a new secure connection is established, by default the dropbear
code only provides stdin and stdout channels. If this option is enabled
then application code can also request a stderr channel for certain
connections. This consumes one extra file descriptor allocated during
initialization, plus another two file descriptors for every connection
that uses stderr.
CYGNUM_NET_DROPBEAR_MAX_PAYLOAD_LENWhile establishing a secure connection the client and daemon negotiate
an upper limit for the packet size. This has to be large enough to
cope with the initial key exchange and related information. For eCos
the default size is set to 1K, which should be sufficient but is still
rather smaller than the dropbear default on other platforms. If the
application involves transferring large amounts of data over ssh then
throughput may be improved by increasing this packet size, at the cost
of increased memory usage.
CYGNUM_NET_DROPBEAR_MAXIMUM_PUBLIC_KEYSDuring the authentication phase the dropbear code may invoke a
get_public_keys callback function provided by the application. One of
the arguments to that function is a fixed-size array of pointers to
public key strings. This configuration option determines the size of
that array, and has a default value of 8. If for some reason the
application supports large numbers of public keys then it may be
necessary to increase this setting.
CYGNUM_NET_DROPBEAR_NETWORK_PORTBy default the dropbear main thread listens on port 22, the standard
TCP/IP port for ssh. An alternative network port can be specified if
desired. This provides a rather limited amount of protection against
network attacks which attempt to connect directly to the ssh port,
but will be of no use against a determined attack. Using a
non-standard port will also be an inconvenience on the client side:
the user has to either specify the port number on the command line or
modify a configuration file such as ~/.ssh/config.
CYGNUM_NET_DROPBEAR_LOCAL_PORTThis configuration option controls the TCP/IP port used to establish
the local socket for each ssh connection.
CYGNUM_NET_DROPBEAR_STDERR_PORTThis configuration option controls the TCP/IP port used to establish
the stderr socket during a call to
cyg_dropbear_get_stderr.
CYGNUM_NET_DROPBEAR_THREAD_PRIThe dropbear package involves one thread started by
cyg_dropbear_init plus additional worker threads,
one per ssh connection. These threads all run at the same priority,
controlled by this configuration option. The ssh protocol involves
computationally intensive operations such as encrypting and decrypting
packets, so these threads may have a significiant impact on the
number of cpu cycles available to the rest of the system. It may be
necessary to manipulate the thread priority to achieve an acceptable
balance between overall system performance and the achievable ssh
bandwidth.
CYGNUM_NET_DROPBEAR_THREAD_STACKSIZEThis configuration option controls the size of the stacks allocated
for the main dropbear thread and for each worker thread. Fairly large
stacks are needed to implement the ssh protocol, and in addition the
various application callback functions will also run on these stacks.
The default value should suffice for all architectures, but this can
be checked by using a debug build with stack checking enabled. If the
stack sizes are reduced to save memory then it is strongly recommended
that the system be tested with stack checking enabled.
CYGNUM_NET_DROPBEAR_CONNECTION_DELAYThe main dropbear thread can delay for a configurable number of system
clock ticks between accepting each ssh connection from the network.
This provides a limited amount of protection against denial of service
attacks, especially when used in conjunction with an accept_connection
callback function which limits the number of open connections.
Obviously if the eCos system is the target of a denial of service
attack then it will still be very hard for legitimate users to get
ssh access to the unit, but there is an increased chance that the unit
will continue operating rather than run out of resources and fail.
CYGNUM_NET_DROPBEAR_RETRY_DELAYWithin the main dropbear code, if the system runs out of resources and
for example a malloc call fails then this is
treated as a serious failure and the ssh connection should get shut
down, which will release resources back to the system. Where
appropriate some of the eCos-specific code will instead sleep for a
while and then retry, in the hope that other parts of the system have
released sufficient resources during the delay. This configuration
option specifies the number of system clock ticks that should be spent
sleeping before retrying.
A further three configuration options in other packages may have a
significant impact on the behaviour of the dropbear code. The dropbear
code involves a fixed overhead of two sockets, one for the network
port and one for the local port, plus an additional three sockets for
each ssh connection, one for the network side and two locally. If
stderr support is enabled then there is an additional fixed overhead
of another socket plus another two sockets for each connection.
Depending on how many concurrent ssh connections the application is
expected to support it may be necessary to increase the limits on the
number of file descriptors and sockets, controlled by
CYGNUM_FILEIO_NFILE and
CYGPKG_NET_MAXSOCKETS respectively. If C library
stdio functions are used then FOPEN_MAX may also
need to be increased. If the system runs out of sockets or file
descriptors when a client attempts to establish a new connection,
this will normally be detected and the connection will be shut down
immediately. However there are edge and race conditions which may
cause the client to hang until a timeout occurs.
PortPorting dropbear to eCos involved non-trivial modifications to the
source code. The package's src
subdirectory corresponds to the contents of a standard dropbear
tarball. New files ecosmain.c,
ecos.h and config.h have
been added, and various existing files have had to be modified. A CDL
script, documentation and an example application have been added to
the appropriate package subdirectories, and a new header dropbear.h has been written to export
the API provided by the eCos port.
|
|
|
| |
|
|
|
|
|