]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - import.c
Move prototypes for base64_decode_atom(), base64_lines(), and base64_encode()
[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] = (unsigned char)(value); \
16   (cp)[2] = (unsigned char)((value) >> 8); \
17   (cp)[1] = (unsigned char)((value) >> 16); \
18   (cp)[0] = (unsigned char)((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 int openssh_write(char *filename, struct ssh2_userkey *key, char *passphrase);
29
30 int sshcom_encrypted(char *filename, char **comment);
31 struct ssh2_userkey *sshcom_read(char *filename, char *passphrase);
32 int sshcom_write(char *filename, struct ssh2_userkey *key, char *passphrase);
33
34 /*
35  * Given a key type, determine whether we know how to import it.
36  */
37 int import_possible(int type)
38 {
39     if (type == SSH_KEYTYPE_OPENSSH)
40         return 1;
41     if (type == SSH_KEYTYPE_SSHCOM)
42         return 1;
43     return 0;
44 }
45
46 /*
47  * Given a key type, determine what native key type
48  * (SSH_KEYTYPE_SSH1 or SSH_KEYTYPE_SSH2) it will come out as once
49  * we've imported it.
50  */
51 int import_target_type(int type)
52 {
53     /*
54      * There are no known foreign SSH1 key formats.
55      */
56     return SSH_KEYTYPE_SSH2;
57 }
58
59 /*
60  * Determine whether a foreign key is encrypted.
61  */
62 int import_encrypted(char *filename, int type, char **comment)
63 {
64     if (type == SSH_KEYTYPE_OPENSSH) {
65         *comment = dupstr(filename);   /* OpenSSH doesn't do key comments */
66         return openssh_encrypted(filename);
67     }
68     if (type == SSH_KEYTYPE_SSHCOM) {
69         return sshcom_encrypted(filename, comment);
70     }
71     return 0;
72 }
73
74 /*
75  * Import an SSH1 key.
76  */
77 int import_ssh1(char *filename, int type, struct RSAKey *key, char *passphrase)
78 {
79     return 0;
80 }
81
82 /*
83  * Import an SSH2 key.
84  */
85 struct ssh2_userkey *import_ssh2(char *filename, int type, char *passphrase)
86 {
87     if (type == SSH_KEYTYPE_OPENSSH)
88         return openssh_read(filename, passphrase);
89     if (type == SSH_KEYTYPE_SSHCOM)
90         return sshcom_read(filename, passphrase);
91     return NULL;
92 }
93
94 /*
95  * Export an SSH1 key.
96  */
97 int export_ssh1(char *filename, int type, struct RSAKey *key, char *passphrase)
98 {
99     return 0;
100 }
101
102 /*
103  * Export an SSH2 key.
104  */
105 int export_ssh2(char *filename, int type,
106                 struct ssh2_userkey *key, char *passphrase)
107 {
108     if (type == SSH_KEYTYPE_OPENSSH)
109         return openssh_write(filename, key, passphrase);
110     if (type == SSH_KEYTYPE_SSHCOM)
111         return sshcom_write(filename, key, passphrase);
112     return 0;
113 }
114
115 /* ----------------------------------------------------------------------
116  * Helper routines. (The base64 ones are defined in sshpubk.c.)
117  */
118
119 #define isbase64(c) (    ((c) >= 'A' && (c) <= 'Z') || \
120                          ((c) >= 'a' && (c) <= 'z') || \
121                          ((c) >= '0' && (c) <= '9') || \
122                          (c) == '+' || (c) == '/' || (c) == '=' \
123                          )
124
125 /*
126  * Read an ASN.1/BER identifier and length pair.
127  * 
128  * Flags are a combination of the #defines listed below.
129  * 
130  * Returns -1 if unsuccessful; otherwise returns the number of
131  * bytes used out of the source data.
132  */
133
134 /* ASN.1 tag classes. */
135 #define ASN1_CLASS_UNIVERSAL        (0 << 6)
136 #define ASN1_CLASS_APPLICATION      (1 << 6)
137 #define ASN1_CLASS_CONTEXT_SPECIFIC (2 << 6)
138 #define ASN1_CLASS_PRIVATE          (3 << 6)
139 #define ASN1_CLASS_MASK             (3 << 6)
140
141 /* Primitive versus constructed bit. */
142 #define ASN1_CONSTRUCTED            (1 << 5)
143
144 int ber_read_id_len(void *source, int sourcelen,
145                     int *id, int *length, int *flags)
146 {
147     unsigned char *p = (unsigned char *) source;
148
149     if (sourcelen == 0)
150         return -1;
151
152     *flags = (*p & 0xE0);
153     if ((*p & 0x1F) == 0x1F) {
154         *id = 0;
155         while (*p & 0x80) {
156             *id = (*id << 7) | (*p & 0x7F);
157             p++, sourcelen--;
158             if (sourcelen == 0)
159                 return -1;
160         }
161         *id = (*id << 7) | (*p & 0x7F);
162         p++, sourcelen--;
163     } else {
164         *id = *p & 0x1F;
165         p++, sourcelen--;
166     }
167
168     if (sourcelen == 0)
169         return -1;
170
171     if (*p & 0x80) {
172         int n = *p & 0x7F;
173         p++, sourcelen--;
174         if (sourcelen < n)
175             return -1;
176         *length = 0;
177         while (n--)
178             *length = (*length << 8) | (*p++);
179         sourcelen -= n;
180     } else {
181         *length = *p;
182         p++, sourcelen--;
183     }
184
185     return p - (unsigned char *) source;
186 }
187
188 /*
189  * Write an ASN.1/BER identifier and length pair. Returns the
190  * number of bytes consumed. Assumes dest contains enough space.
191  * Will avoid writing anything if dest is NULL, but still return
192  * amount of space required.
193  */
194 int ber_write_id_len(void *dest, int id, int length, int flags)
195 {
196     unsigned char *d = (unsigned char *)dest;
197     int len = 0;
198
199     if (id <= 30) {
200         /*
201          * Identifier is one byte.
202          */
203         len++;
204         if (d) *d++ = id | flags;
205     } else {
206         int n;
207         /*
208          * Identifier is multiple bytes: the first byte is 11111
209          * plus the flags, and subsequent bytes encode the value of
210          * the identifier, 7 bits at a time, with the top bit of
211          * each byte 1 except the last one which is 0.
212          */
213         len++;
214         if (d) *d++ = 0x1F | flags;
215         for (n = 1; (id >> (7*n)) > 0; n++)
216             continue;                  /* count the bytes */
217         while (n--) {
218             len++;
219             if (d) *d++ = (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F);
220         }
221     }
222
223     if (length < 128) {
224         /*
225          * Length is one byte.
226          */
227         len++;
228         if (d) *d++ = length;
229     } else {
230         int n;
231         /*
232          * Length is multiple bytes. The first is 0x80 plus the
233          * number of subsequent bytes, and the subsequent bytes
234          * encode the actual length.
235          */
236         for (n = 1; (length >> (8*n)) > 0; n++)
237             continue;                  /* count the bytes */
238         len++;
239         if (d) *d++ = 0x80 | n;
240         while (n--) {
241             len++;
242             if (d) *d++ = (length >> (8*n)) & 0xFF;
243         }
244     }
245
246     return len;
247 }
248
249 static int put_string(void *target, void *data, int len)
250 {
251     unsigned char *d = (unsigned char *)target;
252
253     PUT_32BIT(d, len);
254     memcpy(d+4, data, len);
255     return len+4;
256 }
257
258 static int put_mp(void *target, void *data, int len)
259 {
260     unsigned char *d = (unsigned char *)target;
261     unsigned char *i = (unsigned char *)data;
262
263     if (*i & 0x80) {
264         PUT_32BIT(d, len+1);
265         d[4] = 0;
266         memcpy(d+5, data, len);
267         return len+5;
268     } else {
269         PUT_32BIT(d, len);
270         memcpy(d+4, data, len);
271         return len+4;
272     }
273 }
274
275 /* Simple structure to point to an mp-int within a blob. */
276 struct mpint_pos { void *start; int bytes; };
277
278 int ssh2_read_mpint(void *data, int len, struct mpint_pos *ret)
279 {
280     int bytes;
281     unsigned char *d = (unsigned char *) data;
282
283     if (len < 4)
284         goto error;
285     bytes = GET_32BIT(d);
286     if (len < 4+bytes)
287         goto error;
288
289     ret->start = d + 4;
290     ret->bytes = bytes;
291     return bytes+4;
292
293     error:
294     ret->start = NULL;
295     ret->bytes = -1;
296     return len;                        /* ensure further calls fail as well */
297 }
298
299 /* ----------------------------------------------------------------------
300  * Code to read and write OpenSSH private keys.
301  */
302
303 enum { OSSH_DSA, OSSH_RSA };
304 struct openssh_key {
305     int type;
306     int encrypted;
307     char iv[32];
308     unsigned char *keyblob;
309     int keyblob_len, keyblob_size;
310 };
311
312 struct openssh_key *load_openssh_key(char *filename)
313 {
314     struct openssh_key *ret;
315     FILE *fp;
316     char buffer[256];
317     char *errmsg, *p;
318     int headers_done;
319     char base64_bit[4];
320     int base64_chars = 0;
321
322     ret = smalloc(sizeof(*ret));
323     ret->keyblob = NULL;
324     ret->keyblob_len = ret->keyblob_size = 0;
325     ret->encrypted = 0;
326     memset(ret->iv, 0, sizeof(ret->iv));
327
328     fp = fopen(filename, "r");
329     if (!fp) {
330         errmsg = "Unable to open key file";
331         goto error;
332     }
333     if (!fgets(buffer, sizeof(buffer), fp) ||
334         0 != strncmp(buffer, "-----BEGIN ", 11) ||
335         0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) {
336         errmsg = "File does not begin with OpenSSH key header";
337         goto error;
338     }
339     if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n"))
340         ret->type = OSSH_RSA;
341     else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n"))
342         ret->type = OSSH_DSA;
343     else {
344         errmsg = "Unrecognised key type";
345         goto error;
346     }
347
348     headers_done = 0;
349     while (1) {
350         if (!fgets(buffer, sizeof(buffer), fp)) {
351             errmsg = "Unexpected end of file";
352             goto error;
353         }
354         if (0 == strncmp(buffer, "-----END ", 9) &&
355             0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n"))
356             break;                     /* done */
357         if ((p = strchr(buffer, ':')) != NULL) {
358             if (headers_done) {
359                 errmsg = "Header found in body of key data";
360                 goto error;
361             }
362             *p++ = '\0';
363             while (*p && isspace((unsigned char)*p)) p++;
364             if (!strcmp(buffer, "Proc-Type")) {
365                 if (p[0] != '4' || p[1] != ',') {
366                     errmsg = "Proc-Type is not 4 (only 4 is supported)";
367                     goto error;
368                 }
369                 p += 2;
370                 if (!strcmp(p, "ENCRYPTED\n"))
371                     ret->encrypted = 1;
372             } else if (!strcmp(buffer, "DEK-Info")) {
373                 int i, j;
374
375                 if (strncmp(p, "DES-EDE3-CBC,", 13)) {
376                     errmsg = "Ciphers other than DES-EDE3-CBC not supported";
377                     goto error;
378                 }
379                 p += 13;
380                 for (i = 0; i < 8; i++) {
381                     if (1 != sscanf(p, "%2x", &j))
382                         break;
383                     ret->iv[i] = j;
384                     p += 2;
385                 }
386                 if (i < 8) {
387                     errmsg = "Expected 16-digit iv in DEK-Info";
388                     goto error;
389                 }
390             }
391         } else {
392             headers_done = 1;
393
394             p = buffer;
395             while (isbase64(*p)) {
396                 base64_bit[base64_chars++] = *p;
397                 if (base64_chars == 4) {
398                     unsigned char out[3];
399                     int len;
400
401                     base64_chars = 0;
402
403                     len = base64_decode_atom(base64_bit, out);
404
405                     if (len <= 0) {
406                         errmsg = "Invalid base64 encoding";
407                         goto error;
408                     }
409
410                     if (ret->keyblob_len + len > ret->keyblob_size) {
411                         ret->keyblob_size = ret->keyblob_len + len + 256;
412                         ret->keyblob = srealloc(ret->keyblob, ret->keyblob_size);
413                     }
414
415                     memcpy(ret->keyblob + ret->keyblob_len, out, len);
416                     ret->keyblob_len += len;
417
418                     memset(out, 0, sizeof(out));
419                 }
420
421                 p++;
422             }
423         }
424     }
425
426     if (ret->keyblob_len == 0 || !ret->keyblob) {
427         errmsg = "Key body not present";
428         goto error;
429     }
430
431     if (ret->encrypted && ret->keyblob_len % 8 != 0) {
432         errmsg = "Encrypted key blob is not a multiple of cipher block size";
433         goto error;
434     }
435
436     memset(buffer, 0, sizeof(buffer));
437     memset(base64_bit, 0, sizeof(base64_bit));
438     return ret;
439
440     error:
441     memset(buffer, 0, sizeof(buffer));
442     memset(base64_bit, 0, sizeof(base64_bit));
443     if (ret) {
444         if (ret->keyblob) {
445             memset(ret->keyblob, 0, ret->keyblob_size);
446             sfree(ret->keyblob);
447         }
448         memset(&ret, 0, sizeof(ret));
449         sfree(ret);
450     }
451     return NULL;
452 }
453
454 int openssh_encrypted(char *filename)
455 {
456     struct openssh_key *key = load_openssh_key(filename);
457     int ret;
458
459     if (!key)
460         return 0;
461     ret = key->encrypted;
462     memset(key->keyblob, 0, key->keyblob_size);
463     sfree(key->keyblob);
464     memset(&key, 0, sizeof(key));
465     sfree(key);
466     return ret;
467 }
468
469 struct ssh2_userkey *openssh_read(char *filename, char *passphrase)
470 {
471     struct openssh_key *key = load_openssh_key(filename);
472     struct ssh2_userkey *retkey;
473     unsigned char *p;
474     int ret, id, len, flags;
475     int i, num_integers;
476     struct ssh2_userkey *retval = NULL;
477     char *errmsg;
478     unsigned char *blob;
479     int blobsize, blobptr, privptr;
480     char *modptr;
481     int modlen;
482
483     blob = NULL;
484
485     if (!key)
486         return NULL;
487
488     if (key->encrypted) {
489         /*
490          * Derive encryption key from passphrase and iv/salt:
491          * 
492          *  - let block A equal MD5(passphrase || iv)
493          *  - let block B equal MD5(A || passphrase || iv)
494          *  - block C would be MD5(B || passphrase || iv) and so on
495          *  - encryption key is the first N bytes of A || B
496          */
497         struct MD5Context md5c;
498         unsigned char keybuf[32];
499
500         MD5Init(&md5c);
501         MD5Update(&md5c, passphrase, strlen(passphrase));
502         MD5Update(&md5c, key->iv, 8);
503         MD5Final(keybuf, &md5c);
504
505         MD5Init(&md5c);
506         MD5Update(&md5c, keybuf, 16);
507         MD5Update(&md5c, passphrase, strlen(passphrase));
508         MD5Update(&md5c, key->iv, 8);
509         MD5Final(keybuf+16, &md5c);
510
511         /*
512          * Now decrypt the key blob.
513          */
514         des3_decrypt_pubkey_ossh(keybuf, key->iv,
515                                  key->keyblob, key->keyblob_len);
516
517         memset(&md5c, 0, sizeof(md5c));
518         memset(keybuf, 0, sizeof(keybuf));
519     }
520
521     /*
522      * Now we have a decrypted key blob, which contains an ASN.1
523      * encoded private key. We must now untangle the ASN.1.
524      *
525      * We expect the whole key blob to be formatted as a SEQUENCE
526      * (0x30 followed by a length code indicating that the rest of
527      * the blob is part of the sequence). Within that SEQUENCE we
528      * expect to see a bunch of INTEGERs. What those integers mean
529      * depends on the key type:
530      *
531      *  - For RSA, we expect the integers to be 0, n, e, d, p, q,
532      *    dmp1, dmq1, iqmp in that order. (The last three are d mod
533      *    (p-1), d mod (q-1), inverse of q mod p respectively.)
534      *
535      *  - For DSA, we expect them to be 0, p, q, g, y, x in that
536      *    order.
537      */
538     
539     p = key->keyblob;
540
541     /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */
542     ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags);
543     p += ret;
544     if (ret < 0 || id != 16) {
545         errmsg = "ASN.1 decoding failure";
546         retval = SSH2_WRONG_PASSPHRASE;
547         goto error;
548     }
549
550     /* Expect a load of INTEGERs. */
551     if (key->type == OSSH_RSA)
552         num_integers = 9;
553     else if (key->type == OSSH_DSA)
554         num_integers = 6;
555
556     /*
557      * Space to create key blob in.
558      */
559     blobsize = 256+key->keyblob_len;
560     blob = smalloc(blobsize);
561     PUT_32BIT(blob, 7);
562     if (key->type == OSSH_DSA)
563         memcpy(blob+4, "ssh-dss", 7);
564     else if (key->type == OSSH_RSA)
565         memcpy(blob+4, "ssh-rsa", 7);
566     blobptr = 4+7;
567     privptr = -1;
568
569     for (i = 0; i < num_integers; i++) {
570         ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
571                               &id, &len, &flags);
572         p += ret;
573         if (ret < 0 || id != 2 ||
574             key->keyblob+key->keyblob_len-p < len) {
575             errmsg = "ASN.1 decoding failure";
576             goto error;
577         }
578
579         if (i == 0) {
580             /*
581              * The first integer should be zero always (I think
582              * this is some sort of version indication).
583              */
584             if (len != 1 || p[0] != 0) {
585                 errmsg = "Version number mismatch";
586                 goto error;
587             }
588         } else if (key->type == OSSH_RSA) {
589             /*
590              * Integers 1 and 2 go into the public blob but in the
591              * opposite order; integers 3, 4, 5 and 8 go into the
592              * private blob. The other two (6 and 7) are ignored.
593              */
594             if (i == 1) {
595                 /* Save the details for after we deal with number 2. */
596                 modptr = p;
597                 modlen = len;
598             } else if (i != 6 && i != 7) {
599                 PUT_32BIT(blob+blobptr, len);
600                 memcpy(blob+blobptr+4, p, len);
601                 blobptr += 4+len;
602                 if (i == 2) {
603                     PUT_32BIT(blob+blobptr, modlen);
604                     memcpy(blob+blobptr+4, modptr, modlen);
605                     blobptr += 4+modlen;
606                     privptr = blobptr;
607                 }
608             }
609         } else if (key->type == OSSH_DSA) {
610             /*
611              * Integers 1-4 go into the public blob; integer 5 goes
612              * into the private blob.
613              */
614             PUT_32BIT(blob+blobptr, len);
615             memcpy(blob+blobptr+4, p, len);
616             blobptr += 4+len;
617             if (i == 4)
618                 privptr = blobptr;
619         }
620
621         /* Skip past the number. */
622         p += len;
623     }
624
625     /*
626      * Now put together the actual key. Simplest way to do this is
627      * to assemble our own key blobs and feed them to the createkey
628      * functions; this is a bit faffy but it does mean we get all
629      * the sanity checks for free.
630      */
631     assert(privptr > 0);               /* should have bombed by now if not */
632     retkey = smalloc(sizeof(struct ssh2_userkey));
633     retkey->alg = (key->type == OSSH_RSA ? &ssh_rsa : &ssh_dss);
634     retkey->data = retkey->alg->createkey(blob, privptr,
635                                           blob+privptr, blobptr-privptr);
636     if (!retkey->data) {
637         sfree(retkey);
638         errmsg = "unable to create key data structure";
639         goto error;
640     }
641
642     retkey->comment = dupstr("imported-openssh-key");
643     errmsg = NULL;                     /* no error */
644     retval = retkey;
645
646     error:
647     if (blob) {
648         memset(blob, 0, blobsize);
649         sfree(blob);
650     }
651     memset(key->keyblob, 0, key->keyblob_size);
652     sfree(key->keyblob);
653     memset(&key, 0, sizeof(key));
654     sfree(key);
655     return retval;
656 }
657
658 int openssh_write(char *filename, struct ssh2_userkey *key, char *passphrase)
659 {
660     unsigned char *pubblob, *privblob, *spareblob;
661     int publen, privlen, sparelen;
662     unsigned char *outblob;
663     int outlen;
664     struct mpint_pos numbers[9];
665     int nnumbers, pos, len, seqlen, i;
666     char *header, *footer;
667     char zero[1];
668     unsigned char iv[8];
669     int ret = 0;
670     FILE *fp;
671
672     /*
673      * Fetch the key blobs.
674      */
675     pubblob = key->alg->public_blob(key->data, &publen);
676     privblob = key->alg->private_blob(key->data, &privlen);
677     spareblob = outblob = NULL;
678
679     /*
680      * Find the sequence of integers to be encoded into the OpenSSH
681      * key blob, and also decide on the header line.
682      */
683     if (key->alg == &ssh_rsa) {
684         int pos;
685         struct mpint_pos n, e, d, p, q, iqmp, dmp1, dmq1;
686         Bignum bd, bp, bq, bdmp1, bdmq1;
687
688         pos = 4 + GET_32BIT(pubblob);
689         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e);
690         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n);
691         pos = 0;
692         pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d);
693         pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p);
694         pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
695         pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
696
697         assert(e.start && iqmp.start); /* can't go wrong */
698
699         /* We also need d mod (p-1) and d mod (q-1). */
700         bd = bignum_from_bytes(d.start, d.bytes);
701         bp = bignum_from_bytes(p.start, p.bytes);
702         bq = bignum_from_bytes(q.start, q.bytes);
703         decbn(bp);
704         decbn(bq);
705         bdmp1 = bigmod(bd, bp);
706         bdmq1 = bigmod(bd, bq);
707         freebn(bd);
708         freebn(bp);
709         freebn(bq);
710
711         dmp1.bytes = (bignum_bitcount(bdmp1)+8)/8;
712         dmq1.bytes = (bignum_bitcount(bdmq1)+8)/8;
713         sparelen = dmp1.bytes + dmq1.bytes;
714         spareblob = smalloc(sparelen);
715         dmp1.start = spareblob;
716         dmq1.start = spareblob + dmp1.bytes;
717         for (i = 0; i < dmp1.bytes; i++)
718             spareblob[i] = bignum_byte(bdmp1, dmp1.bytes-1 - i);
719         for (i = 0; i < dmq1.bytes; i++)
720             spareblob[i+dmp1.bytes] = bignum_byte(bdmq1, dmq1.bytes-1 - i);
721         freebn(bdmp1);
722         freebn(bdmq1);
723
724         numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
725         numbers[1] = n;
726         numbers[2] = e;
727         numbers[3] = d;
728         numbers[4] = p;
729         numbers[5] = q;
730         numbers[6] = dmp1;
731         numbers[7] = dmq1;
732         numbers[8] = iqmp;
733
734         nnumbers = 9;
735         header = "-----BEGIN RSA PRIVATE KEY-----\n";
736         footer = "-----END RSA PRIVATE KEY-----\n";
737     } else if (key->alg == &ssh_dss) {
738         int pos;
739         struct mpint_pos p, q, g, y, x;
740
741         pos = 4 + GET_32BIT(pubblob);
742         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p);
743         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q);
744         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g);
745         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y);
746         pos = 0;
747         pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x);
748
749         assert(y.start && x.start); /* can't go wrong */
750
751         numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0'; 
752         numbers[1] = p;
753         numbers[2] = q;
754         numbers[3] = g;
755         numbers[4] = y;
756         numbers[5] = x;
757
758         nnumbers = 6;
759         header = "-----BEGIN DSA PRIVATE KEY-----\n";
760         footer = "-----END DSA PRIVATE KEY-----\n";
761     } else {
762         assert(0);                     /* zoinks! */
763     }
764
765     /*
766      * Now count up the total size of the ASN.1 encoded integers,
767      * so as to determine the length of the containing SEQUENCE.
768      */
769     len = 0;
770     for (i = 0; i < nnumbers; i++) {
771         len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0);
772         len += numbers[i].bytes;
773     }
774     seqlen = len;
775     /* Now add on the SEQUENCE header. */
776     len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
777     /* Round up to the cipher block size, ensuring we have at least one
778      * byte of padding (see below). */
779     outlen = len;
780     if (passphrase)
781         outlen = (outlen+8) &~ 7;
782
783     /*
784      * Now we know how big outblob needs to be. Allocate it.
785      */
786     outblob = smalloc(outlen);
787
788     /*
789      * And write the data into it.
790      */
791     pos = 0;
792     pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
793     for (i = 0; i < nnumbers; i++) {
794         pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
795         memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
796         pos += numbers[i].bytes;
797     }
798
799     /*
800      * Padding on OpenSSH keys is deterministic. The number of
801      * padding bytes is always more than zero, and always at most
802      * the cipher block length. The value of each padding byte is
803      * equal to the number of padding bytes. So a plaintext that's
804      * an exact multiple of the block size will be padded with 08
805      * 08 08 08 08 08 08 08 (assuming a 64-bit block cipher); a
806      * plaintext one byte less than a multiple of the block size
807      * will be padded with just 01.
808      * 
809      * This enables the OpenSSL key decryption function to strip
810      * off the padding algorithmically and return the unpadded
811      * plaintext to the next layer: it looks at the final byte, and
812      * then expects to find that many bytes at the end of the data
813      * with the same value. Those are all removed and the rest is
814      * returned.
815      */
816     assert(pos == len);
817     while (pos < outlen) {
818         outblob[pos++] = outlen - len;
819     }
820
821     /*
822      * Encrypt the key.
823      */
824     if (passphrase) {
825         /*
826          * Invent an iv. Then derive encryption key from passphrase
827          * and iv/salt:
828          * 
829          *  - let block A equal MD5(passphrase || iv)
830          *  - let block B equal MD5(A || passphrase || iv)
831          *  - block C would be MD5(B || passphrase || iv) and so on
832          *  - encryption key is the first N bytes of A || B
833          */
834         struct MD5Context md5c;
835         unsigned char keybuf[32];
836
837         for (i = 0; i < 8; i++) iv[i] = random_byte();
838
839         MD5Init(&md5c);
840         MD5Update(&md5c, passphrase, strlen(passphrase));
841         MD5Update(&md5c, iv, 8);
842         MD5Final(keybuf, &md5c);
843
844         MD5Init(&md5c);
845         MD5Update(&md5c, keybuf, 16);
846         MD5Update(&md5c, passphrase, strlen(passphrase));
847         MD5Update(&md5c, iv, 8);
848         MD5Final(keybuf+16, &md5c);
849
850         /*
851          * Now encrypt the key blob.
852          */
853         des3_encrypt_pubkey_ossh(keybuf, iv, outblob, outlen);
854
855         memset(&md5c, 0, sizeof(md5c));
856         memset(keybuf, 0, sizeof(keybuf));
857     }
858
859     /*
860      * And save it. We'll use Unix line endings just in case it's
861      * subsequently transferred in binary mode.
862      */
863     fp = fopen(filename, "wb");        /* ensure Unix line endings */
864     if (!fp)
865         goto error;
866     fputs(header, fp);
867     if (passphrase) {
868         fprintf(fp, "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,");
869         for (i = 0; i < 8; i++)
870             fprintf(fp, "%02X", iv[i]);
871         fprintf(fp, "\n\n");
872     }
873     base64_encode(fp, outblob, outlen, 64);
874     fputs(footer, fp);
875     fclose(fp);
876     ret = 1;
877
878     error:
879     if (outblob) {
880         memset(outblob, 0, outlen);
881         sfree(outblob);
882     }
883     if (spareblob) {
884         memset(spareblob, 0, sparelen);
885         sfree(spareblob);
886     }
887     if (privblob) {
888         memset(privblob, 0, privlen);
889         sfree(privblob);
890     }
891     if (pubblob) {
892         memset(pubblob, 0, publen);
893         sfree(pubblob);
894     }
895     return ret;
896 }
897
898 /* ----------------------------------------------------------------------
899  * Code to read ssh.com private keys.
900  */
901
902 /*
903  * The format of the base64 blob is largely ssh2-packet-formatted,
904  * except that mpints are a bit different: they're more like the
905  * old ssh1 mpint. You have a 32-bit bit count N, followed by
906  * (N+7)/8 bytes of data.
907  * 
908  * So. The blob contains:
909  * 
910  *  - uint32 0x3f6ff9eb       (magic number)
911  *  - uint32 size             (total blob size)
912  *  - string key-type         (see below)
913  *  - string cipher-type      (tells you if key is encrypted)
914  *  - string encrypted-blob
915  * 
916  * (The first size field includes the size field itself and the
917  * magic number before it. All other size fields are ordinary ssh2
918  * strings, so the size field indicates how much data is to
919  * _follow_.)
920  * 
921  * The encrypted blob, once decrypted, contains a single string
922  * which in turn contains the payload. (This allows padding to be
923  * added after that string while still making it clear where the
924  * real payload ends. Also it probably makes for a reasonable
925  * decryption check.)
926  * 
927  * The payload blob, for an RSA key, contains:
928  *  - mpint e
929  *  - mpint d
930  *  - mpint n  (yes, the public and private stuff is intermixed)
931  *  - mpint u  (presumably inverse of p mod q)
932  *  - mpint p  (p is the smaller prime)
933  *  - mpint q  (q is the larger)
934  * 
935  * For a DSA key, the payload blob contains:
936  *  - uint32 0
937  *  - mpint p
938  *  - mpint g
939  *  - mpint q
940  *  - mpint y
941  *  - mpint x
942  * 
943  * Alternatively, if the parameters are `predefined', that
944  * (0,p,g,q) sequence can be replaced by a uint32 1 and a string
945  * containing some predefined parameter specification. *shudder*,
946  * but I doubt we'll encounter this in real life.
947  * 
948  * The key type strings are ghastly. The RSA key I looked at had a
949  * type string of
950  * 
951  *   `if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}'
952  * 
953  * and the DSA key wasn't much better:
954  * 
955  *   `dl-modp{sign{dsa-nist-sha1},dh{plain}}'
956  * 
957  * It isn't clear that these will always be the same. I think it
958  * might be wise just to look at the `if-modn{sign{rsa' and
959  * `dl-modp{sign{dsa' prefixes.
960  * 
961  * Finally, the encryption. The cipher-type string appears to be
962  * either `none' or `3des-cbc'. Looks as if this is SSH2-style
963  * 3des-cbc (i.e. outer cbc rather than inner). The key is created
964  * from the passphrase by means of yet another hashing faff:
965  * 
966  *  - first 16 bytes are MD5(passphrase)
967  *  - next 16 bytes are MD5(passphrase || first 16 bytes)
968  *  - if there were more, they'd be MD5(passphrase || first 32),
969  *    and so on.
970  */
971
972 #define SSHCOM_MAGIC_NUMBER 0x3f6ff9eb
973
974 struct sshcom_key {
975     char comment[256];                 /* allowing any length is overkill */
976     unsigned char *keyblob;
977     int keyblob_len, keyblob_size;
978 };
979
980 struct sshcom_key *load_sshcom_key(char *filename)
981 {
982     struct sshcom_key *ret;
983     FILE *fp;
984     char buffer[256];
985     int len;
986     char *errmsg, *p;
987     int headers_done;
988     char base64_bit[4];
989     int base64_chars = 0;
990
991     ret = smalloc(sizeof(*ret));
992     ret->comment[0] = '\0';
993     ret->keyblob = NULL;
994     ret->keyblob_len = ret->keyblob_size = 0;
995
996     fp = fopen(filename, "r");
997     if (!fp) {
998         errmsg = "Unable to open key file";
999         goto error;
1000     }
1001     if (!fgets(buffer, sizeof(buffer), fp) ||
1002         0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) {
1003         errmsg = "File does not begin with ssh.com key header";
1004         goto error;
1005     }
1006
1007     headers_done = 0;
1008     while (1) {
1009         if (!fgets(buffer, sizeof(buffer), fp)) {
1010             errmsg = "Unexpected end of file";
1011             goto error;
1012         }
1013         if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n"))
1014             break;                     /* done */
1015         if ((p = strchr(buffer, ':')) != NULL) {
1016             if (headers_done) {
1017                 errmsg = "Header found in body of key data";
1018                 goto error;
1019             }
1020             *p++ = '\0';
1021             while (*p && isspace((unsigned char)*p)) p++;
1022             /*
1023              * Header lines can end in a trailing backslash for
1024              * continuation.
1025              */
1026             while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) ||
1027                    p[len-1] != '\n' || p[len-2] == '\\') {
1028                 if (len > (int)((p-buffer) + sizeof(buffer)-2)) {
1029                     errmsg = "Header line too long to deal with";
1030                     goto error;
1031                 }
1032                 if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) {
1033                     errmsg = "Unexpected end of file";
1034                     goto error;
1035                 }
1036             }
1037             p[strcspn(p, "\n")] = '\0';
1038             if (!strcmp(buffer, "Comment")) {
1039                 /* Strip quotes in comment if present. */
1040                 if (p[0] == '"' && p[strlen(p)-1] == '"') {
1041                     p++;
1042                     p[strlen(p)-1] = '\0';
1043                 }
1044                 strncpy(ret->comment, p, sizeof(ret->comment));
1045                 ret->comment[sizeof(ret->comment)-1] = '\0';
1046             }
1047         } else {
1048             headers_done = 1;
1049
1050             p = buffer;
1051             while (isbase64(*p)) {
1052                 base64_bit[base64_chars++] = *p;
1053                 if (base64_chars == 4) {
1054                     unsigned char out[3];
1055
1056                     base64_chars = 0;
1057
1058                     len = base64_decode_atom(base64_bit, out);
1059
1060                     if (len <= 0) {
1061                         errmsg = "Invalid base64 encoding";
1062                         goto error;
1063                     }
1064
1065                     if (ret->keyblob_len + len > ret->keyblob_size) {
1066                         ret->keyblob_size = ret->keyblob_len + len + 256;
1067                         ret->keyblob = srealloc(ret->keyblob, ret->keyblob_size);
1068                     }
1069
1070                     memcpy(ret->keyblob + ret->keyblob_len, out, len);
1071                     ret->keyblob_len += len;
1072                 }
1073
1074                 p++;
1075             }
1076         }
1077     }
1078
1079     if (ret->keyblob_len == 0 || !ret->keyblob) {
1080         errmsg = "Key body not present";
1081         goto error;
1082     }
1083
1084     return ret;
1085
1086     error:
1087     if (ret) {
1088         if (ret->keyblob) {
1089             memset(ret->keyblob, 0, ret->keyblob_size);
1090             sfree(ret->keyblob);
1091         }
1092         memset(&ret, 0, sizeof(ret));
1093         sfree(ret);
1094     }
1095     return NULL;
1096 }
1097
1098 int sshcom_encrypted(char *filename, char **comment)
1099 {
1100     struct sshcom_key *key = load_sshcom_key(filename);
1101     int pos, len, answer;
1102
1103     *comment = NULL;
1104     if (!key)
1105         return 0;
1106
1107     /*
1108      * Check magic number.
1109      */
1110     if (GET_32BIT(key->keyblob) != 0x3f6ff9eb)
1111         return 0;                      /* key is invalid */
1112
1113     /*
1114      * Find the cipher-type string.
1115      */
1116     answer = 0;
1117     pos = 8;
1118     if (key->keyblob_len < pos+4)
1119         goto done;                     /* key is far too short */
1120     pos += 4 + GET_32BIT(key->keyblob + pos);   /* skip key type */
1121     if (key->keyblob_len < pos+4)
1122         goto done;                     /* key is far too short */
1123     len = GET_32BIT(key->keyblob + pos);   /* find cipher-type length */
1124     if (key->keyblob_len < pos+4+len)
1125         goto done;                     /* cipher type string is incomplete */
1126     if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4))
1127         answer = 1;
1128
1129     done:
1130     *comment = dupstr(key->comment);
1131     memset(key->keyblob, 0, key->keyblob_size);
1132     sfree(key->keyblob);
1133     memset(&key, 0, sizeof(key));
1134     sfree(key);
1135     return answer;
1136 }
1137
1138 int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret)
1139 {
1140     int bits;
1141     int bytes;
1142     unsigned char *d = (unsigned char *) data;
1143
1144     if (len < 4)
1145         goto error;
1146     bits = GET_32BIT(d);
1147
1148     bytes = (bits + 7) / 8;
1149     if (len < 4+bytes)
1150         goto error;
1151
1152     ret->start = d + 4;
1153     ret->bytes = bytes;
1154     return bytes+4;
1155
1156     error:
1157     ret->start = NULL;
1158     ret->bytes = -1;
1159     return len;                        /* ensure further calls fail as well */
1160 }
1161
1162 static int sshcom_put_mpint(void *target, void *data, int len)
1163 {
1164     unsigned char *d = (unsigned char *)target;
1165     unsigned char *i = (unsigned char *)data;
1166     int bits = len * 8 - 1;
1167
1168     while (bits > 0) {
1169         if (*i & (1 << (bits & 7)))
1170             break;
1171         if (!(bits-- & 7))
1172             i++, len--;
1173     }
1174
1175     PUT_32BIT(d, bits+1);
1176     memcpy(d+4, i, len);
1177     return len+4;
1178 }
1179
1180 struct ssh2_userkey *sshcom_read(char *filename, char *passphrase)
1181 {
1182     struct sshcom_key *key = load_sshcom_key(filename);
1183     char *errmsg;
1184     int pos, len;
1185     const char prefix_rsa[] = "if-modn{sign{rsa";
1186     const char prefix_dsa[] = "dl-modp{sign{dsa";
1187     enum { RSA, DSA } type;
1188     int encrypted;
1189     char *ciphertext;
1190     int cipherlen;
1191     struct ssh2_userkey *ret = NULL, *retkey;
1192     const struct ssh_signkey *alg;
1193     unsigned char *blob = NULL;
1194     int blobsize, publen, privlen;
1195
1196     if (!key)
1197         return NULL;
1198
1199     /*
1200      * Check magic number.
1201      */
1202     if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) {
1203         errmsg = "Key does not begin with magic number";
1204         goto error;
1205     }
1206
1207     /*
1208      * Determine the key type.
1209      */
1210     pos = 8;
1211     if (key->keyblob_len < pos+4 ||
1212         (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
1213         errmsg = "Key blob does not contain a key type string";
1214         goto error;
1215     }
1216     if (len > sizeof(prefix_rsa) - 1 &&
1217         !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) {
1218         type = RSA;
1219     } else if (len > sizeof(prefix_dsa) - 1 &&
1220         !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) {
1221         type = DSA;
1222     } else {
1223         errmsg = "Key is of unknown type";
1224         goto error;
1225     }
1226     pos += 4+len;
1227
1228     /*
1229      * Determine the cipher type.
1230      */
1231     if (key->keyblob_len < pos+4 ||
1232         (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
1233         errmsg = "Key blob does not contain a cipher type string";
1234         goto error;
1235     }
1236     if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4))
1237         encrypted = 0;
1238     else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8))
1239         encrypted = 1;
1240     else {
1241         errmsg = "Key encryption is of unknown type";
1242         goto error;
1243     }
1244     pos += 4+len;
1245
1246     /*
1247      * Get hold of the encrypted part of the key.
1248      */
1249     if (key->keyblob_len < pos+4 ||
1250         (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
1251         errmsg = "Key blob does not contain actual key data";
1252         goto error;
1253     }
1254     ciphertext = key->keyblob + pos + 4;
1255     cipherlen = len;
1256     if (cipherlen == 0) {
1257         errmsg = "Length of key data is zero";
1258         goto error;
1259     }
1260
1261     /*
1262      * Decrypt it if necessary.
1263      */
1264     if (encrypted) {
1265         /*
1266          * Derive encryption key from passphrase and iv/salt:
1267          * 
1268          *  - let block A equal MD5(passphrase)
1269          *  - let block B equal MD5(passphrase || A)
1270          *  - block C would be MD5(passphrase || A || B) and so on
1271          *  - encryption key is the first N bytes of A || B
1272          */
1273         struct MD5Context md5c;
1274         unsigned char keybuf[32], iv[8];
1275
1276         if (cipherlen % 8 != 0) {
1277             errmsg = "Encrypted part of key is not a multiple of cipher block"
1278                 " size";
1279             goto error;
1280         }
1281
1282         MD5Init(&md5c);
1283         MD5Update(&md5c, passphrase, strlen(passphrase));
1284         MD5Final(keybuf, &md5c);
1285
1286         MD5Init(&md5c);
1287         MD5Update(&md5c, passphrase, strlen(passphrase));
1288         MD5Update(&md5c, keybuf, 16);
1289         MD5Final(keybuf+16, &md5c);
1290
1291         /*
1292          * Now decrypt the key blob.
1293          */
1294         memset(iv, 0, sizeof(iv));
1295         des3_decrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen);
1296
1297         memset(&md5c, 0, sizeof(md5c));
1298         memset(keybuf, 0, sizeof(keybuf));
1299
1300         /*
1301          * Hereafter we return WRONG_PASSPHRASE for any parsing
1302          * error. (But only if we've just tried to decrypt it!
1303          * Returning WRONG_PASSPHRASE for an unencrypted key is
1304          * automatic doom.)
1305          */
1306         if (encrypted)
1307             ret = SSH2_WRONG_PASSPHRASE;
1308     }
1309
1310     /*
1311      * Strip away the containing string to get to the real meat.
1312      */
1313     len = GET_32BIT(ciphertext);
1314     if (len > cipherlen-4) {
1315         errmsg = "containing string was ill-formed";
1316         goto error;
1317     }
1318     ciphertext += 4;
1319     cipherlen = len;
1320
1321     /*
1322      * Now we break down into RSA versus DSA. In either case we'll
1323      * construct public and private blobs in our own format, and
1324      * end up feeding them to alg->createkey().
1325      */
1326     blobsize = cipherlen + 256;
1327     blob = smalloc(blobsize);
1328     privlen = 0;
1329     if (type == RSA) {
1330         struct mpint_pos n, e, d, u, p, q;
1331         int pos = 0;
1332         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e);
1333         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d);
1334         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n);
1335         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u);
1336         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
1337         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
1338         if (!q.start) {
1339             errmsg = "key data did not contain six integers";
1340             goto error;
1341         }
1342
1343         alg = &ssh_rsa;
1344         pos = 0;
1345         pos += put_string(blob+pos, "ssh-rsa", 7);
1346         pos += put_mp(blob+pos, e.start, e.bytes);
1347         pos += put_mp(blob+pos, n.start, n.bytes);
1348         publen = pos;
1349         pos += put_string(blob+pos, d.start, d.bytes);
1350         pos += put_mp(blob+pos, q.start, q.bytes);
1351         pos += put_mp(blob+pos, p.start, p.bytes);
1352         pos += put_mp(blob+pos, u.start, u.bytes);
1353         privlen = pos - publen;
1354     } else if (type == DSA) {
1355         struct mpint_pos p, q, g, x, y;
1356         int pos = 4;
1357         if (GET_32BIT(ciphertext) != 0) {
1358             errmsg = "predefined DSA parameters not supported";
1359             goto error;
1360         }
1361         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
1362         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g);
1363         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
1364         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y);
1365         pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x);
1366         if (!x.start) {
1367             errmsg = "key data did not contain five integers";
1368             goto error;
1369         }
1370
1371         alg = &ssh_dss;
1372         pos = 0;
1373         pos += put_string(blob+pos, "ssh-dss", 7);
1374         pos += put_mp(blob+pos, p.start, p.bytes);
1375         pos += put_mp(blob+pos, q.start, q.bytes);
1376         pos += put_mp(blob+pos, g.start, g.bytes);
1377         pos += put_mp(blob+pos, y.start, y.bytes);
1378         publen = pos;
1379         pos += put_mp(blob+pos, x.start, x.bytes);
1380         privlen = pos - publen;
1381     }
1382
1383     assert(privlen > 0);               /* should have bombed by now if not */
1384
1385     retkey = smalloc(sizeof(struct ssh2_userkey));
1386     retkey->alg = alg;
1387     retkey->data = alg->createkey(blob, publen, blob+publen, privlen);
1388     if (!retkey->data) {
1389         sfree(retkey);
1390         errmsg = "unable to create key data structure";
1391         goto error;
1392     }
1393     retkey->comment = dupstr(key->comment);
1394
1395     errmsg = NULL; /* no error */
1396     ret = retkey;
1397
1398     error:
1399     if (blob) {
1400         memset(blob, 0, blobsize);
1401         sfree(blob);
1402     }
1403     memset(key->keyblob, 0, key->keyblob_size);
1404     sfree(key->keyblob);
1405     memset(&key, 0, sizeof(key));
1406     sfree(key);
1407     return ret;
1408 }
1409
1410 int sshcom_write(char *filename, struct ssh2_userkey *key, char *passphrase)
1411 {
1412     unsigned char *pubblob, *privblob;
1413     int publen, privlen;
1414     unsigned char *outblob;
1415     int outlen;
1416     struct mpint_pos numbers[6];
1417     int nnumbers, initial_zero, pos, lenpos, i;
1418     char *type;
1419     char *ciphertext;
1420     int cipherlen;
1421     int ret = 0;
1422     FILE *fp;
1423
1424     /*
1425      * Fetch the key blobs.
1426      */
1427     pubblob = key->alg->public_blob(key->data, &publen);
1428     privblob = key->alg->private_blob(key->data, &privlen);
1429     outblob = NULL;
1430
1431     /*
1432      * Find the sequence of integers to be encoded into the OpenSSH
1433      * key blob, and also decide on the header line.
1434      */
1435     if (key->alg == &ssh_rsa) {
1436         int pos;
1437         struct mpint_pos n, e, d, p, q, iqmp;
1438
1439         pos = 4 + GET_32BIT(pubblob);
1440         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e);
1441         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n);
1442         pos = 0;
1443         pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d);
1444         pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p);
1445         pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
1446         pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
1447
1448         assert(e.start && iqmp.start); /* can't go wrong */
1449
1450         numbers[0] = e;
1451         numbers[1] = d;
1452         numbers[2] = n;
1453         numbers[3] = iqmp;
1454         numbers[4] = q;
1455         numbers[5] = p;
1456
1457         nnumbers = 6;
1458         initial_zero = 0;
1459         type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}";
1460     } else if (key->alg == &ssh_dss) {
1461         int pos;
1462         struct mpint_pos p, q, g, y, x;
1463
1464         pos = 4 + GET_32BIT(pubblob);
1465         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p);
1466         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q);
1467         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g);
1468         pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y);
1469         pos = 0;
1470         pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x);
1471
1472         assert(y.start && x.start); /* can't go wrong */
1473
1474         numbers[0] = p;
1475         numbers[1] = g;
1476         numbers[2] = q;
1477         numbers[3] = y;
1478         numbers[4] = x;
1479
1480         nnumbers = 5;
1481         initial_zero = 1;
1482         type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}";
1483     } else {
1484         assert(0);                     /* zoinks! */
1485     }
1486
1487     /*
1488      * Total size of key blob will be somewhere under 512 plus
1489      * combined length of integers. We'll calculate the more
1490      * precise size as we construct the blob.
1491      */
1492     outlen = 512;
1493     for (i = 0; i < nnumbers; i++)
1494         outlen += 4 + numbers[i].bytes;
1495     outblob = smalloc(outlen);
1496
1497     /*
1498      * Create the unencrypted key blob.
1499      */
1500     pos = 0;
1501     PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4;
1502     pos += 4;                          /* length field, fill in later */
1503     pos += put_string(outblob+pos, type, strlen(type));
1504     {
1505         char *ciphertype = passphrase ? "3des-cbc" : "none";
1506         pos += put_string(outblob+pos, ciphertype, strlen(ciphertype));
1507     }
1508     lenpos = pos;                      /* remember this position */
1509     pos += 4;                          /* encrypted-blob size */
1510     pos += 4;                          /* encrypted-payload size */
1511     if (initial_zero) {
1512         PUT_32BIT(outblob+pos, 0);
1513         pos += 4;
1514     }
1515     for (i = 0; i < nnumbers; i++)
1516         pos += sshcom_put_mpint(outblob+pos,
1517                                 numbers[i].start, numbers[i].bytes);
1518     /* Now wrap up the encrypted payload. */
1519     PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8));
1520     /* Pad encrypted blob to a multiple of cipher block size. */
1521     if (passphrase) {
1522         int padding = -(pos - (lenpos+4)) & 7;
1523         while (padding--)
1524             outblob[pos++] = random_byte();
1525     }
1526     ciphertext = outblob+lenpos+4;
1527     cipherlen = pos - (lenpos+4);
1528     assert(!passphrase || cipherlen % 8 == 0);
1529     /* Wrap up the encrypted blob string. */
1530     PUT_32BIT(outblob+lenpos, cipherlen);
1531     /* And finally fill in the total length field. */
1532     PUT_32BIT(outblob+4, pos);
1533
1534     assert(pos < outlen);
1535
1536     /*
1537      * Encrypt the key.
1538      */
1539     if (passphrase) {
1540         /*
1541          * Derive encryption key from passphrase and iv/salt:
1542          * 
1543          *  - let block A equal MD5(passphrase)
1544          *  - let block B equal MD5(passphrase || A)
1545          *  - block C would be MD5(passphrase || A || B) and so on
1546          *  - encryption key is the first N bytes of A || B
1547          */
1548         struct MD5Context md5c;
1549         unsigned char keybuf[32], iv[8];
1550
1551         MD5Init(&md5c);
1552         MD5Update(&md5c, passphrase, strlen(passphrase));
1553         MD5Final(keybuf, &md5c);
1554
1555         MD5Init(&md5c);
1556         MD5Update(&md5c, passphrase, strlen(passphrase));
1557         MD5Update(&md5c, keybuf, 16);
1558         MD5Final(keybuf+16, &md5c);
1559
1560         /*
1561          * Now decrypt the key blob.
1562          */
1563         memset(iv, 0, sizeof(iv));
1564         des3_encrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen);
1565
1566         memset(&md5c, 0, sizeof(md5c));
1567         memset(keybuf, 0, sizeof(keybuf));
1568     }
1569
1570     /*
1571      * And save it. We'll use Unix line endings just in case it's
1572      * subsequently transferred in binary mode.
1573      */
1574     fp = fopen(filename, "wb");        /* ensure Unix line endings */
1575     if (!fp)
1576         goto error;
1577     fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
1578     fprintf(fp, "Comment: \"");
1579     /*
1580      * Comment header is broken with backslash-newline if it goes
1581      * over 70 chars. Although it's surrounded by quotes, it
1582      * _doesn't_ escape backslashes or quotes within the string.
1583      * Don't ask me, I didn't design it.
1584      */
1585     {
1586         int slen = 60;                 /* starts at 60 due to "Comment: " */
1587         char *c = key->comment;
1588         while ((int)strlen(c) > slen) {
1589             fprintf(fp, "%.*s\\\n", slen, c);
1590             c += slen;
1591             slen = 70;                 /* allow 70 chars on subsequent lines */
1592         }
1593         fprintf(fp, "%s\"\n", c);
1594     }
1595     base64_encode(fp, outblob, pos, 70);
1596     fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
1597     fclose(fp);
1598     ret = 1;
1599
1600     error:
1601     if (outblob) {
1602         memset(outblob, 0, outlen);
1603         sfree(outblob);
1604     }
1605     if (privblob) {
1606         memset(privblob, 0, privlen);
1607         sfree(privblob);
1608     }
1609     if (pubblob) {
1610         memset(pubblob, 0, publen);
1611         sfree(pubblob);
1612     }
1613     return ret;
1614 }