diff options
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 | |||