]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - import.c
Be more careful about destroying sensitive data after private key
[PuTTY.git] / import.c
1 /*
2  * Code for PuTTY to import and export private key files in other
3  * SSH clients' formats.
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <assert.h>
9 #include <ctype.h>
10
11 #include "ssh.h"
12 #include "misc.h"
13
14 #define PUT_32BIT(cp, value) do { \
15   (cp)[3] = (value); \
16   (cp)[2] = (value) >> 8; \
17   (cp)[1] = (value) >> 16; \
18   (cp)[0] = (value) >> 24; } while (0)
19
20 #define GET_32BIT(cp) \
21     (((unsigned long)(unsigned char)(cp)[0] << 24) | \
22     ((unsigned long)(unsigned char)(cp)[1] << 16) | \
23     ((unsigned long)(unsigned char)(cp)[2] << 8) | \
24     ((unsigned long)(unsigned char)(cp)[3]))
25
26 int openssh_encrypted(char *filename);
27 struct ssh2_userkey *openssh_read(char *filename, char *passphrase);
28
29 int sshcom_encrypted(char *filename, char **comment);
30 struct ssh2_userkey *sshcom_read(char *filename, char *passphrase);
31
32 /*
33  * Given a key type, determine whether we know how to import it.
34  */
35 int import_possible(int type)
36 {
37     if (type == SSH_KEYTYPE_OPENSSH)
38         return 1;
39     if (type == SSH_KEYTYPE_SSHCOM)
40         return 1;
41     return 0;
42 }
43
44 /*
45  * Given a key type, determine what native key type
46  * (SSH_KEYTYPE_SSH1 or SSH_KEYTYPE_SSH2) it will come out as once
47  * we've imported it.
48  */
49 int import_target_type(int type)
50 {
51     /*
52      * There are no known foreign SSH1 key formats.
53      */
54     return SSH_KEYTYPE_SSH2;
55 }
56
57 /*
58  * Determine whether a foreign key is encrypted.
59  */
60 int import_encrypted(char *filename, int type, char **comment)
61 {
62     if (type == SSH_KEYTYPE_OPENSSH) {
63         *comment = filename;           /* OpenSSH doesn't do key comments */
64         return openssh_encrypted(filename);
65     }
66     if (type == SSH_KEYTYPE_SSHCOM) {
67         return sshcom_encrypted(filename, comment);
68     }
69     return 0;
70 }
71
72 /*
73  * Import an SSH1 key.
74  */
75 int import_ssh1(char *filename, int type, struct RSAKey *key, char *passphrase)
76 {
77     return 0;
78 }
79
80 /*
81  * Import an SSH2 key.
82  */
83 struct ssh2_userkey *import_ssh2(char *filename, int type, char *passphrase)
84 {
85     if (type == SSH_KEYTYPE_OPENSSH)
86         return openssh_read(filename, passphrase);
87     if (type == SSH_KEYTYPE_SSHCOM)
88         return sshcom_read(filename, passphrase);
89     return NULL;
90 }
91
92 /* ----------------------------------------------------------------------
93  * Helper routines. (The base64 ones are defined in sshpubk.c.)
94  */
95
96 #define isbase64(c) (    ((c) >= 'A' && (c) <= 'Z') || \
97                          ((c) >= 'a' && (c) <= 'z') || \
98                          ((c) >= '0' && (c) <= '9') || \
99                          (c) == '+' || (c) == '/' || (c) == '=' \
100                          )
101
102 extern int base64_decode_atom(char *atom, unsigned char *out);
103 extern int base64_lines(int datalen);
104 extern void base64_encode_atom(unsigned char *data, int n, char *out);
105 extern void base64_encode(FILE * fp, unsigned char *data, int datalen);
106
107 /*
108  * Read an ASN.1/BER identifier and length pair.
109  * 
110  * Flags are a combination of the #defines listed below.
111  * 
112  * Returns -1 if unsuccessful; otherwise returns the number of
113  * bytes used out of the source data.
114  */
115
116 /* ASN.1 tag classes. */
117 #define ASN1_CLASS_UNIVERSAL        (0 << 6)
118 #define ASN1_CLASS_APPLICATION      (1 << 6)
119 #define ASN1_CLASS_CONTEXT_SPECIFIC (2 << 6)
120 #define ASN1_CLASS_PRIVATE          (3 << 6)
121 #define ASN1_CLASS_MASK             (3 << 6)
122
123 /* Primitive versus constructed bit. */
124 #define ASN1_CONSTRUCTED            (1 << 5)
125
126 int ber_read_id_len(void *source, int sourcelen,
127                     int *id, int *length, int *flags)
128 {
129     unsigned char *p = (unsigned char *) source;
130
131     if (sourcelen == 0)
132         return -1;
133
134     *flags = (*p & 0xE0);
135     if ((*p & 0x1F) == 0x1F) {
136         *id = 0;
137         while (*p & 0x80) {
138             *id = (*id << 7) | (*p & 0x7F);
139             p++, sourcelen--;
140             if (sourcelen == 0)
141                 return -1;
142         }
143         *id = (*id << 7) | (*p & 0x7F);
144         p++, sourcelen--;
145     } else {
146         *id = *p & 0x1F;
147         p++, sourcelen--;
148     }
149
150     if (sourcelen == 0)
151         return -1;
152
153     if (*p & 0x80) {
154         int n = *p & 0x7F;
155         p++, sourcelen--;
156         if (sourcelen < n)
157             return -1;
158         *length = 0;
159         while (n--)
160             *length = (*length << 8) | (*p++);
161         sourcelen -= n;
162     } else {
163         *length = *p;
164         p++, sourcelen--;
165     }
166
167     return p - (unsigned char *) source;
168 }
169
170 static int put_string(void *target, void *data, int len)
171 {
172     unsigned char *d = (unsigned char *)target;
173
174     PUT_32BIT(d, len);
175     memcpy(d+4, data, len);
176     return len+4;
177 }
178
179 static int put_mp(void *target, void *data, int len)
180 {
181     unsigned char *d = (unsigned char *)target;
182     unsigned char *i = (unsigned char *)data;
183
184     if (*i & 0x80) {
185         PUT_32BIT(d, len+1);
186         d[4] = 0;
187         memcpy(d+5, data, len);
188         return len+5;
189     } else {
190         PUT_32BIT(d, len);
191         memcpy(d+4, data, len);
192         return len+4;
193     }
194 }
195
196 /* ----------------------------------------------------------------------
197  * Code to read OpenSSH private keys.
198  */
199
200 enum { OSSH_DSA, OSSH_RSA };
201 struct openssh_key {
202     int type;
203     int encrypted;
204     char iv[32];
205     unsigned char *keyblob;
206     int keyblob_len, keyblob_size;
207 };
208
209 struct openssh_key *load_openssh_key(char *filename)
210 {
211     struct openssh_key *ret;
212     FILE *fp;
213     char buffer[256];
214     char *errmsg, *p;
215     int headers_done;
216     char base64_bit[4];
217     int base64_chars = 0;
218
219     ret = smalloc(sizeof(*ret));
220     ret->keyblob = NULL;
221     ret->keyblob_len = ret->keyblob_size = 0;
222     ret->encrypted = 0;
223     memset(ret->iv, 0, sizeof(ret->iv));
224
225     fp = fopen(filename, "r");
226     if (!fp) {
227         errmsg = "Unable to open key file";
228         goto error;
229     }
230     if (!fgets(buffer, sizeof(buffer), fp) ||
231         0 != strncmp(buffer, "-----BEGIN ", 11) ||
232         0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) {
233         errmsg = "File does not begin with OpenSSH key header";
234         goto error;
235     }
236     if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n"))
237         ret->type = OSSH_RSA;
238     else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n"))
239         ret->type = OSSH_DSA;
240     else {
241         errmsg = "Unrecognised key type";
242         goto error;
243     }
244
245     headers_done = 0;
246     while (1) {
247         if (!fgets(buffer, sizeof(buffer), fp)) {
248             errmsg = "Unexpected end of file";
249             goto error;
250         }
251         if (0 == strncmp(buffer, "-----END ", 9) &&
252             0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n"))
253             break;                     /* done */
254         if ((p = strchr(buffer, ':')) != NULL) {
255             if (headers_done) {
256                 errmsg = "Header found in body of key data";
257                 goto error;
258             }
259             *p++ = '\0';
260             while (*p && isspace((unsigned char)*p)) p++;
261             if (!strcmp(buffer, "Proc-Type")) {
262                 if (p[0] != '4' || p[1] != ',') {
263                     errmsg = "Proc-Type is not 4 (only 4 is supported)";
264                     goto error;
265                 }
266                 p += 2;
267                 if (!strcmp(p, "ENCRYPTED\n"))
268                     ret->encrypted = 1;
269             } else if (!strcmp(buffer, "DEK-Info")) {
270                 int i, j;
271
272                 if (strncmp(p, "DES-EDE3-CBC,", 13)) {
273                     errmsg = "Ciphers other than DES-EDE3-CBC not supported";
274                     goto error;
275                 }
276                 p += 13;
277                 for (i = 0; i < 8; i++) {
278                     if (1 != sscanf(p, "%2x", &j))
279                         break;
280                     ret->iv[i] = j;
281                     p += 2;
282                 }
283                 if (i < 8) {
284                     errmsg = "Expected 16-digit iv in DEK-Info";
285                     goto error;
286                 }
287             }
288         } else {
289             headers_done = 1;
290
291             p = buffer;
292             while (isbase64(*p)) {
293                 base64_bit[base64_chars++] = *p;
294                 if (base64_chars == 4) {
295                     unsigned char out[3];
296                     int len;
297
298                     base64_chars = 0;
299
300                     len = base64_decode_atom(base64_bit, out);
301
302                     if (len <= 0) {
303                         errmsg = "Invalid base64 encoding";
304                         goto error;
305                     }
306
307                     if (ret->keyblob_len + len > ret->keyblob_size) {
308                         ret->keyblob_size = ret->keyblob_len + len + 256;
309                         ret->keyblob = srealloc(ret->keyblob, ret->keyblob_size);
310                     }
311
312                     memcpy(ret->keyblob + ret->keyblob_len, out, len);
313                     ret->keyblob_len += len;
314
315                     memset(out, 0, sizeof(out));
316                 }
317
318                 p++;
319             }
320         }
321     }
322
323     if (ret->keyblob_len == 0 || !ret->keyblob) {
324         errmsg = "Key body not present";
325         goto error;
326     }
327
328     if (ret->encrypted && ret->keyblob_len % 8 != 0) {
329         errmsg = "Encrypted key blob is not a multiple of cipher block size";
330         goto error;
331     }
332
333     memset(buffer, 0, sizeof(buffer));
334     memset(base64_bit, 0, sizeof(base64_bit));
335     return ret;
336
337     error:
338     memset(buffer, 0, sizeof(buffer));
339     memset(base64_bit, 0, sizeof(base64_bit));
340     if (ret) {
341         if (ret->keyblob) {
342             memset(ret->keyblob, 0, ret->keyblob_size);
343             sfree(ret->keyblob);
344         }
345         memset(&ret, 0, sizeof(ret));
346         sfree(ret);
347     }
348     return NULL;
349 }
350
351 int openssh_encrypted(char *filename)
352 {
353     struct openssh_key *key = load_openssh_key(filename);
354     int ret;
355
356     if (!key)
357         return 0;
358     ret = key->encrypted;
359     memset(key->keyblob, 0, key->keyblob_size);
360     sfree(key->keyblob);
361     memset(&key, 0, sizeof(key));
362     sfree(key);
363     return ret;
364 }
365
366 struct ssh2_userkey *openssh_read(char *filename, char *passphrase)
367 {
368     struct openssh_key *key = load_openssh_key(filename);
369     struct ssh2_userkey *retkey;
370     unsigned char *p;
371     int ret, id, len, flags;
372     int i, num_integers;
373     struct ssh2_userkey *retval = NULL;
374     char *errmsg;
375     unsigned char *blob;
376     int blobsize, blobptr, privptr;
377     char *modptr;
378     int modlen;
379
380     if (!key)
381         return NULL;
382
383     if (key->encrypted) {
384         /*
385          * Derive encryption key from passphrase and iv/salt:
386          * 
387          *  - let block A equal MD5(passphrase || iv)
388          *  - let block B equal MD5(A || passphrase || iv)
389          *  - block C would be MD5(B || passphrase || iv) and so on
390          *  - encryption key is the first N bytes of A || B
391          */
392         struct MD5Context md5c;
393         unsigned char keybuf[32];
394
395         MD5Init(&md5c);
396         MD5Update(&md5c, passphrase, strlen(passphrase));
397         MD5Update(&md5c, key->iv, 8);
398         MD5Final(keybuf, &md5c);
399
400         MD5Init(&md5c);
401         MD5Update(&md5c, keybuf, 16);
402         MD5Update(&md5c, passphrase, strlen(passphrase));
403         MD5Update(&md5c, key->iv, 8);
404         MD5Final(keybuf+16, &md5c);
405
406         /*
407          * Now decrypt the key blob.
408          */
409         des3_decrypt_pubkey_ossh(keybuf, key->iv,
410                                  key->keyblob, key->keyblob_len);
411
412         memset(&md5c, 0, sizeof(md5c));
413         memset(keybuf, 0, sizeof(keybuf));
414     }
415
416     /*
417      * Now we have a decrypted key blob, which contains an ASN.1
418      * encoded private key. We must now untangle the ASN.1.
419      *
420      * We expect the whole key blob to be formatted as a SEQUENCE
421      * (0x30 followed by a length code indicating that the rest of
422      * the blob is part of the sequence). Within that SEQUENCE we
423      * expect to see a bunch of INTEGERs. What those integers mean
424      * depends on the key type:
425      *
426      *  - For RSA, we expect the integers to be 0, n, e, d, p, q,
427      *    dmp1, dmq1, iqmp in that order. (The last three are d mod
428      *    (p-1), d mod (q-1), inverse of q mod p respectively.)
429      *
430      *  - For DSA, we expect them to be 0, p, q, g, y, x in that
431      *    order.
432      */
433     
434     p = key->keyblob;
435
436     /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */
437     ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags);
438     p += ret;
439     if (ret < 0 || id != 16) {
440         errmsg = "ASN.1 decoding failure";
441         retval = SSH2_WRONG_PASSPHRASE;
442         goto error;
443     }
444
445     /* Expect a load of INTEGERs. */
446     if (key->type == OSSH_RSA)
447         num_integers = 9;
448     else if (key->type == OSSH_DSA)
449         num_integers = 6;
450
451     /*
452      * Space to create key blob in.
453      */
454     blobsize = 256+key->keyblob_len;
455     blob = smalloc(blobsize);
456     PUT_32BIT(blob, 7);
457     if (key->type == OSSH_DSA)
458         memcpy(blob+4, "ssh-dss", 7);
459     else if (key->type == OSSH_RSA)
460         memcpy(blob+4, "ssh-rsa", 7);
461     blobptr = 4+7;
462     privptr = -1;
463
464     for (i = 0; i < num_integers; i++) {
465         ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
466                               &id, &len, &flags);
467         p += ret;
468         if (ret < 0 || id != 2 ||
469             key->keyblob+key->keyblob_len-p < len) {
470             errmsg = "ASN.1 decoding failure";
471             goto error;
472         }
473
474         if (i == 0) {
475             /*
476              * The first integer should be zero always (I think
477              * this is some sort of version indication).
478              */
479             if (len != 1 || p[0] != 0) {
480                 errmsg = "Version number mismatch";
481                 goto error;
482             }
483         } else if (key->type == OSSH_RSA) {
484             /*
485              * Integers 1 and 2 go into the public blob but in the
486              * opposite order; integers 3, 4, 5 and 8 go into the
487              * private blob. The other two (6 and 7) are ignored.
488              */
489             if (i == 1) {
490                 /* Save the details for after we deal with number 2. */
491                 modptr = p;
492                 modlen = len;
493             } else if (i != 6 && i != 7) {
494                 PUT_32BIT(blob+blobptr, len);
495                 memcpy(blob+blobptr+4, p, len);
496                 blobptr += 4+len;
497                 if (i == 2) {
498                     PUT_32BIT(blob+blobptr, modlen);
499                     memcpy(blob+blobptr+4, modptr, modlen);
500                     blobptr += 4+modlen;
501                     privptr = blobptr;
502                 }
503             }
504         } else if (key->type == OSSH_DSA) {
505             /*
506              * Integers 1-4 go into the public blob; integer 5 goes
507              * into the private blob.
508              */
509             PUT_32BIT(blob+blobptr, len);
510             memcpy(blob+blobptr+4, p, len);
511             blobptr += 4+len;
512             if (i == 4)
513                 privptr = blobptr;
514         }
515
516         /* Skip past the number. */
517         p += len;
518     }
519
520     /*
521      * Now put together the actual key. Simplest way to do this is
522      * to assemble our own key blobs and feed them to the createkey
523      * functions; this is a bit faffy but it does mean we get all
524      * the sanity checks for free.
525      */
526     assert(privptr > 0);               /* should have bombed by now if not */
527     retkey = smalloc(sizeof(struct ssh2_userkey));
528     retkey->alg = (key->type == OSSH_RSA ? &ssh_rsa : &ssh_dss);
529     retkey->data = retkey->alg->createkey(blob, privptr,
530                                           blob+privptr, blobptr-privptr);
531     if (!retkey->data) {
532         sfree(retkey);
533         errmsg = "unable to create key data structure";
534         goto error;
535     }
536
537     retkey->comment = dupstr("imported-openssh-key");
538     errmsg = NULL;                     /* no error */
539     retval = retkey;
540
541     error:
542     if (blob) {
543         memset(blob, 0, blobsize);
544         sfree(blob);
545     }
546     memset(key->keyblob, 0, key->keyblob_size);
547     sfree(key->keyblob);
548     memset(&key, 0, sizeof(key));
549     sfree(key);
550     return retval;
551 }
552
553 /* ----------------------------------------------------------------------
554  * Code to read ssh.com private keys.
555  */
556
557 /*
558  * The format of the base64 blob is largely ssh2-packet-formatted,
559  * except that mpints are a bit different: they're more like the
560  * old ssh1 mpint. You have a 32-bit bit count N, followed by
561  * (N+7)/8 bytes of data.
562  * 
563  * So. The blob contains:
564  * 
565  *  - uint32 0x3f6ff9eb       (magic number)
566  *  - uint32 size             (total blob size)
567  *  - string key-type         (see below)
568  *  - string cipher-type      (tells you if key is encrypted)
569  *  - string encrypted-blob
570  * 
571  * (The first size field includes the size field itself and the
572  * magic number before it. All other size fields are ordinary ssh2
573  * strings, so the size field indicates how much data is to
574  * _follow_.)
575  * 
576  * The encrypted blob, once decrypted, contains a single string
577  * which in turn contains the payload. (This allows padding to be
578  * added after that string while still making it clear where the
579  * real payload ends. Also it probably makes for a reasonable
580  * decryption check.)
581  * 
582  * The payload blob, for an RSA key, contains:
583  *  - mpint e
584  *  - mpint d
585  *  - mpint n  (yes, the public and private stuff is intermixed)
586  *  - mpint u  (presumably inverse of p mod q)
587  *  - mpint p  (p is the smaller prime)
588  *  - mpint q  (q is the larger)
589  * 
590  * For a DSA key, the payload blob contains:
591  *  - uint32 0
592  *  - mpint p
593  *  - mpint g
594  *  - mpint q
595  *  - mpint y
596  *  - mpint x
597  * 
598  * Alternatively, if the parameters are `predefined', that
599  * (0,p,g,q) sequence can be replaced by a uint32 1 and a string
600  * containing some predefined parameter specification. *shudder*,
601  * but I doubt we'll encounter this in real life.
602  * 
603  * The key type strings are ghastly. The RSA key I looked at had a
604  * type string of
605  * 
606  *   `if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}'
607  * 
608  * and the DSA key wasn't much better:
609  * 
610  *   `dl-modp{sign{dsa-nist-sha1},dh{plain}}'
611  * 
612  * It isn't clear that these will always be the same. I think it
613  * might be wise just to look at the `if-modn{sign{rsa' and
614  * `dl-modp{sign{dsa' prefixes.
615  * 
616  * Finally, the encryption. The cipher-type string appears to be
617  * either `none' or `3des-cbc'. Looks as if this is SSH2-style
618  * 3des-cbc (i.e. outer cbc rather than inner). The key is created
619  * from the passphrase by means of yet another hashing faff:
620  * 
621  *  - first 16 bytes are MD5(passphrase)
622  *  - next 16 bytes are MD5(passphrase || first 16 bytes)
623  *  - if there were more, they'd be MD5(passphrase || first 32),
624  *    and so on.
625  */
626
627 struct sshcom_key {
628     char comment[256];                 /* allowing any length is overkill */
629     unsigned char *keyblob;
630     int keyblob_len, keyblob_size;
631 };
632
633 struct sshcom_key *load_sshcom_key(char *filename)
634 {
635     struct sshcom_key *ret;
636     FILE *fp;
637     char buffer[256];
638     int len;
639     char *errmsg, *p;
640     int headers_done;
641     char base64_bit[4];
642     int base64_chars = 0;
643
644     ret = smalloc(sizeof(*ret));
645     ret->comment[0] = '\0';
646     ret->keyblob = NULL;
647     ret->keyblob_len = ret->keyblob_size = 0;
648
649     fp = fopen(filename, "r");
650     if (!fp) {
651         errmsg = "Unable to open key file";
652         goto error;
653     }
654     if (!fgets(buffer, sizeof(buffer), fp) ||
655         0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) {
656         errmsg = "File does not begin with ssh.com key header";
657         goto error;
658     }
659
660     headers_done = 0;
661     while (1) {
662         if (!fgets(buffer, sizeof(buffer), fp)) {
663             errmsg = "Unexpected end of file";
664             goto error;
665         }
666         if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n"))
667             break;                     /* done */
668         if ((p = strchr(buffer, ':')) != NULL) {
669             if (headers_done) {
670                 errmsg = "Header found in body of key data";
671                 goto error;
672             }
673             *p++ = '\0';
674             while (*p && isspace((unsigned char)*p)) p++;
675             /*
676              * Header lines can end in a trailing backslash for
677              * continuation.
678              */
679             while ((len = strlen(p)) > sizeof(buffer) - (p-buffer) -1 ||
680                    p[len-1] != '\n' || p[len-2] == '\\') {
681                 if (len > (p-buffer) + sizeof(buffer)-2) {
682                     errmsg = "Header line too long to deal with";
683                     goto error;
684                 }
685                 if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) {
686                     errmsg = "Unexpected end of file";
687                     goto error;
688                 }
689             }
690             p[strcspn(p, "\n")] = '\0';
691             if (!strcmp(buffer, "Comment")) {
692                 /* Strip quotes in comment if present. */
693                 if (p[0] == '"' && p[strlen(p)-1] == '"') {
694                     p++;
695                     p[strlen(p)-1] = '\0';
696                 }
697                 strncpy(ret->comment, p, sizeof(ret->comment));
698                 ret->comment[sizeof(ret->comment)-1] = '\0';
699             }
700         } else {
701             headers_done = 1;
702
703             p = buffer;
704             while (isbase64(*p)) {
705                 base64_bit[base64_chars++] = *p;
706                 if (base64_chars == 4) {
707                     unsigned char out[3];
708
709                     base64_chars = 0;
710
711                     len = base64_decode_atom(base64_bit, out);
712
713                     if (len <= 0) {
714                         errmsg = "Invalid base64 encoding";
715                         goto error;
716                     }
717
718                     if (ret->keyblob_len + len > ret->keyblob_size) {
719                         ret->keyblob_size = ret->keyblob_len + len + 256;
720                         ret->keyblob = srealloc(ret->keyblob, ret->keyblob_size);
721                     }
722
723                     memcpy(ret->keyblob + ret->keyblob_len, out, len);
724                     ret->keyblob_len += len;
725                 }
726
727                 p++;
728             }
729         }
730     }
731
732     if (ret->keyblob_len == 0 || !ret->keyblob) {
733         errmsg = "Key body not present";
734         goto error;
735     }
736
737     return ret;
738
739     error:
740     if (ret) {
741         if (ret->keyblob) {
742             memset(ret->keyblob, 0, ret->keyblob_size);
743             sfree(ret->keyblob);
744         }
745         memset(&ret, 0, sizeof(ret));
746         sfree(ret);
747     }
748     return NULL;
749 }
750
751 int sshcom_encrypted(char *filename, char **comment)
752 {
753     struct sshcom_key *key = load_sshcom_key(filename);
754     int pos, len, answer;
755
756     *comment = NULL;
757     if (!key)
758         return 0;
759
760     /*
761      * Check magic number.
762      */
763     if (GET_32BIT(key->keyblob) != 0x3f6ff9eb)
764         return 0;                      /* key is invalid */
765
766     /*
767      * Find the cipher-type string.
768      */
769     answer = 0;
770     pos = 8;
771     if (key->keyblob_len < pos+4)
772         goto done;                     /* key is far too short */
773     pos += 4 + GET_32BIT(key->keyblob + pos);   /* skip key type */
774     if (key->keyblob_len < pos+4)
775         goto done;                     /* key is far too short */
776     len = GET_32BIT(key->keyblob + pos);   /* find cipher-type length */
777     if (key->keyblob_len < pos+4+len)
778         goto done;                     /* cipher type string is incomplete */
779     if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4))
780         answer = 1;
781
782     done:
783     *comment = dupstr(key->comment);
784     memset(key->keyblob, 0, key->keyblob_size);
785     sfree(key->keyblob);
786     memset(&key, 0, sizeof(key));
787     sfree(key);
788     return answer;
789 }
790
791 struct mpint_pos { void *start; int bytes; };
792
793 int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret)
794 {
795     int bits;
796     int bytes;
797     unsigned char *d = (unsigned char *) data;
798
799     if (len < 4)
800         goto error;
801     bits = GET_32BIT(d);
802
803     bytes = (bits + 7) / 8;
804     if (len < 4+bytes)
805         goto error;
806
807     ret->start = d + 4;
808     ret->bytes = bytes;
809     return bytes+4;
810
811     error:
812     ret->start = NULL;
813     ret->bytes = -1;
814     return len;                        /* ensure further calls fail as well */
815 }
816
817 struct ssh2_userkey *sshcom_read(char *filename, char *passphrase)
818 {
819     struct sshcom_key *key = load_sshcom_key(filename);
820     char *errmsg;
821     int pos, len;
822     const char prefix_rsa[] = "if-modn{sign{rsa";
823     const char prefix_dsa[] = "dl-modp{sign{dsa";
824     enum { RSA, DSA } type;
825     int encrypted;
826     char *ciphertext;
827     int cipherlen;
828     struct ssh2_userkey *ret = NULL, *retkey;
829     const struct ssh_signkey *alg;
830     unsigned char *blob = NULL;
831     int blobsize, publen, privlen;
832
833     if (!key)
834         return NULL;
835
836     /*
837      * Check magic number.
838      */
839     if (GET_32BIT(key->keyblob) != 0x3f6ff9eb) {
840         errmsg = "Key does not begin with magic number";
841         goto error;
842     }
843
844     /*
845      * Determine the key type.
846      */
847     pos = 8;
848     if (key->keyblob_len < pos+4 ||
849         (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
850         errmsg = "Key blob does not contain a key type string";
851         goto error;
852     }
853     if (len > sizeof(prefix_rsa) - 1 &&
854         !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) {
855         type = RSA;
856     } else if (len > sizeof(prefix_dsa) - 1 &&
857         !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) {
858         type = DSA;
859     } else {
860         errmsg = "Key is of unknown type";
861         goto error;
862     }
863     pos += 4+len;
864
865     /*
866      * Determine the cipher type.
867      */
868     if (key->keyblob_len < pos+4 ||
869         (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
870         errmsg = "Key blob does not contain a cipher type string";
871         goto error;
872     }
873     if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4))
874         encrypted = 0;
875     else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8))
876         encrypted = 1;
877     else {
878         errmsg = "Key encryption is of unknown type";
879         goto error;
880     }
881     pos += 4+len;
882
883     /*
884      * Get hold of the encrypted part of the key.
885      */
886     if (key->keyblob_len < pos+4 ||
887         (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
888         errmsg = "Key blob does not contain actual key data";
889         goto error;
890     }
891     ciphertext = key->keyblob + pos + 4;
892     cipherlen = len;
893     if (cipherlen == 0) {
894         errmsg = "Length of key data is zero";
895         goto error;
896     }
897
898     /*
899      * Decrypt it if necessary.
900      */
901     if (encrypted) {
902         /*
903          * Derive encryption key from passphrase and iv/salt:
904          * 
905          *  - let block A equal MD5(passphrase)
906          *  - let block B equal MD5(passphrase || A)
907          *  - block C would be MD5(passphrase || A || B) and so on
908          *  - encryption key is the first N bytes of A || B
909          */
910         struct MD5Context md5c;
911         unsigned char keybuf[32], iv[8];
912
913         if (cipherlen % 8 != 0) {
914             errmsg = "Encrypted part of key is not a multiple of cipher block"
915                 " size";
916             goto error;
917         }
918
919         MD5Init(&md5c);
920         MD5Update(&md5c, passphrase, strlen(passphrase));
921         MD5Final(keybuf, &md5c);
922
923         MD5Init(&md5c);
924         MD5Update(&md5c, passphrase, strlen(passphrase));
925         MD5Update(&md5c, keybuf, 16);
926         MD5Final(keybuf+16, &md5c);
927
928         /*
929          * Now decrypt the key blob.
930          */
931         memset(iv, 0, sizeof(iv));
932         des3_decrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen);
933
934         memset(&md5c, 0, sizeof(md5c));
935         memset(keybuf, 0, sizeof(keybuf));
936
937         /*
938          * Hereafter we return WRONG_PASSPHRASE for any parsing
939          * error. (But only if we've just tried to decrypt it!
940          * Returning WRONG_PASSPHRASE for an unencrypted key is
941          * automatic doom.)
942          */
943         if (encrypted)
944             ret = SSH2_WRONG_PASSPHRASE;
945     }
946
947     /*
948      * Strip away the containing string to get to the real meat.
949      */
950     len = GET_32BIT(ciphertext);
951     if (len > cipherlen-4) {
952         errmsg = "containing string was ill-formed";
953         goto error;
954     }
955     ciphertext += 4;
956     cipherlen = len;
957
958     /*
959      * Now we break down into RSA versus DSA. In either case we'll
960      * construct public and private blobs in our own format, and
961      * end up feeding them to alg->createkey().
962      */
963     blobsize = cipherlen + 256;
964     blob = smalloc(blobsize);
965     privlen = 0;
966     if (type == RSA) {
967         struct mpint_pos n, e, d, u, p, q;
968         int pos = 0;
969         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e);
970         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d);
971         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n);
972         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u);
973         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
974         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
975         if (!q.start) {
976             errmsg = "key data did not contain six integers";
977             goto error;
978         }
979
980         alg = &ssh_rsa;
981         pos = 0;
982         pos += put_string(blob+pos, "ssh-rsa", 7);
983         pos += put_mp(blob+pos, e.start, e.bytes);
984         pos += put_mp(blob+pos, n.start, n.bytes);
985         publen = pos;
986         pos += put_string(blob+pos, d.start, d.bytes);
987         pos += put_mp(blob+pos, q.start, q.bytes);
988         pos += put_mp(blob+pos, p.start, p.bytes);
989         pos += put_mp(blob+pos, u.start, u.bytes);
990         privlen = pos - publen;
991     } else if (type == DSA) {
992         struct mpint_pos p, q, g, x, y;
993         int pos = 4;
994         if (GET_32BIT(ciphertext) != 0) {
995             errmsg = "predefined DSA parameters not supported";
996             goto error;
997         }
998         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
999         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g);
1000         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
1001         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y);
1002         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x);
1003         if (!x.start) {
1004             errmsg = "key data did not contain five integers";
1005             goto error;
1006         }
1007
1008         alg = &ssh_dss;
1009         pos = 0;
1010         pos += put_string(blob+pos, "ssh-dss", 7);
1011         pos += put_mp(blob+pos, p.start, p.bytes);
1012         pos += put_mp(blob+pos, q.start, q.bytes);
1013         pos += put_mp(blob+pos, g.start, g.bytes);
1014         pos += put_mp(blob+pos, y.start, y.bytes);
1015         publen = pos;
1016         pos += put_mp(blob+pos, x.start, x.bytes);
1017         privlen = pos - publen;
1018     }
1019
1020     assert(privlen > 0);               /* should have bombed by now if not */
1021
1022     retkey = smalloc(sizeof(struct ssh2_userkey));
1023     retkey->alg = alg;
1024     retkey->data = alg->createkey(blob, publen, blob+publen, privlen);
1025     if (!retkey->data) {
1026         sfree(retkey);
1027         errmsg = "unable to create key data structure";
1028         goto error;
1029     }
1030     retkey->comment = dupstr(key->comment);
1031
1032     errmsg = NULL; /* no error */
1033     ret = retkey;
1034
1035     error:
1036     if (blob) {
1037         memset(blob, 0, blobsize);
1038         sfree(blob);
1039     }
1040     memset(key->keyblob, 0, key->keyblob_size);
1041     sfree(key->keyblob);
1042     memset(&key, 0, sizeof(key));
1043     sfree(key);
1044     return ret;
1045 }