summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSona Sarmadi <sona.sarmadi@enea.com>2016-11-02 10:52:11 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-11-08 23:03:18 +0000
commitcca372506522c1d588f9ebc66c6051089743d2a9 (patch)
tree0e7dd372f5e364d02129a4d9297f81ffe2888fc8
parent1ae228ee5181f12955356c1fe10d341373dd5fcc (diff)
downloadopenembedded-core-cca372506522c1d588f9ebc66c6051089743d2a9.tar.gz
openembedded-core-cca372506522c1d588f9ebc66c6051089743d2a9.tar.bz2
openembedded-core-cca372506522c1d588f9ebc66c6051089743d2a9.zip
dropbear: fix multiple CVEs
CVE-2016-7406 CVE-2016-7407 CVE-2016-7408 CVE-2016-7409 References: https://matt.ucc.asn.au/dropbear/CHANGES http://seclists.org/oss-sec/2016/q3/504 [YOCTO #10443] Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> Signed-off-by: Armin Kuster <akuster808@gmail.com>
-rw-r--r--meta/recipes-core/dropbear/dropbear.inc4
-rw-r--r--meta/recipes-core/dropbear/dropbear/CVE-2016-7406.patch102
-rw-r--r--meta/recipes-core/dropbear/dropbear/CVE-2016-7407.patch2486
-rw-r--r--meta/recipes-core/dropbear/dropbear/CVE-2016-7408.patch101
-rw-r--r--meta/recipes-core/dropbear/dropbear/CVE-2016-7409.patch27
5 files changed, 2720 insertions, 0 deletions
diff --git a/meta/recipes-core/dropbear/dropbear.inc b/meta/recipes-core/dropbear/dropbear.inc
index 923d31c307..ee2cd98845 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 0000000000..a582d0ff81
--- /dev/null
+++ b/meta/recipes-core/dropbear/dropbear/CVE-2016-7406.patch
@@ -0,0 +1,102 @@
+From 8fd720c3e319da773b48c0b191f049dbd1e3c7f0 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Mon, 11 Jul 2016 23:09:33 +0800
+Subject: [PATCH] Improve exit message formatting
+
+CVE: CVE-2016-7406
+Upstream-Status: Backport [backported from:
+https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb]
+
+Signed-off-by: Sona Sarmadi <sona.sarmadi@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 0000000000..64113c112d
--- /dev/null
+++ b/meta/recipes-core/dropbear/dropbear/CVE-2016-7407.patch
@@ -0,0 +1,2486 @@
+
+# HG changeset patch
+# User Matt Johnston <matt@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@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@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@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@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@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@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@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]
+
+
+CVE: CVE-2016-7407
+Upstream-Status: Backport [backported from:
+https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e]
+
+Signed-off-by: Sona Sarmadi <sona.sarmadi@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(blo