]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - pageant.c
first pass
[PuTTY.git] / pageant.c
1 /*
2  * pageant.c: cross-platform code to implement Pageant.
3  */
4
5 #include <stddef.h>
6 #include <stdlib.h>
7 #include <assert.h>
8
9 #include "putty.h"
10 #include "ssh.h"
11 #include "pageant.h"
12
13 /*
14  * We need this to link with the RSA code, because rsaencrypt()
15  * pads its data with random bytes. Since we only use rsadecrypt()
16  * and the signing functions, which are deterministic, this should
17  * never be called.
18  *
19  * If it _is_ called, there is a _serious_ problem, because it
20  * won't generate true random numbers. So we must scream, panic,
21  * and exit immediately if that should happen.
22  */
23 int random_byte(void)
24 {
25     modalfatalbox("Internal error: attempt to use random numbers in Pageant");
26     exit(0);
27     return 0;                 /* unreachable, but placate optimiser */
28 }
29
30 static int pageant_local = FALSE;
31
32 /*
33  * rsakeys stores SSH-1 RSA keys. ssh2keys stores all SSH-2 keys.
34  */
35 static tree234 *rsakeys, *ssh2keys;
36
37 /*
38  * Blob structure for passing to the asymmetric SSH-2 key compare
39  * function, prototyped here.
40  */
41 struct blob {
42     const unsigned char *blob;
43     int len;
44 };
45 static int cmpkeys_ssh2_asymm(void *av, void *bv);
46
47 /*
48  * Key comparison function for the 2-3-4 tree of RSA keys.
49  */
50 static int cmpkeys_rsa(void *av, void *bv)
51 {
52     struct RSAKey *a = (struct RSAKey *) av;
53     struct RSAKey *b = (struct RSAKey *) bv;
54     Bignum am, bm;
55     int alen, blen;
56
57     am = a->modulus;
58     bm = b->modulus;
59     /*
60      * Compare by length of moduli.
61      */
62     alen = bignum_bitcount(am);
63     blen = bignum_bitcount(bm);
64     if (alen > blen)
65         return +1;
66     else if (alen < blen)
67         return -1;
68     /*
69      * Now compare by moduli themselves.
70      */
71     alen = (alen + 7) / 8;             /* byte count */
72     while (alen-- > 0) {
73         int abyte, bbyte;
74         abyte = bignum_byte(am, alen);
75         bbyte = bignum_byte(bm, alen);
76         if (abyte > bbyte)
77             return +1;
78         else if (abyte < bbyte)
79             return -1;
80     }
81     /*
82      * Give up.
83      */
84     return 0;
85 }
86
87 /*
88  * Key comparison function for the 2-3-4 tree of SSH-2 keys.
89  */
90 static int cmpkeys_ssh2(void *av, void *bv)
91 {
92     struct ssh2_userkey *a = (struct ssh2_userkey *) av;
93     struct ssh2_userkey *b = (struct ssh2_userkey *) bv;
94     int i;
95     int alen, blen;
96     unsigned char *ablob, *bblob;
97     int c;
98
99     /*
100      * Compare purely by public blob.
101      */
102     ablob = a->alg->public_blob(a->data, &alen);
103     bblob = b->alg->public_blob(b->data, &blen);
104
105     c = 0;
106     for (i = 0; i < alen && i < blen; i++) {
107         if (ablob[i] < bblob[i]) {
108             c = -1;
109             break;
110         } else if (ablob[i] > bblob[i]) {
111             c = +1;
112             break;
113         }
114     }
115     if (c == 0 && i < alen)
116         c = +1;                        /* a is longer */
117     if (c == 0 && i < blen)
118         c = -1;                        /* a is longer */
119
120     sfree(ablob);
121     sfree(bblob);
122
123     return c;
124 }
125
126 /*
127  * Key comparison function for looking up a blob in the 2-3-4 tree
128  * of SSH-2 keys.
129  */
130 static int cmpkeys_ssh2_asymm(void *av, void *bv)
131 {
132     struct blob *a = (struct blob *) av;
133     struct ssh2_userkey *b = (struct ssh2_userkey *) bv;
134     int i;
135     int alen, blen;
136     const unsigned char *ablob;
137     unsigned char *bblob;
138     int c;
139
140     /*
141      * Compare purely by public blob.
142      */
143     ablob = a->blob;
144     alen = a->len;
145     bblob = b->alg->public_blob(b->data, &blen);
146
147     c = 0;
148     for (i = 0; i < alen && i < blen; i++) {
149         if (ablob[i] < bblob[i]) {
150             c = -1;
151             break;
152         } else if (ablob[i] > bblob[i]) {
153             c = +1;
154             break;
155         }
156     }
157     if (c == 0 && i < alen)
158         c = +1;                        /* a is longer */
159     if (c == 0 && i < blen)
160         c = -1;                        /* a is longer */
161
162     sfree(bblob);
163
164     return c;
165 }
166
167 /*
168  * Create an SSH-1 key list in a malloc'ed buffer; return its
169  * length.
170  */
171 void *pageant_make_keylist1(int *length)
172 {
173     int i, nkeys, len;
174     struct RSAKey *key;
175     unsigned char *blob, *p, *ret;
176     int bloblen;
177
178     /*
179      * Count up the number and length of keys we hold.
180      */
181     len = 4;
182     nkeys = 0;
183     for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
184         nkeys++;
185         blob = rsa_public_blob(key, &bloblen);
186         len += bloblen;
187         sfree(blob);
188         len += 4 + strlen(key->comment);
189     }
190
191     /* Allocate the buffer. */
192     p = ret = snewn(len, unsigned char);
193     if (length) *length = len;
194
195     PUT_32BIT(p, nkeys);
196     p += 4;
197     for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
198         blob = rsa_public_blob(key, &bloblen);
199         memcpy(p, blob, bloblen);
200         p += bloblen;
201         sfree(blob);
202         PUT_32BIT(p, strlen(key->comment));
203         memcpy(p + 4, key->comment, strlen(key->comment));
204         p += 4 + strlen(key->comment);
205     }
206
207     assert(p - ret == len);
208     return ret;
209 }
210
211 /*
212  * Create an SSH-2 key list in a malloc'ed buffer; return its
213  * length.
214  */
215 void *pageant_make_keylist2(int *length)
216 {
217     struct ssh2_userkey *key;
218     int i, len, nkeys;
219     unsigned char *blob, *p, *ret;
220     int bloblen;
221
222     /*
223      * Count up the number and length of keys we hold.
224      */
225     len = 4;
226     nkeys = 0;
227     for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
228         nkeys++;
229         len += 4;              /* length field */
230         blob = key->alg->public_blob(key->data, &bloblen);
231         len += bloblen;
232         sfree(blob);
233         len += 4 + strlen(key->comment);
234     }
235
236     /* Allocate the buffer. */
237     p = ret = snewn(len, unsigned char);
238     if (length) *length = len;
239
240     /*
241      * Packet header is the obvious five bytes, plus four
242      * bytes for the key count.
243      */
244     PUT_32BIT(p, nkeys);
245     p += 4;
246     for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
247         blob = key->alg->public_blob(key->data, &bloblen);
248         PUT_32BIT(p, bloblen);
249         p += 4;
250         memcpy(p, blob, bloblen);
251         p += bloblen;
252         sfree(blob);
253         PUT_32BIT(p, strlen(key->comment));
254         memcpy(p + 4, key->comment, strlen(key->comment));
255         p += 4 + strlen(key->comment);
256     }
257
258     assert(p - ret == len);
259     return ret;
260 }
261
262 static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
263 #ifdef __GNUC__
264 __attribute__ ((format (printf, 3, 4)))
265 #endif
266     ;
267
268 static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
269 {
270     /*
271      * This is the wrapper that takes a variadic argument list and
272      * turns it into the va_list that the log function really expects.
273      * It's safe to call this with logfn==NULL, because we
274      * double-check that below; but if you're going to do lots of work
275      * before getting here (such as looping, or hashing things) then
276      * you should probably check logfn manually before doing that.
277      */
278     if (logfn) {
279         va_list ap;
280         va_start(ap, fmt);
281         logfn(logctx, fmt, ap);
282         va_end(ap);
283     }
284 }
285
286 void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
287                          void *logctx, pageant_logfn_t logfn)
288 {
289     const unsigned char *p = msg;
290     const unsigned char *msgend;
291     unsigned char *ret = snewn(AGENT_MAX_MSGLEN, unsigned char);
292     int type;
293     const char *fail_reason;
294
295     msgend = p + msglen;
296
297     /*
298      * Get the message type.
299      */
300     if (msgend < p+1) {
301         fail_reason = "message contained no type code";
302         goto failure;
303     }
304     type = *p++;
305
306     switch (type) {
307       case SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
308         /*
309          * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
310          */
311         {
312             int len;
313             void *keylist;
314
315             plog(logctx, logfn, "request: SSH1_AGENTC_REQUEST_RSA_IDENTITIES");
316
317             ret[4] = SSH1_AGENT_RSA_IDENTITIES_ANSWER;
318             keylist = pageant_make_keylist1(&len);
319             if (len + 5 > AGENT_MAX_MSGLEN) {
320                 sfree(keylist);
321                 fail_reason = "output would exceed max msglen";
322                 goto failure;
323             }
324             PUT_32BIT(ret, len + 1);
325             memcpy(ret + 5, keylist, len);
326
327             plog(logctx, logfn, "reply: SSH1_AGENT_RSA_IDENTITIES_ANSWER");
328             if (logfn) {               /* skip this loop if not logging */
329                 int i;
330                 struct RSAKey *rkey;
331                 for (i = 0; NULL != (rkey = pageant_nth_ssh1_key(i)); i++) {
332                     char fingerprint[128];
333                     rsa_fingerprint(fingerprint, sizeof(fingerprint), rkey);
334                     plog(logctx, logfn, "returned key: %s", fingerprint);
335                 }
336             }
337             sfree(keylist);
338         }
339         break;
340       case SSH2_AGENTC_REQUEST_IDENTITIES:
341         /*
342          * Reply with SSH2_AGENT_IDENTITIES_ANSWER.
343          */
344         {
345             int len;
346             void *keylist;
347
348             plog(logctx, logfn, "request: SSH2_AGENTC_REQUEST_IDENTITIES");
349
350             ret[4] = SSH2_AGENT_IDENTITIES_ANSWER;
351             keylist = pageant_make_keylist2(&len);
352             if (len + 5 > AGENT_MAX_MSGLEN) {
353                 sfree(keylist);
354                 fail_reason = "output would exceed max msglen";
355                 goto failure;
356             }
357             PUT_32BIT(ret, len + 1);
358             memcpy(ret + 5, keylist, len);
359
360             plog(logctx, logfn, "reply: SSH2_AGENT_IDENTITIES_ANSWER");
361             if (logfn) {               /* skip this loop if not logging */
362                 int i;
363                 struct ssh2_userkey *skey;
364                 for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) {
365                     char *fingerprint = ssh2_fingerprint(skey->alg,
366                                                          skey->data);
367                     plog(logctx, logfn, "returned key: %s %s",
368                          fingerprint, skey->comment);
369                     sfree(fingerprint);
370                 }
371             }
372
373             sfree(keylist);
374         }
375         break;
376       case SSH1_AGENTC_RSA_CHALLENGE:
377         /*
378          * Reply with either SSH1_AGENT_RSA_RESPONSE or
379          * SSH_AGENT_FAILURE, depending on whether we have that key
380          * or not.
381          */
382         {
383             struct RSAKey reqkey, *key;
384             Bignum challenge, response;
385             unsigned char response_source[48], response_md5[16];
386             struct MD5Context md5c;
387             int i, len;
388
389             plog(logctx, logfn, "request: SSH1_AGENTC_RSA_CHALLENGE");
390
391             p += 4;
392             i = ssh1_read_bignum(p, msgend - p, &reqkey.exponent);
393             if (i < 0) {
394                 fail_reason = "request truncated before key exponent";
395                 goto failure;
396             }
397             p += i;
398             i = ssh1_read_bignum(p, msgend - p, &reqkey.modulus);
399             if (i < 0) {
400                 freebn(reqkey.exponent);
401                 fail_reason = "request truncated before key modulus";
402                 goto failure;
403             }
404             p += i;
405             i = ssh1_read_bignum(p, msgend - p, &challenge);
406             if (i < 0) {
407                 freebn(reqkey.exponent);
408                 freebn(reqkey.modulus);
409                 freebn(challenge);
410                 fail_reason = "request truncated before challenge";
411                 goto failure;
412             }
413             p += i;
414             if (msgend < p+16) {
415                 freebn(reqkey.exponent);
416                 freebn(reqkey.modulus);
417                 freebn(challenge);
418                 fail_reason = "request truncated before session id";
419                 goto failure;
420             }
421             memcpy(response_source + 32, p, 16);
422             p += 16;
423             if (msgend < p+4) {
424                 freebn(reqkey.exponent);
425                 freebn(reqkey.modulus);
426                 freebn(challenge);
427                 fail_reason = "request truncated before response type";
428                 goto failure;
429             }
430             if (GET_32BIT(p) != 1) {
431                 freebn(reqkey.exponent);
432                 freebn(reqkey.modulus);
433                 freebn(challenge);
434                 fail_reason = "response type other than 1 not supported";
435                 goto failure;
436             }
437             if (logfn) {
438                 char fingerprint[128];
439                 reqkey.comment = NULL;
440                 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
441                 plog(logctx, logfn, "requested key: %s", fingerprint);
442             }
443             if ((key = find234(rsakeys, &reqkey, NULL)) == NULL) {
444                 freebn(reqkey.exponent);
445                 freebn(reqkey.modulus);
446                 freebn(challenge);
447                 fail_reason = "key not found";
448                 goto failure;
449             }
450             response = rsadecrypt(challenge, key);
451             for (i = 0; i < 32; i++)
452                 response_source[i] = bignum_byte(response, 31 - i);
453
454             MD5Init(&md5c);
455             MD5Update(&md5c, response_source, 48);
456             MD5Final(response_md5, &md5c);
457             smemclr(response_source, 48);       /* burn the evidence */
458             freebn(response);          /* and that evidence */
459             freebn(challenge);         /* yes, and that evidence */
460             freebn(reqkey.exponent);   /* and free some memory ... */
461             freebn(reqkey.modulus);    /* ... while we're at it. */
462
463             /*
464              * Packet is the obvious five byte header, plus sixteen
465              * bytes of MD5.
466              */
467             len = 5 + 16;
468             PUT_32BIT(ret, len - 4);
469             ret[4] = SSH1_AGENT_RSA_RESPONSE;
470             memcpy(ret + 5, response_md5, 16);
471
472             plog(logctx, logfn, "reply: SSH1_AGENT_RSA_RESPONSE");
473         }
474         break;
475       case SSH2_AGENTC_SIGN_REQUEST:
476         /*
477          * Reply with either SSH2_AGENT_SIGN_RESPONSE or
478          * SSH_AGENT_FAILURE, depending on whether we have that key
479          * or not.
480          */
481         {
482             struct ssh2_userkey *key;
483             struct blob b;
484             const unsigned char *data;
485             unsigned char *signature;
486             int datalen, siglen, len;
487
488             plog(logctx, logfn, "request: SSH2_AGENTC_SIGN_REQUEST");
489
490             if (msgend < p+4) {
491                 fail_reason = "request truncated before public key";
492                 goto failure;
493             }
494             b.len = toint(GET_32BIT(p));
495             if (b.len < 0 || b.len > msgend - (p+4)) {
496                 fail_reason = "request truncated before public key";
497                 goto failure;
498             }
499             p += 4;
500             b.blob = p;
501             p += b.len;
502             if (msgend < p+4) {
503                 fail_reason = "request truncated before string to sign";
504                 goto failure;
505             }
506             datalen = toint(GET_32BIT(p));
507             p += 4;
508             if (datalen < 0 || datalen > msgend - p) {
509                 fail_reason = "request truncated before string to sign";
510                 goto failure;
511             }
512             data = p;
513             if (logfn) {
514                 char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len);
515                 plog(logctx, logfn, "requested key: %s", fingerprint);
516                 sfree(fingerprint);
517             }
518             key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
519             if (!key) {
520                 fail_reason = "key not found";
521                 goto failure;
522             }
523             signature = key->alg->sign(key->data, (const char *)data,
524                                        datalen, &siglen);
525             len = 5 + 4 + siglen;
526             PUT_32BIT(ret, len - 4);
527             ret[4] = SSH2_AGENT_SIGN_RESPONSE;
528             PUT_32BIT(ret + 5, siglen);
529             memcpy(ret + 5 + 4, signature, siglen);
530             sfree(signature);
531
532             plog(logctx, logfn, "reply: SSH2_AGENT_SIGN_RESPONSE");
533         }
534         break;
535       case SSH1_AGENTC_ADD_RSA_IDENTITY:
536         /*
537          * Add to the list and return SSH_AGENT_SUCCESS, or
538          * SSH_AGENT_FAILURE if the key was malformed.
539          */
540         {
541             struct RSAKey *key;
542             char *comment;
543             int n, commentlen;
544
545             plog(logctx, logfn, "request: SSH1_AGENTC_ADD_RSA_IDENTITY");
546
547             key = snew(struct RSAKey);
548             memset(key, 0, sizeof(struct RSAKey));
549
550             n = makekey(p, msgend - p, key, NULL, 1);
551             if (n < 0) {
552                 freersakey(key);
553                 sfree(key);
554                 fail_reason = "request truncated before public key";
555                 goto failure;
556             }
557             p += n;
558
559             n = makeprivate(p, msgend - p, key);
560             if (n < 0) {
561                 freersakey(key);
562                 sfree(key);
563                 fail_reason = "request truncated before private key";
564                 goto failure;
565             }
566             p += n;
567
568             /* SSH-1 names p and q the other way round, i.e. we have
569              * the inverse of p mod q and not of q mod p. We swap the
570              * names, because our internal RSA wants iqmp. */
571
572             n = ssh1_read_bignum(p, msgend - p, &key->iqmp);  /* p^-1 mod q */
573             if (n < 0) {
574                 freersakey(key);
575                 sfree(key);
576                 fail_reason = "request truncated before iqmp";
577                 goto failure;
578             }
579             p += n;
580
581             n = ssh1_read_bignum(p, msgend - p, &key->q);  /* p */
582             if (n < 0) {
583                 freersakey(key);
584                 sfree(key);
585                 fail_reason = "request truncated before p";
586                 goto failure;
587             }
588             p += n;
589
590             n = ssh1_read_bignum(p, msgend - p, &key->p);  /* q */
591             if (n < 0) {
592                 freersakey(key);
593                 sfree(key);
594                 fail_reason = "request truncated before q";
595                 goto failure;
596             }
597             p += n;
598
599             if (msgend < p+4) {
600                 freersakey(key);
601                 sfree(key);
602                 fail_reason = "request truncated before key comment";
603                 goto failure;
604             }
605             commentlen = toint(GET_32BIT(p));
606
607             if (commentlen < 0 || commentlen > msgend - p) {
608                 freersakey(key);
609                 sfree(key);
610                 fail_reason = "request truncated before key comment";
611                 goto failure;
612             }
613
614             comment = snewn(commentlen+1, char);
615             if (comment) {
616                 memcpy(comment, p + 4, commentlen);
617                 comment[commentlen] = '\0';
618                 key->comment = comment;
619             }
620
621             if (logfn) {
622                 char fingerprint[128];
623                 rsa_fingerprint(fingerprint, sizeof(fingerprint), key);
624                 plog(logctx, logfn, "submitted key: %s", fingerprint);
625             }
626
627             if (add234(rsakeys, key) == key) {
628                 keylist_update();
629                 PUT_32BIT(ret, 1);
630                 ret[4] = SSH_AGENT_SUCCESS;
631
632                 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
633             } else {
634                 freersakey(key);
635                 sfree(key);
636
637                 fail_reason = "key already present";
638                 goto failure;
639             }
640         }
641         break;
642       case SSH2_AGENTC_ADD_IDENTITY:
643         /*
644          * Add to the list and return SSH_AGENT_SUCCESS, or
645          * SSH_AGENT_FAILURE if the key was malformed.
646          */
647         {
648             struct ssh2_userkey *key;
649             char *comment;
650             const char *alg;
651             int alglen, commlen;
652             int bloblen;
653
654             plog(logctx, logfn, "request: SSH2_AGENTC_ADD_IDENTITY");
655
656             if (msgend < p+4) {
657                 fail_reason = "request truncated before key algorithm";
658                 goto failure;
659             }
660             alglen = toint(GET_32BIT(p));
661             p += 4;
662             if (alglen < 0 || alglen > msgend - p) {
663                 fail_reason = "request truncated before key algorithm";
664                 goto failure;
665             }
666             alg = (const char *)p;
667             p += alglen;
668
669             key = snew(struct ssh2_userkey);
670             key->alg = find_pubkey_alg_len(alglen, alg);
671             if (!key->alg) {
672                 sfree(key);
673                 fail_reason = "algorithm unknown";
674                 goto failure;
675             }
676
677             bloblen = msgend - p;
678             key->data = key->alg->openssh_createkey(key->alg, &p, &bloblen);
679             if (!key->data) {
680                 sfree(key);
681                 fail_reason = "key setup failed";
682                 goto failure;
683             }
684
685             /*
686              * p has been advanced by openssh_createkey, but
687              * certainly not _beyond_ the end of the buffer.
688              */
689             assert(p <= msgend);
690
691             if (msgend < p+4) {
692                 key->alg->freekey(key->data);
693                 sfree(key);
694                 fail_reason = "request truncated before key comment";
695                 goto failure;
696             }
697             commlen = toint(GET_32BIT(p));
698             p += 4;
699
700             if (commlen < 0 || commlen > msgend - p) {
701                 key->alg->freekey(key->data);
702                 sfree(key);
703                 fail_reason = "request truncated before key comment";
704                 goto failure;
705             }
706             comment = snewn(commlen + 1, char);
707             if (comment) {
708                 memcpy(comment, p, commlen);
709                 comment[commlen] = '\0';
710             }
711             key->comment = comment;
712
713             if (logfn) {
714                 char *fingerprint = ssh2_fingerprint(key->alg, key->data);
715                 plog(logctx, logfn, "submitted key: %s %s",
716                      fingerprint, key->comment);
717                 sfree(fingerprint);
718             }
719
720             if (add234(ssh2keys, key) == key) {
721                 keylist_update();
722                 PUT_32BIT(ret, 1);
723                 ret[4] = SSH_AGENT_SUCCESS;
724
725                 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
726             } else {
727                 key->alg->freekey(key->data);
728                 sfree(key->comment);
729                 sfree(key);
730
731                 fail_reason = "key already present";
732                 goto failure;
733             }
734         }
735         break;
736       case SSH1_AGENTC_REMOVE_RSA_IDENTITY:
737         /*
738          * Remove from the list and return SSH_AGENT_SUCCESS, or
739          * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
740          * start with.
741          */
742         {
743             struct RSAKey reqkey, *key;
744             int n;
745
746             plog(logctx, logfn, "request: SSH1_AGENTC_REMOVE_RSA_IDENTITY");
747
748             n = makekey(p, msgend - p, &reqkey, NULL, 0);
749             if (n < 0) {
750                 fail_reason = "request truncated before public key";
751                 goto failure;
752             }
753
754             if (logfn) {
755                 char fingerprint[128];
756                 reqkey.comment = NULL;
757                 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
758                 plog(logctx, logfn, "unwanted key: %s", fingerprint);
759             }
760
761             key = find234(rsakeys, &reqkey, NULL);
762             freebn(reqkey.exponent);
763             freebn(reqkey.modulus);
764             PUT_32BIT(ret, 1);
765             if (key) {
766                 plog(logctx, logfn, "found with comment: %s", key->comment);
767
768                 del234(rsakeys, key);
769                 keylist_update();
770                 freersakey(key);
771                 sfree(key);
772                 ret[4] = SSH_AGENT_SUCCESS;
773
774                 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
775             } else {
776                 fail_reason = "key not found";
777                 goto failure;
778             }
779         }
780         break;
781       case SSH2_AGENTC_REMOVE_IDENTITY:
782         /*
783          * Remove from the list and return SSH_AGENT_SUCCESS, or
784          * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
785          * start with.
786          */
787         {
788             struct ssh2_userkey *key;
789             struct blob b;
790
791             plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_IDENTITY");
792
793             if (msgend < p+4) {
794                 fail_reason = "request truncated before public key";
795                 goto failure;
796             }
797             b.len = toint(GET_32BIT(p));
798             p += 4;
799
800             if (b.len < 0 || b.len > msgend - p) {
801                 fail_reason = "request truncated before public key";
802                 goto failure;
803             }
804             b.blob = p;
805             p += b.len;
806
807             if (logfn) {
808                 char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len);
809                 plog(logctx, logfn, "unwanted key: %s", fingerprint);
810                 sfree(fingerprint);
811             }
812
813             key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
814             if (!key) {
815                 fail_reason = "key not found";
816                 goto failure;
817             }
818
819             plog(logctx, logfn, "found with comment: %s", key->comment);
820
821             del234(ssh2keys, key);
822             keylist_update();
823             key->alg->freekey(key->data);
824             sfree(key);
825             PUT_32BIT(ret, 1);
826             ret[4] = SSH_AGENT_SUCCESS;
827
828             plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
829         }
830         break;
831       case SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
832         /*
833          * Remove all SSH-1 keys. Always returns success.
834          */
835         {
836             struct RSAKey *rkey;
837
838             plog(logctx, logfn, "request:"
839                 " SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES");
840
841             while ((rkey = index234(rsakeys, 0)) != NULL) {
842                 del234(rsakeys, rkey);
843                 freersakey(rkey);
844                 sfree(rkey);
845             }
846             keylist_update();
847
848             PUT_32BIT(ret, 1);
849             ret[4] = SSH_AGENT_SUCCESS;
850
851             plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
852         }
853         break;
854       case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
855         /*
856          * Remove all SSH-2 keys. Always returns success.
857          */
858         {
859             struct ssh2_userkey *skey;
860
861             plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_ALL_IDENTITIES");
862
863             while ((skey = index234(ssh2keys, 0)) != NULL) {
864                 del234(ssh2keys, skey);
865                 skey->alg->freekey(skey->data);
866                 sfree(skey);
867             }
868             keylist_update();
869
870             PUT_32BIT(ret, 1);
871             ret[4] = SSH_AGENT_SUCCESS;
872
873             plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
874         }
875         break;
876       default:
877         plog(logctx, logfn, "request: unknown message type %d", type);
878
879         fail_reason = "unrecognised message";
880         /* fall through */
881       failure:
882         /*
883          * Unrecognised message. Return SSH_AGENT_FAILURE.
884          */
885         PUT_32BIT(ret, 1);
886         ret[4] = SSH_AGENT_FAILURE;
887         plog(logctx, logfn, "reply: SSH_AGENT_FAILURE (%s)", fail_reason);
888         break;
889     }
890
891     *outlen = 4 + GET_32BIT(ret);
892     return ret;
893 }
894
895 void *pageant_failure_msg(int *outlen)
896 {
897     unsigned char *ret = snewn(5, unsigned char);
898     PUT_32BIT(ret, 1);
899     ret[4] = SSH_AGENT_FAILURE;
900     *outlen = 5;
901     return ret;
902 }
903
904 void pageant_init(void)
905 {
906     pageant_local = TRUE;
907     rsakeys = newtree234(cmpkeys_rsa);
908     ssh2keys = newtree234(cmpkeys_ssh2);
909 }
910
911 struct RSAKey *pageant_nth_ssh1_key(int i)
912 {
913     return index234(rsakeys, i);
914 }
915
916 struct ssh2_userkey *pageant_nth_ssh2_key(int i)
917 {
918     return index234(ssh2keys, i);
919 }
920
921 int pageant_count_ssh1_keys(void)
922 {
923     return count234(rsakeys);
924 }
925
926 int pageant_count_ssh2_keys(void)
927 {
928     return count234(ssh2keys);
929 }
930
931 int pageant_add_ssh1_key(struct RSAKey *rkey)
932 {
933     return add234(rsakeys, rkey) == rkey;
934 }
935
936 int pageant_add_ssh2_key(struct ssh2_userkey *skey)
937 {
938     return add234(ssh2keys, skey) == skey;
939 }
940
941 int pageant_delete_ssh1_key(struct RSAKey *rkey)
942 {
943     struct RSAKey *deleted = del234(rsakeys, rkey);
944     if (!deleted)
945         return FALSE;
946     assert(deleted == rkey);
947     return TRUE;
948 }
949
950 int pageant_delete_ssh2_key(struct ssh2_userkey *skey)
951 {
952     struct ssh2_userkey *deleted = del234(ssh2keys, skey);
953     if (!deleted)
954         return FALSE;
955     assert(deleted == skey);
956     return TRUE;
957 }
958
959 /* ----------------------------------------------------------------------
960  * The agent plug.
961  */
962
963 /*
964  * Coroutine macros similar to, but simplified from, those in ssh.c.
965  */
966 #define crBegin(v)      { int *crLine = &v; switch(v) { case 0:;
967 #define crFinish(z)     } *crLine = 0; return (z); }
968 #define crGetChar(c) do                                         \
969     {                                                           \
970         while (len == 0) {                                      \
971             *crLine =__LINE__; return 1; case __LINE__:;        \
972         }                                                       \
973         len--;                                                  \
974         (c) = (unsigned char)*data++;                           \
975     } while (0)
976
977 struct pageant_conn_state {
978     const struct plug_function_table *fn;
979     /* the above variable absolutely *must* be the first in this structure */
980
981     Socket connsock;
982     void *logctx;
983     pageant_logfn_t logfn;
984     unsigned char lenbuf[4], pktbuf[AGENT_MAX_MSGLEN];
985     unsigned len, got;
986     int real_packet;
987     int crLine;            /* for coroutine in pageant_conn_receive */
988 };
989
990 static int pageant_conn_closing(Plug plug, const char *error_msg,
991                                 int error_code, int calling_back)
992 {
993     struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
994     if (error_msg)
995         plog(pc->logctx, pc->logfn, "%p: error: %s", pc, error_msg);
996     else
997         plog(pc->logctx, pc->logfn, "%p: connection closed", pc);
998     sk_close(pc->connsock);
999     sfree(pc);
1000     return 1;
1001 }
1002
1003 static void pageant_conn_sent(Plug plug, int bufsize)
1004 {
1005     /* struct pageant_conn_state *pc = (struct pageant_conn_state *)plug; */
1006
1007     /*
1008      * We do nothing here, because we expect that there won't be a
1009      * need to throttle and unthrottle the connection to an agent -
1010      * clients will typically not send many requests, and will wait
1011      * until they receive each reply before sending a new request.
1012      */
1013 }
1014
1015 static void pageant_conn_log(void *logctx, const char *fmt, va_list ap)
1016 {
1017     /* Wrapper on pc->logfn that prefixes the connection identifier */
1018     struct pageant_conn_state *pc = (struct pageant_conn_state *)logctx;
1019     char *formatted = dupvprintf(fmt, ap);
1020     plog(pc->logctx, pc->logfn, "%p: %s", pc, formatted);
1021     sfree(formatted);
1022 }
1023
1024 static int pageant_conn_receive(Plug plug, int urgent, char *data, int len)
1025 {
1026     struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
1027     char c;
1028
1029     crBegin(pc->crLine);
1030
1031     while (len > 0) {
1032         pc->got = 0;
1033         while (pc->got < 4) {
1034             crGetChar(c);
1035             pc->lenbuf[pc->got++] = c;
1036         }
1037
1038         pc->len = GET_32BIT(pc->lenbuf);
1039         pc->got = 0;
1040         pc->real_packet = (pc->len < AGENT_MAX_MSGLEN-4);
1041
1042         while (pc->got < pc->len) {
1043             crGetChar(c);
1044             if (pc->real_packet)
1045                 pc->pktbuf[pc->got] = c;
1046             pc->got++;
1047         }
1048
1049         {
1050             void *reply;
1051             int replylen;
1052
1053             if (pc->real_packet) {
1054                 reply = pageant_handle_msg(pc->pktbuf, pc->len, &replylen, pc,
1055                                            pc->logfn?pageant_conn_log:NULL);
1056             } else {
1057                 plog(pc->logctx, pc->logfn, "%p: overlong message (%u)",
1058                      pc, pc->len);
1059                 plog(pc->logctx, pc->logfn, "%p: reply: SSH_AGENT_FAILURE "
1060                      "(message too long)", pc);
1061                 reply = pageant_failure_msg(&replylen);
1062             }
1063             sk_write(pc->connsock, reply, replylen);
1064             smemclr(reply, replylen);
1065         }
1066     }
1067
1068     crFinish(1);
1069 }
1070
1071 struct pageant_listen_state {
1072     const struct plug_function_table *fn;
1073     /* the above variable absolutely *must* be the first in this structure */
1074
1075     Socket listensock;
1076     void *logctx;
1077     pageant_logfn_t logfn;
1078 };
1079
1080 static int pageant_listen_closing(Plug plug, const char *error_msg,
1081                                   int error_code, int calling_back)
1082 {
1083     struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1084     if (error_msg)
1085         plog(pl->logctx, pl->logfn, "listening socket: error: %s", error_msg);
1086     sk_close(pl->listensock);
1087     pl->listensock = NULL;
1088     return 1;
1089 }
1090
1091 static int pageant_listen_accepting(Plug plug,
1092                                     accept_fn_t constructor, accept_ctx_t ctx)
1093 {
1094     static const struct plug_function_table connection_fn_table = {
1095         NULL, /* no log function, because that's for outgoing connections */
1096         pageant_conn_closing,
1097         pageant_conn_receive,
1098         pageant_conn_sent,
1099         NULL /* no accepting function, because we've already done it */
1100     };
1101     struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1102     struct pageant_conn_state *pc;
1103     const char *err;
1104     char *peerinfo;
1105
1106     pc = snew(struct pageant_conn_state);
1107     pc->fn = &connection_fn_table;
1108     pc->logfn = pl->logfn;
1109     pc->logctx = pl->logctx;
1110     pc->crLine = 0;
1111
1112     pc->connsock = constructor(ctx, (Plug) pc);
1113     if ((err = sk_socket_error(pc->connsock)) != NULL) {
1114         sk_close(pc->connsock);
1115         sfree(pc);
1116         return TRUE;
1117     }
1118
1119     sk_set_frozen(pc->connsock, 0);
1120
1121     peerinfo = sk_peer_info(pc->connsock);
1122     if (peerinfo) {
1123         plog(pl->logctx, pl->logfn, "%p: new connection from %s",
1124              pc, peerinfo);
1125     } else {
1126         plog(pl->logctx, pl->logfn, "%p: new connection", pc);
1127     }
1128
1129     return 0;
1130 }
1131
1132 struct pageant_listen_state *pageant_listener_new(void)
1133 {
1134     static const struct plug_function_table listener_fn_table = {
1135         NULL, /* no log function, because that's for outgoing connections */
1136         pageant_listen_closing,
1137         NULL, /* no receive function on a listening socket */
1138         NULL, /* no sent function on a listening socket */
1139         pageant_listen_accepting
1140     };
1141
1142     struct pageant_listen_state *pl = snew(struct pageant_listen_state);
1143     pl->fn = &listener_fn_table;
1144     pl->logctx = NULL;
1145     pl->logfn = NULL;
1146     pl->listensock = NULL;
1147     return pl;
1148 }
1149
1150 void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket sock)
1151 {
1152     pl->listensock = sock;
1153 }
1154
1155 void pageant_listener_set_logfn(struct pageant_listen_state *pl,
1156                                 void *logctx, pageant_logfn_t logfn)
1157 {
1158     pl->logctx = logctx;
1159     pl->logfn = logfn;
1160 }
1161
1162 void pageant_listener_free(struct pageant_listen_state *pl)
1163 {
1164     if (pl->listensock)
1165         sk_close(pl->listensock);
1166     sfree(pl);
1167 }
1168
1169 /* ----------------------------------------------------------------------
1170  * Code to perform agent operations either as a client, or within the
1171  * same process as the running agent.
1172  */
1173
1174 static tree234 *passphrases = NULL;
1175
1176 /*
1177  * After processing a list of filenames, we want to forget the
1178  * passphrases.
1179  */
1180 void pageant_forget_passphrases(void)
1181 {
1182     if (!passphrases)                  /* in case we never set it up at all */
1183         return;
1184
1185     while (count234(passphrases) > 0) {
1186         char *pp = index234(passphrases, 0);
1187         smemclr(pp, strlen(pp));
1188         delpos234(passphrases, 0);
1189         free(pp);
1190     }
1191 }
1192
1193 void *pageant_get_keylist1(int *length)
1194 {
1195     void *ret;
1196
1197     if (!pageant_local) {
1198         unsigned char request[5], *response;
1199         void *vresponse;
1200         int resplen;
1201
1202         request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
1203         PUT_32BIT(request, 1);
1204
1205         agent_query_synchronous(request, 5, &vresponse, &resplen);
1206         response = vresponse;
1207         if (resplen < 5 || response[4] != SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
1208             sfree(response);
1209             return NULL;
1210         }
1211
1212         ret = snewn(resplen-5, unsigned char);
1213         memcpy(ret, response+5, resplen-5);
1214         sfree(response);
1215
1216         if (length)
1217             *length = resplen-5;
1218     } else {
1219         ret = pageant_make_keylist1(length);
1220     }
1221     return ret;
1222 }
1223
1224 void *pageant_get_keylist2(int *length)
1225 {
1226     void *ret;
1227
1228     if (!pageant_local) {
1229         unsigned char request[5], *response;
1230         void *vresponse;
1231         int resplen;
1232
1233         request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;
1234         PUT_32BIT(request, 1);
1235
1236         agent_query_synchronous(request, 5, &vresponse, &resplen);
1237         response = vresponse;
1238         if (resplen < 5 || response[4] != SSH2_AGENT_IDENTITIES_ANSWER) {
1239             sfree(response);
1240             return NULL;
1241         }
1242
1243         ret = snewn(resplen-5, unsigned char);
1244         memcpy(ret, response+5, resplen-5);
1245         sfree(response);
1246
1247         if (length)
1248             *length = resplen-5;
1249     } else {
1250         ret = pageant_make_keylist2(length);
1251     }
1252     return ret;
1253 }
1254
1255 int pageant_add_keyfile(Filename *filename, const char *passphrase,
1256                         char **retstr)
1257 {
1258     struct RSAKey *rkey = NULL;
1259     struct ssh2_userkey *skey = NULL;
1260     int needs_pass;
1261     int ret;
1262     int attempts;
1263     char *comment;
1264     const char *this_passphrase;
1265     const char *error = NULL;
1266     int type;
1267
1268     if (!passphrases) {
1269         passphrases = newtree234(NULL);
1270     }
1271
1272     *retstr = NULL;
1273
1274     type = key_type(filename);
1275     if (type != SSH_KEYTYPE_SSH1 && type != SSH_KEYTYPE_SSH2) {
1276         *retstr = dupprintf("Couldn't load this key (%s)",
1277                             key_type_to_str(type));
1278         return PAGEANT_ACTION_FAILURE;
1279     }
1280
1281     /*
1282      * See if the key is already loaded (in the primary Pageant,
1283      * which may or may not be us).
1284      */
1285     {
1286         void *blob;
1287         unsigned char *keylist, *p;
1288         int i, nkeys, bloblen, keylistlen;
1289
1290         if (type == SSH_KEYTYPE_SSH1) {
1291             if (!rsakey_pubblob(filename, &blob, &bloblen, NULL, &error)) {
1292                 *retstr = dupprintf("Couldn't load private key (%s)", error);
1293                 return PAGEANT_ACTION_FAILURE;
1294             }
1295             keylist = pageant_get_keylist1(&keylistlen);
1296         } else {
1297             unsigned char *blob2;
1298             blob = ssh2_userkey_loadpub(filename, NULL, &bloblen,
1299                                         NULL, &error);
1300             if (!blob) {
1301                 *retstr = dupprintf("Couldn't load private key (%s)", error);
1302                 return PAGEANT_ACTION_FAILURE;
1303             }
1304             /* For our purposes we want the blob prefixed with its length */
1305             blob2 = snewn(bloblen+4, unsigned char);
1306             PUT_32BIT(blob2, bloblen);
1307             memcpy(blob2 + 4, blob, bloblen);
1308             sfree(blob);
1309             blob = blob2;
1310
1311             keylist = pageant_get_keylist2(&keylistlen);
1312         }
1313         if (keylist) {
1314             if (keylistlen < 4) {
1315                 *retstr = dupstr("Received broken key list from agent");
1316                 sfree(keylist);
1317                 sfree(blob);
1318                 return PAGEANT_ACTION_FAILURE;
1319             }
1320             nkeys = toint(GET_32BIT(keylist));
1321             if (nkeys < 0) {
1322                 *retstr = dupstr("Received broken key list from agent");
1323                 sfree(keylist);
1324                 sfree(blob);
1325                 return PAGEANT_ACTION_FAILURE;
1326             }
1327             p = keylist + 4;
1328             keylistlen -= 4;
1329
1330             for (i = 0; i < nkeys; i++) {
1331                 if (!memcmp(blob, p, bloblen)) {
1332                     /* Key is already present; we can now leave. */
1333                     sfree(keylist);
1334                     sfree(blob);
1335                     return PAGEANT_ACTION_OK;
1336                 }
1337                 /* Now skip over public blob */
1338                 if (type == SSH_KEYTYPE_SSH1) {
1339                     int n = rsa_public_blob_len(p, keylistlen);
1340                     if (n < 0) {
1341                         *retstr = dupstr("Received broken key list from agent");
1342                         sfree(keylist);
1343                         sfree(blob);
1344                         return PAGEANT_ACTION_FAILURE;
1345                     }
1346                     p += n;
1347                     keylistlen -= n;
1348                 } else {
1349                     int n;
1350                     if (keylistlen < 4) {
1351                         *retstr = dupstr("Received broken key list from agent");
1352                         sfree(keylist);
1353                         sfree(blob);
1354                         return PAGEANT_ACTION_FAILURE;
1355                     }
1356                     n = GET_32BIT(p);
1357                     p += 4;
1358                     keylistlen -= 4;
1359
1360                     if (n < 0 || n > keylistlen) {
1361                         *retstr = dupstr("Received broken key list from agent");
1362                         sfree(keylist);
1363                         sfree(blob);
1364                         return PAGEANT_ACTION_FAILURE;
1365                     }
1366                     p += n;
1367                     keylistlen -= n;
1368                 }
1369                 /* Now skip over comment field */
1370                 {
1371                     int n;
1372                     if (keylistlen < 4) {
1373                         *retstr = dupstr("Received broken key list from agent");
1374                         sfree(keylist);
1375                         sfree(blob);
1376                         return PAGEANT_ACTION_FAILURE;
1377                     }
1378                     n = GET_32BIT(p);
1379                     p += 4;
1380                     keylistlen -= 4;
1381
1382                     if (n < 0 || n > keylistlen) {
1383                         *retstr = dupstr("Received broken key list from agent");
1384                         sfree(keylist);
1385                         sfree(blob);
1386                         return PAGEANT_ACTION_FAILURE;
1387                     }
1388                     p += n;
1389                     keylistlen -= n;
1390                 }
1391             }
1392
1393             sfree(keylist);
1394         }
1395
1396         sfree(blob);
1397     }
1398
1399     error = NULL;
1400     if (type == SSH_KEYTYPE_SSH1)
1401         needs_pass = rsakey_encrypted(filename, &comment);
1402     else
1403         needs_pass = ssh2_userkey_encrypted(filename, &comment);
1404     attempts = 0;
1405     if (type == SSH_KEYTYPE_SSH1)
1406         rkey = snew(struct RSAKey);
1407
1408     /*
1409      * Loop round repeatedly trying to load the key, until we either
1410      * succeed, fail for some serious reason, or run out of
1411      * passphrases to try.
1412      */
1413     while (1) {
1414         if (needs_pass) {
1415
1416             /*
1417              * If we've been given a passphrase on input, try using
1418              * it. Otherwise, try one from our tree234 of previously
1419              * useful passphrases.
1420              */
1421             if (passphrase) {
1422                 this_passphrase = (attempts == 0 ? passphrase : NULL);
1423             } else {
1424                 this_passphrase = (const char *)index234(passphrases, attempts);
1425             }
1426
1427             if (!this_passphrase) {
1428                 /*
1429                  * Run out of passphrases to try.
1430                  */
1431                 *retstr = comment;
1432                 sfree(rkey);
1433                 return PAGEANT_ACTION_NEED_PP;
1434             }
1435         } else
1436             this_passphrase = "";
1437
1438         if (type == SSH_KEYTYPE_SSH1)
1439             ret = loadrsakey(filename, rkey, this_passphrase, &error);
1440         else {
1441             skey = ssh2_load_userkey(filename, this_passphrase, &error);
1442             if (skey == SSH2_WRONG_PASSPHRASE)
1443                 ret = -1;
1444             else if (!skey)
1445                 ret = 0;
1446             else
1447                 ret = 1;
1448         }
1449
1450         if (ret == 0) {
1451             /*
1452              * Failed to load the key file, for some reason other than
1453              * a bad passphrase.
1454              */
1455             *retstr = dupstr(error);
1456             sfree(rkey);
1457             return PAGEANT_ACTION_FAILURE;
1458         } else if (ret == 1) {
1459             /*
1460              * Successfully loaded the key file.
1461              */
1462             break;
1463         } else {
1464             /*
1465              * Passphrase wasn't right; go round again.
1466              */
1467             attempts++;
1468         }
1469     }
1470
1471     /*
1472      * If we get here, we've succesfully loaded the key into
1473      * rkey/skey, but not yet added it to the agent.
1474      */
1475
1476     /*
1477      * If the key was successfully decrypted, save the passphrase for
1478      * use with other keys we try to load.
1479      */
1480     {
1481         char *pp_copy = dupstr(this_passphrase);
1482         if (addpos234(passphrases, pp_copy, 0) != pp_copy) {
1483             /* No need; it was already there. */
1484             smemclr(pp_copy, strlen(pp_copy));
1485             sfree(pp_copy);
1486         }
1487     }
1488
1489     if (comment)
1490         sfree(comment);
1491
1492     if (type == SSH_KEYTYPE_SSH1) {
1493         if (!pageant_local) {
1494             unsigned char *request, *response;
1495             void *vresponse;
1496             int reqlen, clen, resplen;
1497
1498             clen = strlen(rkey->comment);
1499
1500             reqlen = 4 + 1 +           /* length, message type */
1501                 4 +                    /* bit count */
1502                 ssh1_bignum_length(rkey->modulus) +
1503                 ssh1_bignum_length(rkey->exponent) +
1504                 ssh1_bignum_length(rkey->private_exponent) +
1505                 ssh1_bignum_length(rkey->iqmp) +
1506                 ssh1_bignum_length(rkey->p) +
1507                 ssh1_bignum_length(rkey->q) + 4 + clen  /* comment */
1508                 ;
1509
1510             request = snewn(reqlen, unsigned char);
1511
1512             request[4] = SSH1_AGENTC_ADD_RSA_IDENTITY;
1513             reqlen = 5;
1514             PUT_32BIT(request + reqlen, bignum_bitcount(rkey->modulus));
1515             reqlen += 4;
1516             reqlen += ssh1_write_bignum(request + reqlen, rkey->modulus);
1517             reqlen += ssh1_write_bignum(request + reqlen, rkey->exponent);
1518             reqlen +=
1519                 ssh1_write_bignum(request + reqlen,
1520                                   rkey->private_exponent);
1521             reqlen += ssh1_write_bignum(request + reqlen, rkey->iqmp);
1522             reqlen += ssh1_write_bignum(request + reqlen, rkey->p);
1523             reqlen += ssh1_write_bignum(request + reqlen, rkey->q);
1524             PUT_32BIT(request + reqlen, clen);
1525             memcpy(request + reqlen + 4, rkey->comment, clen);
1526             reqlen += 4 + clen;
1527             PUT_32BIT(request, reqlen - 4);
1528
1529             agent_query_synchronous(request, reqlen, &vresponse, &resplen);
1530             response = vresponse;
1531             if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
1532                 *retstr = dupstr("The already running Pageant "
1533                                  "refused to add the key.");
1534                 freersakey(rkey);
1535                 sfree(rkey);
1536                 sfree(request);
1537                 sfree(response);
1538                 return PAGEANT_ACTION_FAILURE;
1539             }
1540             freersakey(rkey);
1541             sfree(rkey);
1542             sfree(request);
1543             sfree(response);
1544         } else {
1545             if (!pageant_add_ssh1_key(rkey)) {
1546                 freersakey(rkey);
1547                 sfree(rkey);           /* already present, don't waste RAM */
1548             }
1549         }
1550     } else {
1551         if (!pageant_local) {
1552             unsigned char *request, *response;
1553             void *vresponse;
1554             int reqlen, alglen, clen, keybloblen, resplen;
1555             alglen = strlen(skey->alg->name);
1556             clen = strlen(skey->comment);
1557
1558             keybloblen = skey->alg->openssh_fmtkey(skey->data, NULL, 0);
1559
1560             reqlen = 4 + 1 +           /* length, message type */
1561                 4 + alglen +           /* algorithm name */
1562                 keybloblen +           /* key data */
1563                 4 + clen               /* comment */
1564                 ;
1565
1566             request = snewn(reqlen, unsigned char);
1567
1568             request[4] = SSH2_AGENTC_ADD_IDENTITY;
1569             reqlen = 5;
1570             PUT_32BIT(request + reqlen, alglen);
1571             reqlen += 4;
1572             memcpy(request + reqlen, skey->alg->name, alglen);
1573             reqlen += alglen;
1574             reqlen += skey->alg->openssh_fmtkey(skey->data,
1575                                                 request + reqlen,
1576                                                 keybloblen);
1577             PUT_32BIT(request + reqlen, clen);
1578             memcpy(request + reqlen + 4, skey->comment, clen);
1579             reqlen += clen + 4;
1580             PUT_32BIT(request, reqlen - 4);
1581
1582             agent_query_synchronous(request, reqlen, &vresponse, &resplen);
1583             response = vresponse;
1584             if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
1585                 *retstr = dupstr("The already running Pageant "
1586                                  "refused to add the key.");
1587                 sfree(request);
1588                 sfree(response);
1589                 return PAGEANT_ACTION_FAILURE;
1590             }
1591
1592             sfree(request);
1593             sfree(response);
1594         } else {
1595             if (!pageant_add_ssh2_key(skey)) {
1596                 skey->alg->freekey(skey->data);
1597                 sfree(skey);           /* already present, don't waste RAM */
1598             }
1599         }
1600     }
1601     return PAGEANT_ACTION_OK;
1602 }
1603
1604 int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
1605                       char **retstr)
1606 {
1607     unsigned char *keylist, *p;
1608     int i, nkeys, keylistlen;
1609     char *comment;
1610     struct pageant_pubkey cbkey;
1611
1612     keylist = pageant_get_keylist1(&keylistlen);
1613     if (keylistlen < 4) {
1614         *retstr = dupstr("Received broken SSH-1 key list from agent");
1615         sfree(keylist);
1616         return PAGEANT_ACTION_FAILURE;
1617     }
1618     nkeys = toint(GET_32BIT(keylist));
1619     if (nkeys < 0) {
1620         *retstr = dupstr("Received broken SSH-1 key list from agent");
1621         sfree(keylist);
1622         return PAGEANT_ACTION_FAILURE;
1623     }
1624     p = keylist + 4;
1625     keylistlen -= 4;
1626
1627     for (i = 0; i < nkeys; i++) {
1628         struct RSAKey rkey;
1629         char fingerprint[128];
1630         int n;
1631
1632         /* public blob and fingerprint */
1633         memset(&rkey, 0, sizeof(rkey));
1634         n = makekey(p, keylistlen, &rkey, NULL, 0);
1635         if (n < 0 || n > keylistlen) {
1636             freersakey(&rkey);
1637             *retstr = dupstr("Received broken SSH-1 key list from agent");
1638             sfree(keylist);
1639             return PAGEANT_ACTION_FAILURE;
1640         }
1641         p += n, keylistlen -= n;
1642         rsa_fingerprint(fingerprint, sizeof(fingerprint), &rkey);
1643
1644         /* comment */
1645         if (keylistlen < 4) {
1646             *retstr = dupstr("Received broken SSH-1 key list from agent");
1647             freersakey(&rkey);
1648             sfree(keylist);
1649             return PAGEANT_ACTION_FAILURE;
1650         }
1651         n = toint(GET_32BIT(p));
1652         p += 4, keylistlen -= 4;
1653         if (n < 0 || keylistlen < n) {
1654             *retstr = dupstr("Received broken SSH-1 key list from agent");
1655             freersakey(&rkey);
1656             sfree(keylist);
1657             return PAGEANT_ACTION_FAILURE;
1658         }
1659         comment = dupprintf("%.*s", (int)n, (const char *)p);
1660         p += n, keylistlen -= n;
1661
1662         cbkey.blob = rsa_public_blob(&rkey, &cbkey.bloblen);
1663         cbkey.comment = comment;
1664         cbkey.ssh_version = 1;
1665         callback(callback_ctx, fingerprint, comment, &cbkey);
1666         sfree(cbkey.blob);
1667         freersakey(&rkey);
1668         sfree(comment);
1669     }
1670
1671     sfree(keylist);
1672
1673     if (keylistlen != 0) {
1674         *retstr = dupstr("Received broken SSH-1 key list from agent");
1675         return PAGEANT_ACTION_FAILURE;
1676     }
1677
1678     keylist = pageant_get_keylist2(&keylistlen);
1679     if (keylistlen < 4) {
1680         *retstr = dupstr("Received broken SSH-2 key list from agent");
1681         sfree(keylist);
1682         return PAGEANT_ACTION_FAILURE;
1683     }
1684     nkeys = toint(GET_32BIT(keylist));
1685     if (nkeys < 0) {
1686         *retstr = dupstr("Received broken SSH-2 key list from agent");
1687         sfree(keylist);
1688         return PAGEANT_ACTION_FAILURE;
1689     }
1690     p = keylist + 4;
1691     keylistlen -= 4;
1692
1693     for (i = 0; i < nkeys; i++) {
1694         char *fingerprint;
1695         int n;
1696
1697         /* public blob */
1698         if (keylistlen < 4) {
1699             *retstr = dupstr("Received broken SSH-2 key list from agent");
1700             sfree(keylist);
1701             return PAGEANT_ACTION_FAILURE;
1702         }
1703         n = toint(GET_32BIT(p));
1704         p += 4, keylistlen -= 4;
1705         if (n < 0 || keylistlen < n) {
1706             *retstr = dupstr("Received broken SSH-2 key list from agent");
1707             sfree(keylist);
1708             return PAGEANT_ACTION_FAILURE;
1709         }
1710         fingerprint = ssh2_fingerprint_blob(p, n);
1711         cbkey.blob = p;
1712         cbkey.bloblen = n;
1713         p += n, keylistlen -= n;
1714
1715         /* comment */
1716         if (keylistlen < 4) {
1717             *retstr = dupstr("Received broken SSH-2 key list from agent");
1718             sfree(fingerprint);
1719             sfree(keylist);
1720             return PAGEANT_ACTION_FAILURE;
1721         }
1722         n = toint(GET_32BIT(p));
1723         p += 4, keylistlen -= 4;
1724         if (n < 0 || keylistlen < n) {
1725             *retstr = dupstr("Received broken SSH-2 key list from agent");
1726             sfree(fingerprint);
1727             sfree(keylist);
1728             return PAGEANT_ACTION_FAILURE;
1729         }
1730         comment = dupprintf("%.*s", (int)n, (const char *)p);
1731         p += n, keylistlen -= n;
1732
1733         cbkey.ssh_version = 2;
1734         cbkey.comment = comment;
1735         callback(callback_ctx, fingerprint, comment, &cbkey);
1736         sfree(fingerprint);
1737         sfree(comment);
1738     }
1739
1740     sfree(keylist);
1741
1742     if (keylistlen != 0) {
1743         *retstr = dupstr("Received broken SSH-1 key list from agent");
1744         return PAGEANT_ACTION_FAILURE;
1745     }
1746
1747     return PAGEANT_ACTION_OK;
1748 }
1749
1750 int pageant_delete_key(struct pageant_pubkey *key, char **retstr)
1751 {
1752     unsigned char *request, *response;
1753     int reqlen, resplen, ret;
1754     void *vresponse;
1755
1756     if (key->ssh_version == 1) {
1757         reqlen = 5 + key->bloblen;
1758         request = snewn(reqlen, unsigned char);
1759         PUT_32BIT(request, reqlen - 4);
1760         request[4] = SSH1_AGENTC_REMOVE_RSA_IDENTITY;
1761         memcpy(request + 5, key->blob, key->bloblen);
1762     } else {
1763         reqlen = 9 + key->bloblen;
1764         request = snewn(reqlen, unsigned char);
1765         PUT_32BIT(request, reqlen - 4);
1766         request[4] = SSH2_AGENTC_REMOVE_IDENTITY;
1767         PUT_32BIT(request + 5, key->bloblen);
1768         memcpy(request + 9, key->blob, key->bloblen);
1769     }
1770
1771     agent_query_synchronous(request, reqlen, &vresponse, &resplen);
1772     response = vresponse;
1773     if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
1774         *retstr = dupstr("Agent failed to delete key");
1775         ret = PAGEANT_ACTION_FAILURE;
1776     } else {
1777         *retstr = NULL;
1778         ret = PAGEANT_ACTION_OK;
1779     }
1780     sfree(request);
1781     sfree(response);
1782     return ret;
1783 }
1784
1785 int pageant_delete_all_keys(char **retstr)
1786 {
1787     unsigned char request[5], *response;
1788     int reqlen, resplen, success;
1789     void *vresponse;
1790
1791     PUT_32BIT(request, 1);
1792     request[4] = SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
1793     reqlen = 5;
1794     agent_query_synchronous(request, reqlen, &vresponse, &resplen);
1795     response = vresponse;
1796     success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
1797     sfree(response);
1798     if (!success) {
1799         *retstr = dupstr("Agent failed to delete SSH-2 keys");
1800         return PAGEANT_ACTION_FAILURE;
1801     }
1802
1803     PUT_32BIT(request, 1);
1804     request[4] = SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
1805     reqlen = 5;
1806     agent_query_synchronous(request, reqlen, &vresponse, &resplen);
1807     response = vresponse;
1808     success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
1809     sfree(response);
1810     if (!success) {
1811         *retstr = dupstr("Agent failed to delete SSH-1 keys");
1812         return PAGEANT_ACTION_FAILURE;
1813     }
1814
1815     *retstr = NULL;
1816     return PAGEANT_ACTION_OK;
1817 }
1818
1819 struct pageant_pubkey *pageant_pubkey_copy(struct pageant_pubkey *key)
1820 {
1821     struct pageant_pubkey *ret = snew(struct pageant_pubkey);
1822     ret->blob = snewn(key->bloblen, unsigned char);
1823     memcpy(ret->blob, key->blob, key->bloblen);
1824     ret->bloblen = key->bloblen;
1825     ret->comment = key->comment ? dupstr(key->comment) : NULL;
1826     ret->ssh_version = key->ssh_version;
1827     return ret;
1828 }
1829
1830 void pageant_pubkey_free(struct pageant_pubkey *key)
1831 {
1832     sfree(key->comment);
1833     sfree(key->blob);
1834     sfree(key);
1835 }