Commit 709a3e75 authored by Matt Johnston's avatar Matt Johnston
Browse files

propagate from branch 'au.asn.ucc.matt.dropbear' (head 899a8851a5edf840b2f7925bcc26ffe99dcac54d)

            to branch 'au.asn.ucc.matt.dropbear.cli-agent' (head 6bbab8364de17bd9ecb1dee5ffb796e48c0380d2)

--HG--
branch : agent-client
extra : convert_revision : d39a49137cc36b624768d4e79e564141dde8d355
parents e674c73e cb82c6e3
0.52 - Wed 12 November 2008
- Add "netcat-alike" option (-B) to dbclient, allowing Dropbear to tunnel
standard input/output to a TCP port-forwarded remote host.
- Add "proxy command" support to dbclient, to allow using a spawned process for
IO rather than a direct TCP connection. eg
dbclient remotehost
is equivalent to
dbclient -J 'nc remotehost 22' remotehost
(the hostname is still provided purely for looking up saved host keys)
- Combine netcat-alike and proxy support to allow "multihop" connections, with
comma-separated host syntax. Allows running
dbclient [email protected],[email protected],[email protected]
to end up at host3 via the other two, using SSH TCP forwarding. It's a bit
like onion-routing. All connections are established from the local machine.
The comma-separated syntax can also be used for scp/rsync, eg
rsync -a -e dbclient [email protected],[email protected],martello:/home/matt/ ~/backup/
to bounce through a few hosts.
- Add -I "idle timeout" option (contributed by Farrell Aultman)
- Allow restrictions on authorized_keys logins such as restricting commands
to be run etc. This is a subset of those allowed by OpenSSH, doesn't
yet allow restricting source host.
- Use vfork() for scp on uClinux
- Default to PATH=/usr/bin:/bin for shells.
- Report errors if -R forwarding fails
- Add counter mode cipher support, which avoids some security problems with the
standard CBC mode.
- Support [email protected] delayed compression for client/server. It can be
required for the Dropbear server with the '-Z' option. This is useful for
security as it avoids exposing the server to attacks on zlib by
unauthenticated remote users, though requires client side support.
- options.h has been split into options.h (user-changable) and sysoptions.h
(less commonly changed)
- Support "dbclient -s sftp" to specify a subsystem
- Fix a bug in replies to channel requests that could be triggered by recent
versions of PuTTY
0.51 - Thu 27 March 2008
- Make a copy of password fields rather erroneously relying on getwpnam()
......
......@@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below.
Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
same license:
Copyright (c) 2002-2006 Matt Johnston
Copyright (c) 2002-2008 Matt Johnston
Portions copyright (c) 2004 Mihnea Stoenescu
All rights reserved.
......
......@@ -25,7 +25,7 @@ COMMONOBJS=dbutil.o buffer.o \
SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
svr-tcpfwd.o svr-authpam.o
svr-tcpfwd.o svr-authpam.o @[email protected]
CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
cli-session.o cli-service.o cli-runopts.o cli-chansession.o \
......
......@@ -29,13 +29,18 @@
#include "includes.h"
#include "buffer.h"
#define DROPBEAR_MODE_UNUSED 0
#define DROPBEAR_MODE_CBC 1
#define DROPBEAR_MODE_CTR 2
struct Algo_Type {
unsigned char *name; /* identifying name */
char val; /* a value for this cipher, or -1 for invalid */
void *data; /* algorithm specific data */
unsigned usable : 1; /* whether we can use this algorithm */
const void *data; /* algorithm specific data */
char usable; /* whether we can use this algorithm */
const void *mode; /* the mode, currently only used for ciphers,
points to a 'struct dropbear_cipher_mode' */
};
typedef struct Algo_Type algo_type;
......@@ -48,6 +53,7 @@ extern algo_type sshhashes[];
extern algo_type sshcompress[];
extern const struct dropbear_cipher dropbear_nocipher;
extern const struct dropbear_cipher_mode dropbear_mode_none;
extern const struct dropbear_hash dropbear_nohash;
struct dropbear_cipher {
......@@ -56,6 +62,16 @@ struct dropbear_cipher {
unsigned char blocksize;
};
struct dropbear_cipher_mode {
int (*start)(int cipher, const unsigned char *IV,
const unsigned char *key,
int keylen, int num_rounds, void *cipher_state);
int (*encrypt)(const unsigned char *pt, unsigned char *ct,
unsigned long len, void *cipher_state);
int (*decrypt)(const unsigned char *ct, unsigned char *pt,
unsigned long len, void *cipher_state);
};
struct dropbear_hash {
const struct ltc_hash_descriptor *hashdesc;
unsigned long keysize;
......
......@@ -135,7 +135,8 @@ struct SignKeyList {
int type; /* The type of key */
struct SignKeyList *next;
int source;
/* filename? or the buffer? for encrypted keys, so we can later get
char *filename;
/* the buffer? for encrypted keys, so we can later get
* the private key portion */
};
......
......@@ -91,7 +91,7 @@ void recv_msg_userauth_banner() {
}
}
printf("%s\n", banner);
fprintf(stderr, "%s\n", banner);
out:
m_free(banner);
......@@ -229,6 +229,8 @@ void recv_msg_userauth_failure() {
void recv_msg_userauth_success() {
TRACE(("received msg_userauth_success"))
/* Note: in delayed-zlib mode, setting authdone here
* will enable compression in the transport layer */
ses.authstate.authdone = 1;
cli_ses.state = USERAUTH_SUCCESS_RCVD;
cli_ses.lastauthtype = AUTH_TYPE_NONE;
......
......@@ -53,6 +53,7 @@ void cli_pubkeyfail() {
}
sign_key_free(cli_ses.lastprivkey->key); /* It won't be used again */
m_free(cli_ses.lastprivkey->filename);
m_free(cli_ses.lastprivkey);
TRACE(("leave cli_pubkeyfail"))
......
......@@ -327,4 +327,5 @@ out:
if (line != NULL) {
buf_free(line);
}
m_free(fingerprint);
}
......@@ -32,7 +32,9 @@
static void cli_dropbear_exit(int exitcode, const char* format, va_list param);
static void cli_dropbear_log(int priority, const char* format, va_list param);
#ifdef ENABLE_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out);
#endif
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
......@@ -63,6 +65,7 @@ int main(int argc, char ** argv) {
#ifdef ENABLE_CLI_PROXYCMD
if (cli_opts.proxycmd) {
cli_proxy_cmd(&sock_in, &sock_out);
m_free(cli_opts.proxycmd);
} else
#endif
{
......@@ -132,6 +135,7 @@ static void exec_proxy_cmd(void *user_data_cmd) {
dropbear_exit("Failed to run '%s'\n", cmd);
}
#ifdef ENABLE_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out) {
int ret;
......@@ -144,3 +148,4 @@ static void cli_proxy_cmd(int *sock_in, int *sock_out) {
*sock_in = *sock_out = -1;
}
}
#endif // ENABLE_CLI_PROXYCMD
......@@ -49,7 +49,11 @@ static void add_netcat(const char *str);
static void printhelp() {
fprintf(stderr, "Dropbear client v%s\n"
#ifdef ENABLE_CLI_MULTIHOP
"Usage: %s [options] [[email protected]]host[/port][,[[email protected]]host/port],...] [command]\n"
#else
"Usage: %s [options] [[email protected]]host[/port] [command]\n"
#endif
"Options are:\n"
"-p <remoteport>\n"
"-l <username>\n"
......@@ -74,22 +78,22 @@ static void printhelp() {
#endif
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
"-K <keepalive> (0 is never, default %d)\n"
"-I <idle_timeout> (0 is never, default %d)\n"
#ifdef ENABLE_CLI_NETCAT
"-B <endhost:endport> Netcat-alike bouncing\n"
"-B <endhost:endport> Netcat-alike forwarding\n"
#endif
#ifdef ENABLE_CLI_PROXYCMD
"-J <proxy_program> Use program rather than tcp connection\n"
"-J <proxy_program> Use program pipe rather than TCP connection\n"
#endif
#ifdef DEBUG_TRACE
"-v verbose\n"
"-v verbose (compiled with DEBUG_TRACE)\n"
#endif
,DROPBEAR_VERSION, cli_opts.progname,
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE);
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
}
void cli_getopts(int argc, char ** argv) {
unsigned int i, j;
char ** next = 0;
unsigned int cmdlen;
......@@ -109,6 +113,8 @@ void cli_getopts(int argc, char ** argv) {
char* recv_window_arg = NULL;
char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL;
char *host_arg = NULL;
/* see printhelp() for options */
cli_opts.progname = argv[0];
......@@ -264,6 +270,9 @@ void cli_getopts(int argc, char ** argv) {
case 'K':
next = &keepalive_arg;
break;
case 'I':
next = &idle_timeout_arg;
break;
#ifdef ENABLE_CLI_AGENTFWD
case 'A':
cli_opts.agent_fwd = 1;
......@@ -307,12 +316,8 @@ void cli_getopts(int argc, char ** argv) {
/* Either the hostname or commands */
if (cli_opts.remotehost == NULL) {
#ifdef ENABLE_CLI_MULTIHOP
parse_multihop_hostname(argv[i], argv[0]);
#else
parse_hostname(argv[i]);
#endif
if (host_arg == NULL) {
host_arg = argv[i];
} else {
/* this is part of the commands to send - after this we
......@@ -341,7 +346,7 @@ void cli_getopts(int argc, char ** argv) {
/* And now a few sanity checks and setup */
if (cli_opts.remotehost == NULL) {
if (host_arg == NULL) {
printhelp();
exit(EXIT_FAILURE);
}
......@@ -377,12 +382,26 @@ void cli_getopts(int argc, char ** argv) {
}
}
if (idle_timeout_arg) {
if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
}
}
#ifdef ENABLE_CLI_NETCAT
if (cli_opts.cmd && cli_opts.netcat_host) {
dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
}
#endif
/* The hostname gets set up last, since
* in multi-hop mode it will require knowledge
* of other flags such as -i */
#ifdef ENABLE_CLI_MULTIHOP
parse_multihop_hostname(host_arg, argv[0]);
#else
parse_hostname(host_arg);
#endif
}
#ifdef ENABLE_CLI_PUBKEY_AUTH
......@@ -395,14 +414,12 @@ static void loadidentityfile(const char* filename) {
key = new_sign_key();
keytype = DROPBEAR_SIGNKEY_ANY;
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
sign_key_free(key);
} else {
nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList));
nextkey->key = key;
nextkey->filename = m_strdup(filename);
nextkey->next = cli_opts.privkeys;
nextkey->type = keytype;
nextkey->source = SIGNKEY_SOURCE_RAW_FILE;
......@@ -413,6 +430,39 @@ static void loadidentityfile(const char* filename) {
#ifdef ENABLE_CLI_MULTIHOP
static char*
multihop_passthrough_args() {
char *ret;
int total;
unsigned int len = 0;
struct SignKeyList *nextkey;
/* Fill out -i and -W options that make sense for all
* the intermediate processes */
for (nextkey = cli_opts.privkeys; nextkey; nextkey = nextkey->next)
{
len += 3 + strlen(nextkey->filename);
}
len += 20; // space for -W <size>, terminator.
ret = m_malloc(len);
total = 0;
if (opts.recv_window != DEFAULT_RECV_WINDOW)
{
int written = snprintf(ret+total, len-total, "-W %d", opts.recv_window);
total += written;
}
for (nextkey = cli_opts.privkeys; nextkey; nextkey = nextkey->next)
{
const size_t size = len - total;
int written = snprintf(ret+total, size, "-i %s", nextkey->filename);
dropbear_assert(written < size);
total += written;
}
return ret;
}
/* Sets up 'onion-forwarding' connections. This will spawn
* a separate dbclient process for each hop.
* As an example, if the cmdline is
......@@ -427,6 +477,7 @@ static void loadidentityfile(const char* filename) {
*/
static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
char *userhostarg = NULL;
char *hostbuf = NULL;
char *last_hop = NULL;;
char *remainder = NULL;
......@@ -439,11 +490,12 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
&& strchr(cli_opts.username, ',')
&& strchr(cli_opts.username, '@')) {
unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
userhostarg = m_malloc(len);
snprintf(userhostarg, len, "%[email protected]%s", cli_opts.username, orighostarg);
hostbuf = m_malloc(len);
snprintf(hostbuf, len, "%[email protected]%s", cli_opts.username, orighostarg);
} else {
userhostarg = m_strdup(orighostarg);
hostbuf = m_strdup(orighostarg);
}
userhostarg = hostbuf;
last_hop = strrchr(userhostarg, ',');
if (last_hop) {
......@@ -461,19 +513,24 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
if (last_hop) {
/* Set up the proxycmd */
unsigned int cmd_len = 0;
char *passthrough_args = multihop_passthrough_args();
if (cli_opts.proxycmd) {
dropbear_exit("-J can't be used with multihop mode");
}
if (cli_opts.remoteport == NULL) {
cli_opts.remoteport = "22";
}
cmd_len = strlen(remainder)
cmd_len = strlen(argv0) + strlen(remainder)
+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
+ strlen(argv0) + 30;
+ strlen(passthrough_args)
+ 30;
cli_opts.proxycmd = m_malloc(cmd_len);
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport, remainder);
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport,
passthrough_args, remainder);
m_free(passthrough_args);
}
m_free(hostbuf);
}
#endif /* !ENABLE_CLI_MULTIHOP */
......@@ -622,6 +679,7 @@ static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
goto badport;
}
newfwd->have_reply = 0;
newfwd->next = *fwdlist;
*fwdlist = newfwd;
......
......@@ -64,6 +64,10 @@ static const packettype cli_packettypes[] = {
{SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
{SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */
{SSH_MSG_USERAUTH_SPECIFIC_60, recv_msg_userauth_specific_60}, /* client */
#ifdef ENABLE_CLI_REMOTETCPFWD
{SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */
{SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */
#endif
{0, 0} /* End */
};
......
......@@ -128,7 +128,7 @@ static void send_msg_global_request_remotetcp(int port) {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
buf_putstring(ses.writepayload, "tcpip-forward", 13);
buf_putbyte(ses.writepayload, 0);
buf_putbyte(ses.writepayload, 1); /* want_reply */
if (opts.listen_fwd_all) {
listenspec = "";
} else {
......@@ -143,6 +143,42 @@ static void send_msg_global_request_remotetcp(int port) {
TRACE(("leave send_msg_global_request_remotetcp"))
}
/* The only global success/failure messages are for remotetcp.
* Since there isn't any identifier in these messages, we have to rely on them
* being in the same order as we sent the requests. This is the ordering
* of the cli_opts.remotefwds list */
void cli_recv_msg_request_success() {
/* Nothing in the packet. We just mark off that we have received the reply,
* so that we can report failure for later ones. */
struct TCPFwdList * iter = NULL;
iter = cli_opts.remotefwds;
while (iter != NULL) {
if (!iter->have_reply)
{
iter->have_reply = 1;
return;
}
iter = iter->next;
}
}
void cli_recv_msg_request_failure() {
struct TCPFwdList * iter = NULL;
iter = cli_opts.remotefwds;
while (iter != NULL) {
if (!iter->have_reply)
{
iter->have_reply = 1;
dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", iter->listenport, iter->connectaddr, iter->connectport);
return;
}
iter = iter->next;
}
}
void setup_remotetcp() {
struct TCPFwdList * iter = NULL;
......
......@@ -29,32 +29,46 @@
/* This file (algo.c) organises the ciphers which can be used, and is used to
* decide which ciphers/hashes/compression/signing to use during key exchange*/
static int void_cipher(const unsigned char* in, unsigned char* out,
unsigned long len, void *cipher_state) {
if (in != out) {
memmove(out, in, len);
}
return CRYPT_OK;
}
static int void_start(int cipher, const unsigned char *IV,
const unsigned char *key,
int keylen, int num_rounds, void *cipher_state) {
return CRYPT_OK;
}
/* Mappings for ciphers, parameters are
{&cipher_desc, keysize, blocksize} */
/* NOTE: if keysize > 2*SHA1_HASH_SIZE, code such as hashkeys()
needs revisiting */
#ifdef DROPBEAR_AES256_CBC
#ifdef DROPBEAR_AES256
static const struct dropbear_cipher dropbear_aes256 =
{&aes_desc, 32, 16};
#endif
#ifdef DROPBEAR_AES128_CBC
#ifdef DROPBEAR_AES128
static const struct dropbear_cipher dropbear_aes128 =
{&aes_desc, 16, 16};
#endif
#ifdef DROPBEAR_BLOWFISH_CBC
#ifdef DROPBEAR_BLOWFISH
static const struct dropbear_cipher dropbear_blowfish =
{&blowfish_desc, 16, 8};
#endif
#ifdef DROPBEAR_TWOFISH256_CBC
#ifdef DROPBEAR_TWOFISH256
static const struct dropbear_cipher dropbear_twofish256 =
{&twofish_desc, 32, 16};
#endif
#ifdef DROPBEAR_TWOFISH128_CBC
#ifdef DROPBEAR_TWOFISH128
static const struct dropbear_cipher dropbear_twofish128 =
{&twofish_desc, 16, 16};
#endif
#ifdef DROPBEAR_3DES_CBC
#ifdef DROPBEAR_3DES
static const struct dropbear_cipher dropbear_3des =
{&des3_desc, 24, 8};
#endif
......@@ -63,6 +77,24 @@ static const struct dropbear_cipher dropbear_3des =
const struct dropbear_cipher dropbear_nocipher =
{NULL, 16, 8};
/* A few void* s are required to silence warnings
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
const struct dropbear_cipher_mode dropbear_mode_cbc =
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
const struct dropbear_cipher_mode dropbear_mode_none =
{void_start, void_cipher, void_cipher};
#ifdef DROPBEAR_ENABLE_CTR_MODE
/* a wrapper to make ctr_start and cbc_start look the same */
static int dropbear_big_endian_ctr_start(int cipher,
const unsigned char *IV,
const unsigned char *key, int keylen,
int num_rounds, symmetric_CTR *ctr) {
return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
}
const struct dropbear_cipher_mode dropbear_mode_ctr =
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
#endif
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
{&hash_desc, keysize, hashsize} */
......@@ -83,65 +115,81 @@ const struct dropbear_hash dropbear_nohash =
{NULL, 16, 0}; /* used initially */
/* The following map ssh names to internal values */
/* The following map ssh names to internal values.
* The ordering here is important for the client - the first mode
* that is also supported by the server will get used. */
algo_type sshciphers[] = {
#ifdef DROPBEAR_AES128_CBC
{"aes128-cbc", 0, (void*)&dropbear_aes128, 1},
#ifdef DROPBEAR_ENABLE_CTR_MODE
#ifdef DROPBEAR_AES128
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_3DES
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_AES256
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
#endif
#endif /* DROPBEAR_ENABLE_CTR_MODE */
/* CBC modes are always enabled */
#ifdef DROPBEAR_AES128
{"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_3DES_CBC
{"3des-cbc", 0, (void*)&dropbear_3des, 1},
#ifdef DROPBEAR_3DES
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_AES256_CBC
{"aes256-cbc", 0, (void*)&dropbear_aes256, 1},
#ifdef DROPBEAR_AES256
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_TWOFISH256_CBC
{"twofish256-cbc", 0, (void*)&dropbear_twofish256, 1},
{"twofish-cbc", 0, (void*)&dropbear_twofish256, 1},
#ifdef DROPBEAR_TWOFISH256
{"twofish256-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
{"twofish-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_TWOFISH128_CBC
{"twofish128-cbc", 0, (void*)&dropbear_twofish128, 1},
#ifdef DROPBEAR_TWOFISH128
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_BLOWFISH_CBC
{"blowfish-cbc", 0, (void*)&dropbear_blowfish, 1},
#ifdef DROPBEAR_BLOWFISH
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
#endif
{NULL, 0, NULL, 0}
{NULL, 0, NULL, 0, NULL}
};
algo_type sshhashes[] = {
#ifdef DROPBEAR_SHA1_96_HMAC
{"hmac-sha1-96", 0, (void*)&dropbear_sha1_96, 1},
{"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
#endif
#ifdef DROPBEAR_SHA1_HMAC
{"hmac-sha1", 0, (void*)&dropbear_sha1, 1},
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
#endif
#ifdef DROPBEAR_MD5_HMAC
{"hmac-md5", 0, (void*)&dropbear_md5, 1},
{"hmac-md5", 0, &dropbear_md5, 1, NULL},
#endif