Skip to content

Commit

Permalink
added generating OpenSSH private keys, as dropbearkey -Z openssh, wit…
Browse files Browse the repository at this point in the history
…h make WRITEOPENSSHKEYS=1
  • Loading branch information
Peter Szabo committed Oct 1, 2017
1 parent ae9da53 commit 4bb002c
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 29 deletions.
4 changes: 4 additions & 0 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ ifeq ($(OPENSSHHOSTKEYLOAD),1)
CFLAGS+=-DOPENSSHHOSTKEYLOAD
endif

ifeq ($(WRITEOPENSSHKEYS),1)
CFLAGS+=-DWRITEOPENSSHKEYS
endif

dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@

Expand Down
42 changes: 36 additions & 6 deletions README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ The most important improvements in pts-dropbear:
implementation is based on TweetNaCl v20140427.
* Added environment variable propagation (similar to OpenSSH AcceptEnv,
command-line flag -A) to Dropbear sshd.
* Added option of autodetection and loading of OpenSSH hostkeys to Dropbear
* Added autodetection and loading of OpenSSH hostkeys to Dropbear
sshd (with `make OPENSSHHOSTKEYLOAD=1').
* Added flag to dropbearkey to generate private keys in OpenSSH format
directly (dropbearkey -Z openssh, with `make WRITEOPENSSHKEYS=1').
* Improved some command-line flags (e.g. dropbear -E is always available).
* Compilation instructions for pts-xstatic (statically linked i386 Linux
binary). Binary size is 350456 bytes.
Expand All @@ -32,7 +34,10 @@ How to generate an ssh-ed25519 server host key:

* Use this command:

$ dropbearkey -t ed25519 -f dropbear_hostkey_ed25519
$ dropbearkey -Z openssh -t ed25519 -f dropbear_hostkey_ed25519

Please note that `-Z openssh' is optional. It creates the private key file
in the OpenSSH format, for improved interoperability.

* Alternatively, this command works if you have OpenSSH:

Expand All @@ -48,21 +53,46 @@ How to generate an ssh-ed25519 server host key:
TODO:

* Send patches to upstream Dropbear.
* Add cipher [email protected] (for feature parity with
tinyssh).
* Add querying an ssh-agent to dbclient. (No need to write an ssh-agent,
the Gnome, gpg and OpenSSH ssh-agent implementations are fine.)
* Add flag to dropbearkey to generate OpenSSH private key format (with
`make WRITEOPENSSHKEYS=1'), `-Z openssh'.
* refactor: split keywrite.c (import_write(...)) out keyimport.c, to make
the dropbear (not dropbearmulti) binary smaller.
* --disable-wtmp in c.sh? Add at least a command-line flag. Is the stock
Ubuntu 14.04 /var/log/wtmp compatible with xstatic uClibc wtmp format?

FYI:

* dropbearconvert (and import_read) ignores comments.
* dropbearconvert (and import_read) ignores comments in keys.
* dropbearkey creates private keys without comments (only public keys have comments).
* OpenSSH `ssh -i' ignores comments in the private key file.
* OpenSSH `ssh -i' ignores comments in the private key file. Good.
* dropbear doesn't support user or host key passphrases.
* dbclient cannot authenticate with an ssh-agent.
* dropbear doesn't try to be smart and slow, e.g. by doing DNS lookups on
the client IP address.
* Dropbear binary size is smaller (353 kB for dropbearmulti linked with
xstatic, containing dropbear, dbclient, dropbearkey, dropbearconvert, scp)
than OpenSSH (836 kB for sshd, 791 kB, 380 kB for ssh-agent for ssh linked
with xstatic, 7.3p1 without OpenSSL).
* OpenSSH crypto operations are faster than in Dropbear. (Is this true?
Benchmark!)
* Dropbear 2017.75 supports these ciphers (with the default compiation flags):
aes128-ctr, aes256-ctr, aes128-cbc, aes256-cbc, twofish256-cbc,
twofish128-cbc, 3des-ctr, 3des-cbc, 3des.
blowfish can also be enabled, but twofish is more efficient.
* OpenSSH_5.3p1 supports these ciphers: (twofish is missing.)
aes128-ctr, aes192-ctr, aes256-ctr, arcfour256, arcfour128, aes128-cbc,
3des-cbc, blowfish-cbc, cast128-cbc, aes192-cbc, aes256-cbc, arcfour,
[email protected].
* OpenSSH_7.2p2 in Ubuntu 14.04 supports these ciphers: (twofish is missing.)
3des-cbc, aes128-cbc, aes128-ctr, [email protected], aes192-cbc
aes192-ctr, aes256-cbc, aes256-ctr, [email protected], arcfour,
arcfour128 arcfour256, [email protected],
[email protected].
* OpenSSH_7.3p1 compiled without OpenSSL supports these ciphers:
aes128-ctr, aes192-ctr, aes256-ctr, [email protected].
* tinyssh 20161101 (and the latest github on 2017-10-01)
supports these ciphers: aes256-str, [email protected].

__END__
2 changes: 1 addition & 1 deletion c.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

set -ex
./configure CC='xstatic gcc' --disable-syslog --disable-shadow --enable-bundled-libtom --disable-lastlog --disable-utmp --disable-utmpx --disable-wtmpx
make PROGRAMS='dropbear dbclient dropbearkey dropbearconvert scp' MULTI=1 STATIC=1 SCPPROGRESS=1 NOSYSHOSTKEYLOAD=1 OPENSSHHOSTKEYLOAD=1
make PROGRAMS='dropbear dbclient dropbearkey dropbearconvert scp' MULTI=1 STATIC=1 SCPPROGRESS=1 NOSYSHOSTKEYLOAD=1 OPENSSHHOSTKEYLOAD=1 WRITEOPENSSHKEYS=1
strip dropbearmulti
ls -l dropbearmulti

Expand Down
46 changes: 37 additions & 9 deletions dropbearkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
#include "crypto_desc.h"
#include "dbrandom.h"
#include "gensignkey.h"
#include "keyimport.h"

static void printhelp(char * progname);

Expand Down Expand Up @@ -127,6 +128,9 @@ static void printhelp(char * progname) {
"-N passhprase Must be empty. For ssh-keygen compatibility.\n"
"-P passhprase Must be empty. For ssh-keygen compatibility.\n"
"-C comment Comment to use in the .pub file.\n"
#ifdef WRITEOPENSSHKEYS
"-Z format Output key format: dropbear (default) or openssh.\n"
#endif
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
#ifdef DEBUG_TRACE
"-v verbose\n"
Expand All @@ -151,6 +155,10 @@ int main(int argc, char ** argv) {
char * comment = NULL;
unsigned int bits = 0;
int printpub = 0;
char * format_str = NULL;
#ifdef WRITEOPENSSHKEYS
int format = KEYFILE_DROPBEAR;
#endif

crypto_init();
seedrandom();
Expand Down Expand Up @@ -185,6 +193,11 @@ int main(int argc, char ** argv) {
case 'C':
next = &comment;
break;
#ifdef WRITEOPENSSHKEYS
case 'Z':
next = &format_str;
break;
#endif
case 'y':
printpub = 1;
break;
Expand Down Expand Up @@ -232,6 +245,12 @@ int main(int argc, char ** argv) {
comment = strdupcat3(username, "@", hostname);
}

#ifdef WRITEOPENSSHKEYS
if (format_str && format_str[0] == 'o') {
format = KEYFILE_OPENSSH;
}
#endif

if (printpub) {
int ret = printpubfile(filename, comment, NULL);
exit(ret);
Expand Down Expand Up @@ -283,7 +302,7 @@ int main(int argc, char ** argv) {
}

fprintf(stderr, "Generating key, this may take a while...\n");
if (signkey_generate(keytype, bits, filename, 0) == DROPBEAR_FAILURE)
if (signkey_generate(keytype, bits, filename, 0, format) == DROPBEAR_FAILURE)
{
dropbear_exit("Failed to generate key.\n");
}
Expand Down Expand Up @@ -311,14 +330,23 @@ static int printpubfile(const char *filename, const char *comment, const char *p
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;
#ifdef WRITEOPENSSHKEYS
if (buf->len >= 4 && 0 == memcmp(buf->data, "----", 4)) {
buf_burn(buf);
buf_free(buf);
if (!(key = key_openssh_read(filename, NULL))) goto out;
keytype = key->type;
} else
#endif
{
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, comment, pub_filename_to_write);
Expand Down
18 changes: 12 additions & 6 deletions gensignkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "gened25519.h"
#include "signkey.h"
#include "dbrandom.h"
#include "keyimport.h"

#define RSA_DEFAULT_SIZE 2048
#define DSS_DEFAULT_SIZE 1024
Expand Down Expand Up @@ -82,7 +83,7 @@ static int get_default_bits(enum signkey_type keytype)
}

/* 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)
int signkey_generate(enum signkey_type keytype, int bits, const char* filename, int skip_exist, int format)
{
sign_key * key = NULL;
buffer *buf = NULL;
Expand Down Expand Up @@ -132,17 +133,22 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,

seedrandom();

buf = buf_new(MAX_PRIVKEY_SIZE);

buf_put_priv_key(buf, key, keytype);
#ifdef WRITEOPENSSHKEYS
if (format == KEYFILE_OPENSSH) {
key->type = keytype;
if (!key_openssh_write(NULL, key, NULL, &buf)) goto out;
} else
#endif
{
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;
}
Expand Down
3 changes: 2 additions & 1 deletion gensignkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "signkey.h"

int signkey_generate(enum signkey_type type, int bits, const char* filename, int skip_exist);
/* format is KEYFILE_DROPBEAR or KEYFILE_OPENSSH */
int signkey_generate(enum signkey_type type, int bits, const char* filename, int skip_exist, int format);

#endif
50 changes: 44 additions & 6 deletions keyimport.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ static const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23};

static int openssh_encrypted(const char *filename);
sign_key *key_openssh_read(const char *filename, char *passphrase);
static int openssh_write(const char *filename, sign_key *key,
char *passphrase);
int key_openssh_write(const char *filename, sign_key *key, char *passphrase, buffer **outbuf);

static int dropbear_write(const char*filename, sign_key * key);
static sign_key *dropbear_read(const char* filename);
Expand Down Expand Up @@ -103,7 +102,7 @@ int import_write(const char *filename, sign_key *key, char *passphrase,
int filetype) {

if (filetype == KEYFILE_OPENSSH) {
return openssh_write(filename, key, passphrase);
return key_openssh_write(filename, key, passphrase, NULL);
} else if (filetype == KEYFILE_DROPBEAR) {
return dropbear_write(filename, key);
#if 0
Expand Down Expand Up @@ -232,6 +231,28 @@ static void base64_encode_fp(FILE * fp, unsigned char *data,
fputc('\n', fp);
}
}

#ifdef WRITEOPENSSHKEYS
/* cpl has to be less than 100 */
static void base64_encode_to_buf(buffer *buf, unsigned char *data, int datalen, int cpl) {
unsigned char out[100];
int n;
unsigned long outlen;
int rawcpl;
rawcpl = cpl * 3 / 4;
dropbear_assert((unsigned int)cpl < sizeof(out));
while (datalen > 0) {
n = (datalen < rawcpl ? datalen : rawcpl);
outlen = sizeof(out);
base64_encode(data, n, out, &outlen);
data += n;
datalen -= n;
buf_putbytes(buf, out, outlen);
buf_putbytes(buf, "\n", 1);
}
}
#endif

/*
* Read an ASN.1/BER identifier and length pair.
*
Expand Down Expand Up @@ -893,9 +914,7 @@ sign_key *key_openssh_read(const char *filename, char * UNUSED(passphrase))
return retval;
}

static int openssh_write(const char *filename, sign_key *key,
char *passphrase)
{
int key_openssh_write(const char *filename, sign_key *key, char *passphrase, buffer **outbuf) {
buffer * keyblob = NULL;
buffer * extrablob = NULL; /* used for calculated values to write */
unsigned char *outblob = NULL;
Expand All @@ -911,6 +930,7 @@ static int openssh_write(const char *filename, sign_key *key,
mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */
#endif


#ifdef DROPBEAR_ED25519
if (key->type == DROPBEAR_SIGNKEY_ED25519) {
const char *spk = key->ed25519key->spk;
Expand Down Expand Up @@ -1242,6 +1262,24 @@ static int openssh_write(const char *filename, sign_key *key,
write_file:
#endif

#ifdef WRITEOPENSSHKEYS
if (outbuf) {
const unsigned header_size = strlen(header);
const unsigned footer_size = strlen(footer);
const unsigned outlen3 = outlen / 3;
buffer *xbuf;
/* (outlen3 >> 4) for the '\n' inserted by base64 encoding, it corresponds to the constant 64 below. */
*outbuf = xbuf = buf_new(header_size + footer_size + outlen + outlen3 + (outlen3 >> 4) + 10);
buf_putbytes(xbuf, header, header_size);
base64_encode_to_buf(xbuf, outblob, outlen, 64);
buf_putbytes(xbuf, footer, footer_size);
ret = 1;
goto error;
}
#else
(void)outbuf;
#endif

/*
* And save it. We'll use Unix line endings just in case it's
* subsequently transferred in binary mode.
Expand Down
2 changes: 2 additions & 0 deletions keyimport.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ enum {
};

sign_key *key_openssh_read(const char* filename, char *passphrase);
/* If outbuf is not NULL, then writes outbuf, else writes to file named filename. */
int key_openssh_write(const char *filename, sign_key *key, char *passphrase, buffer **outbuf);

int import_write(const char *filename, sign_key *key, char *passphrase,
int filetype);
Expand Down

0 comments on commit 4bb002c

Please sign in to comment.