]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - sshpubk.c
Document proxy logging control.
[PuTTY.git] / sshpubk.c
1 /*
2  * Generic SSH public-key handling operations. In particular,
3  * reading of SSH public-key files, and also the generic `sign'
4  * operation for SSH-2 (which checks the type of the key and
5  * dispatches to the appropriate key-type specific function).
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <assert.h>
11
12 #include "putty.h"
13 #include "ssh.h"
14 #include "misc.h"
15
16 #define rsa_signature "SSH PRIVATE KEY FILE FORMAT 1.1\n"
17
18 #define BASE64_TOINT(x) ( (x)-'A'<26 ? (x)-'A'+0 :\
19                           (x)-'a'<26 ? (x)-'a'+26 :\
20                           (x)-'0'<10 ? (x)-'0'+52 :\
21                           (x)=='+' ? 62 : \
22                           (x)=='/' ? 63 : 0 )
23
24 static int key_type_fp(FILE *fp);
25
26 static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only,
27                            char **commentptr, const char *passphrase,
28                            const char **error)
29 {
30     unsigned char buf[16384];
31     unsigned char keybuf[16];
32     int len;
33     int i, j, ciphertype;
34     int ret = 0;
35     struct MD5Context md5c;
36     char *comment;
37
38     *error = NULL;
39
40     /* Slurp the whole file (minus the header) into a buffer. */
41     len = fread(buf, 1, sizeof(buf), fp);
42     fclose(fp);
43     if (len < 0 || len == sizeof(buf)) {
44         *error = "error reading file";
45         goto end;                      /* file too big or not read */
46     }
47
48     i = 0;
49     *error = "file format error";
50
51     /*
52      * A zero byte. (The signature includes a terminating NUL.)
53      */
54     if (len - i < 1 || buf[i] != 0)
55         goto end;
56     i++;
57
58     /* One byte giving encryption type, and one reserved uint32. */
59     if (len - i < 1)
60         goto end;
61     ciphertype = buf[i];
62     if (ciphertype != 0 && ciphertype != SSH_CIPHER_3DES)
63         goto end;
64     i++;
65     if (len - i < 4)
66         goto end;                      /* reserved field not present */
67     if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0
68         || buf[i + 3] != 0) goto end;  /* reserved field nonzero, panic! */
69     i += 4;
70
71     /* Now the serious stuff. An ordinary SSH-1 public key. */
72     j = makekey(buf + i, len - i, key, NULL, 1);
73     if (j < 0)
74         goto end;                      /* overran */
75     i += j;
76
77     /* Next, the comment field. */
78     j = toint(GET_32BIT(buf + i));
79     i += 4;
80     if (j < 0 || len - i < j)
81         goto end;
82     comment = snewn(j + 1, char);
83     if (comment) {
84         memcpy(comment, buf + i, j);
85         comment[j] = '\0';
86     }
87     i += j;
88     if (commentptr)
89         *commentptr = dupstr(comment);
90     if (key)
91         key->comment = comment;
92     else
93         sfree(comment);
94
95     if (pub_only) {
96         ret = 1;
97         goto end;
98     }
99
100     if (!key) {
101         ret = ciphertype != 0;
102         *error = NULL;
103         goto end;
104     }
105
106     /*
107      * Decrypt remainder of buffer.
108      */
109     if (ciphertype) {
110         MD5Init(&md5c);
111         MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
112         MD5Final(keybuf, &md5c);
113         des3_decrypt_pubkey(keybuf, buf + i, (len - i + 7) & ~7);
114         smemclr(keybuf, sizeof(keybuf));        /* burn the evidence */
115     }
116
117     /*
118      * We are now in the secret part of the key. The first four
119      * bytes should be of the form a, b, a, b.
120      */
121     if (len - i < 4)
122         goto end;
123     if (buf[i] != buf[i + 2] || buf[i + 1] != buf[i + 3]) {
124         *error = "wrong passphrase";
125         ret = -1;
126         goto end;
127     }
128     i += 4;
129
130     /*
131      * After that, we have one further bignum which is our
132      * decryption exponent, and then the three auxiliary values
133      * (iqmp, q, p).
134      */
135     j = makeprivate(buf + i, len - i, key);
136     if (j < 0) goto end;
137     i += j;
138     j = ssh1_read_bignum(buf + i, len - i, &key->iqmp);
139     if (j < 0) goto end;
140     i += j;
141     j = ssh1_read_bignum(buf + i, len - i, &key->q);
142     if (j < 0) goto end;
143     i += j;
144     j = ssh1_read_bignum(buf + i, len - i, &key->p);
145     if (j < 0) goto end;
146     i += j;
147
148     if (!rsa_verify(key)) {
149         *error = "rsa_verify failed";
150         freersakey(key);
151         ret = 0;
152     } else
153         ret = 1;
154
155   end:
156     smemclr(buf, sizeof(buf));       /* burn the evidence */
157     return ret;
158 }
159
160 int loadrsakey(const Filename *filename, struct RSAKey *key,
161                const char *passphrase, const char **errorstr)
162 {
163     FILE *fp;
164     char buf[64];
165     int ret = 0;
166     const char *error = NULL;
167
168     fp = f_open(filename, "rb", FALSE);
169     if (!fp) {
170         error = "can't open file";
171         goto end;
172     }
173
174     /*
175      * Read the first line of the file and see if it's a v1 private
176      * key file.
177      */
178     if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {
179         /*
180          * This routine will take care of calling fclose() for us.
181          */
182         ret = loadrsakey_main(fp, key, FALSE, NULL, passphrase, &error);
183         fp = NULL;
184         goto end;
185     }
186
187     /*
188      * Otherwise, we have nothing. Return empty-handed.
189      */
190     error = "not an SSH-1 RSA file";
191
192   end:
193     if (fp)
194         fclose(fp);
195     if ((ret != 1) && errorstr)
196         *errorstr = error;
197     return ret;
198 }
199
200 /*
201  * See whether an RSA key is encrypted. Return its comment field as
202  * well.
203  */
204 int rsakey_encrypted(const Filename *filename, char **comment)
205 {
206     FILE *fp;
207     char buf[64];
208
209     fp = f_open(filename, "rb", FALSE);
210     if (!fp)
211         return 0;                      /* doesn't even exist */
212
213     /*
214      * Read the first line of the file and see if it's a v1 private
215      * key file.
216      */
217     if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {
218         const char *dummy;
219         /*
220          * This routine will take care of calling fclose() for us.
221          */
222         return loadrsakey_main(fp, NULL, FALSE, comment, NULL, &dummy);
223     }
224     fclose(fp);
225     return 0;                          /* wasn't the right kind of file */
226 }
227
228 /*
229  * Return a malloc'ed chunk of memory containing the public blob of
230  * an RSA key, as given in the agent protocol (modulus bits,
231  * exponent, modulus).
232  */
233 int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen,
234                    char **commentptr, const char **errorstr)
235 {
236     FILE *fp;
237     char buf[64];
238     struct RSAKey key;
239     int ret;
240     const char *error = NULL;
241
242     /* Default return if we fail. */
243     *blob = NULL;
244     *bloblen = 0;
245     ret = 0;
246
247     fp = f_open(filename, "rb", FALSE);
248     if (!fp) {
249         error = "can't open file";
250         goto end;
251     }
252
253     /*
254      * Read the first line of the file and see if it's a v1 private
255      * key file.
256      */
257     if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {
258         memset(&key, 0, sizeof(key));
259         if (loadrsakey_main(fp, &key, TRUE, commentptr, NULL, &error)) {
260             *blob = rsa_public_blob(&key, bloblen);
261             freersakey(&key);
262             ret = 1;
263         }
264         fp = NULL; /* loadrsakey_main unconditionally closes fp */
265     } else {
266         /*
267          * Try interpreting the file as an SSH-1 public key.
268          */
269         char *line, *p, *bitsp, *expp, *modp, *commentp;
270
271         rewind(fp);
272         line = chomp(fgetline(fp));
273         p = line;
274
275         bitsp = p;
276         p += strspn(p, "0123456789");
277         if (*p != ' ')
278             goto not_public_either;
279         *p++ = '\0';
280
281         expp = p;
282         p += strspn(p, "0123456789");
283         if (*p != ' ')
284             goto not_public_either;
285         *p++ = '\0';
286
287         modp = p;
288         p += strspn(p, "0123456789");
289         if (*p) {
290             if (*p != ' ')
291                 goto not_public_either;
292             *p++ = '\0';
293             commentp = p;
294         } else {
295             commentp = NULL;
296         }
297
298         memset(&key, 0, sizeof(key));
299         key.exponent = bignum_from_decimal(expp);
300         key.modulus = bignum_from_decimal(modp);
301         if (atoi(bitsp) != bignum_bitcount(key.modulus)) {
302             freebn(key.exponent);
303             freebn(key.modulus);
304             sfree(line);
305             error = "key bit count does not match in SSH-1 public key file";
306             goto end;
307         }
308         if (commentptr)
309             *commentptr = commentp ? dupstr(commentp) : NULL;
310         *blob = rsa_public_blob(&key, bloblen);
311         freersakey(&key);
312         sfree(line);
313         fclose(fp);
314         return 1;
315
316       not_public_either:
317         sfree(line);
318         error = "not an SSH-1 RSA file";
319     }
320
321   end:
322     if (fp)
323         fclose(fp);
324     if ((ret != 1) && errorstr)
325         *errorstr = error;
326     return ret;
327 }
328
329 /*
330  * Save an RSA key file. Return nonzero on success.
331  */
332 int saversakey(const Filename *filename, struct RSAKey *key, char *passphrase)
333 {
334     unsigned char buf[16384];
335     unsigned char keybuf[16];
336     struct MD5Context md5c;
337     unsigned char *p, *estart;
338     FILE *fp;
339
340     /*
341      * Write the initial signature.
342      */
343     p = buf;
344     memcpy(p, rsa_signature, sizeof(rsa_signature));
345     p += sizeof(rsa_signature);
346
347     /*
348      * One byte giving encryption type, and one reserved (zero)
349      * uint32.
350      */
351     *p++ = (passphrase ? SSH_CIPHER_3DES : 0);
352     PUT_32BIT(p, 0);
353     p += 4;
354
355     /*
356      * An ordinary SSH-1 public key consists of: a uint32
357      * containing the bit count, then two bignums containing the
358      * modulus and exponent respectively.
359      */
360     PUT_32BIT(p, bignum_bitcount(key->modulus));
361     p += 4;
362     p += ssh1_write_bignum(p, key->modulus);
363     p += ssh1_write_bignum(p, key->exponent);
364
365     /*
366      * A string containing the comment field.
367      */
368     if (key->comment) {
369         PUT_32BIT(p, strlen(key->comment));
370         p += 4;
371         memcpy(p, key->comment, strlen(key->comment));
372         p += strlen(key->comment);
373     } else {
374         PUT_32BIT(p, 0);
375         p += 4;
376     }
377
378     /*
379      * The encrypted portion starts here.
380      */
381     estart = p;
382
383     /*
384      * Two bytes, then the same two bytes repeated.
385      */
386     *p++ = random_byte();
387     *p++ = random_byte();
388     p[0] = p[-2];
389     p[1] = p[-1];
390     p += 2;
391
392     /*
393      * Four more bignums: the decryption exponent, then iqmp, then
394      * q, then p.
395      */
396     p += ssh1_write_bignum(p, key->private_exponent);
397     p += ssh1_write_bignum(p, key->iqmp);
398     p += ssh1_write_bignum(p, key->q);
399     p += ssh1_write_bignum(p, key->p);
400
401     /*
402      * Now write zeros until the encrypted portion is a multiple of
403      * 8 bytes.
404      */
405     while ((p - estart) % 8)
406         *p++ = '\0';
407
408     /*
409      * Now encrypt the encrypted portion.
410      */
411     if (passphrase) {
412         MD5Init(&md5c);
413         MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase));
414         MD5Final(keybuf, &md5c);
415         des3_encrypt_pubkey(keybuf, estart, p - estart);
416         smemclr(keybuf, sizeof(keybuf));        /* burn the evidence */
417     }
418
419     /*
420      * Done. Write the result to the file.
421      */
422     fp = f_open(filename, "wb", TRUE);
423     if (fp) {
424         int ret = (fwrite(buf, 1, p - buf, fp) == (size_t) (p - buf));
425         if (fclose(fp))
426             ret = 0;
427         return ret;
428     } else
429         return 0;
430 }
431
432 /* ----------------------------------------------------------------------
433  * SSH-2 private key load/store functions.
434  */
435
436 /*
437  * PuTTY's own format for SSH-2 keys is as follows:
438  *
439  * The file is text. Lines are terminated by CRLF, although CR-only
440  * and LF-only are tolerated on input.
441  *
442  * The first line says "PuTTY-User-Key-File-2: " plus the name of the
443  * algorithm ("ssh-dss", "ssh-rsa" etc).
444  *
445  * The next line says "Encryption: " plus an encryption type.
446  * Currently the only supported encryption types are "aes256-cbc"
447  * and "none".
448  *
449  * The next line says "Comment: " plus the comment string.
450  *
451  * Next there is a line saying "Public-Lines: " plus a number N.
452  * The following N lines contain a base64 encoding of the public
453  * part of the key. This is encoded as the standard SSH-2 public key
454  * blob (with no initial length): so for RSA, for example, it will
455  * read
456  *
457  *    string "ssh-rsa"
458  *    mpint  exponent
459  *    mpint  modulus
460  *
461  * Next, there is a line saying "Private-Lines: " plus a number N,
462  * and then N lines containing the (potentially encrypted) private
463  * part of the key. For the key type "ssh-rsa", this will be
464  * composed of
465  *
466  *    mpint  private_exponent
467  *    mpint  p                  (the larger of the two primes)
468  *    mpint  q                  (the smaller prime)
469  *    mpint  iqmp               (the inverse of q modulo p)
470  *    data   padding            (to reach a multiple of the cipher block size)
471  *
472  * And for "ssh-dss", it will be composed of
473  *
474  *    mpint  x                  (the private key parameter)
475  *  [ string hash   20-byte hash of mpints p || q || g   only in old format ]
476  * 
477  * Finally, there is a line saying "Private-MAC: " plus a hex
478  * representation of a HMAC-SHA-1 of:
479  *
480  *    string  name of algorithm ("ssh-dss", "ssh-rsa")
481  *    string  encryption type
482  *    string  comment
483  *    string  public-blob
484  *    string  private-plaintext (the plaintext version of the
485  *                               private part, including the final
486  *                               padding)
487  * 
488  * The key to the MAC is itself a SHA-1 hash of:
489  * 
490  *    data    "putty-private-key-file-mac-key"
491  *    data    passphrase
492  *
493  * (An empty passphrase is used for unencrypted keys.)
494  *
495  * If the key is encrypted, the encryption key is derived from the
496  * passphrase by means of a succession of SHA-1 hashes. Each hash
497  * is the hash of:
498  *
499  *    uint32  sequence-number
500  *    data    passphrase
501  *
502  * where the sequence-number increases from zero. As many of these
503  * hashes are used as necessary.
504  *
505  * For backwards compatibility with snapshots between 0.51 and
506  * 0.52, we also support the older key file format, which begins
507  * with "PuTTY-User-Key-File-1" (version number differs). In this
508  * format the Private-MAC: field only covers the private-plaintext
509  * field and nothing else (and without the 4-byte string length on
510  * the front too). Moreover, the Private-MAC: field can be replaced
511  * with a Private-Hash: field which is a plain SHA-1 hash instead of
512  * an HMAC (this was generated for unencrypted keys).
513  */
514
515 static int read_header(FILE * fp, char *header)
516 {
517     int len = 39;
518     int c;
519
520     while (1) {
521         c = fgetc(fp);
522         if (c == '\n' || c == '\r' || c == EOF)
523             return 0;                  /* failure */
524         if (c == ':') {
525             c = fgetc(fp);
526             if (c != ' ')
527                 return 0;
528             *header = '\0';
529             return 1;                  /* success! */
530         }
531         if (len == 0)
532             return 0;                  /* failure */
533         *header++ = c;
534         len--;
535     }
536     return 0;                          /* failure */
537 }
538
539 static char *read_body(FILE * fp)
540 {
541     char *text;
542     int len;
543     int size;
544     int c;
545
546     size = 128;
547     text = snewn(size, char);
548     len = 0;
549     text[len] = '\0';
550
551     while (1) {
552         c = fgetc(fp);
553         if (c == '\r' || c == '\n' || c == EOF) {
554             if (c != EOF) {
555                 c = fgetc(fp);
556                 if (c != '\r' && c != '\n')
557                     ungetc(c, fp);
558             }
559             return text;
560         }
561         if (len + 1 >= size) {
562             size += 128;
563             text = sresize(text, size, char);
564         }
565         text[len++] = c;
566         text[len] = '\0';
567     }
568 }
569
570 static unsigned char *read_blob(FILE * fp, int nlines, int *bloblen)
571 {
572     unsigned char *blob;
573     char *line;
574     int linelen, len;
575     int i, j, k;
576
577     /* We expect at most 64 base64 characters, ie 48 real bytes, per line. */
578     blob = snewn(48 * nlines, unsigned char);
579     len = 0;
580     for (i = 0; i < nlines; i++) {
581         line = read_body(fp);
582         if (!line) {
583             sfree(blob);
584             return NULL;
585         }
586         linelen = strlen(line);
587         if (linelen % 4 != 0 || linelen > 64) {
588             sfree(blob);
589             sfree(line);
590             return NULL;
591         }
592         for (j = 0; j < linelen; j += 4) {
593             k = base64_decode_atom(line + j, blob + len);
594             if (!k) {
595                 sfree(line);
596                 sfree(blob);
597                 return NULL;
598             }
599             len += k;
600         }
601         sfree(line);
602     }
603     *bloblen = len;
604     return blob;
605 }
606
607 /*
608  * Magic error return value for when the passphrase is wrong.
609  */
610 struct ssh2_userkey ssh2_wrong_passphrase = {
611     NULL, NULL, NULL
612 };
613
614 const struct ssh_signkey *find_pubkey_alg_len(int namelen, const char *name)
615 {
616     if (match_ssh_id(namelen, name, "ssh-rsa"))
617         return &ssh_rsa;
618     else if (match_ssh_id(namelen, name, "ssh-dss"))
619         return &ssh_dss;
620     else if (match_ssh_id(namelen, name, "ecdsa-sha2-nistp256"))
621         return &ssh_ecdsa_nistp256;
622     else if (match_ssh_id(namelen, name, "ecdsa-sha2-nistp384"))
623         return &ssh_ecdsa_nistp384;
624     else if (match_ssh_id(namelen, name, "ecdsa-sha2-nistp521"))
625         return &ssh_ecdsa_nistp521;
626     else if (match_ssh_id(namelen, name, "ssh-ed25519"))
627         return &ssh_ecdsa_ed25519;
628     else
629         return NULL;
630 }
631
632 const struct ssh_signkey *find_pubkey_alg(const char *name)
633 {
634     return find_pubkey_alg_len(strlen(name), name);
635 }
636
637 struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
638                                        const char *passphrase,
639                                        const char **errorstr)
640 {
641     FILE *fp;
642     char header[40], *b, *encryption, *comment, *mac;
643     const struct ssh_signkey *alg;
644     struct ssh2_userkey *ret;
645     int cipher, cipherblk;
646     unsigned char *public_blob, *private_blob;
647     int public_blob_len, private_blob_len;
648     int i, is_mac, old_fmt;
649     int passlen = passphrase ? strlen(passphrase) : 0;
650     const char *error = NULL;
651
652     ret = NULL;                        /* return NULL for most errors */
653     encryption = comment = mac = NULL;
654     public_blob = private_blob = NULL;
655
656     fp = f_open(filename, "rb", FALSE);
657     if (!fp) {
658         error = "can't open file";
659         goto error;
660     }
661
662     /* Read the first header line which contains the key type. */
663     if (!read_header(fp, header))
664         goto error;
665     if (0 == strcmp(header, "PuTTY-User-Key-File-2")) {
666         old_fmt = 0;
667     } else if (0 == strcmp(header, "PuTTY-User-Key-File-1")) {
668         /* this is an old key file; warn and then continue */
669         old_keyfile_warning();
670         old_fmt = 1;
671     } else if (0 == strncmp(header, "PuTTY-User-Key-File-", 20)) {
672         /* this is a key file FROM THE FUTURE; refuse it, but with a
673          * more specific error message than the generic one below */
674         error = "PuTTY key format too new";
675         goto error;
676     } else {
677         error = "not a PuTTY SSH-2 private key";
678         goto error;
679     }
680     error = "file format error";
681     if ((b = read_body(fp)) == NULL)
682         goto error;
683     /* Select key algorithm structure. */
684     alg = find_pubkey_alg(b);
685     if (!alg) {
686         sfree(b);
687         goto error;
688     }
689     sfree(b);
690
691     /* Read the Encryption header line. */
692     if (!read_header(fp, header) || 0 != strcmp(header, "Encryption"))
693         goto error;
694     if ((encryption = read_body(fp)) == NULL)
695         goto error;
696     if (!strcmp(encryption, "aes256-cbc")) {
697         cipher = 1;
698         cipherblk = 16;
699     } else if (!strcmp(encryption, "none")) {
700         cipher = 0;
701         cipherblk = 1;
702     } else {
703         goto error;
704     }
705
706     /* Read the Comment header line. */
707     if (!read_header(fp, header) || 0 != strcmp(header, "Comment"))
708         goto error;
709     if ((comment = read_body(fp)) == NULL)
710         goto error;
711
712     /* Read the Public-Lines header line and the public blob. */
713     if (!read_header(fp, header) || 0 != strcmp(header, "Public-Lines"))
714         goto error;
715     if ((b = read_body(fp)) == NULL)
716         goto error;
717     i = atoi(b);
718     sfree(b);
719     if ((public_blob = read_blob(fp, i, &public_blob_len)) == NULL)
720         goto error;
721
722     /* Read the Private-Lines header line and the Private blob. */
723     if (!read_header(fp, header) || 0 != strcmp(header, "Private-Lines"))
724         goto error;
725     if ((b = read_body(fp)) == NULL)
726         goto error;
727     i = atoi(b);
728     sfree(b);
729     if ((private_blob = read_blob(fp, i, &private_blob_len)) == NULL)
730         goto error;
731
732     /* Read the Private-MAC or Private-Hash header line. */
733     if (!read_header(fp, header))
734         goto error;
735     if (0 == strcmp(header, "Private-MAC")) {
736         if ((mac = read_body(fp)) == NULL)
737             goto error;
738         is_mac = 1;
739     } else if (0 == strcmp(header, "Private-Hash") && old_fmt) {
740         if ((mac = read_body(fp)) == NULL)
741             goto error;
742         is_mac = 0;
743     } else
744         goto error;
745
746     fclose(fp);
747     fp = NULL;
748
749     /*
750      * Decrypt the private blob.
751      */
752     if (cipher) {
753         unsigned char key[40];
754         SHA_State s;
755
756         if (!passphrase)
757             goto error;
758         if (private_blob_len % cipherblk)
759             goto error;
760
761         SHA_Init(&s);
762         SHA_Bytes(&s, "\0\0\0\0", 4);
763         SHA_Bytes(&s, passphrase, passlen);
764         SHA_Final(&s, key + 0);
765         SHA_Init(&s);
766         SHA_Bytes(&s, "\0\0\0\1", 4);
767         SHA_Bytes(&s, passphrase, passlen);
768         SHA_Final(&s, key + 20);
769         aes256_decrypt_pubkey(key, private_blob, private_blob_len);
770     }
771
772     /*
773      * Verify the MAC.
774      */
775     {
776         char realmac[41];
777         unsigned char binary[20];
778         unsigned char *macdata;
779         int maclen;
780         int free_macdata;
781
782         if (old_fmt) {
783             /* MAC (or hash) only covers the private blob. */
784             macdata = private_blob;
785             maclen = private_blob_len;
786             free_macdata = 0;
787         } else {
788             unsigned char *p;
789             int namelen = strlen(alg->name);
790             int enclen = strlen(encryption);
791             int commlen = strlen(comment);
792             maclen = (4 + namelen +
793                       4 + enclen +
794                       4 + commlen +
795                       4 + public_blob_len +
796                       4 + private_blob_len);
797             macdata = snewn(maclen, unsigned char);
798             p = macdata;
799 #define DO_STR(s,len) PUT_32BIT(p,(len));memcpy(p+4,(s),(len));p+=4+(len)
800             DO_STR(alg->name, namelen);
801             DO_STR(encryption, enclen);
802             DO_STR(comment, commlen);
803             DO_STR(public_blob, public_blob_len);
804             DO_STR(private_blob, private_blob_len);
805
806             free_macdata = 1;
807         }
808
809         if (is_mac) {
810             SHA_State s;
811             unsigned char mackey[20];
812             char header[] = "putty-private-key-file-mac-key";
813
814             SHA_Init(&s);
815             SHA_Bytes(&s, header, sizeof(header)-1);
816             if (cipher && passphrase)
817                 SHA_Bytes(&s, passphrase, passlen);
818             SHA_Final(&s, mackey);
819
820             hmac_sha1_simple(mackey, 20, macdata, maclen, binary);
821
822             smemclr(mackey, sizeof(mackey));
823             smemclr(&s, sizeof(s));
824         } else {
825             SHA_Simple(macdata, maclen, binary);
826         }
827
828         if (free_macdata) {
829             smemclr(macdata, maclen);
830             sfree(macdata);
831         }
832
833         for (i = 0; i < 20; i++)
834             sprintf(realmac + 2 * i, "%02x", binary[i]);
835
836         if (strcmp(mac, realmac)) {
837             /* An incorrect MAC is an unconditional Error if the key is
838              * unencrypted. Otherwise, it means Wrong Passphrase. */
839             if (cipher) {
840                 error = "wrong passphrase";
841                 ret = SSH2_WRONG_PASSPHRASE;
842             } else {
843                 error = "MAC failed";
844                 ret = NULL;
845             }
846             goto error;
847         }
848     }
849     sfree(mac);
850     mac = NULL;
851
852     /*
853      * Create and return the key.
854      */
855     ret = snew(struct ssh2_userkey);
856     ret->alg = alg;
857     ret->comment = comment;
858     ret->data = alg->createkey(alg, public_blob, public_blob_len,
859                                private_blob, private_blob_len);
860     if (!ret->data) {
861         sfree(ret);
862         ret = NULL;
863         error = "createkey failed";
864         goto error;
865     }
866     sfree(public_blob);
867     smemclr(private_blob, private_blob_len);
868     sfree(private_blob);
869     sfree(encryption);
870     if (errorstr)
871         *errorstr = NULL;
872     return ret;
873
874     /*
875      * Error processing.
876      */
877   error:
878     if (fp)
879         fclose(fp);
880     if (comment)
881         sfree(comment);
882     if (encryption)
883         sfree(encryption);
884     if (mac)
885         sfree(mac);
886     if (public_blob)
887         sfree(public_blob);
888     if (private_blob) {
889         smemclr(private_blob, private_blob_len);
890         sfree(private_blob);
891     }
892     if (errorstr)
893         *errorstr = error;
894     return ret;
895 }
896
897 unsigned char *rfc4716_loadpub(FILE *fp, char **algorithm,
898                                int *pub_blob_len, char **commentptr,
899                                const char **errorstr)
900 {
901     const char *error;
902     char *line, *colon, *value;
903     char *comment = NULL;
904     unsigned char *pubblob = NULL;
905     int pubbloblen, pubblobsize;
906     char base64in[4];
907     unsigned char base64out[3];
908     int base64bytes;
909     int alglen;
910
911     line = chomp(fgetline(fp));
912     if (!line || 0 != strcmp(line, "---- BEGIN SSH2 PUBLIC KEY ----")) {
913         error = "invalid begin line in SSH-2 public key file";
914         goto error;
915     }
916     sfree(line); line = NULL;
917
918     while (1) {
919         line = chomp(fgetline(fp));
920         if (!line) {
921             error = "truncated SSH-2 public key file";
922             goto error;
923         }
924         colon = strstr(line, ": ");
925         if (!colon)
926             break;
927         *colon = '\0';
928         value = colon + 2;
929
930         if (!strcmp(line, "Comment")) {
931             char *p, *q;
932
933             /* Remove containing double quotes, if present */
934             p = value;
935             if (*p == '"' && p[strlen(p)-1] == '"') {
936                 p[strlen(p)-1] = '\0';
937                 p++;
938             }
939
940             /* Remove \-escaping, not in RFC4716 but seen in the wild
941              * in practice. */
942             for (q = line; *p; p++) {
943                 if (*p == '\\' && p[1])
944                     p++;
945                 *q++ = *p;
946             }
947
948             *q = '\0';
949             comment = dupstr(line);
950         } else if (!strcmp(line, "Subject") ||
951                    !strncmp(line, "x-", 2)) {
952             /* Headers we recognise and ignore. Do nothing. */
953         } else {
954             error = "unrecognised header in SSH-2 public key file";
955             goto error;
956         }
957
958         sfree(line); line = NULL;
959     }
960
961     /*
962      * Now line contains the initial line of base64 data. Loop round
963      * while it still does contain base64.
964      */
965     pubblobsize = 4096;
966     pubblob = snewn(pubblobsize, unsigned char);
967     pubbloblen = 0;
968     base64bytes = 0;
969     while (line && line[0] != '-') {
970         char *p;
971         for (p = line; *p; p++) {
972             base64in[base64bytes++] = *p;
973             if (base64bytes == 4) {
974                 int n = base64_decode_atom(base64in, base64out);
975                 if (pubbloblen + n > pubblobsize) {
976                     pubblobsize = (pubbloblen + n) * 5 / 4 + 1024;
977                     pubblob = sresize(pubblob, pubblobsize, unsigned char);
978                 }
979                 memcpy(pubblob + pubbloblen, base64out, n);
980                 pubbloblen += n;
981                 base64bytes = 0;
982             }
983         }
984         sfree(line); line = NULL;
985         line = chomp(fgetline(fp));
986     }
987
988     /*
989      * Finally, check the END line makes sense.
990      */
991     if (!line || 0 != strcmp(line, "---- END SSH2 PUBLIC KEY ----")) {
992         error = "invalid end line in SSH-2 public key file";
993         goto error;
994     }
995     sfree(line); line = NULL;
996
997     /*
998      * OK, we now have a public blob and optionally a comment. We must
999      * return the key algorithm string too, so look for that at the
1000      * start of the public blob.
1001      */
1002     if (pubbloblen < 4) {
1003         error = "not enough data in SSH-2 public key file";
1004         goto error;
1005     }
1006     alglen = toint(GET_32BIT(pubblob));
1007     if (alglen < 0 || alglen > pubbloblen-4) {
1008         error = "invalid algorithm prefix in SSH-2 public key file";
1009         goto error;
1010     }
1011     if (algorithm)
1012         *algorithm = dupprintf("%.*s", alglen, pubblob+4);
1013     if (pub_blob_len)
1014         *pub_blob_len = pubbloblen;
1015     if (commentptr)
1016         *commentptr = comment;
1017     else
1018         sfree(comment);
1019     return pubblob;
1020
1021   error:
1022     sfree(line);
1023     sfree(comment);
1024     sfree(pubblob);
1025     if (errorstr)
1026         *errorstr = error;
1027     return NULL;
1028 }
1029
1030 unsigned char *openssh_loadpub(FILE *fp, char **algorithm,
1031                                int *pub_blob_len, char **commentptr,
1032                                const char **errorstr)
1033 {
1034     const char *error;
1035     char *line, *base64;
1036     char *comment = NULL;
1037     unsigned char *pubblob = NULL;
1038     int pubbloblen, pubblobsize;
1039     int alglen;
1040
1041     line = chomp(fgetline(fp));
1042
1043     base64 = strchr(line, ' ');
1044     if (!base64) {
1045         error = "no key blob in OpenSSH public key file";
1046         goto error;
1047     }
1048     *base64++ = '\0';
1049
1050     comment = strchr(base64, ' ');
1051     if (comment) {
1052         *comment++ = '\0';
1053         comment = dupstr(comment);
1054     }
1055
1056     pubblobsize = strlen(base64) / 4 * 3;
1057     pubblob = snewn(pubblobsize, unsigned char);
1058     pubbloblen = 0;
1059
1060     while (!memchr(base64, '\0', 4)) {
1061         assert(pubbloblen + 3 <= pubblobsize);
1062         pubbloblen += base64_decode_atom(base64, pubblob + pubbloblen);
1063         base64 += 4;
1064     }
1065     if (*base64) {
1066         error = "invalid length for base64 data in OpenSSH public key file";
1067         goto error;
1068     }
1069
1070     /*
1071      * Sanity check: the first word on the line should be the key
1072      * algorithm, and should match the encoded string at the start of
1073      * the public blob.
1074      */
1075     alglen = strlen(line);
1076     if (pubbloblen < alglen + 4 ||
1077         GET_32BIT(pubblob) != alglen ||
1078         0 != memcmp(pubblob + 4, line, alglen)) {
1079         error = "key algorithms do not match in OpenSSH public key file";
1080         goto error;
1081     }
1082
1083     /*
1084      * Done.
1085      */
1086     if (algorithm)
1087         *algorithm = dupstr(line);
1088     if (pub_blob_len)
1089         *pub_blob_len = pubbloblen;
1090     if (commentptr)
1091         *commentptr = comment;
1092     else
1093         sfree(comment);
1094     sfree(line);
1095     return pubblob;
1096
1097   error:
1098     sfree(line);
1099     sfree(comment);
1100     sfree(pubblob);
1101     if (errorstr)
1102         *errorstr = error;
1103     return NULL;
1104 }
1105
1106 unsigned char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
1107                                     int *pub_blob_len, char **commentptr,
1108                                     const char **errorstr)
1109 {
1110     FILE *fp;
1111     char header[40], *b;
1112     const struct ssh_signkey *alg;
1113     unsigned char *public_blob;
1114     int public_blob_len;
1115     int type, i;
1116     const char *error = NULL;
1117     char *comment = NULL;
1118
1119     public_blob = NULL;
1120
1121     fp = f_open(filename, "rb", FALSE);
1122     if (!fp) {
1123         error = "can't open file";
1124         goto error;
1125     }
1126
1127     /* Initially, check if this is a public-only key file. Sometimes
1128      * we'll be asked to read a public blob from one of those. */
1129     type = key_type_fp(fp);
1130     if (type == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716) {
1131         unsigned char *ret = rfc4716_loadpub(fp, algorithm, pub_blob_len,
1132                                              commentptr, errorstr);
1133         fclose(fp);
1134         return ret;
1135     } else if (type == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) {
1136         unsigned char *ret = openssh_loadpub(fp, algorithm, pub_blob_len,
1137                                              commentptr, errorstr);
1138         fclose(fp);
1139         return ret;
1140     } else if (type != SSH_KEYTYPE_SSH2) {
1141         error = "not a PuTTY SSH-2 private key";
1142         goto error;
1143     }
1144
1145     /* Read the first header line which contains the key type. */
1146     if (!read_header(fp, header)
1147         || (0 != strcmp(header, "PuTTY-User-Key-File-2") &&
1148             0 != strcmp(header, "PuTTY-User-Key-File-1"))) {
1149         if (0 == strncmp(header, "PuTTY-User-Key-File-", 20))
1150             error = "PuTTY key format too new";
1151         else
1152             error = "not a PuTTY SSH-2 private key";
1153         goto error;
1154     }
1155     error = "file format error";
1156     if ((b = read_body(fp)) == NULL)
1157         goto error;
1158     /* Select key algorithm structure. */
1159     alg = find_pubkey_alg(b);
1160     sfree(b);
1161     if (!alg) {
1162         goto error;
1163     }
1164
1165     /* Read the Encryption header line. */
1166     if (!read_header(fp, header) || 0 != strcmp(header, "Encryption"))
1167         goto error;
1168     if ((b = read_body(fp)) == NULL)
1169         goto error;
1170     sfree(b);                          /* we don't care */
1171
1172     /* Read the Comment header line. */
1173     if (!read_header(fp, header) || 0 != strcmp(header, "Comment"))
1174         goto error;
1175     if ((comment = read_body(fp)) == NULL)
1176         goto error;
1177
1178     if (commentptr)
1179         *commentptr = comment;
1180     else
1181         sfree(comment);
1182
1183     /* Read the Public-Lines header line and the public blob. */
1184     if (!read_header(fp, header) || 0 != strcmp(header, "Public-Lines"))
1185         goto error;
1186     if ((b = read_body(fp)) == NULL)
1187         goto error;
1188     i = atoi(b);
1189     sfree(b);
1190     if ((public_blob = read_blob(fp, i, &public_blob_len)) == NULL)
1191         goto error;
1192
1193     fclose(fp);
1194     if (pub_blob_len)
1195         *pub_blob_len = public_blob_len;
1196     if (algorithm)
1197         *algorithm = dupstr(alg->name);
1198     return public_blob;
1199
1200     /*
1201      * Error processing.
1202      */
1203   error:
1204     if (fp)
1205         fclose(fp);
1206     if (public_blob)
1207         sfree(public_blob);
1208     if (errorstr)
1209         *errorstr = error;
1210     if (comment && commentptr) {
1211         sfree(comment);
1212         *commentptr = NULL;
1213     }
1214     return NULL;
1215 }
1216
1217 int ssh2_userkey_encrypted(const Filename *filename, char **commentptr)
1218 {
1219     FILE *fp;
1220     char header[40], *b, *comment;
1221     int ret;
1222
1223     if (commentptr)
1224         *commentptr = NULL;
1225
1226     fp = f_open(filename, "rb", FALSE);
1227     if (!fp)
1228         return 0;
1229     if (!read_header(fp, header)
1230         || (0 != strcmp(header, "PuTTY-User-Key-File-2") &&
1231             0 != strcmp(header, "PuTTY-User-Key-File-1"))) {
1232         fclose(fp);
1233         return 0;
1234     }
1235     if ((b = read_body(fp)) == NULL) {
1236         fclose(fp);
1237         return 0;
1238     }
1239     sfree(b);                          /* we don't care about key type here */
1240     /* Read the Encryption header line. */
1241     if (!read_header(fp, header) || 0 != strcmp(header, "Encryption")) {
1242         fclose(fp);
1243         return 0;
1244     }
1245     if ((b = read_body(fp)) == NULL) {
1246         fclose(fp);
1247         return 0;
1248     }
1249
1250     /* Read the Comment header line. */
1251     if (!read_header(fp, header) || 0 != strcmp(header, "Comment")) {
1252         fclose(fp);
1253         sfree(b);
1254         return 1;
1255     }
1256     if ((comment = read_body(fp)) == NULL) {
1257         fclose(fp);
1258         sfree(b);
1259         return 1;
1260     }
1261
1262     if (commentptr)
1263         *commentptr = comment;
1264     else
1265         sfree(comment);
1266
1267     fclose(fp);
1268     if (!strcmp(b, "aes256-cbc"))
1269         ret = 1;
1270     else
1271         ret = 0;
1272     sfree(b);
1273     return ret;
1274 }
1275
1276 int base64_lines(int datalen)
1277 {
1278     /* When encoding, we use 64 chars/line, which equals 48 real chars. */
1279     return (datalen + 47) / 48;
1280 }
1281
1282 void base64_encode(FILE *fp, const unsigned char *data, int datalen, int cpl)
1283 {
1284     int linelen = 0;
1285     char out[4];
1286     int n, i;
1287
1288     while (datalen > 0) {
1289         n = (datalen < 3 ? datalen : 3);
1290         base64_encode_atom(data, n, out);
1291         data += n;
1292         datalen -= n;
1293         for (i = 0; i < 4; i++) {
1294             if (linelen >= cpl) {
1295                 linelen = 0;
1296                 fputc('\n', fp);
1297             }
1298             fputc(out[i], fp);
1299             linelen++;
1300         }
1301     }
1302     fputc('\n', fp);
1303 }
1304
1305 int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
1306                       char *passphrase)
1307 {
1308     FILE *fp;
1309     unsigned char *pub_blob, *priv_blob, *priv_blob_encrypted;
1310     int pub_blob_len, priv_blob_len, priv_encrypted_len;
1311     int passlen;
1312     int cipherblk;
1313     int i;
1314     const char *cipherstr;
1315     unsigned char priv_mac[20];
1316
1317     /*
1318      * Fetch the key component blobs.
1319      */
1320     pub_blob = key->alg->public_blob(key->data, &pub_blob_len);
1321     priv_blob = key->alg->private_blob(key->data, &priv_blob_len);
1322     if (!pub_blob || !priv_blob) {
1323         sfree(pub_blob);
1324         sfree(priv_blob);
1325         return 0;
1326     }
1327
1328     /*
1329      * Determine encryption details, and encrypt the private blob.
1330      */
1331     if (passphrase) {
1332         cipherstr = "aes256-cbc";
1333         cipherblk = 16;
1334     } else {
1335         cipherstr = "none";
1336         cipherblk = 1;
1337     }
1338     priv_encrypted_len = priv_blob_len + cipherblk - 1;
1339     priv_encrypted_len -= priv_encrypted_len % cipherblk;
1340     priv_blob_encrypted = snewn(priv_encrypted_len, unsigned char);
1341     memset(priv_blob_encrypted, 0, priv_encrypted_len);
1342     memcpy(priv_blob_encrypted, priv_blob, priv_blob_len);
1343     /* Create padding based on the SHA hash of the unpadded blob. This prevents
1344      * too easy a known-plaintext attack on the last block. */
1345     SHA_Simple(priv_blob, priv_blob_len, priv_mac);
1346     assert(priv_encrypted_len - priv_blob_len < 20);
1347     memcpy(priv_blob_encrypted + priv_blob_len, priv_mac,
1348            priv_encrypted_len - priv_blob_len);
1349
1350     /* Now create the MAC. */
1351     {
1352         unsigned char *macdata;
1353         int maclen;
1354         unsigned char *p;
1355         int namelen = strlen(key->alg->name);
1356         int enclen = strlen(cipherstr);
1357         int commlen = strlen(key->comment);
1358         SHA_State s;
1359         unsigned char mackey[20];
1360         char header[] = "putty-private-key-file-mac-key";
1361
1362         maclen = (4 + namelen +
1363                   4 + enclen +
1364                   4 + commlen +
1365                   4 + pub_blob_len +
1366                   4 + priv_encrypted_len);
1367         macdata = snewn(maclen, unsigned char);
1368         p = macdata;
1369 #define DO_STR(s,len) PUT_32BIT(p,(len));memcpy(p+4,(s),(len));p+=4+(len)
1370         DO_STR(key->alg->name, namelen);
1371         DO_STR(cipherstr, enclen);
1372         DO_STR(key->comment, commlen);
1373         DO_STR(pub_blob, pub_blob_len);
1374         DO_STR(priv_blob_encrypted, priv_encrypted_len);
1375
1376         SHA_Init(&s);
1377         SHA_Bytes(&s, header, sizeof(header)-1);
1378         if (passphrase)
1379             SHA_Bytes(&s, passphrase, strlen(passphrase));
1380         SHA_Final(&s, mackey);
1381         hmac_sha1_simple(mackey, 20, macdata, maclen, priv_mac);
1382         smemclr(macdata, maclen);
1383         sfree(macdata);
1384         smemclr(mackey, sizeof(mackey));
1385         smemclr(&s, sizeof(s));
1386     }
1387
1388     if (passphrase) {
1389         unsigned char key[40];
1390         SHA_State s;
1391
1392         passlen = strlen(passphrase);
1393
1394         SHA_Init(&s);
1395         SHA_Bytes(&s, "\0\0\0\0", 4);
1396         SHA_Bytes(&s, passphrase, passlen);
1397         SHA_Final(&s, key + 0);
1398         SHA_Init(&s);
1399         SHA_Bytes(&s, "\0\0\0\1", 4);
1400         SHA_Bytes(&s, passphrase, passlen);
1401         SHA_Final(&s, key + 20);
1402         aes256_encrypt_pubkey(key, priv_blob_encrypted,
1403                               priv_encrypted_len);
1404
1405         smemclr(key, sizeof(key));
1406         smemclr(&s, sizeof(s));
1407     }
1408
1409     fp = f_open(filename, "w", TRUE);
1410     if (!fp) {
1411         sfree(pub_blob);
1412         smemclr(priv_blob, priv_blob_len);
1413         sfree(priv_blob);
1414         smemclr(priv_blob_encrypted, priv_blob_len);
1415         sfree(priv_blob_encrypted);
1416         return 0;
1417     }
1418     fprintf(fp, "PuTTY-User-Key-File-2: %s\n", key->alg->name);
1419     fprintf(fp, "Encryption: %s\n", cipherstr);
1420     fprintf(fp, "Comment: %s\n", key->comment);
1421     fprintf(fp, "Public-Lines: %d\n", base64_lines(pub_blob_len));
1422     base64_encode(fp, pub_blob, pub_blob_len, 64);
1423     fprintf(fp, "Private-Lines: %d\n", base64_lines(priv_encrypted_len));
1424     base64_encode(fp, priv_blob_encrypted, priv_encrypted_len, 64);
1425     fprintf(fp, "Private-MAC: ");
1426     for (i = 0; i < 20; i++)
1427         fprintf(fp, "%02x", priv_mac[i]);
1428     fprintf(fp, "\n");
1429     fclose(fp);
1430
1431     sfree(pub_blob);
1432     smemclr(priv_blob, priv_blob_len);
1433     sfree(priv_blob);
1434     smemclr(priv_blob_encrypted, priv_blob_len);
1435     sfree(priv_blob_encrypted);
1436     return 1;
1437 }
1438
1439 /* ----------------------------------------------------------------------
1440  * Output public keys.
1441  */
1442 char *ssh1_pubkey_str(struct RSAKey *key)
1443 {
1444     char *buffer;
1445     char *dec1, *dec2;
1446
1447     dec1 = bignum_decimal(key->exponent);
1448     dec2 = bignum_decimal(key->modulus);
1449     buffer = dupprintf("%d %s %s%s%s", bignum_bitcount(key->modulus),
1450                        dec1, dec2,
1451                        key->comment ? " " : "",
1452                        key->comment ? key->comment : "");
1453     sfree(dec1);
1454     sfree(dec2);
1455     return buffer;
1456 }
1457
1458 void ssh1_write_pubkey(FILE *fp, struct RSAKey *key)
1459 {
1460     char *buffer = ssh1_pubkey_str(key);
1461     fprintf(fp, "%s\n", buffer);
1462     sfree(buffer);
1463 }
1464
1465 static char *ssh2_pubkey_openssh_str_internal(const char *comment,
1466                                               const void *v_pub_blob,
1467                                               int pub_len)
1468 {
1469     const unsigned char *ssh2blob = (const unsigned char *)v_pub_blob;
1470     const char *alg;
1471     int alglen;
1472     char *buffer, *p;
1473     int i;
1474
1475     if (pub_len < 4) {
1476         alg = NULL;
1477     } else {
1478         alglen = GET_32BIT(ssh2blob);
1479         if (alglen > 0 && alglen < pub_len - 4) {
1480             alg = (const char *)ssh2blob + 4;
1481         } else {
1482             alg = NULL;
1483         }
1484     }
1485
1486     if (!alg) {
1487         alg = "INVALID-ALGORITHM";
1488         alglen = strlen(alg);
1489     }
1490
1491     buffer = snewn(alglen +
1492                    4 * ((pub_len+2) / 3) +
1493                    (comment ? strlen(comment) : 0) + 3, char);
1494     p = buffer + sprintf(buffer, "%.*s ", alglen, alg);
1495     i = 0;
1496     while (i < pub_len) {
1497         int n = (pub_len - i < 3 ? pub_len - i : 3);
1498         base64_encode_atom(ssh2blob + i, n, p);
1499         i += n;
1500         p += 4;
1501     }
1502     if (*comment) {
1503         *p++ = ' ';
1504         strcpy(p, comment);
1505     } else
1506         *p++ = '\0';
1507
1508     return buffer;
1509 }
1510
1511 char *ssh2_pubkey_openssh_str(struct ssh2_userkey *key)
1512 {
1513     int bloblen;
1514     unsigned char *blob;
1515     char *ret;
1516
1517     blob = key->alg->public_blob(key->data, &bloblen);
1518     ret = ssh2_pubkey_openssh_str_internal(key->comment, blob, bloblen);
1519     sfree(blob);
1520
1521     return ret;
1522 }
1523
1524 void ssh2_write_pubkey(FILE *fp, const char *comment,
1525                        const void *v_pub_blob, int pub_len,
1526                        int keytype)
1527 {
1528     unsigned char *pub_blob = (unsigned char *)v_pub_blob;
1529
1530     if (keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716) {
1531         const char *p;
1532         int i, column;
1533
1534         fprintf(fp, "---- BEGIN SSH2 PUBLIC KEY ----\n");
1535
1536         if (comment) {
1537             fprintf(fp, "Comment: \"");
1538             for (p = comment; *p; p++) {
1539                 if (*p == '\\' || *p == '\"')
1540                     fputc('\\', fp);
1541                 fputc(*p, fp);
1542             }
1543             fprintf(fp, "\"\n");
1544         }
1545
1546         i = 0;
1547         column = 0;
1548         while (i < pub_len) {
1549             char buf[5];
1550             int n = (pub_len - i < 3 ? pub_len - i : 3);
1551             base64_encode_atom(pub_blob + i, n, buf);
1552             i += n;
1553             buf[4] = '\0';
1554             fputs(buf, fp);
1555             if (++column >= 16) {
1556                 fputc('\n', fp);
1557                 column = 0;
1558             }
1559         }
1560         if (column > 0)
1561             fputc('\n', fp);
1562
1563         fprintf(fp, "---- END SSH2 PUBLIC KEY ----\n");
1564     } else if (keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) {
1565         char *buffer = ssh2_pubkey_openssh_str_internal(comment,
1566                                                         v_pub_blob, pub_len);
1567         fprintf(fp, "%s\n", buffer);
1568         sfree(buffer);
1569     } else {
1570         assert(0 && "Bad key type in ssh2_write_pubkey");
1571     }
1572 }
1573
1574 /* ----------------------------------------------------------------------
1575  * Utility functions to compute SSH-2 fingerprints in a uniform way.
1576  */
1577 char *ssh2_fingerprint_blob(const void *blob, int bloblen)
1578 {
1579     unsigned char digest[16];
1580     char fingerprint_str[16*3];
1581     const char *algstr;
1582     int alglen;
1583     const struct ssh_signkey *alg;
1584     int i;
1585
1586     /*
1587      * The fingerprint hash itself is always just the MD5 of the blob.
1588      */
1589     MD5Simple(blob, bloblen, digest);
1590     for (i = 0; i < 16; i++)
1591         sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":");
1592
1593     /*
1594      * Identify the key algorithm, if possible.
1595      */
1596     alglen = toint(GET_32BIT((const unsigned char *)blob));
1597     if (alglen > 0 && alglen < bloblen-4) {
1598         algstr = (const char *)blob + 4;
1599
1600         /*
1601          * If we can actually identify the algorithm as one we know
1602          * about, get hold of the key's bit count too.
1603          */
1604         alg = find_pubkey_alg_len(alglen, algstr);
1605         if (alg) {
1606             int bits = alg->pubkey_bits(alg, blob, bloblen);
1607             return dupprintf("%.*s %d %s", alglen, algstr,
1608                              bits, fingerprint_str);
1609         } else {
1610             return dupprintf("%.*s %s", alglen, algstr, fingerprint_str);
1611         }
1612     } else {
1613         /*
1614          * No algorithm available (which means a seriously confused
1615          * key blob, but there we go). Return only the hash.
1616          */
1617         return dupstr(fingerprint_str);
1618     }
1619 }
1620
1621 char *ssh2_fingerprint(const struct ssh_signkey *alg, void *data)
1622 {
1623     int len;
1624     unsigned char *blob = alg->public_blob(data, &len);
1625     char *ret = ssh2_fingerprint_blob(blob, len);
1626     sfree(blob);
1627     return ret;
1628 }
1629
1630 /* ----------------------------------------------------------------------
1631  * Determine the type of a private key file.
1632  */
1633 static int key_type_fp(FILE *fp)
1634 {
1635     char buf[1024];
1636     const char public_std_sig[] = "---- BEGIN SSH2 PUBLIC KEY";
1637     const char putty2_sig[] = "PuTTY-User-Key-File-";
1638     const char sshcom_sig[] = "---- BEGIN SSH2 ENCRYPTED PRIVAT";
1639     const char openssh_new_sig[] = "-----BEGIN OPENSSH PRIVATE KEY";
1640     const char openssh_sig[] = "-----BEGIN ";
1641     int i;
1642     char *p;
1643
1644     i = fread(buf, 1, sizeof(buf)-1, fp);
1645     rewind(fp);
1646
1647     if (i < 0)
1648         return SSH_KEYTYPE_UNOPENABLE;
1649     if (i < 32)
1650         return SSH_KEYTYPE_UNKNOWN;
1651     assert(i > 0 && i < sizeof(buf));
1652     buf[i] = '\0';
1653     if (!memcmp(buf, rsa_signature, sizeof(rsa_signature)-1))
1654         return SSH_KEYTYPE_SSH1;
1655     if (!memcmp(buf, public_std_sig, sizeof(public_std_sig)-1))
1656         return SSH_KEYTYPE_SSH2_PUBLIC_RFC4716;
1657     if (!memcmp(buf, putty2_sig, sizeof(putty2_sig)-1))
1658         return SSH_KEYTYPE_SSH2;
1659     if (!memcmp(buf, openssh_new_sig, sizeof(openssh_new_sig)-1))
1660         return SSH_KEYTYPE_OPENSSH_NEW;
1661     if (!memcmp(buf, openssh_sig, sizeof(openssh_sig)-1))
1662         return SSH_KEYTYPE_OPENSSH_PEM;
1663     if (!memcmp(buf, sshcom_sig, sizeof(sshcom_sig)-1))
1664         return SSH_KEYTYPE_SSHCOM;
1665     if ((p = buf + strspn(buf, "0123456789"), *p == ' ') &&
1666         (p = p+1 + strspn(p+1, "0123456789"), *p == ' ') &&
1667         (p = p+1 + strspn(p+1, "0123456789"), *p == ' ' || *p == '\n' || !*p))
1668         return SSH_KEYTYPE_SSH1_PUBLIC;
1669     if ((p = buf + strcspn(buf, " "), find_pubkey_alg_len(p-buf, buf)) &&
1670         (p = p+1 + strspn(p+1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij"
1671                           "klmnopqrstuvwxyz+/="),
1672          *p == ' ' || *p == '\n' || !*p))
1673         return SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH;
1674     return SSH_KEYTYPE_UNKNOWN;        /* unrecognised or EOF */
1675 }
1676
1677 int key_type(const Filename *filename)
1678 {
1679     FILE *fp;
1680     int ret;
1681
1682     fp = f_open(filename, "r", FALSE);
1683     if (!fp)
1684         return SSH_KEYTYPE_UNOPENABLE;
1685     ret = key_type_fp(fp);
1686     fclose(fp);
1687     return ret;
1688 }
1689
1690 /*
1691  * Convert the type word to a string, for `wrong type' error
1692  * messages.
1693  */
1694 const char *key_type_to_str(int type)
1695 {
1696     switch (type) {
1697       case SSH_KEYTYPE_UNOPENABLE: return "unable to open file"; break;
1698       case SSH_KEYTYPE_UNKNOWN: return "not a recognised key file format"; break;
1699       case SSH_KEYTYPE_SSH1_PUBLIC: return "SSH-1 public key"; break;
1700       case SSH_KEYTYPE_SSH2_PUBLIC_RFC4716: return "SSH-2 public key (RFC 4716 format)"; break;
1701       case SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH: return "SSH-2 public key (OpenSSH format)"; break;
1702       case SSH_KEYTYPE_SSH1: return "SSH-1 private key"; break;
1703       case SSH_KEYTYPE_SSH2: return "PuTTY SSH-2 private key"; break;
1704       case SSH_KEYTYPE_OPENSSH_PEM: return "OpenSSH SSH-2 private key (old PEM format)"; break;
1705       case SSH_KEYTYPE_OPENSSH_NEW: return "OpenSSH SSH-2 private key (new format)"; break;
1706       case SSH_KEYTYPE_SSHCOM: return "ssh.com SSH-2 private key"; break;
1707         /*
1708          * This function is called with a key type derived from
1709          * looking at an actual key file, so the output-only type
1710          * OPENSSH_AUTO should never get here, and is much an INTERNAL
1711          * ERROR as a code we don't even understand.
1712          */
1713       case SSH_KEYTYPE_OPENSSH_AUTO: return "INTERNAL ERROR (OPENSSH_AUTO)"; break;
1714       default: return "INTERNAL ERROR"; break;
1715     }
1716 }