summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSona Sarmadi <sona.sarmadi@enea.com>2016-11-02 09:52:11 (GMT)
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-11-08 23:47:13 (GMT)
commitc4061a0a689fd3f4e3fb5d5dd6357dc542973d45 (patch)
tree55fa2e594e075f6de399f519211a31e6e7bcf23a
parent6962ee368906e096cf2df3031ca5142117e7c52a (diff)
downloadpoky-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>
-rw-r--r--meta/recipes-core/dropbear/dropbear.inc4
-rw-r--r--meta/recipes-core/dropbear/dropbear/CVE-2016-7406.patch102
-rw-r--r--meta/recipes-core/dropbear/dropbear/CVE-2016-7407.patch2486
-rw-r--r--meta/recipes-core/dropbear/dropbear/CVE-2016-7408.patch101
-rw-r--r--meta/recipes-core/dropbear/dropbear/CVE-2016-7409.patch27
5 files changed, 2720 insertions, 0 deletions
diff --git a/meta/recipes-core/dropbear/dropbear.inc b/meta/recipes-core/dropbear/dropbear.inc
index 923d31c..ee2cd98 100644
--- a/meta/recipes-core/dropbear/dropbear.inc
+++ b/meta/recipes-core/dropbear/dropbear.inc
@@ -17,6 +17,10 @@ SRC_URI = "http://matt.ucc.asn.au/dropbear/releases/dropbear-${PV}.tar.bz2 \
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 0000000..a582d0f
--- /dev/null
+++ b/meta/recipes-core/dropbear/dropbear/CVE-2016-7406.patch
@@ -0,0 +1,102 @@
1From 8fd720c3e319da773b48c0b191f049dbd1e3c7f0 Mon Sep 17 00:00:00 2001
2From: Matt Johnston <matt@ucc.asn.au>
3Date: Mon, 11 Jul 2016 23:09:33 +0800
4Subject: [PATCH] Improve exit message formatting
5
6CVE: CVE-2016-7406
7Upstream-Status: Backport [backported from:
8https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb]
9
10Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
11
12diff -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
56diff -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 0000000..64113c1
--- /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
7merge fixes from PuTTY import.c
8
9toint() from misc.c
10
11(revids are from hggit conversion)
12
13changeset: 4620:60a336a6c85c
14user: Simon Tatham <anakin@pobox.com>
15date: Thu Feb 25 20:26:33 2016 +0000
16files: import.c
17description:
18Fix potential segfaults in reading OpenSSH's ASN.1 key format.
19
20The length coming back from ber_read_id_len might have overflowed, so
21treat it as potentially negative. Also, while I'm here, accumulate it
22inside ber_read_id_len as an unsigned, so as to avoid undefined
23behaviour on integer overflow, and toint() it before return.
24
25Thanks to Hanno Böck for spotting this, with the aid of AFL.
26
27(cherry picked from commit 5b7833cd474a24ec098654dcba8cb9509f3bf2c1)
28
29Conflicts:
30 import.c
31
32(cherry-picker's note: resolving the conflict involved removing an
33entire section of the original commit which fixed ECDSA code not
34present on this branch)
35
36
37changeset: 4619:9c6c638d98d8
38user: Simon Tatham <anakin@pobox.com>
39date: Sun Jul 14 10:45:54 2013 +0000
40files: import.c ssh.c sshdss.c sshpubk.c sshrsa.c
41description:
42Tighten up a lot of casts from unsigned to int which are read by one
43of the GET_32BIT macros and then used as length fields. Missing bounds
44checks against zero have been added, and also I've introduced a helper
45function toint() which casts from unsigned to int in such a way as to
46avoid C undefined behaviour, since I'm not sure I trust compilers any
47more to do the obviously sensible thing.
48
49[originally from svn r9918]
50
51
52changeset: 4618:3957829f24d3
53user: Simon Tatham <anakin@pobox.com>
54date: Mon Jul 08 22:36:04 2013 +0000
55files: import.c sshdss.c sshrsa.c
56description:
57Add an assortment of extra safety checks.
58
59[originally from svn r9896]
60
61
62changeset: 4617:2cddee0bce12
63user: Jacob Nevins <jacobn@chiark.greenend.org.uk>
64date: Wed Dec 07 00:24:45 2005 +0000
65files: import.c
66description:
67Institutional failure to memset() things pointed at rather than pointers.
68Things should now be zeroed and memory not leaked. Spotted by Brant Thomsen.
69
70[originally from svn r6476]
71
72
73changeset: 4616:24ac78a9c71d
74user: Simon Tatham <anakin@pobox.com>
75date: Wed Feb 11 13:58:27 2004 +0000
76files: import.c
77description:
78Jacob's last-minute testing found a couple of trivial bugs in
79import.c, and my attempts to reproduce them in cmdgen found another
80one there :-)
81
82[originally from svn r3847]
83
84
85changeset: 4615:088d39a73db0
86user: Simon Tatham <anakin@pobox.com>
87date: Thu Jan 22 18:52:49 2004 +0000
88files: import.c
89description:
90Placate some gcc warnings.
91
92[originally from svn r3761]
93
94
95changeset: 4614:e4288bad4d93
96parent: 1758:108b8924593d
97user: Simon Tatham <anakin@pobox.com>
98date: Fri Oct 03 21:21:23 2003 +0000
99files: import.c
100description:
101My ASN.1 decoder returned wrong IDs for anything above 0x1E! Good
102job it's never had to yet. Ahem.
103
104[originally from svn r3479]
105
106
107CVE: CVE-2016-7407
108Upstream-Status: Backport [backported from:
109https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e]
110
111Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
112
113diff -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 0000000..38ad8c3
--- /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
7improve algorithm list parsing
8
9CVE: CVE-2016-7408
10Upstream-Status: Backport [backported from:
11https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6]
12
13Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
14
15diff -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 0000000..1475475
--- /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
7better TRACE of failed remote ident
8
9CVE: CVE-2016-7409
10Upstream-Status: Backport [backported from:
11https://secure.ucc.asn.au/hg/dropbear/raw-rev/6a14b1f6dc04]
12
13Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
14
15diff -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