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:47:13 +0000 |
| commit | c4061a0a689fd3f4e3fb5d5dd6357dc542973d45 (patch) | |
| tree | 55fa2e594e075f6de399f519211a31e6e7bcf23a /meta | |
| parent | 6962ee368906e096cf2df3031ca5142117e7c52a (diff) | |
| download | poky-c4061a0a689fd3f4e3fb5d5dd6357dc542973d45.tar.gz | |
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]
(From OE-Core rev: cca372506522c1d588f9ebc66c6051089743d2a9)
Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
| -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 \ | |||
| 17 | file://0003-configure.patch \ | 17 | file://0003-configure.patch \ |
| 18 | file://0004-fix-2kb-keys.patch \ | 18 | file://0004-fix-2kb-keys.patch \ |
| 19 | file://0007-dropbear-fix-for-x32-abi.patch \ | 19 | file://0007-dropbear-fix-for-x32-abi.patch \ |
| 20 | file://CVE-2016-7406.patch \ | ||
| 21 | file://CVE-2016-7407.patch \ | ||
| 22 | file://CVE-2016-7408.patch \ | ||
| 23 | file://CVE-2016-7409.patch \ | ||
| 20 | file://init \ | 24 | file://init \ |
| 21 | file://dropbearkey.service \ | 25 | file://dropbearkey.service \ |
| 22 | file://dropbear@.service \ | 26 | 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 @@ | |||
| 1 | From 8fd720c3e319da773b48c0b191f049dbd1e3c7f0 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Matt Johnston <matt@ucc.asn.au> | ||
| 3 | Date: Mon, 11 Jul 2016 23:09:33 +0800 | ||
| 4 | Subject: [PATCH] Improve exit message formatting | ||
| 5 | |||
| 6 | CVE: CVE-2016-7406 | ||
| 7 | Upstream-Status: Backport [backported from: | ||
| 8 | https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb] | ||
| 9 | |||
| 10 | Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> | ||
| 11 | |||
| 12 | diff -ruN a/cli-main.c b/cli-main.c | ||
| 13 | --- a/cli-main.c 2016-03-09 15:54:53.000000000 +0100 | ||
| 14 | +++ b/cli-main.c 2016-10-20 12:49:00.323501119 +0200 | ||
| 15 | @@ -85,29 +85,30 @@ | ||
| 16 | #endif /* DBMULTI stuff */ | ||
| 17 | |||
| 18 | static void cli_dropbear_exit(int exitcode, const char* format, va_list param) { | ||
| 19 | + char exitmsg[150]; | ||
| 20 | + char fullmsg[300]; | ||
| 21 | |||
| 22 | - char fmtbuf[300]; | ||
| 23 | - char exitmsg[500]; | ||
| 24 | + /* Note that exit message must be rendered before session cleanup */ | ||
| 25 | |||
| 26 | + /* Render the formatted exit message */ | ||
| 27 | + vsnprintf(exitmsg, sizeof(exitmsg), format, param); | ||
| 28 | + | ||
| 29 | + /* Add the prefix depending on session/auth state */ | ||
| 30 | if (!sessinitdone) { | ||
| 31 | - snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s", | ||
| 32 | - format); | ||
| 33 | + snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg); | ||
| 34 | } else { | ||
| 35 | - snprintf(fmtbuf, sizeof(fmtbuf), | ||
| 36 | + snprintf(fullmsg, sizeof(fullmsg), | ||
| 37 | "Connection to %s@%s:%s exited: %s", | ||
| 38 | cli_opts.username, cli_opts.remotehost, | ||
| 39 | - cli_opts.remoteport, format); | ||
| 40 | + cli_opts.remoteport, exitmsg); | ||
| 41 | } | ||
| 42 | |||
| 43 | - /* Arguments to the exit printout may be unsafe to use after session_cleanup() */ | ||
| 44 | - vsnprintf(exitmsg, sizeof(exitmsg), fmtbuf, param); | ||
| 45 | - | ||
| 46 | /* Do the cleanup first, since then the terminal will be reset */ | ||
| 47 | session_cleanup(); | ||
| 48 | /* Avoid printing onwards from terminal cruft */ | ||
| 49 | fprintf(stderr, "\n"); | ||
| 50 | |||
| 51 | - dropbear_log(LOG_INFO, "%s", exitmsg);; | ||
| 52 | + dropbear_log(LOG_INFO, "%s", fullmsg); | ||
| 53 | exit(exitcode); | ||
| 54 | } | ||
| 55 | |||
| 56 | diff -ruN a/svr-session.c b/svr-session.c | ||
| 57 | --- a/svr-session.c 2016-03-09 15:54:54.000000000 +0100 | ||
| 58 | +++ b/svr-session.c 2016-10-20 13:27:20.629628336 +0200 | ||
| 59 | @@ -145,30 +145,33 @@ | ||
| 60 | /* failure exit - format must be <= 100 chars */ | ||
| 61 | void svr_dropbear_exit(int exitcode, const char* format, va_list param) { | ||
| 62 | |||
| 63 | - char fmtbuf[300]; | ||
| 64 | + char exitmsg[150]; | ||
| 65 | + char fullmsg[300]; | ||
| 66 | int i; | ||
| 67 | |||
| 68 | + /* Render the formatted exit message */ | ||
| 69 | + vsnprintf(exitmsg, sizeof(exitmsg), format, param); | ||
| 70 | + | ||
| 71 | + /* Add the prefix depending on session/auth state */ | ||
| 72 | if (!sessinitdone) { | ||
| 73 | /* before session init */ | ||
| 74 | - snprintf(fmtbuf, sizeof(fmtbuf), | ||
| 75 | - "Early exit: %s", format); | ||
| 76 | + snprintf(fullmsg, sizeof(fullmsg), "Early exit: %s", exitmsg); | ||
| 77 | } else if (ses.authstate.authdone) { | ||
| 78 | /* user has authenticated */ | ||
| 79 | - snprintf(fmtbuf, sizeof(fmtbuf), | ||
| 80 | + snprintf(fullmsg, sizeof(fullmsg), | ||
| 81 | "Exit (%s): %s", | ||
| 82 | - ses.authstate.pw_name, format); | ||
| 83 | + ses.authstate.pw_name, exitmsg); | ||
| 84 | } else if (ses.authstate.pw_name) { | ||
| 85 | /* we have a potential user */ | ||
| 86 | - snprintf(fmtbuf, sizeof(fmtbuf), | ||
| 87 | + snprintf(fullmsg, sizeof(fullmsg), | ||
| 88 | "Exit before auth (user '%s', %d fails): %s", | ||
| 89 | - ses.authstate.pw_name, ses.authstate.failcount, format); | ||
| 90 | + ses.authstate.pw_name, ses.authstate.failcount, exitmsg); | ||
| 91 | } else { | ||
| 92 | /* before userauth */ | ||
| 93 | - snprintf(fmtbuf, sizeof(fmtbuf), | ||
| 94 | - "Exit before auth: %s", format); | ||
| 95 | + snprintf(fullmsg, sizeof(fullmsg), "Exit before auth: %s", exitmsg); | ||
| 96 | } | ||
| 97 | |||
| 98 | - _dropbear_log(LOG_INFO, fmtbuf, param); | ||
| 99 | + dropbear_log(LOG_INFO, "%s", fullmsg); | ||
| 100 | |||
| 101 | #ifdef USE_VFORK | ||
| 102 | /* 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 @@ | |||
| 1 | |||
| 2 | # HG changeset patch | ||
| 3 | # User Matt Johnston <matt@ucc.asn.au> | ||
| 4 | # Date 1468335601 -28800 | ||
| 5 | # Node ID 34e6127ef02eb52d1f1f9494b9cbfe89bec0e925 | ||
| 6 | # Parent 6914eedb10721db4833c8f005b4acd37f71fb975 | ||
| 7 | merge fixes from PuTTY import.c | ||
| 8 | |||
| 9 | toint() from misc.c | ||
| 10 | |||
| 11 | (revids are from hggit conversion) | ||
| 12 | |||
| 13 | changeset: 4620:60a336a6c85c | ||
| 14 | user: Simon Tatham <anakin@pobox.com> | ||
| 15 | date: Thu Feb 25 20:26:33 2016 +0000 | ||
| 16 | files: import.c | ||
| 17 | description: | ||
| 18 | Fix potential segfaults in reading OpenSSH's ASN.1 key format. | ||
| 19 | |||
| 20 | The length coming back from ber_read_id_len might have overflowed, so | ||
| 21 | treat it as potentially negative. Also, while I'm here, accumulate it | ||
| 22 | inside ber_read_id_len as an unsigned, so as to avoid undefined | ||
| 23 | behaviour on integer overflow, and toint() it before return. | ||
| 24 | |||
| 25 | Thanks to Hanno Böck for spotting this, with the aid of AFL. | ||
| 26 | |||
| 27 | (cherry picked from commit 5b7833cd474a24ec098654dcba8cb9509f3bf2c1) | ||
| 28 | |||
| 29 | Conflicts: | ||
| 30 | import.c | ||
| 31 | |||
| 32 | (cherry-picker's note: resolving the conflict involved removing an | ||
| 33 | entire section of the original commit which fixed ECDSA code not | ||
| 34 | present on this branch) | ||
| 35 | |||
| 36 | |||
| 37 | changeset: 4619:9c6c638d98d8 | ||
| 38 | user: Simon Tatham <anakin@pobox.com> | ||
| 39 | date: Sun Jul 14 10:45:54 2013 +0000 | ||
| 40 | files: import.c ssh.c sshdss.c sshpubk.c sshrsa.c | ||
| 41 | description: | ||
| 42 | Tighten up a lot of casts from unsigned to int which are read by one | ||
| 43 | of the GET_32BIT macros and then used as length fields. Missing bounds | ||
| 44 | checks against zero have been added, and also I've introduced a helper | ||
| 45 | function toint() which casts from unsigned to int in such a way as to | ||
| 46 | avoid C undefined behaviour, since I'm not sure I trust compilers any | ||
| 47 | more to do the obviously sensible thing. | ||
| 48 | |||
| 49 | [originally from svn r9918] | ||
| 50 | |||
| 51 | |||
| 52 | changeset: 4618:3957829f24d3 | ||
| 53 | user: Simon Tatham <anakin@pobox.com> | ||
| 54 | date: Mon Jul 08 22:36:04 2013 +0000 | ||
| 55 | files: import.c sshdss.c sshrsa.c | ||
| 56 | description: | ||
| 57 | Add an assortment of extra safety checks. | ||
| 58 | |||
| 59 | [originally from svn r9896] | ||
| 60 | |||
| 61 | |||
| 62 | changeset: 4617:2cddee0bce12 | ||
| 63 | user: Jacob Nevins <jacobn@chiark.greenend.org.uk> | ||
| 64 | date: Wed Dec 07 00:24:45 2005 +0000 | ||
| 65 | files: import.c | ||
| 66 | description: | ||
| 67 | Institutional failure to memset() things pointed at rather than pointers. | ||
| 68 | Things should now be zeroed and memory not leaked. Spotted by Brant Thomsen. | ||
| 69 | |||
| 70 | [originally from svn r6476] | ||
| 71 | |||
| 72 | |||
| 73 | changeset: 4616:24ac78a9c71d | ||
| 74 | user: Simon Tatham <anakin@pobox.com> | ||
| 75 | date: Wed Feb 11 13:58:27 2004 +0000 | ||
| 76 | files: import.c | ||
| 77 | description: | ||
| 78 | Jacob's last-minute testing found a couple of trivial bugs in | ||
| 79 | import.c, and my attempts to reproduce them in cmdgen found another | ||
| 80 | one there :-) | ||
| 81 | |||
| 82 | [originally from svn r3847] | ||
| 83 | |||
| 84 | |||
| 85 | changeset: 4615:088d39a73db0 | ||
| 86 | user: Simon Tatham <anakin@pobox.com> | ||
| 87 | date: Thu Jan 22 18:52:49 2004 +0000 | ||
| 88 | files: import.c | ||
| 89 | description: | ||
| 90 | Placate some gcc warnings. | ||
| 91 | |||
| 92 | [originally from svn r3761] | ||
| 93 | |||
| 94 | |||
| 95 | changeset: 4614:e4288bad4d93 | ||
| 96 | parent: 1758:108b8924593d | ||
| 97 | user: Simon Tatham <anakin@pobox.com> | ||
| 98 | date: Fri Oct 03 21:21:23 2003 +0000 | ||
| 99 | files: import.c | ||
| 100 | description: | ||
| 101 | My ASN.1 decoder returned wrong IDs for anything above 0x1E! Good | ||
| 102 | job it's never had to yet. Ahem. | ||
| 103 | |||
| 104 | [originally from svn r3479] | ||
| 105 | |||
| 106 | |||
| 107 | CVE: CVE-2016-7407 | ||
| 108 | Upstream-Status: Backport [backported from: | ||
| 109 | https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e] | ||
| 110 | |||
| 111 | Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> | ||
| 112 | |||
| 113 | diff -r 6914eedb1072 -r 34e6127ef02e keyimport.c | ||
| 114 | --- a/keyimport.c Mon Jul 11 23:34:18 2016 +0800 | ||
| 115 | +++ b/keyimport.c Tue Jul 12 23:00:01 2016 +0800 | ||
| 116 | @@ -47,65 +47,67 @@ | ||
| 117 | (cp)[0] = (unsigned char)((value) >> 24); } while (0) | ||
| 118 | |||
| 119 | #define GET_32BIT(cp) \ | ||
| 120 | - (((unsigned long)(unsigned char)(cp)[0] << 24) | \ | ||
| 121 | - ((unsigned long)(unsigned char)(cp)[1] << 16) | \ | ||
| 122 | - ((unsigned long)(unsigned char)(cp)[2] << 8) | \ | ||
| 123 | - ((unsigned long)(unsigned char)(cp)[3])) | ||
| 124 | + (((unsigned long)(unsigned char)(cp)[0] << 24) | \ | ||
| 125 | + ((unsigned long)(unsigned char)(cp)[1] << 16) | \ | ||
| 126 | + ((unsigned long)(unsigned char)(cp)[2] << 8) | \ | ||
| 127 | + ((unsigned long)(unsigned char)(cp)[3])) | ||
| 128 | |||
| 129 | static int openssh_encrypted(const char *filename); | ||
| 130 | static sign_key *openssh_read(const char *filename, char *passphrase); | ||
| 131 | static int openssh_write(const char *filename, sign_key *key, | ||
| 132 | - char *passphrase); | ||
| 133 | + char *passphrase); | ||
| 134 | |||
| 135 | static int dropbear_write(const char*filename, sign_key * key); | ||
| 136 | static sign_key *dropbear_read(const char* filename); | ||
| 137 | |||
| 138 | +static int toint(unsigned u); | ||
| 139 | + | ||
| 140 | #if 0 | ||
| 141 | static int sshcom_encrypted(const char *filename, char **comment); | ||
| 142 | static struct ssh2_userkey *sshcom_read(const char *filename, char *passphrase); | ||
| 143 | static int sshcom_write(const char *filename, struct ssh2_userkey *key, | ||
| 144 | - char *passphrase); | ||
| 145 | + char *passphrase); | ||
| 146 | #endif | ||
| 147 | |||
| 148 | int import_encrypted(const char* filename, int filetype) { | ||
| 149 | |||
| 150 | if (filetype == KEYFILE_OPENSSH) { | ||
| 151 | - return openssh_encrypted(filename); | ||
| 152 | + return openssh_encrypted(filename); | ||
| 153 | #if 0 | ||
| 154 | } else if (filetype == KEYFILE_SSHCOM) { | ||
| 155 | return sshcom_encrypted(filename, NULL); | ||
| 156 | #endif | ||
| 157 | - } | ||
| 158 | - return 0; | ||
| 159 | + } | ||
| 160 | + return 0; | ||
| 161 | } | ||
| 162 | |||
| 163 | sign_key *import_read(const char *filename, char *passphrase, int filetype) { | ||
| 164 | |||
| 165 | if (filetype == KEYFILE_OPENSSH) { | ||
| 166 | - return openssh_read(filename, passphrase); | ||
| 167 | + return openssh_read(filename, passphrase); | ||
| 168 | } else if (filetype == KEYFILE_DROPBEAR) { | ||
| 169 | return dropbear_read(filename); | ||
| 170 | #if 0 | ||
| 171 | } else if (filetype == KEYFILE_SSHCOM) { | ||
| 172 | - return sshcom_read(filename, passphrase); | ||
| 173 | + return sshcom_read(filename, passphrase); | ||
| 174 | #endif | ||
| 175 | } | ||
| 176 | - return NULL; | ||
| 177 | + return NULL; | ||
| 178 | } | ||
| 179 | |||
| 180 | int import_write(const char *filename, sign_key *key, char *passphrase, | ||
| 181 | int filetype) { | ||
| 182 | |||
| 183 | if (filetype == KEYFILE_OPENSSH) { | ||
| 184 | - return openssh_write(filename, key, passphrase); | ||
| 185 | + return openssh_write(filename, key, passphrase); | ||
| 186 | } else if (filetype == KEYFILE_DROPBEAR) { | ||
| 187 | return dropbear_write(filename, key); | ||
| 188 | #if 0 | ||
| 189 | } else if (filetype == KEYFILE_SSHCOM) { | ||
| 190 | - return sshcom_write(filename, key, passphrase); | ||
| 191 | + return sshcom_write(filename, key, passphrase); | ||
| 192 | #endif | ||
| 193 | } | ||
| 194 | - return 0; | ||
| 195 | + return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | static sign_key *dropbear_read(const char* filename) { | ||
| 199 | @@ -183,11 +185,11 @@ | ||
| 200 | * Helper routines. (The base64 ones are defined in sshpubk.c.) | ||
| 201 | */ | ||
| 202 | |||
| 203 | -#define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \ | ||
| 204 | - ((c) >= 'a' && (c) <= 'z') || \ | ||
| 205 | - ((c) >= '0' && (c) <= '9') || \ | ||
| 206 | - (c) == '+' || (c) == '/' || (c) == '=' \ | ||
| 207 | - ) | ||
| 208 | +#define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \ | ||
| 209 | + ((c) >= 'a' && (c) <= 'z') || \ | ||
| 210 | + ((c) >= '0' && (c) <= '9') || \ | ||
| 211 | + (c) == '+' || (c) == '/' || (c) == '=' \ | ||
| 212 | + ) | ||
| 213 | |||
| 214 | /* cpl has to be less than 100 */ | ||
| 215 | static void base64_encode_fp(FILE * fp, unsigned char *data, | ||
| 216 | @@ -220,57 +222,58 @@ | ||
| 217 | */ | ||
| 218 | |||
| 219 | /* ASN.1 tag classes. */ | ||
| 220 | -#define ASN1_CLASS_UNIVERSAL (0 << 6) | ||
| 221 | -#define ASN1_CLASS_APPLICATION (1 << 6) | ||
| 222 | +#define ASN1_CLASS_UNIVERSAL (0 << 6) | ||
| 223 | +#define ASN1_CLASS_APPLICATION (1 << 6) | ||
| 224 | #define ASN1_CLASS_CONTEXT_SPECIFIC (2 << 6) | ||
| 225 | -#define ASN1_CLASS_PRIVATE (3 << 6) | ||
| 226 | -#define ASN1_CLASS_MASK (3 << 6) | ||
| 227 | +#define ASN1_CLASS_PRIVATE (3 << 6) | ||
| 228 | +#define ASN1_CLASS_MASK (3 << 6) | ||
| 229 | |||
| 230 | /* Primitive versus constructed bit. */ | ||
| 231 | -#define ASN1_CONSTRUCTED (1 << 5) | ||
| 232 | +#define ASN1_CONSTRUCTED (1 << 5) | ||
| 233 | |||
| 234 | static int ber_read_id_len(void *source, int sourcelen, | ||
| 235 | - int *id, int *length, int *flags) | ||
| 236 | + int *id, int *length, int *flags) | ||
| 237 | { | ||
| 238 | - unsigned char *p = (unsigned char *) source; | ||
| 239 | + unsigned char *p = (unsigned char *) source; | ||
| 240 | |||
| 241 | - if (sourcelen == 0) | ||
| 242 | + if (sourcelen == 0) | ||
| 243 | + return -1; | ||
| 244 | + | ||
| 245 | + *flags = (*p & 0xE0); | ||
| 246 | + if ((*p & 0x1F) == 0x1F) { | ||
| 247 | + *id = 0; | ||
| 248 | + while (*p & 0x80) { | ||
| 249 | + p++, sourcelen--; | ||
| 250 | + if (sourcelen == 0) | ||
| 251 | return -1; | ||
| 252 | + *id = (*id << 7) | (*p & 0x7F); | ||
| 253 | + } | ||
| 254 | + p++, sourcelen--; | ||
| 255 | + } else { | ||
| 256 | + *id = *p & 0x1F; | ||
| 257 | + p++, sourcelen--; | ||
| 258 | + } | ||
| 259 | |||
| 260 | - *flags = (*p & 0xE0); | ||
| 261 | - if ((*p & 0x1F) == 0x1F) { | ||
| 262 | - *id = 0; | ||
| 263 | - while (*p & 0x80) { | ||
| 264 | - *id = (*id << 7) | (*p & 0x7F); | ||
| 265 | - p++, sourcelen--; | ||
| 266 | - if (sourcelen == 0) | ||
| 267 | - return -1; | ||
| 268 | - } | ||
| 269 | - *id = (*id << 7) | (*p & 0x7F); | ||
| 270 | - p++, sourcelen--; | ||
| 271 | - } else { | ||
| 272 | - *id = *p & 0x1F; | ||
| 273 | - p++, sourcelen--; | ||
| 274 | - } | ||
| 275 | + if (sourcelen == 0) | ||
| 276 | + return -1; | ||
| 277 | |||
| 278 | - if (sourcelen == 0) | ||
| 279 | - return -1; | ||
| 280 | + if (*p & 0x80) { | ||
| 281 | + unsigned len; | ||
| 282 | + int n = *p & 0x7F; | ||
| 283 | + p++, sourcelen--; | ||
| 284 | + if (sourcelen < n) | ||
| 285 | + return -1; | ||
| 286 | + len = 0; | ||
| 287 | + while (n--) | ||
| 288 | + len = (len << 8) | (*p++); | ||
| 289 | + sourcelen -= n; | ||
| 290 | + *length = toint(len); | ||
| 291 | + } else { | ||
| 292 | + *length = *p; | ||
| 293 | + p++, sourcelen--; | ||
| 294 | + } | ||
| 295 | |||
| 296 | - if (*p & 0x80) { | ||
| 297 | - int n = *p & 0x7F; | ||
| 298 | - p++, sourcelen--; | ||
| 299 | - if (sourcelen < n) | ||
| 300 | - return -1; | ||
| 301 | - *length = 0; | ||
| 302 | - while (n--) | ||
| 303 | - *length = (*length << 8) | (*p++); | ||
| 304 | - sourcelen -= n; | ||
| 305 | - } else { | ||
| 306 | - *length = *p; | ||
| 307 | - p++, sourcelen--; | ||
| 308 | - } | ||
| 309 | - | ||
| 310 | - return p - (unsigned char *) source; | ||
| 311 | + return p - (unsigned char *) source; | ||
| 312 | } | ||
| 313 | |||
| 314 | /* | ||
| 315 | @@ -281,57 +284,57 @@ | ||
| 316 | */ | ||
| 317 | static int ber_write_id_len(void *dest, int id, int length, int flags) | ||
| 318 | { | ||
| 319 | - unsigned char *d = (unsigned char *)dest; | ||
| 320 | - int len = 0; | ||
| 321 | + unsigned char *d = (unsigned char *)dest; | ||
| 322 | + int len = 0; | ||
| 323 | |||
| 324 | - if (id <= 30) { | ||
| 325 | - /* | ||
| 326 | - * Identifier is one byte. | ||
| 327 | - */ | ||
| 328 | - len++; | ||
| 329 | - if (d) *d++ = id | flags; | ||
| 330 | - } else { | ||
| 331 | - int n; | ||
| 332 | - /* | ||
| 333 | - * Identifier is multiple bytes: the first byte is 11111 | ||
| 334 | - * plus the flags, and subsequent bytes encode the value of | ||
| 335 | - * the identifier, 7 bits at a time, with the top bit of | ||
| 336 | - * each byte 1 except the last one which is 0. | ||
| 337 | - */ | ||
| 338 | - len++; | ||
| 339 | - if (d) *d++ = 0x1F | flags; | ||
| 340 | - for (n = 1; (id >> (7*n)) > 0; n++) | ||
| 341 | - continue; /* count the bytes */ | ||
| 342 | - while (n--) { | ||
| 343 | - len++; | ||
| 344 | - if (d) *d++ = (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F); | ||
| 345 | - } | ||
| 346 | + if (id <= 30) { | ||
| 347 | + /* | ||
| 348 | + * Identifier is one byte. | ||
| 349 | + */ | ||
| 350 | + len++; | ||
| 351 | + if (d) *d++ = id | flags; | ||
| 352 | + } else { | ||
| 353 | + int n; | ||
| 354 | + /* | ||
| 355 | + * Identifier is multiple bytes: the first byte is 11111 | ||
| 356 | + * plus the flags, and subsequent bytes encode the value of | ||
| 357 | + * the identifier, 7 bits at a time, with the top bit of | ||
| 358 | + * each byte 1 except the last one which is 0. | ||
| 359 | + */ | ||
| 360 | + len++; | ||
| 361 | + if (d) *d++ = 0x1F | flags; | ||
| 362 | + for (n = 1; (id >> (7*n)) > 0; n++) | ||
| 363 | + continue; /* count the bytes */ | ||
| 364 | + while (n--) { | ||
| 365 | + len++; | ||
| 366 | + if (d) *d++ = (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F); | ||
| 367 | } | ||
| 368 | + } | ||
| 369 | |||
| 370 | - if (length < 128) { | ||
| 371 | - /* | ||
| 372 | - * Length is one byte. | ||
| 373 | - */ | ||
| 374 | - len++; | ||
| 375 | - if (d) *d++ = length; | ||
| 376 | - } else { | ||
| 377 | - int n; | ||
| 378 | - /* | ||
| 379 | - * Length is multiple bytes. The first is 0x80 plus the | ||
| 380 | - * number of subsequent bytes, and the subsequent bytes | ||
| 381 | - * encode the actual length. | ||
| 382 | - */ | ||
| 383 | - for (n = 1; (length >> (8*n)) > 0; n++) | ||
| 384 | - continue; /* count the bytes */ | ||
| 385 | - len++; | ||
| 386 | - if (d) *d++ = 0x80 | n; | ||
| 387 | - while (n--) { | ||
| 388 | - len++; | ||
| 389 | - if (d) *d++ = (length >> (8*n)) & 0xFF; | ||
| 390 | - } | ||
| 391 | + if (length < 128) { | ||
| 392 | + /* | ||
| 393 | + * Length is one byte. | ||
| 394 | + */ | ||
| 395 | + len++; | ||
| 396 | + if (d) *d++ = length; | ||
| 397 | + } else { | ||
| 398 | + int n; | ||
| 399 | + /* | ||
| 400 | + * Length is multiple bytes. The first is 0x80 plus the | ||
| 401 | + * number of subsequent bytes, and the subsequent bytes | ||
| 402 | + * encode the actual length. | ||
| 403 | + */ | ||
| 404 | + for (n = 1; (length >> (8*n)) > 0; n++) | ||
| 405 | + continue; /* count the bytes */ | ||
| 406 | + len++; | ||
| 407 | + if (d) *d++ = 0x80 | n; | ||
| 408 | + while (n--) { | ||
| 409 | + len++; | ||
| 410 | + if (d) *d++ = (length >> (8*n)) & 0xFF; | ||
| 411 | } | ||
| 412 | + } | ||
| 413 | |||
| 414 | - return len; | ||
| 415 | + return len; | ||
| 416 | } | ||
| 417 | |||
| 418 | |||
| 419 | @@ -344,99 +347,99 @@ | ||
| 420 | |||
| 421 | enum { OSSH_DSA, OSSH_RSA, OSSH_EC }; | ||
| 422 | struct openssh_key { | ||
| 423 | - int type; | ||
| 424 | - int encrypted; | ||
| 425 | - char iv[32]; | ||
| 426 | - unsigned char *keyblob; | ||
| 427 | + int type; | ||
| 428 | + int encrypted; | ||
| 429 | + char iv[32]; | ||
| 430 | + unsigned char *keyblob; | ||
| 431 | unsigned int keyblob_len, keyblob_size; | ||
| 432 | }; | ||
| 433 | |||
| 434 | static struct openssh_key *load_openssh_key(const char *filename) | ||
| 435 | { | ||
| 436 | - struct openssh_key *ret; | ||
| 437 | + struct openssh_key *ret; | ||
| 438 | FILE *fp = NULL; | ||
| 439 | - char buffer[256]; | ||
| 440 | + char buffer[256]; | ||
| 441 | char *errmsg = NULL, *p = NULL; | ||
| 442 | - int headers_done; | ||
| 443 | + int headers_done; | ||
| 444 | unsigned long len, outlen; | ||
| 445 | |||
| 446 | ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key)); | ||
| 447 | - ret->keyblob = NULL; | ||
| 448 | - ret->keyblob_len = ret->keyblob_size = 0; | ||
| 449 | - ret->encrypted = 0; | ||
| 450 | - memset(ret->iv, 0, sizeof(ret->iv)); | ||
| 451 | + ret->keyblob = NULL; | ||
| 452 | + ret->keyblob_len = ret->keyblob_size = 0; | ||
| 453 | + ret->encrypted = 0; | ||
| 454 | + memset(ret->iv, 0, sizeof(ret->iv)); | ||
| 455 | |||
| 456 | if (strlen(filename) == 1 && filename[0] == '-') { | ||
| 457 | fp = stdin; | ||
| 458 | } else { | ||
| 459 | fp = fopen(filename, "r"); | ||
| 460 | } | ||
| 461 | - if (!fp) { | ||
| 462 | - errmsg = "Unable to open key file"; | ||
| 463 | - goto error; | ||
| 464 | - } | ||
| 465 | - if (!fgets(buffer, sizeof(buffer), fp) || | ||
| 466 | - 0 != strncmp(buffer, "-----BEGIN ", 11) || | ||
| 467 | - 0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) { | ||
| 468 | - errmsg = "File does not begin with OpenSSH key header"; | ||
| 469 | - goto error; | ||
| 470 | - } | ||
| 471 | - if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n")) | ||
| 472 | - ret->type = OSSH_RSA; | ||
| 473 | - else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n")) | ||
| 474 | - ret->type = OSSH_DSA; | ||
| 475 | + if (!fp) { | ||
| 476 | + errmsg = "Unable to open key file"; | ||
| 477 | + goto error; | ||
| 478 | + } | ||
| 479 | + if (!fgets(buffer, sizeof(buffer), fp) || | ||
| 480 | + 0 != strncmp(buffer, "-----BEGIN ", 11) || | ||
| 481 | + 0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) { | ||
| 482 | + errmsg = "File does not begin with OpenSSH key header"; | ||
| 483 | + goto error; | ||
| 484 | + } | ||
| 485 | + if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n")) | ||
| 486 | + ret->type = OSSH_RSA; | ||
| 487 | + else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n")) | ||
| 488 | + ret->type = OSSH_DSA; | ||
| 489 | else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n")) | ||
| 490 | ret->type = OSSH_EC; | ||
| 491 | - else { | ||
| 492 | - errmsg = "Unrecognised key type"; | ||
| 493 | + else { | ||
| 494 | + errmsg = "Unrecognised key type"; | ||
| 495 | + goto error; | ||
| 496 | + } | ||
| 497 | + | ||
| 498 | + headers_done = 0; | ||
| 499 | + while (1) { | ||
| 500 | + if (!fgets(buffer, sizeof(buffer), fp)) { | ||
| 501 | + errmsg = "Unexpected end of file"; | ||
| 502 | + goto error; | ||
| 503 | + } | ||
| 504 | + if (0 == strncmp(buffer, "-----END ", 9) && | ||
| 505 | + 0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) | ||
| 506 | + break; /* done */ | ||
| 507 | + if ((p = strchr(buffer, ':')) != NULL) { | ||
| 508 | + if (headers_done) { | ||
| 509 | + errmsg = "Header found in body of key data"; | ||
| 510 | goto error; | ||
| 511 | - } | ||
| 512 | + } | ||
| 513 | + *p++ = '\0'; | ||
| 514 | + while (*p && isspace((unsigned char)*p)) p++; | ||
| 515 | + if (!strcmp(buffer, "Proc-Type")) { | ||
| 516 | + if (p[0] != '4' || p[1] != ',') { | ||
| 517 | + errmsg = "Proc-Type is not 4 (only 4 is supported)"; | ||
| 518 | + goto error; | ||
| 519 | + } | ||
| 520 | + p += 2; | ||
| 521 | + if (!strcmp(p, "ENCRYPTED\n")) | ||
| 522 | + ret->encrypted = 1; | ||
| 523 | + } else if (!strcmp(buffer, "DEK-Info")) { | ||
| 524 | + int i, j; | ||
| 525 | |||
| 526 | - headers_done = 0; | ||
| 527 | - while (1) { | ||
| 528 | - if (!fgets(buffer, sizeof(buffer), fp)) { | ||
| 529 | - errmsg = "Unexpected end of file"; | ||
| 530 | - goto error; | ||
| 531 | + if (strncmp(p, "DES-EDE3-CBC,", 13)) { | ||
| 532 | + errmsg = "Ciphers other than DES-EDE3-CBC not supported"; | ||
| 533 | + goto error; | ||
| 534 | } | ||
| 535 | - if (0 == strncmp(buffer, "-----END ", 9) && | ||
| 536 | - 0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) | ||
| 537 | - break; /* done */ | ||
| 538 | - if ((p = strchr(buffer, ':')) != NULL) { | ||
| 539 | - if (headers_done) { | ||
| 540 | - errmsg = "Header found in body of key data"; | ||
| 541 | - goto error; | ||
| 542 | - } | ||
| 543 | - *p++ = '\0'; | ||
| 544 | - while (*p && isspace((unsigned char)*p)) p++; | ||
| 545 | - if (!strcmp(buffer, "Proc-Type")) { | ||
| 546 | - if (p[0] != '4' || p[1] != ',') { | ||
| 547 | - errmsg = "Proc-Type is not 4 (only 4 is supported)"; | ||
| 548 | - goto error; | ||
| 549 | - } | ||
| 550 | - p += 2; | ||
| 551 | - if (!strcmp(p, "ENCRYPTED\n")) | ||
| 552 | - ret->encrypted = 1; | ||
| 553 | - } else if (!strcmp(buffer, "DEK-Info")) { | ||
| 554 | - int i, j; | ||
| 555 | - | ||
| 556 | - if (strncmp(p, "DES-EDE3-CBC,", 13)) { | ||
| 557 | - errmsg = "Ciphers other than DES-EDE3-CBC not supported"; | ||
| 558 | - goto error; | ||
| 559 | - } | ||
| 560 | - p += 13; | ||
| 561 | - for (i = 0; i < 8; i++) { | ||
| 562 | - if (1 != sscanf(p, "%2x", &j)) | ||
| 563 | - break; | ||
| 564 | - ret->iv[i] = j; | ||
| 565 | - p += 2; | ||
| 566 | - } | ||
| 567 | - if (i < 8) { | ||
| 568 | - errmsg = "Expected 16-digit iv in DEK-Info"; | ||
| 569 | - goto error; | ||
| 570 | - } | ||
| 571 | - } | ||
| 572 | - } else { | ||
| 573 | - headers_done = 1; | ||
| 574 | + p += 13; | ||
| 575 | + for (i = 0; i < 8; i++) { | ||
| 576 | + if (1 != sscanf(p, "%2x", &j)) | ||
| 577 | + break; | ||
| 578 | + ret->iv[i] = j; | ||
| 579 | + p += 2; | ||
| 580 | + } | ||
| 581 | + if (i < 8) { | ||
| 582 | + errmsg = "Expected 16-digit iv in DEK-Info"; | ||
| 583 | + goto error; | ||
| 584 | + } | ||
| 585 | + } | ||
| 586 | + } else { | ||
| 587 | + headers_done = 1; | ||
| 588 | len = strlen(buffer); | ||
| 589 | outlen = len*4/3; | ||
| 590 | if (ret->keyblob_len + outlen > ret->keyblob_size) { | ||
| 591 | @@ -448,65 +451,65 @@ | ||
| 592 | if (base64_decode((const unsigned char *)buffer, len, | ||
| 593 | ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){ | ||
| 594 | errmsg = "Error decoding base64"; | ||
| 595 | - goto error; | ||
| 596 | - } | ||
| 597 | + goto error; | ||
| 598 | + } | ||
| 599 | ret->keyblob_len += outlen; | ||
| 600 | - } | ||
| 601 | + } | ||
| 602 | } | ||
| 603 | |||
| 604 | - if (ret->keyblob_len == 0 || !ret->keyblob) { | ||
| 605 | - errmsg = "Key body not present"; | ||
| 606 | - goto error; | ||
| 607 | - } | ||
| 608 | + if (ret->keyblob_len == 0 || !ret->keyblob) { | ||
| 609 | + errmsg = "Key body not present"; | ||
| 610 | + goto error; | ||
| 611 | + } | ||
| 612 | |||
| 613 | - if (ret->encrypted && ret->keyblob_len % 8 != 0) { | ||
| 614 | - errmsg = "Encrypted key blob is not a multiple of cipher block size"; | ||
| 615 | - goto error; | ||
| 616 | - } | ||
| 617 | + if (ret->encrypted && ret->keyblob_len % 8 != 0) { | ||
| 618 | + errmsg = "Encrypted key blob is not a multiple of cipher block size"; | ||
| 619 | + goto error; | ||
| 620 | + } | ||
| 621 | |||
| 622 | m_burn(buffer, sizeof(buffer)); | ||
| 623 | - return ret; | ||
| 624 | + return ret; | ||
| 625 | |||
| 626 | - error: | ||
| 627 | + error: | ||
| 628 | m_burn(buffer, sizeof(buffer)); | ||
| 629 | - if (ret) { | ||
| 630 | - if (ret->keyblob) { | ||
| 631 | + if (ret) { | ||
| 632 | + if (ret->keyblob) { | ||
| 633 | m_burn(ret->keyblob, ret->keyblob_size); | ||
| 634 | m_free(ret->keyblob); | ||
| 635 | - } | ||
| 636 | + } | ||
| 637 | m_free(ret); | ||
| 638 | } | ||
| 639 | if (fp) { | ||
| 640 | fclose(fp); | ||
| 641 | - } | ||
| 642 | + } | ||
| 643 | if (errmsg) { | ||
| 644 | fprintf(stderr, "Error: %s\n", errmsg); | ||
| 645 | } | ||
| 646 | - return NULL; | ||
| 647 | + return NULL; | ||
| 648 | } | ||
| 649 | |||
| 650 | static int openssh_encrypted(const char *filename) | ||
| 651 | { | ||
| 652 | - struct openssh_key *key = load_openssh_key(filename); | ||
| 653 | - int ret; | ||
| 654 | + struct openssh_key *key = load_openssh_key(filename); | ||
| 655 | + int ret; | ||
| 656 | |||
| 657 | - if (!key) | ||
| 658 | - return 0; | ||
| 659 | - ret = key->encrypted; | ||
| 660 | + if (!key) | ||
| 661 | + return 0; | ||
| 662 | + ret = key->encrypted; | ||
| 663 | m_burn(key->keyblob, key->keyblob_size); | ||
| 664 | m_free(key->keyblob); | ||
| 665 | m_free(key); | ||
| 666 | - return ret; | ||
| 667 | + return ret; | ||
| 668 | } | ||
| 669 | |||
| 670 | static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase)) | ||
| 671 | { | ||
| 672 | struct openssh_key *key; | ||
| 673 | - unsigned char *p; | ||
| 674 | - int ret, id, len, flags; | ||
| 675 | + unsigned char *p; | ||
| 676 | + int ret, id, len, flags; | ||
| 677 | int i, num_integers = 0; | ||
| 678 | sign_key *retval = NULL; | ||
| 679 | - char *errmsg; | ||
| 680 | + char *errmsg; | ||
| 681 | unsigned char *modptr = NULL; | ||
| 682 | int modlen = -9999; | ||
| 683 | enum signkey_type type; | ||
| 684 | @@ -518,86 +521,87 @@ | ||
| 685 | |||
| 686 | key = load_openssh_key(filename); | ||
| 687 | |||
| 688 | - if (!key) | ||
| 689 | - return NULL; | ||
| 690 | + if (!key) | ||
| 691 | + return NULL; | ||
| 692 | |||
| 693 | - if (key->encrypted) { | ||
| 694 | + if (key->encrypted) { | ||
| 695 | errmsg = "encrypted keys not supported currently"; | ||
| 696 | goto error; | ||
| 697 | #if 0 | ||
| 698 | /* matt TODO */ | ||
| 699 | - /* | ||
| 700 | - * Derive encryption key from passphrase and iv/salt: | ||
| 701 | - * | ||
| 702 | - * - let block A equal MD5(passphrase || iv) | ||
| 703 | - * - let block B equal MD5(A || passphrase || iv) | ||
| 704 | - * - block C would be MD5(B || passphrase || iv) and so on | ||
| 705 | - * - encryption key is the first N bytes of A || B | ||
| 706 | - */ | ||
| 707 | - struct MD5Context md5c; | ||
| 708 | - unsigned char keybuf[32]; | ||
| 709 | + /* | ||
| 710 | + * Derive encryption key from passphrase and iv/salt: | ||
| 711 | + * | ||
| 712 | + * - let block A equal MD5(passphrase || iv) | ||
| 713 | + * - let block B equal MD5(A || passphrase || iv) | ||
| 714 | + * - block C would be MD5(B || passphrase || iv) and so on | ||
| 715 | + * - encryption key is the first N bytes of A || B | ||
| 716 | + */ | ||
| 717 | + struct MD5Context md5c; | ||
| 718 | + unsigned char keybuf[32]; | ||
| 719 | |||
| 720 | - MD5Init(&md5c); | ||
| 721 | - MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 722 | - MD5Update(&md5c, (unsigned char *)key->iv, 8); | ||
| 723 | - MD5Final(keybuf, &md5c); | ||
| 724 | + MD5Init(&md5c); | ||
| 725 | + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 726 | + MD5Update(&md5c, (unsigned char *)key->iv, 8); | ||
| 727 | + MD5Final(keybuf, &md5c); | ||
| 728 | |||
| 729 | - MD5Init(&md5c); | ||
| 730 | - MD5Update(&md5c, keybuf, 16); | ||
| 731 | - MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 732 | - MD5Update(&md5c, (unsigned char *)key->iv, 8); | ||
| 733 | - MD5Final(keybuf+16, &md5c); | ||
| 734 | - | ||
| 735 | - /* | ||
| 736 | - * Now decrypt the key blob. | ||
| 737 | - */ | ||
| 738 | - des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv, | ||
| 739 | - key->keyblob, key->keyblob_len); | ||
| 740 | - | ||
| 741 | - memset(&md5c, 0, sizeof(md5c)); | ||
| 742 | - memset(keybuf, 0, sizeof(keybuf)); | ||
| 743 | -#endif | ||
| 744 | - } | ||
| 745 | + MD5Init(&md5c); | ||
| 746 | + MD5Update(&md5c, keybuf, 16); | ||
| 747 | + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 748 | + MD5Update(&md5c, (unsigned char *)key->iv, 8); | ||
| 749 | + MD5Final(keybuf+16, &md5c); | ||
| 750 | |||
| 751 | /* | ||
| 752 | - * Now we have a decrypted key blob, which contains an ASN.1 | ||
| 753 | - * encoded private key. We must now untangle the ASN.1. | ||
| 754 | - * | ||
| 755 | - * We expect the whole key blob to be formatted as a SEQUENCE | ||
| 756 | - * (0x30 followed by a length code indicating that the rest of | ||
| 757 | - * the blob is part of the sequence). Within that SEQUENCE we | ||
| 758 | - * expect to see a bunch of INTEGERs. What those integers mean | ||
| 759 | - * depends on the key type: | ||
| 760 | - * | ||
| 761 | - * - For RSA, we expect the integers to be 0, n, e, d, p, q, | ||
| 762 | - * dmp1, dmq1, iqmp in that order. (The last three are d mod | ||
| 763 | - * (p-1), d mod (q-1), inverse of q mod p respectively.) | ||
| 764 | - * | ||
| 765 | - * - For DSA, we expect them to be 0, p, q, g, y, x in that | ||
| 766 | - * order. | ||
| 767 | + * Now decrypt the key blob. | ||
| 768 | */ | ||
| 769 | - | ||
| 770 | - p = key->keyblob; | ||
| 771 | + des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv, | ||
| 772 | + key->keyblob, key->keyblob_len); | ||
| 773 | |||
| 774 | - /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */ | ||
| 775 | - ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags); | ||
| 776 | - p += ret; | ||
| 777 | - if (ret < 0 || id != 16) { | ||
| 778 | + memset(&md5c, 0, sizeof(md5c)); | ||
| 779 | + memset(keybuf, 0, sizeof(keybuf)); | ||
| 780 | +#endif | ||
| 781 | + } | ||
| 782 | + | ||
| 783 | + /* | ||
| 784 | + * Now we have a decrypted key blob, which contains an ASN.1 | ||
| 785 | + * encoded private key. We must now untangle the ASN.1. | ||
| 786 | + * | ||
| 787 | + * We expect the whole key blob to be formatted as a SEQUENCE | ||
| 788 | + * (0x30 followed by a length code indicating that the rest of | ||
| 789 | + * the blob is part of the sequence). Within that SEQUENCE we | ||
| 790 | + * expect to see a bunch of INTEGERs. What those integers mean | ||
| 791 | + * depends on the key type: | ||
| 792 | + * | ||
| 793 | + * - For RSA, we expect the integers to be 0, n, e, d, p, q, | ||
| 794 | + * dmp1, dmq1, iqmp in that order. (The last three are d mod | ||
| 795 | + * (p-1), d mod (q-1), inverse of q mod p respectively.) | ||
| 796 | + * | ||
| 797 | + * - For DSA, we expect them to be 0, p, q, g, y, x in that | ||
| 798 | + * order. | ||
| 799 | + */ | ||
| 800 | + | ||
| 801 | + p = key->keyblob; | ||
| 802 | + | ||
| 803 | + /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */ | ||
| 804 | + ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags); | ||
| 805 | + p += ret; | ||
| 806 | + if (ret < 0 || id != 16 || len < 0 || | ||
| 807 | + key->keyblob+key->keyblob_len-p < len) { | ||
| 808 | errmsg = "ASN.1 decoding failure - wrong password?"; | ||
| 809 | - goto error; | ||
| 810 | - } | ||
| 811 | + goto error; | ||
| 812 | + } | ||
| 813 | |||
| 814 | - /* Expect a load of INTEGERs. */ | ||
| 815 | - if (key->type == OSSH_RSA) | ||
| 816 | - num_integers = 9; | ||
| 817 | - else if (key->type == OSSH_DSA) | ||
| 818 | - num_integers = 6; | ||
| 819 | + /* Expect a load of INTEGERs. */ | ||
| 820 | + if (key->type == OSSH_RSA) | ||
| 821 | + num_integers = 9; | ||
| 822 | + else if (key->type == OSSH_DSA) | ||
| 823 | + num_integers = 6; | ||
| 824 | else if (key->type == OSSH_EC) | ||
| 825 | num_integers = 1; | ||
| 826 | |||
| 827 | - /* | ||
| 828 | - * Space to create key blob in. | ||
| 829 | - */ | ||
| 830 | + /* | ||
| 831 | + * Space to create key blob in. | ||
| 832 | + */ | ||
| 833 | blobbuf = buf_new(3000); | ||
| 834 | |||
| 835 | #ifdef DROPBEAR_DSS | ||
| 836 | @@ -613,17 +617,17 @@ | ||
| 837 | } | ||
| 838 | #endif | ||
| 839 | |||
| 840 | - for (i = 0; i < num_integers; i++) { | ||
| 841 | - ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, | ||
| 842 | - &id, &len, &flags); | ||
| 843 | - p += ret; | ||
| 844 | - if (ret < 0 || id != 2 || | ||
| 845 | - key->keyblob+key->keyblob_len-p < len) { | ||
| 846 | - errmsg = "ASN.1 decoding failure"; | ||
| 847 | - goto error; | ||
| 848 | - } | ||
| 849 | + for (i = 0; i < num_integers; i++) { | ||
| 850 | + ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, | ||
| 851 | + &id, &len, &flags); | ||
| 852 | + p += ret; | ||
| 853 | + if (ret < 0 || id != 2 || len < 0 || | ||
| 854 | + key->keyblob+key->keyblob_len-p < len) { | ||
| 855 | + errmsg = "ASN.1 decoding failure"; | ||
| 856 | + goto error; | ||
| 857 | + } | ||
| 858 | |||
| 859 | - if (i == 0) { | ||
| 860 | + if (i == 0) { | ||
| 861 | /* First integer is a version indicator */ | ||
| 862 | int expected = -1; | ||
| 863 | switch (key->type) { | ||
| 864 | @@ -636,35 +640,35 @@ | ||
| 865 | break; | ||
| 866 | } | ||
| 867 | if (len != 1 || p[0] != expected) { | ||
| 868 | - errmsg = "Version number mismatch"; | ||
| 869 | - goto error; | ||
| 870 | - } | ||
| 871 | - } else if (key->type == OSSH_RSA) { | ||
| 872 | - /* | ||
| 873 | + errmsg = "Version number mismatch"; | ||
| 874 | + goto error; | ||
| 875 | + } | ||
| 876 | + } else if (key->type == OSSH_RSA) { | ||
| 877 | + /* | ||
| 878 | * OpenSSH key order is n, e, d, p, q, dmp1, dmq1, iqmp | ||
| 879 | * but we want e, n, d, p, q | ||
| 880 | - */ | ||
| 881 | - if (i == 1) { | ||
| 882 | - /* Save the details for after we deal with number 2. */ | ||
| 883 | + */ | ||
| 884 | + if (i == 1) { | ||
| 885 | + /* Save the details for after we deal with number 2. */ | ||
| 886 | modptr = p; | ||
| 887 | - modlen = len; | ||
| 888 | + modlen = len; | ||
| 889 | } else if (i >= 2 && i <= 5) { | ||
| 890 | buf_putstring(blobbuf, (const char*)p, len); | ||
| 891 | - if (i == 2) { | ||
| 892 | + if (i == 2) { | ||
| 893 | buf_putstring(blobbuf, (const char*)modptr, modlen); | ||
| 894 | - } | ||
| 895 | - } | ||
| 896 | - } else if (key->type == OSSH_DSA) { | ||
| 897 | - /* | ||
| 898 | + } | ||
| 899 | + } | ||
| 900 | + } else if (key->type == OSSH_DSA) { | ||
| 901 | + /* | ||
| 902 | * OpenSSH key order is p, q, g, y, x, | ||
| 903 | * we want the same. | ||
| 904 | - */ | ||
| 905 | + */ | ||
| 906 | buf_putstring(blobbuf, (const char*)p, len); | ||
| 907 | - } | ||
| 908 | + } | ||
| 909 | |||
| 910 | - /* Skip past the number. */ | ||
| 911 | - p += len; | ||
| 912 | - } | ||
| 913 | + /* Skip past the number. */ | ||
| 914 | + p += len; | ||
| 915 | + } | ||
| 916 | |||
| 917 | #ifdef DROPBEAR_ECDSA | ||
| 918 | if (key->type == OSSH_EC) { | ||
| 919 | @@ -780,12 +784,12 @@ | ||
| 920 | } | ||
| 921 | #endif /* DROPBEAR_ECDSA */ | ||
| 922 | |||
| 923 | - /* | ||
| 924 | - * Now put together the actual key. Simplest way to do this is | ||
| 925 | - * to assemble our own key blobs and feed them to the createkey | ||
| 926 | - * functions; this is a bit faffy but it does mean we get all | ||
| 927 | - * the sanity checks for free. | ||
| 928 | - */ | ||
| 929 | + /* | ||
| 930 | + * Now put together the actual key. Simplest way to do this is | ||
| 931 | + * to assemble our own key blobs and feed them to the createkey | ||
| 932 | + * functions; this is a bit faffy but it does mean we get all | ||
| 933 | + * the sanity checks for free. | ||
| 934 | + */ | ||
| 935 | if (key->type == OSSH_RSA || key->type == OSSH_DSA) { | ||
| 936 | buf_setpos(blobbuf, 0); | ||
| 937 | type = DROPBEAR_SIGNKEY_ANY; | ||
| 938 | @@ -794,18 +798,18 @@ | ||
| 939 | errmsg = "unable to create key structure"; | ||
| 940 | sign_key_free(retkey); | ||
| 941 | retkey = NULL; | ||
| 942 | - goto error; | ||
| 943 | - } | ||
| 944 | + goto error; | ||
| 945 | + } | ||
| 946 | } | ||
| 947 | |||
| 948 | - errmsg = NULL; /* no error */ | ||
| 949 | - retval = retkey; | ||
| 950 | + errmsg = NULL; /* no error */ | ||
| 951 | + retval = retkey; | ||
| 952 | |||
| 953 | - error: | ||
| 954 | + error: | ||
| 955 | if (blobbuf) { | ||
| 956 | buf_burn(blobbuf); | ||
| 957 | buf_free(blobbuf); | ||
| 958 | - } | ||
| 959 | + } | ||
| 960 | m_burn(key->keyblob, key->keyblob_size); | ||
| 961 | m_free(key->keyblob); | ||
| 962 | m_burn(key, sizeof(*key)); | ||
| 963 | @@ -813,22 +817,22 @@ | ||
| 964 | if (errmsg) { | ||
| 965 | fprintf(stderr, "Error: %s\n", errmsg); | ||
| 966 | } | ||
| 967 | - return retval; | ||
| 968 | + return retval; | ||
| 969 | } | ||
| 970 | |||
| 971 | static int openssh_write(const char *filename, sign_key *key, | ||
| 972 | - char *passphrase) | ||
| 973 | + char *passphrase) | ||
| 974 | { | ||
| 975 | buffer * keyblob = NULL; | ||
| 976 | buffer * extrablob = NULL; /* used for calculated values to write */ | ||
| 977 | unsigned char *outblob = NULL; | ||
| 978 | int outlen = -9999; | ||
| 979 | - struct mpint_pos numbers[9]; | ||
| 980 | + struct mpint_pos numbers[9]; | ||
| 981 | int nnumbers = -1, pos = 0, len = 0, seqlen, i; | ||
| 982 | char *header = NULL, *footer = NULL; | ||
| 983 | - char zero[1]; | ||
| 984 | - int ret = 0; | ||
| 985 | - FILE *fp; | ||
| 986 | + char zero[1]; | ||
| 987 | + int ret = 0; | ||
| 988 | + FILE *fp; | ||
| 989 | |||
| 990 | #ifdef DROPBEAR_RSA | ||
| 991 | mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */ | ||
| 992 | @@ -843,9 +847,9 @@ | ||
| 993 | #endif | ||
| 994 | 0) | ||
| 995 | { | ||
| 996 | - /* | ||
| 997 | - * Fetch the key blobs. | ||
| 998 | - */ | ||
| 999 | + /* | ||
| 1000 | + * Fetch the key blobs. | ||
| 1001 | + */ | ||
| 1002 | keyblob = buf_new(3000); | ||
| 1003 | buf_put_priv_key(keyblob, key, key->type); | ||
| 1004 | |||
| 1005 | @@ -853,10 +857,10 @@ | ||
| 1006 | /* skip the "ssh-rsa" or "ssh-dss" header */ | ||
| 1007 | buf_incrpos(keyblob, buf_getint(keyblob)); | ||
| 1008 | |||
| 1009 | - /* | ||
| 1010 | - * Find the sequence of integers to be encoded into the OpenSSH | ||
| 1011 | - * key blob, and also decide on the header line. | ||
| 1012 | - */ | ||
| 1013 | + /* | ||
| 1014 | + * Find the sequence of integers to be encoded into the OpenSSH | ||
| 1015 | + * key blob, and also decide on the header line. | ||
| 1016 | + */ | ||
| 1017 | numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0'; | ||
| 1018 | |||
| 1019 | #ifdef DROPBEAR_RSA | ||
| 1020 | @@ -871,17 +875,17 @@ | ||
| 1021 | numbers[2].bytes = buf_getint(keyblob); | ||
| 1022 | numbers[2].start = buf_getptr(keyblob, numbers[2].bytes); | ||
| 1023 | buf_incrpos(keyblob, numbers[2].bytes); | ||
| 1024 | - | ||
| 1025 | + | ||
| 1026 | /* n */ | ||
| 1027 | numbers[1].bytes = buf_getint(keyblob); | ||
| 1028 | numbers[1].start = buf_getptr(keyblob, numbers[1].bytes); | ||
| 1029 | buf_incrpos(keyblob, numbers[1].bytes); | ||
| 1030 | - | ||
| 1031 | + | ||
| 1032 | /* d */ | ||
| 1033 | numbers[3].bytes = buf_getint(keyblob); | ||
| 1034 | numbers[3].start = buf_getptr(keyblob, numbers[3].bytes); | ||
| 1035 | buf_incrpos(keyblob, numbers[3].bytes); | ||
| 1036 | - | ||
| 1037 | + | ||
| 1038 | /* p */ | ||
| 1039 | numbers[4].bytes = buf_getint(keyblob); | ||
| 1040 | numbers[4].start = buf_getptr(keyblob, numbers[4].bytes); | ||
| 1041 | @@ -949,9 +953,9 @@ | ||
| 1042 | numbers[8].start = buf_getptr(extrablob, numbers[8].bytes); | ||
| 1043 | buf_incrpos(extrablob, numbers[8].bytes); | ||
| 1044 | |||
| 1045 | - nnumbers = 9; | ||
| 1046 | - header = "-----BEGIN RSA PRIVATE KEY-----\n"; | ||
| 1047 | - footer = "-----END RSA PRIVATE KEY-----\n"; | ||
| 1048 | + nnumbers = 9; | ||
| 1049 | + header = "-----BEGIN RSA PRIVATE KEY-----\n"; | ||
| 1050 | + footer = "-----END RSA PRIVATE KEY-----\n"; | ||
| 1051 | } | ||
| 1052 | #endif /* DROPBEAR_RSA */ | ||
| 1053 | |||
| 1054 | @@ -983,45 +987,45 @@ | ||
| 1055 | numbers[5].start = buf_getptr(keyblob, numbers[5].bytes); | ||
| 1056 | buf_incrpos(keyblob, numbers[5].bytes); | ||
| 1057 | |||
| 1058 | - nnumbers = 6; | ||
| 1059 | - header = "-----BEGIN DSA PRIVATE KEY-----\n"; | ||
| 1060 | - footer = "-----END DSA PRIVATE KEY-----\n"; | ||
| 1061 | - } | ||
| 1062 | + nnumbers = 6; | ||
| 1063 | + header = "-----BEGIN DSA PRIVATE KEY-----\n"; | ||
| 1064 | + footer = "-----END DSA PRIVATE KEY-----\n"; | ||
| 1065 | + } | ||
| 1066 | #endif /* DROPBEAR_DSS */ | ||
| 1067 | |||
| 1068 | - /* | ||
| 1069 | - * Now count up the total size of the ASN.1 encoded integers, | ||
| 1070 | - * so as to determine the length of the containing SEQUENCE. | ||
| 1071 | - */ | ||
| 1072 | - len = 0; | ||
| 1073 | - for (i = 0; i < nnumbers; i++) { | ||
| 1074 | - len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0); | ||
| 1075 | - len += numbers[i].bytes; | ||
| 1076 | - } | ||
| 1077 | - seqlen = len; | ||
| 1078 | - /* Now add on the SEQUENCE header. */ | ||
| 1079 | - len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED); | ||
| 1080 | - /* Round up to the cipher block size, ensuring we have at least one | ||
| 1081 | - * byte of padding (see below). */ | ||
| 1082 | - outlen = len; | ||
| 1083 | - if (passphrase) | ||
| 1084 | - outlen = (outlen+8) &~ 7; | ||
| 1085 | + /* | ||
| 1086 | + * Now count up the total size of the ASN.1 encoded integers, | ||
| 1087 | + * so as to determine the length of the containing SEQUENCE. | ||
| 1088 | + */ | ||
| 1089 | + len = 0; | ||
| 1090 | + for (i = 0; i < nnumbers; i++) { | ||
| 1091 | + len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0); | ||
| 1092 | + len += numbers[i].bytes; | ||
| 1093 | + } | ||
| 1094 | + seqlen = len; | ||
| 1095 | + /* Now add on the SEQUENCE header. */ | ||
| 1096 | + len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED); | ||
| 1097 | + /* Round up to the cipher block size, ensuring we have at least one | ||
| 1098 | + * byte of padding (see below). */ | ||
| 1099 | + outlen = len; | ||
| 1100 | + if (passphrase) | ||
| 1101 | + outlen = (outlen+8) &~ 7; | ||
| 1102 | |||
| 1103 | - /* | ||
| 1104 | - * Now we know how big outblob needs to be. Allocate it. | ||
| 1105 | - */ | ||
| 1106 | + /* | ||
| 1107 | + * Now we know how big outblob needs to be. Allocate it. | ||
| 1108 | + */ | ||
| 1109 | outblob = (unsigned char*)m_malloc(outlen); | ||
| 1110 | |||
| 1111 | - /* | ||
| 1112 | - * And write the data into it. | ||
| 1113 | - */ | ||
| 1114 | - pos = 0; | ||
| 1115 | - pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED); | ||
| 1116 | - for (i = 0; i < nnumbers; i++) { | ||
| 1117 | - pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0); | ||
| 1118 | - memcpy(outblob+pos, numbers[i].start, numbers[i].bytes); | ||
| 1119 | - pos += numbers[i].bytes; | ||
| 1120 | - } | ||
| 1121 | + /* | ||
| 1122 | + * And write the data into it. | ||
| 1123 | + */ | ||
| 1124 | + pos = 0; | ||
| 1125 | + pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED); | ||
| 1126 | + for (i = 0; i < nnumbers; i++) { | ||
| 1127 | + pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0); | ||
| 1128 | + memcpy(outblob+pos, numbers[i].start, numbers[i].bytes); | ||
| 1129 | + pos += numbers[i].bytes; | ||
| 1130 | + } | ||
| 1131 | } /* end RSA and DSS handling */ | ||
| 1132 | |||
| 1133 | #ifdef DROPBEAR_ECDSA | ||
| 1134 | @@ -1116,40 +1120,40 @@ | ||
| 1135 | } | ||
| 1136 | #endif | ||
| 1137 | |||
| 1138 | - /* | ||
| 1139 | - * Padding on OpenSSH keys is deterministic. The number of | ||
| 1140 | - * padding bytes is always more than zero, and always at most | ||
| 1141 | - * the cipher block length. The value of each padding byte is | ||
| 1142 | - * equal to the number of padding bytes. So a plaintext that's | ||
| 1143 | - * an exact multiple of the block size will be padded with 08 | ||
| 1144 | - * 08 08 08 08 08 08 08 (assuming a 64-bit block cipher); a | ||
| 1145 | - * plaintext one byte less than a multiple of the block size | ||
| 1146 | - * will be padded with just 01. | ||
| 1147 | - * | ||
| 1148 | - * This enables the OpenSSL key decryption function to strip | ||
| 1149 | - * off the padding algorithmically and return the unpadded | ||
| 1150 | - * plaintext to the next layer: it looks at the final byte, and | ||
| 1151 | - * then expects to find that many bytes at the end of the data | ||
| 1152 | - * with the same value. Those are all removed and the rest is | ||
| 1153 | - * returned. | ||
| 1154 | - */ | ||
| 1155 | + /* | ||
| 1156 | + * Padding on OpenSSH keys is deterministic. The number of | ||
| 1157 | + * padding bytes is always more than zero, and always at most | ||
| 1158 | + * the cipher block length. The value of each padding byte is | ||
| 1159 | + * equal to the number of padding bytes. So a plaintext that's | ||
| 1160 | + * an exact multiple of the block size will be padded with 08 | ||
| 1161 | + * 08 08 08 08 08 08 08 (assuming a 64-bit block cipher); a | ||
| 1162 | + * plaintext one byte less than a multiple of the block size | ||
| 1163 | + * will be padded with just 01. | ||
| 1164 | + * | ||
| 1165 | + * This enables the OpenSSL key decryption function to strip | ||
| 1166 | + * off the padding algorithmically and return the unpadded | ||
| 1167 | + * plaintext to the next layer: it looks at the final byte, and | ||
| 1168 | + * then expects to find that many bytes at the end of the data | ||
| 1169 | + * with the same value. Those are all removed and the rest is | ||
| 1170 | + * returned. | ||
| 1171 | + */ | ||
| 1172 | dropbear_assert(pos == len); | ||
| 1173 | - while (pos < outlen) { | ||
| 1174 | - outblob[pos++] = outlen - len; | ||
| 1175 | - } | ||
| 1176 | + while (pos < outlen) { | ||
| 1177 | + outblob[pos++] = outlen - len; | ||
| 1178 | + } | ||
| 1179 | |||
| 1180 | - /* | ||
| 1181 | - * Encrypt the key. | ||
| 1182 | - */ | ||
| 1183 | - if (passphrase) { | ||
| 1184 | + /* | ||
| 1185 | + * Encrypt the key. | ||
| 1186 | + */ | ||
| 1187 | + if (passphrase) { | ||
| 1188 | fprintf(stderr, "Encrypted keys aren't supported currently\n"); | ||
| 1189 | goto error; | ||
| 1190 | - } | ||
| 1191 | + } | ||
| 1192 | |||
| 1193 | - /* | ||
| 1194 | - * And save it. We'll use Unix line endings just in case it's | ||
| 1195 | - * subsequently transferred in binary mode. | ||
| 1196 | - */ | ||
| 1197 | + /* | ||
| 1198 | + * And save it. We'll use Unix line endings just in case it's | ||
| 1199 | + * subsequently transferred in binary mode. | ||
| 1200 | + */ | ||
| 1201 | if (strlen(filename) == 1 && filename[0] == '-') { | ||
| 1202 | fp = stdout; | ||
| 1203 | } else { | ||
| 1204 | @@ -1157,28 +1161,28 @@ | ||
| 1205 | } | ||
| 1206 | if (!fp) { | ||
| 1207 | fprintf(stderr, "Failed opening output file\n"); | ||
| 1208 | - goto error; | ||
| 1209 | + goto error; | ||
| 1210 | } | ||
| 1211 | - fputs(header, fp); | ||
| 1212 | + fputs(header, fp); | ||
| 1213 | base64_encode_fp(fp, outblob, outlen, 64); | ||
| 1214 | - fputs(footer, fp); | ||
| 1215 | - fclose(fp); | ||
| 1216 | - ret = 1; | ||
| 1217 | + fputs(footer, fp); | ||
| 1218 | + fclose(fp); | ||
| 1219 | + ret = 1; | ||
| 1220 | |||
| 1221 | - error: | ||
| 1222 | - if (outblob) { | ||
| 1223 | - memset(outblob, 0, outlen); | ||
| 1224 | + error: | ||
| 1225 | + if (outblob) { | ||
| 1226 | + memset(outblob, 0, outlen); | ||
| 1227 | m_free(outblob); | ||
| 1228 | - } | ||
| 1229 | + } | ||
| 1230 | if (keyblob) { | ||
| 1231 | buf_burn(keyblob); | ||
| 1232 | buf_free(keyblob); | ||
| 1233 | - } | ||
| 1234 | + } | ||
| 1235 | if (extrablob) { | ||
| 1236 | buf_burn(extrablob); | ||
| 1237 | buf_free(extrablob); | ||
| 1238 | - } | ||
| 1239 | - return ret; | ||
| 1240 | + } | ||
| 1241 | + return ret; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | #if 0 | ||
| 1245 | @@ -1196,10 +1200,10 @@ | ||
| 1246 | * | ||
| 1247 | * So. The blob contains: | ||
| 1248 | * | ||
| 1249 | - * - uint32 0x3f6ff9eb (magic number) | ||
| 1250 | - * - uint32 size (total blob size) | ||
| 1251 | - * - string key-type (see below) | ||
| 1252 | - * - string cipher-type (tells you if key is encrypted) | ||
| 1253 | + * - uint32 0x3f6ff9eb (magic number) | ||
| 1254 | + * - uint32 size (total blob size) | ||
| 1255 | + * - string key-type (see below) | ||
| 1256 | + * - string cipher-type (tells you if key is encrypted) | ||
| 1257 | * - string encrypted-blob | ||
| 1258 | * | ||
| 1259 | * (The first size field includes the size field itself and the | ||
| 1260 | @@ -1255,654 +1259,679 @@ | ||
| 1261 | * - first 16 bytes are MD5(passphrase) | ||
| 1262 | * - next 16 bytes are MD5(passphrase || first 16 bytes) | ||
| 1263 | * - if there were more, they'd be MD5(passphrase || first 32), | ||
| 1264 | - * and so on. | ||
| 1265 | + * and so on. | ||
| 1266 | */ | ||
| 1267 | |||
| 1268 | #define SSHCOM_MAGIC_NUMBER 0x3f6ff9eb | ||
| 1269 | |||
| 1270 | struct sshcom_key { | ||
| 1271 | - char comment[256]; /* allowing any length is overkill */ | ||
| 1272 | - unsigned char *keyblob; | ||
| 1273 | - int keyblob_len, keyblob_size; | ||
| 1274 | + char comment[256]; /* allowing any length is overkill */ | ||
| 1275 | + unsigned char *keyblob; | ||
| 1276 | + int keyblob_len, keyblob_size; | ||
| 1277 | }; | ||
| 1278 | |||
| 1279 | static struct sshcom_key *load_sshcom_key(const char *filename) | ||
| 1280 | { | ||
| 1281 | - struct sshcom_key *ret; | ||
| 1282 | - FILE *fp; | ||
| 1283 | - char buffer[256]; | ||
| 1284 | - int len; | ||
| 1285 | - char *errmsg, *p; | ||
| 1286 | - int headers_done; | ||
| 1287 | - char base64_bit[4]; | ||
| 1288 | - int base64_chars = 0; | ||
| 1289 | + struct sshcom_key *ret; | ||
| 1290 | + FILE *fp; | ||
| 1291 | + char buffer[256]; | ||
| 1292 | + int len; | ||
| 1293 | + char *errmsg, *p; | ||
| 1294 | + int headers_done; | ||
| 1295 | + char base64_bit[4]; | ||
| 1296 | + int base64_chars = 0; | ||
| 1297 | |||
| 1298 | - ret = snew(struct sshcom_key); | ||
| 1299 | - ret->comment[0] = '\0'; | ||
| 1300 | - ret->keyblob = NULL; | ||
| 1301 | - ret->keyblob_len = ret->keyblob_size = 0; | ||
| 1302 | + ret = snew(struct sshcom_key); | ||
| 1303 | + ret->comment[0] = '\0'; | ||
| 1304 | + ret->keyblob = NULL; | ||
| 1305 | + ret->keyblob_len = ret->keyblob_size = 0; | ||
| 1306 | |||
| 1307 | fp = fopen(filename, "r"); | ||
| 1308 | - if (!fp) { | ||
| 1309 | - errmsg = "Unable to open key file"; | ||
| 1310 | + if (!fp) { | ||
| 1311 | + errmsg = "Unable to open key file"; | ||
| 1312 | + goto error; | ||
| 1313 | + } | ||
| 1314 | + if (!fgets(buffer, sizeof(buffer), fp) || | ||
| 1315 | + 0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) { | ||
| 1316 | + errmsg = "File does not begin with ssh.com key header"; | ||
| 1317 | + goto error; | ||
| 1318 | + } | ||
| 1319 | + | ||
| 1320 | + headers_done = 0; | ||
| 1321 | + while (1) { | ||
| 1322 | + if (!fgets(buffer, sizeof(buffer), fp)) { | ||
| 1323 | + errmsg = "Unexpected end of file"; | ||
| 1324 | + goto error; | ||
| 1325 | + } | ||
| 1326 | + if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n")) | ||
| 1327 | + break; /* done */ | ||
| 1328 | + if ((p = strchr(buffer, ':')) != NULL) { | ||
| 1329 | + if (headers_done) { | ||
| 1330 | + errmsg = "Header found in body of key data"; | ||
| 1331 | goto error; | ||
| 1332 | + } | ||
| 1333 | + *p++ = '\0'; | ||
| 1334 | + while (*p && isspace((unsigned char)*p)) p++; | ||
| 1335 | + /* | ||
| 1336 | + * Header lines can end in a trailing backslash for | ||
| 1337 | + * continuation. | ||
| 1338 | + */ | ||
| 1339 | + while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) || | ||
| 1340 | + p[len-1] != '\n' || p[len-2] == '\\') { | ||
| 1341 | + if (len > (int)((p-buffer) + sizeof(buffer)-2)) { | ||
| 1342 | + errmsg = "Header line too long to deal with"; | ||
| 1343 | + goto error; | ||
| 1344 | + } | ||
| 1345 | + if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) { | ||
| 1346 | + errmsg = "Unexpected end of file"; | ||
| 1347 | + goto error; | ||
| 1348 | + } | ||
| 1349 | + } | ||
| 1350 | + p[strcspn(p, "\n")] = '\0'; | ||
| 1351 | + if (!strcmp(buffer, "Comment")) { | ||
| 1352 | + /* Strip quotes in comment if present. */ | ||
| 1353 | + if (p[0] == '"' && p[strlen(p)-1] == '"') { | ||
| 1354 | + p++; | ||
| 1355 | + p[strlen(p)-1] = '\0'; | ||
| 1356 | + } | ||
| 1357 | + strncpy(ret->comment, p, sizeof(ret->comment)); | ||
| 1358 | + ret->comment[sizeof(ret->comment)-1] = '\0'; | ||
| 1359 | + } | ||
| 1360 | + } else { | ||
| 1361 | + headers_done = 1; | ||
| 1362 | + | ||
| 1363 | + p = buffer; | ||
| 1364 | + while (isbase64(*p)) { | ||
| 1365 | + base64_bit[base64_chars++] = *p; | ||
| 1366 | + if (base64_chars == 4) { | ||
| 1367 | + unsigned char out[3]; | ||
| 1368 | + | ||
| 1369 | + base64_chars = 0; | ||
| 1370 | + | ||
| 1371 | + len = base64_decode_atom(base64_bit, out); | ||
| 1372 | + | ||
| 1373 | + if (len <= 0) { | ||
| 1374 | + errmsg = "Invalid base64 encoding"; | ||
| 1375 | + goto error; | ||
| 1376 | + } | ||
| 1377 | + | ||
| 1378 | + if (ret->keyblob_len + len > ret->keyblob_size) { | ||
| 1379 | + ret->keyblob_size = ret->keyblob_len + len + 256; | ||
| 1380 | + ret->keyblob = sresize(ret->keyblob, ret->keyblob_size, | ||
| 1381 | + unsigned char); | ||
| 1382 | + } | ||
| 1383 | + | ||
| 1384 | + memcpy(ret->keyblob + ret->keyblob_len, out, len); | ||
| 1385 | + ret->keyblob_len += len; | ||
| 1386 | + } | ||
| 1387 | + | ||
| 1388 | + p++; | ||
| 1389 | + } | ||
| 1390 | } | ||
| 1391 | - if (!fgets(buffer, sizeof(buffer), fp) || | ||
| 1392 | - 0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) { | ||
| 1393 | - errmsg = "File does not begin with ssh.com key header"; | ||
| 1394 | - goto error; | ||
| 1395 | - } | ||
| 1396 | + } | ||
| 1397 | |||
| 1398 | - headers_done = 0; | ||
| 1399 | - while (1) { | ||
| 1400 | - if (!fgets(buffer, sizeof(buffer), fp)) { | ||
| 1401 | - errmsg = "Unexpected end of file"; | ||
| 1402 | - goto error; | ||
| 1403 | - } | ||
| 1404 | - if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n")) | ||
| 1405 | - break; /* done */ | ||
| 1406 | - if ((p = strchr(buffer, ':')) != NULL) { | ||
| 1407 | - if (headers_done) { | ||
| 1408 | - errmsg = "Header found in body of key data"; | ||
| 1409 | - goto error; | ||
| 1410 | - } | ||
| 1411 | - *p++ = '\0'; | ||
| 1412 | - while (*p && isspace((unsigned char)*p)) p++; | ||
| 1413 | - /* | ||
| 1414 | - * Header lines can end in a trailing backslash for | ||
| 1415 | - * continuation. | ||
| 1416 | - */ | ||
| 1417 | - while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) || | ||
| 1418 | - p[len-1] != '\n' || p[len-2] == '\\') { | ||
| 1419 | - if (len > (int)((p-buffer) + sizeof(buffer)-2)) { | ||
| 1420 | - errmsg = "Header line too long to deal with"; | ||
| 1421 | - goto error; | ||
| 1422 | - } | ||
| 1423 | - if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) { | ||
| 1424 | - errmsg = "Unexpected end of file"; | ||
| 1425 | - goto error; | ||
| 1426 | - } | ||
| 1427 | - } | ||
| 1428 | - p[strcspn(p, "\n")] = '\0'; | ||
| 1429 | - if (!strcmp(buffer, "Comment")) { | ||
| 1430 | - /* Strip quotes in comment if present. */ | ||
| 1431 | - if (p[0] == '"' && p[strlen(p)-1] == '"') { | ||
| 1432 | - p++; | ||
| 1433 | - p[strlen(p)-1] = '\0'; | ||
| 1434 | - } | ||
| 1435 | - strncpy(ret->comment, p, sizeof(ret->comment)); | ||
| 1436 | - ret->comment[sizeof(ret->comment)-1] = '\0'; | ||
| 1437 | - } | ||
| 1438 | - } else { | ||
| 1439 | - headers_done = 1; | ||
| 1440 | + if (ret->keyblob_len == 0 || !ret->keyblob) { | ||
| 1441 | + errmsg = "Key body not present"; | ||
| 1442 | + goto error; | ||
| 1443 | + } | ||
| 1444 | |||
| 1445 | - p = buffer; | ||
| 1446 | - while (isbase64(*p)) { | ||
| 1447 | - base64_bit[base64_chars++] = *p; | ||
| 1448 | - if (base64_chars == 4) { | ||
| 1449 | - unsigned char out[3]; | ||
| 1450 | + return ret; | ||
| 1451 | |||
| 1452 | - base64_chars = 0; | ||
| 1453 | - | ||
| 1454 | - len = base64_decode_atom(base64_bit, out); | ||
| 1455 | - | ||
| 1456 | - if (len <= 0) { | ||
| 1457 | - errmsg = "Invalid base64 encoding"; | ||
| 1458 | - goto error; | ||
| 1459 | - } | ||
| 1460 | - | ||
| 1461 | - if (ret->keyblob_len + len > ret->keyblob_size) { | ||
| 1462 | - ret->keyblob_size = ret->keyblob_len + len + 256; | ||
| 1463 | - ret->keyblob = sresize(ret->keyblob, ret->keyblob_size, | ||
| 1464 | - unsigned char); | ||
| 1465 | - } | ||
| 1466 | - | ||
| 1467 | - memcpy(ret->keyblob + ret->keyblob_len, out, len); | ||
| 1468 | - ret->keyblob_len += len; | ||
| 1469 | - } | ||
| 1470 | - | ||
| 1471 | - p++; | ||
| 1472 | - } | ||
| 1473 | - } | ||
| 1474 | - } | ||
| 1475 | - | ||
| 1476 | - if (ret->keyblob_len == 0 || !ret->keyblob) { | ||
| 1477 | - errmsg = "Key body not present"; | ||
| 1478 | - goto error; | ||
| 1479 | - } | ||
| 1480 | - | ||
| 1481 | - return ret; | ||
| 1482 | - | ||
| 1483 | - error: | ||
| 1484 | - if (ret) { | ||
| 1485 | - if (ret->keyblob) { | ||
| 1486 | - memset(ret->keyblob, 0, ret->keyblob_size); | ||
| 1487 | + error: | ||
| 1488 | + if (ret) { | ||
| 1489 | + if (ret->keyblob) { | ||
| 1490 | + memset(ret->keyblob, 0, ret->keyblob_size); | ||
| 1491 | m_free(ret->keyblob); | ||
| 1492 | - } | ||
| 1493 | - memset(&ret, 0, sizeof(ret)); | ||
| 1494 | + } | ||
| 1495 | + memset(ret, 0, sizeof(*ret)); | ||
| 1496 | m_free(ret); | ||
| 1497 | - } | ||
| 1498 | - return NULL; | ||
| 1499 | + } | ||
| 1500 | + return NULL; | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | int sshcom_encrypted(const char *filename, char **comment) | ||
| 1504 | { | ||
| 1505 | - struct sshcom_key *key = load_sshcom_key(filename); | ||
| 1506 | - int pos, len, answer; | ||
| 1507 | + struct sshcom_key *key = load_sshcom_key(filename); | ||
| 1508 | + int pos, len, answer; | ||
| 1509 | |||
| 1510 | - *comment = NULL; | ||
| 1511 | - if (!key) | ||
| 1512 | - return 0; | ||
| 1513 | + *comment = NULL; | ||
| 1514 | + if (!key) | ||
| 1515 | + return 0; | ||
| 1516 | |||
| 1517 | - /* | ||
| 1518 | - * Check magic number. | ||
| 1519 | - */ | ||
| 1520 | - if (GET_32BIT(key->keyblob) != 0x3f6ff9eb) | ||
| 1521 | - return 0; /* key is invalid */ | ||
| 1522 | + /* | ||
| 1523 | + * Check magic number. | ||
| 1524 | + */ | ||
| 1525 | + if (GET_32BIT(key->keyblob) != 0x3f6ff9eb) | ||
| 1526 | + return 0; /* key is invalid */ | ||
| 1527 | |||
| 1528 | - /* | ||
| 1529 | - * Find the cipher-type string. | ||
| 1530 | - */ | ||
| 1531 | - answer = 0; | ||
| 1532 | - pos = 8; | ||
| 1533 | - if (key->keyblob_len < pos+4) | ||
| 1534 | - goto done; /* key is far too short */ | ||
| 1535 | - pos += 4 + GET_32BIT(key->keyblob + pos); /* skip key type */ | ||
| 1536 | - if (key->keyblob_len < pos+4) | ||
| 1537 | - goto done; /* key is far too short */ | ||
| 1538 | - len = GET_32BIT(key->keyblob + pos); /* find cipher-type length */ | ||
| 1539 | - if (key->keyblob_len < pos+4+len) | ||
| 1540 | - goto done; /* cipher type string is incomplete */ | ||
| 1541 | - if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4)) | ||
| 1542 | - answer = 1; | ||
| 1543 | + /* | ||
| 1544 | + * Find the cipher-type string. | ||
| 1545 | + */ | ||
| 1546 | + answer = 0; | ||
| 1547 | + pos = 8; | ||
| 1548 | + if (key->keyblob_len < pos+4) | ||
| 1549 | + goto done; /* key is far too short */ | ||
| 1550 | + len = toint(GET_32BIT(key->keyblob + pos)); | ||
| 1551 | + if (len < 0 || len > key->keyblob_len - pos - 4) | ||
| 1552 | + goto done; /* key is far too short */ | ||
| 1553 | + pos += 4 + len; /* skip key type */ | ||
| 1554 | + len = toint(GET_32BIT(key->keyblob + pos)); /* find cipher-type length */ | ||
| 1555 | + if (len < 0 || len > key->keyblob_len - pos - 4) | ||
| 1556 | + goto done; /* cipher type string is incomplete */ | ||
| 1557 | + if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4)) | ||
| 1558 | + answer = 1; | ||
| 1559 | |||
| 1560 | - done: | ||
| 1561 | - *comment = dupstr(key->comment); | ||
| 1562 | - memset(key->keyblob, 0, key->keyblob_size); | ||
| 1563 | + done: | ||
| 1564 | + *comment = dupstr(key->comment); | ||
| 1565 | + memset(key->keyblob, 0, key->keyblob_size); | ||
| 1566 | m_free(key->keyblob); | ||
| 1567 | - memset(&key, 0, sizeof(key)); | ||
| 1568 | + memset(key, 0, sizeof(*key)); | ||
| 1569 | m_free(key); | ||
| 1570 | - return answer; | ||
| 1571 | + return answer; | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret) | ||
| 1575 | { | ||
| 1576 | - int bits; | ||
| 1577 | - int bytes; | ||
| 1578 | - unsigned char *d = (unsigned char *) data; | ||
| 1579 | + unsigned bits, bytes; | ||
| 1580 | + unsigned char *d = (unsigned char *) data; | ||
| 1581 | |||
| 1582 | - if (len < 4) | ||
| 1583 | - goto error; | ||
| 1584 | - bits = GET_32BIT(d); | ||
| 1585 | + if (len < 4) | ||
| 1586 | + goto error; | ||
| 1587 | + bits = GET_32BIT(d); | ||
| 1588 | |||
| 1589 | - bytes = (bits + 7) / 8; | ||
| 1590 | - if (len < 4+bytes) | ||
| 1591 | - goto error; | ||
| 1592 | + bytes = (bits + 7) / 8; | ||
| 1593 | + if (len < 4+bytes) | ||
| 1594 | + goto error; | ||
| 1595 | |||
| 1596 | - ret->start = d + 4; | ||
| 1597 | - ret->bytes = bytes; | ||
| 1598 | - return bytes+4; | ||
| 1599 | + ret->start = d + 4; | ||
| 1600 | + ret->bytes = bytes; | ||
| 1601 | + return bytes+4; | ||
| 1602 | |||
| 1603 | - error: | ||
| 1604 | - ret->start = NULL; | ||
| 1605 | - ret->bytes = -1; | ||
| 1606 | - return len; /* ensure further calls fail as well */ | ||
| 1607 | + error: | ||
| 1608 | + ret->start = NULL; | ||
| 1609 | + ret->bytes = -1; | ||
| 1610 | + return len; /* ensure further calls fail as well */ | ||
| 1611 | } | ||
| 1612 | |||
| 1613 | static int sshcom_put_mpint(void *target, void *data, int len) | ||
| 1614 | { | ||
| 1615 | - unsigned char *d = (unsigned char *)target; | ||
| 1616 | - unsigned char *i = (unsigned char *)data; | ||
| 1617 | - int bits = len * 8 - 1; | ||
| 1618 | + unsigned char *d = (unsigned char *)target; | ||
| 1619 | + unsigned char *i = (unsigned char *)data; | ||
| 1620 | + int bits = len * 8 - 1; | ||
| 1621 | |||
| 1622 | - while (bits > 0) { | ||
| 1623 | - if (*i & (1 << (bits & 7))) | ||
| 1624 | - break; | ||
| 1625 | - if (!(bits-- & 7)) | ||
| 1626 | - i++, len--; | ||
| 1627 | - } | ||
| 1628 | + while (bits > 0) { | ||
| 1629 | + if (*i & (1 << (bits & 7))) | ||
| 1630 | + break; | ||
| 1631 | + if (!(bits-- & 7)) | ||
| 1632 | + i++, len--; | ||
| 1633 | + } | ||
| 1634 | |||
| 1635 | - PUT_32BIT(d, bits+1); | ||
| 1636 | - memcpy(d+4, i, len); | ||
| 1637 | - return len+4; | ||
| 1638 | + PUT_32BIT(d, bits+1); | ||
| 1639 | + memcpy(d+4, i, len); | ||
| 1640 | + return len+4; | ||
| 1641 | } | ||
| 1642 | |||
| 1643 | sign_key *sshcom_read(const char *filename, char *passphrase) | ||
| 1644 | { | ||
| 1645 | - struct sshcom_key *key = load_sshcom_key(filename); | ||
| 1646 | - char *errmsg; | ||
| 1647 | - int pos, len; | ||
| 1648 | - const char prefix_rsa[] = "if-modn{sign{rsa"; | ||
| 1649 | - const char prefix_dsa[] = "dl-modp{sign{dsa"; | ||
| 1650 | - enum { RSA, DSA } type; | ||
| 1651 | - int encrypted; | ||
| 1652 | - char *ciphertext; | ||
| 1653 | - int cipherlen; | ||
| 1654 | - struct ssh2_userkey *ret = NULL, *retkey; | ||
| 1655 | - const struct ssh_signkey *alg; | ||
| 1656 | - unsigned char *blob = NULL; | ||
| 1657 | - int blobsize, publen, privlen; | ||
| 1658 | + struct sshcom_key *key = load_sshcom_key(filename); | ||
| 1659 | + char *errmsg; | ||
| 1660 | + int pos, len; | ||
| 1661 | + const char prefix_rsa[] = "if-modn{sign{rsa"; | ||
| 1662 | + const char prefix_dsa[] = "dl-modp{sign{dsa"; | ||
| 1663 | + enum { RSA, DSA } type; | ||
| 1664 | + int encrypted; | ||
| 1665 | + char *ciphertext; | ||
| 1666 | + int cipherlen; | ||
| 1667 | + struct ssh2_userkey *ret = NULL, *retkey; | ||
| 1668 | + const struct ssh_signkey *alg; | ||
| 1669 | + unsigned char *blob = NULL; | ||
| 1670 | + int blobsize = 0, publen, privlen; | ||
| 1671 | |||
| 1672 | - if (!key) | ||
| 1673 | - return NULL; | ||
| 1674 | + if (!key) | ||
| 1675 | + return NULL; | ||
| 1676 | + | ||
| 1677 | + /* | ||
| 1678 | + * Check magic number. | ||
| 1679 | + */ | ||
| 1680 | + if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) { | ||
| 1681 | + errmsg = "Key does not begin with magic number"; | ||
| 1682 | + goto error; | ||
| 1683 | + } | ||
| 1684 | + | ||
| 1685 | + /* | ||
| 1686 | + * Determine the key type. | ||
| 1687 | + */ | ||
| 1688 | + pos = 8; | ||
| 1689 | + if (key->keyblob_len < pos+4 || | ||
| 1690 | + (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { | ||
| 1691 | + errmsg = "Key blob does not contain a key type string"; | ||
| 1692 | + goto error; | ||
| 1693 | + } | ||
| 1694 | + if (len > sizeof(prefix_rsa) - 1 && | ||
| 1695 | + !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) { | ||
| 1696 | + type = RSA; | ||
| 1697 | + } else if (len > sizeof(prefix_dsa) - 1 && | ||
| 1698 | + !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) { | ||
| 1699 | + type = DSA; | ||
| 1700 | + } else { | ||
| 1701 | + errmsg = "Key is of unknown type"; | ||
| 1702 | + goto error; | ||
| 1703 | + } | ||
| 1704 | + pos += 4+len; | ||
| 1705 | + | ||
| 1706 | + /* | ||
| 1707 | + * Determine the cipher type. | ||
| 1708 | + */ | ||
| 1709 | + if (key->keyblob_len < pos+4 || | ||
| 1710 | + (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { | ||
| 1711 | + errmsg = "Key blob does not contain a cipher type string"; | ||
| 1712 | + goto error; | ||
| 1713 | + } | ||
| 1714 | + if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4)) | ||
| 1715 | + encrypted = 0; | ||
| 1716 | + else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8)) | ||
| 1717 | + encrypted = 1; | ||
| 1718 | + else { | ||
| 1719 | + errmsg = "Key encryption is of unknown type"; | ||
| 1720 | + goto error; | ||
| 1721 | + } | ||
| 1722 | + pos += 4+len; | ||
| 1723 | + | ||
| 1724 | + /* | ||
| 1725 | + * Get hold of the encrypted part of the key. | ||
| 1726 | + */ | ||
| 1727 | + if (key->keyblob_len < pos+4 || | ||
| 1728 | + (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { | ||
| 1729 | + errmsg = "Key blob does not contain actual key data"; | ||
| 1730 | + goto error; | ||
| 1731 | + } | ||
| 1732 | + ciphertext = (char *)key->keyblob + pos + 4; | ||
| 1733 | + cipherlen = len; | ||
| 1734 | + if (cipherlen == 0) { | ||
| 1735 | + errmsg = "Length of key data is zero"; | ||
| 1736 | + goto error; | ||
| 1737 | + } | ||
| 1738 | + | ||
| 1739 | + /* | ||
| 1740 | + * Decrypt it if necessary. | ||
| 1741 | + */ | ||
| 1742 | + if (encrypted) { | ||
| 1743 | + /* | ||
| 1744 | + * Derive encryption key from passphrase and iv/salt: | ||
| 1745 | + * | ||
| 1746 | + * - let block A equal MD5(passphrase) | ||
| 1747 | + * - let block B equal MD5(passphrase || A) | ||
| 1748 | + * - block C would be MD5(passphrase || A || B) and so on | ||
| 1749 | + * - encryption key is the first N bytes of A || B | ||
| 1750 | + */ | ||
| 1751 | + struct MD5Context md5c; | ||
| 1752 | + unsigned char keybuf[32], iv[8]; | ||
| 1753 | + | ||
| 1754 | + if (cipherlen % 8 != 0) { | ||
| 1755 | + errmsg = "Encrypted part of key is not a multiple of cipher block" | ||
| 1756 | + " size"; | ||
| 1757 | + goto error; | ||
| 1758 | + } | ||
| 1759 | + | ||
| 1760 | + MD5Init(&md5c); | ||
| 1761 | + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 1762 | + MD5Final(keybuf, &md5c); | ||
| 1763 | + | ||
| 1764 | + MD5Init(&md5c); | ||
| 1765 | + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 1766 | + MD5Update(&md5c, keybuf, 16); | ||
| 1767 | + MD5Final(keybuf+16, &md5c); | ||
| 1768 | |||
| 1769 | /* | ||
| 1770 | - * Check magic number. | ||
| 1771 | + * Now decrypt the key blob. | ||
| 1772 | */ | ||
| 1773 | - if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) { | ||
| 1774 | - errmsg = "Key does not begin with magic number"; | ||
| 1775 | - goto error; | ||
| 1776 | - } | ||
| 1777 | + memset(iv, 0, sizeof(iv)); | ||
| 1778 | + des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, | ||
| 1779 | + cipherlen); | ||
| 1780 | |||
| 1781 | - /* | ||
| 1782 | - * Determine the key type. | ||
| 1783 | - */ | ||
| 1784 | - pos = 8; | ||
| 1785 | - if (key->keyblob_len < pos+4 || | ||
| 1786 | - (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { | ||
| 1787 | - errmsg = "Key blob does not contain a key type string"; | ||
| 1788 | - goto error; | ||
| 1789 | - } | ||
| 1790 | - if (len > sizeof(prefix_rsa) - 1 && | ||
| 1791 | - !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) { | ||
| 1792 | - type = RSA; | ||
| 1793 | - } else if (len > sizeof(prefix_dsa) - 1 && | ||
| 1794 | - !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) { | ||
| 1795 | - type = DSA; | ||
| 1796 | - } else { | ||
| 1797 | - errmsg = "Key is of unknown type"; | ||
| 1798 | - goto error; | ||
| 1799 | - } | ||
| 1800 | - pos += 4+len; | ||
| 1801 | + memset(&md5c, 0, sizeof(md5c)); | ||
| 1802 | + memset(keybuf, 0, sizeof(keybuf)); | ||
| 1803 | |||
| 1804 | - /* | ||
| 1805 | - * Determine the cipher type. | ||
| 1806 | - */ | ||
| 1807 | - if (key->keyblob_len < pos+4 || | ||
| 1808 | - (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { | ||
| 1809 | - errmsg = "Key blob does not contain a cipher type string"; | ||
| 1810 | - goto error; | ||
| 1811 | - } | ||
| 1812 | - if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4)) | ||
| 1813 | - encrypted = 0; | ||
| 1814 | - else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8)) | ||
| 1815 | - encrypted = 1; | ||
| 1816 | - else { | ||
| 1817 | - errmsg = "Key encryption is of unknown type"; | ||
| 1818 | - goto error; | ||
| 1819 | - } | ||
| 1820 | - pos += 4+len; | ||
| 1821 | + /* | ||
| 1822 | + * Hereafter we return WRONG_PASSPHRASE for any parsing | ||
| 1823 | + * error. (But only if we've just tried to decrypt it! | ||
| 1824 | + * Returning WRONG_PASSPHRASE for an unencrypted key is | ||
| 1825 | + * automatic doom.) | ||
| 1826 | + */ | ||
| 1827 | + if (encrypted) | ||
| 1828 | + ret = SSH2_WRONG_PASSPHRASE; | ||
| 1829 | + } | ||
| 1830 | |||
| 1831 | - /* | ||
| 1832 | - * Get hold of the encrypted part of the key. | ||
| 1833 | - */ | ||
| 1834 | - if (key->keyblob_len < pos+4 || | ||
| 1835 | - (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { | ||
| 1836 | - errmsg = "Key blob does not contain actual key data"; | ||
| 1837 | - goto error; | ||
| 1838 | - } | ||
| 1839 | - ciphertext = (char *)key->keyblob + pos + 4; | ||
| 1840 | - cipherlen = len; | ||
| 1841 | - if (cipherlen == 0) { | ||
| 1842 | - errmsg = "Length of key data is zero"; | ||
| 1843 | - goto error; | ||
| 1844 | - } | ||
| 1845 | + /* | ||
| 1846 | + * Strip away the containing string to get to the real meat. | ||
| 1847 | + */ | ||
| 1848 | + len = toint(GET_32BIT(ciphertext)); | ||
| 1849 | + if (len < 0 || len > cipherlen-4) { | ||
| 1850 | + errmsg = "containing string was ill-formed"; | ||
| 1851 | + goto error; | ||
| 1852 | + } | ||
| 1853 | + ciphertext += 4; | ||
| 1854 | + cipherlen = len; | ||
| 1855 | |||
| 1856 | - /* | ||
| 1857 | - * Decrypt it if necessary. | ||
| 1858 | - */ | ||
| 1859 | - if (encrypted) { | ||
| 1860 | - /* | ||
| 1861 | - * Derive encryption key from passphrase and iv/salt: | ||
| 1862 | - * | ||
| 1863 | - * - let block A equal MD5(passphrase) | ||
| 1864 | - * - let block B equal MD5(passphrase || A) | ||
| 1865 | - * - block C would be MD5(passphrase || A || B) and so on | ||
| 1866 | - * - encryption key is the first N bytes of A || B | ||
| 1867 | - */ | ||
| 1868 | - struct MD5Context md5c; | ||
| 1869 | - unsigned char keybuf[32], iv[8]; | ||
| 1870 | + /* | ||
| 1871 | + * Now we break down into RSA versus DSA. In either case we'll | ||
| 1872 | + * construct public and private blobs in our own format, and | ||
| 1873 | + * end up feeding them to alg->createkey(). | ||
| 1874 | + */ | ||
| 1875 | + blobsize = cipherlen + 256; | ||
| 1876 | + blob = snewn(blobsize, unsigned char); | ||
| 1877 | + privlen = 0; | ||
| 1878 | + if (type == RSA) { | ||
| 1879 | + struct mpint_pos n, e, d, u, p, q; | ||
| 1880 | + int pos = 0; | ||
| 1881 | + pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e); | ||
| 1882 | + pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d); | ||
| 1883 | + pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n); | ||
| 1884 | + pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u); | ||
| 1885 | + pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); | ||
| 1886 | + pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); | ||
| 1887 | + if (!q.start) { | ||
| 1888 | + errmsg = "key data did not contain six integers"; | ||
| 1889 | + goto error; | ||
| 1890 | + } | ||
| 1891 | |||
| 1892 | - if (cipherlen % 8 != 0) { | ||
| 1893 | - errmsg = "Encrypted part of key is not a multiple of cipher block" | ||
| 1894 | - " size"; | ||
| 1895 | - goto error; | ||
| 1896 | - } | ||
| 1897 | + alg = &ssh_rsa; | ||
| 1898 | + pos = 0; | ||
| 1899 | + pos += put_string(blob+pos, "ssh-rsa", 7); | ||
| 1900 | + pos += put_mp(blob+pos, e.start, e.bytes); | ||
| 1901 | + pos += put_mp(blob+pos, n.start, n.bytes); | ||
| 1902 | + publen = pos; | ||
| 1903 | + pos += put_string(blob+pos, d.start, d.bytes); | ||
| 1904 | + pos += put_mp(blob+pos, q.start, q.bytes); | ||
| 1905 | + pos += put_mp(blob+pos, p.start, p.bytes); | ||
| 1906 | + pos += put_mp(blob+pos, u.start, u.bytes); | ||
| 1907 | + privlen = pos - publen; | ||
| 1908 | + } else if (type == DSA) { | ||
| 1909 | + struct mpint_pos p, q, g, x, y; | ||
| 1910 | + int pos = 4; | ||
| 1911 | + if (GET_32BIT(ciphertext) != 0) { | ||
| 1912 | + errmsg = "predefined DSA parameters not supported"; | ||
| 1913 | + goto error; | ||
| 1914 | + } | ||
| 1915 | + pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); | ||
| 1916 | + pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g); | ||
| 1917 | + pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); | ||
| 1918 | + pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y); | ||
| 1919 | + pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x); | ||
| 1920 | + if (!x.start) { | ||
| 1921 | + errmsg = "key data did not contain five integers"; | ||
| 1922 | + goto error; | ||
| 1923 | + } | ||
| 1924 | |||
| 1925 | - MD5Init(&md5c); | ||
| 1926 | - MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 1927 | - MD5Final(keybuf, &md5c); | ||
| 1928 | - | ||
| 1929 | - MD5Init(&md5c); | ||
| 1930 | - MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 1931 | - MD5Update(&md5c, keybuf, 16); | ||
| 1932 | - MD5Final(keybuf+16, &md5c); | ||
| 1933 | - | ||
| 1934 | - /* | ||
| 1935 | - * Now decrypt the key blob. | ||
| 1936 | - */ | ||
| 1937 | - memset(iv, 0, sizeof(iv)); | ||
| 1938 | - des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, | ||
| 1939 | - cipherlen); | ||
| 1940 | - | ||
| 1941 | - memset(&md5c, 0, sizeof(md5c)); | ||
| 1942 | - memset(keybuf, 0, sizeof(keybuf)); | ||
| 1943 | - | ||
| 1944 | - /* | ||
| 1945 | - * Hereafter we return WRONG_PASSPHRASE for any parsing | ||
| 1946 | - * error. (But only if we've just tried to decrypt it! | ||
| 1947 | - * Returning WRONG_PASSPHRASE for an unencrypted key is | ||
| 1948 | - * automatic doom.) | ||
| 1949 | - */ | ||
| 1950 | - if (encrypted) | ||
| 1951 | - ret = SSH2_WRONG_PASSPHRASE; | ||
| 1952 | - } | ||
| 1953 | - | ||
| 1954 | - /* | ||
| 1955 | - * Strip away the containing string to get to the real meat. | ||
| 1956 | - */ | ||
| 1957 | - len = GET_32BIT(ciphertext); | ||
| 1958 | - if (len > cipherlen-4) { | ||
| 1959 | - errmsg = "containing string was ill-formed"; | ||
| 1960 | - goto error; | ||
| 1961 | - } | ||
| 1962 | - ciphertext += 4; | ||
| 1963 | - cipherlen = len; | ||
| 1964 | - | ||
| 1965 | - /* | ||
| 1966 | - * Now we break down into RSA versus DSA. In either case we'll | ||
| 1967 | - * construct public and private blobs in our own format, and | ||
| 1968 | - * end up feeding them to alg->createkey(). | ||
| 1969 | - */ | ||
| 1970 | - blobsize = cipherlen + 256; | ||
| 1971 | - blob = snewn(blobsize, unsigned char); | ||
| 1972 | - privlen = 0; | ||
| 1973 | - if (type == RSA) { | ||
| 1974 | - struct mpint_pos n, e, d, u, p, q; | ||
| 1975 | - int pos = 0; | ||
| 1976 | - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e); | ||
| 1977 | - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d); | ||
| 1978 | - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n); | ||
| 1979 | - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u); | ||
| 1980 | - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); | ||
| 1981 | - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); | ||
| 1982 | - if (!q.start) { | ||
| 1983 | - errmsg = "key data did not contain six integers"; | ||
| 1984 | - goto error; | ||
| 1985 | - } | ||
| 1986 | - | ||
| 1987 | - alg = &ssh_rsa; | ||
| 1988 | - pos = 0; | ||
| 1989 | - pos += put_string(blob+pos, "ssh-rsa", 7); | ||
| 1990 | - pos += put_mp(blob+pos, e.start, e.bytes); | ||
| 1991 | - pos += put_mp(blob+pos, n.start, n.bytes); | ||
| 1992 | - publen = pos; | ||
| 1993 | - pos += put_string(blob+pos, d.start, d.bytes); | ||
| 1994 | - pos += put_mp(blob+pos, q.start, q.bytes); | ||
| 1995 | - pos += put_mp(blob+pos, p.start, p.bytes); | ||
| 1996 | - pos += put_mp(blob+pos, u.start, u.bytes); | ||
| 1997 | - privlen = pos - publen; | ||
| 1998 | - } else if (type == DSA) { | ||
| 1999 | - struct mpint_pos p, q, g, x, y; | ||
| 2000 | - int pos = 4; | ||
| 2001 | - if (GET_32BIT(ciphertext) != 0) { | ||
| 2002 | - errmsg = "predefined DSA parameters not supported"; | ||
| 2003 | - goto error; | ||
| 2004 | - } | ||
| 2005 | - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); | ||
| 2006 | - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g); | ||
| 2007 | - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); | ||
| 2008 | - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y); | ||
| 2009 | - pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x); | ||
| 2010 | - if (!x.start) { | ||
| 2011 | - errmsg = "key data did not contain five integers"; | ||
| 2012 | - goto error; | ||
| 2013 | - } | ||
| 2014 | - | ||
| 2015 | - alg = &ssh_dss; | ||
| 2016 | - pos = 0; | ||
| 2017 | - pos += put_string(blob+pos, "ssh-dss", 7); | ||
| 2018 | - pos += put_mp(blob+pos, p.start, p.bytes); | ||
| 2019 | - pos += put_mp(blob+pos, q.start, q.bytes); | ||
| 2020 | - pos += put_mp(blob+pos, g.start, g.bytes); | ||
| 2021 | - pos += put_mp(blob+pos, y.start, y.bytes); | ||
| 2022 | - publen = pos; | ||
| 2023 | - pos += put_mp(blob+pos, x.start, x.bytes); | ||
| 2024 | - privlen = pos - publen; | ||
| 2025 | - } | ||
| 2026 | + alg = &ssh_dss; | ||
| 2027 | + pos = 0; | ||
| 2028 | + pos += put_string(blob+pos, "ssh-dss", 7); | ||
| 2029 | + pos += put_mp(blob+pos, p.start, p.bytes); | ||
| 2030 | + pos += put_mp(blob+pos, q.start, q.bytes); | ||
| 2031 | + pos += put_mp(blob+pos, g.start, g.bytes); | ||
| 2032 | + pos += put_mp(blob+pos, y.start, y.bytes); | ||
| 2033 | + publen = pos; | ||
| 2034 | + pos += put_mp(blob+pos, x.start, x.bytes); | ||
| 2035 | + privlen = pos - publen; | ||
| 2036 | + } else | ||
| 2037 | + return NULL; | ||
| 2038 | |||
| 2039 | dropbear_assert(privlen > 0); /* should have bombed by now if not */ | ||
| 2040 | |||
| 2041 | - retkey = snew(struct ssh2_userkey); | ||
| 2042 | - retkey->alg = alg; | ||
| 2043 | - retkey->data = alg->createkey(blob, publen, blob+publen, privlen); | ||
| 2044 | - if (!retkey->data) { | ||
| 2045 | + retkey = snew(struct ssh2_userkey); | ||
| 2046 | + retkey->alg = alg; | ||
| 2047 | + retkey->data = alg->createkey(blob, publen, blob+publen, privlen); | ||
| 2048 | + if (!retkey->data) { | ||
| 2049 | m_free(retkey); | ||
| 2050 | - errmsg = "unable to create key data structure"; | ||
| 2051 | - goto error; | ||
| 2052 | - } | ||
| 2053 | - retkey->comment = dupstr(key->comment); | ||
| 2054 | + errmsg = "unable to create key data structure"; | ||
| 2055 | + goto error; | ||
| 2056 | + } | ||
| 2057 | + retkey->comment = dupstr(key->comment); | ||
| 2058 | |||
| 2059 | - errmsg = NULL; /* no error */ | ||
| 2060 | - ret = retkey; | ||
| 2061 | + errmsg = NULL; /* no error */ | ||
| 2062 | + ret = retkey; | ||
| 2063 | |||
| 2064 | - error: | ||
| 2065 | - if (blob) { | ||
| 2066 | - memset(blob, 0, blobsize); | ||
| 2067 | + error: | ||
| 2068 | + if (blob) { | ||
| 2069 | + memset(blob, 0, blobsize); | ||
| 2070 | m_free(blob); | ||
| 2071 | - } | ||
| 2072 | - memset(key->keyblob, 0, key->keyblob_size); | ||
| 2073 | + } | ||
| 2074 | + memset(key->keyblob, 0, key->keyblob_size); | ||
| 2075 | m_free(key->keyblob); | ||
| 2076 | - memset(&key, 0, sizeof(key)); | ||
| 2077 | + memset(key, 0, sizeof(*key)); | ||
| 2078 | m_free(key); | ||
| 2079 | - return ret; | ||
| 2080 | + return ret; | ||
| 2081 | } | ||
| 2082 | |||
| 2083 | int sshcom_write(const char *filename, sign_key *key, | ||
| 2084 | - char *passphrase) | ||
| 2085 | + char *passphrase) | ||
| 2086 | { | ||
| 2087 | - unsigned char *pubblob, *privblob; | ||
| 2088 | - int publen, privlen; | ||
| 2089 | - unsigned char *outblob; | ||
| 2090 | - int outlen; | ||
| 2091 | - struct mpint_pos numbers[6]; | ||
| 2092 | - int nnumbers, initial_zero, pos, lenpos, i; | ||
| 2093 | - char *type; | ||
| 2094 | - char *ciphertext; | ||
| 2095 | - int cipherlen; | ||
| 2096 | - int ret = 0; | ||
| 2097 | - FILE *fp; | ||
| 2098 | + unsigned char *pubblob, *privblob; | ||
| 2099 | + int publen, privlen; | ||
| 2100 | + unsigned char *outblob; | ||
| 2101 | + int outlen; | ||
| 2102 | + struct mpint_pos numbers[6]; | ||
| 2103 | + int nnumbers, initial_zero, pos, lenpos, i; | ||
| 2104 | + char *type; | ||
| 2105 | + char *ciphertext; | ||
| 2106 | + int cipherlen; | ||
| 2107 | + int ret = 0; | ||
| 2108 | + FILE *fp; | ||
| 2109 | |||
| 2110 | - /* | ||
| 2111 | - * Fetch the key blobs. | ||
| 2112 | - */ | ||
| 2113 | - pubblob = key->alg->public_blob(key->data, &publen); | ||
| 2114 | - privblob = key->alg->private_blob(key->data, &privlen); | ||
| 2115 | - outblob = NULL; | ||
| 2116 | + /* | ||
| 2117 | + * Fetch the key blobs. | ||
| 2118 | + */ | ||
| 2119 | + pubblob = key->alg->public_blob(key->data, &publen); | ||
| 2120 | + privblob = key->alg->private_blob(key->data, &privlen); | ||
| 2121 | + outblob = NULL; | ||
| 2122 | |||
| 2123 | - /* | ||
| 2124 | - * Find the sequence of integers to be encoded into the OpenSSH | ||
| 2125 | - * key blob, and also decide on the header line. | ||
| 2126 | - */ | ||
| 2127 | - if (key->alg == &ssh_rsa) { | ||
| 2128 | - int pos; | ||
| 2129 | - struct mpint_pos n, e, d, p, q, iqmp; | ||
| 2130 | + /* | ||
| 2131 | + * Find the sequence of integers to be encoded into the OpenSSH | ||
| 2132 | + * key blob, and also decide on the header line. | ||
| 2133 | + */ | ||
| 2134 | + if (key->alg == &ssh_rsa) { | ||
| 2135 | + int pos; | ||
| 2136 | + struct mpint_pos n, e, d, p, q, iqmp; | ||
| 2137 | |||
| 2138 | - pos = 4 + GET_32BIT(pubblob); | ||
| 2139 | - pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e); | ||
| 2140 | - pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n); | ||
| 2141 | - pos = 0; | ||
| 2142 | - pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d); | ||
| 2143 | - pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p); | ||
| 2144 | - pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q); | ||
| 2145 | - pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp); | ||
| 2146 | + pos = 4 + GET_32BIT(pubblob); | ||
| 2147 | + pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e); | ||
| 2148 | + pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n); | ||
| 2149 | + pos = 0; | ||
| 2150 | + pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d); | ||
| 2151 | + pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p); | ||
| 2152 | + pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q); | ||
| 2153 | + pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp); | ||
| 2154 | |||
| 2155 | dropbear_assert(e.start && iqmp.start); /* can't go wrong */ | ||
| 2156 | |||
| 2157 | - numbers[0] = e; | ||
| 2158 | - numbers[1] = d; | ||
| 2159 | - numbers[2] = n; | ||
| 2160 | - numbers[3] = iqmp; | ||
| 2161 | - numbers[4] = q; | ||
| 2162 | - numbers[5] = p; | ||
| 2163 | + numbers[0] = e; | ||
| 2164 | + numbers[1] = d; | ||
| 2165 | + numbers[2] = n; | ||
| 2166 | + numbers[3] = iqmp; | ||
| 2167 | + numbers[4] = q; | ||
| 2168 | + numbers[5] = p; | ||
| 2169 | |||
| 2170 | - nnumbers = 6; | ||
| 2171 | - initial_zero = 0; | ||
| 2172 | - type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}"; | ||
| 2173 | - } else if (key->alg == &ssh_dss) { | ||
| 2174 | - int pos; | ||
| 2175 | - struct mpint_pos p, q, g, y, x; | ||
| 2176 | + nnumbers = 6; | ||
| 2177 | + initial_zero = 0; | ||
| 2178 | + type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}"; | ||
| 2179 | + } else if (key->alg == &ssh_dss) { | ||
| 2180 | + int pos; | ||
| 2181 | + struct mpint_pos p, q, g, y, x; | ||
| 2182 | |||
| 2183 | - pos = 4 + GET_32BIT(pubblob); | ||
| 2184 | - pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p); | ||
| 2185 | - pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q); | ||
| 2186 | - pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g); | ||
| 2187 | - pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y); | ||
| 2188 | - pos = 0; | ||
| 2189 | - pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x); | ||
| 2190 | + pos = 4 + GET_32BIT(pubblob); | ||
| 2191 | + pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p); | ||
| 2192 | + pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q); | ||
| 2193 | + pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g); | ||
| 2194 | + pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y); | ||
| 2195 | + pos = 0; | ||
| 2196 | + pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x); | ||
| 2197 | |||
| 2198 | dropbear_assert(y.start && x.start); /* can't go wrong */ | ||
| 2199 | |||
| 2200 | - numbers[0] = p; | ||
| 2201 | - numbers[1] = g; | ||
| 2202 | - numbers[2] = q; | ||
| 2203 | - numbers[3] = y; | ||
| 2204 | - numbers[4] = x; | ||
| 2205 | + numbers[0] = p; | ||
| 2206 | + numbers[1] = g; | ||
| 2207 | + numbers[2] = q; | ||
| 2208 | + numbers[3] = y; | ||
| 2209 | + numbers[4] = x; | ||
| 2210 | |||
| 2211 | - nnumbers = 5; | ||
| 2212 | - initial_zero = 1; | ||
| 2213 | - type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}"; | ||
| 2214 | - } else { | ||
| 2215 | + nnumbers = 5; | ||
| 2216 | + initial_zero = 1; | ||
| 2217 | + type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}"; | ||
| 2218 | + } else { | ||
| 2219 | dropbear_assert(0); /* zoinks! */ | ||
| 2220 | - } | ||
| 2221 | + } | ||
| 2222 | |||
| 2223 | - /* | ||
| 2224 | - * Total size of key blob will be somewhere under 512 plus | ||
| 2225 | - * combined length of integers. We'll calculate the more | ||
| 2226 | - * precise size as we construct the blob. | ||
| 2227 | - */ | ||
| 2228 | - outlen = 512; | ||
| 2229 | - for (i = 0; i < nnumbers; i++) | ||
| 2230 | - outlen += 4 + numbers[i].bytes; | ||
| 2231 | - outblob = snewn(outlen, unsigned char); | ||
| 2232 | + /* | ||
| 2233 | + * Total size of key blob will be somewhere under 512 plus | ||
| 2234 | + * combined length of integers. We'll calculate the more | ||
| 2235 | + * precise size as we construct the blob. | ||
| 2236 | + */ | ||
| 2237 | + outlen = 512; | ||
| 2238 | + for (i = 0; i < nnumbers; i++) | ||
| 2239 | + outlen += 4 + numbers[i].bytes; | ||
| 2240 | + outblob = snewn(outlen, unsigned char); | ||
| 2241 | |||
| 2242 | - /* | ||
| 2243 | - * Create the unencrypted key blob. | ||
| 2244 | - */ | ||
| 2245 | - pos = 0; | ||
| 2246 | - PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4; | ||
| 2247 | - pos += 4; /* length field, fill in later */ | ||
| 2248 | - pos += put_string(outblob+pos, type, strlen(type)); | ||
| 2249 | - { | ||
| 2250 | - char *ciphertype = passphrase ? "3des-cbc" : "none"; | ||
| 2251 | - pos += put_string(outblob+pos, ciphertype, strlen(ciphertype)); | ||
| 2252 | - } | ||
| 2253 | - lenpos = pos; /* remember this position */ | ||
| 2254 | - pos += 4; /* encrypted-blob size */ | ||
| 2255 | - pos += 4; /* encrypted-payload size */ | ||
| 2256 | - if (initial_zero) { | ||
| 2257 | - PUT_32BIT(outblob+pos, 0); | ||
| 2258 | - pos += 4; | ||
| 2259 | - } | ||
| 2260 | - for (i = 0; i < nnumbers; i++) | ||
| 2261 | - pos += sshcom_put_mpint(outblob+pos, | ||
| 2262 | - numbers[i].start, numbers[i].bytes); | ||
| 2263 | - /* Now wrap up the encrypted payload. */ | ||
| 2264 | - PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8)); | ||
| 2265 | - /* Pad encrypted blob to a multiple of cipher block size. */ | ||
| 2266 | - if (passphrase) { | ||
| 2267 | - int padding = -(pos - (lenpos+4)) & 7; | ||
| 2268 | - while (padding--) | ||
| 2269 | - outblob[pos++] = random_byte(); | ||
| 2270 | - } | ||
| 2271 | - ciphertext = (char *)outblob+lenpos+4; | ||
| 2272 | - cipherlen = pos - (lenpos+4); | ||
| 2273 | + /* | ||
| 2274 | + * Create the unencrypted key blob. | ||
| 2275 | + */ | ||
| 2276 | + pos = 0; | ||
| 2277 | + PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4; | ||
| 2278 | + pos += 4; /* length field, fill in later */ | ||
| 2279 | + pos += put_string(outblob+pos, type, strlen(type)); | ||
| 2280 | + { | ||
| 2281 | + char *ciphertype = passphrase ? "3des-cbc" : "none"; | ||
| 2282 | + pos += put_string(outblob+pos, ciphertype, strlen(ciphertype)); | ||
| 2283 | + } | ||
| 2284 | + lenpos = pos; /* remember this position */ | ||
| 2285 | + pos += 4; /* encrypted-blob size */ | ||
| 2286 | + pos += 4; /* encrypted-payload size */ | ||
| 2287 | + if (initial_zero) { | ||
| 2288 | + PUT_32BIT(outblob+pos, 0); | ||
| 2289 | + pos += 4; | ||
| 2290 | + } | ||
| 2291 | + for (i = 0; i < nnumbers; i++) | ||
| 2292 | + pos += sshcom_put_mpint(outblob+pos, | ||
| 2293 | + numbers[i].start, numbers[i].bytes); | ||
| 2294 | + /* Now wrap up the encrypted payload. */ | ||
| 2295 | + PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8)); | ||
| 2296 | + /* Pad encrypted blob to a multiple of cipher block size. */ | ||
| 2297 | + if (passphrase) { | ||
| 2298 | + int padding = -(pos - (lenpos+4)) & 7; | ||
| 2299 | + while (padding--) | ||
| 2300 | + outblob[pos++] = random_byte(); | ||
| 2301 | + } | ||
| 2302 | + ciphertext = (char *)outblob+lenpos+4; | ||
| 2303 | + cipherlen = pos - (lenpos+4); | ||
| 2304 | dropbear_assert(!passphrase || cipherlen % 8 == 0); | ||
| 2305 | - /* Wrap up the encrypted blob string. */ | ||
| 2306 | - PUT_32BIT(outblob+lenpos, cipherlen); | ||
| 2307 | - /* And finally fill in the total length field. */ | ||
| 2308 | - PUT_32BIT(outblob+4, pos); | ||
| 2309 | + /* Wrap up the encrypted blob string. */ | ||
| 2310 | + PUT_32BIT(outblob+lenpos, cipherlen); | ||
| 2311 | + /* And finally fill in the total length field. */ | ||
| 2312 | + PUT_32BIT(outblob+4, pos); | ||
| 2313 | |||
| 2314 | dropbear_assert(pos < outlen); | ||
| 2315 | |||
| 2316 | + /* | ||
| 2317 | + * Encrypt the key. | ||
| 2318 | + */ | ||
| 2319 | + if (passphrase) { | ||
| 2320 | /* | ||
| 2321 | - * Encrypt the key. | ||
| 2322 | + * Derive encryption key from passphrase and iv/salt: | ||
| 2323 | + * | ||
| 2324 | + * - let block A equal MD5(passphrase) | ||
| 2325 | + * - let block B equal MD5(passphrase || A) | ||
| 2326 | + * - block C would be MD5(passphrase || A || B) and so on | ||
| 2327 | + * - encryption key is the first N bytes of A || B | ||
| 2328 | */ | ||
| 2329 | - if (passphrase) { | ||
| 2330 | - /* | ||
| 2331 | - * Derive encryption key from passphrase and iv/salt: | ||
| 2332 | - * | ||
| 2333 | - * - let block A equal MD5(passphrase) | ||
| 2334 | - * - let block B equal MD5(passphrase || A) | ||
| 2335 | - * - block C would be MD5(passphrase || A || B) and so on | ||
| 2336 | - * - encryption key is the first N bytes of A || B | ||
| 2337 | - */ | ||
| 2338 | - struct MD5Context md5c; | ||
| 2339 | - unsigned char keybuf[32], iv[8]; | ||
| 2340 | + struct MD5Context md5c; | ||
| 2341 | + unsigned char keybuf[32], iv[8]; | ||
| 2342 | |||
| 2343 | - MD5Init(&md5c); | ||
| 2344 | - MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 2345 | - MD5Final(keybuf, &md5c); | ||
| 2346 | + MD5Init(&md5c); | ||
| 2347 | + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 2348 | + MD5Final(keybuf, &md5c); | ||
| 2349 | |||
| 2350 | - MD5Init(&md5c); | ||
| 2351 | - MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 2352 | - MD5Update(&md5c, keybuf, 16); | ||
| 2353 | - MD5Final(keybuf+16, &md5c); | ||
| 2354 | - | ||
| 2355 | - /* | ||
| 2356 | - * Now decrypt the key blob. | ||
| 2357 | - */ | ||
| 2358 | - memset(iv, 0, sizeof(iv)); | ||
| 2359 | - des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, | ||
| 2360 | - cipherlen); | ||
| 2361 | - | ||
| 2362 | - memset(&md5c, 0, sizeof(md5c)); | ||
| 2363 | - memset(keybuf, 0, sizeof(keybuf)); | ||
| 2364 | - } | ||
| 2365 | + MD5Init(&md5c); | ||
| 2366 | + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | ||
| 2367 | + MD5Update(&md5c, keybuf, 16); | ||
| 2368 | + MD5Final(keybuf+16, &md5c); | ||
| 2369 | |||
| 2370 | /* | ||
| 2371 | - * And save it. We'll use Unix line endings just in case it's | ||
| 2372 | - * subsequently transferred in binary mode. | ||
| 2373 | + * Now decrypt the key blob. | ||
| 2374 | */ | ||
| 2375 | + memset(iv, 0, sizeof(iv)); | ||
| 2376 | + des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, | ||
| 2377 | + cipherlen); | ||
| 2378 | + | ||
| 2379 | + memset(&md5c, 0, sizeof(md5c)); | ||
| 2380 | + memset(keybuf, 0, sizeof(keybuf)); | ||
| 2381 | + } | ||
| 2382 | + | ||
| 2383 | + /* | ||
| 2384 | + * And save it. We'll use Unix line endings just in case it's | ||
| 2385 | + * subsequently transferred in binary mode. | ||
| 2386 | + */ | ||
| 2387 | fp = fopen(filename, "wb"); /* ensure Unix line endings */ | ||
| 2388 | - if (!fp) | ||
| 2389 | - goto error; | ||
| 2390 | - fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); | ||
| 2391 | - fprintf(fp, "Comment: \""); | ||
| 2392 | - /* | ||
| 2393 | - * Comment header is broken with backslash-newline if it goes | ||
| 2394 | - * over 70 chars. Although it's surrounded by quotes, it | ||
| 2395 | - * _doesn't_ escape backslashes or quotes within the string. | ||
| 2396 | - * Don't ask me, I didn't design it. | ||
| 2397 | - */ | ||
| 2398 | - { | ||
| 2399 | - int slen = 60; /* starts at 60 due to "Comment: " */ | ||
| 2400 | - char *c = key->comment; | ||
| 2401 | - while ((int)strlen(c) > slen) { | ||
| 2402 | - fprintf(fp, "%.*s\\\n", slen, c); | ||
| 2403 | - c += slen; | ||
| 2404 | - slen = 70; /* allow 70 chars on subsequent lines */ | ||
| 2405 | - } | ||
| 2406 | - fprintf(fp, "%s\"\n", c); | ||
| 2407 | + if (!fp) | ||
| 2408 | + goto error; | ||
| 2409 | + fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); | ||
| 2410 | + fprintf(fp, "Comment: \""); | ||
| 2411 | + /* | ||
| 2412 | + * Comment header is broken with backslash-newline if it goes | ||
| 2413 | + * over 70 chars. Although it's surrounded by quotes, it | ||
| 2414 | + * _doesn't_ escape backslashes or quotes within the string. | ||
| 2415 | + * Don't ask me, I didn't design it. | ||
| 2416 | + */ | ||
| 2417 | + { | ||
| 2418 | + int slen = 60; /* starts at 60 due to "Comment: " */ | ||
| 2419 | + char *c = key->comment; | ||
| 2420 | + while ((int)strlen(c) > slen) { | ||
| 2421 | + fprintf(fp, "%.*s\\\n", slen, c); | ||
| 2422 | + c += slen; | ||
| 2423 | + slen = 70; /* allow 70 chars on subsequent lines */ | ||
| 2424 | } | ||
| 2425 | + fprintf(fp, "%s\"\n", c); | ||
| 2426 | + } | ||
| 2427 | base64_encode_fp(fp, outblob, pos, 70); | ||
| 2428 | - fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); | ||
| 2429 | - fclose(fp); | ||
| 2430 | - ret = 1; | ||
| 2431 | + fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); | ||
| 2432 | + fclose(fp); | ||
| 2433 | + ret = 1; | ||
| 2434 | |||
| 2435 | - error: | ||
| 2436 | - if (outblob) { | ||
| 2437 | - memset(outblob, 0, outlen); | ||
| 2438 | + error: | ||
| 2439 | + if (outblob) { | ||
| 2440 | + memset(outblob, 0, outlen); | ||
| 2441 | m_free(outblob); | ||
| 2442 | - } | ||
| 2443 | - if (privblob) { | ||
| 2444 | - memset(privblob, 0, privlen); | ||
| 2445 | + } | ||
| 2446 | + if (privblob) { | ||
| 2447 | + memset(privblob, 0, privlen); | ||
| 2448 | m_free(privblob); | ||
| 2449 | - } | ||
| 2450 | - if (pubblob) { | ||
| 2451 | - memset(pubblob, 0, publen); | ||
| 2452 | + } | ||
| 2453 | + if (pubblob) { | ||
| 2454 | + memset(pubblob, 0, publen); | ||
| 2455 | m_free(pubblob); | ||
| 2456 | - } | ||
| 2457 | - return ret; | ||
| 2458 | + } | ||
| 2459 | + return ret; | ||
| 2460 | } | ||
| 2461 | #endif /* ssh.com stuff disabled */ | ||
| 2462 | + | ||
| 2463 | +/* From PuTTY misc.c */ | ||
| 2464 | +static int toint(unsigned u) | ||
| 2465 | +{ | ||
| 2466 | + /* | ||
| 2467 | + * Convert an unsigned to an int, without running into the | ||
| 2468 | + * undefined behaviour which happens by the strict C standard if | ||
| 2469 | + * the value overflows. You'd hope that sensible compilers would | ||
| 2470 | + * do the sensible thing in response to a cast, but actually I | ||
| 2471 | + * don't trust modern compilers not to do silly things like | ||
| 2472 | + * assuming that _obviously_ you wouldn't have caused an overflow | ||
| 2473 | + * and so they can elide an 'if (i < 0)' test immediately after | ||
| 2474 | + * the cast. | ||
| 2475 | + * | ||
| 2476 | + * Sensible compilers ought of course to optimise this entire | ||
| 2477 | + * function into 'just return the input value'! | ||
| 2478 | + */ | ||
| 2479 | + if (u <= (unsigned)INT_MAX) | ||
| 2480 | + return (int)u; | ||
| 2481 | + else if (u >= (unsigned)INT_MIN) /* wrap in cast _to_ unsigned is OK */ | ||
| 2482 | + return INT_MIN + (int)(u - (unsigned)INT_MIN); | ||
| 2483 | + else | ||
| 2484 | + return INT_MIN; /* fallback; should never occur on binary machines */ | ||
| 2485 | +} | ||
| 2486 | |||
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 0000000000..38ad8c3481 --- /dev/null +++ b/meta/recipes-core/dropbear/dropbear/CVE-2016-7408.patch | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | |||
| 2 | # HG changeset patch | ||
| 3 | # User Matt Johnston <matt@ucc.asn.au> | ||
| 4 | # Date 1468248038 -28800 | ||
| 5 | # Node ID eed9376a4ad68e3ae7f17d154dbf126ee66c54bc | ||
| 6 | # Parent 6a14b1f6dc04e70933c49ea335184e68c1deeb94 | ||
| 7 | improve algorithm list parsing | ||
| 8 | |||
| 9 | CVE: CVE-2016-7408 | ||
| 10 | Upstream-Status: Backport [backported from: | ||
| 11 | https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6] | ||
| 12 | |||
| 13 | Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> | ||
| 14 | |||
| 15 | diff -r 6a14b1f6dc04 -r eed9376a4ad6 common-algo.c | ||
| 16 | --- a/common-algo.c Mon Jul 11 21:51:25 2016 +0800 | ||
| 17 | +++ b/common-algo.c Mon Jul 11 22:40:38 2016 +0800 | ||
| 18 | @@ -531,21 +531,6 @@ | ||
| 19 | return NULL; | ||
| 20 | } | ||
| 21 | |||
| 22 | -static void | ||
| 23 | -try_add_algo(const char *algo_name, algo_type *algos, | ||
| 24 | - const char *algo_desc, algo_type * new_algos, int *num_ret) | ||
| 25 | -{ | ||
| 26 | - algo_type *match_algo = check_algo(algo_name, algos); | ||
| 27 | - if (!match_algo) | ||
| 28 | - { | ||
| 29 | - dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", algo_name, algo_desc); | ||
| 30 | - return; | ||
| 31 | - } | ||
| 32 | - | ||
| 33 | - new_algos[*num_ret] = *match_algo; | ||
| 34 | - (*num_ret)++; | ||
| 35 | -} | ||
| 36 | - | ||
| 37 | /* Checks a user provided comma-separated algorithm list for available | ||
| 38 | * options. Any that are not acceptable are removed in-place. Returns the | ||
| 39 | * number of valid algorithms. */ | ||
| 40 | @@ -553,30 +538,43 @@ | ||
| 41 | check_user_algos(const char* user_algo_list, algo_type * algos, | ||
| 42 | const char *algo_desc) | ||
| 43 | { | ||
| 44 | - algo_type new_algos[MAX_PROPOSED_ALGO]; | ||
| 45 | - /* this has two passes. first we sweep through the given list of | ||
| 46 | - * algorithms and mark them as usable=2 in the algo_type[] array... */ | ||
| 47 | - int num_ret = 0; | ||
| 48 | + algo_type new_algos[MAX_PROPOSED_ALGO+1]; | ||
| 49 | char *work_list = m_strdup(user_algo_list); | ||
| 50 | - char *last_name = work_list; | ||
| 51 | + char *start = work_list; | ||
| 52 | char *c; | ||
| 53 | - for (c = work_list; *c; c++) | ||
| 54 | + int n; | ||
| 55 | + /* So we can iterate and look for null terminator */ | ||
| 56 | + memset(new_algos, 0x0, sizeof(new_algos)); | ||
| 57 | + for (c = work_list, n = 0; ; c++) | ||
| 58 | { | ||
| 59 | - if (*c == ',') | ||
| 60 | - { | ||
| 61 | + char oc = *c; | ||
| 62 | + if (n >= MAX_PROPOSED_ALGO) { | ||
| 63 | + dropbear_exit("Too many algorithms '%s'", user_algo_list); | ||
| 64 | + } | ||
| 65 | + if (*c == ',' || *c == '\0') { | ||
| 66 | + algo_type *match_algo = NULL; | ||
| 67 | *c = '\0'; | ||
| 68 | - try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret); | ||
| 69 | + match_algo = check_algo(start, algos); | ||
| 70 | + if (match_algo) { | ||
| 71 | + if (check_algo(start, new_algos)) { | ||
| 72 | + TRACE(("Skip repeated algorithm '%s'", start)) | ||
| 73 | + } else { | ||
| 74 | + new_algos[n] = *match_algo; | ||
| 75 | + n++; | ||
| 76 | + } | ||
| 77 | + } else { | ||
| 78 | + dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", start, algo_desc); | ||
| 79 | + } | ||
| 80 | c++; | ||
| 81 | - last_name = c; | ||
| 82 | + start = c; | ||
| 83 | + } | ||
| 84 | + if (oc == '\0') { | ||
| 85 | + break; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | - try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret); | ||
| 89 | m_free(work_list); | ||
| 90 | - | ||
| 91 | - new_algos[num_ret].name = NULL; | ||
| 92 | - | ||
| 93 | - /* Copy one more as a blank delimiter */ | ||
| 94 | - memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1)); | ||
| 95 | - return num_ret; | ||
| 96 | + /* n+1 to include a null terminator */ | ||
| 97 | + memcpy(algos, new_algos, sizeof(*new_algos) * (n+1)); | ||
| 98 | + return n; | ||
| 99 | } | ||
| 100 | #endif /* ENABLE_USER_ALGO_LIST */ | ||
| 101 | |||
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 0000000000..1475475b4d --- /dev/null +++ b/meta/recipes-core/dropbear/dropbear/CVE-2016-7409.patch | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | |||
| 2 | # HG changeset patch | ||
| 3 | # User Matt Johnston <matt@ucc.asn.au> | ||
| 4 | # Date 1468245085 -28800 | ||
| 5 | # Node ID 6a14b1f6dc04e70933c49ea335184e68c1deeb94 | ||
| 6 | # Parent 309e1c4a87682b6ca7d80b8555a1db416c3cb7ac | ||
| 7 | better TRACE of failed remote ident | ||
| 8 | |||
| 9 | CVE: CVE-2016-7409 | ||
| 10 | Upstream-Status: Backport [backported from: | ||
| 11 | https://secure.ucc.asn.au/hg/dropbear/raw-rev/6a14b1f6dc04] | ||
| 12 | |||
| 13 | Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> | ||
| 14 | |||
| 15 | diff -r 309e1c4a8768 -r 6a14b1f6dc04 common-session.c | ||
| 16 | --- a/common-session.c Fri Mar 18 22:44:36 2016 +0800 | ||
| 17 | +++ b/common-session.c Mon Jul 11 21:51:25 2016 +0800 | ||
| 18 | @@ -361,7 +361,7 @@ | ||
| 19 | } | ||
| 20 | |||
| 21 | if (!done) { | ||
| 22 | - TRACE(("err: %s for '%s'\n", strerror(errno), linebuf)) | ||
| 23 | + TRACE(("error reading remote ident: %s\n", strerror(errno))) | ||
| 24 | ses.remoteclosed(); | ||
| 25 | } else { | ||
| 26 | /* linebuf is already null terminated */ | ||
| 27 | |||
