mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
merge again
This commit is contained in:
13
Makefile.in
13
Makefile.in
@@ -17,16 +17,17 @@ LTC=libtomcrypt/libtomcrypt.a
|
||||
LTM=libtommath/libtommath.a
|
||||
|
||||
ifeq (@BUNDLED_LIBTOM@, 1)
|
||||
LIBTOM_DEPS=$(LTC) $(LTM)
|
||||
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
|
||||
LIBS+=$(LTC) $(LTM)
|
||||
LIBTOM_DEPS=$(LTC) $(LTM)
|
||||
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
|
||||
LIBS+=$(LTC) $(LTM)
|
||||
endif
|
||||
|
||||
COMMONOBJS=dbutil.o buffer.o \
|
||||
dss.o bignum.o \
|
||||
signkey.o rsa.o random.o \
|
||||
queue.o \
|
||||
atomicio.o compat.o fake-rfc2553.o
|
||||
atomicio.o compat.o fake-rfc2553.o \
|
||||
ltc_prng.o ecc.o ecdsa.o crypto_desc.o
|
||||
|
||||
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
|
||||
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
|
||||
@@ -54,7 +55,7 @@ HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
|
||||
debug.h channel.h chansession.h config.h queue.h sshpty.h \
|
||||
termcodes.h gendss.h genrsa.h runopts.h includes.h \
|
||||
loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
|
||||
listener.h fake-rfc2553.h
|
||||
listener.h fake-rfc2553.h ecc.h ecdsa.h
|
||||
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) @CRYPTLIB@
|
||||
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
|
||||
@@ -185,7 +186,7 @@ link%:
|
||||
-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
|
||||
|
||||
$(LTC): options.h
|
||||
cd libtomcrypt && $(MAKE) clean && $(MAKE)
|
||||
cd libtomcrypt && $(MAKE)
|
||||
|
||||
$(LTM): options.h
|
||||
cd libtommath && $(MAKE)
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
/* client functions */
|
||||
void cli_load_agent_keys(m_list * ret_list);
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const unsigned char *data, unsigned int len);
|
||||
buffer *data_buf);
|
||||
void cli_setup_agent(struct Channel *channel);
|
||||
|
||||
#ifdef __hpux
|
||||
|
||||
40
algo.h
40
algo.h
@@ -35,7 +35,7 @@
|
||||
|
||||
struct Algo_Type {
|
||||
|
||||
unsigned char *name; /* identifying name */
|
||||
const unsigned char *name; /* identifying name */
|
||||
char val; /* a value for this cipher, or -1 for invalid */
|
||||
const void *data; /* algorithm specific data */
|
||||
char usable; /* whether we can use this algorithm */
|
||||
@@ -59,8 +59,8 @@ extern const struct dropbear_hash dropbear_nohash;
|
||||
|
||||
struct dropbear_cipher {
|
||||
const struct ltc_cipher_descriptor *cipherdesc;
|
||||
unsigned long keysize;
|
||||
unsigned char blocksize;
|
||||
const unsigned long keysize;
|
||||
const unsigned char blocksize;
|
||||
};
|
||||
|
||||
struct dropbear_cipher_mode {
|
||||
@@ -74,12 +74,27 @@ struct dropbear_cipher_mode {
|
||||
};
|
||||
|
||||
struct dropbear_hash {
|
||||
const struct ltc_hash_descriptor *hashdesc;
|
||||
unsigned long keysize;
|
||||
unsigned char hashsize;
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
const unsigned long keysize;
|
||||
// hashsize may be truncated from the size returned by hash_desc,
|
||||
// eg sha1-96
|
||||
const unsigned char hashsize;
|
||||
};
|
||||
|
||||
struct dropbear_kex {
|
||||
// "normal" DH KEX
|
||||
const unsigned char *dh_p_bytes;
|
||||
const int dh_p_len;
|
||||
|
||||
// elliptic curve DH KEX
|
||||
#ifdef DROPBEAR_ECDH
|
||||
const struct dropbear_ecc_curve *ecc_curve;
|
||||
#endif
|
||||
|
||||
// both
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
};
|
||||
|
||||
void crypto_init();
|
||||
int have_algo(char* algo, size_t algolen, algo_type algos[]);
|
||||
void buf_put_algolist(buffer * buf, algo_type localalgos[]);
|
||||
|
||||
@@ -102,5 +117,16 @@ int check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
char * algolist_string(algo_type algos[]);
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#define IS_NORMAL_DH(algo) ((algo)->dh_p_bytes != NULL)
|
||||
#else
|
||||
#define IS_NORMAL_DH(algo) 1
|
||||
#endif
|
||||
|
||||
enum {
|
||||
DROPBEAR_COMP_NONE,
|
||||
DROPBEAR_COMP_ZLIB,
|
||||
DROPBEAR_COMP_ZLIB_DELAY,
|
||||
};
|
||||
|
||||
#endif /* _ALGO_H_ */
|
||||
|
||||
23
bignum.c
23
bignum.c
@@ -52,6 +52,22 @@ void m_mp_init_multi(mp_int *mp, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void m_mp_alloc_init_multi(mp_int **mp, ...)
|
||||
{
|
||||
mp_int** cur_arg = mp;
|
||||
va_list args;
|
||||
|
||||
va_start(args, mp); /* init args to next argument from caller */
|
||||
while (cur_arg != NULL) {
|
||||
*cur_arg = m_malloc(sizeof(mp_int));
|
||||
if (mp_init(*cur_arg) != MP_OKAY) {
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
cur_arg = va_arg(args, mp_int**);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
|
||||
|
||||
if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
|
||||
@@ -60,7 +76,8 @@ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
|
||||
}
|
||||
|
||||
/* hash the ssh representation of the mp_int mp */
|
||||
void sha1_process_mp(hash_state *hs, mp_int *mp) {
|
||||
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
|
||||
hash_state *hs, mp_int *mp) {
|
||||
|
||||
int i;
|
||||
buffer * buf;
|
||||
@@ -68,8 +85,6 @@ void sha1_process_mp(hash_state *hs, mp_int *mp) {
|
||||
buf = buf_new(512 + 20); /* max buffer is a 4096 bit key,
|
||||
plus header + some leeway*/
|
||||
buf_putmpint(buf, mp);
|
||||
i = buf->pos;
|
||||
buf_setpos(buf, 0);
|
||||
sha1_process(hs, buf_getptr(buf, i), i);
|
||||
hash_desc->process(hs, buf->data, buf->len);
|
||||
buf_free(buf);
|
||||
}
|
||||
|
||||
4
bignum.h
4
bignum.h
@@ -30,7 +30,9 @@
|
||||
|
||||
void m_mp_init(mp_int *mp);
|
||||
void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
|
||||
void m_mp_alloc_init_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
|
||||
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
|
||||
void sha1_process_mp(hash_state *hs, mp_int *mp);
|
||||
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
|
||||
hash_state *hs, mp_int *mp);
|
||||
|
||||
#endif /* _BIGNUM_H_ */
|
||||
|
||||
5
buffer.c
5
buffer.c
@@ -269,6 +269,11 @@ void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len) {
|
||||
|
||||
}
|
||||
|
||||
/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
|
||||
void buf_putbufstring(buffer *buf, const buffer* buf_str) {
|
||||
buf_putstring(buf, buf_str->data, buf_str->len);
|
||||
}
|
||||
|
||||
/* put the set of len bytes into the buffer, incrementing the pos, increasing
|
||||
* len if required */
|
||||
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
|
||||
|
||||
1
buffer.h
1
buffer.h
@@ -59,6 +59,7 @@ buffer * buf_getstringbuf(buffer *buf);
|
||||
void buf_eatstring(buffer *buf);
|
||||
void buf_putint(buffer* buf, unsigned int val);
|
||||
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
|
||||
void buf_putbufstring(buffer *buf, const buffer* buf_str);
|
||||
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
|
||||
void buf_putmpint(buffer* buf, mp_int * mp);
|
||||
int buf_getmpint(buffer* buf, mp_int* mp);
|
||||
|
||||
@@ -254,7 +254,7 @@ void cli_load_agent_keys(m_list *ret_list) {
|
||||
}
|
||||
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const unsigned char *data, unsigned int len) {
|
||||
buffer *data_buf) {
|
||||
buffer *request_data = NULL;
|
||||
buffer *response = NULL;
|
||||
unsigned int siglen;
|
||||
@@ -266,10 +266,10 @@ void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
string data
|
||||
uint32 flags
|
||||
*/
|
||||
request_data = buf_new(MAX_PUBKEY_SIZE + len + 12);
|
||||
request_data = buf_new(MAX_PUBKEY_SIZE + data_buf->len + 12);
|
||||
buf_put_pub_key(request_data, key, key->type);
|
||||
|
||||
buf_putstring(request_data, data, len);
|
||||
buf_putbufstring(request_data, data_buf);
|
||||
buf_putint(request_data, 0);
|
||||
|
||||
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
|
||||
|
||||
@@ -121,23 +121,19 @@ void recv_msg_userauth_pk_ok() {
|
||||
}
|
||||
|
||||
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len)
|
||||
{
|
||||
buffer *data_buf) {
|
||||
#ifdef ENABLE_CLI_AGENTFWD
|
||||
if (key->source == SIGNKEY_SOURCE_AGENT) {
|
||||
/* Format the agent signature ourselves, as buf_put_sign would. */
|
||||
buffer *sigblob;
|
||||
sigblob = buf_new(MAX_PUBKEY_SIZE);
|
||||
agent_buf_sign(sigblob, key, data, len);
|
||||
buf_setpos(sigblob, 0);
|
||||
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
|
||||
sigblob->len);
|
||||
|
||||
agent_buf_sign(sigblob, key, data_buf);
|
||||
buf_putbufstring(buf, sigblob);
|
||||
buf_free(sigblob);
|
||||
} else
|
||||
#endif /* ENABLE_CLI_AGENTFWD */
|
||||
{
|
||||
buf_put_sign(buf, key, type, data, len);
|
||||
buf_put_sign(buf, key, type, data_buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,10 +169,10 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
TRACE(("realsign"))
|
||||
/* We put the signature as well - this contains string(session id), then
|
||||
* the contents of the write payload to this point */
|
||||
sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
|
||||
buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
|
||||
sigbuf = buf_new(4 + ses.session_id->len + ses.writepayload->len);
|
||||
buf_putbufstring(sigbuf, ses.session_id);
|
||||
buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
|
||||
cli_buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
|
||||
cli_buf_put_sign(ses.writepayload, key, type, sigbuf);
|
||||
buf_free(sigbuf); /* Nothing confidential in the buffer */
|
||||
}
|
||||
|
||||
|
||||
@@ -455,7 +455,7 @@ do_escape(unsigned char c) {
|
||||
}
|
||||
|
||||
static
|
||||
void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len) {
|
||||
void cli_escape_handler(struct Channel* UNUSED(channel), unsigned char* buf, int *len) {
|
||||
char c;
|
||||
int skip_char = 0;
|
||||
|
||||
|
||||
80
cli-kex.c
80
cli-kex.c
@@ -36,6 +36,7 @@
|
||||
#include "random.h"
|
||||
#include "runopts.h"
|
||||
#include "signkey.h"
|
||||
#include "ecc.h"
|
||||
|
||||
|
||||
static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
|
||||
@@ -43,23 +44,31 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
|
||||
|
||||
void send_msg_kexdh_init() {
|
||||
TRACE(("send_msg_kexdh_init()"))
|
||||
if ((cli_ses.dh_e && cli_ses.dh_x
|
||||
&& cli_ses.dh_val_algo == ses.newkeys->algo_kex)) {
|
||||
TRACE(("reusing existing dh_e from first_kex_packet_follows"))
|
||||
} else {
|
||||
if (!cli_ses.dh_e || !cli_ses.dh_e) {
|
||||
cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
|
||||
}
|
||||
|
||||
gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
|
||||
cli_ses.dh_val_algo = ses.newkeys->algo_kex;
|
||||
}
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
|
||||
buf_putmpint(ses.writepayload, cli_ses.dh_e);
|
||||
if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.dh_param) {
|
||||
if (cli_ses.dh_param) {
|
||||
free_kexdh_param(cli_ses.dh_param);
|
||||
}
|
||||
cli_ses.dh_param = gen_kexdh_param();
|
||||
}
|
||||
buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
|
||||
} else {
|
||||
#ifdef DROPBEAR_ECDH
|
||||
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|
||||
|| !cli_ses.ecdh_param) {
|
||||
if (cli_ses.ecdh_param) {
|
||||
free_kexecdh_param(cli_ses.ecdh_param);
|
||||
}
|
||||
cli_ses.ecdh_param = gen_kexecdh_param();
|
||||
}
|
||||
buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key);
|
||||
#endif
|
||||
}
|
||||
cli_ses.param_kex_algo = ses.newkeys->algo_kex;
|
||||
encrypt_packet();
|
||||
ses.requirenext[0] = SSH_MSG_KEXDH_REPLY;
|
||||
ses.requirenext[1] = SSH_MSG_KEXINIT;
|
||||
@@ -68,18 +77,15 @@ void send_msg_kexdh_init() {
|
||||
/* Handle a diffie-hellman key exchange reply. */
|
||||
void recv_msg_kexdh_reply() {
|
||||
|
||||
DEF_MP_INT(dh_f);
|
||||
sign_key *hostkey = NULL;
|
||||
unsigned int type, keybloblen;
|
||||
unsigned char* keyblob = NULL;
|
||||
|
||||
|
||||
TRACE(("enter recv_msg_kexdh_reply"))
|
||||
|
||||
if (cli_ses.kex_state != KEXDH_INIT_SENT) {
|
||||
dropbear_exit("Received out-of-order kexdhreply");
|
||||
}
|
||||
m_mp_init(&dh_f);
|
||||
type = ses.newkeys->algo_hostkey;
|
||||
TRACE(("type is %d", type))
|
||||
|
||||
@@ -97,20 +103,38 @@ void recv_msg_kexdh_reply() {
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
|
||||
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting mpint"))
|
||||
dropbear_exit("Bad KEX packet");
|
||||
if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
|
||||
// Normal diffie-hellman
|
||||
DEF_MP_INT(dh_f);
|
||||
m_mp_init(&dh_f);
|
||||
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting mpint"))
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
|
||||
kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey);
|
||||
mp_clear(&dh_f);
|
||||
} else {
|
||||
#ifdef DROPBEAR_ECDH
|
||||
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
|
||||
kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey);
|
||||
buf_free(ecdh_qs);
|
||||
#endif
|
||||
}
|
||||
|
||||
kexdh_comb_key(cli_ses.dh_e, cli_ses.dh_x, &dh_f, hostkey);
|
||||
mp_clear(&dh_f);
|
||||
mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
|
||||
m_free(cli_ses.dh_e);
|
||||
m_free(cli_ses.dh_x);
|
||||
cli_ses.dh_val_algo = DROPBEAR_KEX_NONE;
|
||||
if (cli_ses.dh_param) {
|
||||
free_kexdh_param(cli_ses.dh_param);
|
||||
cli_ses.dh_param = NULL;
|
||||
}
|
||||
#ifdef DROPBEAR_ECDH
|
||||
if (cli_ses.ecdh_param) {
|
||||
free_kexecdh_param(cli_ses.ecdh_param);
|
||||
cli_ses.ecdh_param = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
cli_ses.param_kex_algo = NULL;
|
||||
if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Bad hostkey signature");
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "dbutil.h"
|
||||
#include "runopts.h"
|
||||
#include "session.h"
|
||||
#include "random.h"
|
||||
#include "crypto_desc.h"
|
||||
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
static void cli_dropbear_log(int priority, const char* format, va_list param);
|
||||
@@ -51,6 +53,9 @@ int main(int argc, char ** argv) {
|
||||
|
||||
disallow_core();
|
||||
|
||||
seedrandom();
|
||||
crypto_init();
|
||||
|
||||
cli_getopts(argc, argv);
|
||||
|
||||
TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "runopts.h"
|
||||
#include "chansession.h"
|
||||
#include "agentfwd.h"
|
||||
#include "crypto_desc.h"
|
||||
|
||||
static void cli_remoteclosed();
|
||||
static void cli_sessionloop();
|
||||
@@ -86,10 +87,6 @@ static const struct ChanType *cli_chantypes[] = {
|
||||
|
||||
void cli_session(int sock_in, int sock_out) {
|
||||
|
||||
seedrandom();
|
||||
|
||||
crypto_init();
|
||||
|
||||
common_session_init(sock_in, sock_out);
|
||||
|
||||
chaninitialise(cli_chantypes);
|
||||
|
||||
104
common-algo.c
104
common-algo.c
@@ -23,24 +23,28 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
#include "session.h"
|
||||
#include "dbutil.h"
|
||||
#include "kex.h"
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.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*/
|
||||
|
||||
static int void_cipher(const unsigned char* in, unsigned char* out,
|
||||
unsigned long len, void *cipher_state) {
|
||||
unsigned long len, void* UNUSED(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) {
|
||||
static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
|
||||
const unsigned char* UNUSED(key),
|
||||
int UNUSED(keylen), int UNUSED(num_rounds), void* UNUSED(cipher_state)) {
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
@@ -204,6 +208,17 @@ algo_type ssh_nocompress[] = {
|
||||
};
|
||||
|
||||
algo_type sshhostkey[] = {
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
|
||||
#endif
|
||||
@@ -213,65 +228,42 @@ algo_type sshhostkey[] = {
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static struct dropbear_kex kex_dh_group1 = {dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
|
||||
static struct dropbear_kex kex_dh_group14 = {dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
|
||||
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
static struct dropbear_kex kex_ecdh_nistp256 = {NULL, 0, &ecc_curve_nistp256, &sha256_desc };
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
static struct dropbear_kex kex_ecdh_nistp384 = {NULL, 0, &ecc_curve_nistp384, &sha384_desc };
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
static struct dropbear_kex kex_ecdh_nistp521 = {NULL, 0, &ecc_curve_nistp521, &sha512_desc };
|
||||
#endif
|
||||
#endif // DROPBEAR_ECDH
|
||||
|
||||
|
||||
algo_type sshkex[] = {
|
||||
{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL},
|
||||
{"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL},
|
||||
#ifdef DROPBEAR_ECDH
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
{"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL},
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
{"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
|
||||
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL},
|
||||
#ifdef USE_KEXGUESS2
|
||||
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
/* Register the compiled in ciphers.
|
||||
* This should be run before using any of the ciphers/hashes */
|
||||
void crypto_init() {
|
||||
|
||||
const struct ltc_cipher_descriptor *regciphers[] = {
|
||||
#ifdef DROPBEAR_AES
|
||||
&aes_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH
|
||||
&blowfish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH
|
||||
&twofish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
&des3_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct ltc_hash_descriptor *reghashes[] = {
|
||||
/* we need sha1 for hostkey stuff regardless */
|
||||
&sha1_desc,
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
&md5_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
&sha256_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA2_512_HMAC
|
||||
&sha512_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; regciphers[i] != NULL; i++) {
|
||||
if (register_cipher(regciphers[i]) == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; reghashes[i] != NULL; i++) {
|
||||
if (register_hash(reghashes[i]) == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* algolen specifies the length of algo, algos is our local list to match
|
||||
* against.
|
||||
* Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
|
||||
|
||||
186
common-kex.c
186
common-kex.c
@@ -34,10 +34,11 @@
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "runopts.h"
|
||||
#include "ecc.h"
|
||||
#include "crypto_desc.h"
|
||||
|
||||
/* diffie-hellman-group1-sha1 value for p */
|
||||
#define DH_P_1_LEN 128
|
||||
static const unsigned char dh_p_1[DH_P_1_LEN] = {
|
||||
const unsigned char dh_p_1[DH_P_1_LEN] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
|
||||
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
|
||||
@@ -51,8 +52,7 @@ static const unsigned char dh_p_1[DH_P_1_LEN] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
/* diffie-hellman-group14-sha1 value for p */
|
||||
#define DH_P_14_LEN 256
|
||||
static const unsigned char dh_p_14[DH_P_14_LEN] = {
|
||||
const unsigned char dh_p_14[DH_P_14_LEN] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
|
||||
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
|
||||
@@ -87,8 +87,9 @@ static void gen_new_zstream_trans();
|
||||
#endif
|
||||
static void read_kex_algos();
|
||||
/* helper function for gen_new_keys */
|
||||
static void hashkeys(unsigned char *out, int outlen,
|
||||
const hash_state * hs, unsigned const char X);
|
||||
static void hashkeys(unsigned char *out, unsigned int outlen,
|
||||
const hash_state * hs, const unsigned char X);
|
||||
static void finish_kexhashbuf(void);
|
||||
|
||||
|
||||
/* Send our list of algorithms we can use */
|
||||
@@ -150,7 +151,7 @@ void send_msg_kexinit() {
|
||||
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
|
||||
if (ses.send_kex_first_guess) {
|
||||
ses.newkeys->algo_kex = sshkex[0].val;
|
||||
ses.newkeys->algo_kex = sshkex[0].data;
|
||||
ses.newkeys->algo_hostkey = sshhostkey[0].val;
|
||||
ses.send_kex_first_guess();
|
||||
}
|
||||
@@ -279,26 +280,28 @@ static void kexinitialise() {
|
||||
* out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
|
||||
*
|
||||
* See Section 7.2 of rfc4253 (ssh transport) for details */
|
||||
static void hashkeys(unsigned char *out, int outlen,
|
||||
static void hashkeys(unsigned char *out, unsigned int outlen,
|
||||
const hash_state * hs, const unsigned char X) {
|
||||
|
||||
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
|
||||
hash_state hs2;
|
||||
int offset;
|
||||
unsigned int offset;
|
||||
unsigned char tmpout[hash_desc->hashsize];
|
||||
|
||||
memcpy(&hs2, hs, sizeof(hash_state));
|
||||
sha1_process(&hs2, &X, 1);
|
||||
sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE);
|
||||
sha1_done(&hs2, out);
|
||||
for (offset = SHA1_HASH_SIZE;
|
||||
hash_desc->process(&hs2, &X, 1);
|
||||
hash_desc->process(&hs2, ses.session_id->data, ses.session_id->len);
|
||||
hash_desc->done(&hs2, tmpout);
|
||||
memcpy(out, tmpout, MIN(hash_desc->hashsize, outlen));
|
||||
for (offset = hash_desc->hashsize;
|
||||
offset < outlen;
|
||||
offset += SHA1_HASH_SIZE)
|
||||
offset += hash_desc->hashsize)
|
||||
{
|
||||
/* need to extend */
|
||||
unsigned char k2[SHA1_HASH_SIZE];
|
||||
memcpy(&hs2, hs, sizeof(hash_state));
|
||||
sha1_process(&hs2, out, offset);
|
||||
sha1_done(&hs2, k2);
|
||||
memcpy(&out[offset], k2, MIN(outlen - offset, SHA1_HASH_SIZE));
|
||||
hash_desc->process(&hs2, out, offset);
|
||||
hash_desc->done(&hs2, tmpout);
|
||||
memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,26 +322,26 @@ static void gen_new_keys() {
|
||||
unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key;
|
||||
|
||||
hash_state hs;
|
||||
unsigned int C2S_keysize, S2C_keysize;
|
||||
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
|
||||
char mactransletter, macrecvletter; /* Client or server specific */
|
||||
|
||||
TRACE(("enter gen_new_keys"))
|
||||
/* the dh_K and hash are the start of all hashes, we make use of that */
|
||||
|
||||
sha1_init(&hs);
|
||||
sha1_process_mp(&hs, ses.dh_K);
|
||||
hash_desc->init(&hs);
|
||||
hash_process_mp(hash_desc, &hs, ses.dh_K);
|
||||
mp_clear(ses.dh_K);
|
||||
m_free(ses.dh_K);
|
||||
sha1_process(&hs, ses.hash, SHA1_HASH_SIZE);
|
||||
m_burn(ses.hash, SHA1_HASH_SIZE);
|
||||
hash_desc->process(&hs, ses.hash->data, ses.hash->len);
|
||||
buf_burn(ses.hash);
|
||||
buf_free(ses.hash);
|
||||
ses.hash = NULL;
|
||||
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
trans_IV = C2S_IV;
|
||||
recv_IV = S2C_IV;
|
||||
trans_key = C2S_key;
|
||||
recv_key = S2C_key;
|
||||
C2S_keysize = ses.newkeys->trans.algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->recv.algo_crypt->keysize;
|
||||
mactransletter = 'E';
|
||||
macrecvletter = 'F';
|
||||
} else {
|
||||
@@ -346,16 +349,14 @@ static void gen_new_keys() {
|
||||
recv_IV = C2S_IV;
|
||||
trans_key = S2C_key;
|
||||
recv_key = C2S_key;
|
||||
C2S_keysize = ses.newkeys->recv.algo_crypt->keysize;
|
||||
S2C_keysize = ses.newkeys->trans.algo_crypt->keysize;
|
||||
mactransletter = 'F';
|
||||
macrecvletter = 'E';
|
||||
}
|
||||
|
||||
hashkeys(C2S_IV, SHA1_HASH_SIZE, &hs, 'A');
|
||||
hashkeys(S2C_IV, SHA1_HASH_SIZE, &hs, 'B');
|
||||
hashkeys(C2S_key, C2S_keysize, &hs, 'C');
|
||||
hashkeys(S2C_key, S2C_keysize, &hs, 'D');
|
||||
hashkeys(C2S_IV, sizeof(C2S_IV), &hs, 'A');
|
||||
hashkeys(S2C_IV, sizeof(S2C_IV), &hs, 'B');
|
||||
hashkeys(C2S_key, sizeof(C2S_key), &hs, 'C');
|
||||
hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D');
|
||||
|
||||
if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
|
||||
int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
|
||||
@@ -381,16 +382,16 @@ static void gen_new_keys() {
|
||||
}
|
||||
}
|
||||
|
||||
if (ses.newkeys->trans.algo_mac->hashdesc != NULL) {
|
||||
if (ses.newkeys->trans.algo_mac->hash_desc != NULL) {
|
||||
hashkeys(ses.newkeys->trans.mackey,
|
||||
ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
|
||||
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name);
|
||||
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hash_desc->name);
|
||||
}
|
||||
|
||||
if (ses.newkeys->recv.algo_mac->hashdesc != NULL) {
|
||||
if (ses.newkeys->recv.algo_mac->hash_desc != NULL) {
|
||||
hashkeys(ses.newkeys->recv.mackey,
|
||||
ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
|
||||
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name);
|
||||
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hash_desc->name);
|
||||
}
|
||||
|
||||
/* Ready to switch over */
|
||||
@@ -560,28 +561,23 @@ void recv_msg_kexinit() {
|
||||
|
||||
static void load_dh_p(mp_int * dh_p)
|
||||
{
|
||||
switch (ses.newkeys->algo_kex) {
|
||||
case DROPBEAR_KEX_DH_GROUP1:
|
||||
bytes_to_mp(dh_p, dh_p_1, DH_P_1_LEN);
|
||||
break;
|
||||
case DROPBEAR_KEX_DH_GROUP14:
|
||||
bytes_to_mp(dh_p, dh_p_14, DH_P_14_LEN);
|
||||
break;
|
||||
}
|
||||
bytes_to_mp(dh_p, ses.newkeys->algo_kex->dh_p_bytes,
|
||||
ses.newkeys->algo_kex->dh_p_len);
|
||||
}
|
||||
|
||||
/* Initialises and generate one side of the diffie-hellman key exchange values.
|
||||
* See the transport rfc 4253 section 8 for details */
|
||||
/* dh_pub and dh_priv MUST be already initialised */
|
||||
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
|
||||
struct kex_dh_param *gen_kexdh_param() {
|
||||
|
||||
DEF_MP_INT(dh_p);
|
||||
DEF_MP_INT(dh_q);
|
||||
DEF_MP_INT(dh_g);
|
||||
|
||||
TRACE(("enter gen_kexdh_vals"))
|
||||
|
||||
m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
|
||||
|
||||
struct kex_dh_param *param = m_malloc(sizeof(*param));
|
||||
m_mp_init_multi(¶m->pub, ¶m->priv, NULL);
|
||||
|
||||
/* read the prime and generator*/
|
||||
load_dh_p(&dh_p);
|
||||
@@ -592,33 +588,39 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
|
||||
|
||||
/* calculate q = (p-1)/2 */
|
||||
/* dh_priv is just a temp var here */
|
||||
if (mp_sub_d(&dh_p, 1, dh_priv) != MP_OKAY) {
|
||||
if (mp_sub_d(&dh_p, 1, ¶m->priv) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
if (mp_div_2(dh_priv, &dh_q) != MP_OKAY) {
|
||||
if (mp_div_2(¶m->priv, &dh_q) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
/* Generate a private portion 0 < dh_priv < dh_q */
|
||||
gen_random_mpint(&dh_q, dh_priv);
|
||||
gen_random_mpint(&dh_q, ¶m->priv);
|
||||
|
||||
/* f = g^y mod p */
|
||||
if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) {
|
||||
if (mp_exptmod(&dh_g, ¶m->priv, &dh_p, ¶m->pub) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
mp_clear_multi(&dh_g, &dh_p, &dh_q, NULL);
|
||||
return param;
|
||||
}
|
||||
|
||||
void free_kexdh_param(struct kex_dh_param *param)
|
||||
{
|
||||
mp_clear_multi(¶m->pub, ¶m->priv, NULL);
|
||||
m_free(param);
|
||||
}
|
||||
|
||||
/* This function is fairly common between client/server, with some substitution
|
||||
* of dh_e/dh_f etc. Hence these arguments:
|
||||
* dh_pub_us is 'e' for the client, 'f' for the server. dh_pub_them is
|
||||
* vice-versa. dh_priv is the x/y value corresponding to dh_pub_us */
|
||||
void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
sign_key *hostkey) {
|
||||
|
||||
mp_int dh_p;
|
||||
mp_int *dh_e = NULL, *dh_f = NULL;
|
||||
hash_state hs;
|
||||
|
||||
/* read the prime and generator*/
|
||||
m_mp_init(&dh_p);
|
||||
@@ -631,9 +633,8 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
}
|
||||
|
||||
/* K = e^y mod p = f^x mod p */
|
||||
ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init(ses.dh_K);
|
||||
if (mp_exptmod(dh_pub_them, dh_priv, &dh_p, ses.dh_K) != MP_OKAY) {
|
||||
m_mp_alloc_init_multi(&ses.dh_K, NULL);
|
||||
if (mp_exptmod(dh_pub_them, ¶m->priv, &dh_p, ses.dh_K) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
|
||||
@@ -643,11 +644,11 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
/* From here on, the code needs to work with the _same_ vars on each side,
|
||||
* not vice-versaing for client/server */
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
dh_e = dh_pub_us;
|
||||
dh_e = ¶m->pub;
|
||||
dh_f = dh_pub_them;
|
||||
} else {
|
||||
dh_e = dh_pub_them;
|
||||
dh_f = dh_pub_us;
|
||||
dh_f = ¶m->pub;
|
||||
}
|
||||
|
||||
/* Create the remainder of the hash buffer, to generate the exchange hash */
|
||||
@@ -661,11 +662,70 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
buf_putmpint(ses.kexhashbuf, ses.dh_K);
|
||||
|
||||
/* calculate the hash H to sign */
|
||||
sha1_init(&hs);
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_ECDH
|
||||
struct kex_ecdh_param *gen_kexecdh_param() {
|
||||
struct kex_ecdh_param *param = m_malloc(sizeof(*param));
|
||||
if (ecc_make_key_ex(NULL, dropbear_ltc_prng,
|
||||
¶m->key, ses.newkeys->algo_kex->ecc_curve->dp) != CRYPT_OK) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
void free_kexecdh_param(struct kex_ecdh_param *param) {
|
||||
ecc_free(¶m->key);
|
||||
m_free(param);
|
||||
|
||||
}
|
||||
void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
sign_key *hostkey) {
|
||||
const struct dropbear_kex *algo_kex = ses.newkeys->algo_kex;
|
||||
// public keys from client and server
|
||||
ecc_key *Q_C, *Q_S, *Q_them;
|
||||
|
||||
Q_them = buf_get_ecc_raw_pubkey(pub_them, algo_kex->ecc_curve);
|
||||
|
||||
ses.dh_K = dropbear_ecc_shared_secret(Q_them, ¶m->key);
|
||||
|
||||
/* From here on, the code needs to work with the _same_ vars on each side,
|
||||
* not vice-versaing for client/server */
|
||||
if (IS_DROPBEAR_CLIENT) {
|
||||
Q_C = ¶m->key;
|
||||
Q_S = Q_them;
|
||||
} else {
|
||||
Q_C = Q_them;
|
||||
Q_S = ¶m->key;
|
||||
}
|
||||
|
||||
/* Create the remainder of the hash buffer, to generate the exchange hash */
|
||||
/* K_S, the host key */
|
||||
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
|
||||
/* Q_C, client's ephemeral public key octet string */
|
||||
buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_C);
|
||||
/* Q_S, server's ephemeral public key octet string */
|
||||
buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_S);
|
||||
/* K, the shared secret */
|
||||
buf_putmpint(ses.kexhashbuf, ses.dh_K);
|
||||
|
||||
/* calculate the hash H to sign */
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void finish_kexhashbuf(void) {
|
||||
hash_state hs;
|
||||
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
|
||||
|
||||
hash_desc->init(&hs);
|
||||
buf_setpos(ses.kexhashbuf, 0);
|
||||
sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
|
||||
hash_desc->process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
|
||||
ses.kexhashbuf->len);
|
||||
sha1_done(&hs, ses.hash);
|
||||
ses.hash = buf_new(hash_desc->hashsize);
|
||||
hash_desc->done(&hs, buf_getwriteptr(ses.hash, hash_desc->hashsize));
|
||||
buf_setlen(ses.hash, hash_desc->hashsize);
|
||||
|
||||
buf_burn(ses.kexhashbuf);
|
||||
buf_free(ses.kexhashbuf);
|
||||
@@ -674,9 +734,9 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
/* first time around, we set the session_id to H */
|
||||
if (ses.session_id == NULL) {
|
||||
/* create the session_id, this never needs freeing */
|
||||
ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE);
|
||||
memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE);
|
||||
ses.session_id = buf_newcopy(ses.hash);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* read the other side's algo list. buf_match_algo is a callback to match
|
||||
@@ -719,7 +779,7 @@ static void read_kex_algos() {
|
||||
}
|
||||
TRACE(("kexguess2 %d", kexguess2))
|
||||
TRACE(("kex algo %s", algo->name))
|
||||
ses.newkeys->algo_kex = algo->val;
|
||||
ses.newkeys->algo_kex = algo->data;
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
|
||||
|
||||
@@ -101,7 +101,7 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
ses.keys->recv.algo_mac = &dropbear_nohash;
|
||||
ses.keys->trans.algo_mac = &dropbear_nohash;
|
||||
|
||||
ses.keys->algo_kex = -1;
|
||||
ses.keys->algo_kex = NULL;
|
||||
ses.keys->algo_hostkey = -1;
|
||||
ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
|
||||
ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
|
||||
@@ -245,7 +245,16 @@ void session_cleanup() {
|
||||
ses.extra_session_cleanup();
|
||||
}
|
||||
|
||||
m_free(ses.session_id);
|
||||
if (ses.session_id) {
|
||||
buf_burn(ses.session_id);
|
||||
buf_free(ses.session_id);
|
||||
ses.session_id = NULL;
|
||||
}
|
||||
if (ses.hash) {
|
||||
buf_burn(ses.hash);
|
||||
buf_free(ses.hash);
|
||||
ses.hash = NULL;
|
||||
}
|
||||
m_burn(ses.keys, sizeof(struct key_context));
|
||||
m_free(ses.keys);
|
||||
|
||||
|
||||
@@ -695,7 +695,7 @@ AS_MKDIR_P(libtomcrypt/src/pk/dsa)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/ecc)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/pkcs1)
|
||||
AS_MKDIR_P(libtomcrypt/src/pk/rsa)
|
||||
AS_MKDIR_P(libtomcrypt/src/prng)
|
||||
AS_MKDIR_P(libtomcrypt/src/prngs)
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_OUTPUT(Makefile)
|
||||
AC_OUTPUT(libtomcrypt/Makefile)
|
||||
|
||||
75
crypto_desc.c
Normal file
75
crypto_desc.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.h"
|
||||
|
||||
#ifdef DROPBEAR_LTC_PRNG
|
||||
int dropbear_ltc_prng = -1;
|
||||
#endif
|
||||
|
||||
|
||||
/* Register the compiled in ciphers.
|
||||
* This should be run before using any of the ciphers/hashes */
|
||||
void crypto_init() {
|
||||
|
||||
const struct ltc_cipher_descriptor *regciphers[] = {
|
||||
#ifdef DROPBEAR_AES
|
||||
&aes_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_BLOWFISH
|
||||
&blowfish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_TWOFISH
|
||||
&twofish_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_3DES
|
||||
&des3_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct ltc_hash_descriptor *reghashes[] = {
|
||||
/* we need sha1 for hostkey stuff regardless */
|
||||
&sha1_desc,
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
&md5_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA256
|
||||
&sha256_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA384
|
||||
&sha384_desc,
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA512
|
||||
&sha512_desc,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; regciphers[i] != NULL; i++) {
|
||||
if (register_cipher(regciphers[i]) == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; reghashes[i] != NULL; i++) {
|
||||
if (register_hash(reghashes[i]) == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_LTC_PRNG
|
||||
dropbear_ltc_prng = register_prng(&dropbear_prng_desc);
|
||||
if (dropbear_ltc_prng == -1) {
|
||||
dropbear_exit("Error registering crypto");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
ltc_mp = ltm_desc;
|
||||
dropbear_ecc_fill_dp();
|
||||
#endif
|
||||
}
|
||||
|
||||
9
crypto_desc.h
Normal file
9
crypto_desc.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef _CRYPTO_DESC_H
|
||||
#define _CRYPTO_DESC_H
|
||||
|
||||
void crypto_init();
|
||||
|
||||
extern int dropbear_ltc_prng;
|
||||
|
||||
#endif // _CRYPTO_DESC_H
|
||||
|
||||
8
dbutil.c
8
dbutil.c
@@ -675,6 +675,14 @@ void printhex(const char * label, const unsigned char * buf, int len) {
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void printmpint(const char *label, mp_int *mp) {
|
||||
buffer *buf = buf_new(1000);
|
||||
buf_putmpint(buf, mp);
|
||||
printhex(label, buf->data, buf->len);
|
||||
buf_free(buf);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Strip all control characters from text (a null-terminated string), except
|
||||
|
||||
1
dbutil.h
1
dbutil.h
@@ -57,6 +57,7 @@ void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN;
|
||||
void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
|
||||
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
|
||||
void printhex(const char * label, const unsigned char * buf, int len);
|
||||
void printmpint(const char *label, mp_int *mp);
|
||||
extern int debug_trace;
|
||||
#endif
|
||||
|
||||
|
||||
3
debug.h
3
debug.h
@@ -40,6 +40,7 @@
|
||||
* since the printing may not sanitise strings etc. This will add a reasonable
|
||||
* amount to your executable size. */
|
||||
/* #define DEBUG_TRACE */
|
||||
#define DEBUG_TRACE
|
||||
|
||||
/* All functions writing to the cleartext payload buffer call
|
||||
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
|
||||
@@ -71,7 +72,7 @@
|
||||
|
||||
/* To debug with GDB it is easier to run with no forking of child processes.
|
||||
You will need to pass "-F" as well. */
|
||||
/* #define DEBUG_NOFORK */
|
||||
#define DEBUG_NOFORK
|
||||
|
||||
|
||||
/* For testing as non-root on shadowed systems, include the crypt of a password
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "keyimport.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "random.h"
|
||||
|
||||
|
||||
static int do_convert(int intype, const char* infile, int outtype,
|
||||
@@ -62,6 +64,9 @@ int main(int argc, char ** argv) {
|
||||
const char* infile;
|
||||
const char* outfile;
|
||||
|
||||
crypto_init();
|
||||
seedrandom();
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
/* It's hard for it to get in the way _too_ much */
|
||||
debug_trace = 1;
|
||||
@@ -111,7 +116,7 @@ static int do_convert(int intype, const char* infile, int outtype,
|
||||
const char* outfile) {
|
||||
|
||||
sign_key * key = NULL;
|
||||
char * keytype = NULL;
|
||||
const char * keytype = NULL;
|
||||
int ret = 1;
|
||||
|
||||
key = import_read(infile, NULL, intype);
|
||||
@@ -121,16 +126,7 @@ static int do_convert(int intype, const char* infile, int outtype,
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (key->rsakey != NULL) {
|
||||
keytype = "RSA";
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->dsskey != NULL) {
|
||||
keytype = "DSS";
|
||||
}
|
||||
#endif
|
||||
keytype = signkey_name_from_type(key->type, NULL);
|
||||
|
||||
fprintf(stderr, "Key is a %s key\n", keytype);
|
||||
|
||||
|
||||
123
dropbearkey.c
123
dropbearkey.c
@@ -51,11 +51,14 @@
|
||||
|
||||
#include "genrsa.h"
|
||||
#include "gendss.h"
|
||||
#include "ecdsa.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "random.h"
|
||||
|
||||
static void printhelp(char * progname);
|
||||
|
||||
#define RSA_SIZE (1024/8) /* 1024 bit */
|
||||
#define DSS_SIZE (1024/8) /* 1024 bit */
|
||||
#define RSA_DEFAULT_SIZE 1024
|
||||
#define DSS_DEFAULT_SIZE 1024
|
||||
|
||||
static void buf_writefile(buffer * buf, const char * filename);
|
||||
static void printpubkey(sign_key * key, int keytype);
|
||||
@@ -71,10 +74,28 @@ static void printhelp(char * progname) {
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
" dss\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
" ecdsa\n"
|
||||
#endif
|
||||
"-f filename Use filename for the secret key\n"
|
||||
"-s bits Key size in bits, should be a multiple of 8 (optional)\n"
|
||||
" (DSS has a fixed size of 1024 bits)\n"
|
||||
#ifdef DROPBEAR_DSS
|
||||
" DSS has a fixed size of 1024 bits\n"
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
" ECDSA has sizes "
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
"256 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
"384 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
"521 "
|
||||
#endif
|
||||
"\n"
|
||||
#endif
|
||||
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
|
||||
#ifdef DEBUG_TRACE
|
||||
"-v verbose\n"
|
||||
@@ -94,13 +115,15 @@ int main(int argc, char ** argv) {
|
||||
sign_key *key = NULL;
|
||||
buffer *buf = NULL;
|
||||
char * filename = NULL;
|
||||
int keytype = -1;
|
||||
enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
|
||||
char * typetext = NULL;
|
||||
char * sizetext = NULL;
|
||||
unsigned int bits;
|
||||
unsigned int keysize;
|
||||
int printpub = 0;
|
||||
|
||||
crypto_init();
|
||||
seedrandom();
|
||||
|
||||
/* get the commandline options */
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i] == NULL) {
|
||||
@@ -162,21 +185,9 @@ int main(int argc, char ** argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (strlen(typetext) == 3) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (strncmp(typetext, "rsa", 3) == 0) {
|
||||
keytype = DROPBEAR_SIGNKEY_RSA;
|
||||
TRACE(("type is rsa"))
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (strncmp(typetext, "dss", 3) == 0) {
|
||||
keytype = DROPBEAR_SIGNKEY_DSS;
|
||||
TRACE(("type is dss"))
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (keytype == -1) {
|
||||
keytype = signkey_type_from_name(typetext, strlen(typetext));
|
||||
|
||||
if (keytype == DROPBEAR_SIGNKEY_NONE) {
|
||||
fprintf(stderr, "Unknown key type '%s'\n", typetext);
|
||||
printhelp(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -188,28 +199,51 @@ int main(int argc, char ** argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS && bits != 1024) {
|
||||
fprintf(stderr, "DSS keys have a fixed size of 1024 bits\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
|
||||
fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
|
||||
" multiple of 8\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// TODO: put RSA and DSS size checks into genrsa.c etc
|
||||
switch (keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
|
||||
fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
|
||||
" multiple of 8\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
if (bits != 1024) {
|
||||
fprintf(stderr, "DSS keys have a fixed size of 1024 bits\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
(void)0; /* quiet, compiler. ecdsa handles checks itself */
|
||||
}
|
||||
|
||||
keysize = bits / 8;
|
||||
} else {
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS) {
|
||||
keysize = DSS_SIZE;
|
||||
} else if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
keysize = RSA_SIZE;
|
||||
} else {
|
||||
exit(EXIT_FAILURE); /* not reached */
|
||||
switch (keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
bits = RSA_DEFAULT_SIZE;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
bits = DSS_DEFAULT_SIZE;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
|
||||
bits = ECDSA_DEFAULT_SIZE;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
exit(EXIT_FAILURE); /* not reached */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", keysize*8,
|
||||
fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", bits,
|
||||
typetext, filename);
|
||||
|
||||
/* don't want the file readable by others */
|
||||
@@ -222,12 +256,21 @@ int main(int argc, char ** argv) {
|
||||
switch(keytype) {
|
||||
#ifdef DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
key->rsakey = gen_rsa_priv_key(keysize); /* 128 bytes = 1024 bit */
|
||||
key->rsakey = gen_rsa_priv_key(bits);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
key->dsskey = gen_dss_priv_key(keysize); /* 128 bytes = 1024 bit */
|
||||
key->dsskey = gen_dss_priv_key(bits);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
|
||||
{
|
||||
ecc_key *ecckey = gen_ecdsa_priv_key(bits);
|
||||
keytype = ecdsa_signkey_type(ecckey);
|
||||
*signkey_ecc_key_ptr(key, keytype) = ecckey;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
@@ -319,7 +362,7 @@ static void printpubkey(sign_key * key, int keytype) {
|
||||
fprintf(stderr, "base64 failed");
|
||||
}
|
||||
|
||||
typestring = signkey_name_from_type(keytype, &err);
|
||||
typestring = signkey_name_from_type(keytype, NULL);
|
||||
|
||||
fp = sign_key_fingerprint(buf_getptr(buf, len), len);
|
||||
|
||||
|
||||
21
dss.c
21
dss.c
@@ -47,11 +47,7 @@ int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
|
||||
|
||||
TRACE(("enter buf_get_dss_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
key->p = m_malloc(sizeof(mp_int));
|
||||
key->q = m_malloc(sizeof(mp_int));
|
||||
key->g = m_malloc(sizeof(mp_int));
|
||||
key->y = m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->p, key->q, key->g, key->y, NULL);
|
||||
m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, NULL);
|
||||
key->x = NULL;
|
||||
|
||||
buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
|
||||
@@ -87,8 +83,7 @@ int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
key->x = m_malloc(sizeof(mp_int));
|
||||
m_mp_init(key->x);
|
||||
m_mp_alloc_init_multi(&key->x, NULL);
|
||||
ret = buf_getmpint(buf, key->x);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(key->x);
|
||||
@@ -161,9 +156,7 @@ void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a DSS signature (in buf) made on data by the key given.
|
||||
* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
hash_state hs;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
@@ -187,7 +180,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data
|
||||
|
||||
/* hash the data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data, len);
|
||||
sha1_process(&hs, data_buf->data, data_buf->len);
|
||||
sha1_done(&hs, msghash);
|
||||
|
||||
/* create the signature - s' and r' are the received signatures in buf */
|
||||
@@ -260,9 +253,7 @@ out:
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer */
|
||||
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
unsigned int writelen;
|
||||
unsigned int i;
|
||||
@@ -279,7 +270,7 @@ void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* d
|
||||
|
||||
/* hash the data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data, len);
|
||||
sha1_process(&hs, data_buf->data, data_buf->len);
|
||||
sha1_done(&hs, msghash);
|
||||
|
||||
m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
|
||||
|
||||
8
dss.h
8
dss.h
@@ -30,8 +30,6 @@
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
|
||||
#define DSS_SIGNATURE_SIZE 4+SSH_SIGNKEY_DSS_LEN+4+2*SHA1_HASH_SIZE
|
||||
|
||||
typedef struct {
|
||||
|
||||
mp_int* p;
|
||||
@@ -43,11 +41,9 @@ typedef struct {
|
||||
|
||||
} dropbear_dss_key;
|
||||
|
||||
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
|
||||
#endif
|
||||
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key);
|
||||
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key);
|
||||
|
||||
271
ecc.c
Normal file
271
ecc.c
Normal file
@@ -0,0 +1,271 @@
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
#include "ecc.h"
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
|
||||
// .dp members are filled out by dropbear_ecc_fill_dp() at startup
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
struct dropbear_ecc_curve ecc_curve_nistp256 = {
|
||||
.ltc_size = 32,
|
||||
.hash_desc = &sha256_desc,
|
||||
.name = "nistp256"
|
||||
};
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
struct dropbear_ecc_curve ecc_curve_nistp384 = {
|
||||
.ltc_size = 48,
|
||||
.hash_desc = &sha384_desc,
|
||||
.name = "nistp384"
|
||||
};
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
struct dropbear_ecc_curve ecc_curve_nistp521 = {
|
||||
.ltc_size = 66,
|
||||
.hash_desc = &sha512_desc,
|
||||
.name = "nistp521"
|
||||
};
|
||||
#endif
|
||||
|
||||
struct dropbear_ecc_curve *dropbear_ecc_curves[] = {
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
&ecc_curve_nistp256,
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
&ecc_curve_nistp384,
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
&ecc_curve_nistp521,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
void dropbear_ecc_fill_dp() {
|
||||
struct dropbear_ecc_curve **curve;
|
||||
// libtomcrypt guarantees they're ordered by size
|
||||
const ltc_ecc_set_type *dp = ltc_ecc_sets;
|
||||
for (curve = dropbear_ecc_curves; *curve; curve++) {
|
||||
for (;dp->size > 0; dp++) {
|
||||
if (dp->size == (*curve)->ltc_size) {
|
||||
(*curve)->dp = dp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!(*curve)->dp) {
|
||||
dropbear_exit("Missing ECC params %s", (*curve)->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp) {
|
||||
struct dropbear_ecc_curve **curve = NULL;
|
||||
for (curve = dropbear_ecc_curves; *curve; curve++) {
|
||||
if ((*curve)->dp == dp) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(*curve);
|
||||
return *curve;
|
||||
}
|
||||
|
||||
ecc_key * new_ecc_key(void) {
|
||||
ecc_key *key = m_malloc(sizeof(*key));
|
||||
m_mp_alloc_init_multi(&key->pubkey.x, &key->pubkey.y,
|
||||
&key->pubkey.z, &key->k, NULL);
|
||||
return key;
|
||||
}
|
||||
|
||||
// Copied from libtomcrypt ecc_import.c (version there is static), modified
|
||||
// for different mp_int pointer without LTC_SOURCE
|
||||
static int ecc_is_point(ecc_key *key)
|
||||
{
|
||||
mp_int *prime, *b, *t1, *t2;
|
||||
int err;
|
||||
|
||||
prime = m_malloc(sizeof(mp_int));
|
||||
b = m_malloc(sizeof(mp_int));
|
||||
t1 = m_malloc(sizeof(mp_int));
|
||||
t2 = m_malloc(sizeof(mp_int));
|
||||
|
||||
m_mp_alloc_init_multi(&prime, &b, &t1, &t2, NULL);
|
||||
|
||||
/* load prime and b */
|
||||
if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute y^2 */
|
||||
if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute x^3 */
|
||||
if ((err = mp_sqr(key->pubkey.x, t2)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_mul(key->pubkey.x, t2, t2)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute y^2 - x^3 */
|
||||
if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK) { goto error; }
|
||||
|
||||
/* compute y^2 - x^3 + 3x */
|
||||
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
|
||||
if ((err = mp_mod(t1, prime, t1)) != CRYPT_OK) { goto error; }
|
||||
while (mp_cmp_d(t1, 0) == LTC_MP_LT) {
|
||||
if ((err = mp_add(t1, prime, t1)) != CRYPT_OK) { goto error; }
|
||||
}
|
||||
while (mp_cmp(t1, prime) != LTC_MP_LT) {
|
||||
if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK) { goto error; }
|
||||
}
|
||||
|
||||
/* compare to b */
|
||||
if (mp_cmp(t1, b) != LTC_MP_EQ) {
|
||||
err = CRYPT_INVALID_PACKET;
|
||||
} else {
|
||||
err = CRYPT_OK;
|
||||
}
|
||||
|
||||
error:
|
||||
mp_clear_multi(prime, b, t1, t2, NULL);
|
||||
m_free(prime);
|
||||
m_free(b);
|
||||
m_free(t1);
|
||||
m_free(t2);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
|
||||
void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key) {
|
||||
unsigned long len = key->dp->size*2 + 1;
|
||||
buf_putint(buf, len);
|
||||
int err = ecc_ansi_x963_export(key, buf_getwriteptr(buf, len), &len);
|
||||
if (err != CRYPT_OK) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
buf_incrwritepos(buf, len);
|
||||
}
|
||||
|
||||
/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
|
||||
ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve) {
|
||||
ecc_key *key = NULL;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
const unsigned int size = curve->dp->size;
|
||||
unsigned char first;
|
||||
|
||||
TRACE(("enter buf_get_ecc_raw_pubkey"))
|
||||
|
||||
buf_setpos(buf, 0);
|
||||
first = buf_getbyte(buf);
|
||||
if (first == 2 || first == 3) {
|
||||
dropbear_log(LOG_WARNING, "Dropbear doesn't support ECC point compression");
|
||||
return NULL;
|
||||
}
|
||||
if (first != 4 || buf->len != 1+2*size) {
|
||||
TRACE(("leave, wrong size"))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key = new_ecc_key();
|
||||
key->dp = curve->dp;
|
||||
|
||||
if (mp_read_unsigned_bin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
TRACE(("failed to read x"))
|
||||
goto out;
|
||||
}
|
||||
buf_incrpos(buf, size);
|
||||
|
||||
if (mp_read_unsigned_bin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
TRACE(("failed to read y"))
|
||||
goto out;
|
||||
}
|
||||
buf_incrpos(buf, size);
|
||||
|
||||
mp_set(key->pubkey.z, 1);
|
||||
|
||||
if (ecc_is_point(key) != CRYPT_OK) {
|
||||
TRACE(("failed, not a point"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
// SEC1 3.2.3.1 Check that Q != 0
|
||||
if (mp_cmp_d(key->pubkey.x, 0) == LTC_MP_EQ) {
|
||||
TRACE(("failed, x == 0"))
|
||||
goto out;
|
||||
}
|
||||
if (mp_cmp_d(key->pubkey.y, 0) == LTC_MP_EQ) {
|
||||
TRACE(("failed, y == 0"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
if (key) {
|
||||
ecc_free(key);
|
||||
m_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
|
||||
}
|
||||
|
||||
// a modified version of libtomcrypt's "ecc_shared_secret" to output
|
||||
// a mp_int instead.
|
||||
mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, ecc_key *private_key)
|
||||
{
|
||||
ecc_point *result = NULL;
|
||||
mp_int *prime = NULL, *shared_secret = NULL;
|
||||
int err = DROPBEAR_FAILURE;
|
||||
|
||||
/* type valid? */
|
||||
if (private_key->type != PK_PRIVATE) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (private_key->dp != public_key->dp) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* make new point */
|
||||
result = ltc_ecc_new_point();
|
||||
if (result == NULL) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
prime = m_malloc(sizeof(*prime));
|
||||
m_mp_init(prime);
|
||||
|
||||
if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) {
|
||||
goto done;
|
||||
}
|
||||
if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = DROPBEAR_SUCCESS;
|
||||
done:
|
||||
if (err == DROPBEAR_SUCCESS) {
|
||||
shared_secret = m_malloc(sizeof(*shared_secret));
|
||||
m_mp_init(shared_secret);
|
||||
mp_copy(result->x, shared_secret);
|
||||
}
|
||||
|
||||
if (prime) {
|
||||
mp_clear(prime);
|
||||
m_free(prime);
|
||||
}
|
||||
if (result)
|
||||
{
|
||||
ltc_ecc_del_point(result);
|
||||
}
|
||||
|
||||
if (err == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
return shared_secret;
|
||||
}
|
||||
|
||||
#endif
|
||||
36
ecc.h
Normal file
36
ecc.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef _DROPBEAR_ECC_H
|
||||
#define _DROPBEAR_ECC_H
|
||||
|
||||
#include "includes.h"
|
||||
#include "options.h"
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
|
||||
struct dropbear_ecc_curve {
|
||||
int ltc_size; // to match the byte sizes in ltc_ecc_sets[]
|
||||
const ltc_ecc_set_type *dp; // curve domain parameters
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
const unsigned char *name;
|
||||
};
|
||||
|
||||
extern struct dropbear_ecc_curve ecc_curve_nistp256;
|
||||
extern struct dropbear_ecc_curve ecc_curve_nistp384;
|
||||
extern struct dropbear_ecc_curve ecc_curve_nistp521;
|
||||
extern struct dropbear_ecc_curve *dropbear_ecc_curves[];
|
||||
|
||||
void dropbear_ecc_fill_dp();
|
||||
struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp);
|
||||
|
||||
// "pubkey" refers to a point, but LTC uses ecc_key structure for both public
|
||||
// and private keys
|
||||
void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key);
|
||||
ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve);
|
||||
int buf_get_ecc_privkey_string(buffer *buf, ecc_key *key);
|
||||
|
||||
mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _DROPBEAR_ECC_H
|
||||
412
ecdsa.c
Normal file
412
ecdsa.c
Normal file
@@ -0,0 +1,412 @@
|
||||
#include "options.h"
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "ecc.h"
|
||||
#include "ecdsa.h"
|
||||
#include "signkey.h"
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
|
||||
enum signkey_type ecdsa_signkey_type(ecc_key * key) {
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
if (key->dp == ecc_curve_nistp256.dp) {
|
||||
return DROPBEAR_SIGNKEY_ECDSA_NISTP256;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
if (key->dp == ecc_curve_nistp384.dp) {
|
||||
return DROPBEAR_SIGNKEY_ECDSA_NISTP384;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
if (key->dp == ecc_curve_nistp521.dp) {
|
||||
return DROPBEAR_SIGNKEY_ECDSA_NISTP521;
|
||||
}
|
||||
#endif
|
||||
return DROPBEAR_SIGNKEY_NONE;
|
||||
}
|
||||
|
||||
ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) {
|
||||
const ltc_ecc_set_type *dp = NULL; // curve domain parameters
|
||||
switch (bit_size) {
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
case 256:
|
||||
dp = ecc_curve_nistp256.dp;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
case 384:
|
||||
dp = ecc_curve_nistp384.dp;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
case 521:
|
||||
dp = ecc_curve_nistp521.dp;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (!dp) {
|
||||
dropbear_exit("Key size %d isn't valid. Try "
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
"256 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
"384 "
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
"521 "
|
||||
#endif
|
||||
, bit_size);
|
||||
}
|
||||
|
||||
ecc_key *new_key = m_malloc(sizeof(*new_key));
|
||||
if (ecc_make_key_ex(NULL, dropbear_ltc_prng, new_key, dp) != CRYPT_OK) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
return new_key;
|
||||
}
|
||||
|
||||
ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
|
||||
unsigned char *key_ident = NULL, *identifier = NULL;
|
||||
unsigned int key_ident_len, identifier_len;
|
||||
buffer *q_buf = NULL;
|
||||
struct dropbear_ecc_curve **curve;
|
||||
ecc_key *new_key = NULL;
|
||||
|
||||
// string "ecdsa-sha2-[identifier]"
|
||||
key_ident = buf_getstring(buf, &key_ident_len);
|
||||
// string "[identifier]"
|
||||
identifier = buf_getstring(buf, &identifier_len);
|
||||
|
||||
if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
|
||||
TRACE(("Bad identifier lengths"))
|
||||
goto out;
|
||||
}
|
||||
if (memcmp(&key_ident[strlen("ecdsa-sha2-")], identifier, identifier_len) != 0) {
|
||||
TRACE(("mismatching identifiers"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (curve = dropbear_ecc_curves; *curve; curve++) {
|
||||
if (memcmp(identifier, (char*)(*curve)->name, strlen((char*)(*curve)->name)) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!*curve) {
|
||||
TRACE(("couldn't match ecc curve"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
// string Q
|
||||
q_buf = buf_getstringbuf(buf);
|
||||
new_key = buf_get_ecc_raw_pubkey(q_buf, *curve);
|
||||
|
||||
out:
|
||||
m_free(key_ident);
|
||||
m_free(identifier);
|
||||
if (q_buf) {
|
||||
buf_free(q_buf);
|
||||
q_buf = NULL;
|
||||
}
|
||||
TRACE(("leave buf_get_ecdsa_pub_key"))
|
||||
return new_key;
|
||||
}
|
||||
|
||||
ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
|
||||
ecc_key *new_key = NULL;
|
||||
TRACE(("enter buf_get_ecdsa_priv_key"))
|
||||
new_key = buf_get_ecdsa_pub_key(buf);
|
||||
if (!new_key) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) {
|
||||
ecc_free(new_key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new_key;
|
||||
}
|
||||
|
||||
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
|
||||
struct dropbear_ecc_curve *curve = NULL;
|
||||
unsigned char key_ident[30];
|
||||
|
||||
curve = curve_for_dp(key->dp);
|
||||
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
buf_putstring(buf, key_ident, strlen(key_ident));
|
||||
buf_putstring(buf, curve->name, strlen(curve->name));
|
||||
buf_put_ecc_raw_pubkey_string(buf, key);
|
||||
}
|
||||
|
||||
void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key) {
|
||||
buf_put_ecdsa_pub_key(buf, key);
|
||||
buf_putmpint(buf, key->k);
|
||||
}
|
||||
|
||||
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
/* Based on libtomcrypt's ecc_sign_hash but without the asn1 */
|
||||
int err = DROPBEAR_FAILURE;
|
||||
struct dropbear_ecc_curve *curve = NULL;
|
||||
hash_state hs;
|
||||
unsigned char hash[64];
|
||||
void *e = NULL, *p = NULL, *s = NULL, *r;
|
||||
unsigned char key_ident[30];
|
||||
buffer *sigbuf = NULL;
|
||||
|
||||
TRACE(("buf_put_ecdsa_sign"))
|
||||
curve = curve_for_dp(key->dp);
|
||||
|
||||
if (ltc_init_multi(&r, &s, &p, &e, NULL) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
curve->hash_desc->init(&hs);
|
||||
curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
|
||||
curve->hash_desc->done(&hs, hash);
|
||||
|
||||
if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
ecc_key R_key; // ephemeral key
|
||||
if (ecc_make_key_ex(NULL, dropbear_ltc_prng, &R_key, key->dp) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.mpdiv(R_key.pubkey.x, p, NULL, r) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ) {
|
||||
// try again
|
||||
ecc_free(&R_key);
|
||||
continue;
|
||||
}
|
||||
/* k = 1/k */
|
||||
if (ltc_mp.invmod(R_key.k, p, R_key.k) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
/* s = xr */
|
||||
if (ltc_mp.mulmod(key->k, r, p, s) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
/* s = e + xr */
|
||||
if (ltc_mp.add(e, s, s) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.mpdiv(s, p, NULL, s) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
/* s = (e + xr)/k */
|
||||
if (ltc_mp.mulmod(s, R_key.k, p, s) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
ecc_free(&R_key);
|
||||
|
||||
if (ltc_mp.compare_d(s, 0) != LTC_MP_EQ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
|
||||
buf_putstring(buf, key_ident, strlen(key_ident));
|
||||
// enough for nistp521
|
||||
sigbuf = buf_new(200);
|
||||
buf_putmpint(sigbuf, (mp_int*)r);
|
||||
buf_putmpint(sigbuf, (mp_int*)s);
|
||||
buf_putbufstring(buf, sigbuf);
|
||||
|
||||
err = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
if (r && s && p && e) {
|
||||
ltc_deinit_multi(r, s, p, e, NULL);
|
||||
}
|
||||
|
||||
if (sigbuf) {
|
||||
buf_free(sigbuf);
|
||||
}
|
||||
|
||||
if (err == DROPBEAR_FAILURE) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
}
|
||||
|
||||
// returns values in s and r
|
||||
// returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
|
||||
static int buf_get_ecdsa_verify_params(buffer *buf, struct dropbear_ecc_curve *curve,
|
||||
void *r, void* s) {
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
unsigned int sig_len;
|
||||
unsigned int sig_pos;
|
||||
|
||||
sig_len = buf_getint(buf);
|
||||
sig_pos = buf->pos;
|
||||
if (buf_getmpint(buf, r) != DROPBEAR_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
if (buf_getmpint(buf, s) != DROPBEAR_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
if (buf->pos - sig_pos != sig_len) {
|
||||
goto out;
|
||||
}
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
|
||||
/* Based on libtomcrypt's ecc_verify_hash but without the asn1 */
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
hash_state hs;
|
||||
struct dropbear_ecc_curve *curve = NULL;
|
||||
unsigned char hash[64];
|
||||
ecc_point *mG = NULL, *mQ = NULL;
|
||||
void *r = NULL, *s = NULL, *v = NULL, *w = NULL, *u1 = NULL, *u2 = NULL,
|
||||
*e = NULL, *p = NULL, *m = NULL;
|
||||
void *mp = NULL;
|
||||
|
||||
/* verify
|
||||
*
|
||||
* w = s^-1 mod n
|
||||
* u1 = xw
|
||||
* u2 = rw
|
||||
* X = u1*G + u2*Q
|
||||
* v = X_x1 mod n
|
||||
* accept if v == r
|
||||
*/
|
||||
|
||||
TRACE(("buf_ecdsa_verify"))
|
||||
curve = curve_for_dp(key->dp);
|
||||
|
||||
mG = ltc_ecc_new_point();
|
||||
mQ = ltc_ecc_new_point();
|
||||
if (ltc_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL) != CRYPT_OK
|
||||
|| !mG
|
||||
|| !mQ) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
|
||||
if (buf_get_ecdsa_verify_params(buf, curve, r, s) != DROPBEAR_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
curve->hash_desc->init(&hs);
|
||||
curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
|
||||
curve->hash_desc->done(&hs, hash);
|
||||
|
||||
if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* get the order */
|
||||
if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* get the modulus */
|
||||
if (ltc_mp.read_radix(m, (char *)key->dp->prime, 16) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check for zero */
|
||||
if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ
|
||||
|| ltc_mp.compare_d(s, 0) == LTC_MP_EQ
|
||||
|| ltc_mp.compare(r, p) != LTC_MP_LT
|
||||
|| ltc_mp.compare(s, p) != LTC_MP_LT) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* w = s^-1 mod n */
|
||||
if (ltc_mp.invmod(s, p, w) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* u1 = ew */
|
||||
if (ltc_mp.mulmod(e, w, p, u1) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* u2 = rw */
|
||||
if (ltc_mp.mulmod(r, w, p, u2) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* find mG and mQ */
|
||||
if (ltc_mp.read_radix(mG->x, (char *)key->dp->Gx, 16) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.read_radix(mG->y, (char *)key->dp->Gy, 16) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.set_int(mG->z, 1) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ltc_mp.copy(key->pubkey.x, mQ->x) != CRYPT_OK
|
||||
|| ltc_mp.copy(key->pubkey.y, mQ->y) != CRYPT_OK
|
||||
|| ltc_mp.copy(key->pubkey.z, mQ->z) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* compute u1*mG + u2*mQ = mG */
|
||||
if (ltc_mp.ecc_mul2add == NULL) {
|
||||
if (ltc_mp.ecc_ptmul(u1, mG, mG, m, 0) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
if (ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* find the montgomery mp */
|
||||
if (ltc_mp.montgomery_setup(m, &mp) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* add them */
|
||||
if (ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* reduce */
|
||||
if (ltc_mp.ecc_map(mG, m, mp) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
|
||||
if (ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* v = X_x1 mod n */
|
||||
if (ltc_mp.mpdiv(mG->x, p, NULL, v) != CRYPT_OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* does v == r */
|
||||
if (ltc_mp.compare(v, r) == LTC_MP_EQ) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
out:
|
||||
ltc_ecc_del_point(mG);
|
||||
ltc_ecc_del_point(mQ);
|
||||
mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL);
|
||||
if (mp != NULL) {
|
||||
ltc_mp.montgomery_deinit(mp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // DROPBEAR_ECDSA
|
||||
32
ecdsa.h
Normal file
32
ecdsa.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef _ECDSA_H_
|
||||
#define _ECDSA_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "signkey.h"
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
|
||||
#if defined(DROPBEAR_ECC_256)
|
||||
#define ECDSA_DEFAULT_SIZE 256
|
||||
#elif defined(DROPBEAR_ECC_384)
|
||||
#define ECDSA_DEFAULT_SIZE 384
|
||||
#elif defined(DROPBEAR_ECC_521)
|
||||
#define ECDSA_DEFAULT_SIZE 521
|
||||
#else
|
||||
#define ECDSA_DEFAULT_SIZE 0
|
||||
#endif
|
||||
|
||||
ecc_key *gen_ecdsa_priv_key(unsigned int bit_size);
|
||||
ecc_key *buf_get_ecdsa_pub_key(buffer* buf);
|
||||
ecc_key *buf_get_ecdsa_priv_key(buffer *buf);
|
||||
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key);
|
||||
void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key);
|
||||
enum signkey_type ecdsa_signkey_type(ecc_key * key);
|
||||
|
||||
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf);
|
||||
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _ECDSA_H_
|
||||
15
gendss.c
15
gendss.c
@@ -47,19 +47,16 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
|
||||
dropbear_dss_key *key;
|
||||
|
||||
if (size != 1024) {
|
||||
dropbear_exit("DSS keys have a fixed size of 1024 bits");
|
||||
}
|
||||
|
||||
key = m_malloc(sizeof(*key));
|
||||
|
||||
key->p = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->q = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->g = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->y = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->x = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->p, key->q, key->g, key->y, key->x, NULL);
|
||||
|
||||
seedrandom();
|
||||
m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
|
||||
|
||||
getq(key);
|
||||
getp(key, size);
|
||||
getp(key, size/8);
|
||||
getg(key);
|
||||
getx(key);
|
||||
gety(key);
|
||||
|
||||
34
genrsa.c
34
genrsa.c
@@ -34,7 +34,7 @@
|
||||
#ifdef DROPBEAR_RSA
|
||||
|
||||
static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
mp_int* rsa_e, unsigned int size);
|
||||
mp_int* rsa_e, unsigned int size_bytes);
|
||||
|
||||
/* mostly taken from libtomcrypt's rsa key generation routine */
|
||||
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
@@ -44,26 +44,22 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
DEF_MP_INT(qminus);
|
||||
DEF_MP_INT(lcm);
|
||||
|
||||
if (size < 512 || size > 4096 || (size % 8 != 0)) {
|
||||
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
|
||||
" multiple of 8");
|
||||
}
|
||||
|
||||
key = m_malloc(sizeof(*key));
|
||||
|
||||
key->e = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->n = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->d = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->p = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
key->q = (mp_int*)m_malloc(sizeof(mp_int));
|
||||
|
||||
m_mp_init_multi(key->e, key->n, key->d, key->p, key->q,
|
||||
&pminus, &lcm, &qminus, NULL);
|
||||
|
||||
seedrandom();
|
||||
m_mp_alloc_init_multi(&key->e, &key->n, &key->d, &key->p, &key->q, NULL);
|
||||
m_mp_init_multi(&pminus, &lcm, &qminus, NULL);
|
||||
|
||||
if (mp_set_int(key->e, RSA_E) != MP_OKAY) {
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
getrsaprime(key->p, &pminus, key->e, size/2);
|
||||
getrsaprime(key->q, &qminus, key->e, size/2);
|
||||
getrsaprime(key->p, &pminus, key->e, size/16);
|
||||
getrsaprime(key->q, &qminus, key->e, size/16);
|
||||
|
||||
if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
@@ -90,21 +86,21 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
|
||||
/* return a prime suitable for p or q */
|
||||
static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
mp_int* rsa_e, unsigned int size) {
|
||||
mp_int* rsa_e, unsigned int size_bytes) {
|
||||
|
||||
unsigned char *buf;
|
||||
DEF_MP_INT(temp_gcd);
|
||||
|
||||
buf = (unsigned char*)m_malloc(size+1);
|
||||
buf = (unsigned char*)m_malloc(size_bytes+1);
|
||||
|
||||
m_mp_init(&temp_gcd);
|
||||
do {
|
||||
/* generate a random odd number with MSB set, then find the
|
||||
the next prime above it */
|
||||
genrandom(buf, size+1);
|
||||
genrandom(buf, size_bytes+1);
|
||||
buf[0] |= 0x80; /* MSB set */
|
||||
|
||||
bytes_to_mp(prime, buf, size+1);
|
||||
bytes_to_mp(prime, buf, size_bytes+1);
|
||||
|
||||
/* find the next integer which is prime, 8 round of miller-rabin */
|
||||
if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
|
||||
@@ -126,7 +122,7 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
|
||||
/* now we have a good value for result */
|
||||
mp_clear(&temp_gcd);
|
||||
m_burn(buf, size+1);
|
||||
m_burn(buf, size_bytes+1);
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
|
||||
29
kex.h
29
kex.h
@@ -27,16 +27,26 @@
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
#include "signkey.h"
|
||||
|
||||
void send_msg_kexinit();
|
||||
void recv_msg_kexinit();
|
||||
void send_msg_newkeys();
|
||||
void recv_msg_newkeys();
|
||||
void kexfirstinitialise();
|
||||
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv);
|
||||
void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
|
||||
|
||||
struct kex_dh_param *gen_kexdh_param();
|
||||
void free_kexdh_param(struct kex_dh_param *param);
|
||||
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
sign_key *hostkey);
|
||||
|
||||
#ifdef DROPBEAR_ECDH
|
||||
struct kex_ecdh_param *gen_kexecdh_param();
|
||||
void free_kexecdh_param(struct kex_ecdh_param *param);
|
||||
void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
sign_key *hostkey);
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_ZLIB
|
||||
int is_compress_trans();
|
||||
int is_compress_recv();
|
||||
@@ -66,6 +76,21 @@ struct KEXState {
|
||||
|
||||
};
|
||||
|
||||
#define DH_P_1_LEN 128
|
||||
extern const unsigned char dh_p_1[DH_P_1_LEN];
|
||||
#define DH_P_14_LEN 256
|
||||
extern const unsigned char dh_p_14[DH_P_14_LEN];
|
||||
|
||||
struct kex_dh_param {
|
||||
mp_int pub; /* e */
|
||||
mp_int priv; /* x */
|
||||
};
|
||||
|
||||
#ifdef DROPBEAR_ECDH
|
||||
struct kex_ecdh_param {
|
||||
ecc_key key;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define MAX_KEXHASHBUF 2000
|
||||
|
||||
|
||||
607
keyimport.c
607
keyimport.c
@@ -2,8 +2,6 @@
|
||||
* Based on PuTTY's import.c for importing/exporting OpenSSH and SSH.com
|
||||
* keyfiles.
|
||||
*
|
||||
* The horribleness of the code is probably mine (matt).
|
||||
*
|
||||
* Modifications copyright 2003 Matt Johnston
|
||||
*
|
||||
* PuTTY is copyright 1997-2003 Simon Tatham.
|
||||
@@ -36,6 +34,11 @@
|
||||
#include "bignum.h"
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "ecc.h"
|
||||
|
||||
static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
|
||||
static const unsigned char OID_SEC384R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
|
||||
static const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
|
||||
|
||||
#define PUT_32BIT(cp, value) do { \
|
||||
(cp)[3] = (unsigned char)(value); \
|
||||
@@ -125,6 +128,8 @@ static sign_key *dropbear_read(const char* filename) {
|
||||
}
|
||||
buf_free(buf);
|
||||
|
||||
ret->type = type;
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
@@ -140,25 +145,13 @@ error:
|
||||
/* returns 0 on fail, 1 on success */
|
||||
static int dropbear_write(const char*filename, sign_key * key) {
|
||||
|
||||
int keytype = -1;
|
||||
buffer * buf;
|
||||
FILE*fp;
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (key->rsakey != NULL) {
|
||||
keytype = DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->dsskey != NULL) {
|
||||
keytype = DROPBEAR_SIGNKEY_DSS;
|
||||
}
|
||||
#endif
|
||||
|
||||
buf = buf_new(MAX_PRIVKEY_SIZE);
|
||||
buf_put_priv_key(buf, key, keytype);
|
||||
buf_put_priv_key(buf, key, key->type);
|
||||
|
||||
fp = fopen(filename, "w");
|
||||
if (!fp) {
|
||||
@@ -349,7 +342,7 @@ struct mpint_pos { void *start; int bytes; };
|
||||
* Code to read and write OpenSSH private keys.
|
||||
*/
|
||||
|
||||
enum { OSSH_DSA, OSSH_RSA };
|
||||
enum { OSSH_DSA, OSSH_RSA, OSSH_EC };
|
||||
struct openssh_key {
|
||||
int type;
|
||||
int encrypted;
|
||||
@@ -392,6 +385,8 @@ static struct openssh_key *load_openssh_key(const char *filename)
|
||||
ret->type = OSSH_RSA;
|
||||
else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n"))
|
||||
ret->type = OSSH_DSA;
|
||||
else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n"))
|
||||
ret->type = OSSH_EC;
|
||||
else {
|
||||
errmsg = "Unrecognised key type";
|
||||
goto error;
|
||||
@@ -521,6 +516,8 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
sign_key *retkey;
|
||||
buffer * blobbuf = NULL;
|
||||
|
||||
retkey = new_sign_key();
|
||||
|
||||
key = load_openssh_key(filename);
|
||||
|
||||
if (!key)
|
||||
@@ -597,6 +594,8 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
num_integers = 9;
|
||||
else if (key->type == OSSH_DSA)
|
||||
num_integers = 6;
|
||||
else if (key->type == OSSH_EC)
|
||||
num_integers = 1;
|
||||
|
||||
/*
|
||||
* Space to create key blob in.
|
||||
@@ -605,8 +604,10 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
|
||||
if (key->type == OSSH_DSA) {
|
||||
buf_putstring(blobbuf, "ssh-dss", 7);
|
||||
retkey->type = DROPBEAR_SIGNKEY_DSS;
|
||||
} else if (key->type == OSSH_RSA) {
|
||||
buf_putstring(blobbuf, "ssh-rsa", 7);
|
||||
retkey->type = DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_integers; i++) {
|
||||
@@ -620,11 +621,18 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
/*
|
||||
* The first integer should be zero always (I think
|
||||
* this is some sort of version indication).
|
||||
*/
|
||||
if (len != 1 || p[0] != 0) {
|
||||
/* First integer is a version indicator */
|
||||
int expected;
|
||||
switch (key->type) {
|
||||
case OSSH_RSA:
|
||||
case OSSH_DSA:
|
||||
expected = 0;
|
||||
break;
|
||||
case OSSH_EC:
|
||||
expected = 1;
|
||||
break;
|
||||
}
|
||||
if (len != 1 || p[0] != expected) {
|
||||
errmsg = "Version number mismatch";
|
||||
goto error;
|
||||
}
|
||||
@@ -655,21 +663,126 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
|
||||
p += len;
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (key->type == OSSH_EC) {
|
||||
unsigned char* private_key_bytes = NULL;
|
||||
int private_key_len = 0;
|
||||
unsigned char* public_key_bytes = NULL;
|
||||
int public_key_len = 0;
|
||||
ecc_key *ecc = NULL;
|
||||
const struct dropbear_ecc_curve *curve = NULL;
|
||||
|
||||
// See SEC1 v2, Appendix C.4
|
||||
// OpenSSL (so OpenSSH) seems to include the optional parts.
|
||||
|
||||
// privateKey OCTET STRING,
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
&id, &len, &flags);
|
||||
p += ret;
|
||||
// id==4 for octet string
|
||||
if (ret < 0 || id != 4 ||
|
||||
key->keyblob+key->keyblob_len-p < len) {
|
||||
errmsg = "ASN.1 decoding failure";
|
||||
goto error;
|
||||
}
|
||||
private_key_bytes = p;
|
||||
private_key_len = len;
|
||||
p += len;
|
||||
|
||||
// parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
&id, &len, &flags);
|
||||
p += ret;
|
||||
// id==0
|
||||
if (ret < 0 || id != 0) {
|
||||
errmsg = "ASN.1 decoding failure";
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
&id, &len, &flags);
|
||||
p += ret;
|
||||
// id==6 for object
|
||||
if (ret < 0 || id != 6 ||
|
||||
key->keyblob+key->keyblob_len-p < len) {
|
||||
errmsg = "ASN.1 decoding failure";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (len == sizeof(OID_SEC256R1_BLOB)
|
||||
&& memcmp(p, OID_SEC256R1_BLOB, len) == 0) {
|
||||
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
|
||||
curve = &ecc_curve_nistp256;
|
||||
} else if (len == sizeof(OID_SEC384R1_BLOB)
|
||||
&& memcmp(p, OID_SEC384R1_BLOB, len) == 0) {
|
||||
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP384;
|
||||
curve = &ecc_curve_nistp384;
|
||||
} else if (len == sizeof(OID_SEC521R1_BLOB)
|
||||
&& memcmp(p, OID_SEC521R1_BLOB, len) == 0) {
|
||||
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP521;
|
||||
curve = &ecc_curve_nistp521;
|
||||
} else {
|
||||
errmsg = "Unknown ECC key type";
|
||||
goto error;
|
||||
}
|
||||
p += len;
|
||||
|
||||
// publicKey [1] BIT STRING OPTIONAL
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
&id, &len, &flags);
|
||||
p += ret;
|
||||
// id==1
|
||||
if (ret < 0 || id != 1) {
|
||||
errmsg = "ASN.1 decoding failure";
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
|
||||
&id, &len, &flags);
|
||||
p += ret;
|
||||
// id==3 for bit string
|
||||
if (ret < 0 || id != 3 ||
|
||||
key->keyblob+key->keyblob_len-p < len) {
|
||||
errmsg = "ASN.1 decoding failure";
|
||||
goto error;
|
||||
}
|
||||
public_key_bytes = p+1;
|
||||
public_key_len = len-1;
|
||||
p += len;
|
||||
|
||||
buf_putbytes(blobbuf, public_key_bytes, public_key_len);
|
||||
ecc = buf_get_ecc_raw_pubkey(blobbuf, curve);
|
||||
if (!ecc) {
|
||||
errmsg = "Error parsing ECC key";
|
||||
goto error;
|
||||
}
|
||||
m_mp_alloc_init_multi((mp_int**)&ecc->k, NULL);
|
||||
if (mp_read_unsigned_bin(ecc->k, private_key_bytes, private_key_len)
|
||||
!= MP_OKAY) {
|
||||
errmsg = "Error parsing ECC key";
|
||||
goto error;
|
||||
}
|
||||
|
||||
*signkey_ecc_key_ptr(retkey, retkey->type) = ecc;
|
||||
}
|
||||
#endif // DROPBEAR_ECDSA
|
||||
|
||||
/*
|
||||
* Now put together the actual key. Simplest way to do this is
|
||||
* to assemble our own key blobs and feed them to the createkey
|
||||
* functions; this is a bit faffy but it does mean we get all
|
||||
* the sanity checks for free.
|
||||
*/
|
||||
retkey = new_sign_key();
|
||||
buf_setpos(blobbuf, 0);
|
||||
type = DROPBEAR_SIGNKEY_ANY;
|
||||
if (buf_get_priv_key(blobbuf, retkey, &type)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
errmsg = "unable to create key structure";
|
||||
sign_key_free(retkey);
|
||||
retkey = NULL;
|
||||
goto error;
|
||||
if (key->type == OSSH_RSA || key->type == OSSH_DSA) {
|
||||
buf_setpos(blobbuf, 0);
|
||||
type = DROPBEAR_SIGNKEY_ANY;
|
||||
if (buf_get_priv_key(blobbuf, retkey, &type)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
errmsg = "unable to create key structure";
|
||||
sign_key_free(retkey);
|
||||
retkey = NULL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
errmsg = NULL; /* no error */
|
||||
@@ -703,202 +816,282 @@ static int openssh_write(const char *filename, sign_key *key,
|
||||
char zero[1];
|
||||
int ret = 0;
|
||||
FILE *fp;
|
||||
int keytype = -1;
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */
|
||||
|
||||
if (key->rsakey != NULL) {
|
||||
keytype = DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->dsskey != NULL) {
|
||||
keytype = DROPBEAR_SIGNKEY_DSS;
|
||||
}
|
||||
#endif
|
||||
|
||||
dropbear_assert(keytype != -1);
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA || key->type == DROPBEAR_SIGNKEY_DSS)
|
||||
{
|
||||
/*
|
||||
* Fetch the key blobs.
|
||||
*/
|
||||
keyblob = buf_new(3000);
|
||||
buf_put_priv_key(keyblob, key, key->type);
|
||||
|
||||
/*
|
||||
* Fetch the key blobs.
|
||||
*/
|
||||
keyblob = buf_new(3000);
|
||||
buf_put_priv_key(keyblob, key, keytype);
|
||||
buf_setpos(keyblob, 0);
|
||||
/* skip the "ssh-rsa" or "ssh-dss" header */
|
||||
buf_incrpos(keyblob, buf_getint(keyblob));
|
||||
|
||||
buf_setpos(keyblob, 0);
|
||||
/* skip the "ssh-rsa" or "ssh-dss" header */
|
||||
buf_incrpos(keyblob, buf_getint(keyblob));
|
||||
/*
|
||||
* Find the sequence of integers to be encoded into the OpenSSH
|
||||
* key blob, and also decide on the header line.
|
||||
*/
|
||||
numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
|
||||
|
||||
/*
|
||||
* Find the sequence of integers to be encoded into the OpenSSH
|
||||
* key blob, and also decide on the header line.
|
||||
*/
|
||||
numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
if (key->rsakey->p == NULL || key->rsakey->q == NULL) {
|
||||
fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (key->rsakey->p == NULL || key->rsakey->q == NULL) {
|
||||
fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
|
||||
goto error;
|
||||
/* e */
|
||||
numbers[2].bytes = buf_getint(keyblob);
|
||||
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
|
||||
buf_incrpos(keyblob, numbers[2].bytes);
|
||||
|
||||
/* n */
|
||||
numbers[1].bytes = buf_getint(keyblob);
|
||||
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
|
||||
buf_incrpos(keyblob, numbers[1].bytes);
|
||||
|
||||
/* d */
|
||||
numbers[3].bytes = buf_getint(keyblob);
|
||||
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
|
||||
buf_incrpos(keyblob, numbers[3].bytes);
|
||||
|
||||
/* p */
|
||||
numbers[4].bytes = buf_getint(keyblob);
|
||||
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
|
||||
buf_incrpos(keyblob, numbers[4].bytes);
|
||||
|
||||
/* q */
|
||||
numbers[5].bytes = buf_getint(keyblob);
|
||||
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
|
||||
buf_incrpos(keyblob, numbers[5].bytes);
|
||||
|
||||
/* now calculate some extra parameters: */
|
||||
m_mp_init(&tmpval);
|
||||
m_mp_init(&dmp1);
|
||||
m_mp_init(&dmq1);
|
||||
m_mp_init(&iqmp);
|
||||
|
||||
/* dmp1 = d mod (p-1) */
|
||||
if (mp_sub_d(key->rsakey->p, 1, &tmpval) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for p-1\n");
|
||||
goto error;
|
||||
}
|
||||
if (mp_mod(key->rsakey->d, &tmpval, &dmp1) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for dmp1\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* dmq1 = d mod (q-1) */
|
||||
if (mp_sub_d(key->rsakey->q, 1, &tmpval) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for q-1\n");
|
||||
goto error;
|
||||
}
|
||||
if (mp_mod(key->rsakey->d, &tmpval, &dmq1) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for dmq1\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* iqmp = (q^-1) mod p */
|
||||
if (mp_invmod(key->rsakey->q, key->rsakey->p, &iqmp) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for iqmp\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
extrablob = buf_new(2000);
|
||||
buf_putmpint(extrablob, &dmp1);
|
||||
buf_putmpint(extrablob, &dmq1);
|
||||
buf_putmpint(extrablob, &iqmp);
|
||||
buf_setpos(extrablob, 0);
|
||||
mp_clear(&dmp1);
|
||||
mp_clear(&dmq1);
|
||||
mp_clear(&iqmp);
|
||||
mp_clear(&tmpval);
|
||||
|
||||
/* dmp1 */
|
||||
numbers[6].bytes = buf_getint(extrablob);
|
||||
numbers[6].start = buf_getptr(extrablob, numbers[6].bytes);
|
||||
buf_incrpos(extrablob, numbers[6].bytes);
|
||||
|
||||
/* dmq1 */
|
||||
numbers[7].bytes = buf_getint(extrablob);
|
||||
numbers[7].start = buf_getptr(extrablob, numbers[7].bytes);
|
||||
buf_incrpos(extrablob, numbers[7].bytes);
|
||||
|
||||
/* iqmp */
|
||||
numbers[8].bytes = buf_getint(extrablob);
|
||||
numbers[8].start = buf_getptr(extrablob, numbers[8].bytes);
|
||||
buf_incrpos(extrablob, numbers[8].bytes);
|
||||
|
||||
nnumbers = 9;
|
||||
header = "-----BEGIN RSA PRIVATE KEY-----\n";
|
||||
footer = "-----END RSA PRIVATE KEY-----\n";
|
||||
}
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (key->type == DROPBEAR_SIGNKEY_DSS) {
|
||||
|
||||
/* p */
|
||||
numbers[1].bytes = buf_getint(keyblob);
|
||||
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
|
||||
buf_incrpos(keyblob, numbers[1].bytes);
|
||||
|
||||
/* q */
|
||||
numbers[2].bytes = buf_getint(keyblob);
|
||||
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
|
||||
buf_incrpos(keyblob, numbers[2].bytes);
|
||||
|
||||
/* g */
|
||||
numbers[3].bytes = buf_getint(keyblob);
|
||||
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
|
||||
buf_incrpos(keyblob, numbers[3].bytes);
|
||||
|
||||
/* y */
|
||||
numbers[4].bytes = buf_getint(keyblob);
|
||||
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
|
||||
buf_incrpos(keyblob, numbers[4].bytes);
|
||||
|
||||
/* x */
|
||||
numbers[5].bytes = buf_getint(keyblob);
|
||||
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
|
||||
buf_incrpos(keyblob, numbers[5].bytes);
|
||||
|
||||
nnumbers = 6;
|
||||
header = "-----BEGIN DSA PRIVATE KEY-----\n";
|
||||
footer = "-----END DSA PRIVATE KEY-----\n";
|
||||
}
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
/*
|
||||
* Now count up the total size of the ASN.1 encoded integers,
|
||||
* so as to determine the length of the containing SEQUENCE.
|
||||
*/
|
||||
len = 0;
|
||||
for (i = 0; i < nnumbers; i++) {
|
||||
len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0);
|
||||
len += numbers[i].bytes;
|
||||
}
|
||||
seqlen = len;
|
||||
/* Now add on the SEQUENCE header. */
|
||||
len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
|
||||
/* Round up to the cipher block size, ensuring we have at least one
|
||||
* byte of padding (see below). */
|
||||
outlen = len;
|
||||
if (passphrase)
|
||||
outlen = (outlen+8) &~ 7;
|
||||
|
||||
/*
|
||||
* Now we know how big outblob needs to be. Allocate it.
|
||||
*/
|
||||
outblob = (unsigned char*)m_malloc(outlen);
|
||||
|
||||
/*
|
||||
* And write the data into it.
|
||||
*/
|
||||
pos = 0;
|
||||
pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
|
||||
for (i = 0; i < nnumbers; i++) {
|
||||
pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
|
||||
memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
|
||||
pos += numbers[i].bytes;
|
||||
}
|
||||
} // end RSA and DSS handling
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
|
||||
|| key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
|
||||
|| key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
|
||||
|
||||
/* SEC1 V2 appendix c.4
|
||||
ECPrivateKey ::= SEQUENCE {
|
||||
version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
|
||||
privateKey OCTET STRING,
|
||||
parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
|
||||
publicKey [1] BIT STRING OPTIONAL
|
||||
}
|
||||
*/
|
||||
buffer *seq_buf = buf_new(400);
|
||||
ecc_key **eck = signkey_ecc_key_ptr(key, key->type);
|
||||
const unsigned long curve_size = (*eck)->dp->size;
|
||||
int curve_oid_len = 0;
|
||||
const void* curve_oid = NULL;
|
||||
unsigned long pubkey_size = 2*curve_size+1;
|
||||
|
||||
/* version. less than 10 bytes */
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 2, 1, 0));
|
||||
buf_putbyte(seq_buf, 1);
|
||||
|
||||
/* privateKey */
|
||||
dropbear_assert(mp_unsigned_bin_size((*eck)->k) == curve_size);
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, curve_size, 0));
|
||||
mp_to_unsigned_bin((*eck)->k, buf_getwriteptr(seq_buf, curve_size));
|
||||
buf_incrwritepos(seq_buf, curve_size);
|
||||
|
||||
/* SECGCurveNames */
|
||||
switch (key->type)
|
||||
{
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
curve_oid_len = sizeof(OID_SEC256R1_BLOB);
|
||||
curve_oid = OID_SEC256R1_BLOB;
|
||||
break;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
|
||||
curve_oid_len = sizeof(OID_SEC384R1_BLOB);
|
||||
curve_oid = OID_SEC384R1_BLOB;
|
||||
break;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
|
||||
curve_oid_len = sizeof(OID_SEC521R1_BLOB);
|
||||
curve_oid = OID_SEC521R1_BLOB;
|
||||
break;
|
||||
default:
|
||||
dropbear_exit("Internal error");
|
||||
}
|
||||
|
||||
/* e */
|
||||
numbers[2].bytes = buf_getint(keyblob);
|
||||
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
|
||||
buf_incrpos(keyblob, numbers[2].bytes);
|
||||
|
||||
/* n */
|
||||
numbers[1].bytes = buf_getint(keyblob);
|
||||
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
|
||||
buf_incrpos(keyblob, numbers[1].bytes);
|
||||
|
||||
/* d */
|
||||
numbers[3].bytes = buf_getint(keyblob);
|
||||
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
|
||||
buf_incrpos(keyblob, numbers[3].bytes);
|
||||
|
||||
/* p */
|
||||
numbers[4].bytes = buf_getint(keyblob);
|
||||
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
|
||||
buf_incrpos(keyblob, numbers[4].bytes);
|
||||
|
||||
/* q */
|
||||
numbers[5].bytes = buf_getint(keyblob);
|
||||
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
|
||||
buf_incrpos(keyblob, numbers[5].bytes);
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 0, 2+curve_oid_len, 0xa0));
|
||||
// object == 6
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 6, curve_oid_len, 0));
|
||||
buf_putbytes(seq_buf, curve_oid, curve_oid_len);
|
||||
|
||||
/* now calculate some extra parameters: */
|
||||
m_mp_init(&tmpval);
|
||||
m_mp_init(&dmp1);
|
||||
m_mp_init(&dmq1);
|
||||
m_mp_init(&iqmp);
|
||||
|
||||
/* dmp1 = d mod (p-1) */
|
||||
if (mp_sub_d(key->rsakey->p, 1, &tmpval) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for p-1\n");
|
||||
goto error;
|
||||
}
|
||||
if (mp_mod(key->rsakey->d, &tmpval, &dmp1) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for dmp1\n");
|
||||
goto error;
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 1, 2+1+pubkey_size, 0xa0));
|
||||
buf_incrwritepos(seq_buf,
|
||||
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 3, 1+pubkey_size, 0));
|
||||
buf_putbyte(seq_buf, 0);
|
||||
int err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
|
||||
if (err != CRYPT_OK) {
|
||||
dropbear_exit("ECC error");
|
||||
}
|
||||
buf_incrwritepos(seq_buf, pubkey_size);
|
||||
|
||||
/* dmq1 = d mod (q-1) */
|
||||
if (mp_sub_d(key->rsakey->q, 1, &tmpval) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for q-1\n");
|
||||
goto error;
|
||||
}
|
||||
if (mp_mod(key->rsakey->d, &tmpval, &dmq1) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for dmq1\n");
|
||||
goto error;
|
||||
}
|
||||
buf_setpos(seq_buf, 0);
|
||||
|
||||
outblob = (unsigned char*)m_malloc(200);
|
||||
|
||||
/* iqmp = (q^-1) mod p */
|
||||
if (mp_invmod(key->rsakey->q, key->rsakey->p, &iqmp) != MP_OKAY) {
|
||||
fprintf(stderr, "Bignum error for iqmp\n");
|
||||
goto error;
|
||||
}
|
||||
pos = 0;
|
||||
pos += ber_write_id_len(outblob+pos, 16, seq_buf->len, ASN1_CONSTRUCTED);
|
||||
memcpy(&outblob[pos], seq_buf->data, seq_buf->len);
|
||||
pos += seq_buf->len;
|
||||
len = pos;
|
||||
outlen = len;
|
||||
|
||||
extrablob = buf_new(2000);
|
||||
buf_putmpint(extrablob, &dmp1);
|
||||
buf_putmpint(extrablob, &dmq1);
|
||||
buf_putmpint(extrablob, &iqmp);
|
||||
buf_setpos(extrablob, 0);
|
||||
mp_clear(&dmp1);
|
||||
mp_clear(&dmq1);
|
||||
mp_clear(&iqmp);
|
||||
mp_clear(&tmpval);
|
||||
|
||||
/* dmp1 */
|
||||
numbers[6].bytes = buf_getint(extrablob);
|
||||
numbers[6].start = buf_getptr(extrablob, numbers[6].bytes);
|
||||
buf_incrpos(extrablob, numbers[6].bytes);
|
||||
|
||||
/* dmq1 */
|
||||
numbers[7].bytes = buf_getint(extrablob);
|
||||
numbers[7].start = buf_getptr(extrablob, numbers[7].bytes);
|
||||
buf_incrpos(extrablob, numbers[7].bytes);
|
||||
|
||||
/* iqmp */
|
||||
numbers[8].bytes = buf_getint(extrablob);
|
||||
numbers[8].start = buf_getptr(extrablob, numbers[8].bytes);
|
||||
buf_incrpos(extrablob, numbers[8].bytes);
|
||||
buf_burn(seq_buf);
|
||||
buf_free(seq_buf);
|
||||
seq_buf = NULL;
|
||||
|
||||
nnumbers = 9;
|
||||
header = "-----BEGIN RSA PRIVATE KEY-----\n";
|
||||
footer = "-----END RSA PRIVATE KEY-----\n";
|
||||
}
|
||||
#endif /* DROPBEAR_RSA */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS) {
|
||||
|
||||
/* p */
|
||||
numbers[1].bytes = buf_getint(keyblob);
|
||||
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
|
||||
buf_incrpos(keyblob, numbers[1].bytes);
|
||||
|
||||
/* q */
|
||||
numbers[2].bytes = buf_getint(keyblob);
|
||||
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
|
||||
buf_incrpos(keyblob, numbers[2].bytes);
|
||||
|
||||
/* g */
|
||||
numbers[3].bytes = buf_getint(keyblob);
|
||||
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
|
||||
buf_incrpos(keyblob, numbers[3].bytes);
|
||||
|
||||
/* y */
|
||||
numbers[4].bytes = buf_getint(keyblob);
|
||||
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
|
||||
buf_incrpos(keyblob, numbers[4].bytes);
|
||||
|
||||
/* x */
|
||||
numbers[5].bytes = buf_getint(keyblob);
|
||||
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
|
||||
buf_incrpos(keyblob, numbers[5].bytes);
|
||||
|
||||
nnumbers = 6;
|
||||
header = "-----BEGIN DSA PRIVATE KEY-----\n";
|
||||
footer = "-----END DSA PRIVATE KEY-----\n";
|
||||
}
|
||||
#endif /* DROPBEAR_DSS */
|
||||
|
||||
/*
|
||||
* Now count up the total size of the ASN.1 encoded integers,
|
||||
* so as to determine the length of the containing SEQUENCE.
|
||||
*/
|
||||
len = 0;
|
||||
for (i = 0; i < nnumbers; i++) {
|
||||
len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0);
|
||||
len += numbers[i].bytes;
|
||||
}
|
||||
seqlen = len;
|
||||
/* Now add on the SEQUENCE header. */
|
||||
len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
|
||||
/* Round up to the cipher block size, ensuring we have at least one
|
||||
* byte of padding (see below). */
|
||||
outlen = len;
|
||||
if (passphrase)
|
||||
outlen = (outlen+8) &~ 7;
|
||||
|
||||
/*
|
||||
* Now we know how big outblob needs to be. Allocate it.
|
||||
*/
|
||||
outblob = (unsigned char*)m_malloc(outlen);
|
||||
|
||||
/*
|
||||
* And write the data into it.
|
||||
*/
|
||||
pos = 0;
|
||||
pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
|
||||
for (i = 0; i < nnumbers; i++) {
|
||||
pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
|
||||
memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
|
||||
pos += numbers[i].bytes;
|
||||
header = "-----BEGIN EC PRIVATE KEY-----\n";
|
||||
footer = "-----END EC PRIVATE KEY-----\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Padding on OpenSSH keys is deterministic. The number of
|
||||
|
||||
@@ -19,7 +19,7 @@ srcdir=@srcdir@
|
||||
|
||||
# Compilation flags. Note the += does not write over the user's CFLAGS!
|
||||
# The rest of the flags come from the parent Dropbear makefile
|
||||
CFLAGS += -c -I$(srcdir)/src/headers/ -I$(srcdir)/../
|
||||
CFLAGS += -c -I$(srcdir)/src/headers/ -I$(srcdir)/../ -DLTC_SOURCE -I$(srcdir)/../libtommath/
|
||||
|
||||
# additional warnings (newer GCC 3.4 and higher)
|
||||
ifdef GCC_34
|
||||
@@ -157,7 +157,53 @@ src/modes/lrw/lrw_decrypt.o src/modes/lrw/lrw_done.o src/modes/lrw/lrw_encrypt.o
|
||||
src/modes/lrw/lrw_getiv.o src/modes/lrw/lrw_process.o src/modes/lrw/lrw_setiv.o \
|
||||
src/modes/lrw/lrw_start.o src/modes/lrw/lrw_test.o src/modes/ofb/ofb_decrypt.o src/modes/ofb/ofb_done.o \
|
||||
src/modes/ofb/ofb_encrypt.o src/modes/ofb/ofb_getiv.o src/modes/ofb/ofb_setiv.o \
|
||||
src/modes/ofb/ofb_start.o
|
||||
src/modes/ofb/ofb_start.o src/pk/asn1/der/bit/der_decode_bit_string.o \
|
||||
src/pk/asn1/der/bit/der_encode_bit_string.o src/pk/asn1/der/bit/der_length_bit_string.o \
|
||||
src/pk/asn1/der/boolean/der_decode_boolean.o src/pk/asn1/der/boolean/der_encode_boolean.o \
|
||||
src/pk/asn1/der/boolean/der_length_boolean.o src/pk/asn1/der/choice/der_decode_choice.o \
|
||||
src/pk/asn1/der/ia5/der_decode_ia5_string.o src/pk/asn1/der/ia5/der_encode_ia5_string.o \
|
||||
src/pk/asn1/der/ia5/der_length_ia5_string.o src/pk/asn1/der/integer/der_decode_integer.o \
|
||||
src/pk/asn1/der/integer/der_encode_integer.o src/pk/asn1/der/integer/der_length_integer.o \
|
||||
src/pk/asn1/der/object_identifier/der_decode_object_identifier.o \
|
||||
src/pk/asn1/der/object_identifier/der_encode_object_identifier.o \
|
||||
src/pk/asn1/der/object_identifier/der_length_object_identifier.o \
|
||||
src/pk/asn1/der/octet/der_decode_octet_string.o src/pk/asn1/der/octet/der_encode_octet_string.o \
|
||||
src/pk/asn1/der/octet/der_length_octet_string.o \
|
||||
src/pk/asn1/der/printable_string/der_decode_printable_string.o \
|
||||
src/pk/asn1/der/printable_string/der_encode_printable_string.o \
|
||||
src/pk/asn1/der/printable_string/der_length_printable_string.o \
|
||||
src/pk/asn1/der/sequence/der_decode_sequence_ex.o \
|
||||
src/pk/asn1/der/sequence/der_decode_sequence_flexi.o \
|
||||
src/pk/asn1/der/sequence/der_decode_sequence_multi.o \
|
||||
src/pk/asn1/der/sequence/der_encode_sequence_ex.o \
|
||||
src/pk/asn1/der/sequence/der_encode_sequence_multi.o src/pk/asn1/der/sequence/der_length_sequence.o \
|
||||
src/pk/asn1/der/sequence/der_sequence_free.o src/pk/asn1/der/set/der_encode_set.o \
|
||||
src/pk/asn1/der/set/der_encode_setof.o src/pk/asn1/der/short_integer/der_decode_short_integer.o \
|
||||
src/pk/asn1/der/short_integer/der_encode_short_integer.o \
|
||||
src/pk/asn1/der/short_integer/der_length_short_integer.o src/pk/asn1/der/utctime/der_decode_utctime.o \
|
||||
src/pk/asn1/der/utctime/der_encode_utctime.o src/pk/asn1/der/utctime/der_length_utctime.o \
|
||||
src/pk/asn1/der/utf8/der_decode_utf8_string.o src/pk/asn1/der/utf8/der_encode_utf8_string.o \
|
||||
src/pk/asn1/der/utf8/der_length_utf8_string.o src/pk/dsa/dsa_decrypt_key.o \
|
||||
src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_import.o \
|
||||
src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o \
|
||||
src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \
|
||||
src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \
|
||||
src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_size.o \
|
||||
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_shared_secret.o \
|
||||
src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
|
||||
src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
|
||||
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
|
||||
src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
|
||||
src/pk/katja/katja_decrypt_key.o src/pk/katja/katja_encrypt_key.o src/pk/katja/katja_export.o \
|
||||
src/pk/katja/katja_exptmod.o src/pk/katja/katja_free.o src/pk/katja/katja_import.o \
|
||||
src/pk/katja/katja_make_key.o src/pk/pkcs1/pkcs_1_i2osp.o src/pk/pkcs1/pkcs_1_mgf1.o \
|
||||
src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o src/pk/pkcs1/pkcs_1_os2ip.o \
|
||||
src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o src/pk/pkcs1/pkcs_1_v1_5_decode.o \
|
||||
src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o src/pk/rsa/rsa_encrypt_key.o \
|
||||
src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o src/pk/rsa/rsa_import.o \
|
||||
src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_sign_hash.o src/pk/rsa/rsa_verify_hash.o src/prngs/fortuna.o \
|
||||
src/prngs/rc4.o src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o \
|
||||
src/prngs/sprng.o src/prngs/yarrow.o
|
||||
|
||||
HEADERS=src/headers/tomcrypt_cfg.h src/headers/tomcrypt_mac.h src/headers/tomcrypt_macros.h \
|
||||
src/headers/tomcrypt_custom.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cipher.h \
|
||||
|
||||
@@ -24,7 +24,7 @@ extern "C" {
|
||||
|
||||
/* descriptor table size */
|
||||
/* Dropbear change - this should be smaller, saves some size */
|
||||
#define TAB_SIZE 4
|
||||
#define TAB_SIZE 5
|
||||
|
||||
/* error codes [will be expanded in future releases] */
|
||||
enum {
|
||||
|
||||
@@ -127,13 +127,32 @@
|
||||
#ifdef DROPBEAR_SHA256
|
||||
#define SHA256
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_SHA384
|
||||
#define SHA384
|
||||
#endif
|
||||
#ifdef DROPBEAR_SHA512
|
||||
#define SHA512
|
||||
#endif
|
||||
|
||||
#define LTC_HMAC
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
#define MECC
|
||||
#define LTC_ECC_SHAMIR
|
||||
#define LTC_ECC_TIMING_RESISTANT
|
||||
#define MPI
|
||||
#define LTM_DESC
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
#define ECC256
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
#define ECC384
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
#define ECC521
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Various tidbits of modern neatoness */
|
||||
#define BASE64
|
||||
|
||||
|
||||
@@ -11,12 +11,9 @@
|
||||
typedef void ecc_point;
|
||||
#endif
|
||||
|
||||
/* Dropbear has its own rsa_key. We just comment this out. */
|
||||
#if 0
|
||||
#ifndef MRSA
|
||||
typedef void rsa_key;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** math descriptor */
|
||||
typedef struct {
|
||||
@@ -389,8 +386,6 @@ typedef struct {
|
||||
ecc_point *C,
|
||||
void *modulus);
|
||||
|
||||
/* Dropbear has its own rsa code */
|
||||
#if 0
|
||||
/* ---- (optional) rsa optimized math (for internal CRT) ---- */
|
||||
|
||||
/** RSA Key Generation
|
||||
@@ -416,7 +411,6 @@ typedef struct {
|
||||
int (*rsa_me)(const unsigned char *in, unsigned long inlen,
|
||||
unsigned char *out, unsigned long *outlen, int which,
|
||||
rsa_key *key);
|
||||
#endif
|
||||
} ltc_math_descriptor;
|
||||
|
||||
extern ltc_math_descriptor ltc_mp;
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
*/
|
||||
#include "tomcrypt.h"
|
||||
|
||||
ltc_math_descriptor ltc_mp;
|
||||
ltc_math_descriptor ltc_mp = {0};
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
/**
|
||||
Decrypt an ECC encrypted key
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
/**
|
||||
Encrypt a symmetric key with ECC
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
/**
|
||||
Export an ECC key as a binary packet
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
static int is_point(ecc_key *key)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
/**
|
||||
Sign a message digest
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ECC Crypto, Tom St Denis
|
||||
*/
|
||||
|
||||
#ifdef MECC
|
||||
#if defined(MECC) && defined(LTC_DER)
|
||||
|
||||
/* verify
|
||||
*
|
||||
|
||||
137
ltc_prng.c
Normal file
137
ltc_prng.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/* Copied from libtomcrypt/src/prngs/sprng.c and modified to
|
||||
* use Dropbear's genrandom(). */
|
||||
|
||||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
|
||||
*
|
||||
* LibTomCrypt is a library that provides various cryptographic
|
||||
* algorithms in a highly modular and flexible manner.
|
||||
*
|
||||
* The library is free for all purposes without any express
|
||||
* guarantee it works.
|
||||
*
|
||||
* Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
|
||||
*/
|
||||
#include "options.h"
|
||||
#include "includes.h"
|
||||
#include "random.h"
|
||||
#include "ltc_prng.h"
|
||||
|
||||
/**
|
||||
@file sprng.c
|
||||
Secure PRNG, Tom St Denis
|
||||
*/
|
||||
|
||||
/* A secure PRNG using the RNG functions. Basically this is a
|
||||
* wrapper that allows you to use a secure RNG as a PRNG
|
||||
* in the various other functions.
|
||||
*/
|
||||
|
||||
#ifdef DROPBEAR_LTC_PRNG
|
||||
|
||||
/**
|
||||
Start the PRNG
|
||||
@param prng [out] The PRNG state to initialize
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_start(prng_state* UNUSED(prng))
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Add entropy to the PRNG state
|
||||
@param in The data to add
|
||||
@param inlen Length of the data to add
|
||||
@param prng PRNG state to update
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_add_entropy(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Make the PRNG ready to read from
|
||||
@param prng The PRNG to make active
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_ready(prng_state* UNUSED(prng))
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Read from the PRNG
|
||||
@param out Destination
|
||||
@param outlen Length of output
|
||||
@param prng The active PRNG to read from
|
||||
@return Number of octets read
|
||||
*/
|
||||
unsigned long dropbear_prng_read(unsigned char* out, unsigned long outlen, prng_state* UNUSED(prng))
|
||||
{
|
||||
LTC_ARGCHK(out != NULL);
|
||||
genrandom(out, outlen);
|
||||
return outlen;
|
||||
}
|
||||
|
||||
/**
|
||||
Terminate the PRNG
|
||||
@param prng The PRNG to terminate
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_done(prng_state* UNUSED(prng))
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Export the PRNG state
|
||||
@param out [out] Destination
|
||||
@param outlen [in/out] Max size and resulting size of the state
|
||||
@param prng The PRNG to export
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_export(unsigned char* UNUSED(out), unsigned long* outlen, prng_state* UNUSED(prng))
|
||||
{
|
||||
LTC_ARGCHK(outlen != NULL);
|
||||
|
||||
*outlen = 0;
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
Import a PRNG state
|
||||
@param in The PRNG state
|
||||
@param inlen Size of the state
|
||||
@param prng The PRNG to import
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
int dropbear_prng_import(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
PRNG self-test
|
||||
@return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
|
||||
*/
|
||||
int dropbear_prng_test(void)
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
const struct ltc_prng_descriptor dropbear_prng_desc =
|
||||
{
|
||||
"dropbear_prng", 0,
|
||||
&dropbear_prng_start,
|
||||
&dropbear_prng_add_entropy,
|
||||
&dropbear_prng_ready,
|
||||
&dropbear_prng_read,
|
||||
&dropbear_prng_done,
|
||||
&dropbear_prng_export,
|
||||
&dropbear_prng_import,
|
||||
&dropbear_prng_test
|
||||
};
|
||||
|
||||
|
||||
#endif // DROPBEAR_LTC_PRNG
|
||||
13
ltc_prng.h
Normal file
13
ltc_prng.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef _LTC_PRNG_H_DROPBEAR
|
||||
#define _LTC_PRNG_H_DROPBEAR
|
||||
|
||||
#include "options.h"
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef DROPBEAR_LTC_PRNG
|
||||
|
||||
extern const struct ltc_prng_descriptor dropbear_prng_desc;
|
||||
|
||||
#endif // DROPBEAR_LTC_PRNG
|
||||
|
||||
#endif // _LTC_PRNG_H_DROPBEAR
|
||||
16
options.h
16
options.h
@@ -5,10 +5,10 @@
|
||||
#ifndef _OPTIONS_H_
|
||||
#define _OPTIONS_H_
|
||||
|
||||
/******************************************************************
|
||||
* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
|
||||
* parts are to allow for commandline -DDROPBEAR_XXX options etc.
|
||||
******************************************************************/
|
||||
/* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
|
||||
* parts are to allow for commandline -DDROPBEAR_XXX options etc. */
|
||||
|
||||
/* Important: Many options will require "make clean" after changes */
|
||||
|
||||
#ifndef DROPBEAR_DEFPORT
|
||||
#define DROPBEAR_DEFPORT "22"
|
||||
@@ -26,6 +26,9 @@
|
||||
#ifndef RSA_PRIV_FILENAME
|
||||
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
|
||||
#endif
|
||||
#ifndef ECDSA_PRIV_FILENAME
|
||||
#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
|
||||
#endif
|
||||
|
||||
/* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
|
||||
* on chosen ports and keeps accepting connections. This is the default.
|
||||
@@ -49,7 +52,7 @@
|
||||
several kB in binary size however will make the symmetrical ciphers and hashes
|
||||
slower, perhaps by 50%. Recommended for small systems that aren't doing
|
||||
much traffic. */
|
||||
/*#define DROPBEAR_SMALL_CODE*/
|
||||
#define DROPBEAR_SMALL_CODE
|
||||
|
||||
/* Enable X11 Forwarding - server only */
|
||||
#define ENABLE_X11FWD
|
||||
@@ -136,6 +139,9 @@ much traffic. */
|
||||
#define DROPBEAR_RSA
|
||||
#define DROPBEAR_DSS
|
||||
|
||||
#define DROPBEAR_ECDH
|
||||
#define DROPBEAR_ECDSA
|
||||
|
||||
/* RSA can be vulnerable to timing attacks which use the time required for
|
||||
* signing to guess the private key. Blinding avoids this attack, though makes
|
||||
* signing operations slightly slower. */
|
||||
|
||||
7
random.c
7
random.c
@@ -28,6 +28,7 @@
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
|
||||
|
||||
/* this is used to generate unique output from the same hashpool */
|
||||
static uint32_t counter = 0;
|
||||
/* the max value for the counter, so it won't integer overflow */
|
||||
@@ -80,14 +81,14 @@ process_file(hash_state *hs, const char *filename,
|
||||
unsigned char readbuf[4096];
|
||||
if (!already_blocked)
|
||||
{
|
||||
int ret;
|
||||
int res;
|
||||
struct timeval timeout = { .tv_sec = 2, .tv_usec = 0};
|
||||
fd_set read_fds;
|
||||
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(readfd, &read_fds);
|
||||
ret = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
|
||||
if (ret == 0)
|
||||
res = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
|
||||
if (res == 0)
|
||||
{
|
||||
dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename);
|
||||
already_blocked = 1;
|
||||
|
||||
32
rsa.c
32
rsa.c
@@ -39,8 +39,7 @@
|
||||
#ifdef DROPBEAR_RSA
|
||||
|
||||
static void rsa_pad_em(dropbear_rsa_key * key,
|
||||
const unsigned char * data, unsigned int len,
|
||||
mp_int * rsa_em);
|
||||
buffer *data_buf, mp_int * rsa_em);
|
||||
|
||||
/* Load a public rsa key from a buffer, initialising the values.
|
||||
* The key will have the same format as buf_put_rsa_key.
|
||||
@@ -51,9 +50,7 @@ int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
TRACE(("enter buf_get_rsa_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
key->e = m_malloc(sizeof(mp_int));
|
||||
key->n = m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->e, key->n, NULL);
|
||||
m_mp_alloc_init_multi(&key->e, &key->n, NULL);
|
||||
key->d = NULL;
|
||||
key->p = NULL;
|
||||
key->q = NULL;
|
||||
@@ -99,8 +96,7 @@ int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
key->p = NULL;
|
||||
key->q = NULL;
|
||||
|
||||
key->d = m_malloc(sizeof(mp_int));
|
||||
m_mp_init(key->d);
|
||||
m_mp_alloc_init_multi(&key->d, NULL);
|
||||
if (buf_getmpint(buf, key->d) == DROPBEAR_FAILURE) {
|
||||
TRACE(("leave buf_get_rsa_priv_key: d: ret == DROPBEAR_FAILURE"))
|
||||
goto out;
|
||||
@@ -109,9 +105,7 @@ int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
if (buf->pos == buf->len) {
|
||||
/* old Dropbear private keys didn't keep p and q, so we will ignore them*/
|
||||
} else {
|
||||
key->p = m_malloc(sizeof(mp_int));
|
||||
key->q = m_malloc(sizeof(mp_int));
|
||||
m_mp_init_multi(key->p, key->q, NULL);
|
||||
m_mp_alloc_init_multi(&key->p, &key->q, NULL);
|
||||
|
||||
if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE) {
|
||||
TRACE(("leave buf_get_rsa_priv_key: p: ret == DROPBEAR_FAILURE"))
|
||||
@@ -213,9 +207,7 @@ void buf_put_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a signature in buf, made on data by the key given.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, buffer *data_buf) {
|
||||
unsigned int slen;
|
||||
DEF_MP_INT(rsa_s);
|
||||
DEF_MP_INT(rsa_mdash);
|
||||
@@ -247,7 +239,7 @@ int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* dat
|
||||
}
|
||||
|
||||
/* create the magic PKCS padded value */
|
||||
rsa_pad_em(key, data, len, &rsa_em);
|
||||
rsa_pad_em(key, data_buf, &rsa_em);
|
||||
|
||||
if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) {
|
||||
TRACE(("failed exptmod rsa_s"))
|
||||
@@ -270,9 +262,7 @@ out:
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer */
|
||||
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len) {
|
||||
|
||||
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, buffer *data_buf) {
|
||||
unsigned int nsize, ssize;
|
||||
unsigned int i;
|
||||
DEF_MP_INT(rsa_s);
|
||||
@@ -285,7 +275,7 @@ void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* d
|
||||
|
||||
m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL);
|
||||
|
||||
rsa_pad_em(key, data, len, &rsa_tmp1);
|
||||
rsa_pad_em(key, data_buf, &rsa_tmp1);
|
||||
|
||||
/* the actual signing of the padded data */
|
||||
|
||||
@@ -377,8 +367,7 @@ void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* d
|
||||
* rsa_em must be a pointer to an initialised mp_int.
|
||||
*/
|
||||
static void rsa_pad_em(dropbear_rsa_key * key,
|
||||
const unsigned char * data, unsigned int len,
|
||||
mp_int * rsa_em) {
|
||||
buffer *data_buf, mp_int * rsa_em) {
|
||||
|
||||
/* ASN1 designator (including the 0x00 preceding) */
|
||||
const unsigned char rsa_asn1_magic[] =
|
||||
@@ -391,7 +380,6 @@ static void rsa_pad_em(dropbear_rsa_key * key,
|
||||
unsigned int nsize;
|
||||
|
||||
dropbear_assert(key != NULL);
|
||||
dropbear_assert(data != NULL);
|
||||
nsize = mp_unsigned_bin_size(key->n);
|
||||
|
||||
rsa_EM = buf_new(nsize-1);
|
||||
@@ -408,7 +396,7 @@ static void rsa_pad_em(dropbear_rsa_key * key,
|
||||
|
||||
/* The hash of the data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data, len);
|
||||
sha1_process(&hs, data_buf->data, data_buf->len);
|
||||
sha1_done(&hs, buf_getwriteptr(rsa_EM, SHA1_HASH_SIZE));
|
||||
buf_incrwritepos(rsa_EM, SHA1_HASH_SIZE);
|
||||
|
||||
|
||||
6
rsa.h
6
rsa.h
@@ -43,11 +43,9 @@ typedef struct {
|
||||
|
||||
} dropbear_rsa_key;
|
||||
|
||||
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, buffer *data_buf);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
|
||||
unsigned int len);
|
||||
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, buffer *data_buf);
|
||||
#endif
|
||||
int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key);
|
||||
int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key);
|
||||
|
||||
@@ -57,11 +57,10 @@ typedef struct runopts {
|
||||
extern runopts opts;
|
||||
|
||||
int readhostkey(const char * filename, sign_key * hostkey, int *type);
|
||||
void load_all_hostkeys();
|
||||
|
||||
typedef struct svr_runopts {
|
||||
|
||||
char * rsakeyfile;
|
||||
char * dsskeyfile;
|
||||
char * bannerfile;
|
||||
|
||||
int forkbg;
|
||||
@@ -99,6 +98,10 @@ typedef struct svr_runopts {
|
||||
#endif
|
||||
|
||||
sign_key *hostkey;
|
||||
|
||||
char *hostkey_files[MAX_HOSTKEYS];
|
||||
int num_hostkey_files;
|
||||
|
||||
buffer * banner;
|
||||
char * pidfile;
|
||||
|
||||
|
||||
19
session.h
19
session.h
@@ -66,7 +66,7 @@ struct key_context_directional {
|
||||
const struct dropbear_cipher_mode *crypt_mode;
|
||||
const struct dropbear_hash *algo_mac;
|
||||
int hash_index; /* lookup for libtomcrypt */
|
||||
char algo_comp; /* compression */
|
||||
int algo_comp; /* compression */
|
||||
#ifndef DISABLE_ZLIB
|
||||
z_streamp zstream;
|
||||
#endif
|
||||
@@ -86,8 +86,8 @@ struct key_context {
|
||||
struct key_context_directional recv;
|
||||
struct key_context_directional trans;
|
||||
|
||||
char algo_kex;
|
||||
char algo_hostkey;
|
||||
const struct dropbear_kex *algo_kex;
|
||||
int algo_hostkey;
|
||||
|
||||
int allow_compress; /* whether compression has started (useful in
|
||||
zlib@openssh.com delayed compression case) */
|
||||
@@ -158,10 +158,10 @@ struct sshsession {
|
||||
struct KEXState kexstate;
|
||||
struct key_context *keys;
|
||||
struct key_context *newkeys;
|
||||
unsigned char *session_id; /* this is the hash from the first kex */
|
||||
/* The below are used temorarily during kex, are freed after use */
|
||||
buffer *session_id; /* this is the hash from the first kex */
|
||||
/* The below are used temporarily during kex, are freed after use */
|
||||
mp_int * dh_K; /* SSH_MSG_KEXDH_REPLY and sending SSH_MSH_NEWKEYS */
|
||||
unsigned char hash[SHA1_HASH_SIZE]; /* the hash*/
|
||||
buffer *hash; /* the session hash */
|
||||
buffer* kexhashbuf; /* session hash buffer calculated from various packets*/
|
||||
buffer* transkexinit; /* the kexinit packet we send should be kept so we
|
||||
can add it to the hash when generating keys */
|
||||
@@ -241,8 +241,11 @@ typedef enum {
|
||||
|
||||
struct clientsession {
|
||||
|
||||
mp_int *dh_e, *dh_x; /* Used during KEX */
|
||||
int dh_val_algo; /* KEX algorithm corresponding to current dh_e and dh_x */
|
||||
// XXX - move these to kexstate?
|
||||
struct kex_dh_param *dh_param;
|
||||
struct kex_ecdh_param *ecdh_param;
|
||||
const struct dropbear_kex *param_kex_algo; /* KEX algorithm corresponding to current dh_e and dh_x */
|
||||
|
||||
cli_kex_state kex_state; /* Used for progressing KEX */
|
||||
cli_state state; /* Used to progress auth/channelsession etc */
|
||||
unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */
|
||||
|
||||
228
signkey.c
228
signkey.c
@@ -27,6 +27,22 @@
|
||||
#include "signkey.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
#include "ecdsa.h"
|
||||
|
||||
static const char *signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
|
||||
#ifdef DROPBEAR_RSA
|
||||
"ssh-rsa",
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
"ssh-dss",
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
"ecdsa-sha2-nistp256",
|
||||
"ecdsa-sha2-nistp384",
|
||||
"ecdsa-sha2-nistp521",
|
||||
"ecdsa" // for keygen
|
||||
#endif // DROPBEAR_ECDSA
|
||||
};
|
||||
|
||||
/* malloc a new sign_key and set the dss and rsa keys to NULL */
|
||||
sign_key * new_sign_key() {
|
||||
@@ -34,60 +50,75 @@ sign_key * new_sign_key() {
|
||||
sign_key * ret;
|
||||
|
||||
ret = (sign_key*)m_malloc(sizeof(sign_key));
|
||||
#ifdef DROPBEAR_DSS
|
||||
ret->dsskey = NULL;
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
ret->rsakey = NULL;
|
||||
#endif
|
||||
ret->filename = NULL;
|
||||
ret->type = DROPBEAR_SIGNKEY_NONE;
|
||||
ret->source = SIGNKEY_SOURCE_INVALID;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns "ssh-dss" or "ssh-rsa" corresponding to the type. Exits fatally
|
||||
/* Returns key name corresponding to the type. Exits fatally
|
||||
* if the type is invalid */
|
||||
const char* signkey_name_from_type(int type, int *namelen) {
|
||||
const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen) {
|
||||
if (type >= DROPBEAR_SIGNKEY_NUM_NAMED) {
|
||||
dropbear_exit("Bad key type %d", type);
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
*namelen = SSH_SIGNKEY_RSA_LEN;
|
||||
return SSH_SIGNKEY_RSA;
|
||||
if (namelen) {
|
||||
*namelen = strlen(signkey_names[type]);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
*namelen = SSH_SIGNKEY_DSS_LEN;
|
||||
return SSH_SIGNKEY_DSS;
|
||||
}
|
||||
#endif
|
||||
dropbear_exit("Bad key type %d", type);
|
||||
return NULL; /* notreached */
|
||||
return signkey_names[type];
|
||||
}
|
||||
|
||||
/* Returns DROPBEAR_SIGNKEY_RSA, DROPBEAR_SIGNKEY_DSS,
|
||||
* or DROPBEAR_SIGNKEY_NONE */
|
||||
int signkey_type_from_name(const char* name, int namelen) {
|
||||
/* Returns DROPBEAR_SIGNKEY_NONE if none match */
|
||||
enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) {
|
||||
int i;
|
||||
for (i = 0; i < DROPBEAR_SIGNKEY_NUM_NAMED; i++) {
|
||||
const char *fixed_name = signkey_names[i];
|
||||
if (namelen == strlen(fixed_name)
|
||||
&& memcmp(fixed_name, name, namelen) == 0) {
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (namelen == SSH_SIGNKEY_RSA_LEN
|
||||
&& memcmp(name, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN) == 0) {
|
||||
return DROPBEAR_SIGNKEY_RSA;
|
||||
}
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
/* Some of the ECDSA key sizes are defined even if they're not compiled in */
|
||||
if (0
|
||||
#ifndef DROPBEAR_ECC_256
|
||||
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP256
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (namelen == SSH_SIGNKEY_DSS_LEN
|
||||
&& memcmp(name, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN) == 0) {
|
||||
return DROPBEAR_SIGNKEY_DSS;
|
||||
}
|
||||
#ifndef DROPBEAR_ECC_384
|
||||
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP384
|
||||
#endif
|
||||
#ifndef DROPBEAR_ECC_521
|
||||
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP521
|
||||
#endif
|
||||
) {
|
||||
TRACE(("attempt to use ecdsa type %d not compiled in", i))
|
||||
return DROPBEAR_SIGNKEY_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE(("signkey_type_from_name unexpected key type."))
|
||||
|
||||
return DROPBEAR_SIGNKEY_NONE;
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
ecc_key **
|
||||
signkey_ecc_key_ptr(sign_key *key, enum signkey_type ecc_type) {
|
||||
switch (ecc_type) {
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
return &key->ecckey256;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
|
||||
return &key->ecckey384;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
|
||||
return &key->ecckey521;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
|
||||
* type should be set by the caller to specify the type to read, and
|
||||
* on return is set to the type read (useful when type = _ANY) */
|
||||
@@ -136,6 +167,21 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
{
|
||||
ecc_key **eck = signkey_ecc_key_ptr(key, keytype);
|
||||
if (eck) {
|
||||
if (*eck) {
|
||||
ecc_free(*eck);
|
||||
*eck = NULL;
|
||||
}
|
||||
*eck = buf_get_ecdsa_pub_key(buf);
|
||||
if (*eck) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE2(("leave buf_get_pub_key"))
|
||||
|
||||
@@ -189,6 +235,21 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
{
|
||||
ecc_key **eck = signkey_ecc_key_ptr(key, keytype);
|
||||
if (eck) {
|
||||
if (*eck) {
|
||||
ecc_free(*eck);
|
||||
*eck = NULL;
|
||||
}
|
||||
*eck = buf_get_ecdsa_priv_key(buf);
|
||||
if (*eck) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE2(("leave buf_get_priv_key"))
|
||||
|
||||
@@ -213,15 +274,20 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
buf_put_rsa_pub_key(pubkeys, key->rsakey);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
{
|
||||
ecc_key **eck = signkey_ecc_key_ptr(key, type);
|
||||
if (eck) {
|
||||
buf_put_ecdsa_pub_key(pubkeys, *eck);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (pubkeys->len == 0) {
|
||||
dropbear_exit("Bad key types in buf_put_pub_key");
|
||||
}
|
||||
|
||||
buf_setpos(pubkeys, 0);
|
||||
buf_putstring(buf, buf_getptr(pubkeys, pubkeys->len),
|
||||
pubkeys->len);
|
||||
|
||||
buf_putbufstring(buf, pubkeys);
|
||||
buf_free(pubkeys);
|
||||
TRACE2(("leave buf_put_pub_key"))
|
||||
}
|
||||
@@ -245,6 +311,16 @@ void buf_put_priv_key(buffer* buf, sign_key *key, int type) {
|
||||
TRACE(("leave buf_put_priv_key: rsa done"))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
{
|
||||
ecc_key **eck = signkey_ecc_key_ptr(key, type);
|
||||
if (eck) {
|
||||
buf_put_ecdsa_priv_key(buf, *eck);
|
||||
TRACE(("leave buf_put_priv_key: ecdsa done"))
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
dropbear_exit("Bad key types in put pub key");
|
||||
}
|
||||
@@ -261,6 +337,20 @@ void sign_key_free(sign_key *key) {
|
||||
rsa_key_free(key->rsakey);
|
||||
key->rsakey = NULL;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
if (key->ecckey256) {
|
||||
ecc_free(key->ecckey256);
|
||||
key->ecckey256 = NULL;
|
||||
}
|
||||
if (key->ecckey384) {
|
||||
ecc_free(key->ecckey384);
|
||||
key->ecckey384 = NULL;
|
||||
}
|
||||
if (key->ecckey521) {
|
||||
ecc_free(key->ecckey521);
|
||||
key->ecckey521 = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_free(key->filename);
|
||||
|
||||
@@ -269,7 +359,6 @@ void sign_key_free(sign_key *key) {
|
||||
}
|
||||
|
||||
static char hexdig(unsigned char x) {
|
||||
|
||||
if (x > 0xf)
|
||||
return 'X';
|
||||
|
||||
@@ -333,14 +422,14 @@ static char * sign_key_sha1_fingerprint(unsigned char* keyblob,
|
||||
|
||||
sha1_done(&hs, hash);
|
||||
|
||||
/* "sha1 hexfingerprinthere\0", each hex digit is "AB:" etc */
|
||||
buflen = 5 + 3*SHA1_HASH_SIZE;
|
||||
/* "sha1!! hexfingerprinthere\0", each hex digit is "AB:" etc */
|
||||
buflen = 7 + 3*SHA1_HASH_SIZE;
|
||||
ret = (char*)m_malloc(buflen);
|
||||
|
||||
strcpy(ret, "sha1 ");
|
||||
strcpy(ret, "sha1!! ");
|
||||
|
||||
for (i = 0; i < SHA1_HASH_SIZE; i++) {
|
||||
unsigned int pos = 5 + 3*i;
|
||||
unsigned int pos = 7 + 3*i;
|
||||
ret[pos] = hexdig(hash[i] >> 4);
|
||||
ret[pos+1] = hexdig(hash[i] & 0x0f);
|
||||
ret[pos+2] = ':';
|
||||
@@ -364,28 +453,32 @@ char * sign_key_fingerprint(unsigned char* keyblob, unsigned int keybloblen) {
|
||||
}
|
||||
|
||||
void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len) {
|
||||
|
||||
buffer *data_buf) {
|
||||
buffer *sigblob;
|
||||
sigblob = buf_new(MAX_PUBKEY_SIZE);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
buf_put_dss_sign(sigblob, key->dsskey, data, len);
|
||||
buf_put_dss_sign(sigblob, key->dsskey, data_buf);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
buf_put_rsa_sign(sigblob, key->rsakey, data, len);
|
||||
buf_put_rsa_sign(sigblob, key->rsakey, data_buf);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
{
|
||||
ecc_key **eck = signkey_ecc_key_ptr(key, type);
|
||||
if (eck) {
|
||||
buf_put_ecdsa_sign(sigblob, *eck, data_buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (sigblob->len == 0) {
|
||||
dropbear_exit("Non-matching signing type");
|
||||
}
|
||||
buf_setpos(sigblob, 0);
|
||||
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
|
||||
sigblob->len);
|
||||
|
||||
buf_putbufstring(buf, sigblob);
|
||||
buf_free(sigblob);
|
||||
|
||||
}
|
||||
@@ -395,40 +488,45 @@ void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
* If FAILURE is returned, the position of
|
||||
* buf is undefined. If SUCCESS is returned, buf will be positioned after the
|
||||
* signature blob */
|
||||
int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
|
||||
unsigned int len) {
|
||||
int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
|
||||
|
||||
unsigned int bloblen;
|
||||
unsigned char * ident = NULL;
|
||||
unsigned int identlen = 0;
|
||||
unsigned char * type_name = NULL;
|
||||
unsigned int type_name_len = 0;
|
||||
|
||||
TRACE(("enter buf_verify"))
|
||||
|
||||
bloblen = buf_getint(buf);
|
||||
ident = buf_getstring(buf, &identlen);
|
||||
type_name = buf_getstring(buf, &type_name_len);
|
||||
enum signkey_type type = signkey_type_from_name(type_name, type_name_len);
|
||||
m_free(type_name);
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (bloblen == DSS_SIGNATURE_SIZE &&
|
||||
memcmp(ident, SSH_SIGNKEY_DSS, identlen) == 0) {
|
||||
m_free(ident);
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
if (key->dsskey == NULL) {
|
||||
dropbear_exit("No DSS key to verify signature");
|
||||
}
|
||||
return buf_dss_verify(buf, key->dsskey, data, len);
|
||||
return buf_dss_verify(buf, key->dsskey, data_buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (memcmp(ident, SSH_SIGNKEY_RSA, identlen) == 0) {
|
||||
m_free(ident);
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
if (key->rsakey == NULL) {
|
||||
dropbear_exit("No RSA key to verify signature");
|
||||
}
|
||||
return buf_rsa_verify(buf, key->rsakey, data, len);
|
||||
return buf_rsa_verify(buf, key->rsakey, data_buf);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
{
|
||||
ecc_key **eck = signkey_ecc_key_ptr(key, type);
|
||||
if (eck) {
|
||||
return buf_ecdsa_verify(buf, *eck, data_buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_free(ident);
|
||||
dropbear_exit("Non-matching signing type");
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
47
signkey.h
47
signkey.h
@@ -29,6 +29,24 @@
|
||||
#include "dss.h"
|
||||
#include "rsa.h"
|
||||
|
||||
enum signkey_type {
|
||||
#ifdef DROPBEAR_RSA
|
||||
DROPBEAR_SIGNKEY_RSA,
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
DROPBEAR_SIGNKEY_DSS,
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
DROPBEAR_SIGNKEY_ECDSA_NISTP256,
|
||||
DROPBEAR_SIGNKEY_ECDSA_NISTP384,
|
||||
DROPBEAR_SIGNKEY_ECDSA_NISTP521,
|
||||
DROPBEAR_SIGNKEY_ECDSA_KEYGEN, // just "ecdsa" for keygen
|
||||
#endif // DROPBEAR_ECDSA
|
||||
DROPBEAR_SIGNKEY_NUM_NAMED,
|
||||
DROPBEAR_SIGNKEY_ANY = 80,
|
||||
DROPBEAR_SIGNKEY_NONE = 90,
|
||||
};
|
||||
|
||||
|
||||
/* Sources for signing keys */
|
||||
typedef enum {
|
||||
@@ -39,11 +57,9 @@ typedef enum {
|
||||
|
||||
struct SIGN_key {
|
||||
|
||||
int type; /* The type of key (dss or rsa) */
|
||||
enum signkey_type type;
|
||||
signkey_source source;
|
||||
char *filename;
|
||||
/* the buffer? for encrypted keys, so we can later get
|
||||
* the private key portion */
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
dropbear_dss_key * dsskey;
|
||||
@@ -51,27 +67,40 @@ struct SIGN_key {
|
||||
#ifdef DROPBEAR_RSA
|
||||
dropbear_rsa_key * rsakey;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
ecc_key * ecckey256;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
ecc_key * ecckey384;
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
ecc_key * ecckey521;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct SIGN_key sign_key;
|
||||
|
||||
sign_key * new_sign_key();
|
||||
const char* signkey_name_from_type(int type, int *namelen);
|
||||
int signkey_type_from_name(const char* name, int namelen);
|
||||
const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen);
|
||||
enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen);
|
||||
int buf_get_pub_key(buffer *buf, sign_key *key, int *type);
|
||||
int buf_get_priv_key(buffer* buf, sign_key *key, int *type);
|
||||
void buf_put_pub_key(buffer* buf, sign_key *key, int type);
|
||||
void buf_put_priv_key(buffer* buf, sign_key *key, int type);
|
||||
void sign_key_free(sign_key *key);
|
||||
void buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
const unsigned char *data, unsigned int len);
|
||||
void buf_put_sign(buffer* buf, sign_key *key, int type, buffer *data_buf);
|
||||
#ifdef DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
|
||||
unsigned int len);
|
||||
int buf_verify(buffer * buf, sign_key *key, buffer *data_buf);
|
||||
char * sign_key_fingerprint(unsigned char* keyblob, unsigned int keybloblen);
|
||||
#endif
|
||||
int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
|
||||
const unsigned char* algoname, unsigned int algolen,
|
||||
buffer * line, char ** fingerprint);
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
ecc_key ** signkey_ecc_key_ptr(sign_key *key, enum signkey_type ecc_type);
|
||||
#endif
|
||||
|
||||
#endif /* _SIGNKEY_H_ */
|
||||
|
||||
11
svr-auth.c
11
svr-auth.c
@@ -88,8 +88,7 @@ void send_msg_userauth_banner(buffer *banner) {
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER);
|
||||
buf_putstring(ses.writepayload, buf_getptr(banner, banner->len),
|
||||
banner->len);
|
||||
buf_putbufstring(ses.writepayload, banner);
|
||||
buf_putstring(ses.writepayload, "en", 2);
|
||||
|
||||
encrypt_packet();
|
||||
@@ -344,12 +343,10 @@ void send_msg_userauth_failure(int partial, int incrfail) {
|
||||
buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
|
||||
}
|
||||
|
||||
buf_setpos(typebuf, 0);
|
||||
buf_putstring(ses.writepayload, buf_getptr(typebuf, typebuf->len),
|
||||
typebuf->len);
|
||||
buf_putbufstring(ses.writepayload, typebuf);
|
||||
|
||||
TRACE(("auth fail: methods %d, '%s'", ses.authstate.authtypes,
|
||||
buf_getptr(typebuf, typebuf->len)));
|
||||
TRACE(("auth fail: methods %d, '%.*s'", ses.authstate.authtypes,
|
||||
typebuf->len, typebuf->data))
|
||||
|
||||
buf_free(typebuf);
|
||||
|
||||
|
||||
@@ -125,15 +125,14 @@ void svr_auth_pubkey() {
|
||||
|
||||
/* create the data which has been signed - this a string containing
|
||||
* session_id, concatenated with the payload packet up to the signature */
|
||||
signbuf = buf_new(ses.payload->pos + 4 + SHA1_HASH_SIZE);
|
||||
buf_putstring(signbuf, ses.session_id, SHA1_HASH_SIZE);
|
||||
signbuf = buf_new(ses.payload->pos + 4 + ses.session_id->len);
|
||||
buf_putbufstring(signbuf, ses.session_id);
|
||||
buf_putbytes(signbuf, ses.payload->data, ses.payload->pos);
|
||||
buf_setpos(signbuf, 0);
|
||||
|
||||
/* ... and finally verify the signature */
|
||||
fp = sign_key_fingerprint(keyblob, keybloblen);
|
||||
if (buf_verify(ses.payload, key, buf_getptr(signbuf, signbuf->len),
|
||||
signbuf->len) == DROPBEAR_SUCCESS) {
|
||||
if (buf_verify(ses.payload, key, signbuf) == DROPBEAR_SUCCESS) {
|
||||
dropbear_log(LOG_NOTICE,
|
||||
"Pubkey auth succeeded for '%s' with key %s from %s",
|
||||
ses.authstate.pw_name, fp, svr_ses.addrstring);
|
||||
|
||||
59
svr-kex.c
59
svr-kex.c
@@ -34,9 +34,9 @@
|
||||
#include "bignum.h"
|
||||
#include "random.h"
|
||||
#include "runopts.h"
|
||||
#include "ecc.h"
|
||||
|
||||
|
||||
static void send_msg_kexdh_reply(mp_int *dh_e);
|
||||
static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs);
|
||||
|
||||
/* Handle a diffie-hellman key exchange initialisation. This involves
|
||||
* calculating a session key reply value, and corresponding hash. These
|
||||
@@ -45,20 +45,30 @@ static void send_msg_kexdh_reply(mp_int *dh_e);
|
||||
void recv_msg_kexdh_init() {
|
||||
|
||||
DEF_MP_INT(dh_e);
|
||||
buffer *ecdh_qs = NULL;
|
||||
|
||||
TRACE(("enter recv_msg_kexdh_init"))
|
||||
if (!ses.kexstate.recvkexinit) {
|
||||
dropbear_exit("Premature kexdh_init message received");
|
||||
}
|
||||
|
||||
m_mp_init(&dh_e);
|
||||
if (buf_getmpint(ses.payload, &dh_e) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failed to get kex value");
|
||||
if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
|
||||
m_mp_init(&dh_e);
|
||||
if (buf_getmpint(ses.payload, &dh_e) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failed to get kex value");
|
||||
}
|
||||
} else {
|
||||
#ifdef DROPBEAR_ECDH
|
||||
ecdh_qs = buf_getstringbuf(ses.payload);
|
||||
#endif
|
||||
}
|
||||
|
||||
send_msg_kexdh_reply(&dh_e);
|
||||
send_msg_kexdh_reply(&dh_e, ecdh_qs);
|
||||
|
||||
mp_clear(&dh_e);
|
||||
if (ecdh_qs) {
|
||||
buf_free(ecdh_qs);
|
||||
}
|
||||
|
||||
send_msg_newkeys();
|
||||
ses.requirenext[0] = SSH_MSG_NEWKEYS;
|
||||
@@ -71,19 +81,10 @@ void recv_msg_kexdh_init() {
|
||||
* that, the session hash is calculated, and signed with RSA or DSS. The
|
||||
* result is sent to the client.
|
||||
*
|
||||
* See the transport rfc 4253 section 8 for details */
|
||||
static void send_msg_kexdh_reply(mp_int *dh_e) {
|
||||
|
||||
DEF_MP_INT(dh_y);
|
||||
DEF_MP_INT(dh_f);
|
||||
|
||||
* See the transport RFC4253 section 8 for details
|
||||
* or RFC5656 section 4 for elliptic curve variant. */
|
||||
static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) {
|
||||
TRACE(("enter send_msg_kexdh_reply"))
|
||||
m_mp_init_multi(&dh_y, &dh_f, NULL);
|
||||
|
||||
gen_kexdh_vals(&dh_f, &dh_y);
|
||||
|
||||
kexdh_comb_key(&dh_f, &dh_y, dh_e, svr_opts.hostkey);
|
||||
mp_clear(&dh_y);
|
||||
|
||||
/* we can start creating the kexdh_reply packet */
|
||||
CHECKCLEARTOWRITE();
|
||||
@@ -91,13 +92,27 @@ static void send_msg_kexdh_reply(mp_int *dh_e) {
|
||||
buf_put_pub_key(ses.writepayload, svr_opts.hostkey,
|
||||
ses.newkeys->algo_hostkey);
|
||||
|
||||
/* put f */
|
||||
buf_putmpint(ses.writepayload, &dh_f);
|
||||
mp_clear(&dh_f);
|
||||
if (IS_NORMAL_DH(ses.newkeys->algo_kex)) {
|
||||
// Normal diffie-hellman
|
||||
struct kex_dh_param * dh_param = gen_kexdh_param();
|
||||
kexdh_comb_key(dh_param, dh_e, svr_opts.hostkey);
|
||||
|
||||
/* put f */
|
||||
buf_putmpint(ses.writepayload, &dh_param->pub);
|
||||
free_kexdh_param(dh_param);
|
||||
} else {
|
||||
#ifdef DROPBEAR_ECDH
|
||||
struct kex_ecdh_param *ecdh_param = gen_kexecdh_param();
|
||||
kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
|
||||
|
||||
buf_put_ecc_raw_pubkey_string(ses.writepayload, &ecdh_param->key);
|
||||
free_kexecdh_param(ecdh_param);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* calc the signature */
|
||||
buf_put_sign(ses.writepayload, svr_opts.hostkey,
|
||||
ses.newkeys->algo_hostkey, ses.hash, SHA1_HASH_SIZE);
|
||||
ses.newkeys->algo_hostkey, ses.hash);
|
||||
|
||||
/* the SSH_MSG_KEXDH_REPLY is done */
|
||||
encrypt_packet();
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "signkey.h"
|
||||
#include "runopts.h"
|
||||
#include "random.h"
|
||||
#include "crypto_desc.h"
|
||||
|
||||
static size_t listensockets(int *sock, size_t sockcount, int *maxfd);
|
||||
static void sigchld_handler(int dummy);
|
||||
@@ -383,9 +384,11 @@ static void commonsetup() {
|
||||
dropbear_exit("signal() error");
|
||||
}
|
||||
|
||||
crypto_init();
|
||||
|
||||
/* Now we can setup the hostkeys - needs to be after logging is on,
|
||||
* otherwise we might end up blatting error messages to the socket */
|
||||
loadhostkeys();
|
||||
load_all_hostkeys();
|
||||
|
||||
seedrandom();
|
||||
}
|
||||
|
||||
157
svr-runopts.c
157
svr-runopts.c
@@ -28,11 +28,14 @@
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
#include "algo.h"
|
||||
#include "ecdsa.h"
|
||||
|
||||
svr_runopts svr_opts; /* GLOBAL */
|
||||
|
||||
static void printhelp(const char * progname);
|
||||
static void addportandaddress(char* spec);
|
||||
static void loadhostkey(const char *keyfile, int fatal_duplicate);
|
||||
static void addhostkey(const char *keyfile);
|
||||
|
||||
static void printhelp(const char * progname) {
|
||||
|
||||
@@ -105,10 +108,10 @@ void svr_getopts(int argc, char ** argv) {
|
||||
char* recv_window_arg = NULL;
|
||||
char* keepalive_arg = NULL;
|
||||
char* idle_timeout_arg = NULL;
|
||||
char* keyfile = NULL;
|
||||
|
||||
|
||||
/* see printhelp() for options */
|
||||
svr_opts.rsakeyfile = NULL;
|
||||
svr_opts.dsskeyfile = NULL;
|
||||
svr_opts.bannerfile = NULL;
|
||||
svr_opts.banner = NULL;
|
||||
svr_opts.forkbg = 1;
|
||||
@@ -160,6 +163,11 @@ void svr_getopts(int argc, char ** argv) {
|
||||
dropbear_exit("Invalid null argument");
|
||||
}
|
||||
next = 0x00;
|
||||
|
||||
if (keyfile) {
|
||||
addhostkey(keyfile);
|
||||
keyfile = NULL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -168,16 +176,10 @@ void svr_getopts(int argc, char ** argv) {
|
||||
case 'b':
|
||||
next = &svr_opts.bannerfile;
|
||||
break;
|
||||
#ifdef DROPBEAR_DSS
|
||||
case 'd':
|
||||
next = &svr_opts.dsskeyfile;
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
case 'r':
|
||||
next = &svr_opts.rsakeyfile;
|
||||
next = &keyfile;
|
||||
break;
|
||||
#endif
|
||||
case 'F':
|
||||
svr_opts.forkbg = 0;
|
||||
break;
|
||||
@@ -267,13 +269,6 @@ void svr_getopts(int argc, char ** argv) {
|
||||
svr_opts.portcount = 1;
|
||||
}
|
||||
|
||||
if (svr_opts.dsskeyfile == NULL) {
|
||||
svr_opts.dsskeyfile = DSS_PRIV_FILENAME;
|
||||
}
|
||||
if (svr_opts.rsakeyfile == NULL) {
|
||||
svr_opts.rsakeyfile = RSA_PRIV_FILENAME;
|
||||
}
|
||||
|
||||
if (svr_opts.bannerfile) {
|
||||
struct stat buf;
|
||||
if (stat(svr_opts.bannerfile, &buf) != 0) {
|
||||
@@ -292,7 +287,6 @@ void svr_getopts(int argc, char ** argv) {
|
||||
svr_opts.bannerfile);
|
||||
}
|
||||
buf_setpos(svr_opts.banner, 0);
|
||||
|
||||
}
|
||||
|
||||
if (recv_window_arg) {
|
||||
@@ -370,55 +364,126 @@ static void addportandaddress(char* spec) {
|
||||
}
|
||||
}
|
||||
|
||||
static void disablekey(int type, const char* filename) {
|
||||
|
||||
static void disablekey(int type) {
|
||||
int i;
|
||||
|
||||
TRACE(("Disabling key type %d", type))
|
||||
for (i = 0; sshhostkey[i].name != NULL; i++) {
|
||||
if (sshhostkey[i].val == type) {
|
||||
sshhostkey[i].usable = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dropbear_log(LOG_WARNING, "Failed reading '%s', disabling %s", filename,
|
||||
type == DROPBEAR_SIGNKEY_DSS ? "DSS" : "RSA");
|
||||
}
|
||||
|
||||
static void loadhostkey_helper(const char *name, void** src, void** dst, int fatal_duplicate) {
|
||||
if (*dst) {
|
||||
if (fatal_duplicate) {
|
||||
dropbear_exit("Only one %s key can be specified", name);
|
||||
}
|
||||
} else {
|
||||
*dst = *src;
|
||||
*src = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Must be called after syslog/etc is working */
|
||||
void loadhostkeys() {
|
||||
static void loadhostkey(const char *keyfile, int fatal_duplicate) {
|
||||
sign_key * read_key = new_sign_key();
|
||||
int type = DROPBEAR_SIGNKEY_ANY;
|
||||
if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) {
|
||||
dropbear_log(LOG_WARNING, "Failed loading %s", keyfile);
|
||||
}
|
||||
|
||||
int ret;
|
||||
int type;
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (type == DROPBEAR_SIGNKEY_RSA) {
|
||||
loadhostkey_helper("RSA", &read_key->rsakey, &svr_opts.hostkey->rsakey, fatal_duplicate);
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE(("enter loadhostkeys"))
|
||||
#ifdef DROPBEAR_DSS
|
||||
if (type == DROPBEAR_SIGNKEY_DSS) {
|
||||
loadhostkey_helper("DSS", &read_key->dsskey, &svr_opts.hostkey->dsskey, fatal_duplicate);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256) {
|
||||
loadhostkey_helper("ECDSA256", &read_key->ecckey256, &svr_opts.hostkey->ecckey256, fatal_duplicate);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP384) {
|
||||
loadhostkey_helper("ECDSA384", &read_key->ecckey384, &svr_opts.hostkey->ecckey384, fatal_duplicate);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
|
||||
loadhostkey_helper("ECDSA521", &read_key->ecckey521, &svr_opts.hostkey->ecckey521, fatal_duplicate);
|
||||
}
|
||||
#endif
|
||||
#endif // DROPBEAR_ECDSA
|
||||
sign_key_free(read_key);
|
||||
TRACE(("leave loadhostkey"))
|
||||
}
|
||||
|
||||
static void addhostkey(const char *keyfile) {
|
||||
if (svr_opts.num_hostkey_files >= MAX_HOSTKEYS) {
|
||||
dropbear_exit("Too many hostkeys");
|
||||
}
|
||||
svr_opts.hostkey_files[svr_opts.num_hostkey_files] = m_strdup(keyfile);
|
||||
svr_opts.num_hostkey_files++;
|
||||
}
|
||||
|
||||
void load_all_hostkeys() {
|
||||
int i;
|
||||
|
||||
svr_opts.hostkey = new_sign_key();
|
||||
|
||||
for (i = 0; i < svr_opts.num_hostkey_files; i++) {
|
||||
char *hostkey_file = svr_opts.hostkey_files[i];
|
||||
loadhostkey(hostkey_file, 1);
|
||||
m_free(hostkey_file);
|
||||
}
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
type = DROPBEAR_SIGNKEY_RSA;
|
||||
ret = readhostkey(svr_opts.rsakeyfile, svr_opts.hostkey, &type);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
disablekey(DROPBEAR_SIGNKEY_RSA, svr_opts.rsakeyfile);
|
||||
loadhostkey(RSA_PRIV_FILENAME, 0);
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_DSS
|
||||
loadhostkey(DSS_PRIV_FILENAME, 0);
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
loadhostkey(ECDSA_PRIV_FILENAME, 0);
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_RSA
|
||||
if (!svr_opts.hostkey->rsakey) {
|
||||
disablekey(DROPBEAR_SIGNKEY_RSA);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_DSS
|
||||
type = DROPBEAR_SIGNKEY_DSS;
|
||||
ret = readhostkey(svr_opts.dsskeyfile, svr_opts.hostkey, &type);
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
disablekey(DROPBEAR_SIGNKEY_DSS, svr_opts.dsskeyfile);
|
||||
if (!svr_opts.hostkey->dsskey) {
|
||||
disablekey(DROPBEAR_SIGNKEY_RSA);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( 1
|
||||
#ifdef DROPBEAR_DSS
|
||||
&& svr_opts.hostkey->dsskey == NULL
|
||||
#endif
|
||||
#ifdef DROPBEAR_RSA
|
||||
&& svr_opts.hostkey->rsakey == NULL
|
||||
#endif
|
||||
) {
|
||||
dropbear_exit("No hostkeys available");
|
||||
#ifdef DROPBEAR_ECDSA
|
||||
#ifdef DROPBEAR_ECC_256
|
||||
if (!svr_opts.hostkey->ecckey256) {
|
||||
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
|
||||
}
|
||||
|
||||
TRACE(("leave loadhostkeys"))
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_384
|
||||
if (!svr_opts.hostkey->ecckey384) {
|
||||
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
|
||||
}
|
||||
#endif
|
||||
#ifdef DROPBEAR_ECC_521
|
||||
if (!svr_opts.hostkey->ecckey521) {
|
||||
disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "service.h"
|
||||
#include "auth.h"
|
||||
#include "runopts.h"
|
||||
#include "crypto_desc.h"
|
||||
|
||||
static void svr_remoteclosed();
|
||||
|
||||
@@ -83,7 +84,6 @@ void svr_session(int sock, int childpipe) {
|
||||
char *host, *port;
|
||||
size_t len;
|
||||
|
||||
crypto_init();
|
||||
common_session_init(sock, sock);
|
||||
|
||||
/* Initialise server specific parts of the session */
|
||||
|
||||
65
sysoptions.h
65
sysoptions.h
@@ -69,20 +69,6 @@
|
||||
#define DROPBEAR_SUCCESS 0
|
||||
#define DROPBEAR_FAILURE -1
|
||||
|
||||
/* various algorithm identifiers */
|
||||
#define DROPBEAR_KEX_NONE 0
|
||||
#define DROPBEAR_KEX_DH_GROUP1 1
|
||||
#define DROPBEAR_KEX_DH_GROUP14 2
|
||||
|
||||
#define DROPBEAR_SIGNKEY_ANY 0
|
||||
#define DROPBEAR_SIGNKEY_RSA 1
|
||||
#define DROPBEAR_SIGNKEY_DSS 2
|
||||
#define DROPBEAR_SIGNKEY_NONE 3
|
||||
|
||||
#define DROPBEAR_COMP_NONE 0
|
||||
#define DROPBEAR_COMP_ZLIB 1
|
||||
#define DROPBEAR_COMP_ZLIB_DELAY 2
|
||||
|
||||
/* Required for pubkey auth */
|
||||
#if defined(ENABLE_SVR_PUBKEY_AUTH) || defined(DROPBEAR_CLIENT)
|
||||
#define DROPBEAR_SIGNKEY_VERIFY
|
||||
@@ -92,8 +78,7 @@
|
||||
#define MD5_HASH_SIZE 16
|
||||
|
||||
#define MAX_KEY_LEN 32 /* 256 bits for aes256 etc */
|
||||
#define MAX_IV_LEN 20 /* must be same as max blocksize,
|
||||
and >= SHA1_HASH_SIZE */
|
||||
#define MAX_IV_LEN 20 /* must be same as max blocksize, */
|
||||
|
||||
#if defined(DROPBEAR_SHA2_512_HMAC)
|
||||
#define MAX_MAC_LEN 64
|
||||
@@ -103,6 +88,39 @@
|
||||
#define MAX_MAC_LEN 20
|
||||
#endif
|
||||
|
||||
#if defined(DROPBEAR_ECDH) || defined (DROPBEAR_ECDSA)
|
||||
#define DROPBEAR_ECC
|
||||
/* Debian doesn't define this in system headers */
|
||||
#define LTM_DESC
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
#define DROPBEAR_ECC_256
|
||||
#define DROPBEAR_ECC_384
|
||||
#define DROPBEAR_ECC_521
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_ECC
|
||||
#define DROPBEAR_LTC_PRNG
|
||||
#endif
|
||||
|
||||
// hashes which will be linked and registered
|
||||
#if defined(DROPBEAR_SHA2_256_HMAC) || defined(DROPBEAR_ECC_256)
|
||||
#define DROPBEAR_SHA256
|
||||
#endif
|
||||
#if defined(DROPBEAR_ECC_384)
|
||||
#define DROPBEAR_SHA384
|
||||
#endif
|
||||
#if defined(DROPBEAR_SHA2_512_HMAC) || defined(DROPBEAR_ECC_521)
|
||||
#define DROPBEAR_SHA512
|
||||
#endif
|
||||
#if defined(DROPBEAR_MD5_HMAC)
|
||||
#define DROPBEAR_MD5
|
||||
#endif
|
||||
|
||||
// roughly 2x 521 bits
|
||||
#define MAX_ECC_SIZE 140
|
||||
|
||||
#define MAX_NAME_LEN 64 /* maximum length of a protocol name, isn't
|
||||
explicitly specified for all protocols (just
|
||||
for algos) but seems valid */
|
||||
@@ -134,6 +152,8 @@
|
||||
/* For a 4096 bit DSS key, empirically determined */
|
||||
#define MAX_PRIVKEY_SIZE 1700
|
||||
|
||||
#define MAX_HOSTKEYS 3
|
||||
|
||||
/* The maximum size of the bignum portion of the kexhash buffer */
|
||||
/* Sect. 8 of the transport rfc 4253, K_S + e + f + K */
|
||||
#define KEXHASHBUF_MAX_INTS (1700 + 130 + 130 + 130)
|
||||
@@ -155,19 +175,6 @@
|
||||
#define DROPBEAR_TWOFISH
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_MD5_HMAC
|
||||
#define DROPBEAR_MD5
|
||||
#endif
|
||||
|
||||
#ifdef DROPBEAR_SHA2_256_HMAC
|
||||
#define DROPBEAR_SHA256
|
||||
#endif
|
||||
|
||||
#if (defined(DROPBEAR_DSS) && defined(DSS_PROTOK)) \
|
||||
|| defined(DROPBEAR_SHA2_512_HMAC)
|
||||
#define DROPBEAR_SHA512
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_X11FWD
|
||||
#define DISABLE_X11FWD
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user