summaryrefslogtreecommitdiff
path: root/gensignkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'gensignkey.c')
-rw-r--r--gensignkey.c43
1 files changed, 35 insertions, 8 deletions
diff --git a/gensignkey.c b/gensignkey.c
index 8317fea..4be3d7d 100644
--- a/gensignkey.c
+++ b/gensignkey.c
@@ -4,18 +4,26 @@
#include "ecdsa.h"
#include "genrsa.h"
#include "gendss.h"
+#include "gened25519.h"
#include "signkey.h"
#include "dbrandom.h"
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
-static int buf_writefile(buffer * buf, const char * filename) {
+static int buf_writefile(buffer * buf, const char * filename, int skip_exist) {
int ret = DROPBEAR_FAILURE;
int fd = -1;
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) {
- dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
- filename, strerror(errno));
+ /* If generating keys on connection (skip_exist) it's OK to get EEXIST
+ - we probably just lost a race with another connection to generate the key */
+ if (skip_exist && errno == EEXIST) {
+ ret = DROPBEAR_SUCCESS;
+ } else {
+ dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
+ filename, strerror(errno));
+ }
+
goto out;
}
@@ -69,6 +77,10 @@ static int get_default_bits(enum signkey_type keytype)
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
return 256;
#endif
+#if DROPBEAR_ED25519
+ case DROPBEAR_SIGNKEY_ED25519:
+ return 256;
+#endif
default:
return 0;
}
@@ -119,6 +131,11 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
}
break;
#endif
+#if DROPBEAR_ED25519
+ case DROPBEAR_SIGNKEY_ED25519:
+ key->ed25519key = gen_ed25519_priv_key(bits);
+ break;
+#endif
default:
dropbear_exit("Internal error");
}
@@ -134,7 +151,7 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
fn_temp = m_malloc(strlen(filename) + 30);
snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid());
- ret = buf_writefile(buf, fn_temp);
+ ret = buf_writefile(buf, fn_temp, 0);
if (ret == DROPBEAR_FAILURE) {
goto out;
@@ -144,14 +161,24 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
/* 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;
+ if (errno == EPERM || errno == EACCES) {
+ /* Non-atomic fallback when hard-links not allowed or unsupported */
+ buf_setpos(buf, 0);
+ ret = buf_writefile(buf, filename, skip_exist);
+ } else {
+ dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
+ strerror(errno));
+ ret = DROPBEAR_FAILURE;
+ }
+
goto out;
}
}
+ /* ensure directory update is flushed to disk, otherwise we can end up
+ with zero-byte hostkey files if the power goes off */
+ fsync_parent_dir(filename);
+
out:
if (buf) {
buf_burn(buf);