static sign_key * loadhostkeys(const char * dsskeyfile, const char * rsakeyfile) { sign_key * hostkey; TRACE(("enter loadhostkeys")); hostkey = new_sign_key(); #ifdef DROPBEAR_RSA (void)readhostkey(rsakeyfile, hostkey, DROPBEAR_SIGNKEY_RSA); #endif #ifdef DROPBEAR_DSS (void)readhostkey(dsskeyfile, hostkey, DROPBEAR_SIGNKEY_DSS); #endif if ( 1 #ifdef DROPBEAR_DSS && hostkey->dsskey == NULL #endif #ifdef DROPBEAR_RSA && hostkey->rsakey == NULL #endif ) { dropbear_exit("No hostkeys available"); } TRACE(("leave loadhostkeys")); return hostkey; }
int signkey_generate(enum signkey_type keytype, int bits, const char* filename) { sign_key * key = NULL; buffer *buf = NULL; int ret = DROPBEAR_FAILURE; if (bits == 0) { bits = get_default_bits(keytype); } /* now we can generate the key */ key = new_sign_key(); seedrandom(); switch(keytype) { #ifdef DROPBEAR_RSA case DROPBEAR_SIGNKEY_RSA: key->rsakey = gen_rsa_priv_key(bits); break; #endif #ifdef DROPBEAR_DSS case DROPBEAR_SIGNKEY_DSS: key->dsskey = gen_dss_priv_key(bits); break; #endif #ifdef DROPBEAR_ECDSA case DROPBEAR_SIGNKEY_ECDSA_KEYGEN: case DROPBEAR_SIGNKEY_ECDSA_NISTP521: case DROPBEAR_SIGNKEY_ECDSA_NISTP384: case DROPBEAR_SIGNKEY_ECDSA_NISTP256: { ecc_key *ecckey = gen_ecdsa_priv_key(bits); keytype = ecdsa_signkey_type(ecckey); *signkey_key_ptr(key, keytype) = ecckey; } break; #endif default: dropbear_exit("Internal error"); } seedrandom(); buf = buf_new(MAX_PRIVKEY_SIZE); buf_put_priv_key(buf, key, keytype); sign_key_free(key); key = NULL; buf_setpos(buf, 0); ret = buf_writefile(buf, filename); buf_burn(buf); buf_free(buf); buf = NULL; return ret; }
/* 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)) hostkey = new_sign_key(); keybloblen = buf_getint(ses.payload); keyblob = buf_getptr(ses.payload, keybloblen); if (!ses.kexstate.donefirstkex) { /* Only makes sense the first time */ checkhostkey(keyblob, keybloblen); } if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) { TRACE(("failed getting pubkey")) dropbear_exit("Bad KEX packet"); } if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) { TRACE(("failed getting mpint")) dropbear_exit("Bad KEX packet"); } 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); if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE) != DROPBEAR_SUCCESS) { dropbear_exit("Bad hostkey signature"); } sign_key_free(hostkey); hostkey = NULL; send_msg_newkeys(); ses.requirenext = SSH_MSG_NEWKEYS; TRACE(("leave recv_msg_kexdh_init")) }
/* Must be called after syslog/etc is working */ static void loadhostkey(const char *keyfile, int fatal_duplicate) { sign_key * read_key = new_sign_key(); enum signkey_type type = DROPBEAR_SIGNKEY_ANY; if (readhostkey(keyfile, read_key, &type) == DROPBEAR_FAILURE) { if (!svr_opts.delay_hostkey) { dropbear_log(LOG_WARNING, "Failed loading %s", keyfile); } } #ifdef DROPBEAR_RSA if (type == DROPBEAR_SIGNKEY_RSA) { loadhostkey_helper("RSA", (void**)&read_key->rsakey, (void**)&svr_opts.hostkey->rsakey, fatal_duplicate); } #endif #ifdef DROPBEAR_DSS if (type == DROPBEAR_SIGNKEY_DSS) { loadhostkey_helper("DSS", (void**)&read_key->dsskey, (void**)&svr_opts.hostkey->dsskey, fatal_duplicate); } #endif #ifdef DROPBEAR_ECDSA #ifdef DROPBEAR_ECC_256 if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP256) { loadhostkey_helper("ECDSA256", (void**)&read_key->ecckey256, (void**)&svr_opts.hostkey->ecckey256, fatal_duplicate); } #endif #ifdef DROPBEAR_ECC_384 if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP384) { loadhostkey_helper("ECDSA384", (void**)&read_key->ecckey384, (void**)&svr_opts.hostkey->ecckey384, fatal_duplicate); } #endif #ifdef DROPBEAR_ECC_521 if (type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) { loadhostkey_helper("ECDSA521", (void**)&read_key->ecckey521, (void**)&svr_opts.hostkey->ecckey521, fatal_duplicate); } #endif #endif /* DROPBEAR_ECDSA */ sign_key_free(read_key); TRACE(("leave loadhostkey")) }
static int printpubfile(const char* filename) { buffer *buf = NULL; sign_key *key = NULL; enum signkey_type keytype; int ret; int err = DROPBEAR_FAILURE; buf = buf_new(MAX_PRIVKEY_SIZE); ret = buf_readfile(buf, filename); if (ret != DROPBEAR_SUCCESS) { fprintf(stderr, "Failed reading '%s'\n", filename); goto out; } key = new_sign_key(); keytype = DROPBEAR_SIGNKEY_ANY; buf_setpos(buf, 0); ret = buf_get_priv_key(buf, key, &keytype); if (ret == DROPBEAR_FAILURE) { fprintf(stderr, "Bad key in '%s'\n", filename); goto out; } printpubkey(key, keytype); err = DROPBEAR_SUCCESS; out: buf_burn(buf); buf_free(buf); buf = NULL; if (key) { sign_key_free(key); key = NULL; } return err; }
/* Must be called after syslog/etc is working */ void loadhostkeys() { int ret; int type; TRACE(("enter loadhostkeys")) svr_opts.hostkey = new_sign_key(); #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); } #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); } #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"); } TRACE(("leave loadhostkeys")) }
void load_all_hostkeys() { int i; int disable_unset_keys = 1; int any_keys = 0; 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 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_DELAY_HOSTKEY if (svr_opts.delay_hostkey) { disable_unset_keys = 0; } #endif #ifdef DROPBEAR_RSA if (disable_unset_keys && !svr_opts.hostkey->rsakey) { disablekey(DROPBEAR_SIGNKEY_RSA); } else { any_keys = 1; } #endif #ifdef DROPBEAR_DSS if (disable_unset_keys && !svr_opts.hostkey->dsskey) { disablekey(DROPBEAR_SIGNKEY_DSS); } else { any_keys = 1; } #endif #ifdef DROPBEAR_ECDSA #ifdef DROPBEAR_ECC_256 if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 256) && !svr_opts.hostkey->ecckey256) { disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256); } else { any_keys = 1; } #endif #ifdef DROPBEAR_ECC_384 if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 384) && !svr_opts.hostkey->ecckey384) { disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384); } else { any_keys = 1; } #endif #ifdef DROPBEAR_ECC_521 if ((disable_unset_keys || ECDSA_DEFAULT_SIZE != 521) && !svr_opts.hostkey->ecckey521) { disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521); } else { any_keys = 1; } #endif #endif /* DROPBEAR_ECDSA */ if (!any_keys) { dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey."); } }
/* Handle a diffie-hellman key exchange reply. */ void recv_msg_kexdh_reply() { 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"); } type = ses.newkeys->algo_hostkey; TRACE(("type is %d", type)) hostkey = new_sign_key(); keybloblen = buf_getint(ses.payload); keyblob = buf_getptr(ses.payload, keybloblen); if (!ses.kexstate.donefirstkex) { /* Only makes sense the first time */ checkhostkey(keyblob, keybloblen); } if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) { TRACE(("failed getting pubkey")) dropbear_exit("Bad KEX packet"); } switch (ses.newkeys->algo_kex->mode) { case DROPBEAR_KEX_NORMAL_DH: { 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); } break; case DROPBEAR_KEX_ECDH: #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 break; #ifdef DROPBEAR_CURVE25519 case DROPBEAR_KEX_CURVE25519: { buffer *ecdh_qs = buf_getstringbuf(ses.payload); kexcurve25519_comb_key(cli_ses.curve25519_param, ecdh_qs, hostkey); buf_free(ecdh_qs); } #endif break; } 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 #ifdef DROPBEAR_CURVE25519 if (cli_ses.curve25519_param) { free_kexcurve25519_param(cli_ses.curve25519_param); cli_ses.curve25519_param = NULL; } #endif cli_ses.param_kex_algo = NULL; if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) { dropbear_exit("Bad hostkey signature"); } sign_key_free(hostkey); hostkey = NULL; send_msg_newkeys(); ses.requirenext[0] = SSH_MSG_NEWKEYS; ses.requirenext[1] = 0; TRACE(("leave recv_msg_kexdh_init")) }
/* if skip_exist is set it will silently return if the key file exists */ int signkey_generate(enum signkey_type keytype, int bits, const char* filename, int skip_exist) { sign_key * key = NULL; buffer *buf = NULL; char *fn_temp = NULL; int ret = DROPBEAR_FAILURE; bits = signkey_generate_get_bits(keytype, bits); /* now we can generate the key */ key = new_sign_key(); seedrandom(); switch(keytype) { #if DROPBEAR_RSA case DROPBEAR_SIGNKEY_RSA: key->rsakey = gen_rsa_priv_key(bits); break; #endif #if DROPBEAR_DSS case DROPBEAR_SIGNKEY_DSS: key->dsskey = gen_dss_priv_key(bits); break; #endif #if DROPBEAR_ECDSA case DROPBEAR_SIGNKEY_ECDSA_KEYGEN: case DROPBEAR_SIGNKEY_ECDSA_NISTP521: case DROPBEAR_SIGNKEY_ECDSA_NISTP384: case DROPBEAR_SIGNKEY_ECDSA_NISTP256: { ecc_key *ecckey = gen_ecdsa_priv_key(bits); keytype = ecdsa_signkey_type(ecckey); *signkey_key_ptr(key, keytype) = ecckey; } break; #endif default: dropbear_exit("Internal error"); } seedrandom(); buf = buf_new(MAX_PRIVKEY_SIZE); buf_put_priv_key(buf, key, keytype); sign_key_free(key); key = NULL; buf_setpos(buf, 0); fn_temp = m_malloc(strlen(filename) + 30); snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid()); ret = buf_writefile(buf, fn_temp); if (ret == DROPBEAR_FAILURE) { goto out; } if (link(fn_temp, filename) < 0) { /* If generating keys on connection (skipexist) it's OK to get EEXIST - we probably just lost a race with another connection to generate the key */ if (!(skip_exist && errno == EEXIST)) { dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename, strerror(errno)); /* XXX fallback to non-atomic copy for some filesystems? */ ret = DROPBEAR_FAILURE; goto out; } } out: if (buf) { buf_burn(buf); buf_free(buf); } if (fn_temp) { unlink(fn_temp); m_free(fn_temp); } return ret; }