text: #include "includes.h"
  #include "dbutil.h"
  #include "buffer.h"
  #include "ecdsa.h"
  #include "genrsa.h"
  #include "gendss.h"
  #include "signkey.h"
  #include "dbrandom.h"
  
  #define RSA_DEFAULT_SIZE 2048
  #define DSS_DEFAULT_SIZE 1024
  
  /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
  static int buf_writefile(buffer * buf, const char * filename) {
  	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));
  		goto out;
  	}
  
  	/* write the file now */
  	while (buf->pos != buf->len) {
  		int len = write(fd, buf_getptr(buf, buf->len - buf->pos),
  				buf->len - buf->pos);
  		if (len == -1 && errno == EINTR) {
  			continue;
  		}
  		if (len <= 0) {
  			dropbear_log(LOG_ERR, "Failed writing file %s: %s",
  				filename, strerror(errno));
  			goto out;
  		}
  		buf_incrpos(buf, len);
  	}
  
  	ret = DROPBEAR_SUCCESS;
  
  out:
  	if (fd >= 0) {
  		if (fsync(fd) != 0) {
  			dropbear_log(LOG_ERR, "fsync of %s failed: %s", filename, strerror(errno));
  		}
  		m_close(fd);
  	}
  	return ret;
  }
  
  /* returns 0 on failure */
  static int get_default_bits(enum signkey_type keytype)
  {
  	switch (keytype) {
  #ifdef DROPBEAR_RSA
  		case DROPBEAR_SIGNKEY_RSA:
  			return RSA_DEFAULT_SIZE;
  #endif
  #ifdef DROPBEAR_DSS
  		case DROPBEAR_SIGNKEY_DSS:
  			return DSS_DEFAULT_SIZE;
  #endif
  #ifdef DROPBEAR_ECDSA
  		case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
  			return ECDSA_DEFAULT_SIZE;
  		case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
  			return 521;
  		case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
  			return 384;
  		case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
  			return 256;
  #endif
  		default:
  			return 0;
  	}
  }
  
  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;
  }
  