diff options
| author | Sona Sarmadi <sona.sarmadi@enea.com> | 2016-11-02 10:52:11 +0100 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-11-08 23:03:18 +0000 |
| commit | cca372506522c1d588f9ebc66c6051089743d2a9 (patch) | |
| tree | 0e7dd372f5e364d02129a4d9297f81ffe2888fc8 | |
| parent | 1ae228ee5181f12955356c1fe10d341373dd5fcc (diff) | |
| download | openembedded-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.inc | 4 | ||||
| -rw-r--r-- | meta/recipes-core/dropbear/dropbear/CVE-2016-7406.patch | 102 | ||||
| -rw-r--r-- | meta/recipes-core/dropbear/dropbear/CVE-2016-7407.patch | 2486 | ||||
| -rw-r--r-- | meta/recipes-core/dropbear/dropbear/CVE-2016-7408.patch | 101 | ||||
| -rw-r--r-- | meta/recipes-core/dropbear/dropbear/CVE-2016-7409.patch | 27 |
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 |
