mirror of
https://github.com/clearml/dropbear
synced 2025-03-03 02:31:35 +00:00
ext-info handling for server-sig-algs
only client side is handled
This commit is contained in:
parent
972d723484
commit
5acee497bf
11
algo.h
11
algo.h
@ -114,18 +114,11 @@ struct dropbear_kex {
|
||||
|
||||
void buf_put_algolist(buffer * buf, const algo_type localalgos[]);
|
||||
|
||||
enum kexguess2_used {
|
||||
KEXGUESS2_LOOK,
|
||||
KEXGUESS2_NO,
|
||||
KEXGUESS2_YES,
|
||||
};
|
||||
|
||||
#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
|
||||
#define KEXGUESS2_ALGO_ID 99
|
||||
|
||||
|
||||
int buf_has_algo(buffer *buf, const char *algo);
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess);
|
||||
int kexguess2, int *goodguess);
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
int check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
|
22
buffer.c
22
buffer.c
@ -228,19 +228,37 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
}
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
static buffer * buf_getstringbuf_int(buffer *buf, int incllen) {
|
||||
buffer *ret = NULL;
|
||||
unsigned int len = buf_getint(buf);
|
||||
int extra = 0;
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("String too long");
|
||||
}
|
||||
ret = buf_new(len);
|
||||
if (incllen) {
|
||||
extra = 4;
|
||||
}
|
||||
ret = buf_new(len+extra);
|
||||
if (incllen) {
|
||||
buf_putint(ret, len);
|
||||
}
|
||||
memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
|
||||
buf_incrpos(buf, len);
|
||||
buf_incrlen(ret, len);
|
||||
buf_setpos(ret, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
return buf_getstringbuf_int(buf, 0);
|
||||
}
|
||||
|
||||
/* Returns a string in a new buffer, including the length */
|
||||
buffer * buf_getbuf(buffer *buf) {
|
||||
return buf_getstringbuf_int(buf, 1);
|
||||
}
|
||||
|
||||
/* Just increment the buffer position the same as if we'd used buf_getstring,
|
||||
* but don't bother copying/malloc()ing for it */
|
||||
void buf_eatstring(buffer *buf) {
|
||||
|
1
buffer.h
1
buffer.h
@ -58,6 +58,7 @@ unsigned char* buf_getptr(const buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getwriteptr(const buffer* buf, unsigned int len);
|
||||
char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
buffer * buf_getstringbuf(buffer *buf);
|
||||
buffer * buf_getbuf(buffer *buf);
|
||||
void buf_eatstring(buffer *buf);
|
||||
void buf_putint(buffer* buf, unsigned int val);
|
||||
void buf_putstring(buffer* buf, const char* str, unsigned int len);
|
||||
|
@ -184,6 +184,7 @@ static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype,
|
||||
|
||||
/* Returns 1 if a key was tried */
|
||||
int cli_auth_pubkey() {
|
||||
enum signature_type sigtype;
|
||||
TRACE(("enter cli_auth_pubkey"))
|
||||
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
@ -191,28 +192,77 @@ int cli_auth_pubkey() {
|
||||
/* get the list of available keys from the agent */
|
||||
cli_load_agent_keys(cli_opts.privkeys);
|
||||
cli_opts.agent_keys_loaded = 1;
|
||||
TRACE(("cli_auth_pubkey: agent keys loaded"))
|
||||
}
|
||||
#endif
|
||||
|
||||
/* TODO iterate through privkeys to skip ones not in server-sig-algs */
|
||||
|
||||
/* TODO: testing */
|
||||
/* iterate through privkeys to remove ones not allowed in server-sig-algs */
|
||||
while (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
if (cli_ses.server_sig_algs) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
cli_ses.preferred_rsa_sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
|
||||
#elif DROPBEAR_RSA_SHA1
|
||||
cli_ses.preferred_rsa_sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNATURE_RSA_SHA256)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
|
||||
TRACE(("server-sig-algs allows rsa sha256"))
|
||||
break;
|
||||
}
|
||||
#endif /* DROPBEAR_RSA_SHA256 */
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNKEY_RSA)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
TRACE(("server-sig-algs allows rsa sha1"))
|
||||
break;
|
||||
}
|
||||
#endif /* DROPBEAR_RSA_SHA256 */
|
||||
} else
|
||||
#endif /* DROPBEAR_RSA */
|
||||
{
|
||||
/* Not RSA */
|
||||
const char *name = NULL;
|
||||
sigtype = signature_type_from_signkey(key->type);
|
||||
name = signature_name_from_type(sigtype, NULL);
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, name)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
TRACE(("server-sig-algs allows %s", name))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* No match, skip this key */
|
||||
TRACE(("server-sig-algs no match keytype %d, skipping", key->type))
|
||||
key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
continue;
|
||||
} else {
|
||||
/* Server didn't provide a server-sig-algs list, we'll
|
||||
assume all except rsa-sha256 are OK. */
|
||||
#if DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
#ifdef DROPBEAR_RSA_SHA1
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
TRACE(("no server-sig-algs, using rsa sha1"))
|
||||
break;
|
||||
#else
|
||||
/* only support rsa-sha256, skip this key */
|
||||
TRACE(("no server-sig-algs, skipping rsa sha256"))
|
||||
key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
continue;
|
||||
#endif
|
||||
} /* key->type == DROPBEAR_SIGNKEY_RSA */
|
||||
#endif /* DROPBEAR_RSA */
|
||||
sigtype = signature_type_from_signkey(key->type);
|
||||
TRACE(("no server-sig-algs, using key"))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
/* Determine the signature type to use */
|
||||
enum signature_type sigtype = (enum signature_type)key->type;
|
||||
#if DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
sigtype = cli_ses.preferred_rsa_sigtype;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Send a trial request */
|
||||
send_msg_userauth_pubkey(key, sigtype, 0);
|
||||
cli_ses.lastprivkey = key;
|
||||
|
25
cli-kex.c
25
cli-kex.c
@ -411,3 +411,28 @@ out:
|
||||
}
|
||||
m_free(fingerprint);
|
||||
}
|
||||
|
||||
void recv_msg_ext_info(void) {
|
||||
/* This message is not client-specific in the protocol but Dropbear only handles
|
||||
a server-sent message at present. */
|
||||
unsigned int num_ext;
|
||||
unsigned int i;
|
||||
|
||||
num_ext = buf_getint(ses.payload);
|
||||
TRACE(("received SSH_MSG_EXT_INFO with %d items", num_ext))
|
||||
|
||||
for (i = 0; i < num_ext; i++) {
|
||||
unsigned int name_len;
|
||||
char *ext_name = buf_getstring(ses.payload, &name_len);
|
||||
TRACE(("extension %d name '%s'", i, ext_name))
|
||||
if (cli_ses.server_sig_algs == NULL
|
||||
&& name_len == strlen(SSH_SERVER_SIG_ALGS)
|
||||
&& strcmp(ext_name, SSH_SERVER_SIG_ALGS) == 0) {
|
||||
cli_ses.server_sig_algs = buf_getbuf(ses.payload);
|
||||
} else {
|
||||
/* valid extension values could be >MAX_STRING_LEN */
|
||||
buf_eatstring(ses.payload);
|
||||
}
|
||||
m_free(ext_name);
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +106,7 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
|
||||
/* Render the formatted exit message */
|
||||
vsnprintf(exitmsg, sizeof(exitmsg), format, param);
|
||||
TRACE(("Exited, cleaning up: %s", exitmsg))
|
||||
|
||||
/* Add the prefix depending on session/auth state */
|
||||
if (!ses.init_done) {
|
||||
|
@ -81,6 +81,7 @@ static const packettype cli_packettypes[] = {
|
||||
{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
|
||||
{SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
|
||||
#endif
|
||||
{SSH_MSG_EXT_INFO, recv_msg_ext_info},
|
||||
{0, NULL} /* End */
|
||||
};
|
||||
|
||||
@ -352,7 +353,9 @@ static void cli_session_cleanup(void) {
|
||||
(void)fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
|
||||
|
||||
cli_tty_cleanup();
|
||||
|
||||
if (cli_ses.server_sig_algs) {
|
||||
buf_free(cli_ses.server_sig_algs);
|
||||
}
|
||||
}
|
||||
|
||||
static void cli_finished() {
|
||||
|
119
common-algo.c
119
common-algo.c
@ -30,6 +30,7 @@
|
||||
#include "dh_groups.h"
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* 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*/
|
||||
@ -280,6 +281,7 @@ static const struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0
|
||||
static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
|
||||
#endif
|
||||
|
||||
/* data == NULL for non-kex algorithm identifiers */
|
||||
algo_type sshkex[] = {
|
||||
#if DROPBEAR_CURVE25519
|
||||
{"curve25519-sha256", 0, &kex_curve25519, 1, NULL},
|
||||
@ -309,7 +311,11 @@ algo_type sshkex[] = {
|
||||
{"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
|
||||
{KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_CLIENT
|
||||
/* Set unusable by svr_algos_initialise() */
|
||||
{SSH_EXT_INFO_C, 0, NULL, 1, NULL},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
@ -336,15 +342,79 @@ void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
|
||||
buf_free(algolist);
|
||||
}
|
||||
|
||||
/* returns a list of pointers into algolist, of null-terminated names.
|
||||
ret_list should be passed in with space for *ret_count elements,
|
||||
on return *ret_count has the number of names filled.
|
||||
algolist is modified. */
|
||||
static void get_algolist(char* algolist, unsigned int algolist_len,
|
||||
const char* *ret_list, unsigned int *ret_count) {
|
||||
unsigned int max_count = *ret_count;
|
||||
unsigned int i;
|
||||
|
||||
if (*ret_count == 0) {
|
||||
return;
|
||||
}
|
||||
if (algolist_len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
*ret_count = 0;
|
||||
}
|
||||
|
||||
/* ret_list will contain a list of the strings parsed out.
|
||||
We will have at least one string (even if it's just "") */
|
||||
ret_list[0] = algolist;
|
||||
*ret_count = 1;
|
||||
for (i = 0; i < algolist_len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
*ret_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (algolist[i] == ',') {
|
||||
if (*ret_count >= max_count) {
|
||||
/* Too many */
|
||||
*ret_count = 0;
|
||||
return;
|
||||
}
|
||||
algolist[i] = '\0';
|
||||
ret_list[*ret_count] = &algolist[i+1];
|
||||
(*ret_count)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return DROPBEAR_SUCCESS if the namelist contains algo,
|
||||
DROPBEAR_FAILURE otherwise. buf position is not incremented. */
|
||||
int buf_has_algo(buffer *buf, const char *algo) {
|
||||
unsigned char* algolist = NULL;
|
||||
unsigned int orig_pos = buf->pos;
|
||||
unsigned int len, remotecount, i;
|
||||
const char *remotenames[MAX_PROPOSED_ALGO];
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
algolist = buf_getstring(buf, &len);
|
||||
remotecount = MAX_PROPOSED_ALGO;
|
||||
get_algolist(algolist, len, remotenames, &remotecount);
|
||||
for (i = 0; i < remotecount; i++)
|
||||
{
|
||||
if (strcmp(remotenames[i], algo) == 0) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (algolist) {
|
||||
m_free(algolist);
|
||||
}
|
||||
buf_setpos(buf, orig_pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* match the first algorithm in the comma-separated list in buf which is
|
||||
* also in localalgos[], or return NULL on failure.
|
||||
* (*goodguess) is set to 1 if the preferred client/server algos match,
|
||||
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
|
||||
* guessed correctly */
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess)
|
||||
{
|
||||
|
||||
int kexguess2, int *goodguess) {
|
||||
char * algolist = NULL;
|
||||
const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
@ -359,40 +429,8 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
TRACE(("buf_match_algo: %s", algolist))
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* remotenames will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotenames[0] = algolist;
|
||||
remotecount = 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotenames[remotecount] = &algolist[i+1];
|
||||
remotecount++;
|
||||
}
|
||||
if (remotecount >= MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
|
||||
for (i = 0; i < remotecount; i++)
|
||||
{
|
||||
if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
|
||||
*kexguess2 = KEXGUESS2_YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*kexguess2 == KEXGUESS2_LOOK) {
|
||||
*kexguess2 = KEXGUESS2_NO;
|
||||
}
|
||||
}
|
||||
remotecount = MAX_PROPOSED_ALGO;
|
||||
get_algolist(algolist, len, remotenames, &remotecount);
|
||||
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
@ -424,12 +462,11 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
}
|
||||
if (strcmp(servnames[j], clinames[i]) == 0) {
|
||||
/* set if it was a good guess */
|
||||
if (goodguess && kexguess2) {
|
||||
if (*kexguess2 == KEXGUESS2_YES) {
|
||||
if (goodguess != NULL) {
|
||||
if (kexguess2) {
|
||||
if (i == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (i == 0 && j == 0) {
|
||||
*goodguess = 1;
|
||||
|
30
common-kex.c
30
common-kex.c
@ -820,21 +820,33 @@ static void read_kex_algos() {
|
||||
int goodguess = 0;
|
||||
int allgood = 1; /* we AND this with each goodguess and see if its still
|
||||
true after */
|
||||
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
|
||||
#else
|
||||
enum kexguess2_used kexguess2 = KEXGUESS2_NO;
|
||||
#endif
|
||||
int kexguess2 = 0;
|
||||
|
||||
buf_incrpos(ses.payload, 16); /* start after the cookie */
|
||||
|
||||
memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
|
||||
|
||||
/* kex_algorithms */
|
||||
algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
if (buf_has_algo(ses.payload, KEXGUESS2_ALGO_NAME) == DROPBEAR_SUCCESS) {
|
||||
kexguess2 = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine if SSH_MSG_EXT_INFO messages should be sent.
|
||||
Should be done for the first key exchange. */
|
||||
if (!ses.kexstate.donefirstkex) {
|
||||
if (IS_DROPBEAR_SERVER) {
|
||||
if (buf_has_algo(ses.payload, SSH_EXT_INFO_C) == DROPBEAR_SUCCESS) {
|
||||
ses.allow_ext_info = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
|
||||
if (algo == NULL || algo->data == NULL) {
|
||||
/* kexguess2, ext-info-c, ext-info-s should not match negotiation */
|
||||
erralgo = "kex";
|
||||
goto error;
|
||||
}
|
||||
@ -843,7 +855,7 @@ static void read_kex_algos() {
|
||||
ses.newkeys->algo_kex = algo->data;
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
|
||||
algo = buf_match_algo(ses.payload, sshhostkey, kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL) {
|
||||
erralgo = "hostkey";
|
||||
|
@ -29,7 +29,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
sign_key *key = new_sign_key();
|
||||
enum signkey_type keytype = DROPBEAR_SIGNKEY_ANY;
|
||||
if (buf_get_pub_key(fuzz.input, key, &keytype) == DROPBEAR_SUCCESS) {
|
||||
enum signature_type sigtype = (enum signature_type)keytype;
|
||||
enum signature_type sigtype;
|
||||
if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
/* Flip a coin to decide rsa signature type */
|
||||
int flag = buf_getbyte(fuzz_input);
|
||||
@ -38,6 +38,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
} else {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
}
|
||||
} else {
|
||||
sigtype = signature_type_from_signkey(keytype);
|
||||
}
|
||||
if (buf_verify(fuzz.input, key, sigtype, verifydata) == DROPBEAR_SUCCESS) {
|
||||
/* The fuzzer is capable of generating keys with a signature to match.
|
||||
|
2
kex.h
2
kex.h
@ -65,6 +65,8 @@ void recv_msg_kexdh_init(void); /* server */
|
||||
void send_msg_kexdh_init(void); /* client */
|
||||
void recv_msg_kexdh_reply(void); /* client */
|
||||
|
||||
void recv_msg_ext_info(void);
|
||||
|
||||
struct KEXState {
|
||||
|
||||
unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */
|
||||
|
11
session.h
11
session.h
@ -185,6 +185,9 @@ struct sshsession {
|
||||
|
||||
/* Enables/disables compression */
|
||||
algo_type *compress_algos;
|
||||
|
||||
/* Other side allows SSH_MSG_EXT_INFO */
|
||||
int allow_ext_info;
|
||||
|
||||
/* a list of queued replies that should be sent after a KEX has
|
||||
concluded (ie, while dataallowed was unset)*/
|
||||
@ -313,13 +316,7 @@ struct clientsession {
|
||||
#endif
|
||||
sign_key *lastprivkey;
|
||||
|
||||
enum signature_type server_sig_algs[DROPBEAR_SIGNKEY_NUM_NAMED+1];
|
||||
int server_sig_algs_count;
|
||||
#if DROPBEAR_RSA
|
||||
/* Set to DROPBEAR_SIGNATURE_RSA_SHA256 or DROPBEAR_SIGNATURE_RSA_SHA1
|
||||
if depending which the server accepts */
|
||||
enum signature_type preferred_rsa_sigtype;
|
||||
#endif
|
||||
buffer *server_sig_algs;
|
||||
|
||||
int retval; /* What the command exit status was - we emulate it */
|
||||
#if 0
|
||||
|
21
signkey.c
21
signkey.c
@ -114,13 +114,17 @@ enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen)
|
||||
const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) {
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
if (type == DROPBEAR_SIGNATURE_RSA_SHA256) {
|
||||
*namelen = strlen(SSH_SIGNATURE_RSA_SHA256);
|
||||
if (namelen) {
|
||||
*namelen = strlen(SSH_SIGNATURE_RSA_SHA256);
|
||||
}
|
||||
return SSH_SIGNATURE_RSA_SHA256;
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
if (type == DROPBEAR_SIGNATURE_RSA_SHA1) {
|
||||
*namelen = strlen(SSH_SIGNKEY_RSA);
|
||||
if (namelen) {
|
||||
*namelen = strlen(SSH_SIGNKEY_RSA);
|
||||
}
|
||||
return SSH_SIGNKEY_RSA;
|
||||
}
|
||||
#endif
|
||||
@ -144,6 +148,16 @@ enum signature_type signature_type_from_name(const char* name, unsigned int name
|
||||
return (enum signature_type)signkey_type_from_name(name, namelen);
|
||||
}
|
||||
|
||||
/* Returns the signature type from a key type. Must not be called
|
||||
with RSA keytype */
|
||||
enum signature_type signature_type_from_signkey(enum signkey_type keytype) {
|
||||
#if DROPBEAR_RSA
|
||||
assert(keytype != DROPBEAR_SIGNKEY_RSA);
|
||||
#endif
|
||||
assert(keytype < DROPBEAR_SIGNKEY_NUM_NAMED);
|
||||
return (enum signature_type)keytype;
|
||||
}
|
||||
|
||||
enum signkey_type signkey_type_from_signature(enum signature_type sigtype) {
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
|
||||
@ -587,8 +601,7 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
|
||||
|
||||
#if DEBUG_TRACE
|
||||
{
|
||||
int namelen;
|
||||
const char* signame = signature_name_from_type(sigtype, &namelen);
|
||||
const char* signame = signature_name_from_type(sigtype, NULL);
|
||||
TRACE(("buf_put_sign type %d %s", sigtype, signame));
|
||||
}
|
||||
#endif
|
||||
|
@ -120,6 +120,8 @@ enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen)
|
||||
const char* signature_name_from_type(enum signature_type type, unsigned int *namelen);
|
||||
enum signature_type signature_type_from_name(const char* name, unsigned int namelen);
|
||||
enum signkey_type signkey_type_from_signature(enum signature_type sigtype);
|
||||
enum signature_type signature_type_from_signkey(enum signkey_type keytype);
|
||||
|
||||
int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type);
|
||||
int buf_get_priv_key(buffer* buf, sign_key *key, enum signkey_type *type);
|
||||
void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type);
|
||||
|
6
ssh.h
6
ssh.h
@ -32,6 +32,7 @@
|
||||
#define SSH_MSG_DEBUG 4
|
||||
#define SSH_MSG_SERVICE_REQUEST 5
|
||||
#define SSH_MSG_SERVICE_ACCEPT 6
|
||||
#define SSH_MSG_EXT_INFO 7
|
||||
#define SSH_MSG_KEXINIT 20
|
||||
#define SSH_MSG_NEWKEYS 21
|
||||
#define SSH_MSG_KEXDH_INIT 30
|
||||
@ -94,6 +95,11 @@
|
||||
#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14
|
||||
#define SSH_DISCONNECT_ILLEGAL_USER_NAME 15
|
||||
|
||||
/* rfc8308 */
|
||||
#define SSH_EXT_INFO_S "ext-info-s"
|
||||
#define SSH_EXT_INFO_C "ext-info-c"
|
||||
#define SSH_SERVER_SIG_ALGS "server-sig-algs"
|
||||
|
||||
/* service types */
|
||||
#define SSH_SERVICE_USERAUTH "ssh-userauth"
|
||||
#define SSH_SERVICE_USERAUTH_LEN 12
|
||||
|
@ -330,13 +330,16 @@ static void svr_remoteclosed() {
|
||||
}
|
||||
|
||||
static void svr_algos_initialise(void) {
|
||||
#if DROPBEAR_DH_GROUP1 && DROPBEAR_DH_GROUP1_CLIENTONLY
|
||||
algo_type *algo;
|
||||
for (algo = sshkex; algo->name; algo++) {
|
||||
#if DROPBEAR_DH_GROUP1 && DROPBEAR_DH_GROUP1_CLIENTONLY
|
||||
if (strcmp(algo->name, "diffie-hellman-group1-sha1") == 0) {
|
||||
algo->usable = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (strcmp(algo->name, SSH_EXT_INFO_C) == 0) {
|
||||
algo->usable = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user