[OE-core] [PATCH][krogoth] dropbear: Fix multiple CVEs

akuster808 akuster808 at gmail.com
Tue Oct 25 21:11:51 UTC 2016



On 10/20/2016 11:25 AM, Sona Sarmadi wrote:
> CVE-2016-7406
> CVE-2016-7407
> CVE-2016-7408
> CVE-2016-7409

merged to staging.

- armin
>
> Reference:
> https://matt.ucc.asn.au/dropbear/CHANGES
>
> [YOCTO #10443]
>
> Signed-off-by: Sona Sarmadi <sona.sarmadi at enea.com>
> ---
>   meta/recipes-core/dropbear/dropbear.inc            |    4 +
>   .../dropbear/dropbear/CVE-2016-7406.patch          |  104 +
>   .../dropbear/dropbear/CVE-2016-7407.patch          | 2485 ++++++++++++++++++++
>   .../dropbear/dropbear/CVE-2016-7408.patch          |  101 +
>   .../dropbear/dropbear/CVE-2016-7409.patch          |   26 +
>   5 files changed, 2720 insertions(+)
>   create mode 100644 meta/recipes-core/dropbear/dropbear/CVE-2016-7406.patch
>   create mode 100644 meta/recipes-core/dropbear/dropbear/CVE-2016-7407.patch
>   create mode 100644 meta/recipes-core/dropbear/dropbear/CVE-2016-7408.patch
>   create mode 100644 meta/recipes-core/dropbear/dropbear/CVE-2016-7409.patch
>
> diff --git a/meta/recipes-core/dropbear/dropbear.inc b/meta/recipes-core/dropbear/dropbear.inc
> index 923d31c..ee2cd98 100644
> --- a/meta/recipes-core/dropbear/dropbear.inc
> +++ b/meta/recipes-core/dropbear/dropbear.inc
> @@ -17,6 +17,10 @@ SRC_URI = "http://matt.ucc.asn.au/dropbear/releases/dropbear-${PV}.tar.bz2 \
>              file://0003-configure.patch \
>              file://0004-fix-2kb-keys.patch \
>              file://0007-dropbear-fix-for-x32-abi.patch \
> +           file://CVE-2016-7406.patch \
> +           file://CVE-2016-7407.patch \
> +           file://CVE-2016-7408.patch \
> +           file://CVE-2016-7409.patch \
>              file://init \
>              file://dropbearkey.service \
>              file://dropbear@.service \
> diff --git a/meta/recipes-core/dropbear/dropbear/CVE-2016-7406.patch b/meta/recipes-core/dropbear/dropbear/CVE-2016-7406.patch
> new file mode 100644
> index 0000000..22b494c
> --- /dev/null
> +++ b/meta/recipes-core/dropbear/dropbear/CVE-2016-7406.patch
> @@ -0,0 +1,104 @@
> +# HG changeset patch
> +# User Matt Johnston <matt at ucc.asn.au>
> +# Date 1468249773 -28800
> +# Node ID b66a483f3dcb66a70341845dd36e922ddaee4c5a
> +# Parent  eed9376a4ad68e3ae7f17d154dbf126ee66c54bc
> +Improve exit message formatting
> +
> +Patch is backported from:
> +https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb
> +
> +CVE: CVE-2016-7406
> +Signed-off-by: Sona Sarmadi <sona.sarmadi at enea.com>
> +
> +diff -ruN a/cli-main.c b/cli-main.c
> +--- a/cli-main.c	2016-03-09 15:54:53.000000000 +0100
> ++++ b/cli-main.c	2016-10-20 12:49:00.323501119 +0200
> +@@ -85,29 +85,30 @@
> + #endif /* DBMULTI stuff */
> +
> + static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
> ++	char exitmsg[150];
> ++	char fullmsg[300];
> +
> +-	char fmtbuf[300];
> +-	char exitmsg[500];
> ++	/* Note that exit message must be rendered before session cleanup */
> +
> ++	/* Render the formatted exit message */
> ++	vsnprintf(exitmsg, sizeof(exitmsg), format, param);
> ++
> ++	/* Add the prefix depending on session/auth state */
> + 	if (!sessinitdone) {
> +-		snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s",
> +-				format);
> ++		snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg);
> + 	} else {
> +-		snprintf(fmtbuf, sizeof(fmtbuf),
> ++		snprintf(fullmsg, sizeof(fullmsg),
> + 				"Connection to %s@%s:%s exited: %s",
> + 				cli_opts.username, cli_opts.remotehost,
> +-				cli_opts.remoteport, format);
> ++				cli_opts.remoteport, exitmsg);
> + 	}
> +
> +-	/* Arguments to the exit printout may be unsafe to use after session_cleanup() */
> +-	vsnprintf(exitmsg, sizeof(exitmsg), fmtbuf, param);
> +-
> + 	/* Do the cleanup first, since then the terminal will be reset */
> + 	session_cleanup();
> + 	/* Avoid printing onwards from terminal cruft */
> + 	fprintf(stderr, "\n");
> +
> +-	dropbear_log(LOG_INFO, "%s", exitmsg);;
> ++	dropbear_log(LOG_INFO, "%s", fullmsg);
> + 	exit(exitcode);
> + }
> +
> +diff -ruN a/svr-session.c b/svr-session.c
> +--- a/svr-session.c	2016-03-09 15:54:54.000000000 +0100
> ++++ b/svr-session.c	2016-10-20 13:27:20.629628336 +0200
> +@@ -145,30 +145,33 @@
> + /* failure exit - format must be <= 100 chars */
> + void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
> +
> +-	char fmtbuf[300];
> ++	char exitmsg[150];
> ++	char fullmsg[300];
> + 	int i;
> +
> ++	/* Render the formatted exit message */
> ++	vsnprintf(exitmsg, sizeof(exitmsg), format, param);
> ++
> ++	/* Add the prefix depending on session/auth state */
> + 	if (!sessinitdone) {
> + 		/* before session init */
> +-		snprintf(fmtbuf, sizeof(fmtbuf),
> +-				"Early exit: %s", format);
> ++                snprintf(fullmsg, sizeof(fullmsg), "Early exit: %s", exitmsg);
> + 	} else if (ses.authstate.authdone) {
> + 		/* user has authenticated */
> +-		snprintf(fmtbuf, sizeof(fmtbuf),
> ++		snprintf(fullmsg, sizeof(fullmsg),
> + 				"Exit (%s): %s",
> +-				ses.authstate.pw_name, format);
> ++				ses.authstate.pw_name, exitmsg);
> + 	} else if (ses.authstate.pw_name) {
> + 		/* we have a potential user */
> +-		snprintf(fmtbuf, sizeof(fmtbuf),
> ++		snprintf(fullmsg, sizeof(fullmsg),
> + 				"Exit before auth (user '%s', %d fails): %s",
> +-				ses.authstate.pw_name, ses.authstate.failcount, format);
> ++				ses.authstate.pw_name, ses.authstate.failcount, exitmsg);
> + 	} else {
> + 		/* before userauth */
> +-		snprintf(fmtbuf, sizeof(fmtbuf),
> +-				"Exit before auth: %s", format);
> ++		snprintf(fullmsg, sizeof(fullmsg), "Exit before auth: %s", exitmsg);
> + 	}
> +
> +-	_dropbear_log(LOG_INFO, fmtbuf, param);
> ++	dropbear_log(LOG_INFO, "%s", fullmsg);
> +
> + #ifdef USE_VFORK
> + 	/* For uclinux only the main server process should cleanup - we don't want
> diff --git a/meta/recipes-core/dropbear/dropbear/CVE-2016-7407.patch b/meta/recipes-core/dropbear/dropbear/CVE-2016-7407.patch
> new file mode 100644
> index 0000000..6cfc3f5
> --- /dev/null
> +++ b/meta/recipes-core/dropbear/dropbear/CVE-2016-7407.patch
> @@ -0,0 +1,2485 @@
> +
> +# HG changeset patch
> +# User Matt Johnston <matt at ucc.asn.au>
> +# Date 1468335601 -28800
> +# Node ID 34e6127ef02eb52d1f1f9494b9cbfe89bec0e925
> +# Parent  6914eedb10721db4833c8f005b4acd37f71fb975
> +merge fixes from PuTTY import.c
> +
> +toint() from misc.c
> +
> +(revids are from hggit conversion)
> +
> +changeset:   4620:60a336a6c85c
> +user:        Simon Tatham <anakin at pobox.com>
> +date:        Thu Feb 25 20:26:33 2016 +0000
> +files:       import.c
> +description:
> +Fix potential segfaults in reading OpenSSH's ASN.1 key format.
> +
> +The length coming back from ber_read_id_len might have overflowed, so
> +treat it as potentially negative. Also, while I'm here, accumulate it
> +inside ber_read_id_len as an unsigned, so as to avoid undefined
> +behaviour on integer overflow, and toint() it before return.
> +
> +Thanks to Hanno Böck for spotting this, with the aid of AFL.
> +
> +(cherry picked from commit 5b7833cd474a24ec098654dcba8cb9509f3bf2c1)
> +
> +Conflicts:
> +	import.c
> +
> +(cherry-picker's note: resolving the conflict involved removing an
> +entire section of the original commit which fixed ECDSA code not
> +present on this branch)
> +
> +
> +changeset:   4619:9c6c638d98d8
> +user:        Simon Tatham <anakin at pobox.com>
> +date:        Sun Jul 14 10:45:54 2013 +0000
> +files:       import.c ssh.c sshdss.c sshpubk.c sshrsa.c
> +description:
> +Tighten up a lot of casts from unsigned to int which are read by one
> +of the GET_32BIT macros and then used as length fields. Missing bounds
> +checks against zero have been added, and also I've introduced a helper
> +function toint() which casts from unsigned to int in such a way as to
> +avoid C undefined behaviour, since I'm not sure I trust compilers any
> +more to do the obviously sensible thing.
> +
> +[originally from svn r9918]
> +
> +
> +changeset:   4618:3957829f24d3
> +user:        Simon Tatham <anakin at pobox.com>
> +date:        Mon Jul 08 22:36:04 2013 +0000
> +files:       import.c sshdss.c sshrsa.c
> +description:
> +Add an assortment of extra safety checks.
> +
> +[originally from svn r9896]
> +
> +
> +changeset:   4617:2cddee0bce12
> +user:        Jacob Nevins <jacobn at chiark.greenend.org.uk>
> +date:        Wed Dec 07 00:24:45 2005 +0000
> +files:       import.c
> +description:
> +Institutional failure to memset() things pointed at rather than pointers.
> +Things should now be zeroed and memory not leaked. Spotted by Brant Thomsen.
> +
> +[originally from svn r6476]
> +
> +
> +changeset:   4616:24ac78a9c71d
> +user:        Simon Tatham <anakin at pobox.com>
> +date:        Wed Feb 11 13:58:27 2004 +0000
> +files:       import.c
> +description:
> +Jacob's last-minute testing found a couple of trivial bugs in
> +import.c, and my attempts to reproduce them in cmdgen found another
> +one there :-)
> +
> +[originally from svn r3847]
> +
> +
> +changeset:   4615:088d39a73db0
> +user:        Simon Tatham <anakin at pobox.com>
> +date:        Thu Jan 22 18:52:49 2004 +0000
> +files:       import.c
> +description:
> +Placate some gcc warnings.
> +
> +[originally from svn r3761]
> +
> +
> +changeset:   4614:e4288bad4d93
> +parent:      1758:108b8924593d
> +user:        Simon Tatham <anakin at pobox.com>
> +date:        Fri Oct 03 21:21:23 2003 +0000
> +files:       import.c
> +description:
> +My ASN.1 decoder returned wrong IDs for anything above 0x1E! Good
> +job it's never had to yet. Ahem.
> +
> +[originally from svn r3479]
> +
> +Patch is backported from:
> +https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e
> +
> +CVE: CVE-2016-7407
> +Signed-off-by: Sona Sarmadi <sona.sarmadi at enea.com>
> +
> +diff -r 6914eedb1072 -r 34e6127ef02e keyimport.c
> +--- a/keyimport.c	Mon Jul 11 23:34:18 2016 +0800
> ++++ b/keyimport.c	Tue Jul 12 23:00:01 2016 +0800
> +@@ -47,65 +47,67 @@
> +   (cp)[0] = (unsigned char)((value) >> 24); } while (0)
> +
> + #define GET_32BIT(cp) \
> +-	(((unsigned long)(unsigned char)(cp)[0] << 24) | \
> +-	((unsigned long)(unsigned char)(cp)[1] << 16) | \
> +-	((unsigned long)(unsigned char)(cp)[2] << 8) | \
> +-	((unsigned long)(unsigned char)(cp)[3]))
> ++    (((unsigned long)(unsigned char)(cp)[0] << 24) | \
> ++    ((unsigned long)(unsigned char)(cp)[1] << 16) | \
> ++    ((unsigned long)(unsigned char)(cp)[2] << 8) | \
> ++    ((unsigned long)(unsigned char)(cp)[3]))
> +
> + static int openssh_encrypted(const char *filename);
> + static sign_key *openssh_read(const char *filename, char *passphrase);
> + static int openssh_write(const char *filename, sign_key *key,
> +-				  char *passphrase);
> ++		  char *passphrase);
> +
> + static int dropbear_write(const char*filename, sign_key * key);
> + static sign_key *dropbear_read(const char* filename);
> +
> ++static int toint(unsigned u);
> ++
> + #if 0
> + static int sshcom_encrypted(const char *filename, char **comment);
> + static struct ssh2_userkey *sshcom_read(const char *filename, char *passphrase);
> + static int sshcom_write(const char *filename, struct ssh2_userkey *key,
> +-				 char *passphrase);
> ++		 char *passphrase);
> + #endif
> +
> + int import_encrypted(const char* filename, int filetype) {
> +
> + 	if (filetype == KEYFILE_OPENSSH) {
> +-		return openssh_encrypted(filename);
> ++	return openssh_encrypted(filename);
> + #if 0
> + 	} else if (filetype == KEYFILE_SSHCOM) {
> + 		return sshcom_encrypted(filename, NULL);
> + #endif
> +-	}
> +-	return 0;
> ++    }
> ++    return 0;
> + }
> +
> + sign_key *import_read(const char *filename, char *passphrase, int filetype) {
> +
> + 	if (filetype == KEYFILE_OPENSSH) {
> +-		return openssh_read(filename, passphrase);
> ++	return openssh_read(filename, passphrase);
> + 	} else if (filetype == KEYFILE_DROPBEAR) {
> + 		return dropbear_read(filename);
> + #if 0
> + 	} else if (filetype == KEYFILE_SSHCOM) {
> +-		return sshcom_read(filename, passphrase);
> ++	return sshcom_read(filename, passphrase);
> + #endif
> + 	}
> +-	return NULL;
> ++    return NULL;
> + }
> +
> + int import_write(const char *filename, sign_key *key, char *passphrase,
> + 		int filetype) {
> +
> + 	if (filetype == KEYFILE_OPENSSH) {
> +-		return openssh_write(filename, key, passphrase);
> ++	return openssh_write(filename, key, passphrase);
> + 	} else if (filetype == KEYFILE_DROPBEAR) {
> + 		return dropbear_write(filename, key);
> + #if 0
> + 	} else if (filetype == KEYFILE_SSHCOM) {
> +-		return sshcom_write(filename, key, passphrase);
> ++	return sshcom_write(filename, key, passphrase);
> + #endif
> + 	}
> +-	return 0;
> ++    return 0;
> + }
> +
> + static sign_key *dropbear_read(const char* filename) {
> +@@ -183,11 +185,11 @@
> +  * Helper routines. (The base64 ones are defined in sshpubk.c.)
> +  */
> +
> +-#define isbase64(c) (	((c) >= 'A' && (c) <= 'Z') || \
> +-						 ((c) >= 'a' && (c) <= 'z') || \
> +-						 ((c) >= '0' && (c) <= '9') || \
> +-						 (c) == '+' || (c) == '/' || (c) == '=' \
> +-						 )
> ++#define isbase64(c) (    ((c) >= 'A' && (c) <= 'Z') || \
> ++                         ((c) >= 'a' && (c) <= 'z') || \
> ++                         ((c) >= '0' && (c) <= '9') || \
> ++                         (c) == '+' || (c) == '/' || (c) == '=' \
> ++                         )
> +
> + /* cpl has to be less than 100 */
> + static void base64_encode_fp(FILE * fp, unsigned char *data,
> +@@ -220,57 +222,58 @@
> +  */
> +
> + /* ASN.1 tag classes. */
> +-#define ASN1_CLASS_UNIVERSAL		(0 << 6)
> +-#define ASN1_CLASS_APPLICATION	  (1 << 6)
> ++#define ASN1_CLASS_UNIVERSAL        (0 << 6)
> ++#define ASN1_CLASS_APPLICATION      (1 << 6)
> + #define ASN1_CLASS_CONTEXT_SPECIFIC (2 << 6)
> +-#define ASN1_CLASS_PRIVATE		  (3 << 6)
> +-#define ASN1_CLASS_MASK			 (3 << 6)
> ++#define ASN1_CLASS_PRIVATE          (3 << 6)
> ++#define ASN1_CLASS_MASK             (3 << 6)
> +
> + /* Primitive versus constructed bit. */
> +-#define ASN1_CONSTRUCTED			(1 << 5)
> ++#define ASN1_CONSTRUCTED            (1 << 5)
> +
> + static int ber_read_id_len(void *source, int sourcelen,
> +-						   int *id, int *length, int *flags)
> ++			   int *id, int *length, int *flags)
> + {
> +-	unsigned char *p = (unsigned char *) source;
> ++    unsigned char *p = (unsigned char *) source;
> +
> +-	if (sourcelen == 0)
> ++    if (sourcelen == 0)
> ++	return -1;
> ++
> ++    *flags = (*p & 0xE0);
> ++    if ((*p & 0x1F) == 0x1F) {
> ++	*id = 0;
> ++	while (*p & 0x80) {
> ++	    p++, sourcelen--;
> ++	    if (sourcelen == 0)
> + 		return -1;
> ++	    *id = (*id << 7) | (*p & 0x7F);
> ++	}
> ++	p++, sourcelen--;
> ++    } else {
> ++	*id = *p & 0x1F;
> ++	p++, sourcelen--;
> ++    }
> +
> +-	*flags = (*p & 0xE0);
> +-	if ((*p & 0x1F) == 0x1F) {
> +-		*id = 0;
> +-		while (*p & 0x80) {
> +-			*id = (*id << 7) | (*p & 0x7F);
> +-			p++, sourcelen--;
> +-			if (sourcelen == 0)
> +-				return -1;
> +-		}
> +-		*id = (*id << 7) | (*p & 0x7F);
> +-		p++, sourcelen--;
> +-	} else {
> +-		*id = *p & 0x1F;
> +-		p++, sourcelen--;
> +-	}
> ++    if (sourcelen == 0)
> ++	return -1;
> +
> +-	if (sourcelen == 0)
> +-		return -1;
> ++    if (*p & 0x80) {
> ++        unsigned len;
> ++	int n = *p & 0x7F;
> ++	p++, sourcelen--;
> ++	if (sourcelen < n)
> ++	    return -1;
> ++	len = 0;
> ++	while (n--)
> ++	    len = (len << 8) | (*p++);
> ++	sourcelen -= n;
> ++        *length = toint(len);
> ++    } else {
> ++	*length = *p;
> ++	p++, sourcelen--;
> ++    }
> +
> +-	if (*p & 0x80) {
> +-		int n = *p & 0x7F;
> +-		p++, sourcelen--;
> +-		if (sourcelen < n)
> +-			return -1;
> +-		*length = 0;
> +-		while (n--)
> +-			*length = (*length << 8) | (*p++);
> +-		sourcelen -= n;
> +-	} else {
> +-		*length = *p;
> +-		p++, sourcelen--;
> +-	}
> +-
> +-	return p - (unsigned char *) source;
> ++    return p - (unsigned char *) source;
> + }
> +
> + /*
> +@@ -281,57 +284,57 @@
> +  */
> + static int ber_write_id_len(void *dest, int id, int length, int flags)
> + {
> +-	unsigned char *d = (unsigned char *)dest;
> +-	int len = 0;
> ++    unsigned char *d = (unsigned char *)dest;
> ++    int len = 0;
> +
> +-	if (id <= 30) {
> +-		/*
> +-		 * Identifier is one byte.
> +-		 */
> +-		len++;
> +-		if (d) *d++ = id | flags;
> +-	} else {
> +-		int n;
> +-		/*
> +-		 * Identifier is multiple bytes: the first byte is 11111
> +-		 * plus the flags, and subsequent bytes encode the value of
> +-		 * the identifier, 7 bits at a time, with the top bit of
> +-		 * each byte 1 except the last one which is 0.
> +-		 */
> +-		len++;
> +-		if (d) *d++ = 0x1F | flags;
> +-		for (n = 1; (id >> (7*n)) > 0; n++)
> +-			continue;					   /* count the bytes */
> +-		while (n--) {
> +-			len++;
> +-			if (d) *d++ = (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F);
> +-		}
> ++    if (id <= 30) {
> ++	/*
> ++	 * Identifier is one byte.
> ++	 */
> ++	len++;
> ++	if (d) *d++ = id | flags;
> ++    } else {
> ++	int n;
> ++	/*
> ++	 * Identifier is multiple bytes: the first byte is 11111
> ++	 * plus the flags, and subsequent bytes encode the value of
> ++	 * the identifier, 7 bits at a time, with the top bit of
> ++	 * each byte 1 except the last one which is 0.
> ++	 */
> ++	len++;
> ++	if (d) *d++ = 0x1F | flags;
> ++	for (n = 1; (id >> (7*n)) > 0; n++)
> ++	    continue;		       /* count the bytes */
> ++	while (n--) {
> ++	    len++;
> ++	    if (d) *d++ = (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F);
> + 	}
> ++    }
> +
> +-	if (length < 128) {
> +-		/*
> +-		 * Length is one byte.
> +-		 */
> +-		len++;
> +-		if (d) *d++ = length;
> +-	} else {
> +-		int n;
> +-		/*
> +-		 * Length is multiple bytes. The first is 0x80 plus the
> +-		 * number of subsequent bytes, and the subsequent bytes
> +-		 * encode the actual length.
> +-		 */
> +-		for (n = 1; (length >> (8*n)) > 0; n++)
> +-			continue;					   /* count the bytes */
> +-		len++;
> +-		if (d) *d++ = 0x80 | n;
> +-		while (n--) {
> +-			len++;
> +-			if (d) *d++ = (length >> (8*n)) & 0xFF;
> +-		}
> ++    if (length < 128) {
> ++	/*
> ++	 * Length is one byte.
> ++	 */
> ++	len++;
> ++	if (d) *d++ = length;
> ++    } else {
> ++	int n;
> ++	/*
> ++	 * Length is multiple bytes. The first is 0x80 plus the
> ++	 * number of subsequent bytes, and the subsequent bytes
> ++	 * encode the actual length.
> ++	 */
> ++	for (n = 1; (length >> (8*n)) > 0; n++)
> ++	    continue;		       /* count the bytes */
> ++	len++;
> ++	if (d) *d++ = 0x80 | n;
> ++	while (n--) {
> ++	    len++;
> ++	    if (d) *d++ = (length >> (8*n)) & 0xFF;
> + 	}
> ++    }
> +
> +-	return len;
> ++    return len;
> + }
> +
> +
> +@@ -344,99 +347,99 @@
> +
> + enum { OSSH_DSA, OSSH_RSA, OSSH_EC };
> + struct openssh_key {
> +-	int type;
> +-	int encrypted;
> +-	char iv[32];
> +-	unsigned char *keyblob;
> ++    int type;
> ++    int encrypted;
> ++    char iv[32];
> ++    unsigned char *keyblob;
> + 	unsigned int keyblob_len, keyblob_size;
> + };
> +
> + static struct openssh_key *load_openssh_key(const char *filename)
> + {
> +-	struct openssh_key *ret;
> ++    struct openssh_key *ret;
> + 	FILE *fp = NULL;
> +-	char buffer[256];
> ++    char buffer[256];
> + 	char *errmsg = NULL, *p = NULL;
> +-	int headers_done;
> ++    int headers_done;
> + 	unsigned long len, outlen;
> +
> + 	ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key));
> +-	ret->keyblob = NULL;
> +-	ret->keyblob_len = ret->keyblob_size = 0;
> +-	ret->encrypted = 0;
> +-	memset(ret->iv, 0, sizeof(ret->iv));
> ++    ret->keyblob = NULL;
> ++    ret->keyblob_len = ret->keyblob_size = 0;
> ++    ret->encrypted = 0;
> ++    memset(ret->iv, 0, sizeof(ret->iv));
> +
> + 	if (strlen(filename) == 1 && filename[0] == '-') {
> + 		fp = stdin;
> + 	} else {
> + 		fp = fopen(filename, "r");
> + 	}
> +-	if (!fp) {
> +-		errmsg = "Unable to open key file";
> +-		goto error;
> +-	}
> +-	if (!fgets(buffer, sizeof(buffer), fp) ||
> +-		0 != strncmp(buffer, "-----BEGIN ", 11) ||
> +-		0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) {
> +-		errmsg = "File does not begin with OpenSSH key header";
> +-		goto error;
> +-	}
> +-	if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n"))
> +-		ret->type = OSSH_RSA;
> +-	else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n"))
> +-		ret->type = OSSH_DSA;
> ++    if (!fp) {
> ++	errmsg = "Unable to open key file";
> ++	goto error;
> ++    }
> ++    if (!fgets(buffer, sizeof(buffer), fp) ||
> ++	0 != strncmp(buffer, "-----BEGIN ", 11) ||
> ++	0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) {
> ++	errmsg = "File does not begin with OpenSSH key header";
> ++	goto error;
> ++    }
> ++    if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n"))
> ++	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";
> ++    else {
> ++	errmsg = "Unrecognised key type";
> ++	goto error;
> ++    }
> ++
> ++    headers_done = 0;
> ++    while (1) {
> ++	if (!fgets(buffer, sizeof(buffer), fp)) {
> ++	    errmsg = "Unexpected end of file";
> ++	    goto error;
> ++	}
> ++	if (0 == strncmp(buffer, "-----END ", 9) &&
> ++	    0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n"))
> ++	    break;		       /* done */
> ++	if ((p = strchr(buffer, ':')) != NULL) {
> ++	    if (headers_done) {
> ++		errmsg = "Header found in body of key data";
> + 		goto error;
> +-	}
> ++	    }
> ++	    *p++ = '\0';
> ++	    while (*p && isspace((unsigned char)*p)) p++;
> ++	    if (!strcmp(buffer, "Proc-Type")) {
> ++		if (p[0] != '4' || p[1] != ',') {
> ++		    errmsg = "Proc-Type is not 4 (only 4 is supported)";
> ++		    goto error;
> ++		}
> ++		p += 2;
> ++		if (!strcmp(p, "ENCRYPTED\n"))
> ++		    ret->encrypted = 1;
> ++	    } else if (!strcmp(buffer, "DEK-Info")) {
> ++		int i, j;
> +
> +-	headers_done = 0;
> +-	while (1) {
> +-		if (!fgets(buffer, sizeof(buffer), fp)) {
> +-			errmsg = "Unexpected end of file";
> +-			goto error;
> ++		if (strncmp(p, "DES-EDE3-CBC,", 13)) {
> ++		    errmsg = "Ciphers other than DES-EDE3-CBC not supported";
> ++		    goto error;
> + 		}
> +-		if (0 == strncmp(buffer, "-----END ", 9) &&
> +-			0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n"))
> +-			break;					   /* done */
> +-		if ((p = strchr(buffer, ':')) != NULL) {
> +-			if (headers_done) {
> +-				errmsg = "Header found in body of key data";
> +-				goto error;
> +-			}
> +-			*p++ = '\0';
> +-			while (*p && isspace((unsigned char)*p)) p++;
> +-			if (!strcmp(buffer, "Proc-Type")) {
> +-				if (p[0] != '4' || p[1] != ',') {
> +-					errmsg = "Proc-Type is not 4 (only 4 is supported)";
> +-					goto error;
> +-				}
> +-				p += 2;
> +-				if (!strcmp(p, "ENCRYPTED\n"))
> +-					ret->encrypted = 1;
> +-			} else if (!strcmp(buffer, "DEK-Info")) {
> +-				int i, j;
> +-
> +-				if (strncmp(p, "DES-EDE3-CBC,", 13)) {
> +-					errmsg = "Ciphers other than DES-EDE3-CBC not supported";
> +-					goto error;
> +-				}
> +-				p += 13;
> +-				for (i = 0; i < 8; i++) {
> +-					if (1 != sscanf(p, "%2x", &j))
> +-						break;
> +-					ret->iv[i] = j;
> +-					p += 2;
> +-				}
> +-				if (i < 8) {
> +-					errmsg = "Expected 16-digit iv in DEK-Info";
> +-					goto error;
> +-				}
> +-			}
> +-		} else {
> +-			headers_done = 1;
> ++		p += 13;
> ++		for (i = 0; i < 8; i++) {
> ++		    if (1 != sscanf(p, "%2x", &j))
> ++			break;
> ++		    ret->iv[i] = j;
> ++		    p += 2;
> ++		}
> ++		if (i < 8) {
> ++		    errmsg = "Expected 16-digit iv in DEK-Info";
> ++		    goto error;
> ++		}
> ++	    }
> ++	} else {
> ++	    headers_done = 1;
> + 			len = strlen(buffer);
> + 			outlen = len*4/3;
> + 			if (ret->keyblob_len + outlen > ret->keyblob_size) {
> +@@ -448,65 +451,65 @@
> + 			if (base64_decode((const unsigned char *)buffer, len,
> + 						ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){
> + 				errmsg = "Error decoding base64";
> +-				goto error;
> +-			}
> ++                        goto error;
> ++                    }
> + 			ret->keyblob_len += outlen;
> +-		}
> ++                }
> + 	}
> +
> +-	if (ret->keyblob_len == 0 || !ret->keyblob) {
> +-		errmsg = "Key body not present";
> +-		goto error;
> +-	}
> ++    if (ret->keyblob_len == 0 || !ret->keyblob) {
> ++	errmsg = "Key body not present";
> ++	goto error;
> ++    }
> +
> +-	if (ret->encrypted && ret->keyblob_len % 8 != 0) {
> +-		errmsg = "Encrypted key blob is not a multiple of cipher block size";
> +-		goto error;
> +-	}
> ++    if (ret->encrypted && ret->keyblob_len % 8 != 0) {
> ++	errmsg = "Encrypted key blob is not a multiple of cipher block size";
> ++	goto error;
> ++    }
> +
> + 	m_burn(buffer, sizeof(buffer));
> +-	return ret;
> ++    return ret;
> +
> +-	error:
> ++    error:
> + 	m_burn(buffer, sizeof(buffer));
> +-	if (ret) {
> +-		if (ret->keyblob) {
> ++    if (ret) {
> ++	if (ret->keyblob) {
> + 			m_burn(ret->keyblob, ret->keyblob_size);
> + 			m_free(ret->keyblob);
> +-		}
> ++        }
> + 		m_free(ret);
> + 	}
> + 	if (fp) {
> + 		fclose(fp);
> +-	}
> ++    }
> + 	if (errmsg) {
> + 		fprintf(stderr, "Error: %s\n", errmsg);
> + 	}
> +-	return NULL;
> ++    return NULL;
> + }
> +
> + static int openssh_encrypted(const char *filename)
> + {
> +-	struct openssh_key *key = load_openssh_key(filename);
> +-	int ret;
> ++    struct openssh_key *key = load_openssh_key(filename);
> ++    int ret;
> +
> +-	if (!key)
> +-		return 0;
> +-	ret = key->encrypted;
> ++    if (!key)
> ++	return 0;
> ++    ret = key->encrypted;
> + 	m_burn(key->keyblob, key->keyblob_size);
> + 	m_free(key->keyblob);
> + 	m_free(key);
> +-	return ret;
> ++    return ret;
> + }
> +
> + static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
> + {
> + 	struct openssh_key *key;
> +-	unsigned char *p;
> +-	int ret, id, len, flags;
> ++    unsigned char *p;
> ++    int ret, id, len, flags;
> + 	int i, num_integers = 0;
> + 	sign_key *retval = NULL;
> +-	char *errmsg;
> ++    char *errmsg;
> + 	unsigned char *modptr = NULL;
> + 	int modlen = -9999;
> + 	enum signkey_type type;
> +@@ -518,86 +521,87 @@
> +
> + 	key = load_openssh_key(filename);
> +
> +-	if (!key)
> +-		return NULL;
> ++    if (!key)
> ++	return NULL;
> +
> +-	if (key->encrypted) {
> ++    if (key->encrypted) {
> + 		errmsg = "encrypted keys not supported currently";
> + 		goto error;
> + #if 0
> + 		/* matt TODO */
> +-		/*
> +-		 * Derive encryption key from passphrase and iv/salt:
> +-		 *
> +-		 *  - let block A equal MD5(passphrase || iv)
> +-		 *  - let block B equal MD5(A || passphrase || iv)
> +-		 *  - block C would be MD5(B || passphrase || iv) and so on
> +-		 *  - encryption key is the first N bytes of A || B
> +-		 */
> +-		struct MD5Context md5c;
> +-		unsigned char keybuf[32];
> ++	/*
> ++	 * Derive encryption key from passphrase and iv/salt:
> ++	 *
> ++	 *  - let block A equal MD5(passphrase || iv)
> ++	 *  - let block B equal MD5(A || passphrase || iv)
> ++	 *  - block C would be MD5(B || passphrase || iv) and so on
> ++	 *  - encryption key is the first N bytes of A || B
> ++	 */
> ++	struct MD5Context md5c;
> ++	unsigned char keybuf[32];
> +
> +-		MD5Init(&md5c);
> +-		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> +-		MD5Update(&md5c, (unsigned char *)key->iv, 8);
> +-		MD5Final(keybuf, &md5c);
> ++	MD5Init(&md5c);
> ++	MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> ++	MD5Update(&md5c, (unsigned char *)key->iv, 8);
> ++	MD5Final(keybuf, &md5c);
> +
> +-		MD5Init(&md5c);
> +-		MD5Update(&md5c, keybuf, 16);
> +-		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> +-		MD5Update(&md5c, (unsigned char *)key->iv, 8);
> +-		MD5Final(keybuf+16, &md5c);
> +-
> +-		/*
> +-		 * Now decrypt the key blob.
> +-		 */
> +-		des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv,
> +-								 key->keyblob, key->keyblob_len);
> +-
> +-		memset(&md5c, 0, sizeof(md5c));
> +-		memset(keybuf, 0, sizeof(keybuf));
> +-#endif
> +-	}
> ++	MD5Init(&md5c);
> ++	MD5Update(&md5c, keybuf, 16);
> ++	MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> ++	MD5Update(&md5c, (unsigned char *)key->iv, 8);
> ++	MD5Final(keybuf+16, &md5c);
> +
> + 	/*
> +-	 * Now we have a decrypted key blob, which contains an ASN.1
> +-	 * encoded private key. We must now untangle the ASN.1.
> +-	 *
> +-	 * We expect the whole key blob to be formatted as a SEQUENCE
> +-	 * (0x30 followed by a length code indicating that the rest of
> +-	 * the blob is part of the sequence). Within that SEQUENCE we
> +-	 * expect to see a bunch of INTEGERs. What those integers mean
> +-	 * depends on the key type:
> +-	 *
> +-	 *  - For RSA, we expect the integers to be 0, n, e, d, p, q,
> +-	 *	dmp1, dmq1, iqmp in that order. (The last three are d mod
> +-	 *	(p-1), d mod (q-1), inverse of q mod p respectively.)
> +-	 *
> +-	 *  - For DSA, we expect them to be 0, p, q, g, y, x in that
> +-	 *	order.
> ++	 * Now decrypt the key blob.
> + 	 */
> +-	
> +-	p = key->keyblob;
> ++	des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv,
> ++				 key->keyblob, key->keyblob_len);
> +
> +-	/* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */
> +-	ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags);
> +-	p += ret;
> +-	if (ret < 0 || id != 16) {
> ++        memset(&md5c, 0, sizeof(md5c));
> ++        memset(keybuf, 0, sizeof(keybuf));
> ++#endif
> ++    }
> ++
> ++    /*
> ++     * Now we have a decrypted key blob, which contains an ASN.1
> ++     * encoded private key. We must now untangle the ASN.1.
> ++     *
> ++     * We expect the whole key blob to be formatted as a SEQUENCE
> ++     * (0x30 followed by a length code indicating that the rest of
> ++     * the blob is part of the sequence). Within that SEQUENCE we
> ++     * expect to see a bunch of INTEGERs. What those integers mean
> ++     * depends on the key type:
> ++     *
> ++     *  - For RSA, we expect the integers to be 0, n, e, d, p, q,
> ++     *    dmp1, dmq1, iqmp in that order. (The last three are d mod
> ++     *    (p-1), d mod (q-1), inverse of q mod p respectively.)
> ++     *
> ++     *  - For DSA, we expect them to be 0, p, q, g, y, x in that
> ++     *    order.
> ++     */
> ++
> ++    p = key->keyblob;
> ++
> ++    /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */
> ++    ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags);
> ++    p += ret;
> ++    if (ret < 0 || id != 16 || len < 0 ||
> ++        key->keyblob+key->keyblob_len-p < len) {
> + 		errmsg = "ASN.1 decoding failure - wrong password?";
> +-		goto error;
> +-	}
> ++	goto error;
> ++    }
> +
> +-	/* Expect a load of INTEGERs. */
> +-	if (key->type == OSSH_RSA)
> +-		num_integers = 9;
> +-	else if (key->type == OSSH_DSA)
> +-		num_integers = 6;
> ++    /* Expect a load of INTEGERs. */
> ++    if (key->type == OSSH_RSA)
> ++	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.
> +-	 */
> ++    /*
> ++     * Space to create key blob in.
> ++     */
> + 	blobbuf = buf_new(3000);
> +
> + #ifdef DROPBEAR_DSS
> +@@ -613,17 +617,17 @@
> + 	}
> + #endif
> +
> +-	for (i = 0; i < num_integers; i++) {
> +-		ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
> +-							  &id, &len, &flags);
> +-		p += ret;
> +-		if (ret < 0 || id != 2 ||
> +-			key->keyblob+key->keyblob_len-p < len) {
> +-			errmsg = "ASN.1 decoding failure";
> +-			goto error;
> +-		}
> ++    for (i = 0; i < num_integers; i++) {
> ++	ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
> ++			      &id, &len, &flags);
> ++	p += ret;
> ++	if (ret < 0 || id != 2 || len < 0 ||
> ++	    key->keyblob+key->keyblob_len-p < len) {
> ++	    errmsg = "ASN.1 decoding failure";
> ++	    goto error;
> ++	}
> +
> +-		if (i == 0) {
> ++	if (i == 0) {
> + 			/* First integer is a version indicator */
> + 			int expected = -1;
> + 			switch (key->type) {
> +@@ -636,35 +640,35 @@
> + 					break;
> + 			}
> + 			if (len != 1 || p[0] != expected) {
> +-				errmsg = "Version number mismatch";
> +-				goto error;
> +-			}
> +-		} else if (key->type == OSSH_RSA) {
> +-			/*
> ++		errmsg = "Version number mismatch";
> ++		goto error;
> ++	    }
> ++	} else if (key->type == OSSH_RSA) {
> ++	    /*
> + 			 * OpenSSH key order is n, e, d, p, q, dmp1, dmq1, iqmp
> + 			 * but we want e, n, d, p, q
> +-			 */
> +-			if (i == 1) {
> +-				/* Save the details for after we deal with number 2. */
> ++	     */
> ++	    if (i == 1) {
> ++		/* Save the details for after we deal with number 2. */
> + 				modptr = p;
> +-				modlen = len;
> ++		modlen = len;
> + 			} else if (i >= 2 && i <= 5) {
> + 				buf_putstring(blobbuf, (const char*)p, len);
> +-				if (i == 2) {
> ++		if (i == 2) {
> + 					buf_putstring(blobbuf, (const char*)modptr, modlen);
> +-				}
> +-			}
> +-		} else if (key->type == OSSH_DSA) {
> +-			/*
> ++		}
> ++	    }
> ++	} else if (key->type == OSSH_DSA) {
> ++	    /*
> + 			 * OpenSSH key order is p, q, g, y, x,
> + 			 * we want the same.
> +-			 */
> ++	     */
> + 			buf_putstring(blobbuf, (const char*)p, len);
> +-		}
> ++	}
> +
> +-		/* Skip past the number. */
> +-		p += len;
> +-	}
> ++	/* Skip past the number. */
> ++	p += len;
> ++    }
> +
> + #ifdef DROPBEAR_ECDSA
> + 	if (key->type == OSSH_EC) {
> +@@ -780,12 +784,12 @@
> + 	}
> + #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.
> +-	 */
> ++    /*
> ++     * 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.
> ++     */
> + 	if (key->type == OSSH_RSA || key->type == OSSH_DSA) {
> + 		buf_setpos(blobbuf, 0);
> + 		type = DROPBEAR_SIGNKEY_ANY;
> +@@ -794,18 +798,18 @@
> + 			errmsg = "unable to create key structure";
> + 			sign_key_free(retkey);
> + 			retkey = NULL;
> +-			goto error;
> +-		}
> ++	goto error;
> ++    }
> + 	}
> +
> +-	errmsg = NULL;					 /* no error */
> +-	retval = retkey;
> ++    errmsg = NULL;                     /* no error */
> ++    retval = retkey;
> +
> +-	error:
> ++    error:
> + 	if (blobbuf) {
> + 		buf_burn(blobbuf);
> + 		buf_free(blobbuf);
> +-	}
> ++    }
> + 	m_burn(key->keyblob, key->keyblob_size);
> + 	m_free(key->keyblob);
> + 	m_burn(key, sizeof(*key));
> +@@ -813,22 +817,22 @@
> + 	if (errmsg) {
> + 		fprintf(stderr, "Error: %s\n", errmsg);
> + 	}
> +-	return retval;
> ++    return retval;
> + }
> +
> + static int openssh_write(const char *filename, sign_key *key,
> +-				  char *passphrase)
> ++		  char *passphrase)
> + {
> + 	buffer * keyblob = NULL;
> + 	buffer * extrablob = NULL; /* used for calculated values to write */
> + 	unsigned char *outblob = NULL;
> + 	int outlen = -9999;
> +-	struct mpint_pos numbers[9];
> ++    struct mpint_pos numbers[9];
> + 	int nnumbers = -1, pos = 0, len = 0, seqlen, i;
> + 	char *header = NULL, *footer = NULL;
> +-	char zero[1];
> +-	int ret = 0;
> +-	FILE *fp;
> ++    char zero[1];
> ++    int ret = 0;
> ++    FILE *fp;
> +
> + #ifdef DROPBEAR_RSA
> + 	mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */
> +@@ -843,9 +847,9 @@
> + #endif
> + 			0)
> + 	{
> +-		/*
> +-		 * Fetch the key blobs.
> +-		 */
> ++    /*
> ++     * Fetch the key blobs.
> ++     */
> + 		keyblob = buf_new(3000);
> + 		buf_put_priv_key(keyblob, key, key->type);
> +
> +@@ -853,10 +857,10 @@
> + 		/* 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.
> +-		 */
> ++    /*
> ++     * 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
> +@@ -871,17 +875,17 @@
> + 			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);
> +@@ -949,9 +953,9 @@
> + 			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";
> ++        nnumbers = 9;
> ++        header = "-----BEGIN RSA PRIVATE KEY-----\n";
> ++        footer = "-----END RSA PRIVATE KEY-----\n";
> + 		}
> + 	#endif /* DROPBEAR_RSA */
> +
> +@@ -983,45 +987,45 @@
> + 			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";
> +-		}
> ++        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 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.
> +-		 */
> ++    /*
> ++     * 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;
> +-		}
> ++    /*
> ++     * 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
> +@@ -1116,40 +1120,40 @@
> + 	}
> + #endif
> +
> +-	/*
> +-	 * Padding on OpenSSH keys is deterministic. The number of
> +-	 * padding bytes is always more than zero, and always at most
> +-	 * the cipher block length. The value of each padding byte is
> +-	 * equal to the number of padding bytes. So a plaintext that's
> +-	 * an exact multiple of the block size will be padded with 08
> +-	 * 08 08 08 08 08 08 08 (assuming a 64-bit block cipher); a
> +-	 * plaintext one byte less than a multiple of the block size
> +-	 * will be padded with just 01.
> +-	 *
> +-	 * This enables the OpenSSL key decryption function to strip
> +-	 * off the padding algorithmically and return the unpadded
> +-	 * plaintext to the next layer: it looks at the final byte, and
> +-	 * then expects to find that many bytes at the end of the data
> +-	 * with the same value. Those are all removed and the rest is
> +-	 * returned.
> +-	 */
> ++    /*
> ++     * Padding on OpenSSH keys is deterministic. The number of
> ++     * padding bytes is always more than zero, and always at most
> ++     * the cipher block length. The value of each padding byte is
> ++     * equal to the number of padding bytes. So a plaintext that's
> ++     * an exact multiple of the block size will be padded with 08
> ++     * 08 08 08 08 08 08 08 (assuming a 64-bit block cipher); a
> ++     * plaintext one byte less than a multiple of the block size
> ++     * will be padded with just 01.
> ++     *
> ++     * This enables the OpenSSL key decryption function to strip
> ++     * off the padding algorithmically and return the unpadded
> ++     * plaintext to the next layer: it looks at the final byte, and
> ++     * then expects to find that many bytes at the end of the data
> ++     * with the same value. Those are all removed and the rest is
> ++     * returned.
> ++     */
> + 	dropbear_assert(pos == len);
> +-	while (pos < outlen) {
> +-		outblob[pos++] = outlen - len;
> +-	}
> ++    while (pos < outlen) {
> ++        outblob[pos++] = outlen - len;
> ++    }
> +
> +-	/*
> +-	 * Encrypt the key.
> +-	 */
> +-	if (passphrase) {
> ++    /*
> ++     * Encrypt the key.
> ++     */
> ++    if (passphrase) {
> + 		fprintf(stderr, "Encrypted keys aren't supported currently\n");
> + 		goto error;
> +-	}
> ++    }
> +
> +-	/*
> +-	 * And save it. We'll use Unix line endings just in case it's
> +-	 * subsequently transferred in binary mode.
> +-	 */
> ++    /*
> ++     * And save it. We'll use Unix line endings just in case it's
> ++     * subsequently transferred in binary mode.
> ++     */
> + 	if (strlen(filename) == 1 && filename[0] == '-') {
> + 		fp = stdout;
> + 	} else {
> +@@ -1157,28 +1161,28 @@
> + 	}
> + 	if (!fp) {
> + 		fprintf(stderr, "Failed opening output file\n");
> +-		goto error;
> ++	goto error;
> + 	}
> +-	fputs(header, fp);
> ++    fputs(header, fp);
> + 	base64_encode_fp(fp, outblob, outlen, 64);
> +-	fputs(footer, fp);
> +-	fclose(fp);
> +-	ret = 1;
> ++    fputs(footer, fp);
> ++    fclose(fp);
> ++    ret = 1;
> +
> +-	error:
> +-	if (outblob) {
> +-		memset(outblob, 0, outlen);
> ++    error:
> ++    if (outblob) {
> ++        memset(outblob, 0, outlen);
> + 		m_free(outblob);
> +-	}
> ++    }
> + 	if (keyblob) {
> + 		buf_burn(keyblob);
> + 		buf_free(keyblob);
> +-	}
> ++    }
> + 	if (extrablob) {
> + 		buf_burn(extrablob);
> + 		buf_free(extrablob);
> +-	}
> +-	return ret;
> ++    }
> ++    return ret;
> + }
> +
> + #if 0
> +@@ -1196,10 +1200,10 @@
> +  *
> +  * So. The blob contains:
> +  *
> +- *  - uint32 0x3f6ff9eb	   (magic number)
> +- *  - uint32 size			 (total blob size)
> +- *  - string key-type		 (see below)
> +- *  - string cipher-type	  (tells you if key is encrypted)
> ++ *  - uint32 0x3f6ff9eb       (magic number)
> ++ *  - uint32 size             (total blob size)
> ++ *  - string key-type         (see below)
> ++ *  - string cipher-type      (tells you if key is encrypted)
> +  *  - string encrypted-blob
> +  *
> +  * (The first size field includes the size field itself and the
> +@@ -1255,654 +1259,679 @@
> +  *  - first 16 bytes are MD5(passphrase)
> +  *  - next 16 bytes are MD5(passphrase || first 16 bytes)
> +  *  - if there were more, they'd be MD5(passphrase || first 32),
> +- *	and so on.
> ++ *    and so on.
> +  */
> +
> + #define SSHCOM_MAGIC_NUMBER 0x3f6ff9eb
> +
> + struct sshcom_key {
> +-	char comment[256];				 /* allowing any length is overkill */
> +-	unsigned char *keyblob;
> +-	int keyblob_len, keyblob_size;
> ++    char comment[256];                 /* allowing any length is overkill */
> ++    unsigned char *keyblob;
> ++    int keyblob_len, keyblob_size;
> + };
> +
> + static struct sshcom_key *load_sshcom_key(const char *filename)
> + {
> +-	struct sshcom_key *ret;
> +-	FILE *fp;
> +-	char buffer[256];
> +-	int len;
> +-	char *errmsg, *p;
> +-	int headers_done;
> +-	char base64_bit[4];
> +-	int base64_chars = 0;
> ++    struct sshcom_key *ret;
> ++    FILE *fp;
> ++    char buffer[256];
> ++    int len;
> ++    char *errmsg, *p;
> ++    int headers_done;
> ++    char base64_bit[4];
> ++    int base64_chars = 0;
> +
> +-	ret = snew(struct sshcom_key);
> +-	ret->comment[0] = '\0';
> +-	ret->keyblob = NULL;
> +-	ret->keyblob_len = ret->keyblob_size = 0;
> ++    ret = snew(struct sshcom_key);
> ++    ret->comment[0] = '\0';
> ++    ret->keyblob = NULL;
> ++    ret->keyblob_len = ret->keyblob_size = 0;
> +
> + 	fp = fopen(filename, "r");
> +-	if (!fp) {
> +-		errmsg = "Unable to open key file";
> ++    if (!fp) {
> ++	errmsg = "Unable to open key file";
> ++	goto error;
> ++    }
> ++    if (!fgets(buffer, sizeof(buffer), fp) ||
> ++	0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) {
> ++	errmsg = "File does not begin with ssh.com key header";
> ++	goto error;
> ++    }
> ++
> ++    headers_done = 0;
> ++    while (1) {
> ++	if (!fgets(buffer, sizeof(buffer), fp)) {
> ++	    errmsg = "Unexpected end of file";
> ++	    goto error;
> ++	}
> ++        if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n"))
> ++            break;                     /* done */
> ++	if ((p = strchr(buffer, ':')) != NULL) {
> ++	    if (headers_done) {
> ++		errmsg = "Header found in body of key data";
> + 		goto error;
> ++	    }
> ++	    *p++ = '\0';
> ++	    while (*p && isspace((unsigned char)*p)) p++;
> ++            /*
> ++             * Header lines can end in a trailing backslash for
> ++             * continuation.
> ++             */
> ++            while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) ||
> ++                   p[len-1] != '\n' || p[len-2] == '\\') {
> ++                if (len > (int)((p-buffer) + sizeof(buffer)-2)) {
> ++                    errmsg = "Header line too long to deal with";
> ++                    goto error;
> ++                }
> ++                if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) {
> ++                    errmsg = "Unexpected end of file";
> ++                    goto error;
> ++                }
> ++            }
> ++            p[strcspn(p, "\n")] = '\0';
> ++            if (!strcmp(buffer, "Comment")) {
> ++                /* Strip quotes in comment if present. */
> ++                if (p[0] == '"' && p[strlen(p)-1] == '"') {
> ++                    p++;
> ++                    p[strlen(p)-1] = '\0';
> ++                }
> ++                strncpy(ret->comment, p, sizeof(ret->comment));
> ++                ret->comment[sizeof(ret->comment)-1] = '\0';
> ++            }
> ++	} else {
> ++	    headers_done = 1;
> ++
> ++	    p = buffer;
> ++	    while (isbase64(*p)) {
> ++                base64_bit[base64_chars++] = *p;
> ++                if (base64_chars == 4) {
> ++                    unsigned char out[3];
> ++
> ++                    base64_chars = 0;
> ++
> ++                    len = base64_decode_atom(base64_bit, out);
> ++
> ++                    if (len <= 0) {
> ++                        errmsg = "Invalid base64 encoding";
> ++                        goto error;
> ++                    }
> ++
> ++                    if (ret->keyblob_len + len > ret->keyblob_size) {
> ++                        ret->keyblob_size = ret->keyblob_len + len + 256;
> ++                        ret->keyblob = sresize(ret->keyblob, ret->keyblob_size,
> ++					       unsigned char);
> ++                    }
> ++
> ++                    memcpy(ret->keyblob + ret->keyblob_len, out, len);
> ++                    ret->keyblob_len += len;
> ++                }
> ++
> ++		p++;
> ++	    }
> + 	}
> +-	if (!fgets(buffer, sizeof(buffer), fp) ||
> +-		0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) {
> +-		errmsg = "File does not begin with ssh.com key header";
> +-		goto error;
> +-	}
> ++    }
> +
> +-	headers_done = 0;
> +-	while (1) {
> +-		if (!fgets(buffer, sizeof(buffer), fp)) {
> +-			errmsg = "Unexpected end of file";
> +-			goto error;
> +-		}
> +-		if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n"))
> +-			break;					 /* done */
> +-		if ((p = strchr(buffer, ':')) != NULL) {
> +-			if (headers_done) {
> +-				errmsg = "Header found in body of key data";
> +-				goto error;
> +-			}
> +-			*p++ = '\0';
> +-			while (*p && isspace((unsigned char)*p)) p++;
> +-			/*
> +-			 * Header lines can end in a trailing backslash for
> +-			 * continuation.
> +-			 */
> +-			while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) ||
> +-				   p[len-1] != '\n' || p[len-2] == '\\') {
> +-				if (len > (int)((p-buffer) + sizeof(buffer)-2)) {
> +-					errmsg = "Header line too long to deal with";
> +-					goto error;
> +-				}
> +-				if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) {
> +-					errmsg = "Unexpected end of file";
> +-					goto error;
> +-				}
> +-			}
> +-			p[strcspn(p, "\n")] = '\0';
> +-			if (!strcmp(buffer, "Comment")) {
> +-				/* Strip quotes in comment if present. */
> +-				if (p[0] == '"' && p[strlen(p)-1] == '"') {
> +-					p++;
> +-					p[strlen(p)-1] = '\0';
> +-				}
> +-				strncpy(ret->comment, p, sizeof(ret->comment));
> +-				ret->comment[sizeof(ret->comment)-1] = '\0';
> +-			}
> +-		} else {
> +-			headers_done = 1;
> ++    if (ret->keyblob_len == 0 || !ret->keyblob) {
> ++	errmsg = "Key body not present";
> ++	goto error;
> ++    }
> +
> +-			p = buffer;
> +-			while (isbase64(*p)) {
> +-				base64_bit[base64_chars++] = *p;
> +-				if (base64_chars == 4) {
> +-					unsigned char out[3];
> ++    return ret;
> +
> +-					base64_chars = 0;
> +-
> +-					len = base64_decode_atom(base64_bit, out);
> +-
> +-					if (len <= 0) {
> +-						errmsg = "Invalid base64 encoding";
> +-						goto error;
> +-					}
> +-
> +-					if (ret->keyblob_len + len > ret->keyblob_size) {
> +-						ret->keyblob_size = ret->keyblob_len + len + 256;
> +-						ret->keyblob = sresize(ret->keyblob, ret->keyblob_size,
> +-											   unsigned char);
> +-					}
> +-
> +-					memcpy(ret->keyblob + ret->keyblob_len, out, len);
> +-					ret->keyblob_len += len;
> +-				}
> +-
> +-				p++;
> +-			}
> +-		}
> +-	}
> +-
> +-	if (ret->keyblob_len == 0 || !ret->keyblob) {
> +-		errmsg = "Key body not present";
> +-		goto error;
> +-	}
> +-
> +-	return ret;
> +-
> +-	error:
> +-	if (ret) {
> +-		if (ret->keyblob) {
> +-			memset(ret->keyblob, 0, ret->keyblob_size);
> ++    error:
> ++    if (ret) {
> ++	if (ret->keyblob) {
> ++            memset(ret->keyblob, 0, ret->keyblob_size);
> + 			m_free(ret->keyblob);
> +-		}
> +-		memset(&ret, 0, sizeof(ret));
> ++        }
> ++        memset(ret, 0, sizeof(*ret));
> + 		m_free(ret);
> +-	}
> +-	return NULL;
> ++    }
> ++    return NULL;
> + }
> +
> + int sshcom_encrypted(const char *filename, char **comment)
> + {
> +-	struct sshcom_key *key = load_sshcom_key(filename);
> +-	int pos, len, answer;
> ++    struct sshcom_key *key = load_sshcom_key(filename);
> ++    int pos, len, answer;
> +
> +-	*comment = NULL;
> +-	if (!key)
> +-		return 0;
> ++    *comment = NULL;
> ++    if (!key)
> ++        return 0;
> +
> +-	/*
> +-	 * Check magic number.
> +-	 */
> +-	if (GET_32BIT(key->keyblob) != 0x3f6ff9eb)
> +-		return 0;					  /* key is invalid */
> ++    /*
> ++     * Check magic number.
> ++     */
> ++    if (GET_32BIT(key->keyblob) != 0x3f6ff9eb)
> ++        return 0;                      /* key is invalid */
> +
> +-	/*
> +-	 * Find the cipher-type string.
> +-	 */
> +-	answer = 0;
> +-	pos = 8;
> +-	if (key->keyblob_len < pos+4)
> +-		goto done;					 /* key is far too short */
> +-	pos += 4 + GET_32BIT(key->keyblob + pos);   /* skip key type */
> +-	if (key->keyblob_len < pos+4)
> +-		goto done;					 /* key is far too short */
> +-	len = GET_32BIT(key->keyblob + pos);   /* find cipher-type length */
> +-	if (key->keyblob_len < pos+4+len)
> +-		goto done;					 /* cipher type string is incomplete */
> +-	if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4))
> +-		answer = 1;
> ++    /*
> ++     * Find the cipher-type string.
> ++     */
> ++    answer = 0;
> ++    pos = 8;
> ++    if (key->keyblob_len < pos+4)
> ++        goto done;                     /* key is far too short */
> ++    len = toint(GET_32BIT(key->keyblob + pos));
> ++    if (len < 0 || len > key->keyblob_len - pos - 4)
> ++        goto done;                     /* key is far too short */
> ++    pos += 4 + len;                    /* skip key type */
> ++    len = toint(GET_32BIT(key->keyblob + pos)); /* find cipher-type length */
> ++    if (len < 0 || len > key->keyblob_len - pos - 4)
> ++        goto done;                     /* cipher type string is incomplete */
> ++    if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4))
> ++        answer = 1;
> +
> +-	done:
> +-	*comment = dupstr(key->comment);
> +-	memset(key->keyblob, 0, key->keyblob_size);
> ++    done:
> ++    *comment = dupstr(key->comment);
> ++    memset(key->keyblob, 0, key->keyblob_size);
> + 	m_free(key->keyblob);
> +-	memset(&key, 0, sizeof(key));
> ++    memset(key, 0, sizeof(*key));
> + 	m_free(key);
> +-	return answer;
> ++    return answer;
> + }
> +
> + static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret)
> + {
> +-	int bits;
> +-	int bytes;
> +-	unsigned char *d = (unsigned char *) data;
> ++    unsigned bits, bytes;
> ++    unsigned char *d = (unsigned char *) data;
> +
> +-	if (len < 4)
> +-		goto error;
> +-	bits = GET_32BIT(d);
> ++    if (len < 4)
> ++        goto error;
> ++    bits = GET_32BIT(d);
> +
> +-	bytes = (bits + 7) / 8;
> +-	if (len < 4+bytes)
> +-		goto error;
> ++    bytes = (bits + 7) / 8;
> ++    if (len < 4+bytes)
> ++        goto error;
> +
> +-	ret->start = d + 4;
> +-	ret->bytes = bytes;
> +-	return bytes+4;
> ++    ret->start = d + 4;
> ++    ret->bytes = bytes;
> ++    return bytes+4;
> +
> +-	error:
> +-	ret->start = NULL;
> +-	ret->bytes = -1;
> +-	return len;						/* ensure further calls fail as well */
> ++    error:
> ++    ret->start = NULL;
> ++    ret->bytes = -1;
> ++    return len;                        /* ensure further calls fail as well */
> + }
> +
> + static int sshcom_put_mpint(void *target, void *data, int len)
> + {
> +-	unsigned char *d = (unsigned char *)target;
> +-	unsigned char *i = (unsigned char *)data;
> +-	int bits = len * 8 - 1;
> ++    unsigned char *d = (unsigned char *)target;
> ++    unsigned char *i = (unsigned char *)data;
> ++    int bits = len * 8 - 1;
> +
> +-	while (bits > 0) {
> +-		if (*i & (1 << (bits & 7)))
> +-			break;
> +-		if (!(bits-- & 7))
> +-			i++, len--;
> +-	}
> ++    while (bits > 0) {
> ++	if (*i & (1 << (bits & 7)))
> ++	    break;
> ++	if (!(bits-- & 7))
> ++	    i++, len--;
> ++    }
> +
> +-	PUT_32BIT(d, bits+1);
> +-	memcpy(d+4, i, len);
> +-	return len+4;
> ++    PUT_32BIT(d, bits+1);
> ++    memcpy(d+4, i, len);
> ++    return len+4;
> + }
> +
> + sign_key *sshcom_read(const char *filename, char *passphrase)
> + {
> +-	struct sshcom_key *key = load_sshcom_key(filename);
> +-	char *errmsg;
> +-	int pos, len;
> +-	const char prefix_rsa[] = "if-modn{sign{rsa";
> +-	const char prefix_dsa[] = "dl-modp{sign{dsa";
> +-	enum { RSA, DSA } type;
> +-	int encrypted;
> +-	char *ciphertext;
> +-	int cipherlen;
> +-	struct ssh2_userkey *ret = NULL, *retkey;
> +-	const struct ssh_signkey *alg;
> +-	unsigned char *blob = NULL;
> +-	int blobsize, publen, privlen;
> ++    struct sshcom_key *key = load_sshcom_key(filename);
> ++    char *errmsg;
> ++    int pos, len;
> ++    const char prefix_rsa[] = "if-modn{sign{rsa";
> ++    const char prefix_dsa[] = "dl-modp{sign{dsa";
> ++    enum { RSA, DSA } type;
> ++    int encrypted;
> ++    char *ciphertext;
> ++    int cipherlen;
> ++    struct ssh2_userkey *ret = NULL, *retkey;
> ++    const struct ssh_signkey *alg;
> ++    unsigned char *blob = NULL;
> ++    int blobsize = 0, publen, privlen;
> +
> +-	if (!key)
> +-		return NULL;
> ++    if (!key)
> ++        return NULL;
> ++
> ++    /*
> ++     * Check magic number.
> ++     */
> ++    if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) {
> ++        errmsg = "Key does not begin with magic number";
> ++        goto error;
> ++    }
> ++
> ++    /*
> ++     * Determine the key type.
> ++     */
> ++    pos = 8;
> ++    if (key->keyblob_len < pos+4 ||
> ++        (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
> ++        errmsg = "Key blob does not contain a key type string";
> ++        goto error;
> ++    }
> ++    if (len > sizeof(prefix_rsa) - 1 &&
> ++        !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) {
> ++        type = RSA;
> ++    } else if (len > sizeof(prefix_dsa) - 1 &&
> ++        !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) {
> ++        type = DSA;
> ++    } else {
> ++        errmsg = "Key is of unknown type";
> ++        goto error;
> ++    }
> ++    pos += 4+len;
> ++
> ++    /*
> ++     * Determine the cipher type.
> ++     */
> ++    if (key->keyblob_len < pos+4 ||
> ++        (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
> ++        errmsg = "Key blob does not contain a cipher type string";
> ++        goto error;
> ++    }
> ++    if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4))
> ++        encrypted = 0;
> ++    else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8))
> ++        encrypted = 1;
> ++    else {
> ++        errmsg = "Key encryption is of unknown type";
> ++        goto error;
> ++    }
> ++    pos += 4+len;
> ++
> ++    /*
> ++     * Get hold of the encrypted part of the key.
> ++     */
> ++    if (key->keyblob_len < pos+4 ||
> ++        (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
> ++        errmsg = "Key blob does not contain actual key data";
> ++        goto error;
> ++    }
> ++    ciphertext = (char *)key->keyblob + pos + 4;
> ++    cipherlen = len;
> ++    if (cipherlen == 0) {
> ++        errmsg = "Length of key data is zero";
> ++        goto error;
> ++    }
> ++
> ++    /*
> ++     * Decrypt it if necessary.
> ++     */
> ++    if (encrypted) {
> ++	/*
> ++	 * Derive encryption key from passphrase and iv/salt:
> ++	 *
> ++	 *  - let block A equal MD5(passphrase)
> ++	 *  - let block B equal MD5(passphrase || A)
> ++	 *  - block C would be MD5(passphrase || A || B) and so on
> ++	 *  - encryption key is the first N bytes of A || B
> ++	 */
> ++	struct MD5Context md5c;
> ++	unsigned char keybuf[32], iv[8];
> ++
> ++        if (cipherlen % 8 != 0) {
> ++            errmsg = "Encrypted part of key is not a multiple of cipher block"
> ++                " size";
> ++            goto error;
> ++        }
> ++
> ++	MD5Init(&md5c);
> ++	MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> ++	MD5Final(keybuf, &md5c);
> ++
> ++	MD5Init(&md5c);
> ++	MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> ++	MD5Update(&md5c, keybuf, 16);
> ++	MD5Final(keybuf+16, &md5c);
> +
> + 	/*
> +-	 * Check magic number.
> ++	 * Now decrypt the key blob.
> + 	 */
> +-	if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) {
> +-		errmsg = "Key does not begin with magic number";
> +-		goto error;
> +-	}
> ++        memset(iv, 0, sizeof(iv));
> ++	des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
> ++				 cipherlen);
> +
> +-	/*
> +-	 * Determine the key type.
> +-	 */
> +-	pos = 8;
> +-	if (key->keyblob_len < pos+4 ||
> +-		(len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
> +-		errmsg = "Key blob does not contain a key type string";
> +-		goto error;
> +-	}
> +-	if (len > sizeof(prefix_rsa) - 1 &&
> +-		!memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) {
> +-		type = RSA;
> +-	} else if (len > sizeof(prefix_dsa) - 1 &&
> +-		!memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) {
> +-		type = DSA;
> +-	} else {
> +-		errmsg = "Key is of unknown type";
> +-		goto error;
> +-	}
> +-	pos += 4+len;
> ++        memset(&md5c, 0, sizeof(md5c));
> ++        memset(keybuf, 0, sizeof(keybuf));
> +
> +-	/*
> +-	 * Determine the cipher type.
> +-	 */
> +-	if (key->keyblob_len < pos+4 ||
> +-		(len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
> +-		errmsg = "Key blob does not contain a cipher type string";
> +-		goto error;
> +-	}
> +-	if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4))
> +-		encrypted = 0;
> +-	else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8))
> +-		encrypted = 1;
> +-	else {
> +-		errmsg = "Key encryption is of unknown type";
> +-		goto error;
> +-	}
> +-	pos += 4+len;
> ++        /*
> ++         * Hereafter we return WRONG_PASSPHRASE for any parsing
> ++         * error. (But only if we've just tried to decrypt it!
> ++         * Returning WRONG_PASSPHRASE for an unencrypted key is
> ++         * automatic doom.)
> ++         */
> ++        if (encrypted)
> ++            ret = SSH2_WRONG_PASSPHRASE;
> ++    }
> +
> +-	/*
> +-	 * Get hold of the encrypted part of the key.
> +-	 */
> +-	if (key->keyblob_len < pos+4 ||
> +-		(len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
> +-		errmsg = "Key blob does not contain actual key data";
> +-		goto error;
> +-	}
> +-	ciphertext = (char *)key->keyblob + pos + 4;
> +-	cipherlen = len;
> +-	if (cipherlen == 0) {
> +-		errmsg = "Length of key data is zero";
> +-		goto error;
> +-	}
> ++    /*
> ++     * Strip away the containing string to get to the real meat.
> ++     */
> ++    len = toint(GET_32BIT(ciphertext));
> ++    if (len < 0 || len > cipherlen-4) {
> ++        errmsg = "containing string was ill-formed";
> ++        goto error;
> ++    }
> ++    ciphertext += 4;
> ++    cipherlen = len;
> +
> +-	/*
> +-	 * Decrypt it if necessary.
> +-	 */
> +-	if (encrypted) {
> +-		/*
> +-		 * Derive encryption key from passphrase and iv/salt:
> +-		 *
> +-		 *  - let block A equal MD5(passphrase)
> +-		 *  - let block B equal MD5(passphrase || A)
> +-		 *  - block C would be MD5(passphrase || A || B) and so on
> +-		 *  - encryption key is the first N bytes of A || B
> +-		 */
> +-		struct MD5Context md5c;
> +-		unsigned char keybuf[32], iv[8];
> ++    /*
> ++     * Now we break down into RSA versus DSA. In either case we'll
> ++     * construct public and private blobs in our own format, and
> ++     * end up feeding them to alg->createkey().
> ++     */
> ++    blobsize = cipherlen + 256;
> ++    blob = snewn(blobsize, unsigned char);
> ++    privlen = 0;
> ++    if (type == RSA) {
> ++        struct mpint_pos n, e, d, u, p, q;
> ++        int pos = 0;
> ++        pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e);
> ++        pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d);
> ++        pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n);
> ++        pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u);
> ++        pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
> ++        pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
> ++        if (!q.start) {
> ++            errmsg = "key data did not contain six integers";
> ++            goto error;
> ++        }
> +
> +-		if (cipherlen % 8 != 0) {
> +-			errmsg = "Encrypted part of key is not a multiple of cipher block"
> +-				" size";
> +-			goto error;
> +-		}
> ++        alg = &ssh_rsa;
> ++        pos = 0;
> ++        pos += put_string(blob+pos, "ssh-rsa", 7);
> ++        pos += put_mp(blob+pos, e.start, e.bytes);
> ++        pos += put_mp(blob+pos, n.start, n.bytes);
> ++        publen = pos;
> ++        pos += put_string(blob+pos, d.start, d.bytes);
> ++        pos += put_mp(blob+pos, q.start, q.bytes);
> ++        pos += put_mp(blob+pos, p.start, p.bytes);
> ++        pos += put_mp(blob+pos, u.start, u.bytes);
> ++        privlen = pos - publen;
> ++    } else if (type == DSA) {
> ++        struct mpint_pos p, q, g, x, y;
> ++        int pos = 4;
> ++        if (GET_32BIT(ciphertext) != 0) {
> ++            errmsg = "predefined DSA parameters not supported";
> ++            goto error;
> ++        }
> ++        pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
> ++        pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g);
> ++        pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
> ++        pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y);
> ++        pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x);
> ++        if (!x.start) {
> ++            errmsg = "key data did not contain five integers";
> ++            goto error;
> ++        }
> +
> +-		MD5Init(&md5c);
> +-		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> +-		MD5Final(keybuf, &md5c);
> +-
> +-		MD5Init(&md5c);
> +-		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> +-		MD5Update(&md5c, keybuf, 16);
> +-		MD5Final(keybuf+16, &md5c);
> +-
> +-		/*
> +-		 * Now decrypt the key blob.
> +-		 */
> +-		memset(iv, 0, sizeof(iv));
> +-		des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
> +-								 cipherlen);
> +-
> +-		memset(&md5c, 0, sizeof(md5c));
> +-		memset(keybuf, 0, sizeof(keybuf));
> +-
> +-		/*
> +-		 * Hereafter we return WRONG_PASSPHRASE for any parsing
> +-		 * error. (But only if we've just tried to decrypt it!
> +-		 * Returning WRONG_PASSPHRASE for an unencrypted key is
> +-		 * automatic doom.)
> +-		 */
> +-		if (encrypted)
> +-			ret = SSH2_WRONG_PASSPHRASE;
> +-	}
> +-
> +-	/*
> +-	 * Strip away the containing string to get to the real meat.
> +-	 */
> +-	len = GET_32BIT(ciphertext);
> +-	if (len > cipherlen-4) {
> +-		errmsg = "containing string was ill-formed";
> +-		goto error;
> +-	}
> +-	ciphertext += 4;
> +-	cipherlen = len;
> +-
> +-	/*
> +-	 * Now we break down into RSA versus DSA. In either case we'll
> +-	 * construct public and private blobs in our own format, and
> +-	 * end up feeding them to alg->createkey().
> +-	 */
> +-	blobsize = cipherlen + 256;
> +-	blob = snewn(blobsize, unsigned char);
> +-	privlen = 0;
> +-	if (type == RSA) {
> +-		struct mpint_pos n, e, d, u, p, q;
> +-		int pos = 0;
> +-		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e);
> +-		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d);
> +-		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n);
> +-		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u);
> +-		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
> +-		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
> +-		if (!q.start) {
> +-			errmsg = "key data did not contain six integers";
> +-			goto error;
> +-		}
> +-
> +-		alg = &ssh_rsa;
> +-		pos = 0;
> +-		pos += put_string(blob+pos, "ssh-rsa", 7);
> +-		pos += put_mp(blob+pos, e.start, e.bytes);
> +-		pos += put_mp(blob+pos, n.start, n.bytes);
> +-		publen = pos;
> +-		pos += put_string(blob+pos, d.start, d.bytes);
> +-		pos += put_mp(blob+pos, q.start, q.bytes);
> +-		pos += put_mp(blob+pos, p.start, p.bytes);
> +-		pos += put_mp(blob+pos, u.start, u.bytes);
> +-		privlen = pos - publen;
> +-	} else if (type == DSA) {
> +-		struct mpint_pos p, q, g, x, y;
> +-		int pos = 4;
> +-		if (GET_32BIT(ciphertext) != 0) {
> +-			errmsg = "predefined DSA parameters not supported";
> +-			goto error;
> +-		}
> +-		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
> +-		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g);
> +-		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
> +-		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y);
> +-		pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x);
> +-		if (!x.start) {
> +-			errmsg = "key data did not contain five integers";
> +-			goto error;
> +-		}
> +-
> +-		alg = &ssh_dss;
> +-		pos = 0;
> +-		pos += put_string(blob+pos, "ssh-dss", 7);
> +-		pos += put_mp(blob+pos, p.start, p.bytes);
> +-		pos += put_mp(blob+pos, q.start, q.bytes);
> +-		pos += put_mp(blob+pos, g.start, g.bytes);
> +-		pos += put_mp(blob+pos, y.start, y.bytes);
> +-		publen = pos;
> +-		pos += put_mp(blob+pos, x.start, x.bytes);
> +-		privlen = pos - publen;
> +-	}
> ++        alg = &ssh_dss;
> ++        pos = 0;
> ++        pos += put_string(blob+pos, "ssh-dss", 7);
> ++        pos += put_mp(blob+pos, p.start, p.bytes);
> ++        pos += put_mp(blob+pos, q.start, q.bytes);
> ++        pos += put_mp(blob+pos, g.start, g.bytes);
> ++        pos += put_mp(blob+pos, y.start, y.bytes);
> ++        publen = pos;
> ++        pos += put_mp(blob+pos, x.start, x.bytes);
> ++        privlen = pos - publen;
> ++    } else
> ++	return NULL;
> +
> + 	dropbear_assert(privlen > 0);			   /* should have bombed by now if not */
> +
> +-	retkey = snew(struct ssh2_userkey);
> +-	retkey->alg = alg;
> +-	retkey->data = alg->createkey(blob, publen, blob+publen, privlen);
> +-	if (!retkey->data) {
> ++    retkey = snew(struct ssh2_userkey);
> ++    retkey->alg = alg;
> ++    retkey->data = alg->createkey(blob, publen, blob+publen, privlen);
> ++    if (!retkey->data) {
> + 		m_free(retkey);
> +-		errmsg = "unable to create key data structure";
> +-		goto error;
> +-	}
> +-	retkey->comment = dupstr(key->comment);
> ++	errmsg = "unable to create key data structure";
> ++	goto error;
> ++    }
> ++    retkey->comment = dupstr(key->comment);
> +
> +-	errmsg = NULL; /* no error */
> +-	ret = retkey;
> ++    errmsg = NULL; /* no error */
> ++    ret = retkey;
> +
> +-	error:
> +-	if (blob) {
> +-		memset(blob, 0, blobsize);
> ++    error:
> ++    if (blob) {
> ++        memset(blob, 0, blobsize);
> + 		m_free(blob);
> +-	}
> +-	memset(key->keyblob, 0, key->keyblob_size);
> ++    }
> ++    memset(key->keyblob, 0, key->keyblob_size);
> + 	m_free(key->keyblob);
> +-	memset(&key, 0, sizeof(key));
> ++    memset(key, 0, sizeof(*key));
> + 	m_free(key);
> +-	return ret;
> ++    return ret;
> + }
> +
> + int sshcom_write(const char *filename, sign_key *key,
> +-				 char *passphrase)
> ++		 char *passphrase)
> + {
> +-	unsigned char *pubblob, *privblob;
> +-	int publen, privlen;
> +-	unsigned char *outblob;
> +-	int outlen;
> +-	struct mpint_pos numbers[6];
> +-	int nnumbers, initial_zero, pos, lenpos, i;
> +-	char *type;
> +-	char *ciphertext;
> +-	int cipherlen;
> +-	int ret = 0;
> +-	FILE *fp;
> ++    unsigned char *pubblob, *privblob;
> ++    int publen, privlen;
> ++    unsigned char *outblob;
> ++    int outlen;
> ++    struct mpint_pos numbers[6];
> ++    int nnumbers, initial_zero, pos, lenpos, i;
> ++    char *type;
> ++    char *ciphertext;
> ++    int cipherlen;
> ++    int ret = 0;
> ++    FILE *fp;
> +
> +-	/*
> +-	 * Fetch the key blobs.
> +-	 */
> +-	pubblob = key->alg->public_blob(key->data, &publen);
> +-	privblob = key->alg->private_blob(key->data, &privlen);
> +-	outblob = NULL;
> ++    /*
> ++     * Fetch the key blobs.
> ++     */
> ++    pubblob = key->alg->public_blob(key->data, &publen);
> ++    privblob = key->alg->private_blob(key->data, &privlen);
> ++    outblob = NULL;
> +
> +-	/*
> +-	 * Find the sequence of integers to be encoded into the OpenSSH
> +-	 * key blob, and also decide on the header line.
> +-	 */
> +-	if (key->alg == &ssh_rsa) {
> +-		int pos;
> +-		struct mpint_pos n, e, d, p, q, iqmp;
> ++    /*
> ++     * Find the sequence of integers to be encoded into the OpenSSH
> ++     * key blob, and also decide on the header line.
> ++     */
> ++    if (key->alg == &ssh_rsa) {
> ++        int pos;
> ++        struct mpint_pos n, e, d, p, q, iqmp;
> +
> +-		pos = 4 + GET_32BIT(pubblob);
> +-		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e);
> +-		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n);
> +-		pos = 0;
> +-		pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d);
> +-		pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p);
> +-		pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
> +-		pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
> ++        pos = 4 + GET_32BIT(pubblob);
> ++        pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e);
> ++        pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n);
> ++        pos = 0;
> ++        pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d);
> ++        pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p);
> ++        pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
> ++        pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
> +
> + 		dropbear_assert(e.start && iqmp.start); /* can't go wrong */
> +
> +-		numbers[0] = e;
> +-		numbers[1] = d;
> +-		numbers[2] = n;
> +-		numbers[3] = iqmp;
> +-		numbers[4] = q;
> +-		numbers[5] = p;
> ++        numbers[0] = e;
> ++        numbers[1] = d;
> ++        numbers[2] = n;
> ++        numbers[3] = iqmp;
> ++        numbers[4] = q;
> ++        numbers[5] = p;
> +
> +-		nnumbers = 6;
> +-		initial_zero = 0;
> +-		type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}";
> +-	} else if (key->alg == &ssh_dss) {
> +-		int pos;
> +-		struct mpint_pos p, q, g, y, x;
> ++        nnumbers = 6;
> ++	initial_zero = 0;
> ++	type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}";
> ++    } else if (key->alg == &ssh_dss) {
> ++        int pos;
> ++        struct mpint_pos p, q, g, y, x;
> +
> +-		pos = 4 + GET_32BIT(pubblob);
> +-		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p);
> +-		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q);
> +-		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g);
> +-		pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y);
> +-		pos = 0;
> +-		pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x);
> ++        pos = 4 + GET_32BIT(pubblob);
> ++        pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p);
> ++        pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q);
> ++        pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g);
> ++        pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y);
> ++        pos = 0;
> ++        pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x);
> +
> + 		dropbear_assert(y.start && x.start); /* can't go wrong */
> +
> +-		numbers[0] = p;
> +-		numbers[1] = g;
> +-		numbers[2] = q;
> +-		numbers[3] = y;
> +-		numbers[4] = x;
> ++        numbers[0] = p;
> ++        numbers[1] = g;
> ++        numbers[2] = q;
> ++        numbers[3] = y;
> ++        numbers[4] = x;
> +
> +-		nnumbers = 5;
> +-		initial_zero = 1;
> +-		type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}";
> +-	} else {
> ++        nnumbers = 5;
> ++	initial_zero = 1;
> ++	type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}";
> ++    } else {
> + 		dropbear_assert(0);					 /* zoinks! */
> +-	}
> ++    }
> +
> +-	/*
> +-	 * Total size of key blob will be somewhere under 512 plus
> +-	 * combined length of integers. We'll calculate the more
> +-	 * precise size as we construct the blob.
> +-	 */
> +-	outlen = 512;
> +-	for (i = 0; i < nnumbers; i++)
> +-		outlen += 4 + numbers[i].bytes;
> +-	outblob = snewn(outlen, unsigned char);
> ++    /*
> ++     * Total size of key blob will be somewhere under 512 plus
> ++     * combined length of integers. We'll calculate the more
> ++     * precise size as we construct the blob.
> ++     */
> ++    outlen = 512;
> ++    for (i = 0; i < nnumbers; i++)
> ++	outlen += 4 + numbers[i].bytes;
> ++    outblob = snewn(outlen, unsigned char);
> +
> +-	/*
> +-	 * Create the unencrypted key blob.
> +-	 */
> +-	pos = 0;
> +-	PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4;
> +-	pos += 4;							   /* length field, fill in later */
> +-	pos += put_string(outblob+pos, type, strlen(type));
> +-	{
> +-		char *ciphertype = passphrase ? "3des-cbc" : "none";
> +-		pos += put_string(outblob+pos, ciphertype, strlen(ciphertype));
> +-	}
> +-	lenpos = pos;					   /* remember this position */
> +-	pos += 4;							   /* encrypted-blob size */
> +-	pos += 4;							   /* encrypted-payload size */
> +-	if (initial_zero) {
> +-		PUT_32BIT(outblob+pos, 0);
> +-		pos += 4;
> +-	}
> +-	for (i = 0; i < nnumbers; i++)
> +-		pos += sshcom_put_mpint(outblob+pos,
> +-								numbers[i].start, numbers[i].bytes);
> +-	/* Now wrap up the encrypted payload. */
> +-	PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8));
> +-	/* Pad encrypted blob to a multiple of cipher block size. */
> +-	if (passphrase) {
> +-		int padding = -(pos - (lenpos+4)) & 7;
> +-		while (padding--)
> +-			outblob[pos++] = random_byte();
> +-	}
> +-	ciphertext = (char *)outblob+lenpos+4;
> +-	cipherlen = pos - (lenpos+4);
> ++    /*
> ++     * Create the unencrypted key blob.
> ++     */
> ++    pos = 0;
> ++    PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4;
> ++    pos += 4;			       /* length field, fill in later */
> ++    pos += put_string(outblob+pos, type, strlen(type));
> ++    {
> ++	char *ciphertype = passphrase ? "3des-cbc" : "none";
> ++	pos += put_string(outblob+pos, ciphertype, strlen(ciphertype));
> ++    }
> ++    lenpos = pos;		       /* remember this position */
> ++    pos += 4;			       /* encrypted-blob size */
> ++    pos += 4;			       /* encrypted-payload size */
> ++    if (initial_zero) {
> ++	PUT_32BIT(outblob+pos, 0);
> ++	pos += 4;
> ++    }
> ++    for (i = 0; i < nnumbers; i++)
> ++	pos += sshcom_put_mpint(outblob+pos,
> ++				numbers[i].start, numbers[i].bytes);
> ++    /* Now wrap up the encrypted payload. */
> ++    PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8));
> ++    /* Pad encrypted blob to a multiple of cipher block size. */
> ++    if (passphrase) {
> ++	int padding = -(pos - (lenpos+4)) & 7;
> ++	while (padding--)
> ++	    outblob[pos++] = random_byte();
> ++    }
> ++    ciphertext = (char *)outblob+lenpos+4;
> ++    cipherlen = pos - (lenpos+4);
> + 	dropbear_assert(!passphrase || cipherlen % 8 == 0);
> +-	/* Wrap up the encrypted blob string. */
> +-	PUT_32BIT(outblob+lenpos, cipherlen);
> +-	/* And finally fill in the total length field. */
> +-	PUT_32BIT(outblob+4, pos);
> ++    /* Wrap up the encrypted blob string. */
> ++    PUT_32BIT(outblob+lenpos, cipherlen);
> ++    /* And finally fill in the total length field. */
> ++    PUT_32BIT(outblob+4, pos);
> +
> + 	dropbear_assert(pos < outlen);
> +
> ++    /*
> ++     * Encrypt the key.
> ++     */
> ++    if (passphrase) {
> + 	/*
> +-	 * Encrypt the key.
> ++	 * Derive encryption key from passphrase and iv/salt:
> ++	 *
> ++	 *  - let block A equal MD5(passphrase)
> ++	 *  - let block B equal MD5(passphrase || A)
> ++	 *  - block C would be MD5(passphrase || A || B) and so on
> ++	 *  - encryption key is the first N bytes of A || B
> + 	 */
> +-	if (passphrase) {
> +-		/*
> +-		 * Derive encryption key from passphrase and iv/salt:
> +-		 *
> +-		 *  - let block A equal MD5(passphrase)
> +-		 *  - let block B equal MD5(passphrase || A)
> +-		 *  - block C would be MD5(passphrase || A || B) and so on
> +-		 *  - encryption key is the first N bytes of A || B
> +-		 */
> +-		struct MD5Context md5c;
> +-		unsigned char keybuf[32], iv[8];
> ++	struct MD5Context md5c;
> ++	unsigned char keybuf[32], iv[8];
> +
> +-		MD5Init(&md5c);
> +-		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> +-		MD5Final(keybuf, &md5c);
> ++	MD5Init(&md5c);
> ++	MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> ++	MD5Final(keybuf, &md5c);
> +
> +-		MD5Init(&md5c);
> +-		MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> +-		MD5Update(&md5c, keybuf, 16);
> +-		MD5Final(keybuf+16, &md5c);
> +-
> +-		/*
> +-		 * Now decrypt the key blob.
> +-		 */
> +-		memset(iv, 0, sizeof(iv));
> +-		des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
> +-								 cipherlen);
> +-
> +-		memset(&md5c, 0, sizeof(md5c));
> +-		memset(keybuf, 0, sizeof(keybuf));
> +-	}
> ++	MD5Init(&md5c);
> ++	MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
> ++	MD5Update(&md5c, keybuf, 16);
> ++	MD5Final(keybuf+16, &md5c);
> +
> + 	/*
> +-	 * And save it. We'll use Unix line endings just in case it's
> +-	 * subsequently transferred in binary mode.
> ++	 * Now decrypt the key blob.
> + 	 */
> ++        memset(iv, 0, sizeof(iv));
> ++	des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext,
> ++				 cipherlen);
> ++
> ++        memset(&md5c, 0, sizeof(md5c));
> ++        memset(keybuf, 0, sizeof(keybuf));
> ++    }
> ++
> ++    /*
> ++     * And save it. We'll use Unix line endings just in case it's
> ++     * subsequently transferred in binary mode.
> ++     */
> + 	fp = fopen(filename, "wb");	  /* ensure Unix line endings */
> +-	if (!fp)
> +-		goto error;
> +-	fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
> +-	fprintf(fp, "Comment: \"");
> +-	/*
> +-	 * Comment header is broken with backslash-newline if it goes
> +-	 * over 70 chars. Although it's surrounded by quotes, it
> +-	 * _doesn't_ escape backslashes or quotes within the string.
> +-	 * Don't ask me, I didn't design it.
> +-	 */
> +-	{
> +-		int slen = 60;					   /* starts at 60 due to "Comment: " */
> +-		char *c = key->comment;
> +-		while ((int)strlen(c) > slen) {
> +-			fprintf(fp, "%.*s\\\n", slen, c);
> +-			c += slen;
> +-			slen = 70;					   /* allow 70 chars on subsequent lines */
> +-		}
> +-		fprintf(fp, "%s\"\n", c);
> ++    if (!fp)
> ++	goto error;
> ++    fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
> ++    fprintf(fp, "Comment: \"");
> ++    /*
> ++     * Comment header is broken with backslash-newline if it goes
> ++     * over 70 chars. Although it's surrounded by quotes, it
> ++     * _doesn't_ escape backslashes or quotes within the string.
> ++     * Don't ask me, I didn't design it.
> ++     */
> ++    {
> ++	int slen = 60;		       /* starts at 60 due to "Comment: " */
> ++	char *c = key->comment;
> ++	while ((int)strlen(c) > slen) {
> ++	    fprintf(fp, "%.*s\\\n", slen, c);
> ++	    c += slen;
> ++	    slen = 70;		       /* allow 70 chars on subsequent lines */
> + 	}
> ++	fprintf(fp, "%s\"\n", c);
> ++    }
> + 	base64_encode_fp(fp, outblob, pos, 70);
> +-	fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
> +-	fclose(fp);
> +-	ret = 1;
> ++    fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
> ++    fclose(fp);
> ++    ret = 1;
> +
> +-	error:
> +-	if (outblob) {
> +-		memset(outblob, 0, outlen);
> ++    error:
> ++    if (outblob) {
> ++        memset(outblob, 0, outlen);
> + 		m_free(outblob);
> +-	}
> +-	if (privblob) {
> +-		memset(privblob, 0, privlen);
> ++    }
> ++    if (privblob) {
> ++        memset(privblob, 0, privlen);
> + 		m_free(privblob);
> +-	}
> +-	if (pubblob) {
> +-		memset(pubblob, 0, publen);
> ++    }
> ++    if (pubblob) {
> ++        memset(pubblob, 0, publen);
> + 		m_free(pubblob);
> +-	}
> +-	return ret;
> ++    }
> ++    return ret;
> + }
> + #endif /* ssh.com stuff disabled */
> ++
> ++/* From PuTTY misc.c */
> ++static int toint(unsigned u)
> ++{
> ++    /*
> ++     * Convert an unsigned to an int, without running into the
> ++     * undefined behaviour which happens by the strict C standard if
> ++     * the value overflows. You'd hope that sensible compilers would
> ++     * do the sensible thing in response to a cast, but actually I
> ++     * don't trust modern compilers not to do silly things like
> ++     * assuming that _obviously_ you wouldn't have caused an overflow
> ++     * and so they can elide an 'if (i < 0)' test immediately after
> ++     * the cast.
> ++     *
> ++     * Sensible compilers ought of course to optimise this entire
> ++     * function into 'just return the input value'!
> ++     */
> ++    if (u <= (unsigned)INT_MAX)
> ++        return (int)u;
> ++    else if (u >= (unsigned)INT_MIN)   /* wrap in cast _to_ unsigned is OK */
> ++        return INT_MIN + (int)(u - (unsigned)INT_MIN);
> ++    else
> ++        return INT_MIN; /* fallback; should never occur on binary machines */
> ++}
> +
> diff --git a/meta/recipes-core/dropbear/dropbear/CVE-2016-7408.patch b/meta/recipes-core/dropbear/dropbear/CVE-2016-7408.patch
> new file mode 100644
> index 0000000..995eec5
> --- /dev/null
> +++ b/meta/recipes-core/dropbear/dropbear/CVE-2016-7408.patch
> @@ -0,0 +1,101 @@
> +
> +# HG changeset patch
> +# User Matt Johnston <matt at ucc.asn.au>
> +# Date 1468248038 -28800
> +# Node ID eed9376a4ad68e3ae7f17d154dbf126ee66c54bc
> +# Parent  6a14b1f6dc04e70933c49ea335184e68c1deeb94
> +improve algorithm list parsing
> +
> +Patch is backported from:
> +https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6
> +
> +CVE: CVE-2016-7408
> +Signed-off-by: Sona Sarmadi <sona.sarmadi at enea.com>
> +
> +diff -r 6a14b1f6dc04 -r eed9376a4ad6 common-algo.c
> +--- a/common-algo.c	Mon Jul 11 21:51:25 2016 +0800
> ++++ b/common-algo.c	Mon Jul 11 22:40:38 2016 +0800
> +@@ -531,21 +531,6 @@
> + 	return NULL;
> + }
> +
> +-static void
> +-try_add_algo(const char *algo_name, algo_type *algos,
> +-		const char *algo_desc, algo_type * new_algos, int *num_ret)
> +-{
> +-	algo_type *match_algo = check_algo(algo_name, algos);
> +-	if (!match_algo)
> +-	{
> +-		dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", algo_name, algo_desc);
> +-		return;
> +-	}
> +-
> +-	new_algos[*num_ret] = *match_algo;
> +-	(*num_ret)++;
> +-}
> +-
> + /* Checks a user provided comma-separated algorithm list for available
> +  * options. Any that are not acceptable are removed in-place. Returns the
> +  * number of valid algorithms. */
> +@@ -553,30 +538,43 @@
> + check_user_algos(const char* user_algo_list, algo_type * algos,
> + 		const char *algo_desc)
> + {
> +-	algo_type new_algos[MAX_PROPOSED_ALGO];
> +-	/* this has two passes. first we sweep through the given list of
> +-	 * algorithms and mark them as usable=2 in the algo_type[] array... */
> +-	int num_ret = 0;
> ++	algo_type new_algos[MAX_PROPOSED_ALGO+1];
> + 	char *work_list = m_strdup(user_algo_list);
> +-	char *last_name = work_list;
> ++	char *start = work_list;
> + 	char *c;
> +-	for (c = work_list; *c; c++)
> ++	int n;
> ++	/* So we can iterate and look for null terminator */
> ++	memset(new_algos, 0x0, sizeof(new_algos));
> ++	for (c = work_list, n = 0; ; c++)
> + 	{
> +-		if (*c == ',')
> +-		{
> ++		char oc = *c;
> ++		if (n >= MAX_PROPOSED_ALGO) {
> ++			dropbear_exit("Too many algorithms '%s'", user_algo_list);
> ++		}
> ++		if (*c == ',' || *c == '\0') {
> ++			algo_type *match_algo = NULL;
> + 			*c = '\0';
> +-			try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
> ++			match_algo = check_algo(start, algos);
> ++			if (match_algo) {
> ++				if (check_algo(start, new_algos)) {
> ++					TRACE(("Skip repeated algorithm '%s'", start))
> ++				} else {
> ++					new_algos[n] = *match_algo;
> ++					n++;
> ++				}
> ++			} else {
> ++				dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", start, algo_desc);
> ++			}
> + 			c++;
> +-			last_name = c;
> ++			start = c;
> ++		}
> ++		if (oc == '\0') {
> ++			break;
> + 		}
> + 	}
> +-	try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
> + 	m_free(work_list);
> +-
> +-	new_algos[num_ret].name = NULL;
> +-
> +-	/* Copy one more as a blank delimiter */
> +-	memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1));
> +-	return num_ret;
> ++	/* n+1 to include a null terminator */
> ++	memcpy(algos, new_algos, sizeof(*new_algos) * (n+1));
> ++	return n;
> + }
> + #endif /* ENABLE_USER_ALGO_LIST */
> +
> diff --git a/meta/recipes-core/dropbear/dropbear/CVE-2016-7409.patch b/meta/recipes-core/dropbear/dropbear/CVE-2016-7409.patch
> new file mode 100644
> index 0000000..fc4762d
> --- /dev/null
> +++ b/meta/recipes-core/dropbear/dropbear/CVE-2016-7409.patch
> @@ -0,0 +1,26 @@
> +# HG changeset patch
> +# User Matt Johnston <matt at ucc.asn.au>
> +# Date 1468245085 -28800
> +# Node ID 6a14b1f6dc04e70933c49ea335184e68c1deeb94
> +# Parent  309e1c4a87682b6ca7d80b8555a1db416c3cb7ac
> +better TRACE of failed remote ident
> +
> +Patch is backported from:
> +https://secure.ucc.asn.au/hg/dropbear/rev/6a14b1f6dc04
> +
> +CVE: CVE-2016-7409
> +Signed-off-by: Sona Sarmadi <sona.sarmadi at enea.com>
> +
> +diff -r 309e1c4a8768 -r 6a14b1f6dc04 common-session.c
> +--- a/common-session.c	Fri Mar 18 22:44:36 2016 +0800
> ++++ b/common-session.c	Mon Jul 11 21:51:25 2016 +0800
> +@@ -361,7 +361,7 @@
> + 	}
> +
> + 	if (!done) {
> +-		TRACE(("err: %s for '%s'\n", strerror(errno), linebuf))
> ++		TRACE(("error reading remote ident: %s\n", strerror(errno)))
> + 		ses.remoteclosed();
> + 	} else {
> + 		/* linebuf is already null terminated */
> +
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openembedded.org/pipermail/openembedded-core/attachments/20161025/dc15a81c/attachment-0002.html>


More information about the Openembedded-core mailing list